Fixposition SDK 0.0.0-heads/main-0-g408dc89
Collection of c++ libraries and apps for use with Fixposition products on Linux
Loading...
Searching...
No Matches
nmea.hpp
Go to the documentation of this file.
1/**
2 * \verbatim
3 * ___ ___
4 * \ \ / /
5 * \ \/ / Copyright (c) Fixposition AG (www.fixposition.com) and contributors
6 * / /\ \ License: see the LICENSE file
7 * /__/ \__\
8 *
9 * Based on work by flipflip (https://github.com/phkehl)
10 * The information on message structures, IDs, descriptions etc. in this file are from publicly available data, such as:
11 * - NMEA 0183 (https://www.nmea.org/)
12 * - https://en.wikipedia.org/wiki/NMEA_0183
13 * - u-blox ZED-F9P Interface Description (HPG 1.50) (https://www.u-blox.com/en/docs/UBXDOC-963802114-12815),
14 * copyright (c) 2024 u-blox AG
15 * \endverbatim
16 *
17 * @file
18 * @brief Fixposition SDK: Parser NMEA routines and types
19 */
20// clang-format off
21/**
22 * @page FPSDK_COMMON_PARSER_NMEA Parser NMEA routines and types
23 *
24 * **API**: fpsdk_common/parser/nmea.hpp and fpsdk::common::parser::nmea
25 *
26 * @fp_msgspec_begin{NMEA-Protocol}
27 *
28 * The NMEA framing and behaviour is defined by the NMEA 0183 standard (v4.11 and erratas).
29 *
30 * In NMEA speak messages are called *Sentences*. Frames (messages) are in this form:
31 *
32 * <code><b style="color: red;">$</b><b style="color: green;">Talker</b><b style="color: blue;">Formatter</b>,<em>field<sub>1</sub></em>,<em>field<sub>2</sub></em>,…,<em>field<sub>N</sub></em><b style="color: red;">\*CC</b><b style="color: red;">\\r\\n</b></code>
33 *
34 * Where:
35 *
36 * - The NMEA style framing:
37 * - <code><b style="color: red;">\$</b></code>
38 * -- Start character ("$", ASCII 36)
39 * - <code><b style="color: red;">\*CC</b></code>
40 * -- Checksum: "\*" (ASCII 42) and two digit XOR value of all payload
41 * characters in captial hexadecimal notation, for example:
42 * "FPX" = <code>'F' ^ 'P' ^ 'X' = 70 ^ 80 ^ 88 = 78 = 0x4e</code> = checksum <code>4E</code>
43 * - <code><b style="color: red;">\\r\\n</b></code>
44 * -- Sentence termination characters (CR + LF, ASCII 13 + 10)
45 * - A <code><b style="color: green;">Talker</b></code> ID -- Two capital characters:
46 * - `GP` -- Talker ID for GPS, also legacy resp. "compatibility"
47 * - `GL` -- Talker ID for GLONASS
48 * - `GA` -- Talker ID for Galileo
49 * - `GB` -- Talker ID for BeiDou
50 * - `GQ` -- Talker ID for QZSS
51 * - `GI` -- Talker ID for NavIC (IRNSS)
52 * - `GN` -- Talker ID for any combination of GNSS
53 * - A <code><b style="color: blue;">Formatter</b></code> ID -- Three capital characters, for example:
54 * - `RMC` for the message containing recommended minimum specific GNSS data
55 * - See the NMEA 0183 standard document for an extensive list
56 * - Data fields (payload)
57 * - <code><em>field<sub>1</sub></em>,<em>field<sub>2</sub></em>,…,<em>field<sub>N</sub></em></code>
58 * -- The structure of the message data is defined by the <code><b style="color: blue;">Formatter</b></code>.
59 * Each field can contain all printable 7-bit ASCII characters (ASCII 32–126), excluding the
60 * reserved characters `!` (ASCII 33), `$` (ASCII 36), `*` (ASCII 42), `,` (ASCII 44),
61 * `\` (ASCII 92), `~` (ASCII 126).
62 * - Field separators
63 * - All fields (identifier, message type, message version, data fields) are separated by a `,` (comma, ASCII 44)
64 * - Null fields
65 * - Data fields can be _null_, meaning their value is absent to indicate that no data is
66 * available. The data for null fields is the empty string. For example:
67 * - Definition: <code>…,<em>field<sub>i</sub></em>,<em>field<sub>i+1</sub></em>,<em>field<sub>i+2</sub></em>,…</code>
68 * - Values: <code><em>field<sub>i</sub></em></code> = 123, <code><em>field<sub>i+1</sub></em></code> = _null_,
69 * <code><em>field<sub>i+2</sub></em></code> = 456
70 * - Payload string: <code>…,123,,456,…</code>
71 * - Data field types:
72 * - See the NMEA 0183 standard document for specifications
73 *
74 * @fp_msgspec_end
75 *
76 */
77// clang-format on
78#ifndef __FPSDK_COMMON_PARSER_NMEA_HPP__
79#define __FPSDK_COMMON_PARSER_NMEA_HPP__
80
81/* LIBC/STL */
82#include <array>
83#include <cstdint>
84#include <memory>
85#include <string>
86#include <vector>
87
88/* EXTERNAL */
89
90/* PACKAGE */
91
92namespace fpsdk {
93namespace common {
94namespace parser {
95/**
96 * @brief Parser NMEA routines and types
97 */
98namespace nmea {
99/* ****************************************************************************************************************** */
100
101static constexpr uint8_t NMEA_PREAMBLE = '$'; //!< NMEA framing preamble
102static constexpr std::size_t NMEA_FRAME_SIZE = 6; //!< NMEA frame size ("$*cc\r\n")
103
104//! NMEA message meta data
106{
107 char talker_[3] = { 0 }; //!< Talker ID (for example, "GP", "GN" or "P"), nul-terminated string
108 char formatter_[20] = { 0 }; //!< Formatter (for example, "GGA", "RMC", or "UBX"), nul-terminated string
109 int payload_ix0_ = 0; //!< Index (offset) for start of payload, 0 if no payload available
110 int payload_ix1_ = 0; //!< Index (offset) for end of payload, 0 if no payload available
111};
112
113/**
114 * @brief Get NMEA message meta data
115 *
116 * @param[out] meta The meta data
117 * @param[in] msg Pointer to the NMEA message
118 * @param[in] msg_size Size of the NMEA message (>= 11)
119 *
120 * @note No check on the data provided is done. The caller must ensure that the data is a correct NMEA message.
121 *
122 * @returns true if the meta data was successfully extracted, false otherwise
123 */
124bool NmeaGetMessageMeta(NmeaMessageMeta& meta, const uint8_t* msg, const std::size_t msg_size);
125
126/**
127 * @brief Get NMEA message name
128 *
129 * Generates a name (string) in the form "NMEA-TALKER-FORMATTER" (for example, "NMEA-GP-GGA"). Some proprietary messages
130 * are recognised, for example, "NMEA-PUBX-POSITION".
131 *
132 * @param[out] name String to write the name to
133 * @param[in] size Size of \c name (incl. nul termination)
134 * @param[in] msg Pointer to the NMEA message
135 * @param[in] msg_size Size of the \c msg
136 *
137 * @note No check on the data provided is done. The caller must ensure that the data is a valid NMEA message.
138 *
139 * @returns true if message name was generated, false if \c name buffer was too small
140 */
141bool NmeaGetMessageName(char* name, const std::size_t size, const uint8_t* msg, const std::size_t msg_size);
142
143/**
144 * @brief Get NMEA message info
145 *
146 * This stringifies the content of some NMEA messages, for debugging.
147 *
148 * @param[out] info String to write the info to
149 * @param[in] size Size of \c name (incl. nul termination)
150 * @param[in] msg Pointer to the NMEA message
151 * @param[in] msg_size Size of the \c msg
152 *
153 * @note No check on the data provided is done. The caller must ensure that the data is a valid NMEA message.
154 *
155 * @returns true if message info was generated (even if info is empty), false if \c name buffer was too small
156 */
157bool NmeaGetMessageInfo(char* info, const std::size_t size, const uint8_t* msg, const std::size_t msg_size);
158
159/**
160 * @brief Make a NMEA message
161 *
162 * @param[out] msg The message frame
163 * @param[in] payload The message payload, including the talker ID and formatter
164 * (up to MAX_NMEA_SIZE - NMEA_FRAME_SIZE bytes, can be empty)
165 *
166 * @note Illegal (< 0x20 or > 0x7e) or reserved/special ('$', '\', '!', '~', '^' and '*') characters are replaced
167 * by a '_'.
168 *
169 * @returns true if the message was successfully constructed (\c msg now contains the message),
170 * false if failed contructing the message (payload too large)
171 */
172bool NmeaMakeMessage(std::vector<uint8_t>& msg, const std::string& payload);
173
174/**
175 * @brief Make a NMEA message
176 *
177 * @param[out] msg The message frame
178 * @param[in] payload The message payload, including the talker ID and formatter
179 * (up to MAX_NMEA_SIZE - NMEA_FRAME_SIZE bytes, can be empty)
180 *
181 * @note Illegal (< 0x20 or > 0x7e) or reserved/special ('$', '\', '!', '~', '^' and '*') characters are replaced
182 * by a '_'.
183 *
184 * @returns true if the message was successfully constructed (\c msg now contains the message),
185 * false if failed contructing the message (payload too large)
186 */
187bool NmeaMakeMessage(std::string& msg, const std::string& payload);
188
189/**
190 * @brief NMEA coordinates (integer degrees, float minutes and a sign for N/S resp. E/W)
191 */
193{
194 /**
195 * @brief Constructor
196 *
197 * @param[in] degs Decimal degrees
198 * @param[in] digits Number of digits (0-12), param clamped to range
199 */
200 NmeaCoordinates(const double degs, const int digits = 5);
201
202 int deg_; //!< Integer degrees value, >= 0
203 double min_; //!< Fractional minutes value, >= 0.0
204 bool sign_; //!< false for negative (S or W), true for positive (N or E)
205};
206
207// ---------------------------------------------------------------------------------------------------------------------
208
209/**
210 * @brief NMEA talker IDs
211 */
212enum class NmeaTalkerId : int
213{ // clang-format off
214 UNSPECIFIED = '!', //!< Unspecified
215 PROPRIETARY = 'x', //!< Proprietary
216 GPS_SBAS = 'P', //!< GPS and/or SBAS
217 GLO = 'L', //!< GLONASS
218 GAL = 'A', //!< GALILEO
219 BDS = 'B', //!< BeiDou
220 NAVIC = 'I', //!< NavIC
221 QZSS = 'Q', //!< QZSS
222 GNSS = 'N', //!< GNSS (multi-constellation)
223}; // clang-format on
224
225/**
226 * @brief NMEA-Gx-GGA quality indicator
227 */
228enum class NmeaQualityGga : int
229{ // clang-format off
230 UNSPECIFIED = '!', //!< Unspecified
231 NOFIX = '0', //!< No fix
232 SPP = '1', //!< Autonomous GNSS fix
233 DGNSS = '2', //!< Differential GPS fix (e.g. with SBAS)
234 PPS = '3', //!< PPS mode
235 RTK_FIXED = '4', //!< RTK fixed
236 RTK_FLOAT = '5', //!< RTK float
237 ESTIMATED = '6', //!< Estimated (dead reckoning only)
238 MANUAL = '7', //!< Manual input mode
239 SIM = '8', //!< Simulator
240}; // clang-format on
241
242/**
243 * @brief NMEA-Gx-GLL and NMEA-Gx-RMC status
244 *
245 * @note Do not use <, >, >=, <= operators on this!
246 */
247enum class NmeaStatusGllRmc : int
248{ // clang-format off
249 UNSPECIFIED = '!', //!< Unspecified
250 INVALID = 'V', //!< Data invalid
251 VALID = 'A', //!< Data valid
252 // DIFFERENTIAL = 'D', // @todo another possible value?
253}; // clang-format on
254
255/**
256 * @brief NMEA-Gx-GLL and NMEA-Gx-VTG pos mode
257 *
258 * @note Do not use <, >, >=, <= operators on this!
259 */
260enum class NmeaModeGllVtg : int
261{ // clang-format off
262 UNSPECIFIED = '!', //!< Unspecified
263 INVALID = 'N', //!< Invalid (no fix)
264 AUTONOMOUS = 'A', //!< Autonomous mode (SPP)
265 DGNSS = 'D', //!< Differential GNSS fix
266 ESTIMATED = 'E', //!< Estimated (dead reckoning only)
267 MANUAL = 'M', //!< Manual input mode
268 SIM = 'S', //!< Simulator mode
269}; // clang-format on
270
271/**
272 * @brief NMEA-Gx-RMC and NMEA-Gx-GNS pos mode
273 *
274 * @note Do not use <, >, >=, <= operators on this!
275 */
276enum class NmeaModeRmcGns : int
277{ // clang-format off
278 UNSPECIFIED = '!', //!< Unspecified
279 INVALID = 'N', //!< Invalid (no fix)
280 AUTONOMOUS = 'A', //!< Autonomous mode (SPP)
281 DGNSS = 'D', //!< Differential GNSS fix
282 ESTIMATED = 'E', //!< Estimated (dead reckoning only)
283 RTK_FIXED = 'R', //!< RTK fixed
284 RTK_FLOAT = 'F', //!< RTK float
285 PRECISE = 'P', //!< Precise
286 MANUAL = 'M', //!< Manual input mode
287 SIM = 'S', //!< Simulator mode
288}; // clang-format on
289
290/**
291 * @brief NMEA-Gx-RMC navigational status
292 *
293 * @note Do not use <, >, >=, <= operators on this!
294 */
295enum class NmeaNavStatusRmc : int
296{ // clang-format off
297 UNSPECIFIED = '!', //!< Unspecified
298 SAFE = 'S', //!< Safe
299 CAUTION = 'C', //!< Caution
300 UNSAFE = 'U', //!< Unsafe
301 NA = 'V', //!< Equipment does not provide navigational status
302}; // clang-format on
303
304/**
305 * @brief NMEA-Gx-GNS operation mode
306 *
307 * @note Do not use <, >, >=, <= operators on this!
308 */
309enum class NmeaOpModeGsa : int
310{ // clang-format off
311 UNSPECIFIED = '!', //!< Unspecified
312 MANUAL = 'M', //!< Manual
313 AUTO = 'A', //!< Automatic
314}; // clang-format on
315
316/**
317 * @brief NMEA-Gx-GNS nav mode
318 */
319enum class NmeaNavModeGsa : int
320{ // clang-format off
321 UNSPECIFIED = '!', //!< Unspecified
322 NOFIX = '1', //!< No fix
323 FIX2D = '2', //!< 2D fix
324 FIX3D = '3', //!< 3D fix
325}; // clang-format on
326
327/**
328 * @brief NMEA system IDs
329 *
330 * @note Do not use <, >, >=, <= operators on this!
331 */
332enum class NmeaSystemId : int
333{ // clang-format off
334 UNSPECIFIED = '!', //!< Unspecified
335 GPS_SBAS = '1', //!< GPS and/or SBAS
336 GLO = '2', //!< GLONASS
337 GAL = '3', //!< Galileo
338 BDS = '4', //!< BeiDou
339 QZSS = '5', //!< QZSS
340 NAVIC = '6', //!< NavIC
341}; // clang-format on
342
343/**
344 * @brief NMEA signal IDs
345 *
346 * @note Do not use <, >, >=, <= operators on this!
347 */
348enum class NmeaSignalId : int
349{ // clang-format off
350 UNSPECIFIED = 0x000 + '!', //!< Unspecified
351 NONE = 0x000 + '0', //!< None
352 GPS_L1CA = 0x100 + '1', //!< GPS L1 C/A or SBAS L1 C/A
353 GPS_L2CL = 0x100 + '6', //!< GPS L2 CL
354 GPS_L2CM = 0x100 + '5', //!< GPS L2 CM
355 GPS_L5I = 0x100 + '7', //!< GPS L5 I
356 GPS_L5Q = 0x100 + '8', //!< GPS L5 Q
357 GLO_L1OF = 0x200 + '1', //!< GLONASS L1 OF
358 GLO_L2OF = 0x200 + '3', //!< GLONASS L2 OF
359 GAL_E1 = 0x300 + '7', //!< Galileo E1
360 GAL_E5A = 0x300 + '1', //!< Galileo E5 A
361 GAL_E5B = 0x300 + '2', //!< Galileo E5 B
362 GAL_E6BC = 0x300 + '3', //!< Galileo E6 B/C
363 GAL_E6A = 0x300 + '4', //!< Galileo E6 A
364 BDS_B1ID = 0x400 + '1', //!< BeiDou B1I D
365 BDS_B2ID = 0x400 + 'B', //!< BeiDou B2I D
366 BDS_B1C = 0x400 + '3', //!< BeiDou B1 C
367 BDS_B2A = 0x400 + '5', //!< BeiDou B2 a
368 QZSS_L1CA = 0x500 + '1', //!< QZSS L1 C/A
369 QZSS_L1S = 0x500 + '4', //!< QZSS L1S
370 QZSS_L2CM = 0x500 + '5', //!< QZSS L2 CM
371 QZSS_L2CL = 0x500 + '6', //!< QZSS L2 CL
372 QZSS_L5I = 0x500 + '7', //!< QZSS L5 I
373 QZSS_L5Q = 0x500 + '8', //!< QZSS L5 Q
374 NAVIC_L5A = 0x600 + '5', //!< NavIC L5 A
375}; // clang-format on
376
377/**
378 * @brief NMEA time (hour, minutes, seconds)
379 */
381{
382 bool valid = false; //!< Data is valid
383 int hours = 0; //!< Hours
384 int mins = 0; //!< Minutes
385 double secs = 0.0; //!< Seconds
386
387 bool operator==(const NmeaTime& rhs) const; //!< Equal
388 bool operator!=(const NmeaTime& rhs) const; //!< Not equal
389};
390
391/**
392 * @brief NMEA date (year, month, day)
393 */
395{
396 bool valid = false; //!< Data is valid
397 int years = 0; //!< Year
398 int months = 0; //!< Month
399 int days = 0.0; //!< Day
400
401 bool operator==(const NmeaDate& rhs) const; //!< Equal
402 bool operator!=(const NmeaDate& rhs) const; //!< Not equal
403};
404
405/**
406 * @brief NMEA geodetic position
407 */
409{
410 bool latlon_valid = false; //!< Latitude/longitude is valid
411 double lat = 0.0; //!< Latitude [deg], >= 0.0 East, < 0.0 West
412 double lon = 0.0; //!< Longitude [deg], >= 0.0 North, < 0.0 South
413 bool height_valid = false; //!< Height is valid
414 double height = 0.0; //!< Ellipsoidal (!) height [m]
415};
416
417/**
418 * @brief NMEA satellite (used, e.g. in GSA)
419 */
421{
422 bool valid = false; //!< Data is valid
424 int svid = 0; //!< Satellite ID (numbering cf. NMEA 0183)
425};
426
427/**
428 * @brief Constants for different versions of NMEA
429 */
431{
432 const int svid_min_gps = -1; //!< Min GPS satellite ID
433 const int svid_max_gps = -1; //!< Max GPS satellite ID
434 const int svid_min_sbas = -1; //!< Min SBAS satellite ID
435 const int svid_max_sbas = -1; //!< Max SBAS satellite ID
436 const int svid_min_gal = -1; //!< Min Galileo satellite ID
437 const int svid_max_gal = -1; //!< Max Galileo satellite ID
438 const int svid_min_bds = -1; //!< Min BeiDou satellite ID
439 const int svid_max_bds = -1; //!< Max BeiDou satellite ID
440 const int svid_min_glo = -1; //!< Min GLONASS satellite ID
441 const int svid_max_glo = -1; //!< Max GLONASS satellite ID
442 const int svid_min_qzss = -1; //!< Min QZSS satellite ID, -1 if not available
443 const int svid_max_qzss = -1; //!< Max QZSS satellite ID, -1 if not available
444 const int svid_min_navic = -1; //!< Min NavIC satellite ID, -1 if not available
445 const int svid_max_navic = -1; //!< Max NavIC satellite ID, -1 if not available
446 static const NmeaVersion V410; //!< Value for NMEA v4.10
447 static const NmeaVersion V410_UBX_EXT; //!< Value for NMEA v4.10 extended (u-blox flavour)
448 static const NmeaVersion V411; //!< Value for NMEA v4.11
449};
450
451/**
452 * NMEA satellite position (GSA)
453 */
455{
456 bool valid = false; //!< Data is valid
458 int svid = 0; //!< Satellite ID (numbering cf. NMEA 0183)
459 int el = 0; //!< Elevation [deg] (-90..90)
460 int az = 0; //!< Azimuth [deg] (0..360)
461};
462
463/**
464 * NMEA signal levels (GSA)
465 */
467{
468 bool valid = false; //!< Data valid
470 int svid = 0; //!< Satellite ID (numbering cf. NMEA 0183)
472 int cno = 0; //!< Signal level [dBHz]
473};
474
475/**
476 * @brief NMEA integer value
477 */
479{
480 bool valid = false; //!< Data is valid
481 int value = 0; //!< Value
482};
483
484/**
485 * @brief NMEA float value
486 */
488{
489 bool valid = false; //!< Data is valid
490 double value = 0; //!< Value
491};
492
493/**
494 * @brief NMEA formatter
495 */
497{
498 UNSPECIFIED, //!< Unspecified
499 GGA, //!< Formatter GGA (NmeaGgaPayload)
500 GLL, //!< Formatter GLL (NmeaGllPayload)
501 RMC, //!< Formatter RMC (NmeaRmcPayload)
502 VTG, //!< Formatter VTG (NmeaVtgPayload)
503 GST, //!< Formatter GST (NmeaGstPayload)
504 HDT, //!< Formatter HDT (NmeaHdtPayload)
505 ZDA, //!< Formatter ZDA (NmeaZdaPayload)
506 GSA, //!< Formatter GSA (NmeaGsaPayload)
507 GSV, //!< Formatter GSV (NmeaGsvPayload)
508};
509
510/**
511 * @brief NMEA payload base class
512 */
514{
517 bool valid_ = false; //!< Payload successfully decoded (true), or not (yet) decoded (false)
518 virtual ~NmeaPayload() = default; //!< Virtual dtor for polymorphism
519
520 /**
521 * @brief Set data from message
522 *
523 * @param[in] msg Pointer to the NMEA message
524 * @param[in] msg_size Size of the NMEA message (>= 11)
525 *
526 * @returns true if sentence payload was correct and all data could be extracted (fields are now valid), or false
527 * otherwise (fields are now invalid)
528 */
529 virtual bool SetFromMsg(const uint8_t* msg, const std::size_t msg_size) = 0;
530
531 /**
532 * @brief Set data from message
533 *
534 * @param[in] buf The NMEA message data
535 *
536 * @returns true if message payload was correct and all data could be extracted (fields are now valid), or false
537 * otherwise (fields are now invalid)
538 */
539 inline bool SetFromBuf(const std::vector<uint8_t>& buf)
540 {
541 return SetFromMsg(buf.data(), buf.size());
542 }
543};
544
545/**
546 * @brief NMEA-Gx-GGA message payload
547 */
549{
550 NmeaTime time; //!< Time
551 NmeaLlh llh; //!< Position (with ellipsoidal height)
552 NmeaFloat height_msl; //!< Orthomeric height [m]
554 NmeaInt num_sv; //!< Number of satellites used (may be limited to 12)
555 NmeaFloat hdop; //!< Horizontal dilution of precision (only with valid fix)
556 NmeaFloat diff_age; //!< Differential data age (optional, NMEA 4.11 only)
557 NmeaInt diff_sta; //!< Differential station ID (optional, NMEA 4.11 only)
558
559 bool SetFromMsg(const uint8_t* msg, const std::size_t msg_size) final;
560
561 static constexpr const char* FORMATTER = "GGA"; //!< Formatter
562};
563
564/**
565 * @brief NMEA-Gx-GLL message payload
566 */
568{
569 NmeaLlh ll; //!< Position (no height)
570 NmeaTime time; //!< Time
571 NmeaStatusGllRmc status = NmeaStatusGllRmc::UNSPECIFIED; //!< Positioning system status
572 NmeaModeGllVtg mode = NmeaModeGllVtg::UNSPECIFIED; //!< Positioning system mode
573
574 bool SetFromMsg(const uint8_t* msg, const std::size_t msg_size) final;
575
576 static constexpr const char* FORMATTER = "GLL"; //!< Formatter
577};
578
579/**
580 * @brief NMEA-Gx-RMC message payload
581 */
583{
584 NmeaTime time; //!< Time
585 NmeaStatusGllRmc status = NmeaStatusGllRmc::UNSPECIFIED; //!< Positioning system status
586 NmeaLlh ll; //!< Position (no height)
587 NmeaFloat speed; //!< Speed over ground [knots]
588 NmeaFloat course; //!< Course over ground w.r.t. True North [deg]
589 NmeaDate date; //!< Date
590 NmeaModeRmcGns mode = NmeaModeRmcGns::UNSPECIFIED; //!< Positioning system mode indicator
591 NmeaNavStatusRmc navstatus = NmeaNavStatusRmc::UNSPECIFIED; //!< Navigational status (optional)
592
593 bool SetFromMsg(const uint8_t* msg, const std::size_t msg_size) final;
594
595 static constexpr const char* FORMATTER = "RMC"; //!< Formatter
596};
597
598/**
599 * @brief NMEA-Gx-VTG message payload
600 */
602{
603 NmeaFloat cogt; //!< Course over ground (true) [deg]
604 NmeaFloat cogm; //!< Course over ground (magnetic) [deg], not typically available
605 NmeaFloat sogn; //!< Speed over ground [knots]
606 NmeaFloat sogk; //!< Speed over ground [km/h]
607 NmeaModeGllVtg mode = NmeaModeGllVtg::UNSPECIFIED; //!< Positioning system mode
608
609 bool SetFromMsg(const uint8_t* msg, const std::size_t msg_size) final;
610
611 static constexpr const char* FORMATTER = "VTG"; //!< Talker
612};
613
614/**
615 * @brief NMEA-Gx-GST message payload
616 */
618{
619 NmeaTime time; //!< Time
620 NmeaFloat rms_range; //!< RMS value of the standard deviation of the range inputs to the navigation process
621 NmeaFloat std_major; //!< Standard deviation of semi-major axis of error ellipse
622 NmeaFloat std_minor; //!< Standard deviation of semi-minor axis of error ellipse
623 NmeaFloat angle_major; //!< Angle of semi-major axis of error ellipse from true North
624 NmeaFloat std_lat; //!< Standard deviation of latitude error
625 NmeaFloat std_lon; //!< Standard deviation of longitude error
626 NmeaFloat std_alt; //!< Standard deviation of altitude error
627
628 bool SetFromMsg(const uint8_t* msg, const std::size_t msg_size) final;
629
630 static constexpr const char* FORMATTER = "GST"; //!< Formatter
631};
632
633/**
634 * @brief NMEA-Gx-HDT message payload
635 */
637{
638 NmeaFloat heading; //!< True heading
639
640 bool SetFromMsg(const uint8_t* msg, const std::size_t msg_size) final;
641
642 static constexpr const char* FORMATTER = "HDT"; //!< Formatter
643};
644
645/**
646 * @brief NMEA-Gx-ZDA message payload
647 */
649{
650 NmeaTime time; //!< Time
651 NmeaDate date; //!< Date
652 NmeaInt local_hr; //!< Local zone hours, always 00 (= UTC)
653 NmeaInt local_min; //!< Local zone minutes, always 00 (= UTC)
654
655 bool SetFromMsg(const uint8_t* msg, const std::size_t msg_size) final;
656
657 static constexpr const char* FORMATTER = "ZDA"; //!< Formatter
658};
659
660/**
661 * @brief NMEA-Gx-GSA message payload (NMEA 4.11 only!)
662 */
664{
667 std::array<NmeaSat, 12> sats; //!< Satellites, valid ones are 0..(num_sats-1)
668 int num_sats = 0; //!< Number of valid sats (the first n of sats[])
669 NmeaFloat pdop; //!< PDOP
670 NmeaFloat hdop; //!< HDOP
671 NmeaFloat vdop; //!< VDOP
673
674 bool SetFromMsg(const uint8_t* msg, const std::size_t msg_size) final;
675
676 static constexpr const char* FORMATTER = "GSA"; //!< Formatter
677};
678
679/**
680 * @brief NMEA-Gx-GSV message payload (NMEA 4.11 only!)
681 */
683{
684 NmeaInt num_msgs; //!< Number of messages in this GSV sequence (for this signal ID)
685 NmeaInt msg_num; //!< Message number in sequence (1...num_msgs)
686 NmeaInt tot_num_sat; //!< Number of sat/sig info in the whole sequence of GSV messages
687 std::array<NmeaAzEl, 4> azels; //!< Satellite positions, valid ones are 0..(num_sats-1)
688 int num_azels = 0; //!< Number of valid satellite positions (the first n of azels[])
689 std::array<NmeaCno, 4> cnos; //!< Signal levels, valid ones are 0..(num_sats-1)
690 int num_cnos = 0; //!< Number of valid signal levels (the first n of azels[])
691 NmeaSystemId system; //!< System ID
692 NmeaSignalId signal; //!< Signal ID
693
694 bool SetFromMsg(const uint8_t* msg, const std::size_t msg_size) final;
695
696 static constexpr const char* FORMATTER = "GSV"; //!< Formatter
697};
698
699// ---------------------------------------------------------------------------------------------------------------------
700
701//! Pointer to NMEA payload
702using NmeaPayloadPtr = std::unique_ptr<NmeaPayload>;
703
704/**
705 * @brief Decode NMEA message
706 *
707 * @param[in] msg Pointer to the NMEA message
708 * @param[in] msg_size Size of the NMEA message (>= 11)
709 *
710 * @returns an instance of the decoded payload on success, nullptr otherwise (bad or unknown message)
711 */
712NmeaPayloadPtr NmeaDecodeMessage(const uint8_t* msg, const std::size_t msg_size);
713
714/**
715 * @brief Decode NMEA message
716 *
717 * @param[in] msg The NMEA message data
718 *
719 * @returns an instance of the decoded payload on success, nullptr otherwise (bad or unknown message)
720 */
721inline NmeaPayloadPtr NmeaDecodeMessage(const std::vector<uint8_t>& msg)
722{
723 return NmeaDecodeMessage(msg.data(), msg.size());
724}
725
726// ---------------------------------------------------------------------------------------------------------------------
727
728/**
729 * @brief Collector for NMEA-Gx-GSA and NMEA-Gx-GPA
730 */
732{
733 /**
734 * @brief Satellite info
735 */
736 struct Sat
737 {
739 int svid_ = 0; //!< Satellite ID (numbering cf. NMEA 0183)
740 int az_ = 0; //!< Azimuth [deg] (0..360)
741 int el_ = 0; //!< Elevation [deg] (-90..90)
742 };
743
744 /**
745 * Signal info
746 */
747 struct Sig
748 {
750 int svid_ = 0; //!< Satellite ID (numbering cf. NMEA 0183)
752 double cno_ = 0.0; //!< Signal level [dBHz]
753 bool used_ = false; //!< Signal is used in navigation
754 };
755
756 std::vector<Sat> sats_; //!< Collected satellite info
757 std::vector<Sig> sigs_; //!< Collected signal info
758
759 /**
760 * @brief Add NMEA-GN-GSA message to collection
761 *
762 * These must be provided in order and completely, and before the GSV messages.
763 *
764 * @param[in] gsa Decoded message payload
765 *
766 * @returns true if the message was accepted, false otherwise
767 */
768 bool AddGsa(const NmeaGsaPayload& gsa);
769
770 /**
771 * @brief Add NMEA-Gx-GSV message to collection
772 *
773 * These must be provided in order and completely, and after the GSA messages.
774 *
775 * @param[in] gsv Decoded message payload
776 *
777 * @returns true if the message was accepted, false otherwise
778 */
779 bool AddGsv(const NmeaGsvPayload& gsv);
780
781 /**
782 * @brief Complete collection after feeding all GSA and GSV messages
783 */
784 void Complete();
785
786 /**
787 * @brief Add NMEA-GN-GSA and NMEA-Gx-GSV messages to collection
788 *
789 * Does all of AddGsa(), AddGsv() and Complete() in one call.
790 *
791 * @param[in] gsas All decoded message payloads, complete and in order
792 * @param[in] gsvs All decoded message payloads, complete and in order
793 *
794 * @returns true if all messages were collected successfully
795 */
796 bool AddGsaAndGsv(const std::vector<NmeaGsaPayload>& gsas, const std::vector<NmeaGsvPayload>& gsvs);
797
798 private:
799 std::vector<NmeaSat> gsa_sats_; //!< Satellites used
800};
801
802/* ****************************************************************************************************************** */
803} // namespace nmea
804} // namespace parser
805} // namespace common
806} // namespace fpsdk
807#endif // __FPSDK_COMMON_PARSER_NMEA_HPP__
Parser NMEA routines and types.
Definition nmea.hpp:98
NmeaSystemId
NMEA system IDs.
Definition nmea.hpp:333
NmeaModeRmcGns
NMEA-Gx-RMC and NMEA-Gx-GNS pos mode.
Definition nmea.hpp:277
static constexpr std::size_t NMEA_FRAME_SIZE
NMEA frame size ("$*cc\r\n")
Definition nmea.hpp:102
bool NmeaMakeMessage(std::vector< uint8_t > &msg, const std::string &payload)
Make a NMEA message.
NmeaOpModeGsa
NMEA-Gx-GNS operation mode.
Definition nmea.hpp:310
NmeaNavStatusRmc
NMEA-Gx-RMC navigational status.
Definition nmea.hpp:296
@ NA
Equipment does not provide navigational status.
Definition nmea.hpp:301
NmeaPayloadPtr NmeaDecodeMessage(const uint8_t *msg, const std::size_t msg_size)
Decode NMEA message.
static constexpr uint8_t NMEA_PREAMBLE
NMEA framing preamble.
Definition nmea.hpp:101
NmeaModeGllVtg
NMEA-Gx-GLL and NMEA-Gx-VTG pos mode.
Definition nmea.hpp:261
NmeaFormatter
NMEA formatter.
Definition nmea.hpp:497
@ ZDA
Formatter ZDA (NmeaZdaPayload)
Definition nmea.hpp:505
@ HDT
Formatter HDT (NmeaHdtPayload)
Definition nmea.hpp:504
@ RMC
Formatter RMC (NmeaRmcPayload)
Definition nmea.hpp:501
@ GGA
Formatter GGA (NmeaGgaPayload)
Definition nmea.hpp:499
@ GST
Formatter GST (NmeaGstPayload)
Definition nmea.hpp:503
@ GSV
Formatter GSV (NmeaGsvPayload)
Definition nmea.hpp:507
@ GSA
Formatter GSA (NmeaGsaPayload)
Definition nmea.hpp:506
@ GLL
Formatter GLL (NmeaGllPayload)
Definition nmea.hpp:500
@ VTG
Formatter VTG (NmeaVtgPayload)
Definition nmea.hpp:502
NmeaNavModeGsa
NMEA-Gx-GNS nav mode.
Definition nmea.hpp:320
NmeaTalkerId
NMEA talker IDs.
Definition nmea.hpp:213
@ GNSS
GNSS (multi-constellation)
Definition nmea.hpp:222
std::unique_ptr< NmeaPayload > NmeaPayloadPtr
Pointer to NMEA payload.
Definition nmea.hpp:702
NmeaStatusGllRmc
NMEA-Gx-GLL and NMEA-Gx-RMC status.
Definition nmea.hpp:248
bool NmeaGetMessageInfo(char *info, const std::size_t size, const uint8_t *msg, const std::size_t msg_size)
Get NMEA message info.
bool NmeaGetMessageMeta(NmeaMessageMeta &meta, const uint8_t *msg, const std::size_t msg_size)
Get NMEA message meta data.
NmeaSignalId
NMEA signal IDs.
Definition nmea.hpp:349
@ GPS_L1CA
GPS L1 C/A or SBAS L1 C/A.
Definition nmea.hpp:352
bool NmeaGetMessageName(char *name, const std::size_t size, const uint8_t *msg, const std::size_t msg_size)
Get NMEA message name.
NmeaQualityGga
NMEA-Gx-GGA quality indicator.
Definition nmea.hpp:229
@ DGNSS
Differential GPS fix (e.g. with SBAS)
Definition nmea.hpp:233
@ ESTIMATED
Estimated (dead reckoning only)
Definition nmea.hpp:237
Fixposition SDK: Common library.
Definition doc.hpp:21
Fixposition SDK.
NmeaSystemId system
System ID.
Definition nmea.hpp:457
int az
Azimuth [deg] (0..360)
Definition nmea.hpp:460
int el
Elevation [deg] (-90..90)
Definition nmea.hpp:459
int svid
Satellite ID (numbering cf. NMEA 0183)
Definition nmea.hpp:458
int cno
Signal level [dBHz].
Definition nmea.hpp:472
NmeaSignalId signal
Signal ID.
Definition nmea.hpp:471
int svid
Satellite ID (numbering cf. NMEA 0183)
Definition nmea.hpp:470
NmeaSystemId system
System ID.
Definition nmea.hpp:469
int svid_
Satellite ID (numbering cf. NMEA 0183)
Definition nmea.hpp:739
int svid_
Satellite ID (numbering cf. NMEA 0183)
Definition nmea.hpp:750
bool used_
Signal is used in navigation.
Definition nmea.hpp:753
Collector for NMEA-Gx-GSA and NMEA-Gx-GPA.
Definition nmea.hpp:732
bool AddGsa(const NmeaGsaPayload &gsa)
Add NMEA-GN-GSA message to collection.
std::vector< Sat > sats_
Collected satellite info.
Definition nmea.hpp:756
bool AddGsv(const NmeaGsvPayload &gsv)
Add NMEA-Gx-GSV message to collection.
std::vector< Sig > sigs_
Collected signal info.
Definition nmea.hpp:757
bool AddGsaAndGsv(const std::vector< NmeaGsaPayload > &gsas, const std::vector< NmeaGsvPayload > &gsvs)
Add NMEA-GN-GSA and NMEA-Gx-GSV messages to collection.
void Complete()
Complete collection after feeding all GSA and GSV messages.
double min_
Fractional minutes value, >= 0.0.
Definition nmea.hpp:203
NmeaCoordinates(const double degs, const int digits=5)
Constructor.
bool sign_
false for negative (S or W), true for positive (N or E)
Definition nmea.hpp:204
int deg_
Integer degrees value, >= 0.
Definition nmea.hpp:202
NMEA date (year, month, day)
Definition nmea.hpp:395
bool operator==(const NmeaDate &rhs) const
Equal.
bool operator!=(const NmeaDate &rhs) const
Not equal.
NMEA-Gx-GGA message payload.
Definition nmea.hpp:549
static constexpr const char * FORMATTER
Formatter.
Definition nmea.hpp:561
NmeaFloat diff_age
Differential data age (optional, NMEA 4.11 only)
Definition nmea.hpp:556
NmeaLlh llh
Position (with ellipsoidal height)
Definition nmea.hpp:551
bool SetFromMsg(const uint8_t *msg, const std::size_t msg_size) final
Set data from message.
NmeaFloat height_msl
Orthomeric height [m].
Definition nmea.hpp:552
NmeaFloat hdop
Horizontal dilution of precision (only with valid fix)
Definition nmea.hpp:555
NmeaQualityGga quality
Fix quality.
Definition nmea.hpp:553
NmeaInt diff_sta
Differential station ID (optional, NMEA 4.11 only)
Definition nmea.hpp:557
NmeaInt num_sv
Number of satellites used (may be limited to 12)
Definition nmea.hpp:554
NMEA-Gx-GLL message payload.
Definition nmea.hpp:568
bool SetFromMsg(const uint8_t *msg, const std::size_t msg_size) final
Set data from message.
NmeaLlh ll
Position (no height)
Definition nmea.hpp:569
static constexpr const char * FORMATTER
Formatter.
Definition nmea.hpp:576
NmeaStatusGllRmc status
Positioning system status.
Definition nmea.hpp:571
NmeaModeGllVtg mode
Positioning system mode.
Definition nmea.hpp:572
NMEA-Gx-GSA message payload (NMEA 4.11 only!)
Definition nmea.hpp:664
static constexpr const char * FORMATTER
Formatter.
Definition nmea.hpp:676
NmeaOpModeGsa opmode
Operation mode.
Definition nmea.hpp:665
int num_sats
Number of valid sats (the first n of sats[])
Definition nmea.hpp:668
bool SetFromMsg(const uint8_t *msg, const std::size_t msg_size) final
Set data from message.
std::array< NmeaSat, 12 > sats
Satellites, valid ones are 0..(num_sats-1)
Definition nmea.hpp:667
NMEA-Gx-GST message payload.
Definition nmea.hpp:618
NmeaFloat angle_major
Angle of semi-major axis of error ellipse from true North.
Definition nmea.hpp:623
NmeaFloat std_lat
Standard deviation of latitude error.
Definition nmea.hpp:624
NmeaFloat std_alt
Standard deviation of altitude error.
Definition nmea.hpp:626
static constexpr const char * FORMATTER
Formatter.
Definition nmea.hpp:630
NmeaFloat std_lon
Standard deviation of longitude error.
Definition nmea.hpp:625
NmeaFloat std_major
Standard deviation of semi-major axis of error ellipse.
Definition nmea.hpp:621
NmeaFloat rms_range
RMS value of the standard deviation of the range inputs to the navigation process.
Definition nmea.hpp:620
NmeaFloat std_minor
Standard deviation of semi-minor axis of error ellipse.
Definition nmea.hpp:622
bool SetFromMsg(const uint8_t *msg, const std::size_t msg_size) final
Set data from message.
NMEA-Gx-GSV message payload (NMEA 4.11 only!)
Definition nmea.hpp:683
int num_azels
Number of valid satellite positions (the first n of azels[])
Definition nmea.hpp:688
NmeaInt tot_num_sat
Number of sat/sig info in the whole sequence of GSV messages.
Definition nmea.hpp:686
NmeaInt num_msgs
Number of messages in this GSV sequence (for this signal ID)
Definition nmea.hpp:684
NmeaInt msg_num
Message number in sequence (1...num_msgs)
Definition nmea.hpp:685
std::array< NmeaAzEl, 4 > azels
Satellite positions, valid ones are 0..(num_sats-1)
Definition nmea.hpp:687
bool SetFromMsg(const uint8_t *msg, const std::size_t msg_size) final
Set data from message.
std::array< NmeaCno, 4 > cnos
Signal levels, valid ones are 0..(num_sats-1)
Definition nmea.hpp:689
int num_cnos
Number of valid signal levels (the first n of azels[])
Definition nmea.hpp:690
static constexpr const char * FORMATTER
Formatter.
Definition nmea.hpp:696
NMEA-Gx-HDT message payload.
Definition nmea.hpp:637
static constexpr const char * FORMATTER
Formatter.
Definition nmea.hpp:642
bool SetFromMsg(const uint8_t *msg, const std::size_t msg_size) final
Set data from message.
NMEA geodetic position.
Definition nmea.hpp:409
double height
Ellipsoidal (!) height [m].
Definition nmea.hpp:414
bool latlon_valid
Latitude/longitude is valid.
Definition nmea.hpp:410
double lon
Longitude [deg], >= 0.0 North, < 0.0 South.
Definition nmea.hpp:412
double lat
Latitude [deg], >= 0.0 East, < 0.0 West.
Definition nmea.hpp:411
bool height_valid
Height is valid.
Definition nmea.hpp:413
char talker_[3]
Talker ID (for example, "GP", "GN" or "P"), nul-terminated string.
Definition nmea.hpp:107
char formatter_[20]
Formatter (for example, "GGA", "RMC", or "UBX"), nul-terminated string.
Definition nmea.hpp:108
int payload_ix1_
Index (offset) for end of payload, 0 if no payload available.
Definition nmea.hpp:110
int payload_ix0_
Index (offset) for start of payload, 0 if no payload available.
Definition nmea.hpp:109
NMEA payload base class.
Definition nmea.hpp:514
virtual bool SetFromMsg(const uint8_t *msg, const std::size_t msg_size)=0
Set data from message.
bool valid_
Payload successfully decoded (true), or not (yet) decoded (false)
Definition nmea.hpp:517
bool SetFromBuf(const std::vector< uint8_t > &buf)
Set data from message.
Definition nmea.hpp:539
virtual ~NmeaPayload()=default
Virtual dtor for polymorphism.
NmeaFormatter formatter_
Formatter.
Definition nmea.hpp:516
NMEA-Gx-RMC message payload.
Definition nmea.hpp:583
NmeaStatusGllRmc status
Positioning system status.
Definition nmea.hpp:585
NmeaLlh ll
Position (no height)
Definition nmea.hpp:586
NmeaNavStatusRmc navstatus
Navigational status (optional)
Definition nmea.hpp:591
static constexpr const char * FORMATTER
Formatter.
Definition nmea.hpp:595
NmeaModeRmcGns mode
Positioning system mode indicator.
Definition nmea.hpp:590
NmeaFloat speed
Speed over ground [knots].
Definition nmea.hpp:587
bool SetFromMsg(const uint8_t *msg, const std::size_t msg_size) final
Set data from message.
NmeaFloat course
Course over ground w.r.t. True North [deg].
Definition nmea.hpp:588
NMEA satellite (used, e.g. in GSA)
Definition nmea.hpp:421
int svid
Satellite ID (numbering cf. NMEA 0183)
Definition nmea.hpp:424
NmeaSystemId system
System ID.
Definition nmea.hpp:423
NMEA time (hour, minutes, seconds)
Definition nmea.hpp:381
bool operator==(const NmeaTime &rhs) const
Equal.
bool operator!=(const NmeaTime &rhs) const
Not equal.
Constants for different versions of NMEA.
Definition nmea.hpp:431
const int svid_max_glo
Max GLONASS satellite ID.
Definition nmea.hpp:441
const int svid_max_gps
Max GPS satellite ID.
Definition nmea.hpp:433
const int svid_min_sbas
Min SBAS satellite ID.
Definition nmea.hpp:434
const int svid_min_bds
Min BeiDou satellite ID.
Definition nmea.hpp:438
const int svid_min_navic
Min NavIC satellite ID, -1 if not available.
Definition nmea.hpp:444
static const NmeaVersion V410
Value for NMEA v4.10.
Definition nmea.hpp:446
const int svid_max_qzss
Max QZSS satellite ID, -1 if not available.
Definition nmea.hpp:443
const int svid_min_qzss
Min QZSS satellite ID, -1 if not available.
Definition nmea.hpp:442
const int svid_min_gps
Min GPS satellite ID.
Definition nmea.hpp:432
const int svid_min_gal
Min Galileo satellite ID.
Definition nmea.hpp:436
const int svid_max_gal
Max Galileo satellite ID.
Definition nmea.hpp:437
const int svid_max_sbas
Max SBAS satellite ID.
Definition nmea.hpp:435
static const NmeaVersion V410_UBX_EXT
Value for NMEA v4.10 extended (u-blox flavour)
Definition nmea.hpp:447
const int svid_max_navic
Max NavIC satellite ID, -1 if not available.
Definition nmea.hpp:445
const int svid_min_glo
Min GLONASS satellite ID.
Definition nmea.hpp:440
static const NmeaVersion V411
Value for NMEA v4.11.
Definition nmea.hpp:448
const int svid_max_bds
Max BeiDou satellite ID.
Definition nmea.hpp:439
NMEA-Gx-VTG message payload.
Definition nmea.hpp:602
NmeaFloat cogt
Course over ground (true) [deg].
Definition nmea.hpp:603
bool SetFromMsg(const uint8_t *msg, const std::size_t msg_size) final
Set data from message.
NmeaModeGllVtg mode
Positioning system mode.
Definition nmea.hpp:607
NmeaFloat sogk
Speed over ground [km/h].
Definition nmea.hpp:606
static constexpr const char * FORMATTER
Talker.
Definition nmea.hpp:611
NmeaFloat sogn
Speed over ground [knots].
Definition nmea.hpp:605
NmeaFloat cogm
Course over ground (magnetic) [deg], not typically available.
Definition nmea.hpp:604
NMEA-Gx-ZDA message payload.
Definition nmea.hpp:649
NmeaInt local_hr
Local zone hours, always 00 (= UTC)
Definition nmea.hpp:652
static constexpr const char * FORMATTER
Formatter.
Definition nmea.hpp:657
bool SetFromMsg(const uint8_t *msg, const std::size_t msg_size) final
Set data from message.
NmeaInt local_min
Local zone minutes, always 00 (= UTC)
Definition nmea.hpp:653