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