# 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 dbus import zavai class GPSMonitor(zavai.Service): def __init__(self, gps): super(GPSMonitor, self).__init__() 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() 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): zavai.info("gps monitor: satellites changed") self.debug_request() def on_ubxdebug_packet(self, clid, length, data): zavai.info("gps monitor: UBX debug packet") self.notify(clid, length, data) def start(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(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) class GPSPosition(zavai.Service): def __init__(self, gps): self.gps = gps def on_position_changed(self, fields, tstamp, lat, lon, alt): zavai.info("gps position: position changed") self.notify(fields, tstamp, lat, lon, alt) def start(self): self.gps.request(self) self.gps.bus.add_signal_receiver( self.on_position_changed, 'PositionChanged', 'org.freedesktop.Gypsy.Position', 'org.freesmartphone.ogpsd', '/org/freedesktop/Gypsy') def stop(self): self.gps.bus.remove_signal_receiver( self.on_position_changed, 'PositionChanged', 'org.freedesktop.Gypsy.Position', 'org.freesmartphone.ogpsd', '/org/freedesktop/Gypsy') self.gps.release(self) # For a list of dbus services, look in /etc/dbus-1/system.d/ class GPS(zavai.Service): def __init__(self, registry, name): super(GPS, self).__init__() 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.position = GPSPosition(self) def start(self): """Request GPS resource""" self.usage.RequestResource('GPS') zavai.info("Acquired GPS") def stop(self): """Release usage of GPS""" 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 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() # class GPX(zavai.Service): "Write GPX track and waypoint files" def __init__(self, registry, name): self.registry = registry self.trk = None self.wpt = None self.last_pos = None conf = registry.resource("conf") self.trackdir = conf.homedir self.activity_monitors = set() self.started = False def add_activity_monitor(self, cb): self.activity_monitors.add(cb) cb(self, self.last_pos is not None) def del_activity_monitor(self, cb): self.activity_monitors.discard(cb) def notify_activity_monitors(self): for mon in self.activity_monitors: mon(self, self.last_pos is not None) def start(self): zavai.info("Starting GPX trace subsystem") self.started = True gps = self.registry.resource("gps") gps.position.connect(self.on_position_changed) def stop(self): if not self.started: return zavai.info("Stopping GPX trace subsystem") gps = self.registry.resource("gps") gps.position.disconnect(self.on_position_changed) self.stop_track() self.started = False def on_position_changed(self, fields, tstamp, lat, lon, alt): self.last_pos = (fields, tstamp, lat, lon, alt) self.trackpoint() def start_track(self, tstamp = None, basename = None): if basename is None: self.basename = basename elif tstamp is not None: # Compute basename for output files self.basename = time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime(tstamp)) self.basename = os.path.join(self.trackdir, self.basename) self.trk = open(self.basename + "-trk.gpx", "wt") print >>self.trk, """ """ % VERSION self.wpt = open(self.basename + "-wpt.gpx", "wt") print >>self.wpt, """ """ % VERSION self.wpt_seq = 1; self.notify_activity_monitors() def stop_track(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 self.last_pos = None self.notify_activity_monitors() def trackpoint(self): "Mark a track point" if self.last_pos is None: return fields, tstamp, lat, lon, ele = self.last_pos if not self.trk: self.start_track(tstamp) print >>self.trk, """ %f""" % (lat, lon, time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime(tstamp)), 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 waypoint(self, name = None): "Mark a waypoint" if self.last_pos is None: return fields, tstamp, lat, lon, ele = self.last_pos if not self.wpt: self.start_track(tstamp) if name is None: name = "wpt_%d" % self.wpt_seq self.wpt_seq += 1 print >>self.wpt, """ %s %f """ % ( lat, lon, name, time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime(tstamp)), ele) # 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 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))