2020-03-21 21:40:39 +00:00
|
|
|
from owrx.config import Config
|
2021-01-23 18:27:01 +00:00
|
|
|
from csdr.chain.fft import FftChain
|
2021-03-18 18:34:53 +00:00
|
|
|
from owrx.source import SdrSourceEventClient, SdrSourceState, SdrClientClass
|
2020-03-23 22:56:05 +00:00
|
|
|
from owrx.property import PropertyStack
|
2021-09-20 13:09:26 +00:00
|
|
|
from pycsdr.modules import Buffer
|
|
|
|
import threading
|
2019-12-21 19:58:28 +00:00
|
|
|
|
|
|
|
import logging
|
|
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
2021-01-23 18:27:01 +00:00
|
|
|
class SpectrumThread(SdrSourceEventClient):
|
2019-12-21 19:58:28 +00:00
|
|
|
def __init__(self, sdrSource):
|
|
|
|
self.sdrSource = sdrSource
|
|
|
|
super().__init__()
|
|
|
|
|
2020-03-23 22:56:05 +00:00
|
|
|
stack = PropertyStack()
|
|
|
|
stack.addLayer(0, self.sdrSource.props)
|
|
|
|
stack.addLayer(1, Config.get())
|
2021-01-23 18:27:01 +00:00
|
|
|
self.props = stack.filter(
|
2019-12-21 19:58:28 +00:00
|
|
|
"samp_rate",
|
|
|
|
"fft_size",
|
|
|
|
"fft_fps",
|
|
|
|
"fft_voverlap_factor",
|
|
|
|
"fft_compression",
|
2020-03-23 22:56:05 +00:00
|
|
|
)
|
2019-12-21 19:58:28 +00:00
|
|
|
|
2021-01-23 18:27:01 +00:00
|
|
|
self.dsp = None
|
2021-09-20 13:09:26 +00:00
|
|
|
self.reader = None
|
2021-01-23 18:27:01 +00:00
|
|
|
|
|
|
|
self.subscriptions = []
|
2019-12-21 19:58:28 +00:00
|
|
|
|
|
|
|
logger.debug("Spectrum thread initialized successfully.")
|
|
|
|
|
|
|
|
def start(self):
|
2021-01-23 18:27:01 +00:00
|
|
|
if self.dsp is not None:
|
|
|
|
return
|
|
|
|
|
|
|
|
self.dsp = FftChain(
|
|
|
|
self.props['samp_rate'],
|
|
|
|
self.props['fft_size'],
|
|
|
|
self.props['fft_voverlap_factor'],
|
|
|
|
self.props['fft_fps'],
|
|
|
|
self.props['fft_compression']
|
|
|
|
)
|
2019-12-21 19:58:28 +00:00
|
|
|
self.sdrSource.addClient(self)
|
|
|
|
|
2021-01-23 18:27:01 +00:00
|
|
|
self.subscriptions += [
|
2021-09-27 15:29:51 +00:00
|
|
|
self.props.filter("fft_size").wire(self.restart),
|
2021-01-23 18:27:01 +00:00
|
|
|
# these props can be set on the fly
|
|
|
|
self.props.wireProperty("samp_rate", self.dsp.setSampleRate),
|
|
|
|
self.props.wireProperty("fft_fps", self.dsp.setFps),
|
|
|
|
self.props.wireProperty("fft_voverlap_factor", self.dsp.setVOverlapFactor),
|
2021-09-28 14:55:17 +00:00
|
|
|
self.props.wireProperty("fft_compression", self._setCompression),
|
2021-01-23 18:27:01 +00:00
|
|
|
]
|
|
|
|
|
2021-09-28 14:55:17 +00:00
|
|
|
if self.sdrSource.isAvailable():
|
|
|
|
self.dsp.setReader(self.sdrSource.getBuffer().getReader())
|
|
|
|
|
|
|
|
def _setCompression(self, compression):
|
|
|
|
if self.reader:
|
|
|
|
self.reader.stop()
|
|
|
|
try:
|
|
|
|
self.dsp.setCompression(compression)
|
|
|
|
except ValueError:
|
|
|
|
# expected since the compressions have different formats
|
|
|
|
pass
|
|
|
|
|
2021-09-20 13:09:26 +00:00
|
|
|
buffer = Buffer(self.dsp.getOutputFormat())
|
|
|
|
self.dsp.setWriter(buffer)
|
|
|
|
self.reader = buffer.getReader()
|
|
|
|
threading.Thread(target=self.dsp.pump(self.reader.read, self.sdrSource.writeSpectrumData)).start()
|
2019-12-21 19:58:28 +00:00
|
|
|
|
|
|
|
def stop(self):
|
2021-01-23 18:27:01 +00:00
|
|
|
if self.dsp is None:
|
|
|
|
return
|
2019-12-21 19:58:28 +00:00
|
|
|
self.dsp.stop()
|
2021-01-23 18:27:01 +00:00
|
|
|
self.dsp = None
|
2021-12-06 14:50:03 +00:00
|
|
|
if self.reader:
|
|
|
|
self.reader.stop()
|
|
|
|
self.reader = None
|
2019-12-21 19:58:28 +00:00
|
|
|
self.sdrSource.removeClient(self)
|
2021-01-23 18:27:01 +00:00
|
|
|
while self.subscriptions:
|
|
|
|
self.subscriptions.pop().cancel()
|
|
|
|
|
|
|
|
def restart(self, *args, **kwargs):
|
|
|
|
self.stop()
|
|
|
|
self.start()
|
2019-12-21 19:58:28 +00:00
|
|
|
|
2021-02-20 21:54:07 +00:00
|
|
|
def getClientClass(self) -> SdrClientClass:
|
|
|
|
return SdrClientClass.USER
|
2019-12-21 19:58:28 +00:00
|
|
|
|
2021-02-20 21:54:07 +00:00
|
|
|
def onStateChange(self, state: SdrSourceState):
|
2021-03-18 18:34:53 +00:00
|
|
|
if state is SdrSourceState.STOPPING:
|
2021-12-06 14:50:03 +00:00
|
|
|
if self.dsp:
|
|
|
|
self.dsp.stop()
|
2021-07-15 16:09:39 +00:00
|
|
|
elif state == SdrSourceState.RUNNING:
|
2021-01-23 18:27:01 +00:00
|
|
|
if self.dsp is None:
|
|
|
|
self.start()
|
|
|
|
else:
|
2021-08-16 14:41:18 +00:00
|
|
|
self.dsp.setReader(self.sdrSource.getBuffer().getReader())
|
2019-12-21 19:58:28 +00:00
|
|
|
|
2021-03-18 18:34:53 +00:00
|
|
|
def onFail(self):
|
2021-08-26 15:22:10 +00:00
|
|
|
if self.dsp is None:
|
|
|
|
return
|
2021-03-18 18:34:53 +00:00
|
|
|
self.dsp.stop()
|
2021-03-18 21:59:46 +00:00
|
|
|
|
|
|
|
def onShutdown(self):
|
2021-08-26 15:22:10 +00:00
|
|
|
if self.dsp is None:
|
|
|
|
return
|
2021-03-18 21:59:46 +00:00
|
|
|
self.dsp.stop()
|