Coverage Report

Created: 2026-10-12 06:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gpsd/gpsd-3.27.6~dev/drivers/driver_sirf.c
Line
Count
Source
1
/*
2
 * This is the gpsd driver for SiRF GPSes operating in binary mode.
3
 * It also handles early u-bloxes that were SiRF derivatives.
4
 *
5
 * The advantages: Reports climb/sink rate (raw-mode clients won't see this).
6
 * Also, we can flag DGPS satellites used in the skyview when SBAS is in use.
7
 * The disadvantages: Doesn't return PDOP or VDOP, just HDOP.
8
 *
9
 * Chris Kuethe, our SiRF expert, tells us:
10
 *
11
 * "I don't see any indication in any of my material that PDOP, GDOP
12
 * or VDOP are output. There are quantities called Estimated
13
 * {Horizontal Position, Vertical Position, Time, Horizontal Velocity}
14
 * Error, but those are apparently only valid when SiRFDRive is
15
 * active."
16
 *
17
 * "(SiRFdrive is their Dead Reckoning augmented firmware. It
18
 * allows you to feed odometer ticks, gyro and possibly
19
 * accelerometer inputs to the chip to allow it to continue
20
 * to navigate in the absence of satellite information, and
21
 * to improve fixes when you do have satellites.)"
22
 *
23
 * "[When we need RINEX data, we can get it from] SiRF Message #5.
24
 *  If it's no longer implemented on your receiver, messages
25
 * 7, 28, 29 and 30 will give you the same information."
26
 *
27
 * There is a known problem with the SiRF IV: it is prone to freeze
28
 * when being switched back to NMEA mode from SiRF binary. The
29
 * failure is randomly flaky, you may get away with several mode
30
 * flips before triggering it.  Powering off the device resets and
31
 * unfreezes it. We have tries waiting on command acknowledges as
32
 * the manual advises; this does not fix the problem.
33
 *
34
 * This file is Copyright 2010 by the GPSD project
35
 * SPDX-License-Identifier: BSD-2-clause
36
 */
37
38
#include "../include/gpsd_config.h"   // must be before all includes
39
40
#include <ctype.h>
41
#include <math.h>
42
#include <stdbool.h>
43
#include <stdio.h>
44
#include <stdlib.h>
45
#include <string.h>
46
#include <strings.h>
47
#include <unistd.h>
48
49
#include "../include/compiler.h"   // for FALLTHROUGH
50
#include "../include/gpsd.h"
51
#include "../include/bits.h"
52
#include "../include/strfuncs.h"
53
#include "../include/timespec.h"
54
55
#if defined(SIRF_ENABLE)
56
57
1
#define HI(n)           ((n) >> 8)
58
1
#define LO(n)           ((n) & 0xff)
59
60
/*
61
 * According to the protocol reference, if you don't get ACK/NACK in response
62
 * to a control send within 6 seconds, you should just retry.
63
 */
64
#define SIRF_RETRY_TIME 6
65
66
// Poll Software Version MID 132
67
static unsigned char versionprobe[] = {
68
    0xa0, 0xa2, 0x00, 0x02,
69
    0x84,               // MID 132
70
    0x00,               // unused
71
    0x00, 0x00, 0xb0, 0xb3
72
};
73
74
// Poll Navigation Parameters MID 152, query for MID 19
75
static unsigned char navparams[] = {
76
    0xa0, 0xa2, 0x00, 0x02,
77
    0x98,               // MID 152
78
    0x00,
79
    0x00, 0x00, 0xb0, 0xb3
80
};
81
82
// DGPS Source MID 133
83
static unsigned char dgpscontrol[] = {
84
    0xa0, 0xa2, 0x00, 0x07,
85
    0x85,               // MID 133
86
    0x01,               // use SBAS
87
    0x00, 0x00,
88
    0x00, 0x00, 0x00,
89
    0x00, 0x00, 0xb0, 0xb3
90
};
91
92
// Set SBAS Parameters MID 170
93
static unsigned char sbasparams[] = {
94
    0xa0, 0xa2, 0x00, 0x06,
95
    0xaa,               // MID 170
96
    0x00,               // SBAS PRN
97
    0x01,               // SBAS Mode
98
    0x00,               // Auto PRN
99
    0x00, 0x00,
100
    0x00, 0x00, 0xb0, 0xb3
101
};
102
103
// Set Message Rate MID 166
104
static unsigned char requestecef[] = {
105
    0xa0, 0xa2, 0x00, 0x08,
106
    0xa6,               // MID 166
107
    0x00,               // enable 1
108
    0x02,               // MID 2
109
    0x01,               // once per Sec
110
    0x00, 0x00,         // unused
111
    0x00, 0x00,         // unused
112
    0x00, 0x00, 0xb0, 0xb3
113
};
114
115
// Set Message Rate MID 166
116
static unsigned char requesttracker[] = {
117
    0xa0, 0xa2, 0x00, 0x08,
118
    0xa6,               // MID 166
119
    0x00,               // enable 1
120
    0x04,               // MID 4
121
    0x03,               // every 3 sec
122
    0x00, 0x00,         // unused
123
    0x00, 0x00,         // unused
124
    0x00, 0x00, 0xb0, 0xb3
125
};
126
127
// disable MID XX
128
static unsigned char unsetmidXX[] = {
129
    0xa0, 0xa2, 0x00, 0x08,
130
    0xa6,               // MID 166
131
    0x00,               // enable XX
132
    0x00,               // MID 0xXX
133
    0x00,               // rate: never
134
    0x00, 0x00,         // reserved
135
    0x00, 0x00,         // reserved
136
    0x00, 0x00, 0xb0, 0xb3
137
};
138
139
/* message to enable:
140
 *   MID 7 Clock Status
141
 *   MID 8 50Bps subframe data
142
 *   MID 17 Differential  Corrections
143
 *   MID 28 Nav Lib Measurement Data
144
 *   MID 29 Nav Lib DGPS Data
145
 *   MID 30 Nav Lib SV State Data
146
 *   MID 31 Nav Lib Initialization data
147
 * at 1Hz rate */
148
static unsigned char enablesubframe[] = {
149
    0xa0, 0xa2, 0x00, 0x19,
150
    0x80,                       // MID 128 initialize Data Source
151
    0x00, 0x00, 0x00, 0x00,     // EXEF X
152
    0x00, 0x00, 0x00, 0x00,     // ECEF Y
153
    0x00, 0x00, 0x00, 0x00,     // ECEF Z
154
    0x00, 0x00, 0x00, 0x00,     // clock drift
155
    0x00, 0x00, 0x00, 0x00,     // time of week
156
    0x00, 0x00,                 // week number
157
    0x0C,                       // Chans 1-12
158
    /* change the next 0x10 to 0x08 for factory reset
159
     * 0x10 turns on MIDs 7, 8, 17, 28, 29, 30 and 31 */
160
    0x10,
161
    0x00, 0x00, 0xb0, 0xb3
162
};
163
164
// disable subframe data
165
static unsigned char disablesubframe[] = {
166
    0xa0, 0xa2, 0x00, 0x19,
167
    0x80,                       // MID 128 initialize Data Source
168
    0x00, 0x00, 0x00, 0x00,     // EXEF X
169
    0x00, 0x00, 0x00, 0x00,     // ECEF Y
170
    0x00, 0x00, 0x00, 0x00,     // ECEF Z
171
    0x00, 0x00, 0x00, 0x00,     // clock drift
172
    0x00, 0x00, 0x00, 0x00,     // time of week
173
    0x00, 0x00,                 // week number
174
    0x0C,                       // Chans 1-12
175
176
    // 0x00 turns off MIDs 7, 8, 17, 28, 29, 30 and 31
177
    0x00,                       // reset bit map
178
179
    0x00, 0x00, 0xb0, 0xb3
180
};
181
182
// mode control MID
183
static unsigned char modecontrol[] = {
184
    0xa0, 0xa2, 0x00, 0x0e,
185
    0x88,                       // MID 136 Mode Control
186
    0x00, 0x00,                 // pad bytes
187
    0x00,                       // degraded mode off
188
    0x00, 0x00,                 // pad bytes
189
    0x00, 0x00,                 // altitude
190
    0x00,                       // altitude hold auto
191
    0x00,                       // use last computed alt
192
    0x00,                       // reserved
193
    0x00,                       // disable degraded mode
194
    0x00,                       // disable dead reckoning
195
    0x01,                       // enable track smoothing
196
    0x00, 0x00, 0xb0, 0xb3
197
};
198
199
// enable 1 PPS Time MID 52, using Set Message Rate MID 166
200
static unsigned char enablemid52[] = {
201
    0xa0, 0xa2, 0x00, 0x08,
202
    0xa6,                       // MID 166
203
    0x00,                       // enable/disable one message
204
    0x34,                       // MID 52
205
    0x01,                       // sent once per second
206
    0x00, 0x00, 0x00, 0x00,     // reserved, set to zero
207
    0x00, 0xdb, 0xb0, 0xb3
208
};
209
210
211
static gps_mask_t sirf_msg_debug(struct gps_device_t *,
212
                                 unsigned char *, size_t);
213
static gps_mask_t sirf_msg_errors(struct gps_device_t *,
214
                                  unsigned char *, size_t);
215
static gps_mask_t sirf_msg_navdata(struct gps_device_t *, unsigned char *,
216
                                   size_t);
217
static gps_mask_t sirf_msg_navsol(struct gps_device_t *, unsigned char *,
218
                                  size_t);
219
static gps_mask_t sirf_msg_nlmd(struct gps_device_t *, unsigned char *,
220
                                size_t);
221
static gps_mask_t sirf_msg_ppstime(struct gps_device_t *, unsigned char *,
222
                                   size_t);
223
static gps_mask_t sirf_msg_nl(struct gps_device_t *, unsigned char *,
224
                                   size_t);
225
static gps_mask_t sirf_msg_ee(struct gps_device_t *, unsigned char *,
226
                                   size_t);
227
static gps_mask_t sirf_msg_svinfo(struct gps_device_t *, unsigned char *,
228
                                  size_t);
229
static gps_mask_t sirf_msg_swversion(struct gps_device_t *, unsigned char *,
230
                                     size_t);
231
static gps_mask_t sirf_msg_sysparam(struct gps_device_t *, unsigned char *,
232
                                    size_t);
233
static gps_mask_t sirf_msg_dgpsstatus(struct gps_device_t *, unsigned char *,
234
                                      size_t);
235
static gps_mask_t sirf_msg_ublox(struct gps_device_t *, unsigned char *,
236
                                 size_t);
237
238
239
static bool sirf_write(struct gps_device_t *session, unsigned char *msg,
240
                       size_t msg_size)
241
4.39k
{
242
4.39k
    unsigned int crc;
243
4.39k
    size_t i, len;
244
4.39k
    bool ok;
245
4.39k
    unsigned int type;
246
247
    // do not write if -b (readonly) option set
248
4.39k
    if (session->context->readonly) {
249
1
        return true;
250
1
    }
251
4.39k
    if (10 > msg_size) {
252
        // message is smaller than minimum size
253
0
        GPSD_LOG(LOG_ERROR, &session->context->errout,
254
0
                 "SiRF: sirf_write() msg too small!\n");
255
0
        return false;
256
0
    }
257
4.39k
    type = msg[4];
258
259
    /*
260
     * Control strings spaced too closely together confuse the SiRF
261
     * IV.  This wasn't an issue on older SiRFs, but they've gone to a
262
     * lower-powered processor that apparently has trouble keeping up.
263
     * Now you have to wait for the ACK, otherwise chaos ensues.
264
     * Add instrumentation to reveal when this may happen.
265
     */
266
    // can also be false because ACK was received after last send
267
4.39k
    if (0 < session->driver.sirf.need_ack) {
268
1.02k
        GPSD_LOG(LOG_WARN, &session->context->errout,
269
1.02k
                 "SiRF: warning, write of MID %#02x while "
270
1.02k
                 "awaiting ACK for %#02x.\n",
271
1.02k
                 type, session->driver.sirf.need_ack);
272
1.02k
    }
273
274
4.39k
    len = (size_t)((msg[2] << 8) | msg[3]);
275
4.39k
    if ((len + 8) > msg_size) {
276
        // message is smaller than len + leader + trailer
277
0
        GPSD_LOG(LOG_ERROR, &session->context->errout,
278
0
                 "SiRF: sirf_write() msg less than %zu!\n", len + 8);
279
0
        return false;
280
0
    }
281
    // calculate CRC
282
4.39k
    crc = 0;
283
29.2k
    for (i = 0; i < len; i++) {
284
24.8k
        crc += (int)msg[4 + i];
285
24.8k
    }
286
4.39k
    crc &= 0x7fff;
287
288
    // enter CRC after payload
289
4.39k
    msg[len + 4] = (unsigned char)((crc & 0xff00) >> 8);
290
4.39k
    msg[len + 5] = (unsigned char)(crc & 0x00ff);
291
292
4.39k
    GPSD_LOG(LOG_PROG, &session->context->errout,
293
4.39k
             "SiRF: Writing MID %#02x:\n", type);
294
4.39k
    ok = (gpsd_write(session, (const char *)msg, len + 8) ==
295
4.39k
          (ssize_t) (len + 8));
296
297
4.39k
    session->driver.sirf.need_ack = type;
298
4.39k
    return ok;
299
4.39k
}
300
301
static ssize_t sirf_control_send(struct gps_device_t *session, char *msg,
302
                                 size_t len)
303
0
{
304
0
    session->msgbuf[0] = (char)0xa0;
305
0
    session->msgbuf[1] = (char)0xa2;
306
0
    session->msgbuf[2] = (len >> 8) & 0xff;
307
0
    session->msgbuf[3] = len & 0xff;
308
0
    memcpy(session->msgbuf + 4, msg, len);
309
0
    session->msgbuf[len + 6] = (char)0xb0;
310
0
    session->msgbuf[len + 7] = (char)0xb3;
311
0
    session->msgbuflen = len + 8;
312
313
    // *INDENT-OFF*
314
0
    return sirf_write(session,
315
0
              (unsigned char *)session->msgbuf,
316
0
              sizeof(session->msgbuf)) ? (int)session->msgbuflen : -1;
317
    // *INDENT-ON*
318
0
}
319
320
// change speed in binary mode
321
static bool sirfbin_speed(struct gps_device_t *session, speed_t speed,
322
                          char parity, int stopbits)
323
0
{
324
0
    static unsigned char msg[] = {
325
0
        0xa0, 0xa2, 0x00, 0x09,
326
0
        0x86,                   /* byte 4:
327
                                 * Set Binary Serial Port
328
                                 * MID 134 */
329
0
        0x00, 0x00, 0x12, 0xc0, // bytes 5-8: 4800 bps
330
0
        0x08,                   // byte  9: 8 data bits
331
0
        0x01,                   // byte 10: 1 stop bit
332
0
        0x00,                   // byte 11: no parity
333
0
        0x00,                   // byte 12: reserved pad
334
0
        0x00, 0x00, 0xb0, 0xb3
335
0
    };
336
0
    GPSD_LOG(LOG_PROG, &session->context->errout,
337
0
             "SiRF: sirf_speed(%u,%c,%d)\n",
338
0
             (unsigned int)speed, parity, stopbits);
339
0
    if (9600 >= speed) {
340
0
        GPSD_LOG(LOG_WARN, &session->context->errout,
341
0
                 "SiRF may lag at 9600bps or less.\n");
342
0
    }
343
344
0
    switch (parity) {
345
0
    case 'E':
346
0
    case 2:
347
0
        parity = (char)2;
348
0
        break;
349
0
    case 'O':
350
0
    case 1:
351
0
        parity = (char)1;
352
0
        break;
353
0
    case 'N':
354
0
    case 0:
355
0
    default:
356
0
        parity = (char)0;
357
0
        break;
358
0
    }
359
0
    msg[5] = (unsigned char)((speed >> 24) & 0xff);
360
0
    msg[6] = (unsigned char)((speed >> 16) & 0xff);
361
0
    msg[7] = (unsigned char)((speed >> 8) & 0xff);
362
0
    msg[8] = (unsigned char)(speed & 0xff);
363
0
    msg[10] = (unsigned char)stopbits;
364
0
    msg[11] = (unsigned char)parity;
365
0
    return sirf_write(session, msg, sizeof(msg));
366
0
}
367
368
/* switch from binary to NMEA at specified baud
369
 * FIXME: does not seem to work... */
