mirror of
https://github.com/gnss-sdr/gnss-sdr
synced 2024-12-04 23:40:04 +00:00
Merge branch 'next' of github.com:carlesfernandez/gnss-sdr into ism
This commit is contained in:
commit
98705b3ff7
11
.github/workflows/main.yml
vendored
11
.github/workflows/main.yml
vendored
@ -34,7 +34,9 @@ jobs:
|
||||
- name: check
|
||||
run: cd build && ninja check && ../install/volk_gnsssdr_profile && ../install/run_tests
|
||||
- name: default position_test
|
||||
run: cd build && cmake -DENABLE_SYSTEM_TESTING_EXTRA=ON .. && ninja && ../install/position_test
|
||||
run: |
|
||||
cd build && cmake -DENABLE_SYSTEM_TESTING_EXTRA=ON -DENABLE_UNIT_TESTING_EXTRA=OFF .. && \
|
||||
ninja && ../install/position_test && ../install/run_tests --gtest_filter=Osnma*
|
||||
|
||||
build-macos:
|
||||
runs-on: macos-latest
|
||||
@ -66,7 +68,9 @@ jobs:
|
||||
- name: check
|
||||
run: cd build && ninja check && ../install/volk_gnsssdr_profile && ../install/run_tests
|
||||
- name: default position_test
|
||||
run: cd build && cmake -DENABLE_SYSTEM_TESTING_EXTRA=ON .. && ninja && ../install/position_test
|
||||
run: |
|
||||
cd build && cmake -DENABLE_SYSTEM_TESTING_EXTRA=ON -DENABLE_UNIT_TESTING_EXTRA=OFF .. && \
|
||||
ninja && ../install/position_test && ../install/run_tests --gtest_filter=Osnma*
|
||||
|
||||
build-macos-xcode:
|
||||
runs-on: macos-latest
|
||||
@ -104,9 +108,10 @@ jobs:
|
||||
- name: default position_test
|
||||
run: |
|
||||
cd build
|
||||
cmake -DENABLE_SYSTEM_TESTING_EXTRA=ON ..
|
||||
cmake -DENABLE_SYSTEM_TESTING_EXTRA=ON -DENABLE_UNIT_TESTING_EXTRA=OFF ..
|
||||
xcodebuild -configuration Release -target position_test
|
||||
../install/position_test
|
||||
../install/run_tests --gtest_filter=Osnma*
|
||||
|
||||
clang-format:
|
||||
runs-on: ubuntu-latest
|
||||
|
3
AUTHORS
3
AUTHORS
@ -33,6 +33,7 @@ Contact Information
|
||||
|
||||
List of authors
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
Carles Fernández-Prades carles.fernandez@cttc.cat Project manager
|
||||
Javier Arribas javier.arribas@cttc.es Developer
|
||||
Luis Esteve Elfau luis@epsilon-formacion.com Developer
|
||||
@ -45,6 +46,7 @@ Andres Cecilia Luque a.cecilia.luque@gmail.com Contributor
|
||||
Anthony Arnold anthony.arnold@uqconnect.edu.au Contributor
|
||||
Antonio Ramos antonio.ramosdet@gmail.com Contributor
|
||||
Carlos Avilés carlos.avilesr@googlemail.com Contributor
|
||||
Cesare Ghionoiu Martinez c.ghionoiu-martinez@tu-braunschweig.de Contributor
|
||||
Cillian O'Driscoll cillian.odriscoll@gmail.com Contributor
|
||||
Damian Miralles dmiralles2009@gmail.com Contributor
|
||||
Daniel Fehr daniel.co@bluewin.ch Contributor
|
||||
@ -69,5 +71,6 @@ Víctor Castillo-Agüero victorcastilloaguero@gmail.com Contributor
|
||||
Will Silberman wsilberm@google.com Contributor
|
||||
Carlos Paniego carpanie@hotmail.com Artwork
|
||||
|
||||
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
# SPDX-FileCopyrightText: 2011-2024 Carles Fernandez-Prades <carles.fernandez@cttc.es>
|
||||
|
@ -61,6 +61,11 @@ authors:
|
||||
- email: daniel.co@bluewin.ch
|
||||
family-names: Fehr
|
||||
given-names: Daniel
|
||||
- alias: cesaaargm
|
||||
affiliation: "Technische Universität Braunschweig"
|
||||
email: c.ghionoiu-martinez@tu-braunschweig.de
|
||||
family-names: "Ghionoiu Martinez"
|
||||
given-names: Cesare
|
||||
- alias: piyush0411
|
||||
email: piyush04111999@gmail.com
|
||||
family-names: Gupta
|
||||
|
@ -102,6 +102,8 @@ option(ENABLE_STRIP "Create stripped binaries without debugging symbols (in Rele
|
||||
|
||||
option(Boost_USE_STATIC_LIBS "Use Boost static libs" OFF)
|
||||
|
||||
option(ENABLE_GNUTLS "Forces linking against GnuTLS" OFF)
|
||||
|
||||
if(ENABLE_PACKAGING)
|
||||
set(ENABLE_ARMA_NO_DEBUG ON)
|
||||
set(CMAKE_VERBOSE_MAKEFILE ON)
|
||||
@ -2217,97 +2219,9 @@ endif()
|
||||
|
||||
|
||||
################################################################################
|
||||
# GnuTLS - https://www.gnutls.org/
|
||||
# OpenSSL https://www.openssl.org/ or GnuTLS - https://www.gnutls.org/
|
||||
################################################################################
|
||||
find_package(GnuTLS)
|
||||
set_package_properties(GnuTLS PROPERTIES
|
||||
URL "https://www.gnutls.org/"
|
||||
PURPOSE "Used for the SUPL protocol implementation."
|
||||
TYPE REQUIRED
|
||||
)
|
||||
if(GnuTLS_FOUND AND GNUTLS_VERSION_STRING)
|
||||
set_package_properties(GnuTLS PROPERTIES
|
||||
DESCRIPTION "Transport Layer Security Library (found: v${GNUTLS_VERSION_STRING})"
|
||||
)
|
||||
else()
|
||||
set_package_properties(GnuTLS PROPERTIES
|
||||
DESCRIPTION "Transport Layer Security Library"
|
||||
)
|
||||
endif()
|
||||
find_library(GNUTLS_OPENSSL_LIBRARY
|
||||
NAMES gnutls-openssl libgnutls-openssl.so.27
|
||||
PATHS
|
||||
/usr/lib
|
||||
/usr/lib64
|
||||
/usr/lib/x86_64-linux-gnu
|
||||
/usr/lib/aarch64-linux-gnu
|
||||
/usr/lib/arm-linux-gnueabihf
|
||||
/usr/lib/arm-linux-gnueabi
|
||||
/usr/lib/i386-linux-gnu
|
||||
/usr/lib/alpha-linux-gnu
|
||||
/usr/lib/hppa-linux-gnu
|
||||
/usr/lib/i386-gnu
|
||||
/usr/lib/i686-gnu
|
||||
/usr/lib/i686-linux-gnu
|
||||
/usr/lib/x86_64-kfreebsd-gnu
|
||||
/usr/lib/i686-kfreebsd-gnu
|
||||
/usr/lib/m68k-linux-gnu
|
||||
/usr/lib/mips-linux-gnu
|
||||
/usr/lib/mips64el-linux-gnuabi64
|
||||
/usr/lib/mipsel-linux-gnu
|
||||
/usr/lib/powerpc-linux-gnu
|
||||
/usr/lib/powerpc-linux-gnuspe
|
||||
/usr/lib/powerpc64-linux-gnu
|
||||
/usr/lib/powerpc64le-linux-gnu
|
||||
/usr/lib/s390x-linux-gnu
|
||||
/usr/lib/riscv64-linux-gnu
|
||||
/usr/lib/sparc64-linux-gnu
|
||||
/usr/lib/x86_64-linux-gnux32
|
||||
/usr/lib/sh4-linux-gnu
|
||||
/usr/lib/loongarch64-linux-gnu
|
||||
/usr/local/lib
|
||||
/usr/local/lib64
|
||||
/opt/local/lib
|
||||
)
|
||||
if(NOT GNUTLS_OPENSSL_LIBRARY)
|
||||
if(GnuTLS_FOUND)
|
||||
message(STATUS " But it was not built with openssl compatibility.")
|
||||
endif()
|
||||
message(STATUS " Looking for OpenSSL instead...")
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
set(OPENSSL_ROOT_DIR /usr/local/opt/openssl) # Trick for Homebrew
|
||||
endif()
|
||||
find_package(OpenSSL)
|
||||
set_package_properties(OpenSSL PROPERTIES
|
||||
URL "https://www.openssl.org"
|
||||
DESCRIPTION "Cryptography and SSL/TLS Toolkit (found: v${OPENSSL_VERSION})"
|
||||
PURPOSE "Used for the SUPL protocol implementation."
|
||||
TYPE REQUIRED
|
||||
)
|
||||
if(OPENSSL_FOUND)
|
||||
set_package_properties(GnuTLS PROPERTIES
|
||||
PURPOSE "Not found, but OpenSSL can replace it."
|
||||
)
|
||||
set(GNUTLS_INCLUDE_DIR ${OPENSSL_INCLUDE_DIR})
|
||||
set(GNUTLS_LIBRARIES "")
|
||||
set(GNUTLS_OPENSSL_LIBRARY ${OPENSSL_SSL_LIBRARY})
|
||||
else()
|
||||
message(" The GnuTLS library with openssl compatibility enabled has not been found.")
|
||||
message(" You can try to install the required libraries by typing:")
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "Linux|kFreeBSD|GNU")
|
||||
if(${LINUX_DISTRIBUTION} MATCHES "Fedora" OR ${LINUX_DISTRIBUTION} MATCHES "Red Hat")
|
||||
message(" sudo yum install openssl-devel")
|
||||
else()
|
||||
message(" sudo apt-get install libgnutls28-dev")
|
||||
endif()
|
||||
endif()
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
message(" 'sudo port install gnutls', if you are using Macports, or")
|
||||
message(" 'brew install openssl', if you are using Homebrew.")
|
||||
endif()
|
||||
message(FATAL_ERROR "GnuTLS libraries with openssl compatibility are required to build gnss-sdr")
|
||||
endif()
|
||||
endif()
|
||||
include(GnsssdrCrypto)
|
||||
|
||||
|
||||
|
||||
@ -3721,6 +3635,7 @@ add_feature_info(ENABLE_OWN_GLOG ENABLE_OWN_GLOG "Forces the downloading and bui
|
||||
add_feature_info(ENABLE_GLOG_AND_GFLAGS ENABLE_GLOG_AND_GFLAGS "Forces the usage of Google glog and Gflags instead of Abseil.")
|
||||
add_feature_info(ENABLE_OWN_ABSEIL ENABLE_OWN_ABSEIL "Forces downloading and building Abseil. Supersedes ENABLE_OWN_GLOG.")
|
||||
add_feature_info(ENABLE_OWN_ARMADILLO ENABLE_OWN_ARMADILLO "Forces the downloading and building of Armadillo.")
|
||||
add_feature_info(ENABLE_GNUTLS ENABLE_GNUTLS "Forces linking against GnuTLS instead of OpenSSL.")
|
||||
add_feature_info(ENABLE_LOG ENABLE_LOG "Enables runtime internal logging.")
|
||||
add_feature_info(ENABLE_ORC ENABLE_ORC "Use the Optimized Inner Loop Runtime Compiler (ORC) for building volk_gnsssdr.")
|
||||
add_feature_info(ENABLE_STRIP ENABLE_STRIP "Enables the generation of stripped binaries (without debugging symbols).")
|
||||
|
26
README.md
26
README.md
@ -74,7 +74,7 @@ information about this open-source, software-defined GNSS receiver.
|
||||
- [Install Armadillo, a C++ linear algebra library](#install-armadillo-a-c-linear-algebra-library)
|
||||
- [Install Gflags, a commandline flags processing module for C++](#install-gflags-a-commandline-flags-processing-module-for-c)
|
||||
- [Install Glog, a library that implements application-level logging](#install-glog-a-library-that-implements-application-level-logging)
|
||||
- [Install the GnuTLS or OpenSSL libraries](#install-the-gnutls-or-openssl-libraries)
|
||||
- [Install the OpenSSL libraries](#install-the-openssl-libraries)
|
||||
- [Install Matio, MATLAB MAT file I/O library](#install-matio-matlab-mat-file-io-library)
|
||||
- [Install Protocol Buffers, a portable mechanism for serialization of structured data](#install-protocol-buffers-a-portable-mechanism-for-serialization-of-structured-data)
|
||||
- [Install Pugixml, a light-weight C++ XML processing library](#install-pugixml-a-light-weight-c-xml-processing-library)
|
||||
@ -167,16 +167,19 @@ $ sudo apt-get install build-essential cmake git pkg-config libboost-dev libboos
|
||||
libboost-system-dev libboost-filesystem-dev libboost-thread-dev libboost-chrono-dev \
|
||||
libboost-serialization-dev liblog4cpp5-dev libuhd-dev gnuradio-dev gr-osmosdr \
|
||||
libblas-dev liblapack-dev libarmadillo-dev libgflags-dev libgoogle-glog-dev \
|
||||
libgnutls-openssl-dev libpcap-dev libmatio-dev libpugixml-dev libgtest-dev \
|
||||
libprotobuf-dev protobuf-compiler python3-mako
|
||||
libssl-dev libpcap-dev libmatio-dev libpugixml-dev libgtest-dev \
|
||||
libprotobuf-dev libcpu-features-dev protobuf-compiler python3-mako
|
||||
```
|
||||
|
||||
Please note that the required files from `libgtest-dev` were named `googletest`
|
||||
in Debian 9 "stretch" and Ubuntu 18.04 "bionic", and renamed to `libgtest-dev`
|
||||
in Debian 10 "buster" and above.
|
||||
|
||||
Since Ubuntu 21.04 Hirsute / Debian 11, the package `libcpu-features-dev` is
|
||||
also required.
|
||||
In distributions older than Ubuntu 21.04 Hirsute / Debian 11, the package
|
||||
`libcpu-features-dev` is not required.
|
||||
|
||||
In distributions older than Ubuntu 22.04 Jammy / Debian 12, the package
|
||||
`libssl-dev` must be replaced by `libgnutls-openssl-dev`.
|
||||
|
||||
**Note for Ubuntu 14.04 LTS "trusty" users:** you will need to build from source
|
||||
and install GNU Radio manually, as explained below, since GNSS-SDR requires
|
||||
@ -431,20 +434,15 @@ Please note that Glog is replaced by the
|
||||
[Abseil Logging Library](https://abseil.io/docs/cpp/guides/logging) if Abseil >=
|
||||
v20240116 is available in your system.
|
||||
|
||||
#### Install the GnuTLS or OpenSSL libraries
|
||||
#### Install the OpenSSL libraries
|
||||
|
||||
```
|
||||
$ sudo apt-get install libgnutls-openssl-dev # For Debian/Ubuntu/LinuxMint
|
||||
$ sudo yum install openssl-devel # For Fedora/RHEL
|
||||
$ sudo apt-get install libssl-dev # For Debian/Ubuntu/LinuxMint
|
||||
$ sudo yum install openssl-devel # For Fedora/CentOS/RHEL
|
||||
$ sudo zypper install openssl-devel # For OpenSUSE
|
||||
$ sudo pacman -S openssl # For Arch Linux
|
||||
```
|
||||
|
||||
In case the [GnuTLS](https://www.gnutls.org/ "GnuTLS's Homepage") library with
|
||||
openssl extensions package is not available in your GNU/Linux distribution,
|
||||
GNSS-SDR can also work well with
|
||||
[OpenSSL](https://www.openssl.org/ "OpenSSL's Homepage").
|
||||
|
||||
#### Install [Matio](https://github.com/tbeu/matio "Matio's Homepage"), MATLAB MAT file I/O library
|
||||
|
||||
```
|
||||
@ -818,7 +816,7 @@ In a terminal, type:
|
||||
```
|
||||
$ sudo port selfupdate
|
||||
$ sudo port upgrade outdated
|
||||
$ sudo port install armadillo cmake pkgconfig protobuf3-cpp pugixml gnutls
|
||||
$ sudo port install armadillo cmake pkgconfig protobuf3-cpp pugixml openssl3
|
||||
$ sudo port install gnuradio +uhd +grc +zeromq
|
||||
$ sudo port install boost matio libad9361-iio libiio
|
||||
$ sudo port install py311-mako
|
||||
|
79
cmake/Modules/FindGMP.cmake
Normal file
79
cmake/Modules/FindGMP.cmake
Normal file
@ -0,0 +1,79 @@
|
||||
# GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
|
||||
# This file is part of GNSS-SDR.
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2024 C. Fernandez-Prades cfernandez(at)cttc.es
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
if(NOT COMMAND feature_summary)
|
||||
include(FeatureSummary)
|
||||
endif()
|
||||
|
||||
if(NOT GNSSSDR_LIB_PATHS)
|
||||
include(GnsssdrLibPaths)
|
||||
endif()
|
||||
|
||||
if(NOT PKG_CONFIG_FOUND)
|
||||
include(FindPkgConfig)
|
||||
endif()
|
||||
pkg_check_modules(PC_GMP "gmp")
|
||||
|
||||
set(GMP_DEFINITIONS ${PC_GMP_CFLAGS_OTHER})
|
||||
|
||||
find_path(GMP_INCLUDE_DIR
|
||||
NAMES gmpxx.h
|
||||
HINTS ${PC_GMP_INCLUDEDIR}
|
||||
PATHS ${CMAKE_INSTALL_PREFIX}/include
|
||||
/usr/local/include
|
||||
/usr/include
|
||||
/opt/local/include
|
||||
)
|
||||
|
||||
set(GMP_INCLUDE_DIRS ${GMP_INCLUDE_DIR})
|
||||
set(GMP_PC_ADD_CFLAGS "-I${GMP_INCLUDE_DIR}")
|
||||
|
||||
find_library(GMPXX_LIBRARY
|
||||
NAMES gmpxx
|
||||
HINTS ${PC_GMP_LIBDIR}
|
||||
PATHS ${GNSSSDR_LIB_PATHS}
|
||||
${CMAKE_INSTALL_PREFIX}/lib
|
||||
${CMAKE_INSTALL_PREFIX}/lib64
|
||||
)
|
||||
|
||||
find_library(GMP_LIBRARY
|
||||
NAMES gmp
|
||||
HINTS ${PC_GMP_LIBDIR}
|
||||
PATHS ${GNSSSDR_LIB_PATHS}
|
||||
${CMAKE_INSTALL_PREFIX}/lib
|
||||
${CMAKE_INSTALL_PREFIX}/lib64
|
||||
)
|
||||
|
||||
set(GMP_LIBRARIES ${GMPXX_LIBRARY} ${GMP_LIBRARY})
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(GMP DEFAULT_MSG GMPXX_LIBRARY GMP_LIBRARY GMP_INCLUDE_DIR)
|
||||
|
||||
if(GMP_FOUND AND NOT TARGET Gmp::gmp)
|
||||
add_library(Gmp::gmp SHARED IMPORTED)
|
||||
set_target_properties(Gmp::gmp PROPERTIES
|
||||
IMPORTED_LINK_INTERFACE_LANGUAGES "CXX"
|
||||
IMPORTED_LOCATION "${GMPXX_LIBRARY}"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${GMP_INCLUDE_DIR}"
|
||||
INTERFACE_LINK_LIBRARIES "${GMP_LIBRARIES}"
|
||||
)
|
||||
endif()
|
||||
|
||||
set_package_properties(GMP PROPERTIES
|
||||
URL "https://gmplib.org/"
|
||||
)
|
||||
|
||||
if(PC_GMP_VERSION)
|
||||
set_package_properties(GMP PROPERTIES
|
||||
DESCRIPTION "The GNU Multiple Precision Arithmetic Library (found: v.${PC_GMP_VERSION})"
|
||||
)
|
||||
else()
|
||||
set_package_properties(GMP PROPERTIES
|
||||
DESCRIPTION "The GNU Multiple Precision Arithmetic Library"
|
||||
)
|
||||
endif()
|
||||
|
||||
mark_as_advanced(GMPXX_LIBRARY GMP_LIBRARY GMP_INCLUDE_DIR)
|
@ -366,8 +366,10 @@ if(GNURADIO_RUNTIME_INCLUDE_DIRS)
|
||||
)
|
||||
if(CMAKE_VERSION VERSION_GREATER 3.13)
|
||||
target_link_libraries(Gnuradio::filter INTERFACE Log4cpp::log4cpp)
|
||||
target_link_libraries(Gnuradio::runtime INTERFACE Log4cpp::log4cpp)
|
||||
else()
|
||||
set_target_properties(Gnuradio::filter PROPERTIES INTERFACE_LINK_LIBRARIES Log4cpp::log4cpp)
|
||||
set_target_properties(Gnuradio::runtime PROPERTIES INTERFACE_LINK_LIBRARIES Log4cpp::log4cpp)
|
||||
endif()
|
||||
endif()
|
||||
if(${_uses_spdlog})
|
||||
|
191
cmake/Modules/GnsssdrCrypto.cmake
Normal file
191
cmake/Modules/GnsssdrCrypto.cmake
Normal file
@ -0,0 +1,191 @@
|
||||
# GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
|
||||
# This file is part of GNSS-SDR.
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2024 C. Fernandez-Prades cfernandez(at)cttc.es
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
if(NOT COMMAND feature_summary)
|
||||
include(FeatureSummary)
|
||||
endif()
|
||||
|
||||
if(NOT GNSSSDR_LIB_PATHS)
|
||||
include(GnsssdrLibPaths)
|
||||
endif()
|
||||
|
||||
################################################################################
|
||||
# OpenSSL https://www.openssl.org/
|
||||
################################################################################
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
set(OPENSSL_ROOT_DIR /usr/local/opt/openssl) # Trick for Homebrew
|
||||
endif()
|
||||
unset(OPENSSL_FOUND CACHE)
|
||||
unset(GnuTLS_FOUND CACHE)
|
||||
unset(GMP_FOUND CACHE)
|
||||
if(NOT ENABLE_GNUTLS)
|
||||
find_package(OpenSSL)
|
||||
endif()
|
||||
set_package_properties(OpenSSL
|
||||
PROPERTIES
|
||||
URL "https://www.openssl.org"
|
||||
PURPOSE "Used for the OSNMA and SUPL protocol implementations."
|
||||
TYPE REQUIRED
|
||||
)
|
||||
if(OPENSSL_FOUND)
|
||||
set_package_properties(OpenSSL
|
||||
PROPERTIES
|
||||
DESCRIPTION "Cryptography and SSL/TLS Toolkit (found: v${OPENSSL_VERSION})"
|
||||
)
|
||||
else()
|
||||
set_package_properties(OpenSSL
|
||||
PROPERTIES
|
||||
DESCRIPTION "OpenSSL has not been found, but GnuTLS with openssl compatibility can replace it"
|
||||
)
|
||||
################################################################################
|
||||
# GnuTLS - https://www.gnutls.org/
|
||||
################################################################################
|
||||
find_package(GnuTLS)
|
||||
set_package_properties(GnuTLS PROPERTIES
|
||||
URL "https://www.gnutls.org/"
|
||||
PURPOSE "Used for the OSNMA and SUPL protocol implementations."
|
||||
TYPE REQUIRED
|
||||
)
|
||||
if(GnuTLS_FOUND AND GNUTLS_VERSION_STRING)
|
||||
set_package_properties(GnuTLS PROPERTIES
|
||||
DESCRIPTION "Transport Layer Security Library (found: v${GNUTLS_VERSION_STRING})"
|
||||
)
|
||||
else()
|
||||
set_package_properties(GnuTLS PROPERTIES
|
||||
DESCRIPTION "Transport Layer Security Library"
|
||||
)
|
||||
endif()
|
||||
find_library(GNUTLS_OPENSSL_LIBRARY
|
||||
NAMES gnutls-openssl libgnutls-openssl.so.27
|
||||
PATHS ${GNSSSDR_LIB_PATHS}
|
||||
)
|
||||
|
||||
find_path(GNUTLS_INCLUDE_DIR NAMES gnutls/gnutls.h
|
||||
PATHS
|
||||
/usr/include
|
||||
/usr/local/include
|
||||
/opt/local/include # default location in Macports
|
||||
/opt/homebrew/opt/gnutls/include/
|
||||
${GNUTLS_ROOT_DIR}/include/
|
||||
)
|
||||
|
||||
if(NOT GNUTLS_OPENSSL_LIBRARY)
|
||||
message(" The GnuTLS library with openssl compatibility enabled has not been found.")
|
||||
message(" You can try to install the required libraries by typing:")
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "Linux|kFreeBSD|GNU")
|
||||
if(${LINUX_DISTRIBUTION} MATCHES "Fedora" OR ${LINUX_DISTRIBUTION} MATCHES "Red Hat")
|
||||
message(" sudo yum install openssl-devel")
|
||||
else()
|
||||
message(" sudo apt-get install libgnutls28-dev")
|
||||
endif()
|
||||
endif()
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
message(" 'sudo port install openssl3', if you are using Macports, or")
|
||||
message(" 'brew install openssl', if you are using Homebrew.")
|
||||
endif()
|
||||
message(FATAL_ERROR "OpenSSL or the GnuTLS libraries with openssl compatibility are required to build gnss-sdr")
|
||||
endif()
|
||||
|
||||
# Test GnuTLS capabilities
|
||||
file(READ "${GNUTLS_INCLUDE_DIR}/gnutls/gnutls.h" gnutls_gnutls_file_contents)
|
||||
if("${gnutls_gnutls_file_contents}" MATCHES "GNUTLS_SIGN_ECDSA_SHA256")
|
||||
set(GNUTLS_SIGN_ECDSA_SHA256 TRUE)
|
||||
endif()
|
||||
if("${gnutls_gnutls_file_contents}" MATCHES "GNUTLS_SIGN_ECDSA_SHA512")
|
||||
set(GNUTLS_SIGN_ECDSA_SHA512 TRUE)
|
||||
endif()
|
||||
if("${gnutls_gnutls_file_contents}" MATCHES "GNUTLS_DIG_SHA3_256")
|
||||
set(GNUTLS_DIG_SHA3_256 TRUE)
|
||||
endif()
|
||||
if("${gnutls_gnutls_file_contents}" MATCHES "#define GNUTLS_VERSION_MAJOR 2")
|
||||
set(GNUTLS_HMAC_INIT_WITH_DIGEST TRUE)
|
||||
endif()
|
||||
if("${gnutls_gnutls_file_contents}" MATCHES "GNUTLS_MAC_AES_CMAC_128")
|
||||
set(GNUTLS_MAC_AES_CMAC_128 TRUE)
|
||||
endif()
|
||||
file(READ "${GNUTLS_INCLUDE_DIR}/gnutls/abstract.h" gnutls_abstract_file_contents)
|
||||
if("${gnutls_abstract_file_contents}" MATCHES "gnutls_pubkey_export2")
|
||||
set(GNUTLS_PUBKEY_EXPORT2 TRUE)
|
||||
endif()
|
||||
|
||||
find_package(GMP)
|
||||
set_package_properties(GMP PROPERTIES
|
||||
PURPOSE "Required to decompress cryptographic keys."
|
||||
TYPE REQUIRED
|
||||
)
|
||||
if(NOT GMP_FOUND)
|
||||
message(FATAL_ERROR "GMP is required by gnss-sdr if linking against GnuTLS")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
################################################################################
|
||||
|
||||
function(link_to_crypto_dependencies target)
|
||||
if(OPENSSL_FOUND)
|
||||
if(TARGET OpenSSL::SSL)
|
||||
target_link_libraries(${target}
|
||||
PUBLIC
|
||||
OpenSSL::SSL
|
||||
)
|
||||
if(TARGET OpenSSL::Crypto)
|
||||
target_link_libraries(${target}
|
||||
PUBLIC
|
||||
OpenSSL::Crypto
|
||||
)
|
||||
endif()
|
||||
else()
|
||||
target_link_libraries(${target}
|
||||
PUBLIC
|
||||
${OPENSSL_LIBRARIES}
|
||||
"${OPENSSL_CRYPTO_LIBRARIES}"
|
||||
)
|
||||
target_include_directories(${target}
|
||||
PUBLIC
|
||||
${OPENSSL_INCLUDE_DIR}
|
||||
)
|
||||
endif()
|
||||
if(OPENSSL_VERSION)
|
||||
if(OPENSSL_VERSION VERSION_GREATER "3.0.0")
|
||||
target_compile_definitions(${target} PUBLIC -DUSE_OPENSSL_3=1)
|
||||
else()
|
||||
if(NOT OPENSSL_VERSION VERSION_LESS "1.1.1")
|
||||
target_compile_definitions(${target} PUBLIC -DUSE_OPENSSL_111=1)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
else() # GnuTLS
|
||||
target_link_libraries(${target}
|
||||
PUBLIC
|
||||
${GNUTLS_LIBRARIES}
|
||||
${GNUTLS_OPENSSL_LIBRARY}
|
||||
PRIVATE
|
||||
Gmp::gmp
|
||||
)
|
||||
target_include_directories(${target}
|
||||
PUBLIC
|
||||
${GNUTLS_INCLUDE_DIR}
|
||||
)
|
||||
target_compile_definitions(${target} PUBLIC -DUSE_GNUTLS_FALLBACK=1)
|
||||
if(GNUTLS_SIGN_ECDSA_SHA256)
|
||||
target_compile_definitions(${target} PRIVATE -DHAVE_GNUTLS_SIGN_ECDSA_SHA256=1)
|
||||
endif()
|
||||
if(GNUTLS_SIGN_ECDSA_SHA512)
|
||||
target_compile_definitions(${target} PRIVATE -DHAVE_GNUTLS_SIGN_ECDSA_SHA512=1)
|
||||
endif()
|
||||
if(GNUTLS_DIG_SHA3_256)
|
||||
target_compile_definitions(${target} PRIVATE -DHAVE_GNUTLS_DIG_SHA3_256=1)
|
||||
endif()
|
||||
if(GNUTLS_PUBKEY_EXPORT2)
|
||||
target_compile_definitions(${target} PRIVATE -DHAVE_GNUTLS_PUBKEY_EXPORT2=1)
|
||||
endif()
|
||||
if(GNUTLS_HMAC_INIT_WITH_DIGEST)
|
||||
target_compile_definitions(${target} PRIVATE -DHAVE_GNUTLS_HMAC_INIT_WITH_DIGEST=1)
|
||||
endif()
|
||||
if(GNUTLS_MAC_AES_CMAC_128)
|
||||
target_compile_definitions(${target} PRIVATE -DHAVE_GNUTLS_MAC_AES_CMAC_128=1)
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
@ -81,6 +81,25 @@ All notable changes to GNSS-SDR will be documented in this file.
|
||||
This change has a downside in maintainability, since the source code becomes
|
||||
plagued with preprocessor directives required to maintain compatibility both
|
||||
with gflags and glog, and with Abseil.
|
||||
- Historically, GNSS-SDR linked against the GnuTLS library for cryptographic
|
||||
functions. If GnuTLS was not found, then the building system looked for and
|
||||
linked against OpenSSL as a fallback. This was due to the OpenSSL 1.x dual
|
||||
license scheme, which was incompatible with GPL v3.0 license, preventing it
|
||||
from being a mandatory dependency for GNSS-SDR in most GNU/Linux
|
||||
distributions. This issue was solved with the release of OpenSSL 3.0.0, which
|
||||
transitioned to the Apache License 2.0, fully compatible with GPL v3.0.
|
||||
Accordingly, the GNSS-SDR building system now looks for OpenSSL in the first
|
||||
place and, if not found, then it looks for GnuTLS as a fallback.
|
||||
|
||||
### Reliability
|
||||
|
||||
- Implementation of the Galileo Open Service Navigation Message Authentication
|
||||
(OSNMA), a data authentication function for the Galileo Open Service worldwide
|
||||
users, freely accessible to all. OSNMA provides receivers with the assurance
|
||||
that the received Galileo navigation message is coming from the system itself
|
||||
and has not been modified. OSNMA is enabled by default if the receiver
|
||||
configuration defines Galileo E1 OS channels. More details can be found in
|
||||
[Introducing GNSS Navigation Message Authentication](https://gnss-sdr.org/osnma).
|
||||
|
||||
### Improvements in Usability:
|
||||
|
||||
|
@ -919,6 +919,17 @@ Rtklib_Pvt::Rtklib_Pvt(const ConfigurationInterface* configuration,
|
||||
// Use unhealthy satellites
|
||||
pvt_output_parameters.use_unhealthy_sats = configuration->property(role + ".use_unhealthy_sats", pvt_output_parameters.use_unhealthy_sats);
|
||||
|
||||
// OSNMA
|
||||
if (gal_1B_count > 0)
|
||||
{
|
||||
std::string osnma_mode = configuration->property("GNSS-SDR.osnma_mode", std::string(""));
|
||||
bool enable_osnma = configuration->property("GNSS-SDR.osnma_enable", true);
|
||||
if (enable_osnma && osnma_mode == "strict")
|
||||
{
|
||||
pvt_output_parameters.osnma_strict = true;
|
||||
}
|
||||
}
|
||||
|
||||
// make PVT object
|
||||
pvt_ = rtklib_make_pvt_gs(in_streams_, pvt_output_parameters, rtk);
|
||||
DLOG(INFO) << "pvt(" << pvt_->unique_id() << ")";
|
||||
|
@ -52,6 +52,7 @@
|
||||
#include "monitor_pvt.h"
|
||||
#include "monitor_pvt_udp_sink.h"
|
||||
#include "nmea_printer.h"
|
||||
#include "osnma_data.h"
|
||||
#include "pvt_conf.h"
|
||||
#include "rinex_printer.h"
|
||||
#include "rtcm_printer.h"
|
||||
@ -184,7 +185,8 @@ rtklib_pvt_gs::rtklib_pvt_gs(uint32_t nchannels,
|
||||
d_an_printer_enabled(conf_.an_output_enabled),
|
||||
d_log_timetag(conf_.log_source_timetag),
|
||||
d_use_has_corrections(conf_.use_has_corrections),
|
||||
d_use_unhealthy_sats(conf_.use_unhealthy_sats)
|
||||
d_use_unhealthy_sats(conf_.use_unhealthy_sats),
|
||||
d_osnma_strict(conf_.osnma_strict)
|
||||
{
|
||||
// Send feedback message to observables block with the receiver clock offset
|
||||
this->message_port_register_out(pmt::mp("pvt_to_observables"));
|
||||
@ -217,6 +219,19 @@ rtklib_pvt_gs::rtklib_pvt_gs(uint32_t nchannels,
|
||||
#else
|
||||
boost::bind(&rtklib_pvt_gs::msg_handler_has_data, this, _1));
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Galileo OSNMA messages port in
|
||||
this->message_port_register_in(pmt::mp("OSNMA_to_PVT"));
|
||||
this->set_msg_handler(pmt::mp("OSNMA_to_PVT"),
|
||||
#if HAS_GENERIC_LAMBDA
|
||||
[this](auto&& PH1) { msg_handler_osnma(PH1); });
|
||||
#else
|
||||
#if USE_BOOST_BIND_PLACEHOLDERS
|
||||
boost::bind(&rtklib_pvt_gs::msg_handler_osnma, this, boost::placeholders::_1));
|
||||
#else
|
||||
boost::bind(&rtklib_pvt_gs::msg_handler_osnma, this, _1));
|
||||
#endif
|
||||
#endif
|
||||
|
||||
d_initial_carrier_phase_offset_estimation_rads = std::vector<double>(nchannels, 0.0);
|
||||
@ -1639,6 +1654,28 @@ void rtklib_pvt_gs::msg_handler_has_data(const pmt::pmt_t& msg)
|
||||
}
|
||||
|
||||
|
||||
void rtklib_pvt_gs::msg_handler_osnma(const pmt::pmt_t& msg)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Still not sure about what we should receive here.
|
||||
// It should be a structure with the list of PRNs authenticated (NavData and utcData,
|
||||
// so with ADKD0 and ADKD12 validated), their corresponding TOW at the beginning
|
||||
// of the authenticated subframe, and maybe the COP.
|
||||
const size_t msg_type_hash_code = pmt::any_ref(msg).type().hash_code();
|
||||
if (msg_type_hash_code == typeid(std::shared_ptr<OSNMA_NavData>).hash_code())
|
||||
{
|
||||
const auto osnma_data = wht::any_cast<std::shared_ptr<OSNMA_NavData>>(pmt::any_ref(msg));
|
||||
d_auth_nav_data_map[osnma_data->get_prn_d()].insert(osnma_data->get_IOD_nav());
|
||||
}
|
||||
}
|
||||
catch (const wht::bad_any_cast& e)
|
||||
{
|
||||
LOG(WARNING) << "msg_handler_osnma Bad any_cast: " << e.what();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::map<int, Gps_Ephemeris> rtklib_pvt_gs::get_gps_ephemeris_map() const
|
||||
{
|
||||
return d_internal_pvt_solver->gps_ephemeris_map;
|
||||
@ -1997,7 +2034,7 @@ int rtklib_pvt_gs::work(int noutput_items, gr_vector_const_void_star& input_item
|
||||
|
||||
bool store_valid_observable = false;
|
||||
|
||||
if (tmp_eph_iter_gps != d_internal_pvt_solver->gps_ephemeris_map.cend())
|
||||
if (!d_osnma_strict && tmp_eph_iter_gps != d_internal_pvt_solver->gps_ephemeris_map.cend())
|
||||
{
|
||||
const uint32_t prn_aux = tmp_eph_iter_gps->second.PRN;
|
||||
if ((prn_aux == in[i][epoch].PRN) && (std::string(in[i][epoch].Signal, 2) == std::string("1C")) && (d_use_unhealthy_sats || (tmp_eph_iter_gps->second.SV_health == 0)))
|
||||
@ -2012,11 +2049,26 @@ int rtklib_pvt_gs::work(int noutput_items, gr_vector_const_void_star& input_item
|
||||
(((std::string(in[i][epoch].Signal, 2) == std::string("1B")) && (d_use_unhealthy_sats || ((tmp_eph_iter_gal->second.E1B_DVS == false) && (tmp_eph_iter_gal->second.E1B_HS == 0)))) ||
|
||||
((std::string(in[i][epoch].Signal, 2) == std::string("5X")) && (d_use_unhealthy_sats || ((tmp_eph_iter_gal->second.E5a_DVS == false) && (tmp_eph_iter_gal->second.E5a_HS == 0)))) ||
|
||||
((std::string(in[i][epoch].Signal, 2) == std::string("7X")) && (d_use_unhealthy_sats || ((tmp_eph_iter_gal->second.E5b_DVS == false) && (tmp_eph_iter_gal->second.E5b_HS == 0))))))
|
||||
{
|
||||
if (d_osnma_strict && ((std::string(in[i][epoch].Signal, 2) == std::string("1B")) || ((std::string(in[i][epoch].Signal, 2) == std::string("7X")))))
|
||||
{
|
||||
// Pick up only authenticated satellites
|
||||
auto IOD_nav_list = d_auth_nav_data_map.find(tmp_eph_iter_gal->second.PRN);
|
||||
if (IOD_nav_list != d_auth_nav_data_map.cend())
|
||||
{
|
||||
if (IOD_nav_list->second.find(tmp_eph_iter_gal->second.IOD_nav) != IOD_nav_list->second.cend())
|
||||
{
|
||||
store_valid_observable = true;
|
||||
}
|
||||
}
|
||||
if (tmp_eph_iter_cnav != d_internal_pvt_solver->gps_cnav_ephemeris_map.cend())
|
||||
}
|
||||
else
|
||||
{
|
||||
store_valid_observable = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!d_osnma_strict && tmp_eph_iter_cnav != d_internal_pvt_solver->gps_cnav_ephemeris_map.cend())
|
||||
{
|
||||
const uint32_t prn_aux = tmp_eph_iter_cnav->second.PRN;
|
||||
if ((prn_aux == in[i][epoch].PRN) && (((std::string(in[i][epoch].Signal, 2) == std::string("2S")) || (std::string(in[i][epoch].Signal, 2) == std::string("L5")))))
|
||||
@ -2024,7 +2076,7 @@ int rtklib_pvt_gs::work(int noutput_items, gr_vector_const_void_star& input_item
|
||||
store_valid_observable = true;
|
||||
}
|
||||
}
|
||||
if (tmp_eph_iter_glo_gnav != d_internal_pvt_solver->glonass_gnav_ephemeris_map.cend())
|
||||
if (!d_osnma_strict && tmp_eph_iter_glo_gnav != d_internal_pvt_solver->glonass_gnav_ephemeris_map.cend())
|
||||
{
|
||||
const uint32_t prn_aux = tmp_eph_iter_glo_gnav->second.PRN;
|
||||
if ((prn_aux == in[i][epoch].PRN) && ((std::string(in[i][epoch].Signal, 2) == std::string("1G")) || (std::string(in[i][epoch].Signal, 2) == std::string("2G"))))
|
||||
@ -2032,7 +2084,7 @@ int rtklib_pvt_gs::work(int noutput_items, gr_vector_const_void_star& input_item
|
||||
store_valid_observable = true;
|
||||
}
|
||||
}
|
||||
if (tmp_eph_iter_bds_dnav != d_internal_pvt_solver->beidou_dnav_ephemeris_map.cend())
|
||||
if (!d_osnma_strict && tmp_eph_iter_bds_dnav != d_internal_pvt_solver->beidou_dnav_ephemeris_map.cend())
|
||||
{
|
||||
const uint32_t prn_aux = tmp_eph_iter_bds_dnav->second.PRN;
|
||||
if ((prn_aux == in[i][epoch].PRN) && (((std::string(in[i][epoch].Signal, 2) == std::string("B1")) || (std::string(in[i][epoch].Signal, 2) == std::string("B3"))) && (d_use_unhealthy_sats || (tmp_eph_iter_bds_dnav->second.SV_health == 0))))
|
||||
@ -2041,9 +2093,16 @@ int rtklib_pvt_gs::work(int noutput_items, gr_vector_const_void_star& input_item
|
||||
}
|
||||
}
|
||||
if (std::string(in[i][epoch].Signal, 2) == std::string("E6"))
|
||||
{
|
||||
if (d_osnma_strict)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
else
|
||||
{
|
||||
store_valid_observable = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (store_valid_observable)
|
||||
{
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "gnss_block_interface.h"
|
||||
#include "gnss_synchro.h"
|
||||
#include "gnss_time.h"
|
||||
#include "osnma_data.h"
|
||||
#include "rtklib.h"
|
||||
#include <boost/date_time/gregorian/gregorian.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
@ -34,6 +35,7 @@
|
||||
#include <map> // for map
|
||||
#include <memory> // for shared_ptr, unique_ptr
|
||||
#include <queue> // for std::queue
|
||||
#include <set> // for std::set
|
||||
#include <string> // for string
|
||||
#include <sys/types.h> // for key_t
|
||||
#include <vector> // for vector
|
||||
@ -144,6 +146,8 @@ private:
|
||||
|
||||
void msg_handler_has_data(const pmt::pmt_t& msg);
|
||||
|
||||
void msg_handler_osnma(const pmt::pmt_t& msg);
|
||||
|
||||
void initialize_and_apply_carrier_phase_offset();
|
||||
|
||||
void apply_rx_clock_offset(std::map<int, Gnss_Synchro>& observables_map,
|
||||
@ -201,6 +205,7 @@ private:
|
||||
std::map<int, Gnss_Synchro> d_gnss_observables_map;
|
||||
std::map<int, Gnss_Synchro> d_gnss_observables_map_t0;
|
||||
std::map<int, Gnss_Synchro> d_gnss_observables_map_t1;
|
||||
std::map<uint32_t, std::set<uint32_t>> d_auth_nav_data_map;
|
||||
|
||||
std::queue<GnssTime> d_TimeChannelTagTimestamps;
|
||||
|
||||
@ -278,6 +283,7 @@ private:
|
||||
bool d_log_timetag;
|
||||
bool d_use_has_corrections;
|
||||
bool d_use_unhealthy_sats;
|
||||
bool d_osnma_strict;
|
||||
};
|
||||
|
||||
|
||||
|
@ -95,6 +95,7 @@ public:
|
||||
bool use_e6_for_pvt = true;
|
||||
bool use_has_corrections = true;
|
||||
bool use_unhealthy_sats = false;
|
||||
bool osnma_strict = false;
|
||||
|
||||
// PVT KF parameters
|
||||
bool enable_pvt_kf = false;
|
||||
|
@ -45,6 +45,7 @@
|
||||
#include <limits> // for std::numeric_limits
|
||||
#include <map> // for std::map
|
||||
#include <stdexcept> // for std::out_of_range
|
||||
#include <tuple> // for std::tuple
|
||||
#include <typeinfo> // for typeid
|
||||
#include <utility> // for std::pair
|
||||
|
||||
@ -111,6 +112,7 @@ galileo_telemetry_decoder_gs::galileo_telemetry_decoder_gs(
|
||||
d_enable_reed_solomon_inav(false),
|
||||
d_valid_timetag(false),
|
||||
d_E6_TOW_set(false),
|
||||
d_there_are_e1_channels(conf.there_are_e1_channels),
|
||||
d_there_are_e6_channels(conf.there_are_e6_channels),
|
||||
d_use_ced(conf.use_ced)
|
||||
{
|
||||
@ -121,12 +123,19 @@ galileo_telemetry_decoder_gs::galileo_telemetry_decoder_gs(
|
||||
// Control messages to tracking block
|
||||
this->message_port_register_out(pmt::mp("telemetry_to_trk"));
|
||||
|
||||
if (d_there_are_e1_channels)
|
||||
{
|
||||
// register OSM out
|
||||
this->message_port_register_out(pmt::mp("OSNMA_from_TLM"));
|
||||
}
|
||||
|
||||
if (d_there_are_e6_channels)
|
||||
{
|
||||
// register Gal E6 messages HAS out
|
||||
this->message_port_register_out(pmt::mp("E6_HAS_from_TLM"));
|
||||
// register TOW from map out
|
||||
this->message_port_register_out(pmt::mp("TOW_from_TLM"));
|
||||
|
||||
// register TOW to TLM input
|
||||
this->message_port_register_in(pmt::mp("TOW_to_TLM"));
|
||||
// handler for input port
|
||||
@ -361,7 +370,6 @@ void galileo_telemetry_decoder_gs::decode_INAV_word(float *page_part_symbols, in
|
||||
// 1. De-interleave
|
||||
std::vector<float> page_part_symbols_soft_value(frame_length);
|
||||
deinterleaver(GALILEO_INAV_INTERLEAVER_ROWS, GALILEO_INAV_INTERLEAVER_COLS, page_part_symbols, page_part_symbols_soft_value.data());
|
||||
|
||||
// 2. Viterbi decoder
|
||||
// 2.1 Take into account the NOT gate in G2 polynomial (Galileo ICD Figure 13, FEC encoder)
|
||||
for (int32_t i = 0; i < frame_length; i++)
|
||||
@ -431,7 +439,29 @@ void galileo_telemetry_decoder_gs::decode_INAV_word(float *page_part_symbols, in
|
||||
}
|
||||
|
||||
// 4. Push the new navigation data to the queues
|
||||
if (d_inav_nav.have_new_ephemeris() == true)
|
||||
// extract OSNMA bits, reset container.
|
||||
if (d_inav_nav.get_osnma_adkd_0_12_nav_bits().size() == 549)
|
||||
{
|
||||
DLOG(INFO) << "Galileo OSNMA: new ADKD=0/12 navData from " << d_satellite << " at TOW_sf=" << d_inav_nav.get_TOW5() - 25;
|
||||
const auto tmp_obj_osnma = std::make_shared<std::tuple<uint32_t, std::string, uint32_t>>( // < PRNd , navDataBits, TOW_Sosf>
|
||||
d_satellite.get_PRN(),
|
||||
d_inav_nav.get_osnma_adkd_0_12_nav_bits(),
|
||||
d_inav_nav.get_TOW5() - 25);
|
||||
this->message_port_pub(pmt::mp("OSNMA_from_TLM"), pmt::make_any(tmp_obj_osnma));
|
||||
d_inav_nav.reset_osnma_nav_bits_adkd0_12();
|
||||
}
|
||||
if (d_inav_nav.get_osnma_adkd_4_nav_bits().size() == 141)
|
||||
{
|
||||
DLOG(INFO) << "Galileo OSNMA: new ADKD=4 navData from " << d_satellite << " at TOW_sf=" << d_inav_nav.get_TOW6() - 5;
|
||||
const auto tmp_obj = std::make_shared<std::tuple<uint32_t, std::string, uint32_t>>( // < PRNd , navDataBits, TOW_Sosf> // TODO conversion from W6 to W_Start_of_subframe
|
||||
d_satellite.get_PRN(),
|
||||
d_inav_nav.get_osnma_adkd_4_nav_bits(),
|
||||
d_inav_nav.get_TOW6() - 5);
|
||||
this->message_port_pub(pmt::mp("OSNMA_from_TLM"), pmt::make_any(tmp_obj));
|
||||
d_inav_nav.reset_osnma_nav_bits_adkd4();
|
||||
}
|
||||
|
||||
if (d_inav_nav.have_new_ephemeris() == true) // C: tells if W1-->W4 available from same blcok (and W5!)
|
||||
{
|
||||
// get object for this SV (mandatory)
|
||||
const std::shared_ptr<Galileo_Ephemeris> tmp_obj = std::make_shared<Galileo_Ephemeris>(d_inav_nav.get_ephemeris());
|
||||
@ -466,7 +496,7 @@ void galileo_telemetry_decoder_gs::decode_INAV_word(float *page_part_symbols, in
|
||||
else
|
||||
{
|
||||
// If we still do not have ephemeris, check if we have a reduced CED
|
||||
if ((d_band == '1') && d_use_ced && !d_first_eph_sent && (d_inav_nav.have_new_reduced_ced() == true))
|
||||
if ((d_band == '1') && d_use_ced && !d_first_eph_sent && (d_inav_nav.have_new_reduced_ced() == true)) // C: W16 has some Eph. params, uneeded for OSNMa I guess
|
||||
{
|
||||
const std::shared_ptr<Galileo_Ephemeris> tmp_obj = std::make_shared<Galileo_Ephemeris>(d_inav_nav.get_reduced_ced());
|
||||
this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj));
|
||||
@ -482,7 +512,7 @@ void galileo_telemetry_decoder_gs::decode_INAV_word(float *page_part_symbols, in
|
||||
}
|
||||
}
|
||||
|
||||
if (d_inav_nav.have_new_iono_and_GST() == true)
|
||||
if (d_inav_nav.have_new_iono_and_GST() == true) // C: W5
|
||||
{
|
||||
// get object for this SV (mandatory)
|
||||
const std::shared_ptr<Galileo_Iono> tmp_obj = std::make_shared<Galileo_Iono>(d_inav_nav.get_iono());
|
||||
@ -513,7 +543,7 @@ void galileo_telemetry_decoder_gs::decode_INAV_word(float *page_part_symbols, in
|
||||
}
|
||||
}
|
||||
|
||||
if (d_inav_nav.have_new_utc_model() == true)
|
||||
if (d_inav_nav.have_new_utc_model() == true) // C: tells if W6 is available
|
||||
{
|
||||
// get object for this SV (mandatory)
|
||||
const std::shared_ptr<Galileo_Utc_Model> tmp_obj = std::make_shared<Galileo_Utc_Model>(d_inav_nav.get_utc_model());
|
||||
@ -548,7 +578,7 @@ void galileo_telemetry_decoder_gs::decode_INAV_word(float *page_part_symbols, in
|
||||
DLOG(INFO) << "delta_t=" << d_delta_t << "[s]";
|
||||
}
|
||||
|
||||
if (d_inav_nav.have_new_almanac() == true)
|
||||
if (d_inav_nav.have_new_almanac() == true) // flag_almanac_4 tells if W10 available.
|
||||
{
|
||||
const std::shared_ptr<Galileo_Almanac_Helper> tmp_obj = std::make_shared<Galileo_Almanac_Helper>(d_inav_nav.get_almanac());
|
||||
this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj));
|
||||
@ -580,6 +610,12 @@ void galileo_telemetry_decoder_gs::decode_INAV_word(float *page_part_symbols, in
|
||||
DLOG(INFO) << "d_TOW_at_current_symbol_ms=" << d_TOW_at_current_symbol_ms;
|
||||
DLOG(INFO) << "d_nav.WN_0=" << d_inav_nav.get_Galileo_week();
|
||||
}
|
||||
auto newOSNMA = d_inav_nav.have_new_nma();
|
||||
if (d_band == '1' && newOSNMA)
|
||||
{
|
||||
const std::shared_ptr<OSNMA_msg> tmp_obj = std::make_shared<OSNMA_msg>(d_inav_nav.get_osnma_msg());
|
||||
this->message_port_pub(pmt::mp("OSNMA_from_TLM"), pmt::make_any(tmp_obj));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -742,7 +778,7 @@ void galileo_telemetry_decoder_gs::decode_CNAV_word(uint64_t time_stamp, float *
|
||||
std::cout << TEXT_MAGENTA << "Receiving Galileo E6 CNAV dummy pages in channel "
|
||||
<< d_channel << " from satellite "
|
||||
<< d_satellite << " with CN0="
|
||||
<< std::setprecision(2) << cn0 << " dB-Hz" << std::setprecision(default_precision)
|
||||
<< std::setprecision(2) << cn0 << std::setprecision(default_precision) << " dB-Hz"
|
||||
<< TEXT_RESET << std::endl;
|
||||
}
|
||||
}
|
||||
|
@ -152,6 +152,7 @@ private:
|
||||
bool d_enable_reed_solomon_inav;
|
||||
bool d_valid_timetag;
|
||||
bool d_E6_TOW_set;
|
||||
bool d_there_are_e1_channels;
|
||||
bool d_there_are_e6_channels;
|
||||
bool d_use_ced;
|
||||
};
|
||||
|
@ -202,7 +202,7 @@ bool sbas_l1_telemetry_decoder_gs::Symbol_Aligner_And_Decoder::get_bits(const st
|
||||
const int32_t nbits_requested = symbols.size() / D_SYMBOLS_PER_BIT;
|
||||
int32_t nbits_decoded;
|
||||
// fill two vectors with the two possible symbol alignments
|
||||
std::vector<double> symbols_vd1(symbols); // aligned symbol vector -> copy input symbol vector
|
||||
const std::vector<double> symbols_vd1(symbols); // aligned symbol vector -> copy input symbol vector
|
||||
std::vector<double> symbols_vd2; // shifted symbol vector -> add past sample in front of input vector
|
||||
symbols_vd2.push_back(d_past_symbol);
|
||||
for (auto symbol_it = symbols.cbegin(); symbol_it != symbols.cend() - 1; ++symbol_it)
|
||||
|
@ -30,6 +30,11 @@ void Tlm_Conf::SetFromConfiguration(const ConfigurationInterface *configuration,
|
||||
const std::string default_crc_stats_dumpname("telemetry_crc_stats");
|
||||
dump_crc_stats_filename = configuration->property(role + ".dump_crc_stats_filename", default_crc_stats_dumpname);
|
||||
enable_navdata_monitor = configuration->property("NavDataMonitor.enable_monitor", false);
|
||||
if (configuration->property("Channels_1B.count", 0) > 0)
|
||||
{
|
||||
there_are_e1_channels = true;
|
||||
}
|
||||
|
||||
if (configuration->property("Channels_E6.count", 0) > 0)
|
||||
{
|
||||
there_are_e6_channels = true;
|
||||
|
@ -42,6 +42,7 @@ public:
|
||||
bool enable_reed_solomon{false}; // for INAV message in Galileo E1B
|
||||
bool dump_crc_stats{false}; // telemetry CRC statistics
|
||||
bool enable_navdata_monitor{false};
|
||||
bool there_are_e1_channels{false};
|
||||
bool there_are_e6_channels{false};
|
||||
bool use_ced{false};
|
||||
};
|
||||
|
@ -9,34 +9,42 @@ protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS ${GNSSSDR_SOURCE_DIR}/docs/protobuf/
|
||||
add_subdirectory(supl)
|
||||
|
||||
set(CORE_LIBS_SOURCES
|
||||
ini.cc
|
||||
INIReader.cc
|
||||
string_converter.cc
|
||||
gnss_sdr_supl_client.cc
|
||||
gnss_sdr_sample_counter.cc
|
||||
channel_status_msg_receiver.cc
|
||||
channel_event.cc
|
||||
channel_status_msg_receiver.cc
|
||||
command_event.cc
|
||||
galileo_e6_has_msg_receiver.cc
|
||||
galileo_tow_map.cc
|
||||
gnss_crypto.cc
|
||||
gnss_sdr_sample_counter.cc
|
||||
gnss_sdr_supl_client.cc
|
||||
ini.cc
|
||||
INIReader.cc
|
||||
nav_message_monitor.cc
|
||||
nav_message_udp_sink.cc
|
||||
galileo_tow_map.cc
|
||||
osnma_helper.cc
|
||||
osnma_msg_receiver.cc
|
||||
osnma_nav_data_manager.cc
|
||||
string_converter.cc
|
||||
)
|
||||
|
||||
set(CORE_LIBS_HEADERS
|
||||
channel_event.h
|
||||
channel_status_msg_receiver.h
|
||||
command_event.h
|
||||
galileo_tow_map.h
|
||||
gnss_crypto.h
|
||||
gnss_sdr_sample_counter.h
|
||||
gnss_sdr_supl_client.h
|
||||
ini.h
|
||||
INIReader.h
|
||||
string_converter.h
|
||||
gnss_sdr_supl_client.h
|
||||
gnss_sdr_sample_counter.h
|
||||
channel_status_msg_receiver.h
|
||||
channel_event.h
|
||||
command_event.h
|
||||
nav_message_monitor.h
|
||||
nav_message_packet.h
|
||||
nav_message_udp_sink.h
|
||||
osnma_helper.h
|
||||
osnma_msg_receiver.h
|
||||
osnma_nav_data_manager.h
|
||||
serdes_nav_message.h
|
||||
nav_message_monitor.h
|
||||
galileo_tow_map.h
|
||||
string_converter.h
|
||||
)
|
||||
|
||||
if(ENABLE_FPGA)
|
||||
@ -91,10 +99,10 @@ target_link_libraries(core_libs
|
||||
core_libs_supl
|
||||
core_system_parameters
|
||||
pvt_libs
|
||||
algorithms_libs
|
||||
PRIVATE
|
||||
algorithms_libs
|
||||
Boost::serialization
|
||||
Boost::system
|
||||
Pugixml::pugixml
|
||||
)
|
||||
|
||||
@ -122,6 +130,10 @@ target_include_directories(core_libs
|
||||
${GNSSSDR_SOURCE_DIR}/src/core/interfaces
|
||||
)
|
||||
|
||||
# links to the appropriate library and defines
|
||||
# USE_GNUTLS_FALLBACK, USE_OPENSSL_3, or USE_OPENSSL_111 accordingly.
|
||||
link_to_crypto_dependencies(core_libs)
|
||||
|
||||
if(USE_GENERIC_LAMBDAS)
|
||||
set(has_generic_lambdas HAS_GENERIC_LAMBDA=1)
|
||||
set(no_has_generic_lambdas HAS_GENERIC_LAMBDA=0)
|
||||
|
1919
src/core/libs/gnss_crypto.cc
Normal file
1919
src/core/libs/gnss_crypto.cc
Normal file
File diff suppressed because it is too large
Load Diff
103
src/core/libs/gnss_crypto.h
Normal file
103
src/core/libs/gnss_crypto.h
Normal file
@ -0,0 +1,103 @@
|
||||
/*!
|
||||
* \file gnss_crypto.h
|
||||
* \brief Class for computing cryptographic functions
|
||||
* \author Carles Fernandez, 2023-2024. cfernandez(at)cttc.es
|
||||
* Cesare Ghionoiu Martinez, 2023-2024. c.ghionoiu-martinez@tu-braunschweig.de
|
||||
*
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
|
||||
* This file is part of GNSS-SDR.
|
||||
*
|
||||
* Copyright (C) 2010-2024 (see AUTHORS file for a list of contributors)
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef GNSS_SDR_GNSS_CRYPTO_H
|
||||
#define GNSS_SDR_GNSS_CRYPTO_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#if USE_GNUTLS_FALLBACK
|
||||
#include <gnutls/abstract.h>
|
||||
#include <gnutls/gnutls.h>
|
||||
#else // OpenSSL
|
||||
#include <openssl/ec.h>
|
||||
#endif
|
||||
|
||||
/** \addtogroup Core
|
||||
* \{ */
|
||||
/** \addtogroup Core_Receiver_Library
|
||||
* \{ */
|
||||
|
||||
/*!
|
||||
* \brief Class implementing cryptographic functions
|
||||
* for Navigation Message Authentication
|
||||
*/
|
||||
class Gnss_Crypto
|
||||
{
|
||||
public:
|
||||
Gnss_Crypto(); //!< Default constructor
|
||||
|
||||
/*!
|
||||
* Constructor with a .crt or .pem file for the ECDSA Public Key
|
||||
* and a XML file for the Merkle Tree root.
|
||||
* Files can be downloaded by registering at https://www.gsc-europa.eu/
|
||||
*/
|
||||
Gnss_Crypto(const std::string& certFilePath, const std::string& merkleTreePath);
|
||||
~Gnss_Crypto(); //!< Default destructor
|
||||
|
||||
bool have_public_key() const; //!< Returns true if the ECDSA Public Key is already loaded
|
||||
|
||||
/*!
|
||||
* Stores the ECDSA Public Key in a .pem file, which is read in a following run if the .crt file is not found
|
||||
*/
|
||||
bool store_public_key(const std::string& pubKeyFilePath) const;
|
||||
|
||||
bool verify_signature_ecdsa_p256(const std::vector<uint8_t>& message, const std::vector<uint8_t>& signature) const; //!< Verify ECDSA-P256 signature (message in plain hex, signature in raw format)
|
||||
bool verify_signature_ecdsa_p521(const std::vector<uint8_t>& message, const std::vector<uint8_t>& signature) const; //!< Verify ECDSA-P521 signature (message in plain hex, signature in raw format)
|
||||
|
||||
std::vector<uint8_t> compute_SHA_256(const std::vector<uint8_t>& input) const; //!< Computes SHA-256 hash
|
||||
std::vector<uint8_t> compute_SHA3_256(const std::vector<uint8_t>& input) const; //!< Computes SHA3-256 hash
|
||||
std::vector<uint8_t> compute_HMAC_SHA_256(const std::vector<uint8_t>& key, const std::vector<uint8_t>& input) const; //!< Computes HMAC-SHA-256 message authentication code
|
||||
std::vector<uint8_t> compute_CMAC_AES(const std::vector<uint8_t>& key, const std::vector<uint8_t>& input) const; //!< Computes CMAC-AES message authentication code
|
||||
|
||||
std::vector<uint8_t> get_merkle_root() const; //!< Gets the Merkle Tree root node (\f$ x_{4,0} \f$)
|
||||
std::string get_public_key_type() const; //!< Gets the ECDSA Public Key type (ECDSA P-256 / ECDSA P-521 / Unknown)
|
||||
|
||||
void set_public_key(const std::vector<uint8_t>& publickey); //!< Sets the ECDSA Public Key (publickey compressed format)
|
||||
void set_public_key_type(const std::string& public_key_type); //!< Sets the ECDSA Public Key type (ECDSA P-256 / ECDSA P-521)
|
||||
void set_merkle_root(const std::vector<uint8_t>& v); //!< Sets the Merkle Tree root node x(\f$ x_{4,0} \f$)
|
||||
void read_merkle_xml(const std::string& merkleFilePath); //!> Reads the XML file provided from the GSC OSNMA server
|
||||
|
||||
private:
|
||||
void readPublicKeyFromPEM(const std::string& pemFilePath);
|
||||
bool readPublicKeyFromCRT(const std::string& crtFilePath);
|
||||
bool convert_raw_to_der_ecdsa(const std::vector<uint8_t>& raw_signature, std::vector<uint8_t>& der_signature) const;
|
||||
std::vector<uint8_t> convert_from_hex_str(const std::string& input) const; // TODO - deprecate if OSNMA helper is to do this operation
|
||||
#if USE_GNUTLS_FALLBACK
|
||||
void decompress_public_key_secp256r1(const std::vector<uint8_t>& compressed_key, std::vector<uint8_t>& x, std::vector<uint8_t>& y) const;
|
||||
void decompress_public_key_secp521r1(const std::vector<uint8_t>& compressed_key, std::vector<uint8_t>& x, std::vector<uint8_t>& y) const;
|
||||
bool pubkey_copy(gnutls_pubkey_t src, gnutls_pubkey_t* dest);
|
||||
gnutls_pubkey_t d_PublicKey{};
|
||||
#else // OpenSSL
|
||||
#if USE_OPENSSL_3
|
||||
bool pubkey_copy(EVP_PKEY* src, EVP_PKEY** dest);
|
||||
EVP_PKEY* d_PublicKey{};
|
||||
#else // OpenSSL 1.x
|
||||
bool pubkey_copy(EC_KEY* src, EC_KEY** dest);
|
||||
EC_KEY* d_PublicKey = nullptr;
|
||||
#endif
|
||||
#endif
|
||||
std::vector<uint8_t> d_x_4_0;
|
||||
std::string d_PublicKeyType;
|
||||
};
|
||||
|
||||
/** \} */
|
||||
/** \} */
|
||||
|
||||
#endif // GNSS_SDR_GNSS_CRYPTO_H
|
175
src/core/libs/osnma_helper.cc
Normal file
175
src/core/libs/osnma_helper.cc
Normal file
@ -0,0 +1,175 @@
|
||||
/*!
|
||||
* \file osnma_helper.h
|
||||
* \brief Class for auxiliary osnma functions
|
||||
* \author Carles Fernandez-Prades, 2024 cfernandez(at)cttc.es
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
|
||||
* This file is part of GNSS-SDR.
|
||||
*
|
||||
* Copyright (C) 2010-2023 (see AUTHORS file for a list of contributors)
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "osnma_helper.h"
|
||||
#include <bitset>
|
||||
#include <chrono>
|
||||
#include <iomanip>
|
||||
#include <ios>
|
||||
#include <sstream>
|
||||
|
||||
|
||||
Osnma_Helper::Osnma_Helper()
|
||||
{
|
||||
GST_START_EPOCH.tm_mday = 22;
|
||||
GST_START_EPOCH.tm_mon = 7; // August (0-based)
|
||||
GST_START_EPOCH.tm_year = 1999 - 1900;
|
||||
}
|
||||
|
||||
|
||||
uint32_t Osnma_Helper::compute_gst(uint32_t WN, uint32_t TOW) const
|
||||
{
|
||||
return (WN & 0x00000FFF) << 20 | (TOW & 0x000FFFFF);
|
||||
}
|
||||
|
||||
|
||||
uint32_t Osnma_Helper::compute_gst(tm& input)
|
||||
{
|
||||
auto epoch_time_point = std::chrono::system_clock::from_time_t(mktime(&GST_START_EPOCH));
|
||||
auto input_time_point = std::chrono::system_clock::from_time_t(mktime(&input));
|
||||
|
||||
// Get the duration from epoch in seconds
|
||||
auto duration_sec = std::chrono::duration_cast<std::chrono::seconds>(input_time_point - epoch_time_point);
|
||||
|
||||
// Calculate the week number (WN) and time of week (TOW)
|
||||
const uint32_t sec_in_week = 604800;
|
||||
const uint32_t week_number = duration_sec.count() / sec_in_week;
|
||||
const uint32_t time_of_week = duration_sec.count() % sec_in_week;
|
||||
return compute_gst(week_number, time_of_week);
|
||||
}
|
||||
|
||||
|
||||
uint32_t Osnma_Helper::compute_gst_now()
|
||||
{
|
||||
time_t now = time(nullptr);
|
||||
struct tm local_tm = *std::localtime(&now);
|
||||
struct tm utc_tm = *std::gmtime(&now);
|
||||
auto timezone_offset = std::mktime(&utc_tm) - std::mktime(&local_tm);
|
||||
auto epoch_time_point = std::chrono::system_clock::from_time_t(std::mktime(&GST_START_EPOCH) - timezone_offset) + std::chrono::seconds(13);
|
||||
auto duration_sec = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now() - epoch_time_point);
|
||||
const uint32_t sec_in_week = 604800;
|
||||
const uint32_t week_number = duration_sec.count() / sec_in_week;
|
||||
const uint32_t time_of_week = duration_sec.count() % sec_in_week;
|
||||
return compute_gst(week_number, time_of_week);
|
||||
}
|
||||
|
||||
|
||||
std::vector<uint8_t> Osnma_Helper::gst_to_uint8(uint32_t GST) const
|
||||
{
|
||||
std::vector<uint8_t> res;
|
||||
|
||||
res.push_back(static_cast<uint8_t>((GST & 0xFF000000) >> 24));
|
||||
res.push_back(static_cast<uint8_t>((GST & 0x00FF0000) >> 16));
|
||||
res.push_back(static_cast<uint8_t>((GST & 0x0000FF00) >> 8));
|
||||
res.push_back(static_cast<uint8_t>(GST & 0x000000FF));
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Convert a binary string to a vector of bytes.
|
||||
*
|
||||
* This function takes a binary string and converts it into a vector of uint8_t bytes.
|
||||
* The binary string is padded with zeros if necessary to ensure that the total number
|
||||
* of bits is a multiple of a byte.
|
||||
*
|
||||
* @param binaryString The binary string to be converted.
|
||||
* @return The vector of bytes converted from the binary string.
|
||||
*/
|
||||
std::vector<uint8_t> Osnma_Helper::bytes(const std::string& binaryString) const
|
||||
{
|
||||
std::vector<uint8_t> bytes;
|
||||
|
||||
// Determine the size of the padding needed.
|
||||
size_t padding_size = binaryString.size() % 8;
|
||||
|
||||
std::string padded_binary = binaryString;
|
||||
|
||||
if (padding_size != 0)
|
||||
{
|
||||
padding_size = 8 - padding_size; // Compute padding size
|
||||
padded_binary.append(padding_size, '0'); // Append zeros to the binary string
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < padded_binary.size(); i += 8)
|
||||
{
|
||||
uint8_t byte = std::bitset<8>(padded_binary.substr(i, 8)).to_ulong();
|
||||
bytes.push_back(byte);
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
|
||||
std::string Osnma_Helper::verification_status_str(int status) const
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case 0:
|
||||
return "SUCCESS";
|
||||
case 1:
|
||||
return "FAIL";
|
||||
case 2:
|
||||
return "UNVERIFIED";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string Osnma_Helper::convert_to_hex_string(const std::vector<uint8_t>& vector) const
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << std::hex << std::setfill('0');
|
||||
for (auto byte : vector)
|
||||
{
|
||||
ss << std::setw(2) << static_cast<int>(byte);
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
|
||||
std::vector<uint8_t> Osnma_Helper::convert_from_hex_string(const std::string& hex_string) const
|
||||
{
|
||||
std::vector<uint8_t> result;
|
||||
|
||||
std::string adjusted_hex_string = hex_string;
|
||||
if (hex_string.length() % 2 != 0)
|
||||
{
|
||||
adjusted_hex_string = "0" + hex_string;
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < adjusted_hex_string.length(); i += 2)
|
||||
{
|
||||
std::string byte_string = adjusted_hex_string.substr(i, 2);
|
||||
auto byte = static_cast<uint8_t>(std::stoul(byte_string, nullptr, 16));
|
||||
result.push_back(byte);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
uint32_t Osnma_Helper::get_WN(uint32_t GST) const
|
||||
{
|
||||
return (GST & 0xFFF00000) >> 20;
|
||||
}
|
||||
|
||||
|
||||
uint32_t Osnma_Helper::get_TOW(uint32_t GST) const
|
||||
{
|
||||
return GST & 0x000FFFFF;
|
||||
}
|
51
src/core/libs/osnma_helper.h
Normal file
51
src/core/libs/osnma_helper.h
Normal file
@ -0,0 +1,51 @@
|
||||
/*!
|
||||
* \file osnma_helper.h
|
||||
* \brief Class for auxiliary osnma functions
|
||||
* \author Carles Fernandez-Prades, 2024 cfernandez(at)cttc.es
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
|
||||
* This file is part of GNSS-SDR.
|
||||
*
|
||||
* Copyright (C) 2010-2023 (see AUTHORS file for a list of contributors)
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef GNSS_SDR_OSNMA_HELPER_H
|
||||
#define GNSS_SDR_OSNMA_HELPER_H
|
||||
|
||||
|
||||
#include <cstdint>
|
||||
#include <ctime>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
/** \addtogroup Core
|
||||
* \{ */
|
||||
/** \addtogroup Core_Receiver_Library
|
||||
* \{ */
|
||||
|
||||
class Osnma_Helper
|
||||
{
|
||||
public:
|
||||
Osnma_Helper();
|
||||
~Osnma_Helper() = default;
|
||||
uint32_t compute_gst(uint32_t WN, uint32_t TOW) const;
|
||||
uint32_t compute_gst(std::tm& input);
|
||||
uint32_t compute_gst_now();
|
||||
uint32_t get_WN(uint32_t GST) const;
|
||||
uint32_t get_TOW(uint32_t GST) const;
|
||||
std::vector<uint8_t> gst_to_uint8(uint32_t GST) const;
|
||||
std::vector<uint8_t> bytes(const std::string& binaryString) const;
|
||||
std::string verification_status_str(int status) const;
|
||||
std::string convert_to_hex_string(const std::vector<uint8_t>& vector) const;
|
||||
std::vector<uint8_t> convert_from_hex_string(const std::string& hex_string) const; // TODO remove similar function in gnss_crypto
|
||||
std::tm GST_START_EPOCH{};
|
||||
};
|
||||
|
||||
/** \} */
|
||||
/** \} */
|
||||
#endif // GNSS_SDR_OSNMA_HELPER_H
|
2085
src/core/libs/osnma_msg_receiver.cc
Normal file
2085
src/core/libs/osnma_msg_receiver.cc
Normal file
File diff suppressed because it is too large
Load Diff
176
src/core/libs/osnma_msg_receiver.h
Normal file
176
src/core/libs/osnma_msg_receiver.h
Normal file
@ -0,0 +1,176 @@
|
||||
/*!
|
||||
* \file osnma_msg_receiver.h
|
||||
* \brief GNU Radio block that processes Galileo OSNMA data received from
|
||||
* Galileo E1B telemetry blocks. After successful decoding, sends the content to
|
||||
* the PVT block.
|
||||
* \author Carles Fernandez-Prades, 2023-2024. cfernandez(at)cttc.es
|
||||
* Cesare Ghionoiu Martinez, 2023-2024. c.ghionoiu-martinez@tu-braunschweig.de
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
|
||||
* This file is part of GNSS-SDR.
|
||||
*
|
||||
* Copyright (C) 2010-2024 (see AUTHORS file for a list of contributors)
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef GNSS_SDR_OSNMA_MSG_RECEIVER_H
|
||||
#define GNSS_SDR_OSNMA_MSG_RECEIVER_H
|
||||
|
||||
#define FRIEND_TEST(test_case_name, test_name) \
|
||||
friend class test_case_name##_##test_name##_Test
|
||||
|
||||
#include "galileo_inav_message.h" // for OSNMA_msg
|
||||
#include "gnss_block_interface.h" // for gnss_shared_ptr
|
||||
#include "osnma_data.h" // for OSNMA_data structures
|
||||
#include "osnma_nav_data_manager.h" // for OSNMA_NavDataManager
|
||||
#include <gnuradio/block.h> // for gr::block
|
||||
#include <pmt/pmt.h> // for pmt::pmt_t
|
||||
#include <array> // for std::array
|
||||
#include <cstdint> // for uint8_t
|
||||
#include <ctime> // for std::time_t
|
||||
#include <map> // for std::map, std::multimap
|
||||
#include <memory> // for std::shared_ptr
|
||||
#include <string> // for std::string
|
||||
#include <utility> // for std::pair
|
||||
#include <vector> // for std::vector
|
||||
|
||||
/** \addtogroup Core
|
||||
* \{ */
|
||||
/** \addtogroup Core_Receiver_Library
|
||||
* \{ */
|
||||
|
||||
class OSNMA_DSM_Reader;
|
||||
class Gnss_Crypto;
|
||||
class Osnma_Helper;
|
||||
class osnma_msg_receiver;
|
||||
|
||||
using osnma_msg_receiver_sptr = gnss_shared_ptr<osnma_msg_receiver>;
|
||||
|
||||
osnma_msg_receiver_sptr osnma_msg_receiver_make(const std::string& pemFilePath, const std::string& merkleFilePath, bool strict_mode = false);
|
||||
|
||||
/*!
|
||||
* \brief GNU Radio block that receives asynchronous OSNMA messages
|
||||
* from the telemetry blocks, stores them in memory, and decodes OSNMA info
|
||||
* when enough data have been received.
|
||||
* The decoded OSNMA data is sent to the PVT block.
|
||||
*/
|
||||
class osnma_msg_receiver : public gr::block
|
||||
{
|
||||
public:
|
||||
~osnma_msg_receiver() = default; //!< Default destructor
|
||||
bool verify_dsm_pkr(const DSM_PKR_message& message) const; //!< Public for benchmarking purposes
|
||||
void msg_handler_osnma(const pmt::pmt_t& msg); //!< For testing purposes
|
||||
void read_merkle_xml(const std::string& merklepath); //!< Public for testing purposes
|
||||
void set_merkle_root(const std::vector<uint8_t>& v); //!< Public for benchmarking purposes
|
||||
|
||||
private:
|
||||
friend osnma_msg_receiver_sptr osnma_msg_receiver_make(const std::string& pemFilePath, const std::string& merkleFilePath, bool strict_mode);
|
||||
osnma_msg_receiver(const std::string& crtFilePath, const std::string& merkleFilePath, bool strict_mode);
|
||||
|
||||
void process_osnma_message(const std::shared_ptr<OSNMA_msg>& osnma_msg);
|
||||
void read_nma_header(uint8_t nma_header);
|
||||
void read_dsm_header(uint8_t dsm_header);
|
||||
void read_dsm_block(const std::shared_ptr<OSNMA_msg>& osnma_msg);
|
||||
void process_dsm_block(const std::shared_ptr<OSNMA_msg>& osnma_msg);
|
||||
void process_dsm_message(const std::vector<uint8_t>& dsm_msg, const uint8_t& nma_header);
|
||||
void read_and_process_mack_block(const std::shared_ptr<OSNMA_msg>& osnma_msg);
|
||||
void read_mack_header();
|
||||
void read_mack_body();
|
||||
void process_mack_message();
|
||||
void remove_verified_tags();
|
||||
void control_tags_awaiting_verify_size();
|
||||
void display_data();
|
||||
void send_data_to_pvt(const std::vector<OSNMA_NavData>& data);
|
||||
|
||||
bool verify_tesla_key(std::vector<uint8_t>& key, uint32_t TOW);
|
||||
bool verify_tag(Tag& tag) const;
|
||||
bool tag_has_nav_data_available(const Tag& t) const;
|
||||
bool tag_has_key_available(const Tag& t) const;
|
||||
bool verify_macseq(const MACK_message& mack);
|
||||
|
||||
bool store_dsm_kroot(const std::vector<uint8_t>& dsm, const uint8_t nma_header) const;
|
||||
|
||||
std::pair<std::vector<uint8_t>, uint8_t> parse_dsm_kroot() const;
|
||||
std::vector<uint8_t> get_merkle_tree_leaves(const DSM_PKR_message& dsm_pkr_message) const;
|
||||
std::vector<uint8_t> compute_merkle_root(const DSM_PKR_message& dsm_pkr_message, const std::vector<uint8_t>& m_i) const;
|
||||
std::vector<uint8_t> build_message(Tag& tag) const;
|
||||
std::vector<uint8_t> hash_chain(uint32_t num_of_hashes_needed, const std::vector<uint8_t>& key, uint32_t GST_SFi, const uint8_t lk_bytes) const;
|
||||
std::vector<MACK_tag_and_info> verify_macseq_new(const MACK_message& mack);
|
||||
|
||||
std::map<uint32_t, std::map<uint32_t, OSNMA_NavData>> d_satellite_nav_data; // map holding OSNMA_NavData sorted by SVID (first key) and TOW (second key).
|
||||
std::map<uint32_t, std::vector<uint8_t>> d_tesla_keys; // tesla keys over time, sorted by TOW
|
||||
std::multimap<uint32_t, Tag> d_tags_awaiting_verify; // container with tags to verify from arbitrary SVIDs, sorted by TOW
|
||||
|
||||
std::vector<uint8_t> d_new_public_key;
|
||||
std::vector<uint8_t> d_tags_to_verify{0, 4, 12};
|
||||
std::vector<MACK_message> d_macks_awaiting_MACSEQ_verification;
|
||||
|
||||
std::array<std::array<uint8_t, 256>, 16> d_dsm_message{}; // structure for recording DSM blocks, when filled it sends them to parse and resets itself.
|
||||
std::array<std::array<uint8_t, 16>, 16> d_dsm_id_received{};
|
||||
std::array<uint16_t, 16> d_number_of_blocks{};
|
||||
std::array<uint8_t, 60> d_mack_message{}; // C: 480 b
|
||||
|
||||
std::unique_ptr<Gnss_Crypto> d_crypto; // class for cryptographic functions
|
||||
std::unique_ptr<OSNMA_DSM_Reader> d_dsm_reader; // osnma parameters parser
|
||||
std::unique_ptr<Osnma_Helper> d_helper; // helper class with auxiliary functions
|
||||
std::unique_ptr<OSNMA_NavDataManager> d_nav_data_manager; // refactor for holding and processing navigation data
|
||||
|
||||
OSNMA_data d_osnma_data{};
|
||||
|
||||
uint32_t d_last_received_GST{0}; // latest GST received
|
||||
uint32_t d_GST_Sf{}; // Scaled GST time for cryptographic computations
|
||||
uint32_t d_GST_Rx{0}; // local GST receiver time
|
||||
uint32_t d_last_verified_key_GST{0}; // GST for the latest verified TESLA key
|
||||
uint32_t d_GST_0{}; // Time of applicability GST (KROOT + 30 s)
|
||||
uint32_t d_GST_SIS{}; // GST coming from W6 and W5 of SIS
|
||||
uint32_t d_GST_PKR_PKREV_start{};
|
||||
uint32_t d_GST_PKR_AM_start{};
|
||||
uint32_t d_GST_chain_renewal_start{};
|
||||
uint32_t d_GST_chain_revocation_start{};
|
||||
|
||||
uint32_t d_count_successful_tags{0};
|
||||
uint32_t d_count_failed_tags{0};
|
||||
uint32_t d_count_failed_Kroot{0};
|
||||
uint32_t d_count_failed_pubKey{0}; // failed public key verifications against Merkle root
|
||||
uint32_t d_count_failed_macseq{0};
|
||||
|
||||
uint8_t const d_T_L{30}; // s RG Section 2.1
|
||||
uint8_t d_new_public_key_id{};
|
||||
|
||||
bool d_new_data{false};
|
||||
bool d_public_key_verified{false};
|
||||
bool d_kroot_verified{false};
|
||||
bool d_tesla_key_verified{false};
|
||||
bool d_strict_mode{false};
|
||||
bool d_flag_hot_start{false};
|
||||
bool d_flag_PK_renewal{false};
|
||||
bool d_flag_PK_revocation{false};
|
||||
bool d_flag_NPK_set{false};
|
||||
bool d_flag_alert_message{false};
|
||||
bool d_flag_chain_renewal{false};
|
||||
bool d_flag_chain_revocation{false};
|
||||
|
||||
// Provide access to inner functions to Gtest
|
||||
FRIEND_TEST(OsnmaMsgReceiverTest, TeslaKeyVerification);
|
||||
FRIEND_TEST(OsnmaMsgReceiverTest, TagVerification);
|
||||
FRIEND_TEST(OsnmaMsgReceiverTest, BuildTagMessageM0);
|
||||
FRIEND_TEST(OsnmaMsgReceiverTest, VerifyPublicKey);
|
||||
FRIEND_TEST(OsnmaMsgReceiverTest, ComputeBaseLeaf);
|
||||
FRIEND_TEST(OsnmaMsgReceiverTest, ComputeMerkleRoot);
|
||||
FRIEND_TEST(OsnmaTestVectors, NominalTestConf1);
|
||||
FRIEND_TEST(OsnmaTestVectors, NominalTestConf2);
|
||||
FRIEND_TEST(OsnmaTestVectors, PublicKeyRenewal);
|
||||
FRIEND_TEST(OsnmaTestVectors, PublicKeyRevocation);
|
||||
FRIEND_TEST(OsnmaTestVectors, ChainRenewal);
|
||||
FRIEND_TEST(OsnmaTestVectors, ChainRevocation);
|
||||
FRIEND_TEST(OsnmaTestVectors, AlertMessage);
|
||||
};
|
||||
|
||||
|
||||
/** \} */
|
||||
/** \} */
|
||||
#endif // GNSS_SDR_OSNMA_MSG_RECEIVER_H
|
322
src/core/libs/osnma_nav_data_manager.cc
Normal file
322
src/core/libs/osnma_nav_data_manager.cc
Normal file
@ -0,0 +1,322 @@
|
||||
/*!
|
||||
* \file osnma_nav_data_manager.cc
|
||||
* \brief Class for Galileo OSNMA navigation data management
|
||||
* \author Cesare Ghionoiu-Martinez, 2020-2023 cesare.martinez(at)proton.me
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
|
||||
* This file is part of GNSS-SDR.
|
||||
*
|
||||
* Copyright (C) 2010-2023 (see AUTHORS file for a list of contributors)
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "osnma_nav_data_manager.h"
|
||||
#if USE_GLOG_AND_GFLAGS
|
||||
#include <glog/logging.h> // for DLOG
|
||||
#else
|
||||
#include <absl/log/log.h>
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Adds the navigation data bits to the container holding OSNMA_NavData objects.
|
||||
*
|
||||
* @param nav_bits The navigation bits.
|
||||
* @param PRNd The satellite ID.
|
||||
* @param TOW The TOW of the received data.
|
||||
*/
|
||||
void OSNMA_NavDataManager::add_navigation_data(const std::string& nav_bits, uint32_t PRNd, uint32_t TOW)
|
||||
{
|
||||
if (not have_nav_data(nav_bits, PRNd, TOW))
|
||||
{
|
||||
d_satellite_nav_data[PRNd][TOW].add_nav_data(nav_bits);
|
||||
d_satellite_nav_data[PRNd][TOW].set_prn_d(PRNd);
|
||||
d_satellite_nav_data[PRNd][TOW].set_tow_sf0(TOW);
|
||||
d_satellite_nav_data[PRNd][TOW].set_last_received_TOW(TOW);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief loops over the verified tags and updates the navigation data tag length
|
||||
*/
|
||||
void OSNMA_NavDataManager::update_nav_data(const std::multimap<uint32_t, Tag>& tags_verified, uint8_t tag_size)
|
||||
{
|
||||
if (d_satellite_nav_data.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
// loop through all tags
|
||||
for (const auto& tag : tags_verified)
|
||||
{
|
||||
// if tag status is verified, look for corresponding OSNMA_NavData and add increase verified tag bits.
|
||||
if (tag.second.status == Tag::e_verification_status::SUCCESS)
|
||||
{
|
||||
auto sat_it = d_satellite_nav_data.find(tag.second.PRN_d);
|
||||
if (sat_it == d_satellite_nav_data.end())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
auto& tow_map = sat_it->second;
|
||||
for (auto& tow_it : tow_map) // note: starts with smallest (i.e. oldest) navigation dataset
|
||||
{
|
||||
std::string nav_data;
|
||||
if (tag.second.ADKD == 0 || tag.second.ADKD == 12)
|
||||
{
|
||||
nav_data = tow_it.second.get_ephemeris_data();
|
||||
}
|
||||
else if (tag.second.ADKD == 4)
|
||||
{
|
||||
nav_data = tow_it.second.get_utc_data();
|
||||
}
|
||||
// find associated OSNMA_NavData
|
||||
if (tag.second.nav_data == nav_data)
|
||||
{
|
||||
d_satellite_nav_data[tag.second.PRN_d][tow_it.first].set_update_verified_bits(tag_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::vector<OSNMA_NavData> OSNMA_NavDataManager::get_verified_data()
|
||||
{
|
||||
std::vector<OSNMA_NavData> result;
|
||||
for (const auto& prna : d_satellite_nav_data)
|
||||
{
|
||||
for (const auto& tow_navdata : prna.second)
|
||||
{
|
||||
if (tow_navdata.second.get_verified_bits() >= L_t_min)
|
||||
{
|
||||
result.push_back(tow_navdata.second);
|
||||
d_satellite_nav_data[prna.first][tow_navdata.first].set_verified_status(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
bool OSNMA_NavDataManager::have_nav_data(uint32_t PRNd, uint32_t TOW, uint8_t ADKD) const
|
||||
{
|
||||
const auto sat_it = d_satellite_nav_data.find(PRNd);
|
||||
if (sat_it == d_satellite_nav_data.cend())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto tow_it = sat_it->second.find(TOW);
|
||||
if (tow_it == sat_it->second.cend())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (ADKD)
|
||||
{
|
||||
case 0:
|
||||
case 12:
|
||||
return !tow_it->second.get_ephemeris_data().empty();
|
||||
case 4:
|
||||
return !tow_it->second.get_utc_data().empty();
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string OSNMA_NavDataManager::get_navigation_data(const Tag& tag) const
|
||||
{
|
||||
// Check if Dummy Tag, navData is all zeros
|
||||
if (tag.cop == 0)
|
||||
{
|
||||
if (tag.ADKD == 0 || tag.ADKD == 12)
|
||||
{
|
||||
return {std::string(549, '0')};
|
||||
}
|
||||
else if (tag.ADKD == 4)
|
||||
{
|
||||
return {std::string(141, '0')};
|
||||
}
|
||||
}
|
||||
auto prn_it = d_satellite_nav_data.find(tag.PRN_d);
|
||||
if (prn_it == d_satellite_nav_data.end())
|
||||
{
|
||||
return "";
|
||||
}
|
||||
// satellite was found, check if TOW exists in inner map
|
||||
auto nav_data = prn_it->second.find(tag.TOW - 30);
|
||||
if (nav_data != prn_it->second.end())
|
||||
{
|
||||
if (tag.ADKD == 0 || tag.ADKD == 12)
|
||||
{
|
||||
if (!nav_data->second.get_ephemeris_data().empty())
|
||||
{
|
||||
return nav_data->second.get_ephemeris_data();
|
||||
}
|
||||
}
|
||||
else if (tag.ADKD == 4)
|
||||
{
|
||||
if (!nav_data->second.get_utc_data().empty())
|
||||
{
|
||||
return nav_data->second.get_utc_data();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto rev_it = prn_it->second.rbegin(); rev_it != prn_it->second.rend(); ++rev_it) // NOLINT(modernize-loop-convert)
|
||||
{
|
||||
// note: starts with largest (i.e. newest) navigation dataset
|
||||
// Check if current key (TOW) fulfills condition
|
||||
if ((tag.TOW - 30 * tag.cop <= rev_it->first || tag.TOW - 30 * tag.cop <= rev_it->second.get_last_received_TOW()) && rev_it->first < tag.TOW)
|
||||
{
|
||||
if (tag.ADKD == 0 || tag.ADKD == 12)
|
||||
{
|
||||
if (!rev_it->second.get_ephemeris_data().empty())
|
||||
{
|
||||
return rev_it->second.get_ephemeris_data();
|
||||
}
|
||||
}
|
||||
else if (tag.ADKD == 4)
|
||||
{
|
||||
if (!rev_it->second.get_utc_data().empty())
|
||||
{
|
||||
return rev_it->second.get_utc_data();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Checks if the OSNMA_NavData bits are already present. In case affirmative, it updates the OSNMA_NavData 'last received' timestamp
|
||||
* @remarks e.g.: a SV may repeat the bits over several subframes. In that case, need to save them only once.
|
||||
* @param nav_bits
|
||||
* @param PRNd
|
||||
* @return
|
||||
*/
|
||||
bool OSNMA_NavDataManager::have_nav_data(const std::string& nav_bits, uint32_t PRNd, uint32_t TOW)
|
||||
{
|
||||
if (d_satellite_nav_data.find(PRNd) != d_satellite_nav_data.end())
|
||||
{
|
||||
for (auto& data_timestamp : d_satellite_nav_data[PRNd])
|
||||
{
|
||||
if (nav_bits.size() == EPH_SIZE)
|
||||
{
|
||||
if (data_timestamp.second.get_ephemeris_data() == nav_bits)
|
||||
{
|
||||
data_timestamp.second.set_last_received_TOW(TOW);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (nav_bits.size() == UTC_SIZE)
|
||||
{
|
||||
if (data_timestamp.second.get_utc_data() == nav_bits)
|
||||
{
|
||||
data_timestamp.second.set_last_received_TOW(TOW);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Checks if there is a OSNMA_NavData element within the COP time interval for a Tag t
|
||||
* @param t Tag object
|
||||
* @return True if the needed navigation data for the tag is available (oldest possible OSNMA_NavData available)
|
||||
*/
|
||||
bool OSNMA_NavDataManager::have_nav_data(const Tag& t) const
|
||||
{
|
||||
if (t.cop == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
auto prn_it = d_satellite_nav_data.find(t.PRN_d);
|
||||
if (prn_it == d_satellite_nav_data.end())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// satellite was found, check if TOW exists in inner map
|
||||
// try find target TOW directly first
|
||||
auto nav_data = prn_it->second.find(t.TOW - 30);
|
||||
if (nav_data != prn_it->second.end())
|
||||
{
|
||||
if (t.ADKD == 0 || t.ADKD == 12)
|
||||
{
|
||||
if (!nav_data->second.get_ephemeris_data().empty())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (t.ADKD == 4)
|
||||
{
|
||||
if (!nav_data->second.get_utc_data().empty())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// iterate in reverse order to find matching TOW with Tag's COP value
|
||||
std::map<uint32_t, OSNMA_NavData> tow_map = prn_it->second;
|
||||
for (auto rev_it = tow_map.rbegin(); rev_it != tow_map.rend(); ++rev_it) // NOLINT(modernize-loop-convert)
|
||||
{
|
||||
// note: starts with largest (i.e. newest) navigation dataset
|
||||
// Check if current key (TOW) fulfills cut-off point and is not received after the tag
|
||||
if ((t.TOW - 30 * t.cop <= rev_it->first || t.TOW - 30 * t.cop <= rev_it->second.get_last_received_TOW()) && rev_it->first < t.TOW)
|
||||
{
|
||||
if (t.ADKD == 0 || t.ADKD == 12)
|
||||
{
|
||||
if (!rev_it->second.get_ephemeris_data().empty())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (t.ADKD == 4)
|
||||
{
|
||||
if (!rev_it->second.get_utc_data().empty())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void OSNMA_NavDataManager::log_status() const
|
||||
{
|
||||
for (const auto& satellite : d_satellite_nav_data)
|
||||
{
|
||||
LOG(INFO) << "Galileo OSNMA: NavData status :: SVID=" << satellite.first;
|
||||
const auto& tow_data = satellite.second;
|
||||
for (const auto& nav_data : tow_data)
|
||||
{
|
||||
LOG(INFO) << "Galileo OSNMA: IOD_nav=0b" << std::uppercase
|
||||
<< std::bitset<10>(nav_data.second.get_IOD_nav())
|
||||
<< ", TOW_start="
|
||||
<< nav_data.second.get_tow_sf0()
|
||||
<< ", TOW_last="
|
||||
<< nav_data.second.get_last_received_TOW()
|
||||
<< ", l_t="
|
||||
<< nav_data.second.get_verified_bits()
|
||||
<< ", PRNd="
|
||||
<< nav_data.second.get_prn_d()
|
||||
<< ", verified="
|
||||
<< nav_data.second.get_verified_status();
|
||||
}
|
||||
}
|
||||
}
|
59
src/core/libs/osnma_nav_data_manager.h
Normal file
59
src/core/libs/osnma_nav_data_manager.h
Normal file
@ -0,0 +1,59 @@
|
||||
/*!
|
||||
* \file osnma_nav_data_manager.h
|
||||
* \brief Class for Galileo OSNMA navigation data management
|
||||
* \author Cesare Ghionoiu-Martinez, 2020-2023 cesare.martinez(at)proton.me
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
|
||||
* This file is part of GNSS-SDR.
|
||||
*
|
||||
* Copyright (C) 2010-2023 (see AUTHORS file for a list of contributors)
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef GNSS_SDR_OSNMA_NAV_DATA_MANAGER_H
|
||||
#define GNSS_SDR_OSNMA_NAV_DATA_MANAGER_H
|
||||
|
||||
#include "osnma_data.h" // for OSNMA_NavData, Tag
|
||||
#include <cstdint> // for uint32_t
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
/** \addtogroup Core
|
||||
* \{ */
|
||||
/** \addtogroup Core_Receiver_Library
|
||||
* \{ */
|
||||
|
||||
/**
|
||||
* @class OSNMA_NavDataManager
|
||||
* @brief Class for managing OSNMA navigation data
|
||||
*/
|
||||
class OSNMA_NavDataManager
|
||||
{
|
||||
public:
|
||||
OSNMA_NavDataManager() = default;
|
||||
|
||||
void log_status() const;
|
||||
bool have_nav_data(const Tag& t) const;
|
||||
bool have_nav_data(uint32_t PRNd, uint32_t TOW, uint8_t ADKD) const;
|
||||
std::string get_navigation_data(const Tag& t) const;
|
||||
|
||||
void add_navigation_data(const std::string& nav_bits, uint32_t PRNd, uint32_t TOW);
|
||||
void update_nav_data(const std::multimap<uint32_t, Tag>& tags_verified, uint8_t tag_size);
|
||||
bool have_nav_data(const std::string& nav_bits, uint32_t PRNd, uint32_t TOW);
|
||||
std::vector<OSNMA_NavData> get_verified_data();
|
||||
|
||||
private:
|
||||
std::map<uint32_t, std::map<uint32_t, OSNMA_NavData>> d_satellite_nav_data{}; // NavData sorted by [PRNd][TOW_start]
|
||||
const uint32_t L_t_min{40};
|
||||
const uint16_t EPH_SIZE{549};
|
||||
const uint16_t UTC_SIZE{141};
|
||||
};
|
||||
|
||||
/** \} */
|
||||
/** \} */
|
||||
#endif // GNSS_SDR_OSNMA_NAV_DATA_MANAGER_H
|
@ -46,15 +46,9 @@ if(CMAKE_C_COMPILER_ID MATCHES "Clang|GNU" AND (CMAKE_VERSION VERSION_GREATER "3
|
||||
target_compile_options(core_libs_supl PUBLIC $<$<COMPILE_LANGUAGE:C>:${MY_C_FLAGS}>)
|
||||
endif()
|
||||
|
||||
if(OPENSSL_FOUND)
|
||||
target_compile_definitions(core_libs_supl PUBLIC -DUSE_OPENSSL_FALLBACK=1)
|
||||
endif()
|
||||
|
||||
target_link_libraries(core_libs_supl
|
||||
PUBLIC
|
||||
${GNUTLS_LIBRARIES}
|
||||
${GNUTLS_OPENSSL_LIBRARY}
|
||||
)
|
||||
# links to the appropriate library and defines
|
||||
# USE_GNUTLS_FALLBACK, USE_OPENSSL_3, or USE_OPENSSL_111 accordingly.
|
||||
link_to_crypto_dependencies(core_libs_supl)
|
||||
|
||||
target_include_directories(core_libs_supl
|
||||
PUBLIC
|
||||
|
@ -24,18 +24,18 @@
|
||||
#define EXPORT
|
||||
#endif
|
||||
// clang-format off
|
||||
#if USE_OPENSSL_FALLBACK
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
#else
|
||||
#if USE_GNUTLS_FALLBACK
|
||||
#include <gnutls/gnutls.h>
|
||||
#include <gnutls/compat.h>
|
||||
#include <gnutls/crypto.h>
|
||||
#include <gnutls/openssl.h>
|
||||
#include <gnutls/x509.h>
|
||||
#else
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
#endif
|
||||
// clang-format on
|
||||
#include <PDU.h>
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "Galileo_E5a.h"
|
||||
#include "Galileo_E5b.h"
|
||||
#include "Galileo_E6.h"
|
||||
#include "Galileo_OSNMA.h"
|
||||
#include "channel.h"
|
||||
#include "channel_fsm.h"
|
||||
#include "channel_interface.h"
|
||||
@ -82,6 +83,7 @@ GNSSFlowgraph::GNSSFlowgraph(std::shared_ptr<ConfigurationInterface> configurati
|
||||
connected_(false),
|
||||
running_(false),
|
||||
multiband_(GNSSFlowgraph::is_multiband()),
|
||||
enable_osnma_rx_(false),
|
||||
enable_e6_has_rx_(false)
|
||||
{
|
||||
enable_fpga_offloading_ = configuration_->property("GNSS-SDR.enable_FPGA", false);
|
||||
@ -120,6 +122,24 @@ void GNSSFlowgraph::init()
|
||||
galileo_tow_map_ = nullptr;
|
||||
}
|
||||
|
||||
if (configuration_->property("Channels_1B.count", 0) > 0 && configuration_->property("GNSS-SDR.osnma_enable", true))
|
||||
{
|
||||
enable_osnma_rx_ = true;
|
||||
const auto certFilePath = configuration_->property("GNSS-SDR.osnma_public_key", CRTFILE_DEFAULT);
|
||||
const auto merKleTreePath = configuration_->property("GNSS-SDR.osnma_merkletree", MERKLEFILE_DEFAULT);
|
||||
std::string osnma_mode = configuration_->property("GNSS-SDR.osnma_mode", std::string(""));
|
||||
bool strict_mode = false;
|
||||
if (osnma_mode == "strict")
|
||||
{
|
||||
strict_mode = true;
|
||||
}
|
||||
osnma_rx_ = osnma_msg_receiver_make(certFilePath, merKleTreePath, strict_mode);
|
||||
}
|
||||
else
|
||||
{
|
||||
osnma_rx_ = nullptr;
|
||||
}
|
||||
|
||||
// 1. read the number of RF front-ends available (one file_source per RF front-end)
|
||||
int sources_count_deprecated = configuration_->property("Receiver.sources_count", 1);
|
||||
sources_count_ = configuration_->property("GNSS-SDR.num_sources", sources_count_deprecated);
|
||||
@ -520,6 +540,14 @@ int GNSSFlowgraph::connect_desktop_flowgraph()
|
||||
}
|
||||
}
|
||||
|
||||
if (enable_osnma_rx_)
|
||||
{
|
||||
if (connect_osnma() != 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Activate acquisition in enabled channels
|
||||
std::lock_guard<std::mutex> lock(signal_list_mutex_);
|
||||
for (int i = 0; i < channels_count_; i++)
|
||||
@ -640,6 +668,14 @@ int GNSSFlowgraph::connect_fpga_flowgraph()
|
||||
}
|
||||
}
|
||||
|
||||
if (enable_osnma_rx_)
|
||||
{
|
||||
if (connect_osnma() != 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
check_desktop_conf_in_fpga_env();
|
||||
|
||||
LOG(INFO) << "The GNU Radio flowgraph for the current GNSS-SDR configuration with FPGA off-loading has been successfully connected";
|
||||
@ -1365,6 +1401,42 @@ int GNSSFlowgraph::connect_monitors()
|
||||
}
|
||||
|
||||
|
||||
int GNSSFlowgraph::connect_osnma()
|
||||
{
|
||||
try
|
||||
{
|
||||
bool gal_e1_channels = false;
|
||||
for (int i = 0; i < channels_count_; i++)
|
||||
{
|
||||
const std::string gnss_signal = channels_.at(i)->get_signal().get_signal_str();
|
||||
switch (mapStringValues_[gnss_signal])
|
||||
{
|
||||
case evGAL_1B:
|
||||
top_block_->msg_connect(channels_.at(i)->get_right_block(), pmt::mp("OSNMA_from_TLM"), osnma_rx_, pmt::mp("OSNMA_from_TLM"));
|
||||
gal_e1_channels = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (gal_e1_channels == true)
|
||||
{
|
||||
top_block_->msg_connect(osnma_rx_, pmt::mp("OSNMA_to_PVT"), pvt_->get_left_block(), pmt::mp("OSNMA_to_PVT"));
|
||||
}
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
LOG(ERROR) << "Can't connect Galileo OSNMA msg ports: " << e.what();
|
||||
top_block_->disconnect_all();
|
||||
return 1;
|
||||
}
|
||||
DLOG(INFO) << "Galileo OSNMA message ports connected";
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int GNSSFlowgraph::connect_gal_e6_has()
|
||||
{
|
||||
try
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "galileo_tow_map.h"
|
||||
#include "gnss_sdr_sample_counter.h"
|
||||
#include "gnss_signal.h"
|
||||
#include "osnma_msg_receiver.h"
|
||||
#include "pvt_interface.h"
|
||||
#include <gnuradio/blocks/null_sink.h> // for null_sink
|
||||
#include <gnuradio/runtime_types.h> // for basic_block_sptr, top_block_sptr
|
||||
@ -179,6 +180,7 @@ private:
|
||||
int connect_channels_to_observables();
|
||||
int connect_observables_to_pvt();
|
||||
int connect_monitors();
|
||||
int connect_osnma();
|
||||
int connect_gal_e6_has();
|
||||
int connect_gnss_synchro_monitor();
|
||||
int connect_acquisition_monitor();
|
||||
@ -234,6 +236,7 @@ private:
|
||||
channel_status_msg_receiver_sptr channels_status_; // class that receives and stores the current status of the receiver channels
|
||||
galileo_e6_has_msg_receiver_sptr gal_e6_has_rx_;
|
||||
galileo_tow_map_sptr galileo_tow_map_;
|
||||
osnma_msg_receiver_sptr osnma_rx_;
|
||||
|
||||
gnss_sdr_sample_counter_sptr ch_out_sample_counter_;
|
||||
#if ENABLE_FPGA
|
||||
@ -290,6 +293,7 @@ private:
|
||||
bool enable_tracking_monitor_;
|
||||
bool enable_navdata_monitor_;
|
||||
bool enable_fpga_offloading_;
|
||||
bool enable_osnma_rx_;
|
||||
bool enable_e6_has_rx_;
|
||||
};
|
||||
|
||||
|
@ -29,6 +29,8 @@ set(SYSTEM_PARAMETERS_SOURCES
|
||||
glonass_gnav_utc_model.cc
|
||||
glonass_gnav_navigation_message.cc
|
||||
reed_solomon.cc
|
||||
osnma_data.cc
|
||||
osnma_dsm_reader.cc
|
||||
)
|
||||
|
||||
set(SYSTEM_PARAMETERS_HEADERS
|
||||
@ -91,6 +93,9 @@ set(SYSTEM_PARAMETERS_HEADERS
|
||||
MATH_CONSTANTS.h
|
||||
reed_solomon.h
|
||||
galileo_has_page.h
|
||||
Galileo_OSNMA.h
|
||||
osnma_data.h
|
||||
osnma_dsm_reader.h
|
||||
)
|
||||
|
||||
list(SORT SYSTEM_PARAMETERS_HEADERS)
|
||||
@ -117,6 +122,8 @@ target_link_libraries(core_system_parameters
|
||||
Boost::date_time
|
||||
Boost::serialization
|
||||
Boost::headers
|
||||
PRIVATE
|
||||
Pugixml::pugixml
|
||||
)
|
||||
|
||||
if(ENABLE_GLOG_AND_GFLAGS)
|
||||
|
199
src/core/system_parameters/Galileo_OSNMA.h
Normal file
199
src/core/system_parameters/Galileo_OSNMA.h
Normal file
@ -0,0 +1,199 @@
|
||||
/*!
|
||||
* \file Galileo_OSNMA.h
|
||||
* \brief Galileo OSNMA mesage constants
|
||||
* \author Carles Fernandez, 2023. cfernandez(at)cttc.es
|
||||
*
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
|
||||
* This file is part of GNSS-SDR.
|
||||
*
|
||||
* Copyright (C) 2010-2023 (see AUTHORS file for a list of contributors)
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef GNSS_SDR_GALILEO_OSNMA_H
|
||||
#define GNSS_SDR_GALILEO_OSNMA_H
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
/** \addtogroup Core
|
||||
* \{ */
|
||||
/** \addtogroup System_Parameters
|
||||
* \{ */
|
||||
|
||||
constexpr size_t SIZE_DSM_BLOCKS_BYTES = 13;
|
||||
|
||||
// OSNMA User ICD, Issue 1.1, Table 1
|
||||
const std::unordered_map<uint8_t, std::string> OSNMA_TABLE_1 = {
|
||||
{0, std::string("Reserved")},
|
||||
{1, std::string("Test")},
|
||||
{2, std::string("Operational")},
|
||||
{3, std::string("Don't use")}}; // key: nmas, value: nmas status
|
||||
|
||||
|
||||
// OSNMA User ICD, Issue 1.1, Table 2
|
||||
const std::unordered_map<uint8_t, std::string> OSNMA_TABLE_2 = {
|
||||
{0, std::string("Reserved")},
|
||||
{1, std::string("Nominal")},
|
||||
{2, std::string("End of Chain (EOC)")},
|
||||
{3, std::string("Chain Revoked (CREV)")},
|
||||
{4, std::string("New Publick Key (NPK)")},
|
||||
{5, std::string("Public Key Revoked (PKREV)")},
|
||||
{6, std::string("New Merkle Tree (NMT)")},
|
||||
{7, std::string("Alert Message (AM)")}}; // key: cpks, value: cpks status
|
||||
|
||||
// OSNMA User ICD for the Test Phase, Issue 1.0, Table 3
|
||||
const std::unordered_map<uint8_t, std::pair<uint16_t, uint16_t>> OSNMA_TABLE_3 = {
|
||||
{0, {0, 0}},
|
||||
{1, {0, 0}},
|
||||
{2, {0, 0}},
|
||||
{3, {0, 0}},
|
||||
{4, {0, 0}},
|
||||
{5, {0, 0}},
|
||||
{6, {0, 0}},
|
||||
{7, {13, 1352}},
|
||||
{8, {14, 1456}},
|
||||
{9, {15, 1560}},
|
||||
{10, {16, 1664}},
|
||||
{11, {0, 0}},
|
||||
{12, {0, 0}},
|
||||
{13, {0, 0}},
|
||||
{14, {0, 0}},
|
||||
{15, {0, 0}}}; // key: nb_dp, value: {num_blocks, l_dp_bits}
|
||||
|
||||
const std::unordered_map<uint8_t, std::string> OSNMA_TABLE_5 = {
|
||||
{0, std::string("Reserved")},
|
||||
{1, std::string("ECDSA P-256")},
|
||||
{2, std::string("Reserved")},
|
||||
{3, std::string("ECDSA P-521")},
|
||||
{4, std::string("OAM")},
|
||||
{5, std::string("Reserved")},
|
||||
{6, std::string("Reserved")},
|
||||
{7, std::string("Reserved")},
|
||||
{8, std::string("Reserved")},
|
||||
{9, std::string("Reserved")},
|
||||
{10, std::string("Reserved")},
|
||||
{11, std::string("Reserved")},
|
||||
{12, std::string("Reserved")},
|
||||
{13, std::string("Reserved")},
|
||||
{14, std::string("Reserved")},
|
||||
{15, std::string("Reserved")}}; // key: nptk, value: message
|
||||
|
||||
const std::unordered_map<std::string, uint16_t> OSNMA_TABLE_6 = {
|
||||
{std::string("ECDSA P-256"), 264},
|
||||
{std::string("ECDSA P-521"), 536}};
|
||||
|
||||
// OSNMA User ICD, Issue 1.1, Table 7
|
||||
const std::unordered_map<uint8_t, std::pair<uint16_t, uint16_t>> OSNMA_TABLE_7 = {
|
||||
{0, {0, 0}},
|
||||
{1, {7, 728}},
|
||||
{2, {8, 832}},
|
||||
{3, {9, 936}},
|
||||
{4, {10, 1040}},
|
||||
{5, {11, 1144}},
|
||||
{6, {12, 1248}},
|
||||
{7, {13, 1352}},
|
||||
{8, {14, 1456}},
|
||||
{9, {0, 0}},
|
||||
{10, {0, 0}},
|
||||
{11, {0, 0}},
|
||||
{12, {0, 0}},
|
||||
{13, {0, 0}},
|
||||
{14, {0, 0}},
|
||||
{15, {0, 0}}}; // key: nb_dk, value: {num_blocks, l_dk_bits}
|
||||
|
||||
const std::unordered_map<uint8_t, std::string> OSNMA_TABLE_8 = {
|
||||
{0, std::string("SHA-256")},
|
||||
{1, std::string("Reserved")},
|
||||
{2, std::string("SHA3-256")},
|
||||
{3, std::string("Reserved")}}; // key: hs, value: hash_function
|
||||
|
||||
const std::unordered_map<uint8_t, uint16_t> OSNMA_TABLE_10 = {
|
||||
{0, 96},
|
||||
{1, 104},
|
||||
{2, 112},
|
||||
{3, 120},
|
||||
{4, 128},
|
||||
{5, 160},
|
||||
{6, 192},
|
||||
{7, 224},
|
||||
{8, 256},
|
||||
{9, 0},
|
||||
{10, 0},
|
||||
{11, 0},
|
||||
{12, 0},
|
||||
{13, 0},
|
||||
{15, 0},
|
||||
{15, 0}}; // key: ks, value: lk_bits
|
||||
|
||||
const std::unordered_map<uint8_t, uint8_t> OSNMA_TABLE_11 = {
|
||||
{0, 0},
|
||||
{1, 0},
|
||||
{2, 0},
|
||||
{3, 0},
|
||||
{4, 0},
|
||||
{5, 20},
|
||||
{6, 24},
|
||||
{7, 28},
|
||||
{8, 32},
|
||||
{9, 40},
|
||||
{10, 0},
|
||||
{11, 0},
|
||||
{12, 0},
|
||||
{13, 0},
|
||||
{14, 0},
|
||||
{15, 0},
|
||||
};
|
||||
|
||||
const std::unordered_map<std::string, uint16_t> OSNMA_TABLE_15 = {
|
||||
{std::string("ECDSA P-256"), 512},
|
||||
{std::string("ECDSA P-521"), 1056}}; // key: ECDSA Curve and hash function, value: {l_ds_bits}
|
||||
|
||||
const std::string PEMFILE_DEFAULT("./OSNMA_PublicKey.pem");
|
||||
const std::string CRTFILE_DEFAULT("./OSNMA_PublicKey_20240115100000_newPKID_1.crt");
|
||||
const std::string MERKLEFILE_DEFAULT("./OSNMA_MerkleTree_20240115100000_newPKID_1.xml");
|
||||
const std::string KROOTFILE_DEFAULT("./OSNMA_DSM_KROOT_NMAHeader.bin");
|
||||
|
||||
class Mack_lookup
|
||||
{
|
||||
public:
|
||||
Mack_lookup() = default;
|
||||
Mack_lookup(uint8_t msg_,
|
||||
uint8_t nt_,
|
||||
const std::vector<std::string>& s1_,
|
||||
const std::vector<std::string>& s2_) : msg(msg_),
|
||||
nt(nt_),
|
||||
sequence1(s1_),
|
||||
sequence2(s2_){};
|
||||
uint8_t msg{};
|
||||
uint8_t nt{};
|
||||
std::vector<std::string> sequence1;
|
||||
std::vector<std::string> sequence2;
|
||||
};
|
||||
|
||||
const std::unordered_map<uint8_t, Mack_lookup> OSNMA_TABLE_16 = {
|
||||
{27, {2, 6, {"00S", "00E", "00E", "00E", "12S", "00E"}, {"00S ", "00E", "00E", "04S", "12S", "00E"}}},
|
||||
{28, {2, 10, {"00S", "00E", "00E", "00E", "00S", "00E", "00E", "12S", "00E", "00E"}, {"00S", "00E", "00E", "00S", "00E", "00E", "04S", "12S", "00E", "00E"}}},
|
||||
{31, {2, 5, {"00S", "00E", "00E", "12S", "00E"}, {"00S", "00E", "00E", "12S", "04S"}}},
|
||||
{33, {2, 6, {"00S", "00E", "04S", "00E", "12S", "00E"}, {"00S", "00E", "00E", "12S", "00E", "12E"}}},
|
||||
{34, {2, 6, {"00S", "FLX", "04S", "FLX", "12S", "00E"}, {"00S", "FLX", "00E", "12S", "00E", "12E"}}},
|
||||
{35, {2, 6, {"00S", "FLX", "04S", "FLX", "12S", "FLX"}, {"00S", "FLX", "FLX", "12S", "FLX", "FLX"}}},
|
||||
{36, {2, 5, {"00S", "FLX", "04S", "FLX", "12S"}, {"00S", "FLX", "00E", "12S", "12E"}}},
|
||||
{37, {2, 5, {"00S", "00E", "04S", "00E", "12S"}, {"00S", "00E", "00E", "12S", "12E"}}},
|
||||
{38, {2, 5, {"00S", "FLX", "04S", "FLX", "12S"}, {"00S", "FLX", "FLX", "12S", "FLX"}}},
|
||||
{39, {2, 4, {"00S", "FLX", "04S", "FLX"}, {"00S", "FLX", "00E", "12S"}}},
|
||||
{40, {2, 4, {"00S", "00E", "04S", "12S"}, {"00S", "00E", "00E", "12E"}}},
|
||||
{41, {2, 4, {"00S", "FLX", "04S", "FLX"}, {"00S", "FLX", "FLX", "12S"}}}};
|
||||
|
||||
/** \} */
|
||||
/** \} */
|
||||
#endif // GNSS_SDR_GALILEO_OSNMA_H
|
@ -392,7 +392,7 @@ std::vector<float> Galileo_HAS_data::get_delta_clock_subset_correction_m(uint8_t
|
||||
}
|
||||
|
||||
auto subset_corr_matrix = this->get_delta_clock_subset_correction_m();
|
||||
std::vector<float> delta_clock_subset_correction_m_v = subset_corr_matrix[nsys_sub_index];
|
||||
const std::vector<float> delta_clock_subset_correction_m_v = subset_corr_matrix[nsys_sub_index];
|
||||
std::vector<float> delta_clock_subset_correction_m_aux;
|
||||
std::vector<uint8_t> num_satellites_subset = this->get_num_subset_satellites();
|
||||
uint8_t num_sats_in_this_system_subset = num_satellites_subset[nsys_sub_index];
|
||||
|
@ -143,8 +143,6 @@ bool Galileo_Inav_Message::read_navigation_bool(const std::bitset<GALILEO_DATA_J
|
||||
|
||||
void Galileo_Inav_Message::split_page(std::string page_string, int32_t flag_even_word)
|
||||
{
|
||||
int32_t Page_type = 0;
|
||||
|
||||
if (page_string.at(0) == '1') // if page is odd
|
||||
{
|
||||
const std::string& page_Odd = page_string;
|
||||
@ -153,21 +151,21 @@ void Galileo_Inav_Message::split_page(std::string page_string, int32_t flag_even
|
||||
{
|
||||
const std::string page_INAV_even = page_Even;
|
||||
const std::string page_INAV = page_INAV_even + page_Odd; // Join pages: Even + Odd = INAV page
|
||||
const std::string Even_bit = page_INAV.substr(0, 1);
|
||||
const std::string Page_type_even = page_INAV.substr(1, 1);
|
||||
const std::string nominal = "0";
|
||||
|
||||
const std::string Data_k = page_INAV.substr(2, 112);
|
||||
const std::string Odd_bit = page_INAV.substr(114, 1);
|
||||
const std::string Page_type_Odd = page_INAV.substr(115, 1);
|
||||
const std::string Data_j = page_INAV.substr(116, 16);
|
||||
|
||||
const std::string Reserved_1 = page_INAV.substr(132, 40);
|
||||
const std::string SAR = page_INAV.substr(172, 22);
|
||||
const std::string Spare = page_INAV.substr(194, 2);
|
||||
const std::string osnma_sis = page_INAV.substr(132, 40);
|
||||
// const std::string SAR = page_INAV.substr(172, 22);
|
||||
// const std::string Spare = page_INAV.substr(194, 2);
|
||||
const std::string CRC_data = page_INAV.substr(196, 24);
|
||||
const std::string Reserved_2 = page_INAV.substr(220, 8);
|
||||
const std::string Tail_odd = page_INAV.substr(228, 6);
|
||||
// const std::string Reserved_2 = page_INAV.substr(220, 8);
|
||||
// const std::string Tail_odd = page_INAV.substr(228, 6);
|
||||
|
||||
if (page_position_in_inav_subframe != 255)
|
||||
{
|
||||
page_position_in_inav_subframe++;
|
||||
}
|
||||
|
||||
// ************ CRC checksum control *******/
|
||||
std::stringstream TLM_word_for_CRC_stream;
|
||||
@ -180,12 +178,29 @@ void Galileo_Inav_Message::split_page(std::string page_string, int32_t flag_even
|
||||
{
|
||||
flag_CRC_test = true;
|
||||
// CRC correct: Decode word
|
||||
const std::string page_number_bits = Data_k.substr(0, 6);
|
||||
const std::bitset<GALILEO_PAGE_TYPE_BITS> page_type_bits(page_number_bits); // from string to bitset
|
||||
Page_type = static_cast<int32_t>(read_page_type_unsigned(page_type_bits, TYPE));
|
||||
Page_type_time_stamp = Page_type;
|
||||
const std::string Data_jk_ephemeris = Data_k + Data_j;
|
||||
page_jk_decoder(Data_jk_ephemeris.c_str());
|
||||
|
||||
// Fill OSNMA data
|
||||
if (page_position_in_inav_subframe != 255)
|
||||
{
|
||||
if (page_position_in_inav_subframe == 0)
|
||||
{ // TODO - is it redundant? receiving Word 2 already resets this
|
||||
nma_position_filled = std::array<int8_t, 15>{};
|
||||
nma_msg.mack = std::array<uint32_t, 15>{};
|
||||
nma_msg.hkroot = std::array<uint8_t, 15>{};
|
||||
}
|
||||
std::bitset<8> hkroot_bs(osnma_sis.substr(0, 8));
|
||||
std::bitset<32> mack_bs(osnma_sis.substr(8, 32));
|
||||
if (hkroot_bs.count() != 0 && mack_bs.count() != 0)
|
||||
{
|
||||
hkroot_sis = static_cast<uint8_t>(hkroot_bs.to_ulong());
|
||||
mack_sis = static_cast<uint32_t>(mack_bs.to_ulong());
|
||||
nma_msg.mack[page_position_in_inav_subframe] = mack_sis;
|
||||
nma_msg.hkroot[page_position_in_inav_subframe] = hkroot_sis;
|
||||
nma_position_filled[page_position_in_inav_subframe] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -201,6 +216,7 @@ void Galileo_Inav_Message::split_page(std::string page_string, int32_t flag_even
|
||||
}
|
||||
|
||||
|
||||
// C: tells if W1-->W4 available from same blcok
|
||||
bool Galileo_Inav_Message::have_new_ephemeris() // Check if we have a new ephemeris stored in the galileo navigation class
|
||||
{
|
||||
if ((flag_ephemeris_1 == true) and (flag_ephemeris_2 == true) and (flag_ephemeris_3 == true) and (flag_ephemeris_4 == true) and (flag_iono_and_GST == true))
|
||||
@ -335,6 +351,7 @@ bool Galileo_Inav_Message::have_new_ephemeris() // Check if we have a new ephem
|
||||
}
|
||||
|
||||
|
||||
// C: tells if W5 is available
|
||||
bool Galileo_Inav_Message::have_new_iono_and_GST() // Check if we have a new iono data set stored in the galileo navigation class
|
||||
{
|
||||
if ((flag_iono_and_GST == true) and (flag_utc_model == true)) // the condition on flag_utc_model is added to have a time stamp for iono
|
||||
@ -347,6 +364,7 @@ bool Galileo_Inav_Message::have_new_iono_and_GST() // Check if we have a new io
|
||||
}
|
||||
|
||||
|
||||
// C: tells if W6 is available
|
||||
bool Galileo_Inav_Message::have_new_utc_model() // Check if we have a new utc data set stored in the galileo navigation class
|
||||
{
|
||||
if (flag_utc_model == true)
|
||||
@ -359,6 +377,7 @@ bool Galileo_Inav_Message::have_new_utc_model() // Check if we have a new utc d
|
||||
}
|
||||
|
||||
|
||||
// flag_almanac_4 tells if W10 available.
|
||||
bool Galileo_Inav_Message::have_new_almanac() // Check if we have a new almanac data set stored in the galileo navigation class
|
||||
{
|
||||
if ((flag_almanac_1 == true) and (flag_almanac_2 == true) and (flag_almanac_3 == true) and (flag_almanac_4 == true))
|
||||
@ -610,6 +629,7 @@ void Galileo_Inav_Message::read_page_1(const std::bitset<GALILEO_DATA_JK_BITS>&
|
||||
DLOG(INFO) << "A_1= " << A_1;
|
||||
flag_ephemeris_1 = true;
|
||||
DLOG(INFO) << "flag_tow_set" << flag_TOW_set;
|
||||
nav_bits_word_1 = data_bits.to_string().substr(6, 120);
|
||||
}
|
||||
|
||||
|
||||
@ -631,6 +651,7 @@ void Galileo_Inav_Message::read_page_2(const std::bitset<GALILEO_DATA_JK_BITS>&
|
||||
DLOG(INFO) << "iDot_2= " << iDot_2;
|
||||
flag_ephemeris_2 = true;
|
||||
DLOG(INFO) << "flag_tow_set" << flag_TOW_set;
|
||||
nav_bits_word_2 = data_bits.to_string().substr(6, 120);
|
||||
}
|
||||
|
||||
|
||||
@ -660,6 +681,7 @@ void Galileo_Inav_Message::read_page_3(const std::bitset<GALILEO_DATA_JK_BITS>&
|
||||
DLOG(INFO) << "SISA_3= " << SISA_3;
|
||||
flag_ephemeris_3 = true;
|
||||
DLOG(INFO) << "flag_tow_set" << flag_TOW_set;
|
||||
nav_bits_word_3 = data_bits.to_string().substr(6, 122);
|
||||
}
|
||||
|
||||
|
||||
@ -668,6 +690,7 @@ void Galileo_Inav_Message::read_page_4(const std::bitset<GALILEO_DATA_JK_BITS>&
|
||||
IOD_nav_4 = static_cast<int32_t>(read_navigation_unsigned(data_bits, IOD_NAV_4_BIT));
|
||||
DLOG(INFO) << "IOD_nav_4= " << IOD_nav_4;
|
||||
SV_ID_PRN_4 = static_cast<int32_t>(read_navigation_unsigned(data_bits, SV_ID_PRN_4_BIT));
|
||||
nma_msg.PRN = static_cast<uint32_t>(SV_ID_PRN_4);
|
||||
DLOG(INFO) << "SV_ID_PRN_4= " << SV_ID_PRN_4;
|
||||
C_ic_4 = static_cast<double>(read_navigation_signed(data_bits, C_IC_4_BIT));
|
||||
C_ic_4 = C_ic_4 * C_IC_4_LSB;
|
||||
@ -692,6 +715,7 @@ void Galileo_Inav_Message::read_page_4(const std::bitset<GALILEO_DATA_JK_BITS>&
|
||||
DLOG(INFO) << "spare_4 = " << spare_4;
|
||||
flag_ephemeris_4 = true;
|
||||
DLOG(INFO) << "flag_tow_set" << flag_TOW_set;
|
||||
nav_bits_word_4 = data_bits.to_string().substr(6, 120);
|
||||
}
|
||||
|
||||
|
||||
@ -826,6 +850,7 @@ int32_t Galileo_Inav_Message::page_jk_decoder(const char* data_jk)
|
||||
{
|
||||
case 1: // Word type 1: Ephemeris (1/4)
|
||||
{
|
||||
page_position_in_inav_subframe = 10;
|
||||
read_page_1(data_jk_bits);
|
||||
if (enable_rs)
|
||||
{
|
||||
@ -862,6 +887,14 @@ int32_t Galileo_Inav_Message::page_jk_decoder(const char* data_jk)
|
||||
|
||||
case 2: // Word type 2: Ephemeris (2/4)
|
||||
{
|
||||
// start of subframe, reset osnma parameters TODO - refactor
|
||||
page_position_in_inav_subframe = 0;
|
||||
nma_msg.mack = std::array<uint32_t, 15>{};
|
||||
nma_msg.hkroot = std::array<uint8_t, 15>{};
|
||||
nma_position_filled = std::array<int8_t, 15>{};
|
||||
reset_osnma_nav_bits_adkd4();
|
||||
reset_osnma_nav_bits_adkd0_12();
|
||||
|
||||
read_page_2(data_jk_bits);
|
||||
if (enable_rs)
|
||||
{
|
||||
@ -893,6 +926,7 @@ int32_t Galileo_Inav_Message::page_jk_decoder(const char* data_jk)
|
||||
}
|
||||
case 3: // Word type 3: Ephemeris (3/4) and SISA
|
||||
{
|
||||
page_position_in_inav_subframe = 11;
|
||||
read_page_3(data_jk_bits);
|
||||
if (enable_rs)
|
||||
{
|
||||
@ -925,6 +959,7 @@ int32_t Galileo_Inav_Message::page_jk_decoder(const char* data_jk)
|
||||
|
||||
case 4: // Word type 4: Ephemeris (4/4) and Clock correction parameters
|
||||
{
|
||||
page_position_in_inav_subframe = 1;
|
||||
read_page_4(data_jk_bits);
|
||||
if (enable_rs)
|
||||
{
|
||||
@ -956,6 +991,7 @@ int32_t Galileo_Inav_Message::page_jk_decoder(const char* data_jk)
|
||||
}
|
||||
|
||||
case 5: // Word type 5: Ionospheric correction, BGD, signal health and data validity status and GST
|
||||
page_position_in_inav_subframe = 12;
|
||||
// Ionospheric correction
|
||||
ai0_5 = static_cast<double>(read_navigation_unsigned(data_jk_bits, AI0_5_BIT));
|
||||
ai0_5 = ai0_5 * AI0_5_LSB;
|
||||
@ -1003,9 +1039,11 @@ int32_t Galileo_Inav_Message::page_jk_decoder(const char* data_jk)
|
||||
flag_iono_and_GST = true; // set to false externally
|
||||
flag_TOW_set = true; // set to false externally
|
||||
DLOG(INFO) << "flag_tow_set" << flag_TOW_set;
|
||||
nav_bits_word_5 = data_jk_bits.to_string().substr(6, 67);
|
||||
break;
|
||||
|
||||
case 6: // Word type 6: GST-UTC conversion parameters
|
||||
page_position_in_inav_subframe = 2;
|
||||
A0_6 = static_cast<double>(read_navigation_signed(data_jk_bits, A0_6_BIT));
|
||||
A0_6 = A0_6 * A0_6_LSB;
|
||||
DLOG(INFO) << "A0_6= " << A0_6;
|
||||
@ -1031,9 +1069,11 @@ int32_t Galileo_Inav_Message::page_jk_decoder(const char* data_jk)
|
||||
flag_utc_model = true; // set to false externally
|
||||
flag_TOW_set = true; // set to false externally
|
||||
DLOG(INFO) << "flag_tow_set" << flag_TOW_set;
|
||||
nav_bits_word_6 = data_jk_bits.to_string().substr(6, 99);
|
||||
break;
|
||||
|
||||
case 7: // Word type 7: Almanac for SVID1 (1/2), almanac reference time and almanac reference week number
|
||||
page_position_in_inav_subframe = 3;
|
||||
IOD_a_7 = static_cast<int32_t>(read_navigation_unsigned(data_jk_bits, IOD_A_7_BIT));
|
||||
DLOG(INFO) << "IOD_a_7= " << IOD_a_7;
|
||||
WN_a_7 = static_cast<int32_t>(read_navigation_unsigned(data_jk_bits, WN_A_7_BIT));
|
||||
@ -1068,7 +1108,8 @@ int32_t Galileo_Inav_Message::page_jk_decoder(const char* data_jk)
|
||||
DLOG(INFO) << "flag_tow_set" << flag_TOW_set;
|
||||
break;
|
||||
|
||||
case 8: // Word type 8: Almanac for SVID1 (2/2) and SVID2 (1/2)*/
|
||||
case 8: // Word type 8: Almanac for SVID1 (2/2) and SVID2 (1/2)
|
||||
page_position_in_inav_subframe = 4;
|
||||
IOD_a_8 = static_cast<int32_t>(read_navigation_unsigned(data_jk_bits, IOD_A_8_BIT));
|
||||
DLOG(INFO) << "IOD_a_8= " << IOD_a_8;
|
||||
af0_8 = static_cast<double>(read_navigation_signed(data_jk_bits, AF0_8_BIT));
|
||||
@ -1106,6 +1147,7 @@ int32_t Galileo_Inav_Message::page_jk_decoder(const char* data_jk)
|
||||
break;
|
||||
|
||||
case 9: // Word type 9: Almanac for SVID2 (2/2) and SVID3 (1/2)
|
||||
page_position_in_inav_subframe = 3;
|
||||
IOD_a_9 = static_cast<int32_t>(read_navigation_unsigned(data_jk_bits, IOD_A_9_BIT));
|
||||
DLOG(INFO) << "IOD_a_9= " << IOD_a_9;
|
||||
WN_a_9 = static_cast<int32_t>(read_navigation_unsigned(data_jk_bits, WN_A_9_BIT));
|
||||
@ -1145,6 +1187,7 @@ int32_t Galileo_Inav_Message::page_jk_decoder(const char* data_jk)
|
||||
break;
|
||||
|
||||
case 10: // Word type 10: Almanac for SVID3 (2/2) and GST-GPS conversion parameters
|
||||
page_position_in_inav_subframe = 4;
|
||||
IOD_a_10 = static_cast<int32_t>(read_navigation_unsigned(data_jk_bits, IOD_A_10_BIT));
|
||||
DLOG(INFO) << "IOD_a_10= " << IOD_a_10;
|
||||
Omega0_10 = static_cast<double>(read_navigation_signed(data_jk_bits, OMEGA0_10_BIT));
|
||||
@ -1183,6 +1226,7 @@ int32_t Galileo_Inav_Message::page_jk_decoder(const char* data_jk)
|
||||
DLOG(INFO) << "WN_0G_10= " << WN_0G_10;
|
||||
flag_almanac_4 = true;
|
||||
DLOG(INFO) << "flag_tow_set" << flag_TOW_set;
|
||||
nav_bits_word_10 = data_jk_bits.to_string().substr(86, 42);
|
||||
break;
|
||||
|
||||
case 16: // Word type 16: Reduced Clock and Ephemeris Data (CED) parameters
|
||||
@ -1216,6 +1260,7 @@ int32_t Galileo_Inav_Message::page_jk_decoder(const char* data_jk)
|
||||
|
||||
case 17: // Word type 17: FEC2 Reed-Solomon for CED
|
||||
{
|
||||
page_position_in_inav_subframe = 5;
|
||||
if (enable_rs)
|
||||
{
|
||||
IODnav_LSB17 = read_octet_unsigned(data_jk_bits, RS_IODNAV_LSBS);
|
||||
@ -1245,6 +1290,7 @@ int32_t Galileo_Inav_Message::page_jk_decoder(const char* data_jk)
|
||||
|
||||
case 18: // Word type 18: FEC2 Reed-Solomon for CED
|
||||
{
|
||||
page_position_in_inav_subframe = 5;
|
||||
if (enable_rs)
|
||||
{
|
||||
IODnav_LSB18 = read_octet_unsigned(data_jk_bits, RS_IODNAV_LSBS);
|
||||
@ -1274,6 +1320,7 @@ int32_t Galileo_Inav_Message::page_jk_decoder(const char* data_jk)
|
||||
|
||||
case 19: // Word type 19: FEC2 Reed-Solomon for CED
|
||||
{
|
||||
page_position_in_inav_subframe = 6;
|
||||
if (enable_rs)
|
||||
{
|
||||
IODnav_LSB19 = read_octet_unsigned(data_jk_bits, RS_IODNAV_LSBS);
|
||||
@ -1303,6 +1350,7 @@ int32_t Galileo_Inav_Message::page_jk_decoder(const char* data_jk)
|
||||
|
||||
case 20: // Word type 20: FEC2 Reed-Solomon for CED
|
||||
{
|
||||
page_position_in_inav_subframe = 6;
|
||||
if (enable_rs)
|
||||
{
|
||||
IODnav_LSB20 = read_octet_unsigned(data_jk_bits, RS_IODNAV_LSBS);
|
||||
@ -1393,6 +1441,19 @@ int32_t Galileo_Inav_Message::page_jk_decoder(const char* data_jk)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (page_position_in_inav_subframe > 14 &&
|
||||
page_position_in_inav_subframe != 255)
|
||||
{
|
||||
// something weird happened, reset
|
||||
page_position_in_inav_subframe = 255;
|
||||
nma_position_filled = std::array<int8_t, 15>{};
|
||||
nma_msg.mack = std::array<uint32_t, 15>{};
|
||||
nma_msg.hkroot = std::array<uint8_t, 15>{};
|
||||
reset_osnma_nav_bits_adkd4();
|
||||
reset_osnma_nav_bits_adkd0_12();
|
||||
}
|
||||
|
||||
return page_number;
|
||||
}
|
||||
|
||||
@ -1401,3 +1462,70 @@ Galileo_ISM Galileo_Inav_Message::get_galileo_ism() const
|
||||
{
|
||||
return gal_ism;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get data relevant for Galileo OSNMA
|
||||
*
|
||||
* \details This function retrieves various parameters and data to compose the OSNMA_msg.
|
||||
* It fills the TOW and WN fields of the message and retrieves ephemeris, iono, and
|
||||
*
|
||||
* @return The OSNMA message
|
||||
*/
|
||||
OSNMA_msg Galileo_Inav_Message::get_osnma_msg()
|
||||
{
|
||||
nma_position_filled = std::array<int8_t, 15>{};
|
||||
// Fill TOW and WN
|
||||
nma_msg.WN_sf0 = WN_0;
|
||||
int32_t TOW_sf0 = TOW_5 - 25;
|
||||
if (TOW_sf0 < 0)
|
||||
{
|
||||
TOW_sf0 += 604800;
|
||||
}
|
||||
nma_msg.TOW_sf0 = static_cast<uint32_t>(TOW_sf0);
|
||||
return nma_msg;
|
||||
}
|
||||
|
||||
|
||||
bool Galileo_Inav_Message::have_new_nma()
|
||||
{
|
||||
if (std::all_of(nma_position_filled.begin(), nma_position_filled.end(), [](int8_t element) { return element == 1; }))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string Galileo_Inav_Message::get_osnma_adkd_4_nav_bits()
|
||||
{
|
||||
nav_bits_adkd_4 = nav_bits_word_6 + nav_bits_word_10;
|
||||
return nav_bits_adkd_4;
|
||||
}
|
||||
|
||||
|
||||
std::string Galileo_Inav_Message::get_osnma_adkd_0_12_nav_bits()
|
||||
{
|
||||
nav_bits_adkd_0_12 = nav_bits_word_1 + nav_bits_word_2 + nav_bits_word_3 + nav_bits_word_4 + nav_bits_word_5;
|
||||
return nav_bits_adkd_0_12;
|
||||
}
|
||||
|
||||
|
||||
void Galileo_Inav_Message::reset_osnma_nav_bits_adkd0_12()
|
||||
{
|
||||
nav_bits_word_1 = "";
|
||||
nav_bits_word_2 = "";
|
||||
nav_bits_word_3 = "";
|
||||
nav_bits_word_4 = "";
|
||||
nav_bits_word_5 = "";
|
||||
}
|
||||
|
||||
|
||||
void Galileo_Inav_Message::reset_osnma_nav_bits_adkd4()
|
||||
{
|
||||
nav_bits_word_6 = "";
|
||||
nav_bits_word_10 = "";
|
||||
}
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "galileo_ism.h"
|
||||
#include "galileo_utc_model.h"
|
||||
#include "gnss_sdr_make_unique.h" // for std::unique_ptr in C++11
|
||||
#include <array>
|
||||
#include <bitset>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
@ -39,7 +40,19 @@ class ReedSolomon; // Forward declaration of the ReedSolomon class
|
||||
* \{ */
|
||||
/** \addtogroup System_Parameters
|
||||
* \{ */
|
||||
|
||||
/*!
|
||||
* \brief This class fills the OSNMA_msg structure with the data received from the telemetry blocks.
|
||||
*/
|
||||
class OSNMA_msg
|
||||
{
|
||||
public:
|
||||
OSNMA_msg() = default;
|
||||
std::array<uint32_t, 15> mack{};
|
||||
std::array<uint8_t, 15> hkroot{};
|
||||
uint32_t PRN{}; // PRN_a authentication data PRN
|
||||
uint32_t WN_sf0{}; // Week number at the start of OSNMA subframe
|
||||
uint32_t TOW_sf0{}; // TOW at the start of OSNMA subframe
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief This class handles the Galileo I/NAV Data message, as described in the
|
||||
@ -58,13 +71,6 @@ public:
|
||||
*/
|
||||
void split_page(std::string page_string, int32_t flag_even_word);
|
||||
|
||||
/*
|
||||
* \brief Takes in input Data_jk (128 bit) and split it in ephemeris parameters according ICD 4.3.5
|
||||
*
|
||||
* Takes in input Data_jk (128 bit) and split it in ephemeris parameters according ICD 4.3.5
|
||||
*/
|
||||
int32_t page_jk_decoder(const char* data_jk);
|
||||
|
||||
/*
|
||||
* \brief Returns true if new Ephemeris has arrived. The flag is set to false when the function is executed
|
||||
*/
|
||||
@ -91,9 +97,15 @@ public:
|
||||
bool have_new_reduced_ced();
|
||||
|
||||
/*
|
||||
<<<<<<< HEAD
|
||||
* \brief Returns true if new ISM data have arrived. The flag is set to false when the function is executed
|
||||
*/
|
||||
bool have_new_ism();
|
||||
=======
|
||||
* \brief Returns true if new NMA data have arrived. The flag is set to false when the function is executed
|
||||
*/
|
||||
bool have_new_nma();
|
||||
>>>>>>> d0a6264754a2f7c98fa16bc44321e0b8c62d44db
|
||||
|
||||
/*
|
||||
* \brief Returns a Galileo_Ephemeris object filled with the latest navigation data received
|
||||
@ -121,9 +133,29 @@ public:
|
||||
Galileo_Ephemeris get_reduced_ced() const;
|
||||
|
||||
/*
|
||||
* \brief Returns a Galileo_ISM object filled with the latest ISM data received
|
||||
* \brief Returns an OSNMA_msg object filled with the latest NMA message received. Resets msg buffer.
|
||||
*/
|
||||
Galileo_ISM get_galileo_ism() const;
|
||||
OSNMA_msg get_osnma_msg();
|
||||
|
||||
/*
|
||||
* @brief Retrieves the OSNMA ADKD 4 NAV bits. Resets the string.
|
||||
*/
|
||||
std::string get_osnma_adkd_4_nav_bits();
|
||||
|
||||
/*
|
||||
* @brief Resets the OSNMA ADKD 4 NAV bits.
|
||||
*/
|
||||
void reset_osnma_nav_bits_adkd4();
|
||||
|
||||
/*
|
||||
* @brief Retrieves the OSNMA ADKD 0/12 NAV bits. Resets the string.
|
||||
*/
|
||||
std::string get_osnma_adkd_0_12_nav_bits();
|
||||
|
||||
/*
|
||||
* @brief Resets the OSNMA ADKD 0/12 NAV bits.
|
||||
*/
|
||||
void reset_osnma_nav_bits_adkd0_12();
|
||||
|
||||
inline bool get_flag_CRC_test() const
|
||||
{
|
||||
@ -221,6 +253,11 @@ public:
|
||||
inline void init_PRN(uint32_t prn)
|
||||
{
|
||||
SV_ID_PRN_4 = prn;
|
||||
nma_msg.PRN = prn;
|
||||
nma_msg.mack = std::array<uint32_t, 15>{};
|
||||
nma_msg.hkroot = std::array<uint8_t, 15>{};
|
||||
page_position_in_inav_subframe = 255;
|
||||
nma_position_filled = std::array<int8_t, 15>{};
|
||||
}
|
||||
|
||||
/*
|
||||
@ -254,7 +291,7 @@ private:
|
||||
std::unique_ptr<ReedSolomon> rs; // The Reed-Solomon decoder
|
||||
std::vector<int> inav_rs_pages; // Pages 1,2,3,4,17,18,19,20. Holds 1 if the page has arrived, 0 otherwise.
|
||||
|
||||
int32_t Page_type_time_stamp{};
|
||||
int32_t page_jk_decoder(const char* data_jk);
|
||||
int32_t IOD_ephemeris{};
|
||||
|
||||
// Word type 1: Ephemeris (1/4)
|
||||
@ -406,6 +443,22 @@ private:
|
||||
|
||||
int32_t current_IODnav{};
|
||||
|
||||
// OSNMA
|
||||
uint32_t mack_sis{};
|
||||
uint8_t hkroot_sis{};
|
||||
uint8_t page_position_in_inav_subframe{255};
|
||||
std::array<int8_t, 15> nma_position_filled{};
|
||||
OSNMA_msg nma_msg{};
|
||||
std::string nav_bits_adkd_4{};
|
||||
std::string nav_bits_word_6{};
|
||||
std::string nav_bits_word_10{};
|
||||
std::string nav_bits_adkd_0_12{};
|
||||
std::string nav_bits_word_1{};
|
||||
std::string nav_bits_word_2{};
|
||||
std::string nav_bits_word_3{};
|
||||
std::string nav_bits_word_4{};
|
||||
std::string nav_bits_word_5{};
|
||||
|
||||
uint8_t IODnav_LSB17{};
|
||||
uint8_t IODnav_LSB18{};
|
||||
uint8_t IODnav_LSB19{};
|
||||
|
45
src/core/system_parameters/osnma_data.cc
Normal file
45
src/core/system_parameters/osnma_data.cc
Normal file
@ -0,0 +1,45 @@
|
||||
/*!
|
||||
* \file osnma_data.cc
|
||||
* \brief Class for Galileo OSNMA data storage
|
||||
* \author Carles Fernandez-Prades, 2020-2023 cfernandez(at)cttc.es
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
|
||||
* This file is part of GNSS-SDR.
|
||||
*
|
||||
* Copyright (C) 2010-2023 (see AUTHORS file for a list of contributors)
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "osnma_data.h"
|
||||
|
||||
uint32_t Tag::id_counter = 0;
|
||||
uint32_t OSNMA_NavData::id_counter = 0;
|
||||
|
||||
bool OSNMA_NavData::add_nav_data(const std::string& nav_data)
|
||||
{
|
||||
if (nav_data.size() == 549)
|
||||
{
|
||||
d_ephemeris_iono = nav_data;
|
||||
std::bitset<10> bits(nav_data.substr(0, 10));
|
||||
IOD_nav = static_cast<uint8_t>(bits.to_ulong());
|
||||
return true;
|
||||
}
|
||||
else if (nav_data.size() == 141)
|
||||
{
|
||||
d_utc = nav_data;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
std::string OSNMA_NavData::get_utc_data() const
|
||||
{
|
||||
return d_utc;
|
||||
}
|
||||
std::string OSNMA_NavData::get_ephemeris_data() const
|
||||
{
|
||||
return d_ephemeris_iono;
|
||||
}
|
250
src/core/system_parameters/osnma_data.h
Normal file
250
src/core/system_parameters/osnma_data.h
Normal file
@ -0,0 +1,250 @@
|
||||
/*!
|
||||
* \file osnma_data.h
|
||||
* \brief Class for Galileo OSNMA data storage
|
||||
* \author Carles Fernandez-Prades, 2020-2023 cfernandez(at)cttc.es
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
|
||||
* This file is part of GNSS-SDR.
|
||||
*
|
||||
* Copyright (C) 2010-2023 (see AUTHORS file for a list of contributors)
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
#ifndef GNSS_SDR_OSNMA_DATA_H
|
||||
#define GNSS_SDR_OSNMA_DATA_H
|
||||
|
||||
#include "galileo_inav_message.h" // for OSNMA_msg
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
/** \addtogroup Core
|
||||
* \{ */
|
||||
/** \addtogroup System_Parameters
|
||||
* \{ */
|
||||
|
||||
class DSM_nma_header
|
||||
{
|
||||
public:
|
||||
DSM_nma_header() = default;
|
||||
uint8_t nmas{};
|
||||
uint8_t cid{};
|
||||
uint8_t cpks{};
|
||||
bool reserved{};
|
||||
};
|
||||
|
||||
|
||||
class DSM_dsm_header
|
||||
{
|
||||
public:
|
||||
DSM_dsm_header() = default;
|
||||
uint8_t dsm_id{};
|
||||
uint8_t dsm_block_id{};
|
||||
};
|
||||
|
||||
|
||||
class MACK_header
|
||||
{
|
||||
public:
|
||||
MACK_header() = default;
|
||||
uint64_t tag0{};
|
||||
uint16_t macseq{};
|
||||
uint8_t cop{};
|
||||
};
|
||||
|
||||
|
||||
class MACK_tag_info
|
||||
{
|
||||
public:
|
||||
MACK_tag_info() = default;
|
||||
uint8_t PRN_d{};
|
||||
uint8_t ADKD{};
|
||||
uint8_t cop{};
|
||||
};
|
||||
|
||||
|
||||
class MACK_tag_and_info
|
||||
{
|
||||
public:
|
||||
MACK_tag_and_info() = default;
|
||||
uint64_t tag; // C: 20-40 bits
|
||||
MACK_tag_info tag_info;
|
||||
uint32_t counter; // CTR
|
||||
};
|
||||
|
||||
|
||||
class DSM_PKR_message
|
||||
{
|
||||
public:
|
||||
DSM_PKR_message() = default;
|
||||
|
||||
std::array<uint8_t, 128> itn{}; // bitset<1024>
|
||||
std::vector<uint8_t> npk;
|
||||
std::vector<uint8_t> p_dp;
|
||||
uint8_t nb_dp{};
|
||||
uint8_t mid{};
|
||||
uint8_t npkt{};
|
||||
uint8_t npktid{};
|
||||
};
|
||||
|
||||
|
||||
class DSM_KROOT_message
|
||||
{
|
||||
public:
|
||||
DSM_KROOT_message() = default;
|
||||
|
||||
std::vector<uint8_t> kroot;
|
||||
std::vector<uint8_t> ds;
|
||||
std::vector<uint8_t> p_dk;
|
||||
uint64_t alpha{};
|
||||
uint16_t wn_k{};
|
||||
uint8_t nb_dk{};
|
||||
uint8_t pkid{};
|
||||
uint8_t cidkr{};
|
||||
uint8_t reserved1{};
|
||||
uint8_t hf{};
|
||||
uint8_t mf{};
|
||||
uint8_t ks{}; // key size, in bits
|
||||
uint8_t ts{};
|
||||
uint8_t maclt{};
|
||||
uint8_t reserved{};
|
||||
uint8_t towh_k{};
|
||||
bool verified{false};
|
||||
};
|
||||
|
||||
|
||||
class MACK_message
|
||||
{
|
||||
public:
|
||||
MACK_message() = default;
|
||||
MACK_header header;
|
||||
std::vector<MACK_tag_and_info> tag_and_info;
|
||||
std::vector<uint8_t> key;
|
||||
uint32_t TOW; // TODO duplicated variable, also in OSNMA_NavData
|
||||
uint32_t WN;
|
||||
uint32_t PRNa;
|
||||
};
|
||||
|
||||
|
||||
class OSNMA_NavData
|
||||
{
|
||||
public:
|
||||
OSNMA_NavData() : nav_data_id(id_counter++) {}
|
||||
const uint32_t nav_data_id;
|
||||
std::string get_utc_data() const;
|
||||
std::string get_ephemeris_data() const;
|
||||
uint32_t get_verified_bits() const { return verified_bits; }
|
||||
uint32_t get_prn_d() const { return PRNd; }
|
||||
uint32_t get_IOD_nav() const { return IOD_nav; }
|
||||
uint32_t get_last_received_TOW() const { return d_last_received_TOW; }
|
||||
uint32_t get_tow_sf0() const { return d_TOW_sf0; }
|
||||
bool have_this_bits(std::string nav_data);
|
||||
bool get_verified_status() const { return verified; }
|
||||
bool add_nav_data(const std::string& nav_data);
|
||||
void set_tow_sf0(int value) { d_TOW_sf0 = value; }
|
||||
void set_ephemeris_data(std::string value) { d_ephemeris_iono = value; }
|
||||
void set_utc_data(std::string value) { d_utc = value; }
|
||||
void update_last_received_timestamp(uint32_t TOW);
|
||||
void set_prn_d(uint32_t value) { PRNd = value; }
|
||||
void set_last_received_TOW(uint32_t TOW) { d_last_received_TOW = TOW; };
|
||||
void set_update_verified_bits(uint32_t morebits) { verified_bits += morebits; }
|
||||
void set_verified_status(bool value) { verified = value; }
|
||||
void set_IOD_nav(uint32_t value) { IOD_nav = value; }
|
||||
|
||||
private:
|
||||
static uint32_t id_counter;
|
||||
std::string d_ephemeris_iono{""};
|
||||
std::string d_utc{""};
|
||||
uint32_t d_TOW_sf0{0};
|
||||
uint32_t d_last_received_TOW{0};
|
||||
uint32_t PRNd{0};
|
||||
uint32_t verified_bits{0};
|
||||
uint32_t IOD_nav{0};
|
||||
bool verified{false};
|
||||
};
|
||||
|
||||
|
||||
/*!
|
||||
* \brief This class handles ONSMA data
|
||||
* See https://www.gsc-europa.eu/sites/default/files/sites/all/files/Galileo_OSNMA_User_ICD_for_Test_Phase_v1.0.pdf
|
||||
*/
|
||||
class OSNMA_data
|
||||
{
|
||||
public:
|
||||
OSNMA_data() = default;
|
||||
DSM_nma_header d_nma_header;
|
||||
DSM_dsm_header d_dsm_header;
|
||||
DSM_PKR_message d_dsm_pkr_message;
|
||||
DSM_KROOT_message d_dsm_kroot_message;
|
||||
DSM_KROOT_message d_dsm_kroot_new_message;
|
||||
MACK_message d_mack_message;
|
||||
OSNMA_NavData d_nav_data;
|
||||
};
|
||||
|
||||
|
||||
class Tag
|
||||
{
|
||||
public:
|
||||
enum e_verification_status
|
||||
{
|
||||
SUCCESS,
|
||||
FAIL,
|
||||
UNVERIFIED
|
||||
};
|
||||
Tag(const MACK_tag_and_info& MTI, uint32_t TOW, uint32_t WN, uint32_t PRNa, uint8_t CTR) // standard tag constructor, for tags within Tag&Info field
|
||||
: tag_id(id_counter++),
|
||||
TOW(TOW), // TODO missing for build_message WN for GST computation, CTR, NMAS, OSNMA_NavData missing
|
||||
WN(WN),
|
||||
PRNa(PRNa),
|
||||
CTR(CTR),
|
||||
status(UNVERIFIED),
|
||||
received_tag(MTI.tag),
|
||||
computed_tag(0),
|
||||
PRN_d(MTI.tag_info.PRN_d),
|
||||
ADKD(MTI.tag_info.ADKD),
|
||||
cop(MTI.tag_info.cop),
|
||||
skipped(0)
|
||||
{
|
||||
}
|
||||
explicit Tag(const MACK_message& mack) // constructor for Tag0
|
||||
: tag_id(id_counter++),
|
||||
TOW(mack.TOW), // TODO missing for build_message WN for GST computation, CTR, NMAS, OSNMA_NavData missing
|
||||
WN(mack.WN),
|
||||
PRNa(mack.PRNa),
|
||||
CTR(1),
|
||||
status(UNVERIFIED),
|
||||
received_tag(mack.header.tag0),
|
||||
computed_tag(0),
|
||||
PRN_d(mack.PRNa), // Tag0 are self-authenticating
|
||||
ADKD(0),
|
||||
cop(mack.header.cop),
|
||||
skipped(0)
|
||||
{
|
||||
}
|
||||
const uint32_t tag_id;
|
||||
uint32_t static id_counter;
|
||||
uint32_t TOW;
|
||||
uint32_t WN;
|
||||
uint32_t PRNa;
|
||||
uint8_t CTR;
|
||||
e_verification_status status;
|
||||
uint64_t received_tag;
|
||||
uint64_t computed_tag;
|
||||
uint8_t PRN_d;
|
||||
uint8_t ADKD;
|
||||
uint8_t cop;
|
||||
uint32_t skipped;
|
||||
std::string nav_data;
|
||||
};
|
||||
|
||||
/** \} */
|
||||
/** \} */
|
||||
|
||||
#endif // GNSS_SDR_OSNMA_DATA_H
|
228
src/core/system_parameters/osnma_dsm_reader.cc
Normal file
228
src/core/system_parameters/osnma_dsm_reader.cc
Normal file
@ -0,0 +1,228 @@
|
||||
/*!
|
||||
* \file osnma_dsm_reader.cc
|
||||
* \brief Class for reading OSNMA DSM messages
|
||||
* \author Carles Fernandez-Prades, 2023 cfernandez(at)cttc.es
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
|
||||
* This file is part of GNSS-SDR.
|
||||
*
|
||||
* Copyright (C) 2010-2023 (see AUTHORS file for a list of contributors)
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "osnma_dsm_reader.h"
|
||||
#include "Galileo_OSNMA.h"
|
||||
|
||||
|
||||
uint8_t OSNMA_DSM_Reader::get_nmas(uint8_t nma_header) const
|
||||
{
|
||||
return (nma_header & mask_nmas) >> 6;
|
||||
}
|
||||
|
||||
|
||||
uint8_t OSNMA_DSM_Reader::get_cid(uint8_t nma_header) const
|
||||
{
|
||||
return (nma_header & mask_cid) >> 4;
|
||||
}
|
||||
|
||||
|
||||
uint8_t OSNMA_DSM_Reader::get_cpks(uint8_t nma_header) const
|
||||
{
|
||||
return (nma_header & mask_cpks) >> 1;
|
||||
}
|
||||
|
||||
|
||||
bool OSNMA_DSM_Reader::get_nma_header_reserved(uint8_t nma_header) const
|
||||
{
|
||||
return (nma_header & mask_nma_header_reserved) != 0;
|
||||
}
|
||||
|
||||
|
||||
uint8_t OSNMA_DSM_Reader::get_dsm_id(uint8_t dsm_header) const
|
||||
{
|
||||
return (dsm_header & mask_dsm_id) >> 4;
|
||||
}
|
||||
|
||||
|
||||
uint8_t OSNMA_DSM_Reader::get_dsm_block_id(uint8_t dsm_header) const
|
||||
{
|
||||
return dsm_header & mask_dsm_block_id;
|
||||
}
|
||||
|
||||
|
||||
uint8_t OSNMA_DSM_Reader::get_number_blocks_index(uint8_t dsm_msg_0) const
|
||||
{
|
||||
return (dsm_msg_0 & mask_dsm_number_blocks) >> 4;
|
||||
}
|
||||
|
||||
|
||||
uint8_t OSNMA_DSM_Reader::get_pkid(const std::vector<uint8_t>& dsm_msg) const
|
||||
{
|
||||
return (dsm_msg[0] & mask_dsm_pkid);
|
||||
}
|
||||
|
||||
|
||||
uint8_t OSNMA_DSM_Reader::get_cidkr(const std::vector<uint8_t>& dsm_msg) const
|
||||
{
|
||||
return (dsm_msg[1] & mask_dsm_cidkr) >> 6;
|
||||
}
|
||||
|
||||
|
||||
uint8_t OSNMA_DSM_Reader::get_dsm_reserved1(const std::vector<uint8_t>& dsm_msg) const
|
||||
{
|
||||
return (dsm_msg[1] & mask_dsm_reserved1) >> 4;
|
||||
}
|
||||
|
||||
|
||||
uint8_t OSNMA_DSM_Reader::get_hf(const std::vector<uint8_t>& dsm_msg) const
|
||||
{
|
||||
return (dsm_msg[1] & mask_dsm_hf) >> 2;
|
||||
}
|
||||
|
||||
|
||||
uint8_t OSNMA_DSM_Reader::get_mf(const std::vector<uint8_t>& dsm_msg) const
|
||||
{
|
||||
return (dsm_msg[1] & mask_dsm_mf);
|
||||
}
|
||||
|
||||
|
||||
uint8_t OSNMA_DSM_Reader::get_ks(const std::vector<uint8_t>& dsm_msg) const
|
||||
{
|
||||
return (dsm_msg[2] & mask_dsm_ks) >> 4;
|
||||
}
|
||||
|
||||
|
||||
uint8_t OSNMA_DSM_Reader::get_ts(const std::vector<uint8_t>& dsm_msg) const
|
||||
{
|
||||
return (dsm_msg[2] & mask_dsm_ts);
|
||||
}
|
||||
|
||||
|
||||
uint8_t OSNMA_DSM_Reader::get_maclt(const std::vector<uint8_t>& dsm_msg) const
|
||||
{
|
||||
return dsm_msg[3];
|
||||
}
|
||||
|
||||
|
||||
uint8_t OSNMA_DSM_Reader::get_dsm_reserved(const std::vector<uint8_t>& dsm_msg) const
|
||||
{
|
||||
return (dsm_msg[4] & mask_dsm_reserved) >> 4;
|
||||
}
|
||||
|
||||
|
||||
uint16_t OSNMA_DSM_Reader::get_wn_k(const std::vector<uint8_t>& dsm_msg) const
|
||||
{
|
||||
return (static_cast<uint16_t>((dsm_msg[4] & mask_dsm_wk_k_msbyte) << 8) + static_cast<uint16_t>(dsm_msg[5]));
|
||||
}
|
||||
|
||||
|
||||
uint8_t OSNMA_DSM_Reader::get_towh_k(const std::vector<uint8_t>& dsm_msg) const
|
||||
{
|
||||
return dsm_msg[6];
|
||||
}
|
||||
|
||||
|
||||
uint64_t OSNMA_DSM_Reader::get_alpha(const std::vector<uint8_t>& dsm_msg) const
|
||||
{
|
||||
uint64_t alpha = (static_cast<uint64_t>(dsm_msg[7]) << 40) +
|
||||
(static_cast<uint64_t>(dsm_msg[8]) << 32) +
|
||||
(static_cast<uint64_t>(dsm_msg[9]) << 24) +
|
||||
(static_cast<uint64_t>(dsm_msg[10]) << 16) +
|
||||
(static_cast<uint64_t>(dsm_msg[11]) << 8) +
|
||||
(static_cast<uint64_t>(dsm_msg[12]));
|
||||
return alpha;
|
||||
}
|
||||
|
||||
|
||||
uint16_t OSNMA_DSM_Reader::get_l_dk_bits(uint8_t nb_dk) const
|
||||
{
|
||||
const auto it = OSNMA_TABLE_7.find(nb_dk);
|
||||
if (it != OSNMA_TABLE_7.cend())
|
||||
{
|
||||
return it->second.second;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
uint16_t OSNMA_DSM_Reader::get_lk_bits(uint8_t ks) const
|
||||
{
|
||||
const auto it = OSNMA_TABLE_10.find(ks);
|
||||
if (it != OSNMA_TABLE_10.cend())
|
||||
{
|
||||
return it->second;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
std::vector<uint8_t> OSNMA_DSM_Reader::get_kroot(const std::vector<uint8_t>& dsm_msg, uint16_t bytes_lk) const
|
||||
{
|
||||
std::vector<uint8_t> kroot = std::vector<uint8_t>(bytes_lk, 0);
|
||||
if (dsm_msg.size() > static_cast<uint64_t>(13 + bytes_lk))
|
||||
{
|
||||
for (uint16_t k = 0; k < bytes_lk; k++)
|
||||
{
|
||||
kroot[k] = dsm_msg[13 + k];
|
||||
}
|
||||
}
|
||||
return kroot;
|
||||
}
|
||||
|
||||
|
||||
std::string OSNMA_DSM_Reader::get_hash_function(uint8_t hf) const
|
||||
{
|
||||
std::string hash_;
|
||||
const auto it = OSNMA_TABLE_8.find(hf);
|
||||
if (it != OSNMA_TABLE_8.cend())
|
||||
{
|
||||
hash_ = it->second;
|
||||
}
|
||||
return hash_;
|
||||
}
|
||||
|
||||
|
||||
uint8_t OSNMA_DSM_Reader::get_mid(const std::vector<uint8_t>& dsm_msg) const
|
||||
{
|
||||
return (dsm_msg[0] & mask_dsm_mid);
|
||||
}
|
||||
|
||||
|
||||
uint8_t OSNMA_DSM_Reader::get_npkt(const std::vector<uint8_t>& dsm_msg) const
|
||||
{
|
||||
return ((dsm_msg[129] & mask_dsm_npkt) >> 4);
|
||||
}
|
||||
|
||||
|
||||
uint8_t OSNMA_DSM_Reader::get_npktid(const std::vector<uint8_t>& dsm_msg) const
|
||||
{
|
||||
return (dsm_msg[129] & mask_dsm_npktid);
|
||||
}
|
||||
|
||||
|
||||
std::string OSNMA_DSM_Reader::get_nmas_status(uint8_t nmas) const
|
||||
{
|
||||
std::string status_;
|
||||
const auto it = OSNMA_TABLE_1.find(nmas);
|
||||
if (it != OSNMA_TABLE_1.cend())
|
||||
{
|
||||
status_ = it->second;
|
||||
}
|
||||
return status_;
|
||||
}
|
||||
|
||||
|
||||
std::string OSNMA_DSM_Reader::get_cpks_status(uint8_t cpks) const
|
||||
{
|
||||
std::string status_;
|
||||
const auto it = OSNMA_TABLE_2.find(cpks);
|
||||
if (it != OSNMA_TABLE_2.cend())
|
||||
{
|
||||
status_ = it->second;
|
||||
}
|
||||
return status_;
|
||||
}
|
89
src/core/system_parameters/osnma_dsm_reader.h
Normal file
89
src/core/system_parameters/osnma_dsm_reader.h
Normal file
@ -0,0 +1,89 @@
|
||||
/*!
|
||||
* \file osnma_dsm_reader.h
|
||||
* \brief Class for reading OSNMA DSM messages
|
||||
* \author Carles Fernandez-Prades, 2023 cfernandez(at)cttc.es
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
|
||||
* This file is part of GNSS-SDR.
|
||||
*
|
||||
* Copyright (C) 2010-2023 (see AUTHORS file for a list of contributors)
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef GNSS_SDR_OSNMA_DSM_READER_H
|
||||
#define GNSS_SDR_OSNMA_DSM_READER_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
/** \addtogroup Core
|
||||
* \{ */
|
||||
/** \addtogroup System_Parameters
|
||||
* \{ */
|
||||
|
||||
class OSNMA_DSM_Reader
|
||||
{
|
||||
public:
|
||||
OSNMA_DSM_Reader() = default;
|
||||
uint8_t get_nmas(uint8_t nma_header) const;
|
||||
uint8_t get_cid(uint8_t nma_header) const;
|
||||
uint8_t get_cpks(uint8_t nma_header) const;
|
||||
bool get_nma_header_reserved(uint8_t nma_header) const;
|
||||
|
||||
uint8_t get_dsm_id(uint8_t dsm_header) const;
|
||||
uint8_t get_dsm_block_id(uint8_t dsm_header) const;
|
||||
|
||||
uint8_t get_number_blocks_index(uint8_t dsm_msg_0) const;
|
||||
uint8_t get_pkid(const std::vector<uint8_t>& dsm_msg) const;
|
||||
uint8_t get_cidkr(const std::vector<uint8_t>& dsm_msg) const;
|
||||
uint8_t get_dsm_reserved1(const std::vector<uint8_t>& dsm_msg) const;
|
||||
uint8_t get_hf(const std::vector<uint8_t>& dsm_msg) const;
|
||||
uint8_t get_mf(const std::vector<uint8_t>& dsm_msg) const;
|
||||
uint8_t get_ks(const std::vector<uint8_t>& dsm_msg) const;
|
||||
uint8_t get_ts(const std::vector<uint8_t>& dsm_msg) const;
|
||||
uint8_t get_maclt(const std::vector<uint8_t>& dsm_msg) const;
|
||||
uint8_t get_dsm_reserved(const std::vector<uint8_t>& dsm_msg) const;
|
||||
uint16_t get_wn_k(const std::vector<uint8_t>& dsm_msg) const;
|
||||
uint8_t get_towh_k(const std::vector<uint8_t>& dsm_msg) const;
|
||||
uint64_t get_alpha(const std::vector<uint8_t>& dsm_msg) const;
|
||||
uint16_t get_l_dk_bits(uint8_t nb_dk) const;
|
||||
uint16_t get_lk_bits(uint8_t ks) const;
|
||||
std::vector<uint8_t> get_kroot(const std::vector<uint8_t>& dsm_msg, uint16_t bytes_lk) const;
|
||||
std::string get_hash_function(uint8_t hf) const;
|
||||
std::string get_nmas_status(uint8_t nmas) const;
|
||||
std::string get_cpks_status(uint8_t cpks) const;
|
||||
|
||||
uint8_t get_mid(const std::vector<uint8_t>& dsm_msg) const;
|
||||
uint8_t get_npkt(const std::vector<uint8_t>& dsm_msg) const;
|
||||
uint8_t get_npktid(const std::vector<uint8_t>& dsm_msg) const;
|
||||
|
||||
private:
|
||||
static constexpr std::uint8_t mask_nmas{0xC0};
|
||||
static constexpr std::uint8_t mask_cid{0x30};
|
||||
static constexpr std::uint8_t mask_cpks{0x0E};
|
||||
static constexpr std::uint8_t mask_nma_header_reserved{0x01};
|
||||
static constexpr std::uint8_t mask_dsm_id{0xF0};
|
||||
static constexpr std::uint8_t mask_dsm_block_id{0x0F};
|
||||
static constexpr std::uint8_t mask_dsm_number_blocks{0xF0};
|
||||
static constexpr std::uint8_t mask_dsm_pkid{0x0F};
|
||||
static constexpr std::uint8_t mask_dsm_cidkr{0xC0};
|
||||
static constexpr std::uint8_t mask_dsm_reserved1{0x30};
|
||||
static constexpr std::uint8_t mask_dsm_hf{0x0C};
|
||||
static constexpr std::uint8_t mask_dsm_mf{0x03};
|
||||
static constexpr std::uint8_t mask_dsm_ks{0xF0};
|
||||
static constexpr std::uint8_t mask_dsm_ts{0x0F};
|
||||
static constexpr std::uint8_t mask_dsm_reserved{0xF0};
|
||||
static constexpr std::uint8_t mask_dsm_wk_k_msbyte{0x0F};
|
||||
static constexpr std::uint8_t mask_dsm_mid{0x0F};
|
||||
static constexpr std::uint8_t mask_dsm_npkt{0xF0};
|
||||
static constexpr std::uint8_t mask_dsm_npktid{0x0F};
|
||||
};
|
||||
|
||||
/** \} */
|
||||
/** \} */
|
||||
#endif // GNSS_SDR_OSNMA_DSM_READER_H
|
@ -7,6 +7,7 @@
|
||||
|
||||
add_subdirectory(unit-tests/signal-processing-blocks/libs)
|
||||
add_subdirectory(system-tests/libs)
|
||||
include_directories("${GNSSSDR_SOURCE_DIR}/src/core/receiver")
|
||||
|
||||
include(XcodeRemoveWarningDuplicates)
|
||||
|
||||
@ -549,6 +550,18 @@ if(ENABLE_UNIT_TESTING_EXTRA)
|
||||
EXPECTED_HASH MD5=066d0d8434a8bc81e161778b7c34cc07
|
||||
)
|
||||
endif()
|
||||
if(NOT EXISTS ${GNSSSDR_BINARY_DIR}/thirdparty/osnma_tests/Test_vectors.zip)
|
||||
message(STATUS "Downloading file: Test_vectors.zip")
|
||||
file(DOWNLOAD https://www.gsc-europa.eu/sites/default/files/sites/all/files/Test_vectors.zip
|
||||
${GNSSSDR_BINARY_DIR}/thirdparty/osnma_tests/Test_vectors.zip
|
||||
SHOW_PROGRESS
|
||||
EXPECTED_HASH MD5=8158aebee735652c9398e5bb6d944364
|
||||
)
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_COMMAND} -E tar xzf ${GNSSSDR_BINARY_DIR}/thirdparty/osnma_tests/Test_vectors.zip
|
||||
WORKING_DIRECTORY ${GNSSSDR_BINARY_DIR}/thirdparty/osnma_tests/
|
||||
)
|
||||
endif()
|
||||
message(STATUS "Done.")
|
||||
if(ENABLE_INSTALL_TESTS)
|
||||
install(FILES ${GNSSSDR_BINARY_DIR}/thirdparty/signal_samples/gps_l2c_m_prn7_5msps.dat DESTINATION share/gnss-sdr/signal_samples)
|
||||
@ -651,6 +664,7 @@ if(ENABLE_UNIT_TESTING)
|
||||
if(GNSSTK_OLDER_THAN_9)
|
||||
target_compile_definitions(run_tests PRIVATE -DGNSSTK_OLDER_THAN_9=1)
|
||||
endif()
|
||||
target_compile_definitions(run_tests PRIVATE -DBASE_OSNMA_TEST_VECTORS="${GNSSSDR_BINARY_DIR}/thirdparty/osnma_tests/Test_vectors/")
|
||||
endif()
|
||||
xcode_remove_warning_duplicates(run_tests)
|
||||
if(ENABLE_STRIP)
|
||||
|
@ -104,11 +104,18 @@ macro(add_benchmark)
|
||||
)
|
||||
endmacro()
|
||||
|
||||
add_benchmark(benchmark_copy)
|
||||
add_benchmark(benchmark_preamble core_system_parameters)
|
||||
add_benchmark(benchmark_detector core_system_parameters)
|
||||
add_benchmark(benchmark_reed_solomon core_system_parameters)
|
||||
set(EXTRA_BENCHMARK_DEPENDENCIES "")
|
||||
if(ENABLE_GLOG_AND_GFLAGS)
|
||||
set(EXTRA_BENCHMARK_DEPENDENCIES "Gflags::gflags;Glog::glog")
|
||||
endif()
|
||||
|
||||
add_benchmark(benchmark_atan2 Gnuradio::runtime)
|
||||
add_benchmark(benchmark_copy)
|
||||
add_benchmark(benchmark_crypto core_libs Boost::headers ${EXTRA_BENCHMARK_DEPENDENCIES})
|
||||
add_benchmark(benchmark_osnma core_libs Boost::headers ${EXTRA_BENCHMARK_DEPENDENCIES})
|
||||
add_benchmark(benchmark_detector core_system_parameters ${EXTRA_BENCHMARK_DEPENDENCIES})
|
||||
add_benchmark(benchmark_preamble core_system_parameters ${EXTRA_BENCHMARK_DEPENDENCIES})
|
||||
add_benchmark(benchmark_reed_solomon core_system_parameters ${EXTRA_BENCHMARK_DEPENDENCIES})
|
||||
|
||||
if(has_std_plus_void)
|
||||
target_compile_definitions(benchmark_detector PRIVATE -DCOMPILER_HAS_STD_PLUS_VOID=1)
|
||||
|
184
src/tests/benchmarks/benchmark_crypto.cc
Normal file
184
src/tests/benchmarks/benchmark_crypto.cc
Normal file
@ -0,0 +1,184 @@
|
||||
/*!
|
||||
* \file benchmark_crypto.cc
|
||||
* \brief Benchmarks for cryptographic functions
|
||||
* \author Carles Fernandez-Prades, 2024. cfernandez(at)cttc.es
|
||||
*
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
|
||||
* This file is part of GNSS-SDR.
|
||||
*
|
||||
* Copyright (C) 2024 (see AUTHORS file for a list of contributors)
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "gnss_crypto.h"
|
||||
#include <benchmark/benchmark.h>
|
||||
#include <memory>
|
||||
|
||||
void bm_SHA_256(benchmark::State& state)
|
||||
{
|
||||
auto d_crypto = std::make_unique<Gnss_Crypto>();
|
||||
|
||||
std::vector<uint8_t> message{
|
||||
0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x0A};
|
||||
|
||||
while (state.KeepRunning())
|
||||
{
|
||||
std::vector<uint8_t> output = d_crypto->compute_SHA_256(message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void bm_SHA3_256(benchmark::State& state)
|
||||
{
|
||||
auto d_crypto = std::make_unique<Gnss_Crypto>();
|
||||
|
||||
std::vector<uint8_t> message{
|
||||
0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x0A};
|
||||
|
||||
while (state.KeepRunning())
|
||||
{
|
||||
std::vector<uint8_t> output = d_crypto->compute_SHA3_256(message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void bm_HMAC_SHA_256(benchmark::State& state)
|
||||
{
|
||||
auto d_crypto = std::make_unique<Gnss_Crypto>();
|
||||
|
||||
std::vector<uint8_t> key = {
|
||||
0x24, 0x24, 0x3B, 0x76, 0xF9, 0x14, 0xB1, 0xA7,
|
||||
0x7D, 0x48, 0xE7, 0xF1, 0x48, 0x0C, 0xC2, 0x98,
|
||||
0xEB, 0x62, 0x3E, 0x95, 0x6B, 0x2B, 0xCE, 0xA3,
|
||||
0xB4, 0xD4, 0xDB, 0x31, 0xEE, 0x96, 0xAB, 0xFA};
|
||||
|
||||
std::vector<uint8_t> message{
|
||||
0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x0A};
|
||||
|
||||
while (state.KeepRunning())
|
||||
{
|
||||
std::vector<uint8_t> output = d_crypto->compute_HMAC_SHA_256(key, message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void bm_CMAC_AES(benchmark::State& state)
|
||||
{
|
||||
auto d_crypto = std::make_unique<Gnss_Crypto>();
|
||||
|
||||
std::vector<uint8_t> key = {
|
||||
0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6,
|
||||
0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C};
|
||||
|
||||
std::vector<uint8_t> message{
|
||||
0x6B, 0xC1, 0xBE, 0xE2, 0x2E, 0x40, 0x9F, 0x96,
|
||||
0xE9, 0x3D, 0x7E, 0x11, 0x73, 0x93, 0x17, 0x2A};
|
||||
|
||||
while (state.KeepRunning())
|
||||
{
|
||||
std::vector<uint8_t> output = d_crypto->compute_CMAC_AES(key, message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void bm_verify_ecdsa_p256(benchmark::State& state)
|
||||
{
|
||||
auto d_crypto = std::make_unique<Gnss_Crypto>();
|
||||
|
||||
// RG example - import crt certificate
|
||||
std::vector<uint8_t> message = {
|
||||
0x82, 0x10, 0x49, 0x22, 0x04, 0xE0, 0x60, 0x61, 0x0B, 0xDF,
|
||||
0x26, 0xD7, 0x7B, 0x5B, 0xF8, 0xC9, 0xCB, 0xFC, 0xF7, 0x04,
|
||||
0x22, 0x08, 0x14, 0x75, 0xFD, 0x44, 0x5D, 0xF0, 0xFF};
|
||||
|
||||
// ECDSA P-256 signature, raw format
|
||||
std::vector<uint8_t> signature = {
|
||||
0xF8, 0xCD, 0x88, 0x29, 0x9F, 0xA4, 0x60, 0x58, 0x00, 0x20,
|
||||
0x7B, 0xFE, 0xBE, 0xAC, 0x55, 0x02, 0x40, 0x53, 0xF3, 0x0F,
|
||||
0x7C, 0x69, 0xB3, 0x5C, 0x15, 0xE6, 0x08, 0x00, 0xAC, 0x3B,
|
||||
0x6F, 0xE3, 0xED, 0x06, 0x39, 0x95, 0x2F, 0x7B, 0x02, 0x8D,
|
||||
0x86, 0x86, 0x74, 0x45, 0x96, 0x1F, 0xFE, 0x94, 0xFB, 0x22,
|
||||
0x6B, 0xFF, 0x70, 0x06, 0xE0, 0xC4, 0x51, 0xEE, 0x3F, 0x87,
|
||||
0x28, 0xC1, 0x77, 0xFB};
|
||||
|
||||
// compressed ECDSA P-256 format
|
||||
std::vector<uint8_t> publicKey = {
|
||||
0x03, 0x03, 0xB2, 0xCE, 0x64, 0xBC, 0x20, 0x7B, 0xDD, 0x8B,
|
||||
0xC4, 0xDF, 0x85, 0x91, 0x87, 0xFC, 0xB6, 0x86, 0x32, 0x0D,
|
||||
0x63, 0xFF, 0xA0, 0x91, 0x41, 0x0F, 0xC1, 0x58, 0xFB, 0xB7,
|
||||
0x79, 0x80, 0xEA};
|
||||
|
||||
d_crypto->set_public_key(publicKey);
|
||||
|
||||
while (state.KeepRunning())
|
||||
{
|
||||
bool output = d_crypto->verify_signature_ecdsa_p256(message, signature);
|
||||
if (output)
|
||||
{
|
||||
// Avoid unused-but-set-variable warning
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void bm_verify_ecdsa_p521(benchmark::State& state)
|
||||
{
|
||||
std::unique_ptr<Gnss_Crypto> d_crypto = std::make_unique<Gnss_Crypto>();
|
||||
|
||||
// Message to be verified
|
||||
std::vector<uint8_t> message = {
|
||||
0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x0A}; // "Hello world\n"
|
||||
|
||||
// Public key in compressed X format
|
||||
std::vector<uint8_t> publicKey = {
|
||||
0x03, 0x00, 0x28, 0x35, 0xBB, 0xE9, 0x24, 0x59, 0x4E, 0xF0,
|
||||
0xE3, 0xA2, 0xDB, 0xC0, 0x49, 0x30, 0x60, 0x7C, 0x61, 0x90,
|
||||
0xE4, 0x03, 0xE0, 0xC7, 0xB8, 0xC2, 0x62, 0x37, 0xF7, 0x58,
|
||||
0x56, 0xBE, 0x63, 0x5C, 0x97, 0xF7, 0x53, 0x64, 0x7E, 0xE1,
|
||||
0x0C, 0x07, 0xD3, 0x97, 0x8D, 0x58, 0x46, 0xFD, 0x6E, 0x06,
|
||||
0x44, 0x01, 0xA7, 0xAA, 0xC4, 0x95, 0x13, 0x5D, 0xC9, 0x77,
|
||||
0x26, 0xE9, 0xF8, 0x72, 0x0C, 0xD3, 0x88};
|
||||
|
||||
// ECDSA P-521 signature, raw format
|
||||
std::vector<uint8_t> signature = {
|
||||
0x01, 0x5C, 0x23, 0xC0, 0xBE, 0xAD, 0x1E, 0x44, 0x60, 0xD4,
|
||||
0xE0, 0x81, 0x38, 0xF2, 0xBA, 0xF5, 0xB5, 0x37, 0x5A, 0x34,
|
||||
0xB5, 0xCA, 0x6B, 0xC8, 0x0F, 0xCD, 0x75, 0x1D, 0x5E, 0xC0,
|
||||
0x8A, 0xD3, 0xD7, 0x79, 0xA7, 0xC1, 0xB8, 0xA2, 0xC6, 0xEA,
|
||||
0x5A, 0x7D, 0x60, 0x66, 0x50, 0x97, 0x37, 0x6C, 0xF9, 0x0A,
|
||||
0xF6, 0x3D, 0x77, 0x9A, 0xE2, 0x19, 0xF7, 0xF9, 0xDD, 0x52,
|
||||
0xC4, 0x0F, 0x98, 0xAA, 0xA2, 0xA4, 0x01, 0xC9, 0x41, 0x0B,
|
||||
0xD0, 0x25, 0xDD, 0xC9, 0x7C, 0x3F, 0x70, 0x32, 0x23, 0xCF,
|
||||
0xFE, 0x37, 0x67, 0x3A, 0xBC, 0x0B, 0x76, 0x16, 0x82, 0x83,
|
||||
0x27, 0x3D, 0x1D, 0x19, 0x15, 0x78, 0x08, 0x2B, 0xD4, 0xA7,
|
||||
0xC2, 0x0F, 0x11, 0xF4, 0xDD, 0xE5, 0x5A, 0x5D, 0x04, 0x8D,
|
||||
0x6D, 0x5E, 0xC4, 0x1F, 0x54, 0x44, 0xA9, 0x13, 0x34, 0x71,
|
||||
0x0F, 0xF7, 0x57, 0x9A, 0x9F, 0x2E, 0xF4, 0x97, 0x7D, 0xAE,
|
||||
0x28, 0xEF};
|
||||
|
||||
d_crypto->set_public_key(publicKey);
|
||||
|
||||
while (state.KeepRunning())
|
||||
{
|
||||
bool output = d_crypto->verify_signature_ecdsa_p521(message, signature);
|
||||
if (output)
|
||||
{
|
||||
// Avoid unused-but-set-variable warning
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BENCHMARK(bm_SHA_256);
|
||||
BENCHMARK(bm_SHA3_256);
|
||||
BENCHMARK(bm_HMAC_SHA_256);
|
||||
BENCHMARK(bm_CMAC_AES);
|
||||
BENCHMARK(bm_verify_ecdsa_p256);
|
||||
BENCHMARK(bm_verify_ecdsa_p521);
|
||||
|
||||
BENCHMARK_MAIN();
|
127
src/tests/benchmarks/benchmark_osnma.cc
Normal file
127
src/tests/benchmarks/benchmark_osnma.cc
Normal file
@ -0,0 +1,127 @@
|
||||
/*!
|
||||
* \file benchmark_osnma.cc
|
||||
* \brief Benchmarks for osnma functions
|
||||
* \author Carles Fernandez-Prades, 2024. cfernandez(at)cttc.es
|
||||
*
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
|
||||
* This file is part of GNSS-SDR.
|
||||
*
|
||||
* Copyright (C) 2024 (see AUTHORS file for a list of contributors)
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "Galileo_OSNMA.h"
|
||||
#include "gnss_crypto.h"
|
||||
#include "osnma_helper.h"
|
||||
#include "osnma_msg_receiver.h"
|
||||
#include <benchmark/benchmark.h>
|
||||
#include <memory>
|
||||
|
||||
void bm_verify_public_key(benchmark::State& state)
|
||||
{
|
||||
osnma_msg_receiver_sptr osnma = osnma_msg_receiver_make(CRTFILE_DEFAULT, MERKLEFILE_DEFAULT);
|
||||
Osnma_Helper helper;
|
||||
osnma->set_merkle_root(helper.convert_from_hex_string("A10C440F3AA62453526DB4AF76DF8D9410D35D8277397D7053C700D192702B0D"));
|
||||
DSM_PKR_message dsm_pkr_message;
|
||||
dsm_pkr_message.npkt = 0x01;
|
||||
dsm_pkr_message.npktid = 0x2;
|
||||
dsm_pkr_message.mid = 0x01;
|
||||
std::vector<uint8_t> vec = helper.convert_from_hex_string(
|
||||
"7CBE05D9970CFC9E22D0A43A340EF557624453A2E821AADEAC989C405D78BA06"
|
||||
"956380BAB0D2C939EC6208151040CCFFCF1FB7156178FD1255BA0AECAAA253F7"
|
||||
"407B6C5DD4DF059FF8789474061301E1C34881DB7A367A913A3674300E21EAB1"
|
||||
"24EF508389B7D446C3E2ECE8D459FBBD3239A794906F5B1F92469C640164FD87");
|
||||
std::copy(vec.begin(), vec.end(), dsm_pkr_message.itn.begin());
|
||||
dsm_pkr_message.npk = helper.convert_from_hex_string("0303B2CE64BC207BDD8BC4DF859187FCB686320D63FFA091410FC158FBB77980EA");
|
||||
|
||||
while (state.KeepRunning())
|
||||
{
|
||||
osnma->verify_dsm_pkr(dsm_pkr_message);
|
||||
}
|
||||
}
|
||||
|
||||
void bm_verify_tesla_key(benchmark::State& state)
|
||||
{
|
||||
// osnma_msg_receiver_sptr osnma = osnma_msg_receiver_make(CRTFILE_DEFAULT, MERKLEFILE_DEFAULT);
|
||||
// Osnma_Helper helper;
|
||||
// osnma->d_tesla_key_verified = false;
|
||||
// osnma->d_osnma_data.d_dsm_kroot_message.kroot = {0x5B, 0xF8, 0xC9, 0xCB, 0xFC, 0xF7, 0x04, 0x22, 0x08, 0x14, 0x75, 0xFD, 0x44, 0x5D, 0xF0, 0xFF}; // Kroot, TOW 345570 GST_0 - 30
|
||||
// osnma->d_osnma_data.d_dsm_kroot_message.ks = 4; // TABLE 10 --> 128 bits
|
||||
// osnma->d_osnma_data.d_dsm_kroot_message.alpha = 0x610BDF26D77B;
|
||||
// osnma->d_GST_SIS = (1248 & 0x00000FFF) << 20 | (345630 & 0x000FFFFF);
|
||||
// osnma->d_GST_0 = ((1248 & 0x00000FFF) << 20 | (345600 & 0x000FFFFF)); // applicable time (GST_Kroot + 30)
|
||||
// osnma->d_GST_Sf = osnma->d_GST_0 + 30 * std::floor((osnma->d_GST_SIS - osnma->d_GST_0) / 30); // Eq. 3 R.G.
|
||||
//
|
||||
// osnma->d_tesla_keys.insert((std::pair<uint32_t, std::vector<uint8_t>>(345600, {0xEF, 0xF9, 0x99, 0x04, 0x0E, 0x19, 0xB5, 0x70, 0x83, 0x50, 0x60, 0xBE, 0xBD, 0x23, 0xED, 0x92}))); // K1, not needed, just for reference.
|
||||
// std::vector<uint8_t> key = {0x2D, 0xC3, 0xA3, 0xCD, 0xB1, 0x17, 0xFA, 0xAD, 0xB8, 0x3B, 0x5F, 0x0B, 0x6F, 0xEA, 0x88, 0xEB}; // K2
|
||||
// uint32_t TOW = 345630;
|
||||
//
|
||||
// while (state.KeepRunning())
|
||||
// {
|
||||
// osnma->verify_tesla_key(key, TOW);
|
||||
// }
|
||||
}
|
||||
|
||||
void bm_verify_tesla_key_24h(benchmark::State& state)
|
||||
{
|
||||
// TODO - copy of normal tesla verification but with 2800 steps instead of only two (max Kroot time is 1 day as per spec.)
|
||||
}
|
||||
|
||||
void bm_tag_verification(benchmark::State& state)
|
||||
{
|
||||
// osnma_msg_receiver_sptr osnma = osnma_msg_receiver_make(CRTFILE_DEFAULT, MERKLEFILE_DEFAULT);
|
||||
// Osnma_Helper helper;
|
||||
// uint32_t TOW_Tag0 = 345660;
|
||||
// uint32_t TOW_NavData = TOW_Tag0 - 30;
|
||||
// uint32_t TOW_Key_Tag0 = TOW_Tag0 + 30;
|
||||
// uint32_t WN = 1248;
|
||||
// uint32_t PRNa = 2;
|
||||
// uint8_t CTR = 1;
|
||||
//
|
||||
// osnma->d_osnma_data.d_dsm_kroot_message.ts = 9; // 40 bit
|
||||
// osnma->d_tesla_keys[TOW_Key_Tag0] = {0x69, 0xC0, 0x0A, 0xA7, 0x36, 0x42, 0x37, 0xA6, 0x5E, 0xBF, 0x00, 0x6A, 0xD8, 0xDD, 0xBC, 0x73}; // K4
|
||||
// osnma->d_osnma_data.d_dsm_kroot_message.mf = 0;
|
||||
// osnma->d_nav_data_manager->add_navigation_data(
|
||||
// "000011101001011001000100000101000111010110100100100101100000000000"
|
||||
// "011101101011001111101110101010000001010000011011111100000011101011"
|
||||
// "011100101101011010101011011011001001110111101011110110111111001111"
|
||||
// "001000011111101110011000111111110111111010000011101011111111110000"
|
||||
// "110111000000100000001110110000110110001110000100001110101100010100"
|
||||
// "110100010001000110001110011010110000111010000010000000000001101000"
|
||||
// "000000000011100101100100010000000000000110110100110001111100000000"
|
||||
// "000000100110100000000101010010100000001011000010001001100000011111"
|
||||
// "110111111111000000000",
|
||||
// PRNa, TOW_NavData);
|
||||
// osnma->d_osnma_data.d_nma_header.nmas = 0b10;
|
||||
//
|
||||
// MACK_tag_and_info MTI;
|
||||
// MTI.tag = static_cast<uint64_t>(0xE37BC4F858);
|
||||
// MTI.tag_info.PRN_d = 0x02;
|
||||
// MTI.tag_info.ADKD = 0x00;
|
||||
// MTI.tag_info.cop = 0x0F;
|
||||
// Tag t0(MTI, TOW_Tag0, WN, PRNa, CTR);
|
||||
//
|
||||
// while (state.KeepRunning())
|
||||
// {
|
||||
// osnma->verify_tag(t0);
|
||||
// }
|
||||
}
|
||||
|
||||
void bm_kroot_verification(benchmark::State& state)
|
||||
{
|
||||
// TODO - this is essentially the signature verification, maybe could implement it for comparison purposes
|
||||
}
|
||||
|
||||
BENCHMARK(bm_verify_public_key);
|
||||
BENCHMARK(bm_verify_tesla_key);
|
||||
BENCHMARK(bm_verify_tesla_key_24h);
|
||||
BENCHMARK(bm_tag_verification);
|
||||
BENCHMARK(bm_kroot_verification);
|
||||
|
||||
|
||||
BENCHMARK_MAIN();
|
@ -18,6 +18,7 @@
|
||||
|
||||
#include "concurrent_map.h"
|
||||
#include "concurrent_queue.h"
|
||||
#include "gnss_sdr_flags.h"
|
||||
#include "gps_acq_assist.h"
|
||||
#include <gtest/gtest.h>
|
||||
#include <fstream>
|
||||
@ -36,7 +37,6 @@ using namespace google;
|
||||
DECLARE_string(log_dir);
|
||||
#endif
|
||||
#else
|
||||
#include "gnss_sdr_flags.h"
|
||||
#include <absl/flags/flag.h>
|
||||
#include <absl/flags/parse.h>
|
||||
#include <absl/log/flags.h>
|
||||
@ -44,7 +44,6 @@ DECLARE_string(log_dir);
|
||||
#include <absl/log/log.h>
|
||||
#include <absl/log/log_sink.h>
|
||||
#include <absl/log/log_sink_registry.h>
|
||||
|
||||
class TestLogSink : public absl::LogSink
|
||||
{
|
||||
public:
|
||||
@ -78,15 +77,14 @@ Concurrent_Map<Gps_Acq_Assist> global_gps_acq_assist_map;
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
#if USE_GLOG_AND_GFLAGS
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
try
|
||||
{
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
} // catch the "testing::internal::<unnamed>::ClassUniqueToAlwaysTrue" from gtest
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
#else
|
||||
absl::ParseCommandLine(argc, argv);
|
||||
try
|
||||
|
@ -112,6 +112,8 @@ private:
|
||||
#include "unit-tests/signal-processing-blocks/adapter/adapter_test.cc"
|
||||
#include "unit-tests/signal-processing-blocks/adapter/pass_through_test.cc"
|
||||
#include "unit-tests/signal-processing-blocks/libs/item_type_helpers_test.cc"
|
||||
#include "unit-tests/signal-processing-blocks/osnma/gnss_crypto_test.cc"
|
||||
#include "unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc"
|
||||
#include "unit-tests/signal-processing-blocks/pvt/geohash_test.cc"
|
||||
#include "unit-tests/signal-processing-blocks/pvt/nmea_printer_test.cc"
|
||||
#include "unit-tests/signal-processing-blocks/pvt/rinex_printer_test.cc"
|
||||
@ -181,6 +183,7 @@ private:
|
||||
#ifndef EXCLUDE_TESTS_REQUIRING_BINARIES
|
||||
#include "unit-tests/signal-processing-blocks/acquisition/glonass_l1_ca_pcps_acquisition_test.cc"
|
||||
#include "unit-tests/signal-processing-blocks/acquisition/gps_l2_m_pcps_acquisition_test.cc"
|
||||
#include "unit-tests/signal-processing-blocks/osnma/osnma_test_vectors.cc"
|
||||
#include "unit-tests/signal-processing-blocks/tracking/gps_l2_m_dll_pll_tracking_test.cc"
|
||||
#endif
|
||||
// #include "unit-tests/signal-processing-blocks/pvt/rtklib_solver_test.cc"
|
||||
|
@ -131,6 +131,7 @@ TEST(MatioTest, WriteAndReadGrComplex)
|
||||
auto *x_read_real = reinterpret_cast<float *>(x_read_st->Re);
|
||||
auto *x_read_imag = reinterpret_cast<float *>(x_read_st->Im);
|
||||
std::vector<gr_complex> x_v_read;
|
||||
x_v_read.reserve(size);
|
||||
for (unsigned int k = 0; k < size; k++)
|
||||
{
|
||||
x_v_read.emplace_back(x_read_real[k], x_read_imag[k]);
|
||||
|
@ -0,0 +1,347 @@
|
||||
/*!
|
||||
* \file gnss_crypto_test.cc
|
||||
* \brief Tests for the Gnss_Crypto class.
|
||||
* \author Carles Fernandez, 2023-2024. cfernandez(at)cttc.es
|
||||
* Cesare Ghionoiu Martinez, 2023-2024. c.ghionoiu-martinez@tu-braunschweig.de
|
||||
*
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
|
||||
* This file is part of GNSS-SDR.
|
||||
*
|
||||
* Copyright (C) 2010-2024 (see AUTHORS file for a list of contributors)
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "gnss_crypto.h"
|
||||
#include "gnss_sdr_filesystem.h"
|
||||
#include "gnss_sdr_make_unique.h"
|
||||
#include <gtest/gtest.h>
|
||||
#include <fstream>
|
||||
#include <iterator>
|
||||
#include <utility>
|
||||
|
||||
class GnssCryptoTest : public ::testing::Test
|
||||
{
|
||||
};
|
||||
|
||||
|
||||
TEST(GnssCryptoTest, VerifyPubKeyImport)
|
||||
{
|
||||
auto d_crypto = std::make_unique<Gnss_Crypto>();
|
||||
// Input taken from RG 1.3 A7.1
|
||||
// compressed ECDSA P-256 format
|
||||
std::vector<uint8_t> publicKey = {
|
||||
0x03, 0x03, 0xB2, 0xCE, 0x64, 0xBC, 0x20, 0x7B, 0xDD, 0x8B,
|
||||
0xC4, 0xDF, 0x85, 0x91, 0x87, 0xFC, 0xB6, 0x86, 0x32, 0x0D,
|
||||
0x63, 0xFF, 0xA0, 0x91, 0x41, 0x0F, 0xC1, 0x58, 0xFB, 0xB7,
|
||||
0x79, 0x80, 0xEA};
|
||||
|
||||
ASSERT_FALSE(d_crypto->have_public_key());
|
||||
|
||||
d_crypto->set_public_key(publicKey);
|
||||
|
||||
ASSERT_TRUE(d_crypto->have_public_key());
|
||||
}
|
||||
|
||||
|
||||
TEST(GnssCryptoTest, VerifyPublicKeyStorage)
|
||||
{
|
||||
const std::string f1("./osnma_test_file1.pem");
|
||||
const std::string f2("./osnma_test_file2.pem");
|
||||
const std::string f3("./osnma_test_file3.pem");
|
||||
|
||||
// Input taken from RG 1.3 A7.1
|
||||
// compressed ECDSA P-256 format
|
||||
std::vector<uint8_t> publicKey = {
|
||||
0x03, 0x03, 0xB2, 0xCE, 0x64, 0xBC, 0x20, 0x7B, 0xDD, 0x8B,
|
||||
0xC4, 0xDF, 0x85, 0x91, 0x87, 0xFC, 0xB6, 0x86, 0x32, 0x0D,
|
||||
0x63, 0xFF, 0xA0, 0x91, 0x41, 0x0F, 0xC1, 0x58, 0xFB, 0xB7,
|
||||
0x79, 0x80, 0xEA};
|
||||
|
||||
auto d_crypto = std::make_unique<Gnss_Crypto>();
|
||||
ASSERT_FALSE(d_crypto->have_public_key());
|
||||
ASSERT_TRUE(d_crypto->get_public_key_type() == "Unknown");
|
||||
d_crypto->set_public_key(publicKey);
|
||||
ASSERT_TRUE(d_crypto->have_public_key());
|
||||
ASSERT_TRUE(d_crypto->store_public_key(f1));
|
||||
|
||||
auto d_crypto2 = std::make_unique<Gnss_Crypto>(f1, "");
|
||||
ASSERT_TRUE(d_crypto2->have_public_key());
|
||||
ASSERT_TRUE(d_crypto2->get_public_key_type() == "ECDSA P-256");
|
||||
ASSERT_TRUE(d_crypto2->store_public_key(f2));
|
||||
|
||||
std::ifstream t(f1);
|
||||
std::string content_file((std::istreambuf_iterator<char>(t)), std::istreambuf_iterator<char>());
|
||||
|
||||
std::ifstream t2(f2);
|
||||
std::string content_file2((std::istreambuf_iterator<char>(t2)), std::istreambuf_iterator<char>());
|
||||
|
||||
ASSERT_EQ(content_file, content_file2);
|
||||
|
||||
// P-521 Public key in compressed X format
|
||||
std::vector<uint8_t> publicKey_P521 = {
|
||||
0x03, 0x00, 0x28, 0x35, 0xBB, 0xE9, 0x24, 0x59, 0x4E, 0xF0,
|
||||
0xE3, 0xA2, 0xDB, 0xC0, 0x49, 0x30, 0x60, 0x7C, 0x61, 0x90,
|
||||
0xE4, 0x03, 0xE0, 0xC7, 0xB8, 0xC2, 0x62, 0x37, 0xF7, 0x58,
|
||||
0x56, 0xBE, 0x63, 0x5C, 0x97, 0xF7, 0x53, 0x64, 0x7E, 0xE1,
|
||||
0x0C, 0x07, 0xD3, 0x97, 0x8D, 0x58, 0x46, 0xFD, 0x6E, 0x06,
|
||||
0x44, 0x01, 0xA7, 0xAA, 0xC4, 0x95, 0x13, 0x5D, 0xC9, 0x77,
|
||||
0x26, 0xE9, 0xF8, 0x72, 0x0C, 0xD3, 0x88};
|
||||
|
||||
d_crypto->set_public_key(publicKey_P521);
|
||||
ASSERT_TRUE(d_crypto->have_public_key());
|
||||
ASSERT_TRUE(d_crypto->get_public_key_type() == "ECDSA P-521");
|
||||
ASSERT_TRUE(d_crypto->store_public_key(f3));
|
||||
|
||||
auto d_crypto3 = std::make_unique<Gnss_Crypto>(f3, "");
|
||||
ASSERT_TRUE(d_crypto3->have_public_key());
|
||||
ASSERT_TRUE(d_crypto3->get_public_key_type() == "ECDSA P-521");
|
||||
|
||||
std::vector<uint8_t> wrong_publicKey = {
|
||||
0x03, 0x03, 0xB2, 0xCE, 0x64, 0xBC, 0x20, 0x7B, 0xDD, 0x8B,
|
||||
0xC4, 0xDF, 0x85, 0x91, 0x87, 0xFC, 0xB6, 0x86, 0x32, 0x0D,
|
||||
0x63, 0xFF, 0xA0};
|
||||
|
||||
auto d_crypto4 = std::make_unique<Gnss_Crypto>();
|
||||
d_crypto4->set_public_key(wrong_publicKey);
|
||||
ASSERT_FALSE(d_crypto4->have_public_key());
|
||||
ASSERT_TRUE(d_crypto4->get_public_key_type() == "Unknown");
|
||||
|
||||
errorlib::error_code ec;
|
||||
ASSERT_TRUE(fs::remove(fs::path(f1), ec));
|
||||
ASSERT_TRUE(fs::remove(fs::path(f2), ec));
|
||||
ASSERT_TRUE(fs::remove(fs::path(f3), ec));
|
||||
}
|
||||
|
||||
|
||||
TEST(GnssCryptoTest, TestComputeSHA_256)
|
||||
{
|
||||
auto d_crypto = std::make_unique<Gnss_Crypto>();
|
||||
std::vector<uint8_t> message{
|
||||
0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x0A}; // Hello world
|
||||
|
||||
std::vector<uint8_t> expected_output = {
|
||||
0x18, 0x94, 0xA1, 0x9C, 0x85, 0xBA, 0x15, 0x3A, 0xCB, 0xF7,
|
||||
0x43, 0xAC, 0x4E, 0x43, 0xFC, 0x00, 0x4C, 0x89, 0x16, 0x04,
|
||||
0xB2, 0x6F, 0x8C, 0x69, 0xE1, 0xE8, 0x3E, 0xA2, 0xAF, 0xC7,
|
||||
0xC4, 0x8F};
|
||||
|
||||
std::vector<uint8_t> output = d_crypto->compute_SHA_256(message);
|
||||
|
||||
ASSERT_EQ(expected_output, output);
|
||||
}
|
||||
|
||||
|
||||
TEST(GnssCryptoTest, TestComputeSHA3_256)
|
||||
{
|
||||
auto d_crypto = std::make_unique<Gnss_Crypto>();
|
||||
std::vector<uint8_t> message{
|
||||
0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x0A}; // Hello world
|
||||
|
||||
std::vector<uint8_t> expected_output = {
|
||||
0xCC, 0xB8, 0xF9, 0x23, 0x5F, 0x4A, 0x93, 0x2C, 0xA0, 0xAB,
|
||||
0xBB, 0x2C, 0x24, 0x36, 0x72, 0x5E, 0x2E, 0x8D, 0xC7, 0x5B,
|
||||
0x99, 0xE7, 0xF6, 0xC4, 0x50, 0x5B, 0x2A, 0x93, 0x6E, 0xB6,
|
||||
0x3B, 0x3F};
|
||||
|
||||
std::vector<uint8_t> output = d_crypto->compute_SHA3_256(message);
|
||||
|
||||
ASSERT_EQ(expected_output, output);
|
||||
}
|
||||
|
||||
|
||||
// Unit test for computeHMAC_SHA_256 function.
|
||||
TEST(GnssCryptoTest, TestComputeHMACSHA256)
|
||||
{
|
||||
auto d_crypto = std::make_unique<Gnss_Crypto>();
|
||||
|
||||
std::vector<uint8_t> key = {
|
||||
0x24, 0x24, 0x3B, 0x76, 0xF9, 0x14, 0xB1, 0xA7,
|
||||
0x7D, 0x48, 0xE7, 0xF1, 0x48, 0x0C, 0xC2, 0x98,
|
||||
0xEB, 0x62, 0x3E, 0x95, 0x6B, 0x2B, 0xCE, 0xA3,
|
||||
0xB4, 0xD4, 0xDB, 0x31, 0xEE, 0x96, 0xAB, 0xFA};
|
||||
|
||||
std::vector<uint8_t> message{
|
||||
0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x0A}; // Hello world
|
||||
|
||||
std::vector<uint8_t> expected_output = {
|
||||
0xC3, 0x51, 0xF6, 0xFD, 0xDD, 0xC9, 0x8B, 0x41,
|
||||
0xD6, 0xF4, 0x77, 0x6D, 0xAC, 0xE8, 0xE0, 0x14,
|
||||
0xB2, 0x7A, 0xCC, 0x22, 0x00, 0xAA, 0xD2, 0x37,
|
||||
0xD0, 0x79, 0x06, 0x12, 0x83, 0x40, 0xB7, 0xA6};
|
||||
|
||||
std::vector<uint8_t> output = d_crypto->compute_HMAC_SHA_256(key, message);
|
||||
|
||||
ASSERT_EQ(expected_output, output);
|
||||
}
|
||||
|
||||
|
||||
TEST(GnssCryptoTest, TestComputeHMACSHA256_m0)
|
||||
{
|
||||
// key and message generated from RG A.6.5.1
|
||||
auto d_crypto = std::make_unique<Gnss_Crypto>();
|
||||
|
||||
// RG K4 @ 345690
|
||||
std::vector<uint8_t> key = {
|
||||
0x69, 0xC0, 0x0A, 0xA7, 0x36, 0x42, 0x37, 0xA6,
|
||||
0x5E, 0xBF, 0x00, 0x6A, 0xD8, 0xDD, 0xBC, 0x73};
|
||||
|
||||
// m0
|
||||
std::vector<uint8_t> message = {
|
||||
0x02, 0x4E, 0x05, 0x46, 0x3C, 0x01, 0x83, 0xA5,
|
||||
0x91, 0x05, 0x1D, 0x69, 0x25, 0x80, 0x07, 0x6B,
|
||||
0x3E, 0xEA, 0x81, 0x41, 0xBF, 0x03, 0xAD, 0xCB,
|
||||
0x5A, 0xAD, 0xB2, 0x77, 0xAF, 0x6F, 0xCF, 0x21,
|
||||
0xFB, 0x98, 0xFF, 0x7E, 0x83, 0xAF, 0xFC, 0x37,
|
||||
0x02, 0x03, 0xB0, 0xD8, 0xE1, 0x0E, 0xB1, 0x4D,
|
||||
0x11, 0x18, 0xE6, 0xB0, 0xE8, 0x20, 0x01, 0xA0,
|
||||
0x00, 0xE5, 0x91, 0x00, 0x06, 0xD3, 0x1F, 0x00,
|
||||
0x02, 0x68, 0x05, 0x4A, 0x02, 0xC2, 0x26, 0x07,
|
||||
0xF7, 0xFC, 0x00};
|
||||
|
||||
std::vector<uint8_t> expected_output = {
|
||||
0xE3, 0x7B, 0xC4, 0xF8, 0x58, 0xAE, 0x1E, 0x5C,
|
||||
0xFD, 0xC4, 0x6F, 0x05, 0x4B, 0x1F, 0x47, 0xB9,
|
||||
0xD2, 0xEA, 0x61, 0xE1, 0xEF, 0x09, 0x11, 0x5C,
|
||||
0xFE, 0x70, 0x68, 0x52, 0xBF, 0xF2, 0x3A, 0x83};
|
||||
|
||||
std::vector<uint8_t> output = d_crypto->compute_HMAC_SHA_256(key, message);
|
||||
|
||||
ASSERT_EQ(expected_output, output);
|
||||
}
|
||||
|
||||
|
||||
TEST(GnssCryptoTest, TestComputeHMACSHA256_adkd4)
|
||||
{
|
||||
// key and message generated from RG A.6.5.2
|
||||
auto d_crypto = std::make_unique<Gnss_Crypto>();
|
||||
|
||||
// RG K4 @ 345690
|
||||
std::vector<uint8_t> key = {
|
||||
0x69, 0xC0, 0x0A, 0xA7, 0x36, 0x42, 0x37, 0xA6,
|
||||
0x5E, 0xBF, 0x00, 0x6A, 0xD8, 0xDD, 0xBC, 0x73};
|
||||
|
||||
std::vector<uint8_t> message = {
|
||||
0x02, 0x02, 0x4E, 0x05, 0x46, 0x3C, 0x03, 0xBF,
|
||||
0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x44, 0x92,
|
||||
0x38, 0x22, 0x78, 0x97, 0xFD, 0xEF, 0xF9, 0x30,
|
||||
0x40};
|
||||
|
||||
std::vector<uint8_t> expected_output = {
|
||||
0x7B, 0xB2, 0x38, 0xC8, 0x83, 0xC0, 0x6A, 0x2B,
|
||||
0x50, 0x8F, 0xE6, 0x3F, 0xB7, 0xF4, 0xF5, 0x4D,
|
||||
0x44, 0xAB, 0xEE, 0x4D, 0xCE, 0xB9, 0x3D, 0xCF,
|
||||
0x65, 0xCB, 0x3A, 0x5B, 0x81, 0x4A, 0x34, 0xE9};
|
||||
|
||||
std::vector<uint8_t> output = d_crypto->compute_HMAC_SHA_256(key, message);
|
||||
|
||||
ASSERT_EQ(expected_output, output);
|
||||
}
|
||||
|
||||
|
||||
TEST(GnssCryptoTest, TestComputeCMAC_AES)
|
||||
{
|
||||
// Tests vectors from https://datatracker.ietf.org/doc/html/rfc4493#appendix-A
|
||||
auto d_crypto = std::make_unique<Gnss_Crypto>();
|
||||
|
||||
std::vector<uint8_t> key = {
|
||||
0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6,
|
||||
0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C};
|
||||
|
||||
std::vector<uint8_t> message{
|
||||
0x6B, 0xC1, 0xBE, 0xE2, 0x2E, 0x40, 0x9F, 0x96,
|
||||
0xE9, 0x3D, 0x7E, 0x11, 0x73, 0x93, 0x17, 0x2A};
|
||||
|
||||
std::vector<uint8_t> expected_output = {
|
||||
0x07, 0x0A, 0x16, 0xB4, 0x6B, 0x4D, 0x41, 0x44,
|
||||
0xF7, 0x9B, 0xDD, 0x9D, 0xD0, 0x4A, 0x28, 0x7C};
|
||||
|
||||
std::vector<uint8_t> output = d_crypto->compute_CMAC_AES(key, message);
|
||||
|
||||
ASSERT_EQ(expected_output, output);
|
||||
}
|
||||
|
||||
|
||||
TEST(GnssCryptoTest, VerifySignatureP256)
|
||||
{
|
||||
auto d_crypto = std::make_unique<Gnss_Crypto>();
|
||||
|
||||
// RG example - import crt certificate
|
||||
std::vector<uint8_t> message = {
|
||||
0x82, 0x10, 0x49, 0x22, 0x04, 0xE0, 0x60, 0x61, 0x0B, 0xDF,
|
||||
0x26, 0xD7, 0x7B, 0x5B, 0xF8, 0xC9, 0xCB, 0xFC, 0xF7, 0x04,
|
||||
0x22, 0x08, 0x14, 0x75, 0xFD, 0x44, 0x5D, 0xF0, 0xFF};
|
||||
|
||||
// ECDSA P-256 signature, raw format
|
||||
std::vector<uint8_t> signature = {
|
||||
0xF8, 0xCD, 0x88, 0x29, 0x9F, 0xA4, 0x60, 0x58, 0x00, 0x20,
|
||||
0x7B, 0xFE, 0xBE, 0xAC, 0x55, 0x02, 0x40, 0x53, 0xF3, 0x0F,
|
||||
0x7C, 0x69, 0xB3, 0x5C, 0x15, 0xE6, 0x08, 0x00, 0xAC, 0x3B,
|
||||
0x6F, 0xE3, 0xED, 0x06, 0x39, 0x95, 0x2F, 0x7B, 0x02, 0x8D,
|
||||
0x86, 0x86, 0x74, 0x45, 0x96, 0x1F, 0xFE, 0x94, 0xFB, 0x22,
|
||||
0x6B, 0xFF, 0x70, 0x06, 0xE0, 0xC4, 0x51, 0xEE, 0x3F, 0x87,
|
||||
0x28, 0xC1, 0x77, 0xFB};
|
||||
|
||||
// Input taken from RG 1.3 A7.1
|
||||
// compressed ECDSA P-256 format
|
||||
std::vector<uint8_t> publicKey = {
|
||||
0x03, 0x03, 0xB2, 0xCE, 0x64, 0xBC, 0x20, 0x7B, 0xDD, 0x8B,
|
||||
0xC4, 0xDF, 0x85, 0x91, 0x87, 0xFC, 0xB6, 0x86, 0x32, 0x0D,
|
||||
0x63, 0xFF, 0xA0, 0x91, 0x41, 0x0F, 0xC1, 0x58, 0xFB, 0xB7,
|
||||
0x79, 0x80, 0xEA};
|
||||
|
||||
d_crypto->set_public_key(publicKey);
|
||||
ASSERT_TRUE(d_crypto->verify_signature_ecdsa_p256(message, signature));
|
||||
|
||||
std::vector<uint8_t> wrong_signature = std::move(signature);
|
||||
wrong_signature[1] = 1;
|
||||
ASSERT_FALSE(d_crypto->verify_signature_ecdsa_p256(message, wrong_signature));
|
||||
}
|
||||
|
||||
|
||||
TEST(GnssCryptoTest, VerifySignatureP521)
|
||||
{
|
||||
std::unique_ptr<Gnss_Crypto> d_crypto = std::make_unique<Gnss_Crypto>();
|
||||
|
||||
// Message to be verified
|
||||
std::vector<uint8_t> message = {
|
||||
0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x0A}; // "Hello world\n"
|
||||
|
||||
// Public key in compressed X format
|
||||
std::vector<uint8_t> publicKey = {
|
||||
0x03, 0x00, 0x28, 0x35, 0xBB, 0xE9, 0x24, 0x59, 0x4E, 0xF0,
|
||||
0xE3, 0xA2, 0xDB, 0xC0, 0x49, 0x30, 0x60, 0x7C, 0x61, 0x90,
|
||||
0xE4, 0x03, 0xE0, 0xC7, 0xB8, 0xC2, 0x62, 0x37, 0xF7, 0x58,
|
||||
0x56, 0xBE, 0x63, 0x5C, 0x97, 0xF7, 0x53, 0x64, 0x7E, 0xE1,
|
||||
0x0C, 0x07, 0xD3, 0x97, 0x8D, 0x58, 0x46, 0xFD, 0x6E, 0x06,
|
||||
0x44, 0x01, 0xA7, 0xAA, 0xC4, 0x95, 0x13, 0x5D, 0xC9, 0x77,
|
||||
0x26, 0xE9, 0xF8, 0x72, 0x0C, 0xD3, 0x88};
|
||||
|
||||
// ECDSA P-521 signature, raw format
|
||||
std::vector<uint8_t> signature = {
|
||||
0x01, 0x5C, 0x23, 0xC0, 0xBE, 0xAD, 0x1E, 0x44, 0x60, 0xD4,
|
||||
0xE0, 0x81, 0x38, 0xF2, 0xBA, 0xF5, 0xB5, 0x37, 0x5A, 0x34,
|
||||
0xB5, 0xCA, 0x6B, 0xC8, 0x0F, 0xCD, 0x75, 0x1D, 0x5E, 0xC0,
|
||||
0x8A, 0xD3, 0xD7, 0x79, 0xA7, 0xC1, 0xB8, 0xA2, 0xC6, 0xEA,
|
||||
0x5A, 0x7D, 0x60, 0x66, 0x50, 0x97, 0x37, 0x6C, 0xF9, 0x0A,
|
||||
0xF6, 0x3D, 0x77, 0x9A, 0xE2, 0x19, 0xF7, 0xF9, 0xDD, 0x52,
|
||||
0xC4, 0x0F, 0x98, 0xAA, 0xA2, 0xA4, 0x01, 0xC9, 0x41, 0x0B,
|
||||
0xD0, 0x25, 0xDD, 0xC9, 0x7C, 0x3F, 0x70, 0x32, 0x23, 0xCF,
|
||||
0xFE, 0x37, 0x67, 0x3A, 0xBC, 0x0B, 0x76, 0x16, 0x82, 0x83,
|
||||
0x27, 0x3D, 0x1D, 0x19, 0x15, 0x78, 0x08, 0x2B, 0xD4, 0xA7,
|
||||
0xC2, 0x0F, 0x11, 0xF4, 0xDD, 0xE5, 0x5A, 0x5D, 0x04, 0x8D,
|
||||
0x6D, 0x5E, 0xC4, 0x1F, 0x54, 0x44, 0xA9, 0x13, 0x34, 0x71,
|
||||
0x0F, 0xF7, 0x57, 0x9A, 0x9F, 0x2E, 0xF4, 0x97, 0x7D, 0xAE,
|
||||
0x28, 0xEF};
|
||||
|
||||
d_crypto->set_public_key(publicKey);
|
||||
ASSERT_TRUE(d_crypto->verify_signature_ecdsa_p521(message, signature));
|
||||
|
||||
std::vector<uint8_t> wrong_signature = std::move(signature);
|
||||
wrong_signature[1] = 1;
|
||||
ASSERT_FALSE(d_crypto->verify_signature_ecdsa_p521(message, wrong_signature));
|
||||
}
|
@ -0,0 +1,301 @@
|
||||
/*!
|
||||
* \file osmna_msg_receiver_test.cc
|
||||
* \brief Tests for the osnma_msg_receiver class.
|
||||
* \author Carles Fernandez, 2023-2024. cfernandez(at)cttc.es
|
||||
* Cesare Ghionoiu Martinez, 2023-2024. c.ghionoiu-martinez@tu-braunschweig.de
|
||||
*
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
|
||||
* This file is part of GNSS-SDR.
|
||||
*
|
||||
* Copyright (C) 2010-2024 (see AUTHORS file for a list of contributors)
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "Galileo_OSNMA.h"
|
||||
#include "gnss_crypto.h"
|
||||
#include "osnma_helper.h"
|
||||
#include "osnma_msg_receiver.h"
|
||||
#include <gtest/gtest.h>
|
||||
#include <bitset>
|
||||
#include <chrono>
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
|
||||
#if USE_GLOG_AND_GFLAGS
|
||||
#include <glog/logging.h> // for LOG
|
||||
#else
|
||||
#include <absl/log/log.h>
|
||||
#endif
|
||||
|
||||
class OsnmaMsgReceiverTest : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
Osnma_Helper helper;
|
||||
osnma_msg_receiver_sptr osnma;
|
||||
OSNMA_msg osnma_msg{};
|
||||
std::array<int8_t, 15> nma_position_filled;
|
||||
uint32_t d_GST_SIS{};
|
||||
uint32_t TOW{};
|
||||
uint32_t WN{};
|
||||
std::tm GST_START_EPOCH = {0, 0, 0, 22, 8 - 1, 1999 - 1900, 0, 0, 0, 0, 0}; // months start with 0 and years since 1900 in std::tm
|
||||
const uint32_t LEAP_SECONDS = 0; // tried with 13 + 5, which is the official count, but won't parse correctly
|
||||
void set_time(std::tm& input);
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
// std::tm input_time = {0, 0, 5, 16, 8 - 1, 2023 - 1900, 0, 0, 0, 0, 0}; // conf. 1
|
||||
std::tm input_time = {0, 0, 0, 27, 7 - 1, 2023 - 1900, 0, 0, 0, 0, 0}; // conf. 2
|
||||
set_time(input_time);
|
||||
osnma = osnma_msg_receiver_make(CRTFILE_DEFAULT, MERKLEFILE_DEFAULT);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
TEST_F(OsnmaMsgReceiverTest, ComputeMerkleRoot)
|
||||
{
|
||||
// input data taken from Receiver Guidelines v1.3, A.7
|
||||
// Arrange
|
||||
std::vector<uint8_t> computed_merkle_root;
|
||||
std::vector<uint8_t> expected_merkle_root = helper.convert_from_hex_string("A10C440F3AA62453526DB4AF76DF8D9410D35D8277397D7053C700D192702B0D");
|
||||
DSM_PKR_message dsm_pkr_message;
|
||||
dsm_pkr_message.npkt = 0x01;
|
||||
dsm_pkr_message.npktid = 0x2;
|
||||
dsm_pkr_message.mid = 0x01;
|
||||
std::vector<uint8_t> base_leaf = helper.convert_from_hex_string("120303B2CE64BC207BDD8BC4DF859187FCB686320D63FFA091410FC158FBB77980EA");
|
||||
|
||||
// ITN
|
||||
std::vector<uint8_t> vec = helper.convert_from_hex_string(
|
||||
"7CBE05D9970CFC9E22D0A43A340EF557624453A2E821AADEAC989C405D78BA06"
|
||||
"956380BAB0D2C939EC6208151040CCFFCF1FB7156178FD1255BA0AECAAA253F7"
|
||||
"407B6C5DD4DF059FF8789474061301E1C34881DB7A367A913A3674300E21EAB1"
|
||||
"24EF508389B7D446C3E2ECE8D459FBBD3239A794906F5B1F92469C640164FD87");
|
||||
std::copy(vec.begin(), vec.end(), dsm_pkr_message.itn.begin());
|
||||
dsm_pkr_message.npk = helper.convert_from_hex_string("0303B2CE64BC207BDD8BC4DF859187FCB686320D63FFA091410FC158FBB77980EA");
|
||||
|
||||
// Act
|
||||
computed_merkle_root = osnma->compute_merkle_root(dsm_pkr_message, base_leaf);
|
||||
|
||||
// Assert
|
||||
ASSERT_EQ(computed_merkle_root, expected_merkle_root);
|
||||
}
|
||||
|
||||
|
||||
TEST_F(OsnmaMsgReceiverTest, ComputeBaseLeaf)
|
||||
{
|
||||
// input data taken from Receiver Guidelines v1.3, A.7
|
||||
// Arrange
|
||||
std::vector<uint8_t> expected_base_leaf = helper.convert_from_hex_string("120303B2CE64BC207BDD8BC4DF859187FCB686320D63FFA091410FC158FBB77980EA");
|
||||
DSM_PKR_message dsm_pkr_message;
|
||||
dsm_pkr_message.npkt = 0x01;
|
||||
dsm_pkr_message.npktid = 0x2;
|
||||
dsm_pkr_message.npk = helper.convert_from_hex_string("0303B2CE64BC207BDD8BC4DF859187FCB686320D63FFA091410FC158FBB77980EA");
|
||||
|
||||
// Act
|
||||
std::vector<uint8_t> computed_base_leaf = osnma->get_merkle_tree_leaves(dsm_pkr_message);
|
||||
|
||||
// Assert
|
||||
ASSERT_EQ(computed_base_leaf, expected_base_leaf);
|
||||
}
|
||||
|
||||
|
||||
TEST_F(OsnmaMsgReceiverTest, VerifyPublicKey)
|
||||
{
|
||||
// Input data taken from Receiver Guidelines v1.3, A.7
|
||||
// Arrange
|
||||
osnma->d_crypto->set_merkle_root(helper.convert_from_hex_string("A10C440F3AA62453526DB4AF76DF8D9410D35D8277397D7053C700D192702B0D"));
|
||||
DSM_PKR_message dsm_pkr_message;
|
||||
dsm_pkr_message.npkt = 0x01;
|
||||
dsm_pkr_message.npktid = 0x2;
|
||||
dsm_pkr_message.mid = 0x01;
|
||||
std::vector<uint8_t> vec = helper.convert_from_hex_string(
|
||||
"7CBE05D9970CFC9E22D0A43A340EF557624453A2E821AADEAC989C405D78BA06"
|
||||
"956380BAB0D2C939EC6208151040CCFFCF1FB7156178FD1255BA0AECAAA253F7"
|
||||
"407B6C5DD4DF059FF8789474061301E1C34881DB7A367A913A3674300E21EAB1"
|
||||
"24EF508389B7D446C3E2ECE8D459FBBD3239A794906F5B1F92469C640164FD87");
|
||||
std::copy(vec.begin(), vec.end(), dsm_pkr_message.itn.begin());
|
||||
dsm_pkr_message.npk = helper.convert_from_hex_string("0303B2CE64BC207BDD8BC4DF859187FCB686320D63FFA091410FC158FBB77980EA");
|
||||
|
||||
// Act
|
||||
bool result = osnma->verify_dsm_pkr(dsm_pkr_message); // TODO - refactor method so that output is more than a boolean.
|
||||
|
||||
// Assert
|
||||
ASSERT_TRUE(result);
|
||||
}
|
||||
|
||||
|
||||
TEST_F(OsnmaMsgReceiverTest, BuildTagMessageM0)
|
||||
{
|
||||
// input data taken from Receiver Guidelines v1.3, A.6.5.1
|
||||
// Arrange
|
||||
std::vector<uint8_t> expected_message = {
|
||||
0x02, 0x4E, 0x05, 0x46, 0x3C, 0x01, 0x83, 0xA5, 0x91, 0x05, 0x1D, 0x69, 0x25, 0x80, 0x07, 0x6B,
|
||||
0x3E, 0xEA, 0x81, 0x41, 0xBF, 0x03, 0xAD, 0xCB, 0x5A, 0xAD, 0xB2, 0x77, 0xAF, 0x6F, 0xCF, 0x21,
|
||||
0xFB, 0x98, 0xFF, 0x7E, 0x83, 0xAF, 0xFC, 0x37, 0x02, 0x03, 0xB0, 0xD8, 0xE1, 0x0E, 0xB1, 0x4D,
|
||||
0x11, 0x18, 0xE6, 0xB0, 0xE8, 0x20, 0x01, 0xA0, 0x00, 0xE5, 0x91, 0x00, 0x06, 0xD3, 0x1F, 0x00,
|
||||
0x02, 0x68, 0x05, 0x4A, 0x02, 0xC2, 0x26, 0x07, 0xF7, 0xFC, 0x00};
|
||||
|
||||
uint32_t TOW_Tag0 = 345660;
|
||||
uint32_t TOW_NavData = TOW_Tag0 - 30;
|
||||
uint32_t TOW_Key_Tag0 = TOW_Tag0 + 30;
|
||||
uint32_t WN = 1248;
|
||||
uint32_t PRNa = 2;
|
||||
uint8_t CTR = 1;
|
||||
|
||||
osnma->d_osnma_data.d_dsm_kroot_message.ts = 9; // 40 bit
|
||||
osnma->d_tesla_keys[TOW_Key_Tag0] = {0x69, 0xC0, 0x0A, 0xA7, 0x36, 0x42, 0x37, 0xA6, 0x5E, 0xBF, 0x00, 0x6A, 0xD8, 0xDB, 0xBC, 0x73}; // K4
|
||||
osnma->d_osnma_data.d_dsm_kroot_message.mf = 0;
|
||||
osnma->d_nav_data_manager->add_navigation_data(
|
||||
"000011101001011001000100000101000111010110100100100101100000000000"
|
||||
"011101101011001111101110101010000001010000011011111100000011101011"
|
||||
"011100101101011010101011011011001001110111101011110110111111001111"
|
||||
"001000011111101110011000111111110111111010000011101011111111110000"
|
||||
"110111000000100000001110110000110110001110000100001110101100010100"
|
||||
"110100010001000110001110011010110000111010000010000000000001101000"
|
||||
"000000000011100101100100010000000000000110110100110001111100000000"
|
||||
"000000100110100000000101010010100000001011000010001001100000011111"
|
||||
"110111111111000000000",
|
||||
PRNa, TOW_NavData);
|
||||
osnma->d_osnma_data.d_nma_header.nmas = 0b10;
|
||||
|
||||
MACK_tag_and_info MTI;
|
||||
MTI.tag = static_cast<uint64_t>(0xE37BC4F858);
|
||||
MTI.tag_info.PRN_d = 0x02;
|
||||
MTI.tag_info.ADKD = 0x00;
|
||||
MTI.tag_info.cop = 0x0F;
|
||||
Tag t0(MTI, TOW_Tag0, WN, PRNa, CTR);
|
||||
|
||||
// Act
|
||||
auto computed_message = osnma->build_message(t0);
|
||||
|
||||
// Assert
|
||||
ASSERT_TRUE(computed_message == expected_message);
|
||||
}
|
||||
|
||||
|
||||
TEST_F(OsnmaMsgReceiverTest, TagVerification)
|
||||
{
|
||||
// input data taken from Receiver Guidelines v1.3, A.6.5.1
|
||||
// Arrange
|
||||
// Tag0
|
||||
uint32_t TOW_Tag0 = 345660;
|
||||
uint32_t TOW_NavData = TOW_Tag0 - 30;
|
||||
uint32_t TOW_Key_Tag0 = TOW_Tag0 + 30;
|
||||
uint32_t WN = 1248;
|
||||
uint32_t PRNa = 2;
|
||||
uint8_t CTR = 1;
|
||||
|
||||
osnma->d_osnma_data.d_dsm_kroot_message.ts = 9; // 40 bit
|
||||
osnma->d_tesla_keys[TOW_Key_Tag0] = {0x69, 0xC0, 0x0A, 0xA7, 0x36, 0x42, 0x37, 0xA6, 0x5E, 0xBF, 0x00, 0x6A, 0xD8, 0xDD, 0xBC, 0x73}; // K4
|
||||
osnma->d_osnma_data.d_dsm_kroot_message.mf = 0;
|
||||
osnma->d_nav_data_manager->add_navigation_data(
|
||||
"000011101001011001000100000101000111010110100100100101100000000000"
|
||||
"011101101011001111101110101010000001010000011011111100000011101011"
|
||||
"011100101101011010101011011011001001110111101011110110111111001111"
|
||||
"001000011111101110011000111111110111111010000011101011111111110000"
|
||||
"110111000000100000001110110000110110001110000100001110101100010100"
|
||||
"110100010001000110001110011010110000111010000010000000000001101000"
|
||||
"000000000011100101100100010000000000000110110100110001111100000000"
|
||||
"000000100110100000000101010010100000001011000010001001100000011111"
|
||||
"110111111111000000000",
|
||||
PRNa, TOW_NavData);
|
||||
osnma->d_osnma_data.d_nma_header.nmas = 0b10;
|
||||
|
||||
MACK_tag_and_info MTI;
|
||||
MTI.tag = static_cast<uint64_t>(0xE37BC4F858);
|
||||
MTI.tag_info.PRN_d = 0x02;
|
||||
MTI.tag_info.ADKD = 0x00;
|
||||
MTI.tag_info.cop = 0x0F;
|
||||
Tag t0(MTI, TOW_Tag0, WN, PRNa, CTR);
|
||||
|
||||
// Act
|
||||
bool result_tag0 = osnma->verify_tag(t0);
|
||||
|
||||
// Assert
|
||||
|
||||
// Tag3
|
||||
uint32_t TOW_Key_Tag3 = TOW_Tag0 + 30;
|
||||
WN = 1248;
|
||||
PRNa = 2;
|
||||
CTR = 3;
|
||||
|
||||
osnma->d_osnma_data.d_dsm_kroot_message.ts = 9; // 40 bit
|
||||
osnma->d_tesla_keys[TOW_Key_Tag3] = {0x69, 0xC0, 0x0A, 0xA7, 0x36, 0x42, 0x37, 0xA6, 0x5E, 0xBF, 0x00, 0x6A, 0xD8, 0xDD, 0xBC, 0x73}; // K4
|
||||
osnma->d_osnma_data.d_dsm_kroot_message.mf = 0;
|
||||
osnma->d_nav_data_manager->add_navigation_data(
|
||||
"111111111111111111111111111111110000000000000000000000010001001001001000"
|
||||
"111000001000100111100010010111111111011110111111111001001100000100000",
|
||||
PRNa, TOW_NavData);
|
||||
osnma->d_osnma_data.d_nma_header.nmas = 0b10;
|
||||
|
||||
MTI.tag = static_cast<uint64_t>(0x7BB238C883);
|
||||
MTI.tag_info.PRN_d = 0x02;
|
||||
MTI.tag_info.ADKD = 0x04;
|
||||
MTI.tag_info.cop = 0x0F;
|
||||
Tag t3(MTI, TOW_Tag0, WN, PRNa, CTR);
|
||||
|
||||
bool result_tag3 = osnma->verify_tag(t3);
|
||||
|
||||
ASSERT_TRUE(result_tag0 && result_tag3);
|
||||
}
|
||||
|
||||
|
||||
TEST_F(OsnmaMsgReceiverTest, TeslaKeyVerification)
|
||||
{
|
||||
// input data taken from Receiver Guidelines v1.3, A.5.2
|
||||
// Arrange
|
||||
osnma->d_tesla_key_verified = false;
|
||||
osnma->d_osnma_data.d_dsm_kroot_message.kroot = {0x5B, 0xF8, 0xC9, 0xCB, 0xFC, 0xF7, 0x04, 0x22, 0x08, 0x14, 0x75, 0xFD, 0x44, 0x5D, 0xF0, 0xFF}; // Kroot, TOW 345570 GST_0 - 30
|
||||
osnma->d_osnma_data.d_dsm_kroot_message.ks = 4; // TABLE 10 --> 128 bits
|
||||
osnma->d_osnma_data.d_dsm_kroot_message.alpha = 0x610BDF26D77B;
|
||||
osnma->d_GST_SIS = (1248 & 0x00000FFF) << 20 | (345630 & 0x000FFFFF);
|
||||
osnma->d_GST_0 = ((1248 & 0x00000FFF) << 20 | (345600 & 0x000FFFFF)); // applicable time (GST_Kroot + 30)
|
||||
osnma->d_GST_Sf = osnma->d_GST_0 + 30 * std::floor((osnma->d_GST_SIS - osnma->d_GST_0) / 30); // Eq. 3 R.G.
|
||||
|
||||
osnma->d_tesla_keys.insert((std::pair<uint32_t, std::vector<uint8_t>>(345600, {0xEF, 0xF9, 0x99, 0x04, 0x0E, 0x19, 0xB5, 0x70, 0x83, 0x50, 0x60, 0xBE, 0xBD, 0x23, 0xED, 0x92}))); // K1, not needed, just for reference.
|
||||
std::vector<uint8_t> key = {0x2D, 0xC3, 0xA3, 0xCD, 0xB1, 0x17, 0xFA, 0xAD, 0xB8, 0x3B, 0x5F, 0x0B, 0x6F, 0xEA, 0x88, 0xEB}; // K2
|
||||
uint32_t TOW = 345630;
|
||||
|
||||
// Act
|
||||
bool result = osnma->verify_tesla_key(key, TOW); // TODO - refactor so that output is not a boolean. Or use last_verified_tesla_key?
|
||||
|
||||
// Assert
|
||||
ASSERT_TRUE(result);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Sets the time based on the given input.
|
||||
*
|
||||
* This function calculates the week number (WN) and time of week (TOW)
|
||||
* based on the input time and the GST_START_EPOCH. It then stores the
|
||||
* calculated values in the WN and TOW member variables. Finally, it
|
||||
* combines the WN and TOW into a single 32-bit value and stores it in
|
||||
* the d_GST_SIS member variable.
|
||||
*
|
||||
* @param input The input time as a tm struct.
|
||||
*/
|
||||
void OsnmaMsgReceiverTest::set_time(std::tm& input)
|
||||
{
|
||||
auto epoch_time_point = std::chrono::system_clock::from_time_t(mktime(&GST_START_EPOCH));
|
||||
auto input_time_point = std::chrono::system_clock::from_time_t(mktime(&input));
|
||||
|
||||
// Get the duration from epoch in seconds
|
||||
auto duration_sec = std::chrono::duration_cast<std::chrono::seconds>(input_time_point - epoch_time_point);
|
||||
|
||||
// Calculate the week number (WN) and time of week (TOW)
|
||||
uint32_t sec_in_week = 7 * 24 * 60 * 60;
|
||||
uint32_t week_number = duration_sec.count() / sec_in_week;
|
||||
uint32_t time_of_week = duration_sec.count() % sec_in_week;
|
||||
this->WN = week_number;
|
||||
this->TOW = time_of_week + LEAP_SECONDS;
|
||||
// Return the week number and time of week as a pair
|
||||
|
||||
// TODO: d_GST_SIS or d_receiver_time? doubt
|
||||
// I am assuming that local realisation of receiver is identical to SIS GST time coming from W5 or W0
|
||||
this->d_GST_SIS = (this->WN & 0x00000FFF) << 20 | (this->TOW & 0x000FFFFF);
|
||||
}
|
@ -0,0 +1,671 @@
|
||||
/*!
|
||||
* \file osmna_test_vectors.cc
|
||||
* \brief Tests for the osnma_msg_receiver class.
|
||||
* \author Carles Fernandez, 2023-2024. cfernandez(at)cttc.es
|
||||
* Cesare Ghionoiu Martinez, 2023-2024. c.ghionoiu-martinez@tu-braunschweig.de
|
||||
*
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
|
||||
* This file is part of GNSS-SDR.
|
||||
*
|
||||
* Copyright (C) 2010-2024 (see AUTHORS file for a list of contributors)
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "gnss_crypto.h"
|
||||
#include "osnma_msg_receiver.h"
|
||||
#include <gtest/gtest.h>
|
||||
#include <bitset>
|
||||
#include <chrono>
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
|
||||
#if USE_GLOG_AND_GFLAGS
|
||||
#include <glog/logging.h> // for LOG
|
||||
#else
|
||||
#include <absl/log/log.h>
|
||||
#endif
|
||||
|
||||
struct TestVector
|
||||
{
|
||||
int svId;
|
||||
int numNavBits;
|
||||
std::vector<uint8_t> navBits;
|
||||
};
|
||||
|
||||
|
||||
class OsnmaTestVectors : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
std::vector<uint8_t> parseNavBits(const std::string& hex);
|
||||
std::vector<TestVector> readTestVectorsFromFile(const std::string& filename);
|
||||
std::string bytes_to_str(const std::vector<uint8_t>& bytes);
|
||||
std::vector<uint8_t> extract_page_bytes(const TestVector& tv, int byte_index, int num_bytes);
|
||||
bool feedOsnmaWithTestVectors(osnma_msg_receiver_sptr osnma_object, std::vector<std::vector<TestVector>> testVectors, std::vector<std::tm> startTimesFiles);
|
||||
void set_time(std::tm& input);
|
||||
void SetUp() override
|
||||
{
|
||||
}
|
||||
|
||||
uint32_t d_GST_SIS{};
|
||||
uint32_t TOW{};
|
||||
uint32_t WN{};
|
||||
std::tm GST_START_EPOCH = {0, 0, 0, 22, 8 - 1, 1999 - 1900, 0, 0, 0, 0, 0}; // months start with 0 and years since 1900 in std::tm
|
||||
const uint32_t LEAP_SECONDS = 0;
|
||||
const int SIZE_PAGE_BYTES{240 / 8}; // total bytes of a page
|
||||
const int SIZE_SUBFRAME_PAGES{15}; // number of pages of a subframe
|
||||
const int DURATION_SUBFRAME{30}; // duration of a subframe, in seconds// 13 + 5;
|
||||
|
||||
bool d_flag_NPK{false}; // flag for NPK, new MT will be set when the new Kroot is received.
|
||||
};
|
||||
|
||||
TEST_F(OsnmaTestVectors, NominalTestConf1)
|
||||
{
|
||||
// Arrange
|
||||
std::string crtFilePath = std::string(BASE_OSNMA_TEST_VECTORS) + "cryptographic_material/Merkle_tree_1/PublicKey/OSNMA_PublicKey_20230803105952_newPKID_1.crt";
|
||||
std::string merkleFilePath = std::string(BASE_OSNMA_TEST_VECTORS) + "cryptographic_material/Merkle_tree_1/MerkleTree/OSNMA_MerkleTree_20230803105953_newPKID_1.xml";
|
||||
osnma_msg_receiver_sptr osnma = osnma_msg_receiver_make(crtFilePath, merkleFilePath);
|
||||
|
||||
std::tm input_time = {0, 0, 5, 16, 8 - 1, 2023 - 1900, 0, 0, 0, 0, 0};
|
||||
std::vector<std::tm> input_times = {input_time};
|
||||
|
||||
std::vector<TestVector> testVector = readTestVectorsFromFile(std::string(BASE_OSNMA_TEST_VECTORS) + "osnma_test_vectors/configuration_1/16_AUG_2023_GST_05_00_01.csv");
|
||||
if (testVector.empty())
|
||||
{
|
||||
ASSERT_TRUE(false);
|
||||
}
|
||||
std::vector<std::vector<TestVector>> testVectors = {testVector};
|
||||
|
||||
// Act
|
||||
bool result = feedOsnmaWithTestVectors(osnma, testVectors, input_times);
|
||||
ASSERT_TRUE(result);
|
||||
|
||||
// Assert
|
||||
LOG(INFO) << "Successful tags count= " << osnma->d_count_successful_tags;
|
||||
LOG(INFO) << "Failed tags count= " << osnma->d_count_failed_tags;
|
||||
LOG(INFO) << "Unverified tags count= " << osnma->d_tags_awaiting_verify.size();
|
||||
LOG(INFO) << "Failed Kroot count= " << osnma->d_count_failed_Kroot;
|
||||
LOG(INFO) << "Failed PK count= " << osnma->d_count_failed_pubKey;
|
||||
LOG(INFO) << "Failed MACSEQ count= " << osnma->d_count_failed_macseq;
|
||||
ASSERT_EQ(osnma->d_count_failed_tags, 0);
|
||||
ASSERT_EQ(osnma->d_count_failed_Kroot, 0);
|
||||
ASSERT_EQ(osnma->d_count_failed_pubKey, 0);
|
||||
ASSERT_EQ(osnma->d_count_failed_macseq, 0);
|
||||
}
|
||||
|
||||
TEST_F(OsnmaTestVectors, NominalTestConf2)
|
||||
{
|
||||
// Arrange
|
||||
std::string crtFilePath = std::string(BASE_OSNMA_TEST_VECTORS) + "cryptographic_material/Merkle_tree_2/PublicKey/OSNMA_PublicKey_20230720113300_newPKID_2.crt"; // conf. 2
|
||||
std::string merkleFilePath = std::string(BASE_OSNMA_TEST_VECTORS) + "cryptographic_material/Merkle_tree_2/MerkleTree/OSNMA_MerkleTree_20230720113300_newPKID_2.xml";
|
||||
osnma_msg_receiver_sptr osnma = osnma_msg_receiver_make(crtFilePath, merkleFilePath);
|
||||
|
||||
std::tm input_time = {0, 0, 0, 27, 7 - 1, 2023 - 1900, 0, 0, 0, 0, 0}; // conf. 2
|
||||
std::vector<std::tm> input_times = {input_time};
|
||||
|
||||
std::vector<TestVector> testVector = readTestVectorsFromFile(std::string(BASE_OSNMA_TEST_VECTORS) + "osnma_test_vectors/configuration_2/27_JUL_2023_GST_00_00_01.csv");
|
||||
if (testVector.empty())
|
||||
{
|
||||
ASSERT_TRUE(false);
|
||||
}
|
||||
std::vector<std::vector<TestVector>> testVectors = {testVector};
|
||||
|
||||
// Act
|
||||
bool result = feedOsnmaWithTestVectors(osnma, testVectors, input_times);
|
||||
ASSERT_TRUE(result);
|
||||
|
||||
// Assert
|
||||
LOG(INFO) << "Successful tags count= " << osnma->d_count_successful_tags;
|
||||
LOG(INFO) << "Failed tags count= " << osnma->d_count_failed_tags;
|
||||
LOG(INFO) << "Unverified tags count= " << osnma->d_tags_awaiting_verify.size();
|
||||
LOG(INFO) << "Failed Kroot count= " << osnma->d_count_failed_Kroot;
|
||||
LOG(INFO) << "Failed PK count= " << osnma->d_count_failed_pubKey;
|
||||
LOG(INFO) << "Failed MACSEQ count= " << osnma->d_count_failed_macseq;
|
||||
ASSERT_EQ(osnma->d_count_failed_tags, 0);
|
||||
ASSERT_EQ(osnma->d_count_failed_Kroot, 0);
|
||||
ASSERT_EQ(osnma->d_count_failed_pubKey, 0);
|
||||
ASSERT_EQ(osnma->d_count_failed_macseq, 0);
|
||||
}
|
||||
|
||||
TEST_F(OsnmaTestVectors, PublicKeyRenewal)
|
||||
{
|
||||
// Arrange
|
||||
std::string crtFilePath = std::string(BASE_OSNMA_TEST_VECTORS) + "cryptographic_material/Merkle_tree_2/PublicKey/OSNMA_PublicKey_20231007041500_PKID_7.crt";
|
||||
std::string merkleFilePath = std::string(BASE_OSNMA_TEST_VECTORS) + "cryptographic_material/Merkle_tree_2/MerkleTree/OSNMA_MerkleTree_20231007041500_PKID_7.xml";
|
||||
osnma_msg_receiver_sptr osnma = osnma_msg_receiver_make(crtFilePath, merkleFilePath);
|
||||
|
||||
std::tm input_time_step1 = {0, 45, 2, 7, 10 - 1, 2023 - 1900, 0, 0, 0, 0, 0};
|
||||
std::tm input_time_step2 = {0, 45, 3, 7, 10 - 1, 2023 - 1900, 0, 0, 0, 0, 0};
|
||||
std::tm input_time_step3 = {0, 45, 4, 7, 10 - 1, 2023 - 1900, 0, 0, 0, 0, 0};
|
||||
std::vector<std::tm> input_times = {input_time_step1, input_time_step2, input_time_step3};
|
||||
|
||||
std::vector<TestVector> testVectors_step1 = readTestVectorsFromFile(std::string(BASE_OSNMA_TEST_VECTORS) + "osnma_test_vectors/npk_step1/07_OCT_2023_GST_02_45_01.csv");
|
||||
std::vector<TestVector> testVectors_step2 = readTestVectorsFromFile(std::string(BASE_OSNMA_TEST_VECTORS) + "osnma_test_vectors/npk_step2/07_OCT_2023_GST_03_45_01.csv");
|
||||
std::vector<TestVector> testVectors_step3 = readTestVectorsFromFile(std::string(BASE_OSNMA_TEST_VECTORS) + "osnma_test_vectors/npk_step3/07_OCT_2023_GST_04_45_01.csv");
|
||||
if (testVectors_step1.empty() || testVectors_step2.empty() || testVectors_step3.empty())
|
||||
{
|
||||
ASSERT_TRUE(false);
|
||||
}
|
||||
std::vector<std::vector<TestVector>> testVectors = {testVectors_step1, testVectors_step2, testVectors_step3};
|
||||
|
||||
// Act
|
||||
d_flag_NPK = true;
|
||||
bool result = feedOsnmaWithTestVectors(osnma, testVectors, input_times);
|
||||
ASSERT_TRUE(result);
|
||||
|
||||
// Assert
|
||||
LOG(INFO) << "Successful tags count= " << osnma->d_count_successful_tags;
|
||||
LOG(INFO) << "Failed tags count= " << osnma->d_count_failed_tags;
|
||||
LOG(INFO) << "Unverified tags count= " << osnma->d_tags_awaiting_verify.size();
|
||||
LOG(INFO) << "Failed Kroot count= " << osnma->d_count_failed_Kroot;
|
||||
LOG(INFO) << "Failed PK count= " << osnma->d_count_failed_pubKey;
|
||||
LOG(INFO) << "Failed MACSEQ count= " << osnma->d_count_failed_macseq;
|
||||
ASSERT_EQ(osnma->d_count_failed_tags, 0);
|
||||
ASSERT_EQ(osnma->d_count_failed_Kroot, 0);
|
||||
ASSERT_EQ(osnma->d_count_failed_pubKey, 0);
|
||||
ASSERT_EQ(osnma->d_count_failed_macseq, 0);
|
||||
}
|
||||
|
||||
TEST_F(OsnmaTestVectors, PublicKeyRevocation)
|
||||
{
|
||||
// Arrange
|
||||
std::string crtFilePath = std::string(BASE_OSNMA_TEST_VECTORS) + "cryptographic_material/Merkle_tree_2/PublicKey/OSNMA_PublicKey_20231007081500_PKID_8.crt";
|
||||
std::string merkleFilePath = std::string(BASE_OSNMA_TEST_VECTORS) + "cryptographic_material/Merkle_tree_2/MerkleTree/OSNMA_MerkleTree_20231007081500_PKID_8.xml";
|
||||
osnma_msg_receiver_sptr osnma = osnma_msg_receiver_make(crtFilePath, merkleFilePath);
|
||||
|
||||
std::tm input_time_step1 = {0, 45, 7, 7, 10 - 1, 2023 - 1900, 0, 0, 0, 0, 0};
|
||||
std::tm input_time_step2 = {0, 30, 9, 7, 10 - 1, 2023 - 1900, 0, 0, 0, 0, 0};
|
||||
std::tm input_time_step3 = {0, 30, 10, 7, 10 - 1, 2023 - 1900, 0, 0, 0, 0, 0};
|
||||
std::vector<std::tm> input_times = {input_time_step1, input_time_step2, input_time_step3};
|
||||
|
||||
std::vector<TestVector> testVectors_step1 = readTestVectorsFromFile(std::string(BASE_OSNMA_TEST_VECTORS) + "osnma_test_vectors/pkrev_step1/07_OCT_2023_GST_07_45_01.csv");
|
||||
std::vector<TestVector> testVectors_step2 = readTestVectorsFromFile(std::string(BASE_OSNMA_TEST_VECTORS) + "osnma_test_vectors/pkrev_step2/07_OCT_2023_GST_09_30_01.csv");
|
||||
std::vector<TestVector> testVectors_step3 = readTestVectorsFromFile(std::string(BASE_OSNMA_TEST_VECTORS) + "osnma_test_vectors/pkrev_step3/07_OCT_2023_GST_10_30_01.csv");
|
||||
if (testVectors_step1.empty() || testVectors_step2.empty() || testVectors_step3.empty())
|
||||
{
|
||||
ASSERT_TRUE(false);
|
||||
}
|
||||
std::vector<std::vector<TestVector>> testVectors = {testVectors_step1, testVectors_step2, testVectors_step3};
|
||||
|
||||
// Act
|
||||
bool result = feedOsnmaWithTestVectors(osnma, testVectors, input_times);
|
||||
ASSERT_TRUE(result);
|
||||
|
||||
// Assert
|
||||
LOG(INFO) << "Successful tags count= " << osnma->d_count_successful_tags;
|
||||
LOG(INFO) << "Failed tags count= " << osnma->d_count_failed_tags;
|
||||
LOG(INFO) << "Unverified tags count= " << osnma->d_tags_awaiting_verify.size();
|
||||
LOG(INFO) << "Failed Kroot count= " << osnma->d_count_failed_Kroot;
|
||||
LOG(INFO) << "Failed PK count= " << osnma->d_count_failed_pubKey;
|
||||
LOG(INFO) << "Failed MACSEQ count= " << osnma->d_count_failed_macseq;
|
||||
ASSERT_EQ(osnma->d_count_failed_tags, 0);
|
||||
ASSERT_EQ(osnma->d_count_failed_Kroot, 0);
|
||||
ASSERT_EQ(osnma->d_count_failed_pubKey, 0);
|
||||
ASSERT_EQ(osnma->d_count_failed_macseq, 0);
|
||||
}
|
||||
|
||||
TEST_F(OsnmaTestVectors, ChainRenewal)
|
||||
{
|
||||
// Arrange
|
||||
std::string crtFilePath = std::string(BASE_OSNMA_TEST_VECTORS) + "cryptographic_material/Merkle_tree_2/PublicKey/OSNMA_PublicKey_20231007041500_PKID_7.crt";
|
||||
std::string merkleFilePath = std::string(BASE_OSNMA_TEST_VECTORS) + "cryptographic_material/Merkle_tree_2/MerkleTree/OSNMA_MerkleTree_20231007041500_PKID_7.xml";
|
||||
osnma_msg_receiver_sptr osnma = osnma_msg_receiver_make(crtFilePath, merkleFilePath);
|
||||
|
||||
std::tm input_time_step1 = {0, 45, 16, 6, 10 - 1, 2023 - 1900, 0, 0, 0, 0, 0};
|
||||
std::tm input_time_step2 = {0, 30, 18, 6, 10 - 1, 2023 - 1900, 0, 0, 0, 0, 0};
|
||||
std::vector<std::tm> input_times = {input_time_step1, input_time_step2};
|
||||
|
||||
std::vector<TestVector> testVectors_step1 = readTestVectorsFromFile(std::string(BASE_OSNMA_TEST_VECTORS) + "osnma_test_vectors/eoc_step1/06_OCT_2023_GST_16_45_01.csv");
|
||||
std::vector<TestVector> testVectors_step2 = readTestVectorsFromFile(std::string(BASE_OSNMA_TEST_VECTORS) + "osnma_test_vectors/eoc_step2/06_OCT_2023_GST_18_30_01.csv");
|
||||
if (testVectors_step1.empty() || testVectors_step2.empty())
|
||||
{
|
||||
ASSERT_TRUE(false);
|
||||
}
|
||||
std::vector<std::vector<TestVector>> testVectors = {testVectors_step1, testVectors_step2};
|
||||
|
||||
// Act
|
||||
bool result = feedOsnmaWithTestVectors(osnma, testVectors, input_times);
|
||||
ASSERT_TRUE(result);
|
||||
|
||||
// Assert
|
||||
LOG(INFO) << "Successful tags count= " << osnma->d_count_successful_tags;
|
||||
LOG(INFO) << "Failed tags count= " << osnma->d_count_failed_tags;
|
||||
LOG(INFO) << "Unverified tags count= " << osnma->d_tags_awaiting_verify.size();
|
||||
LOG(INFO) << "Failed Kroot count= " << osnma->d_count_failed_Kroot;
|
||||
LOG(INFO) << "Failed PK count= " << osnma->d_count_failed_pubKey;
|
||||
LOG(INFO) << "Failed MACSEQ count= " << osnma->d_count_failed_macseq;
|
||||
ASSERT_EQ(osnma->d_count_failed_tags, 0);
|
||||
ASSERT_EQ(osnma->d_count_failed_Kroot, 0);
|
||||
ASSERT_EQ(osnma->d_count_failed_pubKey, 0);
|
||||
ASSERT_EQ(osnma->d_count_failed_macseq, 0);
|
||||
}
|
||||
|
||||
TEST_F(OsnmaTestVectors, ChainRevocation)
|
||||
{
|
||||
// Arrange
|
||||
std::string crtFilePath = std::string(BASE_OSNMA_TEST_VECTORS) + "cryptographic_material/Merkle_tree_2/PublicKey/OSNMA_PublicKey_20231007041500_PKID_7.crt";
|
||||
std::string merkleFilePath = std::string(BASE_OSNMA_TEST_VECTORS) + "cryptographic_material/Merkle_tree_2/MerkleTree/OSNMA_MerkleTree_20231007041500_PKID_7.xml";
|
||||
osnma_msg_receiver_sptr osnma = osnma_msg_receiver_make(crtFilePath, merkleFilePath);
|
||||
|
||||
std::tm input_time_step1 = {0, 45, 21, 6, 10 - 1, 2023 - 1900, 0, 0, 0, 0, 0};
|
||||
std::tm input_time_step2 = {0, 30, 23, 6, 10 - 1, 2023 - 1900, 0, 0, 0, 0, 0};
|
||||
std::tm input_time_step3 = {0, 30, 00, 7, 10 - 1, 2023 - 1900, 0, 0, 0, 0, 0};
|
||||
|
||||
std::vector<std::tm> input_times = {input_time_step1, input_time_step2, input_time_step3};
|
||||
|
||||
std::vector<TestVector> testVectors_step1 = readTestVectorsFromFile(std::string(BASE_OSNMA_TEST_VECTORS) + "osnma_test_vectors/crev_step1/06_OCT_2023_GST_21_45_01.csv");
|
||||
std::vector<TestVector> testVectors_step2 = readTestVectorsFromFile(std::string(BASE_OSNMA_TEST_VECTORS) + "osnma_test_vectors/crev_step2/06_OCT_2023_GST_23_30_01.csv");
|
||||
std::vector<TestVector> testVectors_step3 = readTestVectorsFromFile(std::string(BASE_OSNMA_TEST_VECTORS) + "osnma_test_vectors/crev_step3/07_OCT_2023_GST_00_30_01.csv");
|
||||
if (testVectors_step1.empty() || testVectors_step2.empty() || testVectors_step3.empty())
|
||||
{
|
||||
ASSERT_TRUE(false);
|
||||
}
|
||||
std::vector<std::vector<TestVector>> testVectors = {testVectors_step1, testVectors_step2, testVectors_step3};
|
||||
|
||||
// Act
|
||||
bool result = feedOsnmaWithTestVectors(osnma, testVectors, input_times);
|
||||
ASSERT_TRUE(result);
|
||||
|
||||
// Assert
|
||||
LOG(INFO) << "Successful tags count= " << osnma->d_count_successful_tags;
|
||||
LOG(INFO) << "Failed tags count= " << osnma->d_count_failed_tags;
|
||||
LOG(INFO) << "Unverified tags count= " << osnma->d_tags_awaiting_verify.size();
|
||||
LOG(INFO) << "Failed Kroot count= " << osnma->d_count_failed_Kroot;
|
||||
LOG(INFO) << "Failed PK count= " << osnma->d_count_failed_pubKey;
|
||||
LOG(INFO) << "Failed MACSEQ count= " << osnma->d_count_failed_macseq;
|
||||
ASSERT_EQ(osnma->d_count_failed_tags, 0);
|
||||
ASSERT_EQ(osnma->d_count_failed_Kroot, 0);
|
||||
ASSERT_EQ(osnma->d_count_failed_pubKey, 0);
|
||||
ASSERT_EQ(osnma->d_count_failed_macseq, 0);
|
||||
}
|
||||
|
||||
TEST_F(OsnmaTestVectors, AlertMessage)
|
||||
{
|
||||
// Arrange
|
||||
std::string crtFilePath = std::string(BASE_OSNMA_TEST_VECTORS) + "cryptographic_material/Merkle_tree_3/PublicKey/OSNMA_PublicKey_20231007201500_PKID_1.crt";
|
||||
std::string merkleFilePath = std::string(BASE_OSNMA_TEST_VECTORS) + "cryptographic_material/Merkle_tree_3/MerkleTree/OSNMA_MerkleTree_20231007201500_PKID_1.xml";
|
||||
osnma_msg_receiver_sptr osnma = osnma_msg_receiver_make(crtFilePath, merkleFilePath);
|
||||
|
||||
std::tm input_time_step1 = {0, 45, 18, 7, 10 - 1, 2023 - 1900, 0, 0, 0, 0, 0};
|
||||
std::tm input_time_step2 = {0, 45, 19, 7, 10 - 1, 2023 - 1900, 0, 0, 0, 0, 0};
|
||||
std::vector<std::tm> input_times = {input_time_step1, input_time_step2};
|
||||
|
||||
std::vector<TestVector> testVectors_step1 = readTestVectorsFromFile(std::string(BASE_OSNMA_TEST_VECTORS) + "osnma_test_vectors/oam_step1/07_OCT_2023_GST_18_45_01.csv");
|
||||
std::vector<TestVector> testVectors_step2 = readTestVectorsFromFile(std::string(BASE_OSNMA_TEST_VECTORS) + "osnma_test_vectors/oam_step2/07_OCT_2023_GST_19_45_01.csv");
|
||||
if (testVectors_step1.empty() || testVectors_step2.empty())
|
||||
{
|
||||
ASSERT_TRUE(false);
|
||||
}
|
||||
std::vector<std::vector<TestVector>> testVectors = {testVectors_step1, testVectors_step2};
|
||||
|
||||
// Act
|
||||
bool result = feedOsnmaWithTestVectors(osnma, testVectors, input_times);
|
||||
ASSERT_TRUE(result);
|
||||
|
||||
// Assert
|
||||
LOG(INFO) << "Successful tags count= " << osnma->d_count_successful_tags;
|
||||
LOG(INFO) << "Failed tags count= " << osnma->d_count_failed_tags;
|
||||
LOG(INFO) << "Unverified tags count= " << osnma->d_tags_awaiting_verify.size();
|
||||
LOG(INFO) << "Failed Kroot count= " << osnma->d_count_failed_Kroot;
|
||||
LOG(INFO) << "Failed PK count= " << osnma->d_count_failed_pubKey;
|
||||
LOG(INFO) << "Failed MACSEQ count= " << osnma->d_count_failed_macseq;
|
||||
ASSERT_EQ(osnma->d_count_failed_tags, 0);
|
||||
ASSERT_EQ(osnma->d_count_failed_Kroot, 0);
|
||||
ASSERT_EQ(osnma->d_count_failed_pubKey, 0);
|
||||
ASSERT_EQ(osnma->d_count_failed_macseq, 0);
|
||||
}
|
||||
|
||||
// Auxiliary functions for the OsnmaTestVectorsSimulation test fixture.
|
||||
// Essentially, they perform same work as the telemetry decoder block, but adapted to the osnma-test-vector files.
|
||||
bool OsnmaTestVectors::feedOsnmaWithTestVectors(osnma_msg_receiver_sptr osnma_object, std::vector<std::vector<TestVector>> testVectors, std::vector<std::tm> startTimesFiles)
|
||||
{
|
||||
bool end_of_hex_stream;
|
||||
int offset_byte{0};
|
||||
int byte_index{0}; // index containing the last byte position of the hex stream that was retrieved. Takes advantage that all TVs have same size
|
||||
|
||||
const int DUMMY_PAGE{63};
|
||||
bool flag_dummy_page{false};
|
||||
// Act
|
||||
// loop over all bytes of data. Note: all TestVectors have same amount of data.
|
||||
// if needed, add global flags so that particular logic may be done at certain points in between files
|
||||
for (size_t test_step = 0; test_step < testVectors.size(); test_step++)
|
||||
{
|
||||
// set variables for each file
|
||||
end_of_hex_stream = false;
|
||||
offset_byte = 0;
|
||||
byte_index = 0;
|
||||
set_time(startTimesFiles[test_step]);
|
||||
std::cout << "OsnmaTestVectorsSimulation:"
|
||||
<< " d_GST_SIS= " << d_GST_SIS
|
||||
<< ", TOW=" << TOW
|
||||
<< ", WN=" << WN << std::endl;
|
||||
|
||||
if (test_step == 1 && d_flag_NPK == true)
|
||||
{
|
||||
// step 2: this simulates the osnma connecting to the GSC server and downloading the Merkle tree of the next public key
|
||||
osnma_object->read_merkle_xml(
|
||||
std::string(BASE_OSNMA_TEST_VECTORS) + "cryptographic_material/Merkle_tree_2/MerkleTree/OSNMA_MerkleTree_20231007081500_PKID_8.xml");
|
||||
}
|
||||
|
||||
while (!end_of_hex_stream)
|
||||
{
|
||||
// loop over all SVs, extract a subframe
|
||||
for (const TestVector& tv : testVectors[test_step])
|
||||
{ // loop over all SVs, extract a subframe
|
||||
std::cout << "OsnmaTestVectorsSimulation: SVID (PRN_a) " << tv.svId << std::endl;
|
||||
auto osnmaMsg_sptr = std::make_shared<OSNMA_msg>();
|
||||
std::array<uint8_t, 15> hkroot{};
|
||||
std::array<uint32_t, 15> mack{};
|
||||
byte_index = offset_byte; // reset byte_index to the offset position for the next test vector. Offset is updated at the end of each Subframe (every 30 s or 450 Bytes)
|
||||
std::map<uint8_t, std::bitset<128>> words_for_OSNMA; // structure containing <WORD_NUMBER> and <EXTRACTED_BITS>
|
||||
|
||||
for (int idx = 0; idx < SIZE_SUBFRAME_PAGES; ++idx) // extract all pages of a subframe
|
||||
{
|
||||
// extract bytes of complete page (odd+even) -- extract SIZE_PAGE from tv.navBits, starting from byte_index
|
||||
std::vector<uint8_t> page_bytes = extract_page_bytes(tv, byte_index, SIZE_PAGE_BYTES);
|
||||
if (page_bytes.empty())
|
||||
{
|
||||
std::cout << "OsnmaTestVectorsSimulation: end of TestVectors \n"
|
||||
<< "byte_index=" << byte_index << " expected= " << 432000 / 8 << std::endl;
|
||||
end_of_hex_stream = true;
|
||||
break;
|
||||
}
|
||||
// convert them to bitset representation using bytes_to_string
|
||||
std::string page_bits = bytes_to_str(page_bytes);
|
||||
// Extract the 40 OSNMA bits starting from the 18th bit
|
||||
std::string even_page = page_bits.substr(0, page_bits.size() / 2);
|
||||
std::string odd_page = page_bits.substr(page_bits.size() / 2);
|
||||
if (even_page.size() < 120 || odd_page.size() < 120)
|
||||
{
|
||||
std::cout << "OsnmaTestVectorsSimulation: error parsing pages" << std::endl;
|
||||
}
|
||||
bool even_odd_OK = even_page[0] == '0' && odd_page[0] == '1';
|
||||
bool page_type_OK = even_page[1] == '0' && odd_page[1] == '0';
|
||||
bool tail_bits_OK = even_page.substr(even_page.size() - 6) == "000000" && odd_page.substr(odd_page.size() - 6) == "000000";
|
||||
if (!even_odd_OK || !page_type_OK || !tail_bits_OK)
|
||||
std::cerr << "OsnmaTestVectorsSimulation: error parsing pages." << std::endl;
|
||||
|
||||
std::bitset<112> data_k(even_page.substr(2, 112));
|
||||
std::bitset<16> data_j(odd_page.substr(2, 16));
|
||||
std::bitset<112> shifted_data_k = data_k;
|
||||
uint8_t word_type = static_cast<uint8_t>((shifted_data_k >>= 106).to_ulong()); // word type is the first 6 bits of the word
|
||||
// std::cout << "OsnmaTestVectorsSimulation: received Word " << static_cast<int>(word_type) << std::endl;
|
||||
if ((word_type >= 1 && word_type <= 5) || word_type == 6 || word_type == 10)
|
||||
{
|
||||
// store raw word
|
||||
std::bitset<128> data_combined(data_k.to_string() + data_j.to_string());
|
||||
words_for_OSNMA[word_type] = data_combined;
|
||||
}
|
||||
if (word_type == DUMMY_PAGE)
|
||||
flag_dummy_page = true;
|
||||
|
||||
// place it into osnma object.
|
||||
std::bitset<40> osnmaBits(odd_page.substr(18, 40));
|
||||
|
||||
// Extract bits for hkroot and mack
|
||||
std::bitset<8> hkrootBits(osnmaBits.to_string().substr(0, 8));
|
||||
std::bitset<32> mackBits(osnmaBits.to_string().substr(8, 32));
|
||||
hkroot[idx] = static_cast<uint8_t>(hkrootBits.to_ulong());
|
||||
mack[idx] = static_cast<uint32_t>(mackBits.to_ulong());
|
||||
|
||||
byte_index += SIZE_PAGE_BYTES;
|
||||
}
|
||||
|
||||
// std::cout << "----------" << std::endl;
|
||||
if (end_of_hex_stream)
|
||||
break;
|
||||
if (flag_dummy_page)
|
||||
{
|
||||
flag_dummy_page = false;
|
||||
continue; // skip this SV
|
||||
}
|
||||
|
||||
// Fill osnma object
|
||||
osnmaMsg_sptr->hkroot = hkroot;
|
||||
osnmaMsg_sptr->mack = mack;
|
||||
|
||||
osnmaMsg_sptr->TOW_sf0 = d_GST_SIS & 0x000FFFFF;
|
||||
osnmaMsg_sptr->WN_sf0 = (d_GST_SIS & 0xFFF00000) >> 20;
|
||||
osnmaMsg_sptr->PRN = tv.svId; // PRNa
|
||||
|
||||
// TODO - refactor this logic, currently it is split
|
||||
// check if words_for_OSNMA 1--> 5 words_for_OSNMA are received => fill EphClockStatus data vector
|
||||
bool ephClockStatusWordsReceived = true;
|
||||
for (int i = 1; i <= 5; ++i)
|
||||
{
|
||||
if (words_for_OSNMA.find(i) == words_for_OSNMA.end())
|
||||
{
|
||||
ephClockStatusWordsReceived = false;
|
||||
std::cerr << "OsnmaTestVectorsSimulation: error parsing words_for_OSNMA 1->5. "
|
||||
"Word "
|
||||
<< i << " should be received for each subframe but was not." << std::endl;
|
||||
}
|
||||
}
|
||||
// extract bits as needed by osnma block
|
||||
if (ephClockStatusWordsReceived)
|
||||
{
|
||||
// Define the starting position and length of bits to extract for each word
|
||||
std::map<uint8_t, std::pair<uint8_t, uint8_t>> extractionParams = {
|
||||
{1, {6, 120}},
|
||||
{2, {6, 120}},
|
||||
{3, {6, 122}},
|
||||
{4, {6, 120}},
|
||||
{5, {6, 67}},
|
||||
};
|
||||
|
||||
// Fill NavData bits -- Iterate over the extraction parameters
|
||||
std::string nav_data_ADKD_0_12 = "";
|
||||
for (const auto& param : extractionParams)
|
||||
{
|
||||
uint8_t wordKey = param.first;
|
||||
uint8_t start = param.second.first;
|
||||
uint8_t length = param.second.second;
|
||||
|
||||
// Extract the required bits and fill osnma block
|
||||
nav_data_ADKD_0_12 += words_for_OSNMA[wordKey].to_string().substr(start, length);
|
||||
}
|
||||
// send to osnma block
|
||||
bool check_size_is_ok = nav_data_ADKD_0_12.size() == 549;
|
||||
if (check_size_is_ok)
|
||||
{
|
||||
std::cout << "Galileo OSNMA: sending ADKD=0/12 navData, PRN_d (" << tv.svId << ") "
|
||||
<< "TOW_sf=" << osnmaMsg_sptr->TOW_sf0 << std::endl;
|
||||
const auto tmp_obj_osnma = std::make_shared<std::tuple<uint32_t, std::string, uint32_t>>( // < PRNd , navDataBits, TOW_Sosf>
|
||||
tv.svId,
|
||||
nav_data_ADKD_0_12,
|
||||
osnmaMsg_sptr->TOW_sf0);
|
||||
// LOG(INFO) << "|---> Galileo OSNMA :: Telemetry Decoder NavData (PRN_d=" << static_cast<int>(tv.svId) << ", TOW=" << static_cast<int>(osnmaMsg_sptr->TOW_sf0) << "): 0b" << nav_data_ADKD_0_12;
|
||||
osnma_object->msg_handler_osnma(pmt::make_any(tmp_obj_osnma));
|
||||
}
|
||||
}
|
||||
|
||||
// check w6 && w10 is received => fill TimingData data vector
|
||||
bool timingWordsReceived = words_for_OSNMA.find(6) != words_for_OSNMA.end() &&
|
||||
words_for_OSNMA.find(10) != words_for_OSNMA.end();
|
||||
// extract bits as needed by osnma block
|
||||
if (timingWordsReceived)
|
||||
{
|
||||
// Define the starting position and length of bits to extract for each word
|
||||
std::map<uint8_t, std::pair<uint8_t, uint8_t>> extractionParams = {
|
||||
{6, {6, 99}},
|
||||
{10, {86, 42}}};
|
||||
|
||||
std::string nav_data_ADKD_4 = "";
|
||||
// Fill NavData bits -- Iterate over the extraction parameters
|
||||
for (const auto& param : extractionParams)
|
||||
{
|
||||
uint8_t wordKey = param.first;
|
||||
uint8_t start = param.second.first;
|
||||
uint8_t length = param.second.second;
|
||||
|
||||
// Extract the required bits and fill osnma block
|
||||
nav_data_ADKD_4 += words_for_OSNMA[wordKey].to_string().substr(start, length);
|
||||
}
|
||||
// send to osnma block
|
||||
bool check_size_is_ok = nav_data_ADKD_4.size() == 141;
|
||||
if (check_size_is_ok)
|
||||
{
|
||||
std::cout << "Galileo OSNMA: sending ADKD=04 navData, PRN_d (" << tv.svId << ") "
|
||||
<< "TOW_sf=" << osnmaMsg_sptr->TOW_sf0 << std::endl;
|
||||
const auto tmp_obj_osnma = std::make_shared<std::tuple<uint32_t, std::string, uint32_t>>( // < PRNd , navDataBits, TOW_Sosf>
|
||||
tv.svId,
|
||||
nav_data_ADKD_4,
|
||||
osnmaMsg_sptr->TOW_sf0);
|
||||
// LOG(INFO) << "|---> Galileo OSNMA :: Telemetry Decoder NavData (PRN_d=" << static_cast<int>(tv.svId) << ", TOW=" << static_cast<int>(osnmaMsg_sptr->TOW_sf0) << "): 0b" << nav_data_ADKD_4;
|
||||
osnma_object->msg_handler_osnma(pmt::make_any(tmp_obj_osnma));
|
||||
}
|
||||
}
|
||||
|
||||
// Call the handler, as if it came from telemetry decoder block
|
||||
auto temp_obj = pmt::make_any(osnmaMsg_sptr);
|
||||
|
||||
osnma_object->msg_handler_osnma(temp_obj); // osnma entry point
|
||||
}
|
||||
if (!end_of_hex_stream)
|
||||
{
|
||||
offset_byte = byte_index; // update offset for the next subframe
|
||||
d_GST_SIS += DURATION_SUBFRAME;
|
||||
TOW = d_GST_SIS & 0x000FFFFF;
|
||||
WN = (d_GST_SIS & 0xFFF00000) >> 20;
|
||||
std::cout << "OsnmaTestVectorsSimulation:"
|
||||
<< " d_GST_SIS= " << d_GST_SIS
|
||||
<< ", TOW=" << TOW
|
||||
<< ", WN=" << WN << std::endl;
|
||||
}
|
||||
}
|
||||
if (end_of_hex_stream)
|
||||
continue;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<TestVector> OsnmaTestVectors::readTestVectorsFromFile(const std::string& filename)
|
||||
{
|
||||
std::ifstream file(filename);
|
||||
std::vector<TestVector> testVectors;
|
||||
if (!file.is_open())
|
||||
{
|
||||
std::cerr << "Error reading the file \"" << filename << "\" \n";
|
||||
return testVectors;
|
||||
}
|
||||
|
||||
std::string line;
|
||||
std::getline(file, line);
|
||||
if (line != "SVID,NumNavBits,NavBitsHEX\r")
|
||||
{
|
||||
std::cerr << "Error parsing first line"
|
||||
<< "\n";
|
||||
}
|
||||
|
||||
while (std::getline(file, line))
|
||||
{
|
||||
std::stringstream ss(line);
|
||||
TestVector tv;
|
||||
|
||||
std::string val;
|
||||
|
||||
std::getline(ss, val, ',');
|
||||
tv.svId = std::stoi(val);
|
||||
|
||||
std::getline(ss, val, ',');
|
||||
tv.numNavBits = std::stoi(val);
|
||||
|
||||
std::getline(ss, val, ',');
|
||||
tv.navBits = OsnmaTestVectors::parseNavBits(val);
|
||||
|
||||
testVectors.push_back(tv);
|
||||
}
|
||||
|
||||
return testVectors;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> OsnmaTestVectors::parseNavBits(const std::string& hexadecimal)
|
||||
{
|
||||
std::vector<uint8_t> bytes;
|
||||
|
||||
for (unsigned int i = 0; i < hexadecimal.length() - 1; i += 2)
|
||||
{
|
||||
std::string byteString = hexadecimal.substr(i, 2);
|
||||
uint8_t byte = static_cast<uint8_t>(strtol(byteString.c_str(), nullptr, 16));
|
||||
bytes.push_back(byte);
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
std::string OsnmaTestVectors::bytes_to_str(const std::vector<uint8_t>& bytes)
|
||||
{
|
||||
std::string bit_string;
|
||||
bit_string.reserve(bytes.size() * 8);
|
||||
for (const auto& byte : bytes)
|
||||
{
|
||||
std::bitset<8> bits(byte);
|
||||
bit_string += bits.to_string();
|
||||
}
|
||||
return bit_string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Extracts a range of bytes from a TestVector's navBits vector.
|
||||
*
|
||||
* This function extracts a extracts the bytes of complete page (odd+even)
|
||||
* from the navBits vector of a TestVector object.
|
||||
*
|
||||
*
|
||||
* @param tv The TestVector object from which to extract bytes.
|
||||
* @param byte_index The index of the first byte to extract.
|
||||
* @param num_bytes The number of bytes to extract.
|
||||
* @return A vector containing the extracted bytes, or an empty vector if extraction is not possible.
|
||||
*/
|
||||
std::vector<uint8_t> OsnmaTestVectors::extract_page_bytes(const TestVector& tv, int byte_index, int num_bytes)
|
||||
{
|
||||
// Ensure we don't go beyond the end of tv.navBits
|
||||
int num_bytes_to_extract = std::min(num_bytes, static_cast<int>(tv.navBits.size() - byte_index));
|
||||
|
||||
// If byte_index is beyond the end of tv.navBits, return an empty vector
|
||||
if (num_bytes_to_extract <= 0)
|
||||
{
|
||||
return std::vector<uint8_t>();
|
||||
}
|
||||
|
||||
// Use std::next to get an iterator to the range to extract
|
||||
std::vector<uint8_t> extracted_bytes(tv.navBits.begin() + byte_index, tv.navBits.begin() + byte_index + num_bytes_to_extract);
|
||||
|
||||
return extracted_bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the time based on the given input.
|
||||
*
|
||||
* This function calculates the week number (WN) and time of week (TOW)
|
||||
* based on the input time and the GST_START_EPOCH. It then stores the
|
||||
* calculated values in the WN and TOW member variables. Finally, it
|
||||
* combines the WN and TOW into a single 32-bit value and stores it in
|
||||
* the d_GST_SIS member variable.
|
||||
* \post WN, TOW and GST_SIS are set up based on the input time.
|
||||
*
|
||||
* @param input The input time as a tm struct.
|
||||
*/
|
||||
void OsnmaTestVectors::set_time(std::tm& input)
|
||||
{
|
||||
auto epoch_time_point = std::chrono::system_clock::from_time_t(mktime(&GST_START_EPOCH));
|
||||
auto input_time_point = std::chrono::system_clock::from_time_t(mktime(&input));
|
||||
|
||||
// Get the duration from epoch in seconds
|
||||
auto duration_sec = std::chrono::duration_cast<std::chrono::seconds>(input_time_point - epoch_time_point);
|
||||
|
||||
// Calculate the week number (WN) and time of week (TOW)
|
||||
uint32_t sec_in_week = 7 * 24 * 60 * 60;
|
||||
uint32_t week_number = duration_sec.count() / sec_in_week;
|
||||
uint32_t time_of_week = duration_sec.count() % sec_in_week;
|
||||
this->WN = week_number;
|
||||
this->TOW = time_of_week + LEAP_SECONDS;
|
||||
// Return the week number and time of week as a pair
|
||||
|
||||
// TODO: d_GST_SIS or d_receiver_time? doubt
|
||||
// I am assuming that local realisation of receiver is identical to SIS GST time coming from W5 or W0
|
||||
this->d_GST_SIS = (this->WN & 0x00000FFF) << 20 | (this->TOW & 0x000FFFFF);
|
||||
}
|
Loading…
Reference in New Issue
Block a user