Coverage Report

Created: 2024-02-25 06:36

/src/gpsd/gpsd-3.25.1~dev/drivers/driver_tsip.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Handle the Trimble TSIP packet format
3
 * by Rob Janssen, PE1CHL.
4
 * Acutime Gold support by Igor Socec <igorsocec@gmail.com>
5
 * Trimble RES multi-constellation support by Nuno Goncalves <nunojpg@gmail.com>
6
 *
7
 * Week counters are not limited to 10 bits. It's unknown what
8
 * the firmware is doing to disambiguate them, if anything; it might just
9
 * be adding a fixed offset based on a hidden epoch value, in which case
10
 * unhappy things will occur on the next rollover.
11
 *
12
 * TSIPv1n RES270 Resolution SMTx support added by:
13
 *     Gary E. Miller <gem@rellim.com>
14
 *
15
 * This file is Copyright by the GPSD project
16
 * SPDX-License-Identifier: BSD-2-clause
17
 */
18
19
#include "../include/gpsd_config.h"   // must be before all includes
20
21
#include <math.h>
22
#include <stdbool.h>
23
#include <stdio.h>
24
#include <stdlib.h>           // For llabs()
25
#include <string.h>
26
#include <time.h>
27
#include <unistd.h>
28
29
#include "../include/compiler.h"   // for FALLTHROUGH
30
#include "../include/gpsd.h"
31
#include "../include/bits.h"
32
#include "../include/strfuncs.h"
33
#include "../include/timespec.h"
34
35
#ifdef TSIP_ENABLE
36
// RES SMT 360 has 32 max channels, use 64 for next gen
37
0
#define TSIP_CHANNELS  64
38
39
/* defines for Set or Request I/O Options (0x35)
40
 * SMT 360 default: IO1_DP|IO1_LLA, IO2_ENU, 0, IO4_DBHZ */
41
// byte 1 Position
42
0
#define IO1_ECEF 1
43
0
#define IO1_LLA 2
44
0
#define IO1_MSL 4
45
0
#define IO1_DP 0x10
46
// IO1_8F20 not in SMT 360
47
0
#define IO1_8F20 0x20
48
// byte 2 Velocity
49
0
#define IO2_VECEF 1
50
0
#define IO2_ENU 2
51
// byte 3 Timing
52
#define IO3_UTC 1
53
// byte 4 Aux/Reserved
54
#define IO4_RAW 1
55
0
#define IO4_DBHZ 8
56
57
0
#define SEMI_2_DEG      (180.0 / 2147483647)    // 2^-31 semicircle to deg
58
59
// Start TSIPv1 values and flags
60
61
/* Data Bits v1
62
 * Used in x91-00 */
63
static struct vlist_t vdbits1[] = {
64
    {3, "8 bits"},
65
    {0, NULL},
66
};
67
68
/* Fix Type v1
69
 * Used in xa1-11 */
70
static struct vlist_t vfix_type1[] = {
71
    {0, "No Fix"},
72
    {1, "1D"},
73
    {2, "3D"},
74
    {0, NULL},
75
};
76
77
/* GNSS Decoding Status to string
78
 * Used in xa3-11 */
79
static struct vlist_t vgnss_decode_status1[] = {
80
    {0, "Doing Fixes"},
81
    {1, "No GPS time"},
82
    {2, "PDOP too high"},
83
    {3, "0 usable sats"},
84
    {4, "1 usable sat"},
85
    {5, "2 usable sats"},
86
    {6, "3 usable sats"},
87
    {0xff, "GPS Time Fix (OD mode)"},
88
    {0, NULL},
89
};
90
91
/* Major Alarm Flags v1
92
 * Used in xa3-00 */
93
static struct flist_t vmajor_alarms1[] = {
94
    {1, 1, "Not tracking sats"},
95
    {2, 2, "PPS bad"},
96
    {4, 4, "PPS not generated"},
97
    {0x80, 0x80, "Spoofing/Multipath"},
98
    {0x100, 0x100, "Jamming"},
99
    {0, 0, NULL},
100
};
101
102
/* Minor Alarm Flags v1
103
 * Used in xa3-00 */
104
static struct flist_t vminor_alarms1[] = {
105
    {1, 1, "Ant Open"},
106
    {2, 2, "Ant Short"},
107
    {4, 4, "Leap Pending"},
108
    {8, 8, "Almanac Incomplete"},
109
    {0x10, 0x10, "Survey in Progress"},
110
    {0x20, 0x20, "GPS Almanac Incomplete"},
111
    {0x20, 0x20, "GLO Almanac Incomplete"},
112
    {0x40, 0x40, "BDS Almanac Incomplete"},
113
    {0x80, 0x80, "GAL Almanac Incomplete"},
114
    {0x100, 0x100, "Leap Second Insertion"},
115
    {0x200, 0x200, "Leap Second Deletion"},
116
    {0, 0, NULL},
117
};
118
119
/* Parity v1
120
 * Used in x91-00 */
121
static struct vlist_t vparity1[] = {
122
    {0, "None bits"},
123
    {1, "Odd"},
124
    {2, "Even"},
125
    {255, "Ignore"},
126
    {0, NULL},
127
};
128
129
/* Port Name v1
130
 * Used in x91-00 */
131
static struct vlist_t vport_name1[] = {
132
    {0, "Port A"},
133
    {1, "Port B"},
134
    {255, "Current Port"},
135
    {0, NULL},
136
};
137
138
/* Port Type v1
139
 * Used in x91-00 */
140
static struct vlist_t vport_type1[] = {
141
    {0, "UART"},
142
    {0, NULL},
143
};
144
145
/* Position Mask
146
 * Used in xa1-11 */
147
static struct flist_t vpos_mask1[] = {
148
    {0, 1, "Real Time Position"},
149
    {1, 1, "Surveyed Position"},
150
    {0, 2, "LLA Position"},
151
    {2, 2, "XYZ ECEF"},
152
    {0, 4, "HAE"},
153
    {4, 4, "MSL"},
154
    {0, 8, "Velocity ENU"},
155
    {8, 8, "Velocity ECEF"},
156
    {0, 0, NULL},
157
};
158
159
/* PPS Mask v1
160
 * Used in x91-03 */
161
static struct vlist_t vpps_mask1[] = {
162
    {0, "Off"},
163
    {1, "On"},
164
    {2, "Fix Based"},
165
    {3, "When Valid"},
166
    {4, "Off"},
167
    {5, "On/Negative"},
168
    {6, "Fix Based/Negative"},
169
    {7, "When Valid/Negative"},
170
    {0, NULL},
171
};
172
173
/* Protocol v1
174
 * Used in x91-00 */
175
static struct vlist_t vprotocol1[] = {
176
    {2, "TSIP"},
177
    {4, "NMEA"},
178
    {255, "Ignore"},
179
    {0, NULL},
180
};
181
182
/* Receiver Mode v1
183
 * Used in xa3-11 */
184
static struct vlist_t vrec_mode1[] = {
185
    {0, "2D"},
186
    {1, "(3D) Time Only"},
187
    {3, "Automatic"},
188
    {6, "Overdetermined"},
189
    {0, NULL},
190
};
191
192
/* Satellite Flags v1
193
 * Used in xa2-00 */
194
static struct flist_t vsflags1[] = {
195
    {1, 1, "Acquired"},
196
    {2, 2, "Used in Position"},
197
    {4, 4, "Used in PPS"},
198
    // Bits 8 - 15 "Satellite Status, otherwise undocumented.
199
    {0, 0, NULL},
200
};
201
202
/* Speed v1
203
 * Used in x91-00 */
204
static struct vlist_t vspeed1[] = {
205
    {11, "115200"},
206
    {12, "230400"},
207
    {13, "460800"},
208
    {14, "1821600"},
209
    {255, "Ignore"},
210
    {0, NULL},
211
};
212
213
/* Self-Survey Mask v1
214
 * Used in x91-04 */
215
static struct flist_t vss_mask1[] = {
216
    {1, 1, "SS restarted"},
217
    {0, 2, "SS Disabled"},
218
    {2, 2, "SS Enabled"},
219
    {0, 8, "Don't save position"},
220
    {8, 8, "Save position"},
221
    {0, 0, NULL},
222
};
223
224
/* Stop Bits v1
225
 * Used in x91-00 */
226
static struct vlist_t vstop1[] = {
227
    {0, "1 bit"},
228
    {1, "2 bit"},
229
    {255, "Ignore"},
230
    {0, NULL},
231
};
232
233
/* SV Type v1
234
 * Used in xa2-00 */
235
static struct vlist_t vsv_type1[] = {
236
    {1, "GPS L1C"},
237
    {2, "GPS L2"},
238
    {3, "GPS L5"},
239
    {5, "GLO G1"},
240
    {6, "GLO G2"},
241
    {9, "SBAS"},
242
    {13, "BDS B1"},
243
    {14, "BDS B2i"},
244
    {15, "BDS B2a"},
245
    {17, "GAL E1"},
246
    {18, "GAL E5a"},
247
    {19, "GAL E5b"},
248
    {20, "GAL E6"},
249
    {22, "QZSS L1"},
250
    {23, "QZSS L2C"},
251
    {24, "QZSS L5"},
252
    {26, "IRNSS L5"},
253
    {0, NULL},
254
};
255
256
/* SV Types v1
257
 * Used in x91-01 */
258
static struct flist_t vsv_types1[] = {
259
    {1, 1, "GPS L1C"},
260
    {2, 2, "GPS L2"},
261
    {4, 3, "GPS L5"},
262
    {0x20, 0x20, "GLO G1"},
263
    {0x40, 0x40, "GLO G2"},
264
    {0x100, 0x100, "SBAS"},
265
    {0x1000, 0x1000, "BDS B1"},
266
    {0x2000, 0x2000, "BDS B2i"},
267
    {0x4000, 0x4000, "BDS B2a"},
268
    {0x10000, 0x10000, "GAL E1"},
269
    {0x20000, 0x20000, "GAL E5a"},
270
    {0x40000, 0x40000, "GAL E5b"},
271
    {0x80000, 0x80000, "GAL E6"},
272
    {0x100000, 0x100000, "QZSS L1"},
273
    {0x200000, 0x200000, "QZSS L2C"},
274
    {0x400000, 0x400000, "QZSS L5"},
275
    {0x1000000, 0x1000000, "IRNSS L5"},
276
    {0, 0, NULL},
277
};
278
279
/* Time Base v1
280
 * Used in x91-03, xa1-00 */
281
static struct vlist_t vtime_base1[] = {
282
    {0, "GPS"},
283
    {1, "GLO"},
284
    {2, "BDS"},
285
    {3, "GAL"},
286
    {4, "GPS/UTC"},
287
    {6, "GLO/UTC"},
288
    {6, "BDS/UTC"},
289
    {7, "GAL/UTC"},
290
    {0, NULL},
291
};
292
293
/* Time Flags v1
294
 * Used in xa1-00 */
295
static struct flist_t vtime_flags1[] = {
296
    {0, 1, "UTC Invalid"},
297
    {1, 1, "UTC Valid"},
298
    {0, 2, "Time Invalid"},
299
    {2, 2, "Time Valid"},
300
    {0, 0, NULL},
301
};
302
303
// End  TSIPv1 values and flags
304
305
// Start  TSIP values and flags
306
307
/* GNSS Decoding Status to string
308
 * Used in x46, x8f-ac */
309
static struct vlist_t vgnss_decode_status[] = {
310
    {0, "Doing Fixes"},
311
    {1, "No GPS time"},
312
    {2, "Needs Init"},                      // ACE II, LassenSQ
313
    {3, "PDOP too high"},
314
    {8, "0 usable sats"},
315
    {9, "1 usable sat"},
316
    {10, "2 usable sats"},
317
    {11, "3 usable sats"},
318
    {12, "chosen sat unusable"},
319
    {16, "TRAIM rejected"},                 // Thunderbolt E
320
    {0xbb, "GPS Time Fix (OD mode)"},       // Acutime 360
321
    {0, NULL},
322
};
323
324
/* Receiver Mode
325
 * Used in xbb, x8f-ac */
326
static struct vlist_t vrec_mode[] = {
327
    {0, "Autonomous (2D/3D)"},
328
    {1, "Time Only (1-SV)"},    // Accutime 2000, Tbolt
329
    {3, "2D"},                  // Accutime 2000, Tbolt
330
    {4, "3D"},                  // Accutime 2000, Tbolt
331
    {5, "DGPS"},                // Accutime 2000, Tbolt
332
    {6, "2D Clock hold"},       // Accutime 2000, Tbolt
333
    {7, "Overdetermined"},      // Stationary Timing, surveyed
334
    {0, NULL},
335
};
336
337
/* Error Code Flags
338
 * Used in x46 */
339
static struct flist_t verr_codes[] = {
340
    {1, 1, "No Bat"},
341
    {0x10, 0x30, "Ant Open"},
342
    {0x30, 0x30, "Ant Short"},
343
    {0, 0, NULL},
344
};
345
346
/* Error Code Flags
347
 * Used in xa3-21 */
348
static struct vlist_t verr_codes1[] = {
349
    {1, "Parameter Error"},
350
    {2, "Length Error"},
351
    {3, "Invalid Parket Format"},
352
    {4, "Invalid Checksum"},
353
    {5, "Bad TNL/User mode"},
354
    {6, "Invalid Packet ID"},
355
    {7, "Invalid Subacket ID"},
356
    {8, "Update in Progress"},
357
    {9, "Internal Error (div by 0)"},
358
    {10, "Internal Error (failed queuing)"},
359
    {0, NULL},
360
};
361
362
/* Status 1
363
 * Used in x4b */
364
static struct flist_t vstat1[] = {
365
    {2, 2, "RTC invalid"},
366
    {8, 8, "No Almanac"},
367
    {0, 0, NULL},
368
};
369
370
/* Status 2
371
 * Used in x4b */
372
static struct flist_t vstat2[] = {
373
    {1, 1, "Superpackets"},      // x8f-20 (LFwEI)
374
    {2, 2, "Superpackets 2"},    // x8f-1b, x8f-ac
375
    {0, 0, NULL},
376
};
377
378
/* Fis Dimension, Fix Mode
379
 * Used in x6c, x6d */
380
static struct flist_t vfix[] = {
381
    // Accutime calls 0 "Auto"
382
    {0, 7, "No Fix"},
383
    // in x6d, Thunderbolt E calls 1 "1D Time Fix", not an OD Fix
384
    {1, 7, "OD Fix"},
385
    // Accutime calls 3 "2D Clock Hold"
386
    {3, 7, "2D Fix"},
387
    {4, 7, "3D Fix"},
388
    {5, 7, "OD Fix"},       // in Thunderbolt E, x6d, others
389
    {6, 7, "DGPS"},         // in Accutime
390
    {0, 8, "Auto"},
391
    {1, 8, "Manual"},
392
    {0, 0, NULL},
393
};
394
395
/* Timing Flags
396
 * Used in x8f-ab */
397
static struct flist_t vtiming[] = {
398
    {0, 1, "GPS time"},
399
    {1, 1, "UTC time"},
400
    {0, 2, "GPS PPS"},
401
    {1, 2, "UTC PPS"},
402
    {4, 4, "Time not set"},
403
    {8, 8,  "no UTC info"},
404
    {0x10, 0x10, "time from user"},
405
    {0, 0, NULL},
406
};
407
408
/* Critical Alarm Flags
409
 * Used in x8f-ac */
410
static struct flist_t vcrit_alarms[] = {
411
    {1, 1, "ROM error"},               // Thunderbolt
412
    {2, 2, "RAM error"},               // Thunderbolt
413
    {4, 4, "FPGA error"},              // Thunderbolt
414
    {8, 8, "Power error"},             // Thunderbolt
415
    {0x10, 0x10, "OSC error"},         // Thunderbolt
416
    {0, 0, NULL},
417
};
418
419
/* Minor Alarm Flags
420
 * Used in x8f-ac */
421
static struct flist_t vminor_alarms[] = {
422
    {1, 1, "OSC warning"},                   // Thunderbolt
423
    {2, 2, "Ant Open"},
424
    {4, 4, "Ant Short"},
425
    {8, 8, "Not tracking Sats"},
426
    {0x10, 0x10, "Osc unlocked"},            // Thunderbolt
427
    {0x20, 0x20, "Survey in progress"},
428
    {0x40, 0x40, "No stored Position"},
429
    {0x80, 0x80, "Leap Sec Pending"},
430
    {0x100, 0x100, "Test Mode"},
431
    {0x200, 0x200, "Position questionable"},
432
    {0x400, 0x400, "EEROM corrupt"},         // Thunderbolt
433
    {0x800, 0x800, "Almanac Incomplete"},
434
    {0x1000, 0x1000, "PPS generated"},
435
    {0, 0, NULL},
436
};
437
438
/* convert TSIP SV Type to satellite_t.gnssid and satellite_t.svid
439
 * return gnssid directly, svid indirectly through pointer */
440
static unsigned char tsip_gnssid(unsigned svtype, short prn,
441
                                 unsigned char *svid)
442
0
{
443
    // initialized to shut up clang
444
0
    unsigned char gnssid = 0;
445
446
0
    *svid = 0;
447
448
0
    switch (svtype) {
449
0
    case 0:
450
0
        if (0 < prn && 33 > prn) {
451
0
            gnssid = GNSSID_GPS;
452
0
            *svid = prn;
453
0
        } else if (32 < prn && 55 > prn) {
454
            // RES SMT 360 and ICM SMT 360 put SBAS in 33-54
455
0
            gnssid = GNSSID_SBAS;
456
0
            *svid = prn + 87;
457
0
        } else if (64 < prn && 97 > prn) {
458
            // RES SMT 360 and ICM SMT 360 put GLONASS in 65-96
459
0
            gnssid = GNSSID_GLO;
460
0
            *svid = prn - 64;
461
0
        } else if (96 < prn && 134 > prn) {
462
            // RES SMT 360 and ICM SMT 360 put Galileo in 97-133
463
0
            gnssid = GNSSID_GAL;
464
0
            *svid = prn - 96;
465
0
        } else if (119 < prn && 139 > prn) {
466
            // Copernicus (II) put SBAS in 120-138
467
0
            gnssid = GNSSID_SBAS;
468
0
            *svid = prn + 87;
469
0
        } else if (183 == prn) {
470
0
            gnssid = GNSSID_QZSS;
471
0
            *svid = 1;
472
0
        } else if (192 <= prn && 193 >= prn) {
473
0
            gnssid = GNSSID_QZSS;
474
0
            *svid = prn - 190;
475
0
        } else if (200 == prn) {
476
0
            gnssid = GNSSID_QZSS;
477
0
            *svid = 4;
478
0
        } else if (200 < prn && 238 > prn) {
479
            // BeidDou in 201-237
480
0
            gnssid = GNSSID_BD;
481
0
            *svid = prn - 200;
482
0
        }
483
        // else: huh?
484
0
        break;
485
0
    case 1:
486
0
        gnssid = GNSSID_GLO;  // GLONASS
487
0
        *svid = prn - 64;
488
0
        break;
489
0
    case 2:
490
0
        gnssid = GNSSID_BD;  // BeiDou
491
0
        *svid = prn - 200;
492
0
        break;
493
0
    case 3:
494
0
        gnssid = GNSSID_GAL;  // Galileo
495
0
        *svid = prn - 96;
496
0
        break;
497
0
    case 5:
498
0
        gnssid = GNSSID_QZSS;  // QZSS
499
0
        switch (prn) {
500
0
        case 183:
501
0
            *svid = 1;
502
0
            break;
503
0
        case 192:
504
0
            *svid = 2;
505
0
            break;
506
0
        case 193:
507
0
            *svid = 3;
508
0
            break;
509
0
        case 200:
510
0
            *svid = 4;
511
0
            break;
512
0
        default:
513
0
            *svid = prn;
514
0
            break;
515
0
        }
516
0
        break;
517
0
    case 4:
518
0
        FALLTHROUGH
519
0
    case 6:
520
0
        FALLTHROUGH
521
0
    case 7:
522
0
        FALLTHROUGH
523
0
    default:
524
0
        *svid = 0;
525
0
        gnssid = 0;
526
0
        break;
527
0
    }
528
0
    return gnssid;
529
0
}
530
531
/* tsip1_checksum()
532
 * compute TSIP version 1 checksum
533
 *
534
 * Return: checksum
535
 */
536
static char tsip1_checksum(const char *buf, size_t len)
537
0
{
538
0
    char checksum = 0;
539
0
    size_t index;
540
541
0
    for(index = 0; index < len; index++) {
542
0
        checksum ^= buf[index];
543
0
    }
544
0
    return checksum;
545
0
}
546
547
/* tsip_write1() - send old style TSIP message, improved tsip_write()
548
 * buf - the packet
549
 * len - length of buf
550
 *
551
 * Adds leading DLE, and the trailing DLE, ETX
552
 *
553
 * Return: 0 == OK
554
 *         -1 == write fail
555
 */
556
static ssize_t tsip_write1(struct gps_device_t *session,
557
                           char *buf, size_t len)
558
0
{
559
0
    char *ep, *cp;
560
0
    char obuf[100];
561
0
    size_t olen = len;
562
563
0
    if (session->context->readonly) {
564
0
        return 0;
565
0
    }
566
0
    if ((NULL == buf) ||
567
0
        0 == len ||
568
0
        (sizeof(session->msgbuf) / 2) < len) {
569
        // could over run, do not chance it
570
0
        return -1;
571
0
    }
572
0
    session->msgbuf[0] = '\x10';
573
0
    ep = session->msgbuf + 1;
574
0
    for (cp = buf; olen-- > 0; cp++) {
575
0
        if ('\x10' == *cp) {
576
0
            *ep++ = '\x10';
577
0
        }
578
0
        *ep++ = *cp;
579
0
    }
580
0
    *ep++ = '\x10';
581
0
    *ep++ = '\x03';
582
0
    session->msgbuflen = (size_t)(ep - session->msgbuf);
583
    // Don't bore the user with the header (DLE) or trailer (DLE, STX).
584
0
    GPSD_LOG(LOG_PROG, &session->context->errout,
585
0
             "TSIP: tsip_write1(0x%s)\n",
586
0
             gps_hexdump(obuf, sizeof(obuf),
587
0
                         (unsigned char *)&session->msgbuf[1], len));
588
0
    if (gpsd_write(session, session->msgbuf, session->msgbuflen) !=
589
0
        (ssize_t) session->msgbuflen)
590
0
        return -1;
591
592
0
    return 0;
593
0
}
594
595
/* tsip_detect()
596
 *
597
 * see if it looks like a TSIP device (speaking 9600O81) is listening and
598
 * return 1 if found, 0 if not
599
 */
