You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

driver_geostar.c 18KB

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