Coverage Report

Created: 2026-02-24 07:05

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