Coverage Report

Created: 2026-03-03 06:57

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
32.5k
{
25
32.5k
    if (BAD_PACKET == session->lexer.type ||
26
32.5k
        COMMENT_PACKET == session->lexer.type) {
27
        // ignore bad packets and comment packets
28
0
        return 0;
29
0
    }
30
31
32.5k
    if (NMEA_PACKET == session->lexer.type) {
32
32.0k
        const struct gps_type_t **dp;
33
32.0k
        gps_mask_t st = 0;
34
32.0k
        char *sentence = (char *)session->lexer.outbuffer;
35
36
32.0k
        if ('\n' != sentence[strnlen(sentence,
37
32.0k
                                     sizeof(session->lexer.outbuffer)) - 1]) {
38
934
            GPSD_LOG(LOG_IO, &session->context->errout,
39
934
                     "<= GPS: %s\n", sentence);
40
31.1k
        } else {
41
31.1k
            GPSD_LOG(LOG_IO, &session->context->errout,
42
31.1k
                     "<= GPS: %s", sentence);
43
31.1k
        }
44
45
32.0k
        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
288k
                str_starts_with(sentence, trigger)) {
54
1.93k
                GPSD_LOG(LOG_PROG, &session->context->errout,
55
1.93k
                         "found trigger string %s.\n", trigger);
56
1.93k
                if (*dp != session->device_type) {
57
1.53k
                    (void)gpsd_switch_driver(session, (*dp)->type_name);
58
1.53k
                    if (NULL != session->device_type &&
59
1.53k
                        NULL != session->device_type->event_hook) {
60
1.40k
                        session->device_type->event_hook(session,
61
1.40k
                                                         EVENT_TRIGGERMATCH);
62
1.40k
                    st |= DEVICEID_SET;
63
1.40k
                    }
64
1.53k
                }
65
1.93k
            }
66
1.18M
        }
67
32.0k
        return st;
68
32.0k
    }
69
70
507
    GPSD_LOG(LOG_SHOUT, &session->context->errout,
71
507
             "packet type %d fell through (should never happen): %s.\n",
72
507
             session->lexer.type, gpsd_prettydump(session));
73
507
    return 0;
