1 /* 2 * Copyright (C) 2017 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 #include "guest/hals/gps/gps_thread.h" 17 18 #include <errno.h> 19 #include <fcntl.h> 20 #include <math.h> 21 #include <pthread.h> 22 #include <sys/epoll.h> 23 #include <time.h> 24 #include <unistd.h> 25 26 #include <cutils/log.h> 27 #include <cutils/sockets.h> 28 #include <hardware/gps.h> 29 30 // Calls an callback function to pass received and parsed GPS data to Android. 31 static void reader_call_callback(GpsDataReader* r) { 32 if (!r) { 33 ALOGW("%s: called with r=NULL", __FUNCTION__); 34 return; 35 } 36 if (!r->callback) { 37 ALOGW("%s: no callback registered; keeping the data to send later", 38 __FUNCTION__); 39 return; 40 } 41 if (!r->fix.flags) { 42 ALOGW("%s: no GPS fix", __FUNCTION__); 43 return; 44 } 45 // Always uses current time converted to UTC time in milliseconds. 46 time_t secs = time(NULL); // seconds from 01/01/1970. 47 r->fix.timestamp = (long long)secs * 1000; 48 49 #if GPS_DEBUG 50 D("* Parsed GPS Data"); 51 if (r->fix.flags & GPS_LOCATION_HAS_LAT_LONG) { 52 D(" - latitude = %g", r->fix.latitude); 53 D(" - longitude = %g", r->fix.longitude); 54 } 55 if (r->fix.flags & GPS_LOCATION_HAS_ALTITUDE) 56 D(" - altitude = %g", r->fix.altitude); 57 if (r->fix.flags & GPS_LOCATION_HAS_SPEED) D(" - speed = %g", r->fix.speed); 58 if (r->fix.flags & GPS_LOCATION_HAS_BEARING) 59 D(" - bearing = %g", r->fix.bearing); 60 if (r->fix.flags & GPS_LOCATION_HAS_ACCURACY) 61 D(" - accuracy = %g", r->fix.accuracy); 62 long long utc_secs = r->fix.timestamp / 1000; 63 struct tm utc; 64 gmtime_r((time_t*)&utc_secs, &utc); 65 D(" - time = %s", asctime(&utc)); 66 #endif 67 68 D("Sending fix to callback %p", r->callback); 69 r->callback(&r->fix); 70 } 71 72 // Parses data received so far and calls reader_call_callback(). 73 static void reader_parse_message(GpsDataReader* r) { 74 D("Received: '%s'", r->buffer); 75 76 int num_read = sscanf(r->buffer, "%lf,%lf,%lf,%f,%f,%f", &r->fix.longitude, 77 &r->fix.latitude, &r->fix.altitude, &r->fix.bearing, 78 &r->fix.speed, &r->fix.accuracy); 79 if (num_read != 6) { 80 ALOGE("Couldn't find 6 values from the received message %s.", r->buffer); 81 return; 82 } 83 r->fix.flags = DEFAULT_GPS_LOCATION_FLAG; 84 reader_call_callback(r); 85 } 86 87 // Accepts a newly received string & calls reader_parse_message if '\n' is seen. 88 static void reader_accept_string(GpsDataReader* r, char* const str, 89 const int len) { 90 int index; 91 for (index = 0; index < len; index++) { 92 if (r->index >= (int)sizeof(r->buffer) - 1) { 93 if (str[index] == '\n') { 94 ALOGW("Message longer than buffer; new byte (%d) skipped.", str[index]); 95 r->index = 0; 96 } 97 } else { 98 r->buffer[r->index++] = str[index]; 99 if (str[index] == '\n') { 100 r->buffer[r->index] = '\0'; 101 reader_parse_message(r); 102 r->index = 0; 103 } 104 } 105 } 106 } 107 108 // GPS state threads which communicates with control and data sockets. 109 void gps_state_thread(void* arg) { 110 GpsState* state = (GpsState*)arg; 111 GpsDataReader reader; 112 int epoll_fd = epoll_create(2); 113 int started = -1; 114 int gps_fd = state->fd; 115 int control_fd = state->control[1]; 116 117 memset(&reader, 0, sizeof(reader)); 118 reader.fix.size = sizeof(reader.fix); 119 120 epoll_register(epoll_fd, control_fd); 121 epoll_register(epoll_fd, gps_fd); 122 123 while (1) { 124 struct epoll_event events[2]; 125 int nevents, event_index; 126 127 nevents = epoll_wait(epoll_fd, events, 2, 500); 128 D("Thread received %d events", nevents); 129 if (nevents < 0) { 130 if (errno != EINTR) 131 ALOGE("epoll_wait() unexpected error: %s", strerror(errno)); 132 continue; 133 } else if (nevents == 0) { 134 if (started == 1) { 135 reader_call_callback(&reader); 136 } 137 continue; 138 } 139 140 for (event_index = 0; event_index < nevents; event_index++) { 141 if ((events[event_index].events & (EPOLLERR | EPOLLHUP)) != 0) { 142 ALOGE("EPOLLERR or EPOLLHUP after epoll_wait() !?"); 143 goto Exit; 144 } 145 146 if ((events[event_index].events & EPOLLIN) != 0) { 147 int fd = events[event_index].data.fd; 148 if (fd == control_fd) { 149 unsigned char cmd = 255; 150 int ret; 151 do { 152 ret = read(fd, &cmd, 1); 153 } while (ret < 0 && errno == EINTR); 154 155 if (cmd == CMD_STOP || cmd == CMD_QUIT) { 156 if (started == 1) { 157 D("Thread stopping"); 158 started = 0; 159 reader.callback = NULL; 160 } 161 if (cmd == CMD_QUIT) { 162 D("Thread quitting"); 163 goto Exit; 164 } 165 } else if (cmd == CMD_START) { 166 if (started != 1) { 167 reader.callback = state->callbacks.location_cb; 168 D("Thread starting callback=%p", reader.callback); 169 reader_call_callback(&reader); 170 started = 1; 171 } 172 } else { 173 ALOGE("unknown control command %d", cmd); 174 } 175 } else if (fd == gps_fd) { 176 char buff[256]; 177 int ret; 178 for (;;) { 179 ret = read(fd, buff, sizeof(buff)); 180 if (ret < 0) { 181 if (errno == EINTR) continue; 182 if (errno != EWOULDBLOCK) 183 ALOGE("error while reading from gps daemon socket: %s:", 184 strerror(errno)); 185 break; 186 } 187 D("Thread received %d bytes: %.*s", ret, ret, buff); 188 reader_accept_string(&reader, buff, ret); 189 } 190 } else { 191 ALOGE("epoll_wait() returned unknown fd %d.", fd); 192 } 193 } 194 } 195 } 196 197 Exit: 198 epoll_deregister(epoll_fd, control_fd); 199 epoll_deregister(epoll_fd, gps_fd); 200 } 201