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