Coverage Report

Created: 2024-10-20 06:20

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