600
static bool tsip_detect(struct gps_device_t *session)
601
0
{
602
0
    bool ret = false;
603
0
    int myfd;
604
0
    speed_t old_baudrate;
605
0
    char old_parity;
606
0
    unsigned int old_stopbits;
607
0
    bool override = true;
608
609
0
    if ((speed_t)0 == session->context->fixed_port_speed &&
610
0
        '\0' == session->context->fixed_port_framing[0]) {
611
        // Only try 9600 8O1 is no speed or framing override
612
0
        old_baudrate = session->gpsdata.dev.baudrate;
613
0
        old_parity = session->gpsdata.dev.parity;
614
0
        old_stopbits = session->gpsdata.dev.stopbits;
615
0
        gpsd_set_speed(session, 9600, 'O', 1);
616
0
        override = false;
617
0
    }
618
619
    /* request firmware revision and look for a valid response
620
     * send 0x1f, expext 0x45.  TSIPv1 does not have this, but it
621
     * will respond with a TSIPv1 error message, so all good. */
622
0
    if (0 == tsip_write1(session, "\x1f", 1)) {
623
0
        unsigned int n;
624
0
        struct timespec to;
625
626
0
        myfd = session->gpsdata.gps_fd;
627
628
        // FIXME: this holds the main loop from running...
629
0
        for (n = 0; n < 3; n++) {
630
            // wait 100 milli second
631
0
            to.tv_sec = 0;
632
0
            to.tv_nsec = 100000000;
633
0
            if (!nanowait(myfd, &to)) {
634
0
                break;
635
0
            }
636
0
            if (0 <= packet_get1(session)) {
637
0
                if (TSIP_PACKET == session->lexer.type) {
638
0
                    GPSD_LOG(LOG_RAW, &session->context->errout,
639
0
                             "TSIP: tsip_detect found\n");
640
0
                    ret = true;
641
0
                    break;
642
0
                }
643
0
            }
644
0
        }
645
0
    }
646
647
0
    if (!ret &&
648
0
        !override) {
649
        // return serial port to original settings
650
0
        gpsd_set_speed(session, old_baudrate, old_parity, old_stopbits);
651
0
    }
652
653
0
    return ret;
654
0
}
655
656
// configure generic Trimble TSIP device to a known state
657
static void configuration_packets_generic(struct gps_device_t *session)
658
0
{
659
0
        char buf[100];
660
661
0
        GPSD_LOG(LOG_PROG, &session->context->errout,
662
0
                 "TSIP: configuration_packets_generic()\n");
663
664
        // Set basic configuration, using Set or Request I/O Options (0x35).
665
        // Position: enable: Double Precision, LLA, disable: ECEF
666
0
        buf[0] = 0x35;
667
        // Time: enable: 0x42, 0x43, 0x4a, disable: 0x83, 0x84, 0x56
668
0
        buf[1] = IO1_8F20|IO1_DP|IO1_LLA;
669
        // Velocity: enable: ENU, disable ECEF
670
0
        buf[2] = IO2_ENU;
671
0
        buf[3] = 0x00;
672
0
        buf[4] = IO4_DBHZ;    // Aux: enable: 0x5A, dBHz
673
0
        (void)tsip_write1(session, buf, 5);
674
675
        // Request Software Version (0x1f), returns 0x45
676
0
        (void)tsip_write1(session, "\x1f", 1);
677
678
        // Current Time Request (0x21), returns 0x41
679
0
        (void)tsip_write1(session, "\x21", 1);
680
681
        /* Set Operating Parameters (0x2c)
682
         * not present in:
683
         *   Lassen SQ (2002)
684
         *   Lassen iQ (2005)
685
         *   RES SMT 360 */
686
        /* dynamics code: enabled: 1=land
687
         *   disabled: 2=sea, 3=air, 4=static
688
         *   default is land */
689
0
        buf[0] = 0x2c;
690
0
        buf[1] = 0x01;
691
        // elevation mask, 10 degrees is a common default, TSIP default is 15
692
0
        putbef32(buf, 2, (float)10.0 * DEG_2_RAD);
693
        // signal level mask, default is 2.0 AMU. 5.0 to 6.0 for high accuracy
694
0
        putbef32(buf, 6, (float)06.0);
695
        // PDOP mask default is 12. 5.0 to 6.0 for high accuracy
696
0
        putbef32(buf, 10, (float)8.0);
697
        // PDOP switch, default is 8.0
698
0
        putbef32(buf, 14, (float)6.0);
699
0
        (void)tsip_write1(session, buf, 18);
700
701
        /* Set Position Fix Mode (0x22)
702
         * 0=auto 2D/3D, 1=time only, 3=2D, 4=3D, 10=Overdetermined clock */
703
0
        (void)tsip_write1(session, "\x22\x00", 2);
704
705
        /* Request GPS System Message (0x48)
706
         * not supported on model RES SMT 360 */
707
0
        (void)tsip_write1(session, "\x28", 1);
708
709
        /* Last Position and Velocity Request (0x37)
710
         * returns 0x57 and (0x42, 0x4a, 0x83, or 0x84) and (0x43 or 0x56)  */
711
0
        (void)tsip_write1(session, "\x37", 1);
712
713
        // 0x8e-15 request output datum
714
0
        (void)tsip_write1(session, "\x8e\x15", 2);
715
716
        /* Primary Receiver Configuration Parameters Request (0xbb-00)
717
         * returns  Primary Receiver Configuration Block (0xbb-00) */
718
0
        (void)tsip_write1(session, "\xbb\x00", 2);
719
0
}
720
721
// configure Acutime Gold to a known state
722
static void configuration_packets_acutime_gold(struct gps_device_t *session)
723
0
{
724
0
        char buf[100];
725
726
0
        GPSD_LOG(LOG_PROG, &session->context->errout,
727
0
                 "TSIP: configuration_packets_acutime_gold()\n");
728
729
        /* Request Firmware Version (0x1c-01)
730
         * returns Firmware component version information (0x1x-81) */
731
0
        (void)tsip_write1(session, "\x1c\x01", 2);
732
733
0
        buf[0] = 0x8e;          // Set Self-Survey Parameters (0x8e-a9)
734
0
        buf[1] = 0xa9;          // Subcode
735
0
        buf[2] = 0x01;          // Self-Survey Enable = enable
736
0
        buf[3] = 0x01;          // Position Save Flag = save position
737
0
        putbe32(buf, 4, 2000);  // Self-Survey Length = 2000 fixes, default 2000
738
        // Horizontal Uncertainty, 1-100, 1=best, 100=worst, default 100
739
0
        putbef32(buf, 8, 100);
740
        // Verical Uncertainty, 1-100, 1=best, 100=worst, default 100
741
0
        putbef32(buf, 12, 100);
742
0
        (void)tsip_write1(session, buf, 16);
743
744
        /* Set PPS Output Option (0x8e-4e)
745
         * 0x4e Subcode
746
         * 2 == PPS driver switch (PPS is always output) */
747
0
        (void)tsip_write1(session, "\x8e\x4e\x02", 3);
748
749
0
        buf[0] = 0xbb;  // Set Primary Receiver Configuration (0xbb-00)
750
0
        buf[1] = 0x00;  // 00 =  Subcode
751
0
        buf[2] = 0x07;  // Receiver mode, 7 = Force Overdetermined clock
752
0
        buf[3] = 0xff;  // Not enabled = unchanged, must be 0xff on RES SMT 360
753
0
        buf[4] = 0x01;  // Dynamics code = default must be 0xff on RES SMT 360
754
0
        buf[5] = 0x01;  // Solution Mode = default must be 0xff on RES SMT 360
755
        // Elevation Mask = 10 deg
756
0
        putbef32((char *)buf, 6, (float)10.0 * DEG_2_RAD);
757
        // AMU Mask. 0 to 55. default is 4.0
758
0
        putbef32((char *)buf, 10, (float)4.0);
759
        // PDOP Mask = 8.0, default = 6
760
0
        putbef32((char *)buf, 14, (float)8.0);
761
        // PDOP Switch = 6.0, ignored in RES SMT 360
762
0
        putbef32((char *)buf, 18, (float)6.0);
763
0
        buf[22] = 0xff;  // must be 0xff
764
0
        buf[23] = 0x0;   // Anti-Jam Mode, 0=Off, 1=On
765
0
        putbe16(buf, 24, 0xffff);  // Reserved.  Must be 0xffff
766
        /* Measurement Rate and Position Fix Rate = default
767
         * must be 0xffff on res smt 360 */
768
0
        putbe16(buf, 26, 0x0000);
769
        /* 27 is Constellation on RES SMT 360.
770
         * 1 = GPS, 2=GLONASS, 8=BeiDou, 0x10=Galileo, 5=QZSS */
771
0
        putbe32(buf, 28, 0xffffffff);   // Reserved
772
0
        putbe32(buf, 32, 0xffffffff);   // Reserved
773
0
        putbe32(buf, 36, 0xffffffff);   // Reserved
774
0
        putbe32(buf, 40, 0xffffffff);   // Reserved
775
0
        (void)tsip_write1(session, buf, 44);
776
777
0
        buf[0] = 0x8e;   // Set Packet Broadcast Mask (0x8e-a5)
778
0
        buf[1] = 0xa5;   // Subcode a5
779
        /* Packets bit field = default + Primary timing,
780
         *  Supplemental timing 32e1
781
         *  1=0x8f-ab, 4=0x8f-ac, 0x40=Automatic Output Packets */
782
0
        putbe16(buf, 2, 0x32e1);
783
0
        buf[4] = 0x00;   // not used
784
0
        buf[5] = 0x00;   // not used
785
0
        (void)tsip_write1(session, buf, 6);
786
0
}
787
788
// configure RES 360, Resolution SMTx, and similar to a known state
789
static void configuration_packets_res360(struct gps_device_t *session)
790
0
{
791
0
    char buf[100];
792
793
0
    GPSD_LOG(LOG_PROG, &session->context->errout,
794
0
             "TSIP: configuration_packets_res360()\n");
795
796
    // should already have versions 0x8f-81 and 0x8f-83.
797
798
    // Request Self Survey Parameters (0x8e-a9)
799
0
    (void)tsip_write1(session, "\x8e\xa9", 2);
800
801
0
    if (session->context->passive) {
802
        // request I/O Options (0x55)
803
0
        (void)tsip_write1(session, "\x35", 1);
804
805
        // request Receiver Configuration (0xbb)
806
0
        (void)tsip_write1(session, "\xbb\x00", 2);
807
808
        // Request Packet Broadcast Mask (0x8e-a5)
809
0
        (void)tsip_write1(session, "\x8e\xa5", 2);
810
811
0
    } else {
812
        // PPS Output Option (0x8e-4e) is default on
813
814
0
        buf[0] = 0x8e;  // Set Packet Broadcast Mask (0x8e-a5)
815
0
        buf[1] = 0xa5;  // a5 = Subcode
816
        /* Packets bit field = default + Auto output packets
817
         *  1=0x8f-ab, 4=0x8f-ac, 0x40=Automatic Output Packets */
818
0
        buf[2] = 0;        // reserved
819
0
        buf[3] = 0x45;
820
0
        buf[4] = 0;        // reserved
821
0
        buf[5] = 0;        // reserved
822
0
        (void)tsip_write1(session, buf, 6);
823
824
        /* IO Options defaults:
825
         *   Lassen iQ:       02 02 00 00
826
         *   RES SMT 360:     12 02 00 08
827
         *   Resolution SMTx: 12 02 00 08
828
         */
829
0
        buf[0] = 0x35;  // set I/O Options
830
        // position and velocity only sent during self-survey.
831
        // Position
832
0
        buf[1] =  IO1_DP|IO1_LLA|IO1_ECEF;
833
        // Velocity
834
0
        buf[2] = IO2_VECEF|IO2_ENU;
835
        // Timing
836
0
        buf[3] = 0x01;          // Use 0x8e-a2
837
        // Auxiliary
838
0
        buf[4] = 0x08;         // Packet 0x5a off, dBHz
839
0
        (void)tsip_write1(session, buf, 5);
840
841
#ifdef __UNUSED__
842
// #if 1
843
        // Restart Self-Survey (0x8e-a6)
844
        // which gives us 2,000 normal fixes, before going quiet again.
845
        (void)tsip_write1(session, "\x8e\xa6\x00", 3);
846
#endif // __UNUSED__
847
0
    }
848
0
}
849
850
/* send the next TSIPv1 query
851
 * Return: void
852
 */
853
static void tsipv1_query(struct gps_device_t *session)
854
0
{
855
0
    char snd_buf[24];         // send buffer
856
857
    // advance to next queue item.
858
0
    session->driver.tsip.queue++;
859
    // allow it to repeat every x1000 packets
860
0
    session->driver.tsip.queue &= 0x0ffff;
861
862
0
    if (0 != (session->driver.tsip.queue % 4)) {
863
        // once every 4 messages
864
0
        return;
865
0
    }
866
0
    switch (session->driver.tsip.queue / 4) {
867
0
    case 1:
868
        // x90-00, query protocol version
869
0
        snd_buf[0] = 0x90;             // id
870
0
        snd_buf[1] = 0x00;             // sub id
871
0
        putbe16(snd_buf, 2, 2);        // length
872
0
        snd_buf[4] = 0;                // mode: query
873
0
        snd_buf[5] = tsip1_checksum(snd_buf, 5);   // checksum
874
0
        (void)tsip_write1(session, snd_buf, 6);
875
0
        break;
876
0
    case 2:
877
        // x90-01, query GNSS config version
878
0
        snd_buf[0] = 0x90;             // id
879
0
        snd_buf[1] = 0x01;             // sub id
880
0
        putbe16(snd_buf, 2, 2);        // length
881
0
        snd_buf[4] = 0;                // mode: query
882
0
        snd_buf[5] = tsip1_checksum(snd_buf, 5);   // checksum
883
0
        (void)tsip_write1(session, snd_buf, 6);
884
0
        break;
885
0
    case 3:
886
        // x91-00, Port config
887
0
        snd_buf[0] = 0x91;             // id
888
0
        snd_buf[1] = 0x00;             // sub id
889
0
        putbe16(snd_buf, 2, 3);        // length
890
0
        snd_buf[4] = 0;                // mode: query
891
0
        snd_buf[5] = 0;                // current port
892
0
        snd_buf[6] = tsip1_checksum(snd_buf, 6);   // checksum
893
0
        (void)tsip_write1(session, snd_buf, 7);
894
0
        break;
895
0
    case 4:
896
        // x81-01, GNSS config
897
0
        snd_buf[0] = 0x91;             // id
898
0
        snd_buf[1] = 0x01;             // sub id
899
0
        putbe16(snd_buf, 2, 2);        // length
900
0
        snd_buf[4] = 0;                // mode: query
901
0
        snd_buf[5] = tsip1_checksum(snd_buf, 5);   // checksum
902
0
        (void)tsip_write1(session, snd_buf, 6);
903
0
        break;
904
0
    case 5:
905
        // x91-03, query timing config
906
0
        snd_buf[0] = 0x91;             // id
907
0
        snd_buf[1] = 0x03;             // sub id
908
0
        putbe16(snd_buf, 2, 2);        // length
909
0
        snd_buf[4] = 0;                // mode: query
910
0
        snd_buf[5] = tsip1_checksum(snd_buf, 5);   // checksum
911
0
        (void)tsip_write1(session, snd_buf, 6);
912
0
        break;
913
0
    case 6:
914
        // x91-04, self survey config
915
0
        snd_buf[0] = 0x91;             // id
916
0
        snd_buf[1] = 0x04;             // sub id
917
0
        putbe16(snd_buf, 2, 2);        // length
918
0
        snd_buf[4] = 0;                // mode: query
919
0
        snd_buf[5] = tsip1_checksum(snd_buf, 5);   // checksum
920
0
        (void)tsip_write1(session, snd_buf, 6);
921
0
        break;
922
0
    case 7:
923
0
        if (session->context->passive) {
924
            // x91-05, query current periodic messages
925
0
            snd_buf[0] = 0x91;             // id
926
0
            snd_buf[1] = 0x05;             // sub id
927
0
            putbe16(snd_buf, 2, 3);        // length
928
0
            snd_buf[4] = 0;                // mode: query
929
0
            snd_buf[5] = 0xff;             // port: current port
930
0
            snd_buf[6] = tsip1_checksum(snd_buf, 6);   // checksum
931
0
            (void)tsip_write1(session, snd_buf, 7);
932
0
        } else {
933
            /* request periodic  messages, x91-05
934
             * little harm at 115.2 kbps, this also responses as a query */
935
0
            snd_buf[0] = 0x91;             // id
936
0
            snd_buf[1] = 0x05;             // sub id
937
0
            putbe16(snd_buf, 2, 19);       // length
938
0
            snd_buf[4] = 0x01;             // mode: set
939
0
            snd_buf[5] = 0xff;             // port: current port
940
            // 0xaaaaa, everything preiodic
941
0
            putbe32(snd_buf, 6, 0xaaaaa);
942
0
            putbe32(snd_buf, 10, 0);       // reserved
943
0
            putbe32(snd_buf, 14, 0);       // reserved
944
0
            putbe32(snd_buf, 18, 0);       // reserved
945
0
            snd_buf[22] = tsip1_checksum(snd_buf, 22);   // checksum
946
0
            (void)tsip_write1(session, snd_buf, 23);
947
0
        }
948
0
        break;
949
0
    case 8:
950
        // x93-00, production info
951
0
        snd_buf[0] = 0x93;             // id
952
0
        snd_buf[1] = 0x00;             // sub id
953
0
        putbe16(snd_buf, 2, 2);        // length
954
0
        snd_buf[4] = 0;                // mode: query
955
0
        snd_buf[5] = tsip1_checksum(snd_buf, 5);   // checksum
956
0
        (void)tsip_write1(session, snd_buf, 6);
957
0
        break;
958
0
    default:
959
        // nothing to do
960
0
        break;
961
0
    }
962
0
}
963
964
/* tsipv1_svtype()
965
 * convert TSIPv1 SV Type to satellite_t.gnssid and satellite_t.sigid
966
 * PRN is already GNSS specific (1-99)
967
 * return gnssid directly, sigid indirectly through pointer
968
 *
969
 * Return: gnssid
970
 *         0xff on error
971
 */
972
static unsigned char tsipv1_svtype(unsigned svtype, unsigned char *sigid)
973
0
{
974
975
0
    unsigned char gnssid;
976
977
0
    switch (svtype) {
978
0
    case 1:  // GPS L1C
979
0
       gnssid =  GNSSID_GPS;
980
0
       *sigid = 0;
981
0
       break;
982
0
    case 2:  // GPS L2.  CL or CM?
983
0
       gnssid =  GNSSID_GPS;
984
0
       *sigid = 3;         // or, maybe 4
985
0
       break;
986
0
    case 3:  // GPS L5.  I or Q?
987
0
       gnssid =  GNSSID_GPS;
988
0
       *sigid = 6;         // or maybe 7
989
0
       break;
990
0
    case 5:  // GLONASS G1
991
0
       gnssid =  GNSSID_GLO;
992
0
       *sigid = 0;
993
0
       break;
994
0
    case 6:  // GLONASS G2
995
0
       gnssid =  GNSSID_GLO;
996
0
       *sigid = 2;
997
0
       break;
998
0
    case 9:  // SBAS, assume L1
999
0
       gnssid =  GNSSID_SBAS;
1000
0
       *sigid = 0;
1001
0
       break;
1002
0
    case 13:  // Beidou B1, D1 or D2?
1003
0
       gnssid =  GNSSID_BD;
1004
0
       *sigid = 0;   // or maybe 1
1005
0
       break;
1006
0
    case 14:  // Beidou B2i
1007
0
       gnssid =  GNSSID_BD;
1008
0
       *sigid = 2;
1009
0
       break;
1010
0
    case 15:  // Beidou B2a
1011
0
       gnssid =  GNSSID_BD;
1012
0
       *sigid = 3;
1013
0
       break;
1014
0
    case 17:  // Galileo E1, C or B?
1015
0
       gnssid =  GNSSID_GAL;
1016
0
       *sigid = 0;    // or maybe 1
1017
0
       break;
1018
0
    case 18:  // Galileo E5a, aI or aQ?
1019
0
       gnssid =  GNSSID_GAL;
1020
0
       *sigid = 3;    // or maybe 4?
1021
0
       break;
1022
0
    case 19:  // Galileo E5b, bI or bQ?
1023
0
       gnssid =  GNSSID_GAL;
1024
0
       *sigid = 5;    // or maybe 6
1025
0
       break;
1026
0
    case 20:  // Galileo E6
1027
0
       gnssid =  GNSSID_GAL;
1028
0
       *sigid = 8;     // no idea
1029
0
       break;
1030
0
    case 22:  // QZSS L1
1031
0
       gnssid =  GNSSID_QZSS;
1032
0
       *sigid = 0;
1033
0
       break;
1034
0
    case 23:  // QZSS L2C
1035
0
       gnssid =  GNSSID_QZSS;
1036
0
       *sigid = 4;    // or maybe 5
1037
0
       break;
1038
0
    case 24:  // QZSS L5
1039
0
       gnssid =  GNSSID_QZSS;
1040
0
       *sigid = 8;     // no idea
1041
0
       break;
1042
0
    case 26:  // IRNSS L5
1043
0
       gnssid =  GNSSID_IRNSS;
1044
0
       *sigid = 8;     // no idea
1045
0
       break;
1046
0
    case 4:  // Reserved
1047
0
        FALLTHROUGH
1048
0
    case 7:  // Reserved
1049
0
        FALLTHROUGH
1050
0
    case 8:  // Reserved
1051
0
        FALLTHROUGH
1052
0
    case 10:  // Reservced
1053
0
        FALLTHROUGH
1054
0
    case 11:  // Reservced
1055
0
        FALLTHROUGH
1056
0
    case 12:  // Reservced
1057
0
        FALLTHROUGH
1058
0
    case 16:  // Reserved
1059
0
        FALLTHROUGH
1060
0
    case 21:  // Reserved
1061
0
        FALLTHROUGH
1062
0
    case 25:  // Reserved
1063
0
        FALLTHROUGH
1064
0
    default:
1065
0
        *sigid = 0xff;
1066
0
        return 0xff;
1067
0
    }
1068
0
    return gnssid;
1069
0
}
1070
1071
// decode packet xa3-00
1072
static gps_mask_t decode_xa3_00(struct gps_device_t *session, const char *buf)
1073
0
{
1074
0
    gps_mask_t mask = 0;
1075
0
    char buf2[BUFSIZ];
1076
0
    char buf3[BUFSIZ];
1077
1078
0
    unsigned minor_alarm = getbeu32(buf, 4);            // Minor Alarms
1079
0
    unsigned res1 = getbeu32(buf, 8);                   // reserved
1080
0
    unsigned major_alarm = getbeu32(buf, 12);           // Major Alarms
1081
0
    unsigned res2 = getbeu32(buf, 16);                  // reserved
1082
1083
0
    if (1 == (major_alarm & 1)) {
1084
        // not tracking sats, assume surveyed-in
1085
0
        session->newdata.status = STATUS_DR;
1086
0
    } else {
1087
0
        session->newdata.status = STATUS_GPS;
1088
0
    }
1089
0
    mask |= STATUS_SET;
1090
1091
0
    if (1 & minor_alarm) {
1092
0
        session->newdata.ant_stat = ANT_OPEN;
1093
0
    } else if (2 & minor_alarm) {
1094
0
        session->newdata.ant_stat = ANT_SHORT;
1095
0
    } else {
1096
0
        session->newdata.ant_stat = ANT_OK;
1097
0
    }
1098
0
    GPSD_LOG(LOG_PROG, &session->context->errout,
1099
0
             "TSIPv1 xa3-00: Minor x%04x res x%04x Major x%04x "
1100
0
             "res x%04u status %d\n",
1101
0
             minor_alarm, res1, major_alarm, res2,
1102
0
             session->newdata.status);
1103
0
    GPSD_LOG(LOG_IO, &session->context->errout,
1104
0
             "TSIPv1: minor:%s mojor:%s status:%s\n",
1105
0
             flags2str(minor_alarm, vminor_alarms1, buf2, sizeof(buf2)),
1106
0
             flags2str(major_alarm, vmajor_alarms1, buf3, sizeof(buf3)),
1107
0
             val2str(session->newdata.status, vstatus_str));
1108
0
    return mask;
1109
0
}
1110
1111
// decode packet xa3-11
1112
static gps_mask_t decode_xa3_11(struct gps_device_t *session, const char *buf)
1113
0
{
1114
0
    gps_mask_t mask = 0;
1115
1116
0
    unsigned rec_mode = getub(buf, 4);                // receiver mode
1117
0
    unsigned rec_status = getub(buf, 5);              // status
1118
0
    unsigned ssp = getub(buf, 6);              // self survey progress 0 - 100
1119
0
    session->gpsdata.dop.pdop = getbef32(buf, 7);     // PDOP
1120
0
    session->gpsdata.dop.hdop = getbef32(buf, 11);    // HDOP
1121
0
    session->gpsdata.dop.vdop = getbef32(buf, 15);    // VDOP
1122
0
    session->gpsdata.dop.tdop = getbef32(buf, 19);    // TDOP
1123
0
    session->newdata.temp = getbef32(buf, 23);        // Temperature, degrees C
1124
1125
    // don't have tow, so use the one from xa2-00, if any
1126
0
    session->driver.tsip.last_a311 = session->driver.tsip.last_a200;
1127
1128
0
    if (0 < session->driver.tsip.last_a200) {
1129
0
        session->driver.tsip.last_a200 = 0;
1130
        // TSIPv1 seem to be sent in numerical order, so this
1131
        // is after xa2-00 and the sats.  Push out any lingering sats.
1132
0
        mask |= SATELLITE_SET;
1133
0
    }
1134
0
    mask |= REPORT_IS | DOP_SET;
1135
0
    switch (rec_status) {
1136
0
    case 0:         // 2D
1137
0
        session->newdata.mode = MODE_2D;
1138
0
        mask |= MODE_SET;
1139
0
        break;
1140
0
    case 1:         // 3D (time only)
1141
0
        session->newdata.mode = MODE_3D;
1142
0
        mask |= MODE_SET;
1143
0
        break;
1144
0
    case 3:         // Automatic (?)
1145
0
        break;
1146
0
    case 4:         // OD clock
1147
0
        session->newdata.status = STATUS_TIME;
1148
0
        mask |= STATUS_SET;
1149
0
        break;
1150
0
    default:        // Huh?
1151
0
        break;
1152
0
    }
1153
1154
0
    switch (rec_status) {
1155
0
    case 0:         // doing position fixes
1156
0
        FALLTHROUGH
1157
0
    case 4:         // using 1 sat
1158
0
        FALLTHROUGH
1159
0
    case 5:         // using 2 sat
1160
0
        FALLTHROUGH
1161
0
    case 6:         // using 3 sat
1162
0
        session->newdata.status = STATUS_GPS;
1163
0
        mask |= STATUS_SET;
1164
0
        break;
1165
0
    case 1:         // no GPS time
1166
0
        FALLTHROUGH
1167
0
    case 2:         // PDOP too high
1168
0
        FALLTHROUGH
1169
0
    case 3:         // no sats
1170
0
        session->newdata.status = STATUS_UNK;
1171
0
        mask |= STATUS_SET;
1172
0
        break;
1173
0
    case 255:
1174
0
        session->newdata.mode = MODE_3D;
1175
0
        session->newdata.status = STATUS_TIME;
1176
0
        mask |= STATUS_SET | MODE_SET;
1177
0
        break;
1178
0
    default:
1179
        // huh?
1180
0
        break;
1181
0
    }
1182
1183
0
    if (10.0 < session->gpsdata.dop.pdop) {
1184
0
        session->newdata.status = STATUS_DR;
1185
0
        mask |= STATUS_SET;
1186
0
    }
1187
1188
0
    GPSD_LOG(LOG_PROG, &session->context->errout,
1189
0
             "TSIPv1 xa3-11: mode %d status %d rm %u stat %u survey %u "
1190
0
             "PDOP %f HDOP %f VDOP %f TDOP %f temp %f\n",
1191
0
             session->newdata.mode,
1192
0
             session->newdata.status,
1193
0
             rec_mode, rec_status, ssp,
1194
0
             session->gpsdata.dop.pdop,
1195
0
             session->gpsdata.dop.hdop,
1196
0
             session->gpsdata.dop.vdop,
1197
0
             session->gpsdata.dop.tdop,
1198
0
             session->newdata.temp);
1199
0
    GPSD_LOG(LOG_IO, &session->context->errout,
1200
0
             "TSIPv1: mode:%s status:%s rm:%s stat:%s\n",
1201
0
             val2str(session->newdata.mode, vmode_str),
1202
0
             val2str(session->newdata.status, vstatus_str),
1203
0
             val2str(rec_mode, vrec_mode1),
1204
0
             val2str(rec_status, vgnss_decode_status1));
1205
1206
0
    return mask;
1207
0
}
1208
1209
1210
/* parse TSIP v1 packages.
1211
* Currently only in RES720 devices, from 2020 onward.
1212
* buf: raw data, with DLE stuffing removed
1213
* len:  length of data in buf
1214
*
1215
* return: mask
1216
*/
1217
static gps_mask_t tsipv1_parse(struct gps_device_t *session, unsigned id,
1218
                                const char *buf, int len)
