1 #ifndef __NMEA__VDM__HPP__
2 #define __NMEA__VDM__HPP__
4 #include <marnav/nmea/sentence.hpp>
5 #include <marnav/utils/optional.hpp>
11 MARNAV_NMEA_DECLARE_SENTENCE_PARSE_FUNC(vdm
)
13 /// @brief VDM - AIS VHF Data-Link Message
18 /// $--VDM,x,x,x,a,s--s,x*hh<CR><LF>
22 /// 1. Number of fragments
23 /// 2. Fragment number
24 /// 3. Sequence Message ID
28 /// 5. Payload, 6-bit encoded content, max. 63 characters
29 /// 6. Number of fill bits (0..5)
31 class vdm
: public sentence
33 MARNAV_NMEA_SENTENCE_FRIENDS(vdm
)
36 constexpr static const sentence_id ID
= sentence_id::VDM
;
37 constexpr static const char * TAG
= "VDM";
42 vdm(const vdm
&) = default;
43 vdm
& operator=(const vdm
&) = default;
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
);
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
63 NMEA_GETTER(n_fragments
)
65 NMEA_GETTER(seq_msg_id
)
66 NMEA_GETTER(radio_channel
)
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
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
);
87 /// @brief Collects payload from proper NMEA sentences.
89 /// @note This function assumes, that all sentences in the specified range are
90 /// providing payload (VDM or descendents).
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
95 /// @return The container with all payload and padding bit information.
97 /// std::unique_ptr<nmea::sentence> variant. Example:
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());
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
,
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()));
122 /// Object iterator variant. Example:
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());
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
,
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()));
144 /// Pointer variant. Example:
146 /// nmea::vdm v[3]; // initialize them in any way...
147 /// auto data = nmea::collect_payload(v, v + 3);
151 /// nmea::vdm v[3]; // initialize them in any way...
152 /// auto data = nmea::collect_payload(std::begin(v), std::end(v));
154 /// this will not compile, because MTW does not provide payload:
157 /// auto data = nmea::collect_payload(std::begin(v), std::end(v));
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()));
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
);