2 ** Copyright 2006, The Android Open Source Project
3 ** Copyright 2009, Michael Trimarchi <michael@panicking.kicks-ass.org>
4 ** Copyright 2015, Keith Conger <keith.conger@gmail.com>
6 ** This program is free software; you can redistribute it and/or modify it under
7 ** the terms of the GNU General Public License as published by the Free
8 ** Software Foundation; either version 2, or (at your option) any later
11 ** This program is distributed in the hope that it will be useful, but WITHOUT
12 ** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 ** FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 ** You should have received a copy of the GNU General Public License along with
17 ** this program; if not, write to the Free Software Foundation, Inc., 59
18 ** Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 #include <sys/epoll.h>
31 #define LOG_TAG "gps_serial"
33 #include <cutils/log.h>
34 #include <cutils/sockets.h>
35 #include <cutils/properties.h>
36 #include <hardware/gps.h>
38 /* this is the state of our connection to the qemu_gpsd daemon */
42 GpsCallbacks *callbacks;
48 static GpsState _gps_state[1];
49 static int id_in_fixed[12];
51 #define DFR(...) ALOGD(__VA_ARGS__)
54 # define D(...) ALOGD(__VA_ARGS__)
56 # define D(...) ((void)0)
59 #define GPS_DEV_SLOW_UPDATE_RATE (10)
60 #define GPS_DEV_HIGH_UPDATE_RATE (1)
62 /*****************************************************************/
63 /*****************************************************************/
65 /***** N M E A T O K E N I Z E R *****/
67 /*****************************************************************/
68 /*****************************************************************/
70 #define MAX_NMEA_TOKENS 32
80 Token tokens[ MAX_NMEA_TOKENS ];
85 nmea_tokenizer_init( NmeaTokenizer* t, const char* p, const char* end )
90 // the initial '$' is optional
91 if (p < end && p[0] == '$')
94 // remove trailing newline
95 if (end > p && end[-1] == '\n') {
97 if (end > p && end[-1] == '\r')
101 // get rid of checksum at the end of the sentence
102 if (end >= p+3 && end[-3] == '*') {
109 q = memchr(p, ',', end-p);
113 if (count < MAX_NMEA_TOKENS) {
114 t->tokens[count].p = p;
115 t->tokens[count].end = q;
130 nmea_tokenizer_get( NmeaTokenizer* t, int index )
134 if (index < 0 || index >= t->count || index >= MAX_NMEA_TOKENS)
135 tok.p = tok.end = "";
137 tok = t->tokens[index];
144 str2int( const char* p, const char* end )
149 for ( ; len > 0; len--, p++ ) {
156 if ((unsigned)c >= 10)
159 result = result*10 + c;
169 str2float( const char* p, const char* end )
171 size_t len = end - p;
174 if (len >= sizeof(temp))
177 memcpy( temp, p, len );
179 return strtod( temp, NULL );
183 /*****************************************************************/
184 /*****************************************************************/
186 /***** N M E A P A R S E R *****/
188 /*****************************************************************/
189 /*****************************************************************/
191 #define NMEA_MAX_SIZE 255
201 GpsSvStatus sv_status;
202 gps_location_callback callback;
203 char in[ NMEA_MAX_SIZE+1 ];
207 void update_gps_status(GpsStatusValue val)
209 GpsState* state = _gps_state;
210 //Should be made thread safe...
211 state->status.status=val;
212 if (state->callbacks->status_cb)
213 state->callbacks->status_cb(&state->status);
217 void update_gps_svstatus(GpsSvStatus *val)
219 GpsState* state = _gps_state;
220 //Should be made thread safe...
221 if (state->callbacks->sv_status_cb)
222 state->callbacks->sv_status_cb(val);
226 void update_gps_location(GpsLocation *fix)
228 GpsState* state = _gps_state;
229 //Should be made thread safe...
230 if (state->callbacks->location_cb)
231 state->callbacks->location_cb(fix);
236 nmea_reader_update_utc_diff( NmeaReader* r )
238 time_t now = time(NULL);
241 long time_local, time_utc;
243 gmtime_r( &now, &tm_utc );
244 localtime_r( &now, &tm_local );
246 time_local = tm_local.tm_sec +
247 60*(tm_local.tm_min +
248 60*(tm_local.tm_hour +
249 24*(tm_local.tm_yday +
250 365*tm_local.tm_year)));
252 time_utc = tm_utc.tm_sec +
256 365*tm_utc.tm_year)));
258 r->utc_diff = time_utc - time_local;
263 nmea_reader_init( NmeaReader* r )
265 memset( r, 0, sizeof(*r) );
273 r->fix.size = sizeof(r->fix);
275 nmea_reader_update_utc_diff( r );
280 nmea_reader_update_time( NmeaReader* r, Token tok )
287 if (tok.p + 6 > tok.end)
290 if (r->utc_year < 0) {
291 // no date yet, get current one
292 time_t now = time(NULL);
293 gmtime_r( &now, &tm );
294 r->utc_year = tm.tm_year + 1900;
295 r->utc_mon = tm.tm_mon + 1;
296 r->utc_day = tm.tm_mday;
299 hour = str2int(tok.p, tok.p+2);
300 minute = str2int(tok.p+2, tok.p+4);
301 seconds = str2float(tok.p+4, tok.end);
305 tm.tm_sec = (int) seconds;
306 tm.tm_year = r->utc_year - 1900;
307 tm.tm_mon = r->utc_mon - 1;
308 tm.tm_mday = r->utc_day;
311 fix_time = mktime( &tm ) + r->utc_diff;
312 r->fix.timestamp = (long long)fix_time * 1000;
318 nmea_reader_update_date( NmeaReader* r, Token date, Token time )
323 if (tok.p + 6 != tok.end) {
324 D("Date not properly formatted: '%.*s'", tok.end-tok.p, tok.p);
327 day = str2int(tok.p, tok.p+2);
328 mon = str2int(tok.p+2, tok.p+4);
329 year = str2int(tok.p+4, tok.p+6) + 2000;
331 if ((day|mon|year) < 0) {
332 D("Date not properly formatted: '%.*s'", tok.end-tok.p, tok.p);
340 return nmea_reader_update_time( r, time );
345 convert_from_hhmm( Token tok )
347 double val = str2float(tok.p, tok.end);
348 int degrees = (int)(floor(val) / 100);
349 double minutes = val - degrees*100.;
350 double dcoord = degrees + minutes / 60.0;
356 nmea_reader_update_latlong( NmeaReader* r,
366 if (tok.p + 6 > tok.end) {
367 D("Latitude is too short: '%.*s'", tok.end-tok.p, tok.p);
370 lat = convert_from_hhmm(tok);
371 if (latitudeHemi == 'S')
375 if (tok.p + 6 > tok.end) {
376 D("Longitude is too short: '%.*s'", tok.end-tok.p, tok.p);
379 lon = convert_from_hhmm(tok);
380 if (longitudeHemi == 'W')
383 r->fix.flags |= GPS_LOCATION_HAS_LAT_LONG;
384 r->fix.latitude = lat;
385 r->fix.longitude = lon;
391 nmea_reader_update_altitude( NmeaReader* r,
396 Token tok = altitude;
398 if (tok.p >= tok.end)
401 r->fix.flags |= GPS_LOCATION_HAS_ALTITUDE;
402 r->fix.altitude = str2float(tok.p, tok.end);
407 static int nmea_reader_update_accuracy( NmeaReader* r,
411 Token tok = accuracy;
413 if (tok.p >= tok.end)
416 r->fix.accuracy = str2float(tok.p, tok.end);
417 if (r->fix.accuracy == 99.99){
421 r->fix.flags |= GPS_LOCATION_HAS_ACCURACY;
427 nmea_reader_update_bearing( NmeaReader* r,
433 if (tok.p >= tok.end)
436 r->fix.flags |= GPS_LOCATION_HAS_BEARING;
437 r->fix.bearing = str2float(tok.p, tok.end);
443 nmea_reader_update_speed( NmeaReader* r,
449 if (tok.p >= tok.end)
452 r->fix.flags |= GPS_LOCATION_HAS_SPEED;
453 r->fix.speed = str2float(tok.p, tok.end) * 1.852 / 3.6;
459 nmea_reader_update_svs( NmeaReader* r, int inview, int num, int i, Token prn, Token elevation, Token azimuth, Token snr )
465 r->sv_status.sv_list[i].prn=str2int(prn.p,prn.end);
466 r->sv_status.sv_list[i].elevation=str2int(elevation.p,elevation.end);
467 r->sv_status.sv_list[i].azimuth=str2int(azimuth.p,azimuth.end);
468 r->sv_status.sv_list[i].snr=str2int(snr.p,snr.end);
470 if (id_in_fixed[o]==str2int(prn.p,prn.end)){
471 prnid = str2int(prn.p, prn.end);
472 r->sv_status.used_in_fix_mask |= (1ul << (prnid-1));
481 nmea_reader_parse( NmeaReader* r )
483 /* we received a complete sentence, now parse it to generate
486 NmeaTokenizer tzer[1];
490 D("Received: '%.*s'", r->pos, r->in);
492 D("Too short. discarded.");
496 gettimeofday(&tv, NULL);
497 if (_gps_state->init)
498 _gps_state->callbacks->nmea_cb(tv.tv_sec*1000+tv.tv_usec/1000, r->in, r->pos);
500 nmea_tokenizer_init(tzer, r->in, r->in + r->pos);
504 D("Found %d tokens", tzer->count);
505 for (n = 0; n < tzer->count; n++) {
506 Token tok = nmea_tokenizer_get(tzer,n);
507 D("%2d: '%.*s'", n, tok.end-tok.p, tok.p);
512 tok = nmea_tokenizer_get(tzer, 0);
513 if (tok.p + 5 > tok.end) {
514 D("Sentence id '%.*s' too short, ignored.", tok.end-tok.p, tok.p);
517 // ignore first two characters.
519 if ( !memcmp(tok.p, "GGA", 3) ) {
521 Token tok_time = nmea_tokenizer_get(tzer,1);
522 Token tok_latitude = nmea_tokenizer_get(tzer,2);
523 Token tok_latitudeHemi = nmea_tokenizer_get(tzer,3);
524 Token tok_longitude = nmea_tokenizer_get(tzer,4);
525 Token tok_longitudeHemi = nmea_tokenizer_get(tzer,5);
526 Token tok_accuracy = nmea_tokenizer_get(tzer,8);
527 Token tok_altitude = nmea_tokenizer_get(tzer,9);
528 Token tok_altitudeUnits = nmea_tokenizer_get(tzer,10);
530 nmea_reader_update_time(r, tok_time);
531 nmea_reader_update_latlong(r, tok_latitude,
532 tok_latitudeHemi.p[0],
534 tok_longitudeHemi.p[0]);
535 nmea_reader_update_altitude(r, tok_altitude, tok_altitudeUnits);
537 nmea_reader_update_accuracy(r, tok_accuracy);
539 } else if ( !memcmp(tok.p, "GSA", 3) ) {
542 M=Manual, forced to operate in 2D or 3D
548 3-14 = IDs of SVs used in position fix (null for unused fields)
553 Token tok_mode = nmea_tokenizer_get(tzer,1);
554 Token tok_fix = nmea_tokenizer_get(tzer,2);
555 Token tok_id = nmea_tokenizer_get(tzer,3);
556 Token tok_pdop = nmea_tokenizer_get(tzer,15);
557 Token tok_hdop = nmea_tokenizer_get(tzer,16);
558 Token tok_vdop = nmea_tokenizer_get(tzer,17);
560 nmea_reader_update_accuracy(r, tok_hdop);
563 for ( i=0; i<12; i++ ) {
564 Token tok_id = nmea_tokenizer_get(tzer,3+i);
565 if ( tok_id.end > tok_id.p ){
566 id_in_fixed[i]=str2int(tok_id.p,tok_id.end);
567 D("Satellite used '%.*s'", tok_id.end-tok_id.p, tok_id.p);
570 } else if ( !memcmp(tok.p, "GSV", 3) ) {
572 1 = Total number of messages of this type in this cycle
574 3 = Total number of SVs in view
576 5 = Elevation in degrees, 90 maximum
577 6 = Azimuth, degrees from true north, 000 to 359
578 7 = SNR, 00-99 dB (null when not tracking)
579 8-11 = Information about second SV, same as field 4-7
580 12-15= Information about third SV, same as field 4-7
581 16-19= Information about fourth SV, same as field 4-7
584 //Satellites are handled by RPC-side code.
585 Token tok_num_messages = nmea_tokenizer_get(tzer,1);
586 Token tok_msg_number = nmea_tokenizer_get(tzer,2);
587 Token tok_svs_inview = nmea_tokenizer_get(tzer,3);
588 Token tok_sv1_prn_num = nmea_tokenizer_get(tzer,4);
589 Token tok_sv1_elevation = nmea_tokenizer_get(tzer,5);
590 Token tok_sv1_azimuth = nmea_tokenizer_get(tzer,6);
591 Token tok_sv1_snr = nmea_tokenizer_get(tzer,7);
592 Token tok_sv2_prn_num = nmea_tokenizer_get(tzer,8);
593 Token tok_sv2_elevation = nmea_tokenizer_get(tzer,9);
594 Token tok_sv2_azimuth = nmea_tokenizer_get(tzer,10);
595 Token tok_sv2_snr = nmea_tokenizer_get(tzer,11);
596 Token tok_sv3_prn_num = nmea_tokenizer_get(tzer,12);
597 Token tok_sv3_elevation = nmea_tokenizer_get(tzer,13);
598 Token tok_sv3_azimuth = nmea_tokenizer_get(tzer,14);
599 Token tok_sv3_snr = nmea_tokenizer_get(tzer,15);
600 Token tok_sv4_prn_num = nmea_tokenizer_get(tzer,16);
601 Token tok_sv4_elevation = nmea_tokenizer_get(tzer,17);
602 Token tok_sv4_azimuth = nmea_tokenizer_get(tzer,18);
603 Token tok_sv4_snr = nmea_tokenizer_get(tzer,19);
604 int num_messages = str2int(tok_num_messages.p,tok_num_messages.end);
605 int msg_number = str2int(tok_msg_number.p,tok_msg_number.end);
606 int svs_inview = str2int(tok_svs_inview.p,tok_svs_inview.end);
607 D("GSV %d %d %d", num_messages, msg_number, svs_inview );
609 r->sv_status.used_in_fix_mask = 0ul;
612 nmea_reader_update_svs( r, svs_inview, msg_number, 0, tok_sv1_prn_num, tok_sv1_elevation, tok_sv1_azimuth, tok_sv1_snr );
613 nmea_reader_update_svs( r, svs_inview, msg_number, 1, tok_sv2_prn_num, tok_sv2_elevation, tok_sv2_azimuth, tok_sv2_snr );
614 nmea_reader_update_svs( r, svs_inview, msg_number, 2, tok_sv3_prn_num, tok_sv3_elevation, tok_sv3_azimuth, tok_sv3_snr );
615 nmea_reader_update_svs( r, svs_inview, msg_number, 3, tok_sv4_prn_num, tok_sv4_elevation, tok_sv4_azimuth, tok_sv4_snr );
616 r->sv_status.num_svs=svs_inview;
618 if (num_messages==msg_number)
619 update_gps_svstatus(&r->sv_status);
621 } else if ( !memcmp(tok.p, "RMC", 3) ) {
622 Token tok_time = nmea_tokenizer_get(tzer,1);
623 Token tok_fixStatus = nmea_tokenizer_get(tzer,2);
624 Token tok_latitude = nmea_tokenizer_get(tzer,3);
625 Token tok_latitudeHemi = nmea_tokenizer_get(tzer,4);
626 Token tok_longitude = nmea_tokenizer_get(tzer,5);
627 Token tok_longitudeHemi = nmea_tokenizer_get(tzer,6);
628 Token tok_speed = nmea_tokenizer_get(tzer,7);
629 Token tok_bearing = nmea_tokenizer_get(tzer,8);
630 Token tok_date = nmea_tokenizer_get(tzer,9);
632 D("in RMC, fixStatus=%c", tok_fixStatus.p[0]);
633 if (tok_fixStatus.p[0] == 'A') {
634 nmea_reader_update_date( r, tok_date, tok_time );
636 nmea_reader_update_latlong( r, tok_latitude,
637 tok_latitudeHemi.p[0],
639 tok_longitudeHemi.p[0] );
641 nmea_reader_update_bearing( r, tok_bearing );
642 nmea_reader_update_speed ( r, tok_speed );
644 } else if ( !memcmp(tok.p, "VTG", 3) ) {
645 Token tok_fixStatus = nmea_tokenizer_get(tzer,9);
647 if (tok_fixStatus.p[0] != '\0' && tok_fixStatus.p[0] != 'N') {
648 Token tok_bearing = nmea_tokenizer_get(tzer,1);
649 Token tok_speed = nmea_tokenizer_get(tzer,5);
651 nmea_reader_update_bearing( r, tok_bearing );
652 nmea_reader_update_speed ( r, tok_speed );
656 D("Unknown sentence '%.*s", tok.end-tok.p, tok.p);
664 char* end = p + sizeof(temp);
667 p += snprintf( p, end-p, "Sending fix" );
668 if (r->fix.flags & GPS_LOCATION_HAS_LAT_LONG) {
669 p += snprintf(p, end-p, " lat=%g lon=%g", r->fix.latitude, r->fix.longitude);
671 if (r->fix.flags & GPS_LOCATION_HAS_ALTITUDE) {
672 p += snprintf(p, end-p, " altitude=%g", r->fix.altitude);
674 if (r->fix.flags & GPS_LOCATION_HAS_SPEED) {
675 p += snprintf(p, end-p, " speed=%g", r->fix.speed);
677 if (r->fix.flags & GPS_LOCATION_HAS_BEARING) {
678 p += snprintf(p, end-p, " bearing=%g", r->fix.bearing);
680 if (r->fix.flags & GPS_LOCATION_HAS_ACCURACY) {
681 p += snprintf(p,end-p, " accuracy=%g", r->fix.accuracy);
683 gmtime_r( (time_t*) &r->fix.timestamp, &utc );
684 p += snprintf(p, end-p, " time=%s", asctime( &utc ) );
688 if (r->fix.flags & GPS_LOCATION_HAS_ACCURACY) {
689 if (_gps_state->callbacks->location_cb) {
690 _gps_state->callbacks->location_cb( &r->fix );
693 D("No callback, keeping data until needed !");
700 nmea_reader_addc( NmeaReader* r, int c )
703 r->overflow = (c != '\n');
707 if (r->pos >= (int) sizeof(r->in)-1 ) {
713 r->in[r->pos] = (char)c;
717 nmea_reader_parse( r );
723 /*****************************************************************/
724 /*****************************************************************/
726 /***** C O N N E C T I O N S T A T E *****/
728 /*****************************************************************/
729 /*****************************************************************/
731 /* commands sent to the gps thread */
740 gps_state_done( GpsState* s )
742 // tell the thread to quit, and wait for it
745 write( s->control[0], &cmd, 1 );
746 pthread_join(s->thread, &dummy);
748 // close the control socket pair
749 close( s->control[0] ); s->control[0] = -1;
750 close( s->control[1] ); s->control[1] = -1;
752 // close connection to the QEMU GPS daemon
753 close( s->fd ); s->fd = -1;
759 gps_state_start( GpsState* s )
761 char cmd = CMD_START;
765 ret = write( s->control[0], &cmd, 1 );
766 } while (ret < 0 && errno == EINTR);
769 D("%s: could not send CMD_START command: ret=%d: %s",
770 __FUNCTION__, ret, strerror(errno));
775 gps_state_stop( GpsState* s )
780 do { ret=write( s->control[0], &cmd, 1 ); }
781 while (ret < 0 && errno == EINTR);
784 D("%s: could not send CMD_STOP command: ret=%d: %s",
785 __FUNCTION__, ret, strerror(errno));
790 epoll_register( int epoll_fd, int fd )
792 struct epoll_event ev;
795 /* important: make the fd non-blocking */
796 flags = fcntl(fd, F_GETFL);
797 fcntl(fd, F_SETFL, flags | O_NONBLOCK);
802 ret = epoll_ctl( epoll_fd, EPOLL_CTL_ADD, fd, &ev );
803 } while (ret < 0 && errno == EINTR);
808 /* this is the main thread, it waits for commands from gps_state_start/stop and,
809 * when started, messages from the QEMU GPS daemon. these are simple NMEA sentences
810 * that must be parsed to be converted into GPS fixes sent to the framework
813 gps_state_thread( void* arg )
815 GpsState* state = (GpsState*) arg;
816 NmeaReader reader[1];
817 int epoll_fd = epoll_create(2);
819 int gps_fd = state->fd;
820 int control_fd = state->control[1];
822 nmea_reader_init( reader );
824 // register control file descriptors for polling
825 epoll_register( epoll_fd, control_fd );
826 epoll_register( epoll_fd, gps_fd );
828 D("GPS thread running");
832 struct epoll_event events[2];
835 nevents = epoll_wait( epoll_fd, events, 2, -1 );
838 ALOGE("epoll_wait() unexpected error: %s", strerror(errno));
841 for (ne = 0; ne < nevents; ne++) {
842 if ((events[ne].events & (EPOLLERR|EPOLLHUP)) != 0) {
843 ALOGE("EPOLLERR or EPOLLHUP after epoll_wait() !?");
846 if ((events[ne].events & EPOLLIN) != 0) {
847 int fd = events[ne].data.fd;
849 if (fd == control_fd) {
852 D("GPS control fd event");
854 ret = read( fd, &cmd, 1 );
855 } while (ret < 0 && errno == EINTR);
857 if (cmd == CMD_QUIT) {
858 D("GPS thread quitting on demand");
860 } else if (cmd == CMD_START) {
862 D("GPS thread starting location_cb=%p", state->callbacks->location_cb);
864 update_gps_status(GPS_STATUS_SESSION_BEGIN);
866 } else if (cmd == CMD_STOP) {
868 D("GPS thread stopping");
870 update_gps_status(GPS_STATUS_SESSION_END);
873 } else if (fd == gps_fd) {
878 ret = read( fd, buff, sizeof(buff) );
882 if (errno != EWOULDBLOCK)
883 ALOGE("Error while reading from GPS daemon socket: %s:", strerror(errno));
886 for (nn = 0; nn < ret; nn++)
887 nmea_reader_addc( reader, buff[nn] );
890 ALOGE("epoll_wait() returned unkown fd %d ?", fd);
899 gps_state_init( GpsState* state, GpsCallbacks* callbacks )
901 char prop[PROPERTY_VALUE_MAX];
902 char baud[PROPERTY_VALUE_MAX];
907 struct sigevent tmr_event;
910 state->control[0] = -1;
911 state->control[1] = -1;
913 state->callbacks = callbacks;
916 // Look for a kernel-provided device name
917 if (property_get("ro.kernel.android.gps",prop,"") == 0) {
918 D("no kernel-provided gps device name");
922 snprintf(device, sizeof(device), "/dev/%s",prop);
924 state->fd = open( device, O_RDWR );
925 } while (state->fd < 0 && errno == EINTR);
928 ALOGE("could not open gps serial device %s: %s", device, strerror(errno) );
932 D("GPS will read from %s", device);
934 // Disable echo on serial lines
935 if ( isatty( state->fd ) ) {
937 tcgetattr( state->fd, &ios );
938 ios.c_lflag = 0; /* disable ECHO, ICANON, etc... */
939 ios.c_oflag &= (~ONLCR); /* Stop \n -> \r\n translation on output */
940 ios.c_iflag &= (~(ICRNL | INLCR)); /* Stop \r -> \n & \n -> \r translation on input */
941 ios.c_iflag |= (IGNCR | IXOFF); /* Ignore \r & XON/XOFF on input */
942 // Set baud rate and other flags
943 property_get("ro.kernel.android.gpsttybaud",baud,"9600");
944 if (strcmp(baud, "4800") == 0) {
945 ALOGE("Setting gps baud rate to 4800");
946 ios.c_cflag = B4800 | CRTSCTS | CS8 | CLOCAL | CREAD;
947 } else if (strcmp(baud, "9600") == 0) {
948 ALOGE("Setting gps baud rate to 9600");
949 ios.c_cflag = B9600 | CRTSCTS | CS8 | CLOCAL | CREAD;
950 } else if (strcmp(baud, "19200") == 0) {
951 ALOGE("Setting gps baud rate to 19200");
952 ios.c_cflag = B19200 | CRTSCTS | CS8 | CLOCAL | CREAD;
953 } else if (strcmp(baud, "38400") == 0) {
954 ALOGE("Setting gps baud rate to 38400");
955 ios.c_cflag = B38400 | CRTSCTS | CS8 | CLOCAL | CREAD;
956 } else if (strcmp(baud, "57600") == 0) {
957 ALOGE("Setting gps baud rate to 57600");
958 ios.c_cflag = B57600 | CRTSCTS | CS8 | CLOCAL | CREAD;
959 } else if (strcmp(baud, "115200") == 0) {
960 ALOGE("Setting gps baud rate to 115200");
961 ios.c_cflag = B115200 | CRTSCTS | CS8 | CLOCAL | CREAD;
963 ALOGE("GPS baud rate unknown: '%s'", baud);
967 tcsetattr( state->fd, TCSANOW, &ios );
970 if ( socketpair( AF_LOCAL, SOCK_STREAM, 0, state->control ) < 0 ) {
971 ALOGE("Could not create thread control socket pair: %s", strerror(errno));
975 state->thread = callbacks->create_thread_cb( "gps_state_thread", gps_state_thread, state );
977 if ( !state->thread ) {
978 ALOGE("Could not create GPS thread: %s", strerror(errno));
982 D("GPS state initialized");
987 gps_state_done( state );
991 /*****************************************************************/
992 /*****************************************************************/
994 /***** I N T E R F A C E *****/
996 /*****************************************************************/
997 /*****************************************************************/
1000 serial_gps_init(GpsCallbacks* callbacks)
1002 D("serial_gps_init");
1003 GpsState* s = _gps_state;
1006 gps_state_init(s, callbacks);
1016 serial_gps_cleanup(void)
1018 GpsState* s = _gps_state;
1028 GpsState* s = _gps_state;
1031 DFR("%s: called with uninitialized state !!", __FUNCTION__);
1035 D("%s: called", __FUNCTION__);
1044 GpsState* s = _gps_state;
1047 DFR("%s: called with uninitialized state !!", __FUNCTION__);
1051 D("%s: called", __FUNCTION__);
1058 serial_gps_inject_time(GpsUtcTime time, int64_t timeReference, int uncertainty)
1065 serial_gps_inject_location(double latitude, double longitude, float accuracy)
1071 serial_gps_delete_aiding_data(GpsAidingData flags)
1075 static int serial_gps_set_position_mode(GpsPositionMode mode, GpsPositionRecurrence recurrence,
1076 uint32_t min_interval, uint32_t preferred_accuracy, uint32_t preferred_time)
1078 GpsState* s = _gps_state;
1081 D("%s: called with uninitialized state !!", __FUNCTION__);
1085 D("set_position_mode: mode=%d recurrence=%d min_interval=%d preferred_accuracy=%d preferred_time=%d",
1086 mode, recurrence, min_interval, preferred_accuracy, preferred_time);
1093 serial_gps_get_extension(const char* name)
1099 static const GpsInterface serialGpsInterface = {
1100 sizeof(GpsInterface),
1105 serial_gps_inject_time,
1106 serial_gps_inject_location,
1107 serial_gps_delete_aiding_data,
1108 serial_gps_set_position_mode,
1109 serial_gps_get_extension,
1113 const GpsInterface* gps_get_hardware_interface()
1115 D("GPS dev get_hardware_interface");
1116 return &serialGpsInterface;
1120 /*****************************************************************/
1121 /*****************************************************************/
1123 /***** D E V I C E *****/
1125 /*****************************************************************/
1126 /*****************************************************************/
1129 static int open_gps(const struct hw_module_t* module, char const* name, struct hw_device_t** device)
1131 D("GPS dev open_gps");
1132 struct gps_device_t *dev = malloc(sizeof(struct gps_device_t));
1133 memset(dev, 0, sizeof(*dev));
1135 dev->common.tag = HARDWARE_DEVICE_TAG;
1136 dev->common.version = 0;
1137 dev->common.module = (struct hw_module_t*)module;
1138 dev->get_gps_interface = gps_get_hardware_interface;
1140 *device = &dev->common;
1145 static struct hw_module_methods_t gps_module_methods = {
1150 struct hw_module_t HAL_MODULE_INFO_SYM = {
1151 .tag = HARDWARE_MODULE_TAG,
1154 .id = GPS_HARDWARE_MODULE_ID,
1155 .name = "Serial GPS Module",
1156 .author = "Keith Conger",
1157 .methods = &gps_module_methods,