From 7719070885d2f5e3162e4c77cfbc3149561da046 Mon Sep 17 00:00:00 2001 From: Marat Fayzullin Date: Mon, 11 Sep 2023 21:33:19 -0400 Subject: [PATCH] Switching TextParser to LineBasedModule base. --- csdr/chain/toolbox.py | 2 +- owrx/aircraft.py | 13 +++---- owrx/modes.py | 10 +++--- owrx/toolbox.py | 79 ++++++++++++------------------------------- 4 files changed, 34 insertions(+), 70 deletions(-) diff --git a/csdr/chain/toolbox.py b/csdr/chain/toolbox.py index d92d7438..e3b75a00 100644 --- a/csdr/chain/toolbox.py +++ b/csdr/chain/toolbox.py @@ -150,7 +150,7 @@ class AdsbDemodulator(ServiceDemodulator, DialFrequencyReceiver): self.parser = AdsbParser(service=service) workers = [ Convert(Format.COMPLEX_FLOAT, Format.COMPLEX_SHORT), - Dump1090Module(rawOutput = not service), + Dump1090Module(rawOutput = True), self.parser, ] # Connect all the workers diff --git a/owrx/aircraft.py b/owrx/aircraft.py index 30f0cd73..a5fbe8f7 100644 --- a/owrx/aircraft.py +++ b/owrx/aircraft.py @@ -1,3 +1,4 @@ +from csdr.module import LineBasedModule from owrx.toolbox import TextParser, ColorCache from owrx.map import Map, LatLngLocation from owrx.aprs import getSymbolData @@ -219,7 +220,7 @@ class AircraftManager(object): # Base class for aircraft message parsers. # class AircraftParser(TextParser): - def __init__(self, filePrefix: str, service: bool = False): + def __init__(self, filePrefix: str = None, service: bool = False): super().__init__(filePrefix=filePrefix, service=service) def parseAcars(self, data, out): @@ -403,14 +404,14 @@ class Vdl2Parser(AircraftParser): # class AdsbParser(AircraftParser): def __init__(self, service: bool = False): - super().__init__(filePrefix="ADSB", service=service) + super().__init__(filePrefix=None, service=service) self.smode_parser = ModeSParser() - def parse(self, msg: str): + def process(self, line: bytes) -> any: # If it is a valid Mode-S message... - if msg.startswith("*") and msg.endswith(";") and len(msg) in [16, 30]: + if line.startswith(b"*") and line.endswith(b";") and len(line) in [16, 30]: # Parse Mode-S message - out = self.smode_parser.process(bytes.fromhex(msg[1:-1])) + out = self.smode_parser.process(bytes.fromhex(line[1:-1].decode("utf-8"))) #logger.debug("@@@ PARSE OUT: {0}".format(out)) # Only consider position and identification reports for now if "identification" in out or "groundspeed" in out or ("lat" in out and "lon" in out): @@ -478,7 +479,7 @@ class AcarsParser(AircraftParser): data = json.loads(msg) pm = Config.get() ts = data["timestamp"] - logger.debug("@@@ ACARS: {0}".format(data)) + #logger.debug("@@@ ACARS: {0}".format(data)) # Collect basic data first out = { "mode" : "ACARS", diff --git a/owrx/modes.py b/owrx/modes.py index 4215e6b9..5e7ae133 100644 --- a/owrx/modes.py +++ b/owrx/modes.py @@ -135,9 +135,9 @@ class Modes(object): DigitalMode("bpsk31", "BPSK31", underlying=["usb"]), DigitalMode("bpsk63", "BPSK63", underlying=["usb"]), # Testing jketterl's RTTY decoder - DigitalMode("jkrtty170", "RTTY 45/170", underlying=["usb", "lsb"]), - DigitalMode("jkrtty450", "RTTY 50N/450", underlying=["lsb", "usb"]), - DigitalMode("jkrtty85", "RTTY 50N/85", underlying=["lsb", "usb"]), + DigitalMode("jkrtty170", "RTTY-170 / 45", underlying=["usb", "lsb"]), + DigitalMode("jkrtty450", "RTTY-450 / 50N", underlying=["usb", "lsb"]), + DigitalMode("jkrtty85", "RTTY-85 / 50N", underlying=["usb", "lsb"]), WsjtMode("ft8", "FT8"), WsjtMode("ft4", "FT4"), WsjtMode("jt65", "JT65"), @@ -205,14 +205,14 @@ class Modes(object): DigitalMode( "selcall", "SelCall", - underlying=["empty"], + underlying=["nfm"], requirements=["selcall"], squelch=True ), DigitalMode( "zvei", "Zvei", - underlying=["empty"], + underlying=["nfm"], requirements=["selcall"], squelch=True ), diff --git a/owrx/toolbox.py b/owrx/toolbox.py index 7e84cd0c..e05a0cd1 100644 --- a/owrx/toolbox.py +++ b/owrx/toolbox.py @@ -1,6 +1,6 @@ from owrx.storage import Storage from owrx.config import Config -from csdr.module import ThreadModule +from csdr.module import LineBasedModule from pycsdr.types import Format from datetime import datetime import pickle @@ -45,8 +45,8 @@ class ColorCache: del self.colorBuf[old_id] -class TextParser(ThreadModule): - def __init__(self, filePrefix: str = "LOG", service: bool = False): +class TextParser(LineBasedModule): + def __init__(self, filePrefix: str = None, service: bool = False): self.service = service self.frequency = 0 self.data = bytearray(b'') @@ -88,7 +88,7 @@ class TextParser(ThreadModule): def writeFile(self, data): # If no file open, create and open a new file - if self.file is None: + if self.file is None and self.filePfx is not None: self.newFile(Storage().makeFileName(self.filePfx+"-{0}", self.frequency)) # If file open now... if self.file is not None: @@ -127,68 +127,31 @@ class TextParser(ThreadModule): # By default, do not parse, just return the string return msg - # ONLY IMPLEMENT THIS FUNCTION WHEN REPORTING LOCATION FROM SERVICE! - def updateLocation(self, msg: str): - # By default, do nothing - pass - def run(self): logger.debug("%s starting..." % self.myName()) - # Run while there is input data - while self.doRun: - # Read input data - inp = self.reader.read() - # Terminate if no input data - if inp is None: - logger.debug("%s exiting..." % self.myName()) - self.doRun = False - break - # Add read data to the buffer - self.data = self.data + inp.tobytes() - # Process buffer contents - out = self.process() - # Keep processing while there is input to parse - while out is not None: - if len(out)>0: - if isinstance(out, bytes): - self.writer.write(out) - elif isinstance(out, str): - self.writer.write(bytes(out, 'utf-8')) - else: - self.writer.write(pickle.dumps(out)) - out = self.process() + super().run() + logger.debug("%s exiting..." % self.myName()) - def process(self): + def process(self, line: bytes) -> any: # No result yet out = None - # Search for end-of-line - eol = self.data.find(b'\n') + try: + msg = line.decode(encoding="utf-8", errors="replace") + #logger.debug("%s: %s" % (self.myName(), msg)) + # If running as a service with a log file... + if self.service and self.filePfx is not None: + # Write message into open log file, including end-of-line + self.writeFile(line) + self.writeFile(b"\n") + else: + # Let parse() function do its thing + out = self.parse(msg) - # If found end-of-line... - if eol>=0: - try: - msg = self.data[0:eol].decode(encoding="utf-8", errors="replace") - #logger.debug("%s: %s" % (self.myName(), msg)) - # If running as a service... - if self.service: - # Write message into open log file, including end-of-line - self.writeFile(self.data[0:eol+1]) - # Optionally, parse and report location - self.updateLocation(msg) - # Empty result - out = {} - else: - # Let parse() function do its thing - out = self.parse(msg) + except Exception as exptn: + logger.debug("%s: Exception parsing: %s" % (self.myName(), str(exptn))) - except Exception as exptn: - logger.debug("%s: Exception parsing: %s" % (self.myName(), str(exptn))) - - # Remove parsed message from input, including end-of-line - del self.data[0:eol+1] - - # Return parsed result or None if no result yet + # Return parsed result if any return out