Coverage Report

Created: 2026-10-10 07:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gpsd/gpsd-3.27.6~dev/drivers/drivers.c
Line
Count
Source
1
/*
2
 * This file is Copyright by the GPSD project
3
 * SPDX-License-Identifier: BSD-2-clause
4
 */
5
6
#include "../include/gpsd_config.h"  // must be before all includes
7
8
#include <assert.h>
9
#include <ctype.h>
10
#include <stdarg.h>
11
#include <stdbool.h>
12
#include <stdio.h>
13
#include <stdlib.h>
14
#include <string.h>
15
#include <unistd.h>
16
17
#include "../include/bits.h"    // for getbeu16(), to extract big-endian words
18
#include "../include/compiler.h"   // for FALLTHROUGH
19
#include "../include/gpsd.h"
20
#include "../include/strfuncs.h"
21
22
// This handles only bad, comment, and maybe NMEA packets.
23
gps_mask_t generic_parse_input(struct gps_device_t *session)
24
33.1k
{
25
33.1k
    if (BAD_PACKET == session->lexer.type ||
26
33.1k
        COMMENT_PACKET == session->lexer.type) {
27
        // ignore bad packets and comment packets
28
0
        return 0;
29
0
    }
30
31
33.1k
    if (NMEA_PACKET == session->lexer.type) {
32
32.8k
        const struct gps_type_t **dp;
33
32.8k
        gps_mask_t st = 0;
34
32.8k
        char *sentence = (char *)session->lexer.outbuffer;
35
36
32.8k
        if ('\n' != sentence[strnlen(sentence,
37
32.8k
                                     sizeof(session->lexer.outbuffer)) - 1]) {
38
1.39k
            GPSD_LOG(LOG_IO, &session->context->errout,
39
1.39k
                     "<= GPS: %s\n", sentence);
40
31.4k
        } else {
41
31.4k
            GPSD_LOG(LOG_IO, &session->context->errout,
42
31.4k
                     "<= GPS: %s", sentence);
43
31.4k
        }
44
45
32.8k
        if (0 == (st=nmea_parse(sentence, session))) {
46
0
            GPSD_LOG(LOG_WARN, &session->context->errout,
47
0
                     "unknown sentence: \"%s\"\n", sentence);
48
0
        }
49
1.21M
        for (dp = gpsd_drivers; *dp; dp++) {
50
1.18M
            char *trigger = (*dp)->trigger;
51
52
1.18M
            if (NULL != trigger &&
53
295k
                str_starts_with(sentence, trigger)) {
54
2.19k
                GPSD_LOG(LOG_PROG, &session->context->errout,
55
2.19k
                         "found trigger string %s.\n", trigger);
56
2.19k
                if (*dp != session->device_type) {
57
1.79k
                    (void)gpsd_switch_driver(session, (*dp)->type_name);
58
1.79k
                    if (NULL != session->device_type &&
59
1.79k
                        NULL != session->device_type->event_hook) {
60
1.72k
                        session->device_type->event_hook(session,
61
1.72k
                                                         EVENT_TRIGGERMATCH);
62
1.72k
                    st |= DEVICEID_SET;
63
1.72k
                    }
64
1.79k
                }
65
2.19k
            }
66
1.18M
        }
67
32.8k
        return st;
68
32.8k
    }
69
70
336
    GPSD_LOG(LOG_SHOUT, &session->context->errout,
71
336
             "packet type %d fell through (should never happen): %s.\n",
72
336
             session->lexer.type, gpsd_prettydump(session));
73
336
    return 0;
74
33.1k
}
75
76
/**************************************************************************
77
 *
78
 * Generic driver -- make no assumptions about the device type
79
 *
80
 **************************************************************************/
81
82
// *INDENT-OFF*
83
const struct gps_type_t driver_unknown = {
84
    .type_name      = "Unknown",        // full name of type
85
    .packet_type    = COMMENT_PACKET,   // associated lexer packet type
86
    .flags          = DRIVER_NOFLAGS,   // no flags set
87
    .trigger        = NULL,             // it's the default
88
    .channels       = 12,               // consumer-grade GPS
89
    .probe_detect   = NULL,             // no probe
90
    .get_packet     = packet_get1,      // use generic packet getter
91
    .parse_packet   = generic_parse_input,      // how to interpret a packet
92
    .rtcm_writer    = NULL,             // write RTCM data straight
93
    .init_query     = NULL,             // non-perturbing initial query
94
    .event_hook     = NULL,             // lifetime event handler
95
    .speed_switcher = NULL,             // no speed switcher
96
    .mode_switcher  = NULL,             // no mode switcher
97
    .rate_switcher  = NULL,             // no sample-rate switcher
98
    .min_cycle.tv_sec  = 1,             // not relevant, no rate switch
99
    .min_cycle.tv_nsec = 0,             // not relevant, no rate switch
100
    .control_send   = NULL,             // how to send control strings
101
    .time_offset     = NULL,            // no method for NTP fudge factor
102
};
103
// *INDENT-ON*
104
105
/**************************************************************************
106
 *
107
 * NMEA 0183
108
 *
109
 * This is separate from the 'unknown' driver because we don't want to
110
 * ship NMEA subtype probe strings to a device until we've seen at
111
 * least one NMEA packet.  This avoids spamming devices that might
112
 * actually be USB modems or other things in USB device class FF that
113
 * just happen to have one of 'our' adaptor chips in front of them.
114
 *
115
 **************************************************************************/
116
117
static void nmea_event_hook(struct gps_device_t *session, event_t event)
118
38.6k
{
119
38.6k
    if (session->context->readonly) {
120
13.9k
        return;
121
13.9k
    }
122
    /*
123
     * This is where we try to tickle NMEA devices into revealing their
124
     * inner natures.
125
     */
126
24.6k
    if (event == EVENT_CONFIGURE) {
127
        /*
128
         * The reason for splitting these probes up by packet sequence
129
         * number, interleaving them with the first few packet receives,
130
         * is because many generic-NMEA devices get confused if you send
131
         * too much at them in one go.
132
         *
133
         * A fast response to an early probe will change drivers so the
134
         * later ones won't be sent at all.  Thus, for best overall
135
         * performance, order these to probe for the most popular types
136
         * soonest.
137
         *
138
         * Note: don't make the trigger strings identical to the probe,
139
         * because some NMEA devices (notably SiRFs) will just echo
140
         * unknown strings right back at you. A useful dodge is to append
141
         * a comma to the trigger, because that won't be in the response
142
         * unless there is actual following data.
143
         */
144
21.7k
        switch (session->lexer.counter) {
145
502
        case 0:
146
            // probe for Garmin serial GPS -- expect $PGRMC followed by data
147
502
            GPSD_LOG(LOG_PROG, &session->context->errout,
148
502
                     "=> Probing for Garmin NMEA\n");
149
502
            (void)nmea_send(session, "$PGRMCE");
150
502
            break;
151
0
#ifdef SIRF_ENABLE
152
3.54k
        case 1:
153
            /*
154
             * We used to try to probe for SiRF by issuing
155
             * "$PSRF105,1" and expecting "$Ack Input105.".  But it
156
             * turns out this only works for SiRF-IIs; SiRF-I and
157
             * SiRF-III don't respond.  Sadly, the MID132 binary
158
             * request for firmware version is ignored in NMEA mode.
159
             * Thus the only reliable probe is to try to flip the SiRF
160
             * into binary mode, cluing in the library to revert it on
161
             * close.
162
             *
163
             * SiRFs dominate the consumer-grade GPS-mouse market, so
164
             * we used to put this test first. Unfortunately this
165
             * causes problems for gpsctl, as it cannot select the
166
             * NMEA driver without switching the device back to binary
167
             * mode!  Fix this if we ever find a nondisruptive probe
168
             * string.
169
             */
170
3.54k
            GPSD_LOG(LOG_PROG, &session->context->errout,
171
3.54k
                     "=> Probing for SiRF\n");
172
3.54k
            (void)nmea_send(session,
173
3.54k
                            "$PSRF100,0,%d,%d,%d,0",
174
3.54k
                            session->gpsdata.dev.baudrate,
175
3.54k
                            9 - session->gpsdata.dev.stopbits,
176
3.54k
                            session->gpsdata.dev.stopbits);
177
3.54k
            break;
178
0
#endif  // SIRF_ENABLE
179
1.63k
        case 2:
180
            // probe for the FV-18 -- expect $PFEC,GPint followed by data
181
1.63k
            GPSD_LOG(LOG_PROG, &session->context->errout,
182
1.63k
                     "=> Probing for FV-18\n");
183
1.63k
            (void)nmea_send(session, "$PFEC,GPint");
184
1.63k
            break;
185
1.36k
        case 3:
186
            // probe for the Trimble Copernicus
187
1.36k
            GPSD_LOG(LOG_PROG, &session->context->errout,
188
1.36k
                     "=> Probing for Trimble Copernicus\n");
189
1.36k
            (void)nmea_send(session, "$PTNLSNM,0139,01");
190
1.36k
            break;
191
0
#ifdef EVERMORE_ENABLE
192
1.07k
        case 4:
193
1.07k
            GPSD_LOG(LOG_PROG, &session->context->errout,
194
1.07k
                     "=> Probing for Evermore\n");
195
            // FIXME: not passive compatible
196
            /* Enable checksum and GGA(1s), GLL(0s), GSA(1s), GSV(1s),
197
             * RMC(1s), VTG(0s), PEMT101(0s)
198
             * EverMore will reply with: \x10\x02\x04\x38\x8E\xC6\x10\x03 */
199
1.07k
            (void)gpsd_write(session,
200
1.07k
                             "\x10\x02\x12\x8E\x7F\x01\x01\x00\x01\x01\x01"
201
1.07k
                             "\x00\x00\x00\x00\x00\x00\x00\x00\x13\x10\x03",
202
1.07k
                             22);
203
1.07k
            break;
204
0
#endif  // EVERMORE_ENABLE
205
0
#ifdef GPSCLOCK_ENABLE
206
883
        case 5:
207
            /* probe for Furuno Electric GH-79L4-N (GPSClock);
208
             * expect $PFEC,GPssd */
209
883
            GPSD_LOG(LOG_PROG, &session->context->errout,
210
883
                     "=> Probing for GPSClock\n");
211
883
            (void)nmea_send(session, "$PFEC,GPsrq");
212
883
            break;
213
0
#endif  // GPSCLOCK_ENABLE
214
848
        case 6:
215
            // probe for Ashtech -- expect $PASHR,RID
216
848
            GPSD_LOG(LOG_PROG, &session->context->errout,
217
848
                     "=> Probing for Ashtech\n");
218
848
            (void)nmea_send(session, "$PASHQ,RID");
219
848
            break;
220
788
        case 7:
221
            // probe for UBX
222
788
            GPSD_LOG(LOG_PROG, &session->context->errout,
223
788
                     "=> Probing for UBX\n");
224
            // query port configuration UBX-MON-VER
225
788
            (void)ubx_write(session, 0x0a, 0x04, NULL, 0);
226
            // query port configuration UBX-CFG-PRT
227
788
            (void)ubx_write(session, 0x06, 0x00, NULL, 0);
228
788
            break;
229
744
        case 8:
230
            // probe for MTK-3301 -- expect $PMTK705
231
744
            GPSD_LOG(LOG_PROG, &session->context->errout,
232
744
                     "=> Probing for MediaTek\n");
233
744
            (void)nmea_send(session, "$PMTK605");
234
744
            break;
235
0
#ifdef GREIS_ENABLE
236
577
        case 9:
237
            // probe for Javad GREIS -- expect reply with JAVAD
238
577
            GPSD_LOG(LOG_PROG, &session->context->errout,
239
577
                     "=> Probing for Javad GREIS\n");
240
            // TODO: confirm this actually gets JAVAD response
241
577
            (void)nmea_send(session, "print,/par/rcv/vendor");
242
577
            break;
243
0
#endif  // GREIS_ENABLE
244
538
        case 10:
245
            // probe for ALLYSTAR
246
538
            GPSD_LOG(LOG_PROG, &session->context->errout,
247
538
                     "=> Probing for ALLYSTAR\n");
248
            // query version MON-VER
249
538
            (void)ally_write(session, 0x0a, 0x04, NULL, 0);
250
538
            break;
251
517
        case 11:
252
            // probe for CASIC
253
517
            GPSD_LOG(LOG_PROG, &session->context->errout,
254
517
                     "=> Probing for CASIC\n");
255
            // query version MON-VER
256
517
            (void)casic_write(session, 0x0a, 0x04, NULL, 0);
257
517
            break;
258
8.70k
        default:
259
8.70k
            break;
260
21.7k
        }
261
21.7k
    }
262
24.6k
}
263
264
// *INDENT-OFF*
265
const struct gps_type_t driver_nmea0183 = {
266
    .type_name      = "NMEA0183",       // full name of type
267
    .packet_type    = NMEA_PACKET,      // associated lexer packet type
268
    .flags          = DRIVER_NOFLAGS,   // remember this
269
    .trigger        = NULL,             // it's the default
270
    .channels       = 12,               // consumer-grade GPS
271
    .probe_detect   = NULL,             // no probe
272
    .get_packet     = packet_get1,      // use generic packet getter
273
    .parse_packet   = generic_parse_input,      // how to interpret a packet
274
    .rtcm_writer    = gpsd_write,       // write RTCM data straight
275
    .init_query     = NULL,             // non-perturbing initial query
276
    .event_hook     = nmea_event_hook,  // lifetime event handler
277
    .speed_switcher = NULL,             // no speed switcher
278
    .mode_switcher  = NULL,             // maybe switchable if it was a SiRF
279
    .rate_switcher  = NULL,             // no sample-rate switcher
280
    .min_cycle.tv_sec  = 1,             // not relevant, no rate switch
281
    .min_cycle.tv_nsec = 0,             // not relevant, no rate switch
282
    .control_send   = nmea_write,       // how to send control strings
283
    .time_offset     = NULL,            // no method for NTP fudge factor
284
};
285
// *INDENT-ON*
286
287
#if defined(GARMIN_ENABLE)
288
/**************************************************************************
289
 *
290
 * Garmin NMEA
291
 *
292
 **************************************************************************/
