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.module.msk144 import Msk144Module
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
@ -21,17 +21,22 @@ class AudioChopperDemodulator(ServiceDemodulator, DialFrequencyReceiver):
self.chopper.setDialFrequency(frequency)
class Msk144Demodulator(ServiceDemodulator):
class Msk144Demodulator(ServiceDemodulator, DialFrequencyReceiver):
def __init__(self):
self.parser = ParserAdapter()
workers = [
Convert(Format.FLOAT, Format.SHORT),
Msk144Module(),
self.parser,
]
super().__init__(workers)
def getFixedAudioRate(self) -> int:
return 12000
def setDialFrequency(self, frequency: int) -> None:
self.parser.setDialFrequency(frequency)
class PacketDemodulator(ServiceDemodulator, DialFrequencyReceiver):
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
self.reader.resume()
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):
if self.process is not None:

View File

@ -1,5 +1,10 @@
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):
@ -11,3 +16,45 @@ class Msk144Module(PopenModule):
def getOutputFormat(self) -> Format:
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]
class Msk144Profile(WsjtProfile):
def getMode(self):
return "MSK144"
def getInterval(self):
return 15
def decoder_commandline(self, file):
return None
class WsjtParser(AudioChopperParser):
def parse(self, profile: WsjtProfile, freq: int, raw_msg: bytes):
try:
@ -366,6 +377,8 @@ class Jt9Decoder(Decoder):
# '0003 -4 0.4 1762 # CQ R2ABM KO85'
# fst4 sample
# '**** -23 0.6 3023 ` <...> <...> R 591631 BI53PV'
# MSK144 sample
# '221602 8 0.4 1488 & K1JT WA4CQG EM72'
msg, timestamp = self.parse_timestamp(msg)
wsjt_msg = msg[17:53].strip()