summaryrefslogtreecommitdiff
path: root/doc
diff options
context:
space:
mode:
authorEric S. Raymond <esr@thyrsus.com>2010-04-06 10:46:17 -0400
committerEric S. Raymond <esr@thyrsus.com>2010-04-06 10:46:17 -0400
commit8c1577ca9c8df3d8f72b8b4b6149d4cc5f59bd92 (patch)
treee9fdbc70ffcd7402d6a38554e1c1cfb8fd6347d7 /doc
parentd3a57ee1e3d65f7bc96f9b330fa2ab11892ccce2 (diff)
downloadgpsd-8c1577ca9c8df3d8f72b8b4b6149d4cc5f59bd92.tar.gz
Update Mick Durkin's internals tour and make it part of the website material.
Diffstat (limited to 'doc')
-rw-r--r--doc/Makefile32
-rw-r--r--doc/explan_bits.h.xml10
-rw-r--r--doc/explan_dgnss.c.xml49
-rw-r--r--doc/explan_driver_nmea.c.xml208
-rw-r--r--doc/explan_driver_proto.c.xml2
-rw-r--r--doc/explan_driver_rtcm2.c.xml54
-rw-r--r--doc/explan_drivers.c.xml2
-rw-r--r--doc/explan_geoid.c.xml11
-rw-r--r--doc/explan_gps.h.xml6
-rw-r--r--doc/explan_gpsd.c.xml278
-rw-r--r--doc/explan_gpsd.h.xml2
-rw-r--r--doc/explan_gpsd_dbus.c.xml2
-rw-r--r--doc/explan_gpsd_report.c.xml (renamed from doc/explan_report.c.xml)11
-rw-r--r--doc/explan_gpsdclient.c.xml33
-rw-r--r--doc/explan_gpsutils.c.xml14
-rw-r--r--doc/explan_isgps.c.xml26
-rw-r--r--doc/explan_libgps.c.xml85
-rw-r--r--doc/explan_libgps_core.c.xml111
-rw-r--r--doc/explan_libgpsd_core.c.xml119
-rw-r--r--doc/explan_libgpsmm.cpp.xml2
-rw-r--r--doc/explan_libgpsmm.h.xml2
-rw-r--r--doc/explan_net_dgnss_dispatch.c.xml61
-rw-r--r--doc/explan_net_dgpsip.c.xml (renamed from doc/explan_dgpsip.c.xml)24
-rw-r--r--doc/explan_net_ntrip.c.xml (renamed from doc/explan_ntrip.c.xml)37
-rw-r--r--doc/explan_netlib.c.xml14
-rw-r--r--doc/explan_nmea_parse.c.xml85
-rw-r--r--doc/explan_ntpshm.c.xml36
-rw-r--r--doc/explan_packet.c.xml52
-rw-r--r--doc/explan_packet_names.h.xml9
-rw-r--r--doc/explan_packet_states.h.xml10
-rw-r--r--doc/explan_pseudonmea.c.xml55
-rw-r--r--doc/explan_rtcm.c.xml57
-rw-r--r--doc/explan_serial.c.xml63
-rw-r--r--doc/explan_subframe.c.xml2
-rw-r--r--doc/explan_timebase.h.xml8
-rw-r--r--doc/explanation.xml107
36 files changed, 1172 insertions, 507 deletions
diff --git a/doc/Makefile b/doc/Makefile
index 1be7b834..83672ef1 100644
--- a/doc/Makefile
+++ b/doc/Makefile
@@ -1,32 +1,2 @@
-XML_SOURCES = explanation.xml \
- explan_bits.h.xml \
- explan_dgnss.c.xml \
- explan_dgpsip.c.xml \
- explan_drivers.c.xml \
- explan_geoid.c.xml \
- explan_gpsd.c.xml \
- explan_gpsd_dbus.c.xml \
- explan_gpsd.h.xml \
- explan_gps.h.xml \
- explan_gpsutils.c.xml \
- explan_isgps.c.xml \
- explan_libgps.c.xml \
- explan_libgpsd_core.c.xml \
- explan_libgpsmm.cpp.xml \
- explan_libgpsmm.h.xml \
- explan_netlib.c.xml \
- explan_nmea_parse.c.xml \
- explan_ntpshm.c.xml \
- explan_ntrip.c.xml \
- explan_packet.c.xml \
- explan_packet_names.h.xml \
- explan_packet_states.h.xml \
- explan_report.c.xml \
- explan_rtcm.c.xml \
- explan_serial.c.xml \
- explan_subframe.c.xml \
- explan_timebase.h.xml \
- explan_wrapup.xml
-
-explanation.html: $(SOURCES)
+explanation.html: $(shell ls *.xml)
xmlto xhtml-nochunks explanation.xml
diff --git a/doc/explan_bits.h.xml b/doc/explan_bits.h.xml
index 6a26c2f0..4f188c26 100644
--- a/doc/explan_bits.h.xml
+++ b/doc/explan_bits.h.xml
@@ -7,13 +7,19 @@
<tfoot>
<row>
- <entry spanname='s1' align='left'>Notes based on <function>$Id: bits.h 4030 2006-11-30 07:29:25Z esr $</function></entry>
+ <entry spanname='s1' align='left'>Notes based on code as of Mon Apr 5 21:38:06 2010 -0400.</entry>
</row>
</tfoot>
<tbody>
<row>
- <entry><para>This file only contains macros that convert data variables from the native format of the device output (MSB-first or LSB-first) into a standard form for <function>gpsd</function> use. This makes data parsing consistent regardless of the underlying format. If the device driver file makes no deliberate selection, the default is to assume the device emits data in big-endian (network byte) order.</para></entry>
+ <entry><para>This file only contains macros that convert data
+ variables from the native format of the device output (MSB-first or
+ LSB-first) into a standard form for <function>gpsd</function>
+ use. This makes data parsing consistent regardless of the underlying
+ format. If the device driver file makes no deliberate selection, the
+ default is to assume the device emits data in big-endian (network
+ byte) order.</para></entry>
</row>
</tbody>
diff --git a/doc/explan_dgnss.c.xml b/doc/explan_dgnss.c.xml
deleted file mode 100644
index 2337bfa5..00000000
--- a/doc/explan_dgnss.c.xml
+++ /dev/null
@@ -1,49 +0,0 @@
-<sect1 id="dgnss.c"><title><filename>dgnss.c</filename></title>
-<informaltable frame='all' pgwide='1'>
-<tgroup cols='2'>
-<colspec colname='c1'></colspec>
-<colspec colname='c2'></colspec>
-<spanspec spanname='s1' namest='c1' nameend='c2'></spanspec>
-
-<thead>
-<row>
- <entry>Functions:-</entry><entry>This file provides the interface to Differential GNSS (Global Navigation Satellite Systems) services.</entry>
-</row>
-</thead>
-
-<tfoot>
-<row>
- <entry spanname='s1' align='left'>Notes based on <function>$Id: dgnss.c 3771 2006-11-02 05:15:20Z esr $</function></entry>
-</row>
-</tfoot>
-
-<tbody>
-<row>
- <entry><function>bool dgnss_url(char *name)</function></entry>
- <entry><para>Check if a URL is valid for DGPS service.</para></entry>
-</row>
-<row>
- <entry><function>int dgnss_open(struct gps_context_t *context, char *dgnss_service)</function></entry>
- <entry><para>Try to open a connection to the nominated service. If the service cannot be opened, the return is -1. The supported services are <function>dgpsip</function> (differential corrections via IP) and <function>ntrip</function> (differential corrections in http form).</para></entry>
-</row>
-<row>
- <entry><function>int dgnss_poll(struct gps_context_t *context)</function></entry>
- <entry><para>Try to poll the DGNSS service for a correction report. If no socket is active, simply return 0. If a socket is active, on successful read it stores the current timestamp and the report in the context buffer then returns 0. If no data is ready or an error (except <errortype>EAGAIN</errortype>) occurs, drop the connection and return -1.</para></entry>
-</row>
-<row>
- <entry><function>void dgnss_report(struct gps_device_t *session)</function></entry>
- <entry><para>Call the <function>dgpsip_report()</function> or <function>ntrip_report()</function> function if either is active.</para></entry>
-</row>
-<row>
- <entry><function>void dgnss_autoconnect(struct gps_context_t *context, double lat, double lon)</function></entry>
- <entry><para>Call the <function>autoconnect()</function> function in <function>dgpsip.c</function></para></entry>
-</row>
-<row>
- <entry><function>void rtcm_relay(struct gps_device_t *session)</function></entry>
- <entry><para>If there is a DGNSS connection report in the context buffer, pass it to the caller. If the transaction fails, generate an error log, otherwise, update the session timestamp.</para></entry>
-</row>
-</tbody>
-
-</tgroup>
-</informaltable>
-</sect1>
diff --git a/doc/explan_driver_nmea.c.xml b/doc/explan_driver_nmea.c.xml
new file mode 100644
index 00000000..ab501e87
--- /dev/null
+++ b/doc/explan_driver_nmea.c.xml
@@ -0,0 +1,208 @@
+<sect1 id="driver_nmea.c"><title><filename>nmea_parse.c</filename></title>
+<informaltable frame='all' pgwide='1'>
+<tgroup cols='2'>
+<colspec colname='c1'></colspec>
+<colspec colname='c2'></colspec>
+<spanspec spanname='s1' namest='c1' nameend='c2'></spanspec>
+
+<!-- Not documented: processGPGBS(), processOHPR(), processPASHR() -->
+
+<thead>
+<row>
+ <entry>Functions:-</entry><entry>Parser for NMEA strings, generic and proprietary.</entry>
+</row>
+</thead>
+
+<tfoot>
+<row>
+ <entry spanname='s1' align='left'>Notes based on code as of Mon Apr 5 21:38:06 2010 -0400.</entry>
+</row>
+</tfoot>
+
+<tbody>
+<row>
+ <entry><function>static void do_lat_lon(char *field[], struct gps_fix_t *out)</function></entry>
+ <entry><para>Reads a four element array containing the value and
+ hemisphere of the latitude and longitude of a location as text. It
+ converts them into signed (-ve for S and W) values. The
+ <structname>gps_data_t</structname> structure is updated with the
+ new value(s).</para></entry>
+</row>
+<row>
+ <entry><function>static void merge_ddmmyy(char *ddmmyy, struct gps_device_t *session)</function></entry>
+ <entry><para>If the century has not yet been stored in the nmea
+ driver private data, take the supplied ddmmyy date and generate and
+ store a ddmmyyyy date, using the century value compiled in from
+ <function>timebase.h</function>.</para></entry>
+</row>
+<row>
+ <entry><function>static void merge_hhmmss(char *hhmmss, struct gps_device_t *session)</function></entry>
+ <entry><para>Stash the present hour value before updating it from
+ the incoming data. If the new hour is less than the stashed value,
+ we have passed midnight, so update the day value. Finally update the
+ minutes, seconds and fractions of a second from the incoming
+ data.</para></entry>
+</row>
+<row>
+ <entry><function>static gps_mask_t processGPRMC(int count, char *field[], struct gps_device_t *session)</function></entry>
+ <entry><para>Handle a $GPRMC sentence stored in an array of strings,
+ one member per field.</para><para>Check if the message is stamped
+ valid or not.</para><para>If it is invalid, set the status and fix
+ mode to NO_FIX and save the corresponding flags locally; also save
+ the online flag to indicate we have handled a known
+ sentence.</para><para>If the fix is autonomous and valid, start to
+ decode the fields.</para><para>First, test if there are enough
+ fields available; then handle the date and time via
+ <function>merge_ddmmyy()</function> and
+ <function>merge_hhmmss()</function>, storing the TIME_SET flag and
+ storing the fix time as a UNIX-epoch relative value.</para><para>If
+ the sentence time and this fix time are different, we have started a
+ new cycle of observation, so update the sentence time and the store
+ the CYCLE_START_SET flag.</para><para>Whatever the number of fields,
+ store the fix co-ordinates via <function>do_lat_lon()</function>,
+ store the speed and the track and save the corresponding
+ flags.</para><para>Return the local aggregated flags to allow the
+ main copy in the session data to be updated.</para></entry>
+</row>
+<row>
+ <entry><function>static gps_mask_t processGPGLL(int count, char *field[], struct gps_device_t *session)</function></entry>
+ <entry><para>Preload the local flag with the ERROR_SET
+ flag.</para><para>Check that the sentence is usable, exiting with
+ the preset error flag if it is not.</para><para>If it is usable,
+ clear the local flags and start processing the fields, updating any
+ local flag fields on the way.</para><para>If the year is already
+ known, update the time and check for the start of cycle (see
+ <function>processGPRMC()</function> above).</para><para>Handle the
+ fix location and, if the number of received fixes is more than 8 and
+ the status is differential, stash the new status as STATUS_DGPS_FIX;
+ otherwise stash STATUS_FIX.</para><para>If the present mode is less
+ than 2D_FIX, update it to 2D_FIX.</para><para>Write the stashed
+ value of newstatus into the session status and return all the
+ locally aggregated flags.</para></entry>
+</row>
+<row>
+ <entry><function>static gps_mask_t processGPGGA(int c UNUSED, char *field[], struct gps_device_t *session)</function></entry>
+ <entry><para>Stash the last fix time. Set the status to the value in
+ the message and update the local flag variable.</para><para>If the
+ status is STATUS_NO_FIX, exit immediately, returning the locally
+ aggregated flags. If there is a fix, process it.</para><para>Handle
+ the time as in <function>processGPGLL()</function> above. Handle the
+ latitiude and longitude with a call to
+ <function>do_lat_lon()</function> above and set the local
+ flag.</para><para>Update the <function>satellites_used</function>
+ field and stash the altitude.</para><para>If the altitude is empty,
+ force the fix mode and status to 2D if it was 3D
+ previously.</para><para>If it is not empty, stash the old value of
+ altitude and replace it with the new value stashed earlier and set
+ the local flag variable. If the mode is presently less than 3D,
+ update it to 3D and set the local flag.</para><para>If the stashed
+ old altitude is NaN or the stashed fix time and current fix time are
+ equal, set the climb rate to 0 otherwise calculate it by dividing
+ the altitude difference by the time difference and set the local
+ flag.</para><para>If the geoid separation is available, store it,
+ otherwise store the value from
+ <function>wgs84_separation()</function> that depends on current
+ location.</para><para>Finally, return all the locally aggregated
+ flags.</para></entry>
+</row>
+<row>
+ <entry><function>static gps_mask_t processGPGSA(int count, char *field[], struct gps_device_t *session)</function></entry>
+ <entry><para>Start with a simple validity check on the number of
+ fields (for i.Trek M3) and bail out with a simple indication of
+ on-line status if it fails.</para><para>Set the fix mode from the
+ sentence and either clear the local flag variable (if an Antaris
+ chipset says we are in dead-reckoning mode) or set the MODE_SET
+ flag.</para><para>Update all the DOP fields from the sentence, clear
+ the count of used satellites, then scan all the satellite
+ data.</para><para>If any satellite is good (prn != 0), store the prn
+ and increment the count of used satellites.</para><para>Finally, set
+ the local flags to indicate that DOPs are available and return all
+ the locally aggregated flags.</para></entry>
+</row>
+<row>
+ <entry><function>static gps_mask_t processGPGSV(int count, char *field[], struct gps_device_t *session)</function></entry>
+ <entry><para>Check if the sentence has too few fields or the wrong
+ number fo fields. In this case, clear the data for all satellites
+ and return with an error indication.</para><para>Start to parse the
+ sentence. First, note how many sentences are to be expected to
+ complete the data transfer.</para><para>If the sentence number is
+ invalid, clear the data for all satellites and return with an error
+ indication.</para><para>If this is the first sentence of the
+ sequence, clear the data for all satellites.</para><para>Loop
+ through the sentence fields, updating the session's satellite
+ data.</para><para>If any satellite number is higher than the number
+ of channels, clear all satellite data and break out of the
+ loop.</para><para>Assuming this is not a buggy chipset
+ (e.g. Motorola Oncore GT+), update the satellite count and loop
+ again.</para><para>If this was the last sentence of the block and
+ the number of satellites seen is not the same as the number
+ reported, generate an error log.</para><para>If this is not the last
+ sentence of the block, exit early and return an error flag as a
+ guard.</para><para>Finally, on the last sentence, carry out a sanity
+ check and either return an error flag or a SATELLITE_SET
+ flag.</para></entry>
+</row>
+<row>
+ <entry><function>static gps_mask_t processPGRME(int c UNUSED, char *field[], struct gps_device_t *session)</function></entry>
+ <entry><para>Check that the error estimate data is good. If not, set
+ all error estimate fields to 100m and return an error
+ flag.</para><para>If they are good, calcluate the error value and
+ store it. Return the approriate flag values.</para></entry>
+</row>
+<row>
+ <entry><function>static gps_mask_t processGPZDA(int c UNUSED, char *field[], struct gps_device_t *session)</function></entry>
+ <entry><para>Set the local flag variable to indicate that the time
+ is available.</para><para>Store the actual time by a call to
+ <function>merge_hhmmss()</function> and fill in the other fields
+ from the sentence data.</para><para>If the sentence is not
+ timestamped the same as the fixtime, set the CYCLE_START_SET
+ flag.</para><para>Update the fixtime to the sentence
+ timestamp.</para><para>Finally, return all the locally aggregated
+ flags.</para></entry>
+</row>
+<row>
+ <entry><function>static gps_mask_t processTNTHTM(int c UNUSED, char *field[], struct gps_device_t *session)</function></entry>
+ <entry><para>Set the local variable to indicate the the unit is
+ on-line.</para><para>Fill all appropriate fields from the sentence
+ and set the associated flags in the local flag
+ variable.</para><para>Set the fix status and return all the locally
+ aggregated flags.</para></entry>
+</row>
+<row>
+ <entry><function>static short nmea_checksum(char *sentence, unsigned char *correct_sum)</function></entry>
+ <entry><para>Calculate and return the checksum of an NMEA sentence.</para></entry>
+</row>
+<row>
+ <entry><function>gps_mask_t nmea_parse(char *sentence, struct gps_device_t *session)</function></entry>
+ <entry><para>Test that the length of the NMEA sentence is
+ acceptable, simply returning an on-line indication if it is too long
+ to handle.</para><para>If it is within limits, make a local copy and
+ split it on the commas into an array, one field per
+ element.</para><para>Use the first element to match the command to
+ the table of decodable commands.</para><para>Check if it is
+ supported and the number of fields is reasonable, invoke the correct
+ decoder and return the value from that call.</para><para>If it fails
+ the check, simply return an on-line status.</para><para>This function is
+ also responsible for performing adaptive end-of-cycle
+ detection.</para></entry>
+</row>
+<row>
+ <entry><function>void nmea_add_checksum(char *sentence)</function></entry>
+ <entry><para>Calcluate the checksum then append '*' + the checksum + CR/LF to the end of an NMEA sentence, skipping any existing '*'.</para></entry>
+</row>
+<row>
+ <entry><function>int nmea_write(struct gps_device_t *session, const char *fmt, ... )</function></entry>
+ <entry><para>Ship a string to an NMEA device, adding a checksum and
+ CR/LF if needed. A checksum is added only if the sentence begins
+ with '$'. Bytes written are returned.</para></entry>
+</row>
+<row>
+ <entry><function>int nmea_send(struct gps_device_t *session, , const char *fmt, ... )</function></entry>
+ <entry><para>A wrapper around <function>nmea_write()</function> to
+ give it sprintf-like varargs behavior.</para></entry>
+</row>
+</tbody>
+
+</tgroup>
+</informaltable>
+</sect1>
diff --git a/doc/explan_driver_proto.c.xml b/doc/explan_driver_proto.c.xml
index 78982a93..9ea580fa 100644
--- a/doc/explan_driver_proto.c.xml
+++ b/doc/explan_driver_proto.c.xml
@@ -7,7 +7,7 @@
<tfoot>
<row>
- <entry spanname='s1' align='left'>Notes based on <function>$Id: driver_proto.c 4373 2007-06-01 22:30:43Z esr $</function></entry>
+ <entry spanname='s1' align='left'>Notes based on code as of Mon Apr 5 21:38:06 2010 -0400.</entry>
</row>
</tfoot>
diff --git a/doc/explan_driver_rtcm2.c.xml b/doc/explan_driver_rtcm2.c.xml
new file mode 100644
index 00000000..ae846514
--- /dev/null
+++ b/doc/explan_driver_rtcm2.c.xml
@@ -0,0 +1,54 @@
+<sect1 id="driver_rtcm1.c"><title><filename>rtcm.c</filename></title>
+<informaltable frame='all' pgwide='1'>
+<tgroup cols='2'>
+<colspec colname='c1'></colspec>
+<colspec colname='c2'></colspec>
+<spanspec spanname='s1' namest='c1' nameend='c2'></spanspec>
+
+<thead>
+<row>
+ <entry>Functions:-</entry><entry>This is a decoder for the RTCM-104 serial protocol.</entry>
+</row>
+</thead>
+
+<tfoot>
+<row>
+ <entry spanname='s1' align='left'>Notes based on code as of Mon Apr 5 21:38:06 2010 -0400.</entry>
+</row>
+</tfoot>
+
+<tbody>
+<row>
+ <entry><function>void rtcm2_unpack(struct rtcm2_t *tp, char *buf)</function></entry>
+ <entry><para>Splits RTCM2 raw data into fields.</para></entry>
+</row>
+<row>
+ <entry><function>bool rtcm2_repack(struct rtcm2_t *tp, isgps30bits_t *buf)</function></entry>
+ <entry><para>Packs RTCM2 fields into a raw data stream.</para></entry>
+</row>
+<row>
+ <entry><function>static bool preamble_match(isgps30bits_t *w)</function></entry>
+ <entry><para>Tells if the preamble field in a message is valid or
+ not.</para></entry>
+</row>
+<row>
+ <entry><function>static bool length_check(struct gps_packet_t *lexer)</function></entry>
+ <entry><para>Tells if the message length is valid or not.</para></entry>
+</row>
+<row>
+ <entry><function>enum isgpsstat_t rtcm2_decode(struct gps_packet_t *lexer, unsigned int c)</function></entry>
+ <entry><para>A simple call to <function>isgps_decode()</function>.</para></entry>
+</row>
+<row>
+ <entry><function>void rtcm2_dump(struct rtcm2_t *rtcm2, char buf[], size_t buflen)</function></entry>
+ <entry><para>Dump the contents of a parsed RTCM104v2 message.</para></entry>
+</row>
+<row>
+ <entry><function>void rtcm2_output_magnavox(isgps30bits_t *ip, FILE *fp)</function></entry>
+ <entry><para>Ship an RTCM2 message in the format emitted by Magnavox DGPS receivers.</para></entry>
+</row>
+</tbody>
+
+</tgroup>
+</informaltable>
+</sect1>
diff --git a/doc/explan_drivers.c.xml b/doc/explan_drivers.c.xml
index ce25650e..e3ca682b 100644
--- a/doc/explan_drivers.c.xml
+++ b/doc/explan_drivers.c.xml
@@ -13,7 +13,7 @@
<tfoot>
<row>
- <entry spanname='s1' align='left'>Notes based on <function>$Id: drivers.c 4373 2007-06-01 22:30:43Z esr $</function></entry>
+ <entry spanname='s1' align='left'>Notes based on cde as of Mon Apr 5 21:38:06 2010 -0400.</entry>
</row>
</tfoot>
diff --git a/doc/explan_geoid.c.xml b/doc/explan_geoid.c.xml
index 06e4b948..c2dd6ee5 100644
--- a/doc/explan_geoid.c.xml
+++ b/doc/explan_geoid.c.xml
@@ -13,22 +13,25 @@
<tfoot>
<row>
- <entry spanname='s1' align='left'>Notes based on <function>$Id: geoid.c 4257 2007-01-18 03:56:43Z ckuethe $</function></entry>
+ <entry spanname='s1' align='left'>Notes based on code as of Mon Apr 5 21:38:06 2010 -0400.</entry>
</row>
</tfoot>
<tbody>
<row>
<entry><function>static double bilinear(double x1, double y1, double x2, double y2, double x, double y, double z11, double z12, double z21, double z22)</function></entry>
- <entry><para>This is a piece of mathematical manipulation only used internally in this code, so wrestle with it if you will!</para></entry>
+ <entry><para>This is a piece of mathematical manipulation only used internally in this code, so wrestle with it if you will! It's used to perform bilinear interpolation on the grid points in the WGS4 geoidal-separation array.</para></entry>
</row>
<row>
<entry><function>double wgs84_separation(double lat, double lon)</function></entry>
<entry><para>This is used by drivers to get the separation of MSL from the WGS84 datum at a pair of Latitude/Longitude co-ordinates. The data is in a pre-defined table.</para></entry>
</row>
<row>
- <entry><function>void ecef_to_wgs84fix(struct gps_data_t *gpsdata, double x, double y, double z, double vx, double vy, double vz)</function></entry>
- <entry><para>This does exactly what it says! Co-ordinate system conversion from ecef to the wgs84 equivalent.</para></entry>
+
+ <entry><function>void ecef_to_wgs84fix(struct gps_data_t *gpsdata, double x, double y, double z, double vx, double vy, double vz, float *separation)</function></entry>
+ <entry><para>This does exactly what it says! Co-ordinate system
+ conversion from ecef to the wgs84 equivalent. Geodetic separation
+ for the fix is left in *separaation</para></entry>
</row>
<row>
<entry><function>static double fix_minuz(double d)</function></entry>
diff --git a/doc/explan_gps.h.xml b/doc/explan_gps.h.xml
index 5e6c72a1..8bebee9c 100644
--- a/doc/explan_gps.h.xml
+++ b/doc/explan_gps.h.xml
@@ -5,6 +5,8 @@
<colspec colname='c2'></colspec>
<spanspec spanname='s1' namest='c1' nameend='c2'></spanspec>
+<!-- Not documented: struct ais_t, struct rtcm3_t -->
+
<thead>
<row>
<entry>Structures:-</entry><entry>The interface of the libgps library, provides data structures the library needs and that the daemon fills.</entry>
@@ -13,7 +15,7 @@
<tfoot>
<row>
- <entry spanname='s1' align='left'>Notes based on <function>$Id: gps.h 4369 2007-06-01 19:23:17Z esr $</function></entry>
+ <entry spanname='s1' align='left'>Notes based on code as of Mon Apr 5 21:38:06 2010 -0400</entry>
</row>
</tfoot>
@@ -23,7 +25,7 @@
<entry><para>This is the fix related data gathered from the gps device. Each client session has 2, the current fix and the previous fix.</para></entry>
</row>
<row>
- <entry><function>struct rtcm_t {}</function></entry>
+ <entry><function>struct rtcm2_t {}</function></entry>
<entry><para>This holds the data being processed by the rtcm functions.</para></entry>
</row>
<row>
diff --git a/doc/explan_gpsd.c.xml b/doc/explan_gpsd.c.xml
index dca184e8..28e13590 100644
--- a/doc/explan_gpsd.c.xml
+++ b/doc/explan_gpsd.c.xml
@@ -5,6 +5,8 @@
<colspec colname='c2'></colspec>
<spanspec spanname='s1' namest='c1' nameend='c2'></spanspec>
+<!-- Not documented: json_devicelist_dump(), rstrip() -->
+
<thead>
<row>
<entry>Functions:-</entry><entry>This is the main body of the daemon.</entry>
@@ -13,46 +15,124 @@
<tfoot>
<row>
- <entry spanname='s1' align='left'>Notes based on <function>$Id: gpsd.c 4418 2007-09-12 02:47:38Z ckuethe $</function></entry>
+ <entry spanname='s1' align='left'>Notes based on code as of Mon Apr 5 21:38:06 2010 -0400.</entry>
</row>
</tfoot>
<tbody>
<row>
<entry><function>static void onsig(int sig)</function></entry>
- <entry><para>This ia a simple catchall routine to trap wanted signal. Simply store the signal number in a variable to advise the main loop which signal to handle.</para></entry>
+ <entry><para>This is a simple catchall routine to trap wanted
+ signal. Simply store the signal number in a variable to advise the
+ main loop which signal to handle.</para></entry>
</row>
<row>
<entry><function>static int daemonize(void)</function></entry>
- <entry><para>Try to <function>fork()</function> a child process. The parent will get a return value of either -1 (on a failure to <function>fork()</function>) or non-zero (the child's PID). The parent routine will use this information to either return -1 or exit with an exit code of 0 (i.e. the parent terminates, leaving the child running).</para><para>The child instance gets a return value of 0 (on an unsuccessful <function>fork()</function> there is no child), so this value is used as the trigger to do the following useful stuff.</para><para>First, the child tries to create a new session, returning -1 if unable to do so. If succesful, it will have inherited the exiting parent's session.</para><para>Next switch to the root directory and try to open <quote>/dev/null</quote>. If that succeeds, force stdin, stdout and stderr to duplicate the fd of <quote>/dev/null</quote>. If the fd being used for the operation is >2, release it.</para><para>Finally, set the flag which indicates the process is in the background and return a value of 0.</para></entry>
+ <entry><para>Try to <function>fork()</function> a child process. The
+ parent will get a return value of either -1 (on a failure to
+ <function>fork()</function>) or non-zero (the child's PID). The
+ parent routine will use this information to either return -1 or exit
+ with an exit code of 0 (i.e. the parent terminates, leaving the
+ child running).</para><para>The child instance gets a return value
+ of 0 (on an unsuccessful <function>fork()</function> there is no
+ child), so this value is used as the trigger to do the following
+ useful stuff.</para><para>First, the child tries to create a new
+ session, returning -1 if unable to do so. If succesful, it will have
+ inherited the exiting parent's session.</para><para>Next switch to
+ the root directory and try to open <quote>/dev/null</quote>. If that
+ succeeds, force stdin, stdout and stderr to duplicate the fd of
+ <quote>/dev/null</quote>. If the fd being used for the operation is
+ >2, release it.</para><para>Finally, set the flag which indicates
+ the process is in the background and return a value of
+ 0.</para></entry>
</row>
<row>
<entry><function>void gpsd_report(int errlevel, const char *fmt, ... )</function></entry>
- <entry><para>This code is used for error reporting, but is dependant on SQUELCH_DISABLE so that embedded systems (for example) are not burdened with unneccessary noise. The first thing to check is if the error level offered is high enough to be of interest (controlled by the debug level we are running at).</para><para>If we are interested, the first step is to protect the code with a mutex if we are using the 1PPS input.</para><para>Now we build a message buffer which has a fixed header (<quote>gpsd: </quote>) and the incoming data. The output buffer is prepared (load the start with a NULL) and then the input buffer is scanned, byte-by-byte, up to its terminating NULL. The scanned data is transferred on the fly to the output buffer subject to the following tests:-</para><para>If the character is printable, it passes through unchanged.</para><para>If it is a space and either of the next two bytes is NULL it will also pass through unchanged.</para><para>In any other case, it is copied across as a hexadecimal string like <quote>x09</quote>.</para><para>The completed output buffer is then either sent to the system logger if we are in background mode (daemon) or to the stderr file if we are in foreground mode.</para></entry>
+ <entry><para>This code is used for error reporting, but is dependant
+ on SQUELCH_DISABLE so that embedded systems (for example) are not
+ burdened with unneccessary noise. The first thing to check is if the
+ error level offered is high enough to be of interest (controlled by
+ the debug level we are running at).</para><para>If we are
+ interested, the first step is to protect the code with a mutex if we
+ are using the 1PPS input.</para><para>Now we build a message buffer
+ which has a fixed header (<quote>gpsd: </quote>) and the incoming
+ data. The output buffer is prepared (load the start with a NULL) and
+ then the input buffer is scanned, byte-by-byte, up to its
+ terminating NULL. The scanned data is transferred on the fly to the
+ output buffer subject to the following tests:-</para><para>If the
+ character is printable, it passes through unchanged.</para><para>If
+ it is a space and either of the next two bytes is NULL it will also
+ pass through unchanged.</para><para>In any other case, it is copied
+ across as a hexadecimal string like
+ <quote>x09</quote>.</para><para>The completed output buffer is then
+ either sent to the system logger if we are in background mode
+ (daemon) or to the stderr file if we are in foreground
+ mode.</para></entry>
</row>
<row>
<entry><function>static void usage(void)</function></entry>
- <entry><para>Simply print a big list of the invocation parameters to the default <application>gpsd</application> port (2947, allocated by IANA).</para></entry>
+ <entry><para>Simply print a big list of the invocation parameters to
+ the default <application>gpsd</application> port (2947, allocated by
+ IANA).</para></entry>
</row>
<row>
- <entry><function>static int passivesock(char *service, char *protocol, int qlen)</function></entry>
- <entry><para>Initialise an Internet socket address structure and preload the family and address fields to accept Internet Protocol and any address.</para><para>Test to see if the incoming service and protocol exist in <function>/etc/services</function>. If they do, store the port number in the structure (massaging byte order as needed); if they don't, exit with a -1.</para><para>Test to see if the protocol is listed in <function>/etc/services</function>, exiting with -1 if it is not.</para><para>Test if the protocol is udp or not, setting the type accordingly.</para><para>Try to open a socket with the accumulated settings, exiting with -1 if it fails.</para><para>Try to set the socket options correctly, again exiting with -1 if it fails.</para><para>Try to bind to the open socket; if it fails exit with -1 as earlier, but give a special warning if the error indicates that <application>gpsd</application> may already be active on the socket.</para><para>If we are using a stream type socket and we are unable to listen to the port we exit with -1.</para><para>The last possibilty is a successful set of operations which is signalled by returning the socket fd number.</para></entry>
+ <entry><function>static int passivesock_af(char *service, char *tcp_or_udp, int qlen)</function></entry>
+ <entry><para>Initialise an Internet socket address structure and
+ preload the family and address fields to accept Internet Protocol
+ and any address.</para><para>Test to see if the incoming service and
+ protocol exist in <function>/etc/services</function>. If they do,
+ store the port number in the structure (massaging byte order as
+ needed); if they don't, exit with a -1.</para><para>Test to see if
+ the protocol is listed in <function>/etc/services</function>,
+ exiting with -1 if it is not.</para><para>Test if the protocol is
+ udp or not, setting the type accordingly.</para><para>Try to open a
+ socket with the accumulated settings, exiting with -1 if it
+ fails.</para><para>Try to set the socket options correctly, again
+ exiting with -1 if it fails.</para><para>Try to bind to the open
+ socket; if it fails exit with -1 as earlier, but give a special
+ warning if the error indicates that <application>gpsd</application>
+ may already be active on the socket.</para><para>If we are using a
+ stream type socket and we are unable to listen to the port we exit
+ with -1.</para><para>The last possibilty is a successful set of
+ operations which is signalled by returning the socket fd
+ number.</para></entry>
</row>
<row>
- <entry><function>static int filesock(char *filename)</function></entry>
- <entry><para>Try and open a socket for Local (UNIX) communications in streaming mode. If the open fails, return with a -1.</para><para>If it opens, copy the incoming filename into the socket control structure, bind to the socket and try to listen on it.</para><para>Signal a failure by returning -1 and success by returning the socket fd number.</para></entry>
+ <entry><function>static int passivesocks(char *service, char *tcp_or_udp, int qlen, int socks[])</function></entry>
+ <entry><para>Open a passive socket for each supported address
+ family; presently the supported families are IPV4 and IPv6. This
+ socket will be used to listen for client command
+ connections. Sockets are left in the final array argument, and the
+ number successfully opened is returned.</para>></entry>
</row>
<row>
- <entry><function>static void adjust_max_fd(int fd, bool on)</function></entry>
- <entry><para>If the incoming boolean flag is active, check if the fd number passed is greater than the highest seen so far. If so, save it as the new highest value.</para><para>If the boolean is passive we can take some further action, depending if we are interested in limiting the maximum number of devices and client fds (set by compile time options).</para><para>If we are not limiting ourselves, then we check for the case when we are actually at the highest fd seen so far. In that case, scan through all fds available to the system and store the highest active fd number in our allocation set as the new highest value.</para></entry>
+ <entry><function>static int filesock(char *filename)</function></entry>
+ <entry><para>Try and open a socket for Local (UNIX) communications
+ in streaming mode. If the open fails, return with a
+ -1.</para><para>If it opens, copy the incoming filename into the
+ socket control structure, bind to the socket and try to listen on
+ it.</para><para>Signal a failure by returning -1 and success by
+ returning the socket fd number.</para></entry>
</row>
<row>
- <entry><function>static bool have_fix(struct subscriber_t *whoami)</function></entry>
- <entry><para>If the call is made from a client with no associated device, return a false indication.</para><para>If the status and mode don't agree about having a fix, return a false indication.</para><para>If both status and mode agree that we have a fix, return a true indication.</para><para>Finally, the fall through is that there really is no fix, so return a false indication.</para></entry>
+ <entry><function>static void adjust_max_fd(int fd, bool on)</function></entry>
+ <entry><para>If the incoming boolean flag is active, check if the fd
+ number passed is greater than the highest seen so far. If so, save
+ it as the new highest value.</para><para>If the boolean is passive
+ we can take some further action, depending if we are interested in
+ limiting the maximum number of devices and client fds (set by
+ compile time options).</para><para>If we are not limiting ourselves,
+ then we check for the case when we are actually at the highest fd
+ seen so far. In that case, scan through all fds available to the
+ system and store the highest active fd number in our allocation set
+ as the new highest value.</para></entry>
</row>
<row>
<entry><function>static struct subscriber_t* allocate_client(void)</function></entry>
- <entry><para>Scan through all the client file descriptors, looking for one which does not have a device allocated to it.</para><para>On a match, exit early, returning this fd.</para><para>If none are available, return a NULL.</para></entry>
+ <entry><para>Scan through all the client file descriptors, looking
+ for one which does not have a device allocated to it.</para><para>On
+ a match, exit early, returning this fd.</para><para>If none are
+ available, return a NULL.</para></entry>
</row>
<row>
<entry><function>static void detach_client(struct subscriber_t *sub)</function></entry>
@@ -67,48 +147,180 @@
<entry><para>For every possible subscriber, check if the subscriber is in watcher mode and is interested in the gps device indicated in the calling parameter <function>gps_device_t</function>.</para><para>If so, send the data via a call to <function>throttled_write()</function>.</para></entry>
</row>
<row>
- <entry><function>static void raw_hook(struct gps_data_t *ud, char *sentence, size_t len, int level)</function></entry>
- <entry><para>For every possible subscriber, check if the incoming level matches the subscriber's raw setting, that the subscriber has a device associated with it and that the gps device indicated in the calling parameter <function>gps_device_t</function> is the one the subscriber is interested in.</para><para>If all conditions are satisfied, send the data via <function>throttled_write()</function>.</para></entry>
-</row>
-<row>
<entry><function>static struct gps_device_t *find_device(char *device_name)</function></entry>
<entry><para>For every possible channel, check if the channel is allocated and if the device on the channel is the one passed to us.</para><para>If it is so, exit early and return the channel number.</para><para>If there is no match, return a NULL.</para></entry>
</row>
<row>
- <entry><function>static struct gps_device_t *open_device(char *device_name)</function></entry>
- <entry><para>Check if the incoming device name is a DGPS URL via a call to <function>dgnss_url()</function>.</para><para>If it is, try to open it via a call to <function>dgnss_open()</function>.</para><para>If this worked, add the fd to our list of active fds and housekeep the highest fd number via a call to <function>adjust_max_fd()</function>. Exit by returning the address of the channels array (see the comment in the code!!).</para><para>For a non-DGPS (normal) device, scan all channels looking for an unallocated one. Exit early on a successful search. If none is found, return a NULL.</para><para>If one is found, make a call to <function>gpsd_init()</function> and store address of the local <function>raw_hook()</function> code in the selected channel's <function>gpsdata.raw_hook</function>.</para><para>Try to activate the device via a call to <function>gpsd_activate()</function>.</para><para>If this fails return a NULL.</para><para>If it succeeds, add the fd to our list of active fds, housekeep the highest fd number and return the channel number allocated.</para></entry>
+ <entry><function>static void deactivate_device(struct gps_device_t *device)</function></entry>
+ <entry><para>Deactivate device, but leave it in the device pool; do
+ not frede it. This means it will be available to be watched on
+ subsequent client opens.</para></entry>
</row>
<row>
- <entry><function>static bool allocation_policy(struct gps_device_t *channel, struct subscriber_t *user, double most_recent)</function></entry>
- <entry><para>Test that the caller has an active device and that the timestamp of the proposed channel's last sentence is not older than the caller's most recent data.</para><para>If the tests fail, return <quote>false</quote>.</para><para>Check what type of device is required by the caller.</para><para>If the caller has no preference, just return <quote>true</quote>.</para><para>If the requirement is RTCM and the channel is giving RTCM data, return <quote>true</quote>.</para><para>If the user needs gps and the channel is giving good, non-RTCM, packets return <quote>true</quote>.</para><para>If there is no match, default to returning <quote>false</quote>.</para></entry>
+ <entry><function>static struct gps_device_t *open_device(char *device_name)</function></entry>
+ <entry><para>Scan all devices looking for an unallocated one. Exit
+ early on a successful search. If none is found, return a
+ NULL.</para><para>If one is found, make a call to
+ <function>gpsd_init()</function>.</para><para>Try to activate the
+ device via a call to
+ <function>gpsd_activate()</function>.</para><para>If this fails
+ return a NULL.</para><para>If it succeeds, add the fd to our list of
+ active fds, housekeep the highest fd number and return the channel
+ number allocated.</para></entry>
</row>
<row>
- <entry><function>static bool assign_channel(struct subscriber_t *user)</function></entry>
- <entry><para>Test if the user has a device assigned.</para><para>If none is assigned, scan all channels and test each one to see if it is allocated.</para><para>If it is allocated, test with <function>allocation_policy()</function> to see if we can use it.</para><para>If we can, link the channel to the user and stash the value of its last sentence.</para><para>At the end of the loop, we either have a NULL on no allocation or we have allocated once or more, retaining a suitable device which has the most recent data.</para><para>If we failed to allocate, return <quote>false</quote>.</para><para>Test if the channel has an active fd.</para><para>If it does not, make a call to <function>gpsd_activate()</function>.</para><para>If this fails, return <quote>false</quote>, if not, add the fd to our list of active fds and housekeep the highest fd.</para><para>Check if the user is in watcher mode but not tied to a specific device.</para><para>If these conditions are sastified, generate a string and send it to the caller to advise them of the assigned device's name.</para><para>Finally, if the caller is in watcher mode and did not have a device previously assigned, generate and send a string advising the caller of the time and the assigned device name/subtype from a call to <function>gpsd_id()</function>.</para></entry>
+ <entry><function>static bool add_device(char *device_name)</function></entry>
+ <entry><para>Add a device to the pool of those available. If in
+ nowait mode, open it immediately; otherwise initialize it and make
+ it available for future watches, but don't open it yet.</para></entry>
</row>
<row>
- <entry><function>static int handle_rtcm_request(struct subscriber_t* sub UNUSED, char *buf UNUSED, int buflen UNUSED)</function></entry>
- <entry><para>Does nothing except return 0 at the moment.</para></entry>
+ <entry><function>static bool awaken(struct subscriber_t *user, struct gps_device_t *device)</function></entry>
+
+ <entry><para>If the device is niot initialized, attempt to open the
+ specified device on behalf of the specified user. If you succeed
+ and the device has an active fd, you're done If it does not, make a call to
+ <function>gpsd_activate()</function>.</para><para>If this fails,
+ return <quote>false</quote>, if not, add the fd to our list of
+ active fds and housekeep the highest fd.</para><para>Check if the
+ user is in watcher mode but not tied to a specific
+ device.</para></entry>
</row>
<row>
<entry><function>static char *snarfline(char *p, char **out)</function></entry>
- <entry><para>Copy the input line into a new buffer stopping at the first non-printable or whitespace character.</para></entry>
+ <entry><para>Copy the input line into a new buffer stopping at the
+ first non-printable or whitespace character.</para></entry>
+</row>
+<row>
+ <entry><function>static bool privileged_user(struct gps_device_t *device)</function></entry>
+ <entry><para>Scan all susbcribers and count all who are connected to
+ the device. If only the one user is connected, return
+ <quote>true</quote>, otherwise return
+ <quote>false</quote>.</para></entry>
</row>
<row>
- <entry><function>static bool privileged_user(struct subscriber_t *who)</function></entry>
- <entry><para>Scan all susbcribers and count all who are connected to the caller's device. If only the one user is connected, return <quote>true</quote>, otherwise return <quote>false</quote>.</para></entry>
+ <entry><function>static void handle_request(struct subscriber_t* sub, char *buf, const char **after, char *reply, size_t replylen)</function></entry>
+ <entry><para>Perform a single GPSD JSON command. Accept the command
+ response into a reply buffer, and update the after ponterr to point
+ just after the parsed JSON object.</para></entry>
</row>
<row>
- <entry><function>static int handle_gpsd_request(struct subscriber_t* sub, char *buf, int buflen)</function></entry>
- <entry><para>Start by filling the return buffer with <quote>GPSD</quote> in readiness.</para><para>Scan through the input buffer until the end of the string is reached. Act on the first character (it is assumed to be a command character).</para><para>The commands are checked in a switch statement and either simply generate some output to the buffer or generate output and also cause the input buffer pointer to be advanced over one or more characters as needed (individual command handling will not be analysed here).</para><para>This technique allows several concatenated parameters to be extracted and handled in any order.</para><para>After some checks on the output buffer length (which generate an error return on overflow), the output buffer is passed to <function>throttled_write()</function> and its return value is used used as the return value for the function.</para></entry>
+ <entry><function>static int handle_gpsd_request(struct subscriber_t *sub, const char *buf)
+</function></entry>
+ <entry><para>Parse multiple GPSD JSON commands out of a buffer and
+ perform each. Ship all responses back to the user via
+ <function>throttled_write()</function>.</para></entry>
</row>
<row>
<entry><function>static void handle_control(int sfd, char *buf)</function></entry>
- <entry><para>This code is similar in function to <function>handle_gpsd_request()</function> in that it parses user input. It expects the commands to be one per line and despatches them according to the leading character, which is limited to one of '-', '+' or '!'.</para><para>In the first case, the body of the command is assumed to be a device to remove from the search list. If found, it is removed, any clients are advised and <quote>OK</quote> is written to the calling socket fd. If the device is not found <quote>ERROR</quote> is written to the calling socket fd.</para><para>In the second case, the body of the command is assumed to be a device to be used by the daemon. If the device is already known, or does not respond to <function>open_device()</function>, <quote>ERROR</quote> is written to the calling socket fd, otherwise <quote>OK</quote> is written.</para><para>In the third case, the command is assumed to be a device-specific control string in the form <quote>!device_name=control_string</quote>. If the string is ill-formed or the device is not found <quote>ERROR</quote> is written to the calling socket fd. If all is well, the control string is written to the device and <quote>OK</quote> is written to the calling socket fd.</para></entry>
+ <entry><para>This code is similar in function to
+ <function>handle_gpsd_request()</function> in that it parses user
+ input. It expects the commands to be one per line and despatches
+ them according to the leading character, which is limited to one of
+ '-', '+' or '!'.</para><para>In the first case, the body of the
+ command is assumed to be a device to remove from the search list. If
+ found, it is removed, any clients are advised and <quote>OK</quote>
+ is written to the calling socket fd. If the device is not found
+ <quote>ERROR</quote> is written to the calling socket
+ fd.</para><para>In the second case, the body of the command is
+ assumed to be a device to be used by the daemon. If the device is
+ already known, or does not respond to
+ <function>open_device()</function>, <quote>ERROR</quote> is written
+ to the calling socket fd, otherwise <quote>OK</quote> is
+ written.</para><para>In the third case, the command is assumed to be
+ a device-specific control string in the form
+ <quote>!device_name=control_string</quote>. If the string is
+ ill-formed or the device is not found <quote>ERROR</quote> is
+ written to the calling socket fd. If all is well, the control string
+ is written to the device and <quote>OK</quote> is written to the
+ calling socket fd.</para></entry>
</row>
<row>
<entry><function>int main(int argc, char *argv[])</function></entry>
- <entry><para>If the 1PPS function is compiled in, initialise the local mutex structure for use by the program.</para><para>A <function>while()</function> loop reads in any command line arguments which are options and handles the options. Most set an internal variable to contol action when running, either to a fixed value or to the associated option's parameter.</para><para>Carry out a series of calls to routines to set things up ready for the main task (e.g. opening a control socket if one is needed). We also take care of tasks such as daemonizing when appropriate. The last piece of preparation is to set the permissions of the default devices correctly if we are daemonizing and are presently running as root.</para><para>Switch to the compiled in user name (typically <quote>nobody</quote>) and the group used by the tty devices.</para><para>Now we clear important data for all the records in the subscriber list.</para><para>Use <function>setjmp()</function> to prepare things for when the daemon terminates.</para><para>Clear the semaphore variable which will contain the signal number if one arrives and set some important signals so they are trapped by the stub handler in <function>onsig()</function>.</para><para>Add the command and RTCM sockets (if active) to the list of active fds, housekeeping the highest fd number and pre-clear the list of control fds.</para><para>Process the remaining parameter on the command line which should be the device name and try to open the specified device.</para><para>Enter the main execution loop, a <function>while()</function> loop which terminates if a signal sets the semaphore variable. What follows will repeat over and over until an external termination happens.</para><para>First we make a working copy of the active fds and then we make a time-limited (1 second time limit) call to <function>select()</function> using the working copy of the fds. This means that when the <function>select()</function> returns, we will either have returned on timeout or because some fd became ready to read.</para><para>First we check if any new clients have come active and (if we have resources) allocate a subscriber slot to it, doing housekeeping such as adding it to the main list of active fds and removing it from the local copy of the list. If RTCM support is compiled in, the last operation is repeated for any new RTCM client. The operation is then repeated for any new control socket clients.</para><para>If we are expecting DGPS reports, make a call to <function>dgnss_poll()</function> and if there are no ready reports, clear the fd from the main and local active fd lists.</para><para>Check if any of the active control sockets has sent one or more commands.</para><para>For every one which has sent commands, make calls to <function>handle_control()</function> to process them and remove the associated fd from the main and control lists of active fds.</para><para>Poll every active gps device and send RTCM data to it (if needed), followed by reading its output (if any). If the device returns an error, disable the device. If it has gone off-line, disable the device.</para><para>If we get here, we have something to handle, so we take care of a device which we know about, but do not have a subtype for.</para><para>We send the available data to all subscribers who are connected to this device. If the data is RTCM information, pass it to all gps devices that can accept the data.</para><para>Handle any subscribers who are in watcher mode building up an approriate set of requests, depending on the available data and passing the requests to <function>handle_gpsd_request()</function>.</para><para>If we care about DBUS, send the fix to the DBUS.</para><para><emphasis>Note that this small section of code is presently disabled pending development of the DGNSS function.</emphasis> If DGNSS is avalable and we have a fix, we poll a DGNSS report via <function>dgnss_autoconnect()</function>.</para><para>Loop round all clients and process active ones. We check for input from them and if the read fails, the client is released with <function>detach_cleint()</function>. If it succeeds, any data is handled via <function>handle_rtc_request()</function> or <function>handle_gpsd_request()</function>.</para><para>If the transaction fails, the client is released with <function>detach_client()</function>.</para><para>If the client has timed out with no device assigned, it is released with <function>detach_client()</function>.</para><para>If the client has a device, but has timed out on no response (when not in raw or watcher modes) it is released with <function>detach_client()</function>.</para><para>If we are not running in <quote>nowait</quote> mode, we are supposed to go idle when there are no clients. However, this is subject to a restriction that a device is not allowed to go idle like this until we have actually discovered what it is. This means we stay active until the packet sniffer has returned the packet type.</para><para>If a device (with a known type) has no active clients, then we can actually make it idle via <function>gpsd_deactivate()</function>.</para><para>If we reach here, we are out of the endless while loop. We check if the signal was <function>SIGHUP</function> and restart the program if it was. If it is any other signal, we deallocate all channels and wrap up any devices. Finally we check for the existance of a control socket or a pid file and delete them.</para></entry>
+ <entry><para>If the 1PPS function is compiled in, initialise the
+ local mutex structure for use by the program.</para><para>A
+ <function>while()</function> loop reads in any command line
+ arguments which are options and handles the options. Most set an
+ internal variable to contol action when running, either to a fixed
+ value or to the associated option's parameter.</para><para>Carry out
+ a series of calls to routines to set things up ready for the main
+ task (e.g. opening a control socket if one is needed). We also take
+ care of tasks such as daemonizing when appropriate. The last piece
+ of preparation is to set the permissions of the default devices
+ correctly if we are daemonizing and are presently running as
+ root.</para><para>Switch to the compiled in user name (typically
+ <quote>nobody</quote>) and the group used by the tty
+ devices.</para><para>Now we clear important data for all the records
+ in the subscriber list.</para><para>Use
+ <function>setjmp()</function> to prepare things for when the daemon
+ terminates.</para><para>Clear the semaphore variable which will
+ contain the signal number if one arrives and set some important
+ signals so they are trapped by the stub handler in
+ <function>onsig()</function>.</para><para>Add the command and RTCM
+ sockets (if active) to the list of active fds, housekeeping the
+ highest fd number and pre-clear the list of control
+ fds.</para><para>Process the remaining parameter on the command line
+ which should be the device name and try to open the specified
+ device.</para><para>Enter the main execution loop, a
+ <function>while()</function> loop which terminates if a signal sets
+ the semaphore variable. What follows will repeat over and over until
+ an external termination happens.</para><para>First we make a working
+ copy of the active fds and then we make a time-limited (1 second
+ time limit) call to <function>select()</function> using the working
+ copy of the fds. This means that when the
+ <function>select()</function> returns, we will either have returned
+ on timeout or because some fd became ready to
+ read.</para><para>First we check if any new clients have come active
+ and (if we have resources) allocate a subscriber slot to it, doing
+ housekeeping such as adding it to the main list of active fds and
+ removing it from the local copy of the list. If RTCM support is
+ compiled in, the last operation is repeated for any new RTCM
+ client. The operation is then repeated for any new control socket
+ clients.</para><para>If we are expecting DGPS reports, make a call
+ to <function>netgnss_poll()</function> and if there are no ready
+ reports, clear the fd from the main and local active fd
+ lists.</para><para>Check if any of the active control sockets has
+ sent one or more commands.</para><para>For every one which has sent
+ commands, make calls to <function>handle_control()</function> to
+ process them and remove the associated fd from the main and control
+ lists of active fds.</para><para>Poll every active gps device and
+ send RTCM data to it (if needed), followed by reading its output (if
+ any). If the device returns an error, disable the device. If it has
+ gone off-line, disable the device.</para><para>If we get here, we
+ have something to handle, so we take care of a device which we know
+ about, but do not have a subtype for.</para><para>We send the
+ available data to all subscribers who are connected to this
+ device. If the data is RTCM information, pass it to all GPS devices
+ that can accept the data.</para><para>Handle any subscribers who are
+ in watcher mode building up an approriate set of requests, depending
+ on the available data and passing the requests to
+ <function>handle_gpsd_request()</function>.</para><para>If we care
+ about DBUS, send the fix to the DBUS.</para><para><emphasis>Note
+ that this small section of code is presently disabled pending
+ development of the DGNSS function.</emphasis> If DGNSS is avalable
+ and we have a fix, we poll a DGNSS report via
+ <function>dgnss_autoconnect()</function>.</para><para>Loop round all
+ clients and process active ones. We check for input from them and if
+ the read fails, the client is released with
+ <function>detach_client()</function>. If it succeeds, any data is
+ handled via <function>handle_rtc_request()</function> or
+ <function>handle_gpsd_request()</function>.</para><para>If the
+ transaction fails, the client is released with
+ <function>detach_client()</function>.</para><para>If the client has
+ timed out with no device assigned, it is released with
+ <function>detach_client()</function>.</para><para>If the client has
+ a device, but has timed out on no response (when not in raw or
+ watcher modes) it is released with
+ <function>detach_client()</function>.</para><para>If we are not
+ running in <quote>nowait</quote> mode, we are supposed to go idle
+ after a timeout when there are no clients.</para><para>If a device
+ (with a known type) has no active clients, then we can actually make
+ it idle via <function>gpsd_deactivate()</function>.</para><para>If
+ we reach here, we are out of the endless while loop. We check if the
+ signal was <function>SIGHUP</function> and restart the program if it
+ was. If it is any other signal, we deallocate all channels and wrap
+ up any devices. Finally we check for the existance of a control
+ socket or a pid file and delete them.</para></entry>
</row>
</tbody>
diff --git a/doc/explan_gpsd.h.xml b/doc/explan_gpsd.h.xml
index 55b368f4..82b1927c 100644
--- a/doc/explan_gpsd.h.xml
+++ b/doc/explan_gpsd.h.xml
@@ -13,7 +13,7 @@
<tfoot>
<row>
- <entry spanname='s1' align='left'>Notes based on <function>$Id: gpsd.h-tail 4383 2007-06-03 21:11:37Z ckuethe $</function></entry>
+ <entry spanname='s1' align='left'>Notes based on code as of Mon Apr 5 21:38:06 2010 -0400</entry>
</row>
</tfoot>
diff --git a/doc/explan_gpsd_dbus.c.xml b/doc/explan_gpsd_dbus.c.xml
index 15784cd0..72c8381d 100644
--- a/doc/explan_gpsd_dbus.c.xml
+++ b/doc/explan_gpsd_dbus.c.xml
@@ -13,7 +13,7 @@
<tfoot>
<row>
- <entry spanname='s1' align='left'>Notes based on <function>$Id: gpsd_dbus.c 3666 2006-10-26 23:11:51Z ckuethe $</function></entry>
+ <entry spanname='s1' align='left'>Notes based on code as of Mon Apr 5 21:38:06 2010 -0400.</entry>
</row>
</tfoot>
diff --git a/doc/explan_report.c.xml b/doc/explan_gpsd_report.c.xml
index 1474bd6a..c9047dc4 100644
--- a/doc/explan_report.c.xml
+++ b/doc/explan_gpsd_report.c.xml
@@ -1,4 +1,4 @@
-<sect1 id="report.c"><title><filename>report.c</filename></title>
+<sect1 id="gpsd_report.c"><title><filename>report.c</filename></title>
<informaltable frame='all' pgwide='1'>
<tgroup cols='2'>
<colspec colname='c1'></colspec>
@@ -13,14 +13,19 @@
<tfoot>
<row>
- <entry spanname='s1' align='left'>Notes based on <function>$Id: report.c 3666 2006-10-26 23:11:51Z ckuethe $</function></entry>
+ <entry spanname='s1' align='left'>Notes based on code as of Mon Apr 5 21:38:06 2010 -0400</entry>
</row>
</tfoot>
<tbody>
<row>
<entry><function>void gpsd_report(int errlevel UNUSED, const char *fmt, ... )</function></entry>
- <entry><para>Provides the outputting of strings to stderr for anyone who needs it. Used extensively by many functions to report errors or progress. Responds according to the <function>errlevel</function> argument, which is filled by the DEBUG command line argument, so that the verbosity of output is conditional on the user's wishes at runtime.</para></entry>
+ <entry><para>Provides the outputting of strings to stderr for anyone
+ who needs it. Used extensively by many functions to report errors or
+ progress. Responds according to the <function>errlevel</function>
+ argument, which is filled by the DEBUG command line argument, so
+ that the verbosity of output is conditional on the user's wishes at
+ runtime.</para></entry>
</row>
</tbody>
diff --git a/doc/explan_gpsdclient.c.xml b/doc/explan_gpsdclient.c.xml
new file mode 100644
index 00000000..98ef22fa
--- /dev/null
+++ b/doc/explan_gpsdclient.c.xml
@@ -0,0 +1,33 @@
+<sect1 id="libgps.c"><title><filename>libgps.c</filename></title>
+<informaltable frame='all' pgwide='1'>
+<tgroup cols='2'>
+<colspec colname='c1'></colspec>
+<colspec colname='c2'></colspec>
+<spanspec spanname='s1' namest='c1' nameend='c2'></spanspec>
+
+<thead>
+<row>
+ <entry>Functions:-</entry><entry>The client interface library for the <application>gpsd</application> daemon.</entry>
+</row>
+</thead>
+
+<tfoot>
+<row>
+ <entry spanname='s1' align='left'>Notes based on code as of Mon Apr 5 21:38:06 2010 -0400</entry>
+</row>
+</tfoot>
+
+<tbody>
+<row>
+ <entry><function>char *deg_to_str( enum deg_str_type type, double f)</function></entry>
+ <entry><para>Convert double degrees to a static string and return a pointer to it.</para><para>Makes a simple check on invalid degree values (less than 0 or more than 360) and returns "nan" if found.</para><para>For valid values, it generates the appropriate string according to the string type enumeration, defaulting to DD MM SS.sss</para></entry>
+</row>
+<row>
+ <entry><function>enum unit gpsd_units(void)</function></entry>
+ <entry><para>Simple check of the environment to determine what units are required. If all else fails, use compiled in units.</para></entry>
+</row>
+</tbody>
+
+</tgroup>
+</informaltable>
+</sect1>
diff --git a/doc/explan_gpsutils.c.xml b/doc/explan_gpsutils.c.xml
index bf205a8b..174da1fd 100644
--- a/doc/explan_gpsutils.c.xml
+++ b/doc/explan_gpsutils.c.xml
@@ -7,13 +7,15 @@
<thead>
<row>
- <entry>Functions:-</entry><entry>Code shared between low-level and high-level interfaces. Most of them do exactly what they say on the tin.</entry>
+ <entry>Functions:-</entry><entry>Code shared between low-level and
+ high-level interfaces. Most of them do exactly what they say on the
+ tin.</entry>
</row>
</thead>
<tfoot>
<row>
- <entry spanname='s1' align='left'>Notes based on <function>$Id: gpsutils.c 4108 2006-12-08 11:48:31Z esr $</function></entry>
+ <entry spanname='s1' align='left'>Notes based on code as of Mon Apr 5 21:38:06 2010 -0400.</entry>
</row>
</tfoot>
@@ -27,14 +29,6 @@
<entry><para>Clears certain status flags, depending if the associated fields are invalid.</para></entry>
</row>
<row>
- <entry><function>char *gps_show_transfer(int transfer)</function></entry>
- <entry><para>Takes a mask word and uses it to check certain status flags. If the associated flag is active, the name of the status is written to the return buffer.</para></entry>
-</row>
-<row>
- <entry><function>void gps_merge_fix(struct gps_fix_t *to, gps_mask_t transfer, struct gps_fix_t *from)</function></entry>
- <entry><para>Merges (overwrites the contents of) an old fix with the contents of a new fix for those fields where the associated bit in the mask word is set and the new fix data is valid.</para></entry>
-</row>
-<row>
<entry><function>double timestamp(void)</function></entry>
<entry><para>Returns the number of seconds and microseconds since the UNIX Epoch (00:00:00 UTC, January 1, 1970); i.e. a unique value which can be used to timestamp any event.</para></entry>
</row>
diff --git a/doc/explan_isgps.c.xml b/doc/explan_isgps.c.xml
index 7849c39b..a7c5fb0f 100644
--- a/doc/explan_isgps.c.xml
+++ b/doc/explan_isgps.c.xml
@@ -7,13 +7,16 @@
<thead>
<row>
- <entry>Functions:-</entry><entry>This contains low level handling for the data transmission format of the satellite downlink and the rtcm radio data stream. ESR comments <quote>You are not expected to understand any of this.</quote>. Let's try anyhow.</entry>
+ <entry>Functions:-</entry><entry>This contains low level handling
+ for the data transmission format of the satellite downlink and the
+ RTCM2 radio data stream. ESR comments <quote>You are not expected to
+ understand any of this.</quote>. Let's try anyhow.</entry>
</row>
</thead>
<tfoot>
<row>
- <entry spanname='s1' align='left'>Notes based on <function>$Id: isgps.c 4065 2006-12-04 05:31:59Z esr $</function></entry>
+ <entry spanname='s1' align='left'>Notes based on code as of Mon Apr 5 21:38:06 2010 -0400.</entry>
</row>
</tfoot>
@@ -28,7 +31,10 @@
</row>
<row>
<entry><function>unsigned int isgps_parity(isgps30bits_t th)</function></entry>
- <entry><para>Calculate the ISGPS parity for the incoming 30 bit word. This involves lots of masking (with preset values or values searched through <function>parity_array[]</function>) and shifting</para></entry>
+ <entry><para>Calculate the ISGPS parity for the incoming 30 bit
+ word. This involves lots of masking (with preset values or values
+ searched through <function>parity_array[]</function>) and
+ shifting</para></entry>
</row>
<row>
<entry><function>void isgps_init(struct gps_packet_t *session)</function></entry>
@@ -36,7 +42,19 @@
</row>
<row>
<entry><function>enum isgpsstat_t isgps_decode(struct gps_packet_t *session, bool (*preamble_match)(isgps30bits_t *), bool (*length_check)(struct gps_packet_t *), size_t maxlen, unsigned int c)</function></entry>
- <entry><para>Check the validity of the ISGPS word tag (incoming data <function>unsigned int c</function>) and exit with an error if it is not valid.</para><para>If the session has not already locked with the datastream, loop through the data and try and sync up. If sync is achieved, exit early with an indication of sync, or fall through still marked unsynced.</para><para>If the session is already locked to the datastream, read the data into the session buffer. All the while, take care that the datastream is not corrupted. Any error will result in an early return with an appropriate error code. At the end of this section, return the status of the operations.</para><para>Finally, if the above two sections failed, exit with an error indicating that lock was not achieved.</para></entry>
+ <entry><para>Check the validity of the ISGPS word tag (incoming data
+ <function>unsigned int c</function>) and exit with an error if it is
+ not valid.</para><para>If the session has not already locked with
+ the datastream, loop through the data and try and sync up. If sync
+ is achieved, exit early with an indication of sync, or fall through
+ still marked unsynced.</para><para>If the session is already locked
+ to the datastream, read the data into the session buffer. All the
+ while, take care that the datastream is not corrupted. Any error
+ will result in an early return with an appropriate error code. At
+ the end of this section, return the status of the
+ operations.</para><para>Finally, if the above two sections failed,
+ exit with an error indicating that lock was not
+ achieved.</para></entry>
</row>
<row>
<entry><function>void isgps_output_magnavox(isgps30bits_t *ip, unsigned int len, FILE *fp)</function></entry>
diff --git a/doc/explan_libgps.c.xml b/doc/explan_libgps.c.xml
deleted file mode 100644
index 9eb39f99..00000000
--- a/doc/explan_libgps.c.xml
+++ /dev/null
@@ -1,85 +0,0 @@
-<sect1 id="libgps.c"><title><filename>libgps.c</filename></title>
-<informaltable frame='all' pgwide='1'>
-<tgroup cols='2'>
-<colspec colname='c1'></colspec>
-<colspec colname='c2'></colspec>
-<spanspec spanname='s1' namest='c1' nameend='c2'></spanspec>
-
-<thead>
-<row>
- <entry>Functions:-</entry><entry>The client interface library for the <application>gpsd</application> daemon.</entry>
-</row>
-</thead>
-
-<tfoot>
-<row>
- <entry spanname='s1' align='left'>Notes based on <function>$Id: libgps.c 4377 2007-06-02 14:52:38Z esr $</function></entry>
-</row>
-</tfoot>
-
-<tbody>
-<row>
- <entry><function>char *deg_to_str( enum deg_str_type type, double f)</function></entry>
- <entry><para>Convert double degrees to a static string and return a pointer to it.</para><para>Makes a simple check on invalid degree values (less than 0 or more than 360) and returns "nan" if found.</para><para>For valid values, it generates the appropriate string according to the string type enumeration, defaulting to DD MM SS.sss</para></entry>
-</row>
-<row>
- <entry><function>enum unit gpsd_units(void)</function></entry>
- <entry><para>Simple check of the environment to determine what units are required. If all else fails, use compiled in units.</para></entry>
-</row>
-<row>
- <entry><function>struct gps_data_t *gps_open(const char *host, const char *port)</function></entry>
- <entry><para>Open a connection to a gps daemon.</para><para>Try to get a <function>gps_data_t</function> structure. If it fails, return a NULL.</para><para>Test for a specified host and/or port number, using defaults if nothing is specified in the command line invocation.</para><para>Try to connect to the now defined socket; on error, release the resources and return NULL. On success, initialise the data structure and return the pointer to it.</para></entry>
-</row>
-<row>
- <entry><function>int gps_close(struct gps_data_t *gpsdata)</function></entry>
- <entry><para>Close the fd associated with the <function>gps_data_t</function> structure and stash the result.</para><para>If there is a device id stored, NULL it and the associated path.</para><para>If the device list has any data in it, free this and mark the number of available devices as invalid.</para><para>Free the <function>gps_data_t</function> structure itself and return the stashed <function>close()</function> result.</para></entry>
-</row>
-<row>
- <entry><function>void gps_set_raw_hook(struct gps_data_t *gpsdata, void (*hook)(struct gps_data_t *, char *, size_t len, int level))</function></entry>
- <entry><para>Fill in the hook to the data for use in raw mode.</para></entry>
-</row>
-<row>
- <entry><function>static void gps_unpack(char *buf, struct gps_data_t *gpsdata)</function></entry>
- <entry><para>Keep looping through the data in <function>buf</function> finding an occurrence of <quote>GPSD</quote>.</para><para>Each time one is found, read data in, discarding the initial <quote>GPSD</quote>.</para><para>The data is parsed by scanning to either a <quote>,</quote> or a CR or a LF. This will break the response into <application>gpsd</application> tuples. These are analysed by a big switch statement and the relevant fields and flags are set in the <function>gps_data_t</function> structure.</para><para>Any empty fields (<quote>?</quote> in them) are set to a safe value such as NaN.</para><para>If either of the raw data or thread data hooks is valid, hook the new data in at level 1 (raw mode).</para></entry>
-</row>
-<row>
- <entry><function>int gps_poll(struct gps_data_t *gpsdata)</function></entry>
- <entry><para>Poll the daemon and if there is no data or an error, return -1.</para><para>If there is something to read, clear the buffer, note the time as the received data time and the online time, then unpack the data.</para><para>If profiling is active, use the received data time, the fix time and the present time to calcluate the decode time and the client receipt time.</para></entry>
-</row>
-<row>
- <entry><function>int gps_query(struct gps_data_t *gpsdata, const char *fmt, ... )</function></entry>
- <entry><para>Gather up the instructions to a <application>gpsd</application> instance for information to return and write them to the device.</para><para>If the write fails, return -1; if it succeeds, call <function>gps_poll()</function> to get any response and return its result.</para></entry>
-</row>
-<row>
- <entry><function>static void *poll_gpsd(void *args)</function></entry>
- <entry><para>Set the thread parameters the way we need them (asynchronously cancellable) and then call <function>gps_poll()</function> continuously until we get a failure.</para></entry>
-</row>
-<row>
- <entry><function>int gps_set_callback(struct gps_data_t *gpsdata, void (*callback)(struct gps_data_t *sentence, char *buf, size_t len, int level), pthread_t *handler)</function></entry>
- <entry><para>Set <application>gpsd</application> into watcher mode, so it will be generating data.</para><para>If the thread hook is already active, set it to hook to our data and return a 0, otherwise set it to hook to our data and make a call to <function>pthread_create()</function> and return its value (0 if it succeeded).</para></entry>
-</row>
-<row>
- <entry><function>int gps_del_callback(struct gps_data_t *gpsdata, pthread_t *handler)</function></entry>
- <entry><para>Cancel the thread and stash the return value.</para><para>Set the hook to NULL now it is not needed.</para><para>If the stashed result was good, switch <application>gpsd</application> out of watcher mode.</para><para>In all cases, return the stashed result.</para></entry>
-</row>
-<row>
- <entry></entry>
- <entry><para>The following three functions are guarded by an <function>#ifdef</function> so they only compile if it is required to be able to test the library and set up a command line exerciser interface.</para></entry>
-</row>
-<row>
- <entry><function>static void data_dump(struct gps_data_t *collect, time_t now)</function></entry>
- <entry><para>A data dumper used when debugging. It outputs data according to the command line input data.</para></entry>
-</row>
-<row>
- <entry><function>static void dumpline(struct gps_data_t *ud UNUSED, char *buf, size_t ulen UNUSED, int level UNUSED)</function></entry>
- <entry><para>A simple call to UNIX <function>puts()</function>.</para></entry>
-</row>
-<row>
- <entry><function>int main(int argc, char *argv[])</function></entry>
- <entry><para>A simple command line parser and endless loop to exercise the daemon when debugging.</para></entry>
-</row>
-</tbody>
-
-</tgroup>
-</informaltable>
-</sect1>
diff --git a/doc/explan_libgps_core.c.xml b/doc/explan_libgps_core.c.xml
new file mode 100644
index 00000000..d6e4b0b8
--- /dev/null
+++ b/doc/explan_libgps_core.c.xml
@@ -0,0 +1,111 @@
+<sect1 id="gpsdclient.c"><title><filename>libgps_core.c</filename></title>
+<informaltable frame='all' pgwide='1'>
+<tgroup cols='2'>
+<colspec colname='c1'></colspec>
+<colspec colname='c2'></colspec>
+<spanspec spanname='s1' namest='c1' nameend='c2'></spanspec>
+
+<thead>
+<row>
+ <entry>Functions:-</entry><entry>The client interface library for the <application>gpsd</application> daemon.</entry>
+</row>
+</thead>
+
+<tfoot>
+<row>
+ <entry spanname='s1' align='left'>Notes based on code of Mon Apr 5 21:38:06 2010 -0400</entry>
+</row>
+</tfoot>
+
+<tbody>
+<row>
+ <entry><function>struct gps_data_t *gps_open(const char *host, const char *port)</function></entry>
+ <entry><para>Open a connection to a gps daemon.</para><para>Try to
+ get a <function>gps_data_t</function> structure. If it fails, return
+ a NULL.</para><para>Test for a specified host and/or port number,
+ using defaults if nothing is specified in the command line
+ invocation.</para><para>Try to connect to the now defined socket; on
+ error, release the resources and return NULL. On success, initialise
+ an internal <structname>struct gps_data_t</structname> and return
+ the pointer to it.</para></entry>
+</row>
+<row>
+ <entry><function>struct gps_data_t *gps_open_r(const char *host, const char *port, struct gps_data_t *gpsdata)</function></entry>
+ <entry><para>Variant of <function>gps_open()</function> for when
+ re-entrancy is required. Initializes storage passed by the
+ caller.</para></entry>
+</row>
+<row>
+ <entry><function>int gps_close(struct gps_data_t *gpsdata)</function></entry>
+ <entry><para>Close the fd associated with the
+ <function>gps_data_t</function> structure and stash the
+ result.</para><para>If there is a device id stored, NULL it and the
+ associated path.</para><para>If the device list has any data in it,
+ free this and mark the number of available devices as
+ invalid.</para><para>Free the <function>gps_data_t</function>
+ structure itself and return the stashed <function>close()</function>
+ result.</para></entry>
+</row>
+<row>
+ <entry><function>void gps_set_raw_hook(struct gps_data_t *gpsdata, void (*hook)(struct gps_data_t *, char *, size_t len, int level))</function></entry>
+ <entry><para>Fill in the hook to the data for use in raw mode.</para></entry>
+</row>
+<row>
+ <entry><function>static void gps_unpack(char *buf, struct gps_data_t *gpsdata)</function></entry>
+ <entry><para>Keep looping through the data in
+ <function>buf</function> for JSON objects. Each time one is found,
+ analyze it and umpack it into the struct pointed at by gpsdata,
+ setting the gpasdata->set mask appropriately to indicate which data
+ is valid</para><para>This function is intended for GPSD internal use
+ only and should not be considered a stable part oof the
+ API.</para></entry>
+</row>
+<row>
+ <entry><function>int gps_poll(struct gps_data_t *gpsdata)</function></entry>
+ <entry><para>Poll the daemon and if there is no data or an error,
+ return -1.</para><para>If there is something to read, clear the
+ buffer, note the time as the received data time and the online time,
+ then unpack the data.</para><para>If profiling is active, use the
+ received data time, the fix time and the present time to calcluate
+ the decode time and the client receipt time.</para></entry>
+</row>
+<row>
+ <entry><function>int gps_send(struct gps_data_t *gpsdata, const char *fmt, ... )</function></entry>
+ <entry><para>Gather up the instructions to a
+ <application>gpsd</application> instance for information to return
+ and write them to the device.</para><para>If the write fails, return
+ -1. This entry point is deprecated in favor of
+ <function>gps_stream()</function></para></entry>
+</row>
+<row>
+ <entry><function>bool gps_waiting(struct gps_data_t *gpsdata)</function></entry>
+ <entry><para>Returnn a boolean indicating whether input data is waiting on
+ the daemon socket. Does not block.</para></entry>
+</row>
+<row>
+ <entry><function>int gps_stream(struct gps_data_t *gpsdata, unsigned int, void *d)</function></entry>
+ <entry><para>Set watch and policy flags. This evaluates the flag mask passed
+ as the second argument, composes a corresponding command in the GPSD
+ write protocol, and ships it to the daemon. </para></entry>
+</row>
+<row>
+ <entry></entry>
+ <entry><para>The following three functions are guarded by an <function>#ifdef</function> so they only compile if it is required to be able to test the library and set up a command line exerciser interface.</para></entry>
+</row>
+<row>
+ <entry><function>static void data_dump(struct gps_data_t *collect, time_t now)</function></entry>
+ <entry><para>A data dumper used when debugging. It outputs data according to the command line input data.</para></entry>
+</row>
+<row>
+ <entry><function>static void dumpline(struct gps_data_t *ud UNUSED, char *buf, size_t ulen UNUSED, int level UNUSED)</function></entry>
+ <entry><para>A simple call to UNIX <function>puts()</function>.</para></entry>
+</row>
+<row>
+ <entry><function>int main(int argc, char *argv[])</function></entry>
+ <entry><para>A simple command line parser and endless loop to exercise the daemon when debugging.</para></entry>
+</row>
+</tbody>
+
+</tgroup>
+</informaltable>
+</sect1>
diff --git a/doc/explan_libgpsd_core.c.xml b/doc/explan_libgpsd_core.c.xml
index 9c327245..eb73a48b 100644
--- a/doc/explan_libgpsd_core.c.xml
+++ b/doc/explan_libgpsd_core.c.xml
@@ -5,6 +5,8 @@
<colspec colname='c2'></colspec>
<spanspec spanname='s1' namest='c1' nameend='c2'></spanspec>
+<!-- Not documented: gpsd_ppsmonitor() -->
+
<thead>
<row>
<entry>Functions:-</entry><entry>Direct access to GPSes on serial or USB devices.</entry>
@@ -13,74 +15,109 @@
<tfoot>
<row>
- <entry spanname='s1' align='left'>Notes based on <function>$Id: libgpsd_core.c 4284 2007-01-27 07:27:42Z ckuethe $</function></entry>
+ <entry spanname='s1' align='left'>Notes based on code as of Mon Apr 5 21:38:06 2010 -0400.</entry>
</row>
</tfoot>
<tbody>
<row>
<entry><function>int gpsd_switch_driver(struct gps_device_t *session, char* typename)</function></entry>
- <entry><para>Test if the function is called with the same name as the active driver.</para><para>If it is, test if the driver has a configurator function and is able to be reconfigured. A good result here will call the configurator and return a 0.</para><para>For an entry with a different driver name, scan all available drivers to see if the wanted one is there. An unmatched name exits, returning 0.</para><para>If we got a match, get the baudrate for the device with <function>gpsd_assert_sync()</function>, probe for the subtype if we have one.</para><para>If the device has a configurator and is reconfigurable, trigger the configurator.</para><para>Return a 1 to indicate a device switch.</para></entry>
+ <entry><para>Test if the function is called with the same name as
+ the active driver.</para><para>If it is, test if the driver has a
+ configurator function and is able to be reconfigured. A good result
+ here will call the driver event hook with type 'driver_switch', and
+ return a 0.</para><para>For an entry with a different driver name,
+ scan all available drivers to see if the wanted one is there. An
+ unmatched name exits, returning 0.</para><para>If we got a match,
+ get the baudrate for the device with
+ <function>gpsd_assert_sync()</function>, probe for the subtype if we
+ have one.</para><para>If the device has a configurator and is
+ reconfigurable, trigger the configurator.</para><para>Return a 1 to
+ indicate a device switch.</para></entry>
</row>
<row>
<entry><function>void gpsd_init(struct gps_device_t *session, struct gps_context_t *context, char *device)</function></entry>
- <entry><para>Copy the device name to the session data structure, initialise important data fields and call <function>gpsd_tty_init()</function>, <function>gpsd_zero_satellites()</function> and <function>packet_reset()</function>.</para></entry>
+ <entry><para>Copy the device name to the session data structure,
+ initialise important data fields and call
+ <function>gpsd_tty_init()</function>,
+ <function>gpsd_zero_satellites()</function> and
+ <function>packet_reset()</function>.</para></entry>
</row>
<row>
<entry><function>void gpsd_deactivate(struct gps_device_t *session)</function></entry>
- <entry><para>All actions below, except the last one are conditional on the <function>ntpd</function> interface being compiled in.</para><para>Release the <function>ntpd</function> resources, including the 1PPS resourecs if they are active.</para><para>If the device has a revert function, trigger it.</para><para>If it has an NMEA mode switcher, invoke it.</para><para>If it has a wrapup routine, invoke it.</para><para>Finally, close the device.</para></entry>
+ <entry><para>All actions below, except the last one are conditional
+ on the <function>ntpd</function> interface being compiled
+ in.</para><para>Release the <function>ntpd</function> resources,
+ including the 1PPS resources if they are active.</para><para>If the
+ device has a revert function, trigger it.</para><para>If it has an
+ NMEA mode switcher, invoke it.</para><para>If it has a wrapup
+ routine, invoke it.</para><para>Finally, close the
+ device.</para></entry>
</row>
<row>
<entry><function>static void *gpsd_ppsmonitor(void *arg)</function></entry>
- <entry><para>An <function>ioctl()</function> call is made which returns either 0 if the status of the port changed, or an error.</para><para>If we got a change, we read the modem control bits and extract the 1PPS information.</para><para>We check the returned value and see if it has changed recently. A counter of 10 unchanged events will disable further testing.</para><para>If we are still hanging in there, we now see if we already have had more than 4 good fixes, otherwise we can't trust the 1PPS.</para><para>We then finally test the pulse duration. If it is either a genuine 1PPS or a 2Hz squarewave, we call <function>ntpshm_pps()</function>.</para><para>Short or long PPS pulses are dropped with an error report.</para></entry>
+ <entry><para>An <function>ioctl()</function> call is made which
+ returns either 0 if the status of the port changed, or an
+ error.</para><para>If we got a change, we read the modem control
+ bits and extract the 1PPS information.</para><para>We check the
+ returned value and see if it has changed recently. A counter of 10
+ unchanged events will disable further testing.</para><para>If we are
+ still hanging in there, we now see if we already have had more than
+ 4 good fixes, otherwise we can't trust the 1PPS.</para><para>We then
+ finally test the pulse duration. If it is either a genuine 1PPS or a
+ 2Hz squarewave, we call
+ <function>ntpshm_pps()</function>.</para><para>Short or long PPS
+ pulses are dropped with an error report.</para></entry>
</row>
<row>
<entry><function>int gpsd_activate(struct gps_device_t *session, bool reconfigurable)</function></entry>
- <entry><para>Try and open the device, returning -1 if we fail.</para><para>Probe all possible drivers to see if one recognises the device.</para><para>Set some fundamental data to a clean value.</para><para>Handle the initialisation of NTP and 1PPS functions if needed.</para><para>If we did succeed in probing some device type, try and get the subtype.</para><para>If we need to do so, we now configure the device.</para><para>Finally, signal success by returning the file descriptor given by the device open call.</para></entry>
-</row>
-<row>
- <entry><function>char *gpsd_id(struct gps_device_t *session)</function></entry>
- <entry><para>If the device type is known, return it along with, where appropriate, the subtype. If the data is not available, return <quote>unknown</quote>.</para></entry>
-</row>
-<row>
- <entry><function>static double degtodm(double a)</function></entry>
- <entry><para>Converts a fractional degree value (like 125.3567) into an NMEA field as dddmm.xxx (like 12521.402).</para></entry>
-</row>
-<row>
- <entry><function>void gpsd_position_fix_dump(struct gps_device_t *session, /char bufp[], size_t len)</function></entry>
- <entry><para>If possible, create a $GPGGA message (full time, position and fix data) from the fix data, taking care about the validity of subsidiary fields like HDOP and altitude.</para></entry>
-</row>
-<row>
- <entry><function>static void gpsd_transit_fix_dump(struct gps_device_t *session, char bufp[], size_t len)</function></entry>
- <entry><para>Create a $GPRMC message (minimum navigation data) from the fix data.</para></entry>
-</row>
-<row>
- <entry><function>static void gpsd_binary_fix_dump(struct gps_device_t *session, char bufp[], size_t len)</function></entry>
- <entry><para>Make a call to <function>gpsd_position_fix_dump()</function> and <function>gpsd_transit_fix_dump()</function>.</para></entry>
-</row>
-<row>
- <entry><function>static void gpsd_binary_satellite_dump(struct gps_device_t *session, char bufp[], size_t len)</function></entry>
- <entry><para>Create one or more $GPGSV messages from the status data of all satellites we know about.</para></entry>
-</row>
-<row>
- <entry><function>static void gpsd_binary_quality_dump(struct gps_device_t *session, char bufp[], size_t len)</function></entry>
- <entry><para>Create a $GPGSA message taking care that if any xDOP is not valid, we substitute a <quote>0.0</quote> value.</para><para>If any of the error estimates is available, generate a $PGRME message again taking care about possibly invalid values.</para></entry>
-</row>
-<row>
- <entry><function>static void gpsd_binary_dump(struct gps_device_t *session, char bufp[], size_t len)</function></entry>
- <entry><para>Dump such binary data as we have available; a fix, a quality value and a satellite status block. Each is enabled by the approriate status bits in the session mask variable.</para></entry>
+ <entry><para>Id tge devicename matches an NTRIP or DGNSS URI, hand
+ off to special code for opening a socket to that source over the
+ network.</para><para>Try and open the device, returning -1 if we
+ fail.</para><para>Probe all possible drivers to see if one
+ recognises the device.</para><para>Set some fundamental data to a
+ clean value.</para><para>Handle the initialisation of NTP and 1PPS
+ functions if needed.</para><para>If we did succeed in probing some
+ device type, try and get the subtype.</para><para>If we need to do
+ so, we now configure the device.</para><para>Finally, signal success
+ by returning the file descriptor given by the device open
+ call.</para></entry>
</row>
<row>
<entry><function>void gpsd_error_model(struct gps_device_t *session, struct gps_fix_t *fix, struct gps_fix_t *oldfix)</function></entry>
- <entry><para>Check we have a 2D fix (or better) and if the gps didn't provide an eph value, use the HDOP to calculate one or fail to NAN.</para><para>Do the same with epv/VDOP if we have a 3D or better fix.</para><para>Do the same with epe/PDOP.</para><para>Consider speed error; check if we have two fixes with differing timestamps and use their times and eph values to calculate the speed.</para><para>If we have two valid 3D fixes, we can calculate the climb/sink rate.</para><para>Finally, just before exiting, save this fix as the old fix for the next comparison round.</para></entry>
+ <entry><para>Check we have a 2D fix (or better) and if the gps
+ didn't provide an eph value, use the HDOP to calculate one or fail
+ to NAN.</para><para>Do the same with epv/VDOP if we have a 3D or
+ better fix.</para><para>Do the same with
+ epe/PDOP.</para><para>Consider speed error; check if we have two
+ fixes with differing timestamps and use their times and eph values
+ to calculate the speed.</para><para>If we have two valid 3D fixes,
+ we can calculate the climb/sink rate.</para><para>Finally, just
+ before exiting, save this fix as the old fix for the next comparison
+ round.</para></entry>
</row>
<row>
<entry><function>gps_mask_t gpsd_poll(struct gps_device_t *session)</function></entry>
- <entry><para>Make a call to <function>gps_clear_fix()</function> to prepare the data structure.</para><para>Check if we know the device type. If we do, stash the count of of characters we are able to get from it.</para><para>If the read has given a full packet, we can call the subtype probing method, if the device supports it.</para><para>If we don't know the device type, try and figure out what it is, exiting if we can't.</para><para>Make some checks if the device is offline or the packet is incomplete, using the stashed count of characters and the full packet indicator.</para><para>If a full packet is available, we try to get the fix data and update the main data stucture. We also compute the DOPs so we can fill them in if they are not included in the gps device output.</para><para>Finally, send the data to any clients who need raw mode data.</para></entry>
+ <entry><para>Make a call to <function>gps_clear_fix()</function> to
+ prepare the newdata structure to receive data from an incoming
+ packet.</para><para>Check if we know the device type. If we do,
+ stash the count of of characters we are able to get from
+ it.</para><para>If the read has given a full packet, we can call the
+ subtype probing method, if the device supports it.</para><para>If we
+ don't know the device type, try and figure out what it is, exiting
+ if we can't.</para><para>Make some checks if the device is offline
+ or the packet is incomplete, using the stashed count of characters
+ and the full packet indicator.</para><para>If a full packet is
+ available, we try to get the fix data and update the main data
+ stucture. We also compute the DOPs so we can fill them in if they
+ are not included in the gps device output.</para><para>Mopst of the
+ possible driver events are called from somewhere in
+ here.</para></entry>
</row>
<row>
<entry><function>void gpsd_wrap(struct gps_device_t *session)</function></entry>
- <entry><para>Simple call to <function>gpsd_deactivate(session)</function>.</para></entry>
+ <entry><para>Simple call to
+ <function>gpsd_deactivate(session)</function>.</para></entry>
</row>
<row>
<entry><function>void gpsd_zero_satellites(struct gps_data_t *out)</function></entry>
diff --git a/doc/explan_libgpsmm.cpp.xml b/doc/explan_libgpsmm.cpp.xml
index 5ad73403..f28c9fcf 100644
--- a/doc/explan_libgpsmm.cpp.xml
+++ b/doc/explan_libgpsmm.cpp.xml
@@ -7,7 +7,7 @@
<tfoot>
<row>
- <entry spanname='s1' align='left'>Notes based on <function>$Id: libgpsmm.cpp 4219 2007-01-05 17:44:07Z ckuethe $</function></entry>
+ <entry spanname='s1' align='left'>Notes based on code as of Mon Apr 5 21:38:06 2010 -0400.</entry>
</row>
</tfoot>
diff --git a/doc/explan_libgpsmm.h.xml b/doc/explan_libgpsmm.h.xml
index f54092c2..35524ab9 100644
--- a/doc/explan_libgpsmm.h.xml
+++ b/doc/explan_libgpsmm.h.xml
@@ -7,7 +7,7 @@
<tfoot>
<row>
- <entry spanname='s1' align='left'>Notes based on <function>$Id: libgpsmm.h 3666 2006-10-26 23:11:51Z ckuethe $</function></entry>
+ <entry spanname='s1' align='left'>Notes based on code as of Mon Apr 5 21:38:06 2010 -0400.</entry>
</row>
</tfoot>
diff --git a/doc/explan_net_dgnss_dispatch.c.xml b/doc/explan_net_dgnss_dispatch.c.xml
new file mode 100644
index 00000000..632b4ff7
--- /dev/null
+++ b/doc/explan_net_dgnss_dispatch.c.xml
@@ -0,0 +1,61 @@
+<sect1 id="net_dgnss_dispatch.c"><title><filename>dgnss.c</filename></title>
+<informaltable frame='all' pgwide='1'>
+<tgroup cols='2'>
+<colspec colname='c1'></colspec>
+<colspec colname='c2'></colspec>
+<spanspec spanname='s1' namest='c1' nameend='c2'></spanspec>
+
+<thead>
+<row>
+ <entry>Functions:-</entry><entry>This file provides the interface to Differential GNSS (Global Navigation Satellite Systems) services.</entry>
+</row>
+</thead>
+
+<tfoot>
+<row>
+ <entry spanname='s1' align='left'>Notes based on code as of Mon Apr 5 21:38:06 2010 -0400.</entry>
+</row>
+</tfoot>
+
+<tbody>
+<row>
+ <entry><function>bool netgnss_url(char *name)</function></entry>
+ <entry><para>Check if a URL is valid for GNSS/DGPS service.</para></entry>
+</row>
+<row>
+ <entry><function>int netgnss_open(struct gps_context_t *context, char *dgnss_service)</function></entry>
+ <entry><para>Try to open a connection to the nominated service. If
+ the service cannot be opened, the return is -1. The supported
+ services are <function>dgpsip</function> (differential corrections
+ via IP) and <function>ntrip</function> (differential corrections in
+ http form).</para></entry>
+</row>
+<row>
+ <entry><function>int netgnss_poll(struct gps_context_t *context)</function></entry>
+ <entry><para>Try to poll the GNSS service for a correction
+ report. If no socket is active, simply return 0. If a socket is
+ active, on successful read it stores the current timestamp and the
+ report in the context buffer then returns 0. If no data is ready or
+ an error (except <errortype>EAGAIN</errortype>) occurs, drop the
+ connection and return -1.</para></entry>
+</row>
+<row>
+ <entry><function>void netgnss_report(struct gps_device_t *session)</function></entry>
+ <entry><para>Call the <function>dgpsip_report()</function> or
+ <function>ntrip_report()</function> function if either is
+ active.</para></entry>
+</row>
+<row>
+ <entry><function>void netgnss_autoconnect(struct gps_context_t *context, double lat, double lon)</function></entry>
+ <entry><para>Call the <function>autoconnect()</function> function in
+ <function>dgpsip.c</function></para></entry>
+</row>
+<row>
+ <entry><function>void rtcm_relay(struct gps_device_t *session)</function></entry>
+ <entry><para>If there is a DGNSS connection report in the context buffer, pass it to the caller. If the transaction fails, generate an error log, otherwise, update the session timestamp.</para></entry>
+</row>
+</tbody>
+
+</tgroup>
+</informaltable>
+</sect1>
diff --git a/doc/explan_dgpsip.c.xml b/doc/explan_net_dgpsip.c.xml
index 4c5a5312..a2eb1fc1 100644
--- a/doc/explan_dgpsip.c.xml
+++ b/doc/explan_net_dgpsip.c.xml
@@ -1,4 +1,4 @@
-<sect1 id="dgpsip.c"><title><filename>dgpsip.c</filename></title>
+<sect1 id="net_dgpsip.c"><title><filename>dgpsip.c</filename></title>
<informaltable frame='all' pgwide='1'>
<tgroup cols='2'>
<colspec colname='c1'></colspec>
@@ -13,26 +13,38 @@
<tfoot>
<row>
- <entry spanname='s1' align='left'>Notes based on <function>$Id: dgpsip.c 3771 2006-11-02 05:15:20Z esr $</function></entry>
+ <entry spanname='s1' align='left'>Notes based on code as of Mon Apr 5 21:38:06 2010 -0400.</entry>
</row>
</tfoot>
<tbody>
<row>
<entry><function>int dgpsip_open(struct gps_context_t *context, const char *dgpsserver)</function></entry>
- <entry><para>Tries to open a connection to a dgpsip server. Returns either -1 on failure or the socket number on success. On success, it initializes the connection, sends a <quote>HELO</quote> to the server and stores the type of dgnss service in the context data.</para></entry>
+ <entry><para>Tries to open a connection to a dgpsip server. Returns
+ either -1 on failure or the socket number on success. On success, it
+ initializes the connection, sends a <quote>HELO</quote> to the
+ server and stores the type of dgnss service in the context
+ data.</para></entry>
</row>
<row>
<entry><function>void dgpsip_report(struct gps_device_t *session)</function></entry>
- <entry><para>If we have not contacted the server and we have at received least 10 fixes, send a report to the server and set the flag, so we don't do it again.</para></entry>
+ <entry><para>If we have not contacted the server and we have at
+ received least 10 fixes, send a report to the server and set the
+ flag, so we don't do it again.</para></entry>
</row>
<row>
<entry><function>static int srvcmp(const void *s, const void *t)</function></entry>
- <entry><para>Compare the distance of two servers from our location. Return -ve, 0 or +ve depending if server <function>s</function> is nearer, the same distance away or further away than server <function>t</function>.</para></entry>
+ <entry><para>Compare the distance of two servers from our
+ location. Return -ve, 0 or +ve depending if server
+ <function>s</function> is nearer, the same distance away or further
+ away than server <function>t</function>.</para></entry>
</row>
<row>
<entry><function>void dgpsip_autoconnect(struct gps_context_t *context, double lat, double lon, const char *serverlist)</function></entry>
- <entry><para>This function takes a list of servers and tries to get a connection to the closest one relative to our location. If no servers are within 1600 km or none are in the list, the dsock value is set to -2 to lock out the function.</para></entry>
+ <entry><para>This function takes a list of servers and tries to get
+ a connection to the closest one relative to our location. If no
+ servers are within 1600 km or none are in the list, the dsock value
+ is set to -2 to lock out the function.</para></entry>
</row>
</tbody>
diff --git a/doc/explan_ntrip.c.xml b/doc/explan_net_ntrip.c.xml
index a109f47d..5b015b05 100644
--- a/doc/explan_ntrip.c.xml
+++ b/doc/explan_net_ntrip.c.xml
@@ -1,4 +1,4 @@
-<sect1 id="ntrip.c"><title><filename>ntrip.c</filename></title>
+<sect1 id="net_ntrip.c"><title><filename>ntrip.c</filename></title>
<informaltable frame='all' pgwide='1'>
<tgroup cols='2'>
<colspec colname='c1'></colspec>
@@ -13,42 +13,59 @@
<tfoot>
<row>
- <entry spanname='s1' align='left'>Notes based on <function>$Id: ntrip.c 3771 2006-11-02 05:15:20Z esr $</function></entry>
+ <entry spanname='s1' align='left'>Notes based on codec as of Tue Apr 6 10:17:55 2010 -0400.</entry>
</row>
</tfoot>
<tbody>
<row>
<entry><function>static char *ntrip_field_iterate(char *start, char *prev, const char *eol)</function></entry>
- <entry><para>Extract individual fields from the STR data block using ';' as the separator but handling string-embedded ';' characters correctly.</para></entry>
+ <entry><para>Extract individual fields from the STR data block using
+ ';' as the separator but handling string-embedded ';' characters
+ correctly.</para></entry>
</row>
<row>
<entry><function>static void ntrip_str_parse(char *str, size_t len, struct ntrip_stream_t *hold)</function></entry>
- <entry><para>Break an STR data block down using <function>ntrip_field_iterate()</function> and store the relevant details in an accumulation buffer.</para></entry>
+ <entry><para>Break an STR data block down using
+ <function>ntrip_field_iterate()</function> and store the relevant
+ details in an accumulation buffer.</para></entry>
</row>
<row>
<entry><function>static int ntrip_sourcetable_parse(int fd, char *buf, ssize_t blen, const char *stream, struct ntrip_stream_t *keep)</function></entry>
- <entry><para>Parse a block of ntrip data by passing the STR data to <function>ntrip_str_parse()</function>.</para><para>Return a 0 on success or -1 on any of the many possible failures.</para></entry>
+ <entry><para>Parse a block of ntrip data by passing the STR data to
+ <function>ntrip_str_parse()</function>.</para><para>Return a 0 on
+ success or -1 on any of the many possible failures.</para></entry>
</row>
<row>
<entry><function>static int ntrip_stream_probe(const char *caster, const char *port, const char *stream, struct ntrip_stream_t *keep)</function></entry>
- <entry><para>Send a request to the broadcaster for a block of correction data.</para><para>If successful, return the result of parsing the table. On error return -1.</para></entry>
+ <entry><para>Send a request to the broadcaster for a block of
+ correction data.</para><para>If successful, return the result of
+ parsing the table. On error return -1.</para></entry>
</row>
<row>
<entry><function>static int ntrip_auth_encode(const struct ntrip_stream_t *stream, const char *auth, char buf[], size_t size)</function></entry>
- <entry><para>Check the authorisation of the stream and return 0 if there is none or it is basic. Return -1 in all other cases.</para></entry>
+ <entry><para>Check the authorisation of the stream and return 0 if
+ there is none or it is basic. Return -1 in all other
+ cases.</para></entry>
</row>
<row>
<entry><function>static int ntrip_stream_open(const char *caster, const char *port, const char *auth, struct gps_context_t *context, struct ntrip_stream_t *stream)</function></entry>
- <entry><para>Check the authorisation of the stream and if successful, try to connect.</para><para>On connection, try to read data and test for various errors.</para><para>On success, return the socket number, on error return -1.</para></entry>
+ <entry><para>Check the authorisation of the stream and if
+ successful, try to connect.</para><para>On connection, try to read
+ data and test for various errors.</para><para>On success, return the
+ socket number, on error return -1.</para></entry>
</row>
<row>
<entry><function>int ntrip_open(struct gps_context_t *context, char *caster)</function></entry>
- <entry><para>Try to establish a connection to the ntrip server. On success, return the socket number. Signal error with a return of -1.</para></entry>
+ <entry><para>Try to establish a connection to the ntrip server. On
+ success, return the socket number. Signal error with a return of
+ -1.</para></entry>
</row>
<row>
<entry><function>void ntrip_report(struct gps_device_t *session)</function></entry>
- <entry><para>If we have not contacted the server already and we have at least 10 fixes, send a report to the server and set the flag, so we don't do it again.</para></entry>
+ <entry><para>If we have not contacted the server already and we have
+ at least 10 fixes, send a report to the server and set the flag, so
+ we don't do it again.</para></entry>
</row>
</tbody>
diff --git a/doc/explan_netlib.c.xml b/doc/explan_netlib.c.xml
index 7021eeda..af77aee2 100644
--- a/doc/explan_netlib.c.xml
+++ b/doc/explan_netlib.c.xml
@@ -5,6 +5,8 @@
<colspec colname='c2'></colspec>
<spanspec spanname='s1' namest='c1' nameend='c2'></spanspec>
+<!-- Not documented: netlib_errstr() -->
+
<thead>
<row>
<entry>Functions:-</entry><entry>This provides socket connectivity.</entry>
@@ -13,18 +15,24 @@
<tfoot>
<row>
- <entry spanname='s1' align='left'>Notes based on <function>$Id: netlib.c 4376 2007-06-02 06:29:26Z esr $</function></entry>
+ <entry spanname='s1' align='left'>Notes based on thge code as of Mon Apr 5 21:38:06 2010 -0400.</entry>
</row>
</tfoot>
<tbody>
<row>
<entry><function>int netlib_connectsock(const char *host, const char *service, const char *protocol)</function></entry>
- <entry><para>This attempts to connect the to nominated service on the nominated host using the nominated protocol. On success, the return value is the socket number. On error, an appropriate system defined error code is returned.</para></entry>
+ <entry><para>This attempts to connect the to nominated service on
+ the nominated host using the nominated protocol. On success, the
+ return value is the socket number. On error, an appropriate system
+ defined error code is returned.</para></entry>
</row>
<row>
<entry><function>char *sock2ip(int fd)</function></entry>
- <entry><para>This makes a call to <function>getpeername</function> using the spplied fd. On success, the returned string is the ip address in dotted notation. On error, "&lt;unknown&gt;" is returned.</para></entry>
+ <entry><para>This makes a call to <function>getpeername</function>
+ using the spplied fd. On success, the returned string is the ip
+ address in dotted notation. On error, "&lt;unknown&gt;" is
+ returned.</para></entry>
</row>
</tbody>
diff --git a/doc/explan_nmea_parse.c.xml b/doc/explan_nmea_parse.c.xml
deleted file mode 100644
index 766ada40..00000000
--- a/doc/explan_nmea_parse.c.xml
+++ /dev/null
@@ -1,85 +0,0 @@
-<sect1 id="nmea_parse.c"><title><filename>nmea_parse.c</filename></title>
-<informaltable frame='all' pgwide='1'>
-<tgroup cols='2'>
-<colspec colname='c1'></colspec>
-<colspec colname='c2'></colspec>
-<spanspec spanname='s1' namest='c1' nameend='c2'></spanspec>
-
-<thead>
-<row>
- <entry>Functions:-</entry><entry>Parser for NMEA strings, generic and proprietary.</entry>
-</row>
-</thead>
-
-<tfoot>
-<row>
- <entry spanname='s1' align='left'>Notes based on <function>$Id: nmea_parse.c 4373 2007-06-01 22:30:43Z esr $</function></entry>
-</row>
-</tfoot>
-
-<tbody>
-<row>
- <entry><function>static void do_lat_lon(char *field[], struct gps_data_t *out)</function></entry>
- <entry><para>Reads a four element array containing the value and hemisphere of the latitude and longitude of a location as text. It converts them into signed (-ve for S and W) values and if they are not the same as the values in the <function>gps_data_t</function> structure, it is updated with the new value(s).</para></entry>
-</row>
-<row>
- <entry><function>static void merge_ddmmyy(char *ddmmyy, struct gps_device_t *session)</function></entry>
- <entry><para>If the century has not yet been stored in the nmea driver private data, take the supplied ddmmyy date and generate and store a ddmmyyyy date, using the century value compiled in from <function>timebase.h</function>.</para></entry>
-</row>
-<row>
- <entry><function>static void merge_hhmmss(char *hhmmss, struct gps_device_t *session)</function></entry>
- <entry><para>Stash the present hour value before updating it from the incoming data. If the new hour is less than the stashed value, we have passed midnight, so update the day value. Finally update the minutes, seconds and fractions of a second from the incoming data.</para></entry>
-</row>
-<row>
- <entry><function>static gps_mask_t processGPRMC(int count, char *field[], struct gps_device_t *session)</function></entry>
- <entry><para>Handle a $GPRMC sentence stored in an array of strings, one member per field.</para><para>Check if the message is stamped valid or not.</para><para>If it is invalid, set the status and fix mode to NO_FIX and save the corresponding flags locally; also save the online flag to indicate we have handled a known sentence.</para><para>If the fix is autonomous and valid, start to decode the fields.</para><para>First, test if there are enough fields available; then handle the date and time via <function>merge_ddmmyy()</function> and <function>merge_hhmmss()</function>, storing the TIME_SET flag and storing the fix time as a UNIX-epoch relative value.</para><para>If the sentence time and this fix time are different, we have started a new cycle of observation, so update the sentence time and the store the CYCLE_START_SET flag.</para><para>Whatever the number of fields, store the fix co-ordinates via <function>do_lat_lon()</function>, store the speed and the track and save the corresponding flags.</para><para>Return the local aggregated flags to allow the main copy in the session data to be updated.</para></entry>
-</row>
-<row>
- <entry><function>static gps_mask_t processGPGLL(int count, char *field[], struct gps_device_t *session)</function></entry>
- <entry><para>Preload the local flag with the ERROR_SET flag.</para><para>Check that the sentence is usable, exiting with the preset error flag if it is not.</para><para>If it is usable, clear the local flags and start processing the fields, updating any local flag fields on the way.</para><para>If the year is already known, update the time and check for the start of cycle (see <function>processGPRMC()</function> above).</para><para>Handle the fix location and, if the number of received fixes is more than 8 and the status is differential, stash the new status as STATUS_DGPS_FIX; otherwise stash STATUS_FIX.</para><para>If the present mode is less than 2D_FIX, update it to 2D_FIX.</para><para>Write the stashed value of newstatus into the session status and return all the locally aggregated flags.</para></entry>
-</row>
-<row>
- <entry><function>static gps_mask_t processGPGGA(int c UNUSED, char *field[], struct gps_device_t *session)</function></entry>
- <entry><para>Stash the last fix time. Set the status to the value in the message and update the local flag variable.</para><para>If the status is STATUS_NO_FIX, exit immediately, returning the locally aggregated flags. If there is a fix, process it.</para><para>Handle the time as in <function>processGPGLL()</function> above. Handle the latitiude and longitude with a call to <function>do_lat_lon()</function> above and set the local flag.</para><para>Update the <function>satellites_used</function> field and stash the altitude.</para><para>If the altitude is empty, force the fix mode and status to 2D if it was 3D previously.</para><para>If it is not empty, stash the old value of altitude and replace it with the new value stashed earlier and set the local flag variable. If the mode is presently less than 3D, update it to 3D and set the local flag.</para><para>If the stashed old altitude is NaN or the stashed fix time and current fix time are equal, set the climb rate to 0 otherwise calculate it by dividing the altitude difference by the time difference and set the local flag.</para><para>If the geoid separation is available, store it, otherwise store the value from <function>wgs84_separation()</function> that depends on current location.</para><para>Finally, return all the locally aggregated flags.</para></entry>
-</row>
-<row>
- <entry><function>static gps_mask_t processGPGSA(int count, char *field[], struct gps_device_t *session)</function></entry>
- <entry><para>Start with a simple validity check on the number of fields (for i.Trek M3) and bail out with a simple indication of on-line status if it fails.</para><para>Set the fix mode from the sentence and either clear the local flag variable (if an Antaris chipset says we are in dead-reckoning mode) or set the MODE_SET flag.</para><para>Update all the DOP fields from the sentence, clear the count of used satellites, then scan all the satellite data.</para><para>If any satellite is good (prn != 0), store the prn and increment the count of used satellites.</para><para>Finally, set the local flags to indicate that DOPs are available and return all the locally aggregated flags.</para></entry>
-</row>
-<row>
- <entry><function>static gps_mask_t processGPGSV(int count, char *field[], struct gps_device_t *session)</function></entry>
- <entry><para>Check if the sentence has too few fields or the wrong number fo fields. In this case, clear the data for all satellites and return with an error indication.</para><para>Start to parse the sentence. First, note how many sentences are to be expected to complete the data transfer.</para><para>If the sentence number is invalid, clear the data for all satellites and return with an error indication.</para><para>If this is the first sentence of the sequence, clear the data for all satellites.</para><para>Loop through the sentence fields, updating the session's satellite data.</para><para>If any satellite number is higher than the number of channels, clear all satellite data and break out of the loop.</para><para>Assuming this is not a buggy chipset (e.g. Motorola Oncore GT+), update the satellite count and loop again.</para><para>If this was the last sentence of the block and the number of satellites seen is not the same as the number reported, generate an error log.</para><para>If this is not the last sentence of the block, exit early and return an error flag as a guard.</para><para>Finally, on the last sentence, carry out a sanity check and either return an error flag or a SATELLITE_SET flag.</para></entry>
-</row>
-<row>
- <entry><function>static gps_mask_t processPGRME(int c UNUSED, char *field[], struct gps_device_t *session)</function></entry>
- <entry><para>Check that the error estimate data is good. If not, set all error estimate fields to 100m and return an error flag.</para><para>If they are good, calcluate the error value and store it. Return the approriate flag values.</para></entry>
-</row>
-<row>
- <entry><function>static gps_mask_t processGPZDA(int c UNUSED, char *field[], struct gps_device_t *session)</function></entry>
- <entry><para>Set the local flag variable to indicate that the time is available.</para><para>Store the actual time by a call to <function>merge_hhmmss()</function> and fill in the other fields from the sentence data.</para><para>If the sentence is not timestamped the same as the fixtime, set the CYCLE_START_SET flag.</para><para>Update the fixtime to the sentence timestamp.</para><para>Finally, return all the locally aggregated flags.</para></entry>
-</row>
-<row>
- <entry><function>static gps_mask_t processTNTHTM(int c UNUSED, char *field[], struct gps_device_t *session)</function></entry>
- <entry><para>Set the local variable to indicate the the unit is on-line.</para><para>Fill all appropriate fields from the sentence and set the associated flags in the local flag variable.</para><para>Set the fix status and return all the locally aggregated flags.</para></entry>
-</row>
-<row>
- <entry><function>static short nmea_checksum(char *sentence, unsigned char *correct_sum)</function></entry>
- <entry><para>Calcluate and return the checksum of an NMEA sentence.</para></entry>
-</row>
-<row>
- <entry><function>gps_mask_t nmea_parse(char *sentence, struct gps_device_t *session)</function></entry>
- <entry><para>Take an NMEA sentence and check the checksum with <function>nmea_checksum()</function>, returning an empty flag mask if so (note:- this is switched off at the moment).</para><para>Test the length is acceptable, simply returning an on-line indication if it is too long to handle.</para><para>If it is within limits, make a local copy and split it on the commas into an array, one field per element.</para><para>Use the first element to match the command to the table of decodable commands.</para><para>Check if it is supported and the number of fields is reasonable, invoke the correct decoder and return the value from that call.</para><para>If it fails the check, simply return an on-line status.</para></entry>
-</row>
-<row>
- <entry><function>void nmea_add_checksum(char *sentence)</function></entry>
- <entry><para>Calcluate the checksum then append '*' + the checksum + CR/LF to the end of an NMEA sentence, skipping any existing '*'.</para></entry>
-</row>
-<row>
- <entry><function>int nmea_send(int fd, const char *fmt, ... )</function></entry>
- <entry><para>Read the incoming data into a buffer, reserving the last 5 bytes (at least) for the terminating data.</para><para>If the buffer starts with a '$', asssume it is an NMEA sentence and call <function>nmea_add_checksum</function>. Otherwise, just add a CR+LF.</para><para>Write the buffer to the device, stashing the byte count returned. Wait until all output is sent.</para><para>Check the returned value against the number of bytes in the buffer. If they are equal, return the stashed count. If not, return -1.</para></entry>
-</row>
-</tbody>
-
-</tgroup>
-</informaltable>
-</sect1>
diff --git a/doc/explan_ntpshm.c.xml b/doc/explan_ntpshm.c.xml
index b39bbba8..ea8ede65 100644
--- a/doc/explan_ntpshm.c.xml
+++ b/doc/explan_ntpshm.c.xml
@@ -13,34 +13,56 @@
<tfoot>
<row>
- <entry spanname='s1' align='left'>Notes based on <function>$Id: ntpshm.c 4412 2007-08-21 15:48:02Z ckuethe $</function></entry>
+ <entry spanname='s1' align='left'>Notes based on code as of Tue Apr 6 10:17:55 2010 -0400.</entry>
</row>
</tfoot>
<tbody>
<row>
<entry><function>static struct shmTime *getShmTime(int unit)</function></entry>
- <entry><para>This requests a block of shared memory to communicate to the ntp daemon. It returns a pointer to the memory on success or NULL on failure.</para></entry>
+ <entry><para>This requests a block of shared memory to communicate
+ to the ntp daemon. It returns a pointer to the memory on success or
+ NULL on failure.</para></entry>
</row>
<row>
<entry><function>void ntpshm_init(struct gps_context_t *context, bool enablepps)</function></entry>
- <entry><para>Attaches all ntp shared memeory segments, flagging the avaliablilty of the NMEA and 1pps capabilities as appropriate.</para></entry>
+ <entry><para>Attaches all ntp shared memeory segments, flagging the
+ avaliablilty of the NMEA and 1pps capabilities as
+ appropriate.</para></entry>
</row>
<row>
<entry><function>int ntpshm_alloc(struct gps_context_t *context)</function></entry>
- <entry><para>This tries to allocate a free ntp shared memory segment.</para><para>If one is available, initialise it for use and flag it as in use.</para><para>Returns the segment number on success or -1 on failure.</para></entry>
+ <entry><para>This tries to allocate a free ntp shared memory
+ segment.</para><para>If one is available, initialise it for use and
+ flag it as in use.</para><para>Returns the segment number on success
+ or -1 on failure.</para></entry>
</row>
<row>
<entry><function>bool ntpshm_free(struct gps_context_t *context, int segment)</function></entry>
- <entry><para>This tries to release a previously allocated ntp shared memory segment. Indicates the outcome by returning true (success) or false.</para></entry>
+ <entry><para>This tries to release a previously allocated ntp shared
+ memory segment. Indicates the outcome by returning true (success) or
+ false.</para></entry>
</row>
<row>
<entry><function>int ntpshm_put(struct gps_device_t *session, double fixtime)</function></entry>
- <entry><para>If the shared memory index allocated to the session is valid and the <function>shmTime</function> structure of the session is valid, store the time of the fix.</para><para>Success is indicated by a return value of 1 and errors are indicated by a return value of 0.</para></entry>
+ <entry><para>If the shared memory index allocated to the session is
+ valid and the <function>shmTime</function> structure of the session
+ is valid, store the time of the fix.</para><para>Success is
+ indicated by a return value of 1 and errors are indicated by a
+ return value of 0.</para></entry>
</row>
<row>
<entry><function>int ntpshm_pps(struct gps_device_t *session, struct timeval *tv)</function></entry>
- <entry><para>This code is only available if the 1PPS function is compiled in.</para><para>The shared memory structures are checked for validity and if not valid, a 0 is returned.</para><para>The time received is then checked to be within 100 milliseconds of the PC's internal time and if not, a -1 is returned.</para><para></para><para>The time received is then checked to be within 500 milliseconds of the second boundary and if not, the shared memory structure is advised that lock is lost and a -1 is returned.</para><para>If good, the time is stored in the shared memory and 1 is returned.</para></entry>
+ <entry><para>This code is only available if the 1PPS function is
+ compiled in.</para><para>The shared memory structures are checked
+ for validity and if not valid, a 0 is returned.</para><para>The time
+ received is then checked to be within 100 milliseconds of the PC's
+ internal time and if not, a -1 is
+ returned.</para><para></para><para>The time received is then checked
+ to be within 500 milliseconds of the second boundary and if not, the
+ shared memory structure is advised that lock is lost and a -1 is
+ returned.</para><para>If good, the time is stored in the shared
+ memory and 1 is returned.</para></entry>
</row>
</tbody>
diff --git a/doc/explan_packet.c.xml b/doc/explan_packet.c.xml
index 03d8a705..60c18693 100644
--- a/doc/explan_packet.c.xml
+++ b/doc/explan_packet.c.xml
@@ -13,42 +13,76 @@
<tfoot>
<row>
- <entry spanname='s1' align='left'>Notes based on <function>$Id: packet.c 4377 2007-06-02 14:52:38Z esr $</function></entry>
+ <entry spanname='s1' align='left'>Notes based on code as of Tue Apr 6 10:17:55 2010 -0400.</entry>
</row>
</tfoot>
<tbody>
<row>
<entry><function>static void nextstate(struct gps_packet_t *lexer, unsigned char c)</function></entry>
- <entry><para>This is the main parser loop. It scans the character against the definitions of all the packet structures known to <application>gpsd</application> and, if possible, sets a new packet state.</para><para>If the state is <quote>xxx_RECOGNIZED</quote>, the packet_parse routine will despatch the packet to the appropriate driver.</para></entry>
+ <entry><para>This is the main packet-sniffer loop. It scans the character
+ against the definitions of all the packet structures known to
+ <application>gpsd</application> and, if possible, sets a new packet
+ state.</para><para>If the state is <quote>xxx_RECOGNIZED</quote>,
+ the packet_parse routine will despatch the packet to the appropriate
+ driver.</para></entry>
</row>
<row>
<entry><function>static void packet_accept(struct gps_packet_t *lexer, int packet_type)</function></entry>
- <entry><para>This shifts a packet that has been recognized into the output buffer, provided it is not bigger than the buffer.</para></entry>
+ <entry><para>This shifts a packet that has been recognized into the
+ output buffer, provided it is not bigger than the
+ buffer.</para></entry>
</row>
<row>
<entry><function>static void packet_discard(struct gps_packet_t *lexer)</function></entry>
- <entry><para>This clears a handled packet out of the the input buffer.</para></entry>
+ <entry><para>This clears a handled packet out of the the input
+ buffer.</para></entry>
</row>
<row>
<entry><function>static void character_discard(struct gps_packet_t *lexer)</function></entry>
- <entry><para>This is called if the <function>nextstate()</function> function returns <quote>GROUND_STATE</quote>.</para><para>In this case the character does not match any pattern, so to discard it, the input buffer is shifted back by one character to overwrite the <quote>bad</quote> character.</para></entry>
+ <entry><para>This is called if the <function>nextstate()</function>
+ function returns <quote>GROUND_STATE</quote>.</para><para>In this
+ case the character does not match any pattern, so to discard it, the
+ input buffer is shifted back by one character to overwrite the
+ <quote>bad</quote> character.</para></entry>
</row>
<row>
<entry><function>ssize_t packet_parse(struct gps_packet_t *lexer, size_t fix)</function></entry>
- <entry><para>Call the <function>nextstate()</function> function to process the available data and set the recognition state correctly.</para><para>When a packet is matched to a driver, call <function>packet_accept()</function> and <function>packet_discard()</function> to handle the packet. If it is not matched, call <function>packet_discard()</function> and set the state to <quote>GROUND_STATE</quote></para><para>Return the number of characters handled.</para></entry>
+ <entry><para>Call the <function>nextstate()</function> function to
+ process the available data and set the recognition state
+ correctly.</para><para>When a packet is matched to a driver, call
+ <function>packet_accept()</function> and
+ <function>packet_discard()</function> to handle the packet. If it is
+ not matched, call <function>packet_discard()</function> and set the
+ state to <quote>GROUND_STATE</quote></para><para>Return the number
+ of characters handled.</para></entry>
</row>
<row>
<entry><function>ssize_t packet_get(int fd, struct gps_packet_t *lexer)</function></entry>
- <entry><para>Reads raw data from the input port.</para><para>Returns the number of characters read (0 or more) or BAD_PACKET if there was an error in reading.</para><para>Errors <errortype>EAGAIN</errortype> and <errortype>EINTR</errortype> are not classed as failures and cause a return of 0.</para><para>In case of a good read of more than 0 characters, the return value is the output from a call to <function>packet_parse()</function>.</para></entry>
+ <entry><para>Reads raw data from the input port.</para><para>Returns
+ the number of characters read (0 or more) or BAD_PACKET if there was
+ an error in reading.</para><para>Errors
+ <errortype>EAGAIN</errortype> and <errortype>EINTR</errortype> are
+ not classed as failures and cause a return of 0.</para><para>In case
+ of a good read of more than 0 characters, the return value is the
+ output from a call to
+ <function>packet_parse()</function>.</para></entry>
</row>
<row>
<entry><function>void packet_reset(struct gps_packet_t *lexer)</function></entry>
- <entry><para>This simply resets the entire packet state machine to the ground state.</para></entry>
+ <entry><para>This simply resets the entire packet state machine to
+ the ground state.</para></entry>
+</row>
+<row>
+ <entry><function>void packet_nit(struct gps_packet_t *lexer)</function></entry>
+ <entry><para>Zeros some couinters, then resets the entire packet
+ state machine to the ground state.</para></entry>
</row>
<row>
<entry><function>void packet_pushback(struct gps_packet_t *lexer)</function></entry>
- <entry><para>This pushes back the last packet from the output buffer to the input buffer, provided doing so would not overflow the input buffer.</para></entry>
+ <entry><para>This pushes back the last packet from the output buffer
+ to the input buffer, provided doing so would not overflow the input
+ buffer.</para></entry>
</row>
</tbody>
diff --git a/doc/explan_packet_names.h.xml b/doc/explan_packet_names.h.xml
index a09bd637..65f504e2 100644
--- a/doc/explan_packet_names.h.xml
+++ b/doc/explan_packet_names.h.xml
@@ -7,13 +7,18 @@
<tfoot>
<row>
- <entry spanname='s1' align='left'>Notes based on <function>$Id: packet_names.h 4299 2007-03-11 19:51:22Z ckuethe $</function></entry>
+ <entry spanname='s1' align='left'>Notes based on code as of Tue Apr 6 10:17:55 2010 -0400.</entry>
</row>
</tfoot>
<tbody>
<row>
- <entry><para>This is a file generated by the <quote>make</quote> process from <function>packet_states.h</function>. It takes all the state names in that file and surrounds them with speech marks. These values are read into a table of packet names, <function>state_table[]</function>, in <function>packet.c</function>.</para></entry>
+ <entry><para>This is a file generated by the <quote>make</quote>
+ process from <function>packet_states.h</function>. It takes all the
+ state names in that file and surrounds them with speech marks. These
+ values are read into a table of packet names,
+ <function>state_table[]</function>, in
+ <function>packet.c</function>.</para></entry>
</row>
</tbody>
diff --git a/doc/explan_packet_states.h.xml b/doc/explan_packet_states.h.xml
index 4b401fae..1ef5c709 100644
--- a/doc/explan_packet_states.h.xml
+++ b/doc/explan_packet_states.h.xml
@@ -4,13 +4,19 @@
<tfoot>
<row>
- <entry spanname='s1' align='left'>Notes based on <function>$Id: packet_states.h 4299 2007-03-11 19:51:22Z ckuethe $</function></entry>
+ <entry spanname='s1' align='left'>Notes based on code as of .Tue Apr 6 10:17:55 2010 -0400</entry>
</row>
</tfoot>
<tbody>
<row>
- <entry><para>This is a list of every possible state generated by every driver. The inclusion of each driver's states is controlled by <function>#ifdef</function> blocks, so we only include the states for drivers selected for compilation. These form an enumeration list in <function>packet.c</function> which indexes the <function>state_table[]</function> array mentioned in <function>packet_names.h</function>.</para></entry>
+ <entry><para>This is a list of every possible state generated by
+ every driver. The inclusion of each driver's states is controlled by
+ <function>#ifdef</function> blocks, so we only include the states
+ for drivers selected for compilation. These form an enumeration list
+ in <function>packet.c</function> which indexes the
+ <function>state_table[]</function> array mentioned in
+ <function>packet_names.h</function>.</para></entry>
</row>
</tbody>
diff --git a/doc/explan_pseudonmea.c.xml b/doc/explan_pseudonmea.c.xml
new file mode 100644
index 00000000..daa7c9f0
--- /dev/null
+++ b/doc/explan_pseudonmea.c.xml
@@ -0,0 +1,55 @@
+<sect1 id="pseudonmea.c"><title><filename>libgpsd_core.c</filename></title>
+<informaltable frame='all' pgwide='1'>
+<tgroup cols='2'>
+<colspec colname='c1'></colspec>
+<colspec colname='c2'></colspec>
+<spanspec spanname='s1' namest='c1' nameend='c2'></spanspec>
+
+<!-- Not documented: nmea_tpv_dump(), nmea_sky_dump() -->
+
+<thead>
+<row>
+ <entry>Functions:-</entry><entry>Generate pseudo-NMEA corresponding to binary packet reports</entry>
+</row>
+</thead>
+
+<tfoot>
+<row>
+ <entry spanname='s1' align='left'>Notes based on code as of Mon Apr 5 21:38:06 2010 -0400.</entry>
+</row>
+</tfoot>
+
+<tbody>
+<row>
+ <entry><function>static double degtodm(double a)</function></entry>
+ <entry><para>Converts a fractional degree value (like 125.3567) into an NMEA field as dddmm.xxx (like 12521.402).</para></entry>
+</row>
+<row>
+ <entry><function>void gpsd_position_fix_dump(struct gps_device_t *session, /char bufp[], size_t len)</function></entry>
+ <entry><para>If possible, create a $GPGGA message (full time, position and fix data) from the fix data, taking care about the validity of subsidiary fields like HDOP and altitude.</para></entry>
+</row>
+<row>
+ <entry><function>static void gpsd_transit_fix_dump(struct gps_device_t *session, char bufp[], size_t len)</function></entry>
+ <entry><para>Create a $GPRMC message (minimum navigation data) from the fix data.</para></entry>
+</row>
+<row>
+ <entry><function>static void gpsd_binary_fix_dump(struct gps_device_t *session, char bufp[], size_t len)</function></entry>
+ <entry><para>Make a call to <function>gpsd_position_fix_dump()</function> and <function>gpsd_transit_fix_dump()</function>.</para></entry>
+</row>
+<row>
+ <entry><function>static void gpsd_binary_satellite_dump(struct gps_device_t *session, char bufp[], size_t len)</function></entry>
+ <entry><para>Create one or more $GPGSV messages from the status data of all satellites we know about.</para></entry>
+</row>
+<row>
+ <entry><function>static void gpsd_binary_quality_dump(struct gps_device_t *session, char bufp[], size_t len)</function></entry>
+ <entry><para>Create a $GPGSA message taking care that if any xDOP is not valid, we substitute a <quote>0.0</quote> value.</para><para>If any of the error estimates is available, generate a $PGRME message again taking care about possibly invalid values.</para></entry>
+</row>
+<row>
+ <entry><function>static void gpsd_binary_dump(struct gps_device_t *session, char bufp[], size_t len)</function></entry>
+ <entry><para>Dump such binary data as we have available; a fix, a quality value and a satellite status block. Each is enabled by the approriate status bits in the session mask variable.</para></entry>
+</row>
+</tbody>
+
+</tgroup>
+</informaltable>
+</sect1>
diff --git a/doc/explan_rtcm.c.xml b/doc/explan_rtcm.c.xml
deleted file mode 100644
index c354f7c8..00000000
--- a/doc/explan_rtcm.c.xml
+++ /dev/null
@@ -1,57 +0,0 @@
-<sect1 id="rtcm.c"><title><filename>rtcm.c</filename></title>
-<informaltable frame='all' pgwide='1'>
-<tgroup cols='2'>
-<colspec colname='c1'></colspec>
-<colspec colname='c2'></colspec>
-<spanspec spanname='s1' namest='c1' nameend='c2'></spanspec>
-
-<thead>
-<row>
- <entry>Functions:-</entry><entry>This is a decoder for the RTCM-104 serial protocol.</entry>
-</row>
-</thead>
-
-<tfoot>
-<row>
- <entry spanname='s1' align='left'>Notes based on <function>$Id: rtcm.c 4364 2007-05-31 08:43:23Z esr $</function></entry>
-</row>
-</tfoot>
-
-<tbody>
-<row>
- <entry><function>void rtcm_unpack(struct rtcm_t *tp, char *buf)</function></entry>
- <entry><para>Splits RTCM raw data into fields.</para></entry>
-</row>
-<row>
- <entry><function>bool rtcm_repack(struct rtcm_t *tp, isgps30bits_t *buf)</function></entry>
- <entry><para>Packs RTCM fields into a raw data stream.</para></entry>
-</row>
-<row>
- <entry><function>static bool preamble_match(isgps30bits_t *w)</function></entry>
- <entry><para>Tells if the preamble field in a message is valid or not.</para></entry>
-</row>
-<row>
- <entry><function>static bool length_check(struct gps_packet_t *lexer)</function></entry>
- <entry><para>Tells if the message length is valid or not.</para></entry>
-</row>
-<row>
- <entry><function>enum isgpsstat_t rtcm_decode(struct gps_packet_t *lexer, unsigned int c)</function></entry>
- <entry><para>A simple call to <function>isgps_decode()</function>.</para></entry>
-</row>
-<row>
- <entry><function>void rtcm_dump(struct rtcm_t *rtcm, char buf[], size_t buflen)</function></entry>
- <entry><para>Dump the contents of a parsed RTCM104 message.</para></entry>
-</row>
-<row>
- <entry><function>int rtcm_undump(struct rtcm_t *rtcmp, char *buf)</function></entry>
- <entry><para>Merge a line of data into an RTCM structure, return 0 if done.</para></entry>
-</row>
-<row>
- <entry><function>void rtcm_output_magnavox(isgps30bits_t *ip, FILE *fp)</function></entry>
- <entry><para>Ship an RTCM message in the format emitted by Magnavox DGPS receivers.</para></entry>
-</row>
-</tbody>
-
-</tgroup>
-</informaltable>
-</sect1>
diff --git a/doc/explan_serial.c.xml b/doc/explan_serial.c.xml
index 46e32212..a715d020 100644
--- a/doc/explan_serial.c.xml
+++ b/doc/explan_serial.c.xml
@@ -13,51 +13,90 @@
<tfoot>
<row>
- <entry spanname='s1' align='left'>Notes based on <function>$Id: serial.c 4405 2007-07-27 16:16:09Z ckuethe $</function></entry>
+ <entry spanname='s1' align='left'>Notes based on code as of Tue Apr 6 10:17:55 2010 -0400.</entry>
</row>
</tfoot>
<tbody>
<row>
<entry><function>void gpsd_tty_init(struct gps_device_t *session)</function></entry>
- <entry><para>To be called on allocating a device. Mark GPS fd closed and its baud rate unknown.</para><para>If we are supporting <function>ntpd</function> shared memory segments, ensure they are initally unused.</para></entry>
+ <entry><para>To be called on allocating a device. Mark GPS fd closed
+ and its baud rate unknown.</para><para>If we are supporting
+ <function>ntpd</function> shared memory segments, ensure they are
+ initally unused.</para></entry>
</row>
<row>
<entry><function>void cfmakeraw(struct termios *termios_p)</function></entry>
- <entry><para>Workaround for Cygwin, which is missing <function>cfmakeraw()</function>. It is pasted from man page and added in <function>serial.c</function> arbitrarily.</para></entry>
+ <entry><para>Workaround for Cygwin, which is missing
+ <function>cfmakeraw()</function>. It is pasted from man page and
+ added in <function>serial.c</function> arbitrarily.</para></entry>
</row>
<row>
<entry><function>speed_t gpsd_get_speed(struct termios* ttyctl)</function></entry>
- <entry><para>Calls <function>cfgetospeed()</function> and returns the baud rate, if known. Default otherwise is 115200.</para></entry>
+ <entry><para>Calls <function>cfgetospeed()</function> and returns
+ the baud rate, if known. Default otherwise is 115200.</para></entry>
</row>
<row>
<entry><function>bool gpsd_set_raw(struct gps_device_t *session)</function></entry>
- <entry><para>Tries to set port to raw mode and returns success or not.</para></entry>
+ <entry><para>Tries to set port to raw mode and returns success or
+ not.</para></entry>
</row>
<row>
<entry><function>void gpsd_set_speed(struct gps_device_t *session, speed_t speed, unsigned char parity, unsigned int stopbits)</function></entry>
- <entry><para>Sets the speed, parity and stopbits.</para><para>Lots of black magic fiddling goes on to ensure the port is flushed on the baud rate change and wakeup strings are fired off just in case the device needs prodding into life.</para><para>READ THE CODE AND COMMENTS!!!</para><para>Prior to exit, a call is made to <function>packet_reset()</function> to ensure the packet state machine is initialised.</para></entry>
+ <entry><para>Sets the speed, parity and stopbits.</para><para>Lots
+ of black magic fiddling goes on to ensure the port is flushed on the
+ baud rate change and wakeup strings are fired off just in case the
+ device needs prodding into life.</para><para>READ THE CODE AND
+ COMMENTS!!!</para><para>Prior to exit, a call is made to
+ <function>packet_reset()</function> to ensure the packet state
+ machine is initialised.</para></entry>
</row>
<row>
<entry><function>int gpsd_open(struct gps_device_t *session)</function></entry>
- <entry><para>Test the device and flag it as R/W if it is a character device, or R/O if it isn't.</para><para>Try to open it in non-blocking and no-control mode.</para><para>If that fails, try again, adding read-only mode. If that also fails, exit with an error.</para><para>On no error, force the saved baudrate if we have a fixed port speed (typically embedded devices). Check if we have a saved baudrate and if so, activate it.</para><para>Preset the packet type to BAD_PACKET.</para><para>Check if the device we have opened is a tty. If it is a tty, read the original terminal paramters.</para><para>Exit with an error code -1 on failure to do so.</para><para>Save the old parameters, set important control flags, then set the speed.</para><para>Finally, return the allocated fd.</para></entry>
+ <entry><para>Test the device and flag it as R/W if it is a character
+ device, or R/O if it isn't.</para><para>Try to open it in
+ non-blocking and no-control mode.</para><para>If that fails, try
+ again, adding read-only mode. If that also fails, exit with an
+ error.</para><para>On no error, force the saved baudrate if we have
+ a fixed port speed (typically embedded devices). Check if we have a
+ saved baudrate and if so, activate it.</para><para>Preset the packet
+ type to BAD_PACKET.</para><para>Check if the device we have opened
+ is a tty. If it is a tty, read the original terminal
+ paramters.</para><para>Exit with an error code -1 on failure to do
+ so.</para><para>Save the old parameters, set important control
+ flags, then set the speed.</para><para>Finally, return the allocated
+ fd.</para></entry>
</row>
<row>
<entry><function>bool gpsd_write(struct gps_device_t *session, void const *buf, size_t len)</function></entry>
- <entry><para>If the device is read-only, simply return 0.</para><para>If not, try to write <function>len</function> characters to the device. waiting until all data has been sent.</para><para>Return the number of bytes written.</para></entry>
+ <entry><para>If the device is read-only, simply return
+ 0.</para><para>If not, try to write <function>len</function>
+ characters to the device. waiting until all data has been
+ sent.</para><para>Return the number of bytes written.</para></entry>
</row>
<row>
<entry><function>bool gpsd_next_hunt_setting(struct gps_device_t *session)</function></entry>
- <entry><para>Check if we have had SNIFF_RETRIES attempts at current baudrate. If not, return <quote>true</quote>.</para><para>If we have exceeded the limit, reset the counter and see if there are any more rates to try at.</para><para>If no (fixed baudrate or all attempts exhausted), return <quote>false</quote>, otherwise, set the next speed and return <quote>true</quote>.</para></entry>
+ <entry><para>Check if we have had SNIFF_RETRIES attempts at current
+ baudrate. If not, return <quote>true</quote>.</para><para>If we have
+ exceeded the limit, reset the counter and see if there are any more
+ rates to try at.</para><para>If no (fixed baudrate or all attempts
+ exhausted), return <quote>false</quote>, otherwise, set the next
+ speed and return <quote>true</quote>.</para></entry>
</row>
<row>
<entry><function>void gpsd_assert_sync(struct gps_device_t *session)</function></entry>
- <entry><para>To be called when we want to register that we've synced with a device. We've achieved first sync with the device. Remember the baudrate so we can try it first next time this device is opened.</para></entry>
+ <entry><para>To be called when we want to register that we've synced
+ with a device. We've achieved first sync with the device. Remember
+ the baudrate so we can try it first next time this device is
+ opened.</para></entry>
</row>
<row>
<entry><function>void gpsd_close(struct gps_device_t *session)</function></entry>
- <entry><para>If there is an active fd, check if it is a tty device. If it is, force the baudrate to 0 (should terminate the connection and de-assert control lines).</para><para>
-Set the HUPCL flag in the original data, write the old data to the port, close the fd and clear that fd number from the session data.</para></entry>
+ <entry><para>If there is an active fd, check if it is a tty
+ device. If it is, force the baudrate to 0 (should terminate the
+ connection and de-assert control lines).</para><para> Set the HUPCL
+ flag in the original data, write the old data to the port, close the
+ fd and clear that fd number from the session data.</para></entry>
</row>
</tbody>
diff --git a/doc/explan_subframe.c.xml b/doc/explan_subframe.c.xml
index 085fbc07..7c4730d3 100644
--- a/doc/explan_subframe.c.xml
+++ b/doc/explan_subframe.c.xml
@@ -13,7 +13,7 @@
<tfoot>
<row>
- <entry spanname='s1' align='left'>Notes based on <function>$Id: subframe.c 3770 2006-11-02 05:07:11Z esr $</function></entry>
+ <entry spanname='s1' align='left'>Notes based on code as of .Tue Apr 6 10:17:55 2010 -0400.</entry>
</row>
</tfoot>
diff --git a/doc/explan_timebase.h.xml b/doc/explan_timebase.h.xml
index 6c1aec7a..052487b6 100644
--- a/doc/explan_timebase.h.xml
+++ b/doc/explan_timebase.h.xml
@@ -13,18 +13,20 @@
<tfoot>
<row>
- <entry spanname='s1' align='left'>Notes based on <function>$Id: timebase.h 4040 2006-12-01 03:41:42Z esr $</function></entry>
+ <entry spanname='s1' align='left'>Notes based on Tue Apr 6 10:17:55 2010 -0400</entry>
</row>
</tfoot>
<tbody>
<row>
<entry><function>LEAP_SECONDS</function></entry>
- <entry><para>Currently 14</para></entry>
+ <entry><para>Offset between GPS and UTC, in seconds.</para></entry>
</row>
<row>
<entry><function>START_SUBFRAME</function></entry>
- <entry><para>Currently 1183262400 or 1 Jun 2007 00:00:00</para></entry>
+ <entry><para>When to start doing subframe queries to get the
+ leap-second offset. Should be set to the next possible time for a
+ leap-second change according to IERS.</para></entry>
</row>
<row>
<entry><function>CENTURY_BASE</function></entry>
diff --git a/doc/explanation.xml b/doc/explanation.xml
index ac415648..48d34ed0 100644
--- a/doc/explanation.xml
+++ b/doc/explanation.xml
@@ -3,38 +3,42 @@
"-//OASIS//DTD DocBook XML V4.1.2//EN"
"docbook/docbookx.dtd" [
<!ENTITY homepage "http://gpsd.berlios.de">
-<!ENTITY bits.h SYSTEM "explan_bits.h.xml">
-<!ENTITY dgnss.c SYSTEM "explan_dgnss.c.xml">
-<!ENTITY dgpsip.c SYSTEM "explan_dgpsip.c.xml">
-<!ENTITY driver_proto.c SYSTEM "explan_driver_proto.c.xml">
-<!ENTITY drivers.c SYSTEM "explan_drivers.c.xml">
-<!ENTITY geoid.c SYSTEM "explan_geoid.c.xml">
-<!ENTITY gpsd.c SYSTEM "explan_gpsd.c.xml">
-<!ENTITY gpsd.h SYSTEM "explan_gpsd.h.xml">
-<!ENTITY gpsd_dbus.c SYSTEM "explan_gpsd_dbus.c.xml">
-<!ENTITY gps.h SYSTEM "explan_gps.h.xml">
-<!ENTITY gpsutils.c SYSTEM "explan_gpsutils.c.xml">
-<!ENTITY isgps.c SYSTEM "explan_isgps.c.xml">
-<!ENTITY libgps.c SYSTEM "explan_libgps.c.xml">
-<!ENTITY libgpsd_core.c SYSTEM "explan_libgpsd_core.c.xml">
-<!ENTITY libgpsmm.cpp SYSTEM "explan_libgpsmm.cpp.xml">
-<!ENTITY libgpsmm.h SYSTEM "explan_libgpsmm.h.xml">
-<!ENTITY netlib.c SYSTEM "explan_netlib.c.xml">
-<!ENTITY nmea_parse.c SYSTEM "explan_nmea_parse.c.xml">
-<!ENTITY ntpshm.c SYSTEM "explan_ntpshm.c.xml">
-<!ENTITY ntrip.c SYSTEM "explan_ntrip.c.xml">
-<!ENTITY packet.c SYSTEM "explan_packet.c.xml">
-<!ENTITY packet_names.h SYSTEM "explan_packet_names.h.xml">
-<!ENTITY packet_states.h SYSTEM "explan_packet_states.h.xml">
-<!ENTITY report.c SYSTEM "explan_report.c.xml">
-<!ENTITY rtcm.c SYSTEM "explan_rtcm.c.xml">
-<!ENTITY serial.c SYSTEM "explan_serial.c.xml">
-<!ENTITY subframe.c SYSTEM "explan_subframe.c.xml">
-<!ENTITY timebase.h SYSTEM "explan_timebase.h.xml">
-<!ENTITY wrapup SYSTEM "explan_wrapup.xml">
+
+<!ENTITY bits.h SYSTEM "explan_bits.h.xml">
+<!ENTITY driver_nmea.c SYSTEM "explan_driver_nmea.c.xml">
+<!ENTITY driver_proto.c SYSTEM "explan_driver_proto.c.xml">
+<!ENTITY driver_rtcm2.c SYSTEM "explan_driver_rtcm2.c.xml">
+<!ENTITY drivers.c SYSTEM "explan_drivers.c.xml">
+<!ENTITY geoid.c SYSTEM "explan_geoid.c.xml">
+<!ENTITY gps.h SYSTEM "explan_gps.h.xml">
+<!ENTITY gpsd.c SYSTEM "explan_gpsd.c.xml">
+<!ENTITY gpsd.h SYSTEM "explan_gpsd.h.xml">
+<!ENTITY gpsd_dbus.c SYSTEM "explan_gpsd_dbus.c.xml">
+<!ENTITY gpsd_report.c SYSTEM "explan_gpsd_report.c.xml">
+<!ENTITY gpsdclient.c SYSTEM "explan_gpsdclient.c.xml">
+<!ENTITY gpsutils.c SYSTEM "explan_gpsutils.c.xml">
+<!ENTITY isgps.c SYSTEM "explan_isgps.c.xml">
+<!ENTITY libgps_core.c SYSTEM "explan_libgps_core.c.xml">
+<!ENTITY libgpsd_core.c SYSTEM "explan_libgpsd_core.c.xml">
+<!ENTITY libgpsmm.cpp SYSTEM "explan_libgpsmm.cpp.xml">
+<!ENTITY libgpsmm.h SYSTEM "explan_libgpsmm.h.xml">
+<!ENTITY net_dgnss_dispatch.c SYSTEM "explan_net_dgnss_dispatch.c.xml">
+<!ENTITY net_dgpsip.c SYSTEM "explan_net_dgpsip.c.xml">
+<!ENTITY net_ntrip.c SYSTEM "explan_net_ntrip.c.xml">
+<!ENTITY netlib.c SYSTEM "explan_netlib.c.xml">
+<!ENTITY ntpshm.c SYSTEM "explan_ntpshm.c.xml">
+<!ENTITY packet.c SYSTEM "explan_packet.c.xml">
+<!ENTITY packet_names.h SYSTEM "explan_packet_names.h.xml">
+<!ENTITY packet_states.h SYSTEM "explan_packet_states.h.xml">
+<!ENTITY pseudonmea.c SYSTEM "explan_pseudonmea.c.xml">
+<!ENTITY serial.c SYSTEM "explan_serial.c.xml">
+<!ENTITY subframe.c SYSTEM "explan_subframe.c.xml">
+<!ENTITY timebase.h SYSTEM "explan_timebase.h.xml">
+
+<!ENTITY wrapup SYSTEM "explan_wrapup.xml">
]>
<article>
-<title>Notes on the structure of the code in the GPSD Driver</title>
+<title>A Tour of the GPSD Internals</title>
<articleinfo>
<author>
<firstname>Mick</firstname>
@@ -42,46 +46,69 @@
</author>
<revhistory>
<revision>
+ <revnumber>2.1</revnumber>
+ <date>6 April 2010</date>
+ <authorinitials>esr</authorinitials>
+ <revremark>Updated to match current reality, as far as it
+ goes. Some newer parts of the codebase, notably the JSON parsing
+ machinery and AIS support, aren't documented.</revremark>
+ </revision>
+ <revision>
<revnumber>2.0</revnumber>
<date>14 November 2007</date>
<authorinitials>md</authorinitials>
- <revremark>Updated to version 4420</revremark>
+ <revremark>Updated to version svn revision 4420</revremark>
</revision>
</revhistory>
<abstract>
-<para>These notes are meant as an aid to reading and understanding some of the main code files forming the <application>gpsd</application> daemon and its support libraries. They are not a line-by-line explanation but only pick out the important (or unusual) aspects of the code.</para><para>They do not address the many programs that are used for test purposes, the individual device driver files or any of the supplied applications that use <application>gpsd</application>.</para>
+<para>These notes are meant as an aid to reading and understanding
+some of the main code files forming the
+<application>gpsd</application> daemon and its support libraries. They
+are not a line-by-line explanation but only pick out the important (or
+unusual) aspects of the code.</para><para>They do not address the many
+programs that are used for test purposes, the individual device driver
+files or any of the supplied applications that use
+<application>gpsd</application>.</para>
+
+<para>This guide was written before the move to a JSON-based protocol
+and before AIS support was added. While the information on the rest of
+the code has been updated, the machinery relating to JSON and AIS
+is not yet documented here.</para>
</abstract>
</articleinfo>
&bits.h;
-&dgnss.c;
-&dgpsip.c;
+&driver_nmea.c;
&driver_proto.c;
+&driver_rtcm2.c;
&drivers.c;
&geoid.c;
+&gps.h;
&gpsd.c;
&gpsd.h;
&gpsd_dbus.c;
-&gps.h;
+&gpsd_report.c;
+&gpsdclient.c;
&gpsutils.c;
&isgps.c;
-&libgps.c;
+&libgps_core.c;
&libgpsd_core.c;
&libgpsmm.cpp;
&libgpsmm.h;
+&net_dgnss_dispatch.c;
+&net_dgpsip.c;
+&net_ntrip.c;
&netlib.c;
-&nmea_parse.c;
&ntpshm.c;
-&ntrip.c;
&packet.c;
&packet_names.h;
&packet_states.h;
-&report.c;
-&rtcm.c;
+&pseudonmea.c;
&serial.c;
&subframe.c;
&timebase.h;
+
&wrapup;
</article>