293
294
// only does anything in one direction, going to Garmin binary driver
295
static void garmin_mode_switch(struct gps_device_t *session, int mode)
296
0
{
297
0
    struct timespec delay;
298
299
0
    if (mode == MODE_BINARY) {
300
0
        (void)nmea_send(session, "$PGRMC1,1,2,1,,,,2,W,N");
301
0
        (void)nmea_send(session, "$PGRMI,,,,,,,R");
302
        // wait 333 uSec, standard Garmin settling time
303
0
        delay.tv_sec = 0;
304
0
        delay.tv_nsec = 333000L;
305
0
        nanosleep(&delay, NULL);
306
0
    }
307
0
}
308
309
static void garmin_nmea_event_hook(struct gps_device_t *session,
310
                                   event_t event)
311
2.30k
{
312
2.30k
    if (session->context->readonly) {
313
216
        return;
314
216
    }
315
316
2.08k
    if (event == EVENT_DRIVER_SWITCH) {
317
        // forces a reconfigure as the following packets come in
318
555
        session->lexer.counter = 0;
319
555
    }
320
2.08k
    if (session->context->passive) {
321
103
        return;
322
103
    }
323
1.98k
    if (event == EVENT_CONFIGURE) {
324
        /*
325
         * And here's that reconfigure.  It's split up like this because
326
         * receivers like the Garmin GPS-10 don't handle having having a lot of
327
         * probes shoved at them very well.
328
         */
329
908
        switch (session->lexer.counter) {
330
0
        case 0:
331
            /* reset some config, AutoFix, WGS84, PPS
332
             * Set the PPS pulse length to 40ms which leaves the Garmin 18-5hz
333
             * with a 160ms low state.
334
             * NOTE: new PPS only takes effect after next power cycle
335
             */
336
0
            (void)nmea_send(session, "$PGRMC,A,,100,,,,,,A,,1,2,1,30");
337
0
            break;
338
374
        case 1:
339
            // once a sec, no averaging, NMEA 2.3, WAAS
340
374
            (void)nmea_send(session, "$PGRMC1,1,1,1,,,,2,W,N");
341
374
            break;
342
153
        case 2:
343
            // get some more config info
344
153
            (void)nmea_send(session, "$PGRMC1E");
345
153
            break;
346
114
        case 3:
347
            // turn off all output except GGA
348
114
            (void)nmea_send(session, "$PGRMO,,2");
349
114
            (void)nmea_send(session, "$PGRMO,GPGGA,1");
350
114
            break;
351
79
        case 4:
352
            // enable GPGGA, GPGSA, GPGSV, GPRMC on Garmin serial GPS
353
79
            (void)nmea_send(session, "$PGRMO,GPGSA,1");
354
79
            break;
355
35
        case 5:
356
35
            (void)nmea_send(session, "$PGRMO,GPGSV,1");
357
35
            break;
358
34
        case 6:
359
34
            (void)nmea_send(session, "$PGRMO,GPRMC,1");
360
34
            break;
361
29
        case 7:
362
29
            (void)nmea_send(session, "$PGRMO,PGRME,1");
363
29
            break;
364
908
        }
365
908
    }
366
1.98k
}
367
368
// *INDENT-OFF*
369
const struct gps_type_t driver_garmin = {
370
    .type_name      = "Garmin NMEA",    // full name of type
371
    .packet_type    = NMEA_PACKET,      // associated lexer packet type
372
    .flags          = DRIVER_STICKY,    // remember this
373
    .trigger        = "$PGRMC,",        // Garmin private
374
    .channels       = 12,               // not used by this driver
375
    .probe_detect   = NULL,             // no probe
376
    .get_packet     = packet_get1,      // use generic packet getter
377
    .parse_packet   = generic_parse_input,      // how to interpret a packet
378
    .rtcm_writer    = NULL,             // some do, some don't, skip for now
379
    .init_query     = NULL,             // non-perturbing initial query
380
    .event_hook     = garmin_nmea_event_hook,   // lifetime event handler
381
    .speed_switcher = NULL,                     // no speed switcher
382
    .mode_switcher  = garmin_mode_switch,       // mode switcher
383
    .rate_switcher  = NULL,             // no sample-rate switcher
384
    .min_cycle.tv_sec  = 1,             // not relevant, no rate switch
385
    .min_cycle.tv_nsec = 0,             // not relevant, no rate switch
386
    .control_send   = nmea_write,       // how to send control strings
387
    .time_offset     = NULL,            // no method for NTP fudge factor
388
};
389
// *INDENT-ON*
390
#endif  // GARMIN_ENABLE
391
392
/**************************************************************************
393
 *
394
 * Inertial Sense
395
 * https://inertialsense.com/
396
 * Note that many of the IS "NMEA" messages are too long, non-standard,
397
 * or just broken.
398
 *
399
 **************************************************************************/
400
static void is_event_hook(struct gps_device_t *session, event_t event)
401
0
{
402
0
    if (session->context->readonly) {
403
0
        return;
404
0
    }
405
406
0
    if (event == EVENT_WAKEUP) {
407
        /* probe for device, which is quiet by default
408
         * $INFO is not a valid NMEA message type, public or proprietary */
409
0
        (void)nmea_send(session, "$INFO");
410
0
    }
411
412
0
    if (session->context->passive) {
413
0
        return;
414
0
    }
415
0
    if (event == EVENT_IDENTIFIED) {
416
        // enable some "NMEA", at 5Hz
417
0
        (void)nmea_send(session, "$ASCE,0,6,1,7,1,8,1,10,1,11,1,15,1");
418
0
    }
419
0
}
420
421
// *INDENT-OFF*
422
const struct gps_type_t driver_is = {
423
    .type_name      = "InertialSense",  // full name of type
424
    .packet_type    = NMEA_PACKET,      // associated lexer packet type
425
    .flags          = DRIVER_STICKY,    // remember this
426
    .trigger        = NULL,
427
    .channels       = 24,               // not used, unknown channels
428
    .probe_detect   = NULL,             // no probe
429
    .get_packet     = packet_get1,      // how to get a packet
430
    .parse_packet   = generic_parse_input,      // how to interpret a packet
431
    .rtcm_writer    = gpsd_write,       // write RTCM data straight
432
    .init_query     = NULL,             // non-perturbing initial query
433
    .event_hook     = is_event_hook,    // lifetime event handler
434
    .speed_switcher = NULL,             // no speed switcher
435
    .mode_switcher  = NULL,             // no mode switcher
436
    .rate_switcher  = NULL,             // no sample-rate switcher
437
    .min_cycle.tv_sec  = 1,             // not relevant, no rate switch
438
    .min_cycle.tv_nsec = 0,             // not relevant, no rate switch
439
    .control_send   = nmea_write,       // how to send control strings
440
    .time_offset     = NULL,            // no method for NTP fudge factor
441
};
442
/**************************************************************************
443
 *
444
 * Ashtech (then Thales, now Magellan Professional) Receivers
445
 *
446
 **************************************************************************/
