Coverage Report

Created: 2026-06-10 06:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gpsd/gpsd-3.27.6~dev/drivers/driver_skytraq.c
Line
Count
Source
1
/*
2
 * This is the gpsd driver for Skytraq GPSes operating in binary mode.
3
 *
4
 * SkyTraq is Big Endian
5
 *
6
 * This file is Copyright by the GPSD project
7
 * SPDX-License-Identifier: BSD-2-clause
8
 */
9
10
#include "../include/gpsd_config.h"  // must be before all includes
11
12
#include <ctype.h>
13
#include <math.h>
14
#include <stdbool.h>
15
#include <stdio.h>
16
#include <stdlib.h>
17
#include <string.h>       // for strlcpy()
18
#include <strings.h>
19
#include <unistd.h>
20
21
#include "../include/gpsd.h"
22
#include "../include/bits.h"
23
#include "../include/strfuncs.h"
24
#if defined(SKYTRAQ_ENABLE)
25
#include "../include/timespec.h"
26
27
#define HI(n)           ((n) >> 8)
28
#define LO(n)           ((n) & 0xff)
29
30
/*
31
 * No ACK/NAK?  Just retry after 6 seconds
32
 */
33
#define SKY_RETRY_TIME  6
34
// Phoenix has 230 channels
35
3.26k
#define SKY_CHANNELS    230      // max channels allowed in format
36
37
#if MAXCHANNELS < SKY_CHANNELS
38
    #error "MACHANNELS < SKY_CHANNELS"
39
#endif
40
41
#ifdef __UNUSED
42
// Poll Software Version MID 2
43
static unsigned char versionprobe[] = {
44
    0xa0, 0xa1, 0x00, 0x02,
45
    0x02,               // MID 2
46
    0x01,               // System
47
    0x00, 0x0d, 0x0a
48
};
49
#endif  // __UNUSED
50
51
/* place checksum into msg, write to device
52
 * Return: number of bytes written
53
 *         negative on error
54
 */
55
static ssize_t sky_write(struct gps_device_t *session, char *msg,
56
                         const size_t data_len)
57
3.44k
{
58
3.44k
    uint8_t chk;
59
3.44k
    uint16_t len;
60
3.44k
    ssize_t i;
61
3.44k
    bool ok;
62
3.44k
    unsigned type = (unsigned)msg[4];
63
3.44k
    uint8_t buf[BUFSIZ];
64
3.44k
    uint8_t outbuf[BUFSIZ];
65
66
    // do not write if -b (readonly) option set
67
    // "passive" handled earlier
68
3.44k
    if (session->context->readonly) {
69
1.11k
        return data_len;
70
1.11k
    }
71
72
2.33k
    if (sizeof(buf) <= data_len) {
73
        // uh, oh;
74
0
        return -1;
75
0
    }
76
    // make a copy, so we can edit it
77
2.33k
    memcpy(buf, msg, data_len);
78
79
    // max length is undocumented, largest I could find is 261
80
2.33k
    len = (buf[2] << 8) | buf[3];
81
    // limit to 512 to pacify coverity
82
2.33k
    if (512 < len) {
83
0
        len = 512;
84
0
    }
85
2.33k
    if ((size_t)(len + 7) != data_len) {
86
        // uh, oh;
87
0
        GPSD_LOG(LOG_ERROR, &session->context->errout,
88
0
                 "Skytraq: Length error: len %u data_len %zu buf %s\n",
89
0
                 len, data_len,
90
0
                 gps_hexdump((char *)outbuf, sizeof(outbuf),
91
0
                             buf, data_len));
92
0
        return -2;
93
0
    }
94
95
    // calculate Checksum
96
2.33k
    chk = 0;
97
    // coverity_submit[tainted_data]
98
5.73k
    for (i = 0; i < len; i++) {
99
3.40k
        chk ^= buf[4 + i];
100
3.40k
    }
101
102
    // enter checksum after payload
103
2.33k
    buf[len + 4] = chk;
104
2.33k
    len += 7;
105
106
2.33k
    GPSD_LOG(LOG_IO, &session->context->errout,
107
2.33k
             "Skytraq: Writing control MID %02x: %s\n", type,
108
2.33k
             gps_hexdump((char *)outbuf, sizeof(outbuf), buf, len));
109
2.33k
    ok = gpsd_write(session, (const char *)buf, len) == len;
110
111
2.33k
    return ok;
112
2.33k
}
113
114
/* sky_mode() - NMEA/Binary mode changer
115
 * return: void
116
 *
117
 * Cherry-picked from:
118
 *  0004-Update-Skytraq-driver-to-support-Venus8-modules-chan.patch
119
 * by Kai Harrekilde-Petersen in:
120
 *  https://lists.gnu.org/archive/html/gpsd-dev/2018-03/msg00025.html
121
*/
122
static void sky_mode(struct gps_device_t *session, int mode)
123
0
{
124
0
    char msg[] = {
125
0
        0xA0, 0xA1,    // start-of-sentence sequence
126
0
        0x00, 0x03,
127
0
        0x09,          // SKY_CONFIG_MSG_TYPE
128
0
        0x00, 0x00, 0x00,
129
0
        0x0D, 0x0A     // end-of-sentence sequence
130
0
    };
131
0
    if (MODE_BINARY == mode) {
132
0
        msg[5] = 0x02;
133
0
    } else {                   // else to MODE_NMEA
134
0
        msg[5] = 0x01;
135
0
    }
136
137
0
    GPSD_LOG(LOG_PROG, &session->context->errout,
138
0
             "Skytraq: setting MODE %s\n",
139
0
             (MODE_BINARY == mode) ? "Binary" : "NMEA");
140
0
    (void)sky_write(session, msg, 10);
141
0
}
142
143
/*
144
 * Convert PRN to gnssid and svid
145
 *
146
 * svId is always 0 to 99.
147
 */
148
static void PRN2_gnssId_svId(short PRN, uint8_t *gnssId, uint8_t *svId)
149
7.75k
{
150
    // fit into gnssid:svid
151
7.75k
    if (0 == PRN) {
152
        // skip 0 PRN
153
565
        *gnssId = 0;
154
565
        *svId = 0;
155
7.19k
    } else if ((1 <= PRN) &&
156
7.19k
               (32 >= PRN)) {
157
        // GPS
158
1.26k
        *gnssId = 0;
159
1.26k
        *svId = PRN;
160
5.92k
    } else if ((65 <= PRN) &&
161
4.98k
               (96 >= PRN)) {
162
        // GLONASS
163
1.00k
        *gnssId = 6;
164
1.00k
        *svId = PRN - 64;
165
4.92k
    } else if ((120 <= PRN) &&
166
3.43k
               (158 >= PRN)) {
167
        // SBAS
168
727
        *gnssId = 1;
169
727
        *svId = PRN;
170
4.19k
    } else if ((201 <= PRN) &&
171
2.08k
               (239 >= PRN)) {
172
        // BeiDou
173
698
        *gnssId = 3;
174
698
        *svId = PRN - 200;
175
3.49k
    } else if ((240 <= PRN) &&
176
1.38k
               (254 >= PRN)) {
177
        // IRNSS
178
550
        *gnssId = 20;
179
550
        *svId = PRN - 240;
180
2.94k
    } else {
181
        // huh?
182
2.94k
        *gnssId = 0;
183
2.94k
        *svId = 0;
184
2.94k
    }
185
7.75k
    return;
186
7.75k
}
187
188
/*
189
 decode MID 0x62 -- super packet
190
 *
191
 * Present in Phoenix
192
 */
193
static gps_mask_t sky_msg_62(struct gps_device_t *session,
194
                             const unsigned char *buf, const size_t len)
195
699
{
196
699
    unsigned sid;
197
699
    unsigned u[23];
198
699
    int i;
199
200
699
    if (3 > len) {
201
154
        GPSD_LOG(LOG_WARN, &session->context->errout,
202
154
                 "Skytraq 0x62: bad len %zu\n", len);
203
154
        return 0;
204
154
    }
205
206
545
    sid = getub(buf, 1);
207
545
    switch (sid) {
208
211
    case  0x80:
209
        // SBAS status
210
211
        if (8 < len) {
211
68
            GPSD_LOG(LOG_WARN, &session->context->errout,
212
68
                     "Skytraq 0x62/80: bad len %zu\n", len);
213
68
            return 0;
214
68
        }
215
1.00k
        for (i = 0; i < 6; i++) {
216
858
            u[i] = getub(buf, i + 2);
217
858
        }
218
143
        GPSD_LOG(LOG_PROG, &session->context->errout,
219
143
                 "Skytraq 0x62/80: enable %u ranging %u URA mask %u "
220
143
                 "correction %u chans %u subsystems %u \n",
221
143
                 u[0], u[1], u[2], u[3], u[4], u[5]);
222
143
        break;
223
80
    case  0x81:
224
        // QXSS status
225
80
        u[0] = getub(buf, 2);
226
80
        u[1] = getub(buf, 3);
227
80
        GPSD_LOG(LOG_PROG, &session->context->errout,
228
80
                 "Skytraq 0x62/81: enable %u chans %u\n",
229
80
                 u[0], u[1]);
230
80
        break;
231
113
    case  0x82:
232
        // SBAS advanced status
233
113
        if (46 < len) {
234
44
            GPSD_LOG(LOG_WARN, &session->context->errout,
235
44
                     "Skytraq 0x62/82: bad len %zu\n", len);
236
44
            return 0;
237
44
        }
238
1.58k
        for (i = 0; i < 22; i++) {
239
1.51k
            u[i] = getub(buf, i + 2);
240
1.51k
        }
241
69
        GPSD_LOG(LOG_PROG, &session->context->errout,
242
69
                 "Skytraq 0x62/82: enable %u ranging %u URA %u corr %u "
243
69
                 "chans %u mask x%02x WAAS %u %u %u %u "
244
69
                 "EGNOS %u %u %u %u MSAS %u %u %u %u "
245
69
                 "GAGAN %u %u %u %u\n",
246
69
                 u[0], u[1], u[2], u[3], u[4], u[5], u[6], u[7], u[8],
247
69
                 u[9], u[10], u[11], u[12], u[13], u[14], u[15], u[16], u[17],
248
69
                 u[18], u[19], u[20], u[21]);
249
69
        break;
250
141
    default:
251
141
        GPSD_LOG(LOG_PROG, &session->context->errout,
252
545
                 "Skytraq 0x62: SID x%02x len %zu\n", sid, len);
253
545
    }
254
433
    return 0;
255
545
}
256
257
/*
258
 * decode MID 0x63 -- super packet
259
 *
260
 * Present in Phoenix
261
 */
262
static gps_mask_t sky_msg_63(struct gps_device_t *session,
263
                             const unsigned char *buf, const size_t len)
264
679
{
265
679
    unsigned sid;
266
267
679
    if (3 > len) {
268
569
        GPSD_LOG(LOG_WARN, &session->context->errout,
269
569
                 "Skytraq 0x63: bad len %zu\n", len);
270
569
        return 0;
271
569
    }
272
273
110
    sid = getub(buf, 1);
274
275
    // FIXME: decode them!
276
110
    GPSD_LOG(LOG_PROG, &session->context->errout,
277
110
             "Skytraq 0x63: SID %u\n", sid);
278
110
    return 0;
279
679
}
280
281
/*
282
 * decode MID 0x64 -- super packet
283
 *
284
 * Present in Phoenix
285
 */
