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 <log/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.
reader_call_callback(GpsDataReader * r)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().
reader_parse_message(GpsDataReader * r)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.
reader_accept_string(GpsDataReader * r,char * const str,const int len)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.
gps_state_thread(void * arg)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