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
58typedef struct {
59    const char*  p;
60    const char*  end;
61} Token;
62
63#define  MAX_NMEA_TOKENS  16
64
65typedef struct {
66    int     count;
67    Token   tokens[ MAX_NMEA_TOKENS ];
68} NmeaTokenizer;
69
70static int
71nmea_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
114static Token
115nmea_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
129static int
130str2int( 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
150Fail:
151    return -1;
152}
153
154static double
155str2float( 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
179typedef 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
192static void
193nmea_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
219static void
220nmea_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
236static void
237nmea_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
247static int
248nmea_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
291static int
292nmea_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
318static double
319convert_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
329static int
330nmea_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
364static int
365nmea_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
381static int
382nmea_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
397static int
398nmea_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
412static int
413nmea_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
423static void
424nmea_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
548static void
549nmea_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 */
581enum {
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 */
589typedef struct {
590    int                     init;
591    int                     fd;
592    GpsCallbacks            callbacks;
593    pthread_t               thread;
594    int                     control[2];
595} GpsState;
596
597static GpsState  _gps_state[1];
598
599
600static void
601gps_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
619static void
620gps_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
634static void
635gps_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
649static int
650epoll_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
668static int
669epoll_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 */
682static void
683gps_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
806static void
807gps_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
850Fail:
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
864static int
865qemu_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
878static void
879qemu_gps_cleanup(void)
880{
881    GpsState*  s = _gps_state;
882
883    if (s->init)
884        gps_state_done(s);
885}
886
887
888static int
889qemu_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
904static int
905qemu_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
920static int
921qemu_gps_inject_time(GpsUtcTime __unused time,
922                     int64_t __unused timeReference,
923                     int __unused uncertainty)
924{
925    return 0;
926}
927
928static int
929qemu_gps_inject_location(double __unused latitude,
930                         double __unused longitude,
931                         float __unused accuracy)
932{
933    return 0;
934}
935
936static void
937qemu_gps_delete_aiding_data(GpsAidingData __unused flags)
938{
939}
940
941static 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
951static const void*
952qemu_gps_get_extension(const char* __unused name)
953{
954    // no extensions supported
955    return NULL;
956}
957
958static 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
971const GpsInterface* gps__get_gps_interface(struct gps_device_t* __unused dev)
972{
973    return &qemuGpsInterface;
974}
975
976static 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
994static struct hw_module_methods_t gps_module_methods = {
995    .open = open_gps
996};
997
998struct 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