/src/gpsd/gpsd-3.25.1~dev/gpsd/libgpsd_core.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* libgpsd_core.c -- manage access to sensors |
2 | | * |
3 | | * Access to the driver layer goes through the entry points in this file. |
4 | | * The idea is to present a session as an abstraction from which you get |
5 | | * fixes (and possibly other data updates) by calling gpsd_multipoll(). The |
6 | | * rest is setup and teardown. (For backward compatibility the older gpsd_poll() |
7 | | * entry point has been retained.) |
8 | | * |
9 | | * This file is Copyright 2010 by the GPSD project |
10 | | * SPDX-License-Identifier: BSD-2-clause |
11 | | */ |
12 | | |
13 | | #include "../include/gpsd_config.h" // must be before all includes |
14 | | |
15 | | #include <assert.h> |
16 | | #include <ctype.h> |
17 | | #include <errno.h> |
18 | | #include <fcntl.h> |
19 | | #include <libgen.h> |
20 | | #include <math.h> |
21 | | #include <stdarg.h> |
22 | | #include <stdbool.h> |
23 | | #include <stdio.h> |
24 | | #include <stdlib.h> |
25 | | #include <string.h> |
26 | | #include <syslog.h> |
27 | | #include <sys/select.h> // for pselect() per POSIX |
28 | | #include <sys/socket.h> |
29 | | #include <sys/stat.h> |
30 | | #include <sys/types.h> |
31 | | #include <sys/wait.h> |
32 | | #include <time.h> |
33 | | #include <unistd.h> |
34 | | |
35 | | #include "../include/gpsd.h" |
36 | | #include "../include/matrix.h" |
37 | | #include "../include/strfuncs.h" |
38 | | #include "../include/timespec.h" |
39 | | #if defined(NMEA2000_ENABLE) |
40 | | #include "../include/driver_nmea2000.h" |
41 | | #endif // defined(NMEA2000_ENABLE) |
42 | | |
43 | | // pass low-level data to devices straight through |
44 | | ssize_t gpsd_write(struct gps_device_t *session, |
45 | | const char *buf, |
46 | | const size_t len) |
47 | 0 | { |
48 | 0 | return session->context->serial_write(session, buf, len); |
49 | 0 | } |
50 | | |
51 | | static void basic_report(const char *buf) |
52 | 0 | { |
53 | 0 | (void)fputs(buf, stderr); |
54 | 0 | } |
55 | | |
56 | | void errout_reset(struct gpsd_errout_t *errout) |
57 | 0 | { |
58 | 0 | errout->debug = LOG_SHOUT; |
59 | 0 | errout->report = basic_report; |
60 | 0 | } |
61 | | |
62 | | static pthread_mutex_t report_mutex; |
63 | | |
64 | | void gpsd_acquire_reporting_lock(void) |
65 | 0 | { |
66 | 0 | int err; |
67 | | |
68 | | // pthread_mutex_lock() returns zero, or an error code. |
69 | 0 | err = pthread_mutex_lock(&report_mutex); |
70 | 0 | if (0 != err) { |
71 | | /* POSIX says pthread_mutex_lock() should only fail if the |
72 | | thread holding the lock has died. Best for gpsd to just die |
73 | | because things are FUBAR. */ |
74 | |
|
75 | 0 | (void)fprintf(stderr,"pthread_mutex_lock() failed: %s(%d)\n", |
76 | 0 | strerror(err), err); |
77 | 0 | exit(EXIT_FAILURE); |
78 | 0 | } |
79 | 0 | } |
80 | | |
81 | | void gpsd_release_reporting_lock(void) |
82 | 0 | { |
83 | 0 | int err; |
84 | | |
85 | | // pthread_mutex_lock() returns zero, or an error code. |
86 | 0 | err = pthread_mutex_unlock(&report_mutex); |
87 | 0 | if (0 != err) { |
88 | | /* POSIX says pthread_mutex_unlock() should only fail when |
89 | | trying to unlock a lock that does not exist, or is not owned by |
90 | | this thread. This should never happen, so best for gpsd to die |
91 | | because things are FUBAR. */ |
92 | |
|
93 | 0 | (void)fprintf(stderr,"pthread_mutex_unlock() failed: %s(%d)\n", |
94 | 0 | strerror(err), err); |
95 | 0 | exit(EXIT_FAILURE); |
96 | 0 | } |
97 | 0 | } |
98 | | |
99 | | // assemble msg in vprintf(3) style, use errout hook or syslog for delivery |
100 | | // FIXME: duplicated in gpsd/libgpsd_core.c |
101 | | static void gpsd_vlog(const int errlevel, |
102 | | const struct gpsd_errout_t *errout, |
103 | | char *outbuf, size_t outlen, |
104 | | const char *fmt, va_list ap) |
105 | 0 | { |
106 | | #ifdef SQUELCH_ENABLE |
107 | | (void)errout; |
108 | | (void)errlevel; |
109 | | (void)fmt; |
110 | | #else |
111 | 0 | char buf[BUFSIZ]; |
112 | 0 | const char *err_str; |
113 | 0 | const char *label; |
114 | 0 | int level = LOG_ERR; |
115 | |
|
116 | 0 | gpsd_acquire_reporting_lock(); |
117 | 0 | switch (errlevel) { |
118 | 0 | case LOG_ERROR: // -1, cannot turn off |
119 | 0 | err_str = "ERROR"; |
120 | 0 | level = LOG_CRIT; |
121 | 0 | break; |
122 | 0 | case LOG_SHOUT: // 0, cannot turn off |
123 | 0 | err_str = "SHOUT"; |
124 | 0 | level = LOG_ERR; |
125 | 0 | break; |
126 | 0 | case LOG_WARN: // 1 |
127 | 0 | err_str = "WARN"; |
128 | 0 | level = LOG_WARNING; |
129 | 0 | break; |
130 | 0 | case LOG_CLIENT: // 2, log JSON to clients |
131 | 0 | err_str = "CLIENT"; |
132 | 0 | level = LOG_NOTICE; |
133 | 0 | break; |
134 | 0 | case LOG_INF: // 3, informative info |
135 | 0 | err_str = "INFO"; |
136 | 0 | level = LOG_INFO; |
137 | 0 | break; |
138 | 0 | case LOG_PROG: // 4, program progress messages |
139 | 0 | err_str = "PROG"; |
140 | 0 | level = LOG_DEBUG; |
141 | 0 | break; |
142 | 0 | case LOG_IO: // 5, device IO |
143 | 0 | err_str = "IO"; |
144 | 0 | level = LOG_DEBUG; |
145 | 0 | break; |
146 | 0 | case LOG_DATA: // 6, decoded data |
147 | 0 | err_str = "DATA"; |
148 | 0 | level = LOG_DEBUG; |
149 | 0 | break; |
150 | 0 | case LOG_SPIN: // 7, spin logging |
151 | 0 | err_str = "SPIN"; |
152 | 0 | level = LOG_DEBUG; |
153 | 0 | break; |
154 | 0 | case LOG_RAW: // 8, low level IO |
155 | 0 | err_str = "RAW"; |
156 | 0 | level = LOG_DEBUG; |
157 | 0 | break; |
158 | 0 | case LOG_RAW1: // 9, rediculous |
159 | 0 | err_str = "RAW1"; |
160 | 0 | level = LOG_DEBUG; |
161 | 0 | break; |
162 | 0 | case LOG_RAW2: // 10, insane |
163 | 0 | err_str = "RAW2"; |
164 | 0 | level = LOG_DEBUG; |
165 | 0 | break; |
166 | 0 | default: // WTF? |
167 | 0 | err_str = "UNK"; |
168 | 0 | level = LOG_CRIT; |
169 | 0 | break; |
170 | 0 | } |
171 | | |
172 | 0 | if (NULL == errout->label) { |
173 | 0 | label = "MISSING"; |
174 | 0 | } else { |
175 | 0 | label = errout->label; |
176 | 0 | } |
177 | 0 | snprintf(buf, sizeof(buf), "%s:%s: %s", label, err_str, fmt); |
178 | 0 | vsnprintf(outbuf, outlen, buf, ap); |
179 | | |
180 | | // this was crazy expensive, just fix the bad log calls |
181 | | // gps_visibilize(outbuf, outlen, buf, strlen(buf)); |
182 | |
|
183 | 0 | if (getpid() == getsid(getpid())) { |
184 | | // I think this calls syslog() only when daemonized |
185 | 0 | syslog(level, "%s", outbuf); |
186 | 0 | } else if (NULL != errout->report) { |
187 | | // we are a thread, use report()? |
188 | | // FIXME: is POSIX syslog() thread safe? |
189 | 0 | errout->report(outbuf); |
190 | 0 | } else { |
191 | | // foreground, use stderr? |
192 | 0 | (void)fputs(outbuf, stderr); |
193 | 0 | } |
194 | 0 | gpsd_release_reporting_lock(); |
195 | 0 | #endif // !SQUELCH_ENABLE |
196 | 0 | } |
197 | | |
198 | | // assemble msg in printf(3) style, use errout hook or syslog for delivery |
199 | | void gpsd_log(const int errlevel, const struct gpsd_errout_t *errout, |
200 | | const char *fmt, ...) |
201 | 0 | { |
202 | 0 | char buf[BUFSIZ]; |
203 | 0 | va_list ap; |
204 | | |
205 | | // errout should never be NULL, but some code analyzers complain anyway |
206 | 0 | if (NULL == errout || |
207 | 0 | errout->debug < errlevel) { |
208 | 0 | return; |
209 | 0 | } |
210 | | |
211 | 0 | buf[0] = '\0'; |
212 | 0 | va_start(ap, fmt); |
213 | 0 | gpsd_vlog(errlevel, errout, buf, sizeof(buf), fmt, ap); |
214 | 0 | va_end(ap); |
215 | 0 | } |
216 | | |
217 | | // dump the current packet in a form optimised for eyeballs |
218 | | const char *gpsd_prettydump(struct gps_device_t *session) |
219 | 0 | { |
220 | 0 | return gpsd_packetdump(session->msgbuf, sizeof(session->msgbuf), |
221 | 0 | session->lexer.outbuffer, |
222 | 0 | session->lexer.outbuflen); |
223 | 0 | } |
224 | | |
225 | | // Define the possible hook strings here so we can get the length |
226 | 0 | #define HOOK_ACTIVATE "ACTIVATE" |
227 | 0 | #define HOOK_DEACTIVATE "DEACTIVATE" |
228 | | |
229 | | #define HOOK_CMD_MAX (sizeof(DEVICEHOOKPATH) + GPS_PATH_MAX \ |
230 | | + sizeof(HOOK_DEACTIVATE)) |
231 | | |
232 | | static void gpsd_run_device_hook(struct gpsd_errout_t *errout, |
233 | | char *device_name, char *hook) |
234 | 0 | { |
235 | 0 | struct stat statbuf; |
236 | 0 | int status; |
237 | 0 | char buf[HOOK_CMD_MAX]; |
238 | |
|
239 | 0 | if (-1 == stat(DEVICEHOOKPATH, &statbuf)) { |
240 | 0 | GPSD_LOG(LOG_PROG, errout, |
241 | 0 | "CORE: no %s present, skipped running %s hook. %s(%d)\n", |
242 | 0 | DEVICEHOOKPATH, hook, strerror(errno), errno); |
243 | 0 | return; |
244 | 0 | } |
245 | | |
246 | 0 | (void)snprintf(buf, sizeof(buf), "%s %s %s", |
247 | 0 | DEVICEHOOKPATH, device_name, hook); |
248 | 0 | GPSD_LOG(LOG_INF, errout, "CORE: running %s\n", buf); |
249 | 0 | status = system(buf); |
250 | 0 | if (-1 == status) { |
251 | 0 | GPSD_LOG(LOG_ERROR, errout, "CORE: error %s(%d) running %s\n", |
252 | 0 | strerror(errno), errno, buf); |
253 | 0 | } else { |
254 | 0 | GPSD_LOG(LOG_INF, errout, |
255 | 0 | "CORE: %s returned %d\n", DEVICEHOOKPATH, |
256 | 0 | WEXITSTATUS(status)); |
257 | 0 | } |
258 | 0 | } |
259 | | |
260 | | int gpsd_switch_driver(struct gps_device_t *session, char *type_name) |
261 | 0 | { |
262 | 0 | const struct gps_type_t **dp; |
263 | 0 | bool first_sync = (NULL != session->device_type); |
264 | 0 | unsigned int i; |
265 | |
|
266 | 0 | if (first_sync && |
267 | 0 | 0 == strcmp(session->device_type->type_name, type_name)) { |
268 | | // no need to switch driver |
269 | 0 | return 0; |
270 | 0 | } |
271 | | |
272 | 0 | GPSD_LOG(LOG_PROG, &session->context->errout, |
273 | 0 | "CORE: switch_driver(%s) called...\n", type_name); |
274 | 0 | for (dp = gpsd_drivers, i = 0; *dp; dp++, i++) |
275 | 0 | if (0 == strcmp((*dp)->type_name, type_name)) { |
276 | 0 | GPSD_LOG(LOG_PROG, &session->context->errout, |
277 | 0 | "CORE: selecting %s driver...\n", |
278 | 0 | (*dp)->type_name); |
279 | 0 | gpsd_assert_sync(session); |
280 | 0 | session->device_type = *dp; |
281 | 0 | session->driver_index = i; |
282 | 0 | session->gpsdata.dev.mincycle = session->device_type->min_cycle; |
283 | | // reconfiguration might be required |
284 | 0 | if (first_sync && |
285 | 0 | NULL != session->device_type->event_hook) { |
286 | 0 | session->device_type->event_hook(session, |
287 | 0 | event_driver_switch); |
288 | 0 | } |
289 | 0 | if (STICKY(*dp)) { |
290 | 0 | session->last_controller = *dp; |
291 | 0 | } |
292 | 0 | return 1; |
293 | 0 | } |
294 | 0 | GPSD_LOG(LOG_ERROR, &session->context->errout, |
295 | 0 | "CORE: invalid GPS type \"%s\".\n", type_name); |
296 | 0 | return 0; |
297 | 0 | } |
298 | | |
299 | | void gps_context_init(struct gps_context_t *context, |
300 | | const char *label) |
301 | 0 | { |
302 | 0 | (void)memset(context, '\0', sizeof(struct gps_context_t)); |
303 | | //context.readonly = false; |
304 | 0 | context->leap_notify = LEAP_NOWARNING; |
305 | 0 | context->serial_write = gpsd_serial_write; |
306 | |
|
307 | 0 | errout_reset(&context->errout); |
308 | 0 | context->errout.label = label; |
309 | |
|
310 | 0 | (void)pthread_mutex_init(&report_mutex, NULL); |
311 | 0 | } |
312 | | |
313 | | // initialize GPS polling |
314 | | void gpsd_init(struct gps_device_t *session, struct gps_context_t *context, |
315 | | const char *device) |
316 | 0 | { |
317 | 0 | (void)memset(session, 0, sizeof(struct gps_device_t)); |
318 | |
|
319 | 0 | if (device != NULL) { |
320 | 0 | (void)strlcpy(session->gpsdata.dev.path, device, |
321 | 0 | sizeof(session->gpsdata.dev.path)); |
322 | 0 | } |
323 | | |
324 | | /* with memset(), no need to set NULLs, or zeros |
325 | | * |
326 | | * session->device_type = NULL; // start by hunting packets |
327 | | * session->last_controller = NULL; |
328 | | * session->observed = 0; |
329 | | * memset(session->subtype, 0, sizeof(session->subtype)); |
330 | | * memset(session->subtype1, 0, sizeof(session->subtype1)); |
331 | | * memset(&(session->nmea), 0, sizeof(session->nmea)); |
332 | | * session->gpsdata.set = 0; |
333 | | * session->sor = (timespec_t){0, 0}; |
334 | | * session->ts_startCurrentBaud = (timespec_t){0, 0}; |
335 | | * session->chars = 0; |
336 | | * |
337 | | */ |
338 | 0 | session->context = context; |
339 | 0 | session->gpsdata.dev.cycle =(timespec_t){1, 0}; |
340 | 0 | session->gpsdata.dev.mincycle = (timespec_t){1, 0}; |
341 | 0 | session->gpsdata.dev.parity = ' '; // will be E, N, or O |
342 | 0 | session->servicetype = SERVICE_UNKNOWN; // gpsd_open() sets this |
343 | 0 | session->shm_clock_unit = -1; |
344 | 0 | session->shm_pps_unit = -1; |
345 | 0 | session->sourcetype = SOURCE_UNKNOWN; // gpsd_open() sets this |
346 | 0 | gps_clear_att(&session->gpsdata.attitude); |
347 | 0 | gps_clear_dop(&session->gpsdata.dop); |
348 | 0 | gps_clear_fix(&session->gpsdata.fix); |
349 | 0 | gps_clear_fix(&session->lastfix); |
350 | 0 | gps_clear_fix(&session->newdata); |
351 | 0 | gps_clear_fix(&session->oldfix); |
352 | 0 | gps_clear_log(&session->gpsdata.log); |
353 | | // tty-level initialization |
354 | 0 | gpsd_tty_init(session); |
355 | | // necessary in case we start reading in the middle of a GPGSV sequence |
356 | 0 | gpsd_zero_satellites(&session->gpsdata); |
357 | | |
358 | | // initialize things for the packet parser |
359 | 0 | packet_reset(&session->lexer); |
360 | 0 | } |
361 | | |
362 | | // temporarily release the GPS device |
363 | | void gpsd_deactivate(struct gps_device_t *session) |
364 | 0 | { |
365 | 0 | if (!session->context->readonly && |
366 | 0 | NULL != session->device_type && |
367 | 0 | NULL != session->device_type->event_hook) { |
368 | 0 | session->device_type->event_hook(session, event_deactivate); |
369 | 0 | } |
370 | | // cast for 32-bit ints. |
371 | 0 | GPSD_LOG(LOG_INF, &session->context->errout, |
372 | 0 | "CORE: closing %s, fd %ld\n", |
373 | 0 | session->gpsdata.dev.path, (long)session->gpsdata.gps_fd); |
374 | 0 | if (SERVICE_NTRIP == session->servicetype) { |
375 | 0 | ntrip_close(session); |
376 | 0 | } else |
377 | 0 | #if defined(NMEA2000_ENABLE) |
378 | 0 | if (SOURCE_CAN == session->sourcetype) { |
379 | 0 | (void)nmea2000_close(session); |
380 | 0 | } else |
381 | 0 | #endif // NMEA2000_ENABLE |
382 | 0 | { |
383 | | // could be serial, udp://, tcp://, etc. |
384 | 0 | gpsd_close(session); |
385 | 0 | } |
386 | 0 | if (O_OPTIMIZE == session->mode) { |
387 | 0 | gpsd_run_device_hook(&session->context->errout, |
388 | 0 | session->gpsdata.dev.path, |
389 | 0 | HOOK_DEACTIVATE); |
390 | 0 | } |
391 | | // tell any PPS-watcher thread to die |
392 | 0 | session->pps_thread.report_hook = NULL; |
393 | | // mark it inactivated |
394 | 0 | session->gpsdata.online.tv_sec = 0; |
395 | 0 | session->gpsdata.online.tv_nsec = 0; |
396 | 0 | } |
397 | | |
398 | | // shim function to decouple PPS monitor code from the session structure |
399 | | static void ppsthread_log(volatile struct pps_thread_t *pps_thread, |
400 | | int loglevel, const char *fmt, ...) |
401 | 0 | { |
402 | 0 | struct gps_device_t *device = (struct gps_device_t *)pps_thread->context; |
403 | 0 | char buf[BUFSIZ]; |
404 | 0 | va_list ap; |
405 | |
|
406 | 0 | switch (loglevel) { |
407 | 0 | case THREAD_ERROR: |
408 | 0 | loglevel = LOG_ERROR; |
409 | 0 | break; |
410 | 0 | case THREAD_WARN: |
411 | 0 | loglevel = LOG_WARN; |
412 | 0 | break; |
413 | 0 | case THREAD_INF: |
414 | 0 | loglevel = LOG_INF; |
415 | 0 | break; |
416 | 0 | case THREAD_PROG: |
417 | 0 | loglevel = LOG_PROG; |
418 | 0 | break; |
419 | 0 | case THREAD_RAW: |
420 | 0 | loglevel = LOG_RAW; |
421 | 0 | break; |
422 | 0 | } |
423 | | |
424 | 0 | if (device->context->errout.debug < loglevel) { |
425 | | // skip it |
426 | 0 | return; |
427 | 0 | } |
428 | | |
429 | 0 | buf[0] = '\0'; |
430 | 0 | va_start(ap, fmt); |
431 | 0 | gpsd_vlog(loglevel, &device->context->errout, buf, sizeof(buf), fmt, ap); |
432 | 0 | va_end(ap); |
433 | 0 | } |
434 | | |
435 | | /* gpsd_clear().- set and clear some data storage fields. |
436 | | * device has been opened. |
437 | | * So some things like path and gpsd_fd are already set. |
438 | | * |
439 | | * Return: void |
440 | | */ |
441 | | void gpsd_clear(struct gps_device_t *session) |
442 | 0 | { |
443 | 0 | (void)clock_gettime(CLOCK_REALTIME, &session->gpsdata.online); |
444 | 0 | lexer_init(&session->lexer, &session->context->errout); |
445 | | // session->gpsdata.online = 0; |
446 | 0 | gps_clear_att(&session->gpsdata.attitude); |
447 | 0 | gps_clear_dop(&session->gpsdata.dop); |
448 | 0 | gps_clear_fix(&session->gpsdata.fix); |
449 | 0 | session->releasetime = (time_t)0; |
450 | 0 | session->badcount = 0; |
451 | | |
452 | | // clear the private data union |
453 | 0 | memset((void *)&session->driver, '\0', sizeof(session->driver)); |
454 | | // set up the context structure for the PPS thread monitor |
455 | 0 | memset_volatile(&session->pps_thread, 0, sizeof(session->pps_thread)); |
456 | 0 | session->pps_thread.devicefd = session->gpsdata.gps_fd; |
457 | 0 | session->pps_thread.devicename = session->gpsdata.dev.path; |
458 | 0 | session->pps_thread.log_hook = ppsthread_log; |
459 | 0 | session->pps_thread.context = (void *)session; |
460 | |
|
461 | 0 | session->opentime = time(NULL); |
462 | 0 | } |
463 | | |
464 | | /* split s into host and service parts |
465 | | * if service is not specified, *service is assigned to NULL |
466 | | * device is currently always assigned to NULL |
467 | | * return: -1 on error, 0 otherwise |
468 | | */ |
469 | | int parse_uri_dest(char *s, char **host, char **service, char **device) |
470 | 0 | { |
471 | 0 | char *search = s; |
472 | |
|
473 | 0 | if ('[' == s[0]) { |
474 | | // IPv6 literal |
475 | 0 | char *cb = strchr(s, ']'); |
476 | 0 | if (NULL == cb) { |
477 | | // missing terminating ] |
478 | 0 | return -1; |
479 | 0 | } |
480 | 0 | *cb = '\0'; |
481 | 0 | *host = s + 1; |
482 | 0 | search = cb + 1; |
483 | 0 | } else { |
484 | | // IPv4 literal, or hostname |
485 | 0 | *host = s; |
486 | 0 | } |
487 | 0 | s = strchr(search, ':'); |
488 | 0 | if (NULL != s) { |
489 | | // found a colon, remove it from host |
490 | 0 | *s = '\0'; |
491 | 0 | search = s + 1; |
492 | 0 | if ('\0' != s[1] && ':' != s[1]) { |
493 | | // s[1] start port/service |
494 | 0 | *service = s + 1; |
495 | 0 | } else { |
496 | 0 | *service = NULL; |
497 | 0 | } |
498 | 0 | } else { |
499 | 0 | *service = NULL; |
500 | 0 | } |
501 | 0 | s = strchr(search, ':'); |
502 | 0 | if (NULL != s) { |
503 | | // found a colon, remove it |
504 | 0 | *s = '\0'; |
505 | 0 | if ('\0' != s[1]) { |
506 | 0 | *device = s + 1; |
507 | 0 | } else { |
508 | 0 | *device = NULL; |
509 | 0 | } |
510 | 0 | } else { |
511 | 0 | *device = NULL; |
512 | 0 | } |
513 | | /* Support trailing / in URIs, e.g. tcp://192.168.100.90:1234/ |
514 | | * Assumes / is not valid _inside_ host or service parts of URI |
515 | | * Accepts strange input, e.g. service part with / but no digits |
516 | | */ |
517 | 0 | s = strchr(*host, '/'); |
518 | 0 | if (NULL != s) { |
519 | | // found a backslash, remove it |
520 | 0 | *s = '\0'; |
521 | 0 | } |
522 | | /* Don't enforce that / should not be in both host and service |
523 | | * Or that if host has /, there shouldn't be any service at all */ |
524 | 0 | if (NULL != *service) { |
525 | 0 | s = strchr(*service, '/'); |
526 | 0 | if (NULL != s) { |
527 | | // found a backslash, remove it |
528 | 0 | *s = '\0'; |
529 | 0 | } |
530 | | // nothing in service besides / --> trigger use of default port |
531 | 0 | if ('\0' == *service[0]) { |
532 | 0 | *service = NULL; |
533 | 0 | } |
534 | 0 | } |
535 | 0 | return 0; |
536 | 0 | } |
537 | | |
538 | | /* open a device for access to its data * |
539 | | * return: the opened file descriptor |
540 | | * PLACEHOLDING_FD (-2) - for /dev/ppsX, ntrip waiting reconenct, etc. |
541 | | * UNALLOCATED_FD (-1) - for open failure |
542 | | */ |
543 | | int gpsd_open(struct gps_device_t *session) |
544 | 0 | { |
545 | | // cast for 32-bit ints |
546 | 0 | GPSD_LOG(LOG_PROG, &session->context->errout, |
547 | 0 | "CORE: gpsd_open(%s) fld %ld\n", |
548 | 0 | session->gpsdata.dev.path, |
549 | 0 | (long)session->gpsdata.gps_fd); |
550 | | |
551 | | // special case: source may be a URI to a remote GNSS or DGPS service |
552 | 0 | if (netgnss_uri_check(session->gpsdata.dev.path)) { |
553 | 0 | session->gpsdata.gps_fd = netgnss_uri_open(session, |
554 | 0 | session->gpsdata.dev.path); |
555 | 0 | session->sourcetype = SOURCE_TCP; |
556 | | // cast for 32-bit ints. |
557 | 0 | GPSD_LOG(LOG_PROG, &session->context->errout, |
558 | 0 | "CORE: netgnss_uri_open(%s) returns socket on fd %ld\n", |
559 | 0 | session->gpsdata.dev.path, (long)session->gpsdata.gps_fd); |
560 | 0 | return (int)session->gpsdata.gps_fd; |
561 | | // otherwise, could be an TCP data feed |
562 | 0 | } else if (str_starts_with(session->gpsdata.dev.path, "tcp://")) { |
563 | 0 | char server[GPS_PATH_MAX], *host, *port, *device; |
564 | 0 | socket_t dsock; |
565 | 0 | char addrbuf[50]; // INET6_ADDRSTRLEN |
566 | |
|
567 | 0 | session->sourcetype = SOURCE_TCP; |
568 | 0 | (void)strlcpy(server, session->gpsdata.dev.path + 6, sizeof(server)); |
569 | 0 | INVALIDATE_SOCKET(session->gpsdata.gps_fd); |
570 | 0 | if (-1 == parse_uri_dest(server, &host, &port, &device) || |
571 | 0 | !port) { |
572 | 0 | GPSD_LOG(LOG_ERROR, &session->context->errout, |
573 | 0 | "CORE: Missing service in TCP feed spec %s\n", |
574 | 0 | session->gpsdata.dev.path); |
575 | 0 | return UNALLOCATED_FD ; |
576 | 0 | } |
577 | 0 | GPSD_LOG(LOG_PROG, &session->context->errout, |
578 | 0 | "CORE: opening TCP feed at %s, port %s.\n", host, |
579 | 0 | port); |
580 | | // open non-blocking |
581 | 0 | dsock = netlib_connectsock1(AF_UNSPEC, host, port, "tcp", |
582 | 0 | 1, false, addrbuf, sizeof(addrbuf)); |
583 | 0 | if (0 > dsock) { |
584 | | // cast for 32-bit ints. |
585 | 0 | GPSD_LOG(LOG_ERROR, &session->context->errout, |
586 | 0 | "CORE: TCP %s IP %s, open error %s(%ld).\n", |
587 | 0 | session->gpsdata.dev.path, addrbuf, |
588 | 0 | netlib_errstr(dsock), (long)dsock); |
589 | 0 | } else { |
590 | | // cast for 32-bit ints. |
591 | 0 | GPSD_LOG(LOG_PROG, &session->context->errout, |
592 | 0 | "CORE: TCP %s IP %s opened on fd %ld\n", |
593 | 0 | session->gpsdata.dev.path, addrbuf, (long)dsock); |
594 | 0 | } |
595 | 0 | session->gpsdata.gps_fd = dsock; |
596 | 0 | return session->gpsdata.gps_fd; |
597 | | // or could be UDP |
598 | 0 | } else if (str_starts_with(session->gpsdata.dev.path, "udp://")) { |
599 | 0 | char server[GPS_PATH_MAX], *host, *port, *device; |
600 | 0 | socket_t dsock; |
601 | |
|
602 | 0 | session->sourcetype = SOURCE_UDP; |
603 | 0 | (void)strlcpy(server, session->gpsdata.dev.path + 6, sizeof(server)); |
604 | 0 | INVALIDATE_SOCKET(session->gpsdata.gps_fd); |
605 | 0 | if (-1 == parse_uri_dest(server, &host, &port, &device) || |
606 | 0 | !port) { |
607 | 0 | GPSD_LOG(LOG_ERROR, &session->context->errout, |
608 | 0 | "CORE: Missing service in UDP feed spec.\n"); |
609 | 0 | return -1; |
610 | 0 | } |
611 | 0 | GPSD_LOG(LOG_PROG, &session->context->errout, |
612 | 0 | "CORE: opening UDP feed at %s, port %s.\n", host, |
613 | 0 | port); |
614 | 0 | if (0 > (dsock = netlib_connectsock1(AF_UNSPEC, host, port, "udp", |
615 | 0 | 0, true, NULL, 0))) { |
616 | | // cast for 32-bit ints. |
617 | 0 | GPSD_LOG(LOG_ERROR, &session->context->errout, |
618 | 0 | "CORE: UDP device open error %s(%ld).\n", |
619 | 0 | netlib_errstr(dsock), (long)dsock); |
620 | 0 | return -1; |
621 | 0 | } else { |
622 | | // cast for 32-bit ints. |
623 | 0 | GPSD_LOG(LOG_PROG, &session->context->errout, |
624 | 0 | "CORE: UDP device opened on fd %ld\n", (long)dsock); |
625 | 0 | } |
626 | 0 | session->gpsdata.gps_fd = dsock; |
627 | 0 | return session->gpsdata.gps_fd; |
628 | 0 | } |
629 | 0 | if (str_starts_with(session->gpsdata.dev.path, "gpsd://")) { |
630 | | /* could be: |
631 | | * gpsd://[ipv6] |
632 | | * gpsd://ipv4 |
633 | | * gpsd://hostname |
634 | | * gpsd://[ipv6]:port |
635 | | * gpsd://ipv4:port |
636 | | * gpsd://hostname:port |
637 | | * gpsd://[ipv6]:port:/device |
638 | | * gpsd://ipv4:port:/device |
639 | | * gpsd://hostname:port:/device |
640 | | * gpsd://[ipv6]::/device |
641 | | * gpsd://ipv4::/device |
642 | | * gpsd://hostname::/device |
643 | | */ |
644 | 0 | char server[GPS_PATH_MAX], *host, *port, *device; |
645 | 0 | socket_t dsock; |
646 | |
|
647 | 0 | session->sourcetype = SOURCE_GPSD; |
648 | 0 | (void)strlcpy(server, session->gpsdata.dev.path + 7, sizeof(server)); |
649 | 0 | INVALIDATE_SOCKET(session->gpsdata.gps_fd); |
650 | 0 | if (-1 == parse_uri_dest(server, &host, &port, &device)) { |
651 | 0 | GPSD_LOG(LOG_ERROR, &session->context->errout, |
652 | 0 | "CORE: Malformed URI specified.\n"); |
653 | 0 | return -1; |
654 | 0 | } |
655 | 0 | if (!port) { |
656 | 0 | port = DEFAULT_GPSD_PORT; |
657 | 0 | } |
658 | 0 | GPSD_LOG(LOG_PROG, &session->context->errout, |
659 | 0 | "CORE: opening remote gpsd feed at %s, port %s.\n", |
660 | 0 | host, port); |
661 | 0 | if (0 > (dsock = netlib_connectsock(AF_UNSPEC, host, port, "tcp"))) { |
662 | | // cast for 32-bit ints. |
663 | 0 | GPSD_LOG(LOG_ERROR, &session->context->errout, |
664 | 0 | "CORE: remote gpsd device open error %s(%ld).\n", |
665 | 0 | netlib_errstr(dsock), (long)dsock); |
666 | 0 | return -1; |
667 | 0 | } // else |
668 | | // cast for 32-bit ints. |
669 | 0 | GPSD_LOG(LOG_PROG, &session->context->errout, |
670 | 0 | "CORE: remote gpsd feed opened on fd %ld\n", (long) dsock); |
671 | | |
672 | | // watch to remote is issued when WATCH is |
673 | 0 | session->gpsdata.gps_fd = dsock; |
674 | 0 | return session->gpsdata.gps_fd; |
675 | 0 | } |
676 | 0 | #if defined(NMEA2000_ENABLE) |
677 | 0 | if (str_starts_with(session->gpsdata.dev.path, "nmea2000://")) { |
678 | 0 | return nmea2000_open(session); |
679 | 0 | } |
680 | 0 | #endif // defined(NMEA2000_ENABLE) |
681 | | /* fall through to plain serial open. |
682 | | * could be a naked /dev/ppsX */ |
683 | 0 | return gpsd_serial_open(session); |
684 | 0 | } |
685 | | |
686 | | /* acquire a connection to the GPS device |
687 | | * could be serial, udp://, tcp://, etc. |
688 | | * |
689 | | * Return: fd on success |
690 | | * less than zero on failure |
691 | | * UNALLOCATED_FD (-1) -- give up |
692 | | * PLACEHOLDING_FD (-2) -- retry possible |
693 | | */ |
694 | | int gpsd_activate(struct gps_device_t *session, const int mode) |
695 | 0 | { |
696 | | // cast for 32-bit ints |
697 | 0 | GPSD_LOG(LOG_PROG, &session->context->errout, |
698 | 0 | "CORE: gpsd_activate(%s, %d) fd %ld\n", |
699 | 0 | session->gpsdata.dev.path, mode, |
700 | 0 | (long)session->gpsdata.gps_fd); |
701 | |
|
702 | 0 | if (O_OPTIMIZE == mode) { |
703 | 0 | gpsd_run_device_hook(&session->context->errout, |
704 | 0 | session->gpsdata.dev.path, HOOK_ACTIVATE); |
705 | 0 | } |
706 | 0 | session->gpsdata.gps_fd = (gps_fd_t)gpsd_open(session); |
707 | 0 | if (O_CONTINUE != mode) { |
708 | 0 | session->mode = mode; |
709 | 0 | } |
710 | |
|
711 | 0 | if (0 > session->gpsdata.gps_fd) { |
712 | | // return could be -1, PLACEHOLDING_FD, of UNALLOCATED_FD |
713 | | // could be ntrip:// reconnect in progress |
714 | 0 | if (PLACEHOLDING_FD == session->gpsdata.gps_fd && |
715 | 0 | SOURCE_PPS == session->sourcetype && |
716 | 0 | NULL == session->pps_thread.report_hook) { |
717 | | /* it is /dev/ppsX, need to set devicename, etc. |
718 | | * check report_hook to ensure not already running |
719 | | * cast fot 32-bit ints */ |
720 | 0 | GPSD_LOG(LOG_PROG, &session->context->errout, |
721 | 0 | "CORE: to gpsd_clear() fd %ld\n", |
722 | 0 | (long)session->gpsdata.gps_fd); |
723 | 0 | gpsd_clear(session); |
724 | 0 | } |
725 | 0 | return session->gpsdata.gps_fd; |
726 | 0 | } |
727 | | |
728 | 0 | #ifdef NON_NMEA0183_ENABLE |
729 | | // if it's a sensor, it must be probed |
730 | 0 | if ((SERVICE_SENSOR == session->servicetype) && |
731 | 0 | (SOURCE_CAN != session->sourcetype)) { |
732 | 0 | const struct gps_type_t **dp; |
733 | |
|
734 | 0 | for (dp = gpsd_drivers; *dp; dp++) { |
735 | 0 | if (NULL != (*dp)->probe_detect) { |
736 | 0 | GPSD_LOG(LOG_PROG, &session->context->errout, |
737 | 0 | "CORE: Probing \"%s\" driver...\n", |
738 | 0 | (*dp)->type_name); |
739 | | // toss stale data |
740 | 0 | (void)tcflush(session->gpsdata.gps_fd, TCIOFLUSH); |
741 | 0 | if (0 != (*dp)->probe_detect(session)) { |
742 | 0 | GPSD_LOG(LOG_PROG, &session->context->errout, |
743 | 0 | "CORE: Probe found \"%s\" driver...\n", |
744 | 0 | (*dp)->type_name); |
745 | 0 | session->device_type = *dp; |
746 | 0 | gpsd_assert_sync(session); |
747 | 0 | goto foundit; |
748 | 0 | } else { |
749 | 0 | GPSD_LOG(LOG_PROG, &session->context->errout, |
750 | 0 | "CORE: Probe not found \"%s\" driver...\n", |
751 | 0 | (*dp)->type_name); |
752 | 0 | } |
753 | 0 | } |
754 | 0 | } |
755 | 0 | GPSD_LOG(LOG_PROG, &session->context->errout, |
756 | 0 | "CORE: no probe matched...\n"); |
757 | 0 | } |
758 | 0 | foundit: |
759 | 0 | #endif // NON_NMEA0183_ENABLE |
760 | |
|
761 | 0 | gpsd_clear(session); |
762 | | /* |
763 | | * We might know the device's type, but we shouldn't assume it has |
764 | | * retained its settings. A revert hook might well have undone |
765 | | * them on the previous close. Fire a reactivate event so drivers |
766 | | * can do something about this if they choose. |
767 | | */ |
768 | 0 | if (NULL != session->device_type && |
769 | 0 | NULL != session->device_type->event_hook) { |
770 | 0 | session->device_type->event_hook(session, event_reactivate); |
771 | 0 | } |
772 | | // cast for 32-bit ints |
773 | 0 | GPSD_LOG(LOG_PROG, &session->context->errout, |
774 | 0 | "CORE: activate fd %ld done\n", |
775 | 0 | (long)session->gpsdata.gps_fd); |
776 | |
|
777 | 0 | return session->gpsdata.gps_fd; |
778 | 0 | } |
779 | | |
780 | | |
781 | | /***************************************************************************** |
782 | | |
783 | | Carl Carter of SiRF supplied this algorithm for computing DOPs from |
784 | | a list of visible satellites (some typos corrected)... |
785 | | |
786 | | For satellite n, let az(n) = azimuth angle from North and el(n) be elevation. |
787 | | Let: |
788 | | |
789 | | a(k, 1) = sin az(k) * cos el(k) |
790 | | a(k, 2) = cos az(k) * cos el(k) |
791 | | a(k, 3) = sin el(k) |
792 | | |
793 | | Then form the line-of-sight matrix A for satellites used in the solution: |
794 | | |
795 | | | a(1,1) a(1,2) a(1,3) 1 | |
796 | | | a(2,1) a(2,2) a(2,3) 1 | |
797 | | | : : : : | |
798 | | | a(n,1) a(n,2) a(n,3) 1 | |
799 | | |
800 | | And its transpose A~: |
801 | | |
802 | | |a(1, 1) a(2, 1) . . . a(n, 1) | |
803 | | |a(1, 2) a(2, 2) . . . a(n, 2) | |
804 | | |a(1, 3) a(2, 3) . . . a(n, 3) | |
805 | | | 1 1 . . . 1 | |
806 | | |
807 | | Compute the covariance matrix (A~*A)^-1, which is guaranteed symmetric: |
808 | | |
809 | | | s(x)^2 s(x)*s(y) s(x)*s(z) s(x)*s(t) | |
810 | | | s(y)*s(x) s(y)^2 s(y)*s(z) s(y)*s(t) | |
811 | | | s(z)*s(x) s(z)*s(y) s(z)^2 s(z)*s(t) | |
812 | | | s(t)*s(x) s(t)*s(y) s(t)*s(z) s(t)^2 | |
813 | | |
814 | | Then: |
815 | | |
816 | | GDOP = sqrt(s(x)^2 + s(y)^2 + s(z)^2 + s(t)^2) |
817 | | TDOP = sqrt(s(t)^2) |
818 | | PDOP = sqrt(s(x)^2 + s(y)^2 + s(z)^2) |
819 | | HDOP = sqrt(s(x)^2 + s(y)^2) |
820 | | VDOP = sqrt(s(z)^2) |
821 | | |
822 | | Here's how we implement it... |
823 | | |
824 | | First, each compute element P(i,j) of the 4x4 product A~*A. |
825 | | If S(k=1,k=n): f(...) is the sum of f(...) as k varies from 1 to n, then |
826 | | applying the definition of matrix product tells us: |
827 | | |
828 | | P(i,j) = S(k=1,k=n): B(i, k) * A(k, j) |
829 | | |
830 | | But because B is the transpose of A, this reduces to |
831 | | |
832 | | P(i,j) = S(k=1,k=n): A(k, i) * A(k, j) |
833 | | |
834 | | This is not, however, the entire algorithm that SiRF uses. Carl writes: |
835 | | |
836 | | > As you note, with rounding accounted for, most values agree exactly, and |
837 | | > those that don't agree our number is higher. That is because we |
838 | | > deweight some satellites and account for that in the DOP calculation. |
839 | | > If a satellite is not used in a solution at the same weight as others, |
840 | | > it should not contribute to DOP calculation at the same weight. So our |
841 | | > internal algorithm does a compensation for that which you would have no |
842 | | > way to duplicate on the outside since we don't output the weighting |
843 | | > factors. In fact those are not even available to API users. |
844 | | |
845 | | Queried about the deweighting, Carl says: |
846 | | |
847 | | > In the SiRF tracking engine, each satellite track is assigned a quality |
848 | | > value based on the tracker's estimate of that signal. It includes C/No |
849 | | > estimate, ability to hold onto the phase, stability of the I vs. Q phase |
850 | | > angle, etc. The navigation algorithm then ranks all the tracks into |
851 | | > quality order and selects which ones to use in the solution and what |
852 | | > weight to give those used in the solution. The process is actually a |
853 | | > bit of a "trial and error" method -- we initially use all available |
854 | | > tracks in the solution, then we sequentially remove the lowest quality |
855 | | > ones until the solution stabilizes. The weighting is inherent in the |
856 | | > Kalman filter algorithm. Once the solution is stable, the DOP is |
857 | | > computed from those SVs used, and there is an algorithm that looks at |
858 | | > the quality ratings and determines if we need to deweight any. |
859 | | > Likewise, if we use altitude hold mode for a 3-SV solution, we deweight |
860 | | > the phantom satellite at the center of the Earth. |
861 | | |
862 | | So we cannot exactly duplicate what SiRF does internally. We'll leave |
863 | | HDOP alone and use our computed values for VDOP and PDOP. Note, this |
864 | | may have to change in the future if this code is used by a non-SiRF |
865 | | driver. |
866 | | |
867 | | ******************************************************************************/ |
868 | | |
869 | | |
870 | | static gps_mask_t fill_dop(const struct gpsd_errout_t *errout, |
871 | | const struct gps_data_t * gpsdata, |
872 | | struct dop_t * dop) |
873 | 0 | { |
874 | 0 | double prod[4][4]; |
875 | 0 | double inv[4][4]; |
876 | 0 | double satpos[MAXCHANNELS][4]; |
877 | 0 | double xdop, ydop, hdop, vdop, pdop, tdop, gdop; |
878 | 0 | int i, j, k, n; |
879 | |
|
880 | 0 | memset(satpos, 0, sizeof(satpos)); |
881 | |
|
882 | 0 | for (n = k = 0; k < gpsdata->satellites_visible; k++) { |
883 | | // This double counts single sats where we got 2 signals from them. |
884 | 0 | if (!gpsdata->skyview[k].used) { |
885 | | // skip unused sats |
886 | 0 | continue; |
887 | 0 | } |
888 | 0 | if (1 > gpsdata->skyview[k].PRN) { |
889 | | // skip bad PRN |
890 | 0 | continue; |
891 | 0 | } |
892 | 0 | if (0 == isfinite(gpsdata->skyview[k].azimuth) || |
893 | 0 | 0 > gpsdata->skyview[k].azimuth || |
894 | 0 | 359 < gpsdata->skyview[k].azimuth) { |
895 | | // skip bad azimuth |
896 | 0 | continue; |
897 | 0 | } |
898 | 0 | if (0 == isfinite(gpsdata->skyview[k].elevation) || |
899 | 0 | 90 < fabs(gpsdata->skyview[k].elevation)) { |
900 | | // skip bad elevation |
901 | 0 | continue; |
902 | 0 | } |
903 | 0 | const struct satellite_t *sp = &gpsdata->skyview[k]; |
904 | 0 | satpos[n][0] = sin(sp->azimuth * DEG_2_RAD) |
905 | 0 | * cos(sp->elevation * DEG_2_RAD); |
906 | 0 | satpos[n][1] = cos(sp->azimuth * DEG_2_RAD) |
907 | 0 | * cos(sp->elevation * DEG_2_RAD); |
908 | 0 | satpos[n][2] = sin(sp->elevation * DEG_2_RAD); |
909 | 0 | satpos[n][3] = 1; |
910 | 0 | GPSD_LOG(LOG_INF, errout, |
911 | 0 | "CORE: PRN %3d az %5.1f el %4.1f (%9.6f, %9.6f, %9.6f)\n", |
912 | 0 | gpsdata->skyview[k].PRN, |
913 | 0 | gpsdata->skyview[k].azimuth, |
914 | 0 | gpsdata->skyview[k].elevation, |
915 | 0 | satpos[n][0], satpos[n][1], satpos[n][2]); |
916 | 0 | n++; |
917 | 0 | } |
918 | | /* can't use gpsdata->satellites_used as that is a counter for xxGSA, |
919 | | * and gets cleared at odd times */ |
920 | 0 | GPSD_LOG(LOG_INF, errout, "CORE: Sats used (%d):\n", n); |
921 | | |
922 | | /* If we don't have 4 satellites then we don't have enough |
923 | | * information to calculate DOPS */ |
924 | 0 | if (n < 4) { |
925 | | #ifdef __UNUSED__ |
926 | | GPSD_LOG(LOG_RAW, errout, |
927 | | "CORE: Not enough satellites available %d < 4:\n", |
928 | | n); |
929 | | #endif // __UNUSED__ |
930 | | // Is this correct return code here? or should it be ERROR_SET |
931 | 0 | return 0; |
932 | 0 | } |
933 | | |
934 | 0 | memset(prod, 0, sizeof(prod)); |
935 | 0 | memset(inv, 0, sizeof(inv)); |
936 | |
|
937 | | #ifdef __UNUSED__ |
938 | | GPSD_LOG(LOG_INF, errout, "CORE: Line-of-sight matrix:\n"); |
939 | | for (k = 0; k < n; k++) { |
940 | | GPSD_LOG(LOG_INF, errout, "CORE: %f %f %f %f\n", |
941 | | satpos[k][0], satpos[k][1], satpos[k][2], satpos[k][3]); |
942 | | } |
943 | | #endif // __UNUSED__ |
944 | |
|
945 | 0 | for (i = 0; i < 4; ++i) { //< rows |
946 | 0 | for (j = 0; j < 4; ++j) { //< cols |
947 | 0 | prod[i][j] = 0.0; |
948 | 0 | for (k = 0; k < n; ++k) { |
949 | 0 | prod[i][j] += satpos[k][i] * satpos[k][j]; |
950 | 0 | } |
951 | 0 | } |
952 | 0 | } |
953 | |
|
954 | | #ifdef __UNUSED__ |
955 | | GPSD_LOG(LOG_INF, errout, "CORE: product:\n"); |
956 | | for (k = 0; k < 4; k++) { |
957 | | GPSD_LOG(LOG_INF, errout, "CORE: %f %f %f %f\n", |
958 | | prod[k][0], prod[k][1], prod[k][2], prod[k][3]); |
959 | | } |
960 | | #endif // __UNUSED__ |
961 | |
|
962 | 0 | if (matrix_invert(prod, inv)) { |
963 | | #ifdef __UNUSED__ |
964 | | /* |
965 | | * Note: this will print garbage unless all the subdeterminants |
966 | | * are computed in the invert() function. |
967 | | */ |
968 | | GPSD_LOG(LOG_RAW, errout, "CORE: inverse:\n"); |
969 | | for (k = 0; k < 4; k++) { |
970 | | GPSD_LOG(LOG_RAW, errout, |
971 | | "CORE: %f %f %f %f\n", |
972 | | inv[k][0], inv[k][1], inv[k][2], inv[k][3]); |
973 | | } |
974 | | #endif // __UNUSED__ |
975 | 0 | } else { |
976 | 0 | GPSD_LOG(LOG_DATA, errout, |
977 | 0 | "CORE: LOS matrix singular, DOPs fail - source '%s'\n", |
978 | 0 | gpsdata->dev.path); |
979 | 0 | return 0; |
980 | 0 | } |
981 | | |
982 | 0 | xdop = sqrt(inv[0][0]); |
983 | 0 | ydop = sqrt(inv[1][1]); |
984 | 0 | hdop = sqrt(inv[0][0] + inv[1][1]); |
985 | 0 | vdop = sqrt(inv[2][2]); |
986 | 0 | pdop = sqrt(inv[0][0] + inv[1][1] + inv[2][2]); |
987 | 0 | tdop = sqrt(inv[3][3]); |
988 | 0 | gdop = sqrt(inv[0][0] + inv[1][1] + inv[2][2] + inv[3][3]); |
989 | |
|
990 | 0 | GPSD_LOG(LOG_DATA, errout, |
991 | 0 | "CORE: DOPS computed/reported: X=%f/%f, Y=%f/%f, H=%f/%f, V=%f/%f, " |
992 | 0 | "P=%f/%f, T=%f/%f, G=%f/%f\n", |
993 | 0 | xdop, dop->xdop, ydop, dop->ydop, hdop, dop->hdop, vdop, |
994 | 0 | dop->vdop, pdop, dop->pdop, tdop, dop->tdop, gdop, dop->gdop); |
995 | | |
996 | | /* Check to see which DOPs we already have. Save values if no value |
997 | | * from the GPS. Do not overwrite values which came from the GPS */ |
998 | 0 | if (isfinite(dop->xdop) == 0) { |
999 | 0 | dop->xdop = xdop; |
1000 | 0 | } |
1001 | 0 | if (isfinite(dop->ydop) == 0) { |
1002 | 0 | dop->ydop = ydop; |
1003 | 0 | } |
1004 | 0 | if (isfinite(dop->hdop) == 0) { |
1005 | 0 | dop->hdop = hdop; |
1006 | 0 | } |
1007 | 0 | if (isfinite(dop->vdop) == 0) { |
1008 | 0 | dop->vdop = vdop; |
1009 | 0 | } |
1010 | 0 | if (isfinite(dop->pdop) == 0) { |
1011 | 0 | dop->pdop = pdop; |
1012 | 0 | } |
1013 | 0 | if (isfinite(dop->tdop) == 0) { |
1014 | 0 | dop->tdop = tdop; |
1015 | 0 | } |
1016 | 0 | if (isfinite(dop->gdop) == 0) { |
1017 | 0 | dop->gdop = gdop; |
1018 | 0 | } |
1019 | |
|
1020 | 0 | return DOP_SET; |
1021 | 0 | } |
1022 | | |
1023 | | /* compute errors and derived quantities |
1024 | | * also a handy place to do final sanity checking */ |
1025 | | static void gpsd_error_model(struct gps_device_t *session) |
1026 | 0 | { |
1027 | 0 | struct gps_fix_t *fix; // current fix |
1028 | 0 | struct gps_fix_t *lastfix; // last fix, maybe same time stamp |
1029 | 0 | struct gps_fix_t *oldfix; // old fix, previous time stamp |
1030 | 0 | struct gps_fix_t *newfix; // new fix (just merged) |
1031 | 0 | double deltatime = -1.0; // time span to compute rates |
1032 | | |
1033 | | /* |
1034 | | * Now we compute derived quantities. This is where the tricky error- |
1035 | | * modeling stuff goes. Presently we don't know how to derive |
1036 | | * time error. |
1037 | | * |
1038 | | * Some drivers set the error fields. No NMEA 183 reports climb error. |
1039 | | * $GPXTE and $PSRFEPE can report track error, but are rare. Whenever |
1040 | | * possible, we step aside and allow the GNSS receiver error estimates |
1041 | | * to be used. But even they are only Wild Ass Guesses (WAGs). |
1042 | | * |
1043 | | * The UERE constants are our assumption about the base error of |
1044 | | * GPS fixes in different directions. |
1045 | | * |
1046 | | * UERE is actually a variable sent in the Almanac, so assuming |
1047 | | * a UERE constant is bogus, as is using it this way. |
1048 | | * |
1049 | | * Assuming that DGPS has substantially better accuracy than plain |
1050 | | * GPS is also a fallacy. Extending this to RTK is building false |
1051 | | * conjecture on top of misplaced wishful thinking. |
1052 | | */ |
1053 | 0 | #define H_UERE_NO_DGPS 15.0 // meters, 95% confidence |
1054 | 0 | #define H_UERE_WITH_DGPS 3.75 // meters, 95% confidence |
1055 | 0 | #define V_UERE_NO_DGPS 23.0 // meters, 95% confidence |
1056 | 0 | #define V_UERE_WITH_DGPS 5.75 // meters, 95% confidence |
1057 | 0 | #define P_UERE_NO_DGPS 19.0 // meters, 95% confidence |
1058 | 0 | #define P_UERE_WITH_DGPS 4.75 // meters, 95% confidence |
1059 | 0 | double h_uere, v_uere, p_uere; |
1060 | |
|
1061 | 0 | if (NULL == session) { |
1062 | 0 | return; |
1063 | 0 | } |
1064 | | |
1065 | 0 | fix = &session->gpsdata.fix; |
1066 | 0 | lastfix = &session->lastfix; |
1067 | 0 | oldfix = &session->oldfix; |
1068 | 0 | newfix = &session->newdata; // For whether rcvr supplies values |
1069 | |
|
1070 | 0 | if (0 < fix->time.tv_sec) { |
1071 | | // we have a time for this merge data |
1072 | |
|
1073 | 0 | deltatime = TS_SUB_D(&fix->time, &lastfix->time); |
1074 | |
|
1075 | 0 | if (0.0099 < fabs(deltatime)) { |
1076 | | /* Time just moved, probably forward at least 10 ms. |
1077 | | * Lastfix is now the previous (old) fix. */ |
1078 | 0 | *oldfix = *lastfix; |
1079 | 0 | } else { |
1080 | | // compute delta from old fix |
1081 | 0 | deltatime = TS_SUB_D(&fix->time, &oldfix->time); |
1082 | 0 | } |
1083 | 0 | } |
1084 | | // Sanity check for negative delta? |
1085 | | |
1086 | | // adjusting UERE for DGPS is dodgy... |
1087 | 0 | h_uere = |
1088 | 0 | (session->gpsdata.fix.status == |
1089 | 0 | STATUS_DGPS ? H_UERE_WITH_DGPS : H_UERE_NO_DGPS); |
1090 | 0 | v_uere = |
1091 | 0 | (session->gpsdata.fix.status == |
1092 | 0 | STATUS_DGPS ? V_UERE_WITH_DGPS : V_UERE_NO_DGPS); |
1093 | 0 | p_uere = |
1094 | 0 | (session->gpsdata.fix.status == |
1095 | 0 | STATUS_DGPS ? P_UERE_WITH_DGPS : P_UERE_NO_DGPS); |
1096 | |
|
1097 | 0 | if (0 == isfinite(fix->latitude) || |
1098 | 0 | 0 == isfinite(fix->longitude) || // both lat/lon, or none |
1099 | 0 | 90.0 < fabs(fix->latitude) || // lat out of range |
1100 | 0 | 180.0 < fabs(fix->longitude)) { // lon out of range |
1101 | 0 | fix->latitude = fix->longitude = NAN; |
1102 | 0 | } |
1103 | | // validate ECEF |
1104 | 0 | if (0 == isfinite(fix->ecef.x) || |
1105 | 0 | 0 == isfinite(fix->ecef.y) || |
1106 | 0 | 0 == isfinite(fix->ecef.z) || |
1107 | 0 | 10.0 >= (fabs(fix->ecef.x) + |
1108 | 0 | fabs(fix->ecef.y) + |
1109 | 0 | fabs(fix->ecef.z))) { // all zeros |
1110 | 0 | fix->ecef.x = fix->ecef.y = fix->ecef.z = NAN; |
1111 | 0 | } |
1112 | | |
1113 | | // if we have not lat/lon, but do have ECEF, calculate lat/lon |
1114 | 0 | if ((0 == isfinite(fix->longitude) || |
1115 | 0 | 0 == isfinite(fix->latitude)) && |
1116 | 0 | 0 != isfinite(fix->ecef.x)) { |
1117 | 0 | session->gpsdata.set |= ecef_to_wgs84fix(fix, |
1118 | 0 | fix->ecef.x, fix->ecef.y, |
1119 | 0 | fix->ecef.z, fix->ecef.vx, |
1120 | 0 | fix->ecef.vy, fix->ecef.vz); |
1121 | 0 | } |
1122 | | |
1123 | | /* If you are in a rocket, and your GPS is ITAR unlocked, then |
1124 | | * triple check these sanity checks. |
1125 | | * |
1126 | | * u-blox 8: Max altitude: 50,000m |
1127 | | * Max horizontal speed: 250 m/s |
1128 | | * Max climb: 100 m/s |
1129 | | * |
1130 | | * u-blox ZED-F9P: Max Velocity: 500 m/s |
1131 | | */ |
1132 | | |
1133 | | /* sanity check the speed, 10,000 m/s should be a nice max |
1134 | | * Low Earth Orbit (LEO) is about 7,800 m/s */ |
1135 | 0 | if (9999.9 < fabs(fix->speed)) |
1136 | 0 | fix->speed = NAN; |
1137 | |
|
1138 | 0 | if (9999.9 < fabs(fix->NED.velN)) |
1139 | 0 | fix->NED.velN = NAN; |
1140 | 0 | if (9999.9 < fabs(fix->NED.velE)) |
1141 | 0 | fix->NED.velE = NAN; |
1142 | 0 | if (9999.9 < fabs(fix->NED.velD)) |
1143 | 0 | fix->NED.velD = NAN; |
1144 | | |
1145 | | // sanity check the climb, 10,000 m/s should be a nice max |
1146 | 0 | if (9999.9 < fabs(fix->climb)) |
1147 | 0 | fix->climb = NAN; |
1148 | 0 | if (0 != isfinite(fix->NED.velD) && |
1149 | 0 | 0 == isfinite(fix->climb)) { |
1150 | | // have good velD, use it for climb |
1151 | 0 | fix->climb = -fix->NED.velD; |
1152 | 0 | } |
1153 | | |
1154 | | // compute speed and track from velN and velE if needed and possible |
1155 | 0 | if (0 != isfinite(fix->NED.velN) && |
1156 | 0 | 0 != isfinite(fix->NED.velE)) { |
1157 | 0 | if (0 == isfinite(fix->speed)) { |
1158 | 0 | fix->speed = hypot(fix->NED.velN, fix->NED.velE); |
1159 | 0 | } |
1160 | 0 | if (0 == isfinite(fix->track)) { |
1161 | 0 | fix->track = atan2(fix->NED.velE, fix->NED.velN) * RAD_2_DEG; |
1162 | | // normalized later |
1163 | 0 | } |
1164 | 0 | } |
1165 | | |
1166 | | /* |
1167 | | * OK, this is not an error computation, but we're at the right |
1168 | | * place in the architecture for it. Compute geoid separation |
1169 | | * and altHAE and altMSL in the simplest possible way. |
1170 | | */ |
1171 | | |
1172 | | // geoid (ellipsoid) separation and variation |
1173 | 0 | if (0 != isfinite(fix->latitude) && |
1174 | 0 | 0 != isfinite(fix->longitude)) { |
1175 | 0 | if (0 == isfinite(fix->geoid_sep)) { |
1176 | 0 | fix->geoid_sep = wgs84_separation(fix->latitude, |
1177 | 0 | fix->longitude); |
1178 | 0 | } |
1179 | 0 | if (0 == isfinite(fix->magnetic_var) || |
1180 | 0 | 0.09 >= fabs(fix->magnetic_var)) { |
1181 | | // some GPS set 0.0,E, or 0,W instead of blank |
1182 | 0 | fix->magnetic_var = mag_var(fix->latitude, |
1183 | 0 | fix->longitude); |
1184 | 0 | } |
1185 | 0 | } |
1186 | |
|
1187 | 0 | if (0 != isfinite(fix->magnetic_var)) { |
1188 | 0 | if (0 == isfinite(fix->magnetic_track) && |
1189 | 0 | 0 != isfinite(fix->track)) { |
1190 | | |
1191 | | // calculate mag track, normalized later |
1192 | 0 | fix->magnetic_track = fix->track + fix->magnetic_var; |
1193 | 0 | } else if (0 != isfinite(fix->magnetic_track) && |
1194 | 0 | 0 == isfinite(fix->track)) { |
1195 | | |
1196 | | // calculate true track, normalized later |
1197 | 0 | fix->track = fix->magnetic_track - fix->magnetic_var; |
1198 | 0 | } |
1199 | 0 | } |
1200 | 0 | if (0 != isfinite(fix->track)) { |
1201 | | // normalize true track |
1202 | 0 | DEG_NORM(fix->track); |
1203 | 0 | } |
1204 | |
|
1205 | 0 | if (0 != isfinite(fix->magnetic_track)) { |
1206 | | // normalize mag track |
1207 | 0 | DEG_NORM(fix->magnetic_track); |
1208 | 0 | } |
1209 | |
|
1210 | 0 | if (0 != isfinite(fix->geoid_sep)) { |
1211 | 0 | if (0 != isfinite(fix->altHAE) && |
1212 | 0 | 0 == isfinite(fix->altMSL)) { |
1213 | | // compute missing altMSL |
1214 | 0 | fix->altMSL = fix->altHAE - fix->geoid_sep; |
1215 | 0 | } else if (0 == isfinite(fix->altHAE) && |
1216 | 0 | 0 != isfinite(fix->altMSL)) { |
1217 | | // compute missing altHAE |
1218 | 0 | fix->altHAE = fix->altMSL + fix->geoid_sep; |
1219 | 0 | } |
1220 | 0 | } |
1221 | | |
1222 | | /* |
1223 | | * OK, this is not an error computation, but we're at the right |
1224 | | * place in the architecture for it. Compute speed over ground |
1225 | | * and climb/sink in the simplest possible way. |
1226 | | */ |
1227 | |
|
1228 | | #ifdef __UNUSED__ |
1229 | | // debug code |
1230 | | { |
1231 | | char tbuf[JSON_DATE_MAX+1]; |
1232 | | GPSD_LOG(LOG_SHOUT, &session->context->errout, |
1233 | | "CORE: time %s deltatime %f\n", |
1234 | | timespec_to_iso8601(fix->time, tbuf, sizeof(tbuf)), |
1235 | | deltatime); |
1236 | | } |
1237 | | #endif // __UNUSED__ |
1238 | |
|
1239 | 0 | if (0 < deltatime) { |
1240 | | // have a valid time duration |
1241 | | // FIXME! ignore if large. maybe > 1 hour? |
1242 | |
|
1243 | 0 | if (MODE_2D <= fix->mode && |
1244 | 0 | MODE_2D <= oldfix->mode) { |
1245 | |
|
1246 | 0 | if (0 == isfinite(fix->speed)) { |
1247 | 0 | fix->speed = earth_distance(fix->latitude, |
1248 | 0 | fix->longitude, |
1249 | 0 | oldfix->latitude, |
1250 | 0 | oldfix->longitude) / deltatime; |
1251 | | // sanity check |
1252 | 0 | if (9999.9 < fabs(fix->speed)) |
1253 | 0 | fix->speed = NAN; |
1254 | 0 | } |
1255 | |
|
1256 | 0 | if (MODE_3D <= fix->mode && |
1257 | 0 | MODE_3D <= oldfix->mode && |
1258 | 0 | 0 == isfinite(fix->climb) && |
1259 | 0 | 0 != isfinite(fix->altHAE) && |
1260 | 0 | 0 != isfinite(oldfix->altHAE)) { |
1261 | 0 | fix->climb = (fix->altHAE - oldfix->altHAE) / deltatime; |
1262 | | |
1263 | | // sanity check the climb |
1264 | 0 | if (9999.9 < fabs(fix->climb)) |
1265 | 0 | fix->climb = NAN; |
1266 | 0 | } |
1267 | 0 | } |
1268 | 0 | } |
1269 | | |
1270 | | /* |
1271 | | * Field reports match the theoretical prediction that |
1272 | | * expected time error should be half the resolution of |
1273 | | * the GPS clock, so we put the bound of the error |
1274 | | * in as a constant pending getting it from each driver. |
1275 | | * |
1276 | | * In an ideal world, we'd increase this if no leap-second has |
1277 | | * been seen and it's less than 750s (one almanac load cycle) from |
1278 | | * device powerup. Alas, we have no way to know when device |
1279 | | * powerup occurred - depending on the receiver design it could be |
1280 | | * when the hardware was first powered up or when it was first |
1281 | | * opened. Also, some devices (notably plain NMEA0183 receivers) |
1282 | | * never ship an indication of when they have valid leap second. |
1283 | | */ |
1284 | 0 | if (0 < fix->time.tv_sec && |
1285 | 0 | 0 == isfinite(fix->ept)) { |
1286 | | // can we compute ept from tdop? |
1287 | 0 | fix->ept = 0.005; |
1288 | 0 | } |
1289 | | |
1290 | | // Other error computations depend on having a valid fix |
1291 | 0 | if (MODE_2D <= fix->mode) { |
1292 | 0 | if (0 == isfinite(newfix->epx) && |
1293 | 0 | 0 != isfinite(session->gpsdata.dop.xdop)) { |
1294 | 0 | fix->epx = session->gpsdata.dop.xdop * h_uere; |
1295 | 0 | } |
1296 | |
|
1297 | 0 | if (0 == isfinite(newfix->epy) && |
1298 | 0 | 0 != isfinite(session->gpsdata.dop.ydop)) { |
1299 | 0 | fix->epy = session->gpsdata.dop.ydop * h_uere; |
1300 | 0 | } |
1301 | |
|
1302 | 0 | if (MODE_3D <= fix->mode && |
1303 | 0 | 0 == isfinite(fix->epv) && |
1304 | 0 | 0 != isfinite(session->gpsdata.dop.vdop)) { |
1305 | 0 | fix->epv = session->gpsdata.dop.vdop * v_uere; |
1306 | 0 | } |
1307 | | |
1308 | | // 2D error |
1309 | 0 | if (0 == isfinite(fix->eph) && |
1310 | 0 | 0 != isfinite(session->gpsdata.dop.hdop)) { |
1311 | 0 | fix->eph = session->gpsdata.dop.hdop * p_uere; |
1312 | 0 | } |
1313 | | |
1314 | | // 3D error |
1315 | 0 | if (0 == isfinite(fix->sep) && |
1316 | 0 | 0 != isfinite(session->gpsdata.dop.pdop)) { |
1317 | 0 | fix->sep = session->gpsdata.dop.pdop * p_uere; |
1318 | 0 | } |
1319 | | |
1320 | | /* |
1321 | | * If we have a current fix and an old fix, and the packet handler |
1322 | | * didn't set the speed error, climb error or track error members |
1323 | | * itself, try to compute them now. |
1324 | | */ |
1325 | |
|
1326 | 0 | #define EMAX(x, y) (((x) > (y)) ? (x) : (y)) |
1327 | |
|
1328 | 0 | if (0 < deltatime && |
1329 | 0 | MODE_2D <= oldfix->mode) { |
1330 | |
|
1331 | 0 | if (0 == isfinite(newfix->eps) && |
1332 | 0 | 0 != isfinite(oldfix->epx) && |
1333 | 0 | 0 != isfinite(oldfix->epy)) { |
1334 | 0 | fix->eps = (EMAX(oldfix->epx, oldfix->epy) + |
1335 | 0 | EMAX(fix->epx, fix->epy)) / deltatime; |
1336 | 0 | } |
1337 | |
|
1338 | 0 | if (0 == isfinite(fix->epd)) { |
1339 | | /* |
1340 | | * We compute a track error estimate solely from the |
1341 | | * position of this fix and the last one. The maximum |
1342 | | * track error, as seen from the position of last fix, is |
1343 | | * the angle subtended by the two most extreme possible |
1344 | | * error positions of the current fix; the expected track |
1345 | | * error is half that. Let the position of the old fix be |
1346 | | * A and of the new fix B. We model the view from A as |
1347 | | * two right triangles ABC and ABD with BC and BD both |
1348 | | * having the length of the new fix's estimated error. |
1349 | | * adj = len(AB), opp = len(BC) = len(BD), hyp = len(AC) = |
1350 | | * len(AD). This leads to spurious uncertainties |
1351 | | * near 180 when we're moving slowly; to avoid reporting |
1352 | | * garbage, throw back NaN if the distance from the previous |
1353 | | * fix is less than the error estimate. |
1354 | | */ |
1355 | 0 | double adj = earth_distance(oldfix->latitude, oldfix->longitude, |
1356 | 0 | fix->latitude, fix->longitude); |
1357 | 0 | double opp = EMAX(fix->epx, fix->epy); |
1358 | 0 | if (isfinite(adj) != 0 && adj > opp) { |
1359 | 0 | double hyp = sqrt(adj * adj + opp * opp); |
1360 | 0 | fix->epd = RAD_2_DEG * 2 * asin(opp / hyp); |
1361 | 0 | } |
1362 | 0 | } |
1363 | |
|
1364 | 0 | if (0 == isfinite(newfix->epc) && |
1365 | 0 | 0 != isfinite(fix->epv) && |
1366 | 0 | 0 != isfinite(oldfix->epv)) { |
1367 | | // Is this really valid? |
1368 | | // if vertical uncertainties are zero this will be too |
1369 | 0 | fix->epc = (oldfix->epv + fix->epv) / deltatime; |
1370 | 0 | } |
1371 | 0 | } |
1372 | 0 | } |
1373 | |
|
1374 | | #ifdef __UNUSED__ |
1375 | | { |
1376 | | // Debug code. |
1377 | | char tbuf[JSON_DATE_MAX+1]; |
1378 | | GPSD_LOG(&session->context->errout, 0, |
1379 | | "CORE: %s deltatime %.3f, speed %0.3f climb %.3f " |
1380 | | "epc %.3f fixHAE %.3f oldHAE %.3f\n", |
1381 | | timespec_to_iso8601(fix->time, tbuf, sizeof(tbuf)), |
1382 | | deltatime, fix->speed, fix->climb, fix->epc, |
1383 | | fix->altHAE, oldfix->altHAE); |
1384 | | } |
1385 | | #endif // __UNUSED__ |
1386 | |
|
1387 | 0 | if (0 < fix->time.tv_sec) { |
1388 | | // save lastfix, not yet oldfix, for later error computations |
1389 | 0 | *lastfix = *fix; |
1390 | 0 | } |
1391 | 0 | } |
1392 | | |
1393 | | /* await data from any socket in the all_fds set |
1394 | | * |
1395 | | * return: AWAIT_ value |
1396 | | */ |
1397 | | int gpsd_await_data(fd_set *rfds, |
1398 | | fd_set *efds, |
1399 | | int maxfd, |
1400 | | fd_set *all_fds, |
1401 | | struct gpsd_errout_t *errout, |
1402 | | timespec_t ts_timeout) |
1403 | 0 | { |
1404 | 0 | int status; |
1405 | |
|
1406 | 0 | FD_ZERO(efds); |
1407 | 0 | *rfds = *all_fds; |
1408 | 0 | GPSD_LOG(LOG_RAW1, errout, "CORE: select waits, maxfd %d\n", maxfd); |
1409 | | /* |
1410 | | * Poll for user commands or GPS data. The timeout doesn't |
1411 | | * actually matter here since select returns whenever one of |
1412 | | * the file descriptors in the set goes ready. The point |
1413 | | * of tracking maxfd is to keep the set of descriptors that |
1414 | | * pselect(2) has to poll here as small as possible (for |
1415 | | * low-clock-rate SBCs and the like). |
1416 | | * |
1417 | | * As used here, there is no difference between pselect() |
1418 | | * or select(). A timeout is used, this adds a bit |
1419 | | * of power consumption, but prevents infinite hang during autobaud, |
1420 | | * or select. pselect() may, or may not, modify ts_timeout. |
1421 | | */ |
1422 | 0 | errno = 0; |
1423 | |
|
1424 | 0 | status = pselect(maxfd + 1, rfds, NULL, NULL, &ts_timeout, NULL); |
1425 | 0 | if (-1 == status) { |
1426 | 0 | if (EINTR == errno) { |
1427 | | // caught a signal |
1428 | 0 | return AWAIT_NOT_READY; |
1429 | 0 | } |
1430 | | |
1431 | 0 | if (EBADF == errno) { |
1432 | | // Invalid file descriptor. |
1433 | 0 | int fd; |
1434 | 0 | for (fd = 0; fd < (int)FD_SETSIZE; fd++) { |
1435 | | /* |
1436 | | * All we care about here is a cheap, fast, uninterruptible |
1437 | | * way to check if a file descriptor is valid. |
1438 | | */ |
1439 | 0 | if (FD_ISSET(fd, all_fds) && -1 == fcntl(fd, F_GETFL, 0)) { |
1440 | 0 | FD_CLR(fd, all_fds); |
1441 | 0 | FD_SET(fd, efds); |
1442 | 0 | } |
1443 | 0 | } |
1444 | 0 | return AWAIT_NOT_READY; |
1445 | 0 | } |
1446 | | // else |
1447 | 0 | GPSD_LOG(LOG_ERROR, errout, "CORE: pselect: %s(%d)\n", |
1448 | 0 | strerror(errno), errno); |
1449 | 0 | return AWAIT_FAILED; |
1450 | 0 | } |
1451 | 0 | if (0 == status) { |
1452 | | // pselect timeout |
1453 | 0 | GPSD_LOG(LOG_PROG, errout, "CORE: pselect: timeout\n"); |
1454 | 0 | return AWAIT_TIMEOUT; |
1455 | 0 | } |
1456 | | |
1457 | 0 | if (LOG_SPIN <= errout->debug) { |
1458 | 0 | int i; |
1459 | 0 | char dbuf[BUFSIZ]; |
1460 | 0 | timespec_t ts_now; |
1461 | 0 | char ts_str[TIMESPEC_LEN]; |
1462 | |
|
1463 | 0 | dbuf[0] = '\0'; |
1464 | 0 | for (i = 0; i < (int)FD_SETSIZE; i++) { |
1465 | 0 | if (FD_ISSET(i, all_fds)) { |
1466 | 0 | str_appendf(dbuf, sizeof(dbuf), "%d ", i); |
1467 | 0 | } |
1468 | 0 | } |
1469 | 0 | str_rstrip_char(dbuf, ' '); |
1470 | 0 | (void)strlcat(dbuf, "} -> {", sizeof(dbuf)); |
1471 | 0 | for (i = 0; i < (int)FD_SETSIZE; i++) { |
1472 | 0 | if (FD_ISSET(i, rfds)) { |
1473 | 0 | str_appendf(dbuf, sizeof(dbuf), " %d ", i); |
1474 | 0 | } |
1475 | 0 | } |
1476 | |
|
1477 | 0 | (void)clock_gettime(CLOCK_REALTIME, &ts_now); |
1478 | 0 | GPSD_LOG(LOG_SPIN, errout, |
1479 | 0 | "CORE: pselect() {%s} at %s, %s(%d)\n", |
1480 | 0 | dbuf, |
1481 | 0 | timespec_str(&ts_now, ts_str, sizeof(ts_str)), |
1482 | 0 | strerror(errno), errno); |
1483 | 0 | } |
1484 | |
|
1485 | 0 | return AWAIT_GOT_INPUT; |
1486 | 0 | } |
1487 | | |
1488 | | /* Return false - don't go to next hunt setting |
1489 | | * true - time to go to next hunt setting |
1490 | | */ |
1491 | | static bool hunt_failure(struct gps_device_t *session) |
1492 | 0 | { |
1493 | | /* |
1494 | | * After a bad packet, what should cue us to go to next autobaud setting? |
1495 | | * We have tried three different tests here. |
1496 | | * |
1497 | | * The first was session->badcount++>1. This worked very well on |
1498 | | * ttys for years and years, but caused failure to sync on TCP/IP |
1499 | | * sources, which have I/O boundaries in mid-packet more often |
1500 | | * than RS232 ones. There's a test for this at |
1501 | | * test/daemon/tcp-torture.log. |
1502 | | * |
1503 | | * The second was session->badcount++>1 && session->lexer.state==0. |
1504 | | * Fail hunt only if we get a second consecutive bad packet |
1505 | | * and the lexer is in ground state. We don't want to fail on |
1506 | | * a first bad packet because the source might have a burst of |
1507 | | * leading garbage after open. We don't want to fail if the |
1508 | | * lexer is not in ground state, because that means the read |
1509 | | * might have picked up a valid partial packet - better to go |
1510 | | * back around the loop and pick up more data. |
1511 | | * |
1512 | | * The "&& session->lexer.state==0" guard causes an intermittent |
1513 | | * hang while autobauding on SiRF IIIs (but not on SiRF-IIs, oddly |
1514 | | * enough). Removing this conjunct resurrected the failure |
1515 | | * of test/daemon/tcp-torture.log. |
1516 | | * |
1517 | | * Our third attempt, isatty(session->gpsdata.gps_fd) != 0 |
1518 | | * && session->badcount++ > 1, reverts to the old test that worked |
1519 | | * well on ttys for ttys and prevents non-tty devices from *ever* |
1520 | | * having hunt failures. This has the cost that non-tty devices |
1521 | | * will never get kicked off for presenting bad packets. |
1522 | | * |
1523 | | * Slightly refactored, but equivalent, in 3.23.1 |
1524 | | * |
1525 | | * This test may need further revision. |
1526 | | */ |
1527 | 0 | if (0 >= gpsd_serial_isatty(session)) { |
1528 | | // Not a tty, so can't hunt. |
1529 | 0 | return false; |
1530 | 0 | } |
1531 | | // It is a tty, but don't hunt if speed is fixed. |
1532 | 0 | if (0 != session->context->fixed_port_speed) { |
1533 | 0 | return false; |
1534 | 0 | } |
1535 | 0 | return 1 < session->badcount++; |
1536 | 0 | } |
1537 | | |
1538 | | // update the stuff in the scoreboard structure |
1539 | | // Also used by gpsdecode.c |
1540 | | gps_mask_t gpsd_poll(struct gps_device_t *session) |
1541 | 0 | { |
1542 | 0 | ssize_t newlen; |
1543 | 0 | bool driver_change = false; |
1544 | 0 | timespec_t ts_now; |
1545 | 0 | timespec_t delta; |
1546 | 0 | char ts_buf[TIMESPEC_LEN]; |
1547 | | |
1548 | | // Maybe only clear when we actually get a new packet? How? |
1549 | 0 | gps_clear_fix(&session->newdata); |
1550 | | |
1551 | | /* |
1552 | | * Input just became available from a sensor, but no read from the |
1553 | | * device has yet been done. |
1554 | | * |
1555 | | * What we actually do here is trickier. For latency-timing |
1556 | | * purposes, we want to know the time at the start of the current |
1557 | | * recording cycle. We rely on the fact that even at 4800bps |
1558 | | * there's a quiet time perceptible to the human eye in gpsmon |
1559 | | * between when the last character of the last packet in a |
1560 | | * 1-second cycle ships and when the next reporting cycle |
1561 | | * ships. Because the cycle time is fixed, higher baud rates will |
1562 | | * make this gap larger. |
1563 | | * |
1564 | | * Thus, we look for an inter-character delay much larger than an |
1565 | | * average 4800bps sentence time. How should this delay be set? Well, |
1566 | | * counting framing bits and erring on the side of caution, it's |
1567 | | * about 480 characters per second or 2083 microeconds per character; |
1568 | | * that's almost exactly 0.125 seconds per average 60-char sentence. |
1569 | | * Doubling this to avoid false positives, we look for an inter-character |
1570 | | * delay of greater than 0.250s. |
1571 | | * |
1572 | | * The above assumes a cycle time of 1 second. To get the minimum size of |
1573 | | * the quiet period, we multiply by the device cycle time. |
1574 | | * |
1575 | | * We can sanity-check these calculation by watching logs. If we have set |
1576 | | * MINIMUM_QUIET_TIME correctly, the "transmission pause" message below |
1577 | | * will consistently be emitted just before the sentence that shows up |
1578 | | * as start-of-cycle in gpsmon, and never emitted at any other point |
1579 | | * in the cycle. |
1580 | | * |
1581 | | * In practice, it seems that edge detection succeeds at 9600bps but |
1582 | | * fails at 4800bps. This is not surprising, as previous profiling has |
1583 | | * indicated that at 4800bps some devices overrun a 1-second cycle time |
1584 | | * with the data they transmit. |
1585 | | */ |
1586 | 0 | #define MINIMUM_QUIET_TIME 0.25 |
1587 | 0 | if (0 == session->lexer.outbuflen) { |
1588 | | /* beginning of a new packet, or not... |
1589 | | * 0 == lexer.outbuf just means the last read was not a full packet. |
1590 | | * that works on serial lines that dribble data. |
1591 | | * usb tends to only send complete packets. |
1592 | | * Worse, we do not know if we have a full packet this time. |
1593 | | */ |
1594 | 0 | (void)clock_gettime(CLOCK_REALTIME, &ts_now); |
1595 | 0 | if (NULL != session->device_type && |
1596 | 0 | (0 < session->lexer.start_time.tv_sec || |
1597 | 0 | 0 < session->lexer.start_time.tv_nsec)) { |
1598 | 0 | const double min_cycle = TSTONS(&session->device_type->min_cycle); |
1599 | 0 | double quiet_time = (MINIMUM_QUIET_TIME * min_cycle); |
1600 | 0 | double gap; |
1601 | |
|
1602 | 0 | gap = TS_SUB_D(&ts_now, &session->lexer.start_time); |
1603 | | |
1604 | | // used to comare gap > min_cycle, but min_cycle is now |
1605 | | // so variable as to be not helpful. Some GPS models can |
1606 | | // vary from 20Hz to 1Hz. |
1607 | 0 | if (gap > quiet_time) { |
1608 | | // quiet_time is getting less useful as GNSS receivers |
1609 | | // have more data to send. |
1610 | 0 | GPSD_LOG(LOG_PROG, &session->context->errout, |
1611 | 0 | "CORE: transmission pause. gap %f quiet_time %f\n", |
1612 | 0 | gap, quiet_time); |
1613 | 0 | session->sor = ts_now; |
1614 | 0 | session->lexer.start_char = session->lexer.char_counter; |
1615 | 0 | } |
1616 | 0 | } |
1617 | 0 | session->lexer.start_time = ts_now; |
1618 | 0 | } |
1619 | |
|
1620 | 0 | if (COMMENT_PACKET <= session->lexer.type) { |
1621 | 0 | session->observed |= PACKET_TYPEMASK(session->lexer.type); |
1622 | 0 | } |
1623 | | |
1624 | | // can we get a full packet from the device/NTRIP/DGPS/tcp/etc.? |
1625 | 0 | if (NULL != session->device_type) { |
1626 | 0 | newlen = session->device_type->get_packet(session); |
1627 | | // coverity[deref_ptr] |
1628 | 0 | GPSD_LOG(LOG_RAW, &session->context->errout, |
1629 | 0 | "CORE: %s is known to be %s, packet type %d\n", |
1630 | 0 | session->gpsdata.dev.path, |
1631 | 0 | session->device_type->type_name, |
1632 | 0 | session->lexer.type); |
1633 | 0 | } else { |
1634 | 0 | newlen = packet_get1(session); |
1635 | 0 | } |
1636 | | |
1637 | | // update the scoreboard structure from the GPS |
1638 | 0 | GPSD_LOG(LOG_RAW1, &session->context->errout, |
1639 | 0 | "CORE: %s sent %zd new characters\n", |
1640 | 0 | session->gpsdata.dev.path, newlen); |
1641 | |
|
1642 | 0 | (void)clock_gettime(CLOCK_REALTIME, &ts_now); |
1643 | 0 | TS_SUB(&delta, &ts_now, &session->gpsdata.online); |
1644 | 0 | if (0 > newlen) { // read error |
1645 | 0 | GPSD_LOG(LOG_INF, &session->context->errout, |
1646 | 0 | "CORE: %s returned error %zd (%s sec since data)\n", |
1647 | 0 | session->gpsdata.dev.path, newlen, |
1648 | 0 | timespec_str(&delta, ts_buf, sizeof(ts_buf))); |
1649 | 0 | session->gpsdata.online.tv_sec = 0; |
1650 | 0 | session->gpsdata.online.tv_nsec = 0; |
1651 | 0 | return ERROR_SET; |
1652 | 0 | } |
1653 | 0 | if (0 == newlen) { // zero length read, possible EOF |
1654 | | /* |
1655 | | * Multiplier is 2 to avoid edge effects due to sampling at the exact |
1656 | | * wrong time... |
1657 | | * leave TCP network connection alone, let the TCP link timer expire |
1658 | | * and throw an error. |
1659 | | */ |
1660 | 0 | if (0 < session->gpsdata.online.tv_sec && |
1661 | 0 | SOURCE_TCP != session->sourcetype && |
1662 | | // FIXME: do this with integer math... |
1663 | 0 | TSTONS(&delta) >= (TSTONS(&session->gpsdata.dev.cycle) * 2)) { |
1664 | 0 | GPSD_LOG(LOG_INF, &session->context->errout, |
1665 | 0 | "CORE: %s is offline (%s sec since data) cycle %lld " |
1666 | 0 | "srctype %d\n", |
1667 | 0 | session->gpsdata.dev.path, |
1668 | 0 | timespec_str(&delta, ts_buf, sizeof(ts_buf)), |
1669 | 0 | (long long)session->gpsdata.dev.cycle.tv_sec, |
1670 | 0 | session->sourcetype); |
1671 | 0 | session->gpsdata.online.tv_sec = 0; |
1672 | 0 | session->gpsdata.online.tv_nsec = 0; |
1673 | 0 | } |
1674 | 0 | return NODATA_IS; |
1675 | 0 | } |
1676 | | // else (0 < newlen), got at least something. |
1677 | 0 | session->lexer.pkt_time = ts_now; |
1678 | |
|
1679 | 0 | GPSD_LOG(LOG_RAW, &session->context->errout, |
1680 | 0 | "CORE: packet sniff on %s finds type %d\n", |
1681 | 0 | session->gpsdata.dev.path, session->lexer.type); |
1682 | 0 | if (COMMENT_PACKET == session->lexer.type) { |
1683 | | // deal with regression test helper macros |
1684 | 0 | const char date_str[] = "# Date: "; |
1685 | |
|
1686 | 0 | session->badcount = 0; |
1687 | 0 | if (0 == strcmp((const char *)session->lexer.outbuffer, |
1688 | 0 | "# EOF\n")) { |
1689 | | // undocumented, used by gpsfake to signal EOF |
1690 | 0 | GPSD_LOG(LOG_PROG, &session->context->errout, |
1691 | 0 | "CORE: synthetic EOF\n"); |
1692 | 0 | return EOF_IS; |
1693 | 0 | } |
1694 | 0 | if (0 == strncmp((const char *)session->lexer.outbuffer, |
1695 | 0 | date_str, sizeof(date_str) - 1)) { |
1696 | | // # Date: yyyy-mm-dd |
1697 | | // used by regression tests to correct |
1698 | | // change start time, gps weeks, etc. |
1699 | 0 | gpsd_set_century(session); |
1700 | |
|
1701 | 0 | GPSD_LOG(LOG_PROG, &session->context->errout, |
1702 | 0 | "CORE: start_time %lld\n", |
1703 | 0 | (long long)session->context->start_time); |
1704 | 0 | } |
1705 | 0 | GPSD_LOG(LOG_PROG, &session->context->errout, |
1706 | 0 | "CORE: comment, sync lock deferred: >%s<\n", |
1707 | 0 | session->lexer.outbuffer); |
1708 | 0 | } else if (COMMENT_PACKET < session->lexer.type) { |
1709 | 0 | if (NULL == session->device_type) { |
1710 | 0 | driver_change = true; |
1711 | 0 | } else { |
1712 | 0 | int newtype = session->lexer.type; |
1713 | | /* |
1714 | | * Are we seeing a new packet type? Then we probably |
1715 | | * want to change drivers. |
1716 | | */ |
1717 | 0 | bool new_packet_type = |
1718 | 0 | (newtype != session->device_type->packet_type); |
1719 | | /* |
1720 | | * Possibly the old driver has a mode-switcher method, in |
1721 | | * which case we know it can handle NMEA itself and may |
1722 | | * want to do special things (like tracking whether a |
1723 | | * previous mode switch to binary succeeded in suppressing |
1724 | | * NMEA). |
1725 | | */ |
1726 | | // QQQ: use STICKY() instead? |
1727 | 0 | bool dependent_nmea = (NMEA_PACKET == newtype && |
1728 | 0 | NULL != session->device_type->mode_switcher); |
1729 | | |
1730 | | /* |
1731 | | * Compute whether to switch drivers. |
1732 | | * If the previous driver type was sticky and this one |
1733 | | * isn't, we'll revert after processing the packet. |
1734 | | */ |
1735 | 0 | driver_change = new_packet_type && !dependent_nmea; |
1736 | 0 | } |
1737 | 0 | if (driver_change) { |
1738 | 0 | const struct gps_type_t **dp; |
1739 | |
|
1740 | 0 | for (dp = gpsd_drivers; *dp; dp++) |
1741 | 0 | if (session->lexer.type == (*dp)->packet_type) { |
1742 | 0 | GPSD_LOG(LOG_PROG, &session->context->errout, |
1743 | 0 | "CORE: switching to match packet type %d: %s\n", |
1744 | 0 | session->lexer.type, gpsd_prettydump(session)); |
1745 | 0 | (void)gpsd_switch_driver(session, (*dp)->type_name); |
1746 | 0 | break; |
1747 | 0 | } |
1748 | 0 | } |
1749 | 0 | session->badcount = 0; |
1750 | 0 | session->gpsdata.dev.driver_mode = |
1751 | 0 | (session->lexer.type > NMEA_PACKET) ? MODE_BINARY : MODE_NMEA; |
1752 | 0 | } else if (hunt_failure(session) && !gpsd_next_hunt_setting(session)) { |
1753 | 0 | (void)clock_gettime(CLOCK_REALTIME, &ts_now); |
1754 | 0 | TS_SUB(&delta, &ts_now, &session->gpsdata.online); |
1755 | 0 | GPSD_LOG(LOG_INF, &session->context->errout, |
1756 | 0 | "CORE: hunt on %s failed (%s sec since data)\n", |
1757 | 0 | session->gpsdata.dev.path, |
1758 | 0 | timespec_str(&delta, ts_buf, sizeof(ts_buf))); |
1759 | 0 | return ERROR_SET; |
1760 | 0 | } |
1761 | | |
1762 | 0 | if (0 == session->lexer.outbuflen) { // got new data, but no packet |
1763 | 0 | GPSD_LOG(LOG_RAW1, &session->context->errout, |
1764 | 0 | "CORE: New data on %s, not yet a packet\n", |
1765 | 0 | session->gpsdata.dev.path); |
1766 | 0 | return ONLINE_SET; |
1767 | 0 | } |
1768 | | |
1769 | | // we have recognized a packet |
1770 | 0 | session->badcount = 0; |
1771 | 0 | gps_mask_t received = PACKET_SET; |
1772 | 0 | (void)clock_gettime(CLOCK_REALTIME, &session->gpsdata.online); |
1773 | |
|
1774 | 0 | GPSD_LOG(LOG_RAW1, &session->context->errout, |
1775 | 0 | "CORE: Accepted packet on %s.\n", |
1776 | 0 | session->gpsdata.dev.path); |
1777 | | |
1778 | | // track the packet count since achieving sync on the device |
1779 | 0 | if (driver_change && |
1780 | 0 | 0 == (session->drivers_identified & (1 << session->driver_index))) { |
1781 | | |
1782 | | // coverity[var_deref_op] |
1783 | 0 | GPSD_LOG(LOG_INF, &session->context->errout, |
1784 | 0 | "CORE: %s identified as type %s, %ld sec\n", |
1785 | 0 | session->gpsdata.dev.path, |
1786 | 0 | session->device_type->type_name, |
1787 | 0 | (long)(time(NULL) - session->opentime)); |
1788 | |
|
1789 | 0 | if (0 < gpsd_serial_isatty(session)) { |
1790 | 0 | GPSD_LOG(LOG_INF, &session->context->errout, |
1791 | 0 | "CORE: %s %ubps\n", |
1792 | 0 | session->gpsdata.dev.path, |
1793 | 0 | (unsigned int)gpsd_get_speed(session)); |
1794 | 0 | } |
1795 | | |
1796 | | // fire the init_query method |
1797 | 0 | if (NULL != session->device_type && |
1798 | 0 | NULL != session->device_type->init_query) { |
1799 | | /* |
1800 | | * We can force readonly off knowing this method does |
1801 | | * not alter device state. |
1802 | | */ |
1803 | 0 | bool saved = session->context->readonly; |
1804 | 0 | session->context->readonly = false; |
1805 | 0 | session->device_type->init_query(session); |
1806 | 0 | session->context->readonly = saved; |
1807 | 0 | } |
1808 | | |
1809 | | // fire the identified hook |
1810 | 0 | if (NULL != session->device_type && |
1811 | 0 | NULL != session->device_type->event_hook) { |
1812 | 0 | session->device_type->event_hook(session, event_identified); |
1813 | 0 | } |
1814 | 0 | session->lexer.counter = 0; |
1815 | | |
1816 | | // let clients know about this. |
1817 | 0 | received |= DRIVER_IS; |
1818 | | |
1819 | | // mark the fact that this driver has been seen |
1820 | 0 | session->drivers_identified |= (1 << session->driver_index); |
1821 | 0 | } else { |
1822 | 0 | session->lexer.counter++; |
1823 | 0 | } |
1824 | | |
1825 | | // fire the configure hook, on every packet. Seems excessive... |
1826 | 0 | if (NULL != session->device_type && |
1827 | 0 | NULL != session->device_type->event_hook) { |
1828 | 0 | session->device_type->event_hook(session, event_configure); |
1829 | 0 | } |
1830 | |
|
1831 | 0 | GPSD_LOG(LOG_RAW, &session->context->errout, |
1832 | 0 | "CORE: raw packet of type %d, %zd:%s\n", |
1833 | 0 | session->lexer.type, |
1834 | 0 | session->lexer.outbuflen, |
1835 | 0 | gpsd_prettydump(session)); |
1836 | | |
1837 | | // Get data from current packet into the fix structure |
1838 | 0 | if (COMMENT_PACKET != session->lexer.type && |
1839 | 0 | BAD_PACKET != session->lexer.type && |
1840 | 0 | NULL != session->device_type && |
1841 | 0 | NULL != session->device_type->parse_packet) { |
1842 | 0 | received |= session->device_type->parse_packet(session); |
1843 | 0 | GPSD_LOG(LOG_SPIN, &session->context->errout, |
1844 | 0 | "CORE: parse_packet() = %s\n", gps_maskdump(received)); |
1845 | 0 | } |
1846 | | |
1847 | | /* |
1848 | | * We may want to revert to the last driver that was marked |
1849 | | * sticky. What this accomplishes is that if we've just |
1850 | | * processed something like AIVDM, but a driver with control |
1851 | | * methods or an event hook had been active before that, we |
1852 | | * keep the information about those capabilities. |
1853 | | */ |
1854 | 0 | if (!STICKY(session->device_type) && |
1855 | 0 | NULL != session->last_controller && |
1856 | 0 | STICKY(session->last_controller)) { |
1857 | 0 | session->device_type = session->last_controller; |
1858 | 0 | GPSD_LOG(LOG_PROG, &session->context->errout, |
1859 | 0 | "CORE: reverted to %s driver...\n", |
1860 | 0 | session->device_type->type_name); |
1861 | 0 | } |
1862 | | |
1863 | | // are we going to generate a report? if so, count characters |
1864 | 0 | if (0 != (received & REPORT_IS)) { |
1865 | 0 | session->chars = session->lexer.char_counter - |
1866 | 0 | session->lexer.start_char; |
1867 | 0 | } |
1868 | |
|
1869 | 0 | session->gpsdata.set = ONLINE_SET | received; |
1870 | | |
1871 | | // copy/merge device data into staging buffers |
1872 | 0 | if (0 != (session->gpsdata.set & CLEAR_IS)) { |
1873 | | // CLEAR_IS should only be set on first sentence of cycle |
1874 | 0 | gps_clear_att(&session->gpsdata.attitude); |
1875 | 0 | if (0 == (session->gpsdata.set & DOP_SET)) { |
1876 | | // FIXME: put gpsdata.dop in newdata.dop |
1877 | 0 | gps_clear_dop(&session->gpsdata.dop); |
1878 | 0 | } |
1879 | 0 | gps_clear_fix(&session->gpsdata.fix); |
1880 | 0 | } |
1881 | | #ifdef __UNUSED |
1882 | | // debug |
1883 | | GPSD_LOG(LOG_SHOUT, &session->context->errout, |
1884 | | "CORE: before alt %f new %f\n", |
1885 | | session->gpsdata.fix.altMSL, |
1886 | | session->newdata.altMSL); |
1887 | | |
1888 | | GPSD_LOG(LOG_SHOUT, &session->context->errout, |
1889 | | "CORE: transfer mask: %s\n", |
1890 | | gps_maskdump(session->gpsdata.set)); |
1891 | | GPSD_LOG(LOG_SHOUT, &session->context->errout, |
1892 | | "CORE: SNARD before: status old %d new %d\n", |
1893 | | session->gpsdata.fix.status, |
1894 | | session->newdata.status); |
1895 | | #endif // __UNUSED |
1896 | 0 | gps_merge_fix(&session->gpsdata.fix, |
1897 | 0 | session->gpsdata.set, &session->newdata); |
1898 | | |
1899 | | /* |
1900 | | * Compute fix-quality data from the satellite positions. |
1901 | | * These will not overwrite any DOPs reported from the packet |
1902 | | * we just got. |
1903 | | */ |
1904 | 0 | if (0 != (received & SATELLITE_SET) && |
1905 | 0 | 0 < session->gpsdata.satellites_visible) { |
1906 | 0 | session->gpsdata.set |= fill_dop(&session->context->errout, |
1907 | 0 | &session->gpsdata, |
1908 | 0 | &session->gpsdata.dop); |
1909 | 0 | } |
1910 | |
|
1911 | 0 | gpsd_error_model(session); |
1912 | | |
1913 | | /* |
1914 | | * Count good fixes. We used to check |
1915 | | * session->gpsdata.fix.status > STATUS_UNK |
1916 | | * here, but that wasn't quite right. That tells us whether |
1917 | | * we think we have a valid fix for the current cycle, but remains |
1918 | | * true while following non-fix packets are received. What we |
1919 | | * really want to know is whether the last packet received was a |
1920 | | * fix packet AND held a valid fix. We must ignore non-fix packets |
1921 | | * AND packets which have fix data but are flagged as invalid. Some |
1922 | | * devices output fix packets on a regular basis, even when unable |
1923 | | * to derive a good fix. Such bad packets should set MODE_NO_FIX |
1924 | | */ |
1925 | 0 | if (0 != (session->gpsdata.set & (LATLON_SET|ECEF_SET))) { |
1926 | 0 | if (MODE_NO_FIX < session->gpsdata.fix.mode) { |
1927 | 0 | session->context->fixcnt++; |
1928 | 0 | session->fixcnt++; |
1929 | 0 | } else { |
1930 | 0 | session->context->fixcnt = 0; |
1931 | 0 | session->fixcnt = 0; |
1932 | 0 | } |
1933 | 0 | } else if (0 != (session->gpsdata.set & (MODE_SET))) { |
1934 | 0 | if (MODE_NO_FIX == session->gpsdata.fix.mode) { |
1935 | 0 | session->context->fixcnt = 0; |
1936 | 0 | session->fixcnt = 0; |
1937 | 0 | } |
1938 | 0 | } |
1939 | | /* |
1940 | | * Sanity check. This catches a surprising number of port and |
1941 | | * driver errors, including 32-vs.-64-bit problems. |
1942 | | */ |
1943 | 0 | if (0 != (session->gpsdata.set & TIME_SET)) { |
1944 | 0 | if (session->newdata.time.tv_sec > |
1945 | 0 | (time(NULL) + (60 * 60 * 24 * 365))) { |
1946 | 0 | GPSD_LOG(LOG_WARN, &session->context->errout, |
1947 | 0 | "CORE: date (%lld) more than a year in the future!\n", |
1948 | 0 | (long long)session->newdata.time.tv_sec); |
1949 | 0 | } else if (0 > session->newdata.time.tv_sec) { |
1950 | 0 | GPSD_LOG(LOG_ERROR, &session->context->errout, |
1951 | 0 | "CORE: date (%lld) is negative!\n", |
1952 | 0 | (long long)session->newdata.time.tv_sec); |
1953 | 0 | } |
1954 | 0 | } |
1955 | |
|
1956 | 0 | GPSD_LOG(LOG_DATA, &session->context->errout, |
1957 | 0 | "CORE: gpsd_poll(%s) %s\n", |
1958 | 0 | session->gpsdata.dev.path, |
1959 | 0 | gps_maskdump(session->gpsdata.set)); |
1960 | 0 | return session->gpsdata.set; |
1961 | 0 | } |
1962 | | |
1963 | | // consume and handle packets from a specified device |
1964 | | int gpsd_multipoll(const bool data_ready, |
1965 | | struct gps_device_t *device, |
1966 | | void (*handler)(struct gps_device_t *, gps_mask_t), |
1967 | | float reawake_time) |
1968 | 0 | { |
1969 | 0 | if (data_ready) { |
1970 | 0 | int fragments; |
1971 | | |
1972 | | // cast for 32-bit ints |
1973 | 0 | GPSD_LOG(LOG_RAW1, &device->context->errout, |
1974 | 0 | "CORE: polling %ld\n", (long)device->gpsdata.gps_fd); |
1975 | | |
1976 | | /* |
1977 | | * Strange special case - the opening transaction on an NTRIP |
1978 | | * connection may not yet be completed. |
1979 | | * Try to ratchet things forward. |
1980 | | */ |
1981 | 0 | if (SERVICE_NTRIP == device->servicetype && |
1982 | 0 | NTRIP_CONN_ESTABLISHED != device->ntrip.conn_state) { |
1983 | |
|
1984 | 0 | timespec_t ts_now; |
1985 | 0 | double step; |
1986 | |
|
1987 | 0 | (void)clock_gettime(CLOCK_REALTIME, &ts_now); |
1988 | |
|
1989 | 0 | step = TS_SUB_D(&ts_now, &device->ntrip.stream.stream_time); |
1990 | | // wait 6 seconds between hitting ntrip_open() |
1991 | 0 | if (6 > fabs(step)) { |
1992 | 0 | return DEVICE_UNCHANGED; |
1993 | 0 | } |
1994 | 0 | device->ntrip.stream.stream_time = ts_now; |
1995 | 0 | (void)ntrip_open(device, ""); |
1996 | 0 | if (NTRIP_CONN_ERR == device->ntrip.conn_state) { |
1997 | 0 | GPSD_LOG(LOG_WARN, &device->context->errout, |
1998 | 0 | "CORE: connection to ntrip server failed\n"); |
1999 | | // FIXME: next stat after error should depend on if |
2000 | | // initial connect or reconenct... |
2001 | 0 | device->ntrip.conn_state = NTRIP_CONN_CLOSED; |
2002 | 0 | return DEVICE_ERROR; |
2003 | 0 | } |
2004 | | // else |
2005 | 0 | return DEVICE_READY; |
2006 | 0 | } |
2007 | | |
2008 | 0 | for (fragments = 0; ; fragments++) { |
2009 | 0 | gps_mask_t changed = gpsd_poll(device); |
2010 | |
|
2011 | 0 | if (EOF_IS == changed) { |
2012 | 0 | GPSD_LOG(LOG_WARN, &device->context->errout, |
2013 | 0 | "CORE: device signed off %s\n", |
2014 | 0 | device->gpsdata.dev.path); |
2015 | 0 | return DEVICE_EOF; |
2016 | 0 | } |
2017 | 0 | if (ERROR_SET == changed) { |
2018 | 0 | GPSD_LOG(LOG_WARN, &device->context->errout, |
2019 | 0 | "CORE: device read of %s returned error or " |
2020 | 0 | "packet sniffer failed sync (flags %s)\n", |
2021 | 0 | device->gpsdata.dev.path, |
2022 | 0 | gps_maskdump(changed)); |
2023 | 0 | return DEVICE_ERROR; |
2024 | 0 | } |
2025 | 0 | if (NODATA_IS == changed) { |
2026 | | /* |
2027 | | * No data on the first fragment read means the device |
2028 | | * fd may have been in an end-of-file condition on select. |
2029 | | */ |
2030 | 0 | if (0 == fragments) { |
2031 | 0 | GPSD_LOG(LOG_DATA, &device->context->errout, |
2032 | 0 | "CORE: %s returned zero bytes\n", |
2033 | 0 | device->gpsdata.dev.path); |
2034 | 0 | if (device->zerokill) { |
2035 | | // failed timeout-and-reawake, kill it |
2036 | 0 | gpsd_deactivate(device); |
2037 | 0 | if (device->ntrip.works) { |
2038 | | // reset so we try this once only |
2039 | 0 | device->ntrip.works = false; |
2040 | 0 | if (0 > gpsd_activate(device, O_CONTINUE)) { |
2041 | 0 | GPSD_LOG(LOG_WARN, &device->context->errout, |
2042 | 0 | "CORE: reconnect to ntrip server " |
2043 | 0 | "failed\n"); |
2044 | 0 | return DEVICE_ERROR; |
2045 | 0 | } |
2046 | | // else |
2047 | 0 | GPSD_LOG(LOG_INF, &device->context->errout, |
2048 | 0 | "CORE: reconnecting to ntrip server\n"); |
2049 | 0 | return DEVICE_READY; |
2050 | 0 | } |
2051 | 0 | } else if (0 == reawake_time) { |
2052 | 0 | return DEVICE_ERROR; |
2053 | 0 | } else { |
2054 | | /* |
2055 | | * Disable listening to this fd for long enough |
2056 | | * that the buffer can fill up again. |
2057 | | */ |
2058 | 0 | GPSD_LOG(LOG_DATA, &device->context->errout, |
2059 | 0 | "CORE: %s will be repolled in %f seconds\n", |
2060 | 0 | device->gpsdata.dev.path, reawake_time); |
2061 | 0 | device->reawake = time(NULL) + reawake_time; |
2062 | 0 | return DEVICE_UNREADY; |
2063 | 0 | } |
2064 | 0 | } |
2065 | | /* |
2066 | | * No data on later fragment reads just means the |
2067 | | * input buffer is empty. In this case break out |
2068 | | * of the fragment-processing loop but consider |
2069 | | * the device still good. |
2070 | | */ |
2071 | 0 | break; |
2072 | 0 | } |
2073 | | |
2074 | | // we got actual data, head off the reawake special case |
2075 | 0 | device->zerokill = false; |
2076 | 0 | device->reawake = (time_t)0; |
2077 | | |
2078 | | // must have a full packet to continue |
2079 | 0 | if (0 == (changed & PACKET_SET)) { |
2080 | 0 | break; |
2081 | 0 | } |
2082 | | |
2083 | | // conditional prevents mask dumper from eating CPU |
2084 | 0 | if (LOG_DATA <= device->context->errout.debug) { |
2085 | 0 | if (BAD_PACKET == device->lexer.type) { |
2086 | 0 | GPSD_LOG(LOG_DATA, &device->context->errout, |
2087 | 0 | "CORE: packet with bad checksum from %s\n", |
2088 | 0 | device->gpsdata.dev.path); |
2089 | 0 | } else { |
2090 | 0 | GPSD_LOG(LOG_DATA, &device->context->errout, |
2091 | 0 | "CORE: packet type %d from %s with %s\n", |
2092 | 0 | device->lexer.type, |
2093 | 0 | device->gpsdata.dev.path, |
2094 | 0 | gps_maskdump(device->gpsdata.set)); |
2095 | 0 | } |
2096 | 0 | } |
2097 | | |
2098 | | |
2099 | | // handle data contained in this packet |
2100 | 0 | if (BAD_PACKET != device->lexer.type) { |
2101 | 0 | handler(device, changed); |
2102 | 0 | } |
2103 | |
|
2104 | | #ifdef __future__ |
2105 | | // this breaks: test/daemon/passthrough.log ?? |
2106 | | /* |
2107 | | * Bernd Ocklin suggests: |
2108 | | * Exit when a full packet was received and parsed. |
2109 | | * This allows other devices to be serviced even if |
2110 | | * this device delivers a full packet at every single |
2111 | | * read. |
2112 | | * Otherwise we can sit here for a long time without |
2113 | | * any for-loop exit condition being met. |
2114 | | * It might also reduce the latency from a received packet to |
2115 | | * it being output by gpsd. |
2116 | | */ |
2117 | | if (0 != (changed & PACKET_SET)) { |
2118 | | break; |
2119 | | } |
2120 | | #endif // __future__ |
2121 | 0 | } |
2122 | 0 | } else if (0 < device->reawake && |
2123 | 0 | time(NULL) > device->reawake) { |
2124 | | // FIXME: what if time went backward? |
2125 | | // device may have had a zero-length read |
2126 | 0 | GPSD_LOG(LOG_DATA, &device->context->errout, |
2127 | 0 | "CORE: %s reawakened after zero-length read\n", |
2128 | 0 | device->gpsdata.dev.path); |
2129 | 0 | device->reawake = (time_t)0; |
2130 | 0 | device->zerokill = true; |
2131 | 0 | return DEVICE_READY; |
2132 | 0 | } else if (SERVICE_NTRIP == device->servicetype && |
2133 | 0 | NTRIP_CONN_INPROGRESS == device->ntrip.conn_state) { |
2134 | |
|
2135 | 0 | timespec_t ts_now; |
2136 | 0 | double step; |
2137 | |
|
2138 | 0 | (void)clock_gettime(CLOCK_REALTIME, &ts_now); |
2139 | |
|
2140 | 0 | step = TS_SUB_D(&ts_now, &device->ntrip.stream.stream_time); |
2141 | | // wait 6 seconds between hitting ntrip_open() |
2142 | 0 | if (6 > fabs(step)) { |
2143 | 0 | return DEVICE_UNCHANGED; |
2144 | 0 | } |
2145 | 0 | device->ntrip.stream.stream_time = ts_now; |
2146 | 0 | (void)ntrip_open(device, ""); |
2147 | 0 | if (NTRIP_CONN_ERR == device->ntrip.conn_state) { |
2148 | 0 | GPSD_LOG(LOG_WARN, &device->context->errout, |
2149 | 0 | "CORE: 2 connection to ntrip server failed\n"); |
2150 | | // FIXME: next stat after error should depend on if |
2151 | | // initial connect or reconenct... |
2152 | 0 | device->ntrip.conn_state = NTRIP_CONN_CLOSED; |
2153 | 0 | return DEVICE_ERROR; |
2154 | 0 | } |
2155 | | // else |
2156 | 0 | return DEVICE_READY; |
2157 | 0 | } |
2158 | | |
2159 | | // no change in device descriptor state |
2160 | 0 | return DEVICE_UNCHANGED; |
2161 | 0 | } |
2162 | | |
2163 | | // end-of-session wrapup |
2164 | | void gpsd_wrap(struct gps_device_t *session) |
2165 | 0 | { |
2166 | 0 | if (!BAD_SOCKET(session->gpsdata.gps_fd)) { |
2167 | 0 | gpsd_deactivate(session); |
2168 | 0 | } |
2169 | 0 | } |
2170 | | |
2171 | | /* gpsd_zero_satellites(), initialize the skyview (satellite_t) |
2172 | | * |
2173 | | * return; void |
2174 | | */ |
2175 | | void gpsd_zero_satellites( struct gps_data_t *out) |
2176 | 0 | { |
2177 | 0 | int sat; |
2178 | |
|
2179 | 0 | (void)memset(out->skyview, '\0', sizeof(out->skyview)); |
2180 | 0 | out->satellites_visible = 0; |
2181 | | // zero is good inbound data for ss, elevation, and azimuth. |
2182 | | // we need to set them to invalid values |
2183 | 0 | for ( sat = 0; sat < MAXCHANNELS; sat++ ) { |
2184 | 0 | out->skyview[sat].azimuth = NAN; |
2185 | 0 | out->skyview[sat].elevation = NAN; |
2186 | 0 | out->skyview[sat].ss = NAN; |
2187 | 0 | out->skyview[sat].prRes = NAN; |
2188 | 0 | out->skyview[sat].freqid = -1; |
2189 | 0 | out->skyview[sat].qualityInd = -1; |
2190 | 0 | } |
2191 | | #if 0 |
2192 | | /* |
2193 | | * We used to clear DOPs here, but this causes misbehavior on some |
2194 | | * combined GPS/GLONASS/QZSS receivers like the Telit SL869; the |
2195 | | * symptom is that the "satellites_used" field in a struct gps_data_t |
2196 | | * filled in by gps_read() is always zero. |
2197 | | */ |
2198 | | gps_clear_dop(&out->dop); |
2199 | | #endif |
2200 | 0 | } |
2201 | | |
2202 | | /* Latch the fact that we've saved a fix. |
2203 | | * And add in the device fudge */ |
2204 | | void ntp_latch(struct gps_device_t *device, struct timedelta_t *td) |
2205 | 0 | { |
2206 | | |
2207 | | // this should be an invariant of the way this function is called |
2208 | 0 | if (0 >= device->newdata.time.tv_sec) { |
2209 | 0 | return; |
2210 | 0 | } |
2211 | | |
2212 | 0 | (void)clock_gettime(CLOCK_REALTIME, &td->clock); |
2213 | | // structure copy of time from GPS |
2214 | 0 | td->real = device->newdata.time; |
2215 | | |
2216 | | // is there an offset method? |
2217 | 0 | if (NULL != device->device_type && |
2218 | 0 | NULL != device->device_type->time_offset) { |
2219 | 0 | double integral; |
2220 | 0 | double offset = device->device_type->time_offset(device); |
2221 | | |
2222 | | // add in offset which is double |
2223 | 0 | td->real.tv_nsec += (long)(modf(offset, &integral) * 1e9); |
2224 | 0 | td->real.tv_sec += (time_t)integral; |
2225 | 0 | TS_NORM(&td->real); |
2226 | 0 | } |
2227 | | |
2228 | | // thread-safe update |
2229 | 0 | pps_thread_fixin(&device->pps_thread, td); |
2230 | 0 | } |
2231 | | |
2232 | | // end |
2233 | | // vim: set expandtab shiftwidth=4 |