diff --git a/python/modes_flightgear.py b/python/modes_flightgear.py index 54a0551..a1d51bc 100755 --- a/python/modes_flightgear.py +++ b/python/modes_flightgear.py @@ -34,7 +34,7 @@ class modes_flightgear(modes_parse.modes_parse): msgtype = data["df"] if msgtype == 17: #ADS-B report icao24 = data["aa"] - subtype = data["me"]["sub"] + subtype = data["sub"] if subtype == 4: #ident packet (ident, actype) = self.parseBDS08(data) #select model based on actype @@ -51,7 +51,7 @@ class modes_flightgear(modes_parse.modes_parse): self.update(icao24) elif subtype == 19: #velocity - subsubtype = data["me"]["bds09"]["sub"] + subsubtype = data["sub"] if subsubtype == 0: [velocity, heading, vert_spd, turnrate] = self.parseBDS09_0(data) elif 1 <= subsubtype <= 2: diff --git a/python/modes_parse.py b/python/modes_parse.py index d88d0fc..ba60f39 100644 --- a/python/modes_parse.py +++ b/python/modes_parse.py @@ -30,6 +30,7 @@ from modes_exceptions import * class data_field: def __init__(self, data): self.data = data + self.fields = self.parse() types = { } offset = 1 #field offset applied to all fields. used for offsetting @@ -39,16 +40,24 @@ class data_field: def __getitem__(self, fieldname): mytype = self.get_type() if mytype in self.types: - if fieldname in self.types[mytype]: #verify it exists in this packet type - return self.get_bits(*self.types[mytype][fieldname]) + if fieldname in self.fields: #verify it exists in this packet type + return self.fields[fieldname] else: raise FieldNotInPacket(fieldname) else: raise NoHandlerError(mytype) #grab all the fields in the packet as a dict - def get_fields(self): - return {field: self[field] for field in self.types[self.get_type()]} + #done once on init so you don't have to iterate down every time you grab a field + def parse(self): + fields = {} + for field in self.types[self.get_type()]: + bits = self.types[self.get_type()][field] + if len(bits) == 3: + obj = bits[2](self.get_bits(bits[0], bits[1])) + fields.update(obj.parse()) + fields.update({field: self.get_bits(bits[0], bits[1])}) + return fields def get_type(self): raise NotImplementedError @@ -65,12 +74,7 @@ class data_field: bits = (self.data \ >> (self.get_numbits() - startbit - num + self.offset)) \ & ((1 << num) - 1) - if len(args) == 3: - #construct a subtype from the bit field - return args[2](bits) - else: - #return the bits as a number - return bits + return bits class bds09_reply(data_field): offset = 6 @@ -99,7 +103,7 @@ class bds09_reply(data_field): def get_numbits(self): return 51 - + #type 17 extended squitter data class me_reply(data_field): #types in this format are listed by BDS register @@ -202,12 +206,10 @@ class modes_parse: self.cpr = cpr.cpr_decoder(self.my_location) def parse0(self, data): - fields = data.get_fields() altitude = decode_alt(data["ac"], True) - return [fields["vs"], fields["cc"], fields["sl"], fields["ri"], altitude] + return [data["vs"], data["cc"], data["sl"], data["ri"], altitude] def parse4(self, data): - fields = data.get_fields() altitude = decode_alt(data["ac"], True) return [data["fs"], data["dr"], data["um"], altitude] @@ -224,11 +226,11 @@ class modes_parse: ["NO INFO", "LIGHT", "SMALL", "LARGE", "LARGE HIGH VORTEX", "HEAVY", "HIGH PERFORMANCE", "ROTORCRAFT"]] def parseBDS08(self, data): - catstring = self.categories[data["me"]["ftc"]-1][data["me"]["cat"]] + catstring = self.categories[data["ftc"]-1][data["cat"]] msg = "" for i in range(0, 8): - msg += self.charmap( data["me"]["ident"] >> (42-6*i) & 0x3F) + msg += self.charmap(data["ident"] >> (42-6*i) & 0x3F) return (msg, catstring) def charmap(self, d): @@ -246,10 +248,10 @@ class modes_parse: def parseBDS05(self, data): icao24 = data["aa"] - encoded_lon = data["me"]["lon"] - encoded_lat = data["me"]["lat"] - cpr_format = data["me"]["cpr"] - altitude = decode_alt(data["me"]["alt"], False) + encoded_lon = data["lon"] + encoded_lat = data["lat"] + cpr_format = data["cpr"] + altitude = decode_alt(data["alt"], False) [decoded_lat, decoded_lon, rnge, bearing] = self.cpr.decode(icao24, encoded_lat, encoded_lon, cpr_format, 0) @@ -260,28 +262,27 @@ class modes_parse: def parseBDS06(self, data): icao24 = data["aa"] - encoded_lon = data["me"]["lon"] - encoded_lat = data["me"]["lat"] - cpr_format = data["me"]["cpr"] - ground_track = data["me"]["gtk"] * 360. / 128 + encoded_lon = data["lon"] + encoded_lat = data["lat"] + cpr_format = data["cpr"] + ground_track = data["gtk"] * 360. / 128 [decoded_lat, decoded_lon, rnge, bearing] = self.cpr.decode(icao24, encoded_lat, encoded_lon, cpr_format, 1) return [ground_track, decoded_lat, decoded_lon, rnge, bearing] def parseBDS09_0(self, data): #0: ["sub", "dew", "vew", "dns", "vns", "str", "tr", "svr", "vr"], - bdsobj = data["me"]["bds09"] - vert_spd = bdsobj["vr"] * 32 - ud = bool(bdsobj["dvr"]) + vert_spd = data["vr"] * 32 + ud = bool(data["dvr"]) if ud: vert_spd = 0 - vert_spd - turn_rate = bdsobj["tr"] * 15/62 - rl = bdsobj["str"] + turn_rate = data["tr"] * 15/62 + rl = data["str"] if rl: turn_rate = 0 - turn_rate - ns_vel = bdsobj["vns"] - 1 - ns = bool(bdsobj["dns"]) - ew_vel = bdsobj["vew"] - 1 - ew = bool(bdsobj["dew"]) + ns_vel = data["vns"] - 1 + ns = bool(data["dns"]) + ew_vel = data["vew"] - 1 + ew = bool(data["dew"]) velocity = math.hypot(ns_vel, ew_vel) if ew: @@ -296,21 +297,20 @@ class modes_parse: def parseBDS09_1(self, data): #1: ["sub", "icf", "ifr", "nuc", "dew", "vew", "dns", "vns", "vrsrc", "dvr", "vr", "dhd", "hd"], - bdsobj = data["me"]["bds09"] - alt_geo_diff = bdsobj["hd"] * 25 - above_below = bool(bdsobj["dhd"]) + alt_geo_diff = data["hd"] * 25 + above_below = bool(data["dhd"]) if above_below: alt_geo_diff = 0 - alt_geo_diff; - vert_spd = float(bdsobj["vr"] - 1) * 64 - ud = bool(bdsobj["dvr"]) + vert_spd = float(data["vr"] - 1) * 64 + ud = bool(data["dvr"]) if ud: vert_spd = 0 - vert_spd - vert_src = bool(bdsobj["vrsrc"]) - ns_vel = float(bdsobj["vns"]) - ns = bool(bdsobj["dns"]) - ew_vel = float(bdsobj["vew"]) - ew = bool(bdsobj["dew"]) - subtype = bdsobj["sub"] + vert_src = bool(data["vrsrc"]) + ns_vel = float(data["vns"]) + ns = bool(data["dns"]) + ew_vel = float(data["vew"]) + ew = bool(data["dew"]) + subtype = data["sub"] if subtype == 0x02: ns_vel <<= 2 ew_vel <<= 2 @@ -333,12 +333,12 @@ class modes_parse: def parseBDS62(self, data): eps_strings = ["NO EMERGENCY", "GENERAL EMERGENCY", "LIFEGUARD/MEDICAL", "FUEL EMERGENCY", "NO COMMUNICATIONS", "UNLAWFUL INTERFERENCE", "RESERVED", "RESERVED"] - return eps_strings[data["me"]["eps"]] + return eps_strings[data["eps"]] def parseMB_id(self, data): #bds1 == 2, bds2 == 0 msg = "" for i in range(0, 8): - msg += self.charmap( data["mb"]["ais"] >> (42-6*i) & 0x3F) + msg += self.charmap( data["ais"] >> (42-6*i) & 0x3F) return (msg) def parseMB_TCAS_resolutions(self, data): @@ -348,7 +348,7 @@ class modes_parse: 49: "DON'T CLIMB >1000FPM", 50: "DON'T CLIMB >2000FPM", 51: "TURN LEFT", 52: "TURN RIGHT", 53: "DON'T TURN LEFT", 54: "DON'T TURN RIGHT"} rac_bits = {55: "DON'T DESCEND", 56: "DON'T CLIMB", 57: "DON'T TURN LEFT", 58: "DON'T TURN RIGHT"} - ara = data["mb"]["ara"] + ara = data["ara"] #check to see which bits are set resolutions = "" for bit, name in ara_bits: @@ -368,9 +368,9 @@ class modes_parse: #3: {"bds1": (33,4), "bds2": (37,4), "ara": (41,14), "rac": (55,4), "rat": (59,1), # "mte": (60,1), "tti": (61,2), "tida": (63,13), "tidr": (76,7), "tidb": (83,6)} (resolutions, complements) = self.parseMB_TCAS_resolutions(data) - return (resolutions, complements, data["mb"]["rat"], data["mb"]["mte"], data["mb"]["tcas"]["tid"]) + return (resolutions, complements, data["rat"], data["mte"], data["tid"]) def parseMB_TCAS_threatloc(self, data): #bds1==3, bds2==0, TTI==2 (resolutions, complements) = self.parseMB_TCAS_resolutions(data) - threat_alt = decode_alt(data["mb"]["tcas"]["tida"], True) - return (resolutions, complements, data["mb"]["rat"], data["mb"]["mte"], threat_alt, data["mb"]["tcas"]["tidr"], data["mb"]["tcas"]["tidb"]) + threat_alt = decode_alt(data["tida"], True) + return (resolutions, complements, data["rat"], data["mte"], threat_alt, data["tidr"], data["tidb"]) diff --git a/python/modes_print.py b/python/modes_print.py index 5aac968..a194c51 100644 --- a/python/modes_print.py +++ b/python/modes_print.py @@ -135,7 +135,7 @@ class modes_output_print(modes_parse.modes_parse): def print17(self, data): icao24 = data["aa"] - subtype = data["me"]["ftc"] + subtype = data["ftc"] retstr = None @@ -157,7 +157,7 @@ class modes_output_print(modes_parse.modes_parse): retstr += " at " + str(altitude) + "ft" elif subtype == 19: - subsubtype = data["me"]["bds09"]["sub"] + subsubtype = data["sub"] if subsubtype == 0: [velocity, heading, vert_spd] = self.parseBDS09_0(data) retstr = "Type 17 subtype 09-0 (track report) from %x with velocity %.0fkt heading %.0f VS %.0f" % (icao24, velocity, heading, vert_spd) @@ -182,9 +182,8 @@ class modes_output_print(modes_parse.modes_parse): [fs, dr, um, alt] = self.parse4(data) else: [fs, dr, um, ident] = self.parse5(data) - mb_fields = data["mb"].get_fields() - bds1 = mb_fields["bds1"] - bds2 = mb_fields["bds2"] + bds1 = data["bds1"] + bds2 = data["bds2"] if bds2 != 0: retstr = "No handler for BDS2 == %i from %x" % (bds2, ecc) @@ -193,12 +192,12 @@ class modes_output_print(modes_parse.modes_parse): retstr = "No handler for BDS1 == 0 from %x" % ecc elif bds1 == 1: retstr = "Type 20 link capability report from %x: ACS: 0x%x, BCS: 0x%x, ECS: 0x%x, continues %i" \ - % (ecc, mb_fields["acs"], mb_fields["bcs"], mb_fields["ecs"], mb_fields["cfs"]) + % (ecc, data["acs"], data["bcs"], data["ecs"], data["cfs"]) elif bds1 == 2: retstr = "Type 20 identification from %x with text %s" % (ecc, self.parseMB_id(data)) elif bds2 == 3: retstr = "TCAS report from %x: " % ecc - tti = mb_fields["tcas"].get_type() + tti = data["tti"] if tti == 1: (resolutions, complements, rat, mte, threat_id) = self.parseMB_TCAS_threatid(data) retstr += "threat ID: %x advised: %s complement: %s" % (threat_id, resolutions, complements) diff --git a/python/modes_sbs1.py b/python/modes_sbs1.py index ca38407..28e1430 100644 --- a/python/modes_sbs1.py +++ b/python/modes_sbs1.py @@ -159,7 +159,7 @@ class modes_output_sbs1(modes_parse.modes_parse): def pp17(self, data): icao24 = data["aa"] aircraft_id = self.get_aircraft_id(icao24) - subtype = data["me"]["ftc"] + subtype = data["ftc"] retstr = None #we'll get better timestamps later, hopefully with actual VRT time @@ -192,7 +192,7 @@ class modes_output_sbs1(modes_parse.modes_parse): elif subtype == 19: # Airborne velocity measurements # WRONG (heading, vert_spd), Is this still true? - subsubtype = data["me"]["bds09"]["sub"] + subsubtype = data["sub"] if subsubtype == 0: [velocity, heading, vert_spd] = self.parseBDS09_0(data) retstr = "MSG,4,0,%i,%06X,%i,%s,%s,%s,%s,,,%.1f,%.1f,,,%i,,,,,\n" % (aircraft_id, icao24, aircraft_id+100, datestr, timestr, datestr, timestr, velocity, heading, vert_spd) diff --git a/python/modes_sql.py b/python/modes_sql.py index 2c42899..944bcbf 100644 --- a/python/modes_sql.py +++ b/python/modes_sql.py @@ -88,7 +88,7 @@ class modes_output_sql(modes_parse.modes_parse): def sql17(self, data): icao24 = data["aa"] - subtype = data["me"]["ftc"] + subtype = data["ftc"] retstr = None @@ -112,7 +112,7 @@ class modes_output_sql(modes_parse.modes_parse): retstr = "INSERT INTO positions (icao, seen, alt, lat, lon) VALUES (" + "%i" % icao24 + ", datetime('now'), " + str(altitude) + ", " + "%.6f" % decoded_lat + ", " + "%.6f" % decoded_lon + ")" elif subtype == 19: - subsubtype = data["me"]["bds09"]["sub"] + subsubtype = data["sub"] if subsubtype == 0: [velocity, heading, vert_spd] = self.parseBDS09_0(data) retstr = "INSERT INTO vectors (icao, seen, speed, heading, vertical) VALUES (" + "%i" % icao24 + ", datetime('now'), " + "%.0f" % velocity + ", " + "%.0f" % heading + ", " + "%.0f" % vert_spd + ")";