TYPE3
[iec.git] / src / type3_AndroidCloud / anbox-master / android / gps / gps_qemu.c
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
877 qemu_gps_inject_time(GpsUtcTime time, int64_t timeReference, int uncertainty)
878 {
879     return 0;
880 }
881
882 static int
883 qemu_gps_inject_location(double latitude, double longitude, float accuracy)
884 {
885     return 0;
886 }
887
888 static void
889 qemu_gps_delete_aiding_data(GpsAidingData flags)
890 {
891 }
892
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*
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
919 const GpsInterface* gps__get_gps_interface(struct gps_device_t* dev)
920 {
921     return &qemuGpsInterface;
922 }
923
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 };