NMEA: changed type of talker id from 'std::string' to its own type.
[marnav.git] / src / marnav / nmea / dsc.cpp
blobdda7bbeaf3a404bf80d85167545fd20627ee50f4
1 #include "dsc.hpp"
2 #include <marnav/nmea/checks.hpp>
3 #include <marnav/nmea/io.hpp>
5 namespace marnav
7 namespace nmea
9 MARNAV_NMEA_DEFINE_SENTENCE_PARSE_FUNC(dsc)
11 namespace
13 /// Converts data read from the NMEA string to the corresponding
14 /// enumerator.
15 /// @note This function already takes care about the two lowest digit
16 /// representation of the values in the string.
17 ///
18 /// @param[in] value The numerical value to convert.
19 /// @return The corresponding enumerator.
20 /// @exception std::invalid_argument The specified value to convert is unknown.
21 ///
22 static dsc::format_specifier format_specifier_mapping(
23 typename std::underlying_type<dsc::format_specifier>::type value)
25 switch (value) {
26 case 2:
27 return dsc::format_specifier::geographical_area;
28 case 12:
29 return dsc::format_specifier::distress;
30 case 16:
31 return dsc::format_specifier::all_ships;
32 case 20:
33 return dsc::format_specifier::individual_station;
35 throw std::invalid_argument{"invaild value for conversion to dsc::format_specifier"};
38 /// Converts data read from the NMEA string to the corresponding
39 /// enumerator.
40 /// @note This function already takes care about the two lowest digit
41 /// representation of the values in the string.
42 ///
43 /// @param[in] value The numerical value to convert.
44 /// @return The corresponding enumerator.
45 /// @exception std::invalid_argument The specified value to convert is unknown.
46 ///
47 static dsc::category category_mapping(typename std::underlying_type<dsc::category>::type value)
49 switch (value) {
50 case 0:
51 return dsc::category::routine;
52 case 8:
53 return dsc::category::safety;
54 case 10:
55 return dsc::category::urgency;
56 case 12:
57 return dsc::category::distress;
59 throw std::invalid_argument{"invaild value for conversion to dsc::category"};
62 /// Converts data read from the NMEA string to the corresponding
63 /// enumerator.
64 /// @note This function already takes care about the two lowest digit
65 /// representation of the values in the string.
66 ///
67 /// @param[in] value The numerical value to convert.
68 /// @return The corresponding enumerator.
69 /// @exception std::invalid_argument The specified value to convert is unknown.
70 ///
71 static dsc::acknowledgement acknowledgement_mapping(
72 typename std::underlying_type<dsc::acknowledgement>::type value)
74 switch (value) {
75 case 'B':
76 return dsc::acknowledgement::B;
77 case 'R':
78 return dsc::acknowledgement::R;
79 case 'S':
80 return dsc::acknowledgement::end_of_sequence;
82 throw std::invalid_argument{"invaild value for conversion to dsc::acknowledgement"};
85 /// Converts data read from the NMEA string to the corresponding
86 /// enumerator.
87 /// @note This function already takes care about the two lowest digit
88 /// representation of the values in the string.
89 ///
90 /// @param[in] value The numerical value to convert.
91 /// @return The corresponding enumerator.
92 /// @exception std::invalid_argument The specified value to convert is unknown.
93 ///
94 static dsc::extension_indicator extension_indicator_mapping(
95 typename std::underlying_type<dsc::extension_indicator>::type value)
97 switch (value) {
98 case 0: // works beause 'value' is default initialized in the calling 'read' function
99 return dsc::extension_indicator::none;
100 case 'E':
101 return dsc::extension_indicator::extension_follows;
103 throw std::invalid_argument{"invaild value for conversion to dsc::extension_indicator"};
107 std::string to_string(dsc::format_specifier value)
109 switch (value) {
110 case dsc::format_specifier::geographical_area:
111 return "00";
112 case dsc::format_specifier::distress:
113 return "12";
114 case dsc::format_specifier::all_ships:
115 return "16";
116 case dsc::format_specifier::individual_station:
117 return "20";
119 throw std::invalid_argument{"invaild value for conversion of dsc::format_specifier"};
122 std::string to_string(dsc::category value)
124 switch (value) {
125 case dsc::category::routine:
126 return "00";
127 case dsc::category::safety:
128 return "08";
129 case dsc::category::urgency:
130 return "10";
131 case dsc::category::distress:
132 return "12";
134 throw std::invalid_argument{"invaild value for conversion of dsc::category"};
137 std::string to_string(dsc::acknowledgement value)
139 switch (value) {
140 case dsc::acknowledgement::B:
141 return "B";
142 case dsc::acknowledgement::R:
143 return "R";
144 case dsc::acknowledgement::end_of_sequence:
145 return "S";
147 throw std::invalid_argument{"invaild value for conversion of dsc::acknowledgement"};
150 std::string to_string(dsc::extension_indicator value)
152 switch (value) {
153 case dsc::extension_indicator::none:
154 return "";
155 case dsc::extension_indicator::extension_follows:
156 return "E";
158 throw std::invalid_argument{"invaild value for conversion of dsc::extension_indicator"};
161 constexpr const char * dsc::TAG;
163 dsc::dsc()
164 : sentence(ID, TAG, talker_id::communications_dsc)
168 /// @todo Read and interpret more fields
169 dsc::dsc(talker talk, fields::const_iterator first, fields::const_iterator last)
170 : sentence(ID, TAG, talk)
172 if (std::distance(first, last) != 11)
173 throw std::invalid_argument{"invalid number of fields in dsc"};
175 read(*(first + 0), fmt_spec, format_specifier_mapping);
176 read(*(first + 1), address);
177 read(*(first + 2), cat, category_mapping);
178 // @todo read other 6 data members
179 read(*(first + 9), ack, acknowledgement_mapping);
180 read(*(first + 10), extension, extension_indicator_mapping);
183 /// Valid only for format specifier other than geographical area.
184 /// However, there are no checks and special treatment, the MMSI is
185 /// simply wrong if taken with an invalid format specifier.
186 utils::mmsi dsc::get_mmsi() const
188 return utils::mmsi{static_cast<utils::mmsi::value_type>(address / 10)};
191 /// Valid only for format specifier geographical_area.
192 /// However, there are no checks and special treatment, the data is
193 /// simply wrong if taken with an invalid format specifier.
195 /// Format:
196 /// @code
197 /// 2
198 /// 1| 3 4 5
199 /// || | | |
200 /// qxxyyyaabb
201 /// @endcode
203 /// Field Number:
204 /// 1. Quadrant 0..3
205 /// 2. Latitude in degrees, 2 digits
206 /// 3. Longitude in degrees, 3 digits
207 /// 4. Vertical side of the rectangle (north to south) in degrees, 2 digits
208 /// 5. Horizontal side of the rectangle (west to east) in degrees, 2 digits
210 geo::region dsc::get_geographical_area() const
212 const auto quadrant = (address / 1000000000) % 10;
214 geo::latitude::hemisphere lat_hem = geo::latitude::hemisphere::north;
215 geo::longitude::hemisphere lon_hem = geo::longitude::hemisphere::west;
216 switch (quadrant) {
217 case 0: // NE quadrant
218 lat_hem = geo::latitude::hemisphere::north;
219 lon_hem = geo::longitude::hemisphere::east;
220 break;
221 case 1: // NW quadrant
222 lat_hem = geo::latitude::hemisphere::north;
223 lon_hem = geo::longitude::hemisphere::west;
224 break;
225 case 2: // SE quadrant
226 lat_hem = geo::latitude::hemisphere::south;
227 lon_hem = geo::longitude::hemisphere::east;
228 break;
229 case 3: // SW quadrant
230 lat_hem = geo::latitude::hemisphere::south;
231 lon_hem = geo::longitude::hemisphere::west;
232 break;
233 default:
234 throw std::invalid_argument{"invalid quadrant"};
237 const uint32_t lat = static_cast<uint32_t>((address / 10000000) % 100);
238 const uint32_t lon = static_cast<uint32_t>((address / 10000) % 1000);
239 const double d_lat = static_cast<double>((address / 100) % 100);
240 const double d_lon = static_cast<double>(address % 100);
242 return geo::region{{{lat, 0, 0, lat_hem}, {lon, 0, 0, lon_hem}}, d_lat, d_lon};
245 /// @todo Implementation
247 std::vector<std::string> dsc::get_data() const
249 return {
250 to_string(fmt_spec), format(address, 10), to_string(cat), "", "", "", "", "", "",
251 to_string(ack), to_string(extension),