Coverage Report

Created: 2026-06-10 06:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gpsd/gpsd-3.27.6~dev/drivers/driver_garmin.c
Line
Count
Source
1
/*
2
 * This file contains two drivers for Garmin receivers and some code
3
 * shared by both drivers.
4
 *
5
 * One driver "garmin_usb_binary" handles the Garmin binary packet
6
 * format supported by the USB Garmins tested with the Garmin 18 and
7
 * other models.  (There is also "garmin_usb_binary_old".)  These are ONLY
8
 * for USB devices reporting as: 091e:0003.
9
 *
10
 * The other driver "garmin_ser_binary" is for Garmin receivers via a
11
 * serial port, whether or not one uses a USB/serial adaptor or a real
12
 * serial port.  These receivers provide adequate NMEA support, so it
13
 * often makes sense to just put them into NMEA mode.
14
 *
15
 * On Linux, USB Garmins (091e:0003) need the Linux garmin_gps driver and
16
 * will not function without it.  On other operating systems, it is clear
17
 * garmin_usb_binary_old does not work since it requires the Linux
18
 * garmin_gps module.
19
 *
20
 * This code has been tested and at least at one time is known to work on
21
 * big- and little-endian CPUs and 32 and 64 bit cpu modes.
22
 *
23
 *
24
 * Documentation for the Garmin protocols can be found via
25
 *   http://www.garmin.com/support/commProtocol.html
26
 * The file IOSDK.zip contains IntfSpec.pdf, which describes the
27
 * protocol in terms of Application, Link, and Physical.  This
28
 * identical file is also available at:
29
 *   http://www.garmin.com/support/pdf/iop_spec.pdf
30
 * An older version of iop_spec.pdf that describes only Serial Binary
31
 * is available at:
32
 *   http://vancouver-webpages.com/pub/peter/iop_spec.pdf
33
 * Information about the GPS 18
34
 *   http://www.garmin.com/manuals/425_TechnicalSpecification.pdf
35
 *
36
 * There is one physical link protocol for serial which uses DLE/ETX
37
 * framing.  There is another physical protocol for USB which relies
38
 * on the packetization intrinsic to USB bulk pipes.
39
 *
40
 * There are several link protocols; all devices implement L000.
41
 * There are then product-specific protocols; most devices implement
42
 * L001.  Link protocols are the same and carried over either Physical
43
 * protocol.
44
 *
45
 * Application protocols are named A000 and then with different
46
 * 3-digit numbers.  They are carried over Link protocols.
47
 *
48
 * Thus, much of the higher-level code dealing the data formats is
49
 * shared between USB Binary and Serial Binary.
50
 *
51
 * This code is partly from the Garmin IOSDK and partly from the
52
 * sample code in the Linux garmin_gps driver.
53
 *
54
 * bad code by: Gary E. Miller <gem@rellim.com>
55
 *
56
 * -D 3 = packet trace
57
 * -D 4 = packet details
58
 * -D 5 = more packet details
59
 * -D 6 = very excessive details
60
 *
61
 * limitations:
62
 *
63
 * do not have from garmin:
64
 *      pdop
65
 *      hdop
66
 *      vdop
67
 *      magnetic variation
68
 *
69
 * known bugs:
70
 *      hangs in the fread loop instead of keeping state and returning.
71
 *
72
 * This file is Copyright 2010 by the GPSD project
73
 * SPDX-License-Identifier: BSD-2-clause
74
 */
75
76
#include "../include/gpsd_config.h"   // must be before all includes
77
78
#ifdef GARMIN_ENABLE
79
80
#include <errno.h>
81
#include <math.h>
82
#include <stdbool.h>
83
#include <stdio.h>
84
#include <string.h>
85
#include <time.h>
86
#include <unistd.h>
87
88
#if defined(HAVE_LIBUSB)
89
#include <libusb.h>
90
#endif
91
92
#include "../include/gpsd.h"
93
#include "../include/bits.h"
94
#include "../include/timespec.h"
95
96
12.4k
#define GPSD_LE16TOH(x) getles16((char *)(&(x)), 0)
97
408
#define GPSD_LE32TOH(x) getles32((char *)(&(x)), 0)
98
3.26k
#define GPSD_LEF32(x) getlef32((const char *)(&(x)), 0)
99
1.22k
#define GPSD_LED64(x) getled64((const char *)(&(x)), 0)
100
101
#define USE_RMD 0
102
103
// Used in Serial Physical Layer
104
3.01k
#define ETX 0x03
105
4.09k
#define ACK 0x06
106
9.05k
#define DLE 0x10
107
1.75k
#define NAK 0x15
108
109
#define GARMIN_LAYERID_TRANSPORT (uint8_t)  0
110
98
#define GARMIN_LAYERID_APPL      (uint32_t) 20
111
// Linux Garmin USB driver layer-id to use for some control mechanisms
112
#define GARMIN_LAYERID_PRIVATE  0x01106E4B
113
114
// packet ids used in private layer
115
#define PRIV_PKTID_SET_DEBUG    1
116
#define PRIV_PKTID_SET_MODE     2
117
#define PRIV_PKTID_INFO_REQ     3
118
#define PRIV_PKTID_INFO_RESP    4
119
#define PRIV_PKTID_RESET_REQ    5
120
#define PRIV_PKTID_SET_DEF_MODE 6
121
122
#define MODE_NATIVE       0
123
#define MODE_GARMIN_SERIAL   1
124
125
#define GARMIN_PKTID_TRANSPORT_START_SESSION_REQ 5
126
#define GARMIN_PKTID_TRANSPORT_START_SESSION_RESP 6
127
128
266
#define GARMIN_PKTID_PROTOCOL_ARRAY     253
129
169
#define GARMIN_PKTID_PRODUCT_RQST       254
130
166
#define GARMIN_PKTID_PRODUCT_DATA       255
131
// 0x29 ')'
132
422
#define GARMIN_PKTID_RMD41_DATA  41
133
// 0x33 '3'
134
499
#define GARMIN_PKTID_PVT_DATA      51
135
// 0x33 '4'
136
313
#define GARMIN_PKTID_RMD_DATA      52
137
// 0x72 'r'
138
492
#define GARMIN_PKTID_SAT_DATA      114
139
140
#define GARMIN_PKTID_L001_XFER_CMPLT     12
141
98
#define GARMIN_PKTID_L001_COMMAND_DATA   10
142
#define GARMIN_PKTID_L001_DATE_TIME_DATA 14
143
#define GARMIN_PKTID_L001_RECORDS       27
144
#define GARMIN_PKTID_L001_WPT_DATA       35
145
146
0
#define CMND_ABORT                       0
147
98
#define CMND_START_PVT_DATA              49
148
0
#define CMND_STOP_PVT_DATA               50
149
0
#define CMND_START_RM_DATA               110
150
151
#define MAX_BUFFER_SIZE 4096
152
153
11.8k
#define GARMIN_CHANNELS 12
154
155
// something magic about 64, garmin driver will not return more than
156
// 64 at a time.  If you read less than 64 bytes the next read will
157
// just get the last of the 64 byte buffer.
158
#define ASYNC_DATA_SIZE 64
159
160
161
#pragma pack(1)
162
// This is the data format of the satellite data from the garmin USB
163
typedef struct __attribute__((__packed__))
164
{
165
    uint8_t svid;
166
    uint16_t snr;               // 0 - 0xffff
167
    uint8_t elev;
168
    uint16_t azmth;
169
    uint8_t status;             // bit 0, has ephemeris, 1, has diff correction
170
    // bit 2 used in solution
171
    // bit 3??
172
} cpo_sat_data;
173
174
/* Garmin D800_Pvt_Datetype_Type
175
 * packet type:  GARMIN_PKTID_PVT_DATA   51
176
 * This is the data format of the position data from the garmin USB */
