driver_oncore.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674
  1. /*
  2. * This file is Copyright 2010 by the GPSD project
  3. * SPDX-License-Identifier: BSD-2-clause
  4. */
  5. #include "gpsd_config.h" /* must be before all includes */
  6. #include <stdbool.h>
  7. #include <stdio.h>
  8. #include "gpsd.h"
  9. #if defined(ONCORE_ENABLE) && defined(BINARY_ENABLE)
  10. #include "bits.h"
  11. #include "timespec.h"
  12. static char enableEa[] = { 'E', 'a', 1 };
  13. static char enableBb[] = { 'B', 'b', 1 };
  14. static char getfirmware[] = { 'C', 'j' };
  15. /*static char enableEn[] =
  16. { 'E', 'n', 1, 0, 100, 100, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };*/
  17. /*static char enableAt2[] = { 'A', 't', 2, };*/
  18. static unsigned char pollAs[] =
  19. { 'A', 's', 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff,
  20. 0xff, 0xff, 0xff
  21. };
  22. static unsigned char pollAt[] = { 'A', 't', 0xff };
  23. static unsigned char pollAw[] = { 'A', 'w', 0xff };
  24. static unsigned char pollAy[] = { 'A', 'y', 0xff, 0xff, 0xff, 0xff };
  25. static unsigned char pollBo[] = { 'B', 'o', 0x01 };
  26. static unsigned char pollEn[] = {
  27. 'E', 'n', 0xff, 0xff, 0xff, 0xff, 0xff,
  28. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
  29. };
  30. /*
  31. * These routines are specific to this driver
  32. */
  33. static gps_mask_t oncore_parse_input(struct gps_device_t *);
  34. static gps_mask_t oncore_dispatch(struct gps_device_t *, unsigned char *,
  35. size_t);
  36. static gps_mask_t oncore_msg_navsol(struct gps_device_t *, unsigned char *,
  37. size_t);
  38. static gps_mask_t oncore_msg_utc_offset(struct gps_device_t *,
  39. unsigned char *, size_t);
  40. static gps_mask_t oncore_msg_pos_hold_mode(struct gps_device_t *,
  41. unsigned char *, size_t);
  42. static gps_mask_t oncore_msg_pps_offset(struct gps_device_t *, unsigned char *,
  43. size_t);
  44. static gps_mask_t oncore_msg_svinfo(struct gps_device_t *, unsigned char *,
  45. size_t);
  46. static gps_mask_t oncore_msg_time_mode(struct gps_device_t *, unsigned char *,
  47. size_t);
  48. static gps_mask_t oncore_msg_time_raim(struct gps_device_t *, unsigned char *,
  49. size_t);
  50. static gps_mask_t oncore_msg_firmware(struct gps_device_t *, unsigned char *,
  51. size_t);
  52. /*
  53. * These methods may be called elsewhere in gpsd
  54. */
  55. static ssize_t oncore_control_send(struct gps_device_t *, char *, size_t);
  56. static void oncore_event_hook(struct gps_device_t *, event_t);
  57. /*
  58. * Decode the navigation solution message
  59. *
  60. * @@Ea - Position/Status/Data Message
  61. @@EamdyyhmsffffaaaaoooohhhhmmmmvvhhddtntimsdimsdimsdimsdimsdimsdimsdimsdsC
  62. <CR><LF>
  63. *
  64. * Date
  65. * m - month 1 .. 12
  66. * d - day 1 .. 31
  67. * yy - year 1980 .. 2079
  68. *
  69. * Time
  70. * h - hours 0 .. 23
  71. * m - minutes 0 .. 59
  72. * s - seconds 0 .. 60
  73. * ffff - fractional second 0 .. 999,999,999
  74. * (0.0 .. 0.999999999)
  75. *
  76. * Position
  77. * aaaa - latitude in mas -324,000,000 .. 324,000,000
  78. * (-90 degrees .. 90 degrees)
  79. *
  80. * oooo - longitude in mas -648,000,000 .. 648,000,000
  81. * (-180 degrees .. 180 degrees)
  82. *
  83. * hhhh - ellipsoid height in cm -100,000 .. 1,800,000
  84. * (-1000.00 .. 18,000.00m)*
  85. *
  86. * mmmm - not used 0
  87. *
  88. * Velocity
  89. * vv - velocity in cm/s 0 .. 51,400 (0..514.00 m/s)*
  90. * hh - heading 0 .. 3599 (0.0..359.9 degrees)
  91. *
  92. * (true north res 0.1 degrees)
  93. *
  94. * Geometry
  95. * dd - current DOP (0.1 res) 0 .. 999 (0.0 to 99.9 DOP)
  96. * (0 = not computable, position-hold, or position propagate)
  97. *
  98. * t - DOP TYPE
  99. * 0 PDOP (3D)/antenna ok
  100. * 1 PDOP (3D)/antenna OK
  101. * 64 PDOP (3D)/antenna shorted
  102. * 65 PDOP (3D)/antenna shorted
  103. * 128 PDOP (3D)/antenna open
  104. * 129 PDOP (3D)/antenna open
  105. * 192 PDOP (3D)/antenna shorted
  106. * 193 PDOP (3D)/antenna shorted
  107. *
  108. * Satellite visibility and tracking status
  109. * n - num of visible sats 0 .. 12
  110. * t - num of satellites tracked 0 .. 8
  111. *
  112. * For each of eight receiver channels
  113. * i - sat ID 0 .. 37
  114. * m - channel tracking mode 0 .. 8
  115. * 0 = code search 5 = message sync detect
  116. * 1 = code acquire 6 = satellite time avail.
  117. * 2 = AGC set 7 = ephemeris acquire
  118. * 3 = prep acquire 8 = avail for position
  119. * 4 = bit sync detect
  120. *
  121. * s - carrier to noise density ratio
  122. * (C/No) 0 .. 255 db-Hz
  123. *
  124. * d - channel status flag
  125. * Each bit represents one of the following:
  126. * (msb) Bit 7: using for position fix
  127. * Bit 6: satellite momentum alert flag
  128. * Bit 5: satellite anti-spoof flag set
  129. * Bit 4: satellite reported unhealthy
  130. * Bit 3: satellite reported inaccurate
  131. * (> 16m)
  132. * Bit 2: spare
  133. * Bit 1: spare
  134. * (lsb) Bit 0: parity error
  135. *
  136. * End of channel dependent data
  137. * s - receiver status flag
  138. *
  139. * Each bit represents one of the following:
  140. * (msb) Bit 7: position propagate mode
  141. * Bit 6: poor geometry (DOP > 12)
  142. * Bit 5: 3D fix
  143. * Bit 4: 2D fix
  144. * Bit 3: acquiring satellites/position hold
  145. * Bit 2: spare
  146. * Bit 1: insufficient visible satellites
  147. * (< 3)
  148. * (lsb) Bit 0: bad almanac
  149. *
  150. * C - checksum
  151. * Message length: 76 bytes
  152. *
  153. */
  154. static gps_mask_t
  155. oncore_msg_navsol(struct gps_device_t *session, unsigned char *buf,
  156. size_t data_len)
  157. {
  158. gps_mask_t mask;
  159. unsigned char flags;
  160. double lat, lon, alt;
  161. float speed, track, dop;
  162. unsigned int i, j, st, nsv;
  163. int Bbused;
  164. struct tm unpacked_date;
  165. char ts_buf[TIMESPEC_LEN];
  166. if (data_len != 76)
  167. return 0;
  168. mask = ONLINE_SET;
  169. GPSD_LOG(LOG_DATA, &session->context->errout,
  170. "oncore NAVSOL - navigation data\n");
  171. flags = (unsigned char)getub(buf, 72);
  172. if (flags & 0x20) {
  173. session->newdata.status = STATUS_FIX;
  174. session->newdata.mode = MODE_3D;
  175. } else if (flags & 0x10) {
  176. session->newdata.status = STATUS_FIX;
  177. session->newdata.mode = MODE_2D;
  178. } else if ((flags & 0x08) &&
  179. session->driver.oncore.pos_hold_mode ==
  180. ONCORE_POS_HOLD_MODE_ON) {
  181. /* To be a good time solution for a fixed surveyed position,
  182. * the poshold/acquiring flag (0x08) must be accompanied by
  183. * the device being in position hold-mode. The device is
  184. * also reporting acquiring (0x08) when it has no fix.
  185. * Therefore the pos_hold_mode check above.
  186. */
  187. session->newdata.status = STATUS_TIME;
  188. session->newdata.mode = MODE_3D;
  189. } else {
  190. GPSD_LOG(LOG_WARN, &session->context->errout,
  191. "oncore NAVSOL no fix - flags 0x%02x\n", flags);
  192. session->newdata.mode = MODE_NO_FIX;
  193. session->newdata.status = STATUS_NO_FIX;
  194. }
  195. mask |= MODE_SET | STATUS_SET;
  196. /* Unless we have seen non-zero utc offset data, the time is GPS time
  197. * and not UTC time. Even if time mode (Aw) message already says UTC.
  198. * Do not use the time.
  199. */
  200. if (LEAP_SECOND_VALID == (session->context->valid & LEAP_SECOND_VALID)) {
  201. unsigned int nsec;
  202. unpacked_date.tm_mon = (int)getub(buf, 4) - 1;
  203. unpacked_date.tm_mday = (int)getub(buf, 5);
  204. unpacked_date.tm_year = (int)getbeu16(buf, 6) - 1900;
  205. unpacked_date.tm_hour = (int)getub(buf, 8);
  206. unpacked_date.tm_min = (int)getub(buf, 9);
  207. unpacked_date.tm_sec = (int)getub(buf, 10);
  208. unpacked_date.tm_isdst = 0;
  209. unpacked_date.tm_wday = unpacked_date.tm_yday = 0;
  210. nsec = (unsigned int) getbeu32(buf, 11);
  211. session->newdata.time.tv_sec = mkgmtime(&unpacked_date);
  212. session->newdata.time.tv_nsec = nsec;
  213. mask |= TIME_SET;
  214. GPSD_LOG(LOG_DATA, &session->context->errout,
  215. "oncore NAVSOL - time: %04d-%02d-%02d %02d:%02d:%02d.%09d\n",
  216. unpacked_date.tm_year + 1900, unpacked_date.tm_mon + 1,
  217. unpacked_date.tm_mday, unpacked_date.tm_hour,
  218. unpacked_date.tm_min, unpacked_date.tm_sec, nsec);
  219. }
  220. lat = getbes32(buf, 15) / 3600000.0;
  221. lon = getbes32(buf, 19) / 3600000.0;
  222. alt = getbes32(buf, 23) / 100.0;
  223. speed = getbeu16(buf, 31) / 100.0f;
  224. track = getbeu16(buf, 33) / 10.0f;
  225. dop = getbeu16(buf, 35) / 10.0f;
  226. GPSD_LOG(LOG_DATA, &session->context->errout,
  227. "oncore NAVSOL - %lf %lf %.2lfm | %.2fm/s %.1fdeg dop=%.1f\n",
  228. lat, lon, alt, speed, track,
  229. (float)dop);
  230. if (MODE_2D <= session->newdata.mode) {
  231. session->newdata.latitude = lat;
  232. session->newdata.longitude = lon;
  233. session->newdata.speed = speed;
  234. session->newdata.track = track;
  235. mask |= LATLON_SET | SPEED_SET | TRACK_SET;
  236. }
  237. if (MODE_3D <= session->newdata.mode) {
  238. session->newdata.altHAE = alt; /* is WGS84 */
  239. mask |= ALTITUDE_SET;
  240. }
  241. gpsd_zero_satellites(&session->gpsdata);
  242. /* Merge the satellite information from the Bb message. */
  243. Bbused = 0;
  244. nsv = 0;
  245. for (i = st = 0; i < 8; i++) {
  246. int sv, mode, sn, status;
  247. unsigned int off;
  248. off = 40 + 4 * i;
  249. sv = (int)getub(buf, off);
  250. mode = (int)getub(buf, off + 1);
  251. sn = (int)getub(buf, off + 2);
  252. status = (int)getub(buf, off + 3);
  253. GPSD_LOG(LOG_DATA, &session->context->errout,
  254. "%2d %2d %2d %3d %02x\n", i, sv, mode, sn, status);
  255. if (sn) {
  256. session->gpsdata.skyview[st].PRN = (short)sv;
  257. session->gpsdata.skyview[st].ss = (double)sn;
  258. for (j = 0; (int)j < session->driver.oncore.visible; j++)
  259. if (session->driver.oncore.PRN[j] == sv) {
  260. session->gpsdata.skyview[st].elevation =
  261. (double)session->driver.oncore.elevation[j];
  262. session->gpsdata.skyview[st].azimuth =
  263. (double)session->driver.oncore.azimuth[j];
  264. Bbused |= 1 << j;
  265. break;
  266. }
  267. /* bit 7 of the status word: sat used for position */
  268. session->gpsdata.skyview[st].used = false;
  269. if (status & 0x80) {
  270. session->gpsdata.skyview[st].used = true;
  271. nsv++;
  272. }
  273. /* bit 2 of the status word: using for time solution */
  274. if (status & 0x02)
  275. mask |= NTPTIME_IS | GOODTIME_IS;
  276. /*
  277. * The GOODTIME_IS mask bit exists distinctly from TIME_SET exactly
  278. * so an OnCore running in time-service mode (and other GPS clocks)
  279. * can signal that it's returning time even though no position fixes
  280. * have been available.
  281. */
  282. st++;
  283. }
  284. }
  285. for (j = 0; (int)j < session->driver.oncore.visible; j++)
  286. if (!(Bbused & (1 << j))) {
  287. session->gpsdata.skyview[st].PRN =
  288. (short)session->driver.oncore.PRN[j];
  289. session->gpsdata.skyview[st].elevation =
  290. (double)session->driver.oncore.elevation[j];
  291. session->gpsdata.skyview[st].azimuth =
  292. (double)session->driver.oncore.azimuth[j];
  293. st++;
  294. }
  295. session->gpsdata.skyview_time = session->newdata.time;
  296. session->gpsdata.satellites_used = (int)nsv;
  297. session->gpsdata.satellites_visible = (int)st;
  298. mask |= SATELLITE_SET | USED_IS;
  299. /* Some messages can only be polled. As they are not so
  300. * important, would be enough to poll e.g. one message per cycle.
  301. */
  302. (void)oncore_control_send(session, (char *)pollAs, sizeof(pollAs));
  303. (void)oncore_control_send(session, (char *)pollAt, sizeof(pollAt));
  304. (void)oncore_control_send(session, (char *)pollAw, sizeof(pollAw));
  305. (void)oncore_control_send(session, (char *)pollAy, sizeof(pollAy));
  306. (void)oncore_control_send(session, (char *)pollBo, sizeof(pollBo));
  307. (void)oncore_control_send(session, (char *)pollEn, sizeof(pollEn));
  308. GPSD_LOG(LOG_DATA, &session->context->errout,
  309. "NAVSOL: time=%s lat=%.2f lon=%.2f altMSL=%.2f speed=%.2f "
  310. "track=%.2f mode=%d status=%d visible=%d used=%d\n",
  311. timespec_str(&session->newdata.time, ts_buf, sizeof(ts_buf)),
  312. session->newdata.latitude,
  313. session->newdata.longitude, session->newdata.altHAE,
  314. session->newdata.speed, session->newdata.track,
  315. session->newdata.mode, session->newdata.status,
  316. session->gpsdata.satellites_used,
  317. session->gpsdata.satellites_visible);
  318. return mask;
  319. }
  320. /**
  321. * GPS Leap Seconds = UTC offset
  322. */
  323. static gps_mask_t
  324. oncore_msg_utc_offset(struct gps_device_t *session, unsigned char *buf,
  325. size_t data_len)
  326. {
  327. int utc_offset;
  328. if (data_len != 8)
  329. return 0;
  330. utc_offset = (int)getub(buf, 4);
  331. GPSD_LOG(LOG_DATA, &session->context->errout,
  332. "oncore UTCTIME - leap seconds: %d\n", utc_offset);
  333. if (utc_offset == 0)
  334. return 0; /* that part of almanac not received yet */
  335. session->context->leap_seconds = utc_offset;
  336. session->context->valid |= LEAP_SECOND_VALID;
  337. return 0; /* no flag for leap seconds update */
  338. }
  339. /**
  340. * Pos hold mode
  341. *
  342. * @@AtmC<CR><LF>
  343. *
  344. * m - mode, 0=off, 1=on, 2=surveying
  345. */
  346. static gps_mask_t
  347. oncore_msg_pos_hold_mode(struct gps_device_t *session, unsigned char *buf,
  348. size_t data_len)
  349. {
  350. int pos_hold_mode;
  351. if (data_len != 8)
  352. return 0;
  353. pos_hold_mode = (int)getub(buf, 4);
  354. GPSD_LOG(LOG_DATA, &session->context->errout,
  355. "oncore pos hold mode: %d\n", pos_hold_mode);
  356. /* Add 1 to distinguish an unknown (not set) value from mode off. */
  357. session->driver.oncore.pos_hold_mode = pos_hold_mode + 1;
  358. return 0;
  359. }
  360. /**
  361. * PPS offset
  362. */
  363. static gps_mask_t
  364. oncore_msg_pps_offset(struct gps_device_t *session, unsigned char *buf,
  365. size_t data_len)
  366. {
  367. int pps_offset_ns;
  368. if (data_len != 11)
  369. return 0;
  370. pps_offset_ns = (int)getbes32(buf, 4);
  371. GPSD_LOG(LOG_DATA, &session->context->errout,
  372. "oncore PPS offset: %d\n", pps_offset_ns);
  373. session->driver.oncore.pps_offset_ns = pps_offset_ns;
  374. return 0;
  375. }
  376. /**
  377. * GPS Satellite Info
  378. */
  379. static gps_mask_t
  380. oncore_msg_svinfo(struct gps_device_t *session, unsigned char *buf,
  381. size_t data_len)
  382. {
  383. unsigned int i, nchan;
  384. if (data_len != 92)
  385. return 0;
  386. GPSD_LOG(LOG_DATA, &session->context->errout,
  387. "oncore SVINFO - satellite data\n");
  388. nchan = (unsigned int)getub(buf, 4);
  389. GPSD_LOG(LOG_DATA, &session->context->errout,
  390. "oncore SVINFO - %d satellites:\n", nchan);
  391. /* Then we clamp the value to not read outside the table. */
  392. if (nchan > 12)
  393. nchan = 12;
  394. session->driver.oncore.visible = (int)nchan;
  395. for (i = 0; i < nchan; i++) {
  396. /* get info for one channel/satellite */
  397. unsigned int off = 5 + 7 * i;
  398. int sv = (int)getub(buf, off);
  399. int el = (int)getub(buf, off + 3);
  400. int az = (int)getbeu16(buf, off + 4);
  401. GPSD_LOG(LOG_DATA, &session->context->errout,
  402. "%2d %2d %2d %3d\n", i, sv, el, az);
  403. /* Store for use when Ea messages come. */
  404. session->driver.oncore.PRN[i] = sv;
  405. session->driver.oncore.elevation[i] = (short)el;
  406. session->driver.oncore.azimuth[i] = (short)az;
  407. }
  408. return 0;
  409. }
  410. /**
  411. * GPS Time Mode
  412. *
  413. * @@AwmC<CR><LF>
  414. *
  415. * m - mode, 0=GPS, 1=UTC
  416. */
  417. static gps_mask_t
  418. oncore_msg_time_mode(struct gps_device_t *session UNUSED,
  419. unsigned char *buf UNUSED, size_t data_len UNUSED)
  420. {
  421. int time_mode;
  422. if (data_len != 8)
  423. return 0;
  424. time_mode = (int)getub(buf, 4);
  425. GPSD_LOG(LOG_DATA, &session->context->errout,
  426. "oncore time mode (0=GPS, 1=UTC): %d\n",time_mode);
  427. return 0;
  428. }
  429. /**
  430. * GPS Time RAIM
  431. */
  432. static gps_mask_t
  433. oncore_msg_time_raim(struct gps_device_t *session UNUSED,
  434. unsigned char *buf UNUSED, size_t data_len UNUSED)
  435. {
  436. int sawtooth_ns;
  437. if (data_len != 69)
  438. return 0;
  439. sawtooth_ns = (int)getub(buf, 25);
  440. GPSD_LOG(LOG_DATA, &session->context->errout,
  441. "oncore PPS sawtooth: %d\n",sawtooth_ns);
  442. /* session->driver.oncore.traim_sawtooth_ns = sawtooth_ns; */
  443. return 0;
  444. }
  445. /**
  446. * GPS Firmware
  447. */
  448. static gps_mask_t
  449. oncore_msg_firmware(struct gps_device_t *session UNUSED,
  450. unsigned char *buf UNUSED, size_t data_len UNUSED)
  451. {
  452. return 0;
  453. }
  454. #define ONCTYPE(id2,id3) ((((unsigned int)id2)<<8)|(id3))
  455. /**
  456. * Parse the data from the device
  457. */
  458. gps_mask_t oncore_dispatch(struct gps_device_t * session, unsigned char *buf,
  459. size_t len)
  460. {
  461. unsigned int type;
  462. if (len == 0)
  463. return 0;
  464. type = ONCTYPE(buf[2], buf[3]);
  465. /* we may need to dump the raw packet */
  466. GPSD_LOG(LOG_RAW, &session->context->errout,
  467. "raw Oncore packet type 0x%04x\n", type);
  468. session->cycle_end_reliable = true;
  469. switch (type) {
  470. case ONCTYPE('B', 'b'):
  471. return oncore_msg_svinfo(session, buf, len);
  472. case ONCTYPE('E', 'a'):
  473. return oncore_msg_navsol(session, buf, len) | (CLEAR_IS | REPORT_IS);
  474. case ONCTYPE('E', 'n'):
  475. return oncore_msg_time_raim(session, buf, len);
  476. case ONCTYPE('C', 'j'):
  477. return oncore_msg_firmware(session, buf, len);
  478. case ONCTYPE('B', 'o'):
  479. return oncore_msg_utc_offset(session, buf, len);
  480. case ONCTYPE('A', 's'):
  481. return 0; /* position hold position */
  482. case ONCTYPE('A', 't'):
  483. return oncore_msg_pos_hold_mode(session, buf, len);
  484. case ONCTYPE('A', 'w'):
  485. return oncore_msg_time_mode(session, buf, len);
  486. case ONCTYPE('A', 'y'):
  487. return oncore_msg_pps_offset(session, buf, len);
  488. default:
  489. /* FIX-ME: This gets noisy in a hurry. Change once your driver works */
  490. GPSD_LOG(LOG_WARN, &session->context->errout,
  491. "unknown packet id @@%c%c length %zd\n",
  492. type >> 8, type & 0xff, len);
  493. return 0;
  494. }
  495. }
  496. /**********************************************************
  497. *
  498. * Externally called routines below here
  499. *
  500. **********************************************************/
  501. /**
  502. * Write data to the device, doing any required padding or checksumming
  503. */
  504. static ssize_t oncore_control_send(struct gps_device_t *session,
  505. char *msg, size_t msglen)
  506. {
  507. size_t i;
  508. char checksum = 0;
  509. session->msgbuf[0] = '@';
  510. session->msgbuf[1] = '@';
  511. for (i = 0; i < msglen; i++) {
  512. checksum ^= session->msgbuf[i + 2] = msg[i];
  513. }
  514. session->msgbuf[msglen + 2] = checksum;
  515. session->msgbuf[msglen + 3] = '\r';
  516. session->msgbuf[msglen + 4] = '\n';
  517. session->msgbuflen = msglen + 5;
  518. GPSD_LOG(LOG_PROG, &session->context->errout,
  519. "writing oncore control type %c%c\n", msg[0], msg[1]);
  520. return gpsd_write(session, session->msgbuf, session->msgbuflen);
  521. }
  522. static void oncore_event_hook(struct gps_device_t *session, event_t event)
  523. {
  524. if (session->context->readonly)
  525. return;
  526. /*
  527. * Some oncore VP variants that have not been used after long
  528. * power-down will be silent on startup. Provoke
  529. * identification by requesting the firmware version.
  530. */
  531. if (event == event_wakeup)
  532. (void)oncore_control_send(session, getfirmware, sizeof(getfirmware));
  533. if (session->context->passive) {
  534. return;
  535. }
  536. /*
  537. * FIX-ME: It might not be necessary to call this on reactivate.
  538. * Experiment to see if the holds its settings through a close.
  539. */
  540. if (event == event_identified || event == event_reactivate) {
  541. (void)oncore_control_send(session, enableEa, sizeof(enableEa));
  542. (void)oncore_control_send(session, enableBb, sizeof(enableBb));
  543. /*(void)oncore_control_send(session, enableEn, sizeof(enableEn)); */
  544. /*(void)oncore_control_send(session,enableAt2,sizeof(enableAt2)); */
  545. /*(void)oncore_control_send(session,pollAs,sizeof(pollAs)); */
  546. (void)oncore_control_send(session, (char*)pollBo, sizeof(pollBo));
  547. }
  548. }
  549. static double oncore_time_offset(struct gps_device_t *session UNUSED)
  550. {
  551. /*
  552. * Only one sentence (NAVSOL) ships time. 0.175 seems best at
  553. * 9600 for UT+, not sure what the fudge should be at other baud
  554. * rates or for other models.
  555. */
  556. return 0.175;
  557. }
  558. static gps_mask_t oncore_parse_input(struct gps_device_t *session)
  559. {
  560. if (session->lexer.type == ONCORE_PACKET) {
  561. return oncore_dispatch(session, session->lexer.outbuffer,
  562. session->lexer.outbuflen);
  563. #ifdef NMEA0183_ENABLE
  564. } else if (session->lexer.type == NMEA_PACKET) {
  565. return nmea_parse((char *)session->lexer.outbuffer, session);
  566. #endif /* NMEA0183_ENABLE */
  567. } else
  568. return 0;
  569. }
  570. /* This is everything we export */
  571. /* *INDENT-OFF* */
  572. const struct gps_type_t driver_oncore = {
  573. .type_name = "Motorola Oncore", /* Full name of type */
  574. .packet_type = ONCORE_PACKET, /* numeric packet type */
  575. .flags = DRIVER_STICKY, /* remember this */
  576. .trigger = NULL, /* identifying response */
  577. .channels = 12, /* device channel count */
  578. .probe_detect = NULL, /* no probe */
  579. .get_packet = generic_get, /* packet getter */
  580. .parse_packet = oncore_parse_input, /* packet parser */
  581. .rtcm_writer = gpsd_write, /* device accepts RTCM */
  582. .init_query = NULL, /* non-perturbing query */
  583. .event_hook = oncore_event_hook, /* lifetime event hook */
  584. .speed_switcher = NULL, /* no speed setter */
  585. .mode_switcher = NULL, /* no mode setter */
  586. .rate_switcher = NULL, /* no speed setter */
  587. .min_cycle.tv_sec = 1, /* 1Hz */
  588. .min_cycle.tv_nsec = 0,
  589. /* Control string sender - should provide checksum and headers/trailer */
  590. .control_send = oncore_control_send, /* to send control strings */
  591. .time_offset = oncore_time_offset, /* NTP offset array */
  592. };
  593. /* *INDENT-ON* */
  594. #endif /* defined(ONCORE_ENABLE) && defined(BINARY_ENABLE) */
  595. // vim: set expandtab shiftwidth=4