370
static bool sirf_to_nmea(struct gps_device_t *session, speed_t speed)
371
1
{
372
1
    static unsigned char msg[] = { 0xa0, 0xa2, 0x00, 0x18,
373
1
        0x81, 0x02,
374
1
        0x01, 0x01,             // GGA
375
1
        0x00, 0x00,             // suppress GLL
376
1
        0x01, 0x01,             // GSA
377
1
        0x05, 0x01,             // GSV
378
1
        0x01, 0x01,             // RMC
379
1
        0x00, 0x00,             // suppress VTG
380
1
        0x00, 0x01,             // suppress MSS
381
1
        0x00, 0x01,             // suppress EPE
382
1
        0x00, 0x01,             // suppress EPE
383
1
        0x00, 0x01,             // suppress ZDA
384
1
        0x00, 0x00,             // unused
385
1
        0x12, 0xc0,             // 4800 bps
386
1
        0xb0, 0xb3
387
1
    };
388
389
1
    if (0xffff <= speed) {
390
0
        GPSD_LOG(LOG_ERROR, &session->context->errout,
391
0
                 "SiRF: can't switch from SiRF to NMEA because "
392
0
                 " current speed %u is big.",
393
0
                 (unsigned int)speed);
394
0
        return false;
395
0
    }
396
397
    // stop binary initialization
398
1
    session->cfg_stage = UINT_MAX;
399
400
1
    msg[26] = (unsigned char)HI(speed);
401
1
    msg[27] = (unsigned char)LO(speed);
402
1
    return sirf_write(session, msg, sizeof(msg));
403
1
}
404
405
static void sirfbin_mode(struct gps_device_t *session, int mode)
406
1
{
407
1
    if (MODE_NMEA == mode) {
408
1
        (void)sirf_to_nmea(session, session->gpsdata.dev.baudrate);
409
1
    } else if (MODE_BINARY == mode) {
410
0
        char parity = '0';
411
0
        switch (session->gpsdata.dev.parity) {
412
0
        default:
413
0
        case 'N':
414
0
            parity = '0';
415
0
            break;
416
0
        case 'O':
417
0
            parity = '1';
418
0
            break;
419
0
        case 'E':
420
0
            parity = '2';
421
0
            break;
422
423
0
        }
424
        // gpsd only supports 8[NO]1 or 7[EO]2
425
        // thus the strange use of stopbits
426
0
        (void)nmea_send(session,
427
0
                        "$PSRF100,0,%d,%d,%d,%c",
428
0
                        session->gpsdata.dev.baudrate,
429
0
                        9 - session->gpsdata.dev.stopbits,
430
0
                        session->gpsdata.dev.stopbits, parity);
431
        // reset binary init steps
432
0
        session->cfg_stage = 0;
433
0
        session->cfg_step = 0;
434
0
    }
435
1
}
436
437
// Debug messages MID 255 (0xff)
438
static gps_mask_t sirf_msg_debug(struct gps_device_t *device,
439
                                 unsigned char *buf, size_t len)
440
325
{
441
325
    char msgbuf[MAX_PACKET_LENGTH * 3 + 2];
442
325
    int i;
443
444
325
    memset(msgbuf, 0, (int)sizeof(msgbuf));
445
446
    // FIXME: always/only ID 255
447
325
    if (0xe1 == buf[0]) {       // Development statistics messages
448
0
        if (2 > len) {
449
            // too short
450
0
            GPSD_LOG(LOG_INF, &device->context->errout,
451
0
                     "SiRF: DBG (0xe1) runt len %zu\n", len);
452
0
            return 0;
453
0
        }
454
0
        for (i = 2; i < (int)len; i++) {
455
0
            str_appendf(msgbuf, sizeof(msgbuf), "%c", buf[i] ^ 0xff);
456
0
        }
457
0
        GPSD_LOG(LOG_PROG, &device->context->errout,
458
0
                 "SiRF: MID 0xe1 (225) SID %#0x %s\n", buf[1], msgbuf);
459
325
    } else if (0xff == (unsigned char)buf[0]) {  // Debug messages
460
3.89k
        for (i = 1; i < (int)len; i++) {
461
3.57k
            if (isprint(buf[i])) {
462
980
                str_appendf(msgbuf, sizeof(msgbuf), "%c", buf[i]);
463
2.59k
            } else {
464
2.59k
                str_appendf(msgbuf, sizeof(msgbuf),
465
2.59k
                               "\\x%02x", (unsigned int)buf[i]);
466
2.59k
            }
467
3.57k
        }
468
325
        GPSD_LOG(LOG_PROG, &device->context->errout,
469
325
                 "SiRF: DBG 0xff: %s\n", msgbuf);
470
325
    }
471
325
    return 0;
472
325
}
473
474
// decode Error ID Data MID 10 (0x0a)
475
static gps_mask_t sirf_msg_errors(struct gps_device_t *device,
476
                                  unsigned char *buf,
477
                                  size_t len UNUSED)
478
772
{
479
772
    unsigned count;
480
481
772
    if (5 > len) {
482
        // too short
483
169
        GPSD_LOG(LOG_INF, &device->context->errout,
484
169
                 "SiRF: EID (0x0a) runt len %zu\n", len);
485
169
        return 0;
486
169
    }
487
488
603
    count = getbeu16(buf, 3);
489
490
603
    switch (getbeu16(buf, 1)) {
491
35
    case 2:
492
        // ErrId_CS_SVParity
493
35
        GPSD_LOG(LOG_PROG, &device->context->errout,
494
35
                 "SiRF: EID 0x0a type 2: Subframe %u error on PRN %u\n",
495
35
                 getbeu32(buf, 9), getbeu32(buf, 5));
496
35
        break;
497
498
35
    case 4:
499
        // ErrId_RMC_GettingPosition
500
35
        GPSD_LOG(LOG_PROG, &device->context->errout,
501
35
                 "SiRF: EID 0x0a type 4: RMC_GettingPosition on PRN %u\n",
502
35
                 getbeu32(buf, 5));
503
35
        break;
504
505
35
    case 10:
506
        // ErrId_RXM_TimeExceeded
507
35
        GPSD_LOG(LOG_PROG, &device->context->errout,
508
35
                 "SiRF: EID 0x0a type 10: RXM_TimeExceeded PR %u\n",
509
35
                 getbeu32(buf, 5));
510
35
        break;
511
512
35
    case 11:
513
        // ErrId_RXM_TDOPOverflow
514
35
        GPSD_LOG(LOG_PROG, &device->context->errout,
515
35
                 "SiRF: EID 0x0a type 11: RXM_TDOPOverflow doppler %u\n",
516
35
                 getbeu32(buf, 5));
517
35
        break;
518
519
35
    case 12:
520
        // ErrId_RXM_ValidDurationExceeded
521
35
        GPSD_LOG(LOG_PROG, &device->context->errout,
522
35
                 "SiRF: EID 0x0a type 12: RXM_ValidDurationExceeded PRN %u\n",
523
35
                 getbeu32(buf, 5));
524
35
        break;
525
526
35
    case 13:
527
        // ErrId_STRTP_BadPostion
528
35
        GPSD_LOG(LOG_PROG, &device->context->errout,
529
35
                 "SiRF: EID 0x0a type 13: STRTP_BadPostion\n");
530
35
        break;
531
532
35
    case 4097:
533
        // ErrId_MI_VCOClockLost
534
35
        GPSD_LOG(LOG_PROG, &device->context->errout,
535
35
                 "SiRF: EID 0x0a type 4097: MI_VCOClockLost %u\n",
536
35
                 getbeu32(buf, 5));
537
35
        break;
538
539
35
    case 4099:
540
        // ErrId_MI_FalseAcqReceiverReset
541
35
        GPSD_LOG(LOG_PROG, &device->context->errout,
542
35
                 "SiRF: EID 0x0a type 4099: MI_FalseAcqReceiverReset %u\n",
543
35
                 getbeu32(buf, 5));
544
35
        break;
545
546
35
    case 4104:
547
        // ErrId_STRTP_SRAMCksum
548
35
        GPSD_LOG(LOG_PROG, &device->context->errout,
549
35
                 "SiRF: EID 0x0a type 4104: Failed SRAM "
550
35
                 "checksum during startup.\n");
551
35
        break;
552
553
35
    case 4105:
554
        // ErrId_STRTP_RTCTimeInvalid
555
35
        GPSD_LOG(LOG_PROG, &device->context->errout,
556
35
                 "SiRF: EID 0x0a type 4105: Failed RTC SRAM checksum.\n");
557
35
        break;
558
559
35
    case 4106:
560
        // ErrId_KFC_BackupFailed_Velocity
561
35
        GPSD_LOG(LOG_PROG, &device->context->errout,
562
35
                 "SiRF: EID 0x0a type 4106: Failed saving position "
563
35
                 "to NVRAM.\n");
564
35
        break;
565
566
36
    case 4107:
567
        // ErrId_KFC_BackupFailed_NumSV
568
36
        GPSD_LOG(LOG_PROG, &device->context->errout,
569
36
                 "SiRF: EID 0x0a type 4107: neither KF nor LSQ fix.\n");
570
36
        break;
571
572
35
    case 8193:
573
        // ErrId_MI_BufferAllocFailure
574
35
        GPSD_LOG(LOG_PROG, &device->context->errout,
575
35
                 "SiRF: EID 0x0a type 8193: "
576
35
                 "Error ID Description:Buffer allocation error.\n");
577
35
        break;
578
579
35
    case 8194:
580
        // ErrId_MI_UpdateTimeFailure
581
35
        GPSD_LOG(LOG_PROG, &device->context->errout,
582
35
                 "SiRF: EID 0x0a type 8194: "
583
35
                 "PROCESS_1SEC task unable to complete\n");
584
35
        break;
585
586
35
    case 8195:
587
        // ErrId_MI_MemoryTestFailed
588
35
        GPSD_LOG(LOG_PROG, &device->context->errout,
589
35
                 "SiRF: EID 0x0a type 8195: "
590
35
                 "Failure of hardware memory test.\n");
591
35
        break;
592
593
77
    default:
594
77
        GPSD_LOG(LOG_PROG, &device->context->errout,
595
77
                 "SiRF: EID 0x0a: Error MID %u, count %u\n",
596
77
                 getbeu16(buf, 1), count);
597
77
        break;
598
603
    }
599
603
    return 0;
600
603
}
601
602
// Navigation Library Measurement Data MID 28 (0x1c)
603
static gps_mask_t sirf_msg_nlmd(struct gps_device_t *session,
604
                                unsigned char *buf UNUSED, size_t len)
605
172
{
606
607
172
    double gps_tow = 0.0;
608
609
172
    if (56 != len) {
610
171
        GPSD_LOG(LOG_INF, &session->context->errout,
611
171
                 "SiRF: NLMD (0x0a) runt len %zu\n", len);
612
171
        return 0;
613
171
    }
614
615
    /* oh barf, SiRF claims to be IEEE754 but supports two
616
     * different double orders, neither IEEE754 */
617
    /* FIXME - decode the time, since this is the first MID with a
618
     * good time stamp this will be good for ntpshm time */
619
1
    GPSD_LOG(LOG_PROG, &session->context->errout,
620
1
             "SiRF: NLMD 0x1c gps_tow: %f\n",
621
1
             (double)gps_tow);
622
623
1
    return 0;
624
172
}
625
626
// MID_SiRFNavNotification MID 51 (0x33)
627
static gps_mask_t sirf_msg_navnot(struct gps_device_t *session,
628
                                unsigned char *buf, size_t len)
629
305
{
630
305
    const char *definition = "Unknown";
631
305
    gps_mask_t mask = 0;
632
633
305
    if (3 > len) {
634
132
        GPSD_LOG(LOG_INF, &session->context->errout,
635
132
                 "SiRF: MID (0x33) runt len %zu\n", len);
636
132
        return 0;
637
132
    }
638
639
173
    switch (buf[1]) {
640
8
    case 1:
641
        // last message sent every cycle
642
8
        definition = "SID_GPS_SIRFNAV_COMPLETE";
643
        /* so push a report now */
644
8
        mask = REPORT_IS;
645
8
        break;
646
0
    case 2:
647
0
        definition = "SID_GPS_SIRFNAV_TIMING";
648
0
        break;
649
0
    case 3:
650
0
        definition = "SID_GPS_DEMO_TIMING";
651
0
        break;
652
15
    case 4:
653
15
        definition = "SID_GPS_SIRFNAV_TIME_TAGS";
654
15
        break;
655
28
    case 5:
656
28
        definition = "SID_GPS_NAV_IS801_PSEUDORANGE_DATA";
657
28
        break;
658
0
    case 6:
659
0
        definition = "GPS_TRACKER_LOADER_STATE";
660
0
        break;
661
1
    case 7:
662
1
        definition = "SSB_SIRFNAV_START";
663
1
        break;
664
0
    case 8:
665
0
        definition = "SSB_SIRFNAV_STOP";
666
0
        break;
667
1
    case 9:
668
1
        definition = "SSB_RESULT";
669
1
        break;
670
8
    case 16:
671
8
        definition = "DEMO_TEST_STATUS";
672
8
        break;
673
1
    case 17:
674
1
        definition = "DEMO_TEST_STATE";
675
1
        break;
676
34
    case 18:
677
34
        definition = "DEMO_TEST_DATA";
678
34
        break;
679
3
    case 19:
680
3
        definition = "DEMO_TEST_STATS";
681
3
        break;
682
0
    case 20:
683
0
        definition = "DEMO_TEST_ERROR";
684
0
        break;
685
74
    default:
686
74
        break;
687
173
    }
688
689
173
    GPSD_LOG(LOG_PROG, &session->context->errout,
690
173
             "SiRF IV: NavNotification 51 (0x33), SID: %d (%s), len %lu\n",
691
173
             buf[1], definition, (long unsigned)len);
692
693
173
    return mask;
694
173
}
695
696
/* Multiconstellation Navigation Data response MID 67,1 (0x43)
697
 * SIRF_MSG_SSB_GNSS_NAV_DATA
698
 * this replaces the deprecated MID 41 */
699
static gps_mask_t sirf_msg_67_1(struct gps_device_t *session,
700
                                  unsigned char *buf, size_t len)