177
typedef struct __attribute__((__packed__))
178
{
179
    float alt;                  // altitude above WGS 84 (meters)
180
    float epe;                  // estimated position error, 2 sigma (meters)
181
    float eph;                  // epe, but horizontal only (meters)
182
    float epv;                  // epe but vertical only (meters )
183
    int16_t fix;                /* 0 - failed integrity check
184
                                 * 1 - invalid or unavailable fix
185
                                 * 2 - 2D
186
                                 * 3 - 3D
187
                                 * 4 - 2D Diff
188
                                 * 5 - 3D Diff
189
                                 */
190
    double gps_tow;             // gps time of week (seconds)
191
    double lat;                 // ->latitude (radians)
192
    double lon;                 // ->longitude (radians)
193
    float lon_vel;              // velocity east (meters/second)
194
    float lat_vel;              // velocity north (meters/second)
195
    float alt_vel;              // velocity up (meters/sec)
196
    // Garmin GPS25 uses pkt_id 0x28 and does not output the
197
    // next 3 items
198
    float msl_hght;             // height of WGS 84 above MSL (meters)
199
    int16_t leap_sec;           // diff between GPS and UTC (seconds)
200
    int32_t grmn_days;          /* days from UTC December 31st, 1989 to the
201
                                 * beginning of the current week */
202
} cpo_pvt_data;
203
204
typedef struct __attribute__((__packed__))
205
{
206
    uint32_t cycles;
207
    double pr;                  // pseudorange in meters
208
    uint16_t phase;
209
    int8_t slp_dtct;
210
    uint8_t snr_dbhz;
211
    uint8_t svid;
212
    int8_t valid;
213
} cpo_rcv_sv_data;
214
215
/* packet type:  GARMIN_PKTID_RMD_DATA   53
216
 * seems identical to the packet id 0x29 from the Garmin GPS 25 */
217
typedef struct __attribute__((__packed__))
218
{
219
    double rcvr_tow;
220
    int16_t rcvr_wn;
221
    cpo_rcv_sv_data sv[GARMIN_CHANNELS];
222
} cpo_rcv_data;
223
224
// This is the packet format to/from the Garmin USB
225
typedef struct __attribute__((__packed__))
226
{
227
    uint8_t mPacketType;
228
    uint8_t mReserved1;
229
    uint16_t mReserved2;
230
    uint16_t mPacketId;
231
    uint16_t mReserved3;
232
    uint32_t mDataSize;
233
    union
234
    {
235
        //int8_t chars[MAX_BUFFER_SIZE];
236
        // cppcheck-suppress unusedStructMember
237
        uint8_t uchars[MAX_BUFFER_SIZE];
238
        cpo_pvt_data pvt;
239
        cpo_sat_data sats;
240
    } mData;
241
} Packet_t;
242
243
// useful funcs to read/write ints
244
//  floats and doubles are Intel (little-endian) order only...
245
// FIXME:  use include/bits.h instead
246
static inline void set_int16(uint8_t * buf, uint32_t value)
247
49
{
248
49
    buf[0] = (uint8_t) (0x0FF & value);
249
49
    buf[1] = (uint8_t) (0x0FF & (value >> 8));
250
49
}
251
252
static inline void set_int32(uint8_t * buf, uint32_t value)
253
0
{
254
0
    buf[0] = (uint8_t)(0x0FF & value);
255
0
    buf[1] = (uint8_t)(0x0FF & (value >> 8));
256
0
    buf[2] = (uint8_t)(0x0FF & (value >> 16));
257
0
    buf[3] = (uint8_t)(0x0FF & (value >> 24));
258
0
}
259
260
static inline uint16_t get_uint16(const uint8_t * buf)
261
219
{
262
219
    return (uint16_t)(0xFF & buf[0]) |
263
219
           ((uint16_t)(0xFF & buf[1]) << 8);
264
219
}
265
266
#if defined(HAVE_LIBUSB) && defined(__linux__)
267
static inline uint32_t get_int32(const uint8_t * buf)
268
{
269
    return (uint32_t)(0xFF & buf[0]) |
270
           ((uint32_t)(0xFF & buf[1]) << 8) |
271
           ((uint32_t)(0xFF & buf[2]) << 16) |
272
           ((uint32_t)(0xFF & buf[3]) << 24);
273
}
274
#endif  // HAVE_LIBUSB
275
276
// convert radians to degrees
277
static inline double radtodeg(double rad)
278
816
{
279
816
    return (double)(rad * RAD_2_DEG);
280
816
}
281
282
static gps_mask_t PrintSERPacket(struct gps_device_t *session,
283
                                 unsigned char pkt_id, int pkt_len,
284
                                 unsigned char *buf);
285
#if defined(HAVE_LIBUSB) && defined(__linux__)
286
static gps_mask_t PrintUSBPacket(struct gps_device_t *session,
287
                                 Packet_t * pkt);
288
#endif  // HAVE_LIBUSB
289
290
gps_mask_t PrintSERPacket(struct gps_device_t *session, unsigned char pkt_id,
291
                          int pkt_len, unsigned char *buf)
