diff --git a/lib/air_modes_slicer.cc b/lib/air_modes_slicer.cc index 618efc7..04c4dd2 100644 --- a/lib/air_modes_slicer.cc +++ b/lib/air_modes_slicer.cc @@ -180,8 +180,8 @@ int air_modes_slicer::work(int noutput_items, if(rx_packet.crc && (rx_packet.message_type == 11 || rx_packet.message_type == 17)) {continue;} d_payload.str(""); - for(int m = 0; m < 14; m++) { - d_payload << std::setw(2) << std::setfill('0') << unsigned(rx_packet.data[m]); + for(int m = 0; m < packet_length/8; m++) { + d_payload << std::hex << std::setw(2) << std::setfill('0') << unsigned(rx_packet.data[m]); } d_payload << " " << std::setw(6) << rx_packet.crc << " " << std::dec << rx_packet.reference_level diff --git a/python/modes_parse.py b/python/modes_parse.py index 96927e1..60c5b53 100644 --- a/python/modes_parse.py +++ b/python/modes_parse.py @@ -38,13 +38,17 @@ class data_field: #get a particular field from the data def __getitem__(self, fieldname): - if fieldname in self.types[self.get_type()]: #verify it exists in this packet type - if fieldname in self.subfields: - #create a new subfield object and return it - return self.subfields[fieldname](self.get_bits(self.fields[fieldname])) - return self.get_bits(self.fields[fieldname]) + if self.get_type() in self.types: + if fieldname in self.types[self.get_type()]: #verify it exists in this packet type + if fieldname in self.subfields: + #create a new subfield object and return it + return self.subfields[fieldname](self.get_bits(self.fields[fieldname])) + else: + return self.get_bits(self.fields[fieldname]) + else: + raise FieldNotInPacket(fieldname) else: - raise FieldNotInPacket(fieldname) + raise NoHandlerError(self.get_type()) #grab all the fields in the packet as a dict def get_fields(self): @@ -88,7 +92,7 @@ class mb_reply(data_field): bds2 = self.get_bits(self.fields["bds2"]) if bds1 not in (0,1,2,3) or bds2 not in (0,): raise NoHandlerError - return bds1 + return int(bds1) def get_numbits(self): return 56 @@ -146,11 +150,6 @@ class me_reply(data_field): class modes_reply(data_field): def __init__(self, data): data_field.__init__(self, data) -#TODO FIX PARITY FIELDS - self.parity_fields = { - "ap": (33+(self.get_numbits()-56),24), - "pi": (33+(self.get_numbits()-56),24) - } #bitfield definitions according to Mode S spec #(start bit, num bits) @@ -158,7 +157,8 @@ class modes_reply(data_field): "sl": (9,3), "ri": (14,4), "ac": (20,13), "dr": (9,5), "um": (14,6), "id": (20,13), "ca": (6,3), "aa": (9,24), "mv": (33,56), "me": (33,56), "mb": (33,56), "ke": (6,1), - "nd": (7,4), "md": (11,80) + "nd": (7,4), "md": (11,80), "ap": (33,24), "pi": (33,24), + "lap": (88,24), "lpi": (88,24) } #fields in each packet type (DF value) @@ -166,11 +166,11 @@ class modes_reply(data_field): 4: ["df", "fs", "dr", "um", "ac", "ap"], 5: ["df", "fs", "dr", "um", "id", "ap"], 11: ["df", "ca", "aa", "pi"], - 16: ["df", "vs", "sl", "ri", "ac", "mv", "ap"], - 17: ["df", "ca", "aa", "me", "pi"], - 20: ["df", "fs", "dr", "um", "ac", "mb", "ap"], - 21: ["df", "fs", "dr", "um", "id", "mb", "ap"], - 24: ["df", "ke", "nd", "md", "ap"] + 16: ["df", "vs", "sl", "ri", "ac", "mv", "lap"], + 17: ["df", "ca", "aa", "me", "lpi"], + 20: ["df", "fs", "dr", "um", "ac", "mb", "lap"], + 21: ["df", "fs", "dr", "um", "id", "mb", "lap"], + 24: ["df", "ke", "nd", "md", "lap"] } subfields = { "mb": mb_reply, "me": me_reply } #TODO MV @@ -196,83 +196,34 @@ class modes_parse: self.my_location = mypos self.cpr = cpr.cpr_decoder(self.my_location) - def parse0(self, shortdata): - vs = bool(shortdata >> 26 & 0x1) #ground sensor -- airborne when 0 - cc = bool(shortdata >> 25 & 0x1) #crosslink capability, binary - sl = shortdata >> 21 & 0x07 #operating sensitivity of onboard TCAS system. 0 means no TCAS sensitivity reported, 1-7 give TCAS sensitivity - ri = shortdata >> 15 & 0x0F #speed coding: 0 = no onboard TCAS, 1 = NA, 2 = TCAS w/inhib res, 3 = TCAS w/vert only, 4 = TCAS w/vert+horiz, 5-7 = NA, 8 = no max A/S avail, - #9 = A/S <= 75kt, 10 = A/S (75-150]kt, 11 = (150-300]kt, 12 = (300-600]kt, 13 = (600-1200]kt, 14 = >1200kt, 15 = NA + def parse0(self, data): + fields = data.get_fields() + altitude = decode_alt(data["ac"], True) + return [fields["vs"], fields["cc"], fields["sl"], fields["ri"], altitude] - altitude = decode_alt(shortdata & 0x1FFF, True) #bit 13 is set for type 0 + def parse4(self, data): + fields = data.get_fields() + altitude = decode_alt(data["ac"], True) + return [data["fs"], data["dr"], data["um"], altitude] - return [vs, cc, sl, ri, altitude] + def parse5(self, data): + return [data["fs"], data["dr"], data["um"], data["id"]] - def parse4(self, shortdata): - fs = shortdata >> 24 & 0x07 #flight status: 0 is airborne normal, 1 is ground normal, 2 is airborne alert, 3 is ground alert, 4 is alert SPI, 5 is normal SPI - dr = shortdata >> 19 & 0x1F #downlink request: 0 means no req, bit 0 is Comm-B msg rdy bit, bit 1 is TCAS info msg rdy, bit 2 is Comm-B bcast #1 msg rdy, bit2+bit0 is Comm-B bcast #2 msg rdy, - #bit2+bit1 is TCAS info and Comm-B bcast #1 msg rdy, bit2+bit1+bit0 is TCAS info and Comm-B bcast #2 msg rdy, 8-15 N/A, 16-31 req to send N-15 segments - um = shortdata >> 13 & 0x3F #transponder status readouts, no decoding information available - - altitude = decode_alt(shortdata & 0x1FFF, True) - - return [fs, dr, um, altitude] - - - def parse5(self, shortdata): - fs = shortdata >> 24 & 0x07 #flight status: 0 is airborne normal, 1 is ground normal, 2 is airborne alert, 3 is ground alert, 4 is alert SPI, 5 is normal SPI - dr = shortdata >> 19 & 0x1F #downlink request: 0 means no req, bit 0 is Comm-B msg rdy bit, bit 1 is TCAS info msg rdy, bit 2 is Comm-B bcast #1 msg rdy, bit2+bit0 is Comm-B bcast #2 msg rdy, - #bit2+bit1 is TCAS info and Comm-B bcast #1 msg rdy, bit2+bit1+bit0 is TCAS info and Comm-B bcast #2 msg rdy, 8-15 N/A, 16-31 req to send N-15 segments - um = shortdata >> 13 & 0x3F #transponder status readouts, no decoding information available - ident = shortdata & 0x1FFF - - return [fs, dr, um, ident] - - def parse11(self, shortdata, ecc): + def parse11(self, data, ecc): interrogator = ecc & 0x0F - - ca = shortdata >> 13 & 0x3F #capability - icao24 = shortdata & 0xFFFFFF - - return [icao24, interrogator, ca] - - #the Type 17 subtypes are: - #0: No position information - #1: Identification (Category set D) - #2: Identification (Category set C) - #3: "" (B) - #4: "" (A) - #5: Surface position accurate to 7.5m - #6: "" to 25m - #7: "" to 185.2m (0.1nm) - #8: "" above 185.2m - #9: Airborne position to 7.5m - #10-18: Same with less accuracy - #19: Airborne velocity - #20: Airborne position w/GNSS height above earth - #21: same to 25m - #22: same above 25m - #23: Reserved - #24: Reserved for surface system status - #25-27: Reserved - #28: Extended squitter aircraft status - #29: Current/next trajectory change point - #30: Aircraft operational coordination - #31: Aircraft operational status + return [data["aa"], interrogator, data["ca"]] categories = [["NO INFO", "RESERVED", "RESERVED", "RESERVED", "RESERVED", "RESERVED", "RESERVED", "RESERVED"],\ ["NO INFO", "SURFACE EMERGENCY VEHICLE", "SURFACE SERVICE VEHICLE", "FIXED OBSTRUCTION", "RESERVED", "RESERVED", "RESERVED"],\ ["NO INFO", "GLIDER", "BALLOON/BLIMP", "PARACHUTE", "ULTRALIGHT", "RESERVED", "UAV", "SPACECRAFT"],\ ["NO INFO", "LIGHT", "SMALL", "LARGE", "LARGE HIGH VORTEX", "HEAVY", "HIGH PERFORMANCE", "ROTORCRAFT"]] - def parseBDS08(self, shortdata, longdata): - icao24 = shortdata & 0xFFFFFF - subtype = (longdata >> 51) & 0x1F - category = (longdata >> 48) & 0x07 - catstring = self.categories[subtype-1][category] + def parseBDS08(self, data): + catstring = self.categories[data["me"]["ftc"]-1][data["me"]["cat"]] msg = "" for i in range(0, 8): - msg += self.charmap( longdata >> (42-6*i) & 0x3F) + msg += self.charmap( data["me"]["ident"] >> (42-6*i) & 0x3F) return (msg, catstring) def charmap(self, d): @@ -287,16 +238,13 @@ class modes_parse: return retval - def parseBDS05(self, shortdata, longdata): - icao24 = shortdata & 0xFFFFFF + def parseBDS05(self, data): + icao24 = data["aa"] - encoded_lon = longdata & 0x1FFFF - encoded_lat = (longdata >> 17) & 0x1FFFF - cpr_format = (longdata >> 34) & 1 - - enc_alt = (longdata >> 36) & 0x0FFF - - altitude = decode_alt(enc_alt, False) + encoded_lon = data["me"]["lon"] + encoded_lat = data["me"]["lat"] + cpr_format = data["me"]["cpr"] + altitude = decode_alt(data["me"]["alt"], False) [decoded_lat, decoded_lon, rnge, bearing] = self.cpr.decode(icao24, encoded_lat, encoded_lon, cpr_format, 0) @@ -304,17 +252,14 @@ class modes_parse: #welp turns out it looks like there's only 17 bits in the BDS0,6 ground packet after all. - def parseBDS06(self, shortdata, longdata): - icao24 = shortdata & 0xFFFFFF - - encoded_lon = longdata & 0x1FFFF - encoded_lat = (longdata >> 17) & 0x1FFFF - cpr_format = (longdata >> 34) & 1 - - altitude = 0 - + def parseBDS06(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) [decoded_lat, decoded_lon, rnge, bearing] = self.cpr.decode(icao24, encoded_lat, encoded_lon, cpr_format, 1) - return [altitude, decoded_lat, decoded_lon, rnge, bearing] def parseBDS09_0(self, shortdata, longdata): diff --git a/python/modes_print.py b/python/modes_print.py index 904ce6d..b43349d 100644 --- a/python/modes_print.py +++ b/python/modes_print.py @@ -33,12 +33,16 @@ class modes_output_print(modes_parse.modes_parse): [data, ecc, reference, timestamp] = message.split() #TODO FIXME HALP - data = modes_data(long(data, 16)) + data = modes_parse.modes_reply(long(data, 16)) ecc = long(ecc, 16) reference = float(reference) timestamp = float(timestamp) - msgtype = data["df"] + try: + msgtype = data["df"] + except NoHandlerError as err: + print "No handler for msgtype %s" % err.msgtype + return #TODO this is suspect if reference == 0.0: @@ -119,31 +123,31 @@ class modes_output_print(modes_parse.modes_parse): return retstr - def print11(self, shortdata, ecc): - [icao24, interrogator, ca] = self.parse11(shortdata, ecc) + def print11(self, data, ecc): + [icao24, interrogator, ca] = self.parse11(data, ecc) retstr = "Type 11 (all call reply) from " + "%x" % icao24 + " in reply to interrogator " + str(interrogator) return retstr - def print17(self, shortdata, longdata): - icao24 = shortdata & 0xFFFFFF - subtype = (longdata >> 51) & 0x1F; + def print17(self, data): + icao24 = data["aa"] + subtype = data["me"]["ftc"] - retstr = None + retstr = "" if 1 <= subtype <= 4: - (msg, typestring) = self.parseBDS08(shortdata, longdata) + (msg, typestring) = self.parseBDS08(data) retstr = "Type 17 subtype 04 (ident) from " + "%x" % icao24 + " of type " + typestring + " with ident " + msg elif subtype >= 5 and subtype <= 8: - [altitude, decoded_lat, decoded_lon, rnge, bearing] = self.parseBDS06(shortdata, longdata) + [altitude, decoded_lat, decoded_lon, rnge, bearing] = self.parseBDS06(data) if decoded_lat is not None: retstr = "Type 17 subtype 06 (surface report) from " + "%x" % icao24 + " at (" + "%.6f" % decoded_lat + ", " + "%.6f" % decoded_lon + ")" if rnge is not None and bearing is not None: retstr += " (" + "%.2f" % rnge + " @ " + "%.0f" % bearing + ")" elif subtype >= 9 and subtype <= 18: - [altitude, decoded_lat, decoded_lon, rnge, bearing] = self.parseBDS05(shortdata, longdata) + [altitude, decoded_lat, decoded_lon, rnge, bearing] = self.parseBDS05(data) if decoded_lat is not None: retstr = "Type 17 subtype 05 (position report) from " + "%x" % icao24 + " at (" + "%.6f" % decoded_lat + ", " + "%.6f" % decoded_lon + ")" if rnge is not None and bearing is not None: @@ -151,17 +155,18 @@ class modes_output_print(modes_parse.modes_parse): retstr += " at " + str(altitude) + "ft" elif subtype == 19: - subsubtype = (longdata >> 48) & 0x07 - if subsubtype == 0: - [velocity, heading, vert_spd] = self.parseBDS09_0(shortdata, longdata) - retstr = "Type 17 subtype 09-0 (track report) from " + "%x" % icao24 + " with velocity " + "%.0f" % velocity + "kt heading " + "%.0f" % heading + " VS " + "%.0f" % vert_spd + pass +# subsubtype = (longdata >> 48) & 0x07 +# if subsubtype == 0: +# [velocity, heading, vert_spd] = self.parseBDS09_0(shortdata, longdata) +# retstr = "Type 17 subtype 09-0 (track report) from " + "%x" % icao24 + " with velocity " + "%.0f" % velocity + "kt heading " + "%.0f" % heading + " VS " + "%.0f" % vert_spd - elif subsubtype == 1: - [velocity, heading, vert_spd] = self.parseBDS09_1(shortdata, longdata) - retstr = "Type 17 subtype 09-1 (track report) from " + "%x" % icao24 + " with velocity " + "%.0f" % velocity + "kt heading " + "%.0f" % heading + " VS " + "%.0f" % vert_spd +# elif subsubtype == 1: +# [velocity, heading, vert_spd] = self.parseBDS09_1(shortdata, longdata) +# retstr = "Type 17 subtype 09-1 (track report) from " + "%x" % icao24 + " with velocity " + "%.0f" % velocity + "kt heading " + "%.0f" % heading + " VS " + "%.0f" % vert_spd - else: - retstr = "Type 17 subtype 09-%i" % (subsubtype) + " not implemented" +# else: +# retstr = "Type 17 subtype 09-%i" % (subsubtype) + " not implemented" else: retstr = "Type 17 subtype " + str(subtype) + " not implemented"