SQL parser modified to use flat aircraft table. This breaks KML horribly and eventually you should integrate the flat table into the GUI app and revert to the old method for the KML generator.

This commit is contained in:
Nick Foster 2012-07-12 00:02:11 -07:00
parent 5c0ccaa833
commit 0a1d863f5f
3 changed files with 106 additions and 26 deletions

View File

@ -2,6 +2,7 @@
import os, sys, time, threading, datetime import os, sys, time, threading, datetime
from PyQt4 import QtCore,QtGui,QtSql from PyQt4 import QtCore,QtGui,QtSql
from PyQt4.Qwt5 import Qwt
from gnuradio import gr, gru, optfir, eng_notation, blks2 from gnuradio import gr, gru, optfir, eng_notation, blks2
import gnuradio.gr.gr_threading as _threading import gnuradio.gr.gr_threading as _threading
import air_modes import air_modes
@ -30,6 +31,9 @@ class mainwindow(QtGui.QMainWindow):
#default to 3dB #default to 3dB
self.ui.line_threshold.insert("3") 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")) self.ui.combo_ant.setCurrentIndex(self.ui.combo_ant.findText("RX2"))
#check KML by default, leave the rest unchecked. #check KML by default, leave the rest unchecked.
@ -66,22 +70,52 @@ class mainwindow(QtGui.QMainWindow):
self.ui.list_aircraft.setModel(self.datamodel) self.ui.list_aircraft.setModel(self.datamodel)
self.ui.list_aircraft.setModelColumn(0) self.ui.list_aircraft.setModelColumn(0)
#set up dashboard views
self.icaodelegate = ICAOViewDelegate() self.icaodelegate = ICAOViewDelegate()
self.ui.list_aircraft.setItemDelegate(self.icaodelegate) self.ui.list_aircraft.setItemDelegate(self.icaodelegate)
self.dashboard_mapper = QtGui.QDataWidgetMapper() self.dashboard_mapper = QtGui.QDataWidgetMapper()
self.dashboard_mapper.setModel(self.datamodel) 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_latitude, 3)
self.dashboard_mapper.addMapping(self.ui.line_longitude, 4) 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_alt, 5)
self.dashboard_mapper.addMapping(self.ui.line_speed, 6) 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_climb, 8)
self.dashboard_mapper.addMapping(self.ui.line_ident, 9) self.dashboard_mapper.addMapping(self.ui.line_ident, 9)
self.dashboard_mapper.addMapping(self.ui.line_type, 10) 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 #hook up the update signal
self.ui.list_aircraft.selectionModel().currentRowChanged.connect(self.dashboard_mapper.setCurrentModelIndex) 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 #goes and gets valid antenna, sample rate options from the device and grays out appropriate things
def populate_source_options(self): def populate_source_options(self):
@ -173,7 +207,7 @@ class mainwindow(QtGui.QMainWindow):
except: except:
my_position = None my_position = None
self.outputs = [] self.outputs = [self.update_gui_widgets]
self.updates = [] self.updates = []
#output options to populate outputs, updates #output options to populate outputs, updates
@ -222,7 +256,7 @@ class ICAOViewDelegate(QtGui.QStyledItemDelegate):
def paint(self, painter, option, index): def paint(self, painter, option, index):
paintstr = "%x" % index.model().data(index.model().index(index.row(), 0)).toInt()[0] 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()) 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) #minimum alpha is 0x40 (oldest), max is 0xFF (newest)
alpha = 0xFF - (0xBF / 600.) * min(age, 600) alpha = 0xFF - (0xBF / 600.) * min(age, 600)
painter.setPen(QtGui.QColor(0, 0, 0, alpha)) painter.setPen(QtGui.QColor(0, 0, 0, alpha))

View File

