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()));
20 std::string payload = baseMessage->getPayload();
21 std::istringstream ss(payload);
23 std::vector<std::string> fields;
25 while (std::getline(ss, token,
',')) {
26 fields.push_back(token);
29 if (!fields.empty()) {
30 fields.erase(fields.begin());
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));
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;
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];
64 return std::unique_ptr<RMB>(
new RMB(std::move(*baseMessage),
69 destinationWaypointId,
71 destinationLatitudeHemisphere,
73 destinationLongitudeHemisphere,
75 bearingToDestinationTrue,
76 destinationClosingVelocityKnots,
81RMB::RMB(Message0183 baseMessage,
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,
95 std::optional<char> faaModeIndicator) noexcept
96 : Message0183(std::move(baseMessage)),
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) {}
112RMB::RMB(std::string talkerId,
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,
126 std::optional<char> faaModeIndicator)
132 destinationWaypointId,
134 destinationLatitudeHemisphere,
135 destinationLongitude,
136 destinationLongitudeHemisphere,
137 rangeToDestinationNm,
138 bearingToDestinationTrue,
139 destinationClosingVelocityKnots,
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) {}
158 return std::unique_ptr<RMB>(
new RMB(*
this));
162 std::ostringstream ss;
163 ss << this->toString(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()) {
178 <<
"\tFAA Mode Indicator: " << faaModeIndicator_.value();
182 ss <<
"Status=" << status_
183 <<
", XTE=" << crossTrackErrorNm_
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();
200std::string RMB::composeRaw(
const std::string& talkerId,
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,
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 <<
",";
223 const double latitudeDegrees = std::floor(destinationLatitude);
224 const double latitudeMinutes = (destinationLatitude - latitudeDegrees) * 60.0;
225 const double latitudeNmea = latitudeDegrees * 100.0 + latitudeMinutes;
227 const double longitudeDegrees = std::floor(destinationLongitude);
228 const double longitudeMinutes = (destinationLongitude - longitudeDegrees) * 60.0;
229 const double longitudeNmea = longitudeDegrees * 100.0 + longitudeMinutes;
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();
243 std::string payload = payloadStream.str();
244 return "$" + payload +
"\r\n";
252 return crossTrackErrorNm_;
256 return directionToSteer_;
260 return originWaypointId_;
264 return destinationWaypointId_;
268 return destinationLatitude_;
272 return destinationLatitudeHemisphere_;
276 return destinationLongitude_;
280 return destinationLongitudeHemisphere_;
284 return rangeToDestinationNm_;
288 return bearingToDestinationTrue_;
292 return destinationClosingVelocityKnots_;
296 return arrivalStatus_;
300 return faaModeIndicator_.has_value();
304 return faaModeIndicator_;
Represents an NMEA 0183 sentence.
bool operator==(const Message0183 &other) const noexcept
Compares two Message0183 objects for equality based on their content and timestamp.
Represents a parsed NMEA 0183 RMB (Recommended Minimum Navigation Information) sentence.
std::string getStringContent(bool verbose) const noexcept override
Return a human-readable string representation of this message.
double getBearingToDestinationTrue() const noexcept
Get bearing to destination in true degrees.
char getArrivalStatus() const noexcept
Get arrival status ('A' arrived, 'V' not arrived).
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.
char getDestinationLatitudeHemisphere() const noexcept
Get destination latitude hemisphere indicator ('N' or 'S').
bool operator==(const RMB &other) const noexcept
Compare two RMB messages for equality.
std::string getDestinationWaypointId() const noexcept
Get destination waypoint identifier.
char getDestinationLongitudeHemisphere() const noexcept
Get destination longitude hemisphere indicator ('E' or 'W').
std::string getOriginWaypointId() const noexcept
Get origin waypoint identifier.
char getDirectionToSteer() const noexcept
Get direction to steer ('L' or 'R').
std::unique_ptr< nmealib::Message > clone() const override
Create a polymorphic copy of this RMB message.
std::optional< char > getFaaModeIndicator() const noexcept
Get optional FAA mode indicator (NMEA 2.3+).
bool hasFaaModeIndicator() const noexcept
Return whether FAA mode indicator is present.
double getCrossTrackErrorNm() const noexcept
Get cross track error in nautical miles.
double getDestinationLongitude() const noexcept
Get destination waypoint longitude in decimal degrees.
double getDestinationClosingVelocityKnots() const noexcept
Get destination closing velocity in knots.
double getDestinationLatitude() const noexcept
Get destination waypoint latitude in decimal degrees.
double getRangeToDestinationNm() const noexcept
Get range to destination in nautical miles.
char getStatus() const noexcept
Get status indicator ('A' active, 'V' invalid).
#define NMEALIB_RETURN_ERROR(exceptionExpr)
bool parseNmeaCoordinate(const std::string &text, double &value) noexcept
bool parseOptionalDouble(const std::string &text, double &value) noexcept