driver_geostar.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641
  1. /*
  2. * This is the gpsd driver for GeoStar Navigation receivers
  3. * operating in binary mode.
  4. *
  5. * Tested with GeoS-1M GPS/GLONASS receiver.
  6. *
  7. * By Viktar Palstsiuk, viktar.palstsiuk@promwad.com
  8. *
  9. * This file is Copyright 2010 by the GPSD project
  10. * SPDX-License-Identifier: BSD-2-clause
  11. */
  12. #include "gpsd_config.h" /* must be before all includes */
  13. #include <math.h>
  14. #include <stdbool.h>
  15. #include <stdio.h>
  16. #include <string.h>
  17. #include "bits.h"
  18. #include "gpsd.h"
  19. #include "strfuncs.h"
  20. #include "timespec.h"
  21. #ifdef GEOSTAR_ENABLE
  22. #define GEOSTAR_CHANNELS 24
  23. #define JAN_2008 0x47798280 /* 1199145600 = 2008 - 1970 in seconds */
  24. #define OFFSET(n) ((n)*4+4)
  25. static int decode_channel_id (uint32_t ch_id) {
  26. int num = 0;
  27. num = (int)(ch_id & 0x1F); /* SV ID */
  28. if((ch_id & (1<<30)) == 0) num += GLONASS_PRN_OFFSET; /* GLONASS SV */
  29. else if (num == 0 ) num = 32; /* GPS SV */
  30. return num;
  31. }
  32. static int geostar_write(struct gps_device_t *session,
  33. unsigned int id, unsigned char *data, size_t len)
  34. {
  35. int i;
  36. unsigned long cs = 0;
  37. putbyte(session->msgbuf, 0, 'P');
  38. putbyte(session->msgbuf, 1, 'S');
  39. putbyte(session->msgbuf, 2, 'G');
  40. putbyte(session->msgbuf, 3, 'G');
  41. putbe16(session->msgbuf, 4, id);
  42. putbe16(session->msgbuf, 6, len);
  43. /* Copy content */
  44. memcpy(session->msgbuf + 8, data, len * 4);
  45. len += 2; /* PSGG + id + len */
  46. /* Calculate checksum */
  47. for (i = 0; (size_t)i < len; i++) {
  48. cs ^= getleu32(session->msgbuf, i * 4);
  49. }
  50. putle32(session->msgbuf, len * 4, cs);
  51. len += 1; /* Checksum */
  52. session->msgbuflen = len * 4;
  53. GPSD_LOG(LOG_PROG, &session->context->errout,
  54. "Sent GeoStar packet id 0x%x\n", id);
  55. if (gpsd_write(session, session->msgbuf, session->msgbuflen) !=
  56. (ssize_t) session->msgbuflen)
  57. return -1;
  58. return 0;
  59. }
  60. /* geostar_detect()
  61. *
  62. * see if it looks like a GeoStar device is listening and
  63. * return 1 if found, 0 if not
  64. */
  65. static bool geostar_detect(struct gps_device_t *session)
  66. {
  67. unsigned char buf[1 * 4];
  68. bool ret = false;
  69. int myfd;
  70. myfd = session->gpsdata.gps_fd;
  71. /* request firmware revision and look for a valid response */
  72. putbe32(buf, 0, 0);
  73. if (geostar_write(session, 0xc1, buf, 1) == 0) {
  74. unsigned int n;
  75. struct timespec to;
  76. // FIXME: this holds the main loop from running...
  77. for (n = 0; n < 3; n++) {
  78. // wait one second
  79. to.tv_sec = 1;
  80. to.tv_nsec = 0;
  81. if (!nanowait(myfd, &to))
  82. break;
  83. if (generic_get(session) >= 0) {
  84. if (session->lexer.type == GEOSTAR_PACKET) {
  85. GPSD_LOG(LOG_RAW, &session->context->errout,
  86. "geostar_detect found\n");
  87. ret = true;
  88. break;
  89. }
  90. }
  91. }
  92. }
  93. return ret;
  94. }
  95. static gps_mask_t geostar_analyze(struct gps_device_t *session)
  96. {
  97. int i, len;
  98. gps_mask_t mask = 0;
  99. unsigned int id;
  100. uint16_t uw1, uw2;
  101. uint32_t ul1, ul2, ul3, ul4, ul5;
  102. double d1, d2, d3, d4, d5;
  103. char buf[BUFSIZ];
  104. char buf2[BUFSIZ];
  105. if (session->lexer.type != GEOSTAR_PACKET) {
  106. GPSD_LOG(LOG_INF, &session->context->errout,
  107. "geostar_analyze packet type %d\n",
  108. session->lexer.type);
  109. return 0;
  110. }
  111. if (session->lexer.outbuflen < 12 || session->lexer.outbuffer[0] != 'P')
  112. return 0;
  113. /* put data part of message in buf */
  114. memset(buf, 0, sizeof(buf));
  115. /* cppcheck-suppress redundantCopy */
  116. memcpy(buf, session->lexer.outbuffer, session->lexer.outbuflen);
  117. buf2[len = 0] = '\0';
  118. for (i = 0; i < (int)session->lexer.outbuflen; i++) {
  119. str_appendf(buf2, sizeof(buf2),
  120. "%02x", buf[len++] = session->lexer.outbuffer[i]);
  121. }
  122. id = (unsigned int)getleu16(session->lexer.outbuffer, OFFSET(0));
  123. GPSD_LOG(LOG_DATA, &session->context->errout,
  124. "GeoStar packet id 0x%02x length %d: %s\n", id, len, buf2);
  125. session->cycle_end_reliable = true;
  126. switch (id) {
  127. case 0x10:
  128. GPSD_LOG(LOG_INF, &session->context->errout, "Raw measurements\n");
  129. break;
  130. case 0x11:
  131. GPSD_LOG(LOG_INF, &session->context->errout, "GPS sub-frame data\n");
  132. break;
  133. case 0x12:
  134. GPSD_LOG(LOG_INF, &session->context->errout,
  135. "GLONASS sub-frame data\n");
  136. break;
  137. case 0x13:
  138. d1 = getled64(buf, OFFSET(1));
  139. d2 = getled64(buf, OFFSET(3));
  140. d3 = getled64(buf, OFFSET(5));
  141. d4 = getled64(buf, OFFSET(29)); /* GPS time */
  142. d5 = getled64(buf, OFFSET(31)); /* GLONASS time */
  143. GPSD_LOG(LOG_INF, &session->context->errout,
  144. "ECEF coordinates %g %g %g %f %f\n", d1, d2, d3, d4, d5);
  145. break;
  146. case 0x20:
  147. d1 = getled64(buf, OFFSET(1)); /* time */
  148. DTOTS(&session->newdata.time, d1);
  149. session->newdata.time.tv_sec += JAN_2008;
  150. session->newdata.latitude = getled64(buf, OFFSET(3)) * RAD_2_DEG;
  151. session->newdata.longitude = getled64(buf, OFFSET(5)) * RAD_2_DEG;
  152. /* altitude above ellipsoid */
  153. session->newdata.altHAE = getled64(buf, OFFSET(7));
  154. session->newdata.geoid_sep = getled64(buf, OFFSET(9));
  155. session->gpsdata.satellites_used = (int)getles32(buf, OFFSET(11));
  156. session->gpsdata.dop.gdop = getled64(buf, OFFSET(13));
  157. session->gpsdata.dop.pdop = getled64(buf, OFFSET(15));
  158. session->gpsdata.dop.tdop = getled64(buf, OFFSET(17));
  159. session->gpsdata.dop.hdop = getled64(buf, OFFSET(19));
  160. session->gpsdata.dop.vdop = getled64(buf, OFFSET(21));
  161. session->newdata.speed = getled64(buf, OFFSET(31));
  162. session->newdata.track = getled64(buf, OFFSET(33)) * RAD_2_DEG;
  163. ul1 = getleu32(buf, OFFSET(29)); /* status */
  164. if (ul1 != 0) {
  165. session->newdata.status = STATUS_NO_FIX;
  166. mask |= STATUS_SET;
  167. } else {
  168. if (session->newdata.status < STATUS_FIX) {
  169. session->newdata.status = STATUS_FIX;
  170. mask |= STATUS_SET;
  171. }
  172. }
  173. mask |= TIME_SET | NTPTIME_IS | LATLON_SET | ALTITUDE_SET |
  174. SPEED_SET | STATUS_SET | TRACK_SET | DOP_SET | USED_IS |
  175. REPORT_IS;
  176. GPSD_LOG(LOG_INF, &session->context->errout,
  177. "Geographic coordinates %f %g %g %g %g %g\n",
  178. d1,
  179. session->newdata.latitude,
  180. session->newdata.longitude,
  181. session->newdata.altHAE,
  182. session->newdata.speed,
  183. session->newdata.track);
  184. GPSD_LOG(LOG_INF, &session->context->errout,
  185. "Dilution of precision %g %g %g %g %g\n",
  186. session->gpsdata.dop.gdop,
  187. session->gpsdata.dop.pdop,
  188. session->gpsdata.dop.tdop,
  189. session->gpsdata.dop.hdop,
  190. session->gpsdata.dop.vdop);
  191. break;
  192. case 0x21:
  193. ul1 = getleu32(buf, OFFSET(1));
  194. ul2 = getleu32(buf, OFFSET(2));
  195. uw1 = getleu16(buf, OFFSET(3));
  196. uw2 = getleu16(buf, OFFSET(3) + 2);
  197. GPSD_LOG(LOG_INF, &session->context->errout,
  198. "Current receiver telemetry %x %d %d %d\n",
  199. ul1, ul2, uw1, uw2);
  200. if(ul1 & (1<<3)) {
  201. session->newdata.mode = MODE_2D;
  202. }
  203. else {
  204. session->newdata.mode = MODE_3D;
  205. }
  206. if(ul1 & (1<<2)) {
  207. session->newdata.status = STATUS_FIX;
  208. }
  209. else {
  210. session->newdata.status = STATUS_NO_FIX;
  211. session->newdata.mode = MODE_NO_FIX;
  212. }
  213. mask |= MODE_SET | STATUS_SET;
  214. break;
  215. case 0x22:
  216. ul1 = getleu32(buf, OFFSET(1));
  217. GPSD_LOG(LOG_INF, &session->context->errout, "SVs in view %d\n", ul1);
  218. session->gpsdata.satellites_visible = (int)ul1;
  219. if(ul1 > GEOSTAR_CHANNELS) ul1 = GEOSTAR_CHANNELS;
  220. for(i = 0; (uint32_t)i < ul1; i++) {
  221. int16_t s1, s2, s3;
  222. ul2 = getleu32(buf, OFFSET(2) + i * 3 * 4);
  223. s1 = getles16(buf, OFFSET(3) + i * 3 * 4);
  224. s2 = getles16(buf, OFFSET(3) + 2 + i * 3 * 4);
  225. s3 = getles16(buf, OFFSET(4) + 2 + i * 3 * 4);
  226. GPSD_LOG(LOG_INF, &session->context->errout,
  227. "ID %d Az %g El %g SNR %g\n",
  228. decode_channel_id(ul2), s1 * 0.001 * RAD_2_DEG,
  229. s2 * 0.001 * RAD_2_DEG, s3 * 0.1);
  230. session->gpsdata.skyview[i].PRN = (short)decode_channel_id(ul2);
  231. session->gpsdata.skyview[i].azimuth =
  232. (short)round((double)s1 * 0.001 * RAD_2_DEG);
  233. session->gpsdata.skyview[i].elevation =
  234. (short)round((double)s2 * 0.001 * RAD_2_DEG);
  235. session->gpsdata.skyview[i].ss = (double)s3*0.1;
  236. session->gpsdata.skyview[i].used = (bool)(ul2 & (1<<27));
  237. }
  238. session->gpsdata.skyview_time.tv_sec = 0;
  239. session->gpsdata.skyview_time.tv_nsec = 0;
  240. mask |= SATELLITE_SET | USED_IS;
  241. break;
  242. case 0x3e:
  243. ul1 = getleu32(buf, OFFSET(1));
  244. ul2 = getleu32(buf, OFFSET(2));
  245. ul3 = getleu32(buf, OFFSET(3));
  246. GPSD_LOG(LOG_INF, &session->context->errout,
  247. "Receiver power-up message %d %d %d\n", ul1, ul2, ul3);
  248. break;
  249. case 0x3f:
  250. ul1 = getleu32(buf, OFFSET(1));
  251. ul2 = getleu32(buf, OFFSET(2));
  252. GPSD_LOG(LOG_WARN, &session->context->errout,
  253. "Negative acknowledge %x %d\n", ul1, ul2);
  254. break;
  255. case 0x40:
  256. GPSD_LOG(LOG_INF, &session->context->errout,
  257. "Response to Set initial parameters\n");
  258. break;
  259. case 0x41:
  260. GPSD_LOG(LOG_INF, &session->context->errout,
  261. "Response to Set serial ports parameters\n");
  262. break;
  263. case 0x42:
  264. ul1 = getleu32(buf, OFFSET(1));
  265. ul2 = getleu32(buf, OFFSET(2));
  266. ul3 = getleu32(buf, OFFSET(3));
  267. GPSD_LOG(LOG_INF, &session->context->errout,
  268. "Response to Set receiver operation mode %d %d %d\n",
  269. ul1, ul2, ul3);
  270. break;
  271. case 0x43:
  272. GPSD_LOG(LOG_INF, &session->context->errout,
  273. "Response to Set navigation task solution parameters\n");
  274. break;
  275. case 0x44:
  276. GPSD_LOG(LOG_INF, &session->context->errout,
  277. "Response to Set output data rate\n");
  278. break;
  279. case 0x46:
  280. GPSD_LOG(LOG_INF, &session->context->errout,
  281. "Response to Assign data protocol to communication port\n");
  282. break;
  283. case 0x48:
  284. GPSD_LOG(LOG_INF, &session->context->errout,
  285. "Response to Set GPS almanac\n");
  286. break;
  287. case 0x49:
  288. GPSD_LOG(LOG_INF, &session->context->errout,
  289. "Response to Set GLONASS almanac\n");
  290. break;
  291. case 0x4a:
  292. GPSD_LOG(LOG_INF, &session->context->errout,
  293. "Response to Set GPS ephemeris\n");
  294. break;
  295. case 0x4b:
  296. GPSD_LOG(LOG_INF, &session->context->errout,
  297. "Response to Set GLONASS ephemeris\n");
  298. break;
  299. case 0x4c:
  300. ul1 = getleu32(buf, OFFSET(1));
  301. ul2 = getleu32(buf, OFFSET(2));
  302. ul3 = getleu32(buf, OFFSET(3));
  303. ul4 = getleu32(buf, OFFSET(4));
  304. ul5 = getleu32(buf, OFFSET(5));
  305. GPSD_LOG(LOG_INF, &session->context->errout,
  306. "Response to Set PPS parameters %d %d %d %d %d\n",
  307. ul1, ul2, ul3, ul4, ul5);
  308. break;
  309. case 0x4d:
  310. GPSD_LOG(LOG_INF, &session->context->errout,
  311. "Response to Enable/disable SV in position fix\n");
  312. break;
  313. case 0x4e:
  314. GPSD_LOG(LOG_INF, &session->context->errout,
  315. "Response to Enable/disable NMEA messages\n");
  316. break;
  317. case 0x4f:
  318. ul1 = getleu32(buf, OFFSET(1));
  319. ul2 = getleu32(buf, OFFSET(2));
  320. GPSD_LOG(LOG_INF, &session->context->errout,
  321. "Response to Enable/disable binary messages %x %x\n",
  322. ul1, ul2);
  323. break;
  324. case 0x80:
  325. GPSD_LOG(LOG_INF, &session->context->errout,
  326. "Response to Query initial parameters\n");
  327. break;
  328. case 0x81:
  329. GPSD_LOG(LOG_INF, &session->context->errout,
  330. "Response to Query serial ports parameters\n");
  331. break;
  332. case 0x82:
  333. ul1 = getleu32(buf, OFFSET(1));
  334. ul2 = getleu32(buf, OFFSET(2));
  335. ul3 = getleu32(buf, OFFSET(3));
  336. GPSD_LOG(LOG_INF, &session->context->errout,
  337. "Response to Query receiver operation mode %d %d %d\n",
  338. ul1, ul2, ul3);
  339. break;
  340. case 0x83:
  341. GPSD_LOG(LOG_INF, &session->context->errout,
  342. "Response to Query navigation task solution parameters\n");
  343. break;
  344. case 0x84:
  345. GPSD_LOG(LOG_INF, &session->context->errout,
  346. "Response to Query output data rate\n");
  347. break;
  348. case 0x86:
  349. session->driver.geostar.physical_port =
  350. (unsigned int)getleu32(buf, OFFSET(1));
  351. GPSD_LOG(LOG_INF, &session->context->errout,
  352. "Response to Query data protocol assignment to "
  353. "communication port\n");
  354. GPSD_LOG(LOG_INF, &session->context->errout,
  355. "Connected to physical port %d\n",
  356. session->driver.geostar.physical_port);
  357. break;
  358. case 0x88:
  359. GPSD_LOG(LOG_INF, &session->context->errout,
  360. "Response to Query GPS almanac\n");
  361. break;
  362. case 0x89:
  363. GPSD_LOG(LOG_INF, &session->context->errout,
  364. "Response to Query GLONASS almanac\n");
  365. break;
  366. case 0x8a:
  367. GPSD_LOG(LOG_INF, &session->context->errout,
  368. "Response to Query GPS ephemerides\n");
  369. break;
  370. case 0x8b:
  371. d1 = getled64(buf, OFFSET(23));
  372. d2 = getled64(buf, OFFSET(25));
  373. d3 = getled64(buf, OFFSET(27));
  374. GPSD_LOG(LOG_INF, &session->context->errout,
  375. "Response to Query GLONASS ephemerides %g %g %g\n",
  376. d1, d2, d3);
  377. break;
  378. case 0x8c:
  379. ul1 = getleu32(buf, OFFSET(1));
  380. ul2 = getleu32(buf, OFFSET(2));
  381. ul3 = getleu32(buf, OFFSET(3));
  382. ul4 = getleu32(buf, OFFSET(4));
  383. ul5 = getleu32(buf, OFFSET(5));
  384. GPSD_LOG(LOG_INF, &session->context->errout,
  385. "Response to Query PPS parameters %d %d %d %d %d\n",
  386. ul1, ul2, ul3, ul4, ul5);
  387. break;
  388. case 0x8d:
  389. GPSD_LOG(LOG_INF, &session->context->errout,
  390. "Response to Query enable/disable status of "
  391. "the SV in position fix\n");
  392. break;
  393. case 0x8e:
  394. GPSD_LOG(LOG_INF, &session->context->errout,
  395. "Response to Query enable NMEA messages\n");
  396. break;
  397. case 0x8f:
  398. ul1 = getleu32(buf, OFFSET(1));
  399. ul2 = getleu32(buf, OFFSET(2));
  400. GPSD_LOG(LOG_INF, &session->context->errout,
  401. "Response to Query enable binary messages %x %x\n",
  402. ul1, ul2);
  403. break;
  404. case 0xc0:
  405. GPSD_LOG(LOG_INF, &session->context->errout,
  406. "Response to Change operation mode command\n");
  407. break;
  408. case 0xc1:
  409. ul4 = getleu32(buf, OFFSET(1));
  410. ul1 = getleu32(buf, OFFSET(2));
  411. ul2 = getleu32(buf, OFFSET(3));
  412. ul3 = getleu32(buf, OFFSET(4));
  413. (void)snprintf(session->subtype, sizeof(session->subtype),
  414. "%u.%u %u.%u.%u %x %c-%u\n",
  415. ul4>>16, ul4&0xFFFF, ul1>>9, (ul1>>5)&0xF, ul1&0x1F, ul2,
  416. ul3>>24, ul3&0x00FFFFFF);
  417. GPSD_LOG(LOG_INF, &session->context->errout,
  418. "Response to Request FW version command: %s\n",
  419. session->subtype);
  420. mask |= DEVICEID_SET;
  421. break;
  422. case 0xc2:
  423. GPSD_LOG(LOG_INF, &session->context->errout,
  424. "Response to Restart receiver command\n");
  425. break;
  426. case 0xc3:
  427. GPSD_LOG(LOG_INF, &session->context->errout,
  428. "Response to Store parameters to Flash command\n");
  429. break;
  430. case 0xd0:
  431. GPSD_LOG(LOG_INF, &session->context->errout,
  432. "Response to Erase Flash sector command\n");
  433. break;
  434. case 0xd1:
  435. GPSD_LOG(LOG_INF, &session->context->errout,
  436. "Response to Write data to Flash command\n");
  437. break;
  438. case 0xd2:
  439. GPSD_LOG(LOG_INF, &session->context->errout,
  440. "Response to Store Serial Number command\n");
  441. break;
  442. default:
  443. GPSD_LOG(LOG_WARN, &session->context->errout,
  444. "Unhandled GeoStar packet type 0x%02x\n", id);
  445. break;
  446. }
  447. return mask;
  448. }
  449. static gps_mask_t geostar_parse_input(struct gps_device_t *session)
  450. {
  451. if (session->lexer.type == GEOSTAR_PACKET) {
  452. return geostar_analyze(session);;
  453. } else
  454. return 0;
  455. }
  456. static ssize_t geostar_control_send(struct gps_device_t *session,
  457. char *buf, size_t buflen)
  458. /* not used by the daemon, it's for gpsctl and friends */
  459. {
  460. return (ssize_t) geostar_write(session,
  461. (unsigned int)buf[0],
  462. (unsigned char *)buf + 1, (buflen - 1)/4);
  463. }
  464. static void geostar_init_query(struct gps_device_t *session)
  465. {
  466. unsigned char buf[2 * 4];
  467. /* Poll Software Version */
  468. (void)geostar_write(session, 0xc1, buf, 1);
  469. }
  470. static void geostar_event_hook(struct gps_device_t *session, event_t event)
  471. {
  472. unsigned char buf[2 * 4];
  473. if (session->context->readonly ||
  474. session->context->passive) {
  475. return;
  476. }
  477. if (event == event_identified || event == event_reactivate) {
  478. /* Select binary packets */
  479. putbe32(buf, 0, 0xffff0000);
  480. putbe32(buf, 4, 0);
  481. (void)geostar_write(session, 0x4f, buf, 2);
  482. /* Poll Ports params */
  483. putbe32(buf, 0, 1);
  484. (void)geostar_write(session, 0x81, buf, 1);
  485. putbe32(buf, 0, 0);
  486. (void)geostar_write(session, 0x81, buf, 1);
  487. /* Poll Init params */
  488. (void)geostar_write(session, 0x80, buf, 1);
  489. /* Poll Mode */
  490. (void)geostar_write(session, 0x82, buf, 1);
  491. /* Poll Solution params */
  492. (void)geostar_write(session, 0x83, buf, 1);
  493. /* Poll Output rate */
  494. (void)geostar_write(session, 0x84, buf, 1);
  495. /* Poll Protocols assignment */
  496. (void)geostar_write(session, 0x86, buf, 1);
  497. /* Poll PPS params */
  498. (void)geostar_write(session, 0x8c, buf, 1);
  499. /* Poll NMEA packets selected */
  500. (void)geostar_write(session, 0x8e, buf, 1);
  501. /* Poll binary packets selected */
  502. (void)geostar_write(session, 0x8f, buf, 1);
  503. }
  504. if (event == event_deactivate) {
  505. /* Perform cold restart */
  506. putbe32(buf, 0, 3);
  507. (void)geostar_write(session, 0xc2, buf, 1);
  508. }
  509. }
  510. static bool geostar_speed_switch(struct gps_device_t *session,
  511. speed_t speed, char parity, int stopbits)
  512. {
  513. unsigned char buf[4 * 4];
  514. int iparity;
  515. switch (parity) {
  516. case 'E':
  517. case 2:
  518. parity = (char)2;
  519. break;
  520. case 'O':
  521. case 1:
  522. parity = (char)1;
  523. break;
  524. case 'N':
  525. case 0:
  526. default:
  527. parity = (char)0;
  528. break;
  529. }
  530. iparity = parity;
  531. putbe32(buf, 0, session->driver.geostar.physical_port);
  532. putbe32(buf, 4, speed);
  533. putbe32(buf, 8, stopbits);
  534. putbe32(buf, 12, iparity);
  535. (void)geostar_write(session, 0x41, buf, 4);
  536. return true; /* it would be nice to error-check this */
  537. }
  538. static void geostar_mode(struct gps_device_t *session, int mode)
  539. {
  540. if (mode == MODE_NMEA) {
  541. unsigned char buf[1 * 4];
  542. /* Switch to NMEA mode */
  543. putbe32(buf, 0, 1);
  544. (void)geostar_write(session, 0x46, buf, 1);
  545. } else if (mode == MODE_BINARY) {
  546. /* Switch to binary mode */
  547. (void)nmea_send(session, "$GPSGG,SWPROT");
  548. } else {
  549. GPSD_LOG(LOG_ERROR, &session->context->errout,
  550. "unknown mode %i requested\n", mode);
  551. }
  552. }
  553. static double geostar_time_offset(struct gps_device_t *session UNUSED)
  554. {
  555. return 0.31;
  556. }
  557. /* this is everything we export */
  558. /* *INDENT-OFF* */
  559. const struct gps_type_t driver_geostar =
  560. {
  561. .type_name = "GeoStar", /* full name of type */
  562. .packet_type = GEOSTAR_PACKET, /* associated lexer packet type */
  563. .flags = DRIVER_STICKY, /* remember this */
  564. .trigger = NULL, /* no trigger */
  565. .channels = GEOSTAR_CHANNELS, /* consumer-grade GPS/GLONASS */
  566. .probe_detect = geostar_detect, /* probe for device */
  567. .get_packet = generic_get, /* use the generic packet getter */
  568. .parse_packet = geostar_parse_input, /* parse message packets */
  569. .rtcm_writer = NULL, /* doesn't accept DGPS corrections */
  570. .init_query = geostar_init_query, // non-perturbing initial query
  571. .event_hook = geostar_event_hook, // fire on various lifetime events
  572. .speed_switcher = geostar_speed_switch,/* change baud rate */
  573. .mode_switcher = geostar_mode, /* there is a mode switcher */
  574. .rate_switcher = NULL, /* no rate switcher */
  575. .min_cycle.tv_sec = 1, /* not relevant, no rate switch */
  576. .min_cycle.tv_nsec = 0, /* not relevant, no rate switch */
  577. .control_send = geostar_control_send,/* how to send commands */
  578. .time_offset = geostar_time_offset,
  579. };
  580. /* *INDENT-ON* */
  581. #endif /* GEOSTAR_ENABLE */
  582. // vim: set expandtab shiftwidth=4