def correct_single_bit_error(msg): """Attempts to correct a bit-flip error in an ADS-B message. Parameters ---------- msg : str The hex-string ADS-B message. Returns ------- str If a solution is found, returns the corrected ADS-B message. Returns None if no solution found. """ num = int(msg, 16) bit_length = len(bin(num)[2:]) for k in range(bit_length): test_num = num ^ (1 << k) test_msg = hex(test_num)[2:] # CRC check for long message if (pms.crc(test_msg) == 0): print('*', end='', flush=True) return test_msg # CRC check for short message elif (pms.crc(test_msg[:14]) == 0): print('*', end='', flush=True) return test_msg[:14] return None
def handle_messages(self, messages): # get the current date file today = str(datetime.datetime.now().strftime("%Y%m%d")) csvfile = dataroot + 'ADSB_RAW_%s.csv' % today with open(csvfile, 'a') as f: writer = csv.writer(f) for msg, ts in messages: if len(msg) < 28: continue df = pms.df(msg) if df != 17: continue if '1' in pms.crc(msg): continue addr = pms.adsb.icao(msg) tc = pms.adsb.typecode(msg) line = ['%.6f'%ts, addr, '%02d'%tc, msg] writer.writerow(line)
def handle_messages(self, messages): # get the current date file today = str(datetime.datetime.now().strftime("%Y%m%d")) csvfile = dataroot + 'ADSB_RAW_%s.csv' % today for msg, ts in messages: if len(msg) < 28: continue df = pms.df(msg) if df != 17: continue if '1' in pms.crc(msg): continue addr = pms.adsb.icao(msg) tc = pms.adsb.typecode(msg) line = ['%.6f' % ts, addr, '%02d' % tc, msg] self.lines.append(line) if len(self.lines) > 1000: try: fcsv = open(csvfile, 'a') writer = csv.writer(fcsv) writer.writerows(self.lines) fcsv.close() except Exception, err: print err self.lines = []
def handle_messages(self, messages): self.i += 1 for msg, ts in messages: if len(msg) != 28: # wrong data length continue df = pms.df(msg) if df != 17: # not ADSB continue if pms.crc(msg) !=0: # CRC fail continue icao = pms.adsb.icao(msg) tc = pms.adsb.typecode(msg) flight = None if icao in self.flights: flight = self.flights[icao] else: flight = Flight(icao) flight.last_seen = datetime.now() # Message Type Codes: https://mode-s.org/api/ if tc >= 1 and tc <= 4: # Typecode 1-4 flight.call_sign = pms.adsb.callsign(msg).strip('_') elif tc >= 9 and tc <= 18: # Typecode 9-18 (airborne, barometric height) flight.location = pms.adsb.airborne_position_with_ref(msg, self.lat_ref, self.lon_ref) flight.altitude_ft = pms.adsb.altitude(msg) flight.sent = False elif tc == 19: # Typecode: 19 # Ground Speed (GS) or Airspeed (IAS/TAS) # Output (speed, track angle, vertical speed, tag): (flight.speed_kts, flight.track_angle_deg, flight.vertical_speed_fpm, flight.speed_ref) = pms.adsb.velocity(msg) self.flights[icao] = flight if self.i > 10: self.i = 0 #print("Flights: ", len(self.flights)) for key in list(self.flights): f = self.flights[key] if f.has_info() and not f.sent: #f.pretty_print() f.json_print() f.sent = True elif f.last_seen < (datetime.now() - timedelta(minutes=5)): #print("Deleting ", key) del self.flights[key]
def _check_msg(self, msg): df = pms.df(msg) msglen = len(msg) if df == 17 and msglen == 28: if pms.crc(msg) == 0: return True elif df in [20, 21] and msglen == 28: return True elif df in [4, 5, 11] and msglen == 14: return True
def _debug_msg(self, msg): df = pms.df(msg) msglen = len(msg) if df == 17 and msglen == 28: print(msg, pms.icao(msg), pms.crc(msg)) elif df in [20, 21] and msglen == 28: print(msg, pms.icao(msg)) elif df in [4, 5, 11] and msglen == 14: print(msg, pms.icao(msg)) else: # print("[*]", msg) pass
def decode_ADSB(signal, fix_1bit_errors=False): """Attempts to decode the given signal as an ADS-B message and calculate SNR. Parameters ---------- signal : numpy.array The RF signal to decode. Must have a sample rate of 2MHz and be at least 240 samples long. fix_1bit_errors : bool, optional Whether or not to attempt to fix single bit errors. Returns ------- string If the CRC check passes, returns the hex string for the ADS-B packet. Returns None if the CRC check fails. """ row_size = 16 + 112 * 2 msg = None # Exit if signal's sample size is too small if (len(signal) < row_size): return # Decode the signal to binary (assume Manchester encoded) # Taken from the EE123 Lab 2 code bits = signal[16::2] > signal[17::2] tmp = ''.join(['1' if x else '0' for x in bits]) msg = hex(int(tmp, 2))[2:] # CRC check for long message if (pms.crc(msg) == 0): return msg # CRC check for short message elif (pms.crc(msg[:14]) == 0): return msg[:14] if fix_1bit_errors: return correct_single_bit_error(msg) else: return None
def __rtl_thread(self): """ Internal thread for running the rtl binary """ cmd = [ self.opts['rtlbin'] ] if self.opts['device'] is not None: cmd.append('-d') cmd.append("{}".format(self.opts['device'])) if self.opts['gain'] is not None: cmd.append('-g') cmd.append("{}".format(self.opts['gain'])) seen_any_valid = False failed_once = False try: FNULL = open(os.devnull, 'w') self.rtl_exec = subprocess.Popen(cmd, stderr=FNULL, stdout=subprocess.PIPE) while True: hex_data = self.rtl_exec.stdout.readline().decode('ascii').strip()[1:-1] if pms.crc(hex_data) == "000000000000000000000000": for row in airplanes: if pms.adsb.icao(hex_data) == row[0]: msg = { "icao": row[0] , "regid": row[1] , "mdl": row[2] , "type": row[3] , "operator": row[4] } if 1 <= pms.adsb.typecode(hex_data) <= 4: msg = { "icao": pms.adsb.icao(hex_data), "callsign": pms.adsb.callsign(hex_data) } if 5 <= pms.adsb.typecode(hex_data) <= 8: msg = { "icao": pms.adsb.icao(hex_data), "altitude": pms.adsb.altitude(hex_data) } if pms.adsb.typecode(hex_data) == 19: airborneInfo = pms.adsb.airborne_velocity(hex_data) msg = { "icao": pms.adsb.icao(hex_data), "speed": airborneInfo[0], "heading": airborneInfo[1], "altitude": airborneInfo[2], "GSAS": airborneInfo[3] } l = json.dumps(msg) if not self.handle_json(l): raise RuntimeError('could not process response from rtladsb') seen_any_valid = True except Exception as e: # Catch all errors, but don't die if we're reconfiguring rtl; then we need # to relaunch the binary if not self.rtl_reconfigure: self.kismet.send_datasource_error_report(message = "Unable to process output from rtladsb: {}".format(e)) finally: if not seen_any_valid and not self.rtl_reconfigure: self.kismet.send_datasource_error_report(message = "An error occurred in rtladsb and no valid devices were seen; is your USB device plugged in? Try running rtladsb in a terminal and confirm that it can connect to your device.") self.kismet.spindown() self.rtl_exec.kill()
def process_adsb(self, msg: str) -> None: self.messages += 1 msg = self.correct(msg) if pms.bin2int(pms.crc(msg)) != 0: self.rejects += 1 return # print('Error rate:', 100 * self.rejects / self.messages) tc = pms.adsb.typecode(msg) icao = pms.adsb.icao(msg) if tc in TC_IDENTIFICATION: callsign = pms.adsb.callsign(msg).strip('_') print(msg, '%2d' % tc, pms.adsb.icao(msg), callsign) aircraft = self.context.registerAircraft(pms.adsb.icao(msg), callsign) aircraft.messages.add(msg) self.context.notify(aircraft) if tc in TC_POSITION: altitude = pms.adsb.altitude(msg) aircraft = self.context.getAircraft(icao) if aircraft is not None: aircraft.messages.add(msg) aircraft.lastmessage = datetime.datetime.now() aircraft.altitude = altitude lat, lon = compute_location(aircraft) if lat is not None and lon is not None: aircraft.lat = lat aircraft.lon = lon self.context.notify(aircraft) print(msg, '%2d' % tc, icao, altitude, aircraft) if tc in TC_VELOCITY: velocity = pms.adsb.velocity(msg) aircraft = self.context.getAircraft(icao) if aircraft is not None: aircraft.messages.add(msg) aircraft.lastmessage = datetime.datetime.now() aircraft.speed, aircraft.heading, \ aircraft.vspeed, aircraft.sptype = velocity self.context.notify(aircraft) print(msg, '%2d' % tc, icao, velocity, aircraft)
def correct(self, msg): crc = pms.bin2int(pms.crc(msg)) result = msg if crc != 0: msg_bin = pms.hex2bin(msg) for i in range(len(msg_bin) - 24): if msg_bin[i] == '0': msg_bin = self.replace(msg_bin, i, '1') else: msg_bin = self.replace(msg_bin, i, '0') patched_msg = hex(int(msg_bin, 2))[2:] if pms.bin2int(pms.crc(patched_msg)) == 0: result = patched_msg break if msg_bin[i] == '0': msg_bin = self.replace(msg_bin, i, '1') else: msg_bin = self.replace(msg_bin, i, '0') return result
def handle_messages(self, messages): for msg, ts in messages: if len(msg) != 28: # wrong data length continue df = pms.df(msg) if df != 17: # not ADSB continue if pms.crc(msg) != 0: # CRC fail continue icao = pms.adsb.icao(msg) saved = self.r.get(icao) to_save = pms.get_all(msg) if saved is not None: saved = json.loads(saved) try: if 'location_message' in saved and 'cpr_latitude' in to_save: if saved['location_type'] == to_save['type'] and saved[ 'cpr_format'] != to_save['cpr_format']: if saved['cpr_latitude'] != to_save[ 'cpr_latitude'] and saved[ 'cpr_longitude'] != to_save[ 'cpr_longitude']: gps = pms.adsb.position( msg, saved['location_message'], ts, saved['location_timestamp']) if gps is not None: to_save['gps_latitude'] = gps[0] to_save['gps_longitude'] = gps[1] except: pass saved.update(to_save) if 'cpr_latitude' in to_save: saved['location_type'] = to_save['type'] saved['location_message'] = msg saved['location_timestamp'] = ts self.r.set(icao, json.dumps(saved), ex=60) else: if 'cpr_latitude' in to_save: to_save['location_type'] = to_save['type'] to_save['location_message'] = msg to_save['location_timestamp'] = ts self.r.set(icao, json.dumps(to_save), ex=60)
def start(msg): global aircrafts # verificação da mensagem try: if int(pms.crc(msg[0], encode=False)) != 0: with open('../mensagens/output/corrupted.txt', 'a') as f: f.write('{} {}\n'.format(msg[0], msg[1])) elif 17 != pms.df(msg[0]) != 18: with open('../mensagens/output/incorrectDF.txt', 'a') as f: f.write('{} {}\n'.format(msg[0], msg[1])) else: icao = pms.adsb.icao(msg[0]) # ICAO aeronave if icao not in aircrafts: aircrafts[icao] = Aircraft(icao) aircrafts[icao].code(msg) except: print("Erro com a mensage: ", msg)
data = data[data.find(char1) + 1:data.find(char2)] data_length = len(data) try: dl_format = pms.df(data) except: break #CHECK MESSAGE CORRUPTED try: MSG = pms.hex2bin(data) except: pass if data_length > 14: CRC = pms.crc(MSG, encode=False) if int(CRC, 2) == 0: #print "Received Data:", data #print 'MSG is CORRECT' message = data type_code = pms.adsb.typecode(message) velocity = '' icao = '' lon = '' lat = '' callsign = '' altitude = '' position = '' speed = '' heading = ''
def handle_messages(self, messages): for msg, ts in messages: if all((len(msg) == 28, pms.df(msg) == 17, pms.crc(msg) == 0)): icao = pms.adsb.icao(msg) tc = pms.adsb.typecode(msg) self.process_msg(msg, ts, icao, tc)
#!/usr/bin/python import sys, getopt import pyModeS as mds msg = sys.argv[1] print mds.adsb.icao(msg); print mds.adsb.callsign(msg); print mds.crc(msg);
def process( self, time: datetime, msg: bytes, *args, spd: Optional[float] = None, trk: Optional[float] = None, alt: Optional[float] = None, ) -> None: if len(msg) != 28: return df = pms.df(msg) if df == 4 or df == 20: icao = pms.icao(msg) ac = self.acs[icao.lower()] ac.altcode = time, msg if df == 5 or df == 21: icao = pms.icao(msg) ac = self.acs[icao.lower()] ac.idcode = time, msg if df == 17 or df == 18: # ADS-B if pms.crc(msg, encode=False) != 0: return tc = pms.adsb.typecode(msg) icao = pms.icao(msg) ac = self.acs[icao.lower()] if 1 <= tc <= 4: ac.callsign = time, msg if 5 <= tc <= 8: ac.surface = time, msg if tc == 19: ac.speed = time, msg if 9 <= tc <= 18: # This is barometric altitude ac.position = time, msg if 20 <= tc <= 22: # Only GNSS altitude pass # if 9 <= tc <= 18: # ac["nic_bc"] = pms.adsb.nic_b(msg) # if (5 <= tc <= 8) or (9 <= tc <= 18) or (20 <= tc <= 22): # ac["HPL"], ac["RCu"], ac["RCv"] = pms.adsb.nuc_p(msg) # if (ac["ver"] == 1) and ("nic_s" in ac.keys()): # ac["Rc"], ac["VPL"] = pms.adsb.nic_v1(msg, ac["nic_s"]) # elif ( # (ac["ver"] == 2) # and ("nic_a" in ac.keys()) # and ("nic_bc" in ac.keys()) # ): # ac["Rc"] = pms.adsb.nic_v2(msg, ac["nic_a"], ac["nic_bc"]) # if tc == 19: # ac["HVE"], ac["VVE"] = pms.adsb.nuc_v(msg) # if ac["ver"] in [1, 2]: # ac["EPU"], ac["VEPU"] = pms.adsb.nac_v(msg) # if tc == 29: # ac["PE_RCu"], ac["PE_VPL"], ac["base"] = pms.adsb.sil( # msg, ac["ver"] # ) # ac["HFOMr"], ac["VFOMr"] = pms.adsb.nac_p(msg) # if tc == 31: # ac["ver"] = pms.adsb.version(msg) # ac["HFOMr"], ac["VFOMr"] = pms.adsb.nac_p(msg) # ac["PE_RCu"], ac["PE_VPL"], ac["sil_base"] = pms.adsb.sil( # msg, ac["ver"] # ) # if ac["ver"] == 1: # ac["nic_s"] = pms.adsb.nic_s(msg) # elif ac["ver"] == 2: # ac["nic_a"], ac["nic_bc"] = pms.adsb.nic_a_c(msg) elif df == 20 or df == 21: bds = pms.bds.infer(msg) icao = pms.icao(msg) ac = self.acs[icao.lower()] if bds == "BDS20": ac.bds20 = time, msg return if bds == "BDS40": ac.bds40 = time, msg return if bds == "BDS44": ac.bds44 = time, msg return if bds == "BDS45": ac.bds45 = time, msg return if bds == "BDS50,BDS60": if spd is not None and trk is not None and alt is not None: bds = pms.bds.is50or60(msg, spd, trk, alt) elif (ac.spd is not None and ac.trk is not None and ac.alt is not None): bds = pms.bds.is50or60(msg, ac.spd, ac.trk, ac.alt) else: return # do not return! if bds == "BDS50": ac.bds50 = time, msg return if bds == "BDS60": ac.bds60 = time, msg return
return pms.adsb.position(even[0], odd[0], even[1], odd[1], -15.8037544, -48.0866267) with open("../mensagens/adsb_all.txt") as f: msgs = [] for line in f.readlines(): msgs.append(line.replace("*", "").replace(";", "").replace("\n", "")) print("Total de mensagens captadas: %d" % (len(msgs))) for msg in msgs: # verificação da mensagem if int(pms.crc(msg, encode=False)) != 0: corrupted.append(msg) continue elif 17 != pms.df(msg) != 18: incorrectDF.append(msg) continue icao = pms.adsb.icao(msg) # ICAO aeronava # Informações necessárias da aeronave if not icao in data: data[icao] = { 'mensagens': 0, 'identificação': None, 'posiçãoSurface': [], 'BARO': [],
def process( self, time: datetime, msg: str, *args: Any, uncertainty: bool = False, spd: Optional[float] = None, trk: Optional[float] = None, alt: Optional[float] = None, ) -> None: ac: Aircraft if len(msg) != 28: return df = pms.df(msg) if df == 4 or df == 20: icao = pms.icao(msg) if isinstance(icao, bytes): icao = icao.decode() ac = self.acs[icao.lower()] ac.altcode = time, msg # type: ignore if df == 5 or df == 21: icao = pms.icao(msg) if isinstance(icao, bytes): icao = icao.decode() ac = self.acs[icao.lower()] ac.idcode = time, msg # type: ignore if df == 17 or df == 18: # ADS-B if pms.crc(msg, encode=False) != 0: return tc = pms.adsb.typecode(msg) icao = pms.icao(msg) # before it's fixed in pyModeS release... if isinstance(icao, bytes): icao = icao.decode() ac = self.acs[icao.lower()] if 1 <= tc <= 4: ac.callsign = time, msg # type: ignore if 5 <= tc <= 8: ac.surface = time, msg # type: ignore if tc == 19: ac.speed = time, msg # type: ignore if 9 <= tc <= 18: # This is barometric altitude ac.position = time, msg # type: ignore if 20 <= tc <= 22: # Only GNSS altitude pass if not uncertainty: return if 9 <= tc <= 18: ac.nic_bc = pms.adsb.nic_b(msg) if (5 <= tc <= 8) or (9 <= tc <= 18) or (20 <= tc <= 22): ac.nuc_p = time, msg # type: ignore if ac.version == 1: ac.nic_v1 = time, msg # type: ignore elif ac.version == 2: ac.nic_v2 = time, msg # type: ignore if tc == 19: ac.nuc_r = time, msg # type: ignore if ac.version in [1, 2]: ac.nac_v = time, msg # type: ignore if tc == 29: ac.sil = time, msg # type: ignore ac.nac_p = time, msg # type: ignore if tc == 31: ac.version = pms.adsb.version(msg) ac.sil = time, msg # type: ignore ac.nac_p = time, msg # type: ignore if ac.version == 1: ac.nic_s = pms.adsb.nic_s(msg) elif ac.version == 2: ac.nic_a, ac.nic_bc = pms.adsb.nic_a_c(msg) elif df == 20 or df == 21: bds = pms.bds.infer(msg) icao = pms.icao(msg) if isinstance(icao, bytes): icao = icao.decode() ac = self.acs[icao.lower()] if bds == "BDS20": ac.bds20 = time, msg # type: ignore return if bds == "BDS40": ac.bds40 = time, msg # type: ignore return if bds == "BDS44": ac.bds44 = time, msg # type: ignore return if bds == "BDS45": ac.bds45 = time, msg # type: ignore return if bds == "BDS50,BDS60": if spd is not None and trk is not None and alt is not None: bds = pms.bds.is50or60(msg, spd, trk, alt) elif (ac.spd is not None and ac.trk is not None and ac.alt is not None): bds = pms.bds.is50or60(msg, ac.spd, ac.trk, ac.alt) else: return # do not return! if bds == "BDS50": ac.bds50 = time, msg # type: ignore return if bds == "BDS60": ac.bds60 = time, msg # type: ignore return
async def run(self): self._logger.info("Running ADSBNetWorker for data_type='%s'", self.data_type) self._reset_local_buffer() decoder = pyModeS.streamer.decode.Decode() net_client = pyModeS.streamer.source.NetSource("x", 1, self.data_type) while 1: messages = [] received = await self.net_queue.get() if not received: continue net_client.buffer.extend(received) if "beast" in self.data_type: messages = net_client.read_beast_buffer() elif "raw" in self.data_type: messages = net_client.read_raw_buffer() elif "skysense" in self.data_type: messages = net_client.read_skysense_buffer() self._logger.debug("Received %s messages", len(messages)) if not messages: continue else: for msg, t in messages: if len(msg) != 28: # wrong data length continue df = pms.df(msg) if df != 17: # not ADSB continue if pms.crc(msg) != 0: # CRC fail continue icao = pms.adsb.icao(msg) tc = pms.adsb.typecode(msg) if df == 17 or df == 18: self.local_buffer_adsb_msg.append(msg) self.local_buffer_adsb_ts.append(t) elif df == 20 or df == 21: self.local_buffer_commb_msg.append(msg) self.local_buffer_commb_ts.append(t) else: continue if len(self.local_buffer_adsb_msg) > 1: decoder.process_raw(self.local_buffer_adsb_ts, self.local_buffer_adsb_msg, self.local_buffer_commb_ts, self.local_buffer_commb_msg) self._reset_local_buffer() acs = decoder.get_aircraft() for k, v in acs.items(): # self._logger.debug("acs=%s", acs[k]) lat = v.get("lat") lon = v.get("lon") flight = v.get("call", k) alt_geom = v.get("alt") gs = v.get("gs") if lat and lon and flight and alt_geom and gs: aircraft = [{ "hex": k, "lat": lat, "lon": lon, "flight": flight.replace("_", ""), "alt_geom": alt_geom, "gs": gs }] await self.handle_message(aircraft) else: continue