├── .bazeliskrc ├── .bazelrc ├── .clang-format ├── .github └── workflows │ ├── auto-cancellation.yaml │ └── ci.yaml ├── .gitignore ├── .gitmodules ├── BUILD.bazel ├── CMakeLists.txt ├── Dockerfile ├── Dockerfile.modern ├── Jenkinsfile ├── LICENSE ├── Makefile ├── README.md ├── WORKSPACE.bazel ├── bazel ├── BUILD.bazel └── max_channels_config.bzl ├── ci-build.sh ├── codecov.yml ├── docker-compose.yml ├── include └── swiftnav │ ├── almanac.h │ ├── array_tools.h │ ├── bits.h │ ├── bitstream.h │ ├── bytestream.h │ ├── ch_meas.h │ ├── common.h │ ├── constants.h │ ├── coord_system.h │ ├── decode_glo.h │ ├── edc.h │ ├── ephemeris.h │ ├── fifo_byte.h │ ├── float_equality.h │ ├── geoid_model.h │ ├── glo_map.h │ ├── glonass_phase_biases.h │ ├── gnss_capabilities.h │ ├── gnss_time.h │ ├── ionosphere.h │ ├── leap_seconds.h │ ├── linear_algebra.h │ ├── logging.h │ ├── macro_overload.h │ ├── macros.h │ ├── memcpy_s.h │ ├── nav_meas.h │ ├── pvt_result.h │ ├── sbas_raw_data.h │ ├── set.h │ ├── shm.h │ ├── sid_set.h │ ├── signal.h │ ├── single_epoch_solver.h │ ├── subsystem_status_report.h │ ├── swift_strnlen.h │ └── troposphere.h ├── scripts ├── gtx_convert.pl ├── leap_seconds_generator.py └── requirements.txt ├── src ├── almanac.c ├── bits.c ├── coord_system.c ├── decode_glo.c ├── edc.c ├── ephemeris.c ├── fifo_byte.c ├── geoid_model.c ├── geoid_model_15_minute.inc ├── geoid_model_1_degree.inc ├── glo_map.c ├── glonass_phase_biases.c ├── gnss_time.c ├── ionosphere.c ├── linear_algebra.c ├── logging.c ├── logging_common.c ├── max_channels.h.in ├── memcpy_s.c ├── nav_meas.c ├── set.c ├── shm.c ├── sid_set.c ├── signal.c ├── single_epoch_solver.c ├── subsystem_status_report.c └── troposphere.c ├── tests ├── CMakeLists.txt ├── check_almanac.c ├── check_bits.c ├── check_coord_system.c ├── check_decode_glo.c ├── check_edc.c ├── check_ephemeris.c ├── check_geoid_model.cc ├── check_glo_map.c ├── check_gnss_time.c ├── check_gnss_time_cpp.cc ├── check_ionosphere.c ├── check_linear_algebra.c ├── check_log.c ├── check_main.c ├── check_nav_meas.c ├── check_pedantic.cc ├── check_pvt.c ├── check_set.c ├── check_shm.c ├── check_sid_set.c ├── check_signal.c ├── check_subsystem_status_report.c ├── check_suites.h ├── check_troposphere.c └── common │ ├── CMakeLists.txt │ ├── check_utils.c │ └── check_utils.h └── tools ├── check2junit.py └── requirements.txt /.bazeliskrc: -------------------------------------------------------------------------------- 1 | USE_BAZEL_VERSION=6.2.0 2 | -------------------------------------------------------------------------------- /.bazelrc: -------------------------------------------------------------------------------- 1 | build:clang-format-check --aspects @rules_swiftnav//clang_format:clang_format_check.bzl%clang_format_check_aspect 2 | build:clang-format-check --@rules_swiftnav//clang_format:clang_format_config=//:clang_format_config 3 | build:clang-format-check --output_groups=report 4 | 5 | build:clang-tidy --aspects @rules_swiftnav//clang_tidy:clang_tidy.bzl%clang_tidy_aspect 6 | build:clang-tidy --output_groups=report 7 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | # Complete list of style options can be found at: 2 | # http://clang.llvm.org/docs/ClangFormatStyleOptions.html 3 | --- 4 | Language: Cpp 5 | BasedOnStyle: Google 6 | Standard: Cpp11 7 | BinPackParameters: false 8 | BinPackArguments: false 9 | ... 10 | -------------------------------------------------------------------------------- /.github/workflows/auto-cancellation.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Cancelling previous actions runs. 3 | "on": pull_request 4 | jobs: 5 | cancel: 6 | name: auto-cancellation-running-action 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: fauguste/auto-cancellation-running-action@0.1.4 10 | with: 11 | githubToken: ${{ secrets.GITHUB_TOKEN }} 12 | -------------------------------------------------------------------------------- /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: 7 | - 'master' 8 | - 'starling-v*-release' 9 | - 'v*-release' 10 | tags: 11 | - 'v*' 12 | - 'starling-v*' 13 | 14 | jobs: 15 | 16 | ubuntu-codecov: 17 | runs-on: ubuntu-latest 18 | container: ubuntu:18.04 19 | 20 | steps: 21 | 22 | - name: Setup container 23 | run: | 24 | apt-get update 25 | apt-get install -y gpg wget curl software-properties-common unzip 26 | add-apt-repository -y ppa:git-core/ppa 27 | wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - \ 28 | | tee /usr/share/keyrings/kitware-archive-keyring.gpg >/dev/null 29 | echo 'deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ bionic-rc main' \ 30 | | tee -a /etc/apt/sources.list.d/kitware.list >/dev/null 31 | apt-get update 32 | apt-get install -y git cmake build-essential clang llvm 33 | 34 | - name: Checkout source 35 | uses: actions/checkout@v2 36 | with: 37 | fetch-depth: 0 38 | submodules: recursive 39 | ssh-key: ${{ secrets.SSH_KEY }} 40 | 41 | - name: Run build 42 | env: 43 | CC: clang 44 | CXX: clang++ 45 | TESTENV: codecov 46 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 47 | SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} 48 | SONAR_ORGANIZATION: swift-nav 49 | SONAR_PROJECT_KEY: swift-nav_libswiftnav-private 50 | SONAR_PROJECT_NAME: libswiftnav-private 51 | SONAR_HOST_URL: https://sonarcloud.io 52 | SONAR_SCANNER_VERSION: 4.2.0.1873 53 | 54 | run: | 55 | bash ./ci-build.sh 56 | 57 | windows: 58 | strategy: 59 | matrix: 60 | include: 61 | - {env: "MSVC", arch: "Win32"} 62 | - {env: "MSVC", arch: "x64"} 63 | - {env: "MinGW"} 64 | 65 | runs-on: windows-2019 66 | 67 | steps: 68 | 69 | - name: Checkout source 70 | uses: actions/checkout@v2 71 | with: 72 | submodules: recursive 73 | ssh-key: ${{ secrets.SSH_KEY }} 74 | 75 | - name: Install CMake 76 | run: | 77 | choco install -y --no-progress cmake 78 | 79 | - name: Downgrade MinGW to 6.4.0 (MinGW) 80 | if: matrix.env == 'MinGW' 81 | run: | 82 | choco install -y --no-progress --allow-downgrade --version=6.4.0 mingw 83 | 84 | - name: Install msys2 packages (MinGW) 85 | if: matrix.env == 'MinGW' 86 | uses: msys2/setup-msys2@v2 87 | with: 88 | msystem: MINGW64 89 | install: git base-devel 90 | update: true 91 | 92 | - name: Run build (MSVC) 93 | if: matrix.env == 'MSVC' 94 | env: 95 | CMAKE_GENERATOR: "Visual Studio 16 2019" 96 | run: | 97 | cmake -G "$env:CMAKE_GENERATOR" -A ${{ matrix.arch }} -S . -B build; 98 | cmake --build build --config Release; 99 | bash -c "ls -la ./build/Release/swiftnav.lib || exit 1" 100 | 101 | - name: Run build (MinGW) 102 | if: matrix.env == 'MinGW' 103 | env: 104 | CMAKE_GENERATOR: "MinGW Makefiles" 105 | CC: gcc 106 | CXX: g++ 107 | run: | 108 | cmake -B build -S . -G "$env:CMAKE_GENERATOR"; 109 | cmake --build build 110 | 111 | unix: 112 | strategy: 113 | matrix: 114 | include: 115 | - {cc: "gcc-6", cxx: "g++-6", test_suite: "unit", 116 | package: "gcc-6 g++-6", runs_on: "ubuntu-latest", container: "ubuntu:18.04"} 117 | - {cc: "clang-6.0", cxx: "clang++-6.0", test_suite: "lint", 118 | package: "clang-6.0 libc++-dev libc++abi-dev clang-format-6.0 clang-tidy-6.0", 119 | runs_on: "ubuntu-latest", container: "ubuntu:18.04"} 120 | - {cc: "gcc-11", cxx: "g++-11", test_suite: "unit", 121 | package: "gcc-11 g++-11", runs_on: "ubuntu-latest", container: "ubuntu:18.04"} 122 | - {cc: "clang", cxx: "clang++", test_suite: "unit", 123 | runs_on: "macos-11", container: ~} 124 | 125 | runs-on: ${{ matrix.runs_on }} 126 | container: ${{ matrix.container }} 127 | 128 | steps: 129 | 130 | - name: Setup container 131 | if: matrix.container == 'ubuntu:18.04' 132 | run: | 133 | apt-get update 134 | apt-get install -y gpg wget curl software-properties-common zip 135 | add-apt-repository ppa:ubuntu-toolchain-r/test -y 136 | add-apt-repository -y ppa:git-core/ppa 137 | wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null \ 138 | | gpg --dearmor - | tee /usr/share/keyrings/kitware-archive-keyring.gpg >/dev/null 139 | echo 'deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ bionic-rc main' \ 140 | | tee -a /etc/apt/sources.list.d/kitware.list >/dev/null 141 | apt-get update 142 | apt-get install -y libeigen3-dev libserialport-dev git cmake build-essential ${{ matrix.package }} 143 | 144 | - name: Checkout source 145 | uses: actions/checkout@v2 146 | with: 147 | submodules: recursive 148 | ssh-key: ${{ secrets.SSH_KEY }} 149 | 150 | - name: Run build 151 | env: 152 | CC: ${{ matrix.cc }} 153 | CXX: ${{ matrix.cxx }} 154 | TEST_SUITE: ${{ matrix.test_suite }} 155 | TESTENV: c 156 | run: | 157 | bash ./ci-build.sh 158 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build* 2 | include/swiftnav/config.h 3 | *.swp 4 | .clang-tidy 5 | 6 | # IDE files 7 | .vscode/ 8 | 9 | ### Added by Hedron's Bazel Compile Commands Extractor: https://github.com/hedronvision/bazel-compile-commands-extractor 10 | # The external link: Differs on Windows vs macOS/Linux, so we can't check it in. The pattern needs to not have a trailing / because it's a symlink on macOS/Linux. 11 | /external 12 | # Bazel output symlinks: Same reasoning as /external. You need the * because people can change the name of the directory your repository is cloned into, changing the bazel- symlink. 13 | /bazel-* 14 | # Compiled output -> don't check in 15 | /compile_commands.json 16 | # Directory where clangd puts its indexing work 17 | /.cache/ 18 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "cmake/common"] 2 | path = cmake/common 3 | url = https://github.com/swift-nav/cmake.git 4 | [submodule "third_party/check"] 5 | path = third_party/check 6 | url = https://github.com/swift-nav/check.git 7 | -------------------------------------------------------------------------------- /BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@hedron_compile_commands//:refresh_compile_commands.bzl", "refresh_compile_commands") 2 | load("@rules_swiftnav//cc:defs.bzl", "UNIT", "swift_c_library", "swift_cc_test", "swift_cc_test_library") 3 | load("@bazel_skylib//rules:common_settings.bzl", "int_flag", "bool_flag") 4 | load("//bazel:max_channels_config.bzl", "max_channels_config") 5 | 6 | refresh_compile_commands( 7 | name = "gen_compile_commands", 8 | visibility = ["//visibility:public"], 9 | ) 10 | 11 | int_flag( 12 | name = "max_channels", 13 | build_setting_default = 63, 14 | ) 15 | 16 | bool_flag( 17 | name = "enable_stderr_logging", 18 | build_setting_default = True, 19 | visibility = ["//visibility:public"], 20 | ) 21 | 22 | config_setting( 23 | name = "_enable_stderr_logging", 24 | flag_values = {"enable_stderr_logging": "true"}, 25 | ) 26 | 27 | max_channels_config( 28 | name = "max_channels_h", 29 | out = "max_channels.h", 30 | max_channels = ":max_channels", 31 | template = "src/max_channels.h.in", 32 | ) 33 | 34 | swift_c_library( 35 | name = "swiftnav", 36 | srcs = [ 37 | "src/almanac.c", 38 | "src/bits.c", 39 | "src/coord_system.c", 40 | "src/decode_glo.c", 41 | "src/edc.c", 42 | "src/ephemeris.c", 43 | "src/fifo_byte.c", 44 | "src/geoid_model.c", 45 | "src/geoid_model_15_minute.inc", 46 | "src/geoid_model_1_degree.inc", 47 | "src/glo_map.c", 48 | "src/glonass_phase_biases.c", 49 | "src/gnss_time.c", 50 | "src/ionosphere.c", 51 | "src/linear_algebra.c", 52 | "src/logging.c", 53 | "src/logging_common.c", 54 | "src/memcpy_s.c", 55 | "src/nav_meas.c", 56 | "src/set.c", 57 | "src/shm.c", 58 | "src/sid_set.c", 59 | "src/signal.c", 60 | "src/single_epoch_solver.c", 61 | "src/subsystem_status_report.c", 62 | "src/troposphere.c", 63 | ":max_channels_h", 64 | ], 65 | hdrs = [ 66 | "include/swiftnav/almanac.h", 67 | "include/swiftnav/array_tools.h", 68 | "include/swiftnav/bits.h", 69 | "include/swiftnav/bitstream.h", 70 | "include/swiftnav/bytestream.h", 71 | "include/swiftnav/ch_meas.h", 72 | "include/swiftnav/common.h", 73 | "include/swiftnav/constants.h", 74 | "include/swiftnav/coord_system.h", 75 | "include/swiftnav/decode_glo.h", 76 | "include/swiftnav/edc.h", 77 | "include/swiftnav/ephemeris.h", 78 | "include/swiftnav/fifo_byte.h", 79 | "include/swiftnav/float_equality.h", 80 | "include/swiftnav/geoid_model.h", 81 | "include/swiftnav/glo_map.h", 82 | "include/swiftnav/glonass_phase_biases.h", 83 | "include/swiftnav/gnss_capabilities.h", 84 | "include/swiftnav/gnss_time.h", 85 | "include/swiftnav/ionosphere.h", 86 | "include/swiftnav/leap_seconds.h", 87 | "include/swiftnav/linear_algebra.h", 88 | "include/swiftnav/logging.h", 89 | "include/swiftnav/macro_overload.h", 90 | "include/swiftnav/macros.h", 91 | "include/swiftnav/memcpy_s.h", 92 | "include/swiftnav/nav_meas.h", 93 | "include/swiftnav/pvt_result.h", 94 | "include/swiftnav/sbas_raw_data.h", 95 | "include/swiftnav/set.h", 96 | "include/swiftnav/shm.h", 97 | "include/swiftnav/sid_set.h", 98 | "include/swiftnav/signal.h", 99 | "include/swiftnav/single_epoch_solver.h", 100 | "include/swiftnav/subsystem_status_report.h", 101 | "include/swiftnav/swift_strnlen.h", 102 | "include/swiftnav/troposphere.h", 103 | ], 104 | copts = ["-UNDEBUG"], 105 | local_defines = select({ 106 | "_enable_stderr_logging": ["LIBSWIFTNAV_ENABLE_STDERR_LOGGING=ON"], 107 | "//conditions:default": [], 108 | }), 109 | includes = ["include"], 110 | nocopts = [ 111 | "-Wconversion", 112 | "-Wstack-protector", 113 | ], 114 | textual_hdrs = [ 115 | "src/signal.c", 116 | "src/geoid_model.c", 117 | ], 118 | visibility = ["//visibility:public"], 119 | ) 120 | 121 | swift_cc_test_library( 122 | name = "check-utils", 123 | srcs = ["tests/common/check_utils.c"], 124 | hdrs = ["tests/common/check_utils.h"], 125 | deps = ["//:swiftnav"], 126 | ) 127 | 128 | swift_cc_test( 129 | name = "swiftnav-test", 130 | srcs = [ 131 | "tests/check_almanac.c", 132 | "tests/check_bits.c", 133 | "tests/check_coord_system.c", 134 | "tests/check_decode_glo.c", 135 | "tests/check_edc.c", 136 | "tests/check_ephemeris.c", 137 | "tests/check_geoid_model.cc", 138 | "tests/check_glo_map.c", 139 | "tests/check_gnss_time.c", 140 | "tests/check_gnss_time_cpp.cc", 141 | "tests/check_ionosphere.c", 142 | "tests/check_linear_algebra.c", 143 | "tests/check_log.c", 144 | "tests/check_main.c", 145 | "tests/check_nav_meas.c", 146 | "tests/check_pvt.c", 147 | "tests/check_set.c", 148 | "tests/check_shm.c", 149 | "tests/check_sid_set.c", 150 | "tests/check_signal.c", 151 | "tests/check_subsystem_status_report.c", 152 | "tests/check_suites.h", 153 | "tests/check_troposphere.c", 154 | ], 155 | type = UNIT, 156 | deps = [ 157 | "//:check-utils", 158 | "//:swiftnav", 159 | "@check", 160 | ], 161 | ) 162 | 163 | filegroup( 164 | name = "clang_format_config", 165 | srcs = [".clang-format"], 166 | visibility = ["//visibility:public"], 167 | ) 168 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.3) 2 | project(libswiftnav) 3 | 4 | set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake/" "${CMAKE_CURRENT_LIST_DIR}/cmake/common") 5 | 6 | set(MAX_CHANNELS "63" CACHE STRING "Maximum number of concurrent GNSS channels to support.") 7 | configure_file(src/max_channels.h.in max_channels.h) 8 | 9 | include(GNUInstallDirs) 10 | include(CCache) 11 | include(SwiftCmakeOptions) 12 | include(TestTargets) 13 | include(LanguageStandards) 14 | include(CompileOptions) 15 | 16 | find_package(Python3 COMPONENTS Interpreter) 17 | 18 | set(disable_tests FALSE) 19 | if(WIN32) 20 | message(STATUS "MSVC detected, skipping unit tests") 21 | set(disable_tests TRUE) 22 | endif() 23 | 24 | swift_create_project_options( 25 | HAS_TESTS 26 | HAS_TEST_LIBS 27 | DISABLE_TEST_COMPONENTS ${disable_tests} 28 | TEST_PACKAGES "Check" 29 | ) 30 | 31 | include(ClangFormat) 32 | swift_setup_clang_format() 33 | include(ClangTidy) 34 | include(CodeCoverage) 35 | add_code_coverage_all_targets() 36 | include(CheckAttributes) 37 | create_check_attributes_target(EXCLUDE "include/swiftnav/macros.h") 38 | include(SwiftTargets) 39 | 40 | option(LIBSWIFTNAV_ENABLE_STDERR_LOGGING "Enable logging to stderr by default" ON) 41 | 42 | set(HDRS 43 | include/swiftnav/almanac.h 44 | include/swiftnav/array_tools.h 45 | include/swiftnav/bits.h 46 | include/swiftnav/bitstream.h 47 | include/swiftnav/bytestream.h 48 | include/swiftnav/ch_meas.h 49 | include/swiftnav/common.h 50 | include/swiftnav/constants.h 51 | include/swiftnav/coord_system.h 52 | include/swiftnav/decode_glo.h 53 | include/swiftnav/edc.h 54 | include/swiftnav/ephemeris.h 55 | include/swiftnav/fifo_byte.h 56 | include/swiftnav/float_equality.h 57 | include/swiftnav/geoid_model.h 58 | include/swiftnav/glo_map.h 59 | include/swiftnav/glonass_phase_biases.h 60 | include/swiftnav/gnss_capabilities.h 61 | include/swiftnav/gnss_time.h 62 | include/swiftnav/ionosphere.h 63 | include/swiftnav/leap_seconds.h 64 | include/swiftnav/linear_algebra.h 65 | include/swiftnav/logging.h 66 | include/swiftnav/macro_overload.h 67 | include/swiftnav/macros.h 68 | include/swiftnav/memcpy_s.h 69 | include/swiftnav/nav_meas.h 70 | include/swiftnav/pvt_result.h 71 | include/swiftnav/sbas_raw_data.h 72 | include/swiftnav/set.h 73 | include/swiftnav/shm.h 74 | include/swiftnav/sid_set.h 75 | include/swiftnav/signal.h 76 | include/swiftnav/single_epoch_solver.h 77 | include/swiftnav/swift_strnlen.h 78 | include/swiftnav/troposphere.h) 79 | 80 | set(SRCS 81 | src/almanac.c 82 | src/bits.c 83 | src/coord_system.c 84 | src/decode_glo.c 85 | src/edc.c 86 | src/ephemeris.c 87 | src/fifo_byte.c 88 | src/geoid_model.c 89 | src/glo_map.c 90 | src/glonass_phase_biases.c 91 | src/gnss_time.c 92 | src/ionosphere.c 93 | src/linear_algebra.c 94 | src/logging_common.c 95 | src/logging.c 96 | src/memcpy_s.c 97 | src/nav_meas.c 98 | src/set.c 99 | src/shm.c 100 | src/sid_set.c 101 | src/signal.c 102 | src/single_epoch_solver.c 103 | src/subsystem_status_report.c 104 | src/troposphere.c) 105 | 106 | swift_add_library(swiftnav 107 | SOURCES ${HDRS} ${SRCS} 108 | REMOVE_COMPILE_OPTIONS -Wconversion -Wstack-protector 109 | ) 110 | 111 | target_include_directories(swiftnav PUBLIC ${PROJECT_SOURCE_DIR}/include) 112 | target_include_directories(swiftnav PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) 113 | if(LIBSWIFTNAV_ENABLE_STDERR_LOGGING) 114 | target_compile_definitions(swiftnav PRIVATE "LIBSWIFTNAV_ENABLE_STDERR_LOGGING") 115 | endif() 116 | 117 | target_compile_options(swiftnav PRIVATE "-UNDEBUG") 118 | 119 | if (MSVC) 120 | else () 121 | target_link_libraries(swiftnav PRIVATE m) 122 | endif() 123 | 124 | install(FILES ${HDRS} DESTINATION ${CMAKE_INSTALL_FULL_INCLUDEDIR}/swiftnav) 125 | install(TARGETS swiftnav DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR}) 126 | 127 | # unit tests 128 | if(libswiftnav_BUILD_TESTS OR libswiftnav_BUILD_TEST_LIBS) 129 | add_subdirectory(tests) 130 | endif() 131 | 132 | add_custom_target(do-update-leap_seconds 133 | COMMAND Python3::Interpreter ${PROJECT_SOURCE_DIR}/scripts/leap_seconds_generator.py ${PROJECT_SOURCE_DIR}/include/swiftnav/leap_seconds.h 134 | ) 135 | 136 | swift_validate_targets() 137 | swift_create_clang_tidy_targets(DONT_GENERATE_CLANG_TIDY_CONFIG) 138 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Base image is created by https://github.com/swift-nav/docker-recipes 2 | FROM 571934480752.dkr.ecr.us-west-2.amazonaws.com/swift-build:2023-04-24 3 | 4 | # Add anything that's specific to this repo's build environment here. 5 | COPY tools/requirements.txt /tmp/libswiftnav_requirements.txt 6 | RUN pip3 install -r /tmp/libswiftnav_requirements.txt 7 | RUN sudo apt-get update && sudo apt-get install -y lcov 8 | WORKDIR /mnt/workspace 9 | -------------------------------------------------------------------------------- /Dockerfile.modern: -------------------------------------------------------------------------------- 1 | # Base image is created by https://github.com/swift-nav/docker-recipes 2 | FROM 571934480752.dkr.ecr.us-west-2.amazonaws.com/swift-build-modern:2022-07-29 3 | 4 | WORKDIR /mnt/workspace 5 | -------------------------------------------------------------------------------- /Jenkinsfile: -------------------------------------------------------------------------------- 1 | #!groovy 2 | 3 | /** 4 | * This Jenkinsfile will only work in a Swift Navigation build/CI environment, as it uses 5 | * non-public docker images and pipeline libraries. 6 | */ 7 | 8 | // Use 'ci-jenkins@somebranch' to pull shared lib from a different branch than the default. 9 | // Default is configured in Jenkins and should be from "stable" tag. 10 | @Library("ci-jenkins") import com.swiftnav.ci.* 11 | 12 | def context = new Context(context: this) 13 | context.setRepo("libswiftnav") 14 | def builder = context.getBuilder() 15 | 16 | /** 17 | * - Mount the refrepo to keep git operations functional on a repo that uses ref-repo during clone 18 | **/ 19 | String dockerMountArgs = "-v /mnt/efs/refrepo:/mnt/efs/refrepo" 20 | 21 | pipeline { 22 | // Override agent in each stage to make sure we don't share containers among stages. 23 | agent any 24 | options { 25 | // Make sure job aborts after 2 hours if hanging. 26 | timeout(time: 2, unit: 'HOURS') 27 | timestamps() 28 | // Keep builds for 7 days. 29 | buildDiscarder(logRotator(daysToKeepStr: '7')) 30 | } 31 | 32 | stages { 33 | stage('Build') { 34 | parallel { 35 | stage('Unit Test') { 36 | agent { 37 | dockerfile { 38 | args dockerMountArgs 39 | } 40 | } 41 | steps { 42 | gitPrep() 43 | script { 44 | builder.cmake() 45 | builder.make(workDir: "build") 46 | } 47 | // Convert the test results into a Jenkins-parsable junit-XML format 48 | sh("./tools/check2junit.py build/tests/test_results.xml > build/tests/test_results_junit.xml") 49 | stash( 50 | name: 'libswiftnavUnit', 51 | includes: 'build/tests/test_results_junit.xml') 52 | } 53 | } 54 | stage('Bazel Build') { 55 | agent { 56 | docker { 57 | image '571934480752.dkr.ecr.us-west-2.amazonaws.com/swift-build-bazel:2023-06-21' 58 | } 59 | } 60 | steps { 61 | gitPrep() 62 | script { 63 | sh('''#!/bin/bash -ex 64 | | CC=gcc-8 CXX=g++-8 bazel build --subcommands //... 65 | | bazel run //:gen_compile_commands 66 | | bazel run //:swiftnav-test 67 | | bazel coverage --collect_code_coverage --combined_report=lcov //... 68 | | genhtml bazel-out/_coverage/_coverage_report.dat -o coverage 69 | | tar -zcvf coverage.tar.gz coverage/ 70 | |'''.stripMargin()) 71 | } 72 | } 73 | post { 74 | always { 75 | archiveArtifacts(artifacts: 'coverage.tar.gz', allowEmptyArchive: true) 76 | } 77 | } 78 | } 79 | stage('Format & Lint') { 80 | agent { 81 | dockerfile { 82 | filename "Dockerfile.modern" 83 | args dockerMountArgs 84 | } 85 | } 86 | steps { 87 | gitPrep() 88 | script { 89 | builder.cmake() 90 | builder.make(workDir: "build", target: "clang-format-all-check") 91 | builder.make(workDir: "build", target: "clang-tidy-all-check") 92 | } 93 | } 94 | post { 95 | always { 96 | archiveArtifacts(artifacts: 'fixes.yaml', allowEmptyArchive: true) 97 | } 98 | } 99 | } 100 | stage('Code Coverage') { 101 | agent { 102 | dockerfile { 103 | args dockerMountArgs 104 | } 105 | } 106 | steps { 107 | gitPrep() 108 | script { 109 | builder.cmake(buildType: "Debug", codeCoverage: "ON") 110 | builder.make(workDir: "build", target: "ccov-all") 111 | } 112 | } 113 | post { 114 | success { 115 | script { 116 | context.uploadCodeCov(repo: "libswiftnav", searchdir: "build") 117 | } 118 | } 119 | } 120 | } 121 | } 122 | } 123 | } 124 | post { 125 | always { 126 | node('linux') { 127 | unstash(name: "libswiftnavUnit") 128 | junit('build/tests/*.xml') 129 | } 130 | script { 131 | context.slackNotify() 132 | context.postCommon() 133 | } 134 | } 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | docker-image: 2 | docker-compose build libswiftnav 3 | 4 | docker: docker-image 5 | docker-compose run libswiftnav 6 | 7 | docker-build: docker-image 8 | mkdir -p build 9 | docker-compose run -T libswiftnav /bin/bash -c "cd build && cmake .. && make -j4" 10 | 11 | docker-lint: docker-image 12 | mkdir -p build 13 | docker-compose run -T libswiftnav /bin/bash -c "cd build && cmake .. && make -j4 clang-format-all" 14 | 15 | do-all-unit-tests: 16 | bazel test --test_tag_filters=unit --test_output=all //... 17 | 18 | do-all-integration-tests: 19 | bazel test --test_tag_filters=integration --test_output=all //... 20 | 21 | clang-format-all-check: 22 | bazel build //... --config=clang-format-check 23 | 24 | clang-format-all: 25 | bazel run @rules_swiftnav//clang_format 26 | 27 | clang-tidy-all-check: 28 | bazel build //... --config=clang-tidy 29 | 30 | do-code-coverage: 31 | bazel coverage --test_tag_filters=unit --collect_code_coverage --combined_report=lcov //... 32 | 33 | do-generate-coverage-report: do-code-coverage 34 | genhtml bazel-out/_coverage/_coverage_report.dat -o coverage 35 | 36 | gen-compile-commands: 37 | bazel run //:gen_compile_commands 38 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![CI](https://github.com/swift-nav/libswiftnav/actions/workflows/ci.yaml/badge.svg)](https://github.com/swift-nav/libswiftnav/actions/workflows/ci.yaml) 2 | [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=swift-nav_libswiftnav&metric=alert_status)](https://sonarcloud.io/dashboard?id=swift-nav_libswiftnav) 3 | 4 | 5 | libswiftnav 6 | =========== 7 | 8 | Libswiftnav (LSN) is a platform independent library that implements GNSS utility functions for use by software-defined GNSS receivers or software requiring GNSS functionality. It is intended to be as portable as possible and is written in standards compliant C with no dependancies 9 | 10 | LSN does not provide any functionality for communicating with Swift Navigation receivers. See [libsbp](https://github.com/swift-nav/libsbp) to communicate with receivers using Swift Binary Protocol (SBP). 11 | 12 | To checkout the library run the following commands in an appropriate directory 13 | ``` 14 | git clone git@github.com:swift-nav/libswiftnav.git 15 | ``` 16 | Which should checkout the source code 17 | 18 | ### Build 19 | To build the library, run the following commands from the LSN root directory - LSN depends on the latest xcode for MacOSX and cmake 20 | ``` 21 | mkdir ./build 22 | cd ./build 23 | cmake ../ 24 | make -j4 25 | ``` 26 | 27 | # Build on Docker 28 | 29 | The `libswiftnav` docker image is using a ECR-hosted base image `swift-build` that contains most swift build tools. 30 | 31 | #### Get `swift-build` base image from ECR 32 | 33 | To be able to pull this base image from ECR, you need to log into AWS (select the SSO-Build-User role) and then into 34 | ECR: 35 | 36 | aws-google-auth -S 115297745755 -I C02x4yyeb -p default -a -u @swift-nav.com 37 | $(aws ecr get-login --no-include-email --region us-west-2 --registry-ids 571934480752) 38 | 39 | #### Build the `swift-build` base image yourself (without ECR) 40 | 41 | Alternatively to the AWS/ECR pull, you can build the base image yourself from the Dockerfile.base: 42 | (replace \ with the one used by Dockerfile's FROM statement, e.g. 2018-12-20) 43 | 44 | docker build -t 571934480752.dkr.ecr.us-west-2.amazonaws.com/swift-build: modules/docker-recipes/swift-build 45 | 46 | ### Build the `libswiftnav` image and run container 47 | 48 | Now you can build and run the libswiftnav image with 49 | 50 | docker-compose build libswiftnav 51 | docker-compose run libswiftnav 52 | 53 | #### Run a shell in docker 54 | 55 | make docker 56 | 57 | - Starts a shell in a container, with the workspace mounted as /mnt/workspace. 58 | 59 | #### Run build in docker 60 | 61 | make docker-build 62 | 63 | #### Run clang-format 64 | 65 | make docker-lint 66 | -------------------------------------------------------------------------------- /WORKSPACE.bazel: -------------------------------------------------------------------------------- 1 | workspace(name = "libswiftnav") 2 | 3 | load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") 4 | 5 | http_archive( 6 | name = "rules_swiftnav", 7 | strip_prefix = "rules_swiftnav-26426be6b89a5b9f0489158098599b9fcd973ed4", 8 | url = "https://github.com/swift-nav/rules_swiftnav/archive/26426be6b89a5b9f0489158098599b9fcd973ed4.tar.gz", 9 | ) 10 | 11 | http_archive( 12 | name = "rules_foreign_cc", 13 | strip_prefix = "rules_foreign_cc-c65e8cfbaa002bcd1ce9c26e9fec63b0b866c94b", 14 | url = "https://github.com/bazelbuild/rules_foreign_cc/archive/c65e8cfbaa002bcd1ce9c26e9fec63b0b866c94b.tar.gz", 15 | ) 16 | 17 | load("@rules_foreign_cc//foreign_cc:repositories.bzl", "rules_foreign_cc_dependencies") 18 | 19 | rules_foreign_cc_dependencies() 20 | 21 | # Hedron's Compile Commands Extractor for Bazel 22 | # https://github.com/hedronvision/bazel-compile-commands-extractor 23 | http_archive( 24 | name = "hedron_compile_commands", 25 | sha256 = "4b251a482a85de6c5cb0dc34c5671e73190b9ff348e9979fa2c033d81de0f928", 26 | strip_prefix = "bazel-compile-commands-extractor-5bb5ff2f32d542a986033102af771aa4206387b9", 27 | url = "https://github.com/hedronvision/bazel-compile-commands-extractor/archive/5bb5ff2f32d542a986033102af771aa4206387b9.tar.gz", 28 | ) 29 | 30 | load("@hedron_compile_commands//:workspace_setup.bzl", "hedron_compile_commands_setup") 31 | 32 | hedron_compile_commands_setup() 33 | 34 | new_local_repository( 35 | name = "check", 36 | build_file = "@rules_swiftnav//third_party:check.BUILD", 37 | path = "third_party/check", 38 | ) 39 | -------------------------------------------------------------------------------- /bazel/BUILD.bazel: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swift-nav/libswiftnav/f329a4052f36183fb5b094486a31a2ed7e970d8a/bazel/BUILD.bazel -------------------------------------------------------------------------------- /bazel/max_channels_config.bzl: -------------------------------------------------------------------------------- 1 | load("@rules_swiftnav//tools:configure_file.bzl", "configure_file_impl") 2 | load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo") 3 | 4 | def _max_channels_config_impl(ctx): 5 | vars = { 6 | "MAX_CHANNELS": str(ctx.attr.max_channels[BuildSettingInfo].value), 7 | } 8 | return configure_file_impl(ctx, vars) 9 | 10 | max_channels_config = rule( 11 | implementation = _max_channels_config_impl, 12 | attrs = { 13 | "out": attr.string(), 14 | "template": attr.label( 15 | allow_single_file = [".in"], 16 | mandatory = True, 17 | ), 18 | "max_channels": attr.label(), 19 | }, 20 | ) 21 | -------------------------------------------------------------------------------- /ci-build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright (C) 2018-2021 Swift Navigation Inc. 4 | # Contact: Swift Navigation 5 | 6 | set -ex 7 | set -o errexit 8 | set -o pipefail 9 | 10 | #************************************************************************ 11 | # UTILITY FUNCTIONS 12 | #************************************************************************ 13 | check_format_errors() { 14 | if [[ $(git --no-pager diff --name-only HEAD) ]]; then 15 | echo "######################################################" 16 | echo "####### clang-format warning found! Exiting... #######" 17 | echo "######################################################" 18 | echo "" 19 | echo "This should be formatted locally and pushed again..." 20 | git --no-pager diff 21 | exit 1 22 | fi 23 | } 24 | 25 | check_tidy_errors() { 26 | if [ -e ../fixes.yaml ]; then 27 | echo "####################################################" 28 | echo "####### clang-tidy warning found! Exiting... #######" 29 | echo "####################################################" 30 | echo "" 31 | echo " ^^ Please see and correct the clang-tidy warnings found above ^^" 32 | exit 1 33 | fi 34 | } 35 | 36 | function build_c() { 37 | # Create and enter build directory. 38 | mkdir -p build && cd build 39 | cmake ../ 40 | make -j4 VERBOSE=1 41 | if [ "$TEST_SUITE" == "lint" ]; then 42 | make clang-format-all && check_format_errors 43 | make clang-tidy-all && check_tidy_errors 44 | fi 45 | cd ../ 46 | } 47 | 48 | function build_codecov() { 49 | 50 | mkdir "${HOME}/.sonar" 51 | 52 | # download build-wrapper 53 | curl -sSLo "${HOME}/.sonar/build-wrapper-linux-x86.zip" https://sonarcloud.io/static/cpp/build-wrapper-linux-x86.zip 54 | unzip -o "${HOME}/.sonar/build-wrapper-linux-x86.zip" -d "${HOME}/.sonar/" 55 | export PATH=${HOME}/.sonar/build-wrapper-linux-x86:${PATH} 56 | 57 | # configure 58 | cmake --version 59 | cmake \ 60 | "-DCODE_COVERAGE=ON" \ 61 | "-DCMAKE_BUILD_TYPE=Debug" \ 62 | -S . -B ./build 63 | 64 | # build with wrapper 65 | build-wrapper-linux-x86-64 --out-dir ./bw-output cmake --build ./build --target ccov-all-export -j8 66 | 67 | if [[ -z "${SONAR_SCANNER_VERSION}" ]]; then 68 | echo "Error: SONAR_SCANNER_VERSION must be configured" >&2 69 | exit 1 70 | fi 71 | 72 | export SONAR_SCANNER_HOME="${HOME}/.sonar/sonar-scanner-${SONAR_SCANNER_VERSION}-linux" 73 | 74 | # download sonar-scanner 75 | curl -sSLo "${HOME}/.sonar/sonar-scanner.zip" \ 76 | "https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-${SONAR_SCANNER_VERSION}-linux.zip" 77 | unzip -o "${HOME}/.sonar/sonar-scanner.zip" -d "${HOME}/.sonar/" 78 | export PATH=${SONAR_SCANNER_HOME}/bin:${PATH} 79 | export SONAR_SCANNER_OPTS="-server" 80 | 81 | # Run sonar scanner 82 | [[ -n "${SONAR_TOKEN:-}" ]] && SONAR_TOKEN_CMD_ARG="-Dsonar.login=${SONAR_TOKEN}" 83 | [[ -n "${SONAR_ORGANIZATION:-}" ]] && SONAR_ORGANIZATION_CMD_ARG="-Dsonar.organization=${SONAR_ORGANIZATION}" 84 | [[ -n "${SONAR_PROJECT_NAME:-}" ]] && SONAR_PROJECT_NAME_CMD_ARG="-Dsonar.projectName=${SONAR_PROJECT_NAME}" 85 | 86 | # TODO: setup sonar.projectVersion so that it actually does something useful 87 | # see https://swift-nav.atlassian.net/browse/DEVINFRA-504 88 | SONAR_OTHER_ARGS="\ 89 | -Dsonar.projectVersion=1.0 \ 90 | -Dsonar.sources=. \ 91 | -Dsonar.cfamily.build-wrapper-output=./bw-output \ 92 | -Dsonar.cfamily.threads=1 \ 93 | -Dsonar.cfamily.cache.enabled=false \ 94 | -Dsonar.sourceEncoding=UTF-8" 95 | 96 | set -x 97 | 98 | # shellcheck disable=SC2086 99 | sonar-scanner \ 100 | "-Dsonar.cfamily.llvm-cov.reportPath=./build/ccov/coverage.txt" \ 101 | "-Dsonar.host.url=${SONAR_HOST_URL}" \ 102 | "-Dsonar.projectKey=${SONAR_PROJECT_KEY}" \ 103 | ${SONAR_OTHER_ARGS} \ 104 | "${SONAR_PROJECT_NAME_CMD_ARG}" \ 105 | "${SONAR_TOKEN_CMD_ARG}" \ 106 | "${SONAR_ORGANIZATION_CMD_ARG}" 107 | } 108 | 109 | if [ "$TESTENV" == "c" ]; then 110 | build_c 111 | elif [ "$TESTENV" == "codecov" ]; then 112 | build_codecov 113 | else 114 | echo "Unknown TESTENV value: $TESTENV" >&2 115 | exit 1 116 | fi 117 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | status: 3 | project: 4 | tests: 5 | target: 100% 6 | paths: "tests/" 7 | libswiftnav: 8 | paths: "!tests/" 9 | 10 | comment: off 11 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.1' 2 | 3 | services: 4 | libswiftnav: 5 | build: . 6 | image: libswiftnav 7 | volumes: 8 | - ${PWD}:/mnt/workspace:delegated 9 | - ${HOME}/.ssh/id_rsa:/home/jenkins/.ssh/id_rsa 10 | -------------------------------------------------------------------------------- /include/swiftnav/array_tools.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Swift Navigation Inc. 3 | * Contact: Swift Navigation 4 | * 5 | * This source is subject to the license found in the file 'LICENSE' which must 6 | * be distributed together with this source. All other rights reserved. 7 | * 8 | * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 9 | * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 10 | * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. 11 | */ 12 | 13 | #ifndef ARRAY_TOOLS_H 14 | #define ARRAY_TOOLS_H 15 | 16 | #include 17 | #include 18 | 19 | /** Check if value is in array. 20 | * 21 | * \param array Array of values 22 | * \param count Length of array 23 | * \param value Value to look for 24 | */ 25 | static inline bool is_value_in_array(const u8 *array, u8 count, u8 value) { 26 | for (u8 i = 0; i < count; i++) { 27 | if (array[i] == value) { 28 | return true; 29 | } 30 | } 31 | 32 | return false; 33 | } 34 | 35 | static inline bool is_value_in_array_u16(const u16 *array, 36 | u8 count, 37 | u16 value) { 38 | for (u8 i = 0; i < count; i++) { 39 | if (array[i] == value) { 40 | return true; 41 | } 42 | } 43 | 44 | return false; 45 | } 46 | 47 | #endif // ARRAY_TOOLS_H 48 | -------------------------------------------------------------------------------- /include/swiftnav/bits.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013, 2016 Swift Navigation Inc. 3 | * Contact: Swift Navigation 4 | * 5 | * This source is subject to the license found in the file 'LICENSE' which must 6 | * be distributed together with this source. All other rights reserved. 7 | * 8 | * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 9 | * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 10 | * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. 11 | */ 12 | 13 | #ifndef LIBSWIFTNAV_BITS_H 14 | #define LIBSWIFTNAV_BITS_H 15 | 16 | #include 17 | 18 | #ifdef __cplusplus 19 | extern "C" { 20 | #endif /* __cplusplus */ 21 | 22 | /* See https://github.com/wine-mirror/wine/blob/master/include/windows.h#L22 23 | * If enabled, MSVC will give out warning for the sign extend macros: 24 | * 'unnamed type definition in parentheses' 25 | */ 26 | #if defined(_MSC_VER) && (_MSC_VER >= 800) && !defined(__cplusplus) 27 | #pragma warning(disable : 4116) 28 | #endif 29 | 30 | /** 31 | * Sign extension macro for 32-bit integers. 32 | * 33 | * \param n_bits Number of signed bits in the argument 34 | * \param arg Unsigned ordinal for sign extension 35 | * 36 | * \return 32-bit signed integer with 2-complement of \a n_bits in \a arg 37 | */ 38 | #define BITS_SIGN_EXTEND_32(n_bits, arg) \ 39 | ((struct { s32 bits : (n_bits); }){.bits = (arg)}.bits) 40 | /** 41 | * Sign extension macro for 64-bit integers. 42 | * 43 | * \param n_bits Number of signed bits in the argument 44 | * \param arg Unsigned ordinal for sign extension 45 | * 46 | * \return 64-bit signed integer with 2-complement of \a n_bits in \a arg 47 | */ 48 | #define BITS_SIGN_EXTEND_64(n_bits, arg) \ 49 | ((struct { s64 bits : (n_bits); }){.bits = (arg)}.bits) 50 | 51 | u8 parity(u32 x); 52 | u16 bytes_interleave(const u8 x, const u8 y); 53 | u32 getbitu(const u8 *buff, u32 pos, u8 len); 54 | u64 getbitul(const u8 *buff, u32 pos, u8 len); 55 | s32 getbits(const u8 *buff, u32 pos, u8 len); 56 | s64 getbitsl(const u8 *buff, u32 pos, u8 len); 57 | void setbitu(u8 *buff, u32 pos, u32 len, u32 data); 58 | void setbits(u8 *buff, u32 pos, u32 len, s32 data); 59 | void setbitul(u8 *buff, u32 pos, u32 len, u64 data); 60 | void setbitsl(u8 *buff, u32 pos, u32 len, s64 data); 61 | void bitcopy( 62 | void *dst, u32 dst_index, const void *src, u32 src_index, u32 count); 63 | void bitshl(void *buf, u32 size, u32 shift); 64 | u8 count_bits_u64(u64 v, u8 bv); 65 | u8 count_bits_u32(u32 v, u8 bv); 66 | u8 count_bits_u16(u16 v, u8 bv); 67 | u8 count_bits_u8(u8 v, u8 bv); 68 | 69 | enum endianess { 70 | SWIFT_LITTLE_ENDIAN = 0, // So that a zero'd out value (eg in a struct) 71 | // defaults to little endian 72 | SWIFT_BIG_ENDIAN, 73 | }; 74 | 75 | static inline enum endianess get_endianess(void) { 76 | u16 v = 1; 77 | u8 *ptr = (u8 *)&v; 78 | return (*ptr == 1) ? SWIFT_LITTLE_ENDIAN : SWIFT_BIG_ENDIAN; 79 | } 80 | 81 | static inline u16 byte_swap_16(u16 v) { return (u16)((v >> 8) | (v << 8)); } 82 | 83 | static inline u32 byte_swap_32(u32 v) { 84 | return (v >> 24) | ((v >> 8) & 0xff00) | ((v << 8) & 0xff0000) | (v << 24); 85 | } 86 | 87 | static inline u64 byte_swap_64(u64 v) { 88 | return (v >> 56) | ((v >> 40) & 0xff00) | ((v >> 24) & 0xff0000) | 89 | ((v >> 8) & 0xff000000) | ((v << 8) & 0xff00000000) | 90 | ((v << 24) & 0xff0000000000) | ((v << 40) & 0xff000000000000) | 91 | ((v << 56) & 0xff00000000000000); 92 | } 93 | 94 | static inline u16 htobe_16(u16 v) { 95 | return get_endianess() == SWIFT_BIG_ENDIAN ? v : byte_swap_16(v); 96 | } 97 | 98 | static inline u16 htole_16(u16 v) { 99 | return get_endianess() == SWIFT_LITTLE_ENDIAN ? v : byte_swap_16(v); 100 | } 101 | 102 | static inline u32 htobe_32(u32 v) { 103 | return get_endianess() == SWIFT_BIG_ENDIAN ? v : byte_swap_32(v); 104 | } 105 | 106 | static inline u32 htole_32(u32 v) { 107 | return get_endianess() == SWIFT_LITTLE_ENDIAN ? v : byte_swap_32(v); 108 | } 109 | 110 | static inline u64 htobe_64(u64 v) { 111 | return get_endianess() == SWIFT_BIG_ENDIAN ? v : byte_swap_64(v); 112 | } 113 | 114 | static inline u64 htole_64(u64 v) { 115 | return get_endianess() == SWIFT_LITTLE_ENDIAN ? v : byte_swap_64(v); 116 | } 117 | 118 | static inline u16 betoh_16(u16 v) { 119 | return get_endianess() == SWIFT_BIG_ENDIAN ? v : byte_swap_16(v); 120 | } 121 | 122 | static inline u16 letoh_16(u16 v) { 123 | return get_endianess() == SWIFT_LITTLE_ENDIAN ? v : byte_swap_16(v); 124 | } 125 | 126 | static inline u32 betoh_32(u32 v) { 127 | return get_endianess() == SWIFT_BIG_ENDIAN ? v : byte_swap_32(v); 128 | } 129 | 130 | static inline u32 letoh_32(u32 v) { 131 | return get_endianess() == SWIFT_LITTLE_ENDIAN ? v : byte_swap_32(v); 132 | } 133 | 134 | static inline u64 betoh_64(u64 v) { 135 | return get_endianess() == SWIFT_BIG_ENDIAN ? v : byte_swap_64(v); 136 | } 137 | 138 | static inline u64 letoh_64(u64 v) { 139 | return get_endianess() == SWIFT_LITTLE_ENDIAN ? v : byte_swap_64(v); 140 | } 141 | 142 | #ifdef __cplusplus 143 | } /* extern "C" */ 144 | #endif /* __cplusplus */ 145 | 146 | #endif /* LIBSWIFTNAV_BITS_H */ 147 | -------------------------------------------------------------------------------- /include/swiftnav/bitstream.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBSWIFTNAV_BITSTREAM_H 2 | #define LIBSWIFTNAV_BITSTREAM_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #ifdef __cplusplus 12 | extern "C" { 13 | #endif 14 | 15 | typedef struct swiftnav_in_bitstream { 16 | const uint8_t *data; 17 | uint32_t len; 18 | uint32_t offset; 19 | } swiftnav_in_bitstream_t; 20 | 21 | typedef struct swiftnav_out_bitstream { 22 | uint8_t *data; 23 | uint32_t len; 24 | uint32_t offset; 25 | } swiftnav_out_bitstream_t; 26 | 27 | static inline bool swiftnav_in_bitstream_would_overflow( 28 | const swiftnav_in_bitstream_t *buf, u32 pos, u32 len) { 29 | return (buf->offset + pos + len) > buf->len; 30 | } 31 | 32 | static inline void swiftnav_in_bitstream_init(swiftnav_in_bitstream_t *buf, 33 | const uint8_t *data, 34 | u32 len) { 35 | buf->data = data; 36 | buf->len = len; 37 | buf->offset = 0; 38 | } 39 | 40 | static inline bool swiftnav_in_bitstream_getbitu( 41 | const swiftnav_in_bitstream_t *buf, u32 *out, u32 pos, u32 len) { 42 | if (swiftnav_in_bitstream_would_overflow(buf, pos, len)) { 43 | return false; 44 | } 45 | *out = getbitu(buf->data, buf->offset + pos, (u8)len); 46 | return true; 47 | } 48 | 49 | static inline bool swiftnav_in_bitstream_getbits( 50 | const swiftnav_in_bitstream_t *buf, s32 *out, u32 pos, u32 len) { 51 | if (swiftnav_in_bitstream_would_overflow(buf, pos, len)) { 52 | return false; 53 | } 54 | *out = getbits(buf->data, buf->offset + pos, (u8)len); 55 | return true; 56 | } 57 | 58 | static inline bool swiftnav_in_bitstream_getbitul( 59 | const swiftnav_in_bitstream_t *buf, u64 *out, u32 pos, u32 len) { 60 | if (swiftnav_in_bitstream_would_overflow(buf, pos, len)) { 61 | return false; 62 | } 63 | *out = getbitul(buf->data, buf->offset + pos, (u8)len); 64 | return true; 65 | } 66 | 67 | static inline bool swiftnav_in_bitstream_getbitsl( 68 | const swiftnav_in_bitstream_t *buf, s64 *out, u32 pos, u32 len) { 69 | if (swiftnav_in_bitstream_would_overflow(buf, pos, len)) { 70 | return false; 71 | } 72 | *out = getbitsl(buf->data, buf->offset + pos, (u8)len); 73 | return true; 74 | } 75 | 76 | static inline void swiftnav_in_bitstream_remove(swiftnav_in_bitstream_t *buf, 77 | u32 len) { 78 | buf->offset += len; 79 | } 80 | 81 | static inline u32 swiftnav_in_bitstream_remaining( 82 | swiftnav_in_bitstream_t *buf) { 83 | if (buf->offset > buf->len) { 84 | return 0; 85 | } 86 | return buf->len - buf->offset; 87 | } 88 | 89 | static inline bool swiftnav_out_bitstream_would_overflow( 90 | const swiftnav_out_bitstream_t *buf, u32 pos, u32 len) { 91 | return (buf->offset + pos + len) > buf->len; 92 | } 93 | static inline void swiftnav_out_bitstream_init(swiftnav_out_bitstream_t *buf, 94 | uint8_t *data, 95 | u32 len) { 96 | buf->data = data; 97 | buf->len = len; 98 | buf->offset = 0; 99 | } 100 | static inline bool swiftnav_out_bitstream_setbitu(swiftnav_out_bitstream_t *buf, 101 | const u32 *in, 102 | u32 pos, 103 | u32 len) { 104 | if (swiftnav_out_bitstream_would_overflow(buf, pos, len)) { 105 | return false; 106 | } 107 | setbitu(buf->data, buf->offset + pos, (u8)len, *in); 108 | return true; 109 | } 110 | 111 | static inline bool swiftnav_out_bitstream_setbits(swiftnav_out_bitstream_t *buf, 112 | const s32 *in, 113 | u32 pos, 114 | u32 len) { 115 | if (swiftnav_out_bitstream_would_overflow(buf, pos, len)) { 116 | return false; 117 | } 118 | setbits(buf->data, buf->offset + pos, (u8)len, *in); 119 | return true; 120 | } 121 | 122 | static inline bool swiftnav_out_bitstream_setbitul( 123 | swiftnav_out_bitstream_t *buf, const u64 *in, u32 pos, u32 len) { 124 | if (swiftnav_out_bitstream_would_overflow(buf, pos, len)) { 125 | return false; 126 | } 127 | setbitul(buf->data, buf->offset + pos, (u8)len, *in); 128 | return true; 129 | } 130 | 131 | static inline bool swiftnav_out_bitstream_setbitsl( 132 | swiftnav_out_bitstream_t *buf, const s64 *in, u32 pos, u32 len) { 133 | if (swiftnav_out_bitstream_would_overflow(buf, pos, len)) { 134 | return false; 135 | } 136 | setbitsl(buf->data, buf->offset + pos, (u8)len, *in); 137 | return true; 138 | } 139 | 140 | static inline void swiftnav_out_bitstream_remove(swiftnav_out_bitstream_t *buf, 141 | u32 len) { 142 | buf->offset += len; 143 | } 144 | static inline u32 swiftnav_out_bitstream_remaining( 145 | swiftnav_out_bitstream_t *buf) { 146 | if (buf->offset > buf->len) { 147 | return 0; 148 | } 149 | return buf->len - buf->offset; 150 | } 151 | 152 | #ifdef __cplusplus 153 | } 154 | #endif 155 | 156 | #endif 157 | -------------------------------------------------------------------------------- /include/swiftnav/bytestream.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBSWIFTNAV_BYTESTREAM_H 2 | #define LIBSWIFTNAV_BYTESTREAM_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #ifdef __cplusplus 11 | extern "C" { 12 | #endif 13 | 14 | typedef struct swiftnav_bytestream { 15 | const u8 *data; 16 | u32 len; 17 | u32 offset; 18 | enum endianess endianess; 19 | } swiftnav_bytestream_t; 20 | 21 | static inline bool swiftnav_bytestream_would_overflow( 22 | const swiftnav_bytestream_t *buf, u32 index, u32 len) { 23 | return (buf->offset + index + len) > buf->len; 24 | } 25 | 26 | static inline void swiftnav_bytestream_init(swiftnav_bytestream_t *buf, 27 | const u8 *data, 28 | u32 len) { 29 | buf->data = data; 30 | buf->len = len; 31 | buf->offset = 0; 32 | } 33 | 34 | static inline bool swiftnav_bytestream_get_bytes( 35 | const swiftnav_bytestream_t *buf, u32 index, u32 len, u8 *dest) { 36 | if (swiftnav_bytestream_would_overflow(buf, index, len)) { 37 | return false; 38 | } 39 | memcpy(dest, buf->data + buf->offset + index, len); 40 | return true; 41 | } 42 | 43 | static inline void swiftnav_bytestream_remove(swiftnav_bytestream_t *buf, 44 | u32 len) { 45 | buf->offset += len; 46 | } 47 | 48 | static inline u32 swiftnav_bytestream_remaining(swiftnav_bytestream_t *buf) { 49 | if (buf->offset > buf->len) { 50 | return 0; 51 | } 52 | return buf->len - buf->offset; 53 | } 54 | 55 | static inline bool swiftnav_bytestream_decode_u8(swiftnav_bytestream_t *buf, 56 | u8 *dest) { 57 | if (!swiftnav_bytestream_get_bytes(buf, 0, sizeof(*dest), dest)) { 58 | return false; 59 | } 60 | swiftnav_bytestream_remove(buf, sizeof(*dest)); 61 | return true; 62 | } 63 | 64 | static inline bool swiftnav_bytestream_decode_s8(swiftnav_bytestream_t *buf, 65 | s8 *dest) { 66 | u8 v; 67 | if (!swiftnav_bytestream_get_bytes(buf, 0, sizeof(*dest), &v)) { 68 | return false; 69 | } 70 | swiftnav_bytestream_remove(buf, sizeof(*dest)); 71 | memcpy(dest, &v, sizeof(v)); 72 | return true; 73 | } 74 | 75 | static inline bool swiftnav_bytestream_decode_u16(swiftnav_bytestream_t *buf, 76 | u16 *dest) { 77 | u16 v; 78 | if (!swiftnav_bytestream_get_bytes(buf, 0, sizeof(*dest), (uint8_t *)&v)) { 79 | return false; 80 | } 81 | swiftnav_bytestream_remove(buf, sizeof(*dest)); 82 | v = (buf->endianess == SWIFT_BIG_ENDIAN) ? betoh_16(v) : letoh_16(v); 83 | memcpy(dest, &v, sizeof(v)); 84 | return true; 85 | } 86 | 87 | static inline bool swiftnav_bytestream_decode_s16(swiftnav_bytestream_t *buf, 88 | s16 *dest) { 89 | u16 v; 90 | if (!swiftnav_bytestream_get_bytes(buf, 0, sizeof(*dest), (uint8_t *)&v)) { 91 | return false; 92 | } 93 | swiftnav_bytestream_remove(buf, sizeof(*dest)); 94 | v = (buf->endianess == SWIFT_BIG_ENDIAN) ? betoh_16(v) : letoh_16(v); 95 | memcpy(dest, &v, sizeof(v)); 96 | return true; 97 | } 98 | 99 | static inline bool swiftnav_bytestream_decode_u32(swiftnav_bytestream_t *buf, 100 | u32 *dest) { 101 | u32 v; 102 | if (!swiftnav_bytestream_get_bytes(buf, 0, sizeof(*dest), (uint8_t *)&v)) { 103 | return false; 104 | } 105 | swiftnav_bytestream_remove(buf, sizeof(*dest)); 106 | v = (buf->endianess == SWIFT_BIG_ENDIAN) ? betoh_32(v) : letoh_32(v); 107 | memcpy(dest, &v, sizeof(v)); 108 | return true; 109 | } 110 | 111 | static inline bool swiftnav_bytestream_decode_s32(swiftnav_bytestream_t *buf, 112 | s32 *dest) { 113 | u32 v; 114 | if (!swiftnav_bytestream_get_bytes(buf, 0, sizeof(*dest), (uint8_t *)&v)) { 115 | return false; 116 | } 117 | swiftnav_bytestream_remove(buf, sizeof(*dest)); 118 | v = (buf->endianess == SWIFT_BIG_ENDIAN) ? betoh_32(v) : letoh_32(v); 119 | memcpy(dest, &v, sizeof(v)); 120 | return true; 121 | } 122 | 123 | static inline bool swiftnav_bytestream_decode_u64(swiftnav_bytestream_t *buf, 124 | u64 *dest) { 125 | u64 v; 126 | if (!swiftnav_bytestream_get_bytes(buf, 0, sizeof(*dest), (uint8_t *)&v)) { 127 | return false; 128 | } 129 | swiftnav_bytestream_remove(buf, sizeof(*dest)); 130 | v = (buf->endianess == SWIFT_BIG_ENDIAN) ? betoh_64(v) : letoh_64(v); 131 | memcpy(dest, &v, sizeof(v)); 132 | return true; 133 | } 134 | 135 | static inline bool swiftnav_bytestream_decode_s64(swiftnav_bytestream_t *buf, 136 | s64 *dest) { 137 | u64 v; 138 | if (!swiftnav_bytestream_get_bytes(buf, 0, sizeof(*dest), (uint8_t *)&v)) { 139 | return false; 140 | } 141 | swiftnav_bytestream_remove(buf, sizeof(*dest)); 142 | v = (buf->endianess == SWIFT_BIG_ENDIAN) ? betoh_64(v) : letoh_64(v); 143 | memcpy(dest, &v, sizeof(v)); 144 | return true; 145 | } 146 | 147 | #ifdef __cplusplus 148 | } 149 | #endif 150 | 151 | #endif 152 | -------------------------------------------------------------------------------- /include/swiftnav/ch_meas.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Swift Navigation Inc. 3 | * Contact: Swift Navigation 4 | * 5 | * This source is subject to the license found in the file 'LICENSE' which must 6 | * be distributed together with this source. All other rights reserved. 7 | * 8 | * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 9 | * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 10 | * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. 11 | */ 12 | 13 | #ifndef LIBSWIFTNAV_CH_MEAS_H 14 | #define LIBSWIFTNAV_CH_MEAS_H 15 | 16 | #include 17 | #include 18 | 19 | /** Measurement flag: code measurement is valid. 20 | * \sa chan_meas_flags_t */ 21 | #define CHAN_MEAS_FLAG_CODE_VALID ((chan_meas_flags_t)1 << 0) 22 | /** Measurement flag: phase measurement is valid. 23 | * \sa chan_meas_flags_t */ 24 | #define CHAN_MEAS_FLAG_PHASE_VALID ((chan_meas_flags_t)1 << 1) 25 | /** Measurement flag: doppler measurement is valid. 26 | * \sa chan_meas_flags_t */ 27 | #define CHAN_MEAS_FLAG_MEAS_DOPPLER_VALID ((chan_meas_flags_t)1 << 2) 28 | /** Measurement flag: phase measurement has a known polarity. 29 | * \sa chan_meas_flags_t */ 30 | #define CHAN_MEAS_FLAG_HALF_CYCLE_KNOWN ((chan_meas_flags_t)1 << 3) 31 | 32 | /** Channel measurement flag mask. 33 | * 34 | * Mask value is any combination of the following flags: 35 | * - #CHAN_MEAS_FLAG_CODE_VALID 36 | * - #CHAN_MEAS_FLAG_PHASE_VALID 37 | * - #CHAN_MEAS_FLAG_MEAS_DOPPLER_VALID 38 | * - #CHAN_MEAS_FLAG_HALF_CYCLE_KNOWN 39 | * 40 | * \sa channel_measurement_t 41 | */ 42 | typedef u16 chan_meas_flags_t; 43 | 44 | /** This struct holds the state of a tracking channel at a given receiver time 45 | * epoch. 46 | * 47 | * The struct contains the information necessary to calculate the pseudorange, 48 | * carrier phase and Doppler information needed for a PVT solution but is 49 | * formatted closer to the natural outputs from the tracking channels. 50 | * 51 | * \see calc_navigation_measurement() 52 | */ 53 | typedef struct { 54 | gnss_signal_t sid; /**< Satellite signal. */ 55 | double code_phase_chips; /**< The code-phase in chips at `receiver_time`. */ 56 | double code_phase_rate; /**< Code phase rate in chips/s. */ 57 | double carrier_phase; /**< Carrier phase in cycles. */ 58 | double carrier_freq; /**< Carrier frequency in Hz. */ 59 | u32 time_of_week_ms; /**< Number of milliseconds since the start of the 60 | GPS week corresponding to the last code 61 | rollover. */ 62 | s32 tow_residual_ns; /**< Residual to time_of_week_ms in [ns] */ 63 | double rec_time_delta; /**< Difference between receiver clock time at which 64 | this measurement is valid and reference time 65 | (seconds). */ 66 | double cn0; /**< Carrier to noise ratio in dB-Hz. */ 67 | double lock_time; /**< PLL Lock time in seconds. Counts the time since 68 | the tracking channel re-locked or a cycle 69 | slip was detected and the carrier phase 70 | integer ambiguity was reset. If this value 71 | drops it is an indication you should reset 72 | integer ambiguity resolution for this 73 | channel. */ 74 | double time_in_track; /**< Time the pseudorange has been tracked (s) */ 75 | double elevation; /**< Approximate satellite elevation (deg) */ 76 | chan_meas_flags_t flags; /**< Flags */ 77 | } channel_measurement_t; 78 | 79 | #endif /* LIBSWIFTNAV_CH_MEAS_H */ 80 | -------------------------------------------------------------------------------- /include/swiftnav/common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Swift Navigation Inc. 3 | * Contact: Swift Navigation 4 | * 5 | * This source is subject to the license found in the file 'LICENSE' which must 6 | * be distributed together with this source. All other rights reserved. 7 | * 8 | * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 9 | * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 10 | * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. 11 | */ 12 | 13 | #ifndef LIBSWIFTNAV_COMMON_H 14 | #define LIBSWIFTNAV_COMMON_H 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | #ifdef _MSC_VER 21 | #include 22 | #define LSN_NEW_ARRAY(Name, ItemCount, Type) \ 23 | Type *Name = _malloca(sizeof(Type) * (ItemCount)); \ 24 | assert(Name != NULL); \ 25 | memset(Name, 0, sizeof(Type) * (ItemCount)) 26 | #define LSN_FREE_ARRAY(ptr) _freea((void *)ptr) 27 | #else 28 | #define LSN_NEW_ARRAY(Name, ItemCount, Type) \ 29 | Type Name[ItemCount]; \ 30 | for (size_t _x_##Name = 0; _x_##Name < (ItemCount); _x_##Name++) { \ 31 | (Name)[_x_##Name] = 0; \ 32 | } 33 | #define LSN_FREE_ARRAY(ptr) 34 | #endif 35 | 36 | #ifdef __cplusplus 37 | extern "C" { 38 | #endif 39 | 40 | /** \defgroup common Common definitions 41 | * Common definitions used throughout the library. 42 | * \{ */ 43 | 44 | #ifndef ABS 45 | #define ABS(x) ((x) < 0 ? -(x) : (x)) 46 | #endif 47 | 48 | #ifndef MIN 49 | #define MIN(x, y) (((x) < (y)) ? (x) : (y)) 50 | #endif 51 | 52 | #ifndef MAX 53 | #define MAX(x, y) (((x) > (y)) ? (x) : (y)) 54 | #endif 55 | 56 | #define CLAMP_DIFF(a, b) (MAX((a), (b)) - (b)) 57 | #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) 58 | #define ARRAY_SIZE2(a) (sizeof(a) / sizeof((a)[0][0])) 59 | #define SIGN(a) (((a) >= 0) ? +1 : -1) 60 | 61 | /* See http://c-faq.com/cpp/multistmt.html for 62 | * and explaination of the do {} while(0) 63 | */ 64 | #define DO_EVERY(n, cmd) \ 65 | do { \ 66 | static u32 do_every_count = 0; \ 67 | if ((n) > 0 && do_every_count % (n) == 0) { \ 68 | cmd; \ 69 | } \ 70 | do_every_count++; \ 71 | } while (0) 72 | 73 | #ifndef COMMON_INT_TYPES 74 | #define COMMON_INT_TYPES 75 | 76 | /** \defgroup common_inttypes Integer types 77 | * Specified-width integer type definitions for shorter and nicer code. 78 | * 79 | * These should be used in preference to unspecified width types such as 80 | * `int` which can lead to portability issues between different platforms. 81 | * \{ */ 82 | 83 | typedef int8_t s8; 84 | typedef int16_t s16; 85 | typedef int32_t s32; 86 | typedef int64_t s64; 87 | typedef uint8_t u8; 88 | typedef uint16_t u16; 89 | typedef uint32_t u32; 90 | typedef uint64_t u64; 91 | 92 | #endif /* COMMON_INT_TYPES */ 93 | 94 | /** \} */ 95 | /** \} */ 96 | 97 | #ifdef __cplusplus 98 | } /* extern "C" */ 99 | #endif 100 | 101 | #endif /* LIBSWIFTNAV_COMMON_H */ 102 | -------------------------------------------------------------------------------- /include/swiftnav/coord_system.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010 Swift Navigation Inc. 3 | * Contact: Swift Navigation 4 | * 5 | * This source is subject to the license found in the file 'LICENSE' which must 6 | * be distributed together with this source. All other rights reserved. 7 | * 8 | * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 9 | * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 10 | * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. 11 | */ 12 | 13 | #ifndef LIBSWIFTNAV_COORD_SYSTEM_H 14 | #define LIBSWIFTNAV_COORD_SYSTEM_H 15 | 16 | #ifdef __cplusplus 17 | extern "C" { 18 | #endif /* __cplusplus */ 19 | 20 | /** \addtogroup coord_system 21 | * \{ */ 22 | 23 | /** \defgroup WGS84_params WGS84 Parameters 24 | * Parameters defining the WGS84 ellipsoid. The ellipsoid is defined in terms 25 | * of the semi-major axis and the inverse flattening. We also calculate some 26 | * derived parameters which are useful for the implementation of the coordinate 27 | * transform functions. 28 | * \{ */ 29 | /** Semi-major axis of the Earth, \f$ a \f$, in meters. 30 | * This is a defining parameter of the WGS84 ellipsoid. */ 31 | #define WGS84_A 6378137.0 32 | /** Inverse flattening of the Earth, \f$ 1/f \f$. 33 | * This is a defining parameter of the WGS84 ellipsoid. */ 34 | #define WGS84_IF 298.257223563 35 | /** The flattening of the Earth, \f$ f \f$. */ 36 | #define WGS84_F (1 / WGS84_IF) 37 | /** Semi-minor axis of the Earth in meters, \f$ b = a(1-f) \f$. */ 38 | #define WGS84_B (WGS84_A * (1 - WGS84_F)) 39 | /** Eccentricity of the Earth, \f$ e \f$ where \f$ e^2 = 2f - f^2 \f$ */ 40 | #define WGS84_E (sqrt(2 * WGS84_F - WGS84_F * WGS84_F)) 41 | /** Geocentric Gravitational Contant (GM) in m^3 / s^2 */ 42 | #define WGS84_GM 3.986004418e14 43 | /** Nominal Mean Angular Velocity of the Earth in rad / s */ 44 | #define WGS84_OMEGAE_DOT 7.292115e-5 45 | /** The speed of light in m / s. 46 | * \note This is the exact value of the speed of light in vacuum (by the 47 | * definition of meters). */ 48 | #define WGS84_C 299792458.0 49 | /** Universal Constant of Gravitation in m^2 / kg*s^2 */ 50 | #define WGS84_G 6.67428e-11 51 | /** Mass of the Earth (M) in kg */ 52 | #define WGS84_M (WGS84_GM / WGS84_G) 53 | /** Total Mean Mass of the Atmosphere (with water vapor) M_A in kg */ 54 | #define WGS84_M_A 5.1480e18 55 | /** Dynamic Ellipticity (H) */ 56 | #define WGS84_H 3.273795e-3 57 | /** Second Degree Zonal Harmonic */ 58 | #define WGS84_J02 1.082629821313e-3 59 | /* \} */ 60 | 61 | /* \} */ 62 | 63 | void llhrad2deg(const double llh_rad[3], double llh_deg[3]); 64 | 65 | void llhdeg2rad(const double llh_deg[3], double llh_rad[3]); 66 | 67 | void wgsllh2ecef(const double llh[3], double ecef[3]); 68 | 69 | void wgsecef2llh(const double ecef[3], double llh[3]); 70 | 71 | void wgsecef2ned(const double ecef[3], const double ref_ecef[3], double ned[3]); 72 | void wgsecef2ned_d(const double ecef[3], 73 | const double ref_ecef[3], 74 | double ned[3]); 75 | 76 | void wgsned2ecef(const double ned[3], const double ref_ecef[3], double ecef[3]); 77 | void wgsned2ecef_d(const double ned[3], 78 | const double ref_ecef[3], 79 | double ecef[3]); 80 | 81 | void wgsecef2azel(const double ecef[3], 82 | const double ref_ecef[3], 83 | double* azimuth, 84 | double* elevation); 85 | 86 | void wgs_ecef2ned_matrix(const double llh[3], double M[3][3]); 87 | 88 | void ecef2ned_matrix(const double ref_ecef[3], double M[3][3]); 89 | 90 | #ifdef __cplusplus 91 | } /* extern "C" */ 92 | #endif /* __cplusplus */ 93 | 94 | #endif /* LIBSWIFTNAV_COORD_SYSTEM_H */ 95 | -------------------------------------------------------------------------------- /include/swiftnav/decode_glo.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Swift Navigation Inc. 3 | * Contact: Swift Navigation 4 | * 5 | * This source is subject to the license found in the file 'LICENSE' which must 6 | * be distributed together with this source. All other rights reserved. 7 | * 8 | * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 9 | * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 10 | * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. 11 | */ 12 | 13 | #ifndef LIBSWIFTNAV_DECODE_GLO_H 14 | #define LIBSWIFTNAV_DECODE_GLO_H 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #ifdef __cplusplus 22 | extern "C" { 23 | #endif /* __cplusplus */ 24 | 25 | u32 extract_word_glo(const glo_string_t *string, u16 bit_index, u8 n_bits); 26 | 27 | s8 error_detection_glo(const glo_string_t *string); 28 | 29 | bool decode_glo_string_1(const glo_string_t *string, 30 | ephemeris_t *eph, 31 | glo_time_t *tk); 32 | bool decode_glo_string_2(const glo_string_t *string, 33 | ephemeris_t *eph, 34 | glo_time_t *toe); 35 | bool decode_glo_string_3(const glo_string_t *string, 36 | ephemeris_t *eph, 37 | glo_time_t *toe); 38 | bool decode_glo_string_4(const glo_string_t *string, 39 | ephemeris_t *eph, 40 | glo_time_t *tk, 41 | glo_time_t *toe, 42 | u8 *age_of_data_days); 43 | bool decode_glo_string_5(const glo_string_t *string, 44 | ephemeris_t *eph, 45 | glo_time_t *tk, 46 | glo_time_t *toe, 47 | float *tau_gps_s); 48 | 49 | #ifdef __cplusplus 50 | } /* extern "C" */ 51 | #endif /* __cplusplus */ 52 | 53 | #endif /* LIBSWIFTNAV_DECODE_GLO_H */ 54 | -------------------------------------------------------------------------------- /include/swiftnav/edc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 Swift Navigation Inc. 3 | * Contact: Swift Navigation 4 | * 5 | * This source is subject to the license found in the file 'LICENSE' which must 6 | * be distributed together with this source. All other rights reserved. 7 | * 8 | * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 9 | * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 10 | * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. 11 | */ 12 | 13 | #ifndef LIBSWIFTNAV_EDC_H 14 | #define LIBSWIFTNAV_EDC_H 15 | 16 | #include 17 | #include 18 | 19 | #ifdef __cplusplus 20 | extern "C" { 21 | #endif 22 | 23 | u32 crc24q(const u8 *buf, u32 len, u32 crc); 24 | u32 crc24q_bits(u32 crc, const u8 *buf, u32 n_bits, bool invert); 25 | 26 | #ifdef __cplusplus 27 | } /* extern "C" */ 28 | #endif 29 | 30 | #endif /* LIBSWIFTNAV_EDC_H */ 31 | -------------------------------------------------------------------------------- /include/swiftnav/fifo_byte.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Swift Navigation Inc. 3 | * Contact: Swift Navigation 4 | * 5 | * This source is subject to the license found in the file 'LICENSE' which must 6 | * be be distributed together with this source. All other rights reserved. 7 | * 8 | * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 9 | * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 10 | * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. 11 | */ 12 | 13 | #ifndef FIFO_H 14 | #define FIFO_H 15 | 16 | #include 17 | 18 | #ifdef __cplusplus 19 | extern "C" { 20 | #endif /* __cplusplus */ 21 | 22 | typedef uint32_t fifo_size_t; 23 | 24 | typedef struct { 25 | fifo_size_t read_index; 26 | fifo_size_t write_index; 27 | fifo_size_t buffer_size; 28 | uint8_t *buffer; 29 | } fifo_t; 30 | 31 | void fifo_init(fifo_t *fifo, uint8_t *buffer, fifo_size_t buffer_size); 32 | 33 | fifo_size_t fifo_length(fifo_t *fifo); 34 | fifo_size_t fifo_space(fifo_t *fifo); 35 | 36 | fifo_size_t fifo_read(fifo_t *fifo, uint8_t *buffer, fifo_size_t length); 37 | fifo_size_t fifo_peek(fifo_t *fifo, uint8_t *buffer, fifo_size_t length); 38 | fifo_size_t fifo_remove(fifo_t *fifo, fifo_size_t length); 39 | 40 | fifo_size_t fifo_write(fifo_t *fifo, const uint8_t *buffer, fifo_size_t length); 41 | 42 | #ifdef __cplusplus 43 | } 44 | #endif /* __cplusplus */ 45 | 46 | #endif /* FIFO_H */ 47 | -------------------------------------------------------------------------------- /include/swiftnav/float_equality.h: -------------------------------------------------------------------------------- 1 | #ifndef SWIFTNAV_FLOAT_EQUALITY_H 2 | #define SWIFTNAV_FLOAT_EQUALITY_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | static inline bool double_equal(double a, double b) { 9 | return fabs(a - b) < FLOAT_EQUALITY_EPS; 10 | } 11 | 12 | static inline bool float_equal(float a, float b) { 13 | return double_equal((double)a, (double)b); 14 | } 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /include/swiftnav/geoid_model.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Swift Navigation Inc. 3 | * Contact: Swift Navigation 4 | * 5 | * This source is subject to the license found in the file 'LICENSE' which must 6 | * be distributed together with this source. All other rights reserved. 7 | * 8 | * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 9 | * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 10 | * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. 11 | */ 12 | 13 | #ifndef GEOID_MODEL_H 14 | #define GEOID_MODEL_H 15 | 16 | #include 17 | 18 | #ifdef __cplusplus 19 | extern "C" { 20 | #endif /* __cplusplus */ 21 | 22 | // range for lat_rad is (-M_PI_2, M_PI_2) 23 | // range for lon_rad is (-2 * M_PI, 2 * M_PI) 24 | float get_geoid_offset(double lat_rad, double lon_rad); 25 | 26 | typedef enum { 27 | GEOID_MODEL_NONE = 0, 28 | GEOID_MODEL_EGM96 = 1, 29 | GEOID_MODEL_EGM2008 = 2, 30 | } geoid_model_t; 31 | 32 | geoid_model_t get_geoid_model(void); 33 | 34 | #ifdef __cplusplus 35 | } 36 | #endif /* __cplusplus */ 37 | 38 | #endif /* GEOID_MODEL_H */ 39 | -------------------------------------------------------------------------------- /include/swiftnav/glo_map.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Swift Navigation Inc. 3 | * Contact: Dmitry Tatarinov 4 | * 5 | * This source is subject to the license found in the file 'LICENSE' which must 6 | * be distributed together with this source. All other rights reserved. 7 | * 8 | * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 9 | * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 10 | * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. 11 | */ 12 | 13 | #ifndef SRC_GLO_MAP_H_ 14 | #define SRC_GLO_MAP_H_ 15 | 16 | #include 17 | 18 | #ifdef __cplusplus 19 | extern "C" { 20 | #endif /* __cplusplus */ 21 | 22 | void glo_map_init(void (*lock_cb)(void), void (*unlock_cb)(void)); 23 | bool glo_map_valid(const gnss_signal_t sid); 24 | void glo_map_set_slot_id(u16 fcn, u16 glo_slot_id); 25 | u16 glo_map_get_fcn(gnss_signal_t sid); 26 | void glo_map_clear_slot_id(u16 glo_slot_id); 27 | void glo_map_clear_all(void); 28 | void glo_map_fill_dummy_data(void); 29 | u8 glo_map_get_slot_id(const u16 fcn, u16 *slot_id1, u16 *slot_id2); 30 | #ifdef __cplusplus 31 | } /* extern "C" */ 32 | #endif /* __cplusplus */ 33 | 34 | #endif /* SRC_GLO_MAP_H_ */ 35 | -------------------------------------------------------------------------------- /include/swiftnav/glonass_phase_biases.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2017 Swift Navigation Inc. 3 | * Contact: Fergus Noble 4 | * 5 | * This source is subject to the license found in the file 'LICENSE' which must 6 | * be be distributed together with this source. All other rights reserved. 7 | * 8 | * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 9 | * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 10 | * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. 11 | */ 12 | 13 | #ifndef PIKSI_FIRMWARE_PRIVATE_GLONASS_PHASE_BIASES_H 14 | #define PIKSI_FIRMWARE_PRIVATE_GLONASS_PHASE_BIASES_H 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #ifdef __cplusplus 21 | extern "C" { 22 | #endif 23 | 24 | #define MSG_GLO_BIASES_MULTIPLIER 50.0 25 | 26 | #define RTCM1230_MASK_L2P ((u8)1 << 0) 27 | #define RTCM1230_MASK_L2OF ((u8)1 << 1) 28 | #define RTCM1230_MASK_L1P ((u8)1 << 2) 29 | #define RTCM1230_MASK_L1OF ((u8)1 << 3) 30 | 31 | typedef struct { 32 | /* The following constants describes the biases that will be sent through 33 | * SBP_MSG_GLO_BIASES in the sbp stream. Biases are to be expressed in meters 34 | * and are not quantized 35 | */ 36 | u8 mask; /**< GLONASS FDMA signals mask [boolean] */ 37 | double l1of_bias_m; /**< GLONASS L1 OF Code-Phase Bias [m] */ 38 | double l1p_bias_m; /**< GLONASS L1 P Code-Phase Bias [m] */ 39 | double l2of_bias_m; /**< GLONASS L2 OF Code-Phase Bias [m] */ 40 | double l2p_bias_m; /**< GLONASS L2 P Code-Phase Bias [m] */ 41 | } glo_biases_t; 42 | 43 | bool glonass_biases_are_equal(const glo_biases_t biases1, 44 | const glo_biases_t biases2); 45 | 46 | bool is_bias_mask_flag_set(const u8 msg_flags, const u8 flag); 47 | 48 | // This constant structure contains the Piksi GLONASS phase bias 49 | static const glo_biases_t piksi_glonass_biases = {255, // .mask 50 | 0., // .l1of_bias_m 51 | 0., // .l1p_bias_m 52 | 0., // .l2of_bias_m 53 | 0.}; // .l2p_bias_m 54 | 55 | double get_glonass_bias(const code_t code, const glo_biases_t biases); 56 | 57 | #ifdef __cplusplus 58 | } /* extern "C" */ 59 | #endif 60 | 61 | #endif // PIKSI_FIRMWARE_PRIVATE_GLONASS_PHASE_BIASES_H 62 | -------------------------------------------------------------------------------- /include/swiftnav/gnss_capabilities.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Swift Navigation Inc. 3 | * Contact: Swift Navigation 4 | * 5 | * This source is subject to the license found in the file 'LICENSE' which must 6 | * be distributed together with this source. All other rights reserved. 7 | * 8 | * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 9 | * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 10 | * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. 11 | */ 12 | 13 | #ifndef LIBSWIFTNAV_GNSS_CAPABILITIES_H 14 | #define LIBSWIFTNAV_GNSS_CAPABILITIES_H 15 | 16 | #ifdef __cplusplus 17 | extern "C" { 18 | #endif /* __cplusplus */ 19 | 20 | /** \defgroup constants GNSSS capabilities 21 | * \{ */ 22 | 23 | /* 24 | * Note: BDS GEO SVs are marked as inactive, 25 | * in order to prevent their acquisition. 26 | * Configuration compliant with to 27 | * http://www.csno-tarc.cn/en/system/constellation 28 | * retrieved on May 2nd 29 | */ 30 | #define GNSS_CAPB_BDS_ACTIVE ((u64)0x1fbffcbfe0) 31 | #define GNSS_CAPB_BDS_D2NAV ((u64)0x000000001f) 32 | #define GNSS_CAPB_BDS_B2 ((u64)0x000000bfff) 33 | #define GNSS_CAPB_BDS_B2A ((u64)0x1fbffc0000) 34 | 35 | /** \} */ 36 | 37 | #ifdef __cplusplus 38 | } /* extern "C" */ 39 | #endif /* __cplusplus */ 40 | 41 | #endif /* LIBSWIFTNAV_GNSS_CAPABILITIES_H */ 42 | -------------------------------------------------------------------------------- /include/swiftnav/ionosphere.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015, 2016, 2020 Swift Navigation Inc. 3 | * Contact: Swift Navigation 4 | * 5 | * This source is subject to the license found in the file 'LICENSE' which must 6 | * be distributed together with this source. All other rights reserved. 7 | * 8 | * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 9 | * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 10 | * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. 11 | */ 12 | 13 | #ifndef LIBSWIFTNAV_IONOSHPERE_H 14 | #define LIBSWIFTNAV_IONOSHPERE_H 15 | 16 | #include 17 | #include 18 | 19 | #ifdef __cplusplus 20 | #include 21 | extern "C" { 22 | #endif 23 | 24 | /** IS-GPS-200H Table 20-X: 2^-30 */ 25 | #define GPS_LNAV_IONO_SF_A0 C_1_2P30 26 | /** IS-GPS-200H Table 20-X: 2^-27 */ 27 | #define GPS_LNAV_IONO_SF_A1 C_1_2P27 28 | /** IS-GPS-200H Table 20-X: 2^-24 */ 29 | #define GPS_LNAV_IONO_SF_A2 C_1_2P24 30 | /** IS-GPS-200H Table 20-X: 2^-24 */ 31 | #define GPS_LNAV_IONO_SF_A3 C_1_2P24 32 | /** IS-GPS-200H Table 20-X: 2^11 */ 33 | #define GPS_LNAV_IONO_SF_B0 2048 34 | /** IS-GPS-200H Table 20-X: 2^14 */ 35 | #define GPS_LNAV_IONO_SF_B1 16384 36 | /** IS-GPS-200H Table 20-X: 2^16 */ 37 | #define GPS_LNAV_IONO_SF_B2 65536 38 | /** IS-GPS-200H Table 20-X: 2^16 */ 39 | #define GPS_LNAV_IONO_SF_B3 65536 40 | 41 | /** Structure holding Klobuchar ionospheric model parameters. */ 42 | typedef struct { 43 | gps_time_t toa; /**< Reference time of almanac. */ 44 | double a0, a1, a2, a3; 45 | double b0, b1, b2, b3; 46 | } ionosphere_t; 47 | 48 | static const ionosphere_t DEFAULT_IONO_PARAMS = {{ // .toa 49 | TOW_UNKNOWN, // .tow 50 | WN_UNKNOWN}, // .wn 51 | 0.0, // .a0 52 | 0.0, // .a1 53 | 0.0, // .a2 54 | 0.0, // .a3 55 | 0.0, // .b0 56 | 0.0, // .b1 57 | 0.0, // .b2 58 | 0.0}; // .b3 59 | 60 | double calc_ionosphere(const gps_time_t *t_gps, 61 | double lat_u, 62 | double lon_u, 63 | double a, 64 | double e, 65 | const ionosphere_t *i); 66 | 67 | bool decode_iono_parameters(const u32 words[8], ionosphere_t *i); 68 | 69 | void decode_bds_d1_iono(const u32 words[10], ionosphere_t *iono); 70 | 71 | #ifdef __cplusplus 72 | } /* extern "C" */ 73 | #endif 74 | 75 | #ifdef __cplusplus 76 | static inline bool operator==(const ionosphere_t &a, const ionosphere_t &b) { 77 | return double_approx_eq(gpsdifftime(&a.toa, &b.toa), 0.0) && 78 | double_approx_eq(a.a0, b.a0) && double_approx_eq(a.a1, b.a1) && 79 | double_approx_eq(a.a2, b.a2) && double_approx_eq(a.a3, b.a3) && 80 | double_approx_eq(a.b0, b.b0) && double_approx_eq(a.b1, b.b1) && 81 | double_approx_eq(a.b2, b.b2) && double_approx_eq(a.b3, b.b3); 82 | } 83 | #endif 84 | 85 | #endif /* LIBSWIFTNAV_IONOSHPERE_H */ 86 | -------------------------------------------------------------------------------- /include/swiftnav/leap_seconds.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2021 Swift Navigation Inc. 3 | * Contact: Swift Navigation 4 | * 5 | * This source is subject to the license found in the file 'LICENSE' which must 6 | * distributed together with this source. All other rights reserved. 7 | * 8 | * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 9 | * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 10 | * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. 11 | */ 12 | 13 | /****************************************************************************** 14 | * Automatically generated from scripts/leap_seconds_generator.py. Please do * 15 | * not hand edit! * 16 | * * 17 | * Updated: 30-03-2023 * 18 | ******************************************************************************/ 19 | 20 | #ifndef LIBSWIFTNAV_LEAP_SECONDS_H 21 | #define LIBSWIFTNAV_LEAP_SECONDS_H 22 | 23 | #include 24 | 25 | #ifdef __cplusplus 26 | extern "C" { 27 | #endif 28 | 29 | /** 30 | * Start times of UTC leap second events given in GPS time {wn, tow, gps-utc} 31 | * The leap second event lasts for one second from the start time, and after 32 | * that the new offset is in effect. 33 | */ 34 | static const s32 utc_leaps[][3] = { 35 | {77, 259200, 1}, /* 01-07-1981 */ 36 | {129, 345601, 2}, /* 01-07-1982 */ 37 | {181, 432002, 3}, /* 01-07-1983 */ 38 | {286, 86403, 4}, /* 01-07-1985 */ 39 | {416, 432004, 5}, /* 01-01-1988 */ 40 | {521, 86405, 6}, /* 01-01-1990 */ 41 | {573, 172806, 7}, /* 01-01-1991 */ 42 | {651, 259207, 8}, /* 01-07-1992 */ 43 | {703, 345608, 9}, /* 01-07-1993 */ 44 | {755, 432009, 10}, /* 01-07-1994 */ 45 | {834, 86410, 11}, /* 01-01-1996 */ 46 | {912, 172811, 12}, /* 01-07-1997 */ 47 | {990, 432012, 13}, /* 01-01-1999 */ 48 | {1356, 13, 14}, /* 01-01-2006 */ 49 | {1512, 345614, 15}, /* 01-01-2009 */ 50 | {1695, 15, 16}, /* 01-07-2012 */ 51 | {1851, 259216, 17}, /* 01-07-2015 */ 52 | {1930, 17, 18}, /* 01-01-2017 */ 53 | }; 54 | 55 | /** GPS time when the utc_leaps table expires 28-12-2023 */ 56 | static const s32 gps_time_utc_leaps_expiry[2] = {2294, 345618}; 57 | 58 | /** UNIX time when the utc_leaps table expires 28-12-2023 */ 59 | static const s64 unix_time_utc_leaps_expiry = 1703721600; 60 | 61 | #ifdef __cplusplus 62 | } 63 | #endif 64 | 65 | #endif // LIBSWIFTNAV_LEAP_SECONDS_H 66 | -------------------------------------------------------------------------------- /include/swiftnav/linear_algebra.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Swift Navigation Inc. 3 | * Contact: Swift Navigation 4 | * 5 | * This source is subject to the license found in the file 'LICENSE' which must 6 | * be distributed together with this source. All other rights reserved. 7 | * 8 | * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 9 | * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 10 | * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. 11 | */ 12 | 13 | #ifndef LIBSWIFTNAV_LINEAR_ALGEBRA_H 14 | #define LIBSWIFTNAV_LINEAR_ALGEBRA_H 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | #ifdef __cplusplus 21 | extern "C" { 22 | #endif 23 | 24 | #define VEC_PRINTF(v, _n) \ 25 | { \ 26 | printf("%s:%u <|%s| %lf", __FILE__, __LINE__, #v, (v)[0]); \ 27 | for (u32 _i = 1; _i < (u32)(_n); _i++) printf(", %lf", (v)[_i]); \ 28 | printf(">\n"); \ 29 | } 30 | 31 | #define MAT_PRINTF(m, _r, _c) \ 32 | { \ 33 | printf("%s:%u <|%s|\n", __FILE__, __LINE__, #m); \ 34 | for (u32 _i = 0; _i < (u32)(_r); _i++) { \ 35 | printf(" [% 12lf", (m)[_i * (u32)(_c) + 0]); \ 36 | for (u32 _j = 1; _j < (u32)(_c); _j++) \ 37 | printf(" % 12lf", (m)[_i * (u32)(_c) + _j]); \ 38 | printf("]\n"); \ 39 | } \ 40 | printf(">\n"); \ 41 | } 42 | 43 | void dmtx_printf(double *mtx, u32 m, u32 n); 44 | void dmtx_printi(s32 *mtx, u32 m, u32 n); 45 | void submatrix(u32 new_rows, 46 | u32 new_cols, 47 | u32 old_cols, 48 | const double *old_mat, 49 | const u32 *new_row_to_old, 50 | const u32 *new_col_to_old, 51 | double *new_mat); 52 | void submatrix_ul(u32 new_rows, 53 | u32 new_cols, 54 | u32 old_cols, 55 | const double *old_mat, 56 | double *new_mat); 57 | s32 qrdecomp_square(const double *a, u32 rows, double *qt, double *r); 58 | s32 qrdecomp(const double *a, u32 rows, u32 cols, double *qt, double *r); 59 | void qtmult(const double *qt, u32 n, const double *b, double *x); 60 | void rsolve(const double *r, u32 rows, u32 cols, const double *b, double *x); 61 | s32 qrsolve(const double *a, u32 rows, u32 cols, const double *b, double *x); 62 | 63 | int matrix_inverse(u32 n, const double *const a, double *b); 64 | void matrix_multiply( 65 | u32 n, u32 m, u32 p, const double *a, const double *b, double *c); 66 | void matrix_multiply_i(u32 n, u32 m, u32 p, const s32 *a, const s32 *b, s32 *c); 67 | void matrix_multiply_s64( 68 | u32 n, u32 m, u32 p, const s64 *a, const s64 *b, s64 *c); 69 | void matrix_multiply_diag_right(u32 n, u32 m, double *a, const double *d); 70 | int matrix_wlsq_solve(u32 n, 71 | u32 m, 72 | const double *A, 73 | const double *b, 74 | const double *w, 75 | double *x, 76 | double *V); 77 | void matrix_triu(u32 n, double *M); 78 | void matrix_eye(u32 n, double *M); 79 | void matrix_udu(u32 n, double *M, double *U, double *D); 80 | void matrix_reconstruct_udu(const u32 n, 81 | const double *U, 82 | const double *D, 83 | double *M); 84 | void matrix_add_sc( 85 | u32 n, u32 m, const double *a, const double *b, double gamma, double *c); 86 | void matrix_transpose(u32 n, u32 m, const double *a, double *b); 87 | void matrix_copy(u32 n, u32 m, const double *a, double *b); 88 | 89 | int matrix_pseudoinverse(u32 n, u32 m, const double *a, double *b); 90 | int matrix_atwaiat(u32 n, u32 m, const double *a, const double *w, double *b); 91 | int matrix_ataiat(u32 n, u32 m, const double *a, double *b); 92 | int matrix_atawati(u32 n, u32 m, const double *a, const double *w, double *b); 93 | int matrix_ataati(u32 n, u32 m, const double *a, double *b); 94 | 95 | double vector_dot(u32 n, const double *a, const double *b); 96 | double vector_norm(u32 n, const double *a); 97 | double vector_mean(u32 n, const double *a); 98 | void vector_normalize(u32 n, double *a); 99 | void vector_add_sc( 100 | u32 n, const double *a, const double *b, double gamma, double *c); 101 | void vector_add(u32 n, const double *a, const double *b, double *c); 102 | void vector_subtract(u32 n, const double *a, const double *b, double *c); 103 | void vector_cross(const double a[3], const double b[3], double c[3]); 104 | double vector_distance(u32 n, const double *a, const double *b); 105 | bool double_approx_eq(const double a, const double b); 106 | bool double_within(const double a, const double b, const double tolerance); 107 | 108 | #ifdef __cplusplus 109 | } /* extern "C" */ 110 | #endif 111 | 112 | #endif /* LIBSWIFTNAV_LINEAR_ALGEBRA_H */ 113 | -------------------------------------------------------------------------------- /include/swiftnav/macro_overload.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Swift Navigation Inc. 3 | * Contact: Swift Navigation 4 | * 5 | * This source is subject to the license found in the file 'LICENSE' which must 6 | * be distributed together with this source. All other rights reserved. 7 | * 8 | * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 9 | * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 10 | * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. 11 | */ 12 | #ifndef LIBSWIFTNAV_MACRO_OVERLOAD_H 13 | #define LIBSWIFTNAV_MACRO_OVERLOAD_H 14 | 15 | /** 16 | * Helper for overloaded macros. Define an overloaded macro by passing in 17 | * __VA_ARGS__ followed by a list of macros which accept a different number of 18 | * parameters in decending order, such as: 19 | * 20 | * #define FOO0() ... 21 | * #define FOO1(a) ... 22 | * #define FOO2(a,b) ... 23 | * #define FOO3(a,b,c) ... 24 | * #define FOO LSN_EXPAND(LSN_GET_MACRO(__VA_ARGS, FOO3, FOO2, FOO1, \ 25 | * FOO0)(__VA_ARGS__)) 26 | * 27 | * Then all the following calls are valid and get redirected to the correct 28 | * macro 29 | * 30 | * FOO() 31 | * FOO(one) 32 | * FOO(one,two) 33 | * FOO(one,two,three) 34 | * 35 | * This currently only works up to 16 arguments but can be easily expanded if 36 | * and when required 37 | */ 38 | #define LSN_GET_MACRO(_1, \ 39 | _2, \ 40 | _3, \ 41 | _4, \ 42 | _5, \ 43 | _6, \ 44 | _7, \ 45 | _8, \ 46 | _9, \ 47 | _10, \ 48 | _11, \ 49 | _12, \ 50 | _13, \ 51 | _14, \ 52 | _15, \ 53 | _16, \ 54 | NAME, \ 55 | ...) \ 56 | NAME 57 | 58 | /** 59 | * Helper macro to get around MSVC preprocessor 60 | */ 61 | #define LSN_EXPAND(x) x 62 | 63 | #endif 64 | -------------------------------------------------------------------------------- /include/swiftnav/memcpy_s.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Swift Navigation Inc. 3 | * Contact: Swift Navigation 4 | * 5 | * This source is subject to the license found in the file 'LICENSE' which must 6 | * be distributed together with this source. All other rights reserved. 7 | * 8 | * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 9 | * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 10 | * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. 11 | */ 12 | 13 | #ifndef LIBSWIFTNAV_MEMCPY_S_H 14 | #define LIBSWIFTNAV_MEMCPY_S_H 15 | 16 | #if defined(_MSC_VER) 17 | #include 18 | #elif !defined(_CRT_MEMORY_DEFINED) 19 | #include 20 | #include 21 | 22 | #ifdef __cplusplus 23 | extern "C" { 24 | #endif 25 | 26 | typedef enum { 27 | MEMCPY_S_OK, 28 | MEMCPY_S_DEST_NULL, 29 | MEMCPY_S_SRC_NULL, 30 | MEMCPY_S_DEST_SIZE_ZERO, 31 | MEMCPY_S_SRC_SIZE_ZERO, 32 | MEMCPY_S_OVERLAP, 33 | MEMCPY_S_OVERSIZED 34 | } memcpy_s_t; 35 | 36 | memcpy_s_t memcpy_s(void *dest, size_t destsize, const void *src, size_t count); 37 | 38 | #ifdef __cplusplus 39 | } /* extern "C" */ 40 | #endif 41 | 42 | #endif /* _CRT_MEMORY_DEFINED */ 43 | 44 | #define MEMCPY_S(d, ds, src, c) \ 45 | do { \ 46 | int memcpy_s_res = memcpy_s(d, ds, src, c); \ 47 | if (0 != memcpy_s_res) { \ 48 | log_error("MEMCPY_S failed with code %d", memcpy_s_res); \ 49 | assert(false); \ 50 | } \ 51 | } while (false) 52 | 53 | #endif /* LIBSWIFTNAV_MEMCPY_S_H */ 54 | -------------------------------------------------------------------------------- /include/swiftnav/nav_meas.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Swift Navigation Inc. 3 | * Contact: Swift Navigation 4 | * 5 | * This source is subject to the license found in the file 'LICENSE' which must 6 | * be distributed together with this source. All other rights reserved. 7 | * 8 | * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 9 | * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 10 | * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. 11 | */ 12 | 13 | #ifndef LIBSWIFTNAV_NAV_MEAS_H 14 | #define LIBSWIFTNAV_NAV_MEAS_H 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #ifdef __cplusplus 22 | extern "C" { 23 | #endif /* __cplusplus */ 24 | 25 | /** Measurement flag: pseudorange and raw_pseudorange fields contain a 26 | * valid value. 27 | * \sa nav_meas_flags_t */ 28 | #define NAV_MEAS_FLAG_CODE_VALID ((nav_meas_flags_t)1 << 0) 29 | /** Measurement flag: carrier_phase and raw_carrier_phase fields contain a 30 | * valid value. 31 | * \sa nav_meas_flags_t */ 32 | #define NAV_MEAS_FLAG_PHASE_VALID ((nav_meas_flags_t)1 << 1) 33 | /** Measurement flag: measured_doppler and raw_measured_doppler fields 34 | * contain a valid value. 35 | * \sa nav_meas_flags_t */ 36 | #define NAV_MEAS_FLAG_MEAS_DOPPLER_VALID ((nav_meas_flags_t)1 << 2) 37 | /** Measurement flag: computed_doppler and raw_computed_doppler fields 38 | * contain a valid value. 39 | * \sa nav_meas_flags_t */ 40 | #define NAV_MEAS_FLAG_COMP_DOPPLER_VALID ((nav_meas_flags_t)1 << 3) 41 | /** Measurement flag: if bit not set, the half cycle carrier phase ambiguity has 42 | * yet to be resolved. Carrier phase measurements might be 0.5 cycles out of 43 | * phase. 44 | * \sa nav_meas_flags_t */ 45 | #define NAV_MEAS_FLAG_HALF_CYCLE_KNOWN ((nav_meas_flags_t)1 << 4) 46 | /** Measurement flag: cn0 field contains a valid value. 47 | * \sa nav_meas_flags_t */ 48 | #define NAV_MEAS_FLAG_CN0_VALID ((nav_meas_flags_t)1 << 5) 49 | /** Measurement flag: measurement was excluded by SPP RAIM, use with care. 50 | * \sa nav_meas_flags_t */ 51 | #define NAV_MEAS_FLAG_RAIM_EXCLUSION ((nav_meas_flags_t)1 << 6) 52 | 53 | /** Navigation measurement flag mask. 54 | * 55 | * Mask value is any combination of the following flags: 56 | * - #NAV_MEAS_FLAG_CODE_VALID 57 | * - #NAV_MEAS_FLAG_PHASE_VALID 58 | * - #NAV_MEAS_FLAG_MEAS_DOPPLER_VALID 59 | * - #NAV_MEAS_FLAG_COMP_DOPPLER_VALID 60 | * - #NAV_MEAS_FLAG_HALF_CYCLE_KNOWN 61 | * - #NAV_MEAS_FLAG_CN0_VALID 62 | * 63 | * \sa navigation_measurement_t 64 | */ 65 | typedef u16 nav_meas_flags_t; 66 | 67 | /** 68 | * Used to indicate that the eph_key, sat_pos, sat_vel, sat_acc, sat_clock_err 69 | * and sat_clock_err_rate fields have not yet been initialised. 70 | */ 71 | #define NAV_MEAS_INVALID_EPH_KEY 0xFFFF 72 | 73 | /** 74 | * Structure for processing navigation measurements 75 | */ 76 | typedef struct { 77 | double raw_pseudorange; /**< Raw pseudorange: time of flight 78 | * multiplied by speed of light [m] */ 79 | double raw_carrier_phase; /**< Raw carrier phase [cycle] */ 80 | double raw_measured_doppler; /**< Raw doppler from tracker [Hz] */ 81 | double raw_computed_doppler; /**< Raw doppler from time difference of 82 | * carrier phase [Hz] */ 83 | double sat_pos[3]; /**< SV ECEF position [m] */ 84 | double sat_vel[3]; /**< SV ECEF velocity [m/s] */ 85 | double sat_acc[3]; /**< SV ECEF accel [m/s/s] */ 86 | u16 eph_key; /**< Ephemeris key [unitless] */ 87 | double sat_clock_err; /**< SV clock error [s] */ 88 | double sat_clock_err_rate; /**< SV clock error rate [s/s] */ 89 | double cn0; /**< Carrier to noise ratio [dB-Hz] */ 90 | double lock_time; /**< PLL lock time [s] */ 91 | double elevation; /**< Approximate satellite elevation [deg] */ 92 | gps_time_t tot; /**< Time of transmit */ 93 | gnss_signal_t sid; /**< SV signal identifier */ 94 | nav_meas_flags_t flags; /**< Measurement flags */ 95 | } navigation_measurement_t; 96 | 97 | /* Correction fixing consistency flags */ 98 | #define VALID_CORRECTIONS (1 << 0) 99 | #define PARTIAL_FIXING (1 << 1) 100 | #define FULL_FIXING (1 << 2) 101 | #define INVALID_CODE_CORRECTIONS (1 << 3) 102 | #define INVALID_PHASE_CORRECTIONS (1 << 4) 103 | 104 | /** 105 | * Structure for processing navigation measurements estimated standard deviation 106 | */ 107 | typedef struct { 108 | gnss_signal_t sid; /**< SV signal identifier */ 109 | double iono_std; /**< Observations ionospheric delay std [m] */ 110 | double tropo_std; /**< Observations tropospheric delay std [m] */ 111 | double range_std; /**< Observations orbit/clock delay std [m] */ 112 | u8 flags; /**< Observations fixing flags [m], see above */ 113 | } measurement_std_t; 114 | 115 | bool measurement_std_equal(const measurement_std_t *a, 116 | const measurement_std_t *b); 117 | bool nav_meas_equal(const navigation_measurement_t *a, 118 | const navigation_measurement_t *b); 119 | int nav_meas_cmp(const void *a, const void *b); 120 | bool nav_meas_flags_valid(nav_meas_flags_t flags); 121 | bool pseudorange_valid(const navigation_measurement_t *meas); 122 | 123 | u8 encode_lock_time(double nm_lock_time); 124 | double decode_lock_time(u8 sbp_lock_time); 125 | double nav_meas_cor_sat_clk_on_pseudorange( 126 | const navigation_measurement_t *nav_meas); 127 | double nav_meas_cor_sat_clk_on_measured_doppler( 128 | const navigation_measurement_t *nav_meas); 129 | double nav_meas_cor_sat_clk_on_carrier_phase( 130 | const navigation_measurement_t *nav_meas); 131 | 132 | static inline bool not_l2p_sid(navigation_measurement_t a) { 133 | return a.sid.code != CODE_GPS_L2P; 134 | } 135 | 136 | #ifdef __cplusplus 137 | } /* extern "C" */ 138 | #endif /* __cplusplus */ 139 | 140 | #endif /* LIBSWIFTNAV_NAV_MEAS_H */ 141 | -------------------------------------------------------------------------------- /include/swiftnav/pvt_result.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Swift Navigation Inc. 3 | * Contact: Swift Navigation 4 | * 5 | * This source is subject to the license found in the file 'LICENSE' which must 6 | * be distributed together with this source. All other rights reserved. 7 | * 8 | * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 9 | * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 10 | * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. 11 | */ 12 | 13 | #ifndef LIBSWIFTNAV_PVT_ENGINE_PVT_RESULT_H_ 14 | #define LIBSWIFTNAV_PVT_ENGINE_PVT_RESULT_H_ 15 | 16 | #include 17 | #include 18 | 19 | #ifdef __cplusplus 20 | extern "C" { 21 | #endif // __cplusplus 22 | 23 | /* Define Time types - currently aligned to SBP messages */ 24 | #define NO_TIME 0 25 | #define GNSS_TIME 1 26 | #define PROPAGATED_TIME 2 27 | #define TIME_SOURCE_MASK 0x07 /* Bits 0-2 */ 28 | #define DEFAULT_UTC 0 29 | #define NVM_UTC 1 30 | #define DECODED_UTC 2 31 | #define UTC_SOURCE_MASK 0x18 /* Bits 3-4 */ 32 | 33 | /* Define Position types - currently aligned to SBP messages */ 34 | #define POSITION_MODE_NONE 0 35 | #define POSITION_MODE_SPP 1 36 | #define POSITION_MODE_DGNSS 2 37 | #define POSITION_MODE_FLOAT 3 38 | #define POSITION_MODE_FIXED 4 39 | #define POSITION_MODE_DEAD_RECKONING 5 40 | #define POSITION_MODE_SBAS 6 41 | 42 | /* Define Velocity types - currently aligned to SBP messages */ 43 | #define VELOCITY_MODE_NONE 0 44 | #define VELOCITY_MODE_MEASURED_DOPPLER 1 45 | #define VELOCITY_MODE_COMPUTED_DOPPLER 2 46 | #define VELOCITY_MODE_DEAD_RECKONING 3 47 | 48 | /* Define INS status types used in dr_runner */ 49 | #define INS_STATUS_AWAITING_INIT 0 50 | #define INS_STATUS_ALIGNING 1 51 | #define INS_STATUS_READY 2 52 | #define INS_STATUS_OUTAGE_EXCEEDS_MAX 3 53 | #define INS_STATUS_SEEDING 4 54 | #define INS_STATUS_FASTSTARTING 5 55 | #define INS_MODE_MASK 0x7 /* Bit 0-2 */ 56 | #define INS_GNSS_FIX_AVAILABILITY_MASK 0x8 /* Bit 3 */ 57 | /* Bits 11-13 */ 58 | #define INS_STATUS_MOTION_STATE_UNKNOWN 0 59 | #define INS_STATUS_MOTION_STATE_ARBITRARY_MOTION 1 60 | #define INS_STATUS_MOTION_STATE_STRAIGHT_MOTION 2 61 | #define INS_STATUS_MOTION_STATE_STATIONARY 3 62 | 63 | /* Define GROUP_META flags used in fusion */ 64 | #define GROUP_META_TIME_REF_MASK 0x3 /* Bits 0-1 */ 65 | #define GROUP_META_SOLUTION_SOURCE_MASK 0xC /* Bits 2-3 */ 66 | #define GROUP_META_TIME_QUALITY_MASK 0x30 /* Bits 4-5 */ 67 | /* msg_group_meta.group_id */ 68 | #define GROUP_META_ID_UNKNOWN 0 69 | #define GROUP_META_ID_FUSION_BESTPOS 1 70 | #define GROUP_META_ID_GNSS 2 71 | /* max number of elements in msg_group_soln_meta.sol_in array */ 72 | #define SOLN_META_MAX_N_SOL_IN 20 73 | 74 | /* Define SOLN_META flags used in fusion */ 75 | #define SOLN_META_ALIGNMENT_STATUS_UNKNOWN_OR_ALIGNED 0 76 | #define SOLN_META_ALIGNMENT_STATUS_SEEDED_ALIGNING 1 77 | #define SOLN_META_ALIGNMENT_STATUS_UNSEEDED_ALIGNING 2 78 | #define SOLN_META_ALIGNMENT_STATUS_SEEDED_AWAITING 3 79 | #define SOLN_META_ALIGNMENT_STATUS_UNSEEDED_AWAITING 4 80 | /* soln_meta_msg.sensor_type[0:2] */ 81 | #define SOLN_META_SENSOR_TYPE_INVALID 0 82 | #define SOLN_META_SENSOR_TYPE_GNSS_POS 1 83 | #define SOLN_META_SENSOR_TYPE_GNSS_VEL_DELTA 2 84 | #define SOLN_META_SENSOR_TYPE_GNSS_VEL_DOPPLER 3 85 | #define SOLN_META_SENSOR_TYPE_ODO_TICKS 4 86 | #define SOLN_META_SENSOR_TYPE_ODO_SPEED 5 87 | #define SOLN_META_SENSOR_TYPE_IMU 6 88 | /* sol_in[].flags[0:1] */ 89 | #define SOLN_META_INPUT_TYPE_GNSS_POS 0 90 | #define SOLN_META_INPUT_TYPE_GNSS_VEL_DOPPLER 1 91 | #define SOLN_META_INPUT_TYPE_GNSS_VEL_DELTA 2 92 | /* sol_in[].flags[0:1] */ 93 | #define SOLN_META_INPUT_TYPE_IMU_MEMS 0 94 | #define SOLN_META_INPUT_TYPE_IMU_OTHER 1 95 | /* sol_in[].flags[2:3] */ 96 | #define SOLN_META_INPUT_TYPE_IMU_GRADE_CONSUMER 0 97 | #define SOLN_META_INPUT_TYPE_IMU_GRADE_TACTICAL 1 98 | #define SOLN_META_INPUT_TYPE_IMU_GRADE_INTERM 2 99 | #define SOLN_META_INPUT_TYPE_IMU_GRADE_SUP 3 100 | /* sol_in[].flags[4:5] */ 101 | #define SOLN_META_INPUT_TYPE_IMU_TIME_REF_GPS 0 102 | #define SOLN_META_INPUT_TYPE_IMU_TIME_REF_CPU 1 103 | #define SOLN_META_INPUT_TYPE_IMU_TIME_REF_UNKNOWN 3 104 | #define SOLN_META_INPUT_TYPE_IMU_TIME_REF_PPS 4 105 | /* sol_in[].flags[0:1] */ 106 | #define SOLN_META_INPUT_TYPE_ODO_CLASS_SCALAR_TICKS 0 107 | #define SOLN_META_INPUT_TYPE_ODO_CLASS_SCALAR_SPEED 1 108 | #define SOLN_META_INPUT_TYPE_ODO_CLASS_MULTIDIM_TICKS 2 109 | #define SOLN_META_INPUT_TYPE_ODO_CLASS_MULTIDIM_SPEED 3 110 | /* sol_in[].flags[2:3] */ 111 | #define SOLN_META_INPUT_TYPE_ODO_GRADE_LOW 0 112 | #define SOLN_META_INPUT_TYPE_ODO_GRADE_MED 1 113 | #define SOLN_META_INPUT_TYPE_ODO_GRADE_SUP 2 114 | 115 | /* These masks are used in the firmware. */ 116 | #define POSITION_MODE_MASK 0x07 /* Bits 0-2 */ 117 | #define VELOCITY_MODE_MASK 0x07 /* Bits 0-2 */ 118 | #define RAIM_REPAIR_FLAG 0x80 /* Bit 7 */ 119 | 120 | typedef struct pvt_engine_result_flags_t { 121 | u8 position_mode : 3; 122 | u8 raim_repair_flag : 1; 123 | } pvt_engine_result_flags_t; 124 | 125 | typedef struct { 126 | gps_time_t time; 127 | bool valid; 128 | bool position_ecef_valid; 129 | double position_ecef[3]; 130 | double position_ecef_covariance[9]; 131 | bool baseline_valid; 132 | double baseline[3]; 133 | double baseline_covariance[9]; 134 | bool average_velocity_valid; 135 | double average_velocity[3]; 136 | double average_velocity_covariance[9]; 137 | bool instantaneous_velocity_valid; 138 | double instantaneous_velocity[3]; 139 | double instantaneous_velocity_covariance[9]; 140 | u8 num_sats_used; 141 | u8 num_sigs_used; 142 | pvt_engine_result_flags_t flags; 143 | bool has_known_reference_pos; 144 | double known_reference_pos[3]; 145 | double propagation_time; 146 | bool is_fixed; 147 | } pvt_engine_result_t; 148 | 149 | #ifdef __cplusplus 150 | } 151 | #endif // __cplusplus 152 | 153 | #endif 154 | -------------------------------------------------------------------------------- /include/swiftnav/sbas_raw_data.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Swift Navigation Inc. 3 | * Contact: Swift Navigation 4 | * 5 | * This source is subject to the license found in the file 'LICENSE' which must 6 | * be distributed together with this source. All other rights reserved. 7 | * 8 | * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 9 | * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 10 | * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. 11 | */ 12 | 13 | #ifndef LIBSWIFTNAV_SBAS_RAW_DATA_H 14 | #define LIBSWIFTNAV_SBAS_RAW_DATA_H 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | #ifdef __cplusplus 21 | extern "C" { 22 | #endif 23 | 24 | #define SBAS_RAW_PAYLOAD_LENGTH 27 25 | 26 | typedef struct { 27 | gnss_signal_t sid; 28 | gps_time_t time_of_transmission; 29 | u8 message_type; 30 | u8 data[SBAS_RAW_PAYLOAD_LENGTH]; 31 | } sbas_raw_data_t; 32 | 33 | #ifdef __cplusplus 34 | } /* extern "C" */ 35 | #endif 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /include/swiftnav/set.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Swift Navigation Inc. 3 | * Contact: Swift Navigation 4 | * 5 | * This source is subject to the license found in the file 'LICENSE' which must 6 | * be distributed together with this source. All other rights reserved. 7 | * 8 | * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 9 | * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 10 | * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. 11 | */ 12 | 13 | #ifndef LIBSWIFTNAV_SET_H 14 | #define LIBSWIFTNAV_SET_H 15 | 16 | #include 17 | #include 18 | 19 | #ifdef __cplusplus 20 | extern "C" { 21 | #endif /* __cplusplus */ 22 | 23 | /** \addtogroup set 24 | * \{ */ 25 | 26 | /** Comparison function prototype. 27 | * Follows the standard C library comparison prototype e.g. used by qsort() 28 | * http://www.gnu.org/software/libc/manual/html_node/Comparison-Functions.html 29 | * 30 | * \param a Pointer to A 31 | * \param b Pointer to B 32 | * \return <0 if A < B, 33 | * 0 if A = B, 34 | * >0 if A > B 35 | * */ 36 | typedef int (*cmp_fn)(const void *a, const void *b); 37 | 38 | /** \} */ 39 | 40 | int cmp_s32_s32(const void *a, const void *b); 41 | 42 | bool is_set(u8 n, size_t sz, const void *set, cmp_fn cmp); 43 | bool is_sid_set(u8 n, const gnss_signal_t *sids); 44 | 45 | s32 intersection_map( 46 | u32 na, 47 | size_t sa, 48 | const void *as, 49 | u32 nb, 50 | size_t sb, 51 | const void *bs, 52 | cmp_fn cmp, 53 | void *context, 54 | void (*f)(void *context, u32 n, const void *a, const void *b)); 55 | 56 | s32 intersection(u32 na, 57 | size_t sa, 58 | const void *as, 59 | void *a_out, 60 | u32 nb, 61 | size_t sb, 62 | const void *bs, 63 | void *b_out, 64 | cmp_fn cmp); 65 | 66 | u32 insertion_index(u32 na, size_t sa, const void *as, void *b, cmp_fn cmp); 67 | u32 remove_element( 68 | u32 na, size_t sa, const void *as, void *a_out, void *b, cmp_fn cmp); 69 | u32 insert_element( 70 | u32 na, size_t sa, const void *as, void *a_out, void *b, cmp_fn cmp); 71 | 72 | #ifdef __cplusplus 73 | } /* extern "C" */ 74 | #endif /* __cplusplus */ 75 | 76 | #endif /* LIBSWIFTNAV_SET_H */ 77 | -------------------------------------------------------------------------------- /include/swiftnav/shm.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Swift Navigation Inc. 3 | * Contact: Swift Navigation 4 | * 5 | * This source is subject to the license found in the file 'LICENSE' which must 6 | * be distributed together with this source. All other rights reserved. 7 | * 8 | * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 9 | * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 10 | * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. 11 | */ 12 | 13 | #ifndef LIBSWIFTNAV_SHM_H_ 14 | #define LIBSWIFTNAV_SHM_H_ 15 | 16 | #include 17 | #include 18 | 19 | #ifdef __cplusplus 20 | extern "C" { 21 | #endif /* __cplusplus */ 22 | 23 | /** Table 20-VII. NAV Data Health Indications 24 | * https://www.gps.gov/technical/icwg/IS-GPS-200H.pdf 25 | */ 26 | typedef enum nav_data_health_indicator_e { 27 | NAV_DHI_OK = 0, 28 | NAV_DHI_PARITY_ERR = 1, 29 | NAV_DHI_TLM_HOW_ERR = 2, 30 | NAV_DHI_ZCOUNT_ERR = 3, 31 | NAV_DHI_SUB123_ERR = 4, 32 | NAV_DHI_SUB45_ERR = 5, 33 | NAV_DHI_UPDATA_ERR = 6, 34 | NAV_DHI_ALL_DATA_ERR = 7, 35 | NAV_DHI_COUNT = 8 36 | } nav_dhi_t; 37 | 38 | /* Possible SHM health states */ 39 | typedef enum { 40 | SHM_STATE_UNKNOWN, /* For signals without full support, e.g. GPS L5 */ 41 | SHM_STATE_UNHEALTHY, 42 | SHM_STATE_HEALTHY, 43 | } shm_state_t; 44 | 45 | /* GPS Satellite Health Indicators 46 | * Reference: IS-GPS-200D 47 | */ 48 | typedef struct { 49 | bool shi_ephemeris_set; /* LNAV EPHEMERIS SV HEALTH (SHI1 in SHM doc) 50 | 6 bits, subframe 1, word 3 */ 51 | u8 shi_ephemeris; 52 | 53 | bool shi_page25_set; /* LNAV PAGE#25 SV HEALTH (SHI3 in SHM doc) 54 | 6 bits, subframes 4 & 5, page 25 */ 55 | u8 shi_page25; 56 | u32 shi_page25_timetag_s; 57 | 58 | bool shi_lnav_how_alert_set; /* LNAV alert flag (SHI4 in SHM doc) 59 | HOW, bit 18 */ 60 | bool shi_lnav_how_alert; 61 | 62 | bool shi_cnav_alert_set; /* CNAV alert flag (SHI6 in SHM doc) 63 | bit 38, each message */ 64 | bool shi_cnav_alert; 65 | } gps_sat_health_indicators_t; 66 | 67 | /* GLO Satellite Health Indicator 68 | * Reference: GLO ICD 5.1. 69 | * This is (MSB of B || l). 70 | */ 71 | typedef struct { 72 | bool shi_set; /* SHI SV HEALTH */ 73 | u8 shi; 74 | } glo_sat_health_indicators_t; 75 | 76 | /* BDS Satellite Health Indicator */ 77 | typedef struct { 78 | bool shi_set; /* SHI SV HEALTH */ 79 | u8 shi; 80 | } bds_sat_health_indicators_t; 81 | 82 | /* GAL Satellite Health Indicator */ 83 | typedef struct { 84 | bool shi_set; /* SHI SV HEALTH */ 85 | u8 shi; 86 | } gal_sat_health_indicators_t; 87 | 88 | void shm_gps_decode_shi_ephemeris(u32 sf1w3, u8* shi_ephemeris); 89 | 90 | bool check_8bit_health_word(const u8 health_bits, const code_t code); 91 | bool check_alma_page25_health_word(const u8 health_bits, const code_t code); 92 | bool check_6bit_health_word(const u8 health_bits, const code_t code); 93 | bool check_nav_dhi(const u8 health_8bits, const u8 disabled_errors); 94 | 95 | #ifdef __cplusplus 96 | } /* extern "C" */ 97 | #endif /* __cplusplus */ 98 | 99 | #endif /* LIBSWIFTNAV_SHM_H_ */ 100 | -------------------------------------------------------------------------------- /include/swiftnav/sid_set.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Swift Navigation Inc. 3 | * Contact: Swift Navigation 4 | * 5 | * This source is subject to the license found in the file 'LICENSE' which must 6 | * be distributed together with this source. All other rights reserved. 7 | * 8 | * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 9 | * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 10 | * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. 11 | */ 12 | 13 | #ifndef LIBSWIFTNAV_SID_SET_H 14 | #define LIBSWIFTNAV_SID_SET_H 15 | 16 | #include 17 | #include 18 | 19 | #ifdef __cplusplus 20 | extern "C" { 21 | #endif 22 | 23 | typedef struct { 24 | u64 sats[CODE_COUNT]; 25 | } gnss_sid_set_t; 26 | 27 | void sid_set_init(gnss_sid_set_t *sid_set); 28 | void sid_set_add(gnss_sid_set_t *sid_set, gnss_signal_t sid); 29 | void sid_set_remove(gnss_sid_set_t *sid_set, gnss_signal_t sid); 30 | u32 sid_set_get_sat_count(const gnss_sid_set_t *sid_set); 31 | u32 sid_set_get_sig_count(const gnss_sid_set_t *sid_set); 32 | bool sid_set_contains(const gnss_sid_set_t *sid_set, gnss_signal_t sid); 33 | 34 | #ifdef __cplusplus 35 | } /* extern "C" */ 36 | #endif 37 | 38 | #endif /* LIBSWIFTNAV_SID_SET_H */ 39 | -------------------------------------------------------------------------------- /include/swiftnav/single_epoch_solver.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 Swift Navigation Inc. 3 | * Contact: Swift Navigation 4 | * 5 | * This source is subject to the license found in the file 'LICENSE' which must 6 | * be distributed together with this source. All other rights reserved. 7 | * 8 | * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 9 | * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 10 | * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. 11 | */ 12 | 13 | #ifndef LIBSWIFTNAV_PVT_H 14 | #define LIBSWIFTNAV_PVT_H 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #ifdef __cplusplus 23 | extern "C" { 24 | #endif 25 | 26 | #define MIN_SATS_FOR_PVT 5 27 | 28 | typedef struct { 29 | double pdop; 30 | double gdop; 31 | double tdop; 32 | double hdop; 33 | double vdop; 34 | } dops_t; 35 | 36 | extern const char *pvt_err_msg[7]; 37 | 38 | #define PVT_CONVERGED_NO_RAIM 2 39 | #define PVT_CONVERGED_RAIM_REPAIR 1 40 | #define PVT_CONVERGED_RAIM_OK 0 41 | #define PVT_PDOP_TOO_HIGH (-1) 42 | #define PVT_BAD_ALTITUDE (-2) 43 | #define PVT_VELOCITY_LOCKOUT (-3) 44 | #define PVT_RAIM_REPAIR_FAILED (-4) 45 | #define PVT_RAIM_REPAIR_IMPOSSIBLE (-5) 46 | #define PVT_UNCONVERGED (-6) 47 | #define PVT_INSUFFICENT_MEAS (-7) 48 | 49 | enum processing_strategy_t { 50 | GPS_ONLY, 51 | ALL_CONSTELLATIONS, 52 | GPS_L1CA_WHEN_POSSIBLE, 53 | L1_ONLY 54 | }; 55 | 56 | typedef struct { 57 | /* 58 | * Be careful of stuct packing to avoid (very mild) slowness, 59 | * try to keep all the types aligned i.e. put the 64bit 60 | * things together at the top, then the 32bit ones etc. 61 | */ 62 | /** Receiver position latitude [deg], longitude [deg], altitude [m] */ 63 | double pos_llh[3]; 64 | /** Receiver position ECEF XYZ [m] */ 65 | double pos_ecef[3]; 66 | /** Receiver velocity in NED [m/s] */ 67 | double vel_ned[3]; 68 | /** Receiver velocity in ECEF XYZ [m/s] */ 69 | double vel_ecef[3]; 70 | 71 | /* This is the row-first upper diagonal matrix of error covariances 72 | * in x, y, z (all receiver clock covariance terms are ignored). So 73 | * it goes like so: 74 | * 75 | * 0 1 2 76 | * _ 3 4 77 | * _ _ 5 78 | * 79 | * Index 6 is the GDOP. 80 | */ 81 | double err_cov[7]; 82 | 83 | /* Upper diagonal of the covariances of the velocity solution, similarly 84 | * as above, but without the DOP element. 85 | */ 86 | double vel_cov[7]; 87 | 88 | double clock_offset; 89 | double clock_offset_var; 90 | double clock_drift; 91 | double clock_drift_var; 92 | 93 | /* GPS time */ 94 | gps_time_t time; 95 | 96 | /* 0 = invalid, 1 = code phase */ 97 | u8 valid; 98 | /* 0 = invalid, 1 = doppler */ 99 | u8 velocity_valid; 100 | /* Number of satellites used in the solution. */ 101 | u8 n_sats_used; 102 | /* Number of signals used in the solution. */ 103 | u8 n_sigs_used; 104 | } gnss_solution; 105 | 106 | typedef struct { 107 | bool enable; 108 | float threshold_dbhz; 109 | } cn0_mask_t; 110 | 111 | typedef struct { 112 | cn0_mask_t cn0_mask; 113 | } obs_mask_config_t; 114 | 115 | s8 calc_PVT(const u8 n_used, 116 | const navigation_measurement_t nav_meas[], 117 | const gps_time_t *tor, 118 | const bool disable_raim, 119 | const bool disable_velocity, 120 | const obs_mask_config_t *obs_mask_config, 121 | enum processing_strategy_t strategy, 122 | gnss_solution *soln, 123 | dops_t *dops, 124 | gnss_sid_set_t *raim_removed_sids); 125 | 126 | typedef bool (*sat_sel_predicate)(gnss_signal_t sid, 127 | gnss_sid_set_t sids_used, 128 | u8 n_states); 129 | 130 | s8 calc_PVT_pred(const u8 n_meas, 131 | const navigation_measurement_t nav_meas[], 132 | const gps_time_t *tor, 133 | const bool disable_raim, 134 | const bool disable_velocity, 135 | const obs_mask_config_t *obs_mask_config, 136 | sat_sel_predicate pred, 137 | gnss_solution *soln, 138 | dops_t *dops, 139 | gnss_sid_set_t *raim_removed_sids); 140 | 141 | u8 get_max_channels(void); 142 | 143 | #ifdef __cplusplus 144 | } /* extern "C" */ 145 | #endif 146 | 147 | #endif /* LIBSWIFTNAV_PVT_H */ 148 | -------------------------------------------------------------------------------- /include/swiftnav/subsystem_status_report.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2022 Swift Navigation Inc. 3 | * Contact: Swift Navigation 4 | * 5 | * This source is subject to the license found in the file 'LICENSE' which must 6 | * distributed together with this source. All other rights reserved. 7 | * 8 | * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 9 | * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 10 | * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. 11 | */ 12 | 13 | #ifndef LIBSWIFTNAV_SUBSYSTEM_STATUS_REPORT_H 14 | #define LIBSWIFTNAV_SUBSYSTEM_STATUS_REPORT_H 15 | 16 | #include 17 | #include 18 | 19 | #ifdef __cplusplus 20 | extern "C" { 21 | #endif 22 | 23 | typedef void (*pfn_subsystem_status_report)(uint16_t component, 24 | uint8_t generic, 25 | uint8_t specific, 26 | void* context); 27 | 28 | /** 29 | * Struct used by the "swiftnav_subsystem_status_report_callback_register" to 30 | * register a callback function along with context object to be invoked whenever 31 | * someone invokes "swiftnav_send_subsystem_status_report" from anywhere. Struct 32 | * should not be modified by the user and should be treated as an opaque type. 33 | */ 34 | typedef struct swiftnav_subsystem_status_report_callback_node { 35 | pfn_subsystem_status_report callback; 36 | void* context; 37 | struct swiftnav_subsystem_status_report_callback_node* next; 38 | } swiftnav_subsystem_status_report_callback_node_t; 39 | 40 | /** 41 | * Specifies the callback function to invoke when a user calls the 42 | * "swiftnav_send_subsystem_status_report" function. 43 | * 44 | * @param callback_node pointer to opaque struct which user should pass to the 45 | * function in order for it to register the subsequent callback function and 46 | * context object 47 | * @param callback callback function to register, if the value is NULL the 48 | * function will deregister prior callback 49 | * @param context context object which will be passed to the callback function 50 | * when invoked 51 | */ 52 | void swiftnav_subsystem_status_report_callback_register( 53 | swiftnav_subsystem_status_report_callback_node_t* callback_node, 54 | pfn_subsystem_status_report callback, 55 | void* context); 56 | 57 | /** 58 | * De-registers the previously registered callback node. 59 | * 60 | * @param callback_node pointer to opaque struct which user's have previously 61 | * passed into the "swiftnav_subsystem_status_report_callback_register" 62 | * function. 63 | * 64 | * @see swiftnav_subsystem_status_report_callback_register 65 | */ 66 | void swiftnav_subsystem_status_report_callback_deregister( 67 | swiftnav_subsystem_status_report_callback_node_t* callback_node); 68 | 69 | /** 70 | * De-registers all prior registered callbacks. 71 | * 72 | * @see swiftnav_subsystem_status_report_callback_register 73 | */ 74 | void swiftnav_subsystem_status_report_callback_reset(void); 75 | 76 | /** 77 | * Invoking this function will indirectly call the registered callback function 78 | * specified via "swiftnav_subsystem_status_report_callback_register". 79 | * 80 | * @param component identity of reporting subsystem 81 | * @param generic generic form status report 82 | * @param specific subsystem specific status code 83 | */ 84 | void swiftnav_send_subsystem_status_report(uint16_t component, 85 | uint8_t generic, 86 | uint8_t specific); 87 | 88 | #ifdef __cplusplus 89 | } 90 | #endif 91 | 92 | #endif // LIBSWIFTNAV_SUBSYSTEM_STATUS_REPORT_H 93 | -------------------------------------------------------------------------------- /include/swiftnav/swift_strnlen.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBSWIFTNAV_STRNLEN_H 2 | #define LIBSWIFTNAV_STRNLEN_H 3 | 4 | #include 5 | 6 | static inline size_t swift_strnlen(const char *str, size_t max) { 7 | size_t len = 0; 8 | while (len < max && str[len] != 0) { 9 | len++; 10 | } 11 | return len; 12 | } 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /include/swiftnav/troposphere.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Swift Navigation Inc. 3 | * Contact: Swift Navigation 4 | * 5 | * This source is subject to the license found in the file 'LICENSE' which must 6 | * be distributed together with this source. All other rights reserved. 7 | * 8 | * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 9 | * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 10 | * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. 11 | */ 12 | 13 | #ifndef LIBSWIFTNAV_TROPOSPHERE_H 14 | #define LIBSWIFTNAV_TROPOSPHERE_H 15 | 16 | #include 17 | 18 | #ifdef __cplusplus 19 | extern "C" { 20 | #endif /* __cplusplus */ 21 | 22 | /* tropo correction is not applicable above max altitude */ 23 | /* value is 11km which is the top of the troposphere according to ICAO's 24 | * International Standard Atmosphere. */ 25 | #define MAX_ALTITUDE 11e3 26 | 27 | /* truncate satellite elevations near or below zero [deg] */ 28 | #define MIN_SAT_ELEVATION 0.1 29 | 30 | double calc_troposphere(const double doy, double lat, double h, double el); 31 | 32 | #ifdef __cplusplus 33 | } /* extern "C" */ 34 | #endif /* __cplusplus */ 35 | 36 | #endif /* LIBSWIFTNAV_TROPOSPHERE_H */ 37 | -------------------------------------------------------------------------------- /scripts/gtx_convert.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | # 3 | # Load a VDatum grid file and output two files containing C-style arrays named 4 | # GEOID: 5 | # 6 | # 1. geoid_model_1_degree.inc: Downsampled geoid data (1 x 1 degree gid) 7 | # 2. geoid_model_15_minute.inc: Full resolution geoid data (0.25 x 0.25 degree grid) 8 | # 9 | # See https://vdatum.noaa.gov/docs/gtx_info.html#dev_gtx_binary for details 10 | # of the VDatum file format. 11 | # 12 | # (C) 2020 Swift Navigation 13 | # 14 | 15 | use strict; 16 | 17 | # file names 18 | use constant INPUT_DATA => "egm08_25.gtx"; 19 | use constant OUTPUT_LO_RES => "geoid_model_1_degree.inc"; 20 | use constant OUTPUT_HI_RES => "geoid_model_15_minute.inc"; 21 | 22 | # boundaries 23 | use constant MIN_LON => 0; 24 | use constant MAX_LON => 360; 25 | use constant MIN_LAT => -90; 26 | use constant MAX_LAT => 90; 27 | 28 | 29 | # hash contains height values in metres keyed with "$lat,$lon" 30 | # (so that we can perform random lookups) 31 | my %heights; 32 | 33 | 34 | # read data from '$infile', store data in %heights 35 | sub read_file($) { 36 | my $infile = shift || die; 37 | 38 | open(FILE, "<$infile") || die "Cannot open $infile for reading"; 39 | binmode FILE; 40 | 41 | sub read_uint32() { 42 | die if((read FILE, my $data, 4) != 4); 43 | return unpack("L>", $data); 44 | } 45 | 46 | sub read_double() { 47 | die if((read FILE, my $data, 8) != 8); 48 | return unpack("d>", $data); 49 | } 50 | 51 | sub read_float() { 52 | die if((read FILE, my $data, 4) != 4); 53 | return unpack("f>", $data); 54 | } 55 | 56 | # compare 2 floats to 7 decimal places 57 | sub float_cmp($$) { 58 | return sprintf("%.7f", $_[0]) eq sprintf("%.7f", $_[1]); 59 | } 60 | 61 | # parse header 62 | my $start_lat = read_double(); 63 | my $start_lon = read_double(); 64 | my $delta_lat = read_double(); 65 | my $delta_lon = read_double(); 66 | my $nrows = read_uint32(); 67 | my $ncols = read_uint32(); 68 | 69 | my $end_lat = $start_lat + ($nrows-1) * $delta_lat; 70 | my $end_lon = $start_lon + ($ncols-1) * $delta_lon; 71 | 72 | # sanity checks 73 | die unless float_cmp($start_lat, -90); 74 | die unless float_cmp($start_lon, -180); 75 | die unless float_cmp($end_lat, 90); 76 | die unless float_cmp($end_lon + $delta_lon, 180); 77 | 78 | # read height data 79 | for my $row (0..$nrows-1) { 80 | for my $col (0..$ncols-1) { 81 | my $lat = $start_lat + $row * $delta_lat; 82 | my $lon = $start_lon + $col * $delta_lon; 83 | $lon += 360 if($lon < 0); 84 | $heights{"$lat,$lon"} = read_float(); 85 | } 86 | } 87 | 88 | close FILE; 89 | } 90 | 91 | 92 | # return height value for '$lat'/'$lon' (in metres) 93 | sub get_height($$) { 94 | my($lat, $lon) = @_; 95 | 96 | my $height = $heights{"$lat,$lon"}; 97 | die "$lat/$lon" unless defined($height); 98 | return $height; 99 | } 100 | 101 | 102 | # write geoid data with '$spacing' (in degrees) to '$outfile' 103 | sub write_geoid_file($$) { 104 | my($outfile, $spacing) = @_; 105 | 106 | open(FILE, ">$outfile") || die "Cannot open $outfile for writing"; 107 | 108 | my $rows = (MAX_LON - MIN_LON) / $spacing + 1; 109 | my $cols = (MAX_LAT - MIN_LAT) / $spacing + 1; 110 | 111 | # write header 112 | print FILE < 18 | * 19 | * This source is subject to the license found in the file 'LICENSE' which must 20 | * distributed together with this source. All other rights reserved. 21 | * 22 | * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 23 | * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 24 | * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. 25 | */ 26 | 27 | /****************************************************************************** 28 | * Automatically generated from scripts/leap_seconds_generator.py. Please do * 29 | * not hand edit! * 30 | * * 31 | * Updated: {{now.to_date_string()}} * 32 | ******************************************************************************/ 33 | 34 | #ifndef LIBSWIFTNAV_LEAP_SECONDS_H 35 | #define LIBSWIFTNAV_LEAP_SECONDS_H 36 | 37 | #include 38 | 39 | #ifdef __cplusplus 40 | extern "C" { 41 | #endif 42 | 43 | /** 44 | * Start times of UTC leap second events given in GPS time {wn, tow, gps-utc} 45 | * The leap second event lasts for one second from the start time, and after 46 | * that the new offset is in effect. 47 | */ 48 | static const s32 utc_leaps[][3] = { 49 | {% for utc_leap_item in utc_leap_list %} 50 | {%- if utc_leap_item.to_gps_clock().seconds_since_epoch() >= 0 -%} 51 | { {{utc_leap_item.to_gps_clock().offset_seconds(-1).wn()}}, {{utc_leap_item.to_gps_clock().offset_seconds(-1).tow()}}, {{utc_leap_item.tai_utc_offset() - TAI_GPS_OFFSET}} }, /* {{utc_leap_item.to_date_string()}} */ 52 | {% endif %} 53 | {%- endfor -%} 54 | }; 55 | 56 | /** GPS time when the utc_leaps table expires {{utc_leap_list_expires.to_date_string()}} */ 57 | static const s32 gps_time_utc_leaps_expiry[2] = { {{utc_leap_list_expires.to_gps_clock().wn()}}, {{utc_leap_list_expires.to_gps_clock().tow()}} }; 58 | 59 | /** UNIX time when the utc_leaps table expires {{utc_leap_list_expires.to_date_string()}} */ 60 | static const s64 unix_time_utc_leaps_expiry = {{utc_leap_list_expires.to_unix_clock().seconds_since_epoch()}}; 61 | 62 | #ifdef __cplusplus 63 | } 64 | #endif 65 | 66 | #endif // LIBSWIFTNAV_LEAP_SECONDS_H 67 | 68 | """ 69 | 70 | 71 | class UtcClock: 72 | def __init__(self, utc_time, tai_utc_offset): 73 | self._utc_time = utc_time 74 | self._tai_utc_offset = tai_utc_offset 75 | 76 | def utc_time(self): 77 | return self._utc_time 78 | 79 | def tai_utc_offset(self): 80 | return self._tai_utc_offset 81 | 82 | def to_gps_clock(self): 83 | return GpsClock( 84 | self._utc_time + self._tai_utc_offset - (GPS_EPOCH - UTC_EPOCH).total_seconds() - TAI_GPS_OFFSET) 85 | 86 | def to_unix_clock(self): 87 | return UnixClock( 88 | self._utc_time + self._tai_utc_offset - (UNIX_EPOCH - UTC_EPOCH).total_seconds() - TAI_UNIX_OFFSET) 89 | 90 | def to_date_string(self): 91 | date = UTC_EPOCH + datetime.timedelta(0, self._utc_time) 92 | return DATE_TIME_FORMAT.format(**{"day": date.day, "month": date.month, "year": date.year}) 93 | 94 | 95 | class GpsClock: 96 | def __init__(self, gps_time): 97 | self._gps_time = gps_time 98 | 99 | def wn(self): 100 | return int(self._gps_time / 604800) 101 | 102 | def tow(self): 103 | return int(self._gps_time % 604800) 104 | 105 | def seconds_since_epoch(self): 106 | return int(self._gps_time) 107 | 108 | def offset_seconds(self, seconds): 109 | return GpsClock(self._gps_time + seconds) 110 | 111 | 112 | class UnixClock: 113 | def __init__(self, unix_time): 114 | self._unix_time = unix_time 115 | 116 | def seconds_since_epoch(self): 117 | return int(self._unix_time) 118 | 119 | def offset_seconds(self, seconds): 120 | return UnixClock(self._unix_time + seconds) 121 | 122 | 123 | if len(sys.argv) != 2: 124 | print("error: usage
", file=sys.stderr) 125 | exit(1) 126 | 127 | utc_leap_list = [] 128 | utc_leap_list_expires_utc_time = None 129 | 130 | with urllib.request.urlopen("https://www.ietf.org/timezones/data/leap-seconds.list") as response: 131 | response_content = response.read() 132 | for line in response_content.decode("utf-8").splitlines(): 133 | is_comment = line.startswith("#") 134 | is_comment_expiry_time = line.startswith("#@") 135 | 136 | if is_comment and not is_comment_expiry_time: 137 | continue 138 | 139 | entries = line.split() 140 | 141 | if is_comment_expiry_time: 142 | utc_leap_list_expires_utc_time = int(entries[1]) 143 | else: 144 | utc_leap_list.append(UtcClock(int(entries[0]), int(entries[1]))) 145 | 146 | utc_leap_list_expires = UtcClock(utc_leap_list_expires_utc_time, utc_leap_list[-1].tai_utc_offset()) 147 | now = UtcClock((datetime.datetime.utcnow() - UTC_EPOCH).total_seconds(), utc_leap_list[-1].tai_utc_offset()) 148 | 149 | gnss_time_latest_template = jinja2.Template(JINJA_GNSS_TIME_LATEST_TEMPLATE) 150 | gnss_time_latest_render = gnss_time_latest_template.render({ 151 | "now": now, 152 | "utc_leap_list": utc_leap_list, 153 | "utc_leap_list_expires": utc_leap_list_expires, 154 | "TAI_GPS_OFFSET": TAI_GPS_OFFSET, 155 | }) 156 | 157 | with open(sys.argv[1], "w") as file: 158 | file.write(gnss_time_latest_render) 159 | -------------------------------------------------------------------------------- /scripts/requirements.txt: -------------------------------------------------------------------------------- 1 | Jinja2==3.0.3 2 | -------------------------------------------------------------------------------- /src/edc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 Swift Navigation Inc. 3 | * Contact: Swift Navigation 4 | * 5 | * This source is subject to the license found in the file 'LICENSE' which must 6 | * be distributed together with this source. All other rights reserved. 7 | * 8 | * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 9 | * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 10 | * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. 11 | */ 12 | 13 | #include 14 | 15 | /** \defgroup edc Error Detection and Correction 16 | * Error detection and correction functions. 17 | * \{ */ 18 | 19 | /** \defgroup crc CRC 20 | * Cyclic redundancy checks. 21 | * \{ */ 22 | 23 | static const u32 crc24qtab[256] = { 24 | 0x000000, 0x864CFB, 0x8AD50D, 0x0C99F6, 0x93E6E1, 0x15AA1A, 0x1933EC, 25 | 0x9F7F17, 0xA18139, 0x27CDC2, 0x2B5434, 0xAD18CF, 0x3267D8, 0xB42B23, 26 | 0xB8B2D5, 0x3EFE2E, 0xC54E89, 0x430272, 0x4F9B84, 0xC9D77F, 0x56A868, 27 | 0xD0E493, 0xDC7D65, 0x5A319E, 0x64CFB0, 0xE2834B, 0xEE1ABD, 0x685646, 28 | 0xF72951, 0x7165AA, 0x7DFC5C, 0xFBB0A7, 0x0CD1E9, 0x8A9D12, 0x8604E4, 29 | 0x00481F, 0x9F3708, 0x197BF3, 0x15E205, 0x93AEFE, 0xAD50D0, 0x2B1C2B, 30 | 0x2785DD, 0xA1C926, 0x3EB631, 0xB8FACA, 0xB4633C, 0x322FC7, 0xC99F60, 31 | 0x4FD39B, 0x434A6D, 0xC50696, 0x5A7981, 0xDC357A, 0xD0AC8C, 0x56E077, 32 | 0x681E59, 0xEE52A2, 0xE2CB54, 0x6487AF, 0xFBF8B8, 0x7DB443, 0x712DB5, 33 | 0xF7614E, 0x19A3D2, 0x9FEF29, 0x9376DF, 0x153A24, 0x8A4533, 0x0C09C8, 34 | 0x00903E, 0x86DCC5, 0xB822EB, 0x3E6E10, 0x32F7E6, 0xB4BB1D, 0x2BC40A, 35 | 0xAD88F1, 0xA11107, 0x275DFC, 0xDCED5B, 0x5AA1A0, 0x563856, 0xD074AD, 36 | 0x4F0BBA, 0xC94741, 0xC5DEB7, 0x43924C, 0x7D6C62, 0xFB2099, 0xF7B96F, 37 | 0x71F594, 0xEE8A83, 0x68C678, 0x645F8E, 0xE21375, 0x15723B, 0x933EC0, 38 | 0x9FA736, 0x19EBCD, 0x8694DA, 0x00D821, 0x0C41D7, 0x8A0D2C, 0xB4F302, 39 | 0x32BFF9, 0x3E260F, 0xB86AF4, 0x2715E3, 0xA15918, 0xADC0EE, 0x2B8C15, 40 | 0xD03CB2, 0x567049, 0x5AE9BF, 0xDCA544, 0x43DA53, 0xC596A8, 0xC90F5E, 41 | 0x4F43A5, 0x71BD8B, 0xF7F170, 0xFB6886, 0x7D247D, 0xE25B6A, 0x641791, 42 | 0x688E67, 0xEEC29C, 0x3347A4, 0xB50B5F, 0xB992A9, 0x3FDE52, 0xA0A145, 43 | 0x26EDBE, 0x2A7448, 0xAC38B3, 0x92C69D, 0x148A66, 0x181390, 0x9E5F6B, 44 | 0x01207C, 0x876C87, 0x8BF571, 0x0DB98A, 0xF6092D, 0x7045D6, 0x7CDC20, 45 | 0xFA90DB, 0x65EFCC, 0xE3A337, 0xEF3AC1, 0x69763A, 0x578814, 0xD1C4EF, 46 | 0xDD5D19, 0x5B11E2, 0xC46EF5, 0x42220E, 0x4EBBF8, 0xC8F703, 0x3F964D, 47 | 0xB9DAB6, 0xB54340, 0x330FBB, 0xAC70AC, 0x2A3C57, 0x26A5A1, 0xA0E95A, 48 | 0x9E1774, 0x185B8F, 0x14C279, 0x928E82, 0x0DF195, 0x8BBD6E, 0x872498, 49 | 0x016863, 0xFAD8C4, 0x7C943F, 0x700DC9, 0xF64132, 0x693E25, 0xEF72DE, 50 | 0xE3EB28, 0x65A7D3, 0x5B59FD, 0xDD1506, 0xD18CF0, 0x57C00B, 0xC8BF1C, 51 | 0x4EF3E7, 0x426A11, 0xC426EA, 0x2AE476, 0xACA88D, 0xA0317B, 0x267D80, 52 | 0xB90297, 0x3F4E6C, 0x33D79A, 0xB59B61, 0x8B654F, 0x0D29B4, 0x01B042, 53 | 0x87FCB9, 0x1883AE, 0x9ECF55, 0x9256A3, 0x141A58, 0xEFAAFF, 0x69E604, 54 | 0x657FF2, 0xE33309, 0x7C4C1E, 0xFA00E5, 0xF69913, 0x70D5E8, 0x4E2BC6, 55 | 0xC8673D, 0xC4FECB, 0x42B230, 0xDDCD27, 0x5B81DC, 0x57182A, 0xD154D1, 56 | 0x26359F, 0xA07964, 0xACE092, 0x2AAC69, 0xB5D37E, 0x339F85, 0x3F0673, 57 | 0xB94A88, 0x87B4A6, 0x01F85D, 0x0D61AB, 0x8B2D50, 0x145247, 0x921EBC, 58 | 0x9E874A, 0x18CBB1, 0xE37B16, 0x6537ED, 0x69AE1B, 0xEFE2E0, 0x709DF7, 59 | 0xF6D10C, 0xFA48FA, 0x7C0401, 0x42FA2F, 0xC4B6D4, 0xC82F22, 0x4E63D9, 60 | 0xD11CCE, 0x575035, 0x5BC9C3, 0xDD8538}; 61 | 62 | /** Calculate Qualcomm 24-bit Cyclical Redundancy Check (CRC-24Q). 63 | * 64 | * The CRC polynomial used is: 65 | * \f[ 66 | * x^{24} + x^{23} + x^{18} + x^{17} + x^{14} + x^{11} + x^{10} + 67 | * x^7 + x^6 + x^5 + x^4 + x^3 + x+1 68 | * \f] 69 | * Mask 0x1864CFB, not reversed, not XOR'd 70 | * 71 | * \param buf Array of data to calculate CRC for 72 | * \param len Length of data array 73 | * \param crc Initial CRC value 74 | * 75 | * \return CRC-24Q value 76 | */ 77 | u32 crc24q(const u8 *buf, u32 len, u32 crc) { 78 | for (u32 i = 0; i < len; i++) { 79 | crc = ((crc << 8) & 0xFFFFFF) ^ crc24qtab[((crc >> 16) ^ buf[i]) & 0xff]; 80 | } 81 | return crc; 82 | } 83 | 84 | /** 85 | * Computes CRC-24Q for left-aligned bit message. 86 | * This function is used for left-aligned bit messages, for example SBAS and 87 | * GPS CNAV. 88 | * GPS message is 300 bits total, but 276 bits without CRC. It takes 34.5 89 | * 8-bit bytes, and when computing CRC the message has to be padded with zero 90 | * bits. 91 | * 92 | * \param[in] crc Initial CRC value 93 | * \param[in] buf Pointer to MSB-aligned data. 94 | * \param[in] n_bits Number of bits in the data buffer. 95 | * \param[in] invert Flag to compute inverted CRC. 96 | * 97 | * \return CRC-24Q value 98 | */ 99 | u32 crc24q_bits(u32 crc, const u8 *buf, u32 n_bits, bool invert) { 100 | u16 acc = 0; 101 | u8 b = 0; 102 | u32 shift = 8 - n_bits % 8; 103 | 104 | for (u32 i = 0; i < n_bits / 8; ++i) { 105 | acc = (acc << 8) | *buf++; 106 | if (invert) { 107 | acc ^= 0xFFu; 108 | } 109 | b = (acc >> shift) & 0xFFu; 110 | crc = ((crc << 8) & 0xFFFFFFu) ^ crc24qtab[((crc >> 16) ^ b) & 0xFFu]; 111 | } 112 | acc = (acc << 8) | *buf; 113 | if (invert) { 114 | acc ^= 0xFFu; 115 | } 116 | b = (acc >> shift) & 0xFFu; 117 | crc = ((crc << 8) & 0xFFFFFFu) ^ crc24qtab[((crc >> 16) ^ b) & 0xFFu]; 118 | 119 | return crc; 120 | } 121 | 122 | /** \} */ 123 | 124 | /** \} */ 125 | -------------------------------------------------------------------------------- /src/fifo_byte.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Swift Navigation Inc. 3 | * Contact: Swift Navigation 4 | * 5 | * This source is subject to the license found in the file 'LICENSE' which must 6 | * be be distributed together with this source. All other rights reserved. 7 | * 8 | * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 9 | * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 10 | * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. 11 | */ 12 | 13 | /* TODO: MAP-532 add units tests */ 14 | #include 15 | #include 16 | #include 17 | 18 | #define INDEX_MASK(p_fifo) ((p_fifo)->buffer_size - 1) 19 | #define LENGTH(p_fifo) \ 20 | ((fifo_size_t)((p_fifo)->write_index - (p_fifo)->read_index)) 21 | #define SPACE(p_fifo) ((fifo_size_t)((p_fifo)->buffer_size - LENGTH(p_fifo))) 22 | #define MIN(x, y) (((x) < (y)) ? (x) : (y)) 23 | 24 | /* 25 | * This file implements a lock-free single-producer, single-consumer FIFO 26 | * using a circular buffer. 27 | */ 28 | 29 | /** Initialize a FIFO. 30 | * 31 | * \param fifo fifo_t struct to use. 32 | * \param buffer Buffer to use for the FIFO data. Must remain valid 33 | * while the FIFO is in use. 34 | * \param buffer_size Size of buffer. Must be a power of two. 35 | */ 36 | void fifo_init(fifo_t *fifo, uint8_t *buffer, fifo_size_t buffer_size) { 37 | /* Require buffer_size to be a power of two */ 38 | assert((buffer_size & (buffer_size - 1)) == 0); 39 | 40 | fifo->read_index = 0; 41 | fifo->write_index = 0; 42 | fifo->buffer_size = buffer_size; 43 | fifo->buffer = buffer; 44 | } 45 | 46 | /** Get the length for a FIFO. 47 | * 48 | * \note If called from the consumer thread, the length is a lower bound. 49 | * If called from the producer thread, the length is an upper bound. 50 | * 51 | * \param fifo fifo_t struct to use. 52 | * 53 | * \return Number of bytes that may be read from the FIFO. 54 | */ 55 | fifo_size_t fifo_length(fifo_t *fifo) { return LENGTH(fifo); } 56 | 57 | /** Get the space for a FIFO. 58 | * 59 | * \note If called from the consumer thread, the space is an upper bound. 60 | * If called from the producer thread, the space is a lower bound. 61 | * 62 | * \param fifo fifo_t struct to use. 63 | * 64 | * \return Number of bytes that may be written to the FIFO. 65 | */ 66 | fifo_size_t fifo_space(fifo_t *fifo) { return SPACE(fifo); } 67 | 68 | /** Read data from a FIFO. 69 | * 70 | * \note This function should only be called from a single consumer thread. 71 | * 72 | * \param fifo fifo_t struct to use. 73 | * \param buffer Output buffer. 74 | * \param length Maximum number of bytes to read. 75 | * 76 | * \return Number of bytes read from the FIFO. 77 | */ 78 | fifo_size_t fifo_read(fifo_t *fifo, uint8_t *buffer, fifo_size_t length) { 79 | fifo_size_t read_length = fifo_peek(fifo, buffer, length); 80 | 81 | if (read_length > 0) { 82 | read_length = fifo_remove(fifo, read_length); 83 | } 84 | 85 | return read_length; 86 | } 87 | 88 | /** Read data from a FIFO without removing it. 89 | * 90 | * \note This function should only be called from a single consumer thread. 91 | * 92 | * \param fifo fifo_t struct to use. 93 | * \param buffer Output buffer. 94 | * \param length Maximum number of bytes to read. 95 | * 96 | * \return Number of bytes read from the FIFO. 97 | */ 98 | fifo_size_t fifo_peek(fifo_t *fifo, uint8_t *buffer, fifo_size_t length) { 99 | /* Atomic read of write_index to get fifo_length */ 100 | fifo_size_t fifo_length = LENGTH(fifo); 101 | 102 | fifo_size_t read_length = MIN(length, fifo_length); 103 | if (read_length > 0) { 104 | fifo_size_t read_index_masked = fifo->read_index & INDEX_MASK(fifo); 105 | if (read_index_masked + read_length <= fifo->buffer_size) { 106 | /* One contiguous block */ 107 | memcpy(buffer, &fifo->buffer[read_index_masked], read_length); 108 | } else { 109 | /* Two contiguous blocks */ 110 | fifo_size_t copy_len_a = fifo->buffer_size - read_index_masked; 111 | memcpy(buffer, &fifo->buffer[read_index_masked], copy_len_a); 112 | memcpy(&buffer[copy_len_a], fifo->buffer, read_length - copy_len_a); 113 | } 114 | } 115 | 116 | return read_length; 117 | } 118 | 119 | /** Remove data from a FIFO. 120 | * 121 | * \note This function should only be called from a single consumer thread. 122 | * 123 | * \param fifo fifo_t struct to use. 124 | * \param length Maximum number of bytes to remove. 125 | * 126 | * \return Number of bytes removed from the FIFO. 127 | */ 128 | fifo_size_t fifo_remove(fifo_t *fifo, fifo_size_t length) { 129 | /* Atomic read of write_index to get fifo_length */ 130 | fifo_size_t fifo_length = LENGTH(fifo); 131 | 132 | fifo_size_t read_length = MIN(length, fifo_length); 133 | if (read_length > 0) { 134 | /* Atomic write of read_index */ 135 | fifo->read_index += read_length; 136 | } 137 | 138 | return read_length; 139 | } 140 | 141 | /** Write data to a FIFO. 142 | * 143 | * \note This function should only be called from a single producer thread. 144 | * 145 | * \param fifo fifo_t struct to use. 146 | * \param buffer Input buffer. 147 | * \param length Maximum number of bytes to write. 148 | * 149 | * \return Number of bytes written to the FIFO. 150 | */ 151 | fifo_size_t fifo_write(fifo_t *fifo, 152 | const uint8_t *buffer, 153 | fifo_size_t length) { 154 | /* Atomic read of read_index to get fifo_space */ 155 | fifo_size_t fifo_space = SPACE(fifo); 156 | 157 | fifo_size_t write_length = MIN(length, fifo_space); 158 | if (write_length > 0) { 159 | fifo_size_t write_index_masked = fifo->write_index & INDEX_MASK(fifo); 160 | if (write_index_masked + write_length <= fifo->buffer_size) { 161 | /* One contiguous block */ 162 | memcpy(&fifo->buffer[write_index_masked], buffer, write_length); 163 | } else { 164 | /* Tow contiguous blocks */ 165 | fifo_size_t copy_len_a = fifo->buffer_size - write_index_masked; 166 | memcpy(&fifo->buffer[write_index_masked], buffer, copy_len_a); 167 | memcpy(fifo->buffer, &buffer[copy_len_a], write_length - copy_len_a); 168 | } 169 | 170 | /* Atomic write of write_index */ 171 | fifo->write_index += write_length; 172 | } 173 | 174 | return write_length; 175 | } 176 | -------------------------------------------------------------------------------- /src/glo_map.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Swift Navigation Inc. 3 | * Contact: Swift Navigation 4 | * 5 | * This source is subject to the license found in the file 'LICENSE' which must 6 | * be distributed together with this source. All other rights reserved. 7 | * 8 | * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 9 | * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 10 | * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. 11 | */ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #define NUM_GLO_MAP_INDICES (NUM_SATS_GLO + 1) 20 | 21 | /* GLO to FCN look up table, index 0 unused, index 1 -- SV 1, index 28 -- SV 28 22 | */ 23 | static u8 glo_sv_id_fcn_map[NUM_GLO_MAP_INDICES] = {GLO_FCN_UNKNOWN}; 24 | static void (*lock)(void) = NULL; 25 | static void (*unlock)(void) = NULL; 26 | 27 | /** Locks glo_sv_id_fcn_map for multithread access */ 28 | static void glo_map_lock(void) { 29 | if (lock) { 30 | lock(); 31 | } 32 | } 33 | 34 | /** Unlocks glo_sv_id_fcn_map for multithread access */ 35 | static void glo_map_unlock(void) { 36 | if (unlock) { 37 | unlock(); 38 | } 39 | } 40 | 41 | /** Init GLO map 42 | * @param lock_cb Callback function for mutual exclusion locking 43 | * @param unlock_cb Callback function for mutual exclusion unlocking 44 | */ 45 | void glo_map_init(void (*lock_cb)(void), void (*unlock_cb)(void)) { 46 | lock = lock_cb; 47 | unlock = unlock_cb; 48 | } 49 | 50 | /** GLO map validity predicate. 51 | * @param sid Signal identifier 52 | * @retval true The mapping is valid 53 | * @retval false The mapping is invalid 54 | */ 55 | bool glo_map_valid(const gnss_signal_t sid) { 56 | assert(IS_GLO(sid)); 57 | assert(glo_slot_id_is_valid(sid.sat)); 58 | 59 | u16 fcn = (u16)glo_sv_id_fcn_map[sid.sat]; 60 | bool valid = (fcn != GLO_FCN_UNKNOWN); 61 | 62 | return valid; 63 | } 64 | 65 | /** The function maps GLO orbital slot and frequency slot 66 | * 67 | * @param[in] fcn GLO FCN 68 | * @param[in] glo_slot_id GLO orbital slot 69 | */ 70 | void glo_map_set_slot_id(u16 fcn, u16 glo_slot_id) { 71 | if (!glo_slot_id_is_valid(glo_slot_id) || !glo_fcn_is_valid(fcn)) { 72 | log_debug("GLO PRN %" PRIu16 " or frequency slot %" PRIu16 73 | " is out of range, ignoring", 74 | glo_slot_id, 75 | fcn); 76 | return; 77 | } 78 | 79 | glo_map_lock(); 80 | glo_sv_id_fcn_map[glo_slot_id] = fcn; 81 | glo_map_unlock(); 82 | } 83 | 84 | /** The function returns GLO frequency slot corresponds to the GLO SV ID 85 | * 86 | * @param[in] sid Signal identifier 87 | * @return GLO frequency slot corresponds to the GLO SV ID (1..14) 88 | */ 89 | u16 glo_map_get_fcn(gnss_signal_t sid) { 90 | assert(IS_GLO(sid)); 91 | assert(glo_slot_id_is_valid(sid.sat)); 92 | 93 | u16 fcn = (u16)glo_sv_id_fcn_map[sid.sat]; 94 | 95 | assert(fcn != GLO_FCN_UNKNOWN); 96 | 97 | return fcn; 98 | } 99 | 100 | /** The function clears mapping between GLO SV ID and GLO FCN 101 | * 102 | * @param glo_slot_id GLO orbital slot 103 | */ 104 | void glo_map_clear_slot_id(u16 glo_slot_id) { 105 | assert(glo_slot_id_is_valid(glo_slot_id)); 106 | 107 | glo_map_lock(); 108 | glo_sv_id_fcn_map[glo_slot_id] = GLO_FCN_UNKNOWN; 109 | glo_map_unlock(); 110 | } 111 | 112 | /** This function clears the entire mapping between GLO SV ID and GLO FCN. */ 113 | void glo_map_clear_all(void) { 114 | for (u16 i = 1; i < NUM_GLO_MAP_INDICES; ++i) { 115 | glo_map_clear_slot_id(i); 116 | } 117 | } 118 | 119 | /** This function fills the glo_map with dummy data so unit tests which use 120 | * GLONASS observations (but don't rely on actual wavelength values) can run. 121 | */ 122 | void glo_map_fill_dummy_data(void) { 123 | for (u16 i = 1; i < NUM_GLO_MAP_INDICES; ++i) { 124 | glo_sv_id_fcn_map[i] = -1; 125 | } 126 | } 127 | 128 | /** 129 | * The function checks if the FCN mapped to any slot ID. 130 | * 131 | * @param[in] fcn Frequency slot to be checked 132 | * @param[out] slot_id1 Pointer to the first slot ID container 133 | * @param[out] slot_id2 Pointer to the second slot ID container. 134 | * Function write 0 to the container if there is only one 135 | * slot ID mapped to the frequency 136 | * @return number of slot IDs mapped to the frequency slot in question 137 | * valid values are [0..2] 138 | */ 139 | u8 glo_map_get_slot_id(const u16 fcn, u16 *slot_id1, u16 *slot_id2) { 140 | assert(slot_id1 != NULL && slot_id2 != NULL); 141 | u8 si_num = 0; 142 | *slot_id1 = 0; 143 | *slot_id2 = 0; 144 | for (u8 i = GLO_FIRST_PRN; i < NUM_GLO_MAP_INDICES; i++) { 145 | if (fcn == glo_sv_id_fcn_map[i]) { 146 | /* the fcn mapped, so write to output */ 147 | si_num++; 148 | if (si_num == 1) { 149 | /* 1st slot found */ 150 | *slot_id1 = i; 151 | } 152 | if (si_num == 2) { 153 | /* 2 slots id found no need to continue */ 154 | *slot_id2 = i; 155 | break; 156 | } 157 | } 158 | } 159 | return si_num; 160 | } 161 | -------------------------------------------------------------------------------- /src/glonass_phase_biases.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014-2017 Swift Navigation Inc. 3 | * Contact: Swift Navigation 4 | * 5 | * This source is subject to the license found in the file 'LICENSE' which must 6 | * be be distributed together with this source. All other rights reserved. 7 | * 8 | * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 9 | * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 10 | * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. 11 | */ 12 | #include 13 | 14 | bool glonass_biases_are_equal(const glo_biases_t biases1, 15 | const glo_biases_t biases2) { 16 | if (biases1.mask != biases2.mask) { 17 | return false; 18 | } 19 | if (fabs(biases1.l1of_bias_m - biases2.l1of_bias_m) > FLOAT_EQUALITY_EPS) { 20 | return false; 21 | } 22 | if (fabs(biases1.l2of_bias_m - biases2.l2of_bias_m) > FLOAT_EQUALITY_EPS) { 23 | return false; 24 | } 25 | if (fabs(biases1.l1p_bias_m - biases2.l1p_bias_m) > FLOAT_EQUALITY_EPS) { 26 | return false; 27 | } 28 | if (fabs(biases1.l2p_bias_m - biases2.l2p_bias_m) > FLOAT_EQUALITY_EPS) { 29 | return false; 30 | } 31 | return true; 32 | } 33 | 34 | bool is_bias_mask_flag_set(const u8 msg_flags, const u8 flag) { 35 | return (msg_flags & flag) == flag; 36 | } 37 | 38 | double get_glonass_bias(const code_t code, const glo_biases_t biases) { 39 | /* For each frequency, we first check if the OF bias is present and return it. 40 | * If it is not present, we return the P-code bias. For instance Geo++ seems 41 | * to 42 | * be configured to broadcast L1OF and L2P biases probably to mimic GPS signal 43 | * table. 44 | * Finally, we return zero if none of the mask bit fore a given frequency is 45 | * set, as 46 | * the Septentrio does not seem to set its L1OF mask bit set to zero. 47 | * We do Piksi minus base biases as LSN filter sdiffs convention is rover 48 | * minus base 49 | * */ 50 | if (code == CODE_GLO_L1OF) { 51 | if (is_bias_mask_flag_set(biases.mask, RTCM1230_MASK_L1OF)) { 52 | return piksi_glonass_biases.l1of_bias_m - biases.l1of_bias_m; 53 | } 54 | if (is_bias_mask_flag_set(biases.mask, RTCM1230_MASK_L1P)) { 55 | return piksi_glonass_biases.l1of_bias_m - biases.l1p_bias_m; 56 | } 57 | } 58 | if (code == CODE_GLO_L2OF) { 59 | if (is_bias_mask_flag_set(biases.mask, RTCM1230_MASK_L2OF)) { 60 | return piksi_glonass_biases.l2of_bias_m - biases.l2of_bias_m; 61 | } 62 | if (is_bias_mask_flag_set(biases.mask, RTCM1230_MASK_L2P)) { 63 | return piksi_glonass_biases.l2of_bias_m - biases.l2p_bias_m; 64 | } 65 | } 66 | return 0.0; 67 | } 68 | -------------------------------------------------------------------------------- /src/ionosphere.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015, 2016 Swift Navigation Inc. 3 | * Contact: Swift Navigation 4 | * 5 | * This source is subject to the license found in the file 'LICENSE' which must 6 | * be distributed together with this source. All other rights reserved. 7 | * 8 | * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 9 | * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 10 | * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. 11 | */ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | /** \defgroup ionosphere Ionospheric models 24 | * Implemenations of ionospheric delay correction models. 25 | * \{ */ 26 | 27 | /** Calculate ionospheric delay using Klobuchar model. 28 | * 29 | * References: 30 | * -# IS-GPS-200H, Section 20.3.3.5.2.5 and Figure 20-4 31 | * 32 | * \param t_gps GPS time at which to calculate the ionospheric delay 33 | * \param lat_u Latitude of the receiver [rad] 34 | * \param lon_u Longitude of the receiver [rad] 35 | * \param a Azimuth of the satellite, clockwise positive from North [rad] 36 | * \param e Elevation of the satellite [rad] 37 | * \param i Ionosphere parameters struct from GPS NAV data 38 | * 39 | * \return Ionospheric delay distance for GPS L1 frequency [m] 40 | */ 41 | double calc_ionosphere(const gps_time_t *t_gps, 42 | double lat_u, 43 | double lon_u, 44 | double a, 45 | double e, 46 | const ionosphere_t *i) { 47 | /* Convert inputs from radians to semicircles */ 48 | /* All calculations are in semicircles */ 49 | lat_u = lat_u / M_PI; 50 | lon_u = lon_u / M_PI; 51 | /* a can remain in radians */ 52 | e = e / M_PI; 53 | 54 | /* Calculate the earth-centered angle */ 55 | double psi = 0.0137 / (e + 0.11) - 0.022; 56 | 57 | /* Compute the latitude of the Ionospheric Pierce Point */ 58 | double lat_i = lat_u + psi * cos(a); 59 | if (lat_i > 0.416) { 60 | lat_i = 0.416; 61 | } 62 | if (lat_i < -0.416) { 63 | lat_i = -0.416; 64 | } 65 | 66 | /* Compute the longitude of the IPP */ 67 | double lon_i = lon_u + (psi * sin(a)) / cos(lat_i * M_PI); 68 | 69 | /* Find the geomagnetic latitude of the IPP */ 70 | double lat_m = lat_i + 0.064 * cos((lon_i - 1.617) * M_PI); 71 | 72 | /* Find the local time at the IPP */ 73 | double t = 43200.0 * lon_i + t_gps->tow; 74 | t = fmod(t, DAY_SECS); 75 | if (t > DAY_SECS) { 76 | t -= DAY_SECS; 77 | } 78 | if (t < 0.0) { 79 | t += DAY_SECS; 80 | } 81 | 82 | /* Compute the amplitude of ionospheric delay */ 83 | double amp = i->a0 + lat_m * (i->a1 + lat_m * (i->a2 + i->a3 * lat_m)); 84 | if (amp < 0.0) { 85 | amp = 0.0; 86 | } 87 | 88 | /* Compute the period of ionospheric delay */ 89 | double per = i->b0 + lat_m * (i->b1 + lat_m * (i->b2 + i->b3 * lat_m)); 90 | if (per < 72000.0) { 91 | per = 72000.0; 92 | } 93 | 94 | /* Compute the phase of ionospheric delay */ 95 | double x = 2.0 * M_PI * (t - 50400.0) / per; 96 | 97 | /* Compute the slant factor */ 98 | double temp = 0.53 - e; 99 | double sf = 1.0 + 16.0 * temp * temp * temp; 100 | 101 | /* Compute the ionospheric time delay */ 102 | double d_l1; 103 | if (fabs(x) >= 1.57) { 104 | d_l1 = sf * 5e-9; 105 | } else { 106 | double x_2 = x * x; 107 | d_l1 = sf * (5e-9 + amp * (1.0 - x_2 / 2.0 + x_2 * x_2 / 24.0)); 108 | } 109 | 110 | d_l1 *= GPS_C; 111 | 112 | return d_l1; 113 | } 114 | 115 | /** 116 | * Decodes ionospheric parameters from GLS LNAV message subframe 4. 117 | * 118 | * The method decodes ionosphere data from GPS LNAV subframe 4 words 3-5. 119 | * 120 | * References: 121 | * -# IS-GPS-200H, Section 20.3.3.5.1.7 122 | * 123 | * \param[in] words Subframe 4 page 18. 124 | * \param[out] i Destination object. 125 | * 126 | * \retval true Ionosphere parameters have been decoded. 127 | * \retval false Decoding error. 128 | */ 129 | bool decode_iono_parameters(const u32 words[8], ionosphere_t *i) { 130 | bool retval = false; 131 | 132 | assert(NULL != words); 133 | assert(NULL != i); 134 | 135 | memset(i, 0, sizeof(*i)); 136 | 137 | /* Word 3 bits 1-2: data ID */ 138 | u8 data_id = words[3 - 3] >> (30 - 2) & 0x3; 139 | /* Word 3 bits 3-8: SV ID */ 140 | u8 sv_id = words[3 - 3] >> (30 - 8) & 0x3F; 141 | 142 | if (GPS_LNAV_ALM_DATA_ID_BLOCK_II == data_id && 143 | GPS_LNAV_ALM_SVID_IONO == sv_id) { 144 | /* Word 3 bits 9-16 */ 145 | i->a0 = (s8)(words[3 - 3] >> (30 - 16) & 0xFF) * GPS_LNAV_IONO_SF_A0; 146 | /* Word 3 bits 17-24 */ 147 | i->a1 = (s8)(words[3 - 3] >> (30 - 24) & 0xFF) * GPS_LNAV_IONO_SF_A1; 148 | /* Word 4 bits 1-8 */ 149 | i->a2 = (s8)(words[4 - 3] >> (30 - 8) & 0xFF) * GPS_LNAV_IONO_SF_A2; 150 | /* Word 4 bits 9-16 */ 151 | i->a3 = (s8)(words[4 - 3] >> (30 - 16) & 0xFF) * GPS_LNAV_IONO_SF_A3; 152 | /* Word 4 bits 17-24 */ 153 | i->b0 = (s8)(words[4 - 3] >> (30 - 24) & 0xFF) * GPS_LNAV_IONO_SF_B0; 154 | /* Word 5 bits 1-8 */ 155 | i->b1 = (s8)(words[5 - 3] >> (30 - 8) & 0xFF) * GPS_LNAV_IONO_SF_B1; 156 | /* Word 5 bits 9-16 */ 157 | i->b2 = (s8)(words[5 - 3] >> (30 - 16) & 0xFF) * GPS_LNAV_IONO_SF_B2; 158 | /* Word 5 bits 17-24 */ 159 | i->b3 = (s8)(words[5 - 3] >> (30 - 24) & 0xFF) * GPS_LNAV_IONO_SF_B3; 160 | retval = true; 161 | } 162 | 163 | return retval; 164 | } 165 | 166 | /** 167 | * Decodes Beidou D1 ionospheric parameters. 168 | * \param words subframes (FraID) 1. 169 | * \param iono ionospheric parameters. 170 | */ 171 | void decode_bds_d1_iono(const u32 words[10], ionosphere_t *iono) { 172 | const u32 *sf1_word = &words[0]; 173 | s8 alpha[4]; 174 | alpha[0] = (((sf1_word[4]) >> 16) & 0xff); 175 | alpha[1] = (((sf1_word[4]) >> 8) & 0xff); 176 | alpha[2] = (((sf1_word[5]) >> 22) & 0xff); 177 | alpha[3] = (((sf1_word[5]) >> 14) & 0xff); 178 | s8 beta[4]; 179 | beta[0] = (((sf1_word[5]) >> 8) & 0x3f) << 2; 180 | beta[0] |= (((sf1_word[6]) >> 28) & 0x3); 181 | beta[1] = (((sf1_word[6]) >> 20) & 0xff); 182 | beta[2] = (((sf1_word[6]) >> 12) & 0xff); 183 | beta[3] = (((sf1_word[6]) >> 8) & 0xf) << 4; 184 | beta[3] |= (((sf1_word[7]) >> 26) & 0xf); 185 | 186 | iono->toa.wn = (((sf1_word[2]) >> 17) & 0x1fff) + BDS_WEEK_TO_GPS_WEEK; 187 | iono->a0 = (alpha[0] * C_1_2P30); 188 | iono->a1 = (alpha[1] * C_1_2P27); 189 | iono->a2 = (alpha[2] * C_1_2P24); 190 | iono->a3 = (alpha[3] * C_1_2P24); 191 | iono->b0 = (double)(beta[0] * C_2P11); 192 | iono->b1 = (double)(beta[1] * C_2P14); 193 | iono->b2 = (double)(beta[2] * C_2P16); 194 | iono->b3 = (double)(beta[3] * C_2P16); 195 | } 196 | 197 | /** \} */ 198 | -------------------------------------------------------------------------------- /src/logging.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Swift Navigation Inc. 3 | * Contact: Swift Navigation 4 | * 5 | * This source is subject to the license found in the file 'LICENSE' which must 6 | * be distributed together with this source. All other rights reserved. 7 | * 8 | * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 9 | * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 10 | * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. 11 | */ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #ifdef LIBSWIFTNAV_ENABLE_STDERR_LOGGING 19 | 20 | /** \defgroup logging Logging 21 | * Logging functions. 22 | * \{ */ 23 | 24 | /** Log message by level. 25 | * 26 | * \param level Log level 27 | * \param msg Log contents 28 | */ 29 | SWIFT_ATTR_FORMAT(2, 3) 30 | static void log_stderr(int level, 31 | SWIFT_ATTR_FORMAT_STRING const char *msg, 32 | ...) { 33 | va_list ap; 34 | fprintf(stderr, "%s: ", level_string[level]); 35 | va_start(ap, msg); 36 | vfprintf(stderr, msg, ap); // NOLINT - clang-tidy insists that ap is 37 | // uninitialised when it clearly is 38 | va_end(ap); 39 | fprintf(stderr, "\n"); 40 | } 41 | 42 | /** Log message by level with file path and line number. 43 | * 44 | * \param level Log level 45 | * \param file_path string of full path to file where this function was called 46 | * \param line_number line number where this function was called 47 | * \param msg Log contents 48 | */ 49 | SWIFT_ATTR_FORMAT(4, 5) 50 | static void detailed_log_stderr(int level, 51 | const char *file_path, 52 | const int line_number, 53 | SWIFT_ATTR_FORMAT_STRING const char *msg, 54 | ...) { 55 | va_list ap; 56 | fprintf(stderr, "(lsn::%s:%d) ", file_path, line_number); 57 | fprintf(stderr, "%s: ", level_string[level]); 58 | va_start(ap, msg); 59 | vfprintf(stderr, msg, ap); // NOLINT - clang-tidy insists that ap is 60 | // uninitialised when is clearly is 61 | va_end(ap); 62 | fprintf(stderr, "\n"); 63 | } 64 | 65 | #define DEFAULT_LOG log_stderr 66 | #define DEFAULT_DETAILED_LOG detailed_log_stderr 67 | 68 | #else 69 | 70 | #define DEFAULT_LOG NULL 71 | #define DEFAULT_DETAILED_LOG NULL 72 | 73 | #endif 74 | 75 | pfn_log log_ = DEFAULT_LOG; 76 | pfn_detailed_log detailed_log_ = DEFAULT_DETAILED_LOG; 77 | 78 | void logging_set_implementation(pfn_log impl_log, 79 | pfn_detailed_log impl_detailed_log) { 80 | if (impl_log == NULL && impl_detailed_log == NULL) { 81 | log_ = DEFAULT_LOG; 82 | detailed_log_ = DEFAULT_DETAILED_LOG; 83 | return; 84 | } 85 | 86 | assert(impl_log != NULL); 87 | assert(impl_detailed_log != NULL); 88 | log_ = impl_log; 89 | detailed_log_ = impl_detailed_log; 90 | } 91 | 92 | /* \} */ 93 | -------------------------------------------------------------------------------- /src/logging_common.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Swift Navigation Inc. 3 | * Contact: Swift Navigation 4 | * 5 | * This source is subject to the license found in the file 'LICENSE' which must 6 | * be distributed together with this source. All other rights reserved. 7 | * 8 | * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 9 | * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 10 | * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. 11 | */ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | const char *level_string[] = { 19 | "EMERGENCY", 20 | "ALERT", 21 | "CRITICAL", 22 | "ERROR", 23 | "WARNING", 24 | "NOTICE", 25 | "INFO", 26 | "DEBUG", 27 | }; 28 | 29 | /** Shortens the full path to the filename only. 30 | * 31 | * \param path string of full path to file where this function was called 32 | * @return base file name of the path 33 | */ 34 | const char *truncate_path_(char *path) { 35 | assert(NULL != path); 36 | int i; 37 | 38 | if (path[0] == '\0') { 39 | return ""; 40 | } 41 | for (i = strlen(path) - 1; i >= 0 && path[i] == '/'; i--) { 42 | ; 43 | } 44 | if (i == -1) { 45 | return "/"; 46 | } 47 | /* set the trailing character to null in case it was '/' e.g. /dev/null/ */ 48 | path[i + 1] = '\0'; 49 | /* Go backwards until the prior '/' */ 50 | while (i >= 0 && path[i] != '/') { 51 | i--; 52 | } 53 | /* Return a pointer to the remainder */ 54 | return &path[i + 1]; 55 | } 56 | -------------------------------------------------------------------------------- /src/max_channels.h.in: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Swift Navigation Inc. 3 | * Contact: Swift Navigation 4 | * 5 | * This source is subject to the license found in the file 'LICENSE' which must 6 | * be distributed together with this source. All other rights reserved. 7 | * 8 | * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 9 | * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 10 | * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. 11 | */ 12 | 13 | /* Template for config.h */ 14 | #ifndef CONFIG_H 15 | #define CONFIG_H 16 | 17 | #define MAX_CHANNELS ${MAX_CHANNELS} 18 | 19 | #endif /* CONFIG_H */ 20 | -------------------------------------------------------------------------------- /src/memcpy_s.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Swift Navigation Inc. 3 | * Contact: Swift Navigation 4 | * 5 | * This source is subject to the license found in the file 'LICENSE' which must 6 | * be distributed together with this source. All other rights reserved. 7 | * 8 | * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 9 | * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 10 | * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. 11 | */ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #if !defined(_MSC_VER) && !defined(_CRT_MEMORY_DEFINED) 19 | 20 | memcpy_s_t memcpy_s(void *dest, 21 | size_t destsize, 22 | const void *src, 23 | size_t count) { 24 | if (NULL == dest) { 25 | log_error("memcpy_s error: destination NULL"); 26 | return MEMCPY_S_DEST_NULL; 27 | } 28 | 29 | if (NULL == src) { 30 | log_error("memcpy_s error: source NULL"); 31 | return MEMCPY_S_SRC_NULL; 32 | } 33 | 34 | if (0 == destsize) { 35 | log_error("memcpy_s error: destination size zero"); 36 | return MEMCPY_S_DEST_SIZE_ZERO; 37 | } 38 | 39 | if (0 == count) { 40 | log_error("memcpy_s error: src size zero"); 41 | return MEMCPY_S_SRC_SIZE_ZERO; 42 | } 43 | 44 | if (destsize < count) { 45 | log_error("memcpy_s error: src size %" PRIu64 46 | " greater than dest size %" PRIu64, 47 | (u64)count, 48 | (u64)destsize); 49 | return MEMCPY_S_OVERSIZED; 50 | } 51 | 52 | if (((src > dest) && (src < (void *)((u8 *)dest + destsize))) || 53 | ((dest > src) && (dest < (const void *)((const u8 *)src + count)))) { 54 | log_error("memcpy_s error: overlap"); 55 | return MEMCPY_S_OVERLAP; 56 | } 57 | 58 | memcpy(dest, src, count); 59 | 60 | return MEMCPY_S_OK; 61 | } 62 | 63 | #endif /* _CRT_MEMORY_DEFINED */ 64 | -------------------------------------------------------------------------------- /src/nav_meas.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Swift Navigation Inc. 3 | * Contact: Swift Navigation 4 | * 5 | * This source is subject to the license found in the file 'LICENSE' which must 6 | * be distributed together with this source. All other rights reserved. 7 | * 8 | * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 9 | * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 10 | * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. 11 | */ 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | static bool is_float_eq(const double a, const double b) { 18 | return fabs(a - b) < FLOAT_EQUALITY_EPS; 19 | } 20 | 21 | bool measurement_std_equal(const measurement_std_t *a, 22 | const measurement_std_t *b) { 23 | if (sid_compare(a->sid, b->sid) != 0) { 24 | return false; 25 | } 26 | if (!is_float_eq(a->iono_std, b->iono_std)) { 27 | return false; 28 | } 29 | if (!is_float_eq(a->tropo_std, b->tropo_std)) { 30 | return false; 31 | } 32 | if (!is_float_eq(a->range_std, b->range_std)) { 33 | return false; 34 | } 35 | if (a->flags != b->flags) { 36 | return false; 37 | } 38 | return true; 39 | } 40 | 41 | bool nav_meas_equal(const navigation_measurement_t *a, 42 | const navigation_measurement_t *b) { 43 | if (!is_float_eq(a->raw_pseudorange, b->raw_pseudorange)) { 44 | return false; 45 | } 46 | 47 | if (!is_float_eq(a->raw_carrier_phase, b->raw_carrier_phase)) { 48 | return false; 49 | } 50 | 51 | if (!is_float_eq(a->raw_measured_doppler, b->raw_measured_doppler)) { 52 | return false; 53 | } 54 | 55 | if (!is_float_eq(a->raw_computed_doppler, b->raw_computed_doppler)) { 56 | return false; 57 | } 58 | 59 | if (!is_float_eq(a->sat_pos[0], b->sat_pos[0]) || 60 | !is_float_eq(a->sat_pos[1], b->sat_pos[1]) || 61 | !is_float_eq(a->sat_pos[2], b->sat_pos[2])) { 62 | return false; 63 | } 64 | 65 | if (!is_float_eq(a->sat_vel[0], b->sat_vel[0]) || 66 | !is_float_eq(a->sat_vel[1], b->sat_vel[1]) || 67 | !is_float_eq(a->sat_vel[2], b->sat_vel[2])) { 68 | return false; 69 | } 70 | 71 | if (!is_float_eq(a->sat_acc[0], b->sat_acc[0]) || 72 | !is_float_eq(a->sat_acc[1], b->sat_acc[1]) || 73 | !is_float_eq(a->sat_acc[2], b->sat_acc[2])) { 74 | return false; 75 | } 76 | 77 | if (a->eph_key != b->eph_key) { 78 | return false; 79 | } 80 | 81 | if (!is_float_eq(a->sat_clock_err, b->sat_clock_err)) { 82 | return false; 83 | } 84 | 85 | if (!is_float_eq(a->sat_clock_err_rate, b->sat_clock_err_rate)) { 86 | return false; 87 | } 88 | 89 | if (!is_float_eq(a->cn0, b->cn0)) { 90 | return false; 91 | } 92 | 93 | if (!is_float_eq(a->lock_time, b->lock_time)) { 94 | return false; 95 | } 96 | 97 | if (!is_float_eq(a->elevation, b->elevation)) { 98 | return false; 99 | } 100 | 101 | if (!is_float_eq(gpsdifftime(&a->tot, &b->tot), 0)) { 102 | return false; 103 | } 104 | 105 | if (!sid_is_equal(a->sid, b->sid)) { 106 | return false; 107 | } 108 | 109 | if (a->flags != b->flags) { 110 | return false; 111 | } 112 | 113 | return true; 114 | } 115 | 116 | /** Compare navigation message by PRN. 117 | * This function is designed to be used together with qsort() etc. 118 | */ 119 | int nav_meas_cmp(const void *a, const void *b) { 120 | return sid_compare(((const navigation_measurement_t *)a)->sid, 121 | ((const navigation_measurement_t *)b)->sid); 122 | } 123 | 124 | bool nav_meas_flags_valid(nav_meas_flags_t flags) { 125 | const nav_meas_flags_t all_valid = 126 | NAV_MEAS_FLAG_CODE_VALID & NAV_MEAS_FLAG_PHASE_VALID & 127 | NAV_MEAS_FLAG_MEAS_DOPPLER_VALID & NAV_MEAS_FLAG_COMP_DOPPLER_VALID & 128 | NAV_MEAS_FLAG_HALF_CYCLE_KNOWN & NAV_MEAS_FLAG_CN0_VALID; 129 | return ~all_valid & flags; 130 | } 131 | 132 | bool pseudorange_valid(const navigation_measurement_t *meas) { 133 | return (meas->flags & NAV_MEAS_FLAG_CODE_VALID) && 134 | !(meas->flags & NAV_MEAS_FLAG_RAIM_EXCLUSION); 135 | } 136 | 137 | /** Convert navigation_measurement_t.lock_time into SBP lock time. 138 | * 139 | * Note: It is encoded according to DF402 from the RTCM 10403.2 Amendment 2 140 | * specification. Valid values range from 0 to 15 and the most significant 141 | * nibble is reserved for future use. 142 | * 143 | * \param nm_lock_time Navigation measurement lock time [s] 144 | * \return SBP lock time 145 | */ 146 | u8 encode_lock_time(double nm_lock_time) { 147 | assert(nm_lock_time >= 0.0); 148 | 149 | /* Convert to milliseconds */ 150 | u32 ms_lock_time; 151 | if (nm_lock_time < UINT32_MAX) { 152 | ms_lock_time = (u32)(nm_lock_time * SECS_MS); 153 | } else { 154 | ms_lock_time = UINT32_MAX; 155 | } 156 | 157 | if (ms_lock_time < 32) { 158 | return 0; 159 | } 160 | for (u8 i = 0; i < 16; i++) { 161 | if (ms_lock_time > (1u << (i + 5))) { 162 | continue; 163 | } 164 | return i; 165 | } 166 | return 15; 167 | } 168 | 169 | /** Convert SBP lock time into navigation_measurement_t.lock_time. 170 | * 171 | * Note: It is encoded according to DF402 from the RTCM 10403.2 Amendment 2 172 | * specification. Valid values range from 0 to 15 and the most significant 173 | * nibble is reserved for future use. 174 | * 175 | * \param sbp_lock_time SBP lock time 176 | * \return Minimum possible lock time [s] 177 | */ 178 | double decode_lock_time(u8 sbp_lock_time) { 179 | /* MSB nibble is reserved */ 180 | sbp_lock_time &= 0x0F; 181 | 182 | u32 ms_lock_time; 183 | if (sbp_lock_time == 0) { 184 | ms_lock_time = 0; 185 | } else { 186 | ms_lock_time = 1u << (sbp_lock_time + 4); 187 | } 188 | 189 | /* Convert to seconds */ 190 | return (double)ms_lock_time / SECS_MS; 191 | } 192 | 193 | double nav_meas_cor_sat_clk_on_pseudorange( 194 | const navigation_measurement_t *nav_meas) { 195 | return (nav_meas->raw_pseudorange + GPS_C * nav_meas->sat_clock_err); 196 | } 197 | 198 | double nav_meas_cor_sat_clk_on_measured_doppler( 199 | const navigation_measurement_t *nav_meas) { 200 | double carrier_freq = sid_to_carr_freq(nav_meas->sid); 201 | return (nav_meas->raw_measured_doppler + 202 | nav_meas->sat_clock_err_rate * carrier_freq); 203 | } 204 | 205 | double nav_meas_cor_sat_clk_on_carrier_phase( 206 | const navigation_measurement_t *nav_meas) { 207 | double carrier_freq = sid_to_carr_freq(nav_meas->sid); 208 | return (nav_meas->raw_carrier_phase + nav_meas->sat_clock_err * carrier_freq); 209 | } 210 | -------------------------------------------------------------------------------- /src/sid_set.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Swift Navigation Inc. 3 | * Contact: Swift Navigation 4 | * 5 | * This source is subject to the license found in the file 'LICENSE' which must 6 | * be distributed together with this source. All other rights reserved. 7 | * 8 | * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 9 | * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 10 | * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. 11 | */ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | /** Initialize new sid set 19 | * 20 | * \param sid_set gnss_sid_set_t to be initialized 21 | * 22 | */ 23 | void sid_set_init(gnss_sid_set_t *sid_set) { 24 | memset(sid_set->sats, 0, sizeof(sid_set->sats)); 25 | } 26 | 27 | /** Add new element to the set 28 | * 29 | * \param sid_set gnss_sid_set_t to add new element to 30 | * \param sid element to be added 31 | * 32 | */ 33 | void sid_set_add(gnss_sid_set_t *sid_set, gnss_signal_t sid) { 34 | u16 s = sid_to_code_index(sid); 35 | assert(s < 64); 36 | sid_set->sats[sid.code] |= ((u64)0x01 << s); 37 | } 38 | 39 | /** Remove an element from the set 40 | * 41 | * \param sid_set gnss_sid_set_t to remove from 42 | * \param sid element to be removed 43 | * 44 | */ 45 | void sid_set_remove(gnss_sid_set_t *sid_set, gnss_signal_t sid) { 46 | u16 s = sid_to_code_index(sid); 47 | assert(s < 64); 48 | sid_set->sats[sid.code] &= ~((u64)0x01 << s); 49 | } 50 | 51 | /** Get number of distinct satellites in sid set 52 | * 53 | * \param sid_set gnss_sid_set_t to count number of satellites in 54 | * 55 | * \returns Number of unique satellites present in the set. 56 | * 57 | */ 58 | u32 sid_set_get_sat_count(const gnss_sid_set_t *sid_set) { 59 | u64 sats[CONSTELLATION_COUNT]; 60 | memset(sats, 0, sizeof(sats)); 61 | for (code_t code = 0; code < CODE_COUNT; code++) { 62 | sats[code_to_constellation(code)] |= sid_set->sats[code]; 63 | } 64 | 65 | u32 cnt = 0; 66 | for (constellation_t constellation = 0; constellation < CONSTELLATION_COUNT; 67 | constellation++) { 68 | cnt += count_bits_u64(sats[constellation], 1); 69 | } 70 | 71 | return cnt; 72 | } 73 | 74 | /** Get number of signals in sid set 75 | * 76 | * \param sid_set gnss_sid_set_t to count number of signals in 77 | * 78 | * \returns Number of signals present in the set. 79 | * 80 | */ 81 | u32 sid_set_get_sig_count(const gnss_sid_set_t *sid_set) { 82 | u32 cnt = 0; 83 | for (code_t code = 0; code < CODE_COUNT; code++) { 84 | cnt += count_bits_u64(sid_set->sats[code], 1); 85 | } 86 | 87 | return cnt; 88 | } 89 | 90 | /** Does a sid set contain given sid 91 | * 92 | * \param sid_set gnss_sid_set_t to search from 93 | * \param sid The signal to search for 94 | * 95 | * \returns True if sid is in sid_set 96 | * 97 | */ 98 | bool sid_set_contains(const gnss_sid_set_t *sid_set, gnss_signal_t sid) { 99 | u16 s = sid_to_code_index(sid); 100 | assert(s < 64); 101 | return sid_set->sats[sid.code] & ((u64)0x01 << s); 102 | } 103 | -------------------------------------------------------------------------------- /src/subsystem_status_report.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2022 Swift Navigation Inc. 3 | * Contact: Swift Navigation 4 | * 5 | * This source is subject to the license found in the file 'LICENSE' which must 6 | * distributed together with this source. All other rights reserved. 7 | * 8 | * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 9 | * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 10 | * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. 11 | */ 12 | 13 | #include 14 | #include 15 | 16 | static swiftnav_subsystem_status_report_callback_node_t* root_callback_node = 17 | NULL; 18 | 19 | void swiftnav_subsystem_status_report_callback_register( 20 | swiftnav_subsystem_status_report_callback_node_t* callback_node, 21 | pfn_subsystem_status_report callback, 22 | void* context) { 23 | callback_node->callback = callback; 24 | callback_node->context = context; 25 | callback_node->next = NULL; 26 | 27 | swiftnav_subsystem_status_report_callback_node_t* previous = NULL; 28 | swiftnav_subsystem_status_report_callback_node_t* current = 29 | root_callback_node; 30 | 31 | for (; current != NULL; previous = current, current = current->next) { 32 | } 33 | 34 | if (previous != NULL) { 35 | previous->next = callback_node; 36 | } else { 37 | root_callback_node = callback_node; 38 | } 39 | } 40 | 41 | void swiftnav_subsystem_status_report_callback_deregister( 42 | swiftnav_subsystem_status_report_callback_node_t* callback_node) { 43 | swiftnav_subsystem_status_report_callback_node_t* previous = NULL; 44 | swiftnav_subsystem_status_report_callback_node_t* current = 45 | root_callback_node; 46 | 47 | for (; current != NULL; previous = current, current = current->next) { 48 | if (current != callback_node) { 49 | continue; 50 | } 51 | 52 | if (previous != NULL) { 53 | previous->next = current->next; 54 | } else { 55 | root_callback_node = current->next; 56 | } 57 | } 58 | } 59 | 60 | void swiftnav_subsystem_status_report_callback_reset(void) { 61 | root_callback_node = NULL; 62 | } 63 | 64 | void swiftnav_send_subsystem_status_report(uint16_t component, 65 | uint8_t generic, 66 | uint8_t specific) { 67 | swiftnav_subsystem_status_report_callback_node_t* node = root_callback_node; 68 | for (; node != NULL; node = node->next) { 69 | node->callback(component, generic, specific, node->context); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | if(libswiftnav_BUILD_TEST_LIBS) 2 | add_subdirectory(common) 3 | endif() 4 | 5 | if(libswiftnav_BUILD_TESTS) 6 | find_package(Threads) 7 | 8 | set(SRCS 9 | check_almanac.c 10 | check_bits.c 11 | check_coord_system.c 12 | check_decode_glo.c 13 | check_edc.c 14 | check_ephemeris.c 15 | check_geoid_model.cc 16 | check_glo_map.c 17 | check_gnss_time.c 18 | check_gnss_time_cpp.cc 19 | check_ionosphere.c 20 | check_linear_algebra.c 21 | check_log.c 22 | check_main.c 23 | check_nav_meas.c 24 | check_set.c 25 | check_shm.c 26 | check_sid_set.c 27 | check_signal.c 28 | check_subsystem_status_report.c 29 | check_pvt.c 30 | check_troposphere.c) 31 | 32 | swift_add_test(test-swiftnav-common 33 | UNIT_TEST 34 | POST_BUILD 35 | SRCS ${SRCS} 36 | LINK swiftnav::check-utils check Threads::Threads 37 | ) 38 | target_include_directories(test-swiftnav-common PRIVATE ${PROJECT_SOURCE_DIR}) 39 | 40 | swift_set_compile_options( 41 | test-swiftnav-common 42 | REMOVE 43 | -Wconversion 44 | -Wstack-protector 45 | -Wfloat-equal 46 | -Wsign-compare 47 | ADD 48 | -Wno-format-extra-args 49 | ) 50 | 51 | swift_add_test(test-swiftnav-pedantic 52 | UNIT_TEST 53 | SRCS check_pedantic.cc 54 | LINK swiftnav::swiftnav 55 | ) 56 | swift_set_compile_options(test-swiftnav-pedantic ADD -pedantic) 57 | 58 | endif(libswiftnav_BUILD_TESTS) 59 | -------------------------------------------------------------------------------- /tests/check_edc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "check_suites.h" 5 | 6 | const u8 *test_data = (const u8 *)"123456789"; 7 | 8 | START_TEST(test_crc24q) { 9 | u32 crc; 10 | 11 | crc = crc24q(test_data, 0, 0); 12 | fail_unless(crc == 0, 13 | "CRC of empty buffer with starting value 0 should be 0, not %d", 14 | crc); 15 | 16 | crc = crc24q(test_data, 0, 22); 17 | fail_unless(crc == 22, 18 | "CRC of empty buffer with starting value 22 should be 22, not %d", 19 | crc); 20 | 21 | /* Test value taken from python crcmod package tests, see: 22 | * http://crcmod.sourceforge.net/crcmod.predefined.html */ 23 | crc = crc24q(test_data, 9, 0xB704CE); 24 | fail_unless( 25 | crc == 0x21CF02, 26 | "CRC of \"123456789\" with init value 0xB704CE should be 0x21CF02, " 27 | "not 0x%06X", 28 | crc); 29 | } 30 | END_TEST 31 | 32 | Suite *edc_suite(void) { 33 | Suite *s = suite_create("Error Detection and Correction"); 34 | 35 | TCase *tc_crc = tcase_create("CRC"); 36 | tcase_add_test(tc_crc, test_crc24q); 37 | suite_add_tcase(s, tc_crc); 38 | 39 | return s; 40 | } 41 | -------------------------------------------------------------------------------- /tests/check_glo_map.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Swift Navigation Inc. 3 | * Contact: Dmitry Tatarinov 4 | * 5 | * This source is subject to the license found in the file 'LICENSE' which must 6 | * be distributed together with this source. All other rights reserved. 7 | * 8 | * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 9 | * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 10 | * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. 11 | */ 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | #include "check_suites.h" 18 | 19 | #define FCN_TEST_VAL 14 20 | #define SLOT_ID_TEST_VAL_1 5 21 | #define SLOT_ID_TEST_VAL_2 10 22 | 23 | static void glo_map_lock(void) {} 24 | static void glo_map_unlock(void) {} 25 | 26 | START_TEST(test_glo_map) { 27 | /* We do not test thread safety here. 28 | Therefore lock & unlock functions are just stubs. */ 29 | glo_map_init(glo_map_lock, glo_map_unlock); 30 | 31 | for (u16 i = 1; i <= NUM_SATS_GLO; i++) { 32 | gnss_signal_t glo_sid = construct_sid(CODE_GLO_L1OF, i); 33 | glo_map_set_slot_id(FCN_TEST_VAL, /*glo_slot_id=*/i); 34 | 35 | fail_if(glo_map_valid(glo_sid) == false, "GLO mapping should be valid"); 36 | 37 | u16 fcn = glo_map_get_fcn(glo_sid); 38 | fail_if(fcn != FCN_TEST_VAL, 39 | "Incorrect GLO FCN mapping (have, expected): %d, %d", 40 | fcn, 41 | FCN_TEST_VAL); 42 | 43 | glo_map_clear_slot_id(i); 44 | 45 | fail_if(glo_map_valid(glo_sid) == true, "GLO mapping should be invalid"); 46 | } 47 | 48 | u16 slot_id1, slot_id2; 49 | u8 si_num; 50 | si_num = glo_map_get_slot_id(FCN_TEST_VAL, &slot_id1, &slot_id2); 51 | fail_if(si_num != 0 || slot_id1 != 0 || slot_id2 != 0, 52 | "Incorrect number of slot ID or slot ID\n" 53 | "Number of slot ID (have, expected) %d, 0\n" 54 | "slot_id1 (have, expected): %d, 0\n" 55 | "slot_id2 (have, expected): %d, 0", 56 | si_num, 57 | slot_id1, 58 | slot_id2); 59 | glo_map_set_slot_id(FCN_TEST_VAL, SLOT_ID_TEST_VAL_1); 60 | si_num = glo_map_get_slot_id(FCN_TEST_VAL, &slot_id1, &slot_id2); 61 | fail_if(si_num != 1 || slot_id1 != SLOT_ID_TEST_VAL_1 || slot_id2 != 0, 62 | "Incorrect number of slot ID or slot ID\n" 63 | "Number of slot ID (have, expected) %d, 1\n" 64 | "slot_id1 (have, expected): %d, %d\n" 65 | "slot_id2 (have, expected): %d, 0", 66 | si_num, 67 | slot_id1, 68 | SLOT_ID_TEST_VAL_1, 69 | slot_id2); 70 | glo_map_set_slot_id(FCN_TEST_VAL, SLOT_ID_TEST_VAL_1); 71 | glo_map_set_slot_id(FCN_TEST_VAL, SLOT_ID_TEST_VAL_2); 72 | si_num = glo_map_get_slot_id(FCN_TEST_VAL, &slot_id1, &slot_id2); 73 | fail_if(si_num != 2 || slot_id1 != SLOT_ID_TEST_VAL_1 || 74 | slot_id2 != SLOT_ID_TEST_VAL_2, 75 | "Incorrect number of slot ID or slot ID\n" 76 | "Number of slot ID (have, expected) %d, 2\n" 77 | "slot_id1 (have, expected): %d, %d\n," 78 | "slot_id2 (have, expected): %d, %d", 79 | si_num, 80 | slot_id1, 81 | SLOT_ID_TEST_VAL_1, 82 | slot_id2, 83 | SLOT_ID_TEST_VAL_2); 84 | glo_map_set_slot_id(FCN_TEST_VAL, SLOT_ID_TEST_VAL_1); 85 | glo_map_set_slot_id(FCN_TEST_VAL, SLOT_ID_TEST_VAL_2); 86 | glo_map_set_slot_id(FCN_TEST_VAL, SLOT_ID_TEST_VAL_2 + 1); 87 | si_num = glo_map_get_slot_id(FCN_TEST_VAL, &slot_id1, &slot_id2); 88 | fail_if(si_num != 2 || slot_id1 != SLOT_ID_TEST_VAL_1 || 89 | slot_id2 != SLOT_ID_TEST_VAL_2, 90 | "Incorrect number of slot ID or slot ID\n" 91 | "Number of slot ID (have, expected) %d, 2\n" 92 | "slot_id1 (have, expected): %d, %d\n," 93 | "slot_id2 (have, expected): %d, %d", 94 | si_num, 95 | slot_id1, 96 | SLOT_ID_TEST_VAL_1, 97 | slot_id2, 98 | SLOT_ID_TEST_VAL_2); 99 | } 100 | END_TEST 101 | 102 | Suite *glo_map_test_suite(void) { 103 | Suite *s = suite_create("GLO FCN map"); 104 | TCase *tc_core = tcase_create("Core"); 105 | tcase_add_test(tc_core, test_glo_map); 106 | suite_add_tcase(s, tc_core); 107 | 108 | return s; 109 | } 110 | -------------------------------------------------------------------------------- /tests/check_gnss_time_cpp.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "check_suites.h" 8 | #include "common/check_utils.h" 9 | 10 | #ifdef __cplusplus 11 | extern "C" { 12 | #endif 13 | 14 | #define GPS_TIME_TOL (1.0e-9) 15 | 16 | START_TEST(test_gpstime_comparison_ops) { 17 | gps_time_t a = {567890.0, 1234}; 18 | gps_time_t b = {567890.5, 1234}; 19 | gps_time_t c = {567890.0, 1234}; 20 | gps_time_t time_before_rollover = {WEEK_SECS - 1.0, 1234}; 21 | gps_time_t time_after_rollover{1.0, 1234}; 22 | gps_time_t time_unknown_wn_only{1.0, WN_UNKNOWN}; 23 | gps_time_t time_unknown_tow_only{TOW_UNKNOWN, 1234}; 24 | gps_time_t time_unknown_wn_a{0.0, WN_UNKNOWN}; 25 | gps_time_t time_unknown_wn_b{WEEK_SECS - 1.0, WN_UNKNOWN}; 26 | gps_time_t time_unknown_tow_a{TOW_UNKNOWN, 1234}; 27 | gps_time_t time_unknown_tow_b{TOW_UNKNOWN, 1235}; 28 | fail_unless(a < b, "operator< failed"); 29 | fail_unless(b > a, "operator> failed"); 30 | fail_unless(!(a == b), "operator== failed"); 31 | fail_unless(!(b == a), "operator== failed"); 32 | fail_unless(a == c, "operator== failed"); 33 | fail_unless(a <= b, "operator<= failed"); 34 | fail_unless(b >= a, "operator>= failed"); 35 | fail_unless(a >= c, "operator>= failed"); 36 | fail_unless(a <= c, "operator<= failed"); 37 | fail_unless(GPS_TIME_UNKNOWN == GPS_TIME_UNKNOWN, "operator== failed"); 38 | fail_unless(!(time_before_rollover == GPS_TIME_UNKNOWN), "operator== failed"); 39 | fail_unless(!(GPS_TIME_UNKNOWN == time_before_rollover), "operator== failed"); 40 | fail_unless(!(time_after_rollover == GPS_TIME_UNKNOWN), "operator== failed"); 41 | fail_unless(!(GPS_TIME_UNKNOWN == time_after_rollover), "operator== failed"); 42 | fail_unless(!(time_unknown_wn_only == GPS_TIME_UNKNOWN), "operator== failed"); 43 | fail_unless(!(GPS_TIME_UNKNOWN == time_unknown_wn_only), "operator== failed"); 44 | fail_unless(!(time_unknown_tow_only == GPS_TIME_UNKNOWN), 45 | "operator== failed"); 46 | fail_unless(!(GPS_TIME_UNKNOWN == time_unknown_tow_only), 47 | "operator== failed"); 48 | fail_unless(!(time_unknown_wn_a == time_unknown_wn_b), "operator== failed"); 49 | fail_unless(!(time_unknown_wn_b == time_unknown_wn_a), "operator== failed"); 50 | fail_unless(!(time_unknown_tow_a == time_unknown_tow_b), "operator== failed"); 51 | fail_unless(!(time_unknown_tow_b == time_unknown_tow_a), "operator== failed"); 52 | } 53 | END_TEST 54 | 55 | START_TEST(test_gpstime_operator_minus) { 56 | gps_time_t a = {567890.0, 1234}, b = {567890.5, 1234}; 57 | fail_unless(fabs((b - a) - 0.5) < GPS_TIME_TOL, "operator- failed"); 58 | fail_unless(fabs((b - 0.5) - a) < GPS_TIME_TOL, "operator- failed"); 59 | } 60 | END_TEST 61 | 62 | START_TEST(test_gpstime_operator_plus) { 63 | gps_time_t a = {567890.0, 1234}, b = {567890.5, 1234}; 64 | fail_unless(fabs((a + 0.5) - b) < GPS_TIME_TOL, "operator+ failed"); 65 | fail_unless(fabs((0.5 + a) - b) < GPS_TIME_TOL, "operator+ failed"); 66 | } 67 | END_TEST 68 | 69 | START_TEST(test_gpstime_operator_plus_assignment) { 70 | gps_time_t a = {567890.0, 1234}, b = {567890.5, 1234}; 71 | a += 0.5; 72 | fail_unless(fabs(a - b) < GPS_TIME_TOL, "operator+= failed"); 73 | } 74 | END_TEST 75 | 76 | START_TEST(test_gpstime_operator_minus_assignment) { 77 | gps_time_t a = {567890.0, 1234}, b = {567890.5, 1234}; 78 | b -= 0.5; 79 | fail_unless(fabs(a - b) < GPS_TIME_TOL, "operator-= failed"); 80 | } 81 | END_TEST 82 | 83 | Suite *gnss_time_cpp_test_suite(void) { 84 | Suite *s = suite_create("GPS Time C++ operators"); 85 | 86 | TCase *tc_core = tcase_create("Core"); 87 | tcase_add_test(tc_core, test_gpstime_comparison_ops); 88 | tcase_add_test(tc_core, test_gpstime_operator_minus); 89 | tcase_add_test(tc_core, test_gpstime_operator_plus); 90 | tcase_add_test(tc_core, test_gpstime_operator_plus_assignment); 91 | tcase_add_test(tc_core, test_gpstime_operator_minus_assignment); 92 | suite_add_tcase(s, tc_core); 93 | 94 | return s; 95 | } 96 | 97 | #ifdef __cplusplus 98 | } /* extern "C" */ 99 | #endif -------------------------------------------------------------------------------- /tests/check_ionosphere.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Swift Navigation Inc. 3 | * Contact: Swift Navigation 4 | * 5 | * This source is subject to the license found in the file 'LICENSE' which must 6 | * be distributed together with this source. All other rights reserved. 7 | * 8 | * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 9 | * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 10 | * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. 11 | */ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "check_suites.h" 19 | 20 | START_TEST(test_calc_ionosphere) { 21 | gps_time_t t = {.wn = 1875, .tow = 479820}; 22 | ionosphere_t i = {.a0 = 0.1583e-7, 23 | .a1 = -0.7451e-8, 24 | .a2 = -0.5960e-7, 25 | .a3 = 0.1192e-6, 26 | .b0 = 0.1290e6, 27 | .b1 = -0.2130e6, 28 | .b2 = 0.6554e5, 29 | .b3 = 0.3277e6}; 30 | double lat_u = -35.3 * D2R, lon_u = 149.1 * D2R; 31 | double a = 0.0 * D2R, e = 15.0 * D2R; 32 | double d_true = 7.202; 33 | 34 | const double d_tol = 1e-3; 35 | 36 | double d_l1 = calc_ionosphere(&t, lat_u, lon_u, a, e, &i); 37 | double d_err = fabs(d_l1 - d_true); 38 | 39 | fail_unless( 40 | d_err < d_tol, 41 | "Distance didn't match hardcoded correct value %0.5f. Saw: %.5f\n", 42 | d_true, 43 | d_l1); 44 | 45 | t.wn = 1042; 46 | t.tow = 593100; 47 | i.a0 = 0.3820e-7; 48 | i.a1 = 0.1490e-7; 49 | i.a2 = -0.1790e-6; 50 | i.a3 = 0.0; 51 | i.b0 = 0.1430e6; 52 | i.b1 = 0.0; 53 | i.b2 = -0.3280e6; 54 | i.b3 = 0.1130e6; 55 | lat_u = 40.0 * D2R; 56 | lon_u = 260.0 * D2R; 57 | a = 210.0 * D2R; 58 | e = 20.0 * D2R; 59 | d_true = 23.784; 60 | 61 | d_l1 = calc_ionosphere(&t, lat_u, lon_u, a, e, &i); 62 | d_err = fabs(d_l1 - d_true); 63 | 64 | fail_unless( 65 | d_err < d_tol, 66 | "Distance didn't match hardcoded correct values %0.5f. Saw: %.5f\n", 67 | d_true, 68 | d_l1); 69 | 70 | t.wn = 1042; 71 | t.tow = 345600; 72 | i.a0 = 1.304e-8; 73 | i.a1 = 0; 74 | i.a2 = -5.96e-8; 75 | i.a3 = 5.96e-8; 76 | i.b0 = 1.106e5; 77 | i.b1 = -65540.0; 78 | i.b2 = -2.621e5; 79 | i.b3 = 3.932e5; 80 | lat_u = 0.70605; 81 | lon_u = -0.076233; 82 | a = 2.62049; 83 | e = 0.2939; 84 | d_true = 3.4929; 85 | 86 | d_l1 = calc_ionosphere(&t, lat_u, lon_u, a, e, &i); 87 | d_err = fabs(d_l1 - d_true); 88 | 89 | fail_unless( 90 | d_err < d_tol, 91 | "Distance didn't match hardcoded correct values %0.5f. Saw: %.5f\n", 92 | d_true, 93 | d_l1); 94 | } 95 | END_TEST 96 | 97 | START_TEST(test_decode_iono_parameters) { 98 | #define tol 1e-12 99 | struct { 100 | u32 frame_words[8]; 101 | ionosphere_t result; 102 | } t_case = {.frame_words = 103 | {/* 4th SF real data at 11-May-2016 */ 104 | 0x1e0300c9, 105 | 0x7fff8c24, 106 | 0x23fbdc2, 107 | 0, 108 | 0, 109 | 0, 110 | 0, 111 | 0}, 112 | .result = { 113 | /* reference data provided by u-blox receiver */ 114 | .a0 = 0.0000000111758, 115 | .a1 = 0.0000000223517, 116 | .a2 = -0.0000000596046, 117 | .a3 = -0.0000001192092, 118 | .b0 = 98304.0, 119 | .b1 = 131072.0, 120 | .b2 = -131072.0, 121 | .b3 = -589824.0, 122 | }}; 123 | ionosphere_t i; 124 | decode_iono_parameters(t_case.frame_words, &i); 125 | fail_unless(fabs(i.a0 - t_case.result.a0) < tol, 126 | "alfa 0 == %30.20f, expected %30.20f, tolerance = %30.20f", 127 | i.a0, 128 | t_case.result.a0, 129 | tol); 130 | fail_unless(fabs(i.a1 - t_case.result.a1) < tol, 131 | "alfa 1 == %30.20f, expected %30.20f, tolerance = %30.20f", 132 | i.a1, 133 | t_case.result.a1, 134 | tol); 135 | fail_unless(fabs(i.a2 - t_case.result.a2) < tol, 136 | "alfa 2 == %30.20f, expected %30.20f, tolerance = %30.20f", 137 | i.a2, 138 | t_case.result.a2, 139 | tol); 140 | fail_unless(fabs(i.a3 - t_case.result.a3) < tol, 141 | "alfa 3 == %30.20f, expected %30.20f, tolerance = %30.20f", 142 | i.a3, 143 | t_case.result.a3, 144 | tol); 145 | fail_unless(fabs(i.b0 - t_case.result.b0) < tol, 146 | "beta 0 == %30.20f, expected %30.20f, tolerance = %30.20f", 147 | i.b0, 148 | t_case.result.b0, 149 | tol); 150 | fail_unless(fabs(i.b1 - t_case.result.b1) < tol, 151 | "beta 1 == %30.20f, expected %30.20f, tolerance = %30.20f", 152 | i.b1, 153 | t_case.result.b1, 154 | tol); 155 | fail_unless(fabs(i.b2 - t_case.result.b2) < tol, 156 | "beta 2 == %30.20f, expected %30.20f, tolerance = %30.20f", 157 | i.b2, 158 | t_case.result.b2, 159 | tol); 160 | fail_unless(fabs(i.b3 - t_case.result.b3) < tol, 161 | "beta 3 == %30.20f, expected %30.20f, tolerance = %30.20f", 162 | i.b3, 163 | t_case.result.b3, 164 | tol); 165 | } 166 | END_TEST 167 | 168 | Suite *ionosphere_suite(void) { 169 | Suite *s = suite_create("Ionosphere"); 170 | 171 | TCase *tc_core = tcase_create("Core"); 172 | tcase_add_test(tc_core, test_calc_ionosphere); 173 | tcase_add_test(tc_core, test_decode_iono_parameters); 174 | suite_add_tcase(s, tc_core); 175 | 176 | return s; 177 | } 178 | -------------------------------------------------------------------------------- /tests/check_log.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "check_suites.h" 7 | #define MAX_STR 1024 8 | 9 | /*globals for test */ 10 | static char out_str[MAX_STR]; 11 | char *ptr = out_str; 12 | int last_level = 0; 13 | 14 | static void reset_log(void) { 15 | ptr = out_str; 16 | memset(out_str, 0, MAX_STR); 17 | } 18 | 19 | static void test_log(int level, const char *msg, ...) { 20 | va_list ap; 21 | va_start(ap, msg); 22 | ptr += vsprintf(ptr, msg, ap); 23 | va_end(ap); 24 | ptr += sprintf(ptr, "\n"); 25 | last_level = level; 26 | } 27 | 28 | static void test_detailed_log(int level, 29 | const char *file_path, 30 | const int line_number, 31 | const char *msg, 32 | ...) { 33 | (void)level; 34 | (void)file_path; 35 | (void)line_number; 36 | (void)msg; 37 | } 38 | 39 | START_TEST(test_logging) { 40 | /* check ptr arithmetic in print and null terminatino */ 41 | int expected_len = 11; 42 | logging_set_implementation(test_log, test_detailed_log); 43 | log_info("log_info_1"); 44 | fail_unless((ptr - out_str) == expected_len, 45 | "log_info macro failed length check. got %zu, should be %i. %s", 46 | (size_t)(ptr - out_str), 47 | expected_len, 48 | out_str); 49 | fail_unless( 50 | strnlen(out_str, MAX_STR) == (size_t)expected_len, 51 | "log_info macro failed length check. strlen was %zu, should be %i. %s", 52 | strnlen(out_str, MAX_STR), 53 | expected_len, 54 | out_str); 55 | reset_log(); 56 | 57 | /* test log with rate limit based upon arbitrary tics. no need to check 58 | * pointer as it was done above*/ 59 | expected_len = (14 * 4); /*should print 4 times. line length is 14.*/ 60 | 61 | for (int i = 0; i < 4000; i++) { 62 | LOG_RATE_LIMIT(i, log_info("log_rate_%04d", i)); 63 | } 64 | fail_unless( 65 | strnlen(out_str, MAX_STR) == (size_t)expected_len, 66 | "log_rate_limit macro failed length check. got %zu, should be %i. %s", 67 | strnlen(out_str, MAX_STR), 68 | expected_len, 69 | out_str); 70 | reset_log(); 71 | /* if we somehow go back in time, should print again*/ 72 | expected_len = 2 * 14; /* should print 2 times. String is length 14. */ 73 | for (int j = 2000; j > 0; j -= 1500) { 74 | LOG_RATE_LIMIT(j, log_info("log_rate_%04d", j)); 75 | } 76 | fail_unless( 77 | strnlen(out_str, MAX_STR) == (size_t)expected_len, 78 | "log_rate_limit macro back in time failed length check. got %zu, " 79 | "should be %i. %s", 80 | strnlen(out_str, MAX_STR), 81 | expected_len, 82 | out_str); 83 | reset_log(); 84 | /* if we wrap, arithmetic rules should just work */ 85 | expected_len = (20 * 4); /* should print 4 times.*/ 86 | for (int i = 0xffffffff - 1998; i < 1999; i++) { 87 | LOG_RATE_LIMIT(i, log_info("log_rate_%010u", i)); 88 | } 89 | fail_unless(strnlen(out_str, MAX_STR) == (size_t)expected_len, 90 | "log_rate_limit macro wrap failed length check. got %zu, should " 91 | "be %i. %s", 92 | strnlen(out_str, MAX_STR), 93 | expected_len, 94 | out_str); 95 | } 96 | END_TEST 97 | 98 | Suite *log_suite(void) { 99 | Suite *s = suite_create("Logging"); 100 | 101 | TCase *tc_log = tcase_create("logging"); 102 | tcase_add_test(tc_log, test_logging); 103 | suite_add_tcase(s, tc_log); 104 | 105 | return s; 106 | } 107 | -------------------------------------------------------------------------------- /tests/check_main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "check_suites.h" 5 | 6 | int main(void) { 7 | int number_failed; 8 | 9 | Suite *s = edc_suite(); 10 | 11 | SRunner *sr = srunner_create(s); 12 | srunner_set_xml(sr, "test_results.xml"); 13 | 14 | srunner_add_suite(sr, almanac_suite()); 15 | srunner_add_suite(sr, bits_suite()); 16 | srunner_add_suite(sr, edc_suite()); 17 | srunner_add_suite(sr, ionosphere_suite()); 18 | srunner_add_suite(sr, coord_system_suite()); 19 | srunner_add_suite(sr, linear_algebra_suite()); 20 | srunner_add_suite(sr, troposphere_suite()); 21 | srunner_add_suite(sr, ephemeris_suite()); 22 | srunner_add_suite(sr, decode_glo_suite()); 23 | srunner_add_suite(sr, set_suite()); 24 | srunner_add_suite(sr, gnss_time_test_suite()); 25 | srunner_add_suite(sr, signal_test_suite()); 26 | srunner_add_suite(sr, geoid_model_test_suite()); 27 | srunner_add_suite(sr, glo_map_test_suite()); 28 | srunner_add_suite(sr, shm_suite()); 29 | srunner_add_suite(sr, pvt_test_suite()); 30 | srunner_add_suite(sr, nav_meas_test_suite()); 31 | srunner_add_suite(sr, sid_set_test_suite()); 32 | srunner_add_suite(sr, status_report_suite()); 33 | srunner_add_suite(sr, log_suite()); 34 | srunner_add_suite(sr, gnss_time_cpp_test_suite()); 35 | 36 | srunner_set_fork_status(sr, CK_NOFORK); 37 | srunner_run_all(sr, CK_NORMAL); 38 | number_failed = srunner_ntests_failed(sr); 39 | srunner_free(sr); 40 | return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; 41 | } 42 | -------------------------------------------------------------------------------- /tests/check_nav_meas.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "check_suites.h" 8 | 9 | START_TEST(test_encode_lock_time) { 10 | u8 ret; 11 | 12 | ret = encode_lock_time(0.0); 13 | fail_unless( 14 | ret == 0, "Incorrect return (%" PRIu8 " vs %" PRIu8 ")", ret, (u8)0); 15 | 16 | ret = encode_lock_time(0.05); 17 | fail_unless( 18 | ret == 1, "Incorrect return (%" PRIu8 " vs %" PRIu8 ")", ret, (u8)1); 19 | 20 | ret = encode_lock_time(0.1); 21 | fail_unless( 22 | ret == 2, "Incorrect return (%" PRIu8 " vs %" PRIu8 ")", ret, (u8)2); 23 | 24 | ret = encode_lock_time(0.2); 25 | fail_unless( 26 | ret == 3, "Incorrect return (%" PRIu8 " vs %" PRIu8 ")", ret, (u8)3); 27 | 28 | ret = encode_lock_time(0.5); 29 | fail_unless( 30 | ret == 4, "Incorrect return (%" PRIu8 " vs %" PRIu8 ")", ret, (u8)4); 31 | 32 | ret = encode_lock_time(1.0); 33 | fail_unless( 34 | ret == 5, "Incorrect return (%" PRIu8 " vs %" PRIu8 ")", ret, (u8)5); 35 | 36 | ret = encode_lock_time(2.0); 37 | fail_unless( 38 | ret == 6, "Incorrect return (%" PRIu8 " vs %" PRIu8 ")", ret, (u8)6); 39 | 40 | ret = encode_lock_time(4.0); 41 | fail_unless( 42 | ret == 7, "Incorrect return (%" PRIu8 " vs %" PRIu8 ")", ret, (u8)7); 43 | 44 | ret = encode_lock_time(5.0); 45 | fail_unless( 46 | ret == 8, "Incorrect return (%" PRIu8 " vs %" PRIu8 ")", ret, (u8)8); 47 | 48 | ret = encode_lock_time(10.0); 49 | fail_unless( 50 | ret == 9, "Incorrect return (%" PRIu8 " vs %" PRIu8 ")", ret, (u8)9); 51 | 52 | ret = encode_lock_time(20.0); 53 | fail_unless( 54 | ret == 10, "Incorrect return (%" PRIu8 " vs %" PRIu8 ")", ret, (u8)10); 55 | 56 | ret = encode_lock_time(50.0); 57 | fail_unless( 58 | ret == 11, "Incorrect return (%" PRIu8 " vs %" PRIu8 ")", ret, (u8)11); 59 | 60 | ret = encode_lock_time(100.0); 61 | fail_unless( 62 | ret == 12, "Incorrect return (%" PRIu8 " vs %" PRIu8 ")", ret, (u8)12); 63 | 64 | ret = encode_lock_time(200.0); 65 | fail_unless( 66 | ret == 13, "Incorrect return (%" PRIu8 " vs %" PRIu8 ")", ret, (u8)13); 67 | 68 | ret = encode_lock_time(500.0); 69 | fail_unless( 70 | ret == 14, "Incorrect return (%" PRIu8 " vs %" PRIu8 ")", ret, (u8)14); 71 | 72 | ret = encode_lock_time(1000.0); 73 | fail_unless( 74 | ret == 15, "Incorrect return (%" PRIu8 " vs %" PRIu8 ")", ret, (u8)15); 75 | 76 | ret = encode_lock_time(DBL_MAX); 77 | fail_unless( 78 | ret == 15, "Incorrect return (%" PRIu8 " vs %" PRIu8 ")", ret, (u8)15); 79 | } 80 | END_TEST 81 | 82 | START_TEST(test_decode_lock_time) { 83 | double ret; 84 | 85 | ret = decode_lock_time(0); 86 | fail_unless(ret == 0.0, "Incorrect return (%f vs %f)", ret, 0.0); 87 | 88 | ret = decode_lock_time(0xF0); 89 | fail_unless(ret == 0.0, "Incorrect return (%f vs %f)", ret, 0.0); 90 | 91 | ret = decode_lock_time(1); 92 | fail_unless(ret == 0.032, "Incorrect return (%f vs %f)", ret, 0.032); 93 | 94 | ret = decode_lock_time(2); 95 | fail_unless(ret == 0.064, "Incorrect return (%f vs %f)", ret, 0.064); 96 | 97 | ret = decode_lock_time(3); 98 | fail_unless(ret == 0.128, "Incorrect return (%f vs %f)", ret, 0.128); 99 | 100 | ret = decode_lock_time(4); 101 | fail_unless(ret == 0.256, "Incorrect return (%f vs %f)", ret, 0.256); 102 | 103 | ret = decode_lock_time(5); 104 | fail_unless(ret == 0.512, "Incorrect return (%f vs %f)", ret, 0.512); 105 | 106 | ret = decode_lock_time(6); 107 | fail_unless(ret == 1.024, "Incorrect return (%f vs %f)", ret, 1.024); 108 | 109 | ret = decode_lock_time(7); 110 | fail_unless(ret == 2.048, "Incorrect return (%f vs %f)", ret, 2.048); 111 | 112 | ret = decode_lock_time(8); 113 | fail_unless(ret == 4.096, "Incorrect return (%f vs %f)", ret, 4.096); 114 | 115 | ret = decode_lock_time(9); 116 | fail_unless(ret == 8.192, "Incorrect return (%f vs %f)", ret, 8.192); 117 | 118 | ret = decode_lock_time(10); 119 | fail_unless(ret == 16.384, "Incorrect return (%f vs %f)", ret, 16.384); 120 | 121 | ret = decode_lock_time(11); 122 | fail_unless(ret == 32.768, "Incorrect return (%f vs %f)", ret, 32.768); 123 | 124 | ret = decode_lock_time(12); 125 | fail_unless(ret == 65.536, "Incorrect return (%f vs %f)", ret, 65.536); 126 | 127 | ret = decode_lock_time(13); 128 | fail_unless(ret == 131.072, "Incorrect return (%f vs %f)", ret, 131.072); 129 | 130 | ret = decode_lock_time(14); 131 | fail_unless(ret == 262.144, "Incorrect return (%f vs %f)", ret, 262.144); 132 | 133 | ret = decode_lock_time(15); 134 | fail_unless(ret == 524.288, "Incorrect return (%f vs %f)", ret, 524.288); 135 | } 136 | END_TEST 137 | 138 | START_TEST(test_roundtrip_lock_time) { 139 | const double value_to_encode = 260.0; 140 | u8 encoded_value; 141 | double decoded_value; 142 | 143 | encoded_value = encode_lock_time(value_to_encode); 144 | decoded_value = decode_lock_time(encoded_value); 145 | 146 | fail_unless(encoded_value == 13, 147 | "Incorrect return (%" PRIu8 " vs %" PRIu8 ")", 148 | encoded_value, 149 | (u8)13); 150 | 151 | fail_unless(decoded_value == 131.072, 152 | "Incorrect return (%f vs %f)", 153 | decoded_value, 154 | 131.072); 155 | 156 | fail_unless(decoded_value < value_to_encode, 157 | "Minimum lock time not less than original lock time (%f < %f)", 158 | decoded_value, 159 | value_to_encode); 160 | } 161 | END_TEST 162 | 163 | Suite *nav_meas_test_suite(void) { 164 | Suite *s = suite_create("Navigation Measurement"); 165 | TCase *tc_core = tcase_create("Core"); 166 | tcase_add_test(tc_core, test_encode_lock_time); 167 | tcase_add_test(tc_core, test_decode_lock_time); 168 | tcase_add_test(tc_core, test_roundtrip_lock_time); 169 | suite_add_tcase(s, tc_core); 170 | return s; 171 | } 172 | -------------------------------------------------------------------------------- /tests/check_pedantic.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | /* 34 | * This file exists to ensure that all library includes are valid C++. 35 | */ 36 | int main() { return 0; } 37 | -------------------------------------------------------------------------------- /tests/check_shm.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Swift Navigation Inc. 3 | * Contact: Swift Navigation 4 | * 5 | * This source is subject to the license found in the file 'LICENSE' which must 6 | * be distributed together with this source. All other rights reserved. 7 | * 8 | * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 9 | * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 10 | * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. 11 | */ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include "check_suites.h" 21 | 22 | START_TEST(test_shm_gps_decode_shi_ephemeris) { 23 | u32 sf1w3 = 0x3f122c34; 24 | u8 shi_ephemeris; 25 | 26 | shm_gps_decode_shi_ephemeris(sf1w3, &shi_ephemeris); 27 | 28 | fail_unless(shi_ephemeris == 0x2c, 29 | "shm_gps_decode_shi_ephemeris() returns 0x%x for 0x%x\n", 30 | shi_ephemeris, 31 | sf1w3); 32 | } 33 | END_TEST 34 | 35 | START_TEST(test_check_nav_dhi) { 36 | for (u8 dhi = 0; dhi < NAV_DHI_COUNT; ++dhi) { 37 | for (u16 ignored = 0; ignored <= UCHAR_MAX; ++ignored) { 38 | bool res = check_nav_dhi((dhi << 5), ignored); 39 | bool expected = (NAV_DHI_OK == dhi) || (ignored & 1 << dhi); 40 | fail_unless(res == expected, 41 | "check_nav_dhi(%" PRIu8 ", %" PRIu8 ") failed", 42 | (u8)(dhi << 5), 43 | (u8)ignored); 44 | } 45 | } 46 | } 47 | END_TEST 48 | 49 | Suite *shm_suite(void) { 50 | Suite *s = suite_create("SHM"); 51 | 52 | TCase *tc_core = tcase_create("Core"); 53 | tcase_add_test(tc_core, test_shm_gps_decode_shi_ephemeris); 54 | tcase_add_test(tc_core, test_check_nav_dhi); 55 | suite_add_tcase(s, tc_core); 56 | 57 | return s; 58 | } 59 | -------------------------------------------------------------------------------- /tests/check_sid_set.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "check_suites.h" 8 | #include "common/check_utils.h" 9 | 10 | START_TEST(test_sid_set_empty) { 11 | gnss_sid_set_t sid_set; 12 | sid_set_init(&sid_set); 13 | u32 count = sid_set_get_sat_count(&sid_set); 14 | 15 | fail_unless(count == 0, "count was not 0. Saw %u", count); 16 | } 17 | END_TEST 18 | 19 | START_TEST(test_sid_set) { 20 | gnss_signal_t sids[] = { 21 | {.code = CODE_GPS_L1CA, .sat = 1}, 22 | {.code = CODE_GPS_L2CM, .sat = 1}, 23 | {.code = CODE_GPS_L1CA, .sat = 2}, 24 | {.code = CODE_GPS_L2CM, .sat = 3}, 25 | {.code = CODE_GLO_L1OF, .sat = 1}, 26 | }; 27 | 28 | gnss_sid_set_t sid_set; 29 | sid_set_init(&sid_set); 30 | 31 | for (u32 i = 0; i < sizeof(sids) / sizeof(sids[0]); i++) { 32 | const gnss_signal_t sid = sids[i]; 33 | sid_set_add(&sid_set, sid); 34 | fail_unless(sid_set_get_sig_count(&sid_set) == i + 1); 35 | } 36 | 37 | u32 count = sid_set_get_sat_count(&sid_set); 38 | 39 | fail_unless(count == 4, "count was not 4. Saw %u", count); 40 | } 41 | END_TEST 42 | 43 | START_TEST(test_sid_set_contains) { 44 | gnss_signal_t sids[] = { 45 | {.code = CODE_GPS_L1CA, .sat = 1}, 46 | {.code = CODE_GPS_L2CM, .sat = 1}, 47 | {.code = CODE_GPS_L1CA, .sat = 2}, 48 | {.code = CODE_GPS_L2CM, .sat = 3}, 49 | {.code = CODE_GLO_L1OF, .sat = 1}, 50 | }; 51 | 52 | gnss_sid_set_t sid_set; 53 | sid_set_init(&sid_set); 54 | 55 | /* check that add works by adding sids one by one */ 56 | for (u32 i = 0; i < sizeof(sids) / sizeof(sids[0]); i++) { 57 | const gnss_signal_t sid = sids[i]; 58 | fail_unless(sid_set_contains(&sid_set, sid) == false, 59 | "%d: sid_set should not contain (code %d, sat %d)", 60 | i, 61 | sid.code, 62 | sid.sat); 63 | sid_set_add(&sid_set, sid); 64 | fail_unless(sid_set_contains(&sid_set, sid) == true, 65 | "%d: sid_set should contain (code %d, sat %d)", 66 | i, 67 | sid.code, 68 | sid.sat); 69 | } 70 | 71 | /* check that remove works by removing sids one by one */ 72 | for (u32 i = 0; i < sizeof(sids) / sizeof(sids[0]); i++) { 73 | const gnss_signal_t sid = sids[i]; 74 | fail_unless(sid_set_contains(&sid_set, sid) == true, 75 | "%d: sid_set should contain (code %d, sat %d)", 76 | i, 77 | sid.code, 78 | sid.sat); 79 | sid_set_remove(&sid_set, sid); 80 | fail_unless(sid_set_contains(&sid_set, sid) == false, 81 | "%d: sid_set should not contain (code %d, sat %d)", 82 | i, 83 | sid.code, 84 | sid.sat); 85 | } 86 | } 87 | END_TEST 88 | 89 | Suite *sid_set_test_suite(void) { 90 | Suite *s = suite_create("SID Set"); 91 | TCase *tc_core = tcase_create("Core"); 92 | tcase_add_test(tc_core, test_sid_set_empty); 93 | tcase_add_test(tc_core, test_sid_set); 94 | tcase_add_test(tc_core, test_sid_set_contains); 95 | suite_add_tcase(s, tc_core); 96 | return s; 97 | } 98 | -------------------------------------------------------------------------------- /tests/check_suites.h: -------------------------------------------------------------------------------- 1 | #ifndef CHECK_SUITES_H 2 | #define CHECK_SUITES_H 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | Suite* almanac_suite(void); 9 | Suite* coord_system_suite(void); 10 | Suite* bits_suite(void); 11 | Suite* edc_suite(void); 12 | Suite* linear_algebra_suite(void); 13 | Suite* ephemeris_suite(void); 14 | Suite* decode_glo_suite(void); 15 | Suite* ionosphere_suite(void); 16 | Suite* set_suite(void); 17 | Suite* gnss_time_test_suite(void); 18 | Suite* gnss_time_cpp_test_suite(void); 19 | Suite* signal_test_suite(void); 20 | Suite* geoid_model_test_suite(void); 21 | Suite* glo_map_test_suite(void); 22 | Suite* shm_suite(void); 23 | Suite* troposphere_suite(void); 24 | Suite* pvt_test_suite(void); 25 | Suite* nav_meas_test_suite(void); 26 | Suite* nav_meas_calc_test_suite(void); 27 | Suite* sid_set_test_suite(void); 28 | Suite* status_report_suite(void); 29 | Suite* log_suite(void); 30 | 31 | #ifdef __cplusplus 32 | } /* extern "C" */ 33 | #endif 34 | 35 | #endif /* CHECK_SUITES_H */ 36 | -------------------------------------------------------------------------------- /tests/check_troposphere.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "check_suites.h" 8 | 9 | START_TEST(test_calc_troposphere) { 10 | const double d_tol = 1e-4; 11 | 12 | /* some tests against "true" values computed with UNB3M.f */ 13 | /* http://www2.unb.ca/gge/Personnel/Santos/UNB_pack.pdf */ 14 | 15 | double lat = 40 * D2R; 16 | double h = 1300.0; 17 | double doy = 32.5; 18 | double el = 45 * D2R; 19 | double d_true = 2.8567; 20 | 21 | double d_tropo = calc_troposphere(doy, lat, h, el); 22 | 23 | fail_unless( 24 | fabs(d_tropo - d_true) < d_tol, 25 | "Distance didn't match hardcoded correct values %0.5f. Saw: %.5f\n", 26 | d_true, 27 | d_tropo); 28 | 29 | lat = -10 * D2R; 30 | h = 0.0; 31 | doy = 180.5; 32 | el = 20 * D2R; 33 | d_true = 7.4942; 34 | 35 | d_tropo = calc_troposphere(doy, lat, h, el); 36 | 37 | fail_unless( 38 | fabs(d_tropo - d_true) < d_tol, 39 | "Distance didn't match hardcoded correct values %0.5f. Saw: %.5f\n", 40 | d_true, 41 | d_tropo); 42 | 43 | lat = 75 * D2R; 44 | h = 0.0; 45 | doy = 50.5; 46 | el = 10 * D2R; 47 | d_true = 12.90073; 48 | 49 | d_tropo = calc_troposphere(doy, lat, h, el); 50 | 51 | fail_unless( 52 | fabs(d_tropo - d_true) < d_tol, 53 | "Distance didn't match hardcoded correct values %0.5f. Saw: %.5f\n", 54 | d_true, 55 | d_tropo); 56 | 57 | /* altitude sanity tests */ 58 | double max_tropo_correction = 30.0; 59 | h = -5000; 60 | d_tropo = calc_troposphere(doy, lat, h, el); 61 | 62 | fail_unless(fabs(d_tropo) < max_tropo_correction, 63 | "Sanity test fail at altitude %0.5f. : Correction was %.5f\n", 64 | h, 65 | d_tropo); 66 | 67 | h = 12000; 68 | d_tropo = calc_troposphere(doy, lat, h, el); 69 | 70 | fail_unless(fabs(d_tropo) < max_tropo_correction, 71 | "Sanity test fail at altitude %0.5f. : Correction was %.5f\n", 72 | h, 73 | d_tropo); 74 | 75 | /* satellite elevation sanity tests */ 76 | h = 100; 77 | double elevation_testcases[] = {1e-3, 1e-4, 1e-5, 0, -1e3, -0.1}; 78 | max_tropo_correction = 100.0; 79 | 80 | for (u8 i = 0; i < sizeof(elevation_testcases) / sizeof(double); i++) { 81 | el = elevation_testcases[i]; 82 | d_tropo = calc_troposphere(doy, lat, h, el); 83 | fail_unless(fabs(d_tropo) < max_tropo_correction, 84 | "Sanity test fail at satellite elevation %0.5f. : Correction " 85 | "was %.5f\n", 86 | el, 87 | d_tropo); 88 | } 89 | } 90 | END_TEST 91 | 92 | Suite *troposphere_suite(void) { 93 | Suite *s = suite_create("Troposphere"); 94 | 95 | TCase *tc_core = tcase_create("Core"); 96 | tcase_add_test(tc_core, test_calc_troposphere); 97 | suite_add_tcase(s, tc_core); 98 | 99 | return s; 100 | } 101 | -------------------------------------------------------------------------------- /tests/common/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | swift_add_test_library(check-utils SOURCES check_utils.c) 2 | target_link_libraries(check-utils PUBLIC swiftnav::swiftnav) -------------------------------------------------------------------------------- /tests/common/check_utils.c: -------------------------------------------------------------------------------- 1 | #include "check_utils.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | /*#define epsilon 0.0001*/ 10 | #define EPSILON 1e-5 11 | 12 | u8 within_epsilon(double a, double b) { 13 | if (fabs(a - b) < EPSILON) { 14 | return 1; 15 | } 16 | return 0; 17 | } 18 | 19 | u8 arr_within_epsilon(u32 n, const double *a, const double *b) { 20 | for (u32 i = 0; i < n; i++) { 21 | if (!within_epsilon(a[i], b[i])) { 22 | return false; 23 | } 24 | } 25 | return true; 26 | } 27 | 28 | void seed_rng(void) { srand((unsigned int)time(NULL)); } 29 | 30 | double frand(double fmin, double fmax) { 31 | double f = (double)rand() / RAND_MAX; 32 | return fmin + f * (fmax - fmin); 33 | } 34 | 35 | void arr_frand(u32 n, double fmin, double fmax, double *v) { 36 | for (u32 i = 0; i < n; i++) { 37 | v[i] = frand(fmin, fmax); 38 | } 39 | } 40 | 41 | u32 sizerand(u32 sizemax) { 42 | double f = (double)rand() / RAND_MAX; 43 | return (u32)ceil(f * sizemax); 44 | } 45 | -------------------------------------------------------------------------------- /tests/common/check_utils.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | u8 within_epsilon(double a, double b); 4 | u8 arr_within_epsilon(u32 n, const double *a, const double *b); 5 | void seed_rng(void); 6 | double frand(double fmin, double fmax); 7 | void arr_frand(u32 n, double fmin, double fmax, double *v); 8 | u32 sizerand(u32 sizemax); 9 | -------------------------------------------------------------------------------- /tools/check2junit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # 2016, Georg Sauthoff , GPLv3+ 4 | 5 | import copy 6 | import lxml 7 | from lxml.builder import E 8 | from lxml import etree 9 | import re 10 | import sys 11 | 12 | # necessary for xpath 13 | ns = etree.FunctionNamespace('http://check.sourceforge.net/ns') 14 | ns.prefix='c' 15 | 16 | # not necessary for xpath 17 | #etree.register_namespace('c', 'http://check.sourceforge.net/ns') 18 | 19 | 20 | # see also 21 | # http://nelsonwells.net/2012/09/how-jenkins-ci-parses-and-displays-junit-output/ 22 | # for a discussion of the JUnit format, as used by Jenkins 23 | 24 | def mk_testcase(case): 25 | name = case.xpath('./c:id')[0].text 26 | iteration = case.xpath('./c:iteration')[0].text 27 | if iteration != '0': 28 | name = name + '_' + iteration 29 | fn = case.xpath('./c:fn')[0].text 30 | fn = re.sub('\.[^.]+:.+$', '', fn) 31 | result = case.attrib['result'] 32 | if result == 'success': 33 | duration = case.xpath('./c:duration')[0].text 34 | else: 35 | duration = '0' 36 | r = E('testcase', name=name, classname=fn, time=duration) 37 | if result == 'failure': 38 | message = case.xpath('./c:message')[0].text 39 | err = E('error', message=message) 40 | r.append(err) 41 | return r 42 | 43 | def mk_testsuite(suite, timestamp): 44 | title = suite.xpath('./c:title')[0] 45 | tests = suite.xpath('./c:test') 46 | failures = suite.xpath('./c:test[@result="failure"]') 47 | r = E('testsuite', name=title.text, timestamp=timestamp, 48 | tests=str(tests.__len__()), failures=str(failures.__len__())) 49 | for test in tests: 50 | r.append(mk_testcase(test)) 51 | return r 52 | 53 | def mk_testsuites_P(r, ts): 54 | datetime = ts.xpath('./c:datetime')[0] 55 | timestamp = datetime.text.replace(' ', 'T') 56 | suites = ts.xpath('./c:suite') 57 | for suite in suites: 58 | r.append(mk_testsuite(suite, timestamp)) 59 | return r 60 | 61 | def mk_testsuites(fs): 62 | if type(fs) is list: 63 | filenames = fs 64 | else: 65 | filenames = [fs] 66 | r = E('testsuites') 67 | for filename in filenames: 68 | d = etree.parse(filename) 69 | root = d.getroot() 70 | mk_testsuites_P(r, root) 71 | return r 72 | 73 | def main(argv): 74 | if '-h' in argv or '--help' in argv: 75 | print('''Convert one or many libcheck XML reports into JUnit 76 | compatible output (as understood by Jenkins)''') 77 | return 0 78 | print('''''') 80 | etree.dump(mk_testsuites(argv[1:])) 81 | return 0 82 | 83 | 84 | if __name__ == '__main__': 85 | sys.exit(main(sys.argv)) 86 | -------------------------------------------------------------------------------- /tools/requirements.txt: -------------------------------------------------------------------------------- 1 | # Required by check2junit 2 | lxml~=4.2.5 3 | --------------------------------------------------------------------------------