1219
0
{
1220
0
    gps_mask_t mask = 0;
1221
0
    unsigned sub_id, length, mode;
1222
0
    unsigned short week;
1223
0
    uint32_t tow;             // time of week in milli seconds
1224
0
    timespec_t ts_tow;
1225
0
    unsigned u1, u2, u3, u4, u5, u6, u7, u8, u9;
1226
0
    unsigned u10, u11;
1227
0
    int s1;
1228
0
    double d1, d2, d3, d4, d5, d6, d7, d8, d9;
1229
0
    struct tm date = {0};
1230
0
    bool bad_len = false;
1231
0
    unsigned char chksum;
1232
0
    char buf2[BUFSIZ];
1233
0
    char buf3[BUFSIZ];
1234
0
    unsigned char gnssid, sigid;
1235
1236
0
    if (4 > len) {
1237
        // should never happen
1238
0
        GPSD_LOG(LOG_WARN, &session->context->errout,
1239
0
                 "TSIPv1 0x%02x: runt, got len %u\n",
1240
0
                 id, len);
1241
0
        return mask;
1242
0
    }
1243
    /* Note: bug starts at sub id, offset 2 of the wire packet.
1244
     * So subtract 2 from the offsets in the Trimble doc. */
1245
0
    sub_id = getub(buf, 0);
1246
0
    length = getbeu16(buf, 1);  // expected length
1247
0
    mode = getub(buf, 3);
1248
1249
0
    if ((length + 3) != (unsigned)len) {
1250
0
        GPSD_LOG(LOG_WARN, &session->context->errout,
1251
0
                 "TSIPv1 x%02x-%02x: Bad Length, "
1252
0
                 "length got %d expected %u mode %u\n",
1253
0
                 id, sub_id, len, length + 3, mode);
1254
0
        return mask;
1255
0
    }
1256
1257
    // checksum is id, sub id, length, mode, data, not including trailer
1258
    // length is mode + data + checksum
1259
0
    chksum = id;
1260
0
    for (u1 = 0; u1 < (length + 3); u1++ ) {
1261
0
        chksum ^= buf[u1];
1262
0
    }
1263
0
    if (0 != chksum) {
1264
0
        GPSD_LOG(LOG_WARN, &session->context->errout,
1265
0
                 "TSIPv1 x%02x-%02x: Bad Checksum "
1266
0
                 "length %d/%u mode %u\n",
1267
0
                 id, sub_id, len, length + 3, mode);
1268
0
        return mask;
1269
0
    }
1270
1271
0
    GPSD_LOG(LOG_DATA, &session->context->errout,
1272
0
             "TSIPv1 x%02x-%02x: length %d/%u mode %u\n",
1273
0
             id, sub_id, len, length + 3, mode);
1274
1275
0
    if (2 != mode) {
1276
        /* Don't decode queries (mode 0) or set (mode 1).
1277
         * Why would we even see one? */
1278
0
        return mask;
1279
0
    }
1280
    // FIXME: check len/length
1281
0
    switch ((id << 8) | sub_id) {
1282
0
    case 0x9000:
1283
        // Protocol Version, x90-00
1284
0
        if (11 > length) {
1285
0
            bad_len = true;
1286
0
            break;
1287
0
        }
1288
0
        u1 = getub(buf, 4);              // NMEA Major version
1289
0
        u2 = getub(buf, 5);              // NMEA Minor version
1290
0
        u3 = getub(buf, 6);              // TSIP version
1291
0
        u4 = getub(buf, 7);              // Trimble NMEA version
1292
0
        u6 = getbeu32(buf, 8);           // reserved
1293
0
        u7 = getub(buf, 12);             // reserved
1294
0
        GPSD_LOG(LOG_PROG, &session->context->errout,
1295
0
                 "TSIPv1 x90-00: NMEA %u.%u TSIP %u TNMEA %u "
1296
0
                 "res x%04x x%02x \n",
1297
0
                 u1, u2, u3, u4, u6, u7);
1298
0
        break;
1299
0
    case 0x9001:
1300
        /* Receiver Version Information, x90-01
1301
         * Received in response to the TSIPv1 probe */
1302
0
        if (11 > length) {
1303
0
            bad_len = true;
1304
0
            break;
1305
0
        }
1306
0
        u1 = getub(buf, 4);               // Major version
1307
0
        u2 = getub(buf, 5);               // Minor version
1308
0
        u3 = getub(buf, 6);               // Build number
1309
0
        u4 = getub(buf, 7);               // Build month
1310
0
        u5 = getub(buf, 8);               // Build day
1311
0
        u6 = getbeu16(buf, 9);            // Build year
1312
0
        u7 = getbeu16(buf, 11);           // Hardware ID
1313
0
        u8 = getub(buf, 13);              // Product Name length
1314
0
        session->driver.tsip.hardware_code = u7;
1315
        // check for valid module name length
1316
        // RES720 is 27 long
1317
        // check for valid module name length, again
1318
0
        if (40 < u8) {
1319
0
            u8 = 40;
1320
0
        }
1321
0
        if ((int)u8 > (len - 13)) {
1322
0
            u8 = len - 13;
1323
0
        }
1324
0
        memcpy(buf2, &buf[14], u8);
1325
0
        buf2[u8] = '\0';
1326
0
        (void)snprintf(session->subtype, sizeof(session->subtype),
1327
0
                       "fw %u.%u %u %02u/%02u/%04u %.40s",
1328
0
                       u1, u2, u3, u6, u5, u4, buf2);
1329
0
        GPSD_LOG(LOG_PROG, &session->context->errout,
1330
0
                 "TSIPv1 x90-01: Version %u.%u Build %u %u/%u/%u hwid %u, "
1331
0
                 "%.*s[%u]\n",
1332
0
                 u1, u2, u3, u6, u5, u4, u7, u8, buf2, u8);
1333
0
        mask |= DEVICEID_SET;
1334
1335
0
        break;
1336
0
    case 0x9100:
1337
        // Port Configuration, x91-00
1338
0
        if (17 > length) {
1339
0
            bad_len = true;
1340
0
            break;
1341
0
        }
1342
0
        u1 = getub(buf, 4);               // port
1343
0
        u2 = getub(buf, 5);               // port type
1344
0
        u3 = getub(buf, 6);               // protocol
1345
0
        u4 = getub(buf, 7);               // baud rate
1346
0
        u5 = getub(buf, 8);               // data bits
1347
0
        u6 = getub(buf, 9);               // parity
1348
0
        u7 = getub(buf, 10);              // stop bits
1349
0
        u8 = getbeu32(buf, 11);           // reserved
1350
0
        u9 = getbeu32(buf, 12);           // reserved
1351
0
        GPSD_LOG(LOG_PROG, &session->context->errout,
1352
0
                 "TSIPv1 x91-00: port %u type %u proto %u baud %u bits %u "
1353
0
                 "parity %u stop %u res x%04x %04x\n",
1354
0
                 u1, u2, u3, u4, u5, u6, u7, u8, u9);
1355
0
        GPSD_LOG(LOG_IO, &session->context->errout,
1356
0
                 "TSIPv1: port:%s type:%s, proto:%s speed:%s bits:%s %s %s\n",
1357
0
                 val2str(u1, vport_name1),
1358
0
                 val2str(u2, vport_type1),
1359
0
                 val2str(u3, vprotocol1),
1360
0
                 val2str(u4, vspeed1),
1361
0
                 val2str(u5, vdbits1),
1362
0
                 val2str(u6, vparity1),
1363
0
                 val2str(u6, vstop1));
1364
1365
0
        break;
1366
0
    case 0x9101:
1367
        // GNSS Configuration, x91-01
1368
0
        if (28 > length) {
1369
0
            bad_len = true;
1370
0
            break;
1371
0
        }
1372
        /* constellations, 0 to 26, mashup of constellation and signal
1373
         * ignore if 0xffffffff */
1374
0
        u1 = getbeu32(buf, 4);            // constellation
1375
0
        d1 = getbef32(buf, 8);            // elevation mask
1376
0
        d2 = getbef32(buf, 12);           // signal mask
1377
0
        d3 = getbef32(buf, 16);           // PDOP mask
1378
0
        u2 = getub(buf, 20);              // anti-jamming
1379
0
        u3 = getub(buf, 21);              // fix rate
1380
0
        d4 = getbef32(buf, 22);           // Antenna CAble delay, seconds
1381
0
        u4 = getbeu32(buf, 26);           // reserved
1382
0
        GPSD_LOG(LOG_PROG, &session->context->errout,
1383
0
                 "TSIPv1 x91-01: cons x%x el %f signal %f PDOP %f jam %u "
1384
0
                 "rate %u delay %f res x%04x\n",
1385
0
                 u1, d1, d2, d3, u2, u3, d4, u4);
1386
0
        GPSD_LOG(LOG_IO, &session->context->errout,
1387
0
                 "TSIPv1: cons %s\n",
1388
0
                 flags2str(u1, vsv_types1, buf2, sizeof(buf2)));
1389
0
        break;
1390
0
    case 0x9102:
1391
        // NVS Configuration, x91-02
1392
0
        if (8 > length) {
1393
0
            bad_len = true;
1394
0
            break;
1395
0
        }
1396
0
        u1 = getub(buf, 6);               // status
1397
0
        u2 = getbeu32(buf, 7);            // reserved
1398
0
        GPSD_LOG(LOG_PROG, &session->context->errout,
1399
0
                 "TSIPv1 x91-02: status %u res x%04x\n",
1400
0
                 u1, u2);
1401
0
        break;
1402
0
    case 0x9103:
1403
        // Timing Configuration, x91-03
1404
0
        if (19 > length) {
1405
0
            bad_len = true;
1406
0
            break;
1407
0
        }
1408
0
        u1 = getub(buf, 4);               // time basee
1409
0
        u2 = getub(buf, 5);               // PPS base
1410
0
        u3 = getub(buf, 6);               // PPS mask
1411
0
        u4 = getbeu16(buf, 7);            // reserved
1412
0
        u5 = getbeu16(buf, 9);            // PPS width
1413
0
        d1 = getbed64(buf, 11);           // PPS offset, in seconds
1414
0
        GPSD_LOG(LOG_PROG, &session->context->errout,
1415
0
                 "TSIPv1 x91-03: time base %u PPS base %u mask %u res x%04x "
1416
0
                 "width %u offset %f\n",
1417
0
                 u1, u2, u3, u4, u5, d1);
1418
0
        GPSD_LOG(LOG_IO, &session->context->errout,
1419
0
                 "TSIPv1: time base:%s pps base:%s pps mask:%s\n",
1420
0
                 val2str(u1, vtime_base1),
1421
0
                 val2str(u2, vtime_base1),
1422
0
                 val2str(u3, vpps_mask1));
1423
0
        break;
1424
0
    case 0x9104:
1425
        // Self-Survey Configuration, x91-04
1426
0
        if (11 > length) {
1427
0
            bad_len = true;
1428
0
            break;
1429
0
        }
1430
0
        u1 = getub(buf, 4);               // self-survey mask
1431
0
        u2 = getbeu32(buf, 5);            // self-survey length, # fixes
1432
0
        u3 = getbeu16(buf, 9);            // horz uncertainty, meters
1433
0
        u4 = getbeu16(buf, 11);           // vert uncertainty, meters
1434
0
        GPSD_LOG(LOG_PROG, &session->context->errout,
1435
0
                 "TSIPv1 x91-04: mask x%x length %u eph %u epv %u\n",
1436
0
                 u1, u2, u3, u4);
1437
0
        GPSD_LOG(LOG_IO, &session->context->errout,
1438
0
                 "TSIPv1:ssmask %s\n",
1439
0
                 flags2str(u1, vss_mask1, buf2, sizeof(buf2)));
1440
0
        break;
1441
0
    case 0x9105:
1442
        //  Receiver Configuration, xx91-05
1443
0
        if (19 > length) {
1444
0
            bad_len = true;
1445
0
            break;
1446
0
        }
1447
0
        u1 = getub(buf, 4);              // port
1448
0
        u2 = getbeu32(buf, 5);           // type of output
1449
0
        u3 = getbeu32(buf, 9);           // reserved
1450
0
        u4 = getbeu32(buf, 13);          // reserved
1451
0
        u5 = getbeu32(buf, 17);          // reserved
1452
0
        GPSD_LOG(LOG_PROG, &session->context->errout,
1453
0
                 "TSIPv1 x91-05: port %u type x%04x res x%04x x%04x x%04x\n",
1454
0
                 u1, u2, u3, u4, u5);
1455
0
        GPSD_LOG(LOG_IO, &session->context->errout,
1456
0
                 "TSIPv1: port %s\n",
1457
0
                 val2str(u1, vport_name1));
1458
0
        break;
1459
0
    case 0x9201:
1460
        // Reset Cause, x92-01
1461
0
        if (3 > length) {
1462
0
            bad_len = true;
1463
0
            break;
1464
0
        }
1465
0
        u1 = getub(buf, 6);               // reset cause
1466
0
        GPSD_LOG(LOG_WARN, &session->context->errout,
1467
0
                 "TSIPv1 x92-01: cause %u\n", u1);
1468
0
        break;
1469
0
    case 0x9300:
1470
        // Production Information, x93-00
1471
0
        if (78 > length) {
1472
0
            bad_len = true;
1473
0
            break;
1474
0
        }
1475
0
        u1 = getub(buf, 4);               // reserved. always 0xff
1476
0
        u2 = getbeu32(buf, 5);            // serial number
1477
0
        u3 = getbeu64(buf, 9);            // extended serial number
1478
0
        u4 = getbeu64(buf, 17);           // extended serial number
1479
0
        u5 = getub(buf, 25);              // build day
1480
0
        u6 = getub(buf, 26);              // build month
1481
0
        u7 = getbeu16(buf, 27);           // build year
1482
0
        u8 = getub(buf, 29);              // build hour
1483
0
        u9 = getbeu16(buf, 30);           // machine id
1484
        // getbeu64(buf, 32);             // hardware ID string
1485
        // getbeu64(buf, 40);             // hardware ID string
1486
        // getbeu64(buf, 48);             // product ID string
1487
        // getbeu64(buf, 56);             // product ID string
1488
0
        u10 = getbeu32(buf, 64);          // premium options
1489
0
        u11 = getbeu32(buf, 78);          // reserved
1490
        // ignore 77 Osc search range, and 78–81 Osc offset, always 0xff
1491
0
        (void)snprintf(session->subtype1, sizeof(session->subtype1),
1492
0
                       "hw %u %02u/%02u/%04u",
1493
0
                       u9, u5, u6, u7);
1494
        // The sernum I get does not match the printed one on the device...
1495
        // extended sernum seems to be zeros...
1496
0
        (void)snprintf(session->gpsdata.dev.sernum,
1497
0
                       sizeof(session->gpsdata.dev.sernum),
1498
0
                       "%x", u2);
1499
0
        GPSD_LOG(LOG_WARN, &session->context->errout,
1500
0
                 "TSIPv1 x93-00: res %u ser %s x%x-%x Build %u/%u/%u %u "
1501
0
                 "machine %u hardware %s product %s "
1502
0
                 "options x%04x res x%04x\n",
1503
0
                 u1, session->gpsdata.dev.sernum,
1504
0
                 u3, u4, u7, u6, u5, u8, u9,
1505
0
                 gpsd_packetdump(buf2, sizeof(buf2),
1506
0
                                (const unsigned char *)&buf[32], 16),
1507
0
                 gpsd_packetdump(buf3, sizeof(buf3),
1508
0
                                (const unsigned char *)&buf[48], 16),
1509
0
                 u10, u11);
1510
0
        mask |= DEVICEID_SET;
1511
0
        break;
1512
0
    case 0xa000:
1513
        // Firmware Upload, xa0-00
1514
        // could be length 3, or 8, different data...
1515
0
        switch (length) {
1516
0
        case 3:
1517
0
            u1 = getub(buf, 6);               // command
1518
0
            GPSD_LOG(LOG_PROG, &session->context->errout,
1519
0
                     "TSIPv1 xa0-00: command %u\n", u1);
1520
0
            break;
1521
0
        case 8:
1522
            // ACK/NAK
1523
0
            u1 = getub(buf, 6);               // command
1524
0
            u2 = getub(buf, 7);               // status
1525
0
            u3 = getbeu16(buf, 8);            // frame
1526
0
            GPSD_LOG(LOG_PROG, &session->context->errout,
1527
0
                     "TSIPv1 xa0-00: command %u status %u frame %u\n",
1528
0
                     u1, u2, u3);
1529
0
            break;
1530
0
        default:
1531
0
            bad_len = true;
1532
0
            break;
1533
0
        }
1534
0
        break;
1535
0
    case 0xa100:
1536
        // Timing Information. xa1-00
1537
        // the only message on by default
1538
0
        if (32 > length) {
1539
0
            bad_len = true;
1540
0
            break;
1541
0
        }
1542
1543
0
        tow = getbeu32(buf, 4);
1544
0
        week = getbeu16(buf, 8);
1545
0
        session->context->gps_week = week;
1546
1547
0
        date.tm_hour = getub(buf, 10);               // hours 0 - 23
1548
0
        date.tm_min = getub(buf, 11);                // minutes 0 -59
1549
0
        date.tm_sec = getub(buf, 12);                // seconds 0 - 60
1550
0
        date.tm_mon = getub(buf, 13) - 1;            // month 1 - 12
1551
0
        date.tm_mday = getub(buf, 14);               // day of month 1 - 31
1552
0
        date.tm_year = getbeu16(buf, 15) - 1900;     // year
1553
1554
0
        u1 = getub(buf, 17);                // time base
1555
0
        u2 = getub(buf, 18);                // PPS base
1556
0
        u3 = getub(buf, 19);                // flags
1557
0
        s1 = getbes16(buf, 20);             // UTC Offset
1558
0
        d1 = getbef32(buf, 22);             // PPS Quantization Error
1559
0
        d2 = getbef32(buf, 26);             // Bias
1560
0
        d3 = getbef32(buf, 30);             // Bias Rate
1561
1562
        // convert seconds to pico seconds
1563
0
        session->gpsdata.qErr = (long)(d1 * 10e12);
1564
        // fix.time is w/o leap seconds...
1565
0
        session->newdata.time.tv_sec = mkgmtime(&date) - s1;
1566
0
        session->newdata.time.tv_nsec = 0;
1567
1568
0
        session->context->leap_seconds = s1;
1569
0
        session->context->valid |= LEAP_SECOND_VALID;
1570
0
        GPSD_LOG(LOG_PROG, &session->context->errout,
1571
0
                 "TSIPv1 xa1-00: tow %u week %u %02u:%02u:%02u %4u/%02u/%02u "
1572
0
                 "tbase %u/%u tflags x%x UTC offset %d qErr %f Bias %f/%f\n",
1573
0
                 tow, week, date.tm_hour, date.tm_min, date.tm_sec,
1574
0
                 date.tm_year + 1900, date.tm_mon, date.tm_mday,
1575
0
                 u1, u2, u3, s1, d1, d2, d3);
1576
0
        GPSD_LOG(LOG_IO, &session->context->errout,
1577
0
                 "TSIPv1: tbase:%s pbase:%s tflags:%s\n",
1578
0
                 val2str(u1, vtime_base1),
1579
0
                 val2str(u2, vtime_base1),
1580
0
                 flags2str(u3, vtime_flags1, buf2, sizeof(buf2)));
1581
1582
0
        if (2 == (u3 & 2)) {
1583
            // flags say we have good time
1584
            // if we have good time, can we guess at fix mode?
1585
0
            mask |= TIME_SET;
1586
0
            if (1 == (u3 & 1)) {
1587
                // good UTC
1588
0
                mask |= NTPTIME_IS;
1589
0
            }
1590
0
        }
1591
0
        if (0 == session->driver.tsip.hardware_code) {
1592
            // Query Receiver Version Information
1593
0
            (void)tsip_write1(session, "\x90\x01\x00\x02\x00\x93", 6);
1594
0
        }
1595
0
        mask |= CLEAR_IS;  // ssems to always be first. Time to clear.
1596
0
        break;
1597
0
    case 0xa102:
1598
        // Frequency Information, xa1-02
1599
0
        if (17 > length) {
1600
0
            bad_len = true;
1601
0
            break;
1602
0
        }
1603
0
        d1 = getbef32(buf, 6);            // DAC voltage
1604
0
        u1 = getbeu16(buf, 10);           // DAC value
1605
0
        u2 = getub(buf, 12);              // holdover status
1606
0
        u3 = getbeu32(buf, 13);           // holdover time
1607
0
        session->newdata.temp = getbef32(buf, 17);  // Temperature, degrees C
1608
0
        GPSD_LOG(LOG_PROG, &session->context->errout,
1609
0
                 "TSIPv1 xa1-02: DAC voltage %f value %u Holdover status %u "
1610
0
                 "time %u temp %f\n",
1611
0
                 d1, u1, u2, u3, session->newdata.temp);
1612
0
        break;
1613
1614
0
    case 0xa111:
1615
        // Position Information, xa1-11
1616
0
        if (52 > length) {
1617
0
            bad_len = true;
1618
0
            break;
1619
0
        }
1620
0
        u1 = getub(buf, 4);               // position mask
1621
0
        u2 = getub(buf, 5);               // fix type
1622
0
        d1 = getbed64(buf, 6);            // latitude or X
1623
0
        d2 = getbed64(buf, 14);           // longitude or Y
1624
0
        d3 = getbed64(buf, 22);           // altitude or Z
1625
0
        d4 = getbef32(buf, 30);           // velocity X or E
1626
0
        d5 = getbef32(buf, 34);           // velocity Y or N
1627
0
        d6 = getbef32(buf, 38);           // velocity Z or U
1628
0
        d7 = getbef32(buf, 42);           // PDOP, surveyed or current
1629
0
        d8 = getbef32(buf, 46);           // horz uncertainty
1630
0
        d9 = getbef32(buf, 50);           // vert uncertainty
1631
0
        session->gpsdata.dop.pdop = d7;
1632
0
        mask |= DOP_SET;
1633
        // position mask bit 0 does not tell us if we are in OD mode
1634
0
        if (0 == (u1 & 2)) {
1635
            // LLA
1636
0
            session->newdata.latitude = d1;
1637
0
            session->newdata.longitude = d2;
1638
0
            if (0 == (u1 & 4)) {
1639
                // HAE
1640
0
                session->newdata.altHAE = d3;
1641
0
            } else {
1642
                // MSL
1643
0
                session->newdata.altMSL = d3;
1644
0
            }
1645
0
            mask |= LATLON_SET | ALTITUDE_SET;
1646
0
        } else {
1647
            // XYZ ECEF
1648
0
            session->newdata.ecef.x = d1;
1649
0
            session->newdata.ecef.y = d2;
1650
0
            session->newdata.ecef.z = d3;
1651
0
            mask |= ECEF_SET;
1652
0
        }
1653
0
        if (0 == (u1 & 1)) {
1654
            // valid velocity
1655
0
            if (0 == (u1 & 8)) {
1656
                // Velocity ENU
1657
0
                session->newdata.NED.velN = d5;
1658
0
                session->newdata.NED.velE = d4;
1659
0
                session->newdata.NED.velD = -d6;
1660
0
                mask |= VNED_SET;
1661
0
            } else {
1662
                // Velocity ECEF
1663
0
                session->newdata.ecef.vx = d4;
1664
0
                session->newdata.ecef.vy = d5;
1665
0
                session->newdata.ecef.vz = d6;
1666
0
                mask |= VECEF_SET;
1667
0
            }
1668
0
        }
1669
0
        switch (u2) {
1670
0
        default:
1671
0
            FALLTHROUGH
1672
0
        case 0:
1673
0
            session->newdata.mode = MODE_NO_FIX;
1674
0
            break;
1675
0
        case 1:
1676
0
            session->newdata.mode = MODE_2D;
1677
0
            break;
1678
0
        case 2:
1679
0
            session->newdata.mode = MODE_3D;
1680
0
        }
1681
0
        session->gpsdata.dop.pdop = d7;
1682
0
        session->newdata.eph = d8;       // 0 - 100, unknown units
1683
0
        session->newdata.epv = d9;       // 0 - 100, unknown units
1684
        // status NOT set
1685
0
        mask |= MODE_SET | DOP_SET | HERR_SET | VERR_SET;
1686
0
        GPSD_LOG(LOG_PROG, &session->context->errout,
1687
0
                 "TSIPv1 xa1-11: mode %d status %d pmask %u fixt %u "
1688
0
                 "Pos %f %f %f Vel %f %f %f PDOP %f eph %f epv %f\n",
1689
0
                 session->newdata.mode,
1690
0
                 session->newdata.status,
1691
0
                 u1, u2, d1, d2, d3, d4, d5, d6, d7, d8, d9);
1692
0
        GPSD_LOG(LOG_IO, &session->context->errout,
1693
0
                 "TSIPv1: mode:%s status:%s pmask:%s fixt %s\n",
1694
0
                 val2str(session->newdata.mode, vmode_str),
1695
0
                 val2str(session->newdata.status, vstatus_str),
1696
0
                 flags2str(u1, vpos_mask1, buf2, sizeof(buf2)),
1697
0
                 val2str(u2, vfix_type1));
1698
0
        break;
1699
0
    case 0xa200:
1700
        // Satellite Information, xa2-00
1701
0
        if (25 > length) {
1702
0
            bad_len = true;
1703
0
            break;
1704
0
        }
1705
0
        u1 = getub(buf, 4);               // message number, 1 to X
1706
0
        if (1 == u1) {
1707
            // message number starts at 1, no way to know last number
1708
0
            gpsd_zero_satellites(&session->gpsdata);
1709
            // start of new cycle, save last count
1710
0
            session->gpsdata.satellites_visible =
1711
0
                session->driver.tsip.last_chan_seen;
1712
0
        }
1713
0
        session->driver.tsip.last_chan_seen = u1;
1714
1715
        // SV type, 0 to 26, mashup of constellation and signal
1716
0
        u2 = getub(buf, 5);
1717
0
        u3 = getub(buf, 6);               // PRN (svid) 1 to 32 (99)
1718
0
        d1 = getbef32(buf, 7);            // azimuth, degrees
1719
0
        d2 = getbef32(buf, 11);           // elevation, degrees
1720
0
        d3 = getbef32(buf, 15);           // signal level, db-Hz
1721
0
        u4 = getbeu32(buf, 19);           // Flags
1722
        // TOW of measurement, not current TOW!
1723
0
        tow = getbeu32(buf, 23);          // TOW, seconds
1724
0
        session->driver.tsip.last_a200 = tow;
1725
0
        ts_tow.tv_sec = tow;
1726
0
        ts_tow.tv_nsec = 0;
1727
0
        session->gpsdata.skyview_time =
1728
0
                gpsd_gpstime_resolv(session, session->context->gps_week,
1729
0
                                    ts_tow);
1730
1731
        // convert svtype to gnssid and svid
1732
0
        gnssid = tsipv1_svtype(u2, &sigid);
1733
0
        session->gpsdata.skyview[u1 - 1].gnssid = gnssid;
1734
0
        session->gpsdata.skyview[u1 - 1].svid = u3;
1735
0
        session->gpsdata.skyview[u1 - 1].sigid = sigid;
1736
        // "real" NMEA 4.0 (not 4.10 ir 4.11) PRN
1737
0
        session->gpsdata.skyview[u1 - 1].PRN = ubx2_to_prn(gnssid, u3);
1738
0
        if (0 != (1 & u4)) {
1739
0
            if (90.0 >= fabs(d2)) {
1740
0
                session->gpsdata.skyview[u1 - 1].elevation = d2;
1741
0
            }
1742
0
            if (360.0 >= d1 &&
1743
0
                0.0 <= d1) {
1744
0
                session->gpsdata.skyview[u1 - 1].azimuth = d1;
1745
0
            }
1746
0
        }
1747
0
        session->gpsdata.skyview[u1 - 1].ss = d3;
1748
0
        if (0 != (6 & u4)) {
1749
0
            session->gpsdata.skyview[u1 - 1].used = true;
1750
0
        }
1751
1752
0
        if ((int)u1 >= session->gpsdata.satellites_visible) {
1753
            /* Last of the series? Assume same number of sats as
1754
             * last cycle.
1755
             * This will cause extra SKY if this set has more
1756
             * sats than the last set.  Will cause drop outs when
1757
             * number of sats decreases. */
1758
0
            if (10 < llabs(session->driver.tsip.last_a311 -
1759
0
                           session->driver.tsip.last_a200)) {
1760
                // no xa3-11 in 10 seconds, so push out now
1761
0
                mask |= SATELLITE_SET;
1762
0
                session->driver.tsip.last_a200 = 0;
1763
0
            }
1764
0
        }
1765
        /* If this series has fewer than last series there will
1766
         * be no SKY, unless the cycle ender pushes the SKY */
1767
0
        GPSD_LOG(LOG_PROG, &session->context->errout,
1768
0
                 "TSIPv1 xa2-00: num %u type %u (gnss %u sigid %u) PRN %u "
1769
0
                 "az %f el %f snr %f sflags x%0x4 tow %u\n",
1770
0
                 u1, u2, gnssid, sigid, u3, d1, d2, d3, u4, tow);
1771
0
        GPSD_LOG(LOG_IO, &session->context->errout,
1772
0
                 "TSIPv1: svtype:%s flags:%s\n",
1773
0
                 val2str(u2, vsv_type1),
1774
0
                 flags2str(u4, vsflags1, buf2, sizeof(buf2)));
1775
0
        break;
1776
1777
0
    case 0xa300:
1778
        // System Alarms, xa3-00
1779
0
        if (18 > length) {
1780
0
            bad_len = true;
1781
0
            break;
1782
0
        }
1783
0
        mask = decode_xa3_00(session, buf);
1784
0
        break;
1785
0
    case 0xa311:
1786
        /* Receiver Status, xa3-11
1787
         * RES 720
1788
         */
1789
0
        if (29 > length) {
1790
0
            bad_len = true;
1791
0
            break;
1792
0
        }
1793
        // usually the last message, except for A2-00 (sats)
1794
0
        mask = decode_xa3_11(session, buf);
1795
0
        break;
1796
0
    case 0xa321:
1797
        /* Error Report xa3-21
1798
         * expect errors for x1c-03 and x35-32 from TSIP probes
1799
         */
1800
0
        if (5 > length) {
1801
0
            bad_len = true;
1802
0
            break;
1803
0
        }
1804
0
        u1 = getub(buf, 4);            // reference packet id
1805
0
        u2 = getub(buf, 5);            // reference sub packet id
1806
0
        u3 = getub(buf, 6);            // error code
1807
0
        GPSD_LOG(LOG_WARN, &session->context->errout,
1808
0
                 "TSIPv1 xa3-21: id x%02x-%02x error: %u\n",
1809
0
                 u1, u2, u3);
1810
0
        GPSD_LOG(LOG_IO, &session->context->errout,
1811
0
                 "TSIPv1: ec:%s\n",
1812
0
                 val2str(u3, verr_codes1));
1813
0
        break;
1814
0
    case 0xd000:
1815
        // Debug Output type packet, xd0-00
1816
0
        if (3 > length) {
1817
0
            bad_len = true;
1818
0
            break;
1819
0
        }
1820
0
        u1 = getub(buf, 6);               // debug output type
1821
0
        GPSD_LOG(LOG_WARN, &session->context->errout,
1822
0
                 "TSIPv1 xd0-00: debug %u\n", u1);
1823
0
        break;
1824
0
    case 0xd001:
1825
        // Trimble Debug config packet, xd0-01
1826
0
        if (4 > length) {
1827
0
            bad_len = true;
1828
0
            break;
1829
0
        }
1830
0
        u1 = getub(buf, 6);               // debug type
1831
0
        u2 = getub(buf, 7);               // debug level
1832
0
        GPSD_LOG(LOG_WARN, &session->context->errout,
1833
0
                 "TSIPv1 xd0-01: debug type %u level %u\n", u1, u2);
1834
0
        break;
1835
0
    case 0xd040:
1836
        // Trimble Raw GNSS Debug Output packet. xd0-40
1837
        // length can be zero, contents undefined
1838
0
        GPSD_LOG(LOG_WARN, &session->context->errout,
1839
0
                 "TSIPv1 xd0-40: raw GNSS data\n");
1840
0
        break;
1841
0
    case 0xd041:
1842
        // Trimble Raw GNSS Debug Output packet. xd0-41
1843
        // length can be zero, contents undefined
1844
0
        GPSD_LOG(LOG_WARN, &session->context->errout,
1845
0
                 "TSIPv1 xd0-41: raw GNSS data\n");
1846
0
        break;
1847
1848
    // undecoded:
1849
0
    case 0x9200:
1850
        // Receiver Reset, send only, x92-00
1851
0
        FALLTHROUGH
1852
0
    case 0xa400:
1853
        // AGNSS, send only, xa4-00
1854
0
        FALLTHROUGH
1855
0
    default:
1856
        // Huh?
1857
0
        GPSD_LOG(LOG_WARN, &session->context->errout,
1858
0
                 "TSIPv1 x%02x-%02x: unknown packet id/su-id\n",
1859
0
                 id, sub_id);
1860
0
        break;
1861
0
    }
1862
0
    if (bad_len) {
1863
0
        GPSD_LOG(LOG_WARN, &session->context->errout,
1864
0
                 "TSIPv1 0x%02x-%02x: runt, got length %u\n",
1865
0
                 id, sub_id, length);
1866
0
        mask = 0;
1867
0
    }
1868
    // get next item off queue
1869
0
    tsipv1_query(session);
1870
1871
0
    return mask;
1872
0
}
1873
1874
// decode packet x6d
1875
static gps_mask_t decode_x6d(struct gps_device_t *session, const char *buf,
1876
                           int len)
