Contents of /trunk/src/gps.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 156 - (show annotations)
Tue Nov 3 13:15:35 2009 UTC (14 years, 6 months ago) by harbaum
File MIME type: text/plain
File size: 19104 byte(s)
GCVote gui
1 /*
2 * Copyright (C) 2008 Till Harbaum <till@harbaum.org>.
3 *
4 * This file is part of GPXView.
5 *
6 * GPXView 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 * GPXView 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 GPXView. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <stdio.h>
21 #include <string.h>
22 #include <math.h>
23
24 #include "gpxview.h"
25
26
27 #ifdef USE_MAEMO
28 #ifdef ENABLE_GPSBT
29 #include <gpsbt.h>
30 #include <gpsmgr.h>
31 #endif
32 #include <errno.h>
33 #endif
34
35 static void gps_unregister_all(appdata_t *appdata);
36
37 #ifndef ENABLE_LIBLOCATION
38
39 /* maybe user configurable later on ... */
40 #define GPSD_HOST "127.0.0.1"
41 #define GPSD_PORT 2947
42
43 gps_sat_t *gps_get_sats(appdata_t *appdata) {
44 gps_sat_t *retval = NULL;
45
46 g_mutex_lock(appdata->gps_state->mutex);
47 if(appdata->gps_state->gpsdata.set & SATELLITE_SET) {
48 int i;
49 retval = malloc(sizeof(gps_sat_t));
50 retval->num = appdata->gps_state->gpsdata.satellites;
51
52 retval->PRN = malloc(sizeof(int)*retval->num);
53 retval->used = malloc(sizeof(int)*retval->num);
54 retval->ss = malloc(sizeof(int)*retval->num);
55
56 if(retval->num) {
57 for(i=0;i<retval->num;i++) {
58 retval->PRN[i] = appdata->gps_state->gpsdata.PRN[i];
59 retval->ss[i] = appdata->gps_state->gpsdata.ss[i];
60 retval->used[i] = appdata->gps_state->gpsdata.used[i];
61 }
62 }
63 }
64
65 g_mutex_unlock(appdata->gps_state->mutex);
66
67 return retval;
68 }
69
70 pos_t *gps_get_pos(appdata_t *appdata) {
71 static pos_t retval;
72
73 retval.lat = NAN;
74
75 g_mutex_lock(appdata->gps_state->mutex);
76 if(appdata->gps_state->gpsdata.set & STATUS_SET)
77 if(appdata->gps_state->gpsdata.status != STATUS_NO_FIX)
78 if(appdata->gps_state->gpsdata.set & LATLON_SET)
79 retval = appdata->gps_state->gpsdata.fix.pos;
80
81 g_mutex_unlock(appdata->gps_state->mutex);
82
83 if(isnan(retval.lat))
84 return NULL;
85
86 return &retval;
87 }
88
89 float gps_get_heading(appdata_t *appdata) {
90 float retval = NAN;
91
92 g_mutex_lock(appdata->gps_state->mutex);
93 if(appdata->gps_state->gpsdata.set & STATUS_SET)
94 if(appdata->gps_state->gpsdata.status != STATUS_NO_FIX)
95 if(appdata->gps_state->gpsdata.set & TRACK_SET)
96 retval = appdata->gps_state->gpsdata.fix.track;
97
98 g_mutex_unlock(appdata->gps_state->mutex);
99 return retval;
100 }
101
102 float gps_get_eph(appdata_t *appdata) {
103 float retval = NAN;
104
105 g_mutex_lock(appdata->gps_state->mutex);
106 if(appdata->gps_state->gpsdata.set & STATUS_SET)
107 if(appdata->gps_state->gpsdata.status != STATUS_NO_FIX)
108 retval = appdata->gps_state->gpsdata.fix.eph;
109
110 g_mutex_unlock(appdata->gps_state->mutex);
111 return retval;
112 }
113
114 static int gps_connect(gps_state_t *gps_state) {
115 GnomeVFSResult vfs_result;
116 #ifdef USE_MAEMO
117 char errstr[256] = "";
118
119 /* We need to start gpsd (via gpsbt) first. */
120 memset(&gps_state->context, 0, sizeof(gpsbt_t));
121 errno = 0;
122
123 if(gpsbt_start(NULL, 0, 0, 0, errstr, sizeof(errstr),
124 0, &gps_state->context) < 0) {
125 printf("gps: Error connecting to GPS receiver: (%d) %s (%s)\n",
126 errno, strerror(errno), errstr);
127 }
128 #endif
129
130 /************** from here down pure gnome/gtk/gpsd ********************/
131
132 /* try to connect to gpsd */
133 /* Create a socket to interact with GPSD. */
134
135 int retries = 5;
136 while(retries &&
137 (GNOME_VFS_OK != (vfs_result = gnome_vfs_inet_connection_create(
138 &gps_state->iconn, GPSD_HOST, GPSD_PORT, NULL)))) {
139 printf("gps: Error creating connection to GPSD, retrying ...\n");
140
141 retries--;
142 sleep(1);
143 }
144
145 if(!retries) {
146 printf("gps: Finally failed ...\n");
147 return -1;
148 }
149
150 retries = 5;
151 while(retries && ((gps_state->socket =
152 gnome_vfs_inet_connection_to_socket(gps_state->iconn)) == NULL)) {
153 printf("gps: Error creating connecting GPSD socket, retrying ...\n");
154
155 retries--;
156 sleep(1);
157 }
158
159 if(!retries) {
160 printf("gps: Finally failed ...\n");
161 return -1;
162 }
163
164 GTimeVal timeout = { 10, 0 };
165 if(GNOME_VFS_OK != (vfs_result = gnome_vfs_socket_set_timeout(
166 gps_state->socket, &timeout, NULL))) {
167 printf("gps: Error setting GPSD timeout\n");
168 return -1;
169 }
170
171 printf("gps: GPSD connected ...\n");
172
173 return 0;
174 }
175
176 void gps_clear_fix(struct gps_fix_t *fixp) {
177 fixp->mode = MODE_NOT_SEEN;
178 fixp->pos.lat = fixp->pos.lon = NAN;
179 fixp->track = NAN;
180 fixp->speed = NAN;
181 fixp->climb = NAN;
182 fixp->altitude = NAN;
183 fixp->ept = NAN;
184 fixp->eph = NAN;
185 fixp->epd = NAN;
186 fixp->eps = NAN;
187 fixp->epc = NAN;
188 }
189
190 /* unpack a daemon response into a status structure */
191 static void gps_unpack(char *buf, struct gps_data_t *gpsdata) {
192 char *ns, *sp, *tp;
193
194 for(ns = buf; ns; ns = strstr(ns+1, "GPSD")) {
195 if(strncmp(ns, "GPSD", 4) == 0) {
196 /* the following should execute each time we have a good next sp */
197 for (sp = ns + 5; *sp != '\0'; sp = tp+1) {
198 tp = sp + strcspn(sp, ",\r\n");
199 if (*tp == '\0') tp--;
200 else *tp = '\0';
201
202 switch (*sp) {
203 case 'A':
204 if (sp[2] == '?') {
205 gpsdata->fix.altitude = NAN;
206 } else {
207 (void)sscanf(sp, "A=%lf", &gpsdata->fix.altitude);
208 gpsdata->set |= ALTITUDE_SET;
209 }
210 break;
211 /* B - baudrate isn't supported by gpxview */
212 /* C - cycle isn't supported by gpxview */
213 /* D - utc time isn't supported by gpxview */
214 case 'E':
215 gpsdata->fix.eph = NAN;
216 /* epe should always be present if eph or epv is */
217 if (sp[2] != '?') {
218 char epe[20], eph[20], epv[20];
219 (void)sscanf(sp, "E=%s %s %s", epe, eph, epv);
220 #define DEFAULT(val) (val[0] == '?') ? NAN : g_ascii_strtod(val, NULL)
221 gpsdata->fix.eph = DEFAULT(eph);
222 #undef DEFAULT
223 }
224 break;
225 /* F - device name isn't supported by gpxview */
226 /* I - gps id isn't supported by gpxview */
227 /* K - known devices list isn't supported by gpxview */
228 case 'M':
229 if (sp[2] == '?') {
230 gpsdata->fix.mode = MODE_NOT_SEEN;
231 } else {
232 gpsdata->fix.mode = atoi(sp+2);
233 gpsdata->set |= MODE_SET;
234 }
235 break;
236 /* N - driver mode reporting isn't supported by gpxview */
237 case 'O':
238 if (sp[2] == '?') {
239 gpsdata->set =
240 (gpsdata->set & SATELLITE_SET) | // fix for below
241 MODE_SET | STATUS_SET; // this clears sat info??
242 gpsdata->status = STATUS_NO_FIX;
243 gps_clear_fix(&gpsdata->fix);
244 } else {
245 struct gps_fix_t nf;
246 char tag[MAXTAGLEN+1], alt[20];
247 char eph[20], epv[20], track[20],speed[20], climb[20];
248 char epd[20], eps[20], epc[20], mode[2];
249 char timestr[20], ept[20], lat[20], lon[20];
250 int st = sscanf(sp+2,
251 "%8s %19s %19s %19s %19s %19s %19s %19s %19s %19s %19s %19s %19s %19s %1s",
252 tag, timestr, ept, lat, lon,
253 alt, eph, epv, track, speed, climb,
254 epd, eps, epc, mode);
255 if (st >= 14) {
256 #define DEFAULT(val) (val[0] == '?') ? NAN : g_ascii_strtod(val, NULL)
257 nf.pos.lat = DEFAULT(lat);
258 nf.pos.lon = DEFAULT(lon);
259 nf.ept = DEFAULT(ept);
260 nf.altitude = DEFAULT(alt);
261 nf.eph = DEFAULT(eph);
262 nf.track = DEFAULT(track);
263 nf.speed = DEFAULT(speed);
264 nf.climb = DEFAULT(climb);
265 nf.epd = DEFAULT(epd);
266 nf.eps = DEFAULT(eps);
267 nf.epc = DEFAULT(epc);
268 #undef DEFAULT
269 if (st >= 15)
270 nf.mode = (mode[0] == '?') ? MODE_NOT_SEEN : atoi(mode);
271 else
272 nf.mode = (alt[0] == '?') ? MODE_2D : MODE_3D;
273 if (alt[0] != '?')
274 gpsdata->set |= ALTITUDE_SET | CLIMB_SET;
275 if (isnan(nf.eph)==0)
276 gpsdata->set |= HERR_SET;
277 if (isnan(nf.track)==0)
278 gpsdata->set |= TRACK_SET | SPEED_SET;
279 if (isnan(nf.eps)==0)
280 gpsdata->set |= SPEEDERR_SET;
281 if (isnan(nf.epc)==0)
282 gpsdata->set |= CLIMBERR_SET;
283 gpsdata->fix = nf;
284 gpsdata->set |= TIME_SET|TIMERR_SET|LATLON_SET|MODE_SET;
285 gpsdata->status = STATUS_FIX;
286 gpsdata->set |= STATUS_SET;
287 }
288 }
289 break;
290 case 'P':
291 if (sp[2] == '?') {
292 gpsdata->fix.pos.lat = NAN;
293 gpsdata->fix.pos.lon = NAN;
294 } else {
295 char lat[20], lon[20];
296 (void)sscanf(sp, "P=%19s %19s", lat, lon);
297 gpsdata->fix.pos.lat = g_ascii_strtod(lat, NULL);
298 gpsdata->fix.pos.lon = g_ascii_strtod(lon, NULL);
299 gpsdata->set |= LATLON_SET;
300 }
301 break;
302 case 'Q':
303 if (sp[2] == '?') {
304 gpsdata->satellites_used = 0;
305 gpsdata->pdop = 0;
306 gpsdata->hdop = 0;
307 gpsdata->vdop = 0;
308 } else {
309 (void)sscanf(sp, "Q=%d %lf %lf %lf %lf %lf",
310 &gpsdata->satellites_used,
311 &gpsdata->pdop,
312 &gpsdata->hdop,
313 &gpsdata->vdop,
314 &gpsdata->tdop,
315 &gpsdata->gdop);
316 gpsdata->set |= HDOP_SET | VDOP_SET | PDOP_SET;
317 }
318 break;
319 case 'S':
320 if (sp[2] == '?') {
321 gpsdata->status = -1;
322 } else {
323 gpsdata->status = atoi(sp+2);
324 gpsdata->set |= STATUS_SET;
325 }
326 break;
327 case 'T':
328 if (sp[2] == '?') {
329 gpsdata->fix.track = NAN;
330 } else {
331 (void)sscanf(sp, "T=%lf", &gpsdata->fix.track);
332 gpsdata->set |= TRACK_SET;
333 }
334 break;
335 case 'U':
336 if (sp[2] == '?') {
337 gpsdata->fix.climb = NAN;
338 } else {
339 (void)sscanf(sp, "U=%lf", &gpsdata->fix.climb);
340 gpsdata->set |= CLIMB_SET;
341 }
342 break;
343 case 'V':
344 if (sp[2] == '?') {
345 gpsdata->fix.speed = NAN;
346 } else {
347 (void)sscanf(sp, "V=%lf", &gpsdata->fix.speed);
348 /* V reply is in kt, fix.speed is in metres/sec */
349 gpsdata->fix.speed = gpsdata->fix.speed / MPS_TO_KNOTS;
350 gpsdata->set |= SPEED_SET;
351 }
352 break;
353 case 'X':
354 if (sp[2] == '?')
355 gpsdata->online = -1;
356 else {
357 (void)sscanf(sp, "X=%lf", &gpsdata->online);
358 gpsdata->set |= ONLINE_SET;
359 }
360 break;
361 case 'Y':
362 if (sp[2] == '?') {
363 gpsdata->satellites = 0;
364 } else {
365 int j, i1, i2, i3, i4, i5;
366 int PRN[MAXCHANNELS];
367 int elevation[MAXCHANNELS], azimuth[MAXCHANNELS];
368 int ss[MAXCHANNELS], used[MAXCHANNELS];
369 char tag[MAXTAGLEN+1], timestamp[21];
370
371 (void)sscanf(sp, "Y=%8s %20s %d ",
372 tag, timestamp, &gpsdata->satellites);
373 for (j = 0; j < gpsdata->satellites; j++) {
374 PRN[j]=elevation[j]=azimuth[j]=ss[j]=used[j]=0;
375 }
376 // printf("gps: sats = %d\n", gpsdata->satellites);
377 for (j = 0, gpsdata->satellites_used = 0; j < gpsdata->satellites; j++) {
378 if ((sp != NULL) && ((sp = strchr(sp, ':')) != NULL)) {
379 sp++;
380 (void)sscanf(sp, "%d %d %d %d %d", &i1, &i2, &i3, &i4, &i5);
381 PRN[j] = i1;
382 elevation[j] = i2; azimuth[j] = i3;
383 ss[j] = i4; used[j] = i5;
384 if (i5 == 1)
385 gpsdata->satellites_used++;
386 }
387 }
388 memcpy(gpsdata->PRN, PRN, sizeof(PRN));
389 memcpy(gpsdata->elevation, elevation, sizeof(elevation));
390 memcpy(gpsdata->azimuth, azimuth,sizeof(azimuth));
391 memcpy(gpsdata->ss, ss, sizeof(ss));
392 memcpy(gpsdata->used, used, sizeof(used));
393 /*@ +compdef @*/
394 }
395 gpsdata->set |= SATELLITE_SET;
396 break;
397 /* Z and $ - profiling isn't supported by gpxview */
398 }
399 }
400 }
401 }
402 }
403
404 /* call one of the application provided gps callbacks */
405 static void do_app_cb(gpointer data, gpointer user_data) {
406 appdata_t *appdata = (appdata_t*)user_data;
407 gps_cb_t *cb = (gps_cb_t*)data;
408 cb->cb(appdata->gps_state, cb->data);
409 }
410
411 /* walk though list of all application provided callbacks */
412 static gboolean gps_idle_cb(gpointer data) {
413 appdata_t *appdata = (appdata_t*)data;
414 printf("gps: idle callback, calling app callbacks\n");
415
416 g_slist_foreach(appdata->gps_state->cb, do_app_cb, appdata);
417
418 return FALSE;
419 }
420
421 gpointer gps_thread(gpointer data) {
422 GnomeVFSFileSize bytes_read;
423 GnomeVFSResult vfs_result;
424 char str[512];
425 appdata_t *appdata = (appdata_t*)data;
426 int cnt=1000;
427
428 const char *msg_pos = "o\r\n"; /* pos request */
429 const char *msg_sat = "y\r\n"; /* sat request */
430
431 appdata->gps_state->gpsdata.set = 0;
432
433 gboolean connected = FALSE;
434
435 while(1) {
436 if(appdata->use_gps) {
437 if(!connected) {
438 printf("gps: trying to connect\n");
439
440 if(gps_connect(appdata->gps_state) < 0)
441 sleep(10);
442 else
443 connected = TRUE;
444 } else {
445 const char *msg;
446 if(!cnt) msg = msg_sat;
447 else msg = msg_pos;
448
449 if(GNOME_VFS_OK ==
450 (vfs_result = gnome_vfs_socket_write(appdata->gps_state->socket,
451 msg, strlen(msg)+1, &bytes_read, NULL))) {
452
453 /* update every second, wait here to make sure a complete */
454 /* reply is received */
455 if(cnt <= 1) usleep(500000);
456 else sleep(1);
457
458 if(bytes_read == (strlen(msg)+1)) {
459 vfs_result = gnome_vfs_socket_read(appdata->gps_state->socket,
460 str, sizeof(str)-1, &bytes_read, NULL);
461 if(vfs_result == GNOME_VFS_OK) {
462 str[bytes_read] = 0;
463
464 // printf("gps: msg: %s (%d)\n", str, strlen(str));
465
466 g_mutex_lock(appdata->gps_state->mutex);
467
468 if(!cnt) appdata->gps_state->gpsdata.set &= ~SATELLITE_SET;
469 else appdata->gps_state->gpsdata.set &=
470 ~(TIME_SET|TIMERR_SET|LATLON_SET|MODE_SET|STATUS_SET);
471
472 gps_unpack(str, &appdata->gps_state->gpsdata);
473 g_mutex_unlock(appdata->gps_state->mutex);
474 g_idle_add(gps_idle_cb, appdata);
475 }
476 }
477 }
478 if(cnt++ >= 5) cnt = 0;
479 }
480 } else {
481 if(connected) {
482 printf("gps: stopping GPS connection due to user request\n");
483 gnome_vfs_inet_connection_destroy(appdata->gps_state->iconn, NULL);
484
485 #ifdef USE_MAEMO
486 gpsbt_stop(&appdata->gps_state->context);
487 #endif
488 connected = FALSE;
489 } else
490 sleep(1);
491 }
492 }
493
494 printf("gps: thread ended???\n");
495 return NULL;
496 }
497
498 void gps_init(appdata_t *appdata) {
499 appdata->gps_state = g_new0(gps_state_t, 1);
500
501 /* start a new thread to listen to gpsd */
502 appdata->gps_state->mutex = g_mutex_new();
503 appdata->gps_state->thread_p =
504 g_thread_create(gps_thread, appdata, FALSE, NULL);
505 }
506
507 void gps_release(appdata_t *appdata) {
508 gps_unregister_all(appdata);
509 #ifdef USE_MAEMO
510 gpsbt_stop(&appdata->gps_state->context);
511 #endif
512 g_free(appdata->gps_state);
513 }
514
515 #else
516
517 static void
518 location_changed(LocationGPSDevice *device, gps_state_t *gps_state) {
519
520 gps_state->fields = device->fix->fields;
521
522 if(gps_state->fields & LOCATION_GPS_DEVICE_LATLONG_SET) {
523 gps_state->latitude = device->fix->latitude;
524 gps_state->longitude = device->fix->longitude;
525 gps_state->eph = device->fix->eph/100.0; // we want eph in meters
526 }
527
528 if(gps_state->fields & LOCATION_GPS_DEVICE_TRACK_SET)
529 gps_state->heading = device->fix->track;
530
531 /* update list of sattelites */
532
533 /* free old list */
534 if(gps_state->sats.num) {
535 g_free(gps_state->sats.PRN);
536 g_free(gps_state->sats.used);
537 g_free(gps_state->sats.ss);
538 gps_state->sats.num = 0;
539 }
540
541 /* build new one */
542 if(device->satellites_in_view) {
543 gps_state->sats.PRN = g_new0(int, device->satellites_in_view);
544 gps_state->sats.used = g_new0(int, device->satellites_in_view);
545 gps_state->sats.ss = g_new0(int, device->satellites_in_view);
546
547 int i;
548 for(i=0;i<device->satellites_in_view;i++) {
549 LocationGPSDeviceSatellite *sat =
550 g_ptr_array_index(device->satellites, i);
551
552 gps_state->sats.PRN[i] = sat->prn;
553 gps_state->sats.used[i] = sat->in_use;
554 gps_state->sats.ss[i] = sat->signal_strength;
555 }
556
557 gps_state->sats.num = device->satellites_in_view;
558 }
559 }
560
561 void gps_init(appdata_t *appdata) {
562 gps_state_t *gps_state = appdata->gps_state = g_new0(gps_state_t, 1);
563
564 printf("gps: init: Using liblocation\n");
565
566 gps_state->device = g_object_new(LOCATION_TYPE_GPS_DEVICE, NULL);
567 if(!gps_state->device) {
568 printf("gps: Unable to connect to liblocation\n");
569 return;
570 }
571
572 gps_state->idd_changed =
573 g_signal_connect(gps_state->device, "changed",
574 G_CALLBACK(location_changed), gps_state);
575
576 gps_state->control = location_gpsd_control_get_default();
577
578 if(gps_state->control
579 #if MAEMO_VERSION_MAJOR < 5
580 && gps_state->control->can_control
581 #endif
582 ) {
583
584 printf("gps: Having control over GPSD and GPS is to be enabled, starting it\n");
585 location_gpsd_control_start(gps_state->control);
586 }
587 }
588
589 void gps_release(appdata_t *appdata) {
590 gps_state_t *gps_state = appdata->gps_state;
591 gps_unregister_all(appdata);
592
593 if(!gps_state->device) return;
594
595 if(gps_state->control
596 #if MAEMO_VERSION_MAJOR < 5
597 && gps_state->control->can_control
598 #endif
599 ) {
600 printf("gps: Having control over GPSD, stopping it\n");
601 location_gpsd_control_stop(gps_state->control);
602 }
603
604 /* Disconnect signal */
605 g_signal_handler_disconnect(gps_state->device, gps_state->idd_changed);
606
607 g_free(appdata->gps_state);
608 appdata->gps_state = NULL;
609 }
610
611 pos_t *gps_get_pos(appdata_t *appdata) {
612 static pos_t pos;
613
614 if(!appdata->use_gps)
615 return NULL;
616
617 gps_state_t *gps_state = appdata->gps_state;
618
619 if(!(gps_state->fields & LOCATION_GPS_DEVICE_LATLONG_SET))
620 return NULL;
621
622 pos.lat = gps_state->latitude;
623 pos.lon = gps_state->longitude;
624
625 return &pos;
626 }
627
628 float gps_get_heading(appdata_t *appdata) {
629 gps_state_t *gps_state = appdata->gps_state;
630
631 if(!(gps_state->fields & LOCATION_GPS_DEVICE_TRACK_SET))
632 return NAN;
633
634 return gps_state->heading;
635 }
636
637 float gps_get_eph(appdata_t *appdata) {
638 gps_state_t *gps_state = appdata->gps_state;
639
640 if(!(gps_state->fields & LOCATION_GPS_DEVICE_LATLONG_SET))
641 return NAN;
642
643 return gps_state->eph;
644 }
645
646 gps_sat_t *gps_get_sats(appdata_t *appdata) {
647 gps_sat_t *retval = NULL;
648 gps_state_t *gps_state = appdata->gps_state;
649
650 if(gps_state->sats.num) {
651 retval = g_new0(gps_sat_t, 1);
652 retval->num = gps_state->sats.num;
653
654 retval->PRN = g_memdup(gps_state->sats.PRN,
655 sizeof(int)*gps_state->sats.num);
656 retval->used = g_memdup(gps_state->sats.used,
657 sizeof(int)*gps_state->sats.num);
658 retval->ss = g_memdup(gps_state->sats.ss,
659 sizeof(int)*gps_state->sats.num);
660 }
661
662 return retval;
663 }
664
665
666 #endif
667
668 void *gps_register_callback(appdata_t *appdata, gps_cb cb, gpointer data) {
669 printf("gps: register gps callback\n");
670
671 if(!appdata->gps_state)
672 return NULL;
673
674 /* allocate callback info strcuture */
675 gps_cb_t *cb_info = g_new0(gps_cb_t, 1);
676 cb_info->cb = cb;
677 cb_info->data = data;
678
679 /* and insert it into list of callbacks */
680 appdata->gps_state->cb = g_slist_append(appdata->gps_state->cb, cb_info);
681
682 return cb_info;
683 }
684
685
686 void gps_unregister_callback(appdata_t *appdata, void *cb) {
687 printf("gps: unregister gps callback\n");
688
689 if(!appdata->gps_state)
690 return;
691
692 /* the item must be in the list */
693 g_assert(g_slist_find(appdata->gps_state->cb, cb));
694
695 g_free(cb);
696 appdata->gps_state->cb = g_slist_remove(appdata->gps_state->cb, cb);
697 }
698
699 static void gps_unregister_all(appdata_t *appdata) {
700 printf("gps: unregister all callbacks: ");
701
702 while(appdata->gps_state->cb) {
703 printf(".");
704 g_free(appdata->gps_state->cb->data);
705 appdata->gps_state->cb = g_slist_remove(appdata->gps_state->cb,
706 appdata->gps_state->cb->data);
707 }
708 printf("\n");
709 }