Coverage Report

Created: 2026-10-17 06:30

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