62bcdf787bb1af0567c4e8dcb283ffda3c11ffef
[gregoa/zavai.git] / src / gps.vala
1 /*
2  * gps - gps resource for zavai
3  *
4  * Copyright (C) 2009  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         public dynamic DBus.Object usage;
30         public dynamic DBus.Object device;
31
32         public GPS()
33         {
34                 name = "gps";
35
36                 // see mdbus -s org.freesmartphone.ousaged /org/freesmartphone/Usage
37                 usage = zavai.registry.sbus.get_object(
38                         "org.freesmartphone.ousaged",
39                         "/org/freesmartphone/Usage",
40                         "org.freesmartphone.Usage");
41
42                 device = zavai.registry.sbus.get_object(
43                         "org.freesmartphone.ogpsd", 
44                         "/org/freedesktop/Gypsy",
45                         "org.freedesktop.Gypsy.Device");
46         }
47
48     public void power_cycle(bool aggressive)
49     {
50         // "Have you tried turning it off and on again?"
51         usage.SetResourcePolicy("GPS", "disabled");
52         Thread.usleep(500000);
53         if (aggressive)
54             // Sometimes the GPS crashes because its state contains something
55             // that makes it crash, so we need to remove the saved state or it
56             // crashes again quite soon
57             FileUtils.unlink("/var/lib/freesmartphone/ogpsd.pickle");
58         usage.SetResourcePolicy("GPS", "auto");
59     }
60
61         /// Request GPS resource
62         public override void start()
63         {
64                 if (started) return;
65                 try {
66                         usage.RequestResource("GPS");
67                         zavai.log.info("Acquired GPS");
68                         base.start();
69                 } catch (GLib.Error e) {
70                         zavai.log.error(e.message);
71                 }
72                 base.start();
73         }
74
75         // Release usage of GPS
76         public override void stop()
77         {
78                 if (!started) return;
79                 try {
80                         usage.ReleaseResource("GPS");
81                         zavai.log.info("Released GPS");
82                         base.stop();
83                 } catch (GLib.Error e) {
84                         zavai.log.error(e.message);
85                 }
86                 base.stop();
87         }
88 }
89
90 public class Position : zavai.Service
91 {
92         dynamic DBus.Object position;
93
94         public signal void position_changed(int fields, int tstamp, double lat, double lon, double alt);
95
96         public Position()
97         {
98                 name = "gps.position";
99                 position = zavai.registry.sbus.get_object(
100                         "org.freesmartphone.ogpsd",
101                         "/org/freedesktop/Gypsy",
102                         "org.freedesktop.Gypsy.Position");
103         }
104
105         public void on_position_changed(dynamic DBus.Object pos, int fields, int tstamp, double lat, double lon, double alt)
106         {
107                 zavai.log.info("gps position: position changed");
108                 position_changed(fields, tstamp, lat, lon, alt);
109         }
110
111         public override void start()
112         {
113                 if (started) return;
114                 zavai.log.info("Starting GPS position tracking");
115                 gps.request("gps.position");
116                 position.PositionChanged += on_position_changed;
117                 base.start();
118         }
119
120         public override void stop()
121         {
122                 if (!started) return;
123                 zavai.log.info("Stopping GPS position tracking");
124                 position.PositionChanged -= on_position_changed;
125                 gps.release("gps.position");
126                 base.stop();
127         }
128 }
129
130 // #    def wait_for_fix(self, callback):
131 // #        status = self.gps.GetFixStatus()
132 // #        if status in [2, 3]:
133 // #            zavai.info("We already have a fix, good.")
134 // #            callback()
135 // #            return True
136 // #        else:
137 // #            zavai.info("Waiting for a fix...")
138 // #            self.waiting_for_fix = callback
139 // #            self.bus.add_signal_receiver(
140 // #                self.on_fix_status_changed, 'FixStatusChanged', 'org.freedesktop.Gypsy.Device',
141 // #                'org.freesmartphone.ogpsd', '/org/freedesktop/Gypsy')
142 // #            return False
143 // #
144 // #    def start_recording(self):
145 // #        if self.gps_monitor:
146 // #            self.gps_monitor.stop()
147 // #            self.gps_monitor = None
148 // #
149 // #        if not self.audio:
150 // #            return
151 // #
152 // #        # Sync system time
153 // #        gpstime = self.gps.gps_time.GetTime()
154 // #        subprocess.call(["date", "-s", "@%d" % gpstime])
155 // #        subprocess.call(["hwclock", "--systohc"])
156 // #
157 // #        # Compute basename for output files
158 // #        self.basename = time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime(gpstime))
159 // #        self.basename = os.path.join(AUDIODIR, self.basename)
160 // #
161 // #        # Start recording the GPX track
162 // #        self.gpx = GPX(self.basename)
163 // #        self.gps.track_position(self.on_position_changed)
164 // #
165 // #        # Start recording in background forking arecord
166 // #        self.audio.set_basename(self.basename)
167 // #        self.audio.start_recording()
168 // #
169
170 // Write GPX track and waypoint files
171 public class GPX : Service
172 {
173         public bool tracking {
174                 get { return trk != null; }
175                 set {}
176         }
177         public signal void tracking_changed(bool tracking);
178
179         FileStream trk = null;
180         FileStream wpt = null;
181         int wpt_seq = 1;
182         bool last_valid = false;
183         int last_fields;
184         time_t last_tstamp;
185         double last_lat;
186         double last_lon;
187         double last_alt;
188
189         public GPX()
190         {
191                 name = "gps.gpx";
192         }
193
194         public override void start()
195         {       
196                 if (!started)
197                 {
198                         log.info("Starting GPX trace subsystem");
199                         position.request("gps.gpx");
200                         position.position_changed += on_position_changed;
201                         base.start();
202                 }
203         }
204
205         public override void stop()
206         {
207                 if (started)
208                 {
209                         log.info("Stopping GPX trace subsystem");
210                         position.release("gps.gpx");
211                         position.position_changed -= on_position_changed;
212                         stop_track();
213                         base.stop();
214                 }
215         }
216
217         public void on_position_changed(Position pos, int fields, int tstamp, double lat, double lon, double alt)
218         {
219                 last_fields = fields;
220                 last_tstamp = tstamp;
221                 last_lat = lat;
222                 last_lon = lon;
223                 last_alt = alt;
224                 last_valid = true;
225                 trackpoint();
226         }
227
228         public void start_track(time_t tstamp = 0, string? basename = null)
229         {
230                 string fname;
231                 if (basename != null)
232                         fname = basename;
233                 else
234                 {
235                         time_t now = tstamp == 0 ? time_t() : tstamp;
236
237                         // Compute basename for output files
238                         var t = Time.local(now);
239                         char[] res = new char[25];
240                         t.strftime(res, "%Y-%m-%d-%H-%M-%S");
241                         fname = zavai.config.homedir + "/" + (string)res;
242                 }
243  
244                 trk = FileStream.open(fname + "-trk.gpx", "wt");
245                 trk.puts("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
246                 trk.puts(" <gpx");
247                 trk.puts("     version=\"1.0\"");
248                 trk.printf("     creator=\"zavai %s\"\n", zavai.config.version);
249                 trk.puts("     xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"");
250                 trk.puts("     xmlns=\"http://www.topografix.com/GPX/1/0\"");
251                 trk.puts("     xsi:schemaLocation=\"http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd\">");
252                 trk.puts("   <trk>");
253                 trk.puts("     <trkseg>");
254  
255                 wpt = FileStream.open(fname + "-wpt.gpx", "wt");
256                 wpt.puts("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
257                 wpt.puts(" <gpx");
258                 wpt.puts("     version=\"1.0\"");
259                 wpt.printf("     creator=\"zavai %s\"", zavai.config.version);
260                 wpt.puts("     xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"");
261                 wpt.puts("     xmlns=\"http://www.topografix.com/GPX/1/0\"");
262                 wpt.puts("     xsi:schemaLocation=\"http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd\">");
263  
264                 wpt_seq = 1;
265                 tracking_changed(true);
266         }
267  
268         public void stop_track()
269         {
270                 if (trk != null)
271                 {
272                         trk.puts("</trkseg></trk></gpx>");
273                         trk.flush();
274                         trk = null;
275                 }
276                 if (wpt != null)
277                 {
278                         wpt.puts("</gpx>");
279                         wpt.flush();
280                         wpt = null;
281                 }
282                 last_valid = false;
283                 tracking_changed(false);
284         }
285
286         // Mark a track point
287         public void trackpoint()
288         {
289                 if (!last_valid) return;
290                 if (trk == null)
291                         start_track(last_tstamp);
292
293                 trk.printf("<trkpt lat=\"%f\" lon=\"%f\">\n", last_lat, last_lon);
294                 var t = Time.local(last_tstamp);
295                 char[] ts = new char[25];
296                 t.strftime(ts, "%Y-%m-%dT%H:%M:%SZ");
297                 trk.printf("  <time>%s</time>\n", (string)ts);
298                 trk.printf("  <ele>%f</ele>\n", last_alt);
299                 // if course is not None: print >>self.trk, "    <course>%f</course>" % course
300                 // if speed is not None: print >>self.trk, "    <speed>%f</speed>" % speed
301                 // if fix is not None: print >>self.trk, "    <fix>%f</fix>" % fix
302                 // if hdop is not None: print >>self.trk, "    <hdop>%f</hdop>" % hdop
303                 trk.puts("</trkpt>");
304         }
305
306         // Mark a waypoint
307         public void waypoint(string? name = null)
308         {
309                 if (!last_valid) return;
310                 if (wpt == null)
311                         start_track(last_tstamp);
312
313                 string wptname;
314                 if (name == null)
315                 {
316                         wptname = "wpt_%d".printf(wpt_seq);
317                         wpt_seq += 1;
318                 } else {
319                         wptname = name;
320                 }
321
322                 wpt.printf("<wpt lat=\"%f\" lon=\"%f\">\n", last_lat, last_lon);
323                 wpt.printf("  <name>%s</name>\n", wptname);
324                 var t = Time.local(last_tstamp);
325                 char[] ts = new char[25];
326                 t.strftime(ts, "%Y-%m-%dT%H:%M:%SZ");
327                 wpt.printf("  <time>%s</time>\n", (string)ts);
328                 wpt.printf("  <ele>%f</ele>\n", last_alt);
329                 wpt.puts("</wpt>");
330         }
331 }
332
333 public zavai.gps.GPS gps = null;
334 public zavai.gps.Position position = null;
335 public zavai.gps.GPX gpx = null;
336
337 public void init()
338 {
339         gps = new GPS();
340         position = new Position();
341         gpx = new GPX();
342
343         zavai.registry.register_service(gps);
344         zavai.registry.register_service(position);
345         zavai.registry.register_service(gpx);
346 }
347
348 }
349 }