286
static gps_mask_t sky_msg_64(struct gps_device_t *session,
287
                             const unsigned char *buf, const size_t len)
288
1.19k
{
289
1.19k
    unsigned sid;
290
1.19k
    unsigned u[13];
291
1.19k
    int i;
292
1.19k
    int s[3];
293
294
1.19k
    if (3 > len) {
295
73
        GPSD_LOG(LOG_WARN, &session->context->errout,
296
73
                 "Skytraq 0x64: bad len %zu\n", len);
297
73
        return 0;
298
73
    }
299
300
1.12k
    sid = getub(buf, 1);
301
1.12k
    switch (sid) {
302
49
    case  0x80:
303
        // GNSS Boot status
304
49
        u[0] = getub(buf, 2);
305
49
        u[1] = getub(buf, 3);
306
49
        GPSD_LOG(LOG_PROG, &session->context->errout,
307
49
                 "Skytraq 0x64/80: enable %u type %u\n",
308
49
                 u[0], u[1]);
309
49
        break;
310
135
    case  0x81:
311
        // Extended NMEA Message Interval
312
135
        if (14 > len) {
313
56
            GPSD_LOG(LOG_WARN, &session->context->errout,
314
56
                     "Skytraq 0x64/81: bad len %zu\n", len);
315
56
            return 0;
316
56
        }
317
1.02k
        for (i = 0; i < 12; i++) {
318
948
            u[i] = getub(buf, i + 2);
319
948
        }
320
79
        GPSD_LOG(LOG_PROG, &session->context->errout,
321
79
                 "Skytraq 0x64/81: GGA %u GSA %u GSV %u GLL %u RMC %u "
322
79
                 "VTG %u ZDA %u GNS %u GBS %u GRS %u DTM %u GST %u\n",
323
79
                 u[0], u[1], u[2], u[3], u[4], u[5], u[6], u[7], u[8],
324
79
                 u[9], u[10], u[11]);
325
79
        break;
326
73
    case  0x83:
327
        // Interference Detection Status
328
73
        u[0] = getub(buf, 2);
329
73
        u[1] = getub(buf, 3);
330
73
        GPSD_LOG(LOG_PROG, &session->context->errout,
331
73
                 "Skytraq 0x64/83: enable %u status %u\n",
332
73
                 u[0], u[1]);
333
73
        break;
334
59
    case  0x85:
335
        // GPS PARAMETER SEARCH ENGINE NUMBER
336
59
        u[0] = getub(buf, 2);
337
59
        GPSD_LOG(LOG_PROG, &session->context->errout,
338
59
                 "Skytraq 0x64/85: search engine number %u\n", u[0]);
339
59
        break;
340
74
    case  0x88:
341
        // Position/Fix navigation mask
342
74
        u[0] = getub(buf, 2);
343
74
        u[1] = getub(buf, 3);
344
74
        GPSD_LOG(LOG_PROG, &session->context->errout,
345
74
                 "Skytraq 0x64/88: 1st %u subsequent %u\n",
346
74
                 u[0], u[1]);
347
74
        break;
348
52
    case  0x8a:
349
        // GPS UTC Reference time
350
52
        if (7 > len) {
351
1
            GPSD_LOG(LOG_WARN, &session->context->errout,
352
1
                     "Skytraq 0x64/8a: bad len %zu\n", len);
353
1
            return 0;
354
1
        }
355
51
        u[0] = getub(buf, 2);
356
51
        u[1] = getbeu16(buf, 3);
357
51
        u[2] = getub(buf, 5);
358
51
        u[3] = getub(buf, 6);
359
51
        GPSD_LOG(LOG_PROG, &session->context->errout,
360
51
                 "Skytraq 0x64/8a: enable %u year %u month %u day %u\n",
361
51
                 u[0], u[1], u[2], u[3]);
362
51
        break;
363
142
    case  0x8b:
364
        // GNSS Nav mode
365
142
        u[0] = getub(buf, 2);
366
142
        GPSD_LOG(LOG_PROG, &session->context->errout,
367
142
                 "Skytraq 0x64/8b: mode %u\n", u[0]);
368
142
        break;
369
116
    case  0x8c:
370
        // GNSS Constellation type for nav solution
371
116
        u[0] = getbeu16(buf, 2);
372
116
        GPSD_LOG(LOG_PROG, &session->context->errout,
373
116
                 "Skytraq 0x64/8c: Nav Type x%02x\n", u[0]);
374
116
        break;
375
70
    case  0x8e:
376
        // GPS time
377
70
        u[0] = getbeu32(buf, 2);    // TOW ms
378
70
        u[1] = getbeu32(buf, 6);    // TOW ns
379
70
        u[2] = getbeu16(buf, 10);   // GPS week
380
70
        s[0] = getsb(buf, 12);      // default leap s
381
70
        s[1] = getsb(buf, 13);      // current leap s
382
70
        u[3] = getub(buf, 14);      // valid
383
        // FIXME: save GPS week and leap s
384
70
        GPSD_LOG(LOG_PROG, &session->context->errout,
385
70
                 "Skytraq 0x64/8a: TOW %u %u week %u leap %d %d valid x%x\n",
386
70
                 u[0], u[1], u[2], s[0], s[1], u[3]);
387
70
        break;
388
53
    case  0x92:
389
        // GLONASS Time corrections
390
53
        s[0] = getbes32(buf, 2);    // tau c
391
53
        s[1] = getbes32(buf, 6);    // tau gps
392
53
        GPSD_LOG(LOG_PROG, &session->context->errout,
393
53
                 "Skytraq 0x64/92: tau c %d tau GPS %d\n",
394
53
                 s[0], s[1]);
395
53
        break;
396
83
    case  0xfe:
397
        // Version extension string
398
83
        GPSD_LOG(LOG_PROG, &session->context->errout,
399
83
                 "Skytraq 0x64/fe: >%.32s<\n", &buf[2]);
400
83
        break;
401
218
    default:
402
218
        GPSD_LOG(LOG_PROG, &session->context->errout,
403
1.12k
                 "Skytraq 0x64: SID x%02x len %zu\n", sid, len);
404
1.12k
    }
405
1.06k
    return 0;
406
1.12k
}
407
408
/*
409
 * decode MID 0x65 -- super packet
410
 *
411
 * Present in Phoenix
412
 */
413
static gps_mask_t sky_msg_65(struct gps_device_t *session,
414
                             const unsigned char *buf, const size_t len)
415
728
{
416
728
    unsigned sid;
417
728
    unsigned u[13];
418
419
728
    if (3 > len) {
420
425
        GPSD_LOG(LOG_WARN, &session->context->errout,
421
425
                 "Skytraq 0x65: bad len %zu\n", len);
422
425
        return 0;
423
425
    }
424
425
303
    sid = getub(buf, 1);
426
303
    switch (sid) {
427
63
    case  0x80:
428
        // 1PPS Pulse width
429
63
        u[0] = getbeu32(buf, 2);    // pulse width miicro seconds
430
63
        GPSD_LOG(LOG_PROG, &session->context->errout,
431
63
                 "Skytraq 0x65/80: width %u\n", u[0]);
432
63
        break;
433
70
    case  0x81:
434
        // PPS2 frequency
435
70
        u[0] = getbeu32(buf, 2);    // freq of PPS2 Hz
436
70
        GPSD_LOG(LOG_PROG, &session->context->errout,
437
70
                 "Skytraq 0x65/81: PPS2 Hz %u\n", u[0]);
438
70
        break;
439
170
    default:
440
170
        GPSD_LOG(LOG_PROG, &session->context->errout,
441
303
                 "Skytraq 0x65: SID x%02x len %zu\n", sid, len);
442
303
    }
443
303
    return 0;
444
303
}
445
446
/*
447
 * decode MID 0x6A -- super packet
448
 *
449
 * Present in Phoenix
450
 */
451
static gps_mask_t sky_msg_6A(struct gps_device_t *session,
452
                             const unsigned char *buf, const size_t len)
453
769
{
454
769
    unsigned sid;
455
769
    unsigned u[13];
456
769
    double d[5];
457
458
769
    if (3 > len) {
459
382
        GPSD_LOG(LOG_WARN, &session->context->errout,
460
382
                 "Skytraq 0x6A: bad len %zu\n", len);
461
382
        return 0;
462
382
    }
463
464
387
    sid = getub(buf, 1);
465
387
    switch (sid) {
466
72
    case  0x83:
467
        // RTK mode and operational functioN
468
72
        u[0] = getub(buf, 2);                // RTK mode
469
72
        u[1] = getub(buf, 3);                // RTK function
470
72
        u[2] = getbeu32(buf, 4);             // saved survey length
471
72
        u[3] = getbeu32(buf, 8);             // standard deviation
472
72
        d[0] = getled64((const char *)buf, 12);    // latitude
473
72
        d[1] = getled64((const char *)buf, 20);    // longitude
474
72
        d[3] = getlef32((const char *)buf, 28);    // altitude (HAE or MSL?)
475
72
        u[4] = getub(buf, 32);               // runtime function
476
72
        u[5] = getbeu32(buf, 33);            // run-time survey length
477
72
        d[4] = getlef32((const char *)buf, 37);    // baseline length constant
478
72
        GPSD_LOG(LOG_PROG, &session->context->errout,
479
72
                 "Skytraq 0x6A/83: mode %u func %u len %u sdev %u lat %.8f "
480
72
                 "lon %.8f alt %.4f func %u len %u len %.4f\n",
481
72
                 u[0], u[1], u[2], u[3], d[0], d[1], d[3], u[4], u[5], d[4]);
482
72
        break;
483
107
    case  0x85:
484
        // RTK slave base serial port baud ratE
485
107
        u[0] = getub(buf, 2);        // rate code
486
107
        GPSD_LOG(LOG_PROG, &session->context->errout,
487
107
                 "Skytraq 0x6A/85: rate %u\n", u[0]);
488
107
        break;
489
93
    case  0x88:
490
        // RTK kinematic base serial port baud ratE
491
93
        u[0] = getub(buf, 2);        // rate code
492
93
        GPSD_LOG(LOG_PROG, &session->context->errout,
493
93
                 "Skytraq 0x6A/88: rate %u\n", u[0]);
494
93
        break;
495
115
    default:
496
115
        GPSD_LOG(LOG_PROG, &session->context->errout,
497
387
                 "Skytraq 0x6A: SID x%02x len %zu\n", sid, len);
498
387
    }
499
387
    return 0;
500
387
}
501
502
/*
503
 * decode MID 0x7A -- super packet
504
 *
505
 * Present in Phoenix
506
 */
507
static gps_mask_t sky_msg_7A(struct gps_device_t *session,
508
                             const unsigned char *buf, const size_t len)
