add MSK144 parsing

This commit is contained in:
Jakob Ketterl 2023-02-14 18:36:17 +01:00
parent 525b70d495
commit afcd8277d1
4 changed files with 69 additions and 4 deletions

View File

@ -1,5 +1,5 @@
from csdr.chain.demodulator import ServiceDemodulator, SecondaryDemodulator, DialFrequencyReceiver, SecondarySelectorChain from csdr.chain.demodulator import ServiceDemodulator, SecondaryDemodulator, DialFrequencyReceiver, SecondarySelectorChain
from csdr.module.msk144 import Msk144Module from csdr.module.msk144 import Msk144Module, ParserAdapter
from owrx.audio.chopper import AudioChopper, AudioChopperParser from owrx.audio.chopper import AudioChopper, AudioChopperParser
from owrx.aprs.kiss import KissDeframer from owrx.aprs.kiss import KissDeframer
from owrx.aprs import Ax25Parser, AprsParser from owrx.aprs import Ax25Parser, AprsParser
@ -21,17 +21,22 @@ class AudioChopperDemodulator(ServiceDemodulator, DialFrequencyReceiver):
self.chopper.setDialFrequency(frequency) self.chopper.setDialFrequency(frequency)
class Msk144Demodulator(ServiceDemodulator): class Msk144Demodulator(ServiceDemodulator, DialFrequencyReceiver):
def __init__(self): def __init__(self):
self.parser = ParserAdapter()
workers = [ workers = [
Convert(Format.FLOAT, Format.SHORT), Convert(Format.FLOAT, Format.SHORT),
Msk144Module(), Msk144Module(),
self.parser,
] ]
super().__init__(workers) super().__init__(workers)
def getFixedAudioRate(self) -> int: def getFixedAudioRate(self) -> int:
return 12000 return 12000
def setDialFrequency(self, frequency: int) -> None:
self.parser.setDialFrequency(frequency)
class PacketDemodulator(ServiceDemodulator, DialFrequencyReceiver): class PacketDemodulator(ServiceDemodulator, DialFrequencyReceiver):
def __init__(self, service: bool = False): def __init__(self, service: bool = False):

View File

@ -126,7 +126,7 @@ class PopenModule(AutoStartModule, metaclass=ABCMeta):
# resume in case the reader has been stop()ed before # resume in case the reader has been stop()ed before
self.reader.resume() self.reader.resume()
Thread(target=self.pump(self.reader.read, self.process.stdin.write)).start() Thread(target=self.pump(self.reader.read, self.process.stdin.write)).start()
Thread(target=self.pump(partial(self.process.stdout.read, 1024), self.writer.write)).start() Thread(target=self.pump(partial(self.process.stdout.read1, 1024), self.writer.write)).start()
def stop(self): def stop(self):
if self.process is not None: if self.process is not None:

View File

@ -1,5 +1,10 @@
from pycsdr.types import Format from pycsdr.types import Format
from csdr.module import PopenModule from csdr.module import PopenModule, ThreadModule
from owrx.wsjt import WsjtParser, Msk144Profile
import pickle
import logging
logger = logging.getLogger(__name__)
class Msk144Module(PopenModule): class Msk144Module(PopenModule):
@ -11,3 +16,45 @@ class Msk144Module(PopenModule):
def getOutputFormat(self) -> Format: def getOutputFormat(self) -> Format:
return Format.CHAR return Format.CHAR
class ParserAdapter(ThreadModule):
def __init__(self):
self.retained = bytes()
self.parser = WsjtParser()
self.dialFrequency = 0
super().__init__()
def run(self):
profile = Msk144Profile()
while self.doRun:
data = self.reader.read()
if data is None:
self.doRun = False
else:
logger.debug('raw data: ' + str(bytes(data)))
self.retained += data
lines = self.retained.split(b"\n")
# keep the last line
# this should either be empty if the last char was \n
# or an incomplete line if the read returned early
self.retained = lines[-1]
# parse all completed lines
for line in lines[0:-1]:
# actual messages from msk144decoder should start with "*** "
if line[0:4] == b"*** ":
self.writer.write(pickle.dumps(self.parser.parse(profile, self.dialFrequency, line[4:])))
else:
logger.debug("ignoring static: %s", line.decode())
def getInputFormat(self) -> Format:
return Format.CHAR
def getOutputFormat(self) -> Format:
return Format.CHAR
def setDialFrequency(self, frequency: int) -> None:
self.dialFrequency = frequency

View File

@ -245,6 +245,17 @@ class Q65Profile(WsjtProfile):
return ["jt9", "--q65", "-p", str(self.interval), "-b", self.mode.name, "-d", str(self.decoding_depth()), file] return ["jt9", "--q65", "-p", str(self.interval), "-b", self.mode.name, "-d", str(self.decoding_depth()), file]
class Msk144Profile(WsjtProfile):
def getMode(self):
return "MSK144"
def getInterval(self):
return 15
def decoder_commandline(self, file):
return None
class WsjtParser(AudioChopperParser): class WsjtParser(AudioChopperParser):
def parse(self, profile: WsjtProfile, freq: int, raw_msg: bytes): def parse(self, profile: WsjtProfile, freq: int, raw_msg: bytes):
try: try:
@ -366,6 +377,8 @@ class Jt9Decoder(Decoder):
# '0003 -4 0.4 1762 # CQ R2ABM KO85' # '0003 -4 0.4 1762 # CQ R2ABM KO85'
# fst4 sample # fst4 sample
# '**** -23 0.6 3023 ` <...> <...> R 591631 BI53PV' # '**** -23 0.6 3023 ` <...> <...> R 591631 BI53PV'
# MSK144 sample
# '221602 8 0.4 1488 & K1JT WA4CQG EM72'
msg, timestamp = self.parse_timestamp(msg) msg, timestamp = self.parse_timestamp(msg)
wsjt_msg = msg[17:53].strip() wsjt_msg = msg[17:53].strip()