1 # gps - gps resource for zavai
3 # Copyright (C) 2009 Enrico Zini <enrico@enricozini.org>
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 class GPSMonitor(zavai.Service):
27 def __init__(self, gps):
28 super(GPSMonitor, self).__init__(["satellites"])
31 self.gps_ubx = gps.gps_ubx
33 # This piece of machinery is taken from Zhone
34 self.debug_busy = None
35 self.debug_want = set( ["NAV-STATUS", "NAV-SVINFO"] )
36 self.debug_have = set()
37 self.debug_error = set()
39 def debug_update(self):
40 if self.debug_busy is None:
41 pending = self.debug_want - self.debug_have - self.debug_error
43 self.debug_busy = pending.pop()
44 self.gps_ubx.SetDebugFilter(
47 reply_handler=self.on_debug_reply,
48 error_handler=self.on_debug_error,
51 def debug_request(self):
52 self.debug_have = set()
55 def on_debug_reply(self):
56 self.debug_have.add(self.debug_busy)
57 self.debug_busy = None
60 def on_debug_error(self, e):
61 zavai.info(e, "error while requesting debug packet %s" % self.debug_busy)
62 self.debug_error.add(self.debug_busy)
63 self.debug_busy = None
66 def on_satellites_changed(self, satellites):
67 zavai.info("gps monitor: satellites changed")
70 def on_ubxdebug_packet(self, clid, length, data):
71 zavai.info("gps monitor: UBX debug packet")
72 self.notify("satellites", clid, length, data)
75 self.gps.connect("gps", self)
76 # TODO: find out how come sometimes these events are not sent
77 self.gps.bus.add_signal_receiver(
78 self.on_satellites_changed, 'SatellitesChanged', 'org.freedesktop.Gypsy.Satellite',
79 'org.freesmartphone.ogpsd', '/org/freedesktop/Gypsy')
80 self.gps.bus.add_signal_receiver(
81 self.on_ubxdebug_packet, 'DebugPacket', 'org.freesmartphone.GPS.UBX',
82 'org.freesmartphone.ogpsd', '/org/freedesktop/Gypsy')
86 self.gps.bus.remove_signal_receiver(
87 self.on_satellites_changed, 'SatellitesChanged', 'org.freedesktop.Gypsy.Satellite',
88 'org.freesmartphone.ogpsd', '/org/freedesktop/Gypsy')
89 self.gps.bus.remove_signal_receiver(
90 self.on_ubxdebug_packet, 'DebugPacket', 'org.freesmartphone.GPS.UBX',
91 'org.freesmartphone.ogpsd', '/org/freedesktop/Gypsy')
92 self.gps.disconnect("gps", self)
95 class GPSPosition(zavai.Service):
96 def __init__(self, gps):
97 super(GPSPosition, self).__init__(["position"])
100 def on_position_changed(self, fields, tstamp, lat, lon, alt):
101 zavai.info("gps position: position changed")
102 self.notify("position", fields, tstamp, lat, lon, alt)
105 self.gps.connect("gps", self)
106 self.gps.bus.add_signal_receiver(
107 self.on_position_changed, 'PositionChanged', 'org.freedesktop.Gypsy.Position',
108 'org.freesmartphone.ogpsd', '/org/freedesktop/Gypsy')
111 self.gps.bus.remove_signal_receiver(
112 self.on_position_changed, 'PositionChanged', 'org.freedesktop.Gypsy.Position',
113 'org.freesmartphone.ogpsd', '/org/freedesktop/Gypsy')
114 self.gps.disconnect("gps", self)
116 # For a list of dbus services, look in /etc/dbus-1/system.d/
117 class GPS(zavai.Service):
118 def __init__(self, registry, name):
119 super(GPS, self).__init__(["gps"])
121 self.bus = registry.resource("dbus.system_bus")
123 # see mdbus -s org.freesmartphone.ousaged /org/freesmartphone/Usage
124 self.usage = self.bus.get_object('org.freesmartphone.ousaged', '/org/freesmartphone/Usage')
125 self.usage = dbus.Interface(self.usage, "org.freesmartphone.Usage")
127 # see mdbus -s org.freesmartphone.ogpsd /org/freedesktop/Gypsy
128 gps = self.bus.get_object('org.freesmartphone.ogpsd', '/org/freedesktop/Gypsy')
129 self.gps = dbus.Interface(gps, "org.freedesktop.Gypsy.Device")
130 self.gps_time = dbus.Interface(gps, "org.freedesktop.Gypsy.Time")
131 self.gps_position = dbus.Interface(gps, 'org.freedesktop.Gypsy.Position')
132 self.gps_ubx = dbus.Interface(gps, 'org.freesmartphone.GPS.UBX')
134 self.monitor = GPSMonitor(self)
135 self.position = GPSPosition(self)
138 """Request GPS resource"""
139 self.usage.RequestResource('GPS')
140 zavai.info("Acquired GPS")
143 """Release usage of GPS"""
144 self.usage.ReleaseResource('GPS')
145 zavai.info("Released GPS")
147 # def wait_for_fix(self, callback):
148 # status = self.gps.GetFixStatus()
149 # if status in [2, 3]:
150 # zavai.info("We already have a fix, good.")
154 # zavai.info("Waiting for a fix...")
155 # self.waiting_for_fix = callback
156 # self.bus.add_signal_receiver(
157 # self.on_fix_status_changed, 'FixStatusChanged', 'org.freedesktop.Gypsy.Device',
158 # 'org.freesmartphone.ogpsd', '/org/freedesktop/Gypsy')
161 # def on_fix_status_changed(self, status):
162 # if status not in [2, 3]: return
164 # zavai.info("Got GPS fix")
165 # self.bus.remove_signal_receiver(
166 # self.on_fix_status_changed, 'FixStatusChanged', 'org.freedesktop.Gypsy.Device',
167 # 'org.freesmartphone.ogpsd', '/org/freedesktop/Gypsy')
169 # if self.waiting_for_fix:
170 # self.waiting_for_fix()
171 # self.waiting_for_fix = None
174 # def start_recording(self):
175 # if self.gps_monitor:
176 # self.gps_monitor.stop()
177 # self.gps_monitor = None
183 # gpstime = self.gps.gps_time.GetTime()
184 # subprocess.call(["date", "-s", "@%d" % gpstime])
185 # subprocess.call(["hwclock", "--systohc"])
187 # # Compute basename for output files
188 # self.basename = time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime(gpstime))
189 # self.basename = os.path.join(AUDIODIR, self.basename)
191 # # Start recording the GPX track
192 # self.gpx = GPX(self.basename)
193 # self.gps.track_position(self.on_position_changed)
195 # # Start recording in background forking arecord
196 # self.audio.set_basename(self.basename)
197 # self.audio.start_recording()
200 class GPX(zavai.Service):
201 "Write GPX track and waypoint files"
202 def __init__(self, registry, name):
203 super(GPX, self).__init__(["gpx"])
204 self.registry = registry
208 conf = registry.resource("conf")
209 self.trackdir = conf.homedir
210 self.activity_monitors = set()
213 def add_activity_monitor(self, cb):
214 self.activity_monitors.add(cb)
215 cb(self, self.last_pos is not None)
217 def del_activity_monitor(self, cb):
218 self.activity_monitors.discard(cb)
220 def notify_activity_monitors(self):
221 for mon in self.activity_monitors:
222 mon(self, self.last_pos is not None)
225 zavai.info("Starting GPX trace subsystem")
227 gps = self.registry.resource("gps")
228 gps.position.connect("gps", self.on_position_changed)
231 if not self.started: return
232 zavai.info("Stopping GPX trace subsystem")
233 gps = self.registry.resource("gps")
234 gps.position.disconnect("gps", self.on_position_changed)
238 def on_position_changed(self, fields, tstamp, lat, lon, alt):
239 self.last_pos = (fields, tstamp, lat, lon, alt)
242 def start_track(self, tstamp = None, basename = None):
244 self.basename = basename
245 elif tstamp is not None:
246 # Compute basename for output files
247 self.basename = time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime(tstamp))
248 self.basename = os.path.join(self.trackdir, self.basename)
250 self.trk = open(self.basename + "-trk.gpx", "wt")
251 print >>self.trk, """<?xml version="1.0" encoding="UTF-8"?>
254 creator="audiomap %s"
255 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
256 xmlns="http://www.topografix.com/GPX/1/0"
257 xsi:schemaLocation="http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd">
259 <trkseg>""" % VERSION
261 self.wpt = open(self.basename + "-wpt.gpx", "wt")
262 print >>self.wpt, """<?xml version="1.0" encoding="UTF-8"?>
265 creator="audiomap %s"
266 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
267 xmlns="http://www.topografix.com/GPX/1/0"
268 xsi:schemaLocation="http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd">""" % VERSION
271 self.notify_activity_monitors()
273 def stop_track(self):
274 if self.trk is not None:
275 print >>self.trk, "</trkseg></trk></gpx>"
278 if self.wpt is not None:
279 print >>self.wpt, "</gpx>"
283 self.notify_activity_monitors()
285 def trackpoint(self):
287 if self.last_pos is None:
290 fields, tstamp, lat, lon, ele = self.last_pos
293 self.start_track(tstamp)
295 print >>self.trk, """<trkpt lat="%f" lon="%f">
297 <ele>%f</ele>""" % (lat, lon, time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime(tstamp)), ele)
298 #if course is not None: print >>self.trk, " <course>%f</course>" % course
299 #if speed is not None: print >>self.trk, " <speed>%f</speed>" % speed
300 #if fix is not None: print >>self.trk, " <fix>%f</fix>" % fix
301 #if hdop is not None: print >>self.trk, " <hdop>%f</hdop>" % hdop
302 print >>self.trk, "</trkpt>"
304 def waypoint(self, name = None):
306 if self.last_pos is None:
309 fields, tstamp, lat, lon, ele = self.last_pos
312 self.start_track(tstamp)
315 name = "wpt_%d" % self.wpt_seq
318 print >>self.wpt, """<wpt lat="%f" lon="%f">
323 lat, lon, name, time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime(tstamp)), ele)
327 # self.audio = Audio(self.make_waypoint)
329 # # Get a fix and start recording
330 # if not self.gps.wait_for_fix(self.start_recording):
331 # self.gps_monitor = GPSMonitor(self.gps)
332 # self.gps_monitor.start()
337 # self.gps_monitor = GPSMonitor(self.gps)
338 # self.gps_monitor.start()
341 # def make_waypoint(self):
342 # if self.gpx is None:
344 # if self.last_pos is None:
345 # self.last_pos = self.gps.gps_position.GetPosition()
346 # (fields, tstamp, lat, lon, alt) = self.last_pos
347 # self.gpx.waypoint(tstamp, lat, lon, alt)
348 # zavai.info("Making waypoint at %s: %f, %f, %f" % (
349 # time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(tstamp)), lat, lon, alt))