driver_evermore.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. /*
  2. * DEPRECATED September 2019
  3. *
  4. * September 2019: Looks like Everymore converted most of their products
  5. * over to using to SiRF and u-blox chips a long time ago. They still offer
  6. * the EB-E26 and EB-E36-5Hz modules, but these appear to be NMEA only. Their
  7. * web site has not documentation: http://www.evermoregps.com.tw/
  8. *
  9. * May 2013: The binary bits were commented out. Then removed in
  10. * September 2019, but will live forever in the git history...
  11. *
  12. * This is the gpsd driver for EverMore GPSes. They have both an NMEA and
  13. * a binary reporting mode, with the interesting property that they will
  14. * cheerfully accept binary commands (such as speed changes) while in NMEA
  15. * mode.
  16. *
  17. * This driver seems to be a subset of driver_sirf.c. Is it needed at all?
  18. *
  19. * Binary mode would give us atomic fix reports, but it has one large drawback:
  20. * the Navigation Data Out message doesn't report a leap-second offset, so it
  21. * is not actually possible to collect a leap-second offset from it. Therefore
  22. * we'll normally run the driver in NMEA mode.
  23. *
  24. * About the only thing binary mode gives that NMEA won't is TDOP and raw
  25. * pseudoranges, but gpsd does its own DOPs from skyview. By default we'll
  26. * trade away raw data to get accurate time.
  27. *
  28. * The vendor site is <http://www.emt.com.tw>.
  29. *
  30. * This driver was written by Petr Slansky based on a framework by Eric S.
  31. * Raymond. The following remarks are by Petr Slansky.
  32. *
  33. * Snooping on the serial the communication between a Windows program and
  34. * an Evermore chipset reveals some messages not described in the vendor
  35. * documentation (Issue C of Aug 2002):
  36. *
  37. * 10 02 06 84 00 00 00 84 10 03 switch to binary mode (84 00 00 00)
  38. * 10 02 06 84 01 00 00 85 10 03 switch to NMEA mode (84 01 00 00)
  39. *
  40. * 10 02 06 89 01 00 00 8a 10 03 set baud rate 4800
  41. * 10 02 06 89 01 01 00 8b 10 03 set baud rate 9600
  42. * 10 02 06 89 01 02 00 8c 10 03 set baud rate 19200
  43. * 10 02 06 89 01 03 00 8d 10 03 set baud rate 38400
  44. *
  45. * 10 02 06 8D 00 01 00 8E 10 03 switch to datum ID 001 (WGS-84)
  46. * 10 02 06 8D 00 D8 00 65 10 03 switch to datum ID 217 (WGS-72)
  47. *
  48. * These don't entail a reset of GPS as the 0x80 message does.
  49. *
  50. * 10 02 04 38 85 bd 10 03 answer from GPS to 0x85 message; ACK message
  51. * 10 02 04 38 8d c5 10 03 answer from GPS to 0x8d message; ACK message
  52. * 10 02 04 38 8e c6 10 03 answer from GPS to 0x8e message; ACK message
  53. * 10 02 04 38 8f c7 10 03 answer from GPS to 0x8f message; ACK message
  54. *
  55. * The chip sometimes sends vendor extension messages with the prefix
  56. * $PEMT,100. After restart, it sends a $PEMT,100 message describing the
  57. * chip's configuration. Here is a sample:
  58. *
  59. * $PEMT,100,05.42g,100303,180,05,1,20,15,08,0,0,2,1*5A
  60. * 100 - message type
  61. * 05.42g - firmware version
  62. * 100303 - date of firmware release DDMMYY
  63. * 180 - datum ID; 001 is WGS-84
  64. * 05 - default elevation mask; see message 0x86
  65. * 1 - default DOP select, 1 is auto DOP mask; see message 0x87
  66. * 20 - default GDOP; see message 0x87
  67. * 15 - default PDOP
  68. * 08 - default HDOP
  69. * 0 - Normal mode, without 1PPS
  70. * 0 - default position pinning control (0 disable, 1 enable)
  71. * 2 - altitude hold mode (0 disable, 1 always, 2 auto)
  72. * 1 - 2/1 satellite nav mode (0,1,2,3,4)
  73. * 0 disable 2/1 sat nav mode
  74. * 1 hold direction (2 sat)
  75. * 2 clock hold only (2 sat)
  76. * 3 direction hold then clock hold (1 sat)
  77. * 4 clock hold then direction hold (1 sat)
  78. *
  79. * Message $PEMT,100 could be forced with message 0x85 (restart):
  80. * 10 02 12 85 00 00 00 00 00 01 01 00 00 00 00 00 00 00 00 87 10 03
  81. * 0x85 ID, Restart
  82. * 0x00 restart mode (0 default, 1 hot, 2 warm, 3 cold, 4 test)
  83. * 0x00 test start search PRN (1-32)
  84. * 0x00 UTC second (0-59)
  85. * 0x00 UTC Minute (0-59)
  86. * 0x00 UTC Hour (0-23)
  87. * 0x01 UTC Day (1-31)
  88. * 0x01 UTC Month (1-12)
  89. * 0x0000 UTC year (1980+x, uint16)
  90. * 0x0000 Latitude WGS-84 (+/-900, 1/10 degree, + for N, int16)
  91. * 0x0000 Longtitude WGS-84 (+/-1800, 1/10 degree, + for E, int16)
  92. * 0x0000 Altitude WGS-84 (-1000..+18000, meters, int16)
  93. * 0x87 CRC
  94. *
  95. * With message 0x8e it is possible to define how often each NMEA
  96. * message is sent (0-255 seconds). It is possible with message 0x8e
  97. * to activate PEMT,101 messages that have information about time,
  98. * position, velocity and HDOP.
  99. *
  100. * $PEMT,101,1,02,00.0,300906190446,5002.5062,N,01427.6166,E,00259,000,0000*27
  101. * $PEMT,101,2,06,02.1,300906185730,5002.7546,N,01426.9524,E,00323,020,0011*26
  102. * 101 - message type, Compact Navigation Solution
  103. * 2 - position status (1,2,3,4,5,6)
  104. * (1 invalid, 2 2D fix, 3 3D fix, 4 2D with DIFF, 5 3D with DIFF,
  105. * 6 2/1 sat degrade mode)
  106. * 06 - number of used satellites
  107. * 02.1 - DOP (00.0 no fix, HDOP 2D fix, PDOP 3D fix)
  108. * 300906185730 - date and time, UTC ddmmyyHHMMSS (30/09/2006 18:57:30)
  109. * 5002.7546,N - Latitude (degree)
  110. * 01426.9524,E - Longitude (degree)
  111. * 00323 - Altitude (323 metres)
  112. * 020 - heading (20 degrees from true north)
  113. * 0011 - speed over ground (11 metres per second); documentation says km per h
  114. *
  115. * This is an exampe of an 0x8e message that activates all NMEA sentences
  116. * with 1s period:
  117. * 10 02 12 8E 7F 01 01 01 01 01 01 01 01 00 00 00 00 00 00 15 10 03
  118. *
  119. * There is a way to probe for this chipset. When binary message 0x81 is sent:
  120. * 10 02 04 81 13 94 10 03
  121. *
  122. * EverMore will reply with message like this:
  123. * *10 *02 *0D *20 E1 00 00 *00 0A 00 1E 00 32 00 5B *10 *03
  124. * bytes marked with * are fixed
  125. * Message in reply is information about logging configuration of GPS
  126. *
  127. * Another way to detect the EverMore chipset is to send one of the messages
  128. * 0x85, 0x8d, 0x8e or 0x8f and check for a reply.
  129. * The reply message from an EverMore GPS will look like this:
  130. * *10 *02 *04 *38 8d c5 *10 *03
  131. * 8d indicates that message 0x8d was sent;
  132. * c5 is EverMore checksum, other bytes are fixed
  133. *
  134. * This file is Copyright 2010 by the GPSD project
  135. * SPDX-License-Identifier: BSD-2-clause
  136. */
  137. #include "../include/gpsd_config.h" /* must be before all includes */
  138. #include <math.h>
  139. #include <stdbool.h>
  140. #include <stdio.h>
  141. #include <string.h>
  142. #include "../include/gpsd.h"
  143. #if defined(EVERMORE_ENABLE) && defined(BINARY_ENABLE)
  144. #include "../include/bits.h"
  145. #define EVERMORE_CHANNELS 12
  146. static ssize_t evermore_control_send(struct gps_device_t *session, char *buf,
  147. size_t len)
  148. {
  149. unsigned int crc;
  150. size_t i;
  151. char *cp;
  152. /* prepare a DLE-stuffed copy of the message */
  153. cp = session->msgbuf;
  154. *cp++ = 0x10; /* message starts with DLE STX */
  155. *cp++ = 0x02;
  156. session->msgbuflen = (size_t) (len + 2); /* len < 254 !! */
  157. *cp++ = (char)session->msgbuflen; /* message length */
  158. if (session->msgbuflen == 0x10)
  159. *cp++ = 0x10;
  160. /* payload */
  161. crc = 0;
  162. for (i = 0; i < len; i++) {
  163. *cp++ = buf[i];
  164. if (buf[i] == 0x10)
  165. *cp++ = 0x10;
  166. crc += buf[i];
  167. }
  168. crc &= 0xff;
  169. /* enter CRC after payload */
  170. *cp++ = crc;
  171. if (crc == 0x10)
  172. *cp++ = 0x10;
  173. *cp++ = 0x10; /* message ends with DLE ETX */
  174. *cp++ = 0x03;
  175. session->msgbuflen = (size_t) (cp - session->msgbuf);
  176. return gpsd_write(session, session->msgbuf, session->msgbuflen);
  177. }
  178. static bool evermore_protocol(struct gps_device_t *session, int protocol)
  179. {
  180. char tmp8;
  181. char evrm_protocol_config[] = {
  182. (char)0x84, /* 0: msg ID, Protocol Configuration */
  183. (char)0x00, /* 1: mode; EverMore binary(0), NMEA(1) */
  184. (char)0x00, /* 2: reserved */
  185. (char)0x00, /* 3: reserved */
  186. };
  187. GPSD_LOG(LOG_PROG, &session->context->errout,
  188. "evermore_protocol(%d)\n", protocol);
  189. tmp8 = (protocol != 0) ? 1 : 0;
  190. /* NMEA : binary */
  191. evrm_protocol_config[1] = tmp8;
  192. return (evermore_control_send
  193. (session, evrm_protocol_config,
  194. sizeof(evrm_protocol_config)) != -1);
  195. }
  196. /* mode = 0 : EverMore default */
  197. /* mode = 1 : gpsd best */
  198. /* mode = 2 : EverMore search, activate PEMT101 message */
  199. static bool evermore_nmea_config(struct gps_device_t *session, int mode)
  200. {
  201. unsigned char tmp8;
  202. unsigned char evrm_nmeaout_config[] = {
  203. 0x8e, /* 0: msg ID, NMEA Message Control */
  204. 0xff, // 1: NMEA sentence bitmask, GGA(0), GLL(1), GSA(2), GSV(3)...
  205. 0x01, /* 2: nmea checksum no(0), yes(1) */
  206. 1, /* 3: GPGGA, interval 0-255s */
  207. 0, /* 4: GPGLL, interval 0-255s */
  208. 1, /* 5: GPGSA, interval 0-255s */
  209. 1, /* 6: GPGSV, interval 0-255s */
  210. 1, /* 7: GPRMC, interval 0-255s */
  211. 0, /* 8: GPVTG, interval 0-255s */
  212. 0, /* 9: PEMT,101, interval 0-255s */
  213. 0, 0, 0, 0, 0, 0, /* 10-15: reserved */
  214. };
  215. GPSD_LOG(LOG_PROG, &session->context->errout,
  216. "evermore_nmea_config(%d)\n", mode);
  217. tmp8 = (mode == 1) ? 5 : 1;
  218. /* NMEA GPGSV, gpsd */
  219. evrm_nmeaout_config[6] = tmp8; /* GPGSV, 1s or 5s */
  220. tmp8 = (mode == 2) ? 1 : 0;
  221. /* NMEA PEMT101 */
  222. evrm_nmeaout_config[9] = tmp8; /* PEMT101, 1s or 0s */
  223. return (evermore_control_send(session, (char *)evrm_nmeaout_config,
  224. sizeof(evrm_nmeaout_config)) != -1);
  225. }
  226. static void evermore_mode(struct gps_device_t *session, int mode)
  227. {
  228. GPSD_LOG(LOG_PROG, &session->context->errout,
  229. "evermore_mode(%d)\n", mode);
  230. if (mode == MODE_NMEA) {
  231. /* NMEA */
  232. (void)evermore_protocol(session, 1);
  233. /* configure NMEA messages for gpsd */
  234. (void)evermore_nmea_config(session, 1);
  235. } else {
  236. /* binary */
  237. (void)evermore_protocol(session, 0);
  238. }
  239. }
  240. static void evermore_event_hook(struct gps_device_t *session, event_t event)
  241. {
  242. if (session->context->readonly ||
  243. session->context->passive) {
  244. return;
  245. }
  246. /*
  247. * FIX-ME: It might not be necessary to call this on reactivate.
  248. * Experiment to see if the holds its settings through a close.
  249. */
  250. if (event == event_identified || event == event_reactivate) {
  251. /*
  252. * We used to run this driver in binary mode, but that has the
  253. * problem that Evermore binary mode doesn't report a
  254. * leap-second correction in the Navigation Data Out sentence.
  255. * So, run it in NMEA mode to getbUTC corrected by firmware.
  256. * Fortunately the Evermore firmware interprets binary
  257. * commands in NMEA mode, so nothing else needs to change.
  258. */
  259. (void)evermore_mode(session, 0); /* switch GPS to NMEA mode */
  260. /* configure NMEA messages for gpsd (GPGSV every 5s) */
  261. (void)evermore_nmea_config(session, 1);
  262. } else if (event == event_deactivate) {
  263. /* configure NMEA messages to default */
  264. (void)evermore_nmea_config(session, 0);
  265. }
  266. }
  267. static bool evermore_speed(struct gps_device_t *session,
  268. speed_t speed, char parity, int stopbits)
  269. {
  270. GPSD_LOG(LOG_PROG, &session->context->errout,
  271. "evermore_speed(%u%c%d)\n", (unsigned int)speed, parity,
  272. stopbits);
  273. /* parity and stopbit switching aren't available on this chip */
  274. if (parity != session->gpsdata.dev.parity
  275. || stopbits != (int)session->gpsdata.dev.stopbits) {
  276. return false;
  277. } else {
  278. unsigned char tmp8;
  279. unsigned char msg[] = {
  280. 0x89, /* 0: msg ID, Serial Port Configuration */
  281. 0x01, /* 1: bit 0 cfg for main serial, bit 1 cfg for DGPS port */
  282. 0x00, /* 2: main serial baud rate; 4800(0), 9600(1), 19200(2),
  283. * 38400(3) */
  284. 0x00, /* 3: baud rate for DGPS serial port; 4800(0), 9600(1), etc */
  285. };
  286. switch (speed) {
  287. case 4800:
  288. tmp8 = 0;
  289. break;
  290. case 9600:
  291. tmp8 = 1;
  292. break;
  293. case 19200:
  294. tmp8 = 2;
  295. break;
  296. case 38400:
  297. tmp8 = 3;
  298. break;
  299. default:
  300. return false;
  301. }
  302. msg[2] = tmp8;
  303. return (evermore_control_send(session, (char *)msg, sizeof(msg)) !=
  304. -1);
  305. }
  306. }
  307. static bool evermore_rate_switcher(struct gps_device_t *session, double rate)
  308. /* change the sample rate of the GPS */
  309. {
  310. if (rate < 1 || rate > 10) {
  311. GPSD_LOG(LOG_ERROR, &session->context->errout,
  312. "valid rate range is 1-10.\n");
  313. return false;
  314. } else {
  315. unsigned char evrm_rate_config[] = {
  316. 0x84, /* 1: msg ID, Operating Mode Configuration */
  317. 0x02, /* 2: normal mode with 1PPS */
  318. 0x00, /* 3: navigation update rate */
  319. 0x00, /* 4: RF/GPSBBP On Time */
  320. };
  321. evrm_rate_config[2] = (unsigned char)trunc(rate);
  322. return (evermore_control_send(session, (char *)evrm_rate_config,
  323. sizeof(evrm_rate_config)) != -1);
  324. }
  325. }
  326. /* this is everything we export */
  327. /* *INDENT-OFF* */
  328. const struct gps_type_t driver_evermore =
  329. {
  330. .type_name = "EverMore", /* full name of type */
  331. .packet_type = EVERMORE_PACKET, /* lexer packet type */
  332. .flags = DRIVER_STICKY, /* remember this */
  333. .trigger = NULL, /* recognize the type */
  334. .channels = EVERMORE_CHANNELS, /* consumer-grade GPS */
  335. .probe_detect = NULL, /* no probe */
  336. .get_packet = generic_get, /* use generic one */
  337. .parse_packet = generic_parse_input, /* parse message packets */
  338. .rtcm_writer = gpsd_write, /* send RTCM data straight */
  339. .init_query = NULL, /* non-perturbing query */
  340. .event_hook = evermore_event_hook, /* lifetime event handler */
  341. .speed_switcher = evermore_speed, /* we can change baud rates */
  342. .mode_switcher = evermore_mode, /* there is a mode switcher */
  343. .rate_switcher = evermore_rate_switcher, /* change sample rate */
  344. .min_cycle.tv_sec = 1, /* not relevant, no rate switch */
  345. .min_cycle.tv_nsec = 0, /* not relevant, no rate switch */
  346. .control_send = evermore_control_send, // how to send a control string
  347. .time_offset = NULL, /* no method for NTP fudge factor */
  348. };
  349. /* *INDENT-ON* */
  350. #endif /* defined(EVERMORE_ENABLE) && defined(BINARY_ENABLE) */
  351. // vim: set expandtab shiftwidth=4