diff --git a/.github/workflows/gnss-sdr_archs.yml b/.github/workflows/gnss-sdr_archs.yml new file mode 100644 index 000000000..8105a6e31 --- /dev/null +++ b/.github/workflows/gnss-sdr_archs.yml @@ -0,0 +1,79 @@ +# SPDX-License-Identifier: GPL-3.0-or-later +# SPDX-FileCopyrightText: 2023 Carles Fernandez-Prades + +name: Run gnss-sdr in non-x86 archs + +on: + push: + branches: + - "**-archs" + - main + workflow_dispatch: + +jobs: + gnss-sdr-non-x86: + runs-on: ubuntu-latest + name: ${{ matrix.distro }} ${{ matrix.arch }} ${{ matrix.compiler.name }} + + # Run steps on a matrix of archs. + strategy: + fail-fast: false + matrix: + include: + - arch: aarch64 + distro: ubuntu22.04 + compiler: { name: g++-12, cc: gcc-12, cxx: g++-12 } + - arch: aarch64 + distro: ubuntu22.04 + compiler: { name: clang-14, cc: clang-14, cxx: clang++-14 } + - arch: armv7 + distro: ubuntu22.04 + compiler: { name: g++-12, cc: gcc-12, cxx: g++-12 } + - arch: ppc64le + distro: ubuntu22.04 + compiler: { name: g++-12, cc: gcc-12, cxx: g++-12 } + - arch: s390x + distro: ubuntu22.04 + compiler: { name: g++-12, cc: gcc-12, cxx: g++-12 } + - arch: riscv64 + distro: ubuntu22.04 + compiler: { name: g++-12, cc: gcc-12, cxx: g++-12 } + + steps: + - uses: actions/checkout@v3.1.0 + - uses: uraimo/run-on-arch-action@v2.5.0 + name: Test in non-x86 container + continue-on-error: ${{ contains(fromJson('["ppc64le", "s390x"]'), matrix.arch) }} + id: test + with: + arch: ${{ matrix.arch }} + distro: ${{ matrix.distro }} + githubToken: ${{ github.token }} # Not required, but speeds up builds + setup: | + mkdir -p "${PWD}/testing" + dockerRunArgs: | + --volume "${PWD}:/gnss-sdr" + env: | + CC: ${{ matrix.compiler.cc }} + CXX: ${{ matrix.compiler.cxx }} + shell: /bin/sh + install: | + apt-get update -q -y + apt-get install -q -y ${{ matrix.compiler.name }} git ninja-build cmake \ + libboost-dev libboost-date-time-dev libboost-system-dev libboost-filesystem-dev \ + libboost-thread-dev libboost-chrono-dev libboost-serialization-dev \ + liblog4cpp5-dev gnuradio-dev gr-osmosdr libpugixml-dev libpcap-dev libblas-dev \ + liblapack-dev libarmadillo-dev libgflags-dev libgoogle-glog-dev \ + libgnutls-openssl-dev libmatio-dev googletest protobuf-compiler libprotobuf-dev \ + python3-mako liborc-0.4-dev + run: | + git config --global --add safe.directory /gnss-sdr + cd /gnss-sdr + cd testing + mkdir install + cmake -DENABLE_SYSTEM_TESTING_EXTRA=ON -DCMAKE_INSTALL_PREFIX=/gnss-sdr/testing/install -DENABLE_INSTALL_TESTS=ON .. + echo "Build with $(nproc) thread(s)" + make -j$(nproc) + make install + cd install/bin + ./position_test diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 53d92ec6f..d25e7b2ff 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -9,6 +9,7 @@ on: push: paths-ignore: - "**/CITATION.cff" + workflow_dispatch: jobs: build-ubuntu: @@ -113,7 +114,7 @@ jobs: ln -s $(brew --prefix llvm)/bin/clang-apply-replacements /usr/local/bin ln -s $(brew --prefix llvm)/bin/run-clang-tidy /usr/local/bin - name: Prepare run - run: cd build && cmake .. && make volk_gnsssdr_module gtest-1.12.1 core_monitor core_libs pvt_libs + run: cd build && cmake .. && make volk_gnsssdr_module gtest-1.13.0 core_monitor core_libs pvt_libs - name: run clang-tidy run: cd build && run-clang-tidy -fix - name: check diff --git a/.github/workflows/volk_android.yml b/.github/workflows/volk_gnsssdr_android.yml similarity index 96% rename from .github/workflows/volk_android.yml rename to .github/workflows/volk_gnsssdr_android.yml index 5e466d224..69a04edfc 100644 --- a/.github/workflows/volk_android.yml +++ b/.github/workflows/volk_gnsssdr_android.yml @@ -4,12 +4,14 @@ on: push: paths: - "src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/**" + - "CMakeLists.txt" pull_request: paths: - "src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/**" + - "CMakeLists.txt" workflow_dispatch: -name: Build volk-gnssdr on Android NDK +name: Build volk_gnsssdr on Android NDK jobs: build: name: Build on Android NDK ${{ matrix.arch.name }} diff --git a/.github/workflows/volk_gnsssdr_archs.yml b/.github/workflows/volk_gnsssdr_archs.yml new file mode 100644 index 000000000..a40c1c163 --- /dev/null +++ b/.github/workflows/volk_gnsssdr_archs.yml @@ -0,0 +1,80 @@ +# SPDX-License-Identifier: GPL-3.0-or-later +# SPDX-FileCopyrightText: 2023 Carles Fernandez-Prades + +name: Run volk_gnsssdr tests + +on: + push: + paths: + - "src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/**" + - "CMakeLists.txt" + pull_request: + paths: + - "src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/**" + - "CMakeLists.txt" + workflow_dispatch: + +jobs: + build-ubuntu-non-x86: + runs-on: ubuntu-latest + name: ${{ matrix.distro }} ${{ matrix.arch }} ${{ matrix.compiler.name }} + + # Run steps on a matrix of archs. + strategy: + fail-fast: false + matrix: + include: + - arch: aarch64 + distro: ubuntu22.04 + compiler: { name: g++-12, cc: gcc-12, cxx: g++-12 } + - arch: aarch64 + distro: ubuntu22.04 + compiler: { name: clang-14, cc: clang-14, cxx: clang++-14 } + - arch: armv7 + distro: ubuntu22.04 + compiler: { name: g++-12, cc: gcc-12, cxx: g++-12 } + - arch: ppc64le + distro: ubuntu22.04 + compiler: { name: g++-12, cc: gcc-12, cxx: g++-12 } + - arch: s390x + distro: ubuntu22.04 + compiler: { name: g++-12, cc: gcc-12, cxx: g++-12 } + - arch: riscv64 + distro: ubuntu22.04 + compiler: { name: g++-12, cc: gcc-12, cxx: g++-12 } + + steps: + - uses: actions/checkout@v3.1.0 + - uses: uraimo/run-on-arch-action@v2.5.0 + name: Build in non-x86 container + # continue-on-error: ${{ contains(fromJson('["ppc64le", "s390x"]'), matrix.arch) }} + id: build + with: + arch: ${{ matrix.arch }} + distro: ${{ matrix.distro }} + githubToken: ${{ github.token }} # Not required, but speeds up builds + setup: | + mkdir -p "${PWD}/testing" + dockerRunArgs: | + --volume "${PWD}:/volk_gnsssdr" + env: | + CC: ${{ matrix.compiler.cc }} + CXX: ${{ matrix.compiler.cxx }} + shell: /bin/sh + install: | + apt-get update -q -y + apt-get install -q -y git cmake python3-mako liborc-dev ${{ matrix.compiler.name }} + run: | + git config --global --add safe.directory /volk_gnsssdr + cd /volk_gnsssdr + cd testing + cmake ../src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/ + echo "Build with $(nproc) thread(s)" + make -j$(nproc) + ./cpu_features/list_cpu_features + ./apps/volk_gnsssdr-config-info --alignment + ./apps/volk_gnsssdr-config-info --avail-machines + ./apps/volk_gnsssdr-config-info --all-machines + ./apps/volk_gnsssdr-config-info --malloc + ./apps/volk_gnsssdr-config-info --cc + ctest -V diff --git a/CMakeLists.txt b/CMakeLists.txt index 33d27e6dd..2222702cd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,7 +48,7 @@ option(ENABLE_FLEXIBAND "Enable the use of the signal source adater for the Tele option(ENABLE_ARRAY "Enable the use of CTTC's antenna array front-end as signal source (experimental)" OFF) -option(ENABLE_ZMQ "Enable GNU Radio ZeroMQ Messaging, requires gr-zeromq" OFF) +option(ENABLE_ZMQ "Enable GNU Radio ZeroMQ Messaging, requires gr-zeromq" ON) # Performance analysis tools option(ENABLE_GPERFTOOLS "Enable linking to Gperftools libraries (tcmalloc and profiler)" OFF) @@ -68,8 +68,6 @@ option(ENABLE_CUDA "Enable building of processing blocks implemented with CUDA ( option(ENABLE_FPGA "Enable building of processing blocks implementing FPGA offloading" OFF) # Building and packaging options -option(ENABLE_GENERIC_ARCH "Builds a portable binary" OFF) - option(ENABLE_PACKAGING "Enable software packaging" OFF) option(ENABLE_OWN_GLOG "Download glog and link it to gflags" OFF) @@ -85,7 +83,6 @@ option(ENABLE_STRIP "Create stripped binaries without debugging symbols (in Rele option(Boost_USE_STATIC_LIBS "Use Boost static libs" OFF) if(ENABLE_PACKAGING) - set(ENABLE_GENERIC_ARCH ON) set(ENABLE_ARMA_NO_DEBUG ON) set(CMAKE_VERBOSE_MAKEFILE ON) set(ENABLE_STRIP OFF) @@ -344,7 +341,7 @@ if((CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_ CMAKE_VERSION VERSION_LESS 3.5) set(GNSSSDR_GTEST_LOCAL_VERSION "1.10.x") else() - set(GNSSSDR_GTEST_LOCAL_VERSION "1.12.1") + set(GNSSSDR_GTEST_LOCAL_VERSION "1.13.0") endif() set(GNSSSDR_GNSS_SIM_LOCAL_VERSION "master") if(CMAKE_VERSION VERSION_GREATER 3.17.0) @@ -442,7 +439,6 @@ endif() - ################################################################################ # Set minimal C and C++ standards ################################################################################ @@ -501,23 +497,19 @@ endif() ################################################################################ # Check if the compiler defines the architecture as ARM ################################################################################ +if(CMAKE_SYSTEM_PROCESSOR MATCHES "(^arm)|(^aarch64)") + set(IS_ARM TRUE) +endif() if(NOT (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")) if(CMAKE_CROSSCOMPILING) - set(IS_ARM TRUE) if(NOT CMAKE_NO_SYSTEM_FROM_IMPORTED) set(CMAKE_NO_SYSTEM_FROM_IMPORTED TRUE) endif() - else() - if(NOT IS_ARM) - include(TestForARM) - endif() - endif() -else() - if(CMAKE_SYSTEM_PROCESSOR MATCHES "(^aarch64)|(arm64)") - set(IS_ARM TRUE) endif() endif() + + ################################################################################ # pkg-config - Helper tool used when compiling applications and libraries. ################################################################################ @@ -526,6 +518,7 @@ set(FPHSA_NAME_MISMATCHED ON) find_package(PkgConfig) + ################################################################################ # Find the POSIX thread (pthread) libraries ################################################################################ @@ -620,8 +613,17 @@ if(ENABLE_UHD) endif() endif() +find_package(ZEROMQ) +set_package_properties(ZEROMQ PROPERTIES + PURPOSE "Used by the ZMQ_Signal_Source." + TYPE OPTIONAL +) if(ENABLE_ZMQ) - list(APPEND GR_REQUIRED_COMPONENTS ZEROMQ) + if(NOT ZEROMQ_FOUND) + set(ENABLE_ZMQ OFF) + else() + list(APPEND GR_REQUIRED_COMPONENTS ZEROMQ) + endif() endif() find_package(GNURADIO) @@ -1193,7 +1195,7 @@ if(NOT VOLKGNSSSDR_FOUND) include(GNUInstallDirs) set(SUPPORTED_CPU_FEATURES_ARCH FALSE) if(CMAKE_SYSTEM_PROCESSOR MATCHES - "(^mips)|(^arm)|(^aarch64)|(x86_64)|(AMD64|amd64)|(^i.86$)|(^powerpc)|(^ppc)|(^s390x)") + "(^mips)|(^arm)|(^aarch64)|(x86_64)|(AMD64|amd64)|(^i.86$)|(^powerpc)|(^ppc)|(^s390x)|^riscv") set(SUPPORTED_CPU_FEATURES_ARCH TRUE) endif() if(${CMAKE_INSTALL_LIBDIR} MATCHES lib64) @@ -1232,11 +1234,14 @@ if(NOT VOLKGNSSSDR_FOUND) set_package_properties(CPUFEATURES PROPERTIES DESCRIPTION "A cross platform C99 library to get CPU features at runtime (version: ${CPUFEATURES_VERSION})" ) + if((CMAKE_SYSTEM_PROCESSOR MATCHES "(^s390x)|^riscv") AND (CPUFEATURES_VERSION VERSION_LESS "0.8.0")) # detect cpu_features without s390x / riscv support + set(ENABLE_CPUFEATURES OFF) + endif() else() set_package_properties(CPUFEATURES PROPERTIES DESCRIPTION "A cross platform C99 library to get CPU features at runtime" ) - if(VOLK_VERSION AND VOLK_VERSION VERSION_GREATER "2.3" AND VOLK_VERSION VERSION_LESS "2.5.2") # detect "hidden" cpu_features 0.6.0 + if(DEFINED VOLK_VERSION AND VOLK_VERSION VERSION_GREATER "2.3") # avoid clash with volk's cpufeatures. set(ENABLE_CPUFEATURES OFF) else() set_package_properties(CPUFEATURES PROPERTIES @@ -1805,6 +1810,9 @@ else() if(NOT BLA_VENDOR) set(BLA_VENDOR "Generic") endif() + if(NOT CMAKE_CROSSCOMPILING AND NOT DEFINED BLA_PREFER_PKGCONFIG) + set(BLA_PREFER_PKGCONFIG ON) # Required by riscv64 arch + endif() find_package(BLAS) set_package_properties(BLAS PROPERTIES URL "https://www.netlib.org/blas/" @@ -2903,9 +2911,9 @@ if(ENABLE_OPENCL) message(STATUS " You can disable OpenCL use by doing 'cmake -DENABLE_OPENCL=OFF ..'") endif() endif() - if(ENABLE_GENERIC_ARCH) + if(ENABLE_PACKAGING) set(ENABLE_OPENCL OFF) - message(STATUS "ENABLE_GENERIC_ARCH is set to ON so the use of OpenCL has been disabled.") + message(STATUS "ENABLE_PACKAGING is set to ON so the use of OpenCL has been disabled.") endif() if(NOT OPENCL_FOUND) message(STATUS "Processing blocks using OpenCL will not be built.") @@ -3282,36 +3290,6 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") endif() endif() -# Processor-architecture related flags -# See https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html -if((CMAKE_CXX_COMPILER_ID STREQUAL "GNU") AND NOT WIN32) - if(NOT ENABLE_GENERIC_ARCH) - if(IS_ARM) - # ARM-specific options - # See https://gcc.gnu.org/onlinedocs/gcc/ARM-Options.html - if(NOT CMAKE_CROSSCOMPILING AND NOT CMAKE_TOOLCHAIN_FILE) - add_compile_options(-mtune=native) - endif() - else() - if(NOT ENABLE_CUDA) - add_compile_options(-march=native) - endif() - endif() - endif() -endif() -if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") - if(NOT ENABLE_GENERIC_ARCH) - if(IS_ARM) - # ARM-specific options - if(NOT CMAKE_CROSSCOMPILING AND NOT CMAKE_TOOLCHAIN_FILE) - add_compile_options(-mcpu=native) - endif() - else() - add_compile_options(-march=native) - endif() - endif() -endif() - ################################################################################ @@ -3384,7 +3362,6 @@ add_feature_info(ENABLE_OPENCL ENABLE_OPENCL "Enables GPS_L1_CA_PCPS_OpenCl_Acqu add_feature_info(ENABLE_CUDA ENABLE_CUDA "Enables GPS_L1_CA_DLL_PLL_Tracking_GPU (experimental). Requires CUDA.") add_feature_info(ENABLE_FPGA ENABLE_FPGA "Enables building of processing blocks for FPGA offloading.") add_feature_info(ENABLE_ARMA_NO_DEBUG ENABLE_ARMA_NO_DEBUG "Enables passing the ARMA_NO_DEBUG macro to Armadillo, hence disabling bound checking.") -add_feature_info(ENABLE_GENERIC_ARCH ENABLE_GENERIC_ARCH "When disabled, flags such as '-march=native' are passed to the compiler.") add_feature_info(ENABLE_PACKAGING ENABLE_PACKAGING "Enables software packaging.") add_feature_info(ENABLE_OWN_GLOG ENABLE_OWN_GLOG "Forces the downloading and building of Google glog.") add_feature_info(ENABLE_OWN_ARMADILLO ENABLE_OWN_ARMADILLO "Forces the downloading and building of Armadillo.") diff --git a/README.md b/README.md index 9fa4c0ecd..d3461edfb 100644 --- a/README.md +++ b/README.md @@ -64,11 +64,12 @@ information about this open-source, software-defined GNSS receiver. 1. [GNU/Linux](#gnulinux) 1. [Alternative 1: Install dependencies using software packages](#alternative-1-install-dependencies-using-software-packages) 1. [Debian / Ubuntu](#debian--ubuntu) - 2. [Arch Linux](#arch-linux) - 3. [CentOS](#centos) - 4. [Fedora](#fedora) - 5. [openSUSE](#opensuse) - 6. [Rocky Linux](#rocky-linux) + 2. [AlmaLinux](#almalinux) + 3. [Arch Linux](#arch-linux) + 4. [CentOS](#centos) + 5. [Fedora](#fedora) + 6. [openSUSE](#opensuse) + 7. [Rocky Linux](#rocky-linux) 2. [Alternative 2: Install dependencies using PyBOMBS](#alternative-2-install-dependencies-using-pybombs) 3. [Manual installation of other required dependencies](#manual-installation-of-other-required-dependencies) 1. [Install Armadillo, a C++ linear algebra library](#install-armadillo-a-c-linear-algebra-library) @@ -85,7 +86,6 @@ information about this open-source, software-defined GNSS receiver. 2. [Build FMCOMMS2 based SDR Hardware support (OPTIONAL)](#build-fmcomms2-based-sdr-hardware-support-optional) 3. [Build OpenCL support (OPTIONAL)](#build-opencl-support-optional) 4. [Build CUDA support (OPTIONAL)](#build-cuda-support-optional) - 5. [Build a portable binary](#build-a-portable-binary) 2. [macOS](#macos) 1. [Macports](#macports) 2. [Homebrew](#homebrew) @@ -142,6 +142,7 @@ This section describes how to set up the compilation environment in GNU/Linux or Motorola (now Freescale), and Apple. - ppc64: 64-bit big-endian PowerPC architecture. - ppc64el: 64-bit little-endian PowerPC architecture. + - riscv64: 64-bit RISC-V open standard instruction set architecture. - s390x: IBM System z architecture for mainframe computers. Older distribution releases might work as well, but you will need GCC 4.7 or @@ -201,6 +202,26 @@ need `python-six`. Once you have installed these packages, you can jump directly to [download the source code and build GNSS-SDR](#clone-gnss-sdrs-git-repository). +#### AlmaLinux + +If you are using AlmaLinux: + +``` +# dnf update -y +# dnf install -y 'dnf-command(config-manager)' +# dnf config-manager --set-enabled powertools +# dnf install -y epel-release +# dnf install -y make gcc gcc-c++ kernel-devel cmake git boost-devel \ + boost-date-time boost-system boost-thread boost-chrono \ + boost-serialization log4cpp-devel gmp-devel uhd-devel gnuradio-devel \ + pugixml-devel matio-devel protobuf-devel glog-devel libpcap-devel \ + blas-devel lapack-devel armadillo-devel openssl-devel python3-mako \ + libarchive +``` + +Once you have installed these packages, you can jump directly to +[download the source code and build GNSS-SDR](#clone-gnss-sdrs-git-repository). + #### Arch Linux If you are using Arch Linux: @@ -496,8 +517,8 @@ $ sudo ldconfig #### Download [GoogleTest](https://github.com/google/googletest "Googletest Homepage") ``` -$ wget https://github.com/google/googletest/archive/release-1.12.1.zip -$ unzip release-1.12.1.zip +$ wget https://github.com/google/googletest/archive/refs/tags/v1.13.0.zip +$ unzip v1.13.0.zip ``` Please **DO NOT build or install** Google Test. Every user needs to compile @@ -521,10 +542,10 @@ downloaded resides. Just type in your terminal (or add it to your `$HOME/.bashrc` file for a permanent solution) the following line: ``` -export GTEST_DIR=/home/username/googletest-release-1.12.1 +export GTEST_DIR=/home/username/googletest-1.13.0 ``` -changing `/home/username/googletest-release-1.12.1` by the actual path where you +changing `/home/username/googletest-1.13.0` by the actual path where you unpacked Google Test. If the CMake script does not find that folder, or the environment variable is not defined, or the source code is not installed by a package, then it will download a fresh copy of the Google Test source code and @@ -790,26 +811,6 @@ $ sudo make install Of course, you will also need a GPU that [supports CUDA](https://developer.nvidia.com/cuda-gpus "CUDA GPUs"). -#### Build a portable binary - -In order to build an executable that not depends on the specific SIMD -instruction set that is present in the processor of the compiling machine, so -other users can execute it in other machines without those particular sets, use: - -``` -$ cmake -DENABLE_GENERIC_ARCH=ON .. -$ make -$ sudo make install -``` - -Using this option, all SIMD instructions are exclusively accessed via VOLK, -which automatically includes versions of each function for different SIMD -instruction sets, then detects at runtime which to use, or if there are none, -substitutes a generic, non-SIMD implementation. - -More details can be found in our tutorial about -[GNSS-SDR configuration options at building time](https://gnss-sdr.org/docs/tutorials/using-git/ "Configuration options at building time"). - ## macOS GNSS-SDR can be built on macOS (or the former Mac OS X), starting from 10.9 diff --git a/cmake/Modules/FindGFORTRAN.cmake b/cmake/Modules/FindGFORTRAN.cmake index 13984295f..5e4d2885d 100644 --- a/cmake/Modules/FindGFORTRAN.cmake +++ b/cmake/Modules/FindGFORTRAN.cmake @@ -20,7 +20,7 @@ if(DEFINED ENV{GFORTRAN_ROOT}) ) endif() -set(GCC_MAJOR_SERIES 12 11 10 9 8 7 6 5) +set(GCC_MAJOR_SERIES 13 12 11 10 9 8 7 6 5) set(GCC4_SERIES 4.9.1 4.9 4.8.3 4.8.1 4.7.2 4.7 4.8.2 4.8 4.7 4.6 4.5 4.4.4 4.4) set(GCC_SERIES ${GCC_MAJOR_SERIES} ${GCC4_SERIES}) diff --git a/cmake/Modules/FindZEROMQ.cmake b/cmake/Modules/FindZEROMQ.cmake new file mode 100644 index 000000000..0ef937139 --- /dev/null +++ b/cmake/Modules/FindZEROMQ.cmake @@ -0,0 +1,82 @@ +# GNSS-SDR is a Global Navigation Satellite System software-defined receiver. +# This file is part of GNSS-SDR. +# +# SPDX-FileCopyrightText: 2023 C. Fernandez-Prades cfernandez(at)cttc.es +# SPDX-License-Identifier: BSD-3-Clause + +# +# Provides the following imported target: +# ZeroMQ::ZeroMQ +# + +if(NOT COMMAND feature_summary) + include(FeatureSummary) +endif() + +if(NOT PKG_CONFIG_FOUND) + include(FindPkgConfig) +endif() + +find_package(PkgConfig) +pkg_check_modules(PC_ZEROMQ "libzmq") + +find_path(ZEROMQ_INCLUDE_DIRS + NAMES zmq.hpp + HINTS ${PC_ZEROMQ_INCLUDE_DIR} ${CMAKE_INSTALL_PREFIX}/include + PATHS /usr/local/include /usr/include /opt/local/include +) + +find_library(ZEROMQ_LIBRARIES + NAMES zmq libzmq.so.5 ${ZEROMQ_LIBRARY_NAME} + HINTS ${PC_ZEROMQ_LIBDIR} ${CMAKE_INSTALL_PREFIX}/lib ${CMAKE_INSTALL_PREFIX}/lib64 + PATHS /usr/lib + /usr/lib64 + /usr/lib/alpha-linux-gnu + /usr/lib/x86_64-linux-gnu + /usr/lib/aarch64-linux-gnu + /usr/lib/arm-linux-gnueabi + /usr/lib/arm-linux-gnueabihf + /usr/lib/hppa-linux-gnu + /usr/lib/i386-linux-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-gnuspe + /usr/lib/powerpc64-linux-gnu + /usr/lib/powerpc64le-linux-gnu + /usr/lib/riscv64-linux-gnu + /usr/lib/s390x-linux-gnu + /usr/lib/sh4-linux-gnu + /usr/lib/sparc64-linux-gnu + /usr/lib/x86_64-linux-gnux32 + /usr/lib/x86_64-kfreebsd-gnu + /usr/lib/i386-kfreebsd-gnu + /usr/local/lib + /usr/local/lib64 + /opt/local/lib +) + +include(FindPackageHandleStandardArgs) +# This is just to detect presence, include files not required +find_package_handle_standard_args(ZEROMQ DEFAULT_MSG ZEROMQ_LIBRARIES) +mark_as_advanced(ZEROMQ_LIBRARIES ZEROMQ_INCLUDE_DIRS) + +set_package_properties(ZEROMQ PROPERTIES URL "https://zeromq.org/") +if(PC_ZEROMQ_VERSION) + set_package_properties(ZEROMQ PROPERTIES + DESCRIPTION "An open-source universal messaging library (found: v${PC_ZEROMQ_VERSION})" + ) +else() + set_package_properties(ZEROMQ PROPERTIES + DESCRIPTION "An open-source universal messaging library" + ) +endif() + +if(ZEROMQ_FOUND AND ZEROMQ_INCLUDE_DIRS AND NOT TARGET ZeroMQ::ZeroMQ) + add_library(ZeroMQ::ZeroMQ INTERFACE IMPORTED) + set_target_properties(ZeroMQ::ZeroMQ PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${ZEROMQ_INCLUDE_DIRS}" + INTERFACE_LINK_LIBRARIES "${ZEROMQ_LIBRARIES}" + ) +endif() \ No newline at end of file diff --git a/cmake/Modules/SetupPython.cmake b/cmake/Modules/SetupPython.cmake index 396849e9c..2260357ce 100644 --- a/cmake/Modules/SetupPython.cmake +++ b/cmake/Modules/SetupPython.cmake @@ -12,13 +12,22 @@ # - cmd an additional command to run # - have the result variable to set ######################################################################## -macro(GNSSSDR_PYTHON_CHECK_MODULE_RAW desc python_code have) +macro(GNSSSDR_PYTHON_CHECK_MODULE desc mod cmd have) + message(STATUS "Python checking for ${desc}") execute_process( - COMMAND ${PYTHON_EXECUTABLE} -c "${python_code}" + COMMAND ${PYTHON_EXECUTABLE} -c " +######################################### +try: import ${mod} +except: + try: ${mod} + except: exit(-1) +try: assert ${cmd} +except: exit(-1) +#########################################" OUTPUT_QUIET ERROR_QUIET - RESULT_VARIABLE return_code + RESULT_VARIABLE ${have} ) - if(return_code EQUAL 0) + if(${have} EQUAL 0) message(STATUS "Python checking for ${desc} - found") set(${have} TRUE) else() @@ -27,19 +36,6 @@ macro(GNSSSDR_PYTHON_CHECK_MODULE_RAW desc python_code have) endif() endmacro() -macro(GNSSSDR_PYTHON_CHECK_MODULE desc mod cmd have) - gnsssdr_python_check_module_raw( - "${desc}" " -######################################### -try: - import ${mod} - assert ${cmd} -except (ImportError, AssertionError): exit(-1) -except: pass -#########################################" - "${have}") -endmacro() - ######################################################################## # Setup the python interpreter: diff --git a/cmake/Modules/TestForARM.cmake b/cmake/Modules/TestForARM.cmake deleted file mode 100644 index 9cd248f34..000000000 --- a/cmake/Modules/TestForARM.cmake +++ /dev/null @@ -1,115 +0,0 @@ -# GNSS-SDR is a Global Navigation Satellite System software-defined receiver. -# This file is part of GNSS-SDR. -# -# SPDX-FileCopyrightText: 2011-2020 C. Fernandez-Prades cfernandez(at)cttc.es -# SPDX-License-Identifier: BSD-3-Clause - -############################################################################## -# check if the compiler defines the architecture as ARM and set the -# version, if found. -# -# - Anthony Arnold -############################################################################## - -if(__TEST_FOR_ARM_INCLUDED) - return() -endif() -set(__TEST_FOR_ARM_INCLUDED TRUE) - -# Function checks if the input string defines ARM version and sets the -# output variable if found. -function(check_arm_version ppdef input_string version output_var) - string(REGEX MATCH "${ppdef}" _VERSION_MATCH "${input_string}") - if(NOT _VERSION_MATCH STREQUAL "") - set(${output_var} "${version}" PARENT_SCOPE) - endif() -endfunction() - -message(STATUS "Checking for ARM") - -set(IS_ARM FALSE) -set(ARM_VERSION "") - -if(ENABLE_PACKAGING) - set(VERBOSE_BUILDING "-v") -else() - set(VERBOSE_BUILDING "") -endif() - -if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - execute_process(COMMAND echo "int main(){}" - COMMAND ${CMAKE_CXX_COMPILER} ${CMAKE_CXX_COMPILER_ARG1} -dM ${VERBOSE_BUILDING} -E - - OUTPUT_VARIABLE TEST_FOR_ARM_RESULTS - ) - - string(REGEX MATCH "__arm" ARM_FOUND "${TEST_FOR_ARM_RESULTS}") - if(ARM_FOUND STREQUAL "") - string(REGEX MATCH "__aarch64" ARM_FOUND "${TEST_FOR_ARM_RESULTS}") - endif() - if(ARM_FOUND STREQUAL "") - if(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "arm") - set(ARM_FOUND ${CMAKE_HOST_SYSTEM_PROCESSOR}) - endif() - endif() - - if(NOT ARM_FOUND STREQUAL "") - set(IS_ARM TRUE) - message(STATUS "ARM system detected.") - - # detect the version - check_arm_version("__ARM_ARCH_2__" ${TEST_FOR_ARM_RESULTS} "armv2" ARM_VERSION) - check_arm_version("__ARM_ARCH_2A__" ${TEST_FOR_ARM_RESULTS} "armv2a" ARM_VERSION) - check_arm_version("__ARM_ARCH_3__" ${TEST_FOR_ARM_RESULTS} "armv3" ARM_VERSION) - check_arm_version("__ARM_ARCH_3M__" ${TEST_FOR_ARM_RESULTS} "armv3m" ARM_VERSION) - check_arm_version("__ARM_ARCH_4__" ${TEST_FOR_ARM_RESULTS} "armv4" ARM_VERSION) - check_arm_version("__ARM_ARCH_4T__" ${TEST_FOR_ARM_RESULTS} "armv4t" ARM_VERSION) - check_arm_version("__ARM_ARCH_5__" ${TEST_FOR_ARM_RESULTS} "armv5" ARM_VERSION) - check_arm_version("__ARM_ARCH_5T__" ${TEST_FOR_ARM_RESULTS} "armv5t" ARM_VERSION) - check_arm_version("__ARM_ARCH_5E__" ${TEST_FOR_ARM_RESULTS} "armv5e" ARM_VERSION) - check_arm_version("__ARM_ARCH_5TE__" ${TEST_FOR_ARM_RESULTS} "armv5te" ARM_VERSION) - check_arm_version("__ARM_ARCH_6__" ${TEST_FOR_ARM_RESULTS} "armv6" ARM_VERSION) - check_arm_version("__ARM_ARCH_6J__" ${TEST_FOR_ARM_RESULTS} "armv6j" ARM_VERSION) - check_arm_version("__ARM_ARCH_6K__" ${TEST_FOR_ARM_RESULTS} "armv6k" ARM_VERSION) - check_arm_version("__ARM_ARCH_6T2__" ${TEST_FOR_ARM_RESULTS} "armv6t2" ARM_VERSION) - check_arm_version("__ARM_ARCH_6Z__" ${TEST_FOR_ARM_RESULTS} "armv6z" ARM_VERSION) - check_arm_version("__ARM_ARCH_6ZK__" ${TEST_FOR_ARM_RESULTS} "armv6zk" ARM_VERSION) - check_arm_version("__ARM_ARCH_6M__" ${TEST_FOR_ARM_RESULTS} "armv6-m" ARM_VERSION) - check_arm_version("__ARM_ARCH_7__" ${TEST_FOR_ARM_RESULTS} "armv7" ARM_VERSION) - check_arm_version("__ARM_ARCH_7A__" ${TEST_FOR_ARM_RESULTS} "armv7-a" ARM_VERSION) - check_arm_version("__ARM_ARCH_7M__" ${TEST_FOR_ARM_RESULTS} "armv7-m" ARM_VERSION) - check_arm_version("__ARM_ARCH_7R__" ${TEST_FOR_ARM_RESULTS} "armv7-r" ARM_VERSION) - check_arm_version("__ARM_ARCH_7EM_" ${TEST_FOR_ARM_RESULTS} "armv7e-m" ARM_VERSION) - check_arm_version("__ARM_ARCH_7VE__" ${TEST_FOR_ARM_RESULTS} "armv7ve" ARM_VERSION) - check_arm_version("__ARM_ARCH_8A__" ${TEST_FOR_ARM_RESULTS} "armv8-a" ARM_VERSION) - check_arm_version("__ARM_ARCH_8A" ${TEST_FOR_ARM_RESULTS} "armv8-a" ARM_VERSION) - - # anything else just define as unknown - if(ARM_VERSION STREQUAL "") - message(STATUS "Couldn't detect ARM version.") - set(ARM_VERSION "unknown") - else() - message(STATUS "ARM version ${ARM_VERSION} detected.") - endif() - else() - message(STATUS "System is not ARM.") - endif() -elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") - if(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "arm") - set(IS_ARM TRUE) - set(ARM_VERSION ${CMAKE_HOST_SYSTEM_PROCESSOR}) - message(STATUS "ARM version ${ARM_VERSION} detected.") - endif() -elseif(CMAKE_CXX_COMPILER_ID STREQUAL "ARMClang") - set(IS_ARM TRUE) - set(ARM_VERSION "arm") - if(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "arm") - set(ARM_VERSION ${CMAKE_HOST_SYSTEM_PROCESSOR}) - message(STATUS "ARM version ${ARM_VERSION} detected.") - endif() -else() - message(STATUS "Not detecting ARM on non-GNUCXX or non-Clang compiler. Defaulting to false.") - message(STATUS "If you are compiling for ARM, set -DIS_ARM=ON manually.") -endif() - -set(IS_ARM ${IS_ARM} CACHE BOOL "Compiling for ARM") -set(ARM_VERSION ${ARM_VERSION} CACHE STRING "ARM version") diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index b60c87ddc..fafe79b12 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -14,6 +14,15 @@ All notable changes to GNSS-SDR will be documented in this file. ## [Unreleased](https://github.com/gnss-sdr/gnss-sdr/tree/next) +### Improvements in Accuracy: + +- Processing and application of the corrections provided by the Galileo High + Accuracy Service (HAS) to the PVT solution. It requires at least a Galileo E1 + (or E5a) + Galileo E6B configuration. A new configuration parameter + `PVT.use_has_corrections`, set to `true` by default, can be used to deactivate + the application of HAS corrections but still retrieve the HAS data if set to + `false`. + ### Improvements in Availability: - Fixed bug that made the PVT block to not resolve position anymore after a loss @@ -70,11 +79,14 @@ All notable changes to GNSS-SDR will be documented in this file. - Improved passing of compiler flags to `volk_gnsssdr` if the corresponding environment variables are defined. This fixes warnings in some packaging systems. +- Improved support for the RISC-V architecture. - Test files are now donwloaded at configuration time instead of being included in the source tree. This allows for a smaller package and fixes Lintian `very-long-line-length-in-source-file` warnings since those files were not recognized as binaries. The configuration flag `-DENABLE_PACKAGING=ON` passed to CMake deactivates file downloading. +- The `ENABLE_GENERIC_ARCH` building option was removed, simplifying the process + of buiding the software in non-x86 processor architectures. ### Improvements in Usability: @@ -96,6 +108,9 @@ All notable changes to GNSS-SDR will be documented in this file. manually set the bandwidth of the bandpass filter on the radio frontend. - The new configuration parameter `Channels_XX.RF_channel_ID` allows to specify the signal source per channel group. +- New configuration parameter `PVT.use_unhealthy_sats`, set by default to + `false`, allows processing observables of satellites that report an unhealthy + status in the navigation message if set to `true`. - Allowed the CMake project to be a sub-project. See the definitions of concepts and metrics at diff --git a/src/algorithms/PVT/adapters/rtklib_pvt.cc b/src/algorithms/PVT/adapters/rtklib_pvt.cc index abb17567f..ce1f25173 100644 --- a/src/algorithms/PVT/adapters/rtklib_pvt.cc +++ b/src/algorithms/PVT/adapters/rtklib_pvt.cc @@ -878,6 +878,10 @@ Rtklib_Pvt::Rtklib_Pvt(const ConfigurationInterface* configuration, // Use E6 for PVT pvt_output_parameters.use_e6_for_pvt = configuration->property(role + ".use_e6_for_pvt", pvt_output_parameters.use_e6_for_pvt); + pvt_output_parameters.use_has_corrections = configuration->property(role + ".use_has_corrections", pvt_output_parameters.use_has_corrections); + + // Use unhealthy satellites + pvt_output_parameters.use_unhealthy_sats = configuration->property(role + ".use_unhealthy_sats", pvt_output_parameters.use_unhealthy_sats); // Vector Tracking Loop (VTL) pvt_output_parameters.enable_vtl = configuration->property(role + ".enable_vtl", pvt_output_parameters.enable_vtl); diff --git a/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc b/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc index 63ae58f71..f7a7e2946 100644 --- a/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc +++ b/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc @@ -178,7 +178,9 @@ rtklib_pvt_gs::rtklib_pvt_gs(uint32_t nchannels, d_log_timetag(conf_.log_source_timetag), d_use_e6_for_pvt(conf_.use_e6_for_pvt), d_enable_vtl(conf_.enable_vtl), - d_close_vtl_loop(conf_.close_vtl_loop) + d_close_vtl_loop(conf_.close_vtl_loop), + d_use_has_corrections(conf_.use_has_corrections), + d_use_unhealthy_sats(conf_.use_unhealthy_sats) { // Send feedback message to observables block with the receiver clock offset this->message_port_register_out(pmt::mp("pvt_to_observables")); @@ -553,19 +555,6 @@ rtklib_pvt_gs::rtklib_pvt_gs(uint32_t nchannels, d_user_pvt_solver = d_internal_pvt_solver; } - d_mapStringValues["1C"] = evGPS_1C; - d_mapStringValues["2S"] = evGPS_2S; - d_mapStringValues["L5"] = evGPS_L5; - d_mapStringValues["1B"] = evGAL_1B; - d_mapStringValues["5X"] = evGAL_5X; - d_mapStringValues["E6"] = evGAL_E6; - d_mapStringValues["7X"] = evGAL_7X; - d_mapStringValues["1G"] = evGLO_1G; - d_mapStringValues["2G"] = evGLO_2G; - d_mapStringValues["B1"] = evBDS_B1; - d_mapStringValues["B2"] = evBDS_B2; - d_mapStringValues["B3"] = evBDS_B3; - // set the RTKLIB trace (debug) level tracelevel(conf_.rtk_trace_level); @@ -1209,7 +1198,15 @@ void rtklib_pvt_gs::msg_handler_telemetry(const pmt::pmt_t& msg) if (gps_eph->SV_health != 0) { std::cout << TEXT_RED << "Satellite " << Gnss_Satellite(std::string("GPS"), gps_eph->PRN) - << " is not healthy, not used for navigation" << TEXT_RESET << '\n'; + << " reports an unhealthy status,"; + if (d_use_unhealthy_sats) + { + std::cout << " use PVT solutions at your own risk" << TEXT_RESET << '\n'; + } + else + { + std::cout << " not used for navigation" << TEXT_RESET << '\n'; + } } } else if (msg_type_hash_code == d_gps_iono_sptr_type_hash_code) @@ -1269,8 +1266,15 @@ void rtklib_pvt_gs::msg_handler_telemetry(const pmt::pmt_t& msg) if (gps_cnav_ephemeris->signal_health != 0) { std::cout << "Satellite " << Gnss_Satellite(std::string("GPS"), gps_cnav_ephemeris->PRN) - << " does not report a healthy status in the CNAV message," - << " use PVT solutions at your own risk.\n"; + << " reports an unhealthy status in the CNAV message,"; + if (d_use_unhealthy_sats) + { + std::cout << " use PVT solutions at your own risk.\n"; + } + else + { + std::cout << " not used for navigation.\n"; + } } DLOG(INFO) << "New GPS CNAV ephemeris record has arrived"; } @@ -1356,7 +1360,15 @@ void rtklib_pvt_gs::msg_handler_telemetry(const pmt::pmt_t& msg) ((galileo_eph->E5b_HS != 0) || (galileo_eph->E5b_DVS == true))) { std::cout << TEXT_RED << "Satellite " << Gnss_Satellite(std::string("Galileo"), galileo_eph->PRN) - << " is not healthy, not used for navigation" << TEXT_RESET << '\n'; + << " reports an unhealthy status,"; + if (d_use_unhealthy_sats) + { + std::cout << " use PVT solutions at your own risk" << TEXT_RESET << '\n'; + } + else + { + std::cout << " not used for navigation" << TEXT_RESET << '\n'; + } } } else if (msg_type_hash_code == d_galileo_iono_sptr_type_hash_code) @@ -1532,7 +1544,15 @@ void rtklib_pvt_gs::msg_handler_telemetry(const pmt::pmt_t& msg) if (bds_dnav_eph->SV_health != 0) { std::cout << TEXT_RED << "Satellite " << Gnss_Satellite(std::string("Beidou"), bds_dnav_eph->PRN) - << " is not healthy, not used for navigation" << TEXT_RESET << '\n'; + << " reports an unhealthy status,"; + if (d_use_unhealthy_sats) + { + std::cout << " use PVT solutions at your own risk" << TEXT_RESET << '\n'; + } + else + { + std::cout << " not used for navigation" << TEXT_RESET << '\n'; + } } } else if (msg_type_hash_code == d_beidou_dnav_iono_sptr_type_hash_code) @@ -1580,7 +1600,7 @@ void rtklib_pvt_gs::msg_handler_telemetry(const pmt::pmt_t& msg) } -void rtklib_pvt_gs::msg_handler_has_data(const pmt::pmt_t& msg) const +void rtklib_pvt_gs::msg_handler_has_data(const pmt::pmt_t& msg) { try { @@ -1588,6 +1608,14 @@ void rtklib_pvt_gs::msg_handler_has_data(const pmt::pmt_t& msg) const if (msg_type_hash_code == d_galileo_has_data_sptr_type_hash_code) { const auto has_data = wht::any_cast>(pmt::any_ref(msg)); + if (d_use_has_corrections && (has_data->has_status == 1)) // operational mode + { + d_internal_pvt_solver->store_has_data(*has_data); + if (d_enable_rx_clock_correction == true) + { + d_user_pvt_solver->store_has_data(*has_data); + } + } if (d_has_simple_printer) { d_has_simple_printer->print_message(has_data.get()); @@ -1810,44 +1838,10 @@ void rtklib_pvt_gs::apply_rx_clock_offset(std::map& observabl // all observables in the map are valid observables_iter->second.RX_time -= rx_clock_offset_s; observables_iter->second.Pseudorange_m -= rx_clock_offset_s * SPEED_OF_LIGHT_M_S; - - switch (d_mapStringValues[observables_iter->second.Signal]) + const auto it_freq_map = SIGNAL_FREQ_MAP.find(std::string(observables_iter->second.Signal, 2)); + if (it_freq_map != SIGNAL_FREQ_MAP.cend()) { - case evGPS_1C: - case evSBAS_1C: - case evGAL_1B: - observables_iter->second.Carrier_phase_rads -= rx_clock_offset_s * FREQ1 * TWO_PI; - break; - case evGPS_L5: - case evGAL_5X: - observables_iter->second.Carrier_phase_rads -= rx_clock_offset_s * FREQ5 * TWO_PI; - break; - case evGAL_E6: - observables_iter->second.Carrier_phase_rads -= rx_clock_offset_s * FREQ6 * TWO_PI; - break; - case evGAL_7X: - observables_iter->second.Carrier_phase_rads -= rx_clock_offset_s * FREQ7 * TWO_PI; - break; - case evGPS_2S: - observables_iter->second.Carrier_phase_rads -= rx_clock_offset_s * FREQ2 * TWO_PI; - break; - case evBDS_B3: - observables_iter->second.Carrier_phase_rads -= rx_clock_offset_s * FREQ3_BDS * TWO_PI; - break; - case evGLO_1G: - observables_iter->second.Carrier_phase_rads -= rx_clock_offset_s * FREQ1_GLO * TWO_PI; - break; - case evGLO_2G: - observables_iter->second.Carrier_phase_rads -= rx_clock_offset_s * FREQ2_GLO * TWO_PI; - break; - case evBDS_B1: - observables_iter->second.Carrier_phase_rads -= rx_clock_offset_s * FREQ1_BDS * TWO_PI; - break; - case evBDS_B2: - observables_iter->second.Carrier_phase_rads -= rx_clock_offset_s * FREQ2_BDS * TWO_PI; - break; - default: - break; + observables_iter->second.Carrier_phase_rads -= rx_clock_offset_s * it_freq_map->second * TWO_PI; } } } @@ -1912,44 +1906,11 @@ void rtklib_pvt_gs::initialize_and_apply_carrier_phase_offset() // it is set to false by the work function if the gnss_synchro is not valid if (d_channel_initialized.at(observables_iter->second.Channel_ID) == false) { - double wavelength_m = 0; - switch (d_mapStringValues[observables_iter->second.Signal]) + double wavelength_m = 1.0; + const auto it_freq_map = SIGNAL_FREQ_MAP.find(std::string(observables_iter->second.Signal, 2)); + if (it_freq_map != SIGNAL_FREQ_MAP.cend()) { - case evGPS_1C: - case evSBAS_1C: - case evGAL_1B: - wavelength_m = SPEED_OF_LIGHT_M_S / FREQ1; - break; - case evGPS_L5: - case evGAL_5X: - wavelength_m = SPEED_OF_LIGHT_M_S / FREQ5; - break; - case evGAL_E6: - wavelength_m = SPEED_OF_LIGHT_M_S / FREQ6; - break; - case evGAL_7X: - wavelength_m = SPEED_OF_LIGHT_M_S / FREQ7; - break; - case evGPS_2S: - wavelength_m = SPEED_OF_LIGHT_M_S / FREQ2; - break; - case evBDS_B3: - wavelength_m = SPEED_OF_LIGHT_M_S / FREQ3_BDS; - break; - case evGLO_1G: - wavelength_m = SPEED_OF_LIGHT_M_S / FREQ1_GLO; - break; - case evGLO_2G: - wavelength_m = SPEED_OF_LIGHT_M_S / FREQ2_GLO; - break; - case evBDS_B1: - wavelength_m = SPEED_OF_LIGHT_M_S / FREQ1_BDS; - break; - case evBDS_B2: - wavelength_m = SPEED_OF_LIGHT_M_S / FREQ2_BDS; - break; - default: - break; + wavelength_m = SPEED_OF_LIGHT_M_S / it_freq_map->second; } const double wrap_carrier_phase_rad = fmod(observables_iter->second.Carrier_phase_rads, TWO_PI); d_initial_carrier_phase_offset_estimation_rads.at(observables_iter->second.Channel_ID) = TWO_PI * round(observables_iter->second.Pseudorange_m / wavelength_m) - observables_iter->second.Carrier_phase_rads + wrap_carrier_phase_rad; @@ -1962,6 +1923,16 @@ void rtklib_pvt_gs::initialize_and_apply_carrier_phase_offset() } +void rtklib_pvt_gs::update_HAS_corrections() +{ + this->d_internal_pvt_solver->update_has_corrections(this->d_gnss_observables_map); + if (d_enable_rx_clock_correction == true) + { + this->d_user_pvt_solver->update_has_corrections(this->d_gnss_observables_map); + } +} + + int rtklib_pvt_gs::work(int noutput_items, gr_vector_const_void_star& input_items, gr_vector_void_star& output_items __attribute__((unused))) { @@ -2023,7 +1994,7 @@ int rtklib_pvt_gs::work(int noutput_items, gr_vector_const_void_star& input_item if (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) == std::string("1C")) && (tmp_eph_iter_gps->second.SV_health == 0)) + 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))) { store_valid_observable = true; } @@ -2032,9 +2003,9 @@ int rtklib_pvt_gs::work(int noutput_items, gr_vector_const_void_star& input_item { const uint32_t prn_aux = tmp_eph_iter_gal->second.PRN; if ((prn_aux == in[i][epoch].PRN) && - (((std::string(in[i][epoch].Signal) == std::string("1B")) && (tmp_eph_iter_gal->second.E1B_DVS == false) && (tmp_eph_iter_gal->second.E1B_HS == 0)) || - ((std::string(in[i][epoch].Signal) == std::string("5X")) && (tmp_eph_iter_gal->second.E5a_DVS == false) && (tmp_eph_iter_gal->second.E5a_HS == 0)) || - ((std::string(in[i][epoch].Signal) == std::string("7X")) && (tmp_eph_iter_gal->second.E5b_DVS == false) && (tmp_eph_iter_gal->second.E5b_HS == 0)))) + (((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)))))) { store_valid_observable = true; } @@ -2042,7 +2013,7 @@ int rtklib_pvt_gs::work(int noutput_items, gr_vector_const_void_star& input_item if (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) == std::string("2S")) || (std::string(in[i][epoch].Signal) == std::string("L5"))))) + 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"))))) { store_valid_observable = true; } @@ -2050,7 +2021,7 @@ int rtklib_pvt_gs::work(int noutput_items, gr_vector_const_void_star& input_item if (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) == std::string("1G")) || (std::string(in[i][epoch].Signal) == std::string("2G")))) + 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")))) { store_valid_observable = true; } @@ -2058,12 +2029,12 @@ int rtklib_pvt_gs::work(int noutput_items, gr_vector_const_void_star& input_item if (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) == std::string("B1")) || (std::string(in[i][epoch].Signal) == std::string("B3"))) && (tmp_eph_iter_bds_dnav->second.SV_health == 0))) + 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)))) { store_valid_observable = true; } } - if (std::string(in[i][epoch].Signal) == std::string("E6")) + if (std::string(in[i][epoch].Signal, 2) == std::string("E6")) { store_valid_observable = true; } @@ -2125,6 +2096,12 @@ int rtklib_pvt_gs::work(int noutput_items, gr_vector_const_void_star& input_item } } + // ############ 2. APPLY HAS CORRECTIONS IF AVAILABLE #### + if (d_use_has_corrections && !d_gnss_observables_map.empty()) + { + this->update_HAS_corrections(); + } + // ############ 2 COMPUTE THE PVT ################################ bool flag_pvt_valid = false; if (d_gnss_observables_map.empty() == false) @@ -2524,9 +2501,9 @@ int rtklib_pvt_gs::work(int noutput_items, gr_vector_const_void_star& input_item // p_time += boost::posix_time::microseconds(round(rtklib_utc_time.sec * 1e6)); // std::cout << TEXT_MAGENTA << "Observable RX time (GPST) " << boost::posix_time::to_simple_string(p_time) << TEXT_RESET << '\n'; - DLOG(INFO) << "Position at " << boost::posix_time::to_simple_string(d_user_pvt_solver->get_position_UTC_time()) - << " UTC using " << d_user_pvt_solver->get_num_valid_observations() << " observations is Lat = " << d_user_pvt_solver->get_latitude() << " [deg], Long = " << d_user_pvt_solver->get_longitude() - << " [deg], Height = " << d_user_pvt_solver->get_height() << " [m]"; + LOG(INFO) << "Position at " << boost::posix_time::to_simple_string(d_user_pvt_solver->get_position_UTC_time()) + << " UTC using " << d_user_pvt_solver->get_num_valid_observations() << " observations is Lat = " << d_user_pvt_solver->get_latitude() << " [deg], Long = " << d_user_pvt_solver->get_longitude() + << " [deg], Height = " << d_user_pvt_solver->get_height() << " [m]"; /* std::cout << "Dilution of Precision at " << boost::posix_time::to_simple_string(d_user_pvt_solver->get_position_UTC_time()) << " UTC using "<< d_user_pvt_solver->get_num_valid_observations() <<" observations is HDOP = " << d_user_pvt_solver->get_hdop() << " VDOP = " diff --git a/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.h b/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.h index 3f803260b..10286d344 100644 --- a/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.h +++ b/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.h @@ -49,6 +49,7 @@ class Beidou_Dnav_Almanac; class Beidou_Dnav_Ephemeris; class Galileo_Almanac; class Galileo_Ephemeris; +class Galileo_HAS_data; class GeoJSON_Printer; class Gps_Almanac; class Gps_Ephemeris; @@ -140,13 +141,15 @@ private: void msg_handler_telemetry(const pmt::pmt_t& msg); - void msg_handler_has_data(const pmt::pmt_t& msg) const; + void msg_handler_has_data(const pmt::pmt_t& msg); void initialize_and_apply_carrier_phase_offset(); void apply_rx_clock_offset(std::map& observables_map, double rx_clock_offset_s); + void update_HAS_corrections(); + std::map interpolate_observables(const std::map& observables_map_t0, const std::map& observables_map_t1, double rx_time_s); @@ -160,7 +163,7 @@ private: typedef struct { - long mtype; // NOLINT(google-runtime-int) required by SysV queue messaging + long mtype; // NOLINT(google-runtime-int) double ttff; } d_ttff_msgbuf; bool send_sys_v_ttff_msg(d_ttff_msgbuf ttff) const; @@ -194,23 +197,6 @@ private: std::vector d_channel_initialized; std::vector d_initial_carrier_phase_offset_estimation_rads; - enum StringValue_ - { - evGPS_1C, - evGPS_2S, - evGPS_L5, - evSBAS_1C, - evGAL_1B, - evGAL_5X, - evGAL_E6, - evGAL_7X, - evGLO_1G, - evGLO_2G, - evBDS_B1, - evBDS_B2, - evBDS_B3 - }; - std::map d_mapStringValues; std::map d_gnss_observables_map; std::map d_gnss_observables_map_t0; std::map d_gnss_observables_map_t1; @@ -292,6 +278,8 @@ private: bool d_enable_vtl; bool d_close_vtl_loop; std::map d_last_sent_vtl_cmd_samplestamp_map; + bool d_use_has_corrections; + bool d_use_unhealthy_sats; }; diff --git a/src/algorithms/PVT/libs/pvt_conf.cc b/src/algorithms/PVT/libs/pvt_conf.cc deleted file mode 100644 index bf16f469e..000000000 --- a/src/algorithms/PVT/libs/pvt_conf.cc +++ /dev/null @@ -1,74 +0,0 @@ -/*! - * \file pvt_conf.cc - * \brief Class that contains all the configuration parameters for a PVT block - * \author Carles Fernandez, 2018. 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-2020 (see AUTHORS file for a list of contributors) - * SPDX-License-Identifier: GPL-3.0-or-later - * - * ----------------------------------------------------------------------------- - */ - -#include "pvt_conf.h" - -Pvt_Conf::Pvt_Conf() -{ - type_of_receiver = 0U; - observable_interval_ms = 20U; - output_rate_ms = 0; - display_rate_ms = 0; - kml_rate_ms = 1000; - gpx_rate_ms = 1000; - geojson_rate_ms = 1000; - nmea_rate_ms = 1000; - - max_obs_block_rx_clock_offset_ms = 40; - rinex_version = 0; - rinexobs_rate_ms = 0; - rinex_name = std::string("-"); - - dump = false; - dump_mat = true; - - flag_nmea_tty_port = false; - - flag_rtcm_server = false; - flag_rtcm_tty_port = false; - rtcm_tcp_port = 0U; - rtcm_station_id = 0U; - - output_enabled = true; - rinex_output_enabled = true; - gpx_output_enabled = true; - geojson_output_enabled = true; - nmea_output_file_enabled = true; - kml_output_enabled = true; - xml_output_enabled = true; - rtcm_output_file_enabled = true; - - output_path = std::string("."); - rinex_output_path = std::string("."); - gpx_output_path = std::string("."); - geojson_output_path = std::string("."); - nmea_output_file_path = std::string("."); - kml_output_path = std::string("."); - xml_output_path = std::string("."); - rtcm_output_file_path = std::string("."); - log_source_timetag_file = "PVT_timetag.dat"; - - enable_rx_clock_correction = true; - monitor_enabled = false; - monitor_ephemeris_enabled = false; - protobuf_enabled = true; - udp_port = 0; - udp_eph_port = 0; - pre_2009_file = false; - show_local_time_zone = false; - - log_source_timetag = false; -} diff --git a/src/algorithms/PVT/libs/pvt_conf.h b/src/algorithms/PVT/libs/pvt_conf.h index 1924cc9eb..6945ffe5e 100644 --- a/src/algorithms/PVT/libs/pvt_conf.h +++ b/src/algorithms/PVT/libs/pvt_conf.h @@ -94,6 +94,8 @@ public: bool use_e6_for_pvt = true; bool enable_vtl = false; bool close_vtl_loop = true; + bool use_has_corrections = true; + bool use_unhealthy_sats = false; }; diff --git a/src/algorithms/PVT/libs/rtklib_solver.cc b/src/algorithms/PVT/libs/rtklib_solver.cc index 2cd0ab619..53a261eae 100755 --- a/src/algorithms/PVT/libs/rtklib_solver.cc +++ b/src/algorithms/PVT/libs/rtklib_solver.cc @@ -4,7 +4,7 @@ * data flow and structures * \authors
    *
  • 2017-2019, Javier Arribas - *
  • 2017-2019, Carles Fernandez + *
  • 2017-2023, Carles Fernandez *
  • 2007-2013, T. Takasu *