292
5.06k
{
293
294
5.06k
    gps_mask_t mask = ONLINE_SET;
295
5.06k
    int i = 0, j = 0;
296
5.06k
    uint16_t prod_id = 0;
297
5.06k
    uint16_t ver = 0;
298
5.06k
    int maj_ver;
299
5.06k
    int min_ver;
300
5.06k
    time_t time_l = 0;
301
5.06k
    char msg_buf[512] = "";
302
5.06k
    char *msg = NULL;
303
5.06k
    cpo_sat_data *sats = NULL;
304
5.06k
    cpo_pvt_data *pvt = NULL;
305
5.06k
    cpo_rcv_data *rmd = NULL;
306
5.06k
    double gps_tow = 0;
307
308
5.06k
    GPSD_LOG(LOG_DATA, &session->context->errout,
309
5.06k
             "Garmin: PrintSERPacket(, %#02x, %#02x, )\n", pkt_id, pkt_len);
310
311
5.06k
    session->cycle_end_reliable = true;
312
313
5.06k
    switch (pkt_id) {
314
2.04k
    case ACK:
315
2.04k
        GPSD_LOG(LOG_PROG, &session->context->errout, "Garmin: ACK\n");
316
2.04k
        break;
317
875
    case NAK:
318
875
        GPSD_LOG(LOG_PROG, &session->context->errout, "Garmin: NAK\n");
319
875
        break;
320
49
    case GARMIN_PKTID_L001_COMMAND_DATA:
321
        // A010
322
49
        if (2 > pkt_len) {
323
0
            GPSD_LOG(LOG_WARN, &session->context->errout,
324
0
                     "Garmin: %02x-: runt payload %d",
325
0
                     pkt_id, pkt_len);
326
0
            return 0;
327
0
        }
328
49
        prod_id = get_uint16((uint8_t *) buf);
329
49
        switch (prod_id) {
330
0
        case CMND_ABORT:
331
0
            msg = "Abort current xfer";
332
0
            break;
333
49
        case CMND_START_PVT_DATA:
334
49
            msg = "Start Xmit PVT data";
335
49
            break;
336
0
        case CMND_STOP_PVT_DATA:
337
0
            msg = "Stop Xmit PVT data";
338
0
            break;
339
0
        case CMND_START_RM_DATA:
340
0
            msg = "Start RMD data";
341
0
            break;
342
0
        default:
343
0
            (void)snprintf(msg_buf, sizeof(msg_buf), "Unknown: %u",
344
0
                           (unsigned int)prod_id);
345
0
            msg = msg_buf;
346
0
            break;
347
49
        }
348
49
        GPSD_LOG(LOG_PROG, &session->context->errout,
349
49
                 "Garmin: Appl, Command Data: %s\n", msg);
350
49
        break;
351
120
    case GARMIN_PKTID_PRODUCT_RQST:
352
120
        GPSD_LOG(LOG_PROG, &session->context->errout,
353
120
                 "Garmin: Appl, Product Data req\n");
354
120
        break;
355
166
    case GARMIN_PKTID_PRODUCT_DATA:
356
166
        if (4 > pkt_len) {
357
81
            GPSD_LOG(LOG_WARN, &session->context->errout,
358
81
                     "Garmin: %02x-: runt payload %d",
359
81
                     pkt_id, pkt_len);
360
81
            return 0;
361
81
        }
362
85
        prod_id = get_uint16((uint8_t *) buf);
363
85
        ver = get_uint16((uint8_t *) & buf[2]);
364
85
        maj_ver = (int)(ver / 100);
365
85
        min_ver = (int)(ver - (maj_ver * 100));
366
85
        GPSD_LOG(LOG_PROG, &session->context->errout,
367
85
                 "Garmin: Appl, Product Data, sz: %d\n",
368
85
                 pkt_len);
369
85
        (void)snprintf(session->subtype, sizeof(session->subtype),
370
85
                       "%d: %d.%02d", (int)prod_id, maj_ver, min_ver);
371
85
        GPSD_LOG(LOG_INF, &session->context->errout,
372
85
                 "Garmin: Product ID: %d, SoftVer: %d.%02d\n",
373
85
                 prod_id, maj_ver, min_ver);
374
85
        GPSD_LOG(LOG_INF, &session->context->errout,
375
85
                 "Garmin: Product Desc: %s\n", &buf[4]);
376
85
        mask |= DEVICEID_SET;
377
85
        GPSD_LOG(LOG_DATA, &session->context->errout,
378
85
                 "Garmin: PRODUCT_DATA: subtype=%s\n",
379
85
                 session->subtype);
380
85
        break;
381
499
    case GARMIN_PKTID_PVT_DATA:
382
        // 0x33 (51)
383
499
        if (64 > pkt_len) {
384
91
            GPSD_LOG(LOG_WARN, &session->context->errout,
385
91
                     "Garmin: %02x-: runt payload %d",
386
91
                     pkt_id, pkt_len);
387
91
            return 0;
388
91
        }
389
408
        GPSD_LOG(LOG_PROG, &session->context->errout,
390
408
                 "Garmin: PVT Data (51) Sz: %d\n", pkt_len);
391
392
408
        pvt = (cpo_pvt_data *) buf;
393
394
408
        session->context->leap_seconds = (int)GPSD_LE16TOH(pvt->leap_sec);
395
408
        session->context->valid = LEAP_SECOND_VALID;
396
397
        // 631065600, unix seconds for 31 Dec 1989 Zulu
398
408
        time_l = (time_t) (631065600 + (GPSD_LE32TOH(pvt->grmn_days) * 86400));
399
        // TODO, convert grmn_days to context->gps_week
400
408
        time_l -= session->context->leap_seconds;
401
402
        // gps_tow is always like x.999 or x.998 just round it to nearest sec
403
        // FIXME! this will break 5Hz garmins...
404
408
        gps_tow = GPSD_LED64(pvt->gps_tow);
405
408
        time_l += (time_t)round(gps_tow);
406
407
        /* sanity check unix time against leap second.
408
         * Leap second 18 at 1 Jan 2017: 1483228800 */
409
408
        if (17 < session->context->leap_seconds &&
410
299
            1483228800L > time_l) {
411
200
            time_l += 619315200;               // fast forward 1024 weeks
412
200
        }
413
414
408
        DTOTS(&session->context->gps_tow, gps_tow);
415
408
        session->newdata.time.tv_sec = time_l;
416
408
        session->newdata.time.tv_nsec = 0;
417
        // (long long) for 32-bit systems
418
408
        GPSD_LOG(LOG_PROG, &session->context->errout,
419
408
                 "Garmin: time_l: %lld\n", (long long)time_l);
420
421
408
        session->newdata.latitude = radtodeg(GPSD_LED64(pvt->lat));
422
408
        session->newdata.longitude = radtodeg(GPSD_LED64(pvt->lon));
423
        // altitude is WGS84
424
408
        session->newdata.altHAE = GPSD_LEF32(pvt->alt);
425
426
        // geoid separation from WGS 84
427
        // gpsd sign is opposite of garmin sign
428
408
        session->newdata.geoid_sep = -GPSD_LEF32(pvt->msl_hght);
429
430
        /* Estimated position error in meters.  Confidence (sigma) not
431
         * specified by Garmin.
432
         * We follow the advice at <http://gpsinformation.net/main/errors.htm>.
433
         * Since GPS data is not gaussian, this is marginal advice...
434
         * If this assumption changes here, it should also change in
435
         * nmea_parse.c where we analyze PGRME.
436
         */
437
408
        session->newdata.sep = GPSD_LEF32(pvt->epe) *
438
408
                                   (GPSD_CONFIDENCE / CEP50_SIGMA);
439
        // eph, horizaontal error, 2 sigma
440
408
        session->newdata.eph = GPSD_LEF32(pvt->eph) *
441
408
                                   (GPSD_CONFIDENCE / CEP50_SIGMA);
442
        // eph, horizaontal error, 2 sigma
443
408
        session->newdata.epv = GPSD_LEF32(pvt->epv) *
444
408
                                   (GPSD_CONFIDENCE / CEP50_SIGMA);
445
446
        // meters/sec
447
408
        session->newdata.NED.velN = GPSD_LEF32(pvt->lat_vel);
448
408
        session->newdata.NED.velE = GPSD_LEF32(pvt->lon_vel);
449
408
        session->newdata.NED.velD = -GPSD_LEF32(pvt->alt_vel);
450
451
408
        switch (GPSD_LE16TOH(pvt->fix)) {
452
52
        case 0:
453
52
        case 1:
454
90
        default:
455
            // no fix
456
90
            session->newdata.status = STATUS_UNK;
457
90
            session->newdata.mode = MODE_NO_FIX;
458
90
            break;
459
67
        case 2:
460
            // 2D fix
461
67
            session->newdata.status = STATUS_GPS;
462
67
            session->newdata.mode = MODE_2D;
463
67
            break;
464
1
        case 3:
465
            // 3D fix
466
1
            session->newdata.status = STATUS_GPS;
467
1
            session->newdata.mode = MODE_3D;
468
1
            break;
469
209
        case 4:
470
            // 2D Differential fix
471
209
            session->newdata.status = STATUS_DGPS;
472
209
            session->newdata.mode = MODE_2D;
473
209
            break;
474
41
        case 5:
475
            // 3D differential fix
476
41
            session->newdata.status = STATUS_DGPS;
477
41
            session->newdata.mode = MODE_3D;
478
41
            break;
479
408
        }
480
481
408
        GPSD_LOG(LOG_PROG, &session->context->errout,
482
408
                 "Garmin: Appl, mode %d, status %d\n",
483
408
                 session->newdata.mode, session->newdata.status);
484
485
        // save some expensive calculations if not needed
486
408
        if (session->context->errout.debug >= LOG_INF) {
487
488
0
            GPSD_LOG(LOG_INF, &session->context->errout,
489
0
                     "Garmin: UTC Time: %lld\n",
490
0
                     (long long)session->newdata.time.tv_sec);
491
0
            GPSD_LOG(LOG_INF, &session->context->errout,
492
0
                     "Garmin: Geoid Separation (MSL-WGS84): from garmin %lf, "
493
0
                     "calculated %lf\n",
494
0
                     session->newdata.geoid_sep,
495
0
                     wgs84_separation(session->newdata.latitude,
496
0
                                         session->newdata.longitude));
497
498
0
            GPSD_LOG(LOG_INF, &session->context->errout,
499
0
                     "Garmin: Alt: %.3f, sep: %.3f, eph: %.3f, Epv: %.3f, "
500
0
                     "Fix: %d, Gps_tow: %f, Lat: %.3f, Lon: %.3f, "
501
0
                     "velN: %.3f, velE: %.3f, velD: %.3f, geoidsep: %.3f, "
502
0
                     "Leap: %d, GarminDays: %ld\n",
503
0
                     session->newdata.altHAE,
504
0
                     session->newdata.sep,
505
0
                     session->newdata.eph,
506
0
                     session->newdata.epv,
507
0
                     GPSD_LE16TOH(pvt->fix),
508
0
                     gps_tow,
509
0
                     session->newdata.latitude,
510
0
                     session->newdata.longitude,
511
0
                     session->newdata.NED.velN,
512
0
                     session->newdata.NED.velE,
513
0
                     session->newdata.NED.velD,
514
0
                     session->newdata.geoid_sep,
515
0
                     session->context->leap_seconds,
516
0
                     GPSD_LE32TOH(pvt->grmn_days));
517
0
        }
518
519
408
        if (session->newdata.mode > MODE_NO_FIX) {
520
            // data only valid with a fix
521
318
            mask |=
522
318
                TIME_SET | LATLON_SET | ALTITUDE_SET | STATUS_SET | MODE_SET |
523
318
                HERR_SET | PERR_IS | CLEAR_IS | REPORT_IS | VNED_SET;
524
            /*
525
             * Garmin documentation says we should wait until four good fixes
526
             * have been seen before trying to use the device for precision
527
             * time service.
528
             */
529
318
            if (session->fixcnt > 3)
530
208
                mask |= NTPTIME_IS;
531
318
        }
532
408
        GPSD_LOG(LOG_DATA, &session->context->errout,
533
408
                 "Garmin: PVT_DATA: time=%lld, lat=%.2f lon=%.2f "
534
408
                 "eph=%.2f sep=%.2f epv=%.2f  mode=%d status=%d\n",
535
408
                 (long long)session->newdata.time.tv_sec,
536
408
                 session->newdata.latitude,
537
408
                 session->newdata.longitude,
538
408
                 session->newdata.eph,
539
408
                 session->newdata.sep,
540
408
                 session->newdata.epv,
541
408
                 session->newdata.mode,
542
408
                 session->newdata.status);
543
408
        break;
544
313
    case GARMIN_PKTID_RMD_DATA:
545
313
        FALLTHROUGH
546
422
    case GARMIN_PKTID_RMD41_DATA:
547
422
        rmd = (cpo_rcv_data *) buf;
548
422
        GPSD_LOG(LOG_DATA, &session->context->errout,
549
422
                 "Garmin: PVT RMD Data Sz: %d\n", pkt_len);
550
422
        GPSD_LOG(LOG_PROG, &session->context->errout,
551
422
                 "Garmin: PVT RMD rcvr_tow: %f, rcvr_wn: %d\n",
552
422
                 GPSD_LED64(rmd->rcvr_tow), GPSD_LE16TOH(rmd->rcvr_wn));
553
5.48k
        for (i = 0; i < GARMIN_CHANNELS; i++) {
554
5.06k
            GPSD_LOG(LOG_INF, &session->context->errout,
555
5.06k
                     "Garmin: PVT RMD Sat: %3u, cycles: %9lu, pr: %16.6f, "
556
5.06k
                     "phase: %7.3f, slp_dtct: %3s, snr: %3u, Valid: %3s\n",
557
5.06k
                     (int)rmd->sv[i].svid + 1,
558
5.06k
                     GPSD_LE32TOH(rmd->sv[i].cycles),
559
5.06k
                     GPSD_LED64(rmd->sv[i].pr),
560
5.06k
                     (GPSD_LE16TOH(rmd->sv[i].phase) * 360.0) / 2048.0,
561
5.06k
                     rmd->sv[i].slp_dtct != 0 ? "Yes" : "No",
562
5.06k
                     rmd->sv[i].snr_dbhz,
563
5.06k
                     rmd->sv[i].valid != 0 ? "Yes" : "No");
564
5.06k
        }
565
422
        break;
566
567
492
    case GARMIN_PKTID_SAT_DATA:
568
        // record ID 0x72 (114)
569
492
        GPSD_LOG(LOG_PROG, &session->context->errout,
570
492
                 "Garmin: SAT Data Sz: %d\n", pkt_len);
571
492
        sats = (cpo_sat_data *) buf;
572
573
492
        session->gpsdata.satellites_used = 0;
574
492
        gpsd_zero_satellites(&session->gpsdata);
575
6.39k
        for (i = 0, j = 0; i < GARMIN_CHANNELS; i++, sats++) {
576
5.90k
            GPSD_LOG(LOG_INF, &session->context->errout,
577
5.90k
                     "Garmin: Sat %2d, snr: %5u, elev: %2d, Azmth: %3d, "
578
5.90k
                     "Stat: x%x\n",
579
5.90k
                     sats->svid, GPSD_LE16TOH(sats->snr), sats->elev,
580
5.90k
                     GPSD_LE16TOH(sats->azmth),
581
5.90k
                     sats->status);
582
583
5.90k
            if (255 == (int)sats->svid) {
584
                // Garmin uses 255 for empty
585
                // gpsd uses 0 for empty
586
68
                continue;
587
68
            }
588
589
5.83k
            if ((int)sats->svid <= 32) {
590
                // GPS 1-32
591
3.86k
                session->gpsdata.skyview[j].PRN = (short)sats->svid;
592
3.86k
                session->gpsdata.skyview[j].svid = (short)sats->svid;
593
3.86k
                session->gpsdata.skyview[j].gnssid = GNSSID_GPS;
594
3.86k
            } else {
595
                // SBAS 33-64
596
1.97k
                session->gpsdata.skyview[j].PRN = (short)sats->svid;
597
1.97k
                session->gpsdata.skyview[j].svid = (short)sats->svid + 87;
598
1.97k
                session->gpsdata.skyview[j].gnssid = GNSSID_SBAS;
599
1.97k
            }
600
5.83k
            session->gpsdata.skyview[j].azimuth =
601
5.83k
                (short)GPSD_LE16TOH(sats->azmth);
602
5.83k
            session->gpsdata.skyview[j].elevation = (short)sats->elev;
603
5.83k
            if (0xffff == sats->snr) {
604
84
                session->gpsdata.skyview[j].ss = NAN;
605
5.75k
            } else {
606
                // Garmin does not document this.  snr is in dB*100
607
                // Known, but not seen satellites have a dB value of -1*100
608
5.75k
                session->gpsdata.skyview[j].ss =
609
5.75k
                    (float)(GPSD_LE16TOH(sats->snr) / 100.0);
610
5.75k
            }
611
            // FIX-ME: Garmin documents this, but Daniel Dorau
612
            // <daniel.dorau@gmx.de> says the behavior on his GPSMap60CSX
613
            // doesn't match it.
614
5.83k
            if ((uint8_t) 0 != (sats->status & 4)) {
615
                // used in solution?
616
968
                session->gpsdata.skyview[j].used = true;
617
968
                session->gpsdata.satellites_used++;
618
968
            }
619
5.83k
            session->gpsdata.satellites_visible++;
620
5.83k
            j++;
621
622
5.83k
        }
623
492
        session->gpsdata.skyview_time.tv_sec = 0;
624
492
        session->gpsdata.skyview_time.tv_nsec = 0;
625
492
        mask |= USED_IS | SATELLITE_SET;
626
492
        GPSD_LOG(LOG_DATA, &session->context->errout,
627
492
                 "Garmin: SAT_DATA: visible=%d used=%d\n",
628
492
                 session->gpsdata.satellites_visible,
629
492
                 session->gpsdata.satellites_used);
630
492
        break;
631
266
    case GARMIN_PKTID_PROTOCOL_ARRAY:
632
        // Pid_Protocol_Array, ID 253
633
        // this packet is never requested, it just comes, in some case
634
        // after a GARMIN_PKTID_PRODUCT_RQST
635
266
        GPSD_LOG(LOG_INF, &session->context->errout,
636
266
                 "Garmin: Appl, Product Capability, sz: %d\n",
637
266
                 pkt_len);
638
718
        for (i = 0; i < pkt_len; i += 3) {
639
452
            GPSD_LOG(LOG_INF, &session->context->errout,
640
452
                     "Garmin:   %c%03d\n",
641
452
                     buf[i],    get_uint16((uint8_t *) & buf[i + 1]));
642
452
        }
643
266
        break;
644
129
    default:
645
129
        GPSD_LOG(LOG_WARN, &session->context->errout,
646
129
                 "Garmin: Unknown packet id: %#02x, Sz: %#02x\n",
647
129
                 pkt_id, pkt_len);
648
129
        break;
649
5.06k
    }
650
4.89k
    GPSD_LOG(LOG_DATA, &session->context->errout,
651
4.89k
             "Garmin: PrintSERPacket(, %#02x, %#02x, ) mask=(%s)\n",
652
4.89k
             pkt_id, pkt_len, gps_maskdump(mask));
653
4.89k
    return mask;
654
5.06k
}
655
656
657
#if defined(HAVE_LIBUSB) && defined(__linux__)
658
// For debugging, decodes and prints some known packets
659
static gps_mask_t PrintUSBPacket(struct gps_device_t *session, Packet_t * pkt)
660
{
661
    gps_mask_t mask = 0;
662
    int maj_ver;
663
    int min_ver;
664
    uint32_t mode = 0;
665
    uint16_t prod_id = 0;
666
    uint32_t veri = 0;
667
    uint32_t serial;
668
    uint32_t mDataSize = get_int32((uint8_t *) & pkt->mDataSize);
669
    uint8_t *buffer = (uint8_t *) pkt;
670
671
    GPSD_LOG(LOG_PROG, &session->context->errout, "Garmin: PrintUSBPacket()\n");
672
    if (DLE == pkt->mPacketType) {
673
        GPSD_LOG(LOG_PROG, &session->context->errout,
674
                 "Garmin: really a SER packet!\n");
675
        return PrintSERPacket(session,
676
                              (unsigned char)buffer[1],
677
                              (int)buffer[2], (unsigned char *)(buffer + 3));
678
    }
679
680
    if (4096 < mDataSize) {
681
        GPSD_LOG(LOG_WARN, &session->context->errout,
682
                 "Garmin: bogus packet, size too large=%d\n",
683
                 mDataSize);
684
        return 0;
685
    }
686
687
    switch (pkt->mPacketType) {
688
    case GARMIN_LAYERID_TRANSPORT:
689
        // Garmin USB layer specific
690
        switch (pkt->mPacketId) {
691
        case GARMIN_PKTID_TRANSPORT_START_SESSION_REQ:
692
            // Pid_Start_Session, ID 5
693
            GPSD_LOG(LOG_PROG, &session->context->errout,
694
                     "Garmin: Transport, Start Session req\n");
695
            break;
696
        case GARMIN_PKTID_TRANSPORT_START_SESSION_RESP:
697
            // Pid_Session_Started, ID 6
698
            mode = get_int32(&pkt->mData.uchars[0]);
699
            GPSD_LOG(LOG_PROG, &session->context->errout,
700
                     "Garmin: Transport, Start Session resp, unit: 0x%x\n",
701
                     mode);
702
            break;
703
        default:
704
            GPSD_LOG(LOG_PROG, &session->context->errout,
705
                     "Garmin: Transport, Packet: Type %d %d %d, ID: %d,"
706
                     "Sz: %d\n",
707
                     pkt->mPacketType, pkt->mReserved1, pkt->mReserved2,
708
                     pkt->mPacketId, mDataSize);
709
            break;
710
        }
711
        break;
712
    case GARMIN_LAYERID_APPL:
713
        // raw data transport, shared with Garmin Serial Driver
714
715
        mask = PrintSERPacket(session,
716
                              (unsigned char)pkt->mPacketId,
717
                              (int)mDataSize,
718
                              (unsigned char *)pkt->mData.uchars);
719
        break;
720
    case 75:
721
        // private, garmin USB kernel driver specific
722
        switch (pkt->mPacketId) {
723
        case PRIV_PKTID_SET_MODE:
724
            prod_id = get_uint16(&pkt->mData.uchars[0]);
725
            GPSD_LOG(LOG_PROG, &session->context->errout,
726
                     "Garmin: Private, Set Mode: %d\n", prod_id);
727
            break;
728
        case PRIV_PKTID_INFO_REQ:
729
            GPSD_LOG(LOG_PROG, &session->context->errout,
730
                     "Garmin: Private, ID: Info Req\n");
731
            break;
732
        case PRIV_PKTID_INFO_RESP:
733
            veri = get_int32(pkt->mData.uchars);
734
            maj_ver = (int)(veri >> 16);
735
            min_ver = (int)(veri & 0xffff);
736
            mode = get_int32(&pkt->mData.uchars[4]);
737
            serial = get_int32(&pkt->mData.uchars[8]);
738
            GPSD_LOG(LOG_PROG, &session->context->errout,
739
                     "Garmin: Private, ID: Info Resp\n");
740
            GPSD_LOG(LOG_INF, &session->context->errout,
741
                     "Garmin: USB Driver Version %d.%d Mode %d, Serial# %u\n",
742
                     maj_ver, min_ver, mode, serial);
743
            break;
744
        default:
745
            GPSD_LOG(LOG_PROG, &session->context->errout,
746
                     "Garmin: Private, Packet: ID: %d, Sz: %d\n",
747
                     pkt->mPacketId, mDataSize);
748
            break;
749
        }
750
        break;
751
    default:
752
        GPSD_LOG(LOG_PROG, &session->context->errout,
753
                 "Garmin: Packet: Type %d %d %d, ID: %d, Sz: %d\n",
754
                 pkt->mPacketType, pkt->mReserved1, pkt->mReserved2,
755
                 pkt->mPacketId, mDataSize);
756
        break;
757
    }
758
759
    return mask;
760
}
761
762
#endif  // HAVE_LIBUSB
763
764
765
#if defined(HAVE_LIBUSB) && defined(__linux__)
766
// build and send a packet w/ USB protocol
767
static void Build_Send_USB_Packet(struct gps_device_t *session,
768
                                  uint32_t layer_id, uint32_t pkt_id,
769
                                  uint32_t length, uint32_t data)
