Contents of /trunk/src/gps.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 118 - (hide annotations)
Mon Mar 9 14:28:35 2009 UTC (15 years, 3 months ago) by harbaum
File MIME type: text/plain
File size: 8571 byte(s)
Use liblocation if available to access gps
1 harbaum 1 /*
2     * Copyright (C) 2008 Till Harbaum <till@harbaum.org>.
3     *
4     * This file is part of OSM2Go.
5     *
6     * OSM2Go 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     * OSM2Go 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 OSM2Go. 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 "appdata.h"
25    
26 harbaum 118 #ifdef ENABLE_LIBLOCATION
27    
28     #include <location/location-gps-device.h>
29    
30     pos_t *gps_get_pos(appdata_t *appdata) {
31     gps_state_t *gps_state = appdata->gps_state;
32     static pos_t retval;
33    
34     if(!gps_state->fix)
35     return NULL;
36    
37     retval.lat = gps_state->latitude;
38     retval.lon = gps_state->longitude;
39    
40     return &retval;
41     }
42    
43     static void
44     location_changed(LocationGPSDevice *device, gps_state_t *gps_state) {
45    
46     gps_state->fix =
47     (device->fix->fields & LOCATION_GPS_DEVICE_LATLONG_SET);
48    
49     if(gps_state->fix) {
50     gps_state->latitude = device->fix->latitude;
51     gps_state->longitude = device->fix->longitude;
52     }
53     }
54    
55     void gps_init(appdata_t *appdata) {
56     gps_state_t *gps_state = appdata->gps_state = g_new0(gps_state_t, 1);
57    
58     printf("GPS init: Using liblocation\n");
59    
60     gps_state->device = g_object_new(LOCATION_TYPE_GPS_DEVICE, NULL);
61     if(!gps_state->device) {
62     printf("Unable to connect to liblocation\n");
63     return;
64     }
65    
66     gps_state->idd_changed =
67     g_signal_connect(gps_state->device, "changed",
68     G_CALLBACK(location_changed), gps_state);
69    
70     gps_state->control = location_gpsd_control_get_default();
71     if(gps_state->control->can_control) {
72     printf("Having control over GPSD, starting it\n");
73     location_gpsd_control_start(gps_state->control);
74     }
75     }
76    
77     void gps_release(appdata_t *appdata) {
78     gps_state_t *gps_state = appdata->gps_state;
79    
80     if(!gps_state->device) return;
81    
82     /* Disconnect signal */
83     if(gps_state->control->can_control) {
84     printf("Having control over GPSD, stopping it\n");
85     location_gpsd_control_stop(gps_state->control);
86     }
87    
88     g_signal_handler_disconnect(gps_state->device, gps_state->idd_changed);
89    
90     g_free(appdata->gps_state);
91     appdata->gps_state = NULL;
92     }
93    
94     #else // ENABLE_LIBLOCATION
95    
96 harbaum 112 #ifdef ENABLE_GPSBT
97 harbaum 1 #include <gpsbt.h>
98     #include <gpsmgr.h>
99     #include <errno.h>
100     #endif
101    
102     /* maybe user configurable later on ... */
103     #define GPSD_HOST "127.0.0.1"
104     #define GPSD_PORT 2947
105    
106     pos_t *gps_get_pos(appdata_t *appdata) {
107     static pos_t retval;
108    
109     retval.lat = NAN;
110    
111     g_mutex_lock(appdata->gps_state->mutex);
112     if(appdata->gps_state->gpsdata.set & STATUS_SET)
113     if(appdata->gps_state->gpsdata.status != STATUS_NO_FIX)
114     if(appdata->gps_state->gpsdata.set & LATLON_SET)
115     retval = appdata->gps_state->gpsdata.fix.pos;
116    
117     g_mutex_unlock(appdata->gps_state->mutex);
118    
119     if(isnan(retval.lat))
120     return NULL;
121    
122     return &retval;
123     }
124    
125     static int gps_connect(gps_state_t *gps_state) {
126     GnomeVFSResult vfs_result;
127 harbaum 112 #ifdef ENABLE_GPSBT
128 harbaum 1 char errstr[256] = "";
129    
130     /* We need to start gpsd (via gpsbt) first. */
131     memset(&gps_state->context, 0, sizeof(gpsbt_t));
132     errno = 0;
133    
134     if(gpsbt_start(NULL, 0, 0, 0, errstr, sizeof(errstr),
135     0, &gps_state->context) < 0) {
136     printf("Error connecting to GPS receiver: (%d) %s (%s)\n",
137     errno, strerror(errno), errstr);
138     }
139     #endif
140    
141     /************** from here down pure gnome/gtk/gpsd ********************/
142    
143     /* try to connect to gpsd */
144     /* Create a socket to interact with GPSD. */
145    
146     int retries = 5;
147     while(retries &&
148     (GNOME_VFS_OK != (vfs_result = gnome_vfs_inet_connection_create(
149     &gps_state->iconn, GPSD_HOST, GPSD_PORT, NULL)))) {
150     printf("Error creating connection to GPSD, retrying ...\n");
151    
152     retries--;
153     sleep(1);
154     }
155    
156     if(!retries) {
157     printf("Finally failed ...\n");
158     return -1;
159     }
160    
161     retries = 5;
162     while(retries && ((gps_state->socket =
163     gnome_vfs_inet_connection_to_socket(gps_state->iconn)) == NULL)) {
164     printf("Error creating connecting GPSD socket, retrying ...\n");
165    
166     retries--;
167     sleep(1);
168     }
169    
170     if(!retries) {
171     printf("Finally failed ...\n");
172     gnome_vfs_inet_connection_destroy(gps_state->iconn, NULL);
173     return -1;
174     }
175    
176     GTimeVal timeout = { 10, 0 };
177     if(GNOME_VFS_OK != (vfs_result = gnome_vfs_socket_set_timeout(
178     gps_state->socket, &timeout, NULL))) {
179     printf("Error setting GPSD timeout\n");
180     gnome_vfs_inet_connection_destroy(gps_state->iconn, NULL);
181     return -1;
182     }
183    
184     printf("GPSD connected ...\n");
185    
186     return 0;
187     }
188    
189     void gps_clear_fix(struct gps_fix_t *fixp) {
190     fixp->mode = MODE_NOT_SEEN;
191     fixp->pos.lat = fixp->pos.lon = NAN;
192     fixp->eph = 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 'O':
209     if (sp[2] == '?') {
210     gpsdata->set =
211     (gpsdata->set & SATELLITE_SET) | // fix for below
212     MODE_SET | STATUS_SET; // this clears sat info??
213     gpsdata->status = STATUS_NO_FIX;
214     gps_clear_fix(&gpsdata->fix);
215     } else {
216     struct gps_fix_t nf;
217     char tag[MAXTAGLEN+1], alt[20], eph[20], lat[20], lon[20], mode[2];
218     int st = sscanf(sp+2,
219     "%8s %*s %*s %19s %19s "
220     "%19s %19s %*s %*s %*s %*s "
221     "%*s %*s %*s %1s",
222     tag, lat, lon,
223     alt, eph,
224     mode);
225     if (st >= 5) {
226     #define DEFAULT(val) (val[0] == '?') ? NAN : g_ascii_strtod(val, NULL)
227     nf.pos.lat = DEFAULT(lat);
228     nf.pos.lon = DEFAULT(lon);
229     nf.eph = DEFAULT(eph);
230     #undef DEFAULT
231     if (st >= 6)
232     nf.mode = (mode[0] == '?') ? MODE_NOT_SEEN : atoi(mode);
233     else
234     nf.mode = (alt[0] == '?') ? MODE_2D : MODE_3D;
235     gpsdata->fix = nf;
236     gpsdata->set |= LATLON_SET|MODE_SET;
237     gpsdata->status = STATUS_FIX;
238     gpsdata->set |= STATUS_SET;
239     }
240     }
241     break;
242     }
243     }
244     }
245     }
246     }
247    
248     gpointer gps_thread(gpointer data) {
249     GnomeVFSFileSize bytes_read;
250     GnomeVFSResult vfs_result;
251     char str[512];
252     appdata_t *appdata = (appdata_t*)data;
253    
254     const char *msg = "o\r\n"; /* pos request */
255    
256     appdata->gps_state->gpsdata.set = 0;
257    
258     gboolean connected = FALSE;
259    
260     while(1) {
261     if(appdata->gps_enabled) {
262     if(!connected) {
263     printf("trying to connect\n");
264    
265     if(gps_connect(appdata->gps_state) < 0)
266     sleep(10);
267     else
268     connected = TRUE;
269     } else {
270     if(GNOME_VFS_OK ==
271     (vfs_result = gnome_vfs_socket_write(appdata->gps_state->socket,
272     msg, strlen(msg)+1, &bytes_read, NULL))) {
273    
274     /* update every second, wait here to make sure a complete */
275     /* reply is received */
276     sleep(1);
277    
278     if(bytes_read == (strlen(msg)+1)) {
279     vfs_result = gnome_vfs_socket_read(appdata->gps_state->socket,
280     str, sizeof(str)-1, &bytes_read, NULL);
281     if(vfs_result == GNOME_VFS_OK) {
282     str[bytes_read] = 0;
283    
284     printf("msg: %s (%d)\n", str, strlen(str));
285    
286     g_mutex_lock(appdata->gps_state->mutex);
287    
288     appdata->gps_state->gpsdata.set &=
289     ~(LATLON_SET|MODE_SET|STATUS_SET);
290    
291     gps_unpack(str, &appdata->gps_state->gpsdata);
292     g_mutex_unlock(appdata->gps_state->mutex);
293     }
294     }
295     }
296     }
297     } else {
298     if(connected) {
299     printf("stopping GPS connection due to user request\n");
300     gnome_vfs_inet_connection_destroy(appdata->gps_state->iconn, NULL);
301    
302 harbaum 112 #ifdef ENABLE_GPSBT
303 harbaum 1 gpsbt_stop(&appdata->gps_state->context);
304     #endif
305     connected = FALSE;
306     } else
307     sleep(1);
308     }
309     }
310    
311     printf("GPS thread ended???\n");
312     return NULL;
313     }
314    
315     void gps_init(appdata_t *appdata) {
316     appdata->gps_state = g_new0(gps_state_t, 1);
317    
318 harbaum 118 printf("GPS init: Using gpsd\n");
319    
320 harbaum 1 /* start a new thread to listen to gpsd */
321     appdata->gps_state->mutex = g_mutex_new();
322     appdata->gps_state->thread_p =
323     g_thread_create(gps_thread, appdata, FALSE, NULL);
324     }
325    
326     void gps_release(appdata_t *appdata) {
327 harbaum 112 #ifdef ENABLE_GPSBT
328 harbaum 1 gpsbt_stop(&appdata->gps_state->context);
329     #endif
330     g_free(appdata->gps_state);
331 harbaum 118 appdata->gps_state = NULL;
332 harbaum 1 }
333 harbaum 118
334     #endif // ENABLE_LIBLOCATION