Optimizing aircraft data processing, using bytes everywhere.
This commit is contained in:
parent
ca95040f21
commit
02cb33b69c
|
|
@ -223,6 +223,20 @@ class AircraftParser(TextParser):
|
||||||
def __init__(self, filePrefix: str = None, service: bool = False):
|
def __init__(self, filePrefix: str = None, service: bool = False):
|
||||||
super().__init__(filePrefix=filePrefix, service=service)
|
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):
|
def parseAcars(self, data, out):
|
||||||
# Collect data
|
# Collect data
|
||||||
out["type"] = "ACARS frame"
|
out["type"] = "ACARS frame"
|
||||||
|
|
@ -243,7 +257,7 @@ class HfdlParser(AircraftParser):
|
||||||
def __init__(self, service: bool = False):
|
def __init__(self, service: bool = False):
|
||||||
super().__init__(filePrefix="HFDL", service=service)
|
super().__init__(filePrefix="HFDL", service=service)
|
||||||
|
|
||||||
def parse(self, msg: str):
|
def parseAircraft(self, msg: bytes):
|
||||||
# Expect JSON data in text form
|
# Expect JSON data in text form
|
||||||
data = json.loads(msg)
|
data = json.loads(msg)
|
||||||
pm = Config.get()
|
pm = Config.get()
|
||||||
|
|
@ -267,8 +281,7 @@ class HfdlParser(AircraftParser):
|
||||||
# Parse MPDU if present
|
# Parse MPDU if present
|
||||||
if "mpdu" in data["hfdl"]:
|
if "mpdu" in data["hfdl"]:
|
||||||
self.parseMpdu(data["hfdl"]["mpdu"], out)
|
self.parseMpdu(data["hfdl"]["mpdu"], out)
|
||||||
# Update aircraft database with the new data
|
# Done
|
||||||
AircraftManager.getSharedInstance().update(out)
|
|
||||||
return out
|
return out
|
||||||
|
|
||||||
def parseSpdu(self, data, out):
|
def parseSpdu(self, data, out):
|
||||||
|
|
@ -331,7 +344,7 @@ class Vdl2Parser(AircraftParser):
|
||||||
def __init__(self, service: bool = False):
|
def __init__(self, service: bool = False):
|
||||||
super().__init__(filePrefix="VDL2", service=service)
|
super().__init__(filePrefix="VDL2", service=service)
|
||||||
|
|
||||||
def parse(self, msg: str):
|
def parseAircraft(self, msg: bytes):
|
||||||
# Expect JSON data in text form
|
# Expect JSON data in text form
|
||||||
data = json.loads(msg)
|
data = json.loads(msg)
|
||||||
pm = Config.get()
|
pm = Config.get()
|
||||||
|
|
@ -346,8 +359,7 @@ class Vdl2Parser(AircraftParser):
|
||||||
# Parse AVLC if present
|
# Parse AVLC if present
|
||||||
if "avlc" in data["vdl2"]:
|
if "avlc" in data["vdl2"]:
|
||||||
self.parseAvlc(data["vdl2"]["avlc"], out)
|
self.parseAvlc(data["vdl2"]["avlc"], out)
|
||||||
# Update aircraft database with the new data
|
# Done
|
||||||
AircraftManager.getSharedInstance().update(out)
|
|
||||||
return out
|
return out
|
||||||
|
|
||||||
def parseAvlc(self, data, out):
|
def parseAvlc(self, data, out):
|
||||||
|
|
@ -407,11 +419,12 @@ class AdsbParser(AircraftParser):
|
||||||
super().__init__(filePrefix=None, service=service)
|
super().__init__(filePrefix=None, service=service)
|
||||||
self.smode_parser = ModeSParser()
|
self.smode_parser = ModeSParser()
|
||||||
|
|
||||||
def process(self, line: bytes) -> any:
|
def parseAircraft(self, msg: bytes):
|
||||||
# If it is a valid Mode-S message...
|
# 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
|
# 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))
|
#logger.debug("@@@ PARSE OUT: {0}".format(out))
|
||||||
# Only consider position and identification reports for now
|
# Only consider position and identification reports for now
|
||||||
if "identification" in out or "groundspeed" in out or ("lat" in out and "lon" in out):
|
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"])
|
out["course"] = round(out["heading"])
|
||||||
elif "groundtrack" in out:
|
elif "groundtrack" in out:
|
||||||
out["course"] = round(out["groundtrack"])
|
out["course"] = round(out["groundtrack"])
|
||||||
# Update aircraft database with the new data
|
# Done
|
||||||
AircraftManager.getSharedInstance().update(out)
|
|
||||||
return out
|
return out
|
||||||
|
|
||||||
# No data parsed
|
# No data parsed
|
||||||
return {}
|
return None
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
@ -474,7 +486,7 @@ class AcarsParser(AircraftParser):
|
||||||
"eta" : "eta",
|
"eta" : "eta",
|
||||||
}
|
}
|
||||||
|
|
||||||
def parse(self, msg: str):
|
def parseAircraft(self, msg: bytes):
|
||||||
# Expect JSON data in text form
|
# Expect JSON data in text form
|
||||||
data = json.loads(msg)
|
data = json.loads(msg)
|
||||||
pm = Config.get()
|
pm = Config.get()
|
||||||
|
|
@ -492,6 +504,5 @@ class AcarsParser(AircraftParser):
|
||||||
for key in self.attrMap:
|
for key in self.attrMap:
|
||||||
if key in data:
|
if key in data:
|
||||||
out[self.attrMap[key]] = data[key]
|
out[self.attrMap[key]] = data[key]
|
||||||
# Update aircraft database with the new data
|
# Done
|
||||||
AircraftManager.getSharedInstance().update(out)
|
|
||||||
return out
|
return out
|
||||||
|
|
|
||||||
|
|
@ -122,10 +122,9 @@ class TextParser(LineBasedModule):
|
||||||
def getUtcTime(self) -> str:
|
def getUtcTime(self) -> str:
|
||||||
return datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')
|
return datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')
|
||||||
|
|
||||||
# DERIVED CLASSES SHOULD IMPLEMENT THIS FUNCTION!
|
# By default, do not parse
|
||||||
def parse(self, msg: str):
|
def parse(self, msg: bytes):
|
||||||
# By default, do not parse, just return the string
|
return None
|
||||||
return msg
|
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
logger.debug("%s starting..." % self.myName())
|
logger.debug("%s starting..." % self.myName())
|
||||||
|
|
@ -137,21 +136,20 @@ class TextParser(LineBasedModule):
|
||||||
out = None
|
out = None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
msg = line.decode(encoding="utf-8", errors="replace")
|
#logger.debug("%s: %s" % (self.myName(), str(line)))
|
||||||
#logger.debug("%s: %s" % (self.myName(), msg))
|
|
||||||
# If running as a service with a log file...
|
# If running as a service with a log file...
|
||||||
if self.service and self.filePfx is not None:
|
if self.service and self.filePfx is not None:
|
||||||
# Write message into open log file, including end-of-line
|
# Write message into open log file, including end-of-line
|
||||||
self.writeFile(line)
|
self.writeFile(line)
|
||||||
self.writeFile(b"\n")
|
self.writeFile(b"\n")
|
||||||
# Let parse() function do its thing
|
# Let parse() function do its thing
|
||||||
out = self.parse(msg)
|
out = self.parse(line)
|
||||||
|
|
||||||
except Exception as exptn:
|
except Exception as exptn:
|
||||||
logger.debug("%s: Exception parsing: %s" % (self.myName(), str(exptn)))
|
logger.debug("%s: Exception parsing: %s" % (self.myName(), str(exptn)))
|
||||||
|
|
||||||
# Return parsed result if any
|
# Return parsed result, ignore result in service mode
|
||||||
return out
|
return out if not self.service else None
|
||||||
|
|
||||||
|
|
||||||
class IsmParser(TextParser):
|
class IsmParser(TextParser):
|
||||||
|
|
@ -161,7 +159,7 @@ class IsmParser(TextParser):
|
||||||
# Construct parent object
|
# Construct parent object
|
||||||
super().__init__(filePrefix="ISM", service=service)
|
super().__init__(filePrefix="ISM", service=service)
|
||||||
|
|
||||||
def parse(self, msg: str):
|
def parse(self, msg: bytes):
|
||||||
# Do not parse in service mode
|
# Do not parse in service mode
|
||||||
if self.service:
|
if self.service:
|
||||||
return None
|
return None
|
||||||
|
|
@ -197,14 +195,14 @@ class PageParser(TextParser):
|
||||||
# Construct parent object
|
# Construct parent object
|
||||||
super().__init__(filePrefix="PAGE", service=service)
|
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
|
# Steer message to POCSAG or FLEX parser, do not parse if service
|
||||||
if self.service:
|
if self.service:
|
||||||
return None
|
return None
|
||||||
elif msg.startswith("POCSAG"):
|
elif msg.startswith(b"POCSAG"):
|
||||||
return self.parsePocsag(msg)
|
return self.parsePocsag(msg.decode('utf-8', 'replace'))
|
||||||
elif msg.startswith("FLEX"):
|
elif msg.startswith(b"FLEX"):
|
||||||
return self.parseFlex(msg)
|
return self.parseFlex(msg.decode('utf-8', 'replace'))
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
@ -323,11 +321,12 @@ class SelCallParser(TextParser):
|
||||||
# Construct parent object
|
# Construct parent object
|
||||||
super().__init__(filePrefix="SELCALL", service=service)
|
super().__init__(filePrefix="SELCALL", service=service)
|
||||||
|
|
||||||
def parse(self, msg: str):
|
def parse(self, msg: bytes):
|
||||||
# Do not parse in service mode
|
# Do not parse in service mode
|
||||||
if self.service:
|
if self.service:
|
||||||
return None
|
return None
|
||||||
# Parse SELCALL messages
|
# Parse SELCALL messages
|
||||||
|
msg = msg.decode('utf-8', 'replace')
|
||||||
dec = None
|
dec = None
|
||||||
out = ""
|
out = ""
|
||||||
r = self.reSplit.split(msg)
|
r = self.reSplit.split(msg)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue