driver_superstar2.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576
  1. /*
  2. * This file is Copyright 2010 by the GPSD project
  3. * SPDX-License-Identifier: BSD-2-clause
  4. */
  5. #include "../include/gpsd_config.h" /* must be before all includes */
  6. #include <math.h>
  7. #include <stdbool.h>
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11. #include <time.h>
  12. #include "../include/gpsd.h"
  13. #if defined(SUPERSTAR2_ENABLE) && defined(BINARY_ENABLE)
  14. #include "../include/bits.h"
  15. #include "../include/driver_superstar2.h"
  16. #include "../include/timespec.h"
  17. /*
  18. * These routines are specific to this driver
  19. */
  20. static gps_mask_t superstar2_parse_input(struct gps_device_t *);
  21. static gps_mask_t superstar2_dispatch(struct gps_device_t *,
  22. unsigned char *, size_t);
  23. static gps_mask_t superstar2_msg_ack(struct gps_device_t *,
  24. unsigned char *, size_t);
  25. static gps_mask_t superstar2_msg_navsol_lla(struct gps_device_t *,
  26. unsigned char *, size_t);
  27. static gps_mask_t superstar2_msg_timing(struct gps_device_t *,
  28. unsigned char *, size_t);
  29. static gps_mask_t superstar2_msg_svinfo(struct gps_device_t *,
  30. unsigned char *, size_t);
  31. static gps_mask_t superstar2_msg_iono_utc(struct gps_device_t *,
  32. unsigned char *, size_t);
  33. static gps_mask_t superstar2_msg_ephemeris(struct gps_device_t *,
  34. unsigned char *, size_t);
  35. /*
  36. * These methods may be called elsewhere in gpsd
  37. */
  38. static ssize_t superstar2_control_send(struct gps_device_t *, char *, size_t);
  39. static void superstar2_event_hook(struct gps_device_t *, event_t);
  40. static ssize_t superstar2_write(struct gps_device_t *, char *, size_t);
  41. static bool superstar2_set_speed(struct gps_device_t *, speed_t, char, int);
  42. static void superstar2_set_mode(struct gps_device_t *, int);
  43. /*
  44. * Decode the message ACK message
  45. */
  46. static gps_mask_t superstar2_msg_ack(struct gps_device_t *session,
  47. unsigned char *buf, size_t data_len)
  48. {
  49. if (data_len == 11)
  50. GPSD_LOG(LOG_PROG, &session->context->errout,
  51. "superstar2 #126 - ACK %d %d %d %d %d\n",
  52. buf[5], buf[6], buf[7], buf[8], buf[9]);
  53. return 0;
  54. }
  55. /*
  56. * Decode the navigation solution message. The ECEF version is intentionally
  57. * unhandled. By suppressing evaluation of it, we gain the desirable feature
  58. * that the fix update is atomic and exactly once per cycle.
  59. */
  60. /* Navigation Data (User Coordinates) ID# 20 */
  61. static gps_mask_t superstar2_msg_navsol_lla(struct gps_device_t *session,
  62. unsigned char *buf, size_t data_len)
  63. {
  64. gps_mask_t mask;
  65. unsigned char flags;
  66. double d;
  67. struct tm tm;
  68. double int_part;
  69. char ts_buf[TIMESPEC_LEN];
  70. if (data_len != 77)
  71. return 0;
  72. GPSD_LOG(LOG_PROG, &session->context->errout,
  73. "superstar2 #20 - user navigation data\n");
  74. mask = 0;
  75. flags = (unsigned char)getub(buf, 72);
  76. if ((flags & 0x0f) != 0x03) /* mode 3 is navigation */
  77. return mask;
  78. /* extract time data */
  79. (void)memset(&tm, '\0', sizeof(tm));
  80. tm.tm_hour = (int)getub(buf, 4) & 0x1f;
  81. tm.tm_min = (int)getub(buf, 5);
  82. d = getled64((char *)buf, 6); /* seconds as a double */
  83. session->newdata.time.tv_nsec = (long)(modf(d, &int_part) * 1e9);
  84. tm.tm_sec = (int)int_part;
  85. tm.tm_mday = (int)getub(buf, 14);
  86. tm.tm_mon = (int)getub(buf, 15) - 1;
  87. tm.tm_year = (int)getleu16(buf, 16) - 1900;
  88. tm.tm_isdst = 0;
  89. session->newdata.time.tv_sec = mkgmtime(&tm);
  90. mask |= TIME_SET | NTPTIME_IS;
  91. /* extract the local tangential plane (ENU) solution */
  92. session->newdata.latitude = getled64((char *)buf, 18) * RAD_2_DEG;
  93. session->newdata.longitude = getled64((char *)buf, 26) * RAD_2_DEG;
  94. /* unclear if this is MSL or WGS84. Assume WGS84 */
  95. session->newdata.altHAE = getlef32((char *)buf, 34);
  96. session->newdata.speed = getlef32((char *)buf, 38);
  97. session->newdata.track = getlef32((char *)buf, 42) * RAD_2_DEG;
  98. session->newdata.climb = getlef32((char *)buf, 54);
  99. mask |= LATLON_SET | ALTITUDE_SET | SPEED_SET | TRACK_SET | CLIMB_SET;
  100. session->gpsdata.satellites_used = (int)getub(buf, 71) & 0x0f;
  101. session->gpsdata.dop.hdop = getleu16(buf, 66) * 0.1;
  102. session->gpsdata.dop.vdop = getleu16(buf, 68) * 0.1;
  103. /* other DOP if available */
  104. mask |= DOP_SET | USED_IS;
  105. flags = (unsigned char)getub(buf, 70);
  106. switch (flags & 0x1f) {
  107. case 2:
  108. session->newdata.mode = MODE_3D;
  109. session->newdata.status = STATUS_GPS;
  110. break;
  111. case 4:
  112. session->newdata.mode = MODE_3D;
  113. session->newdata.status = STATUS_DGPS;
  114. break;
  115. case 5:
  116. session->newdata.mode = MODE_2D;
  117. session->newdata.status = STATUS_DGPS;
  118. break;
  119. case 3:
  120. case 6:
  121. session->newdata.mode = MODE_2D;
  122. session->newdata.status = STATUS_GPS;
  123. break;
  124. default:
  125. session->newdata.status = STATUS_UNK;
  126. session->newdata.mode = MODE_NO_FIX;
  127. }
  128. mask |= MODE_SET | STATUS_SET;
  129. GPSD_LOG(LOG_DATA, &session->context->errout,
  130. "NAVSOL_LLA: time=%s lat=%.2f lon=%.2f altHAE=%.2f "
  131. "track=%.2f speed=%.2f climb=%.2f mode=%d status=%d hdop=%.2f "
  132. "hdop=%.2f used=%d\n",
  133. timespec_str(&session->newdata.time, ts_buf, sizeof(ts_buf)),
  134. session->newdata.latitude,
  135. session->newdata.longitude,
  136. session->newdata.altHAE,
  137. session->newdata.track,
  138. session->newdata.speed,
  139. session->newdata.climb,
  140. session->newdata.mode,
  141. session->newdata.status,
  142. session->gpsdata.dop.hdop,
  143. session->gpsdata.dop.vdop,
  144. session->gpsdata.satellites_used);
  145. return mask;
  146. }
  147. /*
  148. * GPS Satellite Info
  149. */
  150. static gps_mask_t
  151. superstar2_msg_svinfo(struct gps_device_t *session,
  152. unsigned char *buf, size_t data_len)
  153. {
  154. int i, st, nchan, nsv;
  155. if (data_len != 67)
  156. return 0;
  157. GPSD_LOG(LOG_PROG, &session->context->errout,
  158. "superstar2 #33 - satellite data\n");
  159. nchan = 12;
  160. gpsd_zero_satellites(&session->gpsdata);
  161. nsv = 0; /* number of actually used satellites */
  162. for (i = st = 0; i < nchan; i++) {
  163. /* get info for one channel/satellite */
  164. int off = i * 5 + 5;
  165. unsigned int porn;
  166. bool used = (getub(buf, off) & 0x60) == 0x60;
  167. if ((porn = (unsigned int)getub(buf, off) & 0x1f) == 0)
  168. porn = (unsigned int)(getub(buf, off + 3) >> 1) + 87;
  169. session->gpsdata.skyview[i].PRN = (short)porn;
  170. session->gpsdata.skyview[i].ss = (double)getub(buf, off + 4);
  171. session->gpsdata.skyview[i].elevation = (double)getsb(buf, off + 1);
  172. session->gpsdata.skyview[i].azimuth = (double)getub(buf, off + 2) +
  173. (short)((unsigned short)(getub(buf, off + 3) & 0x1) << 1);
  174. session->gpsdata.skyview[i].used = used;
  175. if (used)
  176. nsv++;
  177. if (session->gpsdata.skyview[i].PRN)
  178. st++;
  179. }
  180. session->gpsdata.skyview_time.tv_sec = 0;
  181. session->gpsdata.skyview_time.tv_nsec = 0;
  182. session->gpsdata.satellites_used = nsv;
  183. session->gpsdata.satellites_visible = st;
  184. GPSD_LOG(LOG_DATA, &session->context->errout,
  185. "SVINFO: visible=%d used=%d mask={SATELLITE|USED}\n",
  186. session->gpsdata.satellites_visible,
  187. session->gpsdata.satellites_used);
  188. return SATELLITE_SET | USED_IS;
  189. }
  190. static gps_mask_t
  191. superstar2_msg_version(struct gps_device_t *session,
  192. unsigned char *buf, size_t data_len)
  193. {
  194. #define SZ 16
  195. char main_sw[SZ], hw_part[SZ], boot_sw[SZ], ser_num[SZ];
  196. /* byte 98 is device type, value = 3 means superstar2 */
  197. if ((data_len != 101) || ((getub(buf, 98) & 0x0f) != 3))
  198. return 0;
  199. (void)snprintf(main_sw, 15, "%s", (char *)buf + 4);
  200. (void)snprintf(hw_part, 15, "%s", (char *)buf + 18);
  201. (void)snprintf(boot_sw, 15, "%s", (char *)buf + 36);
  202. (void)snprintf(ser_num, 14, "%s", (char *)buf + 73);
  203. GPSD_LOG(LOG_PROG, &session->context->errout,
  204. "superstar2 #45 - hw part %s boot sw %s main sw %s ser num %s\n",
  205. hw_part, boot_sw, main_sw, ser_num);
  206. (void)strlcpy(session->subtype, main_sw, sizeof(session->subtype));
  207. GPSD_LOG(LOG_DATA, &session->context->errout,
  208. "VERSION: subtype='%s' mask={DEVEICEID}\n",
  209. session->subtype);
  210. return DEVICEID_SET;
  211. }
  212. /**
  213. * Timing Status ID# 113
  214. *
  215. * Precise Timing models only
  216. */
  217. static gps_mask_t
  218. superstar2_msg_timing(struct gps_device_t *session, unsigned char *buf,
  219. size_t data_len)
  220. {
  221. gps_mask_t mask;
  222. struct tm tm;
  223. if (data_len != 65)
  224. return 0;
  225. GPSD_LOG(LOG_PROG, &session->context->errout,
  226. "superstar2 #113 - timing status\n");
  227. if ((getub(buf, 55) & 0x30) != 0)
  228. mask = 0;
  229. else {
  230. double d;
  231. /* extract time data */
  232. (void)memset(&tm, '\0', sizeof(tm));
  233. tm.tm_mday = (int)getsb(buf, 37);
  234. tm.tm_mon = (int)getsb(buf, 38) - 1;
  235. tm.tm_year = (int)getles16(buf, 39) - 1900;
  236. tm.tm_hour = (int)getsb(buf, 41);
  237. tm.tm_min = (int)getsb(buf, 42);
  238. d = getled64((char *)buf, 43);
  239. tm.tm_sec = (int)d;
  240. tm.tm_isdst = 0;
  241. session->newdata.time.tv_sec = mkgmtime(&tm);
  242. session->newdata.time.tv_nsec = 0;
  243. session->context->leap_seconds = (int)getsb(buf, 20);
  244. mask = TIME_SET | NTPTIME_IS;
  245. }
  246. GPSD_LOG(LOG_DATA, &session->context->errout,
  247. "TIMING: time=%lld mask={TIME}\n",
  248. (long long)session->newdata.time.tv_sec);
  249. return mask;
  250. }
  251. /**
  252. * Raw Measurements
  253. */
  254. static gps_mask_t
  255. superstar2_msg_measurement(struct gps_device_t *session, unsigned char *buf,
  256. size_t data_len UNUSED)
  257. {
  258. gps_mask_t mask = 0;
  259. int i, n;
  260. double t;
  261. GPSD_LOG(LOG_PROG, &session->context->errout,
  262. "superstar2 #23 - measurement block\n");
  263. n = (int)getub(buf, 6); /* number of measurements */
  264. if ((n < 1) || (n > MAXCHANNELS)) {
  265. GPSD_LOG(LOG_INF, &session->context->errout,
  266. "too many measurements\n");
  267. return 0;
  268. }
  269. t = getled64((char *)buf, 7); /* measurement time */
  270. DTOTS(&session->gpsdata.raw.mtime, t);
  271. /* this is so we can tell which never got set */
  272. for (i = 0; i < MAXCHANNELS; i++)
  273. session->gpsdata.raw.meas[i].svid = 0;
  274. for (i = 0; i < n; i++) {
  275. unsigned long ul;
  276. session->gpsdata.skyview[i].PRN =
  277. (short)(getub(buf, 11 * i + 15) & 0x1f);
  278. session->gpsdata.skyview[i].ss =
  279. (double)getub(buf, 11 * i * 15 + 1) / 4.0;
  280. session->gpsdata.raw.meas[i].codephase =
  281. (double)getleu32(buf, 11 * i * 15 + 2);
  282. ul = (unsigned long)getleu32(buf, 11 * i * 15 + 6);
  283. session->gpsdata.raw.meas[i].satstat = (unsigned int)(ul & 0x03L);
  284. session->gpsdata.raw.meas[i].carrierphase =
  285. (double)((ul >> 2) & 0x03ffL);
  286. session->gpsdata.raw.meas[i].pseudorange = (double)(ul >> 12);
  287. }
  288. /*The above decode does not look correct, do not report */
  289. /* mask |= RAW_IS; */
  290. return mask;
  291. }
  292. /* request for ionospheric and utc time data #75 */
  293. static unsigned char iono_utc_msg[] = { 0x01, 0x4b, 0xb4, 0x00, 0x00, 0x01 };
  294. /**
  295. * Ionospheric/UTC parameters
  296. */
  297. static gps_mask_t
  298. superstar2_msg_iono_utc(struct gps_device_t *session, unsigned char *buf,
  299. size_t data_len UNUSED)
  300. {
  301. unsigned int i, u;
  302. i = (unsigned int)getub(buf, 12);
  303. u = (unsigned int)getub(buf, 21);
  304. GPSD_LOG(LOG_PROG, &session->context->errout,
  305. "superstar2 #75 - ionospheric & utc data: iono %s utc %s\n",
  306. i ? "ok" : "bad", u ? "ok" : "bad");
  307. session->driver.superstar2.last_iono = time(NULL);
  308. return 0;
  309. }
  310. /**
  311. * Ephemeris
  312. */
  313. static gps_mask_t
  314. superstar2_msg_ephemeris(struct gps_device_t *session, unsigned char *buf,
  315. size_t data_len UNUSED)
  316. {
  317. unsigned int prn;
  318. prn = (unsigned int)(getub(buf, 4) & 0x1f);
  319. GPSD_LOG(LOG_PROG, &session->context->errout,
  320. "superstar2 #22 - ephemeris data - prn %u\n", prn);
  321. /* ephemeris data updates fairly slowly, but when it does, poll UTC */
  322. if ((time(NULL) - session->driver.superstar2.last_iono) > 60)
  323. (void)superstar2_write(session, (char *)iono_utc_msg,
  324. sizeof(iono_utc_msg));
  325. return ONLINE_SET;
  326. }
  327. static ssize_t
  328. superstar2_write(struct gps_device_t *session, char *msg, size_t msglen)
  329. {
  330. unsigned short c = 0;
  331. ssize_t i;
  332. for (i = 0; i < (ssize_t) (msglen - 2); i++)
  333. c += (unsigned short)msg[i];
  334. c += 0x100;
  335. msg[(int)msg[3] + 4] = (char)((c >> 8) & 0xff);
  336. msg[(int)msg[3] + 5] = (char)(c & 0xff);
  337. GPSD_LOG(LOG_PROG, &session->context->errout,
  338. "writing superstar2 control type %d len %zu\n",
  339. (int)msg[1] & 0x7f, msglen);
  340. return gpsd_write(session, msg, msglen);
  341. }
  342. /**
  343. * Parse the data from the device
  344. */
  345. gps_mask_t
  346. superstar2_dispatch(struct gps_device_t * session, unsigned char *buf,
  347. size_t len)
  348. {
  349. int type;
  350. if (len == 0)
  351. return 0;
  352. type = (int)buf[SUPERSTAR2_TYPE_OFFSET];
  353. session->cycle_end_reliable = true;
  354. switch (type) {
  355. case SUPERSTAR2_ACK: /* Message Acknowledgement */
  356. return superstar2_msg_ack(session, buf, len);
  357. case SUPERSTAR2_SVINFO: /* Satellite Visibility Data */
  358. return superstar2_msg_svinfo(session, buf, len);
  359. case SUPERSTAR2_NAVSOL_LLA: /* Navigation Data */
  360. return superstar2_msg_navsol_lla(session, buf,
  361. len) | (CLEAR_IS | REPORT_IS);
  362. case SUPERSTAR2_VERSION: /* Hardware/Software Version */
  363. return superstar2_msg_version(session, buf, len);
  364. case SUPERSTAR2_TIMING: /* Timing Parameters */
  365. return superstar2_msg_timing(session, buf, len);
  366. case SUPERSTAR2_MEASUREMENT: /* Timing Parameters */
  367. return superstar2_msg_measurement(session, buf, len);
  368. case SUPERSTAR2_IONO_UTC:
  369. return superstar2_msg_iono_utc(session, buf, len);
  370. case SUPERSTAR2_EPHEMERIS:
  371. return superstar2_msg_ephemeris(session, buf, len);
  372. default:
  373. GPSD_LOG(LOG_WARN, &session->context->errout,
  374. "unknown superstar2 packet id 0x%02x length %zd\n",
  375. type, len);
  376. return 0;
  377. }
  378. }
  379. /**********************************************************
  380. *
  381. * Externally called routines below here
  382. *
  383. **********************************************************/
  384. static void superstar2_event_hook(struct gps_device_t *session, event_t event)
  385. {
  386. if (session->context->readonly ||
  387. session->context->passive) {
  388. return;
  389. }
  390. if (event == event_identified) {
  391. unsigned char version_msg[] = { 0x01, 0x2d, 0xd2, 0x00, 0x00, 0x01 };
  392. unsigned char svinfo_msg[] = { 0x01, 0xa1, 0x5e, 0x00, 0x00, 0x01 };
  393. unsigned char timing_msg[] = { 0x01, 0xf1, 0x0e, 0x00, 0x00, 0x01 };
  394. unsigned char navsol_lla_msg[] = { 0x01, 0x94, 0x6b, 0x00, 0x00, 0x01 };
  395. unsigned char ephemeris_msg[] = { 0x01, 0x96, 0x69, 0x00, 0x00, 0x01 };
  396. unsigned char measurement_msg[] =
  397. { 0x01, 0x97, 0x68, 0x01, 0x00, 0x01, 0x01 };
  398. (void)superstar2_write(session, (char *)timing_msg,
  399. sizeof(timing_msg));
  400. (void)superstar2_write(session, (char *)measurement_msg,
  401. sizeof(measurement_msg));
  402. (void)superstar2_write(session, (char *)svinfo_msg,
  403. sizeof(svinfo_msg));
  404. (void)superstar2_write(session, (char *)navsol_lla_msg,
  405. sizeof(navsol_lla_msg));
  406. (void)superstar2_write(session, (char *)version_msg,
  407. sizeof(version_msg));
  408. (void)superstar2_write(session, (char *)ephemeris_msg,
  409. sizeof(ephemeris_msg));
  410. (void)superstar2_write(session, (char *)iono_utc_msg,
  411. sizeof(iono_utc_msg));
  412. session->driver.superstar2.last_iono = time(NULL);
  413. }
  414. }
  415. /*
  416. * This is the entry point to the driver. When the packet sniffer recognizes
  417. * a packet for this driver, it calls this method which passes the packet to
  418. * the binary processor or the nmea processor, depending on the session type.
  419. */
  420. static gps_mask_t superstar2_parse_input(struct gps_device_t *session)
  421. {
  422. if (SUPERSTAR2_PACKET == session->lexer.type) {
  423. return superstar2_dispatch(session, session->lexer.outbuffer,
  424. session->lexer.length);;
  425. }
  426. if (NMEA_PACKET == session->lexer.type) {
  427. return nmea_parse((char *)session->lexer.outbuffer, session);
  428. }
  429. return 0;
  430. }
  431. static ssize_t superstar2_control_send(struct gps_device_t *session, char *msg,
  432. size_t msglen)
  433. {
  434. session->msgbuf[0] = 0x1; // SOH
  435. session->msgbuf[1] = msg[0];
  436. session->msgbuf[2] = msg[0] ^ 0xff;
  437. session->msgbuf[3] = (char)(msglen + 1);
  438. (void)memcpy(session->msgbuf + 4, msg + 1, msglen - 1);
  439. session->msgbuflen = (size_t) (msglen + 5);
  440. return superstar2_write(session, session->msgbuf, session->msgbuflen);
  441. }
  442. static bool superstar2_set_speed(struct gps_device_t *session,
  443. speed_t speed, char parity, int stopbits)
  444. {
  445. /* parity and stopbit switching aren't available on this chip */
  446. if (parity != session->gpsdata.dev.parity
  447. || stopbits != (int)session->gpsdata.dev.stopbits) {
  448. return false;
  449. } else {
  450. unsigned char speed_msg[] =
  451. { 0x01, 0x48, 0xB7, 0x01, 0x00, 0x00, 0x00 };
  452. /* high bit 0 in the mode word means set NMEA mode */
  453. speed_msg[4] = (unsigned char)(speed / 300);
  454. return (superstar2_write(session, (char *)speed_msg, 7) == 7);
  455. }
  456. }
  457. static void superstar2_set_mode(struct gps_device_t *session, int mode)
  458. {
  459. if (mode == MODE_NMEA) {
  460. unsigned char mode_msg[] =
  461. { 0x01, 0x48, 0xB7, 0x01, 0x00, 0x00, 0x00 };
  462. /* high bit 0 in the mode word means set NMEA mode */
  463. mode_msg[4] = (unsigned char)(session->gpsdata.dev.baudrate / 300);
  464. (void)superstar2_write(session, (char *)mode_msg, 7);
  465. }
  466. }
  467. /* *INDENT-OFF* */
  468. const struct gps_type_t driver_superstar2 = {
  469. /* Full name of type */
  470. .type_name = "SuperStarII",
  471. /* Associated lexer packet type */
  472. .packet_type = SUPERSTAR2_PACKET,
  473. /* Driver type flags */
  474. .flags = DRIVER_STICKY,
  475. /* Response string that identifies device (not active) */
  476. .trigger = NULL,
  477. /* Number of satellite channels supported by the device */
  478. .channels = 12,
  479. /* Startup-time device detector */
  480. .probe_detect = NULL,
  481. /* Packet getter (using default routine) */
  482. .get_packet = generic_get,
  483. /* Parse message packets */
  484. .parse_packet = superstar2_parse_input,
  485. /* RTCM handler (using default routine) */
  486. .rtcm_writer = gpsd_write,
  487. /* non-perturbing initial query */
  488. .init_query = NULL,
  489. /* Fire on various lifetime events */
  490. .event_hook = superstar2_event_hook,
  491. /* Speed (baudrate) switch */
  492. .speed_switcher = superstar2_set_speed,
  493. /* Switch to NMEA mode */
  494. .mode_switcher = superstar2_set_mode,
  495. /* Message delivery rate switcher (not active) */
  496. .rate_switcher = NULL,
  497. /* Minimum cycle time (not used) */
  498. .min_cycle.tv_sec = 1, /* not relevant, no rate switch */
  499. .min_cycle.tv_nsec = 0, /* not relevant, no rate switch */
  500. /* Control string sender - should provide checksum and trailer */
  501. .control_send = superstar2_control_send,
  502. .time_offset = NULL, /* no method for NTP fudge factor */
  503. };
  504. /* *INDENT-ON* */
  505. #endif /* defined(SUPERSTAR2_ENABLE) && defined(BINARY_ENABLE) */
  506. // vim: set expandtab shiftwidth=4