writing-a-driver.xml 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE article PUBLIC
  3. "-//OASIS//DTD DocBook XML V4.1.2//EN"
  4. "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
  5. ]>
  6. <article>
  7. <title>Notes on Writing a GPSD Driver</title>
  8. <articleinfo>
  9. <author>
  10. <firstname>Mick</firstname>
  11. <surname>Durkin</surname>
  12. </author>
  13. <revhistory>
  14. <revision>
  15. <revnumber>1.15</revnumber>
  16. <date>7 Mar 2015</date>
  17. <authorinitials>er</authorinitials>
  18. <revremark>
  19. Updated by esr; track a function rename. Text now fibs about
  20. the original author thought the name was in order to avoid
  21. confusing current readers.
  22. </revremark>
  23. </revision>
  24. <revision>
  25. <revnumber>1.13</revnumber>
  26. <date>25 Aug 2014</date>
  27. <authorinitials>er</authorinitials>
  28. <revremark>
  29. Updated by esr; added init_query method.
  30. </revremark>
  31. </revision>
  32. <revision>
  33. <revnumber>1.12</revnumber>
  34. <date>31 Oct 2013</date>
  35. <authorinitials>er</authorinitials>
  36. <revremark>
  37. Updated by esr; ntp_offset becomes time_offset
  38. </revremark>
  39. </revision>
  40. <revision>
  41. <revnumber>1.11</revnumber>
  42. <date>19 Jan 2011</date>
  43. <authorinitials>er</authorinitials>
  44. <revremark>
  45. Updated by esr; driver type flag field added.
  46. </revremark>
  47. </revision>
  48. <revision>
  49. <revnumber>1.10</revnumber>
  50. <date>9 Jan 2011</date>
  51. <authorinitials>er</authorinitials>
  52. <revremark>
  53. Updated by esr; event_wakeup no longer fires for USB devices,
  54. in order to avoid spamming unidentified devices behind
  55. USB-to-serial adapters that may not be GPSes at all.
  56. </revremark>
  57. </revision>
  58. <revision>
  59. <revnumber>1.9</revnumber>
  60. <date>13 Apr 2010</date>
  61. <authorinitials>er</authorinitials>
  62. <revremark>
  63. Updated by esr; added event_triggermatch and the new
  64. ntp_offset member.
  65. </revremark>
  66. </revision>
  67. <revision>
  68. <revnumber>1.8</revnumber>
  69. <date>16 Sep 2009</date>
  70. <authorinitials>er</authorinitials>
  71. <revremark>
  72. Updated by esr; major rearrangement of driver event set.
  73. </revremark>
  74. </revision>
  75. <revision>
  76. <revnumber>1.8</revnumber>
  77. <date>9 Aug 2009</date>
  78. <authorinitials>er</authorinitials>
  79. <revremark>
  80. Updated by esr; the device_class experiment failed.
  81. </revremark>
  82. </revision>
  83. <revision>
  84. <revnumber>1.7</revnumber>
  85. <date>24 Jul 2009</date>
  86. <authorinitials>er</authorinitials>
  87. <revremark>
  88. Updated by esr; Added the device_class member.
  89. </revremark>
  90. </revision>
  91. <revision>
  92. <revnumber>1.6</revnumber>
  93. <date>9 Mar 2009</date>
  94. <authorinitials>er</authorinitials>
  95. <revremark>
  96. Updated by esr; libgpsd_core.c no longr requires modification
  97. when you add a driver.
  98. </revremark>
  99. </revision>
  100. <revision>
  101. <revnumber>1.6</revnumber>
  102. <date>1 Mar 2009</date>
  103. <authorinitials>er</authorinitials>
  104. <revremark>
  105. Updated by esr to reflect removal of the cycle member.
  106. </revremark>
  107. </revision>
  108. <revision>
  109. <revnumber>1.5</revnumber>
  110. <date>1 Mar 2009</date>
  111. <authorinitials>er</authorinitials>
  112. <revremark>
  113. Updated by esr to reflect the parity/stopbits
  114. extension of the sopeed_switcher method.
  115. </revremark>
  116. </revision>
  117. <revision>
  118. <revnumber>1.4</revnumber>
  119. <date>17 February 2009</date>
  120. <authorinitials>er</authorinitials>
  121. <revremark>
  122. Updated by esr to reflect the renaming of sirfmon to gpsmon,
  123. and document the control_send method.
  124. </revremark>
  125. </revision>
  126. <revision>
  127. <revnumber>1.3</revnumber>
  128. <date>14 November 2006</date>
  129. <authorinitials>md</authorinitials>
  130. <revremark>
  131. Updated to conform to the fepo source at this date.
  132. </revremark>
  133. </revision>
  134. </revhistory>
  135. <abstract>
  136. <para>If you are thinking of writing a GPSD driver for some GPS-like
  137. device, these notes by a person who did it may help you decide
  138. whether or not it's a good idea, and if it is, help you get started.</para>
  139. </abstract>
  140. </articleinfo>
  141. <sect1><title>Introduction</title>
  142. <para>First, ask yourself <quote>Why would I write a driver?</quote>
  143. and do that several times. At the date of writing,
  144. <application>gpsd</application> ships with more than 10 drivers and
  145. supports around 40 different GPS devices, so it may be that your
  146. device is already supported by an existing driver.</para>
  147. <para>It may be worth noting that these notes were written against
  148. gpsd version 2.34 as it existed on of November 14th
  149. 2006. The situation will likely have changed by the time you read
  150. this, but the broad principles should still apply. Check what version
  151. you are using.</para>
  152. <para><application>gpsd</application> supports autodetection, so
  153. connect your device and try it; you may be lucky and find it is
  154. already supported. If you are unlucky, you have to be prepared to do a
  155. lot of work and research on your own.</para>
  156. <para>I found that the device I wanted to use (a Navman Jupiter-T) was
  157. not supported in its default operation mode. The device actually
  158. provides two other supported modes, NMEA (exceptional support) and
  159. Rockwell/Conexant/Navman binary (supported by the Earthmate driver
  160. <filename>zodiac.c</filename>), I could have possibly avoided
  161. writing a driver by switching to one of these modes, but there was an
  162. overwhelming reason to use the unsupported default mode.</para>
  163. <para>I use the Jupiter-T as a precision timing
  164. device with some dedicated hardware to provide a disciplining
  165. signal to a house standard 10MHz signal. In this application I
  166. wanted to keep it as intended; as a drop in emulator of the
  167. Motorola Oncore UT+ running in fixed-location mode giving a
  168. 1PPS signal to very high precision (claimed to be 25ns, 1
  169. sigma).</para>
  170. <para>So for me, the decision whether to write a
  171. driver or not was already made; either write one or forget
  172. connecting this high quality time source to my network, as
  173. <application>gpsd</application> can also use the GPS device to
  174. synchronise the ntpd daemon either to the GPS data or to the
  175. 1PPS, if it is available. A 25ns accurate input to <filename>
  176. ntpd</filename> looked very appealing.</para>
  177. </sect1>
  178. <sect1><title>What you will need to go ahead</title>
  179. <para>To take this decision to maturity, you need
  180. to be able to code in C and compile/install the results. If you
  181. can't do that, you should temporarily shelve the driver project
  182. and start learning to code. While I would not advise this as
  183. the way to go for a complete novice, you will find some good
  184. code to follow in the
  185. <application>gpsd</application> files and there are some good
  186. clues in the existing drivers.</para>
  187. <para>You will also need some understanding of what a GPS device is
  188. and how it works, although I guess you are likely to have this
  189. knowledge or you wouldn't be reading this document. You don't need to
  190. be a satellite navigation guru, but it helps if you are familiar with
  191. the terms used.</para>
  192. <para>You will also need access to the documentation for your GPS
  193. device, specifically the format (communications protocol, speed etc.)
  194. and content of the data the device will generate and the commands it
  195. needs to control it. The ideal source for that would be the
  196. manufacturer's user guide or programming manual.</para>
  197. <para>The information available may be a bit sparse and it may even be
  198. that the device is not best suited for use with
  199. <application>gpsd</application>. In my case, I was lucky because the
  200. Jupiter-T was intended for the professional OEM market. It was
  201. designed to be used in devices like custom vehicle trackers. It has
  202. almost no internal intelligence, being designed to interface to an
  203. external computing device and provide raw navigation and time data,
  204. but the interfaces and control language were superbly specified in a
  205. well written technical document of about 200 pages. In actual fact the
  206. document I used most was the Motorola documentation for the default
  207. Oncore mode, but the NMEA and Rockwell/Conexant/Navman modes were
  208. equally well documented in the Navman manuals.</para>
  209. <para>You will also need to set aside some time
  210. and equipment to do the coding and testing. I actually spent
  211. several weeks on this task and went to some trouble to get the
  212. GPS working on my desktop in a temporary harness so that I
  213. could have the device available to test the code. It took some
  214. imagination to get a usable satellite signal as I live in a
  215. ground floor apartment of a 6 floor block in Helsinki with a
  216. limited view of the sky. I ended up pushing my puck antenna
  217. away from the building by fixing it to a broom handle and
  218. poking it out of a partly open window. As you can imagine, I
  219. suspended operations in winter as an open window at -15
  220. centigrade is no joke.</para>
  221. </sect1>
  222. <sect1><title>What is involved in the coding</title>
  223. <para>I looked long and hard at the other drivers, at the main parts
  224. of <application>gpsd</application>, at the test applications (
  225. <application>like xgps</application>) and at the descriptions on the
  226. <application>gpsd</application> web site to get a feel for what my
  227. driver needed to do to behave like the existing drivers. After some
  228. time, I concluded that for me the best way forward was to write my
  229. driver by modifying an existing driver.</para>
  230. <para>Using this approach, I knew that that I would be working on a
  231. layout/functionality that was already conformant to
  232. <application>gpsd</application>'s internal standards and that already
  233. actually produced viable output. Apart from that, I intended, in the
  234. best tradition, to build on everybody else's good ideas instead of
  235. re-inventing the wheel, wherever possible. Modification is probably an
  236. understatement as actually I ended up replacing almost all the
  237. original code, but it acted as a template during the
  238. development.</para>
  239. <para>My first efforts were directed to understanding what the
  240. different sections of the code did (I actually hacked the
  241. <filename>zodiac.c</filename> driver). This took me into some of the
  242. other programs such as <filename>gpsd.c</filename> to see why the
  243. driver was doing certain things and to see what the inputs to/outputs
  244. from the driver were. I also looked at
  245. <filename>driver-proto.c</filename>, as this is a skeleton which
  246. contains the minimal set of services and entry points. Real drivers
  247. provide these and more, but at first, this is a less overwhelming
  248. piece of code and can act as a guide when unravelling a working
  249. driver.</para>
  250. <para>The real trigger for me writing a new driver was that the native
  251. output of the Jupiter-T is a binary protocol with variable length
  252. strings. None of the existing drivers spoke this language, but I could
  253. get some general ideas on how to handle this from drivers like
  254. <filename>zodiac.c</filename> and
  255. <filename>evermore.c</filename>.</para>
  256. <para>I found from the manufacturer's documentation that the Jupiter-T
  257. produces output only when instructed, rather than spewing out a
  258. set sequence at some pre-defined rate. All the commands and
  259. responses in <quote>Jupiter-T-speak</quote> start with a 4 character
  260. ASCII string <quote> <filename>@@Nn</filename></quote> followed by a
  261. payload of 0 to approx 300 binary bytes, a single byte binary checksum
  262. and an ASCII CR/LF pair. Thus it would be possible to generate all
  263. the wanted data for <application>gpsd</application> by activating
  264. two main messages, <quote> <filename>@@Bb</filename></quote> and
  265. <quote><filename>@@Ea</filename></quote>. This particular structure
  266. was the cause of some headaches in the interpretation, but it means
  267. that the important data is impressively dense. The first command
  268. (<filename>@@Bb</filename>) gives the status of all visible satellites
  269. (up to 12) in 92 bytes and the second command
  270. (<filename>@@Ea</filename>) gives all the navigational data plus
  271. receiver status in 76 bytes.</para>
  272. <para>Once I had determined the two commands and responses that were
  273. needed (a few others were needed for initialisation and
  274. administration), I set about writing the decoder to fill in the
  275. standard data structures that <application>gpsd</application> uses. For
  276. this, the <filename>zodiac.c</filename> driver was very helpful as it
  277. had a routine <quote> <function>static gps_mask_t handle1000(struct
  278. gps_device_t *session)</function></quote> that did a very similar
  279. job.</para>
  280. <para>This brought me neatly to a chicken/egg problem; the device,
  281. as I said earlier, is mute on power-up and unless you send it
  282. some instructions to turn on one or more messages, you will have no
  283. indication if it is even alive. Actually, this is not strictly true,
  284. as it does output a 1PPS and a 10kHz square wave on power up, but
  285. these are free running until satellites are acquired, and
  286. <application>gpsd</application> needs a data stream if it is to do
  287. anything. If it has not discovered your GPS device, it cannot lock to
  288. the 1PPS that is coming in all the while.</para>
  289. <para>The <application>gpsd</application> installation instructions
  290. give a clue about how to check if your device is working, but the
  291. method is best suited to NMEA devices or others which give real ASCII
  292. output. If your device outputs binary, you could mistake the output
  293. for garbage caused by a serial port speed or word size error. A mute
  294. device also makes this a non-starter!</para>
  295. <para>The manufacturer's manual gives the commands to set up the
  296. device, but to be honest, I was not sure what I really needed to send
  297. or even how to do it and see the results easily under Linux. I am sure
  298. there are many of you that are confident in driving and reading a
  299. serial port at low level and could have done this in a few minutes. I
  300. chose a simpler way, though it did involve using some Windows
  301. software.</para>
  302. <para>There is a program available called TAC32 (Totally Accurate
  303. Clock) written to run under Windows which can talk to several
  304. varieties of GPS devices and <quote>wake</quote> them in the correct
  305. way to generate navigation data and timing signals, displaying them in
  306. a nice screen, something like <application>xgps</application> does.
  307. This is available for a free evaluation download (about 30 days expiry,
  308. I believe), but I actually shelled out for a license as I had a
  309. continuing use for this on a laptop which only had Windows on it.
  310. Information was available at the time of writing at <ulink
  311. url="https://www.cnssys.com/">www.cnssys.com</ulink>.</para>
  312. <para>With this software you can monitor the raw
  313. data stream and send arbitrary commands to the GPS (the command
  314. constructor includes a nice syntax verifier and CRC generator), so
  315. I was able to watch the initialisation of the device, check the
  316. output stream used to generate the navigation data and
  317. experiment with the command set.</para>
  318. <para>Armed with this information, I was then
  319. able to start testing my driver as I was able to initialise the
  320. device into a working state and be sure I had a good fix and
  321. valid 1PPS under Windows and then transfer the serial
  322. connection to my Linux box whilst leaving the device powered
  323. up.</para>
  324. <para>Later, when I had the basic decoder working, I looked at a
  325. better way to handle communications to the device for test purposes
  326. and general monitoring of how the driver was behaving. In the end, I
  327. was able to get good results by monitoring the serial link to the
  328. device with a specially made <quote>Y</quote> cable (diagram available
  329. at
  330. <ulink url="http://www.beyondlogic.org/protocolanalyser/protocolanalyser.htm">
  331. http://www.beyondlogic.org/protocolanalyser/protocolanalyser.htm</ulink>)
  332. and some Linux based software, SerLook (
  333. <ulink url="http://serlook.sunsite.dk/">
  334. http://serlook.sunsite.dk/</ulink>). I had access to a 4-port
  335. RS-232 to USB adapter and so I could use two of the ports on
  336. this device with special cable and the SerLook software to monitor
  337. the send and receive streams of my <application>gpsd</application> port.</para>
  338. <para>For sending experimental commands, I
  339. settled on building the wanted commands as simple files using
  340. <application>KhexEdit</application> and then sending them to
  341. the serial port with <function>cat</function>. This allowed me
  342. to experiment with the different commands and to swap between
  343. the three modes (Oncore/Jupiter/NMEA). This is crude, but I found it hard
  344. to get the right results with <function>minicom</function>.</para>
  345. <!-- ESR: gpsd_log had a different name when this was written -->
  346. <para>To return to the development, I liberally
  347. sprinkled the driver code with <quote>
  348. <function>gpsd_log</function></quote> statements set
  349. to trigger at the lowest level of debugging and invoked the
  350. daemon in <quote>non-daemon</quote> mode with
  351. debugging set to LOG_WARN. This made sure that I could watch
  352. the code step through its various routines.</para>
  353. <para>This leads nicely to two things that I had to master early on
  354. and write down so that I wouldn't forget; how to compile/install the
  355. daemon and how to fire it up. The first is fairly straightforward if
  356. you have compiled anything before. You simply issue a <quote>
  357. <command>./configure</command></quote> command to specify what you
  358. want compiling and then issue a
  359. <quote>
  360. <command>make</command></quote> command to compile
  361. the software to that configuration. If it compiles
  362. successfully, you can then issue a <quote>
  363. <command>make install</command></quote> command to
  364. install the driver. This last command will need to be done as
  365. <function>root</function> because the daemon is designed to
  366. be invoked by root.</para>
  367. <para>The second thing is a bit more tricky, at least the first time
  368. for me, as I find the <quote> <command>man</command></quote> output of
  369. how to invoke any command almost impossible to understand. I got more
  370. out of the source code than I did from <quote>
  371. <command>man</command></quote>, but maybe that is just me! What you
  372. basically do, again as root, is to invoke the daemon, telling it which
  373. port (in my case, a serial port) it should use, that it should stay
  374. permanently active (don't wait for an application to ask for data),
  375. should not go into the background (not <quote>daemonize</quote>) and
  376. which debug level to run at. For me this came out as <quote>
  377. <filename>gpsd -n -N -D1 /dev/ttyS0</filename></quote> from a terminal
  378. session activated as root.</para>
  379. <para>The options for compilation would bear a bit more scrutiny. In
  380. the initial stages, I wanted to keep things simple, so I figured out
  381. from the <command>./configure help</command> command what options were
  382. supported and what were the default settings for them. I initially
  383. compiled with everything except NMEA and my driver disabled. This
  384. keeps the code smaller and ensures that you don't trigger the wrong
  385. driver. My reasoning with leaving the NMEA active was twofold; I
  386. wanted to be able to check at an early stage if I could get
  387. <emphasis>any</emphasis> output to be understood (remember, my GPS
  388. also speaks NMEA and I could change the mode in Windows if needed),
  389. also I was not sure if turning this most basic mode off would break
  390. the daemon. Later on, I modified the default settings in
  391. <filename>configure.ac</filename> to default to just this basic
  392. configuration automatically.</para>
  393. <para>Of course, I have jumped a long way forward
  394. in the story as to be able to compile your new driver, you have
  395. to write it and modify several other parts of the existing code
  396. to be aware of your work.</para>
  397. </sect1>
  398. <sect1><title>Where will your driver make an impact?</title>
  399. <para>If we assume for the time being that you are able to write the
  400. code for your GPS, where does it make its <quote>footprint</quote> on
  401. the existing code? I turned again to the
  402. <filename>zodiac.c</filename> driver for inspiration and did a search
  403. over the source code for any mention of the word <quote>
  404. <filename>zodiac</filename></quote>. Once I knew which files were
  405. involved, I then had to figure out why they mentioned the driver and
  406. see where/if I needed to integrate my driver. I had settled on the
  407. name <filename>jupiter_t.c</filename> for my driver, since that did
  408. not conflict with any existing name space.</para>
  409. <para>Several of the files I turned up were obviously not interesting
  410. at this stage such as <filename>gpsd.spec</filename> and
  411. <filename>gpsd.xml</filename> and some others like
  412. <filename>gpsfake.py</filename> were determined not to be part of the
  413. main daemon, but <quote>support</quote> files used for things like
  414. regression testing or dummy traffic generation. Finally, I concluded
  415. that I needed to make mention of my driver in the following
  416. files:</para>
  417. <informaltable frame='none'>
  418. <tgroup cols='2'>
  419. <tbody>
  420. <row>
  421. <entry><filename>Makefile.am</filename></entry>
  422. <entry><para>controls what gets
  423. <quote><filename>make</filename></quote>d</para></entry>
  424. </row>
  425. <row>
  426. <entry><filename>configure.ac</filename></entry>
  427. <entry><para>configuration of compilation options</para></entry>
  428. </row>
  429. <row>
  430. <entry><filename>drivers.c</filename></entry>
  431. <entry><para>generic NMEA driver with device type scanner</para></entry>
  432. </row>
  433. <row>
  434. <entry><filename>gpsd.h</filename></entry>
  435. <entry><para>data type definitions</para></entry>
  436. </row>
  437. <row>
  438. <entry><filename>packet.c</filename></entry>
  439. <entry><para>packet sniffing state machine</para></entry>
  440. </row>
  441. <row>
  442. <entry><filename>packet_states.h</filename></entry>
  443. <entry><para>defines state machine entries each driver uses</para></entry>
  444. </row>
  445. </tbody>
  446. </tgroup>
  447. </informaltable>
  448. <para>These files will cause various files to be created which also
  449. inherit knowledge of your driver such as
  450. <filename>packet_names.h</filename> and later on you will probably need
  451. to modify other files like <filename>gpsfake.py</filename>, but the
  452. above fairly short list was all I had to handle at first. You will
  453. probably find something similar is necessary and if you miss one out,
  454. you will likely fail to get compilation to complete, usually with a
  455. message telling you where your new code is unknown.</para>
  456. </sect1>
  457. <sect1><title>What these important files do</title>
  458. <para>The first two files only need to know simple things for
  459. compilation; the <quote><filename>Makefile.am</filename></quote>
  460. needs only to have your driver added to the list of
  461. <quote><filename>libgps_c_sources</filename></quote>. I simply
  462. duplicated one of the existing lines and substituted my driver's name
  463. for the original copied name. The <quote><filename>config.ac
  464. </filename></quote> needs a few lines to tell the user what compile
  465. time options are available for your driver and to set its default
  466. options. I again copied an existing entry and changed the name,
  467. making sure I set the options so my driver was active by default.
  468. I also, as mentioned, modified the other drivers to default to
  469. inactive. You will also need to add your driver name to the list
  470. at the end of the file which issues a warning if no device drivers
  471. at all are selected at compilation time. Again, I copied and changed
  472. an existing entry.</para>
  473. <para>The <quote><filename>drivers.c</filename></quote> file handles
  474. some basic stuff for the NMEA driver and tries to wake up many of the
  475. other drivers. It needed four small modifications to integrate my
  476. code. The first was a copy of an existing entry in the generic NMEA
  477. handler <quote><function>nmea_parse_input</function></quote> to
  478. generate a debug error if one of my packets was detected when the NMEA
  479. driver had been selected and switch to my driver instead (this is no
  480. longer needed in versions beyond 2,38). The second was a pointer to
  481. simple command to send a Jupiter-T specific string to the GPS at
  482. detection time to test if it is a Jupiter-T in <quote>
  483. <function>nmea_initializer</function></quote>. If it returns the right
  484. answer (in my case, the manufacturer's PROM header), then the packet
  485. sniffer should see this and select my driver. The third was a
  486. (copied/modified) declaration entry in the list of structs known to
  487. <application>gpsd</application> which is located immediately before
  488. and is used by the fourth location,
  489. <quote>
  490. <userinput>*gpsd_driver_array[]</userinput></quote>, to
  491. give the address of the entry point table in my driver.</para>
  492. <para>The <quote><filename>gpsd.h</filename></quote> file is a
  493. conventional header file with declarations common to the whole
  494. application. The changes are again quite simple. There is an entry
  495. added to put my driver in the list of drivers that use binary
  496. mode. This depends if your driver is binary or not. I then modified
  497. the code which sets the maximum packet size as by default the largest
  498. packet was set to 196 bytes for the SiRF driver and the Jupiter-T can
  499. generate a maximum packet of 294 bytes. This is not as bad as it might
  500. seem, as this giant only comes when you dump the device identity
  501. strings from the PROM. The largest <quote>real</quote> packet is 96
  502. bytes for the <quote>Report ASCII Position</quote> message. The
  503. largest command sent is 52 bytes for a <quote>Input Pseudorange
  504. Correction</quote>. The largest received/sent packets used in
  505. <application>gpsd</application> so far are 92 and 20 bytes
  506. respectively. There is a single <quote>#define</quote> in <quote>
  507. <userinput>gps_device_t</userinput></quote> for the new packet type
  508. that this driver needs. This is simply an entry at the end of the
  509. existing list. The last two changes are two <quote>extern</quote>
  510. declarations of prototypes in <quote>
  511. <userinput>**gpsd_drivers</userinput></quote> that the new driver
  512. needs to interface to the rest of the code.</para>
  513. <para>The file <quote><filename>packet.c</filename></quote> is
  514. the state engine which scans packets as they arrive and tries to
  515. match them to an existing driver. Here is where our driver will
  516. be called, so the changes are a little larger. The driver starts
  517. at the beginning of each packet and tries to match, character by
  518. character, until it has determined which (if any) driver owns
  519. this packet in routine <quote>
  520. <function>nextstate</function></quote>. As all
  521. Jupiter-T packets start with <quote>
  522. <constant>@@</constant></quote>, this collides with the
  523. TNT driver, but fortunately, the TNT only uses a single
  524. <quote>
  525. <constant>@</constant></quote>, so matching the second
  526. one allows us to start checking more strictly for Jupiter-T
  527. data. This checking is done in a new block of code lower down
  528. in <quote>
  529. <function>nextstate</function></quote> that was
  530. modelled on the other drivers, but must needs be unique. The
  531. packet is scanned byte by byte until a fully formed packet
  532. has been detected and then it can be parsed in the main driver.
  533. If it fails any of the tests, the state engine is set back to
  534. <quote><constant>GROUND_STATE</constant></quote> and detection
  535. starts again. The code to trigger parsing and deletion of the
  536. packet after it has been parsed is included lower down in the
  537. code <quote>
  538. <function>packet_parse</function></quote> and is based
  539. on existing drivers.</para>
  540. <para>The file
  541. <quote><filename>packet_states.h</filename></quote> is simply
  542. a list of every state needed by every type of GPS which will
  543. produce a long list of unique entries (a big
  544. <filename>enum</filename> list) for use in the
  545. <quote><filename>packet.c</filename></quote> state engine.
  546. The changes here are limited to a small change to the TNT
  547. code, since both drivers share a common first character,
  548. so thus they share a state. There then follow the four new
  549. states that are required by the Jupiter-T state analysis.</para>
  550. </sect1>
  551. <sect1><title>Writing the actual driver code</title>
  552. <para>All that remains now is to write the driver
  553. and you are done. Actually, this part is not too hard,
  554. given the existing code base to guide and I
  555. actually found that the above changes were more troublesome as
  556. I did not know what would need to be updated; you, on the other
  557. hand, now have a nice list to guide you.</para>
  558. <para>The basic entry points or data values
  559. required of every driver are in visible in the
  560. <userinput>struct gps_type_t proto_binary</userinput> in
  561. <quote><filename>drivers_proto.c</filename></quote>. If
  562. any functions are not needed or not provided for your
  563. device, then the corresponding table entry should be a
  564. NULL or -1 (as appropriate). If they exist, the entry
  565. should contain the name of the function or the default
  566. value of the data. What follows is a list of each of
  567. the table entries with a short description of what it
  568. is expected to do or contain.</para>
  569. <para><structfield>.typename</structfield> is a simple string that
  570. uniquely identifies your driver. The first few characters are also
  571. output in some of the monitor output as generated by <filename>
  572. cgps</filename> or <filename>xgps</filename>.</para>
  573. <!-- added by ESR, 2009 -->
  574. <para><structfield>.packet_type</structfield> What packet type this
  575. driver expects to see. This value must be one of those produced by the
  576. packet sniffer and <emphasis>must be unique to each
  577. driver</emphasis>. It is used internally to dispatch to the correct
  578. driver when it collects a complete packet.</para>
  579. <!-- added by ESR, 2010 -->
  580. <para><structfield>.flags</structfield> Driver property flags. This
  581. field is reserved for future expansion.</para>
  582. <para><structfield>.trigger</structfield> is the unique string that,
  583. when seen, will confirm your device is present. This will be detected
  584. in <quote><filename>drivers.c</filename></quote> and will probably
  585. be the same value as that provoked by sending the command mentioned
  586. in <structfield>.probe_detect</structfield>below.</para>
  587. <para><structfield>.channels</structfield> is the number of channels your
  588. GPS uses. Typically this will be 12 for a consumer grade
  589. device.</para>
  590. <para><structfield>.probe_detect</structfield> points to a block of
  591. code that generates a command to send to the device that will provoke
  592. a response if your device is present. The code should then detect and
  593. recognise the response, signalling if detection was successful or
  594. not. Successful detection results in this driver claiming the attached
  595. device. It may also do some more exotic things like set the port to
  596. different operation modes (e.g. raw mode) from the default. If it
  597. makes changes to the port permanently, it should store the
  598. original settings for later restoration, probably by
  599. <structfield>.wrapup</structfield> mentioned below. Later in this
  600. document I discuss my work to implement this function.</para>
  601. <!-- added by ESR, 2014 -->
  602. <para><structfield>.init_query</structfield> points to a block of code
  603. that will be called to query the firmware version of the device. This
  604. code <emphasis>must not</emphasis> alter device state or settings.</para>
  605. <para><structfield>.event_hook</structfield> points to a block of code
  606. that will be executed on and after various events, distinguished by a
  607. second argument that specifies the event type. The event_hook hook is
  608. called in the following circumstances:</para>
  609. <itemizedlist>
  610. <listitem><para>When the main auto-baud hunt loop in the daemon offers
  611. a new speed to probe at, with event argument 'event_wakeup'. Note that
  612. this event does <emphasis>not</emphasis> fire for USB devices, in
  613. order to avoid spamming unidentified devices behind USB-to-serial adapters
  614. that may not be GPSes at all.</para></listitem>
  615. <listitem><para>When the driver has a trigger string and the NMEA driver
  616. sees it, 'event_triggermatch' fires. An 'event_switch_driver' should
  617. follow immediately.</para></listitem>
  618. <listitem><para>
  619. Whenever <application>gpsd</application> first achieves packet lock
  620. with a device, with event type 'identified'.
  621. </para></listitem>
  622. <listitem><para> Whenever a full packet is received, with event type
  623. 'event_configure'. On the first such packet, the packet sequence
  624. number is zeroed, then 'event_identify' fires, then 'event_configure'
  625. fires. On later packets, 'event_configure fires with the packet
  626. sequence number as its argument. </para></listitem>
  627. <listitem><para> Whenever a call to gpsd_switch_driver() sets a
  628. device's driver to a different type, with event type
  629. 'event_switch_driver'.</para></listitem>
  630. <listitem><para>When the device is closed, with event type
  631. 'event_deactivate'. (Closes happen when all clients have disconnected
  632. and the <quote><option>-n</option> </quote> switch is not active.) The
  633. premise is that there may be a special mode you initialized the device
  634. into for <application>gpsd</application> operation which should be
  635. turned off otherwise. It allows for changing the device to a low power
  636. mode, for instance. Any changes you made when 'event_configure' fired
  637. should be undone here. This is also where you should undo any port
  638. parameter changes you made in
  639. <structfield>.probe_detect</structfield>above.</para></listitem>
  640. <listitem><para>When a device is reactivated &mdash; that is, reopened
  641. after being been closed because no clients were listening to it, with
  642. event type 'event_reactivate' </para></listitem>
  643. </itemizedlist>
  644. <para>The 'event_identify' event is normally used to send probe
  645. strings that are expected to elicit a later response that will reveal
  646. the subtype of the driver. Such responses are expected to store
  647. information about the software version in member
  648. <quote><filename>subtype</filename></quote> of the driver data
  649. structure <userinput>struct gps_device_t *session</userinput>.</para>
  650. <para>The 'event_configure' event should set up the device to deliver
  651. the correct set of sentences to supply the parser with the data needed
  652. by <filename>gpsd</filename>.</para>
  653. <para>When writing hook code, it is useful to bear in mind that the
  654. <structfield>.packet.counter</structfield> member of the session
  655. structure is available; it is often useful to take action only
  656. when this counter is zero. It is zeroed when the device is activated
  657. or someting triggers a device change.</para>
  658. <para><structfield>.get_packet</structfield> points to a block of code
  659. that actually gets the packets from the serial stream. You will
  660. almost certainly use the generic routine
  661. <function>packet_get</function>. If you know this won't do,
  662. you already know enough not to need this explaining.</para>
  663. <para><structfield>.parse_packet</structfield> points to a block of code
  664. which parses a packet. This will be the main part of your
  665. driver.</para>
  666. <para><structfield>.rtcm_writer</structfield> points to a block of code
  667. used if the GPS type is capable of accepting differential-GPS
  668. corrections in RTCM-104 format. This is the routine needed to
  669. ship the data to the device. Usually it is a straight binary
  670. write of the data, which is provided by the default routine
  671. <function>pass_rtcm</function>. If the device does not
  672. accept differential data, the value is NULL.</para>
  673. <para><structfield>.speed_switcher</structfield> points to a block of
  674. code to change baud rate, parity, and stop bits (if supported). If
  675. your device can support some speed/parity/stopbits combinations but
  676. not others, it should return false on a mode-change request it can't
  677. handle.</para>
  678. <para><structfield>.mode_switcher</structfield> points to a block of code
  679. to change the mode (if supported) between NMEA (mode 0) and our
  680. binary mode (1).</para>
  681. <para><structfield>.rate_switcher</structfield> points to a block of code
  682. to change the maximum number of fixes your device can generate
  683. in 1 second. If this method is present, you should also fill in
  684. <structfield>.min_cycle</structfield> to indicate the device's
  685. minimum cycle time in seconds; a 0 value indicates that it is limited
  686. only by the data throughput of the reporting channel.</para>
  687. <para><structfield>.control_send</structfield> points to a block of
  688. code that can take a buffer full of message payload, wrap iit in
  689. appropriate headers and trailers and checksumming, and ship it to the
  690. device. This entry point is not used by gpsd itself; it's for
  691. diagnotic tools like gpsctl and gpsmon. Once you've written it,
  692. though, you may find it useful for implementing the other switcher
  693. methods and whatever other probe strings you need to send. Note: if
  694. possible, assemble your packet in
  695. <structfield>session->msgbuf</structfield> and put the length in
  696. <structfield>session->msgbuflen</structfield>; this will allow
  697. gpsmon to display the control messages it sends for you.</para>
  698. <!-- added by ESR, 2009 -->
  699. <para><structfield>.timr_offset</structfield> points to code to
  700. compute an offset to be added, additionally to that in
  701. <filename>ntp.conf</filename> (if any) when shipping time
  702. notifications to NTP, or the equivalent configuration file for
  703. chrony. If multiple sentences set TIME_IS, this will differ by
  704. sentence type; it should differ by baud rate, as well. </para>
  705. </sect1>
  706. <sect1><title>Details of the driver parser</title>
  707. <para>This part of the driver is likely to be the most unique part of
  708. your code and as such you will have to design and implement this your
  709. own way, but it may be useful to cover the details I included in my
  710. driver as the problems you will encounter are likely to be the same
  711. that I did.</para>
  712. <para>It is important not to lose sight of the aim of your driver. You
  713. are trying to convert the manufacturer-specific output of your GPS
  714. into a standard data block in <application>gpsd</application> so that a
  715. consistent set of information is available to client software
  716. regardless of what the original source was. In fact,
  717. <application>gpsd</application> will produce a nice set of NMEA output
  718. from your data stream for you to look at if you wish. This output can
  719. be captured and played back into <application>gpsd</application> at a
  720. later date and it will be handled as though it came from a standard
  721. NMEA device.</para>
  722. <para>The most important information is the actual navigation
  723. position/track/speed/time/climb rate information, but we also take
  724. note of some secondary things like DOP/satellite status if it is
  725. available. In my case, all the fields could be filled directly from
  726. the data shipped by the GPS in the two messages which I activated.
  727. The satellite status data contained exactly what was needed. The
  728. navigation data was all present but some fields did need some
  729. massaging; for example, my GPS reports location data in
  730. milliArcseconds whilst <application>gpsd</application> works in
  731. degrees. All conversions were achieved by simple division by
  732. constants. A few of the more exotic fields such as the quality of the
  733. fix (2D/3D etc.) were packed bit values in bytes or words, but these
  734. were extracted by simple masking and testing.</para>
  735. <para>Initially, I was able to get testable
  736. results from just the two command/report strings that were set
  737. in Windows, but later on I added the capability to bring the
  738. device into use from a cold start through the daemon by adding
  739. the routines such as
  740. <structfield>.probe_detect</structfield> and
  741. <structfield>.trigger</structfield> along with some status
  742. requests.</para>
  743. <!-- ESR: gpsd_log had a different name when this was written -->
  744. <para>As I hinted earlier, I found that support code like <quote>
  745. <userinput>gpsd_log(LOG_WARN, ..., "satellites tracked = %d, seen =
  746. %d\n", tracked, seen);</userinput></quote> was very helpful in the
  747. early stages. Once the driver reached a production stage, much of the
  748. support code was removed and that which was retained had the first
  749. parameter (the debug level it responds to) increased to a more
  750. appropriate level.</para>
  751. <para>For me, support code and copious comments
  752. were vital since I find that the code I wrote as a genius
  753. yesterday is incomprehensible today when I am an idiot. I
  754. realise this is not to everyone's taste, but my view is that
  755. excessive comments can be ignored; missing comments don't help
  756. someone trying to follow your code later &lt;rant mode
  757. off&gt;</para>
  758. </sect1>
  759. <sect1><title>Implementing the <structfield>.probe_detect</structfield> function</title>
  760. <para>As I mentioned earlier, my GPS device
  761. needed to be <quote>woken up</quote>,
  762. otherwise it would never be detected by the normal packet
  763. scanner. The
  764. <structfield>.probe_detect</structfield> function is intended for
  765. just such a case and allows you to seek your device and claim
  766. the port ahead of the normal initialisation, since a check for
  767. devices supporting the
  768. <structfield>.probe_detect</structfield> is made at a very early
  769. point in the startup. The unfortunate thing is that to
  770. implement the function could mean getting down to low level
  771. programming of the tty port since you may find the normal
  772. operating mode capabilities may not match your device's
  773. requirement, even if the baud rate is correct. This
  774. proved to be the case for me and was the single most difficult
  775. part of writing the driver. This, I am sure, is because it involves
  776. working virtually directly with the system hardware. I have documented
  777. this process in some detail in the hope that it may save some other
  778. poor soul the trials I went through.</para>
  779. <!-- Mick actually looked at sirfmon -->
  780. <para>I looked at the code in
  781. <quote><filename>serial.c</filename></quote>,
  782. <quote><filename>garmin.c</filename></quote> and
  783. <quote><filename>gpsmon.c</filename></quote> for inspiration
  784. and noticed some important things:</para>
  785. <itemizedlist>
  786. <listitem><para>You must read and preserve the existing port
  787. settings so that if you change anything, it can be restored
  788. later. This probably means you will have to implement the
  789. <structfield>.wrapup</structfield> function, but this is
  790. likely to be a reverse of the settings you finally arrive
  791. at in this function.</para></listitem>
  792. <listitem><para>You need to be aware of and understand the low level
  793. control settings that are needed to manipulate parameters like parity,
  794. stop bit number, flow control and port mode (raw/cooked). Take some
  795. time to read up on termios (<userinput>man 3 termios</userinput> will
  796. give the grisly details).</para></listitem>
  797. <listitem><para>You will probably find that you need to verify what
  798. delay loops are needed to allow your hardware to catch up if you
  799. change port settings (UART flush and other factors are described in
  800. detail in <quote><filename>serial.c</filename></quote> and you should
  801. read it carefully).</para></listitem>
  802. </itemizedlist>
  803. <para>I also found that even this was not the whole
  804. story, since even when I had allowed the device to catch up on
  805. a settings change, I could not get it to respond reliably to a
  806. <quote>device identify</quote> command. I found that I was
  807. missing some or all of the response message when operating
  808. at 9600 bps.</para>
  809. <para>The reason was that I originally checked the port with a
  810. single character sniff routine a maximum of 300 times (just bigger
  811. than the block of text being returned), which comes out at 300 *
  812. (1 start bit + 8 data bits + 1 stop bit) = 3000 bits. I expected
  813. this would occupy about 312 milliseconds which I considered as an
  814. acceptable delay during the probing phase, but my understanding of
  815. how the serial port is accessed turned out to be faulty. This method
  816. was originally chosen because the probe is speculative and must handle
  817. cases like wrong port speed or the type of device being probed for
  818. is not present and should not hold up progress for too long. Don't
  819. forget that all installed drivers get a chance to probe, one after
  820. another, so the delays for each are cumulative and if no driver
  821. finds and claims the device, you can have many seconds of delay.</para>
  822. <para>When it failed to work as expected, I investigated the GPS device's
  823. documentation (<quote>RTFM</quote> did I hear you say!) and I found in the
  824. Oncore manual that the device's internal scheduler uses a 1
  825. second loop time. Within this loop, the navigation tasks are handled
  826. first, followed by processing of the input commands. Any
  827. resultant output will be generated as soon as the input
  828. buffer is processed, assuming the buffer holds one or more
  829. complete commands.</para>
  830. <para>If you are lucky and just finish your input as the
  831. buffer is ready to be scanned, you can get a result back in 70
  832. milliseconds. If you are unlucky, the most extreme delay is 2
  833. seconds. On average, the turnaround is 1025 milliseconds.
  834. Unfortunately, in the probing code, we have to allow for the
  835. worst case, so once the code issues a command, it has then to
  836. allow a full 2 seconds before scanning for output.</para>
  837. <para>When I found that my initial scanning method was not viable,
  838. I experimented and eventually settled on a loop using a
  839. <function>while</function> statement that checked
  840. time stamp values and was set
  841. to time out at 2 seconds maximum duration, with an early exit on
  842. successfully finding the wanted data. Within the loop, I tested
  843. the serial port for an available character. If one was available,
  844. I checked it against my expected string; if one was not available,
  845. I looped again if the timer had not expired. If I encountered an
  846. error when reading the port I exited. All exits returned a
  847. success/fail value.</para>
  848. <!-- ESR: gpsd_log had a different name when this was written -->
  849. <para>This worked better, but still failed occasionally. I then used
  850. the <quote><function>gpsd_log</function></quote> to check the
  851. error returned and I saw that I was getting lots of <quote>EAGAIN</quote>
  852. errors. This suggested that the port was not able to handle all my
  853. read requests, so I suspected the rate of reading was too fast. Not knowing
  854. for sure, I trapped this particular error and applied a <function>
  855. usleep()</function> of a couple of milliseconds when it occurred. This was
  856. enough to cure the problem and I could get the detection to track
  857. the device's responses reliably. I saw a spread of detection timing
  858. between 250 milliseconds and 1.7 seconds over a large number of tests,
  859. so I concluded that the manufacturer's predictions were being
  860. satisfied.</para>
  861. <para>The only other serial port setting which was not immediately
  862. obvious to me (although present in both <quote><filename>serial.c
  863. </filename></quote> and <quote><filename>sirfmon.c</filename></quote>
  864. ) was <quote><userinput>session-&gt;ttyset.c_cflag |= CREAD |
  865. CLOCAL;</userinput></quote>. This is needed to enable the port and
  866. cause it to ignore any modem control lines. If you are using a
  867. binary protocol , you will also need to issue a
  868. <quote><userinput>cfmakeraw (struct termios *termios_p);</userinput></quote>
  869. to quickly set the most important flags correctly. I was bitten by
  870. this and found that transmitted &lt;CR/LF&gt; sequences were being modified
  871. to &lt;CR/CR/LF&gt; by the kernel's tty port driver.</para>
  872. </sect1>
  873. <sect1><title>Sign off</title>
  874. <para>Hopefully this short document has been some use to you and maybe
  875. encouraged you to <quote>have a go</quote>. I had never attempted
  876. anything so ambitious as this driver before where my code would be put
  877. up to public scrutiny, but I found the experience very rewarding and
  878. found the <application>gpsd</application> community, especially Eric
  879. Raymond, highly supportive and encouraging.</para>
  880. <para>Your feedback on this document, especially any suggestions for
  881. improvements would be most welcome.</para>
  882. <para>Mick Durkin
  883. &lt;mick.durkin@saunalahti.fi&gt;</para>
  884. <para>Helsinki</para>
  885. <para>November 2006</para>
  886. </sect1>
  887. </article>