2019-12-27 23:26:45 +00:00
|
|
|
from abc import ABCMeta
|
2021-02-20 17:09:24 +00:00
|
|
|
from owrx.source import SdrSource, SdrDeviceDescription
|
2021-09-20 16:36:24 +00:00
|
|
|
from csdr.chain import Chain
|
|
|
|
from typing import Optional
|
|
|
|
from pycsdr.modules import Buffer
|
|
|
|
from pycsdr.types import Format
|
2019-12-27 23:26:45 +00:00
|
|
|
|
|
|
|
|
|
|
|
class DirectSource(SdrSource, metaclass=ABCMeta):
|
2022-09-19 16:46:11 +00:00
|
|
|
def __init__(self, id, props):
|
|
|
|
self._conversion = None
|
|
|
|
super().__init__(id, props)
|
|
|
|
|
2020-12-30 16:18:46 +00:00
|
|
|
def onPropertyChange(self, changes):
|
2022-12-10 18:50:26 +00:00
|
|
|
self.logger.debug("restarting sdr source due to property changes: {0}".format(changes))
|
2019-12-27 23:26:45 +00:00
|
|
|
self.stop()
|
|
|
|
self.sleepOnRestart()
|
|
|
|
self.start()
|
|
|
|
|
2021-03-30 22:23:36 +00:00
|
|
|
def nmux_memory(self):
|
|
|
|
# in megabytes. This sets the approximate size of the circular buffer used by nmux.
|
|
|
|
return 50
|
2019-12-27 23:26:45 +00:00
|
|
|
|
|
|
|
def getNmuxCommand(self):
|
2020-03-24 21:52:17 +00:00
|
|
|
props = self.sdrProps
|
2019-12-27 23:26:45 +00:00
|
|
|
|
|
|
|
nmux_bufcnt = nmux_bufsize = 0
|
|
|
|
while nmux_bufsize < props["samp_rate"] / 4:
|
|
|
|
nmux_bufsize += 4096
|
2021-03-30 22:23:36 +00:00
|
|
|
while nmux_bufsize * nmux_bufcnt < self.nmux_memory() * 1e6:
|
2019-12-27 23:26:45 +00:00
|
|
|
nmux_bufcnt += 1
|
|
|
|
if nmux_bufcnt == 0 or nmux_bufsize == 0:
|
2021-03-30 22:23:36 +00:00
|
|
|
raise ValueError("Error: unable to calculate nmux buffer parameters.")
|
2019-12-27 23:26:45 +00:00
|
|
|
|
2021-01-20 16:01:46 +00:00
|
|
|
return [
|
|
|
|
"nmux --bufsize %d --bufcnt %d --port %d --address 127.0.0.1"
|
|
|
|
% (
|
|
|
|
nmux_bufsize,
|
|
|
|
nmux_bufcnt,
|
|
|
|
self.port,
|
|
|
|
)
|
|
|
|
]
|
2019-12-27 23:26:45 +00:00
|
|
|
|
|
|
|
def getCommand(self):
|
2021-09-20 16:36:24 +00:00
|
|
|
return super().getCommand() + self.getNmuxCommand()
|
2019-12-27 23:26:45 +00:00
|
|
|
|
|
|
|
# override this in subclasses, if necessary
|
2021-09-20 16:36:24 +00:00
|
|
|
def getFormatConversion(self) -> Optional[Chain]:
|
|
|
|
return None
|
2019-12-27 23:26:45 +00:00
|
|
|
|
2022-09-19 16:46:11 +00:00
|
|
|
def _getTcpSourceFormat(self):
|
|
|
|
conversion = self.getFormatConversion()
|
|
|
|
return Format.COMPLEX_FLOAT if conversion is None else conversion.getInputFormat()
|
|
|
|
|
2019-12-27 23:26:45 +00:00
|
|
|
# override this in subclasses, if necessary
|
|
|
|
def sleepOnRestart(self):
|
|
|
|
pass
|
2021-02-20 17:09:24 +00:00
|
|
|
|
2021-09-20 16:36:24 +00:00
|
|
|
def getBuffer(self):
|
|
|
|
if self.buffer is None:
|
|
|
|
source = self._getTcpSource()
|
|
|
|
buffer = Buffer(source.getOutputFormat())
|
|
|
|
source.setWriter(buffer)
|
2022-09-19 16:46:11 +00:00
|
|
|
self._conversion = self.getFormatConversion()
|
|
|
|
if self._conversion is not None:
|
|
|
|
self._conversion.setReader(buffer.getReader())
|
2021-09-20 16:36:24 +00:00
|
|
|
# this one must be COMPLEX_FLOAT
|
|
|
|
buffer = Buffer(Format.COMPLEX_FLOAT)
|
2022-09-19 16:46:11 +00:00
|
|
|
self._conversion.setWriter(buffer)
|
2021-09-20 16:36:24 +00:00
|
|
|
self.buffer = buffer
|
|
|
|
return self.buffer
|
|
|
|
|
2021-02-20 17:09:24 +00:00
|
|
|
|
|
|
|
class DirectSourceDeviceDescription(SdrDeviceDescription):
|
|
|
|
pass
|