447
448
static void ashtech_event_hook(struct gps_device_t *session, event_t event)
449
310
{
450
310
    if (session->context->readonly) {
451
69
        return;
452
69
    }
453
454
241
    if (event == EVENT_WAKEUP) {
455
0
        (void)nmea_send(session, "$PASHQ,RID");
456
0
    }
457
458
241
    if (session->context->passive) {
459
65
        return;
460
65
    }
461
176
    if (event == EVENT_IDENTIFIED) {
462
        // turn WAAS on. can't hurt...
463
0
        (void)nmea_send(session, "$PASHS,WAS,ON");
464
        // reset to known output state
465
0
        (void)nmea_send(session, "$PASHS,NME,ALL,A,OFF");
466
        // then turn on some useful sentences
467
#ifdef __future__
468
        // we could parse these, but they're oversize so they get dropped
469
        (void)nmea_send(session, "$PASHS,NME,POS,A,ON");
470
        (void)nmea_send(session, "$PASHS,NME,SAT,A,ON");
471
#else
472
0
        (void)nmea_send(session, "$PASHS,NME,GGA,A,ON");
473
0
        (void)nmea_send(session, "$PASHS,NME,GSA,A,ON");
474
0
        (void)nmea_send(session, "$PASHS,NME,GSV,A,ON");
475
0
        (void)nmea_send(session, "$PASHS,NME,RMC,A,ON");
476
0
#endif
477
0
        (void)nmea_send(session, "$PASHS,NME,ZDA,A,ON");
478
0
    }
479
176
}
480
481
const struct gps_type_t driver_ashtech = {
482
    .type_name      = "Ashtech",        // full name of type
483
    .packet_type    = NMEA_PACKET,      // associated lexer packet type
484
    .flags          = DRIVER_STICKY,    // remember this
485
    .trigger        = "$PASHR,RID,",    // Ashtech receivers respond thus
486
    .channels       = 24,               // not used, GG24 has 24 channels
487
    .probe_detect   = NULL,             // no probe
488
    .get_packet     = packet_get1,      // how to get a packet
489
    .parse_packet   = generic_parse_input,      // how to interpret a packet
490
    .rtcm_writer    = gpsd_write,       // write RTCM data straight
491
    .init_query     = NULL,             // non-perturbing initial query
492
    .event_hook     = ashtech_event_hook, // lifetime event handler
493
    .speed_switcher = NULL,             // no speed switcher
494
    .mode_switcher  = NULL,             // no mode switcher
495
    .rate_switcher  = NULL,             // no sample-rate switcher
496
    .min_cycle.tv_sec  = 1,             // not relevant, no rate switch
497
    .min_cycle.tv_nsec = 0,             // not relevant, no rate switch
498
    .control_send   = nmea_write,       // how to send control strings
499
    .time_offset     = NULL,            // no method for NTP fudge factor
500
};
501
// *INDENT-ON*
502
503
#ifdef FV18_ENABLE
504
/**************************************************************************
505
 *
506
 * FV18 -- uses 2 stop bits, needs to be told to send GSAs
507
 *
508
 **************************************************************************/
509
510
static void fv18_event_hook(struct gps_device_t *session, event_t event)
511
133
{
512
133
    if (session->context->readonly) {
513
65
        return;
514
65
    }
515
516
    /*
517
     * Tell an FV18 to send GSAs so we'll know if 3D is accurate.
518
     * Suppress GLL and VTG.  Enable ZDA so dates will be accurate for replay.
519
     * It's possible we might not need to redo this on event_reactivate,
520
     * but doing so is safe and cheap.
521
     */
522
68
    if (event == EVENT_IDENTIFIED ||
523
68
        event == EVENT_REACTIVATE) {
524
0
        (void)nmea_send(session,
525
0
                        "$PFEC,GPint,GSA01,DTM00,ZDA01,RMC01,GLL00,VTG00,GSV05");
526
0
    }
527
68
}
528
529
// *INDENT-OFF*
530
const struct gps_type_t driver_fv18 = {
531
    .type_name      = "San Jose Navigation FV18",       // full name of type
532
    .packet_type    = NMEA_PACKET,      // associated lexer packet type
533
    .flags          = DRIVER_STICKY,    // remember this
534
    .trigger        = "$PFEC,GPint,",   // FV18s should echo the probe
535
    .channels       = 12,               // not used by this driver
536
    .probe_detect   = NULL,             // no probe
537
    .get_packet     = packet_get1,      // how to get a packet
538
    .parse_packet   = generic_parse_input,      // how to interpret a packet
539
    .rtcm_writer    = gpsd_write,       // write RTCM data straight
540
    .init_query     = NULL,             // non-perturbing initial query
541
    .event_hook     = fv18_event_hook,  // lifetime event handler
542
    .speed_switcher = NULL,             // no speed switcher
543
    .mode_switcher  = NULL,             // no mode switcher
544
    .rate_switcher  = NULL,             // no sample-rate switcher
545
    .min_cycle.tv_sec  = 1,             // not relevant, no rate switch
546
    .min_cycle.tv_nsec = 0,             // not relevant, no rate switch
547
    .control_send   = nmea_write,       // how to send control strings
548
    .time_offset     = NULL,            // no method for NTP fudge factor
549
};
550
// *INDENT-ON*
551
#endif  // FV18_ENABLE
552
553
#ifdef GPSCLOCK_ENABLE
554
/**************************************************************************
555
 *
556
 * Furuno Electric GPSClock (GH-79L4)
557
 *
558
 **************************************************************************/
559
560
/*
561
 * Based on http://www.tecsys.de/fileadmin/user_upload/pdf/gh79_1an_intant.pdf
562
 */
563
564
// *INDENT-OFF*
565
const struct gps_type_t driver_gpsclock = {
566
    .type_name      = "Furuno Electric GH-79L4",        // full name of type
567
    .packet_type    = NMEA_PACKET,      // associated lexer packet type
568
    .flags          = DRIVER_STICKY,    // remember this
569
    .trigger        = "$PFEC,GPssd",    // GPSClock should return this
570
    .channels       = 12,               // not used by this driver
571
    .probe_detect   = NULL,             // no probe
572
    .get_packet     = packet_get1,      // how to get a packet
573
    .parse_packet   = generic_parse_input,      // how to interpret a packet
574
    .rtcm_writer    = gpsd_write,       // write RTCM data straight
575
    .init_query     = NULL,             // non-perturbing initial query
576
    .event_hook     = NULL,             // no lifetime event handler
577
    .speed_switcher = NULL,             // no speed switcher
578
    .mode_switcher  = NULL,             // no mode switcher
579
    .rate_switcher  = NULL,             // sample rate is fixed
580
    .min_cycle.tv_sec  = 1,             // not relevant, no rate switch
581
    .min_cycle.tv_nsec = 0,             // not relevant, no rate switch
582
    .control_send   = nmea_write,       // how to send control strings
583
    .time_offset     = NULL,            // no method for NTP fudge factor
584
};
585
// *INDENT-ON*
586
#endif  // GPSCLOCK_ENABLE
587
588
#ifdef TRIPMATE_ENABLE
589
/**************************************************************************
590
 *
591
 * TripMate -- extended NMEA, gets faster fix when primed with lat/long/time
592
 *
593
 **************************************************************************/
594
595
/*
596
 * Some technical FAQs on the TripMate:
597
 * http://vancouver-webpages.com/pub/peter/tripmate.faq
598
 * http://www.asahi-net.or.jp/~KN6Y-GTU/tripmate/trmfaqe.html
599
 * The TripMate was discontinued sometime before November 1998
600
 * and was replaced by the Zodiac EarthMate.
601
 */
602
603
static void tripmate_event_hook(struct gps_device_t *session, event_t event)
604
0
{
605
0
    if (session->context->readonly) {
606
0
        return;
607
0
    }
608
609
    // TripMate requires this response to the ASTRAL it sends at boot time
610
0
    if (event == EVENT_IDENTIFIED) {
611
0
        (void)nmea_send(session, "$IIGPQ,ASTRAL");
612
0
    }
613
    // stop it sending PRWIZCH
614
0
    if (event == EVENT_IDENTIFIED ||
615
0
        event == EVENT_REACTIVATE) {
616
0
        (void)nmea_send(session, "$PRWIILOG,ZCH,V,,");
617
0
    }
618
0
}
619
620
// *INDENT-OFF*
621
static const struct gps_type_t driver_tripmate = {
622
    .type_name     = "Delorme TripMate",        // full name of type
623
    .packet_type   = NMEA_PACKET,               // lexer packet type
624
    .flags         = DRIVER_STICKY,             // no rollover or other flags
625
    .trigger       ="ASTRAL",                   // tells us to switch
626
    .channels      = 12,                        // consumer-grade GPS
627
    .probe_detect  = NULL,                      // no probe
628
    .get_packet    = packet_get1,               // how to get a packet
629
    .parse_packet  = generic_parse_input,       // how to interpret a packet
630
    .rtcm_writer   = gpsd_write,                // send RTCM data straight
631
    .init_query    = NULL,                      // non-perturbing query
632
    .event_hook    = tripmate_event_hook,       // lifetime event handler
633
    .speed_switcher= NULL,                      // no speed switcher
634
    .mode_switcher = NULL,                      // no mode switcher
635
    .rate_switcher = NULL,                      // no sample-rate switcher
636
    .min_cycle.tv_sec  = 1,             // not relevant, no rate switch
637
    .min_cycle.tv_nsec = 0,             // not relevant, no rate switch
638
    .control_send  = nmea_write,        // how to send control strings
639
    .time_offset     = NULL,            // no method for NTP fudge factor
640
};
641
// *INDENT-ON*
642
#endif  // TRIPMATE_ENABLE
643
644
#ifdef EARTHMATE_ENABLE
645
/**************************************************************************
646
 *
647
 * Zodiac EarthMate textual mode
648
 *
649
 * Note: This is the pre-2003 version using Zodiac binary protocol.
650
 * There is a good HOWTO at <http://www.hamhud.net/ka9mva/earthmate.htm>.
651
 * It has been replaced with a design that uses a SiRF chipset.
652
 *
653
 **************************************************************************/
654
655
static void earthmate_event_hook(struct gps_device_t *session, event_t event)
656
0
{
657
0
    struct timespec delay;
658
659
0
    if (session->context->readonly) {
660
0
        return;
661
0
    }
662
0
    if (event == EVENT_TRIGGERMATCH) {
663
0
        (void)gpsd_write(session, "EARTHA\r\n", 8);
664
        // wait 10,000 uSec
665
0
        delay.tv_sec = 0;
666
0
        delay.tv_nsec = 10000000L;
667
0
        nanosleep(&delay, NULL);
668
669
0
        (void)gpsd_switch_driver(session, "Zodiac");
670
0
    }
671
0
}
672
673
// *INDENT-OFF*
674
static const struct gps_type_t driver_earthmate = {
675
    .type_name     = "Pre-2003 Delorme EarthMate",
676
    .packet_type   = NMEA_PACKET,       // associated lexer packet type
677
    .flags         = DRIVER_STICKY,             // no rollover or other flags
678
    .trigger       = "EARTHA",                  // Earthmate trigger string
679
    .channels      = 12,                        // not used by NMEA parser
680
    .probe_detect  = NULL,                      // no probe
681
    .get_packet    = packet_get1,               // how to get a packet
682
    .parse_packet  = generic_parse_input,       // how to interpret a packet
683
    .rtcm_writer   = NULL,                      // don't send RTCM data
684
    .init_query     = NULL,                     // non-perturbing query
685
    .event_hook    = earthmate_event_hook,      // lifetime event handler
686
    .speed_switcher= NULL,                      // no speed switcher
687
    .mode_switcher = NULL,                      // no mode switcher
688
    .rate_switcher = NULL,                      // no sample-rate switcher
689
    .min_cycle.tv_sec  = 1,             // not relevant, no rate switch
690
    .min_cycle.tv_nsec = 0,             // not relevant, no rate switch
691
    .control_send  = nmea_write,        // never actually used.
692
    .time_offset     = NULL,            // no method for NTP fudge factor
693
};
694
// *INDENT-ON*
695
#endif  // EARTHMATE_ENABLE
696
697
#ifdef TNT_ENABLE
698
/**************************************************************************
699
 * True North Technologies - Revolution 2X Digital compass
700
 *
701
 * More info: http://www.tntc.com/
702
 *
703
 * This is a digital compass which uses magnetometers to measure the
704
 * strength of the earth's magnetic field. Based on these measurements
705
 * it provides a compass heading using NMEA formatted output strings.
706
 * This is useful to supplement the heading provided by another GPS
707
 * unit. A GPS heading is unreliable at slow speed or no speed.
708
 *
709
 **************************************************************************/
