NMEA: Qt example extended.
[marnav.git] / src / marnav / nmea / vdm.hpp
blob5b10045976fef45aa97ca4f2d34cad8622b24112
1 #ifndef __NMEA__VDM__HPP__
2 #define __NMEA__VDM__HPP__
4 #include <marnav/nmea/sentence.hpp>
5 #include <marnav/utils/optional.hpp>
7 namespace marnav
9 namespace nmea
11 MARNAV_NMEA_DECLARE_SENTENCE_PARSE_FUNC(vdm)
13 /// @brief VDM - AIS VHF Data-Link Message
14 ///
15 /// @code
16 /// 1 2 3 4 5 6
17 /// | | | | | |
18 /// $--VDM,x,x,x,a,s--s,x*hh<CR><LF>
19 /// @endcode
20 ///
21 /// Field Number:
22 /// 1. Number of fragments
23 /// 2. Fragment number
24 /// 3. Sequence Message ID
25 /// 4. Radio Channel
26 /// - A
27 /// - B
28 /// 5. Payload, 6-bit encoded content, max. 63 characters
29 /// 6. Number of fill bits (0..5)
30 ///
31 class vdm : public sentence
33 MARNAV_NMEA_SENTENCE_FRIENDS(vdm)
35 public:
36 constexpr static const sentence_id ID = sentence_id::VDM;
37 constexpr static const char * TAG = "VDM";
39 virtual ~vdm() {}
41 vdm();
42 vdm(const vdm &) = default;
43 vdm & operator=(const vdm &) = default;
45 protected:
46 vdm(sentence_id id, const std::string & tag, const std::string & talker);
47 vdm(const std::string & talker, fields::const_iterator first, fields::const_iterator last);
49 virtual std::vector<std::string> get_data() const override;
50 virtual char get_start_token() const override { return start_token_ais; }
52 void read_fields(fields::const_iterator first);
54 private:
55 uint32_t n_fragments = 0;
56 uint32_t fragment = 0;
57 utils::optional<uint32_t> seq_msg_id;
58 utils::optional<ais_channel> radio_channel; // A = 161.975MHz (87B), B = 162.025MHz (88B)
59 std::string payload; // 6bit encoded content
60 uint32_t n_fill_bits = 0; // 0..5
62 public:
63 NMEA_GETTER(n_fragments)
64 NMEA_GETTER(fragment)
65 NMEA_GETTER(seq_msg_id)
66 NMEA_GETTER(radio_channel)
67 NMEA_GETTER(payload)
68 NMEA_GETTER(n_fill_bits)
70 void set_n_fragments(uint32_t t) noexcept { n_fragments = t; }
71 void set_fragment(uint32_t t) noexcept { fragment = t; }
72 void set_seq_msg_id(uint32_t t) { seq_msg_id = t; }
73 void set_radio_channel(ais_channel channel) noexcept { radio_channel = channel; }
74 void set_payload(const std::string & data, uint32_t fill_bits) noexcept
76 payload = data;
77 n_fill_bits = fill_bits;
79 void set_payload(const std::pair<std::string, uint32_t> & data)
81 set_payload(data.first, data.second);
85 /// @{
87 /// @brief Collects payload from proper NMEA sentences.
88 ///
89 /// @note This function assumes, that all sentences in the specified range are
90 /// providing payload (VDM or descendents).
91 ///
92 /// @param[in] begin Iterator pointing to the beginning of the messges to process.
93 /// @param[in] end Iterator pointing after the messages to process (will not be
94 /// processed).
95 /// @return The container with all payload and padding bit information.
96 ///
97 /// std::unique_ptr<nmea::sentence> variant. Example:
98 /// @code
99 /// std::vector<std::unique_ptr<nmea::sentence>> v;
100 /// v.push_back(nmea::make_sentence("..."));
101 /// v.push_back(nmea::make_sentence("..."));
102 /// auto data = nmea::collect_payload(v.begin(), v.end());
103 /// @endcode
104 template <class InputIt, typename std::enable_if<std::is_class<InputIt>::value
105 && std::is_convertible<typename InputIt::value_type,
106 std::unique_ptr<sentence>>::value,
107 int>::type
108 = 0>
109 std::vector<std::pair<std::string, uint32_t>> collect_payload(InputIt begin, InputIt end)
111 std::vector<std::pair<std::string, uint32_t>> v;
112 v.reserve(std::distance(begin, end));
114 for (; begin != end; ++begin) {
115 const auto & s = sentence_cast<nmea::vdm>(*begin);
116 v.push_back(make_pair(s->get_payload(), s->get_n_fill_bits()));
119 return v;
122 /// Object iterator variant. Example:
123 /// @code
124 /// std::vector<nmea::vdm> v; // collect data, for example:
125 /// v.push_back(nmea::vdm{});
126 /// v.push_back(nmea::vdm{});
127 /// auto data = nmea::collect_payload(v.begin(), v.end());
128 /// @endcode
129 template <class InputIt, typename std::enable_if<std::is_class<InputIt>::value
130 && !std::is_convertible<typename InputIt::value_type,
131 std::unique_ptr<sentence>>::value,
132 int>::type
133 = 0>
134 std::vector<std::pair<std::string, uint32_t>> collect_payload(InputIt begin, InputIt end)
136 std::vector<std::pair<std::string, uint32_t>> v;
137 v.reserve(std::distance(begin, end));
138 for (; begin != end; ++begin) {
139 v.push_back(make_pair(begin->get_payload(), begin->get_n_fill_bits()));
141 return v;
144 /// Pointer variant. Example:
145 /// @code
146 /// nmea::vdm v[3]; // initialize them in any way...
147 /// auto data = nmea::collect_payload(v, v + 3);
148 /// @endcode
149 /// or more modern:
150 /// @code
151 /// nmea::vdm v[3]; // initialize them in any way...
152 /// auto data = nmea::collect_payload(std::begin(v), std::end(v));
153 /// @endcode
154 /// this will not compile, because MTW does not provide payload:
155 /// @code
156 /// nmea::mtw v[3];
157 /// auto data = nmea::collect_payload(std::begin(v), std::end(v));
158 /// @endcode
159 template <class InputIt,
160 typename std::enable_if<std::is_pointer<InputIt>::value, int>::type = 0>
161 std::vector<std::pair<std::string, uint32_t>> collect_payload(InputIt begin, InputIt end)
163 std::vector<std::pair<std::string, uint32_t>> v;
164 v.reserve(std::distance(begin, end));
165 for (; begin != end; ++begin) {
166 v.push_back(make_pair(begin->get_payload(), begin->get_n_fill_bits()));
168 return v;
171 /// @}
173 std::vector<std::unique_ptr<nmea::sentence>> make_vdms(
174 const std::vector<std::pair<std::string, uint32_t>> & payload,
175 utils::optional<uint32_t> seq_msg_id = utils::optional<uint32_t>{},
176 ais_channel radio_channel = ais_channel::B);
180 #endif