def adsb_decode_all(n=None): print "===== Decode all ADS-B sample data=====" import csv f = open('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 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 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 onMessage(data): if data: rawData = RawData(data) if rawData.downlinkformat == 17 and len(rawData.frame) == 30: icao = adsb.icao(rawData.frame[1:29]) log.info("Raw Message Received: %s" % str(rawData.frame)) __DATA_OUTPUT.addData(rawData.frame) if not icao in __RAW_BUFFER: __RAW_BUFFER[icao] = MessageBuffer(icao=icao) __RAW_BUFFER[icao].addRawData(rawData) if __RAW_BUFFER[icao].isComplete(): log.info("Complete Message Received: %s" % str(__RAW_BUFFER[icao])) adsbInfo = ADSBInfo.createFromMessageBuffer(__RAW_BUFFER[icao]) log.info("Processed Complete Message: %s" % str(__RAW_BUFFER[icao])) __DATA_UPLOADER.addADSBInfo(adsbInfo) else: log.info("Invalid Raw Message Received: %s" % str(rawData.frame))
def test_adsb_icao(): assert adsb.icao("8D406B902015A678D4D220AA4BDA") == "406B90"
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