710
711
// send a control string in TNT native formal
712
static ssize_t tnt_control_send(struct gps_device_t *session,
713
                                char *msg, size_t len UNUSED)
714
0
{
715
0
    ssize_t status;
716
0
    unsigned char sum = '\0';
717
0
    char c, *p = msg;
718
719
0
    if ('@' == *p) {
720
0
        p++;
721
0
    }
722
#ifdef __UNUSED__
723
    else {
724
        GPSD_LOG(LOG_ERROR, &session->context->errout,
725
                 "Bad TNT sentence: '%s'\n", msg);
726
    }
727
#endif  // __UNUSED__
728
0
    while ('\0' != (c = *p)) {
729
0
        sum ^= c;
730
0
        p++;
731
0
    }
732
0
    (void)snprintf(p, 6, "*%02X\r\n", (unsigned int)sum);
733
734
0
    status = gpsd_write(session, msg, strlen(msg));
735
0
    return status;
736
0
}
737
738
// printf(3)-like TNT command generator
739
static bool tnt_send(struct gps_device_t *session, const char *fmt, ...)
740
0
{
741
0
    char buf[BUFSIZ];
742
0
    va_list ap;
743
0
    ssize_t sent;
744
745
0
    va_start(ap, fmt);
746
0
    (void)vsnprintf(buf, sizeof(buf) - 5, fmt, ap);
747
0
    va_end(ap);
748
0
    sent = tnt_control_send(session, buf, strnlen(buf, sizeof(buf)));
749
0
    if ((ssize_t)strnlen(buf, sizeof(buf)) == sent) {
750
0
        GPSD_LOG(LOG_IO, &session->context->errout,
751
0
                 "=> GPS: %s\n", buf);
752
0
        return true;
753
0
    }  //  else
754
755
0
    GPSD_LOG(LOG_WARN, &session->context->errout,
756
0
             "=> GPS: %s FAILED\n", buf);
757
0
    return false;
758
0
}
759
760
static bool tnt_speed(struct gps_device_t *session,
761
                      speed_t speed, char parity UNUSED, int stopbits UNUSED)
762
0
{
763
    /*
764
     * Baud rate change followed by device reset.
765
     * See page 40 of Technical Guide 1555-B.  We need:
766
     * 2400 -> 1, 4800 -> 2, 9600 -> 3, 19200 -> 4, 38400 -> 5
767
     */
768
0
    unsigned int val = speed / 2400u;  // 2400->1, 4800->2, 9600->4, 19200->8...
769
0
    unsigned int i = 0;
770
771
    // fast way to compute log2(val)
772
0
    while (1 < (val >> i)) {
773
0
        ++i;
774
0
    }
775
0
    return tnt_send(session, "@B6=%d", i + 1) &&
776
0
           tnt_send(session, "@F28.6=1");
777
0
}
778
779
// TNT lifetime event hook
780
static void tnt_event_hook(struct gps_device_t *session, event_t event)
781
224
{
782
224
    if (session->context->readonly) {
783
77
        return;
784
77
    }
785
147
    if (event == EVENT_WAKEUP) {
786
0
        (void)tnt_send(session, "@F0.3=1");     // set run mode
787
0
        (void)tnt_send(session, "@F2.2=1");     // report in degrees
788
0
    }
789
147
}
790
791
// *INDENT-OFF*
792
const struct gps_type_t driver_trueNorth = {
793
    .type_name      = "True North",     // full name of type
794
    .packet_type    = NMEA_PACKET,      // associated lexer packet type
795
    .flags          = DRIVER_STICKY,    // remember this
796
    .trigger        = "$PTNTHTM",       // their proprietary sentence
797
    .channels       = 0,                // not an actual GPS at all
798
    .probe_detect   = NULL,             // no probe in run mode
799
    .get_packet     = packet_get1,      // how to get a packet
800
    .parse_packet   = generic_parse_input,      // how to interpret a packet
801
    .rtcm_writer    = NULL,             // Don't send
802
    .init_query     = NULL,             // non-perturbing initial query
803
    .event_hook     = tnt_event_hook,   // lifetime event handler
804
    .speed_switcher = tnt_speed,        // no speed switcher
805
    .mode_switcher  = NULL,             // no mode switcher
806
    .rate_switcher  = NULL,             // no wrapup
807
    .min_cycle.tv_sec  = 0,             // not relevant, no rate switch
808
    .min_cycle.tv_nsec = 500000000,     // not relevant, no rate switch
809
    .control_send   = tnt_control_send, // how to send control strings
810
    .time_offset     = NULL,
811
};
812
// *INDENT-ON*
813
#endif
814
815
#ifdef FURY_ENABLE
816
/**************************************************************************
817
 *
818
 * Jackson Labs Fury, a high-precision laboratory clock
819
 *
820
 * Will also support other Jackon Labs boards, including the Firefly.
821
 *
822
 * Note: you must either build with fixed_port_speed=115200 or tweak the
823
 * speed on the port to 115200 before running.  The device's default mode
824
 * does not stream output, so our hunt loop will simply time out otherwise.
825
 *
826
 **************************************************************************/
827
828
static bool fury_rate_switcher(struct gps_device_t *session, double rate)
829
0
{
830
0
    char buf[78];
831
0
    double inverted;
832
833
    // rate is a frequency, but the command takes interval in # of seconds
834
0
    if (rate == 0.0) {
835
0
        inverted = 0.0;
836
0
    } else {
837
0
        inverted = 1.0/rate;
838
0
    }
839
0
    if (inverted > 256) {
840
0
        return false;
841
0
    }
842
0
    (void)snprintf(buf, sizeof(buf), "GPS:GPGGA %d\r\n", (int)inverted);
843
0
    (void)gpsd_write(session, buf, strnlen(buf, sizeof(buf)));
844
0
    return true;
845
0
}
846
847
static void fury_event_hook(struct gps_device_t *session, event_t event)
848
0
{
849
0
    if (event == EVENT_WAKEUP &&
850
0
        gpsd_get_speed(session) == 115200) {
851
0
        (void)fury_rate_switcher(session, 1.0);
852
0
    } else if (event == EVENT_DEACTIVATE) {
853
0
        (void)fury_rate_switcher(session, 0.0);
854
0
    }
855
0
}
856
857
858
// *INDENT-OFF*
859
static const struct gps_type_t driver_fury = {
860
    .type_name      = "Jackson Labs Fury", // full name of type
861
    .packet_type    = NMEA_PACKET,      // associated lexer packet type
862
    .flags          = DRIVER_STICKY,    // no rollover or other flags
863
    .trigger        = NULL,             // detect their main sentence
864
    .channels       = 0,                // not an actual GPS at all
865
    .probe_detect   = NULL,
866
    .get_packet     = packet_get1,      // how to get a packet
867
    .parse_packet   = generic_parse_input,      // how to interpret a packet
868
    .rtcm_writer    = NULL,             // Don't send
869
    .init_query     = NULL,             // non-perturbing initial query
870
    .event_hook     = fury_event_hook,
871
    .speed_switcher = NULL,             // no speed switcher
872
    .mode_switcher  = NULL,             // no mode switcher
873
    .rate_switcher  = fury_rate_switcher,
874
    .min_cycle.tv_sec  = 1,             // not relevant, no rate switch
875
    .min_cycle.tv_nsec = 0,             // not relevant, no rate switch
876
    .control_send   = nmea_write,       // how to send control strings
877
    .time_offset     = NULL,
878
};
879
// *INDENT-ON*
880
881
#endif  // FURY_ENABLE
882
883
/**************************************************************************
884
 *
885
 * RTCM-104 (v2), used for broadcasting DGPS corrections and by DGPS radios
886
 *
887
 **************************************************************************/
888
889
static gps_mask_t rtcm104v2_analyze(struct gps_device_t *session)
890
5.54k
{
891
5.54k
    rtcm2_unpack(session, &session->gpsdata.rtcm2,
892
5.54k
                 (char *)session->lexer.isgps.buf);
893
5.54k
    session->cycle_end_reliable = true;
894
5.54k
    return RTCM2_SET;
895
5.54k
}
896
897
// *INDENT-OFF*
898
static const struct gps_type_t driver_rtcm104v2 = {
899
    .type_name     = "RTCM104V2",       // full name of type
900
    .packet_type   = RTCM2_PACKET,      // associated lexer packet type
901
    .flags         = DRIVER_NOFLAGS,    // no rollover or other flags
902
    .trigger       = NULL,              // no recognition string
903
    .channels      = 0,                 // not used
904
    .probe_detect  = NULL,              // no probe
905
    .get_packet    = packet_get1,       // how to get a packet
906
    .parse_packet  = rtcm104v2_analyze, //
907
    .rtcm_writer   = NULL,              // don't send RTCM data
908
    .init_query     = NULL,             // non-perturbing initial query
909
    .event_hook    = NULL,              // no event_hook
910
    .speed_switcher= NULL,              // no speed switcher
911
    .mode_switcher = NULL,              // no mode switcher
912
    .rate_switcher = NULL,              // no sample-rate switcher
913
    // cycle not relevant, no rate switch, but can generate log noise
914
    .min_cycle.tv_sec  = 10,            // Some NTRIP servers are bursty
915
    .min_cycle.tv_nsec = 0,             // not relevant, no rate switch
916
    .control_send   = NULL,             // how to send control strings
917
    .time_offset     = NULL,
918
};
919
// *INDENT-ON*
920
921
/**************************************************************************
922
 *
923
 * RTCM-104 (v3), used for broadcasting DGPS corrections and by DGPS radios
924
 *
925
 **************************************************************************/
926
927
static gps_mask_t rtcm104v3_analyze(struct gps_device_t *session)
928
1.37k
{
929
1.37k
    uint16_t type = getbeu16(session->lexer.outbuffer, 3) >> 4;
930
931
1.37k
    GPSD_LOG(LOG_RAW, &session->context->errout, "RTCM 3.x packet %d\n", type);
932
1.37k
    rtcm3_unpack(session->context,
933
1.37k
                 &session->gpsdata.rtcm3,
934
1.37k
                 session->lexer.outbuffer);
935
1.37k
    session->cycle_end_reliable = true;
936
1.37k
    return RTCM3_SET;
937
1.37k
}
938
939
// *INDENT-OFF*
940
static const struct gps_type_t driver_rtcm104v3 = {
941
    .type_name     = "RTCM104V3",       // full name of type
942
    .packet_type   = RTCM3_PACKET,      // associated lexer packet type
943
    .flags         = DRIVER_NOFLAGS,    // no rollover or other flags
944
    .trigger       = NULL,              // no recognition string
945
    .channels      = 0,                 // not used
946
    .probe_detect  = NULL,              // no probe
947
    .get_packet    = packet_get1,       // how to get a packet
948
    .parse_packet  = rtcm104v3_analyze, //
949
    .rtcm_writer   = NULL,              // don't send RTCM data
950
    .init_query    = NULL,              // non-perturbing initial query
951
    .event_hook    = NULL,              // no event hook
952
    .speed_switcher= NULL,              // no speed switcher
953
    .mode_switcher = NULL,              // no mode switcher
954
    .rate_switcher = NULL,              // no sample-rate switcher
955
    // cycle not relevant, no rate switch, but can generate log noise
956
    .min_cycle.tv_sec  = 10,            // Some NTRIP servers are bursty
957
    .min_cycle.tv_nsec = 0,             // not relevant, no rate switch
958
    .control_send   = NULL,             // how to send control strings
959
    .time_offset     = NULL,
960
};
961
// *INDENT-ON*
962
963
#ifdef GARMINTXT_ENABLE
964
/**************************************************************************
965
 *
966
 * Garmin Simple Text protocol
967
 *
968
 **************************************************************************/
