int gps_opentty(GpsState *state) { DFR("%s", __FUNCTION__); if(strlen(prop) <= 0) { state->fd = -1; return state->fd; } if(state->fd != -1) gps_closetty(state); do { state->fd = open( prop, O_RDWR | O_NOCTTY | O_NONBLOCK); } while (state->fd < 0 && errno == EINTR); if (state->fd < 0) { char device[256]; // let's try add /dev/ to the property name as a last resort if ( snprintf(device, sizeof(device), "/dev/%s0", prop) >= (int)sizeof(device) ) { DFR("gps serial device name too long: '%s'", prop); return -1; } do { state->fd = open( device, O_RDWR | O_NOCTTY | O_NONBLOCK); } while (state->fd < 0 && errno == EINTR); if (state->fd < 0) { ALOGE("could not open gps serial device %s: %s", prop, strerror(errno) ); return -1; } } D("gps will read from %s", prop); // disable echo on serial lines if ( isatty( state->fd ) ) { struct termios ios; tcgetattr( state->fd, &ios ); bzero(&ios, sizeof(ios)); ios.c_cflag = B115200 | CS8 | CLOCAL | CREAD; ios.c_iflag = IGNPAR; ios.c_oflag = 0; ios.c_lflag = 0; /* disable ECHO, ICANON, etc... */ tcsetattr( state->fd, TCSANOW, &ios ); tcflush(state->fd,TCIOFLUSH); } epoll_register( epoll_nmeafd, state->fd ); return 0; }
/* this is the main thread, it waits for commands from gps_state_start/stop and, * when started, messages from the QEMU GPS daemon. these are simple NMEA sentences * that must be parsed to be converted into GPS fixes sent to the framework */ static void gps_state_thread( void* arg ) { GpsState* state = (GpsState*) arg; NmeaReader reader[1]; int epoll_fd = epoll_create(2); int started = 0; int gps_fd = state->fd; int control_fd = state->control[1]; nmea_reader_init( reader ); // register control file descriptors for polling epoll_register( epoll_fd, control_fd ); epoll_register( epoll_fd, gps_fd ); D("gps thread running"); // now loop for (;;) { struct epoll_event events[2]; int ne, nevents; nevents = epoll_wait( epoll_fd, events, 2, -1 ); if (nevents < 0) { if (errno != EINTR) LOGE("epoll_wait() unexpected error: %s", strerror(errno)); continue; } D("gps thread received %d events", nevents); for (ne = 0; ne < nevents; ne++) { if ((events[ne].events & (EPOLLERR|EPOLLHUP)) != 0) { LOGE("EPOLLERR or EPOLLHUP after epoll_wait() !?"); return; } if ((events[ne].events & EPOLLIN) != 0) { int fd = events[ne].data.fd; if (fd == control_fd) { char cmd = 255; int ret; D("gps control fd event"); do { ret = read( fd, &cmd, 1 ); } while (ret < 0 && errno == EINTR); if (cmd == CMD_QUIT) { D("gps thread quitting on demand"); return; } else if (cmd == CMD_START) { if (!started) { D("gps thread starting location_cb=%p", state->callbacks.location_cb); started = 1; nmea_reader_set_callback( reader, state->callbacks.location_cb ); state->init = 1; /*char testbuf[100]; int nn; sprintf(testbuf,"%s",GPS_TestData); for (nn = 0; nn < strlen(testbuf); nn++) { nmea_reader_addc( reader, testbuf[nn]); }*/ } } else if (cmd == CMD_STOP) { if (started) { D("gps thread stopping"); started = 0; nmea_reader_set_callback( reader, NULL ); } } } else if (fd == gps_fd) { char buff[32]; D("gps fd event"); for (;;) { int nn, ret; ret = read( fd, buff, sizeof(buff) ); if (ret < 0) { if (errno == EINTR) continue; if (errno != EWOULDBLOCK) LOGE("error while reading from gps daemon socket: %s:", strerror(errno)); break; } D("received %d bytes: %.*s", ret, ret, buff); for (nn = 0; nn < ret; nn++) nmea_reader_addc( reader, buff[nn] ); } D("gps fd event end"); } else { LOGE("epoll_wait() returned unkown fd %d ?", fd); } } } } }
static void gps_state_thread( void* arg ) { GpsState* state = (GpsState*) arg; int gps_fd = state->fd; int control_fd = state->control[1]; epoll_ctrlfd = epoll_create(1); epoll_nmeafd = epoll_create(1); // register control file descriptors for polling epoll_register( epoll_ctrlfd, control_fd ); D("gps thread running"); state->tmr_thread = state->callbacks.create_thread_cb("athr_gps_tmr", gps_timer_thread, state); if (!state->tmr_thread) { ALOGE("could not create gps timer thread: %s", strerror(errno)); started = 0; state->init = STATE_INIT; goto Exit; } state->nmea_thread = state->callbacks.create_thread_cb("athr_nmea_thread", gps_nmea_thread, state); if (!state->nmea_thread) { ALOGE("could not create gps nmea thread: %s", strerror(errno)); started = 0; state->init = STATE_INIT; goto Exit; } started = 0; state->init = STATE_INIT; // now loop for (;;) { struct epoll_event events[1]; int ne, nevents; nevents = epoll_wait( epoll_ctrlfd, events, 1, -1 ); if (nevents < 0) { if (errno != EINTR) ALOGE("epoll_wait() unexpected error: %s", strerror(errno)); continue; } // D("gps thread received %d events", nevents); for (ne = 0; ne < nevents; ne++) { if ((events[ne].events & (EPOLLERR|EPOLLHUP)) != 0) { ALOGE("EPOLLERR or EPOLLHUP after epoll_wait() !?"); goto Exit; } if ((events[ne].events & EPOLLIN) != 0) { int fd = events[ne].data.fd; if (fd == control_fd) { char cmd = 255; int ret; D("gps control fd event"); do { ret = read( fd, &cmd, 1 ); } while (ret < 0 && errno == EINTR); if (cmd == CMD_QUIT) { D("gps thread quitting on demand"); goto Exit; } else if (cmd == CMD_START) { if (!started) { NmeaReader *reader; reader = &state->reader; nmea_reader_init( reader ); D("gps thread starting location_cb=%p", state->callbacks.location_cb); started = 1; state->init = STATE_START; /* handle wakeup routine*/ gps_wakeup(state); } else D("LM already start"); } else if (cmd == CMD_STOP) { if (started) { state->init = STATE_INIT; } } } else { ALOGE("epoll_wait() returned unkown fd %d ?", fd); gps_fd = _gps_state->fd; //resign fd to gps_fd } } } } Exit: { void *dummy; continue_thread = 0; close(epoll_ctrlfd); close(epoll_nmeafd); pthread_join(state->tmr_thread, &dummy); pthread_join(state->nmea_thread, &dummy); DFR("gps control thread destroyed"); } return; }