701
103
{
702
103
    gps_mask_t mask = 0;
703
103
    uint32_t solution_validity;
704
103
    uint32_t solution_info;
705
103
    uint32_t gps_tow = 0;
706
103
    uint32_t msecs;                      // tow in ms
707
103
    uint32_t gps_tow_sub_ms = 0;
708
103
    uint16_t gps_week = 0;
709
103
    timespec_t gps_tow_ns = {0};
710
103
    timespec_t now;
711
103
    int16_t time_bias = 0;
712
103
    uint8_t time_accuracy = 0;
713
103
    uint8_t time_source = 0;
714
103
    struct tm unpacked_date = {0};
715
103
    unsigned char datum;
716
103
    int64_t clk_bias;
717
103
    uint32_t clk_bias_error;
718
103
    int32_t clk_offset;
719
103
    uint32_t clk_offset_error;
720
103
    int16_t heading_rate;             // rate of change cog deg/s * 100
721
103
    uint32_t distance_travel;         // distance traveled m * 100
722
103
    uint16_t distance_travel_error;   // distance traveled error in m * 100
723
724
103
    uint32_t ehpe;                    // Est horizontal position error * 100
725
103
    unsigned char num_svs_in_sol;     // Num of satellites used in solution
726
103
    uint32_t sv_list_1;
727
103
    uint32_t sv_list_2;
728
103
    uint32_t sv_list_3;
729
103
    uint32_t sv_list_4;
730
103
    uint32_t sv_list_5;
731
103
    uint32_t additional_info;
732
103
    int debug_base = LOG_PROG;
733
734
103
    if (126 > len) {
735
93
        GPSD_LOG(LOG_INF, &session->context->errout,
736
93
                 "SiRF: MID 67,1 runt len %zu\n", len);
737
93
        return 0;
738
93
    }
739
740
10
    GPSD_LOG(LOG_PROG, &session->context->errout,
741
10
             "SiRF V: MND 67,1 Multiconstellation Navigation Data Response \n");
742
743
10
    solution_validity = getbeu32(buf, 2);
744
10
    if (0 != solution_validity) {
745
        // invalid fix, just give up
746
1
        return 0;
747
1
    }
748
749
9
    solution_info = getbeu32(buf, 6);
750
9
    gps_week = getbeu16(buf, 10);
751
9
    msecs = getbeu32(buf, 12);
752
9
    gps_tow = msecs / 1000;
753
9
    gps_tow_ns.tv_sec = gps_tow;
754
    // get ms part
755
9
    gps_tow_sub_ms = msecs % 1000;
756
    // add in the ns
757
9
    gps_tow_ns.tv_nsec = (gps_tow_sub_ms * 1000000LL) + getbeu32(buf, 16);
758
9
    now = gpsd_gpstime_resolv(session, gps_week, gps_tow_ns);
759
    /* we'll not use this time, instead the unpacked date below,
760
     * to get the right epoch */
761
762
9
    time_bias = getbes16(buf, 20);    // add in the ns
763
    // time_accuracy is an odd 8 bit float
764
9
    time_accuracy = getub(buf, 22);
765
9
    time_source = getub(buf, 23);     // unused
766
767
9
    memset(&unpacked_date, 0, sizeof(unpacked_date));
768
9
    unpacked_date.tm_year = (int)getbeu16(buf, 24) - 1900;
769
9
    unpacked_date.tm_mon = (int)getub(buf, 26) - 1;
770
9
    unpacked_date.tm_mday = (int)getub(buf, 27);
771
9
    unpacked_date.tm_hour = (int)getub(buf, 28);
772
9
    unpacked_date.tm_min = (int)getub(buf, 29);
773
9
    unpacked_date.tm_sec = (int)getbeu16(buf, 30) / 1000;
774
9
    session->context->leap_seconds = (int)getub(buf, 32);
775
9
    session->context->valid |= LEAP_SECOND_VALID;
776
9
    session->newdata.time.tv_sec = mkgmtime(&unpacked_date);
777
9
    session->newdata.time.tv_nsec = gps_tow_ns.tv_nsec;
778
    // got time now
779
9
    mask |= TIME_SET;
780
781
9
    datum = getub(buf, 33);
782
9
    datum_code_string(datum, session->newdata.datum,
783
9
                      sizeof(session->newdata.datum));
784
785
9
    clk_bias = getbes64(buf, 34) / 100.0;
786
9
    clk_bias_error = getbeu32(buf, 42) / 100.0;
787
9
    clk_offset = getbes32(buf, 46) / 100.0;
788
9
    clk_offset_error = getbeu32(buf, 50) / 100.0;
789
9
    session->newdata.latitude = getbes32(buf, 54) * 1e-7;
790
9
    session->newdata.longitude = getbes32(buf, 58) * 1e-7;
791
    // altitude WGS84
792
9
    session->newdata.altHAE = getbes32(buf, 62) * 1e-2;
793
    // altitude MSL
794
9
    session->newdata.altMSL = getbes32(buf, 66) * 1e-2;
795
    // Let gpsd_error_model() deal with geoid_sep
796
797
9
    mask |= LATLON_SET;
798
799
9
    switch (solution_info & 0x07) {
800
2
    case 0:      // no fix
801
2
        session->newdata.mode = MODE_NO_FIX;
802
2
        break;
803
1
    case 1:      // unused
804
1
        session->newdata.mode = MODE_NO_FIX;
805
1
        break;
806
1
    case 2:      // unused
807
1
        session->newdata.mode = MODE_NO_FIX;
808
1
        break;
809
1
    case 3:      // 3-SV KF Solution
810
1
        session->newdata.mode = MODE_2D;
811
1
        break;
812
1
    case 4:      // Four or more SV KF Solution
813
1
        session->newdata.mode = MODE_3D;
814
1
        break;
815
1
    case 5:      // 2-D Least-squares Solution
816
1
        session->newdata.mode = MODE_2D;
817
1
        break;
818
1
    case 6:      // 3-D Least-squaresSolution
819
1
        session->newdata.mode = MODE_3D;
820
1
        break;
821
1
    case 7:      // DR solution, assume 3D
822
1
        session->newdata.mode = MODE_3D;
823
1
        break;
824
0
    default:     // can't really happen
825
0
        session->newdata.mode = MODE_NO_FIX;
826
0
        break;
827
9
    }
828
9
    mask |= MODE_SET;
829
830
9
    if (!(solution_info & 0x01000)) {
831
        // sog - speed over ground m/s * 100
832
6
        session->newdata.speed = getbeu16(buf, 70) / 100.0;
833
6
        mask |= SPEED_SET;
834
6
    }
835
    // cog - course over ground fm true north deg * 100
836
9
    session->newdata.track = getbeu16(buf, 72) / 100.0;
837
9
    mask |= TRACK_SET;
838
839
    // climb_rate - vertical velocity m/s * 100
840
9
    session->newdata.climb = getbes16(buf, 74) / 100.0;
841
842
9
    if (MODE_3D == session->newdata.mode) {
843
3
        mask |= ALTITUDE_SET | CLIMB_SET;
844
3
    }
845
846
9
    heading_rate = getbes16(buf, 76);     // rate of change cog deg/s * 100
847
9
    distance_travel = getbeu32(buf, 78);  // distance traveled m * 100
848
    // heading_error error of cog deg * 100
849
9
    session->newdata.epd = getbeu16(buf, 82) / 100.0;
850
    // distance traveled error in m * 100
851
9
    distance_travel_error = getbeu16(buf, 84) / 100.0;
852
853
9
    ehpe = getbeu32(buf, 86);  // Estimated horizontal position error * 100
854
    // Estimated vertical position error * 100
855
9
    session->newdata.epv = getbeu32(buf, 90) / 100.0;
856
    // Estimated horizontal velocity error * 100
857
9
    session->newdata.eps = getbeu16(buf, 94) / 100.0;
858
9
    mask |= SPEEDERR_SET;
859
860
9
    session->gpsdata.dop.gdop = (int)getub(buf, 96) / 5.0;
861
9
    session->gpsdata.dop.pdop = (int)getub(buf, 97) / 5.0;
862
9
    session->gpsdata.dop.hdop = (int)getub(buf, 98) / 5.0;
863
9
    session->gpsdata.dop.vdop = (int)getub(buf, 99) / 5.0;
864
9
    session->gpsdata.dop.tdop = (int)getub(buf, 100) / 5.0;
865
9
    mask |= DOP_SET;
866
867
9
    num_svs_in_sol = getub(buf, 101);
868
9
    sv_list_1 = getbeu32(buf, 102);
869
9
    sv_list_2 = getbeu32(buf, 106);
870
9
    sv_list_3 = getbeu32(buf, 110);
871
9
    sv_list_4 = getbeu32(buf, 114);
872
9
    sv_list_5 = getbeu32(buf, 118);
873
9
    additional_info = getbeu32(buf, 122);
874
875
9
    mask |= REPORT_IS;  // send it
876
877
    // skip all the debug pushing and popping, unless needed
878
9
    if (session->context->errout.debug >= debug_base) {
879
0
        char ts_buf[TIMESPEC_LEN];
880
881
        /* coerce time_t to long to placate older OS, like 32-bit FreeBSD,
882
         * where time_t is int */
883
0
        GPSD_LOG(debug_base, &session->context->errout,
884
0
                 "SiRF V: MND 67,1 GPS Week %d, tow %d.%03d, time %s\n",
885
0
                 gps_week, gps_tow, gps_tow_sub_ms,
886
0
                 timespec_str(&now, ts_buf, sizeof(ts_buf)));
887
0
        GPSD_LOG(debug_base, &session->context->errout,
888
0
                 "SiRF V: MND 67,1 UTC time %s leaps %u, datum %s\n",
889
0
                 timespec_str(&session->newdata.time, ts_buf, sizeof(ts_buf)),
890
0
                 session->context->leap_seconds,
891
0
                 session->newdata.datum);
892
0
        GPSD_LOG(debug_base, &session->context->errout,
893
0
                 "SiRF V: MND 67,1 packed: %02d%02d%02d %02d:%02d:%02d\n",
894
0
                 unpacked_date.tm_mday, unpacked_date.tm_mon + 1,
895
0
                 unpacked_date.tm_year % 100,
896
0
                 unpacked_date.tm_hour, unpacked_date.tm_min,
897
0
                 unpacked_date.tm_sec);
898
0
        GPSD_LOG(debug_base, &session->context->errout,
899
0
                 "SiRF V: MND 67,1 solution_info %08x\n", solution_info);
900
0
        GPSD_LOG(debug_base, &session->context->errout,
901
0
                 "SiRF V: MND 67,1 lat %.7f lon %.7f altHAE %.2f altMSL %.2f\n",
902
0
                 session->newdata.latitude, session->newdata.longitude,
903
0
                 session->newdata.altHAE, session->newdata.altMSL);
904
0
        GPSD_LOG(debug_base, &session->context->errout,
905
0
                 "SiRF V: MND 67,1 speed %.2f track %.2f climb %.2f "
906
0
                 "heading_rate %d\n",
907
0
                 session->newdata.speed, session->newdata.track,
908
0
                 session->newdata.climb, heading_rate);
909
0
        GPSD_LOG(debug_base, &session->context->errout,
910
0
                 "SiRF V: MND 67,1 time_bias %d time_accuracy %u "
911
0
                 "time_source %u\n",
912
0
                 time_bias, time_accuracy, time_source);
913
0
        GPSD_LOG(debug_base, &session->context->errout,
914
0
                 "SiRF V: MND 67,1 distance_travel %u "
915
0
                 "distance_travel_error %d\n",
916
0
                 distance_travel, distance_travel_error);
917
0
        GPSD_LOG(debug_base, &session->context->errout,
918
0
                 "SiRF V: MND 67,1 clk_bias %.2f clk_bias_error %u\n",
919
0
                 clk_bias / 100.0, clk_bias_error);
920
0
        GPSD_LOG(debug_base, &session->context->errout,
921
0
                 "SiRF V: MND 67,1 clk_offset %d clk_offset_error %u\n",
922
0
                 clk_offset, clk_offset_error);
923
0
        GPSD_LOG(debug_base, &session->context->errout,
924
0
                 "SiRF V: MND 67,1 ehpe %d epv %.2f eps %.2f epd %.2f "
925
0
                 "num_svs_in_sol %u\n",
926
0
                 ehpe, session->newdata.epv, session->newdata.eps,
927
0
                 session->newdata.epd, num_svs_in_sol);
928
0
        GPSD_LOG(debug_base, &session->context->errout,
929
0
                 "SiRF V: MND 67,1 sv_list_1 %08x sv_list_2 %08x s"
930
0
                 "v_list_3 %08x\n",
931
0
                 sv_list_1, sv_list_2, sv_list_3);
932
0
        GPSD_LOG(debug_base, &session->context->errout,
933
0
                 "SiRF V: MND 67,1 sv_list_4 %08x sv_list_5 %08x "
934
0
                 "add_info %08x\n",
935
0
                 sv_list_4, sv_list_5, additional_info);
936
0
    }
937
938
9
    return mask;
939
9
}
940
941
/* Multiconstellation Navigation Data response MID 67,16 (0x43)
942
 * this replaces the deprecated MID 41 */
943
static gps_mask_t sirf_msg_67_16(struct gps_device_t *session,
944
                                 unsigned char *buf, size_t len)
945
241
{
946
241
    gps_mask_t mask = 0;
947
241
    uint32_t gps_tow = 0;
948
241
    uint32_t gps_tow_sub_ms = 0;
949
241
    uint16_t gps_week = 0;
950
241
    timespec_t gps_tow_ns = {0};
951
241
    timespec_t now = {0};
952
241
    int16_t time_bias = 0;
953
241
    uint8_t time_accuracy = 0;
954
241
    uint8_t time_source = 0;
955
241
    uint8_t msg_info = 0;
956
241
    uint8_t num_of_sats = 0;
957
241
    unsigned int sat_num;
958
241
    int st;                    // index into skyview
959
960
241
    if (18 > len) {
961
        // zero sats is len == 18
962
74
        GPSD_LOG(LOG_WARN, &session->context->errout,
963
74
                 "SiRF V: MID 67,16 runt packet. Len %lu\n",
964
74
                 (unsigned long)len);
965
74
        return 0;
966
74
    }
967
968
167
    if (198 < len) {
969
        // max sats per message is 15
970
4
        GPSD_LOG(LOG_WARN, &session->context->errout,
971
4
                 "SiRF V: MID 67,16 packet too big. Len %lu\n",
972
4
                 (unsigned long)len);
973
4
        return 0;
974
4
    }
975
976
163
    GPSD_LOG(LOG_PROG, &session->context->errout,
977
163
             "SiRF V: MID 67,16 Multiconstellation Satellite Data Response\n");
978
979
163
    gps_week = getbeu16(buf, 2);
980
163
    gps_tow = getbeu32(buf, 4) / 1000;
981
    // get ms part, convert to ns
982
163
    gps_tow_sub_ms = 1000000 * (getbeu32(buf, 4) % 1000);
983
163
    gps_tow_sub_ms += getbeu32(buf, 8);    // add in the ns
984
163
    gps_tow_ns.tv_sec = gps_tow;
985
163
    gps_tow_ns.tv_nsec = gps_tow_sub_ms;
986
163
    session->newdata.time = gpsd_gpstime_resolv(session, gps_week, gps_tow_ns);
987
163
    session->gpsdata.skyview_time = session->newdata.time;
988
163
    time_bias = getbes16(buf, 12);
989
    // time_accuracy is an odd 8 bit float
990
163
    time_accuracy = getub(buf, 14);
991
163
    time_source = getub(buf, 15);
992
163
    msg_info = getub(buf, 16);
993
163
    if (0 == (msg_info & 0x0f)) {
994
        // WTF?
995
1
        return 0;
996
1
    }
997
162
    if (1 == (msg_info & 0x0f)) {
998
        // first set, zero the sats
999
13
        gpsd_zero_satellites(&session->gpsdata);
1000
13
    }
1001
162
    st = ((msg_info & 0x0f) - 1) * 15;
1002
162
    num_of_sats = getub(buf, 17);
1003
    // got time now
1004
162
    mask |= TIME_SET;
1005
1006
    // skip all the debug pushing and popping, unless needed
1007
162
    if (LOG_IO <= session->context->errout.debug) {
1008
        /* coerce time_t to long to placate older OS, like 32-bit FreeBSD,
1009
         * where time_t is int */
1010
0
        char ts_buf[TIMESPEC_LEN];
1011
1012
0
        GPSD_LOG(LOG_IO, &session->context->errout,
1013
0
             "SiRF V: MID 67,16 GPS Week %d, tow %d.%03d, time %s\n",
1014
0
             gps_week, gps_tow, gps_tow_sub_ms,
1015
0
             timespec_str(&now, ts_buf, sizeof(ts_buf)));
1016
0
        GPSD_LOG(LOG_IO, &session->context->errout,
1017
0
             "SiRF V: MID 67,16 Time bias: %u ns, accuracy %#02x, source %u, "
1018
0
             "msg_info %#02x, sats %u\n",
1019
0
             time_bias, time_accuracy, time_source, msg_info,
1020
0
             num_of_sats);
1021
0
    }
1022
1023
    // used?
1024
1025
162
    if (MAXCHANNELS < num_of_sats) {
1026
        // shut up coverity
1027
36
        num_of_sats = MAXCHANNELS;
1028
36
    }
1029
162
    session->gpsdata.satellites_visible = num_of_sats;
1030
1031
    // now decode the individual sat data
1032
    /* FIXME: num_of_sats is total sats tracked, not the number of sats
1033
     * in this message, so this looks wrong? */
1034
667
    for (sat_num = 0; sat_num < num_of_sats; sat_num++) {
1035
659
        unsigned offset;
1036
659
        uint16_t sat_info;
1037
659
        uint16_t other_info;
1038
659
        unsigned char gnssId_sirf;
1039
659
        unsigned char gnssId;
1040
659
        unsigned char svId;
1041
659
        short PRN;
1042
659
        double azimuth;
1043
659
        double elevation;
1044
659
        short avg_cno;
1045
659
        double ss;
1046
659
        uint32_t status;
1047
1048
659
        offset = 18 + (sat_num * 12);
1049
659
        if (offset >= len) {
1050
            // end of this message
1051
154
            break;
1052
154
        }
1053
505
        sat_info = getbeu16(buf, offset);
1054
505
        if (0 == sat_info) {
1055
            // empty slot, ignore
1056
20
            continue;
1057
20
        }
1058
1059
        /* 0 = GPS/QZSS
1060
           1 = SBAS
1061
           2 = GLONASS
1062
           3 = Galileo
1063
           4 = BDS
1064
         */
1065
485
        gnssId_sirf = sat_info >> 13;
1066
485
        svId = sat_info & 0x0ff;
1067
485
        other_info = (sat_info >> 8) & 0x1f;
1068
        /* make up a PRN based on gnssId:svId, using table 4-55
1069
         * from (CS-303979-SP-9) SiRFstarV OSP Extensions
1070
         * Note: the Qualcomm doc is very vague
1071
         */
1072
485
        switch (gnssId_sirf) {
1073
166
        case 0:
1074
            /* GPS, 1-32 maps to 1-32
1075
             * 173 to 182: QZSS IMES
1076
             * 183 to 187: QZSS SAIF
1077
             * 193 to 202: QZSS */
1078
166
            if ((173 <= svId) &&
1079
83
                (182 >= svId)){
1080
                // IMES
1081
21
                gnssId = 4;
1082
21
                PRN = svId;
1083
21
                svId -= 172;
1084
145
            } else if ((193 <= svId) &&
1085
44
                       (202 >= svId)){
1086
                // QZSS
1087
21
                gnssId = 5;
1088
21
                PRN = svId;
1089
21
                svId -= 192;
1090
124
            } else {
1091
                // GPS, or??
1092
124
                gnssId = 0;
1093
124
                PRN = svId;
1094
124
            }
1095
166
            break;
1096
57
        case 1:
1097
            // SBAS, 120-158 maps to 120-158
1098
57
            if (120 > svId ||
1099
39
                158 < svId) {
1100
                // skip bad svId
1101
39
                continue;
1102
39
            }
1103
18
            gnssId = 1;
1104
18
            PRN = svId;
1105
18
            break;
1106
61
        case 2:
1107
            // GLONASS, 1-32 maps to 65-96
1108
61
            if (1 > svId) {
1109
                // skip bad svId
1110
18
                continue;
1111
18
            }
1112
43
            if (32 < svId) {
1113
                // skip bad svId
1114
24
                continue;
1115
24
            }
1116
19
            gnssId = 6;
1117
19
            PRN = svId + 64;
1118
19
            break;
1119
64
        case 3:
1120
            // Galileo, 1-36 maps to 211-246
1121
64
            if (1 > svId) {
1122
                // skip bad svId
1123
18
                continue;
1124
18
            }
1125
46
            if (37 < svId) {
1126
                // skip bad svId
1127
18
                continue;
1128
18
            }
1129
28
            gnssId = 2;
1130
28
            PRN = svId + 210;
1131
28
            break;
1132
97
        case 4:
1133
            // BeiDou, 1-37 maps to 159-163,33-64
1134
97
            if (1 > svId) {
1135
                // skip bad svId
1136
18
                continue;
1137
79
            } else if (6 > svId) {
1138
                // 1-5 maps to 159-163
1139
31
                PRN = svId + 158;
1140
48
            } else if (37 < svId) {
1141
                // skip bad svId
1142
23
                continue;
1143
25
            } else {
1144
                // 6-37 maps to 33-64
1145
25
                PRN = svId + 27;
1146
25
            }
1147
56
            gnssId = 3;
1148
56
            break;
1149
40
        default:
1150
            // Huh?  Skip bad gnssId
1151
40
            continue;
1152
485
        }
1153
1154
        // note tenths in az and el
1155
287
        azimuth = (double)getbeu16(buf, offset + 2) / 10.0;
1156
        // what, no negative elevation?
1157
287
        elevation = (double)getbeu16(buf, offset + 4) / 10.0;
1158
287
        avg_cno = getbeu16(buf, offset + 6);
1159
287
        ss = (double)avg_cno / 10.0;
1160
287
        status = getbeu32(buf, offset + 8);
1161
287
        if ((0 == avg_cno) &&
1162
122
            (0 >= elevation) &&
1163
45
            (0 >= azimuth)) {
1164
            // null data, skip it
1165
21
            continue;
1166
21
        }
1167
1168
266
        session->gpsdata.skyview[st].PRN = PRN;
1169
266
        session->gpsdata.skyview[st].svid = svId;
1170
266
        session->gpsdata.skyview[st].gnssid = gnssId;
1171
266
        session->gpsdata.skyview[st].azimuth = azimuth;
1172
266
        session->gpsdata.skyview[st].elevation = elevation;
1173
266
        session->gpsdata.skyview[st].ss = ss;
1174
266
        if (0x08000 == (status & 0x08000)) {
1175
75
            session->gpsdata.skyview[st].used = true;
1176
75
        }
1177
266
        GPSD_LOG(LOG_IO, &session->context->errout,
1178
266
                 "SiRF V: MID 67,16 sat_info %04x gnssId %u svId %3u "
1179
266
                 "o %2u PRN %3u az %4.1f "
1180
266
                 "el %5.1f ss %5.1f\n",
1181
266
                 sat_info, gnssId, svId, other_info, PRN, azimuth,
1182
266
                 elevation, ss);
1183
266
        st++;
1184
266
        if (st >= MAXCHANNELS) {
1185
            // filled up skyview
1186
0
            break;
1187
0
        }
1188
266
    }
1189
162
    if ((msg_info >> 4) == (msg_info & 0x0f)) {
1190
        // got all the sats
1191
36
        mask |= SATELLITE_SET;
1192
36
    }
1193
162
    return mask;
1194
162
}
1195
1196
/* Multiconstellation Navigation Data response MID 67 (0x43)
1197
 * this replaces the deprecated MID 41 */
