Contents of /trunk/src/gps.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 288 - (hide annotations)
Mon Jun 7 19:19:50 2010 UTC (13 years, 11 months ago) by harbaum
File MIME type: text/plain
File size: 20523 byte(s)
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 }