btgps/src/lwgps.h

340 lines
16 KiB
C
Raw Normal View History

2024-07-20 23:32:01 +00:00
/**
* \file lwgps.h
* \brief GPS main file
*/
/*
* Copyright (c) 2023 Tilen MAJERLE
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* This file is part of LwGPS - Lightweight GPS NMEA parser library.
*
* Author: Tilen MAJERLE <tilen@majerle.eu>
* Version: v2.1.0
*/
#ifndef LWGPS_HDR_H
#define LWGPS_HDR_H
#include <limits.h>
#include <stddef.h>
#include <stdint.h>
#include "lwgps_opt.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/**
* \defgroup LWGPS Lightweight GPS NMEA parser
* \brief Lightweight GPS NMEA parser
* \{
*/
/**
* \brief GPS float definition, can be either `float` or `double`
* \note Check for \ref LWGPS_CFG_DOUBLE configuration
*/
#if LWGPS_CFG_DOUBLE || __DOXYGEN__
typedef double lwgps_float_t;
#else
typedef float lwgps_float_t;
#endif
/**
* \brief Satellite descriptor
*/
typedef struct {
uint8_t num; /*!< Satellite number */
uint8_t elevation; /*!< Elevation value */
uint16_t azimuth; /*!< Azimuth in degrees */
uint8_t snr; /*!< Signal-to-noise ratio */
} lwgps_sat_t;
/**
* \brief ENUM of possible GPS statements parsed
*/
typedef enum {
STAT_UNKNOWN = 0, /*!< Unknown NMEA statement */
STAT_GGA = 1, /*!< GPGGA statement */
STAT_GSA = 2, /*!< GPGSA statement */
STAT_GSV = 3, /*!< GPGSV statement */
STAT_RMC = 4, /*!< GPRMC statement */
STAT_UBX = 5, /*!< UBX statement (uBlox specific) */
STAT_UBX_TIME = 6, /*!< UBX TIME statement (uBlox specific) */
STAT_UBX_POSITION = 7, /*!< UBX TIME statement (uBlox specific) */
STAT_CHECKSUM_FAIL = UINT8_MAX /*!< Special case, used when checksum fails */
} lwgps_statement_t;
/**
* \brief GPS main structure
*/
typedef struct {
#if LWGPS_CFG_STATEMENT_GPGGA || __DOXYGEN__
/* Information related to GPGGA statement */
#if !LWGPS_CFG_STATEMENT_PUBX_POSITION && !__DOXYGEN__
lwgps_float_t latitude; /*!< Latitude in units of degrees */
lwgps_float_t longitude; /*!< Longitude in units of degrees */
#endif /* !LWGPS_CFG_STATEMENT_PUBX_POSITION && !__DOXYGEN__ */
lwgps_float_t altitude; /*!< Altitude in units of meters */
lwgps_float_t geo_sep; /*!< Geoid separation in units of meters */
uint8_t sats_in_use; /*!< Number of satellites in use */
uint8_t fix; /*!< Fix status. `0` = invalid, `1` = GPS fix, `2` = DGPS fix, `3` = PPS fix */
uint8_t hours; /*!< Hours in UTC */
uint8_t minutes; /*!< Minutes in UTC */
uint8_t seconds; /*!< Seconds in UTC */
#endif /* LWGPS_CFG_STATEMENT_GPGGA || __DOXYGEN__ */
#if LWGPS_CFG_STATEMENT_GPGSA || __DOXYGEN__
/* Information related to GPGSA statement */
#if !LWGPS_CFG_STATEMENT_PUBX_POSITION && !__DOXYGEN__
lwgps_float_t dop_h; /*!< Dolution of precision, horizontal */
lwgps_float_t dop_v; /*!< Dolution of precision, vertical */
lwgps_float_t dop_p; /*!< Dolution of precision, position */
#endif /* !LWGPS_CFG_STATEMENT_PUBX_POSITION && !__DOXYGEN__ */
uint8_t systemId;
uint8_t fix_mode; /*!< Fix mode. `1` = NO fix, `2` = 2D fix, `3` = 3D fix */
uint8_t satellites_ids[12]; /*!< List of satellite IDs in use. Valid range is `0` to `sats_in_use` */
#endif /* LWGPS_CFG_STATEMENT_GPGSA || __DOXYGEN__ */
#if LWGPS_CFG_STATEMENT_GPGSV || __DOXYGEN__
/* Information related to GPGSV statement */
uint8_t sats_in_view; /*!< Number of satellites in view */
#if LWGPS_CFG_STATEMENT_GPGSV_SAT_DET || __DOXYGEN__
lwgps_sat_t sats_in_view_desc[12];
#endif /* LWGPS_CFG_STATEMENT_GPGSV_SAT_DET || __DOXYGEN__ */
#endif /* LWGPS_CFG_STATEMENT_GPGSV || __DOXYGEN__ */
#if LWGPS_CFG_STATEMENT_GPRMC || __DOXYGEN__
/* Information related to GPRMC statement */
uint8_t is_valid; /*!< GPS valid status */
#if !LWGPS_CFG_STATEMENT_PUBX_POSITION && !__DOXYGEN__
lwgps_float_t speed; /*!< Ground speed in knots */
lwgps_float_t course; /*!< Ground coarse */
#endif /* !LWGPS_CFG_STATEMENT_PUBX_POSITION && !__DOXYGEN__ */
lwgps_float_t variation; /*!< Magnetic variation */
uint8_t date; /*!< Fix date */
uint8_t month; /*!< Fix month */
uint8_t year; /*!< Fix year */
#endif /* LWGPS_CFG_STATEMENT_GPRMC || __DOXYGEN__ */
#if !LWGPS_CFG_STATEMENT_GPGGA && !__DOXYGEN__
/* rely on time fields from GPGGA if possible */
uint8_t hours;
uint8_t minutes;
uint8_t seconds;
#endif /* !LWGPS_CFG_STATEMENT_GPGGA && !__DOXYGEN__ */
#if !LWGPS_CFG_STATEMENT_GPRMC && !__DOXYGEN__
/* rely on date fields from GPRMC if possible */
uint8_t date;
uint8_t month;
uint8_t year;
#endif /* !LWGPS_CFG_STATEMENT_GPRMC && !__DOXYGEN__ */
#if LWGPS_CFG_STATEMENT_PUBX_TIME || __DOXYGEN__
/* fields only available in PUBX_TIME */
lwgps_float_t utc_tow; /*!< UTC TimeOfWeek, eg 113851.00 */
uint16_t utc_wk; /*!< UTC week number, continues beyond 1023 */
uint8_t leap_sec; /*!< UTC leap seconds; UTC + leap_sec = TAI */
uint32_t clk_bias; /*!< Receiver clock bias, eg 1930035 */
lwgps_float_t clk_drift; /*!< Receiver clock drift, eg -2660.664 */
uint32_t tp_gran; /*!< Time pulse granularity, eg 43 */
#endif /* LWGPS_CFG_STATEMENT_PUBX_TIME || __DOXYGEN__ */
#if LWGPS_CFG_STATEMENT_PUBX_POSITION || __DOXYGEN__
int32_t latitude; /*!< Latitude in units of degrees */
int32_t longitude; /*!< Longitude in units of degrees */
uint16_t dop_h; /*!< Horizontal dilution of precision */
uint16_t dop_v; /*!< Vertical dilution of precision */
uint32_t acc_h;
uint32_t acc_v;
uint16_t speed; /*!< Ground speed in knots */
uint16_t course; /*!< Ground coarse */
#endif /* LWGPS_CFG_STATEMENT_PUBX_POSITION || __DOXYGEN__ */
#if !__DOXYGEN__
struct {
lwgps_statement_t stat; /*!< Statement index */
char term_str[13]; /*!< Current term in string format */
uint8_t term_pos; /*!< Current index position in term */
uint8_t term_num; /*!< Current term number */
uint8_t star; /*!< Star detected flag */
#if LWGPS_CFG_CRC
uint8_t crc_calc; /*!< Calculated CRC string */
#endif /* LWGPS_CFG_CRC */
union {
uint8_t dummy; /*!< Dummy byte */
#if LWGPS_CFG_STATEMENT_GPGGA
struct {
lwgps_float_t latitude; /*!< GPS latitude position in degrees */
lwgps_float_t longitude; /*!< GPS longitude position in degrees */
lwgps_float_t altitude; /*!< GPS altitude in meters */
lwgps_float_t geo_sep; /*!< Geoid separation in units of meters */
uint8_t sats_in_use; /*!< Number of satellites currently in use */
uint8_t fix; /*!< Type of current fix, `0` = Invalid, `1` = GPS fix, `2` = Differential GPS fix */
uint8_t hours; /*!< Current UTC hours */
uint8_t minutes; /*!< Current UTC minutes */
uint8_t seconds; /*!< Current UTC seconds */
} gga; /*!< GPGGA message */
#endif /* LWGPS_CFG_STATEMENT_GPGGA */
#if LWGPS_CFG_STATEMENT_GPGSA
struct {
lwgps_float_t dop_h; /*!< Horizontal dilution of precision */
lwgps_float_t dop_v; /*!< Vertical dilution of precision */
lwgps_float_t dop_p; /*!< Position dilution of precision */
uint8_t systemId;
uint8_t fix_mode; /*!< Fix mode, `1` = No fix, `2` = 2D fix, `3` = 3D fix */
uint8_t satellites_ids[12]; /*!< IDs of satellites currently in use */
} gsa; /*!< GPGSA message */
#endif /* LWGPS_CFG_STATEMENT_GPGSA */
#if LWGPS_CFG_STATEMENT_GPGSV
struct {
uint8_t sats_in_view; /*!< Number of stallites in view */
uint8_t stat_num; /*!< Satellite line number during parsing GPGSV data */
} gsv; /*!< GPGSV message */
#endif /* LWGPS_CFG_STATEMENT_GPGSV */
#if LWGPS_CFG_STATEMENT_GPRMC
struct {
uint8_t is_valid; /*!< Status whether GPS status is valid or not */
uint8_t date; /*!< Current UTC date */
uint8_t month; /*!< Current UTC month */
uint8_t year; /*!< Current UTC year */
lwgps_float_t speed; /*!< Current spead over the ground in knots */
lwgps_float_t course; /*!< Current course over ground */
lwgps_float_t variation; /*!< Current magnetic variation in degrees */
} rmc; /*!< GPRMC message */
#endif /* LWGPS_CFG_STATEMENT_GPRMC */
#if LWGPS_CFG_STATEMENT_PUBX_POSITION
struct {
int32_t latitude; /*!< Latitude in units of degrees */
int32_t longitude; /*!< Longitude in units of degrees */
uint16_t dop_h; /*!< Horizontal dilution of precision */
uint16_t dop_v; /*!< Vertical dilution of precision */
uint32_t acc_h;
uint32_t acc_v;
uint16_t speed; /*!< Ground speed in knots */
uint16_t course; /*!< Ground coarse */
} position; /*!< PUBX TIME message */
#endif /* LWGPS_CFG_STATEMENT_PUBX_POSITION */
#if LWGPS_CFG_STATEMENT_PUBX_TIME
struct {
uint8_t hours; /*!< Current UTC hours */
uint8_t minutes; /*!< Current UTC minutes */
uint8_t seconds; /*!< Current UTC seconds */
uint8_t date; /*!< Current UTC date */
uint8_t month; /*!< Current UTC month */
uint8_t year; /*!< Current UTC year */
lwgps_float_t utc_tow; /*!< UTC TimeOfWeek, eg 113851.00 */
uint16_t utc_wk; /*!< UTC week number, continues beyond 1023 */
uint8_t leap_sec; /*!< UTC leap seconds; UTC + leap_sec = TAI */
uint32_t clk_bias; /*!< Receiver clock bias, eg 1930035 */
lwgps_float_t clk_drift; /*!< Receiver clock drift, eg -2660.664 */
uint32_t tp_gran; /*!< Time pulse granularity, eg 43 */
} time; /*!< PUBX TIME message */
#endif /* LWGPS_CFG_STATEMENT_PUBX_TIME */
} data; /*!< Union with data for each information */
} p; /*!< Structure with private data */
#endif /* !__DOXYGEN__ */
} lwgps_t;
/**
* \brief List of optional speed transformation from GPS values (in knots)
*/
typedef enum {
/* Metric values */
LWGPS_SPEED_KPS, /*!< Kilometers per second */
LWGPS_SPEED_KPH, /*!< Kilometers per hour */
LWGPS_SPEED_MPS, /*!< Meters per second */
LWGPS_SPEED_MPM, /*!< Meters per minute */
/* Imperial values */
LWGPS_SPEED_MIPS, /*!< Miles per second */
LWGPS_SPEED_MPH, /*!< Miles per hour */
LWGPS_SPEED_FPS, /*!< Foots per second */
LWGPS_SPEED_FPM, /*!< Foots per minute */
/* Optimized for runners/joggers */
LWGPS_SPEED_MPK, /*!< Minutes per kilometer */
LWGPS_SPEED_SPK, /*!< Seconds per kilometer */
LWGPS_SPEED_SP100M, /*!< Seconds per 100 meters */
LWGPS_SPEED_MIPM, /*!< Minutes per mile */
LWGPS_SPEED_SPM, /*!< Seconds per mile */
LWGPS_SPEED_SP100Y, /*!< Seconds per 100 yards */
/* Nautical values */
LWGPS_SPEED_SMPH, /*!< Sea miles per hour */
} lwgps_speed_t;
#define lwgps_speed_kps LWGPS_SPEED_KPS /*!< Backward compatibility. \deprecated Use \ref lwgps_speed_t instead */
#define lwgps_speed_kph LWGPS_SPEED_KPH /*!< Backward compatibility. \deprecated Use \ref lwgps_speed_t instead */
#define lwgps_speed_mps LWGPS_SPEED_MPS /*!< Backward compatibility. \deprecated Use \ref lwgps_speed_t instead */
#define lwgps_speed_mpm LWGPS_SPEED_MPM /*!< Backward compatibility. \deprecated Use \ref lwgps_speed_t instead */
#define lwgps_speed_mips LWGPS_SPEED_MIPS /*!< Backward compatibility. \deprecated Use \ref lwgps_speed_t instead */
#define lwgps_speed_mph LWGPS_SPEED_MPH /*!< Backward compatibility. \deprecated Use \ref lwgps_speed_t instead */
#define lwgps_speed_fps LWGPS_SPEED_FPS /*!< Backward compatibility. \deprecated Use \ref lwgps_speed_t instead */
#define lwgps_speed_fpm LWGPS_SPEED_FPM /*!< Backward compatibility. \deprecated Use \ref lwgps_speed_t instead */
#define lwgps_speed_mpk LWGPS_SPEED_MPK /*!< Backward compatibility. \deprecated Use \ref lwgps_speed_t instead */
#define lwgps_speed_spk LWGPS_SPEED_SPK /*!< Backward compatibility. \deprecated Use \ref lwgps_speed_t instead */
#define lwgps_speed_sp100m LWGPS_SPEED_SP100M /*!< Backward compatibility. \deprecated Use \ref lwgps_speed_t instead */
#define lwgps_speed_mipm LWGPS_SPEED_MIPM /*!< Backward compatibility. \deprecated Use \ref lwgps_speed_t instead */
#define lwgps_speed_spm LWGPS_SPEED_SPM /*!< Backward compatibility. \deprecated Use \ref lwgps_speed_t instead */
#define lwgps_speed_sp100y LWGPS_SPEED_SP100Y /*!< Backward compatibility. \deprecated Use \ref lwgps_speed_t instead */
#define lwgps_speed_smph LWGPS_SPEED_SMPH /*!< Backward compatibility. \deprecated Use \ref lwgps_speed_t instead */
/**
* \brief Signature for caller-suplied callback function from gps_process
* \param[in] res: statement type of recently parsed statement
*/
typedef void (*lwgps_process_fn)(lwgps_statement_t res);
/**
* \brief Check if current GPS data contain valid signal
* \note \ref LWGPS_CFG_STATEMENT_GPRMC must be enabled and `GPRMC` statement must be sent from GPS receiver
* \param[in] _gh: GPS handle
* \return `1` on success, `0` otherwise
*/
#if LWGPS_CFG_STATEMENT_GPRMC || __DOXYGEN__
#define lwgps_is_valid(_gh) ((_gh)->is_valid)
#else
#define lwgps_is_valid(_gh) (0)
#endif /* LWGPS_CFG_STATEMENT_GPRMC || __DOXYGEN__ */
uint8_t lwgps_init(lwgps_t* gh);
#if LWGPS_CFG_STATUS || __DOXYGEN__
uint8_t lwgps_process(lwgps_t* gh, const void* data, size_t len, lwgps_process_fn evt_fn);
#else /* LWGPS_CFG_STATUS */
uint8_t lwgps_process(lwgps_t* gh, const void* data, size_t len);
#endif /* !LWGPS_CFG_STATUS */
uint8_t lwgps_distance_bearing(lwgps_float_t las, lwgps_float_t los, lwgps_float_t lae, lwgps_float_t loe,
lwgps_float_t* d, lwgps_float_t* b);
lwgps_float_t lwgps_to_speed(lwgps_float_t sik, lwgps_speed_t ts);
/**
* \}
*/
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* LWGPS_HDR_H */