1198
static gps_mask_t sirf_msg_67(struct gps_device_t *session,
1199
                              unsigned char *buf, size_t len)
1200
570
{
1201
570
    gps_mask_t mask = 0;
1202
1203
570
    if (2 > len) {
1204
157
        GPSD_LOG(LOG_INF, &session->context->errout,
1205
157
                 "SiRF: MID (0x43) runt len %zu\n", len);
1206
157
        return 0;
1207
157
    }
1208
1209
413
    switch (buf[1]) {
1210
103
    case 1:
1211
103
        return sirf_msg_67_1(session, buf, len);
1212
241
    case 16:
1213
241
        return sirf_msg_67_16(session, buf, len);
1214
69
    default:
1215
69
        GPSD_LOG(LOG_PROG, &session->context->errout,
1216
413
                 "SiRF V: unused MID 67 (0x43), SID: %d, len %ld\n", buf[1],
1217
413
                 (long)len);
1218
413
    }
1219
69
    return mask;
1220
413
}
1221
1222
// MID_QUERY_RESP MID 81 (0x51)
1223
static gps_mask_t sirf_msg_qresp(struct gps_device_t *session,
1224
                                 unsigned char *buf, size_t len)
1225
202
{
1226
1227
202
    if (3 > len) {
1228
135
        GPSD_LOG(LOG_INF, &session->context->errout,
1229
135
                 "SiRF: MID (0x51) runt len %zu\n", len);
1230
135
        return 0;
1231
135
    }
1232
1233
67
    GPSD_LOG(LOG_PROG, &session->context->errout,
1234
67
             "SiRF IV: unused MID_QUERY_RESP 0x51 (81), Q MID: %d, "
1235
67
             "SID: %d Elen: %d\n",
1236
67
             buf[1], buf[2], buf[3]);
1237
67
    return 0;
1238
202
}
1239
1240
// SBAS 50 (0x32)
1241
static gps_mask_t sirf_msg_sbas(struct gps_device_t *session,
1242
                                unsigned char *buf, size_t len)
1243
216
{
1244
216
    unsigned char prn, mode, timeout, flags;
1245
1246
216
    if (13 != len) {
1247
137
        GPSD_LOG(LOG_INF, &session->context->errout,
1248
137
                 "SiRF: MID (0x32) runt len %zu\n", len);
1249
137
        return 0;
1250
137
    }
1251
1252
79
    prn = buf[1];
1253
79
    mode = buf[2];
1254
79
    timeout = buf[3];
1255
79
    flags = buf[4];
1256
79
    GPSD_LOG(LOG_PROG, &session->context->errout,
1257
79
             "SiRF: SBAS 0x32 PRN %u mode %u timeout %u flags x%x\n",
1258
79
             prn, mode, timeout, flags);
1259
79
    return 0;
1260
216
}
1261
1262
// Statistics Channel MID 225 (0xe1)
1263
static gps_mask_t sirf_msg_stats(struct gps_device_t *session,
1264
                                 unsigned char *buf, size_t len)
1265
722
{
1266
722
    const char *definition = "Unknown";
1267
722
    char output[255] = "unused";
1268
722
    uint16_t ttff_reset;
1269
722
    uint16_t ttff_aid;
1270
722
    uint16_t ttff_nav;
1271
1272
722
    if (2 > len) {
1273
146
        GPSD_LOG(LOG_INF, &session->context->errout,
1274
146
                 "SiRF: MID (0xe1) runt len %zu\n", len);
1275
146
        return 0;
1276
146
    }
1277
1278
576
    switch (buf[1]) {
1279
68
    case 6:
1280
68
        definition = "SSB_SIRF_STATS 6";
1281
68
        ttff_reset = getbeu16(buf, 2);
1282
68
        ttff_aid = getbeu16(buf, 4);
1283
68
        ttff_nav = getbeu16(buf, 6);
1284
68
        (void)snprintf(output, sizeof(output),
1285
68
                       "ttff reset %.1f, aid %.1f nav %.1f",
1286
68
                       ttff_reset * 0.1, ttff_aid * 0.1, ttff_nav * 0.1);
1287
68
        break;
1288
70
    case 7:
1289
70
        definition = "SSB_SIRF_STATS 7";
1290
70
        ttff_reset = getbeu16(buf, 2);
1291
70
        ttff_aid = getbeu16(buf, 4);
1292
70
        ttff_nav = getbeu16(buf, 6);
1293
70
        (void)snprintf(output, sizeof(output),
1294
70
                       "ttff reset %.1f, aid %.1f nav %.1f",
1295
70
                       ttff_reset * 0.1, ttff_aid * 0.1, ttff_nav * 0.1);
1296
70
        break;
1297
67
    case 32:
1298
67
        definition = "SIRF_MSG_SSB_DL_COMPAT_REC_OUT ";
1299
67
        break;
1300
67
    case 33:
1301
67
        definition = "SIRF_MSG_SSB_DL_OUT_TERM";
1302
67
        break;
1303
67
    case 34:
1304
67
        definition = "SIRF_MSG_SSB_DL_STATUS_OUT";
1305
67
        break;
1306
88
    case 35:
1307
88
        definition = "SIRF_MSG_SSB_SIRF_INTERNAL_OUT";
1308
88
        break;
1309
81
    case 65:
1310
81
        definition = "SIRF_MSG_SSB_EE_SEA_PROVIDE_EPH_EXT";
1311
81
        break;
1312
68
    default:
1313
68
        break;
1314
576
    }
1315
1316
576
    GPSD_LOG(LOG_PROG, &session->context->errout,
1317
576
             "SiRF IV: MID 225 (0xe1), SID: %d (%s)%s\n",
1318
576
             buf[1], definition, output);
1319
1320
576
    return 0;
1321
576
}
1322
1323
// MID_TCXO_LEARNING_OUT MID 93 (0x5d)
1324
static gps_mask_t sirf_msg_tcxo(struct gps_device_t *session,
1325
                                unsigned char *buf, size_t len)
1326
1.19k
{
1327
1.19k
    const char *definition = "Unknown";
1328
1.19k
    uint32_t gps_tow = 0;
1329
1.19k
    uint16_t gps_week = 0;
1330
1.19k
    timespec_t gps_tow_ns = {0};
1331
1.19k
    char output[255] = "";
1332
1.19k
    timespec_t now = {0};
1333
1.19k
    gps_mask_t mask = 0;
1334
1.19k
    unsigned int time_status = 0;
1335
1.19k
    int clock_offset = 0;
1336
1.19k
    unsigned int temp = 0;
1337
1338
1.19k
    if (2 > len) {
1339
134
        GPSD_LOG(LOG_INF, &session->context->errout,
1340
134
                 "SiRF: MID (0x5d) runt len %zu\n", len);
1341
134
        return 0;
1342
134
    }
1343
1344
1.06k
    switch (buf[1]) {
1345
67
    case 1:
1346
67
        definition = "CLOCK_MODEL_DATA_BASE_OUT";
1347
67
        break;
1348
72
    case 2:
1349
72
        definition = "TEMPERATURE_TABLE";
1350
72
        break;
1351
67
    case 4:
1352
67
        definition = "TEMP_RECORDER_MESSAGE";
1353
67
        break;
1354
67
    case 5:
1355
67
        definition = "EARC";
1356
67
        break;
1357
67
    case 6:
1358
67
        definition = "RTC_ALARM";
1359
67
        break;
1360
111
    case 7:
1361
111
        definition = "RTC_CAL";
1362
111
        break;
1363
67
    case 8:
1364
67
        definition = "MPM_ACQUIRED";
1365
67
        break;
1366
72
    case 9:
1367
72
        definition = "MPM_SEARCHES";
1368
72
        break;
1369
68
    case 10:
1370
68
        definition = "MPM_PREPOS";
1371
68
        break;
1372
67
    case 11:
1373
67
        definition = "MICRO_NAV_MEASUREMENT";
1374
67
        break;
1375
67
    case 12:
1376
67
        definition = "TCXO_UNCEARTAINTY";
1377
67
        break;
1378
67
    case 13:
1379
67
        definition = "SYSTEM_TIME_STAMP";
1380
67
        break;
1381
72
    case 18:
1382
72
        if (26 > len) {
1383
70
            GPSD_LOG(LOG_PROG, &session->context->errout,
1384
70
                     "SiRF IV: TCXO 0x5D (93), SID: %d BAD len %zd\n",
1385
70
                     buf[1], len);
1386
70
            return 0;
1387
70
        }
1388
1389
2
        definition = "SIRF_MSG_SSB_XO_TEMP_REC_VALUE";
1390
2
        gps_tow = getbeu32(buf, 2);
1391
2
        gps_week = getbeu16(buf, 6);
1392
2
        time_status = getub(buf, 8);
1393
2
        clock_offset = getsb(buf, 9);   // looks like leapseconds?
1394
2
        temp = getub(buf, 22);
1395
2
        gps_tow_ns.tv_sec = gps_tow / 100;
1396
2
        gps_tow_ns.tv_nsec = (gps_tow % 100) * 10000000LL;
1397
2
        session->newdata.time = gpsd_gpstime_resolv(session, gps_week,
1398
2
                                                    gps_tow_ns);
1399
1400
        // skip all the debug pushing and popping, unless needed
1401
2
        if (LOG_PROG <= session->context->errout.debug) {
1402
            /* coerce time_t to long to placate older OS, like 32-bit FreeBSD,
1403
             * where time_t is int */
1404
0
            (void)snprintf(output, sizeof(output),
1405
0
                           ", GPS Week %u, tow %u, time %lld, time_status %u "
1406
0
                           "ClockOffset %d, Temp %.1f",
1407
0
                           gps_week, gps_tow, (long long)now.tv_sec,
1408
0
                           time_status,
1409
0
                           clock_offset, temp * 0.54902);
1410
0
        }
1411
1412
2
        if (7 == (time_status & 7)) {
1413
1
            mask |= TIME_SET;
1414
1
        }
1415
2
        break;
1416
134
    default:
1417
134
        break;
1418
1.06k
    }
1419
1420
995
    GPSD_LOG(LOG_PROG, &session->context->errout,
1421
995
             "SiRF IV: TCXO 0x5D (93), SID: %d (%s)%s\n",
1422
995
             buf[1], definition, output);
1423
1424
995
    return mask;
1425
1.06k
}
1426
1427
/* Software Version String MID 6
1428
 * response to Poll Software Version MID 132 */
1429
static gps_mask_t sirf_msg_swversion(struct gps_device_t *session,
1430
                                     unsigned char *buf, size_t len)
1431
1.74k
{
1432
1.74k
    double fv;
1433
1.74k
    unsigned char *cp;
1434
1435
1.74k
    if (1 > len) {
1436
0
        GPSD_LOG(LOG_INF, &session->context->errout,
1437
0
                 "SiRF: MID (0x06) runt len %zu\n", len);
1438
0
        return 0;
1439
0
    }
1440
1441
1.74k
    if ((3 < len) &&
1442
546
        (len == (unsigned int)(buf[1] + buf[2] + 3))) {
1443
        // new style message, Version 4+, max 162 bytes
1444
307
        (void)strlcpy(session->subtype, (char *)buf + 3,
1445
307
                      sizeof(session->subtype));
1446
307
        (void)strlcat(session->subtype, ";", sizeof(session->subtype));
1447
307
        (void)strlcat(session->subtype, (char *)buf + 3 + buf[1],
1448
307
                      sizeof(session->subtype));
1449
307
        session->driver.sirf.driverstate |= SIRF_GE_232;
1450
        // FIXME: this only finding major version, not minor version
1451
973
        for (cp = buf+1; *cp != (unsigned char)'\0' &&
1452
826
                         0 == isdigit(*cp); cp++) {
1453
666
            continue;
1454
666
        }
1455
307
        fv = safe_atof((const char *)cp);
1456
1.43k
    } else {
1457
        // old style, version 3 and below
1458
1459
1.43k
        (void)strlcpy(session->subtype, (char *)buf + 1,
1460
1.43k
                      sizeof(session->subtype));
1461
1462
3.11k
        for (cp = buf+1; *cp != (unsigned char)'\0' &&
1463
1.93k
                         0 == isdigit(*cp); cp++) {
1464
1.68k
            continue;
1465
1.68k
        }
1466
1.43k
        fv = safe_atof((const char *)cp);
1467
1.43k
        if (231 > fv) {
1468
212
            session->driver.sirf.driverstate |= SIRF_LT_231;
1469
212
            if (200 < fv) {
1470
1
                sirfbin_mode(session, 0);
1471
1
            }
1472
1.22k
        } else if (232 > fv) {
1473
1
            session->driver.sirf.driverstate |= SIRF_EQ_231;
1474
1.22k
        } else {
1475
1.22k
            session->driver.sirf.driverstate |= SIRF_GE_232;
1476
1.22k
        }
1477
1.43k
        if (strstr((char *)(buf + 1), "ES")) {
1478
2
            GPSD_LOG(LOG_INF, &session->context->errout,
1479
2
                     "SiRF: Firmware has XTrac capability\n");
1480
2
        }
1481
1.43k
    }
1482
1.74k
    GPSD_LOG(LOG_PROG, &session->context->errout,
1483
1.74k
             "SiRF: FV 0x06: fv: %0.2f, driverstate %0x "
1484
1.74k
             "subtype '%s' len %lu buf1 %u buf2 %u\n",
1485
1.74k
             fv, session->driver.sirf.driverstate,
1486
1.74k
             session->subtype, (long)len, buf[1], buf[2]);
1487
1.74k
    session->driver.sirf.time_seen = 0;
1488
1.74k
    return DEVICEID_SET;
1489
1.74k
}
1490
1491
/* subframe data MID 8
1492
 * Use Message ID 14 and 15 instead?
1493
 * Use Message ID 56, Sub ID 5, instead? */