* @@ -23,7 +23,7 @@ * ----------------------------------------------------------------------------- * Copyright (C) 2007-2013, T. Takasu * Copyright (C) 2017-2019, Javier Arribas - * Copyright (C) 2017-2019, Carles Fernandez + * Copyright (C) 2017-2023, Carles Fernandez * All rights reserved. * * SPDX-License-Identifier: BSD-2-Clause @@ -40,6 +40,8 @@ #include #include #include "iostream" +#include +#include #include #include #include @@ -141,6 +143,8 @@ Rtklib_Solver::Rtklib_Solver(const rtk_t &rtk, d_rtklib_freq_index[1] = 3; break; } + // auto empty_map = std::map < int, HAS_obs_corrections >> (); + // d_has_obs_corr_map["L1 C/A"] = empty_map; // ############# ENABLE DATA FILE LOG ################# if (d_flag_dump_enabled == true) @@ -204,13 +208,13 @@ bool Rtklib_Solver::save_matfile() const { // READ DUMP FILE const std::string dump_filename = d_dump_filename; - const int32_t number_of_double_vars = 23; //+2 MAGL - const int32_t number_of_double_vars_sat = 9; //+ pos(3)/vel(3)/psrange/doppler/CN0 for sat + const int32_t number_of_double_vars = 23; //+2 MAGL + const int32_t number_of_double_vars_sat = 9; //+ pos(3)/vel(3)/psrange/doppler/CN0 for sat const int32_t number_of_uint32_vars = 2; const int32_t number_of_uint8_vars = 3; const int32_t number_of_float_vars = 2; const int32_t epoch_size_bytes = sizeof(double) * number_of_double_vars + - sizeof(double) * number_of_double_vars_sat*6+ + sizeof(double) * number_of_double_vars_sat * 6 + sizeof(uint32_t) * number_of_uint32_vars + sizeof(uint8_t) * number_of_uint8_vars + sizeof(float) * number_of_float_vars; @@ -255,7 +259,7 @@ bool Rtklib_Solver::save_matfile() const auto cov_xy = std::vector(num_epoch); auto cov_yz = std::vector(num_epoch); auto cov_zx = std::vector(num_epoch); - + auto clk_bias = std::vector(num_epoch); auto clk_drift = std::vector(num_epoch); auto sat_posX_m = std::vector>(6, std::vector(num_epoch)); @@ -308,16 +312,16 @@ bool Rtklib_Solver::save_matfile() const dump_file.read(reinterpret_cast(&clk_drift[i]), sizeof(double)); for (uint32_t chan = 0; chan < 6; chan++) { - dump_file.read(reinterpret_cast(&sat_posX_m[chan][i]), sizeof(double)); - dump_file.read(reinterpret_cast(&sat_posY_m[chan][i]), sizeof(double)); - dump_file.read(reinterpret_cast(&sat_posZ_m[chan][i]), sizeof(double)); - dump_file.read(reinterpret_cast(&sat_velX[chan][i]), sizeof(double)); - dump_file.read(reinterpret_cast(&sat_velY[chan][i]), sizeof(double)); - dump_file.read(reinterpret_cast(&sat_velZ[chan][i]), sizeof(double)); - dump_file.read(reinterpret_cast(&sat_prg_m[chan][i]), sizeof(double)); - dump_file.read(reinterpret_cast(&sat_dopp_hz[chan][i]), sizeof(double)); - dump_file.read(reinterpret_cast(&sat_CN0_dBhz[chan][i]), sizeof(double)); - } + dump_file.read(reinterpret_cast(&sat_posX_m[chan][i]), sizeof(double)); + dump_file.read(reinterpret_cast(&sat_posY_m[chan][i]), sizeof(double)); + dump_file.read(reinterpret_cast(&sat_posZ_m[chan][i]), sizeof(double)); + dump_file.read(reinterpret_cast(&sat_velX[chan][i]), sizeof(double)); + dump_file.read(reinterpret_cast(&sat_velY[chan][i]), sizeof(double)); + dump_file.read(reinterpret_cast(&sat_velZ[chan][i]), sizeof(double)); + dump_file.read(reinterpret_cast(&sat_prg_m[chan][i]), sizeof(double)); + dump_file.read(reinterpret_cast(&sat_dopp_hz[chan][i]), sizeof(double)); + dump_file.read(reinterpret_cast(&sat_CN0_dBhz[chan][i]), sizeof(double)); + } dump_file.read(reinterpret_cast(&latitude[i]), sizeof(double)); dump_file.read(reinterpret_cast(&longitude[i]), sizeof(double)); dump_file.read(reinterpret_cast(&height[i]), sizeof(double)); @@ -339,7 +343,7 @@ bool Rtklib_Solver::save_matfile() const std::cerr << "Problem reading dump file:" << e.what() << '\n'; return false; } - + auto sat_posX_m_aux = std::vector(6 * num_epoch); auto sat_posY_m_aux = std::vector(6 * num_epoch); auto sat_posZ_m_aux = std::vector(6 * num_epoch); @@ -350,7 +354,7 @@ bool Rtklib_Solver::save_matfile() const auto sat_dopp_hz_aux = std::vector(6 * num_epoch); auto sat_CN0_dBhz_aux = std::vector(6 * num_epoch); - uint32_t k = 0U; + uint32_t k = 0U; for (int64_t j = 0; j < num_epoch; j++) { for (uint32_t i = 0; i < 6; i++) @@ -563,6 +567,446 @@ Monitor_Pvt Rtklib_Solver::get_monitor_pvt() const return d_monitor_pvt; } +void Rtklib_Solver::store_has_data(const Galileo_HAS_data &new_has_data) +{ + // Compute time of application HAS SIS ICD, Issue 1.0, Section 7.7 + uint16_t toh = new_has_data.header.toh; + uint32_t hr = std::floor(new_has_data.tow / 3600); + uint32_t tmt = 0; + if ((hr * 3600 + toh) <= new_has_data.tow) + { + tmt = hr * 3600 + toh; + } + else + { + tmt = (hr - 1) * 3600 + toh; + } + + const std::string gps_str("GPS"); + const std::string gal_str("Galileo"); + if (new_has_data.header.orbit_correction_flag) + { + LOG(INFO) << "Received HAS orbit corrections"; + // for each satellite in GPS ephemeris + for (const auto &gpseph : gps_ephemeris_map) + { + int prn = gpseph.second.PRN; + int32_t sis_iod = gpseph.second.IODE_SF3; + uint16_t gnss_iod = new_has_data.get_gnss_iod(gps_str, prn); + if (static_cast(gnss_iod) == sis_iod) + { + float radial_m = new_has_data.get_delta_radial_m(gps_str, prn); + if (std::fabs(radial_m + 10.24) < 0.001) // -10.24 means not available + { + radial_m = 0.0; + } + float in_track_m = new_has_data.get_delta_in_track_m(gps_str, prn); + if (std::fabs(in_track_m + 16.384) < 0.001) // -16.384 means not available + { + in_track_m = 0.0; + } + float cross_track_m = new_has_data.get_delta_in_track_m(gps_str, prn); + if (std::fabs(cross_track_m + 16.384) < 0.001) // -16.384 means not available + { + cross_track_m = 0.0; + } + d_has_orbit_corrections_store_map[gps_str][prn].radial_m = radial_m; + d_has_orbit_corrections_store_map[gps_str][prn].in_track_m = in_track_m; + d_has_orbit_corrections_store_map[gps_str][prn].cross_track_m = cross_track_m; + d_has_orbit_corrections_store_map[gps_str][prn].valid_until = tmt + + new_has_data.get_validity_interval_s(new_has_data.validity_interval_index_orbit_corrections); + d_has_orbit_corrections_store_map[gps_str][prn].iod = gnss_iod; + // TODO: check for end of week + } + } + + // for each satellite in Galileo ephemeris + for (const auto &galeph : galileo_ephemeris_map) + { + int prn = galeph.second.PRN; + int32_t sis_iod = galeph.second.IOD_ephemeris; + uint16_t gnss_iod = new_has_data.get_gnss_iod(gal_str, prn); + if (static_cast(gnss_iod) == sis_iod) + { + float radial_m = new_has_data.get_delta_radial_m(gal_str, prn); + if (std::fabs(radial_m + 10.24) < 0.001) // -10.24 means not available + { + radial_m = 0.0; + } + float in_track_m = new_has_data.get_delta_in_track_m(gal_str, prn); + if (std::fabs(in_track_m + 16.384) < 0.001) // -16.384 means not available + { + in_track_m = 0.0; + } + float cross_track_m = new_has_data.get_delta_in_track_m(gal_str, prn); + if (std::fabs(cross_track_m + 16.384) < 0.001) // -16.384 means not available + { + cross_track_m = 0.0; + } + d_has_orbit_corrections_store_map[gal_str][prn].radial_m = radial_m; + d_has_orbit_corrections_store_map[gal_str][prn].in_track_m = in_track_m; + d_has_orbit_corrections_store_map[gal_str][prn].cross_track_m = cross_track_m; + d_has_orbit_corrections_store_map[gal_str][prn].valid_until = tmt + + new_has_data.get_validity_interval_s(new_has_data.validity_interval_index_orbit_corrections); + d_has_orbit_corrections_store_map[gal_str][prn].iod = gnss_iod; + // TODO: check for end of week + } + } + } + if (new_has_data.header.clock_fullset_flag) + { + LOG(INFO) << "Received HAS clock fullset corrections"; + for (const auto &gpseph : gps_ephemeris_map) + { + int prn = gpseph.second.PRN; + int32_t sis_iod = gpseph.second.IODE_SF3; + auto it = d_has_orbit_corrections_store_map[gps_str].find(prn); + if (it != d_has_orbit_corrections_store_map[gps_str].end()) + { + uint16_t gnss_iod = it->second.iod; + if (static_cast(gnss_iod) == sis_iod) + { + float clock_correction_mult_m = new_has_data.get_clock_correction_mult_m(gps_str, prn); + if ((std::fabs(clock_correction_mult_m + 10.24) < 0.001) || + (std::fabs(clock_correction_mult_m + 20.48) < 0.001) || + (std::fabs(clock_correction_mult_m + 30.72) < 0.001) || + (std::fabs(clock_correction_mult_m + 40.96) < 0.001)) + { + clock_correction_mult_m = 0.0; + } + if ((std::fabs(clock_correction_mult_m - 10.2375) < 0.001) || + (std::fabs(clock_correction_mult_m - 20.475) < 0.001) || + (std::fabs(clock_correction_mult_m - 30.7125) < 0.001) || + (std::fabs(clock_correction_mult_m - 40.95) < 0.001)) + { + // Satellite should not be used! + clock_correction_mult_m = 0.0; + } + d_has_clock_corrections_store_map[gps_str][prn].clock_correction_m = clock_correction_mult_m; + d_has_clock_corrections_store_map[gps_str][prn].valid_until = tmt + + new_has_data.get_validity_interval_s(new_has_data.validity_interval_index_clock_fullset_corrections); + // TODO: check for end of week + } + } + } + + // for each satellite in Galileo ephemeris + for (const auto &galeph : galileo_ephemeris_map) + { + int prn = galeph.second.PRN; + int32_t iod_sis = galeph.second.IOD_ephemeris; + auto it = d_has_orbit_corrections_store_map[gal_str].find(prn); + if (it != d_has_orbit_corrections_store_map[gal_str].end()) + { + uint16_t gnss_iod = it->second.iod; + if (static_cast(gnss_iod) == iod_sis) + { + float clock_correction_mult_m = new_has_data.get_clock_correction_mult_m(gal_str, prn); + // std::cout << "Galileo Satellite " << prn + // << " clock correction=" << new_has_data.get_clock_correction_mult_m(gal_str, prn) + // << std::endl; + if ((std::fabs(clock_correction_mult_m + 10.24) < 0.001) || + (std::fabs(clock_correction_mult_m + 20.48) < 0.001) || + (std::fabs(clock_correction_mult_m + 30.72) < 0.001) || + (std::fabs(clock_correction_mult_m + 40.96) < 0.001)) + { + clock_correction_mult_m = 0.0; + } + d_has_clock_corrections_store_map[gal_str][prn].clock_correction_m = clock_correction_mult_m; + d_has_clock_corrections_store_map[gal_str][prn].valid_until = tmt + + new_has_data.get_validity_interval_s(new_has_data.validity_interval_index_clock_fullset_corrections); + // TODO: check for end of week + } + } + } + } + if (new_has_data.header.clock_subset_flag) + { + LOG(INFO) << "Received HAS clock subset corrections"; + for (const auto &gpseph : gps_ephemeris_map) + { + int prn = gpseph.second.PRN; + int32_t sis_iod = gpseph.second.IODE_SF3; + int32_t gnss_iod = d_has_orbit_corrections_store_map[gps_str][prn].iod; + if (gnss_iod == sis_iod) + { + // d_has_clock_corrections_store_map[gps_str][prn].clock_correction_m = new_has_data.get_clock_subset_correction_mult_m(gps_str, prn); + // d_has_clock_corrections_store_map[gps_str][prn].valid_until = tmt + new_has_data.get_validity_interval_s(new_has_data.validity_interval_index_clock_subset_corrections); + // TODO: check for end of week + } + } + } + if (new_has_data.header.code_bias_flag) + { + LOG(INFO) << "Received HAS code bias corrections"; + uint32_t valid_until = tmt + + new_has_data.get_validity_interval_s(new_has_data.validity_interval_index_code_bias_corrections); + auto signals_gal = new_has_data.get_signals_in_mask(gal_str); + for (const auto &it : signals_gal) + { + auto prns = new_has_data.get_PRNs_in_mask(gal_str); + for (auto prn : prns) + { + float code_bias_m = new_has_data.get_code_bias_m(it, prn); + if ((std::fabs(code_bias_m + 20.48) < 0.01)) // -20.48 means not available + { + code_bias_m = 0.0; + } + d_has_code_bias_store_map[it][prn] = {code_bias_m, valid_until}; + } + } + auto signals_gps = new_has_data.get_signals_in_mask(gps_str); + for (const auto &it : signals_gps) + { + auto prns = new_has_data.get_PRNs_in_mask(gps_str); + for (auto prn : prns) + { + float code_bias_m = new_has_data.get_code_bias_m(it, prn); + if ((std::fabs(code_bias_m + 20.48) < 0.01)) // -20.48 means not available + { + code_bias_m = 0.0; + } + d_has_code_bias_store_map[it][prn] = {code_bias_m, valid_until}; + } + } + } + if (new_has_data.header.phase_bias_flag) + { + LOG(INFO) << "Received HAS phase bias corrections"; + uint32_t valid_until = tmt + + new_has_data.get_validity_interval_s(new_has_data.validity_interval_index_phase_bias_corrections); + + auto signals_gal = new_has_data.get_signals_in_mask(gal_str); + for (const auto &it : signals_gal) + { + auto prns = new_has_data.get_PRNs_in_mask(gal_str); + for (auto prn : prns) + { + float phase_bias_correction_cycles = new_has_data.get_phase_bias_cycle(it, prn); + if (std::fabs(phase_bias_correction_cycles + 10.24) < 0.001) // -10.24 means not available + { + phase_bias_correction_cycles = 0.0; + } + d_has_phase_bias_store_map[it][prn] = {phase_bias_correction_cycles, valid_until}; + // TODO: process Phase Discontinuity Indicator + } + } + auto signals_gps = new_has_data.get_signals_in_mask(gps_str); + for (const auto &it : signals_gps) + { + auto prns = new_has_data.get_PRNs_in_mask(gps_str); + for (auto prn : prns) + { + float phase_bias_correction_cycles = new_has_data.get_phase_bias_cycle(it, prn); + if (std::fabs(phase_bias_correction_cycles + 10.24) < 0.001) // -10.24 means not available + { + phase_bias_correction_cycles = 0.0; + } + d_has_phase_bias_store_map[it][prn] = {phase_bias_correction_cycles, valid_until}; + // TODO: process Phase Discontinuity Indicator + } + } + } +} + + +void Rtklib_Solver::update_has_corrections(const std::map &obs_map) +{ + this->check_has_orbit_clock_validity(obs_map); + this->get_has_biases(obs_map); +} + + +void Rtklib_Solver::check_has_orbit_clock_validity(const std::map &obs_map) +{ + for (const auto &it : obs_map) + { + uint32_t obs_tow = it.second.interp_TOW_ms / 1000.0; + auto prn = static_cast(it.second.PRN); + + if (it.second.System == 'G') + { + auto it_sys = d_has_orbit_corrections_store_map.find("GPS"); + if (it_sys != d_has_orbit_corrections_store_map.end()) + { + auto it_map_corr = it_sys->second.find(prn); + if (it_map_corr != it_sys->second.end()) + { + auto has_data_valid_until = it_map_corr->second.valid_until; + if (has_data_valid_until < obs_tow) + { + // Delete outdated data + it_sys->second.erase(prn); + } + } + } + auto it_sys_clock = d_has_clock_corrections_store_map.find("GPS"); + if (it_sys_clock != d_has_clock_corrections_store_map.end()) + { + auto it_map_corr = it_sys_clock->second.find(prn); + if (it_map_corr != it_sys_clock->second.end()) + { + auto has_data_valid_until = it_map_corr->second.valid_until; + if (has_data_valid_until < obs_tow) + { + // Delete outdated data + it_sys_clock->second.erase(prn); + } + } + } + } + if (it.second.System == 'E') + { + auto it_sys = d_has_orbit_corrections_store_map.find("Galileo"); + if (it_sys != d_has_orbit_corrections_store_map.end()) + { + auto it_map_corr = it_sys->second.find(prn); + if (it_map_corr != it_sys->second.end()) + { + auto has_data_valid_until = it_map_corr->second.valid_until; + if (has_data_valid_until < obs_tow) + { + // Delete outdated data + it_sys->second.erase(prn); + } + } + } + auto it_sys_clock = d_has_clock_corrections_store_map.find("Galileo"); + if (it_sys_clock != d_has_clock_corrections_store_map.end()) + { + auto it_map_corr = it_sys_clock->second.find(prn); + if (it_map_corr != it_sys_clock->second.end()) + { + auto has_data_valid_until = it_map_corr->second.valid_until; + if (has_data_valid_until < obs_tow) + { + // Delete outdated data + it_sys_clock->second.erase(prn); + } + } + } + } + } +} + + +void Rtklib_Solver::get_has_biases(const std::map &obs_map) +{ + d_has_obs_corr_map.clear(); + if (!d_has_clock_corrections_store_map.empty() && !d_has_orbit_corrections_store_map.empty()) + { + const std::vector e1b_signals = {"E1-B I/NAV OS", "E1-C", "E1-B + E1-C"}; + const std::vector e6_signals = {"E6-B C/NAV HAS", "E6-C", "E6-B + E6-C"}; + const std::vector e5_signals = {"E5a-I F/NAV OS", "E5a-Q", "E5a-I+E5a-Q"}; + const std::vector e7_signals = {"E5bI I/NAV OS", "E5b-Q", "E5b-I+E5b-Q"}; + const std::vector g1c_signals = {"L1 C/A"}; + const std::vector g2s_signals = {"L2 CM", "L2 CL", "L2 CM+CL", "L2 P"}; + const std::vector g5_signals = {"L5 I", "L5 Q", "L5 I + L5 Q"}; + + for (const auto &it : obs_map) + { + uint32_t obs_tow = it.second.interp_TOW_ms / 1000.0; + int prn = static_cast(it.second.PRN); + std::string sig(it.second.Signal, 2); + if (it.second.System == 'E') + { + auto it_sys_clock = d_has_clock_corrections_store_map.find("Galileo"); + if (it_sys_clock != d_has_clock_corrections_store_map.end()) + { + auto it_map_corr = it_sys_clock->second.find(prn); + if (it_map_corr != it_sys_clock->second.end()) + { + if (sig == "1B") + { + for (const auto &has_signal : e1b_signals) + { + this->get_current_has_obs_correction(has_signal, obs_tow, prn); + } + } + else if (sig == "E6") + { + for (const auto &has_signal : e6_signals) + { + this->get_current_has_obs_correction(has_signal, obs_tow, prn); + } + } + else if (sig == "5X") + { + for (const auto &has_signal : e5_signals) + { + this->get_current_has_obs_correction(has_signal, obs_tow, prn); + } + } + else if (sig == "7X") + { + for (const auto &has_signal : e7_signals) + { + this->get_current_has_obs_correction(has_signal, obs_tow, prn); + } + } + } + } + } + if (it.second.System == 'G') + { + auto it_sys_clock = d_has_clock_corrections_store_map.find("GPS"); + if (it_sys_clock != d_has_clock_corrections_store_map.end()) + { + auto it_map_corr = it_sys_clock->second.find(prn); + if (it_map_corr != it_sys_clock->second.end()) + { + if (sig == "1C") + { + for (const auto &has_signal : g1c_signals) + { + this->get_current_has_obs_correction(has_signal, obs_tow, prn); + } + } + else if (sig == "2S") + { + for (const auto &has_signal : g2s_signals) + { + this->get_current_has_obs_correction(has_signal, obs_tow, prn); + } + } + else if (sig == "L5") + { + for (const auto &has_signal : g5_signals) + { + this->get_current_has_obs_correction(has_signal, obs_tow, prn); + } + } + } + } + } + } + } +} + + +void Rtklib_Solver::get_current_has_obs_correction(const std::string &signal, uint32_t tow_obs, int prn) +{ + auto code_bias_pair_it = this->d_has_code_bias_store_map[signal].find(prn); + if (code_bias_pair_it != this->d_has_code_bias_store_map[signal].end()) + { + uint32_t valid_until = code_bias_pair_it->second.second; + if (valid_until > tow_obs) + { + this->d_has_obs_corr_map[signal][prn].code_bias_m = code_bias_pair_it->second.first; + } + } + auto phase_bias_pair_it = this->d_has_phase_bias_store_map[signal].find(prn); + if (phase_bias_pair_it != this->d_has_phase_bias_store_map[signal].end()) + { + uint32_t valid_until = phase_bias_pair_it->second.second; + if (valid_until > tow_obs) + { + this->d_has_obs_corr_map[signal][prn].phase_bias_cycle = phase_bias_pair_it->second.first; + } + } +} + + bool Rtklib_Solver::get_PVT(const std::map &gnss_observables_map, bool flag_averaging, bool enable_vtl, bool close_vtl_loop) { std::map::const_iterator gnss_observables_iter; @@ -599,7 +1043,7 @@ bool Rtklib_Solver::get_PVT(const std::map &gnss_observables_ { case 'G': { - const std::string sig_(gnss_observables_iter->second.Signal); + const std::string sig_(gnss_observables_iter->second.Signal, 2); if (sig_ == "1C") { band1 = true; @@ -628,7 +1072,8 @@ bool Rtklib_Solver::get_PVT(const std::map &gnss_observables_ { case 'E': { - const std::string sig_(gnss_observables_iter->second.Signal); + const std::string gal_str("Galileo"); + const std::string sig_(gnss_observables_iter->second.Signal, 2); // Galileo E1 if (sig_ == "1B") { @@ -637,11 +1082,14 @@ bool Rtklib_Solver::get_PVT(const std::map &gnss_observables_ if (galileo_ephemeris_iter != galileo_ephemeris_map.cend()) { // convert ephemeris from GNSS-SDR class to RTKLIB structure - eph_data[valid_obs] = eph_to_rtklib(galileo_ephemeris_iter->second); + eph_data[valid_obs] = eph_to_rtklib(galileo_ephemeris_iter->second, + this->d_has_orbit_corrections_store_map[gal_str], + this->d_has_clock_corrections_store_map[gal_str]); // convert observation from GNSS-SDR class to RTKLIB structure obsd_t newobs{}; d_obs_data[valid_obs + glo_valid_obs] = insert_obs_to_rtklib(newobs, gnss_observables_iter->second, + d_has_obs_corr_map, galileo_ephemeris_iter->second.WN, d_rtklib_band_index[sig_]); valid_obs++; @@ -666,6 +1114,7 @@ bool Rtklib_Solver::get_PVT(const std::map &gnss_observables_ { d_obs_data[i + glo_valid_obs] = insert_obs_to_rtklib(d_obs_data[i + glo_valid_obs], gnss_observables_iter->second, + d_has_obs_corr_map, galileo_ephemeris_iter->second.WN, d_rtklib_band_index[sig_]); found_E1_obs = true; @@ -676,7 +1125,9 @@ bool Rtklib_Solver::get_PVT(const std::map &gnss_observables_ { // insert Galileo E5 obs as new obs and also insert its ephemeris // convert ephemeris from GNSS-SDR class to RTKLIB structure - eph_data[valid_obs] = eph_to_rtklib(galileo_ephemeris_iter->second); + eph_data[valid_obs] = eph_to_rtklib(galileo_ephemeris_iter->second, + this->d_has_orbit_corrections_store_map[gal_str], + this->d_has_clock_corrections_store_map[gal_str]); // convert observation from GNSS-SDR class to RTKLIB structure const auto default_code_ = static_cast(CODE_NONE); obsd_t newobs = {{0, 0}, '0', '0', {}, {}, @@ -684,6 +1135,7 @@ bool Rtklib_Solver::get_PVT(const std::map &gnss_observables_ {}, {0.0, 0.0, 0.0}, {}}; d_obs_data[valid_obs + glo_valid_obs] = insert_obs_to_rtklib(newobs, gnss_observables_iter->second, + d_has_obs_corr_map, galileo_ephemeris_iter->second.WN, d_rtklib_band_index[sig_]); valid_obs++; @@ -706,6 +1158,7 @@ bool Rtklib_Solver::get_PVT(const std::map &gnss_observables_ { d_obs_data[i + glo_valid_obs] = insert_obs_to_rtklib(d_obs_data[i + glo_valid_obs], gnss_observables_iter->second, + d_has_obs_corr_map, galileo_ephemeris_iter->second.WN, d_rtklib_band_index[sig_]); found_E1_obs = true; @@ -716,7 +1169,9 @@ bool Rtklib_Solver::get_PVT(const std::map &gnss_observables_ { // insert Galileo E6 obs as new obs and also insert its ephemeris // convert ephemeris from GNSS-SDR class to RTKLIB structure - eph_data[valid_obs] = eph_to_rtklib(galileo_ephemeris_iter->second); + eph_data[valid_obs] = eph_to_rtklib(galileo_ephemeris_iter->second, + this->d_has_orbit_corrections_store_map[gal_str], + this->d_has_clock_corrections_store_map[gal_str]); // convert observation from GNSS-SDR class to RTKLIB structure const auto default_code_ = static_cast(CODE_NONE); obsd_t newobs = {{0, 0}, '0', '0', {}, {}, @@ -724,6 +1179,7 @@ bool Rtklib_Solver::get_PVT(const std::map &gnss_observables_ {}, {0.0, 0.0, 0.0}, {}}; d_obs_data[valid_obs + glo_valid_obs] = insert_obs_to_rtklib(newobs, gnss_observables_iter->second, + d_has_obs_corr_map, galileo_ephemeris_iter->second.WN, d_rtklib_band_index[sig_]); valid_obs++; @@ -740,18 +1196,23 @@ bool Rtklib_Solver::get_PVT(const std::map &gnss_observables_ { // GPS L1 // 1 GPS - find the ephemeris for the current GPS SV observation. The SV PRN ID is the map key - const std::string sig_(gnss_observables_iter->second.Signal); + const std::string gps_str("GPS"); + const std::string sig_(gnss_observables_iter->second.Signal, 2); if (sig_ == "1C") { gps_ephemeris_iter = gps_ephemeris_map.find(gnss_observables_iter->second.PRN); if (gps_ephemeris_iter != gps_ephemeris_map.cend()) { // convert ephemeris from GNSS-SDR class to RTKLIB structure - eph_data[valid_obs] = eph_to_rtklib(gps_ephemeris_iter->second, this->is_pre_2009()); + eph_data[valid_obs] = eph_to_rtklib(gps_ephemeris_iter->second, + this->d_has_orbit_corrections_store_map[gps_str], + this->d_has_clock_corrections_store_map[gps_str], + this->is_pre_2009()); // convert observation from GNSS-SDR class to RTKLIB structure obsd_t newobs{}; d_obs_data[valid_obs + glo_valid_obs] = insert_obs_to_rtklib(newobs, gnss_observables_iter->second, + d_has_obs_corr_map, gps_ephemeris_iter->second.WN, d_rtklib_band_index[sig_], this->is_pre_2009()); @@ -848,6 +1309,7 @@ bool Rtklib_Solver::get_PVT(const std::map &gnss_observables_ {}, {0.0, 0.0, 0.0}, {}}; d_obs_data[valid_obs + glo_valid_obs] = insert_obs_to_rtklib(newobs, gnss_observables_iter->second, + d_has_obs_corr_map, gps_cnav_ephemeris_iter->second.WN, d_rtklib_band_index[sig_]); valid_obs++; @@ -1109,7 +1571,7 @@ bool Rtklib_Solver::get_PVT(const std::map &gnss_observables_ std::vector doppler_residual_vec; result = rtkpos(&d_rtk, d_obs_data.data(), valid_obs + glo_valid_obs, &d_nav_data, tropo_vec, iono_vec, pr_corrected_code_bias_vec, pr_residual_vec, doppler_residual_vec); - + if (result == 0) { LOG(INFO) << "RTKLIB rtkpos error: " << d_rtk.errbuf; @@ -1216,14 +1678,14 @@ bool Rtklib_Solver::get_PVT(const std::map &gnss_observables_ vtl_data.sat_dts(n, 1) = dts[1 + 2 * n]; vtl_data.sat_var(n) = var[n]; vtl_data.sat_health_flag(n) = svh.at(n); - vtl_data.sat_CN0_dB_hz(n) = d_obs_data.at(n).SNR[0] * 0.25; //(0.25 dBHz) + vtl_data.sat_CN0_dB_hz(n) = d_obs_data.at(n).SNR[0] * 0.25; //(0.25 dBHz) // TODO: first version of VTL works only with ONE frequency band (band #0 is L1) //To.Do: check it VTL uses all the information as in rtklib rescode function: v[nv] = P - (r + dtr - SPEED_OF_LIGHT_M_S * dts[i * 2] + dion + dtrp); //corrected pr with code bias, iono and tropo. Still needs the dtr(rx clock bias) and satellite clock bias (dts) vtl_data.pr_m(n) = pr_corrected_code_bias_vec[n] - tropo_vec[n] - iono_vec[n] + SPEED_OF_LIGHT_M_S * dts[n * 2]; - vtl_data.doppler_hz(n) = d_obs_data.at(n).D[0] - SPEED_OF_LIGHT_M_S *dts[1 + 2 * n] / Lambda_GPS_L1; + vtl_data.doppler_hz(n) = d_obs_data.at(n).D[0] - SPEED_OF_LIGHT_M_S * dts[1 + 2 * n] / Lambda_GPS_L1; vtl_data.carrier_phase_rads(n) = d_obs_data.at(n).L[0]; - vtl_data.pr_res(n) = pr_residual_vec[n]; + vtl_data.pr_res(n) = pr_residual_vec[n]; } //VTL input data extraction from rtklib structures /* Receiver position, velocity and clock */ @@ -1259,13 +1721,14 @@ bool Rtklib_Solver::get_PVT(const std::map &gnss_observables_ // pvt_sol.rr[4] = vtl_data.kf_state[4]; // pvt_sol.rr[5] = vtl_data.kf_state[5]; } - else{ + else + { //MAGL: the code should not enter here once the vtl has started // .. but it does! //and not only that but pvt_sol.rr seems to have NOT reasonable values - // pvt_sol.rr[0]=rx_position_and_time[0]; // [m] - // pvt_sol.rr[1]=rx_position_and_time[1]; // [m] - // pvt_sol.rr[2]=rx_position_and_time[2]; // [m] + // pvt_sol.rr[0]=rx_position_and_time[0]; // [m] + // pvt_sol.rr[1]=rx_position_and_time[1]; // [m] + // pvt_sol.rr[2]=rx_position_and_time[2]; // [m] // pvt_sol.rr[3]=4.2e6; // pvt_sol.rr[4]=4.2e6; // pvt_sol.rr[5]=4.2e6; @@ -1418,28 +1881,28 @@ bool Rtklib_Solver::get_PVT(const std::map &gnss_observables_ d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); tmp_double = vtl_data.rx_dts(1); d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); - for (int n = 0; n<6; n++) - { - tmp_double = vtl_data.sat_p(n, 0); - d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); - tmp_double = vtl_data.sat_p(n, 1); - d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); - tmp_double = vtl_data.sat_p(n, 2); - d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); - tmp_double = vtl_data.sat_v(n, 0); - d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); - tmp_double = vtl_data.sat_v(n, 1); - d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); - tmp_double = vtl_data.sat_v(n, 2); - d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); - tmp_double = vtl_data.pr_m(n); - d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); - tmp_double = vtl_data.doppler_hz(n); - d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); - tmp_double = vtl_data.sat_CN0_dB_hz(n); - d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); - } - + for (int n = 0; n < 6; n++) + { + tmp_double = vtl_data.sat_p(n, 0); + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + tmp_double = vtl_data.sat_p(n, 1); + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + tmp_double = vtl_data.sat_p(n, 2); + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + tmp_double = vtl_data.sat_v(n, 0); + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + tmp_double = vtl_data.sat_v(n, 1); + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + tmp_double = vtl_data.sat_v(n, 2); + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + tmp_double = vtl_data.pr_m(n); + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + tmp_double = vtl_data.doppler_hz(n); + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + tmp_double = vtl_data.sat_CN0_dB_hz(n); + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + } + // GEO user position Latitude [deg] tmp_double = this->get_latitude(); d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); diff --git a/src/algorithms/PVT/libs/rtklib_solver.h b/src/algorithms/PVT/libs/rtklib_solver.h index a7d5bab60..61ce86660 100644 --- a/src/algorithms/PVT/libs/rtklib_solver.h +++ b/src/algorithms/PVT/libs/rtklib_solver.h @@ -4,7 +4,7 @@ * data flow and structures * \authors
    *
  • 2017, Javier Arribas - *
  • 2017, Carles Fernandez + *
  • 2017-2023, Carles Fernandez *
  • 2007-2013, T. Takasu *
