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         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     // This is a little confusing, let's use an example:
281     // Suppose now it's 1970-1-1 01:00 GMT, local time is 1970-1-1 00:00 GMT-1
282     // Then the utc_diff is 3600.
283     // The time string from GPS is 01:00:00, mktime assumes it's a local
284     // time. So we are doing mktime for 1970-1-1 01:00 GMT-1. The result of
285     // mktime is 7200 (1970-1-1 02:00 GMT) actually. To get the correct
286     // timestamp, we have to subtract utc_diff here.
287     fix_time = mktime( &tm ) - r->utc_diff;
288     r->fix.timestamp = (long long)fix_time * 1000;
289     return 0;
290 }
291 
292 static int
nmea_reader_update_date(NmeaReader * r,Token date,Token time)293 nmea_reader_update_date( NmeaReader*  r, Token  date, Token  time )
294 {
295     Token  tok = date;
296     int    day, mon, year;
297 
298     if (tok.p + 6 != tok.end) {
299         D("date not properly formatted: '%.*s'", tok.end-tok.p, tok.p);
300         return -1;
301     }
302     day  = str2int(tok.p, tok.p+2);
303     mon  = str2int(tok.p+2, tok.p+4);
304     year = str2int(tok.p+4, tok.p+6) + 2000;
305 
306     if ((day|mon|year) < 0) {
307         D("date not properly formatted: '%.*s'", tok.end-tok.p, tok.p);
308         return -1;
309     }
310 
311     r->utc_year  = year;
312     r->utc_mon   = mon;
313     r->utc_day   = day;
314 
315     return nmea_reader_update_time( r, time );
316 }
317 
318 
319 static double
convert_from_hhmm(Token tok)320 convert_from_hhmm( Token  tok )
321 {
322     double  val     = str2float(tok.p, tok.end);
323     int     degrees = (int)(floor(val) / 100);
324     double  minutes = val - degrees*100.;
325     double  dcoord  = degrees + minutes / 60.0;
326     return dcoord;
327 }
328 
329 
330 static int
nmea_reader_update_latlong(NmeaReader * r,Token latitude,char latitudeHemi,Token longitude,char longitudeHemi)331 nmea_reader_update_latlong( NmeaReader*  r,
332                             Token        latitude,
333                             char         latitudeHemi,
334                             Token        longitude,
335                             char         longitudeHemi )
336 {
337     double   lat, lon;
338     Token    tok;
339 
340     tok = latitude;
341     if (tok.p + 6 > tok.end) {
342         D("latitude is too short: '%.*s'", tok.end-tok.p, tok.p);
343         return -1;
344     }
345     lat = convert_from_hhmm(tok);
346     if (latitudeHemi == 'S')
347         lat = -lat;
348 
349     tok = longitude;
350     if (tok.p + 6 > tok.end) {
351         D("longitude is too short: '%.*s'", tok.end-tok.p, tok.p);
352         return -1;
353     }
354     lon = convert_from_hhmm(tok);
355     if (longitudeHemi == 'W')
356         lon = -lon;
357 
358     r->fix.flags    |= GPS_LOCATION_HAS_LAT_LONG;
359     r->fix.latitude  = lat;
360     r->fix.longitude = lon;
361     return 0;
362 }
363 
364 
365 static int
nmea_reader_update_altitude(NmeaReader * r,Token altitude,Token __unused units)366 nmea_reader_update_altitude( NmeaReader* r,
367                              Token altitude,
368                              Token __unused units )
369 {
370     double  alt;
371     Token   tok = altitude;
372 
373     if (tok.p >= tok.end)
374         return -1;
375 
376     r->fix.flags   |= GPS_LOCATION_HAS_ALTITUDE;
377     r->fix.altitude = str2float(tok.p, tok.end);
378     return 0;
379 }
380 
381 
382 static int
nmea_reader_update_bearing(NmeaReader * r,Token bearing)383 nmea_reader_update_bearing( NmeaReader*  r,
384                             Token        bearing )
385 {
386     double  alt;
387     Token   tok = bearing;
388 
389     if (tok.p >= tok.end)
390         return -1;
391 
392     r->fix.flags   |= GPS_LOCATION_HAS_BEARING;
393     r->fix.bearing  = str2float(tok.p, tok.end);
394     return 0;
395 }
396 
397 
398 static int
nmea_reader_update_speed(NmeaReader * r,Token speed)399 nmea_reader_update_speed( NmeaReader*  r,
400                           Token        speed )
401 {
402     double  alt;
403     Token   tok = speed;
404 
405     if (tok.p >= tok.end)
406         return -1;
407 
408     r->fix.flags   |= GPS_LOCATION_HAS_SPEED;
409     r->fix.speed    = str2float(tok.p, tok.end);
410     return 0;
411 }
412 
413 static int
nmea_reader_update_accuracy(NmeaReader * r)414 nmea_reader_update_accuracy( NmeaReader*  r )
415 {
416     // Always return 20m accuracy.
417     // Possibly parse it from the NMEA sentence in the future.
418     r->fix.flags    |= GPS_LOCATION_HAS_ACCURACY;
419     r->fix.accuracy = 20;
420     return 0;
421 }
422 
423 
424 static void
nmea_reader_parse(NmeaReader * r)425 nmea_reader_parse( NmeaReader*  r )
426 {
427    /* we received a complete sentence, now parse it to generate
428     * a new GPS fix...
429     */
430     NmeaTokenizer  tzer[1];
431     Token          tok;
432 
433     D("Received: '%.*s'", r->pos, r->in);
434     if (r->pos < 9) {
435         D("Too short. discarded.");
436         return;
437     }
438 
439     nmea_tokenizer_init(tzer, r->in, r->in + r->pos);
440 #if GPS_DEBUG
441     {
442         int  n;
443         D("Found %d tokens", tzer->count);
444         for (n = 0; n < tzer->count; n++) {
445             Token  tok = nmea_tokenizer_get(tzer,n);
446             D("%2d: '%.*s'", n, tok.end-tok.p, tok.p);
447         }
448     }
449 #endif
450 
451     tok = nmea_tokenizer_get(tzer, 0);
452     if (tok.p + 5 > tok.end) {
453         D("sentence id '%.*s' too short, ignored.", tok.end-tok.p, tok.p);
454         return;
455     }
456 
457     // ignore first two characters.
458     tok.p += 2;
459     if ( !memcmp(tok.p, "GGA", 3) ) {
460         // GPS fix
461         Token  tok_time          = nmea_tokenizer_get(tzer,1);
462         Token  tok_latitude      = nmea_tokenizer_get(tzer,2);
463         Token  tok_latitudeHemi  = nmea_tokenizer_get(tzer,3);
464         Token  tok_longitude     = nmea_tokenizer_get(tzer,4);
465         Token  tok_longitudeHemi = nmea_tokenizer_get(tzer,5);
466         Token  tok_altitude      = nmea_tokenizer_get(tzer,9);
467         Token  tok_altitudeUnits = nmea_tokenizer_get(tzer,10);
468 
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             nmea_reader_update_date( r, tok_date, tok_time );
493 
494             nmea_reader_update_latlong( r, tok_latitude,
495                                            tok_latitudeHemi.p[0],
496                                            tok_longitude,
497                                            tok_longitudeHemi.p[0] );
498 
499             nmea_reader_update_bearing( r, tok_bearing );
500             nmea_reader_update_speed  ( r, tok_speed );
501         }
502     } else {
503         tok.p -= 2;
504         D("unknown sentence '%.*s", tok.end-tok.p, tok.p);
505     }
506 
507     // Always update accuracy
508     nmea_reader_update_accuracy( r );
509 
510     if (r->fix.flags != 0) {
511 #if GPS_DEBUG
512         char   temp[256];
513         char*  p   = temp;
514         char*  end = p + sizeof(temp);
515         struct tm   utc;
516 
517         p += snprintf( p, end-p, "sending fix" );
518         if (r->fix.flags & GPS_LOCATION_HAS_LAT_LONG) {
519             p += snprintf(p, end-p, " lat=%g lon=%g", r->fix.latitude, r->fix.longitude);
520         }
521         if (r->fix.flags & GPS_LOCATION_HAS_ALTITUDE) {
522             p += snprintf(p, end-p, " altitude=%g", r->fix.altitude);
523         }
524         if (r->fix.flags & GPS_LOCATION_HAS_SPEED) {
525             p += snprintf(p, end-p, " speed=%g", r->fix.speed);
526         }
527         if (r->fix.flags & GPS_LOCATION_HAS_BEARING) {
528             p += snprintf(p, end-p, " bearing=%g", r->fix.bearing);
529         }
530         if (r->fix.flags & GPS_LOCATION_HAS_ACCURACY) {
531             p += snprintf(p,end-p, " accuracy=%g", r->fix.accuracy);
532         }
533         gmtime_r( (time_t*) &r->fix.timestamp, &utc );
534         p += snprintf(p, end-p, " time=%s", asctime( &utc ) );
535         D(temp);
536 #endif
537         if (r->callback) {
538             r->callback( &r->fix );
539             r->fix.flags = 0;
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 
692     nmea_reader_init( reader );
693 
694     // register control file descriptors for polling
695     epoll_register( epoll_fd, control_fd );
696     epoll_register( epoll_fd, gps_fd );
697 
698     D("gps thread running");
699 
700     // now loop
701     for (;;) {
702         struct epoll_event   events[2];
703         int                  ne, nevents;
704 
705         nevents = epoll_wait( epoll_fd, events, 2, -1 );
706         if (nevents < 0) {
707             if (errno != EINTR)
708                 ALOGE("epoll_wait() unexpected error: %s", strerror(errno));
709             continue;
710         }
711         D("gps thread received %d events", nevents);
712         for (ne = 0; ne < nevents; ne++) {
713             if ((events[ne].events & (EPOLLERR|EPOLLHUP)) != 0) {
714                 ALOGE("EPOLLERR or EPOLLHUP after epoll_wait() !?");
715                 return;
716             }
717             if ((events[ne].events & EPOLLIN) != 0) {
718                 int  fd = events[ne].data.fd;
719 
720                 if (fd == control_fd)
721                 {
722                     char  cmd = 255;
723                     int   ret;
724                     D("gps control fd event");
725                     do {
726                         ret = read( fd, &cmd, 1 );
727                     } while (ret < 0 && errno == EINTR);
728 
729                     if (cmd == CMD_QUIT) {
730                         D("gps thread quitting on demand");
731                         return;
732                     }
733                     else if (cmd == CMD_START) {
734                         if (!started) {
735                             D("gps thread starting  location_cb=%p", state->callbacks.location_cb);
736                             started = 1;
737                             nmea_reader_set_callback( reader, state->callbacks.location_cb );
738                         }
739                     }
740                     else if (cmd == CMD_STOP) {
741                         if (started) {
742                             D("gps thread stopping");
743                             started = 0;
744                             nmea_reader_set_callback( reader, NULL );
745                         }
746                     }
747                 }
748                 else if (fd == gps_fd)
749                 {
750                     char  buff[32];
751                     D("gps fd event");
752                     for (;;) {
753                         int  nn, ret;
754 
755                         ret = read( fd, buff, sizeof(buff) );
756                         if (ret < 0) {
757                             if (errno == EINTR)
758                                 continue;
759                             if (errno != EWOULDBLOCK)
760                                 ALOGE("error while reading from gps daemon socket: %s:", strerror(errno));
761                             break;
762                         }
763                         D("received %d bytes: %.*s", ret, ret, buff);
764                         for (nn = 0; nn < ret; nn++)
765                             nmea_reader_addc( reader, buff[nn] );
766                     }
767                     D("gps fd event end");
768                 }
769                 else
770                 {
771                     ALOGE("epoll_wait() returned unkown fd %d ?", fd);
772                 }
773             }
774         }
775     }
776 }
777 
778 
779 static void
gps_state_init(GpsState * state,GpsCallbacks * callbacks)780 gps_state_init( GpsState*  state, GpsCallbacks* callbacks )
781 {
782     state->init       = 1;
783     state->control[0] = -1;
784     state->control[1] = -1;
785     state->fd         = -1;
786 
787     state->fd = qemu_pipe_open(QEMU_CHANNEL_NAME);
788 
789     if (state->fd < 0) {
790         D("no gps emulation detected");
791         return;
792     }
793 
794     D("gps emulation will read from '%s' qemu pipe", QEMU_CHANNEL_NAME );
795 
796     if ( socketpair( AF_LOCAL, SOCK_STREAM, 0, state->control ) < 0 ) {
797         ALOGE("could not create thread control socket pair: %s", strerror(errno));
798         goto Fail;
799     }
800 
801     state->thread = callbacks->create_thread_cb( "gps_state_thread", gps_state_thread, state );
802 
803     if ( !state->thread ) {
804         ALOGE("could not create gps thread: %s", strerror(errno));
805         goto Fail;
806     }
807 
808     state->callbacks = *callbacks;
809 
810     D("gps state initialized");
811     return;
812 
813 Fail:
814     gps_state_done( state );
815 }
816 
817 
818 /*****************************************************************/
819 /*****************************************************************/
820 /*****                                                       *****/
821 /*****       I N T E R F A C E                               *****/
822 /*****                                                       *****/
823 /*****************************************************************/
824 /*****************************************************************/
825 
826 
827 static int
qemu_gps_init(GpsCallbacks * callbacks)828 qemu_gps_init(GpsCallbacks* callbacks)
829 {
830     GpsState*  s = _gps_state;
831 
832     if (!s->init)
833         gps_state_init(s, callbacks);
834 
835     if (s->fd < 0)
836         return -1;
837 
838     return 0;
839 }
840 
841 static void
qemu_gps_cleanup(void)842 qemu_gps_cleanup(void)
843 {
844     GpsState*  s = _gps_state;
845 
846     if (s->init)
847         gps_state_done(s);
848 }
849 
850 
851 static int
qemu_gps_start()852 qemu_gps_start()
853 {
854     GpsState*  s = _gps_state;
855 
856     if (!s->init) {
857         D("%s: called with uninitialized state !!", __FUNCTION__);
858         return -1;
859     }
860 
861     D("%s: called", __FUNCTION__);
862     gps_state_start(s);
863     return 0;
864 }
865 
866 
867 static int
qemu_gps_stop()868 qemu_gps_stop()
869 {
870     GpsState*  s = _gps_state;
871 
872     if (!s->init) {
873         D("%s: called with uninitialized state !!", __FUNCTION__);
874         return -1;
875     }
876 
877     D("%s: called", __FUNCTION__);
878     gps_state_stop(s);
879     return 0;
880 }
881 
882 
883 static int
qemu_gps_inject_time(GpsUtcTime __unused time,int64_t __unused timeReference,int __unused uncertainty)884 qemu_gps_inject_time(GpsUtcTime __unused time,
885                      int64_t __unused timeReference,
886                      int __unused uncertainty)
887 {
888     return 0;
889 }
890 
891 static int
qemu_gps_inject_location(double __unused latitude,double __unused longitude,float __unused accuracy)892 qemu_gps_inject_location(double __unused latitude,
893                          double __unused longitude,
894                          float __unused accuracy)
895 {
896     return 0;
897 }
898 
899 static void
qemu_gps_delete_aiding_data(GpsAidingData __unused flags)900 qemu_gps_delete_aiding_data(GpsAidingData __unused flags)
901 {
902 }
903 
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)904 static int qemu_gps_set_position_mode(GpsPositionMode __unused mode,
905                                       GpsPositionRecurrence __unused recurrence,
906                                       uint32_t __unused min_interval,
907                                       uint32_t __unused preferred_accuracy,
908                                       uint32_t __unused preferred_time)
909 {
910     // FIXME - support fix_frequency
911     return 0;
912 }
913 
914 static const void*
qemu_gps_get_extension(const char * __unused name)915 qemu_gps_get_extension(const char* __unused name)
916 {
917     // no extensions supported
918     return NULL;
919 }
920 
921 static const GpsInterface  qemuGpsInterface = {
922     sizeof(GpsInterface),
923     qemu_gps_init,
924     qemu_gps_start,
925     qemu_gps_stop,
926     qemu_gps_cleanup,
927     qemu_gps_inject_time,
928     qemu_gps_inject_location,
929     qemu_gps_delete_aiding_data,
930     qemu_gps_set_position_mode,
931     qemu_gps_get_extension,
932 };
933 
gps__get_gps_interface(struct gps_device_t * __unused dev)934 const GpsInterface* gps__get_gps_interface(struct gps_device_t* __unused dev)
935 {
936     return &qemuGpsInterface;
937 }
938 
open_gps(const struct hw_module_t * module,char const * __unused name,struct hw_device_t ** device)939 static int open_gps(const struct hw_module_t* module,
940                     char const* __unused name,
941                     struct hw_device_t** device)
942 {
943     struct gps_device_t *dev = malloc(sizeof(struct gps_device_t));
944     memset(dev, 0, sizeof(*dev));
945 
946     dev->common.tag = HARDWARE_DEVICE_TAG;
947     dev->common.version = 0;
948     dev->common.module = (struct hw_module_t*)module;
949 //    dev->common.close = (int (*)(struct hw_device_t*))close_lights;
950     dev->get_gps_interface = gps__get_gps_interface;
951 
952     *device = (struct hw_device_t*)dev;
953     return 0;
954 }
955 
956 
957 static struct hw_module_methods_t gps_module_methods = {
958     .open = open_gps
959 };
960 
961 struct hw_module_t HAL_MODULE_INFO_SYM = {
962     .tag = HARDWARE_MODULE_TAG,
963     .version_major = 1,
964     .version_minor = 0,
965     .id = GPS_HARDWARE_MODULE_ID,
966     .name = "Goldfish GPS Module",
967     .author = "The Android Open Source Project",
968     .methods = &gps_module_methods,
969 };
970