1494
static gps_mask_t sirf_msg_navdata(struct gps_device_t *session,
1495
                                   unsigned char *buf, size_t len)
1496
145
{
1497
145
    unsigned int i, chan, svid;
1498
145
    uint32_t words[10];
1499
145
    const unsigned int numwords = 10;
1500
1501
145
    if (43 != len) {
1502
140
        GPSD_LOG(LOG_INF, &session->context->errout,
1503
140
                 "SiRF: MID (0x08) runt len %zu\n", len);
1504
140
        return 0;
1505
140
    }
1506
1507
5
    chan = (unsigned int)getub(buf, 1);
1508
5
    svid = (unsigned int)getub(buf, 2);
1509
1510
55
    for (i = 0; i < numwords; i++) {
1511
        // packing undocumented...
1512
50
        words[i] = (uint32_t)getbeu32(buf, 4 * i + 3);
1513
50
    }
1514
1515
5
    GPSD_LOG(LOG_DATA, &session->context->errout,
1516
5
             "SiRF: NavData chan %u svid %u\n", chan, svid);
1517
1518
    // SiRF recommends at least 57600 for SiRF IV nav data
1519
5
    if (57600 > session->gpsdata.dev.baudrate) {
1520
        // some USB are also too slow, no way to tell which ones
1521
5
        if (session->context->readonly ||
1522
4
            session->context->passive) {
1523
            // FIXME: duplicated in gpsd_internet_subframe_raw()
1524
2
            GPSD_LOG(LOG_WARN, &session->context->errout,
1525
2
                     "WARNING: SiRF: link too slow.\n");
1526
3
        } else {
1527
3
            GPSD_LOG(LOG_WARN, &session->context->errout,
1528
3
                     "WARNING: SiRF: link too slow, disabling subframes.\n");
1529
3
            (void)sirf_write(session, disablesubframe, sizeof(disablesubframe));
1530
3
        }
1531
5
    }
1532
1533
5
    return gpsd_interpret_subframe_raw(session, GNSSID_GPS, 0, svid, words,
1534
5
                                       numwords);
1535
145
}
1536
1537
// max channels allowed in old MID 4 SiRF format
1538
234
#define SIRF_CHANNELS   12
1539
1540
/* decode Measured Tracker Data response ID 4 (0x04)
1541
 * deprecated on Sirfstar V, use MID 67,16 instead */
1542
static gps_mask_t sirf_msg_svinfo(struct gps_device_t *session,
1543
                                  unsigned char *buf, size_t len)
1544
156
{
1545
156
    int st, i, j, nsv;
1546
156
    uint32_t hsec;        // TOW in hundredths of seconds
1547
156
    timespec_t ts_tow;
1548
156
    char ts_buf[TIMESPEC_LEN];
1549
156
    gps_mask_t mask = 0;
1550
1551
156
    if (188 != len) {
1552
138
        GPSD_LOG(LOG_INF, &session->context->errout,
1553
138
                 "SiRF: MID (0x04) runt len %zu\n", len);
1554
138
        return 0;
1555
138
    }
1556
1557
18
    hsec = getbeu32(buf, 3);
1558
18
    ts_tow.tv_sec = hsec / 100;
1559
18
    ts_tow.tv_nsec = (long)((hsec % 100) * 10000000LL);
1560
18
    session->gpsdata.skyview_time = gpsd_gpstime_resolv(session,
1561
18
        (unsigned short)getbes16(buf, 1), ts_tow);
1562
1563
18
    gpsd_zero_satellites(&session->gpsdata);
1564
234
    for (i = st = nsv = 0; i < SIRF_CHANNELS; i++) {
1565
216
        int cn;
1566
216
        int off = 8 + 15 * i;
1567
216
        bool good;
1568
216
        short prn = (short)getub(buf, off);
1569
216
        unsigned short stat = (unsigned short)getbeu16(buf, off + 3);
1570
1571
216
        session->gpsdata.skyview[st].PRN = prn;
1572
216
        session->gpsdata.skyview[st].svid = prn;
1573
216
        if (120 <= prn &&
1574
106
            158 >= prn) {
1575
            // SBAS
1576
49
            session->gpsdata.skyview[st].gnssid = 1;
1577
167
        } else {
1578
            // GPS
1579
167
            session->gpsdata.skyview[st].gnssid = 0;
1580
167
        }
1581
216
        session->gpsdata.skyview[st].azimuth =
1582
216
            (double)(((unsigned)getub(buf, off + 1) * 3.0) / 2.0);
1583
216
        session->gpsdata.skyview[st].elevation =
1584
216
            (double)((unsigned)getub(buf, off + 2) / 2.0);
1585
216
        cn = 0;
1586
2.37k
        for (j = 0; j < 10; j++) {
1587
2.16k
            cn += (int)getub(buf, off + 5 + j);
1588
2.16k
        }
1589
1590
216
        session->gpsdata.skyview[st].ss = (float)(cn / 10.0);
1591
216
        session->gpsdata.skyview[st].used = (bool)(stat & 0x01);
1592
216
        good = session->gpsdata.skyview[st].PRN != 0 &&
1593
162
            session->gpsdata.skyview[st].azimuth != 0 &&
1594
135
            session->gpsdata.skyview[st].elevation != 0;
1595
#ifdef __UNUSED__
1596
        GPSD_LOG(LOG_PROG, &session->context->errout,
1597
                 "SiRF: MTD 4 PRN=%2d El=%3.2f Az=%3.2f ss=%3d stat=%04x %c\n",
1598
                 prn,
1599
                 getub(buf, off + 2) / 2.0,
1600
                 (getub(buf, off + 1) * 3) / 2.0,
1601
                 cn / 10, stat, good ? '*' : ' ');
1602
#endif /* UNUSED */
1603
216
        if (good != 0) {
1604
115
            st += 1;
1605
115
            if (stat & 0x01) {
1606
74
                nsv++;
1607
74
            }
1608
115
        }
1609
216
    }
1610
18
    if (MAXCHANNELS < st) {
1611
0
        GPSD_LOG(LOG_WARN, &session->context->errout,
1612
0
                "SiRF: MTD 4 too many satellites %d\n", st);
1613
0
        st = MAXCHANNELS;
1614
0
    }
1615
18
    session->gpsdata.satellites_visible = st;
1616
18
    session->gpsdata.satellites_used = nsv;
1617
    // mark SBAS sats in use if SBAS was in use as of the last MID 27
1618
133
    for (i = 0; i < st; i++) {
1619
115
        int prn = session->gpsdata.skyview[i].PRN;
1620
115
        if (120 <= prn &&
1621
78
            158 >= prn &&
1622
35
            STATUS_DGPS == session->lastfix.status &&
1623
0
            SIRF_DGPS_SOURCE_SBAS == session->driver.sirf.dgps_source) {
1624
            /* used does not seem right, DGPS means got the correction
1625
             * data, not that the geometry was improved... */
1626
0
            session->gpsdata.skyview[i].used = true;
1627
0
        }
1628
115
    }
1629
18
    if (3 <= st) {
1630
        // SiRF says if 3 sats in view the time is good
1631
13
        mask |= NTPTIME_IS;
1632
13
        GPSD_LOG(LOG_PROG, &session->context->errout,
1633
13
                 "SiRF: MTD 0x04 NTPD valid time seen %#02x time %s, "
1634
13
                 "leap:%d\n",
1635
13
                 session->driver.sirf.time_seen,
1636
13
                 timespec_str(&session->gpsdata.skyview_time, ts_buf,
1637
13
                              sizeof(ts_buf)),
1638
13
                 session->context->leap_seconds);
1639
13
    }
1640
18
    GPSD_LOG(LOG_DATA, &session->context->errout,
1641
18
             "SiRF: MTD 0x04: visible=%d mask={SATELLITE}\n",
1642
18
             session->gpsdata.satellites_visible);
1643
18
    return mask | SATELLITE_SET;
1644
156
}
1645
1646
// return NTP time-offset fudge factor for this device
1647
// FIXME: this is pointless...
1648
static double sirf_time_offset(struct gps_device_t *session)
1649
0
{
1650
0
    double retval = 0;
1651
1652
    // we need to have seen UTC time with a valid leap-year offset
1653
0
    if (0 != (session->driver.sirf.time_seen & TIME_SEEN_UTC_2)) {
1654
0
        retval = NAN;
1655
0
    } else if ((unsigned char)52 == session->driver.sirf.lastid) {
1656
        // the PPS time message
1657
0
        retval                      = 0.3;
1658
0
    } else if ((unsigned char)98 == session->driver.sirf.lastid) {
1659
        // u-blox EMND message
1660
0
        retval                      = 0.570;
1661
0
    } else if ((unsigned char)41 == session->driver.sirf.lastid) {
1662
        // geodetic-data message
1663
0
        retval = 0.570;
1664
0
    } else if ((unsigned char)2 == session->driver.sirf.lastid) {
1665
        // the Navigation Solution message
1666
0
        if (SOURCE_USB == session->sourcetype ||
1667
0
            SOURCE_ACM == session->sourcetype) {
1668
0
            retval = 0.640;     // USB or ACM, expect +/- 50mS jitter
1669
0
        } else {
1670
0
            switch (session->gpsdata.dev.baudrate) {
1671
0
            default:
1672
0
                retval = 0.704;   // WAG
1673
0
                break;
1674
0
            case 4800:
1675
0
                retval = 0.704;   // fudge valid at 4800bps
1676
0
                break;
1677
0
            case 9600:
1678
0
                retval = 0.688;
1679
0
                break;
1680
0
            case 19200:
1681
0
                retval = 0.484;
1682
0
                break;
1683
0
            case 38400:
1684
0
                retval = 0.845;    //  0.388; ??
1685
0
                break;
1686
0
            }
1687
0
        }
1688
0
    }
1689
1690
0
    return retval;
1691
0
}
1692
1693
// Measured Navigation Data Out MND ID 2 (0x02)
1694
static gps_mask_t sirf_msg_navsol(struct gps_device_t *session,
1695
                                  unsigned char *buf, size_t len)
1696
294
{
1697
294
    unsigned short navtype;
1698
294
    unsigned short nav_mode2;
1699
294
    unsigned short gps_week;
1700
294
    uint32_t iTOW;
1701
294
    timespec_t tow;
1702
294
    gps_mask_t mask = 0;
1703
294
    char ts_buf[TIMESPEC_LEN];
1704
294
    double d;
1705
1706
    // later versions are 47 bytes long
1707
294
    if (41 > len) {
1708
135
        GPSD_LOG(LOG_INF, &session->context->errout,
1709
135
                 "SiRF: MID (0x02) runt len %zu\n", len);
1710
135
        return 0;
1711
135
    }
1712
1713
    /*
1714
     * A count of satellites used is an unsigned byte at offset 28
1715
     * and an array of unsigned bytes listing satellite PRNs used
1716
     * in this fix begins at offset 29, but we don't use either because
1717
     * in JSON the used bits are reported in the SKY sentence;
1718
     * we get that data from the svinfo packet.
1719
     */
1720
    // position/velocity is bytes 1-18
1721
    // ecef position  is in meters
1722
159
    session->newdata.ecef.x = (double)getbes32(buf, 1);
1723
159
    session->newdata.ecef.y = (double)getbes32(buf, 5);
1724
159
    session->newdata.ecef.z = (double)getbes32(buf, 9);
1725
    // ecef velocity is in meters/second * 8
1726
159
    session->newdata.ecef.vx = (double)getbes16(buf, 13) / 8.0;
1727
159
    session->newdata.ecef.vy = (double)getbes16(buf, 15) / 8.0;
1728
159
    session->newdata.ecef.vz = (double)getbes16(buf, 17) / 8.0;
1729
1730
159
    mask |= ECEF_SET | VECEF_SET;
1731
1732
    // fix status is byte 19
1733
159
    navtype = (unsigned short)getub(buf, 19);
1734
159
    session->newdata.mode = MODE_NO_FIX;
1735
159
    if (0 == (navtype & 0x07)) {
1736
        // no fix
1737
35
        session->newdata.status = STATUS_UNK;
1738
124
    } else if (7 == (navtype & 0x07)) {
1739
36
        session->newdata.status = STATUS_DR;
1740
88
    } else if (0x80 == (navtype & 0x80)) {
1741
40
        session->newdata.status = STATUS_DGPS;
1742
48
    } else {
1743
48
        session->newdata.status = STATUS_GPS;
1744
48
    }
1745
    // byte 20 is HDOP, or PDOP!
1746
159
    d = (double)getub(buf, 20) / 5.0;
1747
159
    if (4 == (navtype & 0x07) ||
1748
123
        6 == (navtype & 0x07)) {
1749
73
        session->newdata.mode = MODE_3D;
1750
73
        session->gpsdata.dop.pdop = d;
1751
73
        mask |= DOP_SET;
1752
86
    } else if (0 != session->newdata.status) {
1753
51
        session->newdata.mode = MODE_2D;
1754
51
        session->gpsdata.dop.hdop = d;
1755
51
        mask |= DOP_SET;
1756
51
    }
1757
    // byte 21 is nav_mode2, not clear how to interpret that
1758
159
    nav_mode2 = getub(buf, 21);
1759
1760
159
    gps_week = getbeu16(buf, 22);    // modulo 1024
1761
159
    iTOW = getbeu32(buf, 24);
1762
    /* Gack.  The doc says early SiRF scales iTOW by 100, later ones
1763
     * by 1000.  But that does not seem to be true in sirfstar V. */
1764
159
    tow.tv_sec = iTOW / 100;
1765
159
    tow.tv_nsec = (iTOW % 100) * 10000000LL;
1766
159
    session->newdata.time = gpsd_gpstime_resolv(session, gps_week, tow);
1767
1768
159
    if (MODE_NO_FIX >= session->newdata.mode) {
1769
35
        GPSD_LOG(LOG_PROG, &session->context->errout,
1770
35
                 "SiRF: MND 0x02 NTPD no fix, mode: %d\n",
1771
35
                 session->newdata.mode);
1772
124
    } else {
1773
124
        GPSD_LOG(LOG_PROG, &session->context->errout,
1774
124
                 "SiRF: MND 0x02 NTPD valid time, seen %#02x time %s "
1775
124
                 "leap %d nav_mode2 %#x\n",
1776
124
                 session->driver.sirf.time_seen,
1777
124
                 timespec_str(&session->newdata.time, ts_buf, sizeof(ts_buf)),
1778
124
                 session->context->leap_seconds,
1779
124
                 nav_mode2);
1780
124
    }
1781
159
    mask |= TIME_SET | STATUS_SET | MODE_SET | USED_IS;
1782
159
    if (3 <= session->gpsdata.satellites_visible) {
1783
111
        mask |= NTPTIME_IS;
1784
111
    }
1785
1786
159
    GPSD_LOG(LOG_PROG, &session->context->errout,
1787
159
             "SiRF: MND 0x02: Navtype %#0x, Status %d mode %d "
1788
159
             "gps_week %u iTOW %u\n",
1789
159
             navtype, session->newdata.status, session->newdata.mode,
1790
159
             gps_week, iTOW);
1791
159
    GPSD_LOG(LOG_DATA, &session->context->errout,
1792
159
             "SiRF: MND 0x02: time %s ecef x: %.2f y: %.2f z: %.2f "
1793
159
             "mode %d status %d hdop %.2f used %d\n",
1794
159
             timespec_str(&session->newdata.time, ts_buf, sizeof(ts_buf)),
1795
159
             session->newdata.ecef.x,
1796
159
             session->newdata.ecef.y, session->newdata.ecef.z,
1797
159
             session->newdata.mode, session->newdata.status,
1798
159
             session->gpsdata.dop.hdop, session->gpsdata.satellites_used);
1799
159
    return mask;
1800
294
}
1801
1802
/***************************************************************************
1803
 We've stopped interpreting GND (0x29) for the following reasons:
1804
1805
1) Versions of SiRF firmware still in wide circulation (and likely to be
1806
   so for a while) don't report a valid time field, leading to annoying
1807
   twice-per-second jitter in client displays.
1808
1809
2) What we wanted out of this that MND didn't give us was horizontal and
1810
   vertical error estimates. But we have to do our own error estimation by
1811
   computing DOPs from the skyview covariance matrix anyway, because we
1812
   want separate epx and epy errors a la NMEA 3.0.
1813
1814
3) The fix-merge logic in gpsd.c is (unavoidably) NMEA-centric and
1815
   thinks multiple sentences in one cycle should be treated as
1816
   incremental updates.  This leads to various silly results when (as
1817
   in GND) a subsequent sentence is (a) intended to be a complete fix
1818
   in itself, and (b) frequently broken.
1819
1820
4) Ignoring this dodgy sentence allows us to go to a nice clean single
1821
   fix update per cycle.
1822
1823
Code left in place in case we need to reverse this decision.
1824
1825
update: Jan 2022
1826
1827
Decode the sentence, we need the extended week.
1828
The cycle ender seems to be preventing the previously seen duplicate TPV.
1829
For now be cautious on the mask.
1830
1831
***************************************************************************/
1832
static gps_mask_t sirf_msg_geodetic(struct gps_device_t *session,
1833
                                    unsigned char *buf, size_t len)
