]> ToastFreeware Gitweb - gregoa/zavai.git/blob - src/gps.vala
Merge branch 'master' into gregoa
[gregoa/zavai.git] / src / gps.vala
1 /*
2  * gps - gps resource for zavai
3  *
4  * Copyright (C) 2009--2010  Enrico Zini <enrico@enricozini.org>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 using GLib;
22
23 namespace zavai {
24 namespace gps {
25
26 // For a list of dbus services, look in /etc/dbus-1/system.d/
27 public class GPS: zavai.Service
28 {
29     protected libgps.data_t data;
30     protected IOChannel gpsfd = null;
31     protected uint gpsfd_watch = 0;
32
33     protected int old_fix_status = libgps.STATUS_NO_FIX;
34     protected uint old_time = 0;
35
36     public signal void fix_status_changed(int status);
37     public signal void time_changed(uint time);
38
39     public GPS()
40     {
41         Object(name: "gps");
42         data = libgps.data_t();
43     }
44
45     public int fix_status() { return old_fix_status; }
46     public double time() { return old_time; }
47
48     protected bool on_input_data(IOChannel source, IOCondition condition)
49     {
50         while (libgps.waiting(ref data))
51         {
52             int res = libgps.poll(ref data);
53             if (res != 0)
54                 zavai.log.error(libgps.errstr(res));
55
56             if (data.status != old_fix_status)
57             {
58                 fix_status_changed(data.status);
59                 old_fix_status = data.status;
60             }
61
62             uint cur_time = (uint)data.fix.time;
63             if (data.status != libgps.STATUS_NO_FIX && old_time != cur_time)
64             {
65                 time_changed(cur_time);
66                 old_time = cur_time;
67             }
68
69             /*
70             stderr.printf("GPSMSG %d %d\n", (int)data.set, data.status);
71             stderr.printf("SATUSED %d\n", data.satellites_used);
72             stderr.printf("SWT %f\n", data.skyview_time);
73             stderr.printf("SATVIS %d\n", data.satellites_visible);
74             for (int i = 0; i < data.satellites_visible; ++i)
75             {
76                 stderr.printf("PRN %d ELE %d AZI %d SS %f\n",
77                     data.PRN[i], data.elevation[i], data.azimuth[i], data.ss[i]);
78             }
79             */
80         }
81         return true;
82     }
83
84     /// Request GPS resource
85     public override void start()
86     {
87         if (started) return;
88
89         try {
90             // Then run our own script
91             zavai.app.run_script(zavai.config.homedir + "/gps start");
92         } catch (Error e) {
93             zavai.log.error("Running " + zavai.config.homedir + "/gps start: " + e.message);
94             return;
95         }
96
97         int res = libgps.open_r("ciapino", "gpsd", ref data);
98         if (res != 0)
99         {
100             zavai.log.error(libgps.errstr(res));
101             return;
102         }
103
104         res = libgps.stream(ref data, libgps.WATCH_ENABLE, null);
105         if (res != 0)
106         {
107             zavai.log.error(libgps.errstr(res));
108             return;
109         }
110
111         res = libgps.send(ref data, "?SKY;");
112         //res = libgps.send(ref data, "?WATCH;");
113         //if (res != 0) zavai.log.error(libgps.errstr(res));
114
115         gpsfd = new IOChannel.unix_new(data.gps_fd);
116         try {
117             gpsfd.set_encoding(null);
118         } catch (Error e) {
119             zavai.log.error("Setting encoding to null on gpsd io channel: " + e.message);
120         }
121         //gpsfd.set_buffered(false);
122         gpsfd_watch = gpsfd.add_watch(IOCondition.IN, on_input_data);
123
124         zavai.log.info("GPS turned on");
125         base.start();
126     }
127
128     // Release usage of GPS
129     public override void stop()
130     {
131         if (!started) return;
132
133         Source.remove(gpsfd_watch);
134
135         int res = libgps.close(ref data);
136         if (res != 0)
137             zavai.log.error(libgps.errstr(res));
138
139         try {
140             zavai.app.run_script(zavai.config.homedir + "/gps stop");
141         } catch (Error e) {
142             zavai.log.error("Running device stop gps: " + e.message);
143         }
144
145         if (old_fix_status != libgps.STATUS_NO_FIX)
146         {
147             old_fix_status = libgps.STATUS_NO_FIX;
148             fix_status_changed(old_fix_status);
149         }
150
151         if (old_time != 0)
152         {
153             old_time = 0;
154             time_changed(old_time);
155         }
156
157         base.stop();
158     }
159 }
160
161 public class Position : zavai.Service
162 {
163         dynamic DBus.Object position;
164
165         public signal void position_changed(int fields, int tstamp, double lat, double lon, double alt);
166
167         public Position()
168         {
169                 Object(name: "gps.position");
170                 position = zavai.registry.sbus.get_object(
171                         "org.freesmartphone.ogpsd",
172                         "/org/freedesktop/Gypsy",
173                         "org.freedesktop.Gypsy.Position");
174         }
175
176         public void on_position_changed(dynamic DBus.Object pos, int fields, int tstamp, double lat, double lon, double alt)
177         {
178                 zavai.log.info("gps position: position changed");
179                 position_changed(fields, tstamp, lat, lon, alt);
180         }
181
182         public override void start()
183         {
184                 if (started) return;
185                 zavai.log.info("Starting GPS position tracking");
186                 gps.request("gps.position");
187                 position.PositionChanged += on_position_changed;
188                 base.start();
189         }
190
191         public override void stop()
192         {
193                 if (!started) return;
194                 zavai.log.info("Stopping GPS position tracking");
195                 position.PositionChanged -= on_position_changed;
196                 gps.release("gps.position");
197                 base.stop();
198         }
199 }
200
201 // #    def wait_for_fix(self, callback):
202 // #        status = self.gps.GetFixStatus()
203 // #        if status in [2, 3]:
204 // #            zavai.info("We already have a fix, good.")
205 // #            callback()
206 // #            return True
207 // #        else:
208 // #            zavai.info("Waiting for a fix...")
209 // #            self.waiting_for_fix = callback
210 // #            self.bus.add_signal_receiver(
211 // #                self.on_fix_status_changed, 'FixStatusChanged', 'org.freedesktop.Gypsy.Device',
212 // #                'org.freesmartphone.ogpsd', '/org/freedesktop/Gypsy')
213 // #            return False
214 // #
215 // #    def start_recording(self):
216 // #        if self.gps_monitor:
217 // #            self.gps_monitor.stop()
218 // #            self.gps_monitor = None
219 // #
220 // #        if not self.audio:
221 // #            return
222 // #
223 // #        # Sync system time
224 // #        gpstime = self.gps.gps_time.GetTime()
225 // #        subprocess.call(["date", "-s", "@%d" % gpstime])
226 // #        subprocess.call(["hwclock", "--systohc"])
227 // #
228 // #        # Compute basename for output files
229 // #        self.basename = time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime(gpstime))
230 // #        self.basename = os.path.join(AUDIODIR, self.basename)
231 // #
232 // #        # Start recording the GPX track
233 // #        self.gpx = GPX(self.basename)
234 // #        self.gps.track_position(self.on_position_changed)
235 // #
236 // #        # Start recording in background forking arecord
237 // #        self.audio.set_basename(self.basename)
238 // #        self.audio.start_recording()
239 // #
240
241 // Write GPX track and waypoint files
242 public class GPX : Service
243 {
244         public bool tracking {
245                 get { return trk != null; }
246                 set {}
247         }
248         public signal void tracking_changed(bool tracking);
249
250         FileStream trk = null;
251         FileStream wpt = null;
252         int wpt_seq = 1;
253         bool last_valid = false;
254         int last_fields;
255         time_t last_tstamp;
256         double last_lat;
257         double last_lon;
258         double last_alt;
259
260         public GPX()
261         {
262                 Object(name: "gps.gpx");
263         }
264
265         public override void start()
266         {       
267                 if (!started)
268                 {
269                         log.info("Starting GPX trace subsystem");
270                         position.request("gps.gpx");
271                         position.position_changed += on_position_changed;
272                         base.start();
273                 }
274         }
275
276         public override void stop()
277         {
278                 if (started)
279                 {
280                         log.info("Stopping GPX trace subsystem");
281                         position.release("gps.gpx");
282                         position.position_changed -= on_position_changed;
283                         stop_track();
284                         base.stop();
285                 }
286         }
287
288         public void on_position_changed(Position pos, int fields, int tstamp, double lat, double lon, double alt)
289         {
290                 last_fields = fields;
291                 last_tstamp = tstamp;
292                 last_lat = lat;
293                 last_lon = lon;
294                 last_alt = alt;
295                 last_valid = true;
296                 trackpoint();
297         }
298
299         public void start_track(time_t tstamp = 0, string? basename = null)
300         {
301                 string fname;
302                 if (basename != null)
303                         fname = basename;
304                 else
305                 {
306                         time_t now = tstamp == 0 ? time_t() : tstamp;
307
308                         // Compute basename for output files
309                         var t = Time.local(now);
310                         char[] res = new char[25];
311                         t.strftime(res, "%Y-%m-%d-%H-%M-%S");
312                         fname = zavai.config.homedir + "/" + (string)res;
313                 }
314  
315                 trk = FileStream.open(fname + "-trk.gpx", "wt");
316                 trk.puts("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
317                 trk.puts(" <gpx");
318                 trk.puts("     version=\"1.0\"");
319                 trk.printf("     creator=\"zavai %s\"\n", zavai.config.version);
320                 trk.puts("     xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"");
321                 trk.puts("     xmlns=\"http://www.topografix.com/GPX/1/0\"");
322                 trk.puts("     xsi:schemaLocation=\"http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd\">");
323                 trk.puts("   <trk>");
324                 trk.puts("     <trkseg>");
325  
326                 wpt = FileStream.open(fname + "-wpt.gpx", "wt");
327                 wpt.puts("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
328                 wpt.puts(" <gpx");
329                 wpt.puts("     version=\"1.0\"");
330                 wpt.printf("     creator=\"zavai %s\"", zavai.config.version);
331                 wpt.puts("     xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"");
332                 wpt.puts("     xmlns=\"http://www.topografix.com/GPX/1/0\"");
333                 wpt.puts("     xsi:schemaLocation=\"http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd\">");
334  
335                 wpt_seq = 1;
336                 tracking_changed(true);
337         }
338  
339         public void stop_track()
340         {
341                 if (trk != null)
342                 {
343                         trk.puts("</trkseg></trk></gpx>");
344                         trk.flush();
345                         trk = null;
346                 }
347                 if (wpt != null)
348                 {
349                         wpt.puts("</gpx>");
350                         wpt.flush();
351                         wpt = null;
352                 }
353                 last_valid = false;
354                 tracking_changed(false);
355         }
356
357         // Mark a track point
358         public void trackpoint()
359         {
360                 if (!last_valid) return;
361                 if (trk == null)
362                         start_track(last_tstamp);
363
364                 trk.printf("<trkpt lat=\"%f\" lon=\"%f\">\n", last_lat, last_lon);
365                 var t = Time.local(last_tstamp);
366                 char[] ts = new char[25];
367                 t.strftime(ts, "%Y-%m-%dT%H:%M:%SZ");
368                 trk.printf("  <time>%s</time>\n", (string)ts);
369                 trk.printf("  <ele>%f</ele>\n", last_alt);
370                 // if course is not None: print >>self.trk, "    <course>%f</course>" % course
371                 // if speed is not None: print >>self.trk, "    <speed>%f</speed>" % speed
372                 // if fix is not None: print >>self.trk, "    <fix>%f</fix>" % fix
373                 // if hdop is not None: print >>self.trk, "    <hdop>%f</hdop>" % hdop
374                 trk.puts("</trkpt>");
375         }
376
377         // Mark a waypoint
378         public void waypoint(string? name = null)
379         {
380                 if (!last_valid) return;
381                 if (wpt == null)
382                         start_track(last_tstamp);
383
384                 string wptname;
385                 if (name == null)
386                 {
387                         wptname = "wpt_%d".printf(wpt_seq);
388                         wpt_seq += 1;
389                 } else {
390                         wptname = name;
391                 }
392
393                 wpt.printf("<wpt lat=\"%f\" lon=\"%f\">\n", last_lat, last_lon);
394                 wpt.printf("  <name>%s</name>\n", wptname);
395                 var t = Time.local(last_tstamp);
396                 char[] ts = new char[25];
397                 t.strftime(ts, "%Y-%m-%dT%H:%M:%SZ");
398                 wpt.printf("  <time>%s</time>\n", (string)ts);
399                 wpt.printf("  <ele>%f</ele>\n", last_alt);
400                 wpt.puts("</wpt>");
401         }
402 }
403
404 public zavai.gps.GPS gps = null;
405 public zavai.gps.Position position = null;
406 public zavai.gps.GPX gpx = null;
407
408 public void init()
409 {
410     gps = new GPS();
411     position = new Position();
412     gpx = new GPX();
413
414 }
415
416 }
417 }