1 /*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 /* this implements a GPS hardware library for the Android emulator.
18 * the following code should be built as a shared library that will be
19 * placed into /system/lib/hw/gps.goldfish.so
20 *
21 * it will be loaded by the code in hardware/libhardware/hardware.c
22 * which is itself called from android_location_GpsLocationProvider.cpp
23 */
24
25
26 #include <errno.h>
27 #include <pthread.h>
28 #include <fcntl.h>
29 #include <sys/epoll.h>
30 #include <math.h>
31 #include <time.h>
32
33 #define LOG_TAG "gps_qemu"
34 #include <cutils/log.h>
35 #include <cutils/sockets.h>
36 #include <hardware/gps.h>
37 #include <hardware/qemud.h>
38
39 /* the name of the qemud-controlled socket */
40 #define QEMU_CHANNEL_NAME "gps"
41
42 #define GPS_DEBUG 0
43
44 #if GPS_DEBUG
45 # define D(...) ALOGD(__VA_ARGS__)
46 #else
47 # define D(...) ((void)0)
48 #endif
49
50 /*****************************************************************/
51 /*****************************************************************/
52 /***** *****/
53 /***** N M E A T O K E N I Z E R *****/
54 /***** *****/
55 /*****************************************************************/
56 /*****************************************************************/
57
58 typedef struct {
59 const char* p;
60 const char* end;
61 } Token;
62
63 #define MAX_NMEA_TOKENS 16
64
65 typedef struct {
66 int count;
67 Token tokens[ MAX_NMEA_TOKENS ];
68 } NmeaTokenizer;
69
70 static int
nmea_tokenizer_init(NmeaTokenizer * t,const char * p,const char * end)71 nmea_tokenizer_init( NmeaTokenizer* t, const char* p, const char* end )
72 {
73 int count = 0;
74 char* q;
75
76 // the initial '$' is optional
77 if (p < end && p[0] == '$')
78 p += 1;
79
80 // remove trailing newline
81 if (end > p && end[-1] == '\n') {
82 end -= 1;
83 if (end > p && end[-1] == '\r')
84 end -= 1;
85 }
86
87 // get rid of checksum at the end of the sentecne
88 if (end >= p+3 && end[-3] == '*') {
89 end -= 3;
90 }
91
92 while (p < end) {
93 const char* q = p;
94
95 q = memchr(p, ',', end-p);
96 if (q == NULL)
97 q = end;
98
99 if (count < MAX_NMEA_TOKENS) {
100 t->tokens[count].p = p;
101 t->tokens[count].end = q;
102 count += 1;
103 }
104 if (q < end)
105 q += 1;
106
107 p = q;
108 }
109
110 t->count = count;
111 return count;
112 }
113
114 static Token
nmea_tokenizer_get(NmeaTokenizer * t,int index)115 nmea_tokenizer_get( NmeaTokenizer* t, int index )
116 {
117 Token tok;
118 static const char* dummy = "";
119
120 if (index < 0 || index >= t->count) {
121 tok.p = tok.end = dummy;
122 } else
123 tok = t->tokens[index];
124
125 return tok;
126 }
127
128
129 static int
str2int(const char * p,const char * end)130 str2int( const char* p, const char* end )
131 {
132 int result = 0;
133 int len = end - p;
134
135 for ( ; len > 0; len--, p++ )
136 {
137 int c;
138
139 if (p >= end)
140 goto Fail;
141
142 c = *p - '0';
143 if ((unsigned)c >= 10)
144 goto Fail;
145
146 result = result*10 + c;
147 }
148 return result;
149
150 Fail:
151 return -1;
152 }
153
154 static double
str2float(const char * p,const char * end)155 str2float( const char* p, const char* end )
156 {
157 int result = 0;
158 int len = end - p;
159 char temp[16];
160
161 if (len >= (int)sizeof(temp))
162 return 0.;
163
164 memcpy( temp, p, len );
165 temp[len] = 0;
166 return strtod( temp, NULL );
167 }
168
169 /*****************************************************************/
170 /*****************************************************************/
171 /***** *****/
172 /***** N M E A P A R S E R *****/
173 /***** *****/
174 /*****************************************************************/
175 /*****************************************************************/
176
177 #define NMEA_MAX_SIZE 83
178
179 typedef struct {
180 int pos;
181 int overflow;
182 int utc_year;
183 int utc_mon;
184 int utc_day;
185 int utc_diff;
186 GpsLocation fix;
187 gps_location_callback callback;
188 char in[ NMEA_MAX_SIZE+1 ];
189 } NmeaReader;
190
191
192 static void
nmea_reader_update_utc_diff(NmeaReader * r)193 nmea_reader_update_utc_diff( NmeaReader* r )
194 {
195 time_t now = time(NULL);
196 struct tm tm_local;
197 struct tm tm_utc;
198 long time_local, time_utc;
199
200 gmtime_r( &now, &tm_utc );
201 localtime_r( &now, &tm_local );
202
203 time_local = tm_local.tm_sec +
204 60*(tm_local.tm_min +
205 60*(tm_local.tm_hour +
206 24*(tm_local.tm_yday +
207 365*tm_local.tm_year)));
208
209 time_utc = tm_utc.tm_sec +
210 60*(tm_utc.tm_min +
211 60*(tm_utc.tm_hour +
212 24*(tm_utc.tm_yday +
213 365*tm_utc.tm_year)));
214
215 r->utc_diff = time_utc - time_local;
216 }
217
218
219 static void
nmea_reader_init(NmeaReader * r)220 nmea_reader_init( NmeaReader* r )
221 {
222 memset( r, 0, sizeof(*r) );
223
224 r->pos = 0;
225 r->overflow = 0;
226 r->utc_year = -1;
227 r->utc_mon = -1;
228 r->utc_day = -1;
229 r->callback = NULL;
230 r->fix.size = sizeof(r->fix);
231
232 nmea_reader_update_utc_diff( r );
233 }
234
235
236 static void
nmea_reader_set_callback(NmeaReader * r,gps_location_callback cb)237 nmea_reader_set_callback( NmeaReader* r, gps_location_callback cb )
238 {
239 r->callback = cb;
240 if (cb != NULL && r->fix.flags != 0) {
241 D("%s: sending latest fix to new callback", __FUNCTION__);
242 r->callback( &r->fix );
243 r->fix.flags = 0;
244 }
245 }
246
247
248 static int
nmea_reader_update_time(NmeaReader * r,Token tok)249 nmea_reader_update_time( NmeaReader* r, Token tok )
250 {
251 int hour, minute;
252 double seconds;
253 struct tm tm;
254 time_t fix_time;
255
256 if (tok.p + 6 > tok.end)
257 return -1;
258
259 if (r->utc_year < 0) {
260 // no date yet, get current one
261 time_t now = time(NULL);
262 gmtime_r( &now, &tm );
263 r->utc_year = tm.tm_year + 1900;
264 r->utc_mon = tm.tm_mon + 1;
265 r->utc_day = tm.tm_mday;
266 }
267
268 hour = str2int(tok.p, tok.p+2);
269 minute = str2int(tok.p+2, tok.p+4);
270 seconds = str2float(tok.p+4, tok.end);
271
272 tm.tm_hour = hour;
273 tm.tm_min = minute;
274 tm.tm_sec = (int) seconds;
275 tm.tm_year = r->utc_year - 1900;
276 tm.tm_mon = r->utc_mon - 1;
277 tm.tm_mday = r->utc_day;
278 tm.tm_isdst = -1;
279
280 fix_time = mktime( &tm ) + r->utc_diff;
281 r->fix.timestamp = (long long)fix_time * 1000;
282 return 0;
283 }
284
285 static int
nmea_reader_update_date(NmeaReader * r,Token date,Token time)286 nmea_reader_update_date( NmeaReader* r, Token date, Token time )
287 {
288 Token tok = date;
289 int day, mon, year;
290
291 if (tok.p + 6 != tok.end) {
292 D("date not properly formatted: '%.*s'", tok.end-tok.p, tok.p);
293 return -1;
294 }
295 day = str2int(tok.p, tok.p+2);
296 mon = str2int(tok.p+2, tok.p+4);
297 year = str2int(tok.p+4, tok.p+6) + 2000;
298
299 if ((day|mon|year) < 0) {
300 D("date not properly formatted: '%.*s'", tok.end-tok.p, tok.p);
301 return -1;
302 }
303
304 r->utc_year = year;
305 r->utc_mon = mon;
306 r->utc_day = day;
307
308 return nmea_reader_update_time( r, time );
309 }
310
311
312 static double
convert_from_hhmm(Token tok)313 convert_from_hhmm( Token tok )
314 {
315 double val = str2float(tok.p, tok.end);
316 int degrees = (int)(floor(val) / 100);
317 double minutes = val - degrees*100.;
318 double dcoord = degrees + minutes / 60.0;
319 return dcoord;
320 }
321
322
323 static int
nmea_reader_update_latlong(NmeaReader * r,Token latitude,char latitudeHemi,Token longitude,char longitudeHemi)324 nmea_reader_update_latlong( NmeaReader* r,
325 Token latitude,
326 char latitudeHemi,
327 Token longitude,
328 char longitudeHemi )
329 {
330 double lat, lon;
331 Token tok;
332
333 tok = latitude;
334 if (tok.p + 6 > tok.end) {
335 D("latitude is too short: '%.*s'", tok.end-tok.p, tok.p);
336 return -1;
337 }
338 lat = convert_from_hhmm(tok);
339 if (latitudeHemi == 'S')
340 lat = -lat;
341
342 tok = longitude;
343 if (tok.p + 6 > tok.end) {
344 D("longitude is too short: '%.*s'", tok.end-tok.p, tok.p);
345 return -1;
346 }
347 lon = convert_from_hhmm(tok);
348 if (longitudeHemi == 'W')
349 lon = -lon;
350
351 r->fix.flags |= GPS_LOCATION_HAS_LAT_LONG;
352 r->fix.latitude = lat;
353 r->fix.longitude = lon;
354 return 0;
355 }
356
357
358 static int
nmea_reader_update_altitude(NmeaReader * r,Token altitude,Token units)359 nmea_reader_update_altitude( NmeaReader* r,
360 Token altitude,
361 Token units )
362 {
363 double alt;
364 Token tok = altitude;
365
366 if (tok.p >= tok.end)
367 return -1;
368
369 r->fix.flags |= GPS_LOCATION_HAS_ALTITUDE;
370 r->fix.altitude = str2float(tok.p, tok.end);
371 return 0;
372 }
373
374
375 static int
nmea_reader_update_bearing(NmeaReader * r,Token bearing)376 nmea_reader_update_bearing( NmeaReader* r,
377 Token bearing )
378 {
379 double alt;
380 Token tok = bearing;
381
382 if (tok.p >= tok.end)
383 return -1;
384
385 r->fix.flags |= GPS_LOCATION_HAS_BEARING;
386 r->fix.bearing = str2float(tok.p, tok.end);
387 return 0;
388 }
389
390
391 static int
nmea_reader_update_speed(NmeaReader * r,Token speed)392 nmea_reader_update_speed( NmeaReader* r,
393 Token speed )
394 {
395 double alt;
396 Token tok = speed;
397
398 if (tok.p >= tok.end)
399 return -1;
400
401 r->fix.flags |= GPS_LOCATION_HAS_SPEED;
402 r->fix.speed = str2float(tok.p, tok.end);
403 return 0;
404 }
405
406 static int
nmea_reader_update_accuracy(NmeaReader * r)407 nmea_reader_update_accuracy( NmeaReader* r )
408 {
409 // Always return 20m accuracy.
410 // Possibly parse it from the NMEA sentence in the future.
411 r->fix.flags |= GPS_LOCATION_HAS_ACCURACY;
412 r->fix.accuracy = 20;
413 return 0;
414 }
415
416
417 static void
nmea_reader_parse(NmeaReader * r)418 nmea_reader_parse( NmeaReader* r )
419 {
420 /* we received a complete sentence, now parse it to generate
421 * a new GPS fix...
422 */
423 NmeaTokenizer tzer[1];
424 Token tok;
425
426 D("Received: '%.*s'", r->pos, r->in);
427 if (r->pos < 9) {
428 D("Too short. discarded.");
429 return;
430 }
431
432 nmea_tokenizer_init(tzer, r->in, r->in + r->pos);
433 #if GPS_DEBUG
434 {
435 int n;
436 D("Found %d tokens", tzer->count);
437 for (n = 0; n < tzer->count; n++) {
438 Token tok = nmea_tokenizer_get(tzer,n);
439 D("%2d: '%.*s'", n, tok.end-tok.p, tok.p);
440 }
441 }
442 #endif
443
444 tok = nmea_tokenizer_get(tzer, 0);
445 if (tok.p + 5 > tok.end) {
446 D("sentence id '%.*s' too short, ignored.", tok.end-tok.p, tok.p);
447 return;
448 }
449
450 // ignore first two characters.
451 tok.p += 2;
452 if ( !memcmp(tok.p, "GGA", 3) ) {
453 // GPS fix
454 Token tok_time = nmea_tokenizer_get(tzer,1);
455 Token tok_latitude = nmea_tokenizer_get(tzer,2);
456 Token tok_latitudeHemi = nmea_tokenizer_get(tzer,3);
457 Token tok_longitude = nmea_tokenizer_get(tzer,4);
458 Token tok_longitudeHemi = nmea_tokenizer_get(tzer,5);
459 Token tok_altitude = nmea_tokenizer_get(tzer,9);
460 Token tok_altitudeUnits = nmea_tokenizer_get(tzer,10);
461
462 nmea_reader_update_time(r, tok_time);
463 nmea_reader_update_latlong(r, tok_latitude,
464 tok_latitudeHemi.p[0],
465 tok_longitude,
466 tok_longitudeHemi.p[0]);
467 nmea_reader_update_altitude(r, tok_altitude, tok_altitudeUnits);
468
469 } else if ( !memcmp(tok.p, "GSA", 3) ) {
470 // do something ?
471 } else if ( !memcmp(tok.p, "RMC", 3) ) {
472 Token tok_time = nmea_tokenizer_get(tzer,1);
473 Token tok_fixStatus = nmea_tokenizer_get(tzer,2);
474 Token tok_latitude = nmea_tokenizer_get(tzer,3);
475 Token tok_latitudeHemi = nmea_tokenizer_get(tzer,4);
476 Token tok_longitude = nmea_tokenizer_get(tzer,5);
477 Token tok_longitudeHemi = nmea_tokenizer_get(tzer,6);
478 Token tok_speed = nmea_tokenizer_get(tzer,7);
479 Token tok_bearing = nmea_tokenizer_get(tzer,8);
480 Token tok_date = nmea_tokenizer_get(tzer,9);
481
482 D("in RMC, fixStatus=%c", tok_fixStatus.p[0]);
483 if (tok_fixStatus.p[0] == 'A')
484 {
485 nmea_reader_update_date( r, tok_date, tok_time );
486
487 nmea_reader_update_latlong( r, tok_latitude,
488 tok_latitudeHemi.p[0],
489 tok_longitude,
490 tok_longitudeHemi.p[0] );
491
492 nmea_reader_update_bearing( r, tok_bearing );
493 nmea_reader_update_speed ( r, tok_speed );
494 }
495 } else {
496 tok.p -= 2;
497 D("unknown sentence '%.*s", tok.end-tok.p, tok.p);
498 }
499
500 // Always update accuracy
501 nmea_reader_update_accuracy( r );
502
503 if (r->fix.flags != 0) {
504 #if GPS_DEBUG
505 char temp[256];
506 char* p = temp;
507 char* end = p + sizeof(temp);
508 struct tm utc;
509
510 p += snprintf( p, end-p, "sending fix" );
511 if (r->fix.flags & GPS_LOCATION_HAS_LAT_LONG) {
512 p += snprintf(p, end-p, " lat=%g lon=%g", r->fix.latitude, r->fix.longitude);
513 }
514 if (r->fix.flags & GPS_LOCATION_HAS_ALTITUDE) {
515 p += snprintf(p, end-p, " altitude=%g", r->fix.altitude);
516 }
517 if (r->fix.flags & GPS_LOCATION_HAS_SPEED) {
518 p += snprintf(p, end-p, " speed=%g", r->fix.speed);
519 }
520 if (r->fix.flags & GPS_LOCATION_HAS_BEARING) {
521 p += snprintf(p, end-p, " bearing=%g", r->fix.bearing);
522 }
523 if (r->fix.flags & GPS_LOCATION_HAS_ACCURACY) {
524 p += snprintf(p,end-p, " accuracy=%g", r->fix.accuracy);
525 }
526 gmtime_r( (time_t*) &r->fix.timestamp, &utc );
527 p += snprintf(p, end-p, " time=%s", asctime( &utc ) );
528 D(temp);
529 #endif
530 if (r->callback) {
531 r->callback( &r->fix );
532 r->fix.flags = 0;
533 }
534 else {
535 D("no callback, keeping data until needed !");
536 }
537 }
538 }
539
540
541 static void
nmea_reader_addc(NmeaReader * r,int c)542 nmea_reader_addc( NmeaReader* r, int c )
543 {
544 if (r->overflow) {
545 r->overflow = (c != '\n');
546 return;
547 }
548
549 if (r->pos >= (int) sizeof(r->in)-1 ) {
550 r->overflow = 1;
551 r->pos = 0;
552 return;
553 }
554
555 r->in[r->pos] = (char)c;
556 r->pos += 1;
557
558 if (c == '\n') {
559 nmea_reader_parse( r );
560 r->pos = 0;
561 }
562 }
563
564
565 /*****************************************************************/
566 /*****************************************************************/
567 /***** *****/
568 /***** C O N N E C T I O N S T A T E *****/
569 /***** *****/
570 /*****************************************************************/
571 /*****************************************************************/
572
573 /* commands sent to the gps thread */
574 enum {
575 CMD_QUIT = 0,
576 CMD_START = 1,
577 CMD_STOP = 2
578 };
579
580
581 /* this is the state of our connection to the qemu_gpsd daemon */
582 typedef struct {
583 int init;
584 int fd;
585 GpsCallbacks callbacks;
586 pthread_t thread;
587 int control[2];
588 } GpsState;
589
590 static GpsState _gps_state[1];
591
592
593 static void
gps_state_done(GpsState * s)594 gps_state_done( GpsState* s )
595 {
596 // tell the thread to quit, and wait for it
597 char cmd = CMD_QUIT;
598 void* dummy;
599 write( s->control[0], &cmd, 1 );
600 pthread_join(s->thread, &dummy);
601
602 // close the control socket pair
603 close( s->control[0] ); s->control[0] = -1;
604 close( s->control[1] ); s->control[1] = -1;
605
606 // close connection to the QEMU GPS daemon
607 close( s->fd ); s->fd = -1;
608 s->init = 0;
609 }
610
611
612 static void
gps_state_start(GpsState * s)613 gps_state_start( GpsState* s )
614 {
615 char cmd = CMD_START;
616 int ret;
617
618 do { ret=write( s->control[0], &cmd, 1 ); }
619 while (ret < 0 && errno == EINTR);
620
621 if (ret != 1)
622 D("%s: could not send CMD_START command: ret=%d: %s",
623 __FUNCTION__, ret, strerror(errno));
624 }
625
626
627 static void
gps_state_stop(GpsState * s)628 gps_state_stop( GpsState* s )
629 {
630 char cmd = CMD_STOP;
631 int ret;
632
633 do { ret=write( s->control[0], &cmd, 1 ); }
634 while (ret < 0 && errno == EINTR);
635
636 if (ret != 1)
637 D("%s: could not send CMD_STOP command: ret=%d: %s",
638 __FUNCTION__, ret, strerror(errno));
639 }
640
641
642 static int
epoll_register(int epoll_fd,int fd)643 epoll_register( int epoll_fd, int fd )
644 {
645 struct epoll_event ev;
646 int ret, flags;
647
648 /* important: make the fd non-blocking */
649 flags = fcntl(fd, F_GETFL);
650 fcntl(fd, F_SETFL, flags | O_NONBLOCK);
651
652 ev.events = EPOLLIN;
653 ev.data.fd = fd;
654 do {
655 ret = epoll_ctl( epoll_fd, EPOLL_CTL_ADD, fd, &ev );
656 } while (ret < 0 && errno == EINTR);
657 return ret;
658 }
659
660
661 static int
epoll_deregister(int epoll_fd,int fd)662 epoll_deregister( int epoll_fd, int fd )
663 {
664 int ret;
665 do {
666 ret = epoll_ctl( epoll_fd, EPOLL_CTL_DEL, fd, NULL );
667 } while (ret < 0 && errno == EINTR);
668 return ret;
669 }
670
671 /* this is the main thread, it waits for commands from gps_state_start/stop and,
672 * when started, messages from the QEMU GPS daemon. these are simple NMEA sentences
673 * that must be parsed to be converted into GPS fixes sent to the framework
674 */
675 static void
gps_state_thread(void * arg)676 gps_state_thread( void* arg )
677 {
678 GpsState* state = (GpsState*) arg;
679 NmeaReader reader[1];
680 int epoll_fd = epoll_create(2);
681 int started = 0;
682 int gps_fd = state->fd;
683 int control_fd = state->control[1];
684
685 nmea_reader_init( reader );
686
687 // register control file descriptors for polling
688 epoll_register( epoll_fd, control_fd );
689 epoll_register( epoll_fd, gps_fd );
690
691 D("gps thread running");
692
693 // now loop
694 for (;;) {
695 struct epoll_event events[2];
696 int ne, nevents;
697
698 nevents = epoll_wait( epoll_fd, events, 2, -1 );
699 if (nevents < 0) {
700 if (errno != EINTR)
701 ALOGE("epoll_wait() unexpected error: %s", strerror(errno));
702 continue;
703 }
704 D("gps thread received %d events", nevents);
705 for (ne = 0; ne < nevents; ne++) {
706 if ((events[ne].events & (EPOLLERR|EPOLLHUP)) != 0) {
707 ALOGE("EPOLLERR or EPOLLHUP after epoll_wait() !?");
708 return;
709 }
710 if ((events[ne].events & EPOLLIN) != 0) {
711 int fd = events[ne].data.fd;
712
713 if (fd == control_fd)
714 {
715 char cmd = 255;
716 int ret;
717 D("gps control fd event");
718 do {
719 ret = read( fd, &cmd, 1 );
720 } while (ret < 0 && errno == EINTR);
721
722 if (cmd == CMD_QUIT) {
723 D("gps thread quitting on demand");
724 return;
725 }
726 else if (cmd == CMD_START) {
727 if (!started) {
728 D("gps thread starting location_cb=%p", state->callbacks.location_cb);
729 started = 1;
730 nmea_reader_set_callback( reader, state->callbacks.location_cb );
731 }
732 }
733 else if (cmd == CMD_STOP) {
734 if (started) {
735 D("gps thread stopping");
736 started = 0;
737 nmea_reader_set_callback( reader, NULL );
738 }
739 }
740 }
741 else if (fd == gps_fd)
742 {
743 char buff[32];
744 D("gps fd event");
745 for (;;) {
746 int nn, ret;
747
748 ret = read( fd, buff, sizeof(buff) );
749 if (ret < 0) {
750 if (errno == EINTR)
751 continue;
752 if (errno != EWOULDBLOCK)
753 ALOGE("error while reading from gps daemon socket: %s:", strerror(errno));
754 break;
755 }
756 D("received %d bytes: %.*s", ret, ret, buff);
757 for (nn = 0; nn < ret; nn++)
758 nmea_reader_addc( reader, buff[nn] );
759 }
760 D("gps fd event end");
761 }
762 else
763 {
764 ALOGE("epoll_wait() returned unkown fd %d ?", fd);
765 }
766 }
767 }
768 }
769 }
770
771
772 static void
gps_state_init(GpsState * state,GpsCallbacks * callbacks)773 gps_state_init( GpsState* state, GpsCallbacks* callbacks )
774 {
775 state->init = 1;
776 state->control[0] = -1;
777 state->control[1] = -1;
778 state->fd = -1;
779
780 state->fd = qemud_channel_open(QEMU_CHANNEL_NAME);
781
782 if (state->fd < 0) {
783 D("no gps emulation detected");
784 return;
785 }
786
787 D("gps emulation will read from '%s' qemud channel", QEMU_CHANNEL_NAME );
788
789 if ( socketpair( AF_LOCAL, SOCK_STREAM, 0, state->control ) < 0 ) {
790 ALOGE("could not create thread control socket pair: %s", strerror(errno));
791 goto Fail;
792 }
793
794 state->thread = callbacks->create_thread_cb( "gps_state_thread", gps_state_thread, state );
795
796 if ( !state->thread ) {
797 ALOGE("could not create gps thread: %s", strerror(errno));
798 goto Fail;
799 }
800
801 state->callbacks = *callbacks;
802
803 D("gps state initialized");
804 return;
805
806 Fail:
807 gps_state_done( state );
808 }
809
810
811 /*****************************************************************/
812 /*****************************************************************/
813 /***** *****/
814 /***** I N T E R F A C E *****/
815 /***** *****/
816 /*****************************************************************/
817 /*****************************************************************/
818
819
820 static int
qemu_gps_init(GpsCallbacks * callbacks)821 qemu_gps_init(GpsCallbacks* callbacks)
822 {
823 GpsState* s = _gps_state;
824
825 if (!s->init)
826 gps_state_init(s, callbacks);
827
828 if (s->fd < 0)
829 return -1;
830
831 return 0;
832 }
833
834 static void
qemu_gps_cleanup(void)835 qemu_gps_cleanup(void)
836 {
837 GpsState* s = _gps_state;
838
839 if (s->init)
840 gps_state_done(s);
841 }
842
843
844 static int
qemu_gps_start()845 qemu_gps_start()
846 {
847 GpsState* s = _gps_state;
848
849 if (!s->init) {
850 D("%s: called with uninitialized state !!", __FUNCTION__);
851 return -1;
852 }
853
854 D("%s: called", __FUNCTION__);
855 gps_state_start(s);
856 return 0;
857 }
858
859
860 static int
qemu_gps_stop()861 qemu_gps_stop()
862 {
863 GpsState* s = _gps_state;
864
865 if (!s->init) {
866 D("%s: called with uninitialized state !!", __FUNCTION__);
867 return -1;
868 }
869
870 D("%s: called", __FUNCTION__);
871 gps_state_stop(s);
872 return 0;
873 }
874
875
876 static int
qemu_gps_inject_time(GpsUtcTime time,int64_t timeReference,int uncertainty)877 qemu_gps_inject_time(GpsUtcTime time, int64_t timeReference, int uncertainty)
878 {
879 return 0;
880 }
881
882 static int
qemu_gps_inject_location(double latitude,double longitude,float accuracy)883 qemu_gps_inject_location(double latitude, double longitude, float accuracy)
884 {
885 return 0;
886 }
887
888 static void
qemu_gps_delete_aiding_data(GpsAidingData flags)889 qemu_gps_delete_aiding_data(GpsAidingData flags)
890 {
891 }
892
qemu_gps_set_position_mode(GpsPositionMode mode,int fix_frequency)893 static int qemu_gps_set_position_mode(GpsPositionMode mode, int fix_frequency)
894 {
895 // FIXME - support fix_frequency
896 return 0;
897 }
898
899 static const void*
qemu_gps_get_extension(const char * name)900 qemu_gps_get_extension(const char* name)
901 {
902 // no extensions supported
903 return NULL;
904 }
905
906 static const GpsInterface qemuGpsInterface = {
907 sizeof(GpsInterface),
908 qemu_gps_init,
909 qemu_gps_start,
910 qemu_gps_stop,
911 qemu_gps_cleanup,
912 qemu_gps_inject_time,
913 qemu_gps_inject_location,
914 qemu_gps_delete_aiding_data,
915 qemu_gps_set_position_mode,
916 qemu_gps_get_extension,
917 };
918
gps__get_gps_interface(struct gps_device_t * dev)919 const GpsInterface* gps__get_gps_interface(struct gps_device_t* dev)
920 {
921 return &qemuGpsInterface;
922 }
923
open_gps(const struct hw_module_t * module,char const * name,struct hw_device_t ** device)924 static int open_gps(const struct hw_module_t* module, char const* name,
925 struct hw_device_t** device)
926 {
927 struct gps_device_t *dev = malloc(sizeof(struct gps_device_t));
928 memset(dev, 0, sizeof(*dev));
929
930 dev->common.tag = HARDWARE_DEVICE_TAG;
931 dev->common.version = 0;
932 dev->common.module = (struct hw_module_t*)module;
933 // dev->common.close = (int (*)(struct hw_device_t*))close_lights;
934 dev->get_gps_interface = gps__get_gps_interface;
935
936 *device = (struct hw_device_t*)dev;
937 return 0;
938 }
939
940
941 static struct hw_module_methods_t gps_module_methods = {
942 .open = open_gps
943 };
944
945 struct hw_module_t HAL_MODULE_INFO_SYM = {
946 .tag = HARDWARE_MODULE_TAG,
947 .version_major = 1,
948 .version_minor = 0,
949 .id = GPS_HARDWARE_MODULE_ID,
950 .name = "Goldfish GPS Module",
951 .author = "The Android Open Source Project",
952 .methods = &gps_module_methods,
953 };
954