diff --git a/apps/modes_gui b/apps/modes_gui index 789bc01..303ae80 100755 --- a/apps/modes_gui +++ b/apps/modes_gui @@ -60,17 +60,18 @@ class mainwindow(QtGui.QMainWindow): self.dbinput = None #connect the database to the model and the model to the listview - self.dbname = 'air_modes.db' - self.db = QtSql.QSqlDatabase.addDatabase("QSQLITE") - self.db.setDatabaseName(self.dbname) - self.db.open() - self.datamodel = QtSql.QSqlQueryModel() - self.datamodel.setQuery("select * from aircraft order by icao") +# self.dbname = 'air_modes.db' +# self.db = QtSql.QSqlDatabase.addDatabase("QSQLITE") +# self.db.setDatabaseName(self.dbname) +# self.db.open() + self.datamodel = dashboard_data_model(None) self.ui.list_aircraft.setModel(self.datamodel) self.ui.list_aircraft.setModelColumn(0) #set up dashboard views + #TODO: figure out why you can't update the RSSI or compass widgets with this mapper + #pretty sure it's a Qt bug in the SQL code -- returns as string instead of double self.icaodelegate = ICAOViewDelegate() self.ui.list_aircraft.setItemDelegate(self.icaodelegate) self.dashboard_mapper = QtGui.QDataWidgetMapper() @@ -88,6 +89,7 @@ class mainwindow(QtGui.QMainWindow): compass_palette = QtGui.QPalette() compass_palette.setColor(QtGui.QPalette.Foreground, QtCore.Qt.white) self.ui.compass_heading.setPalette(compass_palette) + #TODO: change the needle to an aircraft silhouette self.ui.compass_heading.setNeedle(Qwt.QwtDialSimpleNeedle(Qwt.QwtDialSimpleNeedle.Ray, False, QtCore.Qt.black)) self.ui.compass_heading.setValue(315.0) @@ -104,19 +106,6 @@ class mainwindow(QtGui.QMainWindow): rssi = index.model().data(index.model().index(index.row(), 2)).toFloat()[0] self.ui.prog_rssi.setValue(rssi) - #this is fired off by the main loop each time a packet comes in. - #eventually you might have this set to just QTimer, depending on how fast things go - #this is also updated on EVERY mode S packet, not just valid ADS-B - #the RIGHT way to do this is: - #all SQL is done inside the datamodel, which can be a QSqlTableModel type. - #No fields are editable by the user. - #when an update happens, the SQL model determines the row which has changed (by ICAO) - #the SQL model then invalidates that row, which will selectively update the list and hopefully the mapper. - def update_gui_widgets(self, msg): - #self.datamodel.reset() #this is hella bad - self.datamodel.setQuery("select * from aircraft order by icao") - self.dashboard_mapper.revert() - #goes and gets valid antenna, sample rate options from the device and grays out appropriate things def populate_source_options(self): sourceid = self.ui.combo_source.currentText() @@ -207,7 +196,7 @@ class mainwindow(QtGui.QMainWindow): except: my_position = None - self.outputs = [self.update_gui_widgets] + self.outputs = [] self.updates = [] #output options to populate outputs, updates @@ -254,7 +243,7 @@ class mainwindow(QtGui.QMainWindow): #all this does is fade the ICAOs out as their last report gets older class ICAOViewDelegate(QtGui.QStyledItemDelegate): def paint(self, painter, option, index): - paintstr = "%x" % index.model().data(index.model().index(index.row(), 0)).toInt()[0] + paintstr = "%06x" % index.model().data(index.model().index(index.row(), 0)).toInt()[0] last_report = str(index.model().data(index.model().index(index.row(), 1)).toString()) age = (datetime.datetime.utcnow() - datetime.datetime.strptime(last_report, "%Y-%m-%d %H:%M:%S")).total_seconds() #minimum alpha is 0x40 (oldest), max is 0xFF (newest) @@ -264,6 +253,30 @@ class ICAOViewDelegate(QtGui.QStyledItemDelegate): painter.drawText(option.rect.left()+3, option.rect.top(), option.rect.width(), option.rect.height(), option.displayAlignment, paintstr) #TODO: draw highlight for selection +class dashboard_data_model(QtCore.QAbstractTableModel): + def __init__(self, parent): + QtCore.QAbstractTableModel.__init__(self, parent) + self._data = [] + self._colnames = ["icao", "seen", "rssi", "latitude", "longitude", "altitude", "speed", "heading", "vertical", "ident", "type"] + self._data.append([0x012345, "2012-07-12 09:17:51", -12.23, 31.12345, -112.12345, 86200.0, 776.0, 251.0, 11200.0, "BUTTSEX", "WAT"]) + def rowCount(self, parent=QtCore.QVariant()): + return len(self._data) + def columnCount(self, parent=QtCore.QVariant()): + return len(self._colnames) + def data(self, index, role=QtCore.Qt.DisplayRole): + if not index.isValid(): + return QtCore.QVariant() + if index.row() >= self.rowCount(): + return QtCore.QVariant() + if index.column() >= self.columnCount(): + return QtCore.QVariant() + if (role != QtCore.Qt.DisplayRole) and (role != QtCore.Qt.EditRole): + return QtCore.QVariant() + if self._data[index.row()][index.column()] is None: + return QtCore.QVariant() + else: + return QtCore.QVariant(self._data[index.row()][index.column()]) + class output_handler(threading.Thread): def __init__(self, outputs, updates, queue): threading.Thread.__init__(self) diff --git a/python/modes_sql.py b/python/modes_sql.py index 24cc328..58612c6 100644 --- a/python/modes_sql.py +++ b/python/modes_sql.py @@ -19,7 +19,7 @@ # Boston, MA 02110-1301, USA. # -import time, os, sys, math +import time, os, sys from string import split, join import modes_parse import sqlite3 @@ -54,20 +54,6 @@ class modes_output_sql(modes_parse.modes_parse): "ident" TEXT NOT NULL );""" c.execute(query) - query = """CREATE TABLE IF NOT EXISTS "aircraft" ( - "icao" integer primary key not null, - "seen" text not null, - "rssi" real, - "latitude" real, - "longitude" real, - "altitude" real, - "speed" real, - "heading" real, - "vertical" real, - "ident" text, - "type" text - );""" - c.execute(query) c.close() #we close the db conn now to reopen it in the output() thread context. self.db.close() @@ -85,8 +71,12 @@ class modes_output_sql(modes_parse.modes_parse): if self.db is None: self.db = sqlite3.connect(self.filename) - self.make_insert_query(message) - self.db.commit() #don't know if this is necessary + query = self.make_insert_query(message) + if query is not None: + c = self.db.cursor() + c.execute(query) + c.close() + self.db.commit() #don't know if this is necessary except ADSBError: pass @@ -97,60 +87,49 @@ class modes_output_sql(modes_parse.modes_parse): data = modes_parse.modes_reply(long(data, 16)) ecc = long(ecc, 16) - rssi = 10.0*math.log10(float(reference)) +# reference = float(reference) query = None msgtype = data["df"] if msgtype == 17: - query = self.sql17(data, rssi) + query = self.sql17(data) return query - def sql17(self, data, rssi): + def sql17(self, data): icao24 = data["aa"] subtype = data["ftc"] - c = self.db.cursor() + + retstr = None if subtype == 4: - (ident, typename) = self.parseBDS08(data) - c.execute("insert or ignore into aircraft (icao, seen, rssi, ident, type) values (%i, datetime('now'), %f, '%s', '%s')" % (icao24, rssi, ident, typename)) - c.execute("update aircraft set seen=datetime('now'), rssi=%f, ident='%s', type='%s' where icao=%i" % (rssi, ident, typename, icao24)) + (msg, typename) = self.parseBDS08(data) + retstr = "INSERT OR REPLACE INTO ident (icao, ident) VALUES (" + "%i" % icao24 + ", '" + msg + "')" elif subtype >= 5 and subtype <= 8: [ground_track, decoded_lat, decoded_lon, rnge, bearing] = self.parseBDS06(data) altitude = 0 if decoded_lat is None: #no unambiguously valid position available - c.execute("insert or ignore into aircraft (icao, seen, rssi) values (%i, datetime('now'), %f)" % (icao24, rssi)) - c.execute("update aircraft set seen=datetime('now'), rssi=%f where icao=%i" % (icao24, rssi)) + retstr = None else: - c.execute("insert or ignore into aircraft (icao, seen, rssi, latitude, longitude, altitude) \ - values (%i, datetime('now'), %f, %.6f, %.6f, %i)" % (icao24, rssi, decoded_lat, decoded_lon, altitude)) - c.execute("update aircraft set seen=datetime('now'), rssi=%f, latitude=%.6f, longitude=%.6f, altitude=%i" % (rssi, decoded_lat, decoded_lon, altitude)) + retstr = "INSERT INTO positions (icao, seen, alt, lat, lon) VALUES (" + "%i" % icao24 + ", datetime('now'), " + str(altitude) + ", " + "%.6f" % decoded_lat + ", " + "%.6f" % decoded_lon + ")" elif subtype >= 9 and subtype <= 18 and subtype != 15: #i'm eliminating type 15 records because they don't appear to be valid position reports. [altitude, decoded_lat, decoded_lon, rnge, bearing] = self.parseBDS05(data) if decoded_lat is None: #no unambiguously valid position available - c.execute("insert or ignore into aircraft (icao, seen, rssi) values (%i, datetime('now'), %f);" % (icao24, rssi)) - c.execute("update aircraft set seen=datetime('now'), rssi=%f where icao=%i" % (icao24, rssi)) + retstr = None else: - c.execute("insert or ignore into aircraft (icao, seen, rssi, latitude, longitude, altitude) \ - values (%i, datetime('now'), %f, %.6f, %.6f, %i)" % (icao24, rssi, decoded_lat, decoded_lon, altitude)) - c.execute("update aircraft set seen=datetime('now'), rssi=%f, latitude=%.6f, longitude=%.6f, altitude=%i where icao=%i" % (rssi, decoded_lat, decoded_lon, altitude, icao24)) + retstr = "INSERT INTO positions (icao, seen, alt, lat, lon) VALUES (" + "%i" % icao24 + ", datetime('now'), " + str(altitude) + ", " + "%.6f" % decoded_lat + ", " + "%.6f" % decoded_lon + ")" elif subtype == 19: subsubtype = data["sub"] if subsubtype == 0: [velocity, heading, vert_spd] = self.parseBDS09_0(data) + retstr = "INSERT INTO vectors (icao, seen, speed, heading, vertical) VALUES (" + "%i" % icao24 + ", datetime('now'), " + "%.0f" % velocity + ", " + "%.0f" % heading + ", " + "%.0f" % vert_spd + ")"; elif 1 <= subsubtype <= 2: [velocity, heading, vert_spd] = self.parseBDS09_1(data) - else: - return None - - c.execute("insert or ignore into aircraft (icao, seen, rssi, speed, heading, vertical) \ - values (%i, datetime('now'), %f, %.0f, %.0f, %.0f);" % (icao24, rssi, velocity, heading, vert_spd)) - c.execute("update aircraft set seen=datetime('now'), rssi=%f, speed=%.0f, heading=%.0f, vertical=%.0f where icao=%i" % (rssi, velocity, heading, vert_spd, icao24)) + retstr = "INSERT INTO vectors (icao, seen, speed, heading, vertical) VALUES (" + "%i" % icao24 + ", datetime('now'), " + "%.0f" % velocity + ", " + "%.0f" % heading + ", " + "%.0f" % vert_spd + ")"; - - c.close() + return retstr diff --git a/res/modes_rx.ui b/res/modes_rx.ui index 8d2fc29..aa8e2c9 100644 --- a/res/modes_rx.ui +++ b/res/modes_rx.ui @@ -785,6 +785,9 @@ 91 + + true + 4 @@ -859,9 +862,15 @@ 271 + + QAbstractItemView::NoEditTriggers + QListView::SinglePass + + true +