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 * This file is Copyright (c) 2010-2019 by the GPSD project
13 * SPDX-License-Identifier: BSD-2-clause
14 */
15
16 #include "gpsd_config.h" /* must be before all includes */
17
18 #include <math.h>
19 #include <stdbool.h>
20 #include <stdio.h>
21 #include <stdlib.h> // For llabs()
22 #include <string.h>
23 #include <time.h>
24 #include <unistd.h>
25
26 #include "gpsd.h"
27 #include "bits.h"
28 #include "strfuncs.h"
29 #include "timespec.h"
30
31 #ifdef TSIP_ENABLE
32 // RES SMT 360 has 32 max channels, use 64 for next gen
33 #define TSIP_CHANNELS 64
34
35 /* defines for Set or Request I/O Options (0x35)
36 * SMT 360 default: IO1_DP|IO1_LLA, IO2_ENU, 0, IO4_DBHZ */
37 // byte 1 Position
38 #define IO1_ECEF 1
39 #define IO1_LLA 2
40 #define IO1_MSL 4
41 #define IO1_DP 0x10
42 // IO1_8F20 not in SMT 360
43 #define IO1_8F20 0x20
44 // byte 2 Velocity
45 #define IO2_VECEF 1
46 #define IO2_ENU 2
47 // byte 3 Timing
48 #define IO3_UTC 1
49 // byte 4 Aux/Reserved
50 #define IO4_RAW 1
51 #define IO4_DBHZ 8
52
53 #define SEMI_2_DEG (180.0 / 2147483647) /* 2^-31 semicircle to deg */
54
55 void configuration_packets_acutime_gold(struct gps_device_t *session);
56 void configuration_packets_res360(struct gps_device_t *session);
57 void configuration_packets_generic(struct gps_device_t *session);
58
59 /* convert TSIP SV Type to satellite_t.gnssid and satellite_t.svid
60 * return gnssid directly, svid indirectly through pointer */
tsip_gnssid(unsigned svtype,short prn,unsigned char * svid)61 static unsigned char tsip_gnssid(unsigned svtype, short prn,
62 unsigned char *svid)
63 {
64 unsigned char gnssid;
65
66 *svid = 0;
67
68 switch (svtype) {
69 case 0:
70 if (0 < prn && 33 > prn) {
71 gnssid = GNSSID_GPS;
72 *svid = prn;
73 } else if (32 < prn && 55 > prn) {
74 // RES SMT 360 and ICM SMT 360 put SBAS in 33-54
75 gnssid = GNSSID_SBAS;
76 *svid = prn + 87;
77 } else if (64 < prn && 97 > prn) {
78 // RES SMT 360 and ICM SMT 360 put GLONASS in 65-96
79 gnssid = GNSSID_GLO;
80 *svid = prn - 64;
81 } else if (96 < prn && 134 > prn) {
82 // RES SMT 360 and ICM SMT 360 put Galileo in 97-133
83 gnssid = GNSSID_GAL;
84 *svid = prn - 96;
85 } else if (119 < prn && 139 > prn) {
86 // Copernicus (II) put SBAS in 120-138
87 gnssid = GNSSID_SBAS;
88 *svid = prn + 87;
89 } else if (183 == prn) {
90 gnssid = GNSSID_QZSS;
91 *svid = 1;
92 } else if (192 >= prn && 193 >= prn) {
93 gnssid = GNSSID_QZSS;
94 *svid = prn - 190;
95 } else if (200 == prn) {
96 gnssid = GNSSID_QZSS;
97 *svid = 4;
98 } else if (200 < prn && 238 > prn) {
99 // BeidDou in 201-237
100 gnssid = GNSSID_BD;
101 *svid = prn - 200;
102 }
103 // else: huh?
104 break;
105 case 1:
106 gnssid = GNSSID_GLO; // GLONASS
107 *svid = prn - 64;
108 break;
109 case 2:
110 gnssid = GNSSID_BD; // BeiDou
111 *svid = prn - 200;
112 break;
113 case 3:
114 gnssid = GNSSID_GAL; // Galileo
115 *svid = prn - 96;
116 break;
117 case 5:
118 gnssid = GNSSID_QZSS; // QZSS
119 switch (prn) {
120 case 183:
121 *svid = 1;
122 break;
123 case 192:
124 *svid = 2;
125 break;
126 case 193:
127 *svid = 3;
128 break;
129 case 200:
130 *svid = 4;
131 break;
132 default:
133 *svid = prn;
134 break;
135 }
136 break;
137 case 4:
138 // FALLTHROUGH
139 case 6:
140 // FALLTHROUGH
141 case 7:
142 // FALLTHROUGH
143 default:
144 svid = 0;
145 gnssid = 0;
146 break;
147 }
148 return gnssid;
149 }
150
tsip_write(struct gps_device_t * session,unsigned int id,unsigned char * buf,size_t len)151 static int tsip_write(struct gps_device_t *session,
152 unsigned int id, unsigned char *buf, size_t len)
153 {
154 char *ep, *cp;
155 char obuf[100];
156 size_t olen = len;
157
158 session->msgbuf[0] = '\x10';
159 session->msgbuf[1] = (char)id;
160 ep = session->msgbuf + 2;
161 for (cp = (char *)buf; olen-- > 0; cp++) {
162 if (*cp == '\x10')
163 *ep++ = '\x10';
164 *ep++ = *cp;
165 }
166 *ep++ = '\x10';
167 *ep++ = '\x03';
168 session->msgbuflen = (size_t) (ep - session->msgbuf);
169 GPSD_LOG(LOG_PROG, &session->context->errout,
170 "TSIP: Sent packet id 0x%s\n",
171 gpsd_hexdump(obuf, sizeof(obuf), &session->msgbuf[1], len + 1));
172 if (gpsd_write(session, session->msgbuf, session->msgbuflen) !=
173 (ssize_t) session->msgbuflen)
174 return -1;
175
176 return 0;
177 }
178
179 /* tsip_detect()
180 *
181 * see if it looks like a TSIP device (speaking 9600O81) is listening and
182 * return 1 if found, 0 if not
183 */
tsip_detect(struct gps_device_t * session)184 static bool tsip_detect(struct gps_device_t *session)
185 {
186 char buf[BUFSIZ];
187 bool ret = false;
188 int myfd;
189 speed_t old_baudrate;
190 char old_parity;
191 unsigned int old_stopbits;
192
193 old_baudrate = session->gpsdata.dev.baudrate;
194 old_parity = session->gpsdata.dev.parity;
195 old_stopbits = session->gpsdata.dev.stopbits;
196 // FIXME. Should respect fixed speed/framing
197 gpsd_set_speed(session, 9600, 'O', 1);
198
199 /* request firmware revision and look for a valid response */
200 putbyte(buf, 0, 0x10);
201 putbyte(buf, 1, 0x1f);
202 putbyte(buf, 2, 0x10);
203 putbyte(buf, 3, 0x03);
204 myfd = session->gpsdata.gps_fd;
205 if (write(myfd, buf, 4) == 4) {
206 unsigned int n;
207 for (n = 0; n < 3; n++) {
208 if (!nanowait(myfd, NS_IN_SEC))
209 break;
210 if (generic_get(session) >= 0) {
211 if (session->lexer.type == TSIP_PACKET) {
212 GPSD_LOG(LOG_RAW, &session->context->errout,
213 "TSIP: tsip_detect found\n");
214 ret = true;
215 break;
216 }
217 }
218 }
219 }
220
221 if (!ret)
222 /* return serial port to original settings */
223 gpsd_set_speed(session, old_baudrate, old_parity, old_stopbits);
224
225 return ret;
226 }
227
228 /* This is the meat of parsing all the TSIP packets */
tsip_parse_input(struct gps_device_t * session)229 static gps_mask_t tsip_parse_input(struct gps_device_t *session)
230 {
231 int i, j, len, count;
232 gps_mask_t mask = 0;
233 unsigned int id;
234 unsigned short week;
235 uint8_t u1, u2, u3, u4, u5, u6, u7, u8, u9, u10;
236 int16_t s1, s2, s3, s4;
237 int32_t sl1, sl2, sl3;
238 uint32_t ul1, ul2;
239 float f1, f2, f3, f4;
240 double d1, d2, d3, d4, d5;
241 time_t now;
242 unsigned char buf[BUFSIZ];
243 char buf2[BUFSIZ];
244 uint32_t tow; // time of week in milli seconds
245 double ftow; // time of week in seconds
246 double temp; // tempurature in degrees C
247 double fqErr; // PPS Offset. positive is slow.
248 timespec_t ts_tow;
249 char ts_buf[TIMESPEC_LEN];
250 int bad_len = 0;
251 const char *name;
252
253 if (session->lexer.type != TSIP_PACKET) {
254 // this should not happen
255 GPSD_LOG(LOG_INF, &session->context->errout,
256 "TSIP: tsip_analyze packet type %d\n",
257 session->lexer.type);
258 return 0;
259 }
260
261 if (session->lexer.outbuflen < 4 || session->lexer.outbuffer[0] != 0x10) {
262 /* packet too short, or does not start with DLE */
263 GPSD_LOG(LOG_INF, &session->context->errout,
264 "TSIP: tsip_analyze packet bad packet\n");
265 return 0;
266 }
267
268 // get receive time, first
269 (void)time(&now);
270
271 /* remove DLE stuffing and put data part of message in buf */
272
273 memset(buf, 0, sizeof(buf));
274 buf2[len = 0] = '\0';
275 for (i = 2; i < (int)session->lexer.outbuflen; i++) {
276 if (session->lexer.outbuffer[i] == 0x10)
277 if (session->lexer.outbuffer[++i] == 0x03)
278 break;
279
280 // FIXME expensive way to do hex
281 str_appendf(buf2, sizeof(buf2),
282 "%02x", buf[len++] = session->lexer.outbuffer[i]);
283 }
284
285 id = (unsigned)session->lexer.outbuffer[1];
286 GPSD_LOG(LOG_DATA, &session->context->errout,
287 "TSIP: got packet id 0x%02x length %d: %s\n",
288 id, len, buf2);
289
290 // session->cycle_end_reliable = true;
291 switch (id) {
292 case 0x13:
293 /* Packet Received
294 * Present in:
295 * pre-2000 models
296 * ICM SMT 360 (2018)
297 * RES SMT 360 (2018)
298 * Not present in:
299 * Copernicus II
300 */
301 if (1 > len) {
302 bad_len = 1;
303 break;
304 }
305 u1 = getub(buf, 0); // Packet ID of non-parsable packet
306 if (2 <= len) {
307 u2 = getub(buf, 1); // Data byte 0 of non-parsable packet
308 } else {
309 u2 = 0;
310 }
311 GPSD_LOG(LOG_WARN, &session->context->errout,
312 "TSIP: Report Packet (0x13): type x%02x %02x "
313 "cannot be parsed\n",
314 u1, u2);
315 // ignore the rest of the bad data
316 if ((int)u1 == 0x8e && (int)u2 == 0x23) {
317 /* no Compact Super Packet 0x8e-23 */
318 GPSD_LOG(LOG_WARN, &session->context->errout,
319 "TSIP: No 0x8e-23, use LFwEI (0x8f-20)\n");
320
321 /* Request LFwEI Super Packet instead
322 * SMT 360 does not support 0x8e-20 either */
323 putbyte(buf, 0, 0x20);
324 putbyte(buf, 1, 0x01); /* auto-report */
325 (void)tsip_write(session, 0x8e, buf, 2);
326 }
327 break;
328
329 case 0x1c: // Hardware/Software Version Information
330 /* Present in:
331 * Acutime Gold
332 * Lassen iQ (2005) fw 1.16+
333 * Copernicus (2006)
334 * Copernicus II (2009)
335 * Thunderbolt E (2012)
336 * RES SMT 360 (2018)
337 * ICM SMT 360 (2018)
338 * RES360 17x22 (2018)
339 * Acutime 360
340 * Not Present in:
341 * pre-2000 models
342 * ACE II (1999)
343 * ACE III (2000)
344 * Lassen SQ (2002)
345 * Lassen iQ (2005) pre fw 1.16
346 */
347 u1 = (uint8_t) getub(buf, 0);
348 // decode by sub-code
349 switch (u1) {
350 case 0x81:
351 /* Firmware component version information (0x1c-81)
352 * polled by 0x1c-01
353 * Present in:
354 * Copernicus II (2009)
355 */
356 // byte 1, reserved
357 u2 = getub(buf, 2); // Major version
358 u3 = getub(buf, 3); // Minor version
359 u4 = getub(buf, 4); // Build number
360 u5 = getub(buf, 5); // Build Month
361 u6 = getub(buf, 6); // Build Day
362 ul1 = getbeu16(buf, 7); // Build Year
363 u7 = getub(buf, 9); // Length of product name
364 // check for valid module name length
365 if (40 < u7) {
366 u7 = 40;
367 }
368 // check for valid module name length, again
369 if (u7 > (len - 10)) {
370 u7 = len - 10;
371 }
372 /* Product name in ASCII */
373 memcpy(buf2, &buf[10], u7);
374 buf2[u7] = '\0';
375
376 (void)snprintf(session->subtype, sizeof(session->subtype),
377 "fw %u.%u %u %02u/%02u/%04u %.40s",
378 u2, u3, u4, u6, u5, ul1, buf2);
379 GPSD_LOG(LOG_PROG, &session->context->errout,
380 "TSIP: Firmware version (0x1c-81): %s\n",
381 session->subtype);
382
383 mask |= DEVICEID_SET;
384 if ('\0' == session->subtype1[0]) {
385 // request actual subtype1 from 0x1c-83
386 putbyte(buf, 0, 0x03);
387 (void)tsip_write(session, 0x1c, buf, 1);
388 }
389 break;
390
391 case 0x83:
392 /* Hardware component version information (0x1c-83)
393 * polled by 0x1c-03
394 * Not Present in:
395 * Copernicus II (2009)
396 */
397 ul1 = getbeu32(buf, 1); // Serial number
398 u2 = getub(buf, 5); // Build day
399 u3 = getub(buf, 6); // Build month
400 ul2 = getbeu16(buf, 7); // Build year
401 u4 = getub(buf, 9); // Build hour
402 /* Hardware Code */
403 session->driver.tsip.hardware_code = getbeu16(buf, 10);
404 u5 = getub(buf, 12); /* Length of Hardware ID */
405 // check for valid module name length
406 // copernicus ii is 27 long
407 if (40 < u5) {
408 u5 = 40;
409 }
410 // check for valid module name length, again
411 if (u5 > (len - 13)) {
412 u5 = len - 13;
413 }
414 memcpy(buf2, &buf[13], u5);
415 buf2[u5] = '\0';
416
417 (void)snprintf(session->subtype1, sizeof(session->subtype1),
418 "hw %u %02u/%02u/%04u %02u %04u %.40s",
419 ul1, u2, u3, ul2, u4,
420 session->driver.tsip.hardware_code,
421 buf2);
422 GPSD_LOG(LOG_PROG, &session->context->errout,
423 "TSIP: Hardware version (0x1c-83): %s\n",
424 session->subtype1);
425
426 mask |= DEVICEID_SET;
427
428 /* Detecting device by Hardware Code */
429 switch (session->driver.tsip.hardware_code) {
430 case 3001: // Acutime Gold
431 session->driver.tsip.subtype = TSIP_ACUTIME_GOLD;
432 configuration_packets_acutime_gold(session);
433 break;
434 case 3023: // RES SMT 360
435 session->driver.tsip.subtype = TSIP_RESSMT360;
436 configuration_packets_res360(session);
437 break;
438 case 3026: // ICM SMT 360
439 session->driver.tsip.subtype = TSIP_ICMSMT360;
440 configuration_packets_res360(session);
441 break;
442 case 3031: // RES360 17x22
443 session->driver.tsip.subtype = TSIP_RES36017x22;
444 configuration_packets_res360(session);
445 break;
446 case 1001: // Lassen iQ
447 // FALLTHROUGH
448 case 1002: // Copernicus, Copernicus II
449 // FALLTHROUGH
450 case 3007: // Thunderbolt E
451 // FALLTHROUGH
452 case 3032: // Acutime 360
453 // FALLTHROUGH
454 default:
455 configuration_packets_generic(session);
456 break;
457 }
458 break;
459 default:
460 GPSD_LOG(LOG_ERROR, &session->context->errout,
461 "TSIP: Unhandled subpacket ID 0x1c-%x\n", u1);
462 break;
463 }
464 break;
465 case 0x41:
466 /* GPS Time (0x41). polled by 0x21
467 * Note: this is not the time of current fix
468 * Present in:
469 * pre-2000 models
470 * Copernicus II (2009)
471 * ICM SMT 360 (2018)
472 * RES SMT 360 (2018)
473 */
474 if (len != 10) {
475 bad_len = 10;
476 break;
477 }
478 session->driver.tsip.last_41 = now; /* keep timestamp for request */
479 ftow = getbef32((char *)buf, 0); /* gpstime */
480 week = getbeu16(buf, 4); /* week */
481 f2 = getbef32((char *)buf, 6); /* leap seconds */
482 if (ftow >= 0.0 && f2 > 10.0) {
483 session->context->leap_seconds = (int)round(f2);
484 session->context->valid |= LEAP_SECOND_VALID;
485 DTOTS(&ts_tow, ftow);
486 session->newdata.time =
487 gpsd_gpstime_resolv(session, week, ts_tow);
488 mask |= TIME_SET | NTPTIME_IS;
489 /* Note: this is not the time of current fix
490 * Do not use in tsip.last_tow */
491 }
492 GPSD_LOG(LOG_PROG, &session->context->errout,
493 "TSIP: GPS Time (0x41): tow %.2f week %u ls %.1f %s\n",
494 ftow, week, f2,
495 timespec_str(&session->newdata.time, ts_buf, sizeof(ts_buf)));
496 break;
497 case 0x42:
498 /* Single-Precision Position Fix, XYZ ECEF
499 * Present in:
500 * pre-2000 models
501 * Copernicus II (2009)
502 * ICM SMT 360 (2018)
503 * RES SMT 360 (2018)
504 */
505 if (16 > len) {
506 bad_len = 16;
507 break;
508 }
509 session->newdata.ecef.x = getbef32((char *)buf, 0); /* X */
510 session->newdata.ecef.y = getbef32((char *)buf, 4); /* Y */
511 session->newdata.ecef.z = getbef32((char *)buf, 8); /* Z */
512 ftow = getbef32((char *)buf, 12); /* time-of-fix */
513 DTOTS(&ts_tow, ftow);
514 session->newdata.time = gpsd_gpstime_resolv(session,
515 session->context->gps_week,
516 ts_tow);
517 GPSD_LOG(LOG_PROG, &session->context->errout,
518 "TSIP: SP-XYZ (0x42): %f %f %f ftow %f\n",
519 session->newdata.ecef.x,
520 session->newdata.ecef.y,
521 session->newdata.ecef.z,
522 ftow);
523 mask = ECEF_SET | TIME_SET | NTPTIME_IS;
524 if (!TS_EQ(&ts_tow, &session->driver.tsip.last_tow)) {
525 mask |= CLEAR_IS;
526 session->driver.tsip.last_tow = ts_tow;
527 }
528 break;
529 case 0x43:
530 /* Velocity Fix, XYZ ECEF
531 * Present in:
532 * pre-2000 models
533 * ICM SMT 360 (2018)
534 * RES SMT 360 (2018)
535 * Not Present in:
536 * Copernicus II (2009)
537 */
538 if (len != 20) {
539 bad_len = 20;
540 break;
541 }
542 session->newdata.ecef.vx = getbef32((char *)buf, 0); // X velocity
543 session->newdata.ecef.vy = getbef32((char *)buf, 4); // Y velocity
544 session->newdata.ecef.vz = getbef32((char *)buf, 8); // Z velocity
545 f4 = getbef32((char *)buf, 12); /* bias rate */
546 ftow = getbef32((char *)buf, 16); /* time-of-fix */
547 DTOTS(&ts_tow, ftow);
548 session->newdata.time = gpsd_gpstime_resolv(session,
549 session->context->gps_week,
550 ts_tow);
551 GPSD_LOG(LOG_PROG, &session->context->errout,
552 "TSIP: Vel XYZ (0x43): %f %f %f %f ftow %f\n",
553 session->newdata.ecef.vx,
554 session->newdata.ecef.vy,
555 session->newdata.ecef.vz,
556 f4, ftow);
557 mask = VECEF_SET | TIME_SET | NTPTIME_IS;
558 if (!TS_EQ(&ts_tow, &session->driver.tsip.last_tow)) {
559 mask |= CLEAR_IS;
560 session->driver.tsip.last_tow = ts_tow;
561 }
562 break;
563 case 0x45:
564 /* Software Version Information (0x45)
565 * Present in:
566 * pre-2000 models
567 * ACE II (1999)
568 * ACE III (2000)
569 * Lassen SQ (2002)
570 * Lassen iQ (2005)
571 * Copernicus II (2009)
572 * ICM SMT 360
573 * RES SMT 360
574 * Probably all TSIP
575 */
576 if (10 > len) {
577 bad_len = 10;
578 break;
579 }
580 // convert 2 digit years to 4 digit years
581 ul1 = getub(buf, 3);
582 if (80 > ul1) {
583 ul1 += 2000;
584 } else {
585 ul1 += 1900;
586 }
587 ul2 = getub(buf, 8);
588 if (80 > ul2) {
589 ul2 += 2000;
590 } else {
591 ul2 += 1900;
592 }
593 /* ACE calls these "NAV processor firmware" and
594 * "SIG processor firmware".
595 * RES SMT 360 calls these "application" and "GPS core".
596 */
597 (void)snprintf(session->subtype, sizeof(session->subtype),
598 "sw %d.%d %02d/%02d/%04d hw %d.%d %02d/%02d/%04d",
599 getub(buf, 0),
600 getub(buf, 1),
601 getub(buf, 4),
602 getub(buf, 2),
603 ul1,
604 getub(buf, 5),
605 getub(buf, 6),
606 getub(buf, 9),
607 getub(buf, 7),
608 ul2);
609 GPSD_LOG(LOG_PROG, &session->context->errout,
610 "TSIP: Software version (0x45): %s\n", session->subtype);
611 mask |= DEVICEID_SET;
612 break;
613 case 0x46:
614 /* Health of Receiver (0x46). Poll with 0x26
615 * Present in:
616 * pre-2000 models
617 * Copernicus II (2009)
618 * ICM SMT 360 (2018)
619 * RES SMT 360 (2018)
620 * all models?
621 * RES SMT 360 says use 0x8f-ab or 0x8f-ac instead
622 */
623 if ( 2 > len) {
624 bad_len = 2;
625 break;
626 }
627 session->driver.tsip.last_46 = now;
628 u1 = getub(buf, 0); /* Status code */
629 /* Error codes, model dependent
630 * 0x01 -- no battery, always set on RES SMT 360
631 * 0x10 -- antenna fault
632 * 0x20 -- antenna is shorted
633 */
634 u2 = getub(buf, 1);
635 if ((uint8_t)0 != u1) {
636 session->gpsdata.status = STATUS_NO_FIX;
637 mask |= STATUS_SET;
638 } else if (session->gpsdata.status < STATUS_FIX) {
639 session->gpsdata.status = STATUS_FIX;
640 mask |= STATUS_SET;
641 }
642 GPSD_LOG(LOG_PROG, &session->context->errout,
643 "TSIP: Receiver Health (0x46): %x %x\n", u1, u2);
644 break;
645 case 0x47:
646 /* Signal Levels for all Satellites
647 * Present in:
648 * pre-2000 models
649 * Copernicus II (2009)
650 * ICM SMT 360 (2018)
651 * RES SMT 360 (2018)
652 */
653 if (1 > len) {
654 bad_len = 1;
655 break;
656 }
657 gpsd_zero_satellites(&session->gpsdata);
658 /* satellite count, RES SMT 360 doc says 12 max */
659 count = (int)getub(buf, 0);
660 if (len != (5 * count + 1)) {
661 bad_len = 5 * count + 1;
662 break;
663 }
664 buf2[0] = '\0';
665 for (i = 0; i < count; i++) {
666 u1 = getub(buf, 5 * i + 1);
667 if ((f1 = getbef32((char *)buf, 5 * i + 2)) < 0)
668 f1 = 0.0;
669 for (j = 0; j < TSIP_CHANNELS; j++)
670 if (session->gpsdata.skyview[j].PRN == (short)u1) {
671 session->gpsdata.skyview[j].ss = f1;
672 break;
673 }
674 str_appendf(buf2, sizeof(buf2), " %d=%.1f", (int)u1, f1);
675 }
676 GPSD_LOG(LOG_PROG, &session->context->errout,
677 "TSIP: Signal Levels (0x47): (%d):%s\n", count, buf2);
678 mask |= SATELLITE_SET;
679 break;
680 case 0x48:
681 /* GPS System Message
682 * Present in:
683 * pre-2000 models
684 * Not Present in:
685 * Copernicus II (2009)
686 * ICM SMT 360 (2018)
687 * RES SMT 360 (2018)
688 */
689 buf[len] = '\0';
690 GPSD_LOG(LOG_PROG, &session->context->errout,
691 "TSIP: GPS System Message (0x48): %s\n", buf);
692 break;
693 case 0x4a:
694 /* Single-Precision Position LLA
695 * Present in:
696 * pre-2000 models
697 * Copernicus II (2009)
698 * ICM SMT 360 (2018)
699 * RES SMT 360 (2018)
700 */
701 if (len != 20) {
702 bad_len = 20;
703 break;
704 }
705 session->newdata.latitude = getbef32((char *)buf, 0) * RAD_2_DEG;
706 session->newdata.longitude = getbef32((char *)buf, 4) * RAD_2_DEG;
707 /* depending on GPS config, could be either WGS84 or MSL */
708 d1 = getbef32((char *)buf, 8);
709 if (0 == session->driver.tsip.alt_is_msl) {
710 session->newdata.altHAE = d1;
711 } else {
712 session->newdata.altMSL = d1;
713 }
714
715 //f1 = getbef32((char *)buf, 12); clock bias */
716 ftow = getbef32((char *)buf, 16); /* time-of-fix */
717 if ((session->context->valid & GPS_TIME_VALID)!=0) {
718 DTOTS(&ts_tow, ftow);
719 session->newdata.time =
720 gpsd_gpstime_resolv(session, session->context->gps_week,
721 ts_tow);
722 mask |= TIME_SET | NTPTIME_IS;
723 if (!TS_EQ(&ts_tow, &session->driver.tsip.last_tow)) {
724 mask |= CLEAR_IS;
725 session->driver.tsip.last_tow = ts_tow;
726 }
727 }
728 // this seems to be often first in cycle
729 // REPORT_IS here breaks reports in read-only mode
730 mask |= LATLON_SET | ALTITUDE_SET;
731 GPSD_LOG(LOG_DATA, &session->context->errout,
732 "TSIP: SP-LLA (0x4a): time=%s lat=%.2f lon=%.2f "
733 "alt=%.2f\n",
734 timespec_str(&session->newdata.time, ts_buf, sizeof(ts_buf)),
735 session->newdata.latitude,
736 session->newdata.longitude, d1);
737 break;
738 case 0x4b:
739 /* Machine/Code ID and Additional Status (0x4b)
740 * polled by i0x25 or 0x26. Sent with 0x46.
741 * Present in:
742 * pre-2000 models
743 * Copernicus II (2009)
744 * ICM SMT 360 (2018)
745 * RES SMT 360 (2018)
746 * all receivers?
747 */
748 if (len != 3) {
749 bad_len = 3;
750 break;
751 }
752 session->driver.tsip.machine_id = getub(buf, 0); /* Machine ID */
753 /* Status 1
754 * bit 1 -- No RTC at power up
755 * bit 3 -- almanac not complete and current */
756 u2 = getub(buf, 1);
757 u3 = getub(buf, 2); /* Status 2/Superpacket Support */
758 GPSD_LOG(LOG_PROG, &session->context->errout,
759 "TSIP: Machine ID (0x4b): %02x %02x %02x\n",
760 session->driver.tsip.machine_id,
761 u2, u3);
762
763 if ('\0' == session->subtype[0]) {
764 // better than nothing
765 switch (session->driver.tsip.machine_id) {
766 case 1:
767 // should use better name from superpacket
768 name = " SMT 360";
769 /* request actual subtype from 0x1c-81
770 * which in turn requests 0x1c-83 */
771 putbyte(buf, 0, 0x01);
772 (void)tsip_write(session, 0x1c, buf, 1);
773 break;
774 case 0x32:
775 name = " Acutime 360";
776 break;
777 case 0x5a:
778 name = " Lassen iQ";
779 /* request actual subtype from 0x1c-81
780 * which in turn requests 0x1c-83.
781 * Only later firmware Lassen iQ supports this */
782 putbyte(buf, 0, 0x01);
783 (void)tsip_write(session, 0x1c, buf, 1);
784 break;
785 case 0x61:
786 name = " Acutime 2000";
787 break;
788 case 0x62:
789 name = " ACE UTC";
790 break;
791 case 0x96:
792 // Also Copernicus II
793 name = " Copernicus, Thunderbolt E";
794 /* so request actual subtype from 0x1c-81
795 * which in turn requests 0x1c-83 */
796 putbyte(buf, 0, 0x01);
797 (void)tsip_write(session, 0x1c, buf, 1);
798 break;
799 default:
800 name = "";
801 }
802 (void)snprintf(session->subtype, sizeof(session->subtype),
803 "Machine ID x%x%s",
804 session->driver.tsip.machine_id, name);
805 }
806 if (u3 != session->driver.tsip.superpkt) {
807 session->driver.tsip.superpkt = u3;
808 GPSD_LOG(LOG_PROG, &session->context->errout,
809 "TSIP: Switching to Super Packet mode %d\n", u3);
810 switch (u3){
811 default:
812 // FALLTHROUGH
813 case 0:
814 // old Trimble, no superpackets
815 break;
816 case 1:
817 // 1 == superpacket is acutime 360, support 0x8f-20
818
819 /* set I/O Options for Super Packet output */
820 /* Position: 8F20, ECEF, DP */
821 putbyte(buf, 0, IO1_8F20|IO1_DP|IO1_ECEF);
822 putbyte(buf, 1, 0x00); /* Velocity: none (via SP) */
823 putbyte(buf, 2, 0x00); /* Time: GPS */
824 putbyte(buf, 3, IO4_DBHZ); /* Aux: dBHz */
825 (void)tsip_write(session, 0x35, buf, 4);
826 break;
827 case 2:
828 // 2 == SMT 360, no 0x8f-20
829 break;
830 }
831 }
832 break;
833 case 0x4c:
834 /* Operating Parameters Report (0x4c). Polled by 0x2c
835 * Present in:
836 * pre-2000 models
837 * Lassen iQ, but not documented
838 * Not Present in:
839 * Copernicus II (2009)
840 * ICM SMT 360 (2018)
841 * RES SMT 360 (2018)
842 */
843 if (len != 17) {
844 bad_len = 17;
845 break;
846 }
847 u1 = getub(buf, 0); // Dynamics Code
848 f1 = getbef32((char *)buf, 1); // Elevation Mask
849 f2 = getbef32((char *)buf, 5); // Signal Level Mask
850 f3 = getbef32((char *)buf, 9); // PDOP Mask
851 f4 = getbef32((char *)buf, 13); // PDOP Switch
852 GPSD_LOG(LOG_PROG, &session->context->errout,
853 "TSIP: Operating Params (0x4c): x%02x %f %f %f %f\n",
854 u1, f1, f2, f3, f4);
855 break;
856 case 0x54:
857 /* Bias and Bias Rate Report (0x54)
858 * Present in:
859 * pre-2000 models
860 * Acutime 360
861 * ICM SMT 360 (undocumented)
862 * RES SMT 360 (undocumented)
863 * Not Present in:
864 * Copernicus II (2009)
865 */
866 {
867 float bias, bias_rate;
868 bias = getbef32((char *)buf, 0); // Bias
869 bias_rate = getbef32((char *)buf, 4); // Bias rate
870 ftow = getbef32((char *)buf, 8); // tow
871 DTOTS(&ts_tow, ftow);
872 session->newdata.time =
873 gpsd_gpstime_resolv(session, session->context->gps_week,
874 ts_tow);
875 GPSD_LOG(LOG_PROG, &session->context->errout,
876 "TSIP: Bias and Bias Rate Report (0x54) %f %f %f\n",
877 bias, bias_rate, ftow);
878 mask |= TIME_SET | NTPTIME_IS;
879 if (!TS_EQ(&ts_tow, &session->driver.tsip.last_tow)) {
880 mask |= CLEAR_IS;
881 session->driver.tsip.last_tow = ts_tow;
882 }
883 }
884 break;
885 case 0x55:
886 /* IO Options (0x55), polled by 0x35
887 * Present in:
888 * pre-2000 models
889 * ICM SMT 360 (2018)
890 * RES SMT 360 (2018)
891 * all TSIP?
892 *
893 * Lassen iQ defaults: 02 02 00 00
894 * RES SMT 360 defaults: 12 02 00 08
895 */
896 if (len != 4) {
897 bad_len = 4;
898 break;
899 }
900 u1 = getub(buf, 0); /* Position */
901 // decode HAE/MSL from Position byte
902 if (IO1_MSL == (IO1_MSL & u1)) {
903 session->driver.tsip.alt_is_msl = 1;
904 } else {
905 session->driver.tsip.alt_is_msl = 0;
906 }
907 u2 = getub(buf, 1); /* Velocity */
908 /* Timing
909 * bit 0 - reserved use 0x8e-a2 ?
910 */
911 u3 = getub(buf, 2);
912 /* Aux
913 * bit 0 - packet 0x5a (raw data)
914 * bit 3 -- Output dbHz
915 */
916 u4 = getub(buf, 3);
917 GPSD_LOG(LOG_PROG, &session->context->errout,
918 "TSIP: IO Options (0x55): %02x %02x %02x %02x\n",
919 u1, u2, u3, u4);
920 if ((u1 & 0x20) != (uint8_t) 0) {
921 /* Try to get Super Packets */
922 /* Turn off 0x8f-20 LFwEI Super Packet */
923 putbyte(buf, 0, 0x20);
924 putbyte(buf, 1, 0x00); /* disabled */
925 (void)tsip_write(session, 0x8e, buf, 2);
926
927 /* Turn on Compact Super Packet 0x8f-23 */
928 putbyte(buf, 0, 0x23);
929 putbyte(buf, 1, 0x01); /* enabled */
930 (void)tsip_write(session, 0x8e, buf, 2);
931 session->driver.tsip.req_compact = now;
932 }
933 break;
934 case 0x56:
935 /* Velocity Fix, East-North-Up (ENU)
936 * Present in:
937 * pre-2000 models
938 * Copernicus II (2009)
939 * ICM SMT 360 (2018)
940 * RES SMT 360 (2018)
941 */
942 if (len != 20) {
943 bad_len = 20;
944 break;
945 }
946 f1 = getbef32((char *)buf, 0); /* East velocity */
947 f2 = getbef32((char *)buf, 4); /* North velocity */
948 f3 = getbef32((char *)buf, 8); /* Up velocity */
949 f4 = getbef32((char *)buf, 12); /* clock bias rate */
950 ftow = getbef32((char *)buf, 16); /* time-of-fix */
951 DTOTS(&ts_tow, ftow);
952 session->newdata.time = gpsd_gpstime_resolv(session,
953 session->context->gps_week,
954 ts_tow);
955 session->newdata.NED.velN = f2;
956 session->newdata.NED.velE = f1;
957 session->newdata.NED.velD = -f3;
958 mask |= VNED_SET | TIME_SET | NTPTIME_IS;
959 if (!TS_EQ(&ts_tow, &session->driver.tsip.last_tow)) {
960 mask |= CLEAR_IS;
961 session->driver.tsip.last_tow = ts_tow;
962 }
963 GPSD_LOG(LOG_PROG, &session->context->errout,
964 "TSIP: Vel ENU (0x56): %f %f %f %f ftow %f\n",
965 f1, f2, f3, f4, ftow);
966 break;
967 case 0x57:
968 /* Information About Last Computed Fix
969 * Present in:
970 * pre-2000 models
971 * Copernicus II (2009)
972 * ICM SMT 360 (2018)
973 * RES SMT 360 (2018)
974 */
975 if (len != 8) {
976 bad_len = 8;
977 break;
978 }
979 u1 = getub(buf, 0); /* Source of information */
980 u2 = getub(buf, 1); /* Mfg. diagnostic */
981 ftow = getbef32((char *)buf, 2); /* gps_time */
982 week = getbeu16(buf, 6); /* tsip.gps_week */
983 if (getub(buf, 0) == 0x01) {
984 /* good current fix */
985 DTOTS(&ts_tow, ftow);
986 (void)gpsd_gpstime_resolv(session, week, ts_tow);
987 mask |= TIME_SET | NTPTIME_IS;
988 if (!TS_EQ(&ts_tow, &session->driver.tsip.last_tow)) {
989 mask |= CLEAR_IS;
990 session->driver.tsip.last_tow = ts_tow;
991 }
992 }
993 GPSD_LOG(LOG_PROG, &session->context->errout,
994 "TSIP: Fix info (0x57): %02x %02x %u %f\n", u1, u2, week, f1);
995 break;
996 case 0x5a:
997 /* Raw Measurement Data
998 * Present in:
999 * pre-2000 models
1000 * Copernicus II (2009)
1001 * ICM SMT 360 (2018)
1002 * RES SMT 360 (2018)
1003 */
1004 if (25 > len) {
1005 bad_len = 25;
1006 break;
1007 }
1008 // Useless without the pseudorange...
1009 u1 = getub(buf, 0); // PRN 1-237
1010 f1 = getbef32((char *)buf, 1); // sample length
1011 f2 = getbef32((char *)buf, 5); // Signal Level, dbHz
1012 f3 = getbef32((char *)buf, 9); // Code phase, 1/16th chip
1013 f4 = getbef32((char *)buf, 13); // Doppler, Hz @ L1
1014 d1 = getbed64((char *)buf, 17); // Time of Measurement
1015 GPSD_LOG(LOG_PROG, &session->context->errout,
1016 "TSIP: Raw Measurement Data (0x5a): %d %f %f %f %f %f\n",
1017 u1, f1, f2, f3, f4, d1);
1018 break;
1019 case 0x5c:
1020 /* Satellite Tracking Status (0x5c) polled by 0x3c
1021 *
1022 * GPS only, no WAAS reported here or used in fix
1023 * Present in:
1024 * pre-2000 models
1025 * Copernicus, Copernicus II
1026 * Thunderbold E
1027 * Not Present in:
1028 * ICM SMT 360 (2018)
1029 * RES SMT 360 (2018)
1030 */
1031 if (len != 24) {
1032 bad_len = 24;
1033 break;
1034 }
1035 u1 = getub(buf, 0); /* PRN 1-32 */
1036 u2 = getub(buf, 1); /* slot:chan */
1037 u3 = getub(buf, 2); /* Acquisition flag */
1038 u4 = getub(buf, 3); /* Ephemeris flag */
1039 f1 = getbef32((char *)buf, 4); /* Signal level */
1040 ftow = getbef32((char *)buf, 8); /* time of Last measurement */
1041 d1 = getbef32((char *)buf, 12) * RAD_2_DEG; /* Elevation */
1042 d2 = getbef32((char *)buf, 16) * RAD_2_DEG; /* Azimuth */
1043
1044 /* Channel number, bits 0-2 reserved/unused as of 1999.
1045 * Seems to always start series at zero and increment to last one.
1046 * No way to know how many there will be.
1047 * Save current channel to check for last 0x5c message
1048 */
1049 i = (int)(u2 >> 3); /* channel number */
1050 if (0 == i) {
1051 // start of new cycle, save last count
1052 session->gpsdata.satellites_visible =
1053 session->driver.tsip.last_chan_seen;
1054 }
1055 session->driver.tsip.last_chan_seen = i;
1056
1057 GPSD_LOG(LOG_PROG, &session->context->errout,
1058 "TSIP: Satellite Tracking Status (0x5c): Ch %2d PRN %3d "
1059 "es %d Acq %d Eph %2d SNR %4.1f LMT %.04f El %4.1f Az %5.1f\n",
1060 i, u1, u2 & 7, u3, u4, f1, ftow, d1, d2);
1061 if (i < TSIP_CHANNELS) {
1062 session->gpsdata.skyview[i].PRN = (short)u1;
1063 session->gpsdata.skyview[i].svid = (unsigned char)u1;
1064 session->gpsdata.skyview[i].gnssid = GNSSID_GPS;
1065 session->gpsdata.skyview[i].ss = (double)f1;
1066 session->gpsdata.skyview[i].elevation = (double)d1;
1067 session->gpsdata.skyview[i].azimuth = (double)d2;
1068 session->gpsdata.skyview[i].used = false;
1069 session->gpsdata.skyview[i].gnssid = tsip_gnssid(0, u1,
1070 &session->gpsdata.skyview[i].svid);
1071 if (0.1 < f1) {
1072 // check used list, if ss is non-zero
1073 for (j = 0; j < session->gpsdata.satellites_used; j++) {
1074 if (session->gpsdata.skyview[i].PRN != 0 &&
1075 session->driver.tsip.sats_used[j] != 0) {
1076 session->gpsdata.skyview[i].used = true;
1077 }
1078 }
1079 }
1080 /* when polled by 0x3c, all the skyview times will be the same
1081 * in one cluster */
1082 if (0.0 < ftow) {
1083 DTOTS(&ts_tow, ftow);
1084 session->gpsdata.skyview_time =
1085 gpsd_gpstime_resolv(session, session->context->gps_week,
1086 ts_tow);
1087 /* do not save in session->driver.tsip.last_tow
1088 * as this is skyview time, not fix time */
1089 }
1090 if (++i >= session->gpsdata.satellites_visible) {
1091 /* Last of the series?
1092 * This will cause extra SKY if this set has more
1093 * sats than the last set */
1094 mask |= SATELLITE_SET;
1095 session->gpsdata.satellites_visible = i;
1096 }
1097 /* If this series has fewer than last series there will
1098 * be no SKY, unless the cycle ender pushes the SKY */
1099 }
1100 break;
1101
1102 case 0x5d:
1103 /* GNSS Satellite Tracking Status (multi-GNSS operation) (0x5d)
1104 * polled by 0x3c
1105 *
1106 * GNSS only, no WAAS reported here or used in fix
1107 * Present in:
1108 * ICM SMT 360 (2018)
1109 * RES SMT 360 (2018)
1110 * Not Present in:
1111 * pre-2000 models
1112 * Copernicus, Copernicus II
1113 * Thunderbold E
1114 */
1115 if (len != 26) {
1116 bad_len = 26;
1117 break;
1118 }
1119 u1 = getub(buf, 0); /* PRN */
1120
1121 /* Channel number, bits 0-2 reserved/unused as of 1999.
1122 * Seems to always start series at zero and increment to last one.
1123 * No way to know how many there will be.
1124 * Save current channel to check for last 0x5d message
1125 */
1126 i = getub(buf, 1); /* chan */
1127 if (0 == i) {
1128 // start of new cycle, save last count
1129 session->gpsdata.satellites_visible =
1130 session->driver.tsip.last_chan_seen;
1131 }
1132 session->driver.tsip.last_chan_seen = i;
1133
1134 u3 = getub(buf, 2); /* Acquisition flag */
1135 u4 = getub(buf, 3); /* SV used in Position or Time calculation*/
1136 f1 = getbef32((char *)buf, 4); /* Signal level */
1137 // This can be one second behind the TPV on RES SMT 360
1138 ftow = getbef32((char *)buf, 8); /* time of Last measurement */
1139 d1 = getbef32((char *)buf, 12) * RAD_2_DEG; /* Elevation */
1140 d2 = getbef32((char *)buf, 16) * RAD_2_DEG; /* Azimuth */
1141 u5 = getub(buf, 20); /* old measurement flag */
1142 u6 = getub(buf, 21); /* integer msec flag */
1143 u7 = getub(buf, 22); /* bad data flag */
1144 u8 = getub(buf, 23); /* data collection flag */
1145 u9 = getub(buf, 24); /* Used flags */
1146 u10 = getub(buf, 25); /* SV Type */
1147
1148
1149 GPSD_LOG(LOG_PROG, &session->context->errout,
1150 "TSIP: Satellite Tracking Status (0x5d): Ch %2d Con %d PRN %3d "
1151 "Acq %d Use %d SNR %4.1f LMT %.04f El %4.1f Az %5.1f Old %d "
1152 "Int %d Bad %d Col %d TPF %d SVT %d\n",
1153 i, u10, u1, u3, u4, f1, ftow, d1, d2, u5, u6, u7, u8, u9, u10);
1154 if (i < TSIP_CHANNELS) {
1155 session->gpsdata.skyview[i].PRN = (short)u1;
1156 session->gpsdata.skyview[i].ss = (double)f1;
1157 session->gpsdata.skyview[i].elevation = (double)d1;
1158 session->gpsdata.skyview[i].azimuth = (double)d2;
1159 session->gpsdata.skyview[i].used = (bool)u4;
1160 session->gpsdata.skyview[i].gnssid = tsip_gnssid(u10, u1,
1161 &session->gpsdata.skyview[i].svid);
1162 if (0 == u7) {
1163 session->gpsdata.skyview[i].health = SAT_HEALTH_OK;
1164 } else {
1165 session->gpsdata.skyview[i].health = SAT_HEALTH_BAD;
1166 }
1167
1168 /* when polled by 0x3c, all the skyview times will be the same
1169 * in one cluster */
1170 if (0.0 < ftow) {
1171 DTOTS(&ts_tow, ftow);
1172 session->gpsdata.skyview_time =
1173 gpsd_gpstime_resolv(session, session->context->gps_week,
1174 ts_tow);
1175 /* do not save in session->driver.tsip.last_tow
1176 * as this is skyview time, not fix time */
1177 }
1178 if (++i >= session->gpsdata.satellites_visible) {
1179 /* Last of the series?
1180 * This will cause extra SKY if this set has more
1181 * sats than the last set */
1182 mask |= SATELLITE_SET;
1183 session->gpsdata.satellites_visible = i;
1184 }
1185 /* If this series has fewer than last series there will
1186 * be no SKY, unless the cycle ender pushes the SKY */
1187 }
1188 break;
1189 case 0x6c:
1190 /* Satellite Selection List (0x6c) polled by 0x24
1191 *
1192 * Present in:
1193 * ICM SMT 360 (2018)
1194 * RES SMT 360 (2018)
1195 * Not present in:
1196 * pre-2000 models
1197 * Copernicus II (2009)
1198 * Lassen SQ (2002)
1199 * Lassen iQ (2005) */
1200 if (18 > len) {
1201 bad_len = 18;
1202 break;
1203 }
1204 u1 = getub(buf, 0); // fix dimension, mode
1205 count = (int)getub(buf, 17);
1206 if (len != (18 + count)) {
1207 bad_len = 18 + count;
1208 break;
1209 }
1210
1211 // why same as 6d?
1212 session->driver.tsip.last_6d = now; /* keep timestamp for request */
1213 /*
1214 * This looks right, but it sets a spurious mode value when
1215 * the satellite constellation looks good to the chip but no
1216 * actual fix has yet been acquired. We should set the mode
1217 * field (which controls gpsd's fix reporting) only from sentences
1218 * that convey actual fix information, like 0x8f-20, but some
1219 * TSIP do not support 0x8f-20, and 0x6c may be all we got.
1220 */
1221 switch (u1 & 7) { /* dimension */
1222 case 1: // clock fix (surveyed in)
1223 // FALLTHROUGH
1224 case 5: // Overdetermined clock fix
1225 session->gpsdata.status = STATUS_TIME;
1226 session->newdata.mode = MODE_3D;
1227 break;
1228 case 3:
1229 session->gpsdata.status = STATUS_FIX;
1230 session->newdata.mode = MODE_2D;
1231 break;
1232 case 4:
1233 session->gpsdata.status = STATUS_FIX;
1234 session->newdata.mode = MODE_3D;
1235 break;
1236 case 2:
1237 // FALLTHROUGH
1238 case 6:
1239 // FALLTHROUGH
1240 case 7:
1241 // FALLTHROUGH
1242 default:
1243 session->gpsdata.status = STATUS_NO_FIX;
1244 session->newdata.mode = MODE_NO_FIX;
1245 break;
1246 }
1247 if (8 == (u1 & 8)) {
1248 // Surveyed in
1249 session->gpsdata.status = STATUS_TIME;
1250 }
1251 mask |= MODE_SET;
1252
1253 session->gpsdata.satellites_used = count;
1254 session->gpsdata.dop.pdop = getbef32((char *)buf, 1);
1255 session->gpsdata.dop.hdop = getbef32((char *)buf, 5);
1256 session->gpsdata.dop.vdop = getbef32((char *)buf, 9);
1257 // RES SMT 360 and ICM SMT 360 always report tdop == 1
1258 session->gpsdata.dop.tdop = getbef32((char *)buf, 13);
1259 session->gpsdata.dop.gdop =
1260 sqrt(pow(session->gpsdata.dop.pdop, 2) +
1261 pow(session->gpsdata.dop.tdop, 2));
1262
1263 memset(session->driver.tsip.sats_used, 0,
1264 sizeof(session->driver.tsip.sats_used));
1265 buf2[0] = '\0';
1266 for (i = 0; i < count; i++) {
1267 session->driver.tsip.sats_used[i] = (short)getub(buf, 18 + i);
1268 if (session->context->errout.debug >= LOG_DATA) {
1269 str_appendf(buf2, sizeof(buf2),
1270 " %d", session->driver.tsip.sats_used[i]);
1271 }
1272 }
1273 GPSD_LOG(LOG_PROG, &session->context->errout,
1274 "TSIP: AIVSS (0x6c): mode %d status %d used %d "
1275 "pdop %.1f hdop %.1f vdop %.1f tdop %.1f gdop %.1f Used %s\n",
1276 session->newdata.mode,
1277 session->gpsdata.status,
1278 session->gpsdata.satellites_used,
1279 session->gpsdata.dop.pdop,
1280 session->gpsdata.dop.hdop,
1281 session->gpsdata.dop.vdop,
1282 session->gpsdata.dop.tdop,
1283 session->gpsdata.dop.gdop,
1284 buf2);
1285 mask |= DOP_SET | MODE_SET | STATUS_SET | USED_IS;
1286 break;
1287 case 0x6d:
1288 /* All-In-View Satellite Selection (0x6d) polled by 0x24
1289 *
1290 * Present in:
1291 * pre-2000 models
1292 * Copernicus II (2009)
1293 * Lassen SQ
1294 * Lassen iQ
1295 * Not present in:
1296 * ICM SMT 360 (2018)
1297 * RES SMT 360 (2018)
1298 */
1299 if (1 > len) {
1300 bad_len = 1;
1301 break;
1302 }
1303 u1 = getub(buf, 0); /* nsvs/dimension */
1304 count = (int)((u1 >> 4) & 0x0f);
1305 if (len != (17 + count)) {
1306 bad_len = 17 + count;
1307 break;
1308 }
1309 session->driver.tsip.last_6d = now; /* keep timestamp for request */
1310 /*
1311 * This looks right, but it sets a spurious mode value when
1312 * the satellite constellation looks good to the chip but no
1313 * actual fix has yet been acquired. We should set the mode
1314 * field (which controls gpsd's fix reporting) only from sentences
1315 * that convey actual fix information, like 0x8f-20, but some
1316 * TSIP do not support 0x8f-20, and 0x6c may be all we got.
1317 */
1318 if (0 != isfinite(session->gpsdata.fix.longitude)) {
1319 // have a fix
1320 switch (u1 & 7) { /* dimension */
1321 case 1: // clock fix (surveyed in)
1322 // FALLTHROUGH
1323 case 5: // Overdetermined clock fix
1324 session->gpsdata.status = STATUS_TIME;
1325 session->newdata.mode = MODE_3D;
1326 break;
1327 case 3:
1328 session->gpsdata.status = STATUS_FIX;
1329 session->newdata.mode = MODE_2D;
1330 break;
1331 case 4:
1332 session->gpsdata.status = STATUS_FIX;
1333 session->newdata.mode = MODE_3D;
1334 break;
1335 case 2:
1336 // FALLTHROUGH
1337 case 6:
1338 // FALLTHROUGH
1339 case 7:
1340 // FALLTHROUGH
1341 default:
1342 session->gpsdata.status = STATUS_NO_FIX;
1343 session->newdata.mode = MODE_NO_FIX;
1344 break;
1345 }
1346 } else {
1347 session->gpsdata.status = STATUS_NO_FIX;
1348 session->newdata.mode = MODE_NO_FIX;
1349 }
1350 mask |= MODE_SET;
1351
1352 session->gpsdata.satellites_used = count;
1353 session->gpsdata.dop.pdop = getbef32((char *)buf, 1);
1354 session->gpsdata.dop.hdop = getbef32((char *)buf, 5);
1355 session->gpsdata.dop.vdop = getbef32((char *)buf, 9);
1356 session->gpsdata.dop.tdop = getbef32((char *)buf, 13);
1357 session->gpsdata.dop.gdop =
1358 sqrt(pow(session->gpsdata.dop.pdop, 2) +
1359 pow(session->gpsdata.dop.tdop, 2));
1360
1361 memset(session->driver.tsip.sats_used, 0,
1362 sizeof(session->driver.tsip.sats_used));
1363 buf2[0] = '\0';
1364 for (i = 0; i < count; i++) {
1365 // negative PRN means sat unhealthy
1366 session->driver.tsip.sats_used[i] = (short)getub(buf, 17 + i);
1367 if (session->context->errout.debug >= LOG_DATA) {
1368 str_appendf(buf2, sizeof(buf2),
1369 " %d", session->driver.tsip.sats_used[i]);
1370 }
1371 }
1372 GPSD_LOG(LOG_PROG, &session->context->errout,
1373 "TSIP: AIVSS (0x6d) status=%d used=%d "
1374 "pdop=%.1f hdop=%.1f vdop=%.1f tdop=%.1f gdop=%.1f used:%s\n",
1375 session->gpsdata.status,
1376 session->gpsdata.satellites_used,
1377 session->gpsdata.dop.pdop,
1378 session->gpsdata.dop.hdop,
1379 session->gpsdata.dop.vdop,
1380 session->gpsdata.dop.tdop,
1381 session->gpsdata.dop.gdop, buf2);
1382 mask |= DOP_SET | STATUS_SET | USED_IS;
1383 break;
1384 case 0x82:
1385 /* Differential Position Fix Mode (0x82) poll with 0x62-ff
1386 * Sent after every position fix in Auto GPS/DGPS,
1387 * so potential cycle ender
1388 *
1389 * Present in:
1390 * pre-2000 models
1391 * Copernicus II (2009)
1392 * Lassen iQ, deprecated use 0xbb instead
1393 * Not Present in:
1394 * ICM SMT 360 (2018)
1395 * RES SMT 360 (2018)
1396 */
1397 if (len != 1) {
1398 bad_len = 1;
1399 break;
1400 }
1401 u1 = getub(buf, 0); /* fix mode */
1402 if (session->gpsdata.status == STATUS_FIX && (u1 & 0x01) != 0) {
1403 session->gpsdata.status = STATUS_DGPS_FIX;
1404 mask |= STATUS_SET;
1405 }
1406 GPSD_LOG(LOG_PROG, &session->context->errout,
1407 "TSIP: DPFM (0x82) mode %d status=%d\n",
1408 u1, session->gpsdata.status);
1409 break;
1410 case 0x83:
1411 /* Double-Precision XYZ Position Fix and Bias Information
1412 * Present in:
1413 * pre-2000 models
1414 * Copernicus II (2009)
1415 * ICM SMT 360 (2018)
1416 * RES SMT 360 (2018)
1417 */
1418 if (36 > len) {
1419 bad_len = 36;
1420 break;
1421 }
1422 session->newdata.ecef.x = getbed64((char *)buf, 0); /* X */
1423 session->newdata.ecef.y = getbed64((char *)buf, 8); /* Y */
1424 session->newdata.ecef.z = getbed64((char *)buf, 16); /* Z */
1425 d4 = getbed64((char *)buf, 24); /* clock bias */
1426 ftow = getbef32((char *)buf, 32); /* time-of-fix */
1427 DTOTS(&ts_tow, ftow);
1428 session->newdata.time = gpsd_gpstime_resolv(session,
1429 session->context->gps_week,
1430 ts_tow);
1431 GPSD_LOG(LOG_PROG, &session->context->errout,
1432 "TSIP: DP-XYZ (0x83) %f %f %f %f tow %f\n",
1433 session->newdata.ecef.x,
1434 session->newdata.ecef.y,
1435 session->newdata.ecef.z,
1436 d4, ftow);
1437 mask = ECEF_SET | TIME_SET | NTPTIME_IS;
1438 if (!TS_EQ(&ts_tow, &session->driver.tsip.last_tow)) {
1439 mask |= CLEAR_IS;
1440 session->driver.tsip.last_tow = ts_tow;
1441 }
1442 break;
1443 case 0x84:
1444 /* Double-Precision LLA Position Fix and Bias Information
1445 * Present in:
1446 * pre-2000 models
1447 * Copernicus II (2009)
1448 * ICM SMT 360 (2018)
1449 * RES SMT 360 (2018)
1450 */
1451 if (len != 36) {
1452 bad_len = 36;
1453 break;
1454 }
1455 session->newdata.latitude = getbed64((char *)buf, 0) * RAD_2_DEG;
1456 session->newdata.longitude = getbed64((char *)buf, 8) * RAD_2_DEG;
1457 /* depending on GPS config, could be either WGS84 or MSL */
1458 d1 = getbed64((char *)buf, 16);
1459 if (0 == session->driver.tsip.alt_is_msl) {
1460 session->newdata.altHAE = d1;
1461 } else {
1462 session->newdata.altMSL = d1;
1463 }
1464 mask |= ALTITUDE_SET;
1465 //d1 = getbed64((char *)buf, 24); clock bias */
1466 ftow = getbef32((char *)buf, 32); /* time-of-fix */
1467 if ((session->context->valid & GPS_TIME_VALID)!=0) {
1468 DTOTS(&ts_tow, ftow);
1469 session->newdata.time =
1470 gpsd_gpstime_resolv(session, session->context->gps_week,
1471 ts_tow);
1472 mask |= TIME_SET | NTPTIME_IS;
1473 if (!TS_EQ(&ts_tow, &session->driver.tsip.last_tow)) {
1474 mask |= CLEAR_IS;
1475 session->driver.tsip.last_tow = ts_tow;
1476 }
1477 }
1478 mask |= LATLON_SET;
1479 GPSD_LOG(LOG_PROG, &session->context->errout,
1480 "TSIP: DP-LLA (0x84) time=%s lat=%.2f lon=%.2f alt=%.2f\n",
1481 timespec_str(&session->newdata.time, ts_buf, sizeof(ts_buf)),
1482 session->newdata.latitude,
1483 session->newdata.longitude, d1);
1484 break;
1485 case 0x8f:
1486 /* Super Packet.
1487 * Present in:
1488 * pre-2000 models
1489 * ACE II
1490 * ACE III
1491 * Copernicus II (2009)
1492 * ICM SMT 360
1493 * RES SMT 360
1494 */
1495 u1 = (uint8_t) getub(buf, 0);
1496 switch (u1) { /* sub-code ID */
1497 case 0x15:
1498 /* Current Datum Values
1499 * Not Present in:
1500 * pre-2000 models
1501 * Copernicus II (2009)
1502 * ICM SMT 360 (2018)
1503 * RES SMT 360 (2018)
1504 */
1505 if (len != 43) {
1506 bad_len = 43;
1507 break;
1508 }
1509 s1 = getbes16(buf, 1); /* Datum Index */
1510 d1 = getbed64((char *)buf, 3); /* DX */
1511 d2 = getbed64((char *)buf, 11); /* DY */
1512 d3 = getbed64((char *)buf, 19); /* DZ */
1513 d4 = getbed64((char *)buf, 27); /* A-axis */
1514 d5 = getbed64((char *)buf, 35); /* Eccentricity Squared */
1515 GPSD_LOG(LOG_PROG, &session->context->errout,
1516 "TSIP: Current Datum (0x8f-15) %d %f %f %f %f %f\n",
1517 s1, d1, d2, d3, d4, d5);
1518 break;
1519
1520 case 0x20:
1521 /* Last Fix with Extra Information (binary fixed point) 0x8f-20
1522 * Only ouput when fix is available.
1523 * CSK sez "why does my Lassen SQ output oversize packets?"
1524 * Present in:
1525 * pre-2000 models
1526 * ACE II
1527 * Copernicus, Copernicus II (64-bytes)
1528 * Not present in:
1529 * ICM SMT 360
1530 * RES SMT 360
1531 */
1532 if ((len != 56) && (len != 64)) {
1533 bad_len = 56;
1534 break;
1535 }
1536 s1 = getbes16(buf, 2); /* east velocity */
1537 s2 = getbes16(buf, 4); /* north velocity */
1538 s3 = getbes16(buf, 6); /* up velocity */
1539 tow = getbeu32(buf, 8); /* time in ms */
1540 sl1 = getbes32(buf, 12); /* latitude */
1541 ul2 = getbeu32(buf, 16); /* longitude */
1542 // Lassen iQ, and copernicus (ii) doc says this is always altHAE
1543 sl2 = getbes32(buf, 20); /* altitude */
1544 u1 = getub(buf, 24); /* velocity scaling */
1545 u2 = getub(buf, 27); /* fix flags */
1546 u3 = getub(buf, 28); /* num svs */
1547 u4 = getub(buf, 29); /* utc offset */
1548 week = getbeu16(buf, 30); /* tsip.gps_week */
1549 /* PRN/IODE data follows */
1550 GPSD_LOG(LOG_PROG, &session->context->errout,
1551 "TSIP: LFwEI (0x8f-20) %d %d %d tow %u %d "
1552 " %u %u %x %x %u leap %u week %d\n",
1553 s1, s2, s3, tow, sl1, ul2, sl2, u1, u2, u3, u4, week);
1554
1555 if ((u1 & 0x01) != (uint8_t) 0) /* check velocity scaling */
1556 d5 = 0.02;
1557 else
1558 d5 = 0.005;
1559
1560 // 0x8000 is over-range
1561 if ((int16_t)0x8000 != s2) {
1562 d2 = (double)s2 * d5; /* north velocity m/s */
1563 session->newdata.NED.velN = d2;
1564 }
1565 if ((int16_t)0x8000 != s1) {
1566 d1 = (double)s1 * d5; /* east velocity m/s */
1567 session->newdata.NED.velE = d1;
1568 }
1569 if ((int16_t)0x8000 != s3) {
1570 d3 = (double)s3 * d5; /* up velocity m/s */
1571 session->newdata.NED.velD = -d3;
1572 }
1573
1574 session->newdata.latitude = (double)sl1 * SEMI_2_DEG;
1575 session->newdata.longitude = (double)ul2 * SEMI_2_DEG;
1576 if (session->newdata.longitude > 180.0)
1577 session->newdata.longitude -= 360.0;
1578 // Lassen iQ doc says this is always altHAE in mm
1579 session->newdata.altHAE = (double)sl2 * 1e-3;
1580 mask |= ALTITUDE_SET;
1581
1582 session->gpsdata.status = STATUS_NO_FIX;
1583 session->newdata.mode = MODE_NO_FIX;
1584 if ((u2 & 0x01) == (uint8_t) 0) { /* Fix Available */
1585 session->gpsdata.status = STATUS_FIX;
1586 if ((u2 & 0x02) != (uint8_t) 0) /* DGPS Corrected */
1587 session->gpsdata.status = STATUS_DGPS_FIX;
1588 if ((u2 & 0x04) != (uint8_t) 0) /* Fix Dimension */
1589 session->newdata.mode = MODE_2D;
1590 else
1591 session->newdata.mode = MODE_3D;
1592 }
1593 session->gpsdata.satellites_used = (int)u3;
1594 if ((int)u4 > 10) {
1595 session->context->leap_seconds = (int)u4;
1596 session->context->valid |= LEAP_SECOND_VALID;
1597 /* check for week rollover
1598 * Trimble uses 15 bit weeks, but can guess the epoch wrong
1599 * Can not be in gpsd_gpstime_resolv() because that
1600 * may see BUILD_LEAPSECONDS instead of leap_seconds
1601 * from receiver.
1602 */
1603 if (17 < u4 && 1930 > week) {
1604 // leap second 18 added in gps week 1930
1605 week += 1024;
1606 if (1930 > week) {
1607 // and again?
1608 week += 1024;
1609 }
1610 }
1611 }
1612 MSTOTS(&ts_tow, tow);
1613 session->newdata.time = gpsd_gpstime_resolv(session, week,
1614 ts_tow);
1615 mask |= TIME_SET | NTPTIME_IS | LATLON_SET |
1616 STATUS_SET | MODE_SET | VNED_SET;
1617 if (!TS_EQ(&ts_tow, &session->driver.tsip.last_tow)) {
1618 mask |= CLEAR_IS;
1619 session->driver.tsip.last_tow = ts_tow;
1620 }
1621 GPSD_LOG(LOG_DATA, &session->context->errout,
1622 "TSIP: LFwEI (0x8f-20): time=%s lat=%.2f lon=%.2f "
1623 "altHAE=%.2f mode=%d status=%d\n",
1624 timespec_str(&session->newdata.time, ts_buf,
1625 sizeof(ts_buf)),
1626 session->newdata.latitude, session->newdata.longitude,
1627 session->newdata.altHAE,
1628 session->newdata.mode, session->gpsdata.status);
1629 break;
1630 case 0x23:
1631 /* Compact Super Packet (0x8f-23)
1632 * Present in:
1633 * Copernicus, Copernicus II
1634 * Not present in:
1635 * pre-2000 models
1636 * Lassen iQ
1637 * ICM SMT 360
1638 * RES SMT 360
1639 */
1640 session->driver.tsip.req_compact = 0;
1641 /* CSK sez "i don't trust this to not be oversized either." */
1642 if (29 > len) {
1643 bad_len = 29;
1644 break;
1645 }
1646 tow = getbeu32(buf, 1); /* time in ms */
1647 week = getbeu16(buf, 5); /* tsip.gps_week */
1648 u1 = getub(buf, 7); /* utc offset */
1649 u2 = getub(buf, 8); /* fix flags */
1650 sl1 = getbes32(buf, 9); /* latitude */
1651 ul2 = getbeu32(buf, 13); /* longitude */
1652 // Copernicus (ii) doc says this is always altHAE in mm
1653 sl3 = getbes32(buf, 17); /* altitude */
1654 /* set xNED here */
1655 s2 = getbes16(buf, 21); /* east velocity */
1656 s3 = getbes16(buf, 23); /* north velocity */
1657 s4 = getbes16(buf, 25); /* up velocity */
1658 GPSD_LOG(LOG_PROG, &session->context->errout,
1659 "TSIP: CSP (0x8f-23): %u %d %u %u %d %u %d %d %d %d\n",
1660 tow, week, u1, u2, sl1, ul2, sl3, s2, s3, s4);
1661 if ((int)u1 > 10) {
1662 session->context->leap_seconds = (int)u1;
1663 session->context->valid |= LEAP_SECOND_VALID;
1664 }
1665 MSTOTS(&ts_tow, tow);
1666 session->newdata.time =
1667 gpsd_gpstime_resolv(session, week, ts_tow);
1668 session->gpsdata.status = STATUS_NO_FIX;
1669 session->newdata.mode = MODE_NO_FIX;
1670 if ((u2 & 0x01) == (uint8_t) 0) { /* Fix Available */
1671 session->gpsdata.status = STATUS_FIX;
1672 if ((u2 & 0x02) != (uint8_t) 0) /* DGPS Corrected */
1673 session->gpsdata.status = STATUS_DGPS_FIX;
1674 if ((u2 & 0x04) != (uint8_t) 0) /* Fix Dimension */
1675 session->newdata.mode = MODE_2D;
1676 else
1677 session->newdata.mode = MODE_3D;
1678 }
1679 session->newdata.latitude = (double)sl1 * SEMI_2_DEG;
1680 session->newdata.longitude = (double)ul2 * SEMI_2_DEG;
1681 if (session->newdata.longitude > 180.0)
1682 session->newdata.longitude -= 360.0;
1683 // Copernicus (ii) doc says this is always altHAE in mm
1684 session->newdata.altHAE = (double)sl3 * 1e-3;
1685 mask |= ALTITUDE_SET;
1686 if ((u2 & 0x20) != (uint8_t) 0) /* check velocity scaling */
1687 d5 = 0.02;
1688 else
1689 d5 = 0.005;
1690 d1 = (double)s2 * d5; /* east velocity m/s */
1691 d2 = (double)s3 * d5; /* north velocity m/s */
1692 d3 = (double)s4 * d5; /* up velocity m/s */
1693 session->newdata.NED.velN = d2;
1694 session->newdata.NED.velE = d1;
1695 session->newdata.NED.velD = -d3;
1696
1697 mask |= TIME_SET | NTPTIME_IS | LATLON_SET |
1698 STATUS_SET | MODE_SET | VNED_SET;
1699 if (!TS_EQ(&ts_tow, &session->driver.tsip.last_tow)) {
1700 mask |= CLEAR_IS;
1701 session->driver.tsip.last_tow = ts_tow;
1702 }
1703 GPSD_LOG(LOG_PROG, &session->context->errout,
1704 "TSIP: SP-CSP (0x8f-23): time %s lat %.2f lon %.2f "
1705 "altHAE %.2f mode %d status %d\n",
1706 timespec_str(&session->newdata.time, ts_buf,
1707 sizeof(ts_buf)),
1708 session->newdata.latitude, session->newdata.longitude,
1709 session->newdata.altHAE,
1710 session->newdata.mode, session->gpsdata.status);
1711 break;
1712
1713 case 0xa5:
1714 /* Packet Broadcast Mask (0x8f-a5) polled by 0x8e-a5
1715 *
1716 * Present in:
1717 * ICM SMT 360
1718 * RES SMT 360
1719 * Not Present in:
1720 * pre-2000 models
1721 * Copernicus II (2009)
1722 */
1723 {
1724 uint16_t mask0, mask1;
1725 if (5 > len) {
1726 bad_len = 5;
1727 break;
1728 }
1729 mask0 = getbeu16(buf, 1); // Mask 0
1730 mask1 = getbeu16(buf, 3); // Mask 1
1731 GPSD_LOG(LOG_DATA, &session->context->errout,
1732 "TSIP: PBM (0x8f-a5) mask0 x%04x mask1 x%04x\n",
1733 mask0, mask1);
1734 }
1735 // RES SMT 360 default 5, 0
1736 break;
1737
1738 case 0xa6:
1739 /* Self-Survey Comman (0x8f-a6) polled by 0x8e-a6
1740 *
1741 * Present in:
1742 * ICM SMT 360
1743 * RES SMT 360
1744 * Not Present in:
1745 * pre-2000 models
1746 * Copernicus II (2009)
1747 */
1748 if (3 > len) {
1749 bad_len = 3;
1750 break;
1751 }
1752 u2 = getub(buf, 1); // Command
1753 u3 = getub(buf, 2); // Status
1754 GPSD_LOG(LOG_DATA, &session->context->errout,
1755 "TSIP: SSC (0x8f-a6) command x%x status x%x\n",
1756 u2, u3);
1757 break;
1758
1759 case 0xab:
1760 /* Thunderbolt Timing Superpacket
1761 * Not Present in:
1762 * pre-2000 models
1763 * Copernicus II (2009)
1764 */
1765 if (17 > len) {
1766 bad_len = 17;
1767 break;
1768 }
1769 session->driver.tsip.last_41 = now; // keep timestamp for request
1770 // we assume the receiver not in some crazy mode, and is GPS time
1771 tow = getbeu32(buf, 1); // gpstime in seconds
1772 ts_tow.tv_sec = tow;
1773 ts_tow.tv_nsec = 0;
1774 week = getbeu16(buf, 5); // week
1775 /* leap seconds */
1776 session->context->leap_seconds = (int)getbes16(buf, 7);
1777 u2 = buf[9]; // Time Flag
1778 // should check time valid?
1779 /* ignore the broken down time, use the GNSS time.
1780 * Hope it is not BeiDou time */
1781
1782 // how do we know leap valid?
1783 session->context->valid |= LEAP_SECOND_VALID;
1784 session->newdata.time = gpsd_gpstime_resolv(session, week, ts_tow);
1785 mask |= TIME_SET | NTPTIME_IS;
1786 if (!TS_EQ(&ts_tow, &session->driver.tsip.last_tow)) {
1787 mask |= CLEAR_IS;
1788 session->driver.tsip.last_tow = ts_tow;
1789 }
1790
1791 GPSD_LOG(LOG_PROG, &session->context->errout,
1792 "TSIP: SP-TTS (0x8f-ab) tow %u wk %u ls %d flag x%x "
1793 "time %s mask %s\n",
1794 tow, week, session->context->leap_seconds, u2,
1795 timespec_str(&session->newdata.time, ts_buf,
1796 sizeof(ts_buf)),
1797 gps_maskdump(mask));
1798 break;
1799
1800
1801 case 0xac:
1802 /* Supplemental Timing Packet (0x8f-ac)
1803 * present in:
1804 * ThunderboltE
1805 * ICM SMT 360
1806 * RES SMT 360
1807 * Not Present in:
1808 * pre-2000 models
1809 * Lassen iQ
1810 * Copernicus II (2009)
1811 */
1812 if (len != 68) {
1813 bad_len = 68;
1814 break;
1815 }
1816
1817 // byte 0 is Subpacket ID
1818 u2 = getub(buf, 1); /* Receiver Mode */
1819 u3 = getub(buf, 12); /* GNSS Decoding Status */
1820 // ignore 2, Disciplining Mode
1821 // ignore 3, Self-Survey Progress
1822 // ignore 4-7, Holdover Duration
1823 // ignore 8-9, Critical Alarms
1824 // ignore 10-11, Minor Alarms
1825 // ignore 12, GNSS Decoding Status
1826 // ignore 13, Disciplining Activity
1827 // ignore 14, PPS indication
1828 // ignore 15, PPS reference
1829 /* PPS Offset in ns
1830 * save as (long)pico seconds
1831 * can't really use it as it is not referenced to any PPS */
1832 fqErr = getbef32((char *)buf, 16);
1833 session->gpsdata.qErr = (long)(fqErr * 1000);
1834 // ignore 20-23, Clock Offset
1835 // ignore 24-27, DAC Value
1836 // ignore 28-31, DAC Voltage
1837 // 32-35, Temperature degrees C
1838 temp = getbef32((char *)buf, 32);
1839 session->newdata.latitude = getbed64((char *)buf, 36) * RAD_2_DEG;
1840 session->newdata.longitude = getbed64((char *)buf, 44) * RAD_2_DEG;
1841 // SMT 360 doc says this is always altHAE in meters
1842 session->newdata.altHAE = getbed64((char *)buf, 52);
1843 // ignore 60-63, always zero
1844 // ignore 64-67, reserved
1845
1846 if (u3 != (uint8_t)0) {
1847 // not exactly true, could be sort of Dead Reckoning
1848 session->gpsdata.status = STATUS_NO_FIX;
1849 mask |= STATUS_SET;
1850 } else {
1851 if (session->gpsdata.status < STATUS_FIX) {
1852 session->gpsdata.status = STATUS_FIX;
1853 mask |= STATUS_SET;
1854 }
1855 }
1856
1857 /* Decode Fix modes */
1858 switch (u2 & 7) {
1859 case 0: /* Auto */
1860 /*
1861 * According to the Thunderbolt Manual, the
1862 * first byte of the supplemental timing packet
1863 * simply indicates the configuration of the
1864 * device, not the actual lock, so we need to
1865 * look at the decode status.
1866 */
1867 switch (u3) {
1868 case 0: /* "Doing Fixes" */
1869 session->newdata.mode = MODE_3D;
1870 break;
1871 case 0x0B: /* "Only 3 usable sats" */
1872 session->newdata.mode = MODE_2D;
1873 break;
1874 case 0x1: /* "Don't have GPS time" */
1875 // FALLTHROUGH
1876 case 0x3: /* "PDOP is too high" */
1877 // FALLTHROUGH
1878 case 0x8: /* "No usable sats" */
1879 // FALLTHROUGH
1880 case 0x9: /* "Only 1 usable sat" */
1881 // FALLTHROUGH
1882 case 0x0A: /* "Only 2 usable sats */
1883 // FALLTHROUGH
1884 case 0x0C: /* "The chosen sat is unusable" */
1885 // FALLTHROUGH
1886 case 0x10: /* TRAIM rejected the fix */
1887 // FALLTHROUGH
1888 default:
1889 session->newdata.mode = MODE_NO_FIX;
1890 break;
1891 }
1892 break;
1893 case 6: /* Clock Hold 2D */
1894 // FALLTHROUGH
1895 case 3: /* 2D Position Fix */
1896 //session->gpsdata.status = STATUS_FIX;
1897 session->newdata.mode = MODE_2D;
1898 break;
1899 case 7: /* Thunderbolt overdetermined clock */
1900 // FALLTHROUGH
1901 case 4: /* 3D position Fix */
1902 //session->gpsdata.status = STATUS_FIX;
1903 session->newdata.mode = MODE_3D;
1904 break;
1905 default:
1906 //session->gpsdata.status = STATUS_NO_FIX;
1907 session->newdata.mode = MODE_NO_FIX;
1908 break;
1909 }
1910
1911 mask |= LATLON_SET | ALTITUDE_SET | MODE_SET;
1912 GPSD_LOG(LOG_PROG, &session->context->errout,
1913 "TSIP: SP-TPS (0x8f-ac) lat=%.2f lon=%.2f altHAE=%.2f "
1914 "mode %d temp %.1f fqErr %.4f\n",
1915 session->newdata.latitude,
1916 session->newdata.longitude,
1917 session->newdata.altHAE,
1918 session->newdata.mode,
1919 temp, fqErr);
1920 break;
1921
1922 case 0x02:
1923 /* UTC Information
1924 * Present in:
1925 * ICM SMT 360 (2018)
1926 * RES SMT 360 (2018)
1927 * Not Present in:
1928 * pre-2000 models
1929 * Copernicus II (2009)
1930 */
1931 // FALLTHROUGH
1932 case 0x21:
1933 /* Request accuracy information
1934 * Present in:
1935 * Copernicus II (2009)
1936 * Not Present in:
1937 * pre-2000 models
1938 */
1939 // FALLTHROUGH
1940 case 0x2a:
1941 /* Request Fix and Channel Tracking info, Type 1
1942 * Present in:
1943 * Copernicus II (2009)
1944 * Not Present in:
1945 * pre-2000 models
1946 */
1947 // FALLTHROUGH
1948 case 0x2b:
1949 /* Request Fix and Channel Tracking info, Type 2
1950 * Present in:
1951 * Copernicus II (2009)
1952 * Not Present in:
1953 * pre-2000 models
1954 */
1955 // FALLTHROUGH
1956 case 0x41:
1957 /* Stored manufacturing operating parameters
1958 * Present in:
1959 * ICM SMT 360 (2018)
1960 * RES SMT 360 (2018)
1961 * Not Present in:
1962 * pre-2000 models
1963 * Copernicus II (2009)
1964 */
1965 // FALLTHROUGH
1966 case 0x42:
1967 /* Stored production parameters
1968 * Present in:
1969 * ICM SMT 360 (2018)
1970 * RES SMT 360 (2018)
1971 * Not Present in:
1972 * pre-2000 models
1973 * Copernicus II (2009)
1974 */
1975 // FALLTHROUGH
1976 case 0x4a:
1977 /* PPS characteristics
1978 * Present in:
1979 * ICM SMT 360 (2018)
1980 * RES SMT 360 (2018)
1981 * Copernicus II (2009)
1982 * Not Present in:
1983 * pre-2000 models
1984 */
1985 // FALLTHROUGH
1986 case 0x4e:
1987 /* PPS Output options
1988 * Present in:
1989 * ICM SMT 360 (2018)
1990 * RES SMT 360 (2018)
1991 * Not Present in:
1992 * pre-2000 models
1993 * Copernicus II (2009)
1994 */
1995 // FALLTHROUGH
1996 case 0x4f:
1997 /* Set PPS Width
1998 * Present in:
1999 * Copernicus II (2009)
2000 * Not Present in:
2001 * pre-2000 models
2002 * ICM SMT 360 (2018)
2003 * RES SMT 360 (2018)
2004 */
2005 // FALLTHROUGH
2006 case 0x60:
2007 /* DR Calibration and Status Report
2008 * Present in:
2009 * pre-2000 models
2010 * Not Present in:
2011 * Copernicus II (2009)
2012 * ICM SMT 360 (2018)
2013 * RES SMT 360 (2018)
2014 */
2015 // FALLTHROUGH
2016 case 0x62:
2017 /* GPS/DR Position/Velocity Report
2018 * Present in:
2019 * pre-2000 models
2020 * Not Present in:
2021 * Copernicus II (2009)
2022 * ICM SMT 360 (2018)
2023 * RES SMT 360 (2018)
2024 */
2025 // FALLTHROUGH
2026 case 0x64:
2027 /* Firmware Version and Configuration Report
2028 * Present in:
2029 * pre-2000 models
2030 * Not Present in:
2031 * Copernicus II (2009)
2032 * ICM SMT 360 (2018)
2033 * RES SMT 360 (2018)
2034 */
2035 // FALLTHROUGH
2036 case 0x6b:
2037 /* Last Gyroscope Readings Report
2038 * Present in:
2039 * pre-2000 models
2040 * Not Present in:
2041 * Copernicus II (2009)
2042 * ICM SMT 360 (2018)
2043 * RES SMT 360 (2018)
2044 */
2045 // FALLTHROUGH
2046 case 0x6d:
2047 /* Last Odometer Readings Report
2048 * Present in:
2049 * pre-2000 models
2050 * Not Present in:
2051 * Copernicus II (2009)
2052 * ICM SMT 360 (2018)
2053 * RES SMT 360 (2018)
2054 */
2055 // FALLTHROUGH
2056 case 0x6f:
2057 /* Firmware Version Name Report
2058 * Present in:
2059 * pre-2000 models
2060 * Not Present in:
2061 * Copernicus II (2009)
2062 * ICM SMT 360 (2018)
2063 * RES SMT 360 (2018)
2064 */
2065 // FALLTHROUGH
2066 case 0x70:
2067 /* Beacon Channel Status Report
2068 * Present in:
2069 * pre-2000 models
2070 * Not Present in:
2071 * Copernicus II (2009)
2072 * ICM SMT 360 (2018)
2073 * RES SMT 360 (2018)
2074 */
2075 // FALLTHROUGH
2076 case 0x71:
2077 /* DGPS Station Database Reports
2078 * Present in:
2079 * pre-2000 models
2080 * Not Present in:
2081 * Copernicus II (2009)
2082 * ICM SMT 360 (2018)
2083 * RES SMT 360 (2018)
2084 */
2085 // FALLTHROUGH
2086 case 0x73:
2087 /* Beacon Channel Control Acknowledgment
2088 * Present in:
2089 * pre-2000 models
2090 * Not Present in:
2091 * Copernicus II (2009)
2092 * ICM SMT 360 (2018)
2093 * RES SMT 360 (2018)
2094 */
2095 // FALLTHROUGH
2096 case 0x74:
2097 /* Clear Beacon Database Acknowledgment
2098 * Present in:
2099 * pre-2000 models
2100 * Not Present in:
2101 * Copernicus II (2009)
2102 * ICM SMT 360 (2018)
2103 * RES SMT 360 (2018)
2104 */
2105 // FALLTHROUGH
2106 case 0x75:
2107 /* FFT Start Acknowledgment
2108 * Present in:
2109 * pre-2000 models
2110 * Not Present in:
2111 * Copernicus II (2009)
2112 * ICM SMT 360 (2018)
2113 * RES SMT 360 (2018)
2114 */
2115 // FALLTHROUGH
2116 case 0x76:
2117 /* FFT Stop Acknowledgment
2118 * Present in:
2119 * pre-2000 models
2120 * Not Present in:
2121 * Copernicus II (2009)
2122 * ICM SMT 360 (2018)
2123 * RES SMT 360 (2018)
2124 */
2125 // FALLTHROUGH
2126 case 0x77:
2127 /* FFT Reports
2128 * Present in:
2129 * pre-2000 models
2130 * Not Present in:
2131 * Copernicus II (2009)
2132 * ICM SMT 360 (2018)
2133 * RES SMT 360 (2018)
2134 */
2135 // FALLTHROUGH
2136 case 0x78:
2137 /* RTCM Reports
2138 * Present in:
2139 * pre-2000 models
2140 * Not Present in:
2141 * Copernicus II (2009)
2142 * ICM SMT 360 (2018)
2143 * RES SMT 360 (2018)
2144 */
2145 // FALLTHROUGH
2146 case 0x79:
2147 /* Beacon Station Attributes Acknowledgment
2148 * Present in:
2149 * pre-2000 models
2150 * Not Present in:
2151 * Copernicus II (2009)
2152 * ICM SMT 360 (2018)
2153 * RES SMT 360 (2018)
2154 */
2155 // FALLTHROUGH
2156 case 0x7a:
2157 /* Beacon Station Attributes Report
2158 * Present in:
2159 * pre-2000 models
2160 * Not Present in:
2161 * Copernicus II (2009)
2162 * ICM SMT 360 (2018)
2163 * RES SMT 360 (2018)
2164 */
2165 // FALLTHROUGH
2166 case 0x7b:
2167 /* DGPS Receiver RAM Configuration Block Report
2168 * Present in:
2169 * pre-2000 models
2170 * Not Present in:
2171 * Copernicus II (2009)
2172 * ICM SMT 360 (2018)
2173 * RES SMT 360 (2018)
2174 */
2175 // FALLTHROUGH
2176 case 0x7c:
2177 /* DGPS Receiver Configuration Block Acknowledgment
2178 * Present in:
2179 * pre-2000 models
2180 * Not Present in:
2181 * Copernicus II (2009)
2182 * ICM SMT 360 (2018)
2183 * RES SMT 360 (2018)
2184 */
2185 // FALLTHROUGH
2186 case 0x7e:
2187 /* Satellite Line-of-Sight (LOS) Message
2188 * Present in:
2189 * pre-2000 models
2190 * Not Present in:
2191 * Copernicus II (2009)
2192 * ICM SMT 360 (2018)
2193 * RES SMT 360 (2018)
2194 */
2195 // FALLTHROUGH
2196 case 0x7f:
2197 /* DGPS Receiver ROM Configuration Block Report
2198 * Present in:
2199 * pre-2000 models
2200 * Not Present in:
2201 * Copernicus II (2009)
2202 * ICM SMT 360 (2018)
2203 * RES SMT 360 (2018)
2204 */
2205 // FALLTHROUGH
2206 case 0x80:
2207 /* DGPS Service Provider System Information Report
2208 * Present in:
2209 * pre-2000 models
2210 * Not Present in:
2211 * Copernicus II (2009)
2212 * ICM SMT 360 (2018)
2213 * RES SMT 360 (2018)
2214 */
2215 // FALLTHROUGH
2216 case 0x81:
2217 /* Decoder Station Information Report and Selection Acknowledgment
2218 * Present in:
2219 * pre-2000 models
2220 * Not Present in:
2221 * Copernicus II (2009)
2222 * ICM SMT 360 (2018)
2223 * RES SMT 360 (2018)
2224 */
2225 // FALLTHROUGH
2226 case 0x82:
2227 /* Decoder Diagnostic Information Report
2228 * Present in:
2229 * pre-2000 models
2230 * Not Present in:
2231 * Copernicus II (2009)
2232 * ICM SMT 360 (2018)
2233 * RES SMT 360 (2018)
2234 */
2235 // FALLTHROUGH
2236 case 0x84:
2237 /* Satellite FFT Control Acknowledgment
2238 * Present in:
2239 * pre-2000 models
2240 * Not Present in:
2241 * Copernicus II (2009)
2242 * ICM SMT 360 (2018)
2243 * RES SMT 360 (2018)
2244 */
2245 // FALLTHROUGH
2246 case 0x85:
2247 /* DGPS Source Tracking Status Report
2248 * Present in:
2249 * pre-2000 models
2250 * Not Present in:
2251 * Copernicus II (2009)
2252 * ICM SMT 360 (2018)
2253 * RES SMT 360 (2018)
2254 */
2255 // FALLTHROUGH
2256 case 0x86:
2257 /* Clear Satellite Database Acknowledgment
2258 * Present in:
2259 * pre-2000 models
2260 * Not Present in:
2261 * Copernicus II (2009)
2262 * ICM SMT 360 (2018)
2263 * RES SMT 360 (2018)
2264 */
2265 // FALLTHROUGH
2266 case 0x87:
2267 /* Network Statistics Report
2268 * Present in:
2269 * pre-2000 models
2270 * Not Present in:
2271 * Copernicus II (2009)
2272 * ICM SMT 360 (2018)
2273 * RES SMT 360 (2018)
2274 */
2275 // FALLTHROUGH
2276 case 0x88:
2277 /* Diagnostic Output Options Report
2278 * Present in:
2279 * pre-2000 models
2280 * Not Present in:
2281 * Copernicus II (2009)
2282 * ICM SMT 360 (2018)
2283 * RES SMT 360 (2018)
2284 */
2285 // FALLTHROUGH
2286 case 0x89:
2287 /* DGPS Source Control Report /Acknowledgment
2288 * Present in:
2289 * pre-2000 models
2290 * Not Present in:
2291 * Copernicus II (2009)
2292 * ICM SMT 360 (2018)
2293 * RES SMT 360 (2018)
2294 */
2295 // FALLTHROUGH
2296 case 0x8a:
2297 /* Service Provider Information Report and Acknowledgment
2298 * Present in:
2299 * pre-2000 models
2300 * Not Present in:
2301 * Copernicus II (2009)
2302 * ICM SMT 360 (2018)
2303 * RES SMT 360 (2018)
2304 */
2305 // FALLTHROUGH
2306 case 0x8b:
2307 /* Service Provider Activation Information Report & Acknowledgment
2308 * Present in:
2309 * pre-2000 models
2310 * Not Present in:
2311 * Copernicus II (2009)
2312 * ICM SMT 360 (2018)
2313 * RES SMT 360 (2018)
2314 */
2315 // FALLTHROUGH
2316 case 0x8e:
2317 /* Service Provider Data Load Report
2318 * Present in:
2319 * pre-2000 models
2320 * Not Present in:
2321 * Copernicus II (2009)
2322 * ICM SMT 360 (2018)
2323 * RES SMT 360 (2018)
2324 */
2325 // FALLTHROUGH
2326 case 0x8f:
2327 /* Receiver Identity Report
2328 * Present in:
2329 * pre-2000 models
2330 * Not Present in:
2331 * Copernicus II (2009)
2332 * ICM SMT 360 (2018)
2333 * RES SMT 360 (2018)
2334 */
2335 // FALLTHROUGH
2336 case 0x90:
2337 /* Guidance Status Report
2338 * Present in:
2339 * pre-2000 models
2340 * Not Present in:
2341 * Copernicus II (2009)
2342 * ICM SMT 360 (2018)
2343 * RES SMT 360 (2018)
2344 */
2345 // FALLTHROUGH
2346 case 0x91:
2347 /* Guidance Configuration Report
2348 * Present in:
2349 * pre-2000 models
2350 * Not Present in:
2351 * Copernicus II (2009)
2352 * ICM SMT 360 (2018)
2353 * RES SMT 360 (2018)
2354 */
2355 // FALLTHROUGH
2356 case 0x92:
2357 /* Lightbar Configuration Report
2358 * Present in:
2359 * pre-2000 models
2360 * Not Present in:
2361 * Copernicus II (2009)
2362 * ICM SMT 360 (2018)
2363 * RES SMT 360 (2018)
2364 */
2365 // FALLTHROUGH
2366 case 0x94:
2367 /* Guidance Operation Acknowledgment
2368 * Present in:
2369 * pre-2000 models
2370 * Not Present in:
2371 * Copernicus II (2009)
2372 * ICM SMT 360 (2018)
2373 * RES SMT 360 (2018)
2374 */
2375 // FALLTHROUGH
2376 case 0x95:
2377 /* Button Box Configuration Type Report
2378 * Present in:
2379 * pre-2000 models
2380 * Not Present in:
2381 * Copernicus II (2009)
2382 * ICM SMT 360 (2018)
2383 * RES SMT 360 (2018)
2384 */
2385 // FALLTHROUGH
2386 case 0x96:
2387 /* Point Manipulation Report
2388 * Present in:
2389 * pre-2000 models
2390 * Not Present in:
2391 * Copernicus II (2009)
2392 * ICM SMT 360 (2018)
2393 * RES SMT 360 (2018)
2394 */
2395 // FALLTHROUGH
2396 case 0x97:
2397 /* Utility Information Report
2398 * Present in:
2399 * pre-2000 models
2400 * Not Present in:
2401 * Copernicus II (2009)
2402 * ICM SMT 360 (2018)
2403 * RES SMT 360 (2018)
2404 */
2405 // FALLTHROUGH
2406 case 0x98:
2407 /* Individual Button Configuration Report
2408 * Present in:
2409 * pre-2000 models
2410 * Not Present in:
2411 * Copernicus II (2009)
2412 * ICM SMT 360 (2018)
2413 * RES SMT 360 (2018)
2414 */
2415 // FALLTHROUGH
2416 case 0x9a:
2417 /* Differential Correction Information Report
2418 * Present in:
2419 * pre-2000 models
2420 * Not Present in:
2421 * Copernicus II (2009)
2422 * ICM SMT 360 (2018)
2423 * RES SMT 360 (2018)
2424 */
2425 // FALLTHROUGH
2426 case 0xa0:
2427 /* DAC value
2428 * Present in:
2429 * ICM SMT 360 (2018)
2430 * RES SMT 360 (2018)
2431 * Not Present in:
2432 * pre-2000 models
2433 * Copernicus II (2009)
2434 */
2435 // FALLTHROUGH
2436 case 0xa2:
2437 /* UTC/GPS timing
2438 * Present in:
2439 * ICM SMT 360 (2018)
2440 * RES SMT 360 (2018)
2441 * Not Present in:
2442 * pre-2000 models
2443 * Copernicus II (2009)
2444 */
2445 // FALLTHROUGH
2446 case 0xa3:
2447 /* Oscillator disciplining command
2448 * Present in:
2449 * ICM SMT 360 (2018)
2450 * RES SMT 360 (2018)
2451 * Not Present in:
2452 * pre-2000 models
2453 * Copernicus II (2009)
2454 */
2455 // FALLTHROUGH
2456 case 0xa8:
2457 /* Oscillator disciplining parameters
2458 * Present in:
2459 * ICM SMT 360 (2018)
2460 * RES SMT 360 (2018)
2461 * Not Present in:
2462 * pre-2000 models
2463 * Copernicus II (2009)
2464 */
2465 // FALLTHROUGH
2466 case 0xa9:
2467 /* self-survey parameters
2468 * Present in:
2469 * ICM SMT 360 (2018)
2470 * RES SMT 360 (2018)
2471 * Not Present in:
2472 * pre-2000 models
2473 * Copernicus II (2009)
2474 */
2475 // FALLTHROUGH
2476 default:
2477 GPSD_LOG(LOG_WARN, &session->context->errout,
2478 "TSIP: Unhandled TSIP superpacket type 0x8f-%02x\n",
2479 u1);
2480 }
2481 break;
2482 case 0xbb:
2483 /* Navigation Configuration
2484 * Present in:
2485 * pre-2000 models
2486 * Copernicus II (2009)
2487 * ICM SMT 360 (2018)
2488 * RES SMT 360 (2018)
2489 */
2490 if (len != 40 && len != 43) {
2491 /* see packet.c for explamation */
2492 bad_len = 40;
2493 break;
2494 }
2495 u1 = getub(buf, 0); // Subcode, always zero?
2496 u2 = getub(buf, 1); // Operating Dimension
2497 u3 = getub(buf, 2); // DGPS Mode (not in Acutime Gold)
2498 u4 = getub(buf, 3); // Dynamics Code
2499 f1 = getbef32((char *)buf, 5); // Elevation Mask
2500 f2 = getbef32((char *)buf, 9); // AMU Mask
2501 f3 = getbef32((char *)buf, 13); // DOP Mask
2502 f4 = getbef32((char *)buf, 17); // DOP Switch
2503 u5 = getub(buf, 21); // DGPS Age Limit (not in Acutime Gold)
2504 /* Constellation
2505 * bit 0 - GPS
2506 * bit 1 - GLONASS
2507 * bit 2 - reserved
2508 * bit 3 - BeiDou
2509 * bit 4 - Galileo
2510 * bit 5 - QZSS
2511 * bit 6 - reserved
2512 * bit 7 - reserved
2513 */
2514 u6 = getub(buf, 27);
2515 GPSD_LOG(LOG_PROG, &session->context->errout,
2516 "TSIP: Navigation Configuration (0xbb) %u %u %u %u %f %f %f "
2517 "%f %u x%x\n",
2518 u1, u2, u3, u4, f1, f2, f3, f4, u5, u6);
2519 // RES SMT 360 defaults to Mode 7, Constellation 3
2520 break;
2521
2522 case 0x1a:
2523 /* TSIP RTCM Wrapper Command
2524 * Present in:
2525 * pre-2000 models
2526 * Not Present in:
2527 * ICM SMT 360 (2018)
2528 * RES SMT 360 (2018)
2529 * Copernicus II (2009)
2530 */
2531 // FALLTHROUGH
2532 case 0x2e:
2533 /* Request GPS Time
2534 * Present in:
2535 * ICM SMT 360 (2018)
2536 * RES SMT 360 (2018)
2537 * Not Present in:
2538 * pre-2000 models
2539 * Copernicus II (2009)
2540 */
2541 // FALLTHROUGH
2542 case 0x32:
2543 /* Request Unit Position
2544 * Present in:
2545 * ICM SMT 360 (2018)
2546 * RES SMT 360 (2018)
2547 * Not Present in:
2548 * pre-2000 models
2549 * Copernicus II (2009)
2550 */
2551 // FALLTHROUGH
2552 case 0x38:
2553 /* Request SV System data
2554 * Present in:
2555 * ICM SMT 360 (2018)
2556 * RES SMT 360 (2018)
2557 * Not Present in:
2558 * pre-2000 models
2559 * Copernicus II (2009)
2560 */
2561 // FALLTHROUGH
2562 case 0x40:
2563 /* Almanac Data for Single Satellite Report
2564 * Present in:
2565 * pre-2000 models
2566 * Not Present in:
2567 * ICM SMT 360 (2018)
2568 * RES SMT 360 (2018)
2569 * Copernicus II (2009)
2570 */
2571 // FALLTHROUGH
2572 case 0x44:
2573 /* Non-Overdetermined Satellite Selection Report
2574 * Present in:
2575 * pre-2000 models
2576 * Not Present in:
2577 * ICM SMT 360 (2018)
2578 * RES SMT 360 (2018)
2579 * Copernicus II (2009)
2580 */
2581 // FALLTHROUGH
2582 case 0x49:
2583 /* Almanac Health Page
2584 * Present in:
2585 * pre-2000 models
2586 * Not Present in:
2587 * Copernicus II (2009)
2588 */
2589 // FALLTHROUGH
2590 case 0x4d:
2591 /* Oscillator Offset
2592 * Present in:
2593 * pre-2000 models
2594 * Copernicus II (2009)
2595 */
2596 // FALLTHROUGH
2597 case 0x4e:
2598 /* Response to set GPS time
2599 * Present in:
2600 * pre-2000 models
2601 * Copernicus II (2009)
2602 * ICM SMT 360 (2018)
2603 * RES SMT 360 (2018)
2604 */
2605 // FALLTHROUGH
2606 case 0x4f:
2607 /* UTC Parameters Report
2608 * Present in:
2609 * pre-2000 models
2610 * Not Present in:
2611 * ICM SMT 360 (2018)
2612 * RES SMT 360 (2018)
2613 * Copernicus II (2009)
2614 */
2615 // FALLTHROUGH
2616 case 0x53:
2617 /* Analog-to-Digital Readings Report
2618 * Present in:
2619 * pre-2000 models
2620 * Not Present in:
2621 * ICM SMT 360 (2018)
2622 * RES SMT 360 (2018)
2623 * Copernicus II (2009)
2624 */
2625 // FALLTHROUGH
2626 case 0x58:
2627 /* Satellite System Data/Acknowledge from Receiver
2628 * Present in:
2629 * pre-2000 models
2630 * Copernicus II (2009)
2631 * ICM SMT 360 (2018)
2632 * RES SMT 360 (2018)
2633 */
2634 // FALLTHROUGH
2635 case 0x59:
2636 /* Status of Satellite Disable or Ignore Health
2637 * aka Satellite Attribute Database Status Report
2638 * Present in:
2639 * pre-2000 models
2640 * ICM SMT 360 (2018)
2641 * RES SMT 360 (2018)
2642 * Not Present in:
2643 * Copernicus II (2009)
2644 */
2645 // FALLTHROUGH
2646 case 0x5b:
2647 /* Satellite Ephemeris Status
2648 * Present in:
2649 * pre-2000 models
2650 * Not Present in:
2651 * Copernicus II (2009)
2652 * ICM SMT 360 (2018)
2653 * RES SMT 360 (2018)
2654 */
2655 // FALLTHROUGH
2656 case 0x5e:
2657 /* Additional Fix Status Report
2658 * Present in:
2659 * pre-2000 models
2660 * Not Present in:
2661 * Copernicus II (2009)
2662 * ICM SMT 360 (2018)
2663 * RES SMT 360 (2018)
2664 */
2665 // FALLTHROUGH
2666 case 0x5f:
2667 /* Severe Failure Notification
2668 * Present in:
2669 * pre-2000 models
2670 * Not Present in:
2671 * ICM SMT 360 (2018)
2672 * RES SMT 360 (2018)
2673 * Copernicus II (2009)
2674 */
2675 // FALLTHROUGH
2676 case 0x60:
2677 /* Differential GPS Pseudorange Corrections Report
2678 * Present in:
2679 * pre-2000 models
2680 * Not Present in:
2681 * ICM SMT 360 (2018)
2682 * RES SMT 360 (2018)
2683 * Copernicus II (2009)
2684 */
2685 // FALLTHROUGH
2686 case 0x61:
2687 /* Differential GPS Delta Pseudorange Corrections Report
2688 * Present in:
2689 * pre-2000 models
2690 * Not Present in:
2691 * ICM SMT 360 (2018)
2692 * RES SMT 360 (2018)
2693 * Copernicus II (2009)
2694 */
2695 // FALLTHROUGH
2696 case 0x6a:
2697 /* Differential Corrections Used in the Fix Repor
2698 * Present in:
2699 * pre-2000 models
2700 * Not Present in:
2701 * ICM SMT 360 (2018)
2702 * RES SMT 360 (2018)
2703 * Copernicus II (2009)
2704 */
2705 // FALLTHROUGH
2706 case 0x6e:
2707 /* Synchronized Measurements
2708 * Present in:
2709 * pre-2000 models
2710 * Not Present in:
2711 * Copernicus II (2009)
2712 * ICM SMT 360 (2018)
2713 * RES SMT 360 (2018)
2714 */
2715 // FALLTHROUGH
2716 case 0x6f:
2717 /* Synchronized Measurements Report
2718 * Present in:
2719 * pre-2000 models
2720 * Not Present in:
2721 * Copernicus II (2009)
2722 * ICM SMT 360 (2018)
2723 * RES SMT 360 (2018)
2724 */
2725 // FALLTHROUGH
2726 case 0x70:
2727 /* Filter Report
2728 * Present in:
2729 * pre-2000 models
2730 * Not Present in:
2731 * Copernicus II (2009)
2732 * ICM SMT 360 (2018)
2733 * RES SMT 360 (2018)
2734 */
2735 // FALLTHROUGH
2736 case 0x76:
2737 /* Overdetermined Mode Report
2738 * Present in:
2739 * pre-2000 models
2740 * Not Present in:
2741 * ICM SMT 360 (2018)
2742 * RES SMT 360 (2018)
2743 * Copernicus II (2009)
2744 */
2745 // FALLTHROUGH
2746 case 0x78:
2747 /* Maximum PRC Age Report
2748 * Present in:
2749 * pre-2000 models
2750 * Not Present in:
2751 * ICM SMT 360 (2018)
2752 * RES SMT 360 (2018)
2753 * Copernicus II (2009)
2754 */
2755 // FALLTHROUGH
2756 case 0x7a:
2757 /* NMEA settings
2758 * Not Present in:
2759 * pre-2000 models
2760 * Copernicus II (2009)
2761 * ICM SMT 360 (2018)
2762 * RES SMT 360 (2018)
2763 */
2764 // FALLTHROUGH
2765 case 0x7b:
2766 /* NMEA interval and message mask response
2767 * Present in:
2768 * pre-2000 models
2769 * ICM SMT 360 (2018)
2770 * RES SMT 360 (2018)
2771 * Not Present in:
2772 * Copernicus II (2009)
2773 */
2774 // FALLTHROUGH
2775 case 0x7d:
2776 /* Position Fix Rate Configuration Reports
2777 * Present in:
2778 * pre-2000 models
2779 * Not Present in:
2780 * ICM SMT 360 (2018)
2781 * RES SMT 360 (2018)
2782 * Copernicus II (2009)
2783 */
2784 // FALLTHROUGH
2785 case 0x85:
2786 /* Differential Correction Status Report
2787 * Present in:
2788 * pre-2000 models
2789 * Not Present in:
2790 * ICM SMT 360 (2018)
2791 * RES SMT 360 (2018)
2792 * Copernicus II (2009)
2793 */
2794 // FALLTHROUGH
2795 case 0x87:
2796 /* Reference Station Parameters Report
2797 * Present in:
2798 * pre-2000 models
2799 * Not Present in:
2800 * ICM SMT 360 (2018)
2801 * RES SMT 360 (2018)
2802 * Copernicus II (2009)
2803 */
2804 // FALLTHROUGH
2805 case 0x89:
2806 /* Receiver acquisition sensitivity mode
2807 * Present in:
2808 * Copernicus II (2009)
2809 * Not Present in:
2810 * pre-2000 models
2811 * ICM SMT 360 (2018)
2812 * RES SMT 360 (2018)
2813 */
2814 // FALLTHROUGH
2815 case 0x88:
2816 /* Mobile Differential Parameters Report
2817 * Present in:
2818 * pre-2000 models
2819 * Not Present in:
2820 * ICM SMT 360 (2018)
2821 * RES SMT 360 (2018)
2822 * Copernicus II (2009)
2823 */
2824 // FALLTHROUGH
2825 case 0x8b:
2826 /* QA/QC Reports
2827 * Present in:
2828 * pre-2000 models
2829 * Not Present in:
2830 * ICM SMT 360 (2018)
2831 * RES SMT 360 (2018)
2832 * Copernicus II (2009)
2833 */
2834 // FALLTHROUGH
2835 case 0x8d:
2836 /* Average Position Reports
2837 * Present in:
2838 * pre-2000 models
2839 * Not Present in:
2840 * ICM SMT 360 (2018)
2841 * RES SMT 360 (2018)
2842 * Copernicus II (2009)
2843 */
2844 // FALLTHROUGH
2845 case 0xb0:
2846 /* PPS and Event Report Packets
2847 * Present in:
2848 * pre-2000 models
2849 * Not Present in:
2850 * ICM SMT 360 (2018)
2851 * RES SMT 360 (2018)
2852 * Copernicus II (2009)
2853 */
2854 // FALLTHROUGH
2855 case 0xbc:
2856 /* Receiver port configuration
2857 * Present in:
2858 * pre-2000 models
2859 * Copernicus II (2009)
2860 * Not Present in:
2861 * ICM SMT 360 (2018)
2862 * RES SMT 360 (2018)
2863 */
2864 // FALLTHROUGH
2865 case 0xc1:
2866 /* Bit Mask for GPIOs in Standby Mode
2867 * Present in:
2868 * Copernicus II (2009)
2869 * ICM SMT 360 (2018)
2870 * RES SMT 360 (2018)
2871 * Not Present in:
2872 * pre-2000 models
2873 */
2874 // FALLTHROUGH
2875 case 0xc2:
2876 /* SBAS SV Mask
2877 * Present in:
2878 * Copernicus II (2009)
2879 * ICM SMT 360 (2018)
2880 * RES SMT 360 (2018)
2881 * Not Present in:
2882 * pre-2000 models
2883 */
2884 // FALLTHROUGH
2885 default:
2886 GPSD_LOG(LOG_WARN, &session->context->errout,
2887 "TSIP: Unhandled packet type x%02x\n", id);
2888 break;
2889 }
2890
2891 #ifdef __UNUSED__
2892 // #if 1
2893 // full reset
2894 putbyte(buf, 0, 0x46);
2895 (void)tsip_write(session, 0x1e, buf, 1);
2896 #endif
2897
2898 if (bad_len) {
2899 GPSD_LOG(LOG_WARNING, &session->context->errout,
2900 "TSIP: ID x%02x wrong len %d s/b >= %d \n", id, len, bad_len);
2901 } else {
2902 GPSD_LOG(LOG_PROG, &session->context->errout,
2903 "TSIP: ID x%02x mask %s\n", id, gps_maskdump(mask));
2904 }
2905 /* See if it is time to send some request packets for reports that.
2906 * The receiver won't send at fixed intervals.
2907 * Use llabs() as time sometimes goes backwards. */
2908
2909 if (5 < llabs(now - session->driver.tsip.last_41)) {
2910 /* Request Current Time returns 0x41.
2911 * Easiest way to get GPS weeks and current leap seconds */
2912 (void)tsip_write(session, 0x21, buf, 0);
2913 session->driver.tsip.last_41 = now;
2914 }
2915
2916 if (5 < llabs(now - session->driver.tsip.last_6d)) {
2917 /* Request GPS Receiver Position Fix Mode
2918 * Returns 0x44, 0x6c, or 0x6d. */
2919 (void)tsip_write(session, 0x24, buf, 0);
2920 session->driver.tsip.last_6d = now;
2921 #ifdef __UNUSED__
2922 // #if 1
2923 // request Receiver Configuration (0xbb)
2924 putbyte(buf, 0, 0x00);
2925 (void)tsip_write(session, 0xbb, buf, 1);
2926 // request Packet Broadcast Mask
2927 putbyte(buf, 0, 0xa5);
2928 (void)tsip_write(session, 0x8e, buf, 1);
2929 #endif // UNUSED
2930 }
2931
2932 if (1 > session->driver.tsip.superpkt &&
2933 60 < llabs(now - session->driver.tsip.last_48)) {
2934 /* Request GPS System Message
2935 * Returns 0x48.
2936 * not supported on:
2937 * Lassen SQ (2002)
2938 * Lassen iQ (2005)
2939 * ICM SMT 360
2940 * RES SMT 360
2941 * and post 2005
2942 * SuperPackets replaced 0x28 */
2943 (void)tsip_write(session, 0x28, buf, 0);
2944 session->driver.tsip.last_48 = now;
2945 }
2946
2947 if (5 < llabs(now - session->driver.tsip.last_5c)) {
2948 /* Request Current Satellite Tracking Status
2949 * Returns: 0x5c or 0x5d
2950 * 5c from GPS only devices
2951 * 5d from multi-gnss devices */
2952 putbyte(buf, 0, 0x00); /* All satellites */
2953 (void)tsip_write(session, 0x3c, buf, 1);
2954 session->driver.tsip.last_5c = now;
2955 }
2956
2957 if (5 < llabs(now - session->driver.tsip.last_46)) {
2958 /* Request Health of Receiver
2959 * Returns 0x46 and 0x4b. */
2960 (void)tsip_write(session, 0x26, buf, 0);
2961 session->driver.tsip.last_46 = now;
2962 }
2963 if ((session->driver.tsip.req_compact > 0) &&
2964 (5 < llabs(now - session->driver.tsip.req_compact))) {
2965 /* Compact Superpacket requested but no response
2966 * Not in:
2967 * ICM SMT 360
2968 * RES SMT 360
2969 */
2970 session->driver.tsip.req_compact = 0;
2971 GPSD_LOG(LOG_WARN, &session->context->errout,
2972 "TSIP: No Compact Super Packet (0x8f-23), "
2973 "try LFwEI (0x8f-20)\n");
2974
2975 /* Request LFwEI Super Packet 0x8f-20 */
2976 putbyte(buf, 0, 0x20);
2977 putbyte(buf, 1, 0x01); /* enabled */
2978 (void)tsip_write(session, 0x8e, buf, 2);
2979 }
2980
2981 return mask;
2982 }
2983
2984 #ifdef CONTROLSEND_ENABLE
tsip_control_send(struct gps_device_t * session,char * buf,size_t buflen)2985 static ssize_t tsip_control_send(struct gps_device_t *session,
2986 char *buf, size_t buflen)
2987 /* not used by the daemon, it's for gpsctl and friends */
2988 {
2989 return (ssize_t) tsip_write(session,
2990 (unsigned int)buf[0],
2991 (unsigned char *)buf + 1, buflen - 1);
2992 }
2993 #endif /* CONTROLSEND_ENABLE */
2994
tsip_init_query(struct gps_device_t * session)2995 static void tsip_init_query(struct gps_device_t *session)
2996 {
2997 unsigned char buf[100];
2998
2999 /* Use 0x1C-03 to Request Hardware Version Information (0x1C-83) */
3000 putbyte(buf, 0, 0x03); /* Subcode */
3001 (void)tsip_write(session, 0x1c, buf, 1);
3002 /*
3003 * After HW information packet is received, a
3004 * decision is made how to configure the device.
3005 */
3006 }
3007
tsip_event_hook(struct gps_device_t * session,event_t event)3008 static void tsip_event_hook(struct gps_device_t *session, event_t event)
3009 {
3010 unsigned char buf[100];
3011
3012 GPSD_LOG(LOG_SPIN, &session->context->errout,
3013 "TSIP: event_hook event %d ro %d\n",
3014 event, session->context->readonly);
3015
3016 if (session->context->readonly)
3017 return;
3018 switch (event) {
3019 case event_identified:
3020 // FALLTHROUGH
3021 case event_reactivate:
3022 // FIXME: reactivate style should depend on model
3023 /*
3024 * Set basic configuration, using Set or Request I/O Options (0x35).
3025 * in case no hardware config response comes back.
3026 */
3027 /* Position: enable: Double Precision, LLA
3028 * disable: ECEF */
3029 putbyte(buf, 0, IO1_8F20|IO1_DP|IO1_LLA);
3030 /* Velocity: enable: ENU, disable vECEF */
3031 putbyte(buf, 1, IO2_ENU);
3032 /* Time: enable: 0x42, 0x43, 0x4a
3033 * disable: 0x83, 0x84, 0x56 */
3034 putbyte(buf, 2, 0x00);
3035 /* Aux: enable: 0x5A, dBHz */
3036 putbyte(buf, 3, IO4_DBHZ);
3037 (void)tsip_write(session, 0x35, buf, 4);
3038 break;
3039 case event_configure:
3040 // this seems to get called on every packet...
3041 if (session->lexer.counter == 0) {
3042 /* but the above if() makes it never execute
3043 * formerely tried to force 801 here, but luckily it
3044 * never fired as some Trimble are 8N1 */
3045 }
3046 break;
3047 case event_deactivate:
3048 // used to revert serial port parms here. No need for that.
3049 // FALLTHROUGH
3050 default:
3051 break;
3052 }
3053 }
3054
3055 #ifdef RECONFIGURE_ENABLE
tsip_speed_switch(struct gps_device_t * session,speed_t speed,char parity,int stopbits)3056 static bool tsip_speed_switch(struct gps_device_t *session,
3057 speed_t speed, char parity, int stopbits)
3058 {
3059 unsigned char buf[100];
3060
3061 switch (parity) {
3062 case 'E':
3063 case 2:
3064 parity = (char)2;
3065 break;
3066 case 'O':
3067 case 1:
3068 parity = (char)1;
3069 break;
3070 case 'N':
3071 case 0:
3072 default:
3073 parity = (char)0;
3074 break;
3075 }
3076
3077 /* Set Port Configuration (0xbc) */
3078 putbyte(buf, 0, 0xff); /* current port */
3079 /* input dev.baudrate */
3080 putbyte(buf, 1, (round(log((double)speed / 300) / GPS_LN2)) + 2);
3081 putbyte(buf, 2, getub(buf, 1)); /* output baudrate */
3082 putbyte(buf, 3, 3); /* character width (8 bits) */
3083 putbyte(buf, 4, parity); /* parity (normally odd) */
3084 putbyte(buf, 5, stopbits - 1); /* stop bits (normally 1 stopbit) */
3085 putbyte(buf, 6, 0); /* flow control (none) */
3086 putbyte(buf, 7, 0x02); /* input protocol (TSIP) */
3087 putbyte(buf, 8, 0x02); /* output protocol (TSIP) */
3088 putbyte(buf, 9, 0); /* reserved */
3089 (void)tsip_write(session, 0xbc, buf, 10);
3090
3091 return true; /* it would be nice to error-check this */
3092 }
3093
tsip_mode(struct gps_device_t * session,int mode)3094 static void tsip_mode(struct gps_device_t *session, int mode)
3095 {
3096 if (mode == MODE_NMEA) {
3097 unsigned char buf[16];
3098
3099 /* send NMEA Interval and Message Mask Command (0x7a)
3100 * First turn on the NMEA messages we want */
3101 putbyte(buf, 0, 0x00); /* subcode 0 */
3102 putbyte(buf, 1, 0x01); /* 1-second fix interval */
3103 putbyte(buf, 2, 0x00); /* Reserved */
3104 putbyte(buf, 3, 0x00); /* Reserved */
3105 putbyte(buf, 4, 0x01); /* 1=GST, Reserved */
3106 /* 1=GGA, 2=GGL, 4=VTG, 8=GSV, */
3107 /* 0x10=GSA, 0x20=ZDA, 0x40=Reserved, 0x80=RMC */
3108 putbyte(buf, 5, 0x19);
3109
3110 (void)tsip_write(session, 0x7A, buf, 6);
3111
3112 /* Now switch to NMEA mode */
3113
3114 memset(buf, 0, sizeof(buf));
3115
3116 /* Set Port Configuration (0xbc) */
3117 // 4800, really?
3118 putbyte(buf, 0, 0xff); /* current port */
3119 putbyte(buf, 1, 0x06); /* 4800 bps input */
3120 putbyte(buf, 2, 0x06); /* 4800 bps output */
3121 putbyte(buf, 3, 0x03); /* 8 data bits */
3122 putbyte(buf, 4, 0x00); /* No parity */
3123 putbyte(buf, 5, 0x00); /* 1 stop bit */
3124 putbyte(buf, 6, 0x00); /* No flow control */
3125 putbyte(buf, 7, 0x02); /* Input protocol TSIP */
3126 putbyte(buf, 8, 0x04); /* Output protocol NMEA */
3127 putbyte(buf, 9, 0x00); /* Reserved */
3128
3129 (void)tsip_write(session, 0xBC, buf, 10);
3130
3131 } else if (mode == MODE_BINARY) {
3132 /* The speed switcher also puts us back in TSIP, so call it */
3133 /* with the default 9600 8O1. */
3134 // FIXME: Should preserve the current speed.
3135 // (void)tsip_speed_switch(session, 9600, 'O', 1);
3136 // FIXME: should config TSIP binary!
3137 ;
3138
3139 } else {
3140 GPSD_LOG(LOG_ERROR, &session->context->errout,
3141 "TSIP: unknown mode %i requested\n", mode);
3142 }
3143 }
3144 #endif /* RECONFIGURE_ENABLE */
3145
3146 /* configure generic Trimble TSIP device to a known state */
configuration_packets_generic(struct gps_device_t * session)3147 void configuration_packets_generic(struct gps_device_t *session)
3148 {
3149 unsigned char buf[100];
3150
3151 GPSD_LOG(LOG_PROG, &session->context->errout,
3152 "TSIP: configuration_packets_generic()\n");
3153
3154 // Set basic configuration, using Set or Request I/O Options (0x35).
3155 /* Position: enable: Double Precision, LLA
3156 * disable: ECEF */
3157 putbyte(buf, 0, IO1_8F20|IO1_DP|IO1_LLA);
3158 /* Velocity: enable: ENU, disable ECEF */
3159 putbyte(buf, 1, IO2_ENU);
3160 /* Time: enable: 0x42, 0x43, 0x4a
3161 * disable: 0x83, 0x84, 0x56 */
3162 putbyte(buf, 2, 0x00);
3163 /* Aux: enable: 0x5A, dBHz */
3164 putbyte(buf, 3, IO4_DBHZ);
3165 (void)tsip_write(session, 0x35, buf, 4);
3166
3167 /* Request Software Version (0x1f), returns 0x45 */
3168 (void)tsip_write(session, 0x1f, NULL, 0);
3169
3170 /* Current Time Request (0x21), returns 0x41 */
3171 (void)tsip_write(session, 0x21, NULL, 0);
3172
3173 /* Set Operating Parameters (0x2c)
3174 * not present in:
3175 * Lassen SQ (2002)
3176 * Lassen iQ (2005)
3177 * RES SMT 360 */
3178 /* dynamics code: enabled: 1=land
3179 * disabled: 2=sea, 3=air, 4=static
3180 * default is land */
3181 putbyte(buf, 0, 0x01);
3182 /* elevation mask, 10 degrees is a common default,
3183 * TSIP default is 15 */
3184 putbef32((char *)buf, 1, (float)10.0 * DEG_2_RAD);
3185 /* signal level mask
3186 * default is 2.0 AMU. 5.0 to 6.0 for high accuracy */
3187 putbef32((char *)buf, 5, (float)06.0);
3188 /* PDOP mask
3189 * default is 12. 5.0 to 6.0 for high accuracy */
3190 putbef32((char *)buf, 9, (float)8.0);
3191 /* PDOP switch
3192 * default is 8.0 */
3193 putbef32((char *)buf, 13, (float)6.0);
3194 (void)tsip_write(session, 0x2c, buf, 17);
3195
3196 /* Set Position Fix Mode (0x22)
3197 * 0=auto 2D/3D, 1=time only, 3=2D, 4=3D, 10=Overdetermined clock */
3198 putbyte(buf, 0, 0x00);
3199 (void)tsip_write(session, 0x22, buf, 1);
3200
3201 /* Request GPS System Message (0x48)
3202 * not supported on model RES SMT 360 */
3203 (void)tsip_write(session, 0x28, NULL, 0);
3204
3205 /* Last Position and Velocity Request (0x37)
3206 * returns 0x57 and (0x42, 0x4a, 0x83, or 0x84) and (0x43 or 0x56) */
3207 (void)tsip_write(session, 0x37, NULL, 0);
3208 putbyte(buf, 0, 0x15);
3209 (void)tsip_write(session, 0x8e, buf, 1);
3210
3211 /* Primary Receiver Configuration Parameters Request (0xbb-00)
3212 * returns Primary Receiver Configuration Block (0xbb-00) */
3213 putbyte(buf, 0, 0x00);
3214 (void)tsip_write(session, 0xbb, buf, 1);
3215 }
3216
3217 /* configure Acutime Gold to a known state */
configuration_packets_acutime_gold(struct gps_device_t * session)3218 void configuration_packets_acutime_gold(struct gps_device_t *session)
3219 {
3220 unsigned char buf[100];
3221
3222 GPSD_LOG(LOG_PROG, &session->context->errout,
3223 "TSIP: configuration_packets_acutime_gold()\n");
3224
3225 /* Request Firmware Version (0x1c-01)
3226 * returns Firmware component version information (0x1x-81) */
3227 putbyte(buf, 0, 0x01);
3228 (void)tsip_write(session, 0x1c, buf, 1);
3229
3230 /* Set Self-Survey Parameters (0x8e-a9) */
3231 putbyte(buf, 0, 0xa9); /* Subcode */
3232 putbyte(buf, 1, 0x01); /* Self-Survey Enable = enable */
3233 putbyte(buf, 2, 0x01); /* Position Save Flag = save position */
3234 putbe32(buf, 3, 2000); /* Self-Survey Length = 2000 fixes */
3235 /* Horizontal Uncertainty, 1-100, 1=best, 100=worst,
3236 * default 100 */
3237 putbe32(buf, 7, 0);
3238 /* Verical Uncertainty, 1-100, 1=best, 100=worst,
3239 * default 100
3240 * not present in RES SMT 360 */
3241 (void)tsip_write(session, 0x8e, buf, 11);
3242
3243 /* Set PPS Output Option (0x8e-4e) */
3244 putbyte(buf, 0, 0x4e); /* Subcode */
3245 /* PPS driver switch = 2 (PPS is always output) */
3246 putbyte(buf, 1, 2);
3247 (void)tsip_write(session, 0x8e, buf, 2);
3248
3249 /* Set Primary Receiver Configuration (0xbb-00) */
3250 putbyte(buf, 0, 0x00); /* Subcode */
3251 /* Receiver mode, 7 = Force Overdetermined clock */
3252 putbyte(buf, 1, 0x07);
3253 /* Not enabled = unchanged
3254 * must be 0xff on RES SMT 360 */
3255 putbyte(buf, 2, 0xff);
3256 /* Dynamics code = default
3257 * must be 0xff on RES SMT 360 */
3258 putbyte(buf, 3, 0x01);
3259 /* Solution Mode = default
3260 * must be 0xff on RES SMT 360 */
3261 putbyte(buf, 4, 0x01);
3262 /* Elevation Mask = 10 deg */
3263 putbef32((char *)buf, 5, (float)10.0 * DEG_2_RAD);
3264 /* AMU Mask. 0 to 55. default is 4.0 */
3265 putbef32((char *)buf, 9, (float)4.0);
3266 /* PDOP Mask = 8.0, default = 6 */
3267 putbef32((char *)buf, 13, (float)8.0);
3268 /* PDOP Switch = 6.0, ignored in RES SMT 360 */
3269 putbef32((char *)buf, 17, (float)6.0);
3270 /* must be 0xff */
3271 putbyte(buf, 21, 0xff);
3272 /* Anti-Jam Mode, 0=Off, 1=On */
3273 putbyte(buf, 22, 0x0);
3274 /* Reserved. Must be 0xffff */
3275 putbe16(buf, 23, 0xffff);
3276 /* Measurement Rate and Position Fix Rate = default
3277 * must be 0xffff on res smt 360 */
3278 putbe16(buf, 25, 0x0000);
3279 /* 27 is Constellation on RES SMT 360.
3280 * 1 = GPS, 2=GLONASS, 8=BeiDou, 0x10=Galileo, 5=QZSS */
3281 putbe32(buf, 27, 0xffffffff); /* Reserved */
3282 putbe32(buf, 31, 0xffffffff); /* Reserved */
3283 putbe32(buf, 35, 0xffffffff); /* Reserved */
3284 putbe32(buf, 39, 0xffffffff); /* Reserved */
3285 (void)tsip_write(session, 0xbb, buf, 43);
3286
3287 /* Set Packet Broadcast Mask (0x8e-a5) */
3288 putbyte(buf, 0, 0xa5); /* Subcode */
3289 /* Packets bit field = default + Primary timing,
3290 * Supplemental timing 32e1
3291 * 1=0x8f-ab, 4=0x8f-ac, 0x40=Automatic Output Packets */
3292 putbe16(buf, 1, 0x32e1);
3293 putbyte(buf, 3, 0x00); /* not used */
3294 putbyte(buf, 4, 0x00); /* not used */
3295 (void)tsip_write(session, 0x8e, buf, 5);
3296 }
3297
3298 /* configure RES 360 to a known state */
configuration_packets_res360(struct gps_device_t * session)3299 void configuration_packets_res360(struct gps_device_t *session)
3300 {
3301 unsigned char buf[100];
3302
3303 GPSD_LOG(LOG_PROG, &session->context->errout,
3304 "TSIP: configuration_packets_res360()\n");
3305
3306 // should already have versions 0x8f-81 and 0x8f-83.
3307 /* Self-Survey Parameters (0x8e-a9) is default on
3308 * query them? */
3309
3310 /* PPS Output Option (0x8e-4e) is default on */
3311
3312 /* Set Packet Broadcast Mask (0x8e-a5)
3313 * RES SMT 360 default 5, 0 */
3314 putbyte(buf, 0, 0xa5); /* Subcode */
3315 /* Packets bit field = default + Auto output packets
3316 * 1=0x8f-ab, 4=0x8f-ac, 0x40=Automatic Output Packets */
3317 putbe16(buf, 1, 0x0045);
3318 putbe16(buf, 3, 0x0000);
3319 (void)tsip_write(session, 0x8e, buf, 5);
3320
3321 // set I/O Options
3322 // RES SMT 360 defaults: 12 02 00 08
3323 // position and velocity only sent during self-survey.
3324 // Position
3325 putbyte(buf, 0, IO1_DP|IO1_LLA|IO1_ECEF);
3326 // Velocity
3327 putbyte(buf, 1, IO2_VECEF|IO2_ENU);
3328 // Timing
3329 putbyte(buf, 2, 0x01); // Use 0x8e-a2
3330 // Auxillary
3331 putbyte(buf, 3, 0x08); // Packet 0x5a off, dBHz
3332 (void)tsip_write(session, 0x35, buf, 4);
3333
3334 #ifdef __UNUSED__
3335 // request I/O Options (0x55)
3336 (void)tsip_write(session, 0x35, buf, 0);
3337
3338 // request Receiver Configuration (0xbb)
3339 putbyte(buf, 0, 0x00);
3340 (void)tsip_write(session, 0xbb, buf, 1);
3341 // Restart Self-Survey (0x8e-a6)
3342 // which gives us 2,000 normal fixes, before going quiet again.
3343 putbyte(buf, 0, 0xa6);
3344 putbyte(buf, 1, 0x00);
3345 (void)tsip_write(session, 0x8e, buf, 2);
3346 #endif // __UNUSED__
3347 }
3348
3349 /* this is everything we export */
3350 /* *INDENT-OFF* */
3351 const struct gps_type_t driver_tsip =
3352 {
3353 .type_name = "Trimble TSIP", /* full name of type */
3354 .packet_type = TSIP_PACKET, /* associated lexer packet type */
3355 .flags = DRIVER_STICKY, /* remember this */
3356 .trigger = NULL, /* no trigger */
3357 .channels = TSIP_CHANNELS, /* consumer-grade GPS */
3358 .probe_detect = tsip_detect, /* probe for 9600O81 device */
3359 .get_packet = generic_get, /* use the generic packet getter */
3360 .parse_packet = tsip_parse_input, /* parse message packets */
3361 .rtcm_writer = NULL, /* doesn't accept DGPS corrections */
3362 .init_query = tsip_init_query, /* non-perturbing initial query */
3363 .event_hook = tsip_event_hook, /* fire on various lifetime events */
3364 #ifdef RECONFIGURE_ENABLE
3365 .speed_switcher = tsip_speed_switch,/* change baud rate */
3366 .mode_switcher = tsip_mode, /* there is a mode switcher */
3367 .rate_switcher = NULL, /* no rate switcher */
3368 .min_cycle.tv_sec = 1, /* not relevant, no rate switch */
3369 .min_cycle.tv_nsec = 0, /* not relevant, no rate switch */
3370 #endif /* RECONFIGURE_ENABLE */
3371 #ifdef CONTROLSEND_ENABLE
3372 .control_send = tsip_control_send,/* how to send commands */
3373 #endif /* CONTROLSEND_ENABLE */
3374 .time_offset = NULL,
3375 };
3376 /* *INDENT-ON* */
3377
3378 #endif /* TSIP_ENABLE */
3379