1877
0
{
1878
0
    gps_mask_t mask = 0;
1879
0
    int i, count;
1880
0
    unsigned fix_dim;
1881
0
    char buf2[BUFSIZ];
1882
1883
0
    fix_dim = getub(buf, 0);     // nsvs/dimension
1884
0
    count = (int)((fix_dim >> 4) & 0x0f);
1885
0
    if ((17 + count) != len) {
1886
0
        GPSD_LOG(LOG_ERROR, &session->context->errout,
1887
0
                 "TSIP: x6d: bad length %d s/b %d\n", len, 17 + count);
1888
0
        return 0;
1889
0
    }
1890
1891
    /*
1892
     * This looks right, but it sets a spurious mode value when
1893
     * the satellite constellation looks good to the chip but no
1894
     * actual fix has yet been acquired.  We should set the mode
1895
     * field (which controls gpsd's fix reporting) only from sentences
1896
     * that convey actual fix information, like 0x8f-20, but some
1897
     * TSIP do not support 0x8f-20, and 0x6c may be all we got.
1898
     */
1899
0
    if (0 != isfinite(session->gpsdata.fix.longitude)) {
1900
        // have a fix?
1901
0
        switch (fix_dim & 7) {   // dimension
1902
0
        case 1:       // clock fix (surveyed in)
1903
0
            FALLTHROUGH
1904
0
        case 5:       // Overdetermined clock fix
1905
0
            session->newdata.status = STATUS_TIME;
1906
0
            session->newdata.mode = MODE_3D;
1907
0
            break;
1908
0
        case 3:
1909
            // Copernicus ii can output this for OD mode.
1910
0
            session->newdata.mode = MODE_2D;
1911
0
            break;
1912
0
        case 4:
1913
            // SMTx can output this for OD mode.
1914
0
            session->newdata.mode = MODE_3D;
1915
0
            break;
1916
0
        case 6:
1917
            // Accutime
1918
0
            session->newdata.status = STATUS_DGPS;
1919
0
            session->newdata.mode = MODE_3D;
1920
0
            break;
1921
0
        case 2:
1922
0
            FALLTHROUGH
1923
0
        case 7:
1924
0
            FALLTHROUGH
1925
0
        default:
1926
0
            session->newdata.mode = MODE_NO_FIX;
1927
0
            break;
1928
0
        }
1929
0
        if (0 == count) {
1930
            // reports a fix even ith no sats!
1931
0
            session->newdata.status = STATUS_DR;
1932
0
        }
1933
0
    } else {
1934
0
        session->newdata.mode = MODE_NO_FIX;
1935
0
    }
1936
0
    if (STATUS_UNK < session->newdata.status) {
1937
0
        mask |= STATUS_SET;
1938
0
    }
1939
0
    mask |= MODE_SET;
1940
1941
0
    session->gpsdata.satellites_used = count;
1942
0
    session->gpsdata.dop.pdop = getbef32(buf, 1);
1943
0
    session->gpsdata.dop.hdop = getbef32(buf, 5);
1944
0
    session->gpsdata.dop.vdop = getbef32(buf, 9);
1945
0
    session->gpsdata.dop.tdop = getbef32(buf, 13);
1946
0
    mask |= DOP_SET;
1947
1948
0
    memset(session->driver.tsip.sats_used, 0,
1949
0
           sizeof(session->driver.tsip.sats_used));
1950
0
    buf2[0] = '\0';
1951
0
    for (i = 0; i < count; i++) {
1952
        // negative PRN means sat unhealthy why use an unhealthy sat??
1953
1954
0
        session->driver.tsip.sats_used[i] = getsb(buf, 17 + i);
1955
0
        if (LOG_PROG <= session->context->errout.debug ) {
1956
0
            str_appendf(buf2, sizeof(buf2),
1957
0
                           " %u", session->driver.tsip.sats_used[i]);
1958
0
        }
1959
0
    }
1960
0
    GPSD_LOG(LOG_PROG, &session->context->errout,
1961
0
             "TSIP x6d: AIVSS: fix_dim=x%x status=%d mode=%d used=%d "
1962
0
             "pdop=%.1f hdop=%.1f vdop=%.1f tdop=%.1f used >%s<\n",
1963
0
             fix_dim,
1964
0
             session->newdata.status,
1965
0
             session->newdata.mode,
1966
0
             session->gpsdata.satellites_used,
1967
0
             session->gpsdata.dop.pdop,
1968
0
             session->gpsdata.dop.hdop,
1969
0
             session->gpsdata.dop.vdop,
1970
0
             session->gpsdata.dop.tdop, buf2);
1971
0
    GPSD_LOG(LOG_IO, &session->context->errout,
1972
0
             "TSIP: fix::%s\n",
1973
0
             flags2str(fix_dim, vfix, buf2, sizeof(buf2)));
1974
0
    mask |= USED_IS;
1975
1976
0
    return mask;
1977
0
}
1978
1979
/* decode Superpacket x8f-ab
1980
 * Oddly, no flag to say if the time is valid...
1981
 */
1982
static gps_mask_t decode_x8f_ab(struct gps_device_t *session, const char *buf)
1983
0
{
1984
0
    gps_mask_t mask = 0;
1985
0
    uint32_t tow;                 // time of week in milli seconds
1986
0
    timespec_t ts_tow;
1987
0
    unsigned short week;
1988
0
    char ts_buf[TIMESPEC_LEN];
1989
0
    unsigned time_flag;
1990
0
    char buf2[BUFSIZ];
1991
1992
    // we assume the receiver not in some crazy mode, and is GPS time
1993
0
    tow = getbeu32(buf, 1);             // gpstime in seconds
1994
0
    ts_tow.tv_sec = tow;
1995
0
    ts_tow.tv_nsec = 0;
1996
0
    week = getbeu16(buf, 5);            // week
1997
    // leap seconds
1998
0
    session->context->leap_seconds = (int)getbes16(buf, 7);
1999
0
    time_flag = buf[9];                // Time Flag
2000
    /* ignore the broken down time, use the GNSS time.
2001
     * Hope it is not BeiDou time */
2002
2003
0
    if (1 == (time_flag & 1)) {
2004
        // time is UTC, have leap seconds.
2005
0
        session->context->valid |= LEAP_SECOND_VALID;
2006
0
    } else {
2007
        // time is GPS
2008
0
        if (0 == (time_flag & 8)) {
2009
            // have leap seconds.
2010
0
            session->context->valid |= LEAP_SECOND_VALID;
2011
0
        }
2012
0
    }
2013
0
    if (0 == (time_flag & 0x14)) {
2014
        // time it good, not in test mode
2015
0
        session->newdata.time = gpsd_gpstime_resolv(session, week,
2016
0
                                                    ts_tow);
2017
0
        mask |= TIME_SET | NTPTIME_IS;
2018
0
    } else {
2019
        // time is bad
2020
0
    }
2021
2022
0
    if (!TS_EQ(&ts_tow, &session->driver.tsip.last_tow)) {
2023
0
        mask |= CLEAR_IS;
2024
0
        session->driver.tsip.last_tow = ts_tow;
2025
0
    }
2026
2027
    /* since we compute time from weeks and tow, we ignore the
2028
     * supplied H:M:S M/D/Y */
2029
0
    GPSD_LOG(LOG_PROG, &session->context->errout,
2030
0
             "TSIP x8f-ab: SP-TTS: tow %u wk %u ls %d flag x%x "
2031
0
             "time %s mask %s\n",
2032
0
             tow, week, session->context->leap_seconds, time_flag,
2033
0
             timespec_str(&session->newdata.time, ts_buf,
2034
0
                          sizeof(ts_buf)),
2035
0
             gps_maskdump(mask));
2036
0
    GPSD_LOG(LOG_IO, &session->context->errout,
2037
0
             "TSIP: tf::%s\n",
2038
0
             flags2str(time_flag, vtiming, buf2, sizeof(buf2)));
2039
2040
0
    return mask;
2041
0
}
2042
2043
// decode Superpacket x8f-ac
2044
static gps_mask_t decode_x8f_ac(struct gps_device_t *session, const char *buf)
2045
0
{
2046
0
    gps_mask_t mask = 0;
2047
0
    unsigned rec_mode;
2048
0
    unsigned disc_mode;
2049
0
    unsigned survey_prog;
2050
0
    unsigned crit_alarm;
2051
0
    unsigned minor_alarm;
2052
0
    unsigned decode_stat;
2053
0
    double fqErr;             // PPS Offset. positive is slow.
2054
0
    char buf2[BUFSIZ];
2055
0
    char buf3[BUFSIZ];
2056
2057
    // byte 0 is Subpacket ID
2058
0
    rec_mode = getub(buf, 1);         // Receiver Mode
2059
    // Disciplining Mode, reserved on Resolution SMTx
2060
0
    disc_mode = getub(buf, 2);
2061
    // Self-Survey Progress
2062
0
    survey_prog = getub(buf, 3);
2063
    // ignore 4-7, Holdover Duration, reserved on Resolution SMTx
2064
    // ignore 8-9, Critical Alarms, reserved on Resolution SMTx
2065
0
    crit_alarm = getbeu16(buf, 8);
2066
    // Minor Alarms
2067
0
    minor_alarm = getbeu16(buf, 10);
2068
0
    switch (minor_alarm & 6) {
2069
0
    case 2:
2070
0
        session->newdata.ant_stat = ANT_OPEN;
2071
0
        break;
2072
0
    case 4:
2073
0
        session->newdata.ant_stat = ANT_SHORT;
2074
0
        break;
2075
0
    default:
2076
0
        session->newdata.ant_stat = ANT_OK;
2077
0
        break;
2078
0
    }
2079
2080
0
    decode_stat = getub(buf, 12);        // GNSS Decoding Status
2081
    // ignore 13, Disciplining Activity
2082
    // ignore 14, PPS indication
2083
    // ignore 15, PPS reference
2084
    /* PPS Offset in ns
2085
     * save as (long)pico seconds
2086
     * can't really use it as it is not referenced to any PPS */
2087
0
    fqErr = getbef32(buf, 16);
2088
0
    session->gpsdata.qErr = (long)(fqErr * 1000);
2089
    // ignore 20-23, Clock Offset
2090
    // ignore 24-27, DAC Value
2091
    // ignore 28-31, DAC Voltage
2092
    // 32-35, Temperature degrees C
2093
0
    session->newdata.temp = getbef32(buf, 32);
2094
0
    session->newdata.latitude = getbed64(buf, 36) * RAD_2_DEG;
2095
0
    session->newdata.longitude = getbed64(buf, 44) * RAD_2_DEG;
2096
    // SMT 360 doc says this is always altHAE in meters
2097
0
    session->newdata.altHAE = getbed64(buf, 52);
2098
    // ignore 60-63, always zero
2099
    // ignore 64-67, reserved
2100
2101
    // We don;t know enough to set status, probably TIME_TIME
2102
2103
    // Decode Fix modes
2104
0
    switch (rec_mode & 7) {
2105
0
    case 0:     // Auto
2106
        /*
2107
        * According to the Thunderbolt Manual, the
2108
        * first byte of the supplemental timing packet
2109
        * simply indicates the configuration of the
2110
        * device, not the actual lock, so we need to
2111
        * look at the decode status.
2112
        */
2113
0
        switch (decode_stat) {
2114
0
        case 0:   // "Doing Fixes"
2115
0
            session->newdata.mode = MODE_3D;
2116
0
            break;
2117
0
        case 0x0B: // "Only 3 usable sats"
2118
0
            session->newdata.mode = MODE_2D;
2119
0
            break;
2120
0
        case 0x1:   // "Don't have GPS time"
2121
0
            FALLTHROUGH
2122
0
        case 0x3:   // "PDOP is too high"
2123
0
            FALLTHROUGH
2124
0
        case 0x8:   // "No usable sats"
2125
0
            FALLTHROUGH
2126
0
        case 0x9:   // "Only 1 usable sat"
2127
0
            FALLTHROUGH
2128
0
        case 0x0A:  // "Only 2 usable sats
2129
0
            FALLTHROUGH
2130
0
        case 0x0C:  // "The chosen sat is unusable"
2131
0
            FALLTHROUGH
2132
0
        case 0x10:  // TRAIM rejected the fix
2133
0
            FALLTHROUGH
2134
0
        default:
2135
0
            session->newdata.mode = MODE_NO_FIX;
2136
0
            break;
2137
0
        }
2138
0
        break;
2139
0
    case 6:             // Clock Hold 2D
2140
        /* Not present:
2141
         *   SMT 360
2142
         *   Acutime 360
2143
         */
2144
0
        FALLTHROUGH
2145
0
    case 3:             // forced 2D Position Fix
2146
        // Does this mean STATUS_TIME?
2147
0
        session->newdata.mode = MODE_2D;
2148
0
        break;
2149
0
    case 1:             // Single Satellite Time
2150
        /* Present in:
2151
         *   Acutime 360
2152
         */
2153
0
        FALLTHROUGH
2154
0
    case 7:             // overdetermined clock
2155
        /* Present in:
2156
         *   Acutiome 360
2157
         *   Resolution SMTx
2158
         */
2159
        /*
2160
        * According to the Thunderbolt Manual, the
2161
        * first byte of the supplemental timing packet
2162
        * simply indicates the configuration of the
2163
        * device, not the actual lock, so we need to
2164
        * look at the decode status.
2165
        */
2166
0
        session->newdata.status = STATUS_TIME;
2167
0
        switch (decode_stat) {
2168
0
        case 0:   // "Doing Fixes"
2169
0
            session->newdata.mode = MODE_3D;
2170
0
            break;
2171
0
        case 0x9:   // "Only 1 usable sat"
2172
0
            FALLTHROUGH
2173
0
        case 0x0A:  // "Only 2 usable sats
2174
0
            FALLTHROUGH
2175
0
        case 0x0B: // "Only 3 usable sats"
2176
0
            session->newdata.mode = MODE_2D;
2177
0
            break;
2178
0
        case 0x1:   // "Don't have GPS time"
2179
0
            FALLTHROUGH
2180
0
        case 0x3:   // "PDOP is too high"
2181
0
            FALLTHROUGH
2182
0
        case 0x8:   // "No usable sats"
2183
0
            FALLTHROUGH
2184
0
        case 0x0C:  // "The chosen sat is unusable"
2185
0
            FALLTHROUGH
2186
0
        case 0x10:  // TRAIM rejected the fix
2187
0
            FALLTHROUGH
2188
0
        default:
2189
0
            session->newdata.mode = MODE_NO_FIX;
2190
0
            break;
2191
0
        }
2192
0
        break;
2193
0
    case 4:             // forced 3D position Fix
2194
0
        session->newdata.mode = MODE_3D;
2195
0
        break;
2196
0
    default:
2197
0
        session->newdata.mode = MODE_NO_FIX;
2198
0
        break;
2199
0
    }
2200
0
    if (0 != (0x208 & minor_alarm) &&
2201
0
        7 == (rec_mode & 7)) {
2202
        // OD, No sats or position questionable, must be Dead reckoning
2203
0
        session->newdata.mode = MODE_3D;
2204
0
        session->newdata.status = STATUS_DR;
2205
0
    }
2206
0
    if (STATUS_UNK != session->newdata.status) {
2207
0
        mask |= STATUS_SET;
2208
0
    }
2209
2210
0
    mask |= LATLON_SET | ALTITUDE_SET | MODE_SET;
2211
0
    GPSD_LOG(LOG_PROG, &session->context->errout,
2212
0
             "TSIP x8f-ac: SP-TPS: lat=%.2f lon=%.2f altHAE=%.2f "
2213
0
             "mode %d status %d  temp %.1f fqErr %.4f rm x%x dm %u "
2214
0
             "sp %u ca %x ma x%x gds x%x\n",
2215
0
             session->newdata.latitude,
2216
0
             session->newdata.longitude,
2217
0
             session->newdata.altHAE,
2218
0
             session->newdata.mode,
2219
0
             session->newdata.status,
2220
0
             session->newdata.temp, fqErr, rec_mode,
2221
0
             disc_mode, survey_prog, crit_alarm,
2222
0
             minor_alarm, decode_stat);
2223
0
    GPSD_LOG(LOG_IO, &session->context->errout,
2224
0
             "TSIP: mode:%s rm:%s gds:%s ca:%s ma:%s\n",
2225
0
             val2str(session->newdata.mode, vmode_str),
2226
0
             val2str(rec_mode, vrec_mode),
2227
0
             val2str(decode_stat, vgnss_decode_status),
2228
0
             flags2str(crit_alarm, vcrit_alarms, buf2,
2229
0
                       sizeof(buf2)),
2230
0
             flags2str(minor_alarm, vminor_alarms, buf3,
2231
0
                       sizeof(buf3)));
2232
0
    return mask;
2233
0
}
2234
2235
/* This is the meat of parsing all the TSIP packets, except v1
2236
 *
2237
 * Return: mask
2238
 */