* @@ -23,7 +23,7 @@ * ----------------------------------------------------------------------------- * Copyright (C) 2007-2013, T. Takasu * Copyright (C) 2017-2019, Javier Arribas - * Copyright (C) 2017-2019, Carles Fernandez + * Copyright (C) 2017-2023, Carles Fernandez * All rights reserved. * * SPDX-License-Identifier: BSD-2-Clause @@ -41,6 +41,7 @@ #include "beidou_dnav_utc_model.h" #include "galileo_almanac.h" #include "galileo_ephemeris.h" +#include "galileo_has_data.h" #include "galileo_iono.h" #include "galileo_utc_model.h" #include "glonass_gnav_almanac.h" @@ -57,6 +58,7 @@ #include "monitor_pvt.h" #include "pvt_solution.h" #include "rtklib.h" +#include "rtklib_conversions.h" #include "vtl_data.h" #include "vtl_engine.h" #include @@ -64,6 +66,7 @@ #include #include #include +#include /** \addtogroup PVT * \{ */ @@ -95,6 +98,8 @@ public: double get_pdop() const override; double get_gdop() const override; Monitor_Pvt get_monitor_pvt() const; + void store_has_data(const Galileo_HAS_data& new_has_data); + void update_has_corrections(const std::map& obs_map); sol_t pvt_sol{}; std::array pvt_ssat{}; @@ -128,10 +133,23 @@ public: private: bool save_matfile() const; + void check_has_orbit_clock_validity(const std::map& obs_map); + void get_has_biases(const std::map& obs_map); + void get_current_has_obs_correction(const std::string& signal, uint32_t tow_obs, int prn); + std::array d_obs_data{}; std::array d_dop{}; std::map d_rtklib_freq_index; std::map d_rtklib_band_index; + + std::map> d_has_orbit_corrections_store_map; // first key is system, second key is PRN + std::map> d_has_clock_corrections_store_map; // first key is system, second key is PRN + + std::map>> d_has_code_bias_store_map; // first key is signal, second key is PRN + std::map>> d_has_phase_bias_store_map; // first key is signal, second key is PRN + + std::map> d_has_obs_corr_map; // first key is signal, second key is PRN + std::string d_dump_filename; std::ofstream d_dump_file; rtk_t d_rtk{}; diff --git a/src/algorithms/libs/rtklib/rtklib.h b/src/algorithms/libs/rtklib/rtklib.h index 064d7aa0b..b470dca83 100644 --- a/src/algorithms/libs/rtklib/rtklib.h +++ b/src/algorithms/libs/rtklib/rtklib.h @@ -4,7 +4,7 @@ * \authors
    *
  • 2007-2013, T. Takasu *
  • 2017, Javier Arribas - *
  • 2017, Carles Fernandez + *
  • 2017-2023, Carles Fernandez *
