nmealib 0.0.4
NMEA 0183/NMEA 2000 parsing library
Loading...
Searching...
No Matches
rmb.cpp
Go to the documentation of this file.
2
5
6#include <cmath>
7#include <iomanip>
8#include <sstream>
9#include <vector>
10
11namespace nmealib {
12namespace nmea0183 {
13
14std::unique_ptr<RMB> RMB::create(std::unique_ptr<Message0183> baseMessage) {
15 std::string context = "RMB::create";
16 if (baseMessage->getSentenceType() != "RMB") {
17 NMEALIB_RETURN_ERROR(NotRMBException(context, "Expected sentence type 'RMB', got " + baseMessage->getSentenceType()));
18 }
19
20 std::string payload = baseMessage->getPayload();
21 std::istringstream ss(payload);
22 std::string token;
23 std::vector<std::string> fields;
24
25 while (std::getline(ss, token, ',')) {
26 fields.push_back(token);
27 }
28
29 if (!fields.empty()) {
30 fields.erase(fields.begin());
31 }
32
33 if (fields.size() != 13 && fields.size() != 14) {
34 NMEALIB_RETURN_ERROR(NotRMBException(context, "Invalid fields in RMB payload: expected 13 or 14, got " + std::to_string(fields.size()) + ". Payload: " + payload));
35 }
36
37 double crossTrackErrorNm = 0.0;
38 double destinationLatitude = 0.0;
39 double destinationLongitude = 0.0;
40 double rangeToDestinationNm = 0.0;
41 double bearingToDestinationTrue = 0.0;
42 double destinationClosingVelocityKnots = 0.0;
43 if (!detail::parseOptionalDouble(fields[1], crossTrackErrorNm) ||
44 !detail::parseNmeaCoordinate(fields[5], destinationLatitude) ||
45 !detail::parseNmeaCoordinate(fields[7], destinationLongitude) ||
46 !detail::parseOptionalDouble(fields[9], rangeToDestinationNm) ||
47 !detail::parseOptionalDouble(fields[10], bearingToDestinationTrue) ||
48 !detail::parseOptionalDouble(fields[11], destinationClosingVelocityKnots)) {
49 NMEALIB_RETURN_ERROR(NmeaException(context, "Error parsing RMB fields"));
50 }
51
52 char status = fields[0].empty() ? '\0' : fields[0][0];
53 char directionToSteer = fields[2].empty() ? '\0' : fields[2][0];
54 const std::string originWaypointId = fields[3];
55 const std::string destinationWaypointId = fields[4];
56 char destinationLatitudeHemisphere = fields[6].empty() ? '\0' : fields[6][0];
57 char destinationLongitudeHemisphere = fields[8].empty() ? '\0' : fields[8][0];
58 char arrivalStatus = fields[12].empty() ? '\0' : fields[12][0];
59 std::optional<char> faaModeIndicator = std::nullopt;
60 if (fields.size() == 14 && !fields[13].empty()) {
61 faaModeIndicator = fields[13][0];
62 }
63
64 return std::unique_ptr<RMB>(new RMB(std::move(*baseMessage),
65 status,
66 crossTrackErrorNm,
67 directionToSteer,
68 originWaypointId,
69 destinationWaypointId,
70 destinationLatitude,
71 destinationLatitudeHemisphere,
72 destinationLongitude,
73 destinationLongitudeHemisphere,
74 rangeToDestinationNm,
75 bearingToDestinationTrue,
76 destinationClosingVelocityKnots,
77 arrivalStatus,
78 faaModeIndicator));
79}
80
81RMB::RMB(Message0183 baseMessage,
82 char status,
83 double crossTrackErrorNm,
84 char directionToSteer,
85 std::string originWaypointId,
86 std::string destinationWaypointId,
87 double destinationLatitude,
88 char destinationLatitudeHemisphere,
89 double destinationLongitude,
90 char destinationLongitudeHemisphere,
91 double rangeToDestinationNm,
92 double bearingToDestinationTrue,
93 double destinationClosingVelocityKnots,
94 char arrivalStatus,
95 std::optional<char> faaModeIndicator) noexcept
96 : Message0183(std::move(baseMessage)),
97 status_(status),
98 crossTrackErrorNm_(crossTrackErrorNm),
99 directionToSteer_(directionToSteer),
100 originWaypointId_(std::move(originWaypointId)),
101 destinationWaypointId_(std::move(destinationWaypointId)),
102 destinationLatitude_(destinationLatitude),
103 destinationLatitudeHemisphere_(destinationLatitudeHemisphere),
104 destinationLongitude_(destinationLongitude),
105 destinationLongitudeHemisphere_(destinationLongitudeHemisphere),
106 rangeToDestinationNm_(rangeToDestinationNm),
107 bearingToDestinationTrue_(bearingToDestinationTrue),
108 destinationClosingVelocityKnots_(destinationClosingVelocityKnots),
109 arrivalStatus_(arrivalStatus),
110 faaModeIndicator_(faaModeIndicator) {}
111
112RMB::RMB(std::string talkerId,
113 char status,
114 double crossTrackErrorNm,
115 char directionToSteer,
116 std::string originWaypointId,
117 std::string destinationWaypointId,
118 double destinationLatitude,
119 char destinationLatitudeHemisphere,
120 double destinationLongitude,
121 char destinationLongitudeHemisphere,
122 double rangeToDestinationNm,
123 double bearingToDestinationTrue,
124 double destinationClosingVelocityKnots,
125 char arrivalStatus,
126 std::optional<char> faaModeIndicator)
127 : Message0183(*Message0183::create(composeRaw(talkerId,
128 status,
129 crossTrackErrorNm,
130 directionToSteer,
131 originWaypointId,
132 destinationWaypointId,
133 destinationLatitude,
134 destinationLatitudeHemisphere,
135 destinationLongitude,
136 destinationLongitudeHemisphere,
137 rangeToDestinationNm,
138 bearingToDestinationTrue,
139 destinationClosingVelocityKnots,
140 arrivalStatus,
141 faaModeIndicator))),
142 status_(status),
143 crossTrackErrorNm_(crossTrackErrorNm),
144 directionToSteer_(directionToSteer),
145 originWaypointId_(std::move(originWaypointId)),
146 destinationWaypointId_(std::move(destinationWaypointId)),
147 destinationLatitude_(destinationLatitude),
148 destinationLatitudeHemisphere_(destinationLatitudeHemisphere),
149 destinationLongitude_(destinationLongitude),
150 destinationLongitudeHemisphere_(destinationLongitudeHemisphere),
151 rangeToDestinationNm_(rangeToDestinationNm),
152 bearingToDestinationTrue_(bearingToDestinationTrue),
153 destinationClosingVelocityKnots_(destinationClosingVelocityKnots),
154 arrivalStatus_(arrivalStatus),
155 faaModeIndicator_(faaModeIndicator) {}
156
157std::unique_ptr<nmealib::Message> RMB::clone() const {
158 return std::unique_ptr<RMB>(new RMB(*this));
159}
160
161std::string RMB::getStringContent(bool verbose) const noexcept {
162 std::ostringstream ss;
163 ss << this->toString(verbose);
164 if (verbose) {
165 ss << "\tStatus: " << status_ << "\n";
166 ss << "\tCross Track Error (nm): " << crossTrackErrorNm_ << "\n";
167 ss << "\tDirection To Steer: " << directionToSteer_ << "\n";
168 ss << "\tOrigin Waypoint ID: " << originWaypointId_ << "\n";
169 ss << "\tDestination Waypoint ID: " << destinationWaypointId_ << "\n";
170 ss << "\tDestination Latitude: " << destinationLatitude_ << " " << destinationLatitudeHemisphere_ << "\n";
171 ss << "\tDestination Longitude: " << destinationLongitude_ << " " << destinationLongitudeHemisphere_ << "\n";
172 ss << "\tRange To Destination (nm): " << rangeToDestinationNm_ << "\n";
173 ss << "\tBearing To Destination (true): " << bearingToDestinationTrue_ << "\n";
174 ss << "\tDestination Closing Velocity (knots): " << destinationClosingVelocityKnots_ << "\n";
175 ss << "\tArrival Status: " << arrivalStatus_;
176 if (faaModeIndicator_.has_value()) {
177 ss << "\n"
178 << "\tFAA Mode Indicator: " << faaModeIndicator_.value();
179 }
180 ss << "\n";
181 } else {
182 ss << "Status=" << status_
183 << ", XTE=" << crossTrackErrorNm_
184 << directionToSteer_
185 << ", Origin=" << originWaypointId_
186 << ", Dest=" << destinationWaypointId_
187 << ", DestLat=" << destinationLatitude_ << destinationLatitudeHemisphere_
188 << ", DestLon=" << destinationLongitude_ << destinationLongitudeHemisphere_
189 << ", Range=" << rangeToDestinationNm_
190 << ", BearingT=" << bearingToDestinationTrue_
191 << ", ClosingVel=" << destinationClosingVelocityKnots_
192 << ", Arrival=" << arrivalStatus_;
193 if (faaModeIndicator_.has_value()) {
194 ss << ", FAA=" << faaModeIndicator_.value();
195 }
196 }
197 return ss.str();
198}
199
200std::string RMB::composeRaw(const std::string& talkerId,
201 char status,
202 double crossTrackErrorNm,
203 char directionToSteer,
204 const std::string& originWaypointId,
205 const std::string& destinationWaypointId,
206 double destinationLatitude,
207 char destinationLatitudeHemisphere,
208 double destinationLongitude,
209 char destinationLongitudeHemisphere,
210 double rangeToDestinationNm,
211 double bearingToDestinationTrue,
212 double destinationClosingVelocityKnots,
213 char arrivalStatus,
214 std::optional<char> faaModeIndicator) {
215 std::ostringstream payloadStream;
216 payloadStream << talkerId << "RMB,";
217 payloadStream << status << ",";
218 payloadStream << std::fixed << std::setprecision(2) << crossTrackErrorNm << ",";
219 payloadStream << directionToSteer << ",";
220 payloadStream << originWaypointId << ",";
221 payloadStream << destinationWaypointId << ",";
222
223 const double latitudeDegrees = std::floor(destinationLatitude);
224 const double latitudeMinutes = (destinationLatitude - latitudeDegrees) * 60.0;
225 const double latitudeNmea = latitudeDegrees * 100.0 + latitudeMinutes;
226
227 const double longitudeDegrees = std::floor(destinationLongitude);
228 const double longitudeMinutes = (destinationLongitude - longitudeDegrees) * 60.0;
229 const double longitudeNmea = longitudeDegrees * 100.0 + longitudeMinutes;
230
231 payloadStream << std::fixed << std::setprecision(4) << latitudeNmea << ",";
232 payloadStream << destinationLatitudeHemisphere << ",";
233 payloadStream << std::fixed << std::setprecision(4) << longitudeNmea << ",";
234 payloadStream << destinationLongitudeHemisphere << ",";
235 payloadStream << std::fixed << std::setprecision(1) << rangeToDestinationNm << ",";
236 payloadStream << std::fixed << std::setprecision(1) << bearingToDestinationTrue << ",";
237 payloadStream << std::fixed << std::setprecision(1) << destinationClosingVelocityKnots << ",";
238 payloadStream << arrivalStatus;
239 if (faaModeIndicator.has_value()) {
240 payloadStream << "," << faaModeIndicator.value();
241 }
242
243 std::string payload = payloadStream.str();
244 return "$" + payload + "\r\n";
245}
246
247char RMB::getStatus() const noexcept {
248 return status_;
249}
250
251double RMB::getCrossTrackErrorNm() const noexcept {
252 return crossTrackErrorNm_;
253}
254
255char RMB::getDirectionToSteer() const noexcept {
256 return directionToSteer_;
257}
258
259std::string RMB::getOriginWaypointId() const noexcept {
260 return originWaypointId_;
261}
262
263std::string RMB::getDestinationWaypointId() const noexcept {
264 return destinationWaypointId_;
265}
266
267double RMB::getDestinationLatitude() const noexcept {
268 return destinationLatitude_;
269}
270
272 return destinationLatitudeHemisphere_;
273}
274
275double RMB::getDestinationLongitude() const noexcept {
276 return destinationLongitude_;
277}
278
280 return destinationLongitudeHemisphere_;
281}
282
283double RMB::getRangeToDestinationNm() const noexcept {
284 return rangeToDestinationNm_;
285}
286
287double RMB::getBearingToDestinationTrue() const noexcept {
288 return bearingToDestinationTrue_;
289}
290
292 return destinationClosingVelocityKnots_;
293}
294
295char RMB::getArrivalStatus() const noexcept {
296 return arrivalStatus_;
297}
298
299bool RMB::hasFaaModeIndicator() const noexcept {
300 return faaModeIndicator_.has_value();
301}
302
303std::optional<char> RMB::getFaaModeIndicator() const noexcept {
304 return faaModeIndicator_;
305}
306
307bool RMB::operator==(const RMB& other) const noexcept {
308 return Message0183::operator==(other);
309}
310
311} // namespace nmea0183
312} // namespace nmealib
Represents an NMEA 0183 sentence.
Definition nmea0183.h:98
bool operator==(const Message0183 &other) const noexcept
Compares two Message0183 objects for equality based on their content and timestamp.
Definition nmea0183.cpp:204
Represents a parsed NMEA 0183 RMB (Recommended Minimum Navigation Information) sentence.
Definition rmb.h:41
std::string getStringContent(bool verbose) const noexcept override
Return a human-readable string representation of this message.
Definition rmb.cpp:161
double getBearingToDestinationTrue() const noexcept
Get bearing to destination in true degrees.
Definition rmb.cpp:287
char getArrivalStatus() const noexcept
Get arrival status ('A' arrived, 'V' not arrived).
Definition rmb.cpp:295
RMB(std::string talkerId, char status, double crossTrackErrorNm, char directionToSteer, std::string originWaypointId, std::string destinationWaypointId, double destinationLatitude, char destinationLatitudeHemisphere, double destinationLongitude, char destinationLongitudeHemisphere, double rangeToDestinationNm, double bearingToDestinationTrue, double destinationClosingVelocityKnots, char arrivalStatus, std::optional< char > faaModeIndicator=std::nullopt)
Construct an RMB message from individual field values.
Definition rmb.cpp:112
char getDestinationLatitudeHemisphere() const noexcept
Get destination latitude hemisphere indicator ('N' or 'S').
Definition rmb.cpp:271
bool operator==(const RMB &other) const noexcept
Compare two RMB messages for equality.
Definition rmb.cpp:307
std::string getDestinationWaypointId() const noexcept
Get destination waypoint identifier.
Definition rmb.cpp:263
char getDestinationLongitudeHemisphere() const noexcept
Get destination longitude hemisphere indicator ('E' or 'W').
Definition rmb.cpp:279
std::string getOriginWaypointId() const noexcept
Get origin waypoint identifier.
Definition rmb.cpp:259
char getDirectionToSteer() const noexcept
Get direction to steer ('L' or 'R').
Definition rmb.cpp:255
std::unique_ptr< nmealib::Message > clone() const override
Create a polymorphic copy of this RMB message.
Definition rmb.cpp:157
std::optional< char > getFaaModeIndicator() const noexcept
Get optional FAA mode indicator (NMEA 2.3+).
Definition rmb.cpp:303
bool hasFaaModeIndicator() const noexcept
Return whether FAA mode indicator is present.
Definition rmb.cpp:299
double getCrossTrackErrorNm() const noexcept
Get cross track error in nautical miles.
Definition rmb.cpp:251
double getDestinationLongitude() const noexcept
Get destination waypoint longitude in decimal degrees.
Definition rmb.cpp:275
double getDestinationClosingVelocityKnots() const noexcept
Get destination closing velocity in knots.
Definition rmb.cpp:291
double getDestinationLatitude() const noexcept
Get destination waypoint latitude in decimal degrees.
Definition rmb.cpp:267
double getRangeToDestinationNm() const noexcept
Get range to destination in nautical miles.
Definition rmb.cpp:283
char getStatus() const noexcept
Get status indicator ('A' active, 'V' invalid).
Definition rmb.cpp:247
#define NMEALIB_RETURN_ERROR(exceptionExpr)
bool parseNmeaCoordinate(const std::string &text, double &value) noexcept
Definition parse.h:118
bool parseOptionalDouble(const std::string &text, double &value) noexcept
Definition parse.h:86