# gps - gps resource for zavai # # Copyright (C) 2009 Enrico Zini # # 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() # 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, """ """ % VERSION self.wpt = open(basename + "-wpt.gpx", "wt") print >>self.wpt, """ """ % VERSION self.wpt_seq = 1; def stop(self): if self.trk is not None: print >>self.trk, "" self.trk.close() self.trk = None if self.wpt is not None: print >>self.wpt, "" 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, """ %s """ % ( lat, lon, name, time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime(tstamp))) if ele is not None: print >>self.wpt, " %f""" % ele print >>self.wpt, "" def trackpoint(self, tstamp, lat, lon, ele = None, course = None, speed = None, fix = None, hdop = None): print >>self.trk, """ """ % (lat, lon, time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime(tstamp))) if ele is not None: print >>self.trk, " %f" % ele if course is not None: print >>self.trk, " %f" % course if speed is not None: print >>self.trk, " %f" % speed if fix is not None: print >>self.trk, " %f" % fix if hdop is not None: print >>self.trk, " %f" % hdop print >>self.trk, "" # 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))