@ -19,7 +19,7 @@
# Boston, MA 02110-1301, USA. # Boston, MA 02110-1301, USA.
# #
import time, os, sys import time, os, sys, math
from string import split, join from string import split, join
import modes_parse import modes_parse
import sqlite3 import sqlite3
@ -54,6 +54,20 @@ class modes_output_sql(modes_parse.modes_parse):
"ident" TEXT NOT NULL "ident" TEXT NOT NULL
);""" );"""
c.execute(query) 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() c.close()
#we close the db conn now to reopen it in the output() thread context. #we close the db conn now to reopen it in the output() thread context.
self.db.close() self.db.close()
@ -71,12 +85,8 @@ class modes_output_sql(modes_parse.modes_parse):
if self.db is None: if self.db is None:
self.db = sqlite3.connect(self.filename) self.db = sqlite3.connect(self.filename)
query = self.make_insert_query(message) self.make_insert_query(message)
if query is not None: self.db.commit() #don't know if this is necessary
c = self.db.cursor()
c.execute(query)
c.close()
self.db.commit() #don't know if this is necessary
except ADSBError: except ADSBError:
pass pass
@ -87,49 +97,60 @@ class modes_output_sql(modes_parse.modes_parse):
data = modes_parse.modes_reply(long(data, 16)) data = modes_parse.modes_reply(long(data, 16))
ecc = long(ecc, 16) ecc = long(ecc, 16)
# reference = float(reference) rssi = 10.0*math.log10(float(reference))
query = None query = None
msgtype = data["df"] msgtype = data["df"]
if msgtype == 17: if msgtype == 17:
query = self.sql17(data) query = self.sql17(data, rssi)
return query return query
def sql17(self, data): def sql17(self, data, rssi):
icao24 = data["aa"] icao24 = data["aa"]
subtype = data["ftc"] subtype = data["ftc"]
c = self.db.cursor()
retstr = None
if subtype == 4: if subtype == 4:
(msg, typename) = self.parseBDS08(data) (ident, typename) = self.parseBDS08(data)
retstr = "INSERT OR REPLACE INTO ident (icao, ident) VALUES (" + "%i" % icao24 + ", '" + msg + "')" 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: elif subtype >= 5 and subtype <= 8:
[ground_track, decoded_lat, decoded_lon, rnge, bearing] = self.parseBDS06(data) [ground_track, decoded_lat, decoded_lon, rnge, bearing] = self.parseBDS06(data)
altitude = 0 altitude = 0
if decoded_lat is None: #no unambiguously valid position available 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: 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. 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) [altitude, decoded_lat, decoded_lon, rnge, bearing] = self.parseBDS05(data)
if decoded_lat is None: #no unambiguously valid position available 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: 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: elif subtype == 19:
subsubtype = data["sub"] subsubtype = data["sub"]
if subsubtype == 0: if subsubtype == 0:
[velocity, heading, vert_spd] = self.parseBDS09_0(data) [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: elif 1 <= subsubtype <= 2:
[velocity, heading, vert_spd] = self.parseBDS09_1(data) [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
return retstr 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))
c.close()

View File

@ -776,6 +776,19 @@
<string>Climb</string> <string>Climb</string>
</property> </property>
</widget> </widget>
<widget class="QwtCompass" name="compass_heading">
<property name="geometry">
<rect>
<x>200</x>
<y>30</y>
<width>161</width>
<height>91</height>
</rect>
</property>
<property name="lineWidth">
<number>4</number>
</property>
</widget>
</widget> </widget>
<widget class="QWidget" name="browsertab"> <widget class="QWidget" name="browsertab">
<attribute name="title"> <attribute name="title">
@ -863,6 +876,18 @@
</widget> </widget>
<widget class="QStatusBar" name="statusbar"/> <widget class="QStatusBar" name="statusbar"/>
</widget> </widget>
<customwidgets>
<customwidget>
<class>QwtCompass</class>
<extends>QwtDial</extends>
<header>qwt_compass.h</header>
</customwidget>
<customwidget>
<class>QwtDial</class>
<extends>QWidget</extends>
<header>qwt_dial.h</header>
</customwidget>
</customwidgets>
<resources/> <resources/>
<connections/> <connections/>
</ui> </ui>