Coverage Report

Created: 2026-03-03 06:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gpsd/gpsd-3.27.6~dev/drivers/driver_tsip.c
Line
Count
Source
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
36.5k
#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
143
#define IO1_ECEF 1
43
220
#define IO1_LLA 2
44
484
#define IO1_MSL 4
45
307
#define IO1_DP 0x10
46
// IO1_8F20 not in SMT 360
47
251
#define IO1_8F20 0x20
48
// byte 2 Velocity
49
56
#define IO2_VECEF 1
50
220
#define IO2_ENU 2
51
// byte 3 Timing
52
#define IO3_UTC 1
53
// byte 4 Aux/Reserved
54
#define IO4_RAW 1
55
251
#define IO4_DBHZ 8
56
57
578
#define SEMI_2_DEG      (180.0 / 2147483647L)    // 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
/* Error Code Flags
69
 * Used in xa3-21 */
70
static struct vlist_t verr_codes1[] = {
71
    {1, "Parameter Error"},
72
    {2, "Length Error"},
73
    {3, "Invalid Parket Format"},
74
    {4, "Invalid Checksum"},
75
    {5, "Bad TNL/User mode"},
76
    {6, "Invalid Packet ID"},
77
    {7, "Invalid Subacket ID"},
78
    {8, "Update in Progress"},
79
    {9, "Internal Error (div by 0)"},
80
    {10, "Internal Error (failed queuing)"},
81
    {0, NULL},
82
};
83
84
/* Fix Type v1
85
 * Used in xa1-11 */
86
static struct vlist_t vfix_type1[] = {
87
    {0, "No Fix"},
88
    {1, "1D"},
89
    {2, "3D"},
90
    {0, NULL},
91
};
92
93
/* GNSS Decoding Status to string
94
 * Used in xa3-11 */
95
static struct vlist_t vgnss_decode_status1[] = {
96
    {0, "Doing Fixes"},
97
    {1, "No GPS time"},
98
    {2, "PDOP too high"},
99
    {3, "0 usable sats"},
100
    {4, "1 usable sat"},
101
    {5, "2 usable sats"},
102
    {6, "3 usable sats"},
103
    {0xff, "GPS Time Fix (OD mode)"},
104
    {0, NULL},
105
};
106
107
/* Major Alarm Flags v1
108
 * Used in xa3-00 */
109
static struct flist_t vmajor_alarms1[] = {
110
    {1, 1, "Not tracking sats"},
111
    {2, 2, "PPS bad"},
112
    {4, 4, "PPS not generated"},
113
    {0x80, 0x80, "Spoofing/Multipath"},
114
    {0x100, 0x100, "Jamming"},
115
    {0, 0, NULL},
116
};
117
118
/* Minor Alarm Flags v1
119
 * Used in xa3-00 */
120
static struct flist_t vminor_alarms1[] = {
121
    {1, 1, "Ant Open"},
122
    {2, 2, "Ant Short"},
123
    {4, 4, "Leap Pending"},
124
    {8, 8, "Almanac Incomplete"},
125
    {0x10, 0x10, "Survey in Progress"},
126
    {0x20, 0x20, "GPS Almanac Incomplete"},
127
    {0x20, 0x20, "GLO Almanac Incomplete"},
128
    {0x40, 0x40, "BDS Almanac Incomplete"},
129
    {0x80, 0x80, "GAL Almanac Incomplete"},
130
    {0x100, 0x100, "Leap Second Insertion"},
131
    {0x200, 0x200, "Leap Second Deletion"},
132
    {0, 0, NULL},
133
};
134
135
/* Parity v1
136
 * Used in x91-00 */
137
static struct vlist_t vparity1[] = {
138
    {0, "None bits"},
139
    {1, "Odd"},
140
    {2, "Even"},
141
    {255, "Ignore"},
142
    {0, NULL},
143
};
144
145
/* Port Name v1
146
 * Used in x91-00 */
147
static struct vlist_t vport_name1[] = {
148
    {0, "Port A"},
149
    {1, "Port B"},
150
    {255, "Current Port"},
151
    {0, NULL},
152
};
153
154
/* Port Type v1
155
 * Used in x91-00 */
156
static struct vlist_t vport_type1[] = {
157
    {0, "UART"},
158
    {0, NULL},
159
};
160
161
/* Position Mask
162
 * Used in xa1-11 */
163
static struct flist_t vpos_mask1[] = {
164
    {0, 1, "Real Time Position"},
165
    {1, 1, "Surveyed Position"},
166
    {0, 2, "LLA Position"},
167
    {2, 2, "XYZ ECEF"},
168
    {0, 4, "HAE"},
169
    {4, 4, "MSL"},
170
    {0, 8, "Velocity ENU"},
171
    {8, 8, "Velocity ECEF"},
172
    {0, 0, NULL},
173
};
174
175
/* PPS Mask v1
176
 * Used in x91-03 */
177
static struct vlist_t vpps_mask1[] = {
178
    {0, "Off"},
179
    {1, "On"},
180
    {2, "Fix Based"},
181
    {3, "When Valid"},
182
    {4, "Off"},
183
    {5, "On/Negative"},
184
    {6, "Fix Based/Negative"},
185
    {7, "When Valid/Negative"},
186
    {0, NULL},
187
};
188
189
/* Protocol v1
190
 * Used in x91-00 */
191
static struct vlist_t vprotocol1[] = {
192
    {2, "TSIP"},
193
    {4, "NMEA"},
194
    {255, "Ignore"},
195
    {0, NULL},
196
};
197
198
/* Receiver Mode v1
199
 * Used in xa3-11 */
200
static struct vlist_t vrec_mode1[] = {
201
    {0, "2D"},
202
    {1, "(3D) Time Only"},
203
    {3, "Automatic"},
204
    {6, "Overdetermined"},
205
    {0, NULL},
206
};
207
208
/* Reset Type, Reset Cause
209
 * Used in x92-00, x92-01 */
210
static struct vlist_t vreset_type1[] = {
211
    {1, "No Reset"},           // x92-01 only
212
    {1, "Cold Reset"},
213
    {2, "Hot Reset"},
214
    {3, "Warm Reset"},
215
    {4, "Factory Reset"},
216
    {5, "System Reset"},
217
    {6, "Power Cycle"},        // x92-01 only
218
    {7, "Watchdog"},           // x92-01 only
219
    {8, "Hardfault"},          // x92-01 only
220
    {0, NULL},
221
};
222
223
/* Satellite Flags v1
224
 * Used in xa2-00 */
225
static struct flist_t vsflags1[] = {
226
    {1, 1, "Acquired"},
227
    {2, 2, "Used in Position"},
228
    {4, 4, "Used in PPS"},
229
    // Bits 8 - 15 "Satellite Status, otherwise undocumented.
230
    {0, 0, NULL},
231
};
232
233
/* Speed v1
234
 * Used in x91-00 */
235
static struct vlist_t vspeed1[] = {
236
    {11, "115200"},
237
    {12, "230400"},
238
    {13, "460800"},
239
    {14, "1821600"},
240
    {255, "Ignore"},
241
    {0, NULL},
242
};
243
244
/* Self-Survey Mask v1
245
 * Used in x91-04 */
246
static struct flist_t vss_mask1[] = {
247
    {1, 1, "SS restarted"},
248
    {0, 2, "SS Disabled"},
249
    {2, 2, "SS Enabled"},
250
    {0, 8, "Don't save position"},
251
    {8, 8, "Save position"},
252
    {0, 0, NULL},
253
};
254
255
/* Stop Bits v1
256
 * Used in x91-00 */
257
static struct vlist_t vstop1[] = {
258
    {0, "1 bit"},
259
    {1, "2 bit"},
260
    {255, "Ignore"},
261
    {0, NULL},
262
};
263
264
/* SV Type v1
265
 * Used in xa2-00 */
266
static struct vlist_t vsv_type1[] = {
267
    {1, "GPS L1C"},
268
    {2, "GPS L2"},
269
    {3, "GPS L5"},
270
    {5, "GLO G1"},
271
    {6, "GLO G2"},
272
    {9, "SBAS"},
273
    {13, "BDS B1"},
274
    {14, "BDS B2i"},
275
    {15, "BDS B2a"},
276
    {17, "GAL E1"},
277
    {18, "GAL E5a"},
278
    {19, "GAL E5b"},
279
    {20, "GAL E6"},
280
    {22, "QZSS L1"},
281
    {23, "QZSS L2C"},
282
    {24, "QZSS L5"},
283
    {26, "IRNSS L5"},
284
    {0, NULL},
285
};
286
287
/* SV Types v1
288
 * Used in x91-01 */
289
static struct flist_t vsv_types1[] = {
290
    {1, 1, "GPS L1C"},
291
    {2, 2, "GPS L2"},
292
    {4, 3, "GPS L5"},
293
    {0x20, 0x20, "GLO G1"},
294
    {0x40, 0x40, "GLO G2"},
295
    {0x100, 0x100, "SBAS"},
296
    {0x1000, 0x1000, "BDS B1"},
297
    {0x2000, 0x2000, "BDS B2i"},
298
    {0x4000, 0x4000, "BDS B2a"},
299
    {0x10000, 0x10000, "GAL E1"},
300
    {0x20000, 0x20000, "GAL E5a"},
301
    {0x40000, 0x40000, "GAL E5b"},
302
    {0x80000, 0x80000, "GAL E6"},
303
    {0x100000, 0x100000, "QZSS L1"},
304
    {0x200000, 0x200000, "QZSS L2C"},
305
    {0x400000, 0x400000, "QZSS L5"},
306
    {0x1000000, 0x1000000, "IRNSS L5"},
307
    {0, 0, NULL},
308
};
309
310
/* Time Base v1
311
 * Used in x91-03, xa1-00 */
312
static struct vlist_t vtime_base1[] = {
313
    {0, "GPS"},
314
    {1, "GLO"},
315
    {2, "BDS"},
316
    {3, "GAL"},
317
    {4, "GPS/UTC"},
318
    {6, "GLO/UTC"},
319
    {6, "BDS/UTC"},
320
    {7, "GAL/UTC"},
321
    {0, NULL},
322
};
323
324
/* Time Flags v1
325
 * Used in xa1-00 */
326
static struct flist_t vtime_flags1[] = {
327
    {0, 1, "UTC Invalid"},
328
    {1, 1, "UTC Valid"},
329
    {0, 2, "Time Invalid"},
330
    {2, 2, "Time Valid"},
331
    {0, 0, NULL},
332
};
333
334
// End TSIPv1 values and flags
335
336
// Start TSIP values and flags
337
338
/* Error Code Flags
339
 * Used in x46 */
340
static struct flist_t verr_codes[] = {
341
    {1, 1, "No Bat"},
342
    {0x10, 0x30, "Ant Open"},
343
    {0x30, 0x30, "Ant Short"},
344
    {0, 0, NULL},
345
};
346
347
/* GNSS Decoding Status to string
348
 * Used in x46, x8f-ac */
349
static struct vlist_t vgnss_decode_status[] = {
350
    {0, "Doing Fixes"},
351
    {1, "No GPS time"},
352
    {2, "Needs Init"},                      // ACE II, LassenSQ
353
    {3, "PDOP too high"},
354
    {8, "0 usable sats"},
355
    {9, "1 usable sat"},
356
    {10, "2 usable sats"},
357
    {11, "3 usable sats"},
358
    {12, "chosen sat unusable"},
359
    {16, "TRAIM rejected"},                 // Thunderbolt E
360
    {0xbb, "GPS Time Fix (OD mode)"},       // Acutime 360
361
    {0, NULL},
362
};
363
364
/* Disciplining Activity
365
 * Used in x46, x8f-ac */
366
static struct vlist_t vdisc_act[] = {
367
    {0, "Phase Locking"},
368
    {1, "OSC Wrm-up"},
369
    {2, "Freq lokgin"},
370
    {3, "Placing PPS"},
371
    {4, "Init Loop FIlter"},
372
    {5, "Comp OCXO"},
373
    {6, "Inactive"},
374
    {7, "Not used"},
375
    {8, "REcovery Mode"},
376
    {0, NULL},
377
};
378
379
/* PPS indication
380
 * Used in x46, x8f-ac */
381
static struct vlist_t vpps_ind[] = {
382
    {0, "PPS Good"},
383
    {1, "PPS Ungood"},
384
    {0, NULL},
385
};
386
387
/* PPS Reference
388
 * Used in x46, x8f-ac */
389
static struct vlist_t vpps_ref[] = {
390
    {0, "GNSS"},
391
    {1, "Externa;"},
392
    {0xff, "None;"},
393
    {0, NULL},
394
};
395
396
/* Packet Broadcast Mask
397
 * Used in x8f-a3 */
398
static struct flist_t vpbm_mask0[] = {
399
    {1, 1, "x8f-ab"},
400
    {4, 4, "x8f-ac"},
401
    {0x40, 0x40, "Automatic"},
402
    {0, 0, NULL},
403
};
404
405
/* Receiver Mode
406
 * Used in xbb, x8f-ac */
407
static struct vlist_t vrec_mode[] = {
408
    {0, "Autonomous (2D/3D)"},
409
    {1, "Time Only (1-SV)"},    // Accutime 2000, Tbolt
410
    {3, "2D"},                  // Accutime 2000, Tbolt
411
    {4, "3D"},                  // Accutime 2000, Tbolt
412
    {5, "DGPS"},                // Accutime 2000, Tbolt
413
    {6, "2D Clock hold"},       // Accutime 2000, Tbolt
414
    {7, "Overdetermined"},      // Stationary Timing, surveyed
415
    {0, NULL},
416
};
417
418
/* Save Status
419
 * Used in x91-02 */
420
static struct flist_t vsave_status1[] = {
421
    {0, 1, "Save failed"},
422
    {1, 1, "Save OK"},
423
    {0, 0, NULL},
424
};
425
426
/* Self-Survey Enable
427
 * Used in x8f-a9 */
428
static struct vlist_t vss_enable[] = {
429
    {0, "SS Disabled"},
430
    {1, "SS Enabled"},
431
    {0, NULL},
432
};
433
434
/* Self-Survey Save
435
 * Used in x8f-a9 */
436
static struct vlist_t vss_save[] = {
437
    {0, "Don't Save"},
438
    {1, "Save at end"},
439
    {0, NULL},
440
};
441
442
/* Status 1
443
 * Used in x4b */
444
static struct flist_t vstat1[] = {
445
    {2, 2, "RTC invalid"},
446
    {8, 8, "No Almanac"},
447
    {0, 0, NULL},
448
};
449
450
/* Status 2
451
 * Used in x4b */
452
static struct flist_t vstat2[] = {
453
    {1, 1, "Superpackets"},      // x8f-20 (LFwEI)
454
    {2, 2, "Superpackets 2"},    // x8f-1b, x8f-ac
455
    {0, 0, NULL},
456
};
457
458
/* SV Bad
459
 * Used in x5d */
460
static struct vlist_t vsv_bad[] = {
461
    {0, "OK"},
462
    {1, "Bad Parity"},
463
    {2, "Bad Health"},
464
    {0, NULL},
465
};
466
467
/* SV Type
468
 * Used in x5d */
469
static struct vlist_t vsv_type[] = {
470
    {0, "GPS"},
471
    {1, "GLO"},
472
    {2, "BDS"},
473
    {3, "GAL"},
474
    {6, "QZSS"},
475
    {0, NULL},
476
};
477
478
/* SV Used Flags
479
 * Used in x5d */
480
static struct flist_t vsv_used_flags[] = {
481
    {1, 1, "Used in Timing"},
482
    {2, 2, "Used in Position"},
483
    {0, 0, NULL},
484
};
485
486
/* x4c Dynamics Code
487
 * Used in x4c */
488
static struct vlist_t vx4c_dyncode[] = {
489
    {1, "Land"},             // < 120 knots
490
    {2, "Sea"},              // < 50 knots
491
    {3, "Air"},              // > 800 knots
492
    {0,NULL},
493
};
494
495
/* x55 auxiliary
496
 * Used in x55 */
497
static struct flist_t vx55_aux[] = {
498
    {0, 1, "x5a Off"},
499
    {1, 1, "x5a On"},
500
    {0, 0, NULL},
501
};
502
503
/* x55 Position
504
 * Used in x55 */
505
static struct flist_t vx55_pos[] = {
506
    {1, 1, "ECEF On"},
507
    {2, 2, "LLA On"},
508
    {0, 4, "HAE"},
509
    {4, 4, "MSL"},
510
    {0, 0x10, "Single Precision"},
511
    {0x10, 0x104, "Double Position"},
512
    {0, 0, NULL},
513
};
514
515
/* x55 Timing
516
 * Used in x55 */
517
static struct flist_t vx55_timing[] = {
518
    {1, 1, "Use x8e-a2"},
519
    {0, 0, NULL},
520
};
521
522
/* x55 Velocity
523
 * Used in x55 */
524
static struct flist_t vx55_vel[] = {
525
    {1, 1, "ECEF On"},
526
    {2, 2, "ENU On"},
527
    {0, 0, NULL},
528
};
529
530
/* x57 Source of Info
531
 * Used in x57 */
532
static struct flist_t vx57_info[] = {
533
    {0, 1, "Old Fix"},
534
    {1, 1, "New Fix"},
535
    {0, 0, NULL},
536
};
537
538
/* x57 Fix Mode
539
 * Used in x6c, x57, yet another decode of the same data... */
540
static struct vlist_t vx57_fmode[] = {
541
    {0, "No Fix"},
542
    {1, "Time"},             // Time only 1SV/2D
543
    {3, "2D Fix"},
544
    {4, "3D Fix"},
545
    {5, "OD Fix"},
546
    {0,NULL},
547
};
548
549
/* x5c Acquisition Flag
550
 * Used in x5c */
551
static struct vlist_t vx5c_acq[] = {
552
    {0, "Never"},
553
    {1, "Yes"},
554
    {2, "Search"},
555
    {0,NULL},
556
};
557
558
/* x5c Ephemeris Flag
559
 * Used in x5c */
560
static struct vlist_t vx5c_eflag[] = {
561
    {0, "none"},
562
    {1, "Decoded"},
563
    {3, "Decoded/Healthy"},
564
    {19, "Used"},
565
    {51, "Used/DGPS"},
566
    {0,NULL},
567
};
568
569
/* x82 Mode Timing
570
 * Used in x82 */
571
static struct vlist_t vx82_mode[] = {
572
    {0, "Man DGPS Off"},      // No DPGS ever
573
    {1, "Man DGPS OOn"},      // Only DPGS ever
574
    {2, "Auto DGPS Off"},     // DGPS unavailable
575
    {3, "Auto DGPS On"},      // DGPS available, and in use
576
    {4, NULL},
577
};
578
579
/* x8f-20 Fix Flags
580
 * Used in x8f-20 */
581
static struct flist_t vx8f_20_fflags[] = {
582
    {0, 1, "Fix Yes"},
583
    {2, 2, "DGPS"},
584
    {0, 4, "3D"},
585
    {4, 4, "2D"},
586
    {8, 8, "Alt Holdt"},
587
    {0x10, 0x10, "Filtered"},
588
    {0, 0, NULL},
589
};
590
591
/* Fis Dimension, Fix Mode
592
 * Used in x6c, x6d */
593
static struct flist_t vfix[] = {
594
    // Accutime calls 0 "Auto"
595
    {0, 7, "No Fix"},       // not in ResSMT360
596
    // in x6d, Thunderbolt E calls 1 "1D Time Fix", not an OD Fix
597
    {1, 7, "1D/OD Fix"},
598
    // Accutime calls 3 "2D Clock Hold"
599
    {3, 7, "2D Fix"},
600
    {4, 7, "3D Fix"},
601
    {5, 7, "OD Fix"},       // in Thunderbolt E, x6d, others
602
    {6, 7, "DGPS"},         // in Accutime
603
    {0, 8, "Auto"},
604
    {8, 8, "Manual"},       // aka surveyed
605
    {0, 0, NULL},
606
};
607
608
/* Timing Flags
609
 * Used in x8f-ab */
610
static struct flist_t vtiming[] = {
611
    {0, 1, "GPS time"},
612
    {1, 1, "UTC time"},
613
    {0, 2, "GPS PPS"},
614
    {1, 2, "UTC PPS"},
615
    {4, 4, "Time not set"},
616
    {8, 8,  "no UTC info"},
617
    {0x10, 0x10, "time from user"},
618
    {0, 0, NULL},
619
};
620
621
/* Critical Alarm Flags
622
 * Used in x8f-ac */
623
static struct flist_t vcrit_alarms[] = {
624
    {1, 1, "ROM error"},               // Thunderbolt
625
    {2, 2, "RAM error"},               // Thunderbolt
626
    {4, 4, "FPGA error"},              // Thunderbolt
627
    {8, 8, "Power error"},             // Thunderbolt
628
    {0x10, 0x10, "OSC error"},         // Thunderbolt
629
    {0, 0, NULL},
630
};
631
632
/* Minor Alarm Flags
633
 * Used in x8f-ac */
634
static struct flist_t vminor_alarms[] = {
635
    {1, 1, "OSC warning"},                   // Thunderbolt
636
    {2, 2, "Ant Open"},
637
    {4, 4, "Ant Short"},
638
    {8, 8, "Not tracking Sats"},
639
    {0x10, 0x10, "Osc unlocked"},            // Thunderbolt
640
    {0x20, 0x20, "Survey in progress"},
641
    {0x40, 0x40, "No stored Position"},
642
    {0x80, 0x80, "Leap Sec Pending"},
643
    {0x100, 0x100, "Test Mode"},
644
    {0x200, 0x200, "Position questionable"},
645
    {0x400, 0x400, "EEROM corrupt"},         // Thunderbolt
646
    {0x800, 0x800, "Almanac Incomplete"},
647
    {0x1000, 0x1000, "PPS generated"},
648
    {0, 0, NULL},
649
};
650
651
/* convert TSIP SV Type to satellite_t.gnssid and satellite_t.svid
652
 * return gnssid directly, svid indirectly through pointer */
653
static unsigned char tsip_gnssid(unsigned svtype, short prn,
654
                                 unsigned char *svid)
655
442
{
656
    // initialized to shut up clang
657
442
    unsigned char gnssid = 0;
658
659
442
    *svid = 0;
660
661
442
    switch (svtype) {
662
291
    case 0:
663
291
        if (0 < prn && 33 > prn) {
664
31
            gnssid = GNSSID_GPS;
665
31
            *svid = prn;
666
260
        } else if (32 < prn && 55 > prn) {
667
            // RES SMT 360 and ICM SMT 360 put SBAS in 33-54
668
6
            gnssid = GNSSID_SBAS;
669
6
            *svid = prn + 87;
670
254
        } else if (64 < prn && 97 > prn) {
671
            // RES SMT 360 and ICM SMT 360 put GLONASS in 65-96
672
28
            gnssid = GNSSID_GLO;
673
28
            *svid = prn - 64;
674
226
        } else if (96 < prn && 134 > prn) {
675
            // RES SMT 360 and ICM SMT 360 put Galileo in 97-133
676
34
            gnssid = GNSSID_GAL;
677
34
            *svid = prn - 96;
678
192
        } else if (119 < prn && 139 > prn) {
679
            // Copernicus (II) put SBAS in 120-138
680
42
            gnssid = GNSSID_SBAS;
681
42
            *svid = prn + 87;
682
150
        } else if (183 == prn) {
683
3
            gnssid = GNSSID_QZSS;
684
3
            *svid = 1;
685
147
        } else if (192 <= prn && 193 >= prn) {
686
20
            gnssid = GNSSID_QZSS;
687
20
            *svid = prn - 190;
688
127
        } else if (200 == prn) {
689
40
            gnssid = GNSSID_QZSS;
690
40
            *svid = 4;
691
87
        } else if (200 < prn && 238 > prn) {
692
            // BeidDou in 201-237
693
8
            gnssid = GNSSID_BD;
694
8
            *svid = prn - 200;
695
8
        }
696
        // else: huh?
697
291
        break;
698
4
    case 1:
699
4
        gnssid = GNSSID_GLO;  // GLONASS
700
4
        *svid = prn - 64;
701
4
        break;
702
4
    case 2:
703
4
        gnssid = GNSSID_BD;  // BeiDou
704
4
        *svid = prn - 200;
705
4
        break;
706
16
    case 3:
707
16
        gnssid = GNSSID_GAL;  // Galileo
708
16
        *svid = prn - 96;
709
16
        break;
710
91
    case 5:
711
91
        gnssid = GNSSID_QZSS;  // QZSS
712
91
        switch (prn) {
713
19
        case 183:
714
19
            *svid = 1;
715
19
            break;
716
8
        case 192:
717
8
            *svid = 2;
718
8
            break;
719
28
        case 193:
720
28
            *svid = 3;
721
28
            break;
722
9
        case 200:
723
9
            *svid = 4;
724
9
            break;
725
27
        default:
726
27
            *svid = prn;
727
27
            break;
728
91
        }
729
91
        break;
730
91
    case 4:
731
0
        FALLTHROUGH
732
0
    case 6:
733
0
        FALLTHROUGH
734
0
    case 7:
735
0
        FALLTHROUGH
736
36
    default:
737
36
        *svid = 0;
738
36
        gnssid = 0;
739
36
        break;
740
442
    }
741
442
    return gnssid;
742
442
}
743
744
/* tsip1_checksum()
745
 * compute TSIP version 1 checksum
746
 *
747
 * Return: checksum
748
 */
749
static char tsip1_checksum(const char *buf, size_t len)
750
180
{
751
180
    char checksum = 0;
752
180
    size_t index;
753
754
1.27k
    for(index = 0; index < len; index++) {
755
1.09k
        checksum ^= buf[index];
756
1.09k
    }
757
180
    return checksum;
758
180
}
759
760
/* tsip_write1() - send old style TSIP message, improved tsip_write()
761
 * buf - the packet
762
 * len - length of buf
763
 *
764
 * Adds leading DLE, and the trailing DLE, ETX
765
 *
766
 * Return: 0 == OK
767
 *         -1 == write fail
768
 */
769
static ssize_t tsip_write1(struct gps_device_t *session,
770
                           char *buf, size_t len)
771
12.0k
{
772
12.0k
    char *ep, *cp;
773
12.0k
    char obuf[100];
774
12.0k
    size_t olen = len;
775
776
12.0k
    if (session->context->readonly) {
777
4.08k
        return 0;
778
4.08k
    }
779
7.92k
    if ((NULL == buf) ||
780
7.92k
        0 == len ||
781
7.92k
        (sizeof(session->msgbuf) / 2) < len) {
782
        // could over run, do not chance it
783
0
        return -1;
784
0
    }
785
7.92k
    session->msgbuf[0] = '\x10';
786
7.92k
    ep = session->msgbuf + 1;
787
23.0k
    for (cp = buf; olen-- > 0; cp++) {
788
15.1k
        if ('\x10' == *cp) {
789
0
            *ep++ = '\x10';
790
0
        }
791
15.1k
        *ep++ = *cp;
792
15.1k
    }
793
7.92k
    *ep++ = '\x10';
794
7.92k
    *ep++ = '\x03';
795
7.92k
    session->msgbuflen = (size_t)(ep - session->msgbuf);
796
    // Don't bore the user with the header (DLE) or trailer (DLE, STX).
797
7.92k
    GPSD_LOG(LOG_PROG, &session->context->errout,
798
7.92k
             "TSIP: tsip_write1(0x%s)\n",
799
7.92k
             gps_hexdump(obuf, sizeof(obuf),
800
7.92k
                         (unsigned char *)&session->msgbuf[1], len));
801
7.92k
    if (gpsd_write(session, session->msgbuf, session->msgbuflen) !=
802
7.92k
        (ssize_t) session->msgbuflen)
803
7.92k
        return -1;
804
805
0
    return 0;
806
7.92k
}
807
808
/* tsip_detect()
809
 *
810
 * see if it looks like a TSIP device (speaking 9600O81) is listening and
811
 * return 1 if found, 0 if not
812
 */
813
static bool tsip_detect(struct gps_device_t *session)
814
0
{
815
0
    bool ret = false;
816
0
    int myfd;
817
0
    speed_t old_baudrate;
818
0
    char old_parity;
819
0
    unsigned int old_stopbits;
820
0
    bool override = true;
821
822
0
    if ((speed_t)0 == session->context->fixed_port_speed &&
823
0
        '\0' == session->context->fixed_port_framing[0]) {
824
        // Only try 9600 8O1 is no speed or framing override
825
0
        old_baudrate = session->gpsdata.dev.baudrate;
826
0
        old_parity = session->gpsdata.dev.parity;
827
0
        old_stopbits = session->gpsdata.dev.stopbits;
828
0
        gpsd_set_speed(session, 9600, 'O', 1);
829
0
        override = false;
830
0
    }
831
832
    /* request firmware revision and look for a valid response
833
     * send 0x1f, expect 0x45.  TSIPv1 does not have this, but it
834
     * will respond with a TSIPv1 error message, so all good. */
835
0
    if (0 == tsip_write1(session, "\x1f", 1)) {
836
0
        unsigned int n;
837
0
        struct timespec to;
838
839
0
        myfd = session->gpsdata.gps_fd;
840
841
        // FIXME: this holds the main loop from running...
842
0
        for (n = 0; n < 3; n++) {
843
            // wait 100 milli second
844
0
            to.tv_sec = 0;
845
0
            to.tv_nsec = 100000000;
846
0
            if (!nanowait(myfd, &to)) {
847
0
                break;
848
0
            }
849
0
            if (0 <= packet_get1(session)) {
850
0
                if (TSIP_PACKET == session->lexer.type) {
851
0
                    GPSD_LOG(LOG_RAW, &session->context->errout,
852
0
                             "TSIP: tsip_detect found\n");
853
0
                    ret = true;
854
0
                    break;
855
0
                }
856
0
            }
857
0
        }
858
0
    }
859
860
0
    if (!ret &&
861
0
        !override) {
862
        // return serial port to original settings
863
0
        gpsd_set_speed(session, old_baudrate, old_parity, old_stopbits);
864
0
    }
865
866
0
    return ret;
867
0
}
868
869
// configure generic Trimble TSIP device to a known state
870
static void configuration_packets_generic(struct gps_device_t *session)
871
164
{
872
164
        char buf[100];
873
874
164
        GPSD_LOG(LOG_PROG, &session->context->errout,
875
164
                 "TSIP: configuration_packets_generic()\n");
876
877
        // Set basic configuration, using Set or Request I/O Options (0x35).
878
        // Position: enable: Double Precision, LLA, disable: ECEF
879
164
        buf[0] = 0x35;
880
        // Time: enable: 0x42, 0x43, 0x4a, disable: 0x83, 0x84, 0x56
881
164
        buf[1] = IO1_8F20|IO1_DP|IO1_LLA;
882
        // Velocity: enable: ENU, disable ECEF
883
164
        buf[2] = IO2_ENU;
884
164
        buf[3] = 0x00;
885
164
        buf[4] = IO4_DBHZ;    // Aux: enable: 0x5A, dBHz
886
164
        (void)tsip_write1(session, buf, 5);
887
888
        // Request Software Version (0x1f), returns 0x45
889
164
        (void)tsip_write1(session, "\x1f", 1);
890
891
        // Current Time Request (0x21), returns 0x41
892
164
        (void)tsip_write1(session, "\x21", 1);
893
894
        /* Set Operating Parameters (0x2c)
895
         * not present in:
896
         *   Lassen SQ (2002)
897
         *   Lassen iQ (2005)
898
         *   RES SMT 360 */
899
        /* dynamics code: enabled: 1=land
900
         *   disabled: 2=sea, 3=air, 4=static
901
         *   default is land */
902
164
        buf[0] = 0x2c;
903
164
        buf[1] = 0x01;
904
        // elevation mask, 10 degrees is a common default, TSIP default is 15
905
164
        putbef32(buf, 2, (float)10.0 * DEG_2_RAD);
906
        // signal level mask, default is 2.0 AMU. 5.0 to 6.0 for high accuracy
907
164
        putbef32(buf, 6, (float)06.0);
908
        // PDOP mask default is 12. 5.0 to 6.0 for high accuracy
909
164
        putbef32(buf, 10, (float)8.0);
910
        // PDOP switch, default is 8.0
911
164
        putbef32(buf, 14, (float)6.0);
912
164
        (void)tsip_write1(session, buf, 18);
913
914
        /* Set Position Fix Mode (0x22)
915
         * 0=auto 2D/3D, 1=time only, 3=2D, 4=3D, 10=Overdetermined clock */
916
164
        (void)tsip_write1(session, "\x22\x00", 2);
917
918
        /* Request GPS System Message (0x48)
919
         * not supported on model RES SMT 360 */
920
164
        (void)tsip_write1(session, "\x28", 1);
921
922
        /* Last Position and Velocity Request (0x37)
923
         * returns 0x57 and (0x42, 0x4a, 0x83, or 0x84) and (0x43 or 0x56)  */
924
164
        (void)tsip_write1(session, "\x37", 1);
925
926
        // 0x8e-15 request output datum
927
164
        (void)tsip_write1(session, "\x8e\x15", 2);
928
929
        /* Primary Receiver Configuration Parameters Request (0xbb-00)
930
         * returns  Primary Receiver Configuration Block (0xbb-00) */
931
164
        (void)tsip_write1(session, "\xbb\x00", 2);
932
164
}
933
934
// configure Acutime Gold to a known state
935
static void configuration_packets_acutime_gold(struct gps_device_t *session)
936
5
{
937
5
        char buf[100];
938
939
5
        GPSD_LOG(LOG_PROG, &session->context->errout,
940
5
                 "TSIP: configuration_packets_acutime_gold()\n");
941
942
        /* Request Firmware Version (0x1c-01)
943
         * returns Firmware component version information (0x1x-81) */
944
5
        (void)tsip_write1(session, "\x1c\x01", 2);
945
946
5
        buf[0] = 0x8e;          // Set Self-Survey Parameters (0x8e-a9)
947
5
        buf[1] = 0xa9;          // Subcode
948
5
        buf[2] = 0x01;          // Self-Survey Enable = enable
949
5
        buf[3] = 0x01;          // Position Save Flag = save position
950
5
        putbe32(buf, 4, 2000);  // Self-Survey Length = 2000 fixes, default 2000
951
        // Horizontal Uncertainty, 1-100, 1=best, 100=worst, default 100
952
5
        putbef32(buf, 8, 100);
953
        // Vertical Uncertainty, 1-100, 1=best, 100=worst, default 100
954
5
        putbef32(buf, 12, 100);
955
5
        (void)tsip_write1(session, buf, 16);
956
957
        /* Set PPS Output Option (0x8e-4e)
958
         * 0x4e Subcode
959
         * 2 == PPS driver switch (PPS is always output) */
960
5
        (void)tsip_write1(session, "\x8e\x4e\x02", 3);
961
962
5
        buf[0] = 0xbb;  // Set Primary Receiver Configuration (0xbb-00)
963
5
        buf[1] = 0x00;  // 00 =  Subcode
964
5
        buf[2] = 0x07;  // Receiver mode, 7 = Force Overdetermined clock
965
5
        buf[3] = 0xff;  // Not enabled = unchanged, must be 0xff on RES SMT 360
966
5
        buf[4] = 0x01;  // Dynamics code = default must be 0xff on RES SMT 360
967
5
        buf[5] = 0x01;  // Solution Mode = default must be 0xff on RES SMT 360
968
        // Elevation Mask = 10 deg
969
5
        putbef32((char *)buf, 6, (float)10.0 * DEG_2_RAD);
970
        // AMU Mask. 0 to 55. default is 4.0
971
5
        putbef32((char *)buf, 10, (float)4.0);
972
        // PDOP Mask = 8.0, default = 6
973
5
        putbef32((char *)buf, 14, (float)8.0);
974
        // PDOP Switch = 6.0, ignored in RES SMT 360
975
5
        putbef32((char *)buf, 18, (float)6.0);
976
5
        buf[22] = 0xff;  // must be 0xff
977
5
        buf[23] = 0x0;   // Anti-Jam Mode, 0=Off, 1=On
978
5
        putbe16(buf, 24, 0xffff);  // Reserved.  Must be 0xffff
979
        /* Measurement Rate and Position Fix Rate = default
980
         * must be 0xffff on res smt 360 */
981
5
        putbe16(buf, 26, 0x0000);
982
        /* 27 is Constellation on RES SMT 360.
983
         * 1 = GPS, 2=GLONASS, 8=BeiDou, 0x10=Galileo, 5=QZSS */
984
5
        putbe32(buf, 28, 0xffffffff);   // Reserved
985
5
        putbe32(buf, 32, 0xffffffff);   // Reserved
986
5
        putbe32(buf, 36, 0xffffffff);   // Reserved
987
5
        putbe32(buf, 40, 0xffffffff);   // Reserved
988
5
        (void)tsip_write1(session, buf, 44);
989
990
5
        buf[0] = 0x8e;   // Set Packet Broadcast Mask (0x8e-a5)
991
5
        buf[1] = 0xa5;   // Subcode a5
992
        /* Packets bit field = default + Primary timing,
993
         *  Supplemental timing 32e1
994
         *  1=0x8f-ab, 4=0x8f-ac, 0x40=Automatic Output Packets */
995
5
        putbe16(buf, 2, 0x32e1);
996
5
        buf[4] = 0x00;   // not used
997
5
        buf[5] = 0x00;   // not used
998
5
        (void)tsip_write1(session, buf, 6);
999
5
}
1000
1001
// configure RES 360, Resolution SMTx, and similar to a known state
1002
static void configuration_packets_res360(struct gps_device_t *session)
1003
124
{
1004
124
    char buf[100];
1005
1006
124
    GPSD_LOG(LOG_PROG, &session->context->errout,
1007
124
             "TSIP: configuration_packets_res360()\n");
1008
1009
    // should already have versions 0x8f-81 and 0x8f-83.
1010
1011
    // Request Self Survey Parameters (0x8e-a9)
1012
124
    (void)tsip_write1(session, "\x8e\xa9", 2);
1013
1014
124
    if (session->context->passive) {
1015
        // request I/O Options (0x55)
1016
68
        (void)tsip_write1(session, "\x35", 1);
1017
1018
        // request Receiver Configuration (0xbb)
1019
68
        (void)tsip_write1(session, "\xbb\x00", 2);
1020
1021
        // Request Packet Broadcast Mask (0x8e-a5)
1022
68
        (void)tsip_write1(session, "\x8e\xa5", 2);
1023
1024
68
    } else {
1025
        // PPS Output Option (0x8e-4e) is default on
1026
1027
56
        buf[0] = 0x8e;  // Set Packet Broadcast Mask (0x8e-a5)
1028
56
        buf[1] = 0xa5;  // a5 = Subcode
1029
        /* Packets bit field = default + Auto output packets
1030
         *  1=0x8f-ab, 4=0x8f-ac, 0x40=Automatic Output Packets */
1031
56
        buf[2] = 0;        // reserved
1032
56
        buf[3] = 0x45;
1033
56
        buf[4] = 0;        // reserved
1034
56
        buf[5] = 0;        // reserved
1035
56
        (void)tsip_write1(session, buf, 6);
1036
1037
        /* IO Options defaults:
1038
         *   Lassen iQ:       02 02 00 00
1039
         *   RES SMT 360:     12 02 00 08
1040
         *   Resolution SMTx: 12 02 00 08
1041
         */
1042
56
        buf[0] = 0x35;  // set I/O Options
1043
        // position and velocity only sent during self-survey.
1044
        // Position
1045
56
        buf[1] =  IO1_DP|IO1_LLA|IO1_ECEF;
1046
        // Velocity
1047
56
        buf[2] = IO2_VECEF|IO2_ENU;
1048
        // Timing
1049
56
        buf[3] = 0x01;          // Use 0x8e-a2
1050
        // Auxiliary
1051
56
        buf[4] = 0x08;         // Packet 0x5a off, dBHz
1052
56
        (void)tsip_write1(session, buf, 5);
1053
1054
#ifdef __UNUSED__
1055
// #if 1
1056
        // Restart Self-Survey (0x8e-a6)
1057
        // which gives us 2,000 normal fixes, before going quiet again.
1058
        (void)tsip_write1(session, "\x8e\xa6\x00", 3);
1059
#endif // __UNUSED__
1060
56
    }
1061
124
}
1062
1063
/* send the next TSIPv1 query
1064
 * Return: void
1065
 */