509
294
{
510
294
    unsigned sid, ssid;
511
294
    unsigned u[16];
512
294
    double d[2];
513
294
    int i;
514
515
294
    if (3 > len) {
516
156
        GPSD_LOG(LOG_WARN, &session->context->errout,
517
156
                 "Skytraq 0x7A: bad len %zu\n", len);
518
156
        return 0;
519
156
    }
520
521
138
    sid = getub(buf, 1);
522
138
    ssid = getub(buf, 2);
523
138
    switch ((sid << 8) | ssid) {
524
3
    case 0x0e80:
525
        // Moving base software version
526
3
        if (16 > len) {
527
1
            GPSD_LOG(LOG_WARN, &session->context->errout,
528
1
                     "Skytraq 0x7A/0E/80: bad len %zu\n", len);
529
1
            return 0;
530
1
        }
531
28
        for (i = 0; i < 13; i++) {
532
26
            u[i] = getub(buf, i + 3);
533
26
        }
534
2
        GPSD_LOG(LOG_PROG, &session->context->errout,
535
2
                 "Skytraq 0x7A/0E/80: type %u "
536
2
                  "kver %u.%u.%u over %u.%u.%u rev %02u.%02u.%02u\n",
537
2
                 u[0], u[2], u[3], u[4], u[6], u[7], u[8], u[10],
538
2
                 u[11], u[12]);
539
2
        break;
540
1
    case 0x0e81:
541
        // Moving base software CRC
542
1
        u[0] = getub(buf, 3);
543
1
        u[1] = getbeu16(buf, 4);
544
545
1
        GPSD_LOG(LOG_PROG, &session->context->errout,
546
1
                 "Skytraq  0x7A/0E/801: type %u crc %u\n", u[0], u[1]);
547
1
        break;
548
1
    case 0x0e82:
549
        // Moving base pos update rate
550
1
        u[0] = getub(buf, 3);
551
552
1
        GPSD_LOG(LOG_PROG, &session->context->errout,
553
1
                 "Skytraq  0x7A/0E/802: rate %u\n", u[0]);
554
1
        break;
555
1
    case 0x0e83:
556
        // Moving base heading and pitch offsets
557
1
        d[0] = getbeu32(buf, 3);    // heading
558
1
        d[1] = getbeu32(buf, 7);    // pitch
559
560
1
        GPSD_LOG(LOG_PROG, &session->context->errout,
561
1
                 "Skytraq  0x7A/0E/803: heading %f pitch %f\n", d[0], d[1]);
562
1
        break;
563
132
    default:
564
132
        GPSD_LOG(LOG_PROG, &session->context->errout,
565
138
                 "Skytraq 0x7A: SID x%02x/%02x len %zu\n", sid, ssid, len);
566
138
    }
567
137
    return 0;
568
138
}
569
570
/*
571
 * decode MID 0x80, Software Version
572
 *
573
 * 10 bytes
574
 *
575
 * Present in: Venus 6
576
 *             Venus 8
577
 *             Phoenix
578
 */
579
static gps_mask_t sky_msg_80(struct gps_device_t *session,
580
                             const unsigned char *buf, const size_t len)
581
310
{
582
310
    unsigned kver_x;  // kernel version
583
310
    unsigned kver_y;  // kernel version
584
310
    unsigned kver_z;  // kernel version
585
310
    unsigned over_x;  // ODM version
586
310
    unsigned over_y;  // ODM version
587
310
    unsigned over_z;  // ODM version
588
310
    unsigned rev_yy;  // revision
589
310
    unsigned rev_mm;  // revision
590
310
    unsigned rev_dd;  // revision
591
592
310
    if (14 != len) {
593
240
        return 0;
594
240
    }
595
596
70
    kver_x  = getbeu16(buf, 2);
597
70
    kver_y  = getub(buf, 4);
598
70
    kver_z  = getub(buf, 5);
599
70
    over_x  = getbeu16(buf, 6);
600
70
    over_y  = getub(buf, 8);
601
70
    over_z  = getub(buf, 9);
602
70
    rev_yy  = getbeu16(buf, 10);
603
70
    rev_mm  = getub(buf, 12);
604
70
    rev_dd  = getub(buf, 13);
605
606
70
    (void)snprintf(session->subtype, sizeof(session->subtype) - 1,
607
70
                   "kver %u.%u.%u over %u.%u.%u rev %02u.%02u.%02u",
608
70
                   kver_x, kver_y, kver_z,
609
70
                   over_x, over_y, over_z,
610
70
                   rev_yy, rev_mm, rev_dd);
611
612
70
    GPSD_LOG(LOG_PROG, &session->context->errout,
613
70
             "Skytraq 0x80: %s\n",
614
70
             session->subtype);
615
70
    return 0;
616
310
}
617
618
/*
619
 * decode MID 0x81 - Software CRC
620
 *
621
 * Present in Phoenix
622
 */
623
static gps_mask_t sky_msg_81(struct gps_device_t *session,
624
                             const unsigned char *buf, const size_t len)
625
200
{
626
200
    unsigned type, crc;
627
628
200
    if (4 != len) {
629
140
        GPSD_LOG(LOG_WARN, &session->context->errout,
630
140
                 "Skytraq 0x81: bad len %zu\n", len);
631
140
        return 0;
632
140
    }
633
634
60
    type = getub(buf, 1);
635
60
    crc  = getbeu16(buf, 2);
636
637
60
    GPSD_LOG(LOG_PROG, &session->context->errout,
638
60
             "Skytraq 0x81: type %u crc %u\n", type, crc);
639
60
    return 0;
640
200
}
641
642
/*
643
 * decode MID 0x86 - Position Update Rate
644
 *
645
 * Present in Phoenix
646
 */
647
static gps_mask_t sky_msg_86(struct gps_device_t *session,
648
                             const unsigned char *buf, const size_t len)
649
225
{
650
225
    unsigned rate;
651
652
225
    if (2 != len) {
653
155
        GPSD_LOG(LOG_WARN, &session->context->errout,
654
155
                 "Skytraq 0x86: bad len %zu\n", len);
655
155
        return 0;
656
155
    }
657
658
70
    rate = getub(buf, 1);
659
660
70
    GPSD_LOG(LOG_PROG, &session->context->errout,
661
70
             "Skytraq 0x86: rate %u\n", rate);
662
70
    return 0;
663
225
}
664
665
/*
666
 * decode MID 0x89 - Binary measurement data output status
667
 *
668
 * Present in Phoenix
669
 */
670
static gps_mask_t sky_msg_89(struct gps_device_t *session,
671
                             const unsigned char *buf, const size_t len)
672
204
{
673
204
    unsigned i;
674
204
    uint8_t u[7];
675
676
204
    if (8 != len) {
677
133
        GPSD_LOG(LOG_WARN, &session->context->errout,
678
133
                 "Skytraq 0x89: bad len %zu\n", len);
679
133
        return 0;
680
133
    }
681
682
568
    for (i = 0; i < 7; i++) {
683
497
        u[i] = getub(buf, i + 1);
684
497
    }
685
71
    GPSD_LOG(LOG_PROG, &session->context->errout,
686
71
             "Skytraq 0x89: rate %u Meas %u raw %u CH_status %u "
687
71
             "RCV_statas %u subf %u eraw %u\n",
688
71
             u[0], u[1], u[2], u[3], u[4], u[5], u[6]);
689
690
71
    return 0;
691
204
}
692
693
/*
694
 * decode MID 0x8A - Binary rtcm data output status
695
 *
696
 * Present in Phoenix
697
 */
698
static gps_mask_t sky_msg_8A(struct gps_device_t *session,
699
                             const unsigned char *buf, const size_t len)
700
1.06k
{
701
1.06k
    unsigned i;
702
1.06k
    uint8_t u[15];
703
704
1.06k
    if (16 != len) {
705
1.00k
        GPSD_LOG(LOG_WARN, &session->context->errout,
706
1.00k
                 "Skytraq 0x8A: bad len %zu\n", len);
707
1.00k
        return 0;
708
1.00k
    }
709
710
1.08k
    for (i = 0; i < 15; i++) {
711
1.02k
        u[i] = getub(buf, i + 1);
712
1.02k
    }
713
68
    GPSD_LOG(LOG_PROG, &session->context->errout,
714
68
             "Skytraq 0x8A: enable %u MSM %u 1005 %u 107x %u 108x %u "
715
68
             "109x %u 110x %u 111x %u 112x %u 1019 %u 1020 %u "
716
68
             "1042 %u 1046 %u type %u version %u\n",
717
68
             u[0], u[1], u[2], u[3], u[4], u[5], u[6], u[7],
718
68
             u[8], u[9], u[10], u[11], u[12], u[13], u[14]);
719
720
68
    return 0;
721
1.06k
}
722
723
/*
724
 * decode MID 0x8B - Base position
725
 *
726
 * Present in Phoenix
727
 */
728
static gps_mask_t sky_msg_8B(struct gps_device_t *session,
729
                             const unsigned char *buf, const size_t len)
730
268
{
731
268
    uint8_t u[5];
732
268
    double d[3];
733
734
268
    if (35 != len) {
735
146
        GPSD_LOG(LOG_WARN, &session->context->errout,
736
146
                 "Skytraq 0x8B: bad len %zu\n", len);
737
146
        return 0;
738
146
    }
739
740
122
    u[0] = getub(buf, 1);
741
122
    u[1] = getbeu32(buf, 2);
742
122
    u[2] = getbeu32(buf, 6);
743
122
    d[0] = getbed64((const char *)buf, 10);
744
122
    d[1] = getbed64((const char *)buf, 18);
745
122
    d[2] = getbef32((const char *)buf, 26);
746
122
    u[3] = getub(buf, 30);
747
122
    u[4] = getbeu32(buf, 31);
748
749
122
    GPSD_LOG(LOG_PROG, &session->context->errout,
750
122
             "Skytraq 0x8B: saved mode %u saved length %u stddev %u "
751
122
             "lat %.9f lon %.9f HAE %0.4f run mode %u survey len %u\n",
752
122
             u[0], u[1], u[2], d[0], d[1], d[2], u[3], u[4]);
753
754
122
    return 0;
755
268
}
756
757
/*
758
 * decode MID 0x93 - NMEA Talker ID
759
 *
760
 * Present in Phoenix
761
 */
762
static gps_mask_t sky_msg_93(struct gps_device_t *session,
763
                             const unsigned char *buf, const size_t len)
764
361
{
765
361
    unsigned mode;
766
767
361
    if (2 != len) {
768
161
        GPSD_LOG(LOG_WARN, &session->context->errout,
769
161
                 "Skytraq 0x93: bad len %zu\n", len);
770
161
        return 0;
771
161
    }
772
773
200
    mode = getub(buf, 1);
774
775
200
    GPSD_LOG(LOG_PROG, &session->context->errout,
776
200
             "Skytraq 0x93: mode %u\n", mode);
777
200
    return 0;
778
361
}
779
780
/*
781
 * Binary Navigation Data Message (0xA8)
782
 * Returns 59 bytes;
783
 * Fix Mode, SV, Week, TOW, Latitude, Longitude, ellipsoid altitude,
784
 * mean sea level altitude, gdop, pdop, hdop, vdop, tdop,
785
 * ecef.{x,y,z}, ecef_v.{x,y,z}
786
 *
787
 * The following message (0xA8) is emitted by the modules supporting
788
 * the Binary Messages Raw Measurements Data Extension in AN0028
789
 * (https://www.skytraq.com.tw/homesite/AN0028.pdf)
790
 * Original implementation by Kai Harrekilde-Petersen
791
 * and adapted by Thatcher Chamberlin (j.thatcher.c@gmail.com)
792
 */
793
static gps_mask_t sky_msg_A8(struct gps_device_t *session,
794
                   const unsigned char *buf, const size_t len)
