Started GPS resource
authorEnrico Zini <enrico@enricozini.org>
Sun, 14 Jun 2009 04:35:48 +0000 (12:35 +0800)
committerEnrico Zini <enrico@enricozini.org>
Sun, 14 Jun 2009 04:35:48 +0000 (12:35 +0800)
src/zavai
zavai/__init__.py
zavai/gps.py [new file with mode: 0755]

index 2997491886bc6298a35b790d30f91797a9019346..e86977a7b5b77022252d26880dd8c9199950ea54 100755 (executable)
--- a/src/zavai
+++ b/src/zavai
@@ -64,6 +64,7 @@ registry.register("dbus.system_bus", dbus.SystemBus)
 registry.register("conf", lambda *args, **kw: conf)
 registry.register("app", zavai.Zavai)
 registry.register("menu", zavai.Menu)
+registry.register("gps", zavai.GPS)
 
 # Load plugins
 zavai.info("Loading plugins")
index aea5a9349dd93c7ecf983ac2fd2b8e3425386782..9a788d97bba1814b59b041463bee8f74926598ab 100644 (file)
@@ -21,6 +21,7 @@ from plugins import load_plugins
 from registry import Registry, Resource
 from menu import Menu, MenuLink
 from app import Zavai
+from gps import GPS, GPX
 
 def warn(*args):
     import sys
