From 21455c1b231e057bfbdad8a0c41f77176b038876 Mon Sep 17 00:00:00 2001 From: Jakob Ketterl Date: Tue, 29 Aug 2023 01:56:27 +0200 Subject: [PATCH] add a LineBasedModule for the common task of parsing line-by-line input --- csdr/module/__init__.py | 36 ++++++++++++++++++++++++++++++++++++ csdr/module/msk144.py | 37 +++++++------------------------------ owrx/adsb/dump1090.py | 37 +++---------------------------------- 3 files changed, 46 insertions(+), 64 deletions(-) diff --git a/csdr/module/__init__.py b/csdr/module/__init__.py index f2c1f9fa..3ee0d0ec 100644 --- a/csdr/module/__init__.py +++ b/csdr/module/__init__.py @@ -110,6 +110,42 @@ class PickleModule(ThreadModule): pass +class LineBasedModule(ThreadModule, metaclass=ABCMeta): + def __init__(self): + self.retained = bytes() + super().__init__() + + def getInputFormat(self) -> Format: + return Format.CHAR + + def getOutputFormat(self) -> Format: + return Format.CHAR + + def run(self): + while self.doRun: + data = self.reader.read() + if data is None: + self.doRun = False + else: + 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] + + # log all completed lines + for line in lines[0:-1]: + parsed = self.process(line) + if parsed is not None: + self.writer.write(pickle.dumps(parsed)) + + @abstractmethod + def process(self, line: bytes) -> any: + pass + + class PopenModule(AutoStartModule, metaclass=ABCMeta): def __init__(self): self.process = None diff --git a/csdr/module/msk144.py b/csdr/module/msk144.py index 9d1b0023..532ed67f 100644 --- a/csdr/module/msk144.py +++ b/csdr/module/msk144.py @@ -1,6 +1,6 @@ from pycsdr.types import Format from pycsdr.modules import ExecModule -from csdr.module import ThreadModule +from csdr.module import LineBasedModule from owrx.wsjt import WsjtParser, Msk144Profile import pickle @@ -17,40 +17,17 @@ class Msk144Module(ExecModule): ) -class ParserAdapter(ThreadModule): +class ParserAdapter(LineBasedModule): def __init__(self): - self.retained = bytes() self.parser = WsjtParser() self.dialFrequency = 0 + self.profile = Msk144Profile() super().__init__() - def run(self): - profile = Msk144Profile() - - while self.doRun: - data = self.reader.read() - if data is None: - self.doRun = False - else: - 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:]))) - - def getInputFormat(self) -> Format: - return Format.CHAR - - def getOutputFormat(self) -> Format: - return Format.CHAR + def process(self, line: bytes): + # actual messages from msk144decoder should start with "*** " + if line[0:4] == b"*** ": + return self.parser.parse(self.profile, self.dialFrequency, line[4:]) def setDialFrequency(self, frequency: int) -> None: self.dialFrequency = frequency diff --git a/owrx/adsb/dump1090.py b/owrx/adsb/dump1090.py index cd4bda2b..299508d6 100644 --- a/owrx/adsb/dump1090.py +++ b/owrx/adsb/dump1090.py @@ -1,9 +1,8 @@ from pycsdr.modules import ExecModule, Writer, TcpSource from pycsdr.types import Format -from csdr.module import LogWriter, ThreadModule +from csdr.module import LogWriter, LineBasedModule from owrx.socket import getAvailablePort import time -import pickle import logging @@ -51,38 +50,8 @@ class Dump1090Module(ExecModule): self.tcpSource.setWriter(writer) -class RawDeframer(ThreadModule): - def __init__(self): - self.retained = bytes() - super().__init__() - - def getInputFormat(self) -> Format: - return Format.CHAR - - def getOutputFormat(self) -> Format: - return Format.CHAR - - def run(self): - while self.doRun: - data = self.reader.read() - if data is None: - self.doRun = False - else: - 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] - - # log all completed lines - for line in lines[0:-1]: - parsed = self.parse(line) - if parsed is not None: - self.writer.write(pickle.dumps(parsed)) - - def parse(self, line): +class RawDeframer(LineBasedModule): + def process(self, line: bytes): if line.startswith(b'*') and line.endswith(b';') and len(line) in [16, 30]: return bytes.fromhex(line[1:-1].decode()) else: