Fixposition SDK 0.0.0-heads/main-0-g90a51ff
Collection of c++ libraries and apps for use with Fixposition products
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 <string>
85#include <vector>
86
87/* EXTERNAL */
88
89/* PACKAGE */
90
91namespace fpsdk {
92namespace common {
93namespace parser {
94/**
95 * @brief Parser NMEA routines and types
96 */
97namespace nmea {
98/* ****************************************************************************************************************** */
99
100static constexpr uint8_t NMEA_PREAMBLE = '$'; //!< NMEA framing preamble
101static constexpr std::size_t NMEA_FRAME_SIZE = 6; //!< NMEA frame size ("$*cc\r\n")
102
103//! NMEA message meta data
105{
106 char talker_[3] = { 0 }; //!< Talker ID (for example, "GP", "GN" or "P"), nul-terminated string
107 char formatter_[20] = { 0 }; //!< Formatter (for example, "GGA", "RMC", or "UBX"), nul-terminated string
108 int payload_ix0_ = 0; //!< Index (offset) for start of payload, 0 if no payload available
109 int payload_ix1_ = 0; //!< Index (offset) for end of payload, 0 if no payload available
110};
111
112/**
113 * @brief Get NMEA message meta data
114 *
115 * @param[out] meta The meta data
116 * @param[in] msg Pointer to the NMEA message
117 * @param[in] msg_size Size of the NMEA message (>= 11)
118 *
119 * @note No check on the data provided is done. The caller must ensure that the data is a correct NMEA message.
120 *
121 * @returns true if the meta data was successfully extracted, false otherwise
122 */
123bool NmeaGetMessageMeta(NmeaMessageMeta& meta, const uint8_t* msg, const std::size_t msg_size);
124
125/**
126 * @brief Get NMEA message name
127 *
128 * Generates a name (string) in the form "NMEA-TALKER-FORMATTER" (for example, "NMEA-GP-GGA"). Some proprietary messages
129 * are recognised, for example, "NMEA-PUBX-POSITION".
130 *
131 * @param[out] name String to write the name to
132 * @param[in] size Size of \c name (incl. nul termination)
133 * @param[in] msg Pointer to the NMEA message
134 * @param[in] msg_size Size of the \c msg
135 *
136 * @note No check on the data provided is done. The caller must ensure that the data is a valid NMEA message.
137 *
138 * @returns true if message name was generated, false if \c name buffer was too small
139 */
140bool NmeaGetMessageName(char* name, const std::size_t size, const uint8_t* msg, const std::size_t msg_size);
141
142/**
143 * @brief Get NMEA message info
144 *
145 * This stringifies the content of some NMEA messages, for debugging.
146 *
147 * @param[out] info String to write the info to
148 * @param[in] size Size of \c name (incl. nul termination)
149 * @param[in] msg Pointer to the NMEA message
150 * @param[in] msg_size Size of the \c msg
151 *
152 * @note No check on the data provided is done. The caller must ensure that the data is a valid NMEA message.
153 *
154 * @returns true if message info was generated (even if info is empty), false if \c name buffer was too small
155 */
156bool NmeaGetMessageInfo(char* info, const std::size_t size, const uint8_t* msg, const std::size_t msg_size);
157
158/**
159 * @brief NMEA coordinates (integer degrees, float minutes and a sign for N/S resp. E/W)
160 */
162{
163 /**
164 * @brief Constructor
165 *
166 * @param[in] degs Decimal degrees
167 * @param[in] digits Number of digits (0-12), param clamped to range
168 */
169 NmeaCoordinates(const double degs, const int digits = 5);
170
171 int deg_; //!< Integer degrees value, >= 0
172 double min_; //!< Fractional minutes value, >= 0.0
173 bool sign_; //!< false for negative (S or W), true for positive (N or E)
174};
175
176// ---------------------------------------------------------------------------------------------------------------------
177
178/**
179 * @brief NMEA talker IDs
180 */
181enum class NmeaTalkerId : int
182{ // clang-format off
183 UNSPECIFIED = '!', //!< Unspecified
184 PROPRIETARY = 'x', //!< Proprietary
185 GPS_SBAS = 'P', //!< GPS and/or SBAS
186 GLO = 'L', //!< GLONASS
187 GAL = 'A', //!< GALILEO
188 BDS = 'B', //!< BeiDou
189 NAVIC = 'I', //!< NavIC
190 QZSS = 'Q', //!< QZSS
191 GNSS = 'N', //!< GNSS (multi-constellation)
192}; // clang-format on
193
194/**
195 * @brief NMEA-Gx-GGA quality indicator
196 */
197enum class NmeaQualityGga : int
198{ // clang-format off
199 UNSPECIFIED = '!', //!< Unspecified
200 NOFIX = '0', //!< No fix
201 SPP = '1', //!< Autonomous GNSS fix
202 DGNSS = '2', //!< Differential GPS fix (e.g. with SBAS)
203 PPS = '3', //!< PPS mode
204 RTK_FIXED = '4', //!< RTK fixed
205 RTK_FLOAT = '5', //!< RTK float
206 ESTIMATED = '6', //!< Estimated (dead reckoning only)
207 MANUAL = '7', //!< Manual input mode
208 SIM = '8', //!< Simulator
209}; // clang-format on
210
211/**
212 * @brief NMEA-Gx-GLL and NMEA-Gx-RMC status
213 *
214 * @note Do not use <, >, >=, <= operators on this!
215 */
216enum class NmeaStatusGllRmc : int
217{ // clang-format off
218 UNSPECIFIED = '!', //!< Unspecified
219 INVALID = 'V', //!< Data invalid
220 VALID = 'A', //!< Data valid
221 // DIFFERENTIAL = 'D', // @todo another possible value?
222}; // clang-format on
223
224/**
225 * @brief NMEA-Gx-GLL and NMEA-Gx-VTG pos mode
226 *
227 * @note Do not use <, >, >=, <= operators on this!
228 */
229enum class NmeaModeGllVtg : int
230{ // clang-format off
231 UNSPECIFIED = '!', //!< Unspecified
232 INVALID = 'N', //!< Invalid (no fix)
233 AUTONOMOUS = 'A', //!< Autonomous mode (SPP)
234 DGNSS = 'D', //!< Differential GNSS fix
235 ESTIMATED = 'E', //!< Estimated (dead reckoning only)
236 MANUAL = 'M', //!< Manual input mode
237 SIM = 'S', //!< Simulator mode
238}; // clang-format on
239
240/**
241 * @brief NMEA-Gx-RMC and NMEA-Gx-GNS pos mode
242 *
243 * @note Do not use <, >, >=, <= operators on this!
244 */
245enum class NmeaModeRmcGns : int
246{ // clang-format off
247 UNSPECIFIED = '!', //!< Unspecified
248 INVALID = 'N', //!< Invalid (no fix)
249 AUTONOMOUS = 'A', //!< Autonomous mode (SPP)
250 DGNSS = 'D', //!< Differential GNSS fix
251 ESTIMATED = 'E', //!< Estimated (dead reckoning only)
252 RTK_FIXED = 'R', //!< RTK fixed
253 RTK_FLOAT = 'F', //!< RTK float
254 PRECISE = 'P', //!< Precise
255 MANUAL = 'M', //!< Manual input mode
256 SIM = 'S', //!< Simulator mode
257}; // clang-format on
258
259/**
260 * @brief NMEA-Gx-RMC navigational status
261 *
262 * @note Do not use <, >, >=, <= operators on this!
263 */
264enum class NmeaNavStatusRmc : int
265{ // clang-format off
266 UNSPECIFIED = '!', //!< Unspecified
267 SAFE = 'S', //!< Safe
268 CAUTION = 'C', //!< Caution
269 UNSAFE = 'U', //!< Unsafe
270 NA = 'V', //!< Equipment does not provide navigational status
271}; // clang-format on
272
273/**
274 * @brief NMEA-Gx-GNS operation mode
275 *
276 * @note Do not use <, >, >=, <= operators on this!
277 */
278enum class NmeaOpModeGsa : int
279{ // clang-format off
280 UNSPECIFIED = '!', //!< Unspecified
281 MANUAL = 'M', //!< Manual
282 AUTO = 'A', //!< Automatic
283}; // clang-format on
284
285/**
286 * @brief NMEA-Gx-GNS nav mode
287 */
288enum class NmeaNavModeGsa : int
289{ // clang-format off
290 UNSPECIFIED = '!', //!< Unspecified
291 NOFIX = '1', //!< No fix
292 FIX2D = '2', //!< 2D fix
293 FIX3D = '3', //!< 3D fix
294}; // clang-format on
295
296/**
297 * @brief NMEA system IDs
298 *
299 * @note Do not use <, >, >=, <= operators on this!
300 */
301enum class NmeaSystemId : int
302{ // clang-format off
303 UNSPECIFIED = '!', //!< Unspecified
304 GPS_SBAS = '1', //!< GPS and/or SBAS
305 GLO = '2', //!< GLONASS
306 GAL = '3', //!< Galileo
307 BDS = '4', //!< BeiDou
308 QZSS = '5', //!< QZSS
309 NAVIC = '6', //!< NavIC
310}; // clang-format on
311
312/**
313 * @brief NMEA signal IDs
314 *
315 * @note Do not use <, >, >=, <= operators on this!
316 */
317enum class NmeaSignalId : int
318{ // clang-format off
319 UNSPECIFIED = 0x000 + '!', //!< Unspecified
320 NONE = 0x000 + '0', //!< None
321 GPS_L1CA = 0x100 + '1', //!< GPS L1 C/A or SBAS L1 C/A
322 GPS_L2CL = 0x100 + '6', //!< GPS L2 CL
323 GPS_L2CM = 0x100 + '5', //!< GPS L2 CM
324 GPS_L5I = 0x100 + '7', //!< GPS L5 I
325 GPS_L5Q = 0x100 + '8', //!< GPS L5 Q
326 GLO_L1OF = 0x200 + '1', //!< GLONASS L1 OF
327 GLO_L2OF = 0x200 + '3', //!< GLONASS L2 OF
328 GAL_E1 = 0x300 + '7', //!< Galileo E1
329 GAL_E5A = 0x300 + '1', //!< Galileo E5 A
330 GAL_E5B = 0x300 + '2', //!< Galileo E5 B
331 BDS_B1ID = 0x400 + '1', //!< BeiDou B1I D
332 BDS_B2ID = 0x400 + 'B', //!< BeiDou B2I D
333 BDS_B1C = 0x400 + '3', //!< BeiDou B1 C
334 BDS_B2A = 0x400 + '5', //!< BeiDou B2 a
335 QZSS_L1CA = 0x500 + '1', //!< QZSS L1 C/A
336 QZSS_L1S = 0x500 + '4', //!< QZSS L1S
337 QZSS_L2CM = 0x500 + '5', //!< QZSS L2 CM
338 QZSS_L2CL = 0x500 + '6', //!< QZSS L2 CL
339 QZSS_L5I = 0x500 + '7', //!< QZSS L5 I
340 QZSS_L5Q = 0x500 + '8', //!< QZSS L5 Q
341 NAVIC_L5A = 0x600 + '5', //!< NavIC L5 A
342}; // clang-format on
343
344/**
345 * @brief NMEA time (hour, minutes, seconds)
346 */
348{
349 bool valid = false; //!< Data is valid
350 int hours = 0; //!< Hours
351 int mins = 0; //!< Minutes
352 double secs = 0.0; //!< Seconds
353
354 bool operator==(const NmeaTime& rhs) const; //!< Equal
355 bool operator!=(const NmeaTime& rhs) const; //!< Not equal
356};
357
358/**
359 * @brief NMEA date (year, month, day)
360 */
362{
363 bool valid = false; //!< Data is valid
364 int years = 0; //!< Year
365 int months = 0; //!< Month
366 int days = 0.0; //!< Day
367
368 bool operator==(const NmeaDate& rhs) const; //!< Equal
369 bool operator!=(const NmeaDate& rhs) const; //!< Not equal
370};
371
372/**
373 * @brief NMEA geodetic position
374 */
376{
377 bool latlon_valid = false; //!< Latitude/longitude is valid
378 double lat = 0.0; //!< Latitude [deg], >= 0.0 East, < 0.0 West
379 double lon = 0.0; //!< Longitude [deg], >= 0.0 North, < 0.0 South
380 bool height_valid = false; //!< Height is valid
381 double height = 0.0; //!< Ellipsoidal (!) height [m]
382};
383
384/**
385 * @brief NMEA satellite (used, e.g. in GSA)
386 */
388{
389 bool valid = false; //!< Data is valid
391 int svid = 0; //!< Satellite ID (numbering cf. NMEA 0183)
392};
393
394/**
395 * @brief Constants for different versions of NMEA
396 */
398{
399 const int svid_min_gps = -1; //!< Min GPS satellite ID
400 const int svid_max_gps = -1; //!< Max GPS satellite ID
401 const int svid_min_sbas = -1; //!< Min SBAS satellite ID
402 const int svid_max_sbas = -1; //!< Max SBAS satellite ID
403 const int svid_min_gal = -1; //!< Min Galileo satellite ID
404 const int svid_max_gal = -1; //!< Max Galileo satellite ID
405 const int svid_min_bds = -1; //!< Min BeiDou satellite ID
406 const int svid_max_bds = -1; //!< Max BeiDou satellite ID
407 const int svid_min_glo = -1; //!< Min GLONASS satellite ID
408 const int svid_max_glo = -1; //!< Max GLONASS satellite ID
409 const int svid_min_qzss = -1; //!< Min QZSS satellite ID, -1 if not available
410 const int svid_max_qzss = -1; //!< Max QZSS satellite ID, -1 if not available
411 static const NmeaVersion V410; //!< Value for NMEA v4.10
412 static const NmeaVersion V410_UBX_EXT; //!< Value for NMEA v4.10 extended (u-blox flavour)
413 static const NmeaVersion V411; //!< Value for NMEA v4.11
414};
415
416/**
417 * NMEA satellite position (GSA)
418 */
420{
421 bool valid = false; //!< Data is valid
423 int svid = 0; //!< Satellite ID (numbering cf. NMEA 0183)
424 int el = 0; //!< Elevation [deg] (-90..90)
425 int az = 0; //!< Azimuth [deg] (0..360)
426};
427
428/**
429 * NMEA signal levels (GSA)
430 */
432{
433 bool valid = false; //!< Data valid
435 int svid = 0; //!< Satellite ID (numbering cf. NMEA 0183)
437 int cno = 0; //!< Signal level [dBHz]
438};
439
440/**
441 * @brief NMEA integer value
442 */
444{
445 bool valid = false; //!< Data is valid
446 int value = 0; //!< Value
447};
448
449/**
450 * @brief NMEA float value
451 */
453{
454 bool valid = false; //!< Data is valid
455 double value = 0; //!< Value
456};
457
458/**
459 * @brief NMEA payload base class
460 */
462{
464 bool valid_ = false; //!< Payload successfully decoded (true), or not (yet) decoded (false)
465 virtual ~NmeaPayload() = default; //!< Virtual dtor for polymorphism
466};
467
468/**
469 * @brief NMEA-Gx-GGA message payload
470 */
472{
473 NmeaTime time; //!< Time
474 NmeaLlh llh; //!< Position (with height)
476 NmeaInt num_sv; //!< Number of satellites used (may be limited to 12)
477 NmeaFloat hdop; //!< Horizontal dilution of precision (only with valid fix)
478 NmeaFloat diff_age; //!< Differential data age (optional, NMEA 4.11 only)
479 NmeaInt diff_sta; //!< Differential station ID (optional, NMEA 4.11 only)
480
481 /**
482 * @brief Set data from sentence
483 *
484 * @param[in] msg Pointer to the NMEA message
485 * @param[in] msg_size Size of the NMEA message (>= 11)
486 *
487 * @returns true if sentence payload was correct and all data could be extracted (fields are now valid), or false
488 * otherwise (fields are now invalid)
489 */
490 bool SetFromMsg(const uint8_t* msg, const std::size_t msg_size);
491
492 static constexpr const char* FORMATTER = "GGA"; //!< Formatter
493};
494
495/**
496 * @brief NMEA-Gx-GLL message payload
497 */
499{
500 NmeaLlh ll; //!< Position (no height)
501 NmeaTime time; //!< Time
502 NmeaStatusGllRmc status = NmeaStatusGllRmc::UNSPECIFIED; //!< Positioning system status
503 NmeaModeGllVtg mode = NmeaModeGllVtg::UNSPECIFIED; //!< Positioning system mode
504
505 /**
506 * @brief Set data from sentence
507 *
508 * @param[in] msg Pointer to the NMEA message
509 * @param[in] msg_size Size of the NMEA message (>= 11)
510 *
511 * @returns true if sentence payload was correct and all data could be extracted (fields are now valid), or false
512 * otherwise (fields are now invalid)
513 */
514 bool SetFromMsg(const uint8_t* msg, const std::size_t msg_size);
515
516 static constexpr const char* FORMATTER = "GLL"; //!< Formatter
517};
518
519/**
520 * @brief NMEA-Gx-RMC message payload
521 */
523{
524 NmeaTime time; //!< Time
525 NmeaStatusGllRmc status = NmeaStatusGllRmc::UNSPECIFIED; //!< Positioning system status
526 NmeaLlh llh; //!< Position
527 NmeaFloat speed; //!< Speed over ground [knots]
528 NmeaFloat course; //!< Course over ground w.r.t. True North [deg]
529 NmeaDate date; //!< Date
530 NmeaModeRmcGns mode = NmeaModeRmcGns::UNSPECIFIED; //!< Positioning system mode indicator
531 NmeaNavStatusRmc navstatus = NmeaNavStatusRmc::UNSPECIFIED; //!< Navigational status (optional)
532 /**
533 * @brief Set data from sentence
534 *
535 * @param[in] msg Pointer to the NMEA message
536 * @param[in] msg_size Size of the NMEA message (>= 11)
537 *
538 * @returns true if sentence payload was correct and all data could be extracted (fields are now valid), or false
539 * otherwise (fields are now invalid)
540 */
541 bool SetFromMsg(const uint8_t* msg, const std::size_t msg_size);
542
543 static constexpr const char* FORMATTER = "RMC"; //!< Formatter
544};
545
546/**
547 * @brief NMEA-Gx-VTG message payload
548 */
550{
551 NmeaFloat cogt; //!< Course over ground (true) [deg]
552 NmeaFloat cogm; //!< Course over ground (magnetic) [deg], not typically available
553 NmeaFloat sogn; //!< Speed over ground [knots]
554 NmeaFloat sogk; //!< Speed over ground [km/h]
555 NmeaModeGllVtg mode = NmeaModeGllVtg::UNSPECIFIED; //!< Positioning system mode
556
557 /**
558 * @brief Set data from sentence
559 *
560 * @param[in] msg Pointer to the NMEA message
561 * @param[in] msg_size Size of the NMEA message (>= 11)
562 *
563 * @returns true if sentence payload was correct and all data could be extracted (fields are now valid), or false
564 * otherwise (fields are now invalid)
565 */
566 bool SetFromMsg(const uint8_t* msg, const std::size_t msg_size);
567
568 static constexpr const char* FORMATTER = "VTG"; //!< Talker
569};
570
571/**
572 * @brief NMEA-Gx-GST message payload
573 */
575{
576 NmeaTime time; //!< Time
577 NmeaFloat rms_range; //!< RMS value of the standard deviation of the range inputs to the navigation process
578 NmeaFloat std_major; //!< Standard deviation of semi-major axis of error ellipse
579 NmeaFloat std_minor; //!< Standard deviation of semi-minor axis of error ellipse
580 NmeaFloat angle_major; //!< Angle of semi-major axis of error ellipse from true North
581 NmeaFloat std_lat; //!< Standard deviation of latitude error
582 NmeaFloat std_lon; //!< Standard deviation of longitude error
583 NmeaFloat std_alt; //!< Standard deviation of altitude error
584
585 /**
586 * @brief Set data from sentence
587 *
588 * @param[in] msg Pointer to the NMEA message
589 * @param[in] msg_size Size of the NMEA message (>= 11)
590 *
591 * @returns true if sentence payload was correct and all data could be extracted (fields are now valid), or false
592 * otherwise (fields are now invalid)
593 */
594 bool SetFromMsg(const uint8_t* msg, const std::size_t msg_size);
595
596 static constexpr const char* FORMATTER = "GST"; //!< Formatter
597};
598
599/**
600 * @brief NMEA-Gx-HDT message payload
601 */
603{
604 NmeaFloat heading; //!< True heading
605
606 /**
607 * @brief Set data from sentence
608 *
609 * @param[in] msg Pointer to the NMEA message
610 * @param[in] msg_size Size of the NMEA message (>= 11)
611 *
612 * @returns true if sentence payload was correct and all data could be extracted (fields are now valid), or false
613 * otherwise (fields are now invalid)
614 */
615 bool SetFromMsg(const uint8_t* msg, const std::size_t msg_size);
616
617 static constexpr const char* FORMATTER = "HDT"; //!< Formatter
618};
619
620/**
621 * @brief NMEA-Gx-ZDA message payload
622 */
624{
625 NmeaTime time; //!< Time
626 NmeaDate date; //!< Date
627 NmeaInt local_hr; //!< Local zone hours, always 00 (= UTC)
628 NmeaInt local_min; //!< Local zone minutes, always 00 (= UTC)
629
630 /**
631 * @brief Set data from sentence
632 *
633 * @param[in] msg Pointer to the NMEA message
634 * @param[in] msg_size Size of the NMEA message (>= 11)
635 *
636 * @returns true if sentence payload was correct and all data could be extracted (fields are now valid), or false
637 * otherwise (fields are now invalid)
638 */
639 bool SetFromMsg(const uint8_t* msg, const std::size_t msg_size);
640
641 static constexpr const char* FORMATTER = "ZDA"; //!< Formatter
642};
643
644/**
645 * @brief NMEA-Gx-GSA message payload (NMEA 4.11 only!)
646 */
648{
651 std::array<NmeaSat, 12> sats; //!< Satellites, valid ones are 0..(num_sats-1)
652 int num_sats = 0; //!< Number of valid sats (the first n of sats[])
653 NmeaFloat pdop; //!< PDOP
654 NmeaFloat hdop; //!< HDOP
655 NmeaFloat vdop; //!< VDOP
657
658 /**
659 * @brief Set data from sentence
660 *
661 * @param[in] msg Pointer to the NMEA message
662 * @param[in] msg_size Size of the NMEA message (>= 11)
663 *
664 * @returns true if sentence payload was correct and all data could be extracted (fields are now valid), or false
665 * otherwise (fields are now invalid)
666 */
667 bool SetFromMsg(const uint8_t* msg, const std::size_t msg_size);
668
669 static constexpr const char* FORMATTER = "GSA"; //!< Formatter
670};
671
672/**
673 * @brief NMEA-Gx-GSV message payload (NMEA 4.11 only!)
674 */
676{
677 NmeaInt num_msgs; //!< Number of messages in this GSV sequence (for this signal ID)
678 NmeaInt msg_num; //!< Message number in sequence (1...num_msgs)
679 NmeaInt tot_num_sat; //!< Number of sat/sig info in the whole sequence of GSV messages
680 std::array<NmeaAzEl, 4> azels; //!< Satellite positions, valid ones are 0..(num_sats-1)
681 int num_azels = 0; //!< Number of valid satellite positions (the first n of azels[])
682 std::array<NmeaCno, 4> cnos; //!< Signal levels, valid ones are 0..(num_sats-1)
683 int num_cnos = 0; //!< Number of valid signal levels (the first n of azels[])
684 NmeaSystemId system; //!< System ID
685 NmeaSignalId signal; //!< Signal ID
686
687 /**
688 * @brief Set data from sentence
689 *
690 * @param[in] msg Pointer to the NMEA message
691 * @param[in] msg_size Size of the NMEA message (>= 11)
692 *
693 * @returns true if sentence payload was correct and all data could be extracted (fields are now valid), or false
694 * otherwise (fields are now invalid)
695 */
696 bool SetFromMsg(const uint8_t* msg, const std::size_t msg_size);
697
698 static constexpr const char* FORMATTER = "GSV"; //!< Formatter
699};
700
701// ---------------------------------------------------------------------------------------------------------------------
702
703/**
704 * @brief Collector for NMEA-Gx-GSA and NMEA-Gx-GPA
705 */
707{
708 /**
709 * @brief Satellite info
710 */
711 struct Sat
712 {
714 int svid_ = 0; //!< Satellite ID (numbering cf. NMEA 0183)
715 int az_ = 0; //!< Azimuth [deg] (0..360)
716 int el_ = 0; //!< Elevation [deg] (-90..90)
717 };
718
719 /**
720 * Signal info
721 */
722 struct Sig
723 {
725 int svid_ = 0; //!< Satellite ID (numbering cf. NMEA 0183)
727 double cno_ = 0.0; //!< Signal level [dBHz]
728 bool used_ = false; //!< Signal is used in navigation
729 };
730
731 std::vector<Sat> sats_; //!< Collected satellite info
732 std::vector<Sig> sigs_; //!< Collected signal info
733
734 /**
735 * @brief Add NMEA-GN-GSA message to collection
736 *
737 * These must be provided in order and completely, and before the GSV messages.
738 *
739 * @param[in] gsa Decoded message payload
740 *
741 * @returns true if the message was accepted, false otherwise
742 */
743 bool AddGsa(const NmeaGsaPayload& gsa);
744
745 /**
746 * @brief Add NMEA-Gx-GSV message to collection
747 *
748 * These must be provided in order and completely, and after the GSA messages.
749 *
750 * @param[in] gsv Decoded message payload
751 *
752 * @returns true if the message was accepted, false otherwise
753 */
754 bool AddGsv(const NmeaGsvPayload& gsv);
755
756 /**
757 * @brief Complete collection after feeding all GSA and GSV messages
758 */
759 void Complete();
760
761 /**
762 * @brief Add NMEA-GN-GSA and NMEA-Gx-GSV messages to collection
763 *
764 * Does all of AddGsa(), AddGsv() and Complete() in one call.
765 *
766 * @param[in] gsas All decoded message payloads, complete and in order
767 * @param[in] gsvs All decoded message payloads, complete and in order
768 *
769 * @returns true if all messages were collected successfully
770 */
771 bool AddGsaAndGsv(const std::vector<NmeaGsaPayload>& gsas, const std::vector<NmeaGsvPayload>& gsvs);
772
773 private:
774 std::vector<NmeaSat> gsa_sats_; //!< Satellites used
775};
776
777/* ****************************************************************************************************************** */
778} // namespace nmea
779} // namespace parser
780} // namespace common
781} // namespace fpsdk
782#endif // __FPSDK_COMMON_PARSER_NMEA_HPP__
NmeaSystemId
NMEA system IDs.
Definition nmea.hpp:302
NmeaModeRmcGns
NMEA-Gx-RMC and NMEA-Gx-GNS pos mode.
Definition nmea.hpp:246
static constexpr std::size_t NMEA_FRAME_SIZE
NMEA frame size ("$*cc\r\n")
Definition nmea.hpp:101
NmeaOpModeGsa
NMEA-Gx-GNS operation mode.
Definition nmea.hpp:279
NmeaNavStatusRmc
NMEA-Gx-RMC navigational status.
Definition nmea.hpp:265
@ NA
Equipment does not provide navigational status.
static constexpr uint8_t NMEA_PREAMBLE
NMEA framing preamble.
Definition nmea.hpp:100
NmeaModeGllVtg
NMEA-Gx-GLL and NMEA-Gx-VTG pos mode.
Definition nmea.hpp:230
NmeaNavModeGsa
NMEA-Gx-GNS nav mode.
Definition nmea.hpp:289
NmeaTalkerId
NMEA talker IDs.
Definition nmea.hpp:182
@ GNSS
GNSS (multi-constellation)
NmeaStatusGllRmc
NMEA-Gx-GLL and NMEA-Gx-RMC status.
Definition nmea.hpp:217
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:318
@ GPS_L1CA
GPS L1 C/A or SBAS L1 C/A.
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:198
@ DGNSS
Differential GPS fix (e.g. with SBAS)
@ ESTIMATED
Estimated (dead reckoning only)
Fixposition SDK.
NmeaSystemId system
System ID.
Definition nmea.hpp:422
int az
Azimuth [deg] (0..360)
Definition nmea.hpp:425
int el
Elevation [deg] (-90..90)
Definition nmea.hpp:424
int svid
Satellite ID (numbering cf. NMEA 0183)
Definition nmea.hpp:423
int cno
Signal level [dBHz].
Definition nmea.hpp:437
NmeaSignalId signal
Signal ID.
Definition nmea.hpp:436
int svid
Satellite ID (numbering cf. NMEA 0183)
Definition nmea.hpp:435
NmeaSystemId system
System ID.
Definition nmea.hpp:434
int svid_
Satellite ID (numbering cf. NMEA 0183)
Definition nmea.hpp:714
int svid_
Satellite ID (numbering cf. NMEA 0183)
Definition nmea.hpp:725
bool used_
Signal is used in navigation.
Definition nmea.hpp:728
Collector for NMEA-Gx-GSA and NMEA-Gx-GPA.
Definition nmea.hpp:707
bool AddGsa(const NmeaGsaPayload &gsa)
Add NMEA-GN-GSA message to collection.
std::vector< Sat > sats_
Collected satellite info.
Definition nmea.hpp:731
bool AddGsv(const NmeaGsvPayload &gsv)
Add NMEA-Gx-GSV message to collection.
std::vector< Sig > sigs_
Collected signal info.
Definition nmea.hpp:732
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.
NMEA coordinates (integer degrees, float minutes and a sign for N/S resp. E/W)
Definition nmea.hpp:162
double min_
Fractional minutes value, >= 0.0.
Definition nmea.hpp:172
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:173
int deg_
Integer degrees value, >= 0.
Definition nmea.hpp:171
NMEA date (year, month, day)
Definition nmea.hpp:362
bool operator==(const NmeaDate &rhs) const
Equal.
bool operator!=(const NmeaDate &rhs) const
Not equal.
NMEA-Gx-GGA message payload.
Definition nmea.hpp:472
static constexpr const char * FORMATTER
Formatter.
Definition nmea.hpp:492
NmeaFloat diff_age
Differential data age (optional, NMEA 4.11 only)
Definition nmea.hpp:478
NmeaLlh llh
Position (with height)
Definition nmea.hpp:474
NmeaFloat hdop
Horizontal dilution of precision (only with valid fix)
Definition nmea.hpp:477
NmeaQualityGga quality
Fix quality.
Definition nmea.hpp:475
NmeaInt diff_sta
Differential station ID (optional, NMEA 4.11 only)
Definition nmea.hpp:479
NmeaInt num_sv
Number of satellites used (may be limited to 12)
Definition nmea.hpp:476
bool SetFromMsg(const uint8_t *msg, const std::size_t msg_size)
Set data from sentence.
NMEA-Gx-GLL message payload.
Definition nmea.hpp:499
NmeaLlh ll
Position (no height)
Definition nmea.hpp:500
bool SetFromMsg(const uint8_t *msg, const std::size_t msg_size)
Set data from sentence.
static constexpr const char * FORMATTER
Formatter.
Definition nmea.hpp:516
NmeaStatusGllRmc status
Positioning system status.
Definition nmea.hpp:502
NmeaModeGllVtg mode
Positioning system mode.
Definition nmea.hpp:503
NMEA-Gx-GSA message payload (NMEA 4.11 only!)
Definition nmea.hpp:648
static constexpr const char * FORMATTER
Formatter.
Definition nmea.hpp:669
NmeaOpModeGsa opmode
Operation mode.
Definition nmea.hpp:649
int num_sats
Number of valid sats (the first n of sats[])
Definition nmea.hpp:652
std::array< NmeaSat, 12 > sats
Satellites, valid ones are 0..(num_sats-1)
Definition nmea.hpp:651
bool SetFromMsg(const uint8_t *msg, const std::size_t msg_size)
Set data from sentence.
NMEA-Gx-GST message payload.
Definition nmea.hpp:575
NmeaFloat angle_major
Angle of semi-major axis of error ellipse from true North.
Definition nmea.hpp:580
NmeaFloat std_lat
Standard deviation of latitude error.
Definition nmea.hpp:581
NmeaFloat std_alt
Standard deviation of altitude error.
Definition nmea.hpp:583
static constexpr const char * FORMATTER
Formatter.
Definition nmea.hpp:596
NmeaFloat std_lon
Standard deviation of longitude error.
Definition nmea.hpp:582
NmeaFloat std_major
Standard deviation of semi-major axis of error ellipse.
Definition nmea.hpp:578
NmeaFloat rms_range
RMS value of the standard deviation of the range inputs to the navigation process.
Definition nmea.hpp:577
bool SetFromMsg(const uint8_t *msg, const std::size_t msg_size)
Set data from sentence.
NmeaFloat std_minor
Standard deviation of semi-minor axis of error ellipse.
Definition nmea.hpp:579
NMEA-Gx-GSV message payload (NMEA 4.11 only!)
Definition nmea.hpp:676
int num_azels
Number of valid satellite positions (the first n of azels[])
Definition nmea.hpp:681
NmeaInt tot_num_sat
Number of sat/sig info in the whole sequence of GSV messages.
Definition nmea.hpp:679
NmeaInt num_msgs
Number of messages in this GSV sequence (for this signal ID)
Definition nmea.hpp:677
NmeaInt msg_num
Message number in sequence (1...num_msgs)
Definition nmea.hpp:678
std::array< NmeaAzEl, 4 > azels
Satellite positions, valid ones are 0..(num_sats-1)
Definition nmea.hpp:680
std::array< NmeaCno, 4 > cnos
Signal levels, valid ones are 0..(num_sats-1)
Definition nmea.hpp:682
bool SetFromMsg(const uint8_t *msg, const std::size_t msg_size)
Set data from sentence.
int num_cnos
Number of valid signal levels (the first n of azels[])
Definition nmea.hpp:683
static constexpr const char * FORMATTER
Formatter.
Definition nmea.hpp:698
NMEA-Gx-HDT message payload.
Definition nmea.hpp:603
static constexpr const char * FORMATTER
Formatter.
Definition nmea.hpp:617
bool SetFromMsg(const uint8_t *msg, const std::size_t msg_size)
Set data from sentence.
NMEA geodetic position.
Definition nmea.hpp:376
double height
Ellipsoidal (!) height [m].
Definition nmea.hpp:381
bool latlon_valid
Latitude/longitude is valid.
Definition nmea.hpp:377
double lon
Longitude [deg], >= 0.0 North, < 0.0 South.
Definition nmea.hpp:379
double lat
Latitude [deg], >= 0.0 East, < 0.0 West.
Definition nmea.hpp:378
bool height_valid
Height is valid.
Definition nmea.hpp:380
char talker_[3]
Talker ID (for example, "GP", "GN" or "P"), nul-terminated string.
Definition nmea.hpp:106
char formatter_[20]
Formatter (for example, "GGA", "RMC", or "UBX"), nul-terminated string.
Definition nmea.hpp:107
int payload_ix1_
Index (offset) for end of payload, 0 if no payload available.
Definition nmea.hpp:109
int payload_ix0_
Index (offset) for start of payload, 0 if no payload available.
Definition nmea.hpp:108
NMEA payload base class.
Definition nmea.hpp:462
bool valid_
Payload successfully decoded (true), or not (yet) decoded (false)
Definition nmea.hpp:464
virtual ~NmeaPayload()=default
Virtual dtor for polymorphism.
NMEA-Gx-RMC message payload.
Definition nmea.hpp:523
NmeaStatusGllRmc status
Positioning system status.
Definition nmea.hpp:525
bool SetFromMsg(const uint8_t *msg, const std::size_t msg_size)
Set data from sentence.
NmeaNavStatusRmc navstatus
Navigational status (optional)
Definition nmea.hpp:531
static constexpr const char * FORMATTER
Formatter.
Definition nmea.hpp:543
NmeaModeRmcGns mode
Positioning system mode indicator.
Definition nmea.hpp:530
NmeaFloat speed
Speed over ground [knots].
Definition nmea.hpp:527
NmeaFloat course
Course over ground w.r.t. True North [deg].
Definition nmea.hpp:528
NMEA satellite (used, e.g. in GSA)
Definition nmea.hpp:388
int svid
Satellite ID (numbering cf. NMEA 0183)
Definition nmea.hpp:391
NmeaSystemId system
System ID.
Definition nmea.hpp:390
NMEA time (hour, minutes, seconds)
Definition nmea.hpp:348
bool operator==(const NmeaTime &rhs) const
Equal.
bool operator!=(const NmeaTime &rhs) const
Not equal.
Constants for different versions of NMEA.
Definition nmea.hpp:398
const int svid_max_glo
Max GLONASS satellite ID.
Definition nmea.hpp:408
const int svid_max_gps
Max GPS satellite ID.
Definition nmea.hpp:400
const int svid_min_sbas
Min SBAS satellite ID.
Definition nmea.hpp:401
const int svid_min_bds
Min BeiDou satellite ID.
Definition nmea.hpp:405
static const NmeaVersion V410
Value for NMEA v4.10.
Definition nmea.hpp:411
const int svid_max_qzss
Max QZSS satellite ID, -1 if not available.
Definition nmea.hpp:410
const int svid_min_qzss
Min QZSS satellite ID, -1 if not available.
Definition nmea.hpp:409
const int svid_min_gps
Min GPS satellite ID.
Definition nmea.hpp:399
const int svid_min_gal
Min Galileo satellite ID.
Definition nmea.hpp:403
const int svid_max_gal
Max Galileo satellite ID.
Definition nmea.hpp:404
const int svid_max_sbas
Max SBAS satellite ID.
Definition nmea.hpp:402
static const NmeaVersion V410_UBX_EXT
Value for NMEA v4.10 extended (u-blox flavour)
Definition nmea.hpp:412
const int svid_min_glo
Min GLONASS satellite ID.
Definition nmea.hpp:407
static const NmeaVersion V411
Value for NMEA v4.11.
Definition nmea.hpp:413
const int svid_max_bds
Max BeiDou satellite ID.
Definition nmea.hpp:406
NMEA-Gx-VTG message payload.
Definition nmea.hpp:550
NmeaFloat cogt
Course over ground (true) [deg].
Definition nmea.hpp:551
bool SetFromMsg(const uint8_t *msg, const std::size_t msg_size)
Set data from sentence.
NmeaModeGllVtg mode
Positioning system mode.
Definition nmea.hpp:555
NmeaFloat sogk
Speed over ground [km/h].
Definition nmea.hpp:554
static constexpr const char * FORMATTER
Talker.
Definition nmea.hpp:568
NmeaFloat sogn
Speed over ground [knots].
Definition nmea.hpp:553
NmeaFloat cogm
Course over ground (magnetic) [deg], not typically available.
Definition nmea.hpp:552
NMEA-Gx-ZDA message payload.
Definition nmea.hpp:624
bool SetFromMsg(const uint8_t *msg, const std::size_t msg_size)
Set data from sentence.
NmeaInt local_hr
Local zone hours, always 00 (= UTC)
Definition nmea.hpp:627
static constexpr const char * FORMATTER
Formatter.
Definition nmea.hpp:641
NmeaInt local_min
Local zone minutes, always 00 (= UTC)
Definition nmea.hpp:628