Adding CW skimmer.
This commit is contained in:
parent
3964f9a23c
commit
399cc3f267
|
|
@ -1,8 +1,8 @@
|
|||
from csdr.chain.demodulator import ServiceDemodulator, DialFrequencyReceiver
|
||||
from csdr.module.toolbox import Rtl433Module, MultimonModule, DumpHfdlModule, DumpVdl2Module, Dump1090Module, AcarsDecModule, RedseaModule, SatDumpModule
|
||||
from csdr.module.toolbox import Rtl433Module, MultimonModule, DumpHfdlModule, DumpVdl2Module, Dump1090Module, AcarsDecModule, RedseaModule, SatDumpModule, CwSkimmerModule
|
||||
from pycsdr.modules import FmDemod, AudioResampler, Convert, Agc, Squelch
|
||||
from pycsdr.types import Format
|
||||
from owrx.toolbox import TextParser, PageParser, SelCallParser, EasParser, IsmParser, RdsParser
|
||||
from owrx.toolbox import TextParser, PageParser, SelCallParser, EasParser, IsmParser, RdsParser, CwSkimmerParser
|
||||
from owrx.aircraft import HfdlParser, Vdl2Parser, AdsbParser, AcarsParser
|
||||
|
||||
from datetime import datetime
|
||||
|
|
@ -223,6 +223,27 @@ class RdsDemodulator(ServiceDemodulator, DialFrequencyReceiver):
|
|||
self.parser.setDialFrequency(frequency)
|
||||
|
||||
|
||||
class CwSkimmerDemodulator(ServiceDemodulator, DialFrequencyReceiver):
|
||||
def __init__(self, sampleRate: int = 12000, charCount: int = 8):
|
||||
self.sampleRate = sampleRate
|
||||
self.parser = CwSkimmerParser()
|
||||
workers = [
|
||||
CwSkimmerModule(sampleRate, charCount),
|
||||
self.parser,
|
||||
]
|
||||
# Connect all the workers
|
||||
super().__init__(workers)
|
||||
|
||||
def getFixedAudioRate(self) -> int:
|
||||
return self.sampleRate
|
||||
|
||||
def supportsSquelch(self) -> bool:
|
||||
return False
|
||||
|
||||
def setDialFrequency(self, frequency: int) -> None:
|
||||
self.parser.setDialFrequency(frequency)
|
||||
|
||||
|
||||
class NoaaAptDemodulator(ServiceDemodulator):
|
||||
def __init__(self, satellite: int = 19, service: bool = False):
|
||||
d = datetime.utcnow()
|
||||
|
|
|
|||
|
|
@ -119,6 +119,12 @@ class AcarsDecModule(WavFileModule):
|
|||
return Format.CHAR
|
||||
|
||||
|
||||
class CwSkimmerModule(ExecModule):
|
||||
def __init__(self, sampleRate: int = 12000, charCount: int = 8):
|
||||
cmd = ["csdr-cwskimmer", "-r", str(sampleRate), "-n", str(charCount)]
|
||||
super().__init__(Format.FLOAT, Format.CHAR, cmd)
|
||||
|
||||
|
||||
class RedseaModule(ExecModule):
|
||||
def __init__(self, sampleRate: int = 171000, rbds: bool = False):
|
||||
cmd = [ "redsea", "--input", "mpx", "--samplerate", str(sampleRate) ]
|
||||
|
|
|
|||
|
|
@ -720,6 +720,9 @@ class DspManager(SdrSourceEventClient, ClientDemodulatorSecondaryDspEventClient)
|
|||
elif mod == "cwdecoder":
|
||||
from csdr.chain.digimodes import CwDemodulator
|
||||
return CwDemodulator(75.0)
|
||||
elif mod == "cwskimmer":
|
||||
from csdr.chain.digimodes import CwSkimmerDemodulator
|
||||
return CwSkimmerDemodulator()
|
||||
elif mod == "mfrtty170":
|
||||
from csdr.chain.digimodes import MFRttyDemodulator
|
||||
return MFRttyDemodulator(170.0, 45.45, reverse = False)
|
||||
|
|
|
|||
|
|
@ -194,6 +194,7 @@ class Modes(object):
|
|||
squelch=False,
|
||||
),
|
||||
DigitalMode("cwdecoder", "CW Decoder", underlying=["usb", "lsb"]),
|
||||
DigitalMode("cwskimmer", "CW Skimmer", underlying=["usb", "lsb"]),
|
||||
# Replaced by Jakob's RTTY decoder
|
||||
# DigitalMode("mfrtty170", "RTTY-170", underlying=["usb"]),
|
||||
# DigitalMode("mfrtty450", "RTTY-450", underlying=["usb"]),
|
||||
|
|
|
|||
|
|
@ -414,3 +414,37 @@ class EasParser(TextParser):
|
|||
|
||||
# Return received message as text
|
||||
return "\n".join(out)
|
||||
|
||||
|
||||
class CwSkimmerParser(TextParser):
|
||||
def __init__(self, charTotal: int = 32, service: bool = False):
|
||||
self.reLine = re.compile("^(\d+):\s*(.*)$")
|
||||
self.data = {}
|
||||
# Construct parent object
|
||||
super().__init__(filePrefix="CW", service=service)
|
||||
|
||||
def parse(self, msg: bytes):
|
||||
# Do not parse in service mode
|
||||
if self.service:
|
||||
return None
|
||||
# Parse CW messages by frequency
|
||||
msg = msg.decode("utf-8", "replace")
|
||||
r = self.reLine.match(msg)
|
||||
if r is not None:
|
||||
freq = int(r.group(1))
|
||||
text = r.group(2)
|
||||
# Add up newly decoded characters
|
||||
if freq in self.data:
|
||||
text = self.data[freq] + text
|
||||
# Truncate received text to charTotal
|
||||
text = text if len(text) <= charTotal else text[:charTotal]
|
||||
self.data[freq] = text
|
||||
# Compose output
|
||||
out = { "mode": "CW", "text": text }
|
||||
# Add frequency, if known
|
||||
if self.frequency:
|
||||
out["freq"] = self.frequency + freq
|
||||
# Done
|
||||
return out
|
||||
# No result
|
||||
return None
|
||||
|
|
|
|||
Loading…
Reference in New Issue