├── .bazelrc ├── .clang-format ├── .gitattributes ├── .github └── workflows │ └── release_build.yml ├── .gitignore ├── BUILD ├── CMakeLists.txt ├── LICENSE ├── WORKSPACE ├── bazel ├── BUILD ├── examples_dependencies.bzl ├── examples_repositories.bzl └── repositories.bzl ├── c ├── .bazelrc ├── BUILD ├── CMakeLists.txt ├── Makefile ├── WORKSPACE ├── bazel │ ├── BUILD │ └── repositories.bzl ├── examples │ ├── BUILD │ ├── CMakeLists.txt │ ├── connection_retry.c │ ├── external_cmake_project │ │ ├── CMakeLists.txt │ │ └── main.c │ └── simple_polaris_client.c ├── src │ └── point_one │ │ └── polaris │ │ ├── polaris.c │ │ ├── polaris.h │ │ ├── polaris_internal.c │ │ ├── polaris_internal.h │ │ ├── portability.c │ │ ├── portability.h │ │ ├── socket.h │ │ ├── socket_freertos.h │ │ └── socket_posix.h └── test │ ├── application_base.py │ ├── run_unit_tests.sh │ ├── test_connection_retry.py │ └── test_simple_polaris_client.py ├── cmake ├── FindGflags.cmake └── FindGlog.cmake ├── compilers ├── BUILD.bazel ├── arm │ ├── BUILD.bazel │ ├── dependencies.bzl │ ├── linaro_linux_gcc_aarch64 │ │ ├── BUILD.bazel │ │ ├── aarch64-linux-gnu-ar │ │ ├── aarch64-linux-gnu-as │ │ ├── aarch64-linux-gnu-gcc │ │ ├── aarch64-linux-gnu-ld │ │ ├── aarch64-linux-gnu-nm │ │ ├── aarch64-linux-gnu-objcopy │ │ ├── aarch64-linux-gnu-objdump │ │ ├── aarch64-linux-gnu-strip │ │ ├── cc_toolchain_config.bzl │ │ └── dependencies.bzl │ └── linaro_linux_gcc_armv7 │ │ ├── BUILD.bazel │ │ ├── arm-linux-gnueabihf-ar │ │ ├── arm-linux-gnueabihf-as │ │ ├── arm-linux-gnueabihf-gcc │ │ ├── arm-linux-gnueabihf-ld │ │ ├── arm-linux-gnueabihf-nm │ │ ├── arm-linux-gnueabihf-objcopy │ │ ├── arm-linux-gnueabihf-objdump │ │ ├── arm-linux-gnueabihf-strip │ │ ├── cc_toolchain_config.bzl │ │ └── dependencies.bzl ├── dependencies.bzl └── k8 │ ├── BUILD.bazel │ └── cc_toolchain_config.bzl ├── docs ├── septentrio_configuration.png ├── septentrio_corrections.png ├── septentrio_rtk_fix.png └── septentrio_rxtools_example.png ├── examples ├── BUILD ├── CMakeLists.txt ├── data │ └── AsteRx_m2_config.txt ├── external_cmake_project │ ├── CMakeLists.txt │ └── main.cc ├── ntrip │ ├── BUILD │ ├── CMakeLists.txt │ ├── connection.cc │ ├── connection.h │ ├── connection_manager.cc │ ├── connection_manager.h │ ├── header.h │ ├── index.html │ ├── mime_types.cc │ ├── mime_types.h │ ├── ntrip-proxy.service │ ├── ntrip_example.cc │ ├── ntrip_example_test_client.cc │ ├── ntrip_proxy.sh │ ├── ntrip_server.cc │ ├── ntrip_server.h │ ├── reply.cc │ ├── reply.h │ ├── request.h │ ├── request_handler.cc │ ├── request_handler.h │ ├── request_parser.cc │ └── request_parser.h ├── septentrio │ ├── BUILD │ ├── sbf_framer.h │ ├── septentrio_interface.h │ └── septentrio_service.h ├── septentrio_example.cc ├── serial_port_example.cc ├── simple_asio_serial_port.h ├── simple_embedded_client.cc └── simple_polaris_client.cc ├── readme.md ├── src └── point_one │ └── polaris │ ├── polaris_client.cc │ ├── polaris_client.h │ ├── polaris_interface.cc │ └── polaris_interface.h ├── test ├── cpp_application_base.py ├── run_unit_tests.sh └── test_simple_polaris_cpp_client.py └── third_party ├── BUILD ├── CMakeLists.txt └── septentrio ├── CMakeLists.txt ├── Makefile ├── ReadMe.txt ├── crc.c ├── crc.h ├── measepoch.h ├── measepochconfig.h ├── sbfdef.h ├── sbfread.c ├── sbfread.h ├── sbfread_meas.c ├── sbfsigtypes.h ├── sbfsvid.c ├── sbfsvid.h ├── ssntypes.h └── sviddef.h /.bazelrc: -------------------------------------------------------------------------------- 1 | # Cross-compilation configurations (e.g., bazel build --config=aarch64). 2 | build:armv7hf --crosstool_top=//compilers:toolchain 3 | build:armv7hf --host_crosstool_top=@bazel_tools//tools/cpp:toolchain 4 | build:armv7hf --cpu=armeabi-v7a --compiler=gcc 5 | build:armv7hf --spawn_strategy=local 6 | 7 | build:aarch64 --crosstool_top=//compilers:toolchain 8 | build:aarch64 --host_crosstool_top=@bazel_tools//tools/cpp:toolchain 9 | build:aarch64 --cpu=aarch64-linux-gnu --compiler=gcc 10 | build:aarch64 --spawn_strategy=local 11 | 12 | # Command-line argument aliases (requires Bazel 3.7.0 or newer). 13 | # 14 | # For example, you may specify: 15 | # bazel build -c opt --polaris_enable_tls=False //:polaris_client 16 | # instead of: 17 | # bazel build -c opt --//c:polaris_enable_tls=False //:polaris_client 18 | #build --flag_alias=polaris_enable_tls=//c:polaris_enable_tls 19 | 20 | # Enable address sanitizer (ASAN). 21 | # 22 | # When using, you may also wish to disable optimizations (`-c dbg` or 23 | # `--copt=-O0`). This may significantly impact performance, but may be 24 | # necessary to pinpoint certain errors in highly optimized sections of code. 25 | build:asan --copt=-g --copt=-fsanitize=address --linkopt=-fsanitize=address --linkopt=-static-libasan 26 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | BasedOnStyle: Google 4 | IndentPPDirectives: AfterHash 5 | --- 6 | Language: Proto 7 | BasedOnStyle: Google 8 | ... 9 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | cmake/* linguist-vendored 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Bazel 2 | bazel-* 3 | 4 | # CMake 5 | build/ 6 | 7 | # Python 8 | *.pyc 9 | .idea/ 10 | venv/ 11 | 12 | # Visual Studio Code 13 | .vscode 14 | # Clion 15 | .clwb/ 16 | 17 | # Build Output 18 | *.o 19 | c/examples/simple_polaris_client 20 | c/examples/connection_retry 21 | -------------------------------------------------------------------------------- /BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//visibility:public"]) 2 | 3 | # Polaris client C++ library. 4 | # 5 | # TLS support is enabled by default, but may be disabled with the following 6 | # command-line argument: 7 | # --//c:polaris_enable_tls=False 8 | cc_library( 9 | name = "polaris_client", 10 | srcs = [ 11 | "src/point_one/polaris/polaris_client.cc", 12 | "src/point_one/polaris/polaris_interface.cc", 13 | ], 14 | hdrs = [ 15 | "src/point_one/polaris/polaris_client.h", 16 | "src/point_one/polaris/polaris_interface.h", 17 | ], 18 | copts = select({ 19 | "//c:tls_enabled": ["-DPOLARIS_USE_TLS=1"], 20 | "//conditions:default": [], 21 | }), 22 | includes = [ 23 | "src", 24 | ], 25 | deps = [ 26 | "//c:polaris_client", 27 | "@com_github_google_glog//:glog", 28 | ], 29 | ) 30 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) Point One Navigation - All Rights Reserved 2 | cmake_minimum_required(VERSION 3.6) 3 | 4 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/") 5 | 6 | # Option definitions. 7 | option(BUILD_SHARED_LIBS "Build shared libraries instead of static libraries." 8 | ON) 9 | 10 | option(POLARIS_BUILD_EXAMPLES "Build example applications." ON) 11 | 12 | # Backwards compatibility. BUILD_EXAMPLES is deprecated and may be removed in a 13 | # future release. 14 | if (DEFINED BUILD_EXAMPLES AND BUILD_EXAMPLES) 15 | set(POLARIS_BUILD_EXAMPLES ${BUILD_EXAMPLES}) 16 | endif() 17 | 18 | # Set toolchain parameters before calling project(). 19 | set(CMAKE_CXX_STANDARD 11) 20 | 21 | # Define the project and setup the compiler toolchain. 22 | project(p1_polaris_client) 23 | 24 | # Set compilation flags. 25 | if (MSVC) 26 | add_compile_options(/W4 /WX) 27 | else() 28 | add_compile_options(-Wall -Werror -Wno-unused-variable) 29 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -pthread") 30 | endif() 31 | 32 | ################################################################################ 33 | # Check for dependencies. 34 | ################################################################################ 35 | 36 | # Find gflags. 37 | option(GFLAGS_PREFER_EXPORTED_GFLAGS_CMAKE_CONFIGURATION TRUE) 38 | find_package(Gflags REQUIRED) 39 | include_directories(${GFLAGS_INCLUDE_DIRS}) 40 | 41 | # Find glog (requires gflags). 42 | option(GLOG_PREFER_EXPORTED_GLOG_CMAKE_CONFIGURATION TRUE) 43 | find_package(Glog REQUIRED) 44 | include_directories(${GLOG_INCLUDE_DIRS}) 45 | 46 | ################################################################################ 47 | # Library Definitions 48 | ################################################################################ 49 | 50 | # Add the C library, used by the C++ library. 51 | add_subdirectory(c) 52 | 53 | # Polaris client C++ library - all messages and supporting code. 54 | add_library(polaris_cpp_client 55 | src/point_one/polaris/polaris_client.cc 56 | src/point_one/polaris/polaris_interface.cc) 57 | target_include_directories(polaris_client PUBLIC ${PROJECT_SOURCE_DIR}/src) 58 | if (MSVC) 59 | target_compile_definitions(polaris_cpp_client PRIVATE BUILDING_DLL) 60 | endif() 61 | if (POLARIS_ENABLE_TLS) 62 | target_compile_definitions(polaris_cpp_client PUBLIC POLARIS_USE_TLS=1) 63 | endif() 64 | target_link_libraries(polaris_cpp_client PUBLIC polaris_client) 65 | target_link_libraries(polaris_cpp_client PUBLIC ${GLOG_LIBRARIES}) 66 | target_link_libraries(polaris_cpp_client PUBLIC ${GFLAGS_LIBRARIES}) 67 | 68 | # Install targets. 69 | install(TARGETS polaris_cpp_client 70 | LIBRARY DESTINATION lib) 71 | 72 | install(DIRECTORY src/point_one DESTINATION include 73 | FILES_MATCHING PATTERN "*.h") 74 | 75 | ################################################################################ 76 | # Example Applications 77 | ################################################################################ 78 | 79 | if (POLARIS_BUILD_EXAMPLES) 80 | add_subdirectory(examples) 81 | endif() 82 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Point One Navigation 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /WORKSPACE: -------------------------------------------------------------------------------- 1 | workspace(name = "polaris") 2 | 3 | #------------------------------------------------------------------------------- 4 | # Point One cross-compilation support 5 | # 6 | # See https://github.com/curtismuntz/bazel_compilers/tree/boost-example. 7 | load("//compilers:dependencies.bzl", "cross_compiler_dependencies") 8 | 9 | cross_compiler_dependencies() 10 | 11 | #------------------------------------------------------------------------------- 12 | # Import Polaris Client dependencies. 13 | load("//bazel:repositories.bzl", polaris_dependencies = "dependencies") 14 | 15 | polaris_dependencies() 16 | 17 | #------------------------------------------------------------------------------- 18 | # Import dependencies for example applications (not needed by the library 19 | # itself). 20 | load("//bazel:examples_repositories.bzl", polaris_examples_dependencies = "dependencies") 21 | 22 | polaris_examples_dependencies() 23 | 24 | load("//bazel:examples_dependencies.bzl", load_polaris_examples_dependencies = "load_dependencies") 25 | 26 | load_polaris_examples_dependencies() 27 | -------------------------------------------------------------------------------- /bazel/BUILD: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PointOneNav/polaris/810845a3e8cfaa41da81dffed31c6ee62933b431/bazel/BUILD -------------------------------------------------------------------------------- /bazel/examples_dependencies.bzl: -------------------------------------------------------------------------------- 1 | load("@com_github_nelhage_rules_boost//:boost/boost.bzl", "boost_deps") 2 | 3 | def load_dependencies(): 4 | # Imports: 5 | # - bazel_skylib (v0.9.0 - 2019/7/12) 6 | # - net_zlib_zlib (v1.2.11 - 2017/1/15) 7 | # - org_bzip_bzip2 (v1.0.6 - 2018/11/3) 8 | # - org_lzma_lzma (v5.2.3) 9 | # - boost (v1.68.0 - 2018/8/9) 10 | boost_deps() 11 | -------------------------------------------------------------------------------- /bazel/examples_repositories.bzl: -------------------------------------------------------------------------------- 1 | load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") 2 | load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe") 3 | 4 | def dependencies(): 5 | #--------------------------------------------------------------------------- 6 | # Boost 7 | maybe( 8 | git_repository, 9 | name = "com_github_nelhage_rules_boost", 10 | # 2019/10/2 = Boost v1.68.0 11 | commit = "9f9fb8b2f0213989247c9d5c0e814a8451d18d7f", 12 | remote = "https://github.com/nelhage/rules_boost", 13 | repo_mapping = {"@net_zlib_zlib": "@p1_zlib"}, 14 | shallow_since = "1570056263 -0700", 15 | ) 16 | -------------------------------------------------------------------------------- /bazel/repositories.bzl: -------------------------------------------------------------------------------- 1 | load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") 2 | load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") 3 | load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe") 4 | 5 | def dependencies(): 6 | #--------------------------------------------------------------------------- 7 | # Bazel build file formatting tool (buildifier). 8 | # 9 | # Needed for //compilers cross-compilation dependencies. 10 | maybe( 11 | http_archive, 12 | name = "com_github_bazelbuild_buildtools", 13 | sha256 = "a5fca3f810588b441a647cf601a42ca98a75aa0681c2e9ade3ce9187d47b506e", 14 | strip_prefix = "buildtools-3.4.0", 15 | # v3.4.0 - 2020/7/18 16 | url = "https://github.com/bazelbuild/buildtools/archive/3.4.0.zip", 17 | ) 18 | 19 | #--------------------------------------------------------------------------- 20 | # Google Commandline Flags (gflags) 21 | # 22 | # Required by glog. 23 | maybe( 24 | http_archive, 25 | name = "com_github_gflags_gflags", 26 | sha256 = "34af2f15cf7367513b352bdcd2493ab14ce43692d2dcd9dfc499492966c64dcf", 27 | strip_prefix = "gflags-2.2.2", 28 | # 2018/11/11 29 | urls = ["https://github.com/gflags/gflags/archive/v2.2.2.tar.gz"], 30 | ) 31 | 32 | #--------------------------------------------------------------------------- 33 | # Google Logging Library (glog) 34 | # 35 | # Optional; may be omitted if POLARIS_HAVE_GLOG is not defined. 36 | # 37 | # Note: Explicitly disabling shallow_since on this repo to avoid a known 38 | # issue between recent versions of git and Bazel that causes some needed 39 | # commit data to be omitted incorrectly, resulting in unexpected "Could not 40 | # parse object" errors. See 41 | # https://github.com/bazelbuild/bazel/issues/10292. 42 | maybe( 43 | git_repository, 44 | name = "com_github_google_glog", 45 | # 2020/5/12 46 | commit = "0a2e5931bd5ff22fd3bf8999eb8ce776f159cda6", 47 | remote = "https://github.com/google/glog.git", 48 | ) 49 | 50 | #--------------------------------------------------------------------------- 51 | # Google BoringSSL 52 | # 53 | # Optional; only used if the system is compiled with POLARIS_USE_SSL 54 | # defined. 55 | maybe( 56 | git_repository, 57 | name = "boringssl", 58 | # 2024/3/25 59 | commit = "54f64295218630fd869b3a079d9dfb5abfe61324", 60 | remote = "https://boringssl.googlesource.com/boringssl", 61 | shallow_since = "1711401451 +0000", 62 | ) 63 | -------------------------------------------------------------------------------- /c/.bazelrc: -------------------------------------------------------------------------------- 1 | # Enable address sanitizer (ASAN). 2 | # 3 | # When using, you may also wish to disable optimizations (`-c dbg` or 4 | # `--copt=-O0`). This may significantly impact performance, but may be 5 | # necessary to pinpoint certain errors in highly optimized sections of code. 6 | build:asan --copt=-g --copt=-fsanitize=address --linkopt=-fsanitize=address --linkopt=-static-libasan 7 | -------------------------------------------------------------------------------- /c/BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//visibility:public"]) 2 | 3 | load("@bazel_skylib//rules:common_settings.bzl", "bool_flag") 4 | 5 | # Option to disable _all_ print messages: 6 | # --//:polaris_enable_print [enabled; default] 7 | # --//:polaris_enable_print=True [enabled; default] 8 | # --//:polaris_enable_print=False [disabled] 9 | # --no//:polaris_enable_print [disabled] 10 | bool_flag( 11 | name = "polaris_enable_print", 12 | build_setting_default = True, 13 | ) 14 | 15 | config_setting( 16 | name = "print_enabled", 17 | flag_values = { 18 | ":polaris_enable_print": "True", 19 | }, 20 | ) 21 | 22 | # Option to enable/disable TLS support (enabled by default): 23 | # --//:polaris_enable_tls [enabled; default] 24 | # --//:polaris_enable_tls=True [enabled; default] 25 | # --//:polaris_enable_tls=False [disabled] 26 | # --no//:polaris_enable_tls [disabled] 27 | bool_flag( 28 | name = "polaris_enable_tls", 29 | build_setting_default = True, 30 | ) 31 | 32 | config_setting( 33 | name = "tls_enabled", 34 | flag_values = { 35 | ":polaris_enable_tls": "True", 36 | }, 37 | ) 38 | 39 | # Polaris client C library - all messages and supporting code. 40 | # 41 | # TLS support is enabled by default, but may be disabled with the following 42 | # command-line argument: 43 | # --//:polaris_enable_tls=False 44 | cc_library( 45 | name = "polaris_client", 46 | deps = select({ 47 | ":tls_enabled": [":polaris_client_tls"], 48 | "//conditions:default": [":polaris_client_no_tls"], 49 | }), 50 | ) 51 | 52 | # Polaris client C library - all messages and supporting code - with TLS 53 | # enabled. 54 | cc_library( 55 | name = "polaris_client_tls", 56 | srcs = glob(["src/**/*.c"]), 57 | hdrs = glob(["src/**/*.h"]), 58 | copts = ["-DPOLARIS_USE_TLS=1"] + 59 | select({ 60 | ":print_enabled": [], 61 | "//conditions:default": ["-DPOLARIS_NO_PRINT"], 62 | }), 63 | includes = ["src"], 64 | deps = ["@boringssl//:ssl"], 65 | ) 66 | 67 | # Polaris client C library - all messages and supporting code - _without_ TLS 68 | # enabled (not recommended). 69 | cc_library( 70 | name = "polaris_client_no_tls", 71 | srcs = glob(["src/**/*.c"]), 72 | hdrs = glob(["src/**/*.h"]), 73 | copts = select({ 74 | ":print_enabled": [], 75 | "//conditions:default": ["-DPOLARIS_NO_PRINT"], 76 | }), 77 | includes = ["src"], 78 | ) 79 | -------------------------------------------------------------------------------- /c/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) Point One Navigation - All Rights Reserved 2 | cmake_minimum_required(VERSION 3.6) 3 | 4 | # Option definitions. 5 | option(BUILD_SHARED_LIBS "Build shared libraries instead of static libraries." 6 | ON) 7 | 8 | option(POLARIS_BUILD_EXAMPLES "Build example applications." ON) 9 | 10 | option(POLARIS_ENABLE_PRINT 11 | "Enable Polaris debug/trace print messages." ON) 12 | 13 | option(POLARIS_ENABLE_TLS "Enable TLS support when connecting to Polaris." ON) 14 | 15 | # Backwards compatibility. BUILD_EXAMPLES is deprecated and may be removed in a 16 | # future release. 17 | if (DEFINED BUILD_EXAMPLES AND BUILD_EXAMPLES) 18 | set(POLARIS_BUILD_EXAMPLES ${BUILD_EXAMPLES}) 19 | endif() 20 | 21 | # Define the project and setup the compiler toolchain. 22 | project(p1_polaris_c_client) 23 | 24 | # Set compilation flags. 25 | if (MSVC) 26 | add_compile_options(/W4 /WX) 27 | else() 28 | add_compile_options(-Wall -Werror) 29 | endif() 30 | 31 | if(NOT POLARIS_ENABLE_PRINT) 32 | add_compile_definitions(POLARIS_NO_PRINT) 33 | endif() 34 | 35 | ################################################################################ 36 | # Check for dependencies. 37 | ################################################################################ 38 | 39 | # Find OpenSSL (or BoringSSL). 40 | if (POLARIS_ENABLE_TLS) 41 | find_package(OpenSSL REQUIRED) 42 | endif() 43 | 44 | ################################################################################ 45 | # Library Definitions 46 | ################################################################################ 47 | 48 | # Polaris client C library - all messages and supporting code. 49 | add_library(polaris_client 50 | src/point_one/polaris/polaris.c 51 | src/point_one/polaris/polaris_internal.c 52 | src/point_one/polaris/portability.c) 53 | target_include_directories(polaris_client PUBLIC ${PROJECT_SOURCE_DIR}/src) 54 | if (MSVC) 55 | target_compile_definitions(polaris_client PRIVATE BUILDING_DLL) 56 | endif() 57 | if (POLARIS_ENABLE_TLS) 58 | target_compile_definitions(polaris_client PUBLIC POLARIS_USE_TLS=1) 59 | target_include_directories(polaris_client PRIVATE ${OPENSSL_INCLUDE_DIR}) 60 | target_link_libraries(polaris_client PUBLIC ${OPENSSL_LIBRARIES}) 61 | endif() 62 | 63 | # Install targets. 64 | install(TARGETS polaris_client 65 | LIBRARY DESTINATION lib) 66 | 67 | install(DIRECTORY src/point_one DESTINATION include 68 | FILES_MATCHING PATTERN "*.h") 69 | 70 | ################################################################################ 71 | # Example Applications 72 | ################################################################################ 73 | 74 | if (POLARIS_BUILD_EXAMPLES) 75 | add_subdirectory(examples) 76 | endif() 77 | -------------------------------------------------------------------------------- /c/Makefile: -------------------------------------------------------------------------------- 1 | SRC_DIR=src 2 | 3 | SOURCES=$(SRC_DIR)/point_one/polaris/polaris.c \ 4 | $(SRC_DIR)/point_one/polaris/polaris_internal.c \ 5 | $(SRC_DIR)/point_one/polaris/portability.c 6 | 7 | OBJECTS=$(patsubst %.c,%.o,$(SOURCES)) 8 | 9 | APPLICATIONS=examples/simple_polaris_client \ 10 | examples/connection_retry 11 | 12 | CFLAGS?=-Wall 13 | 14 | .PHONY: all 15 | all: $(APPLICATIONS) 16 | 17 | .PHONY: clean 18 | clean: 19 | rm -f $(OBJECTS) 20 | rm -f $(APPLICATIONS) 21 | 22 | .PHONY: print_applications 23 | print_applications: 24 | @echo $(APPLICATIONS) 25 | 26 | examples/%: examples/%.c $(OBJECTS) 27 | gcc -o $@ -I$(SRC_DIR) $(CFLAGS) $^ 28 | 29 | %.o: %.c 30 | gcc -o $@ -I$(SRC_DIR) $(CFLAGS) -c $^ 31 | -------------------------------------------------------------------------------- /c/WORKSPACE: -------------------------------------------------------------------------------- 1 | workspace(name = "p1_polaris_c_client") 2 | 3 | #------------------------------------------------------------------------------- 4 | # Import Polaris Client dependencies. 5 | load("//bazel:repositories.bzl", polaris_dependencies = "dependencies") 6 | 7 | polaris_dependencies() 8 | -------------------------------------------------------------------------------- /c/bazel/BUILD: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PointOneNav/polaris/810845a3e8cfaa41da81dffed31c6ee62933b431/c/bazel/BUILD -------------------------------------------------------------------------------- /c/bazel/repositories.bzl: -------------------------------------------------------------------------------- 1 | load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") 2 | load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") 3 | load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe") 4 | 5 | def dependencies(): 6 | #--------------------------------------------------------------------------- 7 | # Bazel Skylib (used by the Bazel build system - not a software dependency) 8 | maybe( 9 | http_archive, 10 | name = "bazel_skylib", 11 | urls = [ 12 | "https://github.com/bazelbuild/bazel-skylib/releases/download/1.0.3/bazel-skylib-1.0.3.tar.gz", 13 | "https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.0.3/bazel-skylib-1.0.3.tar.gz", 14 | ], 15 | sha256 = "1c531376ac7e5a180e0237938a2536de0c54d93f5c278634818e0efc952dd56c", 16 | ) 17 | 18 | #--------------------------------------------------------------------------- 19 | # Google BoringSSL 20 | # 21 | # Optional; only used if the system is compiled with POLARIS_USE_SSL 22 | # defined. 23 | maybe( 24 | git_repository, 25 | name = "boringssl", 26 | # 2024/3/25 27 | commit = "54f64295218630fd869b3a079d9dfb5abfe61324", 28 | remote = "https://boringssl.googlesource.com/boringssl", 29 | shallow_since = "1711401451 +0000", 30 | ) 31 | -------------------------------------------------------------------------------- /c/examples/BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//visibility:public"]) 2 | 3 | # Simple client example with no connection error detection logic. 4 | cc_binary( 5 | name = "simple_polaris_client", 6 | srcs = ["simple_polaris_client.c"], 7 | deps = [ 8 | "//:polaris_client_tls", 9 | ], 10 | ) 11 | 12 | # Example application including connection timeout and retry logic. 13 | cc_binary( 14 | name = "connection_retry", 15 | srcs = ["connection_retry.c"], 16 | deps = [ 17 | "//:polaris_client_tls", 18 | ], 19 | ) 20 | -------------------------------------------------------------------------------- /c/examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Simple client example with no connection error detection logic. 2 | add_executable(simple_polaris_client simple_polaris_client.c) 3 | target_link_libraries(simple_polaris_client PUBLIC polaris_client) 4 | 5 | # Example application including connection timeout and retry logic. 6 | add_executable(connection_retry connection_retry.c) 7 | target_link_libraries(connection_retry PUBLIC polaris_client) 8 | -------------------------------------------------------------------------------- /c/examples/connection_retry.c: -------------------------------------------------------------------------------- 1 | /**************************************************************************/ /** 2 | * @brief Example Polaris client with reconnect/reauthentication support. 3 | * 4 | * Copyright (c) Point One Navigation - All Rights Reserved 5 | ******************************************************************************/ 6 | 7 | #include 8 | #include // For atoi() 9 | 10 | #include "point_one/polaris/polaris.h" 11 | #include "point_one/polaris/portability.h" 12 | 13 | static PolarisContext_t context; 14 | 15 | void HandleData(void* info, PolarisContext_t* polaris_context, 16 | const uint8_t* buffer, size_t size_bytes) { 17 | P1_printf("Application received %u bytes.\n", (unsigned)size_bytes); 18 | } 19 | 20 | void HandleSignal(int sig) { 21 | signal(sig, SIG_DFL); 22 | 23 | P1_printf("Caught signal %s (%d). Closing Polaris connection.\n", 24 | strsignal(sig), sig); 25 | Polaris_Disconnect(&context); 26 | } 27 | 28 | int main(int argc, const char* argv[]) { 29 | if (argc < 2 || argc > 4) { 30 | P1_fprintf(stderr, 31 | "Usage: %s API_KEY [UNIQUE_ID] [LOG_LEVEL (1=debug, 2=trace)]\n", 32 | argv[0]); 33 | return 1; 34 | } 35 | 36 | const char* api_key = argv[1]; 37 | const char* unique_id = argc > 2 ? argv[2] : "device12345"; 38 | 39 | int log_level = argc > 3 ? atoi(argv[3]) : POLARIS_LOG_LEVEL_INFO; 40 | Polaris_SetLogLevel(log_level); 41 | 42 | const int MAX_RECONNECTS = 2; 43 | int auth_valid = 0; 44 | int reconnect_count = 0; 45 | while (1) { 46 | // Retrieve an access token using the specified API key. 47 | if (!auth_valid) { 48 | if (Polaris_Init(&context) != POLARIS_SUCCESS) { 49 | P1_printf("Error initializing context.\n"); 50 | return 2; 51 | } 52 | 53 | P1_printf("Opened Polaris context. Authenticating...\n"); 54 | 55 | int ret = Polaris_Authenticate(&context, api_key, unique_id); 56 | if (ret == POLARIS_FORBIDDEN) { 57 | P1_printf("Authentication rejected. Is your API key valid?\n"); 58 | Polaris_Free(&context); 59 | return 3; 60 | } else if (ret != POLARIS_SUCCESS) { 61 | P1_printf("Authentication failed. Retrying.\n"); 62 | Polaris_Free(&context); 63 | continue; 64 | } 65 | 66 | auth_valid = 1; 67 | } 68 | 69 | // We now have a valid access token. Connect to the corrections service. 70 | // 71 | // In the calls below, if the connection times out or the access token is 72 | // rejected, try to connect again. If it fails too many times, the access 73 | // token may be expired - try reauthenticating. 74 | P1_printf("Authenticated. Connecting to Polaris...\n"); 75 | 76 | Polaris_SetRTCMCallback(&context, HandleData, NULL); 77 | 78 | if (Polaris_Connect(&context) != POLARIS_SUCCESS) { 79 | P1_printf("Error connecting to Polaris corrections stream. Retrying.\n"); 80 | if (++reconnect_count >= MAX_RECONNECTS) { 81 | P1_printf( 82 | "Max reconnects exceeded. Clearing access token and retrying " 83 | "authentication.\n"); 84 | auth_valid = 0; 85 | reconnect_count = 0; 86 | Polaris_Free(&context); 87 | } 88 | continue; 89 | } 90 | 91 | P1_printf("Connected to Polaris...\n"); 92 | 93 | // Send a position update to Polaris. Position updates are used to select an 94 | // appropriate corrections stream, and should be updated periodically as the 95 | // receiver moves. 96 | if (Polaris_SendLLAPosition(&context, 37.773971, -122.430996, -0.02) != 97 | POLARIS_SUCCESS) { 98 | Polaris_Disconnect(&context); 99 | Polaris_Free(&context); 100 | if (++reconnect_count >= MAX_RECONNECTS) { 101 | P1_printf( 102 | "Max reconnects exceeded. Clearing access token and retrying " 103 | "authentication.\n"); 104 | auth_valid = 0; 105 | reconnect_count = 0; 106 | } 107 | continue; 108 | } 109 | 110 | // Receive incoming RTCM data until the application exits. 111 | P1_printf("Sent position. Listening for data...\n"); 112 | 113 | signal(SIGINT, HandleSignal); 114 | signal(SIGTERM, HandleSignal); 115 | 116 | int ret = Polaris_Run(&context, 30000); 117 | if (ret == POLARIS_SUCCESS) { 118 | break; 119 | } 120 | else if (ret == POLARIS_CONNECTION_CLOSED) { 121 | P1_printf("Connection terminated remotely. Reconnecting.\n"); 122 | } 123 | else if (ret == POLARIS_TIMED_OUT) { 124 | P1_printf("Connection timed out. Reconnecting.\n"); 125 | } 126 | else { 127 | P1_printf("Unexpected error (%d). Reconnecting.\n", ret); 128 | } 129 | 130 | signal(SIGINT, SIG_DFL); 131 | signal(SIGTERM, SIG_DFL); 132 | 133 | if (++reconnect_count >= MAX_RECONNECTS) { 134 | P1_printf( 135 | "Max reconnects exceeded. Clearing access token and retrying " 136 | "authentication.\n"); 137 | auth_valid = 0; 138 | reconnect_count = 0; 139 | } 140 | } 141 | 142 | Polaris_Free(&context); 143 | 144 | P1_printf("Finished.\n"); 145 | 146 | return 0; 147 | } 148 | -------------------------------------------------------------------------------- /c/examples/external_cmake_project/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # This is a simple example of how to import the Polaris client library in 3 | # your own project using the CMake FetchContent feature. We strongly encourage 4 | # you to use FetchContent to download Polaris client from the publicly available 5 | # source code. 6 | # 7 | # Alternatively, you may choose to use a git submodule to import the source code 8 | # into your repository. We do not recommend copying the Polaris client souce 9 | # code directly into your repository. Doing so makes it much more difficult to 10 | # receive updates as new features and improvements are released. 11 | ################################################################################ 12 | 13 | # Note: CMake 3.18 or newer required to use SOURCE_SUBDIR below in order to 14 | # include just the Polaris C library and not the top-level C++ library. 15 | cmake_minimum_required(VERSION 3.18) 16 | 17 | project(polaris_usage_example C) 18 | 19 | # Use FetchContent to import the Polaris client C library using Git. 20 | # 21 | # Note that we always recommend using a specific version of the library in your 22 | # code by specifying a git tag (e.g., `GIT_TAG v1.3.1`), and updating that as 23 | # new versions are released. That way, you can be sure that your code is always 24 | # built with a known version of Polaris client. If you prefer, however, you can 25 | # set the GIT_TAG to track the latest changes by setting `GIT_TAG master` below. 26 | # 27 | # We explicitly disable example applications from the Polaris client library by 28 | # setting POLARIS_BUILD_EXAMPLES to OFF below. We only want to build the library 29 | # and make the fusion_engine_client CMake target available here. By default, if 30 | # we do not tell it otherwise, FetchContent_MakeAvailable() will also import all 31 | # of the example applications in polaris/c/examples/. 32 | # 33 | # It is important to specify it as an INTERNAL variable. If you do not do this, 34 | # the option definition in the fusion-engine-client CMakeLists.txt file will 35 | # override this value and enable the example applications anyway. This is a 36 | # result of CMP0077, which was added in CMake 3.13. 37 | include(FetchContent) 38 | FetchContent_Declare( 39 | polaris 40 | GIT_REPOSITORY https://github.com/PointOneNav/polaris.git 41 | GIT_TAG v1.3.1 42 | SOURCE_SUBDIR c 43 | ) 44 | set(POLARIS_BUILD_EXAMPLES OFF CACHE INTERNAL "") 45 | FetchContent_MakeAvailable(polaris) 46 | 47 | # Now we define an example application that uses the Polaris client library. 48 | # In your own code, you can link any add_executable() or add_library() target 49 | # with polaris_client by calling target_link_libraries() as shown. 50 | add_executable(example_app main.c) 51 | target_link_libraries(example_app PUBLIC polaris_client) 52 | -------------------------------------------------------------------------------- /c/examples/external_cmake_project/main.c: -------------------------------------------------------------------------------- 1 | /**************************************************************************/ /** 2 | * @brief Example external cmake project. 3 | * 4 | * Copyright (c) Point One Navigation - All Rights Reserved 5 | ******************************************************************************/ 6 | 7 | #include 8 | 9 | int main(int argc, const char* argv[]) { 10 | P1_printf("Hello, world!\n"); 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /c/examples/simple_polaris_client.c: -------------------------------------------------------------------------------- 1 | /**************************************************************************/ /** 2 | * @brief Simple Polaris client example. 3 | * 4 | * Copyright (c) Point One Navigation - All Rights Reserved 5 | ******************************************************************************/ 6 | 7 | #include 8 | #include // For atoi() 9 | 10 | #include "point_one/polaris/polaris.h" 11 | #include "point_one/polaris/portability.h" 12 | 13 | static PolarisContext_t context; 14 | 15 | void HandleData(void* info, PolarisContext_t* polaris_context, 16 | const uint8_t* buffer, size_t size_bytes) { 17 | P1_printf("Application received %u bytes.\n", (unsigned)size_bytes); 18 | } 19 | 20 | void HandleSignal(int sig) { 21 | signal(sig, SIG_DFL); 22 | 23 | P1_printf("Caught signal %s (%d). Closing Polaris connection.\n", 24 | strsignal(sig), sig); 25 | Polaris_Disconnect(&context); 26 | } 27 | 28 | int main(int argc, const char* argv[]) { 29 | if (argc < 2 || argc > 4) { 30 | P1_fprintf(stderr, 31 | "Usage: %s API_KEY UNIQUE_ID [LOG_LEVEL (1=debug, 2=trace)]\n", 32 | argv[0]); 33 | return 1; 34 | } 35 | 36 | const char* api_key = argv[1]; 37 | if (strlen(api_key) == 0) { 38 | P1_fprintf(stderr, 39 | "You must supply a Polaris API key to connect to the server.\n"); 40 | return 1; 41 | } 42 | 43 | const char* unique_id = argv[2]; 44 | if (strlen(unique_id) == 0) { 45 | P1_fprintf(stderr, "You must supply a unique ID for this connection.\n"); 46 | return 1; 47 | } 48 | 49 | int log_level = argc > 3 ? atoi(argv[3]) : POLARIS_LOG_LEVEL_INFO; 50 | Polaris_SetLogLevel(log_level); 51 | 52 | // Retrieve an access token using the specified API key. 53 | if (Polaris_Init(&context) != POLARIS_SUCCESS) { 54 | return 2; 55 | } 56 | 57 | P1_printf("Opened Polaris context. Authenticating...\n"); 58 | 59 | if (Polaris_Authenticate(&context, api_key, unique_id) != POLARIS_SUCCESS) { 60 | Polaris_Free(&context); 61 | return 3; 62 | } 63 | 64 | // We now have a valid access token. Connect to the corrections service. 65 | P1_printf("Authenticated. Connecting to Polaris...\n"); 66 | 67 | Polaris_SetRTCMCallback(&context, HandleData, NULL); 68 | 69 | if (Polaris_Connect(&context) != POLARIS_SUCCESS) { 70 | Polaris_Free(&context); 71 | return 3; 72 | } 73 | 74 | P1_printf("Connected to Polaris...\n"); 75 | 76 | // Send a position update to Polaris. Position updates are used to select an 77 | // appropriate corrections stream, and should be updated periodically as the 78 | // receiver moves. 79 | P1_printf("Setting initial position.\n"); 80 | if (Polaris_SendLLAPosition(&context, 37.773971, -122.430996, -0.02) != 81 | POLARIS_SUCCESS) { 82 | Polaris_Disconnect(&context); 83 | Polaris_Free(&context); 84 | return 4; 85 | } 86 | 87 | // Receive incoming RTCM data until the application exits. 88 | P1_printf("Sent position. Listening for data...\n"); 89 | 90 | signal(SIGINT, HandleSignal); 91 | signal(SIGTERM, HandleSignal); 92 | 93 | Polaris_Run(&context, 30000); 94 | 95 | P1_printf("Finished running. Cleaning up.\n"); 96 | Polaris_Free(&context); 97 | 98 | P1_printf("Exiting.\n"); 99 | return 0; 100 | } 101 | -------------------------------------------------------------------------------- /c/src/point_one/polaris/polaris_internal.c: -------------------------------------------------------------------------------- 1 | /**************************************************************************/ /** 2 | * @brief Point One Navigation Polaris message definitions and support. 3 | * 4 | * Copyright (c) Point One Navigation - All Rights Reserved 5 | ******************************************************************************/ 6 | 7 | #include "point_one/polaris/polaris_internal.h" 8 | 9 | #include "point_one/polaris/socket.h" 10 | 11 | /******************************************************************************/ 12 | PolarisHeader_t* Polaris_PopulateHeader(void* buffer, uint8_t message_id, 13 | uint16_t payload_length) { 14 | PolarisHeader_t* header = (PolarisHeader_t*)buffer; 15 | header->start_byte0 = POLARIS_START_BYTE_0; 16 | header->start_byte1 = POLARIS_START_BYTE_1; 17 | header->message_class = POLARIS_CLASS_INTERNAL; 18 | header->message_id = message_id; 19 | header->payload_length = htole16(payload_length); 20 | return header; 21 | } 22 | 23 | /******************************************************************************/ 24 | size_t Polaris_PopulateChecksum(void* buffer_in) { 25 | uint8_t* buffer = (uint8_t*)buffer_in; 26 | PolarisHeader_t* header = (PolarisHeader_t*)buffer; 27 | size_t message_length = sizeof(PolarisHeader_t) + header->payload_length; 28 | 29 | // Note: We're manually serializing the 16b checksum, rather than simply 30 | // casting the end of the buffer to a uint16_t, for the sake of architectures 31 | // that do not support unaligned access for multi-byte values in cases where 32 | // the message length is not a multiple of 4 bytes. The checksum is stored as 33 | // a little endian value. 34 | PolarisChecksum_t checksum = 35 | Polaris_CalculateChecksum(buffer, message_length); 36 | buffer[message_length] = (uint8_t)(checksum & 0xFF); 37 | buffer[message_length + 1] = (uint8_t)((checksum >> 8) & 0xFF); 38 | 39 | return message_length + sizeof(PolarisChecksum_t); 40 | } 41 | 42 | /******************************************************************************/ 43 | PolarisChecksum_t Polaris_CalculateChecksum(const void* buffer, size_t length) { 44 | // Note: The Polaris checksum is calculated on the header, _not_ including the 45 | // start bytes, plus the payload. Hence i starts at 2. 46 | uint8_t ckA = 0; 47 | uint8_t ckB = 0; 48 | for (size_t i = 2; i < length; i++) { 49 | ckA = ckA + ((const uint8_t*)buffer)[i]; 50 | ckB = ckB + ckA; 51 | } 52 | return (((PolarisChecksum_t)ckB) << 8) | ckA; 53 | } 54 | -------------------------------------------------------------------------------- /c/src/point_one/polaris/polaris_internal.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************/ /** 2 | * @brief Point One Navigation Polaris message definitions and support. 3 | * 4 | * @note 5 | * Polaris messages are little endian, not network (big) endian. 6 | * 7 | * Copyright (c) Point One Navigation - All Rights Reserved 8 | ******************************************************************************/ 9 | 10 | #pragma once 11 | 12 | #include // For size_t 13 | #include 14 | 15 | #define POLARIS_START_BYTE_0 0xB5 16 | #define POLARIS_START_BYTE_1 0x62 17 | 18 | #define POLARIS_CLASS_INTERNAL 0xE0 19 | 20 | #define POLARIS_ID_AUTH 0x01 21 | #define POLARIS_ID_ECEF 0x03 22 | #define POLARIS_ID_LLA 0x04 23 | #define POLARIS_ID_BEACON 0x05 24 | #define POLARIS_ID_UNIQUE_ID 0x06 25 | 26 | // Enforce 4-byte alignment and packing of all data structures and values so 27 | // that values larger than 1 B are aligned on platforms that require it. 28 | #pragma pack(push, 4) 29 | 30 | typedef struct { 31 | uint8_t start_byte0; 32 | uint8_t start_byte1; 33 | uint8_t message_class; 34 | uint8_t message_id; 35 | uint16_t payload_length; 36 | } PolarisHeader_t; 37 | 38 | typedef struct { 39 | int32_t x_cm; 40 | int32_t y_cm; 41 | int32_t z_cm; 42 | } PolarisECEFMessage_t; 43 | 44 | typedef struct { 45 | int32_t latitude_dege7; 46 | int32_t longitude_dege7; 47 | int32_t altitude_mm; 48 | } PolarisLLAMessage_t; 49 | 50 | #pragma pack(pop) 51 | 52 | typedef uint16_t PolarisChecksum_t; 53 | 54 | #define POLARIS_MAX_HTTP_HEADER_SIZE 256 55 | #define POLARIS_MAX_HTTP_MESSAGE_SIZE \ 56 | (POLARIS_MAX_HTTP_HEADER_SIZE + POLARIS_MAX_TOKEN_SIZE) 57 | 58 | #define POLARIS_MAX_PAYLOAD_SIZE 42 59 | #define POLARIS_MAX_MESSAGE_SIZE \ 60 | (sizeof(PolarisHeader_t) + POLARIS_MAX_PAYLOAD_SIZE + \ 61 | sizeof(PolarisChecksum_t)) 62 | 63 | #ifdef __cplusplus 64 | extern "C" { 65 | #endif 66 | 67 | PolarisHeader_t* Polaris_PopulateHeader(void* buffer, uint8_t message_id, 68 | uint16_t payload_length); 69 | 70 | size_t Polaris_PopulateChecksum(void* buffer); 71 | 72 | PolarisChecksum_t Polaris_CalculateChecksum(const void* buffer, size_t length); 73 | 74 | #ifdef __cplusplus 75 | } // extern "C" 76 | #endif 77 | -------------------------------------------------------------------------------- /c/src/point_one/polaris/portability.c: -------------------------------------------------------------------------------- 1 | /**************************************************************************/ /** 2 | * @brief Portability helpers. 3 | * 4 | * Copyright (c) Point One Navigation - All Rights Reserved 5 | ******************************************************************************/ 6 | 7 | #include "point_one/polaris/portability.h" 8 | 9 | #ifdef P1_FREERTOS // FreeRTOS 10 | 11 | #else // POSIX 12 | 13 | #include 14 | 15 | int P1_GetUTCOffsetSec(P1_TimeValue_t* time) { 16 | time_t now_sec = (time_t)time->tv_sec; 17 | struct tm local_time = *localtime(&now_sec); 18 | #if __GLIBC__ && __USE_MISC 19 | return local_time.tm_gmtoff; 20 | #else // Not glibc 21 | // The tm_gmtoff field is a non-standard glibc extension. If it is not 22 | // available, use the `timezone` global variable defined in time.h by tzset(). 23 | // It does _not_ get adjusted for daylight savings time, so we need to 24 | // manually offset it if tm_isdst is set. 25 | int utc_offset_sec = -timezone; 26 | if (local_time.tm_isdst) { 27 | utc_offset_sec += 3600; 28 | } 29 | return utc_offset_sec; 30 | #endif 31 | } 32 | 33 | #endif // End OS selection 34 | -------------------------------------------------------------------------------- /c/src/point_one/polaris/portability.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************/ /** 2 | * @brief Portability helpers. 3 | * 4 | * Copyright (c) Point One Navigation - All Rights Reserved 5 | ******************************************************************************/ 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | #ifdef __cplusplus 12 | extern "C" { 13 | #endif 14 | 15 | #ifdef P1_FREERTOS // FreeRTOS 16 | 17 | # include // For strerror() 18 | 19 | # include "FreeRTOS.h" 20 | 21 | # ifndef P1_printf 22 | # define P1_printf(format, ...) \ 23 | do { \ 24 | } while (0) 25 | # endif 26 | 27 | # ifndef P1_fprintf 28 | # define P1_fprintf(stream, format, ...) P1_printf(format, ##__VA_ARGS__) 29 | # endif 30 | 31 | typedef TickType_t P1_TimeValue_t; 32 | 33 | static inline void P1_GetCurrentTime(P1_TimeValue_t* result) { 34 | *result = xTaskGetTickCount(); 35 | } 36 | 37 | static inline void P1_SetTimeMS(int time_ms, P1_TimeValue_t* result) { 38 | *result = pdMS_TO_TICKS(time_ms); 39 | } 40 | 41 | static inline uint64_t P1_GetTimeMS(const P1_TimeValue_t* time) { 42 | return (uint64_t)pdTICKS_TO_MS(*time); 43 | } 44 | 45 | static inline int P1_GetElapsedMS(const P1_TimeValue_t* start, 46 | const P1_TimeValue_t* end) { 47 | return (int)((*end - *start) * portTICK_PERIOD_MS); 48 | } 49 | 50 | static inline int P1_GetUTCOffsetSec(P1_TimeValue_t* time) { return 0; } 51 | 52 | static inline int P1_GetUTCOffsetHours(P1_TimeValue_t* time) { 53 | return P1_GetUTCOffsetSec(time) / 3600; 54 | } 55 | 56 | #else // POSIX 57 | 58 | # include 59 | # include 60 | # include 61 | 62 | # ifndef P1_printf 63 | # define P1_printf printf 64 | # endif 65 | 66 | # ifndef P1_fprintf 67 | # define P1_fprintf fprintf 68 | # endif 69 | 70 | typedef struct timeval P1_TimeValue_t; 71 | 72 | static inline void P1_GetCurrentTime(P1_TimeValue_t* result) { 73 | gettimeofday(result, NULL); 74 | } 75 | 76 | static inline void P1_SetTimeMS(uint64_t time_ms, P1_TimeValue_t* result) { 77 | result->tv_sec = (time_t)(time_ms / 1000); 78 | result->tv_usec = (suseconds_t)((time_ms % 1000) * 1000); 79 | } 80 | 81 | static inline uint64_t P1_GetTimeMS(const P1_TimeValue_t* time) { 82 | return (((uint64_t)(time->tv_sec)) * 1000) + (time->tv_usec / 1000); 83 | } 84 | 85 | static inline int P1_GetElapsedMS(const P1_TimeValue_t* start, 86 | const P1_TimeValue_t* end) { 87 | P1_TimeValue_t delta; 88 | timersub(end, start, &delta); 89 | return (int)((delta.tv_sec * 1000) + (delta.tv_usec / 1000)); 90 | } 91 | 92 | int P1_GetUTCOffsetSec(P1_TimeValue_t* time); 93 | 94 | static inline int P1_GetUTCOffsetHours(P1_TimeValue_t* time) { 95 | return P1_GetUTCOffsetSec(time) / 3600; 96 | } 97 | 98 | #endif // End OS selection 99 | 100 | #ifdef __cplusplus 101 | } // extern "C" 102 | #endif 103 | -------------------------------------------------------------------------------- /c/src/point_one/polaris/socket.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************/ /** 2 | * @brief Socket support wrapper for the Polaris client. 3 | * 4 | * Copyright (c) Point One Navigation - All Rights Reserved 5 | ******************************************************************************/ 6 | 7 | #pragma once 8 | 9 | #ifdef P1_FREERTOS 10 | # include "socket_freertos.h" 11 | #else 12 | # include "socket_posix.h" 13 | #endif 14 | -------------------------------------------------------------------------------- /c/src/point_one/polaris/socket_freertos.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************/ /** 2 | * @brief FreeRTOS+TCP socket support wrapper. 3 | * 4 | * The FreeRTOS TCP library's socket API is very similar to the POSIX Berkeley 5 | * sockets API. We map FreeRTOS calls to the POSIX equivalents wherever 6 | * possible. 7 | * 8 | * Copyright (c) Point One Navigation - All Rights Reserved 9 | ******************************************************************************/ 10 | 11 | #pragma once 12 | 13 | #include "FreeRTOS_IP.h" 14 | #include "FreeRTOS_Sockets.h" 15 | 16 | typedef Socket_t P1_Socket_t; 17 | #define P1_INVALID_SOCKET FREERTOS_INVALID_SOCKET 18 | 19 | typedef struct freertos_sockaddr P1_SocketAddrV4_t; 20 | typedef struct freertos_sockaddr P1_SocketAddr_t; 21 | 22 | typedef BaseType_t P1_RecvSize_t; 23 | 24 | #define AF_INET FREERTOS_AF_INET 25 | 26 | #define SOCK_STREAM FREERTOS_SOCK_STREAM 27 | 28 | #define IPPROTO_TCP FREERTOS_IPPROTO_TCP 29 | 30 | // Not currently used/ignored by FreeRTOS. Setting to the same value as POSIX. 31 | #define SOL_SOCKET 1 32 | 33 | #define SO_RCVTIMEO FREERTOS_SO_RCVTIMEO 34 | #define SO_SNDTIMEO FREERTOS_SO_SNDTIMEO 35 | 36 | #define SHUT_RDWR FREERTOS_SHUT_RDWR 37 | 38 | // Aliases mapping FreeRTOS function names to Berkeley names. The APIs are the 39 | // same as the Berkeley definitions for all of these functions. 40 | #define socket FreeRTOS_socket 41 | #define close FreeRTOS_closesocket 42 | #define shutdown FreeRTOS_shutdown 43 | #define connect FreeRTOS_connect 44 | #define send FreeRTOS_send 45 | #define recv FreeRTOS_recv 46 | #define setsockopt FreeRTOS_setsockopt 47 | #define htons FreeRTOS_htons 48 | 49 | // Note: FreeRTOS does not define htole*() macros. 50 | #if ipconfigBYTE_ORDER == pdFREERTOS_LITTLE_ENDIAN 51 | # define htole16(x) (x) 52 | # define le16toh(x) (x) 53 | # define htole32(x) (x) 54 | # define le32toh(x) (x) 55 | #else 56 | // Taken from FreeRTOS_IP.h. 57 | # define htole16(x) ((uint16_t)(((x) << 8U) | ((x) >> 8U))) 58 | # define le16toh(x) htole16(x) 59 | # define htole32(x) \ 60 | ((uint32_t)( \ 61 | ((((uint32_t)(x))) << 24) | ((((uint32_t)(x)) & 0x0000ff00UL) << 8) | \ 62 | ((((uint32_t)(x)) & 0x00ff0000UL) >> 8) | ((((uint32_t)(x))) >> 24))) 63 | # define le32toh(x) htole32(x) 64 | #endif 65 | -------------------------------------------------------------------------------- /c/src/point_one/polaris/socket_posix.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************/ /** 2 | * @brief POSIX socket support wrapper. 3 | * 4 | * We align our socket functionality as closely as possible with the POSIX 5 | * Berkeley sockets API, with minor changes and definitions made to enable other 6 | * OSes with similar APIs. 7 | * 8 | * Copyright (c) Point One Navigation - All Rights Reserved 9 | ******************************************************************************/ 10 | 11 | #pragma once 12 | 13 | #include // For IPPROTO_* macros and hton*() 14 | #include // For gethostbyname() and hostent 15 | #include // For memcpy() 16 | #include 17 | #include 18 | #include // For close() 19 | 20 | typedef int P1_Socket_t; 21 | #define P1_INVALID_SOCKET -1 22 | 23 | typedef struct sockaddr_in P1_SocketAddrV4_t; 24 | typedef struct sockaddr P1_SocketAddr_t; 25 | 26 | typedef ssize_t P1_RecvSize_t; 27 | -------------------------------------------------------------------------------- /c/test/run_unit_tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | echo "Testing simple_polaris_client..." 6 | python3 test/test_simple_polaris_client.py $* 7 | 8 | echo "Testing connection_retry..." 9 | python3 test/test_connection_retry.py $* 10 | -------------------------------------------------------------------------------- /c/test/test_connection_retry.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from application_base import StandardApplication 4 | 5 | class Test(StandardApplication): 6 | def __init__(self): 7 | super().__init__(application_name='connection_retry') 8 | 9 | test = Test() 10 | test.parse_args() 11 | test.run() 12 | -------------------------------------------------------------------------------- /c/test/test_simple_polaris_client.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from application_base import StandardApplication 4 | 5 | class Test(StandardApplication): 6 | def __init__(self): 7 | super().__init__(application_name='simple_polaris_client') 8 | 9 | test = Test() 10 | test.parse_args() 11 | test.run() 12 | -------------------------------------------------------------------------------- /compilers/BUILD.bazel: -------------------------------------------------------------------------------- 1 | # This is the entry point for --crosstool_top. Toolchains are found 2 | # by lopping off the name of --crosstool_top and searching for 3 | # 'cc-compiler-${CPU}' in this BUILD file, where CPU is the target CPU 4 | # specified in --cpu. 5 | 6 | package(default_visibility = ["//compilers:__pkg__"]) 7 | 8 | # This file group should include 9 | # * all cc_toolchain targets supported 10 | # * all file groups that said cc_toolchain might refer to 11 | filegroup( 12 | name = "toolchain_fg", 13 | srcs = [ 14 | "//compilers/arm/linaro_linux_gcc_aarch64:cc-compiler-aarch64-linux-gnu", 15 | "//compilers/arm/linaro_linux_gcc_armv7:cc-compiler-armeabi-v7a", 16 | "//compilers/k8:cc-compiler-k8", 17 | ], 18 | ) 19 | 20 | cc_toolchain_suite( 21 | name = "toolchain", 22 | # target_cpu | compiler 23 | toolchains = { 24 | "k8": "//compilers/k8:cc-compiler-k8", 25 | "k8|compiler": "//compilers/k8:cc-compiler-k8", 26 | "armeabi-v7a": "//compilers/arm/linaro_linux_gcc_armv7:cc-compiler-armeabi-v7a", 27 | "armeabi-v7a|gcc": "//compilers/arm/linaro_linux_gcc_armv7:cc-compiler-armeabi-v7a", 28 | "aarch64-linux-gnu": "//compilers/arm/linaro_linux_gcc_aarch64:cc-compiler-aarch64-linux-gnu", 29 | "aarch64-linux-gnu|gcc": "//compilers/arm/linaro_linux_gcc_aarch64:cc-compiler-aarch64-linux-gnu", 30 | }, 31 | visibility = ["//visibility:public"], 32 | ) 33 | -------------------------------------------------------------------------------- /compilers/arm/BUILD.bazel: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PointOneNav/polaris/810845a3e8cfaa41da81dffed31c6ee62933b431/compilers/arm/BUILD.bazel -------------------------------------------------------------------------------- /compilers/arm/dependencies.bzl: -------------------------------------------------------------------------------- 1 | load( 2 | "//compilers/arm/linaro_linux_gcc_aarch64:dependencies.bzl", 3 | linaro_aarch64_dependencies = "cross_compiler_dependencies", 4 | ) 5 | load( 6 | "//compilers/arm/linaro_linux_gcc_armv7:dependencies.bzl", 7 | linaro_armv7_dependencies = "cross_compiler_dependencies", 8 | ) 9 | 10 | def cross_compiler_dependencies(**kwargs): 11 | linaro_aarch64_dependencies() 12 | linaro_armv7_dependencies() 13 | -------------------------------------------------------------------------------- /compilers/arm/linaro_linux_gcc_aarch64/BUILD.bazel: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//compilers/arm/linaro_linux_gcc_aarch64:__pkg__"]) 2 | 3 | load(":cc_toolchain_config.bzl", "cc_toolchain_config") 4 | 5 | cc_toolchain_config( 6 | name = "aarch64-linux-gnu_config", 7 | compiler = "gcc", 8 | cpu = "aarch64-linux-gnu", 9 | ) 10 | 11 | cc_toolchain( 12 | name = "cc-compiler-aarch64-linux-gnu", 13 | all_files = ":linaro_linux_all_files_aarch64", 14 | ar_files = ":ar", 15 | as_files = ":as", 16 | compiler_files = ":linaro_linux_compiler_files_aarch64", 17 | dwp_files = ":empty", 18 | linker_files = ":linaro_linux_linker_files_aarch64", 19 | objcopy_files = ":objcopy", 20 | strip_files = ":strip", 21 | supports_param_files = 1, 22 | tags = ["no-ide"], 23 | toolchain_config = ":aarch64-linux-gnu_config", 24 | toolchain_identifier = "aarch64-linux-gnu", 25 | visibility = ["//visibility:public"], 26 | ) 27 | 28 | filegroup( 29 | name = "linaro_linux_all_files_aarch64", 30 | srcs = [ 31 | ":tool-wrappers", 32 | "@org_linaro_components_toolchain_gcc_aarch64//:compiler_pieces", 33 | ], 34 | ) 35 | 36 | filegroup( 37 | name = "linaro_linux_linker_files_aarch64", 38 | srcs = [ 39 | ":ar", 40 | ":gcc", 41 | ":ld", 42 | "@org_linaro_components_toolchain_gcc_aarch64//:compiler_pieces", 43 | ], 44 | ) 45 | 46 | filegroup( 47 | name = "linaro_linux_compiler_files_aarch64", 48 | srcs = [ 49 | ":as", 50 | ":gcc", 51 | ":ld", 52 | ], 53 | ) 54 | 55 | filegroup( 56 | name = "tool-wrappers", 57 | srcs = [ 58 | ":ar", 59 | ":as", 60 | ":gcc", 61 | ":ld", 62 | ":nm", 63 | ":objcopy", 64 | ":objdump", 65 | ":strip", 66 | ], 67 | ) 68 | 69 | filegroup( 70 | name = "empty", 71 | srcs = [], 72 | ) 73 | 74 | filegroup( 75 | name = "srcs", 76 | srcs = glob(["**"]), 77 | ) 78 | 79 | filegroup( 80 | name = "gcc", 81 | srcs = [ 82 | "aarch64-linux-gnu-gcc", 83 | "@org_linaro_components_toolchain_gcc_aarch64//:gcc", 84 | ], 85 | ) 86 | 87 | filegroup( 88 | name = "ar", 89 | srcs = [ 90 | "aarch64-linux-gnu-ar", 91 | "@org_linaro_components_toolchain_gcc_aarch64//:ar", 92 | ], 93 | ) 94 | 95 | filegroup( 96 | name = "ld", 97 | srcs = [ 98 | "aarch64-linux-gnu-ld", 99 | "@org_linaro_components_toolchain_gcc_aarch64//:ld", 100 | ], 101 | ) 102 | 103 | filegroup( 104 | name = "nm", 105 | srcs = [ 106 | "aarch64-linux-gnu-nm", 107 | "@org_linaro_components_toolchain_gcc_aarch64//:nm", 108 | ], 109 | ) 110 | 111 | filegroup( 112 | name = "objcopy", 113 | srcs = [ 114 | "aarch64-linux-gnu-objcopy", 115 | "@org_linaro_components_toolchain_gcc_aarch64//:objcopy", 116 | ], 117 | ) 118 | 119 | filegroup( 120 | name = "objdump", 121 | srcs = [ 122 | "aarch64-linux-gnu-objdump", 123 | "@org_linaro_components_toolchain_gcc_aarch64//:objdump", 124 | ], 125 | ) 126 | 127 | filegroup( 128 | name = "strip", 129 | srcs = [ 130 | "aarch64-linux-gnu-strip", 131 | "@org_linaro_components_toolchain_gcc_aarch64//:strip", 132 | ], 133 | ) 134 | 135 | filegroup( 136 | name = "as", 137 | srcs = [ 138 | "aarch64-linux-gnu-as", 139 | "@org_linaro_components_toolchain_gcc_aarch64//:as", 140 | ], 141 | ) 142 | -------------------------------------------------------------------------------- /compilers/arm/linaro_linux_gcc_aarch64/aarch64-linux-gnu-ar: -------------------------------------------------------------------------------- 1 | #!/bin/bash --norc 2 | 3 | if [[ -z "${EXT_BUILD_ROOT}" ]]; then 4 | MY_PREFIX="" 5 | else 6 | MY_PREFIX="${EXT_BUILD_ROOT}/" 7 | fi 8 | 9 | exec -a aarch64-linux-gnu-ar \ 10 | ${MY_PREFIX}external/org_linaro_components_toolchain_gcc_aarch64/bin/aarch64-linux-gnu-ar \ 11 | "$@" 12 | -------------------------------------------------------------------------------- /compilers/arm/linaro_linux_gcc_aarch64/aarch64-linux-gnu-as: -------------------------------------------------------------------------------- 1 | #!/bin/bash --norc 2 | 3 | exec -a aarch64-linux-gnu-as \ 4 | external/org_linaro_components_toolchain_gcc_aarch64/bin/aarch64-linux-gnu-as \ 5 | "$@" 6 | -------------------------------------------------------------------------------- /compilers/arm/linaro_linux_gcc_aarch64/aarch64-linux-gnu-gcc: -------------------------------------------------------------------------------- 1 | #!/bin/bash --norc 2 | 3 | if [[ -z "${EXT_BUILD_ROOT}" ]]; then 4 | MY_PREFIX="" 5 | else 6 | MY_PREFIX="${EXT_BUILD_ROOT}/" 7 | fi 8 | 9 | PATH="${MY_PREFIX}external/org_linaro_components_toolchain_gcc_aarch64/libexec/gcc/aarch64-linux-gnu/7.4.1:$PATH" \ 10 | exec \ 11 | ${MY_PREFIX}external/org_linaro_components_toolchain_gcc_aarch64/bin/aarch64-linux-gnu-gcc \ 12 | "$@" 13 | -------------------------------------------------------------------------------- /compilers/arm/linaro_linux_gcc_aarch64/aarch64-linux-gnu-ld: -------------------------------------------------------------------------------- 1 | #!/bin/bash --norc 2 | 3 | exec -a aarch64-linux-gnu-ld \ 4 | external/org_linaro_components_toolchain_gcc_aarch64/bin/aarch64-linux-gnu-ld \ 5 | "$@" 6 | -------------------------------------------------------------------------------- /compilers/arm/linaro_linux_gcc_aarch64/aarch64-linux-gnu-nm: -------------------------------------------------------------------------------- 1 | #!/bin/bash --norc 2 | 3 | exec -a aarch64-linux-gnu-nm \ 4 | external/org_linaro_components_toolchain_gcc_aarch64/bin/aarch64-linux-gnu-nm \ 5 | "$@" 6 | -------------------------------------------------------------------------------- /compilers/arm/linaro_linux_gcc_aarch64/aarch64-linux-gnu-objcopy: -------------------------------------------------------------------------------- 1 | #!/bin/bash --norc 2 | 3 | exec -a aarch64-linux-gnu-objcopy \ 4 | external/org_linaro_components_toolchain_gcc_aarch64/bin/aarch64-linux-gnu-objcopy \ 5 | "$@" 6 | -------------------------------------------------------------------------------- /compilers/arm/linaro_linux_gcc_aarch64/aarch64-linux-gnu-objdump: -------------------------------------------------------------------------------- 1 | #!/bin/bash --norc 2 | 3 | exec -a aarch64-linux-gnu-objdump \ 4 | external/org_linaro_components_toolchain_gcc_aarch64/bin/aarch64-linux-gnu-objdump \ 5 | "$@" 6 | -------------------------------------------------------------------------------- /compilers/arm/linaro_linux_gcc_aarch64/aarch64-linux-gnu-strip: -------------------------------------------------------------------------------- 1 | #!/bin/bash --norc 2 | 3 | exec -a aarch64-linux-gnu-strip \ 4 | external/org_linaro_components_toolchain_gcc_aarch64/bin/aarch64-linux-gnu-strip \ 5 | "$@" 6 | -------------------------------------------------------------------------------- /compilers/arm/linaro_linux_gcc_aarch64/dependencies.bzl: -------------------------------------------------------------------------------- 1 | load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") 2 | 3 | def cross_compiler_dependencies(**kwargs): 4 | aarch64_name = "org_linaro_components_toolchain_gcc_aarch64" 5 | aarch64_sha266 = "27f1dc2c491ed61ae8f0d4b0c11de59cd2f7dd9c94761ee7153006fcac1bf9ab" 6 | aarch64_prefix = "gcc-linaro-7.4.1-2019.02-x86_64_aarch64-linux-gnu" 7 | aarch64_url = "https://releases.linaro.org/components/toolchain/binaries/7.4-2019.02/aarch64-linux-gnu/gcc-linaro-7.4.1-2019.02-x86_64_aarch64-linux-gnu.tar.xz" 8 | 9 | if aarch64_name not in native.existing_rules(): 10 | http_archive( 11 | name = aarch64_name, 12 | strip_prefix = aarch64_prefix, 13 | url = aarch64_url, 14 | sha256 = aarch64_sha266, 15 | build_file_content = """ 16 | package(default_visibility = ["//visibility:public"]) 17 | 18 | filegroup( 19 | name = "gcc", 20 | srcs = [ 21 | "bin/aarch64-linux-gnu-gcc", 22 | ], 23 | ) 24 | 25 | filegroup( 26 | name = "ar", 27 | srcs = [ 28 | "bin/aarch64-linux-gnu-ar", 29 | ], 30 | ) 31 | 32 | filegroup( 33 | name = "ld", 34 | srcs = [ 35 | "bin/aarch64-linux-gnu-ld", 36 | ], 37 | ) 38 | 39 | filegroup( 40 | name = "nm", 41 | srcs = [ 42 | "bin/aarch64-linux-gnu-nm", 43 | ], 44 | ) 45 | 46 | filegroup( 47 | name = "objcopy", 48 | srcs = [ 49 | "bin/aarch64-linux-gnu-objcopy", 50 | ], 51 | ) 52 | 53 | filegroup( 54 | name = "objdump", 55 | srcs = [ 56 | "bin/aarch64-linux-gnu-objdump", 57 | ], 58 | ) 59 | 60 | filegroup( 61 | name = "strip", 62 | srcs = [ 63 | "bin/aarch64-linux-gnu-strip", 64 | ], 65 | ) 66 | 67 | filegroup( 68 | name = "as", 69 | srcs = [ 70 | "bin/aarch64-linux-gnu-as", 71 | ], 72 | ) 73 | 74 | filegroup( 75 | name = "compiler_pieces", 76 | srcs = glob([ 77 | "aarch64-linux-gnu/**", 78 | "libexec/**", 79 | "lib/gcc/aarch64-linux-gnu/**", 80 | "aarch64-linux-gnu/libc/usr/include/**", 81 | "include/**", 82 | ]), 83 | ) 84 | 85 | filegroup( 86 | name = "compiler_components", 87 | srcs = [ 88 | ":ar", 89 | ":as", 90 | ":gcc", 91 | ":ld", 92 | ":nm", 93 | ":objcopy", 94 | ":objdump", 95 | ":strip", 96 | ], 97 | ) 98 | """, 99 | ) 100 | -------------------------------------------------------------------------------- /compilers/arm/linaro_linux_gcc_armv7/BUILD.bazel: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//compilers/arm/linaro_linux_gcc_armv7:__pkg__"]) 2 | 3 | load(":cc_toolchain_config.bzl", "cc_toolchain_config") 4 | 5 | cc_toolchain_config( 6 | name = "armeabi-v7a_config", 7 | compiler = "gcc", 8 | cpu = "armeabi-v7a", 9 | ) 10 | 11 | cc_toolchain( 12 | name = "cc-compiler-armeabi-v7a", 13 | all_files = ":linaro_linux_all_files_armv7", 14 | ar_files = ":ar", 15 | as_files = ":as", 16 | compiler_files = ":linaro_linux_compiler_files_armv7", 17 | dwp_files = ":empty", 18 | linker_files = ":linaro_linux_linker_files_armv7", 19 | objcopy_files = ":objcopy", 20 | strip_files = ":strip", 21 | supports_param_files = 1, 22 | tags = ["no-ide"], 23 | toolchain_config = ":armeabi-v7a_config", 24 | toolchain_identifier = "armeabi-v7a", 25 | visibility = ["//visibility:public"], 26 | ) 27 | 28 | filegroup( 29 | name = "linaro_linux_all_files_armv7", 30 | srcs = [ 31 | ":tool-wrappers", 32 | "@org_linaro_components_toolchain_gcc_armv7//:compiler_pieces", 33 | ], 34 | ) 35 | 36 | filegroup( 37 | name = "linaro_linux_linker_files_armv7", 38 | srcs = [ 39 | ":ar", 40 | ":gcc", 41 | ":ld", 42 | "@org_linaro_components_toolchain_gcc_armv7//:compiler_pieces", 43 | ], 44 | ) 45 | 46 | filegroup( 47 | name = "linaro_linux_compiler_files_armv7", 48 | srcs = [ 49 | ":as", 50 | ":gcc", 51 | ":ld", 52 | ], 53 | ) 54 | 55 | filegroup( 56 | name = "tool-wrappers", 57 | srcs = [ 58 | ":ar", 59 | ":as", 60 | ":gcc", 61 | ":ld", 62 | ":nm", 63 | ":objcopy", 64 | ":objdump", 65 | ":strip", 66 | ], 67 | ) 68 | 69 | filegroup( 70 | name = "empty", 71 | srcs = [], 72 | ) 73 | 74 | filegroup( 75 | name = "srcs", 76 | srcs = glob(["**"]), 77 | ) 78 | 79 | filegroup( 80 | name = "gcc", 81 | srcs = [ 82 | "arm-linux-gnueabihf-gcc", 83 | "@org_linaro_components_toolchain_gcc_armv7//:gcc", 84 | ], 85 | ) 86 | 87 | filegroup( 88 | name = "ar", 89 | srcs = [ 90 | "arm-linux-gnueabihf-ar", 91 | "@org_linaro_components_toolchain_gcc_armv7//:ar", 92 | ], 93 | ) 94 | 95 | filegroup( 96 | name = "ld", 97 | srcs = [ 98 | "arm-linux-gnueabihf-ld", 99 | "@org_linaro_components_toolchain_gcc_armv7//:ld", 100 | ], 101 | ) 102 | 103 | filegroup( 104 | name = "nm", 105 | srcs = [ 106 | "arm-linux-gnueabihf-nm", 107 | "@org_linaro_components_toolchain_gcc_armv7//:nm", 108 | ], 109 | ) 110 | 111 | filegroup( 112 | name = "objcopy", 113 | srcs = [ 114 | "arm-linux-gnueabihf-objcopy", 115 | "@org_linaro_components_toolchain_gcc_armv7//:objcopy", 116 | ], 117 | ) 118 | 119 | filegroup( 120 | name = "objdump", 121 | srcs = [ 122 | "arm-linux-gnueabihf-objdump", 123 | "@org_linaro_components_toolchain_gcc_armv7//:objdump", 124 | ], 125 | ) 126 | 127 | filegroup( 128 | name = "strip", 129 | srcs = [ 130 | "arm-linux-gnueabihf-strip", 131 | "@org_linaro_components_toolchain_gcc_armv7//:strip", 132 | ], 133 | ) 134 | 135 | filegroup( 136 | name = "as", 137 | srcs = [ 138 | "arm-linux-gnueabihf-as", 139 | "@org_linaro_components_toolchain_gcc_armv7//:as", 140 | ], 141 | ) 142 | -------------------------------------------------------------------------------- /compilers/arm/linaro_linux_gcc_armv7/arm-linux-gnueabihf-ar: -------------------------------------------------------------------------------- 1 | #!/bin/bash --norc 2 | 3 | if [[ -z "${EXT_BUILD_ROOT}" ]]; then 4 | MY_PREFIX="" 5 | else 6 | MY_PREFIX="${EXT_BUILD_ROOT}/" 7 | fi 8 | 9 | exec -a arm-linux-gnueabihf-ar \ 10 | ${MY_PREFIX}external/org_linaro_components_toolchain_gcc_armv7/bin/arm-linux-gnueabihf-ar \ 11 | "$@" 12 | 13 | -------------------------------------------------------------------------------- /compilers/arm/linaro_linux_gcc_armv7/arm-linux-gnueabihf-as: -------------------------------------------------------------------------------- 1 | #!/bin/bash --norc 2 | 3 | exec -a arm-linux-gnueabihf-as \ 4 | external/org_linaro_components_toolchain_gcc_armv7/bin/arm-linux-gnueabihf-as \ 5 | "$@" 6 | -------------------------------------------------------------------------------- /compilers/arm/linaro_linux_gcc_armv7/arm-linux-gnueabihf-gcc: -------------------------------------------------------------------------------- 1 | #!/bin/bash --norc 2 | 3 | if [[ -z "${EXT_BUILD_ROOT}" ]]; then 4 | MY_PREFIX="" 5 | else 6 | MY_PREFIX="${EXT_BUILD_ROOT}/" 7 | fi 8 | 9 | PATH="${MY_PREFIX}external/org_linaro_components_toolchain_gcc_armv7/libexec/gcc/arm-linux-gnueabihf/7.4.1:$PATH" \ 10 | exec \ 11 | ${MY_PREFIX}external/org_linaro_components_toolchain_gcc_armv7/bin/arm-linux-gnueabihf-gcc \ 12 | "$@" -------------------------------------------------------------------------------- /compilers/arm/linaro_linux_gcc_armv7/arm-linux-gnueabihf-ld: -------------------------------------------------------------------------------- 1 | #!/bin/bash --norc 2 | 3 | exec -a arm-linux-gnueabihf-ld \ 4 | external/org_linaro_components_toolchain_gcc_armv7/bin/arm-linux-gnueabihf-ld \ 5 | "$@" 6 | -------------------------------------------------------------------------------- /compilers/arm/linaro_linux_gcc_armv7/arm-linux-gnueabihf-nm: -------------------------------------------------------------------------------- 1 | #!/bin/bash --norc 2 | 3 | exec -a arm-linux-gnueabihf-nm \ 4 | external/org_linaro_components_toolchain_gcc_armv7/bin/arm-linux-gnueabihf-nm \ 5 | "$@" 6 | -------------------------------------------------------------------------------- /compilers/arm/linaro_linux_gcc_armv7/arm-linux-gnueabihf-objcopy: -------------------------------------------------------------------------------- 1 | #!/bin/bash --norc 2 | 3 | exec -a arm-linux-gnueabihf-objcopy \ 4 | external/org_linaro_components_toolchain_gcc_armv7/bin/arm-linux-gnueabihf-objcopy \ 5 | "$@" 6 | -------------------------------------------------------------------------------- /compilers/arm/linaro_linux_gcc_armv7/arm-linux-gnueabihf-objdump: -------------------------------------------------------------------------------- 1 | #!/bin/bash --norc 2 | 3 | exec -a arm-linux-gnueabihf-objdump \ 4 | external/org_linaro_components_toolchain_gcc_armv7/bin/arm-linux-gnueabihf-objdump \ 5 | "$@" 6 | -------------------------------------------------------------------------------- /compilers/arm/linaro_linux_gcc_armv7/arm-linux-gnueabihf-strip: -------------------------------------------------------------------------------- 1 | #!/bin/bash --norc 2 | 3 | exec -a arm-linux-gnueabihf-strip \ 4 | external/org_linaro_components_toolchain_gcc_armv7/bin/arm-linux-gnueabihf-strip \ 5 | "$@" 6 | -------------------------------------------------------------------------------- /compilers/arm/linaro_linux_gcc_armv7/dependencies.bzl: -------------------------------------------------------------------------------- 1 | load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") 2 | 3 | def cross_compiler_dependencies(**kwargs): 4 | armv7_name = "org_linaro_components_toolchain_gcc_armv7" 5 | armv7_sha256 = "3c951cf1941d0fa06d64cc0d5e88612b209d8123b273fa26c16d70bd7bc6b163" 6 | armv7_prefix = "gcc-linaro-7.4.1-2019.02-x86_64_arm-linux-gnueabihf" 7 | armv7_url = "https://releases.linaro.org/components/toolchain/binaries/7.4-2019.02/arm-linux-gnueabihf/gcc-linaro-7.4.1-2019.02-x86_64_arm-linux-gnueabihf.tar.xz" 8 | 9 | if armv7_name not in native.existing_rules(): 10 | http_archive( 11 | name = armv7_name, 12 | strip_prefix = armv7_prefix, 13 | url = armv7_url, 14 | sha256 = armv7_sha256, 15 | build_file_content = """ 16 | package(default_visibility = ["//visibility:public"]) 17 | 18 | filegroup( 19 | name = "gcc", 20 | srcs = [ 21 | "bin/arm-linux-gnueabihf-gcc", 22 | ], 23 | ) 24 | 25 | filegroup( 26 | name = "ar", 27 | srcs = [ 28 | "bin/arm-linux-gnueabihf-ar", 29 | ], 30 | ) 31 | 32 | filegroup( 33 | name = "ld", 34 | srcs = [ 35 | "bin/arm-linux-gnueabihf-ld", 36 | ], 37 | ) 38 | 39 | filegroup( 40 | name = "nm", 41 | srcs = [ 42 | "bin/arm-linux-gnueabihf-nm", 43 | ], 44 | ) 45 | 46 | filegroup( 47 | name = "objcopy", 48 | srcs = [ 49 | "bin/arm-linux-gnueabihf-objcopy", 50 | ], 51 | ) 52 | 53 | filegroup( 54 | name = "objdump", 55 | srcs = [ 56 | "bin/arm-linux-gnueabihf-objdump", 57 | ], 58 | ) 59 | 60 | filegroup( 61 | name = "strip", 62 | srcs = [ 63 | "bin/arm-linux-gnueabihf-strip", 64 | ], 65 | ) 66 | 67 | filegroup( 68 | name = "as", 69 | srcs = [ 70 | "bin/arm-linux-gnueabihf-as", 71 | ], 72 | ) 73 | 74 | filegroup( 75 | name = "compiler_pieces", 76 | srcs = glob([ 77 | "arm-linux-gnueabihf/**", 78 | "libexec/**", 79 | "lib/gcc/arm-linux-gnueabihf/**", 80 | "include/**", 81 | ]), 82 | ) 83 | 84 | filegroup( 85 | name = "compiler_components", 86 | srcs = [ 87 | ":ar", 88 | ":as", 89 | ":gcc", 90 | ":ld", 91 | ":nm", 92 | ":objcopy", 93 | ":objdump", 94 | ":strip", 95 | ], 96 | ) 97 | """, 98 | ) 99 | -------------------------------------------------------------------------------- /compilers/dependencies.bzl: -------------------------------------------------------------------------------- 1 | load( 2 | "//compilers/arm:dependencies.bzl", 3 | arm_dependencies = "cross_compiler_dependencies", 4 | ) 5 | 6 | def cross_compiler_dependencies(**kwargs): 7 | arm_dependencies() 8 | -------------------------------------------------------------------------------- /compilers/k8/BUILD.bazel: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//compilers/k8:__pkg__"]) 2 | 3 | load(":cc_toolchain_config.bzl", "cc_toolchain_config") 4 | 5 | filegroup( 6 | name = "empty", 7 | srcs = [], 8 | ) 9 | 10 | cc_toolchain_config( 11 | name = "local_config", 12 | cpu = "k8", 13 | ) 14 | 15 | cc_toolchain( 16 | name = "cc-compiler-k8", 17 | all_files = ":empty", 18 | ar_files = ":empty", 19 | as_files = ":empty", 20 | compiler_files = ":empty", 21 | dwp_files = ":empty", 22 | linker_files = ":empty", 23 | objcopy_files = ":empty", 24 | strip_files = ":empty", 25 | supports_param_files = 1, 26 | tags = ["no-ide"], 27 | toolchain_config = ":local_config", 28 | toolchain_identifier = "local", 29 | visibility = ["//visibility:public"], 30 | ) 31 | -------------------------------------------------------------------------------- /docs/septentrio_configuration.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PointOneNav/polaris/810845a3e8cfaa41da81dffed31c6ee62933b431/docs/septentrio_configuration.png -------------------------------------------------------------------------------- /docs/septentrio_corrections.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PointOneNav/polaris/810845a3e8cfaa41da81dffed31c6ee62933b431/docs/septentrio_corrections.png -------------------------------------------------------------------------------- /docs/septentrio_rtk_fix.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PointOneNav/polaris/810845a3e8cfaa41da81dffed31c6ee62933b431/docs/septentrio_rtk_fix.png -------------------------------------------------------------------------------- /docs/septentrio_rxtools_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PointOneNav/polaris/810845a3e8cfaa41da81dffed31c6ee62933b431/docs/septentrio_rxtools_example.png -------------------------------------------------------------------------------- /examples/BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//visibility:public"]) 2 | 3 | # Simple example of connecting to the Polaris service. 4 | cc_binary( 5 | name = "simple_polaris_cpp_client", 6 | srcs = ["simple_polaris_client.cc"], 7 | deps = [ 8 | "//:polaris_client", 9 | "@com_github_gflags_gflags//:gflags", 10 | "@com_github_google_glog//:glog", 11 | ], 12 | ) 13 | 14 | # An example of obtaining receiver positions from a serial NMEA-0183 stream and 15 | # forwarding incoming Polaris corrections over the same serial connection. 16 | cc_binary( 17 | name = "serial_port_client", 18 | srcs = ["serial_port_example.cc"], 19 | deps = [ 20 | ":simple_serial_port", 21 | "//:polaris_client", 22 | "@boost//:asio", 23 | "@com_github_gflags_gflags//:gflags", 24 | ], 25 | ) 26 | 27 | # Asynchronous serial port support using the Boost.Asio library. 28 | cc_library( 29 | name = "simple_serial_port", 30 | hdrs = [ 31 | "simple_asio_serial_port.h", 32 | ], 33 | deps = [ 34 | "@boost//:asio", 35 | "@boost//:system", 36 | "@com_github_google_glog//:glog", 37 | ], 38 | ) 39 | 40 | # Example of forwarding RTCM corrections to a Septentrio receiver over a serial 41 | # connection. 42 | cc_binary( 43 | name = "septentrio_client", 44 | srcs = ["septentrio_example.cc"], 45 | deps = [ 46 | "//:polaris_client", 47 | "//examples/septentrio:septentrio_service", 48 | "@boost//:asio", 49 | "@com_github_gflags_gflags//:gflags", 50 | "@com_github_google_glog//:glog", 51 | ], 52 | ) 53 | 54 | ## Simple example of connecting to the Polaris service using the embedded 55 | ## keying method. 56 | #cc_binary( 57 | # name = "simple_embedded_client", 58 | # srcs = ["simple_embedded_client.cc"], 59 | # deps = [ 60 | # "//:polaris_asio_client", 61 | # "//external:gflags", 62 | # "//external:glog", 63 | # ], 64 | #) 65 | -------------------------------------------------------------------------------- /examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # Check for dependencies. 3 | ################################################################################ 4 | 5 | # Find Boost. 6 | find_package(Boost REQUIRED system date_time) 7 | include_directories(${Boost_INCLUDE_DIRS}) 8 | 9 | ################################################################################ 10 | # Example Applications 11 | ################################################################################ 12 | 13 | # Simple example of connecting to the Polaris service. 14 | add_executable(simple_polaris_cpp_client simple_polaris_client.cc) 15 | target_link_libraries(simple_polaris_cpp_client PUBLIC polaris_cpp_client) 16 | 17 | # An example of obtaining receiver positions from a serial NMEA-0183 stream and 18 | # forwarding incoming Polaris corrections over the same serial connection. 19 | add_executable(serial_port_client serial_port_example.cc) 20 | target_link_libraries(serial_port_client PUBLIC polaris_cpp_client) 21 | target_link_libraries(serial_port_client PUBLIC ${Boost_LIBRARIES}) 22 | 23 | # An example of obtaining receiver positions from a serial NMEA-0183 stream and 24 | # forwarding incoming Polaris corrections over the same serial connection. 25 | add_executable(septentrio_client septentrio_example.cc) 26 | add_subdirectory(${PROJECT_SOURCE_DIR}/third_party third_party) 27 | target_include_directories(septentrio PUBLIC ${PROJECT_SOURCE_DIR}/third_party) 28 | target_link_libraries(septentrio_client PUBLIC septentrio) 29 | target_link_libraries(septentrio_client PUBLIC polaris_cpp_client) 30 | target_link_libraries(septentrio_client PUBLIC ${Boost_LIBRARIES}) 31 | 32 | # Example NTRIP server. 33 | add_subdirectory(ntrip) 34 | -------------------------------------------------------------------------------- /examples/data/AsteRx_m2_config.txt: -------------------------------------------------------------------------------- 1 | setDataInOut, COM1, , none 2 | setDataInOut, COM2, , none 3 | setDataInOut, COM3, , none 4 | setDataInOut, COM4, , none 5 | setDataInOut, USB1, , SBF 6 | setSBFGroups, Group1, MeasEpoch+MeasExtra+EndOfMeas+GPSRawCA+PVTGeodetic+ExtEvent+ReceiverStatus 7 | setSBFOutput, Stream1, USB1 8 | setSBFOutput, Stream2, IPS1 9 | setSBFOutput, Stream1, , MeasEpoch+MeasExtra+EndOfMeas+GPSRawCA+GPSRawL2C+GPSRawL5+GLORawCA+GALRawFNAV+GALRawINAV+GEORawL1+GEORawL5+GPSNav+GPSAlm+GPSIon+GPSUtc+GLONav+GLOAlm+GLOTime+GALNav+GALAlm+GALIon+GALUtc+GALGstGps+GALSARRLM+GEOMT00+GEOPRNMask+GEOFastCorr+GEOIntegrity+GEOFastCorrDegr+GEONav+GEODegrFactors+GEONetworkTime+GEOAlm+GEOIGPMask+GEOLongTermCorr+GEOIonoDelay+GEOServiceLevel+GEOClockEphCovMatrix+BaseVectorGeod+PVTGeodetic+PosCovGeodetic+VelCovGeodetic+ReceiverTime+BDSRaw+QZSRawL1CA+QZSRawL2C+QZSRawL5+PosLocal+IRNSSRaw 10 | setSBFOutput, Stream2, , MeasEpoch+MeasExtra+GEORawL1+GPSNav+GPSIon+GPSUtc+GLONav+GLOTime+GALNav+GALIon+GALUtc+GALGstGps+GEONav+PVTGeodetic+ExtEvent+DiffCorrIn+ReceiverSetup+Commands+Comment+BDSNav+QZSNav+BDSIon+BDSUtc 11 | setSBFOutput, Stream1, , , msec100 12 | setSBFOutput, Stream2, , , msec100 13 | setRTCMv2Output, COM1, none 14 | setRTCMv3Formatting, 680 15 | setRTCMv3Output, COM1, RTCM1002+RTCM1004+RTCM1005+RTCM1006+RTCM1010+RTCM1012+RTCM1033+RTCM1230 16 | setIPServerSettings, IPS1, 9000 17 | setStaticPosCartesian, Cartesian1, -2707827.2500 18 | setStaticPosCartesian, Cartesian1, , -4260856.5000 19 | setStaticPosCartesian, Cartesian1, , , 3884899.7500 20 | setClockSyncThreshold, msec1 21 | setLEDMode, DIFFCORLED 22 | setAntennaConnector, Ext 23 | setWBIMitigation, on 24 | setNotchFiltering, Notch1, manual 25 | setNotchFiltering, Notch2, manual 26 | setNotchFiltering, Notch1, , 1600.000 27 | setNotchFiltering, Notch2, , 1200.000 28 | setBBSamplingMode, AfterIM 29 | -------------------------------------------------------------------------------- /examples/external_cmake_project/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # This is a simple example of how to import the Polaris client library in 3 | # your own project using the CMake FetchContent feature. We strongly encourage 4 | # you to use FetchContent to download Polaris client from the publicly available 5 | # source code. 6 | # 7 | # Alternatively, you may choose to use a git submodule to import the source code 8 | # into your repository. We do not recommend copying the Polaris client souce 9 | # code directly into your repository. Doing so makes it much more difficult to 10 | # receive updates as new features and improvements are released. 11 | ################################################################################ 12 | 13 | cmake_minimum_required(VERSION 3.6) 14 | 15 | set(CMAKE_CXX_STANDARD 11) 16 | 17 | project(polaris_usage_example C CXX) 18 | 19 | # Use FetchContent to import the Polaris client C library using Git. 20 | # 21 | # Note that we always recommend using a specific version of the library in your 22 | # code by specifying a git tag (e.g., `GIT_TAG v1.3.1`), and updating that as 23 | # new versions are released. That way, you can be sure that your code is always 24 | # built with a known version of Polaris client. If you prefer, however, you can 25 | # set the GIT_TAG to track the latest changes by setting `GIT_TAG master` below. 26 | # 27 | # We explicitly disable example applications from the Polaris client library by 28 | # setting POLARIS_BUILD_EXAMPLES to OFF below. We only want to build the library 29 | # and make the fusion_engine_client CMake target available here. By default, if 30 | # we do not tell it otherwise, FetchContent_MakeAvailable() will also import all 31 | # of the example applications in polaris/examples/. 32 | # 33 | # It is important to specify it as an INTERNAL variable. If you do not do this, 34 | # the option definition in the fusion-engine-client CMakeLists.txt file will 35 | # override this value and enable the example applications anyway. This is a 36 | # result of CMP0077, which was added in CMake 3.13. 37 | include(FetchContent) 38 | FetchContent_Declare( 39 | polaris 40 | GIT_REPOSITORY https://github.com/PointOneNav/polaris.git 41 | GIT_TAG v1.3.1 42 | ) 43 | set(POLARIS_BUILD_EXAMPLES OFF CACHE INTERNAL "") 44 | FetchContent_MakeAvailable(polaris) 45 | 46 | # Now we define an example application that uses the Polaris client library. 47 | # In your own code, you can link any add_executable() or add_library() target 48 | # with polaris_client by calling target_link_libraries() as shown. 49 | add_executable(example_app main.cc) 50 | target_link_libraries(example_app PUBLIC polaris_cpp_client) 51 | -------------------------------------------------------------------------------- /examples/external_cmake_project/main.cc: -------------------------------------------------------------------------------- 1 | /**************************************************************************/ /** 2 | * @brief Example external cmake project. 3 | * 4 | * Copyright (c) Point One Navigation - All Rights Reserved 5 | ******************************************************************************/ 6 | 7 | #include 8 | #include 9 | 10 | using namespace point_one::polaris; 11 | 12 | int main(int argc, const char* argv[]) { 13 | P1_printf("Hello, world!\n"); 14 | P1_printf("sizeof(PolarisClient): %zu B\n", sizeof(PolarisClient)); 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /examples/ntrip/BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//visibility:public"]) 2 | 3 | # An example NTRIP server that forwards corrections from Polaris to connected 4 | # NTRIP clients. 5 | cc_binary( 6 | name = "ntrip_example_server", 7 | srcs = ["ntrip_example.cc"], 8 | data = ["index.html"], 9 | deps = [ 10 | ":ntrip_server_lib", 11 | "//:polaris_client", 12 | "@boost//:asio", 13 | "@com_github_gflags_gflags//:gflags", 14 | "@com_github_google_glog//:glog", 15 | ], 16 | ) 17 | 18 | # Simple NTRIP client meant for testing the NTRIP server example. 19 | cc_binary( 20 | name = "ntrip_example_client", 21 | srcs = ["ntrip_example_test_client.cc"], 22 | deps = [ 23 | "@boost//:asio", 24 | "@com_github_gflags_gflags//:gflags", 25 | "@com_github_google_glog//:glog", 26 | ], 27 | ) 28 | 29 | # Simple NTRIP server library. 30 | cc_library( 31 | name = "ntrip_server_lib", 32 | srcs = [ 33 | "connection.cc", 34 | "connection_manager.cc", 35 | "mime_types.cc", 36 | "ntrip_server.cc", 37 | "reply.cc", 38 | "request_handler.cc", 39 | "request_parser.cc", 40 | ], 41 | hdrs = [ 42 | "connection.h", 43 | "connection_manager.h", 44 | "header.h", 45 | "mime_types.h", 46 | "ntrip_server.h", 47 | "reply.h", 48 | "request.h", 49 | "request_handler.h", 50 | "request_parser.h", 51 | ], 52 | data = ["index.html"], 53 | deps = [ 54 | "@boost//:asio", 55 | "@boost//:date_time", 56 | "@boost//:system", 57 | "@boost//:tribool", 58 | "@com_github_gflags_gflags//:gflags", 59 | "@com_github_google_glog//:glog", 60 | ], 61 | ) 62 | -------------------------------------------------------------------------------- /examples/ntrip/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Simple NTRIP server library. 2 | add_library(ntrip 3 | connection.cc 4 | connection.h 5 | connection_manager.cc 6 | connection_manager.h 7 | header.h 8 | mime_types.cc 9 | mime_types.h 10 | ntrip_server.cc 11 | ntrip_server.h 12 | reply.cc 13 | reply.h 14 | request.h 15 | request_handler.cc 16 | request_handler.h 17 | request_parser.cc 18 | request_parser.h) 19 | 20 | # An example NTRIP server that forwards corrections from Polaris to connected 21 | # NTRIP clients. 22 | add_executable(ntrip_example_server ntrip_example.cc) 23 | target_link_libraries(ntrip_example_server PUBLIC ntrip) 24 | target_link_libraries(ntrip_example_server PUBLIC polaris_cpp_client) 25 | target_link_libraries(ntrip_example_server PUBLIC ${Boost_LIBRARIES}) 26 | 27 | # Simple NTRIP client meant for testing the NTRIP server example. 28 | add_executable(ntrip_example_client ntrip_example_test_client.cc) 29 | target_link_libraries(ntrip_example_client PUBLIC ${GLOG_LIBRARIES}) 30 | target_link_libraries(ntrip_example_client PUBLIC ${GFLAGS_LIBRARIES}) 31 | target_link_libraries(ntrip_example_client PUBLIC ${Boost_LIBRARIES}) 32 | -------------------------------------------------------------------------------- /examples/ntrip/connection.cc: -------------------------------------------------------------------------------- 1 | // Example ntrip server using boost asio, based off of boost http server example 2 | // See http://www.boost.org/LICENSE_1_0.txt 3 | 4 | #include "connection.h" 5 | #include 6 | #include 7 | #include 8 | #include "connection_manager.h" 9 | #include "request_handler.h" 10 | 11 | #include "glog/logging.h" 12 | 13 | namespace ntrip { 14 | 15 | connection::connection(boost::asio::io_service& io_service, 16 | connection_manager& manager, request_handler& handler) 17 | : socket_(io_service), 18 | connection_manager_(manager), 19 | request_handler_(handler), 20 | connection_upgraded_(false) {} 21 | 22 | boost::asio::ip::tcp::socket& connection::socket() { return socket_; } 23 | 24 | void connection::start() { 25 | socket_.async_read_some( 26 | boost::asio::buffer(buffer_), 27 | boost::bind(&connection::handle_read, shared_from_this(), 28 | boost::asio::placeholders::error, 29 | boost::asio::placeholders::bytes_transferred)); 30 | } 31 | 32 | void connection::async_send(const std::string& data) { 33 | broadcast_buffer_ = data; 34 | boost::asio::async_write( 35 | socket_, boost::asio::buffer(data), 36 | boost::bind(&connection::handle_write, shared_from_this(), 37 | boost::asio::placeholders::error)); 38 | } 39 | 40 | void connection::stop() { socket_.close(); } 41 | 42 | void connection::handle_read(const boost::system::error_code& e, 43 | std::size_t bytes_transferred) { 44 | if (!e) { 45 | VLOG(4) << std::string(buffer_.data(), buffer_.size()); 46 | 47 | boost::tribool result; 48 | if (boost::istarts_with(buffer_, "$GPGGA") || 49 | boost::istarts_with(buffer_, "$INGGA")) { 50 | if (connection_upgraded_) { 51 | connection_manager_.SetGpgga( 52 | std::string(buffer_.data(), buffer_.size())); 53 | socket_.async_read_some( 54 | boost::asio::buffer(buffer_), 55 | boost::bind(&connection::handle_read, shared_from_this(), 56 | boost::asio::placeholders::error, 57 | boost::asio::placeholders::bytes_transferred)); 58 | } else { 59 | reply_ = reply::stock_reply(reply::bad_request); 60 | boost::asio::async_write( 61 | socket_, reply_.to_buffers(), 62 | boost::bind(&connection::handle_write, shared_from_this(), 63 | boost::asio::placeholders::error)); 64 | } 65 | 66 | } else if (!connection_upgraded_) { 67 | boost::tie(result, boost::tuples::ignore) = request_parser_.parse( 68 | request_, buffer_.data(), buffer_.data() + bytes_transferred); 69 | } else { 70 | socket_.async_read_some( 71 | boost::asio::buffer(buffer_), 72 | boost::bind(&connection::handle_read, shared_from_this(), 73 | boost::asio::placeholders::error, 74 | boost::asio::placeholders::bytes_transferred)); 75 | } 76 | 77 | if (result) { 78 | request_handler_.handle_request(request_, reply_); 79 | if (reply_.status == reply::icy_ok) { 80 | LOG(INFO) << "Connection Upgraded!"; 81 | connection_upgraded_ = true; 82 | mount_point_ = reply_.mount_point; 83 | if (!reply_.ntrip_gga.empty()) { 84 | connection_manager_.SetGpgga(reply_.ntrip_gga); 85 | } 86 | } 87 | 88 | boost::asio::async_write( 89 | socket_, reply_.to_buffers(), 90 | boost::bind(&connection::handle_write, shared_from_this(), 91 | boost::asio::placeholders::error)); 92 | } else if (!result) { 93 | reply_ = reply::stock_reply(reply::bad_request); 94 | boost::asio::async_write( 95 | socket_, reply_.to_buffers(), 96 | boost::bind(&connection::handle_write, shared_from_this(), 97 | boost::asio::placeholders::error)); 98 | } else { 99 | socket_.async_read_some( 100 | boost::asio::buffer(buffer_), 101 | boost::bind(&connection::handle_read, shared_from_this(), 102 | boost::asio::placeholders::error, 103 | boost::asio::placeholders::bytes_transferred)); 104 | } 105 | } else if (e != boost::asio::error::operation_aborted) { 106 | LOG(ERROR) << "Read error: " << e; 107 | connection_manager_.stop(shared_from_this()); 108 | } 109 | } 110 | 111 | void connection::handle_write(const boost::system::error_code& e) { 112 | if (!e) { 113 | if (connection_upgraded_) { 114 | connection_manager_.upgrade_connection(shared_from_this(), mount_point_); 115 | socket_.async_read_some( 116 | boost::asio::buffer(buffer_), 117 | boost::bind(&connection::handle_read, shared_from_this(), 118 | boost::asio::placeholders::error, 119 | boost::asio::placeholders::bytes_transferred)); 120 | } else { 121 | // Initiate graceful connection closure. 122 | LOG(INFO) << "Closing connection: " << connection_upgraded_; 123 | 124 | boost::system::error_code ignored_ec; 125 | socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec); 126 | } 127 | } else if (e != boost::asio::error::operation_aborted) { 128 | LOG(ERROR) << "Write error: " << e; 129 | connection_manager_.stop(shared_from_this()); 130 | } 131 | } 132 | 133 | } // namespace ntrip 134 | -------------------------------------------------------------------------------- /examples/ntrip/connection.h: -------------------------------------------------------------------------------- 1 | // Example ntrip server using boost asio, based off of boost http server example 2 | // See http://www.boost.org/LICENSE_1_0.txt 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "reply.h" 12 | #include "request.h" 13 | #include "request_handler.h" 14 | #include "request_parser.h" 15 | 16 | namespace ntrip { 17 | 18 | class connection_manager; 19 | 20 | /// Represents a single connection from a client. 21 | class connection : public boost::enable_shared_from_this, 22 | private boost::noncopyable { 23 | public: 24 | /// Construct a connection with the given io_service. 25 | explicit connection(boost::asio::io_service& io_service, 26 | connection_manager& manager, request_handler& handler); 27 | 28 | /// Get the socket associated with the connection. 29 | boost::asio::ip::tcp::socket& socket(); 30 | 31 | /// Start the first asynchronous operation for the connection. 32 | void start(); 33 | 34 | void async_send(const std::string& data); 35 | 36 | /// Stop all asynchronous operations associated with the connection. 37 | void stop(); 38 | 39 | std::string mount_point() { return mount_point_; } 40 | 41 | private: 42 | /// Handle completion of a read operation. 43 | void handle_read(const boost::system::error_code& e, 44 | std::size_t bytes_transferred); 45 | 46 | /// Handle completion of a write operation. 47 | void handle_write(const boost::system::error_code& e); 48 | 49 | /// Socket for the connection. 50 | boost::asio::ip::tcp::socket socket_; 51 | 52 | /// The manager for this connection. 53 | connection_manager& connection_manager_; 54 | 55 | /// The handler used to process the incoming request. 56 | request_handler& request_handler_; 57 | 58 | /// Buffer for incoming data. 59 | boost::array buffer_; 60 | 61 | // Send buffer 62 | std::string broadcast_buffer_; 63 | 64 | /// The incoming request. 65 | request request_; 66 | 67 | /// The parser for the incoming request. 68 | request_parser request_parser_; 69 | 70 | /// The reply to be sent back to the client. 71 | reply reply_; 72 | 73 | bool connection_upgraded_; 74 | 75 | std::string mount_point_; 76 | }; 77 | 78 | typedef boost::shared_ptr connection_ptr; 79 | 80 | } // namespace ntrip 81 | -------------------------------------------------------------------------------- /examples/ntrip/connection_manager.cc: -------------------------------------------------------------------------------- 1 | // Example ntrip server using boost asio, based off of boost http server example 2 | // See http://www.boost.org/LICENSE_1_0.txt 3 | 4 | #include "connection_manager.h" 5 | #include 6 | #include 7 | 8 | #include "glog/logging.h" 9 | 10 | namespace ntrip { 11 | 12 | void connection_manager::start(connection_ptr c) { 13 | connections_.insert(c); 14 | c->start(); 15 | } 16 | 17 | void connection_manager::stop(connection_ptr c) { 18 | connections_.erase(c); 19 | if (mounted_connections_.find(c->mount_point()) != 20 | mounted_connections_.end() && 21 | mounted_connections_[c->mount_point()].find(c) != 22 | mounted_connections_[c->mount_point()].end()) { 23 | mounted_connections_[c->mount_point()].erase(c); 24 | } 25 | c->stop(); 26 | LOG(INFO) << "Connection closed"; 27 | } 28 | 29 | void connection_manager::SetGpggaCallback( 30 | std::function callback) { 31 | gpgga_callback_ = callback; 32 | } 33 | 34 | void connection_manager::SetGpgga(const std::string &data) { 35 | if (gpgga_callback_) { 36 | gpgga_callback_(data); 37 | } 38 | } 39 | 40 | void connection_manager::broadcast(const std::string &mount_point, 41 | const std::string &data) { 42 | if (mounted_connections_.find(mount_point) == mounted_connections_.end()) { 43 | return; 44 | } 45 | VLOG(4) << "Broadcasting bytes: " << data.size(); 46 | for (auto c : mounted_connections_[mount_point]) { 47 | c->async_send(data); 48 | } 49 | } 50 | 51 | void connection_manager::upgrade_connection(connection_ptr c, 52 | const std::string &mount_point) { 53 | mounted_connections_[c->mount_point()].insert(c); 54 | } 55 | 56 | void connection_manager::stop_all() { 57 | std::for_each(connections_.begin(), connections_.end(), 58 | boost::bind(&connection::stop, _1)); 59 | connections_.clear(); 60 | } 61 | 62 | } // namespace ntrip 63 | -------------------------------------------------------------------------------- /examples/ntrip/connection_manager.h: -------------------------------------------------------------------------------- 1 | // Example ntrip server using boost asio, based off of boost http server example 2 | // See http://www.boost.org/LICENSE_1_0.txt 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "connection.h" 11 | 12 | namespace ntrip { 13 | /// Manages open connections so that they may be cleanly stopped when the server 14 | /// needs to shut down. 15 | class connection_manager : private boost::noncopyable { 16 | public: 17 | /// Add the specified connection to the manager and start it. 18 | void start(connection_ptr c); 19 | 20 | void upgrade_connection(connection_ptr c, const std::string &mount_point); 21 | 22 | void broadcast(const std::string &mount_point, const std::string &data); 23 | 24 | void SetGpggaCallback(std::function callback); 25 | 26 | void SetGpgga(const std::string &); 27 | 28 | /// Stop the specified connection. 29 | void stop(connection_ptr c); 30 | 31 | /// Stop all connections. 32 | void stop_all(); 33 | 34 | private: 35 | /// The managed connections. 36 | std::set connections_; 37 | 38 | std::map> mounted_connections_; 39 | 40 | std::function gpgga_callback_; 41 | }; 42 | 43 | } // namespace ntrip 44 | -------------------------------------------------------------------------------- /examples/ntrip/header.h: -------------------------------------------------------------------------------- 1 | // Example ntrip server using boost asio, based off of boost http server example 2 | // See http://www.boost.org/LICENSE_1_0.txt 3 | 4 | #pragma once 5 | 6 | #include 7 | 8 | namespace ntrip { 9 | 10 | struct header { 11 | std::string name; 12 | std::string value; 13 | }; 14 | 15 | } // namespace ntrip 16 | -------------------------------------------------------------------------------- /examples/ntrip/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | PointOne Sample Ntrip Caster 4 | 5 | 6 | Point One Sample NTRIP Caster

