16std::unique_ptr<RMC> RMC::create(std::unique_ptr<Message0183> baseMessage) {
17 std::string context =
"RMC::create";
18 if (baseMessage->getSentenceType() !=
"RMC") {
19 NMEALIB_RETURN_ERROR(NotRMCException(context,
"Expected sentence type 'RMC', got " + baseMessage->getSentenceType()));
23 std::string payload = baseMessage->getPayload();
24 std::istringstream ss(payload);
26 std::vector<std::string> fields;
28 while (std::getline(ss, token,
',')) {
29 fields.push_back(token);
33 if (!fields.empty()) {
34 fields.erase(fields.begin());
37 size_t messageSize = fields.size();
38 if (messageSize != 11 && messageSize != 12 && messageSize != 13) {
39 NMEALIB_RETURN_ERROR(NotRMCException(context,
"Insufficient fields in RMC payload: expected 11, 12 or 13, got " + std::to_string(fields.size()) +
". Payload: " + payload));
42 unsigned int utcFix = 0U;
43 double latitude = 0.0;
44 double longitude = 0.0;
45 double speedOverGround = 0.0;
46 double courseOverGround = 0.0;
47 unsigned int date = 0U;
48 double magneticVariation = 0.0;
50 auto parseUtcFix = [](
const std::string& utcField,
unsigned int& outUtcFix) {
51 if (utcField.empty()) {
56 double utcDouble = 0.0;
58 utcDouble >
static_cast<double>(std::numeric_limits<unsigned int>::max())) {
62 outUtcFix =
static_cast<unsigned int>(utcDouble);
66 if (!parseUtcFix(fields[0], utcFix) ||
76 char status = fields[1].empty() ?
'\0' : fields[1][0];
77 char latDirection = fields[3].empty() ?
'\0' : fields[3][0];
78 char lonDirection = fields[5].empty() ?
'\0' : fields[5][0];
79 char magneticVariationDirection = fields[10].empty() ?
'\0' : fields[10][0];
80 char modeIndicator =
'\0';
81 char navigationStatus =
'\0';
83 if (messageSize >= 12) {
84 modeIndicator = fields[11].empty() ?
'\0' : fields[11][0];
87 if (messageSize == 13) {
88 navigationStatus = fields[12].empty() ?
'\0' : fields[12][0];
91 return std::unique_ptr<RMC>(
new RMC(std::move(*baseMessage), utcFix, status, latitude, latDirection, longitude, lonDirection, speedOverGround, courseOverGround, date, magneticVariation, magneticVariationDirection, modeIndicator, navigationStatus));
94RMC::RMC(Message0183 baseMessage,
98 char latitudeDirection,
100 char longitudeDirection,
101 double speedOverGround,
102 double courseOverGround,
104 double magneticVariation,
105 char magneticVariationDirection,
107 char navigationStatus) noexcept
108 : Message0183(std::move(baseMessage)),
112 latitudeDirection_(latitudeDirection),
113 longitude_(longitude),
114 longitudeDirection_(longitudeDirection),
115 speedOverGround_(speedOverGround),
116 courseOverGround_(courseOverGround),
118 magneticVariation_(magneticVariation),
119 magneticVariationDirection_(magneticVariationDirection),
120 modeIndicator_(modeIndicator),
121 navigationStatus_(navigationStatus) {}
123RMC::RMC(std::string talkerId,
unsigned int utcFix,
126 char latitudeDirection,
128 char longitudeDirection,
129 double speedOverGround,
130 double courseOverGround,
132 double magneticVariation,
133 char magneticVariationDirection,
135 char navigationStatus) :
137 latitudeDirection, longitude, longitudeDirection,
138 speedOverGround, courseOverGround, date, magneticVariation,
139 magneticVariationDirection, modeIndicator, navigationStatus))),
143 latitudeDirection_(latitudeDirection),
144 longitude_(longitude),
145 longitudeDirection_(longitudeDirection),
146 speedOverGround_(speedOverGround),
147 courseOverGround_(courseOverGround),
149 magneticVariation_(magneticVariation),
150 magneticVariationDirection_(magneticVariationDirection),
151 modeIndicator_(modeIndicator),
152 navigationStatus_(navigationStatus) {}
155 return std::unique_ptr<RMC>(
new RMC(*
this));
159 std::ostringstream ss;
160 ss << this->toString(verbose);
161 std::ostringstream latStream;
162 latStream << std::setprecision(10) << latitude_;
163 const std::string latitudeStr = latStream.str();
165 std::ostringstream lonStream;
166 lonStream << std::setprecision(10) << longitude_;
167 const std::string longitudeStr = lonStream.str();
170 ss <<
"\tUTC Fix: " << utcFix_ <<
"\n";
171 ss <<
"\tStatus: " << status_ <<
"\n";
172 ss <<
"\tLatitude: " << latitudeStr <<
" " << latitudeDirection_ <<
"\n";
173 ss <<
"\tLongitude: " << longitudeStr <<
" " << longitudeDirection_ <<
"\n";
174 ss <<
"\tSpeed Over Ground: " << speedOverGround_ <<
"\n";
175 ss <<
"\tCourse Over Ground: " << courseOverGround_ <<
"\n";
176 ss <<
"\tDate: " << date_ <<
"\n";
177 ss <<
"\tMagnetic Variation: " << magneticVariation_ <<
" " << magneticVariationDirection_ <<
"\n";
178 ss <<
"\tMode Indicator: " << modeIndicator_ <<
"\n";
179 ss <<
"\tNavigation Status: " << navigationStatus_;
182 ss <<
"UTC Fix=" << utcFix_
183 <<
", Status=" << status_
184 <<
", Lat=" << latitudeStr << latitudeDirection_
185 <<
", Lon=" << longitudeStr << longitudeDirection_
186 <<
", SOG=" << speedOverGround_
187 <<
", COG=" << courseOverGround_
188 <<
", Date=" << date_
189 <<
", MagVar=" << magneticVariation_ << magneticVariationDirection_
190 <<
", Mode=" << modeIndicator_
191 <<
", NavStatus=" << navigationStatus_;
196std::string RMC::composeRaw(
const std::string& talkerId,
unsigned int utcFix,
199 char latitudeDirection,
201 char longitudeDirection,
202 double speedOverGround,
203 double courseOverGround,
205 double magneticVariation,
206 char magneticVariationDirection,
208 char navigationStatus) {
209 std::ostringstream payloadStream;
210 payloadStream << talkerId <<
"RMC,";
211 payloadStream << std::setw(6) << std::setfill(
'0') << utcFix <<
",";
212 payloadStream << status <<
",";
213 double latitudeDegrees = std::floor(latitude);
214 double latitudeMinutes = (latitude - latitudeDegrees) * 60.0;
215 latitude = latitudeDegrees * 100.0 + latitudeMinutes;
216 double longitudeDegrees = std::floor(longitude);
217 double longitudeMinutes = (longitude - longitudeDegrees) * 60.0;
218 longitude = longitudeDegrees * 100.0 + longitudeMinutes;
219 payloadStream << std::fixed << std::setprecision(4) << latitude <<
",";
220 payloadStream << latitudeDirection <<
",";
221 payloadStream << std::fixed << std::setprecision(4) << longitude <<
",";
222 payloadStream << longitudeDirection <<
",";
223 payloadStream << std::fixed << std::setprecision(1) << speedOverGround <<
",";
224 payloadStream << std::fixed << std::setprecision(1) << courseOverGround <<
",";
225 payloadStream << std::setw(6) << std::setfill(
'0') << date <<
",";
226 payloadStream << std::fixed << std::setprecision(1) << magneticVariation <<
",";
227 payloadStream << magneticVariationDirection <<
",";
228 payloadStream << modeIndicator <<
",";
229 payloadStream << navigationStatus;
231 std::string payload = payloadStream.str();
232 return "$" + payload +
"\r\n";
248 return latitudeDirection_;
256 return longitudeDirection_;
260 return speedOverGround_;
264 return courseOverGround_;
272 return magneticVariation_;
276 return magneticVariationDirection_;
280 return modeIndicator_;
284 return navigationStatus_;
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 RMC (Recommended Minimum Navigation Information) sentence.
double getCourseOverGround() const noexcept
Get course over ground in degrees.
char getLatitudeDirection() const noexcept
Get latitude hemisphere indicator ('N' or 'S').
char getMagneticVariationDirection() const noexcept
Get magnetic variation direction ('E' or 'W').
double getMagneticVariation() const noexcept
Get magnetic variation in degrees.
double getSpeedOverGround() const noexcept
Get speed over ground in knots.
char getStatus() const noexcept
Get status indicator.
std::string getStringContent(bool verbose) const noexcept override
Return a human-readable string representation of this message.
double getLatitude() const noexcept
Get latitude in decimal degrees.
char getModeIndicator() const noexcept
Get mode indicator character.
std::unique_ptr< nmealib::Message > clone() const override
Create a polymorphic copy of this RMC message.
unsigned int getUtcFix() const noexcept
Get UTC fix time in hhmmss[.ss] numeric form.
RMC(std::string talkerId, unsigned int utcFix, char status, double latitude, char latitudeDirection, double longitude, char longitudeDirection, double speedOverGround, double courseOverGround, unsigned int date, double magneticVariation, char magneticVariationDirection, char modeIndicator, char navigationStatus)
Construct an RMC message from individual field values.
double getLongitude() const noexcept
Get longitude in decimal degrees.
bool operator==(const RMC &other) const noexcept
Compare two RMC messages for equality.
unsigned int getDate() const noexcept
Get date in ddmmyy numeric form.
char getNavigationStatus() const noexcept
Get navigation status character.
char getLongitudeDirection() const noexcept
Get longitude hemisphere indicator ('E' or 'W').
#define NMEALIB_RETURN_ERROR(exceptionExpr)
bool parseNmeaCoordinate(const std::string &text, double &value) noexcept
bool parseOptionalUnsigned(const std::string &text, unsigned int &value) noexcept
bool parseOptionalDouble(const std::string &text, double &value) noexcept