openwebrx/csdr/chain/digimodes.py

121 lines
4.4 KiB
Python
Raw Normal View History

2021-09-23 18:43:41 +02:00
from csdr.chain.demodulator import ServiceDemodulator, SecondaryDemodulator, DialFrequencyReceiver, SecondarySelectorChain
2023-02-14 18:36:17 +01:00
from csdr.module.msk144 import Msk144Module, ParserAdapter
2021-09-28 00:27:01 +02:00
from owrx.audio.chopper import AudioChopper, AudioChopperParser
2021-09-06 15:05:33 +02:00
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
2021-08-31 16:54:37 +02:00
from pycsdr.types import Format
from owrx.aprs.direwolf import DirewolfModule
2021-08-31 16:54:37 +02:00
2021-09-23 18:43:41 +02:00
class AudioChopperDemodulator(ServiceDemodulator, DialFrequencyReceiver):
2021-09-28 00:27:01 +02:00
def __init__(self, mode: str, parser: AudioChopperParser):
2021-08-31 22:46:11 +02:00
self.chopper = AudioChopper(mode, parser)
workers = [Convert(Format.FLOAT, Format.SHORT), self.chopper]
2021-08-31 16:54:37 +02:00
super().__init__(workers)
def getFixedAudioRate(self):
return 12000
2021-08-31 22:46:11 +02:00
def setDialFrequency(self, frequency: int) -> None:
self.chopper.setDialFrequency(frequency)
2021-09-06 15:05:33 +02:00
2023-02-14 18:36:17 +01:00
class Msk144Demodulator(ServiceDemodulator, DialFrequencyReceiver):
2023-02-14 15:39:59 +01:00
def __init__(self):
2023-02-14 18:36:17 +01:00
self.parser = ParserAdapter()
2023-02-14 15:39:59 +01:00
workers = [
Convert(Format.FLOAT, Format.SHORT),
Msk144Module(),
2023-02-14 18:36:17 +01:00
self.parser,
2023-02-14 15:39:59 +01:00
]
super().__init__(workers)
def getFixedAudioRate(self) -> int:
return 12000
2023-02-14 18:36:17 +01:00
def setDialFrequency(self, frequency: int) -> None:
self.parser.setDialFrequency(frequency)
2023-02-14 15:39:59 +01:00
2021-09-23 18:43:41 +02:00
class PacketDemodulator(ServiceDemodulator, DialFrequencyReceiver):
2021-09-06 15:05:33 +02:00
def __init__(self, service: bool = False):
self.parser = AprsParser()
workers = [
FmDemod(),
Convert(Format.FLOAT, Format.SHORT),
DirewolfModule(service=service),
KissDeframer(),
Ax25Parser(),
self.parser,
]
super().__init__(workers)
def supportsSquelch(self) -> bool:
return False
def getFixedAudioRate(self) -> int:
return 48000
def setDialFrequency(self, frequency: int) -> None:
2021-10-01 00:52:32 +02:00
self.parser.setDialFrequency(frequency)
2021-09-23 18:43:41 +02:00
class PskDemodulator(SecondaryDemodulator, SecondarySelectorChain):
def __init__(self, baudRate: float):
self.baudRate = baudRate
# this is an assumption, we will adjust in setSampleRate
self.sampleRate = 12000
secondary_samples_per_bits = int(round(self.sampleRate / self.baudRate)) & ~3
workers = [
Agc(Format.COMPLEX_FLOAT),
2023-08-10 21:29:18 +02:00
TimingRecovery(Format.COMPLEX_FLOAT, secondary_samples_per_bits, 0.5, 2),
2021-09-23 18:43:41 +02:00
DBPskDecoder(),
VaricodeDecoder(),
]
super().__init__(workers)
def getBandwidth(self):
return self.baudRate
def setSampleRate(self, sampleRate: int) -> None:
if sampleRate == self.sampleRate:
return
self.sampleRate = sampleRate
secondary_samples_per_bits = int(round(self.sampleRate / self.baudRate)) & ~3
2023-08-15 16:42:59 +02:00
self.replace(1, TimingRecovery(Format.COMPLEX_FLOAT, secondary_samples_per_bits, 0.5, 2))
class RttyDemodulator(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
2023-08-21 17:30:07 +02:00
loop_gain = self.sampleRate / self.getBandwidth() / 5
2023-08-15 16:42:59 +02:00
workers = [
Agc(Format.COMPLEX_FLOAT),
FmDemod(),
Lowpass(Format.FLOAT, cutoff),
2023-08-21 17:30:07 +02:00
TimingRecovery(Format.FLOAT, secondary_samples_per_bit, loop_gain, 10),
2023-08-15 16:42:59 +02:00
RttyDecoder(invert),
BaudotDecoder(),
]
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
2023-08-21 17:30:07 +02:00
loop_gain = self.sampleRate / self.getBandwidth() / 5
self.replace(2, Lowpass(Format.FLOAT, cutoff))
2023-08-21 17:30:07 +02:00
self.replace(3, TimingRecovery(Format.FLOAT, secondary_samples_per_bit, loop_gain, 10))