1 // This demo shows how to read NMEA sentences and interpret AIS messages.
2 // It does not read directly from a specific device, it provides data
5 #include <marnav/nmea/nmea.hpp>
6 #include <marnav/nmea/ais_helper.hpp>
7 #include <marnav/ais/ais.hpp>
8 #include <marnav/ais/message_01.hpp>
9 #include <marnav/ais/message_05.hpp>
10 #include <marnav-io/device.hpp>
11 #include <marnav-io/default_nmea_reader.hpp>
14 namespace marnav_example
18 static const char DATA
[]
19 = {"!AIVDM,1,1,,B,177KQJ5000G?tO`K>RA1wUbN0TKH,0*5C\r\n"
20 "$GPRMC,201034,A,4702.4040,N,00818.3281,E,0.0,328.4,260807,0.6,E,A*17\r\n"
21 "!AIVDM,2,1,3,B,55P5TL01VIaAL@7WKO@mBplU@<PDhh000000001S;AJ::4A80?4i@E53,0*3E\r\n"
22 "$GPRMC,201034,A,4702.4040,N,00818.3281,E,0.0,328.4,260807,0.6,E,A*17\r\n"
23 "!AIVDM,2,2,3,B,1@0000000000000,2*55\r\n"};
25 // Dummy device to read from 'DATA'.
26 class dummy_device
: public marnav::io::device
34 void open() override
{}
35 void close() override
{}
37 /// Just go through the data once.
38 virtual int read(char * buffer
, uint32_t size
) override
40 if (size
!= sizeof(*buffer
))
41 throw std::invalid_argument
{"buffer type not supported"};
42 if (index
>= sizeof(DATA
))
43 return 0; // end of data
44 *buffer
= static_cast<char>(DATA
[index
]);
49 virtual int write(const char *, uint32_t) override
51 throw std::runtime_error
{"operation not supported"};
58 // NMEA sentence reader which uses the dummy device.
59 class sentence_reader
: public marnav::io::default_nmea_reader
63 : default_nmea_reader(std::make_unique
<dummy_device
>())
68 // This function finally processes the AIS data... for this demo it does not
69 // do very much with the data, just showing how to decode NMEA sentences
70 // into an AIS message.
71 void process_ais_message(const std::vector
<std::unique_ptr
<marnav::nmea::sentence
>> & sentences
)
73 using namespace marnav
;
77 auto payload
= nmea::collect_payload(sentences
.begin(), sentences
.end());
78 auto ais_message
= ais::make_message(payload
);
80 // process the message. for this demo, we only do some of them.
81 switch (ais_message
->type()) {
82 case ais::message_id::position_report_class_a
:
83 std::cout
<< "AIS: Position report\n";
85 case ais::message_id::static_and_voyage_related_data
:
86 std::cout
<< "AIS: Static and voyage related data\n";
95 int main(int, char **)
97 using namespace marnav
;
99 // instance of dummy reader, sufficient for this demo
100 marnav_example::sentence_reader reader
;
102 // sentence collection
103 std::vector
<std::unique_ptr
<nmea::sentence
>> sentences
;
104 std::string raw_sentence
;
106 // read NMEA sentences
107 while (reader
.read_sentence(raw_sentence
)) {
108 auto nmea_sentence
= nmea::make_sentence(raw_sentence
);
110 // we process only VDM messages in this demo
111 if (nmea_sentence
->id() == nmea::sentence_id::VDM
) {
113 // since AIS messages may be splitted up in several VDM sentences,
114 // we have to collect them. this is a very simple implementation
115 // and does not check for sequence or overlapping of messages.
116 // it simply assumes all necessary messages are subsequent.
117 // there is simply a check, whether or not all parts have arrived.
118 const auto vdm
= nmea::sentence_cast
<nmea::vdm
>(nmea_sentence
.get());
119 const auto n_fragments
= vdm
->get_n_fragments();
120 const auto fragment
= vdm
->get_fragment();
123 sentences
.push_back(std::move(nmea_sentence
));
125 // check if all necessary sentences have arrived and if they have,
126 // process the AIS message.
127 if (fragment
== n_fragments
) {
128 marnav_example::process_ais_message(sentences
);
132 std::cout
<< nmea_sentence
->tag() << ": ignored\n";