Build: add GCC-13, Clang-14, Clang-15, Clang-16, Clang-17
[marnav.git] / src / marnav / nmea / mob.cpp
blobc48942d7aba732595ea0ad6895c2757434d2d0ea
1 #include <marnav/nmea/mob.hpp>
2 #include <marnav/nmea/io.hpp>
3 #include "convert.hpp"
4 #include <algorithm>
5 #include <stdexcept>
7 namespace marnav::nmea
9 namespace
11 static mob::mob_status mob_status_mapping(
12 typename std::underlying_type<mob::mob_status>::type value)
14 switch (value) {
15 case 'A':
16 return mob::mob_status::mob_activated;
17 case 'T':
18 return mob::mob_status::test_mode;
19 case 'M':
20 return mob::mob_status::manual_button;
21 case 'V':
22 return mob::mob_status::mob_not_in_use;
23 case 'E':
24 return mob::mob_status::error;
26 throw std::invalid_argument{"invaild value for conversion to mob::mob_status"};
29 static mob::mob_position_source mob_position_source_mapping(
30 typename std::underlying_type<mob::mob_position_source>::type value)
32 switch (value) {
33 case 0:
34 return mob::mob_position_source::position_estimated;
35 case 1:
36 return mob::mob_position_source::position_reported;
37 case 2:
38 case 3:
39 case 4:
40 case 5:
41 return mob::mob_position_source::reserved;
42 case 6:
43 return mob::mob_position_source::error;
45 throw std::invalid_argument{"invaild value for conversion to mob::mob_position_source"};
48 static mob::battery_status battery_status_mapping(
49 typename std::underlying_type<mob::battery_status>::type value)
51 switch (value) {
52 case 0:
53 return mob::battery_status::good;
54 case 1:
55 return mob::battery_status::low;
56 case 2:
57 case 3:
58 case 4:
59 case 5:
60 return mob::battery_status::reserved;
61 case 6:
62 return mob::battery_status::error;
64 throw std::invalid_argument{"invaild value for conversion to mob::battery_status"};
68 std::string to_string(mob::mob_status value)
70 switch (value) {
71 case mob::mob_status::mob_activated:
72 return "A";
73 case mob::mob_status::test_mode:
74 return "T";
75 case mob::mob_status::manual_button:
76 return "M";
77 case mob::mob_status::mob_not_in_use:
78 return "V";
79 case mob::mob_status::error:
80 return "E";
82 throw std::invalid_argument{"invaild value for conversion of mob::mob_status"};
85 std::string to_string(mob::mob_position_source value)
87 switch (value) {
88 case mob::mob_position_source::position_estimated:
89 return "0";
90 case mob::mob_position_source::position_reported:
91 return "1";
92 case mob::mob_position_source::reserved:
93 return "2";
94 case mob::mob_position_source::error:
95 return "6";
97 throw std::invalid_argument{"invaild value for conversion of mob::mob_position_source"};
100 std::string to_string(mob::battery_status value)
102 switch (value) {
103 case mob::battery_status::good:
104 return "0";
105 case mob::battery_status::low:
106 return "1";
107 case mob::battery_status::reserved:
108 return "2";
109 case mob::battery_status::error:
110 return "6";
112 throw std::invalid_argument{"invaild value for conversion of mob::battery_status"};
115 constexpr sentence_id mob::ID;
116 constexpr const char * mob::TAG;
118 mob::mob()
119 : sentence(ID, TAG, talker::integrated_navigation)
123 mob::mob(talker talk, fields::const_iterator first, fields::const_iterator last)
124 : sentence(ID, TAG, talk)
126 if (std::distance(first, last) != 14)
127 throw std::invalid_argument{"invalid number of fields in mob"};
129 read(*(first + 0), emitter_id_);
130 read(*(first + 1), mob_status_, mob_status_mapping);
131 read(*(first + 2), mob_activation_utc_);
132 read(*(first + 3), mob_position_source_, mob_position_source_mapping);
133 read(*(first + 4), position_date_);
134 read(*(first + 5), position_utc_);
135 read(*(first + 6), lat_);
136 read(*(first + 7), lat_hem_);
137 read(*(first + 8), lon_);
138 read(*(first + 9), lon_hem_);
139 read(*(first + 10), cog_);
140 read(*(first + 11), sog_);
141 read(*(first + 12), mmsi_);
142 read(*(first + 13), battery_status_, battery_status_mapping);
144 // instead of reading data into temporary lat/lon, let's correct values afterwards
145 lat_ = correct_hemisphere(lat_, lat_hem_);
146 lon_ = correct_hemisphere(lon_, lon_hem_);
149 void mob::append_data_to(std::string & s, const version &) const
151 append(s, to_string(emitter_id_));
152 append(s, to_string(mob_status_));
153 append(s, to_string(mob_activation_utc_));
154 append(s, to_string(mob_position_source_));
155 append(s, to_string(position_date_));
156 append(s, to_string(position_utc_));
157 append(s, to_string(lat_));
158 append(s, to_string(lat_hem_));
159 append(s, to_string(lon_));
160 append(s, to_string(lon_hem_));
161 append(s, to_string(cog_));
162 append(s, to_string(sog_));
163 append(s, format(mmsi_, 9));
164 append(s, to_string(battery_status_));
167 geo::latitude mob::get_lat() const
169 return lat_;
172 geo::longitude mob::get_lon() const
174 return lon_;
177 utils::mmsi mob::get_mmsi() const
179 return utils::mmsi{static_cast<utils::mmsi::value_type>(mmsi_)};
182 void mob::set_emitter_id(const std::string & t)
184 if (t.empty()) {
185 emitter_id_.reset();
186 return;
189 if (t.size() > emitter_id_max)
190 throw std::invalid_argument("emitter id max 5 digits");
191 if (t.find_first_not_of("0123456789abcdefABCDEF") != std::string::npos)
192 throw std::invalid_argument("emitter id only hex digits allowed");
194 emitter_id_ = std::string(emitter_id_max, '0');
195 std::transform(begin(t), end(t), next(begin(*emitter_id_), emitter_id_max - t.size()),
196 [](std::string::value_type c) -> std::string::value_type { return std::toupper(c); });
199 void mob::set_lat(const geo::latitude & t)
201 lat_ = t;
202 lat_hem_ = convert_hemisphere(t);
205 void mob::set_lon(const geo::longitude & t)
207 lon_ = t;
208 lon_hem_ = convert_hemisphere(t);
211 void mob::set_mmsi(const utils::mmsi & t)
213 mmsi_ = t;