Coverage Report

Created: 2023-11-19 07:13

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