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