1066
static void tsipv1_query(struct gps_device_t *session)
1067
963
{
1068
963
    char snd_buf[24];         // send buffer
1069
1070
    // advance to next queue item.
1071
963
    session->queue++;
1072
    // allow it to repeat every x1000 packets
1073
963
    session->queue &= 0x0ffff;
1074
1075
963
    if (0 != (session->queue % 4)) {
1076
        // once every 4 messages
1077
732
        return;
1078
732
    }
1079
231
    switch (session->queue / 4) {
1080
52
    case 1:
1081
        // x90-00, query protocol version
1082
52
        snd_buf[0] = 0x90;             // id
1083
52
        snd_buf[1] = 0x00;             // sub id
1084
52
        putbe16(snd_buf, 2, 2);        // length
1085
52
        snd_buf[4] = 0;                // mode: query
1086
52
        snd_buf[5] = tsip1_checksum(snd_buf, 5);   // checksum
1087
52
        (void)tsip_write1(session, snd_buf, 6);
1088
52
        break;
1089
32
    case 2:
1090
        // x90-01, query GNSS config version
1091
32
        snd_buf[0] = 0x90;             // id
1092
32
        snd_buf[1] = 0x01;             // sub id
1093
32
        putbe16(snd_buf, 2, 2);        // length
1094
32
        snd_buf[4] = 0;                // mode: query
1095
32
        snd_buf[5] = tsip1_checksum(snd_buf, 5);   // checksum
1096
32
        (void)tsip_write1(session, snd_buf, 6);
1097
32
        break;
1098
23
    case 3:
1099
        // x91-00, Port config
1100
23
        snd_buf[0] = 0x91;             // id
1101
23
        snd_buf[1] = 0x00;             // sub id
1102
23
        putbe16(snd_buf, 2, 3);        // length
1103
23
        snd_buf[4] = 0;                // mode: query
1104
23
        snd_buf[5] = 0;                // current port
1105
23
        snd_buf[6] = tsip1_checksum(snd_buf, 6);   // checksum
1106
23
        (void)tsip_write1(session, snd_buf, 7);
1107
23
        break;
1108
22
    case 4:
1109
        // x81-01, GNSS config
1110
22
        snd_buf[0] = 0x91;             // id
1111
22
        snd_buf[1] = 0x01;             // sub id
1112
22
        putbe16(snd_buf, 2, 2);        // length
1113
22
        snd_buf[4] = 0;                // mode: query
1114
22
        snd_buf[5] = tsip1_checksum(snd_buf, 5);   // checksum
1115
22
        (void)tsip_write1(session, snd_buf, 6);
1116
22
        break;
1117
16
    case 5:
1118
        // x91-03, query timing config
1119
16
        snd_buf[0] = 0x91;             // id
1120
16
        snd_buf[1] = 0x03;             // sub id
1121
16
        putbe16(snd_buf, 2, 2);        // length
1122
16
        snd_buf[4] = 0;                // mode: query
1123
16
        snd_buf[5] = tsip1_checksum(snd_buf, 5);   // checksum
1124
16
        (void)tsip_write1(session, snd_buf, 6);
1125
16
        break;
1126
13
    case 6:
1127
        // x91-04, self survey config
1128
13
        snd_buf[0] = 0x91;             // id
1129
13
        snd_buf[1] = 0x04;             // sub id
1130
13
        putbe16(snd_buf, 2, 2);        // length
1131
13
        snd_buf[4] = 0;                // mode: query
1132
13
        snd_buf[5] = tsip1_checksum(snd_buf, 5);   // checksum
1133
13
        (void)tsip_write1(session, snd_buf, 6);
1134
13
        break;
1135
11
    case 7:
1136
11
        if (session->context->passive) {
1137
            // x91-05, query current periodic messages
1138
1
            snd_buf[0] = 0x91;             // id
1139
1
            snd_buf[1] = 0x05;             // sub id
1140
1
            putbe16(snd_buf, 2, 3);        // length
1141
1
            snd_buf[4] = 0;                // mode: query
1142
1
            snd_buf[5] = 0xff;             // port: current port
1143
1
            snd_buf[6] = tsip1_checksum(snd_buf, 6);   // checksum
1144
1
            (void)tsip_write1(session, snd_buf, 7);
1145
10
        } else {
1146
            /* request periodic  messages, x91-05
1147
             * little harm at 115.2 kbps, this also responses as a query */
1148
10
            snd_buf[0] = 0x91;             // id
1149
10
            snd_buf[1] = 0x05;             // sub id
1150
10
            putbe16(snd_buf, 2, 19);       // length
1151
10
            snd_buf[4] = 0x01;             // mode: set
1152
10
            snd_buf[5] = 0xff;             // port: current port
1153
            // 0xaaaaa, everything preiodic
1154
10
            putbe32(snd_buf, 6, 0xaaaaa);
1155
10
            putbe32(snd_buf, 10, 0);       // reserved
1156
10
            putbe32(snd_buf, 14, 0);       // reserved
1157
10
            putbe32(snd_buf, 18, 0);       // reserved
1158
10
            snd_buf[22] = tsip1_checksum(snd_buf, 22);   // checksum
1159
10
            (void)tsip_write1(session, snd_buf, 23);
1160
10
        }
1161
11
        break;
1162
11
    case 8:
1163
        // x93-00, production info
1164
11
        snd_buf[0] = 0x93;             // id
1165
11
        snd_buf[1] = 0x00;             // sub id
1166
11
        putbe16(snd_buf, 2, 2);        // length
1167
11
        snd_buf[4] = 0;                // mode: query
1168
11
        snd_buf[5] = tsip1_checksum(snd_buf, 5);   // checksum
1169
11
        (void)tsip_write1(session, snd_buf, 6);
1170
11
        break;
1171
51
    default:
1172
        // nothing to do
1173
51
        break;
1174
231
    }
1175
231
}
1176
1177
/* tsipv1_svtype()
1178
 * convert TSIPv1 SV Type to satellite_t.gnssid and satellite_t.sigid
1179
 * PRN is already GNSS specific (1-99)
1180
 * return gnssid directly, sigid indirectly through pointer
1181
 *
1182
 * Return: gnssid
1183
 *         0xff on error
1184
 */
1185
static unsigned char tsipv1_svtype(unsigned svtype, unsigned char *sigid)
1186
0
{
1187
1188
0
    unsigned char gnssid;
1189
1190
0
    switch (svtype) {
1191
0
    case 1:  // GPS L1C
1192
0
       gnssid =  GNSSID_GPS;
1193
0
       *sigid = 0;
1194
0
       break;
1195
0
    case 2:  // GPS L2.  CL or CM?
1196
0
       gnssid =  GNSSID_GPS;
1197
0
       *sigid = 3;         // or, maybe 4
1198
0
       break;
1199
0
    case 3:  // GPS L5.  I or Q?
1200
0
       gnssid =  GNSSID_GPS;
1201
0
       *sigid = 6;         // or maybe 7
1202
0
       break;
1203
0
    case 5:  // GLONASS G1
1204
0
       gnssid =  GNSSID_GLO;
1205
0
       *sigid = 0;
1206
0
       break;
1207
0
    case 6:  // GLONASS G2
1208
0
       gnssid =  GNSSID_GLO;
1209
0
       *sigid = 2;
1210
0
       break;
1211
0
    case 9:  // SBAS, assume L1
1212
0
       gnssid =  GNSSID_SBAS;
1213
0
       *sigid = 0;
1214
0
       break;
1215
0
    case 13:  // Beidou B1, D1 or D2?
1216
0
       gnssid =  GNSSID_BD;
1217
0
       *sigid = 0;   // or maybe 1
1218
0
       break;
1219
0
    case 14:  // Beidou B2i
1220
0
       gnssid =  GNSSID_BD;
1221
0
       *sigid = 2;
1222
0
       break;
1223
0
    case 15:  // Beidou B2a
1224
0
       gnssid =  GNSSID_BD;
1225
0
       *sigid = 3;
1226
0
       break;
1227
0
    case 17:  // Galileo E1, C or B?
1228
0
       gnssid =  GNSSID_GAL;
1229
0
       *sigid = 0;    // or maybe 1
1230
0
       break;
1231
0
    case 18:  // Galileo E5a, aI or aQ?
1232
0
       gnssid =  GNSSID_GAL;
1233
0
       *sigid = 3;    // or maybe 4?
1234
0
       break;
1235
0
    case 19:  // Galileo E5b, bI or bQ?
1236
0
       gnssid =  GNSSID_GAL;
1237
0
       *sigid = 5;    // or maybe 6
1238
0
       break;
1239
0
    case 20:  // Galileo E6
1240
0
       gnssid =  GNSSID_GAL;
1241
0
       *sigid = 8;     // no idea
1242
0
       break;
1243
0
    case 22:  // QZSS L1
1244
0
       gnssid =  GNSSID_QZSS;
1245
0
       *sigid = 0;
1246
0
       break;
1247
0
    case 23:  // QZSS L2C
1248
0
       gnssid =  GNSSID_QZSS;
1249
0
       *sigid = 4;    // or maybe 5
1250
0
       break;
1251
0
    case 24:  // QZSS L5
1252
0
       gnssid =  GNSSID_QZSS;
1253
0
       *sigid = 8;     // no idea
1254
0
       break;
1255
0
    case 26:  // IRNSS L5
1256
0
       gnssid =  GNSSID_IRNSS;
1257
0
       *sigid = 8;     // no idea
1258
0
       break;
1259
0
    case 4:  // Reserved
1260
0
        FALLTHROUGH
1261
0
    case 7:  // Reserved
1262
0
        FALLTHROUGH
1263
0
    case 8:  // Reserved
1264
0
        FALLTHROUGH
1265
0
    case 10:  // Reservced
1266
0
        FALLTHROUGH
1267
0
    case 11:  // Reservced
1268
0
        FALLTHROUGH
1269
0
    case 12:  // Reservced
1270
0
        FALLTHROUGH
1271
0
    case 16:  // Reserved
1272
0
        FALLTHROUGH
1273
0
    case 21:  // Reserved
1274
0
        FALLTHROUGH
1275
0
    case 25:  // Reserved
1276
0
        FALLTHROUGH
1277
0
    default:
1278
0
        *sigid = 0xff;
1279
0
        return 0xff;
1280
0
    }
1281
0
    return gnssid;
1282
0
}
1283
1284
// decode Packet x13
1285
static gps_mask_t decode_x13(struct gps_device_t *session, const char *buf,
1286
                             int len)
1287
339
{
1288
339
    gps_mask_t mask = 0;
1289
339
    unsigned u1 = getub(buf, 0);         // Packet ID of non-parsable packet
1290
339
    unsigned u2 = 0;
1291
1292
339
    if (2 <= len) {
1293
216
        u2 = getub(buf, 1);     // Data byte 0 of non-parsable packet
1294
216
    }
1295
339
    GPSD_LOG(LOG_WARN, &session->context->errout,
1296
339
             "TSIP x13: Report Packet: request x%02x %02x "
1297
339
             "cannot be parsed\n",
1298
339
             u1, u2);
1299
    // ignore the rest of the bad data
1300
339
    if (0x8e == (int)u1 &&
1301
204
        0x23 == (int)u2) {
1302
        // no Compact Super Packet 0x8e-23
1303
103
        GPSD_LOG(LOG_WARN, &session->context->errout,
1304
103
                 "TSIP x8e-23: not available, use LFwEI (0x8f-20)\n");
1305
1306
        /* Request LFwEI Super Packet instead
1307
         * SMT 360 does not support 0x8e-20 either */
1308
103
        (void)tsip_write1(session, "\x8e\x20\x01", 3);
1309
103
    }
1310
339
    return mask;
1311
339
}
1312
// decode Superpacket x1c-81
1313
static gps_mask_t decode_x1c_81(struct gps_device_t *session, const char *buf,
1314
                                int len)
1315
133
{
1316
133
    gps_mask_t mask = 0;
1317
133
    char buf2[BUFSIZ];
1318
1319
    // byte 1, reserved
1320
133
    unsigned maj = getub(buf, 2);        // Major version
1321
133
    unsigned min = getub(buf, 3);        // Minor version
1322
133
    unsigned bnum = getub(buf, 4);       // Build number
1323
133
    unsigned bmon = getub(buf, 5);       // Build Month
1324
133
    unsigned bday = getub(buf, 6);       // Build Day
1325
133
    unsigned byr = getbeu16(buf, 7);     // Build Year
1326
133
    unsigned plen = getub(buf, 9);       // Length of product name
1327
1328
    // check for valid module name length
1329
133
    if (40 < plen) {
1330
102
        plen = 40;
1331
102
    }
1332
    // check for valid module name length, again
1333
133
    if ((unsigned)(len - 10) < plen) {
1334
98
        plen = len - 10;
1335
98
    }
1336
    // Product name in ASCII
1337
133
    memcpy(buf2, &buf[10], plen);
1338
133
    buf2[plen] = '\0';
1339
1340
133
    (void)snprintf(session->subtype, sizeof(session->subtype),
1341
133
                   "fw %u.%u %u %02u/%02u/%04u %.40s",
1342
133
                   min, maj, bnum, bmon, bday, byr, buf2);
1343
133
    GPSD_LOG(LOG_PROG, &session->context->errout,
1344
133
             "TSIP x1c-81: Firmware version: %s\n",
1345
133
             session->subtype);
1346
1347
133
    mask |= DEVICEID_SET;
1348
133
    if ('\0' == session->subtype1[0]) {
1349
        // request actual subtype1 from 0x1c-83
1350
4
        (void)tsip_write1(session, "\x1c\x03", 2);
1351
4
    }
1352
133
    return mask;
1353
133
}
1354
1355
// decode Superpacket x1c-83
1356
static gps_mask_t decode_x1c_83(struct gps_device_t *session, const char *buf,
1357
                                int len)
1358
293
{
1359
293
    gps_mask_t mask = 0;
1360
293
    char buf2[BUFSIZ];
1361
293
    unsigned long ul1 = getbeu32(buf, 1);  // Serial number
1362
293
    unsigned bday = getub(buf, 5);         // Build day
1363
293
    unsigned bmon = getub(buf, 6);         // Build month
1364
293
    unsigned byr = getbeu16(buf, 7);       // Build year
1365
293
    unsigned u4 = getub(buf, 9);           // Build hour
1366
293
    unsigned u5 = getub(buf, 12);          // Length of Hardware ID
1367
1368
    // Hardware Code
1369
293
    session->driver.tsip.hardware_code = getbeu16(buf, 10);
1370
1371
    // check for valid module name length
1372
    // copernicus ii is 27 long
1373
293
    if (40 < u5) {
1374
185
        u5 = 40;
1375
185
    }
1376
    // check for valid module name length, again
1377
293
    if ((unsigned)(len - 13) < u5) {
1378
209
        u5 = len - 13;
1379
209
    }
1380
293
    memcpy(buf2, &buf[13], u5);
1381
293
    buf2[u5] = '\0';
1382
1383
293
    (void)snprintf(session->gpsdata.dev.sernum,
1384
293
                   sizeof(session->gpsdata.dev.sernum),
1385
293
                   "%lx", ul1);
1386
293
    (void)snprintf(session->subtype1, sizeof(session->subtype1),
1387
293
                   "hw %02u/%02u/%04u %02u %04u %.40s",
1388
293
                   bmon, bday, byr, u4,
1389
293
                   session->driver.tsip.hardware_code,
1390
293
                   buf2);
1391
293
    GPSD_LOG(LOG_PROG, &session->context->errout,
1392
293
             "TSIP x1c-83: Hardware vers %s Sernum %s\n",
1393
293
             session->subtype1,
1394
293
             session->gpsdata.dev.sernum);
1395
1396
293
    mask |= DEVICEID_SET;
1397
293
    session->driver.tsip.subtype =
1398
293
        session->driver.tsip.hardware_code;
1399
1400
    // Detecting device by Hardware Code
1401
293
    switch (session->driver.tsip.hardware_code) {
1402
5
    case 3001:            // Acutime Gold
1403
5
        configuration_packets_acutime_gold(session);
1404
5
        break;
1405
1406
    // RES look-alikes
1407
28
    case 3002:            // TSIP_REST
1408
28
        FALLTHROUGH
1409
41
    case 3009:            // TSIP_RESSMT, Model 66266
1410
41
        FALLTHROUGH
1411
80
    case 3017:            // Resolution SMTx,  Model 99889
1412
80
        FALLTHROUGH
1413
100
    case 3023:            // RES SMT 360
1414
100
        FALLTHROUGH
1415
104
    case 3026:            // ICM SMT 360
1416
104
        FALLTHROUGH
1417
104
    case 3031:            // RES360 17x22
1418
104
        FALLTHROUGH
1419
124
    case 3100:            // TSIP_RES720
1420
124
        configuration_packets_res360(session);
1421
124
        break;
1422
1423
    // Unknown
1424
61
    default:
1425
61
        GPSD_LOG(LOG_WARN, &session->context->errout,
1426
61
                 "TSIP x1c-83: Unknown hw code %x\n",
1427
61
                 session->driver.tsip.hardware_code);
1428
61
        FALLTHROUGH
1429
69
    case 1001:            // Lassen iQ
1430
69
        FALLTHROUGH
1431
89
    case 1002:            // Copernicus
1432
89
        FALLTHROUGH
1433
105
    case 1003:            // Copernicus II
1434
105
        FALLTHROUGH
1435
139
    case 3007:            // Thunderbolt E
1436
139
        FALLTHROUGH
1437
164
    case 3032:            // Acutime 360
1438
164
        configuration_packets_generic(session);
1439
164
        break;
1440
293
    }
1441
293
    return mask;
1442
293
}
1443
1444
// decode Superpackets x1c-XX
1445
static gps_mask_t decode_x1c(struct gps_device_t *session, const char *buf,
1446
                             int len, int *pbad_len)
1447
587
{
1448
587
    gps_mask_t mask = 0;
1449
587
    int bad_len = 0;
1450
587
    unsigned u1 = getub(buf, 0);
1451
1452
    // decode by sub-code
1453
587
    switch (u1) {
1454
183
    case 0x81:
1455
        /* Firmware component version information (0x1c-81)
1456
         * polled by 0x1c-01
1457
         * Present in:
1458
         *   Copernicus II (2009)
1459
         */
1460
183
        if (10 > len) {
1461
50
            bad_len = 10;
1462
50
            break;
1463
50
        }
1464
133
        mask = decode_x1c_81(session, buf, len);
1465
133
        break;
1466
1467
348
    case 0x83:
1468
        /* Hardware component version information (0x1c-83)
1469
         * polled by 0x1c-03
1470
         * Present in:
1471
         *   Resolution SMTx
1472
         * Not Present in:
1473
         *   LassenSQ (2002)
1474
         *   Copernicus II (2009)
1475
         */
1476
348
        if (13 > len) {
1477
55
            bad_len = 13;
1478
55
            break;
1479
55
        }
1480
293
        mask = decode_x1c_83(session, buf, len);
1481
293
        break;
1482
56
    default:
1483
56
        GPSD_LOG(LOG_WARN, &session->context->errout,
1484
56
                 "TSIP x1c-%02x: Unhandled subpacket\n", u1);
1485
56
        break;
1486
587
    }
1487
587
    *pbad_len = bad_len;
1488
    // request x8f-42 Stored Production Parameters
1489
587
    (void)tsip_write1(session, "\x8e\x42", 2);
1490
587
    return mask;
1491
587
}
1492
1493
/* decode GPS Time, Packet x41
1494
 * This is "current" time, not the time of a fix */
1495
static gps_mask_t decode_x41(struct gps_device_t *session, const char *buf)
1496
64
{
1497
64
    gps_mask_t mask = 0;
1498
64
    timespec_t ts_tow;
1499
64
    char ts_buf[TIMESPEC_LEN];
1500
64
    double ftow = getbef32(buf, 0);                // gpstime
1501
64
    unsigned week = getbes16(buf, 4);              // week, yes, signed!
1502
64
    double f2 = getbef32(buf, 6);                  // leap seconds, fractional!
1503
1504
64
    if (0.0 <= ftow &&
1505
40
        10.0 < f2) {
1506
36
        session->context->leap_seconds = (int)round(f2);
1507
36
        session->context->valid |= LEAP_SECOND_VALID;
1508
36
        DTOTS(&ts_tow, ftow);
1509
36
        session->newdata.time =
1510
36
            gpsd_gpstime_resolv(session, week, ts_tow);
1511
36
        mask |= TIME_SET | NTPTIME_IS | CLEAR_IS;
1512
        /* Note: this is not the time of current fix. So we do a clear
1513
         * so the previous fix data does not get attached to this time.
1514
         * Do not use in tsip.last_tow */
1515
36
    }
1516
64
    GPSD_LOG(LOG_PROG, &session->context->errout,
1517
64
             "TSIP x41: GPS Time: tow %.3f week %u ls %.1f %s\n",
1518
64
             ftow, week, f2,
1519
64
             timespec_str(&session->newdata.time, ts_buf, sizeof(ts_buf)));
1520
64
    GPSD_LOG(LOG_IO, &session->context->errout,
1521
64
             "TSIP: %s",
1522
64
             ctime(&session->newdata.time.tv_sec));
1523
64
    return mask;
1524
64
}
1525
1526
// decode Packet x42
1527
static gps_mask_t decode_x42(struct gps_device_t *session, const char *buf)
1528
304
{
1529
304
    gps_mask_t mask = 0;
1530
304
    timespec_t ts_tow;
1531
304
    double ecefx = getbef32(buf, 0);                  // X
1532
304
    double ecefy = getbef32(buf, 4);                  // Y
1533
304
    double ecefz = getbef32(buf, 8);                  // Z
1534
304
    double ftow = getbef32(buf, 12);           // time-of-fix
1535
1536
304
    session->newdata.ecef.x = ecefx;
1537
304
    session->newdata.ecef.y = ecefy;
1538
304
    session->newdata.ecef.z = ecefz;
1539
304
    DTOTS(&ts_tow, ftow);
1540
304
    session->newdata.time = gpsd_gpstime_resolv(session,
1541
304
                                                session->context->gps_week,
1542
304
                                                ts_tow);
1543
304
    mask = ECEF_SET | TIME_SET | NTPTIME_IS;
1544
304
    if (!TS_EQ(&ts_tow, &session->driver.tsip.last_tow)) {
1545
257
        mask |= CLEAR_IS;
1546
257
        session->driver.tsip.last_tow = ts_tow;
1547
257
    }
1548
304
    GPSD_LOG(LOG_PROG, &session->context->errout,
1549
304
             "TSIP x42: SP-XYZ: %f %f %f ftow %f\n",
1550
304
             session->newdata.ecef.x,
1551
304
             session->newdata.ecef.y,
1552
304
             session->newdata.ecef.z,
1553
304
             ftow);
1554
304
    return mask;
1555
304
}
1556
1557
// Decode Protocol Version: x43
1558
static gps_mask_t decode_x43(struct gps_device_t *session, const char *buf)
1559
69
{
1560
69
    gps_mask_t mask = 0;
1561
69
    timespec_t ts_tow;
1562
69
    double vx = getbef32(buf, 0);               // X velocity, m/s
1563
69
    double vy = getbef32(buf, 4);               // Y velocity, m/s
1564
69
    double vz = getbef32(buf, 8);               // Z velocity, m/s
1565
69
    double bias_rate = getbef32(buf, 12);       // bias rate, m/s
1566
69
    double ftow = getbef32(buf, 16);            // time-of-fix
1567
1568
69
    session->newdata.ecef.vx = vx;
1569
69
    session->newdata.ecef.vy = vy;
1570
69
    session->newdata.ecef.vz = vz;
1571
1572
    // short circuit to gpsdata. Convert m/s to ns/s
1573
69
    session->gpsdata.fix.clockdrift = 1e9 * bias_rate / CLIGHT;
1574
1575
69
    DTOTS(&ts_tow, ftow);
1576
69
    session->newdata.time = gpsd_gpstime_resolv(session,
1577
69
                                                session->context->gps_week,
1578
69
                                                ts_tow);
1579
69
    mask = VECEF_SET | TIME_SET | NTPTIME_IS;
1580
69
    if (!TS_EQ(&ts_tow, &session->driver.tsip.last_tow)) {
1581
51
        mask |= CLEAR_IS;
1582
51
        session->driver.tsip.last_tow = ts_tow;
1583
51
    }
1584
69
    GPSD_LOG(LOG_PROG, &session->context->errout,
1585
69
             "TSIP x43: Vel XYZ: %f %f %f %f ftow %f\n",
1586
69
             session->newdata.ecef.vx,
1587
69
             session->newdata.ecef.vy,
1588
69
             session->newdata.ecef.vz,
1589
69
             bias_rate, ftow);
1590
69
    return mask;
1591
69
}
1592
1593
// Decode x45
1594
static gps_mask_t decode_x45(struct gps_device_t *session, const char *buf)
1595
4
{
1596
4
    gps_mask_t mask = 0;
1597
4
    unsigned nmaj = getub(buf, 0);
1598
4
    unsigned nmin = getub(buf, 1);
1599
4
    unsigned nmon = getub(buf, 2);
1600
4
    unsigned nday = getub(buf, 3);
1601
4
    unsigned nyr = getub(buf, 4) + 1900;
1602
4
    unsigned fmaj = getub(buf, 5);
1603
4
    unsigned fmin = getub(buf, 6);
1604
4
    unsigned fmon = getub(buf, 7);
1605
4
    unsigned fday = getub(buf, 8);
1606
4
    unsigned fyr = getub(buf, 9) + 2000;
1607
1608
    /* ACE calls these "NAV processor firmware" and
1609
     * "SIG processor firmware".
1610
     * RES SMT 360 calls these "application" and "GPS core".
1611
     */
1612
4
    (void)snprintf(session->subtype, sizeof(session->subtype),
1613
4
                   "sw %u.%u %02u/%02u/%04u hw %u.%u %02u/%02u/%04u",
1614
4
                   nmaj, nmin, nmon, nday, nyr,
1615
4
                   fmaj, fmin, fmon, fday, fyr);
1616
4
    GPSD_LOG(LOG_PROG, &session->context->errout,
1617
4
             "TSIP x45: Software version: %s\n", session->subtype);
1618
4
    mask |= DEVICEID_SET;
1619
1620
    // request I/O Options (0x55)
1621
4
    (void)tsip_write1(session, "\x35", 1);
1622
1623
    /* request actual subtype using x1c-01, returns x1c-81
1624
     * which in turn requests 0x1c-83
1625
     * then requests x8f-42 */
1626
4
    (void)tsip_write1(session, "\x1c\x01", 2);
1627
4
    return mask;
1628
4
}
1629
1630
// Decode Health of Receiver, x46
1631
static gps_mask_t decode_x46(struct gps_device_t *session, const char *buf)
1632
938
{
1633
938
    gps_mask_t mask = 0;
1634
938
    char buf2[80];
1635
    // Status code, see vgnss_decode_status
1636
938
    unsigned status = getub(buf, 0);
1637
938
    unsigned ec = getub(buf, 1);      // error codes
1638
1639
938
    switch (status) {
1640
72
    case 0:         //  "Doing Fixes"
1641
        // could be 2D or 3D.  So check the last setting.
1642
72
        if (MODE_2D >= session->oldfix.mode) {
1643
68
            session->newdata.mode = MODE_2D;  // At least 2D
1644
68
        } else {
1645
4
            session->newdata.mode = MODE_3D;
1646
4
        }
1647
72
        break;
1648
66
    case 9:          // "1 usable sat"
1649
66
        session->newdata.mode = MODE_2D;
1650
66
        break;
1651
140
    case 10:         // "2 usable sats"
1652
140
        session->newdata.mode = MODE_2D;
1653
140
        break;
1654
97
    case 11:         // "3 usable sats"
1655
97
        session->newdata.mode = MODE_2D;
1656
97
        break;
1657
67
    case 1:          // "No GPS time"
1658
67
        FALLTHROUGH
1659
139
    case 2:          // "Needs Init"
1660
139
        FALLTHROUGH
1661
220
    case 3:          // "PDOP too high"
1662
220
        FALLTHROUGH
1663
287
    case 8:          // "0 usable sats"
1664
287
        FALLTHROUGH
1665
353
    case 12:         // "chosen sat unusable"
1666
353
        FALLTHROUGH
1667
483
    case 16:         // "TRAIM rejected"
1668
483
        session->newdata.mode = MODE_NO_FIX;
1669
483
        break;
1670
0
    case 0xbb:       // "GPS Time Fix (OD mode)"
1671
        // Always on after survey, so no info here.
1672
0
        break;
1673
938
    }
1674
938
    if (MODE_NOT_SEEN != session->newdata.mode) {
1675
858
        mask |= MODE_SET;
1676
858
    }
1677
1678
    /* Error codes, model dependent
1679
     * 0x01 -- no battery, always set on RES SMT 360
1680
     * 0x10 -- antenna is open
1681
     * 0x30 -- antenna is shorted
1682
     */
1683
938
    switch (ec & 0x30) {
1684
522
    case 0x10:
1685
522
        session->newdata.ant_stat = ANT_OPEN;
1686
522
        break;
1687
12
    case 0x30:
1688
12
        session->newdata.ant_stat = ANT_SHORT;
1689
12
        break;
1690
404
    default:
1691
404
        session->newdata.ant_stat = ANT_OK;
1692
404
        break;
1693
938
    }
1694
1695
938
    if (STATUS_UNK != session->newdata.status) {
1696
0
        mask |= STATUS_SET;
1697
0
    }
1698
938
    GPSD_LOG(LOG_PROG, &session->context->errout,
1699
938
             "TSIP x46: Receiver Health: mode %d status %d  gds:x%x "
1700
938
             "ec:x%x\n",
1701
938
            session->newdata.mode,
1702
938
            session->newdata.status,
1703
938
            status, ec);
1704
938
    GPSD_LOG(LOG_IO, &session->context->errout,
1705
938
             "TSIP: gds:%s ec:%s\n",
1706
938
             val2str(status, vgnss_decode_status),
1707
938
             flags2str(ec, verr_codes, buf2, sizeof(buf2)));
1708
938
    return mask;
1709
938
}
1710
1711
// Decode x47
1712
static gps_mask_t decode_x47(struct gps_device_t *session, const char *buf,
1713
                             int len, int *pbad_len)