969
970
// *INDENT-OFF*
971
static const struct gps_type_t driver_garmintxt = {
972
    .type_name     = "Garmin Simple Text",              // full name of type
973
    .packet_type   = GARMINTXT_PACKET,  // associated lexer packet type
974
    .flags         = DRIVER_NOFLAGS,    // no rollover or other flags
975
    .trigger       = NULL,              // no recognition string
976
    .channels      = 0,                 // not used
977
    .probe_detect  = NULL,              // no probe
978
    .get_packet    = packet_get1,       // how to get a packet
979
    .parse_packet  = garmintxt_parse,   // how to parse one
980
    .rtcm_writer   = NULL,              // don't send RTCM data
981
    .init_query     = NULL,             // non-perturbing initial query
982
    .event_hook    = NULL,              // no event hook
983
    .speed_switcher= NULL,              // no speed switcher
984
    .mode_switcher = NULL,              // no mode switcher
985
    .rate_switcher = NULL,              // no sample-rate switcher
986
    .min_cycle.tv_sec  = 1,             // not relevant, no rate switch
987
    .min_cycle.tv_nsec = 0,             // not relevant, no rate switch
988
    .control_send   = NULL,             // how to send control strings
989
    .time_offset     = NULL,
990
};
991
// *INDENT-ON*
992
#endif  // GARMINTXT_ENABLE
993
994
/**************************************************************************
995
 *
996
 * MediaTek MTK-3301, 3329, 3333, 3339
997
 *
998
 * OEMs for several GPS vendors, notably including Garmin, FasTrax, Trimble,
999
 * and AdaFruit. Website at <http://www.mediatek.com/>.
1000
 *
1001
 * The Trimble Condor appears to be an MTK3329.  It behaves as an MTK3301
1002
 * and positively acknowledges all 3301 sentences as valid. It ignores $PMTK
1003
 * sentence fields that are not implemented in the Trimble Condor. It does
1004
 * not have power-save mode and ignores $PMTK320.  For $PMTK314 it silently
1005
 * ignores periodic enabling of messages that aren't supported.
1006
 *
1007
 * From its datasheet the MTK3339 seems to add QZSS support not present in
1008
 * earlier versions. The data sheet says it has 66 channels, which mkes
1009
 * sense given the multi-constellation capability. The channel count
1010
 * in the driver is never used by the NMEA driver so leaving the lower MTK3301
1011
 * value in there is OK.
1012
 *
1013
 * MTK3333 support 10Hz.
1014
 *
1015
 * The Adafruit GPS HAT for the Raspberry Pi is an MTK3339. It works with this
1016
 * driver; in fact AdaFruit's overview page for the product features GPSD.
1017
 *
1018
 * SIMCom DIM68M appears to be an MTK3333.
1019
 *
1020
 **************************************************************************/
1021
1022
static void mtk3301_event_hook(struct gps_device_t *session, event_t event)
1023
655
{
1024
/*
1025
0  NMEA_SEN_GLL,  GPGLL   interval - Geographic Position - Latitude longitude
1026
1  NMEA_SEN_RMC,  GPRMC   interval - Recommended Minimum Specific GNSS Sentence
1027
2  NMEA_SEN_VTG,  GPVTG   interval - Course Over Ground and Ground Speed
1028
3  NMEA_SEN_GGA,  GPGGA   interval - GPS Fix Data
1029
4  NMEA_SEN_GSA,  GPGSA   interval - GNSS DOPS and Active Satellites
1030
5  NMEA_SEN_GSV,  GPGSV   interval - GNSS Satellites in View
1031
6  NMEA_SEN_GRS,  GPGRS   interval - GNSS Range Residuals
1032
7  NMEA_SEN_GST,  GPGST   interval - GNSS Pseudorange Errors Statistics
1033
13 NMEA_SEN_MALM, PMTKALM interval - GPS almanac information
1034
14 NMEA_SEN_MEPH, PMTKEPH interval - GPS ephemeris information
1035
15 NMEA_SEN_MDGP, PMTKDGP interval - GPS differential correction information
1036
16 NMEA_SEN_MDBG, PMTKDBG interval – MTK debug information
1037
17 NMEA_SEN_ZDA,  GPZDA   interval - Time & Date
1038
18 NMEA_SEN_MCHN, PMTKCHN interval – GPS channel status
1039
// MTK 3333
1040
19 NMEA_SEN_DTM,  GPDTM   interval - Datum reference
1041
1042
"$PMTK314,1,1,1,1,1,5,1,1,0,0,0,0,0,0,0,0,0,1,0"
1043
1044
*/
1045
655
    if (session->context->readonly) {
1046
159
        return;
1047
159
    }
1048
496
    if (event == EVENT_TRIGGERMATCH) {
1049
153
        (void)nmea_send(session, "$PMTK320,0");  // power save off
1050
        // Fix interval, 1000 milliseconds
1051
153
        (void)nmea_send(session, "$PMTK300,1000,0,0,0.0,0.0");
1052
        // Set NMEA sentences.
1053
153
        (void)nmea_send(session,
1054
153
                        "$PMTK314,0,1,0,1,1,5,1,1,0,0,0,0,0,0,0,0,0,1,0");
1055
        // DGPS is WAAS
1056
153
        (void)nmea_send(session, "$PMTK301,2");
1057
        // SBAS enable
1058
153
        (void)nmea_send(session, "$PMTK313,1");
1059
1060
        /* PMTK_API_Q_OUTPUT_CTL - Query PPS pulse width - Trimble only?
1061
         * http://trl.trimble.com/docushare/dsweb/Get/Document-482603/CONDOR_UG_2C_75263-00.pdf *
1062
         * badly documented */
1063
153
         (void)nmea_send(session, "$PMTK424");
1064
153
    }
1065
496
}
1066
1067
// mtk3301_speed_switcher()
1068
// Always returns True
1069
static bool mtk3301_speed_switcher(struct gps_device_t* session,
1070
                                   speed_t speed, char parity UNUSED,
1071
                                   int stopbits UNUSED)
1072
0
{
1073
0
    int i;
1074
0
    char buf[BUFSIZ] = {0};
1075
1076
0
    (void)snprintf(buf, sizeof(buf), "$PQBAUD,W,%d", (int) speed);
1077
1078
    // Calling PQBAUD fails to set the receiver's baud rate
1079
    // some of the time.  Sending it twice seems to work every time.
1080
    // So just for good measure, send it three times.
1081
0
    for (i = 0; i < 3; i++) {
1082
0
        (void)nmea_send(session, buf);
1083
0
    }
1084
1085
0
    return true;
1086
0
}
1087
1088
static bool mtk3301_rate_switcher(struct gps_device_t *session, double rate)
1089
0
{
1090
0
    char buf[78];
1091
1092
0
    unsigned int milliseconds = (unsigned int)(1000 * rate);
1093
0
    if (rate > 1) {
1094
        // force no slower than 1Hz
1095
0
        milliseconds = 1000;
1096
0
    } else if (rate < 0.1) {
1097
        // force no faster than 10Hz, MTK3333 can do 10Hz
1098
0
        milliseconds = 100;
1099
0
    }
1100
1101
0
    (void)snprintf(buf, sizeof(buf), "$PMTK300,%u,0,0,0,0", milliseconds);
1102
0
    (void)nmea_send(session, buf);      // Fix interval
1103
0
    return true;
1104
0
}
1105
1106
// *INDENT-OFF*
1107
const struct gps_type_t driver_mtk3301 = {
1108
    .type_name      = "MTK-3301",               // full name of type
1109
    .packet_type    = NMEA_PACKET,              // associated lexer packet type
1110
    .flags          = DRIVER_STICKY,            // remember this
1111
    .trigger        = "$PMTK705,",         // firmware release name and version
1112
    .channels       = 12,                       // not used by this driver
1113
    .probe_detect   = NULL,                     // no probe
1114
    .get_packet     = packet_get1,              // how to get a packet
1115
    .parse_packet   = generic_parse_input,      // how to interpret a packet
1116
    .rtcm_writer    = gpsd_write,               // write RTCM data straight
1117
    .init_query     = NULL,                     // non-perturbing initial query
1118
    .event_hook     = mtk3301_event_hook,       // lifetime event handler
1119
    .speed_switcher = mtk3301_speed_switcher,   // sample speed switcher
1120
    .mode_switcher  = NULL,                     // no mode switcher
1121
    .rate_switcher  = mtk3301_rate_switcher,    // sample rate switcher
1122
    .min_cycle.tv_sec  = 0,
1123
    .min_cycle.tv_nsec = 100000000,             // max 10Hz
1124
    .control_send   = nmea_write,               // how to send control strings
1125
    .time_offset     = NULL,
1126
};
1127
// *INDENT-ON*
1128
1129
#ifdef ISYNC_ENABLE
1130
/**************************************************************************
1131
 *
1132
 * Spectratime LNRCLOK / GRCLOK iSync GPS-disciplined rubidium oscillators
1133
 *
1134
 * These devices comprise a u-blox 6 attached to a separate iSync
1135
 * microcontroller which drives the rubidium oscillator.  The iSync
1136
 * microcontroller can be configured to pass through the underlying
1137
 * GPS communication channel, while still using the GPS PPSREF signal
1138
 * to discipline the rubidium oscillator.
1139
 *
1140
 * The iSync can also generate its own periodic status packets in NMEA
1141
 * format.  These describe the state of the oscillator (including
1142
 * whether or not the oscillator PPSOUT is synced to the GPS PPSREF).
1143
 * These packets are transmitted in the middle of the underlying GPS
1144
 * packets, forcing us to handle interrupted NMEA packets.
1145
 *
1146
 * The default state of the device is to generate no periodic output.
1147
 * We send a probe string to initiate beating of the iSync-proprietary
1148
 * $PTNTS,B message, which is then detected as a NMEA trigger.
1149
 *
1150
 **************************************************************************/
