13std::unique_ptr<VTG> VTG::create(std::unique_ptr<Message0183> baseMessage) {
14 std::string context =
"VTG::create";
15 if (baseMessage->getSentenceType() !=
"VTG") {
16 NMEALIB_RETURN_ERROR(NotVTGException(context,
"Expected sentence type 'VTG', 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() != 4 && fields.size() != 8 && fields.size() != 9) {
37 NMEALIB_RETURN_ERROR(NotVTGException(context,
"Invalid fields in VTG payload: expected 4, 8 or 9, got " + std::to_string(fields.size()) +
". Payload: " + payload));
40 bool legacyFormat = fields.size() == 4;
41 if (!legacyFormat && !fields[1].empty() && fields[1] !=
"T") {
46 if (fields.size() != 4) {
50 double courseOverGroundTrue = 0.0;
51 double courseOverGroundMagnetic = 0.0;
52 double speedOverGroundKnots = 0.0;
53 double speedOverGroundKph = 0.0;
61 return std::unique_ptr<VTG>(
new VTG(std::move(*baseMessage),
64 courseOverGroundMagnetic,
74 double courseOverGroundTrue = 0.0;
75 double courseOverGroundMagnetic = 0.0;
76 double speedOverGroundKnots = 0.0;
77 double speedOverGroundKph = 0.0;
85 char courseOverGroundTrueType = fields[1].empty() ?
'\0' : fields[1][0];
86 char courseOverGroundMagneticType = fields[3].empty() ?
'\0' : fields[3][0];
87 char speedOverGroundKnotsType = fields[5].empty() ?
'\0' : fields[5][0];
88 char speedOverGroundKphType = fields[7].empty() ?
'\0' : fields[7][0];
89 std::optional<char> faaModeIndicator = std::nullopt;
91 if (fields.size() == 9 && !fields[8].empty()) {
92 faaModeIndicator = fields[8][0];
95 return std::unique_ptr<VTG>(
new VTG(std::move(*baseMessage),
97 courseOverGroundTrueType,
98 courseOverGroundMagnetic,
99 courseOverGroundMagneticType,
100 speedOverGroundKnots,
101 speedOverGroundKnotsType,
103 speedOverGroundKphType,
108VTG::VTG(Message0183 baseMessage,
109 double courseOverGroundTrue,
110 char courseOverGroundTrueType,
111 double courseOverGroundMagnetic,
112 char courseOverGroundMagneticType,
113 double speedOverGroundKnots,
114 char speedOverGroundKnotsType,
115 double speedOverGroundKph,
116 char speedOverGroundKphType,
117 std::optional<char> faaModeIndicator,
118 bool legacyFormat) noexcept
119 : Message0183(std::move(baseMessage)),
120 courseOverGroundTrue_(courseOverGroundTrue),
121 courseOverGroundTrueType_(courseOverGroundTrueType),
122 courseOverGroundMagnetic_(courseOverGroundMagnetic),
123 courseOverGroundMagneticType_(courseOverGroundMagneticType),
124 speedOverGroundKnots_(speedOverGroundKnots),
125 speedOverGroundKnotsType_(speedOverGroundKnotsType),
126 speedOverGroundKph_(speedOverGroundKph),
127 speedOverGroundKphType_(speedOverGroundKphType),
128 faaModeIndicator_(faaModeIndicator),
129 legacyFormat_(legacyFormat) {}
131VTG::VTG(std::string talkerId,
132 double courseOverGroundTrue,
133 double courseOverGroundMagnetic,
134 double speedOverGroundKnots,
135 double speedOverGroundKph,
136 std::optional<char> faaModeIndicator,
139 courseOverGroundTrue,
140 courseOverGroundMagnetic,
141 speedOverGroundKnots,
145 courseOverGroundTrue_(courseOverGroundTrue),
146 courseOverGroundTrueType_(legacyFormat ?
'\0' :
'T'),
147 courseOverGroundMagnetic_(courseOverGroundMagnetic),
148 courseOverGroundMagneticType_(legacyFormat ?
'\0' :
'M'),
149 speedOverGroundKnots_(speedOverGroundKnots),
150 speedOverGroundKnotsType_(legacyFormat ?
'\0' :
'N'),
151 speedOverGroundKph_(speedOverGroundKph),
152 speedOverGroundKphType_(legacyFormat ?
'\0' :
'K'),
153 faaModeIndicator_(legacyFormat ? std::nullopt : faaModeIndicator),
154 legacyFormat_(legacyFormat) {}
157 return std::unique_ptr<VTG>(
new VTG(*
this));
161 std::ostringstream ss;
162 ss << this->toString(verbose);
163 ss << std::fixed << std::setprecision(2);
166 ss <<
"\tLegacy Format: " << (legacyFormat_ ?
"Yes" :
"No") <<
"\n";
167 ss <<
"\tCourse Over Ground: " << courseOverGroundTrue_ <<
"T\n";
168 ss <<
"\tCourse Over Ground: " << courseOverGroundMagnetic_ <<
"M\n";
169 ss <<
"\tSpeed Over Ground: " << speedOverGroundKnots_ <<
"kts\n";
170 ss <<
"\tSpeed Over Ground: " << speedOverGroundKph_ <<
"kph";
171 if (faaModeIndicator_.has_value()) {
173 <<
"\tFAA Mode Indicator: " << faaModeIndicator_.value();
177 ss <<
"True=" << courseOverGroundTrue_
178 <<
", Magnetic=" << courseOverGroundMagnetic_
179 <<
", Knots=" << speedOverGroundKnots_
180 <<
", KPH=" << speedOverGroundKph_;
181 if (faaModeIndicator_.has_value()) {
182 ss <<
", FAA=" << faaModeIndicator_.value();
184 ss <<
", Legacy=" << (legacyFormat_ ?
"Y" :
"N");
190std::string VTG::composeRaw(
const std::string& talkerId,
191 double courseOverGroundTrue,
192 double courseOverGroundMagnetic,
193 double speedOverGroundKnots,
194 double speedOverGroundKph,
195 std::optional<char> faaModeIndicator,
197 std::ostringstream payloadStream;
198 payloadStream << talkerId <<
"VTG,";
201 payloadStream << std::fixed << std::setprecision(2) << courseOverGroundTrue <<
",";
202 payloadStream << std::fixed << std::setprecision(2) << courseOverGroundMagnetic <<
",";
203 payloadStream << std::fixed << std::setprecision(3) << speedOverGroundKnots <<
",";
204 payloadStream << std::fixed << std::setprecision(3) << speedOverGroundKph;
206 payloadStream << std::fixed << std::setprecision(2) << courseOverGroundTrue <<
",T,";
207 payloadStream << std::fixed << std::setprecision(2) << courseOverGroundMagnetic <<
",M,";
208 payloadStream << std::fixed << std::setprecision(3) << speedOverGroundKnots <<
",N,";
209 payloadStream << std::fixed << std::setprecision(3) << speedOverGroundKph <<
",K";
211 if (faaModeIndicator.has_value()) {
212 payloadStream <<
"," << faaModeIndicator.value();
216 std::string payload = payloadStream.str();
217 return "$" + payload +
"\r\n";
221 return courseOverGroundTrue_;
225 return courseOverGroundTrueType_;
229 return courseOverGroundMagnetic_;
233 return courseOverGroundMagneticType_;
237 return speedOverGroundKnots_;
241 return speedOverGroundKnotsType_;
245 return speedOverGroundKph_;
249 return speedOverGroundKphType_;
253 return faaModeIndicator_.has_value();
257 return faaModeIndicator_;
261 return legacyFormat_;
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 VTG (Course Over Ground and Ground Speed) sentence.
char getSpeedOverGroundKphType() const noexcept
Get km/h unit indicator (typically 'K', or '\0' in legacy format).
double getSpeedOverGroundKnots() const noexcept
Get speed over ground in knots.
bool isLegacyFormat() const noexcept
Return whether this sentence uses legacy compact VTG format.
double getCourseOverGroundMagnetic() const noexcept
Get magnetic course over ground in degrees.
VTG(std::string talkerId, double courseOverGroundTrue, double courseOverGroundMagnetic, double speedOverGroundKnots, double speedOverGroundKph, std::optional< char > faaModeIndicator=std::nullopt, bool legacyFormat=false)
Construct a VTG message from individual field values.
bool operator==(const VTG &other) const noexcept
Compare two VTG messages for equality.
char getCourseOverGroundTrueType() const noexcept
Get true course type indicator (typically 'T', or '\0' in legacy format).
std::unique_ptr< nmealib::Message > clone() const override
Create a polymorphic copy of this VTG message.
char getSpeedOverGroundKnotsType() const noexcept
Get knots unit indicator (typically 'N', or '\0' in legacy format).
double getCourseOverGroundTrue() const noexcept
Get true course over ground in degrees.
std::string getStringContent(bool verbose) const noexcept override
Return a human-readable string representation of this message.
char getCourseOverGroundMagneticType() const noexcept
Get magnetic course type indicator (typically 'M', or '\0' in legacy format).
bool hasFaaModeIndicator() const noexcept
Return whether FAA mode indicator is present.
double getSpeedOverGroundKph() const noexcept
Get speed over ground in kilometers per hour.
std::optional< char > getFaaModeIndicator() const noexcept
Get optional FAA mode indicator.
#define NMEALIB_RETURN_ERROR(exceptionExpr)
bool parseOptionalDouble(const std::string &text, double &value) noexcept