* * This is a derived work from RTKLIB http://www.rtklib.com/ @@ -22,7 +22,7 @@ * ----------------------------------------------------------------------------- * Copyright (C) 2007-2013, T. Takasu * Copyright (C) 2017, Javier Arribas - * Copyright (C) 2017, Carles Fernandez + * Copyright (C) 2017-2023, Carles Fernandez * All rights reserved. * * SPDX-License-Identifier: BSD-2-Clause @@ -442,15 +442,20 @@ typedef struct /* SV orbit parameters */ double A, e, i0, OMG0, omg, M0, deln, OMGd, idot; double crc, crs, cuc, cus, cic, cis; - double toes; /* Toe (s) in week */ - double fit; /* fit interval (h) */ - double f0, f1, f2; /* SV clock parameters (af0,af1,af2) */ - double tgd[4]; /* group delay parameters */ - /* GPS/QZS:tgd[0]=TGD */ - /* GAL :tgd[0]=BGD E5a/E1,tgd[1]=BGD E5b/E1 */ - /* BDS :tgd[0]=BGD1,tgd[1]=BGD2 */ - double isc[4]; /* GPS :isc[0]=ISCL1, isc[1]=ISCL2, isc[2]=ISCL5I, isc[3]=ISCL5Q */ - double Adot, ndot; /* Adot,ndot for CNAV */ + double toes; /* Toe (s) in week */ + double fit; /* fit interval (h) */ + double f0, f1, f2; /* SV clock parameters (af0,af1,af2) */ + double tgd[4]; /* group delay parameters */ + /* GPS/QZS:tgd[0]=TGD */ + /* GAL :tgd[0]=BGD E5a/E1,tgd[1]=BGD E5b/E1 */ + /* BDS :tgd[0]=BGD1,tgd[1]=BGD2 */ + double isc[4]; /* GPS :isc[0]=ISCL1, isc[1]=ISCL2, isc[2]=ISCL5I, isc[3]=ISCL5Q */ + double Adot, ndot; /* Adot,ndot for CNAV */ + float has_clock_correction_m; /* Galileo High Accuracy Service clock correction, in [m] */ + float has_orbit_radial_correction_m; /* Galileo High Accuracy Service orbit radial correction, in [m] */ + float has_orbit_in_track_correction_m; /* Galileo High Accuracy Service orbit in-track correction, in [m] */ + float has_orbit_cross_track_correction_m; /* Galileo High Accuracy Service orbit cross-track correction, in [m] */ + bool apply_has_corrections; } eph_t; diff --git a/src/algorithms/libs/rtklib/rtklib_conversions.cc b/src/algorithms/libs/rtklib/rtklib_conversions.cc index b7e50519c..e8082b729 100644 --- a/src/algorithms/libs/rtklib/rtklib_conversions.cc +++ b/src/algorithms/libs/rtklib/rtklib_conversions.cc @@ -28,13 +28,17 @@ #include "gps_ephemeris.h" // for Gps_Ephemeris #include "rtklib_rtkcmn.h" #include -#include -#include -obsd_t insert_obs_to_rtklib(obsd_t& rtklib_obs, const Gnss_Synchro& gnss_synchro, int week, int band, bool pre_2009_file) + +obsd_t insert_obs_to_rtklib(obsd_t& rtklib_obs, + const Gnss_Synchro& gnss_synchro, + const std::map>& has_obs_corr, + int week, + int band, + bool pre_2009_file) { // Get signal type info to adjust code type based on constellation - std::string sig_ = gnss_synchro.Signal; + const std::string sig_(gnss_synchro.Signal, 2); rtklib_obs.D[band] = gnss_synchro.Carrier_Doppler_hz; rtklib_obs.P[band] = gnss_synchro.Pseudorange_m; @@ -127,10 +131,275 @@ obsd_t insert_obs_to_rtklib(obsd_t& rtklib_obs, const Gnss_Synchro& gnss_synchro } rtklib_obs.rcv = 1; + + if (!has_obs_corr.empty()) + { + float has_pseudorange_correction_m = 0.0; + float has_bias_correction_cycle = 0.0; + switch (gnss_synchro.System) + { + case 'G': + { + if (sig_ == "1C") + { + const auto it = has_obs_corr.find("L1 C/A"); + if (it != has_obs_corr.cend()) + { + const auto it2 = it->second.find(static_cast(gnss_synchro.PRN)); + if (it2 != it->second.cend()) + { + has_pseudorange_correction_m = it2->second.code_bias_m; + has_bias_correction_cycle = it2->second.phase_bias_cycle; + } + } + } + else if (sig_ == "2S") + { + const auto it = has_obs_corr.find("L2 CM"); + if (it != has_obs_corr.cend()) + { + const auto it2 = it->second.find(static_cast(gnss_synchro.PRN)); + if (it2 != it->second.cend()) + { + has_pseudorange_correction_m = it2->second.code_bias_m; + has_bias_correction_cycle = it2->second.phase_bias_cycle; + } + } + } + else if (sig_ == "L5") + { + // TODO: determine which one + const auto it = has_obs_corr.find("L5 I"); + if (it != has_obs_corr.cend()) + { + const auto it2 = it->second.find(static_cast(gnss_synchro.PRN)); + if (it2 != it->second.cend()) + { + has_pseudorange_correction_m = it2->second.code_bias_m; + has_bias_correction_cycle = it2->second.phase_bias_cycle; + } + } + else + { + const auto it_2nd_attempt = has_obs_corr.find("L5 Q"); + if (it_2nd_attempt != has_obs_corr.cend()) + { + const auto it2 = it_2nd_attempt->second.find(static_cast(gnss_synchro.PRN)); + if (it2 != it_2nd_attempt->second.cend()) + { + has_pseudorange_correction_m = it2->second.code_bias_m; + has_bias_correction_cycle = it2->second.phase_bias_cycle; + } + } + else + { + const auto it_3rd_attempt = has_obs_corr.find("L5 I + L5 Q"); + if (it_3rd_attempt != has_obs_corr.cend()) + { + const auto it2 = it_3rd_attempt->second.find(static_cast(gnss_synchro.PRN)); + if (it2 != it_3rd_attempt->second.cend()) + { + has_pseudorange_correction_m = it2->second.code_bias_m; + has_bias_correction_cycle = it2->second.phase_bias_cycle; + } + } + } + } + } + } + break; + case 'E': + { + if (sig_ == "1B") + { + // TODO: determine which one + const auto it = has_obs_corr.find("E1-B I/NAV OS"); + if (it != has_obs_corr.cend()) + { + const auto it2 = it->second.find(static_cast(gnss_synchro.PRN)); + if (it2 != it->second.cend()) + { + has_pseudorange_correction_m = it2->second.code_bias_m; + has_bias_correction_cycle = it2->second.phase_bias_cycle; + } + } + else + { + const auto it_2nd_attempt = has_obs_corr.find("E1-C"); + if (it_2nd_attempt != has_obs_corr.cend()) + { + const auto it2 = it_2nd_attempt->second.find(static_cast(gnss_synchro.PRN)); + if (it2 != it_2nd_attempt->second.cend()) + { + has_pseudorange_correction_m = it2->second.code_bias_m; + has_bias_correction_cycle = it2->second.phase_bias_cycle; + } + } + else + { + const auto it_3rd_attempt = has_obs_corr.find("E1-B + E1-C"); + if (it_3rd_attempt != has_obs_corr.cend()) + { + const auto it2 = it_3rd_attempt->second.find(static_cast(gnss_synchro.PRN)); + if (it2 != it_3rd_attempt->second.cend()) + { + has_pseudorange_correction_m = it2->second.code_bias_m; + has_bias_correction_cycle = it2->second.phase_bias_cycle; + } + } + } + } + } + else if (sig_ == "5X") + { + // TODO: determine which one + const auto it = has_obs_corr.find("E5a-I F/NAV OS"); + if (it != has_obs_corr.cend()) + { + const auto it2 = it->second.find(static_cast(gnss_synchro.PRN)); + if (it2 != it->second.cend()) + { + has_pseudorange_correction_m = it2->second.code_bias_m; + has_bias_correction_cycle = it2->second.phase_bias_cycle; + } + } + else + { + const auto it_2nd_attempt = has_obs_corr.find("E5a-Q"); + if (it_2nd_attempt != has_obs_corr.cend()) + { + const auto it2 = it_2nd_attempt->second.find(static_cast(gnss_synchro.PRN)); + if (it2 != it_2nd_attempt->second.cend()) + { + has_pseudorange_correction_m = it2->second.code_bias_m; + has_bias_correction_cycle = it2->second.phase_bias_cycle; + } + } + else + { + const auto it_3rd_attempt = has_obs_corr.find("E5a-I+E5a-Q"); + if (it_3rd_attempt != has_obs_corr.cend()) + { + const auto it2 = it_3rd_attempt->second.find(static_cast(gnss_synchro.PRN)); + if (it2 != it_3rd_attempt->second.cend()) + { + has_pseudorange_correction_m = it2->second.code_bias_m; + has_bias_correction_cycle = it2->second.phase_bias_cycle; + } + } + } + } + } + + else if (sig_ == "7X") + { + // TODO: determine which one + const auto it = has_obs_corr.find("E5bI I/NAV OS"); + if (it != has_obs_corr.cend()) + { + const auto it2 = it->second.find(static_cast(gnss_synchro.PRN)); + if (it2 != it->second.cend()) + { + has_pseudorange_correction_m = it2->second.code_bias_m; + has_bias_correction_cycle = it2->second.phase_bias_cycle; + } + } + else + { + const auto it_2nd_attempt = has_obs_corr.find("E5b-Q"); + if (it_2nd_attempt != has_obs_corr.cend()) + { + const auto it2 = it_2nd_attempt->second.find(static_cast(gnss_synchro.PRN)); + if (it2 != it_2nd_attempt->second.cend()) + { + has_pseudorange_correction_m = it2->second.code_bias_m; + has_bias_correction_cycle = it2->second.phase_bias_cycle; + } + } + else + { + const auto it_3rd_attempt = has_obs_corr.find("E5b-I+E5b-Q"); + if (it_3rd_attempt != has_obs_corr.cend()) + { + const auto it2 = it_3rd_attempt->second.find(static_cast(gnss_synchro.PRN)); + if (it2 != it_3rd_attempt->second.cend()) + { + has_pseudorange_correction_m = it2->second.code_bias_m; + has_bias_correction_cycle = it2->second.phase_bias_cycle; + } + } + } + } + } + else if (sig_ == "6B") + { + // TODO: determine which one + const auto it = has_obs_corr.find("E6-B C/NAV HAS"); + if (it != has_obs_corr.cend()) + { + const auto it2 = it->second.find(static_cast(gnss_synchro.PRN)); + if (it2 != it->second.cend()) + { + has_pseudorange_correction_m = it2->second.code_bias_m; + has_bias_correction_cycle = it2->second.phase_bias_cycle; + } + } + else + { + const auto it_2nd_attempt = has_obs_corr.find("E6-C"); + if (it_2nd_attempt != has_obs_corr.cend()) + { + const auto it2 = it_2nd_attempt->second.find(static_cast(gnss_synchro.PRN)); + if (it2 != it_2nd_attempt->second.cend()) + { + has_pseudorange_correction_m = it2->second.code_bias_m; + has_bias_correction_cycle = it2->second.phase_bias_cycle; + } + } + else + { + const auto it_3rd_attempt = has_obs_corr.find("E6-B + E6-C"); + if (it_3rd_attempt != has_obs_corr.cend()) + { + const auto it2 = it_3rd_attempt->second.find(static_cast(gnss_synchro.PRN)); + if (it2 != it_3rd_attempt->second.cend()) + { + has_pseudorange_correction_m = it2->second.code_bias_m; + has_bias_correction_cycle = it2->second.phase_bias_cycle; + } + } + } + } + } + } + break; + default: + break; + } + + rtklib_obs.P[band] += has_pseudorange_correction_m; + rtklib_obs.L[band] += has_bias_correction_cycle; + } return rtklib_obs; } +obsd_t insert_obs_to_rtklib(obsd_t& rtklib_obs, + const Gnss_Synchro& gnss_synchro, + int week, + int band, + bool pre_2009_file) +{ + std::map> empty_map; + return insert_obs_to_rtklib(rtklib_obs, + gnss_synchro, + empty_map, + week, + band, + pre_2009_file); +} + + geph_t eph_to_rtklib(const Glonass_Gnav_Ephemeris& glonass_gnav_eph, const Glonass_Gnav_Utc_Model& gnav_clock_model) { int week; @@ -172,9 +441,19 @@ geph_t eph_to_rtklib(const Glonass_Gnav_Ephemeris& glonass_gnav_eph, const Glona eph_t eph_to_rtklib(const Galileo_Ephemeris& gal_eph) +{ + std::map empty_orbit_map; + std::map empty_clock_map; + return eph_to_rtklib(gal_eph, empty_orbit_map, empty_clock_map); +} + + +eph_t eph_to_rtklib(const Galileo_Ephemeris& gal_eph, + const std::map& orbit_correction_map, + const std::map& clock_correction_map) { eph_t rtklib_sat = {0, 0, 0, 0, 0, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0.0, 0.0, 0.0, 0.0, 0.0, - 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, {}, {}, 0.0, 0.0}; + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, {}, {}, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, false}; // Galileo is the third satellite system for RTKLIB, so, add the required offset to discriminate Galileo ephemeris rtklib_sat.sat = gal_eph.PRN + NSATGPS + NSATGLO; rtklib_sat.A = gal_eph.sqrtA * gal_eph.sqrtA; @@ -226,14 +505,54 @@ eph_t eph_to_rtklib(const Galileo_Ephemeris& gal_eph) rtklib_sat.toc = gpst2time(rtklib_sat.week, toc); rtklib_sat.ttr = gpst2time(rtklib_sat.week, tow); + if (!orbit_correction_map.empty() && !clock_correction_map.empty()) + { + int count_has_corrections = 0; + const auto it_orbit = orbit_correction_map.find(static_cast(gal_eph.PRN)); + if (it_orbit != orbit_correction_map.cend()) + { + rtklib_sat.has_orbit_radial_correction_m = it_orbit->second.radial_m; + rtklib_sat.has_orbit_in_track_correction_m = it_orbit->second.in_track_m; + rtklib_sat.has_orbit_cross_track_correction_m = it_orbit->second.cross_track_m; + count_has_corrections++; + } + + const auto it_clock = clock_correction_map.find(static_cast(gal_eph.PRN)); + if (it_clock != clock_correction_map.cend()) + { + rtklib_sat.has_clock_correction_m = it_clock->second.clock_correction_m; + count_has_corrections++; + } + rtklib_sat.apply_has_corrections = (count_has_corrections == 2) ? true : false; + if (rtklib_sat.apply_has_corrections) + { + rtklib_sat.tgd[0] = 0.0; + rtklib_sat.tgd[1] = 0.0; + } + } + else + { + rtklib_sat.apply_has_corrections = false; + } return rtklib_sat; } eph_t eph_to_rtklib(const Gps_Ephemeris& gps_eph, bool pre_2009_file) +{ + std::map empty_orbit_map; + std::map empty_clock_map; + return eph_to_rtklib(gps_eph, empty_orbit_map, empty_clock_map, pre_2009_file); +} + + +eph_t eph_to_rtklib(const Gps_Ephemeris& gps_eph, + const std::map& orbit_correction_map, + const std::map& clock_correction_map, + bool pre_2009_file) { eph_t rtklib_sat = {0, 0, 0, 0, 0, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0.0, 0.0, 0.0, 0.0, 0.0, - 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, {}, {}, 0.0, 0.0}; + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, {}, {}, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, false}; rtklib_sat.sat = gps_eph.PRN; rtklib_sat.A = gps_eph.sqrtA * gps_eph.sqrtA; rtklib_sat.M0 = gps_eph.M_0; @@ -284,6 +603,40 @@ eph_t eph_to_rtklib(const Gps_Ephemeris& gps_eph, bool pre_2009_file) rtklib_sat.toc = gpst2time(rtklib_sat.week, toc); rtklib_sat.ttr = gpst2time(rtklib_sat.week, tow); + if (!orbit_correction_map.empty() && !clock_correction_map.empty()) + { + int count_has_corrections = 0; + const auto it_orbit = orbit_correction_map.find(static_cast(gps_eph.PRN)); + if (it_orbit != orbit_correction_map.cend()) + { + rtklib_sat.has_orbit_radial_correction_m = it_orbit->second.radial_m; + rtklib_sat.has_orbit_in_track_correction_m = it_orbit->second.in_track_m; + rtklib_sat.has_orbit_cross_track_correction_m = it_orbit->second.cross_track_m; + count_has_corrections++; + } + + const auto it_clock = clock_correction_map.find(static_cast(gps_eph.PRN)); + if (it_clock != clock_correction_map.cend()) + { + rtklib_sat.has_clock_correction_m = it_clock->second.clock_correction_m; + count_has_corrections++; + } + rtklib_sat.apply_has_corrections = (count_has_corrections == 2) ? true : false; + if (rtklib_sat.apply_has_corrections) + { + rtklib_sat.tgd[0] = 0.0; + rtklib_sat.tgd[1] = 0.0; + } + } + else + { + rtklib_sat.has_orbit_radial_correction_m = 0.0; + rtklib_sat.has_orbit_in_track_correction_m = 0.0; + rtklib_sat.has_orbit_cross_track_correction_m = 0.0; + rtklib_sat.has_clock_correction_m = 0.0; + rtklib_sat.apply_has_corrections = false; + } + return rtklib_sat; } @@ -291,7 +644,7 @@ eph_t eph_to_rtklib(const Gps_Ephemeris& gps_eph, bool pre_2009_file) eph_t eph_to_rtklib(const Beidou_Dnav_Ephemeris& bei_eph) { eph_t rtklib_sat = {0, 0, 0, 0, 0, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0.0, 0.0, 0.0, 0.0, 0.0, - 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, {}, {}, 0.0, 0.0}; + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, {}, {}, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, false}; rtklib_sat.sat = bei_eph.PRN + NSATGPS + NSATGLO + NSATGAL + NSATQZS; rtklib_sat.A = bei_eph.sqrtA * bei_eph.sqrtA; rtklib_sat.M0 = bei_eph.M_0; @@ -353,6 +706,12 @@ eph_t eph_to_rtklib(const Beidou_Dnav_Ephemeris& bei_eph) rtklib_sat.toc = gpst2time(rtklib_sat.week, toc); rtklib_sat.ttr = gpst2time(rtklib_sat.week, tow); + rtklib_sat.has_orbit_radial_correction_m = 0.0; + rtklib_sat.has_orbit_in_track_correction_m = 0.0; + rtklib_sat.has_orbit_cross_track_correction_m = 0.0; + rtklib_sat.has_clock_correction_m = 0.0; + rtklib_sat.apply_has_corrections = false; + return rtklib_sat; } @@ -360,7 +719,7 @@ eph_t eph_to_rtklib(const Beidou_Dnav_Ephemeris& bei_eph) eph_t eph_to_rtklib(const Gps_CNAV_Ephemeris& gps_cnav_eph) { eph_t rtklib_sat = {0, 0, 0, 0, 0, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0.0, 0.0, 0.0, 0.0, 0.0, - 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, {}, {}, 0.0, 0.0}; + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, {}, {}, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, false}; rtklib_sat.sat = gps_cnav_eph.PRN; rtklib_sat.A = gps_cnav_eph.sqrtA * gps_cnav_eph.sqrtA; rtklib_sat.M0 = gps_cnav_eph.M_0; @@ -415,6 +774,12 @@ eph_t eph_to_rtklib(const Gps_CNAV_Ephemeris& gps_cnav_eph) rtklib_sat.toc = gpst2time(rtklib_sat.week, toc); rtklib_sat.ttr = gpst2time(rtklib_sat.week, tow); + rtklib_sat.has_orbit_radial_correction_m = 0.0; + rtklib_sat.has_orbit_in_track_correction_m = 0.0; + rtklib_sat.has_orbit_cross_track_correction_m = 0.0; + rtklib_sat.has_clock_correction_m = 0.0; + rtklib_sat.apply_has_corrections = false; + return rtklib_sat; } diff --git a/src/algorithms/libs/rtklib/rtklib_conversions.h b/src/algorithms/libs/rtklib/rtklib_conversions.h index d3109002e..84b077b6f 100644 --- a/src/algorithms/libs/rtklib/rtklib_conversions.h +++ b/src/algorithms/libs/rtklib/rtklib_conversions.h @@ -18,6 +18,9 @@ #define GNSS_SDR_RTKLIB_CONVERSIONS_H #include "rtklib.h" +#include +#include +#include /** \addtogroup PVT * \{ */ @@ -35,8 +38,48 @@ class Gps_Almanac; class Gps_CNAV_Ephemeris; class Gps_Ephemeris; +class HAS_clock_corrections +{ +public: + HAS_clock_corrections() = default; + float clock_correction_m{}; + uint32_t valid_until{}; +}; + +class HAS_orbit_corrections +{ +public: + HAS_orbit_corrections() = default; + float radial_m{}; + float in_track_m{}; + float cross_track_m{}; + uint32_t valid_until{}; + uint16_t iod{}; +}; + +class HAS_obs_corrections +{ +public: + HAS_obs_corrections() = default; + float code_bias_m{}; + float phase_bias_cycle{}; +}; + + eph_t eph_to_rtklib(const Galileo_Ephemeris& gal_eph); -eph_t eph_to_rtklib(const Gps_Ephemeris& gps_eph, bool pre_2009_file); + +eph_t eph_to_rtklib(const Galileo_Ephemeris& gal_eph, + const std::map& orbit_correction_map, + const std::map& clock_correction_map); + +eph_t eph_to_rtklib(const Gps_Ephemeris& gps_eph, + bool pre_2009_file = false); + +eph_t eph_to_rtklib(const Gps_Ephemeris& gps_eph, + const std::map& orbit_correction_map, + const std::map& clock_correction_map, + bool pre_2009_file = false); + eph_t eph_to_rtklib(const Gps_CNAV_Ephemeris& gps_cnav_eph); eph_t eph_to_rtklib(const Beidou_Dnav_Ephemeris& bei_eph); @@ -50,6 +93,13 @@ alm_t alm_to_rtklib(const Galileo_Almanac& gal_alm); */ geph_t eph_to_rtklib(const Glonass_Gnav_Ephemeris& glonass_gnav_eph, const Glonass_Gnav_Utc_Model& gnav_clock_model); +obsd_t insert_obs_to_rtklib(obsd_t& rtklib_obs, + const Gnss_Synchro& gnss_synchro, + const std::map>& has_obs_corr, + int week, + int band, + bool pre_2009_file = false); + obsd_t insert_obs_to_rtklib(obsd_t& rtklib_obs, const Gnss_Synchro& gnss_synchro, int week, int band, bool pre_2009_file = false); diff --git a/src/algorithms/libs/rtklib/rtklib_ephemeris.cc b/src/algorithms/libs/rtklib/rtklib_ephemeris.cc index 6b095bdcd..3bd092a7a 100644 --- a/src/algorithms/libs/rtklib/rtklib_ephemeris.cc +++ b/src/algorithms/libs/rtklib/rtklib_ephemeris.cc @@ -4,7 +4,7 @@ * \authors
    *
  • 2007-2013, T. Takasu *
  • 2017, Javier Arribas - *
  • 2017, Carles Fernandez + *
  • 2017-2023, Carles Fernandez *
