Contents of /trunk/src/gps.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 288 - (show 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 /*
2 * Copyright (C) 2009 Till Harbaum <till@harbaum.org>.
3 *
4 * This file is part of Maep.
5 *
6 * Maep 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 3 of the License, or
9 * (at your option) any later version.
10 *
11 * Maep 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 Maep. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 /*
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 #include <stdio.h>
29 #include <string.h>
30 #include <math.h>
31 #include <stdlib.h>
32
33 #ifdef USE_MAEMO
34 #ifdef ENABLE_GPSBT
35 #include <gpsbt.h>
36 #include <gpsmgr.h>
37 #endif
38 #include <errno.h>
39 #else
40 #ifdef USE_LIBGPS
41 #include <gps.h>
42 #include <locale.h>
43 #endif
44 #endif
45
46 #include "gps.h"
47
48 static void gps_unregister_all(gps_state_t *gps_state);
49
50 /* 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
56 static gboolean
57 track_differs(struct gps_t *fix1, struct gps_t *fix2) {
58 return( fabsf(fix1->track - fix2->track) >= TRACK_PRECISION);
59 }
60
61 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
66 if( fabsf(fix1->longitude - fix2->longitude) >= POS_PRECISION)
67 return TRUE;
68
69 return FALSE;
70 }
71
72 static gboolean
73 eph_differs(struct gps_t *fix1, struct gps_t *fix2) {
74 return( fabsf(fix1->eph - fix2->eph) >= EPH_PRECISION);
75 }
76
77 static gboolean
78 altitude_differs(struct gps_t *fix1, struct gps_t *fix2) {
79 return( fabsf(fix1->altitude - fix2->altitude) >= ALTITUDE_PRECISION);
80 }
81
82 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
86 /* 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
94 /* clear "changed" bits */
95 gps_state->set &= ~CHANGED_MASK;
96
97 /* 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
105 /* 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
113 /* 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 }
132
133 #ifndef ENABLE_LIBLOCATION
134
135 static gboolean gps_notify(gpointer data) {
136 gps_state_t *gps_state = (gps_state_t*)data;
137
138 if(gps_state->callbacks) {
139 g_mutex_lock(gps_state->mutex);
140
141 /* tell all clients */
142 g_slist_foreach(gps_state->callbacks, gps_cb_func, gps_state);
143
144 g_mutex_unlock(gps_state->mutex);
145 }
146
147 /* 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 }
153
154 #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 static int gps_connect(gps_state_t *gps_state) {
161 GnomeVFSResult vfs_result;
162
163 #ifdef USE_MAEMO
164 char errstr[256] = "";
165
166 if(!gps_state) {
167 printf("No gps state\n");
168 return -1;
169 }
170
171 /* 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 printf("gps: Error connecting to GPS receiver: (%d) %s (%s)\n",
178 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 printf("gps: Error creating connection to GPSD, retrying ...\n");
192
193 retries--;
194 sleep(1);
195 }
196
197 if(!retries) {
198 printf("gps: Finally failed ...\n");
199 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 printf("gps: Error connecting GPSD socket, retrying ...\n");
206
207 retries--;
208 sleep(1);
209 }
210
211 if(!retries) {
212 printf("gps: Finally failed ...\n");
213 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 printf("gps: Error setting GPSD timeout\n");
220 return -1;
221 }
222
223 printf("gps: GPSD connected ...\n");
224
225 return 0;
226 }
227
228 static double parse_double(char *val) {
229 if(val[0] == '?') return NAN;
230 return g_ascii_strtod(val, NULL);
231 }
232
233 /* unpack a daemon response into a status structure */
234 static void gps_unpack(char *buf, gps_state_t *gps_state) {
235 char *ns, *sp, *tp;
236 int j;
237
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 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 } else {
255 char tag[MAXTAGLEN+1], alt[20];
256 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 }
282 }
283 break;
284
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 break;
309 }
310 }
311 }
312 }
313 }
314
315 static gpointer gps_thread(gpointer data) {
316 gps_state_t *gps_state = (gps_state_t*)data;
317
318 GnomeVFSFileSize bytes_read;
319 GnomeVFSResult vfs_result;
320 char str[512];
321
322 gps_state->set = 0;
323
324 gboolean connected = FALSE;
325
326 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 while(1) {
332 /* 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
339 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 msg, strlen(msg)+1, &bytes_read, NULL))) {
355
356 /* 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
375 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 }
382 }
383
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 }
392 }
393 }
394
395 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 #ifdef USE_MAEMO
416 gpsbt_stop(&gps_state->context);
417 #endif
418
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 }
459
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 #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 /* notify applications of state if useful */
495 g_idle_add(gps_notify, gps_state);
496
497 g_mutex_unlock(gps_state->mutex);
498
499 }
500
501 printf("gps: thread ended???\n");
502 return NULL;
503 }
504
505 gps_state_t *gps_init(void) {
506 gps_state_t *gps_state = g_new0(gps_state_t, 1);
507
508 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 }
522
523 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 }
528
529 #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 }
538
539 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 #else
551
552 static void
553 location_changed(LocationGPSDevice *device, gps_state_t *gps_state) {
554
555 gps_state->set = 0;
556
557 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 gps_state->fix.eph = device->fix->eph/100.0; // we want eph in meters
562 }
563
564 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 gps_state->fix.track = device->fix->track;
573 }
574
575 /* tell all clients */
576 g_slist_foreach(gps_state->callbacks, gps_cb_func, gps_state);
577
578 /* remember last state reported */
579 gps_state->last.set = gps_state->set;
580 gps_state->last.fix = gps_state->fix;
581 }
582
583 gps_state_t *gps_init(void) {
584 gps_state_t *gps_state = g_new0(gps_state_t, 1);
585
586 gps_state->device = g_object_new(LOCATION_TYPE_GPS_DEVICE, NULL);
587 if(!gps_state->device) {
588 printf("gps: Unable to connect to liblocation\n");
589 g_free(gps_state);
590 return NULL;
591 }
592
593 gps_state->idd_changed =
594 g_signal_connect(gps_state->device, "changed",
595 G_CALLBACK(location_changed), gps_state);
596 gps_state->connected = TRUE;
597
598 gps_state->control = location_gpsd_control_get_default();
599
600 if(gps_state->control
601 #if MAEMO_VERSION_MAJOR < 5
602 && gps_state->control->can_control
603 #endif
604 ) {
605
606 printf("gps: Having control over GPSD and GPS is to be enabled, starting it\n");
607 location_gpsd_control_start(gps_state->control);
608 }
609 return gps_state;
610 }
611
612 void gps_release(gps_state_t *gps_state) {
613 gps_unregister_all(gps_state);
614
615 if(gps_state->control
616 #if MAEMO_VERSION_MAJOR < 5
617 && gps_state->control->can_control
618 #endif
619 ) {
620 printf("gps: Having control over GPSD, stopping it\n");
621 location_gpsd_control_stop(gps_state->control);
622 }
623
624 /* Disconnect signal */
625 g_signal_handler_disconnect(gps_state->device, gps_state->idd_changed);
626 gps_state->connected = FALSE;
627
628 g_free(gps_state);
629 }
630
631 static void gps_control(gps_state_t *gps_state,
632 gboolean enable0, gboolean enable1) {
633 printf("GPS: control(stp: %d, bg: %d)\n", enable0, enable1);
634
635 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
655 /* 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
659 gps_state->backgrounded = !enable;
660 gps_control(gps_state, !gps_state->stopped, !gps_state->backgrounded);
661 }
662
663 /* enable/disable on app request */
664 void gps_enable(gps_state_t *gps_state, gboolean enable) {
665 if(gps_state->stopped == !enable) return;
666
667 gps_state->stopped = !enable;
668 gps_control(gps_state, !gps_state->stopped, !gps_state->backgrounded);
669 }
670
671 #endif // USE_LIBLOCATION
672
673 static gint compare(gconstpointer a, gconstpointer b) {
674 return ((gps_callback_t*)a)->cb != b;
675 }
676
677 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 }
685
686 gps_callback_t *callback = g_new0(gps_callback_t, 1);
687
688 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
695 #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 #endif
701
702 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 }
707
708 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
713 #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
721 /* and de-chain and free it */
722 g_free(list->data);
723 gps_state->callbacks = g_slist_remove(gps_state->callbacks, list->data);
724
725 if(g_slist_length(gps_state->callbacks) == 0)
726 gps_background_enable(gps_state, FALSE);
727 }
728
729 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 }