Coverage Report

Created: 2024-02-25 06:36

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