summaryrefslogtreecommitdiff
path: root/doc/explan_nmea_parse.c.xml
blob: 1d6aa6b7036d2e16c3be57eb762fca33946b6735 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
<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>

<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>

<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>

</tgroup>
</informaltable>
</sect1>