770
{
771
    uint8_t *buffer = (uint8_t *) session->driver.garmin.Buffer;
772
    Packet_t *thePacket = (Packet_t *) buffer;
773
    ssize_t theBytesReturned = 0;
774
    ssize_t theBytesToWrite = 12 + (ssize_t) length;
775
776
    set_int32(buffer, layer_id);
777
    set_int32(buffer + 4, pkt_id);
778
    set_int32(buffer + 8, length);
779
    if (2 == length) {
780
        set_int16(buffer + 12, data);
781
    } else if (4 == length) {
782
        set_int32(buffer + 12, data);
783
    }
784
    (void)PrintUSBPacket(session, thePacket);
785
786
    theBytesReturned = gpsd_write(session, (const char *)thePacket,
787
                                  (size_t) theBytesToWrite);
788
    GPSD_LOG(LOG_PROG, &session->context->errout,
789
             "Garmin: SendPacket(), wrote %zd bytes\n",
790
             theBytesReturned);
791
792
    // Garmin says:
793
    // If the packet size was an exact multiple of the USB packet
794
    // size, we must make a final write call with no data
795
796
    // as a practical matter no known packets are 64 bytes long so
797
    // this is untested
798
799
    // So here goes just in case
800
    if (0 == (theBytesToWrite % ASYNC_DATA_SIZE)) {
801
        char *n = "";
802
        (void)gpsd_write(session, n, 0);
803
    }
804
}
805
#endif  // HAVE_LIBUSB && __linux__
806
807
/* build and send a packet in serial protocol
808
 * layer_id unused */
