diff --git a/owrx/aircraft.py b/owrx/aircraft.py index a5fbe8f7..f268960a 100644 --- a/owrx/aircraft.py +++ b/owrx/aircraft.py @@ -223,6 +223,20 @@ class AircraftParser(TextParser): def __init__(self, filePrefix: str = None, service: bool = False): super().__init__(filePrefix=filePrefix, service=service) + def parse(self, msg: bytes): + # Parse incoming message via mode-specific function + out = self.parseAircraft(msg) + # Update aircraft database with the new data + if out is not None: + AircraftManager.getSharedInstance().update(out) + # Done + return out + + # Mode-specific parse function + def parseAircraft(self, msg: bytes): + return None + + # Common function to parse ACARS subframes in HFDL/VDL2/etc def parseAcars(self, data, out): # Collect data out["type"] = "ACARS frame" @@ -243,7 +257,7 @@ class HfdlParser(AircraftParser): def __init__(self, service: bool = False): super().__init__(filePrefix="HFDL", service=service) - def parse(self, msg: str): + def parseAircraft(self, msg: bytes): # Expect JSON data in text form data = json.loads(msg) pm = Config.get() @@ -267,8 +281,7 @@ class HfdlParser(AircraftParser): # Parse MPDU if present if "mpdu" in data["hfdl"]: self.parseMpdu(data["hfdl"]["mpdu"], out) - # Update aircraft database with the new data - AircraftManager.getSharedInstance().update(out) + # Done return out def parseSpdu(self, data, out): @@ -331,7 +344,7 @@ class Vdl2Parser(AircraftParser): def __init__(self, service: bool = False): super().__init__(filePrefix="VDL2", service=service) - def parse(self, msg: str): + def parseAircraft(self, msg: bytes): # Expect JSON data in text form data = json.loads(msg) pm = Config.get() @@ -346,8 +359,7 @@ class Vdl2Parser(AircraftParser): # Parse AVLC if present if "avlc" in data["vdl2"]: self.parseAvlc(data["vdl2"]["avlc"], out) - # Update aircraft database with the new data - AircraftManager.getSharedInstance().update(out) + # Done return out def parseAvlc(self, data, out): @@ -407,11 +419,12 @@ class AdsbParser(AircraftParser): super().__init__(filePrefix=None, service=service) self.smode_parser = ModeSParser() - def process(self, line: bytes) -> any: + def parseAircraft(self, msg: bytes): # If it is a valid Mode-S message... - if line.startswith(b"*") and line.endswith(b";") and len(line) in [16, 30]: + if msg.startswith(b"*") and msg.endswith(b";") and len(msg) in [16, 30]: # Parse Mode-S message - out = self.smode_parser.process(bytes.fromhex(line[1:-1].decode("utf-8"))) + msg = msg[1:-1].decode('utf-8', 'replace') + out = self.smode_parser.process(bytes.fromhex(msg)) #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): @@ -451,12 +464,11 @@ class AdsbParser(AircraftParser): out["course"] = round(out["heading"]) elif "groundtrack" in out: out["course"] = round(out["groundtrack"]) - # Update aircraft database with the new data - AircraftManager.getSharedInstance().update(out) + # Done return out # No data parsed - return {} + return None # @@ -474,7 +486,7 @@ class AcarsParser(AircraftParser): "eta" : "eta", } - def parse(self, msg: str): + def parseAircraft(self, msg: bytes): # Expect JSON data in text form data = json.loads(msg) pm = Config.get() @@ -492,6 +504,5 @@ class AcarsParser(AircraftParser): for key in self.attrMap: if key in data: out[self.attrMap[key]] = data[key] - # Update aircraft database with the new data - AircraftManager.getSharedInstance().update(out) + # Done return out diff --git a/owrx/toolbox.py b/owrx/toolbox.py index 5981e790..fc0a3609 100644 --- a/owrx/toolbox.py +++ b/owrx/toolbox.py @@ -122,10 +122,9 @@ class TextParser(LineBasedModule): def getUtcTime(self) -> str: return datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S') - # DERIVED CLASSES SHOULD IMPLEMENT THIS FUNCTION! - def parse(self, msg: str): - # By default, do not parse, just return the string - return msg + # By default, do not parse + def parse(self, msg: bytes): + return None def run(self): logger.debug("%s starting..." % self.myName()) @@ -137,21 +136,20 @@ class TextParser(LineBasedModule): out = None try: - msg = line.decode(encoding="utf-8", errors="replace") - #logger.debug("%s: %s" % (self.myName(), msg)) + #logger.debug("%s: %s" % (self.myName(), str(line))) # 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") # Let parse() function do its thing - out = self.parse(msg) + out = self.parse(line) except Exception as exptn: logger.debug("%s: Exception parsing: %s" % (self.myName(), str(exptn))) - # Return parsed result if any - return out + # Return parsed result, ignore result in service mode + return out if not self.service else None class IsmParser(TextParser): @@ -161,7 +159,7 @@ class IsmParser(TextParser): # Construct parent object super().__init__(filePrefix="ISM", service=service) - def parse(self, msg: str): + def parse(self, msg: bytes): # Do not parse in service mode if self.service: return None @@ -197,14 +195,14 @@ class PageParser(TextParser): # Construct parent object super().__init__(filePrefix="PAGE", service=service) - def parse(self, msg: str): + def parse(self, msg: bytes): # Steer message to POCSAG or FLEX parser, do not parse if service if self.service: return None - elif msg.startswith("POCSAG"): - return self.parsePocsag(msg) - elif msg.startswith("FLEX"): - return self.parseFlex(msg) + elif msg.startswith(b"POCSAG"): + return self.parsePocsag(msg.decode('utf-8', 'replace')) + elif msg.startswith(b"FLEX"): + return self.parseFlex(msg.decode('utf-8', 'replace')) else: return None @@ -323,11 +321,12 @@ class SelCallParser(TextParser): # Construct parent object super().__init__(filePrefix="SELCALL", service=service) - def parse(self, msg: str): + def parse(self, msg: bytes): # Do not parse in service mode if self.service: return None # Parse SELCALL messages + msg = msg.decode('utf-8', 'replace') dec = None out = "" r = self.reSplit.split(msg)