nmealib 0.0.4
NMEA 0183/NMEA 2000 parsing library
Loading...
Searching...
No Matches
vlw.cpp
Go to the documentation of this file.
2
5
6#include <iomanip>
7#include <sstream>
8#include <vector>
9
10namespace nmealib {
11namespace nmea0183 {
12
13std::unique_ptr<VLW> VLW::create(std::unique_ptr<Message0183> baseMessage) {
14 std::string context = "VLW::create";
15 if (baseMessage->getSentenceType() != "VLW") {
16 NMEALIB_RETURN_ERROR(NotVLWException(context, "Expected sentence type 'VLW', got " + baseMessage->getSentenceType()));
17 }
18
19 std::string payload = baseMessage->getPayload();
20 std::istringstream ss(payload);
21 std::string token;
22 std::vector<std::string> fields;
23
24 while (std::getline(ss, token, ',')) {
25 fields.push_back(token);
26 }
27
28 if (!payload.empty() && payload.back() == ',') {
29 fields.push_back("");
30 }
31
32 if (!fields.empty()) {
33 fields.erase(fields.begin());
34 }
35
36 if (fields.size() != 4 && fields.size() != 8) {
37 NMEALIB_RETURN_ERROR(NotVLWException(context, "Invalid fields in VLW payload: expected 4 or 8, got " + std::to_string(fields.size()) + ". Payload: " + payload));
38 }
39
40 double totalWaterDistanceNm = 0.0;
41 double waterDistanceSinceResetNm = 0.0;
42 if (!detail::parseOptionalDouble(fields[0], totalWaterDistanceNm) ||
43 !detail::parseOptionalDouble(fields[2], waterDistanceSinceResetNm)) {
44 NMEALIB_RETURN_ERROR(NmeaException(context, "Error parsing VLW water-distance fields"));
45 }
46
47 char totalWaterDistanceUnit = fields[1].empty() ? '\0' : fields[1][0];
48 char waterDistanceSinceResetUnit = fields[3].empty() ? '\0' : fields[3][0];
49
50 bool hasGroundDistanceFields = fields.size() == 8;
51 double totalGroundDistanceNm = 0.0;
52 char totalGroundDistanceUnit = '\0';
53 double groundDistanceSinceResetNm = 0.0;
54 char groundDistanceSinceResetUnit = '\0';
55
56 if (hasGroundDistanceFields) {
57 if (!detail::parseOptionalDouble(fields[4], totalGroundDistanceNm) ||
58 !detail::parseOptionalDouble(fields[6], groundDistanceSinceResetNm)) {
59 NMEALIB_RETURN_ERROR(NmeaException(context, "Error parsing VLW ground-distance fields"));
60 }
61
62 totalGroundDistanceUnit = fields[5].empty() ? '\0' : fields[5][0];
63 groundDistanceSinceResetUnit = fields[7].empty() ? '\0' : fields[7][0];
64 }
65
66 return std::unique_ptr<VLW>(new VLW(std::move(*baseMessage),
67 totalWaterDistanceNm,
68 totalWaterDistanceUnit,
69 waterDistanceSinceResetNm,
70 waterDistanceSinceResetUnit,
71 hasGroundDistanceFields,
72 totalGroundDistanceNm,
73 totalGroundDistanceUnit,
74 groundDistanceSinceResetNm,
75 groundDistanceSinceResetUnit));
76}
77
78VLW::VLW(Message0183 baseMessage,
79 double totalWaterDistanceNm,
80 char totalWaterDistanceUnit,
81 double waterDistanceSinceResetNm,
82 char waterDistanceSinceResetUnit,
83 bool hasGroundDistanceData,
84 double totalGroundDistanceNm,
85 char totalGroundDistanceUnit,
86 double groundDistanceSinceResetNm,
87 char groundDistanceSinceResetUnit) noexcept
88 : Message0183(std::move(baseMessage)),
89 totalWaterDistanceNm_(totalWaterDistanceNm),
90 totalWaterDistanceUnit_(totalWaterDistanceUnit),
91 waterDistanceSinceResetNm_(waterDistanceSinceResetNm),
92 waterDistanceSinceResetUnit_(waterDistanceSinceResetUnit),
93 hasGroundDistanceData_(hasGroundDistanceData),
94 totalGroundDistanceNm_(totalGroundDistanceNm),
95 totalGroundDistanceUnit_(totalGroundDistanceUnit),
96 groundDistanceSinceResetNm_(groundDistanceSinceResetNm),
97 groundDistanceSinceResetUnit_(groundDistanceSinceResetUnit) {}
98
99VLW::VLW(std::string talkerId,
100 double totalWaterDistanceNm,
101 double waterDistanceSinceResetNm,
102 std::optional<double> totalGroundDistanceNm,
103 std::optional<double> groundDistanceSinceResetNm)
104 : Message0183(*Message0183::create(composeRaw(talkerId,
105 totalWaterDistanceNm,
106 waterDistanceSinceResetNm,
107 totalGroundDistanceNm,
108 groundDistanceSinceResetNm))),
109 totalWaterDistanceNm_(totalWaterDistanceNm),
110 totalWaterDistanceUnit_('N'),
111 waterDistanceSinceResetNm_(waterDistanceSinceResetNm),
112 waterDistanceSinceResetUnit_('N'),
113 hasGroundDistanceData_(totalGroundDistanceNm.has_value() && groundDistanceSinceResetNm.has_value()),
114 totalGroundDistanceNm_(totalGroundDistanceNm.value_or(0.0)),
115 totalGroundDistanceUnit_(hasGroundDistanceData_ ? 'N' : '\0'),
116 groundDistanceSinceResetNm_(groundDistanceSinceResetNm.value_or(0.0)),
117 groundDistanceSinceResetUnit_(hasGroundDistanceData_ ? 'N' : '\0') {}
118
119std::unique_ptr<nmealib::Message> VLW::clone() const {
120 return std::unique_ptr<VLW>(new VLW(*this));
121}
122
123std::string VLW::getStringContent(bool verbose) const noexcept {
124 std::ostringstream ss;
125 ss << this->toString(verbose);
126 ss << std::fixed << std::setprecision(2);
127
128 if (verbose) {
129 ss << "\tTotal Water Distance: " << totalWaterDistanceNm_ << " " << totalWaterDistanceUnit_ << "\n";
130 ss << "\tWater Distance Since Reset: " << waterDistanceSinceResetNm_ << " " << waterDistanceSinceResetUnit_;
131 if (hasGroundDistanceData_) {
132 ss << "\n"
133 << "\tTotal Ground Distance: " << totalGroundDistanceNm_ << " " << totalGroundDistanceUnit_ << "\n"
134 << "\tGround Distance Since Reset: " << groundDistanceSinceResetNm_ << " " << groundDistanceSinceResetUnit_;
135 }
136 ss << "\n";
137 } else {
138 ss << "WaterTotal=" << totalWaterDistanceNm_
139 << ", WaterReset=" << waterDistanceSinceResetNm_;
140 if (hasGroundDistanceData_) {
141 ss << ", GroundTotal=" << totalGroundDistanceNm_
142 << ", GroundReset=" << groundDistanceSinceResetNm_;
143 }
144 }
145
146 return ss.str();
147}
148
149std::string VLW::composeRaw(const std::string& talkerId,
150 double totalWaterDistanceNm,
151 double waterDistanceSinceResetNm,
152 std::optional<double> totalGroundDistanceNm,
153 std::optional<double> groundDistanceSinceResetNm) {
154 const bool hasGroundDistanceFields = totalGroundDistanceNm.has_value() && groundDistanceSinceResetNm.has_value();
155
156 std::ostringstream payloadStream;
157 payloadStream << talkerId << "VLW,";
158 payloadStream << std::fixed << std::setprecision(1) << totalWaterDistanceNm << ",N,";
159 payloadStream << std::fixed << std::setprecision(1) << waterDistanceSinceResetNm << ",N";
160
161 if (hasGroundDistanceFields) {
162 payloadStream << ",";
163 payloadStream << std::fixed << std::setprecision(1) << totalGroundDistanceNm.value() << ",N,";
164 payloadStream << std::fixed << std::setprecision(1) << groundDistanceSinceResetNm.value() << ",N";
165 }
166
167 std::string payload = payloadStream.str();
168 return "$" + payload + "\r\n";
169}
170
171double VLW::getTotalWaterDistanceNm() const noexcept {
172 return totalWaterDistanceNm_;
173}
174
175char VLW::getTotalWaterDistanceUnit() const noexcept {
176 return totalWaterDistanceUnit_;
177}
178
179double VLW::getWaterDistanceSinceResetNm() const noexcept {
180 return waterDistanceSinceResetNm_;
181}
182
184 return waterDistanceSinceResetUnit_;
185}
186
187bool VLW::hasGroundDistanceData() const noexcept {
188 return hasGroundDistanceData_;
189}
190
191double VLW::getTotalGroundDistanceNm() const noexcept {
192 return totalGroundDistanceNm_;
193}
194
195char VLW::getTotalGroundDistanceUnit() const noexcept {
196 return totalGroundDistanceUnit_;
197}
198
199double VLW::getGroundDistanceSinceResetNm() const noexcept {
200 return groundDistanceSinceResetNm_;
201}
202
204 return groundDistanceSinceResetUnit_;
205}
206
207bool VLW::operator==(const VLW& other) const noexcept {
208 return Message0183::operator==(other);
209}
210
211} // namespace nmea0183
212} // 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
char getTotalWaterDistanceUnit() const noexcept
Definition vlw.cpp:175
double getWaterDistanceSinceResetNm() const noexcept
Definition vlw.cpp:179
std::unique_ptr< nmealib::Message > clone() const override
Creates a polymorphic deep copy of this Message0183.
Definition vlw.cpp:119
char getWaterDistanceSinceResetUnit() const noexcept
Definition vlw.cpp:183
char getTotalGroundDistanceUnit() const noexcept
Definition vlw.cpp:195
VLW(std::string talkerId, double totalWaterDistanceNm, double waterDistanceSinceResetNm, std::optional< double > totalGroundDistanceNm=std::nullopt, std::optional< double > groundDistanceSinceResetNm=std::nullopt)
Definition vlw.cpp:99
double getTotalGroundDistanceNm() const noexcept
Definition vlw.cpp:191
std::string getStringContent(bool verbose) const noexcept override
Returns a human-readable string representation of the message content.
Definition vlw.cpp:123
bool hasGroundDistanceData() const noexcept
Definition vlw.cpp:187
char getGroundDistanceSinceResetUnit() const noexcept
Definition vlw.cpp:203
double getTotalWaterDistanceNm() const noexcept
Definition vlw.cpp:171
double getGroundDistanceSinceResetNm() const noexcept
Definition vlw.cpp:199
bool operator==(const VLW &other) const noexcept
Definition vlw.cpp:207
#define NMEALIB_RETURN_ERROR(exceptionExpr)
bool parseOptionalDouble(const std::string &text, double &value) noexcept
Definition parse.h:86