74
32.5k
}
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
42.6k
{
119
42.6k
    if (session->context->readonly) {
120
13.6k
        return;
121
13.6k
    }
122
    /*
123
     * This is where we try to tickle NMEA devices into revealing their
124
     * inner natures.
125
     */
126
28.9k
    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
25.6k
        switch (session->lexer.counter) {
145
402
        case 0:
146
            // probe for Garmin serial GPS -- expect $PGRMC followed by data
147
402
            GPSD_LOG(LOG_PROG, &session->context->errout,
148
402
                     "=> Probing for Garmin NMEA\n");
149
402
            (void)nmea_send(session, "$PGRMCE");
150
402
            break;
151
0
#ifdef SIRF_ENABLE
152
2.11k
        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
2.11k
            GPSD_LOG(LOG_PROG, &session->context->errout,
171
2.11k
                     "=> Probing for SiRF\n");
172
2.11k
            (void)nmea_send(session,
173
2.11k
                            "$PSRF100,0,%d,%d,%d,0",
174
2.11k
                            session->gpsdata.dev.baudrate,
175
2.11k
                            9 - session->gpsdata.dev.stopbits,
176
2.11k
                            session->gpsdata.dev.stopbits);
177
2.11k
            break;
178
0
#endif  // SIRF_ENABLE
179
1.81k
        case 2:
180
            // probe for the FV-18 -- expect $PFEC,GPint followed by data
181
1.81k
            GPSD_LOG(LOG_PROG, &session->context->errout,
182
1.81k
                     "=> Probing for FV-18\n");
183
1.81k
            (void)nmea_send(session, "$PFEC,GPint");
184
1.81k
            break;
185
1.57k
        case 3:
186
            // probe for the Trimble Copernicus
187
1.57k
            GPSD_LOG(LOG_PROG, &session->context->errout,
188
1.57k
                     "=> Probing for Trimble Copernicus\n");
189
1.57k
            (void)nmea_send(session, "$PTNLSNM,0139,01");
190
1.57k
            break;
191
0
#ifdef EVERMORE_ENABLE
192
1.28k
        case 4:
193
1.28k
            GPSD_LOG(LOG_PROG, &session->context->errout,
194
1.28k
                     "=> 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.28k
            (void)gpsd_write(session,
200
1.28k
                             "\x10\x02\x12\x8E\x7F\x01\x01\x00\x01\x01\x01"
201
1.28k
                             "\x00\x00\x00\x00\x00\x00\x00\x00\x13\x10\x03",
202
1.28k
                             22);
203
1.28k
            break;
204
0
#endif  // EVERMORE_ENABLE
205
0
#ifdef GPSCLOCK_ENABLE
206
1.05k
        case 5:
207
            /* probe for Furuno Electric GH-79L4-N (GPSClock);
208
             * expect $PFEC,GPssd */
209
1.05k
            GPSD_LOG(LOG_PROG, &session->context->errout,
210
1.05k
                     "=> Probing for GPSClock\n");
211
1.05k
            (void)nmea_send(session, "$PFEC,GPsrq");
212
1.05k
            break;
213
0
#endif  // GPSCLOCK_ENABLE
214
945
        case 6:
215
            // probe for Ashtech -- expect $PASHR,RID
216
945
            GPSD_LOG(LOG_PROG, &session->context->errout,
217
945
                     "=> Probing for Ashtech\n");
218
945
            (void)nmea_send(session, "$PASHQ,RID");
219
945
            break;
220
884
        case 7:
221
            // probe for UBX
222
884
            GPSD_LOG(LOG_PROG, &session->context->errout,
223
884
                     "=> Probing for UBX\n");
224
            // query port configuration UBX-MON-VER
225
884
            (void)ubx_write(session, 0x0a, 0x04, NULL, 0);
226
            // query port configuration UBX-CFG-PRT
227
884
            (void)ubx_write(session, 0x06, 0x00, NULL, 0);
228
884
            break;
229
831
        case 8:
230
            // probe for MTK-3301 -- expect $PMTK705
231
831
            GPSD_LOG(LOG_PROG, &session->context->errout,
232
831
                     "=> Probing for MediaTek\n");
233
831
            (void)nmea_send(session, "$PMTK605");
234
831
            break;
235
0
#ifdef GREIS_ENABLE
236
707
        case 9:
237
            // probe for Javad GREIS -- expect reply with JAVAD
238
707
            GPSD_LOG(LOG_PROG, &session->context->errout,
239
707
                     "=> Probing for Javad GREIS\n");
240
            // TODO: confirm this actually gets JAVAD response
241
707
            (void)nmea_send(session, "print,/par/rcv/vendor");
242
707
            break;
243
0
#endif  // GREIS_ENABLE
244
653
        case 10:
245
            // probe for ALLYSTAR
246
653
            GPSD_LOG(LOG_PROG, &session->context->errout,
247
653
                     "=> Probing for ALLYSTAR\n");
248
            // query version MON-VER
249
653
            (void)ally_write(session, 0x0a, 0x04, NULL, 0);
250
653
            break;
251
613
        case 11:
252
            // probe for CASIC
253
613
            GPSD_LOG(LOG_PROG, &session->context->errout,
254
613
                     "=> Probing for CASIC\n");
255
            // query version MON-VER
256
613
            (void)casic_write(session, 0x0a, 0x04, NULL, 0);
257
613
            break;
258
12.7k
        default:
259
12.7k
            break;
260
25.6k
        }
261
25.6k
    }
262
28.9k
}
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
1.41k
{
312
1.41k
    if (session->context->readonly) {
313
65
        return;
314
65
    }
315
316
1.34k
    if (event == EVENT_DRIVER_SWITCH) {
317
        // forces a reconfigure as the following packets come in
318
242
        session->lexer.counter = 0;
319
242
    }
320
1.34k
    if (session->context->passive) {
321
79
        return;
322
79
    }
323
1.26k
    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
801
        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
203
        case 1:
339
            // once a sec, no averaging, NMEA 2.3, WAAS
340
203
            (void)nmea_send(session, "$PGRMC1,1,1,1,,,,2,W,N");
341
203
            break;
342
126
        case 2:
343
            // get some more config info
344
126
            (void)nmea_send(session, "$PGRMC1E");
345
126
            break;
346
111
        case 3:
347
            // turn off all output except GGA
348
111
            (void)nmea_send(session, "$PGRMO,,2");
349
111
            (void)nmea_send(session, "$PGRMO,GPGGA,1");
350
111
            break;
351
62
        case 4:
352
            // enable GPGGA, GPGSA, GPGSV, GPRMC on Garmin serial GPS
353
62
            (void)nmea_send(session, "$PGRMO,GPGSA,1");
354
62
            break;
355
57
        case 5:
356
57
            (void)nmea_send(session, "$PGRMO,GPGSV,1");
357
57
            break;
358
41
        case 6:
359
41
            (void)nmea_send(session, "$PGRMO,GPRMC,1");
360
41
            break;
361
33
        case 7:
362
33
            (void)nmea_send(session, "$PGRMO,PGRME,1");
363
33
            break;
364
801
        }
365
801
    }