1834
195
{
1835
195
    unsigned navtype;
1836
195
    gps_mask_t mask = 0;
1837
195
    char ts_buf[TIMESPEC_LEN];
1838
195
    unsigned gps_week;
1839
195
    timespec_t tow;
1840
195
    unsigned long iTOW;
1841
1842
195
    if (91 != len) {
1843
135
        GPSD_LOG(LOG_INF, &session->context->errout,
1844
135
                 "SiRF: MID (0x29) runt len %zu\n", len);
1845
135
        return 0;
1846
135
    }
1847
1848
60
    navtype = getbeu16(buf, 3);
1849
60
    if (0 == (navtype & 0x07)) {
1850
        // no fix
1851
1
        session->newdata.status = STATUS_UNK;
1852
59
    } else if (7 == (navtype & 0x07)) {
1853
12
        session->newdata.status = STATUS_DR;
1854
47
    } else if (0x80 == (navtype & 0x80)) {
1855
15
        session->newdata.status = STATUS_DGPS;
1856
32
    } else {
1857
32
        session->newdata.status = STATUS_GPS;
1858
32
    }
1859
1860
60
    session->newdata.mode = MODE_NO_FIX;
1861
60
    if (4 == (navtype & 0x07) ||
1862
47
        6 == (navtype & 0x07)) {
1863
20
        session->newdata.mode = MODE_3D;
1864
40
    } else if (session->newdata.status) {
1865
39
        session->newdata.mode = MODE_2D;
1866
39
    }
1867
1868
60
    gps_week = getbeu16(buf, 5);  // extended gps week
1869
60
    iTOW = getbeu32(buf, 7);
1870
60
    MSTOTS(&tow, iTOW);
1871
60
    session->newdata.time = gpsd_gpstime_resolv(session, gps_week, tow);
1872
60
    GPSD_LOG(LOG_PROG, &session->context->errout,
1873
60
             "SiRF: GND 0x29: Navtype 0x%0x Status %d mode %d week %u "
1874
60
             "iTOW %lu\n",
1875
60
             navtype, session->newdata.status, session->newdata.mode,
1876
60
             gps_week, iTOW);
1877
60
    mask |= STATUS_SET | MODE_SET | TIME_SET;
1878
1879
60
    session->newdata.latitude = getbes32(buf, 23) * 1e-7;
1880
60
    session->newdata.longitude = getbes32(buf, 27) * 1e-7;
1881
60
    if (MODE_NO_FIX < session->newdata.mode) {
1882
59
        unsigned u;
1883
1884
59
        if (3 <= session->gpsdata.satellites_visible) {
1885
0
            mask |= NTPTIME_IS;
1886
0
        }
1887
59
        if (0 != session->newdata.latitude &&
1888
56
            0 != session->newdata.longitude) {
1889
            // annoying if you happen be be at 9/0
1890
51
            mask |= LATLON_SET;
1891
51
        }
1892
1893
59
        u = getbeu32(buf, 50);
1894
59
        if (0 != u) {
1895
58
            session->newdata.eph = u * 1e-2;
1896
58
            mask |= HERR_SET;
1897
58
        }
1898
59
        u = getbeu32(buf, 54);
1899
59
        if (0 != u) {
1900
            // vertical error
1901
55
            session->newdata.epv = u * 1e-2;
1902
55
            mask |= VERR_SET;
1903
55
        }
1904
59
        u = getbeu16(buf, 62);
1905
59
        if (0 != u) {
1906
45
            session->newdata.eps = u * 1e-2;
1907
45
            mask |= SPEEDERR_SET;
1908
45
        }
1909
        // HDOP should be available at byte 89, but in 231 it's zero.
1910
59
        u = getub(buf, 89);
1911
59
        if (0 != u) {
1912
40
            session->gpsdata.dop.hdop = u * 0.2;
1913
40
            mask |= DOP_SET;
1914
40
        }
1915
59
    }
1916
1917
1918
60
    if ((MODE_NO_FIX < session->newdata.mode) &&
1919
59
        (session->driver.sirf.driverstate & SIRF_GE_232)) {
1920
0
        struct tm unpacked_date = {0};
1921
0
        unsigned subseconds;
1922
        /*
1923
         * Early versions of the SiRF protocol manual don't document
1924
         * this sentence at all.  Some that do incorrectly
1925
         * describe UTC Day, Hour, and Minute as 2-byte quantities,
1926
         * not 1-byte. Chris Kuethe, our SiRF expert, tells us:
1927
         *
1928
         * "The Geodetic Navigation packet (0x29) was not fully
1929
         * implemented in firmware prior to version 2.3.2. So for
1930
         * anyone running 231.000.000 or earlier (including ES,
1931
         * SiRFDRive, XTrac trains) you won't get UTC time. I don't
1932
         * know what's broken in firmwares before 2.3.1..."
1933
         *
1934
         * To work around the incomplete implementation of this
1935
         * packet in 231, we used to assume that only the altitude field
1936
         * from this packet is valid.  But even this doesn't necessarily
1937
         * seem to be the case.  Instead, we do our own computation
1938
         * of geoid separation now.
1939
         *
1940
         * UTC is left all zeros in 231 and older firmware versions,
1941
         * and misdocumented in version 1.4 of the Protocol Reference.
1942
         *            Documented:        Real:
1943
         * UTC year       2               2
1944
         * UTC month      1               1
1945
         * UTC day        2               1
1946
         * UTC hour       2               1
1947
         * UTC minute     2               1
1948
         * UTC second     2               2
1949
         *                11              8
1950
         *
1951
         * Documentation of this field was corrected in the 1.6 version
1952
         * of the protocol manual.
1953
         */
1954
0
        memset(&unpacked_date, 0, sizeof(unpacked_date));
1955
0
        unpacked_date.tm_year = (int)getbeu16(buf, 11) - 1900;
1956
0
        unpacked_date.tm_mon = (int)buf[13] - 1;
1957
0
        unpacked_date.tm_mday = (int)buf[14];
1958
0
        unpacked_date.tm_hour = (int)buf[15];
1959
0
        unpacked_date.tm_min = (int)buf[16];
1960
0
        subseconds = getbeu16(buf, 17);
1961
0
        unpacked_date.tm_sec = subseconds / 1000;
1962
        // we use iTOW time, not this UTC time, which is often missing
1963
1964
0
        if (MODE_2D <= session->newdata.mode &&
1965
0
            0 != unpacked_date.tm_year) {
1966
0
            GPSD_LOG(LOG_PROG, &session->context->errout,
1967
0
                     "SiRF: GND 0x29 NTPD valid time, seen=%#02x "
1968
0
                     "%4d/%02d/%02d %02d:%02d:%02.6f\n",
1969
0
                     session->driver.sirf.time_seen,
1970
0
                     unpacked_date.tm_year + 1900,
1971
0
                     unpacked_date.tm_mon + 1,
1972
0
                     unpacked_date.tm_mday,
1973
0
                     unpacked_date.tm_hour,
1974
0
                     unpacked_date.tm_min,
1975
0
                     subseconds * 0.001);
1976
0
        }
1977
1978
        // alititude WGS84
1979
0
        session->newdata.altHAE = getbes32(buf, 31) * 1e-2;
1980
0
        session->newdata.altMSL = getbes32(buf, 35) * 1e-2;
1981
        // Let gpsd_error_model() deal with geoid_sep and altHAE
1982
        // skip 1 byte of map datum
1983
0
        session->newdata.speed = getbeu16(buf, 40) * 1e-2;
1984
        // true track
1985
0
        session->newdata.track = getbeu16(buf, 42) * 1e-2;
1986
        // skip 2 bytes of magnetic variation, doc says not implemented
1987
0
        session->newdata.climb = getbes16(buf, 46) * 1e-2;
1988
0
        mask |= TIME_SET | SPEED_SET | TRACK_SET;
1989
0
        if (MODE_3D == session->newdata.mode) {
1990
0
            mask |= ALTITUDE_SET | CLIMB_SET;
1991
0
       }
1992
0
    }
1993
1994
60
    GPSD_LOG(LOG_PROG, &session->context->errout,
1995
60
             "SiRF: GND 0x29: time=%s lat=%.2f lon=%.2f altHAE=%.2f "
1996
60
             "track=%.2f speed=%.2f mode=%d status=%d\n",
1997
60
             timespec_str(&session->newdata.time, ts_buf, sizeof(ts_buf)),
1998
60
             session->newdata.latitude,
1999
60
             session->newdata.longitude,
2000
60
             session->newdata.altHAE,
2001
60
             session->newdata.track,
2002
60
             session->newdata.speed,
2003
60
             session->newdata.mode,
2004
60
             session->newdata.status);
2005
60
    return mask;
2006
195
}
2007
2008
// decode Navigation Parameters MID 19 (0x13) response to ID 152
2009
static gps_mask_t sirf_msg_sysparam(struct gps_device_t *session,
2010
                                    unsigned char *buf, size_t len)
2011
182
{
2012
2013
182
    if (65 > len) {
2014
134
        GPSD_LOG(LOG_INF, &session->context->errout,
2015
134
                 "SiRF: MID (0x13) runt len %zu\n", len);
2016
134
        return 0;
2017
134
    }
2018
2019
    // save these to restore them in the revert method
2020
48
    session->driver.sirf.nav_parameters_seen = true;
2021
48
    session->driver.sirf.altitude_hold_mode = (unsigned char)getub(buf, 5);
2022
48
    session->driver.sirf.altitude_hold_source = (unsigned char)getub(buf, 6);
2023
48
    session->driver.sirf.altitude_source_input = getbes16(buf, 7);
2024
48
    session->driver.sirf.degraded_mode = (unsigned char)getub(buf, 9);
2025
48
    session->driver.sirf.degraded_timeout = (unsigned char)getub(buf, 10);
2026
48
    session->driver.sirf.dr_timeout = (unsigned char)getub(buf, 11);
2027
48
    session->driver.sirf.track_smooth_mode = (unsigned char)getub(buf, 12);
2028
48
    return 0;
2029
182
}
2030
2031
/* DGPS status MID 27 (0x1b)
2032
 * only documentented from prorocol version 1.7 (2005) onwards */
2033
static gps_mask_t sirf_msg_dgpsstatus(struct gps_device_t *session,
2034
                                 unsigned char *buf, size_t len UNUSED)
2035
135
{
2036
135
    session->driver.sirf.dgps_source = (unsigned int)getub(buf, 1);
2037
135
    return 0;
2038
135
}
2039
2040
/* decode Extended Measured Navigation Data MID 98 (0x62)
2041
 * Used in u-blox TIM GPS receivers (SiRF2-ublox)
2042
 * "Firmware Release 2.1 UBX 1.0" */
2043
static gps_mask_t sirf_msg_ublox(struct gps_device_t *session,
2044
                                 unsigned char *buf, size_t len UNUSED)
2045
81
{
2046
81
    gps_mask_t mask;
2047
81
    unsigned short navtype;
2048
81
    char ts_buf[TIMESPEC_LEN];
2049
2050
81
    if (39 != len) {
2051
71
        GPSD_LOG(LOG_INF, &session->context->errout,
2052
71
                 "SiRF: MID (0x62) runt len %zu\n", len);
2053
71
        return 0;
2054
71
    }
2055
2056
    // this packet is only sent by u-blox firmware from version 1.32
2057
10
    mask = LATLON_SET | ALTITUDE_SET | SPEED_SET | TRACK_SET | CLIMB_SET |
2058
10
        STATUS_SET | MODE_SET;
2059
10
    session->newdata.latitude = (double)getbes32(buf, 1) * RAD_2_DEG * 1e-8;
2060
10
    session->newdata.longitude = (double)getbes32(buf, 5) * RAD_2_DEG * 1e-8;
2061
    // defaults to WGS84
2062
10
    session->newdata.altHAE = (double)getbes32(buf, 9) * 1e-3;
2063
10
    session->newdata.speed = (double)getbes32(buf, 13) * 1e-3;
2064
10
    session->newdata.climb = (double)getbes32(buf, 17) * 1e-3;
2065
10
    session->newdata.track = (double)getbes32(buf, 21) * RAD_2_DEG * 1e-8;
2066
2067
10
    navtype = (unsigned short)getub(buf, 25);
2068
10
    session->newdata.status = STATUS_UNK;
2069
10
    session->newdata.mode = MODE_NO_FIX;
2070
10
    if (0 == (navtype & 0x07)) {
2071
        // no fix
2072
1
        session->newdata.status = STATUS_UNK;
2073
9
    } else if (7 == (navtype & 0x07)) {
2074
1
        session->newdata.status = STATUS_DR;
2075
8
    } else if (0x80 == (navtype & 0x80)) {
2076
5
        session->newdata.status = STATUS_DGPS;
2077
5
    } else {
2078
3
        session->newdata.status = STATUS_GPS;
2079
3
    }
2080
10
    if (4 == (navtype & 0x07) ||
2081
8
        6 == (navtype & 0x07)) {
2082
3
        session->newdata.mode = MODE_3D;
2083
7
    } else if (session->newdata.status) {
2084
6
        session->newdata.mode = MODE_2D;
2085
6
    }
2086
10
    GPSD_LOG(LOG_PROG, &session->context->errout,
2087
10
             "SiRF: EMND 0x62: Navtype = 0x%0x, Status = %d, mode = %d\n",
2088
10
             navtype, session->newdata.status, session->newdata.mode);
2089
2090
10
    if (navtype & 0x40) {       // UTC corrected timestamp?
2091
7
        struct tm unpacked_date = {0};
2092
7
        uint32_t msec;
2093
2094
7
        mask |= TIME_SET;
2095
7
        if (3 <= session->gpsdata.satellites_visible) {
2096
0
            mask |= NTPTIME_IS;
2097
0
        }
2098
7
        memset(&unpacked_date, 0, sizeof(unpacked_date));
2099
7
        unpacked_date.tm_year = (int)getbeu16(buf, 26) - 1900;
2100
7
        unpacked_date.tm_mon = (int)getub(buf, 28) - 1;
2101
7
        unpacked_date.tm_mday = (int)getub(buf, 29);
2102
7
        unpacked_date.tm_hour = (int)getub(buf, 30);
2103
7
        unpacked_date.tm_min = (int)getub(buf, 31);
2104
7
        msec = getbeu16(buf, 32);
2105
7
        unpacked_date.tm_sec = msec / 1000;
2106
7
        session->newdata.time.tv_sec = mkgmtime(&unpacked_date);
2107
        // ms to ns
2108
7
        session->newdata.time.tv_nsec = (msec % 1000) * 1000000LL;
2109
7
        if (0 == (session->driver.sirf.time_seen & TIME_SEEN_UTC_2)) {
2110
7
            GPSD_LOG(LOG_RAW, &session->context->errout,
2111
7
                     "SiRF: EMND 0x62 NTPD just SEEN_UTC_2\n");
2112
7
        }
2113
7
        GPSD_LOG(LOG_PROG, &session->context->errout,
2114
7
                 "SiRF: EMND 0x62 NTPD valid time, seen=%#02x\n",
2115
7
                 session->driver.sirf.time_seen);
2116
7
        session->driver.sirf.time_seen |= TIME_SEEN_UTC_2;
2117
        /* The mode byte, bit 6 tells us if leap second is valid.
2118
         * But not what the leap second is.
2119
         * session->context->valid |= LEAP_SECOND_VALID;
2120
         */
2121
7
    }
2122
2123
10
    session->gpsdata.dop.gdop = (int)getub(buf, 34) / 5.0;
2124
10
    session->gpsdata.dop.pdop = (int)getub(buf, 35) / 5.0;
2125
10
    session->gpsdata.dop.hdop = (int)getub(buf, 36) / 5.0;
2126
10
    session->gpsdata.dop.vdop = (int)getub(buf, 37) / 5.0;
2127
10
    session->gpsdata.dop.tdop = (int)getub(buf, 38) / 5.0;
2128
10
    mask |= DOP_SET;
2129
10
    session->driver.sirf.driverstate |= UBLOX;
2130
10
    GPSD_LOG(LOG_DATA, &session->context->errout,
2131
10
             "SiRF: EMND 0x62: time=%s lat=%.2f lon=%.2f altHAE=%.2f "
2132
10
             "speed=%.2f track=%.2f climb=%.2f mode=%d status=%d gdop=%.2f "
2133
10
             "pdop=%.2f hdop=%.2f vdop=%.2f tdop=%.2f\n",
2134
10
             timespec_str(&session->newdata.time, ts_buf, sizeof(ts_buf)),
2135
10
             session->newdata.latitude,
2136
10
             session->newdata.longitude, session->newdata.altHAE,
2137
10
             session->newdata.speed, session->newdata.track,
2138
10
             session->newdata.climb, session->newdata.mode,
2139
10
             session->newdata.status, session->gpsdata.dop.gdop,
2140
10
             session->gpsdata.dop.pdop, session->gpsdata.dop.hdop,
2141
10
             session->gpsdata.dop.vdop, session->gpsdata.dop.tdop);
2142
10
    return mask;
2143
81
}
2144
2145
// decode PPS Time MID 52 (0x34)
2146
static gps_mask_t sirf_msg_ppstime(struct gps_device_t *session,
2147
                                   unsigned char *buf, size_t len)
