/* * gps - gps resource for zavai * * Copyright (C) 2009--2010 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 */ using GLib; namespace zavai { namespace gps { // For a list of dbus services, look in /etc/dbus-1/system.d/ public class GPS: zavai.Service { protected libgps.data_t data; protected IOChannel gpsfd = null; protected uint gpsfd_watch = 0; protected int old_fix_status = libgps.STATUS_NO_FIX; protected uint old_time = 0; public signal void fix_status_changed(int status); public signal void time_changed(uint time); public GPS() { Object(name: "gps"); data = libgps.data_t(); } public int fix_status() { return old_fix_status; } public double time() { return old_time; } protected bool on_input_data(IOChannel source, IOCondition condition) { while (libgps.waiting(ref data)) { int res = libgps.poll(ref data); if (res != 0) zavai.log.error(libgps.errstr(res)); if (data.status != old_fix_status) { fix_status_changed(data.status); old_fix_status = data.status; } uint cur_time = (uint)data.fix.time; if (data.status != libgps.STATUS_NO_FIX && old_time != cur_time) { time_changed(cur_time); old_time = cur_time; } /* stderr.printf("GPSMSG %d %d\n", (int)data.set, data.status); stderr.printf("SATUSED %d\n", data.satellites_used); stderr.printf("SWT %f\n", data.skyview_time); stderr.printf("SATVIS %d\n", data.satellites_visible); for (int i = 0; i < data.satellites_visible; ++i) { stderr.printf("PRN %d ELE %d AZI %d SS %f\n", data.PRN[i], data.elevation[i], data.azimuth[i], data.ss[i]); } */ } return true; } /// Request GPS resource public override void start() { if (started) return; try { // Then run our own script zavai.app.run_script(zavai.config.homedir + "/gps start"); } catch (Error e) { zavai.log.error("Running " + zavai.config.homedir + "/gps start: " + e.message); return; } int res = libgps.open_r("ciapino", "gpsd", ref data); if (res != 0) { zavai.log.error(libgps.errstr(res)); return; } res = libgps.stream(ref data, libgps.WATCH_ENABLE, null); if (res != 0) { zavai.log.error(libgps.errstr(res)); return; } res = libgps.send(ref data, "?SKY;"); //res = libgps.send(ref data, "?WATCH;"); //if (res != 0) zavai.log.error(libgps.errstr(res)); gpsfd = new IOChannel.unix_new(data.gps_fd); try { gpsfd.set_encoding(null); } catch (Error e) { zavai.log.error("Setting encoding to null on gpsd io channel: " + e.message); } //gpsfd.set_buffered(false); gpsfd_watch = gpsfd.add_watch(IOCondition.IN, on_input_data); zavai.log.info("GPS turned on"); base.start(); } // Release usage of GPS public override void stop() { if (!started) return; Source.remove(gpsfd_watch); int res = libgps.close(ref data); if (res != 0) zavai.log.error(libgps.errstr(res)); try { zavai.app.run_script(zavai.config.homedir + "/gps stop"); } catch (Error e) { zavai.log.error("Running device stop gps: " + e.message); } if (old_fix_status != libgps.STATUS_NO_FIX) { old_fix_status = libgps.STATUS_NO_FIX; fix_status_changed(old_fix_status); } if (old_time != 0) { old_time = 0; time_changed(old_time); } base.stop(); } } public class Position : zavai.Service { dynamic DBus.Object position; public signal void position_changed(int fields, int tstamp, double lat, double lon, double alt); public Position() { Object(name: "gps.position"); position = zavai.registry.sbus.get_object( "org.freesmartphone.ogpsd", "/org/freedesktop/Gypsy", "org.freedesktop.Gypsy.Position"); } public void on_position_changed(dynamic DBus.Object pos, int fields, int tstamp, double lat, double lon, double alt) { zavai.log.info("gps position: position changed"); position_changed(fields, tstamp, lat, lon, alt); } public override void start() { if (started) return; zavai.log.info("Starting GPS position tracking"); gps.request("gps.position"); position.PositionChanged += on_position_changed; base.start(); } public override void stop() { if (!started) return; zavai.log.info("Stopping GPS position tracking"); position.PositionChanged -= on_position_changed; gps.release("gps.position"); base.stop(); } } // # 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 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() // # // Write GPX track and waypoint files public class GPX : Service { public bool tracking { get { return trk != null; } set {} } public signal void tracking_changed(bool tracking); FileStream trk = null; FileStream wpt = null; int wpt_seq = 1; bool last_valid = false; int last_fields; time_t last_tstamp; double last_lat; double last_lon; double last_alt; public GPX() { Object(name: "gps.gpx"); } public override void start() { if (!started) { log.info("Starting GPX trace subsystem"); position.request("gps.gpx"); position.position_changed += on_position_changed; base.start(); } } public override void stop() { if (started) { log.info("Stopping GPX trace subsystem"); position.release("gps.gpx"); position.position_changed -= on_position_changed; stop_track(); base.stop(); } } public void on_position_changed(Position pos, int fields, int tstamp, double lat, double lon, double alt) { last_fields = fields; last_tstamp = tstamp; last_lat = lat; last_lon = lon; last_alt = alt; last_valid = true; trackpoint(); } public void start_track(time_t tstamp = 0, string? basename = null) { string fname; if (basename != null) fname = basename; else { time_t now = tstamp == 0 ? time_t() : tstamp; // Compute basename for output files var t = Time.local(now); char[] res = new char[25]; t.strftime(res, "%Y-%m-%d-%H-%M-%S"); fname = zavai.config.homedir + "/" + (string)res; } trk = FileStream.open(fname + "-trk.gpx", "wt"); trk.puts(""); trk.puts(" "); trk.puts(" "); trk.puts(" "); wpt = FileStream.open(fname + "-wpt.gpx", "wt"); wpt.puts(""); wpt.puts(" "); wpt_seq = 1; tracking_changed(true); } public void stop_track() { if (trk != null) { trk.puts(""); trk.flush(); trk = null; } if (wpt != null) { wpt.puts(""); wpt.flush(); wpt = null; } last_valid = false; tracking_changed(false); } // Mark a track point public void trackpoint() { if (!last_valid) return; if (trk == null) start_track(last_tstamp); trk.printf("\n", last_lat, last_lon); var t = Time.local(last_tstamp); char[] ts = new char[25]; t.strftime(ts, "%Y-%m-%dT%H:%M:%SZ"); trk.printf(" \n", (string)ts); trk.printf(" %f\n", last_alt); // 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 trk.puts(""); } // Mark a waypoint public void waypoint(string? name = null) { if (!last_valid) return; if (wpt == null) start_track(last_tstamp); string wptname; if (name == null) { wptname = "wpt_%d".printf(wpt_seq); wpt_seq += 1; } else { wptname = name; } wpt.printf("\n", last_lat, last_lon); wpt.printf(" %s\n", wptname); var t = Time.local(last_tstamp); char[] ts = new char[25]; t.strftime(ts, "%Y-%m-%dT%H:%M:%SZ"); wpt.printf(" \n", (string)ts); wpt.printf(" %f\n", last_alt); wpt.puts(""); } } public zavai.gps.GPS gps = null; public zavai.gps.Position position = null; public zavai.gps.GPX gpx = null; public void init() { gps = new GPS(); position = new Position(); gpx = new GPX(); } } }