1714
227
{
1715
227
    gps_mask_t mask = 0;
1716
227
    char buf2[BUFSIZ];
1717
227
    int i;
1718
1719
    // satellite count, RES SMT 360 doc says 12 max
1720
227
    int count = getub(buf, 0);
1721
1722
227
    if (count < TSIP_CHANNELS) {
1723
108
        GPSD_LOG(LOG_WARN, &session->context->errout,
1724
108
                 "TSIP x47: Too many satellites %d\n", count);
1725
108
        return 0;
1726
108
    }
1727
1728
    // Status code, see vgnss_decode_status
1729
119
    gpsd_zero_satellites(&session->gpsdata);
1730
1731
    // packet too short?
1732
119
    if ((5 * count + 1) > len) {
1733
111
        *pbad_len = 5 * count + 1;
1734
111
        return mask;
1735
111
    }
1736
8
    *pbad_len = 0;
1737
8
    buf2[0] = '\0';
1738
757
    for (i = 0; i < count; i++) {
1739
749
        unsigned j;
1740
749
        int PRN = getub(buf, 5 * i + 1);
1741
749
        double snr = getbef32(buf, 5 * i + 2);
1742
1743
749
        if (0 > snr) {
1744
131
            snr = 0.0;
1745
131
        }
1746
36.0k
        for (j = 0; j < TSIP_CHANNELS; j++) {
1747
35.4k
            if (session->gpsdata.skyview[j].PRN == PRN) {
1748
198
                session->gpsdata.skyview[j].ss = snr;
1749
198
                break;
1750
198
            }
1751
35.4k
        }
1752
749
        str_appendf(buf2, sizeof(buf2), " %u=%.1f", PRN, snr);
1753
749
    }
1754
8
    GPSD_LOG(LOG_PROG, &session->context->errout,
1755
8
             "TSIP x47: Signal Levels: (%d):%s\n", count, buf2);
1756
8
    mask |= SATELLITE_SET;
1757
8
    return mask;
1758
119
}
1759
1760
// Decode x4a
1761
static gps_mask_t decode_x4a(struct gps_device_t *session, const char *buf)
1762
177
{
1763
177
    gps_mask_t mask = 0;
1764
177
    timespec_t ts_tow;
1765
177
    char ts_buf[TIMESPEC_LEN];
1766
177
    double lat = getbef32(buf, 0) * RAD_2_DEG;   // lat
1767
177
    double lon = getbef32(buf, 4) * RAD_2_DEG;   // lon
1768
177
    double alt = getbef32(buf, 8);               // alt
1769
177
    double clock_bias = getbef32(buf, 12);       // clock bias, m/s
1770
177
    double ftow = getbef32(buf, 16);             // time-of-fix
1771
1772
177
    session->newdata.latitude = lat;
1773
177
    session->newdata.longitude = lon;
1774
    // depending on GPS config, could be either WGS84 or MSL
1775
177
    if (0 == session->driver.tsip.alt_is_msl) {
1776
145
        session->newdata.altHAE = alt;
1777
145
    } else {
1778
32
        session->newdata.altMSL = alt;
1779
32
    }
1780
    // short circuit to gpsdata. COnvert m/s to ns
1781
177
    session->gpsdata.fix.clockbias = 1e9 * clock_bias / CLIGHT;
1782
1783
177
    if (0 != (session->context->valid & GPS_TIME_VALID)) {
1784
143
        DTOTS(&ts_tow, ftow);
1785
143
        session->newdata.time =
1786
143
            gpsd_gpstime_resolv(session, session->context->gps_week,
1787
143
                                ts_tow);
1788
143
        mask |= TIME_SET | NTPTIME_IS;
1789
143
        if (!TS_EQ(&ts_tow, &session->driver.tsip.last_tow)) {
1790
98
            mask |= CLEAR_IS;
1791
98
            session->driver.tsip.last_tow = ts_tow;
1792
98
        }
1793
143
    }
1794
    // this seems to be often first in cycle
1795
    // REPORT_IS here breaks reports in read-only mode
1796
177
    mask |= LATLON_SET | ALTITUDE_SET;
1797
177
    GPSD_LOG(LOG_PROG, &session->context->errout,
1798
177
             "TSIP x4a: SP-LLA: time=%s lat=%.2f lon=%.2f "
1799
177
             "alt=%.2f cbias %.2f\n",
1800
177
             timespec_str(&session->newdata.time, ts_buf, sizeof(ts_buf)),
1801
177
             session->newdata.latitude,
1802
177
             session->newdata.longitude, alt, clock_bias);
1803
177
    return mask;
1804
177
}
1805
1806
// Decode x4b
1807
static gps_mask_t decode_x4b(struct gps_device_t *session, const char *buf)
1808
507
{
1809
507
    gps_mask_t mask = 0;
1810
507
    char buf2[80];
1811
507
    char buf3[80];
1812
507
    unsigned u1 = getub(buf, 0);  // Machine ID
1813
    /* Status 1
1814
     * bit 1 -- No RTC at power up
1815
     * bit 3 -- almanac not complete and current */
1816
507
    unsigned u2 = getub(buf, 1);     // status 1
1817
507
    unsigned u3 = getub(buf, 2);     // Status 2/Superpacket Support
1818
1819
507
    session->driver.tsip.machine_id = u1;  // Machine ID
1820
1821
507
    if ('\0' == session->subtype[0]) {
1822
130
        const char *name;
1823
        // better than nothing
1824
130
        switch (session->driver.tsip.machine_id) {
1825
23
        case 1:
1826
            // should use better name from superpacket
1827
23
            name = " SMT 360";
1828
            /* request actual subtype from 0x1c-81
1829
             * which in turn requests 0x1c-83 */
1830
23
            (void)tsip_write1(session, "\x1c\x01", 2);
1831
23
            break;
1832
18
        case 0x32:
1833
18
            name = " Acutime 360";
1834
18
            break;
1835
18
        case 0x5a:
1836
18
            name = " Lassen iQ";
1837
            /* request actual subtype from 0x1c-81
1838
             * which in turn requests 0x1c-83.
1839
             * Only later firmware Lassen iQ supports this */
1840
18
            (void)tsip_write1(session, "\x1c\x01", 2);
1841
18
            break;
1842
18
        case 0x61:
1843
18
            name = " Acutime 2000";
1844
18
            break;
1845
17
        case 0x62:
1846
17
            name = " ACE UTC";
1847
17
            break;
1848
18
        case 0x96:
1849
            // Also Copernicus II
1850
18
            name = " Copernicus, Thunderbolt E";
1851
            /* so request actual subtype from 0x1c-81
1852
             * which in turn requests 0x1c-83 */
1853
18
            (void)tsip_write1(session, "\x1c\x01", 2);
1854
18
            break;
1855
0
        case 0:
1856
            // Resolution SMTx
1857
0
            FALLTHROUGH
1858
18
        default:
1859
18
             name = "";
1860
130
        }
1861
130
        (void)snprintf(session->subtype, sizeof(session->subtype),
1862
130
                       "Machine ID x%x(%s)",
1863
130
                       session->driver.tsip.machine_id, name);
1864
130
    }
1865
507
    GPSD_LOG(LOG_PROG, &session->context->errout,
1866
507
             "TSIP x4b: Machine ID: %02x %02x %02x\n",
1867
507
             session->driver.tsip.machine_id,
1868
507
             u2, u3);
1869
507
    GPSD_LOG(LOG_IO, &session->context->errout,
1870
507
             "TSIP: stat1:%s stat2:%s\n",
1871
507
             flags2str(u2, vstat1, buf2, sizeof(buf2)),
1872
507
             flags2str(u3, vstat2, buf3, sizeof(buf3)));
1873
1874
507
    if (u3 != session->driver.tsip.superpkt) {
1875
339
        session->driver.tsip.superpkt = u3;
1876
339
        GPSD_LOG(LOG_PROG, &session->context->errout,
1877
339
                 "TSIP: Switching to Super Packet mode %d\n", u3);
1878
339
        switch (u3){
1879
205
        default:
1880
205
            FALLTHROUGH
1881
207
        case 0:
1882
            // old Trimble, no superpackets
1883
207
            break;
1884
87
        case 1:
1885
            // 1 == superpacket is acutime 360, support 0x8f-20
1886
1887
            /* set I/O Options for Super Packet output
1888
             * Position: 8F20, ECEF, DP */
1889
87
            buf2[0] = 0x35;
1890
87
            buf2[1] = IO1_8F20|IO1_DP|IO1_ECEF;
1891
87
            buf2[2] = 0x00;          // Velocity: none (via SP)
1892
87
            buf2[3] = 0x00;          // Time: GPS
1893
87
            buf2[4] = IO4_DBHZ;      // Aux: dBHz
1894
87
            (void)tsip_write1(session, buf2, 5);
1895
87
            break;
1896
45
        case 2:
1897
            /* 2 == SMT 360, or Resolution SMTx
1898
             * no 0x8f-20, or x8f-23.
1899
             * request x8f-a5 */
1900
45
            (void)tsip_write1(session, "\x8e\xa5", 2);
1901
45
            break;
1902
339
        }
1903
339
    }
1904
1905
507
    return mask;
1906
507
}
1907
1908
// Decode x4c
1909
static gps_mask_t decode_x4c(struct gps_device_t *session, const char *buf)
1910
5
{
1911
5
    gps_mask_t mask = 0;
1912
5
    unsigned u1 = getub(buf, 0);                  // Dynamics Code
1913
5
    double f1 = getbef32(buf, 1) * RAD_2_DEG;     // Elevation Mask
1914
5
    double f2 = getbef32(buf, 5);                 // Signal Level Mask
1915
5
    double f3 = getbef32(buf, 9);                 // PDOP Mask
1916
5
    double f4 = getbef32(buf, 13);                // PDOP Switch
1917
1918
5
    GPSD_LOG(LOG_PROG, &session->context->errout,
1919
5
             "TSIP x4c: OP: Dyn x%02x El %f Sig %f PDOP %f %f\n",
1920
5
             u1, f1, f2, f3, f4);
1921
5
    GPSD_LOG(LOG_IO, &session->context->errout,
1922
5
             "TSIP: Dynamics:%s\n",
1923
5
             val2str(u1, vx4c_dyncode));
1924
5
    return mask;
1925
5
}
1926
1927
/* Decode  Bias and Bias Rate Report (0x54)
1928
 * Present in:
1929
 *   pre-2000 models
1930
 *   Acutime 360
1931
 *   ICM SMT 360  (undocumented)
1932
 *   RES SMT 360  (undocumented)
1933
 * Not Present in:
1934
 *   Copernicus II (2009)
1935
 *   Resolution SMTx
1936
 */
1937
static gps_mask_t decode_x54(struct gps_device_t *session, const char *buf)
1938
191
{
1939
191
    gps_mask_t mask = 0;
1940
191
    timespec_t ts_tow;
1941
191
    double clock_bias = getbef32(buf, 0);         // clock Bias, m
1942
191
    double clock_rate = getbef32(buf, 4);         // clock Bias rate, m/s
1943
191
    double ftow = getbef32(buf, 8);               // tow
1944
1945
191
    DTOTS(&ts_tow, ftow);
1946
191
    session->newdata.time =
1947
191
        gpsd_gpstime_resolv(session, session->context->gps_week, ts_tow);
1948
191
    if (!TS_EQ(&ts_tow, &session->driver.tsip.last_tow)) {
1949
178
        mask |= CLEAR_IS;
1950
178
        session->driver.tsip.last_tow = ts_tow;
1951
178
    }
1952
    // short circuit to gpsdata. Convert m to ns
1953
191
    session->gpsdata.fix.clockbias = 1e9 * clock_bias / CLIGHT;
1954
191
    session->gpsdata.fix.clockdrift = 1e9 * clock_rate / CLIGHT;
1955
1956
191
    mask |= TIME_SET | NTPTIME_IS;
1957
1958
191
    GPSD_LOG(LOG_PROG, &session->context->errout,
1959
191
            "TSIP x54: BBRR: Bias %f brate %f tow %f\n",
1960
191
            clock_bias, clock_rate, ftow);
1961
191
    return mask;
1962
191
}
1963
1964
// Decode Protocol Version: x55
1965
static gps_mask_t decode_x55(struct gps_device_t *session, const char *buf,
1966
                             time_t now)
1967
242
{
1968
242
    gps_mask_t mask = 0;
1969
242
    char buf2[80];
1970
242
    char buf3[80];
1971
242
    char buf4[80];
1972
242
    char buf5[80];
1973
1974
242
    unsigned u1 = getub(buf, 0);     // Position
1975
242
    unsigned u2 = getub(buf, 1);     // Velocity
1976
    /* Timing
1977
     * bit 0 - reserved use 0x8e-a2 ?
1978
     */
1979
242
    unsigned u3 = getub(buf, 2);
1980
    /* Aux
1981
     * bit 0 - packet 0x5a (raw data)
1982
     * bit 3 -- Output dbHz
1983
     */
1984
242
    unsigned u4 = getub(buf, 3);
1985
1986
    // decode HAE/MSL from Position byte
1987
242
    if (IO1_MSL == (IO1_MSL & u1)) {
1988
110
        session->driver.tsip.alt_is_msl = 1;
1989
132
    } else {
1990
132
        session->driver.tsip.alt_is_msl = 0;
1991
132
    }
1992
1993
242
    GPSD_LOG(LOG_PROG, &session->context->errout,
1994
242
             "TSIP x55: IO Options: %02x %02x %02x %02x\n",
1995
242
             u1, u2, u3, u4);
1996
242
    GPSD_LOG(LOG_IO, &session->context->errout,
1997
242
             "TSIPv1: pos:%s vel:%s timing:%s aux:%s\n",
1998
242
             flags2str(u1, vx55_pos, buf2, sizeof(buf2)),
1999
242
             flags2str(u2, vx55_vel, buf3, sizeof(buf3)),
2000
242
             flags2str(u3, vx55_timing, buf4, sizeof(buf4)),
2001
242
             flags2str(u4, vx55_aux, buf5, sizeof(buf5)));
2002
242
    if ((u1 & 0x20) != (uint8_t) 0) {
2003
        /* Try to get Super Packets
2004
         * Turn off 0x8f-20 LFwEI Super Packet */
2005
108
        (void)tsip_write1(session, "\x8e\x20\x00", 3);
2006
2007
        // Turn on Compact Super Packet 0x8f-23
2008
108
        (void)tsip_write1(session, "\x8e\x23\x01", 3);
2009
108
        session->driver.tsip.req_compact = now;
2010
108
    }
2011
242
    return mask;
2012
242
}
2013
2014
// Decode Velocity Fix, Easst-North-Up, packet x56
2015
static gps_mask_t decode_x56(struct gps_device_t *session, const char *buf)
2016
66
{
2017
66
    gps_mask_t mask = 0;
2018
66
    timespec_t ts_tow;
2019
2020
66
    float f1 = getbef32(buf, 0);        // East velocity
2021
66
    float f2 = getbef32(buf, 4);        // North velocity
2022
66
    float f3 = getbef32(buf, 8);        // Up velocity
2023
66
    float cbias = getbef32(buf, 12);    // clock bias rate, m/s
2024
66
    float ftow = getbef32(buf, 16);     // time-of-fix
2025
2026
    // Could be GPS, or UTC...
2027
66
    DTOTS(&ts_tow, ftow);
2028
66
    session->newdata.time = gpsd_gpstime_resolv(session,
2029
66
                                                session->context->gps_week,
2030
66
                                                ts_tow);
2031
66
    session->newdata.NED.velN = f2;
2032
66
    session->newdata.NED.velE = f1;
2033
66
    session->newdata.NED.velD = -f3;
2034
    // short circuit to gpsdata. Convert m to ns
2035
66
    session->gpsdata.fix.clockdrift = 1e9 * cbias / CLIGHT;
2036
2037
66
    mask |= VNED_SET | TIME_SET | NTPTIME_IS;
2038
66
    if (!TS_EQ(&ts_tow, &session->driver.tsip.last_tow)) {
2039
61
        mask |= CLEAR_IS;
2040
61
        session->driver.tsip.last_tow = ts_tow;
2041
61
    }
2042
66
    GPSD_LOG(LOG_PROG, &session->context->errout,
2043
66
             "TSIP x56: Vel ENU: %f %f %f cbias %f ftow %f\n",
2044
66
             f1, f2, f3, cbias, ftow);
2045
66
    GPSD_LOG(LOG_IO, &session->context->errout,
2046
66
             "TSIP: %s",
2047
66
             ctime(&session->newdata.time.tv_sec));
2048
66
    return mask;
2049
66
}
2050
2051
// Decode x57
2052
static gps_mask_t decode_x57(struct gps_device_t *session, const char *buf)
2053
470
{
2054
470
    gps_mask_t mask = 0;
2055
470
    timespec_t ts_tow;
2056
470
    char buf2[80];
2057
470
    unsigned u1 = getub(buf, 0);                     // Source of information
2058
470
    unsigned u2 = getub(buf, 1);                     // Mfg. diagnostic
2059
470
    double ftow = getbef32(buf, 2);                  // gps_time
2060
470
    unsigned week = getbeu16(buf, 6);                // tsip.gps_week
2061
2062
470
    if (0x01 == u1) {
2063
        // good current fix
2064
397
        DTOTS(&ts_tow, ftow);
2065
397
        (void)gpsd_gpstime_resolv(session, week, ts_tow);
2066
397
        mask |= TIME_SET | NTPTIME_IS;
2067
397
        if (!TS_EQ(&ts_tow, &session->driver.tsip.last_tow)) {
2068
323
            mask |= CLEAR_IS;
2069
323
            session->driver.tsip.last_tow = ts_tow;
2070
323
        }
2071
397
    }
2072
470
    GPSD_LOG(LOG_PROG, &session->context->errout,
2073
470
             "TSIP x57: Fix info: %02x %02x %u %f\n",
2074
470
             u1, u2, week, ftow);
2075
470
    GPSD_LOG(LOG_IO, &session->context->errout,
2076
470
             "TSIP: info:%s fmode:%s\n",
2077
470
             flags2str(u1, vx57_info, buf2, sizeof(buf2)),
2078
470
             val2str(u1, vx57_fmode));
2079
470
    return mask;
2080
470
}
2081
2082
// Decode x5a
2083
static gps_mask_t decode_x5a(struct gps_device_t *session, const char *buf)
2084
17
{
2085
17
    gps_mask_t mask = 0;
2086
    // Useless without the pseudorange...
2087
17
    unsigned u1 = getub(buf, 0);             // PRN 1-237
2088
17
    float f1 = getbef32(buf, 1);             // sample length
2089
17
    float f2 = getbef32(buf, 5);             // Signal Level, dbHz
2090
17
    float f3 = getbef32(buf, 9);             // Code phase, 1/16th chip
2091
17
    float f4 = getbef32(buf, 13);            // Doppler, Hz @ L1
2092
17
    double d1 = getbed64(buf, 17);           // Time of Measurement
2093
2094
17
    GPSD_LOG(LOG_PROG, &session->context->errout,
2095
17
             "TSIP x5a: Raw Measurement Data: PRN %d len %f SNR %f chip %f "
2096
17
             "doppler %f tom %f\n",
2097
17
             u1, f1, f2, f3, f4, d1);
2098
17
    return mask;
2099
17
}
2100
2101
// Decode Satellite Tracking Status, packet x5c
2102
static gps_mask_t decode_x5c(struct gps_device_t *session, const char *buf)
2103
174
{
2104
174
    gps_mask_t mask = 0;
2105
174
    timespec_t ts_tow;
2106
174
    int i;
2107
    // Useless without the pseudorange...
2108
174
    int PRN = getub(buf, 0);                     // PRN 1-32
2109
    // slot unused in Lassen IQ
2110
174
    unsigned u2 = getub(buf, 1);                 // slot:chan
2111
174
    unsigned acq = getub(buf, 2);                // Acquisition flag
2112
174
    unsigned eflag = getub(buf, 3);              // Ephemeris flag
2113
174
    double snr = getbef32(buf, 4);               // Signal level
2114
    // time of skyview, not current time, nor time of fix
2115
174
    double ftow = getbef32(buf, 8);
2116
2117
174
    double el = getbef32(buf, 12) * RAD_2_DEG;   // Elevation
2118
174
    double az = getbef32(buf, 16) * RAD_2_DEG;   // Azimuth
2119
2120
    // Old Measurement flag, unused in Lassen IQ
2121
174
    unsigned omf = getub(buf, 20);
2122
2123
174
    DTOTS(&session->gpsdata.skyview_time, ftow);
2124
    /* Channel number, bits 0-2 reserved/unused as of 1999.
2125
     * Seems to always start series at zero and increment to last one.
2126
     * No way to know how many there will be.
2127
     * Save current channel to check for last 0x5c message
2128
     */
2129
174
    i = (int)(u2 >> 3);     // channel number, starting at 0
2130
174
    if (0 == i) {
2131
        // start of new cycle, save last count
2132
142
        session->gpsdata.satellites_visible =
2133
142
            session->driver.tsip.last_chan_seen;
2134
142
    } else if (i > TSIP_CHANNELS) {
2135
0
        GPSD_LOG(LOG_WARN, &session->context->errout,
2136
0
                 "TSIP x5c: Satellite Tracking Status: Too many chans %d\n", i);
2137
0
        return 0;
2138
32
    } else if (0 == PRN ||
2139
32
               32 < PRN) {
2140
21
        GPSD_LOG(LOG_WARN, &session->context->errout,
2141
21
                "TSIPv1 x5c: invalid prn %d\n", PRN);
2142
21
        return 0;
2143
21
    }
2144
153
    session->driver.tsip.last_chan_seen = i;
2145
2146
153
    session->gpsdata.skyview[i].PRN = PRN;
2147
153
    session->gpsdata.skyview[i].svid = PRN;
2148
153
    session->gpsdata.skyview[i].gnssid = GNSSID_GPS;
2149
153
    session->gpsdata.skyview[i].ss = snr;
2150
153
    session->gpsdata.skyview[i].elevation = el;
2151
153
    session->gpsdata.skyview[i].azimuth = az;
2152
153
    session->gpsdata.skyview[i].gnssid = tsip_gnssid(0, PRN,
2153
153
        &session->gpsdata.skyview[i].svid);
2154
153
    if (2 == (2 & eflag)) {
2155
92
        session->gpsdata.skyview[i].health = SAT_HEALTH_OK;
2156
92
    } else if (1 == eflag) {
2157
3
        session->gpsdata.skyview[i].health = SAT_HEALTH_BAD;
2158
3
    } // else, unknown
2159
2160
153
    if (0x10 == (0x10 & eflag)) {
2161
100
        session->gpsdata.skyview[i].used = true;
2162
100
        if (51 == eflag) {
2163
0
            session->newdata.status = STATUS_DGPS;
2164
0
            mask |= STATUS_SET;
2165
0
        }
2166
100
    } else {
2167
53
        session->gpsdata.skyview[i].used = false;
2168
53
    }
2169
    /* when polled by 0x3c, all the skyview times will be the same
2170
     * in one cluster */
2171
153
    if (0.0 < ftow) {
2172
84
        DTOTS(&ts_tow, ftow);
2173
84
        session->gpsdata.skyview_time =
2174
84
            gpsd_gpstime_resolv(session, session->context->gps_week,
2175
84
                                ts_tow);
2176
        /* do not save in session->driver.tsip.last_tow
2177
         * as this is skyview time, not fix time */
2178
84
    }
2179
153
    if ((i + 1) >= session->gpsdata.satellites_visible) {
2180
        /* Last of the series?
2181
         * This will cause extra SKY if this set has more
2182
         * sats than the last set */
2183
146
        mask |= SATELLITE_SET;
2184
146
        session->gpsdata.satellites_visible = i + 1;
2185
146
    }
2186
153
    if (MAXCHANNELS < session->gpsdata.satellites_visible) {
2187
0
        GPSD_LOG(LOG_WARN, &session->context->errout,
2188
0
                "TSIP x5c: too many satellites %d\n",
2189
0
                 session->gpsdata.satellites_visible);
2190
0
        session->gpsdata.satellites_visible = MAXCHANNELS;
2191
0
    }
2192
    /* If this series has fewer than last series there will
2193
     * be no SKY, unless the cycle ender pushes the SKY */
2194
153
    GPSD_LOG(LOG_PROG, &session->context->errout,
2195
153
             "TSIP x5c: Satellite Tracking Status: Ch %2d PRN %3d "
2196
153
             "es %d Acq %d Eph %2d SNR %4.1f LMT %.04f El %.1f Az %.1f "
2197
153
             "omf %u hlth %u\n",
2198
153
             i, PRN, u2 & 7, acq, eflag, snr, ftow, el, az, omf,
2199
153
            session->gpsdata.skyview[i].health);
2200
153
    GPSD_LOG(LOG_IO, &session->context->errout,
2201
153
             "TSIP: acq:%s eflag:%s\n",
2202
153
             val2str(acq, vx5c_acq),
2203
153
             val2str(eflag, vx5c_eflag));
2204
2205
153
    return mask;
2206
174
}
2207
2208
// Decode x5d
2209
static gps_mask_t decode_x5d(struct gps_device_t *session, const char *buf)
2210
290
{
2211
290
    gps_mask_t mask = 0;
2212
290
    timespec_t ts_tow;
2213
290
    char buf2[BUFSIZ];
2214
290
    unsigned char u1 = getub(buf, 0);           // PRN
2215
290
    int i = getub(buf, 1);                      // chan
2216
290
    unsigned u3 = getub(buf, 2);                // Acquisition flag
2217
290
    unsigned u4 = getub(buf, 3);                // used?
2218
290
    double f1 = getbef32(buf, 4);               // SNR
2219
    // This can be one second behind the TPV on RES SMT 360
2220
290
    double ftow = getbef32(buf, 8);             // time of Last measurement
2221
290
    double d1 = getbef32(buf, 12) * RAD_2_DEG;  // Elevation
2222
290
    double d2 = getbef32(buf, 16) * RAD_2_DEG;  // Azimuth
2223
290
    unsigned u5 = getub(buf, 20);               // old measurement flag
2224
290
    unsigned u6 = getub(buf, 21);               // integer msec flag
2225
290
    unsigned u7 = getub(buf, 22);               // bad data flag
2226
290
    unsigned u8 = getub(buf, 23);               // data collection flag
2227
290
    unsigned u9 = getub(buf, 24);               // Used flags
2228
290
    unsigned u10 = getub(buf, 25);              // SV Type
2229
2230
    /* Channel number, bits 0-2 reserved/unused as of 1999.
2231
     * Seems to always start series at zero and increment to last one.
2232
     * No way to know how many there will be.
2233
     * Save current channel to check for last 0x5d message
2234
     */
2235
290
    if (0 == i) {
2236
        // start of new cycle, save last count
2237
54
        session->gpsdata.satellites_visible =
2238
54
            session->driver.tsip.last_chan_seen;
2239
236
    } else if (i >= TSIP_CHANNELS) {
2240
1
        GPSD_LOG(LOG_WARN, &session->context->errout,
2241
1
                 "TSIP x5d: Satellite Tracking Status: Too many chans %d\n", i);
2242
1
        return 0;
2243
1
    }
2244
289
    session->driver.tsip.last_chan_seen = i;
2245
2246
289
    session->gpsdata.skyview[i].PRN = u1;
2247
289
    session->gpsdata.skyview[i].ss = f1;
2248
289
    session->gpsdata.skyview[i].elevation = d1;
2249
289
    session->gpsdata.skyview[i].azimuth = d2;
2250
289
    session->gpsdata.skyview[i].used = (bool)u4;
2251
289
    session->gpsdata.skyview[i].gnssid = tsip_gnssid(u10, u1,
2252
289
        &session->gpsdata.skyview[i].svid);
2253
289
    if (0 == u7) {
2254
81
        session->gpsdata.skyview[i].health = SAT_HEALTH_OK;
2255
208
    } else {
2256
208
        session->gpsdata.skyview[i].health = SAT_HEALTH_BAD;
2257
208
    }
2258
2259
    /* when polled by 0x3c, all the skyview times will be the same
2260
     * in one cluster */
2261
289
    if (0.0 < ftow) {
2262
204
        DTOTS(&ts_tow, ftow);
2263
204
        session->gpsdata.skyview_time =
2264
204
            gpsd_gpstime_resolv(session, session->context->gps_week,
2265
204
                                ts_tow);
2266
        /* do not save in session->driver.tsip.last_tow
2267
         * as this is skyview time, not fix time */
2268
204
    }
2269
289
    if (++i >= session->gpsdata.satellites_visible) {
2270
        /* Last of the series?
2271
         * This will cause extra SKY if this set has more
2272
         * sats than the last set */
2273
271
        mask |= SATELLITE_SET;
2274
271
        session->gpsdata.satellites_visible = i;
2275
271
    }
2276
    /* If this series has fewer than last series there will
2277
     * be no SKY, unless the cycle ender pushes the SKY */
2278
2279
289
    if (MAXCHANNELS < session->gpsdata.satellites_visible) {
2280
0
        GPSD_LOG(LOG_WARN, &session->context->errout,
2281
0
                "TSIP x5d: too many satellites %d\n",
2282
0
                 session->gpsdata.satellites_visible);
2283
0
        session->gpsdata.satellites_visible = MAXCHANNELS;
2284
0
    }
2285
289
    GPSD_LOG(LOG_PROG, &session->context->errout,
2286
289
            "TSIP x5d: Satellite Tracking Status: Ch %2d Con %d PRN %3d "
2287
289
            "Acq %d Use %d SNR %4.1f LMT %.04f El %4.1f Az %5.1f Old %d "
2288
289
            "Int %d Bad %d Col %d TPF %d SVT %d\n",
2289
289
            i, u10, u1, u3, u4, f1, ftow, d1, d2, u5, u6, u7, u8, u9, u10);
2290
289
    GPSD_LOG(LOG_IO, &session->context->errout,
2291
289
             "TSIP: bad:%s uflags:%s scons:%s\n",
2292
289
             val2str(u7, vsv_bad),
2293
289
             flags2str(u9, vsv_used_flags, buf2, sizeof(buf2)),
2294
289
             val2str(u10, vsv_type));
2295
289
    return mask;
2296
290
}
2297
2298
// Decode x6c
2299
static gps_mask_t decode_x6c(struct gps_device_t *session, const char *buf,
2300
                             int len, int *pbad_len)
2301
228
{
2302
228
    gps_mask_t mask = 0;
2303
228
    char buf2[80];
2304
228
    int i, count;
2305
228
    unsigned fixdm = getub(buf, 0);          // fix dimension, mode
2306
228
    double pdop = getbef32(buf, 1);
2307
228
    double hdop = getbef32(buf, 5);
2308
228
    double vdop = getbef32(buf, 9);
2309
    // RES SMT 360 and ICM SMT 360 always report tdop == 1
2310
228
    double tdop = getbef32(buf, 13);
2311
2312
228
    if (IN(0.01, pdop, 89.99)) {
2313
        // why not to newdata?
2314
66
        session->gpsdata.dop.pdop = pdop;
2315
66
        mask |= DOP_SET;
2316
66
    }
2317
228
    if (IN(0.01, hdop, 89.99)) {
2318
        // why not to newdata?
2319
80
        session->gpsdata.dop.hdop = hdop;
2320
80
        mask |= DOP_SET;
2321
80
    }
2322
228
    if (IN(0.01, vdop, 89.99)) {
2323
        // why not to newdata?
2324
27
        session->gpsdata.dop.vdop = vdop;
2325
27
        mask |= DOP_SET;
2326
27
    }
2327
228
    if (IN(0.01, tdop, 89.99)) {
2328
        // why not to newdata?
2329
36
        session->gpsdata.dop.tdop = tdop;
2330
36
        mask |= DOP_SET;
2331
36
    }
2332
2333
228
    count = getub(buf, 17);
2334
2335
228
    if ((18 + count) > len) {
2336
63
        *pbad_len = 18 + count;
2337
63
        return mask;
2338
63
    }
2339
165
    *pbad_len = 0;
2340
2341
    /*
2342
     * This looks right, but it sets a spurious mode value when
2343
     * the satellite constellation looks good to the chip but no
2344
     * actual fix has yet been acquired.  We should set the mode
2345
     * field (which controls gpsd's fix reporting) only from sentences
2346
     * that convey actual fix information, like 0x8f-20, but some
2347
     * TSIP do not support 0x8f-20, and 0x6c may be all we got.
2348
     */
2349
165
    switch (fixdm & 7) {       // dimension
2350
11
    case 1:       // clock fix (surveyed in)
2351
11
        FALLTHROUGH
2352
30
    case 5:       // Overdetermined clock fix
2353
30
        session->newdata.status = STATUS_TIME;
2354
30
        session->newdata.mode = MODE_3D;
2355
30
        break;
2356
8
    case 3:
2357
8
        session->newdata.mode = MODE_2D;
2358
8
        break;
2359
33
    case 4:
2360
33
        session->newdata.mode = MODE_3D;
2361
33
        break;
2362
77
    case 6:
2363
        // Accutime
2364
77
        session->newdata.status = STATUS_DGPS;
2365
77
        session->newdata.mode = MODE_3D;
2366
77
        break;
2367
3
    case 0:
2368
        // Sometimes this is No Fix, sometimes Auto....
2369
3
        FALLTHROUGH
2370
13
    case 2:
2371
13
        FALLTHROUGH
2372
17
    case 7:
2373
17
        FALLTHROUGH
2374
17
    default:
2375
17
        session->newdata.mode = MODE_NO_FIX;
2376
17
        break;
2377
165
    }
2378
165
    if (8 == (fixdm & 8)) {      // fix mode
2379
        // Manual (Surveyed in)
2380
124
        if (count) {
2381
49
            session->newdata.status = STATUS_TIME;
2382
75
        } else {
2383
            // no saats, must be DR
2384
75
            session->newdata.status = STATUS_DR;
2385
75
        }
2386
124
    }
2387
165
    if (STATUS_UNK < session->newdata.status) {
2388
153
        mask |= STATUS_SET;
2389
153
    }
2390
165
    mask |= MODE_SET;
2391
2392
165
    session->gpsdata.satellites_used = count;
2393
2394
165
    memset(session->driver.tsip.sats_used, 0,
2395
165
            sizeof(session->driver.tsip.sats_used));
2396
165
    buf2[0] = '\0';
2397
3.38k
    for (i = 0; i < count; i++) {
2398
        // negative PRN means sat unhealthy why use an unhealthy sat??
2399
3.21k
        session->driver.tsip.sats_used[i] = getsb(buf, 18 + i);
2400
3.21k
        if (LOG_PROG <= session->context->errout.debug) {
2401
0
            str_appendf(buf2, sizeof(buf2),
2402
0
                           " %d", session->driver.tsip.sats_used[i]);
2403
0
        }
2404
3.21k
    }
2405
165
    GPSD_LOG(LOG_PROG, &session->context->errout,
2406
165
             "TSIP x6c: AIVSS: mode %d status %d used %d "
2407
165
             "pdop %.1f hdop %.1f vdop %.1f tdop %.1f Used %s fixdm x%x\n",
2408
165
             session->newdata.mode,
2409
165
             session->newdata.status,
2410
165
             session->gpsdata.satellites_used,
2411
165
             pdop, hdop, vdop, tdop, buf2, fixdm);
2412
165
    GPSD_LOG(LOG_IO, &session->context->errout,
2413
165
             "TSIP: fixd:%s\n",
2414
165
             flags2str(fixdm, vfix, buf2, sizeof(buf2)));
2415
165
    mask |= USED_IS;
2416
165
    return mask;
2417
165
}
2418
2419
// decode All-in-view Satellite Selection, x6d
2420
static gps_mask_t decode_x6d(struct gps_device_t *session, const char *buf,
2421
                             int len, int *pbad_len)