795
323
{
796
323
    unsigned char  navmode; // Navigation fix mode (0: No fix, 1: 2D, 2: 3D, 3: 3D+DGNSS
797
323
    unsigned short week;    // GNSS week number
798
323
    double   ftow;       // Time of week
799
323
    timespec_t ts_tow;
800
323
    char ts_buf[TIMESPEC_LEN];
801
802
323
    int *mode = &session->newdata.mode;
803
323
    int *status = &session->newdata.status;
804
323
    gps_mask_t mask = 0;
805
806
323
    if (59 != len) {
807
295
        GPSD_LOG(LOG_INF, &session->context->errout, "Skytraq: "
808
295
            "Navigation Data Message has incorrect length %zu\n", len);
809
295
        return 0;
810
295
    }
811
812
28
    navmode = getub(buf, 1);
813
28
    switch (navmode) {
814
4
    case 1: // 2D fix
815
4
        *mode = MODE_2D;
816
4
        *status = STATUS_GPS;
817
4
        break;
818
1
    case 2: // 3D fix
819
1
        *mode = MODE_3D;
820
1
        *status = STATUS_GPS;
821
1
        break;
822
0
    case 3: // 3D DGPS fix
823
0
        *mode = MODE_3D;
824
0
        *status = STATUS_DGPS;
825
0
        break;
826
827
23
    default: // Includes SKY_MODE_NONE
828
23
        *mode = MODE_NO_FIX;
829
23
        *status = STATUS_UNK;
830
23
        break;
831
28
    }
832
28
    mask |= MODE_SET | STATUS_SET;
833
834
28
    session->gpsdata.satellites_used = getub(buf, 2);
835
836
28
    mask |= ONLINE_SET;
837
28
    week = getbeu16(buf,  3);
838
28
    ftow = getbeu32(buf,  5) / 100.0;
839
28
    DTOTS(&ts_tow, (int)ftow);
840
841
28
    session->newdata.time = gpsd_gpstime_resolv(session, week, ts_tow);
842
28
    mask |= TIME_SET;
843
844
28
    if (MODE_2D == *mode || MODE_3D == *mode) {
845
5
        session->newdata.latitude  = getbes32(buf,  9) / 1e7;
846
5
        session->newdata.longitude = getbes32(buf, 13) / 1e7;
847
5
        mask |= LATLON_SET | NTPTIME_IS;
848
849
5
        if (MODE_3D == *mode) {
850
1
            session->newdata.altHAE  = getbes32(buf, 17) / 100.0;
851
1
            session->newdata.altMSL  = getbes32(buf, 21) / 100.0;
852
853
1
            session->newdata.ecef.x  = getbes32(buf, 35) / 100.0;
854
1
            session->newdata.ecef.y  = getbes32(buf, 39) / 100.0;
855
1
            session->newdata.ecef.z  = getbes32(buf, 43) / 100.0;
856
1
            session->newdata.ecef.vx = getbes32(buf, 47) / 100.0;
857
1
            session->newdata.ecef.vy = getbes32(buf, 51) / 100.0;
858
1
            session->newdata.ecef.vz = getbes32(buf, 55) / 100.0;
859
1
            mask |= ECEF_SET | VECEF_SET | ALTITUDE_SET;
860
1
        }
861
5
    }
862
863
28
    session->gpsdata.dop.gdop = getbeu16(buf, 25) / 100.0;
864
28
    session->gpsdata.dop.pdop = getbeu16(buf, 27) / 100.0;
865
28
    session->gpsdata.dop.hdop = getbeu16(buf, 29) / 100.0;
866
28
    session->gpsdata.dop.vdop = getbeu16(buf, 31) / 100.0;
867
28
    session->gpsdata.dop.tdop = getbeu16(buf, 33) / 100.0;
868
28
    mask |= DOP_SET | CLEAR_IS | REPORT_IS;
869
28
    GPSD_LOG(LOG_DATA, &session->context->errout,
870
28
         "Skytraq: NAVDATA time=%s, lat=%.7f lon=%.7f altHAE=%.2f altMSL=%.2f mode=%d status=%d "
871
28
         "gdop: %.2f, hdop: %.2f, pdop: %.2f, tdop: %.2f, vdop: %.2f\n",
872
28
         timespec_str(&session->newdata.time, ts_buf, sizeof(ts_buf)),
873
28
         session->newdata.latitude,
874
28
         session->newdata.longitude,
875
28
         session->newdata.altHAE,
876
28
         session->newdata.altMSL,
877
28
         session->newdata.mode,
878
28
         session->newdata.status,
879
28
         session->gpsdata.dop.gdop,
880
28
         session->gpsdata.dop.hdop,
881
28
         session->gpsdata.dop.pdop,
882
28
         session->gpsdata.dop.tdop,
883
28
         session->gpsdata.dop.vdop);
884
28
    return mask;
885
28
}
886
887
/*
888
 * decode MID 0xAE - GNSS Datum
889
 *
890
 * Present in Phoenix
891
 */
892
static gps_mask_t sky_msg_AE(struct gps_device_t *session,
893
                             const unsigned char *buf, const size_t len)
894
1.29k
{
895
1.29k
    unsigned datum;
896
897
1.29k
    if (3 != len) {
898
1.01k
        GPSD_LOG(LOG_WARN, &session->context->errout,
899
1.01k
                 "Skytraq 0xAE: bad len %zu\n", len);
900
1.01k
        return 0;
901
1.01k
    }
902
903
279
    datum  = getbeu16(buf, 1);
904
905
279
    GPSD_LOG(LOG_PROG, &session->context->errout,
906
279
             "Skytraq 0xAE: datum %u\n", datum);
907
279
    return 0;
908
1.29k
}
909
910
/*
911
 * decode MID 0xaf - DOP mask
912
 *
913
 * Present in Phoenix
914
 */
915
static gps_mask_t sky_msg_AF(struct gps_device_t *session,
916
                             const unsigned char *buf, const size_t len)
917
323
{
918
323
    unsigned mode, pdop, hdop, gdop;
919
920
323
    if (8 != len) {
921
173
        GPSD_LOG(LOG_WARN, &session->context->errout,
922
173
                 "Skytraq 0xAF: bad len %zu\n", len);
923
173
        return 0;
924
173
    }
925
926
150
    mode = getub(buf, 1);
927
150
    pdop = getbeu16(buf, 2);
928
150
    hdop = getbeu16(buf, 4);
929
150
    gdop = getbeu16(buf, 6);
930
931
150
    GPSD_LOG(LOG_PROG, &session->context->errout,
932
150
             "Skytraq 0xAF: Masks: mode %u pdop %u hdop %u gdop %u\n",
933
150
             mode, pdop, hdop, gdop);
934
150
    return 0;
935
323
}
936
937
/*
938
 * decode MID 0xb0 Elevation and DOP mask
939
 *
940
 * Present in Phoenix
941
 */
942
static gps_mask_t sky_msg_B0(struct gps_device_t *session,
943
                             const unsigned char *buf, const size_t len)
944
486
{
945
486
    unsigned select, elevation, cnr;
946
947
486
    if (4 != len) {
948
406
        GPSD_LOG(LOG_WARN, &session->context->errout,
949
406
                 "Skytraq 0xB0: bad len %zu\n", len);
950
406
        return 0;
951
406
    }
952
953
80
    select = getub(buf, 1);
954
80
    elevation = getub(buf, 2);
955
80
    cnr = getub(buf, 3);
956
957
80
    GPSD_LOG(LOG_PROG, &session->context->errout,
958
80
             "Skytraq 0xB0: select %u el %u cnr %u\n",
959
80
             select, elevation, cnr);
960
80
    return 0;
961
486
}
962
963
/*
964
 * decode MID 0xb4 - Position Pinning Status
965
 *
966
 * Present in Phoenix
967
 */
968
static gps_mask_t sky_msg_B4(struct gps_device_t *session,
969
                             const unsigned char *buf, const size_t len)
970
205
{
971
205
    unsigned status, pspeed, pcnt, uspeed, ucnt, udist;
972
973
205
    if (12 != len) {
974
131
        GPSD_LOG(LOG_WARN, &session->context->errout,
975
131
                 "Skytraq 0xB4: bad len %zu\n", len);
976
131
        return 0;
977
131
    }
978
979
74
    status = getub(buf, 1);
980
74
    pspeed = getbeu16(buf, 2);
981
74
    pcnt = getbeu16(buf, 4);
982
74
    uspeed = getbeu16(buf, 6);
983
74
    ucnt = getbeu16(buf, 8);
984
74
    udist = getbeu16(buf, 10);
985
986
74
    GPSD_LOG(LOG_PROG, &session->context->errout,
987
74
             "Skytraq 0xB4: status %u pspeed %u pcnt %u uspeed %u "
988
74
             "ucnt %u udist %u\n",
989
74
             status, pspeed, pcnt, uspeed, ucnt, udist);
990
74
    return 0;
991
205
}
992
993
/*
994
 * decode MID 0xB9 - Power Mode Status
995
 *
996
 * Present in Phoenix
997
 */
998
static gps_mask_t sky_msg_B9(struct gps_device_t *session,
999
                             const unsigned char *buf, const size_t len)
1000
247
{
1001
247
    unsigned mode;
1002
1003
247
    if (2 != len) {
1004
107
        GPSD_LOG(LOG_WARN, &session->context->errout,
1005
107
                 "Skytraq 0xB9: bad len %zu\n", len);
1006
107
        return 0;
1007
107
    }
1008
1009
140
    mode = getub(buf, 1);
1010
1011
140
    GPSD_LOG(LOG_PROG, &session->context->errout,
1012
140
             "Skytraq 0xB9: mode %u\n", mode);
1013
140
    return 0;
1014
247
}
1015
1016
/*
1017
 * decode MID 0xBB - 1PPS Cable Delay
1018
 *
1019
 * Present in Phoenix
1020
 */
1021
static gps_mask_t sky_msg_BB(struct gps_device_t *session,
1022
                             const unsigned char *buf, const size_t len)
1023
143
{
1024
143
    int delay;
1025
1026
143
    if (5 != len) {
1027
142
        GPSD_LOG(LOG_WARN, &session->context->errout,
1028
142
                 "Skytraq 0xBB: bad len %zu\n", len);
1029
142
        return 0;
1030
142
    }
1031
1032
1
    delay = getbeu32(buf, 1);
1033
1034
1
    GPSD_LOG(LOG_PROG, &session->context->errout,
1035
1
             "Skytraq 0xBB: delay %d\n", delay);
1036
1
    return 0;
1037
143
}
1038
1039
/*
1040
 * decode MID 0xDC, Measurement Time
1041
 *
1042
 * 10 bytes
1043
 */
1044
static gps_mask_t sky_msg_DC(struct gps_device_t *session,
1045
                             const unsigned char *buf, const size_t len)
1046
506
{
1047
506
    unsigned iod;   // Issue of data 0 - 255
1048
506
    unsigned wn;    // week number 0 - 65535
1049
506
    unsigned tow;   // receiver tow 0 - 604799999 in mS
1050
506
    unsigned mp;    // measurement period 1 - 1000 ms
1051
506
    char ts_buf[TIMESPEC_LEN];
1052
506
    timespec_t ts_tow;
1053
1054
506
    if (10 != len) {
1055
403
        return 0;
1056
403
    }
1057
1058
103
    iod = (unsigned)getub(buf, 1);
1059
103
    wn = getbeu16(buf, 2);
1060
103
    tow = getbeu32(buf, 4);
1061
103
    mp = getbeu16(buf, 8);
1062
103
    MSTOTS(&ts_tow, tow);
1063
1064
    // should this be newdata.skyview_time?
1065
103
    session->gpsdata.skyview_time = gpsd_gpstime_resolv(session, wn, ts_tow);
1066
1067
103
    GPSD_LOG(LOG_DATA, &session->context->errout,
1068
103
             "Skytraq 0xDC: iod %u wn %u tow %u mp %u t%s\n",
1069
103
             iod, wn, tow, mp,
1070
103
             timespec_str(&session->gpsdata.skyview_time, ts_buf,
1071
103
                          sizeof(ts_buf)));
1072
103
    return 0;
1073
506
}
1074
1075
/*
1076
 * decode MID 0xDD, Raw Measurements
1077
 *
1078
 */
