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