* * This is a derived work from RTKLIB http://www.rtklib.com/ @@ -22,7 +22,7 @@ * ----------------------------------------------------------------------------- * Copyright (C) 2007-2013, T. Takasu * Copyright (C) 2017, Javier Arribas - * Copyright (C) 2017, Carles Fernandez + * Copyright (C) 2017-2023, Carles Fernandez * All rights reserved. * * SPDX-License-Identifier: BSD-2-Clause @@ -231,6 +231,7 @@ void eph2pos(gtime_t time, const eph_t *eph, double *rs, double *dts, int sys; int prn; + double has_relativistic_correction = 0.0; trace(4, "eph2pos : time=%s sat=%2d\n", time_str(time, 3), eph->sat); if (eph->A <= 0.0) @@ -307,12 +308,102 @@ void eph2pos(gtime_t time, const eph_t *eph, double *rs, double *dts, rs[0] = x * cosO - y * cosi * sinO; rs[1] = x * sinO + y * cosi * cosO; rs[2] = y * sin(i); + // Apply HAS orbit correction if available + if (eph->apply_has_corrections) + { + // HAS SIS ICD, Issue 1.0, Section 7.2 + double vel_sat[3]{}; + double cross_pos_vel[3]{}; + double et[3]{}; + double ew[3]{}; + double en[3]{}; + double R[3][3]{}; + double corrections[3]{}; + double rotated_corrections[3]{}; + // Compute satellite velocity + const double OneMinusecosE = 1.0 - (eph->e * cosE); + const double ekdot = (sqrt(mu / (eph->A * eph->A * eph->A)) + eph->deln) / OneMinusecosE; + const double pkdot = sqrt(1.0 - eph->e * eph->e) * ekdot / OneMinusecosE; + const double ukdot = pkdot * (1.0 + 2.0 * (eph->cus * cos2u - eph->cuc * sin2u)); + const double ikdot = eph->idot + 2.0 * pkdot * (eph->cis * cos2u - eph->cic * sin2u); + const double rkdot = eph->A * eph->e * sinE * ekdot + 2.0 * pkdot * (eph->crs * cos2u - eph->crc * sin2u); + const double xpkdot = rkdot * cos(u) - y * ukdot; + const double ypkdot = rkdot * sin(u) + x * ukdot; + const double tmp = ypkdot * cosi - rs[2] * ikdot; + + vel_sat[0] = -(eph->OMGd - omge) * rs[1] + xpkdot * cosO - tmp * sinO; + vel_sat[1] = (eph->OMGd - omge) * rs[0] + xpkdot * sinO + tmp * cosO; + vel_sat[2] = y * cosi * ikdot + ypkdot * sin(i); + + // Compute HAS relativistic clock correction (HAS SIS ICD, Issue 1.0, Section 7.3) + const double pos_by_vel = rs[0] * vel_sat[0] + rs[1] * vel_sat[1] + rs[2] * vel_sat[2]; + has_relativistic_correction = -(2.0 * pos_by_vel) / (SPEED_OF_LIGHT_M_S * SPEED_OF_LIGHT_M_S); + + // Compute rotation matrix + const double norm_velocity = sqrt(vel_sat[0] * vel_sat[0] + vel_sat[1] * vel_sat[1] + vel_sat[2] * vel_sat[2]); + et[0] = vel_sat[0] / norm_velocity; + et[1] = vel_sat[1] / norm_velocity; + et[2] = vel_sat[2] / norm_velocity; + + cross_pos_vel[0] = rs[1] * vel_sat[2] - rs[2] * vel_sat[1]; + cross_pos_vel[1] = rs[2] * vel_sat[0] - rs[0] * vel_sat[2]; + cross_pos_vel[2] = rs[0] * vel_sat[1] - rs[1] * vel_sat[0]; + const double norm_cross_pos_vel = sqrt(cross_pos_vel[0] * cross_pos_vel[0] + cross_pos_vel[1] * cross_pos_vel[1] + cross_pos_vel[2] * cross_pos_vel[2]); + + ew[0] = cross_pos_vel[0] / norm_cross_pos_vel; + ew[1] = cross_pos_vel[1] / norm_cross_pos_vel; + ew[2] = cross_pos_vel[2] / norm_cross_pos_vel; + + en[0] = et[1] * ew[2] - et[2] * ew[1]; + en[1] = et[2] * ew[0] - et[0] * ew[2]; + en[2] = et[0] * ew[1] - et[1] * ew[0]; + + R[0][0] = en[0]; + R[0][1] = et[0]; + R[0][2] = ew[0]; + + R[1][0] = en[1]; + R[1][1] = et[1]; + R[1][2] = ew[1]; + + R[2][0] = en[2]; + R[2][1] = et[2]; + R[2][2] = ew[2]; + + // Compute rotated corrections + corrections[0] = eph->has_orbit_radial_correction_m; + corrections[1] = eph->has_orbit_in_track_correction_m; + corrections[2] = eph->has_orbit_cross_track_correction_m; + + for (int row = 0; row < 3; row++) + { + for (int col = 0; col < 3; col++) + { + rotated_corrections[row] = R[row][col] * corrections[col]; + } + } + + // Apply HAS orbit corrections + rs[0] += rotated_corrections[0]; + rs[1] += rotated_corrections[1]; + rs[2] += rotated_corrections[2]; + } } tk = timediffweekcrossover(time, eph->toc); *dts = eph->f0 + eph->f1 * tk + eph->f2 * tk * tk; /* relativity correction */ - *dts -= 2.0 * sqrt(mu * eph->A) * eph->e * sinE / std::pow(SPEED_OF_LIGHT_M_S, 2.0); + if (eph->apply_has_corrections) + { + // Apply HAS clock correction (HAS SIS ICD, Issue 1.0, Section 7.3) + *dts += (has_relativistic_correction + (eph->has_clock_correction_m / SPEED_OF_LIGHT_M_S)); + // Note: This is referred to the GST for Galileo satellites. The user must account for + // a possible common offset in the broadcast HAS GPS clock corrections + } + else + { + *dts -= 2.0 * sqrt(mu * eph->A) * eph->e * sinE / (SPEED_OF_LIGHT_M_S * SPEED_OF_LIGHT_M_S); + } /* position and clock error variance */ *var = var_uraeph(eph->sva); diff --git a/src/algorithms/libs/rtklib/rtklib_rtcm.cc b/src/algorithms/libs/rtklib/rtklib_rtcm.cc index d67199292..db431f513 100644 --- a/src/algorithms/libs/rtklib/rtklib_rtcm.cc +++ b/src/algorithms/libs/rtklib/rtklib_rtcm.cc @@ -49,7 +49,7 @@ int init_rtcm(rtcm_t *rtcm) obsd_t data0 = {{0, 0.0}, 0, 0, {0}, {0}, {0}, {0.0}, {0.0}, {0.0}}; eph_t eph0 = {0, -1, -1, 0, 0, 0, 0, 0, {0, 0.0}, {0, 0.0}, {0, 0.0}, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, - 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, {0.0}, {0.0}, 0.0, 0.0}; + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, {0.0}, {0.0}, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, false}; geph_t geph0 = {0, -1, 0, 0, 0, 0, {0, 0.0}, {0, 0.0}, {0.0}, {0.0}, {0.0}, 0.0, 0.0, 0.0}; ssr_t ssr0 = {{{0, 0.0}}, {0.0}, {0}, 0, 0, 0, 0, {0.0}, {0.0}, {0.0}, 0.0, {0.0}, {0.0}, {0.0}, 0.0, 0.0, '0'}; diff --git a/src/algorithms/libs/rtklib/rtklib_rtcm2.cc b/src/algorithms/libs/rtklib/rtklib_rtcm2.cc index 9ae477aff..b07bdd226 100644 --- a/src/algorithms/libs/rtklib/rtklib_rtcm2.cc +++ b/src/algorithms/libs/rtklib/rtklib_rtcm2.cc @@ -228,7 +228,7 @@ int decode_type17(rtcm_t *rtcm, bool pre_2009_file) { eph_t eph = {0, -1, -1, 0, 0, 0, 0, 0, {0, 0.0}, {0, 0.0}, {0, 0.0}, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, - 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, {0.0}, {0.0}, 0.0, 0.0}; + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, {0.0}, {0.0}, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, false}; double toc; double sqrtA; int i = 48; diff --git a/src/algorithms/libs/rtklib/rtklib_rtcm3.cc b/src/algorithms/libs/rtklib/rtklib_rtcm3.cc index 6f2f7b204..afed31c1f 100644 --- a/src/algorithms/libs/rtklib/rtklib_rtcm3.cc +++ b/src/algorithms/libs/rtklib/rtklib_rtcm3.cc @@ -1019,7 +1019,7 @@ int decode_type1019(rtcm_t *rtcm, bool pre_2009_file) { eph_t eph = {0, -1, -1, 0, 0, 0, 0, 0, {0, 0.0}, {0, 0.0}, {0, 0.0}, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, - 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, {0.0}, {0.0}, 0.0, 0.0}; + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, {0.0}, {0.0}, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, false}; double toc; double sqrtA; char *msg; @@ -1518,7 +1518,7 @@ int decode_type1044(rtcm_t *rtcm, bool pre_2009_file) { eph_t eph = {0, -1, -1, 0, 0, 0, 0, 0, {0, 0.0}, {0, 0.0}, {0, 0.0}, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, - 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, {0.0}, {0.0}, 0.0, 0.0}; + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, {0.0}, {0.0}, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, false}; double toc; double sqrtA; char *msg; @@ -1631,7 +1631,7 @@ int decode_type1045(rtcm_t *rtcm) { eph_t eph = {0, -1, -1, 0, 0, 0, 0, 0, {0, 0.0}, {0, 0.0}, {0, 0.0}, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, - 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, {0.0}, {0.0}, 0.0, 0.0}; + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, {0.0}, {0.0}, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, false}; double toc; double sqrtA; char *msg; @@ -1745,7 +1745,7 @@ int decode_type1046(rtcm_t *rtcm) { eph_t eph = {0, -1, -1, 0, 0, 0, 0, 0, {0, 0.0}, {0, 0.0}, {0, 0.0}, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, - 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, {0.0}, {0.0}, 0.0, 0.0}; + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, {0.0}, {0.0}, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, false}; double toc; double sqrtA; char *msg; @@ -1859,7 +1859,7 @@ int decode_type1047(rtcm_t *rtcm) { eph_t eph = {0, -1, -1, 0, 0, 0, 0, 0, {0, 0.0}, {0, 0.0}, {0, 0.0}, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, - 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, {0.0}, {0.0}, 0.0, 0.0}; + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, {0.0}, {0.0}, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, false}; double toc; double sqrtA; char *msg; @@ -1976,7 +1976,7 @@ int decode_type63(rtcm_t *rtcm) { eph_t eph = {0, -1, -1, 0, 0, 0, 0, 0, {0, 0.0}, {0, 0.0}, {0, 0.0}, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, - 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, {0.0}, {0.0}, 0.0, 0.0}; + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, {0.0}, {0.0}, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, false}; double toc; double sqrtA; char *msg; diff --git a/src/algorithms/libs/rtklib/rtklib_rtkcmn.cc b/src/algorithms/libs/rtklib/rtklib_rtkcmn.cc index 40a271ece..b4074abb8 100644 --- a/src/algorithms/libs/rtklib/rtklib_rtkcmn.cc +++ b/src/algorithms/libs/rtklib/rtklib_rtkcmn.cc @@ -3610,7 +3610,7 @@ int readnav(const char *file, nav_t *nav) { FILE *fp; eph_t eph0 = {0, 0, 0, 0, 0, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0.0, 0.0, 0.0, 0.0, 0.0, - 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, {}, {}, 0.0, 0.0}; + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, {}, {}, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, false}; geph_t geph0 = {0, 0, 0, 0, 0, 0, {0, 0}, {0, 0}, {}, {}, {}, 0.0, 0.0, 0.0}; char buff[4096]; char *p; diff --git a/src/algorithms/libs/rtklib/rtklib_rtksvr.cc b/src/algorithms/libs/rtklib/rtklib_rtksvr.cc index 998a067a1..fcf2b0cdc 100644 --- a/src/algorithms/libs/rtklib/rtklib_rtksvr.cc +++ b/src/algorithms/libs/rtklib/rtklib_rtksvr.cc @@ -688,7 +688,7 @@ int rtksvrinit(rtksvr_t *svr) '0', '0', '0', 0, 0, 0}; eph_t eph0 = {0, -1, -1, 0, 0, 0, 0, 0, {0, 0.0}, {0, 0.0}, {0, 0.0}, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, - 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, {0.0}, {0.0}, 0.0, 0.0}; + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, {0.0}, {0.0}, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, false}; geph_t geph0 = {0, -1, 0, 0, 0, 0, {0, 0.0}, {0, 0.0}, {0.0}, {0.0}, {0.0}, 0.0, 0.0, 0.0}; seph_t seph0 = {0, {0, 0.0}, {0, 0.0}, 0, 0, {0.0}, {0.0}, {0.0}, 0.0, 0.0}; diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/CMakeLists.txt b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/CMakeLists.txt index 3ca3f822f..40286d2cb 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/CMakeLists.txt +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/CMakeLists.txt @@ -258,7 +258,7 @@ endif() # cpu_features - sensible defaults, user settable option if(CMAKE_SYSTEM_PROCESSOR MATCHES - "(^mips)|(^arm)|(^aarch64)|(x86_64)|(AMD64|amd64)|(^i.86$)|(^powerpc)|(^ppc)|(^s390x)") + "(^mips)|(^arm)|(^aarch64)|(x86_64)|(AMD64|amd64)|(^i.86$)|(^powerpc)|(^ppc)|(^s390x)|^riscv") option(VOLK_CPU_FEATURES "volk-gnsssdr uses cpu_features" ON) else() option(VOLK_CPU_FEATURES "volk-gnsssdr uses cpu_features" OFF) @@ -266,7 +266,13 @@ endif() if(CMAKE_VERSION VERSION_GREATER 3.0 AND VOLK_CPU_FEATURES) find_package(CPUFEATURES) - set(USE_CPU_FEATURES ON) + if(CPUFEATURES_FOUND AND (CMAKE_SYSTEM_PROCESSOR MATCHES "(^s390x)|^riscv") AND (CPUFEATURES_VERSION VERSION_LESS "0.8.0")) + set(USE_CPU_FEATURES OFF) + unset(CPUFEATURES_FOUND CACHE) + message(STATUS "Building volk-gnsssdr without cpu_features, installed version v${CPUFEATURES_VERSION} does not support the ${CMAKE_SYSTEM_PROCESSOR} architecture") + else() + set(USE_CPU_FEATURES ON) + endif() if(NOT CPUFEATURES_FOUND) message(STATUS "Building volk-gnsssdr with cpu_features") set(BUILD_TESTING OFF CACHE BOOL "Build cpu_features without tests." FORCE) @@ -290,13 +296,8 @@ endif() # Python include(VolkPython) # sets PYTHON_EXECUTABLE -volk_python_check_module("python >= 2.7" sys "sys.version.split()[0] >= '2.7'" PYTHON_MIN_VER_FOUND) -volk_python_check_module("mako >= 0.4.2" mako "mako.__version__ >= '0.4.2'" MAKO_FOUND) -if(Python2_VERSION OR (PYTHON_VERSION_STRING VERSION_LESS "3.0")) - volk_python_check_module("six - python 2 and 3 compatibility library" six "True" SIX_FOUND) -endif() -if(NOT PYTHON_MIN_VER_FOUND) +if(NOT PYTHON_EXECUTABLE) message(FATAL_ERROR "Python 2.7 or greater required to build VOLK_GNSSSDR") endif() diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/Modules/VolkPython.cmake b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/Modules/VolkPython.cmake index fcaabe4ff..2fc0819b7 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/Modules/VolkPython.cmake +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cmake/Modules/VolkPython.cmake @@ -16,13 +16,22 @@ set(__INCLUDED_VOLK_PYTHON_CMAKE TRUE) # - cmd an additional command to run # - have the result variable to set ######################################################################## -macro(VOLK_PYTHON_CHECK_MODULE_RAW desc python_code have) +macro(VOLK_PYTHON_CHECK_MODULE desc mod cmd have) + message(STATUS "Python checking for ${desc}") execute_process( - COMMAND ${PYTHON_EXECUTABLE} -c "${python_code}" + COMMAND ${PYTHON_EXECUTABLE} -c " +######################################### +try: import ${mod} +except: + try: ${mod} + except: exit(-1) +try: assert ${cmd} +except: exit(-1) +#########################################" OUTPUT_QUIET ERROR_QUIET - RESULT_VARIABLE return_code + RESULT_VARIABLE ${have} ) - if(return_code EQUAL 0) + if(${have} EQUAL 0) message(STATUS "Python checking for ${desc} - found") set(${have} TRUE) else() @@ -31,19 +40,6 @@ macro(VOLK_PYTHON_CHECK_MODULE_RAW desc python_code have) endif() endmacro() -macro(VOLK_PYTHON_CHECK_MODULE desc mod cmd have) - volk_python_check_module_raw( - "${desc}" " -######################################### -try: - import ${mod} - assert ${cmd} -except (ImportError, AssertionError): exit(-1) -except: pass -#########################################" - "${have}") -endmacro() - ######################################################################## # Setup the python interpreter: @@ -57,6 +53,9 @@ if(CMAKE_VERSION VERSION_LESS 3.12 OR CMAKE_CROSSCOMPILING) if(PYTHON_EXECUTABLE) message(STATUS "User set python executable ${PYTHON_EXECUTABLE}") find_package(PythonInterp ${VOLK_PYTHON_MIN_VERSION} REQUIRED) + if(PYTHON_VERSION_STRING VERSION_LESS "3.0") + volk_python_check_module("six - python 2 and 3 compatibility library" six "True" SIX_FOUND) + endif() else() message(STATUS "PYTHON_EXECUTABLE not set - trying by default python3") message(STATUS "Use -DPYTHON_EXECUTABLE=/path/to/python to build for python 2.7") @@ -65,12 +64,18 @@ if(CMAKE_VERSION VERSION_LESS 3.12 OR CMAKE_CROSSCOMPILING) if(NOT PYTHONINTERP_FOUND) message(STATUS "python3 not found - trying with python2.7") find_package(PythonInterp ${VOLK_PYTHON_MIN_VERSION} REQUIRED) + volk_python_check_module("six - python 2 and 3 compatibility library" six "True" SIX_FOUND) endif() endif() + volk_python_check_module("mako >= 0.4.2" mako "mako.__version__ >= '0.4.2'" MAKO_FOUND) else() if(PYTHON_EXECUTABLE) message(STATUS "User set python executable ${PYTHON_EXECUTABLE}") find_package(PythonInterp ${VOLK_PYTHON_MIN_VERSION} REQUIRED) + volk_python_check_module("mako >= 0.4.2" mako "mako.__version__ >= '0.4.2'" MAKO_FOUND) + if(PYTHON_VERSION_STRING VERSION_LESS "3.0") + volk_python_check_module("six - python 2 and 3 compatibility library" six "True" SIX_FOUND) + endif() else() if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") set(_previous ${CMAKE_FIND_FRAMEWORK}) @@ -98,6 +103,7 @@ else() if(NOT MAKO_FOUND OR NOT SIX_FOUND) unset(PYTHON_EXECUTABLE) find_package(PythonInterp ${VOLK_PYTHON_MIN_VERSION}) + volk_python_check_module("mako >= 0.4.2" mako "mako.__version__ >= '0.4.2'" MAKO_FOUND) endif() endif() endif() diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/CMakeLists.txt b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/CMakeLists.txt index d02de9ee7..56c411c53 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/CMakeLists.txt +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/CMakeLists.txt @@ -56,6 +56,7 @@ set(PROCESSOR_IS_AARCH64 FALSE) set(PROCESSOR_IS_X86 FALSE) set(PROCESSOR_IS_POWER FALSE) set(PROCESSOR_IS_S390X FALSE) +set(PROCESSOR_IS_RISCV FALSE) if(CMAKE_SYSTEM_PROCESSOR MATCHES "^mips") set(PROCESSOR_IS_MIPS TRUE) @@ -69,6 +70,8 @@ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(powerpc|ppc)") set(PROCESSOR_IS_POWER TRUE) elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(s390x)") set(PROCESSOR_IS_S390X TRUE) +elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^riscv") + set(PROCESSOR_IS_RISCV TRUE) endif() macro(add_cpu_features_headers_and_sources HDRS_LIST_NAME SRCS_LIST_NAME) @@ -90,6 +93,8 @@ macro(add_cpu_features_headers_and_sources HDRS_LIST_NAME SRCS_LIST_NAME) list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_ppc.h) elseif(PROCESSOR_IS_S390X) list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_s390x.h) + elseif(PROCESSOR_IS_RISCV) + list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_riscv.h) else() message(FATAL_ERROR "Unsupported architectures ${CMAKE_SYSTEM_PROCESSOR}") endif() diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/README.md b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/README.md index 972e56814..b23e8dec6 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/README.md +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/README.md @@ -158,14 +158,14 @@ flags : aes,avx,cx16,smx,sse4_1,sse4_2,ssse3 ## What's supported -| | x86³ | AArch64 | ARM | MIPS⁴ | s390x | POWER | -| ------- | :--: | :-----: | :-----: | :-----: | :-----: | :-----: | -| Linux | yes² | yes¹ | yes¹ | yes¹ | yes¹ | yes¹ | -| FreeBSD | yes² | not yet | not yet | not yet | not yet | not yet | -| MacOs | yes² | not yet | N/A | N/A | no | no | -| Windows | yes² | not yet | not yet | N/A | N/A | N/A | -| Android | yes² | yes¹ | yes¹ | yes¹ | N/A | N/A | -| iOS | N/A | not yet | not yet | N/A | N/A | N/A | +| | x86³ | AArch64 | ARM | MIPS⁴ | POWER | RISCV | s390x | +| ------- | :--: | :-----: | :-----: | :-----: | :-----: | :---: | :-----: | +| Linux | yes² | yes¹ | yes¹ | yes¹ | yes¹ | yes¹ | yes¹ | +| FreeBSD | yes² | not yet | not yet | not yet | not yet | N/A | not yet | +| MacOs | yes² | not yet | N/A | N/A | no | N/A | no | +| Windows | yes² | not yet | not yet | N/A | N/A | N/A | N/A | +| Android | yes² | yes¹ | yes¹ | yes¹ | N/A | N/A | N/A | +| iOS | N/A | not yet | not yet | N/A | N/A | N/A | N/A | 1. **Features revealed from Linux.** We gather data from several sources depending on availability: diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/include/cpuinfo_riscv.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/include/cpuinfo_riscv.h new file mode 100644 index 000000000..85bea6027 --- /dev/null +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/include/cpuinfo_riscv.h @@ -0,0 +1,62 @@ +// SPDX-FileCopyrightText: 2022 Google LLC +// SPDX-License-Identifier: Apache-2.0 + +#ifndef CPU_FEATURES_INCLUDE_CPUINFO_RISCV_H_ +#define CPU_FEATURES_INCLUDE_CPUINFO_RISCV_H_ + +#include "cpu_features_cache_info.h" +#include "cpu_features_macros.h" + +#if !defined(CPU_FEATURES_ARCH_RISCV) +#error "Including cpuinfo_riscv.h from a non-riscv target." +#endif + +CPU_FEATURES_START_CPP_NAMESPACE + +typedef struct +{ + // Base + int RV32I : 1; // Base Integer Instruction Set, 32-bit + int RV64I : 1; // Base Integer Instruction Set, 64-bit + + // Extension + int M : 1; // Standard Extension for Integer Multiplication/Division + int A : 1; // Standard Extension for Atomic Instructions + int F : 1; // Standard Extension for Single-Precision Floating-Point + int D : 1; // Standard Extension for Double-Precision Floating-Point + int Q : 1; // Standard Extension for Quad-Precision Floating-Point + int C : 1; // Standard Extension for Compressed Instructions + int Zicsr : 1; // Control and Status Register (CSR) + int Zifencei : 1; // Instruction-Fetch Fence +} RiscvFeatures; + +typedef struct +{ + RiscvFeatures features; + char uarch[64]; // 0 terminated string + char vendor[64]; // 0 terminated string +} RiscvInfo; + +typedef enum +{ + RISCV_RV32I, + RISCV_RV64I, + RISCV_M, + RISCV_A, + RISCV_F, + RISCV_D, + RISCV_Q, + RISCV_C, + RISCV_Zicsr, + RISCV_Zifencei, + RISCV_LAST_, +} RiscvFeaturesEnum; + +RiscvInfo GetRiscvInfo(void); +int GetRiscvFeaturesEnumValue(const RiscvFeatures* features, + RiscvFeaturesEnum value); +const char* GetRiscvFeaturesEnumName(RiscvFeaturesEnum); + +CPU_FEATURES_END_CPP_NAMESPACE + +#endif // CPU_FEATURES_INCLUDE_CPUINFO_RISCV_H_ \ No newline at end of file diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/include/internal/hwcaps.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/include/internal/hwcaps.h index 29da4837a..c5836af35 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/include/internal/hwcaps.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/include/internal/hwcaps.h @@ -193,15 +193,15 @@ CPU_FEATURES_START_CPP_NAMESPACE #define HWCAP_S390_SIE 4194304 // https://elixir.bootlin.com/linux/latest/source/arch/riscv/include/uapi/asm/hwcap.h -#define RISCV_HWCAP_A (1UL << ('A' - 'A')) -#define RISCV_HWCAP_C (1UL << ('C' - 'A')) -#define RISCV_HWCAP_D (1UL << ('D' - 'A')) -#define RISCV_HWCAP_E (1UL << ('E' - 'A')) -#define RISCV_HWCAP_F (1UL << ('F' - 'A')) -#define RISCV_HWCAP_I (1UL << ('I' - 'A')) +#define RISCV_HWCAP_32 0x32 +#define RISCV_HWCAP_64 0x64 +#define RISCV_HWCAP_128 0x128 #define RISCV_HWCAP_M (1UL << ('M' - 'A')) -#define RISCV_HWCAP_V (1UL << ('V' - 'A')) +#define RISCV_HWCAP_A (1UL << ('A' - 'A')) +#define RISCV_HWCAP_F (1UL << ('F' - 'A')) +#define RISCV_HWCAP_D (1UL << ('D' - 'A')) #define RISCV_HWCAP_Q (1UL << ('Q' - 'A')) +#define RISCV_HWCAP_C (1UL << ('C' - 'A')) typedef struct { diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/src/impl_riscv_linux.c b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/src/impl_riscv_linux.c new file mode 100644 index 000000000..4bcf440d5 --- /dev/null +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/src/impl_riscv_linux.c @@ -0,0 +1,109 @@ +// SPDX-FileCopyrightText: 2022 Google LLC +// SPDX-License-Identifier: Apache-2.0 + +#include "cpu_features_macros.h" + +#ifdef CPU_FEATURES_ARCH_RISCV +#if defined(CPU_FEATURES_OS_LINUX) + +#include "cpuinfo_riscv.h" + +// According to +// https://elixir.bootlin.com/linux/latest/source/Documentation/devicetree/bindings/riscv/cpus.yaml +// isa string should match the following regex +// ^rv(?:64|32)imaf?d?q?c?b?v?k?h?(?:_[hsxz](?:[a-z])+)*$ +// +// This means we can test for features in this exact order except for Z +// extensions. + +//////////////////////////////////////////////////////////////////////////////// +// Definitions for introspection. +//////////////////////////////////////////////////////////////////////////////// +#define INTROSPECTION_TABLE \ + LINE(RISCV_RV32I, RV32I, "rv32i", RISCV_HWCAP_32, 0) \ + LINE(RISCV_RV64I, RV64I, "rv64i", RISCV_HWCAP_64, 0) \ + LINE(RISCV_M, M, "m", RISCV_HWCAP_M, 0) \ + LINE(RISCV_A, A, "a", RISCV_HWCAP_A, 0) \ + LINE(RISCV_F, F, "f", RISCV_HWCAP_F, 0) \ + LINE(RISCV_D, D, "d", RISCV_HWCAP_D, 0) \ + LINE(RISCV_Q, Q, "q", RISCV_HWCAP_Q, 0) \ + LINE(RISCV_C, C, "c", RISCV_HWCAP_C, 0) \ + LINE(RISCV_Zicsr, Zicsr, "_zicsr", 0, 0) \ + LINE(RISCV_Zifencei, Zifencei, "_zifencei", 0, 0) +#define INTROSPECTION_PREFIX Riscv +#define INTROSPECTION_ENUM_PREFIX RISCV +#include "define_introspection_and_hwcaps.inl" + +//////////////////////////////////////////////////////////////////////////////// +// Implementation. +//////////////////////////////////////////////////////////////////////////////// + +#include "internal/filesystem.h" +#include "internal/stack_line_reader.h" +#include +#include + +static const RiscvInfo kEmptyRiscvInfo; + +static void HandleRiscVIsaLine(StringView line, RiscvFeatures* const features) +{ + for (size_t i = 0; i < RISCV_LAST_; ++i) + { + StringView flag = str(kCpuInfoFlags[i]); + int index_of_flag = CpuFeatures_StringView_IndexOf(line, flag); + bool is_set = index_of_flag != -1; + kSetters[i](features, is_set); + if (is_set) + line = CpuFeatures_StringView_PopFront(line, index_of_flag + flag.size); + } +} + +static bool HandleRiscVLine(const LineResult result, RiscvInfo* const info) +{ + StringView line = result.line; + StringView key, value; + if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) + { + if (CpuFeatures_StringView_IsEquals(key, str("isa"))) + { + HandleRiscVIsaLine(value, &info->features); + } + else if (CpuFeatures_StringView_IsEquals(key, str("uarch"))) + { + int index = CpuFeatures_StringView_IndexOfChar(value, ','); + if (index == -1) return true; + StringView vendor = CpuFeatures_StringView_KeepFront(value, index); + StringView uarch = CpuFeatures_StringView_PopFront(value, index + 1); + CpuFeatures_StringView_CopyString(vendor, info->vendor, + sizeof(info->vendor)); + CpuFeatures_StringView_CopyString(uarch, info->uarch, + sizeof(info->uarch)); + } + } + return !result.eof; +} + +static void FillProcCpuInfoData(RiscvInfo* const info) +{ + const int fd = CpuFeatures_OpenFile("/proc/cpuinfo"); + if (fd >= 0) + { + StackLineReader reader; + StackLineReader_Initialize(&reader, fd); + for (;;) + { + if (!HandleRiscVLine(StackLineReader_NextLine(&reader), info)) break; + } + CpuFeatures_CloseFile(fd); + } +} + +RiscvInfo GetRiscvInfo(void) +{ + RiscvInfo info = kEmptyRiscvInfo; + FillProcCpuInfoData(&info); + return info; +} + +#endif // defined(CPU_FEATURES_OS_LINUX) || defined(CPU_FEATURES_OS_ANDROID) +#endif // CPU_FEATURES_ARCH_RISCV \ No newline at end of file diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/src/utils/list_cpu_features.c b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/src/utils/list_cpu_features.c index 38489640c..647c4e05f 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/src/utils/list_cpu_features.c +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/src/utils/list_cpu_features.c @@ -25,6 +25,8 @@ #include "cpuinfo_ppc.h" #elif defined(CPU_FEATURES_ARCH_S390X) #include "cpuinfo_s390x.h" +#elif defined(CPU_FEATURES_ARCH_RISCV) +#include "cpuinfo_riscv.h" #endif // Design principles @@ -217,6 +219,9 @@ DEFINE_ADD_FLAGS(GetPPCFeaturesEnumValue, GetPPCFeaturesEnumName, PPCFeatures, #elif defined(CPU_FEATURES_ARCH_S390X) DEFINE_ADD_FLAGS(GetS390XFeaturesEnumValue, GetS390XFeaturesEnumName, S390XFeatures, S390X_LAST_) +#elif defined(CPU_FEATURES_ARCH_RISCV) +DEFINE_ADD_FLAGS(GetRiscvFeaturesEnumValue, GetRiscvFeaturesEnumName, RiscvFeatures, + RISCV_LAST_) #endif // Prints a json string with characters escaping. @@ -447,6 +452,12 @@ static Node* CreateTree(void) AddMapEntry(root, "model", CreateString(strings.type.platform)); AddMapEntry(root, "# processors", CreateInt(strings.num_processors)); AddFlags(root, &info.features); +#elif defined(CPU_FEATURES_ARCH_RISCV) + const RiscvInfo info = GetRiscvInfo(); + AddMapEntry(root, "arch", CreateString("risc-v")); + AddMapEntry(root, "vendor", CreateString(info.vendor)); + AddMapEntry(root, "microarchitecture", CreateString(info.uarch)); + AddFlags(root, &info.features); #endif return root; } diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/test/CMakeLists.txt b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/test/CMakeLists.txt index e887cbb55..8df134964 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/test/CMakeLists.txt +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/test/CMakeLists.txt @@ -99,3 +99,10 @@ if(PROCESSOR_IS_S390X) target_link_libraries(cpuinfo_s390x_test all_libraries) add_test(NAME cpuinfo_s390x_test COMMAND cpuinfo_s390x_test) endif() +##------------------------------------------------------------------------------ +## cpuinfo_riscv_test +if(PROCESSOR_IS_RISCV) + add_executable(cpuinfo_riscv_test cpuinfo_riscv_test.cc ../src/impl_riscv_linux.c) + target_link_libraries(cpuinfo_riscv_test all_libraries) + add_test(NAME cpuinfo_riscv_test COMMAND cpuinfo_riscv_test) +endif() \ No newline at end of file diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/test/cpuinfo_riscv_test.cc b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/test/cpuinfo_riscv_test.cc new file mode 100644 index 000000000..ff22a18d9 --- /dev/null +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/test/cpuinfo_riscv_test.cc @@ -0,0 +1,141 @@ +// SPDX-FileCopyrightText: 2022 Google LLC +// SPDX-License-Identifier: Apache-2.0 + +#include "cpuinfo_riscv.h" +#include "filesystem_for_testing.h" +#include "gtest/gtest.h" +#include "hwcaps_for_testing.h" + +namespace cpu_features +{ +namespace +{ + +TEST(CpuinfoRiscvTest, Sipeed_Lichee_RV_FromCpuInfo) +{ + ResetHwcaps(); + auto& fs = GetEmptyFilesystem(); + fs.CreateFile("/proc/cpuinfo", R"(processor : 0 +hart : 0 +isa : rv64imafdc +mmu : sv39 +uarch : thead,c906)"); + const auto info = GetRiscvInfo(); + EXPECT_STREQ(info.uarch, "c906"); + EXPECT_STREQ(info.vendor, "thead"); + + EXPECT_FALSE(info.features.RV32I); + EXPECT_TRUE(info.features.RV64I); + EXPECT_TRUE(info.features.M); + EXPECT_TRUE(info.features.A); + EXPECT_TRUE(info.features.F); + EXPECT_TRUE(info.features.D); + EXPECT_FALSE(info.features.Q); + EXPECT_TRUE(info.features.C); +} + +// https://github.com/ThomasKaiser/sbc-bench/blob/284e82b016ec1beeac42a5fcbe556b670f68441a/results/Kendryte-K510-4.17.0.cpuinfo +TEST(CpuinfoRiscvTest, Kendryte_K510_FromCpuInfo) +{ + ResetHwcaps(); + auto& fs = GetEmptyFilesystem(); + fs.CreateFile("/proc/cpuinfo", R"( +hart : 0 +isa : rv64i2p0m2p0a2p0f2p0d2p0c2p0xv5-0p0 +mmu : sv39 + +hart : 1 +isa : rv64i2p0m2p0a2p0f2p0d2p0c2p0xv5-0p0 +mmu : sv39"); + const auto info = GetRiscvInfo(); + EXPECT_STREQ(info.uarch, ""); + EXPECT_STREQ(info.vendor, ""); + EXPECT_FALSE(info.features.RV32I); + EXPECT_TRUE(info.features.RV64I); + EXPECT_TRUE(info.features.M); + EXPECT_TRUE(info.features.A); + EXPECT_TRUE(info.features.F); + EXPECT_TRUE(info.features.D); + EXPECT_FALSE(info.features.Q); + EXPECT_TRUE(info.features.C); +} + +// https://github.com/ThomasKaiser/sbc-bench/blob/284e82b016ec1beeac42a5fcbe556b670f68441a/results/T-Head-C910-5.10.4.cpuinfo +TEST(CpuinfoRiscvTest, T_Head_C910_FromCpuInfo) { + ResetHwcaps(); + auto& fs = GetEmptyFilesystem(); + fs.CreateFile("/proc/cpuinfo", R"( +processor : 0 +hart : 0 +isa : rv64imafdcsu +mmu : sv39 +cpu-freq : 1.2Ghz +cpu-icache : 64KB +cpu-dcache : 64KB +cpu-l2cache : 2MB +cpu-tlb : 1024 4-ways +cpu-cacheline : 64Bytes +cpu-vector : 0.7.1 +processor : 1 +hart : 1 +isa : rv64imafdcsu +mmu : sv39 +cpu-freq : 1.2Ghz +cpu-icache : 64KB +cpu-dcache : 64KB +cpu-l2cache : 2MB +cpu-tlb : 1024 4-ways +cpu-cacheline : 64Bytes +cpu-vector : 0.7.1"); + const auto info = GetRiscvInfo(); + EXPECT_STREQ(info.uarch, ""); + EXPECT_STREQ(info.vendor, ""); + EXPECT_FALSE(info.features.RV32I); + EXPECT_TRUE(info.features.RV64I); + EXPECT_TRUE(info.features.M); + EXPECT_TRUE(info.features.A); + EXPECT_TRUE(info.features.F); + EXPECT_TRUE(info.features.D); + EXPECT_FALSE(info.features.Q); + EXPECT_TRUE(info.features.C); +} +TEST(CpuinfoRiscvTest, UnknownFromCpuInfo) { + ResetHwcaps(); + auto& fs = GetEmptyFilesystem(); + fs.CreateFile("/proc/cpuinfo", R"( +processor : 0 +hart : 2 +isa : rv64imafdc +mmu : sv39 +uarch : sifive,bullet0 +processor : 1 +hart : 1 +isa : rv64imafdc +mmu : sv39 +uarch : sifive,bullet0 +processor : 2 +hart : 3 +isa : rv64imafdc +mmu : sv39 +uarch : sifive,bullet0 +processor : 3 +hart : 4 +isa : rv64imafdc +mmu : sv39 +uarch : sifive,bullet0)"); + const auto info = GetRiscvInfo(); + EXPECT_STREQ(info.uarch, "bullet0"); + EXPECT_STREQ(info.vendor, "sifive"); + + EXPECT_FALSE(info.features.RV32I); + EXPECT_TRUE(info.features.RV64I); + EXPECT_TRUE(info.features.M); + EXPECT_TRUE(info.features.A); + EXPECT_TRUE(info.features.F); + EXPECT_TRUE(info.features.D); + EXPECT_FALSE(info.features.Q); + EXPECT_TRUE(info.features.C); +} + +} // namespace +} // namespace cpu_features \ No newline at end of file diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/docs/kernels.dox b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/docs/kernels.dox index 06ab5521a..1b0a21d71 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/docs/kernels.dox +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/docs/kernels.dox @@ -23,7 +23,6 @@ \li \subpage volk_gnsssdr_8ic_magnitude_squared_8i \li \subpage volk_gnsssdr_8ic_x2_dot_prod_8ic \li \subpage volk_gnsssdr_8ic_x2_multiply_8ic -\li \subpage volk_gnsssdr_8ic_s8ic_multiply_8ic \li \subpage volk_gnsssdr_8i_accumulator_s8i \li \subpage volk_gnsssdr_8i_index_max_16u \li \subpage volk_gnsssdr_8i_max_s8i diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/asm/orc/volk_gnsssdr_8ic_conjugate_8ic.orc b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/asm/orc/volk_gnsssdr_8ic_conjugate_8ic.orc deleted file mode 100644 index 38e439925..000000000 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/asm/orc/volk_gnsssdr_8ic_conjugate_8ic.orc +++ /dev/null @@ -1,27 +0,0 @@ -# -# ORC implementation: calculates the conjugate of a 16 bits vector -# -# Andres Cecilia, 2014. a.cecilia.luque(at)gmail.com -# -# ORC code that calculates the conjugate of a -# 16 bits vector (8 bits the real part and 8 bits the imaginary part) -# result = (real*real) + (imag*imag) -# -# -# ------------------------------------------------------------------------------ -# -# GNSS-SDR is a Global Navigation Satellite System software-defined receiver. -# This file is part of GNSS-SDR. -# -# Copyright (C) 2010-2020 (see AUTHORS file for a list of contributors) -# SPDX-License-Identifier: GPL-3.0-or-later -# -# ------------------------------------------------------------------------------ -# - -.function volk_gnsssdr_8ic_conjugate_8ic_a_orc_impl -.source 2 src1 -.dest 2 dst -.temp 2 merged -mergebw merged, 1, -1 -x2 mullb dst, merged, src1 diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/asm/orc/volk_gnsssdr_8ic_s8ic_multiply_8ic.orc b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/asm/orc/volk_gnsssdr_8ic_s8ic_multiply_8ic.orc deleted file mode 100644 index bdd0dc32d..000000000 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/asm/orc/volk_gnsssdr_8ic_s8ic_multiply_8ic.orc +++ /dev/null @@ -1,39 +0,0 @@ -# -# ORC implementation: multiplies a group of 16 bits vectors by one constant vector -# -# Andres Cecilia, 2014. a.cecilia.luque(at)gmail.com -# -# -# ORC code that multiplies a group of 16 bits vectors -# (8 bits the real part and 8 bits the imaginary part) by one constant vector -# -# ------------------------------------------------------------------------------ -# -# GNSS-SDR is a Global Navigation Satellite System software-defined receiver. -# This file is part of GNSS-SDR. -# -# Copyright (C) 2010-2020 (see AUTHORS file for a list of contributors) -# SPDX-License-Identifier: GPL-3.0-or-later -# -# ------------------------------------------------------------------------------ -# - -.function volk_gnsssdr_8ic_s8ic_multiply_8ic_a_orc_impl -.source 2 src1 -.param 2 src2real -.param 2 src2imag -.dest 2 dst -.temp 2 iqprod -.temp 1 real -.temp 1 imag -.temp 1 rr -.temp 1 ii -.temp 1 ri -.temp 1 ir -x2 mullb iqprod, src1, src2real -splitwb ir, rr, iqprod -x2 mullb iqprod, src1, src2imag -splitwb ii, ri, iqprod -subb real, rr, ii -addb imag, ri, ir -mergebw dst, real, imag diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_8ic_conjugate_8ic.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_8ic_conjugate_8ic.h index 57ceaba72..6876d6a24 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_8ic_conjugate_8ic.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_8ic_conjugate_8ic.h @@ -324,16 +324,6 @@ static inline void volk_gnsssdr_8ic_conjugate_8ic_a_sse3(lv_8sc_t* cVector, cons #endif /* LV_HAVE_SSE3 */ -#ifdef LV_HAVE_ORC - -extern void volk_gnsssdr_8ic_conjugate_8ic_a_orc_impl(lv_8sc_t* cVector, const lv_8sc_t* aVector, unsigned int num_points); -static inline void volk_gnsssdr_8ic_conjugate_8ic_u_orc(lv_8sc_t* cVector, const lv_8sc_t* aVector, unsigned int num_points) -{ - volk_gnsssdr_8ic_conjugate_8ic_a_orc_impl(cVector, aVector, num_points); -} -#endif /* LV_HAVE_ORC */ - - #ifdef LV_HAVE_NEON #include diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_8ic_s8ic_multiply_8ic.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_8ic_s8ic_multiply_8ic.h deleted file mode 100644 index 71cf1d269..000000000 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/kernels/volk_gnsssdr/volk_gnsssdr_8ic_s8ic_multiply_8ic.h +++ /dev/null @@ -1,205 +0,0 @@ -/*! - * \file volk_gnsssdr_8ic_s8ic_multiply_8ic.h - * \brief VOLK_GNSSSDR kernel: multiplies a group of 16 bits vectors by one constant vector. - * \authors
    - *
  • Andres Cecilia, 2014. a.cecilia.luque(at)gmail.com - *