809
// FIX-ME: This should go through the common message buffer someday
810
static void Build_Send_SER_Packet(struct gps_device_t *session,
811
                                  uint32_t layer_id UNUSED, uint32_t pkt_id,
812
                                  uint32_t length, uint32_t data)
813
3.01k
{
814
3.01k
    uint8_t *buffer = (uint8_t *) session->driver.garmin.Buffer;
815
3.01k
    uint8_t *buffer0 = buffer;
816
3.01k
    Packet_t *thePacket = (Packet_t *) buffer;
817
3.01k
    ssize_t theBytesReturned = 0;
818
3.01k
    ssize_t theBytesToWrite = 6 + (ssize_t) length;
819
3.01k
    uint8_t chksum = 0;
820
821
3.01k
    *buffer++ = (uint8_t) DLE;
822
3.01k
    *buffer++ = (uint8_t) pkt_id;
823
3.01k
    chksum = pkt_id;
824
3.01k
    *buffer++ = (uint8_t) length;
825
3.01k
    chksum += length;
826
    // ??? What is this doing?
827
3.01k
    if (2 == length) {
828
        // careful!  no DLE stuffing here!
829
49
        set_int16(buffer, data);
830
49
        chksum += buffer[0];
831
49
        chksum += buffer[1];
832
2.96k
    } else if (4 == length) {
833
        // careful!  no DLE stuffing here!
834
0
        set_int32(buffer, data);
835
0
        chksum += buffer[0];
836
0
        chksum += buffer[1];
837
0
        chksum += buffer[2];
838
0
        chksum += buffer[3];
839
0
    }
840
    // ??? How is data copied to the buffer?
841
3.01k
    buffer += length;
842
843
    // Add checksum
844
3.01k
    *buffer++ = -chksum;
845
3.01k
    if (DLE == -chksum) {
846
        // stuff another DLE
847
0
        *buffer++ = (uint8_t) DLE;
848
0
        theBytesToWrite++;
849
0
    }
850
    // Add DLE, ETX
851
3.01k
    *buffer++ = (uint8_t) DLE;
852
    // we used to say n++ here, but scan-build complains
853
3.01k
    *buffer = (uint8_t) ETX;
854
855
3.01k
    (void)PrintSERPacket(session,
856
3.01k
                         (unsigned char)buffer0[1],
857
3.01k
                         (int)buffer0[2], (unsigned char *)(buffer0 + 3));
858
859
3.01k
    theBytesReturned = gpsd_write(session, (const char *)thePacket,
860
3.01k
                                  (size_t) theBytesToWrite);
861
3.01k
    GPSD_LOG(LOG_PROG, &session->context->errout,
862
3.01k
             "Garmin: SendPacket(), wrote %zd bytes\n",
863
3.01k
             theBytesReturned);
864
865
3.01k
}
866
867
#if defined(HAVE_LIBUSB) && defined(__linux__)
868
/*
869
 * is_usb_device() - is a specified device USB matching given vendor/product?
870
 *
871
 * BUG: Doesn't actually match against path yet. Must finish this function
872
 * by querying /sys/dev/char, either directly or using libudev. Greg KH
873
 * assures this is possible, though he is vague about how.
874
 *
875
 * libudev: http://www.kernel.org/pub/linux/utils/kernel/hotplug/libudev/
876
 */