2239
static gps_mask_t tsip_parse_input(struct gps_device_t *session)
2240
0
{
2241
0
    int i, j, len, count;
2242
0
    gps_mask_t mask = 0;
2243
0
    unsigned int id;
2244
0
    unsigned short week;
2245
0
    uint8_t u1, u2, u3, u4, u5, u6, u7, u8, u9, u10;
2246
0
    int16_t s1, s2, s3, s4;
2247
0
    int32_t sl1, sl2, sl3;
2248
0
    uint32_t ul1, ul2;
2249
0
    float f1, f2, f3, f4;
2250
0
    double d1, d2, d3, d4, d5;
2251
0
    time_t now;
2252
0
    char buf[BUFSIZ];
2253
0
    char buf2[BUFSIZ];
2254
0
    char buf3[BUFSIZ];
2255
0
    uint32_t tow;             // time of week in milli seconds
2256
0
    double ftow;              // time of week in seconds
2257
0
    timespec_t ts_tow;
2258
0
    char ts_buf[TIMESPEC_LEN];
2259
0
    int bad_len = 0;
2260
2261
0
    if (TSIP_PACKET != session->lexer.type) {
2262
        // this should not happen
2263
0
        GPSD_LOG(LOG_INF, &session->context->errout,
2264
0
                 "TSIP: tsip_analyze packet type %d\n",
2265
0
                 session->lexer.type);
2266
0
        return 0;
2267
0
    }
2268
2269
0
    if (4 > session->lexer.outbuflen ||
2270
0
        0x10 != session->lexer.outbuffer[0]) {
2271
        // packet too short, or does not start with DLE
2272
0
        GPSD_LOG(LOG_INF, &session->context->errout,
2273
0
                 "TSIP: tsip_analyze packet bad packet\n");
2274
0
        return 0;
2275
0
    }
2276
2277
    /* get receive time, first
2278
     * using system time breaks regressions!
2279
     * so use latest from receiver */
2280
0
    if (0 != session->lastfix.time.tv_sec) {
2281
0
        now = session->lastfix.time.tv_sec;
2282
0
    } else if (0 != session->oldfix.time.tv_sec) {
2283
0
        now = session->oldfix.time.tv_sec;
2284
0
    } else {
2285
0
        now = 0;
2286
0
    }
2287
2288
    // put data part of message in buf
2289
2290
0
    memset(buf, 0, sizeof(buf));
2291
0
    len = 0;
2292
0
    for (i = 2; i < (int)session->lexer.outbuflen; i++) {
2293
0
        if (0x10 == session->lexer.outbuffer[i] &&
2294
0
            0x03 == session->lexer.outbuffer[++i]) {
2295
                // DLE, STX.  end of packet, we know the length
2296
0
                break;
2297
0
        }
2298
0
        buf[len++] = session->lexer.outbuffer[i];
2299
0
    }
2300
2301
0
    id = (unsigned)session->lexer.outbuffer[1];
2302
#ifdef __UNUSED__      // debug code
2303
    GPSD_LOG(LOG_SHOUT, &session->context->errout,
2304
             "TSIP x%02x: length %d: %s\n",
2305
             id, len, gps_hexdump(buf2, sizeof(buf2),
2306
             (char *)session->lexer.outbuffer, session->lexer.outbuflen));
2307
#endif  // __UNUSED__
2308
0
    GPSD_LOG(LOG_DATA, &session->context->errout,
2309
0
             "TSIP x%02x: length %d: %s\n",
2310
0
             id, len, gps_hexdump(buf2, sizeof(buf2),
2311
0
                                  (unsigned char *)buf, len));
2312
2313
    // session->cycle_end_reliable = true;
2314
0
    switch (id) {
2315
0
    case 0x13:
2316
        /* Packet Received
2317
         * Present in:
2318
         *   pre-2000 models
2319
         *   ICM SMT 360 (2018)
2320
         *   RES SMT 360 (2018)
2321
         *   Resolution SMTx
2322
         * Not present in:
2323
         *   Copernicus II
2324
         */
2325
0
        if (1 > len) {
2326
0
            bad_len = 1;
2327
0
            break;
2328
0
        }
2329
0
        u1 = getub(buf, 0);         // Packet ID of non-parsable packet
2330
0
        if (2 <= len) {
2331
0
            u2 = getub(buf, 1);     // Data byte 0 of non-parsable packet
2332
0
        } else {
2333
0
            u2 = 0;
2334
0
        }
2335
0
        GPSD_LOG(LOG_WARN, &session->context->errout,
2336
0
                 "TSIP x13: Report Packet: request x%02x %02x "
2337
0
                 "cannot be parsed\n",
2338
0
                 u1, u2);
2339
        // ignore the rest of the bad data
2340
0
        if (0x8e == (int)u1 &&
2341
0
            0x23 == (int)u2) {
2342
            // no Compact Super Packet 0x8e-23
2343
0
            GPSD_LOG(LOG_WARN, &session->context->errout,
2344
0
                     "TSIP x8e-23: not available, use LFwEI (0x8f-20)\n");
2345
2346
            /* Request LFwEI Super Packet instead
2347
             * SMT 360 does not support 0x8e-20 either */
2348
0
            (void)tsip_write1(session, "\x8e\x20\x01", 3);
2349
0
        }
2350
0
        break;
2351
2352
0
    case 0x1c:        // Hardware/Software Version Information
2353
        /* Present in:
2354
         *   Acutime Gold
2355
         *   Lassen iQ (2005) fw 1.16+
2356
         *   Copernicus (2006)
2357
         *   Copernicus II (2009)
2358
         *   Thunderbolt E (2012)
2359
         *   RES SMT 360 (2018)
2360
         *   ICM SMT 360 (2018)
2361
         *   RES360 17x22 (2018)
2362
         *   Acutime 360
2363
         * Not Present in:
2364
         *   pre-2000 models
2365
         *   ACE II (1999)
2366
         *   ACE III (2000)
2367
         *   Lassen SQ (2002)
2368
         *   Lassen iQ (2005) pre fw 1.16
2369
         */
2370
0
        u1 = getub(buf, 0);
2371
        // decode by sub-code
2372
0
        switch (u1) {
2373
0
        case 0x81:
2374
                /* Firmware component version information (0x1c-81)
2375
                 * polled by 0x1c-01
2376
                 * Present in:
2377
                 *   Copernicus II (2009)
2378
                 */
2379
                // byte 1, reserved
2380
0
                u2 = getub(buf, 2);       // Major version
2381
0
                u3 = getub(buf, 3);       // Minor version
2382
0
                u4 = getub(buf, 4);       // Build number
2383
0
                u5 = getub(buf, 5);       // Build Month
2384
0
                u6 = getub(buf, 6);       // Build Day
2385
0
                ul1 = getbeu16(buf, 7);   // Build Year
2386
0
                u7 = getub(buf, 9);       // Length of product name
2387
                // check for valid module name length
2388
0
                if (40 < u7) {
2389
0
                    u7 = 40;
2390
0
                }
2391
                // check for valid module name length, again
2392
0
                if ((len - 10) < u7) {
2393
0
                    u7 = len - 10;
2394
0
                }
2395
                // Product name in ASCII
2396
0
                memcpy(buf2, &buf[10], u7);
2397
0
                buf2[u7] = '\0';
2398
2399
0
                (void)snprintf(session->subtype, sizeof(session->subtype),
2400
0
                               "fw %u.%u %u %02u/%02u/%04u %.40s",
2401
0
                               u2, u3, u4, u6, u5, ul1, buf2);
2402
0
                GPSD_LOG(LOG_PROG, &session->context->errout,
2403
0
                         "TSIP x1c-81: Firmware version: %s\n",
2404
0
                         session->subtype);
2405
2406
0
                mask |= DEVICEID_SET;
2407
0
                if ('\0' == session->subtype1[0]) {
2408
                    // request actual subtype1 from 0x1c-83
2409
0
                    (void)tsip_write1(session, "\x1c\x03", 2);
2410
0
                }
2411
0
                break;
2412
2413
0
        case 0x83:
2414
                /* Hardware component version information (0x1c-83)
2415
                 * polled by 0x1c-03
2416
                 * Present in:
2417
                 *   Resolution SMTx
2418
                 * Not Present in:
2419
                 *   LassenSQ (2002)
2420
                 *   Copernicus II (2009)
2421
                 */
2422
0
                ul1 = getbeu32(buf, 1);  // Serial number
2423
0
                u2 = getub(buf, 5);      // Build day
2424
0
                u3 = getub(buf, 6);      // Build month
2425
0
                ul2 = getbeu16(buf, 7);  // Build year
2426
0
                u4 = getub(buf, 9);      // Build hour
2427
                // Hardware Code
2428
0
                session->driver.tsip.hardware_code = getbeu16(buf, 10);
2429
0
                u5 = getub(buf, 12);     // Length of Hardware ID
2430
                // check for valid module name length
2431
                // copernicus ii is 27 long
2432
0
                if (40 < u5) {
2433
0
                    u5 = 40;
2434
0
                }
2435
                // check for valid module name length, again
2436
0
                if ((len - 13) < u5) {
2437
0
                    u5 = len - 13;
2438
0
                }
2439
0
                memcpy(buf2, &buf[13], u5);
2440
0
                buf2[u5] = '\0';
2441
2442
0
                (void)snprintf(session->gpsdata.dev.sernum,
2443
0
                               sizeof(session->gpsdata.dev.sernum),
2444
0
                               "%x", ul1);
2445
0
                (void)snprintf(session->subtype1, sizeof(session->subtype1),
2446
0
                               "hw %02u/%02u/%04u %02u %04u %.40s",
2447
0
                               u2, u3, ul2, u4,
2448
0
                               session->driver.tsip.hardware_code,
2449
0
                               buf2);
2450
0
                GPSD_LOG(LOG_PROG, &session->context->errout,
2451
0
                         "TSIP x1c-83: Hardware vers %s Sernum %s\n",
2452
0
                         session->subtype1,
2453
0
                         session->gpsdata.dev.sernum);
2454
2455
0
                mask |= DEVICEID_SET;
2456
0
                session->driver.tsip.subtype =
2457
0
                    session->driver.tsip.hardware_code;
2458
2459
                // Detecting device by Hardware Code
2460
0
                switch (session->driver.tsip.hardware_code) {
2461
0
                case 3001:            // Acutime Gold
2462
0
                    configuration_packets_acutime_gold(session);
2463
0
                    break;
2464
2465
                // RES look-alikes
2466
0
                case 3002:            // TSIP_REST
2467
0
                    FALLTHROUGH
2468
0
                case 3009:            // TSIP_RESSMT, Model 66266
2469
0
                    FALLTHROUGH
2470
0
                case 3017:            // Resolution SMTx,  Model 99889
2471
0
                    FALLTHROUGH
2472
0
                case 3023:            // RES SMT 360
2473
0
                    FALLTHROUGH
2474
0
                case 3026:            // ICM SMT 360
2475
0
                    FALLTHROUGH
2476
0
                case 3031:            // RES360 17x22
2477
0
                    FALLTHROUGH
2478
0
                case 3100:            // TSIP_RES720
2479
0
                    configuration_packets_res360(session);
2480
0
                    break;
2481
2482
                // Unknown
2483
0
                default:
2484
0
                    GPSD_LOG(LOG_WARN, &session->context->errout,
2485
0
                             "TSIP x1c-83: Unknown hw code %x\n",
2486
0
                             session->driver.tsip.hardware_code);
2487
0
                    FALLTHROUGH
2488
0
                case 1001:            // Lassen iQ
2489
0
                    FALLTHROUGH
2490
0
                case 1002:            // Copernicus
2491
0
                    FALLTHROUGH
2492
0
                case 1003:            // Copernicus II
2493
0
                    FALLTHROUGH
2494
0
                case 3007:            // Thunderbolt E
2495
0
                    FALLTHROUGH
2496
0
                case 3032:            // Acutime 360
2497
0
                    configuration_packets_generic(session);
2498
0
                    break;
2499
0
                }
2500
0
                break;
2501
0
        default:
2502
0
                GPSD_LOG(LOG_WARN, &session->context->errout,
2503
0
                         "TSIP x1c-%02x: Unhandled subpacket\n", u1);
2504
0
                break;
2505
0
        }
2506
        // request x8f-42 Stored Production Parameters
2507
0
        (void)tsip_write1(session, "\x8e\x42", 2);
2508
0
        break;
2509
0
    case 0x41:
2510
        /* GPS Time (0x41).  polled by 0x21
2511
         * Note: this is not the time of current fix
2512
         * Present in:
2513
         *   pre-2000 models
2514
         *   Copernicus II (2009)
2515
         *   ICM SMT 360 (2018)
2516
         *   RES SMT 360 (2018)
2517
         *   Resolution SMTx
2518
         */
2519
0
        if (10 != len) {
2520
0
            bad_len = 10;
2521
0
            break;
2522
0
        }
2523
0
        session->driver.tsip.last_41 = now;     // keep timestamp for request
2524
0
        ftow = getbef32(buf, 0);                // gpstime
2525
0
        week = getbes16(buf, 4);                // week, yes, signed!
2526
0
        f2 = getbef32(buf, 6);                  // leap seconds
2527
0
        if (0.0 <= ftow &&
2528
0
            10.0 < f2) {
2529
0
            session->context->leap_seconds = (int)round(f2);
2530
0
            session->context->valid |= LEAP_SECOND_VALID;
2531
0
            DTOTS(&ts_tow, ftow);
2532
0
            session->newdata.time =
2533
0
                gpsd_gpstime_resolv(session, week, ts_tow);
2534
0
            mask |= TIME_SET | NTPTIME_IS;
2535
            /* Note: this is not the time of current fix
2536
             * Do not use in tsip.last_tow */
2537
0
        }
2538
0
        GPSD_LOG(LOG_PROG, &session->context->errout,
2539
0
                 "TSIP x41: GPS Time: tow %.2f week %u ls %.1f %s\n",
2540
0
                 ftow, week, f2,
2541
0
                 timespec_str(&session->newdata.time, ts_buf, sizeof(ts_buf)));
2542
0
        break;
2543
0
    case 0x42:
2544
        /* Single-Precision Position Fix, XYZ ECEF
2545
         * Present in:
2546
         *   pre-2000 models
2547
         *   Copernicus II (2009)
2548
         *   ICM SMT 360 (2018)
2549
         *   RES SMT 360 (2018)
2550
         */
2551
0
        if (16 > len) {
2552
0
            bad_len = 16;
2553
0
            break;
2554
0
        }
2555
0
        session->newdata.ecef.x = getbef32(buf, 0);  // X
2556
0
        session->newdata.ecef.y = getbef32(buf, 4);  // Y
2557
0
        session->newdata.ecef.z = getbef32(buf, 8);  // Z
2558
0
        ftow = getbef32(buf, 12);                    // time-of-fix
2559
0
        DTOTS(&ts_tow, ftow);
2560
0
        session->newdata.time = gpsd_gpstime_resolv(session,
2561
0
                                                    session->context->gps_week,
2562
0
                                                    ts_tow);
2563
0
        GPSD_LOG(LOG_PROG, &session->context->errout,
2564
0
                 "TSIP x42: SP-XYZ: %f %f %f ftow %f\n",
2565
0
                 session->newdata.ecef.x,
2566
0
                 session->newdata.ecef.y,
2567
0
                 session->newdata.ecef.z,
2568
0
                 ftow);
2569
0
        mask = ECEF_SET | TIME_SET | NTPTIME_IS;
2570
0
        if (!TS_EQ(&ts_tow, &session->driver.tsip.last_tow)) {
2571
0
            mask |= CLEAR_IS;
2572
0
            session->driver.tsip.last_tow = ts_tow;
2573
0
        }
2574
0
        break;
2575
0
    case 0x43:
2576
        /* Velocity Fix, XYZ ECEF
2577
         * Present in:
2578
         *   pre-2000 models
2579
         *   ICM SMT 360 (2018)
2580
         *   RES SMT 360 (2018)
2581
         * Not Present in:
2582
         *   Copernicus II (2009)
2583
         */
2584
0
        if (20 != len) {
2585
0
            bad_len = 20;
2586
0
            break;
2587
0
        }
2588
0
        session->newdata.ecef.vx = getbef32(buf, 0);  // X velocity
2589
0
        session->newdata.ecef.vy = getbef32(buf, 4);  // Y velocity
2590
0
        session->newdata.ecef.vz = getbef32(buf, 8);  // Z velocity
2591
0
        f4 = getbef32(buf, 12);                       // bias rate
2592
0
        ftow = getbef32(buf, 16);                     // time-of-fix
2593
0
        DTOTS(&ts_tow, ftow);
2594
0
        session->newdata.time = gpsd_gpstime_resolv(session,
2595
0
                                                    session->context->gps_week,
2596
0
                                                    ts_tow);
2597
0
        GPSD_LOG(LOG_PROG, &session->context->errout,
2598
0
                 "TSIP x43: Vel XYZ: %f %f %f %f ftow %f\n",
2599
0
                 session->newdata.ecef.vx,
2600
0
                 session->newdata.ecef.vy,
2601
0
                 session->newdata.ecef.vz,
2602
0
                 f4, ftow);
2603
0
        mask = VECEF_SET | TIME_SET | NTPTIME_IS;
2604
0
        if (!TS_EQ(&ts_tow, &session->driver.tsip.last_tow)) {
2605
0
            mask |= CLEAR_IS;
2606
0
            session->driver.tsip.last_tow = ts_tow;
2607
0
        }
2608
0
        break;
2609
0
    case 0x45:
2610
        /* Software Version Information (0x45)
2611
         * Present in:
2612
         *   pre-2000 models
2613
         *   ACE II (1999)
2614
         *   ACE III (2000)
2615
         *   Lassen SQ (2002)
2616
         *   Lassen iQ (2005)
2617
         *   Copernicus II (2009)
2618
         *   ICM SMT 360
2619
         *   RES SMT 360
2620
         * Not present in:
2621
         *   RES 720
2622
         */
2623
0
        if (10 > len) {
2624
0
            bad_len = 10;
2625
0
            break;
2626
0
        }
2627
        // convert 2 digit years to 4 digit years
2628
0
        ul1 = getub(buf, 3);
2629
0
        if (80 > ul1) {
2630
0
            ul1 += 2000;
2631
0
        } else {
2632
0
            ul1 += 1900;
2633
0
        }
2634
0
        ul2 = getub(buf, 8);
2635
0
        if (80 > ul2) {
2636
0
            ul2 += 2000;
2637
0
        } else {
2638
0
            ul2 += 1900;
2639
0
        }
2640
        /* ACE calls these "NAV processor firmware" and
2641
         * "SIG processor firmware".
2642
         * RES SMT 360 calls these "application" and "GPS core".
2643
         */
2644
0
        (void)snprintf(session->subtype, sizeof(session->subtype),
2645
0
                       "sw %u.%u %02u/%02u/%04u hw %u.%u %02u/%02u/%04u",
2646
0
                       getub(buf, 0),
2647
0
                       getub(buf, 1),
2648
0
                       getub(buf, 4),
2649
0
                       getub(buf, 2),
2650
0
                       ul1,
2651
0
                       getub(buf, 5),
2652
0
                       getub(buf, 6),
2653
0
                       getub(buf, 9),
2654
0
                       getub(buf, 7),
2655
0
                       ul2);
2656
0
        GPSD_LOG(LOG_PROG, &session->context->errout,
2657
0
                 "TSIP x45: Software version: %s\n", session->subtype);
2658
0
        mask |= DEVICEID_SET;
2659
2660
        // request I/O Options (0x55)
2661
0
        (void)tsip_write1(session, "\x35", 1);
2662
2663
        /* request actual subtype using x1c-01, returns x1c-81
2664
         * which in turn requests 0x1c-83
2665
         * then requests x8f-42 */
2666
0
        (void)tsip_write1(session, "\x1c\x01", 2);
2667
0
        break;
2668
0
    case 0x46:
2669
        /* Health of Receiver (0x46).  Poll with 0x26
2670
         * Present in:
2671
         *   pre-2000 models
2672
         *   Copernicus II (2009)
2673
         *   ICM SMT 360 (2018)
2674
         *   RES SMT 360 (2018)
2675
         *   Resolution SMTx
2676
         *   all models?
2677
         * RES SMT 360 says use 0x8f-ab or 0x8f-ac instead
2678
         */
2679
0
        if (2 > len) {
2680
0
            bad_len = 2;
2681
0
            break;
2682
0
        }
2683
0
        session->driver.tsip.last_46 = now;
2684
        // Status code, see vgnss_decode_status
2685
0
        u1 = getub(buf, 0);
2686
0
        switch (u1) {
2687
0
        case 0:         //  "Doing Fixes"
2688
0
            session->newdata.mode = MODE_3D;
2689
0
            break;
2690
0
        case 9:          // "1 usable sat"
2691
0
            session->newdata.mode = MODE_2D;
2692
0
            break;
2693
0
        case 10:         // "2 usable sats"
2694
0
            session->newdata.mode = MODE_2D;
2695
0
            break;
2696
0
        case 11:         // "3 usable sats"
2697
0
            session->newdata.mode = MODE_2D;
2698
0
            break;
2699
0
        case 1:          // "No GPS time"
2700
0
            FALLTHROUGH
2701
0
        case 2:          // "Needs Init"
2702
0
            FALLTHROUGH
2703
0
        case 3:          // "PDOP too high"
2704
0
            FALLTHROUGH
2705
0
        case 8:          // "0 usable sats"
2706
0
            FALLTHROUGH
2707
0
        case 12:         // "chosen sat unusable"
2708
0
            FALLTHROUGH
2709
0
        case 16:         // "TRAIM rejected"
2710
0
            session->newdata.mode = MODE_NO_FIX;
2711
0
            break;
2712
0
        case 0xbb:       // "GPS Time Fix (OD mode)"
2713
0
            session->newdata.status = STATUS_TIME;
2714
0
            session->newdata.mode = MODE_3D;
2715
0
            break;
2716
0
         }
2717
2718
        /* Error codes, model dependent
2719
         * 0x01 -- no battery, always set on RES SMT 360
2720
         * 0x10 -- antenna is open
2721
         * 0x30 -- antenna is shorted
2722
         */
2723
0
        u2 = getub(buf, 1);
2724
0
        switch (u2 & 0x30) {
2725
0
        case 0x10:
2726
0
            session->newdata.ant_stat = ANT_OPEN;
2727
0
            break;
2728
0
        case 0x30:
2729
0
            session->newdata.ant_stat = ANT_SHORT;
2730
0
            break;
2731
0
        default:
2732
0
            session->newdata.ant_stat = ANT_OK;
2733
0
            break;
2734
0
        }
2735
2736
0
        if (STATUS_UNK != session->newdata.status) {
2737
0
            mask |= STATUS_SET;
2738
0
        }
2739
0
        GPSD_LOG(LOG_PROG, &session->context->errout,
2740
0
                 "TSIP x46: Receiver Health: mode %d status %d  gds:x%x "
2741
0
                 "ec:x%x\n",
2742
0
                session->newdata.status,
2743
0
                session->newdata.mode,
2744
0
                u1, u2);
2745
0
        GPSD_LOG(LOG_IO, &session->context->errout,
2746
0
                 "TSIP: gds:%s ec:%s\n",
2747
0
                 val2str(u1, vgnss_decode_status),
2748
0
                 flags2str(u2, verr_codes, buf2, sizeof(buf2)));
2749
0
        break;
2750
0
    case 0x47:
2751
        /* Signal Levels for all Satellites
2752
         * Present in:
2753
         *   pre-2000 models
2754
         *   Copernicus II (2009)
2755
         *   ICM SMT 360 (2018)
2756
         *   RES SMT 360 (2018)
2757
         */
2758
0
        if (1 > len) {
2759
0
            bad_len = 1;
2760
0
            break;
2761
0
        }
2762
0
        gpsd_zero_satellites(&session->gpsdata);
2763
        // satellite count, RES SMT 360 doc says 12 max
2764
0
        count = (int)getub(buf, 0);
2765
0
        if ((5 * count + 1) != len) {
2766
0
            bad_len = 5 * count + 1;
2767
0
            break;
2768
0
        }
2769
0
        buf2[0] = '\0';
2770
0
        for (i = 0; i < count; i++) {
2771
0
            u1 = getub(buf, 5 * i + 1);
2772
0
            if (0 > (f1 = getbef32(buf, 5 * i + 2))) {
2773
0
                f1 = 0.0;
2774
0
            }
2775
0
            for (j = 0; j < TSIP_CHANNELS; j++) {
2776
0
                if (session->gpsdata.skyview[j].PRN == (short)u1) {
2777
0
                    session->gpsdata.skyview[j].ss = f1;
2778
0
                    break;
2779
0
                }
2780
0
            }
2781
0
            str_appendf(buf2, sizeof(buf2), " %d=%.1f", (int)u1, f1);
2782
0
        }
2783
0
        GPSD_LOG(LOG_PROG, &session->context->errout,
2784
0
                 "TSIP x47: Signal Levels: (%d):%s\n", count, buf2);
2785
0
        mask |= SATELLITE_SET;
2786
0
        break;
2787
0
    case 0x48:
2788
        /* GPS System Message
2789
         * Present in:
2790
         *   pre-2000 models
2791
         * Not Present in:
2792
         *   Copernicus II (2009)
2793
         *   ICM SMT 360 (2018)
2794
         *   RES SMT 360 (2018)
2795
         */
2796
0
        buf[len] = '\0';
2797
0
        GPSD_LOG(LOG_PROG, &session->context->errout,
2798
0
                 "TSIP x48: GPS System Message: %s\n", buf);
2799
0
        break;
2800
0
    case 0x4a:
2801
        /* Single-Precision Position LLA
2802
         * Only sent when valid
2803
         * Present in:
2804
         *   pre-2000 models
2805
         *   Copernicus II (2009)
2806
         *   ICM SMT 360 (2018)
2807
         *   RES SMT 360 (2018)
2808
         */
2809
0
        if (20 != len) {
2810
0
            bad_len = 20;
2811
0
            break;
2812
0
        }
2813
0
        session->newdata.latitude = getbef32(buf, 0) * RAD_2_DEG;
2814
0
        session->newdata.longitude = getbef32(buf, 4) * RAD_2_DEG;
2815
        // depending on GPS config, could be either WGS84 or MSL
2816
0
        d1 = getbef32(buf, 8);
2817
0
        if (0 == session->driver.tsip.alt_is_msl) {
2818
0
            session->newdata.altHAE = d1;
2819
0
        } else {
2820
0
            session->newdata.altMSL = d1;
2821
0
        }
2822
2823
        //f1 = getbef32(buf, 12);       // clock bias
2824
0
        ftow = getbef32(buf, 16);       // time-of-fix
2825
0
        if (0 != (session->context->valid & GPS_TIME_VALID)) {
2826
0
            DTOTS(&ts_tow, ftow);
2827
0
            session->newdata.time =
2828
0
                gpsd_gpstime_resolv(session, session->context->gps_week,
2829
0
                                    ts_tow);
2830
0
            mask |= TIME_SET | NTPTIME_IS;
2831
0
            if (!TS_EQ(&ts_tow, &session->driver.tsip.last_tow)) {
2832
0
                mask |= CLEAR_IS;
2833
0
                session->driver.tsip.last_tow = ts_tow;
2834
0
            }
2835
0
        }
2836
        // this seems to be often first in cycle
2837
        // REPORT_IS here breaks reports in read-only mode
2838
0
        mask |= LATLON_SET | ALTITUDE_SET;
2839
0
        GPSD_LOG(LOG_PROG, &session->context->errout,
2840
0
                 "TSIP x4a: SP-LLA: time=%s lat=%.2f lon=%.2f "
2841
0
                 "alt=%.2f\n",
2842
0
                 timespec_str(&session->newdata.time, ts_buf, sizeof(ts_buf)),
2843
0
                 session->newdata.latitude,
2844
0
                 session->newdata.longitude, d1);
2845
0
        break;
2846
0
    case 0x4b:
2847
        /* Machine/Code ID and Additional Status (0x4b)
2848
         * polled by 0x25 (soft reset) or 0x26 (request health).
2849
         * Sent with 0x46 (receiver health).
2850
         * Present in:
2851
         *   pre-2000 models
2852
         *   Copernicus II (2009)
2853
         *   ICM SMT 360 (2018)
2854
         *   RES SMT 360 (2018)
2855
         *   Resolution SMTx
2856
         * Deprecated in:
2857
         *   Resolution SMTx
2858
         * Not in:
2859
         *   Thunderbolt (2003)
2860
         */
2861
0
        if (3 != len) {
2862
0
            bad_len = 3;
2863
0
            break;
2864
0
        }
2865
0
        session->driver.tsip.machine_id = getub(buf, 0);  // Machine ID
2866
        /* Status 1
2867
         * bit 1 -- No RTC at power up
2868
         * bit 3 -- almanac not complete and current */
2869
0
        u2 = getub(buf, 1);     // status 1
2870
0
        u3 = getub(buf, 2);     // Status 2/Superpacket Support
2871
0
        GPSD_LOG(LOG_PROG, &session->context->errout,
2872
0
                 "TSIP x4b: Machine ID: %02x %02x %02x\n",
2873
0
                 session->driver.tsip.machine_id,
2874
0
                 u2, u3);
2875
0
        GPSD_LOG(LOG_IO, &session->context->errout,
2876
0
                 "TSIP: stat1:%s stat2:%s\n",
2877
0
                 flags2str(u2, vstat1, buf2, sizeof(buf2)),
2878
0
                 flags2str(u3, vstat2, buf3, sizeof(buf3)));
2879
2880
0
        if ('\0' == session->subtype[0]) {
2881
0
            const char *name;
2882
            // better than nothing
2883
0
            switch (session->driver.tsip.machine_id) {
2884
0
            case 1:
2885
                // should use better name from superpacket
2886
0
                name = " SMT 360";
2887
                /* request actual subtype from 0x1c-81
2888
                 * which in turn requests 0x1c-83 */
2889
0
                (void)tsip_write1(session, "\x1c\x01", 2);
2890
0
                break;
2891
0
            case 0x32:
2892
0
                name = " Acutime 360";
2893
0
                break;
2894
0
            case 0x5a:
2895
0
                name = " Lassen iQ";
2896
                /* request actual subtype from 0x1c-81
2897
                 * which in turn requests 0x1c-83.
2898
                 * Only later firmware Lassen iQ supports this */
2899
0
                (void)tsip_write1(session, "\x1c\x01", 2);
2900
0
                break;
2901
0
            case 0x61:
2902
0
                name = " Acutime 2000";
2903
0
                break;
2904
0
            case 0x62:
2905
0
                name = " ACE UTC";
2906
0
                break;
2907
0
            case 0x96:
2908
                // Also Copernicus II
2909
0
                name = " Copernicus, Thunderbolt E";
2910
                /* so request actual subtype from 0x1c-81
2911
                 * which in turn requests 0x1c-83 */
2912
0
                (void)tsip_write1(session, "\x1c\x01", 2);
2913
0
                break;
2914
0
            case 0:
2915
                // Resolution SMTx
2916
0
                FALLTHROUGH
2917
0
            default:
2918
0
                 name = "";
2919
0
            }
2920
0
            (void)snprintf(session->subtype, sizeof(session->subtype),
2921
0
                           "Machine ID x%x(%s)",
2922
0
                           session->driver.tsip.machine_id, name);
2923
0
        }
2924
0
        if (u3 != session->driver.tsip.superpkt) {
2925
0
            session->driver.tsip.superpkt = u3;
2926
0
            GPSD_LOG(LOG_PROG, &session->context->errout,
2927
0
                     "TSIP: Switching to Super Packet mode %d\n", u3);
2928
0
            switch (u3){
2929
0
            default:
2930
0
                FALLTHROUGH
2931
0
            case 0:
2932
                // old Trimble, no superpackets
2933
0
                break;
2934
0
            case 1:
2935
                // 1 == superpacket is acutime 360, support 0x8f-20
2936
2937
                /* set I/O Options for Super Packet output
2938
                 * Position: 8F20, ECEF, DP */
2939
0
                buf[0] = 0x35;
2940
0
                buf[1] = IO1_8F20|IO1_DP|IO1_ECEF;
2941
0
                buf[2] = 0x00;          // Velocity: none (via SP)
2942
0
                buf[3] = 0x00;          // Time: GPS
2943
0
                buf[4] = IO4_DBHZ;      // Aux: dBHz
2944
0
                (void)tsip_write1(session, buf, 5);
2945
0
                break;
2946
0
            case 2:
2947
                /* 2 == SMT 360, or Resolution SMTx
2948
                 * no 0x8f-20, or x8f-23.
2949
                 * request x8f-a5 */
2950
0
                (void)tsip_write1(session, "\x8e\xa5", 2);
2951
0
                break;
2952
0
            }
2953
0
        }
2954
0
        break;
2955
0
    case 0x4c:
2956
        /* Operating Parameters Report (0x4c).  Polled by 0x2c
2957
         * Present in:
2958
         *   pre-2000 models
2959
         *   Lassen iQ, but not documented
2960
         * Not Present in:
2961
         *   Copernicus II (2009)
2962
         *   ICM SMT 360 (2018)
2963
         *   RES SMT 360 (2018)
2964
         */
2965
0
        if (17 != len) {
2966
0
            bad_len = 17;
2967
0
            break;
2968
0
        }
2969
0
        u1 = getub(buf, 0);               // Dynamics Code
2970
0
        f1 = getbef32(buf, 1);            // Elevation Mask
2971
0
        f2 = getbef32(buf, 5);            // Signal Level Mask
2972
0
        f3 = getbef32(buf, 9);            // PDOP Mask
2973
0
        f4 = getbef32(buf, 13);           // PDOP Switch
2974
0
        GPSD_LOG(LOG_PROG, &session->context->errout,
2975
0
                 "TSIP x4c: Operating Params: x%02x %f %f %f %f\n",
2976
0
                 u1, f1, f2, f3, f4);
2977
0
        break;
2978
0
    case 0x54:
2979
        /* Bias and Bias Rate Report (0x54)
2980
         * Present in:
2981
         *   pre-2000 models
2982
         *   Acutime 360
2983
         *   ICM SMT 360  (undocumented)
2984
         *   RES SMT 360  (undocumented)
2985
         * Not Present in:
2986
         *   Copernicus II (2009)
2987
         */
2988
0
         {
2989
0
            float  bias, bias_rate;
2990
0
            bias = getbef32(buf, 0);         // Bias
2991
0
            bias_rate = getbef32(buf, 4);    // Bias rate
2992
0
            ftow = getbef32(buf, 8);         // tow
2993
0
            DTOTS(&ts_tow, ftow);
2994
0
            session->newdata.time =
2995
0
                gpsd_gpstime_resolv(session, session->context->gps_week,
2996
0
                                    ts_tow);
2997
0
            GPSD_LOG(LOG_PROG, &session->context->errout,
2998
0
                     "TSIP x54: Bias and Bias Rate Report: %f %f %f\n",
2999
0
                     bias, bias_rate, ftow);
3000
0
            mask |= TIME_SET | NTPTIME_IS;
3001
0
            if (!TS_EQ(&ts_tow, &session->driver.tsip.last_tow)) {
3002
0
                mask |= CLEAR_IS;
3003
0
                session->driver.tsip.last_tow = ts_tow;
3004
0
            }
3005
0
         }
3006
0
         break;
3007
0
    case 0x55:
3008
        /* IO Options (0x55), polled by 0x35
3009
         * Present in:
3010
         *   pre-2000 models
3011
         *   ICM SMT 360 (2018)
3012
         *   RES SMT 360 (2018)
3013
         *   Resolution SMTx
3014
         *   all TSIP?
3015
         *
3016
         * Defaults:
3017
         *   Lassen iQ:       02 02 00 00
3018
         *   RES SMT 360:     12 02 00 08
3019
         *   Resolution SMTx: 12 02 00 08
3020
         */
3021
0
        if (4 != len) {
3022
0
            bad_len = 4;
3023
0
            break;
3024
0
        }
3025
0
        u1 = getub(buf, 0);     // Position
3026
        // decode HAE/MSL from Position byte
3027
0
        if (IO1_MSL == (IO1_MSL & u1)) {
3028
0
            session->driver.tsip.alt_is_msl = 1;
3029
0
        } else {
3030
0
            session->driver.tsip.alt_is_msl = 0;
3031
0
        }
3032
0
        u2 = getub(buf, 1);     // Velocity
3033
        /* Timing
3034
         * bit 0 - reserved use 0x8e-a2 ?
3035
         */
3036
0
        u3 = getub(buf, 2);
3037
        /* Aux
3038
         * bit 0 - packet 0x5a (raw data)
3039
         * bit 3 -- Output dbHz
3040
         */
3041
0
        u4 = getub(buf, 3);
3042
0
        GPSD_LOG(LOG_PROG, &session->context->errout,
3043
0
                 "TSIP x55: IO Options: %02x %02x %02x %02x\n",
3044
0
                 u1, u2, u3, u4);
3045
0
        if ((u1 & 0x20) != (uint8_t) 0) {
3046
            /* Try to get Super Packets
3047
             * Turn off 0x8f-20 LFwEI Super Packet */
3048
0
            (void)tsip_write1(session, "\x8e\x20\x00", 3);
3049
3050
            // Turn on Compact Super Packet 0x8f-23
3051
0
            (void)tsip_write1(session, "\x8e\x23\x01", 3);
3052
0
            session->driver.tsip.req_compact = now;
3053
0
        }
3054
0
        break;
3055
0
    case 0x56:
3056
        /* Velocity Fix, East-North-Up (ENU)
3057
         * Present in:
3058
         *   pre-2000 models
3059
         *   Copernicus II (2009)
3060
         *   ICM SMT 360 (2018)
3061
         *   RES SMT 360 (2018)
3062
         */
3063
0
        if (20 != len) {
3064
0
            bad_len = 20;
3065
0
            break;
3066
0
        }
3067
0
        f1 = getbef32(buf, 0);     // East velocity
3068
0
        f2 = getbef32(buf, 4);     // North velocity
3069
0
        f3 = getbef32(buf, 8);     // Up velocity
3070
0
        f4 = getbef32(buf, 12);    // clock bias rate
3071
0
        ftow = getbef32(buf, 16);  // time-of-fix
3072
0
        DTOTS(&ts_tow, ftow);
3073
0
        session->newdata.time = gpsd_gpstime_resolv(session,
3074
0
                                                    session->context->gps_week,
3075
0
                                                    ts_tow);
3076
0
        session->newdata.NED.velN = f2;
3077
0
        session->newdata.NED.velE = f1;
3078
0
        session->newdata.NED.velD = -f3;
3079
0
        mask |= VNED_SET | TIME_SET | NTPTIME_IS;
3080
0
        if (!TS_EQ(&ts_tow, &session->driver.tsip.last_tow)) {
3081
0
            mask |= CLEAR_IS;
3082
0
            session->driver.tsip.last_tow = ts_tow;
3083
0
        }
3084
0
        GPSD_LOG(LOG_PROG, &session->context->errout,
3085
0
                 "TSIP x56: Vel ENU: %f %f %f %f ftow %f\n",
3086
0
                 f1, f2, f3, f4, ftow);
3087
0
        break;
3088
0
    case 0x57:
3089
        /* Information About Last Computed Fix
3090
         * Present in:
3091
         *   pre-2000 models
3092
         *   Copernicus II (2009)
3093
         *   ICM SMT 360 (2018)
3094
         *   RES SMT 360 (2018)
3095
         */
3096
0
        if (8 != len) {
3097
0
            bad_len = 8;
3098
0
            break;
3099
0
        }
3100
0
        u1 = getub(buf, 0);                     // Source of information
3101
0
        u2 = getub(buf, 1);                     // Mfg. diagnostic
3102
0
        ftow = getbef32(buf, 2);                // gps_time
3103
0
        week = getbeu16(buf, 6);                // tsip.gps_week
3104
0
        if (0x01 == getub(buf, 0)) {
3105
            // good current fix
3106
0
            DTOTS(&ts_tow, ftow);
3107
0
            (void)gpsd_gpstime_resolv(session, week, ts_tow);
3108
0
            mask |= TIME_SET | NTPTIME_IS;
3109
0
            if (!TS_EQ(&ts_tow, &session->driver.tsip.last_tow)) {
3110
0
                mask |= CLEAR_IS;
3111
0
                session->driver.tsip.last_tow = ts_tow;
3112
0
            }
3113
0
        }
3114
0
        GPSD_LOG(LOG_PROG, &session->context->errout,
3115
0
                 "TSIP x57: Fix info: %02x %02x %u %f\n",
3116
0
                 u1, u2, week, ftow);
3117
0
        break;
3118
0
    case 0x5a:
3119
        /* Raw Measurement Data
3120
         * Present in:
3121
         *   pre-2000 models
3122
         *   Copernicus II (2009)
3123
         *   ICM SMT 360 (2018)
3124
         *   RES SMT 360 (2018)
3125
         */
3126
0
        if (25 > len) {
3127
0
            bad_len = 25;
3128
0
            break;
3129
0
        }
3130
        // Useless without the pseudorange...
3131
0
        u1 = getub(buf, 0);             // PRN 1-237
3132
0
        f1 = getbef32(buf, 1);          // sample length
3133
0
        f2 = getbef32(buf, 5);          // Signal Level, dbHz
3134
0
        f3 = getbef32(buf, 9);          // Code phase, 1/16th chip
3135
0
        f4 = getbef32(buf, 13);         // Doppler, Hz @ L1
3136
0
        d1 = getbed64(buf, 17);         // Time of Measurement
3137
0
        GPSD_LOG(LOG_PROG, &session->context->errout,
3138
0
                 "TSIP x5a: Raw Measurement Data: %d %f %f %f %f %f\n",
3139
0
                 u1, f1, f2, f3, f4, d1);
3140
0
        break;
3141
0
    case 0x5c:
3142
        /* Satellite Tracking Status (0x5c) polled by 0x3c
3143
         *
3144
         * GPS only, no WAAS reported here or used in fix
3145
         * Present in:
3146
         *   pre-2000 models
3147
         *   Copernicus, Copernicus II
3148
         *   Thunderbold E
3149
         * Not Present in:
3150
         *   ICM SMT 360 (2018)
3151
         *   RES SMT 360 (2018)
3152
         */
3153
0
        if (24 != len) {
3154
0
            bad_len = 24;
3155
0
            break;
3156
0
        }
3157
0
        u1 = getub(buf, 0);                 // PRN 1-32
3158
0
        u2 = getub(buf, 1);                 // slot:chan
3159
0
        u3 = getub(buf, 2);                 // Acquisition flag
3160
0
        u4 = getub(buf, 3);                 // Ephemeris flag
3161
0
        f1 = getbef32(buf, 4);              // Signal level
3162
        // time of skyview, not current time, or time of fix
3163
0
        ftow = getbef32(buf, 8);
3164
0
        DTOTS(&session->gpsdata.skyview_time, ftow);
3165
3166
0
        d1 = getbef32(buf, 12) * RAD_2_DEG;     // Elevation
3167
0
        d2 = getbef32(buf, 16) * RAD_2_DEG;     // Azimuth
3168
3169
0
        u5 = getub(buf, 20);                    // Old Meassurement flag
3170
        /* Channel number, bits 0-2 reserved/unused as of 1999.
3171
         * Seems to always start series at zero and increment to last one.
3172
         * No way to know how many there will be.
3173
         * Save current channel to check for last 0x5c message
3174
         */
3175
0
        i = (int)(u2 >> 3);     // channel number, starting at 0
3176
0
        if (0 == i) {
3177
            // start of new cycle, save last count
3178
0
            session->gpsdata.satellites_visible =
3179
0
                session->driver.tsip.last_chan_seen;
3180
0
        }
3181
0
        session->driver.tsip.last_chan_seen = i;
3182
3183
0
        GPSD_LOG(LOG_PROG, &session->context->errout,
3184
0
                 "TSIP x5c: Satellite Tracking Status: Ch %2d PRN %3d "
3185
0
                 "es %d Acq %d Eph %2d SNR %4.1f LMT %.04f El %4.1f Az %5.1f "
3186
0
                 "omf %u\n",
3187
0
                 i, u1, u2 & 7, u3, u4, f1, ftow, d1, d2, u5);
3188
0
        if (i < TSIP_CHANNELS) {
3189
0
            session->gpsdata.skyview[i].PRN = (short)u1;
3190
0
            session->gpsdata.skyview[i].svid = (unsigned char)u1;
3191
0
            session->gpsdata.skyview[i].gnssid = GNSSID_GPS;
3192
0
            session->gpsdata.skyview[i].ss = (double)f1;
3193
0
            session->gpsdata.skyview[i].elevation = (double)d1;
3194
0
            session->gpsdata.skyview[i].azimuth = (double)d2;
3195
0
            session->gpsdata.skyview[i].used = false;
3196
0
            session->gpsdata.skyview[i].gnssid = tsip_gnssid(0, u1,
3197
0
                &session->gpsdata.skyview[i].svid);
3198
0
            if (0.1 < f1) {
3199
                // check used list, if ss is non-zero
3200
                // FIXME: what about negative PRN?
3201
0
                for (j = 0; j < session->gpsdata.satellites_used; j++) {
3202
0
                    if (session->gpsdata.skyview[i].PRN != 0 &&
3203
0
                        session->driver.tsip.sats_used[j] != 0) {
3204
0
                        session->gpsdata.skyview[i].used = true;
3205
0
                    }
3206
0
                }
3207
0
            }
3208
            /* when polled by 0x3c, all the skyview times will be the same
3209
             * in one cluster */
3210
0
            if (0.0 < ftow) {
3211
0
                DTOTS(&ts_tow, ftow);
3212
0
                session->gpsdata.skyview_time =
3213
0
                    gpsd_gpstime_resolv(session, session->context->gps_week,
3214
0
                                        ts_tow);
3215
                /* do not save in session->driver.tsip.last_tow
3216
                 * as this is skyview time, not fix time */
3217
0
            }
3218
0
            if (++i >= session->gpsdata.satellites_visible) {
3219
                /* Last of the series?
3220
                 * This will cause extra SKY if this set has more
3221
                 * sats than the last set */
3222
0
                mask |= SATELLITE_SET;
3223
0
                session->gpsdata.satellites_visible = i;
3224
0
            }
3225
            /* If this series has fewer than last series there will
3226
             * be no SKY, unless the cycle ender pushes the SKY */
3227
0
        }
3228
0
        break;
3229
3230
0
     case 0x5d:
3231
        /* GNSS Satellite Tracking Status (multi-GNSS operation) (0x5d)
3232
         * polled by 0x3c
3233
         *
3234
         * GNSS only, no WAAS reported here or used in fix
3235
         * Present in:
3236
         *   ICM SMT 360 (2018)
3237
         *   RES SMT 360 (2018)
3238
         * Not Present in:
3239
         *   pre-2000 models
3240
         *   Copernicus, Copernicus II
3241
         *   Thunderbold E
3242
         */
3243
0
        if (26 != len) {
3244
0
            bad_len = 26;
3245
0
            break;
3246
0
        }
3247
0
        u1 = getub(buf, 0);     // PRN
3248
3249
        /* Channel number, bits 0-2 reserved/unused as of 1999.
3250
         * Seems to always start series at zero and increment to last one.
3251
         * No way to know how many there will be.
3252
         * Save current channel to check for last 0x5d message
3253
         */
3254
0
        i = getub(buf, 1);     // chan
3255
0
        if (0 == i) {
3256
            // start of new cycle, save last count
3257
0
            session->gpsdata.satellites_visible =
3258
0
                session->driver.tsip.last_chan_seen;
3259
0
        }
3260
0
        session->driver.tsip.last_chan_seen = i;
3261
3262
0
        u3 = getub(buf, 2);       // Acquisition flag
3263
0
        u4 = getub(buf, 3);       // SV used in Position or Time calculation
3264
0
        f1 = getbef32(buf, 4);    // Signal level
3265
        // This can be one second behind the TPV on RES SMT 360
3266
0
        ftow = getbef32(buf, 8);  // time of Last measurement
3267
0
        d1 = getbef32(buf, 12) * RAD_2_DEG;     // Elevation
3268
0
        d2 = getbef32(buf, 16) * RAD_2_DEG;     // Azimuth
3269
0
        u5 = getub(buf, 20);    // old measurement flag
3270
0
        u6 = getub(buf, 21);    // integer msec flag
3271
0
        u7 = getub(buf, 22);    // bad data flag
3272
0
        u8 = getub(buf, 23);    // data collection flag
3273
0
        u9 = getub(buf, 24);    // Used flags
3274
0
        u10 = getub(buf, 25);   // SV Type
3275
3276
3277
0
        GPSD_LOG(LOG_PROG, &session->context->errout,
3278
0
                "TSIP x5d: Satellite Tracking Status: Ch %2d Con %d PRN %3d "
3279
0
                "Acq %d Use %d SNR %4.1f LMT %.04f El %4.1f Az %5.1f Old %d "
3280
0
                "Int %d Bad %d Col %d TPF %d SVT %d\n",
3281
0
                i, u10, u1, u3, u4, f1, ftow, d1, d2, u5, u6, u7, u8, u9, u10);
3282
0
        if (TSIP_CHANNELS > i) {
3283
0
            session->gpsdata.skyview[i].PRN = (short)u1;
3284
0
            session->gpsdata.skyview[i].ss = (double)f1;
3285
0
            session->gpsdata.skyview[i].elevation = (double)d1;
3286
0
            session->gpsdata.skyview[i].azimuth = (double)d2;
3287
0
            session->gpsdata.skyview[i].used = (bool)u4;
3288
0
            session->gpsdata.skyview[i].gnssid = tsip_gnssid(u10, u1,
3289
0
                &session->gpsdata.skyview[i].svid);
3290
0
            if (0 == u7) {
3291
0
                session->gpsdata.skyview[i].health = SAT_HEALTH_OK;
3292
0
            } else {
3293
0
                session->gpsdata.skyview[i].health = SAT_HEALTH_BAD;
3294
0
            }
3295
3296
            /* when polled by 0x3c, all the skyview times will be the same
3297
             * in one cluster */
3298
0
            if (0.0 < ftow) {
3299
0
                DTOTS(&ts_tow, ftow);
3300
0
                session->gpsdata.skyview_time =
3301
0
                    gpsd_gpstime_resolv(session, session->context->gps_week,
3302
0
                                        ts_tow);
3303
                /* do not save in session->driver.tsip.last_tow
3304
                 * as this is skyview time, not fix time */
3305
0
            }
3306
0
            if (++i >= session->gpsdata.satellites_visible) {
3307
                /* Last of the series?
3308
                 * This will cause extra SKY if this set has more
3309
                 * sats than the last set */
3310
0
                mask |= SATELLITE_SET;
3311
0
                session->gpsdata.satellites_visible = i;
3312
0
            }
3313
            /* If this series has fewer than last series there will
3314
             * be no SKY, unless the cycle ender pushes the SKY */
3315
0
        }
3316
0
        break;
3317
0
    case 0x6c:
3318
        /* Satellite Selection List (0x6c) polled by 0x24
3319
         * Eeerily similar to 0x6d, the difference is where the sat count is.
3320
         *
3321
         * Present in:
3322
         *   ICM SMT 360 (2018)
3323
         *   RES SMT 360 (2018)
3324
         * Not present in:
3325
         *   pre-2000 models
3326
         *   Copernicus II (2009)
3327
         *   Lassen SQ (2002)
3328
         *   Lassen iQ (2005) */
3329
0
        if (18 > len) {
3330
0
            bad_len = 18;
3331
0
            break;
3332
0
        }
3333
0
        u1 = getub(buf, 0);          // fix dimension, mode
3334
0
        count = (int)getub(buf, 17);
3335
0
        if ((18 + count) != len) {
3336
0
            bad_len = 18 + count;
3337
0
            break;
3338
0
        }
3339
3340
        // why same as 6d?
3341
0
        session->driver.tsip.last_6d = now;     // keep timestamp for request
3342
        /*
3343
         * This looks right, but it sets a spurious mode value when
3344
         * the satellite constellation looks good to the chip but no
3345
         * actual fix has yet been acquired.  We should set the mode
3346
         * field (which controls gpsd's fix reporting) only from sentences
3347
         * that convey actual fix information, like 0x8f-20, but some
3348
         * TSIP do not support 0x8f-20, and 0x6c may be all we got.
3349
         */
3350
0
        switch (u1 & 7) {       // dimension
3351
0
        case 1:       // clock fix (surveyed in)
3352
0
            FALLTHROUGH
3353
0
        case 5:       // Overdetermined clock fix
3354
0
            session->newdata.status = STATUS_TIME;
3355
0
            session->newdata.mode = MODE_3D;
3356
0
            break;
3357
0
        case 3:
3358
0
            session->newdata.mode = MODE_2D;
3359
0
            break;
3360
0
        case 4:
3361
0
            session->newdata.mode = MODE_3D;
3362
0
            break;
3363
0
        case 6:
3364
            // Accutime
3365
0
            session->newdata.status = STATUS_DGPS;
3366
0
            session->newdata.mode = MODE_3D;
3367
0
            break;
3368
0
        case 0:
3369
            // Sometimes this is No Fix, sometimes Auto....
3370
0
            FALLTHROUGH
3371
0
        case 2:
3372
0
            FALLTHROUGH
3373
0
        case 7:
3374
0
            FALLTHROUGH
3375
0
        default:
3376
0
            session->newdata.mode = MODE_NO_FIX;
3377
0
            break;
3378
0
        }
3379
0
        if (8 == (u1 & 8)) {
3380
            // Surveyed in
3381
0
            session->newdata.status = STATUS_TIME;
3382
0
        }
3383
0
        if (STATUS_UNK < session->newdata.status) {
3384
0
            mask |= STATUS_SET;
3385
0
        }
3386
0
        mask |= MODE_SET;
3387
3388
0
        session->gpsdata.satellites_used = count;
3389
0
        session->gpsdata.dop.pdop = getbef32(buf, 1);
3390
0
        session->gpsdata.dop.hdop = getbef32(buf, 5);
3391
0
        session->gpsdata.dop.vdop = getbef32(buf, 9);
3392
        // RES SMT 360 and ICM SMT 360 always report tdop == 1
3393
0
        session->gpsdata.dop.tdop = getbef32(buf, 13);
3394
0
        mask |= DOP_SET;
3395
3396
0
        memset(session->driver.tsip.sats_used, 0,
3397
0
                sizeof(session->driver.tsip.sats_used));
3398
0
        buf2[0] = '\0';
3399
0
        for (i = 0; i < count; i++) {
3400
            // negative PRN means sat unhealthy why use an unhealthy sat??
3401
0
            session->driver.tsip.sats_used[i] = getsb(buf, 18 + i);
3402
0
            if (LOG_PROG <= session->context->errout.debug) {
3403
0
                str_appendf(buf2, sizeof(buf2),
3404
0
                               " %d", session->driver.tsip.sats_used[i]);
3405
0
            }
3406
0
        }
3407
0
        GPSD_LOG(LOG_PROG, &session->context->errout,
3408
0
                 "TSIP xcc: AIVSS: mode %d status %d used %d "
3409
0
                 "pdop %.1f hdop %.1f vdop %.1f tdop %.1f Used %s fixd x%x\n",
3410
0
                 session->newdata.mode,
3411
0
                 session->newdata.status,
3412
0
                 session->gpsdata.satellites_used,
3413
0
                 session->gpsdata.dop.pdop,
3414
0
                 session->gpsdata.dop.hdop,
3415
0
                 session->gpsdata.dop.vdop,
3416
0
                 session->gpsdata.dop.tdop,
3417
0
                 buf2, u1);
3418
0
        GPSD_LOG(LOG_IO, &session->context->errout,
3419
0
                 "TSIP: fixd %s\n",
3420
0
                 flags2str(u1, vfix, buf2, sizeof(buf2)));
3421
0
        mask |= USED_IS;
3422
0
        break;
3423
0
    case 0x6d:
3424
        /* All-In-View Satellite Selection (0x6d) polled by 0x24
3425
         * Sent after every fix
3426
         *
3427
         * Present in:
3428
         *   pre-2000 models
3429
         *   Copernicus II (2009)
3430
         *   Lassen SQ
3431
         *   Lassen iQ
3432
         * Deprecated in:
3433
         *   Resolution SMTx
3434
         * Not present in:
3435
         *   ICM SMT 360 (2018)
3436
         *   RES SMT 360 (2018)
3437
         */
3438
0
        if (17 > len) {
3439
0
            bad_len = 17;
3440
0
            break;
3441
0
        }
3442
0
        session->driver.tsip.last_6d = now;     // keep timestamp for request
3443
3444
0
        mask = decode_x6d(session, buf, len);
3445
0
        break;
3446
0
    case 0x82:
3447
        /* Differential Position Fix Mode (0x82) poll with 0x62-ff
3448
         * Sent after every position fix in Auto GPS/DGPS,
3449
         * so potential cycle ender
3450
         *
3451
         * Present in:
3452
         *   pre-2000 models
3453
         *   Copernicus II (2009)
3454
         *   Lassen SQ
3455
         *   Lassen iQ, deprecated use 0xbb instead
3456
         * Not Present in:
3457
         *   ICM SMT 360 (2018)
3458
         *   RES SMT 360 (2018)
3459
         */
3460
0
        if (1 != len) {
3461
0
            bad_len = 1;
3462
0
            break;
3463
0
        }
3464
        // differential position fix mode
3465
0
        u1 = getub(buf, 0);
3466
0
        if (3 == (u1 & 3)) {
3467
            // currently mode 3 (auto DGPS) and so have DGPS
3468
0
            session->newdata.status = STATUS_DGPS;
3469
0
            mask |= STATUS_SET;
3470
0
        }
3471
0
        GPSD_LOG(LOG_PROG, &session->context->errout,
3472
0
                 "TSIP x82: DPFM: mode %d status=%d\n",
3473
0
                 u1, session->newdata.status);
3474
0
        break;
3475
0
    case 0x83:
3476
        /* Double-Precision XYZ Position Fix and Bias Information
3477
         * Only sent when valid
3478
         * Present in:
3479
         *   pre-2000 models
3480
         *   LasenSQ (2002)
3481
         *   Copernicus II (2009)
3482
         *   ICM SMT 360 (2018)
3483
         *   RES SMT 360 (2018)
3484
         */
3485
0
        if (36 > len) {
3486
0
            bad_len = 36;
3487
0
            break;
3488
0
        }
3489
0
        session->newdata.ecef.x = getbed64(buf, 0);  // X
3490
0
        session->newdata.ecef.y = getbed64(buf, 8);  // Y
3491
0
        session->newdata.ecef.z = getbed64(buf, 16); // Z
3492
0
        d4 = getbed64(buf, 24);                      // clock bias
3493
0
        ftow = getbef32(buf, 32);                    // time-of-fix
3494
0
        DTOTS(&ts_tow, ftow);
3495
0
        session->newdata.time = gpsd_gpstime_resolv(session,
3496
0
                                                    session->context->gps_week,
3497
0
                                                    ts_tow);
3498
        /* No fix mode info!! That comes later in 0x6d.
3499
         * This message only sent when there is 2D or 3D fix.
3500
         * This is a problem as gpsd will send a report with no mode.
3501
         * Steal mode from last fix.
3502
         * The last fix is likely lastfix, not oldfix, as this is likely
3503
         * a new time and starts a new cycle! */
3504
0
        session->newdata.status = session->lastfix.status;
3505
0
        if (MODE_2D > session->oldfix.mode) {
3506
0
            session->newdata.mode = MODE_2D;  // At least 2D
3507
0
        } else {
3508
0
            session->newdata.mode = session->lastfix.mode;
3509
0
        }
3510
0
        mask |= STATUS_SET | MODE_SET;
3511
3512
0
        GPSD_LOG(LOG_PROG, &session->context->errout,
3513
0
                 "TSIP x83: DP-XYZ: %f %f %f %f tow %f mode %u\n",
3514
0
                 session->newdata.ecef.x,
3515
0
                 session->newdata.ecef.y,
3516
0
                 session->newdata.ecef.z,
3517
0
                 d4, ftow,
3518
0
                 session->newdata.mode);
3519
0
        mask |= ECEF_SET | TIME_SET | NTPTIME_IS;
3520
0
        if (!TS_EQ(&ts_tow, &session->driver.tsip.last_tow)) {
3521
            // New time, so new fix.
3522
0
            mask |= CLEAR_IS;
3523
0
            session->driver.tsip.last_tow = ts_tow;
3524
0
        }
3525
0
        break;
3526
0
    case 0x84:
3527
        /* Double-Precision LLA Position Fix and Bias Information
3528
         * Present in:
3529
         *   pre-2000 models
3530
         *   Copernicus II (2009)
3531
         *   LassenSQ  (2002)
3532
         *   ICM SMT 360 (2018)
3533
         *   RES SMT 360 (2018)
3534
         */
3535
0
        if (36 != len) {
3536
0
            bad_len = 36;
3537
0
            break;
3538
0
        }
3539
0
        session->newdata.latitude = getbed64(buf, 0) * RAD_2_DEG;
3540
0
        session->newdata.longitude = getbed64(buf, 8) * RAD_2_DEG;
3541
        // depending on GPS config, could be either WGS84 or MSL
3542
0
        d1 = getbed64(buf, 16);
3543
0
        if (0 == session->driver.tsip.alt_is_msl) {
3544
0
            session->newdata.altHAE = d1;
3545
0
        } else {
3546
0
            session->newdata.altMSL = d1;
3547
0
        }
3548
0
        mask |= ALTITUDE_SET;
3549
        // d1 = getbed64(buf, 24);     // clock bias
3550
0
        ftow = getbef32(buf, 32);       // time-of-fix
3551
0
        if (0 != (session->context->valid & GPS_TIME_VALID)) {
3552
            // fingers crossed receiver set to UTC, not GPS.
3553
0
            DTOTS(&ts_tow, ftow);
3554
0
            session->newdata.time =
3555
0
                gpsd_gpstime_resolv(session, session->context->gps_week,
3556
0
                                    ts_tow);
3557
0
            mask |= TIME_SET | NTPTIME_IS;
3558
0
            if (!TS_EQ(&ts_tow, &session->driver.tsip.last_tow)) {
3559
0
                mask |= CLEAR_IS;
3560
0
                session->driver.tsip.last_tow = ts_tow;
3561
0
            }
3562
0
        }
3563
0
        mask |= LATLON_SET;
3564
        /* No fix mode info!! That comes later in 0x6d.
3565
         * Message sent when there is 2D or 3D fix.
3566
         * This is a problem as gpsd will send a report with no mode.
3567
         * This message only sent on 2D or 3D fix.
3568
         * Steal mode from last fix. */
3569
0
        session->newdata.status = session->oldfix.status;
3570
0
        session->newdata.mode = session->oldfix.mode;
3571
0
        mask |= STATUS_SET | MODE_SET;
3572
3573
0
        GPSD_LOG(LOG_PROG, &session->context->errout,
3574
0
                 "TSIP x84: DP-LLA: time=%s lat=%.2f lon=%.2f alt=%.2f\n",
3575
0
                 timespec_str(&session->newdata.time, ts_buf, sizeof(ts_buf)),
3576
0
                 session->newdata.latitude,
3577
0
                 session->newdata.longitude, d1);
3578
0
        break;
3579
0
    case 0x8f:
3580
        /* Super Packet.
3581
         * Present in:
3582
         *   pre-2000 models
3583
         *   ACE II
3584
         *   ACE III
3585
         *   Copernicus II (2009)
3586
         *   ICM SMT 360
3587
         *   RES SMT 360
3588
         *   Resolution SMTx
3589
         */
3590
0
        u1 = (uint8_t) getub(buf, 0);
3591
0
        switch (u1) {           // sub-code ID
3592
0
        case 0x15:
3593
            /* Current Datum Values
3594
             * Not Present in:
3595
             *   pre-2000 models
3596
             *   Copernicus II (2009)
3597
             *   ICM SMT 360 (2018)
3598
             *   RES SMT 360 (2018)
3599
             */
3600
0
            if (43 != len) {
3601
0
                bad_len = 43;
3602
0
                break;
3603
0
            }
3604
0
            s1 = getbes16(buf, 1);              // Datum Index
3605
0
            d1 = getbed64(buf, 3);              // DX
3606
0
            d2 = getbed64(buf, 11);             // DY
3607
0
            d3 = getbed64(buf, 19);             // DZ
3608
0
            d4 = getbed64(buf, 27);             // A-axis
3609
0
            d5 = getbed64(buf, 35);             // Eccentricity Squared
3610
0
            GPSD_LOG(LOG_PROG, &session->context->errout,
3611
0
                     "TSIP x8f-15: Current Datum: %d %f %f %f %f %f\n",
3612
0
                     s1, d1, d2, d3, d4, d5);
3613
0
            break;
3614
3615
0
        case 0x20:
3616
            /* Last Fix with Extra Information (binary fixed point) 0x8f-20
3617
             * Only output when fix is available.
3618
             * CSK sez "why does my Lassen SQ output oversize packets?"
3619
             * Present in:
3620
             *   pre-2000 models
3621
             *   ACE II
3622
             *   Copernicus, Copernicus II (64-bytes)
3623
             * Not present in:
3624
             *   ICM SMT 360
3625
             *   RES SMT 360
3626
             */
3627
0
            if (56 != (len) &&
3628
0
                64 != (len)) {
3629
0
                bad_len = 56;
3630
0
                break;
3631
0
            }
3632
0
            s1 = getbes16(buf, 2);      // east velocity
3633
0
            s2 = getbes16(buf, 4);      // north velocity
3634
0
            s3 = getbes16(buf, 6);      // up velocity
3635
0
            tow = getbeu32(buf, 8);     // time in ms
3636
0
            sl1 = getbes32(buf, 12);    // latitude
3637
0
            ul2 = getbeu32(buf, 16);    // longitude
3638
            // Lassen iQ, and copernicus (ii) doc says this is always altHAE
3639
0
            sl2 = getbes32(buf, 20);    // altitude
3640
0
            u1 = getub(buf, 24);        // velocity scaling
3641
0
            u2 = getub(buf, 27);        // fix flags
3642
0
            u3 = getub(buf, 28);        // num svs
3643
0
            u4 = getub(buf, 29);        // utc offset
3644
0
            week = getbeu16(buf, 30);   // tsip.gps_week
3645
            // PRN/IODE data follows
3646
0
            GPSD_LOG(LOG_PROG, &session->context->errout,
3647
0
                     "TSIP x8f-20: LFwEI: %d %d %d tow %u %d "
3648
0
                     " %u %u %x %x %u leap %u week %d\n",
3649
0
                     s1, s2, s3, tow, sl1, ul2, sl2, u1, u2, u3, u4, week);
3650
3651
0
            if ((u1 & 0x01) != (uint8_t) 0) {     // check velocity scaling
3652
0
                d5 = 0.02;
3653
0
            } else {
3654
0
                d5 = 0.005;
3655
0
            }
3656
3657
            // 0x8000 is over-range
3658
0
            if ((int16_t)0x8000 != s2) {
3659
0
                d2 = (double)s2 * d5;   // north velocity m/s
3660
0
                session->newdata.NED.velN = d2;
3661
0
            }
3662
0
            if ((int16_t)0x8000 != s1) {
3663
0
                d1 = (double)s1 * d5;   // east velocity m/s
3664
0
                session->newdata.NED.velE = d1;
3665
0
            }
3666
0
            if ((int16_t)0x8000 != s3) {
3667
0
                d3 = (double)s3 * d5;       // up velocity m/s
3668
0
                session->newdata.NED.velD = -d3;
3669
0
            }
3670
3671
0
            session->newdata.latitude = (double)sl1 * SEMI_2_DEG;
3672
0
            session->newdata.longitude = (double)ul2 * SEMI_2_DEG;
3673
0
            if (180.0 < session->newdata.longitude) {
3674
0
                session->newdata.longitude -= 360.0;
3675
0
            }
3676
            // Lassen iQ doc says this is always altHAE in mm
3677
0
            session->newdata.altHAE = (double)sl2 * 1e-3;
3678
0
            mask |= ALTITUDE_SET;
3679
3680
0
            session->newdata.status = STATUS_UNK;
3681
0
            session->newdata.mode = MODE_NO_FIX;
3682
0
            if ((u2 & 0x01) == (uint8_t)0) {          // Fix Available
3683
0
                session->newdata.status = STATUS_GPS;
3684
0
                if ((u2 & 0x02) != (uint8_t)0) {      // DGPS Corrected
3685
0
                    session->newdata.status = STATUS_DGPS;
3686
0
                }
3687
0
                if ((u2 & 0x04) != (uint8_t)0) {      // Fix Dimension
3688
0
                    session->newdata.mode = MODE_2D;
3689
0
                } else {
3690
0
                    session->newdata.mode = MODE_3D;
3691
0
                }
3692
0
            }
3693
0
            session->gpsdata.satellites_used = (int)u3;
3694
0
            if (10 < (int)u4) {
3695
0
                session->context->leap_seconds = (int)u4;
3696
0
                session->context->valid |= LEAP_SECOND_VALID;
3697
                /* check for week rollover
3698
                 * Trimble uses 15 bit weeks, but can guess the epoch wrong
3699
                 * Can not be in gpsd_gpstime_resolv() because that
3700
                 * may see BUILD_LEAPSECONDS instead of leap_seconds
3701
                 * from receiver.
3702
                 */
3703
0
                if (17 < u4 &&
3704
0
                    1930 > week) {
3705
                    // leap second 18 added in gps week 1930
3706
0
                    week += 1024;
3707
0
                    if (1930 > week) {
3708
                        // and again?
3709
0
                        week += 1024;
3710
0
                    }
3711
0
                }
3712
0
            }
3713
0
            MSTOTS(&ts_tow, tow);
3714
0
            session->newdata.time = gpsd_gpstime_resolv(session, week,
3715
0
                                                        ts_tow);
3716
0
            mask |= TIME_SET | NTPTIME_IS | LATLON_SET |
3717
0
                    STATUS_SET | MODE_SET | VNED_SET;
3718
0
            if (!TS_EQ(&ts_tow, &session->driver.tsip.last_tow)) {
3719
0
                mask |= CLEAR_IS;
3720
0
                session->driver.tsip.last_tow = ts_tow;
3721
0
            }
3722
0
            GPSD_LOG(LOG_PROG, &session->context->errout,
3723
0
                     "TSIP x8f-20: LFwEI: time=%s lat=%.2f lon=%.2f "
3724
0
                     "altHAE=%.2f mode=%d status=%d\n",
3725
0
                     timespec_str(&session->newdata.time, ts_buf,
3726
0
                                  sizeof(ts_buf)),
3727
0
                     session->newdata.latitude, session->newdata.longitude,
3728
0
                     session->newdata.altHAE,
3729
0
                     session->newdata.mode, session->newdata.status);
3730
0
            break;
3731
0
        case 0x23:
3732
            /* Compact Super Packet (0x8f-23)
3733
             * Present in:
3734
             *   Copernicus, Copernicus II
3735
             * Not present in:
3736
             *   pre-2000 models
3737
             *   Lassen iQ
3738
             *   ICM SMT 360
3739
             *   RES SMT 360
3740
             */
3741
0
            session->driver.tsip.req_compact = 0;
3742
            // CSK sez "i don't trust this to not be oversized either."
3743
0
            if (29 > len) {
3744
0
                bad_len = 29;
3745
0
                break;
3746
0
            }
3747
0
            tow = getbeu32(buf, 1);             // time in ms
3748
0
            week = getbeu16(buf, 5);            // tsip.gps_week
3749
0
            u1 = getub(buf, 7);                 // utc offset
3750
0
            u2 = getub(buf, 8);                 // fix flags
3751
0
            sl1 = getbes32(buf, 9);             // latitude
3752
0
            ul2 = getbeu32(buf, 13);            // longitude
3753
            // Copernicus (ii) doc says this is always altHAE in mm
3754
0
            sl3 = getbes32(buf, 17);    // altitude
3755
            // set xNED here
3756
0
            s2 = getbes16(buf, 21);     // east velocity
3757
0
            s3 = getbes16(buf, 23);     // north velocity
3758
0
            s4 = getbes16(buf, 25);     // up velocity
3759
0
            GPSD_LOG(LOG_PROG, &session->context->errout,
3760
0
                     "TSIP x8f-23: CSP: %u %d %u %u %d %u %d %d %d %d\n",
3761
0
                     tow, week, u1, u2, sl1, ul2, sl3, s2, s3, s4);
3762
0
            if (10 < (int)u1) {
3763
0
                session->context->leap_seconds = (int)u1;
3764
0
                session->context->valid |= LEAP_SECOND_VALID;
3765
0
            }
3766
0
            MSTOTS(&ts_tow, tow);
3767
0
            session->newdata.time =
3768
0
                gpsd_gpstime_resolv(session, week, ts_tow);
3769
0
            session->newdata.status = STATUS_UNK;
3770
0
            session->newdata.mode = MODE_NO_FIX;
3771
0
            if ((u2 & 0x01) == (uint8_t)0) {          // Fix Available
3772
0
                session->newdata.status = STATUS_GPS;
3773
0
                if ((u2 & 0x02) != (uint8_t)0) {      // DGPS Corrected
3774
0
                    session->newdata.status = STATUS_DGPS;
3775
0
                }
3776
0
                if ((u2 & 0x04) != (uint8_t)0) {       // Fix Dimension
3777
0
                    session->newdata.mode = MODE_2D;
3778
0
                } else {
3779
0
                    session->newdata.mode = MODE_3D;
3780
0
                }
3781
0
            }
3782
0
            session->newdata.latitude = (double)sl1 * SEMI_2_DEG;
3783
0
            session->newdata.longitude = (double)ul2 * SEMI_2_DEG;
3784
0
            if (180.0 < session->newdata.longitude) {
3785
0
                session->newdata.longitude -= 360.0;
3786
0
            }
3787
            // Copernicus (ii) doc says this is always altHAE in mm
3788
0
            session->newdata.altHAE = (double)sl3 * 1e-3;
3789
0
            mask |= ALTITUDE_SET;
3790
0
            if ((u2 & 0x20) != (uint8_t)0) {     // check velocity scaling
3791
0
                d5 = 0.02;
3792
0
            } else {
3793
0
                d5 = 0.005;
3794
0
            }
3795
0
            d1 = (double)s2 * d5;       // east velocity m/s
3796
0
            d2 = (double)s3 * d5;       // north velocity m/s
3797
0
            d3 = (double)s4 * d5;       // up velocity m/s
3798
0
            session->newdata.NED.velN = d2;
3799
0
            session->newdata.NED.velE = d1;
3800
0
            session->newdata.NED.velD = -d3;
3801
3802
0
            mask |= TIME_SET | NTPTIME_IS | LATLON_SET |
3803
0
                    STATUS_SET | MODE_SET | VNED_SET;
3804
0
            if (!TS_EQ(&ts_tow, &session->driver.tsip.last_tow)) {
3805
0
                mask |= CLEAR_IS;
3806
0
                session->driver.tsip.last_tow = ts_tow;
3807
0
            }
3808
0
            GPSD_LOG(LOG_PROG, &session->context->errout,
3809
0
                     "TSIP x8f-23: SP-CSP: time %s lat %.2f lon %.2f "
3810
0
                     "altHAE %.2f mode %d status %d\n",
3811
0
                     timespec_str(&session->newdata.time, ts_buf,
3812
0
                                  sizeof(ts_buf)),
3813
0
                     session->newdata.latitude, session->newdata.longitude,
3814
0
                     session->newdata.altHAE,
3815
0
                     session->newdata.mode, session->newdata.status);
3816
0
            break;
3817
3818
0
        case 0x42:
3819
            /* Stored production parameters
3820
             * Present in:
3821
             *   ICM SMT 360 (2018)
3822
             *   RES SMT 360 (2018)
3823
             *   Resolution SMTx (2013)
3824
             * Not Present in:
3825
             *   pre-2000 models
3826
             *   Copernicus II (2009)
3827
             */
3828
0
            if (19 > len) {
3829
0
                bad_len = 19;
3830
0
                break;
3831
0
            }
3832
0
            u1 = getub(buf, 1);                 // Production Options Prefix
3833
0
            u2 = getub(buf, 2);                 // Production Number Extension
3834
0
            u3 = getbeu16(buf, 3);              // Case Sernum Prefix
3835
0
            u4 = getbeu32(buf, 5);              // Case Sernum
3836
0
            u5 = getbeu32(buf, 9);              // Production Number
3837
0
            u6 = getbeu32(buf, 13);             // Resevered
3838
0
            u7 = getbeu16(buf, 15);             // Machine ID
3839
0
            u8 = getbeu16(buf, 17);             // Reserved
3840
0
            GPSD_LOG(LOG_PROG, &session->context->errout,
3841
0
                     "TSIP x8f-42: SPP: Prod x%x-%x Sernum %x-%x "
3842
0
                     "Prod %x  Res %x ID %x Res %x\n",
3843
0
                     u1, u2, u3, u4, u5, u6, u7, u8);
3844
0
            break;
3845
0
        case 0xa5:
3846
            /* Packet Broadcast Mask (0x8f-a5) polled by 0x8e-a5
3847
             *
3848
             * Present in:
3849
             *   ICM SMT 360
3850
             *   RES SMT 360
3851
             * Not Present in:
3852
             *   pre-2000 models
3853
             *   Copernicus II (2009)
3854
             *
3855
             * Defaults:
3856
             *   RES SMT 360: 05, 00
3857
             *   Resolution SMTx: 05 00
3858
             */
3859
0
            {
3860
0
                uint16_t mask0, mask1;
3861
0
                if (5 > len) {
3862
0
                    bad_len = 5;
3863
0
                    break;
3864
0
                }
3865
0
                mask0 = getbeu16(buf, 1);    // Mask 0
3866
0
                mask1 = getbeu16(buf, 3);    // Mask 1
3867
0
                GPSD_LOG(LOG_PROG, &session->context->errout,
3868
0
                         "TSIP x8f-a5: PBM: mask0 x%04x mask1 x%04x\n",
3869
0
                         mask0, mask1);
3870
0
            }
3871
0
            break;
3872
3873
0
        case 0xa6:
3874
            /* Self-Survey Command (0x8f-a6) polled by 0x8e-a6
3875
             *
3876
             * Present in:
3877
             *   ICM SMT 360
3878
             *   RES SMT 360
3879
             * Not Present in:
3880
             *   pre-2000 models
3881
             *   Copernicus II (2009)
3882
             */
3883
0
            if (3 > len) {
3884
0
                bad_len = 3;
3885
0
                break;
3886
0
            }
3887
0
            u2 = getub(buf, 1);          // Command
3888
0
            u3 = getub(buf, 2);          // Status
3889
0
            GPSD_LOG(LOG_PROG, &session->context->errout,
3890
0
                     "TSIP x8f-a6: SSC: command x%x status x%x\n",
3891
0
                     u2, u3);
3892
0
            break;
3893
3894
0
        case 0xa7:
3895
            /* Thunderbolt Individual Satellite Solutions
3896
             * partial decode
3897
             */
3898
0
            if (10 > len) {
3899
0
                bad_len = 10;
3900
0
                break;
3901
0
            }
3902
            // we assume the receiver not in some crazy mode, and is GPS time
3903
0
            tow = getbeu32(buf, 2);             // gpstime in seconds
3904
0
            ts_tow.tv_sec = tow;
3905
0
            ts_tow.tv_nsec = 0;
3906
0
            u1 = buf[1];                     // format, 0 Float, 1 Int
3907
3908
0
            if (0 == u1) {
3909
                // floating point mode
3910
0
                d1 = getbef32(buf, 6);   // clock bias (combined)
3911
0
                d2 = getbef32(buf, 10);  // clock bias rate (combined)
3912
                // FIXME: decode the individual biases
3913
0
                GPSD_LOG(LOG_PROG, &session->context->errout,
3914
0
                         "TSIP x8f-a7: tow %llu mode %u bias %e "
3915
0
                         "bias rate %e\n",
3916
0
                         (long long unsigned)tow, u1, d1, d2);
3917
0
            } else if (1 == u1) {
3918
                // integer mode
3919
0
                s1 = getbeu16(buf, 6);    // Clock Bias (combined)
3920
0
                s2 = getbeu16(buf, 8);    // Clock Bias rate (combined)
3921
                // FIXME: decode the individual biases
3922
0
                GPSD_LOG(LOG_PROG, &session->context->errout,
3923
0
                         "TSIP x8f-a7: tow %llu mode %u bias %d "
3924
0
                         "bias rate %d\n",
3925
0
                         (long long unsigned)tow, u1, s1, s2);
3926
0
            } else {
3927
                // unknown mode
3928
0
                GPSD_LOG(LOG_WARN, &session->context->errout,
3929
0
                         "TSIP x8f-a7: tow %llu mode %u. Unnown mode\n",
3930
0
                         (long long unsigned)tow, u1);
3931
0
            }
3932
0
            break;
3933
0
        case 0xa9:
3934
            /* Self Survey Parameters
3935
             * Present in:
3936
             *   ICM SMT 360 (2018)
3937
             *   RES SMT 360 (2018)
3938
             *   Resolution SMTx
3939
             * Not Present in:
3940
             *   pre-2000 models
3941
             *   Copernicus II (2009)
3942
             */
3943
0
            if (11 > len) {
3944
0
                bad_len = 11;
3945
0
                break;
3946
0
            }
3947
0
            u1 = getub(buf, 1);         // Self Survey Enable
3948
0
            u2 = getub(buf, 2);         // Position Save Flag
3949
0
            u3 = getbeu32(buf, 3);      // Self Survey Length
3950
0
            u4 = getbeu32(buf, 7);      // Reserved
3951
0
            GPSD_LOG(LOG_WARN, &session->context->errout,
3952
0
                     "TSIP x8f-a9 SSP: sse %u psf %u length %d rex x%x \n",
3953
0
                     u1, u2, u3, u4);
3954
0
            break;
3955
0
        case 0xab:
3956
            /* Thunderbolt Timing Superpacket
3957
             * Present in:
3958
             *   Resolution SMTx
3959
             * Not Present in:
3960
             *   pre-2000 models
3961
             *   Copernicus II (2009)
3962
             */
3963
0
            if (17 > len) {
3964
0
                bad_len = 17;
3965
0
                break;
3966
0
            }
3967
0
            session->driver.tsip.last_41 = now; // keep timestamp for request
3968
0
            mask = decode_x8f_ab(session, buf);
3969
0
            break;
3970
3971
0
        case 0xac:
3972
            /* Supplemental Timing Packet (0x8f-ac)
3973
             * present in:
3974
             *   ThunderboltE
3975
             *   ICM SMT 360
3976
             *   RES SMT 360
3977
             *   Resolution SMTx
3978
             * Not Present in:
3979
             *   pre-2000 models
3980
             *   Lassen iQ
3981
             *   Copernicus II (2009)
3982
             */
3983
0
            if (68 != len) {
3984
0
                bad_len = 68;
3985
0
                break;
3986
0
            }
3987
0
            mask = decode_x8f_ac(session, buf);
3988
0
            break;
3989
3990
0
        case 0x02:
3991
            /* UTC Information
3992
             * Present in:
3993
             *   ICM SMT 360 (2018)
3994
             *   RES SMT 360 (2018)
3995
             * Not Present in:
3996
             *   pre-2000 models
3997
             *   Copernicus II (2009)
3998
             */
3999
0
            FALLTHROUGH
4000
0
        case 0x21:
4001
            /* Request accuracy information
4002
             * Present in:
4003
             *   Copernicus II (2009)
4004
             * Not Present in:
4005
             *   pre-2000 models
4006
             */
4007
0
            FALLTHROUGH
4008
0
        case 0x2a:
4009
            /* Request Fix and Channel Tracking info, Type 1
4010
             * Present in:
4011
             *   Copernicus II (2009)
4012
             * Not Present in:
4013
             *   pre-2000 models
4014
             */
4015
0
            FALLTHROUGH
4016
0
        case 0x2b:
4017
            /* Request Fix and Channel Tracking info, Type 2
4018
             * Present in:
4019
             *   Copernicus II (2009)
4020
             * Not Present in:
4021
             *   pre-2000 models
4022
             */
4023
0
            FALLTHROUGH
4024
0
        case 0x41:
4025
            /* Stored manufacturing operating parameters
4026
             * Present in:
4027
             *   ICM SMT 360 (2018)
4028
             *   RES SMT 360 (2018)
4029
             * Not Present in:
4030
             *   pre-2000 models
4031
             *   Copernicus II (2009)
4032
             */
4033
0
            FALLTHROUGH
4034
0
        case 0x4a:
4035
            /* PPS characteristics
4036
             * Present in:
4037
             *   ICM SMT 360 (2018)
4038
             *   RES SMT 360 (2018)
4039
             *   Copernicus II (2009)
4040
             * Not Present in:
4041
             *   pre-2000 models
4042
             */
4043
0
            FALLTHROUGH
4044
0
        case 0x4e:
4045
            /* PPS Output options
4046
             * Present in:
4047
             *   ICM SMT 360 (2018)
4048
             *   RES SMT 360 (2018)
4049
             * Not Present in:
4050
             *   pre-2000 models
4051
             *   Copernicus II (2009)
4052
             */
4053
0
            FALLTHROUGH
4054
0
        case 0x4f:
4055
            /* Set PPS Width
4056
             * Present in:
4057
             *   Copernicus II (2009)
4058
             * Not Present in:
4059
             *   pre-2000 models
4060
             *   ICM SMT 360 (2018)
4061
             *   RES SMT 360 (2018)
4062
             */
4063
0
            FALLTHROUGH
4064
0
        case 0x60:
4065
            /* DR Calibration and Status Report
4066
             * Present in:
4067
             *   pre-2000 models
4068
             * Not Present in:
4069
             *   Copernicus II (2009)
4070
             *   ICM SMT 360 (2018)
4071
             *   RES SMT 360 (2018)
4072
             */
4073
0
            FALLTHROUGH
4074
0
        case 0x62:
4075
            /* GPS/DR Position/Velocity Report
4076
             * Present in:
4077
             *   pre-2000 models
4078
             * Not Present in:
4079
             *   Copernicus II (2009)
4080
             *   ICM SMT 360 (2018)
4081
             *   RES SMT 360 (2018)
4082
             */
4083
0
            FALLTHROUGH
4084
0
        case 0x64:
4085
            /* Firmware Version and Configuration Report
4086
             * Present in:
4087
             *   pre-2000 models
4088
             * Not Present in:
4089
             *   Copernicus II (2009)
4090
             *   ICM SMT 360 (2018)
4091
             *   RES SMT 360 (2018)
4092
             */
4093
0
            FALLTHROUGH
4094
0
        case 0x6b:
4095
            /* Last Gyroscope Readings Report
4096
             * Present in:
4097
             *   pre-2000 models
4098
             * Not Present in:
4099
             *   Copernicus II (2009)
4100
             *   ICM SMT 360 (2018)
4101
             *   RES SMT 360 (2018)
4102
             */
4103
0
            FALLTHROUGH
4104
0
        case 0x6d:
4105
            /* Last Odometer Readings Report
4106
             * Present in:
4107
             *   pre-2000 models
4108
             * Not Present in:
4109
             *   Copernicus II (2009)
4110
             *   ICM SMT 360 (2018)
4111
             *   RES SMT 360 (2018)
4112
             */
4113
0
            FALLTHROUGH
4114
0
        case 0x6f:
4115
            /* Firmware Version Name Report
4116
             * Present in:
4117
             *   pre-2000 models
4118
             * Not Present in:
4119
             *   Copernicus II (2009)
4120
             *   ICM SMT 360 (2018)
4121
             *   RES SMT 360 (2018)
4122
             */
4123
0
            FALLTHROUGH
4124
0
        case 0x70:
4125
            /* Beacon Channel Status Report
4126
             * Present in:
4127
             *   pre-2000 models
4128
             * Not Present in:
4129
             *   Copernicus II (2009)
4130
             *   ICM SMT 360 (2018)
4131
             *   RES SMT 360 (2018)
4132
             */
4133
0
            FALLTHROUGH
4134
0
        case 0x71:
4135
            /* DGPS Station Database Reports
4136
             * Present in:
4137
             *   pre-2000 models
4138
             * Not Present in:
4139
             *   Copernicus II (2009)
4140
             *   ICM SMT 360 (2018)
4141
             *   RES SMT 360 (2018)
4142
             */
4143
0
            FALLTHROUGH
4144
0
        case 0x73:
4145
            /* Beacon Channel Control Acknowledgment
4146
             * Present in:
4147
             *   pre-2000 models
4148
             * Not Present in:
4149
             *   Copernicus II (2009)
4150
             *   ICM SMT 360 (2018)
4151
             *   RES SMT 360 (2018)
4152
             */
4153
0
            FALLTHROUGH
4154
0
        case 0x74:
4155
            /* Clear Beacon Database Acknowledgment
4156
             * Present in:
4157
             *   pre-2000 models
4158
             * Not Present in:
4159
             *   Copernicus II (2009)
4160
             *   ICM SMT 360 (2018)
4161
             *   RES SMT 360 (2018)
4162
             */
4163
0
            FALLTHROUGH
4164
0
        case 0x75:
4165
            /* FFT Start Acknowledgment
4166
             * Present in:
4167
             *   pre-2000 models
4168
             * Not Present in:
4169
             *   Copernicus II (2009)
4170
             *   ICM SMT 360 (2018)
4171
             *   RES SMT 360 (2018)
4172
             */
4173
0
            FALLTHROUGH
4174
0
        case 0x76:
4175
            /* FFT Stop Acknowledgment
4176
             * Present in:
4177
             *   pre-2000 models
4178
             * Not Present in:
4179
             *   Copernicus II (2009)
4180
             *   ICM SMT 360 (2018)
4181
             *   RES SMT 360 (2018)
4182
             */
4183
0
            FALLTHROUGH
4184
0
        case 0x77:
4185
            /* FFT Reports
4186
             * Present in:
4187
             *   pre-2000 models
4188
             * Not Present in:
4189
             *   Copernicus II (2009)
4190
             *   ICM SMT 360 (2018)
4191
             *   RES SMT 360 (2018)
4192
             */
4193
0
            FALLTHROUGH
4194
0
        case 0x78:
4195
            /* RTCM Reports
4196
             * Present in:
4197
             *   pre-2000 models
4198
             * Not Present in:
4199
             *   Copernicus II (2009)
4200
             *   ICM SMT 360 (2018)
4201
             *   RES SMT 360 (2018)
4202
             */
4203
0
            FALLTHROUGH
4204
0
        case 0x79:
4205
            /* Beacon Station Attributes Acknowledgment
4206
             * Present in:
4207
             *   pre-2000 models
4208
             * Not Present in:
4209
             *   Copernicus II (2009)
4210
             *   ICM SMT 360 (2018)
4211
             *   RES SMT 360 (2018)
4212
             */
4213
0
            FALLTHROUGH
4214
0
        case 0x7a:
4215
            /* Beacon Station Attributes Report
4216
             * Present in:
4217
             *   pre-2000 models
4218
             * Not Present in:
4219
             *   Copernicus II (2009)
4220
             *   ICM SMT 360 (2018)
4221
             *   RES SMT 360 (2018)
4222
             */
4223
0
            FALLTHROUGH
4224
0
        case 0x7b:
4225
            /* DGPS Receiver RAM Configuration Block Report
4226
             * Present in:
4227
             *   pre-2000 models
4228
             * Not Present in:
4229
             *   Copernicus II (2009)
4230
             *   ICM SMT 360 (2018)
4231
             *   RES SMT 360 (2018)
4232
             */
4233
0
            FALLTHROUGH
4234
0
        case 0x7c:
4235
            /* DGPS Receiver Configuration Block Acknowledgment
4236
             * Present in:
4237
             *   pre-2000 models
4238
             * Not Present in:
4239
             *   Copernicus II (2009)
4240
             *   ICM SMT 360 (2018)
4241
             *   RES SMT 360 (2018)
4242
             */
4243
0
            FALLTHROUGH
4244
0
        case 0x7e:
4245
            /* Satellite Line-of-Sight (LOS) Message
4246
             * Present in:
4247
             *   pre-2000 models
4248
             * Not Present in:
4249
             *   Copernicus II (2009)
4250
             *   ICM SMT 360 (2018)
4251
             *   RES SMT 360 (2018)
4252
             */
4253
0
            FALLTHROUGH
4254
0
        case 0x7f:
4255
            /* DGPS Receiver ROM Configuration Block Report
4256
             * Present in:
4257
             *   pre-2000 models
4258
             * Not Present in:
4259
             *   Copernicus II (2009)
4260
             *   ICM SMT 360 (2018)
4261
             *   RES SMT 360 (2018)
4262
             */
4263
0
            FALLTHROUGH
4264
0
        case 0x80:
4265
            /* DGPS Service Provider System Information Report
4266
             * Present in:
4267
             *   pre-2000 models
4268
             * Not Present in:
4269
             *   Copernicus II (2009)
4270
             *   ICM SMT 360 (2018)
4271
             *   RES SMT 360 (2018)
4272
             */
4273
0
            FALLTHROUGH
4274
0
        case 0x81:
4275
            /* Decoder Station Information Report and Selection Acknowledgment
4276
             * Present in:
4277
             *   pre-2000 models
4278
             * Not Present in:
4279
             *   Copernicus II (2009)
4280
             *   ICM SMT 360 (2018)
4281
             *   RES SMT 360 (2018)
4282
             */
4283
0
            FALLTHROUGH
4284
0
        case 0x82:
4285
            /* Decoder Diagnostic Information Report
4286
             * Present in:
4287
             *   pre-2000 models
4288
             * Not Present in:
4289
             *   Copernicus II (2009)
4290
             *   ICM SMT 360 (2018)
4291
             *   RES SMT 360 (2018)
4292
             */
4293
0
            FALLTHROUGH
4294
0
        case 0x84:
4295
            /* Satellite FFT Control Acknowledgment
4296
             * Present in:
4297
             *   pre-2000 models
4298
             * Not Present in:
4299
             *   Copernicus II (2009)
4300
             *   ICM SMT 360 (2018)
4301
             *   RES SMT 360 (2018)
4302
             */
4303
0
            FALLTHROUGH
4304
0
        case 0x85:
4305
            /* DGPS Source Tracking Status Report
4306
             * Present in:
4307
             *   pre-2000 models
4308
             * Not Present in:
4309
             *   Copernicus II (2009)
4310
             *   ICM SMT 360 (2018)
4311
             *   RES SMT 360 (2018)
4312
             */
4313
0
            FALLTHROUGH
4314
0
        case 0x86:
4315
            /* Clear Satellite Database Acknowledgment
4316
             * Present in:
4317
             *   pre-2000 models
4318
             * Not Present in:
4319
             *   Copernicus II (2009)
4320
             *   ICM SMT 360 (2018)
4321
             *   RES SMT 360 (2018)
4322
             */
4323
0
            FALLTHROUGH
4324
0
        case 0x87:
4325
            /* Network Statistics Report
4326
             * Present in:
4327
             *   pre-2000 models
4328
             * Not Present in:
4329
             *   Copernicus II (2009)
4330
             *   ICM SMT 360 (2018)
4331
             *   RES SMT 360 (2018)
4332
             */
4333
0
            FALLTHROUGH
4334
0
        case 0x88:
4335
            /* Diagnostic Output Options Report
4336
             * Present in:
4337
             *   pre-2000 models
4338
             * Not Present in:
4339
             *   Copernicus II (2009)
4340
             *   ICM SMT 360 (2018)
4341
             *   RES SMT 360 (2018)
4342
             */
4343
0
            FALLTHROUGH
4344
0
        case 0x89:
4345
            /* DGPS Source Control Report /Acknowledgment
4346
             * Present in:
4347
             *   pre-2000 models
4348
             * Not Present in:
4349
             *   Copernicus II (2009)
4350
             *   ICM SMT 360 (2018)
4351
             *   RES SMT 360 (2018)
4352
             */
4353
0
            FALLTHROUGH
4354
0
        case 0x8a:
4355
            /* Service Provider Information Report and Acknowledgment
4356
             * Present in:
4357
             *   pre-2000 models
4358
             * Not Present in:
4359
             *   Copernicus II (2009)
4360
             *   ICM SMT 360 (2018)
4361
             *   RES SMT 360 (2018)
4362
             */
4363
0
            FALLTHROUGH
4364
0
        case 0x8b:
4365
            /* Service Provider Activation Information Report & Acknowledgment
4366
             * Present in:
4367
             *   pre-2000 models
4368
             * Not Present in:
4369
             *   Copernicus II (2009)
4370
             *   ICM SMT 360 (2018)
4371
             *   RES SMT 360 (2018)
4372
             */
4373
0
            FALLTHROUGH
4374
0
        case 0x8e:
4375
            /* Service Provider Data Load Report
4376
             * Present in:
4377
             *   pre-2000 models
4378
             * Not Present in:
4379
             *   Copernicus II (2009)
4380
             *   ICM SMT 360 (2018)
4381
             *   RES SMT 360 (2018)
4382
             */
4383
0
            FALLTHROUGH
4384
0
        case 0x8f:
4385
            /* Receiver Identity Report
4386
             * Present in:
4387
             *   pre-2000 models
4388
             * Not Present in:
4389
             *   Copernicus II (2009)
4390
             *   ICM SMT 360 (2018)
4391
             *   RES SMT 360 (2018)
4392
             */
4393
0
            FALLTHROUGH
4394
0
        case 0x90:
4395
            /* Guidance Status Report
4396
             * Present in:
4397
             *   pre-2000 models
4398
             * Not Present in:
4399
             *   Copernicus II (2009)
4400
             *   ICM SMT 360 (2018)
4401
             *   RES SMT 360 (2018)
4402
             */
4403
0
            FALLTHROUGH
4404
0
        case 0x91:
4405
            /* Guidance Configuration Report
4406
             * Present in:
4407
             *   pre-2000 models
4408
             * Not Present in:
4409
             *   Copernicus II (2009)
4410
             *   ICM SMT 360 (2018)
4411
             *   RES SMT 360 (2018)
4412
             */
4413
0
            FALLTHROUGH
4414
0
        case 0x92:
4415
            /* Lightbar Configuration Report
4416
             * Present in:
4417
             *   pre-2000 models
4418
             * Not Present in:
4419
             *   Copernicus II (2009)
4420
             *   ICM SMT 360 (2018)
4421
             *   RES SMT 360 (2018)
4422
             */
4423
0
            FALLTHROUGH
4424
0
        case 0x94:
4425
            /* Guidance Operation Acknowledgment
4426
             * Present in:
4427
             *   pre-2000 models
4428
             * Not Present in:
4429
             *   Copernicus II (2009)
4430
             *   ICM SMT 360 (2018)
4431
             *   RES SMT 360 (2018)
4432
             */
4433
0
            FALLTHROUGH
4434
0
        case 0x95:
4435
            /* Button Box Configuration Type Report
4436
             * Present in:
4437
             *   pre-2000 models
4438
             * Not Present in:
4439
             *   Copernicus II (2009)
4440
             *   ICM SMT 360 (2018)
4441
             *   RES SMT 360 (2018)
4442
             */
4443
0
            FALLTHROUGH
4444
0
        case 0x96:
4445
            /* Point Manipulation Report
4446
             * Present in:
4447
             *   pre-2000 models
4448
             * Not Present in:
4449
             *   Copernicus II (2009)
4450
             *   ICM SMT 360 (2018)
4451
             *   RES SMT 360 (2018)
4452
             */
4453
0
            FALLTHROUGH
4454
0
        case 0x97:
4455
            /* Utility Information Report
4456
             * Present in:
4457
             *   pre-2000 models
4458
             * Not Present in:
4459
             *   Copernicus II (2009)
4460
             *   ICM SMT 360 (2018)
4461
             *   RES SMT 360 (2018)
4462
             */
4463
0
            FALLTHROUGH
4464
0
        case 0x98:
4465
            /* Individual Button Configuration Report
4466
             * Present in:
4467
             *   pre-2000 models
4468
             * Not Present in:
4469
             *   Copernicus II (2009)
4470
             *   ICM SMT 360 (2018)
4471
             *   RES SMT 360 (2018)
4472
             */
4473
0
            FALLTHROUGH
4474
0
        case 0x9a:
4475
            /* Differential Correction Information Report
4476
             * Present in:
4477
             *   pre-2000 models
4478
             * Not Present in:
4479
             *   Copernicus II (2009)
4480
             *   ICM SMT 360 (2018)
4481
             *   RES SMT 360 (2018)
4482
             */
4483
0
            FALLTHROUGH
4484
0
        case 0xa0:
4485
            /* DAC value
4486
             * Present in:
4487
             *   ICM SMT 360 (2018)
4488
             *   RES SMT 360 (2018)
4489
             * Not Present in:
4490
             *   pre-2000 models
4491
             *   Copernicus II (2009)
4492
             */
4493
0
            FALLTHROUGH
4494
0
        case 0xa2:
4495
            /* UTC/GPS timing
4496
             * Present in:
4497
             *   ICM SMT 360 (2018)
4498
             *   RES SMT 360 (2018)
4499
             * Not Present in:
4500
             *   pre-2000 models
4501
             *   Copernicus II (2009)
4502
             */
4503
0
            FALLTHROUGH
4504
0
        case 0xa3:
4505
            /* Oscillator disciplining command
4506
             * Present in:
4507
             *   ICM SMT 360 (2018)
4508
             *   RES SMT 360 (2018)
4509
             * Not Present in:
4510
             *   pre-2000 models
4511
             *   Copernicus II (2009)
4512
             */
4513
0
            FALLTHROUGH
4514
0
        case 0xa8:
4515
            /* Oscillator disciplining parameters
4516
             * Present in:
4517
             *   ICM SMT 360 (2018)
4518
             *   RES SMT 360 (2018)
4519
             * Not Present in:
4520
             *   pre-2000 models
4521
             *   Copernicus II (2009)
4522
             */
4523
0
            FALLTHROUGH
4524
0
        default:
4525
0
            GPSD_LOG(LOG_WARN, &session->context->errout,
4526
0
                     "TSIP x8f-%02x: Unhandled TSIP superpacket\n", u1);
4527
0
        }
4528
0
        break;
4529
// Start of TSIP V1
4530
0
    case 0x90:
4531
        /* Version Information, TSIP v1
4532
         * Present in:
4533
         *   RES720
4534
         */
4535
0
        FALLTHROUGH
4536
0
    case 0x91:
4537
        /* Receiver Configuration, TSIP v1
4538
         * Present in:
4539
         *   RES720
4540
         */
4541
0
        FALLTHROUGH
4542
0
    case 0x92:
4543
        /* Resets, TSIP v1
4544
         * Present in:
4545
         *   RES720
4546
         */
4547
0
        FALLTHROUGH
4548
0
    case 0x93:
4549
        /* Production & Manufacturing, TSIP v1
4550
         * Present in:
4551
         *   RES720
4552
         */
4553
0
        FALLTHROUGH
4554
0
    case 0xa0:
4555
        /* Firmware Upload, TSIP v1
4556
         * Present in:
4557
         *   RES720
4558
         */
4559
0
        FALLTHROUGH
4560
0
    case 0xa1:
4561
        /* PVT, TSIP v1
4562
         * Present in:
4563
         *   RES720
4564
         */
4565
0
        FALLTHROUGH
4566
0
    case 0xa2:
4567
        /* GNSS Information, TSIP v1
4568
         * Present in:
4569
         *   RES720
4570
         */
4571
0
        FALLTHROUGH
4572
0
    case 0xa3:
4573
        /* Alarms % Status, TSIP v1
4574
         * Present in:
4575
         *   RES720
4576
         */
4577
0
        FALLTHROUGH
4578
0
    case 0xa4:
4579
        /* AGNSS, TSIP v1
4580
         * Present in:
4581
         *   RES720
4582
         */
4583
0
        FALLTHROUGH
4584
0
    case 0xa5:
4585
        /* Miscellaneous, TSIP v1
4586
         * Present in:
4587
         *   RES720
4588
         */
4589
0
        FALLTHROUGH
4590
0
    case 0xd0:
4591
        /* Debug & Logging, TSIP v1
4592
         * Present in:
4593
         *   RES720
4594
         */
4595
0
        return tsipv1_parse(session, id, buf, len);
4596
// end of TSIP V1
4597
0
    case 0xbb:
4598
        /* Navigation Configuration
4599
         * Present in:
4600
         *   pre-2000 models
4601
         *   Copernicus II (2009)
4602
         *   ICM SMT 360 (2018)
4603
         *   RES SMT 360 (2018)
4604
         */
4605
0
        if (40 != len &&
4606
0
            43 != len) {
4607
            // see packet.c for explamation
4608
0
            bad_len = 40;
4609
0
            break;
4610
0
        }
4611
0
        u1 = getub(buf, 0);             // Subcode, always zero?
4612
0
        u2 = getub(buf, 1);             // Operating Dimension (Receiver Mode)
4613
0
        u3 = getub(buf, 2);             // DGPS Mode (not in Acutime Gold)
4614
0
        u4 = getub(buf, 3);             // Dynamics Code
4615
0
        f1 = getbef32(buf, 5);          // Elevation Mask
4616
0
        f2 = getbef32(buf, 9);          // AMU Mask
4617
0
        f3 = getbef32(buf, 13);         // DOP Mask
4618
0
        f4 = getbef32(buf, 17);         // DOP Switch
4619
0
        u5 = getub(buf, 21);            // DGPS Age Limit (not in Acutime Gold)
4620
        /* Constellation
4621
         * bit 0 - GPS
4622
         * bit 1 - GLONASS
4623
         * bit 2 - reserved
4624
         * bit 3 - BeiDou
4625
         * bit 4 - Galileo
4626
         * bit 5 - QZSS
4627
         * bit 6 - reserved
4628
         * bit 7 - reserved
4629
         */
4630
        // RES SMT 360 defaults to Mode 7, Constellation 3
4631
0
        u6 = getub(buf, 27);
4632
4633
0
        GPSD_LOG(LOG_PROG, &session->context->errout,
4634
0
                 "TSIP xbb: Navigation Configuration: %u %u %u %u %f %f %f "
4635
0
                 "%f %u x%x\n",
4636
0
                 u1, u2, u3, u4, f1, f2, f3, f4, u5, u6);
4637
0
        GPSD_LOG(LOG_IO, &session->context->errout,
4638
0
                 "TSIP: rm %s\n",
4639
0
                 val2str(u1, vrec_mode));
4640
0
        break;
4641
4642
0
    case 0x1a:
4643
        /* TSIP RTCM Wrapper Command
4644
         * Present in:
4645
         *   pre-2000 models
4646
         * Not Present in:
4647
         *   ICM SMT 360 (2018)
4648
         *   RES SMT 360 (2018)
4649
         *   Copernicus II (2009)
4650
         */
4651
0
        FALLTHROUGH
4652
0
    case 0x2e:
4653
        /* Request GPS Time
4654
         * Present in:
4655
         *   ICM SMT 360 (2018)
4656
         *   RES SMT 360 (2018)
4657
         * Not Present in:
4658
         *   pre-2000 models
4659
         *   Copernicus II (2009)
4660
         */
4661
0
        FALLTHROUGH
4662
0
    case 0x32:
4663
        /* Request Unit Position
4664
         * Present in:
4665
         *   ICM SMT 360 (2018)
4666
         *   RES SMT 360 (2018)
4667
         * Not Present in:
4668
         *   pre-2000 models
4669
         *   Copernicus II (2009)
4670
         */
4671
0
        FALLTHROUGH
4672
0
    case 0x38:
4673
        /* Request SV System data
4674
         * Present i