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;
17 std::string context =
"GSV::create";
18 if (baseMessage->getSentenceType() !=
"GSV") {
19 NMEALIB_RETURN_ERROR(NotGSVException(context,
"Expected sentence type 'GSV', got " + baseMessage->getSentenceType()));
22 std::string payload = baseMessage->getPayload();
23 std::istringstream ss(payload);
25 std::vector<std::string> fields;
27 while (std::getline(ss, token,
',')) {
28 fields.push_back(token);
31 if (!payload.empty() && payload.back() ==
',') {
35 if (!fields.empty()) {
36 fields.erase(fields.begin());
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));
43 unsigned int totalSentences = 0U;
44 unsigned int sentenceNumber = 0U;
45 unsigned int satellitesInView = 0U;
52 const std::size_t remainingAfterHeader = fields.size() - GSV_HEADER_FIELDS;
53 const std::size_t remainder = remainingAfterHeader % GSV_FIELDS_PER_SATELLITE;
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));
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;
68 signalId = parsedSignalId;
72 std::vector<SatelliteInfo> satellites;
73 for (std::size_t index = GSV_HEADER_FIELDS; index < satelliteFieldEnd; index += GSV_FIELDS_PER_SATELLITE) {
74 SatelliteInfo satellite;
80 if ((index + 1U) < satelliteFieldEnd) {
86 if ((index + 2U) < satelliteFieldEnd) {
92 if ((index + 3U) < satelliteFieldEnd && !fields[index + 3U].empty()) {
93 unsigned int parsedSnr = 0U;
97 satellite.snr = parsedSnr;
100 satellites.push_back(std::move(satellite));
103 return std::unique_ptr<GSV>(
new GSV(std::move(*baseMessage),
107 std::move(satellites),
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) {}
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)
136 totalSentences_(totalSentences),
137 sentenceNumber_(sentenceNumber),
138 satellitesInView_(satellitesInView),
139 satellites_(std::move(satellites)),
140 signalId_(signalId) {}
143 return std::unique_ptr<GSV>(
new GSV(*
this));
147 std::ostringstream ss;
148 ss << this->toString(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();
160 ss <<
"Total=" << totalSentences_
161 <<
", Number=" << sentenceNumber_
162 <<
", InView=" << satellitesInView_
163 <<
", Reported=" << satellites_.size();
164 if (signalId_.has_value()) {
165 ss <<
", SignalID=" << signalId_.value();
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;
181 for (
const SatelliteInfo& satellite : satellites) {
182 payloadStream <<
"," << satellite.satelliteId
183 <<
"," << satellite.elevation
184 <<
"," << satellite.azimuth
186 if (satellite.snr.has_value()) {
187 payloadStream << satellite.snr.value();
191 if (signalId.has_value()) {
192 payloadStream <<
"," << signalId.value();
195 std::string payload = payloadStream.str();
196 return "$" + payload +
"\r\n";
200 return totalSentences_;
204 return sentenceNumber_;
208 return satellitesInView_;
216 return satellites_.size();
220 if (index >= satellites_.size()) {
223 return &satellites_[index];
227 return signalId_.has_value();
unsigned int getTotalSentences() const noexcept
GSV(std::string talkerId, unsigned int totalSentences, unsigned int sentenceNumber, unsigned int satellitesInView, std::vector< SatelliteInfo > satellites, std::optional< unsigned int > signalId=std::nullopt)
bool operator==(const GSV &other) const noexcept
std::optional< unsigned int > getSignalId() const noexcept
const std::vector< SatelliteInfo > & getSatellites() const noexcept
std::size_t getSatelliteCount() const noexcept
unsigned int getSentenceNumber() const noexcept
bool hasSignalId() const noexcept
std::unique_ptr< nmealib::Message > clone() const override
Creates a polymorphic deep copy of this message.
unsigned int getSatellitesInView() const noexcept
std::string getStringContent(bool verbose) const noexcept override
Returns a human-readable string representation of the message content.
const SatelliteInfo * getSatellite(std::size_t index) const noexcept
Represents an NMEA 0183 sentence.
bool operator==(const Message0183 &other) const noexcept
Compares two Message0183 objects for equality based on their content and timestamp.
#define NMEALIB_RETURN_ERROR(exceptionExpr)
bool parseOptionalInt(const std::string &text, int &value) noexcept
bool parseUnsigned(const std::string &text, T &value, int base=10) noexcept
bool parseOptionalUnsigned(const std::string &text, unsigned int &value) noexcept