877
static bool is_usb_device(const char *path UNUSED, int vendor, int product,
878
                          struct gpsd_errout_t *errout)
879
{
880
    // discover devices
881
    libusb_device **list;
882
    ssize_t cnt;
883
    ssize_t i = 0;
884
    bool found = false;
885
886
    GPSD_LOG(LOG_INF, errout, "attempting USB device enumeration.\n");
887
    (void)libusb_init(NULL);
888
889
    if (0 > (cnt = libusb_get_device_list(NULL, &list))) {
890
        GPSD_LOG(LOG_ERROR, errout, "USB device list call failed.\n");
891
        libusb_exit(NULL);
892
        return false;
893
    }
894
895
    for (i = 0; i < cnt; i++) {
896
        struct libusb_device_descriptor desc;
897
        libusb_device *dev = list[i];
898
899
        int r = libusb_get_device_descriptor(dev, &desc);
900
        if (0 > r) {
901
            GPSD_LOG(LOG_ERROR, errout,
902
                     "USB descriptor fetch failed on device %zd.\n", i);
903
            continue;
904
        }
905
906
        // we can extract device descriptor data
907
        GPSD_LOG(LOG_INF, errout,
908
                 "%04x:%04x (bus %d, device %d)\n",
909
                 desc.idVendor, desc.idProduct,
910
                 libusb_get_bus_number(dev),
911
                 libusb_get_device_address(dev));
912
913
        // we match if vendor and product ID are right
914
        if (desc.idVendor == (uint16_t)vendor &&
915
            desc.idProduct == (uint16_t)product) {
916
            found = true;
917
            break;
918
        }
919
    }
920
921
    GPSD_LOG(LOG_INF, errout,
922
             "vendor/product match with %04x:%04x %sfound\n",
923
             vendor, product, found ? "" : "not ");
924
    libusb_free_device_list(list, 1);
925
    libusb_exit(NULL);
926
    return found;
927
}
928
929
#endif  // HAVE_LIBUSB
930
931
/*
932
 * garmin_usb_detect() - detect a Garmin USB device connected to session fd.
933
 *
934
 * This is ONLY for USB devices reporting as: 091e:0003.
935
 *
936
 * This driver ONLY works in Linux and ONLY when the garmin_gps kernel
937
 * module is installed.
938
 *
939
 * This is only necessary because under Linux Garmin USB devices need a
940
 * kernel module rather than being normal USB-serial devices.
941
 *
942
 * The actual wire protocol from the Garmin device is very strange. There
943
 * are no delimiters.  End of packet is signaled by a zero-length read
944
 * on the USB device, and start of packet is the next read.  You can't just
945
 * ignore the zero reads and pass the data through - you'd never be able
946
 * to tell where the packet boundaries are.
947
 *
948
 * The garmin_usb module's job is to grab the packet and frame it in
949
 * DLEs (with DLE stuffing).  This makes the USB packets look as
950
 * though they came from a regular Garmin *serial* device, which is how
951
 * most of the processing for both types can be unified here.
952
 *
953
 * return 1 is device found
954
 * return 0 if not
955
 */
