Devuan fork of gpsd
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

3379 lines
117 KiB

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