- * - * VOLK_GNSSSDR kernel that multiplies a group of 16 bits vectors - * (8 bits the real part and 8 bits the imaginary part) by one constant vector - * - * ----------------------------------------------------------------------------- - * - * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. - * This file is part of GNSS-SDR. - * - * Copyright (C) 2010-2020 (see AUTHORS file for a list of contributors) - * SPDX-License-Identifier: GPL-3.0-or-later - * - * ----------------------------------------------------------------------------- - */ - -/*! - * \page volk_gnsssdr_8ic_s8ic_multiply_8ic - * - * \b Overview - * - * Multiplies the input vector by a scalar and stores the results in the third vector - * - * Dispatcher Prototype - * \code - * void volk_gnsssdr_8ic_s8ic_multiply_8ic(lv_8sc_t* cVector, const lv_8sc_t* aVector, const lv_8sc_t scalar, unsigned int num_points); - * \endcode - * - * \b Inputs - * \li aVector: The vector to be multiplied. - * \li scalar The complex scalar to multiply \p aVector - * \li num_points: The number of complex values in \p aVector to be multiplied by \p scalar and stored into \p cVector. - * - * \b Outputs - * \li cVector: The vector where the results will be stored - * - */ - -#ifndef INCLUDED_volk_gnsssdr_8ic_s8ic_multiply_8ic_H -#define INCLUDED_volk_gnsssdr_8ic_s8ic_multiply_8ic_H - -#include - -#ifdef LV_HAVE_SSE3 -#include - -static inline void volk_gnsssdr_8ic_s8ic_multiply_8ic_u_sse3(lv_8sc_t* cVector, const lv_8sc_t* aVector, const lv_8sc_t scalar, unsigned int num_points) -{ - unsigned int number = 0; - const unsigned int sse_iters = num_points / 8; - - __m128i x, y, mult1, realx, imagx, realy, imagy, realx_mult_realy, imagx_mult_imagy, realx_mult_imagy, imagx_mult_realy, realc, imagc, totalc; - - lv_8sc_t* c = cVector; - const lv_8sc_t* a = aVector; - - mult1 = _mm_set_epi8(0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF); - - y = _mm_set1_epi16(*(short*)&scalar); - imagy = _mm_srli_si128(y, 1); - imagy = _mm_and_si128(imagy, mult1); - realy = _mm_and_si128(y, mult1); - - for (; number < sse_iters; number++) - { - x = _mm_lddqu_si128((__m128i*)a); - - imagx = _mm_srli_si128(x, 1); - imagx = _mm_and_si128(imagx, mult1); - realx = _mm_and_si128(x, mult1); - - realx_mult_realy = _mm_mullo_epi16(realx, realy); - imagx_mult_imagy = _mm_mullo_epi16(imagx, imagy); - realx_mult_imagy = _mm_mullo_epi16(realx, imagy); - imagx_mult_realy = _mm_mullo_epi16(imagx, realy); - - realc = _mm_sub_epi16(realx_mult_realy, imagx_mult_imagy); - realc = _mm_and_si128(realc, mult1); - imagc = _mm_add_epi16(realx_mult_imagy, imagx_mult_realy); - imagc = _mm_and_si128(imagc, mult1); - imagc = _mm_slli_si128(imagc, 1); - - totalc = _mm_or_si128(realc, imagc); - - _mm_storeu_si128((__m128i*)c, totalc); - - a += 8; - c += 8; - } - - for (number = sse_iters * 8; number < num_points; ++number) - { - *c++ = (*a++) * scalar; - } -} -#endif /* LV_HAVE_SSE3 */ - - -#ifdef LV_HAVE_GENERIC - -static inline void volk_gnsssdr_8ic_s8ic_multiply_8ic_generic(lv_8sc_t* cVector, const lv_8sc_t* aVector, const lv_8sc_t scalar, unsigned int num_points) -{ - /*lv_8sc_t* cPtr = cVector; - const lv_8sc_t* aPtr = aVector; - - for (int i = 0; i= 8) - { - *cPtr++ = (*aPtr++) * scalar; - *cPtr++ = (*aPtr++) * scalar; - *cPtr++ = (*aPtr++) * scalar; - *cPtr++ = (*aPtr++) * scalar; - *cPtr++ = (*aPtr++) * scalar; - *cPtr++ = (*aPtr++) * scalar; - *cPtr++ = (*aPtr++) * scalar; - *cPtr++ = (*aPtr++) * scalar; - number -= 8; - } - - // clean up any remaining - while (number-- > 0) - *cPtr++ = *aPtr++ * scalar; -} -#endif /* LV_HAVE_GENERIC */ - - -#ifdef LV_HAVE_SSE3 -#include - -static inline void volk_gnsssdr_8ic_s8ic_multiply_8ic_a_sse3(lv_8sc_t* cVector, const lv_8sc_t* aVector, const lv_8sc_t scalar, unsigned int num_points) -{ - unsigned int number = 0; - const unsigned int sse_iters = num_points / 8; - - __m128i x, y, mult1, realx, imagx, realy, imagy, realx_mult_realy, imagx_mult_imagy, realx_mult_imagy, imagx_mult_realy, realc, imagc, totalc; - - lv_8sc_t* c = cVector; - const lv_8sc_t* a = aVector; - - mult1 = _mm_set_epi8(0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF); - - y = _mm_set1_epi16(*(short*)&scalar); - imagy = _mm_srli_si128(y, 1); - imagy = _mm_and_si128(imagy, mult1); - realy = _mm_and_si128(y, mult1); - - for (; number < sse_iters; number++) - { - x = _mm_load_si128((__m128i*)a); - - imagx = _mm_srli_si128(x, 1); - imagx = _mm_and_si128(imagx, mult1); - realx = _mm_and_si128(x, mult1); - - realx_mult_realy = _mm_mullo_epi16(realx, realy); - imagx_mult_imagy = _mm_mullo_epi16(imagx, imagy); - realx_mult_imagy = _mm_mullo_epi16(realx, imagy); - imagx_mult_realy = _mm_mullo_epi16(imagx, realy); - - realc = _mm_sub_epi16(realx_mult_realy, imagx_mult_imagy); - realc = _mm_and_si128(realc, mult1); - imagc = _mm_add_epi16(realx_mult_imagy, imagx_mult_realy); - imagc = _mm_and_si128(imagc, mult1); - imagc = _mm_slli_si128(imagc, 1); - - totalc = _mm_or_si128(realc, imagc); - - _mm_store_si128((__m128i*)c, totalc); - - a += 8; - c += 8; - } - - for (number = sse_iters * 8; number < num_points; ++number) - { - *c++ = (*a++) * scalar; - } -} -#endif /* LV_HAVE_SSE3 */ - - -#ifdef LV_HAVE_ORC - -extern void volk_gnsssdr_8ic_s8ic_multiply_8ic_a_orc_impl(lv_8sc_t* cVector, const lv_8sc_t* aVector, const char scalarreal, const char scalarimag, unsigned int num_points); -static inline void volk_gnsssdr_8ic_s8ic_multiply_8ic_u_orc(lv_8sc_t* cVector, const lv_8sc_t* aVector, const lv_8sc_t scalar, unsigned int num_points) -{ - volk_gnsssdr_8ic_s8ic_multiply_8ic_a_orc_impl(cVector, aVector, lv_creal(scalar), lv_cimag(scalar), num_points); -} -#endif /* LV_HAVE_ORC */ - -#endif /* INCLUDED_volk_gnsssdr_32fc_x2_multiply_32fc_H */ diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/lib/kernel_tests.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/lib/kernel_tests.h index 3f38b263e..6a089836b 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/lib/kernel_tests.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/lib/kernel_tests.h @@ -51,7 +51,8 @@ std::vector init_test_list(volk_gnsssdr_test_params_t volk_gnsssdr_test_params_t test_params_inacc2 = volk_gnsssdr_test_params_t(2e-1, test_params.scalar(), test_params.vlen(), test_params.iter(), test_params.benchmark_mode(), test_params.kernel_regex()); - std::vector test_cases; + std::vector + test_cases; QA(VOLK_INIT_TEST(volk_gnsssdr_8i_accumulator_s8i, test_params_more_iters)) QA(VOLK_INIT_TEST(volk_gnsssdr_8i_index_max_16u, test_params_more_iters)) @@ -61,7 +62,6 @@ std::vector init_test_list(volk_gnsssdr_test_params_t QA(VOLK_INIT_TEST(volk_gnsssdr_8ic_magnitude_squared_8i, test_params_more_iters)) QA(VOLK_INIT_TEST(volk_gnsssdr_8ic_x2_dot_prod_8ic, test_params)) QA(VOLK_INIT_TEST(volk_gnsssdr_8ic_x2_multiply_8ic, test_params)) - QA(VOLK_INIT_TEST(volk_gnsssdr_8ic_s8ic_multiply_8ic, test_params)) QA(VOLK_INIT_TEST(volk_gnsssdr_8u_x2_multiply_8u, test_params_more_iters)) QA(VOLK_INIT_TEST(volk_gnsssdr_64f_accumulator_64f, test_params)) QA(VOLK_INIT_TEST(volk_gnsssdr_32f_sincos_32fc, test_params_inacc)) diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/tmpl/volk_gnsssdr_cpu.tmpl.c b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/tmpl/volk_gnsssdr_cpu.tmpl.c index d0db27e89..c089e8625 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/tmpl/volk_gnsssdr_cpu.tmpl.c +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/tmpl/volk_gnsssdr_cpu.tmpl.c @@ -26,6 +26,10 @@ #include "cpuinfo_mips.h" #elif defined(CPU_FEATURES_ARCH_PPC) #include "cpuinfo_ppc.h" +#elif defined(CPU_FEATURES_ARCH_S390X) +#include "cpuinfo_s390x.h" +#elif defined(CPU_FEATURES_ARCH_RISCV) +#include "cpuinfo_riscv.h" #endif // This is required for MSVC @@ -41,15 +45,31 @@ struct VOLK_CPU volk_gnsssdr_cpu; %for arch in archs: static int i_can_has_${arch.name} (void) { %for check, params in arch.checks: - %if "neon" in arch.name: + %if "neon" in arch.name: #if defined(CPU_FEATURES_ARCH_ARM) if (GetArmInfo().features.${check} == 0){ return 0; } #endif - %else: + %elif "mips" in arch.name: +#if defined(CPU_FEATURES_ARCH_MIPS) + if (GetMipsInfo().features.${check} == 0){ return 0; } +#endif + %elif "ppc" in arch.name: +#if defined(CPU_FEATURES_ARCH_PPC) + if (GetPPCInfo().features.${check} == 0){ return 0; } +#endif + %elif "s390x" in arch.name: +#if defined(CPU_FEATURES_ARCH_S390X) + if (GetS390XInfo().features.${check} == 0){ return 0; } +#endif + %elif "riscv" in arch.name: +#if defined(CPU_FEATURES_ARCH_RISCV) + if (GetRiscvInfo().features.${check} == 0){ return 0; } +#endif + %else: #if defined(CPU_FEATURES_ARCH_X86) if (GetX86Info().features.${check} == 0){ return 0; } #endif - %endif + %endif %endfor return 1; } diff --git a/src/algorithms/observables/gnuradio_blocks/hybrid_observables_gs.cc b/src/algorithms/observables/gnuradio_blocks/hybrid_observables_gs.cc index b7f2c56be..6fb36d92c 100644 --- a/src/algorithms/observables/gnuradio_blocks/hybrid_observables_gs.cc +++ b/src/algorithms/observables/gnuradio_blocks/hybrid_observables_gs.cc @@ -100,19 +100,6 @@ hybrid_observables_gs::hybrid_observables_gs(const Obs_Conf &conf_) d_channel_last_pseudorange_smooth = std::vector(d_nchannels_out, 0.0); d_channel_last_carrier_phase_rads = std::vector(d_nchannels_out, 0.0); - d_mapStringValues["1C"] = evGPS_1C; - d_mapStringValues["2S"] = evGPS_2S; - d_mapStringValues["L5"] = evGPS_L5; - d_mapStringValues["1B"] = evGAL_1B; - d_mapStringValues["5X"] = evGAL_5X; - d_mapStringValues["E6"] = evGAL_E6; - d_mapStringValues["7X"] = evGAL_7X; - d_mapStringValues["1G"] = evGLO_1G; - d_mapStringValues["2G"] = evGLO_2G; - d_mapStringValues["B1"] = evBDS_B1; - d_mapStringValues["B2"] = evBDS_B2; - d_mapStringValues["B3"] = evBDS_B3; - d_SourceTagTimestamps = std::vector>(d_nchannels_out); set_tag_propagation_policy(TPP_DONT); // no tag propagation, the time tag will be adjusted and regenerated in work() @@ -581,44 +568,11 @@ void hybrid_observables_gs::smooth_pseudoranges(std::vector &data) if (it->Flag_valid_pseudorange) { // 0. get wavelength for the current signal - double wavelength_m = 0; - switch (d_mapStringValues[it->Signal]) + double wavelength_m = 0.0; + const auto it_freq_map = SIGNAL_FREQ_MAP.find(std::string(it->Signal, 2)); + if (it_freq_map != SIGNAL_FREQ_MAP.cend()) { - case evGPS_1C: - case evSBAS_1C: - case evGAL_1B: - wavelength_m = SPEED_OF_LIGHT_M_S / FREQ1; - break; - case evGPS_L5: - case evGAL_5X: - wavelength_m = SPEED_OF_LIGHT_M_S / FREQ5; - break; - case evGAL_E6: - wavelength_m = SPEED_OF_LIGHT_M_S / FREQ6; - break; - case evGAL_7X: - wavelength_m = SPEED_OF_LIGHT_M_S / FREQ7; - break; - case evGPS_2S: - wavelength_m = SPEED_OF_LIGHT_M_S / FREQ2; - break; - case evBDS_B3: - wavelength_m = SPEED_OF_LIGHT_M_S / FREQ3_BDS; - break; - case evGLO_1G: - wavelength_m = SPEED_OF_LIGHT_M_S / FREQ1_GLO; - break; - case evGLO_2G: - wavelength_m = SPEED_OF_LIGHT_M_S / FREQ2_GLO; - break; - case evBDS_B1: - wavelength_m = SPEED_OF_LIGHT_M_S / FREQ1_BDS; - break; - case evBDS_B2: - wavelength_m = SPEED_OF_LIGHT_M_S / FREQ2_BDS; - break; - default: - break; + wavelength_m = SPEED_OF_LIGHT_M_S / it_freq_map->second; } // todo: propagate the PLL lock status in Gnss_Synchro diff --git a/src/algorithms/observables/gnuradio_blocks/hybrid_observables_gs.h b/src/algorithms/observables/gnuradio_blocks/hybrid_observables_gs.h index 5c4863c7c..96a83b733 100644 --- a/src/algorithms/observables/gnuradio_blocks/hybrid_observables_gs.h +++ b/src/algorithms/observables/gnuradio_blocks/hybrid_observables_gs.h @@ -29,12 +29,11 @@ #include // for size_t #include // for int32_t #include // for std::ofstream -#include // for std::map #include // for std::shared, std:unique_ptr -#include -#include // for std::string -#include // for typeid -#include // for std::vector +#include // for std::queue +#include // for std::string +#include // for typeid +#include // for std::vector /** \addtogroup Observables * \{ */ @@ -84,24 +83,6 @@ private: Obs_Conf d_conf; - enum StringValue_ - { - evGPS_1C, - evGPS_2S, - evGPS_L5, - evSBAS_1C, - evGAL_1B, - evGAL_5X, - evGAL_E6, - evGAL_7X, - evGLO_1G, - evGLO_2G, - evBDS_B1, - evBDS_B2, - evBDS_B3 - }; - std::map d_mapStringValues; - std::unique_ptr> d_gnss_synchro_history; // Tracking observable history boost::circular_buffer d_Rx_clock_buffer; // time history diff --git a/src/algorithms/signal_source/adapters/zmq_signal_source.cc b/src/algorithms/signal_source/adapters/zmq_signal_source.cc index 5d51434ff..7a6370000 100644 --- a/src/algorithms/signal_source/adapters/zmq_signal_source.cc +++ b/src/algorithms/signal_source/adapters/zmq_signal_source.cc @@ -44,6 +44,7 @@ ZmqSignalSource::ZmqSignalSource(const ConfigurationInterface* configuration, LOG(INFO) << "Connecting to ZMQ pub at " << endpoint; // work around gnuradio interface deficiency d_source_block = gr::zeromq::sub_source::make(d_item_size, vlen, const_cast(endpoint.data()), timeout_ms, pass_tags, hwm); + d_source_block->set_tag_propagation_policy(gr::block::TPP_DONT); // GNSS-SDR doesn't do well with tags/ } else { @@ -94,9 +95,13 @@ auto ZmqSignalSource::get_right_block() -> gr::basic_block_sptr auto result = gr::basic_block_sptr(); if (d_vec_block) - result = d_vec_block; // NOLINT + { + result = d_vec_block; + } else - result = d_source_block; // NOLINT + { + result = d_source_block; + } return result; } diff --git a/src/algorithms/signal_source/libs/fpga_switch.h b/src/algorithms/signal_source/libs/fpga_switch.h index 3595cf9ce..b4a73cb4f 100644 --- a/src/algorithms/signal_source/libs/fpga_switch.h +++ b/src/algorithms/signal_source/libs/fpga_switch.h @@ -23,6 +23,7 @@ #ifndef GNSS_SDR_FPGA_SWITCH_H #define GNSS_SDR_FPGA_SWITCH_H +#include #include /** \addtogroup Signal_Source diff --git a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc index def867de7..2c2693c44 100644 --- a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc +++ b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc @@ -664,6 +664,7 @@ void galileo_telemetry_decoder_gs::set_satellite(const Gnss_Satellite &satellite d_received_tow_ms = std::numeric_limits::max(); d_E6_TOW_set = false; d_valid_timetag = false; + d_inav_nav.init_PRN(d_satellite.get_PRN()); if (d_there_are_e6_channels) { const std::pair tow_and_sample{d_received_tow_ms, 0ULL}; @@ -684,6 +685,7 @@ void galileo_telemetry_decoder_gs::reset() d_fnav_nav.set_flag_TOW_set(false); d_inav_nav.set_flag_TOW_set(false); d_inav_nav.set_TOW0_flag(false); + d_inav_nav.init_PRN(d_satellite.get_PRN()); d_last_valid_preamble = d_symbol_counter; d_sent_tlm_failed_msg = false; d_E6_TOW_set = false; diff --git a/src/core/libs/galileo_e6_has_msg_receiver.cc b/src/core/libs/galileo_e6_has_msg_receiver.cc index a18bc23cc..22e1cd524 100644 --- a/src/core/libs/galileo_e6_has_msg_receiver.cc +++ b/src/core/libs/galileo_e6_has_msg_receiver.cc @@ -149,7 +149,7 @@ std::shared_ptr galileo_e6_has_msg_receiver::process_test_page { d_HAS_data.has_status = d_current_has_status; d_HAS_data.message_id = d_current_message_id; - d_HAS_data.tow = tow - static_cast(std::remainder(tow, 3600)) + d_HAS_data.header.toh; + d_HAS_data.tow = tow; auto has_data_ptr = std::make_shared(d_HAS_data); d_new_message = false; d_printed_mids[d_current_message_id] = true; @@ -201,7 +201,7 @@ void galileo_e6_has_msg_receiver::msg_handler_galileo_e6_has(const pmt::pmt_t& m { d_HAS_data.has_status = d_current_has_status; d_HAS_data.message_id = d_current_message_id; - d_HAS_data.tow = tow - static_cast(std::remainder(tow, 3600)) + d_HAS_data.header.toh; + d_HAS_data.tow = tow; d_printed_mids[d_current_message_id] = true; d_printed_timestamps[d_current_message_id] = timestamp; auto has_data_ptr = std::make_shared(d_HAS_data); @@ -699,8 +699,7 @@ void galileo_e6_has_msg_receiver::read_MT1_body(const std::string& message_body) // count satellites in the mask std::bitset satellite_mask_bits(satellite_mask); - std::string satellite_mask_string = satellite_mask_bits.to_string(); - int number_sats_this_gnss_id = std::count(satellite_mask_string.begin(), satellite_mask_string.end(), '1'); + int number_sats_this_gnss_id = satellite_mask_bits.count(); d_HAS_data.satellite_submask[i] = read_has_message_body_uint64(message.substr(0, number_sats_this_gnss_id)); message = std::string(message.begin() + number_sats_this_gnss_id, message.end()); diff --git a/src/core/system_parameters/galileo_has_data.cc b/src/core/system_parameters/galileo_has_data.cc index 447d9faef..5168e33bf 100644 --- a/src/core/system_parameters/galileo_has_data.cc +++ b/src/core/system_parameters/galileo_has_data.cc @@ -18,372 +18,75 @@ #include "Galileo_CNAV.h" #include #include +#include +#include #include #include - - -std::vector Galileo_HAS_data::get_PRNs_in_mask(uint8_t nsys) const -{ - std::vector prn; - if (nsys < satellite_mask.size()) - { - uint64_t sat_mask = satellite_mask[nsys]; - std::bitset bits(sat_mask); - std::string bit_str = bits.to_string(); - for (int32_t i = 0; i < HAS_MSG_NUMBER_SATELLITE_IDS; i++) - { - if (bit_str[i] == '1') - { - prn.push_back(i + 1); - } - } - } - return prn; -} - - -std::vector Galileo_HAS_data::get_PRNs_in_submask(uint8_t nsys) const -{ - std::vector prn; - std::vector prn_in_submask; - if (nsys < satellite_submask.size()) - { - auto it = std::find(gnss_id_mask.begin(), gnss_id_mask.end(), gnss_id_clock_subset[nsys]); - int index = 0; - if (it != gnss_id_mask.end()) - { - index = it - gnss_id_mask.begin(); - } - else - { - return prn_in_submask; - } - - uint8_t nsys_index_in_mask = gnss_id_mask[index]; - uint64_t sat_mask = satellite_mask[nsys_index_in_mask]; - - std::bitset bits(sat_mask); - std::string mask_bit_str = bits.to_string(); - for (int i = 0; i < HAS_MSG_NUMBER_SATELLITE_IDS; i++) - { - if (mask_bit_str[i] == '1') - { - prn.push_back(i + 1); - } - } - - int number_sats_this_gnss_id = std::count(mask_bit_str.begin(), mask_bit_str.end(), '1'); - uint64_t sat_submask = satellite_submask[nsys]; - // convert into string - std::string sat_submask_str(""); - sat_submask_str.reserve(number_sats_this_gnss_id); - uint64_t aux = 1; - const std::string one_str("1"); - const std::string zero_str("0"); - - for (int k = 0; k < number_sats_this_gnss_id - 1; k++) - { - if ((aux & sat_submask) >= 1) - { - sat_submask_str.insert(0, one_str); - } - else - { - sat_submask_str.insert(0, zero_str); - } - aux <<= 1; - } - - for (int i = 0; i < number_sats_this_gnss_id; i++) - { - if (sat_submask_str[i] == '1') - { - prn_in_submask.push_back(prn[i]); - } - } - } - - return prn_in_submask; -} +#include +#include std::vector Galileo_HAS_data::get_signals_in_mask(uint8_t nsys) const { - std::vector signals_in_mask; - if (signal_mask.size() > nsys) + if (signal_mask.size() <= nsys) { - uint16_t sig = signal_mask[nsys]; - std::bitset bits(sig); - std::string bits_str = bits.to_string(); - for (int32_t k = 0; k < HAS_MSG_NUMBER_SIGNAL_MASKS; k++) + return {}; + } + // See HAS SIS ICD v1.0 Table 20 + std::unordered_map> signal_index_table = { + {0, { + {0, "L1 C/A"}, + {1, "Reserved"}, + {2, "Reserved"}, + {3, "L1C(D)"}, + {4, "L1C(P)"}, + {5, "L1C(D+P)"}, + {6, "L2 CM"}, + {7, "L2 CL"}, + {8, "L2 CM+CL"}, + {9, "L2 P"}, + {10, "Reserved"}, + {11, "L5 I"}, + {12, "L5 Q"}, + {13, "L5 I + L5 Q"}, + {14, "Reserved"}, + {15, "Reserved"}, + }}, + {2, { + {0, "E1-B I/NAV OS"}, + {1, "E1-C"}, + {2, "E1-B + E1-C"}, + {3, "E5a-I F/NAV OS"}, + {4, "E5a-Q"}, + {5, "E5a-I+E5a-Q"}, + {6, "E5b-I I/NAV OS"}, + {7, "E5b-Q"}, + {8, "E5b-I+E5b-Q"}, + {9, "E5-I"}, + {10, "E5-Q"}, + {11, "E5-I + E5-Q"}, + {12, "E6-B C/NAV HAS"}, + {13, "E6-C"}, + {14, "E6-B + E6-C"}, + {15, "Reserved"}, + }}}; + + std::vector signals_in_mask; + uint16_t sig = signal_mask[nsys]; + uint8_t system = gnss_id_mask[nsys]; + std::bitset bits(sig); + + for (int32_t k = 0; k < HAS_MSG_NUMBER_SIGNAL_MASKS; k++) + { + if ((bits[HAS_MSG_NUMBER_SIGNAL_MASKS - k - 1])) { - if (bits_str[k] == '1') + if (signal_index_table[system].count(k) == 0) { - uint8_t system = gnss_id_mask[nsys]; - std::string signal; - // See HAS SIS ICD v1.0 Table 20 - switch (k) - { - case 0: - if (system == 0) - { - // GPS - signal = "L1 C/A"; - } - else if (system == 2) - { - // Galileo - signal = "E1-B I/NAV OS"; - } - else - { - signal = "Unknown"; - } - break; - case 1: - if (system == 0) - { - // GPS - signal = "Reserved"; - } - else if (system == 2) - { - // Galileo - signal = "E1-C"; - } - else - { - signal = "Unknown"; - } - break; - case 2: - if (system == 0) - { - // GPS - signal = "Reserved"; - } - else if (system == 2) - { - // Galileo - signal = "E1-B + E1-C"; - } - else - { - signal = "Unknown"; - } - break; - case 3: - if (system == 0) - { - // GPS - signal = "L1C(D)"; - } - else if (system == 2) - { - // Galileo - signal = "E5a-I F/NAV OS"; - } - else - { - signal = "Unknown"; - } - break; - case 4: - if (system == 0) - { - // GPS - signal = "L1C(P)"; - } - else if (system == 2) - { - // Galileo - signal = "E5a-Q"; - } - else - { - signal = "Unknown"; - } - break; - case 5: - if (system == 0) - { - // GPS - signal = "L1C(D+P)"; - } - else if (system == 2) - { - // Galileo - signal = "E5a-I+E5a-Q"; - } - else - { - signal = "Unknown"; - } - break; - case 6: - if (system == 0) - { - // GPS - signal = "L2 CM"; - } - else if (system == 2) - { - // Galileo - signal = "E5b-I I/NAV OS"; - } - else - { - signal = "Unknown"; - } - break; - case 7: - if (system == 0) - { - // GPS - signal = "L2 CL"; - } - else if (system == 2) - { - // Galileo - signal = "E5b-Q"; - } - else - { - signal = "Unknown"; - } - break; - case 8: - if (system == 0) - { - // GPS - signal = "L2 CM+CL"; - } - else if (system == 2) - { - // Galileo - signal = "E5b-I+E5b-Q"; - } - else - { - signal = "Unknown"; - } - break; - case 9: - if (system == 0) - { - // GPS - signal = "L2 P"; - } - else if (system == 2) - { - // Galileo - signal = "E5-I"; - } - else - { - signal = "Unknown"; - } - break; - case 10: - if (system == 0) - { - // GPS - signal = "Reserved"; - } - else if (system == 2) - { - // Galileo - signal = "E5-Q"; - } - else - { - signal = "Unknown"; - } - break; - case 11: - if (system == 0) - { - // GPS - signal = "L5 I"; - } - else if (system == 2) - { - // Galileo - signal = "E5-I + E5-Q"; - } - else - { - signal = "Unknown"; - } - break; - case 12: - if (system == 0) - { - // GPS - signal = "L5 Q"; - } - else if (system == 2) - { - // Galileo - signal = "E6-B C/NAV HAS"; - } - else - { - signal = "Unknown"; - } - break; - case 13: - if (system == 0) - { - // GPS - signal = "L5 I + L5 Q"; - } - else if (system == 2) - { - // Galileo - signal = "E6-C"; - } - else - { - signal = "Unknown"; - } - break; - case 14: - if (system == 0) - { - // GPS - signal = "Reserved"; - } - else if (system == 2) - { - // Galileo - signal = "E6-B + E6-C"; - } - else - { - signal = "Unknown"; - } - break; - case 15: - if (system == 0) - { - // GPS - signal = "Reserved"; - } - else if (system == 2) - { - // Galileo - signal = "Reserved"; - } - else - { - signal = "Unknown"; - } - break; - default: - signal = "Unknown"; - } - signals_in_mask.push_back(signal); + signals_in_mask.emplace_back("Unknown"); + } + else + { + signals_in_mask.push_back(signal_index_table[system][k]); } } } @@ -391,77 +94,139 @@ std::vector Galileo_HAS_data::get_signals_in_mask(uint8_t nsys) con } -uint8_t Galileo_HAS_data::get_gnss_id(int nsat) const +std::vector Galileo_HAS_data::get_signals_in_mask(const std::string& system) const { - int number_sats = 0; - for (uint8_t i = 0; i < Nsys; i++) + auto systems = this->get_systems_string(); + auto sys_it = std::find(systems.begin(), systems.end(), system); + if (sys_it == systems.end()) { - number_sats += static_cast(get_PRNs_in_mask(i).size()); - if (nsat < number_sats) - { - return gnss_id_mask[i]; - } + return {}; } - - return HAS_MSG_WRONG_SYSTEM; + auto system_index = std::distance(systems.begin(), sys_it); + return this->get_signals_in_mask(system_index); } -uint16_t Galileo_HAS_data::get_validity_interval_s(uint8_t validity_interval_index) const +std::vector Galileo_HAS_data::get_systems_string() const { - uint16_t validity_interval; - // See HAS SIS ICD v1.0 Table 23 - switch (validity_interval_index) + if (this->gnss_id_mask.empty()) { - case 0: - validity_interval = 5; - break; - case 1: - validity_interval = 10; - break; - case 2: - validity_interval = 15; - break; - case 3: - validity_interval = 20; - break; - case 4: - validity_interval = 30; - break; - case 5: - validity_interval = 60; - break; - case 6: - validity_interval = 90; - break; - case 7: - validity_interval = 120; - break; - case 8: - validity_interval = 180; - break; - case 9: - validity_interval = 240; - break; - case 10: - validity_interval = 300; - break; - case 11: - validity_interval = 600; - break; - case 12: - validity_interval = 900; - break; - case 13: - validity_interval = 1800; - break; - case 14: - validity_interval = 3600; - break; - default: // reserved - validity_interval = 0; + return {}; } - return validity_interval; + + std::vector systems; + systems.reserve(this->gnss_id_mask.size()); + + for (uint8_t i = 0; i < this->Nsys; i++) + { + switch (this->gnss_id_mask[i]) + { + case 0: + systems.emplace_back("GPS"); + break; + case 2: + systems.emplace_back("Galileo"); + break; + default: + systems.emplace_back("Reserved"); + } + } + + return systems; +} + + +std::vector Galileo_HAS_data::get_systems_subset_string() const +{ + if (this->gnss_id_clock_subset.empty()) + { + return {}; + } + + std::vector systems; + systems.reserve(this->gnss_id_clock_subset.size()); + + for (uint8_t i = 0; i < this->Nsys_sub; i++) + { + switch (this->gnss_id_clock_subset[i]) + { + case 0: + systems.emplace_back("GPS"); + break; + case 2: + systems.emplace_back("Galileo"); + break; + default: + systems.emplace_back("Reserved"); + } + } + + return systems; +} + + +std::vector> Galileo_HAS_data::get_code_bias_m() const +{ + if (code_bias.empty()) + { + return {}; + } + const size_t outer_size = this->code_bias.size(); + const size_t inner_size = this->code_bias[0].size(); + std::vector> code_bias_m(outer_size, std::vector(inner_size)); + for (size_t i = 0; i < outer_size; i++) + { + for (size_t j = 0; j < inner_size; j++) + { + code_bias_m[i][j] = static_cast(this->code_bias[i][j]) * HAS_MSG_CODE_BIAS_SCALE_FACTOR; + } + } + return code_bias_m; +} + + +std::vector> Galileo_HAS_data::get_phase_bias_cycle() const +{ + if (phase_bias.empty()) + { + return {}; + } + const size_t outer_size = this->phase_bias.size(); + const size_t inner_size = this->phase_bias[0].size(); + std::vector> phase_bias_cycle(outer_size, std::vector(inner_size)); + for (size_t i = 0; i < outer_size; i++) + { + for (size_t j = 0; j < inner_size; j++) + { + phase_bias_cycle[i][j] = static_cast(this->phase_bias[i][j]) * HAS_MSG_PHASE_BIAS_SCALE_FACTOR; + } + } + return phase_bias_cycle; +} + + +std::vector> Galileo_HAS_data::get_delta_clock_subset_correction_m() const +{ + if (this->delta_clock_correction_clock_subset.empty()) + { + return {}; + } + + std::vector> delta_clock_subset_correction_m; + delta_clock_subset_correction_m.reserve(this->Nsys_sub); + + for (const auto& correction_subset : this->delta_clock_correction_clock_subset) + { + std::vector correction_m; + correction_m.reserve(correction_subset.size()); + for (const auto& d : correction_subset) + { + correction_m.push_back(static_cast(d) * HAS_MSG_DELTA_CLOCK_SCALE_FACTOR); + } + delta_clock_subset_correction_m.emplace_back(std::move(correction_m)); + } + + return delta_clock_subset_correction_m; } @@ -479,19 +244,20 @@ std::vector Galileo_HAS_data::get_delta_radial_m() const std::vector Galileo_HAS_data::get_delta_radial_m(uint8_t nsys) const { - std::vector delta_orbit_radial_m = this->get_delta_radial_m(); if (nsys >= this->Nsys) { - return delta_orbit_radial_m; + return {}; } + std::vector delta_orbit_radial_m_v = this->get_delta_radial_m(); + std::vector num_satellites = this->get_num_satellites(); std::vector delta_orbit_radial_m_aux; - uint8_t num_sats_in_this_system = this->get_num_satellites()[nsys]; + uint8_t num_sats_in_this_system = num_satellites[nsys]; delta_orbit_radial_m_aux.reserve(num_sats_in_this_system); size_t index = 0; for (uint8_t sys = 0; sys <= nsys; sys++) { - uint8_t num_sats_in_system = this->get_num_satellites()[sys]; + uint8_t num_sats_in_system = num_satellites[sys]; if (sys != nsys) { index += num_sats_in_system; @@ -500,7 +266,7 @@ std::vector Galileo_HAS_data::get_delta_radial_m(uint8_t nsys) const { for (uint8_t sat = 0; sat < num_sats_in_system; sat++) { - delta_orbit_radial_m_aux.push_back(delta_orbit_radial_m[index]); + delta_orbit_radial_m_aux.push_back(delta_orbit_radial_m_v[index]); index++; } } @@ -523,19 +289,20 @@ std::vector Galileo_HAS_data::get_delta_in_track_m() const std::vector Galileo_HAS_data::get_delta_in_track_m(uint8_t nsys) const { - std::vector delta_in_track_m = this->get_delta_in_track_m(); if (nsys >= this->Nsys) { - return delta_in_track_m; + return {}; } + std::vector delta_in_track_m_v = this->get_delta_in_track_m(); + std::vector num_satellites = this->get_num_satellites(); std::vector delta_in_track_m_aux; - uint8_t num_sats_in_this_system = this->get_num_satellites()[nsys]; + uint8_t num_sats_in_this_system = num_satellites[nsys]; delta_in_track_m_aux.reserve(num_sats_in_this_system); size_t index = 0; for (uint8_t sys = 0; sys <= nsys; sys++) { - uint8_t num_sats_in_system = this->get_num_satellites()[sys]; + uint8_t num_sats_in_system = num_satellites[sys]; if (sys != nsys) { index += num_sats_in_system; @@ -544,7 +311,7 @@ std::vector Galileo_HAS_data::get_delta_in_track_m(uint8_t nsys) const { for (uint8_t sat = 0; sat < num_sats_in_system; sat++) { - delta_in_track_m_aux.push_back(delta_in_track_m[index]); + delta_in_track_m_aux.push_back(delta_in_track_m_v[index]); index++; } } @@ -567,19 +334,20 @@ std::vector Galileo_HAS_data::get_delta_cross_track_m() const std::vector Galileo_HAS_data::get_delta_cross_track_m(uint8_t nsys) const { - std::vector delta_cross_track_m = this->get_delta_cross_track_m(); if (nsys >= this->Nsys) { - return delta_cross_track_m; + return {}; } + std::vector delta_cross_track_m_v = this->get_delta_cross_track_m(); std::vector delta_cross_track_m_aux; - uint8_t num_sats_in_this_system = this->get_num_satellites()[nsys]; + std::vector num_satellites = this->get_num_satellites(); + uint8_t num_sats_in_this_system = num_satellites[nsys]; delta_cross_track_m_aux.reserve(num_sats_in_this_system); size_t index = 0; for (uint8_t sys = 0; sys <= nsys; sys++) { - uint8_t num_sats_in_system = this->get_num_satellites()[sys]; + uint8_t num_sats_in_system = num_satellites[sys]; if (sys != nsys) { index += num_sats_in_system; @@ -588,7 +356,7 @@ std::vector Galileo_HAS_data::get_delta_cross_track_m(uint8_t nsys) const { for (uint8_t sat = 0; sat < num_sats_in_system; sat++) { - delta_cross_track_m_aux.push_back(delta_cross_track_m[index]); + delta_cross_track_m_aux.push_back(delta_cross_track_m_v[index]); index++; } } @@ -611,19 +379,20 @@ std::vector Galileo_HAS_data::get_delta_clock_correction_m() const std::vector Galileo_HAS_data::get_delta_clock_correction_m(uint8_t nsys) const { - std::vector delta_clock_correction_m = this->get_delta_clock_correction_m(); if (nsys >= this->Nsys) { - return delta_clock_correction_m; + return {}; } + std::vector delta_clock_correction_m_v = this->get_delta_clock_correction_m(); std::vector delta_clock_correction_m_aux; - uint8_t num_sats_in_this_system = this->get_num_satellites()[nsys]; + std::vector num_satellites = this->get_num_satellites(); + uint8_t num_sats_in_this_system = num_satellites[nsys]; delta_clock_correction_m_aux.reserve(num_sats_in_this_system); size_t index = 0; for (uint8_t sys = 0; sys <= nsys; sys++) { - uint8_t num_sats_in_system = this->get_num_satellites()[sys]; + uint8_t num_sats_in_system = num_satellites[sys]; if (sys != nsys) { index += num_sats_in_system; @@ -632,7 +401,7 @@ std::vector Galileo_HAS_data::get_delta_clock_correction_m(uint8_t nsys) { for (uint8_t sat = 0; sat < num_sats_in_system; sat++) { - delta_clock_correction_m_aux.push_back(delta_clock_correction_m[index]); + delta_clock_correction_m_aux.push_back(delta_clock_correction_m_v[index]); index++; } } @@ -641,85 +410,143 @@ std::vector Galileo_HAS_data::get_delta_clock_correction_m(uint8_t nsys) } -std::vector> Galileo_HAS_data::get_code_bias_m() const +std::vector Galileo_HAS_data::get_delta_clock_subset_correction_m(uint8_t nsys) const { - std::vector> code_bias_m; - const size_t outer_size = this->code_bias.size(); - if (outer_size == 0) + if (nsys >= this->Nsys) { - return code_bias_m; + return {}; } - const size_t inner_size = this->code_bias[0].size(); - code_bias_m = std::vector>(outer_size, std::vector(inner_size)); - for (size_t i = 0; i < outer_size; i++) + + // get equivalence of nsys in mask with nsys_sub_index in submask + auto gnss_id_in_mask = this->gnss_id_mask[nsys]; + auto sys_it = std::find(gnss_id_clock_subset.begin(), gnss_id_clock_subset.end(), gnss_id_in_mask); + if (sys_it == gnss_id_clock_subset.end()) { - for (size_t j = 0; j < inner_size; j++) + return {}; + } + uint64_t nsys_sub_index = std::distance(gnss_id_clock_subset.begin(), sys_it); + if (nsys_sub_index >= satellite_submask.size()) + { + return {}; + } + + auto subset_corr_matrix = this->get_delta_clock_subset_correction_m(); + std::vector delta_clock_subset_correction_m_v = subset_corr_matrix[nsys_sub_index]; + std::vector delta_clock_subset_correction_m_aux; + std::vector num_satellites_subset = this->get_num_subset_satellites(); + uint8_t num_sats_in_this_system_subset = num_satellites_subset[nsys_sub_index]; + delta_clock_subset_correction_m_aux.reserve(num_sats_in_this_system_subset); + size_t index = 0; + for (uint8_t sys = 0; sys <= nsys; sys++) + { + uint8_t num_sats_in_subset = num_satellites_subset[sys]; + if (sys != nsys) { - code_bias_m[i][j] = static_cast(this->code_bias[i][j]) * HAS_MSG_CODE_BIAS_SCALE_FACTOR; + index += num_sats_in_subset; + } + else + { + for (uint8_t sat = 0; sat < num_sats_in_subset; sat++) + { + delta_clock_subset_correction_m_aux.push_back(delta_clock_subset_correction_m_v[index]); + index++; + } } } - return code_bias_m; + return delta_clock_subset_correction_m_aux; } -std::vector> Galileo_HAS_data::get_phase_bias_cycle() const +std::vector Galileo_HAS_data::get_PRNs_in_mask(uint8_t nsys) const { - std::vector> phase_bias_cycle; - const size_t outer_size = this->phase_bias.size(); - if (outer_size == 0) + if (nsys >= satellite_mask.size()) { - return phase_bias_cycle; + return {}; } - const size_t inner_size = this->phase_bias[0].size(); - phase_bias_cycle = std::vector>(outer_size, std::vector(inner_size)); - for (size_t i = 0; i < outer_size; i++) + std::vector prn; + auto sat_mask = satellite_mask[nsys]; + std::bitset bits(sat_mask); + + for (int32_t i = 0; i < HAS_MSG_NUMBER_SATELLITE_IDS; i++) { - for (size_t j = 0; j < inner_size; j++) + if ((bits[HAS_MSG_NUMBER_SATELLITE_IDS - i - 1])) { - phase_bias_cycle[i][j] = static_cast(this->phase_bias[i][j]) * HAS_MSG_PHASE_BIAS_SCALE_FACTOR; + prn.push_back(i + 1); } } - return phase_bias_cycle; + return prn; } -std::vector Galileo_HAS_data::get_num_satellites() const +std::vector Galileo_HAS_data::get_PRNs_in_mask(const std::string& system) const { - std::vector num_satellites; - if (this->Nsys == 0) + auto systems = this->get_systems_string(); + auto sys_it = std::find(systems.begin(), systems.end(), system); + if (sys_it == systems.end()) { - return num_satellites; + return {}; // system not found } - num_satellites.reserve(this->Nsys); - for (uint8_t i = 0; i < this->Nsys; i++) + auto system_index = std::distance(systems.begin(), sys_it); + return this->get_PRNs_in_mask(system_index); +} + + +std::vector Galileo_HAS_data::get_PRNs_in_submask(uint8_t nsys) const +{ + // nsys refers to the system index in the main mask + if (nsys >= this->Nsys) { - std::stringstream ss; - std::bitset bits(this->satellite_mask[i]); - ss << bits.to_string(); - std::string sat_mask = ss.str(); - num_satellites.push_back(static_cast(std::count(sat_mask.begin(), sat_mask.end(), '1'))); + return {}; } - return num_satellites; + // get equivalence of nsys in mask with nsys_sub_index in submask + auto gnss_id_in_mask = this->gnss_id_mask[nsys]; + auto sys_it = std::find(gnss_id_clock_subset.begin(), gnss_id_clock_subset.end(), gnss_id_in_mask); + if (sys_it == gnss_id_clock_subset.end()) + { + return {}; + } + uint64_t nsys_sub_index = std::distance(gnss_id_clock_subset.begin(), sys_it); + if (nsys_sub_index >= satellite_submask.size()) + { + return {}; + } + + auto mask_prns = this->get_PRNs_in_mask(nsys); + + std::vector prn_in_submask; + auto sat_submask = this->satellite_submask[nsys_sub_index]; + int count = 0; + while (sat_submask) + { + if (sat_submask & 1) + { + prn_in_submask.push_back(mask_prns[count]); + count++; + } + sat_submask >>= 1; + } + + return prn_in_submask; } std::vector Galileo_HAS_data::get_gnss_iod(uint8_t nsys) const { - std::vector gnss_iod_v = this->gnss_iod; - if (nsys >= this->Nsys) { - return gnss_iod_v; + return {}; } + std::vector gnss_iod_aux; - uint8_t num_sats_in_this_system = this->get_num_satellites()[nsys]; + std::vector num_satellites = this->get_num_satellites(); + uint8_t num_sats_in_this_system = num_satellites[nsys]; gnss_iod_aux.reserve(num_sats_in_this_system); size_t index = 0; for (uint8_t sys = 0; sys <= nsys; sys++) { - uint8_t num_sats_in_system = this->get_num_satellites()[sys]; + uint8_t num_sats_in_system = num_satellites[sys]; if (sys != nsys) { index += num_sats_in_system; @@ -728,7 +555,7 @@ std::vector Galileo_HAS_data::get_gnss_iod(uint8_t nsys) const { for (uint8_t sat = 0; sat < num_sats_in_system; sat++) { - gnss_iod_aux.push_back(gnss_iod_v[index]); + gnss_iod_aux.push_back(this->gnss_iod[index]); index++; } } @@ -737,6 +564,348 @@ std::vector Galileo_HAS_data::get_gnss_iod(uint8_t nsys) const } +std::vector Galileo_HAS_data::get_num_satellites() const +{ + if (this->Nsys == 0) + { + return {}; + } + std::vector num_satellites; + num_satellites.reserve(this->Nsys); + for (uint8_t i = 0; i < this->Nsys; i++) + { + uint64_t sat_mask = this->satellite_mask[i]; + int count = 0; + while (sat_mask) + { + count += sat_mask & 1; + sat_mask >>= 1; + } + num_satellites.push_back(count); + } + + return num_satellites; +} + + +std::vector Galileo_HAS_data::get_num_subset_satellites() const +{ + if (this->Nsys_sub == 0) + { + return {}; + } + std::vector num_satellites_subset; + num_satellites_subset.reserve(this->Nsys_sub); + + for (uint8_t i = 0; i < this->Nsys_sub; i++) + { + uint64_t sat_submask = this->satellite_submask[i]; + int count = 0; + while (sat_submask) + { + count += sat_submask & 1; + sat_submask >>= 1; + } + num_satellites_subset.push_back(count); + } + return num_satellites_subset; +} + + +float Galileo_HAS_data::get_code_bias_m(const std::string& signal, int PRN) const +{ + float code_bias_correction_m = 0.0; + const size_t outer_size = this->code_bias.size(); + if (outer_size == 0) + { + return code_bias_correction_m; + } + const size_t inner_size = this->code_bias[0].size(); + if (inner_size == 0) + { + return code_bias_correction_m; + } + + std::string targeted_system; + if ((signal == "L1 C/A") || (signal == "L1C(D)") || (signal == "L1C(P)" || (signal == "L1C(D+P)") || (signal == "L2 CM") || (signal == "L2 CL") || (signal == "L2 CM+CL") || (signal == "L2 P") || (signal == "L5 I")) || + (signal == "L5 Q") || (signal == "L5 I + L5 Q")) + { + targeted_system = std::string("GPS"); + } + if ((signal == "E1-B I/NAV OS") || (signal == "E1-C") || (signal == "E1-B + E1-C") || (signal == "E5a-I F/NAV OS") || (signal == "E5a-Q") || (signal == "E5a-I+E5a-Q") || (signal == "E5b-I I/NAV OS") || + (signal == "E5b-Q") || (signal == "E5b-I+E5b-Q") || (signal == "E5-I") || (signal == "E5-Q") || (signal == "E5-I + E5-Q") || (signal == "E6-B C/NAV HAS") || (signal == "E6-C") || (signal == "E6-B + E6-C")) + { + targeted_system = std::string("Galileo"); + } + + if (!code_bias.empty() && !targeted_system.empty()) + { + std::vector systems = this->get_systems_string(); + auto Nsys = systems.size(); + auto nsys_index = std::distance(systems.cbegin(), std::find(systems.cbegin(), systems.cend(), targeted_system)); + + if (static_cast(nsys_index) < Nsys) + { + std::vector signals = get_signals_in_mask(static_cast(nsys_index)); + auto sig_index = std::distance(signals.cbegin(), std::find(signals.cbegin(), signals.cend(), signal)); + + if (static_cast(sig_index) < signals.size()) + { + int sat_index = 0; + bool index_found = false; + for (int s = 0; s < static_cast(Nsys); s++) + { + std::vector PRNs_in_mask = get_PRNs_in_mask(s); + if (s == nsys_index) + { + if (index_found == false) + { + auto sati = std::distance(PRNs_in_mask.cbegin(), std::find(PRNs_in_mask.cbegin(), PRNs_in_mask.cend(), PRN)); + if (static_cast(sati) < PRNs_in_mask.size()) + { + sat_index += sati; + index_found = true; + } + } + } + else + { + if (index_found == false) + { + sat_index += PRNs_in_mask.size(); + } + } + } + if (index_found == true) + { + code_bias_correction_m = static_cast(this->code_bias[sat_index][sig_index]) * HAS_MSG_CODE_BIAS_SCALE_FACTOR; + } + } + } + } + + return code_bias_correction_m; +} + + +float Galileo_HAS_data::get_phase_bias_cycle(const std::string& signal, int PRN) const +{ + float phase_bias_correction_cycles = 0.0; + const size_t outer_size = this->phase_bias.size(); + if (outer_size == 0) + { + return phase_bias_correction_cycles; + } + const size_t inner_size = this->phase_bias[0].size(); + if (inner_size == 0) + { + return phase_bias_correction_cycles; + } + + std::string targeted_system; + if ((signal == "L1 C/A") || (signal == "L1C(D)") || (signal == "L1C(P)" || (signal == "L1C(D+P)") || (signal == "L2 CM") || (signal == "L2 CL") || (signal == "L2 CM+CL") || (signal == "L2 P") || (signal == "L5 I")) || + (signal == "L5 Q") || (signal == "L5 I + L5 Q")) + { + targeted_system = std::string("GPS"); + } + if ((signal == "E1-B I/NAV OS") || (signal == "E1-C") || (signal == "E1-B + E1-C") || (signal == "E5a-I F/NAV OS") || (signal == "E5a-Q") || (signal == "E5a-I+E5a-Q") || (signal == "E5b-I I/NAV OS") || + (signal == "E5b-Q") || (signal == "E5b-I+E5b-Q") || (signal == "E5-I") || (signal == "E5-Q") || (signal == "E5-I + E5-Q") || (signal == "E6-B C/NAV HAS") || (signal == "E6-C") || (signal == "E6-B + E6-C")) + { + targeted_system = std::string("Galileo"); + } + + if (!phase_bias.empty() && !targeted_system.empty()) + { + std::vector systems = this->get_systems_string(); + auto Nsys = systems.size(); + auto nsys_index = std::distance(systems.cbegin(), std::find(systems.cbegin(), systems.cend(), targeted_system)); + + if (static_cast(nsys_index) < Nsys) + { + std::vector signals = get_signals_in_mask(static_cast(nsys_index)); + auto sig_index = std::distance(signals.cbegin(), std::find(signals.cbegin(), signals.cend(), signal)); + + if (static_cast(sig_index) < signals.size()) + { + int sat_index = 0; + bool index_found = false; + for (int s = 0; s < static_cast(Nsys); s++) + { + std::vector PRNs_in_mask = get_PRNs_in_mask(s); + if (s == nsys_index) + { + if (index_found == false) + { + auto sati = std::distance(PRNs_in_mask.cbegin(), std::find(PRNs_in_mask.cbegin(), PRNs_in_mask.cend(), PRN)); + if (static_cast(sati) < PRNs_in_mask.size()) + { + sat_index += sati; + index_found = true; + } + } + } + else + { + if (index_found == false) + { + sat_index += PRNs_in_mask.size(); + } + } + } + if (index_found == true) + { + phase_bias_correction_cycles = static_cast(this->phase_bias[sat_index][sig_index]) * HAS_MSG_PHASE_BIAS_SCALE_FACTOR; + } + } + } + } + + return phase_bias_correction_cycles; +} + + +float Galileo_HAS_data::get_delta_radial_m(const std::string& system, int prn) const +{ + if (this->delta_radial.empty()) + { + return 0.0; + } + auto systems = this->get_systems_string(); + auto sys_it = std::find(systems.begin(), systems.end(), system); + if (sys_it == systems.end()) + { + return 0.0; // system not found + } + auto system_index = std::distance(systems.begin(), sys_it); + + auto prns = this->get_PRNs_in_mask(system_index); + auto it = std::find(prns.begin(), prns.end(), prn); + if (it == prns.end()) + { + return 0.0; // PRN not found + } + + auto radial_m_v = this->get_delta_radial_m(system_index); + return radial_m_v[std::distance(prns.begin(), it)]; +} + + +float Galileo_HAS_data::get_delta_in_track_m(const std::string& system, int prn) const +{ + if (this->delta_in_track.empty()) + { + return 0.0; + } + auto systems = this->get_systems_string(); + auto sys_it = std::find(systems.begin(), systems.end(), system); + if (sys_it == systems.end()) + { + return 0.0; // system not found + } + auto system_index = std::distance(systems.begin(), sys_it); + + auto prns = this->get_PRNs_in_mask(system_index); + auto it = std::find(prns.begin(), prns.end(), prn); + if (it == prns.end()) + { + return 0.0; // PRN not found + } + + auto in_track_m_v = this->get_delta_in_track_m(system_index); + return in_track_m_v[std::distance(prns.begin(), it)]; +} + + +float Galileo_HAS_data::get_delta_cross_track_m(const std::string& system, int prn) const +{ + if (this->delta_cross_track.empty()) + { + return 0.0; + } + auto systems = this->get_systems_string(); + auto sys_it = std::find(systems.begin(), systems.end(), system); + if (sys_it == systems.end()) + { + return 0.0; // system not found + } + auto system_index = std::distance(systems.begin(), sys_it); + + auto prns = this->get_PRNs_in_mask(system_index); + auto it = std::find(prns.begin(), prns.end(), prn); + if (it == prns.end()) + { + return 0.0; // PRN not found + } + + auto cross_track_m_v = this->get_delta_cross_track_m(system_index); + return cross_track_m_v[std::distance(prns.begin(), it)]; +} + + +float Galileo_HAS_data::get_clock_correction_mult_m(const std::string& system, int prn) const +{ + if (this->delta_clock_correction.empty()) + { + return 0.0; + } + auto systems = this->get_systems_string(); + auto sys_it = std::find(systems.begin(), systems.end(), system); + if (sys_it == systems.end()) + { + return 0.0; // system not found + } + auto system_index = std::distance(systems.begin(), sys_it); + + auto prns = this->get_PRNs_in_mask(system_index); + auto it = std::find(prns.begin(), prns.end(), prn); + if (it == prns.end()) + { + return 0.0; // PRN not found + } + + auto index = std::distance(prns.begin(), it); + auto clock_correction_m_v = this->get_delta_clock_correction_m(system_index); + auto dcm = static_cast(this->delta_clock_multiplier[system_index]); + return clock_correction_m_v[index] * dcm; +} + + +float Galileo_HAS_data::get_clock_subset_correction_mult_m(const std::string& system, int prn) const +{ + if (this->gnss_id_clock_subset.empty()) + { + return 0.0; + } + + auto systems = this->get_systems_string(); + auto sys_it = std::find(systems.begin(), systems.end(), system); + if (sys_it == systems.end()) + { + return 0.0; // system not found + } + auto system_index = std::distance(systems.begin(), sys_it); + + auto prns_subset = this->get_PRNs_in_submask(system_index); + auto it = std::find(prns_subset.begin(), prns_subset.end(), prn); + if (it == prns_subset.end()) + { + return 0.0; // PRN not found + } + + auto index_subset = std::distance(prns_subset.begin(), it); + auto clock_correction_m_v = this->get_delta_clock_subset_correction_m(system_index); + auto dcm = static_cast(this->delta_clock_multiplier_clock_subset[system_index]); + if (!clock_correction_m_v.empty()) + { + return clock_correction_m_v[index_subset] * dcm; + } + else + { + return 0.0; + } +} + + uint16_t Galileo_HAS_data::get_nsat() const { std::vector num_satellites = this->get_num_satellites(); @@ -745,29 +914,80 @@ uint16_t Galileo_HAS_data::get_nsat() const } -std::vector Galileo_HAS_data::get_systems_string() const -{ - const size_t nsys = this->gnss_id_mask.size(); - std::vector systems(nsys, std::string("")); - for (uint8_t i = 0; i < this->Nsys; i++) - { - std::string system("Reserved"); - if (this->gnss_id_mask[i] == 0) - { - system = "GPS"; - } - if (this->gnss_id_mask[i] == 2) - { - system = "Galileo"; - } - systems[i] = system; - } - return systems; -} - - uint16_t Galileo_HAS_data::get_nsat_sub() const { auto Nsat_sub = static_cast(this->delta_clock_correction_clock_subset.size()); return Nsat_sub; } + + +uint16_t Galileo_HAS_data::get_validity_interval_s(uint8_t validity_interval_index) const +{ + // See HAS SIS ICD v1.0 Table 23 + const std::map validity_intervals = { + {0, 5}, + {1, 10}, + {2, 15}, + {3, 20}, + {4, 30}, + {5, 60}, + {6, 90}, + {7, 120}, + {8, 180}, + {9, 240}, + {10, 300}, + {11, 600}, + {12, 900}, + {13, 1800}, + {14, 3600}}; + + auto it = validity_intervals.find(validity_interval_index); + if (it == validity_intervals.end()) + { + return 0; + } + return it->second; +} + + +uint16_t Galileo_HAS_data::get_gnss_iod(const std::string& system, int prn) const +{ + if (this->gnss_iod.empty()) + { + return 65535; // not found + } + auto systems = this->get_systems_string(); + auto sys_it = std::find(systems.begin(), systems.end(), system); + if (sys_it == systems.end()) + { + return 65535; // not found + } + auto system_index = std::distance(systems.begin(), sys_it); + + auto prns = this->get_PRNs_in_mask(system_index); + auto it = std::find(prns.begin(), prns.end(), prn); + if (it == prns.end()) + { + return 65535; // PRN not found + } + + auto gnss_iod_v = this->get_gnss_iod(system_index); + return gnss_iod_v[std::distance(prns.begin(), it)]; +} + + +uint8_t Galileo_HAS_data::get_gnss_id(int nsat) const +{ + int number_sats = 0; + for (uint8_t i = 0; i < Nsys; i++) + { + auto prns = get_PRNs_in_mask(i); + number_sats += static_cast(prns.size()); + if (nsat < number_sats) + { + return gnss_id_mask[i]; + } + } + + return HAS_MSG_WRONG_SYSTEM; +} diff --git a/src/core/system_parameters/galileo_has_data.h b/src/core/system_parameters/galileo_has_data.h index 79b50eaeb..b69eeff82 100644 --- a/src/core/system_parameters/galileo_has_data.h +++ b/src/core/system_parameters/galileo_has_data.h @@ -52,26 +52,40 @@ class Galileo_HAS_data public: Galileo_HAS_data() = default; - std::vector get_signals_in_mask(uint8_t nsys) const; //!< Get a vector of Nsys std::string with signals in mask for system nsys, with 0 <= nsys < Nsys - std::vector get_systems_string() const; //!< Get Nsys system name strings - std::vector> get_code_bias_m() const; //!< Get Nsat x Ncodes code biases in [m] - std::vector> get_phase_bias_cycle() const; //!< Get Nsat x Nphases phase biases in [cycles] - std::vector get_delta_radial_m() const; //!< Get Nsat delta radial corrections in [m] - std::vector get_delta_radial_m(uint8_t nsys) const; //!< Get delta radial corrections in [m] for system nsys, with 0 <= nsys < Nsys - std::vector get_delta_in_track_m() const; //!< Get Nsat delta in-track corrections in [m] - std::vector get_delta_in_track_m(uint8_t nsys) const; //!< Get delta in-track corrections in [m] for system nsys, with 0 <= nsys < Nsys - std::vector get_delta_cross_track_m() const; //!< Get Nsat delta cross-track corrections in [m] - std::vector get_delta_cross_track_m(uint8_t nsys) const; //!< Get delta cross-track corrections in [m] for system nsys, with 0 <= nsys < Nsys - std::vector get_delta_clock_correction_m() const; //!< Get Nsat delta clock C0 corrections in [m] - std::vector get_delta_clock_correction_m(uint8_t nsys) const; //!< Get delta clock C0 corrections in [m] for system nsys, with 0 <= nsys < Nsys - std::vector get_PRNs_in_mask(uint8_t nsys) const; //!< Get PRNs in mask for system nsys, with 0 <= nsys < Nsys - std::vector get_PRNs_in_submask(uint8_t nsys) const; //!< Get PRNs in submask for system nsys, with 0 <= nsys < Nsys - std::vector get_gnss_iod(uint8_t nsys) const; //!< Get GNSS IODs for for system nsys, with 0 <= nsys < Nsys - std::vector get_num_satellites() const; //!< Get Nsys number of satellites - uint16_t get_nsat() const; //!< Get total number of satellites with corrections - uint16_t get_nsat_sub() const; //!< Get number of satellites in clock subset corrections - uint16_t get_validity_interval_s(uint8_t validity_interval_index) const; //!< Get validity interval in [s] from the validity_interval_index - uint8_t get_gnss_id(int nsat) const; //!< Get GNSS ID from the nsat satellite + std::vector get_signals_in_mask(uint8_t nsys) const; //!< Get a vector of Nsys std::string with signals in mask for system nsys, with 0 <= nsys < Nsys + std::vector get_signals_in_mask(const std::string& system) const; //!< Get a vector of Nsys std::string with signals in mask for system ("GPS"/"Galileo") + std::vector get_systems_string() const; //!< Get Nsys system name strings + std::vector get_systems_subset_string() const; //!< Get Nsat system name strings present in clock corrections subset + std::vector> get_code_bias_m() const; //!< Get Nsat x Ncodes code biases in [m] + std::vector> get_phase_bias_cycle() const; //!< Get Nsat x Nphases phase biases in [cycles] + std::vector> get_delta_clock_subset_correction_m() const; //!< Get Nsys_sub vectors with Nsat_sub delta clock C0 corrections in [m] + std::vector get_delta_radial_m() const; //!< Get Nsat delta radial corrections in [m] + std::vector get_delta_radial_m(uint8_t nsys) const; //!< Get delta radial corrections in [m] for system nsys, with 0 <= nsys < Nsys + std::vector get_delta_in_track_m() const; //!< Get Nsat delta in-track corrections in [m] + std::vector get_delta_in_track_m(uint8_t nsys) const; //!< Get delta in-track corrections in [m] for system nsys, with 0 <= nsys < Nsys + std::vector get_delta_cross_track_m() const; //!< Get Nsat delta cross-track corrections in [m] + std::vector get_delta_cross_track_m(uint8_t nsys) const; //!< Get delta cross-track corrections in [m] for system nsys, with 0 <= nsys < Nsys + std::vector get_delta_clock_correction_m() const; //!< Get Nsat delta clock C0 corrections in [m] + std::vector get_delta_clock_correction_m(uint8_t nsys) const; //!< Get delta clock C0 corrections in [m] for system nsys, with 0 <= nsys < Nsys + std::vector get_delta_clock_subset_correction_m(uint8_t nsys) const; //!< Get delta clock C0 subset corrections in [m] for system nsys, with 0 <= nsys < Nsys + std::vector get_PRNs_in_mask(uint8_t nsys) const; //!< Get PRNs in mask for system nsys, with 0 <= nsys < Nsys + std::vector get_PRNs_in_mask(const std::string& system) const; //!< Get PRNs in mask for system ("GPS"/"Galileo") + std::vector get_PRNs_in_submask(uint8_t nsys) const; //!< Get PRNs in submask for system nsys, with 0 <= nsys < Nsys + std::vector get_gnss_iod(uint8_t nsys) const; //!< Get GNSS IODs for for system nsys, with 0 <= nsys < Nsys + std::vector get_num_satellites() const; //!< Get Nsys number of satellites + std::vector get_num_subset_satellites() const; //!< Get Nsys_sub number of satellites + float get_code_bias_m(const std::string& signal, int PRN) const; //!< Get code bias in [m] for a given signal and PRN satellite + float get_phase_bias_cycle(const std::string& signal, int PRN) const; //!< Get phase bias in [cycles] for a given signal and PRN satellite + float get_delta_radial_m(const std::string& system, int prn) const; //!< Get orbital radial correction in [m] for a given system ("GPS"/"Galileo") and PRN + float get_delta_in_track_m(const std::string& system, int prn) const; //!< Get orbital in_track correction in [m] for a given system ("GPS"/"Galileo") and PRN + float get_delta_cross_track_m(const std::string& system, int prn) const; //!< Get orbital cross_track correction in [m] for a given system ("GPS"/"Galileo") and PRN + float get_clock_correction_mult_m(const std::string& system, int prn) const; //!< Get clock correction in [m], already multiplied by its Delta Clock Multiplier, for a given system ("GPS"/"Galileo") and PRN + float get_clock_subset_correction_mult_m(const std::string& system, int prn) const; //!< Get clock correction subset in [m], already multiplied by its Delta Clock Multiplier + uint16_t get_nsat() const; //!< Get total number of satellites with corrections + uint16_t get_nsat_sub() const; //!< Get number of satellites in clock subset corrections + uint16_t get_validity_interval_s(uint8_t validity_interval_index) const; //!< Get validity interval in [s] from the validity_interval_index + uint16_t get_gnss_iod(const std::string& system, int prn) const; //!< Get GNSS IOD from a given system ("GPS"/"Galileo") and PRN + uint8_t get_gnss_id(int nsat) const; //!< Get GNSS ID from the nsat satellite // Mask std::vector gnss_id_mask; //!< GNSS ID. See HAS SIS ICD 1.0 Section 5.2.1.1 diff --git a/src/core/system_parameters/gnss_frequencies.h b/src/core/system_parameters/gnss_frequencies.h index 0d2288ceb..3099bae68 100644 --- a/src/core/system_parameters/gnss_frequencies.h +++ b/src/core/system_parameters/gnss_frequencies.h @@ -19,6 +19,9 @@ #ifndef GNSS_SDR_GNSS_FREQUENCIES_H #define GNSS_SDR_GNSS_FREQUENCIES_H +#include +#include + /** \addtogroup Core * \{ */ /** \addtogroup System_Parameters @@ -41,6 +44,21 @@ constexpr double FREQ1_BDS = 1.561098e9; //!< BeiDou B1 frequency (Hz) constexpr double FREQ2_BDS = 1.20714e9; //!< BeiDou B2 frequency (Hz) constexpr double FREQ3_BDS = 1.26852e9; //!< BeiDou B3 frequency (Hz) +const std::unordered_map SIGNAL_FREQ_MAP = { + {"1C", FREQ1}, + {"2S", FREQ2}, + {"L5", FREQ5}, + {"1B", FREQ1}, + {"5X", FREQ5}, + {"E6", FREQ6}, + {"7X", FREQ7}, + {"1G", FREQ1_GLO}, + {"2G", FREQ2_GLO}, + {"B1", FREQ1_BDS}, + {"B2", FREQ2_BDS}, + {"B3", FREQ3_BDS}, +}; + /** \} */ /** \} */ diff --git a/src/main/main.cc b/src/main/main.cc index 84e349a96..b48e2272d 100644 --- a/src/main/main.cc +++ b/src/main/main.cc @@ -11,7 +11,7 @@ * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. * This file is part of GNSS-SDR. * - * Copyright (C) 2010-2019 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2013 (see AUTHORS file for a list of contributors) * SPDX-License-Identifier: GPL-3.0-or-later * * ----------------------------------------------------------------------------- @@ -65,17 +65,26 @@ Concurrent_Map global_gps_acq_assist_map; int main(int argc, char** argv) { - const std::string intro_help( - std::string("\nGNSS-SDR is an Open Source GNSS Software Defined Receiver\n") + - "Copyright (C) 2010-2022 (see AUTHORS file for a list of contributors)\n" + - "This program comes with ABSOLUTELY NO WARRANTY;\n" + - "See COPYING file to see a copy of the General Public License\n \n"); + try + { + const std::string intro_help( + std::string("\nGNSS-SDR is an Open Source GNSS Software Defined Receiver\n") + + "Copyright (C) 2010-2023 (see AUTHORS file for a list of contributors)\n" + + "This program comes with ABSOLUTELY NO WARRANTY;\n" + + "See COPYING file to see a copy of the General Public License\n \n"); - const std::string gnss_sdr_version(GNSS_SDR_VERSION); - gflags::SetUsageMessage(intro_help); - gflags::SetVersionString(gnss_sdr_version); - gflags::ParseCommandLineFlags(&argc, &argv, true); - std::cout << "Initializing GNSS-SDR v" << gnss_sdr_version << " ... Please wait.\n"; + const std::string gnss_sdr_version(GNSS_SDR_VERSION); + gflags::SetUsageMessage(intro_help); + gflags::SetVersionString(gnss_sdr_version); + gflags::ParseCommandLineFlags(&argc, &argv, true); + std::cout << "Initializing GNSS-SDR v" << gnss_sdr_version << " ... Please wait.\n"; + } + catch (const std::exception& e) + { + std::cerr << e.what() << '\n'; + std::cout << "GNSS-SDR program ended.\n"; + return 1; + } #if CUDA_GPU_ACCEL // Reset the device @@ -100,21 +109,31 @@ int main(int argc, char** argv) } else { - const fs::path p(FLAGS_log_dir); - if (!fs::exists(p)) + try { - std::cout << "The path " - << FLAGS_log_dir - << " does not exist, attempting to create it.\n"; - errorlib::error_code ec; - if (!fs::create_directory(p, ec)) + const fs::path p(FLAGS_log_dir); + if (!fs::exists(p)) { - std::cerr << "Could not create the " << FLAGS_log_dir << " folder. GNSS-SDR program ended.\n"; - gflags::ShutDownCommandLineFlags(); - return 1; + std::cout << "The path " + << FLAGS_log_dir + << " does not exist, attempting to create it.\n"; + errorlib::error_code ec; + if (!fs::create_directory(p, ec)) + { + std::cerr << "Could not create the " << FLAGS_log_dir << " folder. GNSS-SDR program ended.\n"; + gflags::ShutDownCommandLineFlags(); + return 1; + } } + std::cout << "Logging will be written at " << FLAGS_log_dir << '\n'; + } + catch (const std::exception& e) + { + std::cerr << e.what() << '\n'; + std::cerr << "Could not create the " << FLAGS_log_dir << " folder. GNSS-SDR program ended.\n"; + gflags::ShutDownCommandLineFlags(); + return 1; } - std::cout << "Logging will be written at " << FLAGS_log_dir << '\n'; } } @@ -132,9 +151,7 @@ int main(int argc, char** argv) catch (const boost::thread_resource_error& e) { std::cerr << "Failed to create boost thread.\n"; - gflags::ShutDownCommandLineFlags(); - std::cout << "GNSS-SDR program ended.\n"; - return 1; + return_code = 1; } catch (const boost::exception& e) { @@ -147,9 +164,7 @@ int main(int argc, char** argv) { std::cerr << "Boost exception: " << boost::diagnostic_information(e) << '\n'; } - gflags::ShutDownCommandLineFlags(); - std::cout << "GNSS-SDR program ended.\n"; - return 1; + return_code = 1; } catch (const std::exception& ex) { @@ -162,9 +177,7 @@ int main(int argc, char** argv) { std::cerr << "C++ Standard Library exception: " << ex.what() << '\n'; } - gflags::ShutDownCommandLineFlags(); - std::cout << "GNSS-SDR program ended.\n"; - return 1; + return_code = 1; } catch (...) { @@ -177,9 +190,7 @@ int main(int argc, char** argv) { std::cerr << "Unexpected catch. This should not happen.\n"; } - gflags::ShutDownCommandLineFlags(); - std::cout << "GNSS-SDR program ended.\n"; - return 1; + return_code = 1; } // report the elapsed time diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index 6a71d38d0..af8e96075 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -37,12 +37,6 @@ if(NOT GOOGLETEST_FOUND) if(CMAKE_GENERATOR STREQUAL Xcode) set(GTEST_BUILD_COMMAND "xcodebuild" "-configuration" $<$:Debug>$<$:Release>$<$:RelWithDebInfo>$<$:MinSizeRel> "-target" "gtest_main") endif() - if((CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0) OR - (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0)) - set(GOOGLETEST_GIT_TAG v${GNSSSDR_GTEST_LOCAL_VERSION}) - else() - set(GOOGLETEST_GIT_TAG release-${GNSSSDR_GTEST_LOCAL_VERSION}) - endif() if(GNSSSDR_GTEST_LOCAL_VERSION VERSION_LESS 1.12.0) set(DEBUG_DECORATION "d") else() @@ -51,7 +45,7 @@ if(NOT GOOGLETEST_FOUND) if(CMAKE_VERSION VERSION_LESS 3.2) ExternalProject_Add(gtest-${GNSSSDR_GTEST_LOCAL_VERSION} GIT_REPOSITORY https://github.com/google/googletest - GIT_TAG ${GOOGLETEST_GIT_TAG} + GIT_TAG v${GNSSSDR_GTEST_LOCAL_VERSION} SOURCE_DIR ${GNSSSDR_BINARY_DIR}/thirdparty/gtest/gtest-${GNSSSDR_GTEST_LOCAL_VERSION} BINARY_DIR ${GNSSSDR_BINARY_DIR}/gtest-${GNSSSDR_GTEST_LOCAL_VERSION} CMAKE_ARGS ${GTEST_COMPILER} @@ -80,7 +74,7 @@ if(NOT GOOGLETEST_FOUND) endif() ExternalProject_Add(gtest-${GNSSSDR_GTEST_LOCAL_VERSION} GIT_REPOSITORY https://github.com/google/googletest - GIT_TAG ${GOOGLETEST_GIT_TAG} + GIT_TAG v${GNSSSDR_GTEST_LOCAL_VERSION} SOURCE_DIR ${GNSSSDR_BINARY_DIR}/thirdparty/gtest/gtest-${GNSSSDR_GTEST_LOCAL_VERSION} BINARY_DIR ${GNSSSDR_BINARY_DIR}/gtest-${GNSSSDR_GTEST_LOCAL_VERSION} CMAKE_ARGS ${GTEST_COMPILER} @@ -369,12 +363,14 @@ if(ENABLE_UNIT_TESTING_EXTRA OR ENABLE_SYSTEM_TESTING_EXTRA OR ENABLE_FPGA) if(CMAKE_VERSION VERSION_GREATER 3.17.0) set(GNSSTK_PATCH_COMMAND cd ${GNSSSDR_BINARY_DIR}/thirdparty/gnsstk-${GNSSSDR_GNSSTK_LOCAL_VERSION} && - ${Patch_EXECUTABLE} ${GNSSSDR_BINARY_DIR}/thirdparty/gnsstk-${GNSSSDR_GNSSTK_LOCAL_VERSION}/CMakeLists.txt < ${GNSSSDR_SOURCE_DIR}/src/tests/data/gnsstk_static14.patch + ${Patch_EXECUTABLE} ${GNSSSDR_BINARY_DIR}/thirdparty/gnsstk-${GNSSSDR_GNSSTK_LOCAL_VERSION}/CMakeLists.txt < ${GNSSSDR_SOURCE_DIR}/src/tests/data/gnsstk_static14.patch && + ${Patch_EXECUTABLE} ${GNSSSDR_BINARY_DIR}/thirdparty/gnsstk-${GNSSSDR_GNSSTK_LOCAL_VERSION}/core/lib/GNSSCore/ObsID.hpp < ${GNSSSDR_SOURCE_DIR}/src/tests/data/gnsstk_gcc13.patch ) else() set(GNSSTK_PATCH_COMMAND cd ${GNSSSDR_BINARY_DIR}/thirdparty/gnsstk-${GNSSSDR_GNSSTK_LOCAL_VERSION} && - ${Patch_EXECUTABLE} ${GNSSSDR_BINARY_DIR}/thirdparty/gnsstk-${GNSSSDR_GNSSTK_LOCAL_VERSION}/CMakeLists.txt < ${GNSSSDR_SOURCE_DIR}/src/tests/data/gnsstk_static13.patch + ${Patch_EXECUTABLE} ${GNSSSDR_BINARY_DIR}/thirdparty/gnsstk-${GNSSSDR_GNSSTK_LOCAL_VERSION}/CMakeLists.txt < ${GNSSSDR_SOURCE_DIR}/src/tests/data/gnsstk_static13.patch && + ${Patch_EXECUTABLE} ${GNSSSDR_BINARY_DIR}/thirdparty/gnsstk-${GNSSSDR_GNSSTK_LOCAL_VERSION}/core/lib/GNSSCore/ObsID.hpp < ${GNSSSDR_SOURCE_DIR}/src/tests/data/gnsstk_gcc13.patch ) endif() # Patch only once @@ -408,6 +404,9 @@ if(ENABLE_UNIT_TESTING_EXTRA OR ENABLE_SYSTEM_TESTING_EXTRA OR ENABLE_FPGA) set(GNSSTK_PARALLEL_BUILD "-j${NUMBER_OF_PROCESSORS}") endif() endif() + if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + set(GNSSTK_FLAGS "-DCMAKE_CXX_FLAGS:STRING=-w") # Fix for clang in aarch64 + endif() if(CMAKE_VERSION VERSION_GREATER 3.17.0) ExternalProject_Add(gnsstk-${GNSSSDR_GNSSTK_LOCAL_VERSION} GIT_REPOSITORY https://github.com/SGL-UT/gnsstk @@ -425,6 +424,7 @@ if(ENABLE_UNIT_TESTING_EXTRA OR ENABLE_SYSTEM_TESTING_EXTRA OR ENABLE_FPGA) -DCMAKE_CXX_EXTENSIONS=ON -DCMAKE_C_STANDARD=11 -DCMAKE_C_EXTENSIONS=ON + "${GNSSTK_FLAGS}" BUILD_COMMAND ${GNSSTK_BUILD_COMMAND} ${GNSSTK_PARALLEL_BUILD} BUILD_BYPRODUCTS ${GNSSSDR_BINARY_DIR}/gnsstk-${GNSSSDR_GNSSTK_LOCAL_VERSION}/install/lib/${CMAKE_FIND_LIBRARY_PREFIXES}gnsstk${CMAKE_STATIC_LIBRARY_SUFFIX} UPDATE_COMMAND "" diff --git a/src/tests/data/gnsstk_gcc13.patch b/src/tests/data/gnsstk_gcc13.patch new file mode 100644 index 000000000..e2ac0030f --- /dev/null +++ b/src/tests/data/gnsstk_gcc13.patch @@ -0,0 +1,12 @@ +SPDX-License-Identifier: GPL-3.0-or-later +SPDX-FileCopyrightText: 2022 Carles Fernandez-Prades +--- ObsID.hpp 2023-01-23 16:53:25.000000000 +0100 ++++ ObsID.hpp 2023-01-23 16:55:14.000000000 +0100 +@@ -47,6 +47,7 @@ + #ifndef OBSID_HPP + #define OBSID_HPP + ++#include + #include + #include + #include diff --git a/src/tests/unit-tests/system-parameters/has_decoding_test.cc b/src/tests/unit-tests/system-parameters/has_decoding_test.cc index 5f4c7930f..593ce79de 100644 --- a/src/tests/unit-tests/system-parameters/has_decoding_test.cc +++ b/src/tests/unit-tests/system-parameters/has_decoding_test.cc @@ -353,6 +353,10 @@ TEST(HAS_Test, Decoder) EXPECT_EQ(has_message->phase_discontinuity_indicator[has_message->get_PRNs_in_mask(0).size() + i][2], phase_discontinuity_indicator_expected_gal[i]); EXPECT_EQ(has_message->phase_discontinuity_indicator[has_message->get_PRNs_in_mask(0).size() + i][3], phase_discontinuity_indicator_expected_gal[i]); } + EXPECT_FLOAT_EQ(has_message->get_code_bias_m("L1 C/A", 10), -2.64 * HAS_MSG_CODE_BIAS_SCALE_FACTOR); + EXPECT_FLOAT_EQ(has_message->get_code_bias_m("L1 C/A", 11), 0.0); + EXPECT_FLOAT_EQ(has_message->get_code_bias_m("E1-C", 36), -1.98 * HAS_MSG_CODE_BIAS_SCALE_FACTOR); + EXPECT_FLOAT_EQ(has_message->get_code_bias_m("E1-C", 37), 0.0); } else {