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
27 def __init__(self, gps):
29 self.gps_ubx = gps.gps_ubx
31 # This piece of machinery is taken from Zhone
32 self.debug_busy = None
33 self.debug_want = set( ["NAV-STATUS", "NAV-SVINFO"] )
34 self.debug_have = set()
35 self.debug_error = set()
37 self.callbacks = 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 for c in self.callbacks:
75 def _start_listening(self):
76 self.gps.request(self)
77 # TODO: find out how come sometimes these events are not sent
78 self.gps.bus.add_signal_receiver(
79 self.on_satellites_changed, 'SatellitesChanged', 'org.freedesktop.Gypsy.Satellite',
80 'org.freesmartphone.ogpsd', '/org/freedesktop/Gypsy')
81 self.gps.bus.add_signal_receiver(
82 self.on_ubxdebug_packet, 'DebugPacket', 'org.freesmartphone.GPS.UBX',
83 'org.freesmartphone.ogpsd', '/org/freedesktop/Gypsy')
86 def _stop_listening(self):
87 self.gps.bus.remove_signal_receiver(
88 self.on_satellites_changed, 'SatellitesChanged', 'org.freedesktop.Gypsy.Satellite',
89 'org.freesmartphone.ogpsd', '/org/freedesktop/Gypsy')
90 self.gps.bus.remove_signal_receiver(
91 self.on_ubxdebug_packet, 'DebugPacket', 'org.freesmartphone.GPS.UBX',
92 'org.freesmartphone.ogpsd', '/org/freedesktop/Gypsy')
93 self.gps.release(self)
95 def connect(self, callback):
96 "Send UBX debug packets to the given callback"
97 do_start = not self.callbacks
98 self.callbacks.add(callback)
100 self._start_listening()
102 def disconnect(self, callback):
103 "Stop sending UBX debug packets to the given callback"
104 if not self.callbacks: return
105 self.callbacks.discard(callback)
106 if not self.callbacks:
107 self._stop_listening()
110 def __init__(self, gps):
112 self.callbacks = set()
114 def on_position_changed(self, fields, tstamp, lat, lon, alt):
115 zavai.info("gps position: position changed")
116 for c in self.callbacks:
117 c(fields, tstamp, lat, lon, alt)
119 def _start_listening(self):
120 self.gps.request(self)
122 self.bus.add_signal_receiver(
123 self.on_position_changed, 'PositionChanged', 'org.freedesktop.Gypsy.Position',
124 'org.freesmartphone.ogpsd', '/org/freedesktop/Gypsy')
126 # TODO: find out how come sometimes these events are not sent
127 self.gps.bus.add_signal_receiver(
128 self.on_satellites_changed, 'SatellitesChanged', 'org.freedesktop.Gypsy.Satellite',
129 'org.freesmartphone.ogpsd', '/org/freedesktop/Gypsy')
130 self.gps.bus.add_signal_receiver(
131 self.on_ubxdebug_packet, 'DebugPacket', 'org.freesmartphone.GPS.UBX',
132 'org.freesmartphone.ogpsd', '/org/freedesktop/Gypsy')
135 def _stop_listening(self):
136 self.gps.bus.remove_signal_receiver(
137 self.on_satellites_changed, 'SatellitesChanged', 'org.freedesktop.Gypsy.Satellite',
138 'org.freesmartphone.ogpsd', '/org/freedesktop/Gypsy')
139 self.gps.bus.remove_signal_receiver(
140 self.on_ubxdebug_packet, 'DebugPacket', 'org.freesmartphone.GPS.UBX',
141 'org.freesmartphone.ogpsd', '/org/freedesktop/Gypsy')
142 self.gps.release(self)
144 def connect(self, callback):
145 "Send position changed messages to the given callback"
146 do_start = not self.callbacks
147 self.callbacks.add(callback)
149 self._start_listening()
151 def disconnect(self, callback):
152 "Stop sending position changed messages to the given callback"
153 if not self.callbacks: return
154 self.callbacks.discard(callback)
155 if not self.callbacks:
156 self._stop_listening()
159 # For a list of dbus services, look in /etc/dbus-1/system.d/
160 class GPS(zavai.Resource):
161 def __init__(self, registry, name):
162 self.bus = registry.resource("dbus.system_bus")
164 # see mdbus -s org.freesmartphone.ousaged /org/freesmartphone/Usage
165 self.usage = self.bus.get_object('org.freesmartphone.ousaged', '/org/freesmartphone/Usage')
166 self.usage = dbus.Interface(self.usage, "org.freesmartphone.Usage")
168 # see mdbus -s org.freesmartphone.ogpsd /org/freedesktop/Gypsy
169 gps = self.bus.get_object('org.freesmartphone.ogpsd', '/org/freedesktop/Gypsy')
170 self.gps = dbus.Interface(gps, "org.freedesktop.Gypsy.Device")
171 self.gps_time = dbus.Interface(gps, "org.freedesktop.Gypsy.Time")
172 self.gps_position = dbus.Interface(gps, 'org.freedesktop.Gypsy.Position')
173 self.gps_ubx = dbus.Interface(gps, 'org.freesmartphone.GPS.UBX')
175 self.monitor = GPSMonitor(self)
176 self.position = GPSPosition(self)
178 self.requestors = set()
180 def request(self, tag):
181 "Request usage of GPS by the subsystem with the given tag"
182 do_start = not self.requestors
183 self.requestors.add(tag)
185 # Request GPS resource
186 self.usage.RequestResource('GPS')
187 zavai.info("Acquired GPS")
189 def release(self, tag):
190 "Release usage of GPS by the subsystem with the given tag"
191 if not self.requestors: return
192 self.requestors.discard(tag)
193 if not self.requestors:
194 self.usage.ReleaseResource('GPS')
195 zavai.info("Released GPS")
199 self.requestors.clear()
200 self.usage.ReleaseResource('GPS')
201 zavai.info("Released GPS")
203 # def wait_for_fix(self, callback):
204 # status = self.gps.GetFixStatus()
205 # if status in [2, 3]:
206 # zavai.info("We already have a fix, good.")
210 # zavai.info("Waiting for a fix...")
211 # self.waiting_for_fix = callback
212 # self.bus.add_signal_receiver(
213 # self.on_fix_status_changed, 'FixStatusChanged', 'org.freedesktop.Gypsy.Device',
214 # 'org.freesmartphone.ogpsd', '/org/freedesktop/Gypsy')
217 # def on_fix_status_changed(self, status):
218 # if status not in [2, 3]: return
220 # zavai.info("Got GPS fix")
221 # self.bus.remove_signal_receiver(
222 # self.on_fix_status_changed, 'FixStatusChanged', 'org.freedesktop.Gypsy.Device',
223 # 'org.freesmartphone.ogpsd', '/org/freedesktop/Gypsy')
225 # if self.waiting_for_fix:
226 # self.waiting_for_fix()
227 # self.waiting_for_fix = None
230 # def start_recording(self):
231 # if self.gps_monitor:
232 # self.gps_monitor.stop()
233 # self.gps_monitor = None
239 # gpstime = self.gps.gps_time.GetTime()
240 # subprocess.call(["date", "-s", "@%d" % gpstime])
241 # subprocess.call(["hwclock", "--systohc"])
243 # # Compute basename for output files
244 # self.basename = time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime(gpstime))
245 # self.basename = os.path.join(AUDIODIR, self.basename)
247 # # Start recording the GPX track
248 # self.gpx = GPX(self.basename)
249 # self.gps.track_position(self.on_position_changed)
251 # # Start recording in background forking arecord
252 # self.audio.set_basename(self.basename)
253 # self.audio.start_recording()
256 class GPX(zavai.Resource):
257 "Write GPX track and waypoint files"
258 def __init__(self, registry, name):
259 self.registry = registry
263 self.requestors = set()
264 conf = registry.resource("conf")
265 self.trackdir = os.path.expanduser("~/.zavai")
266 if conf.has_section("gps"):
267 if conf.has_option("gps", "trackdir"):
268 self.trackdir = conf.get("gps", "trackdir")
269 if not os.path.isdir(self.trackdir):
270 os.makedirs(self.trackdir)
272 def request(self, tag):
273 "Request the GPX trace to be taken"
274 do_start = not self.requestors
275 self.requestors.add(tag)
277 zavai.info("Starting GPX trace subsystem")
278 gps = self.registry.resource("gps")
279 gps.position.connect(self.on_position_changed)
281 def release(self, tag):
282 "Release a GPX trace request"
283 if not self.requestors: return
284 self.requestors.discard(tag)
285 if not self.requestors:
286 zavai.info("Stopping GPX trace subsystem")
287 gps = self.registry.resource("gps")
288 gps.position.disconnect(self.on_position_changed)
291 def on_position_changed(self, fields, tstamp, lat, lon, alt):
292 self.last_pos = (fields, tstamp, lat, lon, alt)
295 def start(basename = None, tstamp = None):
297 # Compute basename for output files
298 basename = time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime(tstamp))
299 basename = os.path.join(self.trackdir, self.basename)
301 self.trk = open(basename + "-trk.gpx", "wt")
302 print >>self.trk, """<?xml version="1.0" encoding="UTF-8"?>
305 creator="audiomap %s"
306 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
307 xmlns="http://www.topografix.com/GPX/1/0"
308 xsi:schemaLocation="http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd">
310 <trkseg>""" % VERSION
312 self.wpt = open(basename + "-wpt.gpx", "wt")
313 print >>self.wpt, """<?xml version="1.0" encoding="UTF-8"?>
316 creator="audiomap %s"
317 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
318 xmlns="http://www.topografix.com/GPX/1/0"
319 xsi:schemaLocation="http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd">""" % VERSION
324 if self.trk is not None:
325 print >>self.trk, "</trkseg></trk></gpx>"
328 if self.wpt is not None:
329 print >>self.wpt, "</gpx>"
337 def trackpoint(self):
339 if self.last_pos is None:
342 fields, tstamp, lat, lon, ele = self.last_pos
347 print >>self.trk, """<trkpt lat="%f" lon="%f">
349 <ele>%f</ele>""" % (lat, lon, time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime(tstamp)), ele)
350 #if course is not None: print >>self.trk, " <course>%f</course>" % course
351 #if speed is not None: print >>self.trk, " <speed>%f</speed>" % speed
352 #if fix is not None: print >>self.trk, " <fix>%f</fix>" % fix
353 #if hdop is not None: print >>self.trk, " <hdop>%f</hdop>" % hdop
354 print >>self.trk, "</trkpt>"
356 def waypoint(self, name = None):
358 if self.last_pos is None:
361 fields, tstamp, lat, lon, ele = self.last_pos
367 name = "wpt_%d" % self.wpt_seq
370 print >>self.wpt, """<wpt lat="%f" lon="%f">
375 lat, lon, name, time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime(tstamp)), ele)
379 # self.audio = Audio(self.make_waypoint)
381 # # Get a fix and start recording
382 # if not self.gps.wait_for_fix(self.start_recording):
383 # self.gps_monitor = GPSMonitor(self.gps)
384 # self.gps_monitor.start()
389 # self.gps_monitor = GPSMonitor(self.gps)
390 # self.gps_monitor.start()
393 # def make_waypoint(self):
394 # if self.gpx is None:
396 # if self.last_pos is None:
397 # self.last_pos = self.gps.gps_position.GetPosition()
398 # (fields, tstamp, lat, lon, alt) = self.last_pos
399 # self.gpx.waypoint(tstamp, lat, lon, alt)
400 # zavai.info("Making waypoint at %s: %f, %f, %f" % (
401 # time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(tstamp)), lat, lon, alt))