366
1.26k
}
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
464
{
450
464
    if (session->context->readonly) {
451
67
        return;
452
67
    }
453
454
397
    if (event == EVENT_WAKEUP) {
455
0
        (void)nmea_send(session, "$PASHQ,RID");
456
0
    }
457
458
397
    if (session->context->passive) {
459
73
        return;
460
73
    }
461
324
    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
324
}
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
319
{
512
319
    if (session->context->readonly) {
513
106
        return;
514
106
    }
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
213
    if (event == EVENT_IDENTIFIED ||
523
213
        event == EVENT_REACTIVATE) {
524
0
        (void)nmea_send(session,
525
0
                        "$PFEC,GPint,GSA01,DTM00,ZDA01,RMC01,GLL00,VTG00,GSV05");
526
0
    }
527
213
}
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
305
{
782
305
    if (session->context->readonly) {
783
89
        return;
784
89
    }
785
216
    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
216
}
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.70k
{
891
5.70k
    rtcm2_unpack(session, &session->gpsdata.rtcm2,
892
5.70k
                 (char *)session->lexer.isgps.buf);
893
5.70k
    session->cycle_end_reliable = true;
894
5.70k
    return RTCM2_SET;
895
5.70k
}
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
14.7k
{
929
14.7k
    uint16_t type = getbeu16(session->lexer.outbuffer, 3) >> 4;
930
931
14.7k
    GPSD_LOG(LOG_RAW, &session->context->errout, "RTCM 3.x packet %d\n", type);
932
14.7k
    rtcm3_unpack(session->context,
933
14.7k
                 &session->gpsdata.rtcm3,
934
14.7k
                 session->lexer.outbuffer);
935
14.7k
    session->cycle_end_reliable = true;
936
14.7k
    return RTCM3_SET;
937
14.7k
}
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
1.16k
{
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
1.16k
    if (session->context->readonly) {
1046
356
        return;
1047
356
    }
1048
805
    if (event == EVENT_TRIGGERMATCH) {
1049
190
        (void)nmea_send(session, "$PMTK320,0");  // power save off
1050
        // Fix interval, 1000 milliseconds
1051
190
        (void)nmea_send(session, "$PMTK300,1000,0,0,0.0,0.0");
1052
        // Set NMEA sentences.
1053
190
        (void)nmea_send(session,
1054
190
                        "$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
190
        (void)nmea_send(session, "$PMTK301,2");
1057
        // SBAS enable
1058
190
        (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
190
         (void)nmea_send(session, "$PMTK424");
1064
190
    }
1065
805
}
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
9.92k
{
1155
    // 80 nseems a reasonable max, and strnlen() shuts up Codacy.
1156
9.92k
    return gpsd_write(session, data, strnlen(data, 80));
1157
9.92k
}
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
5.41k
{
1184
5.41k
    if (session->context->readonly) {
1185
79
        return;
1186
79
    }
1187
1188
5.33k
    if (event == EVENT_DRIVER_SWITCH) {
1189
810
        session->lexer.counter = 0;
1190
810
    }
1191
1192
5.33k
    if (event == EVENT_CONFIGURE) {
1193
3.71k
        switch (session->lexer.counter) {
1194
750
        case 1:
1195
            /* Configure timing and frequency flags:
1196
             *  - Thermal compensation active
1197
             *  - PPSREF active
1198
             *  - PPSOUT active
1199
             */
1200
750
            (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
750
            (void)isync_write(session, "MAW0513\r\n");
1207
            /* Configure tracking start flags:
1208
             *  - Tracking restart allowed
1209
             *  - Align to PPSREF
1210
             */
1211
750
            (void)isync_write(session, "MAW0606\r\n");
1212
            /* Configure tracking window:
1213
             *  - 4us
1214
             */
1215
750
            (void)isync_write(session, "MAW1304\r\n");
1216
            /* Configure alarm window:
1217
             *  - 4us
1218
             */
1219
750
            (void)isync_write(session, "MAW1404\r\n");
1220
750
            break;
1221
649
        case 2:
1222
            /* Configure pulse every d second:
1223
             *  - pulse every second
1224
             */
1225
649
            (void)isync_write(session, "MAW1701\r\n");
1226
            /* Configure pulse origin:
1227
             *  - zero offset
1228
             */
1229
649
            (void)isync_write(session, "MAW1800\r\n");
1230
            /* Configure pulse width:
1231
             *  - 600ms
1232
             */
1233
649
            (void)isync_write(session, "MAW1223C34600\r\n");
1234
649
            break;
1235
622
        case 3:
1236
            /* Configure GPS resource utilization:
1237
             *  - do not consider GPS messages
1238
             */
1239
622
            (void)isync_write(session, "MAW2200\r\n");
1240
            // Restart sync
1241
622
            (void)isync_write(session, "SY1\r\n");
1242
            // Restart tracking
1243
622
            (void)isync_write(session, "TR1\r\n");
1244
622
            break;
1245
596
        case 4:
1246
            // Cancel BTx messages (if any)
1247
596
            (void)isync_write(session, "BT0\r\n");
1248
            /* Configure messages coming out every second:
1249
             *  - Oscillator status ($PTNTA) at 750ms
1250
             */
1251
596
            (void)isync_write(session, "MAW0B00\r\n");
1252
596
            (void)isync_write(session, "MAW0C0A\r\n");
1253
596
            break;
1254
572
        case 5:
1255
            /* Enable GPS passthrough and force u-blox driver to
1256
             * select NMEA mode.
1257
             */
1258
572
            session->mode = 0;
1259
572
            session->drivers_identified = 0;
1260
572
            (void)isync_write(session, "@@@@GPS\r\n");
1261
572
            break;
1262
260
        case 6:
1263
            /* Trigger detection of underlying u-blox (if necessary)
1264
             * UBX-CFG-PRT */
1265
260
            (void)ubx_write(session, 0x06, 0x00, NULL, 0);
1266
260
            break;
1267
3.71k
        }
1268
3.71k
    }
1269
5.33k
}
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
11.3k
{
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
11.3k
    int nfrags, ifrag, nfields = 0;
1323
    /* maximum ength of IEC 61162 message is 79 chars
1324
     * we will copy fields here, NUL separated */
1325
11.3k
    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
11.3k
    unsigned char *field[200];
1329
11.3k
    unsigned char *data, *cp;
1330
11.3k
    int pad;
1331
11.3k
    struct aivdm_context_t *ais_context;
1332
11.3k
    int i;
1333
1334
11.3k
    if (0 == buflen) {
1335
0
        return false;
1336
0
    }
1337
1338
    // we may need to dump the raw packet
1339
11.3k
    GPSD_LOG(LOG_PROG, &session->context->errout,
1340
11.3k
             "AIVDM packet length %zd: %s\n", buflen, buf);
1341
1342
    // first clear the result, making sure we don't return garbage
1343
11.3k
    memset(ais, 0, sizeof(*ais));
1344
1345
    // discard overlong sentences
1346
11.3k
    if (buflen > (sizeof(fieldcopy) - 1)) {
1347
38
        GPSD_LOG(LOG_ERROR, &session->context->errout,
1348
38
                 "overlong AIVDM packet.\n");
1349
38
        return false;
1350
38
    }
1351
1352
    // avoid reoccuring CVE here
1353
11.2k
    memset(fieldcopy, 0, sizeof(fieldcopy));
1354
11.2k
    memset(field, 0, sizeof(field));
1355
1356
    // extract packet fields
1357
11.2k
    field[nfields++] = fieldcopy;
1358
716k
    for (i = 0; i < (int)buflen; i++) {
1359
705k
        unsigned char c = buf[i];
1360
1361
705k
        if (!isascii(c)) {
1362
            /* discard sentences with high-half characters in them,
1363
             * they're corrupted. */
1364
71
            GPSD_LOG(LOG_ERROR, &session->context->errout,
1365
71
                     "corrupted AIVDM packet.\n");
1366
71
            return false;
1367
71
        }
1368
705k
        if (((unsigned char)',' == c) ||
1369
633k
            ((unsigned char)'*' == c)) {
1370
84.2k
            c = '\0';
1371
84.2k
            field[nfields++] = &fieldcopy[i] + 1;
1372
84.2k
        }
1373
705k
        fieldcopy[i] = c;
1374
705k
    }
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
11.2k
    if (7 > nfields) {
1384
92
        GPSD_LOG(LOG_ERROR, &session->context->errout,
1385
92
                 "malformed AIVDM packet.\n");
1386
92
        return false;
1387
92
    }
1388
1389
11.1k
    switch (field[4][0]) {
1390
5.57k
    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
5.57k
        if (!str_starts_with((const char *)field[0], "!AIVDO")) {
1397
5.46k
            GPSD_LOG(LOG_INF, &session->context->errout,
1398
5.46k
                     "invalid empty AIS channel. Assuming 'A'\n");
1399
5.46k
        }
1400
5.57k
        ais_context = &session->driver.aivdm.context[0];
1401
5.57k
        session->driver.aivdm.ais_channel ='A';
1402
5.57k
        break;
1403
712
    case '1':
1404
712
        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
646
        FALLTHROUGH
1410
5.21k
    case 'A':
1411
5.21k
        ais_context = &session->driver.aivdm.context[0];
1412
5.21k
        session->driver.aivdm.ais_channel ='A';
1413
5.21k
        break;
1414
70
    case '2':
1415
70
        FALLTHROUGH
1416
137
    case 'B':
1417
137
        ais_context = &session->driver.aivdm.context[1];
1418
137
        session->driver.aivdm.ais_channel ='B';
1419
137
        break;
1420
66
    case 'C':
1421
66
        GPSD_LOG(LOG_INF, &session->context->errout,
1422
66
                 "ignoring AIS channel C (secure AIS).\n");
1423
66
        return false;
1424
81
    default:
1425
81
        GPSD_LOG(LOG_ERROR, &session->context->errout,
1426
81
                 "invalid AIS channel 0x%0X .\n", field[4][0]);
1427
81
        return false;
1428
11.1k
    }
1429
1430
10.9k
    nfrags = atoi((char *)field[1]);  // number of fragments to expect
1431
10.9k
    ifrag = atoi((char *)field[2]);   // fragment id
1432
10.9k
    data = field[5];
1433
1434
10.9k
    pad = 0;
1435
10.9k
    if(isdigit(field[6][0])) {
1436
5.51k
        pad = field[6][0] - '0';  // number of padding bits ASCII encoded
1437
5.51k
    }
1438
10.9k
    GPSD_LOG(LOG_PROG, &session->context->errout,
1439
10.9k
             "nfrags %d ifrag %d decoded_frags %d data %s pad %d "
1440
10.9k
             "bitlen %zu datalen %zu\n",
1441
10.9k
             nfrags, ifrag, ais_context->decoded_frags, data, pad,
1442
10.9k
             ais_context->bitlen, strnlen((char *)data, 256));
1443
1444
    // assemble the binary data
1445
1446
    // check fragment ordering
1447
10.9k
    if (ifrag != ais_context->decoded_frags + 1) {
1448
283
        GPSD_LOG(LOG_ERROR, &session->context->errout,
1449
283
                 "invalid fragment #%d received, expected #%d.\n",
1450
283
                 ifrag, ais_context->decoded_frags + 1);
1451
283
        if (1 != ifrag) {
1452
173
            return false;
1453
173
        }
1454
        /* else, ifrag==1: Just discard all that was previously decoded and
1455
         * simply handle that packet */
1456
110
        ais_context->decoded_frags = 0;
1457
110
    }
1458
10.7k
    if (1 == ifrag) {
1459
10.6k
        (void)memset(ais_context->bits, '\0', sizeof(ais_context->bits));
1460
10.6k
        ais_context->bitlen = 0;
1461
10.6k
    }
1462
1463
    /* wacky 6-bit encoding, shades of FIELDATA
1464
     * Max 256 data chars is a guess, to pacify Codacy
1465
     * IEC61993.pdf implies 84.
1466
     * Max bitlen is likely 1008, max see is 776 */
1467
391k
    for (cp = data; cp < data + strnlen((char *)data, 256); cp++) {
1468
381k
        unsigned char ch;
1469
381k
        ch = *cp;
1470
381k
        ch -= 48;
1471
381k
        if (ch >= 40) {
1472
144k
            ch -= 8;
1473
144k
        }
1474
#ifdef __UNUSED_DEBUG__
1475
        GPSD_LOG(LOG_RAW, &session->context->errout,
1476
                 "%c: %s\n", *cp, sixbits[ch]);
1477
#endif  // __UNUSED_DEBUG__
1478
381k
        if (sizeof(ais_context->bits) <=
1479
381k
            (ais_context->bitlen + 6)) {
1480
            // FIXME?  Maybe move above the previsou for() ??
1481
0
            GPSD_LOG(LOG_INF, &session->context->errout,
1482
0
                     "overlong AIVDM payload ignored.\n");
1483
0
            (void)memset(ais_context->bits, '\0',
1484
0
                         sizeof(ais_context->bits));
1485
0
            ais_context->bitlen = 0;
1486
0
            return false;
1487
0
        }
1488
2.66M
        for (i = 5; i >= 0; i--) {
1489
2.28M
            if ((ch >> i) & 0x01) {
1490
955k
                ais_context->bits[ais_context->bitlen / 8] |=
1491
955k
                    (1 << (7 - ais_context->bitlen % 8));
1492
955k
            }
1493
2.28M
            ais_context->bitlen++;
1494
2.28M
        }
1495
381k
    }
1496
10.7k
    ais_context->bitlen -= pad;
1497
10.7k
    if (ais_context->bitlen >= sizeof(ais_context->bits)) {
1498
95
        GPSD_LOG(LOG_INF, &session->context->errout,
1499
95
                 "invalid bitlen AIVDM payload ignored.\n");
1500
95
        (void)memset(ais_context->bits, '\0',
1501
95
                     sizeof(ais_context->bits));
1502
95
        ais_context->bitlen = 0;
1503
95
        return false;
1504
95
    }
1505
1506
    // time to pass buffered-up data to where it's actually processed?
1507
10.6k
    if (ifrag == nfrags) {
1508
10.4k
        if (debug >= LOG_INF) {
1509
0
            size_t clen = BITS_TO_BYTES(ais_context->bitlen);
1510
0
            GPSD_LOG(LOG_INF, &session->context->errout,
1511
0
                     "AIVDM payload is %zd bits, %zd chars: %s\n",
1512
0
                     ais_context->bitlen, clen,
1513
0
                     gps_hexdump(session->msgbuf, sizeof(session->msgbuf),
1514
0
                                 ais_context->bits, clen));
1515
0
        }
1516
1517
        // clear waiting fragments count
1518
10.4k
        ais_context->decoded_frags = 0;
1519
1520
        // decode the assembled binary packet
1521
10.4k
        return ais_binary_decode(&session->context->errout,
1522
10.4k
                                 ais,
1523
10.4k
                                 ais_context->bits,
1524
10.4k
                                 ais_context->bitlen,
1525
10.4k
                                 &ais_context->type24_queue);
1526
10.4k
    }
1527
1528
    // we're still waiting on another sentence
1529
206
    ais_context->decoded_frags++;
1530
206
    return false;
1531
10.6k
}
1532
1533
static gps_mask_t aivdm_analyze(struct gps_device_t *session)
1534
11.3k
{
1535
11.3k
    if (session->lexer.type == AIVDM_PACKET) {
1536
11.3k
        if (aivdm_decode(session->lexer.outbuffer, session->lexer.outbuflen,
1537
11.3k
                         session, &session->gpsdata.ais,
1538
11.3k
                         session->context->errout.debug)) {
1539
7.29k
            return ONLINE_SET | AIS_SET;
1540
7.29k
        }
1541
        // else
1542
4.04k
        return ONLINE_SET;
1543
11.3k
    }
1544
0
    if (session->lexer.type == NMEA_PACKET) {
1545
0
        return nmea_parse((char *)session->lexer.outbuffer, session);
1546
0
    }
1547
    // else
1548
0
    return 0;
1549
0
}
1550
1551
// *INDENT-OFF*
1552
const struct gps_type_t driver_aivdm = {
1553
    // Full name of type
1554
    .type_name        = "AIVDM",        // associated lexer packet type
1555
    .packet_type      = AIVDM_PACKET,   // numeric packet type
1556
    .flags            = DRIVER_NOFLAGS, // no rollover or other flags
1557
    .trigger          = NULL,           // identifying response
1558
    .channels         = 0,              // not used by this driver
1559
    .probe_detect     = NULL,           // no probe
1560
    .get_packet       = packet_get1,    // how to get a packet
1561
    .parse_packet     = aivdm_analyze,  // how to analyze a packet
1562
    .rtcm_writer      = NULL,           // don't send RTCM data,
1563
    .init_query       = NULL,           // non-perturbing initial query
1564
    .event_hook       = NULL,           // lifetime event handler
1565
    .speed_switcher   = NULL,           // no speed switcher
1566
    .mode_switcher    = NULL,           // no mode switcher
1567
    .rate_switcher    = NULL,           // no rate switcher
1568
    .min_cycle.tv_sec  = 1,             // max 1Hz
1569
    .min_cycle.tv_nsec = 0,
1570
    .control_send     = NULL,           // no control sender
1571
    .time_offset     = NULL,            // no NTP communication
1572
};
1573
// *INDENT-ON*
1574
#endif  // AIVDM_ENABLE
1575
1576
/**************************************************************************
1577
 *
1578
 * JSON passthrough driver
1579
 *
1580
 **************************************************************************/
1581
1582
// prepend the session path to the value of a specified attribute
1583
static void path_rewrite(struct gps_device_t *session, char *prefix)
1584
0
{
1585
    /*
1586
     * Hack the packet to reflect its origin.  This code is supposed
1587
     * to insert the path naming the remote gpsd instance into the
1588
     * beginning of the path attribute, followed by a # to separate it
1589
     * from the device.
1590
     */
1591
0
    char *prefloc;
1592
1593
0
    assert(prefix != NULL && session->lexer.outbuffer != NULL);
1594
1595
    // possibly the rewrite has been done already, this comw up in gpsmon
1596
0
    if (strstr((char *)session->lexer.outbuffer,
1597
0
               session->gpsdata.dev.path) != NULL) {
1598
0
        return;
1599
0
    }
1600
1601
0
    for (prefloc = (char *)session->lexer.outbuffer;
1602
0
         prefloc < (char *)session->lexer.outbuffer+session->lexer.outbuflen;
1603
0
         prefloc++) {
1604
0
        if (str_starts_with(prefloc, prefix)) {
1605
0
            char *sfxloc;
1606
0
            char copy[sizeof(session->lexer.outbuffer)+1];
1607
0
            (void)strlcpy(copy,
1608
0
                          (char *)session->lexer.outbuffer,
1609
0
                          sizeof(copy));
1610
0
            prefloc += strlen(prefix);
1611
0
            (void)strlcpy(prefloc,
1612
0
                          session->gpsdata.dev.path,
1613
0
                          sizeof(session->gpsdata.dev.path));
1614
0
            sfxloc = strchr(prefloc, '#');
1615
0
            if (sfxloc) {
1616
0
                *sfxloc = '\0';  // Avoid accumulating multiple device names
1617
0
            }
1618
0
            (void)strlcat((char *)session->lexer.outbuffer, "#",
1619
0
                          sizeof(session->lexer.outbuffer));
1620
0
            (void)strlcat((char *)session->lexer.outbuffer,
1621
0
                          copy + (prefloc-(char *)session->lexer.outbuffer),
1622
0
                          sizeof(session->lexer.outbuffer));
1623
0
        }
1624
0
    }
1625
0
    session->lexer.outbuflen = strnlen((char *)session->lexer.outbuffer,
1626
0
                                       sizeof(session->lexer.outbuffer));
1627
0
}
1628
1629
static gps_mask_t json_pass_packet(struct gps_device_t *session)
1630
86
{
1631
86
    GPSD_LOG(LOG_IO, &session->context->errout,
1632
86
             "<= GPS: %s\n", (char *)session->lexer.outbuffer);
1633
1634
86
    if (strstr(session->gpsdata.dev.path, ":/") != NULL &&
1635
0
        strstr(session->gpsdata.dev.path, "localhost") == NULL) {
1636
        // devices and paths need to be edited
1637
0
        if (strstr((char *)session->lexer.outbuffer, "DEVICE") != NULL) {
1638
0
            path_rewrite(session, "\"path\":\"");
1639
0
        }
1640
0
        path_rewrite(session, "\"device\":\"");
1641
1642
        // mark certain responses without a path or device attribute
1643
0
        if (session->gpsdata.dev.path[0] != '\0') {
1644
0
            if (strstr((char *)session->lexer.outbuffer, "VERSION") != NULL ||
1645
0
                strstr((char *)session->lexer.outbuffer, "WATCH") != NULL ||
1646
0
                strstr((char *)session->lexer.outbuffer, "DEVICES") != NULL) {
1647
0
                session->lexer.outbuffer[session->lexer.outbuflen-1] = '\0';
1648
0
                (void)strlcat((char *)session->lexer.outbuffer, ",\"remote\":\"",
1649
0
                              sizeof(session->lexer.outbuffer));
1650
0
                (void)strlcat((char *)session->lexer.outbuffer,
1651
0
                              session->gpsdata.dev.path,
1652
0
                              sizeof(session->lexer.outbuffer));
1653
0
                (void)strlcat((char *)session->lexer.outbuffer, "\"}",
1654
0
                              sizeof(session->lexer.outbuffer));
1655
0
            }
1656
0
            session->lexer.outbuflen = strnlen(
1657
0
                (char *)session->lexer.outbuffer,
1658
0
                sizeof(session->lexer.outbuffer));
1659
0
        }
1660
0
    }
1661
86
    GPSD_LOG(LOG_PROG, &session->context->errout,
1662
86
             "JSON, passing through %s\n",
1663
86
             (char *)session->lexer.outbuffer);
1664
86
    return PASSTHROUGH_IS;
1665
86
}
1666
1667
// *INDENT-OFF*
1668
const struct gps_type_t driver_json_passthrough = {
1669
    .type_name      = "JSON slave driver",      // full name of type
1670
    .packet_type    = JSON_PACKET,      // associated lexer packet type
1671
    .flags          = DRIVER_NOFLAGS,   // don't remember this
1672
    .trigger        = NULL,             // it's the default
1673
    .channels       = 0,                // not used
1674
    .probe_detect   = NULL,             // no probe
1675
    .get_packet     = packet_get1,      // use generic packet getter
1676
    .parse_packet   = json_pass_packet, // how to interpret a packet
1677
    .rtcm_writer    = NULL,             // write RTCM data straight
1678
    .init_query     = NULL,             // non-perturbing initial query
1679
    .event_hook     = NULL,             // lifetime event handler
1680
    .speed_switcher = NULL,             // no speed switcher
1681
    .mode_switcher  = NULL,             // no mode switcher
1682
    .rate_switcher  = NULL,             // no sample-rate switcher
1683
    .min_cycle.tv_sec  = 1,             // not relevant, no rate switch
1684
    .min_cycle.tv_nsec = 0,             // not relevant, no rate switch
1685
    .control_send   = NULL,             // how to send control strings
1686
    .time_offset     = NULL,            // no method for NTP fudge factor
1687
};
1688
// *INDENT-ON*
1689
1690
1691
// *INDENT-OFF*
1692
const struct gps_type_t driver_pps = {
1693
    .type_name      = "PPS",            // full name of type
1694
    .packet_type    = BAD_PACKET,       // associated lexer packet type
1695
    .flags          = DRIVER_NOFLAGS,   // don't remember this
1696
    .trigger        = NULL,             // it's the default
1697
    .channels       = 0,                // not used
1698
    .probe_detect   = NULL,             // no probe
1699
    .get_packet     = NULL,             // use generic packet getter
1700
    .parse_packet   = NULL,             // how to interpret a packet
1701
    .rtcm_writer    = NULL,             // write RTCM data straight
1702
    .init_query     = NULL,             // non-perturbing initial query
1703
    .event_hook     = NULL,             // lifetime event handler
1704
    .speed_switcher = NULL,             // no speed switcher
1705
    .mode_switcher  = NULL,             // no mode switcher
1706
    .rate_switcher  = NULL,             // no sample-rate switcher
1707
    .min_cycle.tv_sec  = 1,             // not relevant, no rate switch
1708
    .min_cycle.tv_nsec = 0,             // not relevant, no rate switch
1709
    .control_send   = NULL,             // how to send control strings
1710
    .time_offset     = NULL,            // no method for NTP fudge factor
1711
};
1712
1713
static const struct gps_type_t driver_spartn = {
1714
    .type_name     = "SPARTN",          // full name of type
1715
    .packet_type   = SPARTN_PACKET,     // associated lexer packet type
1716
    .flags         = DRIVER_NOFLAGS,    // no rollover or other flags
1717
    .trigger       = NULL,              // no recognition string
1718
    .channels      = 0,                 // not used
1719
    .probe_detect  = NULL,              // no probe
1720
    .get_packet    = NULL,              // use generic packet getter
1721
    .parse_packet  = spartn_parse,      //
1722
    .rtcm_writer   = NULL,              // Do not write back to NTRIP!
1723
    .init_query    = NULL,              // non-perturbing initial query
1724
    .event_hook    = NULL,              // no event hook
1725
    .speed_switcher= NULL,              // no speed switcher
1726
    .mode_switcher = NULL,              // no mode switcher
1727
    .rate_switcher = NULL,              // no sample-rate switcher
1728
    // cycle not relevant, no rate switch, but can generate log noise
1729
    .min_cycle.tv_sec  = 10,            // Some NTRIP servers are bursty
1730
    .min_cycle.tv_nsec = 0,             // not relevant, no rate switch
1731
    .control_send   = NULL,             // how to send control strings
1732
    .time_offset     = NULL,
1733
};
1734
// *INDENT-ON*
1735
1736
extern const struct gps_type_t driver_allystar;
1737
extern const struct gps_type_t driver_casic;
1738
extern const struct gps_type_t driver_evermore;
1739
extern const struct gps_type_t driver_garmin_ser_binary;
1740
extern const struct gps_type_t driver_garmin_usb_binary;
1741
extern const struct gps_type_t driver_geostar;
1742
extern const struct gps_type_t driver_greis;
1743
extern const struct gps_type_t driver_italk;
1744
extern const struct gps_type_t driver_navcom;
1745
extern const struct gps_type_t driver_nmea2000;
1746
extern const struct gps_type_t driver_oncore;
1747
extern const struct gps_type_t driver_sirf;
1748
extern const struct gps_type_t driver_skytraq;
1749
extern const struct gps_type_t driver_superstar2;
1750
extern const struct gps_type_t driver_tsip;
1751
extern const struct gps_type_t driver_ubx;
1752
extern const struct gps_type_t driver_zodiac;
1753
1754
// the point of this rigamarole is to not have to export a table size
1755
static const struct gps_type_t *gpsd_driver_array[] = {
1756
    &driver_unknown,
1757
    &driver_nmea0183,
1758
    &driver_allystar,
1759
    &driver_is,
1760
    &driver_ashtech,
1761
    &driver_casic,
1762
#ifdef TRIPMATE_ENABLE
1763
    &driver_tripmate,
1764
#endif  // TRIPMATE_ENABLE
1765
#ifdef EARTHMATE_ENABLE
1766
    &driver_earthmate,
1767
#endif  // EARTHMATE_ENABLE
1768
#ifdef GPSCLOCK_ENABLE
1769
    &driver_gpsclock,
1770
#endif  // GPSCLOCK_ENABLE
1771
#ifdef GARMIN_ENABLE
1772
    &driver_garmin,
1773
#endif  // GARMIN_ENABLE
1774
    &driver_mtk3301,
1775
#ifdef FV18_ENABLE
1776
    &driver_fv18,
1777
#endif  // FV18_ENABLE
1778
#ifdef TNT_ENABLE
1779
    &driver_trueNorth,
1780
#endif  // TNT_ENABLE
1781
#ifdef FURY_ENABLE
1782
    &driver_fury,
1783
#endif  // FURY_ENABLE
1784
#ifdef AIVDM_ENABLE
1785
    &driver_aivdm,
1786
#endif  // AIVDM_ENABLE
1787
1788
#ifdef EVERMORE_ENABLE
1789
    &driver_evermore,
1790
#endif  // EVERMORE_ENABLE
1791
#ifdef GARMIN_ENABLE
1792
    // be sure to try Garmin Serial Binary before Garmin USB Binary
1793
    &driver_garmin_ser_binary,
1794
    &driver_garmin_usb_binary,
1795
#endif  // GARMIN_ENABLE
1796
#ifdef GEOSTAR_ENABLE
1797
    &driver_geostar,
1798
#endif  // GEOSTAR_ENABLE
1799
#ifdef GREIS_ENABLE
1800
    &driver_greis,
1801
#endif  // GREIS_ENABLE
1802
#ifdef ITRAX_ENABLE
1803
    &driver_italk,
1804
#endif  // ITRAX_ENABLE
1805
#ifdef ONCORE_ENABLE
1806
    &driver_oncore,
1807
#endif  // ONCORE_ENABLE
1808
#ifdef NAVCOM_ENABLE
1809
    &driver_navcom,
1810
#endif  // NAVCOM_ENABLE
1811
#ifdef SIRF_ENABLE
1812
    &driver_sirf,
1813
#endif  // SIRF_ENABLE
1814
#ifdef SKYTRAQ_ENABLE
1815
    &driver_skytraq,
1816
#endif  // SKYTRAQ_ENABLE
1817
    &driver_spartn,
1818
#ifdef SUPERSTAR2_ENABLE
1819
    &driver_superstar2,
1820
#endif  // SUPERSTAR2_ENABLE
1821
#ifdef TSIP_ENABLE
1822
    &driver_tsip,
1823
#endif  // TSIP_ENABLE
1824
#ifdef ISYNC_ENABLE
1825
    &driver_isync,
1826
#endif  // ISYNC_ENABLE
1827
    &driver_ubx,
1828
#ifdef ZODIAC_ENABLE
1829
    &driver_zodiac,
1830
#endif  // ZODIAC_ENABLE
1831
1832
#ifdef NMEA2000_ENABLE
1833
    &driver_nmea2000,
1834
#endif  // NMEA2000_ENABLE
1835
1836
    &driver_rtcm104v2,
1837
    &driver_rtcm104v3,
1838
#ifdef GARMINTXT_ENABLE
1839
    &driver_garmintxt,
1840
#endif  // GARMINTXT_ENABLE
1841
1842
    &driver_json_passthrough,
1843
    &driver_pps,
1844
    NULL,
1845
};
1846
1847
const struct gps_type_t **gpsd_drivers = &gpsd_driver_array[0];
1848
// vim: set expandtab shiftwidth=4