driver_proto.c 19 KB

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