/** * \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 * Version: v2.1.0 */ #ifndef LWGPS_HDR_H #define LWGPS_HDR_H #include #include #include #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 */