1079
static gps_mask_t sky_msg_DD(struct gps_device_t *session,
1080
                             const unsigned char *buf, const size_t len)
1081
1.14k
{
1082
1.14k
    unsigned i;     // generic loop variable
1083
1084
    // buf[0] os the message ID
1085
    // Issue of data 0 - 255
1086
1.14k
    unsigned iod = getub(buf, 1);
1087
    // number of measurements
1088
1.14k
    unsigned nmeas = getub(buf, 2);
1089
1090
1.14k
    GPSD_LOG(LOG_DATA, &session->context->errout,
1091
1.14k
             "Skytraq 0xDD: iod %u, nmeas %u len %zd\n",
1092
1.14k
             iod, nmeas, len);
1093
1094
1.14k
    if (SKY_CHANNELS < nmeas) {
1095
85
        GPSD_LOG(LOG_WARN, &session->context->errout,
1096
85
                "Skytraq 0x0D: too many measurements %d\n",
1097
85
                 nmeas);
1098
85
        nmeas = SKY_CHANNELS;
1099
85
    }
1100
1101
1.14k
    if (len < (3 + (nmeas * 23))) {
1102
165
        GPSD_LOG(LOG_ERROR, &session->context->errout,
1103
165
                 "Skytraq 0xDD: bad len %zd, s/b %d\n",
1104
165
                 len, 3 + (nmeas & 23));
1105
165
        return 0;
1106
165
    }
1107
1108
    // check IOD?
1109
978
    session->gpsdata.raw.mtime = session->gpsdata.skyview_time;
1110
1111
    /* zero the measurement data
1112
     * so we can tell which meas never got set */
1113
978
    memset(session->gpsdata.raw.meas, 0, sizeof(session->gpsdata.raw.meas));
1114
1115
4.58k
    for (i = 0; i < nmeas; i++) {
1116
3.61k
        const char *obs_code;
1117
3.61k
        int off = 3 + (23 * i);
1118
1119
3.61k
        uint8_t PRN = getub(buf, off + 0);
1120
        // carrier-to-noise density ratio dB-Hz
1121
3.61k
        uint8_t cno = getub(buf, off + 1);
1122
        // pseudorange in meters
1123
3.61k
        double prMes = getbed64((const char *)buf, off + 2);
1124
        // carrier phase in cycles
1125
3.61k
        double cpMes = getbed64((const char *)buf, off + 10);
1126
        // doppler in Hz, positive towards sat
1127
3.61k
        double doMes = getbef32((const char *)buf, off + 18);
1128
1129
        /* tracking stat
1130
         * bit 0 - prMes valid
1131
         * bit 1 - doppler valid
1132
         * bit 2 - cpMes valid
1133
         * bit 3 - cp slip
1134
         * bit 4 - Coherent integration time?
1135
         */
1136
3.61k
        uint8_t trkStat = getub(buf, off + 22);
1137
3.61k
        uint8_t gnssId = 0;
1138
        // svId should always be from 0 to 99, except SBAS.
1139
3.61k
        uint8_t svId = 0;
1140
3.61k
        PRN2_gnssId_svId(PRN, &gnssId, &svId);
1141
1142
3.61k
        session->gpsdata.raw.meas[i].gnssid = gnssId;
1143
3.61k
        switch (gnssId) {
1144
2.23k
        case 0:       // GPS
1145
2.23k
            FALLTHROUGH
1146
2.23k
        case 5:       // QZSS
1147
2.23k
            FALLTHROUGH
1148
2.39k
        case 20:      // IRNSS, just guessing here
1149
2.39k
            obs_code = "L1C";       // u-blox calls this L1C/A ?
1150
2.39k
            break;
1151
468
        case 1:       // SBAS
1152
468
            if (100 < svId) {
1153
                // Should be always true, but pacify Coverity 498045
1154
468
                svId -= 100;            // adjust for RINEX 3 svid
1155
468
            }
1156
468
            obs_code = "L1C";       // u-blox calls this L1C/A
1157
468
            break;
1158
0
        case 2:       // GALILEO
1159
0
            obs_code = "L1B";       // u-blox calls this E1OS
1160
0
            break;
1161
241
        case 3:       // BeiDou
1162
241
            obs_code = "L2I";       // u-blox calls this B1I
1163
241
            break;
1164
0
        default:      // huh?
1165
0
            FALLTHROUGH
1166
0
        case 4:       // IMES.  really?
1167
0
            obs_code = "";       // u-blox calls this L1
1168
0
            break;
1169
509
        case 6:       // GLONASS
1170
509
            obs_code = "L1C";       // u-blox calls this L1OF
1171
509
            break;
1172
3.61k
        }
1173
3.61k
        (void)strlcpy(session->gpsdata.raw.meas[i].obs_code, obs_code,
1174
3.61k
                      sizeof(session->gpsdata.raw.meas[i].obs_code));
1175
1176
3.61k
        session->gpsdata.raw.meas[i].svid = svId;
1177
3.61k
        session->gpsdata.raw.meas[i].snr = cno;
1178
3.61k
        session->gpsdata.raw.meas[i].satstat = trkStat;
1179
3.61k
        if (trkStat & 1) {
1180
            // prMes valid
1181
2.00k
            session->gpsdata.raw.meas[i].pseudorange = prMes;
1182
2.00k
        } else {
1183
1.60k
            session->gpsdata.raw.meas[i].pseudorange = NAN;
1184
1.60k
        }
1185
3.61k
        if (trkStat & 2) {
1186
            // doppler valid
1187
1.86k
            session->gpsdata.raw.meas[i].doppler = doMes;
1188
1.86k
        } else {
1189
1.74k
            session->gpsdata.raw.meas[i].doppler = NAN;
1190
1.74k
        }
1191
3.61k
        if (trkStat & 4) {
1192
            // cpMes valid
1193
1.70k
            session->gpsdata.raw.meas[i].carrierphase = cpMes;
1194
1.90k
        } else {
1195
1.90k
            session->gpsdata.raw.meas[i].carrierphase = NAN;
1196
1.90k
        }
1197
3.61k
        session->gpsdata.raw.meas[i].codephase = NAN;
1198
3.61k
        session->gpsdata.raw.meas[i].deltarange = NAN;
1199
        // skytraq does not report locktime, so assume max
1200
3.61k
        session->gpsdata.raw.meas[i].locktime = LOCKMAX;
1201
3.61k
        if (trkStat & 8) {
1202
            // possible slip
1203
1.64k
            session->gpsdata.raw.meas[i].lli = 2;
1204
1.64k
        }
1205
3.61k
        GPSD_LOG(LOG_DATA, &session->context->errout,
1206
3.61k
                 "PRN %u (%u:%u) prMes %f cpMes %f doMes %f\n"
1207
3.61k
                 "cno %u  rtkStat %u\n", PRN,
1208
3.61k
                 gnssId, svId, prMes, cpMes, doMes, cno, trkStat);
1209
1210
3.61k
    }
1211
1212
    // return RAW_IS;  // WIP
1213
978
    return 0;
1214
978
}
1215
1216
/*
1217
 * decode MID 0xDE, SV and channel status
1218
 *
1219
 * max payload: 3 + (Num_sats * 10) = 483 bytes
1220
 */
1221
static gps_mask_t sky_msg_DE(struct gps_device_t *session,
1222
                             const unsigned char *buf, const size_t len)
1223
1.42k
{
1224
1.42k
    int st, nsv;
1225
1.42k
    unsigned i;
1226
1.42k
    unsigned iod;   // Issue of data 0 - 255
1227
1.42k
    unsigned nsvs;  // number of SVs in this packet
1228
1229
1.42k
    if (3 > len) {
1230
278
        GPSD_LOG(LOG_WARN, &session->context->errout,
1231
278
                 "Skytraq 0xDE: bad len %zu\n", len);
1232
278
        return 0;
1233
278
    }
1234
1.14k
    iod = (unsigned)getub(buf, 1);
1235
1.14k
    nsvs = (unsigned)getub(buf, 2);
1236
    // too many sats?
1237
1.14k
    if (SKY_CHANNELS < nsvs) {
1238
116
        GPSD_LOG(LOG_WARN, &session->context->errout,
1239
116
                "Skytraq 0xDE: too many satellites %d\n",
1240
116
                 nsvs);
1241
116
        return 0;
1242
116
    }
1243
1244
1.03k
    if (len < (3 + (nsvs * 10))) {
1245
140
        GPSD_LOG(LOG_WARN, &session->context->errout,
1246
140
                 "Skytraq 0xDE: bad len %zu\n", len);
1247
140
        return 0;
1248
140
    }
1249
892
    gpsd_zero_satellites(&session->gpsdata);
1250
5.53k
    for (i = st = nsv =  0; i < nsvs; i++) {
1251
4.64k
        int off = 3 + (10 * i);  // offset into buffer of start of this sat
1252
4.64k
        bool good;               // do we have a good record ?
1253
4.64k
        unsigned short sv_stat;
1254
4.64k
        unsigned short chan_stat;
1255
4.64k
        unsigned short ura;
1256
4.64k
        short PRN;
1257
4.64k
        uint8_t gnssId = 0;
1258
4.64k
        uint8_t svId = 0;
1259
1260
4.64k
        PRN = (short)getub(buf, off + 1);
1261
        // fit into gnssid:svid
1262
4.64k
        if (0 == PRN) {
1263
            // skip 0 PRN
1264
495
            continue;
1265
495
        }
1266
4.14k
        PRN2_gnssId_svId(PRN, &gnssId, &svId);
1267
1268
4.14k
        session->gpsdata.skyview[st].gnssid = gnssId;
1269
4.14k
        session->gpsdata.skyview[st].svid = svId;
1270
4.14k
        session->gpsdata.skyview[st].PRN = PRN;
1271
1272
4.14k
        sv_stat = (unsigned short)getub(buf, off + 2);
1273
4.14k
        ura = (unsigned short)getub(buf, off + 3);
1274
4.14k
        session->gpsdata.skyview[st].ss = (double)getub(buf, off + 4);
1275
4.14k
        session->gpsdata.skyview[st].elevation =
1276
4.14k
            (double)getbes16(buf, off + 5);
1277
4.14k
        session->gpsdata.skyview[st].azimuth =
1278
4.14k
            (double)getbes16(buf, off + 7);
1279
4.14k
        chan_stat = (unsigned short)getub(buf, off + 9);
1280
1281
4.14k
        session->gpsdata.skyview[st].used = (bool)(chan_stat & 0x30);
1282
4.14k
        good = session->gpsdata.skyview[st].PRN != 0 &&
1283
4.14k
            session->gpsdata.skyview[st].azimuth != 0 &&
1284
3.85k
            session->gpsdata.skyview[st].elevation != 0;
1285
1286
4.14k
        GPSD_LOG(LOG_DATA, &session->context->errout,
1287
4.14k
                 "Skytraq PRN=%2d El=%4.0f Az=%5.0f ss=%3.2f stat=%02x,%02x "
1288
4.14k
                 "ura=%d %c\n",
1289
4.14k
                 session->gpsdata.skyview[st].PRN,
1290
4.14k
                 session->gpsdata.skyview[st].elevation,
1291
4.14k
                 session->gpsdata.skyview[st].azimuth,
1292
4.14k
                 session->gpsdata.skyview[st].ss,
1293
4.14k
                 chan_stat, sv_stat, ura,
1294
4.14k
                 good ? '*' : ' ');
1295
1296
4.14k
        if (good) {
1297
3.70k
            st += 1;
1298
3.70k
            if (session->gpsdata.skyview[st].used) {
1299
0
                nsv++;
1300
0
            }
1301
3.70k
        }
1302
4.14k
    }
1303
1304
892
    session->gpsdata.satellites_visible = st;
1305
892
    if (SKY_CHANNELS < session->gpsdata.satellites_visible) {
1306
0
        GPSD_LOG(LOG_WARN, &session->context->errout,
1307
0
                "Skytraq 0xDE: too many satellites %d\n",
1308
0
                 session->gpsdata.satellites_visible);
1309
0
        session->gpsdata.satellites_visible = SKY_CHANNELS;
1310
0
    }
1311
892
    session->gpsdata.satellites_used = nsv;
1312
1313
892
    GPSD_LOG(LOG_DATA, &session->context->errout,
1314
892
             "Skytraq 0xDE: nsvs=%u visible=%u iod=%u\n", nsvs,
1315
892
             session->gpsdata.satellites_visible, iod);
1316
892
    return SATELLITE_SET | USED_IS;
1317
1.03k
}
1318
1319
/*
1320
 * decode MID 0xDF, Nav status (PVT)
1321
 *
1322
 * 81 bytes
1323
 */
