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