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.

542 lines
18KB

  1. /*
  2. * A prototype driver. Doesn't run, doesn't even compile.
  3. *
  4. * For new driver authors: replace "_PROTO_" and "_proto_" with the name of
  5. * your new driver. That will give you a skeleton with all the required
  6. * functions defined.
  7. *
  8. * Once that is done, you will likely have to define a large number of
  9. * flags and masks. From there, you will be able to start extracting
  10. * useful quantities. There are roughed-in decoders for the navigation
  11. * solution, satellite status and gps-utc offset. These are the 3 key
  12. * messages that gpsd needs. Some protocols transmit error estimates
  13. * separately from the navigation solution; if developing a driver for
  14. * such a protocol you will need to add a decoder function for that
  15. * message. Be extra careful when using sizeof(<type>) to extract part
  16. * of packets (ie. don't do it). This idiom creates portability problems
  17. * between 32 and 64 bit systems.
  18. *
  19. * For anyone hacking this driver skeleton: "_PROTO_" and "_proto_" are now
  20. * reserved tokens. We suggest that they only ever be used as prefixes,
  21. * but if they are used infix, they must be used in a way that allows a
  22. * driver author to find-and-replace to create a unique namespace for
  23. * driver functions.
  24. *
  25. * If using vi, ":%s/_PROTO_/MYDRIVER/g" and ":%s/_proto_/mydriver/g"
  26. * should produce a source file that comes very close to being useful.
  27. * You will also need to add hooks for your new driver to:
  28. * SConstruct
  29. * drivers.c
  30. * gpsd.h-tail
  31. * libgpsd_core.c
  32. * packet.c
  33. * packet_states.h
  34. *
  35. * This file is Copyright (c) 2010-2018 by the GPSD project
  36. * SPDX-License-Identifier: BSD-2-clause
  37. */
  38. #include "gpsd_config.h" /* must be before all includes */
  39. #include <stdio.h>
  40. #include <stdbool.h>
  41. #include <string.h>
  42. #if defined(_PROTO__ENABLE) && defined(BINARY_ENABLE)
  43. #include "bits.h"
  44. static gps_mask_t _proto__parse_input(struct gps_device_t *);
  45. static gps_mask_t _proto__dispatch(struct gps_device_t *, unsigned char *, size_t );
  46. static gps_mask_t _proto__msg_navsol(struct gps_device_t *, unsigned char *, size_t );
  47. static gps_mask_t _proto__msg_utctime(struct gps_device_t *, unsigned char *, size_t );
  48. static gps_mask_t _proto__msg_svinfo(struct gps_device_t *, unsigned char *, size_t );
  49. static gps_mask_t _proto__msg_raw(struct gps_device_t *, unsigned char *, size_t );
  50. /*
  51. * These methods may be called elsewhere in gpsd
  52. */
  53. static ssize_t _proto__control_send(struct gps_device_t *, char *, size_t);
  54. static bool _proto__probe_detect(struct gps_device_t *);
  55. static void _proto__event_hook(struct gps_device_t *, event_t);
  56. static bool _proto__set_speed(struct gps_device_t *, speed_t, char, int);
  57. static void _proto__set_mode(struct gps_device_t *, int);
  58. /*
  59. * Decode the navigation solution message
  60. */
  61. static gps_mask_t
  62. _proto__msg_navsol(struct gps_device_t *session, unsigned char *buf, size_t data_len)
  63. {
  64. gps_mask_t mask;
  65. int flags;
  66. double Px, Py, Pz, Vx, Vy, Vz;
  67. if (data_len != _PROTO__NAVSOL_MSG_LEN)
  68. return 0;
  69. GPSD_LOG(LOG_DATA, &session->context->errout,
  70. "_proto_ NAVSOL - navigation data\n");
  71. /* if this protocol has a way to test message validity, use it */
  72. flags = GET_FLAGS();
  73. if ((flags & _PROTO__SOLUTION_VALID) == 0)
  74. return 0;
  75. mask = ONLINE_SET;
  76. /* extract ECEF navigation solution here */
  77. /* or extract the local tangential plane (ENU) solution */
  78. [session->newdata.ecef.x,
  79. session->newdata.ecef.y,
  80. session->newdata.ecef.z,
  81. session->newdata.ecef.vx,
  82. session->newdata.ecef.vy,
  83. session->newdata.ecef.vz] = GET_ECEF_FIX();
  84. mask |= ECEF_SET | VECEF_SET;
  85. session->newdata.epx = GET_LONGITUDE_ERROR();
  86. session->newdata.epy = GET_LATITUDE_ERROR();
  87. session->newdata.eps = GET_SPEED_ERROR();
  88. session->gpsdata.satellites_used = GET_SATELLITES_USED();
  89. /*
  90. * Do *not* clear DOPs in a navigation solution message;
  91. * instead, opportunistically pick up whatever it gives
  92. * us and replace whatever values we computed from the
  93. * visibility matrix for he last skyview. The reason to trust
  94. * the chip returns over what we compute is that some
  95. * chips have internal deweighting albums to throw out sats
  96. * that increase DOP.
  97. */
  98. session->gpsdata.dop.hdop = GET_HDOP();
  99. session->gpsdata.dop.vdop = GET_VDOP();
  100. /* other DOP if available */
  101. mask |= DOP_SET;
  102. session->newdata.mode = GET_FIX_MODE();
  103. session->gpsdata.status = GET_FIX_STATUS();
  104. /*
  105. * Mix in CLEAR_IS to clue the daemon in about when to clear fix
  106. * information. Mix in REPORT_IS when the sentence is reliably
  107. * the last in a reporting cycle.
  108. */
  109. mask |= MODE_SET | STATUS_SET | REPORT_IS;
  110. /*
  111. * At the end of each packet-cracking function, report at LOG_DATA level
  112. * the fields it potentially set and the transfer mask. Doing this
  113. * makes it relatively easy to track down data-management problems.
  114. */
  115. GPSD_LOG(LOG_DATA, &session->context->errout,
  116. "NAVSOL: time=%.2f, ecef x:%.2f y: %.2f z: %.2f mode=%d "
  117. "status=%d\n",
  118. session->newdata.time,
  119. session->newdata.ecef.x,
  120. session->newdata.ecef.y,
  121. session->newdata.ecef.z,
  122. session->newdata.longitude,
  123. session->newdata.mode,
  124. session->gpsdata.status);
  125. return mask;
  126. }
  127. /**
  128. * GPS Leap Seconds
  129. */
  130. static gps_mask_t
  131. _proto__msg_utctime(struct gps_device_t *session, unsigned char *buf, size_t data_len)
  132. {
  133. double t;
  134. if (data_len != UTCTIME_MSG_LEN)
  135. return 0;
  136. GPSD_LOG(LOG_DATA, &session->context->errout,
  137. "_proto_ UTCTIME - navigation data\n");
  138. /* if this protocol has a way to test message validity, use it */
  139. flags = GET_FLAGS();
  140. if ((flags & _PROTO__TIME_VALID) == 0)
  141. return 0;
  142. tow = GET_MS_TIMEOFWEEK();
  143. gps_week = GET_WEEKNUMBER();
  144. session->context->leap_seconds = GET_GPS_LEAPSECONDS();
  145. session->newdata.time = gpsd_gpstime_resolv(session, gps_week, tow);
  146. return TIME_SET | NTPTIME_IS | ONLINE_SET;
  147. }
  148. /**
  149. * GPS Satellite Info
  150. */
  151. static gps_mask_t
  152. _proto__msg_svinfo(struct gps_device_t *session, unsigned char *buf, size_t data_len)
  153. {
  154. unsigned char i, st, nchan, nsv;
  155. unsigned int tow;
  156. if (data_len != SVINFO_MSG_LEN )
  157. return 0;
  158. GPSD_LOG(LOG_DATA, &session->context->errout,
  159. "_proto_ SVINFO - navigation data\n");
  160. /* if this protocol has a way to test message validity, use it */
  161. flags = GET_FLAGS();
  162. if ((flags & _PROTO__SVINFO_VALID) == 0)
  163. return 0;
  164. /*
  165. * some protocols have a variable length message listing only visible
  166. * satellites, even if there are less than the number of channels. others
  167. * have a fixed length message and send empty records for idle channels
  168. * that are not tracking or searching. whatever the case, nchan should
  169. * be set to the number of satellites which might be visible.
  170. */
  171. nchan = GET_NUMBER_OF_CHANNELS();
  172. if ((nchan < 1) || (nchan > MAXCHANNELS)) {
  173. GPSD_LOG(LOG_INF, &session->context->errout,
  174. "too many channels reported\n");
  175. return 0;
  176. }
  177. gpsd_zero_satellites(&session->gpsdata);
  178. nsv = 0; /* number of actually used satellites */
  179. for (i = st = 0; i < nchan; i++) {
  180. /* get info for one channel/satellite */
  181. int off = GET_CHANNEL_STATUS(i);
  182. session->gpsdata.PRN[i] = PRN_THIS_CHANNEL_IS_TRACKING(i);
  183. session->gpsdata.ss[i] = (float)SIGNAL_STRENGTH_FOR_CHANNEL(i);
  184. session->gpsdata.elevation[i] = SV_ELEVATION_FOR_CHANNEL(i);
  185. session->gpsdata.azimuth[i] = SV_AZIMUTH_FOR_CHANNEL(i);
  186. if (CHANNEL_USED_IN_SOLUTION(i))
  187. session->gpsdata.used[nsv++] = session->gpsdata.PRN[i];
  188. if(session->gpsdata.PRN[i])
  189. st++;
  190. }
  191. /* if the satellite-info setence gives you UTC time, use it */
  192. session->gpsdata.skyview_time = NaN;
  193. session->gpsdata.satellites_used = nsv;
  194. session->gpsdata.satellites_visible = st;
  195. GPSD_LOG(LOG_DATA, &session->context->errout,
  196. "SVINFO: visible=%d used=%d mask={SATELLITE|USED}\n",
  197. session->gpsdata.satellites_visible,
  198. session->gpsdata.satellites_used);
  199. return SATELLITE_SET | USED_IS;
  200. }
  201. /**
  202. * Raw measurements
  203. */
  204. static gps_mask_t
  205. _proto__msg_raw(struct gps_device_t *session, unsigned char *buf, size_t data_len)
  206. {
  207. unsigned char i, st, nchan, nsv;
  208. unsigned int tow;
  209. if (data_len != RAW_MSG_LEN )
  210. return 0;
  211. GPSD_LOG(LOG_DATA, &session->context->errout,
  212. "_proto_ RAW - raw measurements\n");
  213. /* if this protocol has a way to test message validity, use it */
  214. flags = GET_FLAGS();
  215. if ((flags & _PROTO__SVINFO_VALID) == 0)
  216. return 0;
  217. /*
  218. * not all chipsets emit the same information. some of these observables
  219. * can be easily converted into others. these are suggestions for the
  220. * quantities you may wish to try extract. chipset documentation may say
  221. * something like "this message contains information required to generate
  222. * a RINEX file." assign NAN for unavailable data.
  223. */
  224. nchan = GET_NUMBER_OF_CHANNELS();
  225. if ((nchan < 1) || (nchan > MAXCHANNELS)) {
  226. GPSD_LOG(LOG_INF, &session->context->errout,
  227. "too many channels reported\n");
  228. return 0;
  229. }
  230. DTONS(&session->raw.mtime, GET_TIME());
  231. /* this is so we can tell which never got set */
  232. for (i = 0; i < MAXCHANNELS; i++)
  233. session->gpsdata.raw.meas[i].svid = 0;
  234. for (i = 0; i < n; i++){
  235. session->gpsdata.PRN[i] = GET_PRN();
  236. session->gpsdata.ss[i] = GET_SIGNAL()
  237. session->gpsdata.raw.meas[i].satstat = GET_FLAGS();
  238. session->gpsdata.raw.meas[i].pseudorange = GET_PSEUDORANGE();
  239. session->gpsdata.raw.meas[i].doppler = GET_DOPPLER();
  240. session->gpsdata.raw.meas[i].carrierphase = GET_CARRIER_PHASE();
  241. session->gpsdata.raw.meas[i].codephase = GET_CODE_PHASE();
  242. session->gpsdata.raw.meas[i].deltarange = GET_DELTA_RANGE();
  243. }
  244. return RAW_IS;
  245. }
  246. /**
  247. * Parse the data from the device
  248. */
  249. gps_mask_t _proto__dispatch(struct gps_device_t *session, unsigned char *buf, size_t len)
  250. {
  251. size_t i;
  252. int type, used, visible, retmask = 0;
  253. if (len == 0)
  254. return 0;
  255. /*
  256. * Set this if the driver reliably signals end of cycle.
  257. * The core library zeroes it just before it calls each driver's
  258. * packet analyzer.
  259. */
  260. session->cycle_end_reliable = true;
  261. if (msgid == MY_START_OF_CYCLE)
  262. retmask |= CLEAR_IS;
  263. else if (msgid == MY_END_OF_CYCLE)
  264. retmask |= REPORT_IS;
  265. type = GET_MESSAGE_TYPE();
  266. /* we may need to dump the raw packet */
  267. GPSD_LOG(LOG_RAW, &session->context->errout,
  268. "raw _proto_ packet type 0x%02x\n", type);
  269. switch (type)
  270. {
  271. /* Deliver message to specific decoder based on message type */
  272. default:
  273. GPSD_LOG(LOG_WARN, &session->context->errout,
  274. "unknown packet id %d length %d\n", type, len);
  275. return 0;
  276. }
  277. }
  278. /**********************************************************
  279. *
  280. * Externally called routines below here
  281. *
  282. **********************************************************/
  283. static bool _proto__probe_detect(struct gps_device_t *session)
  284. {
  285. /*
  286. * This method is used to elicit a positively identifying
  287. * response from a candidate device. Some drivers may use
  288. * this to test for the presence of a certain kernel module.
  289. */
  290. int test, satisfied;
  291. /* Your testing code here */
  292. test=satisfied=0;
  293. if (test==satisfied)
  294. return true;
  295. return false;
  296. }
  297. #ifdef CONTROLSEND_ENABLE
  298. /**
  299. * Write data to the device, doing any required padding or checksumming
  300. */
  301. static ssize_t _proto__control_send(struct gps_device_t *session,
  302. char *msg, size_t msglen)
  303. {
  304. bool ok;
  305. /* CONSTRUCT THE MESSAGE */
  306. /*
  307. * This copy to a public assembly buffer
  308. * enables gpsmon to snoop the control message
  309. * after it has been sent.
  310. */
  311. session->msgbuflen = msglen;
  312. (void)memcpy(session->msgbuf, msg, msglen);
  313. /* we may need to dump the message */
  314. GPSD_LOG(LOG_PROG, &session->context->errout,
  315. "writing _proto_ control type %02x\n");
  316. return gpsd_write(session, session->msgbuf, session->msgbuflen);
  317. }
  318. #endif /* CONTROLSEND_ENABLE */
  319. #ifdef RECONFIGURE_ENABLE
  320. static void _proto__event_hook(struct gps_device_t *session, event_t event)
  321. {
  322. if (session->context->readonly)
  323. return;
  324. if (event == event_wakeup) {
  325. /*
  326. * Code to make the device ready to communicate. Only needed if the
  327. * device is in some kind of sleeping state, and only shipped to
  328. * RS232C, so that gpsd won't send strings to unidentified USB devices
  329. * that might not be GPSes at all.
  330. */
  331. }
  332. if (event == event_identified) {
  333. /*
  334. * Fires when the first full packet is recognized from a
  335. * previously unidentified device. The session.lexer counter
  336. * is zeroed. If your device has a default cycle time other
  337. * than 1 second, set session->device->gpsdata.cycle here. If
  338. * possible, get the software version and store it in
  339. * session->subtype.
  340. */
  341. }
  342. if (event == event_configure) {
  343. /*
  344. * Change sentence mix and set reporting modes as needed.
  345. * Called immediately after event_identified fires, then just
  346. * after every packet received thereafter, but you probably
  347. * only want to take actions on the first few packets after
  348. * the session.lexer counter has been zeroed,
  349. *
  350. * Remember that session->lexer.counter is available when you
  351. * write this hook; you can use this fact to interleave configuration
  352. * sends with the first few packet reads, which is useful for
  353. * devices with small receive buffers.
  354. */
  355. } else if (event == event_driver_switch) {
  356. /*
  357. * Fires when the driver on a device is changed *after* it
  358. * has been identified.
  359. */
  360. } else if (event == event_deactivate) {
  361. /*
  362. * Fires when the device is deactivated. Usr this to revert
  363. * whatever was done at event_identify and event_configure
  364. * time.
  365. */
  366. } else if (event == event_reactivate) {
  367. /*
  368. * Fires when a device is reactivated after having been closed.
  369. * Use this hook for re-establishing device settings that
  370. * it doesn't hold through closes.
  371. */
  372. }
  373. }
  374. /*
  375. * This is the entry point to the driver. When the packet sniffer recognizes
  376. * a packet for this driver, it calls this method which passes the packet to
  377. * the binary processor or the nmea processor, depending on the session type.
  378. */
  379. static gps_mask_t _proto__parse_input(struct gps_device_t *session)
  380. {
  381. if (session->lexer.type == _PROTO__PACKET) {
  382. return _proto__dispatch(session, session->lexer.outbuffer, session->lexer.outbuflen);
  383. #ifdef NMEA0183_ENABLE
  384. } else if (session->lexer.type == NMEA_PACKET) {
  385. return nmea_parse((char *)session->lexer.outbuffer, session);
  386. #endif /* NMEA0183_ENABLE */
  387. } else
  388. return 0;
  389. }
  390. static bool _proto__set_speed(struct gps_device_t *session,
  391. speed_t speed, char parity, int stopbits)
  392. {
  393. /*
  394. * Set port operating mode, speed, parity, stopbits etc. here.
  395. * Note: parity is passed as 'N'/'E'/'O', but you should program
  396. * defensively and allow 0/1/2 as well.
  397. */
  398. }
  399. /*
  400. * Switch between NMEA and binary mode, if supported
  401. */
  402. static void _proto__set_mode(struct gps_device_t *session, int mode)
  403. {
  404. if (mode == MODE_NMEA) {
  405. /* send a mode switch control string */
  406. } else {
  407. /* send a mode switch control string */
  408. }
  409. }
  410. #endif /* RECONFIGURE_ENABLE */
  411. static double _proto_time_offset(struct gps_device_t *session)
  412. {
  413. /*
  414. * If NTP notification is enabled, the GPS will occasionally NTP
  415. * its notion of the time. This will lag behind actual time by
  416. * some amount which has to be determined by observation vs. (say
  417. * WWVB radio broadcasts) and, furthermore, may differ by baud
  418. * rate. This method is for computing the NTP fudge factor. If
  419. * it's absent, an offset of 0.0 will be assumed, effectively
  420. * falling back on what's in ntp.conf. When it returns NAN,
  421. * nothing will be sent to NTP.
  422. */
  423. return MAGIC_CONSTANT;
  424. }
  425. static void _proto__wrapup(struct gps_device_t *session)
  426. {
  427. }
  428. /* The methods in this code take parameters and have */
  429. /* return values that conform to the requirements AT */
  430. /* THE TIME THE CODE WAS WRITTEN. */
  431. /* */
  432. /* These values may well have changed by the time */
  433. /* you read this and methods could have been added */
  434. /* or deleted. Unused methods can be set to NULL. */
  435. /* */
  436. /* The latest version can be found by inspecting */
  437. /* the contents of struct gps_type_t in gpsd.h. */
  438. /* */
  439. /* This always contains the correct definitions that */
  440. /* any driver must use to compile. */
  441. /* This is everything we export */
  442. /* *INDENT-OFF* */
  443. const struct gps_type_t driver__proto__binary = {
  444. /* Full name of type */
  445. .type_name = "_proto",
  446. /* Associated lexer packet type */
  447. .packet_type = _PROTO__PACKET,
  448. /* Driver tyoe flags */
  449. .flags = DRIVER_NOFLAGS,
  450. /* Response string that identifies device (not active) */
  451. .trigger = NULL,
  452. /* Number of satellite channels supported by the device */
  453. .channels = 12,
  454. /* Startup-time device detector */
  455. .probe_detect = _proto__probe_detect,
  456. /* Packet getter (using default routine) */
  457. .get_packet = generic_get,
  458. /* Parse message packets */
  459. .parse_packet = _proto__parse_input,
  460. /* RTCM handler (using default routine) */
  461. .rtcm_writer = pass_rtcm,
  462. /* non-perturbing initial query (e.g. for version) */
  463. .init_query = NULL,
  464. /* fire on various lifetime events */
  465. .event_hook = _proto__event_hook,
  466. #ifdef RECONFIGURE_ENABLE
  467. /* Speed (baudrate) switch */
  468. .speed_switcher = _proto__set_speed,
  469. /* Switch to NMEA mode */
  470. .mode_switcher = _proto__set_mode,
  471. /* Message delivery rate switcher (not active) */
  472. .rate_switcher = NULL,
  473. /* Minimum cycle time of the device */
  474. .min_cycle = 1,
  475. #endif /* RECONFIGURE_ENABLE */
  476. #ifdef CONTROLSEND_ENABLE
  477. /* Control string sender - should provide checksum and headers/trailer */
  478. .control_send = _proto__control_send,
  479. #endif /* CONTROLSEND_ENABLE */
  480. .time_offset = _proto_time_offset,
  481. /* *INDENT-ON* */
  482. };
  483. #endif /* defined(_PROTO__ENABLE) && defined(BINARY_ENABLE) */