956
static bool garmin_usb_detect(struct gps_device_t *session UNUSED)
957
0
{
958
0
#if defined(__linux__)
959
    /*
960
     * Only perform this check if we're looking at a USB-serial
961
     * device.  This prevents drivers for attached serial GPSes
962
     * from being rudely elbowed aside by this one if they happen
963
     * to be trying to coexist with the Garmin.
964
     */
965
0
    if (SOURCE_USB != session->sourcetype) {
966
0
        return false;
967
0
    }
968
969
#ifdef HAVE_LIBUSB
970
    if (!is_usb_device(session->gpsdata.dev.path, 0x091e, 0x0003,
971
            &session->context->errout)) {
972
        return false;
973
    }
974
975
    if (!gpsd_set_raw(session)) {
976
        GPSD_LOG(LOG_ERROR, &session->context->errout,
977
                 "Garmin: garmin_usb_detect: error changing port "
978
                 "attributes: %s\n",
979
                 strerror(errno));
980
        return false;
981
    }
982
983
    if (sizeof(session->driver.garmin.Buffer) < sizeof(Packet_t)) {
984
        // dunno how this happens, but it does on some compilers
985
        GPSD_LOG(LOG_ERROR, &session->context->errout,
986
                 "Garmin: garmin_usb_detect: Compile error, "
987
                 "garmin.Buffer too small.\n");
988
        return false;
989
    }
990
991
    // FIXME!!! needs to use libusb totally and move garmin_gps aside */
992
    // set Mode 1, mode 0 is broken somewhere past 2.6.14
993
    // but how?
994
    GPSD_LOG(LOG_PROG, &session->context->errout,
995
             "Garmin: Set garmin_gps driver mode = 0\n");
996
    Build_Send_USB_Packet(session, GARMIN_LAYERID_PRIVATE,
997
                          PRIV_PKTID_SET_MODE, 4, MODE_GARMIN_SERIAL);
998
    // expect no return packet !?
999
1000
    return true;
1001
#endif  // HAVE_LIBUSB
1002
0
#endif  // __linux__
1003
0
    return false;
1004
0
}
1005
1006
static void garmin_event_hook(struct gps_device_t *session, event_t event)
1007
4.53k
{
1008
4.53k
    if (session->context->readonly ||
1009
2.84k
        session->context->passive) {
1010
2.84k
        return;
1011
2.84k
    }
1012
    /*
1013
     * FIX-ME: It might not be necessary to call this on reactivate.
1014
     * Experiment to see if the holds its settings through a close.
1015
     */
1016
1.68k
    if (event == EVENT_IDENTIFIED ||
1017
1.64k
        event == EVENT_REACTIVATE) {
1018
        // Tell the device to send product data
1019
49
        GPSD_LOG(LOG_PROG, &session->context->errout,
1020
49
                 "Garmin: Get Product Data\n");
1021
49
        Build_Send_SER_Packet(session, GARMIN_LAYERID_APPL,
1022
49
                              GARMIN_PKTID_PRODUCT_RQST, 0, 0);
1023
1024
        // turn on PVT data 49
1025
49
        GPSD_LOG(LOG_PROG, &session->context->errout,
1026
49
                 "Garmin: Set to send reports every 1 second\n");
1027
1028
49
        Build_Send_SER_Packet(session, GARMIN_LAYERID_APPL,
1029
49
                              GARMIN_PKTID_L001_COMMAND_DATA, 2,
1030
49
                              CMND_START_PVT_DATA);
1031
1032
#if USE_RMD
1033
        // turn on RMD data 110
1034
        GPSD_LOG(LOG_PROG, &session->context->errout,
1035
                 "Garmin: Set to send Raw sat data\n");
1036
        Build_Send_SER_Packet(session, GARMIN_LAYERID_APPL,
1037
                              GARMIN_PKTID_L001_COMMAND_DATA, 2,
1038
                              CMND_START_RM_DATA);
1039
#endif
1040
49
    }
1041
1.68k
    if (event == EVENT_DEACTIVATE) {
1042
        // FIX-ME: is any action needed, or is closing the port sufficient?
1043
0
        GPSD_LOG(LOG_PROG, &session->context->errout,
1044
0
                 "Garmin: garmin_close()\n");
1045
0
    }
1046
1.68k
}
1047
1048
2.04k
#define Send_ACK()    Build_Send_SER_Packet(session, 0, ACK, 0, 0)
1049
875
#define Send_NAK()    Build_Send_SER_Packet(session, 0, NAK, 0, 0)
1050
1051
gps_mask_t garmin_ser_parse(struct gps_device_t *session)
1052
2.92k
{
1053
2.92k
    unsigned char *buf = session->lexer.outbuffer;
1054
2.92k
    size_t len = session->lexer.outbuflen;
1055
2.92k
    unsigned char data_buf[300];  // Max Garmin payload is 255
1056
2.92k
    unsigned char c;
1057
2.92k
    int i = 0;
1058
2.92k
    size_t n = 0;
1059
2.92k
    int data_index = 0;
1060
2.92k
    int got_dle = 0;
1061
2.92k
    unsigned char pkt_id = 0;
1062
2.92k
    unsigned char pkt_len = 0;
1063
2.92k
    unsigned char chksum = 0;
1064
2.92k
    gps_mask_t mask = 0;
1065
2.92k
    struct timespec delay;
1066
1067
2.92k
    GPSD_LOG(LOG_RAW, &session->context->errout,
1068
2.92k
             "Garmin: garmin_ser_parse()\n");
1069
2.92k
    if (6 > len) {
1070
        // WTF?
1071
        // minimum packet; <DLE> [pkt id] [length=0] [chksum] <DLE> <STX>
1072
125
        Send_NAK();
1073
125
        GPSD_LOG(LOG_RAW, &session->context->errout,
1074
125
                 "Garmin: serial too short: %zd\n", len);
1075
125
        return 0;
1076
125
    }
1077
    // debug
1078
136k
    for (i = 0; i < (int)len; i++) {
1079
133k
        GPSD_LOG(LOG_RAW, &session->context->errout,
1080
133k
                 "Garmin: Char: %#02x\n", buf[i]);
1081
133k
    }
1082
1083
2.79k
    if ('\x10' != buf[0]) {
1084
235
        Send_NAK();
1085
235
        GPSD_LOG(LOG_RAW, &session->context->errout,
1086
235
                 "Garmin: buf[0] not DLE\n");
1087
235
        return 0;
1088
235
    }
1089
2.56k
    n = 1;
1090
2.56k
    pkt_id = buf[n++];
1091
2.56k
    chksum = pkt_id;
1092
2.56k
    if ('\x10' == pkt_id) {
1093
92
        if ('\x10' != buf[n++]) {
1094
92
            Send_NAK();
1095
92
            GPSD_LOG(LOG_RAW, &session->context->errout,
1096
92
                     "Garmin: Bad pkt_id %#02x\n", pkt_id);
1097
92
            return 0;
1098
92
        }
1099
92
    }
1100
1101
2.46k
    pkt_len = buf[n++];
1102
2.46k
    chksum += pkt_len;
1103
2.46k
    if ('\x10' == pkt_len) {
1104
151
        if ('\x10' != buf[n++]) {
1105
0
            GPSD_LOG(LOG_RAW, &session->context->errout,
1106
0
                     "Garmin: Bad pkt_len %#02x\n", pkt_len);
1107
0
            Send_NAK();
1108
0
            return 0;
1109
0
        }
1110
151
    }
1111
2.46k
    data_index = 0;
1112
    // we are never really sure of garmin packet sizes, prevent another CVE
1113
2.46k
    memset(data_buf, 0, sizeof(data_buf));
1114
64.8k
    for (i = 0; i < 256; i++) {
1115
1116
64.8k
        if ((int)pkt_len == data_index) {
1117
            // got it all
1118
2.26k
            break;
1119
2.26k
        }
1120
62.5k
        if (len < n + i) {
1121
0
            GPSD_LOG(LOG_RAW, &session->context->errout,
1122
0
                     "Garmin: Packet too short %zd < %zd\n",
1123
0
                     len, n + i);
1124
0
            Send_NAK();
1125
0
            return 0;
1126
0
        }
1127
62.5k
        c = buf[n + i];
1128
62.5k
        if (got_dle) {
1129
            // handle DLE stuffing
1130
567
            got_dle = 0;
1131
567
            if ('\x10' != c) {
1132
174
                Send_NAK();
1133
174
                GPSD_LOG(LOG_RAW, &session->context->errout,
1134
174
                         "Garmin: Bad DLE %#02x\n", c);
1135
174
                return 0;
1136
174
            }
1137
62.0k
        } else {
1138
62.0k
            chksum += c;
1139
62.0k
            data_buf[data_index++] = c;
1140
62.0k
            if ('\x10' == c) {
1141
671
                got_dle = 1;
1142
671
            }
1143
62.0k
        }
1144
62.5k
    }
1145
    // get checksum
1146
2.29k
    if (len < n + i) {
1147
0
        Send_NAK();
1148
0
        GPSD_LOG(LOG_RAW, &session->context->errout,
1149
0
                 "Garmin: No checksum, Packet too short %zd < %zd\n", len,
1150
0
                 n + i);
1151
0
        return 0;
1152
0
    }
1153
2.29k
    c = buf[n + i++];
1154
2.29k
    chksum += c;
1155
    // get final DLE
1156
2.29k
    if (len < n + i) {
1157
0
        Send_NAK();
1158
0
        GPSD_LOG(LOG_RAW, &session->context->errout,
1159
0
                 "Garmin: No final DLE, Packet too short %zd < %zd\n", len,
1160
0
                 n + i);
1161
0
        return 0;
1162
0
    }
1163
2.29k
    c = buf[n + i++];
1164
2.29k
    if ('\x10' != c) {
1165
154
        Send_NAK();
1166
154
        GPSD_LOG(LOG_RAW, &session->context->errout,
1167
154
                 "Garmin: Final DLE not DLE\n");
1168
154
        return 0;
1169
154
    }
1170
    // get final ETX
1171
2.14k
    if (len < n + i) {
1172
0
        Send_NAK();
1173
0
        GPSD_LOG(LOG_RAW, &session->context->errout,
1174
0
                 "Garmin: No final ETX, Packet too short %zd < %zd\n", len,
1175
0
                 n + i);
1176
0
        return 0;
1177
0
    }
1178
    // we used to say n++ here, but scan-build complains
1179
2.14k
    c = buf[n + i];
1180
2.14k
    if ('\x03' != c) {
1181
95
        Send_NAK();
1182
95
        GPSD_LOG(LOG_RAW, &session->context->errout,
1183
95
                 "Garmin: Final ETX not ETX\n");
1184
95
        return 0;
1185
95
    }
1186
1187
    // debug
1188
53.5k
    for (i = 0; i < data_index; i++) {
1189
51.4k
        GPSD_LOG(LOG_RAW, &session->context->errout,
1190
51.4k
                 "Garmin: Char %#02x\n", data_buf[i]);
1191
51.4k
    }
1192
1193
1194
2.04k
    GPSD_LOG(LOG_DATA, &session->context->errout,
1195
2.04k
             "Garmin: garmin_ser_parse() Type %#02x Len %#02x chksum %#02x\n",
1196
2.04k
             pkt_id, pkt_len, chksum);
1197
2.04k
    mask = PrintSERPacket(session, pkt_id, pkt_len, data_buf);
1198
1199
    /* sending ACK too soon might hang the session
1200
     * so send ACK last, after a pause, then wait 300 uSec */
1201
2.04k
    delay.tv_sec = 0;
1202
2.04k
    delay.tv_nsec = 300000L;
1203
2.04k
    nanosleep(&delay, NULL);
1204
1205
2.04k
    Send_ACK();
1206
2.04k
    GPSD_LOG(LOG_DATA, &session->context->errout,
1207
2.04k
             "Garmin: garmin_ser_parse( )\n");
1208
2.04k
    return mask;
1209
2.14k
}
1210
1211
1212
static void settle(void)
1213
0
{
1214
0
    struct timespec delay, rem;
1215
0
    memset(&delay, 0, sizeof(delay));
1216
0
    delay.tv_sec = 0;
1217
0
    delay.tv_nsec = 333000000L;
1218
0
    nanosleep(&delay, &rem);
1219
0
}
1220
1221
static void garmin_switcher(struct gps_device_t *session, int mode)
1222
0
{
1223
0
    if (mode == MODE_NMEA) {
1224
0
        const char switcher[] =
1225
0
            { 0x10, 0x0A, 0x02, 0x26, 0x00, 0xCE, 0x10, 0x03 };
1226
        // Note hard-coded string length in the next line...
1227
0
        ssize_t status = gpsd_write(session, switcher, sizeof(switcher));
1228
0
        if ((ssize_t)sizeof(switcher) == status) {
1229
0
            GPSD_LOG(LOG_PROG, &session->context->errout,
1230
0
                     "Garmin: => GPS: turn off binary %02x %02x %02x... \n",
1231
0
                     switcher[0], switcher[1], switcher[2]);
1232
0
        } else {
1233
0
            GPSD_LOG(LOG_ERROR, &session->context->errout,
1234
0
                     "Garmin: => GPS: FAILED\n");
1235
0
        }
1236
0
        settle();               // wait 333mS, essential!
1237
1238
        // once a sec, no binary, no averaging, NMEA 2.3, WAAS
1239
0
        (void)nmea_send(session, "$PGRMC1,1,1");
1240
        //(void)nmea_send(fd, "$PGRMC1,1,1,1,,,,2,W,N");
1241
0
        (void)nmea_send(session, "$PGRMI,,,,,,,R");
1242
0
        settle();               // wait 333mS, essential!
1243
0
    } else {
1244
0
        (void)nmea_send(session, "$PGRMC1,1,2,1,,,,2,W,N");
1245
0
        (void)nmea_send(session, "$PGRMI,,,,,,,R");
1246
0
        settle();               // wait 333mS, essential!
1247
0
    }
1248
0
}
1249
1250
// not used by the daemon, it's for gpsctl and friends
1251
static ssize_t garmin_control_send(struct gps_device_t *session,
1252
                                   char *buf, size_t buflen)
