diff --git a/csdr/chain/digimodes.py b/csdr/chain/digimodes.py index ce4b3d5d..53b17ce0 100644 --- a/csdr/chain/digimodes.py +++ b/csdr/chain/digimodes.py @@ -3,7 +3,7 @@ from csdr.module.msk144 import Msk144Module, ParserAdapter from owrx.audio.chopper import AudioChopper, AudioChopperParser from owrx.aprs.kiss import KissDeframer from owrx.aprs import Ax25Parser, AprsParser -from pycsdr.modules import Convert, FmDemod, Agc, TimingRecovery, DBPskDecoder, VaricodeDecoder, RttyDecoder, BaudotDecoder, Lowpass, MFRttyDecoder, CwDecoder, SstvDecoder, FaxDecoder, SitorDecoder, Ccir476Decoder, Shift +from pycsdr.modules import Convert, FmDemod, Agc, TimingRecovery, DBPskDecoder, VaricodeDecoder, RttyDecoder, BaudotDecoder, Lowpass, MFRttyDecoder, CwDecoder, SstvDecoder, FaxDecoder, SitorDecoder, Ccir476Decoder, DscDecoder, Ccir493Decoder, Shift from pycsdr.types import Format from owrx.aprs.direwolf import DirewolfModule from owrx.sstv import SstvParser @@ -250,3 +250,37 @@ class SitorBDemodulator(SecondaryDemodulator, SecondarySelectorChain): loop_gain = self.sampleRate / self.getBandwidth() / 5 self.replace(2, Lowpass(Format.FLOAT, cutoff)) self.replace(3, TimingRecovery(Format.FLOAT, secondary_samples_per_bit, loop_gain, 10)) + + +class DscDemodulator(SecondaryDemodulator, SecondarySelectorChain): + def __init__(self, baudRate, bandWidth, invert=False): + self.baudRate = baudRate + self.bandWidth = bandWidth + self.invert = invert + # this is an assumption, we will adjust in setSampleRate + self.sampleRate = 12000 + secondary_samples_per_bit = int(round(self.sampleRate / self.baudRate)) + cutoff = self.baudRate / self.sampleRate + loop_gain = self.sampleRate / self.getBandwidth() / 5 + workers = [ + Agc(Format.COMPLEX_FLOAT), + FmDemod(), + Lowpass(Format.FLOAT, cutoff), + TimingRecovery(Format.FLOAT, secondary_samples_per_bit, loop_gain, 10), + Ccir493Decoder(fec=True, invert=invert), + DscDecoder(), + ] + super().__init__(workers) + + def getBandwidth(self) -> float: + return self.bandWidth + + def setSampleRate(self, sampleRate: int) -> None: + if sampleRate == self.sampleRate: + return + self.sampleRate = sampleRate + secondary_samples_per_bit = int(round(self.sampleRate / self.baudRate)) + cutoff = self.baudRate / self.sampleRate + loop_gain = self.sampleRate / self.getBandwidth() / 5 + self.replace(2, Lowpass(Format.FLOAT, cutoff)) + self.replace(3, TimingRecovery(Format.FLOAT, secondary_samples_per_bit, loop_gain, 10)) diff --git a/owrx/dsp.py b/owrx/dsp.py index 2126b1c1..70f253ee 100644 --- a/owrx/dsp.py +++ b/owrx/dsp.py @@ -670,6 +670,9 @@ class DspManager(SdrSourceEventClient, ClientDemodulatorSecondaryDspEventClient) elif mod == "sitorb": from csdr.chain.digimodes import SitorBDemodulator return SitorBDemodulator(100, 170) + elif mod == "dsc": + from csdr.chain.digimodes import DscDemodulator + return DscDemodulator(100, 170) elif mod == "cwdecoder": from csdr.chain.digimodes import CwDemodulator return CwDemodulator(75.0) diff --git a/owrx/modes.py b/owrx/modes.py index b7d01f90..d8fb1e54 100644 --- a/owrx/modes.py +++ b/owrx/modes.py @@ -139,6 +139,7 @@ class Modes(object): DigitalMode("rtty450", "RTTY-450 (50N)", underlying=["usb", "lsb"]), DigitalMode("rtty85", "RTTY-85 (50N)", underlying=["usb", "lsb"]), DigitalMode("sitorb", "SITOR-B", underlying=["usb"]), + DigitalMode("dsc", "DSC", underlying=["usb"]), WsjtMode("ft8", "FT8"), WsjtMode("ft4", "FT4"), WsjtMode("jt65", "JT65"),