7 | Connect to this URL using an NTRIP client to get correction data. 8 | 9 | 10 | -------------------------------------------------------------------------------- /examples/ntrip/mime_types.cc: -------------------------------------------------------------------------------- 1 | // Example ntrip server using boost asio, based off of boost http server example 2 | // See http://www.boost.org/LICENSE_1_0.txt 3 | 4 | #include "mime_types.h" 5 | 6 | namespace ntrip { 7 | 8 | struct mapping { 9 | const char* extension; 10 | const char* mime_type; 11 | } mappings[] = { 12 | {"gif", "image/gif"}, {"htm", "text/html"}, {"html", "text/html"}, 13 | {"jpg", "image/jpeg"}, {"png", "image/png"}, {0, 0} // Marks end of list. 14 | }; 15 | 16 | std::string extension_to_type(const std::string& extension) { 17 | for (mapping* m = mappings; m->extension; ++m) { 18 | if (m->extension == extension) { 19 | return m->mime_type; 20 | } 21 | } 22 | 23 | return "text/plain"; 24 | } 25 | 26 | } // namespace ntrip -------------------------------------------------------------------------------- /examples/ntrip/mime_types.h: -------------------------------------------------------------------------------- 1 | // Example ntrip server using boost asio, based off of boost http server example 2 | // See http://www.boost.org/LICENSE_1_0.txt 3 | 4 | #pragma once 5 | 6 | #include 7 | 8 | namespace ntrip { 9 | 10 | /// Convert a file extension into a MIME type. 11 | std::string extension_to_type(const std::string& extension); 12 | 13 | } // namespace ntrip -------------------------------------------------------------------------------- /examples/ntrip/ntrip-proxy.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Ntrip Proxy Service 3 | 4 | [Service] 5 | ExecStart=/home/pointone/polaris/examples/ntrip/ntrip_proxy.sh 6 | WorkingDirectory=/home/pointone/polaris/examples/ntrip 7 | Restart=always 8 | RestartSec=10 9 | StandardOutput=syslog 10 | StandardError=syslog 11 | SyslogIdentifier=ntrip-proxy 12 | 13 | [Install] 14 | WantedBy=multi-user.target -------------------------------------------------------------------------------- /examples/ntrip/ntrip_example.cc: -------------------------------------------------------------------------------- 1 | /**************************************************************************/ /** 2 | * @brief Example of relaying Polaris corrections as an NTRIP server. 3 | * 4 | * Copyright (c) Point One Navigation - All Rights Reserved 5 | ******************************************************************************/ 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | #include "ntrip_server.h" 18 | 19 | // Allows for prebuilt versions of gflags/google that don't have gflags/google 20 | // namespace. 21 | namespace gflags {} 22 | namespace google {} 23 | using namespace gflags; 24 | using namespace google; 25 | 26 | using namespace point_one::polaris; 27 | 28 | // Options for connecting to Polaris Server: 29 | DEFINE_string( 30 | polaris_host, "", 31 | "Specify an alternate Polaris corrections endpoint URL to be used."); 32 | 33 | DEFINE_int32(polaris_port, 0, 34 | "Specify an alternate TCP port for the Polaris corrections " 35 | "endpoint."); 36 | 37 | DEFINE_string(polaris_api_key, "", 38 | "The polaris API key. Sign up at app.pointonenav.com."); 39 | 40 | DEFINE_string(polaris_unique_id, "ntrip-device12345", 41 | "The unique ID to assign to this Polaris connection."); 42 | 43 | double ConvertGGADegrees(double gga_degrees) { 44 | double degrees = std::floor(gga_degrees/100.0); 45 | degrees += (gga_degrees - degrees * 100) / 60.0; 46 | return degrees; 47 | } 48 | 49 | void OnGpgga(const std::string& gpgga, PolarisClient* polaris_client) { 50 | LOG_FIRST_N(INFO, 1) << "Got first receiver GPGGA: " << gpgga; 51 | VLOG(1) << "Got receiver GPGGA: " << gpgga; 52 | std::stringstream ss(gpgga); 53 | std::vector result; 54 | 55 | while( ss.good() ) 56 | { 57 | std::string substr; 58 | std::getline( ss, substr, ',' ); 59 | result.push_back( substr ); 60 | } 61 | std::string::size_type sz; // alias of size_t 62 | 63 | try { 64 | // TODO: This is not exactly correct but should not really matter because its just beacon association. 65 | double lat = ConvertGGADegrees(std::stod(result[2], &sz)) * (result[3] == "N" ? 1 : -1); 66 | double lon = ConvertGGADegrees(std::stod(result[4], &sz)) * (result[5] == "E" ? 1 : -1); 67 | double alt = std::stod(result[8], &sz); 68 | 69 | VLOG(2) << "Setting position: lat: " << lat << " lon: " << lon << " alt: " << alt; 70 | polaris_client->SendLLAPosition(lat, lon, alt); 71 | } 72 | catch (const std::exception&){ 73 | LOG(WARNING) << "GPGGA Bad parse of string " << gpgga; 74 | return; 75 | } 76 | } 77 | 78 | 79 | int main(int argc, char* argv[]) { 80 | // Parse commandline flags. 81 | FLAGS_logtostderr = true; 82 | FLAGS_colorlogtostderr = true; 83 | ParseCommandLineFlags(&argc, &argv, true); 84 | 85 | // Setup logging interface. 86 | InitGoogleLogging(argv[0]); 87 | 88 | try { 89 | // Check command line arguments. 90 | if (argc != 4) { 91 | LOG(INFO) << "Usage: ntrip_example --polaris_api_key=KEY
\n"; 92 | LOG(INFO) << "For IPv4, try: --polaris_api_key=KEY 0.0.0.0 2101 examples/ntrip\n"; 93 | return 1; 94 | } 95 | 96 | // Create connection to receiver to forward correction data received from 97 | // Polaris Server. 98 | 99 | // Construct a Polaris client. 100 | if (FLAGS_polaris_api_key == "") { 101 | LOG(ERROR) 102 | << "You must supply a Polaris API key to connect to the server."; 103 | return 1; 104 | } 105 | 106 | PolarisClient polaris_client(FLAGS_polaris_api_key, 107 | FLAGS_polaris_unique_id); 108 | polaris_client.SetPolarisEndpoint(FLAGS_polaris_host, FLAGS_polaris_port); 109 | 110 | // Setup the NTRIP server. 111 | std::string ntrip_host = argv[1]; 112 | std::string ntrip_port = argv[2]; 113 | std::string ntrip_root = argv[3]; 114 | LOG(INFO) << "Starting NTRIP server on " << ntrip_host << ":" << ntrip_port 115 | << "."; 116 | boost::asio::io_service io_loop; 117 | boost::asio::io_service::work work(io_loop); 118 | ntrip::server ntrip_server(io_loop, ntrip_host, ntrip_port, ntrip_root); 119 | 120 | polaris_client.SetRTCMCallback( 121 | std::bind(&ntrip::server::broadcast, &ntrip_server, "/Polaris", 122 | std::placeholders::_1, std::placeholders::_2)); 123 | 124 | ntrip_server.SetGpggaCallback( 125 | std::bind(OnGpgga, std::placeholders::_1, &polaris_client)); 126 | 127 | // Run the Polaris connection connection asynchronously. 128 | LOG(INFO) << "Connecting to Polaris..."; 129 | polaris_client.RunAsync(); 130 | 131 | // Now run the Boost IO loop to communicate with the serial port. This will 132 | // block forever. 133 | LOG(INFO) << "Running NTRIP server..."; 134 | io_loop.run(); 135 | } catch (std::exception& e) { 136 | LOG(ERROR) << "Caught exception: " << e.what(); 137 | } 138 | 139 | return 0; 140 | } 141 | -------------------------------------------------------------------------------- /examples/ntrip/ntrip_example_test_client.cc: -------------------------------------------------------------------------------- 1 | // Example ntrip client using boost asio, based off of boost http server example 2 | // See http://www.boost.org/LICENSE_1_0.txt 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | using boost::asio::ip::tcp; 12 | 13 | class client { 14 | public: 15 | client(boost::asio::io_service& io_service, const std::string& server, 16 | const std::string& path) 17 | : resolver_(io_service), socket_(io_service), response_(4096) { 18 | // Form the request. We specify the "Connection: close" header so that the 19 | // server will close the socket after transmitting the response. This will 20 | // allow us to treat all data up until the EOF as the content. 21 | std::ostream request_stream(&request_); 22 | request_stream << "GET " << path << " HTTP/1.0\r\n"; 23 | request_stream << "User-Agent: NTRIP" 24 | << "\r\n"; 25 | request_stream << "Accept: */*\r\n"; 26 | request_stream << "Connection: close\r\n\r\n"; 27 | 28 | // Start an asynchronous resolve to translate the server and service names 29 | // into a list of endpoints. 30 | tcp::resolver::query query(server, std::to_string(2101)); 31 | resolver_.async_resolve(query, 32 | boost::bind(&client::handle_resolve, this, 33 | boost::asio::placeholders::error, 34 | boost::asio::placeholders::iterator)); 35 | } 36 | 37 | private: 38 | void handle_resolve(const boost::system::error_code& err, 39 | tcp::resolver::iterator endpoint_iterator) { 40 | if (!err) { 41 | // Attempt a connection to each endpoint in the list until we 42 | // successfully establish a connection. 43 | boost::asio::async_connect(socket_, endpoint_iterator, 44 | boost::bind(&client::handle_connect, this, 45 | boost::asio::placeholders::error)); 46 | } else { 47 | std::cout << "Error: " << err.message() << "\n"; 48 | } 49 | } 50 | 51 | void handle_connect(const boost::system::error_code& err) { 52 | if (!err) { 53 | // The connection was successful. Send the request. 54 | boost::asio::async_write(socket_, request_, 55 | boost::bind(&client::handle_write_request, this, 56 | boost::asio::placeholders::error)); 57 | } else { 58 | std::cout << "Error: " << err.message() << "\n"; 59 | } 60 | } 61 | 62 | void handle_write_request(const boost::system::error_code& err) { 63 | if (!err) { 64 | // Read the response status line. The response_ streambuf will 65 | // automatically grow to accommodate the entire line. The growth may be 66 | // limited by passing a maximum size to the streambuf constructor. 67 | boost::asio::async_read_until( 68 | socket_, response_, "\r\n", 69 | boost::bind(&client::handle_read_status_line, this, 70 | boost::asio::placeholders::error)); 71 | } else { 72 | std::cout << "Error: " << err.message() << "\n"; 73 | } 74 | } 75 | 76 | void handle_gga_write(const boost::system::error_code& err) { 77 | if (!err) { 78 | gga_sent_ = true; 79 | boost::asio::async_read( 80 | socket_, response_, boost::asio::transfer_at_least(1), 81 | boost::bind(&client::handle_read_icy, this, 82 | boost::asio::placeholders::error, 83 | boost::asio::placeholders::bytes_transferred)); 84 | } else { 85 | std::cout << "Error: " << err.message() << "\n"; 86 | } 87 | } 88 | 89 | void handle_read_status_line(const boost::system::error_code& err) { 90 | if (!err) { 91 | // Check that response is OK. 92 | std::istream response_stream(&response_); 93 | std::string http_version; 94 | response_stream >> http_version; 95 | unsigned int status_code; 96 | response_stream >> status_code; 97 | std::string status_message; 98 | std::getline(response_stream, status_message); 99 | 100 | if (!response_stream) { 101 | std::cout << "Invalid response\n"; 102 | return; 103 | } 104 | if (http_version.substr(0, 5) == "HTTP/") { 105 | return handle_http(); 106 | } else if (http_version.substr(0, 11) == "SOURCETABLE") { 107 | std::cout << "Received source table: " << std::endl; 108 | return handle_source_table(); 109 | } else if (http_version.substr(0, 3) == "ICY") { 110 | std::cout << "Upgraded to ICY" << std::endl; 111 | return handle_icy(); 112 | } else { 113 | std::cout << "Invalid response\n"; 114 | std::cout << http_version << std::endl; 115 | return; 116 | } 117 | if (status_code != 200) { 118 | std::cout << "Response returned with status code "; 119 | std::cout << status_code << "\n"; 120 | return; 121 | } 122 | 123 | } else { 124 | std::cout << "Error: " << err << "\n"; 125 | } 126 | } 127 | 128 | void handle_http() { 129 | boost::asio::async_read_until( 130 | socket_, response_, "\r\n\r\n", 131 | boost::bind(&client::handle_read_headers, this, 132 | boost::asio::placeholders::error)); 133 | } 134 | 135 | void handle_source_table() { 136 | boost::asio::async_read_until( 137 | socket_, response_, "\r\n\r\n", 138 | boost::bind(&client::handle_read_content, this, 139 | boost::asio::placeholders::error)); 140 | } 141 | 142 | void handle_icy() { 143 | // Continue reading remaining data until EOF. 144 | if (!gga_sent_) { 145 | boost::asio::async_write(socket_, boost::asio::buffer(gga_string_), 146 | boost::bind(&client::handle_gga_write, this, 147 | boost::asio::placeholders::error)); 148 | return; 149 | } 150 | 151 | boost::asio::async_read( 152 | socket_, response_, boost::asio::transfer_at_least(1), 153 | boost::bind(&client::handle_read_icy, this, 154 | boost::asio::placeholders::error, 155 | boost::asio::placeholders::bytes_transferred)); 156 | } 157 | 158 | void handle_read_icy(const boost::system::error_code& err, 159 | size_t bytes_transferred) { 160 | if (!err && bytes_transferred > 0) { 161 | // Write all of the data that has been read so far. 162 | std::cout << "Read: " << bytes_transferred << std::endl; 163 | // TODO: Do something with this stream data. 164 | std::istream response_stream(&response_); 165 | std::string stream_data; 166 | response_stream >> stream_data; 167 | 168 | // Continue reading remaining data until EOF. 169 | boost::asio::async_read( 170 | socket_, response_, boost::asio::transfer_at_least(1), 171 | boost::bind(&client::handle_read_icy, this, 172 | boost::asio::placeholders::error, 173 | boost::asio::placeholders::bytes_transferred)); 174 | } else if (err != boost::asio::error::eof) { 175 | std::cout << "ICY read Error: " << err << "\n"; 176 | } 177 | } 178 | 179 | void handle_read_headers(const boost::system::error_code& err) { 180 | if (!err) { 181 | // Process the response headers. 182 | std::istream response_stream(&response_); 183 | std::string header; 184 | while (std::getline(response_stream, header) && header != "\r") 185 | std::cout << header << "\n"; 186 | std::cout << "\n"; 187 | 188 | // Write whatever content we already have to output. 189 | if (response_.size() > 0) std::cout << &response_; 190 | 191 | // Start reading remaining data until EOF. 192 | boost::asio::async_read(socket_, response_, 193 | boost::asio::transfer_at_least(1), 194 | boost::bind(&client::handle_read_content, this, 195 | boost::asio::placeholders::error)); 196 | } else { 197 | std::cout << "Error: " << err << "\n"; 198 | } 199 | } 200 | 201 | void handle_read_content(const boost::system::error_code& err) { 202 | if (!err) { 203 | // Write all of the data that has been read so far. 204 | std::cout << &response_; 205 | 206 | // Continue reading remaining data until EOF. 207 | boost::asio::async_read(socket_, response_, 208 | boost::asio::transfer_at_least(1), 209 | boost::bind(&client::handle_read_content, this, 210 | boost::asio::placeholders::error)); 211 | } else if (err != boost::asio::error::eof) { 212 | std::cout << "Error: " << err << "\n"; 213 | } 214 | } 215 | tcp::resolver resolver_; 216 | tcp::socket socket_; 217 | boost::asio::streambuf request_; 218 | boost::asio::streambuf response_; 219 | bool gga_sent_ = false; 220 | std::string gga_string_ = 221 | "$GPGGA,165631.00,3220.8483085,N,12200.900759,W,1,05,01.9,+00400,M,,M,,*?" 222 | "?"; 223 | }; 224 | 225 | int main(int argc, char* argv[]) { 226 | try { 227 | if (argc != 3) { 228 | std::cout << "Usage: async_client \n"; 229 | std::cout << "Example:\n"; 230 | std::cout << " async_client www.boost.org /LICENSE_1_0.txt\n"; 231 | return 1; 232 | } 233 | 234 | boost::asio::io_service io_service; 235 | client c(io_service, argv[1], argv[2]); 236 | io_service.run(); 237 | } catch (std::exception& e) { 238 | std::cout << "Exception: " << e.what() << "\n"; 239 | } 240 | 241 | return 0; 242 | } 243 | -------------------------------------------------------------------------------- /examples/ntrip/ntrip_proxy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | bazel-run.sh -c opt :ntrip_example -- --polaris_api_key=${MY_POLARIS_APP_KEY} --logtostderr 0.0.0.0 2101 . -------------------------------------------------------------------------------- /examples/ntrip/ntrip_server.cc: -------------------------------------------------------------------------------- 1 | // Example ntrip server using boost asio, based off of boost http server example 2 | // See http://www.boost.org/LICENSE_1_0.txt 3 | 4 | #include "ntrip_server.h" 5 | #include 6 | #include 7 | namespace ntrip { 8 | 9 | server::server(boost::asio::io_service& io_service, const std::string& address, 10 | const std::string& port, const std::string& doc_root) 11 | : io_service_(io_service), 12 | signals_(io_service_), 13 | acceptor_(io_service_), 14 | connection_manager_(), 15 | new_connection_(), 16 | request_handler_(doc_root) { 17 | // Register to handle the signals that indicate when the server should exit. 18 | // It is safe to register for the same signal multiple times in a program, 19 | // provided all registration for the specified signal is made through Asio. 20 | /* 21 | signals_.add(SIGINT); 22 | signals_.add(SIGTERM); 23 | #if defined(SIGQUIT) 24 | signals_.add(SIGQUIT); 25 | #endif // defined(SIGQUIT) 26 | signals_.async_wait(boost::bind(&server::handle_stop, this)); 27 | */ 28 | 29 | // Open the acceptor with the option to reuse the address (i.e. SO_REUSEADDR). 30 | boost::asio::ip::tcp::resolver resolver(io_service_); 31 | boost::asio::ip::tcp::resolver::query query(address, port); 32 | boost::asio::ip::tcp::endpoint endpoint = *resolver.resolve(query); 33 | acceptor_.open(endpoint.protocol()); 34 | acceptor_.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true)); 35 | acceptor_.bind(endpoint); 36 | acceptor_.listen(); 37 | 38 | start_accept(); 39 | } 40 | 41 | void server::start_accept() { 42 | new_connection_.reset( 43 | new connection(io_service_, connection_manager_, request_handler_)); 44 | acceptor_.async_accept(new_connection_->socket(), 45 | boost::bind(&server::handle_accept, this, 46 | boost::asio::placeholders::error)); 47 | } 48 | 49 | void server::SetGpggaCallback(std::function callback) { 50 | connection_manager_.SetGpggaCallback(callback); 51 | } 52 | 53 | void server::broadcast(const std::string& mount_point, const uint8_t* data, 54 | size_t len) { 55 | connection_manager_.broadcast(mount_point, 56 | std::string((const char*)data, len)); 57 | } 58 | 59 | void server::handle_accept(const boost::system::error_code& e) { 60 | // Check whether the server was stopped by a signal before this completion 61 | // handler had a chance to run. 62 | if (!acceptor_.is_open()) { 63 | return; 64 | } 65 | 66 | if (!e) { 67 | connection_manager_.start(new_connection_); 68 | } 69 | 70 | start_accept(); 71 | } 72 | 73 | void server::handle_stop() { 74 | // The server is stopped by cancelling all outstanding asynchronous 75 | // operations. Once all operations have finished the io_service::run() call 76 | // will exit. 77 | acceptor_.close(); 78 | connection_manager_.stop_all(); 79 | } 80 | 81 | } // namespace ntrip 82 | -------------------------------------------------------------------------------- /examples/ntrip/ntrip_server.h: -------------------------------------------------------------------------------- 1 | // Example ntrip server using boost asio, based off of boost http server example 2 | // See http://www.boost.org/LICENSE_1_0.txt 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | #include "connection.h" 10 | #include "connection_manager.h" 11 | #include "request_handler.h" 12 | 13 | namespace ntrip { 14 | 15 | /// The top-level class of the HTTP server. 16 | class server { 17 | public: 18 | /// Construct the server to listen on the specified TCP address and port, and 19 | /// serve up files from the given directory. 20 | explicit server(boost::asio::io_service& io_service, 21 | const std::string& address, const std::string& port, 22 | const std::string& doc_root); 23 | 24 | void broadcast(const std::string& mount_point, const uint8_t* data, 25 | size_t len); 26 | 27 | void SetGpggaCallback(std::function callback); 28 | 29 | void stop(); 30 | 31 | private: 32 | /// Initiate an asynchronous accept operation. 33 | void start_accept(); 34 | 35 | /// Handle completion of an asynchronous accept operation. 36 | void handle_accept(const boost::system::error_code& e); 37 | 38 | /// Handle a request to stop the server. 39 | void handle_stop(); 40 | 41 | /// The io_service used to perform asynchronous operations. 42 | boost::asio::io_service &io_service_; 43 | 44 | /// The signal_set is used to register for process termination notifications. 45 | boost::asio::signal_set signals_; 46 | 47 | /// Acceptor used to listen for incoming connections. 48 | boost::asio::ip::tcp::acceptor acceptor_; 49 | 50 | /// The connection manager which owns all live connections. 51 | connection_manager connection_manager_; 52 | 53 | /// The next connection to be accepted. 54 | connection_ptr new_connection_; 55 | 56 | /// The handler for all incoming requests. 57 | request_handler request_handler_; 58 | }; 59 | 60 | } // namespace once 61 | -------------------------------------------------------------------------------- /examples/ntrip/reply.cc: -------------------------------------------------------------------------------- 1 | // Example ntrip server using boost asio, based off of boost http server example 2 | // See http://www.boost.org/LICENSE_1_0.txt 3 | 4 | #include "reply.h" 5 | #include 6 | #include 7 | 8 | namespace ntrip { 9 | 10 | namespace status_strings { 11 | 12 | const std::string ok = "HTTP/1.0 200 OK\r\n"; 13 | const std::string icy_ok = "ICY 200 OK\r\n"; 14 | const std::string source_table_ok = "SOURCETABLE 200 OK\r\n"; 15 | const std::string bad_request = "HTTP/1.0 400 Bad Request\r\n"; 16 | const std::string not_found = "HTTP/1.0 404 Not Found\r\n"; 17 | const std::string internal_server_error = 18 | "HTTP/1.0 500 Internal Server Error\r\n"; 19 | 20 | boost::asio::const_buffer to_buffer(reply::status_type status) { 21 | switch (status) { 22 | case reply::ok: 23 | return boost::asio::buffer(ok); 24 | case reply::icy_ok: 25 | return boost::asio::buffer(icy_ok); 26 | case reply::source_table_ok: 27 | return boost::asio::buffer(source_table_ok); 28 | case reply::bad_request: 29 | return boost::asio::buffer(bad_request); 30 | case reply::not_found: 31 | return boost::asio::buffer(not_found); 32 | case reply::internal_server_error: 33 | return boost::asio::buffer(internal_server_error); 34 | default: 35 | return boost::asio::buffer(internal_server_error); 36 | } 37 | } 38 | 39 | } // namespace status_strings 40 | 41 | namespace misc_strings { 42 | 43 | const char name_value_separator[] = {':', ' '}; 44 | const char crlf[] = {'\r', '\n'}; 45 | 46 | } // namespace misc_strings 47 | 48 | std::vector reply::to_buffers() { 49 | std::vector buffers; 50 | buffers.push_back(status_strings::to_buffer(status)); 51 | for (std::size_t i = 0; i < headers.size(); ++i) { 52 | header& h = headers[i]; 53 | buffers.push_back(boost::asio::buffer(h.name)); 54 | buffers.push_back(boost::asio::buffer(misc_strings::name_value_separator)); 55 | buffers.push_back(boost::asio::buffer(h.value)); 56 | buffers.push_back(boost::asio::buffer(misc_strings::crlf)); 57 | } 58 | buffers.push_back(boost::asio::buffer(misc_strings::crlf)); 59 | buffers.push_back(boost::asio::buffer(content)); 60 | return buffers; 61 | } 62 | 63 | namespace stock_replies { 64 | 65 | const char ok[] = ""; 66 | const char icy_ok[] = ""; 67 | const char source_table_ok[] = ""; 68 | const char bad_request[] = 69 | "" 70 | "Bad Request" 71 | "

