nmeadump: more NMEA sentences added.
[marnav.git] / src / nmeadump.cpp
blob4199b9f8795260fbe76342ad552112571af8cd8f
1 // This is a diagnostics tool and also serves as demonstration
2 // on how to use the library.
4 #include <fstream>
5 #include <iostream>
6 #include <vector>
8 #include <cxxopts/cxxopts.hpp>
10 #define FMT_HEADER_ONLY
11 #include <fmt/format.h>
13 #include <marnav/nmea/nmea.hpp>
14 #include <marnav/nmea/ais_helper.hpp>
15 #include <marnav/nmea/checksum.hpp>
16 #include <marnav/nmea/sentence.hpp>
17 #include <marnav/nmea/waypoint.hpp>
19 #include <marnav/nmea/aam.hpp>
20 #include <marnav/nmea/apb.hpp>
21 #include <marnav/nmea/bod.hpp>
22 #include <marnav/nmea/bwc.hpp>
23 #include <marnav/nmea/dbt.hpp>
24 #include <marnav/nmea/dtm.hpp>
25 #include <marnav/nmea/gga.hpp>
26 #include <marnav/nmea/gll.hpp>
27 #include <marnav/nmea/gsa.hpp>
28 #include <marnav/nmea/gsv.hpp>
29 #include <marnav/nmea/hdg.hpp>
30 #include <marnav/nmea/hdm.hpp>
31 #include <marnav/nmea/mtw.hpp>
32 #include <marnav/nmea/mwv.hpp>
33 #include <marnav/nmea/rmb.hpp>
34 #include <marnav/nmea/rmc.hpp>
35 #include <marnav/nmea/rte.hpp>
36 #include <marnav/nmea/vhw.hpp>
37 #include <marnav/nmea/vlw.hpp>
38 #include <marnav/nmea/vtg.hpp>
39 #include <marnav/nmea/vwr.hpp>
40 #include <marnav/nmea/zda.hpp>
41 #include <marnav/nmea/vdm.hpp>
42 #include <marnav/nmea/vdo.hpp>
44 #include <marnav/nmea/pgrme.hpp>
45 #include <marnav/nmea/pgrmm.hpp>
46 #include <marnav/nmea/pgrmz.hpp>
48 #include <marnav/ais/ais.hpp>
50 #include <marnav/ais/message_01.hpp>
51 #include <marnav/ais/message_02.hpp>
52 #include <marnav/ais/message_03.hpp>
53 #include <marnav/ais/message_04.hpp>
54 #include <marnav/ais/message_05.hpp>
55 #include <marnav/ais/message_11.hpp>
56 #include <marnav/ais/message_18.hpp>
57 #include <marnav/ais/message_21.hpp>
58 #include <marnav/ais/message_24.hpp>
60 #include <marnav/io/default_nmea_reader.hpp>
61 #include <marnav/io/serial.hpp>
63 #include <marnav/utils/unique.hpp>
65 namespace nmeadump
67 namespace terminal
69 static constexpr const char * normal = "\033[0m";
70 static constexpr const char * black = "\033[30m";
71 static constexpr const char * red = "\033[31m";
72 static constexpr const char * green = "\033[32m";
73 static constexpr const char * yellow = "\033[33m";
74 static constexpr const char * blue = "\033[34m";
75 static constexpr const char * magenta = "\033[35m";
76 static constexpr const char * cyan = "\033[36m";
77 static constexpr const char * white = "\033[37m";
80 namespace
82 template <class Container>
83 static bool contains(
84 const Container & container, const typename Container::value_type & element)
86 return std::find(std::begin(container), std::end(container), element)
87 != std::end(container);
91 static struct {
92 struct {
93 std::string port;
94 uint32_t port_speed = 0;
95 std::string file;
96 } config;
97 } global;
99 static bool parse_options(int argc, char ** argv)
101 // clang-format off
102 cxxopts::Options options{argv[0], "NMEA Dump"};
103 options.add_options()
104 ("h,help",
105 "Shows help information.")
106 ("p,port",
107 "Specifies the port to use.",
108 cxxopts::value<std::string>(global.config.port))
109 ("s,speed",
110 "Specifies the port speed. Valid values: 4800, 38400",
111 cxxopts::value<uint32_t>(global.config.port_speed))
112 ("f,file",
113 "Specifies the file to use.",
114 cxxopts::value<std::string>(global.config.file))
116 // clang-format on
118 options.parse(argc, argv);
120 if (options.count("help")) {
121 fmt::printf("%s\n", options.help());
122 fmt::printf("If no file or port is specified, stdin is used to read data from.\n\n");
123 return true;
126 // validation
128 static const std::vector<uint32_t> valid_port_speeds = {4800, 38400};
130 if (options.count("port") && options.count("file"))
131 throw std::runtime_error{"specifying port and file is illegal"};
132 if (options.count("port") && !contains(valid_port_speeds, global.config.port_speed))
133 throw std::runtime_error{"invalid port speed"};
135 return false;
138 static std::string trim(const std::string & s)
140 static const char * whitespace = "\n\r\t ";
141 const auto begin = s.find_first_not_of(whitespace);
142 const auto end = s.find_last_not_of(whitespace);
143 return begin != std::string::npos ? s.substr(begin, end - begin + 1) : "";
146 namespace detail
148 template <typename T> static std::string render(const T & t)
150 return marnav::nmea::to_string(t);
153 static std::string render(const std::string & t) { return t; }
155 static std::string render(bool t) { return t ? "true" : "false"; }
157 static std::string render(char t) { return fmt::sprintf("%c", t); }
159 static std::string render(const uint32_t t) { return fmt::sprintf("%u", t); }
161 static std::string render(const int32_t t) { return fmt::sprintf("%d", t); }
163 static std::string render(const int8_t t) { return fmt::sprintf("%d", t); }
165 static std::string render(const uint8_t t) { return fmt::sprintf("%u", t); }
167 static std::string render(const double t) { return fmt::sprintf("%-8.3f", t); }
169 static std::string render(const marnav::utils::mmsi & t)
171 return fmt::sprintf("%09u", static_cast<marnav::utils::mmsi::value_type>(t));
174 static std::string render(const marnav::nmea::time & t)
176 return fmt::sprintf("%02u:%02u:%02u", t.hour(), t.minutes(), t.seconds());
179 static std::string render(const marnav::geo::latitude & t)
181 using namespace marnav::nmea;
182 return fmt::sprintf(
183 " %02u\u00b0%02u'%04.1f%s", t.degrees(), t.minutes(), t.seconds(), to_string(t.hem()));
186 static std::string render(const marnav::geo::longitude & t)
188 using namespace marnav::nmea;
189 return fmt::sprintf(
190 "%03u\u00b0%02u'%04.1f%s", t.degrees(), t.minutes(), t.seconds(), to_string(t.hem()));
193 static std::string render(const marnav::ais::message_24::part t)
195 switch (t) {
196 case marnav::ais::message_24::part::A:
197 return "A";
198 case marnav::ais::message_24::part::B:
199 return "B";
201 return "-";
204 static std::string render(const marnav::ais::ship_type t)
206 switch (t) {
207 case marnav::ais::ship_type::not_available:
208 return "Not Available";
209 case marnav::ais::ship_type::wing_in_ground:
210 return "Wing in ground";
211 case marnav::ais::ship_type::wing_in_ground_hazardous_cat_a:
212 return "Wing in ground hazardous Cat A";
213 case marnav::ais::ship_type::wing_in_ground_hazardous_cat_b:
214 return "Wing in ground hazardous Cat B";
215 case marnav::ais::ship_type::wing_in_ground_hazardous_cat_c:
216 return "Wing in ground hazardous Cat C";
217 case marnav::ais::ship_type::wing_in_ground_hazardous_cat_d:
218 return "Wing in ground hazardous Cat D";
219 case marnav::ais::ship_type::fishing:
220 return "Fishing";
221 case marnav::ais::ship_type::towing:
222 return "Towing";
223 case marnav::ais::ship_type::towing_large:
224 return "Towing large";
225 case marnav::ais::ship_type::dredging_or_underwater_ops:
226 return "Dredging or underwater ops";
227 case marnav::ais::ship_type::diving_ops:
228 return "Diving ops";
229 case marnav::ais::ship_type::military_ops:
230 return "Military ops";
231 case marnav::ais::ship_type::sailing:
232 return "Sailing";
233 case marnav::ais::ship_type::pleasure_craft:
234 return "Pleasure Craft";
235 case marnav::ais::ship_type::high_speed_craft:
236 return "High speed craft";
237 case marnav::ais::ship_type::high_speed_craft_hazardous_cat_a:
238 return "High speed craft hazardous Cat A";
239 case marnav::ais::ship_type::high_speed_craft_hazardous_cat_b:
240 return "High speed craft hazardous Cat B";
241 case marnav::ais::ship_type::high_speed_craft_hazardous_cat_c:
242 return "High speed craft hazardous Cat C";
243 case marnav::ais::ship_type::high_speed_craft_hazardous_cat_d:
244 return "High speed craft hazardous Cat D";
245 case marnav::ais::ship_type::high_speed_craft_no_info:
246 return "High speed craft no_info";
247 case marnav::ais::ship_type::pilot_vessel:
248 return "Pilot Vessel";
249 case marnav::ais::ship_type::search_and_rescue_vessel:
250 return "Search and Rescue Vessel";
251 case marnav::ais::ship_type::tug:
252 return "Tug";
253 case marnav::ais::ship_type::port_tender:
254 return "Port Tender";
255 case marnav::ais::ship_type::anti_pollution_equipment:
256 return "Anti Pollution Equipment";
257 case marnav::ais::ship_type::law_enforcement:
258 return "Law Enforcement";
259 case marnav::ais::ship_type::medical_transport:
260 return "Medical Transport";
261 case marnav::ais::ship_type::noncombatant:
262 return "Noncombatant";
263 case marnav::ais::ship_type::passenger:
264 return "Passenger";
265 case marnav::ais::ship_type::passenger_hazardous_cat_a:
266 return "Passenger hazardous Cat A";
267 case marnav::ais::ship_type::passenger_hazardous_cat_b:
268 return "Passenger hazardous Cat B";
269 case marnav::ais::ship_type::passenger_hazardous_cat_c:
270 return "Passenger hazardous Cat C";
271 case marnav::ais::ship_type::passenger_hazardous_cat_d:
272 return "Passenger hazardous Cat D";
273 case marnav::ais::ship_type::passenger_no_info:
274 return "Passenger no info";
275 case marnav::ais::ship_type::cargo:
276 return "Cargo";
277 case marnav::ais::ship_type::cargo_hazardous_cat_a:
278 return "Cargo hazardous Cat A";
279 case marnav::ais::ship_type::cargo_hazardous_cat_b:
280 return "Cargo hazardous Cat B";
281 case marnav::ais::ship_type::cargo_hazardous_cat_c:
282 return "Cargo hazardous Cat C";
283 case marnav::ais::ship_type::cargo_hazardous_cat_d:
284 return "Cargo hazardous Cat D";
285 case marnav::ais::ship_type::cargo_no_info:
286 return "Cargo no info";
287 case marnav::ais::ship_type::tanker:
288 return "Tanker";
289 case marnav::ais::ship_type::tanker_hazardous_cat_a:
290 return "Tanker hazardous Cat A";
291 case marnav::ais::ship_type::tanker_hazardous_cat_b:
292 return "Tanker hazardous Cat B";
293 case marnav::ais::ship_type::tanker_hazardous_cat_c:
294 return "Tanker hazardous Cat C";
295 case marnav::ais::ship_type::tanker_hazardous_cat_d:
296 return "Tanker hazardous Cat D";
297 case marnav::ais::ship_type::tanker_no_info:
298 return "Tanker no info";
299 case marnav::ais::ship_type::other:
300 return "Other";
301 case marnav::ais::ship_type::other_hazardous_cat_a:
302 return "Other hazardous Cat A";
303 case marnav::ais::ship_type::other_hazardous_cat_b:
304 return "Other hazardous Cat B";
305 case marnav::ais::ship_type::other_hazardous_cat_c:
306 return "Other hazardous Cat C";
307 case marnav::ais::ship_type::other_hazardous_cat_d:
308 return "Other hazardous Cat D";
309 case marnav::ais::ship_type::other_no_info:
310 return "Other no info";
312 return "-";
315 static std::string render(const marnav::ais::epfd_fix_type t)
317 switch (t) {
318 case marnav::ais::epfd_fix_type::undefined:
319 return "undefined";
320 case marnav::ais::epfd_fix_type::gps:
321 return "GPS";
322 case marnav::ais::epfd_fix_type::glonass:
323 return "GLONASS";
324 case marnav::ais::epfd_fix_type::combined_gps_glonass:
325 return "Combined GPS GLONASS";
326 case marnav::ais::epfd_fix_type::loran_c:
327 return "Loran C";
328 case marnav::ais::epfd_fix_type::chayka:
329 return "Chayka";
330 case marnav::ais::epfd_fix_type::integrated_navigation_system:
331 return "Integrated Navigation System";
332 case marnav::ais::epfd_fix_type::surveyed:
333 return "surveyed";
334 case marnav::ais::epfd_fix_type::galileo:
335 return "Galileo";
337 return "-";
340 static std::string render(const marnav::ais::message_21::off_position_indicator t)
342 switch (t) {
343 case marnav::ais::message_21::off_position_indicator::on_position:
344 return "On Position";
345 case marnav::ais::message_21::off_position_indicator::off_position:
346 return "Off Position";
348 return "-";
351 static std::string render(const marnav::ais::message_21::virtual_aid t)
353 switch (t) {
354 case marnav::ais::message_21::virtual_aid::real_aid:
355 return "Real Aid";
356 case marnav::ais::message_21::virtual_aid::virtual_aid:
357 return "Virtual Aid";
359 return "-";
362 static std::string render(const marnav::ais::message_21::aid_type_id t)
364 switch (t) {
365 case marnav::ais::message_21::aid_type_id::unspecified:
366 return "unspecified";
367 case marnav::ais::message_21::aid_type_id::reference_point:
368 return "Reference point";
369 case marnav::ais::message_21::aid_type_id::racon:
370 return "RACON (radar transponder marking a navigation hazard)";
371 case marnav::ais::message_21::aid_type_id::fixed_structure:
372 return "Fixed structure";
373 case marnav::ais::message_21::aid_type_id::reserved:
374 return "Spare, Reserved for future use";
375 case marnav::ais::message_21::aid_type_id::light_no_sectors:
376 return "Light, without sectors";
377 case marnav::ais::message_21::aid_type_id::light_sectors:
378 return "Light, with sectors";
379 case marnav::ais::message_21::aid_type_id::leading_light_fromt:
380 return "Leading Light Front";
381 case marnav::ais::message_21::aid_type_id::leading_light_rear:
382 return "Leading Light Rear";
383 case marnav::ais::message_21::aid_type_id::beacon_cardinal_n:
384 return "Beacon, Cardinal N";
385 case marnav::ais::message_21::aid_type_id::beacon_cardinal_e:
386 return "Beacon, Cardinal E";
387 case marnav::ais::message_21::aid_type_id::beacon_cardinal_s:
388 return "Beacon, Cardinal S";
389 case marnav::ais::message_21::aid_type_id::beacon_cardinal_w:
390 return "Beacon, Cardinal W";
391 case marnav::ais::message_21::aid_type_id::beacon_port_hand:
392 return "Beacon, Port hand";
393 case marnav::ais::message_21::aid_type_id::beacon_starboard_hand:
394 return "Beacon, Starboard hand";
395 case marnav::ais::message_21::aid_type_id::beacon_preferred_channel_port_hand:
396 return "Beacon, Preferred Channel port hand";
397 case marnav::ais::message_21::aid_type_id::beacon_preferred_channel_starboard_hand:
398 return "Beacon, Preferred Channel starboard hand";
399 case marnav::ais::message_21::aid_type_id::beacon_isolated_danger:
400 return "Beacon, Isolated danger";
401 case marnav::ais::message_21::aid_type_id::beacon_safe_water:
402 return "Beacon, Safe water";
403 case marnav::ais::message_21::aid_type_id::beacon_sepcial_mark:
404 return "Beacon, Special mark";
405 case marnav::ais::message_21::aid_type_id::cardinal_n:
406 return "Cardinal Mark N";
407 case marnav::ais::message_21::aid_type_id::cardinal_e:
408 return "Cardinal Mark E";
409 case marnav::ais::message_21::aid_type_id::cardinal_s:
410 return "Cardinal Mark S";
411 case marnav::ais::message_21::aid_type_id::cardinal_w:
412 return "Cardinal Mark W";
413 case marnav::ais::message_21::aid_type_id::mark_port_hand:
414 return "Port hand Mark";
415 case marnav::ais::message_21::aid_type_id::mark_starboard_hand:
416 return "Starboard hand Mark";
417 case marnav::ais::message_21::aid_type_id::preferred_channel_port_hand:
418 return "Preferred Channel Port hand";
419 case marnav::ais::message_21::aid_type_id::preferred_channel_starboard_hand:
420 return "Preferred Channel Starboard hand";
421 case marnav::ais::message_21::aid_type_id::isolated_danger:
422 return "Isolated danger";
423 case marnav::ais::message_21::aid_type_id::safe_water:
424 return "Safe Water";
425 case marnav::ais::message_21::aid_type_id::special_mark:
426 return "Special Mark";
427 case marnav::ais::message_21::aid_type_id::light_vessel:
428 return "Light Vessel / LANBY / Rigs";
430 return "-";
433 static std::string render(const marnav::ais::message_id t)
435 switch (t) {
436 case marnav::ais::message_id::NONE:
437 return "<none>";
438 case marnav::ais::message_id::position_report_class_a:
439 return "Position Report Class A";
440 case marnav::ais::message_id::position_report_class_a_assigned_schedule:
441 return "Position Report Class A - Assigned Schedule";
442 case marnav::ais::message_id::position_report_class_a_response_to_interrogation:
443 return "Position Report Class A - Response to Interrogation";
444 case marnav::ais::message_id::base_station_report:
445 return "Base Station Report";
446 case marnav::ais::message_id::static_and_voyage_related_data:
447 return "Static and Voyage related Data";
448 case marnav::ais::message_id::binary_addressed_message:
449 return "Binary Addressed Message";
450 case marnav::ais::message_id::binary_acknowledge:
451 return "Binary Acknowledge";
452 case marnav::ais::message_id::binary_broadcast_message:
453 return "Binary Broadcast Message";
454 case marnav::ais::message_id::standard_sar_aircraft_position_report:
455 return "Standard SAR Aircraft Position Report";
456 case marnav::ais::message_id::utc_and_date_inquiry:
457 return "UTC and Date Inquiry";
458 case marnav::ais::message_id::utc_and_date_response:
459 return "UTC and Date Response";
460 case marnav::ais::message_id::addressed_safety_related_message:
461 return "Addresed Safety related Message";
462 case marnav::ais::message_id::safety_related_acknowledgement_:
463 return "Safety related Acknowledgement";
464 case marnav::ais::message_id::safety_related_broadcast_message:
465 return "Safety related Broadcast Message";
466 case marnav::ais::message_id::interrogation:
467 return "Interrogation";
468 case marnav::ais::message_id::assignment_mode_command:
469 return "Assignment Mode Command";
470 case marnav::ais::message_id::dgnss_binary_broadcast_message:
471 return "DGNSS Binary Broadcast Message";
472 case marnav::ais::message_id::standard_class_b_cs_position_report:
473 return "Standard Class B CS Position Report";
474 case marnav::ais::message_id::extended_class_b_equipment_position_report:
475 return "Extended Class B Equipment Position Report";
476 case marnav::ais::message_id::data_link_management:
477 return "Data Link Management";
478 case marnav::ais::message_id::aid_to_navigation_report:
479 return "Aid to Navigation Report";
480 case marnav::ais::message_id::channel_management:
481 return "Channel Management";
482 case marnav::ais::message_id::group_assignment_command:
483 return "Group Assignment Command";
484 case marnav::ais::message_id::static_data_report:
485 return "Static Data Report";
486 case marnav::ais::message_id::single_slot_binary_message:
487 return "Single Slot Binary Message";
488 case marnav::ais::message_id::multiple_slot_binary_message_with_communications_state:
489 return "Multiple slot Binary Message with Communication State";
490 case marnav::ais::message_id::position_report_for_long_range_applications:
491 return "Position Report for long range Applications";
493 return "-";
496 static std::string render(const marnav::nmea::sentence_id t)
498 switch (t) {
499 case marnav::nmea::sentence_id::NONE:
500 return "<none>";
501 case marnav::nmea::sentence_id::AAM:
502 return "Waypoint Arrival Alarm";
503 case marnav::nmea::sentence_id::ALM:
504 return "GPS Almanac Data";
505 case marnav::nmea::sentence_id::APB:
506 return "Autopilot Sentence 'B'";
507 case marnav::nmea::sentence_id::BOD:
508 return "Bearing - Waypoint to Waypoint";
509 case marnav::nmea::sentence_id::BWC:
510 return "Bearing & Distance to Waypoint - Geat Circle";
511 case marnav::nmea::sentence_id::BWR:
512 return "Bearing and Distance to Waypoint - Rhumb Line";
513 case marnav::nmea::sentence_id::BWW:
514 return "Bearing - Waypoint to Waypoint";
515 case marnav::nmea::sentence_id::DBT:
516 return "Depth below transducer (II)";
517 case marnav::nmea::sentence_id::DPT:
518 return "Depth of Water";
519 case marnav::nmea::sentence_id::DSC:
520 return "Digital Selective Calling Information";
521 case marnav::nmea::sentence_id::DSE:
522 return "Extended DSC";
523 case marnav::nmea::sentence_id::DSI:
524 return "DSC Transponder Initiate";
525 case marnav::nmea::sentence_id::DSR:
526 return "DSC Transponder Response";
527 case marnav::nmea::sentence_id::DTM:
528 return "Datum Reference";
529 case marnav::nmea::sentence_id::FSI:
530 return "Frequency Set Information";
531 case marnav::nmea::sentence_id::GBS:
532 return "GPS Satellite Fault Detection";
533 case marnav::nmea::sentence_id::GGA:
534 return "Global Positioning System Fix Data";
535 case marnav::nmea::sentence_id::GLC:
536 return "Geographic Position, Loran-C";
537 case marnav::nmea::sentence_id::GLL:
538 return "Geographic Position - Latitude/Longitude";
539 case marnav::nmea::sentence_id::GNS:
540 return "Fix data";
541 case marnav::nmea::sentence_id::GRS:
542 return "GPS Range Residuals";
543 case marnav::nmea::sentence_id::GST:
544 return "GPS Pseudorange Noise Statistics";
545 case marnav::nmea::sentence_id::GSA:
546 return "GPS DOP and active satellites";
547 case marnav::nmea::sentence_id::GSV:
548 return "Satellites in view";
549 case marnav::nmea::sentence_id::HDG:
550 return "Heading - Deviation & Variation (vendor extension)";
551 case marnav::nmea::sentence_id::HFB:
552 return "Trawl Headrope to Footrope and Bottom";
553 case marnav::nmea::sentence_id::HSC:
554 return "Heading Steering Command";
555 case marnav::nmea::sentence_id::ITS:
556 return "Trawl Door Spread 2 Distance";
557 case marnav::nmea::sentence_id::LCD:
558 return "Loran-C Signal Data";
559 case marnav::nmea::sentence_id::MSK:
560 return "Control for a Beacon Receiver";
561 case marnav::nmea::sentence_id::MSS:
562 return "Beacon Receiver Status";
563 case marnav::nmea::sentence_id::MWD:
564 return "Wind Directinon and Speed";
565 case marnav::nmea::sentence_id::MTW:
566 return "Mean Temperature of Water (II)";
567 case marnav::nmea::sentence_id::MWV:
568 return "Wind Speed and Angle (II)";
569 case marnav::nmea::sentence_id::OSD:
570 return "Own Ship Data";
571 case marnav::nmea::sentence_id::RMA:
572 return "Recommended Minimum Navigation Information A";
573 case marnav::nmea::sentence_id::RMB:
574 return "Recommended Minimum Navigation Information B";
575 case marnav::nmea::sentence_id::RMC:
576 return "Recommended Minimum Navigation Information C";
577 case marnav::nmea::sentence_id::ROT:
578 return "Rate Of Turn";
579 case marnav::nmea::sentence_id::RPM:
580 return "Revolutions";
581 case marnav::nmea::sentence_id::RSA:
582 return "Rudder Sensor Angle";
583 case marnav::nmea::sentence_id::RSD:
584 return "RADAR System Data";
585 case marnav::nmea::sentence_id::RTE:
586 return "Routes";
587 case marnav::nmea::sentence_id::SFI:
588 return "Scanning Frequency Information";
589 case marnav::nmea::sentence_id::STN:
590 return "Multiple Data ID";
591 case marnav::nmea::sentence_id::TDS:
592 return "Trawl Door Spread Distance";
593 case marnav::nmea::sentence_id::TFI:
594 return "Trawl Filling Indicator";
595 case marnav::nmea::sentence_id::TPC:
596 return "Trawl Position Cartesian Coordinates";
597 case marnav::nmea::sentence_id::TPR:
598 return "Trawl Position Relative Vessel";
599 case marnav::nmea::sentence_id::TPT:
600 return "Trawl Position True";
601 case marnav::nmea::sentence_id::TRF:
602 return "TRANSIT Fix Data";
603 case marnav::nmea::sentence_id::TLL:
604 return "Target latitude and longitude";
605 case marnav::nmea::sentence_id::TTM:
606 return "Tracked Target Message";
607 case marnav::nmea::sentence_id::VBW:
608 return "Dual Ground/Water Speed";
609 case marnav::nmea::sentence_id::VDM:
610 return "AIS";
611 case marnav::nmea::sentence_id::VDO:
612 return "AIS, own ship data";
613 case marnav::nmea::sentence_id::VDR:
614 return "Set and Drift";
615 case marnav::nmea::sentence_id::VHW:
616 return "Water speed and heading (II)";
617 case marnav::nmea::sentence_id::VLW:
618 return "Distance Traveled through Water (II)";
619 case marnav::nmea::sentence_id::VPW:
620 return "Speed - Measured Parallel to Wind";
621 case marnav::nmea::sentence_id::VTG:
622 return "Track made good and Ground speed";
623 case marnav::nmea::sentence_id::VWR:
624 return "Relative Wind Speed and Angle (II)";
625 case marnav::nmea::sentence_id::WCV:
626 return "Waypoint Closure Velocity";
627 case marnav::nmea::sentence_id::WNC:
628 return "Distance - Waypoint to Waypoint";
629 case marnav::nmea::sentence_id::WPL:
630 return "Waypoint Location";
631 case marnav::nmea::sentence_id::XDR:
632 return "Transducer Measurement";
633 case marnav::nmea::sentence_id::XTE:
634 return "Cross-Track Error, Measured";
635 case marnav::nmea::sentence_id::XTR:
636 return "Cross Track Error - Dead Reckoning";
637 case marnav::nmea::sentence_id::ZDA:
638 return "Time & Date - UTC, day, month, year and local time zone";
639 case marnav::nmea::sentence_id::ZDL:
640 return "Time and Distance to Variable Point";
641 case marnav::nmea::sentence_id::ZFO:
642 return "UTC & Time from origin Waypoint";
643 case marnav::nmea::sentence_id::ZTG:
644 return "UTC & Time to Destination Waypoint";
645 case marnav::nmea::sentence_id::APA:
646 return "Autopilot Sentence 'A'";
647 case marnav::nmea::sentence_id::BER:
648 return "Bearing & Distance to Waypoint, Dead Reckoning, Rhumb Line";
649 case marnav::nmea::sentence_id::BPI:
650 return "Bearing & Distance to Point of Interest";
651 case marnav::nmea::sentence_id::DBK:
652 return "Depth Below Keel";
653 case marnav::nmea::sentence_id::DBS:
654 return "Depth Below Surface";
655 case marnav::nmea::sentence_id::DCN:
656 return "Decca Position";
657 case marnav::nmea::sentence_id::DRU:
658 return "Dual Doppler Auxiliary Data";
659 case marnav::nmea::sentence_id::GDA:
660 return "Dead Reckoning Positions";
661 case marnav::nmea::sentence_id::GLA:
662 return "Loran-C Positions";
663 case marnav::nmea::sentence_id::GOA:
664 return "OMEGA Positions";
665 case marnav::nmea::sentence_id::GTD:
666 return "Geographical Position, Loran-C TDs";
667 case marnav::nmea::sentence_id::GXA:
668 return "TRANSIT Position";
669 case marnav::nmea::sentence_id::HCC:
670 return "Compass Heading";
671 case marnav::nmea::sentence_id::HCD:
672 return "Heading and Deviation";
673 case marnav::nmea::sentence_id::HDM:
674 return "Heading, Magnetic";
675 case marnav::nmea::sentence_id::HDT:
676 return "Heading, True";
677 case marnav::nmea::sentence_id::HVD:
678 return "Magnetic Variation, Automatic";
679 case marnav::nmea::sentence_id::HVM:
680 return "Magnetic Variation, Manually Set";
681 case marnav::nmea::sentence_id::IMA:
682 return "Vessel Identification";
683 case marnav::nmea::sentence_id::MDA:
684 return "Meteorological Composite";
685 case marnav::nmea::sentence_id::MHU:
686 return "Humidity";
687 case marnav::nmea::sentence_id::MMB:
688 return "Barometer";
689 case marnav::nmea::sentence_id::MTA:
690 return "Air Temperature";
691 case marnav::nmea::sentence_id::MWH:
692 return "Wave Height";
693 case marnav::nmea::sentence_id::MWS:
694 return "Wind & Sea State";
695 case marnav::nmea::sentence_id::OLN:
696 return "Omega Lane Numbers";
697 case marnav::nmea::sentence_id::R00:
698 return "(Rnn) Waypoints in active route";
699 case marnav::nmea::sentence_id::SBK:
700 return "Loran-C Blink Status";
701 case marnav::nmea::sentence_id::SCY:
702 return "Loran-C Cycle Lock Status";
703 case marnav::nmea::sentence_id::SCD:
704 return "Loran-C ECDs";
705 case marnav::nmea::sentence_id::SDB:
706 return "Loran-C Signal Strength";
707 case marnav::nmea::sentence_id::SGD:
708 return "Position Accuracy Estimate";
709 case marnav::nmea::sentence_id::SGR:
710 return "Loran-C Chain Identifier";
711 case marnav::nmea::sentence_id::SIU:
712 return "Loran-C Stations in Use";
713 case marnav::nmea::sentence_id::SLC:
714 return "Loran-C Status";
715 case marnav::nmea::sentence_id::SNC:
716 return "Navigation Calculation Basis";
717 case marnav::nmea::sentence_id::SNU:
718 return "Loran-C SNR Status";
719 case marnav::nmea::sentence_id::SPS:
720 return "Loran-C Predicted Signal Strength";
721 case marnav::nmea::sentence_id::SSF:
722 return "Position Correction Offset";
723 case marnav::nmea::sentence_id::STC:
724 return "Time Constant";
725 case marnav::nmea::sentence_id::STR:
726 return "Tracking Reference";
727 case marnav::nmea::sentence_id::SYS:
728 return "Hybrid System Configuration";
729 case marnav::nmea::sentence_id::VWT:
730 return "True Wind Speed and Angle";
731 case marnav::nmea::sentence_id::PGRME:
732 return "Estimated Error Information (Garmin Extension)";
733 case marnav::nmea::sentence_id::PGRMM:
734 return "Map Datum (Garmin Extension)";
735 case marnav::nmea::sentence_id::PGRMZ:
736 return "Altitude (Garmin Extension)";
737 case marnav::nmea::sentence_id::PMGNST:
738 return "Magellan Status";
739 case marnav::nmea::sentence_id::PRWIZCH:
740 return "Rockwell Channel Status";
741 case marnav::nmea::sentence_id::PUBX:
742 return "u-blox (misc formats, depending on first field)";
743 case marnav::nmea::sentence_id::TMVTD:
744 return "Transas VTS / SML tracking system report";
746 return "-";
749 static std::string render(const marnav::nmea::unit::distance t)
751 switch (t) {
752 case marnav::nmea::unit::distance::meter:
753 return "m";
754 case marnav::nmea::unit::distance::feet:
755 return "ft";
756 case marnav::nmea::unit::distance::nm:
757 return "nm";
758 case marnav::nmea::unit::distance::km:
759 return "km";
760 case marnav::nmea::unit::distance::fathom:
761 return "fathom";
763 return "-";
766 static std::string render(const marnav::nmea::unit::temperature t)
768 switch (t) {
769 case marnav::nmea::unit::temperature::celsius:
770 return "\u00b0C";
772 return "-";
775 static std::string render(const marnav::nmea::unit::velocity t)
777 switch (t) {
778 case marnav::nmea::unit::velocity::knot:
779 return "kn";
780 case marnav::nmea::unit::velocity::kmh:
781 return "km/h";
782 case marnav::nmea::unit::velocity::mps:
783 return "m/s";
785 return "-";
788 static std::string render(const marnav::nmea::side t)
790 switch (t) {
791 case marnav::nmea::side::left:
792 return "Left";
793 case marnav::nmea::side::right:
794 return "Rigth";
796 return "-";
799 static std::string render(const marnav::nmea::reference t)
801 switch (t) {
802 case marnav::nmea::reference::RELATIVE:
803 return "relative";
804 case marnav::nmea::reference::TRUE:
805 return "true";
806 case marnav::nmea::reference::MAGNETIC:
807 return "magnetic";
809 return "-";
812 static std::string render(const marnav::nmea::quality t)
814 switch (t) {
815 case marnav::nmea::quality::invalid:
816 return "invaild";
817 case marnav::nmea::quality::gps_fix:
818 return "GPS fix";
819 case marnav::nmea::quality::dgps_fix:
820 return "DGPS fix";
821 case marnav::nmea::quality::guess:
822 return "guess";
823 case marnav::nmea::quality::simulation:
824 return "simulation";
826 return "-";
829 static std::string render(const marnav::nmea::direction t)
831 switch (t) {
832 case marnav::nmea::direction::north:
833 return "N";
834 case marnav::nmea::direction::south:
835 return "S";
836 case marnav::nmea::direction::west:
837 return "W";
838 case marnav::nmea::direction::east:
839 return "E";
840 case marnav::nmea::direction::none:
841 return "<none>";
843 return "-";
846 static std::string render(const marnav::nmea::selection_mode t)
848 switch (t) {
849 case marnav::nmea::selection_mode::manual:
850 return "manual";
851 case marnav::nmea::selection_mode::automatic:
852 return "automatic";
854 return "-";
857 static std::string render(const marnav::nmea::status t)
859 switch (t) {
860 case marnav::nmea::status::ok:
861 return "OK";
862 case marnav::nmea::status::warning:
863 return "Warning";
865 return "-";
868 static std::string render(const marnav::nmea::route t)
870 switch (t) {
871 case marnav::nmea::route::complete:
872 return "complete";
873 case marnav::nmea::route::working:
874 return "working";
876 return "-";
879 static std::string render(const marnav::nmea::waypoint & t) { return t.c_str(); }
881 static std::string render(const marnav::nmea::mode_indicator t)
883 switch (t) {
884 case marnav::nmea::mode_indicator::invalid:
885 return "invalid";
886 case marnav::nmea::mode_indicator::autonomous:
887 return "autonomous";
888 case marnav::nmea::mode_indicator::differential:
889 return "differential";
890 case marnav::nmea::mode_indicator::estimated:
891 return "estimated";
892 case marnav::nmea::mode_indicator::manual_input:
893 return "manual input";
894 case marnav::nmea::mode_indicator::simulated:
895 return "simulated";
896 case marnav::nmea::mode_indicator::data_not_valid:
897 return "not valid";
898 case marnav::nmea::mode_indicator::precise:
899 return "precise";
901 return "-";
904 template <typename T> static std::string render(const marnav::utils::optional<T> & t)
906 if (!t)
907 return "-";
908 return render(*t);
911 static void print(const std::string & name, const std::string & value)
913 fmt::printf("\t%-30s : %s\n", name, value);
916 static void print_detail_hdg(const marnav::nmea::sentence * s)
918 const auto t = marnav::nmea::sentence_cast<marnav::nmea::hdg>(s);
919 print("Heading", render(t->get_heading()));
920 print("Magn Deviation",
921 fmt::sprintf("%s %s", render(t->get_magn_dev()), render(t->get_magn_dev_hem())));
922 print("Magn Variation",
923 fmt::sprintf("%s %s", render(t->get_magn_var()), render(t->get_magn_var_hem())));
926 static void print_detail_hdm(const marnav::nmea::sentence * s)
928 const auto t = marnav::nmea::sentence_cast<marnav::nmea::hdm>(s);
929 print("Heading", render(t->get_heading()));
932 static void print_detail_rmb(const marnav::nmea::sentence * s)
934 const auto t = marnav::nmea::sentence_cast<marnav::nmea::rmb>(s);
935 print("Active", render(t->get_active()));
936 print("Cross Track Error", render(t->get_cross_track_error()));
937 print("Waypoint To", render(t->get_waypoint_to()));
938 print("Waypoint From", render(t->get_waypoint_from()));
939 print("Latitude", render(t->get_latitude()));
940 print("Longitude", render(t->get_longitude()));
941 print("Range", render(t->get_range()));
942 print("Bearing", render(t->get_bearing()));
943 print("Dest. Velocity", render(t->get_dst_velocity()));
944 print("Arrival Status", render(t->get_arrival_status()));
945 print("Mode Indicator", render(t->get_mode_ind()));
948 static void print_detail_rmc(const marnav::nmea::sentence * s)
950 const auto t = marnav::nmea::sentence_cast<marnav::nmea::rmc>(s);
951 print("Time UTC", render(t->get_time_utc()));
952 print("Status", render(t->get_status()));
953 print("Latitude", render(t->get_latitude()));
954 print("Longitude", render(t->get_longitude()));
955 print("SOG", render(t->get_sog()));
956 print("Heading", render(t->get_heading()));
957 print("Date", render(t->get_date()));
958 print("Magn Dev", fmt::sprintf("%s %s", render(t->get_mag()), render(t->get_mag_hem())));
959 print("Mode Ind ", render(t->get_mode_ind()));
962 static void print_detail_vtg(const marnav::nmea::sentence * s)
964 const auto t = marnav::nmea::sentence_cast<marnav::nmea::vtg>(s);
965 print("Track True", render(t->get_track_true()));
966 print("Track Magn", render(t->get_track_magn()));
967 print("Speed Knots", render(t->get_speed_kn()));
968 print("Speed kmh", render(t->get_speed_kmh()));
969 print("Mode Indicator", render(t->get_mode_ind()));
972 static void print_detail_gll(const marnav::nmea::sentence * s)
974 const auto t = marnav::nmea::sentence_cast<marnav::nmea::gll>(s);
975 print("Latitude", render(t->get_latitude()));
976 print("Longitude", render(t->get_longitude()));
977 print("Time UTC", render(t->get_time_utc()));
978 print("Status", render(t->get_data_valid()));
979 print("Mode Indicator", render(t->get_mode_ind()));
982 static void print_detail_bod(const marnav::nmea::sentence * s)
984 const auto t = marnav::nmea::sentence_cast<marnav::nmea::bod>(s);
985 print("Bearing True", render(t->get_bearing_true()));
986 print("Bearing Magn", render(t->get_bearing_magn()));
987 print("Waypoint To", render(t->get_waypoint_to()));
988 print("Waypoint From", render(t->get_waypoint_from()));
991 static void print_detail_bwc(const marnav::nmea::sentence * s)
993 const auto t = marnav::nmea::sentence_cast<marnav::nmea::bwc>(s);
994 print("Time UTC", render(t->get_time_utc()));
995 print("Bearing True", render(t->get_bearing_true()));
996 print("Bearing Magnetic", render(t->get_bearing_mag()));
997 print("Distance",
998 fmt::sprintf("%s %s", render(t->get_distance()), render(t->get_distance_unit())));
999 print("Waypoint", render(t->get_waypoint_id()));
1000 print("Mode Indicator", render(t->get_mode_ind()));
1003 static void print_detail_gsa(const marnav::nmea::sentence * s)
1005 const auto t = marnav::nmea::sentence_cast<marnav::nmea::gsa>(s);
1006 print("Selection Mode", render(t->get_sel_mode()));
1007 print("Mode", render(t->get_mode()));
1008 for (auto i = 0; i < marnav::nmea::gsa::max_satellite_ids; ++i) {
1009 print(fmt::sprintf("Satellite %02u", i), render(t->get_satellite_id(i)));
1011 print("PDOP", render(t->get_pdop()));
1012 print("HDOP", render(t->get_hdop()));
1013 print("VDOP", render(t->get_vdop()));
1016 static void print_detail_gga(const marnav::nmea::sentence * s)
1018 const auto t = marnav::nmea::sentence_cast<marnav::nmea::gga>(s);
1019 print("Time", render(t->get_time()));
1020 print("Latitude", render(t->get_latitude()));
1021 print("Longitude", render(t->get_longitude()));
1022 print("Quality Ind", render(t->get_quality_indicator()));
1023 print("Num Satellites", render(t->get_n_satellites()));
1024 print("Horiz Dilution", render(t->get_hor_dilution()));
1025 print("Altitude",
1026 fmt::sprintf("%s %s", render(t->get_altitude()), render(t->get_altitude_unit())));
1027 print("Geodial Sep", fmt::sprintf("%s %s", render(t->get_geodial_separation()),
1028 render(t->get_geodial_separation_unit())));
1029 print("DGPS Age", render(t->get_dgps_age()));
1030 print("DGPS Ref", render(t->get_dgps_ref()));
1033 static void print_detail_mwv(const marnav::nmea::sentence * s)
1035 const auto t = marnav::nmea::sentence_cast<marnav::nmea::mwv>(s);
1036 print("Angle", fmt::sprintf("%s %s", render(t->get_angle()), render(t->get_angle_ref())));
1037 print("Speed", fmt::sprintf("%s %s", render(t->get_speed()), render(t->get_speed_unit())));
1038 print("Data Valid", render(t->get_data_valid()));
1041 static void print_detail_gsv(const marnav::nmea::sentence * s)
1043 const auto t = marnav::nmea::sentence_cast<marnav::nmea::gsv>(s);
1044 print("Num Messages", render(t->get_n_messages()));
1045 print("Messages Number", render(t->get_message_number()));
1046 print("Num Sat in View", render(t->get_n_satellites_in_view()));
1047 for (int i = 0; i < 4; ++i) {
1048 const auto sat = t->get_sat(i);
1049 if (sat) {
1050 print("Sat", fmt::sprintf("ID:%02u ELEV:%02u AZIMUTH:%03u SNR:%02u", sat->id,
1051 sat->elevation, sat->azimuth, sat->snr));
1056 static void print_detail_zda(const marnav::nmea::sentence * s)
1058 const auto t = marnav::nmea::sentence_cast<marnav::nmea::zda>(s);
1059 print("Time UTC", render(t->get_time_utc()));
1060 print("Day", render(t->get_day()));
1061 print("Month", render(t->get_month()));
1062 print("Year", render(t->get_year()));
1063 print("Local Zone Hours", render(t->get_local_zone_hours()));
1064 print("Local Zone Min", render(t->get_local_zone_minutes()));
1067 static void print_detail_dtm(const marnav::nmea::sentence * s)
1069 const auto t = marnav::nmea::sentence_cast<marnav::nmea::dtm>(s);
1070 print("Ref", render(t->get_ref()));
1071 print("Subcode", render(t->get_subcode()));
1072 print("Latitude Offset", render(t->get_lat_offset()));
1073 print("Latitude Hem", render(t->get_lat_hem()));
1074 print("Longitude Offset", render(t->get_lon_offset()));
1075 print("Longitude Hem", render(t->get_lon_hem()));
1076 print("Altitude", render(t->get_altitude()));
1077 print("Name", render(t->get_name()));
1080 static void print_detail_aam(const marnav::nmea::sentence * s)
1082 const auto t = marnav::nmea::sentence_cast<marnav::nmea::aam>(s);
1083 print("Arrival Circle Entred", render(t->get_arrival_circle_entered()));
1084 print("Perpendicular Passed", render(t->get_perpendicualar_passed()));
1085 print("Arrival Circle Radius", fmt::sprintf("%s %s", render(t->get_arrival_circle_radius()),
1086 render(t->get_arrival_circle_radius_unit())));
1087 print("Waypoint", render(t->get_waypoint_id()));
1090 static void print_detail_rte(const marnav::nmea::sentence * s)
1092 const auto t = marnav::nmea::sentence_cast<marnav::nmea::rte>(s);
1093 print("Number of Messages", render(t->get_n_messages()));
1094 print("Message Number", render(t->get_message_number()));
1095 print("Message Mode", render(t->get_message_mode()));
1096 for (int i = 0; i < marnav::nmea::rte::max_waypoints; ++i) {
1097 const auto wp = t->get_waypoint_id(i);
1098 if (wp)
1099 print(fmt::sprintf("Waypoint %i", i), render(wp));
1103 static void print_detail_mtw(const marnav::nmea::sentence * s)
1105 const auto t = marnav::nmea::sentence_cast<marnav::nmea::mtw>(s);
1106 print("Water Temperature",
1107 fmt::sprintf("%s %s", render(t->get_temperature()), render(t->get_temperature_unit())));
1110 static void print_detail_dbt(const marnav::nmea::sentence * s)
1112 const auto t = marnav::nmea::sentence_cast<marnav::nmea::dbt>(s);
1113 print("Depth Feet", render(t->get_depth_feet()));
1114 print("Depth Meter", render(t->get_depth_meter()));
1115 print("Depth Fathom", render(t->get_depth_fathom()));
1118 static void print_detail_apb(const marnav::nmea::sentence * s)
1120 const auto t = marnav::nmea::sentence_cast<marnav::nmea::apb>(s);
1121 print("Loran C blink warn", render(t->get_loran_c_blink_warning()));
1122 print("Loran C cycle lock warn", render(t->get_loran_c_cycle_lock_warning()));
1123 print("Cross Track Error Magnitude", render(t->get_cross_track_error_magnitude()));
1124 print("Direction to Steer", render(t->get_direction_to_steer()));
1125 print("Cross Track Unit", render(t->get_cross_track_unit()));
1126 print("Status Arrival", render(t->get_status_arrival()));
1127 print("Status Perpendicular Pass", render(t->get_status_perpendicular_passing()));
1128 print("Bearing Org to Dest", render(t->get_bearing_origin_to_destination()));
1129 print("Bearing Org to Dest Ref", render(t->get_bearing_origin_to_destination_ref()));
1130 print("Waypoint", render(t->get_waypoint_id()));
1131 print("Bearing Pos to Dest", render(t->get_bearing_pos_to_destination()));
1132 print("Bearing Pos to Dest Ref", render(t->get_bearing_pos_to_destination_ref()));
1133 print("Heading to Steer to Dest", render(t->get_heading_to_steer_to_destination()));
1134 print("Heading to Steer to Dest Ref", render(t->get_heading_to_steer_to_destination_ref()));
1135 print("Mode Indicator", render(t->get_mode_ind()));
1138 static void print_detail_pgrme(const marnav::nmea::sentence * s)
1140 const auto t = marnav::nmea::sentence_cast<marnav::nmea::pgrme>(s);
1141 print("HPE", render(t->get_horizontal_position_error()));
1142 print("VPE", render(t->get_vertical_position_error()));
1143 print("O.sph.eq.pos err", render(t->get_overall_spherical_equiv_position_error()));
1146 static void print_detail_pgrmm(const marnav::nmea::sentence * s)
1148 const auto t = marnav::nmea::sentence_cast<marnav::nmea::pgrmm>(s);
1149 print("Map Datum", render(t->get_map_datum()));
1152 static void print_detail_pgrmz(const marnav::nmea::sentence * s)
1154 const auto t = marnav::nmea::sentence_cast<marnav::nmea::pgrmz>(s);
1155 print("Altitude",
1156 fmt::sprintf("%s %s", render(t->get_altitude()), render(t->get_altitude_unit())));
1157 print("Fix Type", render(t->get_fix()));
1160 static void print_detail_vwr(const marnav::nmea::sentence * s)
1162 const auto t = marnav::nmea::sentence_cast<marnav::nmea::vwr>(s);
1163 print("Angle", fmt::sprintf("%s %s", render(t->get_angle()), render(t->get_angle_side())));
1164 print("Speed Knots", render(t->get_speed_knots()));
1165 print("Speed m/s", render(t->get_speed_mps()));
1166 print("Speed km/h", render(t->get_speed_kmh()));
1169 static void print_detail_vlw(const marnav::nmea::sentence * s)
1171 const auto t = marnav::nmea::sentence_cast<marnav::nmea::vlw>(s);
1172 print("Distance Cumulative nm", render(t->get_distance_cum()));
1173 print("Distance since Rest nm", render(t->get_distance_reset()));
1176 static void print_detail_vhw(const marnav::nmea::sentence * s)
1178 const auto t = marnav::nmea::sentence_cast<marnav::nmea::vhw>(s);
1179 print("Heading True", render(t->get_heading_empty()));
1180 print("Heading Magn", render(t->get_heading()));
1181 print("Speed kn", render(t->get_speed_knots()));
1182 print("Speed km/h", render(t->get_speed_kmh()));
1185 static void print_detail_message_01_common(const marnav::ais::message_01 * t)
1187 print("Repeat Indicator", render(t->get_repeat_indicator()));
1188 print("MMSI", render(t->get_mmsi()));
1189 print("ROT", render(t->get_rot()));
1190 print("SOG", render(t->get_sog()));
1191 print("Pos Accuracy", render(t->get_position_accuracy()));
1192 print("Latitude", render(t->get_latitude()));
1193 print("Longitude", render(t->get_longitude()));
1194 print("COG", render(t->get_cog()));
1195 print("HDG", render(t->get_hdg()));
1196 print("Time Stamp", render(t->get_timestamp()));
1197 print("RAIM", render(t->get_raim()));
1198 print("Radio Status", render(t->get_radio_status()));
1201 static void print_detail_message_01(const marnav::ais::message * m)
1203 print_detail_message_01_common(marnav::ais::message_cast<marnav::ais::message_01>(m));
1206 static void print_detail_message_02(const marnav::ais::message * m)
1208 print_detail_message_01_common(marnav::ais::message_cast<marnav::ais::message_02>(m));
1211 static void print_detail_message_03(const marnav::ais::message * m)
1213 print_detail_message_01_common(marnav::ais::message_cast<marnav::ais::message_03>(m));
1216 static void print_detail_message_04_common(const marnav::ais::message_04 * t)
1218 print("Repeat Indicator", render(t->get_repeat_indicator()));
1219 print("MMSI", render(t->get_mmsi()));
1220 print("Year", render(t->get_year()));
1221 print("Month", render(t->get_month()));
1222 print("Day", render(t->get_day()));
1223 print("Hour", render(t->get_hour()));
1224 print("Minute", render(t->get_minute()));
1225 print("Second", render(t->get_second()));
1226 print("Pos Accuracy", render(t->get_position_accuracy()));
1227 print("Latitude", render(t->get_latitude()));
1228 print("Longitude", render(t->get_longitude()));
1229 print("EPFD Fix", render(t->get_epfd_fix()));
1230 print("RAIM", render(t->get_raim()));
1231 print("Radio Status", render(t->get_radio_status()));
1234 static void print_detail_message_04(const marnav::ais::message * m)
1236 print_detail_message_04_common(marnav::ais::message_cast<marnav::ais::message_04>(m));
1239 static void print_detail_message_11(const marnav::ais::message * m)
1241 print_detail_message_04_common(marnav::ais::message_cast<marnav::ais::message_11>(m));
1244 static void print_detail_message_05(const marnav::ais::message * m)
1246 const auto t = marnav::ais::message_cast<marnav::ais::message_05>(m);
1247 print("Repeat Indicator", render(t->get_repeat_indicator()));
1248 print("MMSI", render(t->get_mmsi()));
1249 print("AIS Version", render(t->get_ais_version()));
1250 print("IMO", render(t->get_imo_number()));
1251 print("Callsign", render(t->get_callsign()));
1252 print("Shipname", render(t->get_shipname()));
1253 print("Shiptype", render(t->get_shiptype()));
1254 print("Length", render(t->get_to_bow() + t->get_to_stern()));
1255 print("Width", render(t->get_to_port() + t->get_to_starboard()));
1256 print("Draught", render(t->get_draught()));
1257 print("EPFD Fix", render(t->get_epfd_fix()));
1258 print("ETA Month", render(t->get_eta_month()));
1259 print("ETA Day", render(t->get_eta_day()));
1260 print("ETA Hour", render(t->get_eta_hour()));
1261 print("ETA Minute", render(t->get_eta_minute()));
1262 print("Destination", render(t->get_destination()));
1263 print("DTE", render(t->get_dte()));
1266 static void print_detail_message_18(const marnav::ais::message * m)
1268 const auto t = marnav::ais::message_cast<marnav::ais::message_18>(m);
1269 print("Repeat Indicator", render(t->get_repeat_indicator()));
1270 print("MMSI", render(t->get_mmsi()));
1271 print("SOG", render(t->get_sog()));
1272 print("Pos Accuracy", render(t->get_position_accuracy()));
1273 print("Latitude", render(t->get_latitude()));
1274 print("Longitude", render(t->get_longitude()));
1275 print("COG", render(t->get_cog()));
1276 print("HDG", render(t->get_hdg()));
1277 print("Time Stamp", render(t->get_timestamp()));
1278 print("CS Unit", render(t->get_cs_unit()));
1279 print("Display Flag", render(t->get_display_flag()));
1280 print("DSC Flag", render(t->get_dsc_flag()));
1281 print("Band Flag", render(t->get_band_flag()));
1282 print("Message 22 Flag", render(t->get_message_22_flag()));
1283 print("Assigned", render(t->get_assigned()));
1284 print("RAIM", render(t->get_raim()));
1285 print("Radio Status", render(t->get_radio_status()));
1288 static void print_detail_message_21(const marnav::ais::message * m)
1290 const auto t = marnav::ais::message_cast<marnav::ais::message_21>(m);
1291 print("Repeat Indicator", render(t->get_repeat_indicator()));
1292 print("MMSI", render(t->get_mmsi()));
1293 print("Aid Type", render(t->get_aid_type()));
1294 print("Name", render(t->get_name()));
1295 print("Pos Accuracy", render(t->get_position_accuracy()));
1296 print("Latitude", render(t->get_latitude()));
1297 print("Longitude", render(t->get_longitude()));
1298 print("Length", render(t->get_to_bow() + t->get_to_stern()));
1299 print("Width", render(t->get_to_port() + t->get_to_starboard()));
1300 print("EPFD Fix", render(t->get_epfd_fix()));
1301 print("UTC Second", render(t->get_utc_second()));
1302 print("Off Pos Indicator", render(t->get_off_position()));
1303 print("Regional", render(t->get_regional()));
1304 print("RAIM", render(t->get_raim()));
1305 print("Virtual Aid Flag", render(t->get_virtual_aid_flag()));
1306 print("Assigned", render(t->get_assigned()));
1307 print("Name Extension", render(t->get_name_extension()));
1310 static void print_detail_message_24(const marnav::ais::message * m)
1312 const auto t = marnav::ais::message_cast<marnav::ais::message_24>(m);
1313 print("Repeat Indicator", render(t->get_repeat_indicator()));
1314 print("MMSI", render(t->get_mmsi()));
1315 print("Part", render(t->get_part_number()));
1316 if (t->get_part_number() == marnav::ais::message_24::part::A) {
1317 print("Ship Name", render(t->get_shipname()));
1318 } else {
1319 print("Ship Type", render(t->get_shiptype()));
1320 print("Vendor ID", render(t->get_vendor_id()));
1321 print("Model", render(t->get_model()));
1322 print("Serial", render(t->get_serial()));
1323 print("Callsign", render(t->get_callsign()));
1324 if (t->is_auxiliary_vessel()) {
1325 print("Mothership MMSI", render(t->get_mothership_mmsi()));
1326 } else {
1327 print("Length", render(t->get_to_bow() + t->get_to_stern()));
1328 print("Width", render(t->get_to_port() + t->get_to_starboard()));
1334 static void dump_nmea(const std::string & line)
1336 #define ADD_SENTENCE(s) \
1338 marnav::nmea::s::ID, detail::print_detail_##s \
1340 struct entry {
1341 marnav::nmea::sentence_id id;
1342 std::function<void(const marnav::nmea::sentence *)> func;
1344 using container = std::vector<entry>;
1345 // clang-format off
1346 static const container sentences = {
1347 // standard
1348 ADD_SENTENCE(aam),
1349 ADD_SENTENCE(apb),
1350 ADD_SENTENCE(bod),
1351 ADD_SENTENCE(bwc),
1352 ADD_SENTENCE(dbt),
1353 ADD_SENTENCE(dtm),
1354 ADD_SENTENCE(gga),
1355 ADD_SENTENCE(gll),
1356 ADD_SENTENCE(gsa),
1357 ADD_SENTENCE(gsv),
1358 ADD_SENTENCE(hdg),
1359 ADD_SENTENCE(hdm),
1360 ADD_SENTENCE(mtw),
1361 ADD_SENTENCE(mwv),
1362 ADD_SENTENCE(rmb),
1363 ADD_SENTENCE(rmc),
1364 ADD_SENTENCE(rte),
1365 ADD_SENTENCE(vhw),
1366 ADD_SENTENCE(vlw),
1367 ADD_SENTENCE(vtg),
1368 ADD_SENTENCE(vwr),
1369 ADD_SENTENCE(zda),
1371 // proprietary
1372 ADD_SENTENCE(pgrme),
1373 ADD_SENTENCE(pgrmm),
1374 ADD_SENTENCE(pgrmz)
1376 // clang-format on
1377 #undef ADD_SENTENCE
1379 using namespace marnav;
1381 try {
1382 auto s = nmea::make_sentence(line);
1383 auto i = std::find_if(std::begin(sentences), std::end(sentences),
1384 [&s](const container::value_type & item) { return item.id == s->id(); });
1385 if (i == std::end(sentences)) {
1386 fmt::printf("\t%s\n", detail::render(s->id()));
1387 fmt::printf(
1388 "%s%s%s\n\tnot implemented\n\n", terminal::magenta, line, terminal::normal);
1389 } else {
1390 fmt::printf("%s%s%s\n", terminal::green, line, terminal::normal);
1391 fmt::printf("\t%s\n", detail::render(s->id()));
1392 i->func(s.get());
1393 fmt::printf("\n");
1395 } catch (nmea::unknown_sentence & error) {
1396 fmt::printf("%s%s%s\n\terror: unknown sentence: %s\n\n", terminal::red, line,
1397 terminal::normal, error.what());
1398 } catch (nmea::checksum_error & error) {
1399 fmt::printf("%s%s%s\n\terror: checksum error: %s\n\n", terminal::red, line,
1400 terminal::normal, error.what());
1401 } catch (std::invalid_argument & error) {
1402 fmt::printf(
1403 "%s%s%s\n\terror: %s\n\n", terminal::red, line, terminal::normal, error.what());
1407 static void dump_ais(const std::vector<std::unique_ptr<marnav::nmea::sentence>> & sentences)
1409 #define ADD_MESSAGE(m) \
1411 marnav::ais::m::ID, detail::print_detail_##m \
1413 struct entry {
1414 marnav::ais::message_id id;
1415 std::function<void(const marnav::ais::message *)> func;
1417 using container = std::vector<entry>;
1418 // clang-format off
1419 static const container messages = {
1420 ADD_MESSAGE(message_01),
1421 ADD_MESSAGE(message_02),
1422 ADD_MESSAGE(message_03),
1423 ADD_MESSAGE(message_04),
1424 ADD_MESSAGE(message_05),
1425 ADD_MESSAGE(message_11),
1426 ADD_MESSAGE(message_18),
1427 ADD_MESSAGE(message_21),
1428 ADD_MESSAGE(message_24)
1430 // clang-format on
1431 #undef ADD_MESSAGE
1433 using namespace marnav;
1435 try {
1436 auto m = ais::make_message(nmea::collect_payload(sentences.begin(), sentences.end()));
1437 auto i = std::find_if(std::begin(messages), std::end(messages),
1438 [&m](const container::value_type & item) { return item.id == m->type(); });
1439 if (i == std::end(messages)) {
1440 fmt::printf("\t%s\n", detail::render(m->type()));
1441 fmt::printf("%smessage_%02u%s\n\tnot implemented\n\n", terminal::magenta,
1442 static_cast<uint8_t>(m->type()), terminal::normal);
1443 } else {
1444 fmt::printf("\t%s\n", detail::render(m->type()));
1445 i->func(m.get());
1446 fmt::printf("\n");
1448 } catch (std::exception & error) {
1449 fmt::printf("\t%serror:%s %s\n\n", terminal::red, terminal::normal, error.what());
1453 static void process(std::function<bool(std::string &)> source)
1455 using namespace marnav;
1457 std::string line;
1458 std::vector<std::unique_ptr<nmea::sentence>> sentences;
1460 while (source(line)) {
1461 line = trim(line);
1462 if (line.empty())
1463 continue;
1464 if (line[0] == '#')
1465 continue;
1467 if (line[0] == nmea::sentence::start_token) {
1468 dump_nmea(line);
1469 } else if (line[0] == nmea::sentence::start_token_ais) {
1470 fmt::printf("%s%s%s\n", terminal::blue, line, terminal::normal);
1471 auto s = nmea::make_sentence(line);
1473 nmea::vdm * v = nullptr; // VDM is the common denominator for AIS relevant messages
1475 if (s->id() == nmea::sentence_id::VDO) {
1476 v = nmea::sentence_cast<nmea::vdo>(s);
1477 } else if (s->id() == nmea::sentence_id::VDM) {
1478 v = nmea::sentence_cast<nmea::vdm>(s);
1479 } else {
1480 // something strange happened, no VDM nor VDO
1481 fmt::printf("%s%s%s\n\terror: ignoring AIS sentence, dropping collection.\n\n",
1482 terminal::red, line, terminal::normal);
1483 sentences.clear();
1484 continue;
1487 // check sentences if a discontuniation has occurred
1488 if (sentences.size() && (sentences.back()->id() != v->id())) {
1489 sentences.clear(); // there was a discontinuation, start over collecting
1490 fmt::printf(
1491 "\t%swarning:%s dropping collection.\n", terminal::cyan, terminal::normal);
1494 // check if a previous message was not complete
1495 const auto n_fragments = v->get_n_fragments();
1496 const auto fragment = v->get_fragment();
1497 if (sentences.size() >= fragment) {
1498 sentences.clear();
1499 fmt::printf(
1500 "\t%swarning:%s dropping collection.\n", terminal::cyan, terminal::normal);
1503 sentences.push_back(std::move(s));
1504 if (fragment == n_fragments) {
1505 dump_ais(sentences);
1506 sentences.clear();
1508 } else {
1509 fmt::printf("%s%s%s\n\terror: ignoring AIS sentence.\n\n", terminal::red, line,
1510 terminal::normal);
1515 static marnav::io::serial::baud get_baud_rate(uint32_t speed)
1517 switch (speed) {
1518 case 4800:
1519 return marnav::io::serial::baud::baud_4800;
1520 case 38400:
1521 return marnav::io::serial::baud::baud_38400;
1522 default:
1523 break;
1525 throw std::runtime_error{"invalid baud rate"};
1529 int main(int argc, char ** argv)
1531 using namespace nmeadump;
1533 if (parse_options(argc, argv))
1534 return EXIT_SUCCESS;
1536 if (!global.config.file.empty()) {
1537 std::ifstream ifs{global.config.file.c_str()};
1538 process([&](std::string & line) { return !!std::getline(ifs, line); });
1539 } else if (!global.config.port.empty()) {
1540 using namespace marnav;
1541 using namespace marnav::io;
1542 default_nmea_reader source{utils::make_unique<serial>(global.config.port,
1543 get_baud_rate(global.config.port_speed), serial::databits::bit_8,
1544 serial::stopbits::bit_1, serial::parity::none)};
1545 process([&](std::string & line) { return source.read_sentence(line); });
1546 } else {
1547 process([&](std::string & line) { return !!std::getline(std::cin, line); });
1550 return EXIT_SUCCESS;