2422
252
{
2423
252
    gps_mask_t mask = 0;
2424
252
    int i;
2425
252
    char buf2[BUFSIZ];
2426
2427
252
    unsigned fix_dim = getub(buf, 0);     // nsvs/dimension
2428
252
    int count = (int)((fix_dim >> 4) & 0x0f);
2429
252
    double pdop = getbef32(buf, 1);
2430
252
    double hdop = getbef32(buf, 5);
2431
252
    double vdop = getbef32(buf, 9);
2432
252
    double tdop = getbef32(buf, 13);
2433
2434
252
    if ((17 + count) > len) {
2435
5
        *pbad_len = 17 + count;
2436
5
        return 0;
2437
5
    }
2438
247
    *pbad_len = 0;
2439
2440
247
    session->gpsdata.satellites_used = count;
2441
247
    if (IN(0.01, pdop, 89.99)) {
2442
        // why not to newdata?
2443
47
        session->gpsdata.dop.pdop = pdop;
2444
47
        mask |= DOP_SET;
2445
47
    }
2446
247
    if (IN(0.01, hdop, 89.99)) {
2447
        // why not to newdata?
2448
30
        session->gpsdata.dop.hdop = hdop;
2449
30
        mask |= DOP_SET;
2450
30
    }
2451
247
    if (IN(0.01, vdop, 89.99)) {
2452
        // why not to newdata?
2453
35
        session->gpsdata.dop.vdop = vdop;
2454
35
        mask |= DOP_SET;
2455
35
    }
2456
247
    if (IN(0.01, tdop, 89.99)) {
2457
        // why not to newdata?
2458
30
        session->gpsdata.dop.tdop = tdop;
2459
30
        mask |= DOP_SET;
2460
30
    }
2461
2462
    /*
2463
     * This looks right, but it sets a spurious mode value when
2464
     * the satellite constellation looks good to the chip but no
2465
     * actual fix has yet been acquired.  We should set the mode
2466
     * field (which controls gpsd's fix reporting) only from sentences
2467
     * that convey actual fix information, like 0x8f-20, but some
2468
     * TSIP do not support 0x8f-20, and 0x6c may be all we got.
2469
     */
2470
247
    switch (fix_dim & 7) {   // dimension
2471
7
    case 1:
2472
        // clock fix (surveyed in), not in Lassen IQ
2473
7
        FALLTHROUGH
2474
46
    case 5:       // Overdetermined clock fix, not in Lassen IQ
2475
46
        session->newdata.status = STATUS_TIME;
2476
46
        session->newdata.mode = MODE_3D;
2477
46
        break;
2478
26
    case 3:
2479
        // Copernicus ii can output this for OD mode.
2480
26
        session->newdata.mode = MODE_2D;
2481
26
        break;
2482
53
    case 4:
2483
        // SMTx can output this for OD mode.
2484
53
        session->newdata.mode = MODE_3D;
2485
53
        break;
2486
21
    case 6:
2487
        // Accutime, not in Lassen IQ
2488
21
        session->newdata.status = STATUS_DGPS;
2489
21
        session->newdata.mode = MODE_3D;
2490
21
        break;
2491
15
    case 2:              // not in Lassen IQ
2492
15
        FALLTHROUGH
2493
45
    case 7:              // not in Lassen IQ
2494
45
        FALLTHROUGH
2495
101
    default:             // huh?
2496
101
        session->newdata.mode = MODE_NO_FIX;
2497
101
        break;
2498
247
    }
2499
247
    if (0 >= count &&
2500
136
        0 != isfinite(session->oldfix.longitude)) {
2501
        // use oldfix, as this may be the 1st message in an epoch.
2502
2503
        // reports a fix even ith no sats!
2504
112
        session->newdata.status = STATUS_DR;
2505
112
    }
2506
247
    if (STATUS_UNK < session->newdata.status) {
2507
165
        mask |= STATUS_SET;
2508
165
    }
2509
247
    mask |= MODE_SET;
2510
2511
247
    memset(session->driver.tsip.sats_used, 0,
2512
247
           sizeof(session->driver.tsip.sats_used));
2513
247
    buf2[0] = '\0';
2514
724
    for (i = 0; i < count; i++) {
2515
        // negative PRN means sat unhealthy why use an unhealthy sat??
2516
2517
477
        session->driver.tsip.sats_used[i] = getsb(buf, 17 + i);
2518
477
        if (LOG_PROG <= session->context->errout.debug ) {
2519
0
            str_appendf(buf2, sizeof(buf2),
2520
0
                           " %u", session->driver.tsip.sats_used[i]);
2521
0
        }
2522
477
    }
2523
247
    GPSD_LOG(LOG_PROG, &session->context->errout,
2524
247
             "TSIP x6d: AIVSS: fix_dim=x%x status=%d mode=%d used=%d "
2525
247
             "pdop=%.1f hdop=%.1f vdop=%.1f tdop=%.1f used >%s<\n",
2526
247
             fix_dim,
2527
247
             session->newdata.status,
2528
247
             session->newdata.mode,
2529
247
             session->gpsdata.satellites_used,
2530
247
             pdop, hdop, vdop, tdop, buf2);
2531
247
    GPSD_LOG(LOG_IO, &session->context->errout,
2532
247
             "TSIP: fix::%s\n",
2533
247
             flags2str(fix_dim, vfix, buf2, sizeof(buf2)));
2534
247
    mask |= USED_IS;
2535
2536
247
    return mask;
2537
247
}
2538
2539
// decode packet x82
2540
static gps_mask_t decode_x82(struct gps_device_t *session, const char *buf)
2541
198
{
2542
198
    gps_mask_t mask = 0;
2543
    // differential position fix mode
2544
198
    unsigned mode = getub(buf, 0);
2545
198
    if (1 == (mode & 1)) {
2546
        /* mode 1 (manual DGPS), output fixes only w/ SGPS,
2547
         * or
2548
         * mode 3 (auto DGPS) and have DGPS */
2549
129
        session->newdata.status = STATUS_DGPS;
2550
129
        mask |= STATUS_SET;
2551
129
    }
2552
198
    GPSD_LOG(LOG_PROG, &session->context->errout,
2553
198
             "TSIP x82: DPFM: mode %d status=%d\n",
2554
198
             mode, session->newdata.status);
2555
198
    GPSD_LOG(LOG_IO, &session->context->errout,
2556
198
             "TSIP: mode:%s\n",
2557
198
             val2str(mode, vx82_mode));
2558
198
    return mask;
2559
198
}
2560
2561
// decode packet x83
2562
static gps_mask_t decode_x83(struct gps_device_t *session, const char *buf)
2563
134
{
2564
134
    gps_mask_t mask = 0;
2565
134
    timespec_t ts_tow;
2566
    // differential position fix mode
2567
134
    double ecefx = getbed64(buf, 0);            // X, m
2568
134
    double ecefy = getbed64(buf, 8);            // Y, m
2569
134
    double ecefz = getbed64(buf, 16);           // Z, m
2570
134
    double clock_bias = getbed64(buf, 24);      // clock bias, m
2571
134
    double ftow = getbef32(buf, 32);            // time-of-fix, s
2572
2573
134
    session->newdata.ecef.x = ecefx;
2574
134
    session->newdata.ecef.y = ecefy;
2575
134
    session->newdata.ecef.z = ecefz;
2576
    // short circuit to gpsdata. Convert m to ns
2577
134
    session->gpsdata.fix.clockbias = 1e9 * clock_bias / CLIGHT;
2578
2579
134
    DTOTS(&ts_tow, ftow);
2580
134
    session->newdata.time = gpsd_gpstime_resolv(session,
2581
134
                                                session->context->gps_week,
2582
134
                                                ts_tow);
2583
    /* No fix mode info!! That comes later in 0x6d.
2584
     * This message only sent when there is 2D or 3D fix.
2585
     * This is a problem as gpsd will send a report with no mode.
2586
     * Steal mode from last fix.
2587
     * The last fix is likely lastfix, not oldfix, as this is likely
2588
     * a new time and starts a new cycle! */
2589
134
    session->newdata.status = session->lastfix.status;
2590
134
    if (MODE_2D > session->oldfix.mode) {
2591
52
        session->newdata.mode = MODE_2D;  // At least 2D
2592
82
    } else {
2593
82
        session->newdata.mode = session->lastfix.mode;
2594
82
    }
2595
134
    mask |= STATUS_SET | MODE_SET | ECEF_SET | TIME_SET | NTPTIME_IS;
2596
134
    if (!TS_EQ(&ts_tow, &session->driver.tsip.last_tow)) {
2597
        // New time, so new fix.
2598
118
        mask |= CLEAR_IS;
2599
118
        session->driver.tsip.last_tow = ts_tow;
2600
118
    }
2601
134
    GPSD_LOG(LOG_PROG, &session->context->errout,
2602
134
             "TSIP x83: DP-XYZ: %f %f %f cbias %f tow %f mode %u\n",
2603
134
             session->newdata.ecef.x,
2604
134
             session->newdata.ecef.y,
2605
134
             session->newdata.ecef.z,
2606
134
             clock_bias, ftow,
2607
134
             session->newdata.mode);
2608
134
    return mask;
2609
134
}
2610
2611
// decode packet x84
2612
static gps_mask_t decode_x84(struct gps_device_t *session, const char *buf)
2613
134
{
2614
134
    gps_mask_t mask = 0;
2615
134
    timespec_t ts_tow;
2616
134
    char ts_buf[TIMESPEC_LEN];
2617
134
    double lat = getbed64(buf, 0) * RAD_2_DEG;   // lat, radians
2618
134
    double lon = getbed64(buf, 8) * RAD_2_DEG;   // lon, radians
2619
    // depending on GPS config, could be either WGS84 or MSL
2620
134
    double d1 = getbed64(buf, 16);               // altitude, m
2621
134
    double cbias = getbed64(buf, 16);            // clock bias, meters
2622
134
    double ftow = getbef32(buf, 32);             // time-of-fix, s
2623
2624
134
    session->newdata.latitude = lat;
2625
134
    session->newdata.longitude =lon;
2626
134
    if (0 == session->driver.tsip.alt_is_msl) {
2627
108
        session->newdata.altHAE = d1;
2628
108
    } else {
2629
26
        session->newdata.altMSL = d1;
2630
26
    }
2631
134
    mask |= ALTITUDE_SET;
2632
2633
    // short circuit to gpsdata. Convert m to ns
2634
134
    session->gpsdata.fix.clockbias = 1e9 * cbias / CLIGHT;
2635
2636
134
    if (0 != (session->context->valid & GPS_TIME_VALID)) {
2637
        // fingers crossed receiver set to UTC, not GPS.
2638
128
        DTOTS(&ts_tow, ftow);
2639
128
        session->newdata.time =
2640
128
            gpsd_gpstime_resolv(session, session->context->gps_week,
2641
128
                                ts_tow);
2642
128
        mask |= TIME_SET | NTPTIME_IS;
2643
128
        if (!TS_EQ(&ts_tow, &session->driver.tsip.last_tow)) {
2644
68
            mask |= CLEAR_IS;
2645
68
            session->driver.tsip.last_tow = ts_tow;
2646
68
        }
2647
128
    }
2648
134
    mask |= LATLON_SET;
2649
    /* No fix mode info!! That comes later in 0x6d.
2650
     * Message sent when there is 2D or 3D fix.
2651
     * This is a problem as gpsd will send a report with no mode.
2652
     * This message only sent on 2D or 3D fix.
2653
     * Steal mode from last fix. */
2654
134
    session->newdata.status = session->oldfix.status;
2655
134
    session->newdata.mode = session->oldfix.mode;
2656
134
    mask |= STATUS_SET | MODE_SET;
2657
2658
134
    GPSD_LOG(LOG_PROG, &session->context->errout,
2659
134
             "TSIP x84: DP-LLA: time=%s lat=%.2f lon=%.2f alt=%.2f %s "
2660
134
             "cbias %.2f\n",
2661
134
             timespec_str(&session->newdata.time, ts_buf, sizeof(ts_buf)),
2662
134
             session->newdata.latitude,
2663
134
             session->newdata.longitude, d1,
2664
134
             session->driver.tsip.alt_is_msl ? "MSL" : "HAE", cbias);
2665
134
    GPSD_LOG(LOG_IO, &session->context->errout,
2666
134
             "TSIP: mode:%s status:%s\n",
2667
134
             val2str(session->newdata.mode, vmode_str),
2668
134
             val2str(session->newdata.status, vstatus_str));
2669
134
    return mask;
2670
134
}
2671
2672
/* decode Superpacket x8f-15
2673
*/
2674
static gps_mask_t decode_x8f_15(struct gps_device_t *session, const char *buf)
2675
17
{
2676
17
    gps_mask_t mask = 0;
2677
17
    int s1 = getbes16(buf, 1);                 // Datum Index
2678
17
    double d1 = getbed64(buf, 3);              // DX
2679
17
    double d2 = getbed64(buf, 11);             // DY
2680
17
    double d3 = getbed64(buf, 19);             // DZ
2681
17
    double d4 = getbed64(buf, 27);             // A-axis
2682
17
    double d5 = getbed64(buf, 35);             // Eccentricity Squared
2683
2684
17
    GPSD_LOG(LOG_PROG, &session->context->errout,
2685
17
             "TSIP x8f-15: Current Datum: %d %f %f %f %f %f\n",
2686
17
             s1, d1, d2, d3, d4, d5);
2687
17
    return mask;
2688
17
}
2689
2690
/* decode Last Fix with Extra Information, Superpacket x8f-20
2691
 */
2692
static gps_mask_t decode_x8f_20(struct gps_device_t *session, const char *buf,
2693
                                const int length)
2694
96
{
2695
96
    gps_mask_t mask = 0;
2696
96
    double d1, d2, d3, d4;
2697
96
    timespec_t ts_tow;
2698
96
    char buf2[80];
2699
96
    char buf3[160];
2700
96
    char ts_buf[TIMESPEC_LEN];
2701
96
    int i;
2702
2703
96
    int s1 = getbes16(buf, 2);                // east velocity
2704
96
    int s2 = getbes16(buf, 4);                // north velocity
2705
96
    int s3 = getbes16(buf, 6);                // up velocity
2706
96
    unsigned long tow = getbeu32(buf, 8);     // time in ms
2707
96
    long lat = getbes32(buf, 12);             // latitude
2708
96
    unsigned long lon = getbeu32(buf, 16);    // longitude
2709
    // Lassen iQ, and copernicus (ii) doc says this is always altHAE
2710
96
    long alt = getbes32(buf, 20);             // altitude
2711
96
    unsigned u1 = getub(buf, 24);             // velocity scaling
2712
96
    unsigned datum = getub(buf, 26);          // Datum + 1
2713
96
    unsigned fflags = getub(buf, 27);         // fix flags
2714
96
    int numSV = getub(buf, 28);               // num svs
2715
96
    unsigned ls = getub(buf, 29);             // utc offset (leap seconds)
2716
96
    unsigned week = getbeu16(buf, 30);        // tsip.gps_week
2717
2718
    // PRN/IODE data follows
2719
2720
96
    if (0 != (u1 & 0x01)) {     // check velocity scaling
2721
24
        d4 = 0.02;
2722
72
    } else {
2723
72
        d4 = 0.005;
2724
72
    }
2725
2726
    // 0x8000 is over-range
2727
96
    if ((int)0x8000 != s2) {
2728
96
        d2 = (double)s2 * d4;   // north velocity m/s
2729
96
        session->newdata.NED.velN = d2;
2730
96
    }
2731
96
    if ((int16_t)0x8000 != s1) {
2732
87
        d1 = (double)s1 * d4;   // east velocity m/s
2733
87
        session->newdata.NED.velE = d1;
2734
87
    }
2735
96
    if ((int16_t)0x8000 != s3) {
2736
85
        d3 = (double)s3 * d4;       // up velocity m/s
2737
85
        session->newdata.NED.velD = -d3;
2738
85
    }
2739
2740
96
    session->newdata.latitude = (double)lat * SEMI_2_DEG;
2741
96
    session->newdata.longitude = (double)lon * SEMI_2_DEG;
2742
2743
96
    if (180.0 < session->newdata.longitude) {
2744
29
        session->newdata.longitude -= 360.0;
2745
29
    }
2746
    // Lassen iQ doc says this is always altHAE in mm
2747
96
    session->newdata.altHAE = (double)alt * 1e-3;
2748
96
    mask |= ALTITUDE_SET;
2749
2750
96
    session->newdata.status = STATUS_UNK;
2751
96
    session->newdata.mode = MODE_NO_FIX;
2752
96
    if ((uint8_t)0 == (fflags & 0x01)) {          // Fix Available
2753
74
        session->newdata.status = STATUS_GPS;
2754
74
        if ((uint8_t)0 != (fflags & 0x02)) {      // DGPS Corrected
2755
8
            session->newdata.status = STATUS_DGPS;
2756
8
        }
2757
74
        if ((uint8_t)0 != (fflags & 0x04)) {      // Fix Dimension
2758
18
            session->newdata.mode = MODE_2D;
2759
56
        } else {
2760
56
            session->newdata.mode = MODE_3D;
2761
56
        }
2762
74
    }
2763
96
    session->gpsdata.satellites_used = numSV;
2764
96
    if (10 < ls) {
2765
68
        session->context->leap_seconds = ls;
2766
68
        session->context->valid |= LEAP_SECOND_VALID;
2767
        /* check for week rollover
2768
         * Trimble uses 15 bit weeks, but can guess the epoch wrong
2769
         * Can not be in gpsd_gpstime_resolv() because that
2770
         * may see BUILD_LEAPSECONDS instead of leap_seconds
2771
         * from receiver.
2772
         */
2773
68
        if (17 < ls &&
2774
60
            1930 > week) {
2775
            // leap second 18 added in gps week 1930
2776
25
            week += 1024;
2777
25
            if (1930 > week) {
2778
                // and again?
2779
14
                week += 1024;
2780
14
            }
2781
25
        }
2782
68
    }
2783
96
    MSTOTS(&ts_tow, tow);
2784
96
    session->newdata.time = gpsd_gpstime_resolv(session, week,
2785
96
                                                ts_tow);
2786
96
    mask |= TIME_SET | NTPTIME_IS | LATLON_SET |
2787
96
            STATUS_SET | MODE_SET | VNED_SET;
2788
96
    if (!TS_EQ(&ts_tow, &session->driver.tsip.last_tow)) {
2789
61
        mask |= CLEAR_IS;
2790
61
        session->driver.tsip.last_tow = ts_tow;
2791
61
    }
2792
2793
96
    memset(session->driver.tsip.sats_used, 0,
2794
96
           sizeof(session->driver.tsip.sats_used));
2795
96
    buf3[0] = '\0';
2796
96
    if (MAXCHANNELS < numSV) {
2797
        // should not happen, pacify Coverity 493012
2798
3
        GPSD_LOG(LOG_WARN, &session->context->errout,
2799
3
                 "TSIP x8f-20: MAXCHANNELS < numSV (%d)\n", numSV);
2800
3
        return 0;
2801
3
    }
2802
783
    for (i = 0; i < numSV; i++) {
2803
719
        if (length < (33 + (i * 2))) {
2804
            // too short
2805
29
            break;
2806
29
        }
2807
        // bits 0 to 5, junk in 5 to 7
2808
690
        int PRN = getub(buf, 32 + (i * 2)) & 0x1f;
2809
690
        int IODE = getub(buf, 33 + (i * 2));
2810
2811
690
        session->driver.tsip.sats_used[i] = PRN;
2812
690
        if (LOG_PROG <= session->context->errout.debug) {
2813
0
            str_appendf(buf3, sizeof(buf3),
2814
0
                           " %d (%d)", session->driver.tsip.sats_used[i], IODE);
2815
0
        }
2816
690
    }
2817
2818
93
    GPSD_LOG(LOG_PROG, &session->context->errout,
2819
93
             "TSIP x8f-20: LFwEI: %d %d %d tow %lu %ld "
2820
93
             " %lu %lu %x fflags %x numSV %u ls %u week %d datum %u used:%s\n",
2821
93
             s1, s2, s3, tow, lat, lon, alt, u1, fflags, numSV,
2822
93
             ls, week, datum, buf3);
2823
93
    GPSD_LOG(LOG_PROG, &session->context->errout,
2824
93
             "TSIP x8f-20: LFwEI: time=%s lat=%.2f lon=%.2f "
2825
93
             "altHAE=%.2f mode=%d status=%d\n",
2826
93
             timespec_str(&session->newdata.time, ts_buf,
2827
93
                          sizeof(ts_buf)),
2828
93
             session->newdata.latitude, session->newdata.longitude,
2829
93
             session->newdata.altHAE,
2830
93
             session->newdata.mode, session->newdata.status);
2831
93
    GPSD_LOG(LOG_IO, &session->context->errout,
2832
93
             "TSIP: flags:%s\n",
2833
93
             flags2str(fflags, vx8f_20_fflags, buf2, sizeof(buf2)));
2834
93
    return mask;
2835
96
}
2836
2837
/* decode Packet Broadcast Mask: Superpacket x8f-23
2838
 */
2839
static gps_mask_t decode_x8f_23(struct gps_device_t *session, const char *buf)
2840
193
{
2841
193
    gps_mask_t mask = 0;
2842
193
    double d1, d2, d3, d5;
2843
193
    timespec_t ts_tow;
2844
193
    char ts_buf[TIMESPEC_LEN];
2845
2846
193
    unsigned long tow = getbeu32(buf, 1);    // time in ms
2847
193
    unsigned week = getbeu16(buf, 5);        // tsip.gps_week
2848
193
    unsigned u1 = getub(buf, 7);             // utc offset
2849
193
    unsigned u2 = getub(buf, 8);             // fix flags
2850
193
    long lat = getbes32(buf, 9);             // latitude
2851
193
    unsigned long lon = getbeu32(buf, 13);   // longitude
2852
    // Copernicus (ii) doc says this is always altHAE in mm
2853
193
    long alt = getbes32(buf, 17);            // altitude
2854
    // set xNED here
2855
193
    int s2 = getbes16(buf, 21);              // east velocity
2856
193
    int s3 = getbes16(buf, 23);              // north velocity
2857
193
    int s4 = getbes16(buf, 25);              // up velocity
2858
2859
193
    GPSD_LOG(LOG_PROG, &session->context->errout,
2860
193
             "TSIP x8f-23: CSP: tow %lu week %u %u %u %ld %lu %ld "
2861
193
             " %d %d %d\n",
2862
193
             tow, week, u1, u2, lat, lon, alt, s2, s3, s4);
2863
193
    if (10 < (int)u1) {
2864
148
        session->context->leap_seconds = (int)u1;
2865
148
        session->context->valid |= LEAP_SECOND_VALID;
2866
148
    }
2867
193
    MSTOTS(&ts_tow, tow);
2868
193
    session->newdata.time =
2869
193
        gpsd_gpstime_resolv(session, week, ts_tow);
2870
193
    session->newdata.status = STATUS_UNK;
2871
193
    session->newdata.mode = MODE_NO_FIX;
2872
193
    if ((u2 & 0x01) == (uint8_t)0) {          // Fix Available
2873
152
        session->newdata.status = STATUS_GPS;
2874
152
        if ((u2 & 0x02) != (uint8_t)0) {      // DGPS Corrected
2875
90
            session->newdata.status = STATUS_DGPS;
2876
90
        }
2877
152
        if ((u2 & 0x04) != (uint8_t)0) {       // Fix Dimension
2878
35
            session->newdata.mode = MODE_2D;
2879
117
        } else {
2880
117
            session->newdata.mode = MODE_3D;
2881
117
        }
2882
152
    }
2883
193
    session->newdata.latitude = (double)lat * SEMI_2_DEG;
2884
193
    session->newdata.longitude = (double)lon * SEMI_2_DEG;
2885
193
    if (180.0 < session->newdata.longitude) {
2886
72
        session->newdata.longitude -= 360.0;
2887
72
    }
2888
    // Copernicus (ii) doc says this is always altHAE in mm
2889
193
    session->newdata.altHAE = (double)alt * 1e-3;
2890
193
    mask |= ALTITUDE_SET;
2891
193
    if ((u2 & 0x20) != (uint8_t)0) {     // check velocity scaling
2892
103
        d5 = 0.02;
2893
103
    } else {
2894
90
        d5 = 0.005;
2895
90
    }
2896
193
    d1 = (double)s2 * d5;       // east velocity m/s
2897
193
    d2 = (double)s3 * d5;       // north velocity m/s
2898
193
    d3 = (double)s4 * d5;       // up velocity m/s
2899
193
    session->newdata.NED.velN = d2;
2900
193
    session->newdata.NED.velE = d1;
2901
193
    session->newdata.NED.velD = -d3;
2902
2903
193
    mask |= TIME_SET | NTPTIME_IS | LATLON_SET |
2904
193
            STATUS_SET | MODE_SET | VNED_SET;
2905
193
    if (!TS_EQ(&ts_tow, &session->driver.tsip.last_tow)) {
2906
169
        mask |= CLEAR_IS;
2907
169
        session->driver.tsip.last_tow = ts_tow;
2908
169
    }
2909
193
    session->driver.tsip.req_compact = 0;
2910
193
    GPSD_LOG(LOG_PROG, &session->context->errout,
2911
193
             "TSIP x8f-23: SP-CSP: time %s lat %.2f lon %.2f "
2912
193
             "altHAE %.2f mode %d status %d\n",
2913
193
             timespec_str(&session->newdata.time, ts_buf,
2914
193
                          sizeof(ts_buf)),
2915
193
             session->newdata.latitude, session->newdata.longitude,
2916
193
             session->newdata.altHAE,
2917
193
             session->newdata.mode, session->newdata.status);
2918
193
    return mask;
2919
193
}
2920
2921
/* decode Superpacket x8f-42
2922
 */
2923
static gps_mask_t decode_x8f_42(struct gps_device_t *session, const char *buf)
2924
6
{
2925
6
    gps_mask_t mask = 0;
2926
2927
6
    unsigned u1 = getub(buf, 1);                 // Production Options Prefix
2928
6
    unsigned u2 = getub(buf, 2);                 // Production Number Extension
2929
6
    unsigned u3 = getbeu16(buf, 3);              // Case Sernum Prefix
2930
6
    unsigned long ul1 = getbeu32(buf, 5);        // Case Sernum
2931
6
    unsigned long ul2 = getbeu32(buf, 9);        // Production Number
2932
6
    unsigned long ul3 = getbeu32(buf, 13);       // Reserved
2933
6
    unsigned u4 = getbeu16(buf, 15);             // Machine ID
2934
6
    unsigned u5 = getbeu16(buf, 17);             // Reserved
2935
2936
6
    GPSD_LOG(LOG_PROG, &session->context->errout,
2937
6
             "TSIP x8f-42: SPP: Prod x%x-%x Sernum %x-%lx "
2938
6
             "Prod %lx  Res %lx ID %x Res %x\n",
2939
6
             u1, u2, u3, ul1, ul2, ul3, u4, u5);
2940
6
    return mask;
2941
6
}
2942
2943
/* decode Packet Broadcast Mask: Superpacket x8f-ad
2944
 */
2945
static gps_mask_t decode_x8f_a5(struct gps_device_t *session, const char *buf)
2946
99
{
2947
99
    gps_mask_t mask = 0;
2948
99
    uint16_t mask0, mask1;
2949
99
    char buf2[40];
2950
2951
99
    mask0 = getbeu16(buf, 1);    // Mask 0
2952
99
    mask1 = getbeu16(buf, 3);    // Mask 1, reserved in ResSMT 360
2953
99
    GPSD_LOG(LOG_PROG, &session->context->errout,
2954
99
             "TSIP x8f-a5: PBM: mask0 x%04x mask1 x%04x\n",
2955
99
             mask0, mask1);
2956
99
    GPSD_LOG(LOG_IO, &session->context->errout,
2957
99
             "TSIP: mask0::%s\n",
2958
99
             flags2str(mask0, vpbm_mask0, buf2, sizeof(buf2)));
2959
2960
99
    return mask;
2961
99
}
2962
2963
/* decode Superpacket x8f-a6
2964
 */
2965
static gps_mask_t decode_x8f_a6(struct gps_device_t *session, const char *buf)
2966
43
{
2967
43
    gps_mask_t mask = 0;
2968
43
    unsigned u1 = getub(buf, 1);          // Command
2969
43
    unsigned u2 = getub(buf, 2);          // Status
2970
2971
43
    GPSD_LOG(LOG_PROG, &session->context->errout,
2972
43
             "TSIP x8f-a6: SSC: command x%x status x%x\n",
2973
43
             u1, u2);
2974
43
    return mask;
2975
43
}
2976
2977
/* decode Superpacket x8f-a7
2978
 * Individual Satellite Solutions
2979
 *
2980
 * Present in:
2981
 *   Thunderbolt
2982
 * Not present in:
2983
 *   THunderbolt E
2984
 *
2985
 */
2986
static gps_mask_t decode_x8f_a7(struct gps_device_t *session, const char *buf,
2987
                                const int length)
2988
95
{
2989
95
    gps_mask_t mask = 0;
2990
2991
    // we assume the receiver not in some crazy mode, and is GPS time
2992
95
    unsigned long tow = getbeu32(buf, 2);         // gpstime in seconds
2993
95
    unsigned fmt = buf[1];                        // format, 0 Float, 1 Int
2994
2995
95
    if (0 == fmt) {
2996
        // floating point mode
2997
60
        double clock_bias = getbef32(buf, 6);    // clock bias (combined). s
2998
        // clock bias rate (combined), s/s
2999
60
        double clock_rate = getbef32(buf, 10);
3000
3001
        // short circuit to gpsdata
3002
60
        session->gpsdata.fix.clockbias = clock_bias / 1e9;
3003
60
        session->gpsdata.fix.clockdrift = clock_rate / 1e9;
3004
3005
        // FIXME: decode the individual biases
3006
60
        GPSD_LOG(LOG_PROG, &session->context->errout,
3007
60
                 "TSIP x8f-a7: tow %llu fmt %u bias %e "
3008
60
                 "bias rate %e len %d\n",
3009
60
                 (long long unsigned)tow, fmt, clock_bias, clock_rate, length);
3010
60
    } else if (1 == fmt) {
3011
        // integer mode
3012
0
        int clock_bias = getbes16(buf, 6);   // Clock Bias (combined) 0.1ns
3013
0
        int clock_rate = getbes16(buf, 8);   // Clock Bias rate (combined) ps/s
3014
3015
        // short circuit to gpsdata
3016
0
        session->gpsdata.fix.clockbias = clock_bias / 10;
3017
0
        session->gpsdata.fix.clockdrift = clock_rate / 1000;
3018
3019
        // FIXME: decode the individual biases
3020
0
        GPSD_LOG(LOG_PROG, &session->context->errout,
3021
0
                 "TSIP x8f-a7: tow %llu mode %u bias %ld "
3022
0
                 "bias rate %ld len %d\n",
3023
0
                 (long long unsigned)tow, fmt,
3024
0
                 session->gpsdata.fix.clockbias,
3025
0
                 session->gpsdata.fix.clockdrift, length);
3026
35
    } else {
3027
        // unknown mode
3028
35
        GPSD_LOG(LOG_WARN, &session->context->errout,
3029
35
                 "TSIP x8f-a7: tow %llu fmt %u. Unknown mode len %d\n",
3030
35
                 (long long unsigned)tow, fmt, length);
3031
35
    }
3032
    // FIXME: loop over the individual sat data
3033
95
    return mask;
3034
95
}
3035
3036
/* decode Superpacket x8f-a9
3037
 */
3038
static gps_mask_t decode_x8f_a9(struct gps_device_t *session, const char *buf)
3039
4
{
3040
4
    gps_mask_t mask = 0;
3041
3042
4
    unsigned u1 = getub(buf, 1);              // Self Survey Enable
3043
4
    unsigned u2 = getub(buf, 2);              // Position Save Flag
3044
4
    unsigned long u3 = getbeu32(buf, 3);      // Self Survey Length
3045
4
    unsigned long u4 = getbeu32(buf, 7);      // Reserved
3046
3047
4
    GPSD_LOG(LOG_WARN, &session->context->errout,
3048
4
             "TSIP x8f-a9 SSP: sse %u psf %u length %ld rex x%lx \n",
3049
4
             u1, u2, u3, u4);
3050
4
    GPSD_LOG(LOG_IO, &session->context->errout,
3051
4
             "TSIP: sse:%s sssave:%s\n",
3052
4
             val2str(u1, vss_enable),
3053
4
             val2str(u2, vss_save));
3054
4
    return mask;
3055
4
}
3056
3057
/* decode Superpacket x8f-ab
3058
 * Oddly, no flag to say if the time is valid...
3059
 */
