• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "qemu_pipe.h"
38 
39 /* the name of the qemu-controlled pipe */
40 #define  QEMU_CHANNEL_NAME  "qemud: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     }
244 }
245 
246 
247 static int
nmea_reader_update_time(NmeaReader * r,Token tok)248 nmea_reader_update_time( NmeaReader*  r, Token  tok )
249 {
250     int        hour, minute;
251     double     seconds;
252     struct tm  tm;
253     time_t     fix_time;
254 
255     if (tok.p + 6 > tok.end)
256         return -1;
257 
258     if (r->utc_year < 0) {
259         // no date yet, get current one
260         time_t  now = time(NULL);
261         gmtime_r( &now, &tm );
262         r->utc_year = tm.tm_year + 1900;
263         r->utc_mon  = tm.tm_mon + 1;
264         r->utc_day  = tm.tm_mday;
265     }
266 
267     hour    = str2int(tok.p,   tok.p+2);
268     minute  = str2int(tok.p+2, tok.p+4);
269     seconds = str2float(tok.p+4, tok.end);
270 
271     tm.tm_hour  = hour;
272     tm.tm_min   = minute;
273     tm.tm_sec   = (int) seconds;
274     tm.tm_year  = r->utc_year - 1900;
275     tm.tm_mon   = r->utc_mon - 1;
276     tm.tm_mday  = r->utc_day;
277     tm.tm_isdst = -1;
278 
279     // This is a little confusing, let's use an example:
280     // Suppose now it's 1970-1-1 01:00 GMT, local time is 1970-1-1 00:00 GMT-1
281     // Then the utc_diff is 3600.
282     // The time string from GPS is 01:00:00, mktime assumes it's a local
283     // time. So we are doing mktime for 1970-1-1 01:00 GMT-1. The result of
284     // mktime is 7200 (1970-1-1 02:00 GMT) actually. To get the correct
285     // timestamp, we have to subtract utc_diff here.
286     fix_time = mktime( &tm ) - r->utc_diff;
287     r->fix.timestamp = (long long)fix_time * 1000;
288     return 0;
289 }
290 
291 static int
nmea_reader_update_date(NmeaReader * r,Token date,Token time)292 nmea_reader_update_date( NmeaReader*  r, Token  date, Token  time )
293 {
294     Token  tok = date;
295     int    day, mon, year;
296 
297     if (tok.p + 6 != tok.end) {
298         D("date not properly formatted: '%.*s'", tok.end-tok.p, tok.p);
299         return -1;
300     }
301     day  = str2int(tok.p, tok.p+2);
302     mon  = str2int(tok.p+2, tok.p+4);
303     year = str2int(tok.p+4, tok.p+6) + 2000;
304 
305     if ((day|mon|year) < 0) {
306         D("date not properly formatted: '%.*s'", tok.end-tok.p, tok.p);
307         return -1;
308     }
309 
310     r->utc_year  = year;
311     r->utc_mon   = mon;
312     r->utc_day   = day;
313 
314     return nmea_reader_update_time( r, time );
315 }
316 
317 
318 static double
convert_from_hhmm(Token tok)319 convert_from_hhmm( Token  tok )
320 {
321     double  val     = str2float(tok.p, tok.end);
322     int     degrees = (int)(floor(val) / 100);
323     double  minutes = val - degrees*100.;
324     double  dcoord  = degrees + minutes / 60.0;
325     return dcoord;
326 }
327 
328 
329 static int
nmea_reader_update_latlong(NmeaReader * r,Token latitude,char latitudeHemi,Token longitude,char longitudeHemi)330 nmea_reader_update_latlong( NmeaReader*  r,
331                             Token        latitude,
332                             char         latitudeHemi,
333                             Token        longitude,
334                             char         longitudeHemi )
335 {
336     double   lat, lon;
337     Token    tok;
338 
339     tok = latitude;
340     if (tok.p + 6 > tok.end) {
341         D("latitude is too short: '%.*s'", tok.end-tok.p, tok.p);
342         return -1;
343     }
344     lat = convert_from_hhmm(tok);
345     if (latitudeHemi == 'S')
346         lat = -lat;
347 
348     tok = longitude;
349     if (tok.p + 6 > tok.end) {
350         D("longitude is too short: '%.*s'", tok.end-tok.p, tok.p);
351         return -1;
352     }
353     lon = convert_from_hhmm(tok);
354     if (longitudeHemi == 'W')
355         lon = -lon;
356 
357     r->fix.flags    |= GPS_LOCATION_HAS_LAT_LONG;
358     r->fix.latitude  = lat;
359     r->fix.longitude = lon;
360     return 0;
361 }
362 
363 
364 static int
nmea_reader_update_altitude(NmeaReader * r,Token altitude,Token __unused units)365 nmea_reader_update_altitude( NmeaReader* r,
366                              Token altitude,
367                              Token __unused units )
368 {
369     double  alt;
370     Token   tok = altitude;
371 
372     if (tok.p >= tok.end)
373         return -1;
374 
375     r->fix.flags   |= GPS_LOCATION_HAS_ALTITUDE;
376     r->fix.altitude = str2float(tok.p, tok.end);
377     return 0;
378 }
379 
380 
381 static int
nmea_reader_update_bearing(NmeaReader * r,Token bearing)382 nmea_reader_update_bearing( NmeaReader*  r,
383                             Token        bearing )
384 {
385     double  alt;
386     Token   tok = bearing;
387 
388     if (tok.p >= tok.end)
389         return -1;
390 
391     r->fix.flags   |= GPS_LOCATION_HAS_BEARING;
392     r->fix.bearing  = str2float(tok.p, tok.end);
393     return 0;
394 }
395 
396 
397 static int
nmea_reader_update_speed(NmeaReader * r,Token speed)398 nmea_reader_update_speed( NmeaReader*  r,
399                           Token        speed )
400 {
401     double  alt;
402     Token   tok = speed;
403 
404     if (tok.p >= tok.end)
405         return -1;
406 
407     r->fix.flags   |= GPS_LOCATION_HAS_SPEED;
408     r->fix.speed    = str2float(tok.p, tok.end);
409     return 0;
410 }
411 
412 static int
nmea_reader_update_accuracy(NmeaReader * r)413 nmea_reader_update_accuracy( NmeaReader*  r )
414 {
415     // Always return 20m accuracy.
416     // Possibly parse it from the NMEA sentence in the future.
417     r->fix.flags    |= GPS_LOCATION_HAS_ACCURACY;
418     r->fix.accuracy = 20;
419     return 0;
420 }
421 
422 
423 static void
nmea_reader_parse(NmeaReader * r)424 nmea_reader_parse( NmeaReader*  r )
425 {
426    /* we received a complete sentence, now parse it to generate
427     * a new GPS fix...
428     */
429     NmeaTokenizer  tzer[1];
430     Token          tok;
431 
432     D("Received: '%.*s'", r->pos, r->in);
433     if (r->pos < 9) {
434         D("Too short. discarded.");
435         return;
436     }
437 
438     nmea_tokenizer_init(tzer, r->in, r->in + r->pos);
439 #if GPS_DEBUG
440     {
441         int  n;
442         D("Found %d tokens", tzer->count);
443         for (n = 0; n < tzer->count; n++) {
444             Token  tok = nmea_tokenizer_get(tzer,n);
445             D("%2d: '%.*s'", n, tok.end-tok.p, tok.p);
446         }
447     }
448 #endif
449 
450     tok = nmea_tokenizer_get(tzer, 0);
451     if (tok.p + 5 > tok.end) {
452         D("sentence id '%.*s' too short, ignored.", tok.end-tok.p, tok.p);
453         return;
454     }
455 
456     // ignore first two characters.
457     tok.p += 2;
458     if ( !memcmp(tok.p, "GGA", 3) ) {
459         // GPS fix
460         Token  tok_time          = nmea_tokenizer_get(tzer,1);
461         Token  tok_latitude      = nmea_tokenizer_get(tzer,2);
462         Token  tok_latitudeHemi  = nmea_tokenizer_get(tzer,3);
463         Token  tok_longitude     = nmea_tokenizer_get(tzer,4);
464         Token  tok_longitudeHemi = nmea_tokenizer_get(tzer,5);
465         Token  tok_altitude      = nmea_tokenizer_get(tzer,9);
466         Token  tok_altitudeUnits = nmea_tokenizer_get(tzer,10);
467 
468         r->fix.flags = 0;
469         nmea_reader_update_time(r, tok_time);
470         nmea_reader_update_latlong(r, tok_latitude,
471                                       tok_latitudeHemi.p[0],
472                                       tok_longitude,
473                                       tok_longitudeHemi.p[0]);
474         nmea_reader_update_altitude(r, tok_altitude, tok_altitudeUnits);
475 
476     } else if ( !memcmp(tok.p, "GSA", 3) ) {
477         // do something ?
478     } else if ( !memcmp(tok.p, "RMC", 3) ) {
479         Token  tok_time          = nmea_tokenizer_get(tzer,1);
480         Token  tok_fixStatus     = nmea_tokenizer_get(tzer,2);
481         Token  tok_latitude      = nmea_tokenizer_get(tzer,3);
482         Token  tok_latitudeHemi  = nmea_tokenizer_get(tzer,4);
483         Token  tok_longitude     = nmea_tokenizer_get(tzer,5);
484         Token  tok_longitudeHemi = nmea_tokenizer_get(tzer,6);
485         Token  tok_speed         = nmea_tokenizer_get(tzer,7);
486         Token  tok_bearing       = nmea_tokenizer_get(tzer,8);
487         Token  tok_date          = nmea_tokenizer_get(tzer,9);
488 
489         D("in RMC, fixStatus=%c", tok_fixStatus.p[0]);
490         if (tok_fixStatus.p[0] == 'A')
491         {
492             r->fix.flags = 0;
493             nmea_reader_update_date( r, tok_date, tok_time );
494 
495             nmea_reader_update_latlong( r, tok_latitude,
496                                            tok_latitudeHemi.p[0],
497                                            tok_longitude,
498                                            tok_longitudeHemi.p[0] );
499 
500             nmea_reader_update_bearing( r, tok_bearing );
501             nmea_reader_update_speed  ( r, tok_speed );
502         }
503     } else {
504         tok.p -= 2;
505         D("unknown sentence '%.*s", tok.end-tok.p, tok.p);
506     }
507 
508     // Always update accuracy
509     nmea_reader_update_accuracy( r );
510 
511     if (r->fix.flags != 0) {
512 #if GPS_DEBUG
513         char   temp[256];
514         char*  p   = temp;
515         char*  end = p + sizeof(temp);
516         struct tm   utc;
517 
518         p += snprintf( p, end-p, "sending fix" );
519         if (r->fix.flags & GPS_LOCATION_HAS_LAT_LONG) {
520             p += snprintf(p, end-p, " lat=%g lon=%g", r->fix.latitude, r->fix.longitude);
521         }
522         if (r->fix.flags & GPS_LOCATION_HAS_ALTITUDE) {
523             p += snprintf(p, end-p, " altitude=%g", r->fix.altitude);
524         }
525         if (r->fix.flags & GPS_LOCATION_HAS_SPEED) {
526             p += snprintf(p, end-p, " speed=%g", r->fix.speed);
527         }
528         if (r->fix.flags & GPS_LOCATION_HAS_BEARING) {
529             p += snprintf(p, end-p, " bearing=%g", r->fix.bearing);
530         }
531         if (r->fix.flags & GPS_LOCATION_HAS_ACCURACY) {
532             p += snprintf(p,end-p, " accuracy=%g", r->fix.accuracy);
533         }
534         gmtime_r( (time_t*) &r->fix.timestamp, &utc );
535         p += snprintf(p, end-p, " time=%s", asctime( &utc ) );
536         D(temp);
537 #endif
538         if (r->callback) {
539             r->callback( &r->fix );
540         }
541         else {
542             D("no callback, keeping data until needed !");
543         }
544     }
545 }
546 
547 
548 static void
nmea_reader_addc(NmeaReader * r,int c)549 nmea_reader_addc( NmeaReader*  r, int  c )
550 {
551     if (r->overflow) {
552         r->overflow = (c != '\n');
553         return;
554     }
555 
556     if (r->pos >= (int) sizeof(r->in)-1 ) {
557         r->overflow = 1;
558         r->pos      = 0;
559         return;
560     }
561 
562     r->in[r->pos] = (char)c;
563     r->pos       += 1;
564 
565     if (c == '\n') {
566         nmea_reader_parse( r );
567         r->pos = 0;
568     }
569 }
570 
571 
572 /*****************************************************************/
573 /*****************************************************************/
574 /*****                                                       *****/
575 /*****       C O N N E C T I O N   S T A T E                 *****/
576 /*****                                                       *****/
577 /*****************************************************************/
578 /*****************************************************************/
579 
580 /* commands sent to the gps thread */
581 enum {
582     CMD_QUIT  = 0,
583     CMD_START = 1,
584     CMD_STOP  = 2
585 };
586 
587 
588 /* this is the state of our connection to the qemu_gpsd daemon */
589 typedef struct {
590     int                     init;
591     int                     fd;
592     GpsCallbacks            callbacks;
593     pthread_t               thread;
594     int                     control[2];
595 } GpsState;
596 
597 static GpsState  _gps_state[1];
598 
599 
600 static void
gps_state_done(GpsState * s)601 gps_state_done( GpsState*  s )
602 {
603     // tell the thread to quit, and wait for it
604     char   cmd = CMD_QUIT;
605     void*  dummy;
606     write( s->control[0], &cmd, 1 );
607     pthread_join(s->thread, &dummy);
608 
609     // close the control socket pair
610     close( s->control[0] ); s->control[0] = -1;
611     close( s->control[1] ); s->control[1] = -1;
612 
613     // close connection to the QEMU GPS daemon
614     close( s->fd ); s->fd = -1;
615     s->init = 0;
616 }
617 
618 
619 static void
gps_state_start(GpsState * s)620 gps_state_start( GpsState*  s )
621 {
622     char  cmd = CMD_START;
623     int   ret;
624 
625     do { ret=write( s->control[0], &cmd, 1 ); }
626     while (ret < 0 && errno == EINTR);
627 
628     if (ret != 1)
629         D("%s: could not send CMD_START command: ret=%d: %s",
630           __FUNCTION__, ret, strerror(errno));
631 }
632 
633 
634 static void
gps_state_stop(GpsState * s)635 gps_state_stop( GpsState*  s )
636 {
637     char  cmd = CMD_STOP;
638     int   ret;
639 
640     do { ret=write( s->control[0], &cmd, 1 ); }
641     while (ret < 0 && errno == EINTR);
642 
643     if (ret != 1)
644         D("%s: could not send CMD_STOP command: ret=%d: %s",
645           __FUNCTION__, ret, strerror(errno));
646 }
647 
648 
649 static int
epoll_register(int epoll_fd,int fd)650 epoll_register( int  epoll_fd, int  fd )
651 {
652     struct epoll_event  ev;
653     int                 ret, flags;
654 
655     /* important: make the fd non-blocking */
656     flags = fcntl(fd, F_GETFL);
657     fcntl(fd, F_SETFL, flags | O_NONBLOCK);
658 
659     ev.events  = EPOLLIN;
660     ev.data.fd = fd;
661     do {
662         ret = epoll_ctl( epoll_fd, EPOLL_CTL_ADD, fd, &ev );
663     } while (ret < 0 && errno == EINTR);
664     return ret;
665 }
666 
667 
668 static int
epoll_deregister(int epoll_fd,int fd)669 epoll_deregister( int  epoll_fd, int  fd )
670 {
671     int  ret;
672     do {
673         ret = epoll_ctl( epoll_fd, EPOLL_CTL_DEL, fd, NULL );
674     } while (ret < 0 && errno == EINTR);
675     return ret;
676 }
677 
678 /* this is the main thread, it waits for commands from gps_state_start/stop and,
679  * when started, messages from the QEMU GPS daemon. these are simple NMEA sentences
680  * that must be parsed to be converted into GPS fixes sent to the framework
681  */
682 static void
gps_state_thread(void * arg)683 gps_state_thread( void*  arg )
684 {
685     GpsState*   state = (GpsState*) arg;
686     NmeaReader  reader[1];
687     int         epoll_fd   = epoll_create(2);
688     int         started    = 0;
689     int         gps_fd     = state->fd;
690     int         control_fd = state->control[1];
691     GpsStatus gps_status;
692     gps_status.size = sizeof(gps_status);
693     GpsSvStatus  gps_sv_status;
694     memset(&gps_sv_status, 0, sizeof(gps_sv_status));
695     gps_sv_status.size = sizeof(gps_sv_status);
696     gps_sv_status.num_svs = 1;
697     gps_sv_status.sv_list[0].size = sizeof(gps_sv_status.sv_list[0]);
698     gps_sv_status.sv_list[0].prn = 17;
699     gps_sv_status.sv_list[0].snr = 60.0;
700     gps_sv_status.sv_list[0].elevation = 30.0;
701     gps_sv_status.sv_list[0].azimuth = 30.0;
702 
703     nmea_reader_init( reader );
704 
705     // register control file descriptors for polling
706     epoll_register( epoll_fd, control_fd );
707     epoll_register( epoll_fd, gps_fd );
708 
709     D("gps thread running");
710 
711     // now loop
712     for (;;) {
713         struct epoll_event   events[2];
714         int                  ne, nevents;
715 
716         int timeout = -1;
717         if (gps_status.status == GPS_STATUS_SESSION_BEGIN) {
718             timeout = 10 * 1000; // 10 seconds
719         }
720         nevents = epoll_wait( epoll_fd, events, 2, timeout );
721         if (state->callbacks.sv_status_cb) {
722             state->callbacks.sv_status_cb(&gps_sv_status);
723         }
724         // update satilite info
725         if (nevents < 0) {
726             if (errno != EINTR)
727                 ALOGE("epoll_wait() unexpected error: %s", strerror(errno));
728             continue;
729         }
730         D("gps thread received %d events", nevents);
731         for (ne = 0; ne < nevents; ne++) {
732             if ((events[ne].events & (EPOLLERR|EPOLLHUP)) != 0) {
733                 ALOGE("EPOLLERR or EPOLLHUP after epoll_wait() !?");
734                 return;
735             }
736             if ((events[ne].events & EPOLLIN) != 0) {
737                 int  fd = events[ne].data.fd;
738 
739                 if (fd == control_fd)
740                 {
741                     char  cmd = 255;
742                     int   ret;
743                     D("gps control fd event");
744                     do {
745                         ret = read( fd, &cmd, 1 );
746                     } while (ret < 0 && errno == EINTR);
747 
748                     if (cmd == CMD_QUIT) {
749                         D("gps thread quitting on demand");
750                         return;
751                     }
752                     else if (cmd == CMD_START) {
753                         if (!started) {
754                             D("gps thread starting  location_cb=%p", state->callbacks.location_cb);
755                             started = 1;
756                             nmea_reader_set_callback( reader, state->callbacks.location_cb );
757                             gps_status.status = GPS_STATUS_SESSION_BEGIN;
758                             if (state->callbacks.status_cb) {
759                                 state->callbacks.status_cb(&gps_status);
760                             }
761                         }
762                     }
763                     else if (cmd == CMD_STOP) {
764                         if (started) {
765                             D("gps thread stopping");
766                             started = 0;
767                             nmea_reader_set_callback( reader, NULL );
768                             gps_status.status = GPS_STATUS_SESSION_END;
769                             if (state->callbacks.status_cb) {
770                                 state->callbacks.status_cb(&gps_status);
771                             }
772                         }
773                     }
774                 }
775                 else if (fd == gps_fd)
776                 {
777                     char  buff[32];
778                     D("gps fd event");
779                     for (;;) {
780                         int  nn, ret;
781 
782                         ret = read( fd, buff, sizeof(buff) );
783                         if (ret < 0) {
784                             if (errno == EINTR)
785                                 continue;
786                             if (errno != EWOULDBLOCK)
787                                 ALOGE("error while reading from gps daemon socket: %s:", strerror(errno));
788                             break;
789                         }
790                         D("received %d bytes: %.*s", ret, ret, buff);
791                         for (nn = 0; nn < ret; nn++)
792                             nmea_reader_addc( reader, buff[nn] );
793                     }
794                     D("gps fd event end");
795                 }
796                 else
797                 {
798                     ALOGE("epoll_wait() returned unkown fd %d ?", fd);
799                 }
800             }
801         }
802     }
803 }
804 
805 
806 static void
gps_state_init(GpsState * state,GpsCallbacks * callbacks)807 gps_state_init( GpsState*  state, GpsCallbacks* callbacks )
808 {
809     state->init       = 1;
810     state->control[0] = -1;
811     state->control[1] = -1;
812     state->fd         = -1;
813 
814     state->fd = qemu_pipe_open(QEMU_CHANNEL_NAME);
815 
816     if (state->fd < 0) {
817         D("no gps emulation detected");
818         return;
819     }
820 
821     D("gps emulation will read from '%s' qemu pipe", QEMU_CHANNEL_NAME );
822 
823     if ( socketpair( AF_LOCAL, SOCK_STREAM, 0, state->control ) < 0 ) {
824         ALOGE("could not create thread control socket pair: %s", strerror(errno));
825         goto Fail;
826     }
827 
828     state->thread = callbacks->create_thread_cb( "gps_state_thread", gps_state_thread, state );
829 
830     if ( !state->thread ) {
831         ALOGE("could not create gps thread: %s", strerror(errno));
832         goto Fail;
833     }
834 
835     state->callbacks = *callbacks;
836 
837     // Explicitly initialize capabilities
838     state->callbacks.set_capabilities_cb(0);
839 
840 
841     // Setup system info, we are pre 2016 hardware.
842     GnssSystemInfo sysinfo;
843     sysinfo.size = sizeof(GnssSystemInfo);
844     sysinfo.year_of_hw = 2015;
845     state->callbacks.set_system_info_cb(&sysinfo);
846 
847     D("gps state initialized");
848     return;
849 
850 Fail:
851     gps_state_done( state );
852 }
853 
854 
855 /*****************************************************************/
856 /*****************************************************************/
857 /*****                                                       *****/
858 /*****       I N T E R F A C E                               *****/
859 /*****                                                       *****/
860 /*****************************************************************/
861 /*****************************************************************/
862 
863 
864 static int
qemu_gps_init(GpsCallbacks * callbacks)865 qemu_gps_init(GpsCallbacks* callbacks)
866 {
867     GpsState*  s = _gps_state;
868 
869     if (!s->init)
870         gps_state_init(s, callbacks);
871 
872     if (s->fd < 0)
873         return -1;
874 
875     return 0;
876 }
877 
878 static void
qemu_gps_cleanup(void)879 qemu_gps_cleanup(void)
880 {
881     GpsState*  s = _gps_state;
882 
883     if (s->init)
884         gps_state_done(s);
885 }
886 
887 
888 static int
qemu_gps_start()889 qemu_gps_start()
890 {
891     GpsState*  s = _gps_state;
892 
893     if (!s->init) {
894         D("%s: called with uninitialized state !!", __FUNCTION__);
895         return -1;
896     }
897 
898     D("%s: called", __FUNCTION__);
899     gps_state_start(s);
900     return 0;
901 }
902 
903 
904 static int
qemu_gps_stop()905 qemu_gps_stop()
906 {
907     GpsState*  s = _gps_state;
908 
909     if (!s->init) {
910         D("%s: called with uninitialized state !!", __FUNCTION__);
911         return -1;
912     }
913 
914     D("%s: called", __FUNCTION__);
915     gps_state_stop(s);
916     return 0;
917 }
918 
919 
920 static int
qemu_gps_inject_time(GpsUtcTime __unused time,int64_t __unused timeReference,int __unused uncertainty)921 qemu_gps_inject_time(GpsUtcTime __unused time,
922                      int64_t __unused timeReference,
923                      int __unused uncertainty)
924 {
925     return 0;
926 }
927 
928 static int
qemu_gps_inject_location(double __unused latitude,double __unused longitude,float __unused accuracy)929 qemu_gps_inject_location(double __unused latitude,
930                          double __unused longitude,
931                          float __unused accuracy)
932 {
933     return 0;
934 }
935 
936 static void
qemu_gps_delete_aiding_data(GpsAidingData __unused flags)937 qemu_gps_delete_aiding_data(GpsAidingData __unused flags)
938 {
939 }
940 
qemu_gps_set_position_mode(GpsPositionMode __unused mode,GpsPositionRecurrence __unused recurrence,uint32_t __unused min_interval,uint32_t __unused preferred_accuracy,uint32_t __unused preferred_time)941 static int qemu_gps_set_position_mode(GpsPositionMode __unused mode,
942                                       GpsPositionRecurrence __unused recurrence,
943                                       uint32_t __unused min_interval,
944                                       uint32_t __unused preferred_accuracy,
945                                       uint32_t __unused preferred_time)
946 {
947     // FIXME - support fix_frequency
948     return 0;
949 }
950 
951 static const void*
qemu_gps_get_extension(const char * __unused name)952 qemu_gps_get_extension(const char* __unused name)
953 {
954     // no extensions supported
955     return NULL;
956 }
957 
958 static const GpsInterface  qemuGpsInterface = {
959     sizeof(GpsInterface),
960     qemu_gps_init,
961     qemu_gps_start,
962     qemu_gps_stop,
963     qemu_gps_cleanup,
964     qemu_gps_inject_time,
965     qemu_gps_inject_location,
966     qemu_gps_delete_aiding_data,
967     qemu_gps_set_position_mode,
968     qemu_gps_get_extension,
969 };
970 
gps__get_gps_interface(struct gps_device_t * __unused dev)971 const GpsInterface* gps__get_gps_interface(struct gps_device_t* __unused dev)
972 {
973     return &qemuGpsInterface;
974 }
975 
open_gps(const struct hw_module_t * module,char const * __unused name,struct hw_device_t ** device)976 static int open_gps(const struct hw_module_t* module,
977                     char const* __unused name,
978                     struct hw_device_t** device)
979 {
980     struct gps_device_t *dev = malloc(sizeof(struct gps_device_t));
981     memset(dev, 0, sizeof(*dev));
982 
983     dev->common.tag = HARDWARE_DEVICE_TAG;
984     dev->common.version = 0;
985     dev->common.module = (struct hw_module_t*)module;
986 //    dev->common.close = (int (*)(struct hw_device_t*))close_lights;
987     dev->get_gps_interface = gps__get_gps_interface;
988 
989     *device = (struct hw_device_t*)dev;
990     return 0;
991 }
992 
993 
994 static struct hw_module_methods_t gps_module_methods = {
995     .open = open_gps
996 };
997 
998 struct hw_module_t HAL_MODULE_INFO_SYM = {
999     .tag = HARDWARE_MODULE_TAG,
1000     .version_major = 1,
1001     .version_minor = 0,
1002     .id = GPS_HARDWARE_MODULE_ID,
1003     .name = "Goldfish GPS Module",
1004     .author = "The Android Open Source Project",
1005     .methods = &gps_module_methods,
1006 };
1007