1151
1152
static ssize_t isync_write(struct gps_device_t *session, const char *data)
1153
1154
12.2k
{
1155
    // 80 nseems a reasonable max, and strnlen() shuts up Codacy.
1156
12.2k
    return gpsd_write(session, data, strnlen(data, 80));
1157
12.2k
}
1158
1159
static bool isync_detect(struct gps_device_t *session)
1160
0
{
1161
0
    speed_t old_baudrate;
1162
0
    char old_parity;
1163
0
    unsigned int old_stopbits;
1164
1165
    // Set 9600 8N1
1166
0
    old_baudrate = session->gpsdata.dev.baudrate;
1167
0
    old_parity = session->gpsdata.dev.parity;
1168
0
    old_stopbits = session->gpsdata.dev.stopbits;
1169
0
    gpsd_set_speed(session, 9600, 'N', 1);
1170
1171
    /* Cancel pass-through mode and initiate beating of $PTNTS,B
1172
     * message, which can subsequently be detected as a trigger.
1173
     */
1174
0
    (void)isync_write(session, "@@@@\r\nMAW0C0B\r\n");
1175
1176
    // return serial port to original settings
1177
0
    gpsd_set_speed(session, old_baudrate, old_parity, old_stopbits);
1178
1179
0
    return false;
1180
0
}
1181
1182
static void isync_event_hook(struct gps_device_t *session, event_t event)
1183
6.16k
{
1184
6.16k
    if (session->context->readonly) {
1185
139
        return;
1186
139
    }
1187
1188
6.02k
    if (event == EVENT_DRIVER_SWITCH) {
1189
856
        session->lexer.counter = 0;
1190
856
    }
1191
1192
6.02k
    if (event == EVENT_CONFIGURE) {
1193
4.31k
        switch (session->lexer.counter) {
1194
835
        case 1:
1195
            /* Configure timing and frequency flags:
1196
             *  - Thermal compensation active
1197
             *  - PPSREF active
1198
             *  - PPSOUT active
1199
             */
1200
835
            (void)isync_write(session, "MAW040B\r\n");
1201
            /* Configure tracking flags:
1202
             *  - Save frequency every 24 hours
1203
             *  - Align PPSOUT to PPSINT
1204
             *  - Track PPSREF
1205
             */
1206
835
            (void)isync_write(session, "MAW0513\r\n");
1207
            /* Configure tracking start flags:
1208
             *  - Tracking restart allowed
1209
             *  - Align to PPSREF
1210
             */
1211
835
            (void)isync_write(session, "MAW0606\r\n");
1212
            /* Configure tracking window:
1213
             *  - 4us
1214
             */
1215
835
            (void)isync_write(session, "MAW1304\r\n");
1216
            /* Configure alarm window:
1217
             *  - 4us
1218
             */
1219
835
            (void)isync_write(session, "MAW1404\r\n");
1220
835
            break;
1221
813
        case 2:
1222
            /* Configure pulse every d second:
1223
             *  - pulse every second
1224
             */
1225
813
            (void)isync_write(session, "MAW1701\r\n");
1226
            /* Configure pulse origin:
1227
             *  - zero offset
1228
             */
1229
813
            (void)isync_write(session, "MAW1800\r\n");
1230
            /* Configure pulse width:
1231
             *  - 600ms
1232
             */
1233
813
            (void)isync_write(session, "MAW1223C34600\r\n");
1234
813
            break;
1235
807
        case 3:
1236
            /* Configure GPS resource utilization:
1237
             *  - do not consider GPS messages
1238
             */
1239
807
            (void)isync_write(session, "MAW2200\r\n");
1240
            // Restart sync
1241
807
            (void)isync_write(session, "SY1\r\n");
1242
            // Restart tracking
1243
807
            (void)isync_write(session, "TR1\r\n");
1244
807
            break;
1245
798
        case 4:
1246
            // Cancel BTx messages (if any)
1247
798
            (void)isync_write(session, "BT0\r\n");
1248
            /* Configure messages coming out every second:
1249
             *  - Oscillator status ($PTNTA) at 750ms
1250
             */
1251
798
            (void)isync_write(session, "MAW0B00\r\n");
1252
798
            (void)isync_write(session, "MAW0C0A\r\n");
1253
798
            break;
1254
781
        case 5:
1255
            /* Enable GPS passthrough and force u-blox driver to
1256
             * select NMEA mode.
1257
             */
1258
781
            session->mode = 0;
1259
781
            session->drivers_identified = 0;
1260
781
            (void)isync_write(session, "@@@@GPS\r\n");
1261
781
            break;
1262
142
        case 6:
1263
            /* Trigger detection of underlying u-blox (if necessary)
1264
             * UBX-CFG-PRT */
1265
142
            (void)ubx_write(session, 0x06, 0x00, NULL, 0);
1266
142
            break;
1267
4.31k
        }
1268
4.31k
    }
1269
6.02k
}
1270
1271
// *INDENT-OFF*
1272
const struct gps_type_t driver_isync = {
1273
    .type_name      = "iSync",          // full name of type
1274
    .packet_type    = NMEA_PACKET,      // associated lexer packet type
1275
    .flags          = DRIVER_STICKY,    // remember this
1276
    .trigger        = "$PTNTS,B,",      // iSync status message
1277
    .channels       = 50,               // copied from driver_ubx
1278
    .probe_detect   = isync_detect,     // how to detect at startup time
1279
    .get_packet     = packet_get1,      // how to get a packet
1280
    .parse_packet   = generic_parse_input,      // how to interpret a packet
1281
    .init_query     = NULL,             // non-perturbing initial query
1282
    .event_hook     = isync_event_hook, // lifetime event handler
1283
    .speed_switcher = NULL,             // no speed switcher
1284
    .mode_switcher  = NULL,             // no mode switcher
1285
    .rate_switcher  = NULL,             // no sample-rate switcher
1286
    .min_cycle.tv_sec  = 1,             // not relevant, no rate switch
1287
    .min_cycle.tv_nsec = 0,             // not relevant, no rate switch
1288
    .control_send   = nmea_write,       // how to send control strings
1289
    .time_offset     = NULL,            // no method for NTP fudge factor
1290
};
1291
// *INDENT-ON*
1292
#endif  // ISYNC_ENABLE
1293
1294
#ifdef AIVDM_ENABLE
1295
/**************************************************************************
1296
 *
1297
 * AIVDM - ASCII armoring of binary AIS packets
1298
 *
1299
 **************************************************************************/
1300
1301
static bool aivdm_decode(unsigned char *buf, size_t buflen,
1302
                         struct gps_device_t *session, struct ais_t *ais,
1303
                         int debug)