3060
static gps_mask_t decode_x8f_ab(struct gps_device_t *session, const char *buf)
3061
136
{
3062
136
    gps_mask_t mask = 0;
3063
136
    unsigned long tow;                 // time of week in milli seconds
3064
136
    timespec_t ts_tow;
3065
136
    unsigned short week;
3066
136
    char ts_buf[TIMESPEC_LEN];
3067
136
    unsigned time_flag;
3068
136
    char buf2[BUFSIZ];
3069
3070
    // we assume the receiver not in some crazy mode, and is GPS time
3071
136
    tow = getbeu32(buf, 1);             // gpstime in seconds
3072
136
    ts_tow.tv_sec = tow;
3073
136
    ts_tow.tv_nsec = 0;
3074
136
    week = getbeu16(buf, 5);            // week
3075
    // leap seconds
3076
136
    session->context->leap_seconds = (int)getbes16(buf, 7);
3077
136
    time_flag = buf[9];                // Time Flag
3078
    /* ignore the broken down time, use the GNSS time.
3079
     * Hope it is not BeiDou time */
3080
3081
136
    if (1 == (time_flag & 1)) {
3082
        // time is UTC, have leap seconds.
3083
29
        session->context->valid |= LEAP_SECOND_VALID;
3084
107
    } else {
3085
        // time is GPS
3086
107
        if (0 == (time_flag & 8)) {
3087
            // have leap seconds.
3088
65
            session->context->valid |= LEAP_SECOND_VALID;
3089
65
        }
3090
107
    }
3091
136
    if (0 == (time_flag & 0x14)) {
3092
        // time it good, not in test mode
3093
93
        session->newdata.time = gpsd_gpstime_resolv(session, week,
3094
93
                                                    ts_tow);
3095
93
        mask |= TIME_SET | NTPTIME_IS;
3096
93
    } else {
3097
        // time is bad
3098
43
    }
3099
3100
136
    if (!TS_EQ(&ts_tow, &session->driver.tsip.last_tow)) {
3101
114
        mask |= CLEAR_IS;
3102
114
        session->driver.tsip.last_tow = ts_tow;
3103
114
    }
3104
3105
    /* since we compute time from weeks and tow, we ignore the
3106
     * supplied H:M:S M/D/Y */
3107
136
    GPSD_LOG(LOG_PROG, &session->context->errout,
3108
136
             "TSIP x8f-ab: SP-TTS: tow %lu wk %u ls %d flag x%x "
3109
136
             "time %s mask %s\n",
3110
136
             tow, week, session->context->leap_seconds, time_flag,
3111
136
             timespec_str(&session->newdata.time, ts_buf,
3112
136
                          sizeof(ts_buf)),
3113
136
             gps_maskdump(mask));
3114
136
    GPSD_LOG(LOG_IO, &session->context->errout,
3115
136
             "TSIP: tf:%s\n",
3116
136
             flags2str(time_flag, vtiming, buf2, sizeof(buf2)));
3117
3118
136
    return mask;
3119
136
}
3120
3121
/* decode Supplemental Timing Packet (0x8f-ac)
3122
 * present in:
3123
 *   ThunderboltE
3124
 *   ICM SMT 360
3125
 *   RES SMT 360
3126
 *   Resolution SMTx
3127
 * Not Present in:
3128
 *   pre-2000 models
3129
 *   Lassen iQ
3130
 *   Copernicus II (2009)
3131
 */
3132
static gps_mask_t decode_x8f_ac(struct gps_device_t *session, const char *buf)
3133
124
{
3134
124
    gps_mask_t mask = 0;
3135
124
    char buf2[BUFSIZ];
3136
124
    char buf3[BUFSIZ];
3137
3138
    // byte 0 is Subpacket ID
3139
124
    unsigned rec_mode = getub(buf, 1);         // Receiver Mode
3140
    // Disciplining Mode, ICM SMT 360 only
3141
124
    unsigned disc_mode = getub(buf, 2);
3142
    // Self-Survey Progress
3143
124
    unsigned survey_prog = getub(buf, 3);
3144
    // ignore 4-7, Holdover Duration, reserved on Resolution SMTx
3145
    // ignore 8-9, Critical Alarms, reserved on Resolution SMTx
3146
124
    unsigned crit_alarm = getbeu16(buf, 8);
3147
    // Minor Alarms
3148
124
    unsigned minor_alarm = getbeu16(buf, 10);
3149
124
    unsigned decode_stat = getub(buf, 12);        // GNSS Decoding Status
3150
    // Disciplining Activity, ICM SMT 360 Only
3151
124
    unsigned disc_act = getub(buf, 13);
3152
    // PPS indication, RES SMT 360 Only
3153
124
    unsigned pps_ind = getub(buf, 14);
3154
124
    unsigned pps_ref = getub(buf, 15);            // PPS reference
3155
    /* PPS Offset in ns
3156
     * save as (long)pico seconds
3157
     * can't really use it as it is not referenced to any PPS */
3158
124
    double fqErr = getbef32(buf, 16);          // PPS Offset. positive is slow.
3159
    // Clock Offset (bias) ns. same as ppb
3160
124
    double clk_off = getbef32(buf, 20);
3161
    // ignore 24-27, DAC Value (ICM SMT 360 Only)
3162
124
    double dac_v = getbef32(buf, 28);          // DAC Voltage
3163
    // 32-35, Temperature degrees C
3164
124
    session->newdata.temp = getbef32(buf, 32);
3165
124
    session->newdata.latitude = getbed64(buf, 36) * RAD_2_DEG;
3166
124
    session->newdata.longitude = getbed64(buf, 44) * RAD_2_DEG;
3167
    // SMT 360 doc says this is always altHAE in meters
3168
124
    session->newdata.altHAE = getbed64(buf, 52);
3169
    // ignore 60-63, always zero, PPS Quanization error, ns ?
3170
    // ignore 64-67, reserved
3171
3172
124
    switch (minor_alarm & 6) {
3173
15
    case 2:
3174
15
        session->newdata.ant_stat = ANT_OPEN;
3175
15
        break;
3176
16
    case 4:
3177
16
        session->newdata.ant_stat = ANT_SHORT;
3178
16
        break;
3179
93
    default:
3180
93
        session->newdata.ant_stat = ANT_OK;
3181
93
        break;
3182
124
    }
3183
3184
124
    session->gpsdata.qErr = (long)(fqErr * 1000);
3185
    // short circuit to gpsdata.
3186
124
    session->gpsdata.fix.clockbias = clk_off;
3187
3188
    // PPS indication
3189
124
    if (3026 == session->driver.tsip.hardware_code) {
3190
        // only ICM SMT 360 has disciplining activity
3191
        // disc_act = 10;
3192
0
    }
3193
    // We don;t know enough to set status, probably TIME_TIME
3194
3195
    // Decode Fix modes
3196
124
    switch (rec_mode & 7) {
3197
41
    case 0:     // Auto
3198
        /*
3199
        * According to the Thunderbolt Manual, the
3200
        * first byte of the supplemental timing packet
3201
        * simply indicates the configuration of the
3202
        * device, not the actual lock, so we need to
3203
        * look at the decode status.
3204
        */
3205
41
        switch (decode_stat) {
3206
13
        case 0:   // "Doing Fixes"
3207
13
            session->newdata.mode = MODE_3D;
3208
13
            break;
3209
15
        case 0x0B: // "Only 3 usable sats"
3210
15
            session->newdata.mode = MODE_2D;
3211
15
            break;
3212
0
        case 0x1:   // "Don't have GPS time"
3213
0
            FALLTHROUGH
3214
0
        case 0x3:   // "PDOP is too high"
3215
0
            FALLTHROUGH
3216
0
        case 0x8:   // "No usable sats"
3217
0
            FALLTHROUGH
3218
0
        case 0x9:   // "Only 1 usable sat"
3219
0
            FALLTHROUGH
3220
0
        case 0x0A:  // "Only 2 usable sats
3221
0
            FALLTHROUGH
3222
0
        case 0x0C:  // "The chosen sat is unusable"
3223
0
            FALLTHROUGH
3224
0
        case 0x10:  // TRAIM rejected the fix
3225
0
            FALLTHROUGH
3226
13
        default:
3227
13
            session->newdata.mode = MODE_NO_FIX;
3228
13
            break;
3229
41
        }
3230
41
        break;
3231
41
    case 6:             // Clock Hold 2D
3232
        /* Not present:
3233
         *   SMT 360
3234
         *   Acutime 360
3235
         */
3236
13
        FALLTHROUGH
3237
24
    case 3:             // forced 2D Position Fix
3238
        // Does this mean STATUS_TIME?
3239
24
        session->newdata.mode = MODE_2D;
3240
24
        break;
3241
12
    case 1:             // Single Satellite Time
3242
        /* Present in:
3243
         *   Acutime 360
3244
         */
3245
12
        FALLTHROUGH
3246
28
    case 7:             // overdetermined clock
3247
        /* Present in:
3248
         *   Acutiome 360
3249
         *   ResSMT360
3250
         *   Resolution SMTx
3251
         */
3252
        /*
3253
        * According to the Thunderbolt Manual, the
3254
        * first byte of the supplemental timing packet
3255
        * simply indicates the configuration of the
3256
        * device, not the actual lock, so we need to
3257
        * look at the decode status.
3258
        */
3259
28
        session->newdata.status = STATUS_TIME;
3260
28
        switch (decode_stat) {
3261
0
        case 0:   // "Doing Fixes"
3262
0
            session->newdata.mode = MODE_3D;
3263
0
            break;
3264
15
        case 0x9:   // "Only 1 usable sat"
3265
15
            FALLTHROUGH
3266
20
        case 0x0A:  // "Only 2 usable sats
3267
20
            FALLTHROUGH
3268
23
        case 0x0B: // "Only 3 usable sats"
3269
23
            session->newdata.mode = MODE_2D;
3270
23
            break;
3271
0
        case 0x1:   // "Don't have GPS time"
3272
0
            FALLTHROUGH
3273
0
        case 0x3:   // "PDOP is too high"
3274
0
            FALLTHROUGH
3275
0
        case 0x8:   // "No usable sats"
3276
0
            FALLTHROUGH
3277
0
        case 0x0C:  // "The chosen sat is unusable"
3278
0
            FALLTHROUGH
3279
0
        case 0x10:  // TRAIM rejected the fix
3280
0
            FALLTHROUGH
3281
5
        default:
3282
5
            session->newdata.mode = MODE_NO_FIX;
3283
5
            break;
3284
28
        }
3285
28
        break;
3286
28
    case 4:             // forced 3D position Fix
3287
19
        session->newdata.mode = MODE_3D;
3288
19
        break;
3289
12
    default:
3290
12
        session->newdata.mode = MODE_NO_FIX;
3291
12
        break;
3292
124
    }
3293
124
    if (0 != (0x208 & minor_alarm) &&
3294
114
        7 == (rec_mode & 7)) {
3295
        // OD, No sats or position questionable, must be Dead reckoning
3296
16
        session->newdata.mode = MODE_3D;
3297
16
        session->newdata.status = STATUS_DR;
3298
16
    }
3299
124
    if (STATUS_UNK != session->newdata.status) {
3300
28
        mask |= STATUS_SET;
3301
28
    }
3302
3303
124
    mask |= LATLON_SET | ALTITUDE_SET | MODE_SET;
3304
124
    GPSD_LOG(LOG_PROG, &session->context->errout,
3305
124
             "TSIP x8f-ac: SP-TPS: lat=%.2f lon=%.2f altHAE=%.2f "
3306
124
             "mode %d status %d  temp %.1f disc %u pps_ind %u pps_ref %u "
3307
124
             "fqErr %.4f clko %f DACV %f rm x%x dm %u "
3308
124
             "sp %u ca %x ma x%x gds x%x\n",
3309
124
             session->newdata.latitude,
3310
124
             session->newdata.longitude,
3311
124
             session->newdata.altHAE,
3312
124
             session->newdata.mode,
3313
124
             session->newdata.status,
3314
124
             session->newdata.temp,
3315
124
             disc_act, pps_ind, pps_ref, fqErr, clk_off, dac_v,  rec_mode,
3316
124
             disc_mode, survey_prog, crit_alarm,
3317
124
             minor_alarm, decode_stat);
3318
124
    GPSD_LOG(LOG_IO, &session->context->errout,
3319
124
             "TSIP: mode:%s status:%s rm:%s gds:%s ca:%s ma:%s disc_act %s "
3320
124
             "pps_ing %s pps_ref %s\n",
3321
124
             val2str(session->newdata.mode, vmode_str),
3322
124
             val2str(session->newdata.status, vstatus_str),
3323
124
             val2str(rec_mode, vrec_mode),
3324
124
             val2str(decode_stat, vgnss_decode_status),
3325
124
             flags2str(crit_alarm, vcrit_alarms, buf2,
3326
124
                       sizeof(buf2)),
3327
124
             flags2str(minor_alarm, vminor_alarms, buf3,
3328
124
                       sizeof(buf3)),
3329
124
             val2str(disc_act, vdisc_act),
3330
124
             val2str(pps_ind, vpps_ind),
3331
124
             val2str(pps_ref, vpps_ref));
3332
124
    return mask;
3333
124
}
3334
3335
// decode Superpackets x8f-XX
3336
static gps_mask_t decode_x8f(struct gps_device_t *session, const char *buf,
3337
                             int len, int *pbad_len, time_t now)
3338
1.60k
{
3339
1.60k
    gps_mask_t mask = 0;
3340
1.60k
    int bad_len = 0;
3341
1.60k
    unsigned u1 = getub(buf, 0);
3342
3343
1.60k
    switch (u1) {           // sub-code ID
3344
68
    case 0x15:
3345
        /* Current Datum Values
3346
         * Not Present in:
3347
         *   pre-2000 models
3348
         *   Copernicus II (2009)
3349
         *   ICM SMT 360 (2018)
3350
         *   RES SMT 360 (2018)
3351
         */
3352
68
        if (43 > len) {
3353
51
            bad_len = 43;
3354
51
            break;
3355
51
        }
3356
17
        mask = decode_x8f_15(session, buf);
3357
17
        break;
3358
3359
184
    case 0x20:
3360
        /* Last Fix with Extra Information (binary fixed point) 0x8f-20
3361
         * Only output when fix is available.
3362
         * CSK sez "why does my Lassen SQ output oversize packets?"
3363
         * Present in:
3364
         *   pre-2000 models
3365
         *   ACE II
3366
         *   Copernicus, Copernicus II (64-bytes)
3367
         * Not present in:
3368
         *   ICM SMT 360
3369
         *   RES SMT 360
3370
         */
3371
184
        if (56 != (len) &&
3372
137
            64 != (len)) {
3373
88
            bad_len = 56;
3374
88
            break;
3375
88
        }
3376
96
        mask = decode_x8f_20(session, buf, len);
3377
96
        break;
3378
297
    case 0x23:
3379
        /* Compact Super Packet (0x8f-23)
3380
         * Present in:
3381
         *   Copernicus, Copernicus II
3382
         * Not present in:
3383
         *   pre-2000 models
3384
         *   Lassen iQ
3385
         *   ICM SMT 360
3386
         *   RES SMT 360
3387
         */
3388
        // CSK sez "i don't trust this to not be oversized either."
3389
297
        if (29 > len) {
3390
104
            bad_len = 29;
3391
104
            break;
3392
104
        }
3393
193
        mask = decode_x8f_23(session, buf);
3394
193
        break;
3395
3396
46
    case 0x42:
3397
        /* Stored production parameters
3398
         * Present in:
3399
         *   ICM SMT 360 (2018)
3400
         *   RES SMT 360 (2018)
3401
         *   Resolution SMTx (2013)
3402
         * Not Present in:
3403
         *   pre-2000 models
3404
         *   Copernicus II (2009)
3405
         */
3406
46
        if (19 > len) {
3407
40
            bad_len = 19;
3408
40
            break;
3409
40
        }
3410
6
        mask = decode_x8f_42(session, buf);
3411
6
        break;
3412
169
    case 0xa5:
3413
        /* Packet Broadcast Mask (0x8f-a5) polled by 0x8e-a5
3414
         *
3415
         * Present in:
3416
         *   ICM SMT 360
3417
         *   RES SMT 360
3418
         * Not Present in:
3419
         *   pre-2000 models
3420
         *   Copernicus II (2009)
3421
         *
3422
         * Defaults:
3423
         *   RES SMT 360: 05, 00
3424
         *   Resolution SMTx: 05 00
3425
         */
3426
169
        if (5 > len) {
3427
70
            bad_len = 5;
3428
70
            break;
3429
70
        }
3430
99
        mask = decode_x8f_a5(session, buf);
3431
99
        break;
3432
3433
117
    case 0xa6:
3434
        /* Self-Survey Command (0x8f-a6) polled by 0x8e-a6
3435
         *
3436
         * Present in:
3437
         *   ICM SMT 360
3438
         *   RES SMT 360
3439
         * Not Present in:
3440
         *   pre-2000 models
3441
         *   Copernicus II (2009)
3442
         */
3443
117
        if (3 > len) {
3444
74
            bad_len = 3;
3445
74
            break;
3446
74
        }
3447
43
        mask = decode_x8f_a6(session, buf);
3448
43
        break;
3449
3450
108
    case 0xa7:
3451
        /* Thunderbolt Individual Satellite Solutions
3452
         * partial decode
3453
         */
3454
108
        if (10 > len) {
3455
13
            bad_len = 10;
3456
13
            break;
3457
13
        }
3458
95
        mask = decode_x8f_a7(session, buf, len);
3459
95
        break;
3460
151
    case 0xa9:
3461
        /* Self Survey Parameters
3462
         * Present in:
3463
         *   ICM SMT 360 (2018)
3464
         *   RES SMT 360 (2018)
3465
         *   Resolution SMTx
3466
         * Not Present in:
3467
         *   pre-2000 models
3468
         *   Copernicus II (2009)
3469
         */
3470
151
        if (11 > len) {
3471
147
            bad_len = 11;
3472
147
            break;
3473
147
        }
3474
4
        mask = decode_x8f_a9(session, buf);
3475
4
        break;
3476
230
    case 0xab:
3477
        /* Thunderbolt Timing Superpacket
3478
         * Present in:
3479
         *   Resolution SMTx
3480
         * Not Present in:
3481
         *   pre-2000 models
3482
         *   Copernicus II (2009)
3483
         */
3484
230
        if (17 > len) {
3485
94
            bad_len = 17;
3486
94
            break;
3487
94
        }
3488
136
        session->driver.tsip.last_41 = now; // keep timestamp for request
3489
136
        mask = decode_x8f_ab(session, buf);
3490
136
        break;
3491
3492
143
    case 0xac:
3493
        /* Supplemental Timing Packet (0x8f-ac)
3494
         * present in:
3495
         *   ThunderboltE
3496
         *   ICM SMT 360
3497
         *   RES SMT 360
3498
         *   Resolution SMTx
3499
         * Not Present in:
3500
         *   pre-2000 models
3501
         *   Lassen iQ
3502
         *   Copernicus II (2009)
3503
         */
3504
143
        if (68 > len) {
3505
19
            bad_len = 68;
3506
19
            break;
3507
19
        }
3508
124
        mask = decode_x8f_ac(session, buf);
3509
124
        break;
3510
3511
4
    case 0x02:
3512
        /* UTC Information
3513
         * Present in:
3514
         *   ICM SMT 360 (2018)
3515
         *   RES SMT 360 (2018)
3516
         * Not Present in:
3517
         *   pre-2000 models
3518
         *   Copernicus II (2009)
3519
         */
3520
4
        FALLTHROUGH
3521
4
    case 0x21:
3522
        /* Request accuracy information
3523
         * Present in:
3524
         *   Copernicus II (2009)
3525
         * Not Present in:
3526
         *   pre-2000 models
3527
         */
3528
4
        FALLTHROUGH
3529
4
    case 0x2a:
3530
        /* Request Fix and Channel Tracking info, Type 1
3531
         * Present in:
3532
         *   Copernicus II (2009)
3533
         * Not Present in:
3534
         *   pre-2000 models
3535
         */
3536
4
        FALLTHROUGH
3537
4
    case 0x2b:
3538
        /* Request Fix and Channel Tracking info, Type 2
3539
         * Present in:
3540
         *   Copernicus II (2009)
3541
         * Not Present in:
3542
         *   pre-2000 models
3543
         */
3544
4
        FALLTHROUGH
3545
4
    case 0x41:
3546
        /* Stored manufacturing operating parameters x8f-41
3547
         * Present in:
3548
         *   ICM SMT 360 (2018)
3549
         *   RES SMT 360 (2018)
3550
         * Not Present in:
3551
         *   pre-2000 models
3552
         *   Copernicus II (2009)
3553
         */
3554
4
        FALLTHROUGH
3555
4
    case 0x4a:
3556
        /* PPS characteristics
3557
         * Present in:
3558
         *   ICM SMT 360 (2018)
3559
         *   RES SMT 360 (2018)
3560
         *   Copernicus II (2009)
3561
         * Not Present in:
3562
         *   pre-2000 models
3563
         */
3564
4
        FALLTHROUGH
3565
4
    case 0x4e:
3566
        /* PPS Output options
3567
         * Present in:
3568
         *   ICM SMT 360 (2018)
3569
         *   RES SMT 360 (2018)
3570
         * Not Present in:
3571
         *   pre-2000 models
3572
         *   Copernicus II (2009)
3573
         */
3574
4
        FALLTHROUGH
3575
4
    case 0x4f:
3576
        /* Set PPS Width
3577
         * Present in:
3578
         *   Copernicus II (2009)
3579
         * Not Present in:
3580
         *   pre-2000 models
3581
         *   ICM SMT 360 (2018)
3582
         *   RES SMT 360 (2018)
3583
         */
3584
4
        FALLTHROUGH
3585
4
    case 0x60:
3586
        /* DR Calibration and Status Report
3587
         * Present in:
3588
         *   pre-2000 models
3589
         * Not Present in:
3590
         *   Copernicus II (2009)
3591
         *   ICM SMT 360 (2018)
3592
         *   RES SMT 360 (2018)
3593
         */
3594
4
        FALLTHROUGH
3595
5
    case 0x62:
3596
        /* GPS/DR Position/Velocity Report
3597
         * Present in:
3598
         *   pre-2000 models
3599
         * Not Present in:
3600
         *   Copernicus II (2009)
3601
         *   ICM SMT 360 (2018)
3602
         *   RES SMT 360 (2018)
3603
         */
3604
5
        FALLTHROUGH
3605
5
    case 0x64:
3606
        /* Firmware Version and Configuration Report
3607
         * Present in:
3608
         *   pre-2000 models
3609
         * Not Present in:
3610
         *   Copernicus II (2009)
3611
         *   ICM SMT 360 (2018)
3612
         *   RES SMT 360 (2018)
3613
         */
3614
5
        FALLTHROUGH
3615
5
    case 0x6b:
3616
        /* Last Gyroscope Readings Report
3617
         * Present in:
3618
         *   pre-2000 models
3619
         * Not Present in:
3620
         *   Copernicus II (2009)
3621
         *   ICM SMT 360 (2018)
3622
         *   RES SMT 360 (2018)
3623
         */
3624
5
        FALLTHROUGH
3625
5
    case 0x6d:
3626
        /* Last Odometer Readings Report x8f-6d
3627
         * Present in:
3628
         *   pre-2000 models
3629
         * Not Present in:
3630
         *   Copernicus II (2009)
3631
         *   ICM SMT 360 (2018)
3632
         *   RES SMT 360 (2018)
3633
         */
3634
5
        FALLTHROUGH
3635
5
    case 0x6f:
3636
        /* Firmware Version Name Report
3637
         * Present in:
3638
         *   pre-2000 models
3639
         * Not Present in:
3640
         *   Copernicus II (2009)
3641
         *   ICM SMT 360 (2018)
3642
         *   RES SMT 360 (2018)
3643
         */
3644
5
        FALLTHROUGH
3645
5
    case 0x70:
3646
        /* Beacon Channel Status Report
3647
         * Present in:
3648
         *   pre-2000 models
3649
         * Not Present in:
3650
         *   Copernicus II (2009)
3651
         *   ICM SMT 360 (2018)
3652
         *   RES SMT 360 (2018)
3653
         */
3654
5
        FALLTHROUGH
3655
5
    case 0x71:
3656
        /* DGPS Station Database Reports
3657
         * Present in:
3658
         *   pre-2000 models
3659
         * Not Present in:
3660
         *   Copernicus II (2009)
3661
         *   ICM SMT 360 (2018)
3662
         *   RES SMT 360 (2018)
3663
         */
3664
5
        FALLTHROUGH
3665
5
    case 0x73:
3666
        /* Beacon Channel Control Acknowledgment
3667
         * Present in:
3668
         *   pre-2000 models
3669
         * Not Present in:
3670
         *   Copernicus II (2009)
3671
         *   ICM SMT 360 (2018)
3672
         *   RES SMT 360 (2018)
3673
         */
3674
5
        FALLTHROUGH
3675
5
    case 0x74:
3676
        /* Clear Beacon Database Acknowledgment
3677
         * Present in:
3678
         *   pre-2000 models
3679
         * Not Present in:
3680
         *   Copernicus II (2009)
3681
         *   ICM SMT 360 (2018)
3682
         *   RES SMT 360 (2018)
3683
         */
3684
5
        FALLTHROUGH
3685
5
    case 0x75:
3686
        /* FFT Start Acknowledgment
3687
         * Present in:
3688
         *   pre-2000 models
3689
         * Not Present in:
3690
         *   Copernicus II (2009)
3691
         *   ICM SMT 360 (2018)
3692
         *   RES SMT 360 (2018)
3693
         */
3694
5
        FALLTHROUGH
3695
5
    case 0x76:
3696
        /* FFT Stop Acknowledgment
3697
         * Present in:
3698
         *   pre-2000 models
3699
         * Not Present in:
3700
         *   Copernicus II (2009)
3701
         *   ICM SMT 360 (2018)
3702
         *   RES SMT 360 (2018)
3703
         */
3704
5
        FALLTHROUGH
3705
10
    case 0x77:
3706
        /* FFT Reports
3707
         * Present in:
3708
         *   pre-2000 models
3709
         * Not Present in:
3710
         *   Copernicus II (2009)
3711
         *   ICM SMT 360 (2018)
3712
         *   RES SMT 360 (2018)
3713
         */
3714
10
        FALLTHROUGH
3715
10
    case 0x78:
3716
        /* RTCM Reports
3717
         * Present in:
3718
         *   pre-2000 models
3719
         * Not Present in:
3720
         *   Copernicus II (2009)
3721
         *   ICM SMT 360 (2018)
3722
         *   RES SMT 360 (2018)
3723
         */
3724
10
        FALLTHROUGH
3725
10
    case 0x79:
3726
        /* Beacon Station Attributes Acknowledgment
3727
         * Present in:
3728
         *   pre-2000 models
3729
         * Not Present in:
3730
         *   Copernicus II (2009)
3731
         *   ICM SMT 360 (2018)
3732
         *   RES SMT 360 (2018)
3733
         */
3734
10
        FALLTHROUGH
3735
10
    case 0x7a:
3736
        /* Beacon Station Attributes Report
3737
         * Present in:
3738
         *   pre-2000 models
3739
         * Not Present in:
3740
         *   Copernicus II (2009)
3741
         *   ICM SMT 360 (2018)
3742
         *   RES SMT 360 (2018)
3743
         */
3744
10
        FALLTHROUGH
3745
10
    case 0x7b:
3746
        /* DGPS Receiver RAM Configuration Block Report
3747
         * Present in:
3748
         *   pre-2000 models
3749
         * Not Present in:
3750
         *   Copernicus II (2009)
3751
         *   ICM SMT 360 (2018)
3752
         *   RES SMT 360 (2018)
3753
         */
3754
10
        FALLTHROUGH
3755
10
    case 0x7c:
3756
        /* DGPS Receiver Configuration Block Acknowledgment
3757
         * Present in:
3758
         *   pre-2000 models
3759
         * Not Present in:
3760
         *   Copernicus II (2009)
3761
         *   ICM SMT 360 (2018)
3762
         *   RES SMT 360 (2018)
3763
         */
3764
10
        FALLTHROUGH
3765
10
    case 0x7e:
3766
        /* Satellite Line-of-Sight (LOS) Message
3767
         * Present in:
3768
         *   pre-2000 models
3769
         * Not Present in:
3770
         *   Copernicus II (2009)
3771
         *   ICM SMT 360 (2018)
3772
         *   RES SMT 360 (2018)
3773
         */
3774
10
        FALLTHROUGH
3775
10
    case 0x7f:
3776
        /* DGPS Receiver ROM Configuration Block Report
3777
         * Present in:
3778
         *   pre-2000 models
3779
         * Not Present in:
3780
         *   Copernicus II (2009)
3781
         *   ICM SMT 360 (2018)
3782
         *   RES SMT 360 (2018)
3783
         */
3784
10
        FALLTHROUGH
3785
10
    case 0x80:
3786
        /* DGPS Service Provider System Information Report
3787
         * Present in:
3788
         *   pre-2000 models
3789
         * Not Present in:
3790
         *   Copernicus II (2009)
3791
         *   ICM SMT 360 (2018)
3792
         *   RES SMT 360 (2018)
3793
         */
3794
10
        FALLTHROUGH
3795
10
    case 0x81:
3796
        /* Decoder Station Information Report and Selection Acknowledgment
3797
         * Present in:
3798
         *   pre-2000 models
3799
         * Not Present in:
3800
         *   Copernicus II (2009)
3801
         *   ICM SMT 360 (2018)
3802
         *   RES SMT 360 (2018)
3803
         */
3804
10
        FALLTHROUGH
3805
11
    case 0x82:
3806
        /* Decoder Diagnostic Information Report
3807
         * Present in:
3808
         *   pre-2000 models
3809
         * Not Present in:
3810
         *   Copernicus II (2009)
3811
         *   ICM SMT 360 (2018)
3812
         *   RES SMT 360 (2018)
3813
         */
3814
11
        FALLTHROUGH
3815
11
    case 0x84:
3816
        /* Satellite FFT Control Acknowledgment x8f-84
3817
         * Present in:
3818
         *   pre-2000 models
3819
         * Not Present in:
3820
         *   Copernicus II (2009)
3821
         *   ICM SMT 360 (2018)
3822
         *   RES SMT 360 (2018)
3823
         */
3824
11
        FALLTHROUGH
3825
11
    case 0x85:
3826
        /* DGPS Source Tracking Status Report
3827
         * Present in:
3828
         *   pre-2000 models
3829
         * Not Present in:
3830
         *   Copernicus II (2009)
3831
         *   ICM SMT 360 (2018)
3832
         *   RES SMT 360 (2018)
3833
         */
3834
11
        FALLTHROUGH
3835
11
    case 0x86:
3836
        /* Clear Satellite Database Acknowledgment
3837
         * Present in:
3838
         *   pre-2000 models
3839
         * Not Present in:
3840
         *   Copernicus II (2009)
3841
         *   ICM SMT 360 (2018)
3842
         *   RES SMT 360 (2018)
3843
         */
3844
11
        FALLTHROUGH
3845
11
    case 0x87:
3846
        /* Network Statistics Report
3847
         * Present in:
3848
         *   pre-2000 models
3849
         * Not Present in:
3850
         *   Copernicus II (2009)
3851
         *   ICM SMT 360 (2018)
3852
         *   RES SMT 360 (2018)
3853
         */
3854
11
        FALLTHROUGH
3855
11
    case 0x88:
3856
        /* Diagnostic Output Options Report
3857
         * Present in:
3858
         *   pre-2000 models
3859
         * Not Present in:
3860
         *   Copernicus II (2009)
3861
         *   ICM SMT 360 (2018)
3862
         *   RES SMT 360 (2018)
3863
         */
3864
11
        FALLTHROUGH
3865
11
    case 0x89:
3866
        /* DGPS Source Control Report /Acknowledgment
3867
         * Present in:
3868
         *   pre-2000 models
3869
         * Not Present in:
3870
         *   Copernicus II (2009)
3871
         *   ICM SMT 360 (2018)
3872
         *   RES SMT 360 (2018)
3873
         */
3874
11
        FALLTHROUGH
3875
11
    case 0x8a:
3876
        /* Service Provider Information Report and Acknowledgment
3877
         * Present in:
3878
         *   pre-2000 models
3879
         * Not Present in:
3880
         *   Copernicus II (2009)
3881
         *   ICM SMT 360 (2018)
3882
         *   RES SMT 360 (2018)
3883
         */
3884
11
        FALLTHROUGH
3885
11
    case 0x8b:
3886
        /* Service Provider Activation Information Report & Acknowledgment
3887
         * Present in:
3888
         *   pre-2000 models
3889
         * Not Present in:
3890
         *   Copernicus II (2009)
3891
         *   ICM SMT 360 (2018)
3892
         *   RES SMT 360 (2018)
3893
         */
3894
11
        FALLTHROUGH
3895
11
    case 0x8e:
3896
        /* Service Provider Data Load Report
3897
         * Present in:
3898
         *   pre-2000 models
3899
         * Not Present in:
3900
         *   Copernicus II (2009)
3901
         *   ICM SMT 360 (2018)
3902
         *   RES SMT 360 (2018)
3903
         */
3904
11
        FALLTHROUGH
3905
16
    case 0x8f:
3906
        /* Receiver Identity Report
3907
         * Present in:
3908
         *   pre-2000 models
3909
         * Not Present in:
3910
         *   Copernicus II (2009)
3911
         *   ICM SMT 360 (2018)
3912
         *   RES SMT 360 (2018)
3913
         */
3914
16
        FALLTHROUGH
3915
17
    case 0x90:
3916
        /* Guidance Status Report
3917
         * Present in:
3918
         *   pre-2000 models
3919
         * Not Present in:
3920
         *   Copernicus II (2009)
3921
         *   ICM SMT 360 (2018)
3922
         *   RES SMT 360 (2018)
3923
         */
3924
17
        FALLTHROUGH
3925
18
    case 0x91:
3926
        /* Guidance Configuration Report
3927
         * Present in:
3928
         *   pre-2000 models
3929
         * Not Present in:
3930
         *   Copernicus II (2009)
3931
         *   ICM SMT 360 (2018)
3932
         *   RES SMT 360 (2018)
3933
         */
3934
18
        FALLTHROUGH
3935
19
    case 0x92:
3936
        /* Lightbar Configuration Report
3937
         * Present in:
3938
         *   pre-2000 models
3939
         * Not Present in:
3940
         *   Copernicus II (2009)
3941
         *   ICM SMT 360 (2018)
3942
         *   RES SMT 360 (2018)
3943
         */
3944
19
        FALLTHROUGH
3945
19
    case 0x94:
3946
        /* Guidance Operation Acknowledgment
3947
         * Present in:
3948
         *   pre-2000 models
3949
         * Not Present in:
3950
         *   Copernicus II (2009)
3951
         *   ICM SMT 360 (2018)
3952
         *   RES SMT 360 (2018)
3953
         */
3954
19
        FALLTHROUGH
3955
19
    case 0x95:
3956
        /* Button Box Configuration Type Report
3957
         * Present in:
3958
         *   pre-2000 models
3959
         * Not Present in:
3960
         *   Copernicus II (2009)
3961
         *   ICM SMT 360 (2018)
3962
         *   RES SMT 360 (2018)
3963
         */
3964
19
        FALLTHROUGH
3965
19
    case 0x96:
3966
        /* Point Manipulation Report
3967
         * Present in:
3968
         *   pre-2000 models
3969
         * Not Present in:
3970
         *   Copernicus II (2009)
3971
         *   ICM SMT 360 (2018)
3972
         *   RES SMT 360 (2018)
3973
         */
3974
19
        FALLTHROUGH
3975
19
    case 0x97:
3976
        /* Utility Information Report
3977
         * Present in:
3978
         *   pre-2000 models
3979
         * Not Present in:
3980
         *   Copernicus II (2009)
3981
         *   ICM SMT 360 (2018)
3982
         *   RES SMT 360 (2018)
3983
         */
3984
19
        FALLTHROUGH
3985
20
    case 0x98:
3986
        /* Individual Button Configuration Report
3987
         * Present in:
3988
         *   pre-2000 models
3989
         * Not Present in:
3990
         *   Copernicus II (2009)
3991
         *   ICM SMT 360 (2018)
3992
         *   RES SMT 360 (2018)
3993
         */
3994
20
        FALLTHROUGH
3995
20
    case 0x9a:
3996
        /* Differential Correction Information Report
3997
         * Present in:
3998
         *   pre-2000 models
3999
         * Not Present in:
4000
         *   Copernicus II (2009)
4001
         *   ICM SMT 360 (2018)
4002
         *   RES SMT 360 (2018)
4003
         */
4004
20
        FALLTHROUGH
4005
20
    case 0xa0:
4006
        /* DAC value
4007
         * Present in:
4008
         *   ICM SMT 360 (2018)
4009
         *   RES SMT 360 (2018)
4010
         * Not Present in:
4011
         *   pre-2000 models
4012
         *   Copernicus II (2009)
4013
         */
4014
20
        FALLTHROUGH
4015
20
    case 0xa2:
4016
        /* UTC/GPS timing
4017
         * Present in:
4018
         *   ICM SMT 360 (2018)
4019
         *   RES SMT 360 (2018)
4020
         * Not Present in:
4021
         *   pre-2000 models
4022
         *   Copernicus II (2009)
4023
         */
4024
20
        FALLTHROUGH
4025
20
    case 0xa3:
4026
        /* Oscillator disciplining command
4027
         * Present in:
4028
         *   ICM SMT 360 (2018)
4029
         *   RES SMT 360 (2018)
4030
         * Not Present in:
4031
         *   pre-2000 models
4032
         *   Copernicus II (2009)
4033
         */
4034
20
        FALLTHROUGH
4035
20
    case 0xa8:
4036
        /* Oscillator disciplining parameters
4037
         * Present in:
4038
         *   ICM SMT 360 (2018)
4039
         *   RES SMT 360 (2018)
4040
         * Not Present in:
4041
         *   pre-2000 models
4042
         *   Copernicus II (2009)
4043
         */
4044
20
        FALLTHROUGH
4045
89
    default:
4046
89
        GPSD_LOG(LOG_WARN, &session->context->errout,
4047
1.60k
                 "TSIP x8f-%02x: Unhandled TSIP superpacket\n", u1);
4048
1.60k
    }
4049
1.60k
    *pbad_len = bad_len;
4050
4051
1.60k
    return mask;
4052
1.60k
}
4053
4054
// Decode Protocol Versi/on: x90-00
4055
static gps_mask_t decode_x90_00(struct gps_device_t *session, const char *buf)
4056
4
{
4057
4
    gps_mask_t mask = 0;
4058
4059
4
    unsigned u1 = getub(buf, 4);              // NMEA Major version
4060
4
    unsigned u2 = getub(buf, 5);              // NMEA Minor version
4061
4
    unsigned u3 = getub(buf, 6);              // TSIP version
4062
4
    unsigned u4 = getub(buf, 7);              // Trimble NMEA version
4063
4
    unsigned long u6 = getbeu32(buf, 8);      // reserved
4064
4
    unsigned u7 = getub(buf, 12);             // reserved
4065
4
    GPSD_LOG(LOG_PROG, &session->context->errout,
4066
4
             "TSIPv1 x90-00: NMEA %u.%u TSIP %u TNMEA %u "
4067
4
             "res x%04lx x%02x \n",
4068
4
             u1, u2, u3, u4, u6, u7);
4069
4
    return mask;
4070
4
}
4071
4072
/* Receiver Version Information, x90-01
4073
 * Received in response to TSIPv1 probe
4074
 */
