Coverage Report

Created: 2025-07-11 06:47

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