1304
14.9k
{
1305
#ifdef __UNUSED_DEBUG__
1306
    static char *sixbits[64] = {
1307
        "000000", "000001", "000010", "000011", "000100",
1308
        "000101", "000110", "000111", "001000", "001001",
1309
        "001010", "001011", "001100", "001101", "001110",
1310
        "001111", "010000", "010001", "010010", "010011",
1311
        "010100", "010101", "010110", "010111", "011000",
1312
        "011001", "011010", "011011", "011100", "011101",
1313
        "011110", "011111", "100000", "100001", "100010",
1314
        "100011", "100100", "100101", "100110", "100111",
1315
        "101000", "101001", "101010", "101011", "101100",
1316
        "101101", "101110", "101111", "110000", "110001",
1317
        "110010", "110011", "110100", "110101", "110110",
1318
        "110111", "111000", "111001", "111010", "111011",
1319
        "111100", "111101", "111110", "111111",
1320
    };
1321
#endif  // __UNUSED_DEBUG__
1322
14.9k
    int nfrags, ifrag, nfields = 0;
1323
    /* maximum ength of IEC 61162 message is 79 chars
1324
     * we will copy fields here, NUL separated */
1325
14.9k
    unsigned char fieldcopy[200];
1326
    /* pointer to fields in fieldcopy, so only 80 fields possible
1327
     * if buf is all commas, then there as many fields as chars. */
1328
14.9k
    unsigned char *field[200];
1329
14.9k
    unsigned char *data, *cp;
1330
14.9k
    int pad;
1331
14.9k
    struct aivdm_context_t *ais_context;
1332
14.9k
    int i;
1333
1334
14.9k
    if (0 == buflen) {
1335
0
        return false;
1336
0
    }
1337
1338
    // we may need to dump the raw packet
1339
14.9k
    GPSD_LOG(LOG_PROG, &session->context->errout,
1340
14.9k
             "AIVDM packet length %zd: %s\n", buflen, buf);
1341
1342
    // first clear the result, making sure we don't return garbage
1343
14.9k
    memset(ais, 0, sizeof(*ais));
1344
1345
    // discard overlong sentences
1346
14.9k
    if (buflen > (sizeof(fieldcopy) - 1)) {
1347
67
        GPSD_LOG(LOG_ERROR, &session->context->errout,
1348
67
                 "overlong AIVDM packet.\n");
1349
67
        return false;
1350
67
    }
1351
1352
    // avoid reoccuring CVE here
1353
14.8k
    memset(fieldcopy, 0, sizeof(fieldcopy));
1354
14.8k
    memset(field, 0, sizeof(field));
1355
1356
    // extract packet fields
1357
14.8k
    field[nfields++] = fieldcopy;
1358
775k
    for (i = 0; i < (int)buflen; i++) {
1359
761k
        unsigned char c = buf[i];
1360
1361
761k
        if (!isascii(c)) {
1362
            /* discard sentences with high-half characters in them,
1363
             * they're corrupted. */
1364
75
            GPSD_LOG(LOG_ERROR, &session->context->errout,
1365
75
                     "corrupted AIVDM packet.\n");
1366
75
            return false;
1367
75
        }
1368
760k
        if (((unsigned char)',' == c) ||
1369
720k
            ((unsigned char)'*' == c)) {
1370
104k
            c = '\0';
1371
104k
            field[nfields++] = &fieldcopy[i] + 1;
1372
104k
        }
1373
760k
        fieldcopy[i] = c;
1374
760k
    }
1375
#ifdef __UNDEF_DEBUG_
1376
    for(int nf = 0; nf < nfields; nf++) {
1377
        GPSD_LOG(LOG_DATA, &session->context->errout,
1378
                 "field [%d] [%s]\n", nf, field[nf]);
1379
    }
1380
#endif
1381
1382
    // discard sentences with exiguous commas; catches run-ons
1383
14.8k
    if (7 > nfields) {
1384
226
        GPSD_LOG(LOG_ERROR, &session->context->errout,
1385
226
                 "malformed AIVDM packet.\n");
1386
226
        return false;
1387
226
    }
1388
1389
14.5k
    switch (field[4][0]) {
1390
11.0k
    case '\0':
1391
        /*
1392
         * Apparently an empty channel is normal for AIVDO sentences,
1393
         * which makes sense as they don't come in over radio.  This
1394
         * is going to break if there's ever an AIVDO type 24, though.
1395
         */
1396
11.0k
        if (!str_starts_with((const char *)field[0], "!AIVDO")) {
1397
11.0k
            GPSD_LOG(LOG_INF, &session->context->errout,
1398
11.0k
                     "invalid empty AIS channel. Assuming 'A'\n");
1399
11.0k
        }
1400
11.0k
        ais_context = &session->driver.aivdm.context[0];
1401
11.0k
        session->driver.aivdm.ais_channel ='A';
1402
11.0k
        break;
1403
2.81k
    case '1':
1404
2.81k
        if (strcmp((char *)field[4], (char *)"12") == 0) {
1405
66
            GPSD_LOG(LOG_INF, &session->context->errout,
1406
66
                     "ignoring bogus AIS channel '12'.\n");
1407
66
            return false;
1408
66
        }
1409
2.74k
        FALLTHROUGH
1410
2.88k
    case 'A':
1411
2.88k
        ais_context = &session->driver.aivdm.context[0];
1412
2.88k
        session->driver.aivdm.ais_channel ='A';
1413
2.88k
        break;
1414
352
    case '2':
1415
352
        FALLTHROUGH
1416
422
    case 'B':
1417
422
        ais_context = &session->driver.aivdm.context[1];
1418
422
        session->driver.aivdm.ais_channel ='B';
1419
422
        break;
1420
67
    case 'C':
1421
67
        GPSD_LOG(LOG_INF, &session->context->errout,
1422
67
                 "ignoring AIS channel C (secure AIS).\n");
1423
67
        return false;
1424
70
    default:
1425
70
        GPSD_LOG(LOG_ERROR, &session->context->errout,
1426
70
                 "invalid AIS channel 0x%0X .\n", field[4][0]);
1427
70
        return false;
1428
14.5k
    }
1429
1430
14.3k
    nfrags = atoi((char *)field[1]);  // number of fragments to expect
1431
14.3k
    ifrag = atoi((char *)field[2]);   // fragment id
1432
14.3k
    data = field[5];
1433
1434
14.3k
    pad = 0;
1435
14.3k
    if(isdigit(field[6][0])) {
1436
2.78k
        pad = field[6][0] - '0';  // number of padding bits ASCII encoded
1437
2.78k
    }
1438
14.3k
    GPSD_LOG(LOG_PROG, &session->context->errout,
1439
14.3k
             "nfrags %d ifrag %d decoded_frags %d data %s pad %d "
1440
14.3k
             "bitlen %zu datalen %zu\n",
1441
14.3k
             nfrags, ifrag, ais_context->decoded_frags, data, pad,
1442
14.3k
             ais_context->bitlen, strnlen((char *)data, 256));
1443
1444
    // assemble the binary data
1445
1446
    // check fragment ordering
1447
14.3k
    if (ifrag != ais_context->decoded_frags + 1) {
1448
346
        GPSD_LOG(LOG_ERROR, &session->context->errout,
1449
346
                 "invalid fragment #%d received, expected #%d.\n",
1450
346
                 ifrag, ais_context->decoded_frags + 1);
1451
346
        if (1 != ifrag) {
1452
217
            return false;
1453
217
        }
1454
        /* else, ifrag==1: Just discard all that was previously decoded and
1455
         * simply handle that packet */
1456
129
        ais_context->decoded_frags = 0;
1457
129
    }
1458
14.1k
    if (1 == ifrag) {
1459
14.1k
        (void)memset(ais_context->bits, '\0', sizeof(ais_context->bits));
1460
14.1k
        ais_context->bitlen = 0;
1461
14.1k
    }
1462
1463
    /* wacky 6-bit encoding, shades of FIELDATA
1464
     * See IEC 61162-1, Table 7.
1465
     * All 64 values that can fit in 6 bits are valid.
1466
     * Max 256 data chars is a guess, to pacify Codacy
1467
     * IEC61993.pdf implies 84.
1468
     * Max bitlen is likely 1008, max see is 776 */
1469
431k
    for (cp = data; cp < data + strnlen((char *)data, 256); cp++) {
1470
417k
        unsigned char ch;
1471
417k
        ch = *cp;
1472
417k
        ch -= 48;
1473
417k
        if (ch >= 40) {
1474
169k
            ch -= 8;
1475
169k
        }
1476
#ifdef __UNUSED_DEBUG__
1477
        GPSD_LOG(LOG_RAW, &session->context->errout,
1478
                 "%c: %s\n", *cp, sixbits[ch]);
1479
#endif  // __UNUSED_DEBUG__
1480
417k
        if (sizeof(ais_context->bits) <=
1481
417k
            (ais_context->bitlen + 6)) {
1482
            // FIXME?  Maybe move above the previous for() ??
1483
0
            GPSD_LOG(LOG_INF, &session->context->errout,
1484
0
                     "overlong AIVDM payload ignored.\n");
1485
0
            (void)memset(ais_context->bits, '\0',
1486
0
                         sizeof(ais_context->bits));
1487
0
            ais_context->bitlen = 0;
1488
0
            return false;
1489
0
        }
1490
2.92M
        for (i = 5; i >= 0; i--) {
1491
2.50M
            if ((ch >> i) & 0x01) {
1492
1.01M
                ais_context->bits[ais_context->bitlen / 8] |=
1493
1.01M
                    (1 << (7 - ais_context->bitlen % 8));
1494
1.01M
            }
1495
2.50M
            ais_context->bitlen++;
1496
2.50M
        }
1497
417k
    }
1498
14.1k
    ais_context->bitlen -= pad;
1499
14.1k
    if (ais_context->bitlen >= sizeof(ais_context->bits)) {
1500
74
        GPSD_LOG(LOG_INF, &session->context->errout,
1501
74
                 "invalid bitlen AIVDM payload ignored.\n");
1502
74
        (void)memset(ais_context->bits, '\0',
1503
74
                     sizeof(ais_context->bits));
1504
74
        ais_context->bitlen = 0;
1505
74
        return false;
1506
74
    }
1507
1508
    // time to pass buffered-up data to where it's actually processed?
1509
14.0k
    if (ifrag == nfrags) {
1510
13.8k
        if (debug >= LOG_INF) {
1511
0
            size_t clen = BITS_TO_BYTES(ais_context->bitlen);
1512
0
            GPSD_LOG(LOG_INF, &session->context->errout,
1513
0
                     "AIVDM payload is %zd bits, %zd chars: %s\n",
1514
0
                     ais_context->bitlen, clen,
1515
0
                     gps_hexdump(session->msgbuf, sizeof(session->msgbuf),
1516
0
                                 ais_context->bits, clen));
1517
0
        }
1518
1519
        // clear waiting fragments count
1520
13.8k
        ais_context->decoded_frags = 0;
1521
1522
        // decode the assembled binary packet
1523
13.8k
        return ais_binary_decode(&session->context->errout,
1524
13.8k
                                 ais,
1525
13.8k
                                 ais_context->bits,
1526
13.8k
                                 ais_context->bitlen,
1527
13.8k
                                 &ais_context->type24_queue);
1528
13.8k
    }
1529
1530
    // we're still waiting on another sentence
1531
261
    ais_context->decoded_frags++;
1532
261
    return false;
1533
14.0k
}
1534
1535
static gps_mask_t aivdm_analyze(struct gps_device_t *session)
1536
14.9k
{
1537
14.9k
    if (session->lexer.type == AIVDM_PACKET) {
1538
14.9k
        if (aivdm_decode(session->lexer.outbuffer, session->lexer.outbuflen,
1539
14.9k
                         session, &session->gpsdata.ais,
1540
14.9k
                         session->context->errout.debug)) {
1541
8.30k
            return ONLINE_SET | AIS_SET;
1542
8.30k
        }
1543
        // else
1544
6.64k
        return ONLINE_SET;
1545
14.9k
    }
1546
0
    if (session->lexer.type == NMEA_PACKET) {
1547
0
        return nmea_parse((char *)session->lexer.outbuffer, session);
1548
0
    }
1549
    // else
1550
0
    return 0;
1551
0
}
1552
1553
// *INDENT-OFF*
1554
const struct gps_type_t driver_aivdm = {
1555
    // Full name of type
1556
    .type_name        = "AIVDM",        // associated lexer packet type
1557
    .packet_type      = AIVDM_PACKET,   // numeric packet type
1558
    .flags            = DRIVER_NOFLAGS, // no rollover or other flags
1559
    .trigger          = NULL,           // identifying response
1560
    .channels         = 0,              // not used by this driver
1561
    .probe_detect     = NULL,           // no probe
1562
    .get_packet       = packet_get1,    // how to get a packet
1563
    .parse_packet     = aivdm_analyze,  // how to analyze a packet
1564
    .rtcm_writer      = NULL,           // don't send RTCM data,
1565
    .init_query       = NULL,           // non-perturbing initial query
1566
    .event_hook       = NULL,           // lifetime event handler
1567
    .speed_switcher   = NULL,           // no speed switcher
1568
    .mode_switcher    = NULL,           // no mode switcher
1569
    .rate_switcher    = NULL,           // no rate switcher
1570
    .min_cycle.tv_sec  = 1,             // max 1Hz
1571
    .min_cycle.tv_nsec = 0,
1572
    .control_send     = NULL,           // no control sender
1573
    .time_offset     = NULL,            // no NTP communication
1574
};
1575
// *INDENT-ON*
1576
#endif  // AIVDM_ENABLE
1577
1578
/**************************************************************************
1579
 *
1580
 * JSON passthrough driver
1581
 *
1582
 **************************************************************************/
