Actually decrement usage count when releasing a service
[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.ScriptService
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     protected double old_lat = 1000;
36     protected double old_lon = 1000;
37
38     public signal void fix_status_changed(int status);
39     public signal void time_changed(uint time);
40     public signal void pos_changed();
41
42     public GPS()
43     {
44         Object(name: "gps");
45         data = libgps.data_t();
46         started = script_status();
47     }
48
49     public int fix_status() { return old_fix_status; }
50     public double time() { return old_time; }
51     public weak libgps.data_t info() { return data; }
52
53     protected bool on_input_data(IOChannel source, IOCondition condition)
54     {
55         while (libgps.waiting(ref data))
56         {
57             int res = libgps.poll(ref data);
58             if (res != 0)
59                 zavai.log.error(libgps.errstr(res));
60
61             if (data.status != old_fix_status)
62             {
63                 fix_status_changed(data.status);
64                 old_fix_status = data.status;
65             }
66
67             uint cur_time = (uint)data.fix.time;
68             if (data.status != libgps.STATUS_NO_FIX && old_time != cur_time)
69             {
70                 time_changed(cur_time);
71                 old_time = cur_time;
72             }
73
74             double lat = (data.status == libgps.STATUS_NO_FIX ? 1000 : data.fix.latitude);
75             double lon = (data.status == libgps.STATUS_NO_FIX ? 1000 : data.fix.longitude);
76             if (lat != old_lat || lon != old_lon)
77                 pos_changed();
78
79             /*
80             stderr.printf("GPSMSG %d %d\n", (int)data.set, data.status);
81             stderr.printf("SATUSED %d\n", data.satellites_used);
82             stderr.printf("SWT %f\n", data.skyview_time);
83             stderr.printf("SATVIS %d\n", data.satellites_visible);
84             for (int i = 0; i < data.satellites_visible; ++i)
85             {
86                 stderr.printf("PRN %d ELE %d AZI %d SS %f\n",
87                     data.PRN[i], data.elevation[i], data.azimuth[i], data.ss[i]);
88             }
89             */
90         }
91         return true;
92     }
93
94     /// Request GPS resource
95     public override void start()
96     {
97         if (started) return;
98
99         if (!script_start()) return;
100
101         zavai.log.info("Connecting to gpsd at " + config.gpsd_host + ":" + config.gpsd_port);
102         int res = libgps.open_r(config.gpsd_host, config.gpsd_port, ref data);
103         if (res != 0)
104         {
105             zavai.log.error(libgps.errstr(res));
106             return;
107         }
108
109         res = libgps.stream(ref data, libgps.WATCH_ENABLE, null);
110         if (res != 0)
111         {
112             zavai.log.error(libgps.errstr(res));
113             return;
114         }
115
116         //res = libgps.send(ref data, "?SKY;");
117         //res = libgps.send(ref data, "?WATCH;");
118         //if (res != 0) zavai.log.error(libgps.errstr(res));
119
120         gpsfd = new IOChannel.unix_new(data.gps_fd);
121         try {
122             gpsfd.set_encoding(null);
123         } catch (Error e) {
124             zavai.log.error("Setting encoding to null on gpsd io channel: " + e.message);
125         }
126         //gpsfd.set_buffered(false);
127         gpsfd_watch = gpsfd.add_watch(IOCondition.IN, on_input_data);
128
129         zavai.log.info("GPS turned on");
130         base.start();
131     }
132
133     // Release usage of GPS
134     public override void stop()
135     {
136         if (!started) return;
137
138         Source.remove(gpsfd_watch);
139
140         int res = libgps.close(ref data);
141         if (res != 0)
142             zavai.log.error(libgps.errstr(res));
143
144         script_stop();
145
146         if (old_fix_status != libgps.STATUS_NO_FIX)
147         {
148             old_fix_status = libgps.STATUS_NO_FIX;
149             fix_status_changed(old_fix_status);
150         }
151
152         if (old_time != 0)
153         {
154             old_time = 0;
155             time_changed(old_time);
156         }
157
158         base.stop();
159     }
160 }
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     protected uint wpt_seq = 0;
192     protected zavai.log.Log log = null;
193
194     public GPX()
195     {
196         Object(name: "gps.gpx");
197     }
198
199     public override void start()
200     {
201         if (!started)
202         {
203             log = zavai.log.log.start("track", "GPS track");
204             base.start();
205         }
206     }
207
208     public override void stop()
209     {
210         if (started)
211         {
212             zavai.log.log.end(log);
213             log = null;
214             base.stop();
215         }
216     }
217
218     // Mark a waypoint
219     public void waypoint(string? name = null)
220     {
221         if (log == null) return;
222
223         string wptname;
224         if (name == null)
225         {
226             wptname = "wpt_%u".printf(wpt_seq);
227             wpt_seq += 1;
228         } else {
229             wptname = name;
230         }
231
232         log.add(wptname);
233     }
234 }
235
236 public zavai.gps.GPS gps = null;
237 public zavai.gps.GPX gpx = null;
238
239 public void init()
240 {
241     gps = new GPS();
242     gpx = new GPX();
243
244 }
245
246 }
247 }