4075
static gps_mask_t decode_x90_01(struct gps_device_t *session, const char *buf,
4076
                                int len)
4077
11
{
4078
11
    gps_mask_t mask = 0;
4079
11
    char buf2[BUFSIZ];
4080
4081
11
    unsigned u1 = getub(buf, 4);               // Major version
4082
11
    unsigned u2 = getub(buf, 5);               // Minor version
4083
11
    unsigned u3 = getub(buf, 6);               // Build number
4084
11
    unsigned u4 = getub(buf, 7);               // Build month
4085
11
    unsigned u5 = getub(buf, 8);               // Build day
4086
11
    unsigned u6 = getbeu16(buf, 9);            // Build year
4087
11
    unsigned u7 = getbeu16(buf, 11);           // Hardware ID
4088
11
    unsigned u8 = getub(buf, 13);              // Product Name length
4089
4090
11
    session->driver.tsip.hardware_code = u7;
4091
    // check for valid module name length
4092
    // RES720 is 27 long
4093
    // check for valid module name length, again
4094
11
    if (40 < u8) {
4095
11
        u8 = 40;
4096
11
    }
4097
11
    if ((int)u8 > (len - 13)) {
4098
0
        u8 = len - 13;
4099
0
    }
4100
11
    memcpy(buf2, &buf[14], u8);
4101
11
    buf2[u8] = '\0';
4102
11
    (void)snprintf(session->subtype, sizeof(session->subtype),
4103
11
                   "fw %u.%u %u %02u/%02u/%04u %.40s",
4104
11
                   u1, u2, u3, u6, u5, u4, buf2);
4105
11
    GPSD_LOG(LOG_PROG, &session->context->errout,
4106
11
             "TSIPv1 x90-01: Version %u.%u Build %u %u/%u/%u hwid %u, "
4107
11
             "%.*s[%u]\n",
4108
11
             u1, u2, u3, u6, u5, u4, u7, u8, buf2, u8);
4109
11
    mask |= DEVICEID_SET;
4110
11
    return mask;
4111
11
}
4112
4113
// Decode, Port Configuration: x91-00
4114
static gps_mask_t decode_x91_00(struct gps_device_t *session, const char *buf)
4115
1
{
4116
1
    gps_mask_t mask = 0;
4117
4118
1
    unsigned u1 = getub(buf, 4);               // port
4119
1
    unsigned u2 = getub(buf, 5);               // port type
4120
1
    unsigned u3 = getub(buf, 6);               // protocol
4121
1
    unsigned u4 = getub(buf, 7);               // baud rate
4122
1
    unsigned u5 = getub(buf, 8);               // data bits
4123
1
    unsigned u6 = getub(buf, 9);               // parity
4124
1
    unsigned u7 = getub(buf, 10);              // stop bits
4125
1
    unsigned long u8 = getbeu32(buf, 11);      // reserved
4126
1
    unsigned long u9 = getbeu32(buf, 12);      // reserved
4127
4128
1
    GPSD_LOG(LOG_PROG, &session->context->errout,
4129
1
             "TSIPv1 x91-00: port %u type %u proto %u baud %u bits %u "
4130
1
             "parity %u stop %u res x%04lx %04lx\n",
4131
1
             u1, u2, u3, u4, u5, u6, u7, u8, u9);
4132
1
    GPSD_LOG(LOG_IO, &session->context->errout,
4133
1
             "TSIPv1: port:%s type:%s, proto:%s speed:%s bits:%s %s %s\n",
4134
1
             val2str(u1, vport_name1),
4135
1
             val2str(u2, vport_type1),
4136
1
             val2str(u3, vprotocol1),
4137
1
             val2str(u4, vspeed1),
4138
1
             val2str(u5, vdbits1),
4139
1
             val2str(u6, vparity1),
4140
1
             val2str(u6, vstop1));
4141
1
    return mask;
4142
1
}
4143
4144
// Decode GNSS COnfiguration: x91-01
4145
static gps_mask_t decode_x91_01(struct gps_device_t *session, const char *buf)
4146
11
{
4147
11
    gps_mask_t mask = 0;
4148
11
    char buf2[BUFSIZ];
4149
4150
    /* constellations, 0 to 26, mashup of constellation and signal
4151
     * ignore if 0xffffffff */
4152
11
    unsigned long cons = getbeu32(buf, 4);     // constellations
4153
11
    double d1 = getbef32(buf, 8);              // elevation mask
4154
11
    double d2 = getbef32(buf, 12);             // signal mask
4155
11
    double d3 = getbef32(buf, 16);             // PDOP mask
4156
    // anti-jamming, always enabled in RES 720
4157
11
    unsigned u2 = getub(buf, 20);
4158
11
    unsigned u3 = getub(buf, 21);              // fix rate
4159
11
    double d4 = getbef32(buf, 22);             // Antenna CAble delay, seconds
4160
11
    unsigned long u4 = getbeu32(buf, 26);      // reserved
4161
4162
11
    GPSD_LOG(LOG_PROG, &session->context->errout,
4163
11
             "TSIPv1 x91-01 cons x%lx el %f signal %f PDOP %f jam %u "
4164
11
             "frate %u delay %f res x%04lx\n",
4165
11
             cons, d1, d2, d3, u2, u3, d4, u4);
4166
11
    GPSD_LOG(LOG_IO, &session->context->errout,
4167
11
             "TSIPv1: cons %s\n",
4168
11
             flags2str(cons, vsv_types1, buf2, sizeof(buf2)));
4169
11
    return mask;
4170
11
}
4171
4172
// Decode NVS Configuration, x91-02
4173
static gps_mask_t decode_x91_02(struct gps_device_t *session, const char *buf)
4174
2
{
4175
2
    gps_mask_t mask = 0;
4176
2
    char buf2[20];
4177
4178
2
    unsigned u1 = getub(buf, 6);               // status
4179
2
    unsigned long u2 = getbeu32(buf, 7);            // reserved
4180
4181
2
    GPSD_LOG(LOG_PROG, &session->context->errout,
4182
2
             "TSIPv1 x91-02: status %u res x%04lx\n",
4183
2
             u1, u2);
4184
2
    GPSD_LOG(LOG_IO, &session->context->errout,
4185
2
             "TSIPv1: Status:%s\n",
4186
2
             flags2str(u1, vsave_status1, buf2, sizeof(buf2)));
4187
2
    return mask;
4188
2
}
4189
4190
// Decode Timing Configuration: x91-03
4191
static gps_mask_t decode_x91_03(struct gps_device_t *session, const char *buf)
4192
5
{
4193
5
    gps_mask_t mask = 0;
4194
4195
5
    unsigned tbase = getub(buf, 4);               // time base
4196
5
    unsigned pbase = getub(buf, 5);               // PPS base
4197
5
    unsigned pmask = getub(buf, 6);               // PPS mask
4198
5
    unsigned res = getbeu16(buf, 7);              // reserved
4199
5
    unsigned pwidth = getbeu16(buf, 9);           // PPS width
4200
5
    double  poffset = getbed64(buf, 11);          // PPS offset, in seconds
4201
4202
5
    GPSD_LOG(LOG_PROG, &session->context->errout,
4203
5
             "TSIPv1 x91-03: time base %u PPS base %u mask %u res x%04x "
4204
5
             "width %u offset %f\n",
4205
5
             tbase, pbase, pmask, res, pwidth, poffset);
4206
5
    GPSD_LOG(LOG_IO, &session->context->errout,
4207
5
             "TSIPv1: time base:%s pps base:%s pps mask:%s\n",
4208
5
             val2str(tbase, vtime_base1),
4209
5
             val2str(pbase, vtime_base1),
4210
5
             val2str(pmask, vpps_mask1));
4211
5
    return mask;
4212
5
}
4213
4214
// Decode Self Survey Copnfiguration: x91-04
4215
static gps_mask_t decode_x91_04(struct gps_device_t *session, const char *buf)
4216
0
{
4217
0
    gps_mask_t mask = 0;
4218
0
    char buf2[BUFSIZ];
4219
4220
0
    unsigned u1 = getub(buf, 4);               // self-survey mask
4221
0
    unsigned long u2 = getbeu32(buf, 5);       // self-survey length, # fixes
4222
0
    unsigned u3 = getbeu16(buf, 9);            // horz uncertainty, meters
4223
0
    unsigned u4 = getbeu16(buf, 11);           // vert uncertainty, meters
4224
4225
0
    GPSD_LOG(LOG_PROG, &session->context->errout,
4226
0
             "TSIPv1 x91-04: mask x%x length %lu eph %u epv %u\n",
4227
0
             u1, u2, u3, u4);
4228
0
    GPSD_LOG(LOG_IO, &session->context->errout,
4229
0
             "TSIPv1:ssmask %s\n",
4230
0
             flags2str(u1, vss_mask1, buf2, sizeof(buf2)));
4231
0
    return mask;
4232
0
}
4233
4234
// Decode Receiver COnfiguration: x91-05
4235
static gps_mask_t decode_x91_05(struct gps_device_t *session, const char *buf)
4236
0
{
4237
0
    gps_mask_t mask = 0;
4238
4239
0
    unsigned port = getub(buf, 4);              // port
4240
0
    unsigned long otype = getbeu32(buf, 5);     // type of output
4241
0
    unsigned long res1 = getbeu32(buf, 9);      // reserved
4242
0
    unsigned long res2 = getbeu32(buf, 13);     // reserved
4243
0
    unsigned long res3 = getbeu32(buf, 17);     // reserved
4244
4245
0
    GPSD_LOG(LOG_PROG, &session->context->errout,
4246
0
             "TSIPv1 x91-05: port %u type x%04lx res x%04lx x%04lx x%04lx\n",
4247
0
             port, otype, res1, res2, res3);
4248
0
    GPSD_LOG(LOG_IO, &session->context->errout,
4249
0
             "TSIPv1: port %s xa1-00: %lu xa1-03: %lu xa1-11: %lu "
4250
0
             "xa1-00: %lu  xa3-00: %lu  xa3-11: %lu\n",
4251
0
             val2str(port, vport_name1),
4252
0
             otype & 3, (otype >> 2) & 3, (otype >> 4) & 3,
4253
0
            (otype >> 6) & 3, (otype >> 8) & 3, (otype >> 10) & 3);
4254
0
    return mask;
4255
0
}
4256
4257
// Decode Receiver Reset: x92-01
4258
static gps_mask_t decode_x92_01(struct gps_device_t *session, const char *buf)
4259
0
{
4260
0
    gps_mask_t mask = 0;
4261
0
    unsigned u1 = getub(buf, 6);               // reset cause
4262
4263
0
    GPSD_LOG(LOG_WARN, &session->context->errout,
4264
0
             "TSIPv1 x92-01: cause %u\n", u1);
4265
0
    GPSD_LOG(LOG_IO, &session->context->errout,
4266
0
             "TSIPv1: cause:%s\n",
4267
0
             val2str(u1, vreset_type1));
4268
0
    return mask;
4269
0
}
4270
4271
// Decode Production Information: x93-00
4272
static gps_mask_t decode_x93_00(struct gps_device_t *session, const char *buf)
4273
0
{
4274
0
    gps_mask_t mask = 0;
4275
0
    char buf2[BUFSIZ];
4276
0
    char buf3[BUFSIZ];
4277
4278
0
    unsigned u1 = getub(buf, 4);                // reserved. always 0xff
4279
0
    unsigned long u2 = getbeu32(buf, 5);        // serial number
4280
0
    unsigned long long u3 = getbeu64(buf, 9);   // extended serial number
4281
0
    unsigned long long u4 = getbeu64(buf, 17);  // extended serial number
4282
0
    unsigned u5 = getub(buf, 25);               // build day
4283
0
    unsigned u6 = getub(buf, 26);               // build month
4284
0
    unsigned u7 = getbeu16(buf, 27);            // build year
4285
0
    unsigned u8 = getub(buf, 29);               // build hour
4286
0
    unsigned u9 = getbeu16(buf, 30);            // machine id
4287
    // getbeu64(buf, 32);             // hardware ID string
4288
    // getbeu64(buf, 40);             // hardware ID string
4289
    // getbeu64(buf, 48);             // product ID string
4290
    // getbeu64(buf, 56);             // product ID string
4291
0
    unsigned long u10 = getbeu32(buf, 64);       // premium options
4292
0
    unsigned long u11 = getbeu32(buf, 78);       // reserved
4293
    // ignore 77 Osc search range, and 78–81 Osc offset, always 0xff
4294
4295
0
    (void)snprintf(session->subtype1, sizeof(session->subtype1),
4296
0
                   "hw %u %02u/%02u/%04u",
4297
0
                   u9, u5, u6, u7);
4298
    // The sernum I get does not match the printed one on the device...
4299
    // extended sernum seems to be zeros...
4300
0
    (void)snprintf(session->gpsdata.dev.sernum,
4301
0
                   sizeof(session->gpsdata.dev.sernum),
4302
0
                   "%lx", u2);
4303
0
    GPSD_LOG(LOG_WARN, &session->context->errout,
4304
0
             "TSIPv1 x93-00: res %u ser %s x%llx-%llx Build %u/%u/%u %u "
4305
0
             "machine %u hardware %s product %s "
4306
0
             "options x%04lx res x%04lx\n",
4307
0
             u1, session->gpsdata.dev.sernum,
4308
0
             u3, u4, u7, u6, u5, u8, u9,
4309
0
             gpsd_packetdump(buf2, sizeof(buf2),
4310
0
                            (const unsigned char *)&buf[32], 16),
4311
0
             gpsd_packetdump(buf3, sizeof(buf3),
4312
0
                            (const unsigned char *)&buf[48], 16),
4313
0
             u10, u11);
4314
0
    mask |= DEVICEID_SET;
4315
0
    return mask;
4316
0
}
4317
4318
// Decode xa0-00
4319
static gps_mask_t decode_xa0_00(struct gps_device_t *session, const char *buf,
4320
                                int len)
4321
0
{
4322
0
    gps_mask_t mask = 0;
4323
0
    unsigned u1, u2, u3;
4324
4325
0
    switch (len) {
4326
0
    case 3:
4327
0
        u1 = getub(buf, 6);               // command
4328
0
        GPSD_LOG(LOG_PROG, &session->context->errout,
4329
0
                 "TSIPv1 xa0-00: command %u\n", u1);
4330
0
        break;
4331
0
    case 8:
4332
        // ACK/NAK
4333
0
        u1 = getub(buf, 6);               // command
4334
0
        u2 = getub(buf, 7);               // status
4335
0
        u3 = getbeu16(buf, 8);            // frame
4336
0
        GPSD_LOG(LOG_PROG, &session->context->errout,
4337
0
                 "TSIPv1 xa0-00: command %u status %u frame %u\n",
4338
0
                 u1, u2, u3);
4339
0
        break;
4340
0
    default:
4341
0
        GPSD_LOG(LOG_WARN, &session->context->errout,
4342
0
                 "TSIPv1 xa0-00: bad length %d\n", len);
4343
0
        break;
4344
0
    }
4345
0
    return mask;
4346
0
}
4347
4348
// Decode xa1-00
4349
static gps_mask_t decode_xa1_00(struct gps_device_t *session, const char *buf)
4350
2
{
4351
2
    gps_mask_t mask = 0;
4352
2
    char buf2[BUFSIZ];
4353
2
    unsigned u1, u2, u3;
4354
2
    int s1;
4355
2
    double d1, d2, d3;
4356
2
    struct tm date = {0};
4357
4358
2
    unsigned tow = getbeu32(buf, 4);
4359
2
    unsigned week = getbeu16(buf, 8);
4360
4361
2
    session->context->gps_week = week;
4362
4363
2
    date.tm_hour = getub(buf, 10);               // hours 0 - 23
4364
2
    date.tm_min = getub(buf, 11);                // minutes 0 -59
4365
2
    date.tm_sec = getub(buf, 12);                // seconds 0 - 60
4366
2
    date.tm_mon = getub(buf, 13) - 1;            // month 1 - 12
4367
2
    date.tm_mday = getub(buf, 14);               // day of month 1 - 31
4368
2
    date.tm_year = getbeu16(buf, 15) - 1900;     // year
4369
4370
2
    u1 = getub(buf, 17);                // time base
4371
2
    u2 = getub(buf, 18);                // PPS base
4372
2
    u3 = getub(buf, 19);                // flags
4373
2
    s1 = getbes16(buf, 20);             // UTC Offset
4374
2
    d1 = getbef32(buf, 22);             // PPS Quantization Error
4375
2
    d2 = getbef32(buf, 26);             // Bias
4376
2
    d3 = getbef32(buf, 30);             // Bias Rate
4377
4378
    // convert seconds to pico seconds
4379
2
    session->gpsdata.qErr = (long)(d1 * 10e12);
4380
    // fix.time is w/o leap seconds...
4381
2
    session->newdata.time.tv_sec = mkgmtime(&date) - s1;
4382
2
    session->newdata.time.tv_nsec = 0;
4383
4384
2
    session->context->leap_seconds = s1;
4385
2
    session->context->valid |= LEAP_SECOND_VALID;
4386
2
    GPSD_LOG(LOG_PROG, &session->context->errout,
4387
2
             "TSIPv1 xa1-00: tow %u week %u %02u:%02u:%02u %4u/%02u/%02u "
4388
2
             "tbase %u/%u tflags x%x UTC offset %d qErr %f Bias %f/%f\n",
4389
2
             tow, week, date.tm_hour, date.tm_min, date.tm_sec,
4390
2
             date.tm_year + 1900, date.tm_mon, date.tm_mday,
4391
2
             u1, u2, u3, s1, d1, d2, d3);
4392
2
    GPSD_LOG(LOG_IO, &session->context->errout,
4393
2
             "TSIPv1: tbase:%s pbase:%s tflags:%s\n",
4394
2
             val2str(u1, vtime_base1),
4395
2
             val2str(u2, vtime_base1),
4396
2
             flags2str(u3, vtime_flags1, buf2, sizeof(buf2)));
4397
4398
2
    if (2 == (u3 & 2)) {
4399
        // flags say we have good time
4400
        // if we have good time, can we guess at fix mode?
4401
1
        mask |= TIME_SET;
4402
1
        if (1 == (u3 & 1)) {
4403
            // good UTC
4404
0
            mask |= NTPTIME_IS;
4405
0
        }
4406
1
    }
4407
2
    if (0 == session->driver.tsip.hardware_code) {
4408
        // Query Receiver Version Information
4409
2
        (void)tsip_write1(session, "\x90\x01\x00\x02\x00\x93", 6);
4410
2
    }
4411
2
    mask |= CLEAR_IS;  // ssems to always be first. Time to clear.
4412
2
    return mask;
4413
2
}
4414
4415
// Decode packet xa1-02
4416
static gps_mask_t decode_xa1_02(struct gps_device_t *session, const char *buf)
4417
0
{
4418
0
    gps_mask_t mask = 0;
4419
4420
0
    double d1 = getbef32(buf, 6);               // DAC voltage
4421
0
    unsigned u1 = getbeu16(buf, 10);            // DAC value
4422
0
    unsigned u2 = getub(buf, 12);               // holdover status
4423
0
    unsigned u3 = getbeu32(buf, 13);            // holdover time
4424
4425
0
    session->newdata.temp = getbef32(buf, 17);  // Temperature, degrees C
4426
0
    GPSD_LOG(LOG_PROG, &session->context->errout,
4427
0
             "TSIPv1 xa1-02: DAC voltage %f value %u Holdover status %u "
4428
0
             "time %u temp %f\n",
4429
0
             d1, u1, u2, u3, session->newdata.temp);
4430
0
    return mask;
4431
0
}
4432
4433
// Decode packet Position Information, xa1-11
4434
static gps_mask_t decode_xa1_11(struct gps_device_t *session, const char *buf)
4435
0
{
4436
0
    gps_mask_t mask = 0;
4437
0
    char buf2[BUFSIZ];
4438
4439
0
    unsigned pmask = getub(buf, 4);            // position mask
4440
0
    unsigned ftype = getub(buf, 5);            // fix type
4441
0
    double d1 = getbed64(buf, 6);              // latitude or X
4442
0
    double d2  = getbed64(buf, 14);            // longitude or Y
4443
0
    double d3  = getbed64(buf, 22);            // altitude or Z
4444
0
    double d4  = getbef32(buf, 30);            // velocity X or E
4445
0
    double d5  = getbef32(buf, 34);            // velocity Y or N
4446
0
    double d6  = getbef32(buf, 38);            // velocity Z or U
4447
4448
0
    double pdop = getbef32(buf, 42);  // PDOP, surveyed/current
4449
4450
0
    if (IN(0.01, pdop, 89.99)) {
4451
        // why not to newdata?
4452
0
        session->gpsdata.dop.pdop = pdop;
4453
0
        mask |= DOP_SET;
4454
0
    }
4455
0
    session->newdata.eph = getbef32(buf, 46);  // eph, 0 - 100, unknown units
4456
0
    session->newdata.epv = getbef32(buf, 50);  // epv, 0 - 100, unknown units
4457
0
    mask |= DOP_SET;
4458
    // position mask bit 0 does not tell us if we are in OD mode
4459
0
    if (0 == (pmask & 2)) {
4460
        // LLA
4461
0
        session->newdata.latitude = d1;
4462
0
        session->newdata.longitude = d2;
4463
0
        if (0 == (pmask & 4)) {
4464
            // HAE
4465
0
            session->newdata.altHAE = d3;
4466
0
        } else {
4467
            // MSL
4468
0
            session->newdata.altMSL = d3;
4469
0
        }
4470
0
        mask |= LATLON_SET | ALTITUDE_SET;
4471
0
    } else {
4472
        // XYZ ECEF
4473
0
        session->newdata.ecef.x = d1;
4474
0
        session->newdata.ecef.y = d2;
4475
0
        session->newdata.ecef.z = d3;
4476
0
        mask |= ECEF_SET;
4477
0
    }
4478
0
    if (0 == (pmask & 1)) {
4479
        // valid velocity
4480
0
        if (0 == (pmask & 8)) {
4481
            // Velocity ENU
4482
0
            session->newdata.NED.velN = d5;
4483
0
            session->newdata.NED.velE = d4;
4484
0
            session->newdata.NED.velD = -d6;
4485
0
            mask |= VNED_SET;
4486
0
        } else {
4487
            // Velocity ECEF
4488
0
            session->newdata.ecef.vx = d4;
4489
0
            session->newdata.ecef.vy = d5;
4490
0
            session->newdata.ecef.vz = d6;
4491
0
            mask |= VECEF_SET;
4492
0
        }
4493
0
    }
4494
0
    switch (ftype) {
4495
0
    default:
4496
0
        FALLTHROUGH
4497
0
    case 0:
4498
0
        session->newdata.mode = MODE_NO_FIX;
4499
0
        break;
4500
0
    case 1:
4501
0
        session->newdata.mode = MODE_2D;
4502
0
        break;
4503
0
    case 2:
4504
0
        session->newdata.mode = MODE_3D;
4505
0
    }
4506
    // status NOT set
4507
0
    mask |= MODE_SET | DOP_SET | HERR_SET | VERR_SET;
4508
0
    GPSD_LOG(LOG_PROG, &session->context->errout,
4509
0
             "TSIPv1 xa1-11: mode %d status %d pmask %u fixt %u "
4510
0
             "Pos %f %f %f Vel %f %f %f PDOP %f eph %f epv %f\n",
4511
0
             session->newdata.mode,
4512
0
             session->newdata.status,
4513
0
             pmask, ftype, d1, d2, d3, d4, d5, d6,
4514
0
             pdop,
4515
0
             session->newdata.eph,
4516
0
             session->newdata.epv);
4517
0
    GPSD_LOG(LOG_IO, &session->context->errout,
4518
0
             "TSIPv1: mode:%s status:%s pmask:%s fixt %s\n",
4519
0
             val2str(session->newdata.mode, vmode_str),
4520
0
             val2str(session->newdata.status, vstatus_str),
4521
0
             flags2str(pmask, vpos_mask1, buf2, sizeof(buf2)),
4522
0
             val2str(ftype, vfix_type1));
4523
0
    return mask;
4524
0
}
4525
4526
// decode packet xa2-00
4527
static gps_mask_t decode_xa2_00(struct gps_device_t *session, const char *buf)
4528
2
{
4529
2
    gps_mask_t mask = 0;
4530
2
    timespec_t ts_tow;
4531
2
    unsigned char gnssid, sigid;
4532
2
    char buf2[BUFSIZ];
4533
4534
2
    unsigned u1 = getub(buf, 4);               // message number, 1 to X
4535
4536
    // SV type, 0 to 26, mashup of constellation and signal
4537
2
    unsigned u2 = getub(buf, 5);
4538
2
    unsigned prn = getub(buf, 6);              // PRN (svid) 1 to 32 (99)
4539
2
    double az = getbef32(buf, 7);              // azimuth, degrees
4540
2
    double el = getbef32(buf, 11);             // elevation, degrees
4541
2
    double d3 = getbef32(buf, 15);             // signal level, db-Hz
4542
2
    unsigned u4 = getbeu32(buf, 19);           // Flags
4543
    // TOW of measurement, not current TOW!
4544
2
    unsigned tow = getbeu32(buf, 23);          // TOW, seconds
4545
4546
2
    if (0 == u1) {
4547
2
        GPSD_LOG(LOG_WARN, &session->context->errout,
4548
2
                "TSIPv1 xa2-00: invalid message number %u\n", u1);
4549
2
        return 0;
4550
2
    } else if (1 == u1) {
4551
        // message number starts at 1, no way to know last number
4552
0
        gpsd_zero_satellites(&session->gpsdata);
4553
        // start of new cycle, save last count
4554
0
        session->gpsdata.satellites_visible =
4555
0
            session->driver.tsip.last_chan_seen;
4556
0
    } else if (TSIP_CHANNELS < u1) {
4557
0
        GPSD_LOG(LOG_WARN, &session->context->errout,
4558
0
                "TSIPv1 xa2-00: too many satellites %d\n", u1);
4559
0
        return 0;
4560
0
    } else if (0 == prn ||
4561
0
               99 < prn) {
4562
0
        GPSD_LOG(LOG_WARN, &session->context->errout,
4563
0
                "TSIPv1 xa2-00: invalid prn %d\n", prn);
4564
0
        return 0;
4565
0
    }
4566
0
    session->driver.tsip.last_chan_seen = u1;
4567
0
    session->driver.tsip.last_a200 = tow;
4568
0
    ts_tow.tv_sec = tow;
4569
0
    ts_tow.tv_nsec = 0;
4570
0
    session->gpsdata.skyview_time =
4571
0
            gpsd_gpstime_resolv(session, session->context->gps_week,
4572
0
                                ts_tow);
4573
4574
    // convert svtype to gnssid and svid
4575
0
    gnssid = tsipv1_svtype(u2, &sigid);
4576
0
    session->gpsdata.skyview[u1 - 1].gnssid = gnssid;
4577
0
    session->gpsdata.skyview[u1 - 1].svid = prn;
4578
0
    session->gpsdata.skyview[u1 - 1].sigid = sigid;
4579
    // "real" NMEA 4.0 (not 4.10 ir 4.11) PRN
4580
0
    session->gpsdata.skyview[u1 - 1].PRN = ubx2_to_prn(gnssid, prn);
4581
0
    if (0 >= session->gpsdata.skyview[u1 - 1].PRN) {
4582
        // bad PRN??
4583
0
        GPSD_LOG(LOG_WARN, &session->context->errout,
4584
0
                 "TSIPv1 xa2-00(%u): Bad PRN: gnssid %u, prn %u PRN %d\n",
4585
0
                 u1, gnssid, prn, session->gpsdata.skyview[u1 - 1].PRN);
4586
0
    }
4587
0
    if (0 != (1 & u4)) {
4588
0
        if (90.0 >= fabs(el)) {
4589
0
            session->gpsdata.skyview[u1 - 1].elevation = el;
4590
0
        }
4591
0
        if (360.0 > az &&
4592
0
            0.0 <= az) {
4593
0
            session->gpsdata.skyview[u1 - 1].azimuth = az;
4594
0
        }
4595
0
    }
4596
0
    session->gpsdata.skyview[u1 - 1].ss = d3;
4597
0
    if (0 != (6 & u4)) {
4598
0
        session->gpsdata.skyview[u1 - 1].used = true;
4599
0
    }
4600
4601
0
    if ((int)u1 >= session->gpsdata.satellites_visible) {
4602
        /* Last of the series? Assume same number of sats as
4603
         * last cycle.
4604
         * This will cause extra SKY if this set has more
4605
         * sats than the last set.  Will cause drop outs when
4606
         * number of sats decreases. */
4607
0
        if (10 < llabs(session->driver.tsip.last_a311 -
4608
0
                       session->driver.tsip.last_a200)) {
4609
            // no xa3-11 in 10 seconds, so push out now
4610
0
            mask |= SATELLITE_SET;
4611
0
            session->driver.tsip.last_a200 = 0;
4612
0
        }
4613
0
    }
4614
0
    if (MAXCHANNELS < session->gpsdata.satellites_visible) {
4615
0
        GPSD_LOG(LOG_WARN, &session->context->errout,
4616
0
                "TSIPv1 xa2-00: too many satellites %d\n",
4617
0
                 session->gpsdata.satellites_visible);
4618
0
        session->gpsdata.satellites_visible = MAXCHANNELS;
4619
0
    }
4620
    /* If this series has fewer than last series there will
4621
     * be no SKY, unless the cycle ender pushes the SKY */
4622
0
    GPSD_LOG(LOG_PROG, &session->context->errout,
4623
0
             "TSIPv1 xa2-00: num %u type %u (gnss %u sigid %u) PRN %u "
4624
0
             "az %f el %f snr %f sflags x%0x4 tow %u\n",
4625
0
             u1, u2, gnssid, sigid, prn, az, el, d3, u4, tow);
4626
0
    GPSD_LOG(LOG_IO, &session->context->errout,
4627
0
             "TSIPv1: svtype:%s flags:%s\n",
4628
0
             val2str(u2, vsv_type1),
4629
0
             flags2str(u4, vsflags1, buf2, sizeof(buf2)));
4630
0
    return mask;
4631
2
}
4632
4633
4634
// decode System Alarms,  packet xa3-00
4635
static gps_mask_t decode_xa3_00(struct gps_device_t *session, const char *buf)
4636
0
{
4637
0
    gps_mask_t mask = 0;
4638
0
    char buf2[BUFSIZ];
4639
0
    char buf3[BUFSIZ];
4640
4641
0
    unsigned minor_alarm = getbeu32(buf, 4);            // Minor Alarms
4642
0
    unsigned res1 = getbeu32(buf, 8);                   // reserved
4643
0
    unsigned major_alarm = getbeu32(buf, 12);           // Major Alarms
4644
0
    unsigned res2 = getbeu32(buf, 16);                  // reserved
4645
4646
0
    if (1 & minor_alarm) {
4647
0
        session->newdata.ant_stat = ANT_OPEN;
4648
0
    } else if (2 & minor_alarm) {
4649
0
        session->newdata.ant_stat = ANT_SHORT;
4650
0
    } else {
4651
0
        session->newdata.ant_stat = ANT_OK;
4652
0
    }
4653
4654
0
    if (1 == (major_alarm & 1)) {
4655
        // not tracking sats, assume surveyed-in
4656
0
        session->newdata.status = STATUS_DR;
4657
0
    } else {
4658
0
        session->newdata.status = STATUS_GPS;
4659
0
    }
4660
0
    if (0x80 == (major_alarm & 0x80)) {
4661
        // jamming
4662
0
        session->newdata.jam = 255;
4663
0
    } else if (0x40 == (major_alarm & 0x40)) {
4664
        // spoofing/multipath
4665
0
        session->newdata.jam = 128;
4666
0
    }
4667
0
    mask |= STATUS_SET;
4668
4669
0
    GPSD_LOG(LOG_PROG, &session->context->errout,
4670
0
             "TSIPv1 xa3-00: Minor x%04x res x%04x Major x%04x "
4671
0
             "res x%04u status %d\n",
4672
0
             minor_alarm, res1, major_alarm, res2,
4673
0
             session->newdata.status);
4674
0
    GPSD_LOG(LOG_IO, &session->context->errout,
4675
0
             "TSIPv1: minor:%s mojor:%s status:%s\n",
4676
0
             flags2str(minor_alarm, vminor_alarms1, buf2, sizeof(buf2)),
4677
0
             flags2str(major_alarm, vmajor_alarms1, buf3, sizeof(buf3)),
4678
0
             val2str(session->newdata.status, vstatus_str));
4679
0
    return mask;
4680
0
}
4681
4682
// decode packet xa3-11
4683
static gps_mask_t decode_xa3_11(struct gps_device_t *session, const char *buf)
4684
0
{
4685
0
    gps_mask_t mask = 0;
4686
4687
0
    unsigned rec_mode = getub(buf, 4);                // receiver mode
4688
0
    unsigned rec_status = getub(buf, 5);              // status
4689
0
    unsigned ssp = getub(buf, 6);              // self survey progress 0 - 100
4690
4691
0
    double pdop = getbef32(buf, 7);     // PDOP
4692
0
    double hdop = getbef32(buf, 11);    // HDOP
4693
0
    double vdop = getbef32(buf, 15);    // VDOP
4694
0
    double tdop = getbef32(buf, 19);    // TDOP
4695
4696
0
    session->newdata.temp = getbef32(buf, 23);        // Temperature, degrees C
4697
4698
0
    if (IN(0.01, pdop, 89.99)) {
4699
        // why not to newdata?
4700
0
        session->gpsdata.dop.pdop = pdop;
4701
0
        mask |= DOP_SET;
4702
0
    }
4703
0
    if (IN(0.01, hdop, 89.99)) {
4704
        // why not to newdata?
4705
0
        session->gpsdata.dop.hdop = hdop;
4706
0
        mask |= DOP_SET;
4707
0
    }
4708
0
    if (IN(0.01, vdop, 89.99)) {
4709
        // why not to newdata?
4710
0
        session->gpsdata.dop.vdop = vdop;
4711
0
        mask |= DOP_SET;
4712
0
    }
4713
0
    if (IN(0.01, tdop, 89.99)) {
4714
        // why not to newdata?
4715
0
        session->gpsdata.dop.tdop = tdop;
4716
0
        mask |= DOP_SET;
4717
0
    }
4718
4719
    // don't have tow, so use the one from xa2-00, if any
4720
0
    session->driver.tsip.last_a311 = session->driver.tsip.last_a200;
4721
4722
0
    if (0 < session->driver.tsip.last_a200) {
4723
0
        session->driver.tsip.last_a200 = 0;
4724
        // TSIPv1 seem to be sent in numerical order, so this
4725
        // is after xa2-00 and the sats.  Push out any lingering sats.
4726
0
        mask |= SATELLITE_SET;
4727
0
    }
4728
0
    mask |= REPORT_IS;
4729
0
    switch (rec_status) {
4730
0
    case 0:         // 2D
4731
0
        session->newdata.mode = MODE_2D;
4732
0
        mask |= MODE_SET;
4733
0
        break;
4734
0
    case 1:         // 3D (time only)
4735
0
        session->newdata.mode = MODE_3D;
4736
0
        mask |= MODE_SET;
4737
0
        break;
4738
0
    case 3:         // Automatic (?)
4739
0
        break;
4740
0
    case 4:         // OD clock
4741
0
        session->newdata.status = STATUS_TIME;
4742
0
        mask |= STATUS_SET;
4743
0
        break;
4744
0
    default:        // Huh?
4745
0
        break;
4746
0
    }
4747
4748
0
    switch (rec_status) {
4749
0
    case 0:         // doing position fixes
4750
0
        FALLTHROUGH
4751
0
    case 4:         // using 1 sat
4752
0
        FALLTHROUGH
4753
0
    case 5:         // using 2 sat
4754
0
        FALLTHROUGH
4755
0
    case 6:         // using 3 sat
4756
0
        session->newdata.status = STATUS_GPS;
4757
0
        mask |= STATUS_SET;
4758
0
        break;
4759
0
    case 1:         // no GPS time
4760
0
        FALLTHROUGH
4761
0
    case 2:         // PDOP too high
4762
0
        FALLTHROUGH
4763
0
    case 3:         // no sats
4764
0
        session->newdata.status = STATUS_UNK;
4765
0
        mask |= STATUS_SET;
4766
0
        break;
4767
0
    case 255:
4768
0
        session->newdata.mode = MODE_3D;
4769
0
        session->newdata.status = STATUS_TIME;
4770
0
        mask |= STATUS_SET | MODE_SET;
4771
0
        break;
4772
0
    default:
4773
        // huh?
4774
0
        break;
4775
0
    }
4776
4777
0
    if (10.0 < pdop) {
4778
0
        session->newdata.status = STATUS_DR;
4779
0
        mask |= STATUS_SET;
4780
0
    }
4781
4782
0
    GPSD_LOG(LOG_PROG, &session->context->errout,
4783
0
             "TSIPv1 xa3-11: mode %d status %d rm %u stat %u survey %u "
4784
0
             "PDOP %f HDOP %f VDOP %f TDOP %f temp %f\n",
4785
0
             session->newdata.mode,
4786
0
             session->newdata.status,
4787
0
             rec_mode, rec_status, ssp,
4788
0
             pdop, hdop, vdop, tdop,
4789
0
             session->newdata.temp);
4790
0
    GPSD_LOG(LOG_IO, &session->context->errout,
4791
0
             "TSIPv1: mode:%s status:%s rm:%s stat:%s\n",
4792
0
             val2str(session->newdata.mode, vmode_str),
4793
0
             val2str(session->newdata.status, vstatus_str),
4794
0
             val2str(rec_mode, vrec_mode1),
4795
0
             val2str(rec_status, vgnss_decode_status1));
4796
4797
0
    return mask;
4798
0
}
4799
4800
// decode packet xa3-21
4801
static gps_mask_t decode_xa3_21(struct gps_device_t *session, const char *buf)
4802
0
{
4803
0
    gps_mask_t mask = 0;
4804
4805
0
    unsigned u1 = getub(buf, 4);            // reference packet id
4806
0
    unsigned u2 = getub(buf, 5);            // reference sub packet id
4807
0
    unsigned u3 = getub(buf, 6);            // error code
4808
4809
0
    GPSD_LOG(LOG_WARN, &session->context->errout,
4810
0
             "TSIPv1 xa3-21: id x%02x-%02x error: %u\n",
4811
0
             u1, u2, u3);
4812
0
    GPSD_LOG(LOG_IO, &session->context->errout,
4813
0
             "TSIPv1: ec:%s\n",
4814
0
             val2str(u3, verr_codes1));
4815
0
    return mask;
4816
0
}
4817
4818
// Decode xbb
4819
static gps_mask_t decode_xbb(struct gps_device_t *session, const char *buf)
4820
7
{
4821
7
    gps_mask_t mask = 0;
4822
7
    unsigned u1 = getub(buf, 0);        // Subcode, always zero?
4823
7
    unsigned u2 = getub(buf, 1);        // Operating Dimension (Receiver Mode)
4824
7
    unsigned u3 = getub(buf, 2);        // DGPS Mode (not in Acutime Gold)
4825
7
    unsigned u4 = getub(buf, 3);        // Dynamics Code
4826
7
    double f1 = getbef32(buf, 5);       // Elevation Mask
4827
7
    double f2 = getbef32(buf, 9);       // AMU Mask
4828
7
    double f3 = getbef32(buf, 13);      // DOP Mask
4829
7
    double f4 = getbef32(buf, 17);      // DOP Switch
4830
7
    unsigned u5 = getub(buf, 21);       // DGPS Age Limit (not in Acutime Gold)
4831
    /* Constellation
4832
     * bit 0 - GPS
4833
     * bit 1 - GLONASS
4834
     * bit 2 - reserved
4835
     * bit 3 - BeiDou
4836
     * bit 4 - Galileo
4837
     * bit 5 - QZSS
4838
     * bit 6 - reserved
4839
     * bit 7 - reserved
4840
     */
4841
    // RES SMT 360 defaults to Mode 7, Constellation 3
4842
7
    unsigned u6 = getub(buf, 27);
4843
4844
7
    GPSD_LOG(LOG_PROG, &session->context->errout,
4845
7
             "TSIP xbb: Navigation Configuration: %u %u %u %u %f %f %f "
4846
7
             "%f %u x%x\n",
4847
7
             u1, u2, u3, u4, f1, f2, f3, f4, u5, u6);
4848
7
    GPSD_LOG(LOG_IO, &session->context->errout,
4849
7
             "TSIP: rm %s\n",
4850
7
             val2str(u1, vrec_mode));
4851
7
    return mask;
4852
7
}
4853
4854
// decode packet xd0-00
4855
static gps_mask_t decode_xd0_00(struct gps_device_t *session, const char *buf)
4856
0
{
4857
0
    gps_mask_t mask = 0;
4858
4859
0
    unsigned u1 = getub(buf, 6);               // debug output type
4860
0
    GPSD_LOG(LOG_WARN, &session->context->errout,
4861
0
             "TSIPv1 xd0-00: debug %u\n", u1);
4862
4863
0
    return mask;
4864
0
}
4865
4866
// decode packet xd0-01
4867
static gps_mask_t decode_xd0_01(struct gps_device_t *session, const char *buf)
4868
0
{
4869
0
    gps_mask_t mask = 0;
4870
4871
0
    unsigned u1 = getub(buf, 6);               // debug type
4872
0
    unsigned u2 = getub(buf, 7);               // debug level
4873
4874
0
    GPSD_LOG(LOG_WARN, &session->context->errout,
4875
0
             "TSIPv1 xd0-01: debug type %u level %u\n", u1, u2);
4876
4877
0
    return mask;
4878
0
}
4879
4880
/* parse TSIP v1 packages.
4881
* Currently only in RES720 devices, from 2020 onward.
4882
* buf: raw data, with DLE stuffing removed
4883
* len:  length of data in buf
4884
*
4885
* return: mask
4886
*/
4887
static gps_mask_t tsipv1_parse(struct gps_device_t *session, unsigned id,
4888
                                const char *buf, int len)
