• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  
409  static void
nmea_reader_parse(NmeaReader * r)410  nmea_reader_parse( NmeaReader*  r )
411  {
412     /* we received a complete sentence, now parse it to generate
413      * a new GPS fix...
414      */
415      NmeaTokenizer  tzer[1];
416      Token          tok;
417  
418      D("Received: '%.*s'", r->pos, r->in);
419      if (r->pos < 9) {
420          D("Too short. discarded.");
421          return;
422      }
423  
424      nmea_tokenizer_init(tzer, r->in, r->in + r->pos);
425  #if GPS_DEBUG
426      {
427          int  n;
428          D("Found %d tokens", tzer->count);
429          for (n = 0; n < tzer->count; n++) {
430              Token  tok = nmea_tokenizer_get(tzer,n);
431              D("%2d: '%.*s'", n, tok.end-tok.p, tok.p);
432          }
433      }
434  #endif
435  
436      tok = nmea_tokenizer_get(tzer, 0);
437      if (tok.p + 5 > tok.end) {
438          D("sentence id '%.*s' too short, ignored.", tok.end-tok.p, tok.p);
439          return;
440      }
441  
442      // ignore first two characters.
443      tok.p += 2;
444      if ( !memcmp(tok.p, "GGA", 3) ) {
445          // GPS fix
446          Token  tok_time          = nmea_tokenizer_get(tzer,1);
447          Token  tok_latitude      = nmea_tokenizer_get(tzer,2);
448          Token  tok_latitudeHemi  = nmea_tokenizer_get(tzer,3);
449          Token  tok_longitude     = nmea_tokenizer_get(tzer,4);
450          Token  tok_longitudeHemi = nmea_tokenizer_get(tzer,5);
451          Token  tok_altitude      = nmea_tokenizer_get(tzer,9);
452          Token  tok_altitudeUnits = nmea_tokenizer_get(tzer,10);
453  
454          nmea_reader_update_time(r, tok_time);
455          nmea_reader_update_latlong(r, tok_latitude,
456                                        tok_latitudeHemi.p[0],
457                                        tok_longitude,
458                                        tok_longitudeHemi.p[0]);
459          nmea_reader_update_altitude(r, tok_altitude, tok_altitudeUnits);
460  
461      } else if ( !memcmp(tok.p, "GSA", 3) ) {
462          // do something ?
463      } else if ( !memcmp(tok.p, "RMC", 3) ) {
464          Token  tok_time          = nmea_tokenizer_get(tzer,1);
465          Token  tok_fixStatus     = nmea_tokenizer_get(tzer,2);
466          Token  tok_latitude      = nmea_tokenizer_get(tzer,3);
467          Token  tok_latitudeHemi  = nmea_tokenizer_get(tzer,4);
468          Token  tok_longitude     = nmea_tokenizer_get(tzer,5);
469          Token  tok_longitudeHemi = nmea_tokenizer_get(tzer,6);
470          Token  tok_speed         = nmea_tokenizer_get(tzer,7);
471          Token  tok_bearing       = nmea_tokenizer_get(tzer,8);
472          Token  tok_date          = nmea_tokenizer_get(tzer,9);
473  
474          D("in RMC, fixStatus=%c", tok_fixStatus.p[0]);
475          if (tok_fixStatus.p[0] == 'A')
476          {
477              nmea_reader_update_date( r, tok_date, tok_time );
478  
479              nmea_reader_update_latlong( r, tok_latitude,
480                                             tok_latitudeHemi.p[0],
481                                             tok_longitude,
482                                             tok_longitudeHemi.p[0] );
483  
484              nmea_reader_update_bearing( r, tok_bearing );
485              nmea_reader_update_speed  ( r, tok_speed );
486          }
487      } else {
488          tok.p -= 2;
489          D("unknown sentence '%.*s", tok.end-tok.p, tok.p);
490      }
491      if (r->fix.flags != 0) {
492  #if GPS_DEBUG
493          char   temp[256];
494          char*  p   = temp;
495          char*  end = p + sizeof(temp);
496          struct tm   utc;
497  
498          p += snprintf( p, end-p, "sending fix" );
499          if (r->fix.flags & GPS_LOCATION_HAS_LAT_LONG) {
500              p += snprintf(p, end-p, " lat=%g lon=%g", r->fix.latitude, r->fix.longitude);
501          }
502          if (r->fix.flags & GPS_LOCATION_HAS_ALTITUDE) {
503              p += snprintf(p, end-p, " altitude=%g", r->fix.altitude);
504          }
505          if (r->fix.flags & GPS_LOCATION_HAS_SPEED) {
506              p += snprintf(p, end-p, " speed=%g", r->fix.speed);
507          }
508          if (r->fix.flags & GPS_LOCATION_HAS_BEARING) {
509              p += snprintf(p, end-p, " bearing=%g", r->fix.bearing);
510          }
511          if (r->fix.flags & GPS_LOCATION_HAS_ACCURACY) {
512              p += snprintf(p,end-p, " accuracy=%g", r->fix.accuracy);
513          }
514          gmtime_r( (time_t*) &r->fix.timestamp, &utc );
515          p += snprintf(p, end-p, " time=%s", asctime( &utc ) );
516          D(temp);
517  #endif
518          if (r->callback) {
519              r->callback( &r->fix );
520              r->fix.flags = 0;
521          }
522          else {
523              D("no callback, keeping data until needed !");
524          }
525      }
526  }
527  
528  
529  static void
nmea_reader_addc(NmeaReader * r,int c)530  nmea_reader_addc( NmeaReader*  r, int  c )
531  {
532      if (r->overflow) {
533          r->overflow = (c != '\n');
534          return;
535      }
536  
537      if (r->pos >= (int) sizeof(r->in)-1 ) {
538          r->overflow = 1;
539          r->pos      = 0;
540          return;
541      }
542  
543      r->in[r->pos] = (char)c;
544      r->pos       += 1;
545  
546      if (c == '\n') {
547          nmea_reader_parse( r );
548          r->pos = 0;
549      }
550  }
551  
552  
553  /*****************************************************************/
554  /*****************************************************************/
555  /*****                                                       *****/
556  /*****       C O N N E C T I O N   S T A T E                 *****/
557  /*****                                                       *****/
558  /*****************************************************************/
559  /*****************************************************************/
560  
561  /* commands sent to the gps thread */
562  enum {
563      CMD_QUIT  = 0,
564      CMD_START = 1,
565      CMD_STOP  = 2
566  };
567  
568  
569  /* this is the state of our connection to the qemu_gpsd daemon */
570  typedef struct {
571      int                     init;
572      int                     fd;
573      GpsCallbacks            callbacks;
574      pthread_t               thread;
575      int                     control[2];
576  } GpsState;
577  
578  static GpsState  _gps_state[1];
579  
580  
581  static void
gps_state_done(GpsState * s)582  gps_state_done( GpsState*  s )
583  {
584      // tell the thread to quit, and wait for it
585      char   cmd = CMD_QUIT;
586      void*  dummy;
587      write( s->control[0], &cmd, 1 );
588      pthread_join(s->thread, &dummy);
589  
590      // close the control socket pair
591      close( s->control[0] ); s->control[0] = -1;
592      close( s->control[1] ); s->control[1] = -1;
593  
594      // close connection to the QEMU GPS daemon
595      close( s->fd ); s->fd = -1;
596      s->init = 0;
597  }
598  
599  
600  static void
gps_state_start(GpsState * s)601  gps_state_start( GpsState*  s )
602  {
603      char  cmd = CMD_START;
604      int   ret;
605  
606      do { ret=write( s->control[0], &cmd, 1 ); }
607      while (ret < 0 && errno == EINTR);
608  
609      if (ret != 1)
610          D("%s: could not send CMD_START command: ret=%d: %s",
611            __FUNCTION__, ret, strerror(errno));
612  }
613  
614  
615  static void
gps_state_stop(GpsState * s)616  gps_state_stop( GpsState*  s )
617  {
618      char  cmd = CMD_STOP;
619      int   ret;
620  
621      do { ret=write( s->control[0], &cmd, 1 ); }
622      while (ret < 0 && errno == EINTR);
623  
624      if (ret != 1)
625          D("%s: could not send CMD_STOP command: ret=%d: %s",
626            __FUNCTION__, ret, strerror(errno));
627  }
628  
629  
630  static int
epoll_register(int epoll_fd,int fd)631  epoll_register( int  epoll_fd, int  fd )
632  {
633      struct epoll_event  ev;
634      int                 ret, flags;
635  
636      /* important: make the fd non-blocking */
637      flags = fcntl(fd, F_GETFL);
638      fcntl(fd, F_SETFL, flags | O_NONBLOCK);
639  
640      ev.events  = EPOLLIN;
641      ev.data.fd = fd;
642      do {
643          ret = epoll_ctl( epoll_fd, EPOLL_CTL_ADD, fd, &ev );
644      } while (ret < 0 && errno == EINTR);
645      return ret;
646  }
647  
648  
649  static int
epoll_deregister(int epoll_fd,int fd)650  epoll_deregister( int  epoll_fd, int  fd )
651  {
652      int  ret;
653      do {
654          ret = epoll_ctl( epoll_fd, EPOLL_CTL_DEL, fd, NULL );
655      } while (ret < 0 && errno == EINTR);
656      return ret;
657  }
658  
659  /* this is the main thread, it waits for commands from gps_state_start/stop and,
660   * when started, messages from the QEMU GPS daemon. these are simple NMEA sentences
661   * that must be parsed to be converted into GPS fixes sent to the framework
662   */
663  static void
gps_state_thread(void * arg)664  gps_state_thread( void*  arg )
665  {
666      GpsState*   state = (GpsState*) arg;
667      NmeaReader  reader[1];
668      int         epoll_fd   = epoll_create(2);
669      int         started    = 0;
670      int         gps_fd     = state->fd;
671      int         control_fd = state->control[1];
672  
673      nmea_reader_init( reader );
674  
675      // register control file descriptors for polling
676      epoll_register( epoll_fd, control_fd );
677      epoll_register( epoll_fd, gps_fd );
678  
679      D("gps thread running");
680  
681      // now loop
682      for (;;) {
683          struct epoll_event   events[2];
684          int                  ne, nevents;
685  
686          nevents = epoll_wait( epoll_fd, events, 2, -1 );
687          if (nevents < 0) {
688              if (errno != EINTR)
689                  ALOGE("epoll_wait() unexpected error: %s", strerror(errno));
690              continue;
691          }
692          D("gps thread received %d events", nevents);
693          for (ne = 0; ne < nevents; ne++) {
694              if ((events[ne].events & (EPOLLERR|EPOLLHUP)) != 0) {
695                  ALOGE("EPOLLERR or EPOLLHUP after epoll_wait() !?");
696                  return;
697              }
698              if ((events[ne].events & EPOLLIN) != 0) {
699                  int  fd = events[ne].data.fd;
700  
701                  if (fd == control_fd)
702                  {
703                      char  cmd = 255;
704                      int   ret;
705                      D("gps control fd event");
706                      do {
707                          ret = read( fd, &cmd, 1 );
708                      } while (ret < 0 && errno == EINTR);
709  
710                      if (cmd == CMD_QUIT) {
711                          D("gps thread quitting on demand");
712                          return;
713                      }
714                      else if (cmd == CMD_START) {
715                          if (!started) {
716                              D("gps thread starting  location_cb=%p", state->callbacks.location_cb);
717                              started = 1;
718                              nmea_reader_set_callback( reader, state->callbacks.location_cb );
719                          }
720                      }
721                      else if (cmd == CMD_STOP) {
722                          if (started) {
723                              D("gps thread stopping");
724                              started = 0;
725                              nmea_reader_set_callback( reader, NULL );
726                          }
727                      }
728                  }
729                  else if (fd == gps_fd)
730                  {
731                      char  buff[32];
732                      D("gps fd event");
733                      for (;;) {
734                          int  nn, ret;
735  
736                          ret = read( fd, buff, sizeof(buff) );
737                          if (ret < 0) {
738                              if (errno == EINTR)
739                                  continue;
740                              if (errno != EWOULDBLOCK)
741                                  ALOGE("error while reading from gps daemon socket: %s:", strerror(errno));
742                              break;
743                          }
744                          D("received %d bytes: %.*s", ret, ret, buff);
745                          for (nn = 0; nn < ret; nn++)
746                              nmea_reader_addc( reader, buff[nn] );
747                      }
748                      D("gps fd event end");
749                  }
750                  else
751                  {
752                      ALOGE("epoll_wait() returned unkown fd %d ?", fd);
753                  }
754              }
755          }
756      }
757  }
758  
759  
760  static void
gps_state_init(GpsState * state,GpsCallbacks * callbacks)761  gps_state_init( GpsState*  state, GpsCallbacks* callbacks )
762  {
763      state->init       = 1;
764      state->control[0] = -1;
765      state->control[1] = -1;
766      state->fd         = -1;
767  
768      state->fd = qemud_channel_open(QEMU_CHANNEL_NAME);
769  
770      if (state->fd < 0) {
771          D("no gps emulation detected");
772          return;
773      }
774  
775      D("gps emulation will read from '%s' qemud channel", QEMU_CHANNEL_NAME );
776  
777      if ( socketpair( AF_LOCAL, SOCK_STREAM, 0, state->control ) < 0 ) {
778          ALOGE("could not create thread control socket pair: %s", strerror(errno));
779          goto Fail;
780      }
781  
782      state->thread = callbacks->create_thread_cb( "gps_state_thread", gps_state_thread, state );
783  
784      if ( !state->thread ) {
785          ALOGE("could not create gps thread: %s", strerror(errno));
786          goto Fail;
787      }
788  
789      state->callbacks = *callbacks;
790  
791      D("gps state initialized");
792      return;
793  
794  Fail:
795      gps_state_done( state );
796  }
797  
798  
799  /*****************************************************************/
800  /*****************************************************************/
801  /*****                                                       *****/
802  /*****       I N T E R F A C E                               *****/
803  /*****                                                       *****/
804  /*****************************************************************/
805  /*****************************************************************/
806  
807  
808  static int
qemu_gps_init(GpsCallbacks * callbacks)809  qemu_gps_init(GpsCallbacks* callbacks)
810  {
811      GpsState*  s = _gps_state;
812  
813      if (!s->init)
814          gps_state_init(s, callbacks);
815  
816      if (s->fd < 0)
817          return -1;
818  
819      return 0;
820  }
821  
822  static void
qemu_gps_cleanup(void)823  qemu_gps_cleanup(void)
824  {
825      GpsState*  s = _gps_state;
826  
827      if (s->init)
828          gps_state_done(s);
829  }
830  
831  
832  static int
qemu_gps_start()833  qemu_gps_start()
834  {
835      GpsState*  s = _gps_state;
836  
837      if (!s->init) {
838          D("%s: called with uninitialized state !!", __FUNCTION__);
839          return -1;
840      }
841  
842      D("%s: called", __FUNCTION__);
843      gps_state_start(s);
844      return 0;
845  }
846  
847  
848  static int
qemu_gps_stop()849  qemu_gps_stop()
850  {
851      GpsState*  s = _gps_state;
852  
853      if (!s->init) {
854          D("%s: called with uninitialized state !!", __FUNCTION__);
855          return -1;
856      }
857  
858      D("%s: called", __FUNCTION__);
859      gps_state_stop(s);
860      return 0;
861  }
862  
863  
864  static int
qemu_gps_inject_time(GpsUtcTime time,int64_t timeReference,int uncertainty)865  qemu_gps_inject_time(GpsUtcTime time, int64_t timeReference, int uncertainty)
866  {
867      return 0;
868  }
869  
870  static int
qemu_gps_inject_location(double latitude,double longitude,float accuracy)871  qemu_gps_inject_location(double latitude, double longitude, float accuracy)
872  {
873      return 0;
874  }
875  
876  static void
qemu_gps_delete_aiding_data(GpsAidingData flags)877  qemu_gps_delete_aiding_data(GpsAidingData flags)
878  {
879  }
880  
qemu_gps_set_position_mode(GpsPositionMode mode,int fix_frequency)881  static int qemu_gps_set_position_mode(GpsPositionMode mode, int fix_frequency)
882  {
883      // FIXME - support fix_frequency
884      return 0;
885  }
886  
887  static const void*
qemu_gps_get_extension(const char * name)888  qemu_gps_get_extension(const char* name)
889  {
890      // no extensions supported
891      return NULL;
892  }
893  
894  static const GpsInterface  qemuGpsInterface = {
895      sizeof(GpsInterface),
896      qemu_gps_init,
897      qemu_gps_start,
898      qemu_gps_stop,
899      qemu_gps_cleanup,
900      qemu_gps_inject_time,
901      qemu_gps_inject_location,
902      qemu_gps_delete_aiding_data,
903      qemu_gps_set_position_mode,
904      qemu_gps_get_extension,
905  };
906  
gps__get_gps_interface(struct gps_device_t * dev)907  const GpsInterface* gps__get_gps_interface(struct gps_device_t* dev)
908  {
909      return &qemuGpsInterface;
910  }
911  
open_gps(const struct hw_module_t * module,char const * name,struct hw_device_t ** device)912  static int open_gps(const struct hw_module_t* module, char const* name,
913          struct hw_device_t** device)
914  {
915      struct gps_device_t *dev = malloc(sizeof(struct gps_device_t));
916      memset(dev, 0, sizeof(*dev));
917  
918      dev->common.tag = HARDWARE_DEVICE_TAG;
919      dev->common.version = 0;
920      dev->common.module = (struct hw_module_t*)module;
921  //    dev->common.close = (int (*)(struct hw_device_t*))close_lights;
922      dev->get_gps_interface = gps__get_gps_interface;
923  
924      *device = (struct hw_device_t*)dev;
925      return 0;
926  }
927  
928  
929  static struct hw_module_methods_t gps_module_methods = {
930      .open = open_gps
931  };
932  
933  struct hw_module_t HAL_MODULE_INFO_SYM = {
934      .tag = HARDWARE_MODULE_TAG,
935      .version_major = 1,
936      .version_minor = 0,
937      .id = GPS_HARDWARE_MODULE_ID,
938      .name = "Goldfish GPS Module",
939      .author = "The Android Open Source Project",
940      .methods = &gps_module_methods,
941  };
942