protocol-transition.adoc 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451
  1. = Moving to GPSD-NG: a Guide for Client Developers =
  2. :description: A Guide for Client Developers moving to GPSD-ND
  3. :keywords: time, GPSD, gpsd, guide, developers, client
  4. Eric S. Raymond <esr@thyrsus.com>
  5. v1.10, February 2011
  6. This document is mastered in asciidoc format. If you are reading it in HTML,
  7. you can find the original at the GPSD project website.
  8. == Why a new protocol? ==
  9. GPSD has moved to a new request/response protocol. This move has been
  10. forced upon us because the old one ran out of namespace. It was
  11. designed with case-insensitive single-character command/response
  12. codes. 25 of 26 ASCII alphabetics were already in use by 2006, and
  13. there have been functional challenges accumulating over the last three
  14. years that will require several more request/response codes - things
  15. like reporting AIS data, reporting raw pseudoranges, and reporting
  16. RTCM3.
  17. Yes, we could as a desperate expedient have pressed non-alphabetic
  18. printables into service - but the result would have looked like
  19. line noise and only delayed the day of reckoning. Instead, we've
  20. written a new protocol that is upward-compatible with the old one
  21. in that you can mix old and new syntax.
  22. There were other problems as well. The old command set encouraged
  23. sloppy handling of data by supporting commands that return PVT and
  24. fix-quality information in atomized partial form, without timestamps.
  25. There was also no way to support returning more than single-line
  26. responses to a client. This was a problem for returning things like
  27. [RINEX] format, which we'd like to be able to do when a device can
  28. report pseudoranges.
  29. == The transition plan ==
  30. We need to shed the code complexity and overhead of maintaining both
  31. protocols at once. This will happen sooner than it otherwise might
  32. have because gpsd is in part targeted for SBCs and other constrained
  33. environments where shaving a few K off the runtime image can actually
  34. matter. When it comes to keeping the codebase lean and mean, we try
  35. harder.
  36. The old-protocol support was removed from the daemon in 2.91. Old
  37. protocol will be supported in the client-side library for somewhat
  38. longer, giving your applications a bridge period when they can speak
  39. both old and new protocol -- but the client-side support for old
  40. protocol will be removed when 3.0 ships.
  41. The 2.92 version, with the new protocol deployed, is be in Lucid
  42. Lynx, the Ubuntu LTS release of April 2010.
  43. If you follow our transition advice now, you will be able to talk to
  44. all old-protocol and new-protocol versions of the daemon until the 3.0
  45. shared client library is deployed, at which point your runtime will
  46. silently get smaller but you may no longer be able to use 2.x daemon
  47. versions any more.
  48. We're counting on binary-package dependencies to make the transition
  49. easier. When you ship a release using the new interface library,
  50. specify the GPSD package at version >= 2.90 to get the new shared
  51. library; then, when the 3.0 interface library is deployed next year,
  52. you shouldn't have to do anything.
  53. We'll try to make the transition easy, but we cannot guarantee no
  54. problems. The sooner you start adapting your code, the less pain you
  55. are likely to experience. The rest of this document will explain both
  56. theory and practice, and give you specific pointers on how to fix
  57. client code.
  58. == Virtue is rewarded ==
  59. Since 2004, the way you were *supposed* to be using gpsd was through
  60. one of the client libraries (in C or Python). If you have been doing
  61. it right, you have been telling gpsd to stream data at you with the
  62. 'w' command, via application code probably looked something like this:
  63. -------------------------------------------------------------------
  64. gpsdata = gps_open(source.server, source.port);
  65. (void)gps_query(gpsdata, "w+x\n");
  66. // This is in your application's main event loop somewhere.
  67. // It polls gpsd for new data.
  68. ... gps_poll(gpsdata) ...
  69. gps_close()
  70. -------------------------------------------------------------------
  71. If you have been virtuous, you need only to make four small changes to
  72. your code.
  73. . Give gps_open() a third argument that is the address of a struct gps_data_t.
  74. (This interface changed to avoid malloc(3) and make it possible to write
  75. re-entrant client code.)
  76. . Replace the gps_query() call with:
  77. -------------------------------------------------------------------
  78. gps_stream(gpsdata, WATCH_ENABLE, NULL)
  79. -------------------------------------------------------------------
  80. This will tell whatever version of the client library your application
  81. dynamically links to emit what it should under the hood, either old
  82. or new protocol. Unless a target system carries a version of the
  83. libgps shared library different from the gpsd version, everything
  84. should work and continue to work through future updates.
  85. . Change gps_poll calls to gps_read calls.
  86. . If you have references to the 'satellites' member of the structure,
  87. those need to change them to 'satellites_visible'.
  88. There. You're probably done, unless you relied on some parts of
  89. struct gpsdata_t that application developers usually don't or issued
  90. unusual configuration commands. Here are the exceptions:
  91. * You issued other gps_query() or gps_send() commands, such as "J=1".
  92. If so, you'll need to learn how to say them in the new API (the J
  93. command itself is dead, and you can just remove it entirely). That
  94. is not difficult, and this document will cover what you need to
  95. know.
  96. * Your application code referenced struct gpsdata_t members that no
  97. longer exist. This will be obvious because your compilation will
  98. fail. Later in this document you will learn how to fix these
  99. problems.
  100. * You set a per-packet raw hook. This feature is gone; code
  101. can now just look at the response buffer directly.
  102. * You set a thread hook. We have deleted the thread-hook portion of
  103. the API; for discussion, see "Why threads are gone" below.
  104. You can probably ignore the rest of this document, unless
  105. either (a) you want to learn about gpsd's new capabilities so you
  106. can use them in creative ways, or (b) you want to caper with unholy glee
  107. as you contemplate the trials awaiting the non-virtuous.
  108. If you are non-virtuous -- that is, you rolled your own client-side
  109. interface -- you've had years of warning that this choice would
  110. fail to insulate you from protocol details and cost you pain in the
  111. future. That future is now.
  112. In the remainder of this document we will try to help you minimize the
  113. pain. The main strategy for doing so is to *use libgps* (or its
  114. functional equivalents in languages other than C). Scrap your
  115. hand-rolled interface code! When you use libgps, compatibility issues
  116. become *our* problem to solve rather than *yours*.
  117. == Binary stability ==
  118. In the past, the GPSD project has not been very good about preserving
  119. stability of the binary structure layout for struct gpsdata_t between
  120. releases. There was a reason for this -- we were very focused
  121. on reducing memory footprint for SBCs and embedded devices, so we
  122. conditioned out various pieces of the strucure depending on what
  123. features were or were not compiled in.
  124. We're not going to do this any more. It has been pointed out to us
  125. that the friction costs of breaking shared-library compatibility are
  126. higher than we were reckoning. The new layout has no sections
  127. conditionalized; instead, we have moved a number of fields into
  128. a union. From 2.90 on, the structure layout will change rarely,
  129. only at major version bumps.
  130. == When the bough breaks ==
  131. Even virtuous clients have to worry about version skew. Supposing you
  132. have used libgps and not done anything exotic, you will still have
  133. problems if the client library you linked and the instance of gpsd it
  134. speaks to are using different protocols.
  135. The possible failure modes are pretty obvious. Transitions are
  136. difficult. We're essentially relying on the distribution integrators
  137. to ship libgps and gpsd updates at the same time, with sane
  138. package dependencies. If that goes smoothly, applications may
  139. not even notice the changes. We can hope...
  140. == Why threads are gone ==
  141. We have deleted the two functions in the API that managed a
  142. library-internal thread hook. Here's why:
  143. 1. Actual use of it has been at best very rare and possibly nonexistent.
  144. 2. Applications that want location handing to run in a thread are in
  145. a better position to manage thread locks and mutexes themselves
  146. than our client library can possibly be -- after all, the
  147. application knows what all the other threads and mutex locks
  148. are, and our library doesn't.
  149. 3. We don't like to ship code we can't test, we didn't have a
  150. regression test for the thread stuff, and writing one would
  151. have been a painful expenditure of time better spent elsewhere.
  152. == On not doing things by halves ==
  153. At the same time that pressure has been building to redesign the
  154. protocol, we've been gaining experience in gpsd's application domain
  155. that has made us rethink some of the assumptions behind the old one.
  156. Since we knew we were going to have a forced compatibility break at the
  157. wire-protocol level anyway, we decided not to do things by halves. One
  158. big break -- in the application model, struct gpsdata_t, and the
  159. wire protocol behind it -- is better than three or four spread out
  160. over a period of time.
  161. As a result, the new protocol is not an exact superset of the old one.
  162. It reflects a different way of carving up the behavior space in gpsd's
  163. application domain. And the shape of struct gpsdata_t, the
  164. client-side interface structure, has changed in corresponding ways.
  165. Accordingly, there are three things a client developer will need to
  166. understand about the new protocol. The first is theory: how its model
  167. of the gpsd application domain is different. The second is practice:
  168. how to issue new-style commands and interpret responses. The third, if
  169. you have relied on the structure in a way that now breaks your
  170. compile, is how that structure has changed.
  171. == How the theory has changed ==
  172. === Channels are gone ===
  173. In old protocol, when you requested data from the daemon, it would
  174. search for a device supplying the kind of data you had told it you
  175. wanted (GPS, by default) and connect your listening channel to *that
  176. single device*. The association between channel and device was set
  177. when channel was first bound to device and implicit; reports weren't
  178. labeled with the device name. You could request a specific device if
  179. you wanted to.
  180. In the new protocol, channels are gone. You tell gpsd to stream
  181. reports at you; thereafter, every time an attached GPS or other device
  182. generates a report, you'll get it. There may be multiple devices
  183. reporting; each report will come labeled with the name of the
  184. originating device, and that name will be left in your client
  185. structure along with the rest of the new data.
  186. In both protocols, when you poll gpsd and get data the client library
  187. takes care of interpreting what comes up the wire from the daemon, and
  188. merges the resulting data into your client structure (struct
  189. gpsdata_t).
  190. The difference is that before, the API locked you to one device during
  191. the life of the session. Now it potentially has to deal with a *set*
  192. of devices, treated symmetrically.
  193. There are multiple reasons this change is a good idea. One is that it
  194. makes coping with devices being hotplugged in or out completely
  195. trivial from the client's point of view - it can just choose to ignore
  196. the fact that the device IDs in the reports have changed. Also, the
  197. channel-management hair in the interface goes away. Also, it means
  198. that clients can treat identically the cases where (a) you have one
  199. device reporting different kinds of data (e.g. a marine navigation
  200. system reporting both GPS and AIS) and (b) you have several devices
  201. reporting different kinds of data.
  202. === From lockstep to streaming ===
  203. A subtler change has to do with the difference between a lockstep
  204. or conversational interface and a streaming, stateless one.
  205. In the earliest versions of GPSD, clients requested various pieces of
  206. data by command. After each request, they would need to wait until a
  207. response came back. Then, watcher mode was added. By saying "w+",
  208. you could ask gpsd to stream GPS reports at you whenever it got them.
  209. In the new protocol, streaming is all there is. Every report coming
  210. up from the daemon is tagged with its device and type. Instead of
  211. issuing commands and then waiting for specific responses, clients
  212. should expect any kind of report at any time and merge it into
  213. client-local storage (libgps does this for you).
  214. This change is necessary to cope with devices that may send (for
  215. example) mixed GPS and AIS data. In the future, the stream from
  216. gpsd could include other kinds of data, such as the take from
  217. a digital compass, water-temperature sensors, or even aircraft
  218. transponders.
  219. === Asynchronous-write handling ===
  220. The old client code had an assumption baked into it that gps_poll()
  221. can do one read call end expect the daemon to hand it an entire
  222. \n-terminated packet. 99.9% of the time this is true, but socket
  223. layers can do some remarkably perverse things.
  224. In 2.91 and later, what was gps_poll() and is now gps_read() behaves
  225. in a subtly different way. Each call does exactly one read() call as
  226. before, but the incoming data is now buffered; the logic to interpret
  227. the buffer and empty it is called only when the read() contains a \n.
  228. When that happens, the validity flags include the PACKET_SET mask.
  229. == How the command set has changed ==
  230. If your code issues old-protocol commands 'A', 'D', 'E', 'M', 'P',
  231. 'T', 'U', or 'V', it is a wretched hive of scum and villainy that
  232. probably hasn't changed since before the introduction of 'W' in
  233. 2004-2005. You are using the oldest single-shot commands and will
  234. have to rewrite your interface significantly, as the new protocol does
  235. not support equivalents. Use libgps.
  236. If your code issues B, C, or N commands, they need to change to
  237. ?DEVICE commands. See the protocol reference for details.
  238. The 'F' command has no equivalent in 2.90; consider teaching your
  239. client to ignore fix updates when they don't have a specified "device"
  240. or "class" tag, respectively. In 2.91 and later versions, use the "device"
  241. option of the ?WATCH command for similar effect.
  242. The old 'G' command does not have an equivalent. It would be possible
  243. to implement one, but we probably won't do it unless there is actual
  244. demand (and we don't expect any).
  245. The old 'I' command has no equivalent. You probably issued it as part
  246. of an initialization string, hoping that a subtype string would later
  247. show up in gps_id so you could post it somewhere. In the new
  248. protocol, when a device sends back subtype information the daemon
  249. ships the client an object of class DEVICE with a device tag and
  250. subtype fields. Watch for that and process appropriately.
  251. The old 'J' command is dead. gpsd now detects the end of the reporting
  252. cycle reliably and ships on that, buffering data during the individual
  253. reporting cycle.
  254. The old 'K' command is replaced by ?DEVICES.
  255. The old 'L' command is replaced by ?VERSION. Note that the daemon now
  256. ships a version response to each client on connect, so it will
  257. probably never be necessary for you to issue a ?VERSION request.
  258. The old 'M' command has no equivalent. Mode is reported in the TPV response.
  259. The old 'O' and 'Y' commands are gone. Use ?WATCH and sample the
  260. stream instead.
  261. The old 'Q' command has no equivalent. DOPs are reported in the SKY response.
  262. The 'S' command has no equivalent, because it is not well defined what
  263. value should be presented for binary protocols.
  264. The old 'R' command has been replaced by three optional attributes in
  265. ?WATCH. Include the WATCH_RARE, WATCH_RAW and/or WATCH_NMEA masks in
  266. the argument of gps_stream(), or set a raw hook before alling
  267. gps_stream().
  268. The old 'W' command has been replaced by ?WATCH. Call gps_stream()
  269. with whatever options you want to set.
  270. The old 'X' command is gone. Instead, you will see an object of
  271. class DEVICE from the daemon whenever a device is opened or closed.
  272. The old 'Z' and '$' commands, used by the developers for profiling,
  273. have equivalents, which are presently considered unstable and thus
  274. are undocumented.
  275. == How the C API and gps_data_t structure has changed ==
  276. gps_open() now takes a third argument and is re-entrant - it's the
  277. old undocumented gps_open_r().
  278. The gps_query() entry point is gone. With the new streaming-oriented
  279. wire protocol, it is extremely unwise to assume that the first
  280. transmission from the damon after a command is shipped to it will be
  281. the response to command. If you must send explicit
  282. commands to the daemon, use gps_send() and handle the response in
  283. your main event-polling loop -- but beware, as using gps_send()
  284. ties your code to the GPSD wire protocol and is not recommended.
  285. gps_poll() is renamed gps_read().
  286. The client library's reporting structure, struct gpsdata_t, has a new
  287. substructure (struct devconfig_t) named "dev" that groups together
  288. information about the device that shipped the last update to the
  289. client. The members of this structure replace several top-level
  290. struct gpsdata members in older versions.
  291. Most notably, the gps_device member has been replaced by dev.path.
  292. It is valid after every response with a device tag (DEVICE, TPV, SKY,
  293. AIS, RTCM2, RTCM3).
  294. The top-level gps_id member is replaced by dev.subtype. This data
  295. should be considered valid only when DEVICEID_SET is on in the
  296. top-level set member.
  297. The dev members baudrate, parity, stopbits, cycle, mincycle, and
  298. driver_mode replace older top-level members. They should be
  299. considered valid only when DEVICE_SET is on in the top-level set
  300. member.
  301. The top-level members ndevices and devicelist (used only on the client
  302. side) have been replaced by an array of struct devconfig_t structures.
  303. Data in this structure should be considered valid only when
  304. DEVICELIST_SET is on in the top-level set member. Storage for
  305. pathnames is no longer dynamically allocated, but static; to save
  306. space, it lives in a union with several other substructures.
  307. The top-level member "satellites" has been changed to
  308. "satellites_visible". The ambiguity in that name had actually induced
  309. a bug or two.
  310. There is a new substructure, dop, which holds the
  311. dilution-of-precision factors that were previously individual members
  312. of the gpsdata structure. Two new DOPs, xdop and ydop, are available;
  313. these express dilution of precision in longitude and latitude,
  314. respectively.
  315. There is a gps_waiting() method analogous to the waiting() method in
  316. the Python class -- a way to check if input is waiting from the
  317. daemon. It blocks but takes a timeout value.
  318. The raw_hook member is gone.
  319. == C++ client library changes ==
  320. In API version 5, the C++ library defines a single object using RAII.
  321. There are no explicit open() and close() methods; instead, you initialize
  322. the object handing it a host and server, and the connection is shut down
  323. when the object is deleted or goes out of scope.
  324. == Python client library changes ==
  325. There is a new stream() method analogous to the gps_stream() call in
  326. the C library. As in the C library, the query() method is gone, for
  327. the same reasons. The gps_send() entry point, new in version 3 of the C API,
  328. has had a corresponding Python gps-class send() method all along.
  329. The pre-existing interface using the poll() method and self.valid is
  330. still available and should work compatibly with a daemon speaking
  331. JSON. One new feature has been added; after a VERSION response (which
  332. a JSON-speaking instance of gpsd should emit when a connection is
  333. opened) the version member of the session will be an object containing
  334. version information. However, data from the new responses (WATCH,
  335. VERSION, AIS, and TIMING in particular) will be available only through
  336. the self.data member.
  337. The preferred way to use the new gps class is as an iterator
  338. factory, like this:
  339. ----------------------------------------------------------------------
  340. for report in gps(mode=WATCH_ENABLE):
  341. process(report)
  342. ----------------------------------------------------------------------
  343. See the Client HOWTO for a more detailed example.