Parent Directory | Revision Log
GPS focus enable, portrait support and some attribute icon work
1 | harbaum | 1 | /* |
2 | harbaum | 282 | * Copyright (C) 2009 Till Harbaum <till@harbaum.org>. |
3 | harbaum | 1 | * |
4 | harbaum | 282 | * This file is part of Maep. |
5 | harbaum | 1 | * |
6 | harbaum | 282 | * Maep is free software: you can redistribute it and/or modify |
7 | harbaum | 1 | * it under the terms of the GNU General Public License as published by |
8 | * the Free Software Foundation, either version 3 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | harbaum | 282 | * Maep is distributed in the hope that it will be useful, |
12 | harbaum | 1 | * 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 | harbaum | 282 | * along with Maep. If not, see <http://www.gnu.org/licenses/>. |
18 | harbaum | 1 | */ |
19 | |||
20 | harbaum | 282 | /* |
21 | * This version focusses on low power consumption. This means that | ||
22 | * a component can register for GPS callbacks for certain events | ||
23 | * (e.g. position change, altitude change, track change ...) and it | ||
24 | * will only get notified if one of these changes. Also it's been | ||
25 | * verified that the change in question exceed a certain limit. | ||
26 | */ | ||
27 | |||
28 | harbaum | 1 | #include <stdio.h> |
29 | #include <string.h> | ||
30 | #include <math.h> | ||
31 | harbaum | 282 | #include <stdlib.h> |
32 | harbaum | 1 | |
33 | #ifdef USE_MAEMO | ||
34 | #ifdef ENABLE_GPSBT | ||
35 | #include <gpsbt.h> | ||
36 | #include <gpsmgr.h> | ||
37 | #endif | ||
38 | #include <errno.h> | ||
39 | harbaum | 282 | #else |
40 | #ifdef USE_LIBGPS | ||
41 | #include <gps.h> | ||
42 | #include <locale.h> | ||
43 | harbaum | 1 | #endif |
44 | harbaum | 282 | #endif |
45 | harbaum | 1 | |
46 | harbaum | 282 | #include "gps.h" |
47 | harbaum | 156 | |
48 | harbaum | 282 | static void gps_unregister_all(gps_state_t *gps_state); |
49 | harbaum | 1 | |
50 | harbaum | 282 | /* limits below which a fix is considered different */ |
51 | #define TRACK_PRECISION (1.0) // one degree | ||
52 | #define POS_PRECISION (1.0/60000.0) // 0.001 minute | ||
53 | #define EPH_PRECISION (2.0) // 2 meters | ||
54 | #define ALTITUDE_PRECISION (1.0) // 1 meters | ||
55 | harbaum | 1 | |
56 | harbaum | 282 | static gboolean |
57 | track_differs(struct gps_t *fix1, struct gps_t *fix2) { | ||
58 | return( fabsf(fix1->track - fix2->track) >= TRACK_PRECISION); | ||
59 | } | ||
60 | harbaum | 1 | |
61 | harbaum | 282 | static gboolean |
62 | latlon_differs(struct gps_t *fix1, struct gps_t *fix2) { | ||
63 | if( fabsf(fix1->latitude - fix2->latitude) >= POS_PRECISION) | ||
64 | return TRUE; | ||
65 | harbaum | 1 | |
66 | harbaum | 282 | if( fabsf(fix1->longitude - fix2->longitude) >= POS_PRECISION) |
67 | return TRUE; | ||
68 | harbaum | 1 | |
69 | harbaum | 282 | return FALSE; |
70 | } | ||
71 | harbaum | 1 | |
72 | harbaum | 282 | static gboolean |
73 | eph_differs(struct gps_t *fix1, struct gps_t *fix2) { | ||
74 | return( fabsf(fix1->eph - fix2->eph) >= EPH_PRECISION); | ||
75 | } | ||
76 | harbaum | 1 | |
77 | harbaum | 282 | static gboolean |
78 | altitude_differs(struct gps_t *fix1, struct gps_t *fix2) { | ||
79 | return( fabsf(fix1->altitude - fix2->altitude) >= ALTITUDE_PRECISION); | ||
80 | harbaum | 1 | } |
81 | |||
82 | harbaum | 282 | static void gps_cb_func(gpointer data, gpointer user_data) { |
83 | gps_callback_t *callback = (gps_callback_t*)data; | ||
84 | gps_state_t *gps_state = (gps_state_t*)user_data; | ||
85 | harbaum | 1 | |
86 | harbaum | 282 | /* we can save some energy here if we make sure that */ |
87 | /* we really only wake up the main app whenever the */ | ||
88 | /* gps state changed in a way that the map needs to */ | ||
89 | /* be updated */ | ||
90 | |||
91 | /* for all data check if its status has changed (data is available */ | ||
92 | /* or not) or if the data itself changed */ | ||
93 | harbaum | 1 | |
94 | harbaum | 282 | /* clear "changed" bits */ |
95 | gps_state->set &= ~CHANGED_MASK; | ||
96 | harbaum | 1 | |
97 | harbaum | 282 | /* check for changes in position */ |
98 | if(callback->mask & LATLON_CHANGED && | ||
99 | (((gps_state->set & FIX_LATLON_SET) != | ||
100 | (gps_state->last.set & FIX_LATLON_SET)) || | ||
101 | ((gps_state->set & FIX_LATLON_SET) && | ||
102 | latlon_differs(&gps_state->last.fix, &gps_state->fix)))) | ||
103 | gps_state->set |= LATLON_CHANGED; | ||
104 | harbaum | 1 | |
105 | harbaum | 282 | /* check for changes in eph */ |
106 | if(callback->mask & HERR_CHANGED && | ||
107 | (((gps_state->set & FIX_HERR_SET) != | ||
108 | (gps_state->last.set & FIX_HERR_SET)) || | ||
109 | ((gps_state->set & FIX_HERR_SET) && | ||
110 | eph_differs(&gps_state->last.fix, &gps_state->fix)))) | ||
111 | gps_state->set |= HERR_CHANGED; | ||
112 | harbaum | 1 | |
113 | harbaum | 282 | /* check for changes in track */ |
114 | if(callback->mask & TRACK_CHANGED && | ||
115 | (((gps_state->set & FIX_TRACK_SET) != | ||
116 | (gps_state->last.set & FIX_TRACK_SET)) || | ||
117 | ((gps_state->set & FIX_TRACK_SET) && | ||
118 | track_differs(&gps_state->last.fix, &gps_state->fix)))) | ||
119 | gps_state->set |= TRACK_CHANGED; | ||
120 | |||
121 | /* check for changes in altitude */ | ||
122 | if(callback->mask & ALTITUDE_CHANGED && | ||
123 | (((gps_state->set & FIX_ALTITUDE_SET) != | ||
124 | (gps_state->last.set & FIX_ALTITUDE_SET)) || | ||
125 | ((gps_state->set & FIX_ALTITUDE_SET) && | ||
126 | altitude_differs(&gps_state->last.fix, &gps_state->fix)))) | ||
127 | gps_state->set |= ALTITUDE_CHANGED; | ||
128 | |||
129 | if(gps_state->set & CHANGED_MASK) | ||
130 | callback->cb(gps_state->set, &gps_state->fix, callback->data); | ||
131 | harbaum | 1 | } |
132 | |||
133 | harbaum | 282 | #ifndef ENABLE_LIBLOCATION |
134 | harbaum | 1 | |
135 | harbaum | 282 | static gboolean gps_notify(gpointer data) { |
136 | gps_state_t *gps_state = (gps_state_t*)data; | ||
137 | harbaum | 1 | |
138 | harbaum | 282 | if(gps_state->callbacks) { |
139 | g_mutex_lock(gps_state->mutex); | ||
140 | harbaum | 1 | |
141 | harbaum | 282 | /* tell all clients */ |
142 | g_slist_foreach(gps_state->callbacks, gps_cb_func, gps_state); | ||
143 | harbaum | 1 | |
144 | harbaum | 282 | g_mutex_unlock(gps_state->mutex); |
145 | } | ||
146 | harbaum | 1 | |
147 | harbaum | 282 | /* remember last state reported */ |
148 | gps_state->last.set = gps_state->set; | ||
149 | gps_state->last.fix = gps_state->fix; | ||
150 | |||
151 | return FALSE; | ||
152 | harbaum | 1 | } |
153 | |||
154 | harbaum | 282 | #ifndef USE_LIBGPS |
155 | |||
156 | /* maybe user configurable later on ... */ | ||
157 | #define GPSD_HOST "127.0.0.1" | ||
158 | #define GPSD_PORT 2947 | ||
159 | |||
160 | harbaum | 1 | static int gps_connect(gps_state_t *gps_state) { |
161 | GnomeVFSResult vfs_result; | ||
162 | harbaum | 282 | |
163 | harbaum | 1 | #ifdef USE_MAEMO |
164 | char errstr[256] = ""; | ||
165 | |||
166 | harbaum | 160 | if(!gps_state) { |
167 | printf("No gps state\n"); | ||
168 | return -1; | ||
169 | } | ||
170 | |||
171 | harbaum | 1 | /* We need to start gpsd (via gpsbt) first. */ |
172 | memset(&gps_state->context, 0, sizeof(gpsbt_t)); | ||
173 | errno = 0; | ||
174 | |||
175 | if(gpsbt_start(NULL, 0, 0, 0, errstr, sizeof(errstr), | ||
176 | 0, &gps_state->context) < 0) { | ||
177 | harbaum | 156 | printf("gps: Error connecting to GPS receiver: (%d) %s (%s)\n", |
178 | harbaum | 1 | errno, strerror(errno), errstr); |
179 | } | ||
180 | #endif | ||
181 | |||
182 | /************** from here down pure gnome/gtk/gpsd ********************/ | ||
183 | |||
184 | /* try to connect to gpsd */ | ||
185 | /* Create a socket to interact with GPSD. */ | ||
186 | |||
187 | int retries = 5; | ||
188 | while(retries && | ||
189 | (GNOME_VFS_OK != (vfs_result = gnome_vfs_inet_connection_create( | ||
190 | &gps_state->iconn, GPSD_HOST, GPSD_PORT, NULL)))) { | ||
191 | harbaum | 156 | printf("gps: Error creating connection to GPSD, retrying ...\n"); |
192 | harbaum | 1 | |
193 | retries--; | ||
194 | sleep(1); | ||
195 | } | ||
196 | |||
197 | if(!retries) { | ||
198 | harbaum | 156 | printf("gps: Finally failed ...\n"); |
199 | harbaum | 1 | return -1; |
200 | } | ||
201 | |||
202 | retries = 5; | ||
203 | while(retries && ((gps_state->socket = | ||
204 | gnome_vfs_inet_connection_to_socket(gps_state->iconn)) == NULL)) { | ||
205 | harbaum | 282 | printf("gps: Error connecting GPSD socket, retrying ...\n"); |
206 | harbaum | 1 | |
207 | retries--; | ||
208 | sleep(1); | ||
209 | } | ||
210 | |||
211 | if(!retries) { | ||
212 | harbaum | 156 | printf("gps: Finally failed ...\n"); |
213 | harbaum | 1 | return -1; |
214 | } | ||
215 | |||
216 | GTimeVal timeout = { 10, 0 }; | ||
217 | if(GNOME_VFS_OK != (vfs_result = gnome_vfs_socket_set_timeout( | ||
218 | gps_state->socket, &timeout, NULL))) { | ||
219 | harbaum | 156 | printf("gps: Error setting GPSD timeout\n"); |
220 | harbaum | 1 | return -1; |
221 | } | ||
222 | |||
223 | harbaum | 156 | printf("gps: GPSD connected ...\n"); |
224 | harbaum | 1 | |
225 | return 0; | ||
226 | } | ||
227 | |||
228 | harbaum | 282 | static double parse_double(char *val) { |
229 | if(val[0] == '?') return NAN; | ||
230 | return g_ascii_strtod(val, NULL); | ||
231 | harbaum | 1 | } |
232 | |||
233 | /* unpack a daemon response into a status structure */ | ||
234 | harbaum | 282 | static void gps_unpack(char *buf, gps_state_t *gps_state) { |
235 | harbaum | 1 | char *ns, *sp, *tp; |
236 | harbaum | 282 | int j; |
237 | harbaum | 1 | |
238 | for(ns = buf; ns; ns = strstr(ns+1, "GPSD")) { | ||
239 | if(strncmp(ns, "GPSD", 4) == 0) { | ||
240 | /* the following should execute each time we have a good next sp */ | ||
241 | for (sp = ns + 5; *sp != '\0'; sp = tp+1) { | ||
242 | tp = sp + strcspn(sp, ",\r\n"); | ||
243 | if (*tp == '\0') tp--; | ||
244 | else *tp = '\0'; | ||
245 | |||
246 | switch (*sp) { | ||
247 | case 'O': | ||
248 | if (sp[2] == '?') { | ||
249 | harbaum | 282 | gps_state->fix.latitude = NAN; |
250 | gps_state->fix.longitude = NAN; | ||
251 | gps_state->fix.altitude = NAN; | ||
252 | gps_state->fix.track = NAN; | ||
253 | gps_state->fix.eph = NAN; | ||
254 | harbaum | 1 | } else { |
255 | char tag[MAXTAGLEN+1], alt[20]; | ||
256 | harbaum | 282 | char eph[20], track[20],speed[20]; |
257 | char lat[20], lon[20]; | ||
258 | if(sscanf(sp+2, | ||
259 | "%8s %*s %*s %19s %19s " | ||
260 | "%19s %19s %*s %19s %19s %*s " | ||
261 | "%*s %*s %*s %*s", | ||
262 | tag, lat, lon, | ||
263 | alt, eph, track, speed) == 7) { | ||
264 | |||
265 | gps_state->fix.latitude = parse_double(lat); | ||
266 | gps_state->fix.longitude = parse_double(lon); | ||
267 | gps_state->fix.altitude = parse_double(alt); | ||
268 | gps_state->fix.eph = parse_double(eph); | ||
269 | gps_state->fix.track = parse_double(track); | ||
270 | |||
271 | gps_state->set |= FIX_LATLON_SET; | ||
272 | |||
273 | if (!isnan(gps_state->fix.eph)) | ||
274 | gps_state->set |= FIX_HERR_SET; | ||
275 | |||
276 | if (!isnan(gps_state->fix.track)) | ||
277 | gps_state->set |= FIX_TRACK_SET; | ||
278 | |||
279 | if(!isnan(gps_state->fix.altitude)) | ||
280 | gps_state->set |= FIX_ALTITUDE_SET; | ||
281 | harbaum | 1 | } |
282 | } | ||
283 | break; | ||
284 | harbaum | 282 | |
285 | case 'Y': | ||
286 | gps_state->fix.sat_num = 0; | ||
287 | |||
288 | if (sp[2] != '?') { | ||
289 | (void)sscanf(sp, "Y=%*s %*s %d ", &gps_state->fix.sat_num); | ||
290 | |||
291 | /* clear all slots */ | ||
292 | for (j = 0; j < gps_state->fix.sat_num; j++) | ||
293 | gps_state->fix.sat_data[j].prn = | ||
294 | gps_state->fix.sat_data[j].ss = | ||
295 | gps_state->fix.sat_data[j].used = 0; | ||
296 | |||
297 | for (j = 0; j < gps_state->fix.sat_num; j++) { | ||
298 | if ((sp != NULL) && ((sp = strchr(sp, ':')) != NULL)) { | ||
299 | sp++; | ||
300 | (void)sscanf(sp, "%d %*d %*d %d %d", | ||
301 | &gps_state->fix.sat_data[j].prn, | ||
302 | &gps_state->fix.sat_data[j].ss, | ||
303 | &gps_state->fix.sat_data[j].used); | ||
304 | } | ||
305 | } | ||
306 | } | ||
307 | gps_state->set |= FIX_SATELLITE_SET; | ||
308 | harbaum | 1 | break; |
309 | } | ||
310 | } | ||
311 | } | ||
312 | } | ||
313 | } | ||
314 | |||
315 | harbaum | 282 | static gpointer gps_thread(gpointer data) { |
316 | gps_state_t *gps_state = (gps_state_t*)data; | ||
317 | |||
318 | harbaum | 1 | GnomeVFSFileSize bytes_read; |
319 | GnomeVFSResult vfs_result; | ||
320 | char str[512]; | ||
321 | |||
322 | harbaum | 282 | gps_state->set = 0; |
323 | harbaum | 1 | |
324 | gboolean connected = FALSE; | ||
325 | |||
326 | harbaum | 282 | int cnt=1000; |
327 | |||
328 | const char *msg_pos = "o\r\n"; /* pos request */ | ||
329 | const char *msg_sat = "y\r\n"; /* sat request */ | ||
330 | |||
331 | harbaum | 1 | while(1) { |
332 | harbaum | 282 | /* just lock and unlock the control mutex. This stops the thread */ |
333 | /* while the main process locks this mutex */ | ||
334 | g_mutex_lock(gps_state->control_mutex); | ||
335 | g_mutex_unlock(gps_state->control_mutex); | ||
336 | g_mutex_lock(gps_state->global_mutex); | ||
337 | g_mutex_unlock(gps_state->global_mutex); | ||
338 | harbaum | 1 | |
339 | harbaum | 282 | if(!connected) { |
340 | printf("gps: trying to connect\n"); | ||
341 | |||
342 | if(gps_connect(gps_state) < 0) | ||
343 | sleep(10); | ||
344 | else | ||
345 | connected = TRUE; | ||
346 | |||
347 | } else { | ||
348 | const char *msg; | ||
349 | if(!cnt) msg = msg_sat; | ||
350 | else msg = msg_pos; | ||
351 | |||
352 | if(GNOME_VFS_OK == | ||
353 | (vfs_result = gnome_vfs_socket_write(gps_state->socket, | ||
354 | harbaum | 1 | msg, strlen(msg)+1, &bytes_read, NULL))) { |
355 | |||
356 | harbaum | 282 | /* update every second, wait here to make sure a complete */ |
357 | /* reply is received */ | ||
358 | if(cnt <= 1) usleep(500000); | ||
359 | else sleep(1); | ||
360 | |||
361 | if(bytes_read == (strlen(msg)+1)) { | ||
362 | vfs_result = gnome_vfs_socket_read(gps_state->socket, | ||
363 | str, sizeof(str)-1, &bytes_read, NULL); | ||
364 | |||
365 | if(vfs_result == GNOME_VFS_OK) { | ||
366 | str[bytes_read] = 0; | ||
367 | |||
368 | g_mutex_lock(gps_state->mutex); | ||
369 | |||
370 | /* assume we could't parse anything ... */ | ||
371 | if(!cnt) gps_state->set &= ~FIX_SATELLITE_SET; | ||
372 | else gps_state->set &= | ||
373 | ~(FIX_LATLON_SET|FIX_HERR_SET|FIX_ALTITUDE_SET|FIX_TRACK_SET); | ||
374 | harbaum | 1 | |
375 | harbaum | 282 | gps_unpack(str, gps_state); |
376 | |||
377 | /* notify applications of state if useful */ | ||
378 | g_idle_add(gps_notify, gps_state); | ||
379 | |||
380 | g_mutex_unlock(gps_state->mutex); | ||
381 | harbaum | 1 | } |
382 | } | ||
383 | harbaum | 282 | |
384 | /* if we have clients requesting sat information return to */ | ||
385 | /* state 0 which will request them. Otherwise loop in states */ | ||
386 | /* 1 - 4 which don't request them */ | ||
387 | if(cnt++ >= 5) { | ||
388 | if(gps_state->sat_requests) cnt = 0; | ||
389 | else cnt = 1; | ||
390 | } | ||
391 | harbaum | 1 | } |
392 | harbaum | 282 | } |
393 | } | ||
394 | harbaum | 1 | |
395 | harbaum | 282 | printf("gps: thread ended???\n"); |
396 | return NULL; | ||
397 | } | ||
398 | |||
399 | gps_state_t *gps_init(void) { | ||
400 | gps_state_t *gps_state = g_new0(gps_state_t, 1); | ||
401 | |||
402 | /* start a new thread to listen to gpsd */ | ||
403 | gps_state->mutex = g_mutex_new(); | ||
404 | gps_state->control_mutex = g_mutex_new(); | ||
405 | gps_state->global_mutex = g_mutex_new(); | ||
406 | gps_state->thread_p = | ||
407 | g_thread_create(gps_thread, gps_state, FALSE, NULL); | ||
408 | |||
409 | return gps_state; | ||
410 | } | ||
411 | |||
412 | void gps_release(gps_state_t *gps_state) { | ||
413 | gps_unregister_all(gps_state); | ||
414 | |||
415 | harbaum | 1 | #ifdef USE_MAEMO |
416 | harbaum | 282 | gpsbt_stop(&gps_state->context); |
417 | harbaum | 1 | #endif |
418 | harbaum | 282 | |
419 | g_free(gps_state); | ||
420 | } | ||
421 | |||
422 | #else // USE_LIBGPS | ||
423 | |||
424 | static gpointer gps_thread(gpointer data) { | ||
425 | gps_state_t *gps_state = (gps_state_t*)data; | ||
426 | |||
427 | /* the following is required for libgps to be able to parse */ | ||
428 | /* the gps messages. Unfortunately this also affect the rest of */ | ||
429 | /* the program and the main thread */ | ||
430 | setlocale(LC_NUMERIC, "C"); | ||
431 | |||
432 | while(1) { | ||
433 | /* just lock and unlock the control mutex. This stops the thread */ | ||
434 | /* while the main process locks this mutex */ | ||
435 | g_mutex_lock(gps_state->control_mutex); | ||
436 | g_mutex_unlock(gps_state->control_mutex); | ||
437 | |||
438 | gps_poll(gps_state->data); | ||
439 | |||
440 | g_mutex_lock(gps_state->mutex); | ||
441 | |||
442 | /* assume we could't parse anything ... */ | ||
443 | gps_state->set = 0; | ||
444 | |||
445 | if(gps_state->data->fix.mode >= MODE_2D) { | ||
446 | /* latlon valid */ | ||
447 | gps_state->set |= FIX_LATLON_SET; | ||
448 | gps_state->fix.latitude = gps_state->data->fix.latitude; | ||
449 | gps_state->fix.longitude = gps_state->data->fix.longitude; | ||
450 | |||
451 | gps_state->fix.eph = | ||
452 | gps_state->data->fix.epy > gps_state->data->fix.epx ? | ||
453 | gps_state->data->fix.epy : gps_state->data->fix.epx; | ||
454 | if(!isnan(gps_state->fix.eph)) gps_state->set |= FIX_HERR_SET; | ||
455 | |||
456 | gps_state->fix.track = gps_state->data->fix.track; | ||
457 | if(!isnan(gps_state->fix.track)) gps_state->set |= FIX_TRACK_SET; | ||
458 | harbaum | 1 | } |
459 | harbaum | 282 | |
460 | if(gps_state->data->fix.mode >= MODE_3D) { | ||
461 | /* altitude valid */ | ||
462 | gps_state->set |= FIX_ALTITUDE_SET; | ||
463 | gps_state->fix.altitude = gps_state->data->fix.altitude; | ||
464 | } else | ||
465 | gps_state->fix.altitude = NAN; | ||
466 | |||
467 | harbaum | 283 | #if MAXCHANNELS > GPS_MAXCHANNELS |
468 | #error "Channel number mismatch!" | ||
469 | #endif | ||
470 | |||
471 | /* process sat info */ | ||
472 | if(gps_state->data->set | SATELLITE_SET) { | ||
473 | int i; | ||
474 | |||
475 | gps_state->set |= FIX_SATELLITE_SET; | ||
476 | |||
477 | gps_state->fix.sat_num = 0; | ||
478 | for(i=0;i<GPS_MAXCHANNELS;i++) | ||
479 | gps_state->fix.sat_data[i].used = 0; | ||
480 | |||
481 | for(i=0;i<MAXCHANNELS;i++) { | ||
482 | if(gps_state->data->used[i]) { | ||
483 | gps_state->fix.sat_data[gps_state->fix.sat_num].used = 1; | ||
484 | gps_state->fix.sat_data[gps_state->fix.sat_num].prn = | ||
485 | gps_state->data->PRN[i]; | ||
486 | gps_state->fix.sat_data[gps_state->fix.sat_num].ss = | ||
487 | gps_state->data->ss[i]; | ||
488 | gps_state->fix.sat_num++; | ||
489 | } | ||
490 | } | ||
491 | |||
492 | } | ||
493 | |||
494 | harbaum | 282 | /* notify applications of state if useful */ |
495 | g_idle_add(gps_notify, gps_state); | ||
496 | |||
497 | g_mutex_unlock(gps_state->mutex); | ||
498 | |||
499 | harbaum | 1 | } |
500 | |||
501 | harbaum | 156 | printf("gps: thread ended???\n"); |
502 | harbaum | 1 | return NULL; |
503 | } | ||
504 | |||
505 | harbaum | 282 | gps_state_t *gps_init(void) { |
506 | gps_state_t *gps_state = g_new0(gps_state_t, 1); | ||
507 | harbaum | 1 | |
508 | harbaum | 282 | gps_state->mutex = g_mutex_new(); |
509 | gps_state->control_mutex = g_mutex_new(); | ||
510 | |||
511 | gps_state->data = gps_open("127.0.0.1", DEFAULT_GPSD_PORT ); | ||
512 | if(!gps_state->data) | ||
513 | perror("gps_open()"); | ||
514 | |||
515 | (void)gps_stream(gps_state->data, WATCH_ENABLE, NULL); | ||
516 | |||
517 | gps_state->thread_p = | ||
518 | g_thread_create(gps_thread, gps_state, FALSE, NULL); | ||
519 | |||
520 | return gps_state; | ||
521 | harbaum | 1 | } |
522 | |||
523 | harbaum | 282 | void gps_release(gps_state_t *gps_state) { |
524 | gps_unregister_all(gps_state); | ||
525 | gps_close(gps_state->data); | ||
526 | g_free(gps_state); | ||
527 | harbaum | 243 | } |
528 | |||
529 | harbaum | 282 | #endif // USE_LIBGPS |
530 | |||
531 | static void gps_background_enable(gps_state_t *gps_state, gboolean enable) { | ||
532 | printf("GPS: %sable background process\n", enable?"en":"dis"); | ||
533 | |||
534 | /* start and stop gps thread by locking and unlocking the control mutex */ | ||
535 | if(enable) g_mutex_unlock(gps_state->control_mutex); | ||
536 | else g_mutex_lock(gps_state->control_mutex); | ||
537 | harbaum | 1 | } |
538 | |||
539 | harbaum | 282 | void gps_enable(gps_state_t *gps_state, gboolean enable) { |
540 | /* just ignore request if we are already in that state */ | ||
541 | if(gps_state->stopped == !enable) return; | ||
542 | |||
543 | if(!enable) g_mutex_lock(gps_state->global_mutex); | ||
544 | else g_mutex_unlock(gps_state->global_mutex); | ||
545 | |||
546 | gps_state->stopped = !enable; | ||
547 | } | ||
548 | |||
549 | |||
550 | harbaum | 1 | #else |
551 | |||
552 | static void | ||
553 | location_changed(LocationGPSDevice *device, gps_state_t *gps_state) { | ||
554 | |||
555 | harbaum | 282 | gps_state->set = 0; |
556 | harbaum | 8 | |
557 | harbaum | 282 | if(device->fix->fields & LOCATION_GPS_DEVICE_LATLONG_SET) { |
558 | gps_state->set |= FIX_LATLON_SET | FIX_HERR_SET; | ||
559 | gps_state->fix.latitude = device->fix->latitude; | ||
560 | gps_state->fix.longitude = device->fix->longitude; | ||
561 | harbaum | 233 | gps_state->fix.eph = device->fix->eph/100.0; // we want eph in meters |
562 | harbaum | 8 | } |
563 | harbaum | 7 | |
564 | harbaum | 282 | if(device->fix->fields & LOCATION_GPS_DEVICE_ALTITUDE_SET) { |
565 | gps_state->set |= FIX_ALTITUDE_SET; | ||
566 | gps_state->fix.altitude = device->fix->altitude; | ||
567 | } else | ||
568 | gps_state->fix.altitude = NAN; | ||
569 | |||
570 | if(device->fix->fields & LOCATION_GPS_DEVICE_TRACK_SET) { | ||
571 | gps_state->set |= FIX_TRACK_SET; | ||
572 | harbaum | 233 | gps_state->fix.track = device->fix->track; |
573 | harbaum | 1 | } |
574 | harbaum | 8 | |
575 | harbaum | 282 | /* tell all clients */ |
576 | g_slist_foreach(gps_state->callbacks, gps_cb_func, gps_state); | ||
577 | harbaum | 8 | |
578 | harbaum | 282 | /* remember last state reported */ |
579 | gps_state->last.set = gps_state->set; | ||
580 | gps_state->last.fix = gps_state->fix; | ||
581 | harbaum | 1 | } |
582 | |||
583 | harbaum | 282 | gps_state_t *gps_init(void) { |
584 | gps_state_t *gps_state = g_new0(gps_state_t, 1); | ||
585 | harbaum | 1 | |
586 | gps_state->device = g_object_new(LOCATION_TYPE_GPS_DEVICE, NULL); | ||
587 | if(!gps_state->device) { | ||
588 | harbaum | 156 | printf("gps: Unable to connect to liblocation\n"); |
589 | harbaum | 282 | g_free(gps_state); |
590 | return NULL; | ||
591 | harbaum | 1 | } |
592 | |||
593 | gps_state->idd_changed = | ||
594 | g_signal_connect(gps_state->device, "changed", | ||
595 | G_CALLBACK(location_changed), gps_state); | ||
596 | harbaum | 282 | gps_state->connected = TRUE; |
597 | harbaum | 1 | |
598 | harbaum | 11 | gps_state->control = location_gpsd_control_get_default(); |
599 | |||
600 | harbaum | 36 | if(gps_state->control |
601 | #if MAEMO_VERSION_MAJOR < 5 | ||
602 | && gps_state->control->can_control | ||
603 | #endif | ||
604 | ) { | ||
605 | |||
606 | harbaum | 156 | printf("gps: Having control over GPSD and GPS is to be enabled, starting it\n"); |
607 | harbaum | 11 | location_gpsd_control_start(gps_state->control); |
608 | } | ||
609 | harbaum | 282 | return gps_state; |
610 | harbaum | 1 | } |
611 | |||
612 | harbaum | 282 | void gps_release(gps_state_t *gps_state) { |
613 | gps_unregister_all(gps_state); | ||
614 | harbaum | 11 | |
615 | harbaum | 36 | if(gps_state->control |
616 | harbaum | 11 | #if MAEMO_VERSION_MAJOR < 5 |
617 | harbaum | 36 | && gps_state->control->can_control |
618 | #endif | ||
619 | ) { | ||
620 | harbaum | 156 | printf("gps: Having control over GPSD, stopping it\n"); |
621 | harbaum | 11 | location_gpsd_control_stop(gps_state->control); |
622 | } | ||
623 | harbaum | 1 | |
624 | /* Disconnect signal */ | ||
625 | g_signal_handler_disconnect(gps_state->device, gps_state->idd_changed); | ||
626 | harbaum | 282 | gps_state->connected = FALSE; |
627 | harbaum | 1 | |
628 | harbaum | 282 | g_free(gps_state); |
629 | harbaum | 1 | } |
630 | |||
631 | harbaum | 282 | static void gps_control(gps_state_t *gps_state, |
632 | gboolean enable0, gboolean enable1) { | ||
633 | harbaum | 288 | printf("GPS: control(stp: %d, bg: %d)\n", enable0, enable1); |
634 | |||
635 | harbaum | 282 | if(!gps_state->connected) { |
636 | /* both "enable" signals have to be true */ | ||
637 | if(enable0 && enable1) { | ||
638 | printf("GPS: connecting\n"); | ||
639 | gps_state->idd_changed = | ||
640 | g_signal_connect(gps_state->device, "changed", | ||
641 | G_CALLBACK(location_changed), gps_state); | ||
642 | gps_state->connected = TRUE; | ||
643 | } | ||
644 | } else { | ||
645 | /* at least one "enable" is false */ | ||
646 | if(!enable0 || !enable1) { | ||
647 | printf("GPS: disconnecting\n"); | ||
648 | /* Disconnect signal */ | ||
649 | g_signal_handler_disconnect(gps_state->device, gps_state->idd_changed); | ||
650 | gps_state->connected = FALSE; | ||
651 | } | ||
652 | } | ||
653 | } | ||
654 | harbaum | 1 | |
655 | harbaum | 282 | /* enable/disable due to all windows being in background */ |
656 | void gps_background_enable(gps_state_t *gps_state, gboolean enable) { | ||
657 | if(gps_state->backgrounded == !enable) return; | ||
658 | harbaum | 1 | |
659 | harbaum | 282 | gps_state->backgrounded = !enable; |
660 | harbaum | 288 | gps_control(gps_state, !gps_state->stopped, !gps_state->backgrounded); |
661 | harbaum | 1 | } |
662 | |||
663 | harbaum | 282 | /* enable/disable on app request */ |
664 | void gps_enable(gps_state_t *gps_state, gboolean enable) { | ||
665 | if(gps_state->stopped == !enable) return; | ||
666 | harbaum | 1 | |
667 | harbaum | 282 | gps_state->stopped = !enable; |
668 | harbaum | 288 | gps_control(gps_state, !gps_state->stopped, !gps_state->backgrounded); |
669 | harbaum | 7 | } |
670 | harbaum | 1 | |
671 | harbaum | 282 | #endif // USE_LIBLOCATION |
672 | harbaum | 7 | |
673 | harbaum | 282 | static gint compare(gconstpointer a, gconstpointer b) { |
674 | return ((gps_callback_t*)a)->cb != b; | ||
675 | harbaum | 7 | } |
676 | |||
677 | harbaum | 282 | void gps_register_callback(gps_state_t *gps_state, int mask, |
678 | gps_cb cb, void *data) { | ||
679 | /* make sure the callback isn't already registered */ | ||
680 | GSList *list = g_slist_find_custom(gps_state->callbacks, cb, compare); | ||
681 | if(list) { | ||
682 | printf("GPS register: ignoring duplicate\n"); | ||
683 | return; | ||
684 | harbaum | 8 | } |
685 | harbaum | 1 | |
686 | harbaum | 282 | gps_callback_t *callback = g_new0(gps_callback_t, 1); |
687 | harbaum | 8 | |
688 | harbaum | 282 | g_assert(mask & CHANGED_MASK); |
689 | g_assert(!(mask & ~CHANGED_MASK)); | ||
690 | |||
691 | callback->mask = mask; | ||
692 | callback->cb = cb; | ||
693 | callback->data = data; | ||
694 | harbaum | 8 | |
695 | harbaum | 282 | #if !defined(ENABLE_LIBLOCATION) && !defined(USE_LIBGPS) |
696 | /* the gpsd solution needs to know the number of clients */ | ||
697 | /* requesting sat information */ | ||
698 | if(mask & SATELLITE_CHANGED) | ||
699 | gps_state->sat_requests++; | ||
700 | harbaum | 1 | #endif |
701 | harbaum | 149 | |
702 | harbaum | 282 | gps_state->callbacks = g_slist_append(gps_state->callbacks, callback); |
703 | |||
704 | if(g_slist_length(gps_state->callbacks) == 1) | ||
705 | gps_background_enable(gps_state, TRUE); | ||
706 | harbaum | 149 | } |
707 | |||
708 | harbaum | 282 | void gps_unregister_callback(gps_state_t *gps_state, gps_cb cb) { |
709 | /* find callback in list */ | ||
710 | GSList *list = g_slist_find_custom(gps_state->callbacks, cb, compare); | ||
711 | g_assert(list); | ||
712 | harbaum | 149 | |
713 | harbaum | 282 | #if !defined(ENABLE_LIBLOCATION) && !defined(USE_LIBGPS) |
714 | /* the gpsd solution needs to know the number of clients */ | ||
715 | /* requesting sat information */ | ||
716 | gps_callback_t *cb_s = list->data; | ||
717 | if(cb_s->mask & SATELLITE_CHANGED) | ||
718 | gps_state->sat_requests--; | ||
719 | #endif | ||
720 | harbaum | 156 | |
721 | harbaum | 282 | /* and de-chain and free it */ |
722 | g_free(list->data); | ||
723 | gps_state->callbacks = g_slist_remove(gps_state->callbacks, list->data); | ||
724 | harbaum | 156 | |
725 | harbaum | 282 | if(g_slist_length(gps_state->callbacks) == 0) |
726 | gps_background_enable(gps_state, FALSE); | ||
727 | harbaum | 149 | } |
728 | harbaum | 156 | |
729 | harbaum | 282 | static void gps_unregister_all(gps_state_t *gps_state) { |
730 | g_slist_foreach(gps_state->callbacks, (GFunc)g_free, NULL); | ||
731 | g_slist_free(gps_state->callbacks); | ||
732 | harbaum | 156 | } |