├── .gitignore ├── img ├── logo-words_75.png └── arduino_logo_75.png ├── docs └── u-blox-F9-HPG-1.30_InterfaceDescription_UBX-21046737.pdf ├── CONTRIBUTING.md ├── library.properties ├── .gitlab-ci.yml ├── LICENSE.md ├── CHANGELOG.md ├── examples ├── arduino │ └── ublox_example │ │ └── ublox_example.ino └── cmake │ └── ublox_example.cc ├── keywords.txt ├── CMakeLists.txt ├── src ├── ubx_defs.h ├── ubx.h ├── ubx.cpp └── ubx_nav.h └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # ignore the build directory 2 | /build* 3 | 4 | # ignore VS code 5 | .vscode 6 | -------------------------------------------------------------------------------- /img/logo-words_75.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolderflight/ublox/HEAD/img/logo-words_75.png -------------------------------------------------------------------------------- /img/arduino_logo_75.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolderflight/ublox/HEAD/img/arduino_logo_75.png -------------------------------------------------------------------------------- /docs/u-blox-F9-HPG-1.30_InterfaceDescription_UBX-21046737.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolderflight/ublox/HEAD/docs/u-blox-F9-HPG-1.30_InterfaceDescription_UBX-21046737.pdf -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Please see our [Contributing Guide](https://github.com/bolderflight/contributing) for tips on how to effectively make contributions to our project. 4 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=Bolder Flight Systems UBLOX 2 | version=6.0.6 3 | author=Brian Taylor 4 | maintainer=Brian Taylor 5 | sentence=Library for communicating with uBlox GPS receivers. 6 | paragraph=This library communicates with the uBlox receivers using the UBX protocol. This approach allows for very efficiently collecting GPS data that most users need. 7 | category=Sensors 8 | url=https://github.com/bolderflight/ublox 9 | architectures=* 10 | includes=ubx.h 11 | depends=Bolder Flight Systems Eigen 12 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | stages: 2 | - lint 3 | 4 | Lint: 5 | stage: lint 6 | tags: 7 | - bfs 8 | script: 9 | - cpplint --verbose=0 src/ubx.cpp 10 | - cpplint --verbose=0 src/ubx.h 11 | - cpplint --verbose=0 src/ubx_ack.h 12 | - cpplint --verbose=0 src/ubx_cfg.h 13 | - cpplint --verbose=0 src/ubx_defs.h 14 | - cpplint --verbose=0 src/ubx_inf.h 15 | - cpplint --verbose=0 src/ubx_log.h 16 | - cpplint --verbose=0 src/ubx_mga.h 17 | - cpplint --verbose=0 src/ubx_mon.h 18 | - cpplint --verbose=0 src/ubx_nav.h 19 | - cpplint --verbose=0 src/ubx_rxm.h 20 | - cpplint --verbose=0 src/ubx_sec.h 21 | - cpplint --verbose=0 src/ubx_time.h 22 | - cpplint --verbose=0 src/ubx_upd.h -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2022 Bolder Flight Systems Inc 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | 11 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## v6.0.6 4 | - Removing the bus->end call in the Begin method, this caused some microcontrollers to lock up. 5 | 6 | ## v6.0.5 7 | - Updated core to v3.1.3 8 | 9 | ## v6.0.4 10 | - Updated core to v3.1.2 11 | 12 | ## v6.0.3 13 | - Fixed a bug in init where it could get stuck in Begin method. 14 | 15 | ## v6.0.2 16 | - Updated core to support MMOD 17 | 18 | ## v6.0.1 19 | - Fixed bug in converting from deg to rad where precision could be lost with lat / lon 20 | 21 | ## v6.0.0 22 | - Removed dependency on Eigen and Units libraries to better support Arduino AVR 23 | - Added CMake support for Teensy MMOD 24 | 25 | ## v5.1.0 26 | - Added default constructor and a config method to configure the receiver 27 | 28 | ## v5.0.0 29 | - Removed configuration methods (for now), since they weren't always reliable 30 | - Added relative position output 31 | - Added survey-in output 32 | 33 | ## v4.1.0 34 | - Added relative position output to support GNSS RTK and GNSS yaw 35 | 36 | ## v4.0.1 37 | - Fixing issue with linker in versions older than C++17 38 | 39 | ## v4.0.0 40 | - Merging ublox and ublox-arduino 41 | - Using mcu_support repo for CMake builds 42 | - Autoconfiguring receiver 43 | 44 | ## v2.0.0 45 | - Updated to match our [Ublox](https://github.com/bolderflight/ublox-arduino) library for flight software 46 | - Updated license to MIT 47 | 48 | ## v1.1.0 49 | - Updated license to GPLV3. 50 | 51 | ## v1.0.0 52 | - Modified to work with Arduino 1.5 format and creating a baseline release now. 53 | -------------------------------------------------------------------------------- /examples/arduino/ublox_example/ublox_example.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * Brian R Taylor 3 | * brian.taylor@bolderflight.com 4 | * 5 | * Copyright (c) 2022 Bolder Flight Systems Inc 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the “Software”), to 9 | * deal in the Software without restriction, including without limitation the 10 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 11 | * sell copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 23 | * IN THE SOFTWARE. 24 | */ 25 | 26 | #include "ubx.h" 27 | 28 | /* Ublox object, GNSS on Serial3 */ 29 | bfs::Ubx gnss(&Serial3); 30 | 31 | void setup() { 32 | /* Serial to display data */ 33 | Serial.begin(115200); 34 | while(!Serial) {} 35 | gnss.Begin(921600); 36 | } 37 | 38 | void loop() { 39 | if(gnss.Read()) { 40 | Serial.print(gnss.fix()); 41 | Serial.print("\t"); 42 | Serial.print(gnss.num_sv()); 43 | Serial.print("\t"); 44 | Serial.print(gnss.lat_deg(), 6); 45 | Serial.print("\t"); 46 | Serial.print(gnss.lon_deg(), 6); 47 | Serial.print("\t"); 48 | Serial.print(gnss.alt_wgs84_m(), 2); 49 | Serial.print("\n"); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | Ubx KEYWORD1 2 | Fix KEYWORD1 3 | FIX_NONE LITERAL1 4 | FIX_2D LITERAL1 5 | FIX_3D LITERAL1 6 | FIX_DGNSS LITERAL1 7 | FIX_RTK_FLOAT LITERAL1 8 | FIX_RTK_FIXED LITERAL1 9 | Read KEYWORD2 10 | Config KEYWORD2 11 | Begin KEYWORD2 12 | fix KEYWORD2 13 | num_sv KEYWORD2 14 | utc_year KEYWORD2 15 | utc_month KEYWORD2 16 | utc_day KEYWORD2 17 | utc_hour KEYWORD2 18 | utc_min KEYWORD2 19 | utc_sec KEYWORD2 20 | utc_nano KEYWORD2 21 | gps_tow_s KEYWORD2 22 | gps_week KEYWORD2 23 | leap_s KEYWORD2 24 | time_acc_ns KEYWORD2 25 | north_vel_mps KEYWORD2 26 | east_vel_mps KEYWORD2 27 | down_vel_mps KEYWORD2 28 | gnd_spd_mps KEYWORD2 29 | ecef_vel_x_mps KEYWORD2 30 | ecef_vel_y_mps KEYWORD2 31 | ecef_vel_z_mps KEYWORD2 32 | spd_acc_mps KEYWORD2 33 | track_deg KEYWORD2 34 | track_rad KEYWORD2 35 | track_acc_deg KEYWORD2 36 | track_acc_rad KEYWORD2 37 | lat_deg KEYWORD2 38 | lat_rad KEYWORD2 39 | lon_deg KEYWORD2 40 | lon_rad KEYWORD2 41 | alt_wgs84_m KEYWORD2 42 | alt_msl_m KEYWORD2 43 | horz_acc_m KEYWORD2 44 | vert_acc_m KEYWORD2 45 | ecef_pos_x_m KEYWORD2 46 | ecef_pos_y_m KEYWORD2 47 | ecef_pos_z_m KEYWORD2 48 | ecef_pos_acc_m KEYWORD2 49 | gdop KEYWORD2 50 | pdop KEYWORD2 51 | tdop KEYWORD2 52 | vdop KEYWORD2 53 | hdop KEYWORD2 54 | ndop KEYWORD2 55 | edop KEYWORD2 56 | rel_pos_avail KEYWORD2 57 | rel_pos_moving_baseline KEYWORD2 58 | rel_pos_ref_pos_miss KEYWORD2 59 | rel_pos_ref_obs_miss KEYWORD2 60 | rel_pos_heading_valid KEYWORD2 61 | rel_pos_normalized KEYWORD2 62 | rel_pos_north_m KEYWORD2 63 | rel_pos_east_m KEYWORD2 64 | rel_pos_down_m KEYWORD2 65 | rel_pos_acc_north_m KEYWORD2 66 | rel_pos_acc_east_m KEYWORD2 67 | rel_pos_acc_down_m KEYWORD2 68 | rel_pos_len_m KEYWORD2 69 | rel_pos_len_acc_m KEYWORD2 70 | rel_pos_heading_deg KEYWORD2 71 | rel_pos_heading_acc_deg KEYWORD2 72 | rel_pos_heading_rad KEYWORD2 73 | rel_pos_heading_acc_rad KEYWORD2 74 | svin_valid KEYWORD2 75 | svin_in_progress KEYWORD2 76 | svin_dur_s KEYWORD2 77 | svin_ecef_pos_x_m KEYWORD2 78 | svin_ecef_pos_y_m KEYWORD2 79 | svin_ecef_pos_z_m KEYWORD2 80 | svin_ecef_pos_acc_m KEYWORD2 81 | svin_num_obs KEYWORD2 -------------------------------------------------------------------------------- /examples/cmake/ublox_example.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Brian R Taylor 3 | * brian.taylor@bolderflight.com 4 | * 5 | * Copyright (c) 2022 Bolder Flight Systems Inc 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the “Software”), to 9 | * deal in the Software without restriction, including without limitation the 10 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 11 | * sell copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 23 | * IN THE SOFTWARE. 24 | */ 25 | 26 | #include "ubx.h" 27 | 28 | /* Ublox object */ 29 | bfs::Ubx gnss; 30 | 31 | int main() { 32 | /* Serial to display data */ 33 | Serial.begin(115200); 34 | while(!Serial) {} 35 | /* GNSS on Serial1 */ 36 | gnss.Config(&Serial1); 37 | if (!gnss.Begin(115200)) { 38 | Serial.println("Failed to establish communication with GNSS RX"); 39 | while (1) {} 40 | } 41 | while (1) { 42 | if(gnss.Read()) { 43 | Serial.print(gnss.fix()); 44 | Serial.print("\t"); 45 | Serial.print(gnss.num_sv()); 46 | Serial.print("\t"); 47 | Serial.print(gnss.lat_deg(), 6); 48 | Serial.print("\t"); 49 | Serial.print(gnss.lon_deg(), 6); 50 | Serial.print("\t"); 51 | Serial.print(gnss.alt_wgs84_m(), 2); 52 | Serial.print("\n"); 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # v3.14 required for FetchContent_MakeAvailable 2 | cmake_minimum_required(VERSION 3.14) 3 | if (DEFINED MCU) 4 | include(FetchContent) 5 | FetchContent_Declare( 6 | mcu_support 7 | GIT_REPOSITORY https://github.com/bolderflight/mcu-support.git 8 | GIT_TAG v1.1.0 9 | ) 10 | FetchContent_MakeAvailable(mcu_support) 11 | # Setting up the toolchain 12 | set(CMAKE_TOOLCHAIN_FILE "${mcu_support_SOURCE_DIR}/cmake/cortex.cmake") 13 | # Project information 14 | project(Ublox 15 | VERSION 6.0.6 16 | DESCRIPTION "uBlox UBX sensor driver" 17 | LANGUAGES CXX 18 | ) 19 | # Grab the processor and set up definitions and compile options 20 | include(${mcu_support_SOURCE_DIR}/cmake/config_mcu.cmake) 21 | configMcu(${MCU} ${mcu_support_SOURCE_DIR}) 22 | # Fetch core 23 | FetchContent_Declare( 24 | core 25 | GIT_REPOSITORY https://github.com/bolderflight/core.git 26 | GIT_TAG v3.1.3 27 | ) 28 | FetchContent_MakeAvailable(core) 29 | # Add the library target 30 | add_library(ubx 31 | src/ubx.cpp 32 | src/ubx.h 33 | src/ubx_defs.h 34 | src/ubx_nav.h 35 | ) 36 | # Link libraries 37 | target_link_libraries(ubx 38 | PUBLIC 39 | core 40 | ) 41 | # Setup include directories 42 | target_include_directories(ubx PUBLIC 43 | $ 44 | $ 45 | ) 46 | 47 | # Example and test if this project is built separately 48 | if (PROJECT_NAME STREQUAL CMAKE_PROJECT_NAME) 49 | # Add the spi example target 50 | add_executable(ublox_example examples/cmake/ublox_example.cc) 51 | # Add the includes 52 | target_include_directories(ublox_example PUBLIC 53 | $ 54 | $ 55 | ) 56 | # Link libraries to the example target 57 | target_link_libraries(ublox_example 58 | PRIVATE 59 | ubx 60 | ) 61 | # Add hex and upload targets 62 | include(${mcu_support_SOURCE_DIR}/cmake/flash_mcu.cmake) 63 | FlashMcu(ublox_example ${MCU} ${mcu_support_SOURCE_DIR}) 64 | endif() 65 | endif() 66 | -------------------------------------------------------------------------------- /src/ubx_defs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Brian R Taylor 3 | * brian.taylor@bolderflight.com 4 | * 5 | * Copyright (c) 2022 Bolder Flight Systems Inc 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the “Software”), to 9 | * deal in the Software without restriction, including without limitation the 10 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 11 | * sell copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 23 | * IN THE SOFTWARE. 24 | */ 25 | 26 | #ifndef SRC_UBX_DEFS_H_ 27 | #define SRC_UBX_DEFS_H_ 28 | 29 | #if !defined(ARDUINO) 30 | #include 31 | #include 32 | #endif 33 | 34 | namespace bfs { 35 | /* 36 | * Aliases for uBlox defined types to make defining packets from the interface 37 | * descriptions easier. 38 | */ 39 | using U1 = uint8_t; 40 | using I1 = int8_t; 41 | using X1 = uint8_t; 42 | using U2 = uint16_t; 43 | using I2 = int16_t; 44 | using X2 = uint16_t; 45 | using U4 = uint32_t; 46 | using I4 = int32_t; 47 | using X4 = uint32_t; 48 | using R4 = float; 49 | using R8 = double; 50 | using CH = char; 51 | /* Classes */ 52 | static constexpr uint8_t UBX_ACK_CLS_ = 0x05; 53 | static constexpr uint8_t UBX_CFG_CLS_ = 0x06; 54 | static constexpr uint8_t UBX_INF_CLS_ = 0x04; 55 | static constexpr uint8_t UBX_LOG_CLS_ = 0x21; 56 | static constexpr uint8_t UBX_MGA_CLS_ = 0x13; 57 | static constexpr uint8_t UBX_MON_CLS_ = 0x0a; 58 | static constexpr uint8_t UBX_NAV_CLS_ = 0x01; 59 | static constexpr uint8_t UBX_RXM_CLS_ = 0x02; 60 | static constexpr uint8_t UBX_SEC_CLS_ = 0x27; 61 | static constexpr uint8_t UBX_TIM_CLS_ = 0x0d; 62 | static constexpr uint8_t UBX_UPD_CLS_ = 0x09; 63 | /* Port definitions */ 64 | static constexpr uint8_t UBX_COM_PORT_I2C_ = 0; 65 | static constexpr uint8_t UBX_COM_PORT_UART1_ = 1; 66 | static constexpr uint8_t UBX_COM_PORT_UART2_ = 2; 67 | static constexpr uint8_t UBX_COM_PORT_USB_ = 3; 68 | static constexpr uint8_t UBX_COM_PORT_SPI_ = 4; 69 | /* Port protocols */ 70 | static constexpr uint8_t UBX_COM_PROT_UBX_ = 0x01; 71 | static constexpr uint8_t UBX_COM_PROT_NMEA_ = 0x02; 72 | static constexpr uint8_t UBX_COM_PROT_RTCM_ = 0x04; 73 | static constexpr uint8_t UBX_COM_PROT_RTCM3_ = 0x08; 74 | 75 | } // namespace bfs 76 | 77 | #endif // SRC_UBX_DEFS_H_ 78 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) 2 | 3 | ![Bolder Flight Systems Logo](img/logo-words_75.png)     ![Arduino Logo](img/arduino_logo_75.png) 4 | 5 | # Ubx 6 | This library communicates with uBlox GNSS receivers using the UBX protocol. This library is compatible with Arduino and CMake build systems. 7 | * [License](LICENSE.md) 8 | * [Changelog](CHANGELOG.md) 9 | * [Contributing guide](CONTRIBUTING.md) 10 | 11 | # Description 12 | uBlox produces standard and high precision GPS receivers. These receivers feature high sensitivity, minimal acquisition times, and small form factors. UBX is a uBlox binary format for efficiently retrieving data from the receiver. 13 | 14 | # Installation 15 | 16 | ## Arduino 17 | Use the Arduino Library Manager to install this library or clone to your Arduino/libraries folder. This library is added as: 18 | 19 | ```C++ 20 | #include "ubx.h" 21 | ``` 22 | 23 | An example Arduino executable is located in: *examples/arduino/ublox_example/ublox_example.ino*. Teensy 3.x, 4.x, and LC devices are used for testing under Arduino and this library should be compatible with other Arduino devices. 24 | 25 | ## CMake 26 | CMake is used to build this library, which is exported as a library target called *ubx*. The header is added as: 27 | 28 | ```C++ 29 | #include "ubx.h" 30 | ``` 31 | 32 | The library can be also be compiled stand-alone using the CMake idiom of creating a *build* directory and then, from within that directory issuing: 33 | 34 | ``` 35 | cmake .. -DMCU=MK66FX1M0 36 | make 37 | ``` 38 | 39 | This will build the library and an example executable called *ublox_example*. The example executable source files are located at *examples/cmake/ublox_example.cc*. Notice that the *cmake* command includes a define specifying the microcontroller the code is being compiled for. This is required to correctly configure the code, CPU frequency, and compile/linker options. The available MCUs are: 40 | * MK20DX128 41 | * MK20DX256 42 | * MK64FX512 43 | * MK66FX1M0 44 | * MKL26Z64 45 | * IMXRT1062_T40 46 | * IMXRT1062_T41 47 | * IMXRT1062_MMOD 48 | 49 | These are known to work with the same packages used in Teensy products. Also switching packages is known to work well, as long as it's only a package change. 50 | 51 | The example target creates an executable for communicating with the GNSS receiver using the UBX protocol. Each target also has a *_hex*, for creating the hex file to upload to the microcontroller, and an *_upload* for using the [Teensy CLI Uploader](https://www.pjrc.com/teensy/loader_cli.html) to flash the Teensy. Instructions for setting up your build environment can be found in our [build-tools repo](https://github.com/bolderflight/build-tools). 52 | 53 | # Namespace 54 | This library is within the namespace *bfs*. 55 | 56 | # Usage 57 | 58 | ## Receiver Setup 59 | This library parses data from the following messages: 60 | * UBX-NAV-DOP 61 | * UBX-NAV-EOE 62 | * UBX-NAV-POSECEF 63 | * UBX-NAV-PVT 64 | * UBX-NAV-VELECEF 65 | * UBX-NAV-TIMEGPS 66 | 67 | These messages should be enabled using the [u-center software](https://www.u-blox.com/en/product/u-center). 68 | 69 | If high accuracy position data is available, the following messages should be enabled and will be used by this library. 70 | * UBX-NAV-HPPOSECEF 71 | * UBX-NAV-HPPOSLLH 72 | 73 | If relative position data is available, such as from a stationary or moving reference, the following message should be enabled and will be used by this library. 74 | * UBX-NAV-RELPOSNED 75 | 76 | Finally, if you are connected to a fixed-baseline and conducting a survey-in, the following message should be enabled and will be used by this library to provide information regarding the survey-in status. 77 | * UBX-NAV-SVIN 78 | 79 | # Ubx 80 | 81 | ## Methods 82 | 83 | **Ubx()** Default constructor, requires calling the Config method to setup the serial port. 84 | 85 | **Ubx(HardwareSerial* bus)** Creates a Ubx object. This constructor is used for the serial communication interface and a pointer to the serial bus object is passed to the constructor. 86 | 87 | ```C++ 88 | bfs::Ubx ubx(&Serial1); 89 | ``` 90 | 91 | **void Config(HardwareSerial* bus)** Sets up the serial port to use for communication. Required if the default constructor is used. 92 | 93 | **bool Begin(const int32_t baud)** Establishes communication with the GNSS receiver. Returns true on successfully receiving data, otherwise, returns false. 94 | 95 | ```C++ 96 | bool status = ubx.Begin(921600); 97 | ``` 98 | 99 | ### Data Collection 100 | The following method reads and parses the serial data. True is returned on receiving a full epoch of new data. 101 | 102 | **bool Read()** Reads and parses data from the serial port. Returns true on receiving the end of epoch frame, which indicates that all data should be updated and available to use. 103 | 104 | ```C++ 105 | if (ubx.Read()) { 106 | // use the GNSS data 107 | } 108 | ``` 109 | 110 | ### Data Retrieval 111 | The most recent valid packet is stored in the Ubx object. Data fields can be retrieved using the following functions. 112 | 113 | #### Common Data 114 | 115 | **Fix fix()** Returns the GNSS fix status. 116 | 117 | | Enum | Description | 118 | | --- | --- | 119 | | FIX_NONE | No fix | 120 | | FIX_2D | 2D fix | 121 | | FIX_3D | 3D fix | 122 | | FIX_DGNSS | 3D fix with differential corrections applied | 123 | | FIX_RTK_FLOAT | 3D fix, RTK corrections with floating ambiguities | 124 | | FIX_RTK_FIXED | 3D fix, RTK corrections with fixed ambiguities | 125 | 126 | **int8_t num_sv()** Number of satellite vehicles used in the navigation solution. 127 | 128 | **int16_t utc_year()** UTC year. 129 | 130 | **int8_t utc_month()** UTC month. 131 | 132 | **int8_t utc_day()** UTC day. 133 | 134 | **int8_t utc_hour()** UTC hour. 135 | 136 | **int8_t utc_min()** UTC minute. 137 | 138 | **int8_t utc_sec()** UTC second. 139 | 140 | **int32_t utc_nano()** UTC nanoseconds. 141 | 142 | **double gps_tow_s()** GPS time of week, s. 143 | 144 | **int16_t week()** GPS week number. 145 | 146 | **int8_t leap_s()** Leap seconds (GPS-UTC). 147 | 148 | **uint32_t time_acc_ns()** Estimated time accuracy, ns. 149 | 150 | **float north_vel_mps()** North velocity, m/s 151 | 152 | **float east_vel_mps()** East velocity, m/s 153 | 154 | **float down_vel_mps()** Down velocity, m/s 155 | 156 | **float gnd_spd_mps()** Ground speed (2D), m/s 157 | 158 | **float ecef_vel_x_mps()** ECEF x velocity, m/s 159 | 160 | **float ecef_vel_y_mps()** ECEF y velocity, m/s 161 | 162 | **float ecef_vel_z_mps()** ECEF z velocity, m/s 163 | 164 | **float spd_acc_mps()** Estimated speed accuracy, m/s 165 | 166 | **float track_deg()** Estimated ground track (2D heading of motion), deg 167 | 168 | **float track_rad()** Estimated ground track (2D heading of motion), rad 169 | 170 | **float track_acc_deg()** Estimated ground track (2D heading of motion) accuracy, deg 171 | 172 | **float track_acc_rad()** Estimated ground track (2D heading of motion) accuracy, rad 173 | 174 | **double lat_deg()** Latitude, deg 175 | 176 | **double lat_rad()** Latitude, rad 177 | 178 | **double lon_deg()** Longitude, deg 179 | 180 | **double lon_rad()** Longitude, rad 181 | 182 | **float alt_wgs84_m()** Altitude above the WGS84 ellipsoid, m 183 | 184 | **float alt_msl_m()** Altitude above Mean Sea Level, m 185 | 186 | **float horz_acc_m()** Estimated horizontal position accuracy, m 187 | 188 | **float vert_acc_m()** Estimated vertical position accuracy, m 189 | 190 | **double ecef_pos_x_m()** ECEF x position, m 191 | 192 | **double ecef_pos_y_m()** ECEF y position, m 193 | 194 | **double ecef_pos_z_m()** ECEF z position, m 195 | 196 | **float ecef_pos_acc_m()** Estimated ECEF position accuracy, m 197 | 198 | **float gdop()** geometric dilution of precision. 199 | 200 | **float pdop()** position dilution of precision. 201 | 202 | **float tdop()** time dilution of precision. 203 | 204 | **float vdop()** vertical dilution of precision. 205 | 206 | **float hdop()** horizontal dilution of precision. 207 | 208 | **float ndop()** northing dilution of precision. 209 | 210 | **float edop()** easting dilution of precision. 211 | 212 | #### Relative Position Data 213 | 214 | **bool rel_pos_avail()** Whether relative position data is available. 215 | 216 | **bool rel_pos_moving_baseline()** Whether the receiver is operating in moving base mode. 217 | 218 | **bool rel_pos_ref_pos_miss()** Whether extrapolated reference position was used to compute moving base solution this epoch. 219 | 220 | **bool rel_pos_ref_obs_miss()** Whether extrapolated reference observations were used to compute moving base solution this epoch. 221 | 222 | **bool rel_pos_heading_valid()** Whether heading of the relative position vector is valid. 223 | 224 | **bool rel_pos_normalized()** Whether the components of the relative position vector 225 | (including the high-precision parts) are normalized. 226 | 227 | **double rel_pos_north_m()** North component of relative position vector, m. 228 | 229 | **double rel_pos_east_m()** East component of relative position vector, m. 230 | 231 | **double rel_pos_down_m()** Down component of relative position vector, m. 232 | 233 | **float rel_pos_acc_north_m()** Accuracy of relative position North component, m. 234 | 235 | **float rel_pos_acc_east_m()** Accuracy of relative position East component, m. 236 | 237 | **float rel_pos_acc_down_m()** Accuracy of relative position Down component, m. 238 | 239 | **double rel_pos_len_m()** Length of the relative position vector, m. 240 | 241 | **float rel_pos_len_acc_m()** Accuracy of length of the relative position vector, m. 242 | 243 | **float rel_pos_heading_deg()** Heading of the relative position vector, deg. 244 | 245 | **float rel_pos_heading_rad()** Heading of the relative position vector, rad. 246 | 247 | **float rel_pos_heading_acc_deg()** Accuracy of the heading of the relative position vector, deg. 248 | 249 | **float rel_pos_heading_acc_rad()** Accuracy of the heading of the relative position vector, rad. 250 | 251 | #### Survey In Data 252 | 253 | **bool svin_valid()** Survey-in position validity flag, true = valid, otherwise false. 254 | 255 | **bool svin_in_progress()** Survey-in in progress flag, true = in-progress, otherwise false. 256 | 257 | **uint32_t svin_dur_s()** Passed survey-in observation time, s. 258 | 259 | **double svin_ecef_pos_x_m()** Current survey-in mean position ECEF X coordinate, m. 260 | 261 | **double svin_ecef_pos_y_m()** Current survey-in mean position ECEF Y coordinate, m. 262 | 263 | **double svin_ecef_pos_z_m()** Current survey-in mean position ECEF Z coordinate, m. 264 | 265 | **float svin_ecef_pos_acc_m()** Current survey-in mean position accuracy, m. 266 | 267 | **uint32_t svin_num_obs()** Number of position observations used during survey-in. 268 | -------------------------------------------------------------------------------- /src/ubx.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Brian R Taylor 3 | * brian.taylor@bolderflight.com 4 | * 5 | * Copyright (c) 2022 Bolder Flight Systems Inc 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the “Software”), to 9 | * deal in the Software without restriction, including without limitation the 10 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 11 | * sell copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 23 | * IN THE SOFTWARE. 24 | */ 25 | 26 | #ifndef UBX_SRC_UBX_H_ // NOLINT 27 | #define UBX_SRC_UBX_H_ 28 | 29 | #if defined(ARDUINO) 30 | #include 31 | #else 32 | #include 33 | #include 34 | #include "core/core.h" 35 | #endif 36 | #include "ubx_defs.h" // NOLINT 37 | #include "ubx_nav.h" // NOLINT 38 | 39 | namespace bfs { 40 | 41 | class Ubx { 42 | public: 43 | enum Fix : int8_t { 44 | FIX_NONE = 1, 45 | FIX_2D = 2, 46 | FIX_3D = 3, 47 | FIX_DGNSS = 4, 48 | FIX_RTK_FLOAT = 5, 49 | FIX_RTK_FIXED = 6 50 | }; 51 | Ubx() {} 52 | explicit Ubx(HardwareSerial* bus) : bus_(bus) {} 53 | void Config(HardwareSerial* bus); 54 | /* Standard begin, set the baud and test for comms */ 55 | bool Begin(const int32_t baud); 56 | /* Reads NAV data and returns true on EOE */ 57 | bool Read(); 58 | /* Data output */ 59 | inline Fix fix() const {return fix_;} 60 | inline int8_t num_sv() const {return num_sv_;} 61 | inline int16_t utc_year() const {return year_;} 62 | inline int8_t utc_month() const {return month_;} 63 | inline int8_t utc_day() const {return day_;} 64 | inline int8_t utc_hour() const {return hour_;} 65 | inline int8_t utc_min() const {return min_;} 66 | inline int8_t utc_sec() const {return sec_;} 67 | inline int32_t utc_nano() const {return nano_;} 68 | inline double gps_tow_s() const {return tow_s_;} 69 | inline int16_t gps_week() const {return week_;} 70 | inline int8_t leap_s() const {return leap_s_;} 71 | inline uint32_t time_acc_ns() const {return t_acc_ns_;} 72 | inline float north_vel_mps() const {return ned_vel_mps_[0];} 73 | inline float east_vel_mps() const {return ned_vel_mps_[1];} 74 | inline float down_vel_mps() const {return ned_vel_mps_[2];} 75 | inline float gnd_spd_mps() const {return gnd_spd_mps_;} 76 | inline float ecef_vel_x_mps() const {return ecef_vel_mps_[0];} 77 | inline float ecef_vel_y_mps() const {return ecef_vel_mps_[1];} 78 | inline float ecef_vel_z_mps() const {return ecef_vel_mps_[2];} 79 | inline float spd_acc_mps() const {return s_acc_mps_;} 80 | inline float track_deg() const {return track_deg_;} 81 | inline float track_rad() const {return track_deg_ * DEG2RADf_;} 82 | inline float track_acc_deg() const {return track_acc_deg_;} 83 | inline float track_acc_rad() const {return track_acc_deg_ * DEG2RADf_;} 84 | inline double lat_deg() const {return llh_[0];} 85 | inline double lat_rad() const {return llh_[0] * DEG2RADl_;} 86 | inline double lon_deg() const {return llh_[1];} 87 | inline double lon_rad() const {return llh_[1] * DEG2RADl_;} 88 | inline float alt_wgs84_m() const {return static_cast(llh_[2]);} 89 | inline float alt_msl_m() const {return alt_msl_m_;} 90 | inline float horz_acc_m() const {return h_acc_m_;} 91 | inline float vert_acc_m() const {return v_acc_m_;} 92 | inline double ecef_pos_x_m() const {return ecef_m_[0];} 93 | inline double ecef_pos_y_m() const {return ecef_m_[1];} 94 | inline double ecef_pos_z_m() const {return ecef_m_[2];} 95 | inline float ecef_pos_acc_m() const {return p_acc_m_;} 96 | inline float gdop() const {return gdop_;} 97 | inline float pdop() const {return pdop_;} 98 | inline float tdop() const {return tdop_;} 99 | inline float vdop() const {return vdop_;} 100 | inline float hdop() const {return hdop_;} 101 | inline float ndop() const {return ndop_;} 102 | inline float edop() const {return edop_;} 103 | /* Relative position data */ 104 | inline bool rel_pos_avail() const {return rel_pos_avail_;} 105 | inline bool rel_pos_moving_baseline() const {return rel_pos_moving_baseline_;} 106 | inline bool rel_pos_ref_pos_miss() const {return rel_pos_ref_pos_miss_;} 107 | inline bool rel_pos_ref_obs_miss() const {return rel_pos_ref_obs_miss_;} 108 | inline bool rel_pos_heading_valid() const {return rel_pos_heading_valid_;} 109 | inline bool rel_pos_normalized() const {return rel_pos_norm_;} 110 | inline double rel_pos_north_m() const {return rel_pos_ned_m_[0];} 111 | inline double rel_pos_east_m() const {return rel_pos_ned_m_[1];} 112 | inline double rel_pos_down_m() const {return rel_pos_ned_m_[2];} 113 | inline float rel_pos_acc_north_m() const {return rel_pos_ned_acc_m_[0];} 114 | inline float rel_pos_acc_east_m() const {return rel_pos_ned_acc_m_[1];} 115 | inline float rel_pos_acc_down_m() const {return rel_pos_ned_acc_m_[2];} 116 | inline double rel_pos_len_m() const {return rel_pos_len_m_;} 117 | inline float rel_pos_len_acc_m() const {return rel_pos_len_acc_m_;} 118 | inline float rel_pos_heading_deg() const {return rel_pos_heading_deg_;} 119 | inline float rel_pos_heading_acc_deg() const { 120 | return rel_pos_heading_acc_deg_; 121 | } 122 | inline float rel_pos_heading_rad() const { 123 | return rel_pos_heading_deg_ * DEG2RADf_; 124 | } 125 | inline float rel_pos_heading_acc_rad() const { 126 | return rel_pos_heading_acc_deg_ * DEG2RADf_; 127 | } 128 | /* Survey-in data */ 129 | inline bool svin_valid() const {return svin_valid_;} 130 | inline bool svin_in_progress() const {return svin_in_progress_;} 131 | inline uint32_t svin_dur_s() const {return svin_dur_s_;} 132 | inline double svin_ecef_pos_x_m() const {return svin_ecef_m_[0];} 133 | inline double svin_ecef_pos_y_m() const {return svin_ecef_m_[1];} 134 | inline double svin_ecef_pos_z_m() const {return svin_ecef_m_[2];} 135 | inline float svin_ecef_pos_acc_m() const {return svin_acc_m_;} 136 | inline uint32_t svin_num_obs() const {return svin_num_obs_;} 137 | 138 | private: 139 | /* Parse messages, return true on valid msg received */ 140 | bool ParseMsg(); 141 | /* Process nav data */ 142 | void ProcessNavData(); 143 | /* Communication */ 144 | HardwareSerial* bus_; 145 | int16_t comm_timeout_count_ = 0; 146 | static const int16_t COMM_TIMEOUT_TRIES_ = 1000; 147 | static const int16_t COMM_TIMEOUT_DELAY_MS_ = 10; 148 | /* Max payload bytes supported */ 149 | static constexpr size_t UBX_MAX_PAYLOAD_ = 128; 150 | /* Parsing */ 151 | static constexpr uint8_t UBX_HEADER_[2] = {0xB5, 0x62}; 152 | static constexpr uint8_t UBX_CLS_POS_ = 2; 153 | static constexpr uint8_t UBX_ID_POS_ = 3; 154 | static constexpr uint8_t UBX_LEN_POS_LSB_ = 4; 155 | static constexpr uint8_t UBX_LEN_POS_MSB_ = 5; 156 | static constexpr uint8_t UBX_HEADER_LEN_ = 6; 157 | static constexpr uint8_t UBX_CHK_OFFSET_ = UBX_HEADER_LEN_ - 158 | sizeof(UBX_HEADER_); 159 | uint8_t c_, len_, chk_rx_, chk_[2]; 160 | uint16_t chk_cmp_rx_, chk_cmp_tx_; 161 | size_t parser_state_ = 0; 162 | static constexpr float DEG2RADf_ = 3.14159265358979323846264338327950288f / 163 | 180.0f; 164 | static constexpr double DEG2RADl_ = 3.14159265358979323846264338327950288 / 165 | 180.0; 166 | /* Data members */ 167 | bool eoe_ = false; 168 | bool use_hp_pos_ = false; 169 | bool svin_data_ = false; 170 | bool rel_pos_data_ = false; 171 | Fix fix_; 172 | bool gnss_fix_ok_, diff_soln_; 173 | bool valid_date_, valid_time_, fully_resolved_, validity_confirmed_; 174 | bool tow_valid_, week_valid_, leap_valid_; 175 | bool confirmed_date_, confirmed_time_, valid_time_and_date_; 176 | bool invalid_llh_, invalid_ecef_; 177 | bool rel_pos_avail_ = false; 178 | bool rel_pos_moving_baseline_ = false; 179 | bool rel_pos_ref_pos_miss_ = false; 180 | bool rel_pos_ref_obs_miss_ = false; 181 | bool rel_pos_heading_valid_ = false; 182 | bool rel_pos_norm_ = false; 183 | bool svin_valid_ = false; 184 | bool svin_in_progress_ = false; 185 | int8_t carr_soln_; 186 | int8_t num_sv_; 187 | int8_t month_, day_, hour_, min_, sec_; 188 | int8_t leap_s_; 189 | int16_t year_; 190 | int16_t week_; 191 | int32_t nano_; 192 | uint32_t t_acc_ns_; 193 | uint32_t svin_dur_s_, svin_num_obs_; 194 | float alt_msl_m_; 195 | float gnd_spd_mps_; 196 | float track_deg_; 197 | float gdop_, pdop_, tdop_, vdop_, hdop_, ndop_, edop_; 198 | float h_acc_m_, v_acc_m_, p_acc_m_, track_acc_deg_, s_acc_mps_; 199 | float rel_pos_heading_deg_; 200 | float rel_pos_heading_acc_deg_; 201 | float rel_pos_len_acc_m_; 202 | float svin_acc_m_; 203 | double rel_pos_len_m_; 204 | double tow_s_; 205 | float ecef_vel_mps_[3]; 206 | float ned_vel_mps_[3]; 207 | float rel_pos_ned_acc_m_[3]; 208 | double ecef_m_[3]; 209 | double llh_[3]; 210 | double rel_pos_ned_m_[3]; 211 | double svin_ecef_m_[3]; 212 | /* Class to compute UBX checksum */ 213 | class Checksum { 214 | public: 215 | uint16_t Compute(uint8_t const * const data, const size_t len) { 216 | if (!data) { 217 | return 0; 218 | } 219 | sum0_ = 0; 220 | sum1_ = 0; 221 | for (size_t i = 0; i < len; i++) { 222 | sum0_ += data[i]; 223 | sum1_ += sum0_; 224 | } 225 | return static_cast(sum1_) << 8 | sum0_; 226 | } 227 | uint16_t Update(uint8_t const * const data, const size_t len) { 228 | if (!data) { 229 | return 0; 230 | } 231 | for (size_t i = 0; i < len; i++) { 232 | sum0_ += data[i]; 233 | sum1_ += sum0_; 234 | } 235 | return static_cast(sum1_) << 8 | sum0_; 236 | } 237 | 238 | private: 239 | uint8_t sum0_, sum1_; 240 | } chksum_rx_, chksum_tx_; 241 | /* Struct for unkown messages */ 242 | struct UbxMsg { 243 | uint8_t cls; 244 | uint8_t id; 245 | uint16_t len; 246 | uint8_t payload[UBX_MAX_PAYLOAD_]; 247 | } rx_msg_; 248 | /* Data messages */ 249 | UbxNavDop ubx_nav_dop_; 250 | UbxNavEoe ubx_nav_eoe_; 251 | UbxNavHpposecef ubx_nav_hp_pos_ecef_; 252 | UbxNavHpposllh ubx_nav_hp_pos_llh_; 253 | UbxNavPosecef ubx_nav_pos_ecef_; 254 | UbxNavRelposned ubx_nav_rel_pos_ned_; 255 | UbxNavVelecef ubx_nav_vel_ecef_; 256 | UbxNavPvt ubx_nav_pvt_; 257 | UbxNavTimegps ubx_nav_time_gps_; 258 | UbxNavSvin ubx_nav_svin_; 259 | }; 260 | 261 | } // namespace bfs 262 | 263 | #endif // UBX_SRC_UBX_H_ NOLINT 264 | -------------------------------------------------------------------------------- /src/ubx.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Brian R Taylor 3 | * brian.taylor@bolderflight.com 4 | * 5 | * Copyright (c) 2022 Bolder Flight Systems Inc 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the “Software”), to 9 | * deal in the Software without restriction, including without limitation the 10 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 11 | * sell copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 23 | * IN THE SOFTWARE. 24 | */ 25 | 26 | #if defined(ARDUINO) 27 | #include 28 | #else 29 | #include 30 | #include 31 | #include "core/core.h" 32 | #endif 33 | #include "ubx.h" 34 | #include "ubx_defs.h" // NOLINT 35 | #include "ubx_nav.h" // NOLINT 36 | 37 | namespace bfs { 38 | 39 | constexpr uint8_t Ubx::UBX_HEADER_[]; 40 | void Ubx::Config(HardwareSerial* bus) { 41 | bus_ = bus; 42 | } 43 | bool Ubx::Begin(int32_t baud) { 44 | bus_->begin(baud); 45 | bus_->flush(); 46 | while (comm_timeout_count_++ < COMM_TIMEOUT_TRIES_) { 47 | if (ParseMsg()) { 48 | return true; 49 | } 50 | delay(COMM_TIMEOUT_DELAY_MS_); 51 | } 52 | return false; 53 | } 54 | bool Ubx::Read() { 55 | while (bus_->available()) { 56 | if (ParseMsg()) { 57 | if (rx_msg_.cls == UBX_NAV_CLS_) { 58 | switch (rx_msg_.id) { 59 | case UBX_NAV_POSECEF_ID_: { 60 | if (rx_msg_.len == ubx_nav_pos_ecef_.len) { 61 | memcpy(&ubx_nav_pos_ecef_.payload, rx_msg_.payload, rx_msg_.len); 62 | } 63 | break; 64 | } 65 | case UBX_NAV_PVT_ID_: { 66 | if (rx_msg_.len == ubx_nav_pvt_.len) { 67 | memcpy(&ubx_nav_pvt_.payload, rx_msg_.payload, rx_msg_.len); 68 | } 69 | break; 70 | } 71 | case UBX_NAV_DOP_ID_: { 72 | if (rx_msg_.len == ubx_nav_dop_.len) { 73 | memcpy(&ubx_nav_dop_.payload, rx_msg_.payload, rx_msg_.len); 74 | } 75 | break; 76 | } 77 | case UBX_NAV_VELECEF_ID_: { 78 | if (rx_msg_.len == ubx_nav_vel_ecef_.len) { 79 | memcpy(&ubx_nav_vel_ecef_.payload, rx_msg_.payload, rx_msg_.len); 80 | } 81 | break; 82 | } 83 | case UBX_NAV_HPPOSECEF_ID_: { 84 | if (rx_msg_.len == ubx_nav_hp_pos_ecef_.len) { 85 | memcpy(&ubx_nav_hp_pos_ecef_.payload, rx_msg_.payload, 86 | rx_msg_.len); 87 | use_hp_pos_ = true; 88 | } 89 | break; 90 | } 91 | case UBX_NAV_HPPOSLLH_ID_: { 92 | if (rx_msg_.len == ubx_nav_hp_pos_llh_.len) { 93 | memcpy(&ubx_nav_hp_pos_llh_.payload, rx_msg_.payload, 94 | rx_msg_.len); 95 | use_hp_pos_ = true; 96 | } 97 | break; 98 | } 99 | case UBX_NAV_TIMEGPS_ID_: { 100 | if (rx_msg_.len == ubx_nav_time_gps_.len) { 101 | memcpy(&ubx_nav_time_gps_.payload, rx_msg_.payload, rx_msg_.len); 102 | } 103 | break; 104 | } 105 | case UBX_NAV_SVIN_ID_: { 106 | if (rx_msg_.len == ubx_nav_svin_.len) { 107 | memcpy(&ubx_nav_svin_.payload, rx_msg_.payload, rx_msg_.len); 108 | svin_data_ = true; 109 | } 110 | break; 111 | } 112 | case UBX_NAV_RELPOSNED_ID_: { 113 | if (rx_msg_.len == ubx_nav_rel_pos_ned_.len) { 114 | memcpy(&ubx_nav_rel_pos_ned_.payload, rx_msg_.payload, 115 | rx_msg_.len); 116 | rel_pos_data_ = true; 117 | } 118 | break; 119 | } 120 | case UBX_NAV_EOE_ID_: { 121 | if (rx_msg_.len == ubx_nav_eoe_.len) { 122 | memcpy(&ubx_nav_eoe_.payload, rx_msg_.payload, rx_msg_.len); 123 | eoe_ = true; 124 | } 125 | break; 126 | } 127 | default: { 128 | break; 129 | } 130 | } 131 | } 132 | } 133 | } 134 | if (eoe_) { 135 | eoe_ = false; 136 | ProcessNavData(); 137 | return true; 138 | } 139 | return false; 140 | } 141 | void Ubx::ProcessNavData() { 142 | /* Fix */ 143 | gnss_fix_ok_ = ubx_nav_pvt_.payload.flags & 0x01; 144 | diff_soln_ = ubx_nav_pvt_.payload.flags & 0x02; 145 | carr_soln_ = ubx_nav_pvt_.payload.flags >> 6; 146 | if (gnss_fix_ok_) { 147 | switch (ubx_nav_pvt_.payload.fix_type) { 148 | case 2: { 149 | fix_ = FIX_2D; 150 | break; 151 | } 152 | case 3: { 153 | fix_ = FIX_3D; 154 | if (diff_soln_) { 155 | fix_ = FIX_DGNSS; 156 | } 157 | if (carr_soln_ == 1) { 158 | fix_ = FIX_RTK_FLOAT; 159 | } 160 | if (carr_soln_ == 2) { 161 | fix_ = FIX_RTK_FIXED; 162 | } 163 | break; 164 | } 165 | default: { 166 | fix_ = FIX_NONE; 167 | break; 168 | } 169 | } 170 | } else { 171 | fix_ = FIX_NONE; 172 | } 173 | /* Number of satellites */ 174 | num_sv_ = ubx_nav_pvt_.payload.num_sv; 175 | /* Date and time */ 176 | valid_date_ = ubx_nav_pvt_.payload.valid & 0x01; 177 | valid_time_ = ubx_nav_pvt_.payload.valid & 0x02; 178 | fully_resolved_ = ubx_nav_pvt_.payload.valid & 0x04; 179 | validity_confirmed_ = ubx_nav_pvt_.payload.flags2 & 0x20; 180 | confirmed_date_ = ubx_nav_pvt_.payload.flags2 & 0x40; 181 | confirmed_time_ = ubx_nav_pvt_.payload.flags2 & 0x80; 182 | valid_time_and_date_ = valid_date_ && valid_time_ && fully_resolved_ && 183 | validity_confirmed_ && confirmed_date_ && 184 | confirmed_time_; 185 | if (valid_time_and_date_) { 186 | year_ = ubx_nav_pvt_.payload.year; 187 | month_ = ubx_nav_pvt_.payload.month; 188 | day_ = ubx_nav_pvt_.payload.day; 189 | hour_ = ubx_nav_pvt_.payload.hour; 190 | min_ = ubx_nav_pvt_.payload.min; 191 | sec_ = ubx_nav_pvt_.payload.sec; 192 | nano_ = ubx_nav_pvt_.payload.nano; 193 | } else { 194 | year_ = 0; 195 | month_ = 0; 196 | day_ = 0; 197 | hour_ = 0; 198 | min_ = 0; 199 | sec_ = 0; 200 | nano_ = 0; 201 | } 202 | t_acc_ns_ = ubx_nav_pvt_.payload.t_acc; 203 | /* GPS time */ 204 | tow_valid_ = ubx_nav_time_gps_.payload.valid & 0x01; 205 | week_valid_ = ubx_nav_time_gps_.payload.valid & 0x02; 206 | leap_valid_ = ubx_nav_time_gps_.payload.valid & 0x04; 207 | if (tow_valid_) { 208 | tow_s_ = static_cast(ubx_nav_time_gps_.payload.i_tow) * 1e-3 + 209 | static_cast(ubx_nav_time_gps_.payload.f_tow) * 1e-9; 210 | } else { 211 | tow_s_ = 0; 212 | } 213 | if (week_valid_) { 214 | week_ = ubx_nav_time_gps_.payload.week; 215 | } else { 216 | week_ = 0; 217 | } 218 | if (leap_valid_) { 219 | leap_s_ = ubx_nav_time_gps_.payload.leap_s; 220 | } else { 221 | leap_s_ = 0; 222 | } 223 | /* DOP */ 224 | gdop_ = static_cast(ubx_nav_dop_.payload.g_dop) * 0.01f; 225 | pdop_ = static_cast(ubx_nav_dop_.payload.p_dop) * 0.01f; 226 | tdop_ = static_cast(ubx_nav_dop_.payload.t_dop) * 0.01f; 227 | vdop_ = static_cast(ubx_nav_dop_.payload.v_dop) * 0.01f; 228 | hdop_ = static_cast(ubx_nav_dop_.payload.h_dop) * 0.01f; 229 | ndop_ = static_cast(ubx_nav_dop_.payload.n_dop) * 0.01f; 230 | edop_ = static_cast(ubx_nav_dop_.payload.e_dop) * 0.01f; 231 | /* NED velocity */ 232 | ned_vel_mps_[0] = static_cast(ubx_nav_pvt_.payload.vel_n) / 1000.0f; 233 | ned_vel_mps_[1] = static_cast(ubx_nav_pvt_.payload.vel_e) / 1000.0f; 234 | ned_vel_mps_[2] = static_cast(ubx_nav_pvt_.payload.vel_d) / 1000.0f; 235 | s_acc_mps_ = static_cast(ubx_nav_pvt_.payload.s_acc) / 1000.0f; 236 | /* ECEF velocity */ 237 | ecef_vel_mps_[0] = static_cast(ubx_nav_vel_ecef_.payload.ecef_v_x) / 238 | 100.0f; 239 | ecef_vel_mps_[1] = static_cast(ubx_nav_vel_ecef_.payload.ecef_v_y) / 240 | 100.0f; 241 | ecef_vel_mps_[2] = static_cast(ubx_nav_vel_ecef_.payload.ecef_v_z) / 242 | 100.0f; 243 | /* Ground track and speed */ 244 | gnd_spd_mps_ = static_cast(ubx_nav_pvt_.payload.g_speed) / 1000.0f; 245 | track_deg_ = static_cast(ubx_nav_pvt_.payload.head_mot) / 100000.0f; 246 | track_acc_deg_ = static_cast(ubx_nav_pvt_.payload.head_acc) / 247 | 100000.0f; 248 | /* LLH position */ 249 | invalid_llh_ = ubx_nav_pvt_.payload.flags3 & 0x01; 250 | if (!invalid_llh_) { 251 | if (use_hp_pos_) { 252 | llh_[0] = (static_cast(ubx_nav_hp_pos_llh_.payload.lat) + 253 | static_cast(ubx_nav_hp_pos_llh_.payload.lat_hp) * 254 | 1e-2) * 1e-7; 255 | llh_[1] = (static_cast(ubx_nav_hp_pos_llh_.payload.lon) + 256 | static_cast(ubx_nav_hp_pos_llh_.payload.lon_hp) * 257 | 1e-2) * 1e-7; 258 | llh_[2] = (static_cast(ubx_nav_hp_pos_llh_.payload.height) + 259 | static_cast(ubx_nav_hp_pos_llh_.payload.height_hp) * 260 | 0.1) * 1e-3; 261 | alt_msl_m_ = (static_cast(ubx_nav_hp_pos_llh_.payload.h_msl) + 262 | static_cast(ubx_nav_hp_pos_llh_.payload.h_msl_hp) * 263 | 0.1f) / 1000.0f; 264 | h_acc_m_ = static_cast(ubx_nav_hp_pos_llh_.payload.h_acc) / 265 | 10000.0f; 266 | v_acc_m_ = static_cast(ubx_nav_hp_pos_llh_.payload.v_acc) / 267 | 10000.0f; 268 | } else { 269 | llh_[0] = static_cast(ubx_nav_pvt_.payload.lat) * 1e-7; 270 | llh_[1] = static_cast(ubx_nav_pvt_.payload.lon) * 1e-7; 271 | llh_[2] = static_cast(ubx_nav_pvt_.payload.height) * 1e-3; 272 | alt_msl_m_ = static_cast(ubx_nav_pvt_.payload.h_msl) / 1000.0f; 273 | h_acc_m_ = static_cast(ubx_nav_pvt_.payload.h_acc) / 1000.0f; 274 | v_acc_m_ = static_cast(ubx_nav_pvt_.payload.v_acc) / 1000.0f; 275 | } 276 | } 277 | /* ECEF position */ 278 | invalid_ecef_ = ubx_nav_hp_pos_ecef_.payload.flags & 0x01; 279 | if (!invalid_ecef_) { 280 | if (use_hp_pos_) { 281 | ecef_m_[0] = (static_cast(ubx_nav_hp_pos_ecef_.payload.ecef_x) + 282 | static_cast(ubx_nav_hp_pos_ecef_.payload.ecef_x_hp) 283 | * 1e-2) * 1e-2; 284 | ecef_m_[1] = (static_cast(ubx_nav_hp_pos_ecef_.payload.ecef_y) + 285 | static_cast(ubx_nav_hp_pos_ecef_.payload.ecef_y_hp) 286 | * 1e-2) * 1e-2; 287 | ecef_m_[2] = (static_cast(ubx_nav_hp_pos_ecef_.payload.ecef_z) + 288 | static_cast(ubx_nav_hp_pos_ecef_.payload.ecef_z_hp) 289 | * 1e-2) * 1e-2; 290 | p_acc_m_ = static_cast(ubx_nav_hp_pos_ecef_.payload.p_acc) / 291 | 10000.0f; 292 | } else { 293 | ecef_m_[0] = static_cast(ubx_nav_pos_ecef_.payload.ecef_x) * 1e-2; 294 | ecef_m_[1] = static_cast(ubx_nav_pos_ecef_.payload.ecef_y) * 1e-2; 295 | ecef_m_[2] = static_cast(ubx_nav_pos_ecef_.payload.ecef_z) * 1e-2; 296 | p_acc_m_ = static_cast(ubx_nav_pos_ecef_.payload.p_acc) / 100.0f; 297 | } 298 | } 299 | /* Relative position */ 300 | if (rel_pos_data_) { 301 | rel_pos_avail_ = ubx_nav_rel_pos_ned_.payload.flags & 0x04; 302 | rel_pos_moving_baseline_ = ubx_nav_rel_pos_ned_.payload.flags & 0x20; 303 | rel_pos_ref_pos_miss_ = ubx_nav_rel_pos_ned_.payload.flags & 0x40; 304 | rel_pos_ref_obs_miss_ = ubx_nav_rel_pos_ned_.payload.flags & 0x80; 305 | rel_pos_heading_valid_ = ubx_nav_rel_pos_ned_.payload.flags & 0x100; 306 | rel_pos_norm_ = ubx_nav_rel_pos_ned_.payload.flags & 0x200; 307 | if (rel_pos_avail_) { 308 | rel_pos_ned_m_[0] = 309 | (static_cast(ubx_nav_rel_pos_ned_.payload.rel_pos_n) + 310 | static_cast(ubx_nav_rel_pos_ned_.payload.rel_pos_hp_n) * 1e-2) * 311 | 1e-2; 312 | rel_pos_ned_m_[1] = 313 | (static_cast(ubx_nav_rel_pos_ned_.payload.rel_pos_e) + 314 | static_cast(ubx_nav_rel_pos_ned_.payload.rel_pos_hp_e) * 1e-2) * 315 | 1e-2; 316 | rel_pos_ned_m_[2] = 317 | (static_cast(ubx_nav_rel_pos_ned_.payload.rel_pos_d) + 318 | static_cast(ubx_nav_rel_pos_ned_.payload.rel_pos_hp_d) * 1e-2) * 319 | 1e-2; 320 | rel_pos_len_m_ = 321 | (static_cast(ubx_nav_rel_pos_ned_.payload.rel_pos_length) + 322 | static_cast(ubx_nav_rel_pos_ned_.payload.rel_pos_hp_length) * 323 | 1e-2) * 1e-2; 324 | rel_pos_heading_deg_ = 325 | static_cast(ubx_nav_rel_pos_ned_.payload.rel_pos_heading) / 326 | 100000.0f; 327 | rel_pos_ned_acc_m_[0] = 328 | static_cast(ubx_nav_rel_pos_ned_.payload.acc_n) / 10000.0f; 329 | rel_pos_ned_acc_m_[1] = 330 | static_cast(ubx_nav_rel_pos_ned_.payload.acc_e) / 10000.0f; 331 | rel_pos_ned_acc_m_[2] = 332 | static_cast(ubx_nav_rel_pos_ned_.payload.acc_d) / 10000.0f; 333 | rel_pos_len_acc_m_ = 334 | static_cast(ubx_nav_rel_pos_ned_.payload.acc_length) / 10000.0f; 335 | rel_pos_heading_acc_deg_ = 336 | static_cast(ubx_nav_rel_pos_ned_.payload.acc_heading) / 337 | 100000.0f; 338 | } 339 | } 340 | /* Survey in data */ 341 | if (svin_data_) { 342 | svin_dur_s_ = ubx_nav_svin_.payload.dur; 343 | svin_ecef_m_[0] = (static_cast(ubx_nav_svin_.payload.mean_x) + 344 | static_cast(ubx_nav_svin_.payload.mean_x_hp) 345 | * 1e-2) * 1e-2; 346 | svin_ecef_m_[1] = (static_cast(ubx_nav_svin_.payload.mean_y) + 347 | static_cast(ubx_nav_svin_.payload.mean_y_hp) 348 | * 1e-2) * 1e-2; 349 | svin_ecef_m_[2] = (static_cast(ubx_nav_svin_.payload.mean_z) + 350 | static_cast(ubx_nav_svin_.payload.mean_z_hp) 351 | * 1e-2) * 1e-2; 352 | svin_acc_m_ = static_cast(ubx_nav_svin_.payload.mean_acc) / 353 | 10000.0f; 354 | svin_valid_ = ubx_nav_svin_.payload.valid; 355 | svin_in_progress_ = ubx_nav_svin_.payload.active; 356 | svin_num_obs_ = ubx_nav_svin_.payload.obs; 357 | } 358 | } 359 | bool Ubx::ParseMsg() { 360 | while (bus_->available()) { 361 | c_ = bus_->read(); 362 | /* Packet header */ 363 | if (parser_state_ < sizeof(UBX_HEADER_)) { 364 | if (c_ == UBX_HEADER_[parser_state_]) { 365 | parser_state_++; 366 | } else { 367 | parser_state_ = 0; 368 | } 369 | /* Class */ 370 | } else if (parser_state_ == UBX_CLS_POS_) { 371 | rx_msg_.cls = c_; 372 | parser_state_++; 373 | /* ID */ 374 | } else if (parser_state_ == UBX_ID_POS_) { 375 | rx_msg_.id = c_; 376 | parser_state_++; 377 | /* Length */ 378 | } else if (parser_state_ == UBX_LEN_POS_LSB_) { 379 | len_ = c_; 380 | parser_state_++; 381 | } else if (parser_state_ == UBX_LEN_POS_MSB_) { 382 | rx_msg_.len = static_cast(c_) << 8 | len_; 383 | parser_state_++; 384 | /* Prevent buffer overflow */ 385 | if (rx_msg_.len > UBX_MAX_PAYLOAD_) { 386 | parser_state_ = 0; 387 | } 388 | /* Payload */ 389 | } else if (parser_state_ < (rx_msg_.len + UBX_HEADER_LEN_)) { 390 | rx_msg_.payload[parser_state_ - UBX_HEADER_LEN_] = c_; 391 | parser_state_++; 392 | /* Checksum */ 393 | } else if (parser_state_ == (rx_msg_.len + UBX_HEADER_LEN_)) { 394 | chk_rx_ = c_; 395 | parser_state_++; 396 | } else { 397 | chk_cmp_rx_ = 398 | chksum_rx_.Compute(reinterpret_cast(&rx_msg_), 399 | rx_msg_.len + UBX_CHK_OFFSET_); 400 | parser_state_ = 0; 401 | /* Check the computed & received checksums */ 402 | if (chk_cmp_rx_ == (static_cast(c_) << 8 | chk_rx_)) { 403 | /* Valid message */ 404 | return true; 405 | } 406 | } 407 | } 408 | return false; 409 | } 410 | 411 | } // namespace bfs 412 | -------------------------------------------------------------------------------- /src/ubx_nav.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Brian R Taylor 3 | * brian.taylor@bolderflight.com 4 | * 5 | * Copyright (c) 2022 Bolder Flight Systems Inc 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the “Software”), to 9 | * deal in the Software without restriction, including without limitation the 10 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 11 | * sell copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 23 | * IN THE SOFTWARE. 24 | */ 25 | 26 | #ifndef SRC_UBX_NAV_H_ 27 | #define SRC_UBX_NAV_H_ 28 | 29 | #if !defined(ARDUINO) 30 | #include 31 | #include 32 | #endif 33 | #include "ubx_defs.h" // NOLINT 34 | 35 | namespace bfs { 36 | /* 37 | * Defs for UBX-NAV messages 38 | */ 39 | /* UBX-NAV IDs */ 40 | static constexpr uint8_t UBX_NAV_CLOCK_ID_ = 0x22; 41 | static constexpr uint8_t UBX_NAV_DOP_ID_ = 0x04; 42 | static constexpr uint8_t UBX_NAV_EOE_ID_ = 0x61; 43 | static constexpr uint8_t UBX_NAV_GEOFENCE_ID_ = 0x39; 44 | static constexpr uint8_t UBX_NAV_HPPOSECEF_ID_ = 0x13; 45 | static constexpr uint8_t UBX_NAV_HPPOSLLH_ID_ = 0x14; 46 | static constexpr uint8_t UBX_NAV_ODO_ID_ = 0x09; 47 | static constexpr uint8_t UBX_NAV_ORB_ID_ = 0x34; 48 | static constexpr uint8_t UBX_NAV_POSECEF_ID_ = 0x01; 49 | static constexpr uint8_t UBX_NAV_POSLLH_ID_ = 0x02; 50 | static constexpr uint8_t UBX_NAV_PVT_ID_ = 0x07; 51 | static constexpr uint8_t UBX_NAV_RELPOSNED_ID_ = 0x3c; 52 | static constexpr uint8_t UBX_NAV_RESETODO_ID_ = 0x10; 53 | static constexpr uint8_t UBX_NAV_SAT_ID_ = 0x35; 54 | static constexpr uint8_t UBX_NAV_SBAS_ID_ = 0x32; 55 | static constexpr uint8_t UBX_NAV_SIG_ID_ = 0x43; 56 | static constexpr uint8_t UBX_NAV_SLAS_ID_ = 0x42; 57 | static constexpr uint8_t UBX_NAV_STATUS_ID_ = 0x03; 58 | static constexpr uint8_t UBX_NAV_SVIN_ID_ = 0x3b; 59 | static constexpr uint8_t UBX_NAV_TIMEBDS_ID_ = 0x24; 60 | static constexpr uint8_t UBX_NAV_TIMEGAL_ID_ = 0x25; 61 | static constexpr uint8_t UBX_NAV_TIMEGLO_ID_ = 0x23; 62 | static constexpr uint8_t UBX_NAV_TIMEGPS_ID_ = 0x20; 63 | static constexpr uint8_t UBX_NAV_TIMELS_ID_ = 0x26; 64 | static constexpr uint8_t UBX_NAV_TIMEQZSS_ID_ = 0x27; 65 | static constexpr uint8_t UBX_NAV_TIMEUTC_ID_ = 0x21; 66 | static constexpr uint8_t UBX_NAV_VELECEF_ID_ = 0x11; 67 | static constexpr uint8_t UBX_NAV_VELNED_ID_ = 0x12; 68 | /* UBX-NAV messages */ 69 | struct UbxNavClock { 70 | static constexpr uint8_t cls = UBX_NAV_CLS_; 71 | static constexpr uint8_t id = UBX_NAV_CLOCK_ID_; 72 | static constexpr uint16_t len = 20; 73 | struct { 74 | U4 i_tow; // GPS time of week, ms 75 | I4 clk_b; // Clock bias, ns 76 | I4 clk_d; // Clock drift, ns/s 77 | U4 t_acc; // Time accuracy estimate, ns 78 | U4 f_acc; // Frequency accuracy estimate, ps/s 79 | } payload; 80 | }; 81 | struct UbxNavDop { 82 | static constexpr uint8_t cls = UBX_NAV_CLS_; 83 | static constexpr uint8_t id = UBX_NAV_DOP_ID_; 84 | static constexpr uint16_t len = 18; 85 | struct { 86 | U4 i_tow; // GPS time of week, ms 87 | U2 g_dop; // Geometric DOP, scale 0.01 88 | U2 p_dop; // Position DOP, scale 0.01 89 | U2 t_dop; // Time DOP, scale 0.01 90 | U2 v_dop; // Vertical DOP, scale 0.01 91 | U2 h_dop; // Horizontal DOP, scale 0.01 92 | U2 n_dop; // Northing DOP, scale 0.01 93 | U2 e_dop; // Easting DOP, scale 0.01 94 | } payload; 95 | }; 96 | struct UbxNavEoe { 97 | static constexpr uint8_t cls = UBX_NAV_CLS_; 98 | static constexpr uint8_t id = UBX_NAV_EOE_ID_; 99 | static constexpr uint16_t len = 4; 100 | struct { 101 | U4 i_tow; // GPS time of week, ms 102 | } payload; 103 | }; 104 | template // templated by the maximum number of fences 105 | struct UbxNavGeofence { 106 | static constexpr uint8_t cls = UBX_NAV_CLS_; 107 | static constexpr uint8_t id = UBX_NAV_GEOFENCE_ID_; 108 | uint16_t len; 109 | struct { 110 | U4 i_tow; // GPS time of week, ms 111 | U1 version; // Message version 112 | U1 status; // Geofencing status 113 | U1 num_fences; // Number of geofences 114 | U1 comb_state; // Combined (logical OR) state of all geofences 115 | struct { 116 | U1 state; // Geofence state 117 | U1 id; // Geofence ID 118 | } fence[N]; // Repeated group (num_fences times) 119 | } payload; 120 | }; 121 | struct UbxNavHpposecef { 122 | static constexpr uint8_t cls = UBX_NAV_CLS_; 123 | static constexpr uint8_t id = UBX_NAV_HPPOSECEF_ID_; 124 | static constexpr uint16_t len = 28; 125 | struct { 126 | U1 version; // Message version 127 | U1 reserved0[3]; 128 | U4 i_tow; // GPS time of week, ms 129 | I4 ecef_x; // ECEF x coordinate, cm 130 | I4 ecef_y; // ECEF y coordinate, cm 131 | I4 ecef_z; // ECEF z coordinate, cm 132 | I1 ecef_x_hp; // High precision component of ECEF x, mm, scale 0.1 133 | I1 ecef_y_hp; // High precision component of ECEF y, mm, scale 0.1 134 | I1 ecef_z_hp; // High precision component of ECEF z, mm, scale 0.1 135 | X1 flags; // Flags 136 | U4 p_acc; // Position accuracy estimate, mm, scale 0.1 137 | } payload; 138 | }; 139 | struct UbxNavHpposllh { 140 | static constexpr uint8_t cls = UBX_NAV_CLS_; 141 | static constexpr uint8_t id = UBX_NAV_HPPOSLLH_ID_; 142 | static constexpr uint16_t len = 36; 143 | struct { 144 | U1 version; // Message version 145 | U1 reserved0[2]; 146 | X1 flags; // Flags 147 | U4 i_tow; // GPS time of week, ms 148 | I4 lon; // Longitude, deg, scale 1e-7 149 | I4 lat; // Latitude, deg, scale 1e-7 150 | I4 height; // Height above ellipsoid, mm 151 | I4 h_msl; // Height above MSL, mm 152 | I1 lon_hp; // High precision component of lon, deg, scale 1e-9 153 | I1 lat_hp; // High precision component of lat, deg, scale 1e-9 154 | I1 height_hp; // High precision component of height, mm, scale 0.1 155 | I1 h_msl_hp; // High precision component of MSL, mm, scale 0.1 156 | U4 h_acc; // Horizontal accuracy estimate, mm, scale 0.1 157 | U4 v_acc; // Vertical accuracy estimate, mm, scale 0.1 158 | } payload; 159 | }; 160 | struct UbxNavOdo { 161 | static constexpr uint8_t cls = UBX_NAV_CLS_; 162 | static constexpr uint8_t id = UBX_NAV_ODO_ID_; 163 | static constexpr uint16_t len = 20; 164 | struct { 165 | U1 version; // Message version 166 | U1 reserved0[3]; 167 | U4 i_tow; // GPS time of week, ms 168 | U4 distance; // Ground distance since last reset, m 169 | U4 total_distance; // Total cumulative ground distance, m 170 | U4 distance_std; // Ground distance accuracy (1-sigma), m 171 | } payload; 172 | }; 173 | template // templated by maximum number of satellites 174 | struct UbxNavOrb { 175 | static constexpr uint8_t cls = UBX_NAV_CLS_; 176 | static constexpr uint8_t id = UBX_NAV_ORB_ID_; 177 | uint16_t len; 178 | struct { 179 | U4 i_tow; // GPS time of week, ms 180 | U1 version; // Message version 181 | U1 num_sv; // Number of satellite vehicles 182 | U1 reserved0[2]; 183 | struct { 184 | U1 gnss_id; // GNSS ID 185 | U1 sv_id; // Satellite ID 186 | X1 sv_flag; // Information flags 187 | X1 eph; // Ephemeris data 188 | X1 alm; // Almanac data 189 | X1 other_orb; // Other orbital data 190 | } sv[N]; // Repeated group (num_sv times) 191 | } payload; 192 | }; 193 | struct UbxNavPosecef { 194 | static constexpr uint8_t cls = UBX_NAV_CLS_; 195 | static constexpr uint8_t id = UBX_NAV_POSECEF_ID_; 196 | static constexpr uint16_t len = 20; 197 | struct { 198 | U4 i_tow; // GPS time of week, ms 199 | I4 ecef_x; // ECEF x coordinate, cm 200 | I4 ecef_y; // ECEF y coordinate, cm 201 | I4 ecef_z; // ECEF z coordinate, cm 202 | U4 p_acc; // Position accuracy estimate, cm 203 | } payload; 204 | }; 205 | struct UbxNavPosllh { 206 | static constexpr uint8_t cls = UBX_NAV_CLS_; 207 | static constexpr uint8_t id = UBX_NAV_POSLLH_ID_; 208 | static constexpr uint16_t len = 28; 209 | struct { 210 | U4 i_tow; // GPS time of week, ms 211 | I4 lon; // Longitude, deg, scale 1e-7 212 | I4 lat; // Latitude, deg, scale 1e-7 213 | I4 height; // Height above ellipsoid, mm 214 | I4 h_msl; // Height above MSL, mm 215 | U4 h_acc; // Horizontal accuracy estimate, mm 216 | U4 v_acc; // Vertical accuracy estimate, mm 217 | } payload; 218 | }; 219 | struct UbxNavPvt { 220 | static constexpr uint8_t cls = UBX_NAV_CLS_; 221 | static constexpr uint8_t id = UBX_NAV_PVT_ID_; 222 | static constexpr uint16_t len = 92; 223 | struct { 224 | U4 i_tow; // GPS time of week, ms 225 | U2 year; // Year (UTC) 226 | U1 month; // Month (UTC) 227 | U1 day; // Day (UTC) 228 | U1 hour; // Hour (UTC) 229 | U1 min; // Minute (UTC) 230 | U1 sec; // Seconds (UTC) 231 | X1 valid; // Validity flags 232 | U4 t_acc; // Time accuracy estimate (UTC), ns 233 | I4 nano; // Fraction of second (UTC), ns 234 | U1 fix_type; // GNSS fix type 235 | X1 flags; // Fix status flags 236 | X1 flags2; // Additional flags 237 | U1 num_sv; // Number of satellites used in nav solution 238 | I4 lon; // Longitude, deg, scale 1e-7 239 | I4 lat; // Latitude, deg, scale 1e-7 240 | I4 height; // Height above the ellipsoid, mm 241 | I4 h_msl; // Height above MSL, mm 242 | U4 h_acc; // Horizontal accuracy estimate, mm 243 | U4 v_acc; // Vertical accuracy estimate, mm 244 | I4 vel_n; // NED north velocity, mm/s 245 | I4 vel_e; // NED east velocity, mm/s 246 | I4 vel_d; // NED down velocity, mm/s 247 | I4 g_speed; // Ground speed (2D), mm/s 248 | I4 head_mot; // Heading of motion (2D), deg, scale 1e-5 249 | U4 s_acc; // Speed accuracy estimate, mm/s 250 | U4 head_acc; // Heading accuracy estimate, deg, scale 1e-5 251 | U2 p_dop; // Position DOP, scale 0.01 252 | X1 flags3; // Additional flags 253 | U1 reserved0[5]; 254 | I4 head_veh; // Heading of vehicle (2D), deg, scale 1e-5 255 | I2 mag_dec; // Magnetic declination, deg, scale 1e-2 256 | U2 mag_acc; // Magnetic declination accuracy, deg, scale 1e-2 257 | } payload; 258 | }; 259 | struct UbxNavRelposned { 260 | static constexpr uint8_t cls = UBX_NAV_CLS_; 261 | static constexpr uint8_t id = UBX_NAV_RELPOSNED_ID_; 262 | static constexpr uint16_t len = 64; 263 | struct { 264 | U1 version; // Message version 265 | U1 reserved0; 266 | U2 ref_station_id; // Reference station ID 267 | U4 i_tow; // GPS time of week, ms 268 | I4 rel_pos_n; // North component of relative position vector, cm 269 | I4 rel_pos_e; // East component of relative position vector, cm 270 | I4 rel_pos_d; // Down component of relative position vector, cm 271 | I4 rel_pos_length; // Length of the relative position vector, cm 272 | I4 rel_pos_heading; // Heading of the rel pos vector, deg, scale 1e-5 273 | U1 reserved1[4]; 274 | I1 rel_pos_hp_n; // High precision N. rel pos vector, mm, scale 0.1 275 | I1 rel_pos_hp_e; // High precision E. rel pos vector, mm, scale 0.1 276 | I1 rel_pos_hp_d; // High precision D. rel pos vector, mm, scale 0.1 277 | I1 rel_pos_hp_length; // High precision rel pos vector len, mm, scale 0.1 278 | U4 acc_n; // Accuracy of N. rel pos vector, mm, scale 0.1 279 | U4 acc_e; // Accuracy of E. rel pos vector, mm, scale 0.1 280 | U4 acc_d; // Accuracy of D. rel pos vector, mm, scale 0.1 281 | U4 acc_length; // Accuracy of len of rel pos vector, mm, scale 0.1 282 | U4 acc_heading; // Accuracy of heading, deg, scale 1e-5 283 | U1 reserved2[4]; 284 | X4 flags; // Flags 285 | } payload; 286 | }; 287 | struct UbxNavResetodo { 288 | static constexpr uint8_t cls = UBX_NAV_CLS_; 289 | static constexpr uint8_t id = UBX_NAV_RESETODO_ID_; 290 | static constexpr uint16_t len = 0; 291 | }; 292 | template // templated by maximum number of satellites 293 | struct UbxNavSat { 294 | static constexpr uint8_t cls = UBX_NAV_CLS_; 295 | static constexpr uint8_t id = UBX_NAV_SAT_ID_; 296 | uint16_t len; 297 | struct { 298 | U4 i_tow; // GPS time of week, ms 299 | U1 version; // Message version 300 | U1 num_sv; // Number of satellites 301 | U1 reserved0[2]; 302 | struct { 303 | U1 gnss_id; // GNSS identifier 304 | U1 sv_id; // Satellite identifier 305 | U1 cno; // Carrier to noise ratio, dBHz 306 | I1 elev; // Elevation, deg 307 | I2 azim; // Azimuth, deg 308 | I2 pr_res; // Pseudorange residual, m, scale 0.1 309 | X4 flags; // Flags 310 | } sv[N]; // Repeated group (num_sv times) 311 | } payload; 312 | }; 313 | template // templated by maximum number of satellites 314 | struct UbxNavSbas { 315 | static constexpr uint8_t cls = UBX_NAV_CLS_; 316 | static constexpr uint8_t id = UBX_NAV_SBAS_ID_; 317 | uint16_t len; 318 | struct { 319 | U4 i_tow; // GPS time of week, ms 320 | U1 geo; // PRN number of the GEO where correction data is from 321 | U1 mode; // SBAS mode 322 | I1 sys; // SBAS system 323 | X1 service; // SBAS services available 324 | U1 cnt; // Number of SV data following 325 | U1 reserved0[3]; 326 | struct { 327 | U1 sv_id; // SV ID 328 | U1 flags; // Flags for this SV 329 | U1 udre; // Monitoring status 330 | U1 sv_sys; // System 331 | U1 sv_service; // Services available 332 | U1 reserved1; 333 | I2 prc; // pseudorange correction, cm 334 | U1 reserved2[2]; 335 | I2 ic; // ionosphere correction, cm 336 | } sv[N]; // Repeated group (cnt times) 337 | } payload; 338 | }; 339 | template // templated by maximum number of signals 340 | struct UbxNavSig { 341 | static constexpr uint8_t cls = UBX_NAV_CLS_; 342 | static constexpr uint8_t id = UBX_NAV_SIG_ID_; 343 | uint16_t len; 344 | struct { 345 | U4 i_tow; // GPS time of week, ms 346 | U1 version; // Message version 347 | U1 num_sigs; // Number of signals 348 | U1 reserved0[2]; 349 | struct { 350 | U1 gnss_id; // GNSS identifier 351 | U1 sv_id; // Satellite identifier 352 | U1 sig_id; // Signal identifier 353 | U1 freq_id; // GLONASS frequency slot 354 | I2 pr_res; // Pseudorange residuals, m, scale 0.1 355 | U1 cno; // Carrier to noise ratio, dBHz 356 | U1 quality_ind; // Signal quality indicator 357 | U1 corr_source; // Correction source 358 | U1 iono_model; // Ionospheric model 359 | X2 sig_flags; // Signal related flags 360 | U1 reserved1[4]; 361 | } sig[N]; // Repeated group (num_sigs times) 362 | } payload; 363 | }; 364 | template // templated by maximum number of corrections 365 | struct UbxNavSlas { 366 | static constexpr uint8_t cls = UBX_NAV_CLS_; 367 | static constexpr uint8_t id = UBX_NAV_SLAS_ID_; 368 | uint16_t len; 369 | struct { 370 | U4 i_tow; // GPS time of week, ms 371 | U1 version; // Message version 372 | U1 reserved0[3]; 373 | I4 gms_lon; // Longitude of ground monitoring stn, deg, scale 1e-3 374 | I4 gms_lat; // Latitude of ground monitoring stn, deg, scale 1e-3 375 | U1 gms_code; // Ground monitoring station code 376 | U1 qzss_sc_id; // Satellite id of QZS/GEO corr data used 377 | X1 service_flags; // Flags regarding SLAS service 378 | U1 cnt; // Number of pseudorange corr following 379 | struct { 380 | U1 gnss_id; // GNSS ID 381 | U1 sv_id; // Satellite ID 382 | U1 reserved1; 383 | U1 reserved2[3]; 384 | I2 prc; // Pseudorange correction, cm 385 | } corr[N]; 386 | } payload; 387 | }; 388 | struct UbxNavStatus { 389 | static constexpr uint8_t cls = UBX_NAV_CLS_; 390 | static constexpr uint8_t id = UBX_NAV_STATUS_ID_; 391 | static constexpr uint16_t len = 16; 392 | struct { 393 | U4 i_tow; // GPS time of week, ms 394 | U1 gps_fix; // GPS fix type 395 | X1 flags; // Navigation status flags 396 | X1 fix_stat; // Fix status info 397 | X1 flags2; // Further info about nav output 398 | U4 ttff; // Time to first fix, ms 399 | U4 msss; // Milliseconds since startup, ms 400 | } payload; 401 | }; 402 | struct UbxNavSvin { 403 | static constexpr uint8_t cls = UBX_NAV_CLS_; 404 | static constexpr uint8_t id = UBX_NAV_SVIN_ID_; 405 | static constexpr uint16_t len = 40; 406 | struct { 407 | U1 version; // Message version 408 | U1 reserved0[3]; 409 | U4 i_tow; // GPS time of week, ms 410 | U4 dur; // Passed survey-in observation time, s 411 | I4 mean_x; // Current mean ECEF x, cm 412 | I4 mean_y; // Current mean ECEF y, cm 413 | I4 mean_z; // Current mean ECEF z, cm 414 | I1 mean_x_hp; // High precision ECEF x, mm, scale 0.1 415 | I1 mean_y_hp; // High precision ECEF y, mm, scale 0.1 416 | I1 mean_z_hp; // High precision ECEF z, mm, scale 0.1 417 | U1 reserved1; 418 | U4 mean_acc; // Current survey-in accuracy, mm, scale 0.1 419 | U4 obs; // Number of position observations used during survey 420 | U1 valid; // Survey-in position validity 421 | U1 active; // Survey-in progress flag 422 | U1 reserved2[2]; 423 | } payload; 424 | }; 425 | struct UbxNavTimebds { 426 | static constexpr uint8_t cls = UBX_NAV_CLS_; 427 | static constexpr uint8_t id = UBX_NAV_TIMEBDS_ID_; 428 | static constexpr uint16_t len = 20; 429 | struct { 430 | U4 i_tow; // GPS time of week, ms 431 | U4 sow; // BDS time of week, s 432 | I4 f_sow; // Fractional part of SOW, ns 433 | I2 week; // BDS week number 434 | I1 leap_s; // BDS leap seconds 435 | X1 valid; // Validity flags 436 | U4 t_acc; // Time accuracy estimate, ns 437 | } payload; 438 | }; 439 | struct UbxNavTimegal { 440 | static constexpr uint8_t cls = UBX_NAV_CLS_; 441 | static constexpr uint8_t id = UBX_NAV_TIMEGAL_ID_; 442 | static constexpr uint16_t len = 20; 443 | struct { 444 | U4 i_tow; // GPS time of week, ms 445 | U4 gal_tow; // Galileo time of week, s 446 | I4 f_gal_tow; // Fractional part of gal_tow, ns 447 | I2 gal_wno; // Galileo week number 448 | I1 leap_s; // Galileo leap seconds 449 | X1 valid; // Validity flags 450 | U4 t_acc; // Time accuracy estimate, ns 451 | } payload; 452 | }; 453 | struct UbxNavTimeglo { 454 | static constexpr uint8_t cls = UBX_NAV_CLS_; 455 | static constexpr uint8_t id = UBX_NAV_TIMEGLO_ID_; 456 | static constexpr uint16_t len = 20; 457 | struct { 458 | U4 i_tow; // GPS time of week, ms 459 | U4 tod; // GLONASS time of day, s 460 | I4 f_tod; // Fractional part of GLONASS, ns 461 | U2 nt; // Current date starting @ 1 from 1st Jan of n4 462 | U1 n4; // Four year interval number 463 | X1 valid; // Validity flags 464 | U4 t_acc; // Time accuracy estimate, ns 465 | } payload; 466 | }; 467 | struct UbxNavTimegps { 468 | static constexpr uint8_t cls = UBX_NAV_CLS_; 469 | static constexpr uint8_t id = UBX_NAV_TIMEGPS_ID_; 470 | static constexpr uint16_t len = 16; 471 | struct { 472 | U4 i_tow; // GPS time of week, ms 473 | I4 f_tow; // Fractional part of TOW, ns 474 | I2 week; // GPS week number 475 | I1 leap_s; // GPS leap seconds 476 | X1 valid; // Validity flags 477 | U4 t_acc; // Time accuracy estimate, ns 478 | } payload; 479 | }; 480 | struct UbxNavTimels { 481 | static constexpr uint8_t cls = UBX_NAV_CLS_; 482 | static constexpr uint8_t id = UBX_NAV_TIMELS_ID_; 483 | static constexpr uint16_t len = 24; 484 | struct { 485 | U4 i_tow; // GPS time of week, ms 486 | U1 version; // Message version 487 | U1 reserved0[3]; 488 | U1 src_of_curr_ls; // Info src for current num of leap sec 489 | I1 curr_ls; // Current number of leap sec 490 | U1 src_of_ls_change; // Info src for future leap sec 491 | I1 ls_change; // Future leap sec change 492 | I4 time_to_ls_event; // Number of seconds until leap sec change 493 | U2 date_of_ls_gps_wn; // GPS week number of leap sec change 494 | U2 date_of_ls_gps_dn; // GPS day of week of leap sec change 495 | U1 reserved1[3]; 496 | X1 valid; // Validity flags 497 | } payload; 498 | }; 499 | struct UbxNavTimeqzss { 500 | static constexpr uint8_t cls = UBX_NAV_CLS_; 501 | static constexpr uint8_t id = UBX_NAV_TIMEQZSS_ID_; 502 | static constexpr uint16_t len = 20; 503 | struct { 504 | U4 i_tow; // GPS time of week, ms 505 | U4 qzss_tow; // QZSS time of week, s 506 | I4 f_qzss_tow; // Fractional part of QZSS TOW, ns 507 | I2 qzss_wno; // QZSS week number 508 | I1 leap_s; // QZSS leap seconds, s 509 | X1 valid; // Validity flags 510 | U4 t_acc; // Time accuracy estimate, ns 511 | } payload; 512 | }; 513 | struct UbxNavTimeutc { 514 | static constexpr uint8_t cls = UBX_NAV_CLS_; 515 | static constexpr uint8_t id = UBX_NAV_TIMEUTC_ID_; 516 | static constexpr uint16_t len = 20; 517 | struct { 518 | U4 i_tow; // GPS time of week, ms 519 | U4 t_acc; // Time accuracy estimate (UTC), ns 520 | I4 nano; // Fraction of a second (UTC), ns 521 | U2 year; // Year (UTC) 522 | U1 month; // Month (UTC) 523 | U1 day; // Day (UTC) 524 | U1 hour; // Hour (UTC) 525 | U1 min; // Minute (UTC) 526 | U1 sec; // Seconds (UTC) 527 | X1 valid; // Validity flags 528 | } payload; 529 | }; 530 | struct UbxNavVelecef { 531 | static constexpr uint8_t cls = UBX_NAV_CLS_; 532 | static constexpr uint8_t id = UBX_NAV_VELECEF_ID_; 533 | static constexpr uint16_t len = 20; 534 | struct { 535 | U4 i_tow; // GPS time of week, ms 536 | I4 ecef_v_x; // ECEF x velocity, cm/s 537 | I4 ecef_v_y; // ECEF y velocity, cm/s 538 | I4 ecef_v_z; // ECEF z velocity, cm/s 539 | U4 s_acc; // Speed accuracy estimate, cm/s 540 | } payload; 541 | }; 542 | struct UbxNavVelned { 543 | static constexpr uint8_t cls = UBX_NAV_CLS_; 544 | static constexpr uint8_t id = UBX_NAV_VELNED_ID_; 545 | static constexpr uint16_t len = 36; 546 | struct { 547 | U4 i_tow; // GPS time of week, ms 548 | I4 vel_n; // North velocity component, cm/s 549 | I4 vel_e; // East velocity component, cm/s 550 | I4 vel_d; // Down velocity component, cm/s 551 | U4 speed; // Speed (3D), cm/s 552 | U4 g_speed; // Ground speed (2D), cm/s 553 | I4 heading; // Heading of motion (2D), deg, scale 1e-5 554 | U4 s_acc; // Speed accuracy estimate, cm/s 555 | U4 c_acc; // Course/Heading accuracy estimate, deg, scale 1e-5 556 | } payload; 557 | }; 558 | 559 | } // namespace bfs 560 | 561 | #endif // SRC_UBX_NAV_H_ 562 | --------------------------------------------------------------------------------