1324
static gps_mask_t sky_msg_DF(struct gps_device_t *session,
1325
                             const unsigned char *buf, const size_t len)
1326
152
{
1327
152
    unsigned short navstat;
1328
152
    unsigned iod;           // Issue of data 0 - 255
1329
152
    unsigned wn;            // week number 0 - 65535
1330
152
    double f_tow;           // receiver tow Sec
1331
152
    double clock_bias;
1332
152
    double clock_drift;
1333
152
    gps_mask_t mask = 0;
1334
152
    timespec_t ts_tow;
1335
152
    char ts_buf[TIMESPEC_LEN];
1336
1337
152
    if (81 != len) {
1338
150
        return 0;
1339
150
    }
1340
1341
2
    iod = (unsigned)getub(buf, 1);
1342
1343
    // fix status is byte 2
1344
2
    navstat = (unsigned short)getub(buf, 2);
1345
2
    session->newdata.status = STATUS_UNK;
1346
2
    session->newdata.mode = MODE_NO_FIX;
1347
2
    switch (navstat) {
1348
0
    case 1:
1349
        // fix prediction, ignore
1350
0
        break;
1351
1
    case 2:
1352
1
        session->newdata.status = STATUS_GPS;
1353
1
        session->newdata.mode = MODE_2D;
1354
1
        break;
1355
0
    case 3:
1356
0
        session->newdata.status = STATUS_GPS;
1357
0
        session->newdata.mode = MODE_3D;
1358
0
        break;
1359
0
    case 4:
1360
0
        session->newdata.status = STATUS_DGPS;
1361
0
        session->newdata.mode = MODE_3D;
1362
0
        break;
1363
1
    default:
1364
1
        break;
1365
2
    }
1366
1367
2
    wn = getbeu16(buf, 3);
1368
2
    f_tow = getbed64((const char *)buf, 5);
1369
2
    DTOTS(&ts_tow, f_tow);
1370
1371
    // position/velocity is bytes 13-48, meters and m/s
1372
2
    session->newdata.ecef.x = (double)getbed64((const char *)buf, 13),
1373
2
    session->newdata.ecef.y = (double)getbed64((const char *)buf, 21),
1374
2
    session->newdata.ecef.z = (double)getbed64((const char *)buf, 29),
1375
2
    session->newdata.ecef.vx = (double)getbef32((const char *)buf, 37),
1376
2
    session->newdata.ecef.vy = (double)getbef32((const char *)buf, 41),
1377
2
    session->newdata.ecef.vz = (double)getbef32((const char *)buf, 45);
1378
2
    mask |= ECEF_SET | VECEF_SET;
1379
1380
2
    clock_bias = getbed64((const char *)buf, 49);
1381
2
    clock_drift = getbes32(buf, 57);
1382
1383
2
    session->gpsdata.dop.gdop = getbef32((const char *)buf, 61);
1384
2
    session->gpsdata.dop.pdop = getbef32((const char *)buf, 65);
1385
2
    session->gpsdata.dop.hdop = getbef32((const char *)buf, 69);
1386
2
    session->gpsdata.dop.vdop = getbef32((const char *)buf, 73);
1387
2
    session->gpsdata.dop.tdop = getbef32((const char *)buf, 77);
1388
2
    mask |= DOP_SET;
1389
1390
2
    session->newdata.time = gpsd_gpstime_resolv(session, wn, ts_tow );
1391
1392
2
    GPSD_LOG(LOG_DATA, &session->context->errout,
1393
2
             "Skytraq 0xDF: iod=%u, stat=%u, wn=%u, tow=%f, t=%s "
1394
2
             "cb: %f, cd: %f "
1395
2
             "gdop: %.2f, pdop: %.2f, hdop: %.2f, vdop: %.2f, tdop: %.2f\n",
1396
2
             iod, navstat, wn, f_tow,
1397
2
             timespec_str(&session->newdata.time, ts_buf, sizeof(ts_buf)),
1398
2
             clock_bias, clock_drift,
1399
2
             session->gpsdata.dop.gdop,
1400
2
             session->gpsdata.dop.pdop,
1401
2
             session->gpsdata.dop.hdop,
1402
2
             session->gpsdata.dop.vdop,
1403
2
             session->gpsdata.dop.tdop);
1404
1405
2
    mask |= TIME_SET | STATUS_SET | MODE_SET | CLEAR_IS | REPORT_IS;
1406
2
    return mask;
1407
2
}
1408
1409
/*
1410
 * decode MID 0xE0, GPS Subframe data
1411
 *
1412
 * len 33 bytes
1413
 *
1414
 */
1415
static gps_mask_t sky_msg_E0(struct gps_device_t *session,
1416
                             const unsigned char *buf, const size_t len)
1417
324
{
1418
324
    int i;
1419
324
    unsigned prn;   // GPS sat PRN
1420
324
    unsigned subf;  // subframe 1-5
1421
    // the words are preprocessed, not raw, just the 24bits of data
1422
324
    uint32_t words[10];  // subframe 1-5
1423
1424
324
    if (33 != len) {
1425
144
        return 0;
1426
144
    }
1427
1428
180
    prn = (unsigned)getub(buf, 1);
1429
180
    subf = (unsigned)getub(buf, 2);
1430
1.98k
    for (i = 0; i < 10; i++) {
1431
1.80k
        words[i] = (uint32_t)getbeu24(buf, 3 + (i * 3));
1432
1.80k
    }
1433
1434
180
    GPSD_LOG(LOG_DATA, &session->context->errout,
1435
180
             "Skytraq 0xE0: prn=%u, subf=%u\n",
1436
180
             prn, subf);
1437
1438
    // could be SBAS?
1439
180
    return gpsd_interpret_subframe(session, GNSSID_GPS, prn, words);
1440
324
}
1441
1442
/*
1443
 * pretend to decode MID 0xE2, Beiduo D1 Subframe data
1444
 *
1445
 * from Beidou Standard BDS-SIS-ICD-2.0
1446
 * D1, with the data rate of 50 bps, is broadcasted by the MEO/IGSO satellites
1447
 *
1448
 * len 31 bytes
1449
 *
1450
 */
1451
static gps_mask_t sky_msg_E2(struct gps_device_t *session,
1452
                             const unsigned char *buf, const size_t len)
1453
246
{
1454
246
    int i;
1455
246
    unsigned prn;   // BeidouPS sat PRN 206-214
1456
246
    unsigned subf;  // subframe 1-5
1457
    // the words are preprocessed, not raw, just the 28 bytes of data
1458
246
    uint8_t bytes[28];  // raw data
1459
1460
246
    if (31 != len) {
1461
245
        return 0;
1462
245
    }
1463
1464
1
    prn = (unsigned)getub(buf, 1);
1465
1
    subf = (unsigned)getub(buf, 2);
1466
29
    for (i = 0; i < 28; i++) {
1467
28
        bytes[i] = getub(buf, 3 + i);
1468
28
    }
1469
1470
1
    GPSD_LOG(LOG_PROG, &session->context->errout,
1471
1
             "Skytraq Beidou D1 subframe PRN %d Subframe %d "
1472
1
             "length %zd byte:%s\n",
1473
1
             prn, subf, len,
1474
1
             gps_hexdump(session->msgbuf, sizeof(session->msgbuf),
1475
1
                         bytes, 28));
1476
1477
1
    return ONLINE_SET;
1478
246
}
1479
1480
/*
1481
 * pretend to decode MID 0xE3, Beiduo D2 Subframe data
1482
 *
1483
 * from Beidou Standard BDS-SIS-ICD-2.0
1484
 * D2, with the data rate of 500 bps, is broadcasted by the GEO satellites.
1485
 *
1486
 * len 31 bytes
1487
 *
1488
 */
1489
static gps_mask_t sky_msg_E3(struct gps_device_t *session,
1490
                             const unsigned char *buf, const size_t len)
1491
535
{
1492
535
    int i;
1493
535
    unsigned prn;   // BeidouPS sat PRN 201-205
1494
535
    unsigned subf;  // subframe 1-5
1495
    // the words are preprocessed, not raw, just the 28 bytes of data
1496
535
    uint8_t bytes[28];  // raw data
1497
1498
535
    if (31 != len) {
1499
534
        return 0;
1500
534
    }
1501
1502
1
    prn = (unsigned)getub(buf, 1);
1503
1
    subf = (unsigned)getub(buf, 2);
1504
29
    for (i = 0; i < 28; i++) {
1505
28
        bytes[i] = getub(buf, 3 + i);
1506
28
    }
1507
1508
1
    GPSD_LOG(LOG_PROG, &session->context->errout,
1509
1
             "Skytraq Beidou D2 subframe PRN %d Subframe %d "
1510
1
             "length %zd byte:%s\n",
1511
1
             prn, subf, len,
1512
1
             gps_hexdump(session->msgbuf, sizeof(session->msgbuf),
1513
1
                         bytes, 28));
1514
1515
1
    return ONLINE_SET;
1516
535
}
1517
1518
1519
static gps_mask_t sky_parse(struct gps_device_t * session,
1520
                            unsigned char *buf, size_t len)
