nmealib 0.0.4
NMEA 0183/NMEA 2000 parsing library
Loading...
Searching...
No Matches
gsv.cpp
Go to the documentation of this file.
2
5
6#include <sstream>
7#include <vector>
8
9namespace nmealib {
10namespace nmea0183 {
11
12std::unique_ptr<GSV> GSV::create(std::unique_ptr<Message0183> baseMessage) {
13 constexpr std::size_t GSV_HEADER_FIELDS = 3U;
14 constexpr std::size_t GSV_FIELDS_PER_SATELLITE = 4U;
15 constexpr std::size_t GSV_OPTIONAL_SIGNAL_ID_REMAINDER = 1U;
16
17 std::string context = "GSV::create";
18 if (baseMessage->getSentenceType() != "GSV") {
19 NMEALIB_RETURN_ERROR(NotGSVException(context, "Expected sentence type 'GSV', got " + baseMessage->getSentenceType()));
20 }
21
22 std::string payload = baseMessage->getPayload();
23 std::istringstream ss(payload);
24 std::string token;
25 std::vector<std::string> fields;
26
27 while (std::getline(ss, token, ',')) {
28 fields.push_back(token);
29 }
30
31 if (!payload.empty() && payload.back() == ',') {
32 fields.push_back("");
33 }
34
35 if (!fields.empty()) {
36 fields.erase(fields.begin());
37 }
38
39 if (fields.size() < GSV_HEADER_FIELDS) {
40 NMEALIB_RETURN_ERROR(NotGSVException(context, "Invalid fields in GSV payload: expected at least 3, got " + std::to_string(fields.size()) + ". Payload: " + payload));
41 }
42
43 unsigned int totalSentences = 0U;
44 unsigned int sentenceNumber = 0U;
45 unsigned int satellitesInView = 0U;
46 if (!detail::parseOptionalUnsigned(fields[0], totalSentences) ||
47 !detail::parseOptionalUnsigned(fields[1], sentenceNumber) ||
48 !detail::parseOptionalUnsigned(fields[2], satellitesInView)) {
49 NMEALIB_RETURN_ERROR(NmeaException(context, "Error parsing GSV fields"));
50 }
51
52 const std::size_t remainingAfterHeader = fields.size() - GSV_HEADER_FIELDS;
53 const std::size_t remainder = remainingAfterHeader % GSV_FIELDS_PER_SATELLITE;
54
55 if (remainder != 0U && remainder != GSV_OPTIONAL_SIGNAL_ID_REMAINDER) {
56 NMEALIB_RETURN_ERROR(NotGSVException(context, "Invalid fields in GSV payload: expected satellite quadruplets with optional trailing signal ID. Payload: " + payload));
57 }
58
59 std::size_t satelliteFieldEnd = fields.size();
60 std::optional<unsigned int> signalId = std::nullopt;
61 if (remainder == GSV_OPTIONAL_SIGNAL_ID_REMAINDER) {
62 satelliteFieldEnd = fields.size() - 1U;
63 if (!fields.back().empty()) {
64 unsigned int parsedSignalId = 0U;
65 if (!detail::parseUnsigned(fields.back(), parsedSignalId)) {
66 NMEALIB_RETURN_ERROR(NmeaException(context, "Error parsing GSV fields"));
67 }
68 signalId = parsedSignalId;
69 }
70 }
71
72 std::vector<SatelliteInfo> satellites;
73 for (std::size_t index = GSV_HEADER_FIELDS; index < satelliteFieldEnd; index += GSV_FIELDS_PER_SATELLITE) {
74 SatelliteInfo satellite;
75
76 if (!detail::parseOptionalUnsigned(fields[index], satellite.satelliteId)) {
77 NMEALIB_RETURN_ERROR(NmeaException(context, "Error parsing GSV fields"));
78 }
79
80 if ((index + 1U) < satelliteFieldEnd) {
81 if (!detail::parseOptionalInt(fields[index + 1U], satellite.elevation)) {
82 NMEALIB_RETURN_ERROR(NmeaException(context, "Error parsing GSV fields"));
83 }
84 }
85
86 if ((index + 2U) < satelliteFieldEnd) {
87 if (!detail::parseOptionalUnsigned(fields[index + 2U], satellite.azimuth)) {
88 NMEALIB_RETURN_ERROR(NmeaException(context, "Error parsing GSV fields"));
89 }
90 }
91
92 if ((index + 3U) < satelliteFieldEnd && !fields[index + 3U].empty()) {
93 unsigned int parsedSnr = 0U;
94 if (!detail::parseUnsigned(fields[index + 3U], parsedSnr)) {
95 NMEALIB_RETURN_ERROR(NmeaException(context, "Error parsing GSV fields"));
96 }
97 satellite.snr = parsedSnr;
98 }
99
100 satellites.push_back(std::move(satellite));
101 }
102
103 return std::unique_ptr<GSV>(new GSV(std::move(*baseMessage),
104 totalSentences,
105 sentenceNumber,
106 satellitesInView,
107 std::move(satellites),
108 signalId));
109}
110
111GSV::GSV(Message0183 baseMessage,
112 unsigned int totalSentences,
113 unsigned int sentenceNumber,
114 unsigned int satellitesInView,
115 std::vector<SatelliteInfo> satellites,
116 std::optional<unsigned int> signalId) noexcept
117 : Message0183(std::move(baseMessage)),
118 totalSentences_(totalSentences),
119 sentenceNumber_(sentenceNumber),
120 satellitesInView_(satellitesInView),
121 satellites_(std::move(satellites)),
122 signalId_(signalId) {}
123
124GSV::GSV(std::string talkerId,
125 unsigned int totalSentences,
126 unsigned int sentenceNumber,
127 unsigned int satellitesInView,
128 std::vector<SatelliteInfo> satellites,
129 std::optional<unsigned int> signalId)
130 : Message0183(*Message0183::create(composeRaw(talkerId,
131 totalSentences,
132 sentenceNumber,
133 satellitesInView,
134 satellites,
135 signalId))),
136 totalSentences_(totalSentences),
137 sentenceNumber_(sentenceNumber),
138 satellitesInView_(satellitesInView),
139 satellites_(std::move(satellites)),
140 signalId_(signalId) {}
141
142std::unique_ptr<nmealib::Message> GSV::clone() const {
143 return std::unique_ptr<GSV>(new GSV(*this));
144}
145
146std::string GSV::getStringContent(bool verbose) const noexcept {
147 std::ostringstream ss;
148 ss << this->toString(verbose);
149
150 if (verbose) {
151 ss << "\tTotal Sentences: " << totalSentences_ << "\n";
152 ss << "\tSentence Number: " << sentenceNumber_ << "\n";
153 ss << "\tSatellites in View: " << satellitesInView_ << "\n";
154 ss << "\tSatellites Reported: " << satellites_.size();
155 if (signalId_.has_value()) {
156 ss << "\n\tSignal ID: " << signalId_.value();
157 }
158 ss << "\n";
159 } else {
160 ss << "Total=" << totalSentences_
161 << ", Number=" << sentenceNumber_
162 << ", InView=" << satellitesInView_
163 << ", Reported=" << satellites_.size();
164 if (signalId_.has_value()) {
165 ss << ", SignalID=" << signalId_.value();
166 }
167 }
168
169 return ss.str();
170}
171
172std::string GSV::composeRaw(const std::string& talkerId,
173 unsigned int totalSentences,
174 unsigned int sentenceNumber,
175 unsigned int satellitesInView,
176 const std::vector<SatelliteInfo>& satellites,
177 std::optional<unsigned int> signalId) {
178 std::ostringstream payloadStream;
179 payloadStream << talkerId << "GSV," << totalSentences << "," << sentenceNumber << "," << satellitesInView;
180
181 for (const SatelliteInfo& satellite : satellites) {
182 payloadStream << "," << satellite.satelliteId
183 << "," << satellite.elevation
184 << "," << satellite.azimuth
185 << ",";
186 if (satellite.snr.has_value()) {
187 payloadStream << satellite.snr.value();
188 }
189 }
190
191 if (signalId.has_value()) {
192 payloadStream << "," << signalId.value();
193 }
194
195 std::string payload = payloadStream.str();
196 return "$" + payload + "\r\n";
197}
198
199unsigned int GSV::getTotalSentences() const noexcept {
200 return totalSentences_;
201}
202
203unsigned int GSV::getSentenceNumber() const noexcept {
204 return sentenceNumber_;
205}
206
207unsigned int GSV::getSatellitesInView() const noexcept {
208 return satellitesInView_;
209}
210
211const std::vector<GSV::SatelliteInfo>& GSV::getSatellites() const noexcept {
212 return satellites_;
213}
214
215std::size_t GSV::getSatelliteCount() const noexcept {
216 return satellites_.size();
217}
218
219const GSV::SatelliteInfo* GSV::getSatellite(std::size_t index) const noexcept {
220 if (index >= satellites_.size()) {
221 return nullptr;
222 }
223 return &satellites_[index];
224}
225
226bool GSV::hasSignalId() const noexcept {
227 return signalId_.has_value();
228}
229
230std::optional<unsigned int> GSV::getSignalId() const noexcept {
231 return signalId_;
232}
233
234bool GSV::operator==(const GSV& other) const noexcept {
235 return Message0183::operator==(other);
236}
237
238} // namespace nmea0183
239} // namespace nmealib
unsigned int getTotalSentences() const noexcept
Definition gsv.cpp:199
GSV(std::string talkerId, unsigned int totalSentences, unsigned int sentenceNumber, unsigned int satellitesInView, std::vector< SatelliteInfo > satellites, std::optional< unsigned int > signalId=std::nullopt)
Definition gsv.cpp:124
bool operator==(const GSV &other) const noexcept
Definition gsv.cpp:234
std::optional< unsigned int > getSignalId() const noexcept
Definition gsv.cpp:230
const std::vector< SatelliteInfo > & getSatellites() const noexcept
Definition gsv.cpp:211
std::size_t getSatelliteCount() const noexcept
Definition gsv.cpp:215
unsigned int getSentenceNumber() const noexcept
Definition gsv.cpp:203
bool hasSignalId() const noexcept
Definition gsv.cpp:226
std::unique_ptr< nmealib::Message > clone() const override
Creates a polymorphic deep copy of this message.
Definition gsv.cpp:142
unsigned int getSatellitesInView() const noexcept
Definition gsv.cpp:207
std::string getStringContent(bool verbose) const noexcept override
Returns a human-readable string representation of the message content.
Definition gsv.cpp:146
const SatelliteInfo * getSatellite(std::size_t index) const noexcept
Definition gsv.cpp:219
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
#define NMEALIB_RETURN_ERROR(exceptionExpr)
bool parseOptionalInt(const std::string &text, int &value) noexcept
Definition parse.h:110
bool parseUnsigned(const std::string &text, T &value, int base=10) noexcept
Definition parse.h:15
bool parseOptionalUnsigned(const std::string &text, unsigned int &value) noexcept
Definition parse.h:102