diff --git a/apps/modes_rx b/apps/modes_rx index ee2355a..9293f22 100755 --- a/apps/modes_rx +++ b/apps/modes_rx @@ -63,15 +63,21 @@ def main(): #ok now relay is gonna get all those tasty strings #internally we want to distribute parsed data instead, lighten the load + #TODO obviously this should go somewhere besides the main app. But where? publisher = pubsub() - def send(message): + def make_report(pub, message): [data, ecc, reference, timestamp] = message.split() try: - ret = air_modes.modes_report(air_modes.modes_reply(int(data, 16)), int(ecc, 16), 20.0*math.log10(float(reference)), air_modes.stamp(0, float(timestamp))) - publisher["modes_dl"] = ret - publisher["type%i_dl" % ret.data.get_type()] = ret + ret = air_modes.modes_report(air_modes.modes_reply(int(data, 16)), + int(ecc, 16), + 20.0*math.log10(float(reference)), + air_modes.stamp(0, float(timestamp))) + pub["modes_dl"] = ret + pub["type%i_dl" % ret.data.get_type()] = ret except ADSBError: pass + + send = lambda msg: make_report(publisher, msg) relay.subscribe("dl_data", send) @@ -84,12 +90,10 @@ def main(): if options.kml is not None: dbname = 'adsb.db' lock = threading.Lock() - sqldb = air_modes.output_sql(my_position, dbname, lock) #input into the db + sqldb = air_modes.output_sql(cpr_dec, dbname, lock, publisher) #input into the db kmlgen = air_modes.output_kml(options.kml, dbname, my_position, lock) #create a KML generating thread to read from the db - relay.subscribe("dl_data", sqldb.insert) if options.no_print is not True: - #relay.subscribe("dl_data", air_modes.output_print(my_position).output) printer = air_modes.output_print(cpr_dec, publisher) if options.multiplayer is not None: @@ -98,8 +102,7 @@ def main(): relay.subscribe("dl_data", fgout.output) if options.sbs1 is True: - sbs1port = air_modes.output_sbs1(my_position, 30003) - relay.subscribe("dl_data", sbs1port.output) + sbs1port = air_modes.output_sbs1(cpr_dec, 30003, publisher) tb.run() tb.close() diff --git a/python/__init__.py b/python/__init__.py index 28560f2..c42c61d 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -55,22 +55,22 @@ from rx_path import rx_path from zmq_socket import zmq_pubsub_iface from parse import * from msprint import output_print -#from sql import output_sql -#from sbs1 import output_sbs1 -#from kml import output_kml -#from raw_server import raw_server +from sql import output_sql +from sbs1 import output_sbs1 +from kml import output_kml +from raw_server import raw_server from radio import modes_radio from exceptions import * -#from az_map import * +from az_map import * from types import * from altitude import * #this is try/excepted in case the user doesn't have numpy installed -#try: -# from flightgear import output_flightgear -# from Quaternion import * -#except ImportError: -# print "gr-air-modes warning: numpy+scipy not installed, FlightGear interface not supported" -# pass +try: + from flightgear import output_flightgear + from Quaternion import * +except ImportError: + print "gr-air-modes warning: numpy+scipy not installed, FlightGear interface not supported" + pass # ---------------------------------------------------------------- # Tail of workaround diff --git a/python/az_map.py b/python/az_map.py index bd96878..d064608 100755 --- a/python/az_map.py +++ b/python/az_map.py @@ -169,29 +169,26 @@ class az_map(QtGui.QWidget): self.ringsize = ringsize self.drawPath() -class az_map_output(air_modes.parse): - def __init__(self, mypos, model): - air_modes.parse.__init__(self, mypos) +class az_map_output: + def __init__(self, cprdec, model, pub): + self._cpr = cprdec self.model = model + pub.subscribe("type17_dl", output) def output(self, msg): try: - [data, ecc, reference, timestamp] = msg.split() - data = air_modes.modes_reply(long(data, 16)) - ecc = long(ecc, 16) - rssi = 10.*math.log10(float(reference)) - msgtype = data["df"] + msgtype = msg.data["df"] now = time.time() if msgtype == 17: - icao = data["aa"] - subtype = data["ftc"] + icao = msg.data["aa"] + subtype = msg.data["ftc"] distance, altitude, bearing = [0,0,0] if 5 <= subtype <= 8: - (ground_track, decoded_lat, decoded_lon, distance, bearing) = self.parseBDS06(data) + (ground_track, decoded_lat, decoded_lon, distance, bearing) = air_modes.parseBDS06(msg.data, self._cpr) altitude = 0 elif 9 <= subtype <= 18: - (altitude, decoded_lat, decoded_lon, distance, bearing) = self.parseBDS05(data) + (altitude, decoded_lat, decoded_lon, distance, bearing) = air_modes.parseBDS05(msg.data, self._cpr) self.model.addRecord(bearing, altitude, distance) except ADSBError: diff --git a/python/sbs1.py b/python/sbs1.py index adf02dd..b0507ce 100644 --- a/python/sbs1.py +++ b/python/sbs1.py @@ -47,9 +47,8 @@ class dumb_task_runner(threading.Thread): self.shutdown.set() self.finished.wait(self._interval) -class output_sbs1(air_modes.parse): - def __init__(self, mypos, port): - air_modes.parse.__init__(self, mypos) +class output_sbs1: + def __init__(self, cprdec, port, pub): self._s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self._s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self._s.bind(('', port)) @@ -59,6 +58,13 @@ class output_sbs1(air_modes.parse): self._aircraft_id_map = {} # dictionary of icao24 to aircraft IDs self._aircraft_id_count = 0 # Current Aircraft ID count + self._cpr = cprdec + + #it could be cleaner if there were separate output_* fns + #but this works + for i in (0, 4, 5, 11, 17): + pub.subscribe("type%i_dl" % i, output) + #spawn thread to add new connections as they come in self._runner = dumb_task_runner(self.add_pending_conns, 0.1) @@ -124,35 +130,30 @@ class output_sbs1(air_modes.parse): else: return ",,," - def parse(self, message): + def parse(self, msg): #assembles a SBS-1-style output string from the received message - [data, ecc, reference, timestamp] = message.split() - - data = air_modes.modes_reply(long(data, 16)) - ecc = long(ecc, 16) - msgtype = data["df"] + msgtype = msg.data["df"] outmsg = None if msgtype == 0: - outmsg = self.pp0(data, ecc) + outmsg = self.pp0(msg.data, msg.ecc) elif msgtype == 4: - outmsg = self.pp4(data, ecc) + outmsg = self.pp4(msg.data, msg.ecc) elif msgtype == 5: - outmsg = self.pp5(data, ecc) + outmsg = self.pp5(msg.data, msg.ecc) elif msgtype == 11: - outmsg = self.pp11(data, ecc) + outmsg = self.pp11(msg.data, msg.ecc) elif msgtype == 17: - outmsg = self.pp17(data) + outmsg = self.pp17(msg.data) else: raise NoHandlerError(msgtype) return outmsg def pp0(self, shortdata, ecc): [datestr, timestr] = self.current_time() - [vs, cc, sl, ri, altitude] = self.parse0(shortdata) aircraft_id = self.get_aircraft_id(ecc) - retstr = "MSG,7,0,%i,%06X,%i,%s,%s,%s,%s,,%s,,,,,,,,,," % (aircraft_id, ecc, aircraft_id+100, datestr, timestr, datestr, timestr, altitude) + retstr = "MSG,7,0,%i,%06X,%i,%s,%s,%s,%s,,%s,,,,,,,,,," % (aircraft_id, ecc, aircraft_id+100, datestr, timestr, datestr, timestr, air_modes.decode_alt(shortdata["ac"], True)) if vs: retstr += "1\r\n" else: @@ -161,23 +162,20 @@ class output_sbs1(air_modes.parse): def pp4(self, shortdata, ecc): [datestr, timestr] = self.current_time() - [fs, dr, um, altitude] = self.parse4(shortdata) aircraft_id = self.get_aircraft_id(ecc) - retstr = "MSG,5,0,%i,%06X,%i,%s,%s,%s,%s,,%s,,,,,,," % (aircraft_id, ecc, aircraft_id+100, datestr, timestr, datestr, timestr, altitude) - return retstr + self.decode_fs(fs) + "\r\n" + retstr = "MSG,5,0,%i,%06X,%i,%s,%s,%s,%s,,%s,,,,,,," % (aircraft_id, ecc, aircraft_id+100, datestr, timestr, datestr, timestr, air_modes.decode_alt(shortdata["ac"], True)) + return retstr + self.decode_fs(shortdata["fs"]) + "\r\n" def pp5(self, shortdata, ecc): [datestr, timestr] = self.current_time() - [fs, dr, um, ident] = self.parse5(shortdata) aircraft_id = self.get_aircraft_id(ecc) - retstr = "MSG,6,0,%i,%06X,%i,%s,%s,%s,%s,,,,,,,,%04i," % (aircraft_id, ecc, aircraft_id+100, datestr, timestr, datestr, timestr, ident) - return retstr + self.decode_fs(fs) + "\r\n" + retstr = "MSG,6,0,%i,%06X,%i,%s,%s,%s,%s,,,,,,,,%04i," % (aircraft_id, ecc, aircraft_id+100, datestr, timestr, datestr, timestr, air_modes.decode_id(shortdata["id"])) + return retstr + self.decode_fs(shortdata["fs"]) + "\r\n" def pp11(self, shortdata, ecc): [datestr, timestr] = self.current_time() - [icao24, interrogator, ca] = self.parse11(shortdata, ecc) aircraft_id = self.get_aircraft_id(icao24) - return "MSG,8,0,%i,%06X,%i,%s,%s,%s,%s,,,,,,,,,,,,\r\n" % (aircraft_id, icao24, aircraft_id+100, datestr, timestr, datestr, timestr) + return "MSG,8,0,%i,%06X,%i,%s,%s,%s,%s,,,,,,,,,,,,\r\n" % (aircraft_id, shortdata["aa"], aircraft_id+100, datestr, timestr, datestr, timestr) def pp17(self, data): icao24 = data["aa"] @@ -191,12 +189,12 @@ class output_sbs1(air_modes.parse): if bdsreg == 0x08: # Aircraft Identification - (msg, typestring) = self.parseBDS08(data) + (msg, typestring) = air_modes.parseBDS08(data) retstr = "MSG,1,0,%i,%06X,%i,%s,%s,%s,%s,%s,,,,,,,,,,,\r\n" % (aircraft_id, icao24, aircraft_id+100, datestr, timestr, datestr, timestr, msg) elif bdsreg == 0x06: # Surface position measurement - [ground_track, decoded_lat, decoded_lon, rnge, bearing] = self.parseBDS06(data) + [ground_track, decoded_lat, decoded_lon, rnge, bearing] = air_modes.parseBDS06(data, self._cpr) altitude = 0 if decoded_lat is None: #no unambiguously valid position available retstr = None @@ -206,7 +204,7 @@ class output_sbs1(air_modes.parse): elif bdsreg == 0x05: # Airborne position measurements # WRONG (rnge, bearing), is this still true? - [altitude, decoded_lat, decoded_lon, rnge, bearing] = self.parseBDS05(data) + [altitude, decoded_lat, decoded_lon, rnge, bearing] = air_modes.parseBDS05(data, self._cpr) if decoded_lat is None: #no unambiguously valid position available retstr = None else: @@ -217,7 +215,7 @@ class output_sbs1(air_modes.parse): # WRONG (heading, vert_spd), Is this still true? subtype = data["bds09"].get_type() if subtype == 0 or subtype == 1: - parser = self.parseBDS09_0 if subtype == 0 else self.parseBDS09_1 + parser = air_modes.parseBDS09_0 if subtype == 0 else air_modes.parseBDS09_1 [velocity, heading, vert_spd] = parser(data) retstr = "MSG,4,0,%i,%06X,%i,%s,%s,%s,%s,,,%.1f,%.1f,,,%i,,,,,\r\n" % (aircraft_id, icao24, aircraft_id+100, datestr, timestr, datestr, timestr, velocity, heading, vert_spd) diff --git a/python/sql.py b/python/sql.py index f230db1..0f240ad 100644 --- a/python/sql.py +++ b/python/sql.py @@ -26,11 +26,10 @@ import sqlite3 from air_modes.exceptions import * from gnuradio.gr.pubsub import pubsub -class output_sql(air_modes.parse, pubsub): - def __init__(self, mypos, filename, lock): - air_modes.parse.__init__(self, mypos) - pubsub.__init__(self) - +class output_sql: + def __init__(self, cpr, filename, lock, publisher): + #pubsub.__init__(self) + self._cpr = cpr self._lock = lock; #create the database self.filename = filename @@ -63,6 +62,7 @@ class output_sql(air_modes.parse, pubsub): #we close the db conn now to reopen it in the output() thread context. self._db.close() self._db = None + publisher.subscribe("type17_dl", self.insert) def insert(self, message): with self._lock: @@ -84,19 +84,14 @@ class output_sql(air_modes.parse, pubsub): except ADSBError: pass - def make_insert_query(self, message): + def make_insert_query(self, msg): #assembles a SQL query tailored to our database #this version ignores anything that isn't Type 17 for now, because we just don't care - [data, ecc, reference, timestamp] = message.split() - - data = air_modes.modes_reply(long(data, 16)) - ecc = long(ecc, 16) -# reference = float(reference) query = None - msgtype = data["df"] + msgtype = msg.data["df"] if msgtype == 17: - query = self.sql17(data) - self["new_adsb"] = data["aa"] #publish change notification + query = self.sql17(msg.data) + #self["new_adsb"] = data["aa"] #publish change notification return query @@ -111,20 +106,20 @@ class output_sql(air_modes.parse, pubsub): def sql17(self, data): icao24 = data["aa"] bdsreg = data["me"].get_type() - self["bds%.2i" % bdsreg] = icao24 #publish under "bds08", "bds06", etc. + #self["bds%.2i" % bdsreg] = icao24 #publish under "bds08", "bds06", etc. if bdsreg == 0x08: - (msg, typename) = self.parseBDS08(data) + (msg, typename) = air_modes.parseBDS08(data) return "INSERT OR REPLACE INTO ident (icao, ident) VALUES (" + "%i" % icao24 + ", '" + msg + "')" elif bdsreg == 0x06: - [ground_track, decoded_lat, decoded_lon, rnge, bearing] = self.parseBDS06(data) + [ground_track, decoded_lat, decoded_lon, rnge, bearing] = air_modes.parseBDS06(data, self._cpr) altitude = 0 if decoded_lat is None: #no unambiguously valid position available raise CPRNoPositionError else: return "INSERT INTO positions (icao, seen, alt, lat, lon) VALUES (" + "%i" % icao24 + ", datetime('now'), " + str(altitude) + ", " + "%.6f" % decoded_lat + ", " + "%.6f" % decoded_lon + ")" elif bdsreg == 0x05: - [altitude, decoded_lat, decoded_lon, rnge, bearing] = self.parseBDS05(data) + [altitude, decoded_lat, decoded_lon, rnge, bearing] = air_modes.parseBDS05(data, self._cpr) if decoded_lat is None: #no unambiguously valid position available raise CPRNoPositionError else: @@ -132,10 +127,10 @@ class output_sql(air_modes.parse, pubsub): elif bdsreg == 0x09: subtype = data["bds09"].get_type() if subtype == 0: - [velocity, heading, vert_spd, turnrate] = self.parseBDS09_0(data) + [velocity, heading, vert_spd, turnrate] = air_modes.parseBDS09_0(data) return "INSERT INTO vectors (icao, seen, speed, heading, vertical) VALUES (" + "%i" % icao24 + ", datetime('now'), " + "%.0f" % velocity + ", " + "%.0f" % heading + ", " + "%.0f" % vert_spd + ")" elif subtype == 1: - [velocity, heading, vert_spd] = self.parseBDS09_1(data) + [velocity, heading, vert_spd] = air_modes.parseBDS09_1(data) return "INSERT INTO vectors (icao, seen, speed, heading, vertical) VALUES (" + "%i" % icao24 + ", datetime('now'), " + "%.0f" % velocity + ", " + "%.0f" % heading + ", " + "%.0f" % vert_spd + ")" else: raise NoHandlerError