NMEA: TODO added.
[marnav.git] / examples / read_ais.cpp
blob49a09e98e2944f298ffcf90b538f0e838dc46816
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
3 // as a demonstration.
5 #include <iostream>
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
18 // Demo data.
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
29 public:
30 dummy_device()
31 : index(0)
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]);
46 ++index;
47 return 1;
50 virtual int write(const char *, uint32_t) override
52 throw std::runtime_error{"operation not supported"};
55 private:
56 unsigned int index;
59 // NMEA sentence reader which uses the dummy device.
60 class sentence_reader : public marnav::io::default_nmea_reader
62 public:
63 sentence_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;
75 using namespace std;
77 // create AIS message
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";
85 break;
86 case ais::message_id::static_and_voyage_related_data:
87 std::cout << "AIS: Static and voyage related data\n";
88 break;
89 default:
90 // ignore all others
91 break;
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();
123 // collect sentence
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);
130 sentences.clear();
132 } else {
133 std::cout << nmea_sentence->tag() << ": ignored\n";