def adsb_decode_all(n=None): print "===== Decode all ADS-B sample data=====" import csv f = open('tests/adsb.csv', 'rt') msg0 = None msg1 = None for i, r in enumerate(csv.reader(f)): if n and i > n: break ts = r[0] m = r[1] icao = adsb.icao(m) tc = adsb.typecode(m) if 1 <= tc <= 4: print ts, m, icao, tc, adsb.category(m), adsb.callsign(m) if tc == 19: print ts, m, icao, tc, adsb.velocity(m) if 5 <= tc <= 18: if adsb.oe_flag(m): msg1 = m t1 = ts else: msg0 = m t0 = ts if msg0 and msg1: pos = adsb.position(msg0, msg1, t0, t1) alt = adsb.altitude(m) print ts, m, icao, tc, pos, alt
def createFromMessageBuffer(messageBuffer): info = None if messageBuffer.isComplete(): latLng = adsb.position(messageBuffer.dataPositionEven[0].frame[1:29], messageBuffer.dataPositionOdd[0].frame[1:29], messageBuffer.dataPositionEven[0].timestamp, messageBuffer.dataPositionOdd[0].timestamp) velocity = adsb.velocity(messageBuffer.dataVelocity[0].frame[1:29]) if latLng: info = ADSBInfo( collector=COLLECTOR_ID, modeSCode=adsb.icao(messageBuffer.dataId[0].frame[1:29]), callsign=adsb.callsign(messageBuffer.dataId[0].frame[1:29]).replace("_", ""), latitude=latLng[0], longitude=latLng[1], altitude=adsb.altitude(messageBuffer.dataPositionEven[0].frame[1:29]), horizontalVelocity=velocity[0], groundTrackHeading=velocity[1], verticalVelocity=velocity[2], messagDataId=messageBuffer.dataId[0].frame[1:29], messagDataPositionEven=messageBuffer.dataId[0].frame[1:29], messagDataPositionOdd=messageBuffer.dataId[0].frame[1:29], messagDataVelocity=messageBuffer.dataId[0].frame[1:29], timestamp=int(systemTimestamp() * 1000), timestampSent=int(systemTimestamp() * 1000) ) messageBuffer.clearPositionMessages() return info
def adsb_decode_all(n=None): print("===== Decode ADS-B sample data=====") import csv f = open('tests/data/sample_data_adsb.csv', 'rt') msg0 = None msg1 = None for i, r in enumerate(csv.reader(f)): if n and i > n: break ts = r[0] m = r[1] icao = adsb.icao(m) tc = adsb.typecode(m) if 1 <= tc <= 4: print(ts, m, icao, tc, adsb.category(m), adsb.callsign(m)) if tc == 19: print(ts, m, icao, tc, adsb.velocity(m)) if 5 <= tc <= 18: if adsb.oe_flag(m): msg1 = m t1 = ts else: msg0 = m t0 = ts if msg0 and msg1: pos = adsb.position(msg0, msg1, t0, t1) alt = adsb.altitude(m) print(ts, m, icao, tc, pos, alt)
def test_adsb_callsign(): assert adsb.callsign("8D406B902015A678D4D220AA4BDA") == "EZY85MH_"
def tell(msg: str) -> None: from pyModeS import common, adsb, commb, bds def _print(label, value, unit=None): print("%20s: " % label, end="") print("%s " % value, end="") if unit: print(unit) else: print() df = common.df(msg) icao = common.icao(msg) _print("Message", msg) _print("ICAO address", icao) _print("Downlink Format", df) if df == 17: _print("Protocol", "Mode-S Extended Squitter (ADS-B)") tc = common.typecode(msg) if 1 <= tc <= 4: # callsign callsign = adsb.callsign(msg) _print("Type", "Identitification and category") _print("Callsign:", callsign) if 5 <= tc <= 8: # surface position _print("Type", "Surface position") oe = adsb.oe_flag(msg) msgbin = common.hex2bin(msg) cprlat = common.bin2int(msgbin[54:71]) / 131072.0 cprlon = common.bin2int(msgbin[71:88]) / 131072.0 v = adsb.surface_velocity(msg) _print("CPR format", "Odd" if oe else "Even") _print("CPR Latitude", cprlat) _print("CPR Longitude", cprlon) _print("Speed", v[0], "knots") _print("Track", v[1], "degrees") if 9 <= tc <= 18: # airborne position _print("Type", "Airborne position (with barometric altitude)") alt = adsb.altitude(msg) oe = adsb.oe_flag(msg) msgbin = common.hex2bin(msg) cprlat = common.bin2int(msgbin[54:71]) / 131072.0 cprlon = common.bin2int(msgbin[71:88]) / 131072.0 _print("CPR format", "Odd" if oe else "Even") _print("CPR Latitude", cprlat) _print("CPR Longitude", cprlon) _print("Altitude", alt, "feet") if tc == 19: _print("Type", "Airborne velocity") spd, trk, vr, t = adsb.velocity(msg) types = {"GS": "Ground speed", "TAS": "True airspeed"} _print("Speed", spd, "knots") _print("Track", trk, "degrees") _print("Vertical rate", vr, "feet/minute") _print("Type", types[t]) if 20 <= tc <= 22: # airborne position _print("Type", "Airborne position (with GNSS altitude)") alt = adsb.altitude(msg) oe = adsb.oe_flag(msg) msgbin = common.hex2bin(msg) cprlat = common.bin2int(msgbin[54:71]) / 131072.0 cprlon = common.bin2int(msgbin[71:88]) / 131072.0 _print("CPR format", "Odd" if oe else "Even") _print("CPR Latitude", cprlat) _print("CPR Longitude", cprlon) _print("Altitude", alt, "feet") if df == 20: _print("Protocol", "Mode-S Comm-B altitude reply") _print("Altitude", common.altcode(msg), "feet") if df == 21: _print("Protocol", "Mode-S Comm-B identity reply") _print("Squawk code", common.idcode(msg)) if df == 20 or df == 21: labels = { "BDS10": "Data link capability", "BDS17": "GICB capability", "BDS20": "Aircraft identification", "BDS30": "ACAS resolution", "BDS40": "Vertical intention report", "BDS50": "Track and turn report", "BDS60": "Heading and speed report", "BDS44": "Meteorological routine air report", "BDS45": "Meteorological hazard report", "EMPTY": "[No information available]", } BDS = bds.infer(msg, mrar=True) if BDS in labels.keys(): _print("BDS", "%s (%s)" % (BDS, labels[BDS])) else: _print("BDS", BDS) if BDS == "BDS20": callsign = commb.cs20(msg) _print("Callsign", callsign) if BDS == "BDS40": _print("MCP target alt", commb.selalt40mcp(msg), "feet") _print("FMS Target alt", commb.selalt40fms(msg), "feet") _print("Pressure", commb.p40baro(msg), "millibar") if BDS == "BDS50": _print("Roll angle", commb.roll50(msg), "degrees") _print("Track angle", commb.trk50(msg), "degrees") _print("Track rate", commb.rtrk50(msg), "degree/second") _print("Ground speed", commb.gs50(msg), "knots") _print("True airspeed", commb.tas50(msg), "knots") if BDS == "BDS60": _print("Megnatic Heading", commb.hdg60(msg), "degrees") _print("Indicated airspeed", commb.ias60(msg), "knots") _print("Mach number", commb.mach60(msg)) _print("Vertical rate (Baro)", commb.vr60baro(msg), "feet/minute") _print("Vertical rate (INS)", commb.vr60ins(msg), "feet/minute") if BDS == "BDS44": _print("Wind speed", commb.wind44(msg)[0], "knots") _print("Wind direction", commb.wind44(msg)[1], "degrees") _print("Temperature 1", commb.temp44(msg)[0], "Celsius") _print("Temperature 2", commb.temp44(msg)[1], "Celsius") _print("Pressure", commb.p44(msg), "hPa") _print("Humidity", commb.hum44(msg), "%") _print("Turbulence", commb.turb44(msg)) if BDS == "BDS45": _print("Turbulence", commb.turb45(msg)) _print("Wind shear", commb.ws45(msg)) _print("Microbust", commb.mb45(msg)) _print("Icing", commb.ic45(msg)) _print("Wake vortex", commb.wv45(msg)) _print("Temperature", commb.temp45(msg), "Celsius") _print("Pressure", commb.p45(msg), "hPa") _print("Radio height", commb.rh45(msg), "feet")
def test_adsb_callsign(): assert adsb.callsign("8D406B902015A678D4D220AA4BDA") == "EZY85MH_"
def message(self, msg): # Printout of statistics if self.signal_hup == 1: self.logstats() self.signal_hup = 0 ret_dict = {} ret_dict['ret'] = 0 ret_dict['type'] = "" self.msgs_curr_total = self.msgs_curr_total + 1 if len(msg) == 26 or len(msg) == 40: # Some version of dump1090 have the 12 first characters used w/ # some date (timestamp ?). E.g. sdbr245 feeding flightradar24. # Strip 12 first characters. msg = msg[12:] if len(msg) < 28: # Message length 112 bits self.msgs_curr_short = self.msgs_curr_short + 1 else: self.msgs_curr_len28 = self.msgs_curr_len28 + 1 ret_dict['crc'] = self.check_msg(msg) if ret_dict['crc']: self.parity_check_ok = self.parity_check_ok + 1 else: self.parity_check_ko = self.parity_check_ko + 1 # Do not manage messages with bad CRC if ret_dict['crc'] is not True: raise ValueError("CrcKO") dfmt = common.df(msg) ret_dict['dfmt'] = dfmt self.df[dfmt] = self.df[dfmt] + 1 ret_dict['ic'] = common.icao(msg) if dfmt in [17, 18]: # Downlink format 17 or 18 tc = common.typecode(msg) ret_dict['tc'] = tc self.tc[tc] = self.tc[tc] + 1 lat_ref = float(self.params["lat"]) long_ref = float(self.params["long"]) if tc == 4: # Aircraft identification self.msgs_discovered = self.msgs_discovered + 1 ret_dict['type'] = "CS" ret_dict['cs'] = adsb.callsign(msg) ca = adsb_ca(msg) ret_dict['ca'] = ca_msg[ca] self.ca[ca] = self.ca[ca] + 1 elif 9 <= tc <= 18: self.msgs_discovered = self.msgs_discovered + 1 ret_dict['type'] = "LB" ret_dict['altb'] = adsb.altitude(msg) (lat, long) = adsb.position_with_ref(msg, lat_ref, long_ref) ret_dict['lat'] = lat ret_dict['long'] = long elif tc == 19: self.msgs_discovered = self.msgs_discovered + 1 ret_dict['type'] = "VH" _dict = adsb.velocity(msg) if _dict is None: raise ValueError("AdsbVelocity") (ret_dict['speed'], ret_dict['head'], ret_dict['rocd'], var) = _dict if ret_dict['head'] is None: raise ValueError("AdsbHeading") if ret_dict['rocd'] is None: raise ValueError("AdsbRocd") elif 20 <= tc <= 22: self.msgs_discovered = self.msgs_discovered + 1 ret_dict['type'] = "LG" ret_dict['altg'] = adsb.altitude(msg) (lat, long) = adsb.position_with_ref(msg, lat_ref, long_ref) ret_dict['lat'] = lat ret_dict['long'] = long elif dfmt in [5, 21]: self.msgs_discovered = self.msgs_discovered + 1 ret_dict['type'] = "SQ" ret_dict['sq'] = common.idcode(msg) if dfmt in [0, 4, 16, 20]: self.msgs_discovered = self.msgs_discovered + 1 ret_dict['type'] = "AL" _alt = common.altcode(msg) alt = _alt if _alt is not None else 0 ret_dict['alt'] = alt return ret_dict
def _parse(self, msg_ascii): if not msg_ascii or msg_ascii[0] != '*': raise ValueError msg_hex = msg_ascii[1:].split(';', 1)[0] try: icao = adsb.icao(msg_hex).lower() downlink_format = df(msg_hex) type_code = adsb.typecode(msg_hex) except: raise ValueError # version 0 is assumed, so populate it on initialisation ac_data = self.positions.get(icao, {"version": 0}) if downlink_format == 17 or downlink_format == 18: # An aircraft airborne position message has downlink format 17 (or 18) with # type code from 9 to 18 (baro altitude) or 20 to 22 (GNSS altitude) # ref https://mode-s.org/decode/adsb/airborne-position.html if ac_data.get("version", None) == 1 and ac_data.get("nic_s", None): ac_data["nic"] = adsb.nic_v1(msg_hex, ac_data["nic_s"]) if (type_code >= 1 and type_code <= 4): # Slightly normalise the callsign - it's supposed to only be [0-9A-Z] # with space padding. PyModeS uses _ padding, which I think is an older # version of the spec. ac_data["callsign"] = adsb.callsign(msg_hex).upper().replace("_", " ")[:8] ac_data["emitter_category"] = adsb.category(msg_hex) elif (type_code >= 9 and type_code <= 18) or (type_code >= 20 and type_code <= 22): nuc_p = None if ac_data.get("version", None) == 0: # In ADSB version 0, the type code encodes the nuc_p (navigational # uncertianty category - position) value via this magic lookup table nuc_p_lookup = { 9: 9, 10: 8, 11: 7, 12: 6, 13: 5, 14: 4, 15: 3, 16: 2, 17: 1, 18: 0, 20: 9, 21: 8, 22: 0, } ac_data["nuc_p"] = nuc_p_lookup.get(type_code, None) elif ac_data.get("version", None) == 2: ac_data["nic_b"] = adsb.nic_b(msg_hex) if ac_data.get("version", None) == 2 and "nic_a" in ac_data.keys() and "nic_c" in ac_data.keys(): nic_a = ac_data["nic_a"] nic_c = ac_data["nic_c"] ac_data["nic"] = adsb.nic_v2(msg_hex, nic_a, nic_c) # Aircraft position if not self.gps.is_fresh(): #print("aircraft: not updating {0} df={1} tc={2} as my GPS position is unknown ({3})".format(icao, downlink_format, type_code, msg_hex)) raise ValueError # Use the known location of the receiver to calculate the aircraft position # from one messsage try: my_latitude, my_longitude = self.gps.position() except NoFixError: # For testing my_latitude, my_longitude = (51.519559, -0.114227) # a rare race condition #raise ValueError ac_lat, ac_lon = adsb.position_with_ref(msg_hex, my_latitude, my_longitude) #print("aircraft: update {0} df={1} tc={2} {3}, {4} ({5})".format(icao, downlink_format, type_code, ac_lat, ac_lon, msg_hex)) ac_data["lat"] = ac_lat ac_data["lon"] = ac_lon elif type_code == 19: # From the docs: returns speed (kt) ground track or heading (degree), # rate of climb/descent (ft/min), speed type (‘GS’ for ground speed, # ‘AS’ for airspeed), direction source (‘true_north’ for ground track / # true north as refrence, ‘mag_north’ for magnetic north as reference), # rate of climb/descent source (‘Baro’ for barometer, ‘GNSS’ for GNSS # constellation). if ac_data.get("version", None) == 1 or ac_data.get("version", None) == 2: ac_data["nac_v"] = adsb.nac_v(msg_hex) try: (speed, track, climb, speed_source, track_source, climb_source) = adsb.velocity(msg_hex, rtn_sources=True) ac_data["speed_h"] = speed ac_data["track"] = track ac_data["speed_v"] = climb ac_data["speed_h_source"] = speed_source ac_data["track_source"] = track_source ac_data["speed_v_source"] = climb_source except TypeError: # adsb.velocity can return None raise ValueError elif type_code == 31: # Operational status version = adsb.version(msg_hex) nic_s = adsb.nic_s(msg_hex) # v0 nuc_p is determined by type_code above if version == 1: try: # Is this the right place for nucp? The docs say yes, but one error # I've received says 8d3c5ee6f81300000039283c21cf: Not a surface # position message (5<TC<8), airborne position message (8<TC<19), # or airborne position with GNSS height (20<TC<22) nuc_p = adsb.nuc_p(msg_hex) nuc_v = adsb.nuc_v(msg_hex) except RuntimeError as e: print("aircraft: error parsing v1 NUC: {}".format(e)) raise ValueError ac_data["nic_s"] = nic_s ac_data["nuc_p"] = nuc_p ac_data["nuc_v"] = nuc_v ac_data["nac_p"] = adsb.nac_p(msg_hex) ac_data["sil"] = adsb.sil(msg_hex, version) elif version == 2: ac_data["nac_p"] = adsb.nac_p(msg_hex) (nic_a, nic_c) = adsb.nic_a_c(msg_hex) ac_data["nic_a"] = nic_a ac_data["nic_c"] = nic_c ac_data["sil"] = adsb.sil(msg_hex, version) ac_data["version"] = version ac_data["nic_s"] = nic_s else: raise ValueError elif downlink_format == 4 or downlink_format == 20: altitude = adsb_common.altcode(msg_hex) ac_data["altitude"] = altitude else: # unsupported message raise ValueError ac_data["updated"] = datetime.now() self.positions[icao] = ac_data
def tell(msg: str) -> None: from pyModeS import common, adsb, commb, bds def _print(label, value, unit=None): print("%20s: " % label, end="") print("%s " % value, end="") if unit: print(unit) else: print() df = common.df(msg) icao = common.icao(msg) _print("Message", msg) _print("ICAO address", icao) _print("Downlink Format", df) if df == 17: _print("Protocol", "Mode-S Extended Squitter (ADS-B)") tc = common.typecode(msg) if 1 <= tc <= 4: # callsign callsign = adsb.callsign(msg) _print("Type", "Identification and category") _print("Callsign:", callsign) if 5 <= tc <= 8: # surface position _print("Type", "Surface position") oe = adsb.oe_flag(msg) msgbin = common.hex2bin(msg) cprlat = common.bin2int(msgbin[54:71]) / 131072.0 cprlon = common.bin2int(msgbin[71:88]) / 131072.0 v = adsb.surface_velocity(msg) _print("CPR format", "Odd" if oe else "Even") _print("CPR Latitude", cprlat) _print("CPR Longitude", cprlon) _print("Speed", v[0], "knots") _print("Track", v[1], "degrees") if 9 <= tc <= 18: # airborne position _print("Type", "Airborne position (with barometric altitude)") alt = adsb.altitude(msg) oe = adsb.oe_flag(msg) msgbin = common.hex2bin(msg) cprlat = common.bin2int(msgbin[54:71]) / 131072.0 cprlon = common.bin2int(msgbin[71:88]) / 131072.0 _print("CPR format", "Odd" if oe else "Even") _print("CPR Latitude", cprlat) _print("CPR Longitude", cprlon) _print("Altitude", alt, "feet") if tc == 19: _print("Type", "Airborne velocity") spd, trk, vr, t = adsb.velocity(msg) types = {"GS": "Ground speed", "TAS": "True airspeed"} _print("Speed", spd, "knots") _print("Track", trk, "degrees") _print("Vertical rate", vr, "feet/minute") _print("Type", types[t]) if 20 <= tc <= 22: # airborne position _print("Type", "Airborne position (with GNSS altitude)") alt = adsb.altitude(msg) oe = adsb.oe_flag(msg) msgbin = common.hex2bin(msg) cprlat = common.bin2int(msgbin[54:71]) / 131072.0 cprlon = common.bin2int(msgbin[71:88]) / 131072.0 _print("CPR format", "Odd" if oe else "Even") _print("CPR Latitude", cprlat) _print("CPR Longitude", cprlon) _print("Altitude", alt, "feet") if tc == 29: # target state and status _print("Type", "Target State and Status") subtype = common.bin2int((common.hex2bin(msg)[32:])[5:7]) _print("Subtype", subtype) tcas_operational = adsb.tcas_operational(msg) types = {0: "Not Engaged", 1: "Engaged"} tcas_operational_types = {0: "Not Operational", 1: "Operational"} if subtype == 0: emergency_types = { 0: "No emergency", 1: "General emergency", 2: "Lifeguard/medical emergency", 3: "Minimum fuel", 4: "No communications", 5: "Unlawful interference", 6: "Downed aircraft", 7: "Reserved" } vertical_horizontal_types = { 1: "Acquiring mode", 2: "Capturing/Maintaining mode" } tcas_ra_types = {0: "Not active", 1: "Active"} alt, alt_source, alt_ref = adsb.target_altitude(msg) angle, angle_type, angle_source = adsb.target_angle(msg) vertical_mode = adsb.vertical_mode(msg) horizontal_mode = adsb.horizontal_mode(msg) tcas_ra = adsb.tcas_ra(msg) emergency_status = adsb.emergency_status(msg) _print("Target altitude", alt, "feet") _print("Altitude source", alt_source) _print("Altitude reference", alt_ref) _print("Angle", angle, "°") _print("Angle Type", angle_type) _print("Angle Source", angle_source) _print("Vertical mode", vertical_horizontal_types[vertical_mode]) _print("Horizontal mode", vertical_horizontal_types[horizontal_mode]) _print("TCAS/ACAS", tcas_operational_types[tcas_operational]) _print("TCAS/ACAS RA", tcas_ra_types[tcas_ra]) _print("Emergency status", emergency_types[emergency_status]) else: alt, alt_source = adsb.selected_altitude(msg) baro = adsb.baro_pressure_setting(msg) hdg = adsb.selected_heading(msg) autopilot = adsb.autopilot(msg) vnav = adsb.vnav_mode(msg) alt_hold = adsb.altitude_hold_mode(msg) app = adsb.approach_mode(msg) lnav = adsb.lnav_mode(msg) _print("Selected altitude", alt, "feet") _print("Altitude source", alt_source) _print("Barometric pressure setting", baro, "millibars") _print("Selected Heading", hdg, "°") if not (common.bin2int((common.hex2bin(msg)[32:])[46]) == 0): _print("Autopilot", types[autopilot]) _print("VNAV mode", types[vnav]) _print("Altitude hold mode", types[alt_hold]) _print("Approach mode", types[app]) _print("TCAS/ACAS", tcas_operational_types[tcas_operational]) _print("LNAV mode", types[lnav]) if df == 20: _print("Protocol", "Mode-S Comm-B altitude reply") _print("Altitude", common.altcode(msg), "feet") if df == 21: _print("Protocol", "Mode-S Comm-B identity reply") _print("Squawk code", common.idcode(msg)) if df == 20 or df == 21: labels = { "BDS10": "Data link capability", "BDS17": "GICB capability", "BDS20": "Aircraft identification", "BDS30": "ACAS resolution", "BDS40": "Vertical intention report", "BDS50": "Track and turn report", "BDS60": "Heading and speed report", "BDS44": "Meteorological routine air report", "BDS45": "Meteorological hazard report", "EMPTY": "[No information available]", } BDS = bds.infer(msg, mrar=True) if BDS in labels.keys(): _print("BDS", "%s (%s)" % (BDS, labels[BDS])) else: _print("BDS", BDS) if BDS == "BDS20": callsign = commb.cs20(msg) _print("Callsign", callsign) if BDS == "BDS40": _print("MCP target alt", commb.selalt40mcp(msg), "feet") _print("FMS Target alt", commb.selalt40fms(msg), "feet") _print("Pressure", commb.p40baro(msg), "millibar") if BDS == "BDS50": _print("Roll angle", commb.roll50(msg), "degrees") _print("Track angle", commb.trk50(msg), "degrees") _print("Track rate", commb.rtrk50(msg), "degree/second") _print("Ground speed", commb.gs50(msg), "knots") _print("True airspeed", commb.tas50(msg), "knots") if BDS == "BDS60": _print("Megnatic Heading", commb.hdg60(msg), "degrees") _print("Indicated airspeed", commb.ias60(msg), "knots") _print("Mach number", commb.mach60(msg)) _print("Vertical rate (Baro)", commb.vr60baro(msg), "feet/minute") _print("Vertical rate (INS)", commb.vr60ins(msg), "feet/minute") if BDS == "BDS44": _print("Wind speed", commb.wind44(msg)[0], "knots") _print("Wind direction", commb.wind44(msg)[1], "degrees") _print("Temperature 1", commb.temp44(msg)[0], "Celsius") _print("Temperature 2", commb.temp44(msg)[1], "Celsius") _print("Pressure", commb.p44(msg), "hPa") _print("Humidity", commb.hum44(msg), "%") _print("Turbulence", commb.turb44(msg)) if BDS == "BDS45": _print("Turbulence", commb.turb45(msg)) _print("Wind shear", commb.ws45(msg)) _print("Microbust", commb.mb45(msg)) _print("Icing", commb.ic45(msg)) _print("Wake vortex", commb.wv45(msg)) _print("Temperature", commb.temp45(msg), "Celsius") _print("Pressure", commb.p45(msg), "hPa") _print("Radio height", commb.rh45(msg), "feet")
def get_all(msg: str) -> dict: from pyModeS import common, adsb, commb, bds _dict = {} def push(key, data, unit=None): _dict[key] = data df = common.df(msg) icao = common.icao(msg) push("message", msg) push("icao", icao) push("downlink_format", df) if df == 17: push("protocol", "Mode-S Extended Squitter (ADS-B)") tc = common.typecode(msg) if 1 <= tc <= 4: # callsign callsign = adsb.callsign(msg) push("type", "Identitification and category") push("callsign:", callsign) if 5 <= tc <= 8: # surface position push("type", "Surface position") oe = adsb.oe_flag(msg) msgbin = common.hex2bin(msg) cprlat = common.bin2int(msgbin[54:71]) / 131072.0 cprlon = common.bin2int(msgbin[71:88]) / 131072.0 v = adsb.surface_velocity(msg) push("cpr_format", "Odd" if oe else "Even") push("cpr_latitude", cprlat) push("cpr_longitude", cprlon) push("speed", v[0] * 1.85200, "km") push("track", v[1], "degrees") if 9 <= tc <= 18: # airborne position push("type", "Airborne position (with barometric altitude)") alt = adsb.altitude(msg) oe = adsb.oe_flag(msg) msgbin = common.hex2bin(msg) cprlat = common.bin2int(msgbin[54:71]) / 131072.0 cprlon = common.bin2int(msgbin[71:88]) / 131072.0 push("cpr_format", "Odd" if oe else "Even") push("cpr_latitude", cprlat) push("cpr_longitude", cprlon) push("altitude", alt, "feet") if tc == 19: push("type", "Airborne velocity") spd, trk, vr, t = adsb.velocity(msg) types = {"GS": "Ground speed", "TAS": "True airspeed"} push("speed", spd * 1.85200, "km") push("track", trk, "degrees") push("vertical rate", vr, "feet/minute") push("type", types[t]) if 20 <= tc <= 22: # airborne position push("type", "Airborne position (with GNSS altitude)") alt = adsb.altitude(msg) oe = adsb.oe_flag(msg) msgbin = common.hex2bin(msg) cprlat = common.bin2int(msgbin[54:71]) / 131072.0 cprlon = common.bin2int(msgbin[71:88]) / 131072.0 push("cpr_format", "Odd" if oe else "Even") push("cpr_latitude", cprlat) push("cpr_longitude", cprlon) push("altitude", alt, "feet") if tc == 29: # target state and status push("type", "Target State and Status") subtype = common.bin2int((common.hex2bin(msg)[32:])[5:7]) push("subtype", subtype) tcas_operational = adsb.tcas_operational(msg) types = {0: "Not Engaged", 1: "Engaged"} tcas_operational_types = {0: "Not Operational", 1: "Operational"} if subtype == 0: emergency_types = { 0: "No emergency", 1: "General emergency", 2: "Lifeguard/medical emergency", 3: "Minimum fuel", 4: "No communications", 5: "Unlawful interference", 6: "Downed aircraft", 7: "Reserved" } vertical_horizontal_types = { 1: "Acquiring mode", 2: "Capturing/Maintaining mode" } tcas_ra_types = {0: "Not active", 1: "Active"} altitude = adsb.target_altitude(msg) if altitude is not None: alt, alt_source, alt_ref = altitude angle, angle_type, angle_source = adsb.target_angle(msg) vertical_mode = adsb.vertical_mode(msg) horizontal_mode = adsb.horizontal_mode(msg) tcas_ra = adsb.tcas_ra(msg) emergency_status = adsb.emergency_status(msg) push("target_altitude", alt, "feet") push("altitude_source", alt_source) push("altitude_reference", alt_ref) push("angle", angle, "°") push("angle Type", angle_type) push("angle Source", angle_source) push("vertical mode", vertical_horizontal_types[vertical_mode]) push("horizontal mode", vertical_horizontal_types[horizontal_mode]) push("TCAS/ACAS", tcas_operational_types[tcas_operational]) push("TCAS/ACAS_RA", tcas_ra_types[tcas_ra]) push("emergency_status", emergency_types[emergency_status]) else: alt, alt_source = adsb.selected_altitude(msg) baro = adsb.baro_pressure_setting(msg) hdg = adsb.selected_heading(msg) autopilot = adsb.autopilot(msg) vnav = adsb.vnav_mode(msg) alt_hold = adsb.altitude_hold_mode(msg) app = adsb.approach_mode(msg) lnav = adsb.lnav_mode(msg) push("selected_altitude", alt, "feet") push("altitude_source", alt_source) push("barometric_pressure_setting", baro, "millibars") push("selected_Heading", hdg, "°") if not (common.bin2int((common.hex2bin(msg)[32:])[46]) == 0): push("autopilot", types[autopilot]) push("VNAV_mode", types[vnav]) push("altitude_hold_mode", types[alt_hold]) push("approach_mode", types[app]) push("TCAS/ACAS", tcas_operational_types[tcas_operational]) push("LNAV_mode", types[lnav]) if df == 20: push("protocol", "Mode-S Comm-B altitude reply") push("altitude", common.altcode(msg), "feet") if df == 21: push("protocol", "Mode-S Comm-B identity reply") push("squawk_code", common.idcode(msg)) if df == 20 or df == 21: labels = { "BDS10": "Data link capability", "BDS17": "GICB capability", "BDS20": "Aircraft identification", "BDS30": "ACAS resolution", "BDS40": "Vertical intention report", "BDS50": "Track and turn report", "BDS60": "Heading and speed report", "BDS44": "Meteorological routine air report", "BDS45": "Meteorological hazard report", "EMPTY": "[No information available]", } BDS = bds.infer(msg, mrar=True) if BDS in labels.keys(): push("BDS", "%s (%s)" % (BDS, labels[BDS])) else: push("BDS", BDS) if BDS == "BDS20": callsign = commb.cs20(msg) push("callsign", callsign) if BDS == "BDS40": push("MCP_target_alt", commb.selalt40mcp(msg), "feet") push("FMS_Target_alt", commb.selalt40fms(msg), "feet") push("pressure", commb.p40baro(msg), "millibar") if BDS == "BDS50": push("roll_angle", commb.roll50(msg), "degrees") push("track_angle", commb.trk50(msg), "degrees") push("track_rate", commb.rtrk50(msg), "degree/second") push("ground_speed", commb.gs50(msg) * 1.85200, "km") push("true_airspeed", commb.tas50(msg) * 1.85200, "km") if BDS == "BDS60": push("megnatic Heading", commb.hdg60(msg), "degrees") push("indicated airspeed", commb.ias60(msg) * 1.85200, "km") push("mach number", commb.mach60(msg)) push("vertical rate (Baro)", commb.vr60baro(msg), "feet/minute") push("vertical rate (INS)", commb.vr60ins(msg), "feet/minute") if BDS == "BDS44": push("wind_speed", commb.wind44(msg)[0] * 1.85200, "km") push("wind_direction", commb.wind44(msg)[1], "degrees") push("temperature_1", commb.temp44(msg)[0], "Celsius") push("temperature_2", commb.temp44(msg)[1], "Celsius") push("pressure", commb.p44(msg), "hPa") push("humidity", commb.hum44(msg), "%") push("turbulence", commb.turb44(msg)) if BDS == "BDS45": push("turbulence", commb.turb45(msg)) push("wind_shear", commb.ws45(msg)) push("microbust", commb.mb45(msg)) push("icing", commb.ic45(msg)) push("wake_vortex", commb.wv45(msg)) push("temperature", commb.temp45(msg), "Celsius") push("pressure", commb.p45(msg), "hPa") push("radio_height", commb.rh45(msg), "feet") return _dict