1253
0
{
1254
0
    session->msgbuflen = buflen;
1255
0
    (void)memcpy(session->msgbuf, buf, buflen);
1256
0
    return gpsd_write(session, session->msgbuf, session->msgbuflen);
1257
0
}
1258
1259
static double garmin_time_offset(struct gps_device_t *session)
1260
0
{
1261
0
    if (SOURCE_USB == session->sourcetype) {
1262
0
        return 0.035;           // Garmin USB, expect +/- 40mS jitter
1263
0
    }
1264
    /* only two sentences ships time
1265
     * but the PVT data is always first */
1266
0
    switch (session->gpsdata.dev.baudrate) {
1267
0
    case 4800:
1268
0
        return 0.430;           // TBD
1269
0
    case 9600:
1270
0
        return 0.430;           // tested 12Arp10
1271
0
    case 19200:
1272
0
        return 0.430;           // TBD
1273
0
    case 38400:
1274
0
        return 0.430;           // TBD
1275
0
    }
1276
0
    return 0.430;               // WTF?  WAG
1277
0
}
1278
1279
// this is everything we export
1280
1281
// *INDENT-OFF*
1282
const struct gps_type_t driver_garmin_usb_binary =
1283
{
1284
    .type_name      = "Garmin USB binary",  // full name of type
1285
    .packet_type    = GARMIN_PACKET,        // associated lexer packet type
1286
    .flags          = DRIVER_STICKY,        // remember this
1287
    .trigger        = NULL,                 // no trigger, it has a probe
1288
    .channels       = GARMIN_CHANNELS,      // consumer-grade GPS
1289
    .probe_detect   = garmin_usb_detect,    // how to detect at startup time
1290
    .get_packet     = packet_get1,          // how to grab a packet
1291
    .parse_packet   = garmin_ser_parse,     // parse message packets
1292
    .rtcm_writer    = NULL,                 // don't send DGPS corrections
1293
    .init_query     = NULL,                 // non-perturbing initial query
1294
    .event_hook     = garmin_event_hook,    // lifetime ebent handler
1295
    .speed_switcher = NULL,                 // no speed switcher
1296
    .mode_switcher  = NULL,                 // Garmin USB Binary has no NMEA
1297
    .rate_switcher  = NULL,                 // no sample-rate switcher
1298
    .min_cycle.tv_sec  = 0,
1299
    .min_cycle.tv_nsec = 10000000,          // 10Hz
1300
    .control_send   = garmin_control_send,  // send raw bytes
1301
    .time_offset     = garmin_time_offset,
1302
};
1303
1304
const struct gps_type_t driver_garmin_ser_binary =
1305
{
1306
    .type_name      = "Garmin Serial binary",  // full name of type
1307
    .packet_type    = GARMIN_PACKET,           // associated lexer packet type
1308
    .flags          = DRIVER_STICKY,           // remember this
1309
    .trigger        = NULL,                    // no trigger, it has a probe
1310
    .channels       = GARMIN_CHANNELS,         // consumer-grade GPS
1311
    .probe_detect   = NULL,                    // how to detect at startup time
1312
    .get_packet     = packet_get1,             // how to grab a packet
1313
    .parse_packet   = garmin_ser_parse,        // parse message packets
1314
    .rtcm_writer    = NULL,                    // don't send DGPS corrections
1315
    .init_query     = NULL,                    // non-perturbing initial query
1316
    /* The Garmin Gek0 301 needs to be kicked to start sending binary.
1317
     * like the Garmin USB. */
1318
    .event_hook     = garmin_event_hook,       // lifetime event handler
1319
    .speed_switcher = NULL,                    // no speed switcher
1320
    .mode_switcher  = garmin_switcher,         // how to change modes
1321
    .rate_switcher  = NULL,                    // no sample-rate switcher
1322
    .min_cycle.tv_sec  = 0,
1323
    .min_cycle.tv_nsec = 10000000,             // 10Hz
1324
    .control_send   = garmin_control_send,     // send raw bytes
1325
    .time_offset     = garmin_time_offset,
1326
};
1327
// *INDENT-ON*
1328
1329
#endif  // GARMIN_ENABLE
1330
1331
// vim: set expandtab shiftwidth=4