1583
1584
// prepend the session path to the value of a specified attribute
1585
static void path_rewrite(struct gps_device_t *session, char *prefix)
1586
0
{
1587
    /*
1588
     * Hack the packet to reflect its origin.  This code is supposed
1589
     * to insert the path naming the remote gpsd instance into the
1590
     * beginning of the path attribute, followed by a # to separate it
1591
     * from the device.
1592
     */
1593
0
    char *prefloc;
1594
1595
0
    assert(prefix != NULL && session->lexer.outbuffer != NULL);
1596
1597
    // possibly the rewrite has been done already, this comw up in gpsmon
1598
0
    if (strstr((char *)session->lexer.outbuffer,
1599
0
               session->gpsdata.dev.path) != NULL) {
1600
0
        return;
1601
0
    }
1602
1603
0
    for (prefloc = (char *)session->lexer.outbuffer;
1604
0
         prefloc < (char *)session->lexer.outbuffer+session->lexer.outbuflen;
1605
0
         prefloc++) {
1606
0
        if (str_starts_with(prefloc, prefix)) {
1607
0
            char *sfxloc;
1608
0
            char copy[sizeof(session->lexer.outbuffer)+1];
1609
0
            (void)strlcpy(copy,
1610
0
                          (char *)session->lexer.outbuffer,
1611
0
                          sizeof(copy));
1612
0
            prefloc += strlen(prefix);
1613
0
            (void)strlcpy(prefloc,
1614
0
                          session->gpsdata.dev.path,
1615
0
                          sizeof(session->gpsdata.dev.path));
1616
0
            sfxloc = strchr(prefloc, '#');
1617
0
            if (sfxloc) {
1618
0
                *sfxloc = '\0';  // Avoid accumulating multiple device names
1619
0
            }
1620
0
            (void)strlcat((char *)session->lexer.outbuffer, "#",
1621
0
                          sizeof(session->lexer.outbuffer));
1622
0
            (void)strlcat((char *)session->lexer.outbuffer,
1623
0
                          copy + (prefloc-(char *)session->lexer.outbuffer),
1624
0
                          sizeof(session->lexer.outbuffer));
1625
0
        }
1626
0
    }
1627
0
    session->lexer.outbuflen = strnlen((char *)session->lexer.outbuffer,
1628
0
                                       sizeof(session->lexer.outbuffer));
1629
0
}
1630
1631
static gps_mask_t json_pass_packet(struct gps_device_t *session)
1632
170
{
1633
170
    GPSD_LOG(LOG_IO, &session->context->errout,
1634
170
             "<= GPS: %s\n", (char *)session->lexer.outbuffer);
1635
1636
170
    if (strstr(session->gpsdata.dev.path, ":/") != NULL &&
1637
0
        strstr(session->gpsdata.dev.path, "localhost") == NULL) {
1638
        // devices and paths need to be edited
1639
0
        if (strstr((char *)session->lexer.outbuffer, "DEVICE") != NULL) {
1640
0
            path_rewrite(session, "\"path\":\"");
1641
0
        }
1642
0
        path_rewrite(session, "\"device\":\"");
1643
1644
        // mark certain responses without a path or device attribute
1645
0
        if (session->gpsdata.dev.path[0] != '\0') {
1646
0
            if (strstr((char *)session->lexer.outbuffer, "VERSION") != NULL ||
1647
0
                strstr((char *)session->lexer.outbuffer, "WATCH") != NULL ||
1648
0
                strstr((char *)session->lexer.outbuffer, "DEVICES") != NULL) {
1649
0
                session->lexer.outbuffer[session->lexer.outbuflen-1] = '\0';
1650
0
                (void)strlcat((char *)session->lexer.outbuffer, ",\"remote\":\"",
1651
0
                              sizeof(session->lexer.outbuffer));
1652
0
                (void)strlcat((char *)session->lexer.outbuffer,
1653
0
                              session->gpsdata.dev.path,
1654
0
                              sizeof(session->lexer.outbuffer));
1655
0
                (void)strlcat((char *)session->lexer.outbuffer, "\"}",
1656
0
                              sizeof(session->lexer.outbuffer));
1657
0
            }
1658
0
            session->lexer.outbuflen = strnlen(
1659
0
                (char *)session->lexer.outbuffer,
1660
0
                sizeof(session->lexer.outbuffer));
1661
0
        }
1662
0
    }
1663
170
    GPSD_LOG(LOG_PROG, &session->context->errout,
1664
170
             "JSON, passing through %s\n",
1665
170
             (char *)session->lexer.outbuffer);
1666
170
    return PASSTHROUGH_IS;
1667
170
}
1668
1669
// *INDENT-OFF*
1670
const struct gps_type_t driver_json_passthrough = {
1671
    .type_name      = "JSON slave driver",      // full name of type
1672
    .packet_type    = JSON_PACKET,      // associated lexer packet type
1673
    .flags          = DRIVER_NOFLAGS,   // don't remember this
1674
    .trigger        = NULL,             // it's the default
1675
    .channels       = 0,                // not used
1676
    .probe_detect   = NULL,             // no probe
1677
    .get_packet     = packet_get1,      // use generic packet getter
1678
    .parse_packet   = json_pass_packet, // how to interpret a packet
1679
    .rtcm_writer    = NULL,             // write RTCM data straight
1680
    .init_query     = NULL,             // non-perturbing initial query
1681
    .event_hook     = NULL,             // lifetime event handler
1682
    .speed_switcher = NULL,             // no speed switcher
1683
    .mode_switcher  = NULL,             // no mode switcher
1684
    .rate_switcher  = NULL,             // no sample-rate switcher
1685
    .min_cycle.tv_sec  = 1,             // not relevant, no rate switch
1686
    .min_cycle.tv_nsec = 0,             // not relevant, no rate switch
1687
    .control_send   = NULL,             // how to send control strings
1688
    .time_offset     = NULL,            // no method for NTP fudge factor
1689
};
1690
// *INDENT-ON*
1691
1692
1693
// *INDENT-OFF*
1694
const struct gps_type_t driver_pps = {
1695
    .type_name      = "PPS",            // full name of type
1696
    .packet_type    = BAD_PACKET,       // associated lexer packet type
1697
    .flags          = DRIVER_NOFLAGS,   // don't remember this
1698
    .trigger        = NULL,             // it's the default
1699
    .channels       = 0,                // not used
1700
    .probe_detect   = NULL,             // no probe
1701
    .get_packet     = NULL,             // use generic packet getter
1702
    .parse_packet   = NULL,             // how to interpret a packet
1703
    .rtcm_writer    = NULL,             // write RTCM data straight
1704
    .init_query     = NULL,             // non-perturbing initial query
1705
    .event_hook     = NULL,             // lifetime event handler
1706
    .speed_switcher = NULL,             // no speed switcher
1707
    .mode_switcher  = NULL,             // no mode switcher
1708
    .rate_switcher  = NULL,             // no sample-rate switcher
1709
    .min_cycle.tv_sec  = 1,             // not relevant, no rate switch
1710
    .min_cycle.tv_nsec = 0,             // not relevant, no rate switch
1711
    .control_send   = NULL,             // how to send control strings
1712
    .time_offset     = NULL,            // no method for NTP fudge factor
1713
};
1714
1715
static const struct gps_type_t driver_spartn = {
1716
    .type_name     = "SPARTN",          // full name of type
1717
    .packet_type   = SPARTN_PACKET,     // associated lexer packet type
1718
    .flags         = DRIVER_NOFLAGS,    // no rollover or other flags
1719
    .trigger       = NULL,              // no recognition string
1720
    .channels      = 0,                 // not used
1721
    .probe_detect  = NULL,              // no probe
1722
    .get_packet    = NULL,              // use generic packet getter
1723
    .parse_packet  = spartn_parse,      //
1724
    .rtcm_writer   = NULL,              // Do not write back to NTRIP!
1725
    .init_query    = NULL,              // non-perturbing initial query
1726
    .event_hook    = NULL,              // no event hook
1727
    .speed_switcher= NULL,              // no speed switcher
1728
    .mode_switcher = NULL,              // no mode switcher
1729
    .rate_switcher = NULL,              // no sample-rate switcher
1730
    // cycle not relevant, no rate switch, but can generate log noise
1731
    .min_cycle.tv_sec  = 10,            // Some NTRIP servers are bursty
1732
    .min_cycle.tv_nsec = 0,             // not relevant, no rate switch
1733
    .control_send   = NULL,             // how to send control strings
1734
    .time_offset     = NULL,
1735
};
1736
// *INDENT-ON*
1737
1738
extern const struct gps_type_t driver_allystar;
1739
extern const struct gps_type_t driver_casic;
1740
extern const struct gps_type_t driver_evermore;
1741
extern const struct gps_type_t driver_garmin_ser_binary;
1742
extern const struct gps_type_t driver_garmin_usb_binary;
1743
extern const struct gps_type_t driver_geostar;
1744
extern const struct gps_type_t driver_greis;
1745
extern const struct gps_type_t driver_italk;
1746
extern const struct gps_type_t driver_navcom;
1747
extern const struct gps_type_t driver_nmea2000;
1748
extern const struct gps_type_t driver_oncore;
1749
extern const struct gps_type_t driver_sirf;
1750
extern const struct gps_type_t driver_skytraq;
1751
extern const struct gps_type_t driver_superstar2;
1752
extern const struct gps_type_t driver_tsip;
1753
extern const struct gps_type_t driver_ubx;
1754
extern const struct gps_type_t driver_zodiac;
1755
1756
// the point of this rigamarole is to not have to export a table size
1757
static const struct gps_type_t *gpsd_driver_array[] = {
1758
    &driver_unknown,
1759
    &driver_nmea0183,
1760
    &driver_allystar,
1761
    &driver_is,
1762
    &driver_ashtech,
1763
    &driver_casic,
1764
#ifdef TRIPMATE_ENABLE
1765
    &driver_tripmate,
1766
#endif  // TRIPMATE_ENABLE
1767
#ifdef EARTHMATE_ENABLE
1768
    &driver_earthmate,
1769
#endif  // EARTHMATE_ENABLE
1770
#ifdef GPSCLOCK_ENABLE
1771
    &driver_gpsclock,
1772
#endif  // GPSCLOCK_ENABLE
1773
#ifdef GARMIN_ENABLE
1774
    &driver_garmin,
1775
#endif  // GARMIN_ENABLE
1776
    &driver_mtk3301,
1777
#ifdef FV18_ENABLE
1778
    &driver_fv18,
1779
#endif  // FV18_ENABLE
1780
#ifdef TNT_ENABLE
1781
    &driver_trueNorth,
1782
#endif  // TNT_ENABLE
1783
#ifdef FURY_ENABLE
1784
    &driver_fury,
1785
#endif  // FURY_ENABLE
1786
#ifdef AIVDM_ENABLE
1787
    &driver_aivdm,
1788
#endif  // AIVDM_ENABLE
1789
1790
#ifdef EVERMORE_ENABLE
1791
    &driver_evermore,
1792
#endif  // EVERMORE_ENABLE
1793
#ifdef GARMIN_ENABLE
1794
    // be sure to try Garmin Serial Binary before Garmin USB Binary
1795
    &driver_garmin_ser_binary,
1796
    &driver_garmin_usb_binary,
1797
#endif  // GARMIN_ENABLE
1798
#ifdef GEOSTAR_ENABLE
1799
    &driver_geostar,
1800
#endif  // GEOSTAR_ENABLE
1801
#ifdef GREIS_ENABLE
1802
    &driver_greis,
1803
#endif  // GREIS_ENABLE
1804
#ifdef ITRAX_ENABLE
1805
    &driver_italk,
1806
#endif  // ITRAX_ENABLE
1807
#ifdef ONCORE_ENABLE
1808
    &driver_oncore,
1809
#endif  // ONCORE_ENABLE
1810
#ifdef NAVCOM_ENABLE
1811
    &driver_navcom,
1812
#endif  // NAVCOM_ENABLE
1813
#ifdef SIRF_ENABLE
1814
    &driver_sirf,
1815
#endif  // SIRF_ENABLE
1816
#ifdef SKYTRAQ_ENABLE
1817
    &driver_skytraq,
1818
#endif  // SKYTRAQ_ENABLE
1819
    &driver_spartn,
1820
#ifdef SUPERSTAR2_ENABLE
1821
    &driver_superstar2,
1822
#endif  // SUPERSTAR2_ENABLE
1823
#ifdef TSIP_ENABLE
1824
    &driver_tsip,
1825
#endif  // TSIP_ENABLE
1826
#ifdef ISYNC_ENABLE
1827
    &driver_isync,
1828
#endif  // ISYNC_ENABLE
1829
    &driver_ubx,
1830
#ifdef ZODIAC_ENABLE
1831
    &driver_zodiac,
1832
#endif  // ZODIAC_ENABLE
1833
1834
#ifdef NMEA2000_ENABLE
1835
    &driver_nmea2000,
1836
#endif  // NMEA2000_ENABLE
1837
1838
    &driver_rtcm104v2,
1839
    &driver_rtcm104v3,
1840
#ifdef GARMINTXT_ENABLE
1841
    &driver_garmintxt,
1842
#endif  // GARMINTXT_ENABLE
1843
1844
    &driver_json_passthrough,
1845
    &driver_pps,
1846
    NULL,
1847
};
1848
1849
const struct gps_type_t **gpsd_drivers = &gpsd_driver_array[0];
1850
// vim: set expandtab shiftwidth=4