4889
1.72k
{
4890
1.72k
    gps_mask_t mask = 0;
4891
1.72k
    unsigned sub_id, length, mode;
4892
1.72k
    unsigned u1;
4893
1.72k
    bool bad_len = false;
4894
1.72k
    unsigned char chksum;
4895
4896
1.72k
    if (4 > len) {
4897
        // should never happen
4898
382
        GPSD_LOG(LOG_WARN, &session->context->errout,
4899
382
                 "TSIPv1 0x%02x: runt, got len %u\n",
4900
382
                 id, len);
4901
382
        return mask;
4902
382
    }
4903
    /* Note: bug starts at sub id, offset 2 of the wire packet.
4904
     * So subtract 2 from the offsets in the Trimble doc. */
4905
1.33k
    sub_id = getub(buf, 0);
4906
1.33k
    length = getbeu16(buf, 1);  // expected length
4907
1.33k
    mode = getub(buf, 3);
4908
4909
1.33k
    if ((length + 3) != (unsigned)len) {
4910
150
        GPSD_LOG(LOG_WARN, &session->context->errout,
4911
150
                 "TSIPv1 x%02x-%02x: Bad Length, "
4912
150
                 "length got %d expected %u mode %u\n",
4913
150
                 id, sub_id, len, length + 3, mode);
4914
150
        return mask;
4915
150
    }
4916
4917
    // checksum is id, sub id, length, mode, data, not including trailer
4918
    // length is mode + data + checksum
4919
1.18k
    chksum = id;
4920
12.0k
    for (u1 = 0; u1 < (length + 3); u1++ ) {
4921
10.8k
        chksum ^= buf[u1];
4922
10.8k
    }
4923
1.18k
    if (0 != chksum) {
4924
155
        GPSD_LOG(LOG_WARN, &session->context->errout,
4925
155
                 "TSIPv1 x%02x-%02x: Bad Checksum "
4926
155
                 "length %d/%u mode %u\n",
4927
155
                 id, sub_id, len, length + 3, mode);
4928
155
        return mask;
4929
155
    }
4930
4931
1.03k
    GPSD_LOG(LOG_DATA, &session->context->errout,
4932
1.03k
             "TSIPv1 x%02x-%02x: length %d/%u mode %u\n",
4933
1.03k
             id, sub_id, len, length + 3, mode);
4934
4935
1.03k
    if (2 != mode) {
4936
        /* Don't decode queries (mode 0) or set (mode 1).
4937
         * Why would we even see one? */
4938
70
        return mask;
4939
70
    }
4940
    // FIXME: check len/length
4941
963
    switch ((id << 8) | sub_id) {
4942
83
    case 0x9000:
4943
        // Protocol Version, x90-00
4944
83
        if (11 > length) {
4945
79
            bad_len = true;
4946
79
            break;
4947
79
        }
4948
4
        mask = decode_x90_00(session, buf);
4949
4
        break;
4950
387
    case 0x9001:
4951
        /* Receiver Version Information, x90-01
4952
         * Received in response to the TSIPv1 probe */
4953
387
        if (11 > length) {
4954
376
            bad_len = true;
4955
376
            break;
4956
376
        }
4957
11
        mask = decode_x90_01(session, buf, len);
4958
11
        break;
4959
69
    case 0x9100:
4960
        // Port Configuration, x91-00
4961
69
        if (17 > length) {
4962
68
            bad_len = true;
4963
68
            break;
4964
68
        }
4965
1
        mask = decode_x91_00(session, buf);
4966
1
        break;
4967
77
    case 0x9101:
4968
        // GNSS Configuration, x91-01
4969
77
        if (28 > length) {
4970
66
            bad_len = true;
4971
66
            break;
4972
66
        }
4973
11
        mask = decode_x91_01(session, buf);
4974
11
        break;
4975
36
    case 0x9102:
4976
        // NVS Configuration, x91-02
4977
36
        if (8 > length) {
4978
34
            bad_len = true;
4979
34
            break;
4980
34
        }
4981
2
        mask = decode_x91_02(session, buf);
4982
2
        break;
4983
39
    case 0x9103:
4984
        // Timing Configuration, x91-03
4985
39
        if (19 > length) {
4986
34
            bad_len = true;
4987
34
            break;
4988
34
        }
4989
5
        mask = decode_x91_03(session, buf);
4990
5
        break;
4991
34
    case 0x9104:
4992
        // Self-Survey Configuration, x91-04
4993
34
        if (11 > length) {
4994
34
            bad_len = true;
4995
34
            break;
4996
34
        }
4997
0
        mask = decode_x91_04(session, buf);
4998
0
        break;
4999
66
    case 0x9105:
5000
        //  Receiver Configuration, xx91-05
5001
66
        if (19 > length) {
5002
66
            bad_len = true;
5003
66
            break;
5004
66
        }
5005
0
        mask = decode_x91_05(session, buf);
5006
0
        break;
5007
34
    case 0x9201:
5008
        // Reset Cause, x92-01
5009
34
        if (3 > length) {
5010
34
            bad_len = true;
5011
34
            break;
5012
34
        }
5013
0
        mask = decode_x92_01(session, buf);
5014
0
        break;
5015
66
    case 0x9300:
5016
        // Production Information, x93-00
5017
66
        if (78 > length) {
5018
66
            bad_len = true;
5019
66
            break;
5020
66
        }
5021
0
        mask = decode_x93_00(session, buf);
5022
0
        break;
5023
0
    case 0xa000:
5024
        // Firmware Upload, xa0-00
5025
        // could be length 3, or 8, different data...
5026
0
        if (3 != length &&
5027
0
            8 != length) {
5028
0
            bad_len = true;
5029
0
            break;
5030
0
        }
5031
0
        mask = decode_xa0_00(session, buf, length);
5032
0
        break;
5033
2
    case 0xa100:
5034
        // Timing Information. xa1-00
5035
        // the only message on by default
5036
2
        if (32 > length) {
5037
0
            bad_len = true;
5038
0
            break;
5039
0
        }
5040
2
        mask = decode_xa1_00(session, buf);
5041
2
        break;
5042
5043
0
    case 0xa102:
5044
        // Frequency Information, xa1-02
5045
0
        if (17 > length) {
5046
0
            bad_len = true;
5047
0
            break;
5048
0
        }
5049
0
        mask = decode_xa1_02(session, buf);
5050
0
        break;
5051
5052
0
    case 0xa111:
5053
        // Position Information, xa1-11
5054
0
        if (52 > length) {
5055
0
            bad_len = true;
5056
0
            break;
5057
0
        }
5058
0
        mask = decode_xa1_11(session, buf);
5059
0
        break;
5060
2
    case 0xa200:
5061
        // Satellite Information, xa2-00
5062
2
        if (25 > length) {
5063
0
            bad_len = true;
5064
0
            break;
5065
0
        }
5066
2
        mask = decode_xa2_00(session, buf);
5067
2
        break;
5068
5069
0
    case 0xa300:
5070
        // System Alarms, xa3-00
5071
0
        if (18 > length) {
5072
0
            bad_len = true;
5073
0
            break;
5074
0
        }
5075
0
        mask = decode_xa3_00(session, buf);
5076
0
        break;
5077
0
    case 0xa311:
5078
        /* Receiver Status, xa3-11
5079
         * RES 720
5080
         */
5081
0
        if (29 > length) {
5082
0
            bad_len = true;
5083
0
            break;
5084
0
        }
5085
        // usually the last message, except for A2-00 (sats)
5086
0
        mask = decode_xa3_11(session, buf);
5087
0
        break;
5088
0
    case 0xa321:
5089
        /* Error Report xa3-21
5090
         * expect errors for x1c-03 and x35-32 from TSIP probes
5091
         */
5092
0
        if (5 > length) {
5093
0
            bad_len = true;
5094
0
            break;
5095
0
        }
5096
0
        mask = decode_xa3_21(session, buf);
5097
0
        break;
5098
0
    case 0xd000:
5099
        // Debug Output type packet, xd0-00
5100
0
        if (3 > length) {
5101
0
            bad_len = true;
5102
0
            break;
5103
0
        }
5104
0
        mask = decode_xd0_00(session, buf);
5105
0
        break;
5106
0
    case 0xd001:
5107
        // Trimble Debug config packet, xd0-01
5108
0
        if (4 > length) {
5109
0
            bad_len = true;
5110
0
            break;
5111
0
        }
5112
0
        mask = decode_xd0_01(session, buf);
5113
0
        break;
5114
0
    case 0xd040:
5115
        // Trimble Raw GNSS Debug Output packet. xd0-40
5116
        // length can be zero, contents undefined
5117
0
        GPSD_LOG(LOG_WARN, &session->context->errout,
5118
0
                 "TSIPv1 xd0-40: raw GNSS data\n");
5119
0
        break;
5120
0
    case 0xd041:
5121
        // Trimble Raw GNSS Debug Output packet. xd0-41
5122
        // length can be zero, contents undefined
5123
0
        GPSD_LOG(LOG_WARN, &session->context->errout,
5124
0
                 "TSIPv1 xd0-41: raw GNSS data\n");
5125
0
        break;
5126
5127
    // undecoded:
5128
0
    case 0x9200:
5129
        // Receiver Reset, send only, x92-00
5130
0
        FALLTHROUGH
5131
0
    case 0xa400:
5132
        // AGNSS, send only, xa4-00
5133
0
        FALLTHROUGH
5134
68
    default:
5135
        // Huh?
5136
68
        GPSD_LOG(LOG_WARN, &session->context->errout,
5137
68
                 "TSIPv1 x%02x-%02x: unknown packet id/su-id\n",
5138
68
                 id, sub_id);
5139
68
        break;
5140
963
    }
5141
963
    if (bad_len) {
5142
857
        GPSD_LOG(LOG_WARN, &session->context->errout,
5143
857
                 "TSIPv1 0x%02x-%02x: runt, got length %u\n",
5144
857
                 id, sub_id, length);
5145
857
        mask = 0;
5146
857
    }
5147
    // get next item off queue
5148
963
    tsipv1_query(session);
5149
5150
963
    return mask;
5151
963
}
5152
5153
/* This is the meat of parsing all the TSIP packets, except v1
5154
 *
5155
 * Return: mask
5156
 */
