13std::unique_ptr<XTE> XTE::create(std::unique_ptr<Message0183> baseMessage) {
14 std::string context =
"XTE::create";
15 if (baseMessage->getSentenceType() !=
"XTE") {
16 NMEALIB_RETURN_ERROR(NotXTEException(context,
"Expected sentence type 'XTE', got " + baseMessage->getSentenceType()));
19 std::string payload = baseMessage->getPayload();
20 std::istringstream ss(payload);
22 std::vector<std::string> fields;
24 while (std::getline(ss, token,
',')) {
25 fields.push_back(token);
28 if (!payload.empty() && payload.back() ==
',') {
32 if (!fields.empty()) {
33 fields.erase(fields.begin());
36 if (fields.size() != 5 && fields.size() != 6) {
37 NMEALIB_RETURN_ERROR(NotXTEException(context,
"Invalid fields in XTE payload: expected 5 or 6, got " + std::to_string(fields.size()) +
". Payload: " + payload));
40 char status1 = fields[0].empty() ?
'\0' : fields[0][0];
41 char status2 = fields[1].empty() ?
'\0' : fields[1][0];
42 double crossTrackError = 0.0;
46 char steerDirection = fields[3].empty() ?
'\0' : fields[3][0];
47 char crossTrackUnits = fields[4].empty() ?
'\0' : fields[4][0];
48 std::optional<char> faaModeIndicator = std::nullopt;
49 if (fields.size() == 6 && !fields[5].empty()) {
50 faaModeIndicator = fields[5][0];
53 return std::unique_ptr<XTE>(
new XTE(std::move(*baseMessage),
62XTE::XTE(Message0183 baseMessage,
65 double crossTrackError,
68 std::optional<char> faaModeIndicator) noexcept
69 : Message0183(std::move(baseMessage)),
72 crossTrackError_(crossTrackError),
73 steerDirection_(steerDirection),
74 crossTrackUnits_(crossTrackUnits),
75 faaModeIndicator_(faaModeIndicator) {}
77XTE::XTE(std::string talkerId,
80 double crossTrackError,
83 std::optional<char> faaModeIndicator)
93 crossTrackError_(crossTrackError),
94 steerDirection_(steerDirection),
95 crossTrackUnits_(crossTrackUnits),
96 faaModeIndicator_(faaModeIndicator) {}
99 return std::unique_ptr<XTE>(
new XTE(*
this));
103 std::ostringstream ss;
104 ss << this->toString(verbose);
105 ss << std::fixed << std::setprecision(2);
108 ss <<
"\tStatus1: " << status1_ <<
"\n";
109 ss <<
"\tStatus2: " << status2_ <<
"\n";
110 ss <<
"\tCross Track Error: " << crossTrackError_ <<
" " << crossTrackUnits_ <<
"\n";
111 ss <<
"\tSteer Direction: " << steerDirection_;
112 if (faaModeIndicator_.has_value()) {
113 ss <<
"\n\tFAA Mode Indicator: " << faaModeIndicator_.value();
117 ss <<
"Status1=" << status1_
118 <<
", Status2=" << status2_
119 <<
", XTE=" << crossTrackError_ << crossTrackUnits_
120 <<
", Steer=" << steerDirection_;
121 if (faaModeIndicator_.has_value()) {
122 ss <<
", FAA=" << faaModeIndicator_.value();
129std::string XTE::composeRaw(
const std::string& talkerId,
132 double crossTrackError,
134 char crossTrackUnits,
135 std::optional<char> faaModeIndicator) {
136 std::ostringstream payloadStream;
137 payloadStream << talkerId <<
"XTE,";
138 if (status1 !=
'\0') {
139 payloadStream << status1;
141 payloadStream <<
",";
142 if (status2 !=
'\0') {
143 payloadStream << status2;
145 payloadStream <<
",";
146 payloadStream << std::fixed << std::setprecision(1) << crossTrackError <<
",";
147 if (steerDirection !=
'\0') {
148 payloadStream << steerDirection;
150 payloadStream <<
",";
151 if (crossTrackUnits !=
'\0') {
152 payloadStream << crossTrackUnits;
154 if (faaModeIndicator.has_value()) {
155 payloadStream <<
"," << faaModeIndicator.value();
158 std::string payload = payloadStream.str();
159 return "$" + payload +
"\r\n";
171 return crossTrackError_;
175 return steerDirection_;
179 return crossTrackUnits_;
183 return faaModeIndicator_.has_value();
187 return faaModeIndicator_;
192 status1_ == other.status1_ &&
193 status2_ == other.status2_ &&
194 crossTrackError_ == other.crossTrackError_ &&
195 steerDirection_ == other.steerDirection_ &&
196 crossTrackUnits_ == other.crossTrackUnits_ &&
197 faaModeIndicator_ == other.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 XTE (Cross-Track Error, Measured) sentence.
char getStatus1() const noexcept
Get the first status field.
double getCrossTrackError() const noexcept
Get the cross-track error magnitude in nautical miles.
char getCrossTrackUnits() const noexcept
Get the cross-track units indicator (typically 'N').
std::optional< char > getFaaModeIndicator() const noexcept
Get optional FAA mode indicator.
bool operator==(const XTE &other) const noexcept
Compare two XTE messages for equality.
std::unique_ptr< nmealib::Message > clone() const override
Create a polymorphic copy of this XTE message.
char getSteerDirection() const noexcept
Get the steer direction indicator ('L' or 'R').
char getStatus2() const noexcept
Get the second status field.
std::string getStringContent(bool verbose) const noexcept override
Return a human-readable string representation of this message.
bool hasFaaModeIndicator() const noexcept
Return whether FAA mode indicator is present.
XTE(std::string talkerId, char status1, char status2, double crossTrackError, char steerDirection, char crossTrackUnits, std::optional< char > faaModeIndicator=std::nullopt)
Construct an XTE message from individual field values.
#define NMEALIB_RETURN_ERROR(exceptionExpr)
bool parseOptionalDouble(const std::string &text, double &value) noexcept