12#include <QtCore/QByteArray>
13#include <QtCore/QByteArrayView>
14#include <QtCore/QTime>
76constexpr unsigned GPS = 1;
86namespace FixDimension {
100 if (field.front() ==
'+') {
101 field.remove_prefix(1);
102 if (!field.empty() && (field.front() ==
'-' || field.front() ==
'+')) {
110 if constexpr (std::is_integral_v<T>) {
111 const auto parsed = std::from_chars(field.data(), field.data() + field.size(), value, base);
112 if (parsed.ec != std::errc{} || parsed.ptr != field.data() + field.size()) {
116 static_assert(std::is_same_v<T, double> || std::is_same_v<T, float>);
119 constexpr std::string_view WHITESPACE =
" \t\n\v\f\r";
120 if (WHITESPACE.find(field.front()) != std::string_view::npos ||
121 WHITESPACE.find(field.back()) != std::string_view::npos) {
125 if constexpr (std::is_same_v<T, float>) {
126 value = QByteArrayView(field).toFloat(&ok);
128 value = QByteArrayView(field).toDouble(&ok);
130 if (!ok || !std::isfinite(value)) {
146 std::array<std::string_view, MAX_FIELDS>
fields{};
154[[nodiscard]]
unsigned char checksum(std::string_view body);
159 return ch >=
'0' && ch <=
'9';
164 return ch >=
'A' && ch <=
'Z';
168[[nodiscard]] std::optional<uint32_t>
hexNumber(std::string_view digits);
171size_t splitFields(std::string_view text, std::span<std::string_view> fields);
184[[nodiscard]] std::optional<Frame>
frame(std::string_view text);
186[[nodiscard]] std::optional<Sentence>
sentence(std::string_view text);
194[[nodiscard]] std::optional<double>
coordinate(std::string_view field, std::string_view hemisphere,
bool latitude);
208[[nodiscard]] std::optional<GGA>
gga(
const Sentence& input);
219[[nodiscard]] std::optional<UtcDate>
rmcDate(std::string_view field);
230[[nodiscard]] std::optional<RMC>
rmc(
const Sentence& input);
239[[nodiscard]] std::optional<GLL>
gll(
const Sentence& input);
247[[nodiscard]] std::optional<VTG>
vtg(
const Sentence& input);
255[[nodiscard]] std::optional<ZDA>
zda(
const Sentence& input);
273[[nodiscard]] std::optional<GST>
gst(
const Sentence& input);
278[[nodiscard]] QByteArray
frame(QByteArrayView body);
281[[nodiscard]] QByteArray
repairChecksum(
const QByteArray& sentence);
QByteArray repairChecksum(const QByteArray &sentence)
Rebuild a valid frame with its checksum and CRLF; short or malformed bodies are only terminated.
QByteArray makeGGA(const NMEA::GGA &fix, const QTime &utc)
QByteArray frame(QByteArrayView body)
body as one "$<body>*hh\r\n" sentence, with uppercase checksum digits.
constexpr size_t VTG_SPEED_KNOTS
constexpr size_t GST_LONGITUDE_ERROR
constexpr size_t GLL_STATUS
constexpr size_t GSA_DIMENSION
constexpr size_t GSA_SATELLITE_SLOTS
constexpr size_t GGA_QUALITY
constexpr size_t RMC_MIN_FIELDS
constexpr size_t RMC_SPEED_KNOTS
constexpr size_t GLL_LONGITUDE_HEMISPHERE
constexpr size_t GGA_GEOID_UNITS
constexpr size_t GSA_VDOP
constexpr size_t RMC_DATE
constexpr size_t GGA_LATITUDE_HEMISPHERE
constexpr size_t RMC_LONGITUDE
constexpr size_t GSA_MIN_FIELDS
constexpr size_t VTG_MIN_FIELDS
constexpr size_t RMC_LONGITUDE_HEMISPHERE
constexpr size_t GGA_LONGITUDE_HEMISPHERE
constexpr size_t GGA_HDOP
constexpr size_t ZDA_MONTH
constexpr size_t ZDA_MIN_FIELDS
constexpr size_t GGA_ALTITUDE_UNITS
constexpr size_t GSA_SYSTEM_ID
constexpr size_t RMC_COURSE
constexpr size_t GLL_MIN_FIELDS
constexpr size_t GLL_TIME
constexpr size_t GLL_LATITUDE_HEMISPHERE
constexpr size_t GGA_SATELLITES_USED
constexpr size_t VTG_TRUE_COURSE
constexpr size_t GSA_FIRST_SATELLITE
constexpr size_t GST_ALTITUDE_ERROR
constexpr size_t GGA_ALTITUDE
constexpr size_t ZDA_YEAR
constexpr size_t GGA_LONGITUDE
constexpr size_t RMC_STATUS
constexpr size_t RMC_LATITUDE
constexpr size_t GLL_LONGITUDE
constexpr size_t GST_LATITUDE_ERROR
constexpr size_t GSA_HDOP
constexpr size_t VTG_SPEED_KMH
constexpr size_t GGA_MIN_FIELDS
constexpr size_t RMC_LATITUDE_HEMISPHERE
constexpr size_t GLL_LATITUDE
constexpr size_t GGA_LATITUDE
constexpr size_t UTC_TIME
constexpr size_t GGA_GEOID_SEPARATION
constexpr unsigned THREE_D
constexpr unsigned NO_FIX
constexpr unsigned MAX_VALUE
constexpr unsigned RTK_FLOAT
constexpr unsigned DIFFERENTIAL
constexpr unsigned MANUAL
Manual input: the position a base station was fixed at.
constexpr unsigned ESTIMATED
constexpr unsigned RTK_FIXED
constexpr unsigned INVALID
std::optional< ZDA > zda(const Sentence &input)
std::optional< T > number(std::string_view field, int base=DECIMAL_BASE)
std::optional< Sentence > sentence(std::string_view text)
std::optional< double > coordinate(std::string_view field, std::string_view hemisphere, bool latitude)
std::optional< UtcDate > rmcDate(std::string_view field)
GPSFixQuality fixQuality(unsigned quality, GPSFixQuality autonomous)
Autonomous GGA does not distinguish 2D/3D; the caller supplies its independently resolved quality.
constexpr int DECIMAL_BASE
constexpr bool isAsciiUpper(char ch)
std::optional< int > utcMilliseconds(std::string_view field)
std::optional< RMC > rmc(const Sentence &input)
std::optional< GLL > gll(const Sentence &input)
double degreesFromDegreesMinutes(double ddmm)
Convert a signed ddmm.mmmm (or dddmm.mmmm) value; invalid values return NaN.
std::optional< uint32_t > hexNumber(std::string_view digits)
The value of digits when every one is a hexadecimal digit, with no sign or prefix; nullopt otherwise.
constexpr int CHECKSUM_DIGITS
unsigned char checksum(std::string_view body)
constexpr double MINUTES_PER_DEGREE
std::optional< GGA > gga(const Sentence &input)
Quality zero is a valid fix-loss observation with empty coordinates and optional hemisphere fields.
std::optional< VTG > vtg(const Sentence &input)
constexpr bool isAsciiDigit(char ch)
Locale-independent ASCII character classes for receiver text.
std::optional< NavigationStatus > navigationStatus(const Sentence &input)
std::optional< GST > gst(const Sentence &input)
bool isStandardSentence(std::string_view text)
A checked sentence from a standard talker, not a proprietary $P... sentence.
size_t splitFields(std::string_view text, std::span< std::string_view > fields)
Preserve empty fields, including the final field. Return zero on storage overflow.
std::optional< Frame > frame(std::string_view text)
Views into a single wire frame; the caller owns the backing bytes.
bool hasValidChecksum() const
std::string_view checksum
std::optional< unsigned > satellitesUsed
std::optional< int > utcMilliseconds
double horizontalAccuracy
std::optional< int > utcMilliseconds
double speedMetersPerSecond
std::optional< int > utcMilliseconds
static constexpr size_t MAX_FIELDS
static constexpr int TALKER_LENGTH
static constexpr int TYPE_OFFSET
std::string_view type() const
static constexpr int TYPE_LENGTH
static constexpr int PREFIX_LENGTH
std::array< std::string_view, MAX_FIELDS > fields
std::string_view talker() const
static constexpr int HEADER_LENGTH
double speedMetersPerSecond
std::optional< int > utcMilliseconds