2 * Routines for NMEA 0183 protocol dissection
3 * Copyright 2024 Casper Meijn <casper@meijn.net>
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * SPDX-License-Identifier: GPL-2.0-or-later
13 #include <epan/packet.h>
14 #include <epan/expert.h>
16 static int hf_nmea0183_talker_id
;
17 static int hf_nmea0183_sentence_id
;
18 static int hf_nmea0183_unknown_field
;
19 static int hf_nmea0183_checksum
;
20 static int hf_nmea0183_checksum_calculated
;
22 static int hf_nmea0183_dpt_depth
;
23 static int hf_nmea0183_dpt_offset
;
24 static int hf_nmea0183_dpt_max_range
;
26 static int hf_nmea0183_hdt_heading
;
27 static int hf_nmea0183_hdt_unit
;
29 static int hf_nmea0183_gga_time
;
30 static int hf_nmea0183_gga_time_hour
;
31 static int hf_nmea0183_gga_time_minute
;
32 static int hf_nmea0183_gga_time_second
;
33 static int hf_nmea0183_gga_latitude
;
34 static int hf_nmea0183_gga_latitude_degree
;
35 static int hf_nmea0183_gga_latitude_minute
;
36 static int hf_nmea0183_gga_latitude_direction
;
37 static int hf_nmea0183_gga_longitude
;
38 static int hf_nmea0183_gga_longitude_degree
;
39 static int hf_nmea0183_gga_longitude_minute
;
40 static int hf_nmea0183_gga_longitude_direction
;
41 static int hf_nmea0183_gga_quality
;
42 static int hf_nmea0183_gga_number_satellites
;
43 static int hf_nmea0183_gga_horizontal_dilution
;
44 static int hf_nmea0183_gga_altitude
;
45 static int hf_nmea0183_gga_altitude_unit
;
46 static int hf_nmea0183_gga_geoidal_separation
;
47 static int hf_nmea0183_gga_geoidal_separation_unit
;
48 static int hf_nmea0183_gga_age_dgps
;
49 static int hf_nmea0183_gga_dgps_station
;
51 static int hf_nmea0183_gll_latitude
;
52 static int hf_nmea0183_gll_latitude_degree
;
53 static int hf_nmea0183_gll_latitude_minute
;
54 static int hf_nmea0183_gll_latitude_direction
;
55 static int hf_nmea0183_gll_longitude
;
56 static int hf_nmea0183_gll_longitude_degree
;
57 static int hf_nmea0183_gll_longitude_minute
;
58 static int hf_nmea0183_gll_longitude_direction
;
59 static int hf_nmea0183_gll_time
;
60 static int hf_nmea0183_gll_time_hour
;
61 static int hf_nmea0183_gll_time_minute
;
62 static int hf_nmea0183_gll_time_second
;
63 static int hf_nmea0183_gll_status
;
64 static int hf_nmea0183_gll_mode
;
66 static int hf_nmea0183_gst_time
;
67 static int hf_nmea0183_gst_time_hour
;
68 static int hf_nmea0183_gst_time_minute
;
69 static int hf_nmea0183_gst_time_second
;
70 static int hf_nmea0183_gst_rms_total_sd
;
71 static int hf_nmea0183_gst_ellipse_major_sd
;
72 static int hf_nmea0183_gst_ellipse_minor_sd
;
73 static int hf_nmea0183_gst_ellipse_orientation
;
74 static int hf_nmea0183_gst_latitude_sd
;
75 static int hf_nmea0183_gst_longitude_sd
;
76 static int hf_nmea0183_gst_altitude_sd
;
78 static int hf_nmea0183_rot_rate_of_turn
;
79 static int hf_nmea0183_rot_valid
;
81 static int hf_nmea0183_vbw_water_speed_longitudinal
;
82 static int hf_nmea0183_vbw_water_speed_transverse
;
83 static int hf_nmea0183_vbw_water_speed_valid
;
84 static int hf_nmea0183_vbw_ground_speed_longitudinal
;
85 static int hf_nmea0183_vbw_ground_speed_transverse
;
86 static int hf_nmea0183_vbw_ground_speed_valid
;
87 static int hf_nmea0183_vbw_stern_water_speed
;
88 static int hf_nmea0183_vbw_stern_water_speed_valid
;
89 static int hf_nmea0183_vbw_stern_ground_speed
;
90 static int hf_nmea0183_vbw_stern_ground_speed_valid
;
92 static int hf_nmea0183_vhw_true_heading
;
93 static int hf_nmea0183_vhw_true_heading_unit
;
94 static int hf_nmea0183_vhw_magnetic_heading
;
95 static int hf_nmea0183_vhw_magnetic_heading_unit
;
96 static int hf_nmea0183_vhw_water_speed_knot
;
97 static int hf_nmea0183_vhw_water_speed_knot_unit
;
98 static int hf_nmea0183_vhw_water_speed_kilometer
;
99 static int hf_nmea0183_vhw_water_speed_kilometer_unit
;
101 static int hf_nmea0183_vlw_cumulative_water
;
102 static int hf_nmea0183_vlw_cumulative_water_unit
;
103 static int hf_nmea0183_vlw_trip_water
;
104 static int hf_nmea0183_vlw_trip_water_unit
;
105 static int hf_nmea0183_vlw_cumulative_ground
;
106 static int hf_nmea0183_vlw_cumulative_ground_unit
;
107 static int hf_nmea0183_vlw_trip_ground
;
108 static int hf_nmea0183_vlw_trip_ground_unit
;
110 static int hf_nmea0183_vtg_true_course
;
111 static int hf_nmea0183_vtg_true_course_unit
;
112 static int hf_nmea0183_vtg_magnetic_course
;
113 static int hf_nmea0183_vtg_magnetic_course_unit
;
114 static int hf_nmea0183_vtg_ground_speed_knot
;
115 static int hf_nmea0183_vtg_ground_speed_knot_unit
;
116 static int hf_nmea0183_vtg_ground_speed_kilometer
;
117 static int hf_nmea0183_vtg_ground_speed_kilometer_unit
;
118 static int hf_nmea0183_vtg_mode
;
120 static int hf_nmea0183_zda_time
;
121 static int hf_nmea0183_zda_time_hour
;
122 static int hf_nmea0183_zda_time_minute
;
123 static int hf_nmea0183_zda_time_second
;
124 static int hf_nmea0183_zda_date_day
;
125 static int hf_nmea0183_zda_date_month
;
126 static int hf_nmea0183_zda_date_year
;
127 static int hf_nmea0183_zda_local_zone_hour
;
128 static int hf_nmea0183_zda_local_zone_minute
;
130 static int ett_nmea0183
;
131 static int ett_nmea0183_checksum
;
132 static int ett_nmea0183_sentence
;
133 static int ett_nmea0183_zda_time
;
134 static int ett_nmea0183_gga_time
;
135 static int ett_nmea0183_gga_latitude
;
136 static int ett_nmea0183_gga_longitude
;
137 static int ett_nmea0183_gll_time
;
138 static int ett_nmea0183_gll_latitude
;
139 static int ett_nmea0183_gll_longitude
;
140 static int ett_nmea0183_gst_time
;
142 static expert_field ei_nmea0183_invalid_first_character
;
143 static expert_field ei_nmea0183_missing_checksum_character
;
144 static expert_field ei_nmea0183_invalid_end_of_line
;
145 static expert_field ei_nmea0183_checksum_incorrect
;
146 static expert_field ei_nmea0183_sentence_too_long
;
147 static expert_field ei_nmea0183_field_time_too_short
;
148 static expert_field ei_nmea0183_field_latitude_too_short
;
149 static expert_field ei_nmea0183_field_longitude_too_short
;
150 static expert_field ei_nmea0183_field_missing
;
151 static expert_field ei_nmea0183_gga_altitude_unit_incorrect
;
152 static expert_field ei_nmea0183_gga_geoidal_separation_unit_incorrect
;
153 static expert_field ei_nmea0183_hdt_unit_incorrect
;
154 static expert_field ei_nmea0183_vhw_true_heading_unit_incorrect
;
155 static expert_field ei_nmea0183_vhw_magnetic_heading_unit_incorrect
;
156 static expert_field ei_nmea0183_vhw_water_speed_knot_unit_incorrect
;
157 static expert_field ei_nmea0183_vhw_water_speed_kilometer_unit_incorrect
;
158 static expert_field ei_nmea0183_vlw_cumulative_water_unit_incorrect
;
159 static expert_field ei_nmea0183_vlw_trip_water_unit_incorrect
;
160 static expert_field ei_nmea0183_vlw_cumulative_ground_unit_incorrect
;
161 static expert_field ei_nmea0183_vlw_trip_ground_unit_incorrect
;
162 static expert_field ei_nmea0183_vtg_true_course_unit_incorrect
;
163 static expert_field ei_nmea0183_vtg_magnetic_course_unit_incorrect
;
164 static expert_field ei_nmea0183_vtg_ground_speed_knot_unit_incorrect
;
165 static expert_field ei_nmea0183_vtg_ground_speed_kilometer_unit_incorrect
;
167 static int proto_nmea0183
;
169 static dissector_handle_t nmea0183_handle
;
171 // List of known Talker IDs (Source: NMEA Revealed by Eric S. Raymond, https://gpsd.gitlab.io/gpsd/NMEA.html, retrieved 2023-01-26)
172 static const string_string known_talker_ids
[] = {
173 {"AB", "Independent AIS Base Station"},
174 {"AD", "Dependent AIS Base Station"},
175 {"AG", "Autopilot - General"},
176 {"AI", "Mobile AIS Station"},
177 {"AN", "AIS Aid to Navigation"},
178 {"AP", "Autopilot - Magnetic"},
179 {"AR", "AIS Receiving Station"},
180 {"AT", "AIS Transmitting Station"},
181 {"AX", "AIS Simplex Repeater"},
182 {"BD", "BeiDou (China)"},
183 {"BI", "Bilge System"},
184 {"BN", "Bridge navigational watch alarm system"},
185 {"CA", "Central Alarm"},
186 {"CC", "Computer - Programmed Calculator (obsolete)"},
187 {"CD", "Communications - Digital Selective Calling (DSC)"},
188 {"CM", "Computer - Memory Data (obsolete)"},
189 {"CR", "Data Receiver"},
190 {"CS", "Communications - Satellite"},
191 {"CT", "Communications - Radio-Telephone (MF/HF)"},
192 {"CV", "Communications - Radio-Telephone (VHF)"},
193 {"CX", "Communications - Scanning Receiver"},
194 {"DE", "DECCA Navigation (obsolete)"},
195 {"DF", "Direction Finder"},
196 {"DM", "Velocity Sensor, Speed Log, Water, Magnetic"},
197 {"DP", "Dynamiv Position"},
198 {"DU", "Duplex repeater station"},
199 {"EC", "Electronic Chart Display & Information System (ECDIS)"},
200 {"EP", "Emergency Position Indicating Beacon (EPIRB)"},
201 {"ER", "Engine Room Monitoring Systems"},
203 {"FS", "Fire Sprinkler"},
204 {"GA", "Galileo Positioning System"},
205 {"GB", "BeiDou (China)"},
206 {"GI", "NavIC, IRNSS (India)"},
207 {"GL", "GLONASS, according to IEIC 61162-1"},
208 {"GN", "Combination of multiple satellite systems (NMEA 1083)"},
209 {"GP", "Global Positioning System receiver"},
210 {"GQ", "QZSS regional GPS augmentation system (Japan)"},
211 {"HC", "Heading - Magnetic Compass"},
213 {"HE", "Heading - North Seeking Gyro"},
214 {"HF", "Heading - Fluxgate"},
215 {"HN", "Heading - Non North Seeking Gyro"},
216 {"HS", "Hull Stress"},
217 {"II", "Integrated Instrumentation"},
218 {"IN", "Integrated Navigation"},
219 {"JA", "Alarm and Monitoring"},
220 {"JB", "Water Monitoring"},
221 {"JC", "Power Management"},
222 {"JD", "Propulsion Control"},
223 {"JE", "Engine Control"},
224 {"JF", "Propulsion Boiler"},
225 {"JG", "Aux Boiler"},
226 {"JH", "Engine Governor"},
227 {"LA", "Loran A (obsolete)"},
228 {"LC", "Loran C (obsolete)"},
229 {"MP", "Microwave Positioning System (obsolete)"},
230 {"MX", "Multiplexer"},
231 {"NL", "Navigation light controller"},
232 {"OM", "OMEGA Navigation System (obsolete)"},
233 {"OS", "Distress Alarm System (obsolete)"},
234 {"P ", "Vendor specific"},
235 {"QZ", "QZSS regional GPS augmentation system (Japan)"},
236 {"RA", "RADAR and/or ARPA"},
237 {"RB", "Record Book"},
238 {"RC", "Propulsion Machinery"},
239 {"RI", "Rudder Angle Indicator"},
240 {"SA", "Physical Shore AUS Station"},
241 {"SD", "Depth Sounder"},
242 {"SG", "Steering Gear"},
243 {"SN", "Electronic Positioning System, other/general"},
244 {"SS", "Scanning Sounder"},
245 {"ST", "Skytraq debug output"},
246 {"TC", "Track Control"},
247 {"TI", "Turn Rate Indicator"},
248 {"TR", "TRANSIT Navigation System"},
249 {"U0", "User Configured 0"},
250 {"U1", "User Configured 1"},
251 {"U2", "User Configured 2"},
252 {"U3", "User Configured 3"},
253 {"U4", "User Configured 4"},
254 {"U5", "User Configured 5"},
255 {"U6", "User Configured 6"},
256 {"U7", "User Configured 7"},
257 {"U8", "User Configured 8"},
258 {"U9", "User Configured 9"},
259 {"UP", "Microprocessor controller"},
260 {"VA", "VHF Data Exchange System (VDES), ASM"},
261 {"VD", "Velocity Sensor, Doppler, other/general"},
262 {"VM", "Velocity Sensor, Speed Log, Water, Magnetic"},
263 {"VR", "Voyage Data recorder"},
264 {"VS", "VHF Data Exchange System (VDES), Satellite"},
265 {"VT", "VHF Data Exchange System (VDES), Terrestrial"},
266 {"VW", "Velocity Sensor, Speed Log, Water, Mechanical"},
267 {"WD", "Watertight Door"},
268 {"WI", "Weather Instruments"},
269 {"WL", "Water Level"},
270 {"YC", "Transducer - Temperature (obsolete)"},
271 {"YD", "Transducer - Displacement, Angular or Linear (obsolete)"},
272 {"YF", "Transducer - Frequency (obsolete)"},
273 {"YL", "Transducer - Level (obsolete)"},
274 {"YP", "Transducer - Pressure (obsolete)"},
275 {"YR", "Transducer - Flow Rate (obsolete)"},
276 {"YT", "Transducer - Tachometer (obsolete)"},
277 {"YV", "Transducer - Volume (obsolete)"},
278 {"YX", "Transducer"},
279 {"ZA", "Timekeeper - Atomic Clock"},
280 {"ZC", "Timekeeper - Chronometer"},
281 {"ZQ", "Timekeeper - Quartz"},
282 {"ZV", "Timekeeper - Radio Update, WWV or WWVH"},
285 // List of known Sentence IDs (Source: NMEA Revealed by Eric S. Raymond, https://gpsd.gitlab.io/gpsd/NMEA.html, retrieved 2023-01-26)
286 static const string_string known_sentence_ids
[] = {
287 {"AAM", "Waypoint Arrival Alarm"},
288 {"ACK", "Alarm Acknowledgement"},
289 {"ADS", "Automatic Device Status"},
290 {"AKD", "Acknowledge Detail Alarm Condition"},
291 {"ALA", "Set Detail Alarm Condition"},
292 {"ALM", "GPS Almanac Data"},
293 {"APA", "Autopilot Sentence A"},
294 {"APB", "Autopilot Sentence B"},
295 {"ASD", "Autopilot System Data"},
296 {"BEC", "Bearing & Distance to Waypoint - Dead Reckoning"},
297 {"BER", "Bearing & Distance to Waypoint, Dead Reckoning, Rhumb Line"},
298 {"BOD", "Bearing - Waypoint to Waypoint"},
299 {"BPI", "Bearing & Distance to Point of Interest"},
300 {"BWC", "Bearing & Distance to Waypoint - Great Circle"},
301 {"BWR", "Bearing and Distance to Waypoint - Rhumb Line"},
302 {"BWW", "Bearing - Waypoint to Waypoint"},
303 {"CEK", "Configure Encryption Key Command"},
304 {"COP", "Configure the Operational Period, Command"},
305 {"CUR", "Water Current Layer"},
306 {"DBK", "Depth Below Keel"},
307 {"DBS", "Depth Below Surface"},
308 {"DBT", "Depth below transducer"},
309 {"DCN", "DECCA Position"},
310 {"DCR", "Device Capability Report"},
311 {"DDC", "Display Dimming Control"},
312 {"DOR", "Door Status Detection"},
313 {"DPT", "Depth of Water"},
314 {"DRU", "Dual Doppler Auxiliary Data"},
315 {"DSC", "Digital Selective Calling Information"},
316 {"DSE", "Extended DSC"},
317 {"DSI", "DSC Transponder Initiate"},
318 {"DSR", "DSC Transponder Response"},
319 {"DTM", "Datum Reference"},
320 {"ETL", "Engine Telegraph Operation Status"},
321 {"EVE", "General Event Message"},
322 {"FIR", "Fire Detection"},
323 {"FSI", "Frequency Set Information"},
324 {"GBS", "GPS Satellite Fault Detection"},
325 {"GDA", "Dead Reckoning Positions"},
326 {"GGA", "Global Positioning System Fix Data"},
327 {"GLa", "Loran-C Positions"},
328 {"GLC", "Geographic Position, Loran-C"},
329 {"GLL", "Geographic Position - Latitude/Longitude"},
331 {"GOA", "OMEGA Positions"},
332 {"GRS", "GPS Range Residuals"},
333 {"GSA", "GPS DOP and active satellites"},
334 {"GST", "GPS Pseudorange Noise Statistics"},
335 {"GSV", "Satellites in view"},
336 {"GTD", "Geographic Location in Time Differences"},
337 {"GXA", "TRANSIT Position"},
338 {"HCC", "Compass Heading"},
339 {"HCD", "Heading and Deviation"},
340 {"HDG", "Heading - Deviation & Variation"},
341 {"HDM", "Heading - Magnetic"},
342 {"HDT", "Heading - True"},
343 {"HFB", "Trawl Headrope to Footrope and Bottom"},
344 {"HSC", "Heading Steering Command"},
345 {"HVD", "Magnetic Variation, Automatic"},
346 {"HVM", "Magnetic Variation, Manually Set"},
347 {"IMA", "Vessel Identification"},
348 {"ITS", "Trawl Door Spread 2 Distance"},
349 {"LCD", "Loran-C Signal Data"},
350 {"MDA", "Meteorological Composite"},
352 {"MMB", "Barometer"},
353 {"MSK", "Control for a Beacon Receiver"},
354 {"MSS", "Beacon Receiver Status"},
355 {"MTA", "Air Temperature"},
356 {"MTW", "Mean Temperature of Water"},
357 {"MWD", "Wind Direction & Speed"},
358 {"MWH", "Wave Height"},
359 {"MWS", "Wind & Sea State"},
360 {"MWV", "Wind Speed and Angle"},
361 {"OLN", "Omega Lane Numbers"},
362 {"OLW", "Omega Lane Width"},
363 {"OMP", "Omega Position"},
364 {"OSD", "Own Ship Data"},
365 {"OZN", "Omega Zone Number"},
366 {"R00", "Waypoints in active route"},
367 {"RLM", "Return Link Message"},
368 {"RMA", "Recommended Minimum Navigation Information"},
369 {"RMB", "Recommended Minimum Navigation Information"},
370 {"RMC", "Recommended Minimum Navigation Information"},
372 {"ROT", "Rate Of Turn"},
373 {"RPM", "Revolutions"},
374 {"RSA", "Rudder Sensor Angle"},
375 {"RSD", "RADAR System Data"},
377 {"SBK", "Loran-C Blink Status"},
378 {"SCD", "Loran-C ECDs"},
379 {"SCY", "Loran-C Cycle Lock Status"},
380 {"SDB", "Loran-C Signal Strength"},
381 {"SFI", "Scanning Frequency Information"},
382 {"SGD", "Position Accuracy Estimate"},
383 {"SGR", "Loran-C Chain Identifier"},
384 {"SIU", "Loran-C Stations in Use"},
385 {"SLC", "Loran-C Status"},
386 {"SNC", "Navigation Calculation Basis"},
387 {"SNU", "Loran-C SNR Status"},
388 {"SPS", "Loran-C Predicted Signal Strength"},
389 {"SSF", "Position Correction Offset"},
390 {"STC", "Time Constant"},
391 {"STN", "Multiple Data ID"},
392 {"STR", "Tracking Reference"},
393 {"SYS", "Hybrid System Configuration"},
394 {"TDS", "Trawl Door Spread Distance"},
395 {"TEC", "TRANSIT Satellite Error Code & Doppler Count"},
396 {"TEP", "TRANSIT Satellite Predicted Elevation"},
397 {"TFI", "Trawl Filling Indicator"},
398 {"TGA", "TRANSIT Satellite Antenna & Geoidal Heights"},
399 {"TIF", "TRANSIT Satellite Initial Flag"},
400 {"TLB", "Target Label"},
401 {"TLL", "Target Latitude and Longitude"},
402 {"TPC", "Trawl Position Cartesian Coordinates"},
403 {"TPR", "Trawl Position Relative Vessel"},
404 {"TPT", "Trawl Position True"},
405 {"TRF", "TRANSIT Fix Data"},
406 {"TRP", "TRANSIT Satellite Predicted Direction of Rise"},
407 {"TRS", "TRANSIT Satellite Operating Status"},
408 {"TTM", "Tracked Target Message"},
409 {"VBW", "Dual Ground/Water Speed"},
410 {"VCD", "Current at Selected Depth"},
411 {"VDR", "Set and Drift"},
412 {"VHW", "Water speed and heading"},
413 {"VLW", "Distance Traveled through Water"},
414 {"VPE", "Speed, Dead Reckoned Parallel to True Wind"},
415 {"VPW", "Speed - Measured Parallel to Wind"},
416 {"VTA", "Actual Track"},
417 {"VTG", "Track made good and Ground speed"},
418 {"VTI", "Intended Track"},
419 {"VWE", "Wind Track Efficiency"},
420 {"VWR", "Relative Wind Speed and Angle"},
421 {"VWT", "True Wind Speed and Angle"},
422 {"WCV", "Waypoint Closure Velocity"},
423 {"WDC", "Distance to Waypoint - Great Circle"},
424 {"WDR", "Distance to Waypoint - Rhumb Line"},
425 {"WFM", "Route Following Mode"},
426 {"WNC", "Distance - Waypoint to Waypoint"},
427 {"WNR", "Waypoint-to-Waypoint Distance, Rhumb Line"},
428 {"WPL", "Waypoint Location"},
429 {"XDR", "Transducer Measurement"},
430 {"XTE", "Cross-Track Error, Measured"},
431 {"XTR", "Cross Track Error - Dead Reckoning"},
432 {"YWP", "Water Propagation Speed"},
433 {"YWS", "Water Profile"},
434 {"ZAA", "Time, Elapsed/Estimated"},
436 {"ZDA", "Time & Date - UTC, day, month, year and local time zone"},
437 {"ZDL", "Time and Distance to Variable Point"},
438 {"ZEV", "Event Timer"},
439 {"ZFO", "UTC & Time from origin Waypoint"},
440 {"ZLZ", "Time of Day"},
441 {"ZTG", "UTC & Time to Destination Waypoint"},
442 {"ZZU", "Time, UTC"},
445 // List of GPS Quality Indicator (Source: NMEA Revealed by Eric S. Raymond, https://gpsd.gitlab.io/gpsd/NMEA.html, retrieved 2023-01-26)
446 static const string_string known_gps_quality_indicators
[] = {
447 {"0", "Fix not available"},
449 {"2", "Differential GPS fix"},
451 {"4", "Real Time Kinematic"},
452 {"5", "Float Real Time Kinematic"},
453 {"6", "Estimated (dead reckoning)"},
454 {"7", "Manual input mode"},
455 {"8", "Simulation mode"},
458 // List of status indicators (Source: NMEA Revealed by Eric S. Raymond, https://gpsd.gitlab.io/gpsd/NMEA.html, retrieved 2024-04-19)
459 static const string_string known_status_indicators
[] = {
460 {"A", "Valid/Active"},
461 {"V", "Invalid/Void"},
464 // List of FAA Mode Indicator (Source: NMEA Revealed by Eric S. Raymond, https://gpsd.gitlab.io/gpsd/NMEA.html, retrieved 2024-04-19)
465 static const string_string known_faa_mode_indicators
[] = {
466 {"A", "Autonomous mode"},
467 {"C", "Quectel Querk, Caution"},
468 {"D", "Differential Mode"},
469 {"E", "Estimated (dead-reckoning) mode"},
470 {"F", "RTK Float mode"},
471 {"M", "Manual Input Mode"},
472 {"N", "Data Not Valid"},
474 {"R", "RTK Integer mode"},
475 {"S", "Simulated Mode"},
476 {"U", "Quectel Querk, Unsafe"},
479 static uint8_t calculate_checksum(tvbuff_t
*tvb
, const int start
, const int length
)
481 uint8_t checksum
= 0;
482 for (int i
= start
; i
< start
+ length
; i
++)
484 checksum
^= tvb_get_uint8(tvb
, i
);
489 /* Find first occurrence of a field separator in tvbuff, starting at offset. Searches
491 * Returns the offset of the found separator.
492 * If separator is not found, return the offset of end of tvbuff.
493 * If offset is out of bounds, return the offset of end of tvbuff.
496 tvb_find_end_of_nmea0183_field(tvbuff_t
*tvb
, const int offset
)
498 if (tvb_captured_length_remaining(tvb
, offset
) == 0)
500 return tvb_captured_length(tvb
);
503 int end_of_field_offset
= tvb_find_uint8(tvb
, offset
, -1, ',');
504 if (end_of_field_offset
== -1)
506 return tvb_captured_length(tvb
);
508 return end_of_field_offset
;
511 /* Add a zero length item which indicates an expected but missing field */
513 proto_tree_add_missing_field(proto_tree
*tree
, packet_info
*pinfo
, int hf
, tvbuff_t
*tvb
,
516 proto_item
*ti
= NULL
;
517 ti
= proto_tree_add_item(tree
, hf
, tvb
, offset
, 0, ENC_ASCII
);
518 proto_item_append_text(ti
, "[missing]");
519 expert_add_info(pinfo
, ti
, &ei_nmea0183_field_missing
);
523 /* Dissect a time field. The field is split into a tree with hour, minute and second elements.
524 * Returns length including separator
527 dissect_nmea0183_field_time(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, int offset
,
528 int hf_time
, int hf_hour
, int hf_minute
, int hf_second
, int ett_time
)
530 if (offset
> (int)tvb_captured_length(tvb
))
532 proto_tree_add_missing_field(tree
, pinfo
, hf_time
, tvb
, tvb_captured_length(tvb
));
536 proto_item
*ti
= NULL
;
537 int end_of_field_offset
= tvb_find_end_of_nmea0183_field(tvb
, offset
);
538 ti
= proto_tree_add_item(tree
, hf_time
, tvb
, offset
, end_of_field_offset
- offset
, ENC_ASCII
);
539 if (end_of_field_offset
- offset
== 0)
541 proto_item_append_text(ti
, ": [empty]");
543 else if (end_of_field_offset
- offset
>= 6)
545 const uint8_t *hour
= NULL
;
546 const uint8_t *minute
= NULL
;
547 const uint8_t *second
= NULL
;
548 proto_tree
*time_subtree
= proto_item_add_subtree(ti
, ett_time
);
550 proto_tree_add_item_ret_string(time_subtree
, hf_hour
,
551 tvb
, offset
, 2, ENC_ASCII
,
554 proto_tree_add_item_ret_string(time_subtree
, hf_minute
,
555 tvb
, offset
+ 2, 2, ENC_ASCII
,
556 pinfo
->pool
, &minute
);
558 proto_tree_add_item_ret_string(time_subtree
, hf_second
,
559 tvb
, offset
+ 4, end_of_field_offset
- offset
- 4,
560 ENC_ASCII
, pinfo
->pool
, &second
);
562 proto_item_append_text(ti
, ": %s:%s:%s", hour
, minute
, second
);
566 expert_add_info(pinfo
, ti
, &ei_nmea0183_field_time_too_short
);
568 return end_of_field_offset
- offset
+ 1;
571 /* Dissect a single field containing a dimensionless value. Returns length including separator */
573 dissect_nmea0183_field(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, int offset
, int hf
, const char *suffix
)
575 if (offset
> (int)tvb_captured_length(tvb
))
577 proto_tree_add_missing_field(tree
, pinfo
, hf
, tvb
, tvb_captured_length(tvb
));
581 proto_item
*ti
= NULL
;
582 int end_of_field_offset
= tvb_find_end_of_nmea0183_field(tvb
, offset
);
583 ti
= proto_tree_add_item(tree
, hf
, tvb
, offset
, end_of_field_offset
- offset
, ENC_ASCII
);
584 if (end_of_field_offset
- offset
== 0)
586 proto_item_append_text(ti
, "[empty]");
588 else if (suffix
!= NULL
)
590 proto_item_append_text(ti
, " %s", suffix
);
592 return end_of_field_offset
- offset
+ 1;
595 /* Dissect a latitude/longitude direction field.
596 * Returns length including separator
599 dissect_nmea0183_field_latlong_direction(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
,
601 wmem_allocator_t
*scope
, const uint8_t **retval
)
603 if (offset
> (int)tvb_captured_length(tvb
))
605 proto_tree_add_missing_field(tree
, pinfo
, hf
, tvb
, tvb_captured_length(tvb
));
609 int end_of_field_offset
= tvb_find_end_of_nmea0183_field(tvb
, offset
);
610 proto_item
*ti
= proto_tree_add_item_ret_string(tree
, hf
,
611 tvb
, offset
, end_of_field_offset
- offset
, ENC_ASCII
,
613 if (end_of_field_offset
- offset
== 0)
617 proto_item_append_text(ti
, "[empty]");
621 proto_item_append_text(ti
, "[missing]");
622 expert_add_info(pinfo
, ti
, &ei_nmea0183_field_missing
);
625 return end_of_field_offset
- offset
+ 1;
628 /* Dissect a latitude field + direction field. The fields are split into a tree with degree, minute and direction elements.
629 * Returns length including separator
632 dissect_nmea0183_field_latitude(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, int offset
,
633 int hf_latitude
, int hf_degree
, int hf_minute
, int hf_direction
, int ett_latitude
)
635 if (offset
> (int)tvb_captured_length(tvb
))
637 proto_tree_add_missing_field(tree
, pinfo
, hf_latitude
, tvb
, tvb_captured_length(tvb
));
641 proto_item
*ti
= NULL
;
642 int end_of_field_offset
= tvb_find_end_of_nmea0183_field(tvb
, offset
);
643 ti
= proto_tree_add_item(tree
, hf_latitude
, tvb
, offset
, end_of_field_offset
- offset
, ENC_ASCII
);
644 if (end_of_field_offset
- offset
== 0)
646 proto_item_append_text(ti
, "[empty]");
648 end_of_field_offset
+= dissect_nmea0183_field_latlong_direction(tvb
, pinfo
, tree
, end_of_field_offset
+ 1, hf_direction
, NULL
, NULL
);
650 else if (end_of_field_offset
- offset
>= 4)
652 const uint8_t *degree
= NULL
;
653 const uint8_t *minute
= NULL
;
654 const uint8_t *direction
= NULL
;
655 proto_tree
*latitude_subtree
= proto_item_add_subtree(ti
, ett_latitude
);
657 proto_tree_add_item_ret_string(latitude_subtree
, hf_degree
,
659 ENC_ASCII
, pinfo
->pool
, °ree
);
661 proto_tree_add_item_ret_string(latitude_subtree
, hf_minute
,
662 tvb
, offset
+ 2, end_of_field_offset
- offset
- 2,
663 ENC_ASCII
, pinfo
->pool
, &minute
);
665 end_of_field_offset
+= dissect_nmea0183_field_latlong_direction(tvb
, pinfo
, latitude_subtree
, end_of_field_offset
+ 1, hf_direction
, pinfo
->pool
, &direction
);
667 proto_item_append_text(ti
, ": %s° %s' %s", degree
, minute
, direction
);
671 expert_add_info(pinfo
, ti
, &ei_nmea0183_field_latitude_too_short
);
673 end_of_field_offset
+= dissect_nmea0183_field_latlong_direction(tvb
, pinfo
, tree
, end_of_field_offset
+ 1, hf_direction
, NULL
, NULL
);
675 return end_of_field_offset
- offset
+ 1;
678 /* Dissect a longitude field + direction field. The fields are split into a tree with degree, minute and direction elements.
679 * Returns length including separator
682 dissect_nmea0183_field_longitude(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, int offset
,
683 int hf_longitude
, int hf_degree
, int hf_minute
, int hf_direction
, int ett_latitude
)
685 if (offset
> (int)tvb_captured_length(tvb
))
687 proto_tree_add_missing_field(tree
, pinfo
, hf_longitude
, tvb
, tvb_captured_length(tvb
));
691 proto_item
*ti
= NULL
;
692 int end_of_field_offset
= tvb_find_end_of_nmea0183_field(tvb
, offset
);
693 ti
= proto_tree_add_item(tree
, hf_longitude
, tvb
, offset
, end_of_field_offset
- offset
, ENC_ASCII
);
694 if (end_of_field_offset
- offset
== 0)
696 proto_item_append_text(ti
, "[empty]");
698 end_of_field_offset
+= dissect_nmea0183_field_latlong_direction(tvb
, pinfo
, tree
, end_of_field_offset
+ 1, hf_direction
, NULL
, NULL
);
700 else if (end_of_field_offset
- offset
>= 5)
702 const uint8_t *degree
= NULL
;
703 const uint8_t *minute
= NULL
;
704 const uint8_t *direction
= NULL
;
705 proto_tree
*longitude_subtree
= proto_item_add_subtree(ti
, ett_latitude
);
707 proto_tree_add_item_ret_string(longitude_subtree
, hf_degree
,
709 ENC_ASCII
, pinfo
->pool
, °ree
);
711 proto_tree_add_item_ret_string(longitude_subtree
, hf_minute
,
712 tvb
, offset
+ 3, end_of_field_offset
- offset
- 3,
713 ENC_ASCII
, pinfo
->pool
, &minute
);
715 end_of_field_offset
+= dissect_nmea0183_field_latlong_direction(tvb
, pinfo
, longitude_subtree
, end_of_field_offset
+ 1, hf_direction
, pinfo
->pool
, &direction
);
717 proto_item_append_text(ti
, ": %s° %s' %s", degree
, minute
, direction
);
721 expert_add_info(pinfo
, ti
, &ei_nmea0183_field_longitude_too_short
);
723 end_of_field_offset
+= dissect_nmea0183_field_latlong_direction(tvb
, pinfo
, tree
, end_of_field_offset
+ 1, hf_direction
, NULL
, NULL
);
725 return end_of_field_offset
- offset
+ 1;
728 /* Dissect a required gps quality field. Returns length including separator */
730 dissect_nmea0183_field_gps_quality(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, int offset
, int hf
)
732 if (offset
> (int)tvb_captured_length(tvb
))
734 proto_tree_add_missing_field(tree
, pinfo
, hf
, tvb
, tvb_captured_length(tvb
));
738 proto_item
*ti
= NULL
;
739 int end_of_field_offset
= tvb_find_end_of_nmea0183_field(tvb
, offset
);
740 const uint8_t *quality
= NULL
;
741 ti
= proto_tree_add_item_ret_string(tree
, hf
,
742 tvb
, offset
, end_of_field_offset
- offset
, ENC_ASCII
,
743 pinfo
->pool
, &quality
);
744 if (end_of_field_offset
- offset
== 0)
746 proto_item_append_text(ti
, "[missing]");
747 expert_add_info(pinfo
, ti
, &ei_nmea0183_field_missing
);
751 proto_item_append_text(ti
, " (%s)", str_to_str(quality
, known_gps_quality_indicators
, "Unknown quality"));
753 return end_of_field_offset
- offset
+ 1;
756 /* Dissect a single field containing a fixed text.
757 The text of the field must match the `expected_text` or expert info `invalid_ei` is
758 added to the field. An empty field is allowed. Returns length including separator */
760 dissect_nmea0183_field_fixed_text(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, int offset
, int hf
,
761 const uint8_t *expected_text
, expert_field
*invalid_ei
)
763 if (offset
> (int)tvb_captured_length(tvb
))
765 proto_tree_add_missing_field(tree
, pinfo
, hf
, tvb
, tvb_captured_length(tvb
));
769 proto_item
*ti
= NULL
;
770 const uint8_t *text
= NULL
;
771 int end_of_field_offset
= tvb_find_end_of_nmea0183_field(tvb
, offset
);
772 ti
= proto_tree_add_item_ret_string(tree
, hf
,
773 tvb
, offset
, end_of_field_offset
- offset
, ENC_ASCII
,
775 if (end_of_field_offset
- offset
== 0)
777 proto_item_append_text(ti
, "[empty]");
779 else if (g_ascii_strcasecmp(text
, expected_text
) != 0)
781 expert_add_info(pinfo
, ti
, invalid_ei
);
783 return end_of_field_offset
- offset
+ 1;
786 /* Dissect a optional FAA mode indicator field. Returns length including separator */
788 dissect_nmea0183_field_faa_mode(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, int offset
, int hf
)
790 if (offset
> (int)tvb_captured_length(tvb
))
792 proto_tree_add_missing_field(tree
, pinfo
, hf
, tvb
, tvb_captured_length(tvb
));
796 proto_item
*ti
= NULL
;
797 int end_of_field_offset
= tvb_find_end_of_nmea0183_field(tvb
, offset
);
798 const uint8_t *mode
= NULL
;
799 ti
= proto_tree_add_item_ret_string(tree
, hf
,
800 tvb
, offset
, end_of_field_offset
- offset
, ENC_ASCII
,
802 if (end_of_field_offset
- offset
== 0)
804 proto_item_append_text(ti
, "[empty]");
808 proto_item_append_text(ti
, " (%s)", str_to_str(mode
, known_faa_mode_indicators
, "Unknown FAA mode"));
810 return end_of_field_offset
- offset
+ 1;
813 /* Dissect a optional A/V status field. Returns length including separator */
815 dissect_nmea0183_field_status(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, int offset
, int hf
)
817 if (offset
> (int)tvb_captured_length(tvb
))
819 proto_tree_add_missing_field(tree
, pinfo
, hf
, tvb
, tvb_captured_length(tvb
));
823 proto_item
*ti
= NULL
;
824 int end_of_field_offset
= tvb_find_end_of_nmea0183_field(tvb
, offset
);
825 const uint8_t *mode
= NULL
;
826 ti
= proto_tree_add_item_ret_string(tree
, hf
,
827 tvb
, offset
, end_of_field_offset
- offset
, ENC_ASCII
,
829 if (end_of_field_offset
- offset
== 0)
831 proto_item_append_text(ti
, "[empty]");
835 proto_item_append_text(ti
, " (%s)", str_to_str(mode
, known_status_indicators
, "Unknown status"));
837 return end_of_field_offset
- offset
+ 1;
840 /* Dissect a DPT sentence. */
842 dissect_nmea0183_sentence_dpt(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
846 proto_tree
*subtree
= proto_tree_add_subtree(tree
, tvb
, offset
,
847 tvb_captured_length(tvb
), ett_nmea0183_sentence
, NULL
, "DPT sentence - Depth of Water");
849 offset
+= dissect_nmea0183_field(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_dpt_depth
, "meter");
851 offset
+= dissect_nmea0183_field(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_dpt_offset
, "meter");
853 dissect_nmea0183_field(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_dpt_max_range
, "meter");
855 return tvb_captured_length(tvb
);
858 /* Dissect a GGA sentence. The time, latitude and longitude fields is split into individual parts. */
860 dissect_nmea0183_sentence_gga(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
864 proto_tree
*subtree
= proto_tree_add_subtree(tree
, tvb
, offset
,
865 tvb_captured_length(tvb
), ett_nmea0183_sentence
,
866 NULL
, "GGA sentence - Global Positioning System Fix");
868 offset
+= dissect_nmea0183_field_time(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_gga_time
,
869 hf_nmea0183_gga_time_hour
, hf_nmea0183_gga_time_minute
,
870 hf_nmea0183_gga_time_second
, ett_nmea0183_gga_time
);
872 offset
+= dissect_nmea0183_field_latitude(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_gga_latitude
,
873 hf_nmea0183_gga_latitude_degree
, hf_nmea0183_gga_latitude_minute
,
874 hf_nmea0183_gga_latitude_direction
, ett_nmea0183_gga_latitude
);
876 offset
+= dissect_nmea0183_field_longitude(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_gga_longitude
,
877 hf_nmea0183_gga_longitude_degree
, hf_nmea0183_gga_longitude_minute
,
878 hf_nmea0183_gga_longitude_direction
, ett_nmea0183_gga_longitude
);
880 offset
+= dissect_nmea0183_field_gps_quality(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_gga_quality
);
882 offset
+= dissect_nmea0183_field(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_gga_number_satellites
, NULL
);
884 offset
+= dissect_nmea0183_field(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_gga_horizontal_dilution
, "meter");
886 offset
+= dissect_nmea0183_field(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_gga_altitude
, "meter");
888 offset
+= dissect_nmea0183_field_fixed_text(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_gga_altitude_unit
,
889 "M", &ei_nmea0183_gga_altitude_unit_incorrect
);
891 offset
+= dissect_nmea0183_field(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_gga_geoidal_separation
, "meter");
893 offset
+= dissect_nmea0183_field_fixed_text(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_gga_geoidal_separation_unit
,
894 "M", &ei_nmea0183_gga_geoidal_separation_unit_incorrect
);
896 offset
+= dissect_nmea0183_field(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_gga_age_dgps
, "second");
898 dissect_nmea0183_field(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_gga_dgps_station
, NULL
);
900 return tvb_captured_length(tvb
);
903 /* Dissect a GLL sentence. The latitude, longitude and time fields is split into individual parts. */
905 dissect_nmea0183_sentence_gll(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
909 proto_tree
*subtree
= proto_tree_add_subtree(tree
, tvb
, offset
,
910 tvb_captured_length(tvb
), ett_nmea0183_sentence
,
911 NULL
, "GLL sentence - Geographic Position");
913 offset
+= dissect_nmea0183_field_latitude(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_gll_latitude
,
914 hf_nmea0183_gll_latitude_degree
, hf_nmea0183_gll_latitude_minute
,
915 hf_nmea0183_gll_latitude_direction
, ett_nmea0183_gll_latitude
);
917 offset
+= dissect_nmea0183_field_longitude(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_gll_longitude
,
918 hf_nmea0183_gll_longitude_degree
, hf_nmea0183_gll_longitude_minute
,
919 hf_nmea0183_gll_longitude_direction
, ett_nmea0183_gll_longitude
);
921 offset
+= dissect_nmea0183_field_time(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_gll_time
,
922 hf_nmea0183_gll_time_hour
, hf_nmea0183_gll_time_minute
,
923 hf_nmea0183_gll_time_second
, ett_nmea0183_gll_time
);
925 offset
+= dissect_nmea0183_field_status(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_gll_status
);
927 dissect_nmea0183_field_faa_mode(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_gll_mode
);
929 return tvb_captured_length(tvb
);
932 /* Dissect a GST sentence. The time field is split into individual parts. */
934 dissect_nmea0183_sentence_gst(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
938 proto_tree
*subtree
= proto_tree_add_subtree(tree
, tvb
, offset
,
939 tvb_captured_length(tvb
), ett_nmea0183_sentence
,
940 NULL
, "GST sentence - GPS Pseudorange Noise Statistics");
942 offset
+= dissect_nmea0183_field_time(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_gst_time
,
943 hf_nmea0183_gst_time_hour
, hf_nmea0183_gst_time_minute
,
944 hf_nmea0183_gst_time_second
, ett_nmea0183_gst_time
);
946 offset
+= dissect_nmea0183_field(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_gst_rms_total_sd
, "");
948 offset
+= dissect_nmea0183_field(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_gst_ellipse_major_sd
, "meter");
949 offset
+= dissect_nmea0183_field(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_gst_ellipse_minor_sd
, "meter");
950 offset
+= dissect_nmea0183_field(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_gst_ellipse_orientation
, "degree (true north)");
952 offset
+= dissect_nmea0183_field(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_gst_latitude_sd
, "meter");
953 offset
+= dissect_nmea0183_field(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_gst_longitude_sd
, "meter");
954 dissect_nmea0183_field(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_gst_altitude_sd
, "meter");
956 return tvb_captured_length(tvb
);
959 /* Dissect a HDT sentence. */
961 dissect_nmea0183_sentence_hdt(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
965 proto_tree
*subtree
= proto_tree_add_subtree(tree
, tvb
, offset
,
966 tvb_captured_length(tvb
), ett_nmea0183_sentence
,
967 NULL
, "HDT sentence - True Heading");
969 offset
+= dissect_nmea0183_field(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_hdt_heading
, "degree");
971 dissect_nmea0183_field_fixed_text(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_hdt_unit
,
972 "T", &ei_nmea0183_hdt_unit_incorrect
);
974 return tvb_captured_length(tvb
);
977 /* Dissect a ROT sentence. */
979 dissect_nmea0183_sentence_rot(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
983 proto_tree
*subtree
= proto_tree_add_subtree(tree
, tvb
, offset
,
984 tvb_captured_length(tvb
), ett_nmea0183_sentence
,
985 NULL
, "ROT sentence - Rate Of Turn");
987 offset
+= dissect_nmea0183_field(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_rot_rate_of_turn
, "degree per minute");
989 dissect_nmea0183_field_status(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_rot_valid
);
991 return tvb_captured_length(tvb
);
994 /* Dissect a VHW sentence. */
996 dissect_nmea0183_sentence_vhw(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
1000 proto_tree
*subtree
= proto_tree_add_subtree(tree
, tvb
, offset
,
1001 tvb_captured_length(tvb
), ett_nmea0183_sentence
,
1002 NULL
, "VHW sentence - Water speed and heading");
1004 offset
+= dissect_nmea0183_field(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_vhw_true_heading
, "degree");
1006 offset
+= dissect_nmea0183_field_fixed_text(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_vhw_true_heading_unit
,
1007 "T", &ei_nmea0183_vhw_true_heading_unit_incorrect
);
1009 offset
+= dissect_nmea0183_field(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_vhw_magnetic_heading
, "degree");
1011 offset
+= dissect_nmea0183_field_fixed_text(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_vhw_magnetic_heading_unit
,
1012 "M", &ei_nmea0183_vhw_magnetic_heading_unit_incorrect
);
1014 offset
+= dissect_nmea0183_field(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_vhw_water_speed_knot
, "knot");
1016 offset
+= dissect_nmea0183_field_fixed_text(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_vhw_water_speed_knot_unit
,
1017 "N", &ei_nmea0183_vhw_water_speed_knot_unit_incorrect
);
1019 offset
+= dissect_nmea0183_field(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_vhw_water_speed_kilometer
, "kilometer per hour");
1021 dissect_nmea0183_field_fixed_text(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_vhw_water_speed_kilometer_unit
,
1022 "K", &ei_nmea0183_vhw_water_speed_kilometer_unit_incorrect
);
1024 return tvb_captured_length(tvb
);
1027 /* Dissect a VBW sentence. */
1029 dissect_nmea0183_sentence_vbw(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
1033 proto_tree
*subtree
= proto_tree_add_subtree(tree
, tvb
, offset
,
1034 tvb_captured_length(tvb
), ett_nmea0183_sentence
,
1035 NULL
, "VBW sentence - Dual Ground/Water Speed");
1037 offset
+= dissect_nmea0183_field(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_vbw_water_speed_longitudinal
, "knot");
1038 offset
+= dissect_nmea0183_field(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_vbw_water_speed_transverse
, "knot");
1039 offset
+= dissect_nmea0183_field_status(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_vbw_water_speed_valid
);
1041 offset
+= dissect_nmea0183_field(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_vbw_ground_speed_longitudinal
, "knot");
1042 offset
+= dissect_nmea0183_field(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_vbw_ground_speed_transverse
, "knot");
1043 offset
+= dissect_nmea0183_field_status(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_vbw_ground_speed_valid
);
1045 offset
+= dissect_nmea0183_field(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_vbw_stern_water_speed
, "knot");
1046 offset
+= dissect_nmea0183_field_status(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_vbw_stern_water_speed_valid
);
1048 offset
+= dissect_nmea0183_field(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_vbw_stern_ground_speed
, "knot");
1049 dissect_nmea0183_field_status(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_vbw_stern_ground_speed_valid
);
1051 return tvb_captured_length(tvb
);
1054 /* Dissect a VLW sentence. */
1056 dissect_nmea0183_sentence_vlw(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
1060 proto_tree
*subtree
= proto_tree_add_subtree(tree
, tvb
, offset
,
1061 tvb_captured_length(tvb
), ett_nmea0183_sentence
,
1062 NULL
, "VLW sentence - Distance Traveled through Water");
1064 offset
+= dissect_nmea0183_field(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_vlw_cumulative_water
, "nautical miles");
1066 offset
+= dissect_nmea0183_field_fixed_text(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_vlw_cumulative_water_unit
,
1067 "N", &ei_nmea0183_vlw_cumulative_water_unit_incorrect
);
1069 offset
+= dissect_nmea0183_field(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_vlw_trip_water
, "nautical miles");
1071 offset
+= dissect_nmea0183_field_fixed_text(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_vlw_trip_water_unit
,
1072 "N", &ei_nmea0183_vlw_trip_water_unit_incorrect
);
1074 offset
+= dissect_nmea0183_field(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_vlw_cumulative_ground
, "nautical miles");
1076 offset
+= dissect_nmea0183_field_fixed_text(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_vlw_cumulative_ground_unit
,
1077 "N", &ei_nmea0183_vlw_cumulative_ground_unit_incorrect
);
1079 offset
+= dissect_nmea0183_field(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_vlw_trip_ground
, "nautical miles");
1081 dissect_nmea0183_field_fixed_text(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_vlw_trip_ground_unit
,
1082 "N", &ei_nmea0183_vlw_trip_ground_unit_incorrect
);
1084 return tvb_captured_length(tvb
);
1087 /* Dissect a VTG sentence. */
1089 dissect_nmea0183_sentence_vtg(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
1093 proto_tree
*subtree
= proto_tree_add_subtree(tree
, tvb
, offset
,
1094 tvb_captured_length(tvb
), ett_nmea0183_sentence
,
1095 NULL
, "VTG sentence - Track made good and Ground speed");
1097 offset
+= dissect_nmea0183_field(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_vtg_true_course
, "degree");
1099 offset
+= dissect_nmea0183_field_fixed_text(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_vtg_true_course_unit
,
1100 "T", &ei_nmea0183_vtg_true_course_unit_incorrect
);
1102 offset
+= dissect_nmea0183_field(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_vtg_magnetic_course
, "degree");
1104 offset
+= dissect_nmea0183_field_fixed_text(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_vtg_magnetic_course_unit
,
1105 "M", &ei_nmea0183_vtg_magnetic_course_unit_incorrect
);
1107 offset
+= dissect_nmea0183_field(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_vtg_ground_speed_knot
, "knot");
1109 offset
+= dissect_nmea0183_field_fixed_text(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_vtg_ground_speed_knot_unit
,
1110 "N", &ei_nmea0183_vtg_ground_speed_knot_unit_incorrect
);
1112 offset
+= dissect_nmea0183_field(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_vtg_ground_speed_kilometer
, "kilometer per hour");
1114 offset
+= dissect_nmea0183_field_fixed_text(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_vtg_ground_speed_kilometer_unit
,
1115 "K", &ei_nmea0183_vtg_ground_speed_kilometer_unit_incorrect
);
1117 dissect_nmea0183_field_faa_mode(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_vtg_mode
);
1119 return tvb_captured_length(tvb
);
1122 /* Dissect a ZDA (Time & Date) sentence. The time field is split into individual parts. */
1124 dissect_nmea0183_sentence_zda(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
1127 proto_tree
*subtree
= proto_tree_add_subtree(tree
, tvb
, offset
,
1128 tvb_captured_length(tvb
), ett_nmea0183_sentence
,
1129 NULL
, "ZDA sentence - Time & Date");
1131 offset
+= dissect_nmea0183_field_time(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_zda_time
,
1132 hf_nmea0183_zda_time_hour
, hf_nmea0183_zda_time_minute
,
1133 hf_nmea0183_zda_time_second
, ett_nmea0183_zda_time
);
1135 offset
+= dissect_nmea0183_field(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_zda_date_day
, NULL
);
1137 offset
+= dissect_nmea0183_field(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_zda_date_month
, NULL
);
1139 offset
+= dissect_nmea0183_field(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_zda_date_year
, NULL
);
1141 offset
+= dissect_nmea0183_field(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_zda_local_zone_hour
, NULL
);
1143 dissect_nmea0183_field(tvb
, pinfo
, subtree
, offset
, hf_nmea0183_zda_local_zone_minute
, NULL
);
1145 return tvb_captured_length(tvb
);
1148 /* Dissect a sentence where the sentence id is unknown. Each field is shown as an generic field. */
1150 dissect_nmea0183_sentence_unknown(tvbuff_t
*tvb
, packet_info
*pinfo _U_
, proto_tree
*tree
)
1154 proto_tree
*subtree
= proto_tree_add_subtree(tree
, tvb
, offset
,
1155 tvb_captured_length(tvb
), ett_nmea0183_sentence
,
1156 NULL
, "Unknown sentence");
1158 /* In an unknown sentence, the name of each field is unknown. Find all field by splitting at a comma. */
1159 while (tvb_captured_length_remaining(tvb
, offset
) > 0)
1161 int end_of_field_offset
= tvb_find_end_of_nmea0183_field(tvb
, offset
);
1162 proto_item
*ti
= proto_tree_add_item(subtree
, hf_nmea0183_unknown_field
,
1163 tvb
, offset
, end_of_field_offset
- offset
, ENC_ASCII
);
1164 if (end_of_field_offset
- offset
== 0)
1166 proto_item_append_text(ti
, "[empty]");
1168 offset
= end_of_field_offset
+ 1;
1170 return tvb_captured_length(tvb
);
1174 dissect_nmea0183(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
1177 int start_checksum_offset
= 0;
1178 const uint8_t *talker_id
= NULL
;
1179 const uint8_t *sentence_id
= NULL
;
1180 const uint8_t *checksum
= NULL
;
1182 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "NMEA 0183");
1183 /* Clear the info column */
1184 col_clear(pinfo
->cinfo
, COL_INFO
);
1186 proto_item
*ti
= proto_tree_add_item(tree
, proto_nmea0183
, tvb
, 0, -1, ENC_NA
);
1187 proto_tree
*nmea0183_tree
= proto_item_add_subtree(ti
, ett_nmea0183
);
1189 /* Start delimiter */
1190 if (tvb_get_uint8(tvb
, offset
) != '$')
1192 expert_add_info(pinfo
, nmea0183_tree
, &ei_nmea0183_invalid_first_character
);
1197 ti
= proto_tree_add_item_ret_string(nmea0183_tree
, hf_nmea0183_talker_id
,
1198 tvb
, offset
, 2, ENC_ASCII
,
1199 pinfo
->pool
, &talker_id
);
1201 proto_item_append_text(ti
, " (%s)", str_to_str(talker_id
, known_talker_ids
, "Unknown talker ID"));
1203 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "Talker %s", talker_id
);
1208 ti
= proto_tree_add_item_ret_string(nmea0183_tree
, hf_nmea0183_sentence_id
,
1209 tvb
, offset
, 3, ENC_ASCII
,
1210 pinfo
->pool
, &sentence_id
);
1212 proto_item_append_text(ti
, " (%s)", str_to_str(sentence_id
, known_sentence_ids
, "Unknown sentence ID"));
1214 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", Sentence %s", sentence_id
);
1218 /* Start of checksum */
1219 start_checksum_offset
= tvb_find_uint8(tvb
, offset
, -1, '*');
1220 if (start_checksum_offset
== -1)
1222 expert_add_info(pinfo
, nmea0183_tree
, &ei_nmea0183_missing_checksum_character
);
1223 return tvb_captured_length(tvb
);
1228 tvbuff_t
*data_tvb
= tvb_new_subset_length(tvb
, offset
, start_checksum_offset
- offset
);
1229 if (g_ascii_strcasecmp(sentence_id
, "DPT") == 0)
1231 offset
+= dissect_nmea0183_sentence_dpt(data_tvb
, pinfo
, nmea0183_tree
);
1233 else if (g_ascii_strcasecmp(sentence_id
, "GGA") == 0)
1235 offset
+= dissect_nmea0183_sentence_gga(data_tvb
, pinfo
, nmea0183_tree
);
1237 else if (g_ascii_strcasecmp(sentence_id
, "GLL") == 0)
1239 offset
+= dissect_nmea0183_sentence_gll(data_tvb
, pinfo
, nmea0183_tree
);
1241 else if (g_ascii_strcasecmp(sentence_id
, "GST") == 0)
1243 offset
+= dissect_nmea0183_sentence_gst(data_tvb
, pinfo
, nmea0183_tree
);
1245 else if (g_ascii_strcasecmp(sentence_id
, "HDT") == 0)
1247 offset
+= dissect_nmea0183_sentence_hdt(data_tvb
, pinfo
, nmea0183_tree
);
1249 else if (g_ascii_strcasecmp(sentence_id
, "ROT") == 0)
1251 offset
+= dissect_nmea0183_sentence_rot(data_tvb
, pinfo
, nmea0183_tree
);
1253 else if (g_ascii_strcasecmp(sentence_id
, "VBW") == 0)
1255 offset
+= dissect_nmea0183_sentence_vbw(data_tvb
, pinfo
, nmea0183_tree
);
1257 else if (g_ascii_strcasecmp(sentence_id
, "VHW") == 0)
1259 offset
+= dissect_nmea0183_sentence_vhw(data_tvb
, pinfo
, nmea0183_tree
);
1261 else if (g_ascii_strcasecmp(sentence_id
, "VLW") == 0)
1263 offset
+= dissect_nmea0183_sentence_vlw(data_tvb
, pinfo
, nmea0183_tree
);
1265 else if (g_ascii_strcasecmp(sentence_id
, "VTG") == 0)
1267 offset
+= dissect_nmea0183_sentence_vtg(data_tvb
, pinfo
, nmea0183_tree
);
1269 else if (g_ascii_strcasecmp(sentence_id
, "ZDA") == 0)
1271 offset
+= dissect_nmea0183_sentence_zda(data_tvb
, pinfo
, nmea0183_tree
);
1275 offset
+= dissect_nmea0183_sentence_unknown(data_tvb
, pinfo
, nmea0183_tree
);
1280 ti
= proto_tree_add_item_ret_string(nmea0183_tree
, hf_nmea0183_checksum
,
1281 tvb
, offset
, 2, ENC_ASCII
,
1282 pinfo
->pool
, &checksum
);
1284 uint8_t received_checksum
= (uint8_t)strtol(checksum
, NULL
, 16);
1285 uint8_t calculated_checksum
= calculate_checksum(tvb
, 1, offset
- 2);
1286 if (received_checksum
== calculated_checksum
)
1288 proto_item_append_text(ti
, " [correct]");
1292 proto_item_append_text(ti
, " [INCORRECT]");
1293 expert_add_info(pinfo
, ti
, &ei_nmea0183_checksum_incorrect
);
1296 // Calculated checksum highlights 2 bytes, which is the ascii hex value of a 1 byte checksum
1297 proto_item
*checksum_tree
= proto_item_add_subtree(ti
, ett_nmea0183_checksum
);
1298 ti
= proto_tree_add_uint(checksum_tree
, hf_nmea0183_checksum_calculated
,
1299 tvb
, offset
, 2, calculated_checksum
);
1300 proto_item_set_generated(ti
);
1305 if (tvb_captured_length_remaining(tvb
, offset
) < 2 ||
1306 tvb_get_uint8(tvb
, offset
) != '\r' ||
1307 tvb_get_uint8(tvb
, offset
+ 1) != '\n')
1309 expert_add_info(pinfo
, nmea0183_tree
, &ei_nmea0183_invalid_end_of_line
);
1313 /* Check sentence length */
1316 expert_add_info(pinfo
, nmea0183_tree
, &ei_nmea0183_sentence_too_long
);
1319 return tvb_captured_length(tvb
);
1322 void proto_register_nmea0183(void)
1324 expert_module_t
*expert_nmea0183
;
1326 static hf_register_info hf
[] = {
1327 {&hf_nmea0183_talker_id
,
1328 {"Talker ID", "nmea0183.talker",
1329 FT_STRING
, BASE_NONE
,
1332 {&hf_nmea0183_sentence_id
,
1333 {"Sentence ID", "nmea0183.sentence",
1334 FT_STRING
, BASE_NONE
,
1337 {&hf_nmea0183_unknown_field
,
1338 {"Field", "nmea0183.unknown_field",
1339 FT_STRING
, BASE_NONE
,
1341 "NMEA 0183 Unknown field", HFILL
}},
1342 {&hf_nmea0183_checksum
,
1343 {"Checksum", "nmea0183.checksum",
1344 FT_STRING
, BASE_NONE
,
1347 {&hf_nmea0183_checksum_calculated
,
1348 {"Calculated checksum", "nmea0183.checksum_calculated",
1352 {&hf_nmea0183_dpt_depth
,
1353 {"Water depth", "nmea0183.dpt_depth",
1354 FT_STRING
, BASE_NONE
,
1356 "NMEA 0183 DPT Water depth relative to transducer", HFILL
}},
1357 {&hf_nmea0183_dpt_offset
,
1358 {"Offset", "nmea0183.dpt_offset",
1359 FT_STRING
, BASE_NONE
,
1361 "NMEA 0183 DPT Offset from transducer, positive means distance from transducer to water line, negative means distance from transducer to keel", HFILL
}},
1362 {&hf_nmea0183_dpt_max_range
,
1363 {"Maximum range", "nmea0183.dpt_max_range",
1364 FT_STRING
, BASE_NONE
,
1366 "NMEA 0183 DPT Maximum range scale in use (NMEA 3.0 and above)", HFILL
}},
1367 {&hf_nmea0183_gga_time
,
1368 {"UTC Time of position", "nmea0183.gga_time",
1372 {&hf_nmea0183_gga_time_hour
,
1373 {"Hour", "nmea0183.gga_time_hour",
1374 FT_STRING
, BASE_NONE
,
1377 {&hf_nmea0183_gga_time_minute
,
1378 {"Minute", "nmea0183.gga_time_minute",
1379 FT_STRING
, BASE_NONE
,
1382 {&hf_nmea0183_gga_time_second
,
1383 {"Second", "nmea0183.gga_time_second",
1384 FT_STRING
, BASE_NONE
,
1387 {&hf_nmea0183_gga_latitude
,
1388 {"Latitude", "nmea0183.gga_latitude",
1392 {&hf_nmea0183_gga_latitude_degree
,
1393 {"Degree", "nmea0183.gga_latitude_degree",
1394 FT_STRING
, BASE_NONE
,
1397 {&hf_nmea0183_gga_latitude_minute
,
1398 {"Minute", "nmea0183.gga_latitude_minute",
1399 FT_STRING
, BASE_NONE
,
1402 {&hf_nmea0183_gga_latitude_direction
,
1403 {"Direction", "nmea0183.gga_latitude_direction",
1404 FT_STRING
, BASE_NONE
,
1407 {&hf_nmea0183_gga_longitude
,
1408 {"Longitude", "nmea0183.gga_longitude",
1412 {&hf_nmea0183_gga_longitude_degree
,
1413 {"Degree", "nmea0183.gga_longitude_degree",
1414 FT_STRING
, BASE_NONE
,
1417 {&hf_nmea0183_gga_longitude_minute
,
1418 {"Minute", "nmea0183.gga_longitude_minute",
1419 FT_STRING
, BASE_NONE
,
1422 {&hf_nmea0183_gga_longitude_direction
,
1423 {"Direction", "nmea0183.gga_longitude_direction",
1424 FT_STRING
, BASE_NONE
,
1427 {&hf_nmea0183_gga_quality
,
1428 {"Quality indicator", "nmea0183.gga_quality",
1429 FT_STRING
, BASE_NONE
,
1432 {&hf_nmea0183_gga_number_satellites
,
1433 {"Number of satellites", "nmea0183.gga_number_satellites",
1434 FT_STRING
, BASE_NONE
,
1436 "NMEA 0183 GGA Number of satellites in use", HFILL
}},
1437 {&hf_nmea0183_gga_horizontal_dilution
,
1438 {"Horizontal Dilution", "nmea0183.gga_horizontal_dilution",
1439 FT_STRING
, BASE_NONE
,
1441 "NMEA 0183 GGA Horizontal Dilution of precision", HFILL
}},
1442 {&hf_nmea0183_gga_altitude
,
1443 {"Altitude", "nmea0183.gga_altitude",
1444 FT_STRING
, BASE_NONE
,
1446 "NMEA 0183 GGA Antenna Altitude above mean-sea-level", HFILL
}},
1447 {&hf_nmea0183_gga_altitude_unit
,
1448 {"Altitude unit", "nmea0183.gga_altitude_unit",
1449 FT_STRING
, BASE_NONE
,
1451 "NMEA 0183 GGA Units of antenna altitude", HFILL
}},
1452 {&hf_nmea0183_gga_geoidal_separation
,
1453 {"Geoidal separation", "nmea0183.gga_geoidal_separation",
1454 FT_STRING
, BASE_NONE
,
1456 "NMEA 0183 GGA Geoidal separation, the difference between the WGS-84 earth ellipsoid and mean-sea-level", HFILL
}},
1457 {&hf_nmea0183_gga_geoidal_separation_unit
,
1458 {"Geoidal separation unit", "nmea0183.gga_geoidal_separation_unit",
1459 FT_STRING
, BASE_NONE
,
1461 "NMEA 0183 GGA Units of geoidal separation, meters", HFILL
}},
1462 {&hf_nmea0183_gga_age_dgps
,
1463 {"Age of differential GPS", "nmea0183.gga_age_dgps",
1464 FT_STRING
, BASE_NONE
,
1467 {&hf_nmea0183_gga_dgps_station
,
1468 {"Differential GPS station id", "nmea0183.gga_dgps_station",
1469 FT_STRING
, BASE_NONE
,
1471 "NMEA 0183 GGA Differential reference station ID", HFILL
}},
1472 {&hf_nmea0183_gll_latitude
,
1473 {"Latitude", "nmea0183.gll_latitude",
1477 {&hf_nmea0183_gll_latitude_degree
,
1478 {"Degree", "nmea0183.gll_latitude_degree",
1479 FT_STRING
, BASE_NONE
,
1482 {&hf_nmea0183_gll_latitude_minute
,
1483 {"Minute", "nmea0183.gll_latitude_minute",
1484 FT_STRING
, BASE_NONE
,
1487 {&hf_nmea0183_gll_latitude_direction
,
1488 {"Direction", "nmea0183.gll_latitude_direction",
1489 FT_STRING
, BASE_NONE
,
1492 {&hf_nmea0183_gll_longitude
,
1493 {"Longitude", "nmea0183.gll_longitude",
1497 {&hf_nmea0183_gll_longitude_degree
,
1498 {"Degree", "nmea0183.gll_longitude_degree",
1499 FT_STRING
, BASE_NONE
,
1502 {&hf_nmea0183_gll_longitude_minute
,
1503 {"Minute", "nmea0183.gll_longitude_minute",
1504 FT_STRING
, BASE_NONE
,
1507 {&hf_nmea0183_gll_longitude_direction
,
1508 {"Direction", "nmea0183.gll_longitude_direction",
1509 FT_STRING
, BASE_NONE
,
1512 {&hf_nmea0183_gll_time
,
1513 {"UTC Time of position", "nmea0183.gll_time",
1517 {&hf_nmea0183_gll_time_hour
,
1518 {"Hour", "nmea0183.gll_time_hour",
1519 FT_STRING
, BASE_NONE
,
1522 {&hf_nmea0183_gll_time_minute
,
1523 {"Minute", "nmea0183.gll_time_minute",
1524 FT_STRING
, BASE_NONE
,
1527 {&hf_nmea0183_gll_time_second
,
1528 {"Second", "nmea0183.gll_time_second",
1529 FT_STRING
, BASE_NONE
,
1532 {&hf_nmea0183_gll_status
,
1533 {"Status", "nmea0183.gll_status",
1534 FT_STRING
, BASE_NONE
,
1537 {&hf_nmea0183_gll_mode
,
1538 {"FAA mode", "nmea0183.gll_mode",
1539 FT_STRING
, BASE_NONE
,
1541 "NMEA 0183 GLL FAA mode indicator (NMEA 2.3 and later)", HFILL
}},
1542 {&hf_nmea0183_gst_time
,
1543 {"UTC Time of position", "nmea0183.gst_time",
1547 {&hf_nmea0183_gst_time_hour
,
1548 {"Hour", "nmea0183.gst_time_hour",
1549 FT_STRING
, BASE_NONE
,
1552 {&hf_nmea0183_gst_time_minute
,
1553 {"Minute", "nmea0183.gst_time_minute",
1554 FT_STRING
, BASE_NONE
,
1557 {&hf_nmea0183_gst_time_second
,
1558 {"Second", "nmea0183.gst_time_second",
1559 FT_STRING
, BASE_NONE
,
1562 {&hf_nmea0183_gst_rms_total_sd
,
1563 {"Total RMS standard deviation", "nmea0183.gst_sd_rms_total",
1564 FT_STRING
, BASE_NONE
,
1566 "NMEA 0183 GST Total RMS standard deviation of ranges inputs to the navigation solution", HFILL
}},
1567 {&hf_nmea0183_gst_ellipse_major_sd
,
1568 {"Standard deviation of semi-major axis of error", "nmea0183.gst_ellipse_major_sd",
1569 FT_STRING
, BASE_NONE
,
1572 {&hf_nmea0183_gst_ellipse_minor_sd
,
1573 {"Standard deviation of semi-minor axis of error ellipse", "nmea0183.gst_ellipse_minor_sd",
1574 FT_STRING
, BASE_NONE
,
1577 {&hf_nmea0183_gst_ellipse_orientation
,
1578 {"Orientation of semi-major axis of error ellipse", "nmea0183.gst_ellipse_orientation",
1579 FT_STRING
, BASE_NONE
,
1581 "NMEA 0183 GST Orientation of semi-major axis of error ellipse (true north degrees)", HFILL
}},
1582 {&hf_nmea0183_gst_latitude_sd
,
1583 {"Standard deviation of latitude error", "nmea0183.gst_sd_latitude",
1584 FT_STRING
, BASE_NONE
,
1587 {&hf_nmea0183_gst_longitude_sd
,
1588 {"Standard deviation of longitude error", "nmea0183.gst_sd_longitude",
1589 FT_STRING
, BASE_NONE
,
1592 {&hf_nmea0183_gst_altitude_sd
,
1593 {"Standard deviation of altitude error", "nmea0183.gst_sd_altitude",
1594 FT_STRING
, BASE_NONE
,
1597 {&hf_nmea0183_hdt_heading
,
1598 {"True heading", "nmea0183.hdt_heading",
1599 FT_STRING
, BASE_NONE
,
1602 {&hf_nmea0183_hdt_unit
,
1603 {"Heading unit", "nmea0183.hdt_unit",
1604 FT_STRING
, BASE_NONE
,
1606 "NMEA 0183 HDT Heading unit, must be T", HFILL
}},
1607 {&hf_nmea0183_rot_rate_of_turn
,
1608 {"Rate of turn", "nmea0183.rot_rate_of_turn",
1609 FT_STRING
, BASE_NONE
,
1611 "NMEA 0183 ROT Rate Of Turn, degrees per minute, negative value means bow turns to port", HFILL
}},
1612 {&hf_nmea0183_rot_valid
,
1613 {"Validity", "nmea0183.rot_valid",
1614 FT_STRING
, BASE_NONE
,
1616 "NMEA 0183 ROT Status, A means data is valid", HFILL
}},
1617 {&hf_nmea0183_vbw_water_speed_longitudinal
,
1618 {"Longitudinal water speed", "nmea0183.vbw_water_speed_longitudinal",
1619 FT_STRING
, BASE_NONE
,
1621 "NMEA 0183 VBW Longitudinal water speed, negative value means astern, knots", HFILL
}},
1622 {&hf_nmea0183_vbw_water_speed_transverse
,
1623 {"Transverse water speed", "nmea0183.vbw_water_speed_transverse",
1624 FT_STRING
, BASE_NONE
,
1626 "NMEA 0183 VBW Transverse water speed, negative value means port, knots", HFILL
}},
1627 {&hf_nmea0183_vbw_water_speed_valid
,
1628 {"Water speed validity", "nmea0183.vbw_water_speed_valid",
1629 FT_STRING
, BASE_NONE
,
1631 "NMEA 0183 VBW Water speed status, A means data is valid", HFILL
}},
1632 {&hf_nmea0183_vbw_ground_speed_longitudinal
,
1633 {"Longitudinal ground speed", "nmea0183.vbw_ground_speed_longitudinal",
1634 FT_STRING
, BASE_NONE
,
1636 "NMEA 0183 VBW Longitudinal ground speed, negative value means astern, knots", HFILL
}},
1637 {&hf_nmea0183_vbw_ground_speed_transverse
,
1638 {"Transverse ground speed", "nmea0183.vbw_ground_speed_transverse",
1639 FT_STRING
, BASE_NONE
,
1641 "NMEA 0183 VBW Transverse ground speed, negative value means port, knots", HFILL
}},
1642 {&hf_nmea0183_vbw_ground_speed_valid
,
1643 {"Ground speed validity", "nmea0183.vbw_ground_speed_valid",
1644 FT_STRING
, BASE_NONE
,
1646 "NMEA 0183 VBW Ground speed status, A means data is valid", HFILL
}},
1647 {&hf_nmea0183_vbw_stern_water_speed
,
1648 {"Stern water speed", "nmea0183.vbw_stern_water_speed",
1649 FT_STRING
, BASE_NONE
,
1651 "NMEA 0183 VBW Stern traverse water ground speed, negative value means port, knots", HFILL
}},
1652 {&hf_nmea0183_vbw_stern_water_speed_valid
,
1653 {"Stern water speed validity", "nmea0183.vbw_stern_water_speed_valid",
1654 FT_STRING
, BASE_NONE
,
1656 "NMEA 0183 VBW Stern traverse water speed status, A means data is valid", HFILL
}},
1657 {&hf_nmea0183_vbw_stern_ground_speed
,
1658 {"Stern ground speed", "nmea0183.vbw_stern_ground_speed",
1659 FT_STRING
, BASE_NONE
,
1661 "NMEA 0183 VBW Stern traverse ground ground speed, negative value means port, knots", HFILL
}},
1662 {&hf_nmea0183_vbw_stern_ground_speed_valid
,
1663 {"Stern ground speed validity", "nmea0183.vbw_stern_ground_speed_valid",
1664 FT_STRING
, BASE_NONE
,
1666 "NMEA 0183 VBW Stern traverse ground speed status, A means data is valid", HFILL
}},
1667 {&hf_nmea0183_vhw_true_heading
,
1668 {"True heading", "nmea0183.vhw_true_heading",
1669 FT_STRING
, BASE_NONE
,
1672 {&hf_nmea0183_vhw_true_heading_unit
,
1673 {"Heading unit", "nmea0183.vhw_true_heading_unit",
1674 FT_STRING
, BASE_NONE
,
1676 "NMEA 0183 VHW Heading unit, must be T", HFILL
}},
1677 {&hf_nmea0183_vhw_magnetic_heading
,
1678 {"Magnetic heading", "nmea0183.vhw_magnetic_heading",
1679 FT_STRING
, BASE_NONE
,
1682 {&hf_nmea0183_vhw_magnetic_heading_unit
,
1683 {"Heading unit", "nmea0183.vhw_magnetic_heading_unit",
1684 FT_STRING
, BASE_NONE
,
1686 "NMEA 0183 VHW Heading unit, must be M", HFILL
}},
1687 {&hf_nmea0183_vhw_water_speed_knot
,
1688 {"Water speed", "nmea0183.vhw_water_speed_knot",
1689 FT_STRING
, BASE_NONE
,
1692 {&hf_nmea0183_vhw_water_speed_knot_unit
,
1693 {"Speed unit", "nmea0183.vhw_water_speed_knot_unit",
1694 FT_STRING
, BASE_NONE
,
1696 "NMEA 0183 VHW Water speed unit, must be N", HFILL
}},
1697 {&hf_nmea0183_vhw_water_speed_kilometer
,
1698 {"Water speed", "nmea0183.vhw_water_speed_kilometer",
1699 FT_STRING
, BASE_NONE
,
1702 {&hf_nmea0183_vhw_water_speed_kilometer_unit
,
1703 {"Speed unit", "nmea0183.vhw_water_speed_kilometer_unit",
1704 FT_STRING
, BASE_NONE
,
1706 "NMEA 0183 VHW Water speed unit, must be K", HFILL
}},
1707 {&hf_nmea0183_vlw_cumulative_water
,
1708 {"Cumulative water distance", "nmea0183.vlw_hf_nmea0183_vlw_cumulative_water",
1709 FT_STRING
, BASE_NONE
,
1711 "NMEA 0183 VLW Total cumulative water distance, nautical miles", HFILL
}},
1712 {&hf_nmea0183_vlw_cumulative_water_unit
,
1713 {"Distance unit", "nmea0183.vlw_cumulative_water_unit",
1714 FT_STRING
, BASE_NONE
,
1716 "NMEA 0183 VLW Distance unit, must be N", HFILL
}},
1717 {&hf_nmea0183_vlw_trip_water
,
1718 {"Trip water distance", "nmea0183.vlw_hf_nmea0183_vlw_trip_water",
1719 FT_STRING
, BASE_NONE
,
1721 "NMEA 0183 VLW Water distance since Reset, nautical miles", HFILL
}},
1722 {&hf_nmea0183_vlw_trip_water_unit
,
1723 {"Distance unit", "nmea0183.vlw_trip_water_unit",
1724 FT_STRING
, BASE_NONE
,
1726 "NMEA 0183 VLW Distance unit, must be N", HFILL
}},
1727 {&hf_nmea0183_vlw_cumulative_ground
,
1728 {"Cumulative ground distance", "nmea0183.vlw_hf_nmea0183_vlw_cumulative_ground",
1729 FT_STRING
, BASE_NONE
,
1731 "NMEA 0183 VLW Total cumulative ground distance, nautical miles (NMEA 3 and above)", HFILL
}},
1732 {&hf_nmea0183_vlw_cumulative_ground_unit
,
1733 {"Distance unit", "nmea0183.vlw_cumulative_ground_unit",
1734 FT_STRING
, BASE_NONE
,
1736 "NMEA 0183 VLW Distance unit, must be N", HFILL
}},
1737 {&hf_nmea0183_vlw_trip_ground
,
1738 {"Trip ground distance", "nmea0183.vlw_hf_nmea0183_vlw_trip_ground",
1739 FT_STRING
, BASE_NONE
,
1741 "NMEA 0183 VLW Ground distance since Reset, nautical miles (NMEA 3 and above)", HFILL
}},
1742 {&hf_nmea0183_vlw_trip_ground_unit
,
1743 {"Distance unit", "nmea0183.vlw_trip_ground_unit",
1744 FT_STRING
, BASE_NONE
,
1746 "NMEA 0183 VLW Distance unit, must be N", HFILL
}},
1747 {&hf_nmea0183_vtg_true_course
,
1748 {"True course over ground", "nmea0183.vtg_true_course",
1749 FT_STRING
, BASE_NONE
,
1752 {&hf_nmea0183_vtg_true_course_unit
,
1753 {"Course unit", "nmea0183.vtg_true_course_unit",
1754 FT_STRING
, BASE_NONE
,
1756 "NMEA 0183 VTG Course unit, must be T", HFILL
}},
1757 {&hf_nmea0183_vtg_magnetic_course
,
1758 {"Magnetic course over ground", "nmea0183.vtg_magnetic_course",
1759 FT_STRING
, BASE_NONE
,
1762 {&hf_nmea0183_vtg_magnetic_course_unit
,
1763 {"Course unit", "nmea0183.vtg_magnetic_course_unit",
1764 FT_STRING
, BASE_NONE
,
1766 "NMEA 0183 VTG Course unit, must be M", HFILL
}},
1767 {&hf_nmea0183_vtg_ground_speed_knot
,
1768 {"Speed over ground", "nmea0183.vtg_ground_speed_knot",
1769 FT_STRING
, BASE_NONE
,
1772 {&hf_nmea0183_vtg_ground_speed_knot_unit
,
1773 {"Speed unit", "nmea0183.vtg_ground_speed_knot_unit",
1774 FT_STRING
, BASE_NONE
,
1776 "NMEA 0183 VTG Ground speed unit, must be N", HFILL
}},
1777 {&hf_nmea0183_vtg_ground_speed_kilometer
,
1778 {"Speed over ground", "nmea0183.vtg_ground_speed_kilometer",
1779 FT_STRING
, BASE_NONE
,
1782 {&hf_nmea0183_vtg_ground_speed_kilometer_unit
,
1783 {"Speed unit", "nmea0183.vtg_ground_speed_kilometer_unit",
1784 FT_STRING
, BASE_NONE
,
1786 "NMEA 0183 VTG Ground speed unit, must be K", HFILL
}},
1787 {&hf_nmea0183_vtg_mode
,
1788 {"FAA mode", "nmea0183.vtg_mode",
1789 FT_STRING
, BASE_NONE
,
1791 "NMEA 0183 VTG FAA mode indicator (NMEA 2.3 and later)", HFILL
}},
1792 {&hf_nmea0183_zda_time
,
1793 {"UTC Time", "nmea0183.zda_time",
1797 {&hf_nmea0183_zda_time_hour
,
1798 {"Hour", "nmea0183.zda_time_hour",
1799 FT_STRING
, BASE_NONE
,
1802 {&hf_nmea0183_zda_time_minute
,
1803 {"Minute", "nmea0183.zda_time_minute",
1804 FT_STRING
, BASE_NONE
,
1807 {&hf_nmea0183_zda_time_second
,
1808 {"Second", "nmea0183.zda_time_second",
1809 FT_STRING
, BASE_NONE
,
1812 {&hf_nmea0183_zda_date_day
,
1813 {"Day", "nmea0183.zda_date_day",
1814 FT_STRING
, BASE_NONE
,
1817 {&hf_nmea0183_zda_date_month
,
1818 {"Month", "nmea0183.zda_date_month",
1819 FT_STRING
, BASE_NONE
,
1822 {&hf_nmea0183_zda_date_year
,
1823 {"Year", "nmea0183.zda_date_year",
1824 FT_STRING
, BASE_NONE
,
1827 {&hf_nmea0183_zda_local_zone_hour
,
1828 {"Local zone hour", "nmea0183.zda_local_zone_hour",
1829 FT_STRING
, BASE_NONE
,
1832 {&hf_nmea0183_zda_local_zone_minute
,
1833 {"Local zone minute", "nmea0183.zda_local_zone_minute",
1834 FT_STRING
, BASE_NONE
,
1838 /* Setup protocol subtree array */
1839 static int *ett
[] = {
1841 &ett_nmea0183_checksum
,
1842 &ett_nmea0183_sentence
,
1843 &ett_nmea0183_zda_time
,
1844 &ett_nmea0183_gga_time
,
1845 &ett_nmea0183_gga_latitude
,
1846 &ett_nmea0183_gga_longitude
,
1847 &ett_nmea0183_gll_time
,
1848 &ett_nmea0183_gll_latitude
,
1849 &ett_nmea0183_gll_longitude
,
1850 &ett_nmea0183_gst_time
};
1852 static ei_register_info ei
[] = {
1853 {&ei_nmea0183_invalid_first_character
,
1854 {"nmea0183.invalid_first_character", PI_PROTOCOL
, PI_WARN
,
1855 "First character should be '$'", EXPFILL
}},
1856 {&ei_nmea0183_missing_checksum_character
,
1857 {"nmea0183.missing_checksum_character", PI_MALFORMED
, PI_ERROR
,
1858 "Missing begin of checksum character '*'", EXPFILL
}},
1859 {&ei_nmea0183_invalid_end_of_line
,
1860 {"nmea0183.invalid_end_of_line", PI_PROTOCOL
, PI_WARN
,
1861 "Sentence should end with <CR><LF>", EXPFILL
}},
1862 {&ei_nmea0183_checksum_incorrect
,
1863 {"nmea0183.checksum_incorrect", PI_CHECKSUM
, PI_WARN
,
1864 "Incorrect checksum", EXPFILL
}},
1865 {&ei_nmea0183_sentence_too_long
,
1866 {"nmea0183.sentence_too_long", PI_PROTOCOL
, PI_WARN
,
1867 "Sentence is too long. Maximum is 82 bytes including $ and <CR><LF>", EXPFILL
}},
1868 {&ei_nmea0183_field_time_too_short
,
1869 {"nmea0183.field_time_too_short", PI_PROTOCOL
, PI_WARN
,
1870 "Field containing time is too short. Field should be at least 6 characters", EXPFILL
}},
1871 {&ei_nmea0183_field_latitude_too_short
,
1872 {"nmea0183.field_latitude_too_short", PI_PROTOCOL
, PI_WARN
,
1873 "Field containing latitude is too short. Field should be at least 4 characters", EXPFILL
}},
1874 {&ei_nmea0183_field_longitude_too_short
,
1875 {"nmea0183.field_longitude_too_short", PI_PROTOCOL
, PI_WARN
,
1876 "Field containing longitude is too short. Field should be at least 5 characters", EXPFILL
}},
1877 {&ei_nmea0183_field_missing
,
1878 {"nmea0183.field_missing", PI_PROTOCOL
, PI_WARN
,
1879 "Field expected, but not found", EXPFILL
}},
1880 {&ei_nmea0183_gga_altitude_unit_incorrect
,
1881 {"nmea0183.gga_altitude_unit_incorrect", PI_PROTOCOL
, PI_WARN
,
1882 "Incorrect altitude unit (should be 'M')", EXPFILL
}},
1883 {&ei_nmea0183_gga_geoidal_separation_unit_incorrect
,
1884 {"nmea0183.gga_geoidal_separation_unit_incorrect", PI_PROTOCOL
, PI_WARN
,
1885 "Incorrect geoidal separation unit (should be 'M')", EXPFILL
}},
1886 {&ei_nmea0183_hdt_unit_incorrect
,
1887 {"nmea0183.hdt_unit_incorrect", PI_PROTOCOL
, PI_WARN
,
1888 "Incorrect heading unit (should be 'T')", EXPFILL
}},
1889 {&ei_nmea0183_vhw_true_heading_unit_incorrect
,
1890 {"nmea0183.vhw_true_heading_unit_incorrect", PI_PROTOCOL
, PI_WARN
,
1891 "Incorrect heading unit (should be 'T')", EXPFILL
}},
1892 {&ei_nmea0183_vhw_magnetic_heading_unit_incorrect
,
1893 {"nmea0183.vhw_magnetic_heading_unit_incorrect", PI_PROTOCOL
, PI_WARN
,
1894 "Incorrect heading unit (should be 'M')", EXPFILL
}},
1895 {&ei_nmea0183_vhw_water_speed_knot_unit_incorrect
,
1896 {"nmea0183.vhw_water_speed_knot_unit_incorrect", PI_PROTOCOL
, PI_WARN
,
1897 "Incorrect speed unit (should be 'N')", EXPFILL
}},
1898 {&ei_nmea0183_vhw_water_speed_kilometer_unit_incorrect
,
1899 {"nmea0183.vhw_water_speed_kilometer_unit_incorrect", PI_PROTOCOL
, PI_WARN
,
1900 "Incorrect speed unit (should be 'K')", EXPFILL
}},
1901 {&ei_nmea0183_vlw_cumulative_water_unit_incorrect
,
1902 {"nmea0183.vlw_cumulative_water_unit_incorrect", PI_PROTOCOL
, PI_WARN
,
1903 "Incorrect distance unit (should be 'N')", EXPFILL
}},
1904 {&ei_nmea0183_vlw_trip_water_unit_incorrect
,
1905 {"nmea0183.vlw_trip_water_unit_incorrect", PI_PROTOCOL
, PI_WARN
,
1906 "Incorrect distance unit (should be 'N')", EXPFILL
}},
1907 {&ei_nmea0183_vlw_cumulative_ground_unit_incorrect
,
1908 {"nmea0183.vlw_cumulative_ground_unit_incorrect", PI_PROTOCOL
, PI_WARN
,
1909 "Incorrect distance unit (should be 'N')", EXPFILL
}},
1910 {&ei_nmea0183_vlw_trip_ground_unit_incorrect
,
1911 {"nmea0183.vlw_trip_ground_unit_incorrect", PI_PROTOCOL
, PI_WARN
,
1912 "Incorrect distance unit (should be 'N')", EXPFILL
}},
1913 {&ei_nmea0183_vtg_true_course_unit_incorrect
,
1914 {"nmea0183.vtg_true_course_unit_incorrect", PI_PROTOCOL
, PI_WARN
,
1915 "Incorrect course unit (should be 'T')", EXPFILL
}},
1916 {&ei_nmea0183_vtg_magnetic_course_unit_incorrect
,
1917 {"nmea0183.vtg_magnetic_course_unit_incorrect", PI_PROTOCOL
, PI_WARN
,
1918 "Incorrect course unit (should be 'M')", EXPFILL
}},
1919 {&ei_nmea0183_vtg_ground_speed_knot_unit_incorrect
,
1920 {"nmea0183.vtg_ground_speed_knot_unit_incorrect", PI_PROTOCOL
, PI_WARN
,
1921 "Incorrect speed unit (should be 'N')", EXPFILL
}},
1922 {&ei_nmea0183_vtg_ground_speed_kilometer_unit_incorrect
,
1923 {"nmea0183.vtg_ground_speed_kilometer_unit_incorrect", PI_PROTOCOL
, PI_WARN
,
1924 "Incorrect speed unit (should be 'K')", EXPFILL
}}};
1926 proto_nmea0183
= proto_register_protocol("NMEA 0183 protocol", "NMEA 0183", "nmea0183");
1928 proto_register_field_array(proto_nmea0183
, hf
, array_length(hf
));
1929 proto_register_subtree_array(ett
, array_length(ett
));
1930 expert_nmea0183
= expert_register_protocol(proto_nmea0183
);
1931 expert_register_field_array(expert_nmea0183
, ei
, array_length(ei
));
1933 nmea0183_handle
= register_dissector("nmea0183", dissect_nmea0183
, proto_nmea0183
);
1936 void proto_reg_handoff_nmea0183(void)
1938 dissector_add_for_decode_as_with_preference("udp.port", nmea0183_handle
);