2148
443
{
2149
443
    gps_mask_t mask = 0;
2150
2151
443
    if (19 > len) {
2152
140
        GPSD_LOG(LOG_INF, &session->context->errout,
2153
140
                 "SiRF: MID (0x34) runt len %zu\n", len);
2154
140
        return 0;
2155
140
    }
2156
2157
303
    GPSD_LOG(LOG_PROG, &session->context->errout,
2158
303
             "SiRF: PPS 0x34: Status = %#02x\n",
2159
303
             getub(buf, 14));
2160
303
    if (0x07 == ((int)getub(buf, 14) & 0x07)) {
2161
        // valid UTC time
2162
235
        struct tm unpacked_date = {0};
2163
2164
235
        memset(&unpacked_date, 0, sizeof(unpacked_date));
2165
235
        unpacked_date.tm_hour = (int)getub(buf, 1);
2166
235
        unpacked_date.tm_min = (int)getub(buf, 2);
2167
235
        unpacked_date.tm_sec = (int)getub(buf, 3);
2168
235
        unpacked_date.tm_mday = (int)getub(buf, 4);
2169
235
        unpacked_date.tm_mon = (int)getub(buf, 5) - 1;
2170
235
        unpacked_date.tm_year = (int)getbeu16(buf, 6) - 1900;
2171
235
        session->newdata.time.tv_sec = mkgmtime(&unpacked_date);
2172
235
        session->newdata.time.tv_nsec = 0;
2173
235
        session->context->leap_seconds = (int)getbeu16(buf, 8);
2174
        // Ignore UTCOffsetFrac1
2175
235
        session->context->valid |= LEAP_SECOND_VALID;
2176
235
        if (0 == (session->driver.sirf.time_seen & TIME_SEEN_UTC_2)) {
2177
110
            GPSD_LOG(LOG_RAW, &session->context->errout,
2178
110
                     "SiRF: NTPD just SEEN_UTC_2\n");
2179
110
        }
2180
235
        GPSD_LOG(LOG_PROG, &session->context->errout,
2181
235
                 "SiRF: NTPD valid time MID 0x34, seen=%#02x, leap=%d\n",
2182
235
                 session->driver.sirf.time_seen,
2183
235
                 session->context->leap_seconds);
2184
235
        session->driver.sirf.time_seen |= TIME_SEEN_UTC_2;
2185
235
        mask |= TIME_SET;
2186
235
        if (3 <= session->gpsdata.satellites_visible) {
2187
122
            mask |= NTPTIME_IS;
2188
122
        }
2189
235
    }
2190
303
    return mask;
2191
443
}
2192
2193
// decode Navigation Library Measurement Data MID 28 (0x38)
2194
static gps_mask_t sirf_msg_nl(struct gps_device_t *session,
2195
                                   unsigned char *buf, size_t len)
2196
150
{
2197
2198
150
    if (67 != len) {
2199
139
        GPSD_LOG(LOG_INF, &session->context->errout,
2200
139
                 "SiRF: MID (0x38) runt len %zu\n", len);
2201
139
        return 0;
2202
139
    }
2203
2204
11
    switch (buf[1]) {
2205
1
    case 1:
2206
1
        GPSD_LOG(LOG_PROG, &session->context->errout,
2207
1
                 "SiRF IV: unused NL 0x38, SubID: 1, GPS Data\n");
2208
1
        break;
2209
1
    case 2:
2210
1
        GPSD_LOG(LOG_PROG, &session->context->errout,
2211
1
                 "SiRF IV: unused NL 0x38, SubID: 2, EE Integrity\n");
2212
1
        break;
2213
1
    case 3:
2214
1
        GPSD_LOG(LOG_PROG, &session->context->errout,
2215
1
                 "SiRF IV: unused NL 0x38, SubID: 3, EE Integrity\n");
2216
1
        break;
2217
1
    case 4:
2218
1
        GPSD_LOG(LOG_PROG, &session->context->errout,
2219
1
                 "SiRF IV: unused NL 0x38, SubID: 4, EE Clock Bias\n");
2220
1
        break;
2221
1
    case 5:
2222
1
        GPSD_LOG(LOG_PROG, &session->context->errout,
2223
1
                 "SiRF IV: unused NL 0x38, SubID: 4, 50bps\n");
2224
1
        break;
2225
1
    case 32:
2226
1
        GPSD_LOG(LOG_PROG, &session->context->errout,
2227
1
                 "SiRF IV: unused NL 0x38, SubID: 4, ECLM ACK/NACK\n");
2228
1
        break;
2229
1
    case 33:
2230
1
        GPSD_LOG(LOG_PROG, &session->context->errout,
2231
1
                 "SiRF IV: unused NL 0x38, SubID: 4, ECLM EE Age\n");
2232
1
        break;
2233
1
    case 34:
2234
1
        GPSD_LOG(LOG_PROG, &session->context->errout,
2235
1
                 "SiRF IV: unused NL 0x38, SubID: 4, ECLM SGEE Age\n");
2236
1
        break;
2237
1
    case 35:
2238
1
        GPSD_LOG(LOG_PROG, &session->context->errout,
2239
1
                 "SiRF IV: unused NL 0x38, SubID: 4, ECLM Download Initiate\n");
2240
1
        break;
2241
1
    case 255:
2242
1
        GPSD_LOG(LOG_PROG, &session->context->errout,
2243
1
            "SiRF IV: unused NL 0x38, SubID: 4, EE ACK\n");
2244
1
        break;
2245
1
    default:
2246
1
        GPSD_LOG(LOG_PROG, &session->context->errout,
2247
11
                 "SiRF IV: unused NL 0x38, unknown SubID: %d\n",
2248
11
                 buf[1]);
2249
11
    }
2250
2251
11
    return 0;
2252
11
}
2253
2254
// decode  Extended Ephemeris Data MID 56 (0x38)
2255
static gps_mask_t sirf_msg_ee(struct gps_device_t *session,
2256
                              unsigned char *buf, size_t len)
2257
141
{
2258
2259
141
    if (67 != len) {
2260
138
        GPSD_LOG(LOG_INF, &session->context->errout,
2261
138
                 "SiRF: MID (0x38) runt len %zu\n", len);
2262
138
        return 0;
2263
138
    }
2264
2265
3
    switch (buf[1]) {
2266
1
    case 1:
2267
1
        GPSD_LOG(LOG_PROG, &session->context->errout,
2268
1
                 "SiRF IV: unused EE 0x40, SubID: 1\n");
2269
1
        break;
2270
1
    case 2:
2271
1
        GPSD_LOG(LOG_PROG, &session->context->errout,
2272
1
                 "SiRF IV: unused EE 0x40, SubID: 2, PRN: %d\n",
2273
1
                 buf[2]);
2274
1
        break;
2275
1
    default:
2276
1
        GPSD_LOG(LOG_PROG, &session->context->errout,
2277
3
                 "SiRF IV: unused EE 0x40, unknown SubID: %d\n",
2278
3
                 buf[1]);
2279
3
    }
2280
2281
3
    return 0;
2282
3
}
2283
2284
2285
gps_mask_t sirf_parse(struct gps_device_t * session, unsigned char *buf,
2286
                      size_t len)