1521
17.4k
{
1522
17.4k
    gps_mask_t mask = 0;
1523
1524
17.4k
    if (0 == len) {
1525
0
        return mask;
1526
0
    }
1527
1528
17.4k
    buf += 4;   // skip the leaders and length
1529
17.4k
    len -= 7;   // don't count the leaders, length, csum and terminators
1530
    // session->driver.sirf.lastid = buf[0];
1531
1532
    // check the checksum??
1533
1534
    // could change if the set of messages we enable does
1535
    // session->cycle_end_reliable = true;
1536
1537
17.4k
    switch (buf[0]) {
1538
699
    case 0x62:
1539
699
        mask = sky_msg_62(session, buf, len);
1540
699
        break;
1541
679
    case 0x63:
1542
679
        mask = sky_msg_63(session, buf, len);
1543
679
        break;
1544
1.19k
    case 0x64:
1545
1.19k
        mask = sky_msg_64(session, buf, len);
1546
1.19k
        break;
1547
728
    case 0x65:
1548
728
        mask = sky_msg_65(session, buf, len);
1549
728
        break;
1550
769
    case 0x6A:
1551
769
        mask = sky_msg_6A(session, buf, len);
1552
769
        break;
1553
294
    case 0x7A:
1554
294
        mask = sky_msg_7A(session, buf, len);
1555
294
        break;
1556
310
    case 0x80:
1557
        // 128
1558
310
        mask = sky_msg_80(session, buf, len);
1559
310
        break;
1560
200
    case 0x81:
1561
        // Software CRC
1562
200
        mask = sky_msg_81(session, buf, len);
1563
200
        break;
1564
896
    case 0x83:
1565
        // 131 - ACK
1566
896
        if (2 == len) {
1567
139
            GPSD_LOG(LOG_PROG, &session->context->errout,
1568
139
                     "Skytraq 0x83: ACK MID %#02x\n", buf[1]);
1569
757
        } else if (3 == len) {
1570
218
            GPSD_LOG(LOG_PROG, &session->context->errout,
1571
218
                     "Skytraq 0x83: ACK MID %#02x/%02x\n", buf[1], buf[2]);
1572
539
        } else if (4 <= len) {
1573
284
            GPSD_LOG(LOG_PROG, &session->context->errout,
1574
284
                     "Skytraq 0x83: ACK MID %#02x/%02x/%02x\n",
1575
284
                     buf[1], buf[2], buf[3]);
1576
284
        } else {
1577
255
            GPSD_LOG(LOG_PROG, &session->context->errout,
1578
255
                     "Skytraq 0x83: ACK\n");
1579
255
        }
1580
896
        break;
1581
889
    case 0x84:
1582
        // 132 - NACK
1583
889
        if (2 == len) {
1584
362
            GPSD_LOG(LOG_INF, &session->context->errout,
1585
362
                     "Skytraq 0x84: NACK MID %#02x\n", buf[1]);
1586
527
        } else if (3 == len) {
1587
85
            GPSD_LOG(LOG_INF, &session->context->errout,
1588
85
                     "Skytraq 0x84: NACK MID %#02x/%02x\n", buf[1], buf[2]);
1589
442
        } else if (4 <= len) {
1590
108
            GPSD_LOG(LOG_INF, &session->context->errout,
1591
108
                     "Skytraq 0x84: NACK MID %#02x/%02x/x%02x\n",
1592
108
                     buf[1], buf[2], buf[3]);
1593
334
        } else {
1594
334
            GPSD_LOG(LOG_INF, &session->context->errout,
1595
334
                     "Skytraq 0x84: NACK\n");
1596
334
        }
1597
889
        break;
1598
225
    case 0x86:
1599
        // 134 Position Update Rate
1600
225
        mask = sky_msg_86(session, buf, len);
1601
225
        break;
1602
204
    case 0x89:
1603
204
        mask = sky_msg_89(session, buf, len);
1604
204
        break;
1605
1.06k
    case 0x8A:
1606
1.06k
        mask = sky_msg_8A(session, buf, len);
1607
1.06k
        break;
1608
268
    case 0x8B:
1609
268
        mask = sky_msg_8B(session, buf, len);
1610
268
        break;
1611
361
    case 0x93:
1612
        // NMEA TALKER id
1613
361
        mask = sky_msg_93(session, buf, len);
1614
361
        break;
1615
1616
323
    case 0xA8:
1617
        // Navigation Data Message
1618
323
        mask = sky_msg_A8(session, buf, len);
1619
323
        break;
1620
1621
1.29k
    case 0xae:
1622
        // GNSS Datum
1623
1.29k
        mask = sky_msg_AE(session, buf, len);
1624
1.29k
        break;
1625
1626
323
    case 0xaf:
1627
        // DOP Mask
1628
323
        mask = sky_msg_AF(session, buf, len);
1629
323
        break;
1630
1631
486
    case 0xb0:
1632
        // Elevation and CNR mask
1633
486
        mask = sky_msg_B0(session, buf, len);
1634
486
        break;
1635
1636
205
    case 0xb4:
1637
        // Position Pinning Status
1638
205
        mask = sky_msg_B4(session, buf, len);
1639
205
        break;
1640
1641
247
    case 0xb9:
1642
247
        mask = sky_msg_B9(session, buf, len);
1643
247
        break;
1644
1645
143
    case 0xbb:
1646
143
        mask = sky_msg_BB(session, buf, len);
1647
143
        break;
1648
1649
506
    case 0xDC:
1650
        // 220
1651
506
        mask = sky_msg_DC(session, buf, len);
1652
506
        break;
1653
1654
1.43k
    case 0xDD:
1655
        // 221
1656
1.43k
        if (3 <= len) {
1657
1.14k
            mask = sky_msg_DD(session, buf, len);
1658
1.14k
        }
1659
1.43k
        break;
1660
1661
1.42k
    case 0xDE:
1662
        // 222
1663
1.42k
        mask = sky_msg_DE(session, buf, len);
1664
1.42k
        break;
1665
1666
152
    case 0xDF:
1667
        // 223 - Nave status (PVT)
1668
152
        mask = sky_msg_DF(session, buf, len);
1669
152
        break;
1670
1671
324
    case 0xE0:
1672
        // 224
1673
324
        mask = sky_msg_E0(session, buf, len);
1674
324
        break;
1675
1676
246
    case 0xE2:
1677
        // 226 - Beidou2 D1 Subframe data
1678
246
        mask = sky_msg_E2(session, buf, len);
1679
246
        break;
1680
1681
535
    case 0xE3:
1682
        // 227 - Beidou2 D2 Subframe data
1683
535
        mask = sky_msg_E3(session, buf, len);
1684
535
        break;
1685
1686
129
    case 0x67:   // sub-id messages
1687
129
        FALLTHROUGH
1688
263
    case 0x6F:   // sub-id messages
1689
263
        GPSD_LOG(LOG_PROG, &session->context->errout,
1690
263
                 "Skytraq Unknown MID x%02x SID x%02x length %zd\n",
1691
263
                 buf[0], buf[1], len);
1692
263
        break;
1693
756
    default:
1694
756
        GPSD_LOG(LOG_PROG, &session->context->errout,
1695
756
                 "Skytraq Unknown MID %#02x length %zd\n",
1696
756
                 buf[0], len);
1697
756
        break;
1698
17.4k
    }
1699
17.4k
    return mask;
1700
17.4k
}
1701
1702
static gps_mask_t skybin_parse_input(struct gps_device_t *session)
1703
19.7k
{
1704
    /*
1705
     * Use this hook to step, slowly, through the init messages.
1706
     * By sending only one for each three received we try
1707
     * to avoid overrunning the receiver input buffer.
1708
     */
1709
1710
19.7k
    if (UINT_MAX != session->cfg_stage) {
1711
10.3k
        session->cfg_step++;
1712
10.3k
    }
1713
1714
19.7k
    if (UINT_MAX != session->cfg_stage &&
1715
10.3k
        3 <= session->cfg_step) {
1716
        // more init to do
1717
1718
3.45k
        session->cfg_stage++;
1719
3.45k
        session->cfg_step = 0;
1720
1721
        // Note: the checksums in the Skytaq doc are sometimes wrong...
1722
1723
        // drivers/driver_nmea0183.c send 0x04 to get MID 0x80 on detect
1724
1725
        // FIXME: make a table
1726
3.45k
        switch (session->cfg_stage) {
1727
164
        case 1:
1728
            // Send MID 0x3, to get back MID 0x81 Software CRC
1729
164
            (void)sky_write(session, "\xA0\xA1\x00\x02\x03\x00\x03\x0d\x0a",
1730
164
                            9);
1731
164
            break;
1732
164
        case 2:
1733
            // Send MID 0x10, to get back MID 0x86 (Position Update Rate)
1734
164
            (void)sky_write(session, "\xA0\xA1\x00\x01\x10\x10\x0d\x0a", 8);
1735
164
            break;
1736
164
        case 3:
1737
            // Send MID 0x15, to get back MID 0xB9 (Power Mode Status)
1738
164
            (void)sky_write(session, "\xA0\xA1\x00\x01\x15\x15\x0d\x0a", 8);
1739
164
            break;
1740
155
        case 4:
1741
            // Send MID 0x1f, to get back MID 0x89 Measurement data statuS
1742
155
            (void)sky_write(session, "\xA0\xA1\x00\x01\x1f\x1f\x0d\x0a", 8);
1743
155
            break;
1744
161
        case 5:
1745
            // Send MID 0x21, to get back MID 0x8a  RTCM Data output status
1746
161
            (void)sky_write(session, "\xA0\xA1\x00\x01\x21\x21\x0d\x0a", 8);
1747
161
            break;
1748
155
        case 6:
1749
            // Send MID 0x23, to get back MID 0x8B (Base Position)
1750
155
            (void)sky_write(session, "\xA0\xA1\x00\x01\x23\x23\x0d\x0a", 8);
1751
155
            break;
1752
147
        case 7:
1753
            // Send MID 0x2d, to get back MID 0xAE (GNSS Datum)
1754
147
            (void)sky_write(session, "\xA0\xA1\x00\x01\x2d\x2d\x0d\x0a", 8);
1755
147
            break;
1756
144
        case 8:
1757
            // Send MID 0x2E, to get back MID 0xAF (DOP Mask)
1758
144
            (void)sky_write(session, "\xA0\xA1\x00\x01\x2e\x2e\x0d\x0a", 8);
1759
144
            break;
1760
148
        case 9:
1761
            // Send MID 0x2F, to get back MID 0x80 Elevation and SNR mask
1762
148
            (void)sky_write(session, "\xA0\xA1\x00\x01\x2f\x2f\x0d\x0a", 8);
1763
148
            break;
1764
143
        case 10:
1765
            // Send MID 0x3a, to get back MID 0xb4 Position Pinning
1766
143
            (void)sky_write(session, "\xA0\xA1\x00\x01\x3a\x3a\x0d\x0a", 8);
1767
143
            break;
1768
139
        case 11:
1769
            // Send MID 0x44, to get back MID 0xc2 1PPS timing
1770
            // Timing mode versions only
1771
139
            (void)sky_write(session, "\xA0\xA1\x00\x01\x44\x44\x0d\x0a", 8);
1772
139
            break;
1773
125
        case 12:
1774
            // Send MID 0x46, to get back MID 0xbb 1PPS delay
1775
125
            (void)sky_write(session, "\xA0\xA1\x00\x01\x46\x46\x0d\x0a", 8);
1776
125
            break;
1777
121
        case 13:
1778
            // Send MID 0x4f, to get back MID 0x93 NMEA talker ID
1779
121
            (void)sky_write(session, "\xA0\xA1\x00\x01\x4f\x4f\x0d\x0a", 8);
1780
121
            break;
1781
112
        case 14:
1782
            // Send MID 0x56, to get back MID 0xc3 1PPS Output Mode
1783
            // Timing mode versions only
1784
112
            (void)sky_write(session, "\xA0\xA1\x00\x01\x56\x56\x0d\x0a", 8);
1785
112
            break;
1786
104
        case 15:
1787
            // Send MID 0x62/02, to get back MID 0x62/80 SBAS status
1788
104
            (void)sky_write(session,
1789
104
                            "\xA0\xA1\x00\x02\x62\x02\x60\x0d\x0a", 9);
1790
104
            break;
1791
99
        case 16:
1792
            // Send MID 0x62/04, to get back MID 0x62/81 QZSS status
1793
99
            (void)sky_write(session,
1794
99
                            "\xA0\xA1\x00\x02\x62\x04\x66\x0d\x0a", 9);
1795
99
            break;
1796
88
        case 17:
1797
            // Send MID 0x62/06, to get back MID 0x62/82 SBAS Advanced status
1798
88
            (void)sky_write(session,
1799
88
                            "\xA0\xA1\x00\x02\x62\x06\x64\x0d\x0a", 9);
1800
88
            break;
1801
83
        case 18:
1802
            // Send MID 0x63/02, to get back MID 0x62/80 SAEE Status
1803
            // not on PX1172RH_DS
1804
83
            (void)sky_write(session,
1805
83
                            "\xA0\xA1\x00\x02\x63\x02\x61\x0d\x0a", 9);
1806
83
            break;
1807
80
        case 19:
1808
            // Send MID 0x64/01, to get back MID 0x64/80
1809
80
            (void)sky_write(session,
1810
80
                            "\xA0\xA1\x00\x02\x64\x01\x65\x0d\x0a", 9);
1811
80
            break;
1812
76
        case 20:
1813
            // Send MID 0x64/03, to get back MID 0x64/81
1814
76
            (void)sky_write(session,
1815
76
                            "\xA0\xA1\x00\x02\x64\x03\x67\x0d\x0a", 9);
1816
76
            break;
1817
73
        case 21:
1818
            // Send MID 0x64/07, to get back MID 0x64/83
1819
73
            (void)sky_write(session,
1820
73
                            "\xA0\xA1\x00\x02\x64\x07\x63\x0d\x0a", 9);
1821
73
            break;
1822
67
        case 22:
1823
            // Send MID 0x64/0b, to get back MID 0x64/85
1824
67
            (void)sky_write(session,
1825
67
                            "\xA0\xA1\x00\x02\x64\x0b\x6f\x0d\x0a", 9);
1826
67
            break;
1827
63
        case 23:
1828
            // Send MID 0x64/12, to get back MID 0x64/88
1829
63
            (void)sky_write(session,
1830
63
                            "\xA0\xA1\x00\x02\x64\x12\x76\x0d\x0a", 9);
1831
63
            break;
1832
60
        case 24:
1833
            // Send MID 0x64/16, to get back MID 0x64/8a
1834
60
            (void)sky_write(session,
1835
60
                            "\xA0\xA1\x00\x02\x64\x16\x72\x0d\x0a", 9);
1836
60
            break;
1837
58
        case 25:
1838
            // Send MID 0x64/18, to get back MID 0x64/8b
1839
58
            (void)sky_write(session,
1840
58
                            "\xA0\xA1\x00\x02\x64\x18\x7c\x0d\x0a", 9);
1841
58
            break;
1842
52
        case 26:
1843
            // Send MID 0x64/1a, to get back MID 0x64/8c
1844
52
            (void)sky_write(session,
1845
52
                            "\xA0\xA1\x00\x02\x64\x1a\x7e\x0d\x0a", 9);
1846
52
            break;
1847
47
        case 27:
1848
            // Send MID 0x64/20, to get back MID 0x64/8e
1849
47
            (void)sky_write(session,
1850
47
                            "\xA0\xA1\x00\x02\x64\x20\x44\x0d\x0a", 9);
1851
47
            break;
1852
43
        case 28:
1853
            // Send MID 0x64/22, to get back MID 0x64/8f
1854
            // not on PX1172RH_DS
1855
43
            (void)sky_write(session,
1856
43
                            "\xA0\xA1\x00\x02\x64\x22\x46\x0d\x0a", 9);
1857
43
            break;
1858
37
        case 29:
1859
            // Send MID 0x64/28, to get back MID 0x64/92
1860
37
            (void)sky_write(session,
1861
37
                            "\xA0\xA1\x00\x02\x64\x28\x4c\x0d\x0a", 9);
1862
37
            break;
1863
33
        case 30:
1864
            // Send MID 0x64/30, to get back MID 0x64/98
1865
            // not on PX1172RH_DS
1866
33
            (void)sky_write(session,
1867
33
                            "\xA0\xA1\x00\x02\x64\x30\x54\x0d\x0a", 9);
1868
33
            break;
1869
32
        case 31:
1870
            // Send MID 0x64/31, to get back MID 0x64/
1871
            // not on PX1172RH_DS
1872
32
            (void)sky_write(session,
1873
32
                            "\xA0\xA1\x00\x02\x64\x31\x55\x0d\x0a", 9);
1874
32
            break;
1875
27
        case 32:
1876
            // Send MID 0x64/7d, to get back MID 0x64/fe
1877
27
            (void)sky_write(session,
1878
27
                            "\xA0\xA1\x00\x02\x64\x7d\x19\x0d\x0a", 9);
1879
27
            break;
1880
27
        case 33:
1881
            // Send MID 0x64/35, to get back MID 0x64/99
1882
            // not on PX1172RH_DS
1883
27
            (void)sky_write(session,
1884
27
                            "\xA0\xA1\x00\x03\x64\x35\x01\x50\x0d\x0a", 10);
1885
27
            break;
1886
25
        case 34:
1887
            // Send MID 0x64/36, to get back MID 0x64/9a
1888
            // not on PX1172RH_DS
1889
25
            (void)sky_write(session,
1890
25
                            "\xA0\xA1\x00\x02\x64\x36\x52\x0d\x0a", 9);
1891
25
            break;
1892
25
        case 35:
1893
            // Send MID 0x64/3c, to get back MID 0x64/99
1894
            // not on PX1172RH_DS
1895
25
            (void)sky_write(session,
1896
25
                            "\xA0\xA1\x00\x04\x64\x3c\x47\x47\x19\x0d\x0a",
1897
25
                            11);
1898
25
            break;
1899
23
        case 36:
1900
            // Send MID 0x65/02, to get back MID 0x64/80
1901
23
            (void)sky_write(session,
1902
23
                            "\xA0\xA1\x00\x02\x65\x02\x67\x0d\x0a", 9);
1903
23
            break;
1904
23
        case 37:
1905
            // Send MID 0x65/04, to get back MID 0x64/8f
1906
23
            (void)sky_write(session,
1907
23
                            "\xA0\xA1\x00\x02\x65\x04\x61\x0d\x0a", 9);
1908
23
            break;
1909
23
        case 38:
1910
            // Send MID 0x6a/02, to get back MID 0x6a/83
1911
23
            (void)sky_write(session,
1912
23
                            "\xA0\xA1\x00\x02\x6a\x02\x68\x0d\x0a", 9);
1913
23
            break;
1914
21
        case 39:
1915
            // Send MID 0x6a/07, to get back MID 0x6a/83
1916
21
            (void)sky_write(session,
1917
21
                            "\xA0\xA1\x00\x02\x6a\x07\x6d\x0d\x0a", 9);
1918
21
            break;
1919
20
        case 40:
1920
            // Send MID 0x6a/0d, to get back MID 0x6a/85
1921
20
            (void)sky_write(session,
1922
20
                            "\xA0\xA1\x00\x02\x6a\x0d\x67\x0d\x0a", 9);
1923
20
            break;
1924
18
        case 41:
1925
            // Send MID 0x6a/14, to get back MID 0x6a/86
1926
18
            (void)sky_write(session,
1927
18
                            "\xA0\xA1\x00\x02\x6a\x14\xfd\x0d\x0a", 9);
1928
18
            break;
1929
16
        case 42:
1930
            // Send MID 0x6a/16, to get back MID 0x6a/89
1931
            // not on PX1172RH_DS ?
1932
16
            (void)sky_write(session,
1933
16
                            "\xA0\xA1\x00\x02\x6a\x16\x7c\x0d\x0a", 9);
1934
16
            break;
1935
16
        case 43:
1936
            // Send MID 0x7a/0e/01, to get back MID 0x7a/0e/80
1937
            // not on PX1172RH_DS ?
1938
16
            (void)sky_write(session,
1939
16
                            "\xA0\xA1\x00\x03\x7a\x0e\x01\x75\x0d\x0a", 10);
1940
16
            break;
1941
16
        case 44:
1942
            // Send MID 0x7a/0e/02, to get back MID 0x7a/0e/81
1943
            // not on PX1172RH_DS ?
1944
16
            (void)sky_write(session,
1945
16
                            "\xA0\xA1\x00\x03\x7a\x0e\x02\x76\x0d\x0a", 10);
1946
16
            break;
1947
14
        case 45:
1948
            // Send MID 0x7a/0e/03, to get back MID 0x7a/0e/82
1949
            // not on PX1172RH_DS ?
1950
14
            (void)sky_write(session,
1951
14
                            "\xA0\xA1\x00\x03\x7a\x0e\x03\x77\x0d\x0a", 10);
1952
14
            break;
1953
13
        case 46:
1954
            // Send MID 0x7a/0e/05, to get back MID 0x7a/0e/83
1955
            // not on PX1172RH_DS ?
1956
13
            (void)sky_write(session,
1957
13
                            "\xA0\xA1\x00\x03\x7a\x0e\x05\x71\x0d\x0a", 10);
1958
13
            break;
1959
11
        default:
1960
            // Done
1961
11
            session->cfg_stage = UINT_MAX;
1962
11
            break;
1963
3.45k
        }
1964
3.45k
    }
1965
1966
19.7k
    if (SKY_PACKET == session->lexer.type) {
1967
17.4k
        return  sky_parse(session, session->lexer.outbuffer,
1968
17.4k
                        session->lexer.outbuflen);
1969
17.4k
    }
1970
2.31k
    if (NMEA_PACKET == session->lexer.type) {
1971
2.31k
        return nmea_parse((char *)session->lexer.outbuffer, session);
1972
2.31k
    }
1973
    // should not get here...
1974
1975
0
    return 0;
1976
2.31k
}
1977
1978
// this is everything we export
1979
// *INDENT-OFF*
1980
const struct gps_type_t driver_skytraq =
1981
{
1982
    .channels       = SKY_CHANNELS,          // consumer-grade GPS
1983
    .control_send   = sky_write,             // how to send a control string
1984
    .event_hook     = NULL,                  // lifetime event handler
1985
    .flags          = DRIVER_STICKY,         // remember this
1986
    .get_packet     = packet_get1,           // be prepared for Skytraq or NMEA
1987
    .init_query     = NULL,                  // non-perturbing initial query
1988
    .mode_switcher  = sky_mode,              // Mode switcher
1989
    .packet_type    = SKY_PACKET,            // associated lexer packet type
1990
    .parse_packet   = skybin_parse_input,    // parse message packets
1991
    .probe_detect   = NULL,                  // no probe
1992
    .rtcm_writer    = gpsd_write,            // send RTCM data straight
1993
    .trigger        = NULL,                  // no trigger
1994
    .type_name      = "Skytraq",             // full name of type
1995
};
1996
// *INDENT-ON*
1997
#endif  // defined SKYTRAQ_ENABLE)
1998
1999
// vim: set expandtab shiftwidth=4