Contents of /trunk/src/gps.c

Parent Directory Parent Directory | Revision Log Revision Log


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