5157
static gps_mask_t tsip_parse_input(struct gps_device_t *session)
5158
9.33k
{
5159
9.33k
    int i, len;
5160
9.33k
    gps_mask_t mask = 0;
5161
9.33k
    unsigned int id;
5162
9.33k
    time_t now;
5163
9.33k
    char buf[sizeof(session->lexer.outbuffer)];
5164
9.33k
    char buf2[BUFSIZ];
5165
9.33k
    int bad_len = 0;
5166
9.33k
    bool valid = false;
5167
5168
9.33k
    if (TSIP_PACKET != session->lexer.type) {
5169
        // this should not happen
5170
130
        GPSD_LOG(LOG_INF, &session->context->errout,
5171
130
                 "TSIP: tsip_analyze packet type %d\n",
5172
130
                 session->lexer.type);
5173
130
        return 0;
5174
130
    }
5175
5176
9.20k
    if (4 > session->lexer.outbuflen ||
5177
9.20k
        0x10 != session->lexer.outbuffer[0]) {
5178
        // packet too short, or does not start with DLE
5179
98
        GPSD_LOG(LOG_INF, &session->context->errout,
5180
98
                 "TSIP: tsip_analyze packet bad packet\n");
5181
98
        return 0;
5182
98
    }
5183
5184
    /* get receive time, first
5185
     * using system time breaks regressions!
5186
     * so use latest from receiver */
5187
9.10k
    if (0 != session->lastfix.time.tv_sec) {
5188
9.00k
        now = session->lastfix.time.tv_sec;
5189
9.00k
    } else if (0 != session->oldfix.time.tv_sec) {
5190
0
        now = session->oldfix.time.tv_sec;
5191
94
    } else {
5192
94
        now = 0;
5193
94
    }
5194
5195
    // put data part of message in buf
5196
5197
9.10k
    memset(buf, 0, sizeof(buf));
5198
9.10k
    len = 0;
5199
140k
    for (i = 2; i < (int)session->lexer.outbuflen; i++) {
5200
140k
        if (0x10 == session->lexer.outbuffer[i] &&
5201
11.1k
            0x03 == session->lexer.outbuffer[++i]) {
5202
                // DLE, STX.  end of packet, we know the length
5203
9.10k
                valid = true;
5204
9.10k
                break;
5205
9.10k
        }
5206
131k
        buf[len++] = session->lexer.outbuffer[i];
5207
131k
    }
5208
5209
9.10k
    id = (unsigned)session->lexer.outbuffer[1];
5210
9.10k
    if (valid &&
5211
9.10k
        1024 > len) {
5212
9.10k
        GPSD_LOG(LOG_DATA, &session->context->errout,
5213
9.10k
                 "TSIP x%02x: length %d: %s\n",
5214
9.10k
                 id, len, gps_hexdump(buf2, sizeof(buf2),
5215
9.10k
                                      (unsigned char *)buf, len));
5216
9.10k
    } else {
5217
        /* End of message not found, or too long, or both.
5218
         * Fuzzers gonna fuzz. */
5219
3
        GPSD_LOG(LOG_WARN, &session->context->errout,
5220
3
                 "TSIP x%02x: Too long. length %d: %s\n",
5221
3
                 id, len, gps_hexdump(buf2, sizeof(buf2),
5222
3
                                      (unsigned char *)buf, len));
5223
3
        return mask;
5224
3
    }
5225
5226
    // session->cycle_end_reliable = true;
5227
9.10k
    switch (id) {
5228
339
    case 0x13:
5229
        /* Packet Received
5230
         * Present in:
5231
         *   pre-2000 models
5232
         *   ICM SMT 360 (2018)
5233
         *   RES SMT 360 (2018)
5234
         *   Resolution SMTx
5235
         * Not present in:
5236
         *   Copernicus II
5237
         */
5238
339
        if (1 > len) {
5239
0
            bad_len = 1;
5240
0
            break;
5241
0
        }
5242
339
        mask = decode_x13(session, buf, len);
5243
339
        break;
5244
5245
587
    case 0x1c:        // Hardware/Software Version Information
5246
        /* Present in:
5247
         *   Acutime Gold
5248
         *   Lassen iQ (2005) fw 1.16+
5249
         *   Copernicus (2006)
5250
         *   Copernicus II (2009)
5251
         *   Thunderbolt E (2012)
5252
         *   RES SMT 360 (2018)
5253
         *   ICM SMT 360 (2018)
5254
         *   RES360 17x22 (2018)
5255
         *   Acutime 360
5256
         * Not Present in:
5257
         *   pre-2000 models
5258
         *   ACE II (1999)
5259
         *   ACE III (2000)
5260
         *   Lassen SQ (2002)
5261
         *   Lassen iQ (2005) pre fw 1.16
5262
         */
5263
587
        mask = decode_x1c(session, buf, len, &bad_len);
5264
587
        break;
5265
64
    case 0x41:
5266
        /* GPS Time (0x41).  polled by 0x21
5267
         * Note: this is not the time of current fix
5268
         * Present in:
5269
         *   pre-2000 models
5270
         *   Copernicus II (2009)
5271
         *   ICM SMT 360 (2018)
5272
         *   RES SMT 360 (2018)
5273
         *   Resolution SMTx
5274
         */
5275
64
        if (10 > len) {
5276
0
            bad_len = 10;
5277
0
            break;
5278
0
        }
5279
64
        session->driver.tsip.last_41 = now;     // keep timestamp for request
5280
64
        mask = decode_x41(session, buf);
5281
64
        break;
5282
304
    case 0x42:
5283
        /* Single-Precision Position Fix, XYZ ECEF
5284
         * Present in:
5285
         *   pre-2000 models
5286
         *   Copernicus II (2009)
5287
         *   ICM SMT 360 (2018)
5288
         *   RES SMT 360 (2018)
5289
         */
5290
304
        if (16 > len) {
5291
0
            bad_len = 16;
5292
0
            break;
5293
0
        }
5294
304
        mask = decode_x42(session, buf);
5295
304
        break;
5296
69
    case 0x43:
5297
        /* Velocity Fix, XYZ ECEF
5298
         * Present in:
5299
         *   pre-2000 models
5300
         *   ICM SMT 360 (2018)
5301
         *   RES SMT 360 (2018)
5302
         * Not Present in:
5303
         *   Copernicus II (2009)
5304
         */
5305
69
        if (20 > len) {
5306
0
            bad_len = 20;
5307
0
            break;
5308
0
        }
5309
69
        mask = decode_x43(session, buf);
5310
69
        break;
5311
4
    case 0x45:
5312
        /* Software Version Information (0x45)
5313
         * Present in:
5314
         *   pre-2000 models
5315
         *   ACE II (1999)
5316
         *   ACE III (2000)
5317
         *   Lassen SQ (2002)
5318
         *   Lassen iQ (2005)
5319
         *   Copernicus II (2009)
5320
         *   ICM SMT 360
5321
         *   RES SMT 360
5322
         * Not present in:
5323
         *   RES 720
5324
         */
5325
4
        if (10 > len) {
5326
0
            bad_len = 10;
5327
0
            break;
5328
0
        }
5329
4
        mask = decode_x45(session, buf);
5330
4
        break;
5331
938
    case 0x46:
5332
        /* Health of Receiver (0x46).  Poll with 0x26
5333
         * Present in:
5334
         *   pre-2000 models
5335
         *   Copernicus II (2009)
5336
         *   ICM SMT 360 (2018)
5337
         *   RES SMT 360 (2018) (deprecated, used x8f-ab or x8f-1c)
5338
         *   Resolution SMTx
5339
         *   all models?
5340
         */
5341
938
        if (2 > len) {
5342
0
            bad_len = 2;
5343
0
            break;
5344
0
        }
5345
938
        session->driver.tsip.last_46 = now;
5346
938
        mask = decode_x46(session, buf);
5347
938
        break;
5348
227
    case 0x47:
5349
        /* Signal Levels for all Satellites
5350
         * Present in:
5351
         *   pre-2000 models
5352
         *   Copernicus II (2009)
5353
         *   ICM SMT 360 (2018)
5354
         *   RES SMT 360 (2018)
5355
         */
5356
227
        if (1 > len) {
5357
0
            bad_len = 1;
5358
0
            break;
5359
0
        }
5360
227
        mask = decode_x47(session, buf, len, &bad_len);
5361
227
        break;
5362
30
    case 0x48:
5363
        /* GPS System Message
5364
         * Present in:
5365
         *   pre-2000 models
5366
         * Not Present in:
5367
         *   Copernicus II (2009)
5368
         *   ICM SMT 360 (2018)
5369
         *   RES SMT 360 (2018)
5370
         */
5371
30
        buf[len] = '\0';
5372
30
        GPSD_LOG(LOG_PROG, &session->context->errout,
5373
30
                 "TSIP x48: GPS System Message: %s\n", buf);
5374
30
        break;
5375
177
    case 0x4a:
5376
        /* Single-Precision Position LLA
5377
         * Only sent when valid
5378
         * Present in:
5379
         *   pre-2000 models
5380
         *   Copernicus II (2009)
5381
         *   ICM SMT 360 (2018)
5382
         *   RES SMT 360 (2018)
5383
         */
5384
177
        if (20 > len) {
5385
0
            bad_len = 20;
5386
0
            break;
5387
0
        }
5388
177
        mask = decode_x4a(session, buf);
5389
177
        break;
5390
507
    case 0x4b:
5391
        /* Machine/Code ID and Additional Status (0x4b)
5392
         * polled by 0x25 (soft reset) or 0x26 (request health).
5393
         * Sent with 0x46 (receiver health).
5394
         * Present in:
5395
         *   pre-2000 models
5396
         *   Copernicus II (2009)
5397
         *   ICM SMT 360 (2018)
5398
         *   RES SMT 360 (2018)
5399
         *   Resolution SMTx
5400
         * Deprecated in:
5401
         *   Resolution SMTx
5402
         * Not in:
5403
         *   Thunderbolt (2003)
5404
         */
5405
507
        if (3 > len) {
5406
0
            bad_len = 3;
5407
0
            break;
5408
0
        }
5409
507
        mask = decode_x4b(session, buf);
5410
507
        break;
5411
5
    case 0x4c:
5412
        /* Operating Parameters Report (0x4c).  Polled by 0x2c
5413
         * Present in:
5414
         *   pre-2000 models
5415
         *   Lassen iQ, but not documented
5416
         * Not Present in:
5417
         *   Copernicus II (2009)
5418
         *   ICM SMT 360 (2018)
5419
         *   RES SMT 360 (2018)
5420
         */
5421
5
        if (17 > len) {
5422
0
            bad_len = 17;
5423
0
            break;
5424
0
        }
5425
5
        mask = decode_x4c(session, buf);
5426
5
        break;
5427
191
    case 0x54:
5428
        /* Bias and Bias Rate Report (0x54)
5429
         * Present in:
5430
         *   pre-2000 models
5431
         *   Acutime 360
5432
         *   ICM SMT 360  (undocumented)
5433
         *   RES SMT 360  (undocumented)
5434
         * Not Present in:
5435
         *   Copernicus II (2009)
5436
         *   Resolution SMTx
5437
         */
5438
191
        if (12 > len) {
5439
0
            bad_len = 12;
5440
0
            break;
5441
0
        }
5442
191
         mask = decode_x54(session, buf);
5443
191
        break;
5444
242
    case 0x55:
5445
        /* IO Options (0x55), polled by 0x35
5446
         * Present in:
5447
         *   pre-2000 models
5448
         *   ICM SMT 360 (2018)
5449
         *   RES SMT 360 (2018)
5450
         *   Resolution SMTx
5451
         *   all TSIP?
5452
         *
5453
         * Defaults:
5454
         *   Lassen iQ:       02 02 00 00
5455
         *   RES SMT 360:     12 02 00 08
5456
         *   Resolution SMTx: 12 02 00 08
5457
         */
5458
242
        if (4 > len) {
5459
0
            bad_len = 4;
5460
0
            break;
5461
0
        }
5462
242
        mask = decode_x55(session, buf, now);
5463
242
        break;
5464
66
    case 0x56:
5465
        /* Velocity Fix, East-North-Up (ENU)
5466
         * Present in:
5467
         *   pre-2000 models
5468
         *   Copernicus II (2009)
5469
         *   ICM SMT 360 (2018)
5470
         *   RES SMT 360 (2018)
5471
         */
5472
66
        if (20 > len) {
5473
0
            bad_len = 20;
5474
0
            break;
5475
0
        }
5476
66
        mask = decode_x56(session, buf);
5477
66
        break;
5478
470
    case 0x57:
5479
        /* Information About Last Computed Fix
5480
         * Present in:
5481
         *   pre-2000 models
5482
         *   Copernicus II (2009)
5483
         *   ICM SMT 360 (2018)
5484
         *   RES SMT 360 (2018)
5485
         */
5486
470
        if (8 > len) {
5487
0
            bad_len = 8;
5488
0
            break;
5489
0
        }
5490
470
        mask = decode_x57(session, buf);
5491
470
        break;
5492
17
    case 0x5a:
5493
        /* Raw Measurement Data
5494
         * Present in:
5495
         *   pre-2000 models
5496
         *   Copernicus II (2009)
5497
         *   ICM SMT 360 (2018)
5498
         *   RES SMT 360 (2018)
5499
         */
5500
17
        if (25 > len) {
5501
0
            bad_len = 25;
5502
0
            break;
5503
0
        }
5504
17
        mask = decode_x5a(session, buf);
5505
17
        break;
5506
174
    case 0x5c:
5507
        /* Satellite Tracking Status (0x5c) polled by 0x3c
5508
         *
5509
         * GPS only, no WAAS reported here or used in fix
5510
         * Present in:
5511
         *   pre-2000 models
5512
         *   Copernicus, Copernicus II
5513
         *   Thunderbold E
5514
         * Not Present in:
5515
         *   ICM SMT 360 (2018)
5516
         *   RES SMT 360 (2018)
5517
         */
5518
174
        if (24 > len) {
5519
0
            bad_len = 24;
5520
0
            break;
5521
0
        }
5522
174
        mask = decode_x5c(session, buf);
5523
174
        break;
5524
5525
290
     case 0x5d:
5526
        /* GNSS Satellite Tracking Status (multi-GNSS operation) (0x5d)
5527
         * polled by 0x3c
5528
         *
5529
         * GNSS only, no WAAS reported here or used in fix
5530
         * Present in:
5531
         *   ICM SMT 360 (2018)
5532
         *   RES SMT 360 (2018)
5533
         * Not Present in:
5534
         *   pre-2000 models
5535
         *   Copernicus, Copernicus II
5536
         *   Thunderbold E
5537
         */
5538
290
        if (26 > len) {
5539
0
            bad_len = 26;
5540
0
            break;
5541
0
        }
5542
290
        mask = decode_x5d(session, buf);
5543
290
        break;
5544
228
    case 0x6c:
5545
        /* Satellite Selection List (0x6c) polled by 0x24
5546
         * Eeerily similar to 0x6d, the difference is where the sat count is.
5547
         *
5548
         * Present in:
5549
         *   ICM SMT 360 (2018)
5550
         *   RES SMT 360 (2018)
5551
         * Not present in:
5552
         *   pre-2000 models
5553
         *   Copernicus II (2009)
5554
         *   Lassen SQ (2002)
5555
         *   Lassen iQ (2005) */
5556
228
        if (18 > len) {
5557
0
            bad_len = 18;
5558
0
            break;
5559
0
        }
5560
        // why same as 6d?
5561
228
        session->driver.tsip.last_6d = now;     // keep timestamp for request
5562
228
        mask = decode_x6c(session, buf, len, &bad_len);
5563
228
        break;
5564
252
    case 0x6d:
5565
        /* All-In-View Satellite Selection (0x6d) polled by 0x24
5566
         * Sent after every fix
5567
         *
5568
         * Present in:
5569
         *   pre-2000 models
5570
         *   Copernicus II (2009)
5571
         *   Lassen SQ
5572
         *   Lassen iQ
5573
         * Deprecated in:
5574
         *   Resolution SMTx
5575
         * Not present in:
5576
         *   ICM SMT 360 (2018)
5577
         *   RES SMT 360 (2018)
5578
         */
5579
252
        if (17 > len) {
5580
0
            bad_len = 17;
5581
0
            break;
5582
0
        }
5583
252
        session->driver.tsip.last_6d = now;     // keep timestamp for request
5584
252
        mask = decode_x6d(session, buf, len, &bad_len);
5585
252
        break;
5586
198
    case 0x82:
5587
        /* Differential Position Fix Mode (0x82) poll with 0x62-ff
5588
         * Sent after every position fix in Auto GPS/DGPS,
5589
         * so potential cycle ender
5590
         *
5591
         * Present in:
5592
         *   pre-2000 models
5593
         *   Copernicus II (2009)
5594
         *   Lassen SQ
5595
         *   Lassen iQ, deprecated use 0xbb instead
5596
         * Not Present in:
5597
         *   ICM SMT 360 (2018)
5598
         *   RES SMT 360 (2018)
5599
         */
5600
198
        if (1 > len) {
5601
0
            bad_len = 1;
5602
0
            break;
5603
0
        }
5604
198
        mask = decode_x82(session, buf);
5605
198
        break;
5606
134
    case 0x83:
5607
        /* Double-Precision XYZ Position Fix and Bias Information
5608
         * Only sent when valid
5609
         * Present in:
5610
         *   pre-2000 models
5611
         *   LasenSQ (2002)
5612
         *   Copernicus II (2009)
5613
         *   ICM SMT 360 (2018)
5614
         *   RES SMT 360 (2018)
5615
         */
5616
134
        if (36 > len) {
5617
0
            bad_len = 36;
5618
0
            break;
5619
0
        }
5620
134
        mask = decode_x83(session, buf);
5621
134
        break;
5622
134
    case 0x84:
5623
        /* Double-Precision LLA Position Fix and Bias Information
5624
         * Present in:
5625
         *   pre-2000 models
5626
         *   Copernicus II (2009)
5627
         *   LassenSQ  (2002)
5628
         *   ICM SMT 360 (2018)
5629
         *   RES SMT 360 (2018)
5630
         */
5631
134
        if (36 > len) {
5632
0
            bad_len = 36;
5633
0
            break;
5634
0
        }
5635
134
        mask = decode_x84(session, buf);
5636
134
        break;
5637
1.60k
    case 0x8f:
5638
        /* Super Packet.
5639
         * Present in:
5640
         *   pre-2000 models
5641
         *   ACE II
5642
         *   ACE III
5643
         *   Copernicus II (2009)
5644
         *   ICM SMT 360
5645
         *   RES SMT 360
5646
         *   Resolution SMTx
5647
         */
5648
1.60k
        mask = decode_x8f(session, buf, len, &bad_len, now);
5649
1.60k
        break;
5650
// Start of TSIP V1
5651
716
    case 0x90:
5652
        /* Version Information, TSIP v1
5653
         * Present in:
5654
         *   RES720
5655
         */
5656
716
        FALLTHROUGH
5657
1.21k
    case 0x91:
5658
        /* Receiver Configuration, TSIP v1
5659
         * Present in:
5660
         *   RES720
5661
         */
5662
1.21k
        FALLTHROUGH
5663
1.35k
    case 0x92:
5664
        /* Resets, TSIP v1
5665
         * Present in:
5666
         *   RES720
5667
         */
5668
1.35k
        FALLTHROUGH
5669
1.50k
    case 0x93:
5670
        /* Production & Manufacturing, TSIP v1
5671
         * Present in:
5672
         *   RES720
5673
         */
5674
1.50k
        FALLTHROUGH
5675
1.50k
    case 0xa0:
5676
        /* Firmware Upload, TSIP v1
5677
         * Present in:
5678
         *   RES720
5679
         */
5680
1.50k
        FALLTHROUGH
5681
1.57k
    case 0xa1:
5682
        /* PVT, TSIP v1
5683
         * Present in:
5684
         *   RES720
5685
         */
5686
1.57k
        FALLTHROUGH
5687
1.65k
    case 0xa2:
5688
        /* GNSS Information, TSIP v1
5689
         * Present in:
5690
         *   RES720
5691
         */
5692
1.65k
        FALLTHROUGH
5693
1.72k
    case 0xa3:
5694
        /* Alarms % Status, TSIP v1
5695
         * Present in:
5696
         *   RES720
5697
         */
5698
1.72k
        FALLTHROUGH
5699
1.72k
    case 0xa4:
5700
        /* AGNSS, TSIP v1
5701
         * Present in:
5702
         *   RES720
5703
         */
5704
1.72k
        FALLTHROUGH
5705
1.72k
    case 0xa5:
5706
        /* Miscellaneous, TSIP v1
5707
         * Present in:
5708
         *   RES720
5709
         */
5710
1.72k
        FALLTHROUGH
5711
1.72k
    case 0xd0:
5712
        /* Debug & Logging, TSIP v1
5713
         * Present in:
5714
         *   RES720
5715
         */
5716
1.72k
        return tsipv1_parse(session, id, buf, len);
5717
// end of TSIP V1
5718
7
    case 0xbb:
5719
        /* Navigation Configuration
5720
         * Present in:
5721
         *   pre-2000 models
5722
         *   Copernicus II (2009)
5723
         *   ICM SMT 360 (2018)
5724
         *   RES SMT 360 (2018)
5725
         */
5726
7
        if (40 != len &&
5727
6
            43 != len) {
5728
            // see packet.c for explamation
5729
0
            bad_len = 40;
5730
0
            break;
5731
0
        }
5732
7
        mask = decode_xbb(session, buf);
5733
7
        break;
5734
5735
0
    case 0x1a:
5736
        /* TSIP RTCM Wrapper Command
5737
         * Present in:
5738
         *   pre-2000 models
5739
         * Not Present in:
5740
         *   ICM SMT 360 (2018)
5741
         *   RES SMT 360 (2018)
5742
         *   Copernicus II (2009)
5743
         */
5744
0
        FALLTHROUGH
5745
0
    case 0x2e:
5746
        /* Request GPS Time
5747
         * Present in:
5748
         *   ICM SMT 360 (2018)
5749
         *   RES SMT 360 (2018)
5750
         * Not Present in:
5751
         *   pre-2000 models
5752
         *   Copernicus II (2009)
5753
         */
5754
0
        FALLTHROUGH
5755
0
    case 0x32:
5756
        /* Request Unit Position
5757
         * Present in:
5758
         *   ICM SMT 360 (2018)
5759
         *   RES SMT 360 (2018)
5760
         * Not Present in:
5761
         *   pre-2000 models
5762
         *   Copernicus II (2009)
5763
         */
5764
0
        FALLTHROUGH
5765
0
    case 0x38:
5766
        /* Request SV System data
5767
         * Present in:
5768
         *   ICM SMT 360 (2018)
5769
         *   RES SMT 360 (2018)
5770
         * Not Present in:
5771
         *   pre-2000 models
5772
         *   Copernicus II (2009)
5773
         */
5774
0
        FALLTHROUGH
5775
0
    case 0x40:
5776
        /* Almanac Data for Single Satellite Report
5777
         * Present in:
5778
         *   pre-2000 models
5779
         * Not Present in:
5780
         *   ICM SMT 360 (2018)
5781
         *   RES SMT 360 (2018)
5782
         *   Copernicus II (2009)
5783
         */
5784
0
        FALLTHROUGH
5785
0
    case 0x44:
5786
        /* Non-Overdetermined Satellite Selection Report
5787
         * Present in:
5788
         *   pre-2000 models
5789
         * Not Present in:
5790
         *   ICM SMT 360 (2018)
5791
         *   RES SMT 360 (2018)
5792
         *   Copernicus II (2009)
5793
         */
5794
0
        FALLTHROUGH
5795
10
    case 0x49:
5796
        /* Almanac Health Page
5797
         * Present in:
5798
         *   pre-2000 models
5799
         * Not Present in:
5800
         *   Copernicus II (2009)
5801
         */
5802
10
        FALLTHROUGH
5803
10
    case 0x4d:
5804
        /* Oscillator Offset
5805
         * Present in:
5806
         *   pre-2000 models
5807
         *   Copernicus II (2009)
5808
         */
5809
10
        FALLTHROUGH
5810
10
    case 0x4e:
5811
        /* Response to set GPS time
5812
         * Present in:
5813
         *   pre-2000 models
5814
         *   Copernicus II (2009)
5815
         *   ICM SMT 360 (2018)
5816
         *   RES SMT 360 (2018)
5817
         */
5818
10
        FALLTHROUGH
5819
10
    case 0x4f:
5820
        /* UTC Parameters Report
5821
         * Present in:
5822
         *   pre-2000 models
5823
         * Not Present in:
5824
         *   ICM SMT 360 (2018)
5825
         *   RES SMT 360 (2018)
5826
         *   Copernicus II (2009)
5827
         */
5828
10
        FALLTHROUGH
5829
10
    case 0x53:
5830
        /* Analog-to-Digital Readings Report
5831
         * Present in:
5832
         *   pre-2000 models
5833
         * Not Present in:
5834
         *   ICM SMT 360 (2018)
5835
         *   RES SMT 360 (2018)
5836
         *   Copernicus II (2009)
5837
         */
5838
10
        FALLTHROUGH
5839
10
    case 0x58:
5840
        /* Satellite System Data/Acknowledge from Receiver
5841
         * Present in:
5842
         *   pre-2000 models
5843
         *   Copernicus II (2009)
5844
         *   ICM SMT 360 (2018)
5845
         *   RES SMT 360 (2018)
5846
         */
5847
10
        FALLTHROUGH
5848
10
    case 0x59:
5849
        /* Status of Satellite Disable or Ignore Health
5850
         * aka Satellite Attribute Database Status Report
5851
         * Present in:
5852
         *   pre-2000 models
5853
         *   ICM SMT 360 (2018)
5854
         *   RES SMT 360 (2018)
5855
         * Not Present in:
5856
         *   Copernicus II (2009)
5857
         */
5858
10
        FALLTHROUGH
5859
15
    case 0x5b:
5860
        /* Satellite Ephemeris Status
5861
         * Present in:
5862
         *   pre-2000 models
5863
         * Not Present in:
5864
         *   Copernicus II (2009)
5865
         *   ICM SMT 360 (2018)
5866
         *   RES SMT 360 (2018)
5867
         */
5868
15
        FALLTHROUGH
5869
113
    case 0x5e:
5870
        /* Additional Fix Status Report
5871
         * Present in:
5872
         *   pre-2000 models
5873
         * Not Present in:
5874
         *   Copernicus II (2009)
5875
         *   ICM SMT 360 (2018)
5876
         *   RES SMT 360 (2018)
5877
         */
5878
113
        FALLTHROUGH
5879
124
    case 0x5f:
5880
        /* Severe Failure Notification
5881
         * Present in:
5882
         *   pre-2000 models
5883
         * Not Present in:
5884
         *   ICM SMT 360 (2018)
5885
         *   RES SMT 360 (2018)
5886
         *   Copernicus II (2009)
5887
         */
5888
124
        FALLTHROUGH
5889
124
    case 0x60:
5890
        /* Differential GPS Pseudorange Corrections Report
5891
         * Present in:
5892
         *   pre-2000 models
5893
         * Not Present in:
5894
         *   ICM SMT 360 (2018)
5895
         *   RES SMT 360 (2018)
5896
         *   Copernicus II (2009)
5897
         */
5898
124
        FALLTHROUGH
5899
124
    case 0x61:
5900
        /* Differential GPS Delta Pseudorange Corrections Report
5901
         * Present in:
5902
         *   pre-2000 models
5903
         * Not Present in:
5904
         *   ICM SMT 360 (2018)
5905
         *   RES SMT 360 (2018)
5906
         *   Copernicus II (2009)
5907
         */
5908
124
        FALLTHROUGH
5909
124
    case 0x6a:
5910
        /* Differential Corrections Used in the Fix Repor
5911
         * Present in:
5912
         *   pre-2000 models
5913
         * Not Present in:
5914
         *   ICM SMT 360 (2018)
5915
         *   RES SMT 360 (2018)
5916
         *   Copernicus II (2009)
5917
         */
5918
124
        FALLTHROUGH
5919
124
    case 0x6e:
5920
        /* Synchronized Measurements
5921
         * Present in:
5922
         *   pre-2000 models
5923
         * Not Present in:
5924
         *   Copernicus II (2009)
5925
         *   ICM SMT 360 (2018)
5926
         *   RES SMT 360 (2018)
5927
         */
5928
124
        FALLTHROUGH
5929
124
    case 0x6f:
5930
        /* Synchronized Measurements Report
5931
         * Present in:
5932
         *   pre-2000 models
5933
         * Not Present in:
5934
         *   Copernicus II (2009)
5935
         *   ICM SMT 360 (2018)
5936
         *   RES SMT 360 (2018)
5937
         */
5938
124
        FALLTHROUGH
5939
124
    case 0x70:
5940
        /* Filter Report
5941
         * Present in:
5942
         *   pre-2000 models
5943
         * Not Present in:
5944
         *   Copernicus II (2009)
5945
         *   ICM SMT 360 (2018)
5946
         *   RES SMT 360 (2018)
5947
         */
5948
124
        FALLTHROUGH
5949
124
    case 0x76:
5950
        /* Overdetermined Mode Report
5951
         * Present in:
5952
         *   pre-2000 models
5953
         * Not Present in:
5954
         *   ICM SMT 360 (2018)
5955
         *   RES SMT 360 (2018)
5956
         *   Copernicus II (2009)
5957
         */
5958
124
        FALLTHROUGH
5959
124
    case 0x78:
5960
        /* Maximum PRC Age Report
5961
         * Present in:
5962
         *   pre-2000 models
5963
         * Not Present in:
5964
         *   ICM SMT 360 (2018)
5965
         *   RES SMT 360 (2018)
5966
         *   Copernicus II (2009)
5967
         */
5968
124
        FALLTHROUGH
5969
124
    case 0x7a:
5970
        /* NMEA settings
5971
         * Not Present in:
5972
         *   pre-2000 models
5973
         *   Copernicus II (2009)
5974
         *   ICM SMT 360 (2018)
5975
         *   RES SMT 360 (2018)
5976
         */
5977
124
        FALLTHROUGH
5978
124
    case 0x7b:
5979
        /* NMEA interval and message mask response
5980
         * Present in:
5981
         *   pre-2000 models
5982
         *   ICM SMT 360 (2018)
5983
         *   RES SMT 360 (2018)
5984
         * Not Present in:
5985
         *   Copernicus II (2009)
5986
         */
5987
124
        FALLTHROUGH
5988
124
    case 0x7d:
5989
        /* Position Fix Rate Configuration Reports
5990
         * Present in:
5991
         *   pre-2000 models
5992
         * Not Present in:
5993
         *   ICM SMT 360 (2018)
5994
         *   RES SMT 360 (2018)
5995
         *   Copernicus II (2009)
5996
         */
5997
124
        FALLTHROUGH
5998
124
    case 0x85:
5999
        /* Differential Correction Status Report
6000
         * Present in:
6001
         *   pre-2000 models
6002
         * Not Present in:
6003
         *   ICM SMT 360 (2018)
6004
         *   RES SMT 360 (2018)
6005
         *   Copernicus II (2009)
6006
         */
6007
124
        FALLTHROUGH
6008
124
    case 0x87:
6009
        /* Reference Station Parameters Report
6010
         * Present in:
6011
         *   pre-2000 models
6012
         * Not Present in:
6013
         *   ICM SMT 360 (2018)
6014
         *   RES SMT 360 (2018)
6015
         *   Copernicus II (2009)
6016
         */
6017
124
        FALLTHROUGH
6018
124
    case 0x89:
6019
        /* Receiver acquisition sensitivity mode
6020
         * Present in:
6021
         *   Copernicus II (2009)
6022
         * Not Present in:
6023
         *   pre-2000 models
6024
         *   ICM SMT 360 (2018)
6025
         *   RES SMT 360 (2018)
6026
         */
6027
124
        FALLTHROUGH
6028
124
    case 0x88:
6029
        /* Mobile Differential Parameters Report
6030
         * Present in:
6031
         *   pre-2000 models
6032
         * Not Present in:
6033
         *   ICM SMT 360 (2018)
6034
         *   RES SMT 360 (2018)
6035
         *   Copernicus II (2009)
6036
         */
6037
124
        FALLTHROUGH
6038
124
    case 0x8b:
6039
        /* QA/QC Reports
6040
         * Present in:
6041
         *   pre-2000 models
6042
         * Not Present in:
6043
         *   ICM SMT 360 (2018)
6044
         *   RES SMT 360 (2018)
6045
         *   Copernicus II (2009)
6046
         */
6047
124
        FALLTHROUGH
6048
124
    case 0x8d:
6049
        /* Average Position Reports
6050
         * Present in:
6051
         *   pre-2000 models
6052
         * Not Present in:
6053
         *   ICM SMT 360 (2018)
6054
         *   RES SMT 360 (2018)
6055
         *   Copernicus II (2009)
6056
         */
6057
124
        FALLTHROUGH
6058
124
    case 0xb0:
6059
        /* PPS and Event Report Packets
6060
         * Present in:
6061
         *   pre-2000 models
6062
         * Not Present in:
6063
         *   ICM SMT 360 (2018)
6064
         *   RES SMT 360 (2018)
6065
         *   Copernicus II (2009)
6066
         */
6067
124
        FALLTHROUGH
6068
124
    case 0xbc:
6069
        /* Receiver port configuration
6070
         * Present in:
6071
         *   pre-2000 models
6072
         *   Copernicus II (2009)
6073
         * Not Present in:
6074
         *   ICM SMT 360 (2018)
6075
         *   RES SMT 360 (2018)
6076
         */
6077
124
        FALLTHROUGH
6078
124
    case 0xc1:
6079
        /* Bit Mask for GPIOs in Standby Mode
6080
         * Present in:
6081
         *   Copernicus II (2009)
6082
         *   ICM SMT 360 (2018)
6083
         *   RES SMT 360 (2018)
6084
         * Not Present in:
6085
         *   pre-2000 models
6086
         */
6087
124
        FALLTHROUGH
6088
124
    case 0xc2:
6089
        /* SBAS SV Mask
6090
         * Present in:
6091
         *   Copernicus II (2009)
6092
         *   ICM SMT 360 (2018)
6093
         *   RES SMT 360 (2018)
6094
         * Not Present in:
6095
         *   pre-2000 models
6096
         */
6097
124
        FALLTHROUGH
6098
124
    default:
6099
124
        GPSD_LOG(LOG_WARN, &session->context->errout,
6100
124
                 "TSIP x%02x: Unhandled packet type\n", id);
6101
124
        break;
6102
9.10k
    }
6103
6104
#ifdef __UNUSED__
6105
// #if 1
6106
    // full reset
6107
    (void)tsip_write1(session, "\x1e\x46", 2);
6108
#endif
6109
6110
7.38k
    if (bad_len) {
6111
984
        GPSD_LOG(LOG_WARNING, &session->context->errout,
6112
984
                 "TSIP x%02x: wrong len %d s/b >= %d \n", id, len, bad_len);
6113
6.39k
    } else {
6114
6.39k
        GPSD_LOG(LOG_IO, &session->context->errout,
6115
6.39k
                 "TSIP x%02x: mask %s\n", id, gps_maskdump(mask));
6116
6.39k
    }
6117
    /* See if it is time to send some request packets for reports that.
6118
     * The receiver won't send at fixed intervals.
6119
     * Use llabs() as time sometimes goes backwards. */
6120
6121
7.38k
    if (5 < llabs(now - session->driver.tsip.last_41)) {
6122
        /* Request Current Time returns 0x41.
6123
         * Easiest way to get GPS weeks and current leap seconds */
6124
1.72k
        (void)tsip_write1(session, "\x21", 1);
6125
1.72k
        session->driver.tsip.last_41 = now;
6126
1.72k
    }
6127
6128
7.38k
    if (5 < llabs(now - session->driver.tsip.last_6d)) {
6129
        /* Request GPS Receiver Position Fix Mode
6130
         * Returns 0x44, 0x6c, or 0x6d
6131
         * We need one of those to get PDOP, HDOP, etc.
6132
         * At least on RexSMT360. */
6133
1.69k
        (void)tsip_write1(session, "\x24", 1);
6134
1.69k
        session->driver.tsip.last_6d = now;
6135
#ifdef __UNUSED__
6136
// #if 1
6137
        // request Receiver Configuration (0xbb)
6138
        (void)tsip_write1(session, "\xbb\x00", 2);
6139
6140
        // request Packet Broadcast Mask
6141
        (void)tsip_write1(session, "\x8e\xa5", 2);
6142
#endif // UNUSED
6143
1.69k
    }
6144
6145
7.38k
    if (1 > session->driver.tsip.superpkt &&
6146
6.86k
        60 < llabs(now - session->driver.tsip.last_48)) {
6147
        /* Request GPS System Message
6148
         * Returns 0x48.
6149
         * not supported on:
6150
         *  Lassen SQ (2002)
6151
         *  Lassen iQ (2005)
6152
         *  ICM SMT 360
6153
         *  RES SMT 360
6154
         *  and post 2005
6155
         * SuperPackets replaced 0x28 */
6156
1.72k
        (void)tsip_write1(session, "\x28", 1);
6157
1.72k
        session->driver.tsip.last_48 = now;
6158
1.72k
    }
6159
6160
7.38k
    if (5 < llabs(now - session->driver.tsip.last_5c)) {
6161
        /* Request Current Satellite Tracking Status
6162
         * Returns: 0x5c or 0x5d
6163
         *  5c from GPS only devices
6164
         *  5d from multi-gnss devices */
6165
        // 00 == All satellites
6166
1.81k
        (void)tsip_write1(session, "\x3c\x00", 2);
6167
1.81k
        session->driver.tsip.last_5c = now;
6168
1.81k
    }
6169
6170
7.38k
    if (5 < llabs(now - session->driver.tsip.last_46)) {
6171
        /* Request Health of Receiver
6172
         * Returns 0x46 and 0x4b. */
6173
1.70k
        (void)tsip_write1(session, "\x26", 1);
6174
1.70k
        session->driver.tsip.last_46 = now;
6175
1.70k
    }
6176
7.38k
    if ((0 < session->driver.tsip.req_compact) &&
6177
162
        (5 < llabs(now - session->driver.tsip.req_compact))) {
6178
        /* Compact Superpacket requested but no response
6179
         * Not in:
6180
         * ICM SMT 360
6181
         * RES SMT 360
6182
          */
6183
28
        session->driver.tsip.req_compact = 0;
6184
28
        GPSD_LOG(LOG_WARN, &session->context->errout,
6185
28
                 "TSIP x8f-23: No Compact Super Packet, "
6186
28
                 "try LFwEI (0x8f-20)\n");
6187
6188
        // Request LFwEI Super Packet 0x8f-20, enabled
6189
28
        (void)tsip_write1(session, "\x8e\x20\x01", 3);
6190
28
    }
6191
6192
7.38k
    return mask;
6193
9.10k
}
6194
6195
static void tsip_init_query(struct gps_device_t *session)
6196
67
{
6197
    // Use 0x1C-03 to Request Hardware Version Information (0x1C-83)
6198
67
    (void)tsip_write1(session, "\x1c\x03", 2);
6199
    /*
6200
     * After HW information packet is received, a
6201
     * decision is made how to configure the device.
6202
     */
6203
67
}
6204
6205
static void tsip_event_hook(struct gps_device_t *session, event_t event)
6206
11.5k
{
6207
11.5k
    GPSD_LOG(LOG_SPIN, &session->context->errout,
6208
11.5k
             "TSIP: event_hook event %d ro %d\n",
6209
11.5k
             event, session->context->readonly);
6210
6211
11.5k
    if (session->context->readonly ||
6212
8.15k
        session->context->passive) {
6213
7.10k
        return;
6214
7.10k
    }
6215
4.48k
    switch (event) {
6216
32
    case EVENT_IDENTIFIED:
6217
32
        FALLTHROUGH
6218
32
    case EVENT_REACTIVATE:
6219
        /* reactivate style needs to depend on model
6220
         * So send Request Software Version (0x1f), which returns 0x45.
6221
         * Once we have the x45, we can decide how to configure */
6222
32
        (void)tsip_write1(session, "\x1f", 1);
6223
32
        break;
6224
4.35k
    case EVENT_CONFIGURE:
6225
        // this seems to get called on every packet...
6226
4.35k
        if (0 == session->lexer.counter) {
6227
            /* but the above if() makes it never execute
6228
             * formerely tried to force 801 here, but luckily it
6229
             * never fired as some Trimble are 8N1 */
6230
32
        }
6231
4.35k
        break;
6232
0
    case EVENT_DEACTIVATE:
6233
        // used to revert serial port params here.  No need for that.
6234
0
        FALLTHROUGH
6235
92
    default:
6236
92
        break;
6237
4.48k
    }
6238
4.48k
}
6239
6240
static bool tsip_speed_switch(struct gps_device_t *session,
6241
                              speed_t speed, char parity, int stopbits)
6242
0
{
6243
0
    char buf[100];
6244
6245
0
    switch (parity) {
6246
0
    case 'E':
6247
0
    case 2:
6248
0
        parity = (char)2;
6249
0
        break;
6250
0
    case 'O':
6251
0
    case 1:
6252
0
        parity = (char)1;
6253
0
        break;
6254
0
    case 'N':
6255
0
    case 0:
6256
0
    default:
6257
0
        parity = (char)0;
6258
0
        break;
6259
0
    }
6260
6261
0
    buf[0] = 0xbc;          // Set Port Configuration (0xbc)
6262
0
    buf[1] = 0xff;          // current port
6263
    // input dev.baudrate
6264
0
    buf[2] = (round(log((double)speed / 300) / GPS_LN2)) + 2;
6265
0
    buf[3] = buf[2];        // output baudrate
6266
0
    buf[4] = 3;             // character width (8 bits)
6267
0
    buf[5] = parity;        // parity (normally odd)
6268
0
    buf[6] = stopbits - 1;  // stop bits (normally 1 stopbit)
6269
0
    buf[7] = 0;             // flow control (none)
6270
0
    buf[8] = 0x02;          // input protocol (TSIP)
6271
0
    buf[9] = 0x02;          // output protocol (TSIP)
6272
0
    buf[10] = 0;            // reserved
6273
0
    (void)tsip_write1(session, buf, 11);
6274
6275
0
    return true;            // it would be nice to error-check this
6276
0
}
6277
6278
static void tsip_mode(struct gps_device_t *session, int mode)
6279
0
{
6280
0
    if (MODE_NMEA == mode) {
6281
0
        char buf[16];
6282
6283
        /* send NMEA Interval and Message Mask Command (0x7a)
6284
         * First turn on the NMEA messages we want */
6285
0
        buf[0] = 0x7a;
6286
0
        buf[1] = 0x00;  //  subcode 0
6287
0
        buf[2] = 0x01;  //  1-second fix interval
6288
0
        buf[3] = 0x00;  //  Reserved
6289
0
        buf[4] = 0x00;  //  Reserved
6290
0
        buf[5] = 0x01;  //  1=GST, Reserved
6291
        /* 1=GGA, 2=GGL, 4=VTG, 8=GSV,
6292
         * 0x10=GSA, 0x20=ZDA, 0x40=Reserved, 0x80=RMC  */
6293
0
        buf[6] = 0x19;
6294
6295
0
        (void)tsip_write1(session, buf, 7);
6296
6297
        // Now switch to NMEA mode
6298
0
        memset(buf, 0, sizeof(buf));
6299
6300
0
        buf[0] = 0x8c;     // Set Port Configuration (0xbc)
6301
0
        buf[1] = 0xff;     // current port
6302
0
        buf[2] = 0x06;     // 4800 bps input.  4800, really?
6303
0
        buf[3] = buf[2];   // output SAME AS INPUT
6304
0
        buf[4] = 0x03;     // 8 data bits
6305
0
        buf[5] = 0x00;     // No parity
6306
0
        buf[6] = 0x00;     // 1 stop bit
6307
0
        buf[7] = 0x00;     // No flow control
6308
0
        buf[8] = 0x02;     // Input protocol TSIP
6309
0
        buf[9] = 0x04;     // Output protocol NMEA
6310
0
        buf[10] = 0x00;    // Reserved
6311
6312
0
        (void)tsip_write1(session, buf, 11);
6313
6314
0
    } else if (MODE_BINARY == mode) {
6315
        /* The speed switcher also puts us back in TSIP, so call it
6316
         * with the default 9600 8O1. */
6317
        // FIXME: Should preserve the current speed.
6318
        // (void)tsip_speed_switch(session, 9600, 'O', 1);
6319
        // FIXME: should config TSIP binary!
6320
0
        ;
6321
6322
0
    } else {
6323
0
        GPSD_LOG(LOG_ERROR, &session->context->errout,
6324
0
                 "TSIP: unknown mode %i requested\n", mode);
6325
0
    }
6326
0
}
6327
6328
// this is everything we export
6329
// *INDENT-OFF*
6330
const struct gps_type_t driver_tsip =
6331
{
6332
    .type_name      = "Trimble TSIP",     // full name of type
6333
    .packet_type    = TSIP_PACKET,        // associated lexer packet type
6334
    .flags          = DRIVER_STICKY,      // remember this
6335
    .trigger        = NULL,               // no trigger
6336
    .channels       = TSIP_CHANNELS,      // consumer-grade GPS
6337
    .probe_detect   = tsip_detect,        // probe for 9600O81 device
6338
    .get_packet     = packet_get1,        // use the generic packet getter
6339
    .parse_packet   = tsip_parse_input,   // parse message packets
6340
    .rtcm_writer    = NULL,               // doesn't accept DGPS corrections
6341
    .init_query     = tsip_init_query,    // non-perturbing initial query
6342
    .event_hook     = tsip_event_hook,    // fire on various lifetime events
6343
    .speed_switcher = tsip_speed_switch,  // change baud rate
6344
    .mode_switcher  = tsip_mode,          // there is a mode switcher
6345
    .rate_switcher  = NULL,               // no rate switcher
6346
    .min_cycle.tv_sec  = 1,               // not relevant, no rate switch
6347
    .min_cycle.tv_nsec = 0,               // not relevant, no rate switch
6348
    .control_send   = tsip_write1,        // how to send commands
6349
    .time_offset     = NULL,
6350
};
6351
// *INDENT-ON*
6352
6353
#endif  // TSIP_ENABLE
6354
6355
// vim: set expandtab shiftwidth=4