driver_superstar2.c 18 KB

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