Coverage Report

Created: 2024-02-25 06:36

/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