Contents of /trunk/src/gps.c

Parent Directory Parent Directory | Revision Log Revision Log


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