400 Bad Request

" 72 | ""; 73 | const char not_found[] = 74 | "" 75 | "Not Found" 76 | "

404 Not Found

" 77 | ""; 78 | const char internal_server_error[] = 79 | "" 80 | "Internal Server Error" 81 | "

500 Internal Server Error

" 82 | ""; 83 | 84 | std::string to_string(reply::status_type status) { 85 | switch (status) { 86 | case reply::ok: 87 | return ok; 88 | case reply::icy_ok: 89 | return ok; 90 | case reply::source_table_ok: 91 | return ok; 92 | case reply::bad_request: 93 | return bad_request; 94 | case reply::not_found: 95 | return not_found; 96 | case reply::internal_server_error: 97 | return internal_server_error; 98 | default: 99 | return internal_server_error; 100 | } 101 | } 102 | 103 | } // namespace stock_replies 104 | 105 | reply reply::stock_reply(reply::status_type status) { 106 | reply rep; 107 | rep.status = status; 108 | rep.content = stock_replies::to_string(status); 109 | rep.headers.resize(2); 110 | rep.headers[0].name = "Content-Length"; 111 | rep.headers[0].value = boost::lexical_cast(rep.content.size()); 112 | rep.headers[1].name = "Content-Type"; 113 | rep.headers[1].value = "text/html"; 114 | return rep; 115 | } 116 | 117 | } // namespace ntrip -------------------------------------------------------------------------------- /examples/ntrip/reply.h: -------------------------------------------------------------------------------- 1 | // Example ntrip server using boost asio, based off of boost http server example 2 | // See http://www.boost.org/LICENSE_1_0.txt 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | #include "header.h" 10 | 11 | namespace ntrip { 12 | 13 | /// A reply to be sent to a client. 14 | struct reply { 15 | /// The status of the reply. 16 | enum status_type { 17 | ok = 200, 18 | icy_ok = 205, 19 | source_table_ok = 206, 20 | bad_request = 400, 21 | not_found = 404, 22 | internal_server_error = 500, 23 | } status; 24 | 25 | /// The headers to be included in the reply. 26 | std::vector
headers; 27 | 28 | /// The content to be sent in the reply. 29 | std::string content; 30 | 31 | /// Convert the reply into a vector of buffers. The buffers do not own the 32 | /// underlying memory blocks, therefore the reply object must remain valid and 33 | /// not be changed until the write operation has completed. 34 | std::vector to_buffers(); 35 | 36 | /// Get a stock reply. 37 | static reply stock_reply(status_type status); 38 | 39 | std::string mount_point; 40 | 41 | std::string ntrip_gga; 42 | }; 43 | 44 | } // namespace ntrip 45 | -------------------------------------------------------------------------------- /examples/ntrip/request.h: -------------------------------------------------------------------------------- 1 | // Example ntrip server using boost asio, based off of boost http server example 2 | // See http://www.boost.org/LICENSE_1_0.txt 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include "header.h" 9 | 10 | namespace ntrip { 11 | 12 | /// A request received from a client. 13 | struct request { 14 | std::string method; 15 | std::string uri; 16 | int http_version_major; 17 | int http_version_minor; 18 | std::vector
headers; 19 | }; 20 | 21 | } // namespace ntrip 22 | -------------------------------------------------------------------------------- /examples/ntrip/request_handler.cc: -------------------------------------------------------------------------------- 1 | // Example ntrip server using boost asio, based off of boost http server example 2 | // See http://www.boost.org/LICENSE_1_0.txt 3 | 4 | #include "request_handler.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | #include "glog/logging.h" 15 | #include "mime_types.h" 16 | #include "reply.h" 17 | #include "request.h" 18 | 19 | namespace ntrip { 20 | 21 | request_handler::request_handler(const std::string& doc_root) 22 | : doc_root_(doc_root) {} 23 | 24 | void request_handler::handle_source_table_request(reply& rep) { 25 | rep.status = reply::source_table_ok; 26 | // Thu, 04 April 2019 19:31:18 UTC 27 | std::stringstream content_ss; 28 | content_ss << "STR;Polaris;PointOneNavigation;RTCM " 29 | "3.3;1010(1),1012(1),1006(30);2;GPS+GLO;PointOne;USA;32.56;-" 30 | "127.63;1;0;P1;none;N;N;4096;;\r\n"; 31 | content_ss << "ENDSOURCETABLE\r\n"; 32 | content_ss << "\r\n"; 33 | 34 | std::stringstream date_ss; 35 | boost::posix_time::ptime t = 36 | boost::posix_time::microsec_clock::universal_time(); 37 | date_ss << boost::posix_time::to_iso_extended_string(t) << "Z\n"; 38 | 39 | rep.content = content_ss.str(); 40 | rep.headers.resize(4); 41 | rep.headers[0].name = "Server"; 42 | rep.headers[0].value = "PointOne Navigation Polaris NTRIP Proxy Example"; 43 | rep.headers[1].name = "Date"; 44 | rep.headers[1].value = date_ss.str(); 45 | rep.headers[2].name = "Content-Length"; 46 | rep.headers[2].value = boost::lexical_cast(rep.content.size()); 47 | rep.headers[3].name = "Content-Type"; 48 | rep.headers[3].value = "text/plain"; 49 | } 50 | 51 | void request_handler::handle_mountpoint_request(const std::string& mount_point, 52 | const std::string& ntrip_gga, 53 | reply& rep) { 54 | rep = reply::stock_reply(reply::icy_ok); 55 | rep.mount_point = mount_point; 56 | rep.ntrip_gga = ntrip_gga; 57 | } 58 | 59 | void request_handler::handle_normal_http_request(const request& req, 60 | reply& rep) { 61 | // Decode url to path. 62 | std::string request_path; 63 | if (!url_decode(req.uri, request_path)) { 64 | LOG(INFO) << "Bad request"; 65 | rep = reply::stock_reply(reply::bad_request); 66 | return; 67 | } 68 | 69 | // Request path must be absolute and not contain "..". 70 | if (request_path.empty() || request_path[0] != '/' || 71 | request_path.find("..") != std::string::npos) { 72 | LOG(INFO) << "Bad request: " << request_path; 73 | rep = reply::stock_reply(reply::bad_request); 74 | return; 75 | } 76 | // If path ends in slash (i.e. is a directory) then add "index.html". 77 | if (request_path[request_path.size() - 1] == '/') { 78 | request_path += "index.html"; 79 | } 80 | 81 | // Determine the file extension. 82 | std::size_t last_slash_pos = request_path.find_last_of("/"); 83 | std::size_t last_dot_pos = request_path.find_last_of("."); 84 | std::string extension; 85 | if (last_dot_pos != std::string::npos && last_dot_pos > last_slash_pos) { 86 | extension = request_path.substr(last_dot_pos + 1); 87 | } 88 | 89 | // Open the file to send back. 90 | std::string full_path = doc_root_ + request_path; 91 | std::ifstream is(full_path.c_str(), std::ios::in | std::ios::binary); 92 | if (!is) { 93 | LOG(INFO) << full_path; 94 | rep = reply::stock_reply(reply::not_found); 95 | return; 96 | } 97 | 98 | // Fill out the reply to be sent to the client. 99 | rep.status = reply::ok; 100 | char buf[512]; 101 | while (is.read(buf, sizeof(buf)).gcount() > 0) 102 | rep.content.append(buf, is.gcount()); 103 | rep.headers.resize(2); 104 | rep.headers[0].name = "Content-Length"; 105 | rep.headers[0].value = boost::lexical_cast(rep.content.size()); 106 | rep.headers[1].name = "Content-Type"; 107 | rep.headers[1].value = extension_to_type(extension); 108 | } 109 | 110 | void request_handler::handle_request(const request& req, reply& rep) { 111 | bool ntrip_user_agent = false; 112 | std::string ntrip_gga; 113 | for (const auto& header : req.headers) { 114 | std::string data = header.name; 115 | std::transform(data.begin(), data.end(), data.begin(), ::tolower); 116 | std::string value = header.value; 117 | std::transform(value.begin(), value.end(), value.begin(), ::tolower); 118 | if (data == "user-agent" && boost::istarts_with(value, "ntrip")) { 119 | LOG(INFO) << value; 120 | ntrip_user_agent = true; 121 | } 122 | if (data == "ntrip-gga") { 123 | ntrip_gga = header.value; 124 | } 125 | } 126 | 127 | VLOG(2) << "Ntrip user agent: " << ntrip_user_agent; 128 | VLOG(2) << req.uri; 129 | 130 | // The ntrip user agent makes this respond with NTRIP standard responses 131 | // that dont have the normal HTTP codes (as expected by receviers) 132 | if (!ntrip_user_agent) { 133 | handle_normal_http_request(req, rep); 134 | } else if (mountpoints_.find(req.uri) != mountpoints_.end()) { 135 | handle_mountpoint_request(req.uri, ntrip_gga, rep); 136 | } else { 137 | handle_source_table_request(rep); 138 | } 139 | } 140 | 141 | bool request_handler::url_decode(const std::string& in, std::string& out) { 142 | out.clear(); 143 | out.reserve(in.size()); 144 | for (std::size_t i = 0; i < in.size(); ++i) { 145 | if (in[i] == '%') { 146 | if (i + 3 <= in.size()) { 147 | int value = 0; 148 | std::istringstream is(in.substr(i + 1, 2)); 149 | if (is >> std::hex >> value) { 150 | out += static_cast(value); 151 | i += 2; 152 | } else { 153 | return false; 154 | } 155 | } else { 156 | return false; 157 | } 158 | } else if (in[i] == '+') { 159 | out += ' '; 160 | } else { 161 | out += in[i]; 162 | } 163 | } 164 | return true; 165 | } 166 | 167 | } // namespace ntrip -------------------------------------------------------------------------------- /examples/ntrip/request_handler.h: -------------------------------------------------------------------------------- 1 | // Example ntrip server using boost asio, based off of boost http server example 2 | // See http://www.boost.org/LICENSE_1_0.txt 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | namespace ntrip { 11 | 12 | struct reply; 13 | struct request; 14 | 15 | /// The common handler for all incoming requests. 16 | class request_handler : private boost::noncopyable { 17 | public: 18 | /// Construct with a directory containing files to be served. 19 | explicit request_handler(const std::string& doc_root); 20 | 21 | void handle_source_table_request(reply& rep); 22 | 23 | void handle_mountpoint_request(const std::string& endpoint, 24 | const std::string& ntrip_gga, reply& rep); 25 | 26 | void handle_normal_http_request(const request& req, reply& rep); 27 | 28 | /// Handle a request and produce a reply. 29 | void handle_request(const request& req, reply& rep); 30 | 31 | private: 32 | /// The directory containing the files to be served. 33 | std::string doc_root_; 34 | 35 | std::unordered_set mountpoints_ = {"/Polaris"}; 36 | 37 | /// Perform URL-decoding on a string. Returns false if the encoding was 38 | /// invalid. 39 | static bool url_decode(const std::string& in, std::string& out); 40 | }; 41 | 42 | } // namespace ntrip 43 | -------------------------------------------------------------------------------- /examples/ntrip/request_parser.cc: -------------------------------------------------------------------------------- 1 | // Example ntrip server using boost asio, based off of boost http server example 2 | // See http://www.boost.org/LICENSE_1_0.txt 3 | 4 | #include "request_parser.h" 5 | #include "request.h" 6 | 7 | namespace ntrip { 8 | 9 | request_parser::request_parser() : state_(method_start) {} 10 | 11 | void request_parser::reset() { state_ = method_start; } 12 | 13 | boost::tribool request_parser::consume(request& req, char input) { 14 | switch (state_) { 15 | case method_start: 16 | if (!is_char(input) || is_ctl(input) || is_tspecial(input)) { 17 | return false; 18 | } else { 19 | state_ = method; 20 | req.method.push_back(input); 21 | return boost::indeterminate; 22 | } 23 | case method: 24 | if (input == ' ') { 25 | state_ = uri; 26 | return boost::indeterminate; 27 | } else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) { 28 | return false; 29 | } else { 30 | req.method.push_back(input); 31 | return boost::indeterminate; 32 | } 33 | case uri: 34 | if (input == ' ') { 35 | state_ = http_version_h; 36 | return boost::indeterminate; 37 | } else if (is_ctl(input)) { 38 | return false; 39 | } else { 40 | req.uri.push_back(input); 41 | return boost::indeterminate; 42 | } 43 | case http_version_h: 44 | if (input == 'H') { 45 | state_ = http_version_t_1; 46 | return boost::indeterminate; 47 | } else { 48 | return false; 49 | } 50 | case http_version_t_1: 51 | if (input == 'T') { 52 | state_ = http_version_t_2; 53 | return boost::indeterminate; 54 | } else { 55 | return false; 56 | } 57 | case http_version_t_2: 58 | if (input == 'T') { 59 | state_ = http_version_p; 60 | return boost::indeterminate; 61 | } else { 62 | return false; 63 | } 64 | case http_version_p: 65 | if (input == 'P') { 66 | state_ = http_version_slash; 67 | return boost::indeterminate; 68 | } else { 69 | return false; 70 | } 71 | case http_version_slash: 72 | if (input == '/') { 73 | req.http_version_major = 0; 74 | req.http_version_minor = 0; 75 | state_ = http_version_major_start; 76 | return boost::indeterminate; 77 | } else { 78 | return false; 79 | } 80 | case http_version_major_start: 81 | if (is_digit(input)) { 82 | req.http_version_major = req.http_version_major * 10 + input - '0'; 83 | state_ = http_version_major; 84 | return boost::indeterminate; 85 | } else { 86 | return false; 87 | } 88 | case http_version_major: 89 | if (input == '.') { 90 | state_ = http_version_minor_start; 91 | return boost::indeterminate; 92 | } else if (is_digit(input)) { 93 | req.http_version_major = req.http_version_major * 10 + input - '0'; 94 | return boost::indeterminate; 95 | } else { 96 | return false; 97 | } 98 | case http_version_minor_start: 99 | if (is_digit(input)) { 100 | req.http_version_minor = req.http_version_minor * 10 + input - '0'; 101 | state_ = http_version_minor; 102 | return boost::indeterminate; 103 | } else { 104 | return false; 105 | } 106 | case http_version_minor: 107 | if (input == '\r') { 108 | state_ = expecting_newline_1; 109 | return boost::indeterminate; 110 | } else if (is_digit(input)) { 111 | req.http_version_minor = req.http_version_minor * 10 + input - '0'; 112 | return boost::indeterminate; 113 | } else { 114 | return false; 115 | } 116 | case expecting_newline_1: 117 | if (input == '\n') { 118 | state_ = header_line_start; 119 | return boost::indeterminate; 120 | } else { 121 | return false; 122 | } 123 | case header_line_start: 124 | if (input == '\r') { 125 | state_ = expecting_newline_3; 126 | return boost::indeterminate; 127 | } else if (!req.headers.empty() && (input == ' ' || input == '\t')) { 128 | state_ = header_lws; 129 | return boost::indeterminate; 130 | } else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) { 131 | return false; 132 | } else { 133 | req.headers.push_back(header()); 134 | req.headers.back().name.push_back(input); 135 | state_ = header_name; 136 | return boost::indeterminate; 137 | } 138 | case header_lws: 139 | if (input == '\r') { 140 | state_ = expecting_newline_2; 141 | return boost::indeterminate; 142 | } else if (input == ' ' || input == '\t') { 143 | return boost::indeterminate; 144 | } else if (is_ctl(input)) { 145 | return false; 146 | } else { 147 | state_ = header_value; 148 | req.headers.back().value.push_back(input); 149 | return boost::indeterminate; 150 | } 151 | case header_name: 152 | if (input == ':') { 153 | state_ = space_before_header_value; 154 | return boost::indeterminate; 155 | } else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) { 156 | return false; 157 | } else { 158 | req.headers.back().name.push_back(input); 159 | return boost::indeterminate; 160 | } 161 | case space_before_header_value: 162 | if (input == ' ') { 163 | state_ = header_value; 164 | return boost::indeterminate; 165 | } else { 166 | return false; 167 | } 168 | case header_value: 169 | if (input == '\r') { 170 | state_ = expecting_newline_2; 171 | return boost::indeterminate; 172 | } else if (is_ctl(input)) { 173 | return false; 174 | } else { 175 | req.headers.back().value.push_back(input); 176 | return boost::indeterminate; 177 | } 178 | case expecting_newline_2: 179 | if (input == '\n') { 180 | state_ = header_line_start; 181 | return boost::indeterminate; 182 | } else { 183 | return false; 184 | } 185 | case expecting_newline_3: 186 | return (input == '\n'); 187 | default: 188 | return false; 189 | } 190 | } 191 | 192 | bool request_parser::is_char(int c) { return c >= 0 && c <= 127; } 193 | 194 | bool request_parser::is_ctl(int c) { return (c >= 0 && c <= 31) || (c == 127); } 195 | 196 | bool request_parser::is_tspecial(int c) { 197 | switch (c) { 198 | case '(': 199 | case ')': 200 | case '<': 201 | case '>': 202 | case '@': 203 | case ',': 204 | case ';': 205 | case ':': 206 | case '\\': 207 | case '"': 208 | case '/': 209 | case '[': 210 | case ']': 211 | case '?': 212 | case '=': 213 | case '{': 214 | case '}': 215 | case ' ': 216 | case '\t': 217 | return true; 218 | default: 219 | return false; 220 | } 221 | } 222 | 223 | bool request_parser::is_digit(int c) { return c >= '0' && c <= '9'; } 224 | 225 | } // namespace ntrip -------------------------------------------------------------------------------- /examples/ntrip/request_parser.h: -------------------------------------------------------------------------------- 1 | // Example ntrip server using boost asio, based off of boost http server example 2 | // See http://www.boost.org/LICENSE_1_0.txt 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | namespace ntrip { 10 | 11 | struct request; 12 | 13 | /// Parser for incoming requests. 14 | class request_parser { 15 | public: 16 | /// Construct ready to parse the request method. 17 | request_parser(); 18 | 19 | /// Reset to initial parser state. 20 | void reset(); 21 | 22 | /// Parse some data. The tribool return value is true when a complete request 23 | /// has been parsed, false if the data is invalid, indeterminate when more 24 | /// data is required. The InputIterator return value indicates how much of the 25 | /// input has been consumed. 26 | template 27 | boost::tuple parse(request& req, 28 | InputIterator begin, 29 | InputIterator end) { 30 | while (begin != end) { 31 | boost::tribool result = consume(req, *begin++); 32 | if (result || !result) return boost::make_tuple(result, begin); 33 | } 34 | boost::tribool result = boost::indeterminate; 35 | return boost::make_tuple(result, begin); 36 | } 37 | 38 | private: 39 | /// Handle the next character of input. 40 | boost::tribool consume(request& req, char input); 41 | 42 | /// Check if a byte is an HTTP character. 43 | static bool is_char(int c); 44 | 45 | /// Check if a byte is an HTTP control character. 46 | static bool is_ctl(int c); 47 | 48 | /// Check if a byte is defined as an HTTP tspecial character. 49 | static bool is_tspecial(int c); 50 | 51 | /// Check if a byte is a digit. 52 | static bool is_digit(int c); 53 | 54 | /// The current state of the parser. 55 | enum state { 56 | method_start, 57 | method, 58 | uri, 59 | http_version_h, 60 | http_version_t_1, 61 | http_version_t_2, 62 | http_version_p, 63 | http_version_slash, 64 | http_version_major_start, 65 | http_version_major, 66 | http_version_minor_start, 67 | http_version_minor, 68 | expecting_newline_1, 69 | header_line_start, 70 | header_lws, 71 | header_name, 72 | space_before_header_value, 73 | header_value, 74 | expecting_newline_2, 75 | expecting_newline_3 76 | } state_; 77 | }; 78 | 79 | } // namespace ntrip -------------------------------------------------------------------------------- /examples/septentrio/BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//visibility:public"]) 2 | 3 | # Async Septentrio receiver support using Septentrio's official library. 4 | cc_library( 5 | name = "septentrio_service", 6 | hdrs = [ 7 | "sbf_framer.h", 8 | "septentrio_interface.h", 9 | "septentrio_service.h", 10 | ], 11 | deps = [ 12 | "//examples:simple_serial_port", 13 | "//third_party:septentrio", 14 | "@com_github_google_glog//:glog", 15 | ], 16 | ) 17 | -------------------------------------------------------------------------------- /examples/septentrio/sbf_framer.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) Point One Navigation - All Rights Reserved 2 | 3 | #pragma once 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | namespace point_one { 11 | namespace gpsreceiver { 12 | 13 | #pragma pack(1) 14 | struct SbfHeader 15 | { 16 | uint8_t sync1; 17 | uint8_t sync2; 18 | uint16_t crc; 19 | uint16_t id; 20 | uint16_t length; 21 | }; 22 | #pragma pack() 23 | 24 | class SBFFramer { 25 | public: 26 | 27 | SBFFramer() { 28 | this->parser_state = STATE_SYNC1; 29 | 30 | this->cur_packet[MAX_SBF_MSG_LEN] = 0x00; 31 | this->cur_packet_index = 0; 32 | this->cur_msg_len = 0; 33 | this->bad_sync_counter = 0; 34 | 35 | this->callbackSBFFrame = NULL; 36 | this->callbackResponse = NULL; 37 | } 38 | 39 | void SetCallbackSBFFrame(std::function callback) { 40 | this->callbackSBFFrame = callback; 41 | LOG(INFO)<<"Set Septentrio Parser SBF Callback"; 42 | } 43 | 44 | void SetCallbackResponse(std::function callback) { 45 | this->callbackResponse = callback; 46 | LOG(INFO)<<"Set Septentrio Parser Response Callback"; 47 | } 48 | 49 | void OnByte(uint8_t b) { 50 | // debugPrintf("byte: %c\n", b); 51 | // debugPrintf("Parser State: %d\n", parser_state); 52 | switch (parser_state) { 53 | case STATE_SYNC1: { 54 | cur_packet_index = 0; 55 | if (b == '$') { 56 | cur_packet[cur_packet_index++] = b; 57 | parser_state = STATE_SYNC2; 58 | } else { 59 | bad_sync_counter++; 60 | } 61 | break; 62 | } 63 | case STATE_SYNC2: { 64 | cur_packet[cur_packet_index++] = b; 65 | if (b == '@') { 66 | parser_state = STATE_HEADER; 67 | } else if (b == 'R') { 68 | parser_state = STATE_CMD_RESPONSE; 69 | } else { 70 | parser_state = STATE_SYNC1; //reset state machine 71 | } 72 | break; 73 | } 74 | case STATE_HEADER: { 75 | //Get the remaining bytes that complete the header 76 | cur_packet[cur_packet_index++] = b; 77 | if (cur_packet_index == sizeof(SbfHeader)) { 78 | SbfHeader *header = (SbfHeader *) cur_packet; 79 | this->cur_msg_len = header->length; //lenght is the total packet length, including header 80 | if (this->cur_msg_len >= MAX_SBF_MSG_LEN) { 81 | LOG(WARNING) <<"Too big a message?"; 82 | parser_state = STATE_SYNC1; 83 | break; 84 | } 85 | 86 | if (header->length <= sizeof(SbfHeader)) { 87 | LOG(WARNING) <<"Something Broke, start over!"; 88 | parser_state = STATE_SYNC1; 89 | } else { 90 | parser_state = STATE_DATA; 91 | } 92 | } 93 | break; 94 | } 95 | case STATE_DATA: { 96 | cur_packet[cur_packet_index++] = b; 97 | if (cur_packet_index >= this->cur_msg_len) { 98 | //We have our Packet now verify it 99 | SbfHeader *header = (SbfHeader *)cur_packet; 100 | if (this->calculate_crc_16_ccitt(cur_packet + CRC_START_OFFSET, 101 | header->length - CRC_START_OFFSET) == 102 | header->crc) { 103 | if (this->callbackSBFFrame != NULL) 104 | this->callbackSBFFrame(header->length, cur_packet); 105 | } 106 | parser_state = STATE_SYNC1; 107 | } 108 | break; 109 | } 110 | 111 | case STATE_CMD_RESPONSE: { 112 | cur_packet[cur_packet_index++] = b; 113 | if (this->cur_msg_len >= MAX_SBF_MSG_LEN) { 114 | LOG(WARNING) <<"Too big a message?"; 115 | parser_state = STATE_SYNC1; 116 | break; 117 | } 118 | //We have our Packet now verify it 119 | if (cur_packet[cur_packet_index - 2] == '\r' && cur_packet[cur_packet_index - 1] == '\n') { 120 | cur_packet[cur_packet_index] = 0x00; 121 | if (this->callbackResponse != NULL) 122 | this->callbackResponse((char *) cur_packet); 123 | parser_state = STATE_SYNC1; 124 | } 125 | break; 126 | } 127 | 128 | } 129 | } 130 | 131 | private: 132 | 133 | std::function callbackSBFFrame; 134 | std::function callbackResponse; 135 | 136 | enum MsgState { 137 | STATE_DONE = 1, 138 | STATE_SYNC1 = 2, 139 | STATE_SYNC2 = 3, 140 | STATE_HEADER = 4, 141 | STATE_DATA = 5, 142 | STATE_CMD_RESPONSE = 6, 143 | }; 144 | 145 | uint8_t parser_state; 146 | 147 | 148 | 149 | uint16_t cur_packet_index; 150 | uint16_t cur_msg_len; 151 | 152 | uint32_t bad_sync_counter; 153 | 154 | static constexpr uint16_t MAX_SBF_MSG_LEN = 4096; 155 | uint8_t cur_packet[MAX_SBF_MSG_LEN + 1]; 156 | //CRC calc starts with the ID, so skip 2 Sync bytes and 2 CRC btyes in header. 157 | const uint8_t CRC_START_OFFSET = 4; 158 | 159 | uint16_t crc_ccitt_update(uint8_t x, uint16_t current_crc) { 160 | uint16_t crc_new = (uint8_t) (current_crc >> 8) | (current_crc << 8); 161 | crc_new ^= x; 162 | crc_new ^= (uint8_t) (crc_new & 0xff) >> 4; 163 | crc_new ^= crc_new << 12; 164 | crc_new ^= (crc_new & 0xff) << 5; 165 | return crc_new; 166 | } 167 | 168 | uint16_t calculate_crc_16_ccitt(uint8_t *data, uint16_t len) { 169 | uint16_t crc_new = 0; 170 | for (int i = 0; i < len; i++) { 171 | crc_new = crc_ccitt_update(data[i], crc_new); 172 | } 173 | return crc_new; 174 | } 175 | 176 | }; 177 | } 178 | } 179 | -------------------------------------------------------------------------------- /examples/septentrio/septentrio_interface.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) Point One Navigation - All Rights Reserved 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "sbf_framer.h" 15 | #include "../simple_asio_serial_port.h" 16 | 17 | #pragma once 18 | namespace point_one { 19 | namespace gpsreceiver { 20 | 21 | class SeptentrioReceiver { 22 | public: 23 | SeptentrioReceiver(const std::string &raw_log_path = "") { 24 | InitBinLog(raw_log_path); 25 | } 26 | virtual ~SeptentrioReceiver() { 27 | if (bin_log_.is_open()) { 28 | bin_log_.close(); 29 | } 30 | } 31 | 32 | virtual bool Connect() = 0; 33 | 34 | void SetCallbackSBF(std::function callback) { 35 | this->callbackSBF = callback; 36 | LOG(INFO) << "Set Septentrio Receiver Callback"; 37 | } 38 | 39 | protected: 40 | std::ofstream bin_log_; 41 | std::function callbackSBF; 42 | 43 | void InitBinLog(const std::string &raw_log_path) { 44 | if (!raw_log_path.empty()) { 45 | LOG(INFO) << " SEPT LOG PATH IS " << raw_log_path; 46 | 47 | char name[100]; 48 | if (raw_log_path.find(".") == std::string::npos) { 49 | sprintf(name, "%s/septentrio-%d.bin", raw_log_path.c_str(), 50 | (int)std::time(nullptr)); 51 | } else { 52 | sprintf(name, "%s", raw_log_path.c_str()); 53 | } 54 | LOG(INFO) << " SEPT LOGGING TO " << name; 55 | bin_log_.open(name, std::ios::out | std::ios::app | std::ios::binary); 56 | } 57 | } 58 | 59 | void OnSBF(uint16_t len, const void *data) { 60 | if (bin_log_.is_open()) { 61 | bin_log_.write((const char *)data, len); 62 | bin_log_.flush(); 63 | } 64 | if (callbackSBF != nullptr) { 65 | callbackSBF(len, data); 66 | } 67 | } 68 | }; 69 | 70 | class SeptentrioSerialReceiver : public SeptentrioReceiver { 71 | public: 72 | SeptentrioSerialReceiver(boost::asio::io_service &io_service, 73 | const std::string &device_path, 74 | const std::string &raw_log_path = "") 75 | : SeptentrioReceiver(raw_log_path), serial_port(io_service), device_path_(device_path) { 76 | serial_port.SetCallback(std::bind(&SeptentrioSerialReceiver::OnData, this, 77 | std::placeholders::_1, 78 | std::placeholders::_2)); 79 | framer.SetCallbackSBFFrame(std::bind(&SeptentrioSerialReceiver::OnSBF, this, 80 | std::placeholders::_1, 81 | std::placeholders::_2)); 82 | } 83 | 84 | ~SeptentrioSerialReceiver() {} 85 | 86 | void Send(const void *buf, size_t len) { serial_port.AsyncWrite(buf, len); } 87 | 88 | bool Connect() override { return serial_port.Open(device_path_, 115200); } 89 | 90 | private: 91 | point_one::utils::SimpleAsioSerialPort serial_port; 92 | std::string device_path_; 93 | SBFFramer framer; 94 | 95 | void OnData(const void *data, size_t len) { 96 | for (size_t i = 0; i < len; i++) { 97 | framer.OnByte(static_cast(data)[i]); // optimize... 98 | } 99 | } 100 | }; 101 | 102 | } // namespace gpsreceiver 103 | } // namespace point_one 104 | -------------------------------------------------------------------------------- /examples/septentrio/septentrio_service.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) Point One Navigation - All Rights Reserved 2 | 3 | #pragma once 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "septentrio_interface.h" 14 | 15 | namespace point_one { 16 | namespace gpsreceiver { 17 | 18 | class SeptentrioService { 19 | public: 20 | SeptentrioService(std::string device_path) : device_path_(device_path) {} 21 | 22 | void SendRtcm(const void *buf, size_t len) { 23 | if (!sp_) { 24 | return; 25 | } 26 | sp_->Send(buf, len); 27 | } 28 | 29 | void SetPvtCallback( 30 | const std::function &callback) { 31 | pvt_callback_ = callback; 32 | } 33 | 34 | bool Connect(boost::asio::io_service &io_service) { 35 | sp_.reset(new point_one::gpsreceiver::SeptentrioSerialReceiver( 36 | io_service, device_path_)); 37 | 38 | sp_->SetCallbackSBF(std::bind(&SeptentrioService::OnSBF, this, 39 | std::placeholders::_1, 40 | std::placeholders::_2)); 41 | return sp_->Connect(); 42 | } 43 | 44 | private: 45 | std::string device_path_; 46 | std::unique_ptr sp_; 47 | std::function pvt_callback_; 48 | 49 | void OnSBF(size_t len, const void *data) { 50 | const BlockHeader_t *blockHeader = (const BlockHeader_t *)data; 51 | 52 | // Top 3 bits represent the version of the message. 53 | uint16_t msg_id = blockHeader->ID & 0x1FFF; 54 | // Get the msg id version. 55 | uint8_t msg_id_version = (blockHeader->ID >> 13) & 0x07; 56 | 57 | if (msg_id == sbfnr_PVTGeodetic_2 && msg_id_version >= 2) { 58 | const PVTGeodetic_2_2_t *PVT = (const PVTGeodetic_2_2_t *)data; 59 | if (pvt_callback_ != nullptr) pvt_callback_(*PVT); 60 | } 61 | } 62 | }; 63 | 64 | } // namespace gpsreceiver 65 | } // namespace point_one 66 | -------------------------------------------------------------------------------- /examples/septentrio_example.cc: -------------------------------------------------------------------------------- 1 | // Copyright (C) Point One Navigation - All Rights Reserved 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include "septentrio/septentrio_service.h" 10 | 11 | // Allows for prebuilt versions of gflags/google that don't have gflags/google 12 | // namespace. 13 | namespace gflags {} 14 | namespace google {} 15 | using namespace gflags; 16 | using namespace google; 17 | 18 | using namespace point_one::polaris; 19 | 20 | // Polaris options: 21 | DEFINE_string(polaris_api_key, "", 22 | "The service API key. Contact account administrator or " 23 | "sales@pointonenav.com if unknown."); 24 | 25 | DEFINE_string(polaris_unique_id, "device12345", 26 | "The unique ID to assign to this Polaris connection."); 27 | 28 | // Septentrio/output options: 29 | DEFINE_string(device, "/dev/ttyACM0", 30 | "The serial device on which the Septentrio is connected."); 31 | 32 | DEFINE_string( 33 | udp_host, "", 34 | "If set, forward RTCM corrections over UDP to the specified hostname/IP in " 35 | "addition to the Septentrio receiver (over serial)."); 36 | 37 | DEFINE_int32( 38 | udp_port, 0, 39 | "The UDP port to which RTCM corrections will be forwarded."); 40 | 41 | #ifndef RAD2DEG 42 | #define RAD2DEG (57.295779513082320876798154814105) //!< 180.0/PI 43 | #endif 44 | 45 | // Simple callback to print position when received and update Polaris Client. 46 | void PvtCallback(const PVTGeodetic_2_2_t& pvt, PolarisClient* polaris_client) { 47 | LOG_EVERY_N(INFO, 10) << "Week: " << pvt.WNc << " Tow: " << pvt.TOW / 1000.0 48 | << " Solution Type: " << (int)pvt.Mode 49 | << " Hacc: " << pvt.HAccuracy 50 | << " Vacc: " << pvt.VAccuracy 51 | << " Lat: " << pvt.Lat * RAD2DEG 52 | << " Lon: " << pvt.Lon * RAD2DEG << " Alt: " << pvt.Alt; 53 | polaris_client->SendLLAPosition(pvt.Lat * RAD2DEG, pvt.Lon * RAD2DEG, 54 | pvt.Alt); 55 | } 56 | 57 | int main(int argc, char *argv[]) { 58 | ParseCommandLineFlags(&argc, &argv, true); 59 | InitGoogleLogging(argv[0]); 60 | 61 | boost::asio::io_service io_loop; 62 | boost::asio::io_service::work work(io_loop); 63 | 64 | bool udp_enabled = false; 65 | boost::asio::ip::udp::socket udp_socket(io_loop); 66 | boost::asio::ip::udp::endpoint udp_endpoint; 67 | 68 | // Validate arguments. 69 | if (FLAGS_polaris_api_key == "") { 70 | LOG(ERROR) << "You must supply a Polaris API key to connect to the server."; 71 | return 1; 72 | } 73 | 74 | if (!FLAGS_udp_host.empty()) { 75 | if (FLAGS_udp_port < 1 || FLAGS_udp_port > 65535) { 76 | LOG(ERROR) 77 | << "You must specify a valid UDP port when enabling UDP output."; 78 | return 1; 79 | } 80 | else { 81 | udp_enabled = true; 82 | udp_endpoint = boost::asio::ip::udp::endpoint( 83 | boost::asio::ip::address_v4::from_string(FLAGS_udp_host), 84 | static_cast(FLAGS_udp_port)); 85 | } 86 | } 87 | 88 | // Connect to the Septentrio receiver. 89 | point_one::gpsreceiver::SeptentrioService septentrio(FLAGS_device); 90 | LOG(INFO) << "Connecting to receiver..."; 91 | if (!septentrio.Connect(io_loop)) { 92 | LOG(FATAL) << "Could not connect to the receiver at path: " << FLAGS_device; 93 | } 94 | 95 | // Create the Polaris client. 96 | PolarisClient polaris_client(FLAGS_polaris_api_key, FLAGS_polaris_unique_id); 97 | 98 | // This callback will forward RTCM correction bytes received from Polaris to 99 | // the Septentrio, as well as to an output UDP port if enabled. 100 | polaris_client.SetRTCMCallback([&](const uint8_t* buffer, size_t size_bytes) { 101 | septentrio.SendRtcm(buffer, size_bytes); 102 | if (udp_enabled) { 103 | udp_socket.send_to(boost::asio::buffer(buffer, size_bytes), udp_endpoint); 104 | } 105 | }); 106 | 107 | // This callback will send position updates from the Septentrio to Polaris. 108 | // Polaris uses the positions to associate the connection with a corrections 109 | // stream. 110 | // 111 | // Position updates should be sent periodically to ensure the incoming 112 | // corrections are from the most appropriate stream. 113 | // 114 | // Note that positions are supplied by the Septentrio over serial. The UDP 115 | // interface does not support receiving positions. 116 | septentrio.SetPvtCallback( 117 | std::bind(PvtCallback, std::placeholders::_1, &polaris_client)); 118 | 119 | // Run the Polaris connection connection asynchronously. 120 | LOG(INFO) << "Connecting to Polaris..."; 121 | polaris_client.RunAsync(); 122 | 123 | // Now run the Boost IO loop to communicate with the serial port. This will 124 | // block forever. 125 | LOG(INFO) << "Listening for incoming serial data..."; 126 | io_loop.run(); 127 | 128 | return 0; 129 | } 130 | -------------------------------------------------------------------------------- /examples/serial_port_example.cc: -------------------------------------------------------------------------------- 1 | /**************************************************************************/ /** 2 | * @brief Example of receiving positions from a GNSS receiver and forwarding 3 | * Polaris corrections to the receiver over a serial port. 4 | * 5 | * Copyright (c) Point One Navigation - All Rights Reserved 6 | ******************************************************************************/ 7 | 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | #include "simple_asio_serial_port.h" 18 | 19 | // Allows for prebuilt versions of gflags/google that don't have gflags/google 20 | // namespace. 21 | namespace gflags {} 22 | namespace google {} 23 | using namespace gflags; 24 | using namespace google; 25 | 26 | using namespace point_one::polaris; 27 | 28 | // Polaris options: 29 | DEFINE_string(polaris_api_key, "", 30 | "The polaris API key. Sign up at app.pointonenav.com."); 31 | 32 | DEFINE_string(polaris_unique_id, "", 33 | "The unique ID to assign to this Polaris connection."); 34 | 35 | // Serial port forwarding options. 36 | DEFINE_string(receiver_serial_port, "/dev/ttyUSB0", 37 | "The path to the serial port for which to forward corrections."); 38 | 39 | DEFINE_int32(receiver_serial_baud, 460800, "The baud rate of the serial port."); 40 | 41 | namespace { 42 | // Max size of string buffer to hold before clearing NMEA data. Should be larger 43 | // than max expected frame size. 44 | constexpr double MAX_NMEA_SENTENCE_LENGTH = 1024; 45 | 46 | // Variable to hold NMEA data for this example. If using in production 47 | // you should use a production grade NMEA parser. 48 | std::string nmea_sentence_buffer; 49 | } // namespace 50 | 51 | // Converts from GPGGA ddMM (degrees arc minutes) format to decimal degrees 52 | double ConvertGGADegreesToDecimalDegrees(double gga_degrees) { 53 | double degrees = std::floor(gga_degrees / 100.0); 54 | degrees += (gga_degrees - degrees * 100) / 60.0; 55 | return degrees; 56 | } 57 | 58 | // Handle an nmea string. If message is a parseable gga message, send position 59 | // to server. 60 | void OnNmea(const std::string& nmea_str, PolarisClient* polaris_client) { 61 | // Some receivers put out INGGA messages as opposed to GPGGA. 62 | if (!(boost::istarts_with(nmea_str, "$GPGGA") || 63 | boost::istarts_with(nmea_str, "$GNGGA") || 64 | boost::istarts_with(nmea_str, "$INGGA"))) { 65 | VLOG(2) << nmea_str; 66 | return; 67 | } 68 | LOG(INFO) << "Got GGA: " << nmea_str; 69 | std::stringstream ss(nmea_str); 70 | std::vector result; 71 | 72 | while (ss.good()) { 73 | std::string substr; 74 | std::getline(ss, substr, ','); 75 | result.push_back(substr); 76 | } 77 | std::string::size_type sz; 78 | try { 79 | // TODO: This is not exactly correct but should not really matter because 80 | // its just beacon association. 81 | double lat = ConvertGGADegreesToDecimalDegrees(std::stod(result[2], &sz)) * 82 | (result[3] == "N" ? 1 : -1); 83 | double lon = ConvertGGADegreesToDecimalDegrees(std::stod(result[4], &sz)) * 84 | (result[5] == "E" ? 1 : -1); 85 | double alt = std::stod(result[9], &sz); 86 | VLOG(3) << "Setting position: lat: " << lat << " lon: " << lon 87 | << " alt: " << alt; 88 | polaris_client->SendLLAPosition(lat, lon, alt); 89 | } catch (const std::exception&) { 90 | LOG(ERROR) << "Bad parse of received NMEA string: " << nmea_str; 91 | LOG(WARNING) << "Could not send position to server for bad NMEA string."; 92 | return; 93 | } 94 | } 95 | 96 | // Process receiver incomming messages. This example code expects received data 97 | // to be ascii NMEA messages. 98 | void OnSerialData(const void* data, size_t length, 99 | PolarisClient* polaris_client) { 100 | std::string nmea_data((const char*)data, length); 101 | for (const char& c : nmea_data) { 102 | if (c == '$') { 103 | OnNmea(nmea_sentence_buffer, polaris_client); 104 | nmea_sentence_buffer.clear(); 105 | } 106 | nmea_sentence_buffer.push_back(c); 107 | } 108 | 109 | if (nmea_sentence_buffer.size() > MAX_NMEA_SENTENCE_LENGTH) { 110 | LOG(WARNING) << "Clearing NMEA buffer. Are you sending NMEA ascii data?"; 111 | nmea_sentence_buffer.clear(); 112 | } 113 | } 114 | 115 | int main(int argc, char* argv[]) { 116 | // Parse commandline flags. 117 | FLAGS_logtostderr = true; 118 | FLAGS_colorlogtostderr = true; 119 | ParseCommandLineFlags(&argc, &argv, true); 120 | 121 | // Setup logging interface. 122 | InitGoogleLogging(argv[0]); 123 | 124 | // Setup asio work loop. 125 | boost::asio::io_service io_loop; 126 | boost::asio::io_service::work work(io_loop); 127 | 128 | // Create connection to receiver to forward correction data received from 129 | // Polaris. 130 | point_one::utils::SimpleAsioSerialPort serial_port_correction_forwarder( 131 | io_loop); 132 | if (!serial_port_correction_forwarder.Open(FLAGS_receiver_serial_port, 133 | FLAGS_receiver_serial_baud)) { 134 | LOG(ERROR) << "Could not open serial port " << FLAGS_receiver_serial_port 135 | << ", terminating."; 136 | return 1; 137 | } 138 | 139 | // Construct a Polaris client. 140 | if (FLAGS_polaris_api_key == "") { 141 | LOG(ERROR) << "You must supply a Polaris API key to connect to the server."; 142 | return 1; 143 | } 144 | 145 | PolarisClient polaris_client(FLAGS_polaris_api_key, FLAGS_polaris_unique_id); 146 | polaris_client.SetRTCMCallback([&](const uint8_t* buffer, size_t size_bytes) { 147 | serial_port_correction_forwarder.Write(buffer, size_bytes); 148 | }); 149 | 150 | serial_port_correction_forwarder.SetCallback( 151 | std::bind(OnSerialData, std::placeholders::_1, std::placeholders::_2, 152 | &polaris_client)); 153 | 154 | // Run the Polaris connection connection asynchronously. 155 | LOG(INFO) << "Connecting to Polaris..."; 156 | polaris_client.RunAsync(); 157 | 158 | // Now run the Boost IO loop to communicate with the serial port. This will 159 | // block forever. 160 | LOG(INFO) << "Listening for incoming serial data..."; 161 | io_loop.run(); 162 | 163 | return 0; 164 | } 165 | -------------------------------------------------------------------------------- /examples/simple_asio_serial_port.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) Point One Navigation - All Rights Reserved 2 | 3 | #pragma once 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | namespace point_one { 12 | namespace utils { 13 | 14 | // Simple wrapper around Boost asio serial port to add minimal error checking 15 | // and logging. 16 | class SimpleAsioSerialPort { 17 | public: 18 | explicit SimpleAsioSerialPort(boost::asio::io_service& io_service) 19 | : sp_(io_service) {} 20 | 21 | ~SimpleAsioSerialPort() { sp_.close(); } 22 | 23 | // Open serial port and return true on success. 24 | bool Open(const std::string& path, int baud_rate = 115200) { 25 | try { 26 | sp_.open(path); 27 | } catch (boost::system::system_error& e) { 28 | LOG(ERROR) << "Could not connect to serial port at " << path 29 | << " -> Boost: " << e.what(); 30 | return false; 31 | } 32 | // Setup The options 33 | sp_.set_option(boost::asio::serial_port_base::baud_rate(baud_rate)); 34 | sp_.set_option(boost::asio::serial_port_base::character_size(8)); 35 | sp_.set_option(boost::asio::serial_port_base::stop_bits( 36 | boost::asio::serial_port_base::stop_bits::one)); 37 | sp_.set_option(boost::asio::serial_port_base::parity( 38 | boost::asio::serial_port_base::parity::none)); 39 | sp_.set_option(boost::asio::serial_port_base::flow_control( 40 | boost::asio::serial_port_base::flow_control::none)); 41 | 42 | AsyncReadData(); 43 | return true; 44 | } 45 | 46 | void Write(const void* buf, size_t len) { 47 | VLOG(6) << "Forwarding " << len << " bytes to serial port."; 48 | sp_.write_some(boost::asio::buffer(buf, len)); 49 | } 50 | 51 | void AsyncWrite(const void* buf, size_t len) { 52 | VLOG(6) << "Forwarding " << len << " bytes to serial port."; 53 | std::string data((const char*)buf, len); 54 | sp_.async_write_some( 55 | boost::asio::buffer(buf, len), 56 | boost::bind(&SimpleAsioSerialPort::OnWrite, this, data, 57 | boost::asio::placeholders::error, 58 | boost::asio::placeholders::bytes_transferred)); 59 | } 60 | 61 | void OnWrite(const std::string& buffer_data, 62 | const boost::system::error_code& error_code, 63 | size_t bytes_transferred) { 64 | if (error_code) { 65 | LOG(ERROR) << "ERROR on receive " << error_code.message().c_str(); 66 | } 67 | } 68 | 69 | void SetCallback(std::function callback) { 70 | this->callback = callback; 71 | } 72 | 73 | void AsyncReadData() { 74 | if (!sp_.is_open()) return; 75 | 76 | sp_.async_read_some( 77 | boost::asio::buffer(buf_, READ_SIZE), 78 | boost::bind(&SimpleAsioSerialPort::OnReceive, this, 79 | boost::asio::placeholders::error, 80 | boost::asio::placeholders::bytes_transferred)); 81 | } 82 | 83 | void OnReceive(const boost::system::error_code& error_code, 84 | size_t bytes_transferred) { 85 | if (!sp_.is_open()) { 86 | return; 87 | } 88 | 89 | if (error_code) { 90 | LOG(FATAL) << "Error on receive " << error_code.message().c_str(); 91 | 92 | AsyncReadData(); 93 | return; 94 | } 95 | 96 | if (this->callback != nullptr) { 97 | callback(buf_, bytes_transferred); 98 | } 99 | AsyncReadData(); 100 | } 101 | 102 | private: 103 | boost::asio::serial_port sp_; 104 | static const int READ_SIZE = 1024; 105 | char buf_[READ_SIZE]; 106 | 107 | std::function callback; 108 | }; 109 | 110 | } // namespace utils 111 | } // namespace point_one 112 | -------------------------------------------------------------------------------- /examples/simple_embedded_client.cc: -------------------------------------------------------------------------------- 1 | // Copyright (C) Point One Navigation - All Rights Reserved 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | #include 9 | 10 | #include 11 | 12 | // Polaris options: 13 | DEFINE_string(polaris_signing_secret, "bRb1q3k4yiX4VbZxztx", 14 | "The signing secret."); 15 | DEFINE_string(company_id, "co994711e0d78611e69dd502fd95286f33", 16 | "Company ID issued by Point One."); 17 | DEFINE_string(unique_id, "123456789", 18 | "Unique identifier of the device (serial number)."); 19 | DEFINE_string(api_server, "api.pointonenav.com", "Address of the API server"); 20 | DEFINE_string(polaris_server, "polaris.pointonenav.com", 21 | "Address of the Polaris server"); 22 | 23 | // Allows for prebuilt versions of gflags/google that don't have gflags/google 24 | // namespace. 25 | namespace gflags {} 26 | namespace google {} 27 | using namespace gflags; 28 | using namespace google; 29 | 30 | // Process receiver incoming messages. This example code expects received data 31 | // to be ascii nmea messages. 32 | void ReceivedData(const void* data, size_t length) { 33 | LOG(INFO) << "Received " << length << " bytes."; 34 | } 35 | 36 | int main(int argc, char* argv[]) { 37 | // Parse commandline flags. 38 | ParseCommandLineFlags(&argc, &argv, true); 39 | 40 | // Setup logging interface. 41 | InitGoogleLogging(argv[0]); 42 | 43 | // Setup asio work loop. 44 | boost::asio::io_service io_loop; 45 | boost::asio::io_service::work work(io_loop); 46 | 47 | auto connection_settings = point_one::polaris::DEFAULT_CONNECTION_SETTINGS; 48 | connection_settings.api_host = FLAGS_api_server; 49 | connection_settings.host = FLAGS_polaris_server; 50 | 51 | point_one::polaris::PolarisAsioEmbeddedClient polaris_client( 52 | io_loop, FLAGS_polaris_signing_secret, FLAGS_unique_id, FLAGS_company_id, 53 | connection_settings); 54 | polaris_client.SetPolarisBytesReceived( 55 | std::bind(&ReceivedData, std::placeholders::_1, std::placeholders::_2)); 56 | // Application can set position at any time to change associated beacon(s) and 57 | // corrections. Example setting postion to SF in ECEF meters. 58 | // It is required to call SetPositionECEF at some cadence to assure the 59 | // corrections received are the best and relevant. 60 | polaris_client.SetPositionECEF(-2707071, -4260565, 3885644); 61 | polaris_client.Connect(); 62 | 63 | // Run work loop. 64 | io_loop.run(); 65 | 66 | return 0; 67 | } 68 | -------------------------------------------------------------------------------- /examples/simple_polaris_client.cc: -------------------------------------------------------------------------------- 1 | /**************************************************************************/ /** 2 | * @brief Simple example of connecting to the Polaris service to receive 3 | * corrections. 4 | * 5 | * Copyright (c) Point One Navigation - All Rights Reserved 6 | ******************************************************************************/ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | // Allows for prebuilt versions of gflags/google that don't have gflags/google 18 | // namespace. 19 | namespace gflags {} 20 | namespace google {} 21 | using namespace gflags; 22 | using namespace google; 23 | 24 | using namespace point_one::polaris; 25 | 26 | // Polaris options: 27 | DEFINE_string(polaris_api_key, "", 28 | "The polaris API key. Sign up at app.pointonenav.com."); 29 | 30 | DEFINE_string(polaris_unique_id, "", 31 | "The unique ID to assign to this Polaris connection."); 32 | 33 | DEFINE_string( 34 | polaris_hostname, "", 35 | "Specify an alternate hostname to use when connecting to the Polaris " 36 | "corrections network. This may be useful when connecting to a regional " 37 | "endpoint in the EU or APAC. If blank, use the default hostname."); 38 | 39 | DEFINE_string( 40 | polaris_api_hostname, "", 41 | "Specify an alternate hostname to use when connecting to the Polaris " 42 | "authentication API server. Specifying a custom API hostname is not " 43 | "common, and is intended primarily for development purposes. If blank, use " 44 | "the default hostname."); 45 | 46 | PolarisClient* polaris_client = nullptr; 47 | 48 | // Process receiver incoming messages. This example code expects received data 49 | // to be ascii nmea messages. 50 | void ReceivedData(const uint8_t* data, size_t length) { 51 | LOG(INFO) << "Application received " << length << " bytes."; 52 | } 53 | 54 | void HandleSignal(int sig) { 55 | signal(sig, SIG_DFL); 56 | 57 | LOG(INFO) << "Caught signal " << strsignal(sig) << " (" << sig 58 | << "). Closing Polaris connection."; 59 | polaris_client->Disconnect(); 60 | } 61 | 62 | int main(int argc, char* argv[]) { 63 | // Parse commandline flags. 64 | FLAGS_logtostderr = true; 65 | FLAGS_colorlogtostderr = true; 66 | ParseCommandLineFlags(&argc, &argv, true); 67 | 68 | // Setup logging interface. 69 | InitGoogleLogging(argv[0]); 70 | 71 | // Construct a Polaris client. 72 | if (FLAGS_polaris_api_key.empty()) { 73 | LOG(ERROR) << "You must supply a Polaris API key to connect to the server."; 74 | return 1; 75 | } 76 | else if (FLAGS_polaris_unique_id.empty()) { 77 | LOG(ERROR) << "You must supply a unique ID for this connection."; 78 | return 1; 79 | } 80 | 81 | polaris_client = 82 | new PolarisClient(FLAGS_polaris_api_key, FLAGS_polaris_unique_id); 83 | polaris_client->SetPolarisEndpoint(FLAGS_polaris_hostname); 84 | polaris_client->SetPolarisAuthenticationServer(FLAGS_polaris_api_hostname); 85 | 86 | polaris_client->SetRTCMCallback( 87 | std::bind(&ReceivedData, std::placeholders::_1, std::placeholders::_2)); 88 | 89 | // Send the receiver's position to Polaris (this example is a position in San 90 | // Francisco). Sending your position allows Polaris to associate you with an 91 | // appropriate corrections stream. You must send a position at least once 92 | // before any data will be sent back. You should periodically update your 93 | // position as you move to make sure you are receiving the best set of 94 | // corrections. 95 | LOG(INFO) << "Setting initial position."; 96 | polaris_client->SendECEFPosition(-2707071.0, -4260565.0, 3885644.0); 97 | 98 | // Run the client, receiving data until the user presses Ctrl-C. 99 | signal(SIGINT, HandleSignal); 100 | signal(SIGTERM, HandleSignal); 101 | 102 | LOG(INFO) << "Connecting to Polaris and listening for data..."; 103 | polaris_client->Run(); 104 | 105 | LOG(INFO) << "Finished running. Cleaning up."; 106 | delete polaris_client; 107 | 108 | LOG(INFO) << "Exiting."; 109 | return 0; 110 | } 111 | -------------------------------------------------------------------------------- /src/point_one/polaris/polaris_interface.cc: -------------------------------------------------------------------------------- 1 | /**************************************************************************/ /** 2 | * @brief Polaris client C++ wrapper class. 3 | * 4 | * Copyright (c) Point One Navigation - All Rights Reserved 5 | ******************************************************************************/ 6 | 7 | #include "point_one/polaris/polaris_interface.h" 8 | 9 | using namespace point_one::polaris; 10 | 11 | /******************************************************************************/ 12 | PolarisInterface::PolarisInterface() { 13 | Polaris_Init(&context_); 14 | Polaris_SetRTCMCallback(&context_, &PolarisInterface::HandleRTCMData, this); 15 | } 16 | 17 | /******************************************************************************/ 18 | PolarisInterface::~PolarisInterface() { 19 | Disconnect(); 20 | Polaris_Free(&context_); 21 | } 22 | 23 | /******************************************************************************/ 24 | int PolarisInterface::Authenticate(const std::string& api_key, 25 | const std::string& unique_id) { 26 | return Polaris_Authenticate(&context_, api_key.c_str(), unique_id.c_str()); 27 | } 28 | 29 | /******************************************************************************/ 30 | int PolarisInterface::AuthenticateTo(const std::string& api_key, 31 | const std::string& unique_id, 32 | const std::string& api_url) { 33 | return Polaris_AuthenticateTo(&context_, api_key.c_str(), unique_id.c_str(), 34 | api_url.c_str()); 35 | } 36 | 37 | /******************************************************************************/ 38 | int PolarisInterface::SetAuthToken(const std::string& auth_token) { 39 | return Polaris_SetAuthToken(&context_, auth_token.c_str()); 40 | } 41 | 42 | /******************************************************************************/ 43 | int PolarisInterface::Connect() { 44 | return Polaris_Connect(&context_); 45 | } 46 | 47 | /******************************************************************************/ 48 | int PolarisInterface::ConnectTo(const std::string& endpoint_url, 49 | int endpoint_port) { 50 | return Polaris_ConnectTo(&context_, endpoint_url.c_str(), endpoint_port); 51 | } 52 | 53 | /******************************************************************************/ 54 | int PolarisInterface::ConnectWithoutAuth( 55 | const std::string& endpoint_url, int endpoint_port, 56 | const std::string& unique_id) { 57 | return Polaris_ConnectWithoutAuth(&context_, endpoint_url.c_str(), 58 | endpoint_port, unique_id.c_str()); 59 | } 60 | 61 | /******************************************************************************/ 62 | void PolarisInterface::Disconnect() { 63 | Polaris_Disconnect(&context_); 64 | } 65 | 66 | /******************************************************************************/ 67 | void PolarisInterface::SetRTCMCallback( 68 | std::function callback) { 69 | callback_ = callback; 70 | } 71 | 72 | /******************************************************************************/ 73 | int PolarisInterface::SendECEFPosition(double x_m, double y_m, double z_m) { 74 | return Polaris_SendECEFPosition(&context_, x_m, y_m, z_m); 75 | } 76 | 77 | /******************************************************************************/ 78 | int PolarisInterface::SendLLAPosition(double latitude_deg, double longitude_deg, 79 | double altitude_m) { 80 | return Polaris_SendLLAPosition(&context_, latitude_deg, longitude_deg, 81 | altitude_m); 82 | } 83 | 84 | /******************************************************************************/ 85 | int PolarisInterface::RequestBeacon(const std::string& beacon_id) { 86 | return Polaris_RequestBeacon(&context_, beacon_id.c_str()); 87 | } 88 | 89 | /******************************************************************************/ 90 | int PolarisInterface::Work() { 91 | return Polaris_Work(&context_); 92 | } 93 | 94 | /******************************************************************************/ 95 | int PolarisInterface::Run(int connection_timeout_ms) { 96 | return Polaris_Run(&context_, connection_timeout_ms); 97 | } 98 | 99 | /******************************************************************************/ 100 | const uint8_t* PolarisInterface::GetRecvBuffer() const { 101 | return context_.recv_buffer; 102 | } 103 | 104 | /******************************************************************************/ 105 | void PolarisInterface::HandleRTCMData(void* ptr, PolarisContext_t* context, 106 | const uint8_t* buffer, 107 | size_t size_bytes) { 108 | auto interface = static_cast(ptr); 109 | if (interface->callback_) { 110 | interface->callback_(buffer, size_bytes); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /test/cpp_application_base.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | # Add the polaris/c/test/ directory to the search path, then import the C library's test base class. 5 | repo_root_dir = os.path.normpath(os.path.join(os.path.dirname(__file__), '..')) 6 | sys.path.append(os.path.join(repo_root_dir, 'c/test')) 7 | 8 | from application_base import StandardApplication 9 | 10 | class CppStandardApplication(StandardApplication): 11 | DEFAULT_ROOT_DIR = repo_root_dir 12 | DEFAULT_COMMAND = ['%(path)s', '--polaris_api_key=%(polaris_api_key)s', '--polaris_unique_id=%(unique_id)s'] 13 | 14 | def __init__(self, application_name): 15 | super().__init__(application_name=application_name) 16 | -------------------------------------------------------------------------------- /test/run_unit_tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | echo "Testing simple_polaris_client..." 6 | python3 test/test_simple_polaris_cpp_client.py $* 7 | -------------------------------------------------------------------------------- /test/test_simple_polaris_cpp_client.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from cpp_application_base import CppStandardApplication 4 | 5 | class Test(CppStandardApplication): 6 | def __init__(self): 7 | super().__init__(application_name='simple_polaris_cpp_client') 8 | 9 | test = Test() 10 | test.parse_args() 11 | test.run() 12 | -------------------------------------------------------------------------------- /third_party/BUILD: -------------------------------------------------------------------------------- 1 | licenses(["notice"]) # Septentrio free use. 2 | 3 | package(default_visibility = ["//visibility:public"]) 4 | 5 | cc_library( 6 | name = "septentrio", 7 | srcs = [ 8 | "septentrio/crc.c", 9 | "septentrio/sbfread.c", 10 | "septentrio/sbfread_meas.c", 11 | "septentrio/sbfsvid.c", 12 | ], 13 | hdrs = [ 14 | "septentrio/crc.h", 15 | "septentrio/measepoch.h", 16 | "septentrio/measepochconfig.h", 17 | "septentrio/sbfdef.h", 18 | "septentrio/sbfread.h", 19 | "septentrio/sbfsigtypes.h", 20 | "septentrio/sbfsvid.h", 21 | "septentrio/ssntypes.h", 22 | "septentrio/sviddef.h", 23 | ], 24 | copts = [ 25 | "-DNO_DECRYPTION", 26 | ], 27 | includes = ["."], 28 | ) 29 | -------------------------------------------------------------------------------- /third_party/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(septentrio) 2 | -------------------------------------------------------------------------------- /third_party/septentrio/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(septentrio 2 | sbfsvid.h 3 | ssntypes.h 4 | measepochconfig.h 5 | sbfdef.h 6 | sbfread.h 7 | crc.h 8 | sbfread_meas.c 9 | sbfread.c 10 | measepoch.h 11 | crc.c 12 | sbfsvid.c 13 | sviddef.h 14 | sbfsigtypes.h) 15 | 16 | # Disable Septentrio encryption support. 17 | target_compile_options(septentrio PUBLIC -DNO_DECRYPTION=1) 18 | -------------------------------------------------------------------------------- /third_party/septentrio/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Makefile to rebuild the "sbf2asc" tool 3 | # 4 | # 5 | # Septentrio grants permission to use, copy, modify, and/or distribute 6 | # this software for any purpose with or without fee. 7 | # 8 | # THE SOFTWARE IS PROVIDED "AS IS" AND SEPTENTRIO DISCLAIMS ALL 9 | # WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 10 | # WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL 11 | # SEPTENTRIO BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR 12 | # CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS 13 | # OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, 14 | # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 15 | # CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | 17 | 18 | # $(CC) should be your C++ compiler, for instance: 19 | # CC = gcc 20 | 21 | # On some platform (Cygwin + GCC 3.2, i.e.), doubles are aligned on an 22 | # 8 bytes boundary by default. The GCC i386 "-mno-align-double" option 23 | # packs the structure and makes it binary compatible with SBF data 24 | # generated by the receivers. 25 | CFLAGS = -O -mno-align-double -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -DNO_DECRYPTION 26 | 27 | LDFLAGS = -lm 28 | 29 | COMMON_OBJS = sbfread.o sbfread_meas.o sbfsvid.o ssngetop.o crc.o 30 | ALL_OBJS = sbf2asc.o $(COMMON_OBJS) 31 | 32 | sbf2asc : sbf2asc.o $(COMMON_OBJS) 33 | $(CC) $^ -o $@ $(LDFLAGS) 34 | 35 | %.o : %.c 36 | $(CC) -c $(CFLAGS) -o $@ $< 37 | 38 | clean : 39 | rm sbf2asc $(ALL_OBJS) 40 | 41 | # Source dependencies: 42 | 43 | sbf2asc.o : sbf2asc.c ssngetop.h sbfread.h measepoch.h measepochconfig.h sviddef.h sbfsvid.h ssntypes.h sbfdef.h sbfsigtypes.h sbf2asc_version.h 44 | 45 | sbfread.o : sbfread.c sbfread.h crc.h ssntypes.h sbfdef.h sbfsigtypes.h 46 | 47 | sbfread_meas.o : sbfread_meas.c sbfread.h measepoch.h measepochconfig.h sviddef.h sbfsvid.h crc.h ssntypes.h sbfdef.h sbfsigtypes.h 48 | 49 | ssngetop.o : ssngetop.c ssngetop.h 50 | 51 | crc.o : crc.c crc.h ssntypes.h sbfdef.h 52 | 53 | # End of Makefile 54 | -------------------------------------------------------------------------------- /third_party/septentrio/ReadMe.txt: -------------------------------------------------------------------------------- 1 | 2 | "sbf2asc" Program 3 | 4 | ----------------- 5 | 6 | Introduction 7 | ------------ 8 | "sbf2asc" is a simple command-line program that converts the SBF data 9 | produced by Septentrio's GNSS receivers, into a column-based plain 10 | text file. "sbf2asc" and its sources are delivered by Septentrio as 11 | a help for the users of its GNSS receivers. It contains an "sbfdef.h" 12 | C header file, with structure definitions to ease the reading of SBF 13 | messages. 14 | 15 | "sbf2asc" is given "as is", without warranty. 16 | 17 | Compiling 18 | --------- 19 | Recompiling "sbf2asc" requires: 20 | 1. A C compiler and library 21 | 2. Preferably, a "make" utility 22 | 23 | "sbf2asc" has been successfully compiled and tested on 24 | the following systems, all with x86 processors: 25 | 26 | Microsoft Visual C++ Toolkit 2003 on Windows2000 27 | 28 | Microsoft Visual C++ 2005 Express Edition on Windows XP 29 | 30 | MinGW on Windows2000 (MSYS v1.0.10, w32api v3.1, mingw-runtime v3.5, 31 | gcc v3.4.2, binutils v2.15.91-20040904-1) 32 | 33 | Cygwin on Windows2000 (v1.5.5-1, gcc v3.3.1, ld v2.14.90, 34 | bash v2.05b.0(1), make v3.80) 35 | 36 | Linux Red Hat 6.2 (Linux v2.2.14-5.0, gcc v.egcs-2.91.66, ld v2.9.5, 37 | bash v2.03.8(1), make v3.78.1, glibc v2.1.3-15) 38 | 39 | Linux Fedora Core 2 (Linux v2.6.9-1.6_FC2, gcc v3.3.3, ld v2.15.90.0.3, 40 | bash v2.05b.0(1), make v3.80, glibc v2.3.3-27.1) 41 | 42 | Linux Fedora 7 (Linux v2.6.22.9-91.fc7, gcc v4.1.2, ld v2.17.50.0.12-4, 43 | bash v3.2.9(1)-release, GNU make v3.81, glibc v2.6-4) 44 | 45 | To recompile "sbf2asc" with "make": 46 | 47 | 1. Copy the "sbf2asc/" directory and its content from the CD-Rom on a 48 | local disc. 49 | 2. "cd sbf2asc" and compile with the "make" command. 50 | 51 | To compile "sbf2asc" with Microsoft Visual C++ Toolkit 2003: 52 | 53 | 1. Open the C++ Toolkit command window. 54 | 2. "cd sbf2asc" and compile with the "build.bat" command. 55 | 56 | 57 | To compile "sbf2asc" with Microsoft Visual C++ 6.0: 58 | 59 | 1. Open Visual C++ and create a project of type "Win32 Console 60 | Application". Select an empty project, without any default 61 | sources. 62 | 63 | 2. Add the following C sources to the project: 64 | "sbf2asc.c", "sbfread.c", "ssngetop.c", "crc.c" 65 | 66 | 3. Make sure to compile with structures aligned on 4-bytes boundary: 67 | 3.1 Open Projects -> Settings 68 | 3.2 Select tab "C/C++" 69 | 3.3 Select category: "Code generation" 70 | 3.4 Select "Struct member alignment": 4 byte 71 | 72 | 4. Build the project. 73 | 74 | 5. Use the executable in a "cmd.exe" windows, (a.k.a. a "DOS box") 75 | 76 | To compile with other compilers, make sure the compiler does not align 77 | "double"s on addresses multiple of 8 ("8 bytes alignment") but on 78 | addresses multiple of 4. 79 | 80 | Usage 81 | ----- 82 | Type "sbf2asc" without arguments to see a short summary 83 | of options and arguments. 84 | 85 | Known Limitations 86 | ----------------- 87 | "sbf2asc" has been written as an example and preferred readability to 88 | portability. It is not highly portable and will fail to parse an SBF 89 | file if compiled for big-endian processors, for instance, or for 90 | processors with different alignment requirements. They have been 91 | tested on 32-bit x86 processors only. 92 | 93 | References 94 | ---------- 95 | Contact: Septentrio NV Tel: +32.16.300.800 96 | Greenhill Campus Fax: +32.16.22.16.40 97 | Interleuvenlaan 15i 98 | 3001 Leuven e-mail: support@septentrio.com 99 | Belgium Web: http://www.septentrio.com 100 | 101 | (c) Copyright 2002-2015 Septentrio NV/SA. All rights reserved. 102 | -------------------------------------------------------------------------------- /third_party/septentrio/crc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * crc.c: Definition of a table and functions to compute and validate 3 | * a CRC. 4 | * 5 | * Septentrio grants permission to use, copy, modify, and/or distribute 6 | * this software for any purpose with or without fee. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND SEPTENTRIO DISCLAIMS ALL 9 | * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 10 | * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL 11 | * SEPTENTRIO BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR 12 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS 13 | * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, 14 | * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 15 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | */ 17 | 18 | #include "crc.h" 19 | 20 | /* Look up table for fast computation of the 16-bit CRC in the SBF header. */ 21 | 22 | typedef struct 23 | { 24 | uint16_t Sync; 25 | uint16_t CRC; 26 | uint16_t ID; 27 | uint16_t Length; 28 | } HeaderBlock_t; 29 | 30 | typedef HeaderBlock_t VoidBlock_t; 31 | 32 | static const uint16_t CRC_SBF_LookUp[256] = { 33 | 34 | 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 35 | 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, 36 | 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, 37 | 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, 38 | 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, 39 | 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, 40 | 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, 41 | 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, 42 | 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, 43 | 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, 44 | 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, 45 | 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, 46 | 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, 47 | 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, 48 | 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, 49 | 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, 50 | 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, 51 | 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, 52 | 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, 53 | 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, 54 | 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, 55 | 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 56 | 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, 57 | 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, 58 | 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, 59 | 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, 60 | 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, 61 | 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, 62 | 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 63 | 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, 64 | 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, 65 | 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 66 | }; 67 | 68 | /*---------------------------------------------------------------------------*/ 69 | /* This function computes the CRC of a buffer "buf" of "buf_length" bytes. */ 70 | 71 | uint16_t CRC_compute16CCITT (const void *buf, size_t buf_length) 72 | { 73 | uint32_t i; 74 | uint16_t crc = 0; 75 | const uint8_t *buf8 = (const uint8_t *) buf; /* Convert the type to access by byte. */ 76 | 77 | for (i=0; i> 8) ^ buf8[i] ]; 79 | } 80 | 81 | return crc; 82 | } 83 | 84 | /*---------------------------------------------------------------------------*/ 85 | /* Returns true if the CRC check of the SBFBlock is passed. */ 86 | 87 | bool CRCIsValid(const void *Mess) 88 | { 89 | const VoidBlock_t * Mess2 = (const VoidBlock_t *) Mess; /* Convert to access the generic fields. */ 90 | uint16_t crc; 91 | 92 | crc = CRC_compute16CCITT ( &(Mess2->ID), Mess2->Length-2*sizeof(uint16_t) ); 93 | 94 | return (crc == Mess2->CRC) ? true:false; 95 | } 96 | -------------------------------------------------------------------------------- /third_party/septentrio/crc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * crc.h: Declaration of functions to compute and validate 3 | * a CRC. 4 | * 5 | * Septentrio grants permission to use, copy, modify, and/or distribute 6 | * this software for any purpose with or without fee. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND SEPTENTRIO DISCLAIMS ALL 9 | * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 10 | * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL 11 | * SEPTENTRIO BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR 12 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS 13 | * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, 14 | * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 15 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | */ 17 | 18 | #ifndef CRC_H 19 | #define CRC_H 1 20 | 21 | #ifdef __cplusplus 22 | extern "C" { 23 | #endif 24 | 25 | #include 26 | #include "ssntypes.h" 27 | 28 | 29 | /*---------------------------------------------------------------------------*/ 30 | /* This function computes the CRC of a buffer "buf" of "buf_length" bytes. */ 31 | 32 | uint16_t FW_EXPORT CRC_compute16CCITT(const void * buf, size_t buf_length); 33 | 34 | /*---------------------------------------------------------------------------*/ 35 | /* Returns true if the CRC check of the SBFBlock is passed. */ 36 | 37 | bool FW_EXPORT CRCIsValid(const void *Mess); 38 | 39 | #ifdef __cplusplus 40 | } 41 | #endif 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /third_party/septentrio/measepochconfig.h: -------------------------------------------------------------------------------- 1 | /* 2 | * measepochconfig.h: definition of number of elements in the 3 | * MeasEpoch_t structure. 4 | * 5 | * Septentrio grants permission to use, copy, modify, and/or distribute 6 | * this software for any purpose with or without fee. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND SEPTENTRIO DISCLAIMS ALL 9 | * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 10 | * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL 11 | * SEPTENTRIO BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR 12 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS 13 | * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, 14 | * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 15 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | */ 17 | 18 | #ifndef MEASEPOCHCONFIG_DEFAULT_H 19 | #define MEASEPOCHCONFIG_DEFAULT_H 1 20 | 21 | /* when converting a Meas3 SBF block into MeasEpoch_t, support up to 22 | 100 logical channels (a logical channel contains all measurements 23 | for a given satellite), 2 antennas (MAIN and AUX) and up to 8 24 | signals per satellite. */ 25 | #define NR_OF_LOGICALCHANNELS 100 26 | #define NR_OF_ANTENNAS 2 27 | #define MAX_NR_OF_SIGNALS_PER_SATELLITE 8 28 | 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /third_party/septentrio/sbfread.h: -------------------------------------------------------------------------------- 1 | /* 2 | * sbfread.h: Declarations of SBF (Septentrio Binary 3 | * Format) reading and parsing functions. 4 | * 5 | * Septentrio grants permission to use, copy, modify, and/or distribute 6 | * this software for any purpose with or without fee. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND SEPTENTRIO DISCLAIMS ALL 9 | * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 10 | * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL 11 | * SEPTENTRIO BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR 12 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS 13 | * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, 14 | * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 15 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | */ 17 | 18 | #ifndef SBFREAD_H 19 | #define SBFREAD_H 1 20 | 21 | #include 22 | 23 | #include "ssntypes.h" 24 | 25 | #ifndef S_SPLINT_S 26 | #include 27 | #else 28 | typedef int64_t off_t; 29 | #endif 30 | 31 | #include "measepoch.h" 32 | #include "sbfdef.h" 33 | #include "sbfsigtypes.h" 34 | #include "sbfsvid.h" 35 | 36 | #ifdef __cplusplus 37 | extern "C" { 38 | #endif 39 | 40 | /* 64 bit versions for fseek and ftell are different for the different compilers */ 41 | /* STD C version */ 42 | #if (defined(__rtems__)) 43 | #define ssnfseek fseek 44 | #define ssnftell ftell 45 | #elif (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) 46 | #define ssnfseek fseeko 47 | #define ssnftell ftello 48 | /* Microsoft compiler MSVC */ 49 | #elif defined (_MSC_VER) 50 | #define ssnfseek _fseeki64 51 | #define ssnftell _ftelli64 52 | #define off_t __int64 53 | /* MinGW-32 */ 54 | #elif defined (__MINGW32__) && !defined (__MINGW64__) 55 | /* 32 bit on MinGW-64 already redefines them if _FILE_OFFSET_BITS=64 */ 56 | #define ssnfseek fseeko64 57 | #define ssnftell ftello64 58 | /* fall back to 32 bit version */ 59 | #else 60 | #define ssnfseek fseek 61 | #define ssnftell ftell 62 | #endif 63 | 64 | #define BLOCKNUMBER_ALL (0xffff) 65 | 66 | #define START_POS_FIELD 0x03LU 67 | #define START_POS_CURRENT 0x00LU 68 | #define START_POS_SET 0x01LU 69 | 70 | #define END_POS_FIELD 0x0cLU 71 | #define END_POS_AFTER_BLOCK 0x00LU 72 | #define END_POS_DONT_CHANGE 0x04LU 73 | 74 | #ifndef M_PI 75 | #define M_PI 3.14159265358979323846 /* pi */ 76 | #endif 77 | 78 | #define c84 299792458. /* WGS-84 value for lightspeed */ 79 | 80 | #define E5FREQ 1191.795e6 81 | #define E5aFREQ 1176.45e6 82 | #define E5bFREQ 1207.14e6 83 | #define E6FREQ 1278.75e6 84 | #define L1FREQ 1575.42e6 85 | #define L2FREQ 1227.60e6 86 | #define L5FREQ 1176.45e6 87 | #define E2FREQ 1561.098e6 88 | #define L1GLOFREQ 1602.00e6 89 | #define L2GLOFREQ 1246.00e6 90 | #define L3GLOFREQ 1202.025e6 91 | #define B3FREQ 1268.52e6 92 | 93 | #define E5WAVELENGTH (c84/E5FREQ) 94 | #define E5aWAVELENGTH (c84/E5aFREQ) 95 | #define E5bWAVELENGTH (c84/E5bFREQ) 96 | #define E6WAVELENGTH (c84/E6FREQ) 97 | #define L1WAVELENGTH (c84/L1FREQ) 98 | #define L2WAVELENGTH (c84/L2FREQ) 99 | #define L5WAVELENGTH (c84/L5FREQ) 100 | #define E2WAVELENGTH (c84/E2FREQ) 101 | #define L3WAVELENGTH (c84/L3GLOFREQ) 102 | #define B3WAVELENGTH (c84/B3FREQ) 103 | 104 | #define FIRSTEPOCHms_DONTCARE (-1LL) 105 | #define LASTEPOCHms_DONTCARE (1LL<<62) 106 | #define INTERVALms_DONTCARE (1) 107 | 108 | 109 | /* structure to keep the data from the last reference epoch when 110 | decoding Meas3 blocks. */ 111 | typedef struct { 112 | uint8_t SigIdx[MEAS3_SYS_MAX][MEAS3_SAT_MAX][MEAS3_SIG_MAX]; 113 | MeasSet_t MeasSet[MEAS3_SYS_MAX][MEAS3_SAT_MAX][MEAS3_SIG_MAX]; 114 | uint32_t SlaveSigMask[MEAS3_SYS_MAX][MEAS3_SAT_MAX]; 115 | int16_t PRRate_64mm_s[MEAS3_SYS_MAX][MEAS3_SAT_MAX]; 116 | uint32_t TOW_ms; 117 | 118 | uint8_t M3SatDataCopy[MEAS3_SYS_MAX][32]; 119 | } sbfread_Meas3_RefEpoch_t; 120 | 121 | 122 | typedef struct { 123 | uint8_t key[32]; /* decryption key */ 124 | bool has_key; /* true if decryption key has been set */ 125 | uint64_t nonce; /* decryption nonce */ 126 | bool has_nonce; /* true if decryption nonce has been set */ 127 | } SBFDecrypt_t; 128 | 129 | 130 | typedef struct { 131 | FILE* F; /* handle to the file */ 132 | SBFDecrypt_t decrypt; /* SBF decryption context */ 133 | 134 | /* the following fields are used to collect and decode the measurement 135 | blocks */ 136 | sbfread_Meas3_RefEpoch_t RefEpoch[NR_OF_ANTENNAS]; 137 | Meas3Ranges_1_t Meas3Ranges[NR_OF_ANTENNAS]; 138 | Meas3Doppler_1_t Meas3Doppler[NR_OF_ANTENNAS]; 139 | Meas3CN0HiRes_1_t Meas3CN0HiRes[NR_OF_ANTENNAS]; 140 | Meas3PP_1_t Meas3PP[NR_OF_ANTENNAS]; 141 | Meas3MP_1_t Meas3MP[NR_OF_ANTENNAS]; 142 | MeasEpoch_2_t MeasEpoch; 143 | MeasExtra_1_t MeasExtra; 144 | MeasFullRange_1_t MeasFullRange; 145 | uint32_t MeasCollect_CurrentTOW; 146 | uint32_t MeasCollect_BlocksSeenAtLastEpoch; 147 | uint32_t MeasCollect_BlocksSeenAtThisEpoch; 148 | uint32_t TOWAtLastMeasEpoch; 149 | } SBFData_t; 150 | 151 | void FW_EXPORT AlignSubBlockSize(void* SBFBlock, 152 | unsigned int N, 153 | size_t SourceSBSize, 154 | size_t TargetSBSize); 155 | 156 | int32_t FW_EXPORT CheckBlock(SBFData_t* SBFData, uint8_t* Buffer); 157 | 158 | int32_t FW_EXPORT GetNextBlock(SBFData_t* SBFData, 159 | /*@out@*/ void* SBFBlock, 160 | uint16_t BlockNumber1, uint16_t BlockNumber2, 161 | uint32_t FilePos); 162 | 163 | off_t FW_EXPORT GetSBFFilePos(SBFData_t* SBFData); 164 | 165 | off_t FW_EXPORT GetSBFFileLength(SBFData_t* SBFData); 166 | 167 | void FW_EXPORT InitializeSBFDecoding(char *FileName, 168 | /*@out@*/ SBFData_t* SBFData); 169 | 170 | void FW_EXPORT CloseSBFFile(SBFData_t* SBFData); 171 | 172 | bool FW_EXPORT IsTimeValid(void* SBFBlock); 173 | 174 | int FW_EXPORT GetCRCErrors(); 175 | 176 | #define SBFREAD_MEAS3_ENABLED 0x1 177 | #define SBFREAD_MEASEPOCH_ENABLED 0x2 178 | #define SBFREAD_ALLMEAS_ENABLED 0x3 179 | 180 | bool FW_EXPORT sbfread_MeasCollectAndDecode( 181 | SBFData_t *SBFData, 182 | void *SBFBlock, 183 | MeasEpoch_t /*@out@*/ *MeasEpoch, 184 | uint32_t EnabledMeasTypes); 185 | 186 | bool FW_EXPORT sbfread_FlushMeasEpoch(SBFData_t *SBFData, 187 | MeasEpoch_t *MeasEpoch, 188 | uint32_t EnabledMeasTypes); 189 | 190 | void FW_EXPORT sbfread_MeasEpoch_Decode(MeasEpoch_2_t *sbfMeasEpoch, 191 | MeasEpoch_t *MeasEpoch ); 192 | 193 | void FW_EXPORT sbfread_MeasExtra_Decode(MeasExtra_1_t *sbfMeasExtra, 194 | MeasEpoch_t *measEpoch ); 195 | 196 | 197 | double FW_EXPORT GetWavelength_m(SignalType_t SignalType, int GLOfn); 198 | 199 | 200 | MeasEpochChannelType1_t 201 | FW_EXPORT *GetFirstType1SubBlock(const MeasEpoch_2_t *MeasEpoch); 202 | 203 | MeasEpochChannelType1_t 204 | FW_EXPORT *GetNextType1SubBlock(const MeasEpoch_2_t *MeasEpoch, 205 | MeasEpochChannelType1_t *CurrentType1SubBlock); 206 | 207 | uint32_t FW_EXPORT GetMeasEpochSVID(MeasEpochChannelType1_t *Type1SubBlock); 208 | 209 | uint32_t FW_EXPORT GetMeasEpochRXChannel(MeasEpochChannelType1_t *Type1SubBlock); 210 | 211 | bool FW_EXPORT IncludeThisEpoch(void* SBFBlock, 212 | int64_t ForcedFirstEpoch_ms, 213 | int64_t ForcedLastEpoch_ms, 214 | int ForcedInterval_ms, 215 | bool AcceptInvalidTimeStamp); 216 | 217 | void FW_EXPORT SBFDecryptBlock(SBFDecrypt_t *decrypt, 218 | VoidBlock_t *block); 219 | 220 | #define TerminateProgram {char S[255]; \ 221 | (void)snprintf(S, sizeof(S), "Abnormal program termination (%s,%i)", \ 222 | __FILE__, __LINE__); \ 223 | S[254] = '\0'; \ 224 | perror(S); \ 225 | exit(EXIT_FAILURE); \ 226 | } 227 | 228 | #ifdef __cplusplus 229 | } 230 | #endif 231 | 232 | #endif 233 | /* End of "ifndef SBFREAD_H" */ 234 | -------------------------------------------------------------------------------- /third_party/septentrio/sbfsigtypes.h: -------------------------------------------------------------------------------- 1 | /* 2 | * sbfsigtypes.h: Definition of GNSS signal types used by Septentrio receivers. 3 | * 4 | * Septentrio grants permission to use, copy, modify, and/or distribute 5 | * this software for any purpose with or without fee. 6 | * 7 | * THE SOFTWARE IS PROVIDED "AS IS" AND SEPTENTRIO DISCLAIMS ALL 8 | * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 9 | * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL 10 | * SEPTENTRIO BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR 11 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS 12 | * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, 13 | * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 14 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | /** 17 | * \file 18 | * \brief Declaration of an enumeration for satellite signals. 19 | * \ingroup sbfdata 20 | * 21 | * Declaration and definition of an enumeration for satellite signals. 22 | * 23 | * \par Copyright: 24 | * (c) 2000-2015 Copyright Septentrio NV/SA. All rights reserved. 25 | */ 26 | 27 | #ifndef SBFSIGTYPES_H 28 | #define SBFSIGTYPES_H 1 /*!< To avoid multiple inclusions */ 29 | 30 | 31 | /** Enumeration of the different signal modulations. 32 | * It is important not to mix signal types from different constellations. */ 33 | 34 | typedef enum { 35 | SIG_GPSL1CA =0, /**< GPS L1 C/A */ 36 | SIG_GPSL1P =1, /**< GPS L1 P(Y) */ 37 | SIG_GPSL2P =2, /**< GPS L2 P(Y) */ 38 | SIG_GPSL2C =3, /**< GPS L2C */ 39 | SIG_GPSL5 =4, /**< GPS L5 */ 40 | SIG_GPSL1C =5, /**< GPS L1C */ 41 | SIG_QZSL1CA =6, /**< QZSS L1 C/A */ 42 | SIG_QZSL2C =7, /**< QZSS L2C */ 43 | SIG_GLOL1CA =8, /**< GLONASS L1 C/A */ 44 | SIG_GLOL1P =9, /**< GLONASS L1 P */ 45 | SIG_GLOL2P =10, /**< GLONASS L2 P */ 46 | SIG_GLOL2CA =11, /**< GLONASS L2 C/A */ 47 | SIG_GLOL3 =12, /**< GLONASS L3 */ 48 | SIG_BDSB1C =13, /**< BeiDou B1C */ 49 | SIG_BDSB2a =14, /**< BeiDou B2a */ 50 | SIG_IRNL5 =15, /**< IRNSS L5 */ 51 | SIG_GALE1A =16, /**< Galileo E1 A */ 52 | SIG_GALE1BC =17, /**< Galileo E1 BC */ 53 | SIG_GALE6A =18, /**< Galileo E6 A */ 54 | SIG_GALE6BC =19, /**< Galileo E6 BC */ 55 | SIG_GALE5a =20, /**< Galileo E5a */ 56 | SIG_GALE5b =21, /**< Galileo E5b */ 57 | SIG_GALE5 =22, /**< Galileo E5 AltBOC */ 58 | SIG_MSS =23, /**< MSS L-Band signal */ 59 | SIG_SBSL1CA =24, /**< SBAS L1 C/A */ 60 | SIG_SBSL5 =25, /**< SBAS L5 */ 61 | SIG_QZSL5 =26, /**< QZSS L5 */ 62 | SIG_QZSL6 =27, /**< QZSS L6 */ 63 | SIG_BDSB1I =28, /**< BeiDou B1I */ 64 | SIG_BDSB2I =29, /**< BeiDou B2I */ 65 | SIG_BDSB3 =30, /**< BeiDou B3 */ 66 | SIG_UNUSED =31, /**< */ 67 | SIG_QZSL1C =32, /**< QZSS L1C */ 68 | SIG_QZSL1S =33, /**< QZSS L1S */ 69 | 70 | SIG_LAST =34, /**< (This must be the last item in the list, never delete it.) */ 71 | SIG_INVALID =255 72 | } SignalType_t; 73 | 74 | #endif 75 | /* End of "ifndef SBFSIGTYPES_H" */ 76 | -------------------------------------------------------------------------------- /third_party/septentrio/sbfsvid.c: -------------------------------------------------------------------------------- 1 | /* 2 | * sbfsvid.c: Definition of the functions to transform SVID number in 3 | * SBF to SVID numbering the MeasEpoch_t structure. 4 | * 5 | * Septentrio grants permission to use, copy, modify, and/or distribute 6 | * this software for any purpose with or without fee. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND SEPTENTRIO DISCLAIMS ALL 9 | * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 10 | * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL 11 | * SEPTENTRIO BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR 12 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS 13 | * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, 14 | * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 15 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | */ 17 | 18 | #include "sbfsvid.h" 19 | #include "sviddef.h" 20 | 21 | #define SBFSVID_GPS_MIN ( 1) 22 | #define SBFSVID_GPS_MAX ( 37) 23 | 24 | #define SBFSVID_GLO_MIN1 ( 38) 25 | #define SBFSVID_GLO_MAX1 ( 61) 26 | #define SBFSVID_GLO_UNK ( 62) 27 | #define SBFSVID_GLO_MIN2 ( 63) 28 | #define SBFSVID_GLO_MAX2 ( 70) 29 | #define SBFSVID_GLO_GAP1 (SBFSVID_GLO_MIN2-SBFSVID_GLO_MAX1-1) 30 | 31 | #define SBFSVID_GAL_MIN ( 71) 32 | #define SBFSVID_GAL_MAX (106) 33 | 34 | #define SBFSVID_LBR_MIN (107) 35 | #define SBFSVID_LBR_MAX (118) 36 | #define SBFSVID_LBR_UNK (119) 37 | 38 | #define SBFSVID_RA_MIN1 (120) 39 | #define SBFSVID_RA_MAX1 (140) 40 | #define SBFSVID_RA_MIN2 (198) 41 | #define SBFSVID_RA_MAX2 (215) 42 | #define SBFSVID_RA_GAP1 (SBFSVID_RA_MIN2-SBFSVID_RA_MAX1-1) 43 | 44 | #define SBFSVID_BDS_MIN (141) 45 | #define SBFSVID_BDS_MAX (177) 46 | 47 | #define SBFSVID_QZSS_MIN (181) 48 | #define SBFSVID_QZSS_MAX (187) 49 | 50 | #define SBFSVID_IRNS_MIN (191) 51 | #define SBFSVID_IRNS_MAX (197) 52 | 53 | #define SBFSVID_INVALID (255) 54 | 55 | uint32_t convertSVIDfromSBF(uint32_t sbfSVID) 56 | { 57 | uint32_t internalSBF = 0; 58 | 59 | // GPS 60 | if (sbfSVID >= SBFSVID_GPS_MIN && sbfSVID <= SBFSVID_GPS_MAX) 61 | { 62 | internalSBF = (uint32_t)(sbfSVID+(gpMINPRN-SBFSVID_GPS_MIN)); 63 | } 64 | // GLO 65 | if (sbfSVID >= SBFSVID_GLO_MIN1 && sbfSVID <= SBFSVID_GLO_MAX1) 66 | { 67 | internalSBF = (uint32_t)(sbfSVID+(glMINPRN-SBFSVID_GLO_MIN1)); 68 | } 69 | if (sbfSVID == SBFSVID_GLO_UNK) 70 | { 71 | internalSBF = (uint32_t)glPRNUNKWN; 72 | } 73 | if (sbfSVID >= SBFSVID_GLO_MIN2 && sbfSVID <= SBFSVID_GLO_MAX2) 74 | { 75 | internalSBF = (uint32_t)(sbfSVID+(glMINPRN-SBFSVID_GLO_MIN1-SBFSVID_GLO_GAP1)); 76 | } 77 | // GAL 78 | if (sbfSVID >= SBFSVID_GAL_MIN && sbfSVID <= SBFSVID_GAL_MAX) 79 | { 80 | internalSBF = (uint32_t)(sbfSVID+(galMINPRN-SBFSVID_GAL_MIN)); 81 | } 82 | // LBAND 83 | if (sbfSVID >= SBFSVID_LBR_MIN && sbfSVID <= SBFSVID_LBR_MAX) 84 | { 85 | internalSBF = (uint32_t)(sbfSVID+(lbMINPRN-SBFSVID_LBR_MIN)); 86 | } 87 | if (sbfSVID == SBFSVID_LBR_UNK) 88 | { 89 | internalSBF = (uint32_t)lbPRNUNKWN; 90 | } 91 | // SBAS 92 | if (sbfSVID >= SBFSVID_RA_MIN1 && sbfSVID <= SBFSVID_RA_MAX1) 93 | { 94 | internalSBF = (uint32_t)(sbfSVID+(raMINPRN-SBFSVID_RA_MIN1)); 95 | } 96 | if (sbfSVID >= SBFSVID_RA_MIN2 && sbfSVID <= SBFSVID_RA_MAX2) 97 | { 98 | internalSBF = (uint32_t)(sbfSVID+(raMINPRN-SBFSVID_RA_MIN1-SBFSVID_RA_GAP1)); 99 | } 100 | // BDS 101 | if (sbfSVID >= SBFSVID_BDS_MIN && sbfSVID <= SBFSVID_BDS_MAX) 102 | { 103 | internalSBF = (uint32_t)(sbfSVID+(cmpMINPRN-SBFSVID_BDS_MIN)); 104 | } 105 | // QZSS 106 | if (sbfSVID >= SBFSVID_QZSS_MIN && sbfSVID <= SBFSVID_QZSS_MAX) 107 | { 108 | internalSBF = (uint32_t)(sbfSVID+(qzMINPRN-SBFSVID_QZSS_MIN)); 109 | } 110 | // IRNSS 111 | if (sbfSVID >= SBFSVID_IRNS_MIN && sbfSVID <= SBFSVID_IRNS_MAX) 112 | { 113 | internalSBF = (uint32_t)(sbfSVID+(irMINPRN-SBFSVID_IRNS_MIN)); 114 | } 115 | 116 | return internalSBF; 117 | } 118 | 119 | 120 | uint8_t convertSVIDtoSBF(uint32_t internalSVID) 121 | { 122 | uint8_t sbfSVID = SBFSVID_INVALID; 123 | 124 | if (agIsGPS(internalSVID)) 125 | { 126 | sbfSVID = (uint8_t)(internalSVID-gpMINPRN+SBFSVID_GPS_MIN); 127 | } 128 | else if (agIsGLONASS(internalSVID)) 129 | { 130 | sbfSVID = (uint8_t)(internalSVID-glMINPRN+SBFSVID_GLO_MIN1); 131 | /* this is for the GLONASS slots > 24 */ 132 | if (internalSVID >= glMINPRN+24 && internalSVID <(int)glPRNUNKWN) 133 | { 134 | sbfSVID += SBFSVID_GLO_GAP1; 135 | } 136 | if (internalSVID == (int)glPRNUNKWN) 137 | { 138 | sbfSVID = (uint8_t)SBFSVID_GLO_UNK; 139 | } 140 | } 141 | else if (agIsGAL(internalSVID)) 142 | { 143 | sbfSVID = (uint8_t)(internalSVID-galMINPRN+SBFSVID_GAL_MIN); 144 | } 145 | else if (agIsLBR(internalSVID)) 146 | { 147 | sbfSVID = (uint8_t)(internalSVID-lbMINPRN+SBFSVID_LBR_MIN); 148 | if (internalSVID == (int)lbPRNUNKWN) 149 | { 150 | sbfSVID = (uint8_t)SBFSVID_LBR_UNK; 151 | } 152 | } 153 | else if (agIsRA(internalSVID)) 154 | { 155 | sbfSVID = (uint8_t)(internalSVID-raMINPRN+SBFSVID_RA_MIN1); 156 | /* this is the second part of the SBAS PRNS, remapped in SBF in the 198-215 range */ 157 | if (internalSVID >= raMINPRN+21) 158 | { 159 | sbfSVID += SBFSVID_RA_GAP1; 160 | } 161 | } 162 | else if (agIsCOMPASS(internalSVID)) 163 | { 164 | sbfSVID = (uint8_t)(internalSVID-cmpMINPRN+SBFSVID_BDS_MIN); 165 | } 166 | else if (agIsQZSS(internalSVID)) 167 | { 168 | sbfSVID = (uint8_t)(internalSVID-qzMINPRN+SBFSVID_QZSS_MIN); 169 | } 170 | else if (agIsIRNSS(internalSVID)) 171 | { 172 | sbfSVID = (uint8_t)(internalSVID-irMINPRN+SBFSVID_IRNS_MIN); 173 | } 174 | 175 | return sbfSVID; 176 | } 177 | -------------------------------------------------------------------------------- /third_party/septentrio/sbfsvid.h: -------------------------------------------------------------------------------- 1 | /* 2 | * sbfsvid.h: Declaration of the functions to transform SVID number in 3 | * SBF to SVID numbering the MeasEpoch_t structure. 4 | * 5 | * Septentrio grants permission to use, copy, modify, and/or distribute 6 | * this software for any purpose with or without fee. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND SEPTENTRIO DISCLAIMS ALL 9 | * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 10 | * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL 11 | * SEPTENTRIO BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR 12 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS 13 | * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, 14 | * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 15 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | */ 17 | 18 | #ifndef SBFSVID_H 19 | #define SBFSVID_H 1 20 | 21 | #include "ssntypes.h" 22 | 23 | #ifdef __cplusplus 24 | extern "C" { 25 | #endif 26 | 27 | /*! Convert the SBF SVID numbering into the internal SVID numbering . 28 | */ 29 | uint32_t FW_EXPORT convertSVIDfromSBF(uint32_t sbfSVID); 30 | 31 | /*! Convert the internal SVID numbering into SBF SVID numbering 32 | */ 33 | uint8_t FW_EXPORT convertSVIDtoSBF(uint32_t internalSVID); 34 | 35 | #ifdef __cplusplus 36 | } 37 | #endif 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /third_party/septentrio/ssntypes.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ssntypes.h: 3 | * Declarations of Septentrio types and implementation of common C types which 4 | * are not implemented by every compiler. 5 | * 6 | * If your compiler does not support the standard C99 types from \p stdint.h 7 | * and \p stdbool.h, please define them for your platform. \n 8 | * This is already done for the Microsoft C/C++ compiler. 9 | * 10 | * 11 | * Septentrio grants permission to use, copy, modify, and/or distribute 12 | * this software for any purpose with or without fee. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS" AND SEPTENTRIO DISCLAIMS ALL 15 | * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL 17 | * SEPTENTRIO BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR 18 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS 19 | * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, 20 | * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 21 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 22 | */ 23 | 24 | #ifndef SSNTYPES_H 25 | #define SSNTYPES_H 1 /**< To avoid multiple inclusions. */ 26 | 27 | #ifdef __linux__ 28 | # ifndef FW_EXPORT 29 | # ifdef ENABLE_VISIBILITY 30 | # define FW_EXPORT __attribute__((visibility("default"))) 31 | # else 32 | # define FW_EXPORT 33 | # endif 34 | # endif 35 | #endif 36 | 37 | #if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || defined(__GNUC__) || defined(__ARMCC__) 38 | # include 39 | # include 40 | # include 41 | #else 42 | # ifdef _MSC_VER 43 | # include "mscssntypes.h" 44 | # ifndef _USE_MATH_DEFINES /* used to define M_PI and so*/ 45 | # define _USE_MATH_DEFINES 46 | # endif 47 | # endif 48 | #endif 49 | 50 | #define I8_NOTVALID (int8_t) (0x80) 51 | #define UI8_NOTVALID (uint8_t) (0xFF) 52 | #define I16_NOTVALID (int16_t) (0x8000) 53 | #define U16_NOTVALID (uint16_t)(0xFFFF) 54 | #define I32_NOTVALID (int32_t) (0x80000000) 55 | #define U32_NOTVALID (uint32_t)(0xFFFFFFFF) 56 | #define I64_NOTVALID (int64_t) (0x8000000000000000LL) 57 | #define U64_NOTVALID (uint64_t)(0xFFFFFFFFFFFFFFFFULL) 58 | #define F32_NOTVALID (-2e10F) 59 | #define F64_NOTVALID (-2e10) 60 | 61 | #ifndef FW_EXPORT 62 | # define FW_EXPORT /**< For making a DLL with the Microsoft C/C++ compiler. */ 63 | #endif 64 | 65 | #endif 66 | /* End of "ifndef SSNTYPES_H" */ 67 | -------------------------------------------------------------------------------- /third_party/septentrio/sviddef.h: -------------------------------------------------------------------------------- 1 | /* 2 | * sviddef.h: Septentrio specific GNSS satellite numbering. 3 | * 4 | * Septentrio grants permission to use, copy, modify, and/or distribute 5 | * this software for any purpose with or without fee. 6 | * 7 | * THE SOFTWARE IS PROVIDED "AS IS" AND SEPTENTRIO DISCLAIMS ALL 8 | * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 9 | * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL 10 | * SEPTENTRIO BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR 11 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS 12 | * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, 13 | * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 14 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #ifndef SVIDDEF_H 18 | #define SVIDDEF_H 1 19 | 20 | /* Septentrio-specific internal SVID numbering (this numbering is 21 | different from the numbering in the SBF blocks): 22 | 23 | 1- 32 : GPS 24 | 38- 68 : GLONASS 25 | 71-106 : GALILEO 26 | 107-119 : L-Band (MSS) 27 | 120-158 : SBAS, Regional Augmentation (RA) 28 | 161-197 : BeiDou/Compass 29 | 201-207 : QZSS 30 | 211-217 : IRNSS (NAVIC) 31 | */ 32 | 33 | 34 | /* GPS */ 35 | #define gpMINPRN 1U 36 | #define gpMAXPRN 32U 37 | #define gpNBRPRN ((gpMAXPRN-gpMINPRN)+1U) 38 | 39 | /* GLONASS */ 40 | /* At cold boot, the relation between the slot numbers and the freq NR 41 | is unknown. The PRN number glPRNUNKWN is reserved to indicate that 42 | the actual slot number is unknown. */ 43 | #define glMINPRN 38U 44 | #define glMAXPRN 67U 45 | #define glNBRPRN ((glMAXPRN-glMINPRN)+1U) 46 | #define glPRNUNKWN (glMAXPRN+1U) 47 | #define glNBRFN 14U /**< number of frequency numbers (from -7 to +6)*/ 48 | 49 | /* GALILEO */ 50 | #define galMINPRN 71U 51 | #define galMAXPRN 106U 52 | #define galNBRPRN ((galMAXPRN-galMINPRN)+1U) 53 | 54 | /* L-Band (Inmarsat) satellites */ 55 | #define lbMINPRN 107U 56 | #define lbMAXPRN 118U 57 | #define lbNBRPRN ((lbMAXPRN-lbMINPRN)+1U) 58 | #define lbPRNUNKWN 119U 59 | 60 | /* SBAS (regional augmentation) */ 61 | #define raMINPRN 120U 62 | #define raMAXPRN 158U 63 | #define raNBRPRN ((raMAXPRN-raMINPRN)+1U) 64 | 65 | /* BeiDou */ 66 | #define cmpMINPRN 161U 67 | #define cmpMAXPRN 197U 68 | #define cmpNBRPRN ((cmpMAXPRN-cmpMINPRN)+1U) 69 | 70 | /* QZSS */ 71 | #define qzMINPRN 201U 72 | #define qzMAXPRN 207U 73 | #define qzNBRPRN ((qzMAXPRN-qzMINPRN)+1U) 74 | 75 | /* IRNSS */ 76 | #define irMINPRN 211U 77 | #define irMAXPRN 217U 78 | #define irNBRPRN ((irMAXPRN-irMINPRN)+1U) 79 | 80 | 81 | #define agIsGLONASS(prn) (((unsigned long)prn >= glMINPRN) && \ 82 | ((unsigned long)prn <= glPRNUNKWN)) 83 | 84 | #define agIsGLOKWN(prn) (((unsigned long)prn >= glMINPRN) && \ 85 | ((unsigned long)prn <= glMAXPRN)) 86 | 87 | #define agIsGPS(prn) (((unsigned long)prn >= gpMINPRN) && \ 88 | ((unsigned long)prn <= gpMAXPRN)) 89 | 90 | #define agIsRA(prn) (((unsigned long)prn >= raMINPRN) && \ 91 | ((unsigned long)prn <= raMAXPRN)) 92 | 93 | #define agIsGAL(prn) (((unsigned long)prn >= galMINPRN) && \ 94 | ((unsigned long)prn <= galMAXPRN)) 95 | 96 | #define agIsCOMPASS(prn) (((unsigned long)prn >= cmpMINPRN) && \ 97 | ((unsigned long)prn <= cmpMAXPRN)) 98 | 99 | #define agIsLBR(prn) (((unsigned long)prn >= lbMINPRN) && \ 100 | ((unsigned long)prn <= lbPRNUNKWN)) 101 | 102 | #define agIsQZSS(prn) (((unsigned long)prn >= qzMINPRN) && \ 103 | ((unsigned long)prn <= qzMAXPRN)) 104 | 105 | #define agIsIRNSS(prn) (((unsigned long)prn >= irMINPRN) && \ 106 | ((unsigned long)prn <= irMAXPRN)) 107 | 108 | #define agIsValid(prn) (agIsGPS(prn) || \ 109 | agIsGLONASS(prn) || \ 110 | agIsGAL(prn) || \ 111 | agIsCOMPASS(prn) || \ 112 | agIsLBR(prn) || \ 113 | agIsQZSS(prn) || \ 114 | agIsIRNSS(prn) || \ 115 | agIsRA(prn) ) 116 | 117 | 118 | #endif 119 | 120 | --------------------------------------------------------------------------------