2287
15.0k
{
2288
2289
15.0k
    if (0 == len) {
2290
0
        GPSD_LOG(LOG_INF, &session->context->errout,
2291
0
                 "SiRF: runt len %zu\n", len);
2292
0
        return 0;
2293
0
    }
2294
2295
15.0k
    buf += 4;
2296
15.0k
    len -= 8;
2297
    // cast for 32/64 bit compatiility
2298
15.0k
    GPSD_LOG(LOG_RAW, &session->context->errout,
2299
15.0k
             "SiRF: Raw packet type %#04x len %ld\n", buf[0],
2300
15.0k
             (long)len);
2301
15.0k
    session->driver.sirf.lastid = buf[0];
2302
2303
    // could change if the set of messages we enable does
2304
15.0k
    session->cycle_end_reliable = true;
2305
2306
15.0k
    switch (buf[0]) {
2307
294
    case 0x02:                  // Measure Navigation Data Out MID 2
2308
294
        if (0 == (session->driver.sirf.driverstate & UBLOX)) {
2309
294
            return sirf_msg_navsol(session, buf,
2310
294
                                   len) | (CLEAR_IS | REPORT_IS);
2311
294
        }
2312
0
        GPSD_LOG(LOG_PROG, &session->context->errout,
2313
0
                 "SiRF: MID 2 (0x02) MND skipped, u-blox flag is on.\n");
2314
0
        return 0;
2315
2316
156
    case 0x04:                  // Measured tracker data out MID 4
2317
156
        return sirf_msg_svinfo(session, buf, len);
2318
2319
133
    case 0x05:                  // Raw Tracker Data Out MID 5
2320
133
        GPSD_LOG(LOG_PROG, &session->context->errout,
2321
133
                 "SiRF: unused MID 5 (0x05) Raw Tracker Data\n");
2322
133
        return 0;
2323
2324
1.74k
    case 0x06:                  // Software Version String MID 6
2325
1.74k
        return sirf_msg_swversion(session, buf, len);
2326
2327
132
    case 0x07:                  // Clock Status Data MID 7
2328
132
        GPSD_LOG(LOG_PROG, &session->context->errout,
2329
132
                 "SiRF: unused MID 7 (0x07) CLK\n");
2330
132
        return 0;
2331
2332
145
    case 0x08:                  // subframe data MID 8
2333
        // extract leap-second from this
2334
        /*
2335
         * Chris Kuethe says:
2336
         * "Message 8 is generated as the data is received. It is not
2337
         * buffered on the chip. So when you enable message 8, you'll
2338
         * get one subframe every 6 seconds.  Of the data received, the
2339
         * almanac and ephemeris are buffered and stored, so you can
2340
         * query them at will. Alas, the time parameters are not
2341
         * stored, which is really lame, as the UTC-GPS correction
2342
         * changes 1 second every few years. Maybe."
2343
         */
2344
145
        return sirf_msg_navdata(session, buf, len);
2345
2346
937
    case 0x09:                  // CPU Throughput MID 9 (0x09)
2347
937
        GPSD_LOG(LOG_PROG, &session->context->errout,
2348
937
                 "SiRF: THR 0x09: SegStatMax=%.3f, SegStatLat=%3.f, "
2349
937
                 "AveTrkTime=%.3f, Last MS=%u\n",
2350
937
                 (float)getbeu16(buf, 1) / 186, (float)getbeu16(buf, 3) / 186,
2351
937
                 (float)getbeu16(buf, 5) / 186, getbeu16(buf, 7));
2352
937
        return 0;
2353
2354
772
    case 0x0a:                  // Error ID Data MID 10
2355
772
        return sirf_msg_errors(session, buf, len);
2356
2357
1.85k
    case 0x0b:                  // Command Acknowledgement MID 11
2358
1.85k
        if (2 > len) {
2359
168
            return 0;
2360
168
        }
2361
1.68k
        if (2 == len) {
2362
1.53k
            GPSD_LOG(LOG_PROG, &session->context->errout,
2363
1.53k
                     "SiRF: ACK 0x0b: %#02x\n", getub(buf, 1));
2364
1.53k
        } else {
2365
            // SiRF III+, has ACK ID
2366
146
            GPSD_LOG(LOG_PROG, &session->context->errout,
2367
146
                     "SiRF: ACK 0x0b: %#02x/%02x\n",
2368
146
                     getub(buf, 1), getub(buf, 2));
2369
146
        }
2370
1.68k
        session->driver.sirf.need_ack = 0;
2371
1.68k
        return 0;
2372
2373
2.04k
    case 0x0c:                  // Command NAcknowledgement MID 12
2374
2.04k
        if (2 > len) {
2375
133
            return 0;
2376
133
        }
2377
1.91k
        if (2 == len) {
2378
1.75k
            GPSD_LOG(LOG_PROG, &session->context->errout,
2379
1.75k
                     "SiRF: NACK 0x0c: %#02x\n", getub(buf, 1));
2380
1.75k
        } else {
2381
            // SiRF III+, has NACK ID
2382
160
            GPSD_LOG(LOG_PROG, &session->context->errout,
2383
160
                     "SiRF: NACK 0x0c: %#02x/%02x\n",
2384
160
                     getub(buf, 1), getub(buf, 2));
2385
160
        }
2386
        // ugh -- there's no alternative but silent failure here
2387
1.91k
        session->driver.sirf.need_ack = 0;
2388
1.91k
        return 0;
2389
2390
135
    case 0x0d:                  // Visible List MID 13
2391
        // no data here not already in MID 67,16
2392
135
        GPSD_LOG(LOG_PROG, &session->context->errout,
2393
135
                 "SiRF: unused MID 13 (0x0d) Visible List, len %zd\n", len);
2394
135
        return 0;
2395
2396
139
    case 0x0e:                  // Almanac Data MID 14
2397
139
        GPSD_LOG(LOG_PROG, &session->context->errout,
2398
139
                 "SiRF: unused MID 14 (0x0e) ALM\n");
2399
139
        return 0;
2400
2401
132
    case 0x0f:                  // Ephemeris Data MID 15
2402
132
        GPSD_LOG(LOG_PROG, &session->context->errout,
2403
132
                 "SiRF: unused MID 15 (0x0f) EPH\n");
2404
132
        return 0;
2405
2406
132
    case 0x11:                  // Differential Corrections MID 17
2407
132
        GPSD_LOG(LOG_PROG, &session->context->errout,
2408
132
                 "SiRF: unused MID 17 (0x11) DIFF\n");
2409
132
        return 0;
2410
2411
133
    case 0x12:                  // OK To Send MID 18 (0x12)
2412
133
        GPSD_LOG(LOG_PROG, &session->context->errout,
2413
133
                 "SiRF: MID 18 (0x12) OkToSend: OK = %d\n",
2414
133
                 getub(buf, 1));
2415
133
        return 0;
2416
2417
182
    case 0x13:                  // Navigation Parameters MID 19 (0x13)
2418
182
        return sirf_msg_sysparam(session, buf, len);
2419
2420
135
    case 0x1b:                  // DGPS status MID 27
2421
135
        return sirf_msg_dgpsstatus(session, buf, len);
2422
2423
172
    case 0x1c:                  // Navigation Library Measurement Data MID 28
2424
172
        return sirf_msg_nlmd(session, buf, len);
2425
2426
137
    case 0x1d:                  // Navigation Library DGPS Data MID 29
2427
137
        GPSD_LOG(LOG_PROG, &session->context->errout,
2428
137
                 "SiRF: unused MID 29 (0x1d) NLDG\n");
2429
137
        return 0;
2430
2431
140
    case 0x1e:                  // Navigation Library SV State Data MID 30
2432
140
        GPSD_LOG(LOG_PROG, &session->context->errout,
2433
140
                 "SiRF: unused MID 30 (0x1e) NLSV\n");
2434
140
        return 0;
2435
2436
141
    case 0x1f:          // Navigation Library Initialization Data MID 31
2437
141
        GPSD_LOG(LOG_PROG, &session->context->errout,
2438
141
                 "SiRF: unused MID 32 (0x1f) NLID\n");
2439
141
        return 0;
2440
2441
195
    case 0x29:                  // Geodetic Navigation Data MID 41
2442
195
        return sirf_msg_geodetic(session, buf, len);
2443
2444
216
    case 0x32:                  // SBAS corrections MID 50
2445
216
        return sirf_msg_sbas(session, buf, len);
2446
2447
305
    case 0x33:                  // MID_SiRFNavNotification MID 51, 0x33
2448
305
        return sirf_msg_navnot(session, buf, len);
2449
2450
443
    case 0x34:                  // PPS Time MID 52
2451
        /*
2452
         * Carl Carter from SiRF writes: "We do not output on the
2453
         * second (unless you are using MID 52).  We make
2454
         * measurements in the receiver in time with an internal
2455
         * counter that is not slaved to GPS time, so the measurements
2456
         * are made at a time that wanders around the second.  Then,
2457
         * after the measurements are made (all normalized to the same
2458
         * point in time) we dispatch the navigation software to make
2459
         * a solution, and that solution comes out some 200 to 300 ms
2460
         * after the measurement time.  So you may get a message at
2461
         * 700 ms after the second that uses measurements time tagged
2462
         * 450 ms after the second.  And if some other task jumps up
2463
         * and delays things, that message may not come out until 900
2464
         * ms after the second.  Things can get out of sync to the
2465
         * point that if you try to resolve the GPS time of our 1 PPS
2466
         * pulses using the navigation messages, you will find it
2467
         * impossible to be consistent.  That is why I added
2468
         * MID 52 to our system -- it is tied to the creation of the 1
2469
         * PPS and always comes out right around the top of the
2470
         * second."
2471
         */
2472
443
        return sirf_msg_ppstime(session, buf, len);
2473
2474
141
    case 0x38:                // EE Output MID 56
2475
141
        return sirf_msg_ee(session, buf, len);
2476
2477
150
    case 0x40:                // Nav Library MID 64
2478
150
        return sirf_msg_nl(session, buf, len);
2479
2480
570
    case 0x43:                // Multiconstellation Nav Data Response MID 67
2481
570
        return sirf_msg_67(session, buf, len);
2482
2483
133
    case 0x47:                // Hardware Config MID 71
2484
        // MID_HW_CONFIG_REQ
2485
133
        GPSD_LOG(LOG_PROG, &session->context->errout,
2486
133
                 "SiRF IV: unused MID 71 (0x47) Hardware Config Request, "
2487
133
                 "len %zd\n", len);
2488
133
        return 0;
2489
2490
202
    case 0x51:                // MID_QUERY_RESP MID 81
2491
202
        return sirf_msg_qresp(session, buf, len);
2492
2493
67
    case 0x5c:                // Controller Interference Report MID 92
2494
67
        GPSD_LOG(LOG_PROG, &session->context->errout,
2495
67
                 "SiRF IV: unused MID 92 (0x5c) CW Interference Report\n");
2496
67
        return 0;
2497
2498
1.19k
    case 0x5d:                // TCXO Output MID 93
2499
1.19k
        return sirf_msg_tcxo(session, buf, len);
2500
2501
81
   case 0x62:          // u-blox Extended Measured Navigation Data MID 98
2502
81
        GPSD_LOG(LOG_PROG, &session->context->errout,
2503
81
                 "SiRF: MID 98 (0x62) u-blox EMND\n");
2504
81
        return sirf_msg_ublox(session, buf, len) | (CLEAR_IS | REPORT_IS);
2505
2506
134
    case 0x80:                  // Initialize Data Source MID 128
2507
134
        GPSD_LOG(LOG_PROG, &session->context->errout,
2508
134
                 "SiRF: unused MID 128 (0x80) INIT\n");
2509
134
        return 0;
2510
2511
722
    case 0xe1:                  // statistics messages MID 225
2512
722
        return sirf_msg_stats(session, buf, len);
2513
2514
325
    case 0xff:                  // Debug messages MID 255
2515
325
        (void)sirf_msg_debug(session, buf, len);
2516
325
        return 0;
2517
2518
389
    default:
2519
389
        GPSD_LOG(LOG_PROG, &session->context->errout,
2520
389
                 "SiRF: Unknown packet id %d (%#x) length %zd\n",
2521
389
                 buf[0], buf[0], len);
2522
389
        return 0;
2523
15.0k
    }
2524
15.0k
}
2525
2526
static gps_mask_t sirfbin_parse_input(struct gps_device_t *session)
2527
15.7k
{
2528
15.7k
    if (SIRF_PACKET == session->lexer.type) {
2529
15.0k
        return sirf_parse(session, session->lexer.outbuffer,
2530
15.0k
                        session->lexer.outbuflen);
2531
15.0k
    }
2532
647
    if (NMEA_PACKET == session->lexer.type) {
2533
647
        return nmea_parse((char *)session->lexer.outbuffer, session);
2534
647
    }
2535
0
    return 0;
2536
647
}
2537
2538
static void sirfbin_init_query(struct gps_device_t *session)
2539
687
{
2540
687
    GPSD_LOG(LOG_PROG, &session->context->errout,
2541
687
             "SiRF: Probing for firmware version.\n");
2542
2543
    // reset binary init steps
2544
687
    session->cfg_stage = 0;
2545
687
    session->cfg_step = 0;
2546
2547
    // MID 132
2548
687
    (void)sirf_write(session, versionprobe, sizeof(versionprobe));
2549
    // ask twice, SiRF IV on USB often misses the first request
2550
687
    (void)sirf_write(session, versionprobe, sizeof(versionprobe));
2551
687
}
2552
2553
static void sirfbin_event_hook(struct gps_device_t *session, event_t event)
2554
19.6k
{
2555
19.6k
    static unsigned char moderevert[] = {
2556
19.6k
        0xa0, 0xa2, 0x00, 0x0e,
2557
19.6k
        0x88,
2558
19.6k
        0x00, 0x00,     // pad bytes
2559
19.6k
        0x00,           // degraded mode
2560
19.6k
        0x00, 0x00,     // pad bytes
2561
19.6k
        0x00, 0x00,     // altitude source
2562
19.6k
        0x00,           // altitude hold mode
2563
19.6k
        0x00,           // use last computed alt
2564
19.6k
        0x00,           // reserved
2565
19.6k
        0x00,           // degraded mode timeout
2566
19.6k
        0x00,           // dead reckoning timeout
2567
19.6k
        0x00,           // track smoothing
2568
19.6k
        0x00, 0x00, 0xb0, 0xb3
2569
19.6k
    };
2570
2571
19.6k
    if (session->context->readonly ||
2572
14.6k
        session->context->passive) {
2573
8.99k
        return;
2574
8.99k
    }
2575
2576
10.6k
    switch (event) {
2577
603
    case EVENT_IDENTIFIED:
2578
603
        FALLTHROUGH
2579
603
    case EVENT_REACTIVATE:
2580
603
        if (NMEA_PACKET == session->lexer.type) {
2581
0
            GPSD_LOG(LOG_PROG, &session->context->errout,
2582
0
                     "SiRF: Switching chip mode to binary.\n");
2583
0
            (void)nmea_send(session,
2584
0
                            "$PSRF100,0,%d,8,1,0",
2585
0
                            session->gpsdata.dev.baudrate);
2586
0
        }
2587
603
        break;
2588
2589
9.09k
    case EVENT_CONFIGURE:
2590
        /* This wakes up on every received packet.
2591
         * Use this hook to step, slowly, through the init messages.
2592
         * We try, but not always succeed, to wait for the ACK/NACK.
2593
         * Send a message only every 15 times so we get an ACK/NACK
2594
         * before next one.
2595
         *
2596
         * This tries to avoid overrunning the input buffer, and makes
2597
         * it much easier to identify which messages get a NACK
2598
         */
2599
2600
2601
9.09k
        if (UINT_MAX == session->cfg_stage) {
2602
            // init done
2603
3.06k
            return;
2604
3.06k
        }
2605
6.03k
        session->cfg_step++;
2606
2607
6.03k
        if ((0 < session->driver.sirf.need_ack) &&
2608
3.04k
            (15 > session->cfg_step)) {
2609
            // we are waiting for ACK, just wait for 15 messages
2610
2.92k
            return;
2611
2.92k
        }
2612
3.11k
        session->cfg_step = 0;
2613
3.11k
        session->cfg_stage++;
2614
3.11k
        GPSD_LOG(LOG_PROG, &session->context->errout, "stage: %d\n",
2615
3.11k
                 session->cfg_stage);
2616
2617
2618
3.11k
        switch (session->cfg_stage) {
2619
0
        case 0:
2620
            // this slot used by EVENT_IDENTIFIED
2621
0
            return;
2622
2623
481
        case 1:
2624
481
            (void)sirf_write(session, versionprobe, sizeof(versionprobe));
2625
481
            break;
2626
408
        case 2:
2627
            // unset MID 0x40 = 64 first since there is a flood of them
2628
408
            GPSD_LOG(LOG_PROG, &session->context->errout,
2629
408
                     "SiRF: unset MID 0x40.\n");
2630
408
            unsetmidXX[5] = 1;        // enable/disable
2631
408
            unsetmidXX[6] = 0x40;     // MID 0x40
2632
408
            (void)sirf_write(session, unsetmidXX, sizeof(unsetmidXX));
2633
408
            break;
2634
2635
374
        case 3:
2636
            /*
2637
             * The response to this request will save the navigation
2638
             * parameters so they can be reverted before close.
2639
             */
2640
374
            GPSD_LOG(LOG_PROG, &session->context->errout,
2641
374
                     "SiRF: Requesting navigation parameters.\n");
2642
374
            (void)sirf_write(session, navparams, sizeof(navparams));
2643
374
            break;
2644
2645
318
        case 4:
2646
            // unset GND (0x29 = 41), it's not reliable on SiRF II
2647
318
            GPSD_LOG(LOG_PROG, &session->context->errout,
2648
318
                     "SiRF: unset MID 0x29.\n");
2649
318
            unsetmidXX[5] = 1;        // enable/disable
2650
318
            unsetmidXX[6] = 0x29;     // MID 0x29
2651
318
            (void)sirf_write(session, unsetmidXX, sizeof(unsetmidXX));
2652
318
            break;
2653
2654
279
        case 5:
2655
279
            GPSD_LOG(LOG_PROG, &session->context->errout,
2656
279
                     "SiRF: Setting Navigation Parameters.\n");
2657
279
            (void)sirf_write(session, modecontrol, sizeof(modecontrol));
2658
279
            break;
2659
2660
255
        case 6:
2661
255
            GPSD_LOG(LOG_PROG, &session->context->errout,
2662
255
                     "SiRF: Requesting periodic ecef reports.\n");
2663
255
            (void)sirf_write(session, requestecef, sizeof(requestecef));
2664
255
            break;
2665
2666
221
        case 7:
2667
221
            GPSD_LOG(LOG_PROG, &session->context->errout,
2668
221
                     "SiRF: Requesting periodic tracker reports.\n");
2669
221
            (void)sirf_write(session, requesttracker, sizeof(requesttracker));
2670
221
            break;
2671
2672
194
        case 8:
2673
194
            GPSD_LOG(LOG_PROG, &session->context->errout,
2674
194
                     "SiRF: Setting DGPS control to use SBAS.\n");
2675
194
            (void)sirf_write(session, dgpscontrol, sizeof(dgpscontrol));
2676
194
            break;
2677
2678
165
        case 9:
2679
165
            GPSD_LOG(LOG_PROG, &session->context->errout,
2680
165
                     "SiRF: Setting SBAS to auto/integrity mode.\n");
2681
165
            (void)sirf_write(session, sbasparams, sizeof(sbasparams));
2682
165
            break;
2683
2684
132
        case 10:
2685
132
            GPSD_LOG(LOG_PROG, &session->context->errout,
2686
132
                     "SiRF: Enabling PPS message MID 52 (0x32).\n");
2687
            /* Not supported on some GPS.
2688
             * It will be NACKed is not supported */
2689
132
            (void)sirf_write(session, enablemid52, sizeof(enablemid52));
2690
132
            break;
2691
2692
112
        case 11:
2693
            // SiRF recommends at least 57600 for SiRF IV subframe data
2694
112
            if (57600 <= session->gpsdata.dev.baudrate) {
2695
                // fast enough, turn on subframe data
2696
0
                GPSD_LOG(LOG_PROG, &session->context->errout,
2697
0
                         "SiRF: Enabling subframe transmission.\n");
2698
0
                (void)sirf_write(session, enablesubframe,
2699
0
                                 sizeof(enablesubframe));
2700
112
            } else {
2701
                // too slow, turn off subframe data
2702
112
                GPSD_LOG(LOG_PROG, &session->context->errout,
2703
112
                         "SiRF: Disabling subframe transmission.\n");
2704
112
                (void)sirf_write(session, disablesubframe,
2705
112
                                 sizeof(disablesubframe));
2706
112
            }
2707
112
            break;
2708
2709
79
        case 12:
2710
            /*
2711
             * Disable navigation debug messages (the value 5 is magic)
2712
             * must be done *after* subframe enable.
2713
             */
2714
79
            GPSD_LOG(LOG_PROG, &session->context->errout,
2715
79
                     "SiRF: disable MID 7, 28, 29, 30, 31.\n");
2716
79
            unsetmidXX[5] = 5;
2717
79
            unsetmidXX[6] = 0;
2718
79
            (void)sirf_write(session, unsetmidXX, sizeof(unsetmidXX));
2719
79
            break;
2720
2721
94
        default:
2722
            // initialization is done
2723
94
            session->cfg_stage = UINT_MAX;
2724
94
            session->cfg_step = 0;
2725
94
            return;
2726
3.11k
        }
2727
3.01k
        break;
2728
2729
3.01k
    case EVENT_DEACTIVATE:
2730
2731
0
        putbyte(moderevert, 7, session->driver.sirf.degraded_mode);
2732
0
        putbe16(moderevert, 10, session->driver.sirf.altitude_source_input);
2733
0
        putbyte(moderevert, 12, session->driver.sirf.altitude_hold_mode);
2734
0
        putbyte(moderevert, 13, session->driver.sirf.altitude_hold_source);
2735
0
        putbyte(moderevert, 15, session->driver.sirf.degraded_timeout);
2736
0
        putbyte(moderevert, 16, session->driver.sirf.dr_timeout);
2737
0
        putbyte(moderevert, 17, session->driver.sirf.track_smooth_mode);
2738
0
        GPSD_LOG(LOG_PROG, &session->context->errout,
2739
0
                 "SiRF: Reverting navigation parameters...\n");
2740
0
        (void)sirf_write(session, moderevert, sizeof(moderevert));
2741
0
        break;
2742
2743
990
    case EVENT_DRIVER_SWITCH:
2744
        // do what here?
2745
990
        break;
2746
0
    case EVENT_TRIGGERMATCH:
2747
        // do what here?
2748
0
        break;
2749
0
    case EVENT_WAKEUP:
2750
        // do what here?
2751
0
        break;
2752
10.6k
    }
2753
10.6k
}
2754
2755
2756
2757
// this is everything we export
2758
// *INDENT-OFF*
2759
const struct gps_type_t driver_sirf =
2760
{
2761
    .type_name      = "SiRF",               // full name of type
2762
    .packet_type    = SIRF_PACKET,          // associated lexer packet type
2763
    .flags          = DRIVER_STICKY,        // remember this
2764
    .trigger        = NULL,                 // no trigger
2765
    .channels       = SIRF_CHANNELS,        // consumer-grade GPS
2766
    .probe_detect   = NULL,                 // no probe
2767
    .get_packet     = packet_get1,          // be prepared for SiRF or NMEA
2768
    .parse_packet   = sirfbin_parse_input,  // parse message packets
2769
    .rtcm_writer    = gpsd_write,           // send RTCM data straight
2770
    .init_query     = sirfbin_init_query,   // non-perturbing initial query
2771
    .event_hook     = sirfbin_event_hook,   // lifetime event handler
2772
    .speed_switcher = sirfbin_speed,        // we can change baud rate
2773
    .mode_switcher  = sirfbin_mode,         // there's a mode switcher
2774
    .rate_switcher  = NULL,                 // no sample-rate switcher
2775
    .min_cycle.tv_sec  = 1,                 // not relevant, no rate switch
2776
    .min_cycle.tv_nsec = 0,                 // not relevant, no rate switch
2777
    .control_send   = sirf_control_send,    // how to send a control string
2778
    .time_offset    = sirf_time_offset,
2779
};
2780
// *INDENT-ON*
2781
#endif // defined(SIRF_ENABLE)
2782
2783
// vim: set expandtab shiftwidth=4