diff --git a/CHANGELOG.md b/CHANGELOG.md index 18e5329d..89a9aa39 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Changelog +## [3.4.8] 2024-04-26 +- Added support for age of correction when using NMEA. + ## [3.4.7] 2024-04-25 - Added support for UBX-RXM-RTCM messages. - Added support for UBX-RXM-SPARTN messages. diff --git a/CMakeLists.txt b/CMakeLists.txt index 4f58685b..f4afd3cf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,8 +36,8 @@ find_package(OpenSSL REQUIRED) endif (USE_OPENSSL) add_definitions(-D_POSIX_C_SOURCE=200809L) -add_definitions(-DCLIENT_VERSION="3.4.7") -add_definitions(-DCLIENT_VERSION_INT=0x030407) +add_definitions(-DCLIENT_VERSION="3.4.8") +add_definitions(-DCLIENT_VERSION_INT=0x030408) if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") add_definitions(-DCOMPILER_CANNOT_DEDUCE_UNREACHABLE=1) diff --git a/README.md b/README.md index ff2b2881..0a51374d 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # SUPL 3GPP LPP client -![version](https://img.shields.io/badge/version-3.4.7-green) +![version](https://img.shields.io/badge/version-3.4.8-green) ![license](https://img.shields.io/badge/license-MXM-blue) This project is a set of libraries, examples and tools to facilitate the development of 3GPP LPP clients. diff --git a/examples/lpp/location_information.cpp b/examples/lpp/location_information.cpp index e00b6ddb..a46a697b 100644 --- a/examples/lpp/location_information.cpp +++ b/examples/lpp/location_information.cpp @@ -142,6 +142,7 @@ PLI_Result provide_location_information_callback_nmea(LocationInformation& locat metrics.fix_quality = FixQuality::INVALID; metrics.number_of_satellites = gga->satellites_in_view(); metrics.hdop = gga->h_dop(); + metrics.age_of_corrections = gga->age_of_differential_corrections(); switch (gga->fix_quality()) { case receiver::nmea::GgaFixQuality::Invalid: metrics.fix_quality = FixQuality::INVALID; break; @@ -174,10 +175,10 @@ PLI_Result provide_location_information_callback_fake(LocationInformation& loca location.velocity = VelocityShape::horizontal_vertical_with_uncertainty(10, 0.5, 90, 1, 0.5, VerticalDirection::Up); - if(rand() % 2 == 0) { - metrics.fix_quality = FixQuality::RTK_FIX; + if (rand() % 2 == 0) { + metrics.fix_quality = FixQuality::RTK_FIX; } else { - metrics.fix_quality = FixQuality::RTK_FLOAT; + metrics.fix_quality = FixQuality::RTK_FLOAT; } metrics.age_of_corrections = 5; metrics.number_of_satellites = 1; diff --git a/libs/lpplib/include/lpp/location_information.h b/libs/lpplib/include/lpp/location_information.h index 645ac036..8344c48d 100644 --- a/libs/lpplib/include/lpp/location_information.h +++ b/libs/lpplib/include/lpp/location_information.h @@ -326,7 +326,7 @@ struct HaGnssMetrics { FixQuality fix_quality; // Number of satellites used in the navigation solution [0, 64]. long number_of_satellites; - // Age of the most recently used assistance data in seconds [0, 99]. + // Age of the most recently used assistance data in seconds [0, 9.9]. Optional age_of_corrections; // Horizontal dilution of precision in range [0.1, 25.6]. Optional hdop; diff --git a/libs/lpplib/src/internal_lpp.cpp b/libs/lpplib/src/internal_lpp.cpp index 7c7d0593..d8ef25bc 100644 --- a/libs/lpplib/src/internal_lpp.cpp +++ b/libs/lpplib/src/internal_lpp.cpp @@ -449,20 +449,26 @@ lpp_ha_GNSS_Metrics_r17(location_information::HaGnssMetrics const& metrics) { default: break; } - if (metrics.age_of_corrections.has_value() && metrics.age_of_corrections.const_value() >= 0 && - metrics.age_of_corrections.const_value() < 1000.0) { + if (metrics.age_of_corrections.has_value()) { + auto age = metrics.age_of_corrections.const_value() / 0.1; + if (age < 0) age = 0; + if (age > 99) age = 99; element->age_r17 = ALLOC_ZERO(long); - *element->age_r17 = static_cast(metrics.age_of_corrections.const_value() / 0.1); + *element->age_r17 = static_cast(age); } - if (metrics.hdop.has_value() && metrics.hdop.const_value() >= 0.1 && - metrics.hdop.const_value() < 2560) { + if (metrics.hdop.has_value()) { + auto hdop = metrics.hdop.const_value() / 0.1; + if (hdop < 1) hdop = 1; + if (hdop > 256) hdop = 256; element->hdopi_r17 = ALLOC_ZERO(long); - *element->hdopi_r17 = static_cast(metrics.hdop.const_value() / 0.1); + *element->hdopi_r17 = static_cast(hdop); } - if (metrics.pdop.has_value() && metrics.pdop.const_value() >= 0.1 && - metrics.pdop.const_value() < 2560) { + if (metrics.pdop.has_value()) { + auto pdop = metrics.pdop.const_value() / 0.1; + if (pdop < 1) pdop = 1; + if (pdop > 256) pdop = 256; element->pdopi_r17 = ALLOC_ZERO(long); *element->pdopi_r17 = static_cast(metrics.pdop.const_value() / 0.1); } diff --git a/libs/lpplib/src/supl.cpp b/libs/lpplib/src/supl.cpp index 764cf32d..670b720e 100644 --- a/libs/lpplib/src/supl.cpp +++ b/libs/lpplib/src/supl.cpp @@ -215,15 +215,18 @@ SUPL_Message SUPL_Client::process() { uper_decode_complete(0, &asn_DEF_ULP_PDU, (void**)&pdu, mReceiveBuffer, mReceiveLength); if (result.code == RC_FAIL) { mReceiveLength = 0; + ASN_STRUCT_FREE(asn_DEF_ULP_PDU, pdu); return nullptr; } else if (result.code == RC_WMORE) { expected_size = static_cast(pdu->length); if (expected_size > SUPL_CLIENT_RECEIVER_BUFFER_SIZE) { // Unable to handle such big messages mReceiveLength = 0; + ASN_STRUCT_FREE(asn_DEF_ULP_PDU, pdu); return nullptr; } else if (expected_size > mReceiveLength) { // Not enough data + ASN_STRUCT_FREE(asn_DEF_ULP_PDU, pdu); return nullptr; } @@ -231,6 +234,7 @@ SUPL_Message SUPL_Client::process() { uper_decode_complete(0, &asn_DEF_ULP_PDU, (void**)&pdu, mReceiveBuffer, expected_size); if (result.code != RC_OK) { mReceiveLength = 0; + ASN_STRUCT_FREE(asn_DEF_ULP_PDU, pdu); return nullptr; } } else { diff --git a/receiver/nmea/gga.cpp b/receiver/nmea/gga.cpp index 3e0f08c5..56639cb9 100644 --- a/receiver/nmea/gga.cpp +++ b/receiver/nmea/gga.cpp @@ -123,13 +123,28 @@ static bool parse_altitude(std::string const& altitude, std::string const& units } } +static bool +parse_age_of_differential_corrections(std::string const& age_of_differential_corrections, + double& value) { + try { + value = std::stod(age_of_differential_corrections); + return true; + } catch (...) { + return false; + } +} + GgaMessage::GgaMessage(std::string prefix, std::string payload, std::string checksum) NMEA_NOEXCEPT : Message{prefix, payload, checksum}, mTimeOfDay{TAI_Time::now()}, mLatitude{0.0}, mLongitude{0.0}, mFixQuality{GgaFixQuality::Invalid}, - mSatellitesInView{0} {} + mSatellitesInView{0}, + mHdop{0.0}, + mMsl{0.0}, + mGeoidSeparation{0.0}, + mAgeOfDifferentialCorrections{0} {} void GgaMessage::print() const NMEA_NOEXCEPT { printf("[%5s]\n", prefix().c_str()); @@ -150,6 +165,7 @@ void GgaMessage::print() const NMEA_NOEXCEPT { printf(" satellites: %d\n", satellites_in_view()); printf(" hdop: %.4f\n", h_dop()); printf(" altitude: %.2f\n", altitude()); + printf(" age: %.2f\n", age_of_differential_corrections()); } std::unique_ptr GgaMessage::parse(std::string prefix, std::string const& payload, @@ -174,6 +190,13 @@ std::unique_ptr GgaMessage::parse(std::string prefix, std::string const success &= parse_altitude(tokens[8], tokens[9], message->mMsl); success &= parse_altitude(tokens[10], tokens[11], message->mGeoidSeparation); + if (tokens.size() > 12) { + success &= parse_age_of_differential_corrections(tokens[12], + message->mAgeOfDifferentialCorrections); + } else { + message->mAgeOfDifferentialCorrections = 0; + } + if (success) { return std::unique_ptr(message); } else { diff --git a/receiver/nmea/include/receiver/nmea/gga.hpp b/receiver/nmea/include/receiver/nmea/gga.hpp index 913946f3..ec41fcde 100644 --- a/receiver/nmea/include/receiver/nmea/gga.hpp +++ b/receiver/nmea/include/receiver/nmea/gga.hpp @@ -26,7 +26,7 @@ class GgaMessage final : public Message { : Message(other), mTimeOfDay(other.mTimeOfDay), mLatitude(other.mLatitude), mLongitude(other.mLongitude), mFixQuality(other.mFixQuality), mSatellitesInView(other.mSatellitesInView), mHdop(other.mHdop), mMsl(other.mMsl), - mGeoidSeparation(other.mGeoidSeparation) {} + mGeoidSeparation(other.mGeoidSeparation), mAgeOfDifferentialCorrections(other.mAgeOfDifferentialCorrections) {} GgaMessage(GgaMessage&&) = delete; GgaMessage& operator=(GgaMessage const&) = delete; GgaMessage& operator=(GgaMessage&&) = delete; @@ -54,6 +54,11 @@ class GgaMessage final : public Message { /// Get the altitude in meters. NMEA_NODISCARD double altitude() const NMEA_NOEXCEPT { return mMsl + mGeoidSeparation; } + /// Get the age of differential corrections. + NMEA_NODISCARD double age_of_differential_corrections() const NMEA_NOEXCEPT { + return mAgeOfDifferentialCorrections; + } + NMEA_NODISCARD static std::unique_ptr parse(std::string prefix, std::string const& payload, std::string checksum); @@ -69,6 +74,7 @@ class GgaMessage final : public Message { double mHdop; double mMsl; double mGeoidSeparation; + double mAgeOfDifferentialCorrections; }; } // namespace nmea