--- /dev/null
+#!/usr/bin/python
+#
+# Satellite monitor for Gypsy, based on the zhone satellite monitor
+#
+# Copyright (C) 2009 Enrico Zini <enrico@enricozini.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+import sys
+import os
+import os.path
+import dbus
+import dbus.mainloop.glib
+import gtk
+from gettext import gettext as _
+
+SAT_QI_NAMES = {
+ 0: _("idle"),
+ 1: _("searching"),
+ 2: _("signal acquired"),
+ 3: _("signal unusable"),
+ 4: _("code lock"),
+ 5: _("code&carrier lock"),
+ 6: _("code&carrier lock"),
+ 7: _("receiving data")
+}
+
+
+class GPSMonitor:
+ def __init__(self):
+ self.bus = dbus.SystemBus()
+
+ # see mdbus -s org.freesmartphone.ousaged /org/freesmartphone/Usage
+ self.usage = self.bus.get_object('org.freesmartphone.ousaged', '/org/freesmartphone/Usage')
+ self.usage = dbus.Interface(self.usage, "org.freesmartphone.Usage")
+
+ # see mdbus -s org.freesmartphone.ogpsd /org/freedesktop/Gypsy
+ gps = self.bus.get_object('org.freesmartphone.ogpsd', '/org/freedesktop/Gypsy')
+ self.gps = dbus.Interface(gps, "org.freedesktop.Gypsy.Device")
+ self.gps_ubx = dbus.Interface(gps, 'org.freesmartphone.GPS.UBX')
+
+ # This piece of machinery is taken from Zhone
+ self.debug_busy = None
+ self.debug_want = set( ["NAV-STATUS", "NAV-SVINFO"] )
+ self.debug_have = set()
+ self.debug_error = set()
+
+ self.callback = None
+
+ def debug_update(self):
+ if self.debug_busy is None:
+ pending = self.debug_want - self.debug_have - self.debug_error
+ if pending:
+ self.debug_busy = pending.pop()
+ self.gps_ubx.SetDebugFilter(
+ self.debug_busy,
+ True,
+ reply_handler=self.on_debug_reply,
+ error_handler=self.on_debug_error,
+ )
+
+ def debug_request(self):
+ self.debug_have = set()
+ self.debug_update()
+
+ def on_debug_reply(self):
+ self.debug_have.add(self.debug_busy)
+ self.debug_busy = None
+ self.debug_update()
+
+ def on_debug_error(self, e):
+ zavai.info(e, "error while requesting debug packet %s" % self.debug_busy)
+ self.debug_error.add(self.debug_busy)
+ self.debug_busy = None
+ self.debug_update()
+
+ def on_satellites_changed(self, satellites):
+ self.debug_request()
+
+ def on_ubxdebug_packet(self, clid, length, data):
+ self.callback(clid, length, data)
+
+ def start(self):
+ self.usage.RequestResource('GPS')
+
+ # TODO: find out how come sometimes these events are not sent
+ self.bus.add_signal_receiver(
+ self.on_satellites_changed, 'SatellitesChanged', 'org.freedesktop.Gypsy.Satellite',
+ 'org.freesmartphone.ogpsd', '/org/freedesktop/Gypsy')
+ self.bus.add_signal_receiver(
+ self.on_ubxdebug_packet, 'DebugPacket', 'org.freesmartphone.GPS.UBX',
+ 'org.freesmartphone.ogpsd', '/org/freedesktop/Gypsy')
+ self.debug_request()
+
+ def stop(self):
+ self.bus.remove_signal_receiver(
+ self.on_satellites_changed, 'SatellitesChanged', 'org.freedesktop.Gypsy.Satellite',
+ 'org.freesmartphone.ogpsd', '/org/freedesktop/Gypsy')
+ self.bus.remove_signal_receiver(
+ self.on_ubxdebug_packet, 'DebugPacket', 'org.freesmartphone.GPS.UBX',
+ 'org.freesmartphone.ogpsd', '/org/freedesktop/Gypsy')
+ self.usage.ReleaseResource('GPS')
+
+class SatelliteMonitor(gtk.Window):
+ def __init__(self, **kw):
+ super(SatelliteMonitor, self).__init__()
+
+ self.set_title(_("Satellite monitor"))
+
+ self.gps = GPSMonitor()
+ self.gps.callback = self.on_ubxdebug_packet
+
+ self.store = gtk.ListStore(str, str, str, str, str, str, str, str, str, str, str)
+ self.view = gtk.TreeView(self.store)
+ renderer = gtk.CellRendererText()
+ for idx, name in enumerate((_("CH"), _("ID"), _("SN"), _("ELE"), _("AZI"),
+ _("Used"), _("Diff"), _("Alm"), _("Eph"),
+ _("Bad"), _("Status"))):
+ col = gtk.TreeViewColumn(name)
+ col.pack_start(renderer, False)
+ col.add_attribute(renderer, "text", idx)
+ self.view.append_column(col)
+ self.add(self.view)
+
+ self.connect("destroy", gtk.main_quit)
+ self.set_size_request(100, 200)
+ self.show_all()
+
+ def start(self, *args):
+ self.gps.start()
+
+ def stop(self, *args):
+ self.gps.stop()
+
+ def on_ubxdebug_packet(self, clid, length, data):
+ # In zhone it is cbUBXDebugPacket
+ #if clid == "NAV-STATUS" and data:
+ # i = ["%s: %d" % (k, data[0][k]) for k in sorted(data[0].keys())]
+ # zavai.info("Status:", " ".join(i))
+ ## if data[0]['TTFF']:
+ ## zavai.info("TTFF: %f", data[0]['TTFF']/1000.0)
+ if clid == "NAV-SVINFO":
+ self.handle_ubx_sat_data(data[1:])
+ #else:
+ # zavai.info("gps got ubxdebug packet", clid)
+ # zavai.info("DATA:", data)
+
+ def handle_ubx_sat_data(self, ubxinfo):
+ #zavai.info("CH ID SN ELE AZI Used Diff Alm Eph Bad Status")
+ self.store.clear()
+ for sv in ubxinfo:
+ if sv["CNO"] == 0: continue
+ svid = sv["SVID"]
+ used = sv["Flags"] & 0x01
+ diff = sv["Flags"] & 0x02
+ almoreph = sv["Flags"] & 0x04
+ eph = sv["Flags"] & 0x08
+ bad = sv["Flags"] & 0x10
+ qi = ("%i: " % sv["QI"]) + SAT_QI_NAMES.get(sv["QI"], _("Unknown"))
+ self.store.append([
+ "%2d" % sv["chn"],
+ "%2d" % sv["SVID"],
+ "%2d" % sv["CNO"],
+ "%3d" % sv["Elev"],
+ "%3d" % sv["Azim"],
+ used and "used" or "",
+ diff and "diff" or "",
+ almoreph and "alm" or "",
+ eph and "eph" or "",
+ bad and "bad" or "",
+ qi])
+
+if __name__ == "__main__":
+ dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+
+ app = SatelliteMonitor()
+ app.start()
+ gtk.main()
+
+