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