General: separation of marav-io as a library
[marnav.git] / examples / read_ais.cpp
blob9df99e21cc47e7fa82dbcf2e7687169dc42a3646
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 <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>
12 #include <iostream>
14 namespace marnav_example
17 // Demo data.
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
28 public:
29 dummy_device()
30 : index(0)
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]);
45 ++index;
46 return 1;
49 virtual int write(const char *, uint32_t) override
51 throw std::runtime_error{"operation not supported"};
54 private:
55 unsigned int index;
58 // NMEA sentence reader which uses the dummy device.
59 class sentence_reader : public marnav::io::default_nmea_reader
61 public:
62 sentence_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;
74 using namespace std;
76 // create AIS message
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";
84 break;
85 case ais::message_id::static_and_voyage_related_data:
86 std::cout << "AIS: Static and voyage related data\n";
87 break;
88 default:
89 // ignore all others
90 break;
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();
122 // collect sentence
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);
129 sentences.clear();
131 } else {
132 std::cout << nmea_sentence->tag() << ": ignored\n";