diff --git a/apps/modes_gui b/apps/modes_gui
index bbf9af6..789bc01 100755
--- a/apps/modes_gui
+++ b/apps/modes_gui
@@ -2,6 +2,7 @@
import os, sys, time, threading, datetime
from PyQt4 import QtCore,QtGui,QtSql
+from PyQt4.Qwt5 import Qwt
from gnuradio import gr, gru, optfir, eng_notation, blks2
import gnuradio.gr.gr_threading as _threading
import air_modes
@@ -30,6 +31,9 @@ class mainwindow(QtGui.QMainWindow):
#default to 3dB
self.ui.line_threshold.insert("3")
+ self.ui.prog_rssi.setMinimum(-20)
+ self.ui.prog_rssi.setMaximum(0)
+
self.ui.combo_ant.setCurrentIndex(self.ui.combo_ant.findText("RX2"))
#check KML by default, leave the rest unchecked.
@@ -65,23 +69,53 @@ class mainwindow(QtGui.QMainWindow):
self.ui.list_aircraft.setModel(self.datamodel)
self.ui.list_aircraft.setModelColumn(0)
-
+
+ #set up dashboard views
self.icaodelegate = ICAOViewDelegate()
self.ui.list_aircraft.setItemDelegate(self.icaodelegate)
self.dashboard_mapper = QtGui.QDataWidgetMapper()
self.dashboard_mapper.setModel(self.datamodel)
- self.dashboard_mapper.addMapping(self.ui.prog_rssi, 2)
+ #self.dashboard_mapper.addMapping(self.ui.prog_rssi, 2)
self.dashboard_mapper.addMapping(self.ui.line_latitude, 3)
self.dashboard_mapper.addMapping(self.ui.line_longitude, 4)
self.dashboard_mapper.addMapping(self.ui.line_alt, 5)
self.dashboard_mapper.addMapping(self.ui.line_speed, 6)
- #self.dashboard_mapper.addMapping(self.ui.line_heading, 7)
+ #self.dashboard_mapper.addMapping(self.ui.compass_heading, 7)
self.dashboard_mapper.addMapping(self.ui.line_climb, 8)
self.dashboard_mapper.addMapping(self.ui.line_ident, 9)
self.dashboard_mapper.addMapping(self.ui.line_type, 10)
+ compass_palette = QtGui.QPalette()
+ compass_palette.setColor(QtGui.QPalette.Foreground, QtCore.Qt.white)
+ self.ui.compass_heading.setPalette(compass_palette)
+ self.ui.compass_heading.setNeedle(Qwt.QwtDialSimpleNeedle(Qwt.QwtDialSimpleNeedle.Ray, False, QtCore.Qt.black))
+ self.ui.compass_heading.setValue(315.0)
+
#hook up the update signal
self.ui.list_aircraft.selectionModel().currentRowChanged.connect(self.dashboard_mapper.setCurrentModelIndex)
+ self.ui.list_aircraft.selectionModel().currentRowChanged.connect(self.update_heading_widget)
+ self.ui.list_aircraft.selectionModel().currentRowChanged.connect(self.update_rssi_widget)
+
+ def update_heading_widget(self, index):
+ heading = index.model().data(index.model().index(index.row(), 7)).toFloat()[0]
+ self.ui.compass_heading.setValue(heading)
+
+ def update_rssi_widget(self, index):
+ 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):
@@ -173,7 +207,7 @@ class mainwindow(QtGui.QMainWindow):
except:
my_position = None
- self.outputs = []
+ self.outputs = [self.update_gui_widgets]
self.updates = []
#output options to populate outputs, updates
@@ -222,7 +256,7 @@ class ICAOViewDelegate(QtGui.QStyledItemDelegate):
def paint(self, painter, option, index):
paintstr = "%x" % 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.now() - datetime.datetime.strptime(last_report, "%Y-%m-%d %H:%M:%S")).total_seconds()
+ 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)
alpha = 0xFF - (0xBF / 600.) * min(age, 600)
painter.setPen(QtGui.QColor(0, 0, 0, alpha))
diff --git a/python/modes_sql.py b/python/modes_sql.py
index 58612c6..24cc328 100644
--- a/python/modes_sql.py
+++ b/python/modes_sql.py
@@ -19,7 +19,7 @@
# Boston, MA 02110-1301, USA.
#
-import time, os, sys
+import time, os, sys, math
from string import split, join
import modes_parse
import sqlite3
@@ -54,6 +54,20 @@ 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()
@@ -71,12 +85,8 @@ class modes_output_sql(modes_parse.modes_parse):
if self.db is None:
self.db = sqlite3.connect(self.filename)
- 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
+ self.make_insert_query(message)
+ self.db.commit() #don't know if this is necessary
except ADSBError:
pass
@@ -87,49 +97,60 @@ class modes_output_sql(modes_parse.modes_parse):
data = modes_parse.modes_reply(long(data, 16))
ecc = long(ecc, 16)
-# reference = float(reference)
+ rssi = 10.0*math.log10(float(reference))
query = None
msgtype = data["df"]
if msgtype == 17:
- query = self.sql17(data)
+ query = self.sql17(data, rssi)
return query
- def sql17(self, data):
+ def sql17(self, data, rssi):
icao24 = data["aa"]
subtype = data["ftc"]
-
- retstr = None
+ c = self.db.cursor()
if subtype == 4:
- (msg, typename) = self.parseBDS08(data)
- retstr = "INSERT OR REPLACE INTO ident (icao, ident) VALUES (" + "%i" % icao24 + ", '" + msg + "')"
+ (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))
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
- retstr = None
+ 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))
else:
- retstr = "INSERT INTO positions (icao, seen, alt, lat, lon) VALUES (" + "%i" % icao24 + ", datetime('now'), " + str(altitude) + ", " + "%.6f" % decoded_lat + ", " + "%.6f" % decoded_lon + ")"
+ 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))
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
- retstr = None
+ 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))
else:
- retstr = "INSERT INTO positions (icao, seen, alt, lat, lon) VALUES (" + "%i" % icao24 + ", datetime('now'), " + str(altitude) + ", " + "%.6f" % decoded_lat + ", " + "%.6f" % decoded_lon + ")"
+ 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))
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)
- retstr = "INSERT INTO vectors (icao, seen, speed, heading, vertical) VALUES (" + "%i" % icao24 + ", datetime('now'), " + "%.0f" % velocity + ", " + "%.0f" % heading + ", " + "%.0f" % vert_spd + ")";
+ 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))
- return retstr
+
+ c.close()
diff --git a/res/modes_rx.ui b/res/modes_rx.ui
index 50e1112..8d2fc29 100644
--- a/res/modes_rx.ui
+++ b/res/modes_rx.ui
@@ -776,6 +776,19 @@
Climb
+
+
+
+ 200
+ 30
+ 161
+ 91
+
+
+
+ 4
+
+
@@ -863,6 +876,18 @@
+
+
+ QwtCompass
+ QwtDial
+
+
+
+ QwtDial
+ QWidget
+
+
+