diff --git a/csdr/chain/dablin.py b/csdr/chain/dablin.py index d451a248..1e1c5667 100644 --- a/csdr/chain/dablin.py +++ b/csdr/chain/dablin.py @@ -1,4 +1,5 @@ -from csdr.chain.demodulator import BaseDemodulatorChain, FixedIfSampleRateChain, FixedAudioRateChain, HdAudio, MetaProvider +from csdr.chain.demodulator import BaseDemodulatorChain, FixedIfSampleRateChain, FixedAudioRateChain, HdAudio, \ + MetaProvider, DabServiceSelector from csdr.module import PickleModule from csdreti.modules import EtiDecoder from owrx.dab.dablin import DablinModule @@ -46,7 +47,7 @@ class MetaProcessor(PickleModule): return result -class Dablin(BaseDemodulatorChain, FixedIfSampleRateChain, FixedAudioRateChain, HdAudio, MetaProvider): +class Dablin(BaseDemodulatorChain, FixedIfSampleRateChain, FixedAudioRateChain, HdAudio, MetaProvider, DabServiceSelector): def __init__(self): shift = Shift(0) decoder = EtiDecoder() @@ -59,10 +60,12 @@ class Dablin(BaseDemodulatorChain, FixedIfSampleRateChain, FixedAudioRateChain, # will be replaced by setMetaWriter(). self.processor.setWriter(Buffer(Format.CHAR)) + self.dablin = DablinModule() + workers = [ shift, decoder, - DablinModule(), + self.dablin, Downmix(Format.FLOAT), ] super().__init__(workers) @@ -84,3 +87,6 @@ class Dablin(BaseDemodulatorChain, FixedIfSampleRateChain, FixedAudioRateChain, def setMetaWriter(self, writer: Writer) -> None: self.processor.setWriter(writer) + + def setDabServiceId(self, serviceId: int) -> None: + self.dablin.setDabServiceId(serviceId) diff --git a/csdr/chain/demodulator.py b/csdr/chain/demodulator.py index 99042d99..7b4506cc 100644 --- a/csdr/chain/demodulator.py +++ b/csdr/chain/demodulator.py @@ -55,6 +55,12 @@ class RdsChain(ABC): pass +class DabServiceSelector(ABC): + @abstractmethod + def setDabServiceId(self, serviceId: int) -> None: + pass + + class BaseDemodulatorChain(Chain): def supportsSquelch(self) -> bool: return True diff --git a/docker/scripts/install-owrx-tools.sh b/docker/scripts/install-owrx-tools.sh index 231f5919..a4b64d01 100755 --- a/docker/scripts/install-owrx-tools.sh +++ b/docker/scripts/install-owrx-tools.sh @@ -32,13 +32,13 @@ popd rm -rf js8py git clone https://github.com/jketterl/csdr.git -# latest develop as of 2024-01-22 (downmix format) -cmakebuild csdr e6ae546a6a1d3fd052fe962eb5a04fd33e794214 +# latest develop as of 2024-01-25 (exemodule setargs) +cmakebuild csdr 344179a616cdbadf501479ce9ed1b836543e657b git clone https://github.com/jketterl/pycsdr.git cd pycsdr -# latest develop as of 2024-01-22 (downmix format) -git checkout c7dafe83d08b74012e233502dff0bc6e6f17c01c +# latest develop as of 2024-01-25 (execmodule setargs) +git checkout 9063b8a119e366c31d089596641a24a427e3cbdc ./setup.py install install_headers cd .. rm -rf pycsdr diff --git a/htdocs/lib/Demodulator.js b/htdocs/lib/Demodulator.js index b55cbdcf..e729ebe7 100644 --- a/htdocs/lib/Demodulator.js +++ b/htdocs/lib/Demodulator.js @@ -205,6 +205,7 @@ function Demodulator(offset_frequency, modulation) { this.filter = new Filter(this); this.squelch_level = -150; this.dmr_filter = 3; + this.dab_service_id = 0; this.started = false; this.state = {}; this.secondary_demod = false; @@ -294,6 +295,7 @@ Demodulator.prototype.set = function () { //this function sends demodulator par "offset_freq": this.offset_frequency, "mod": this.modulation, "dmr_filter": this.dmr_filter, + "dab_service_id": this.dab_service_id, "squelch_level": this.squelch_level, "secondary_mod": this.secondary_demod, "secondary_offset_freq": this.secondary_offset_freq @@ -331,6 +333,11 @@ Demodulator.prototype.setDmrFilter = function(dmr_filter) { this.set(); }; +Demodulator.prototype.setDabServiceId = function(dab_service_id) { + this.dab_service_id = dab_service_id; + this.set(); +} + Demodulator.prototype.setBandpass = function(bandpass) { this.bandpass = bandpass; this.low_cut = bandpass.low_cut; diff --git a/htdocs/lib/MetaPanel.js b/htdocs/lib/MetaPanel.js index e84a29d3..d94a9d6b 100644 --- a/htdocs/lib/MetaPanel.js +++ b/htdocs/lib/MetaPanel.js @@ -553,9 +553,12 @@ WfmMetaPanel.prototype.clear = function() { function DabMetaPanel(el) { MetaPanel.call(this, el); this.modes = ['DAB']; - $(this.el).html( - '' - ) + this.$select = $(''); + $(this.el).append(this.$select); + this.$select.on("change", function() { + var service_id = parseInt($(this).val()); + $('#openwebrx-panel-receiver').demodulatorPanel().getDemodulator().setDabServiceId(service_id); + }); this.clear(); } @@ -573,7 +576,10 @@ DabMetaPanel.prototype.update = function(data) { var options = Object.entries(data.programmes).map(function(e) { return ''; }); - $(this.el).find('#dab-service-id').html(options.join('')); + $(this.el).find('#dab-service-id').html( + '' + + options.join('') + ); } console.info(data); diff --git a/owrx/dab/dablin.py b/owrx/dab/dablin.py index ffb9bc68..ad7d2641 100644 --- a/owrx/dab/dablin.py +++ b/owrx/dab/dablin.py @@ -4,8 +4,17 @@ from pycsdr.types import Format class DablinModule(ExecModule): def __init__(self): + self.serviceId = 0 super().__init__( Format.CHAR, Format.FLOAT, - ["dablin", "-1", "-p"] + self._buildArgs() ) + + def _buildArgs(self): + return ["dablin", "-p", "-s", "{:#06x}".format(self.serviceId)] + + def setDabServiceId(self, serviceId: int) -> None: + self.serviceId = serviceId + self.setArgs(self._buildArgs()) + self.restart() diff --git a/owrx/dsp.py b/owrx/dsp.py index f9f8bb7f..84306d6a 100644 --- a/owrx/dsp.py +++ b/owrx/dsp.py @@ -3,7 +3,9 @@ from owrx.property import PropertyStack, PropertyLayer, PropertyValidator, Prope from owrx.property.validators import OrValidator, RegexValidator, BoolValidator from owrx.modes import Modes, DigitalMode from csdr.chain import Chain -from csdr.chain.demodulator import BaseDemodulatorChain, FixedIfSampleRateChain, FixedAudioRateChain, HdAudio, SecondaryDemodulator, DialFrequencyReceiver, MetaProvider, SlotFilterChain, SecondarySelectorChain, DeemphasisTauChain, DemodulatorError, RdsChain +from csdr.chain.demodulator import BaseDemodulatorChain, FixedIfSampleRateChain, FixedAudioRateChain, HdAudio, \ + SecondaryDemodulator, DialFrequencyReceiver, MetaProvider, SlotFilterChain, SecondarySelectorChain, \ + DeemphasisTauChain, DemodulatorError, RdsChain, DabServiceSelector from csdr.chain.selector import Selector, SecondarySelector from csdr.chain.clientaudio import ClientAudioChain from csdr.chain.fft import FftChain @@ -328,6 +330,11 @@ class ClientDemodulatorChain(Chain): return self.demodulator.setSlotFilter(filter) + def setDabServiceId(self, serviceId: int) -> None: + if not isinstance(self.demodulator, DabServiceSelector): + return + self.demodulator.setDabServiceId(serviceId) + def setSecondaryFftSize(self, size: int) -> None: if size == self.secondaryFftSize: return @@ -422,6 +429,7 @@ class DspManager(SdrSourceEventClient, ClientDemodulatorSecondaryDspEventClient) "mod": ModulationValidator(), "secondary_offset_freq": "int", "dmr_filter": "int", + "dab_service_id": "int", } self.localProps = PropertyValidator(PropertyLayer().filter(*validators.keys()), validators) @@ -502,6 +510,7 @@ class DspManager(SdrSourceEventClient, ClientDemodulatorSecondaryDspEventClient) self.props.wireProperty("high_cut", self.setHighCut), self.props.wireProperty("mod", self.setDemodulator), self.props.wireProperty("dmr_filter", self.chain.setSlotFilter), + self.props.wireProperty("dab_service_id", self.chain.setDabServiceId), self.props.wireProperty("wfm_deemphasis_tau", self.chain.setWfmDeemphasisTau), self.props.wireProperty("wfm_rds_rbds", self.chain.setRdsRbds), self.props.wireProperty("secondary_mod", self.setSecondaryDemodulator),