driver_geostar.c 22 KB

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