diff --git a/zavai/gps.py b/zavai/gps.py
new file mode 100755 (executable)
index 0000000..22e3a6d
--- /dev/null
@@ -0,0 +1,364 @@
+# gps - gps resource for zavai
+#
+# 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 time
+#import struct
+#import signal
+#import optparse
+#import dbus
+#import dbus.mainloop.glib
+#import gobject
+import zavai
+
+class GPSMonitor():
+    def __init__(self, gps):
+        self.gps = gps
+        self.gps_ubx = gps.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.callbacks = set()
+
+    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.gps_debug.request()
+
+    def on_ubxdebug_packet(self, clid, length, data):
+        for c in self.callbacks:
+            c(clid, length, data)
+
+    def _start_listening(self):
+        self.gps.request(self)
+        # TODO: find out how come sometimes these events are not sent
+        self.gps.bus.add_signal_receiver(
+            self.on_satellites_changed, 'SatellitesChanged', 'org.freedesktop.Gypsy.Satellite',
+            'org.freesmartphone.ogpsd', '/org/freedesktop/Gypsy')
+        self.gps.bus.add_signal_receiver(
+            self.on_ubxdebug_packet, 'DebugPacket', 'org.freesmartphone.GPS.UBX',
+            'org.freesmartphone.ogpsd', '/org/freedesktop/Gypsy')
+        self.debug_request()
+
+    def _stop_listening(self):
+        self.gps.bus.remove_signal_receiver(
+            self.on_satellites_changed, 'SatellitesChanged', 'org.freedesktop.Gypsy.Satellite',
+            'org.freesmartphone.ogpsd', '/org/freedesktop/Gypsy')
+        self.gps.bus.remove_signal_receiver(
+            self.on_ubxdebug_packet, 'DebugPacket', 'org.freesmartphone.GPS.UBX',
+            'org.freesmartphone.ogpsd', '/org/freedesktop/Gypsy')
+        self.gps.release(self)
+
+    def connect(self, callback):
+        "Send UBX debug packets to the given callback"
+        do_start = not self.callbacks
+        self.callbacks.add(callback)
+        if do_start:
+            self._start_listening()
+
+    def disconnect(self, callback):
+        "Stop sending UBX debug packets to the given callback"
+        if not self.callbacks: return
+        self.callbacks.discard(callback)
+        if not self.callbacks:
+            self._stop_listening()
+
+#        # 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.print_ubx_sat_data(data[1:])
+#        #else:
+#        #    zavai.info("gps got ubxdebug packet", clid)
+#        #    zavai.info("DATA:", data)
+#
+#    def print_ubx_sat_data(self, ubxinfo):
+#        zavai.info("CH ID SN ELE AZI Used Diff Alm Eph Bad Status")
+#        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"]) + {
+#                0: "idle",
+#                1: "searching",
+#                2: "signal acquired",
+#                3: "signal unusable",
+#                4: "code lock",
+#                5: "code&carrier lock",
+#                6: "code&carrier lock",
+#                7: "receiving data"
+#            }[sv["QI"]]
+#            zavai.info("%2d %2d %2d %3d %3d %s %s %s %s %s %s" % (
+#                sv["chn"], sv["SVID"],
+#                sv["CNO"], sv["Elev"], sv["Azim"],
+#                used and "used" or "----",
+#                diff and "diff" or "----",
+#                almoreph and "alm" or "---",
+#                eph and "eph" or "---",
+#                bad and "bad" or "---",
+#                qi))
+#
+#    def print_sat_data(self, satellites):
+#        for sat in satellites:
+#            if sat[4] == 0: continue
+#            zavai.info("PRN %u" % sat[0],
+#                 sat[1] and "used" or "unused",
+#                 "el %u" % sat[2],
+#                 "az %u" % sat[3],
+#                 "snr %u" % sat[4])
+
+# For a list of dbus services, look in /etc/dbus-1/system.d/
+class GPS(zavai.Resource):
+    def __init__(self, registry, name):
+        self.bus = registry.resource("dbus.system_bus")
+
+        # 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_time = dbus.Interface(gps, "org.freedesktop.Gypsy.Time")
+        self.gps_position = dbus.Interface(gps, 'org.freedesktop.Gypsy.Position')
+        self.gps_ubx = dbus.Interface(gps, 'org.freesmartphone.GPS.UBX')
+
+        self.monitor = GPSMonitor(self)
+
+        self.requestors = set()
+
+    def request(self, tag):
+        "Request usage of GPS by the subsystem with the given tag"
+        do_start = not self.requestors
+        self.requestors.add(tag)
+        if do_start:
+            # Request GPS resource
+            self.usage.RequestResource('GPS')
+            zavai.info("Acquired GPS")
+
+    def release(self, tag):
+        "Release usage of GPS by the subsystem with the given tag"
+        if not self.requestors: return
+        self.requestors.discard(tag)
+        if not self.requestors:
+            self.usage.ReleaseResource('GPS')
+            zavai.info("Released GPS")
+
+    def shutdown(self):
+        if self.requestors:
+            self.requestors.clear()
+            self.usage.ReleaseResource('GPS')
+            zavai.info("Released GPS")
+
+#    def wait_for_fix(self, callback):
+#        status = self.gps.GetFixStatus()
+#        if status in [2, 3]:
+#            zavai.info("We already have a fix, good.")
+#            callback()
+#            return True
+#        else:
+#            zavai.info("Waiting for a fix...")
+#            self.waiting_for_fix = callback
+#            self.bus.add_signal_receiver(
+#                self.on_fix_status_changed, 'FixStatusChanged', 'org.freedesktop.Gypsy.Device',
+#                'org.freesmartphone.ogpsd', '/org/freedesktop/Gypsy')
+#            return False
+#
+#    def on_fix_status_changed(self, status):
+#        if status not in [2, 3]: return
+#
+#        zavai.info("Got GPS fix")
+#        self.bus.remove_signal_receiver(
+#            self.on_fix_status_changed, 'FixStatusChanged', 'org.freedesktop.Gypsy.Device',
+#            'org.freesmartphone.ogpsd', '/org/freedesktop/Gypsy')
+#
+#        if self.waiting_for_fix:
+#            self.waiting_for_fix()
+#            self.waiting_for_fix = None
+#
+#    def track_position(self, callback):
+#        self.bus.add_signal_receiver(
+#            callback, 'PositionChanged', 'org.freedesktop.Gypsy.Position',
+#            'org.freesmartphone.ogpsd', '/org/freedesktop/Gypsy')
+
+
+class GPX(zavai.Resource):
+    "Write GPX track and waypoint files"
+    def __init__(self, resource, name):
+        self.resource = resource
+        self.trk = None
+        self.wpt = None
+
+    def start(basename = None, tstamp = None):
+        if basename is None:
+            # compute it from GPS
+            pass
+
+        self.trk = open(basename + "-trk.gpx", "wt")
+        print >>self.trk, """<?xml version="1.0" encoding="UTF-8"?>
+<gpx
+    version="1.0"
+    creator="audiomap %s"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xmlns="http://www.topografix.com/GPX/1/0"
+    xsi:schemaLocation="http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd">
+  <trk>
+    <trkseg>""" % VERSION
+
+        self.wpt = open(basename + "-wpt.gpx", "wt")
+        print >>self.wpt, """<?xml version="1.0" encoding="UTF-8"?>
+<gpx
+    version="1.0"
+    creator="audiomap %s"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xmlns="http://www.topografix.com/GPX/1/0"
+    xsi:schemaLocation="http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd">""" % VERSION
+
+        self.wpt_seq = 1;
+
+    def stop(self):
+        if self.trk is not None:
+            print >>self.trk, "</trkseg></trk></gpx>"
+            self.trk.close()
+            self.trk = None
+        if self.wpt is not None:
+            print >>self.wpt, "</gpx>"
+            self.wpt.close()
+            self.wpt = None
+
+    def shutdown(self):
+        self.stop()
+
+    def waypoint(self, tstamp, lat, lon, ele = None, name = None):
+        "Mark a waypoint"
+        if name is None:
+            name = "wpt_%d" % self.wpt_seq
+            self.wpt_seq += 1
+
+        print >>self.wpt, """<wpt lat="%f" lon="%f">
+    <name>%s</name>
+    <time>%s</time>""" % (
+            lat, lon, name, time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime(tstamp)))
+        if ele is not None:
+            print >>self.wpt, "    <ele>%f</ele>""" % ele
+        print >>self.wpt, "</wpt>"
+
+    def trackpoint(self, tstamp, lat, lon, ele = None, course = None, speed = None, fix = None, hdop = None):
+        print >>self.trk, """<trkpt lat="%f" lon="%f">
+  <time>%s</time>""" % (lat, lon, time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime(tstamp)))
+        if ele is not None: print >>self.trk, "    <ele>%f</ele>" % ele
+        if course is not None: print >>self.trk, "    <course>%f</course>" % course
+        if speed is not None: print >>self.trk, "    <speed>%f</speed>" % speed
+        if fix is not None: print >>self.trk, "    <fix>%f</fix>" % fix
+        if hdop is not None: print >>self.trk, "    <hdop>%f</hdop>" % hdop
+        print >>self.trk, "</trkpt>"
+
+
+
+
+#    def record(self):
+#        self.audio = Audio(self.make_waypoint)
+#        self.gps = GPS()
+#        # Get a fix and start recording
+#        if not self.gps.wait_for_fix(self.start_recording):
+#            self.gps_monitor = GPSMonitor(self.gps)
+#            self.gps_monitor.start()
+#
+#    def monitor(self):
+#        self.audio = None
+#        self.gps = GPS()
+#        self.gps_monitor = GPSMonitor(self.gps)
+#        self.gps_monitor.start()
+#
+#    def start_recording(self):
+#        if self.gps_monitor:
+#            self.gps_monitor.stop()
+#            self.gps_monitor = None
+#
+#        if not self.audio:
+#            return
+#
+#        # Sync system time
+#        gpstime = self.gps.gps_time.GetTime()
+#        subprocess.call(["date", "-s", "@%d" % gpstime])
+#        subprocess.call(["hwclock", "--systohc"])
+#
+#        # Compute basename for output files
+#        self.basename = time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime(gpstime))
+#        self.basename = os.path.join(AUDIODIR, self.basename)
+#
+#        # Start recording the GPX track
+#        self.gpx = GPX(self.basename)
+#        self.gps.track_position(self.on_position_changed)
+#
+#        # Start recording in background forking arecord
+#        self.audio.set_basename(self.basename)
+#        self.audio.start_recording()
+#
+#    def on_position_changed(self, fields, tstamp, lat, lon, alt):
+#        self.last_pos = (fields, tstamp, lat, lon, alt)
+#        if self.gpx:
+#            self.gpx.trackpoint(tstamp, lat, lon, alt)
+#
+#    def make_waypoint(self):
+#        if self.gpx is None:
+#            return
+#        if self.last_pos is None:
+#            self.last_pos = self.gps.gps_position.GetPosition()
+#        (fields, tstamp, lat, lon, alt) = self.last_pos
+#        self.gpx.waypoint(tstamp, lat, lon, alt)
+#        zavai.info("Making waypoint at %s: %f, %f, %f" % (
+#            time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(tstamp)), lat, lon, alt))