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.
 
 
 
 
 
 

3586 lines
125 KiB

  1. /*
  2. * This file is Copyright (c) 2010-2018 by the GPSD project
  3. * SPDX-License-Identifier: BSD-2-clause
  4. */
  5. #include "gpsd_config.h" /* must be before all includes */
  6. #include <ctype.h> /* for isdigit() */
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <stdbool.h>
  10. #include <math.h>
  11. #include <string.h>
  12. #include <stdarg.h>
  13. #include <time.h>
  14. #include "gpsd.h"
  15. #include "strfuncs.h"
  16. #ifdef NMEA0183_ENABLE
  17. #include "timespec.h"
  18. /**************************************************************************
  19. *
  20. * Parser helpers begin here
  21. *
  22. **************************************************************************/
  23. /* process a pair of latitude/longitude fields starting at field index BEGIN
  24. * The input fields look like this:
  25. * field[0]: 4404.1237962
  26. * field[1]: N
  27. * field[2]: 12118.8472460
  28. * field[3]: W
  29. * input format of lat/lon is NMEA style DDDMM.mmmmmmm
  30. * yes, 7 digits of precision from survey grade GPS
  31. *
  32. * return: 0 == OK, non zero is failure.
  33. */
  34. static int do_lat_lon(char *field[], struct gps_fix_t *out)
  35. {
  36. double d, m;
  37. double lon;
  38. double lat;
  39. if ('\0' == field[0][0] ||
  40. '\0' == field[1][0] ||
  41. '\0' == field[2][0] ||
  42. '\0' == field[3][0]) {
  43. return 1;
  44. }
  45. lat = safe_atof(field[0]);
  46. m = 100.0 * modf(lat / 100.0, &d);
  47. lat = d + m / 60.0;
  48. if ('S' == field[1][0])
  49. lat = -lat;
  50. lon = safe_atof(field[2]);
  51. m = 100.0 * modf(lon / 100.0, &d);
  52. lon = d + m / 60.0;
  53. if ('W' == field[3][0])
  54. lon = -lon;
  55. if (0 == isfinite(lat) ||
  56. 0 == isfinite(lon)) {
  57. return 2;
  58. }
  59. out->latitude = lat;
  60. out->longitude = lon;
  61. return 0;
  62. }
  63. /* process an FAA mode character
  64. * return status as in session->gpsdata.status
  65. */
  66. static int faa_mode(char mode)
  67. {
  68. int newstatus = STATUS_FIX;
  69. switch (mode) {
  70. case '\0': /* missing */
  71. newstatus = STATUS_NO_FIX;
  72. break;
  73. case 'A': /* Autonomous */
  74. default:
  75. newstatus = STATUS_FIX;
  76. break;
  77. case 'D': /* Differential */
  78. newstatus = STATUS_DGPS_FIX;
  79. break;
  80. case 'E': /* Estimated dead reckoning */
  81. newstatus = STATUS_DR;
  82. break;
  83. case 'F': /* Float RTK */
  84. newstatus = STATUS_RTK_FLT;
  85. break;
  86. case 'N': /* Data Not Valid */
  87. /* already handled, for paranoia sake also here */
  88. newstatus = STATUS_NO_FIX;
  89. break;
  90. case 'P': /* Precise (NMEA 4+) */
  91. newstatus = STATUS_DGPS_FIX; /* sort of DGPS */
  92. break;
  93. case 'R': /* fixed RTK */
  94. newstatus = STATUS_RTK_FIX;
  95. break;
  96. case 'S': /* simulator */
  97. newstatus = STATUS_NO_FIX; /* or maybe MODE_FIX? */
  98. break;
  99. }
  100. return newstatus;
  101. }
  102. /**************************************************************************
  103. *
  104. * Scary timestamp fudging begins here
  105. *
  106. * Four sentences, GGA and GLL and RMC and ZDA, contain timestamps.
  107. * GGA/GLL/RMC timestamps look like hhmmss.ss, with the trailing .ss,
  108. * or .sss, part optional.
  109. * RMC has a date field, in the format ddmmyy. ZDA has separate fields
  110. * for day/month/year, with a 4-digit year. This means that for RMC we
  111. * must supply a century and for GGA and GLL we must supply a century,
  112. * year, and day. We get the missing data from a previous RMC or ZDA;
  113. * century in RMC is supplied from the daemon's context (initialized at
  114. * startup time) if there has been no previous ZDA.
  115. *
  116. **************************************************************************/
  117. #define DD(s) ((int)((s)[0]-'0')*10+(int)((s)[1]-'0'))
  118. /* sentence supplied ddmmyy, but no century part
  119. *
  120. * return: 0 == OK, greater than zero on failure
  121. */
  122. static int merge_ddmmyy(char *ddmmyy, struct gps_device_t *session)
  123. {
  124. int yy;
  125. int mon;
  126. int mday;
  127. int year;
  128. unsigned i; /* NetBSD complains about signed array index */
  129. if (NULL == ddmmyy) {
  130. return 1;
  131. }
  132. for (i = 0; i < 6; i++) {
  133. /* NetBSD 6 wants the cast */
  134. if (0 == isdigit((int)ddmmyy[i])) {
  135. /* catches NUL and non-digits */
  136. /* Telit HE910 can set year to "-1" (1999 - 2000) */
  137. GPSD_LOG(LOG_WARN, &session->context->errout,
  138. "merge_ddmmyy(%s), malformed date\n", ddmmyy);
  139. return 2;
  140. }
  141. }
  142. /* check for termination */
  143. if ('\0' != ddmmyy[6]) {
  144. /* missing NUL */
  145. GPSD_LOG(LOG_WARN, &session->context->errout,
  146. "merge_ddmmyy(%s), malformed date\n", ddmmyy);
  147. return 3;
  148. }
  149. /* should be no defects left to segfault DD() */
  150. yy = DD(ddmmyy + 4);
  151. mon = DD(ddmmyy + 2);
  152. mday = DD(ddmmyy);
  153. /* check for century wrap */
  154. if (session->nmea.date.tm_year % 100 == 99 && yy == 0)
  155. gpsd_century_update(session, session->context->century + 100);
  156. year = (session->context->century + yy);
  157. /* 32 bit systems will break in 2038.
  158. * Telix fails on GPS rollover to 2099, which 32 bit system
  159. * can not handle. So wrap at 2080. That way 64 bit systems
  160. * work until 2080, and 2099 gets reported as 1999.
  161. * since GPS epoch started in 1980, allows for old NMEA to work.
  162. */
  163. if (2080 <= year) {
  164. year -= 100;
  165. }
  166. if ( (1 > mon ) || (12 < mon ) ) {
  167. GPSD_LOG(LOG_WARN, &session->context->errout,
  168. "merge_ddmmyy(%s), malformed month\n", ddmmyy);
  169. return 4;
  170. } else if ( (1 > mday ) || (31 < mday ) ) {
  171. GPSD_LOG(LOG_WARN, &session->context->errout,
  172. "merge_ddmmyy(%s), malformed day\n", ddmmyy);
  173. return 5;
  174. } else {
  175. GPSD_LOG(LOG_DATA, &session->context->errout,
  176. "merge_ddmmyy(%s) sets year %d\n",
  177. ddmmyy, year);
  178. session->nmea.date.tm_year = year - 1900;
  179. session->nmea.date.tm_mon = mon - 1;
  180. session->nmea.date.tm_mday = mday;
  181. }
  182. GPSD_LOG(LOG_RAW, &session->context->errout,
  183. "merge_ddmmyy(%s) %d %d %d\n",
  184. ddmmyy,
  185. session->nmea.date.tm_mon,
  186. session->nmea.date.tm_mday,
  187. session->nmea.date.tm_year);
  188. return 0;
  189. }
  190. /* decode an hhmmss.ss string into struct tm data and nsecs
  191. *
  192. * return: 0 == OK, otherwise failure
  193. */
  194. static int decode_hhmmss(struct tm *date, long *nsec, char *hhmmss,
  195. struct gps_device_t *session)
  196. {
  197. int old_hour = date->tm_hour;
  198. int i, sublen;
  199. if (NULL == hhmmss) {
  200. return 1;
  201. }
  202. for (i = 0; i < 6; i++) {
  203. /* NetBSD 6 wants the cast */
  204. if (0 == isdigit((int)hhmmss[i])) {
  205. /* catches NUL and non-digits */
  206. GPSD_LOG(LOG_WARN, &session->context->errout,
  207. "decode_hhmmss(%s), malformed time\n", hhmmss);
  208. return 2;
  209. }
  210. }
  211. /* don't check for termination, might have fractional seconds */
  212. date->tm_hour = DD(hhmmss);
  213. if (date->tm_hour < old_hour) /* midnight wrap */
  214. date->tm_mday++;
  215. date->tm_min = DD(hhmmss + 2);
  216. date->tm_sec = DD(hhmmss + 4);
  217. if ('.' == hhmmss[6] &&
  218. /* NetBSD 6 wants the cast */
  219. 0 != isdigit((int)hhmmss[7])) {
  220. i = atoi(hhmmss + 7);
  221. sublen = strlen(hhmmss + 7);
  222. *nsec = (long)i * (long)pow(10.0, 9 - sublen);
  223. } else {
  224. *nsec = 0;
  225. }
  226. return 0;
  227. }
  228. /* update from a UTC time
  229. *
  230. * return: 0 == OK, greater than zero on failure
  231. */
  232. static int merge_hhmmss(char *hhmmss, struct gps_device_t *session)
  233. {
  234. int old_hour = session->nmea.date.tm_hour;
  235. int i, sublen;
  236. if (NULL == hhmmss) {
  237. return 1;
  238. }
  239. for (i = 0; i < 6; i++) {
  240. /* NetBSD 6 wants the cast */
  241. if (0 == isdigit((int)hhmmss[i])) {
  242. /* catches NUL and non-digits */
  243. GPSD_LOG(LOG_WARN, &session->context->errout,
  244. "merge_hhmmss(%s), malformed time\n", hhmmss);
  245. return 2;
  246. }
  247. }
  248. /* don't check for termination, might have fractional seconds */
  249. session->nmea.date.tm_hour = DD(hhmmss);
  250. if (session->nmea.date.tm_hour < old_hour) /* midnight wrap */
  251. session->nmea.date.tm_mday++;
  252. session->nmea.date.tm_min = DD(hhmmss + 2);
  253. session->nmea.date.tm_sec = DD(hhmmss + 4);
  254. session->nmea.subseconds.tv_sec = 0;
  255. if ('.' == hhmmss[6] &&
  256. /* NetBSD 6 wants the cast */
  257. 0 != isdigit((int)hhmmss[7])) {
  258. i = atoi(hhmmss + 7);
  259. sublen = strlen(hhmmss + 7);
  260. session->nmea.subseconds.tv_nsec = (long)i *
  261. (long)pow(10.0, 9 - sublen);
  262. } else {
  263. session->nmea.subseconds.tv_nsec = 0;
  264. }
  265. return 0;
  266. }
  267. static void register_fractional_time(const char *tag, const char *fld,
  268. struct gps_device_t *session)
  269. {
  270. char ts_buf[TIMESPEC_LEN];
  271. if (fld[0] != '\0') {
  272. session->nmea.last_frac_time = session->nmea.this_frac_time;
  273. DTOTS(&session->nmea.this_frac_time, safe_atof(fld));
  274. session->nmea.latch_frac_time = true;
  275. GPSD_LOG(LOG_DATA, &session->context->errout,
  276. "%s: registers fractional time %s\n",
  277. tag,
  278. timespec_str(&session->nmea.this_frac_time, ts_buf,
  279. sizeof(ts_buf)));
  280. }
  281. }
  282. /**************************************************************************
  283. *
  284. * NMEA sentence handling begins here
  285. *
  286. **************************************************************************/
  287. /* process xxVTG
  288. * $GPVTG,054.7,T,034.4,M,005.5,N,010.2,K
  289. * $GPVTG,054.7,T,034.4,M,005.5,N,010.2,K,A
  290. *
  291. * where:
  292. * 1,2 054.7,T True track made good (degrees)
  293. * 3,4 034.4,M Magnetic track made good
  294. * 5,6 005.5,N Ground speed, knots
  295. * 7,8 010.2,K Ground speed, Kilometers per hour
  296. * 9 A Mode Indicator (optional)
  297. * see faa_mode() for possible mode values
  298. *
  299. * see also:
  300. * https://gpsd.gitlab.io/gpsd/NMEA.html#_vtg_track_made_good_and_ground_speed
  301. */
  302. static gps_mask_t processVTG(int count,
  303. char *field[],
  304. struct gps_device_t *session)
  305. {
  306. gps_mask_t mask = ONLINE_SET;
  307. if( (field[1][0] == '\0') || (field[5][0] == '\0')){
  308. return mask;
  309. }
  310. /* ignore empty/missing field, fix mode of last resort */
  311. if ((count > 9) && ('\0' != field[9][0])) {
  312. switch (field[9][0]) {
  313. case 'A':
  314. /* Autonomous, 2D or 3D fix */
  315. /* FALL THROUGH */
  316. case 'D':
  317. /* Differential, 2D or 3D fix */
  318. // MODE_SET here causes issues
  319. // mask |= MODE_SET;
  320. break;
  321. case 'E':
  322. /* Estimated, DR only */
  323. /* FALL THROUGH */
  324. case 'N':
  325. /* Not Valid */
  326. // MODE_SET here causes issues
  327. // mask |= MODE_SET;
  328. // nothing to use here, leave
  329. return mask;
  330. default:
  331. /* Huh? */
  332. break;
  333. }
  334. }
  335. // set true track
  336. session->newdata.track = safe_atof(field[1]);
  337. mask |= TRACK_SET;
  338. // set magnetic variation
  339. if (field[3][0] != '\0'){ // ignore empty fields
  340. session->newdata.magnetic_track = safe_atof(field[3]);
  341. mask |= MAGNETIC_TRACK_SET;
  342. }
  343. session->newdata.speed = safe_atof(field[5]) * KNOTS_TO_MPS;
  344. mask |= SPEED_SET;
  345. GPSD_LOG(LOG_DATA, &session->context->errout,
  346. "VTG: course(T)=%.2f, course(M)=%.2f, speed=%.2f",
  347. session->newdata.track, session->newdata.magnetic_track,
  348. session->newdata.speed);
  349. return mask;
  350. }
  351. /* Recommend Minimum Course Specific GPS/TRANSIT Data */
  352. static gps_mask_t processRMC(int count, char *field[],
  353. struct gps_device_t *session)
  354. {
  355. /*
  356. * RMC,225446.33,A,4916.45,N,12311.12,W,000.5,054.7,191194,020.3,E,A*68
  357. * 1 225446.33 Time of fix 22:54:46 UTC
  358. * 2 A Status of Fix:
  359. * A = Autonomous, valid;
  360. * D = Differential, valid;
  361. * V = invalid
  362. * 3,4 4916.45,N Latitude 49 deg. 16.45 min North
  363. * 5,6 12311.12,W Longitude 123 deg. 11.12 min West
  364. * 7 000.5 Speed over ground, Knots
  365. * 8 054.7 Course Made Good, True north
  366. * 9 181194 Date of fix ddmmyy. 18 November 1994
  367. * 10,11 020.3,E Magnetic variation 20.3 deg East
  368. * 12 A FAA mode indicator (NMEA 2.3 and later)
  369. * see faa_mode() for possible mode values
  370. * 13 V Nav Status (NMEA 4.1 and later)
  371. * A=autonomous,
  372. * D=differential,
  373. * E=Estimated,
  374. * M=Manual input mode
  375. * N=not valid,
  376. * S=Simulator,
  377. * V = Valid
  378. * *68 mandatory nmea_checksum
  379. *
  380. * SiRF chipsets don't return either Mode Indicator or magnetic variation.
  381. */
  382. gps_mask_t mask = ONLINE_SET;
  383. char status = field[2][0];
  384. int newstatus;
  385. switch (status) {
  386. default:
  387. /* missing */
  388. /* FALLTHROUGH */
  389. case 'V':
  390. /* Invalid */
  391. session->gpsdata.status = STATUS_NO_FIX;
  392. session->newdata.mode = MODE_NO_FIX;
  393. mask |= STATUS_SET | MODE_SET;
  394. break;
  395. case 'D':
  396. /* Differential Fix */
  397. /* FALLTHROUGH */
  398. case 'A':
  399. /* Valid Fix */
  400. /*
  401. * The MTK3301, Royaltek RGM-3800, and possibly other
  402. * devices deliver bogus time values when the navigation
  403. * warning bit is set.
  404. */
  405. if ('\0' != field[1][0] &&
  406. 9 < count &&
  407. '\0' != field[9][0]) {
  408. if (0 == merge_hhmmss(field[1], session) &&
  409. 0 == merge_ddmmyy(field[9], session)) {
  410. /* got a good data/time */
  411. mask |= TIME_SET;
  412. register_fractional_time(field[0], field[1], session);
  413. }
  414. }
  415. /* else, no point to the time only case, no regressions with that */
  416. if (0 == do_lat_lon(&field[3], &session->newdata)) {
  417. newstatus = STATUS_FIX;
  418. mask |= LATLON_SET;
  419. if (MODE_2D >= session->gpsdata.fix.mode) {
  420. /* we have at least a 2D fix */
  421. /* might cause blinking */
  422. session->newdata.mode = MODE_2D;
  423. mask |= MODE_SET;
  424. }
  425. } else {
  426. newstatus = STATUS_NO_FIX;
  427. session->newdata.mode = MODE_NO_FIX;
  428. mask |= MODE_SET;
  429. }
  430. if ('\0' != field[7][0]) {
  431. session->newdata.speed = safe_atof(field[7]) * KNOTS_TO_MPS;
  432. mask |= SPEED_SET;
  433. }
  434. if ('\0' != field[8][0]) {
  435. session->newdata.track = safe_atof(field[8]);
  436. mask |= TRACK_SET;
  437. }
  438. /* get magnetic variation */
  439. if ('\0' != field[10][0] &&
  440. '\0' != field[11][0]) {
  441. session->newdata.magnetic_var = safe_atof(field[10]);
  442. switch (field[11][0]) {
  443. case 'E':
  444. /* no change */
  445. break;
  446. case 'W':
  447. session->newdata.magnetic_var = -session->newdata.magnetic_var;
  448. break;
  449. default:
  450. /* huh? */
  451. session->newdata.magnetic_var = NAN;
  452. break;
  453. }
  454. if (0 == isfinite(session->newdata.magnetic_var) ||
  455. 0.09 >= fabs(session->newdata.magnetic_var)) {
  456. /* some GPS set 0.0,E, or 0,w instead of blank */
  457. session->newdata.magnetic_var = NAN;
  458. } else {
  459. mask |= MAGNETIC_TRACK_SET;
  460. }
  461. }
  462. if (count >= 12) {
  463. newstatus = faa_mode(field[12][0]);
  464. }
  465. /*
  466. * This copes with GPSes like the Magellan EC-10X that *only* emit
  467. * GPRMC. In this case we set mode and status here so the client
  468. * code that relies on them won't mistakenly believe it has never
  469. * received a fix.
  470. */
  471. if (3 < session->gpsdata.satellites_used) {
  472. /* 4 sats used means 3D */
  473. session->newdata.mode = MODE_3D;
  474. mask |= MODE_SET;
  475. } else if (0 != isfinite(session->gpsdata.fix.altHAE) ||
  476. 0 != isfinite(session->gpsdata.fix.altMSL)) {
  477. /* we probably have at least a 3D fix */
  478. /* this handles old GPS that do not report 3D */
  479. session->newdata.mode = MODE_3D;
  480. mask |= MODE_SET;
  481. }
  482. session->gpsdata.status = newstatus;
  483. }
  484. GPSD_LOG(LOG_DATA, &session->context->errout,
  485. "RMC: ddmmyy=%s hhmmss=%s lat=%.2f lon=%.2f "
  486. "speed=%.2f track=%.2f mode=%d var=%.1f status=%d\n",
  487. field[9], field[1],
  488. session->newdata.latitude,
  489. session->newdata.longitude,
  490. session->newdata.speed,
  491. session->newdata.track,
  492. session->newdata.mode,
  493. session->newdata.magnetic_var,
  494. session->gpsdata.status);
  495. return mask;
  496. }
  497. /* Geographic position - Latitude, Longitude */
  498. static gps_mask_t processGLL(int count, char *field[],
  499. struct gps_device_t *session)
  500. {
  501. /* Introduced in NMEA 3.0.
  502. *
  503. * $GPGLL,4916.45,N,12311.12,W,225444,A,A*5C
  504. *
  505. * 1,2: 4916.46,N Latitude 49 deg. 16.45 min. North
  506. * 3,4: 12311.12,W Longitude 123 deg. 11.12 min. West
  507. * 5: 225444 Fix taken at 22:54:44 UTC
  508. * 6: A Data valid
  509. * 7: A Autonomous mode
  510. * 8: *5C Mandatory NMEA checksum
  511. *
  512. * 1,2 Latitude, N (North) or S (South)
  513. * 3,4 Longitude, E (East) or W (West)
  514. * 5 UTC of position
  515. * 6 A = Active, V = Invalid data
  516. * 7 Mode Indicator
  517. * See faa_mode() for possible mode values.
  518. *
  519. * I found a note at <http://www.secoh.ru/windows/gps/nmfqexep.txt>
  520. * indicating that the Garmin 65 does not return time and status.
  521. * SiRF chipsets don't return the Mode Indicator.
  522. * This code copes gracefully with both quirks.
  523. *
  524. * Unless you care about the FAA indicator, this sentence supplies nothing
  525. * that GPRMC doesn't already. But at least two (Garmin GPS 48 and
  526. * Magellan Triton 400) actually ship updates in GLL that aren't redundant.
  527. *
  528. */
  529. char *status = field[7];
  530. gps_mask_t mask = ONLINE_SET;
  531. if (field[5][0] != '\0') {
  532. if (0 == merge_hhmmss(field[5], session)) {
  533. register_fractional_time(field[0], field[5], session);
  534. if (session->nmea.date.tm_year == 0)
  535. GPSD_LOG(LOG_WARN, &session->context->errout,
  536. "can't use GLL time until after ZDA or RMC"
  537. " has supplied a year.\n");
  538. else {
  539. mask = TIME_SET;
  540. }
  541. }
  542. }
  543. if ('\0' == field[6][0] ||
  544. 'V' == field[6][0]) {
  545. /* Invalid */
  546. session->gpsdata.status = STATUS_NO_FIX;
  547. session->newdata.mode = MODE_NO_FIX;
  548. mask |= STATUS_SET | MODE_SET;
  549. } else if ('A' == field[6][0] &&
  550. (count < 8 || *status != 'N') &&
  551. 0 == do_lat_lon(&field[1], &session->newdata)) {
  552. int newstatus;
  553. mask |= LATLON_SET;
  554. newstatus = STATUS_FIX;
  555. if (count >= 8) {
  556. newstatus = faa_mode(*status);
  557. }
  558. /*
  559. * This is a bit dodgy. Technically we shouldn't set the mode
  560. * bit until we see GSA, or similar. But it may be later in the
  561. * cycle, some devices like the FV-18 don't send it by default,
  562. * and elsewhere in the code we want to be able to test for the
  563. * presence of a valid fix with mode > MODE_NO_FIX.
  564. */
  565. if (0 != isfinite(session->gpsdata.fix.altHAE) ||
  566. 0 != isfinite(session->gpsdata.fix.altMSL)) {
  567. session->newdata.mode = MODE_3D;
  568. mask |= MODE_SET;
  569. } else if (3 < session->gpsdata.satellites_used) {
  570. /* 4 sats used means 3D */
  571. session->newdata.mode = MODE_3D;
  572. mask |= MODE_SET;
  573. } else if (MODE_2D > session->gpsdata.fix.mode ||
  574. (0 == isfinite(session->oldfix.altHAE) &&
  575. 0 == isfinite(session->oldfix.altMSL))) {
  576. session->newdata.mode = MODE_2D;
  577. mask |= MODE_SET;
  578. }
  579. session->gpsdata.status = newstatus;
  580. } else {
  581. session->gpsdata.status = STATUS_NO_FIX;
  582. session->newdata.mode = MODE_NO_FIX;
  583. mask |= STATUS_SET | MODE_SET;
  584. }
  585. GPSD_LOG(LOG_DATA, &session->context->errout,
  586. "GLL: hhmmss=%s lat=%.2f lon=%.2f mode=%d status=%d\n",
  587. field[5],
  588. session->newdata.latitude,
  589. session->newdata.longitude,
  590. session->newdata.mode,
  591. session->gpsdata.status);
  592. return mask;
  593. }
  594. /* Geographic position - Latitude, Longitude, and more */
  595. static gps_mask_t processGNS(int count UNUSED, char *field[],
  596. struct gps_device_t *session)
  597. {
  598. /* Introduced in NMEA 4.0?
  599. *
  600. * This mostly duplicates RMC, except for the multi GNSS mode
  601. * indicatore.
  602. *
  603. * Example. Ignore the line break.
  604. * $GPGNS,224749.00,3333.4268304,N,11153.3538273,W,D,19,0.6,406.110,
  605. * -26.294,6.0,0138,S,*6A
  606. *
  607. * 1: 224749.00 UTC HHMMSS.SS. 22:47:49.00
  608. * 2: 3333.4268304 Latitude DDMM.MMMMM. 33 deg. 33.4268304 min
  609. * 3: N Latitude North
  610. * 4: 12311.12 Longitude 111 deg. 53.3538273 min
  611. * 5: W Longitude West
  612. * 6: D FAA mode indicator
  613. * see faa_mode() for possible mode values
  614. * May be one to four characters.
  615. * Char 1 = GPS
  616. * Char 2 = GLONASS
  617. * Char 3 = ?
  618. * Char 4 = ?
  619. * 7: 19 Number of Satellites used in solution
  620. * 8: 0.6 HDOP
  621. * 9: 406110 MSL Altitude in meters
  622. * 10: -26.294 Geoid separation in meters
  623. * 11: 6.0 Age of differential corrections, in seconds
  624. * 12: 0138 Differential reference station ID
  625. * 13: S NMEA 4.1+ Navigation status
  626. * S = Safe
  627. * C = Caution
  628. * U = Unsafe
  629. * V = Not valid for navigation
  630. * 8: *6A Mandatory NMEA checksum
  631. *
  632. */
  633. int newstatus;
  634. int satellites_used;
  635. gps_mask_t mask = ONLINE_SET;
  636. if (field[1][0] != '\0') {
  637. if (0 == merge_hhmmss(field[1], session)) {
  638. register_fractional_time(field[0], field[1], session);
  639. if (session->nmea.date.tm_year == 0) {
  640. GPSD_LOG(LOG_WARN, &session->context->errout,
  641. "can't use GNS time until after ZDA or RMC"
  642. " has supplied a year.\n");
  643. } else {
  644. mask = TIME_SET;
  645. }
  646. }
  647. }
  648. /* FAA mode: not valid, ignore
  649. * Yes, in 2019 a GLONASS only fix may be valid, but not worth
  650. * the confusion */
  651. if ('\0' == field[6][0] || /* FAA mode: missing */
  652. 'N' == field[6][0]) { /* FAA mode: not valid */
  653. session->newdata.mode = MODE_NO_FIX;
  654. mask |= MODE_SET;
  655. return mask;
  656. }
  657. /* navigation status, assume S=safe and C=caution are OK */
  658. /* can be missing on valid fix */
  659. if ('U' == field[13][0] || /* Unsafe */
  660. 'V' == field[13][0]) { /* not valid */
  661. return mask;
  662. }
  663. satellites_used = atoi(field[7]);
  664. if (0 == do_lat_lon(&field[2], &session->newdata)) {
  665. mask |= LATLON_SET;
  666. session->newdata.mode = MODE_2D;
  667. if ('\0' != field[9][0]) {
  668. /* altitude is MSL */
  669. session->newdata.altMSL = safe_atof(field[9]);
  670. if (0 != isfinite(session->newdata.altMSL)) {
  671. mask |= ALTITUDE_SET;
  672. if (3 < satellites_used) {
  673. /* more than 3 sats used means 3D */
  674. session->newdata.mode = MODE_3D;
  675. }
  676. }
  677. /* only need geoid_sep if in 3D mode */
  678. if ('\0' != field[10][0]) {
  679. session->newdata.geoid_sep = safe_atof(field[10]);
  680. }
  681. /* Let gpsd_error_model() deal with geoid_sep and altHAE */
  682. }
  683. } else {
  684. session->newdata.mode = MODE_NO_FIX;
  685. mask |= MODE_SET;
  686. }
  687. if (field[8][0] != '\0') {
  688. session->gpsdata.dop.hdop = safe_atof(field[8]);
  689. }
  690. newstatus = faa_mode(field[6][0]);
  691. session->gpsdata.status = newstatus;
  692. mask |= MODE_SET;
  693. /* get DGPS stuff */
  694. if ('\0' != field[11][0] &&
  695. '\0' != field[12][0]) {
  696. /* both, or neither */
  697. session->newdata.dgps_age = safe_atof(field[11]);
  698. session->newdata.dgps_station = atoi(field[12]);
  699. }
  700. GPSD_LOG(LOG_DATA, &session->context->errout,
  701. "GNS: hhmmss=%s lat=%.2f lon=%.2f mode=%d status=%d\n",
  702. field[1],
  703. session->newdata.latitude,
  704. session->newdata.longitude,
  705. session->newdata.mode,
  706. session->gpsdata.status);
  707. return mask;
  708. }
  709. /* Global Positioning System Fix Data */
  710. static gps_mask_t processGGA(int c UNUSED, char *field[],
  711. struct gps_device_t *session)
  712. {
  713. /*
  714. * GGA,123519,4807.038,N,01131.324,E,1,08,0.9,545.4,M,46.9,M, , *42
  715. * 1 123519 Fix taken at 12:35:19 UTC
  716. * 2,3 4807.038,N Latitude 48 deg 07.038' N
  717. * 4,5 01131.324,E Longitude 11 deg 31.324' E
  718. * 6 1 Fix quality:
  719. * 0 = invalid,
  720. * 1 = GPS,
  721. * u-blox may use 1 for Estimated
  722. * 2 = DGPS,
  723. * 3 = PPS (Precise Position Service),
  724. * 4 = RTK (Real Time Kinematic) with fixed integers,
  725. * 5 = Float RTK,
  726. * 6 = Estimated,
  727. * 7 = Manual,
  728. * 8 = Simulator
  729. * 7 08 Number of satellites in use
  730. * 8 0.9 Horizontal dilution of position
  731. * 9,10 545.4,M Altitude, Meters MSL
  732. * 11,12 46.9,M Height of geoid (mean sea level) above WGS84
  733. * ellipsoid, in Meters
  734. * 13 33 time in seconds since last DGPS update
  735. * usually empty
  736. * 14 1023 DGPS station ID number (0000-1023)
  737. * usually empty
  738. *
  739. * Some GPS, like the SiRFstarV in NMEA mode, send both GPGSA and
  740. * GLGPSA with identical data.
  741. */
  742. gps_mask_t mask = ONLINE_SET;
  743. int newstatus;
  744. char last_last_gga_talker = session->nmea.last_gga_talker;
  745. int fix;
  746. int satellites_visible;
  747. session->nmea.last_gga_talker = field[0][1];
  748. if (0 == strlen(field[6])) {
  749. /* no data is no data, assume no fix
  750. * the test/daemon/myguide-3100.log shows lat/lon/alt but
  751. * no status, and related RMC shows no fix. */
  752. fix = -1;
  753. } else {
  754. fix = atoi(field[6]);
  755. }
  756. switch (fix) {
  757. case 0: /* no fix */
  758. newstatus = STATUS_NO_FIX;
  759. break;
  760. case 1:
  761. /* could be 2D, 3D, GNSSDR */
  762. newstatus = STATUS_FIX;
  763. break;
  764. case 2: /* differential */
  765. newstatus = STATUS_DGPS_FIX;
  766. break;
  767. case 3:
  768. /* GPS PPS, fix valid, could be 2D, 3D, GNSSDR */
  769. newstatus = STATUS_PPS_FIX;
  770. break;
  771. case 4: /* RTK integer */
  772. newstatus = STATUS_RTK_FIX;
  773. break;
  774. case 5: /* RTK float */
  775. newstatus = STATUS_RTK_FLT;
  776. break;
  777. case 6:
  778. /* dead reckoning, could be valid or invalid */
  779. newstatus = STATUS_DR;
  780. break;
  781. case 7:
  782. /* manual input, surveyed */
  783. newstatus = STATUS_TIME;
  784. break;
  785. case 8:
  786. /* simulated mode */
  787. /* Garmin GPSMAP and Gecko sends an 8, but undocumented why */
  788. newstatus = STATUS_SIM;
  789. break;
  790. default:
  791. newstatus = -1;
  792. break;
  793. }
  794. if (0 <= newstatus) {
  795. session->gpsdata.status = newstatus;
  796. mask = STATUS_SET;
  797. }
  798. /*
  799. * There are some receivers (the Trimble Placer 450 is an example) that
  800. * don't ship a GSA with mode 1 when they lose satellite lock. Instead
  801. * they just keep reporting GGA and GSA on subsequent cycles with the
  802. * timestamp not advancing and a bogus mode.
  803. *
  804. * On the assumption that GGA is only issued once per cycle we can
  805. * detect this here (it would be nicer to do it on GSA but GSA has
  806. * no timestamp).
  807. *
  808. * SiRFstarV breaks this assumption, sending GGA with different
  809. * talker IDs.
  810. */
  811. if ('\0' != last_last_gga_talker &&
  812. last_last_gga_talker != session->nmea.last_gga_talker) {
  813. /* skip the time check */
  814. session->nmea.latch_mode = 0;
  815. } else {
  816. session->nmea.latch_mode = strncmp(field[1],
  817. session->nmea.last_gga_timestamp,
  818. sizeof(session->nmea.last_gga_timestamp))==0;
  819. }
  820. if (session->nmea.latch_mode) {
  821. session->gpsdata.status = STATUS_NO_FIX;
  822. session->newdata.mode = MODE_NO_FIX;
  823. GPSD_LOG(LOG_PROG, &session->context->errout,
  824. "xxGGA: latch mode\n");
  825. } else
  826. (void)strlcpy(session->nmea.last_gga_timestamp, field[1],
  827. sizeof(session->nmea.last_gga_timestamp));
  828. /* satellites_visible is used as an accumulator in xxGSV
  829. * so if we set it here we break xxGSV
  830. * Some GPS, like SiRFstarV NMEA, report per GNSS used
  831. * counts in GPGGA and GLGGA.
  832. * session->gpsdata.satellites_visible = atoi(field[7]);
  833. */
  834. satellites_visible = atoi(field[7]);
  835. if (0 == merge_hhmmss(field[1], session)) {
  836. register_fractional_time(field[0], field[1], session);
  837. if (session->nmea.date.tm_year == 0)
  838. GPSD_LOG(LOG_WARN, &session->context->errout,
  839. "can't use GGA time until after ZDA or RMC"
  840. " has supplied a year.\n");
  841. else {
  842. mask |= TIME_SET;
  843. }
  844. }
  845. if (0 == do_lat_lon(&field[2], &session->newdata)) {
  846. session->newdata.mode = MODE_2D;
  847. mask |= LATLON_SET;
  848. if ('\0' != field[11][0]) {
  849. session->newdata.geoid_sep = safe_atof(field[11]);
  850. } else {
  851. session->newdata.geoid_sep = wgs84_separation(
  852. session->newdata.latitude, session->newdata.longitude);
  853. }
  854. /*
  855. * SiRF chipsets up to version 2.2 report a null altitude field.
  856. * See <http://www.sirf.com/Downloads/Technical/apnt0033.pdf>.
  857. * If we see this, force mode to 2D at most.
  858. */
  859. if ('\0' != field[9][0]) {
  860. /* altitude is MSL */
  861. session->newdata.altMSL = safe_atof(field[9]);
  862. /* Let gpsd_error_model() deal with altHAE */
  863. mask |= ALTITUDE_SET;
  864. /*
  865. * This is a bit dodgy. Technically we shouldn't set the mode
  866. * bit until we see GSA. But it may be later in the cycle,
  867. * some devices like the FV-18 don't send it by default, and
  868. * elsewhere in the code we want to be able to test for the
  869. * presence of a valid fix with mode > MODE_NO_FIX.
  870. *
  871. * Use satellites_visible as double check on MODE_3D
  872. */
  873. if (4 <= satellites_visible) {
  874. session->newdata.mode = MODE_3D;
  875. }
  876. }
  877. if (3 > satellites_visible) {
  878. session->newdata.mode = MODE_NO_FIX;
  879. }
  880. } else {
  881. session->newdata.mode = MODE_NO_FIX;
  882. }
  883. mask |= MODE_SET;
  884. if ('\0' != field[8][0]) {
  885. /* why not to newdata? */
  886. session->gpsdata.dop.hdop = safe_atof(field[8]);
  887. }
  888. /* get DGPS stuff */
  889. if ('\0' != field[13][0] &&
  890. '\0' != field[14][0]) {
  891. /* both, or neither */
  892. double age;
  893. int station;
  894. age = safe_atof(field[13]);
  895. station = atoi(field[14]);
  896. if (0.09 < age ||
  897. 0 < station) {
  898. /* ignore both zeros */
  899. session->newdata.dgps_age = age;
  900. session->newdata.dgps_station = station;
  901. }
  902. }
  903. GPSD_LOG(LOG_DATA, &session->context->errout,
  904. "GGA: hhmmss=%s lat=%.2f lon=%.2f altMSL=%.2f mode=%d status=%d\n",
  905. field[1],
  906. session->newdata.latitude,
  907. session->newdata.longitude,
  908. session->newdata.altMSL,
  909. session->newdata.mode,
  910. session->gpsdata.status);
  911. return mask;
  912. }
  913. static gps_mask_t processGST(int count, char *field[],
  914. struct gps_device_t *session)
  915. /* GST - GPS Pseudorange Noise Statistics */
  916. {
  917. /*
  918. * GST,hhmmss.ss,x,x,x,x,x,x,x,*hh
  919. * 1 UTC time of associated GGA fix
  920. * 2 Total RMS standard deviation of ranges inputs to the nav solution
  921. * 3 Standard deviation (meters) of semi-major axis of error ellipse
  922. * 4 Standard deviation (meters) of semi-minor axis of error ellipse
  923. * 5 Orientation of semi-major axis of error ellipse (true north degrees)
  924. * 6 Standard deviation (meters) of latitude error
  925. * 7 Standard deviation (meters) of longitude error
  926. * 8 Standard deviation (meters) of altitude error
  927. * 9 Checksum
  928. */
  929. struct tm date;
  930. timespec_t ts;
  931. int ret;
  932. char ts_buf[TIMESPEC_LEN];
  933. gps_mask_t mask = ONLINE_SET;
  934. if (0 > count) {
  935. return mask;
  936. }
  937. /* since it is NOT current time, do not register_fractional_time() */
  938. // compute start of today
  939. if (0 < session->nmea.date.tm_year) {
  940. // Do not bother if no current year
  941. memset(&date, 0, sizeof(date));
  942. date.tm_year = session->nmea.date.tm_year;
  943. date.tm_mon = session->nmea.date.tm_mon;
  944. date.tm_mday = session->nmea.date.tm_mday;
  945. /* note this is not full UTC, just HHMMSS.ss */
  946. /* this is not the current time,
  947. * it references another GPA of the same stamp. So do not set
  948. * any time stamps with it */
  949. ret = decode_hhmmss(&date, &ts.tv_nsec, field[1], session);
  950. } else {
  951. ret = 1;
  952. }
  953. if (0 == ret) {
  954. // convert to timespec_t , tv_nsec already set
  955. session->gpsdata.gst.utctime.tv_sec = mkgmtime(&date);
  956. session->gpsdata.gst.utctime.tv_nsec = ts.tv_nsec;
  957. } else {
  958. /* no idea of UTC time now */
  959. session->gpsdata.gst.utctime.tv_sec = 0;
  960. session->gpsdata.gst.utctime.tv_nsec = 0;
  961. }
  962. session->gpsdata.gst.rms_deviation = safe_atof(field[2]);
  963. session->gpsdata.gst.smajor_deviation = safe_atof(field[3]);
  964. session->gpsdata.gst.sminor_deviation = safe_atof(field[4]);
  965. session->gpsdata.gst.smajor_orientation = safe_atof(field[5]);
  966. session->gpsdata.gst.lat_err_deviation = safe_atof(field[6]);
  967. session->gpsdata.gst.lon_err_deviation = safe_atof(field[7]);
  968. session->gpsdata.gst.alt_err_deviation = safe_atof(field[8]);
  969. GPSD_LOG(LOG_DATA, &session->context->errout,
  970. "GST: utc = %s, rms = %.2f, maj = %.2f, min = %.2f,"
  971. " ori = %.2f, lat = %.2f, lon = %.2f, alt = %.2f\n",
  972. timespec_str(&session->gpsdata.gst.utctime, ts_buf,
  973. sizeof(ts_buf)),
  974. session->gpsdata.gst.rms_deviation,
  975. session->gpsdata.gst.smajor_deviation,
  976. session->gpsdata.gst.sminor_deviation,
  977. session->gpsdata.gst.smajor_orientation,
  978. session->gpsdata.gst.lat_err_deviation,
  979. session->gpsdata.gst.lon_err_deviation,
  980. session->gpsdata.gst.alt_err_deviation);
  981. mask = GST_SET | ONLINE_SET;
  982. return mask;
  983. }
  984. /* convert NMEA sigid to ublox sigid */
  985. static unsigned char nmea_sigid_to_ubx(unsigned char nmea_sigid)
  986. {
  987. unsigned char ubx_sigid = 0;
  988. switch (nmea_sigid) {
  989. default:
  990. /* FALLTHROUGH */
  991. case 0:
  992. /* missing, assume GPS L1 */
  993. ubx_sigid = 0;
  994. break;
  995. case 1:
  996. /* L1 */
  997. ubx_sigid = 0;
  998. break;
  999. case 2:
  1000. /* E5, could be 5 or 6. */
  1001. ubx_sigid = 5;
  1002. break;
  1003. case 3:
  1004. /* B2 or L2, could be 2 or 3. */
  1005. ubx_sigid = 2;
  1006. break;
  1007. case 5:
  1008. /* L2 */
  1009. ubx_sigid = 4;
  1010. break;
  1011. case 6:
  1012. /* L2CL */
  1013. ubx_sigid = 3;
  1014. break;
  1015. case 7:
  1016. /* E1, could be 0 or 1. */
  1017. ubx_sigid = 0;
  1018. break;
  1019. }
  1020. return ubx_sigid;
  1021. }
  1022. /* Deal with range-mapping attempts to use IDs 1-32 by Beidou, etc.
  1023. *
  1024. * See struct satellite_t in gps.h for ubx and nmea gnssid and svid mappings
  1025. *
  1026. * char *talker -- NMEA talker string
  1027. * int nmea_satnum -- NMEA (All ver) satellite number (kinda the PRN)
  1028. * int nmea_gnssid -- NMEA 4.10 gnssid, if known, otherwise zero
  1029. * unsigned char *ubx_gnssid -- returned u-blox gnssid
  1030. * unsigned char *ubx_svid -- returned u-blox gnssid
  1031. *
  1032. * Return the NMEA 2.x to 4.0 extended PRN
  1033. */
  1034. static int nmeaid_to_prn(char *talker, int nmea_satnum,
  1035. int nmea_gnssid,
  1036. unsigned char *ubx_gnssid,
  1037. unsigned char *ubx_svid)
  1038. {
  1039. /*
  1040. * According to https://github.com/mvglasow/satstat/wiki/NMEA-IDs
  1041. * and u-blox documentation.
  1042. * NMEA IDs can be roughly divided into the following ranges:
  1043. *
  1044. * 1..32: GPS
  1045. * 33..64: Various SBAS systems (EGNOS, WAAS, SDCM, GAGAN, MSAS)
  1046. * 65..96: GLONASS
  1047. * 152..158: Various SBAS systems (EGNOS, WAAS, SDCM, GAGAN, MSAS)
  1048. * 173..182: IMES
  1049. * 193..197: QZSS (undocumented u-blox goes to 199)
  1050. * 201..235: Beidou (not NMEA, not u-blox?)
  1051. * 301..336: Galileo
  1052. * 401..437: Beidou
  1053. * null: GLONASS unused
  1054. *
  1055. * The issue is what to do when GPSes from these different systems
  1056. * fight for IDs in the 1-32 range, as in this pair of Beidou sentences
  1057. *
  1058. * $BDGSV,2,1,07,01,00,000,45,02,13,089,35,03,00,000,37,04,00,000,42*6E
  1059. * $BDGSV,2,2,07,05,27,090,,13,19,016,,11,07,147,*5E
  1060. *
  1061. * Because the PRNs are only used for generating a satellite
  1062. * chart, mistakes here aren't dangerous. The code will record
  1063. * and use multiple sats with the same ID in one skyview; in
  1064. * effect, they're recorded by the order in which they occur
  1065. * rather than by PRN.
  1066. */
  1067. int nmea2_prn = nmea_satnum;
  1068. *ubx_gnssid = 0; /* default to ubx_gnssid is GPS */
  1069. *ubx_svid = 0; /* default to unnknown ubx_svid */
  1070. if (1 > nmea_satnum) {
  1071. /* uh, oh... */
  1072. nmea2_prn = 0;
  1073. } else if (0 < nmea_gnssid) {
  1074. /* this switch handles case where nmea_gnssid is known */
  1075. switch (nmea_gnssid) {
  1076. default:
  1077. /* x = IMES Not defined by NMEA 4.10 */
  1078. /* FALLTHROUGH */
  1079. case 0:
  1080. /* none given, ignore */
  1081. nmea2_prn = 0;
  1082. break;
  1083. case 1:
  1084. if (33 > nmea_satnum) {
  1085. /* 1 = GPS 1-32 */
  1086. *ubx_gnssid = 0;
  1087. *ubx_svid = nmea_satnum;
  1088. } else if (65 > nmea_satnum) {
  1089. /* 1 = SBAS 33-64 */
  1090. *ubx_gnssid = 1;
  1091. *ubx_svid = 87 + nmea_satnum;
  1092. } else if (152 > nmea_satnum) {
  1093. /* Huh? */
  1094. *ubx_gnssid = 0;
  1095. *ubx_svid = 0;
  1096. nmea2_prn = 0;
  1097. } else if (158 > nmea_satnum) {
  1098. /* 1 = SBAS 152-158 */
  1099. *ubx_gnssid = 1;
  1100. *ubx_svid = nmea_satnum;
  1101. } else if (193 > nmea_satnum) {
  1102. /* Huh? */
  1103. *ubx_gnssid = 0;
  1104. *ubx_svid = 0;
  1105. nmea2_prn = 0;
  1106. } else if (200 > nmea_satnum) {
  1107. /* 1 = QZSS 193-197 */
  1108. /* undocumented u-blox goes to 199 */
  1109. *ubx_gnssid = 3;
  1110. *ubx_svid = nmea_satnum - 192;
  1111. } else {
  1112. /* Huh? */
  1113. *ubx_gnssid = 0;
  1114. *ubx_svid = 0;
  1115. nmea2_prn = 0;
  1116. }
  1117. break;
  1118. case 2:
  1119. /* 2 = GLONASS 65-96, nul */
  1120. *ubx_gnssid = 6;
  1121. *ubx_svid = nmea_satnum;
  1122. break;
  1123. case 3:
  1124. /* 3 = Galileo 1-36 */
  1125. *ubx_gnssid = 2;
  1126. *ubx_svid = nmea_satnum;
  1127. nmea2_prn = 300 + nmea_satnum;
  1128. break;
  1129. case 4:
  1130. /* 4 - BeiDou 1-37 */
  1131. *ubx_gnssid = 3;
  1132. *ubx_svid = nmea_satnum;
  1133. nmea2_prn = 300 + nmea_satnum;
  1134. break;
  1135. }
  1136. /* left with NMEA 2.x to NMEA 4.0 satnums
  1137. * use talker ID to disambiguate */
  1138. } else if (32 >= nmea_satnum) {
  1139. *ubx_svid = nmea_satnum;
  1140. switch (talker[0]) {
  1141. case 'G':
  1142. if (talker[1] == 'A') {
  1143. /* Galileo */
  1144. nmea2_prn = 300 + nmea_satnum;
  1145. *ubx_gnssid = 2;
  1146. } else if (talker[1] == 'B') {
  1147. /* map Beidou IDs 1..37 to 401..437 */
  1148. *ubx_gnssid = 3;
  1149. nmea2_prn = 400 + nmea_satnum;
  1150. } else if (talker[1] == 'L') {
  1151. /* GLONASS GL doesn't seem to do this, better safe than sorry */
  1152. nmea2_prn = 64 + nmea_satnum;
  1153. *ubx_gnssid = 6;
  1154. } else if (talker[1] == 'N') {
  1155. /* all of them, but only GPS is 0 < PRN < 33 */
  1156. } else if (talker[1] == 'P') {
  1157. /* GPS,SBAS,QZSS, but only GPS is 0 < PRN < 33 */
  1158. } /* else ?? */
  1159. break;
  1160. case 'B':
  1161. if (talker[1] == 'D') {
  1162. /* map Beidou IDs */
  1163. nmea2_prn = 400 + nmea_satnum;
  1164. *ubx_gnssid = 3;
  1165. } /* else ?? */
  1166. break;
  1167. case 'P':
  1168. /* Quectel EC25 & EC21 use PQxxx for BeiDou */
  1169. if (talker[1] == 'Q') {
  1170. /* map Beidou IDs */
  1171. nmea2_prn = 400 + nmea_satnum;
  1172. *ubx_gnssid = 3;
  1173. } /* else ?? */
  1174. break;
  1175. case 'Q':
  1176. if (talker[1] == 'Z') {
  1177. /* QZSS */
  1178. nmea2_prn = 192 + nmea_satnum;
  1179. *ubx_gnssid = 5;
  1180. } /* else ? */
  1181. break;
  1182. default:
  1183. /* huh? */
  1184. break;
  1185. }
  1186. } else if (64 >= nmea_satnum) {
  1187. // NMEA-ID (33..64) to SBAS PRN 120-151.
  1188. /* SBAS */
  1189. *ubx_gnssid = 1;
  1190. *ubx_svid = 87 + nmea_satnum;
  1191. } else if (96 >= nmea_satnum) {
  1192. /* GLONASS 65..96 */
  1193. *ubx_gnssid = 6;
  1194. *ubx_svid = nmea_satnum - 64;
  1195. } else if (120 > nmea_satnum) {
  1196. /* Huh? */
  1197. *ubx_gnssid = 0;
  1198. *ubx_svid = 0;
  1199. nmea2_prn = 0;
  1200. } else if (158 >= nmea_satnum) {
  1201. /* SBAS 120..158 */
  1202. *ubx_gnssid = 1;
  1203. *ubx_svid = nmea_satnum;
  1204. } else if (173 > nmea_satnum) {
  1205. /* Huh? */
  1206. *ubx_gnssid = 0;
  1207. *ubx_svid = 0;
  1208. nmea2_prn = 0;
  1209. } else if (182 >= nmea_satnum) {
  1210. /* IMES 173..182 */
  1211. *ubx_gnssid = 4;
  1212. *ubx_svid = nmea_satnum - 172;
  1213. } else if (193 > nmea_satnum) {
  1214. /* Huh? */
  1215. *ubx_gnssid = 0;
  1216. *ubx_svid = 0;
  1217. nmea2_prn = 0;
  1218. } else if (197 >= nmea_satnum) {
  1219. /* QZSS 193..197 */
  1220. /* undocumented u-blox goes to 199 */
  1221. *ubx_gnssid = 5;
  1222. *ubx_svid = nmea_satnum - 192;
  1223. } else if (201 > nmea_satnum) {
  1224. /* Huh? */
  1225. *ubx_gnssid = 0;
  1226. *ubx_svid = 0;
  1227. nmea2_prn = 0;
  1228. } else if (237 >= nmea_satnum) {
  1229. /* BeiDou, non-standard, some SiRF put BeiDou 201-237 */
  1230. /* $GBGSV,2,2,05,209,07,033,*62 */
  1231. *ubx_gnssid = 3;
  1232. *ubx_svid = nmea_satnum - 200;
  1233. nmea2_prn += 200; /* move up to 400 where NMEA 2.x wants it. */
  1234. } else if (301 > nmea_satnum) {
  1235. /* Huh? */
  1236. *ubx_gnssid = 0;
  1237. *ubx_svid = 0;
  1238. nmea2_prn = 0;
  1239. } else if (356 >= nmea_satnum) {
  1240. /* Galileo 301..356 */
  1241. *ubx_gnssid = 2;
  1242. *ubx_svid = nmea_satnum - 300;
  1243. } else if (401 > nmea_satnum) {
  1244. /* Huh? */
  1245. *ubx_gnssid = 0;
  1246. *ubx_svid = 0;
  1247. nmea2_prn = 0;
  1248. } else if (437 >= nmea_satnum) {
  1249. /* BeiDou */
  1250. *ubx_gnssid = 3;
  1251. *ubx_svid = nmea_satnum - 400;
  1252. } else {
  1253. /* greater than 437 Huh? */
  1254. *ubx_gnssid = 0;
  1255. *ubx_svid = 0;
  1256. nmea2_prn = 0;
  1257. }
  1258. return nmea2_prn;
  1259. }
  1260. static gps_mask_t processGSA(int count, char *field[],
  1261. struct gps_device_t *session)
  1262. /* GPS DOP and Active Satellites */
  1263. {
  1264. #define GSA_TALKER field[0][1]
  1265. /*
  1266. * eg1. $GPGSA,A,3,,,,,,16,18,,22,24,,,3.6,2.1,2.2*3C
  1267. * eg2. $GPGSA,A,3,19,28,14,18,27,22,31,39,,,,,1.7,1.0,1.3*35
  1268. * NMEA 4.10: $GNGSA,A,3,13,12,22,19,08,21,,,,,,,1.05,0.64,0.83,4*0B
  1269. * 1 = Mode:
  1270. * M=Manual, forced to operate in 2D or 3D
  1271. * A=Automatic, 3D/2D
  1272. * 2 = Mode:
  1273. * 1=Fix not available,
  1274. * 2=2D,
  1275. * 3=3D
  1276. * 3-14 = PRNs of satellites used in position fix (null for unused fields)
  1277. * 15 = PDOP
  1278. * 16 = HDOP
  1279. * 17 = VDOP
  1280. * 18 - NMEA 4.1+ GNSS System ID, u-blox extended
  1281. * 1 = GPS L1C/A, L2CL, L2CM
  1282. * 2 = GLONASS L1 OF, L2 OF
  1283. * 3 = Galileo E1C, E1B, E5 bl, E5 bQ
  1284. * 4 = BeiDou B1I D1, B1I D2, B2I D1, B2I D12
  1285. *
  1286. * Not all documentation specifies the number of PRN fields, it
  1287. * may be variable. Most doc that specifies says 12 PRNs.
  1288. *
  1289. * The Navior-24 CH-4701 outputs 30 fields, 24 PRNs!
  1290. * GPGSA,A,3,27,23,13,07,25,,,,,,,,,,,,,,,,,,,,07.9,06.0,05.2
  1291. *
  1292. * The Skytraq S2525F8-BD-RTK output both GPGSA and BDGSA in the
  1293. * same cycle:
  1294. * $GPGSA,A,3,23,31,22,16,03,07,,,,,,,1.8,1.1,1.4*3E
  1295. * $BDGSA,A,3,214,,,,,,,,,,,,1.8,1.1,1.4*18
  1296. * These need to be combined like GPGSV and BDGSV
  1297. *
  1298. * Some GPS emit GNGSA. So far we have not seen a GPS emit GNGSA
  1299. * and then another flavor of xxGSA
  1300. *
  1301. * Some Skytraq will emit all GPS in one GNGSA, Then follow with
  1302. * another GNGSA with the BeiDou birds.
  1303. *
  1304. * SEANEXX, SiRFstarIV, and others also do it twice in one cycle:
  1305. * $GNGSA,A,3,31,26,21,,,,,,,,,,3.77,2.55,2.77*1A
  1306. * $GNGSA,A,3,75,86,87,,,,,,,,,,3.77,2.55,2.77*1C
  1307. * seems like the first is GNSS and the second GLONASS
  1308. *
  1309. * u-blox 9 outputs one per GNSS on each cycle. Note the
  1310. * extra last parameter which is NMEA gnssid:
  1311. * $GNGSA,A,3,13,16,21,15,10,29,27,20,,,,,1.05,0.64,0.83,1*03
  1312. * $GNGSA,A,3,82,66,81,,,,,,,,,,1.05,0.64,0.83,2*0C
  1313. * $GNGSA,A,3,07,12,33,,,,,,,,,,1.05,0.64,0.83,3*0A
  1314. * $GNGSA,A,3,13,12,22,19,08,21,,,,,,,1.05,0.64,0.83,4*0B
  1315. * Also note the NMEA 4.0 GLONASS PRN (82) in an NMEA 4.1
  1316. * sentence.
  1317. */
  1318. gps_mask_t mask = ONLINE_SET;
  1319. char last_last_gsa_talker = session->nmea.last_gsa_talker;
  1320. int nmea_gnssid = 0;
  1321. int nmea_sigid = 0;
  1322. int ubx_sigid = 0;
  1323. /*
  1324. * One chipset called the i.Trek M3 issues GPGSA lines that look like
  1325. * this: "$GPGSA,A,1,,,,*32" when it has no fix. This is broken
  1326. * in at least two ways: it's got the wrong number of fields, and
  1327. * it claims to be a valid sentence (A flag) when it isn't.
  1328. * Alarmingly, it's possible this error may be generic to SiRFstarIII.
  1329. */
  1330. if (18 > count) {
  1331. GPSD_LOG(LOG_DATA, &session->context->errout,
  1332. "xxGSA: malformed, setting ONLINE_SET only.\n");
  1333. mask = ONLINE_SET;
  1334. } else if (session->nmea.latch_mode) {
  1335. /* last GGA had a non-advancing timestamp; don't trust this GSA */
  1336. mask = ONLINE_SET;
  1337. GPSD_LOG(LOG_DATA, &session->context->errout,
  1338. "xxGSA: non-advancing timestamp\n");
  1339. } else {
  1340. int i;
  1341. session->newdata.mode = atoi(field[2]);
  1342. /*
  1343. * The first arm of this conditional ignores dead-reckoning
  1344. * fixes from an Antaris chipset. which returns E in field 2
  1345. * for a dead-reckoning estimate. Fix by Andreas Stricker.
  1346. */
  1347. if ('E' == field[2][0])
  1348. mask = ONLINE_SET;
  1349. else
  1350. mask = MODE_SET;
  1351. GPSD_LOG(LOG_PROG, &session->context->errout,
  1352. "xxGSA sets mode %d\n", session->newdata.mode);
  1353. if (19 < count ) {
  1354. GPSD_LOG(LOG_WARN, &session->context->errout,
  1355. "xxGSA: count %d too long!\n", count);
  1356. } else {
  1357. /* Just ignore the last fields of the Navior CH-4701 */
  1358. if (field[15][0] != '\0')
  1359. session->gpsdata.dop.pdop = safe_atof(field[15]);
  1360. if (field[16][0] != '\0')
  1361. session->gpsdata.dop.hdop = safe_atof(field[16]);
  1362. if (field[17][0] != '\0')
  1363. session->gpsdata.dop.vdop = safe_atof(field[17]);
  1364. if (19 == count && '\0' != field[18][0]) {
  1365. /* get the NMEA 4.10 sigid */
  1366. nmea_sigid = atoi(field[18]);
  1367. /* FIXME: ubx_sigid not used yet */
  1368. ubx_sigid = nmea_sigid_to_ubx(nmea_sigid);
  1369. }
  1370. }
  1371. /*
  1372. * might have gone from GPGSA to GLGSA/BDGSA
  1373. * or GNGSA to GNGSA
  1374. * in which case accumulate
  1375. */
  1376. if ( '\0' == session->nmea.last_gsa_talker
  1377. || (GSA_TALKER == session->nmea.last_gsa_talker
  1378. && 'N' != GSA_TALKER) ) {
  1379. session->gpsdata.satellites_used = 0;
  1380. memset(session->nmea.sats_used, 0, sizeof(session->nmea.sats_used));
  1381. GPSD_LOG(LOG_DATA, &session->context->errout,
  1382. "xxGSA: clear sats_used\n");
  1383. }
  1384. session->nmea.last_gsa_talker = GSA_TALKER;
  1385. if ((session->nmea.last_gsa_talker == 'B') ||
  1386. (session->nmea.last_gsa_talker == 'D') ||
  1387. (session->nmea.last_gsa_talker == 'Q'))
  1388. /* Quectel EC25 & EC21 use PQGSA for BeiDou */
  1389. session->nmea.seen_bdgsa = true;
  1390. else if (session->nmea.last_gsa_talker == 'L')
  1391. session->nmea.seen_glgsa = true;
  1392. else if (session->nmea.last_gsa_talker == 'N')
  1393. session->nmea.seen_gngsa = true;
  1394. else if (session->nmea.last_gsa_talker == 'A')
  1395. session->nmea.seen_gagsa = true;
  1396. /* the magic 6 here counts the tag, two mode fields, and DOP fields */
  1397. for (i = 0; i < count - 6; i++) {
  1398. int prn;
  1399. int nmea_satnum;
  1400. unsigned char ubx_gnssid; /* UNUSED */
  1401. unsigned char ubx_svid; /* UNUSED */
  1402. /* skip empty fields, otherwise empty becomes prn=200 */
  1403. nmea_satnum = atoi(field[i + 3]);
  1404. if (1 > nmea_satnum) {
  1405. continue;
  1406. }
  1407. prn = nmeaid_to_prn(field[0], nmea_satnum, nmea_gnssid,
  1408. &ubx_gnssid, &ubx_svid);
  1409. #ifdef __UNUSED__
  1410. /* debug */
  1411. GPSD_LOG(LOG_ERROR, &session->context->errout,
  1412. "%s nmeaid_to_prn: nmea_gnssid %d nmea_satnum %d "
  1413. "ubx_gnssid %d ubx_svid %d nmea2_prn %d\n",
  1414. field[0],
  1415. nmea_gnssid, nmea_satnum, ubx_gnssid, ubx_svid, prn);
  1416. GPSD_LOG(LOG_ERROR, &session->context->errout,
  1417. "%s count %d\n", field[0], count);
  1418. #endif /* __UNUSED__ */
  1419. if (prn > 0) {
  1420. /* check first BEFORE over-writing memory */
  1421. if (MAXCHANNELS <= session->gpsdata.satellites_used) {
  1422. /* This should never happen as xxGSA is limited to 12,
  1423. * except for the Navior-24 CH-4701.
  1424. * But it could happen with multiple GSA per cycle */
  1425. break;
  1426. }
  1427. session->nmea.sats_used[session->gpsdata.satellites_used++] =
  1428. (unsigned short)prn;
  1429. }
  1430. }
  1431. mask |= DOP_SET | USED_IS;
  1432. GPSD_LOG(LOG_DATA, &session->context->errout,
  1433. "xxGSA: mode=%d used=%d pdop=%.2f hdop=%.2f vdop=%.2f "
  1434. "ubx_sigid %d\n",
  1435. session->newdata.mode,
  1436. session->gpsdata.satellites_used,
  1437. session->gpsdata.dop.pdop,
  1438. session->gpsdata.dop.hdop,
  1439. session->gpsdata.dop.vdop, ubx_sigid);
  1440. }
  1441. /* assumes GLGSA or BDGSA, if present, is emitted directly
  1442. * after the GPGSA*/
  1443. if ((session->nmea.seen_glgsa || session->nmea.seen_bdgsa ||
  1444. session->nmea.seen_gagsa) && GSA_TALKER == 'P') {
  1445. mask = ONLINE_SET;
  1446. /* first of two GNGSA */
  1447. /* if mode == 1 some GPS only output 1 GNGSA, so ship mode always */
  1448. } else if ( 'N' != last_last_gsa_talker && 'N' == GSA_TALKER) {
  1449. mask = ONLINE_SET | MODE_SET;
  1450. }
  1451. /* cast for 32/64 compatibility */
  1452. GPSD_LOG(LOG_PROG, &session->context->errout,
  1453. "xxGSA: mask %#llx\n", (long long unsigned)mask);
  1454. return mask;
  1455. #undef GSA_TALKER
  1456. }
  1457. /* xxGSV - GPS Satellites in View */
  1458. static gps_mask_t processGSV(int count, char *field[],
  1459. struct gps_device_t *session)
  1460. {
  1461. #define GSV_TALKER field[0][1]
  1462. /*
  1463. * GSV,2,1,08,01,40,083,46,02,17,308,41,12,07,344,39,14,22,228,45*75
  1464. * 1) 2 Number of sentences for full data
  1465. * 2) 1 Sentence 1 of 2
  1466. * 3) 08 Total number of satellites in view
  1467. * 4) 01 Satellite PRN number
  1468. * 5) 40 Elevation, degrees
  1469. * 6) 083 Azimuth, degrees
  1470. * 7) 46 Signal-to-noise ratio in decibels
  1471. * <repeat for up to 4 satellites per sentence>
  1472. * ) NMEA 4.1 signalId
  1473. * ) checksum
  1474. *
  1475. * NMEA 4.1+:
  1476. * $GAGSV,3,1,09,02,00,179,,04,09,321,,07,11,134,11,11,10,227,,7*7F
  1477. * after the satellite block, before the checksum, new field:
  1478. * 7 NMEA Signal ID
  1479. * 1 = GPS L1C/A, BeiDou B1I D1, BeiDou B1I D2, GLONASS L1 OF
  1480. * 2 = Galileo E5 bl, E5 bQ
  1481. * 3 = BeiDou B2I D1, B2I D2
  1482. * 5 = GPS L2 CM
  1483. * 6 = GPS L2 CL
  1484. * 7 = Galileo E1C, E1B
  1485. *
  1486. * Can occur with talker IDs:
  1487. * BD (Beidou),
  1488. * GA (Galileo),
  1489. * GB (Beidou),
  1490. * GL (GLONASS),
  1491. * GN (GLONASS, any combination GNSS),
  1492. * GP (GPS, SBAS, QZSS),
  1493. * QZ (QZSS).
  1494. *
  1495. * As of April 2019:
  1496. * no gpsd regressions have GNGSV
  1497. * every xxGSV cycle starts with GPGSV
  1498. * xxGSV cycles may be spread over several xxRMC cycles
  1499. *
  1500. * GL may be (incorrectly) used when GSVs are mixed containing
  1501. * GLONASS, GN may be (incorrectly) used when GSVs contain GLONASS
  1502. * only. Usage is inconsistent.
  1503. *
  1504. * In the GLONASS version sat IDs run from 65-96 (NMEA0183
  1505. * standardizes this). At least two GPSes, the BU-353 GLONASS and
  1506. * the u-blox NEO-M8N, emit a GPGSV set followed by a GLGSV set.
  1507. * We have also seen two GPSes, the Skytraq S2525F8-BD-RTK and a
  1508. * SiRF-IV variant, that emit GPGSV followed by BDGSV. We need to
  1509. * combine these.
  1510. *
  1511. * The following shows how the Skytraq S2525F8-BD-RTK output both
  1512. * GPGSV and BDGSV in the same cycle:
  1513. * $GPGSV,4,1,13,23,66,310,29,03,65,186,33,26,43,081,27,16,41,124,38*78
  1514. * $GPGSV,4,2,13,51,37,160,38,04,37,066,25,09,34,291,07,22,26,156,37*77
  1515. * $GPGSV,4,3,13,06,19,301,,31,17,052,20,193,11,307,,07,11,232,27*4F
  1516. * $GPGSV,4,4,13,01,03,202,30*4A
  1517. * $BDGSV,1,1,02,214,55,153,40,208,01,299,*67
  1518. *
  1519. * The driver automatically adapts to either case, but it takes until the
  1520. * second cycle (usually 10 seconds from device connect) for it to
  1521. * learn to expect BSDGV or GLGSV.
  1522. *
  1523. * Some GPS (Garmin 17N) spread the xxGSV over several cycles. So
  1524. * cycles, or cycle time, can not be used to determine start of
  1525. * xxGSV cycle.
  1526. *
  1527. * NMEA 4.1 adds a signal-ID field just before the checksum. First
  1528. * seen in May 2015 on a u-blox M8. It can output 2 sets of GPGSV
  1529. * in one cycle, one for L1C and the other for L2C.
  1530. */
  1531. int n, fldnum;
  1532. unsigned char nmea_sigid = 0;
  1533. int nmea_gnssid = 0;
  1534. unsigned char ubx_sigid = 0;
  1535. if (count <= 3) {
  1536. GPSD_LOG(LOG_WARN, &session->context->errout,
  1537. "malformed xxGSV - fieldcount %d <= 3\n",
  1538. count);
  1539. gpsd_zero_satellites(&session->gpsdata);
  1540. return ONLINE_SET;
  1541. }
  1542. GPSD_LOG(LOG_PROG, &session->context->errout,
  1543. "x%cGSV: part %s of %s, last_gsv_talker '%#x' "
  1544. " last_gsv_sigid %u\n",
  1545. GSV_TALKER, field[2], field[1],
  1546. session->nmea.last_gsv_talker,
  1547. session->nmea.last_gsv_sigid);
  1548. /*
  1549. * This check used to be !=0, but we have loosen it a little to let by
  1550. * NMEA 4.1 GSVs with an extra signal-ID field at the end.
  1551. */
  1552. switch (count % 4) {
  1553. case 0:
  1554. /* normal, pre-NMEA 4.10 */
  1555. break;
  1556. case 1:
  1557. /* NMEA 4.10, get the signal ID */
  1558. nmea_sigid = atoi(field[count - 1]);
  1559. ubx_sigid = nmea_sigid_to_ubx(nmea_sigid);
  1560. break;
  1561. default:
  1562. /* bad count */
  1563. GPSD_LOG(LOG_WARN, &session->context->errout,
  1564. "malformed GPGSV - fieldcount %d %% 4 != 0\n", count);
  1565. gpsd_zero_satellites(&session->gpsdata);
  1566. return ONLINE_SET;
  1567. }
  1568. session->nmea.await = atoi(field[1]);
  1569. if ((session->nmea.part = atoi(field[2])) < 1) {
  1570. GPSD_LOG(LOG_WARN, &session->context->errout,
  1571. "malformed GPGSV - bad part\n");
  1572. gpsd_zero_satellites(&session->gpsdata);
  1573. return ONLINE_SET;
  1574. }
  1575. if (session->nmea.part == 1) {
  1576. /*
  1577. * might have gone from GPGSV to GLGSV/BDGSV/QZGSV,
  1578. * in which case accumulate
  1579. *
  1580. * NMEA 4.1 might have gone from GPGVS,sigid=x to GPGSV,sigid=y
  1581. *
  1582. * session->nmea.last_gsv_talker is zero at cycle start
  1583. */
  1584. if (session->nmea.last_gsv_talker == '\0' ||
  1585. ('P' == GSV_TALKER &&
  1586. 0 == ubx_sigid)) {
  1587. GPSD_LOG(LOG_PROG, &session->context->errout,
  1588. "x%cGSV: new part %d, last_gsv_talker '%#x', zeroing\n",
  1589. GSV_TALKER,
  1590. session->nmea.part,
  1591. session->nmea.last_gsv_talker);
  1592. gpsd_zero_satellites(&session->gpsdata);
  1593. }
  1594. session->nmea.last_gsv_talker = GSV_TALKER;
  1595. session->nmea.last_gsv_sigid = ubx_sigid; /* UNUSED */
  1596. switch (GSV_TALKER) {
  1597. case 'A':
  1598. session->nmea.seen_gagsv = true;
  1599. break;
  1600. case 'B':
  1601. /* FALLTHROUGH */
  1602. case 'D':
  1603. /* FALLTHROUGH */
  1604. case 'Q':
  1605. /* Quectel EC25 & EC21 use PQGSA for BeiDou */
  1606. session->nmea.seen_bdgsv = true;
  1607. break;
  1608. case 'L':
  1609. session->nmea.seen_glgsv = true;
  1610. break;
  1611. case 'P':
  1612. session->nmea.seen_gpgsv = true;
  1613. break;
  1614. case 'Z':
  1615. session->nmea.seen_qzss = true;
  1616. break;
  1617. default:
  1618. /* uh, what? */
  1619. break;
  1620. }
  1621. }
  1622. for (fldnum = 4; fldnum < count / 4 * 4;) {
  1623. struct satellite_t *sp;
  1624. int nmea_svid;
  1625. if (session->gpsdata.satellites_visible >= MAXCHANNELS) {
  1626. GPSD_LOG(LOG_ERROR, &session->context->errout,
  1627. "xxGSV: internal error - too many satellites [%d]!\n",
  1628. session->gpsdata.satellites_visible);
  1629. gpsd_zero_satellites(&session->gpsdata);
  1630. break;
  1631. }
  1632. sp = &session->gpsdata.skyview[session->gpsdata.satellites_visible];
  1633. nmea_svid = atoi(field[fldnum++]);
  1634. if (0 == nmea_svid) {
  1635. /* skip bogus fields */
  1636. continue;
  1637. }
  1638. /* FIXME: this ignores possible NMEA 4.1 Signal ID hint */
  1639. sp->PRN = (short)nmeaid_to_prn(field[0], nmea_svid, nmea_gnssid,
  1640. &sp->gnssid, &sp->svid);
  1641. #ifdef __UNUSED__
  1642. {
  1643. /* debug */
  1644. char ts_buf[TIMESPEC_LEN];
  1645. GPSD_LOG(LOG_ERROR, &session->context->errout,
  1646. "%s nmeaid_to_prn: nmea_gnssid %d nmea_satnum %d "
  1647. "ubx_gnssid %d ubx_svid %d nmea2_prn %d\n", field[0],
  1648. nmea_gnssid, nmea_svid, sp->gnssid, sp->svid, sp->PRN);
  1649. }
  1650. #endif /* __UNUSED__ */
  1651. sp->elevation = (double)atoi(field[fldnum++]);
  1652. sp->azimuth = (double)atoi(field[fldnum++]);
  1653. sp->ss = (double)atoi(field[fldnum++]);
  1654. sp->used = false;
  1655. sp->sigid = ubx_sigid;
  1656. /* sadly NMEA 4.1 does not tell us which sigid (L1, L2) is
  1657. * used. So if the ss is zero, do not mark used */
  1658. if (0 < sp->PRN && 0 < sp->ss) {
  1659. for (n = 0; n < MAXCHANNELS; n++)
  1660. if (session->nmea.sats_used[n] == (unsigned short)sp->PRN) {
  1661. sp->used = true;
  1662. break;
  1663. }
  1664. }
  1665. /*
  1666. * Incrementing this unconditionally falls afoul of chipsets like
  1667. * the Motorola Oncore GT+ that emit empty fields at the end of the
  1668. * last sentence in a GPGSV set if the number of satellites is not
  1669. * a multiple of 4.
  1670. */
  1671. session->gpsdata.satellites_visible++;
  1672. }
  1673. #if __UNUSED
  1674. /* debug code */
  1675. GPSD_LOG(LOG_ERROR, &session->context->errout,
  1676. "x%cGSV: vis %d gagsv %d bdgsv %d glgsv %d qzss %d\n",
  1677. GSV_TALKER,
  1678. session->gpsdata.satellites_visible,
  1679. session->nmea.seen_gagsv,
  1680. session->nmea.seen_bdgsv,
  1681. session->nmea.seen_glgsv,
  1682. session->nmea.seen_qzss);
  1683. #endif
  1684. /*
  1685. * Alas, we can't sanity check field counts when there are multiple sat
  1686. * pictures, because the visible member counts *all* satellites - you
  1687. * get a bad result on the second and later SV spans. Note, this code
  1688. * assumes that if any of the special sat pics occur they come right
  1689. * after a stock GPGSV one.
  1690. *
  1691. * FIXME: Add per-talker totals so we can do this check properly.
  1692. */
  1693. if (!(session->nmea.seen_glgsv || session->nmea.seen_bdgsv
  1694. || session->nmea.seen_qzss || session->nmea.seen_gagsv))
  1695. if (session->nmea.part == session->nmea.await
  1696. && atoi(field[3]) != session->gpsdata.satellites_visible)
  1697. GPSD_LOG(LOG_WARN, &session->context->errout,
  1698. "GPGSV field 3 value of %d != actual count %d\n",
  1699. atoi(field[3]), session->gpsdata.satellites_visible);
  1700. /* not valid data until we've seen a complete set of parts */
  1701. if (session->nmea.part < session->nmea.await) {
  1702. GPSD_LOG(LOG_PROG, &session->context->errout,
  1703. "xxGSV: Partial satellite data (%d of %d).\n",
  1704. session->nmea.part, session->nmea.await);
  1705. return ONLINE_SET;
  1706. }
  1707. /*
  1708. * This sanity check catches an odd behavior of SiRFstarII receivers.
  1709. * When they can't see any satellites at all (like, inside a
  1710. * building) they sometimes cough up a hairball in the form of a
  1711. * GSV packet with all the azimuth entries 0 (but nonzero
  1712. * elevations). This behavior was observed under SiRF firmware
  1713. * revision 231.000.000_A2.
  1714. */
  1715. for (n = 0; n < session->gpsdata.satellites_visible; n++)
  1716. if (session->gpsdata.skyview[n].azimuth != 0)
  1717. goto sane;
  1718. GPSD_LOG(LOG_WARN, &session->context->errout,
  1719. "xxGSV: Satellite data no good (%d of %d).\n",
  1720. session->nmea.part, session->nmea.await);
  1721. gpsd_zero_satellites(&session->gpsdata);
  1722. return ONLINE_SET;
  1723. sane:
  1724. session->gpsdata.skyview_time.tv_sec = 0;
  1725. session->gpsdata.skyview_time.tv_nsec = 0;
  1726. GPSD_LOG(LOG_DATA, &session->context->errout,
  1727. "xxGSV: Satellite data OK (%d of %d).\n",
  1728. session->nmea.part, session->nmea.await);
  1729. /* assumes GLGSV or BDGSV group, if present, is emitted after the GPGSV */
  1730. if ((session->nmea.seen_glgsv || session->nmea.seen_bdgsv
  1731. || session->nmea.seen_qzss || session->nmea.seen_gagsv)
  1732. && GSV_TALKER == 'P')
  1733. return ONLINE_SET;
  1734. #if __UNUSED
  1735. /* debug code */
  1736. GPSD_LOG(LOG_ERROR, &session->context->errout,
  1737. "x%cGSV: set skyview_time %s frac_time %.2f\n", GSV_TALKER,
  1738. timespec_str(&session->gpsdata.skyview_time, ts_buf, sizeof(ts_buf)),
  1739. session->nmea.this_frac_time);
  1740. #endif
  1741. /* clear computed DOPs so they get recomputed. */
  1742. /* FIXME: this kills GPS reported dops... */
  1743. session->gpsdata.dop.xdop = NAN;
  1744. session->gpsdata.dop.ydop = NAN;
  1745. session->gpsdata.dop.tdop = NAN;
  1746. session->gpsdata.dop.gdop = NAN;
  1747. return SATELLITE_SET;
  1748. #undef GSV_TALKER
  1749. }
  1750. /* Garmin Estimated Position Error */
  1751. static gps_mask_t processPGRME(int c UNUSED, char *field[],
  1752. struct gps_device_t *session)
  1753. {
  1754. /*
  1755. * $PGRME,15.0,M,45.0,M,25.0,M*22
  1756. * 1 = horizontal error estimate
  1757. * 2 = units
  1758. * 3 = vertical error estimate
  1759. * 4 = units
  1760. * 5 = spherical error estimate
  1761. * 6 = units
  1762. * *
  1763. * * Garmin won't say, but the general belief is that these are 50% CEP.
  1764. * * We follow the advice at <http://gpsinformation.net/main/errors.htm>.
  1765. * * If this assumption changes here, it should also change in garmin.c
  1766. * * where we scale error estimates from Garmin binary packets, and
  1767. * * in libgpsd_core.c where we generate $PGRME.
  1768. */
  1769. gps_mask_t mask = ONLINE_SET;
  1770. if ('M' != field[2][0] ||
  1771. 'M' != field[4][0] ||
  1772. 'M' != field[6][0]) {
  1773. mask = ONLINE_SET;
  1774. } else {
  1775. session->newdata.epx = session->newdata.epy =
  1776. safe_atof(field[1]) * (1 / sqrt(2))
  1777. * (GPSD_CONFIDENCE / CEP50_SIGMA);
  1778. session->newdata.epv =
  1779. safe_atof(field[3]) * (GPSD_CONFIDENCE / CEP50_SIGMA);
  1780. session->newdata.sep =
  1781. safe_atof(field[5]) * (GPSD_CONFIDENCE / CEP50_SIGMA);
  1782. mask = HERR_SET | VERR_SET | PERR_IS;
  1783. }
  1784. GPSD_LOG(LOG_DATA, &session->context->errout,
  1785. "PGRME: epx=%.2f epy=%.2f sep=%.2f\n",
  1786. session->newdata.epx,
  1787. session->newdata.epy,
  1788. session->newdata.sep);
  1789. return mask;
  1790. }
  1791. /* Garmin GPS Fix Data Sentence
  1792. *
  1793. * FIXME: seems to happen after cycle ender, so little happens...
  1794. */
  1795. static gps_mask_t processPGRMF(int c UNUSED, char *field[],
  1796. struct gps_device_t *session)
  1797. {
  1798. /*
  1799. * $PGRMF,290,293895,160305,093802,13,5213.1439,N,02100.6511,E,A,2,0,226,2,1*11
  1800. *
  1801. * 1 = GPS week
  1802. * 2 = GPS seconds
  1803. * 3 = UTC Date ddmmyy
  1804. * 4 = UTC time hhmmss
  1805. * 5 = GPS leap seconds
  1806. * 6 = Latitude ddmm.mmmm
  1807. * 7 = N or S
  1808. * 8 = Longitude dddmm.mmmm
  1809. * 9 = E or W
  1810. * 10 = Mode, M = Manual, A = Automatic
  1811. * 11 = Fix type, 0 = No fix, 2 = 2D fix, 2 = 3D fix
  1812. * 12 = Ground Speed, 0 to 1151 km/hr
  1813. * 13 = Course over ground, 0 to 359 degrees true
  1814. * 14 = pdop, 0 to 9
  1815. * 15 = dop, 0 to 9
  1816. */
  1817. gps_mask_t mask = ONLINE_SET;
  1818. unsigned short week = 0;
  1819. time_t tow = 0;
  1820. timespec_t ts_tow = {0, 0};
  1821. /* Some garmin fail due to GPS Week Roll Over
  1822. * Ignore their UTC date/time, use their GPS week, GPS tow and
  1823. * leap seconds to decide the correct time */
  1824. if (isdigit((int)field[5][0])) {
  1825. session->context->leap_seconds = atoi(field[5]);
  1826. session->context->valid = LEAP_SECOND_VALID;
  1827. }
  1828. if (isdigit((int)field[1][0]) &&
  1829. isdigit((int)field[2][0]) &&
  1830. 0 < session->context->leap_seconds) {
  1831. // have GPS week, tow and leap second
  1832. week = atol(field[1]);
  1833. ts_tow.tv_sec = tow = atol(field[2]);
  1834. ts_tow.tv_nsec = 0;
  1835. session->newdata.time = gpsd_gpstime_resolv(session, week, ts_tow);
  1836. mask |= TIME_SET;
  1837. // (long long) cast for 32/64 bit compat
  1838. GPSD_LOG(LOG_SPIN, &session->context->errout,
  1839. "PGRMF gps time %lld\n",
  1840. (long long)session->newdata.time.tv_sec);
  1841. } else if (0 == merge_hhmmss(field[4], session) &&
  1842. 0 == merge_ddmmyy(field[3], session)) {
  1843. // fall back to UTC if we need and can
  1844. // (long long) cast for 32/64 bit compat
  1845. GPSD_LOG(LOG_SPIN, &session->context->errout,
  1846. "PGRMF gps time %lld\n",
  1847. (long long)session->newdata.time.tv_sec);
  1848. mask |= TIME_SET;
  1849. }
  1850. if ('A' != field[10][0]) {
  1851. /* Huh? */
  1852. return mask;
  1853. }
  1854. if (0 == do_lat_lon(&field[6], &session->newdata)) {
  1855. mask |= LATLON_SET;
  1856. }
  1857. switch (field[11][0]) {
  1858. default:
  1859. /* Huh? */
  1860. break;
  1861. case '0':
  1862. session->newdata.mode = MODE_NO_FIX;
  1863. mask |= MODE_SET;
  1864. break;
  1865. case '1':
  1866. session->newdata.mode = MODE_2D;
  1867. mask |= MODE_SET;
  1868. break;
  1869. case '2':
  1870. session->newdata.mode = MODE_3D;
  1871. mask |= MODE_SET;
  1872. break;
  1873. }
  1874. session->newdata.speed = safe_atof(field[12]) / MPS_TO_KPH;
  1875. session->newdata.track = safe_atof(field[13]);
  1876. mask |= SPEED_SET | TRACK_SET;
  1877. session->gpsdata.dop.pdop = safe_atof(field[14]);
  1878. session->gpsdata.dop.tdop = safe_atof(field[15]);
  1879. mask |= DOP_SET;
  1880. GPSD_LOG(LOG_DATA, &session->context->errout,
  1881. "PGRMF: pdop %.1f tdop %.1f \n",
  1882. session->gpsdata.dop.pdop,
  1883. session->gpsdata.dop.tdop);
  1884. return mask;
  1885. }
  1886. /* Garmin Map Datum
  1887. *
  1888. * FIXME: seems to happen after cycle ender, so nothing happens...
  1889. */
  1890. static gps_mask_t processPGRMM(int c UNUSED, char *field[],
  1891. struct gps_device_t *session)
  1892. {
  1893. /*
  1894. * $PGRMM,NAD83*29
  1895. * 1 = Map Datum
  1896. */
  1897. gps_mask_t mask = ONLINE_SET;
  1898. if ('\0' != field[1][0]) {
  1899. strlcpy(session->newdata.datum, field[1],
  1900. sizeof(session->newdata.datum));
  1901. }
  1902. GPSD_LOG(LOG_DATA, &session->context->errout,
  1903. "PGRMM: datum=%.40s\n",
  1904. session->newdata.datum);
  1905. return mask;
  1906. }
  1907. /* Garmin Altitude Information */
  1908. static gps_mask_t processPGRMZ(int c UNUSED, char *field[],
  1909. struct gps_device_t *session)
  1910. {
  1911. /*
  1912. * $PGRMZ,246,f,3*1B
  1913. * 1 = Altitude (probably MSL) in feet
  1914. * 2 = f (feet)
  1915. * 3 = Mode
  1916. * 1 = No Fix
  1917. * 2 = 2D Fix
  1918. * 3 = 3D Fix
  1919. *
  1920. * From: Garmin Proprietary NMEA 0183 Sentences
  1921. * technical Specifications
  1922. * 190-00684-00, Revision C December 2008
  1923. */
  1924. gps_mask_t mask = ONLINE_SET;
  1925. if ('f' == field[2][0] &&
  1926. 0 < strlen(field[1])) {
  1927. /* have a GPS altitude, must be 3D */
  1928. /* seems to be altMSL. regressions show this matches GPGGA MSL */
  1929. session->newdata.altMSL = atoi(field[1]) / METERS_TO_FEET;
  1930. mask |= (ALTITUDE_SET);
  1931. }
  1932. switch (field[3][0]) {
  1933. default:
  1934. /* Huh? */
  1935. break;
  1936. case '1':
  1937. session->newdata.mode = MODE_NO_FIX;
  1938. mask |= MODE_SET;
  1939. break;
  1940. case '2':
  1941. session->newdata.mode = MODE_2D;
  1942. mask |= MODE_SET;
  1943. break;
  1944. case '3':
  1945. session->newdata.mode = MODE_3D;
  1946. mask |= MODE_SET;
  1947. break;
  1948. }
  1949. GPSD_LOG(LOG_DATA, &session->context->errout,
  1950. "PGRMZ: altMSL %.2f mode %d\n",
  1951. session->newdata.altMSL,
  1952. session->newdata.mode);
  1953. return mask;
  1954. }
  1955. /* Magellan Status */
  1956. static gps_mask_t processPMGNST(int c UNUSED, char *field[],
  1957. struct gps_device_t *session)
  1958. {
  1959. /*
  1960. * $PMGNST,01.75,3,T,816,11.1,-00496,00*43
  1961. * 1 = Firmware version number
  1962. * 2 = Mode (1 = no fix, 2 = 2D fix, 3 = 3D fix)
  1963. * 3 = T if we have a fix
  1964. * 4 = battery percentage left in tenths of a percent
  1965. * 5 = time left on the GPS battery in hours
  1966. * 6 = numbers change (freq. compensation?)
  1967. * 7 = PRN number receiving current focus
  1968. */
  1969. gps_mask_t mask = ONLINE_SET;
  1970. int newmode = atoi(field[3]);
  1971. if ('T' == field[4][0]) {
  1972. switch(newmode) {
  1973. default:
  1974. session->newdata.mode = MODE_NO_FIX;
  1975. break;
  1976. case 2:
  1977. session->newdata.mode = MODE_2D;
  1978. break;
  1979. case 3:
  1980. session->newdata.mode = MODE_3D;
  1981. break;
  1982. }
  1983. } else {
  1984. /* Can report 3D fix, but 'F' for no fix */
  1985. session->newdata.mode = MODE_NO_FIX;
  1986. }
  1987. mask |= MODE_SET;
  1988. GPSD_LOG(LOG_DATA, &session->context->errout,
  1989. "PMGNST: mode: %d\n",
  1990. session->newdata.mode);
  1991. return mask;
  1992. }
  1993. /* SiRF Estimated Position Errors */
  1994. static gps_mask_t processPSRFEPE(int c UNUSED, char *field[],
  1995. struct gps_device_t *session)
  1996. {
  1997. /*
  1998. * $PSRFEPE,100542.000,A,0.7,6.82,10.69,0.0,180.0*24
  1999. * 1 = UTC Time hhmmss.sss
  2000. * 2 = Status. A = Valid, V = Data not valid
  2001. * 3 = HDOP
  2002. * 4 = EHPE meters (Estimated Horizontal Position Error)
  2003. * 5 = EVPE meters (Estimated Vertical Position Error)
  2004. * 6 = EHVE meters (Estimated Speed Over Ground/Velocity Error)
  2005. * 7 = EHE degrees (Estimated Heading Error)
  2006. *
  2007. * SiRF won't say if these are 1-sigma or what...
  2008. */
  2009. gps_mask_t mask = STATUS_SET;
  2010. /* get time/ valid or not */
  2011. if ('\0' != field[1][0]) {
  2012. if (0 == merge_hhmmss(field[1], session)) {
  2013. register_fractional_time(field[0], field[1], session);
  2014. if (session->nmea.date.tm_year == 0) {
  2015. GPSD_LOG(LOG_WARN, &session->context->errout,
  2016. "can't use PSRFEPE time until after ZDA or RMC"
  2017. " has supplied a year.\n");
  2018. } else {
  2019. mask |= TIME_SET;
  2020. }
  2021. }
  2022. }
  2023. if ('A' != field[2][0]) {
  2024. /* Huh? */
  2025. return mask;
  2026. }
  2027. if ('\0' != field[3][0]) {
  2028. /* This adds nothing, it just agrees with the gpsd calculation
  2029. * from the skyview. Which is a nice confirmation. */
  2030. session->gpsdata.dop.hdop = safe_atof(field[3]);
  2031. mask |= DOP_SET;
  2032. }
  2033. if ('\0' != field[4][0]) {
  2034. /* EHPE (Estimated Horizontal Position Error) */
  2035. session->newdata.eph = safe_atof(field[4]);
  2036. mask |= HERR_SET;
  2037. }
  2038. if ('\0' != field[5][0]) {
  2039. /* Estimated Vertical Position Error (meters, 0.01 resolution) */
  2040. session->newdata.epv = safe_atof(field[5]);
  2041. mask |= VERR_SET;
  2042. }
  2043. if ('\0' != field[6][0]) {
  2044. /* Estimated Horizontal Speed Error meters/sec */
  2045. session->newdata.eps = safe_atof(field[6]);
  2046. }
  2047. if ('\0' != field[7][0]) {
  2048. /* Estimated Heading Error degrees */
  2049. session->newdata.epd = safe_atof(field[7]);
  2050. }
  2051. GPSD_LOG(LOG_PROG, &session->context->errout,
  2052. "PSRFEPE: hdop=%.1f eph=%.1f epv=%.1f eps=%.1f epd=%.1f\n",
  2053. session->gpsdata.dop.hdop,
  2054. session->newdata.eph,
  2055. session->newdata.epv,
  2056. session->newdata.eps,
  2057. session->newdata.epd);
  2058. return mask;
  2059. }
  2060. /* NMEA Map Datum
  2061. *
  2062. * FIXME: seems to happen after cycle ender, so nothing happens...
  2063. */
  2064. static gps_mask_t processDTM(int c UNUSED, char *field[],
  2065. struct gps_device_t *session)
  2066. {
  2067. /*
  2068. * $GPDTM,W84,C*52
  2069. * $GPDTM,xxx,x,xx.xxxx,x,xx.xxxx,x,,xxx*hh<CR><LF>
  2070. * 1 = Local datum code (xxx):
  2071. * W84 – WGS84
  2072. * W72 – WGS72
  2073. * S85 – SGS85
  2074. * P90 – PE90
  2075. * 999 – User defined
  2076. * IHO datum code
  2077. * 2 = Local datum sub code (x)
  2078. * 3 = Latitude offset in minutes (xx.xxxx)
  2079. * 4 = Latitude offset mark (N: +, S: -) (x)
  2080. * 5 = Longitude offset in minutes (xx.xxxx)
  2081. * 6 = Longitude offset mark (E: +, W: -) (x)
  2082. * 7 = Altitude offset in meters. Always null
  2083. * 8 = Datum (xxx):
  2084. * W84 – WGS84
  2085. * W72 – WGS72
  2086. * S85 – SGS85
  2087. * P90 – PE90
  2088. * 999 – User defined
  2089. * IHO datum code
  2090. * 9 = checksum
  2091. */
  2092. int i;
  2093. static struct
  2094. {
  2095. char *code;
  2096. char *name;
  2097. } codes[] = {
  2098. {"W84", "WGS84"},
  2099. {"W72", "WGS72"},
  2100. {"S85", "SGS85"},
  2101. {"P90", "PE90"},
  2102. {"999", "User Defined"},
  2103. {"", ""},
  2104. };
  2105. gps_mask_t mask = ONLINE_SET;
  2106. if ('\0' == field[1][0]) {
  2107. return mask;
  2108. }
  2109. for (i = 0; ; i++) {
  2110. if ('\0' == codes[i].code[0]) {
  2111. /* not found */
  2112. strlcpy(session->newdata.datum, field[1],
  2113. sizeof(session->newdata.datum));
  2114. break;
  2115. }
  2116. if (0 ==strcmp(codes[i].code, field[1])) {
  2117. strlcpy(session->newdata.datum, codes[i].name,
  2118. sizeof(session->newdata.datum));
  2119. break;
  2120. }
  2121. }
  2122. GPSD_LOG(LOG_DATA, &session->context->errout,
  2123. "xxDTM: datum=%.40s\n",
  2124. session->newdata.datum);
  2125. return mask;
  2126. }
  2127. /* NMEA 3.0 Estimated Position Error */
  2128. static gps_mask_t processGBS(int c UNUSED, char *field[],
  2129. struct gps_device_t *session)
  2130. {
  2131. /*
  2132. * $GPGBS,082941.00,2.4,1.5,3.9,25,,-43.7,27.5*65
  2133. * 1) UTC time of the fix associated with this sentence (hhmmss.ss)
  2134. * 2) Expected error in latitude (meters)
  2135. * 3) Expected error in longitude (meters)
  2136. * 4) Expected error in altitude (meters)
  2137. * 5) PRN of most likely failed satellite
  2138. * 6) Probability of missed detection for most likely failed satellite
  2139. * 7) Estimate of bias in meters on most likely failed satellite
  2140. * 8) Standard deviation of bias estimate
  2141. * 9) NMEA 4.1 GNSS ID
  2142. * 10) NMEA 4.1 Signal ID
  2143. * Checksum
  2144. *
  2145. * Fields 2, 3 and 4 are one standard deviation.
  2146. */
  2147. gps_mask_t mask = ONLINE_SET;
  2148. /* register fractional time for end-of-cycle detection */
  2149. register_fractional_time(field[0], field[1], session);
  2150. /* check that we're associated with the current fix */
  2151. if (session->nmea.date.tm_hour == DD(field[1])
  2152. && session->nmea.date.tm_min == DD(field[1] + 2)
  2153. && session->nmea.date.tm_sec == DD(field[1] + 4)) {
  2154. session->newdata.epy = safe_atof(field[2]);
  2155. session->newdata.epx = safe_atof(field[3]);
  2156. session->newdata.epv = safe_atof(field[4]);
  2157. GPSD_LOG(LOG_DATA, &session->context->errout,
  2158. "GBS: epx=%.2f epy=%.2f epv=%.2f\n",
  2159. session->newdata.epx,
  2160. session->newdata.epy,
  2161. session->newdata.epv);
  2162. mask = HERR_SET | VERR_SET;
  2163. } else {
  2164. GPSD_LOG(LOG_PROG, &session->context->errout,
  2165. "second in $GPGBS error estimates doesn't match.\n");
  2166. }
  2167. return mask;
  2168. }
  2169. static gps_mask_t processZDA(int c UNUSED, char *field[],
  2170. struct gps_device_t *session)
  2171. /* Time & Date */
  2172. {
  2173. /*
  2174. * $GPZDA,160012.71,11,03,2004,-1,00*7D
  2175. * 1) UTC time (hours, minutes, seconds, may have fractional subsecond)
  2176. * 2) Day, 01 to 31
  2177. * 3) Month, 01 to 12
  2178. * 4) Year (4 digits)
  2179. * 5) Local zone description, 00 to +- 13 hours
  2180. * 6) Local zone minutes description, apply same sign as local hours
  2181. * 7) Checksum
  2182. *
  2183. * Note: some devices, like the u-blox ANTARIS 4h, are known to ship ZDAs
  2184. * with some fields blank under poorly-understood circumstances (probably
  2185. * when they don't have satellite lock yet).
  2186. */
  2187. gps_mask_t mask = ONLINE_SET;
  2188. int year, mon, mday, century;
  2189. if (field[1][0] == '\0' || field[2][0] == '\0' || field[3][0] == '\0'
  2190. || field[4][0] == '\0') {
  2191. GPSD_LOG(LOG_WARN, &session->context->errout, "ZDA fields are empty\n");
  2192. return mask;
  2193. }
  2194. if (0 != merge_hhmmss(field[1], session)) {
  2195. /* bad time */
  2196. return mask;
  2197. }
  2198. /*
  2199. * We don't register fractional time here because want to leave
  2200. * ZDA out of end-of-cycle detection. Some devices sensibly emit it only
  2201. * when they have a fix, so watching for it can make them look
  2202. * like they have a variable fix reporting cycle.
  2203. */
  2204. year = atoi(field[4]);
  2205. mon = atoi(field[3]);
  2206. mday = atoi(field[2]);
  2207. century = year - year % 100;
  2208. if ( (1900 > year ) || (2200 < year ) ) {
  2209. GPSD_LOG(LOG_WARN, &session->context->errout,
  2210. "malformed ZDA year: %s\n", field[4]);
  2211. } else if ( (1 > mon ) || (12 < mon ) ) {
  2212. GPSD_LOG(LOG_WARN, &session->context->errout,
  2213. "malformed ZDA month: %s\n", field[3]);
  2214. } else if ( (1 > mday ) || (31 < mday ) ) {
  2215. GPSD_LOG(LOG_WARN, &session->context->errout,
  2216. "malformed ZDA day: %s\n", field[2]);
  2217. } else {
  2218. gpsd_century_update(session, century);
  2219. session->nmea.date.tm_year = year - 1900;
  2220. session->nmea.date.tm_mon = mon - 1;
  2221. session->nmea.date.tm_mday = mday;
  2222. mask = TIME_SET;
  2223. }
  2224. return mask;
  2225. }
  2226. static gps_mask_t processHDG(int c UNUSED, char *field[],
  2227. struct gps_device_t *session)
  2228. {
  2229. /*
  2230. * $SDHDG,234.6,,,1.3,E*34
  2231. *
  2232. * $--HDG,h.h,d.d,a,v.v,a*hh<CR><LF>
  2233. * Magnetic sensor heading, degrees
  2234. * Magnetic deviation, degrees E/W
  2235. * Magnetic variation, degrees, E/W
  2236. *
  2237. * 1. To obtain Magnetic Heading:
  2238. * Add Easterly deviation (E) to Magnetic Sensor Reading
  2239. * Subtract Westerly deviation (W) from Magnetic Sensor Reading
  2240. * 2. To obtain True Heading:
  2241. * Add Easterly variation (E) to Magnetic Heading
  2242. * Subtract Westerly variation (W) from Magnetic Heading
  2243. * 3. Variation and deviation fields shall be null fields if unknown.
  2244. */
  2245. gps_mask_t mask = ONLINE_SET;
  2246. double sensor_heading;
  2247. double magnetic_deviation;
  2248. if ( 0 == strlen(field[1])) {
  2249. /* no data */
  2250. return mask;
  2251. }
  2252. sensor_heading = safe_atof(field[1]);
  2253. if ((0.0 > sensor_heading) || (360.0 < sensor_heading)) {
  2254. /* bad data */
  2255. return mask;
  2256. }
  2257. magnetic_deviation = safe_atof(field[2]);
  2258. if ((0.0 > magnetic_deviation) || (360.0 < magnetic_deviation)) {
  2259. /* bad data */
  2260. return mask;
  2261. }
  2262. switch (field[2][0]) {
  2263. case 'E':
  2264. sensor_heading += magnetic_deviation;
  2265. break;
  2266. case 'W':
  2267. sensor_heading += magnetic_deviation;
  2268. break;
  2269. default:
  2270. /* ignore */
  2271. break;
  2272. }
  2273. /* good data */
  2274. session->newdata.magnetic_track = sensor_heading;
  2275. mask |= MAGNETIC_TRACK_SET;
  2276. /* get magnetic variation */
  2277. if ('\0' != field[3][0] &&
  2278. '\0' != field[4][0]) {
  2279. session->newdata.magnetic_var = safe_atof(field[3]);
  2280. switch (field[4][0]) {
  2281. case 'E':
  2282. /* no change */
  2283. mask |= MAGNETIC_TRACK_SET;
  2284. break;
  2285. case 'W':
  2286. session->newdata.magnetic_var = -session->newdata.magnetic_var;
  2287. mask |= MAGNETIC_TRACK_SET;
  2288. break;
  2289. default:
  2290. /* huh? */
  2291. session->newdata.magnetic_var = NAN;
  2292. break;
  2293. }
  2294. }
  2295. GPSD_LOG(LOG_DATA, &session->context->errout,
  2296. "$SDHDG heading %lf var %.1f\n",
  2297. session->newdata.magnetic_track,
  2298. session->newdata.magnetic_var);
  2299. return mask;
  2300. }
  2301. static gps_mask_t processHDT(int c UNUSED, char *field[],
  2302. struct gps_device_t *session)
  2303. {
  2304. /*
  2305. * $HEHDT,341.8,T*21
  2306. *
  2307. * HDT,x.x*hh<cr><lf>
  2308. *
  2309. * The only data field is true heading in degrees.
  2310. * The following field is required to be 'T' indicating a true heading.
  2311. * It is followed by a mandatory nmea_checksum.
  2312. */
  2313. gps_mask_t mask = ONLINE_SET;
  2314. double heading;
  2315. if ( 0 == strlen(field[1])) {
  2316. /* no data */
  2317. return mask;
  2318. }
  2319. heading = safe_atof(field[1]);
  2320. if ((0.0 > heading) || (360.0 < heading)) {
  2321. /* bad data */
  2322. return mask;
  2323. }
  2324. /* good data */
  2325. session->gpsdata.attitude.heading = heading;
  2326. mask |= (ATTITUDE_SET);
  2327. GPSD_LOG(LOG_DATA, &session->context->errout,
  2328. "$HEHDT heading %lf.\n",
  2329. session->gpsdata.attitude.heading);
  2330. return mask;
  2331. }
  2332. static gps_mask_t processDBT(int c UNUSED, char *field[],
  2333. struct gps_device_t *session)
  2334. {
  2335. /*
  2336. * $SDDBT,7.7,f,2.3,M,1.3,F*05
  2337. * 1) Depth below sounder in feet
  2338. * 2) Fixed value 'f' indicating feet
  2339. * 3) Depth below sounder in meters
  2340. * 4) Fixed value 'M' indicating meters
  2341. * 5) Depth below sounder in fathoms
  2342. * 6) Fixed value 'F' indicating fathoms
  2343. * 7) Checksum.
  2344. *
  2345. * In real-world sensors, sometimes not all three conversions are reported.
  2346. */
  2347. gps_mask_t mask = ONLINE_SET;
  2348. if (field[3][0] != '\0') {
  2349. session->newdata.depth = safe_atof(field[3]);
  2350. mask |= (ALTITUDE_SET);
  2351. } else if (field[1][0] != '\0') {
  2352. session->newdata.depth = safe_atof(field[1]) / METERS_TO_FEET;
  2353. mask |= (ALTITUDE_SET);
  2354. } else if (field[5][0] != '\0') {
  2355. session->newdata.depth = safe_atof(field[5]) / METERS_TO_FATHOMS;
  2356. mask |= (ALTITUDE_SET);
  2357. }
  2358. GPSD_LOG(LOG_DATA, &session->context->errout,
  2359. "mode %d, depth %lf.\n",
  2360. session->newdata.mode,
  2361. session->newdata.depth);
  2362. return mask;
  2363. }
  2364. /* GPS Text message */
  2365. static gps_mask_t processTXT(int count, char *field[],
  2366. struct gps_device_t *session)
  2367. {
  2368. /*
  2369. * $GNTXT,01,01,01,PGRM inv format*2A
  2370. * 1 Number of sentences for full data
  2371. * 1 Sentence 1 of 1
  2372. * 01 Message type
  2373. * 00 - error
  2374. * 01 - warning
  2375. * 02 - notice
  2376. * 07 - user
  2377. * PGRM inv format ASCII text
  2378. *
  2379. * Can occur with talker IDs:
  2380. * BD (Beidou),
  2381. * GA (Galileo),
  2382. * GB (Beidou),
  2383. * GL (GLONASS),
  2384. * GN (GLONASS, any combination GNSS),
  2385. * GP (GPS, SBAS, QZSS),
  2386. * QZ (QZSS).
  2387. */
  2388. gps_mask_t mask = ONLINE_SET;
  2389. int msgType = 0;
  2390. char *msgType_txt = "Unknown";
  2391. if ( 5 != count) {
  2392. return mask;
  2393. }
  2394. msgType = atoi(field[3]);
  2395. switch ( msgType ) {
  2396. case 0:
  2397. msgType_txt = "Error";
  2398. break;
  2399. case 1:
  2400. msgType_txt = "Warning";
  2401. break;
  2402. case 2:
  2403. msgType_txt = "Notice";
  2404. break;
  2405. case 7:
  2406. msgType_txt = "User";
  2407. break;
  2408. }
  2409. /* maximum text lenght unknown, guess 80 */
  2410. GPSD_LOG(LOG_WARN, &session->context->errout,
  2411. "TXT: %.10s: %.80s\n",
  2412. msgType_txt, field[4]);
  2413. return mask;
  2414. }
  2415. #ifdef TNT_ENABLE
  2416. static gps_mask_t processTNTHTM(int c UNUSED, char *field[],
  2417. struct gps_device_t *session)
  2418. {
  2419. /*
  2420. * Proprietary sentence for True North Technologies Magnetic Compass.
  2421. * This may also apply to some Honeywell units since they may have been
  2422. * designed by True North.
  2423. $PTNTHTM,14223,N,169,N,-43,N,13641,2454*15
  2424. HTM,x.x,a,x.x,a,x.x,a,x.x,x.x*hh<cr><lf>
  2425. Fields in order:
  2426. 1. True heading (compass measurement + deviation + variation)
  2427. 2. magnetometer status character:
  2428. C = magnetometer calibration alarm
  2429. L = low alarm
  2430. M = low warning
  2431. N = normal
  2432. O = high warning
  2433. P = high alarm
  2434. V = magnetometer voltage level alarm
  2435. 3. pitch angle
  2436. 4. pitch status character - see field 2 above
  2437. 5. roll angle
  2438. 6. roll status character - see field 2 above
  2439. 7. dip angle
  2440. 8. relative magnitude horizontal component of earth's magnetic field
  2441. *hh mandatory nmea_checksum
  2442. By default, angles are reported as 26-bit integers: weirdly, the
  2443. technical manual says either 0 to 65535 or -32768 to 32767 can
  2444. occur as a range.
  2445. */
  2446. gps_mask_t mask = ONLINE_SET;
  2447. session->gpsdata.attitude.heading = safe_atof(field[1]);
  2448. session->gpsdata.attitude.mag_st = *field[2];
  2449. session->gpsdata.attitude.pitch = safe_atof(field[3]);
  2450. session->gpsdata.attitude.pitch_st = *field[4];
  2451. session->gpsdata.attitude.roll = safe_atof(field[5]);
  2452. session->gpsdata.attitude.roll_st = *field[6];
  2453. session->gpsdata.attitude.dip = safe_atof(field[7]);
  2454. session->gpsdata.attitude.mag_x = safe_atof(field[8]);
  2455. mask |= (ATTITUDE_SET);
  2456. GPSD_LOG(LOG_DATA, &session->context->errout,
  2457. "$PTNTHTM heading %lf (%c).\n",
  2458. session->gpsdata.attitude.heading,
  2459. session->gpsdata.attitude.mag_st);
  2460. return mask;
  2461. }
  2462. static gps_mask_t processTNTA(int c UNUSED, char *field[],
  2463. struct gps_device_t *session)
  2464. {
  2465. /*
  2466. * Proprietary sentence for iSync GRClok/LNRClok.
  2467. $PTNTA,20000102173852,1,T4,,,6,1,0*32
  2468. 1. Date/time in format year, month, day, hour, minute, second
  2469. 2. Oscillator quality 0:warming up, 1:freerun, 2:disciplined.
  2470. 3. Always T4. Format indicator.
  2471. 4. Interval ppsref-ppsout in [ns]. Blank if no ppsref.
  2472. 5. Fine phase comparator in approx. [ns]. Always close to -500 or
  2473. +500 if not disciplined. Blank if no ppsref.
  2474. 6. iSync Status. 0:warming up or no light, 1:tracking set-up,
  2475. 2:track to PPSREF, 3:synch to PPSREF, 4:Free Run. Track OFF,
  2476. 5:FR. PPSREF unstable, 6:FR. No PPSREF, 7:FREEZE, 8:factory
  2477. used, 9:searching Rb line
  2478. 7. GPS messages indicator. 0:do not take account, 1:take account,
  2479. but no message, 2:take account, partially ok, 3:take account,
  2480. totally ok.
  2481. 8. Transfer quality of date/time. 0:no, 1:manual, 2:GPS, older
  2482. than x hours, 3:GPS, fresh.
  2483. */
  2484. gps_mask_t mask = ONLINE_SET;
  2485. if (strcmp(field[3], "T4") == 0) {
  2486. struct oscillator_t *osc = &session->gpsdata.osc;
  2487. unsigned int quality = atoi(field[2]);
  2488. unsigned int delta = atoi(field[4]);
  2489. unsigned int fine = atoi(field[5]);
  2490. unsigned int status = atoi(field[6]);
  2491. char deltachar = field[4][0];
  2492. osc->running = (quality > 0);
  2493. osc->reference = (deltachar && (deltachar != '?'));
  2494. if (osc->reference) {
  2495. if (delta < 500) {
  2496. osc->delta = fine;
  2497. } else {
  2498. osc->delta = ((delta < 500000000) ? delta : 1000000000 - delta);
  2499. }
  2500. } else {
  2501. osc->delta = 0;
  2502. }
  2503. osc->disciplined = ((quality == 2) && (status == 3));
  2504. mask |= OSCILLATOR_SET;
  2505. GPSD_LOG(LOG_DATA, &session->context->errout,
  2506. "PTNTA,T4: quality=%s, delta=%s, fine=%s, status=%s\n",
  2507. field[2], field[4], field[5], field[6]);
  2508. }
  2509. return mask;
  2510. }
  2511. #endif /* TNT_ENABLE */
  2512. #ifdef OCEANSERVER_ENABLE
  2513. static gps_mask_t processOHPR(int c UNUSED, char *field[],
  2514. struct gps_device_t *session)
  2515. {
  2516. /*
  2517. * Proprietary sentence for OceanServer Magnetic Compass.
  2518. OHPR,x.x,x.x,x.x,x.x,x.x,x.x,x.x,x.x,x.x,x.x,x.x,x.x,x.x,x.x,x.x,x.x,x.x,x.x*hh<cr><lf>
  2519. Fields in order:
  2520. 1. Azimuth
  2521. 2. Pitch Angle
  2522. 3. Roll Angle
  2523. 4. Sensor temp, degrees centigrade
  2524. 5. Depth (feet)
  2525. 6. Magnetic Vector Length
  2526. 7-9. 3 axis Magnetic Field readings x,y,z
  2527. 10. Acceleration Vector Length
  2528. 11-13. 3 axis Acceleration Readings x,y,z
  2529. 14. Reserved
  2530. 15-16. 2 axis Gyro Output, X,y
  2531. 17. Reserved
  2532. 18. Reserved
  2533. *hh mandatory nmea_checksum
  2534. */
  2535. gps_mask_t mask = ONLINE_SET;
  2536. session->gpsdata.attitude.heading = safe_atof(field[1]);
  2537. session->gpsdata.attitude.pitch = safe_atof(field[2]);
  2538. session->gpsdata.attitude.roll = safe_atof(field[3]);
  2539. session->gpsdata.attitude.temp = safe_atof(field[4]);
  2540. session->gpsdata.attitude.depth = safe_atof(field[5]) / METERS_TO_FEET;
  2541. session->gpsdata.attitude.mag_len = safe_atof(field[6]);
  2542. session->gpsdata.attitude.mag_x = safe_atof(field[7]);
  2543. session->gpsdata.attitude.mag_y = safe_atof(field[8]);
  2544. session->gpsdata.attitude.mag_z = safe_atof(field[9]);
  2545. session->gpsdata.attitude.acc_len = safe_atof(field[10]);
  2546. session->gpsdata.attitude.acc_x = safe_atof(field[11]);
  2547. session->gpsdata.attitude.acc_y = safe_atof(field[12]);
  2548. session->gpsdata.attitude.acc_z = safe_atof(field[13]);
  2549. session->gpsdata.attitude.gyro_x = safe_atof(field[15]);
  2550. session->gpsdata.attitude.gyro_y = safe_atof(field[16]);
  2551. mask |= (ATTITUDE_SET);
  2552. GPSD_LOG(LOG_DATA, &session->context->errout,
  2553. "Heading %lf.\n", session->gpsdata.attitude.heading);
  2554. return mask;
  2555. }
  2556. #endif /* OCEANSERVER_ENABLE */
  2557. #ifdef ASHTECH_ENABLE
  2558. /* Ashtech sentences take this format:
  2559. * $PASHDR,type[,val[,val]]*CS
  2560. * type is an alphabetic subsentence type
  2561. *
  2562. * Oxford Technical Solutions (OxTS) also uses the $PASHR sentence,
  2563. * but with a very different sentence contents:
  2564. * $PASHR,HHMMSS.SSS,HHH.HH,T,RRR.RR,PPP.PP,aaa.aa,r.rrr,p.ppp,h.hhh,Q1,Q2*CS
  2565. *
  2566. * so field 1 in ASHTECH is always alphabetic and numeric in OXTS
  2567. *
  2568. */
  2569. static gps_mask_t processPASHR(int c UNUSED, char *field[],
  2570. struct gps_device_t *session)
  2571. {
  2572. gps_mask_t mask = ONLINE_SET;
  2573. char ts_buf[TIMESPEC_LEN];
  2574. if (0 == strcmp("ACK", field[1])) {
  2575. /* ACK */
  2576. GPSD_LOG(LOG_DATA, &session->context->errout, "PASHR,ACK\n");
  2577. return ONLINE_SET;
  2578. } else if (0 == strcmp("MCA", field[1])) {
  2579. /* MCA, raw data */
  2580. GPSD_LOG(LOG_DATA, &session->context->errout, "PASHR,MCA\n");
  2581. return ONLINE_SET;
  2582. } else if (0 == strcmp("NAK", field[1])) {
  2583. /* NAK */
  2584. GPSD_LOG(LOG_DATA, &session->context->errout, "PASHR,NAK\n");
  2585. return ONLINE_SET;
  2586. } else if (0 == strcmp("PBN", field[1])) {
  2587. /* PBN, position data */
  2588. /* FIXME: decode this for ECEF */
  2589. GPSD_LOG(LOG_DATA, &session->context->errout, "PASHR,PBN\n");
  2590. return ONLINE_SET;
  2591. } else if (0 == strcmp("POS", field[1])) { /* 3D Position */
  2592. /* $PASHR,POS,
  2593. *
  2594. * 2: position type:
  2595. * 0 = autonomous
  2596. * 1 = position differentially corrected with RTCM code
  2597. * 2 = position differentially corrected with CPD float solution
  2598. * 3 = position is CPD fixed solution
  2599. */
  2600. mask |= MODE_SET | STATUS_SET | CLEAR_IS;
  2601. if (0 == strlen(field[2])) {
  2602. /* empty first field means no 3D fix is available */
  2603. session->gpsdata.status = STATUS_NO_FIX;
  2604. session->newdata.mode = MODE_NO_FIX;
  2605. } else {
  2606. int satellites_used;
  2607. /* if we make it this far, we at least have a 3D fix */
  2608. session->newdata.mode = MODE_3D;
  2609. if (1 <= atoi(field[2]))
  2610. session->gpsdata.status = STATUS_DGPS_FIX;
  2611. else
  2612. session->gpsdata.status = STATUS_FIX;
  2613. /* don't use as this breaks the GPGSV counter
  2614. * session->gpsdata.satellites_used = atoi(field[3]); */
  2615. satellites_used = atoi(field[3]);
  2616. if (0 == merge_hhmmss(field[4], session)) {
  2617. register_fractional_time(field[0], field[4], session);
  2618. mask |= TIME_SET;
  2619. }
  2620. if (0 == do_lat_lon(&field[5], &session->newdata)) {
  2621. mask |= LATLON_SET;
  2622. if ('\0' != field[9][0]) {
  2623. /* altitude is already WGS 84 */
  2624. session->newdata.altHAE = safe_atof(field[9]);
  2625. mask |= ALTITUDE_SET;
  2626. }
  2627. }
  2628. session->newdata.track = safe_atof(field[11]);
  2629. session->newdata.speed = safe_atof(field[12]) / MPS_TO_KPH;
  2630. session->newdata.climb = safe_atof(field[13]);
  2631. session->gpsdata.dop.pdop = safe_atof(field[14]);
  2632. session->gpsdata.dop.hdop = safe_atof(field[15]);
  2633. session->gpsdata.dop.vdop = safe_atof(field[16]);
  2634. session->gpsdata.dop.tdop = safe_atof(field[17]);
  2635. mask |= (SPEED_SET | TRACK_SET | CLIMB_SET);
  2636. mask |= DOP_SET;
  2637. GPSD_LOG(LOG_DATA, &session->context->errout,
  2638. "PASHR,POS: hhmmss=%s lat=%.2f lon=%.2f altHAE=%.f"
  2639. " speed=%.2f track=%.2f climb=%.2f mode=%d status=%d"
  2640. " pdop=%.2f hdop=%.2f vdop=%.2f tdop=%.2f used=%d\n",
  2641. field[4], session->newdata.latitude,
  2642. session->newdata.longitude, session->newdata.altHAE,
  2643. session->newdata.speed, session->newdata.track,
  2644. session->newdata.climb, session->newdata.mode,
  2645. session->gpsdata.status, session->gpsdata.dop.pdop,
  2646. session->gpsdata.dop.hdop, session->gpsdata.dop.vdop,
  2647. session->gpsdata.dop.tdop, satellites_used);
  2648. }
  2649. } else if (0 == strcmp("RID", field[1])) { /* Receiver ID */
  2650. (void)snprintf(session->subtype, sizeof(session->subtype) - 1,
  2651. "%s ver %s", field[2], field[3]);
  2652. GPSD_LOG(LOG_DATA, &session->context->errout,
  2653. "PASHR,RID: subtype=%s mask={}\n",
  2654. session->subtype);
  2655. return mask;
  2656. } else if (0 == strcmp("SAT", field[1])) { /* Satellite Status */
  2657. struct satellite_t *sp;
  2658. int i, n = session->gpsdata.satellites_visible = atoi(field[2]);
  2659. session->gpsdata.satellites_used = 0;
  2660. for (i = 0, sp = session->gpsdata.skyview;
  2661. sp < session->gpsdata.skyview + n; sp++, i++) {
  2662. sp->PRN = (short)atoi(field[3 + i * 5 + 0]);
  2663. sp->azimuth = (double)atoi(field[3 + i * 5 + 1]);
  2664. sp->elevation = (double)atoi(field[3 + i * 5 + 2]);
  2665. sp->ss = safe_atof(field[3 + i * 5 + 3]);
  2666. sp->used = false;
  2667. if (field[3 + i * 5 + 4][0] == 'U') {
  2668. sp->used = true;
  2669. session->gpsdata.satellites_used++;
  2670. }
  2671. }
  2672. GPSD_LOG(LOG_DATA, &session->context->errout,
  2673. "PASHR,SAT: used=%d\n",
  2674. session->gpsdata.satellites_used);
  2675. session->gpsdata.skyview_time.tv_sec = 0;
  2676. session->gpsdata.skyview_time.tv_nsec = 0;
  2677. mask |= SATELLITE_SET | USED_IS;
  2678. } else if (0 == strcmp("T", field[3])) { /* Assume OxTS PASHR */
  2679. /* FIXME: decode OxTS $PASHDR, time is wrong, breaks cycle order */
  2680. if (0 == merge_hhmmss(field[1], session)) {
  2681. register_fractional_time(field[0], field[1], session);
  2682. /* mask |= TIME_SET; confuses cycle order */
  2683. }
  2684. session->gpsdata.attitude.heading = safe_atof(field[2]);
  2685. session->gpsdata.attitude.roll = safe_atof(field[4]);
  2686. session->gpsdata.attitude.pitch = safe_atof(field[5]);
  2687. /* mask |= ATTITUDE_SET; * confuses cycle order ?? */
  2688. GPSD_LOG(LOG_DATA, &session->context->errout,
  2689. "PASHR (OxTS) time %s, heading %lf.\n",
  2690. timespec_str(&session->newdata.time, ts_buf, sizeof(ts_buf)),
  2691. session->gpsdata.attitude.heading);
  2692. }
  2693. return mask;
  2694. }
  2695. #endif /* ASHTECH_ENABLE */
  2696. #ifdef MTK3301_ENABLE
  2697. static gps_mask_t processMTK3301(int c UNUSED, char *field[],
  2698. struct gps_device_t *session)
  2699. {
  2700. int msg, reason;
  2701. msg = atoi(&(session->nmea.field[0])[4]);
  2702. switch (msg) {
  2703. case 001: /* ACK / NACK */
  2704. reason = atoi(field[2]);
  2705. if (atoi(field[1]) == -1)
  2706. GPSD_LOG(LOG_WARN, &session->context->errout,
  2707. "MTK NACK: unknown sentence\n");
  2708. else if (reason < 3) {
  2709. const char *mtk_reasons[] = {
  2710. "Invalid",
  2711. "Unsupported",
  2712. "Valid but Failed",
  2713. "Valid success"
  2714. };
  2715. GPSD_LOG(LOG_WARN, &session->context->errout,
  2716. "MTK NACK: %s, reason: %s\n",
  2717. field[1], mtk_reasons[reason]);
  2718. }
  2719. else
  2720. GPSD_LOG(LOG_DATA, &session->context->errout,
  2721. "MTK ACK: %s\n", field[1]);
  2722. return ONLINE_SET;
  2723. case 424: /* PPS pulse width response */
  2724. /*
  2725. * Response will look something like: $PMTK424,0,0,1,0,69*12
  2726. * The pulse width is in field 5 (69 in this example). This
  2727. * sentence is poorly documented at:
  2728. * http://www.trimble.com/embeddedsystems/condor-gps-module.aspx?dtID=documentation
  2729. *
  2730. * Packet Type: 324 PMTK_API_SET_OUTPUT_CTL
  2731. * Packet meaning
  2732. * Write the TSIP / antenna / PPS configuration data to the Flash memory.
  2733. * DataField [Data0]:TSIP Packet[on/off]
  2734. * 0 - Disable TSIP output (Default).
  2735. * 1 - Enable TSIP output.
  2736. * [Data1]:Antenna Detect[on/off]
  2737. * 0 - Disable antenna detect function (Default).
  2738. * 1 - Enable antenna detect function.
  2739. * [Data2]:PPS on/off
  2740. * 0 - Disable PPS function.
  2741. * 1 - Enable PPS function (Default).
  2742. * [Data3]:PPS output timing
  2743. * 0 - Always output PPS (Default).
  2744. * 1 - Only output PPS when GPS position is fixed.
  2745. * [Data4]:PPS pulse width
  2746. * 1~16367999: 61 ns~(61x 16367999) ns (Default = 69)
  2747. *
  2748. * The documentation does not give the units of the data field.
  2749. * Andy Walls <andy@silverblocksystems.net> says:
  2750. *
  2751. * "The best I can figure using an oscilloscope, is that it is
  2752. * in units of 16.368000 MHz clock cycles. It may be
  2753. * different for any other unit other than the Trimble
  2754. * Condor. 69 cycles / 16368000 cycles/sec = 4.216 microseconds
  2755. * [which is the pulse width I have observed]"
  2756. *
  2757. * Support for this theory comes from the fact that crystal
  2758. * TXCOs with a 16.368MHZ period are commonly available from
  2759. * multiple vendors. Furthermore, 61*69 = 4209, which is
  2760. * close to the observed cycle time and suggests that the
  2761. * documentation is trying to indicate 61ns units.
  2762. *
  2763. * He continues:
  2764. *
  2765. * "I chose [127875] because to divides 16368000 nicely and the
  2766. * pulse width is close to 1/100th of a second. Any number
  2767. * the user wants to use would be fine. 127875 cycles /
  2768. * 16368000 cycles/second = 1/128 seconds = 7.8125
  2769. * milliseconds"
  2770. */
  2771. /* too short? Make it longer */
  2772. if (atoi(field[5]) < 127875)
  2773. (void)nmea_send(session, "$PMTK324,0,0,1,0,127875");
  2774. return ONLINE_SET;
  2775. case 705: /* return device subtype */
  2776. (void)strlcat(session->subtype, field[1], sizeof(session->subtype));
  2777. (void)strlcat(session->subtype, "-", sizeof(session->subtype));
  2778. (void)strlcat(session->subtype, field[2], sizeof(session->subtype));
  2779. return ONLINE_SET;
  2780. default:
  2781. GPSD_LOG(LOG_PROG, &session->context->errout,
  2782. "MTK: unknown msg: %d\n", msg);
  2783. return ONLINE_SET; /* ignore */
  2784. }
  2785. }
  2786. #endif /* MTK3301_ENABLE */
  2787. #ifdef SKYTRAQ_ENABLE
  2788. /* Recommended Minimum 3D GNSS Data */
  2789. static gps_mask_t processPSTI030(int count, char *field[],
  2790. struct gps_device_t *session)
  2791. {
  2792. /*
  2793. * $PSTI,030,hhmmss.sss,A,dddmm.mmmmmmm,a,dddmm.mmmmmmm,a,x.x,x.x,x.x,x.x,ddmmyy,a.x.x,x.x*hh<CR><LF>
  2794. * 1 030 Sentence ID
  2795. * 2 225446.334 Time of fix 22:54:46 UTC
  2796. * 3 A Status of Fix: A = Autonomous, valid;
  2797. * V = invalid
  2798. * 4,5 4916.45,N Latitude 49 deg. 16.45 min North
  2799. * 6,7 12311.12,W Longitude 123 deg. 11.12 min West
  2800. * 8 103.323 Mean Sea Level meters
  2801. * 9 0.00 East Velocity meters/sec
  2802. * 10 0.00 North Velocity meters/sec
  2803. * 11 0.00 Up Velocity meters/sec
  2804. * 12 181194 Date of fix 18 November 1994
  2805. * 13 A FAA mode indicator
  2806. * See faa_mode() for possible mode values.
  2807. * 14 1.2 RTK Age
  2808. * 15 4.2 RTK Ratio
  2809. * 16 *68 mandatory nmea_checksum
  2810. *
  2811. * In private email, SkyTraq says F mode is 10x more accurate
  2812. * than R mode.
  2813. */
  2814. gps_mask_t mask = ONLINE_SET;
  2815. if ( 16 != count )
  2816. return mask;
  2817. if ('V' == field[3][0] ||
  2818. 'N' == field[13][0]) {
  2819. /* nav warning, or FAA not valid, ignore the rest of the data */
  2820. session->gpsdata.status = STATUS_NO_FIX;
  2821. session->newdata.mode = MODE_NO_FIX;
  2822. mask |= MODE_SET;
  2823. } else if ('A' == field[3][0]) {
  2824. double east, north, climb;
  2825. /* data valid */
  2826. if (field[2][0] != '\0' && field[12][0] != '\0') {
  2827. /* good date and time */
  2828. if (0 == merge_hhmmss(field[2], session) &&
  2829. 0 == merge_ddmmyy(field[12], session)) {
  2830. mask |= TIME_SET;
  2831. register_fractional_time( "PSTI030", field[2], session);
  2832. }
  2833. }
  2834. if (0 == do_lat_lon(&field[4], &session->newdata)) {
  2835. session->newdata.mode = MODE_2D;
  2836. mask |= LATLON_SET;
  2837. if ('\0' != field[8][0]) {
  2838. /* altitude is MSL */
  2839. session->newdata.altMSL = safe_atof(field[8]);
  2840. mask |= ALTITUDE_SET;
  2841. session->newdata.mode = MODE_3D;
  2842. /* Let gpsd_error_model() deal with geoid_sep and altHAE */
  2843. }
  2844. mask |= MODE_SET;
  2845. }
  2846. /* convert ENU to track */
  2847. /* this has more precision than GPVTG, GPVTG comes earlier
  2848. * in the cycle */
  2849. east = safe_atof(field[9]); /* east velocity m/s */
  2850. north = safe_atof(field[10]); /* north velocity m/s */
  2851. /* up velocity m/s */
  2852. climb = safe_atof(field[11]);
  2853. session->newdata.NED.velN = north;
  2854. session->newdata.NED.velE = east;
  2855. session->newdata.NED.velD = -climb;
  2856. mask |= VNED_SET;
  2857. session->gpsdata.status = faa_mode(field[13][0]);
  2858. /* Ignore RTK Age and RTK Ratio, for now */
  2859. }
  2860. GPSD_LOG(LOG_DATA, &session->context->errout,
  2861. "PSTI,030: ddmmyy=%s hhmmss=%s lat=%.2f lon=%.2f "
  2862. "status=%d, RTK(Age=%s Ratio=%s)\n",
  2863. field[12], field[2],
  2864. session->newdata.latitude,
  2865. session->newdata.longitude,
  2866. session->gpsdata.status,
  2867. field[14], field[15]);
  2868. return mask;
  2869. }
  2870. /*
  2871. * Skytraq sentences take this format:
  2872. * $PSTI,type[,val[,val]]*CS
  2873. * type is a 2 or 3 digit subsentence type
  2874. *
  2875. * Note: this sentence can be at least 100 chars long.
  2876. * That violates the NMEA 3.01 max of 82.
  2877. *
  2878. */
  2879. static gps_mask_t processPSTI(int count, char *field[],
  2880. struct gps_device_t *session)
  2881. {
  2882. gps_mask_t mask = ONLINE_SET;
  2883. if ( 0 != strncmp(session->subtype, "Skytraq", 7) ) {
  2884. /* this is skytraq, but not marked yet, so probe for Skytraq */
  2885. (void)gpsd_write(session, "\xA0\xA1\x00\x02\x02\x01\x03\x0d\x0a",9);
  2886. }
  2887. if (0 == strcmp("00", field[1]) ) {
  2888. if ( 4 != count )
  2889. return mask;
  2890. /* 1 PPS Timing report ID */
  2891. GPSD_LOG(LOG_DATA, &session->context->errout,
  2892. "PSTI,00: Mode: %s, Length: %s, Quant: %s\n",
  2893. field[2], field[3], field[4]);
  2894. return mask;
  2895. }
  2896. if (0 == strcmp("001", field[1])) {
  2897. /* Active Antenna Status Report */
  2898. GPSD_LOG(LOG_DATA, &session->context->errout,
  2899. "PSTI,001: Count: %d\n", count);
  2900. return mask;
  2901. }
  2902. if (0 == strcmp("005", field[1])) {
  2903. /* GPIO 10 event-triggered time & position stamp. */
  2904. GPSD_LOG(LOG_DATA, &session->context->errout,
  2905. "PSTI,005: Count: %d\n", count);
  2906. return mask;
  2907. }
  2908. if (0 == strcmp("030", field[1])) {
  2909. /* Recommended Minimum 3D GNSS Data */
  2910. return processPSTI030(count, field, session);
  2911. }
  2912. if (0 == strcmp("032", field[1])) {
  2913. if ( 16 != count )
  2914. return mask;
  2915. /* RTK Baseline */
  2916. if ( 0 == strcmp(field[4], "A")) {
  2917. /* Status Valid */
  2918. if (field[2][0] != '\0' && field[3][0] != '\0') {
  2919. /* good date and time */
  2920. if (0 == merge_hhmmss(field[2], session) &&
  2921. 0 == merge_ddmmyy(field[3], session)) {
  2922. mask |= TIME_SET;
  2923. register_fractional_time( "PSTI032", field[2], session);
  2924. }
  2925. }
  2926. }
  2927. GPSD_LOG( LOG_DATA,&session->context->errout,
  2928. "PSTI,032: stat:%s mode: %s E: %s N: %s U:%s L:%s C:%s\n",
  2929. field[4], field[5],
  2930. field[6], field[7], field[8],
  2931. field[9], field[10]);
  2932. return mask;
  2933. }
  2934. GPSD_LOG(LOG_DATA, &session->context->errout,
  2935. "PSTI,%s: Unknown type, Count: %d\n", field[1], count);
  2936. return mask;
  2937. }
  2938. /*
  2939. * Skytraq undocumented debug sentences take this format:
  2940. * $STI,type,val*CS
  2941. * type is a 2 char subsentence type
  2942. * Note: NO checksum
  2943. */
  2944. static gps_mask_t processSTI(int count, char *field[],
  2945. struct gps_device_t *session)
  2946. {
  2947. gps_mask_t mask = ONLINE_SET;
  2948. if ( 0 != strncmp(session->subtype, "Skytraq", 7) ) {
  2949. /* this is skytraq, but marked yet, so probe for Skytraq */
  2950. (void)gpsd_write(session, "\xA0\xA1\x00\x02\x02\x01\x03\x0d\x0a",9);
  2951. }
  2952. if ( 0 == strcmp( field[1], "IC") ) {
  2953. /* $STI,IC,error=XX, this is always very bad, but undocumented */
  2954. GPSD_LOG(LOG_ERROR, &session->context->errout,
  2955. "Skytraq: $STI,%s,%s\n", field[1], field[2]);
  2956. return mask;
  2957. }
  2958. GPSD_LOG(LOG_DATA, &session->context->errout,
  2959. "STI,%s: Unknown type, Count: %d\n", field[1], count);
  2960. return mask;
  2961. }
  2962. #endif /* SKYTRAQ_ENABLE */
  2963. /**************************************************************************
  2964. *
  2965. * Entry points begin here
  2966. *
  2967. **************************************************************************/
  2968. gps_mask_t nmea_parse(char *sentence, struct gps_device_t * session)
  2969. /* parse an NMEA sentence, unpack it into a session structure */
  2970. {
  2971. typedef gps_mask_t(*nmea_decoder) (int count, char *f[],
  2972. struct gps_device_t * session);
  2973. static struct
  2974. {
  2975. char *name;
  2976. int nf; /* minimum number of fields required to parse */
  2977. bool cycle_continue; /* cycle continuer? */
  2978. nmea_decoder decoder;
  2979. } nmea_phrase[] = {
  2980. {"PGRMB", 0, false, NULL}, /* ignore Garmin DGPS Beacon Info */
  2981. {"PGRMC", 0, false, NULL}, /* ignore Garmin Sensor Config */
  2982. {"PGRME", 7, false, processPGRME},
  2983. {"PGRMF", 15, false, processPGRMF}, /* Garmin GPS Fix Data */
  2984. {"PGRMH", 0, false, NULL}, /* ignore Garmin Aviation Height... */
  2985. {"PGRMI", 0, false, NULL}, /* ignore Garmin Sensor Init */
  2986. {"PGRMM", 2, false, processPGRMM}, /* Garmin Map Datum */
  2987. {"PGRMO", 0, false, NULL}, /* ignore Garmin Sentence Enable */
  2988. {"PGRMT", 0, false, NULL}, /* ignore Garmin Sensor Info */
  2989. {"PGRMV", 0, false, NULL}, /* ignore Garmin 3D Velocity Info */
  2990. {"PGRMZ", 4, false, processPGRMZ},
  2991. /*
  2992. * Basic sentences must come after the PG* ones, otherwise
  2993. * Garmins can get stuck in a loop that looks like this:
  2994. *
  2995. * 1. A Garmin GPS in NMEA mode is detected.
  2996. *
  2997. * 2. PGRMC is sent to reconfigure to Garmin binary mode.
  2998. * If successful, the GPS echoes the phrase.
  2999. *
  3000. * 3. nmea_parse() sees the echo as RMC because the talker
  3001. * ID is ignored, and fails to recognize the echo as
  3002. * PGRMC and ignore it.
  3003. *
  3004. * 4. The mode is changed back to NMEA, resulting in an
  3005. * infinite loop.
  3006. */
  3007. {"AAM", 0, false, NULL}, /* ignore Waypoint Arrival Alarm */
  3008. {"APB", 0, false, NULL}, /* ignore Autopilot Sentence B */
  3009. {"BOD", 0, false, NULL}, /* ignore Bearing Origin to Destination */
  3010. /* ignore Bearing & Distance to Waypoint, Great Circle*/
  3011. {"BWC", 0, false, NULL},
  3012. {"DBT", 7, true, processDBT},
  3013. {"DPT", 0, false, NULL}, /* ignore depth */
  3014. {"DTM", 2, false, processDTM}, /* datum */
  3015. {"GBS", 7, false, processGBS},
  3016. {"GGA", 13, false, processGGA},
  3017. {"GLC", 0, false, NULL}, /* ignore Geographic Position, LoranC */
  3018. {"GLL", 7, false, processGLL},
  3019. {"GNS", 13, false, processGNS},
  3020. {"GRS", 0, false, NULL}, /* ignore GNSS Range Residuals */
  3021. {"GSA", 18, false, processGSA},
  3022. {"GST", 8, false, processGST},
  3023. {"GSV", 0, false, processGSV},
  3024. /* ignore Heading, Deviation and Variation */
  3025. {"HDG", 0, false, processHDG},
  3026. {"HDT", 1, false, processHDT},
  3027. {"MSS", 0, false, NULL}, /* ignore beacon receiver status */
  3028. {"MTW", 0, false, NULL}, /* ignore Water Temperature */
  3029. {"MWD", 0, false, NULL}, /* ignore Wind Direction and Speed */
  3030. {"MWV", 0, false, NULL}, /* ignore Wind Speed and Angle */
  3031. #ifdef OCEANSERVER_ENABLE
  3032. {"OHPR", 18, false, processOHPR},
  3033. #endif /* OCEANSERVER_ENABLE */
  3034. #ifdef ASHTECH_ENABLE
  3035. /* general handler for Ashtech */
  3036. {"PASHR", 3, false, processPASHR},
  3037. #endif /* ASHTECH_ENABLE */
  3038. {"PMGNST", 8, false, processPMGNST}, /* Magellan Status */
  3039. #ifdef MTK3301_ENABLE
  3040. {"PMTK", 3, false, processMTK3301},
  3041. /* for some reason the parser no longer triggering on leading chars */
  3042. {"PMTK001", 3, false, processMTK3301},
  3043. {"PMTK424", 3, false, processMTK3301},
  3044. {"PMTK705", 3, false, processMTK3301},
  3045. {"PMTKCHN", 0, false, NULL}, /* ignore MediaTek Channel Status */
  3046. #endif /* MTK3301_ENABLE */
  3047. {"PRWIZCH", 0, false, NULL}, /* ignore Rockwell Channel Status */
  3048. {"PSRFEPE", 7, false, processPSRFEPE}, /* SiRF Estimated Errors */
  3049. {"PTFTTXT", 0, false, NULL}, /* ignore unknown uptime */
  3050. {"PUBX", 0, false, NULL}, /* ignore u-blox Antaris */
  3051. #ifdef TNT_ENABLE
  3052. {"PTNTHTM", 9, false, processTNTHTM},
  3053. {"PTNTA", 8, false, processTNTA},
  3054. #endif /* TNT_ENABLE */
  3055. #ifdef SKYTRAQ_ENABLE
  3056. {"PSTI", 2, false, processPSTI}, /* $PSTI Skytraq */
  3057. {"STI", 2, false, processSTI}, /* $STI Skytraq */
  3058. #endif /* SKYTRAQ_ENABLE */
  3059. // $PSTM ST Micro STA8088xx/STA8089xx/STA8090xx
  3060. {"PSTM", 0, false, NULL},
  3061. /* ignore Recommended Minimum Navigation Info, waypoint */
  3062. {"RMB", 0, false, NULL},
  3063. {"RMC", 8, false, processRMC},
  3064. {"RTE", 0, false, NULL}, /* ignore Routes */
  3065. {"TXT", 5, false, processTXT},
  3066. {"VHW", 0, false, NULL}, /* ignore Water Speed and Heading */
  3067. {"VLW", 0, false, NULL}, /* ignore Dual ground/water distance */
  3068. {"VTG", 5, false, processVTG},
  3069. {"XDR", 0, false, NULL}, /* ignore $HCXDR, IMU? */
  3070. {"XTE", 0, false, NULL}, /* ignore Cross-Track Error */
  3071. {"ZDA", 4, false, processZDA},
  3072. };
  3073. int count;
  3074. gps_mask_t mask = 0;
  3075. unsigned int i, thistag, lasttag;
  3076. char *p, *e;
  3077. volatile char *t;
  3078. uint64_t lasttag_mask = 0;
  3079. uint64_t thistag_mask = 0;
  3080. char ts_buf1[TIMESPEC_LEN];
  3081. char ts_buf2[TIMESPEC_LEN];
  3082. #ifdef SKYTRAQ_ENABLE
  3083. bool skytraq_sti = false;
  3084. #endif
  3085. /*
  3086. * We've had reports that on the Garmin GPS-10 the device sometimes
  3087. * (1:1000 or so) sends garbage packets that have a valid checksum
  3088. * but are like 2 successive NMEA packets merged together in one
  3089. * with some fields lost. Usually these are much longer than the
  3090. * legal limit for NMEA, so we can cope by just tossing out overlong
  3091. * packets. This may be a generic bug of all Garmin chipsets.
  3092. */
  3093. if (strlen(sentence) > NMEA_MAX) {
  3094. GPSD_LOG(LOG_WARN, &session->context->errout,
  3095. "Overlong packet of %zd chars rejected.\n",
  3096. strlen(sentence));
  3097. return ONLINE_SET;
  3098. }
  3099. /* make an editable copy of the sentence */
  3100. (void)strlcpy((char *)session->nmea.fieldcopy, sentence,
  3101. sizeof(session->nmea.fieldcopy) - 1);
  3102. /* discard the checksum part */
  3103. for (p = (char *)session->nmea.fieldcopy;
  3104. (*p != '*') && (*p >= ' ');)
  3105. ++p;
  3106. if (*p == '*')
  3107. *p++ = ','; /* otherwise we drop the last field */
  3108. #ifdef SKYTRAQ_ENABLE_UNUSED
  3109. /* $STI is special, no trailing *, or chacksum */
  3110. if ( 0 != strncmp( "STI,", sentence, 4) ) {
  3111. skytraq_sti = true;
  3112. *p++ = ','; /* otherwise we drop the last field */
  3113. }
  3114. #endif
  3115. *p = '\0';
  3116. e = p;
  3117. /* split sentence copy on commas, filling the field array */
  3118. count = 0;
  3119. t = p; /* end of sentence */
  3120. p = (char *)session->nmea.fieldcopy + 1; /* beginning of tag, 'G' not '$' */
  3121. /* while there is a search string and we haven't run off the buffer... */
  3122. while ((p != NULL) && (p <= t)) {
  3123. session->nmea.field[count] = p; /* we have a field. record it */
  3124. if ((p = strchr(p, ',')) != NULL) { /* search for the next delimiter */
  3125. *p = '\0'; /* replace it with a NUL */
  3126. count++; /* bump the counters and continue */
  3127. p++;
  3128. }
  3129. }
  3130. /* point remaining fields at empty string, just in case */
  3131. for (i = (unsigned int)count;
  3132. i <
  3133. (unsigned)(sizeof(session->nmea.field) /
  3134. sizeof(session->nmea.field[0])); i++)
  3135. session->nmea.field[i] = e;
  3136. /* sentences handlers will tell us when they have fractional time */
  3137. session->nmea.latch_frac_time = false;
  3138. #ifdef __UNUSED
  3139. // debug
  3140. GPSD_LOG(&session->context->errout, 0,
  3141. "NMEA0183: got %s\n", session->nmea.field[0]);
  3142. #endif // __UNUSED
  3143. /* dispatch on field zero, the sentence tag */
  3144. for (thistag = i = 0;
  3145. i < (unsigned)(sizeof(nmea_phrase) / sizeof(nmea_phrase[0])); ++i) {
  3146. char *s = session->nmea.field[0];
  3147. if (strlen(nmea_phrase[i].name) == 3
  3148. #ifdef SKYTRAQ_ENABLE
  3149. /* $STI is special */
  3150. && !skytraq_sti
  3151. #endif
  3152. ) {
  3153. s += 2; /* skip talker ID */
  3154. }
  3155. if (strcmp(nmea_phrase[i].name, s) == 0) {
  3156. if (NULL == nmea_phrase[i].decoder) {
  3157. /* no decoder for this sentence */
  3158. mask = ONLINE_SET;
  3159. GPSD_LOG(LOG_DATA, &session->context->errout,
  3160. "No decoder for sentence %s\n",
  3161. session->nmea.field[0]);
  3162. break;
  3163. }
  3164. if (count < nmea_phrase[i].nf) {
  3165. /* sentence to short */
  3166. mask = ONLINE_SET;
  3167. GPSD_LOG(LOG_DATA, &session->context->errout,
  3168. "Sentence %s too short\n", session->nmea.field[0]);
  3169. break;
  3170. }
  3171. mask = (nmea_phrase[i].decoder)(count, session->nmea.field,
  3172. session);
  3173. if (nmea_phrase[i].cycle_continue)
  3174. session->nmea.cycle_continue = true;
  3175. /*
  3176. * Must force this to be nz, as we're going to rely on a zero
  3177. * value to mean "no previous tag" later.
  3178. */
  3179. thistag = i + 1;
  3180. break;
  3181. }
  3182. }
  3183. /* prevent overaccumulation of sat reports */
  3184. if (!str_starts_with(session->nmea.field[0] + 2, "GSV"))
  3185. session->nmea.last_gsv_talker = '\0';
  3186. if (!str_starts_with(session->nmea.field[0] + 2, "GSA"))
  3187. session->nmea.last_gsa_talker = '\0';
  3188. /* timestamp recording for fixes happens here */
  3189. if ((mask & TIME_SET) != 0) {
  3190. session->newdata.time = gpsd_utc_resolve(session);
  3191. GPSD_LOG(LOG_DATA, &session->context->errout,
  3192. "%s time is %s = %d-%02d-%02dT%02d:%02d:%02d.%03ldZ\n",
  3193. session->nmea.field[0],
  3194. timespec_str(&session->newdata.time, ts_buf1, sizeof(ts_buf1)),
  3195. 1900 + session->nmea.date.tm_year,
  3196. session->nmea.date.tm_mon + 1,
  3197. session->nmea.date.tm_mday,
  3198. session->nmea.date.tm_hour,
  3199. session->nmea.date.tm_min,
  3200. session->nmea.date.tm_sec,
  3201. session->nmea.subseconds.tv_nsec / 1000000L);
  3202. /*
  3203. * If we have time and PPS is available, assume we have good time.
  3204. * Because this is a generic driver we don't really have enough
  3205. * information for a sharper test, so we'll leave it up to the
  3206. * PPS code to do its own sanity filtering.
  3207. */
  3208. mask |= NTPTIME_IS;
  3209. }
  3210. /*
  3211. * The end-of-cycle detector. This code depends on just one
  3212. * assumption: if a sentence with a timestamp occurs just before
  3213. * start of cycle, then it is always good to trigger a report on
  3214. * that sentence in the future. For devices with a fixed cycle
  3215. * this should work perfectly, locking in detection after one
  3216. * cycle. Most split-cycle devices (Garmin 48, for example) will
  3217. * work fine. Problems will only arise if a a sentence that
  3218. * occurs just before timestamp increments also occurs in
  3219. * mid-cycle, as in the Garmin eXplorist 210; those might jitter.
  3220. */
  3221. /* cast for 32/64 bit compat */
  3222. GPSD_LOG(LOG_DATA, &session->context->errout,
  3223. "%s time %s last %s latch %d cont %d enders %#llx\n",
  3224. session->nmea.field[0],
  3225. timespec_str(&session->nmea.this_frac_time, ts_buf1,
  3226. sizeof(ts_buf1)),
  3227. timespec_str(&session->nmea.last_frac_time, ts_buf2,
  3228. sizeof(ts_buf2)),
  3229. session->nmea.latch_frac_time,
  3230. session->nmea.cycle_continue,
  3231. (unsigned long long)session->nmea.cycle_enders);
  3232. lasttag = session->nmea.lasttag;
  3233. if (0 < session->nmea.lasttag) {
  3234. lasttag_mask = (uint64_t)1 << lasttag;
  3235. }
  3236. if (0 < thistag) {
  3237. thistag_mask = (uint64_t)1 << thistag;
  3238. }
  3239. if (session->nmea.latch_frac_time) {
  3240. timespec_t ts_delta;
  3241. TS_SUB(&ts_delta, &session->nmea.this_frac_time,
  3242. &session->nmea.last_frac_time);
  3243. if (0.01 < fabs(TSTONS(&ts_delta))) {
  3244. /* time changed */
  3245. mask |= CLEAR_IS;
  3246. GPSD_LOG(LOG_PROG, &session->context->errout,
  3247. "%s starts a reporting cycle. lasttag %d\n",
  3248. session->nmea.field[0], lasttag);
  3249. /*
  3250. * Have we seen a previously timestamped NMEA tag?
  3251. * If so, designate as end-of-cycle marker.
  3252. * But not if there are continuation sentences;
  3253. * those get sorted after the last timestamped sentence
  3254. *
  3255. */
  3256. if (0 < lasttag &&
  3257. 0 == (session->nmea.cycle_enders & lasttag_mask) &&
  3258. !session->nmea.cycle_continue) {
  3259. session->nmea.cycle_enders |= lasttag_mask;
  3260. /* (long long) cast for 32/64 bit compat */
  3261. GPSD_LOG(LOG_PROG, &session->context->errout,
  3262. "tagged %s as a cycle ender. %#llx\n",
  3263. nmea_phrase[lasttag - 1].name,
  3264. (unsigned long long)lasttag_mask);
  3265. }
  3266. }
  3267. } else {
  3268. /* extend the cycle to an un-timestamped sentence? */
  3269. if (0 != (session->nmea.cycle_enders & lasttag_mask)) {
  3270. GPSD_LOG(LOG_PROG, &session->context->errout,
  3271. "%s is just after a cycle ender.\n",
  3272. session->nmea.field[0]);
  3273. }
  3274. if (session->nmea.cycle_continue) {
  3275. GPSD_LOG(LOG_PROG, &session->context->errout,
  3276. "%s extends the reporting cycle.\n",
  3277. session->nmea.field[0]);
  3278. /* change ender */
  3279. session->nmea.cycle_enders &= ~lasttag_mask;
  3280. session->nmea.cycle_enders |= thistag_mask;
  3281. }
  3282. }
  3283. /* here's where we check for end-of-cycle */
  3284. if ((session->nmea.latch_frac_time || session->nmea.cycle_continue)
  3285. && (session->nmea.cycle_enders & thistag_mask)!=0) {
  3286. GPSD_LOG(LOG_PROG, &session->context->errout,
  3287. "%s ends a reporting cycle.\n",
  3288. session->nmea.field[0]);
  3289. mask |= REPORT_IS;
  3290. }
  3291. if (session->nmea.latch_frac_time)
  3292. session->nmea.lasttag = thistag;
  3293. /* we might have a (somewhat) reliable end-of-cycle */
  3294. if (session->nmea.cycle_enders != 0)
  3295. session->cycle_end_reliable = true;
  3296. /* don't downgrade mode if holding previous fix */
  3297. /* usually because of xxRMC which does not report 2D/3D */
  3298. if (MODE_SET == (mask & MODE_SET) &&
  3299. MODE_3D == session->gpsdata.fix.mode &&
  3300. MODE_NO_FIX != session->newdata.mode &&
  3301. (0 != isfinite(session->lastfix.altHAE) ||
  3302. 0 != isfinite(session->oldfix.altHAE) ||
  3303. 0 != isfinite(session->lastfix.altMSL) ||
  3304. 0 != isfinite(session->oldfix.altMSL))) {
  3305. session->newdata.mode = session->gpsdata.fix.mode;
  3306. }
  3307. return mask;
  3308. }
  3309. #endif /* NMEA0183_ENABLE */
  3310. void nmea_add_checksum(char *sentence)
  3311. /* add NMEA checksum to a possibly *-terminated sentence */
  3312. {
  3313. unsigned char sum = '\0';
  3314. char c, *p = sentence;
  3315. if (*p == '$' || *p == '!') {
  3316. p++;
  3317. }
  3318. while (((c = *p) != '*') && (c != '\0')) {
  3319. sum ^= c;
  3320. p++;
  3321. }
  3322. *p++ = '*';
  3323. (void)snprintf(p, 5, "%02X\r\n", (unsigned)sum);
  3324. }
  3325. ssize_t nmea_write(struct gps_device_t *session, char *buf, size_t len UNUSED)
  3326. /* ship a command to the GPS, adding * and correct checksum */
  3327. {
  3328. (void)strlcpy(session->msgbuf, buf, sizeof(session->msgbuf));
  3329. if (session->msgbuf[0] == '$') {
  3330. (void)strlcat(session->msgbuf, "*", sizeof(session->msgbuf));
  3331. nmea_add_checksum(session->msgbuf);
  3332. } else
  3333. (void)strlcat(session->msgbuf, "\r\n", sizeof(session->msgbuf));
  3334. session->msgbuflen = strlen(session->msgbuf);
  3335. return gpsd_write(session, session->msgbuf, session->msgbuflen);
  3336. }
  3337. ssize_t nmea_send(struct gps_device_t * session, const char *fmt, ...)
  3338. {
  3339. char buf[BUFSIZ];
  3340. va_list ap;
  3341. va_start(ap, fmt);
  3342. (void)vsnprintf(buf, sizeof(buf) - 5, fmt, ap);
  3343. va_end(ap);
  3344. return nmea_write(session, buf, strlen(buf));
  3345. }
  3346. // vim: set expandtab shiftwidth=4