├── LICENSE ├── tools ├── fake_ubx_mon_hw.ubx ├── fake_ubx_esf_meas.ubx ├── fake_ubx_esf_status.ubx ├── make_fake_ubxmonhw.c ├── make_fake_ubxesfstatus.c ├── make_fake_ubxesfmeas.c └── 99-ftdi-ublox.rules ├── .ackrc ├── contrib ├── Makefile └── main.c ├── CMakeLists.txt ├── cmake ├── config.pc.in ├── config.cmake.in └── setup.cmake ├── .gitignore ├── ff ├── ff_crc.txt ├── README.md ├── ff_time.h ├── ff_spartn.h ├── ff_crc.h ├── ff_stuff.c ├── ff_trafo.h ├── ff_debug.h ├── ff_port.h ├── ff_stuff.h ├── ff_parser.h ├── ff_time.c ├── ff_novatel.h ├── ff_rx.h ├── ff_spartn.c ├── CMakeLists.txt ├── ff_novatel.c ├── ff_rtcm3.h ├── ff_nmea.h └── ff_debug.c ├── .clang-format ├── .github └── workflows │ └── ci.yml ├── cfgtool ├── cfgtool_uc2cfg.h ├── cfgtool_cfginfo.h ├── cfgtool_bin2hex.h ├── cfgtool_parse.h ├── cfgtool_dump.h ├── cfgtool_status.h ├── cfgtool_reset.h ├── cfgtool_cmd2rx.h ├── README.md ├── cfgtool_rx2cfg.h ├── cfgtool_cfg2ubx.h ├── cfgtool_cfg2rx.h ├── cfgtool_util.h ├── cfgtool_bin2hex.c ├── cfgtool_cfginfo.c ├── CMakeLists.txt ├── cfgtool_reset.c ├── cfgtool_cfg2ubx.c ├── cfgtool_parse.c ├── cfgtool_uc2cfg.c ├── cfgtool_dump.c ├── cfgtool_status.c └── cfgtool_util.c ├── README.md ├── ubloxcfg ├── README.md ├── CMakeLists.txt ├── LICENSE └── ubloxcfg-99-test.jsonc └── Makefile /LICENSE: -------------------------------------------------------------------------------- 1 | See files in the subfolders (**/*LICENSE*) 2 | 3 | -------------------------------------------------------------------------------- /tools/fake_ubx_mon_hw.ubx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phkehl/ubloxcfg/HEAD/tools/fake_ubx_mon_hw.ubx -------------------------------------------------------------------------------- /tools/fake_ubx_esf_meas.ubx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phkehl/ubloxcfg/HEAD/tools/fake_ubx_esf_meas.ubx -------------------------------------------------------------------------------- /.ackrc: -------------------------------------------------------------------------------- 1 | --ignore-directory=output 2 | --known-types 3 | --smart-case 4 | --group 5 | --context=3 6 | --color 7 | -------------------------------------------------------------------------------- /tools/fake_ubx_esf_status.ubx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phkehl/ubloxcfg/HEAD/tools/fake_ubx_esf_status.ubx -------------------------------------------------------------------------------- /contrib/Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | CFLAGS=-o2 -W -Wall 3 | LDFLAGS=-lubloxcfg -lm 4 | OBJ=main.o 5 | EXE=main 6 | 7 | all: $(EXE) -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.16) 2 | include(cmake/setup.cmake) 3 | 4 | project(everything 5 | LANGUAGES C CXX 6 | VERSION ${FF_VERSION_NUMBER} 7 | DESCRIPTION "everything" 8 | ) 9 | 10 | add_subdirectory(ubloxcfg) 11 | add_subdirectory(ff) 12 | add_subdirectory(cfgtool) 13 | -------------------------------------------------------------------------------- /cmake/config.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@CMAKE_INSTALL_PREFIX@ 2 | exec_prefix=@CMAKE_INSTALL_PREFIX@ 3 | libdir=${exec_prefix}/@CMAKE_INSTALL_LIBDIR@ 4 | includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@/@PROJECT_NAME@ 5 | 6 | Name: @PROJECT_NAME@ 7 | Description: @PROJECT_DESCRIPTION@ 8 | Version: @PROJECT_VERSION@ 9 | 10 | Requires: 11 | Libs: -L${libdir} -l@TARGET1@ 12 | Cflags: -I${includedir} 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.bak 3 | x 4 | xx* 5 | meier* 6 | /tmp 7 | 8 | /.vstags 9 | /.vscode/bookmarks.json 10 | /.vscode-cache 11 | 12 | /.vs 13 | /.vscode 14 | 15 | core 16 | core.[0-9]* 17 | 18 | /output 19 | /build 20 | /*/build 21 | /*/html 22 | /install 23 | 24 | /*.cfg 25 | imgui.ini 26 | 27 | /*.ubx 28 | /*.ubz 29 | /*.ubx.gz 30 | 31 | /tools/make_fake_ubxmonhw 32 | /tools/make_fake_ubxesfstatus 33 | /tools/make_fake_ubxesfmeas 34 | 35 | /.history 36 | 37 | *.pyc 38 | 39 | /config.mk 40 | 41 | -------------------------------------------------------------------------------- /ff/ff_crc.txt: -------------------------------------------------------------------------------- 1 | width=4 poly=0x9 init=0x0 refin=true refout=true xorout=0x0 check=0x0 residue=0x0 name="FF-SPARTN-4" 2 | width=8 poly=0x07 init=0x00 refin=false refout=false xorout=0x0 check=0x0 residue=0x0 name="FF-SPARTN-8" 3 | width=16 poly=0x1021 init=0x0000 refin=false refout=false xorout=0x0000 check=0x0000 residue=0x0000 name="FF-SPARTN-16" 4 | width=24 poly=0x864cfb init=0x000000 refin=false refout=false xorout=0x000000 check=0x000000 residue=0x000000 name="FF-SPARTN-24" 5 | width=32 poly=0x04c11db7 init=0xffffffff refin=false refout=false xorout=0xffffffff check=0x00000000 residue=0x000000 name="FF-SPARTN-32" 6 | width=32 poly=0x04c11db7 init=0x00000000 refin=true refout=false xorout=0x00000000 check=0x00000000 residue=0x000000 name="FF-NOVATEL-32" 7 | -------------------------------------------------------------------------------- /cmake/config.cmake.in: -------------------------------------------------------------------------------- 1 | @PACKAGE_INIT@ 2 | 3 | include ( "${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@-targets.cmake" ) 4 | 5 | # library version information 6 | set(@PROJECT_NAME@_VERSION_STRING "@PROJECT_VERSION@") 7 | set(@PROJECT_NAME@_VERSION_MAJOR @PROJECT_VERSION_MAJOR@) 8 | set(@PROJECT_NAME@_VERSION_MINOR @PROJECT_VERSION_MINOR@) 9 | set(@PROJECT_NAME@_VERSION_PATCH @PROJECT_VERSION_PATCH@) 10 | 11 | set(@PROJECT_NAME@_FOUND 1) 12 | 13 | # Include and library dirs 14 | set(_INSTALL_PREFIX "@CMAKE_INSTALL_PREFIX@") 15 | set(@PROJECT_NAME@_INCLUDE_DIRS "${_INSTALL_PREFIX}/@CMAKE_INSTALL_INCLUDEDIR@/@PROJECT_NAME@") 16 | set(@PROJECT_NAME@_LIBRARY_DIRS "${_INSTALL_PREFIX}/@CMAKE_INSTALL_LIBDIR@") 17 | 18 | # Libraries 19 | set(@PROJECT_NAME@_LIBRARIES "@TARGET1@") 20 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: Google 2 | IndentWidth: 4 3 | ColumnLimit: 120 4 | DerivePointerAlignment: false 5 | PointerAlignment: Left 6 | AlignAfterOpenBracket: DontAlign 7 | AllowShortFunctionsOnASingleLine: false 8 | BreakBeforeBraces: Custom 9 | BraceWrapping: 10 | AfterClass: true 11 | AfterStruct: true 12 | AfterFunction: true 13 | AfterEnum: true 14 | AfterUnion: true 15 | IndentPPDirectives: AfterHash 16 | PPIndentWidth: 2 17 | IncludeCategories: 18 | - Regex: '^<.*' 19 | Priority: -1 20 | SortPriority: -2 21 | CaseSensitive: false 22 | - Regex: '^".*' 23 | Priority: -1 24 | SortPriority: -1 25 | CaseSensitive: false 26 | SortIncludes: CaseInsensitive 27 | InsertBraces: true 28 | Cpp11BracedListStyle: false 29 | -------------------------------------------------------------------------------- /ff/README.md: -------------------------------------------------------------------------------- 1 | # ff library -- allecheibs utilities 2 | 3 | Copyright (c) Philippe Kehl (flipflip at oinkzwurgl dot org) and contributors 4 | 5 | https://oinkzwurgl.org/projaeggd/ubloxcfg/ 6 | 7 | [License](./LICENSE): GNU General Public License (GPL) v3 8 | 9 | ## Overview 10 | 11 | This is a utility library. It contains a UBX/NMEA/RTCM3 message parser, a serial port library, a receiver control, and 12 | some other things), which could be useful for other projects. 13 | 14 | This uses some gcc/libc stuff ("GNU99"). 15 | 16 | ## Build and install 17 | 18 | First, build and install the [ubloxcfg library](../ubloxcfg/README.md). 19 | 20 | ```sh 21 | cmake -B build -S . -DCMAKE_INSTALL_PREFIX=/wherever/you/want/it 22 | cmake --build build 23 | cmake --install build 24 | ``` 25 | 26 | Dev command: 27 | 28 | ```sh 29 | clear; rm -rf build; cmake -B build -S . -DCMAKE_INSTALL_PREFIX=/tmp/ub && cmake --build build --verbose && cmake --install build 30 | ``` 31 | 32 | ## See also 33 | 34 | - [../README.md](../README.md) 35 | -------------------------------------------------------------------------------- /tools/make_fake_ubxmonhw.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "ff_stuff.h" 4 | #include "ff_ubx.h" 5 | // gcc -o make_fake_ubxmonhw -I../ff -I../ubloxcfg make_fake_ubxmonhw.c ../ff/ff_ubx.c ../ff/ff_debug.c ../ubloxcfg/*.c 6 | int main(int argc, char **argv) 7 | { 8 | FILE *f = fopen("fake_ubx_mon_hw.ubx", "w"); 9 | UBX_MON_HW_V0_GROUP0_t hw; 10 | memset(&hw, 0, sizeof(hw)); 11 | uint8_t vPinIx = 0; 12 | //hw.pinSel = 0x0001ffff; 13 | //hw.pinVal = 0x0001ffff; 14 | hw.pinBank = 0x0001ffff; 15 | //hw.pinDir = 0x0001ffff; 16 | hw.usedMask = 0x0001ffff; 17 | hw.reserved0 = 0x85; 18 | hw.reserved1[0] = 0xee; 19 | hw.reserved1[1] = 0x5a; 20 | while (vPinIx < 0xff) 21 | { 22 | for (int ix = 0; ix < NUMOF(hw.VP); ix++) 23 | { 24 | hw.VP[ix] = vPinIx; 25 | vPinIx++; 26 | } 27 | uint8_t msg[sizeof(hw) + UBX_FRAME_SIZE]; 28 | const int size = ubxMakeMessage(UBX_MON_CLSID, UBX_MON_HW_MSGID, (uint8_t *)&hw, sizeof(hw), msg); 29 | fwrite(msg, size, 1, f); 30 | } 31 | fclose(f); 32 | return 0; 33 | } -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: ci 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | branches: [main] 8 | workflow_dispatch: 9 | 10 | jobs: 11 | ci-build: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Checks-out 15 | uses: actions/checkout@v4 16 | - name: Install dependencies 17 | run: | 18 | sudo apt-get -y update 19 | sudo apt-get -y install gcc libpath-tiny-perl libdata-float-perl 20 | - name: Build (Debug) 21 | run: | 22 | make clean build BUILD_TYPE=Debug BUILD_TESTING=OFF 23 | - name: Build (Release) 24 | run: | 25 | make clean build BUILD_TYPE=Release BUILD_TESTING=OFF 26 | - name: Test (Debug) 27 | run: | 28 | make clean test VERBOSE=1 BUILD_TYPE=Debug BUILD_TESTING=ON 29 | - name: Test (Release) 30 | run: | 31 | make clean test VERBOSE=1 BUILD_TYPE=Release BUILD_TESTING=ON 32 | - name: Generate code 33 | run: | 34 | cd ubloxcfg 35 | rm -vf ubloxcfg_gen.[ch] 36 | cmake -B build -S . 37 | cmake --build build 38 | git diff --exit-code ubloxcfg_gen.[ch] 39 | 40 | -------------------------------------------------------------------------------- /tools/make_fake_ubxesfstatus.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "ff_stuff.h" 4 | #include "ff_ubx.h" 5 | // gcc -o make_fake_ubxesfstatus -I../ff -I../ubloxcfg make_fake_ubxesfstatus.c ../ff/ff_ubx.c ../ff/ff_debug.c ../ubloxcfg/*.c 6 | 7 | #define NUM_SEN_TYPE 64 // 2**6 8 | int main(int argc, char **argv) 9 | { 10 | FILE *f = fopen("fake_ubx_esf_status.ubx", "w"); 11 | UBX_ESF_STATUS_V2_GROUP0_t status; 12 | memset(&status, 0, sizeof(status)); 13 | status.version = UBX_ESF_STATUS_V2_VERSION; 14 | status.numSens = NUM_SEN_TYPE; 15 | 16 | uint8_t msg[UBX_FRAME_SIZE + sizeof(UBX_ESF_STATUS_V2_GROUP0_t) + (NUM_SEN_TYPE * sizeof(UBX_ESF_STATUS_V2_GROUP1_t))]; 17 | 18 | int offs = 0; 19 | memcpy(&msg[offs], &status, sizeof(status)); 20 | offs += sizeof(status); 21 | for (int sensType = 0; sensType < NUM_SEN_TYPE; sensType++, offs += (int)sizeof(UBX_ESF_STATUS_V2_GROUP1_t)) 22 | { 23 | UBX_ESF_STATUS_V2_GROUP1_t sens; 24 | sens.sensStatus1 = sensType; 25 | sens.sensStatus2 = 0; 26 | memcpy(&msg[offs], &sens, sizeof(sens)); 27 | } 28 | 29 | const int size = ubxMakeMessage(UBX_ESF_CLSID, UBX_ESF_STATUS_MSGID, msg, offs, msg); 30 | fwrite(msg, size, 1, f); 31 | fclose(f); 32 | return 0; 33 | } -------------------------------------------------------------------------------- /tools/make_fake_ubxesfmeas.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "ff_stuff.h" 4 | #include "ff_ubx.h" 5 | // gcc -o make_fake_ubxesfmeas -I../ff -I../ubloxcfg make_fake_ubxesfmeas.c ../ff/ff_ubx.c ../ff/ff_debug.c ../ubloxcfg/*.c 6 | 7 | #define NUM_DATA_TYPE 64 // 2**6 8 | int main(int argc, char **argv) 9 | { 10 | FILE *f = fopen("fake_ubx_esf_meas.ubx", "w"); 11 | 12 | const int numDataTypePerMsg = 32; // 2**5 13 | for (int dataTypeOffs = 0; dataTypeOffs < NUM_DATA_TYPE; dataTypeOffs += numDataTypePerMsg) 14 | { 15 | UBX_ESF_MEAS_V0_GROUP0_t meas; 16 | memset(&meas, 0, sizeof(meas)); 17 | meas.flags = numDataTypePerMsg << 11; 18 | 19 | uint8_t msg[UBX_FRAME_SIZE + sizeof(UBX_ESF_MEAS_V0_GROUP0_t) + (NUM_DATA_TYPE * sizeof(UBX_ESF_MEAS_V0_GROUP1_t))]; 20 | 21 | int offs = 0; 22 | memcpy(&msg[offs], &meas, sizeof(meas)); 23 | offs += sizeof(meas); 24 | for (int dataType = dataTypeOffs; dataType < dataTypeOffs + numDataTypePerMsg; dataType++, offs += (int)sizeof(UBX_ESF_MEAS_V0_GROUP1_t)) 25 | { 26 | UBX_ESF_MEAS_V0_GROUP1_t meas; 27 | meas.data = (dataType << 24) | 1234; 28 | memcpy(&msg[offs], &meas, sizeof(meas)); 29 | } 30 | 31 | const int size = ubxMakeMessage(UBX_ESF_CLSID, UBX_ESF_MEAS_MSGID, msg, offs, msg); 32 | fwrite(msg, size, 1, f); 33 | 34 | } 35 | fclose(f); 36 | return 0; 37 | } -------------------------------------------------------------------------------- /cfgtool/cfgtool_uc2cfg.h: -------------------------------------------------------------------------------- 1 | // clang-format off 2 | /* ****************************************************************************************************************** */ 3 | // u-blox positioning receivers configuration tool 4 | // 5 | // Copyright (c) Philippe Kehl (flipflip at oinkzwurgl dot org) and contributors 6 | // 7 | // This program is free software: you can redistribute it and/or modify it under the terms of the 8 | // GNU General Public License as published by the Free Software Foundation, either version 3 of the 9 | // License, or (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 12 | // even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | // See the GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License along with this program. 16 | // If not, see . 17 | 18 | #include 19 | #include 20 | 21 | #ifndef __CFGTOOL_UC2CFG_H__ 22 | #define __CFGTOOL_UC2CFG_H__ 23 | 24 | /* ****************************************************************************************************************** */ 25 | 26 | const char *uc2cfgHelp(void); 27 | int uc2cfgRun(void); 28 | 29 | /* ****************************************************************************************************************** */ 30 | #endif // __CFGTOOL_UC2CFG_H__ 31 | -------------------------------------------------------------------------------- /cfgtool/cfgtool_cfginfo.h: -------------------------------------------------------------------------------- 1 | // clang-format off 2 | /* ****************************************************************************************************************** */ 3 | // u-blox positioning receivers configuration tool 4 | // 5 | // Copyright (c) Philippe Kehl (flipflip at oinkzwurgl dot org) and contributors 6 | // 7 | // This program is free software: you can redistribute it and/or modify it under the terms of the 8 | // GNU General Public License as published by the Free Software Foundation, either version 3 of the 9 | // License, or (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 12 | // even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | // See the GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License along with this program. 16 | // If not, see . 17 | 18 | #include 19 | #include 20 | 21 | #ifndef __CFGTOOL_CFGINFO_H__ 22 | #define __CFGTOOL_CFGINFO_H__ 23 | 24 | /* ****************************************************************************************************************** */ 25 | 26 | const char *cfginfoHelp(void); 27 | 28 | int cfginfoRun(void); 29 | 30 | /* ****************************************************************************************************************** */ 31 | #endif // __CFGTOOL_CFGINFO_H__ 32 | -------------------------------------------------------------------------------- /tools/99-ftdi-ublox.rules: -------------------------------------------------------------------------------- 1 | # udev rules for USB-to-UART device (FTDI chip) used in u-blox eval kits 2 | # 3 | # This configures the ftdi_sio Linux driver to recognise it as ttyUSB serial ports 4 | # 5 | # To install: 6 | # 7 | # sudo cp 99-ftdi-ublox.rules /etc/udev/rules.d/ 8 | # sudo udevadm control --reload-rules 9 | # 10 | # To test new IDs one can also do: 11 | # 12 | # echo 1546 0507 > /sys/bus/usb-serial/drivers/ftdi_sio/new_id 13 | # 14 | 15 | # EVK-F9P 16 | # Bus 001 Device 046: ID 1546:0507 U-Blox AG F9P; ZED_UART1 17 | # Bus 001 Device 047: ID 1546:0508 U-Blox AG F9P; ZED_UART2 18 | ACTION=="add", SUBSYSTEM=="usb", ATTRS{idVendor}=="1546", ATTRS{idProduct}=="0507", RUN+="/bin/sh -c '/sbin/modprobe ftdi_sio && echo 1546 0507 > /sys/bus/usb-serial/drivers/ftdi_sio/new_id'" 19 | ACTION=="add", SUBSYSTEM=="usb", ATTRS{idVendor}=="1546", ATTRS{idProduct}=="0508", RUN+="/bin/sh -c '/sbin/modprobe ftdi_sio && echo 1546 0508 > /sys/bus/usb-serial/drivers/ftdi_sio/new_id'" 20 | 21 | # EVK-X20P 22 | # Bus 001 Device 050: ID 1546:050c U-Blox AG X20P UART1 23 | # Bus 001 Device 051: ID 1546:050d U-Blox AG X20P UART2 24 | ACTION=="add", SUBSYSTEM=="usb", ATTRS{idVendor}=="1546", ATTRS{idProduct}=="050c", RUN+="/bin/sh -c '/sbin/modprobe ftdi_sio && echo 1546 050c > /sys/bus/usb-serial/drivers/ftdi_sio/new_id'" 25 | ACTION=="add", SUBSYSTEM=="usb", ATTRS{idVendor}=="1546", ATTRS{idProduct}=="050d", RUN+="/bin/sh -c '/sbin/modprobe ftdi_sio && echo 1546 050d > /sys/bus/usb-serial/drivers/ftdi_sio/new_id'" 26 | -------------------------------------------------------------------------------- /cfgtool/cfgtool_bin2hex.h: -------------------------------------------------------------------------------- 1 | // clang-format off 2 | /* ****************************************************************************************************************** */ 3 | // u-blox positioning receivers configuration tool 4 | // 5 | // Copyright (c) Philippe Kehl (flipflip at oinkzwurgl dot org) and contributors 6 | // 7 | // This program is free software: you can redistribute it and/or modify it under the terms of the 8 | // GNU General Public License as published by the Free Software Foundation, either version 3 of the 9 | // License, or (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 12 | // even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | // See the GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License along with this program. 16 | // If not, see . 17 | 18 | #include 19 | #include 20 | 21 | #ifndef __CFGTOOL_BIN2HEX_H__ 22 | #define __CFGTOOL_BIN2HEX_H__ 23 | 24 | /* ****************************************************************************************************************** */ 25 | 26 | const char *bin2hexHelp(void); 27 | int bin2hexRun(void); 28 | int hex2binRun(void); 29 | 30 | /* ****************************************************************************************************************** */ 31 | #endif // __CFGTOOL_BIN2HEX_H__ 32 | -------------------------------------------------------------------------------- /cfgtool/cfgtool_parse.h: -------------------------------------------------------------------------------- 1 | // clang-format off 2 | /* ****************************************************************************************************************** */ 3 | // u-blox positioning receivers configuration tool 4 | // 5 | // Copyright (c) Philippe Kehl (flipflip at oinkzwurgl dot org) and contributors 6 | // 7 | // This program is free software: you can redistribute it and/or modify it under the terms of the 8 | // GNU General Public License as published by the Free Software Foundation, either version 3 of the 9 | // License, or (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 12 | // even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | // See the GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License along with this program. 16 | // If not, see . 17 | 18 | #include 19 | #include 20 | 21 | #ifndef __CFGTOOL_PARSE_H__ 22 | #define __CFGTOOL_PARSE_H__ 23 | 24 | /* ****************************************************************************************************************** */ 25 | 26 | const char *parseHelp(void); 27 | 28 | int parseRun(const bool extraInfo, const bool doEpoch); 29 | 30 | /* ****************************************************************************************************************** */ 31 | #endif // __CFGTOOL_PARSE_H__ 32 | -------------------------------------------------------------------------------- /cfgtool/cfgtool_dump.h: -------------------------------------------------------------------------------- 1 | // clang-format off 2 | /* ****************************************************************************************************************** */ 3 | // u-blox positioning receivers configuration tool 4 | // 5 | // Copyright (c) Philippe Kehl (flipflip at oinkzwurgl dot org) and contributors 6 | // 7 | // This program is free software: you can redistribute it and/or modify it under the terms of the 8 | // GNU General Public License as published by the Free Software Foundation, either version 3 of the 9 | // License, or (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 12 | // even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | // See the GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License along with this program. 16 | // If not, see . 17 | 18 | #include 19 | #include 20 | 21 | #ifndef __CFGTOOL_DUMP_H__ 22 | #define __CFGTOOL_DUMP_H__ 23 | 24 | /* ****************************************************************************************************************** */ 25 | 26 | const char *dumpHelp(void); 27 | 28 | int dumpRun(const char *portArg, const bool extraInfo, const bool noProbe); 29 | 30 | /* ****************************************************************************************************************** */ 31 | #endif // __CFGTOOL_DUMP_H__ 32 | -------------------------------------------------------------------------------- /ff/ff_time.h: -------------------------------------------------------------------------------- 1 | // clang-format off 2 | // flipflip's time functions 3 | // 4 | // Copyright (c) Philippe Kehl (flipflip at oinkzwurgl dot org) and contributors 5 | // https://oinkzwurgl.org/projaeggd/ubloxcfg/ 6 | // 7 | // This program is free software: you can redistribute it and/or modify it under the terms of the 8 | // GNU General Public License as published by the Free Software Foundation, either version 3 of the 9 | // License, or (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 12 | // even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | // See the GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License along with this program. 16 | // If not, see . 17 | 18 | #ifndef __FF_TIME_H__ 19 | #define __FF_TIME_H__ 20 | 21 | #include 22 | #include 23 | 24 | #ifdef __cplusplus 25 | extern "C" { 26 | #endif 27 | 28 | /* ****************************************************************************************************************** */ 29 | 30 | double wnoTow2ts(const int wno, const double tow); 31 | 32 | double ts2posix(const double ts, const int leapSec, const bool leapSecValid); 33 | 34 | double posixNow(); 35 | 36 | /* ****************************************************************************************************************** */ 37 | #ifdef __cplusplus 38 | } 39 | #endif 40 | #endif // __FF_TIME_H__ 41 | -------------------------------------------------------------------------------- /cfgtool/cfgtool_status.h: -------------------------------------------------------------------------------- 1 | // clang-format off 2 | /* ****************************************************************************************************************** */ 3 | // u-blox positioning receivers configuration tool 4 | // 5 | // Copyright (c) Philippe Kehl (flipflip at oinkzwurgl dot org) and contributors 6 | // 7 | // This program is free software: you can redistribute it and/or modify it under the terms of the 8 | // GNU General Public License as published by the Free Software Foundation, either version 3 of the 9 | // License, or (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 12 | // even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | // See the GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License along with this program. 16 | // If not, see . 17 | 18 | #include 19 | #include 20 | 21 | #include "ff_rx.h" 22 | 23 | #ifndef __CFGTOOL_STATUS_H__ 24 | #define __CFGTOOL_STATUS_H__ 25 | 26 | /* ****************************************************************************************************************** */ 27 | 28 | const char *statusHelp(void); 29 | 30 | int statusRun(const char *portArg, const bool extraInfo, const bool noProbe); 31 | 32 | /* ****************************************************************************************************************** */ 33 | #endif // __CFGTOOL_STATUS_H__ 34 | -------------------------------------------------------------------------------- /cfgtool/cfgtool_reset.h: -------------------------------------------------------------------------------- 1 | // clang-format off 2 | /* ****************************************************************************************************************** */ 3 | // u-blox positioning receivers configuration tool 4 | // 5 | // Copyright (c) Philippe Kehl (flipflip at oinkzwurgl dot org) and contributors 6 | // 7 | // This program is free software: you can redistribute it and/or modify it under the terms of the 8 | // GNU General Public License as published by the Free Software Foundation, either version 3 of the 9 | // License, or (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 12 | // even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | // See the GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License along with this program. 16 | // If not, see . 17 | 18 | #include 19 | #include 20 | 21 | #include "ff_rx.h" 22 | 23 | #ifndef __CFGTOOL_RESET_H__ 24 | #define __CFGTOOL_RESET_H__ 25 | 26 | /* ****************************************************************************************************************** */ 27 | 28 | const char *resetHelp(void); 29 | 30 | int resetRun(const char *portArg, const char *resetArg); 31 | 32 | bool resetTypeFromStr(const char *resetType, RX_RESET_t *reset); 33 | 34 | 35 | /* ****************************************************************************************************************** */ 36 | #endif // __CFGTOOL_RESET_H__ 37 | -------------------------------------------------------------------------------- /cfgtool/cfgtool_cmd2rx.h: -------------------------------------------------------------------------------- 1 | // clang-format off 2 | /* ****************************************************************************************************************** */ 3 | // u-blox positioning receivers configuration tool 4 | // 5 | // Copyright (c) Philippe Kehl (flipflip at oinkzwurgl dot org) and contributors 6 | // 7 | // This program is free software: you can redistribute it and/or modify it under the terms of the 8 | // GNU General Public License as published by the Free Software Foundation, either version 3 of the 9 | // License, or (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 12 | // even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | // See the GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License along with this program. 16 | // If not, see . 17 | 18 | /* ****************************************************************************************************************** */ 19 | 20 | #ifndef __CFGTOOL_CMD2RX_H__ 21 | #define __CFGTOOL_CMD2RX_H__ 22 | 23 | #include 24 | 25 | /* ****************************************************************************************************************** */ 26 | 27 | const char *cmd2rxHelp(void); 28 | int cmd2rxRun(const char *portArg, const bool noProbe, const bool extraInfo); 29 | 30 | /* ****************************************************************************************************************** */ 31 | #endif // __CFGTOOL_CMD2RX_H__ 32 | -------------------------------------------------------------------------------- /cfgtool/README.md: -------------------------------------------------------------------------------- 1 | # cfgtool -- u-blox positioning receivers configuration tool 2 | 3 | Copyright (c) Philippe Kehl (flipflip at oinkzwurgl dot org) and contributors 4 | 5 | https://oinkzwurgl.org/projaeggd/ubloxcfg/ 6 | 7 | [License](./LICENSE): GNU General Public License (GPL) v3 8 | 9 | ## Overview 10 | 11 | A command line app to configure a receiver from the configuration defined in a human-readable configuration file, 12 | as well as a few other functions. 13 | 14 | This uses some gcc/libc stuff ("GNU99"). 15 | 16 | The `cfgtool` command line tool can do the following: 17 | 18 | - Configure a receiver from a configuration text file 19 | - Receiver connection on local serial ports, remote raw TCP/IP ports or telnet (incl. RFC2217) connections 20 | - Retrieve configuration from a receiver 21 | - Convert a config text file into UBX-CFG-VALSET messages, output as binary UBX messages, u-center compatible hex 22 | dumps, or c code 23 | - Display receiver navigation status 24 | - And more... 25 | 26 | Run `cfgtool -h` or see [`cfgtool.txt`](./cfgtool.txt) for more information. 27 | 28 | ## Build and install 29 | 30 | First, build and install the [ubloxcfg library](../ubloxcfg/README.md) and the [ff library](../ff/README.md). Then build 31 | cfgtool: 32 | 33 | ```sh 34 | cmake -B build -S . -DCMAKE_INSTALL_PREFIX=/wherever/you/want/it 35 | cmake --build build 36 | cmake --install build 37 | ``` 38 | 39 | Dev command: 40 | 41 | ```sh 42 | clear; rm -rf build; cmake -B build -S . -DCMAKE_INSTALL_PREFIX=/tmp/ub && cmake --build build --verbose && cmake --install build 43 | ``` 44 | 45 | ## See also 46 | 47 | - [../README.md](../README.md) 48 | -------------------------------------------------------------------------------- /cfgtool/cfgtool_rx2cfg.h: -------------------------------------------------------------------------------- 1 | // clang-format off 2 | /* ****************************************************************************************************************** */ 3 | // u-blox positioning receivers configuration tool 4 | // 5 | // Copyright (c) Philippe Kehl (flipflip at oinkzwurgl dot org) and contributors 6 | // 7 | // This program is free software: you can redistribute it and/or modify it under the terms of the 8 | // GNU General Public License as published by the Free Software Foundation, either version 3 of the 9 | // License, or (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 12 | // even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | // See the GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License along with this program. 16 | // If not, see . 17 | 18 | #include 19 | #include 20 | 21 | #ifndef __CFGTOOL_RX2CFG_H__ 22 | #define __CFGTOOL_RX2CFG_H__ 23 | 24 | /* ****************************************************************************************************************** */ 25 | 26 | const char *rx2cfgHelp(void); 27 | int rx2cfgRun(const char *portArg, const char *layerArg, const bool useUnknownItems, const bool extraInfo); 28 | 29 | const char *rx2listHelp(void); 30 | int rx2listRun(const char *portArg, const char *layerArg, const bool useUnknownItems, const bool extraInfo); 31 | 32 | /* ****************************************************************************************************************** */ 33 | #endif // __CFGTOOL_RX2CFG_H__ 34 | -------------------------------------------------------------------------------- /cfgtool/cfgtool_cfg2ubx.h: -------------------------------------------------------------------------------- 1 | // clang-format off 2 | /* ****************************************************************************************************************** */ 3 | // u-blox positioning receivers configuration tool 4 | // 5 | // Copyright (c) Philippe Kehl (flipflip at oinkzwurgl dot org) and contributors 6 | // 7 | // This program is free software: you can redistribute it and/or modify it under the terms of the 8 | // GNU General Public License as published by the Free Software Foundation, either version 3 of the 9 | // License, or (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 12 | // even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | // See the GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License along with this program. 16 | // If not, see . 17 | 18 | #include 19 | #include 20 | 21 | #ifndef __CFGTOOL_CFG2UBX_H__ 22 | #define __CFGTOOL_CFG2UBX_H__ 23 | 24 | /* ****************************************************************************************************************** */ 25 | 26 | const char *cfg2ubxHelp(void); 27 | int cfg2ubxRun(const char *layerArg, const bool extraInfo, const bool allow_replace); 28 | int cfg2hexRun(const char *layerArg, const bool extraInfo, const bool allow_replace); 29 | int cfg2cRun(const char *layerArg, const bool extraInfo, const bool allow_replace); 30 | 31 | /* ****************************************************************************************************************** */ 32 | #endif // __CFGTOOL_CFG2UBX_H__ 33 | -------------------------------------------------------------------------------- /ff/ff_spartn.h: -------------------------------------------------------------------------------- 1 | // clang-format off 2 | // flipflip's SPARTN protocol stuff 3 | // 4 | // Copyright (c) Philippe Kehl (flipflip at oinkzwurgl dot org) and contributors 5 | // https://oinkzwurgl.org/projaeggd/ubloxcfg/ 6 | // 7 | // This program is free software: you can redistribute it and/or modify it under the terms of the 8 | // GNU General Public License as published by the Free Software Foundation, either version 3 of the 9 | // License, or (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 12 | // even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | // See the GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License along with this program. 16 | // If not, see . 17 | 18 | #ifndef __FF_SPARTN_H__ 19 | #define __FF_SPARTN_H__ 20 | 21 | #include 22 | #include 23 | 24 | #ifdef __cplusplus 25 | extern "C" { 26 | #endif 27 | 28 | /* ****************************************************************************************************************** */ 29 | 30 | #define SPARTN_PREAMBLE 0x73 31 | #define SPARTN_MIN_HEAD_SIZE 8 32 | 33 | bool spartnMessageName(char *name, const int size, const uint8_t *msg, const int msgSize); 34 | 35 | bool spartnMessageInfo(char *info, const int size, const uint8_t *msg, const int msgSize); 36 | 37 | const char *spartnTypeDesc(const int msgType, const int subType); 38 | 39 | /* ****************************************************************************************************************** */ 40 | #ifdef __cplusplus 41 | } 42 | #endif 43 | #endif // __FF_SPARTN_H__ 44 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # u-blox positioning receivers configuration library and tool 2 | 3 | Copyright (c) Philippe Kehl (flipflip at oinkzwurgl dot org) and contributors 4 | 5 | https://oinkzwurgl.org/projaeggd/ubloxcfg/ 6 | 7 | This repository contains: 8 | 9 | - The [ubloxcfg](./ubloxcfg/README.md) library to deal with the configuration interface of u-blox position receivers 10 | - The [ff](./ff/README.md) utility library 11 | - The [cfgtool](./cfgtool/README.md) command line app to configure a receiver 12 | 13 | This is tested on Linux ([GCC](https://gcc.gnu.org/)). 14 | 15 | Some of it might work on Windows (using [Mingw-w64](http://mingw-w64.org)). I wouldn't know... 16 | 17 | [![CI](/../../actions/workflows/ci.yml/badge.svg)](/../../actions) 18 | 19 | ## Building 20 | 21 | Install dependencies (see [CI workflow](./actions/workflows/ci.yml/badge.svg) for an up-to-date list). 22 | 23 | ```sh 24 | apt install gcc libpath-tiny-perl libdata-float-perl 25 | ``` 26 | 27 | Either build and install the individual components (ubloxcfg, ff, cfgtool) or use the top-level CMake: 28 | 29 | ```sh 30 | cmake -B build -S . # add -DNO_CODEGEN=ON to skip (re-)generating ubloxcfg_gen.[ch] 31 | cmake --build build --parallel 8 32 | ./build/ubloxcfg/ubloxcfg-test 33 | ./build/cfgtool/cfgtool -h 34 | ``` 35 | 36 | Build and install: 37 | 38 | ```sh 39 | cmake -B build -S . -DCMAKE_INSTALL_PREFIX=/wherever/you/want/it 40 | cmake --build build --parallel 8 41 | cmake --install build 42 | /wherever/you/want/it/bin/cfgtool -h 43 | ``` 44 | 45 | Alternatively, a Makefile is available. Run `make help` for details. 46 | 47 | 48 | ## Licenses 49 | 50 | Se the LICENSE files for the various packages in this repository: [ubloxcfg/LICENSE](./ubloxcfg/LICENSE), 51 | [ff/LICENSE](./ff/LICENSE), [cfgtool/LICENSE](./cfgtool/LICENSE) 52 | 53 | 54 | -------------------------------------------------------------------------------- /cfgtool/cfgtool_cfg2rx.h: -------------------------------------------------------------------------------- 1 | // clang-format off 2 | /* ****************************************************************************************************************** */ 3 | // u-blox positioning receivers configuration tool 4 | // 5 | // Copyright (c) Philippe Kehl (flipflip at oinkzwurgl dot org) and contributors 6 | // 7 | // This program is free software: you can redistribute it and/or modify it under the terms of the 8 | // GNU General Public License as published by the Free Software Foundation, either version 3 of the 9 | // License, or (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 12 | // even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | // See the GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License along with this program. 16 | // If not, see . 17 | 18 | #include 19 | #include 20 | 21 | #include "ff_ubx.h" 22 | 23 | #include "ubloxcfg/ubloxcfg.h" 24 | 25 | #ifndef __CFGTOOL_CFG2RX_H__ 26 | #define __CFGTOOL_CFG2RX_H__ 27 | 28 | /* ****************************************************************************************************************** */ 29 | 30 | const char *cfg2rxHelp(void); 31 | int cfg2rxRun(const char *portArg, const char *layerArg, const char *resetArg, const bool applyConfig, const bool updateOnly, const bool allowReplace); 32 | 33 | // --------------------------------------------------------------------------------------------------------------------- 34 | 35 | UBLOXCFG_KEYVAL_t *cfgToKeyVal(int *nKv, const bool allowReplace); 36 | 37 | /* ****************************************************************************************************************** */ 38 | #endif // __CFGTOOL_RX2CFG_H__ 39 | -------------------------------------------------------------------------------- /ff/ff_crc.h: -------------------------------------------------------------------------------- 1 | // clang-format off 2 | // flipflip's CRC stuff 3 | // 4 | // Copyright (c) Philippe Kehl (flipflip at oinkzwurgl dot org) and contributors 5 | // https://oinkzwurgl.org/projaeggd/ubloxcfg/ 6 | // 7 | // This program is free software: you can redistribute it and/or modify it under the terms of the 8 | // GNU General Public License as published by the Free Software Foundation, either version 3 of the 9 | // License, or (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 12 | // even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | // See the GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License along with this program. 16 | // If not, see . 17 | 18 | #ifndef __FF_CRC_H__ 19 | #define __FF_CRC_H__ 20 | 21 | #include 22 | #include 23 | 24 | #ifdef __cplusplus 25 | extern "C" { 26 | #endif 27 | 28 | /* ****************************************************************************************************************** */ 29 | 30 | uint32_t crcRtcm3(const uint8_t *data, const int len); 31 | uint32_t crcSpartn4(const uint8_t *data, const int len); // frame CRC 32 | uint32_t crcSpartn8(const uint8_t *data, const int len); // type 0 33 | uint32_t crcSpartn16(const uint8_t *data, const int len); // type 1 34 | uint32_t crcSpartn24(const uint8_t *data, const int len); // type 2, same as crcRtcm3() 35 | uint32_t crcSpartn32(const uint8_t *data, const int len); // type 3 36 | uint32_t crcNovatel32(const uint8_t *data, const int len); 37 | 38 | /* ****************************************************************************************************************** */ 39 | #ifdef __cplusplus 40 | } 41 | #endif 42 | #endif // __FF_CRC_H__ 43 | -------------------------------------------------------------------------------- /ff/ff_stuff.c: -------------------------------------------------------------------------------- 1 | // clang-format off 2 | // flipflip's Allencheibs 3 | // 4 | // Copyright (c) Philippe Kehl (flipflip at oinkzwurgl dot org) and contributors 5 | // https://oinkzwurgl.org/projaeggd/ubloxcfg/ 6 | // 7 | // This program is free software: you can redistribute it and/or modify it under the terms of the 8 | // GNU General Public License as published by the Free Software Foundation, either version 3 of the 9 | // License, or (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 12 | // even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | // See the GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License along with this program. 16 | // If not, see . 17 | 18 | #include 19 | #include 20 | #ifdef _WIN32 21 | # define NOGDI 22 | # include 23 | #endif 24 | 25 | #include "ff_stuff.h" 26 | 27 | /* ****************************************************************************************************************** */ 28 | 29 | uint64_t TIME(void) 30 | { 31 | static uint64_t t0 = 0; 32 | struct timespec tp; 33 | clock_gettime(CLOCK_MONOTONIC, &tp); 34 | uint64_t t = (tp.tv_sec * 1000) + (tp.tv_nsec / 1000000); 35 | if (t0 == 0) 36 | { 37 | t0 = t; 38 | return 0; 39 | } 40 | 41 | return t - t0; 42 | } 43 | 44 | void SLEEP(uint32_t dur) 45 | { 46 | #ifdef _WIN32 47 | Sleep(dur); 48 | #else 49 | usleep(dur * 1000); 50 | #endif 51 | } 52 | 53 | uint64_t timeOfDay(void) 54 | { 55 | struct timespec ts; 56 | clock_gettime(CLOCK_REALTIME, &ts); 57 | uint64_t t = ts.tv_sec % 86400; 58 | t *= 1000; 59 | t += ts.tv_nsec / 1000000; 60 | return t; 61 | } 62 | 63 | /* ****************************************************************************************************************** */ 64 | // eof 65 | -------------------------------------------------------------------------------- /ubloxcfg/README.md: -------------------------------------------------------------------------------- 1 | # ubloxcfg -- u-blox positioning receivers configuration library 2 | 3 | Copyright (c) Philippe Kehl (flipflip at oinkzwurgl dot org) and contributors 4 | 5 | https://oinkzwurgl.org/projaeggd/ubloxcfg/ 6 | 7 | [License](./LICENSE): GNU Lesser General Public License (LGPL) 8 | 9 | ## Overview 10 | 11 | This implements a library (API) do deal with the new configuration interface introduced in u-blox generation 9 positioning receivers. 12 | 13 | See the references in [ubloxcfg-50-ublox.jsonc](./ubloxcfg-50-ublox.jsonc). 14 | 15 | The ubloxcfg library is thread-safe, free of dynamic memory allocation and written in c (ISO C99 with no further 16 | dependencies). 17 | 18 | 19 | ## Build and install 20 | 21 | ```sh 22 | cmake -B build -S . -DCMAKE_INSTALL_PREFIX=/wherever/you/want/it 23 | cmake --build build 24 | cmake --install build 25 | ``` 26 | 27 | Dev command: 28 | 29 | ```sh 30 | clear; rm -rf build; cmake -B build -S . -DCMAKE_INSTALL_PREFIX=/tmp/ub && cmake --build build --verbose && cmake --install build 31 | ``` 32 | 33 | ## Configuration definitions 34 | 35 | The definitions for the configuration items (parameters) have been taken from u-blox manuals and converted into a JSON 36 | file (with comments): [`ubloxcfg-50-ublox.jsonc`](./ubloxcfg-50-ublox.jsonc). 37 | 38 | The [`ubloxcfg_gen.pl`](./ubloxcfg_gen.pl) script converts this to c source code: 39 | [`ubloxcfg_gen.h`](./ubloxcfg_gen.h) and [`ubloxcfg_gen.c`](./ubloxcfg_gen.c). 40 | 41 | ## Configuration library 42 | 43 | The configuration library provides the following: 44 | 45 | - Type definitions for configuration items (size, data types, IDs) 46 | - Functions to look up information on a configuration item (by name, by ID) 47 | - Functions to help configuring output message rates. 48 | - Helper macros to define lists of key-value pairs 49 | - Functions to encode lists of key-value pairs into configuration data (and the reverse) 50 | - Functions to stringify configuration items 51 | - A function to convert strings into values 52 | 53 | See [`ubloxcfg.h`](./ubloxcfg.h) for details and examples. 54 | 55 | ## See also 56 | 57 | - [../README.md](../README.md) 58 | -------------------------------------------------------------------------------- /ff/ff_trafo.h: -------------------------------------------------------------------------------- 1 | // clang-format off 2 | // flipflip's (WGS84) transformation functions 3 | // 4 | // Copyright (c) Philippe Kehl (flipflip at oinkzwurgl dot org) and contributors 5 | // https://oinkzwurgl.org/projaeggd/ubloxcfg/ 6 | // 7 | // This program is free software: you can redistribute it and/or modify it under the terms of the 8 | // GNU General Public License as published by the Free Software Foundation, either version 3 of the 9 | // License, or (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 12 | // even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | // See the GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License along with this program. 16 | // If not, see . 17 | 18 | #ifndef __FF_TRAFO_H__ 19 | #define __FF_TRAFO_H__ 20 | 21 | #include 22 | #include 23 | 24 | #ifdef __cplusplus 25 | extern "C" { 26 | #endif 27 | 28 | /* ****************************************************************************************************************** */ 29 | 30 | double rad2deg(const double rad); 31 | 32 | double deg2rad(const double deg); 33 | 34 | void deg2dms(const double deg, int *d, int *m, double *s); 35 | 36 | void llh2xyz_vec(const double llh[3], double xyz[3]); 37 | void llh2xyz_deg(const double lat, const double lon, const double height, double *x, double *y, double *z); 38 | void llh2xyz_rad(const double lat, const double lon, const double height, double *x, double *y, double *z); 39 | 40 | void xyz2llh_vec(const double xyz[3], double llh[3]); 41 | void xyz2llh_deg(const double x, const double y, const double z, double *lat, double *lon, double *height); 42 | void xyz2llh_rad(const double x, const double y, const double z, double *lat, double *lon, double *height); 43 | 44 | // FIXME: this is more like xyzxyz2enu() 45 | void xyz2enu_vec(const double xyz[3], const double xyzRef[3], const double llhRef[3], double enu[3]); 46 | // FIXME: this is more like enuxyz2xyz() 47 | void enu2xyz_vec(const double enu[3], const double xyzRef[3], const double llhRef[3], double xyz[3]); 48 | 49 | void xyz2ned_vec(const double ned[3], const double llhRef[3], double xyz[3]); 50 | 51 | /* ****************************************************************************************************************** */ 52 | #ifdef __cplusplus 53 | } 54 | #endif 55 | #endif // __FF_TRAFO_H__ 56 | -------------------------------------------------------------------------------- /cfgtool/cfgtool_util.h: -------------------------------------------------------------------------------- 1 | // clang-format off 2 | /* ****************************************************************************************************************** */ 3 | // u-blox positioning receivers configuration tool 4 | // 5 | // Copyright (c) Philippe Kehl (flipflip at oinkzwurgl dot org) and contributors 6 | // 7 | // This program is free software: you can redistribute it and/or modify it under the terms of the 8 | // GNU General Public License as published by the Free Software Foundation, either version 3 of the 9 | // License, or (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 12 | // even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | // See the GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License along with this program. 16 | // If not, see . 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include "ubloxcfg/ubloxcfg.h" 24 | #include "ff_debug.h" 25 | #include "ff_stuff.h" 26 | 27 | #ifndef __CFGTOOL_UTIL_H__ 28 | #define __CFGTOOL_UTIL_H__ 29 | 30 | /* ****************************************************************************************************************** */ 31 | 32 | #define EXIT_BADARGS 1 33 | #define EXIT_RXFAIL 2 34 | #define EXIT_RXNODATA 3 35 | #define EXIT_OTHERFAIL 99 36 | 37 | typedef struct IO_LINE_s 38 | { 39 | char *line; 40 | int lineNr; 41 | int lineLen; 42 | const char *file; 43 | 44 | } IO_LINE_t; 45 | 46 | void ioSetOutput(const char *name, FILE *file, const bool overwrite); 47 | void ioSetInput(const char *name, FILE *file); 48 | IO_LINE_t *ioGetNextInputLine(void); 49 | int ioReadInput(uint8_t *data, const int size); 50 | void ioOutputStr(const char *fmt, ...); 51 | void ioAddOutputBin(const uint8_t *data, const int size); 52 | void ioAddOutputHex(const uint8_t *data, const int size, const int wordsPerLine, const bool ugly); 53 | void ioAddOutputHexdump(const uint8_t *data, const int size); 54 | void ioAddOutputC(const uint8_t *data, const int size, const int wordsPerLine, const char *indent); 55 | bool ioWriteOutput(const bool append); 56 | 57 | bool layersStringToFlags(const char *layers, bool *ram, bool *bbr, bool *flash, bool *def); 58 | 59 | /* ****************************************************************************************************************** */ 60 | #endif // __CFGTOOL_UTIL_H__ 61 | -------------------------------------------------------------------------------- /ff/ff_debug.h: -------------------------------------------------------------------------------- 1 | // clang-format off 2 | // flipflip's colourful (printf style) debugging stuff 3 | // 4 | // Copyright (c) Philippe Kehl (flipflip at oinkzwurgl dot org) and contributors 5 | // https://oinkzwurgl.org/projaeggd/ubloxcfg/ 6 | // 7 | // This program is free software: you can redistribute it and/or modify it under the terms of the 8 | // GNU General Public License as published by the Free Software Foundation, either version 3 of the 9 | // License, or (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 12 | // even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | // See the GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License along with this program. 16 | // If not, see . 17 | 18 | #ifndef __FF_DEBUG_H__ 19 | #define __FF_DEBUG_H__ 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | #ifdef _WIN32 26 | # ifndef NOGDI 27 | # define NOGDI 28 | # endif 29 | # include 30 | #endif 31 | 32 | #include "ff_stuff.h" 33 | 34 | #ifdef __cplusplus 35 | extern "C" { 36 | #endif 37 | 38 | /* ****************************************************************************************************************** */ 39 | 40 | typedef enum DEBUG_LEVEL_e 41 | { 42 | DEBUG_LEVEL_ERROR = -2, 43 | DEBUG_LEVEL_WARNING = -1, 44 | DEBUG_LEVEL_NOTICE = 0, 45 | DEBUG_LEVEL_PRINT = 1, 46 | DEBUG_LEVEL_DEBUG = 2, 47 | DEBUG_LEVEL_TRACE = 3, 48 | } DEBUG_LEVEL_t; 49 | 50 | typedef struct DEBUG_CFG_s DEBUG_CFG_t; 51 | 52 | typedef struct DEBUG_CFG_s 53 | { 54 | DEBUG_LEVEL_t level; 55 | bool colour; 56 | const char *mark; 57 | void (*func)(DEBUG_LEVEL_t level, const char *line, const DEBUG_CFG_t *); 58 | void *arg; 59 | 60 | } DEBUG_CFG_t; 61 | 62 | void debugSetup(const DEBUG_CFG_t *cfg); 63 | 64 | void debugGetCfg(DEBUG_CFG_t *cfg); 65 | 66 | void ERROR(const char *fmt, ...) PRINTF_ATTR(1); 67 | void WARNING(const char *fmt, ...) PRINTF_ATTR(1); 68 | void NOTICE(const char *fmt, ...) PRINTF_ATTR(1); 69 | void PRINT(const char *fmt, ...) PRINTF_ATTR(1); 70 | void DEBUG(const char *fmt, ...) PRINTF_ATTR(1); 71 | void TRACE(const char *fmt, ...) PRINTF_ATTR(1); 72 | 73 | void PANIC_AND_EXIT(const char *fmt, ...) PRINTF_ATTR(1); 74 | 75 | bool isDEBUG(void); 76 | bool isTRACE(void); 77 | 78 | void DEBUG_HEXDUMP(const void *data, const int size, const char *fmt, ...) PRINTF_ATTR(3); 79 | void TRACE_HEXDUMP(const void *data, const int size, const char *fmt, ...) PRINTF_ATTR(3); 80 | 81 | void DEBUGGER_BREAK(void); 82 | 83 | /* ****************************************************************************************************************** */ 84 | #ifdef __cplusplus 85 | } 86 | #endif 87 | #endif // __FF_DEBUG_H__ 88 | -------------------------------------------------------------------------------- /contrib/main.c: -------------------------------------------------------------------------------- 1 | // Library test program 2 | // Copyright (c) 2021 Charles Parent (charles.parent@orolia2s.com) 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | int main() 17 | { 18 | RX_ARGS_t args = RX_ARGS_DEFAULT(); 19 | RX_t *rx = rxInit("/dev/ttyS2", &args); 20 | if ((rx == NULL || !rxOpen(rx))) { 21 | free(rx); 22 | printf("rx init failed\n"); 23 | return -1; 24 | } 25 | 26 | uint32_t nMsgs = 0, sMsgs = 0; 27 | 28 | const uint64_t tOffs = TIME() - timeOfDay(); // Offset between wall clock and parser time reference 29 | 30 | EPOCH_t coll; 31 | EPOCH_t epoch; 32 | epochInit(&coll); 33 | 34 | printf("Dumping received data...\n"); 35 | while (true) 36 | { 37 | PARSER_MSG_t *msg = rxGetNextMessage(rx); 38 | if (msg != NULL) 39 | { 40 | nMsgs++; 41 | sMsgs += msg->size; 42 | const uint32_t latency = (msg->ts - tOffs) % 1000; // Relative to wall clock top of second 43 | 44 | 45 | const char *prot = "?"; 46 | switch (msg->type) 47 | { 48 | case PARSER_MSGTYPE_UBX: 49 | prot = "UBX"; 50 | break; 51 | case PARSER_MSGTYPE_NMEA: 52 | prot = "NMEA"; 53 | break; 54 | case PARSER_MSGTYPE_RTCM3: 55 | prot = "RTMC3"; 56 | break; 57 | case PARSER_MSGTYPE_GARBAGE: 58 | prot = "GARBAGE"; 59 | break; 60 | } 61 | 62 | if (msg->type == PARSER_MSGTYPE_UBX) { 63 | printf("message %4u, dt %4u, size %4d, %-8s %-20s %s\n", 64 | msg->seq, latency, msg->size, prot, msg->name, msg->info != NULL ? msg->info : "n/a"); 65 | epochCollect(&coll, msg, &epoch); 66 | printf("EPOCH data is:\n"); 67 | printf("Fix: %d, Fix Ok %s, LepSecKnow %s, Hours %d, Minutes %d Seconds %f\n", 68 | epoch.fix, 69 | epoch.fixOk ? "TRUE" : "FALSE", 70 | epoch.leapSecKnown ? "TRUE" : "FALSE", 71 | epoch.hour, 72 | epoch.minute, 73 | epoch.second 74 | ); 75 | 76 | struct tm t; 77 | time_t t_of_day; 78 | t.tm_year = epoch.year - 1900; // Year - 1900 79 | t.tm_mon = epoch.month - 1; // Month, where 0 = jan 80 | t.tm_mday = epoch.day; // Day of the month 81 | t.tm_hour = epoch.hour; 82 | t.tm_min = epoch.minute; 83 | t.tm_sec = epoch.second; 84 | t.tm_isdst = -1; // Is DST on? 1 = yes, 0 = no, -1 = unknown 85 | t_of_day = mktime(&t); 86 | 87 | printf("seconds since the Epoch: %ld\n", (long) t_of_day); 88 | 89 | if (epoch.haveLeapSeconds) { 90 | printf("leaps seconds count is %d\n", epoch.leapSeconds); 91 | } 92 | if (epoch.haveLeapSecondEvent) { 93 | printf("lsChange is %d, dateOfLsGpsWn is %d and dateofLsFpsDn is %d\n", 94 | epoch.lsChange, 95 | epoch.dateOfLsGpsWn, 96 | epoch.dateOfLsGpsDn 97 | ); 98 | } 99 | } 100 | 101 | } else { 102 | usleep(5 * 1000); 103 | } 104 | } 105 | 106 | rxClose(rx); 107 | free(rx); 108 | return 0; 109 | } 110 | -------------------------------------------------------------------------------- /ff/ff_port.h: -------------------------------------------------------------------------------- 1 | // clang-format off 2 | // flipflip's serial port library 3 | // 4 | // Copyright (c) Philippe Kehl (flipflip at oinkzwurgl dot org) and contributors 5 | // https://oinkzwurgl.org/projaeggd/ubloxcfg/ 6 | // 7 | // This program is free software: you can redistribute it and/or modify it under the terms of the 8 | // GNU General Public License as published by the Free Software Foundation, either version 3 of the 9 | // License, or (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 12 | // even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | // See the GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License along with this program. 16 | // If not, see . 17 | 18 | #ifndef __FF_PORT_H__ 19 | #define __FF_PORT_H__ 20 | 21 | #include 22 | #include 23 | 24 | #ifdef __cplusplus 25 | extern "C" { 26 | #endif 27 | 28 | /* ****************************************************************************************************************** */ 29 | 30 | #define PORT_BAUDRATES 9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600 31 | #ifdef _WIN32 32 | # define PORT_BAUDVALUES 9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600 33 | #else 34 | # define PORT_BAUDVALUES B9600, B19200, B38400, B57600, B115200, B230400, B460800, B921600 35 | #endif 36 | 37 | #define PORT_SPEC_MAX_LEN 256 38 | 39 | typedef enum PORT_TYPE_e 40 | { 41 | PORT_TYPE_SER, // Serial ports: ser://[@baudrate] 42 | PORT_TYPE_TCP, // TCP/IP sockets: tcp://: 43 | PORT_TYPE_TELNET // TCP/IP sockets with telnet (RFC854 etc.) and com port control (RFC2217): telnet://:[@] 44 | //PORT_TYPE_HANDLE // Use existing file handle (or pair of file handles, such as stdin/stdout) 45 | } PORT_TYPE_t; 46 | 47 | typedef struct PORT_s 48 | { 49 | PORT_TYPE_t type; 50 | uint32_t numRx; 51 | uint32_t numTx; 52 | bool portOk; 53 | int baudrate; 54 | char file[PORT_SPEC_MAX_LEN]; 55 | #ifdef _WIN32 56 | void *handle; 57 | #else 58 | int fd; 59 | #endif 60 | // tcp 61 | uint16_t port; 62 | uint64_t lastTime; 63 | int lastCount; 64 | // telnet 65 | int tnState; 66 | uint8_t tnInband[12]; 67 | int nTnInband; 68 | char tmp[PORT_SPEC_MAX_LEN + 32]; 69 | uint32_t lastWarn; 70 | } PORT_t; 71 | 72 | bool portInit(PORT_t *port, const char *spec); 73 | bool portOpen(PORT_t *port); 74 | void portClose(PORT_t *port); 75 | bool portWrite(PORT_t *port, const uint8_t *data, const int size); 76 | bool portRead(PORT_t *port, uint8_t *data, const int size, int *read); 77 | bool portCanBaudrate(PORT_t *port); 78 | bool portSetBaudrate(PORT_t *port, const int baudrate); 79 | int portGetBaudrate(PORT_t *port); 80 | 81 | /* ****************************************************************************************************************** */ 82 | #ifdef __cplusplus 83 | } 84 | #endif 85 | #endif // __FF_PORT_H__ 86 | -------------------------------------------------------------------------------- /cfgtool/cfgtool_bin2hex.c: -------------------------------------------------------------------------------- 1 | // clang-format off 2 | /* ****************************************************************************************************************** */ 3 | // u-blox positioning receivers configuration tool 4 | // 5 | // Copyright (c) Philippe Kehl (flipflip at oinkzwurgl dot org) and contributors 6 | // 7 | // This program is free software: you can redistribute it and/or modify it under the terms of the 8 | // GNU General Public License as published by the Free Software Foundation, either version 3 of the 9 | // License, or (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 12 | // even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | // See the GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License along with this program. 16 | // If not, see . 17 | 18 | #include 19 | #include 20 | //#include 21 | //#include 22 | 23 | #include "ubloxcfg/ubloxcfg.h" 24 | 25 | #include "cfgtool_util.h" 26 | 27 | #include "cfgtool_bin2hex.h" 28 | 29 | /* ****************************************************************************************************************** */ 30 | 31 | const char *bin2hexHelp(void) 32 | { 33 | return 34 | // ----------------------------------------------------------------------------- 35 | "Commands 'bin2hex' and 'hex2bin':\n" 36 | "\n" 37 | " Usage: cfgtool bin2hex [-i ] [-o ] [-y]\n" 38 | " cfgtool hex2bin [-i ] [-o ] [-y]\n" 39 | "\n" 40 | " Convert data from or to u-center style hex dump.\n" 41 | "\n" 42 | " Example:\n" 43 | "\n" 44 | " echo 48 61 6B 75 6E 61 20 4D 61 74 61 74 61 21 0A | cfgtool -q hex2bin\n" 45 | "\n"; 46 | } 47 | 48 | #define NUM_WORDS (64 / 4) 49 | 50 | int bin2hexRun(void) 51 | { 52 | ioWriteOutput(false); 53 | while (true) 54 | { 55 | uint8_t buf[NUM_WORDS * 4]; 56 | const int num = ioReadInput(buf, sizeof(buf)); 57 | if (num > 0) 58 | { 59 | ioAddOutputHex(buf, num, NUM_WORDS, true); 60 | ioWriteOutput(true); 61 | } 62 | else 63 | { 64 | break; 65 | } 66 | } 67 | return ioWriteOutput(true) ? EXIT_SUCCESS : EXIT_OTHERFAIL; 68 | } 69 | 70 | int hex2binRun(void) 71 | { 72 | ioWriteOutput(false); 73 | bool inputOk = true; 74 | while (inputOk) 75 | { 76 | IO_LINE_t *line = ioGetNextInputLine(); 77 | if (line != NULL) 78 | { 79 | const char *sep = " "; 80 | for (char *save = NULL, *tok = strtok_r(line->line, sep, &save); tok != NULL; tok = strtok_r(NULL, sep, &save)) 81 | { 82 | uint8_t b; 83 | int n = 0; 84 | if ( (sscanf(tok, "%2hhx%n", &b, &n) == 1) && (n == 2) ) 85 | { 86 | ioAddOutputBin(&b, 1); 87 | } 88 | else 89 | { 90 | WARNING("%s:%d: Bad input ('%s')!", line->file, line->lineNr, tok); 91 | inputOk = false; 92 | } 93 | } 94 | } 95 | else 96 | { 97 | break; 98 | } 99 | } 100 | const bool writeOk = ioWriteOutput(true); 101 | return writeOk && inputOk ? EXIT_SUCCESS : EXIT_OTHERFAIL; 102 | } 103 | 104 | /* ****************************************************************************************************************** */ 105 | // eof 106 | -------------------------------------------------------------------------------- /ff/ff_stuff.h: -------------------------------------------------------------------------------- 1 | // clang-format off 2 | // flipflip's Allencheibs 3 | // 4 | // Copyright (c) Philippe Kehl (flipflip at oinkzwurgl dot org) and contributors 5 | // https://oinkzwurgl.org/projaeggd/ubloxcfg/ 6 | // 7 | // This program is free software: you can redistribute it and/or modify it under the terms of the 8 | // GNU General Public License as published by the Free Software Foundation, either version 3 of the 9 | // License, or (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 12 | // even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | // See the GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License along with this program. 16 | // If not, see . 17 | 18 | #ifndef __FF_STUFF_H__ 19 | #define __FF_STUFF_H__ 20 | 21 | #include 22 | #include 23 | 24 | #ifdef __cplusplus 25 | extern "C" { 26 | #endif 27 | 28 | /* ****************************************************************************************************************** */ 29 | 30 | uint64_t TIME(void); 31 | void SLEEP(uint32_t dur); 32 | 33 | uint64_t timeOfDay(void); 34 | 35 | //! Number of elements in array \hideinitializer 36 | #define NUMOF(x) (int)(sizeof(x)/sizeof(*(x))) 37 | 38 | //! Mark variable as unused to silence compiler warnings \hideinitializer 39 | #ifndef UNUSED 40 | # define UNUSED(thing) (void)thing 41 | #endif 42 | 43 | #ifdef _WIN32 44 | # define IF_WIN(x) x 45 | # define NOT_WIN(x) /* nothing */ 46 | #else 47 | # define IF_WIN(x) /* nothing */ 48 | # define NOT_WIN(x) x 49 | #endif 50 | 51 | #if (defined(DEBUG) || defined(_DEBUG) || defined(DBG)) && !defined(NDEBUG) 52 | # define FF_DEBUG 1 53 | #else 54 | # define FF_DEBUG 0 55 | #endif 56 | 57 | #ifndef STRINGIFY 58 | # define STRINGIFY(x) _STRINGIFY(x) //!< preprocessor stringification \hideinitializer 59 | # ifndef __DOXYGEN__ 60 | # define _STRINGIFY(x) #x 61 | # endif 62 | #endif 63 | #ifndef CONCAT 64 | # define CONCAT(a, b) _CONCAT(a, b) //!< preprocessor concatenation \hideinitializer 65 | # ifndef __DOXYGEN__ 66 | # define _CONCAT(a, b) a ## b 67 | # endif 68 | #endif 69 | 70 | 71 | #define MIN(a, b) ((b) < (a) ? (b) : (a)) //!< smaller value of a and b \hideinitializer 72 | #define MAX(a, b) ((b) > (a) ? (b) : (a)) //!< bigger value of a and b \hideinitializer 73 | #define ABS(x) ( (x) < 0 ? -(x) : (x) ) //!< absolute value \hideinitializer 74 | 75 | //! Bit \hideinitializer 76 | #define BIT(bit) (1<<(bit)) 77 | 78 | //! Check if all bit(s) is (are) set \hideinitializer 79 | #define CHKBITS(mask, bits) (((mask) & (bits)) == (bits)) 80 | 81 | //! Check if any bit(s) is (are) set \hideinitializer 82 | #define CHKBITS_ANY(mask, bits) (((mask) & (bits)) != 0) 83 | 84 | //! Sets the bits \hideinitializer 85 | #define SETBITS(mask, bits) ( (mask) |= (bits) ) 86 | 87 | //! Clears the bits \hideinitializer 88 | #define CLRBITS(mask, bits) ( (mask) &= ~(bits) ) 89 | 90 | //! Toggles the bits \hideinitializer 91 | #define TOGBITS(mask, bits) ( (mask) ^= (bits) ) 92 | 93 | #ifndef PRINTF_ATTR 94 | # define PRINTF_ATTR(n) __attribute__ ((format (printf, n, n + 1))) 95 | #endif 96 | 97 | #define CLIP(x, a, b) ((x) <= (a) ? (a) : ((x) >= (b) ? (b) : (x))) //!< Clip value in range [a:b] \hideinitializer 98 | 99 | #ifdef __cplusplus 100 | # ifndef _Static_assert 101 | # define _Static_assert static_assert // static_assert only in c++11 and later 102 | # endif 103 | #endif 104 | 105 | //! Static (compile-time) assertion 106 | #define STATIC_ASSERT(expr) _Static_assert((expr), #expr) 107 | 108 | //! Size of struct member 109 | #define SIZEOF_MEMBER(_type, _member) sizeof((((_type *)NULL)->_member)) 110 | 111 | /* ****************************************************************************************************************** */ 112 | #ifdef __cplusplus 113 | } 114 | #endif 115 | #endif // __FF_STUFF_H__ 116 | -------------------------------------------------------------------------------- /cfgtool/cfgtool_cfginfo.c: -------------------------------------------------------------------------------- 1 | // clang-format off 2 | /* ****************************************************************************************************************** */ 3 | // u-blox positioning receivers configuration tool 4 | // 5 | // Copyright (c) Philippe Kehl (flipflip at oinkzwurgl dot org) and contributors 6 | // 7 | // This program is free software: you can redistribute it and/or modify it under the terms of the 8 | // GNU General Public License as published by the Free Software Foundation, either version 3 of the 9 | // License, or (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 12 | // even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | // See the GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License along with this program. 16 | // If not, see . 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | #include "ubloxcfg/ubloxcfg.h" 23 | 24 | #include "cfgtool_util.h" 25 | 26 | #include "cfgtool_cfginfo.h" 27 | 28 | /* ****************************************************************************************************************** */ 29 | 30 | const char *cfginfoHelp(void) 31 | { 32 | return 33 | // ----------------------------------------------------------------------------- 34 | "Command 'cfginfo':\n" 35 | "\n" 36 | " Usage: cfgtool cfginfo [-o ] [-y]\n" 37 | "\n" 38 | " This generates a list with information on all configuration items and\n" 39 | " messages known to this tool.\n" 40 | "\n"; 41 | } 42 | 43 | /* ****************************************************************************************************************** */ 44 | 45 | int cfginfoRun(void) 46 | { 47 | int numItems = 0; 48 | const UBLOXCFG_ITEM_t **items = ubloxcfg_getAllItems(&numItems); 49 | ioOutputStr("# Item/constant Type Scale Unit Description\n"); 50 | ioOutputStr("#---------------------------------------------------------------------------------------------------------------------\n"); 51 | for (int ix = 0; ix < numItems; ix++) 52 | { 53 | const UBLOXCFG_ITEM_t *it = items[ix]; 54 | ioOutputStr("item %-40s %-2s %-15s %-10s # %s\n", 55 | it->name, 56 | ubloxcfg_typeStr(it->type), 57 | it->scale != NULL ? it->scale : "-", 58 | it->unit != NULL ? it->unit : "-", 59 | it->title); 60 | for (int ix2 = 0; ix2 < it->nConsts; ix2++) 61 | { 62 | const UBLOXCFG_CONST_t *co = &it->consts[ix2]; 63 | ioOutputStr("const %-20s %-18s # %s\n", 64 | co->name, 65 | co->value, 66 | co->title); 67 | } 68 | } 69 | 70 | ioOutputStr("\n"); 71 | ioOutputStr("# Message UART1 UART2 SPI I2C USB\n"); 72 | ioOutputStr("#-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n"); 73 | int numRates = 0; 74 | const UBLOXCFG_MSGRATE_t **rates = ubloxcfg_getAllMsgRateCfgs(&numRates); 75 | for (int ix = 0; ix < numRates; ix++) 76 | { 77 | const UBLOXCFG_MSGRATE_t *ra = rates[ix]; 78 | ioOutputStr("message %-30s %-35s %-35s %-35s %-35s %-35s\n", 79 | ra->msgName, 80 | ra->itemUart1 != NULL ? ra->itemUart1->name : "-", 81 | ra->itemUart2 != NULL ? ra->itemUart2->name : "-", 82 | ra->itemSpi != NULL ? ra->itemSpi->name : "-", 83 | ra->itemI2c != NULL ? ra->itemI2c->name : "-", 84 | ra->itemUsb != NULL ? ra->itemUsb->name : "-"); 85 | } 86 | 87 | return ioWriteOutput(false) ? EXIT_SUCCESS : EXIT_OTHERFAIL; 88 | } 89 | 90 | /* ****************************************************************************************************************** */ 91 | // eof 92 | -------------------------------------------------------------------------------- /ff/ff_parser.h: -------------------------------------------------------------------------------- 1 | // clang-format off 2 | // flipflip's UBX/NMEA/RTCM3 message parser 3 | // 4 | // Copyright (c) Philippe Kehl (flipflip at oinkzwurgl dot org) and contributors 5 | // https://oinkzwurgl.org/projaeggd/ubloxcfg/ 6 | // 7 | // This program is free software: you can redistribute it and/or modify it under the terms of the 8 | // GNU General Public License as published by the Free Software Foundation, either version 3 of the 9 | // License, or (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 12 | // even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | // See the GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License along with this program. 16 | // If not, see . 17 | 18 | // This is a UBX, NMEA and RTCM3 message parser. It only parses the frames, not the content 19 | // of the message (it does not decode any message fields). 20 | // The parser will pass-through all data that is input. Unknown parts (other protocols, 21 | // spurious data, incorrect messages, etc.) are output as GARBAGE type messages. GARBAGE messages 22 | // are not guaranteed to be combined and can be split arbitrarily (into several GARBAGE messages). 23 | 24 | #ifndef __FF_PARSER_H__ 25 | #define __FF_PARSER_H__ 26 | 27 | #include 28 | #include 29 | 30 | #ifdef __cplusplus 31 | extern "C" { 32 | #endif 33 | 34 | /* ****************************************************************************************************************** */ 35 | 36 | #define PARSER_BUF_SIZE 32768 // must be >= 2*PARSER_MAX_ANY_SIZE (FIXME: does it?) 37 | #define PARSER_MAX_UBX_SIZE 8192 // messages larger than this will be GARBAGE 38 | #define PARSER_MAX_NMEA_SIZE 400 // messages larger than this will be GARBAGE 39 | #define PARSER_MAX_RTCM3_SIZE 4096 // messages larger than this will be GARBAGE 40 | #define PARSER_MAX_NOVATEL_SIZE 4096 // messages larger than this will be GARBAGE 41 | #define PARSER_MAX_GARB_SIZE 4096 42 | #define PARSER_MAX_ANY_SIZE 16384 // the largest of the above 43 | #define PARSER_MAX_NAME_SIZE 100 44 | #define PARSER_MAX_INFO_SIZE 1000 45 | 46 | typedef struct PARSER_s 47 | { 48 | // Parser state, don't mess with this 49 | uint8_t buf[PARSER_BUF_SIZE]; 50 | int size; 51 | int offs; 52 | uint8_t tmp[PARSER_MAX_ANY_SIZE]; 53 | char name[PARSER_MAX_NAME_SIZE]; 54 | char info[PARSER_MAX_INFO_SIZE]; 55 | // Statistics (number and size of all messages reps. of protocol) 56 | uint32_t nMsgs; 57 | uint32_t sMsgs; 58 | uint32_t nNmea; 59 | uint32_t sNmea; 60 | uint32_t nUbx; 61 | uint32_t sUbx; 62 | uint32_t nRtcm3; 63 | uint32_t sRtcm3; 64 | uint32_t nSpartn; 65 | uint32_t sSpartn; 66 | uint32_t nNovatel; 67 | uint32_t sNovatel; 68 | uint32_t nGarbage; 69 | uint32_t sGarbage; 70 | 71 | } PARSER_t; 72 | 73 | typedef enum PARSER_MSGTYPE_e 74 | { 75 | PARSER_MSGTYPE_GARBAGE, 76 | PARSER_MSGTYPE_UBX, 77 | PARSER_MSGTYPE_NMEA, 78 | PARSER_MSGTYPE_RTCM3, 79 | PARSER_MSGTYPE_SPARTN, 80 | PARSER_MSGTYPE_NOVATEL, 81 | } PARSER_MSGTYPE_t; 82 | 83 | typedef enum PARSER_MSGSRC_e 84 | { 85 | PARSER_MSGSRC_UNKN = 0, 86 | PARSER_MSGSRC_FROM_RX, 87 | PARSER_MSGSRC_TO_RX, 88 | PARSER_MSGSRC_VIRTUAL, 89 | PARSER_MSGSRC_USER, 90 | PARSER_MSGSRC_LOG 91 | } PARSER_MSGSRC_t; 92 | 93 | typedef struct PARSER_MSG_s 94 | { 95 | PARSER_MSGTYPE_t type; 96 | const uint8_t *data; 97 | int size; 98 | uint32_t seq; 99 | uint64_t ts; 100 | PARSER_MSGSRC_t src; 101 | const char *name; 102 | const char *info; // may be NULL 103 | } PARSER_MSG_t; 104 | 105 | void parserInit(PARSER_t *parser); 106 | bool parserAdd(PARSER_t *parser, const uint8_t *data, const int size); 107 | bool parserProcess(PARSER_t *parser, PARSER_MSG_t *msg, const bool info); 108 | bool parserFlush(PARSER_t *parser, PARSER_MSG_t *msg); 109 | 110 | const char *parserMsgtypeName(const PARSER_MSGTYPE_t type); 111 | 112 | /* ****************************************************************************************************************** */ 113 | #ifdef __cplusplus 114 | } 115 | #endif 116 | #endif // __FF_PARSER_H__ 117 | -------------------------------------------------------------------------------- /cfgtool/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ######################################################################################################################## 2 | # 3 | # cfgtool -- u-blox positioning receivers configuration tool 4 | # 5 | # Copyright (c) Philippe Kehl (flipflip at oinkzwurgl dot org) and contributors 6 | # 7 | # This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public 8 | # License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later 9 | # version. 10 | # 11 | # This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied 12 | # warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License along with this program. 15 | # If not, see . 16 | # 17 | ######################################################################################################################## 18 | 19 | # GENERAL ============================================================================================================== 20 | 21 | cmake_minimum_required(VERSION 3.16) 22 | include(../cmake/setup.cmake) 23 | 24 | project(cfgtool 25 | LANGUAGES C 26 | VERSION ${FF_VERSION_NUMBER} 27 | DESCRIPTION "ubloxcfg tool" 28 | ) 29 | 30 | 31 | # COMPILER SETUP ======================================================================================================= 32 | 33 | set(CMAKE_C_STANDARD 99) 34 | set(CMAKE_C_EXTENSIONS ON) 35 | set(CMAKE_C_STANDARD_REQUIRED ON) 36 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Werror \ 37 | -Wshadow -Wunused-parameter -Wformat -Wpointer-arith -Wundef") 38 | set(CMAKE_C_FLAGS_RELEASE "-O3") 39 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 40 | if(NOT CMAKE_BUILD_TYPE) 41 | set(CMAKE_BUILD_TYPE Release) 42 | endif() 43 | if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug") 44 | add_compile_definitions(NDEBUG) 45 | endif() 46 | 47 | 48 | # DEPENDENCIES ========================================================================================================= 49 | 50 | if(NOT TARGET ubloxcfg) 51 | find_package(ubloxcfg REQUIRED) 52 | endif() 53 | if(NOT TARGET ff) 54 | find_package(ff REQUIRED) 55 | endif() 56 | 57 | 58 | # EXECUTABLES ========================================================================================================== 59 | 60 | file(GLOB C_FILES *.c) 61 | file(GLOB H_FILES *.h) 62 | message(STATUS "ff: C_FILES=${C_FILES}") 63 | message(STATUS "ff: H_FILES=${H_FILES}") 64 | 65 | list(APPEND CMAKE_INSTALL_RPATH $ORIGIN) 66 | list(APPEND CMAKE_INSTALL_RPATH $ORIGIN/../lib) 67 | 68 | add_executable(${PROJECT_NAME} ${C_FILES}) 69 | target_link_libraries(${PROJECT_NAME} 70 | PRIVATE 71 | ubloxcfg 72 | ff 73 | m 74 | ) 75 | 76 | # GENERATED HELP ======================================================================================================= 77 | 78 | if(NOT NO_CODEGEN) 79 | add_custom_command( 80 | OUTPUT ${PROJECT_SOURCE_DIR}/cfgtool.txt 81 | COMMAND ${PROJECT_NAME} -H > ${PROJECT_SOURCE_DIR}/cfgtool.txt 82 | DEPENDS ${PROJECT_NAME} ${C_FILES} ${H_FILES} 83 | ) 84 | 85 | add_custom_target(${PROJECT_NAME}-help ALL DEPENDS ${PROJECT_SOURCE_DIR}/cfgtool.txt) 86 | endif() 87 | 88 | # INSTALL ============================================================================================================== 89 | 90 | include(GNUInstallDirs) # Provides nice relative paths wrt CMAKE_INSTALL_PREFIX 91 | set(PROJECT_RUNTIME_DIR ${CMAKE_INSTALL_FULL_BINDIR}) 92 | set(PROJECT_LIBRARY_DIR ${CMAKE_INSTALL_FULL_LIBDIR}) 93 | set(PROJECT_INCLUDE_DIR ${CMAKE_INSTALL_FULL_INCLUDEDIR}/${PROJECT_NAME}) 94 | set(PROJECT_DATA_DIR ${CMAKE_INSTALL_FULL_DATAROOTDIR}/${PROJECT_NAME}) 95 | set(PROJECT_DOC_DIR ${CMAKE_INSTALL_FULL_DOCDIR}) 96 | 97 | install(TARGETS ${PROJECT_NAME} 98 | EXPORT ${PROJECT_NAME}-targets 99 | RUNTIME DESTINATION ${PROJECT_RUNTIME_DIR} 100 | ) 101 | 102 | install( 103 | FILES 104 | ${PROJECT_SOURCE_DIR}/README.md 105 | ${PROJECT_SOURCE_DIR}/LICENSE 106 | DESTINATION ${PROJECT_DOC_DIR} 107 | ) 108 | 109 | if(NOT NO_CODEGEN) 110 | install( 111 | FILES 112 | ${PROJECT_SOURCE_DIR}/cfgtool.txt 113 | DESTINATION ${PROJECT_DOC_DIR} 114 | ) 115 | endif() 116 | 117 | ######################################################################################################################## 118 | -------------------------------------------------------------------------------- /ff/ff_time.c: -------------------------------------------------------------------------------- 1 | // clang-format off 2 | // flipflip's time functions 3 | // 4 | // Copyright (c) Philippe Kehl (flipflip at oinkzwurgl dot org) and contributors 5 | // https://oinkzwurgl.org/projaeggd/ubloxcfg/ 6 | // 7 | // This program is free software: you can redistribute it and/or modify it under the terms of the 8 | // GNU General Public License as published by the Free Software Foundation, either version 3 of the 9 | // License, or (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 12 | // even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | // See the GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License along with this program. 16 | // If not, see . 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | #include "ff_debug.h" 23 | 24 | #include "ff_time.h" 25 | 26 | /* ****************************************************************************************************************** */ 27 | 28 | #define GPS_POSIX_OFFS (3657*86400) // Offset [s] from POSIX epoch to GPS epoch 29 | #define WEEK (7*86400) // Number of seconds in a week 30 | #define GPS_TAI_OFFSET 19 // TAI (International Atomic Time) - GPS time 31 | 32 | // --------------------------------------------------------------------------------------------------------------------- 33 | 34 | static int sLeapSecAtTs(const double ts) 35 | { 36 | // See IERS bulletin C (https://hpiers.obspm.fr/iers/bul/bulc/bulletinc.dat) 37 | if (ts > 1356393618.0) // 2022-12-30 2242:432018 (see IERS "Bulletin C" #63 January 2022) 38 | { 39 | static bool warned = false; 40 | if (!warned) 41 | { 42 | WARNING("No leap second information!"); 43 | warned = true; 44 | } 45 | return 37 - GPS_TAI_OFFSET; // = 37 - 19 = 18 46 | } 47 | else if (ts >= 1167264000.0) { return 18; } // 2017-01-01 1930:000000 (see IERS "Bulletin C" #52 January 2016) 48 | else if (ts >= 1119744000.0) { return 17; } // 2015-07-01 1851:259200 49 | else if (ts >= 1025136000.0) { return 16; } // 2012-07-01 1695:000000 50 | else if (ts >= 914803200.0) { return 15; } // 2009-01-01 1512:345600 51 | else if (ts >= 820108800.0) { return 14; } // 2006-01-01 1356:000000 52 | else if (ts >= 598795200.0) { return 13; } // 1999-01-01 0990:043200 53 | else if (ts >= 551750400.0) { return 12; } // 1997-07-01 0912:172800 54 | else if (ts >= 504489600.0) { return 11; } // 1996-01-01 0834:086400 55 | else if (ts >= 457056000.0) { return 10; } // 1994-07-01 0755:432000 56 | else if (ts >= 425520000.0) { return 9; } // 1993-07-01 0703:345600 57 | else if (ts >= 393984000.0) { return 8; } // 1992-07-01 0651:259200 58 | else if (ts >= 346723200.0) { return 7; } // 1991-01-01 0573:172800 59 | else if (ts >= 315187200.0) { return 6; } // 1990-01-01 0512:086400 60 | else if (ts >= 251640000.0) { return 5; } // 1988-01-01 0416:043200 61 | else if (ts >= 173059200.0) { return 4; } // 1985-07-01 0286:086400 62 | else if (ts >= 109900800.0) { return 3; } // 1983-07-01 0181:432000 63 | else if (ts >= 62726400.0) { return 2; } // 1982-01-01 0103:432000 64 | else if (ts >= 31190400.0) { return 1; } // 1981-01-01 0051:345600 65 | else if (ts >= 0.0) { return 0; } // 1980-01-06 0000:000000 66 | else { return 0; } // FIXME: warn? 67 | } 68 | 69 | // --------------------------------------------------------------------------------------------------------------------- 70 | 71 | double wnoTow2ts(const int wno, const double tow) 72 | { 73 | return (double)(wno * WEEK) + tow; 74 | } 75 | 76 | // --------------------------------------------------------------------------------------------------------------------- 77 | 78 | double ts2posix(const double ts, const int leapSec, const bool leapSecValid) 79 | { 80 | if (leapSecValid) 81 | { 82 | return ts + (double)(GPS_POSIX_OFFS - leapSec); 83 | } 84 | else 85 | { 86 | return ts + (double)(GPS_POSIX_OFFS - sLeapSecAtTs(ts)); 87 | } 88 | } 89 | 90 | 91 | // --------------------------------------------------------------------------------------------------------------------- 92 | 93 | double posixNow() 94 | { 95 | struct timespec ts; 96 | clock_gettime(CLOCK_REALTIME, &ts); 97 | return (double)ts.tv_sec + ((double)ts.tv_nsec * 1e-9); 98 | } 99 | 100 | /* ****************************************************************************************************************** */ 101 | // eof 102 | -------------------------------------------------------------------------------- /ff/ff_novatel.h: -------------------------------------------------------------------------------- 1 | // clang-format off 2 | // flipflip's NOVATEL protocol stuff 3 | // 4 | // Copyright (c) Philippe Kehl (flipflip at oinkzwurgl dot org) and contributors 5 | // https://oinkzwurgl.org/projaeggd/ubloxcfg/ 6 | // 7 | // This program is free software: you can redistribute it and/or modify it under the terms of the 8 | // GNU General Public License as published by the Free Software Foundation, either version 3 of the 9 | // License, or (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 12 | // even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | // See the GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License along with this program. 16 | // If not, see . 17 | 18 | #ifndef __FF_NOVATEL_H__ 19 | #define __FF_NOVATEL_H__ 20 | 21 | #include 22 | #include 23 | 24 | #include "ubloxcfg/ubloxcfg.h" 25 | 26 | #ifdef __cplusplus 27 | extern "C" { 28 | #endif 29 | 30 | /* ****************************************************************************************************************** */ 31 | 32 | #define NOVATEL_SYNC_1 0xaa 33 | #define NOVATEL_SYNC_2 0x44 34 | #define NOVATEL_SYNC_3_LONG 0x12 35 | #define NOVATEL_SYNC_3_SHORT 0x13 36 | 37 | #define NOVATEL_MSGID(msg) ( ((uint16_t)((uint8_t *)msg)[5] << 8) | (uint16_t)((uint8_t *)msg)[4] ) 38 | 39 | #define NOVATEL_BESTPOS_MSGID 42 40 | #define NOVATEL_BESTXYZ_MSGID 241 41 | #define NOVATEL_BESTUTM_MSGID 726 42 | #define NOVATEL_BESTVEL_MSGID 99 43 | #define NOVATEL_CORRIMUS_MSGID 2264 44 | #define NOVATEL_HEADING2_MSGID 1335 45 | #define NOVATEL_IMURATECORRIMUS_MSGID 1362 46 | #define NOVATEL_INSCONFIG_MSGID 1945 47 | #define NOVATEL_INSPVAS_MSGID 508 48 | #define NOVATEL_INSPVAX_MSGID 1465 49 | #define NOVATEL_INSSTDEV_MSGID 2051 50 | #define NOVATEL_PSRDOP2_MSGID 1163 51 | #define NOVATEL_RXSTATUS_MSGID 93 52 | #define NOVATEL_TIME_MSGID 101 53 | #define NOVATEL_RAWIMUSX_MSGID 1462 54 | #define NOVATEL_RAWDMI_MSGID 2269 55 | #define NOVATEL_RAWIMU_MSGID 268 56 | #define NOVATEL_INSPVA_MSGID 507 57 | #define NOVATEL_BESTGNSSPOS_MSGID 1429 58 | 59 | #define NOVATEL_MESSAGES(_P_) \ 60 | _P_(NOVATEL_BESTPOS_MSGID, "BESTPOS") \ 61 | _P_(NOVATEL_BESTXYZ_MSGID, "BESTXYZ") \ 62 | _P_(NOVATEL_BESTUTM_MSGID, "BESTUTM") \ 63 | _P_(NOVATEL_BESTVEL_MSGID, "BESTVEL") \ 64 | _P_(NOVATEL_CORRIMUS_MSGID, "CORRIMUS") \ 65 | _P_(NOVATEL_HEADING2_MSGID, "HEADING2") \ 66 | _P_(NOVATEL_IMURATECORRIMUS_MSGID, "IMURATECORRIMUS") \ 67 | _P_(NOVATEL_INSCONFIG_MSGID, "INSCONFIG") \ 68 | _P_(NOVATEL_INSPVAS_MSGID, "INSPVAS") \ 69 | _P_(NOVATEL_INSPVAX_MSGID, "INSPVAX") \ 70 | _P_(NOVATEL_INSSTDEV_MSGID, "INSSTDEV") \ 71 | _P_(NOVATEL_PSRDOP2_MSGID, "PSRDOP2") \ 72 | _P_(NOVATEL_RXSTATUS_MSGID, "RXSTATUS") \ 73 | _P_(NOVATEL_TIME_MSGID, "TIME") \ 74 | _P_(NOVATEL_RAWIMUSX_MSGID, "RAWIMUSX") \ 75 | _P_(NOVATEL_RAWDMI_MSGID, "RAWDMI") \ 76 | _P_(NOVATEL_RAWIMU_MSGID, "RAWIMU") \ 77 | _P_(NOVATEL_INSPVA_MSGID, "INSPVA") \ 78 | _P_(NOVATEL_BESTGNSSPOS_MSGID, "BESTGNSSPOS") 79 | 80 | typedef struct NOVATEL_HEADER_LONG_s 81 | { 82 | uint8_t sync1; 83 | uint8_t sync2; 84 | uint8_t sync3; 85 | uint8_t headerLen; 86 | uint16_t msgId; 87 | uint8_t msgType; 88 | uint8_t portAddr; 89 | uint16_t msgLen; 90 | uint16_t seq; 91 | uint8_t idleTime; 92 | uint8_t timeStatus; 93 | uint16_t gpsWeek; 94 | uint32_t gpsTowMs; 95 | uint32_t rxStatus; 96 | uint16_t reserved; 97 | uint16_t swVersion; 98 | } NOVATEL_HEADER_LONG_t; 99 | 100 | typedef struct NOVATEL_HEADER_SHORT_s 101 | { 102 | uint8_t sync1; 103 | uint8_t sync2; 104 | uint8_t sync3; 105 | uint8_t msgLen; 106 | uint16_t msgId; 107 | uint16_t gpsWeek; 108 | uint32_t gpsTowMs; 109 | } NOVATEL_HEADER_SHORT_t; 110 | 111 | typedef struct NOVATEL_RAWDMI_PAYLOAD_s 112 | { 113 | int32_t dmi1; 114 | int32_t dmi2; 115 | int32_t dmi3; 116 | int32_t dmi4; 117 | int32_t mask; 118 | } NOVATEL_RAWDMI_PAYLOAD_t; 119 | 120 | bool novatelMessageName(char *name, const int size, const uint8_t *msg, const int msgSize); 121 | bool novatelMessageInfo(char *info, const int size, const uint8_t *msg, const int msgSize); 122 | 123 | /* ****************************************************************************************************************** */ 124 | #ifdef __cplusplus 125 | } 126 | #endif 127 | #endif // __FF_UBX_H__ 128 | -------------------------------------------------------------------------------- /ff/ff_rx.h: -------------------------------------------------------------------------------- 1 | // clang-format off 2 | // flipflip's u-blox positioning receiver control library 3 | // 4 | // Copyright (c) Philippe Kehl (flipflip at oinkzwurgl dot org) and contributors 5 | // https://oinkzwurgl.org/projaeggd/ubloxcfg/ 6 | // 7 | // This program is free software: you can redistribute it and/or modify it under the terms of the 8 | // GNU General Public License as published by the Free Software Foundation, either version 3 of the 9 | // License, or (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 12 | // even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | // See the GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License along with this program. 16 | // If not, see . 17 | 18 | #ifndef __FF_RX_H__ 19 | #define __FF_RX_H__ 20 | 21 | #include 22 | #include 23 | 24 | #include "ubloxcfg/ubloxcfg.h" 25 | #include "ff_parser.h" 26 | 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #endif 30 | 31 | /* ****************************************************************************************************************** */ 32 | 33 | //! Receiver handle 34 | typedef struct RX_s RX_t; 35 | 36 | //! Receiver detection 37 | typedef enum RX_DET_e 38 | { 39 | RX_DET_NONE = 0, //!< No receiver detection, assume port settings are correct and receiver is present 40 | RX_DET_UBX, //!< Actively check for a u-blox receiver 41 | RX_DET_PASSIVE, //!< Passively check for any receiver (that outputs messages using a known protocol) 42 | } RX_DET_t; 43 | 44 | //! Receiver options 45 | typedef struct RX_OPTS_s 46 | { 47 | RX_DET_t detect; //!< Receiver detection method 48 | bool autobaud; //!< Automatically find baudrate (on ports that can change baudrate, and only for detect != RX_DET_NONE) 49 | int baudrate; //!< (Initial) baudrate 50 | bool verbose; //!< Print what's going on for some operations 51 | char *name; //!< Name of the receiver (automatic if NULL) 52 | void (*msgcb)(PARSER_MSG_t *, void *arg); //!< Optional callback for every message received 53 | void *cbarg; //!< Optional user argument for callback 54 | } RX_OPTS_t; 55 | 56 | #define RX_OPTS_DEFAULT() { .detect = RX_DET_UBX, .autobaud = true, .baudrate = 0, .verbose = true, .name = NULL, .msgcb = NULL, .cbarg = NULL } 57 | 58 | RX_t *rxInit(const char *port, const RX_OPTS_t *opts); 59 | 60 | bool rxOpen(RX_t *rx); 61 | void rxClose(RX_t *rx); 62 | 63 | PARSER_MSG_t *rxGetNextMessage(RX_t *rx); 64 | PARSER_MSG_t *rxGetNextMessageTimeout(RX_t *rx, const uint32_t timeout); 65 | 66 | bool rxSend(RX_t *rx, const uint8_t *data, const int size); 67 | 68 | bool rxAutobaud(RX_t *rx); 69 | int rxGetBaudrate(RX_t *rx); 70 | bool rxSetBaudrate(RX_t *rx, const int baudrate); 71 | 72 | void rxAbort(RX_t *rx); 73 | 74 | const PARSER_t *rxGetParser(RX_t *rx); 75 | 76 | /* ****************************************************************************************************************** */ 77 | 78 | bool rxGetVerStr(RX_t *rx, char *str, const int size); 79 | 80 | typedef struct RX_POLL_UBX_s 81 | { 82 | uint8_t clsId; 83 | uint8_t msgId; 84 | const uint8_t *payload; 85 | int payloadSize; 86 | uint32_t timeout; 87 | int retries; 88 | int respSizeMin; 89 | } RX_POLL_UBX_t; 90 | 91 | PARSER_MSG_t *rxPollUbx(RX_t *rx, const RX_POLL_UBX_t *param, bool *pollNak); 92 | 93 | bool rxSendUbxCfg(RX_t *rx, const uint8_t *msg, const int size, const uint32_t timeout); 94 | 95 | typedef enum RX_RESET_e 96 | { 97 | RX_RESET_NONE, // No reset 98 | RX_RESET_SOFT, // Controlled software reset 99 | RX_RESET_HARD, // Controlled hardware reset 100 | RX_RESET_HOT, // Hotstart (like u-center) 101 | RX_RESET_WARM, // Warmstart (like u-center) 102 | RX_RESET_COLD, // Coldstart (like u-center) 103 | RX_RESET_DEFAULT, // Revert config to default, keep nav data 104 | RX_RESET_FACTORY, // Revert config to default and coldstart 105 | RX_RESET_GNSS_STOP, // Stop GNSS (stop navigation) 106 | RX_RESET_GNSS_START, // Start GNSS (start navigation) 107 | RX_RESET_GNSS_RESTART, // Restart GNSS (restart navigation) 108 | RX_RESET_SAFEBOOT, // Safeboot mode 109 | } RX_RESET_t; 110 | 111 | bool rxReset(RX_t *rx, const RX_RESET_t reset); 112 | 113 | const char *rxResetStr(const RX_RESET_t reset); 114 | 115 | int rxGetConfig(RX_t *rx, const UBLOXCFG_LAYER_t layer, const uint32_t *keys, const int numKeys, UBLOXCFG_KEYVAL_t *kv, const int maxKv); 116 | 117 | bool rxSetConfig(RX_t *rx, const UBLOXCFG_KEYVAL_t *kv, const int nKv, const bool ram, const bool bbr, const bool flash); 118 | 119 | /* ****************************************************************************************************************** */ 120 | #ifdef __cplusplus 121 | } 122 | #endif 123 | #endif // __FF_RX_H__ 124 | -------------------------------------------------------------------------------- /ff/ff_spartn.c: -------------------------------------------------------------------------------- 1 | // clang-format off 2 | // flipflip's SPARTN protocol stuff 3 | // 4 | // Copyright (c) Philippe Kehl (flipflip at oinkzwurgl dot org) and contributors 5 | // https://oinkzwurgl.org/projaeggd/ubloxcfg/ 6 | // 7 | // This program is free software: you can redistribute it and/or modify it under the terms of the 8 | // GNU General Public License as published by the Free Software Foundation, either version 3 of the 9 | // License, or (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 12 | // even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | // See the GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License along with this program. 16 | // If not, see . 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | #include "ff_stuff.h" 23 | #include "ff_spartn.h" 24 | 25 | /* ****************************************************************************************************************** */ 26 | 27 | bool spartnMessageName(char *name, const int size, const uint8_t *msg, const int msgSize) 28 | { 29 | if ( (name == NULL) || (size < 1) ) 30 | { 31 | return false; 32 | } 33 | if ( (msg == NULL) || (msgSize < (SPARTN_MIN_HEAD_SIZE + 2)) ) 34 | { 35 | name[0] = '\0'; 36 | return false; 37 | } 38 | const uint32_t msgType = (msg[1] & 0xfe) >> 1; 39 | const uint32_t msgSubType = (msg[4] & 0xf0) >> 4; 40 | const int res = snprintf(name, size, "SPARTN-TYPE%" PRIu32 "_%" PRIu32, msgType, msgSubType); 41 | return res < size; 42 | } 43 | 44 | // --------------------------------------------------------------------------------------------------------------------- 45 | 46 | bool spartnMessageInfo(char *info, const int size, const uint8_t *msg, const int msgSize) 47 | { 48 | if ( (info == NULL) || (size < 1) ) 49 | { 50 | return false; 51 | } 52 | 53 | if ( (msg == NULL) || (msgSize < (SPARTN_MIN_HEAD_SIZE + 2)) ) 54 | { 55 | info[0] = '\0'; 56 | return false; 57 | } 58 | const uint32_t msgType = (msg[1] & 0xfe) >> 1; 59 | const uint32_t subType = (msg[4] & 0xf0) >> 4; 60 | const char *desc = spartnTypeDesc(msgType, subType); 61 | if (desc != NULL) 62 | { 63 | const int res = snprintf(info, size, "%s", desc); 64 | return res < size; 65 | } 66 | else 67 | { 68 | return false; 69 | } 70 | } 71 | 72 | // --------------------------------------------------------------------------------------------------------------------- 73 | 74 | const char *spartnTypeDesc(const int msgType, const int subType) 75 | { 76 | const char *desc = NULL; 77 | switch (msgType) 78 | { 79 | case 0: 80 | switch (subType) 81 | { 82 | case 0: desc = "Orbits, clock, bias (OCB) GPS"; break; 83 | case 1: desc = "Orbits, clock, bias (OCB) GLONASS"; break; 84 | case 2: desc = "Orbits, clock, bias (OCB) Galileo"; break; 85 | case 3: desc = "Orbits, clock, bias (OCB) BeiDou"; break; 86 | case 4: desc = "Orbits, clock, bias (OCB) QZSS"; break; 87 | } 88 | break; 89 | case 1: 90 | switch (subType) 91 | { 92 | case 0: desc = "High-precision atmosphere correction (HPAC) GPS"; break; 93 | case 1: desc = "High-precision atmosphere correction (HPAC) GLONASS"; break; 94 | case 2: desc = "High-precision atmosphere correction (HPAC) Galileo"; break; 95 | case 3: desc = "High-precision atmosphere correction (HPAC) BeiDou"; break; 96 | case 4: desc = "High-precision atmosphere correction (HPAC) QZSS"; break; 97 | } 98 | break; 99 | case 2: 100 | switch (subType) 101 | { 102 | case 0: desc = "Geographic area definition (GAD)"; break; 103 | } 104 | break; 105 | case 3: 106 | switch (subType) 107 | { 108 | case 0: desc = "Basic-precision atmosphere correction (BPAC)"; break; 109 | } 110 | break; 111 | case 4: 112 | switch (subType) 113 | { 114 | case 0: desc = "Dynamic key"; break; 115 | case 1: desc = "Group authentication"; break; 116 | } 117 | break; 118 | case 120: 119 | switch (subType) 120 | { 121 | case 0: desc = "proprietary test"; break; 122 | case 1: desc = "u-blox proprietary"; break; 123 | case 2: desc = "Swift proprietary"; break; 124 | } 125 | break; 126 | } 127 | 128 | return desc; 129 | } 130 | 131 | 132 | /* ****************************************************************************************************************** */ 133 | // eof 134 | -------------------------------------------------------------------------------- /cmake/setup.cmake: -------------------------------------------------------------------------------- 1 | ######################################################################################################################## 2 | # Some variables 3 | set(FF_CMAKE_CMD_HELP "cmake -B build -DCMAKE_INSTALL_PREFIX=~/ubloxcfg") 4 | 5 | 6 | ######################################################################################################################## 7 | # (Somewhat) prevent in-source builds 8 | get_filename_component(srcdir "${CMAKE_SOURCE_DIR}" REALPATH) 9 | get_filename_component(bindir "${CMAKE_BINARY_DIR}" REALPATH) 10 | message(STATUS "ff: srcdir=${srcdir}") 11 | message(STATUS "ff: bindir=${bindir}") 12 | if("${srcdir}" STREQUAL "${bindir}") 13 | message(FATAL_ERROR "\n\n ==> Aborting attempt to do a in-source build. Use '${FF_CMAKE_CMD_HELP}'\n\n") 14 | endif() 15 | 16 | 17 | ######################################################################################################################## 18 | # Add install prefix to cmake path. Other libs may be available there. 19 | if(NOT "${CMAKE_INSTALL_PREFIX}" STREQUAL "") 20 | list(APPEND CMAKE_PREFIX_PATH ${CMAKE_INSTALL_PREFIX}) 21 | endif() 22 | 23 | 24 | ######################################################################################################################## 25 | # Get version info from GIT, unless explicitly given by the user (cmake command line) 26 | # TODO: This is executed only once on configuration of the project. That's of course wrong. We'd have to execute this 27 | # always, write/update some.hpp that can be included and properly dependency-managed. There are things like 28 | # https://github.com/andrew-hardin/cmake-git-version-tracking/tree/master, but they're quite involved, too. 29 | 30 | if (NOT FF_VERSION_IS_SET) # Do this only once. E.g. when running the top-level CMakeLists.txt 31 | # - Version supplied on cmake command line (-DVERSION_STRING=x.x.x, -DVERSION_STRING=x.x.x-gggggg) 32 | if (FF_VERSION_STRING) 33 | string(REGEX MATCH "^([0-9]+\.[0-9]+\.[0-9]+).*$" _ ${FF_VERSION_STRING}) 34 | if ("${CMAKE_MATCH_1}" STREQUAL "") 35 | message(FATAL_ERROR "ff: bad FF_VERSION_STRING=${FF_VERSION_STRING}, must be x.x.x or x.x.x-ggggggg") 36 | endif() 37 | set(FF_VERSION_NUMBER "${CMAKE_MATCH_1}") 38 | set(FF_VERSION_STRING "${FF_VERSION_STRING}") 39 | # - Version supplied from VERSION file (release tarballs), but ignore file if is a git repo 40 | elseif(EXISTS ${CMAKE_CURRENT_LIST_DIR}/../../FF_VERSION_NUMBER AND NOT EXISTS ${CMAKE_CURRENT_LIST_DIR}/../../.git) 41 | file(STRINGS ${CMAKE_CURRENT_LIST_DIR}/../../FF_VERSION_NUMBER FF_VERSION_NUMBER LIMIT_COUNT 1) 42 | set(FF_VERSION_NUMBER "${FF_VERSION_NUMBER}") 43 | file(STRINGS ${CMAKE_CURRENT_LIST_DIR}/../../FF_VERSION_STRING FF_VERSION_STRING LIMIT_COUNT 1) 44 | set(FF_VERSION_STRING "${FF_VERSION_STRING}") 45 | # - Version from git 46 | else() 47 | execute_process( 48 | COMMAND git -C ${CMAKE_CURRENT_LIST_DIR} describe --dirty --tags --always --exact-match --all --long 49 | OUTPUT_VARIABLE CMD_OUTPUT 50 | OUTPUT_STRIP_TRAILING_WHITESPACE 51 | ) 52 | # tags/fp_9.16.0-0-g9db8f03 at tag, clean 53 | # tags/fp_9.16.0-0-g9db8f03-dirty at tag, dirty 54 | # heads/integ/master-0-geec9255 at commit, clean 55 | # heads/integ/master-0-geec9255-dirty at commit, dirty 56 | 57 | # Anything dirty: version number 0.0.0 and string "0.0.0-dirty" 58 | if("${CMD_OUTPUT}" MATCHES "-dirty") 59 | set(FF_VERSION_NUMBER 0.0.0) 60 | set(FF_VERSION_STRING "${FF_VERSION_NUMBER}-${CMD_OUTPUT}") 61 | # Tags that look like a version: version number x.y.z and string "x.y.z" 62 | elseif("${CMD_OUTPUT}" MATCHES "^tags/([a-z0-9]+_|v|)(0|[1-9][0-9]*).(0|[1-9][0-9]*).(0|[1-9][0-9]*)") 63 | set(FF_VERSION_NUMBER "${CMAKE_MATCH_2}.${CMAKE_MATCH_3}.${CMAKE_MATCH_4}") 64 | set(FF_VERSION_STRING "${FF_VERSION_NUMBER}") 65 | # Anything else: version number 0.0.0 and string "0.0.0-whatevergitsaid" 66 | elseif(NOT "${CMD_OUTPUT}" STREQUAL "") 67 | set(FF_VERSION_NUMBER 0.0.0) 68 | set(FF_VERSION_STRING "${FF_VERSION_NUMBER}-${CMD_OUTPUT}") 69 | # Git failed: version number 0.0.0 and string "0.0.0-dev" 70 | else() 71 | set(FF_VERSION_NUMBER 0.0.0) 72 | set(FF_VERSION_STRING "${FF_VERSION_NUMBER}-dev") 73 | endif() 74 | endif() 75 | 76 | add_compile_definitions(FF_VERSION_NUMBER="${FF_VERSION_NUMBER}") 77 | add_compile_definitions(FF_VERSION_STRING="${FF_VERSION_STRING}") 78 | 79 | # write version info to file 80 | file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/FF_VERSION_NUMBER "${FF_VERSION_NUMBER}") 81 | file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/FF_VERSION_STRING "${FF_VERSION_STRING}") 82 | 83 | set(FF_VERSION_IS_SET ON) 84 | endif() 85 | 86 | 87 | ######################################################################################################################## 88 | # Some debugging 89 | message(STATUS "ff: CMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}") 90 | message(STATUS "ff: CMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH}") 91 | message(STATUS "ff: CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}") 92 | message(STATUS "ff: FF_VERSION_NUMBER=${FF_VERSION_NUMBER}") 93 | message(STATUS "ff: FF_VERSION_STRING=${FF_VERSION_STRING}") 94 | 95 | 96 | ######################################################################################################################## 97 | -------------------------------------------------------------------------------- /ff/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ######################################################################################################################## 2 | # 3 | # ff -- various utilities used by cfgtool 4 | # 5 | # Copyright (c) Philippe Kehl (flipflip at oinkzwurgl dot org) and contributors 6 | # 7 | # This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public 8 | # License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later 9 | # version. 10 | # 11 | # This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied 12 | # warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License along with this program. 15 | # If not, see . 16 | # 17 | ######################################################################################################################## 18 | 19 | # GENERAL ============================================================================================================== 20 | 21 | cmake_minimum_required(VERSION 3.16) 22 | include(../cmake/setup.cmake) 23 | 24 | project(ff 25 | LANGUAGES C 26 | VERSION ${FF_VERSION_NUMBER} 27 | DESCRIPTION "ff library" 28 | ) 29 | 30 | 31 | # COMPILER SETUP ======================================================================================================= 32 | 33 | set(CMAKE_C_STANDARD 99) 34 | set(CMAKE_C_EXTENSIONS ON) 35 | set(CMAKE_C_STANDARD_REQUIRED ON) 36 | set(CMAKE_C_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Werror \ 37 | -Wshadow -Wunused-parameter -Wformat -Wpointer-arith -Wundef") 38 | set(CMAKE_C_FLAGS_RELEASE "-O3") 39 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 40 | if(NOT CMAKE_BUILD_TYPE) 41 | set(CMAKE_BUILD_TYPE Release) 42 | endif() 43 | if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug") 44 | add_compile_definitions(NDEBUG) 45 | endif() 46 | 47 | 48 | # DEPENDENCIES ========================================================================================================= 49 | 50 | if(NOT TARGET ubloxcfg) 51 | find_package(ubloxcfg REQUIRED) 52 | endif() 53 | 54 | 55 | # SHARED LIBRARY ======================================================================================================= 56 | 57 | file(GLOB C_FILES *.c) 58 | file(GLOB H_FILES *.h) 59 | message(STATUS "ff: C_FILES=${C_FILES}") 60 | message(STATUS "ff: H_FILES=${H_FILES}") 61 | 62 | list(APPEND CMAKE_INSTALL_RPATH $ORIGIN) 63 | list(APPEND CMAKE_INSTALL_RPATH $ORIGIN/../lib) 64 | 65 | add_library(${PROJECT_NAME} SHARED ${C_FILES} ${GEN_FILES}) 66 | 67 | target_include_directories(${PROJECT_NAME} 68 | PUBLIC 69 | $ 70 | $ 71 | PRIVATE 72 | $ 73 | ) 74 | 75 | target_link_libraries(${PROJECT_NAME} 76 | PUBLIC 77 | PRIVATE 78 | ubloxcfg 79 | ) 80 | 81 | set_target_properties(${PROJECT_NAME} 82 | PROPERTIES 83 | VERSION ${PROJECT_VERSION} 84 | ) 85 | 86 | 87 | # INSTALL ============================================================================================================== 88 | 89 | include(GNUInstallDirs) # Provides nice relative paths wrt CMAKE_INSTALL_PREFIX 90 | set(PROJECT_RUNTIME_DIR ${CMAKE_INSTALL_FULL_BINDIR}) 91 | set(PROJECT_LIBRARY_DIR ${CMAKE_INSTALL_FULL_LIBDIR}) 92 | set(PROJECT_INCLUDE_DIR ${CMAKE_INSTALL_FULL_INCLUDEDIR}/${PROJECT_NAME}) 93 | set(PROJECT_DATA_DIR ${CMAKE_INSTALL_FULL_DATAROOTDIR}/${PROJECT_NAME}) 94 | set(PROJECT_DOC_DIR ${CMAKE_INSTALL_FULL_DOCDIR}) 95 | 96 | # Headers 97 | install(FILES ${H_FILES} 98 | DESTINATION ${PROJECT_INCLUDE_DIR} 99 | ) 100 | 101 | # Library 102 | install(TARGETS ${PROJECT_NAME} 103 | EXPORT ${PROJECT_NAME}-targets 104 | LIBRARY DESTINATION ${PROJECT_LIBRARY_DIR} 105 | ) 106 | 107 | install( 108 | FILES 109 | ${PROJECT_SOURCE_DIR}/README.md 110 | ${PROJECT_SOURCE_DIR}/LICENSE 111 | DESTINATION ${PROJECT_DOC_DIR} 112 | ) 113 | 114 | # CMake target config 115 | install(EXPORT ${PROJECT_NAME}-targets 116 | NAMESPACE ${PROJECT_NAMESPACE_PREFIX} 117 | FILE ${PROJECT_NAME}-targets.cmake 118 | DESTINATION lib/cmake/${PROJECT_NAME} 119 | ) 120 | 121 | # CMake config 122 | include(CMakePackageConfigHelpers) 123 | set(TARGET1 ${PROJECT_NAME}) 124 | configure_package_config_file( 125 | ${CMAKE_CURRENT_SOURCE_DIR}/../cmake/config.cmake.in 126 | ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake 127 | INSTALL_DESTINATION lib/cmake/${PROJECT_NAME} 128 | NO_SET_AND_CHECK_MACRO 129 | NO_CHECK_REQUIRED_COMPONENTS_MACRO 130 | ) 131 | write_basic_package_version_file( 132 | ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake 133 | VERSION "${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}" 134 | COMPATIBILITY AnyNewerVersion 135 | ) 136 | install( 137 | FILES 138 | ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake 139 | ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake 140 | DESTINATION lib/cmake/${PROJECT_NAME} 141 | ) 142 | 143 | # pkg-config config 144 | include(CMakePackageConfigHelpers) 145 | set(TARGET1 ${PROJECT_NAME}) 146 | configure_package_config_file( 147 | ${CMAKE_CURRENT_SOURCE_DIR}/../cmake/config.pc.in 148 | ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc 149 | INSTALL_DESTINATION lib/cmake/${PROJECT_NAME} 150 | NO_SET_AND_CHECK_MACRO 151 | NO_CHECK_REQUIRED_COMPONENTS_MACRO 152 | ) 153 | install( 154 | FILES 155 | ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc 156 | DESTINATION lib/pkgconfig 157 | ) 158 | 159 | ######################################################################################################################## 160 | -------------------------------------------------------------------------------- /cfgtool/cfgtool_reset.c: -------------------------------------------------------------------------------- 1 | // clang-format off 2 | /* ****************************************************************************************************************** */ 3 | // u-blox positioning receivers configuration tool 4 | // 5 | // Copyright (c) Philippe Kehl (flipflip at oinkzwurgl dot org) and contributors 6 | // 7 | // This program is free software: you can redistribute it and/or modify it under the terms of the 8 | // GNU General Public License as published by the Free Software Foundation, either version 3 of the 9 | // License, or (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 12 | // even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | // See the GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License along with this program. 16 | // If not, see . 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | #include "cfgtool_util.h" 23 | 24 | #include "ff_rx.h" 25 | #include "ff_ubx.h" 26 | 27 | #include "cfgtool_reset.h" 28 | 29 | /* ****************************************************************************************************************** */ 30 | 31 | const char *resetHelp(void) 32 | { 33 | return 34 | // ----------------------------------------------------------------------------- 35 | "Command 'reset':\n" 36 | "\n" 37 | " Usage: cfgtool reset -p -r \n" 38 | "\n" 39 | " This resets the receiver. Depending on the type different parts of\n" 40 | " the navigation data and the configuration are deleted.\n" 41 | "\n" 42 | " Navigation Configuration Reset\n" 43 | " ------------------------------------------------------------\n" 44 | " soft - - (update) Software (controlled)\n" 45 | " hard - - (update) Hardware (controlled)\n" 46 | " hot - - Software (GNSS only)\n" 47 | " warm Ephemerides - Software (GNSS only)\n" 48 | " cold All - Software (GNSS only)\n" 49 | " default - All Hardware (controlled)\n" 50 | " factory All All Hardware (controlled)\n" 51 | " stop - - -\n" 52 | " start - - -\n" 53 | " gnss - - -\n" 54 | " safeboot - - Safeboot\n" 55 | "\n" 56 | " Notes:\n" 57 | "\n" 58 | " All hardware resets cause a USB disconnect, which triggers the the host\n" 59 | " to re-enumerate the device. For local serial s (ser://)\n" 60 | " this is taken into account and should be handled by this command.\n" 61 | " However, this is not 100% reliable. Don't use USB...\n" 62 | "\n" 63 | " The hot, warm, and cold resets use the same command as the corresponding\n" 64 | " buttons in u-center.\n" 65 | "\n" 66 | " The soft and hard resets both trigger a full restart, which includes re-\n" 67 | " freshing the RAM configuration layer.\n" 68 | "\n" 69 | " Note that for hardware resets the navigation and configuration data is\n" 70 | " only preserved with battery backup respectively configuration in the\n" 71 | " Flash layer.\n" 72 | "\n" 73 | " The stop, start and gnss resets do not actually reset anything but\n" 74 | " instead stop, start and restart the GNSS operation.\n" 75 | "\n" 76 | " The safeboot reset makes the receiver restart into safeboot mode.\n" 77 | " Use a 'soft' reset to reboot into normal operation.\n" 78 | "\n"; 79 | } 80 | 81 | /* ****************************************************************************************************************** */ 82 | 83 | bool resetTypeFromStr(const char *resetType, RX_RESET_t *reset) 84 | { 85 | if (strcasecmp("soft", resetType) == 0) 86 | { 87 | *reset = RX_RESET_SOFT; 88 | } 89 | else if (strcasecmp("hard", resetType) == 0) 90 | { 91 | *reset = RX_RESET_HARD; 92 | } 93 | else if (strcasecmp("hot", resetType) == 0) 94 | { 95 | *reset = RX_RESET_HOT; 96 | } 97 | else if (strcasecmp("warm", resetType) == 0) 98 | { 99 | *reset = RX_RESET_WARM; 100 | } 101 | else if (strcasecmp("cold", resetType) == 0) 102 | { 103 | *reset = RX_RESET_COLD; 104 | } 105 | else if (strcasecmp("default", resetType) == 0) 106 | { 107 | *reset = RX_RESET_DEFAULT; 108 | } 109 | else if (strcasecmp("factory", resetType) == 0) 110 | { 111 | *reset = RX_RESET_FACTORY; 112 | } 113 | else if (strcasecmp("stop", resetType) == 0) 114 | { 115 | *reset = RX_RESET_GNSS_STOP; 116 | } 117 | else if (strcasecmp("start", resetType) == 0) 118 | { 119 | *reset = RX_RESET_GNSS_START; 120 | } 121 | else if (strcasecmp("gnss", resetType) == 0) 122 | { 123 | *reset = RX_RESET_GNSS_RESTART; 124 | } 125 | else if (strcasecmp("safeboot", resetType) == 0) 126 | { 127 | *reset = RX_RESET_SAFEBOOT; 128 | } 129 | else 130 | { 131 | WARNING("Invalid argument '-r %s'!", resetType); 132 | return false; 133 | } 134 | return true; 135 | } 136 | 137 | int resetRun(const char *portArg, const char *resetArg) 138 | { 139 | RX_RESET_t reset; 140 | if (!resetTypeFromStr(resetArg, &reset)) 141 | { 142 | return EXIT_BADARGS; 143 | } 144 | 145 | RX_t *rx = rxInit(portArg, NULL); 146 | if ( (rx == NULL) || !rxOpen(rx) ) 147 | { 148 | free(rx); 149 | return EXIT_RXFAIL; 150 | } 151 | 152 | const bool res = rxReset(rx, reset); 153 | 154 | rxClose(rx); 155 | free(rx); 156 | return res ? EXIT_SUCCESS : EXIT_RXFAIL; 157 | } 158 | 159 | /* ****************************************************************************************************************** */ 160 | // eof 161 | -------------------------------------------------------------------------------- /ff/ff_novatel.c: -------------------------------------------------------------------------------- 1 | // clang-format off 2 | // flipflip's NOVATEL protocol stuff 3 | // 4 | // Copyright (c) Philippe Kehl (flipflip at oinkzwurgl dot org) and contributors 5 | // https://oinkzwurgl.org/projaeggd/ubloxcfg/ 6 | // 7 | // This program is free software: you can redistribute it and/or modify it under the terms of the 8 | // GNU General Public License as published by the Free Software Foundation, either version 3 of the 9 | // License, or (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 12 | // even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | // See the GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License along with this program. 16 | // If not, see . 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "ff_stuff.h" 26 | #include "ff_debug.h" 27 | 28 | #include "ff_novatel.h" 29 | 30 | /* ****************************************************************************************************************** */ 31 | 32 | typedef struct MSGINFO_s 33 | { 34 | uint16_t msgId; 35 | const char *msgName; 36 | } MSGINFO_t; 37 | 38 | #define _P_MSGINFO(_msgId_, _msgName_) { .msgId = (_msgId_), .msgName = (_msgName_) }, 39 | 40 | static const MSGINFO_t kMsgInfo[] = 41 | { 42 | NOVATEL_MESSAGES(_P_MSGINFO) 43 | }; 44 | 45 | bool novatelMessageName(char *name, const int size, const uint8_t *msg, const int msgSize) 46 | { 47 | if ( (name == NULL) || (size < 1) || (msgSize < 12) || (msg == NULL) ) 48 | { 49 | return false; 50 | } 51 | 52 | const uint16_t msgId = NOVATEL_MSGID(msg); 53 | 54 | for (int ix = 0; ix < NUMOF(kMsgInfo); ix++) 55 | { 56 | if (kMsgInfo[ix].msgId == msgId) 57 | { 58 | return snprintf(name, size, "NOVATEL-%s", kMsgInfo[ix].msgName) < size; 59 | } 60 | } 61 | 62 | return snprintf(name, size, "NOVATEL-%" PRIu16, msgId) < size; 63 | } 64 | 65 | // --------------------------------------------------------------------------------------------------------------------- 66 | 67 | static int _strNovatelRawdmi(char *info, const int size, const uint8_t *msg, const int msgSize); 68 | static int _strNovatelHeader(char *info, const int size, const uint8_t *msg, const int msgSize); 69 | 70 | bool novatelMessageInfo(char *info, const int size, const uint8_t *msg, const int msgSize) 71 | { 72 | if ( (info == NULL) || (size < 1) ) 73 | { 74 | return false; 75 | } 76 | if ( (msg == NULL) || (msgSize < 6) ) 77 | { 78 | info[0] = '\0'; 79 | return false; 80 | } 81 | 82 | const uint16_t msgId = NOVATEL_MSGID(msg); 83 | int len = 0; 84 | switch (msgId) 85 | { 86 | case NOVATEL_RAWDMI_MSGID: 87 | len = _strNovatelRawdmi(info, size, msg, msgSize); 88 | break; 89 | case NOVATEL_BESTPOS_MSGID: 90 | case NOVATEL_BESTXYZ_MSGID: 91 | case NOVATEL_BESTUTM_MSGID: 92 | case NOVATEL_BESTVEL_MSGID: 93 | case NOVATEL_CORRIMUS_MSGID: 94 | case NOVATEL_HEADING2_MSGID: 95 | case NOVATEL_IMURATECORRIMUS_MSGID: 96 | case NOVATEL_INSCONFIG_MSGID: 97 | case NOVATEL_INSPVAS_MSGID: 98 | case NOVATEL_INSPVAX_MSGID: 99 | case NOVATEL_INSSTDEV_MSGID: 100 | case NOVATEL_PSRDOP2_MSGID: 101 | case NOVATEL_RXSTATUS_MSGID: 102 | case NOVATEL_TIME_MSGID: 103 | case NOVATEL_RAWIMUSX_MSGID: 104 | case NOVATEL_RAWIMU_MSGID: 105 | case NOVATEL_INSPVA_MSGID: 106 | case NOVATEL_BESTGNSSPOS_MSGID: 107 | len = _strNovatelHeader(info, size, msg, msgSize); 108 | break; 109 | } 110 | 111 | return (len > 0) && (len < size); 112 | } 113 | 114 | // --------------------------------------------------------------------------------------------------------------------- 115 | 116 | static int _strNovatelHeader(char *info, const int size, const uint8_t *msg, const int msgSize) 117 | { 118 | if ((msg[2] == NOVATEL_SYNC_3_LONG) && (msgSize >= (int)sizeof(NOVATEL_HEADER_LONG_t))) 119 | { 120 | NOVATEL_HEADER_LONG_t hdr; 121 | memcpy(&hdr, msg, sizeof(hdr)); 122 | return snprintf(info, size, "l %04u:%010.3f", hdr.gpsWeek, (double)hdr.gpsTowMs * 1e-3); 123 | } 124 | else if ((msg[2] == NOVATEL_SYNC_3_SHORT) && (msgSize >= (int)sizeof(NOVATEL_HEADER_SHORT_t))) 125 | { 126 | NOVATEL_HEADER_SHORT_t hdr; 127 | memcpy(&hdr, msg, sizeof(hdr)); 128 | return snprintf(info, size, "s %04u:%010.3f", hdr.gpsWeek, (double)hdr.gpsTowMs * 1e-3); 129 | } 130 | else 131 | { 132 | return 0; 133 | } 134 | } 135 | 136 | // --------------------------------------------------------------------------------------------------------------------- 137 | 138 | #define _CHKSIZE(_type_) \ 139 | ( ((msg[2] == NOVATEL_SYNC_3_LONG) && (msgSize == (sizeof(NOVATEL_HEADER_LONG_t) + sizeof(_type_) + 4))) || \ 140 | ((msg[2] == NOVATEL_SYNC_3_SHORT) && (msgSize == (sizeof(NOVATEL_HEADER_SHORT_t) + sizeof(_type_) + 4))) ) 141 | 142 | #define _PAYLOAD(_type_, _dst_) \ 143 | _type_ _dst_; \ 144 | memcpy(&_dst_, &msg[ msg[2] == NOVATEL_SYNC_3_LONG ? sizeof(NOVATEL_HEADER_LONG_t) : sizeof(NOVATEL_HEADER_SHORT_t) ], sizeof(_dst_)) 145 | 146 | 147 | static int _strNovatelRawdmi(char *info, const int size, const uint8_t *msg, const int msgSize) 148 | { 149 | int len = _strNovatelHeader(info, size, msg, msgSize); 150 | if (_CHKSIZE(NOVATEL_RAWDMI_PAYLOAD_t)) 151 | { 152 | _PAYLOAD(NOVATEL_RAWDMI_PAYLOAD_t, dmi); 153 | len += snprintf(&info[len], size - len, " [%c]=%d [%c]=%d [%c]=%d [%c]=%d", 154 | CHKBITS(dmi.mask, BIT(0)) ? '1' : '.', dmi.dmi1, 155 | CHKBITS(dmi.mask, BIT(1)) ? '2' : '.', dmi.dmi2, 156 | CHKBITS(dmi.mask, BIT(2)) ? '3' : '.', dmi.dmi3, 157 | CHKBITS(dmi.mask, BIT(3)) ? '4' : '.', dmi.dmi4); 158 | } 159 | 160 | return len; 161 | } 162 | 163 | /* ****************************************************************************************************************** */ 164 | // eof 165 | -------------------------------------------------------------------------------- /ff/ff_rtcm3.h: -------------------------------------------------------------------------------- 1 | // clang-format off 2 | // flipflip's RTCM3 protocol stuff 3 | // 4 | // Copyright (c) Philippe Kehl (flipflip at oinkzwurgl dot org) and contributors 5 | // https://oinkzwurgl.org/projaeggd/ubloxcfg/ 6 | // 7 | // This program is free software: you can redistribute it and/or modify it under the terms of the 8 | // GNU General Public License as published by the Free Software Foundation, either version 3 of the 9 | // License, or (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 12 | // even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | // See the GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License along with this program. 16 | // If not, see . 17 | 18 | #ifndef __FF_RTCM3_H__ 19 | #define __FF_RTCM3_H__ 20 | 21 | #include 22 | #include 23 | 24 | #ifdef __cplusplus 25 | extern "C" { 26 | #endif 27 | 28 | /* ****************************************************************************************************************** */ 29 | 30 | #define RTCM3_PREAMBLE 0xd3 31 | #define RTCM3_HEAD_SIZE 3 32 | #define RTCM3_FRAME_SIZE (RTCM3_HEAD_SIZE + 3) 33 | 34 | //! Get message type from message 35 | #define RTCM3_TYPE(msg) ( (((uint8_t *)(msg))[RTCM3_HEAD_SIZE + 0] << 4) | ((((uint8_t *)(msg))[RTCM3_HEAD_SIZE + 1] >> 4) & 0x0f) ) 36 | 37 | //! Get sub-type for RTCM-4072 message 38 | #define RTCM3_4072_SUBTYPE(msg) ( (((uint8_t *)(msg))[RTCM3_HEAD_SIZE + 1] & 0x0f) | (((uint8_t *)(msg))[RTCM3_HEAD_SIZE + 2]) ) 39 | 40 | bool rtcm3MessageName(char *name, const int size, const uint8_t *msg, const int msgSize); 41 | 42 | bool rtcm3MessageInfo(char *info, const int size, const uint8_t *msg, const int msgSize); 43 | 44 | const char *rtcm3TypeDesc(const int msgType, const int subType); 45 | 46 | /* ****************************************************************************************************************** */ 47 | 48 | typedef enum RTCM3_MSM_GNSS_e 49 | { 50 | RTCM3_MSM_GNSS_GPS = 70, 51 | RTCM3_MSM_GNSS_GLO = 80, 52 | RTCM3_MSM_GNSS_GAL = 90, 53 | RTCM3_MSM_GNSS_SBAS = 100, 54 | RTCM3_MSM_GNSS_QZSS = 110, 55 | RTCM3_MSM_GNSS_BDS = 120, 56 | RTCM3_MSM_GNSS_NAVIC = 130, 57 | } RTCM3_MSM_GNSS_t; 58 | 59 | typedef enum RTCM3_MSM_TYPE_e 60 | { 61 | RTCM3_MSM_TYPE_1 = 1, 62 | RTCM3_MSM_TYPE_2 = 2, 63 | RTCM3_MSM_TYPE_3 = 3, 64 | RTCM3_MSM_TYPE_4 = 4, 65 | RTCM3_MSM_TYPE_5 = 5, 66 | RTCM3_MSM_TYPE_6 = 6, 67 | RTCM3_MSM_TYPE_7 = 7, 68 | } RTCM3_MSM_TYPE_t; 69 | 70 | //! RTMC3 message type to MSM GNSS and type 71 | /*! 72 | \param[in] msgType The RTMC3 message type 73 | \param[out] gnss The GNSS 74 | \param[out] msm The MSM type (number) 75 | \returns true if msgType was a valid and known RTCM3 MSM message 76 | */ 77 | bool rtcm3typeToMsm(int msgType, RTCM3_MSM_GNSS_t *gnss, RTCM3_MSM_TYPE_t *msm); 78 | 79 | //! RTCM3 MSM messages common header 80 | typedef struct RTCM3_MSM_HEADER_s 81 | { 82 | RTCM3_MSM_GNSS_t gnss; //!< GNSS 83 | RTCM3_MSM_TYPE_t msm; //!< MSM 84 | 85 | uint16_t msgType; //!< Message number (DF002, uint12) 86 | uint16_t refStaId; //!< Reference station ID (DF003, uint12) 87 | union 88 | { 89 | double anyTow; //!< Any time of week [s] 90 | double gpsTow; //!< GPS time of week [s] (DF004 uint30 [ms]) 91 | double sbasTow; //!< SBAS time of week [s] (DF004 uint30 [ms]) 92 | double gloTow; //!< GLONASS time of week [s] (DF416 uint3 [d], DF034 uint27 [ms]) 93 | double galTow; //!< Galileo time of week [s] (DF248 uint30 [ms]) 94 | double qzssTow; //!< QZSS time of week [s] (DF428 uint30 [ms]) 95 | double bdsTow; //!< BeiDou time of week [s] (DF427 uint30 [ms]) 96 | }; 97 | bool multiMsgBit; //!< Multiple message bit (DF393, bit(1)), 1 = more to follow, 0 = last message 98 | uint8_t iods; //!< IODS, issue of data station (DF409, uint3) 99 | uint8_t clkSteering; //!< Clock steering indicator (DF411, uint2) 100 | uint8_t extClock; //!< External clock indicator (DF412, uint2) 101 | bool smooth; //!< GNSS divergence-free smoothing indicator (DF417, bit(1)) 102 | uint8_t smoothInt; //!< GNSS smoothing interval (DF418, bit(3)) 103 | uint64_t satMask; //!< GNSS satellite mask (DF394, bit(64)) 104 | uint64_t sigMask; //!< GNSS signal mask (DF395, bit(64)) 105 | uint64_t cellMask; //!< GNSS cell mask (DF396, bit(64)) 106 | 107 | int numSat; //!< Number of satellites (in satMask) 108 | int numSig; //!< Number of signals (in sigMask) 109 | int numCell; //!< Number of cells (in cellMask) 110 | 111 | } RTCM3_MSM_HEADER_t; 112 | 113 | bool rtcm3GetMsmHeader(const uint8_t *msg, RTCM3_MSM_HEADER_t *header); 114 | 115 | //! Antenna reference point 116 | typedef struct RTCM3_ARP_s 117 | { 118 | int refStaId; 119 | double X; 120 | double Y; 121 | double Z; 122 | } RTCM3_ARP_t; 123 | 124 | //! Get ARP from message types 1005, 1006 or 1032 125 | bool rtcm3GetArp(const uint8_t *msg, RTCM3_ARP_t *arp); 126 | 127 | //! Antenna info 128 | typedef struct RTCM3_ANT_s 129 | { 130 | int refStaId; 131 | char antDesc[32]; 132 | char antSerial[32]; 133 | uint8_t antSetupId; 134 | char rxType[32]; 135 | char rxFw[32]; 136 | char rxSerial[32]; 137 | } RTCM3_ANT_t; 138 | 139 | //! Get (some) antenna info from message type 1007, 1008 or 1033 140 | bool rtcm3GetAnt(const uint8_t *msg, RTCM3_ANT_t *ant); 141 | 142 | //! Get RTCM3 message IDs ("fake" UBX class and message IDs) 143 | /*! 144 | \param[in] name Message name (e.g. "NMEA-STANDARD-GGA", "NMEA-PUBX-POSITION") 145 | \param[out] clsId Class ID, or NULL 146 | \param[out] msgId Message ID, or NULL 147 | 148 | \returns true if \c name was found and \c clsId and \c msgId are valid 149 | */ 150 | bool rtcm3MessageClsId(const char *name, uint8_t *clsId, uint8_t *msgId); 151 | 152 | /* ****************************************************************************************************************** */ 153 | #ifdef __cplusplus 154 | } 155 | #endif 156 | #endif // __FF_RTCM3_H__ 157 | -------------------------------------------------------------------------------- /cfgtool/cfgtool_cfg2ubx.c: -------------------------------------------------------------------------------- 1 | // clang-format off 2 | /* ****************************************************************************************************************** */ 3 | // u-blox positioning receivers configuration tool 4 | // 5 | // Copyright (c) Philippe Kehl (flipflip at oinkzwurgl dot org) and contributors 6 | // 7 | // This program is free software: you can redistribute it and/or modify it under the terms of the 8 | // GNU General Public License as published by the Free Software Foundation, either version 3 of the 9 | // License, or (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 12 | // even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | // See the GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License along with this program. 16 | // If not, see . 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include "cfgtool_util.h" 24 | #include "ff_ubx.h" 25 | 26 | #include "cfgtool_cfg2rx.h" 27 | #include "cfgtool_cfg2ubx.h" 28 | 29 | /* ****************************************************************************************************************** */ 30 | 31 | const char *cfg2ubxHelp(void) 32 | { 33 | return 34 | // ----------------------------------------------------------------------------- 35 | "Commands 'cfg2ubx', 'cfg2hex' and 'cfg2c':\n" 36 | "\n" 37 | " Usage: cfgtool cfg2ubx [-i ] [-o ] [-y] -l [-R]\n" 38 | " cfgtool cfg2hex [-i ] [-o ] [-y] -l [-R] [-x]\n" 39 | " cfgtool cfg2c [-i ] [-o ] [-y] -l [-R] [-x]\n" 40 | "\n" 41 | " The cfg2ubx, cfg2hex and cfg2c modes convert a configuration file into one\n" 42 | " or more UBX-CFG-VALSET messages, output as binary UBX messages, u-center\n" 43 | " compatible hex dumps, or c code. Optional extra comments can be enabled\n" 44 | " using the -x flag.\n" 45 | " See the 'rx2cfg' command for the specification of the configuration file and\n" 46 | " the documentation of the other flags.\n" 47 | "\n"; 48 | } 49 | 50 | /* ****************************************************************************************************************** */ 51 | 52 | typedef enum FMT_e 53 | { 54 | FMT_UBX, FMT_HEX, FMT_C 55 | } FMT_t; 56 | 57 | static int _cfg2fmt(const char *layerArg, const bool extraInfo, const FMT_t fmt, const bool allow_replace); 58 | 59 | int cfg2ubxRun(const char *layerArg, const bool extraInfo, const bool allow_replace) 60 | { 61 | return _cfg2fmt(layerArg, extraInfo, FMT_UBX, allow_replace); 62 | } 63 | 64 | int cfg2hexRun(const char *layerArg, const bool extraInfo, const bool allow_replace) 65 | { 66 | return _cfg2fmt(layerArg, extraInfo, FMT_HEX, allow_replace); 67 | } 68 | 69 | int cfg2cRun(const char *layerArg, const bool extraInfo, const bool allow_replace) 70 | { 71 | return _cfg2fmt(layerArg, extraInfo, FMT_C, allow_replace); 72 | } 73 | 74 | /* ****************************************************************************************************************** */ 75 | 76 | static int _cfg2fmt(const char *layerArg, const bool extraInfo, const FMT_t fmt, const bool allow_replace) 77 | { 78 | bool ram = false; 79 | bool bbr = false; 80 | bool flash = false; 81 | if (!layersStringToFlags(layerArg, &ram, &bbr, &flash, NULL) || !(ram || bbr || flash)) 82 | { 83 | return EXIT_BADARGS; 84 | } 85 | 86 | PRINT("Loading configuration"); 87 | int nKv = 0; 88 | UBLOXCFG_KEYVAL_t *kv = cfgToKeyVal(&nKv, allow_replace); 89 | if (kv == NULL) 90 | { 91 | return EXIT_OTHERFAIL; 92 | } 93 | 94 | PRINT("Converting %d items into UBX-CFG-VALSET messages", nKv); 95 | int nMsgs = 0; 96 | UBX_CFG_VALSET_MSG_t *msgs = ubxKeyValToUbxCfgValset(kv, nKv, ram, bbr, flash, &nMsgs); 97 | if (msgs == NULL) 98 | { 99 | free(kv); 100 | return EXIT_OTHERFAIL; 101 | } 102 | 103 | int kvOffs = 0; 104 | for (int msgIx = 0; msgIx < nMsgs; msgIx++) 105 | { 106 | PRINT("Dumping UBX-CFG-VALSET %d/%d (%s)", 107 | msgIx + 1, nMsgs, msgs[msgIx].info); 108 | 109 | if (fmt != FMT_UBX) 110 | { 111 | const char *comment1 = fmt == FMT_HEX ? "# - " : "// "; 112 | const char *comment2 = fmt == FMT_HEX ? "# " : "// "; 113 | ioOutputStr("%sUBX-CFG-VALSET %d/%d (%s)\n", 114 | comment1, msgIx + 1, nMsgs, msgs[msgIx].info); 115 | if (extraInfo) 116 | { 117 | for (int kvIx = 0; (kvIx < UBX_CFG_VALSET_V1_MAX_KV) && (kvOffs < nKv); kvIx++, kvOffs++) 118 | { 119 | char str[UBLOXCFG_MAX_KEYVAL_STR_SIZE]; 120 | if (ubloxcfg_stringifyKeyVal(str, sizeof(str), &kv[kvOffs])) 121 | { 122 | ioOutputStr("%s%2d. %s\n", comment2, kvOffs + 1, str); 123 | } 124 | } 125 | } 126 | } 127 | if (fmt == FMT_C) 128 | { 129 | ioOutputStr("const uint8_t ubxCfgValset%d[%d] =\n{\n", msgIx, msgs[msgIx].size); 130 | } 131 | switch (fmt) 132 | { 133 | case FMT_HEX: 134 | ioAddOutputHex(msgs[msgIx].msg, msgs[msgIx].size, 4, false); 135 | break; 136 | case FMT_C: 137 | ioAddOutputC(msgs[msgIx].msg, msgs[msgIx].size, 4, " "); 138 | break; 139 | case FMT_UBX: 140 | ioAddOutputBin(msgs[msgIx].msg, msgs[msgIx].size); 141 | break; 142 | default: 143 | break; 144 | } 145 | if (fmt == FMT_C) 146 | { 147 | ioOutputStr("};\n"); 148 | } 149 | } 150 | if (fmt == FMT_C) 151 | { 152 | ioOutputStr("const struct { const int size; const uint8_t *data; } ubxCfgValsetMsgs[%d] =\n{\n", nMsgs); 153 | for (int ix = 0; ix < nMsgs; ix++) 154 | { 155 | ioOutputStr(" { .size = sizeof(ubxCfgValset%d), .data = ubxCfgValset%d }%s\n", 156 | ix, ix, (ix + 1) < nMsgs ? "," : ""); 157 | } 158 | ioOutputStr("};\n", nMsgs); 159 | } 160 | 161 | free(kv); 162 | return ioWriteOutput(false) ? EXIT_SUCCESS : EXIT_OTHERFAIL; 163 | } 164 | 165 | /* ****************************************************************************************************************** */ 166 | // eof 167 | -------------------------------------------------------------------------------- /cfgtool/cfgtool_parse.c: -------------------------------------------------------------------------------- 1 | // clang-format off 2 | /* ****************************************************************************************************************** */ 3 | // u-blox positioning receivers configuration tool 4 | // 5 | // Copyright (c) Philippe Kehl (flipflip at oinkzwurgl dot org) and contributors 6 | // 7 | // This program is free software: you can redistribute it and/or modify it under the terms of the 8 | // GNU General Public License as published by the Free Software Foundation, either version 3 of the 9 | // License, or (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 12 | // even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | // See the GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License along with this program. 16 | // If not, see . 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | #include "cfgtool_util.h" 23 | 24 | #include "ff_ubx.h" 25 | #include "ff_parser.h" 26 | #include "ff_epoch.h" 27 | 28 | #include "cfgtool_parse.h" 29 | 30 | /* ****************************************************************************************************************** */ 31 | 32 | const char *parseHelp(void) 33 | { 34 | return 35 | // ----------------------------------------------------------------------------- 36 | "Command 'parse':\n" 37 | "\n" 38 | " Usage: cfgtool parse [-i ] [-o ] [-y] [-x] [-e]\n" 39 | "\n" 40 | " This processes data from the input file through the parser and outputs\n" 41 | " information on the found messages and optionally a hex dump of the messages.\n" 42 | " It stops at the end of the file or when SIGINT (e.g. CTRL-C)" NOT_WIN(", SIGHUP") "\n" 43 | " or SIGTERM is received.\n" 44 | "\n" 45 | " Add -e to enable epoch detection and to output detected epochs.\n" 46 | "\n"; 47 | } 48 | 49 | /* ****************************************************************************************************************** */ 50 | 51 | static bool gAbort; 52 | 53 | static void _sigHandler(int signal) 54 | { 55 | if ( (signal == SIGINT) || (signal == SIGTERM) NOT_WIN(|| (signal == SIGHUP)) ) 56 | { 57 | PRINT("Aborting..."); 58 | gAbort = true; 59 | } 60 | } 61 | 62 | int parseRun(const bool extraInfo, const bool doEpoch) 63 | { 64 | uint32_t nEpochs = 0; 65 | 66 | gAbort = false; 67 | signal(SIGINT, _sigHandler); 68 | signal(SIGTERM, _sigHandler); 69 | NOT_WIN( signal(SIGHUP, _sigHandler) ); 70 | 71 | PARSER_t parser; 72 | parserInit(&parser); 73 | 74 | EPOCH_t coll; 75 | EPOCH_t epoch; 76 | PARSER_MSG_t msg; 77 | epochInit(&coll); 78 | bool done = false; 79 | while (!(gAbort || done)) 80 | { 81 | uint8_t buf[1000]; 82 | const int num = ioReadInput(buf, sizeof(buf)); 83 | if (num < 0) // eof 84 | { 85 | done = true; 86 | } 87 | else if (num == 0) // wait 88 | { 89 | SLEEP(5); 90 | continue; 91 | } 92 | if (num > 0) 93 | { 94 | parserAdd(&parser, buf, num); 95 | } 96 | 97 | while (parserProcess(&parser, &msg, true)) 98 | { 99 | if (doEpoch && epochCollect(&coll, &msg, &epoch)) 100 | { 101 | nEpochs++; 102 | ioOutputStr("epoch %4d, size 0, NONE EPOCH %s\n", nEpochs, epoch.str); 103 | } 104 | ioOutputStr("message %4u, size %4d, %-8s %-20s %s\n", 105 | msg.seq, msg.size, parserMsgtypeName(msg.type), msg.name, msg.info != NULL ? msg.info : "n/a"); 106 | if (extraInfo) 107 | { 108 | ioAddOutputHexdump(msg.data, msg.size); 109 | } 110 | if (!ioWriteOutput(parser.nMsgs == 1 ? false : true)) 111 | { 112 | break; 113 | } 114 | } 115 | } 116 | 117 | // Anything left in parser? 118 | if (parserFlush(&parser, &msg)) 119 | { 120 | ioOutputStr("message %4u, size %4d, %-8s %-20s %s\n", 121 | msg.seq, msg.size, parserMsgtypeName(msg.type), msg.name, msg.info != NULL ? msg.info : "n/a"); 122 | if (extraInfo) 123 | { 124 | ioAddOutputHexdump(msg.data, msg.size); 125 | } 126 | ioWriteOutput(true); 127 | } 128 | 129 | ioOutputStr("stats UBX count %6u (%5.1f%%) size %10u (%5.1f%%)\n", parser.nUbx, parser.nMsgs > 0 ? (double)parser.nUbx / (double)parser.nMsgs * 1e2 : 0.0, parser.sUbx, parser.sMsgs > 0 ? (double)parser.sUbx / (double)parser.sMsgs * 1e2 : 0.0); 130 | ioOutputStr("stats NMEA count %6u (%5.1f%%) size %10u (%5.1f%%)\n", parser.nNmea, parser.nMsgs > 0 ? (double)parser.nNmea / (double)parser.nMsgs * 1e2 : 0.0, parser.sNmea, parser.sMsgs > 0 ? (double)parser.sNmea / (double)parser.sMsgs * 1e2 : 0.0); 131 | ioOutputStr("stats RTCM3 count %6u (%5.1f%%) size %10u (%5.1f%%)\n", parser.nRtcm3, parser.nMsgs > 0 ? (double)parser.nRtcm3 / (double)parser.nMsgs * 1e2 : 0.0, parser.sRtcm3, parser.sMsgs > 0 ? (double)parser.sRtcm3 / (double)parser.sMsgs * 1e2 : 0.0); 132 | ioOutputStr("stats SPARTN count %6u (%5.1f%%) size %10u (%5.1f%%)\n", parser.nSpartn, parser.nMsgs > 0 ? (double)parser.nSpartn / (double)parser.nMsgs * 1e2 : 0.0, parser.sSpartn, parser.sMsgs > 0 ? (double)parser.sSpartn / (double)parser.sMsgs * 1e2 : 0.0); 133 | ioOutputStr("stats NOVATEL count %6u (%5.1f%%) size %10u (%5.1f%%)\n", parser.nUbx, parser.nMsgs > 0 ? (double)parser.nNovatel / (double)parser.nMsgs * 1e2 : 0.0, parser.sNovatel, parser.sMsgs > 0 ? (double)parser.sNovatel / (double)parser.sMsgs * 1e2 : 0.0); 134 | ioOutputStr("stats GARBAGE count %6u (%5.1f%%) size %10u (%5.1f%%)\n", parser.nGarbage, parser.nMsgs > 0 ? (double)parser.nGarbage / (double)parser.nMsgs * 1e2 : 0.0, parser.sGarbage, parser.sMsgs > 0 ? (double)parser.sGarbage / (double)parser.sMsgs * 1e2 : 0.0); 135 | ioOutputStr("stats Total count %6u (100.0%%) size %10u (100.0%%)\n", parser.nMsgs, parser.sMsgs); 136 | if (doEpoch) 137 | { 138 | ioOutputStr("stats EPOCH count %6u (%5.1f%%)\n", nEpochs, parser.nMsgs > 0 ? (double)nEpochs / (double)parser.nMsgs * 1e2 : 0.0); 139 | } 140 | 141 | return ioWriteOutput(true) ? EXIT_SUCCESS : EXIT_OTHERFAIL; 142 | } 143 | 144 | /* ****************************************************************************************************************** */ 145 | // eof 146 | -------------------------------------------------------------------------------- /ff/ff_nmea.h: -------------------------------------------------------------------------------- 1 | // clang-format off 2 | // flipflip's NMEA protocol stuff 3 | // 4 | // Copyright (c) Philippe Kehl (flipflip at oinkzwurgl dot org) and contributors 5 | // https://oinkzwurgl.org/projaeggd/ubloxcfg/ 6 | // 7 | // This program is free software: you can redistribute it and/or modify it under the terms of the 8 | // GNU General Public License as published by the Free Software Foundation, either version 3 of the 9 | // License, or (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 12 | // even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | // See the GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License along with this program. 16 | // If not, see . 17 | 18 | #ifndef __FF_NMEA_H__ 19 | #define __FF_NMEA_H__ 20 | 21 | #include 22 | #include 23 | 24 | #ifdef __cplusplus 25 | extern "C" { 26 | #endif 27 | 28 | /* ****************************************************************************************************************** */ 29 | 30 | #define NMEA_FRAME_SIZE 6 // "$*cc\r\n" 31 | #define NMEA_PREAMBLE '$' 32 | 33 | typedef struct NMEA_TIME_s 34 | { 35 | bool valid; 36 | int hour; 37 | int minute; 38 | double second; 39 | } NMEA_TIME_t; 40 | 41 | typedef struct NMEA_DATE_s 42 | { 43 | bool valid; 44 | int day; 45 | int month; 46 | int year; 47 | } NMEA_DATE_t; 48 | 49 | typedef enum NMEA_FIX_e 50 | { 51 | NMEA_FIX_UNKNOWN = 0, 52 | NMEA_FIX_NOFIX, 53 | NMEA_FIX_DRONLY, 54 | NMEA_FIX_S2D, 55 | NMEA_FIX_S3D, 56 | NMEA_FIX_S3D_DR, 57 | NMEA_FIX_RTK_FLOAT, 58 | NMEA_FIX_RTK_FIXED, 59 | // keep in sync with kNmeaFixStrs 60 | } NMEA_FIX_t; 61 | 62 | typedef enum NMEA_GNSS_e 63 | { 64 | NMEA_GNSS_UNKNOWN = 0, 65 | NMEA_GNSS_GPS, 66 | NMEA_GNSS_GLO, 67 | NMEA_GNSS_BDS, 68 | NMEA_GNSS_GAL, 69 | NMEA_GNSS_SBAS, 70 | NMEA_GNSS_QZSS, 71 | NMEA_GNSS_NAVIC, 72 | } NMEA_GNSS_t; 73 | 74 | typedef enum NMEA_SIGNAL_e 75 | { 76 | NMEA_SIGNAL_UNKNOWN = 0, 77 | NMEA_SIGNAL_GPS_L1CA, 78 | NMEA_SIGNAL_GPS_L2CL, 79 | NMEA_SIGNAL_GPS_L2CM, 80 | NMEA_SIGNAL_GPS_L5I, 81 | NMEA_SIGNAL_GPS_L5Q, 82 | NMEA_SIGNAL_GLO_L1OF, 83 | NMEA_SIGNAL_GLO_L2OF, 84 | NMEA_SIGNAL_GAL_E1, 85 | NMEA_SIGNAL_GAL_E5A, 86 | NMEA_SIGNAL_GAL_E5B, 87 | NMEA_SIGNAL_BDS_B1ID, 88 | NMEA_SIGNAL_BDS_B2ID, 89 | NMEA_SIGNAL_BDS_B1C, 90 | NMEA_SIGNAL_BDS_B2A, 91 | NMEA_SIGNAL_QZSS_L1CA, 92 | NMEA_SIGNAL_QZSS_L1S, 93 | NMEA_SIGNAL_QZSS_L2CM, 94 | NMEA_SIGNAL_QZSS_L2CL, 95 | NMEA_SIGNAL_QZSS_L5I, 96 | NMEA_SIGNAL_QZSS_L5Q, 97 | NMEA_SIGNAL_NAVIC_L5A, 98 | } NMEA_SIGNAL_t; 99 | 100 | typedef struct NMEA_GGA_s 101 | { 102 | NMEA_TIME_t time; 103 | double lat; 104 | double lon; 105 | NMEA_FIX_t fix; 106 | int numSv; 107 | double hDOP; 108 | double height; 109 | double heightMsl; 110 | double diffAge; // < 0 = no DGPS 111 | int diffStation; // < 0 = no DGPS 112 | } NMEA_GGA_t; 113 | 114 | typedef struct NMEA_RMC_s 115 | { 116 | NMEA_DATE_t date; 117 | NMEA_TIME_t time; 118 | NMEA_FIX_t fix; 119 | bool valid; 120 | double lat; 121 | double lon; 122 | double spd; 123 | double cog; 124 | double mv; 125 | } NMEA_RMC_t; 126 | 127 | typedef struct NMEA_GLL_s 128 | { 129 | NMEA_TIME_t time; 130 | NMEA_FIX_t fix; 131 | bool valid; 132 | double lat; 133 | double lon; 134 | } NMEA_GLL_t; 135 | 136 | typedef struct NMEA_GSV_s 137 | { 138 | int numMsg; 139 | int msgNum; 140 | int numSat; 141 | struct 142 | { 143 | int svId; 144 | int elev; 145 | int azim; 146 | int cno; 147 | NMEA_SIGNAL_t sig; 148 | NMEA_GNSS_t gnss; 149 | } svs[4]; 150 | int nSvs; 151 | } NMEA_GSV_t; 152 | 153 | typedef struct NMEA_TXT_s 154 | { 155 | int numMsg; 156 | int msgNum; 157 | int msgType; 158 | char text[200]; 159 | } NMEA_TXT_t; 160 | 161 | typedef enum NMEA_TYPE_e 162 | { 163 | NMEA_TYPE_NONE = 0, 164 | NMEA_TYPE_TXT, 165 | NMEA_TYPE_GGA, 166 | NMEA_TYPE_RMC, 167 | NMEA_TYPE_GLL, 168 | NMEA_TYPE_GSV, 169 | } NMEA_TYPE_t; 170 | 171 | typedef struct NMEA_MSG_s 172 | { 173 | char talker[3]; //!< Talker ID ("GP", "GN", "P", ...) 174 | char formatter[8]; //!< Formatter ("GGA", "RMC", "UBX", ...) 175 | char info[200]; 176 | int payloadIx0; 177 | int payloadIx1; 178 | NMEA_TYPE_t type; 179 | union 180 | { 181 | NMEA_TXT_t txt; 182 | NMEA_GGA_t gga; 183 | NMEA_RMC_t rmc; 184 | NMEA_GLL_t gll; 185 | NMEA_GSV_t gsv; 186 | }; 187 | 188 | } NMEA_MSG_t; 189 | 190 | // --------------------------------------------------------------------------------------------------------------------- 191 | 192 | bool nmeaMessageName(char *name, const int size, const uint8_t *msg, const int msgSize); 193 | 194 | bool nmeaMessageInfo(char *info, const int size, const uint8_t *msg, const int msgSize); 195 | 196 | bool nmeaDecode(NMEA_MSG_t *nmea, const uint8_t *msg, const int msgSize); 197 | 198 | //! Get NMEA message IDs ("fake" UBX class and message IDs) 199 | /*! 200 | \param[in] name Message name (e.g. "NMEA-STANDARD-GGA", "NMEA-PUBX-POSITION") 201 | \param[out] clsId Class ID, or NULL 202 | \param[out] msgId Message ID, or NULL 203 | 204 | \returns true if \c name was found and \c clsId and \c msgId are valid 205 | */ 206 | bool nmeaMessageClsId(const char *name, uint8_t *clsId, uint8_t *msgId); 207 | 208 | //! Make a NMEA message (sentence) 209 | /*! 210 | \param[in] talker Talker ID (can be "") 211 | \param[in] formatter Formatter (can be "") 212 | \param[in] payload The message payload (can be NULL) 213 | \param[out] msg Message buffer (must be at least \c strlen(talker) + \c strlen(formatter) + 214 | \c strlen(payload) + #NMEA_FRAME_SIZE + 3) 215 | 216 | \note \c payload and \c msg may be the same buffer (or may overlap). 217 | 218 | \returns the message size 219 | */ 220 | int nmeaMakeMessage(const char *talker, const char *formatter, const char *payload, char *msg); 221 | 222 | /* ****************************************************************************************************************** */ 223 | #ifdef __cplusplus 224 | } 225 | #endif 226 | #endif // __FF_NMEA_H__ 227 | -------------------------------------------------------------------------------- /cfgtool/cfgtool_uc2cfg.c: -------------------------------------------------------------------------------- 1 | // clang-format off 2 | /* ****************************************************************************************************************** */ 3 | // u-blox positioning receivers configuration tool 4 | // 5 | // Copyright (c) Philippe Kehl (flipflip at oinkzwurgl dot org) and contributors 6 | // 7 | // This program is free software: you can redistribute it and/or modify it under the terms of the 8 | // GNU General Public License as published by the Free Software Foundation, either version 3 of the 9 | // License, or (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 12 | // even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | // See the GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License along with this program. 16 | // If not, see . 17 | 18 | #include 19 | #include 20 | //#include 21 | //#include 22 | 23 | #include "ubloxcfg/ubloxcfg.h" 24 | 25 | #include "cfgtool_util.h" 26 | 27 | #include "ff_rx.h" 28 | #include "ff_ubx.h" 29 | 30 | #include "cfgtool_uc2cfg.h" 31 | 32 | /* ****************************************************************************************************************** */ 33 | 34 | #define MAX_KEY 50 35 | #define MAX_VAL 25 36 | #define NUM_KVSTRS 200 37 | 38 | const char *uc2cfgHelp(void) 39 | { 40 | return 41 | // ----------------------------------------------------------------------------- 42 | "Command 'uc2cfg':\n" 43 | "\n" 44 | " Usage: cfgtool uc2cfg [-i ] [-o ] [-y]\n" 45 | "\n" 46 | " This converts a configuration file from u-center's 'Generation 9 Advanced\n" 47 | " Configuration' tool and converts it into the format cfgtool understands.\n" 48 | " It reads all key-value pairs in the [set] section of the input file. The\n" 49 | " layer tokens are ignored. Duplicate key-value pairs are silently ignored\n" 50 | " unless the values are inconsistent. No formal checks on the key names or\n" 51 | " values are performed and the data is passed-through as-is. Empty lines,\n" 52 | " comments as well as sections other than the [set] section are ignored.\n" 53 | " A maximum of "STRINGIFY(NUM_KVSTRS)" key-value pairs are processed. Key and value strings must\n" 54 | " not exceed "STRINGIFY(MAX_KEY)" respectively "STRINGIFY(MAX_VAL)" characters.\n" 55 | "\n"; 56 | } 57 | 58 | /* ****************************************************************************************************************** */ 59 | 60 | #define WARNING_INFILE(fmt, args...) WARNING("%s:%d: " fmt, line->file, line->lineNr, ## args) 61 | #define DEBUG_INFILE(fmt, args...) DEBUG("%s:%d: " fmt, line->file, line->lineNr, ## args) 62 | #define TRACE_INFILE(fmt, args...) TRACE("%s:%d: " fmt, line->file, line->lineNr, ## args) 63 | 64 | /* ****************************************************************************************************************** */ 65 | 66 | typedef struct KV_STRS_s 67 | { 68 | char key[MAX_KEY]; 69 | char val[MAX_VAL]; 70 | } KVSTRS_t; 71 | 72 | int uc2cfgRun(void) 73 | { 74 | const int kvStrsSize = NUM_KVSTRS * sizeof(KVSTRS_t); 75 | KVSTRS_t *kvStrs = malloc(kvStrsSize); 76 | if (kvStrs == NULL) 77 | { 78 | WARNING("malloc fail!"); 79 | return EXIT_FAILURE; 80 | } 81 | memset(kvStrs, 0, kvStrsSize); 82 | int nKvStrs = 0; 83 | 84 | bool inSet = false; 85 | int errors = 0; 86 | while (true) 87 | { 88 | IO_LINE_t *line = ioGetNextInputLine(); 89 | if (line == NULL) 90 | { 91 | break; 92 | } 93 | if (strcasecmp(line->line, "[set]") == 0) 94 | { 95 | inSet = true; 96 | } 97 | else if (line->line[0] == '[') 98 | { 99 | inSet = false; 100 | } 101 | else if (inSet) 102 | { 103 | const char *sep = " \t"; 104 | char *layer = strtok(line->line, sep); 105 | char *key = strtok(NULL, sep); 106 | char *val = strtok(NULL, sep); 107 | if ( (layer == NULL) || (key == NULL) || (val == NULL) || (strncmp(key, "CFG-", 4) != 0) || 108 | ((strcasecmp(layer, "RAM") != 0) && (strcasecmp(layer, "BBR") != 0) && (strcasecmp(layer, "Flash") != 0)) ) 109 | { 110 | WARNING_INFILE("Bad data!"); 111 | } 112 | else if (strlen(key) > (MAX_KEY - 1)) 113 | { 114 | WARNING_INFILE("Too long key!"); 115 | errors++; 116 | } 117 | else if (strlen(val) > (MAX_VAL - 1)) 118 | { 119 | WARNING_INFILE("Too long value!"); 120 | errors++; 121 | } 122 | else 123 | { 124 | //DEBUG_INFILE("layer=[%s] key=[%s] val=[%s]", layer, key, val); 125 | bool kvOk = true; 126 | for (int ix = 0; ix < nKvStrs; ix++) 127 | { 128 | if (strcmp(kvStrs[ix].key, key) == 0) 129 | { 130 | if (strcmp(kvStrs[ix].val, val) == 0) 131 | { 132 | DEBUG_INFILE("Ignoring duplicate key-value pair (%s %s)!", key, val); 133 | } 134 | else 135 | { 136 | WARNING_INFILE("Inconsistent key-value pair (%s %s, previously %s)!", 137 | key, val, kvStrs[ix].val); 138 | errors++; 139 | } 140 | kvOk = false; 141 | } 142 | } 143 | if (kvOk) 144 | { 145 | if (nKvStrs >= NUM_KVSTRS) 146 | { 147 | WARNING_INFILE("Too many key-value pairs!"); 148 | errors++; 149 | break; 150 | } 151 | strcat(kvStrs[nKvStrs].key, key); 152 | strcat(kvStrs[nKvStrs].val, val); 153 | nKvStrs++; 154 | } 155 | } 156 | } 157 | } 158 | 159 | bool res = true; 160 | if (errors > 0) 161 | { 162 | WARNING("Bad input!"); 163 | res = false; 164 | } 165 | else 166 | { 167 | ioOutputStr("# uc2cfg\n"); 168 | for (int ix = 0; ix < nKvStrs; ix++) 169 | { 170 | ioOutputStr("%-30s %s\n", kvStrs[ix].key, kvStrs[ix].val); 171 | } 172 | res = ioWriteOutput(false); 173 | 174 | } 175 | 176 | free(kvStrs); 177 | return res ? EXIT_SUCCESS : EXIT_OTHERFAIL; 178 | } 179 | 180 | /* ****************************************************************************************************************** */ 181 | // eof 182 | -------------------------------------------------------------------------------- /cfgtool/cfgtool_dump.c: -------------------------------------------------------------------------------- 1 | // clang-format off 2 | /* ****************************************************************************************************************** */ 3 | // u-blox positioning receivers configuration tool 4 | // 5 | // Copyright (c) Philippe Kehl (flipflip at oinkzwurgl dot org) and contributors 6 | // 7 | // This program is free software: you can redistribute it and/or modify it under the terms of the 8 | // GNU General Public License as published by the Free Software Foundation, either version 3 of the 9 | // License, or (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 12 | // even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | // See the GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License along with this program. 16 | // If not, see . 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | #include "cfgtool_util.h" 23 | 24 | #include "ff_rx.h" 25 | #include "ff_ubx.h" 26 | #include "ff_epoch.h" 27 | 28 | #include "cfgtool_dump.h" 29 | 30 | /* ****************************************************************************************************************** */ 31 | 32 | const char *dumpHelp(void) 33 | { 34 | return 35 | // ----------------------------------------------------------------------------- 36 | "Command 'dump':\n" 37 | "\n" 38 | " Usage: cfgtool dump -p [-o ] [-y] [-x] [-n]\n" 39 | "\n" 40 | " Connects to the receiver and outputs information on the received messages\n" 41 | " and optionally a hex dump of the messages until SIGINT (e.g. CTRL-C)"NOT_WIN(", SIGHUP")"\n" 42 | " or SIGTERM is received.\n" 43 | "\n" 44 | " Returns success (0) if receiver was detected and at least one message was\n" 45 | " received. Otherwise returns "STRINGIFY(EXIT_RXFAIL)" (rx not detected) or "STRINGIFY(EXIT_RXNODATA)" (no messages).\n" 46 | "\n" 47 | " Examples:\n" 48 | "\n" 49 | #ifdef _WIN32 50 | " cfgtool dump -p COM3\n" 51 | #else 52 | " cfgtool dump -p /dev/ttyUSB0\n" 53 | " timeout 20 cfgtool dump -p /dev/ttyACM0\n" 54 | #endif 55 | "\n"; 56 | } 57 | 58 | /* ****************************************************************************************************************** */ 59 | 60 | bool gAbort; 61 | 62 | static void _sigHandler(int signal) 63 | { 64 | if ( (signal == SIGINT) || (signal == SIGTERM) NOT_WIN(|| (signal == SIGHUP)) ) 65 | { 66 | PRINT("Aborting..."); 67 | gAbort = true; 68 | } 69 | } 70 | 71 | int dumpRun(const char *portArg, const bool extraInfo, const bool noProbe) 72 | { 73 | RX_OPTS_t opts = RX_OPTS_DEFAULT(); 74 | if (noProbe) 75 | { 76 | opts.autobaud = false; 77 | opts.detect = RX_DET_NONE; 78 | } 79 | 80 | RX_t *rx = rxInit(portArg, &opts); 81 | if ( (rx == NULL) || !rxOpen(rx) ) 82 | { 83 | free(rx); 84 | return EXIT_RXFAIL; 85 | } 86 | 87 | gAbort = false; 88 | signal(SIGINT, _sigHandler); 89 | signal(SIGTERM, _sigHandler); 90 | NOT_WIN( signal(SIGHUP, _sigHandler) ); 91 | 92 | const uint64_t tOffs = TIME() - timeOfDay(); // Offset between wall clock and parser time reference 93 | uint32_t nEpochs = 0; 94 | EPOCH_t coll; 95 | EPOCH_t epoch; 96 | epochInit(&coll); 97 | 98 | PRINT("Dumping received data..."); 99 | const PARSER_t *parser = rxGetParser(rx); 100 | while (!gAbort) 101 | { 102 | PARSER_MSG_t *msg = rxGetNextMessage(rx); 103 | if (msg != NULL) 104 | { 105 | const uint32_t latency = (msg->ts - tOffs) % 1000; // Relative to wall clock top of second 106 | if (epochCollect(&coll, msg, &epoch)) 107 | { 108 | nEpochs++; 109 | ioOutputStr("epoch %4u, %s\n", epoch.seq, epoch.str); 110 | if (!ioWriteOutput(parser->nMsgs == 1 ? false : true)) 111 | { 112 | break; 113 | } 114 | } 115 | ioOutputStr("message %4u, dt %4u, size %4d, %-8s %-20s %s\n", 116 | msg->seq, latency, msg->size, parserMsgtypeName(msg->type), msg->name, msg->info != NULL ? msg->info : "n/a"); 117 | if (extraInfo) 118 | { 119 | ioAddOutputHexdump(msg->data, msg->size); 120 | } 121 | if (!ioWriteOutput(parser->nMsgs == 1 ? false : true)) 122 | { 123 | break; 124 | } 125 | } 126 | // No data, yield 127 | else 128 | { 129 | SLEEP(5); 130 | } 131 | } 132 | 133 | ioOutputStr("stats UBX count %6u (%5.1f%%) size %10u (%5.1f%%)\n", parser->nUbx, parser->nMsgs > 0 ? (double)parser->nUbx / (double)parser->nMsgs * 1e2 : 0.0, parser->sUbx, parser->sMsgs > 0 ? (double)parser->sUbx / (double)parser->sMsgs * 1e2 : 0.0); 134 | ioOutputStr("stats NMEA count %6u (%5.1f%%) size %10u (%5.1f%%)\n", parser->nNmea, parser->nMsgs > 0 ? (double)parser->nNmea / (double)parser->nMsgs * 1e2 : 0.0, parser->sNmea, parser->sMsgs > 0 ? (double)parser->sNmea / (double)parser->sMsgs * 1e2 : 0.0); 135 | ioOutputStr("stats RTCM3 count %6u (%5.1f%%) size %10u (%5.1f%%)\n", parser->nRtcm3, parser->nMsgs > 0 ? (double)parser->nRtcm3 / (double)parser->nMsgs * 1e2 : 0.0, parser->sRtcm3, parser->sMsgs > 0 ? (double)parser->sRtcm3 / (double)parser->sMsgs * 1e2 : 0.0); 136 | ioOutputStr("stats SPARTN count %6u (%5.1f%%) size %10u (%5.1f%%)\n", parser->nSpartn, parser->nMsgs > 0 ? (double)parser->nSpartn / (double)parser->nMsgs * 1e2 : 0.0, parser->sSpartn, parser->sMsgs > 0 ? (double)parser->sSpartn / (double)parser->sMsgs * 1e2 : 0.0); 137 | ioOutputStr("stats NOVATEL count %6u (%5.1f%%) size %10u (%5.1f%%)\n", parser->nUbx, parser->nMsgs > 0 ? (double)parser->nNovatel / (double)parser->nMsgs * 1e2 : 0.0, parser->sNovatel, parser->sMsgs > 0 ? (double)parser->sNovatel / (double)parser->sMsgs * 1e2 : 0.0); 138 | ioOutputStr("stats GARBAGE count %6u (%5.1f%%) size %10u (%5.1f%%)\n", parser->nGarbage, parser->nMsgs > 0 ? (double)parser->nGarbage / (double)parser->nMsgs * 1e2 : 0.0, parser->sGarbage, parser->sMsgs > 0 ? (double)parser->sGarbage / (double)parser->sMsgs * 1e2 : 0.0); 139 | ioOutputStr("stats Total count %6u (100.0%%) size %10u (100.0%%)\n", parser->nMsgs, parser->sMsgs); 140 | ioOutputStr("stats EPOCH count %6u (%5.1f%%)\n", nEpochs, parser->nMsgs > 0 ? (double)nEpochs / (double)parser->nMsgs * 1e2 : 0.0); 141 | 142 | bool res = ioWriteOutput(true); 143 | const uint32_t nMsgs = parser->nMsgs; 144 | 145 | rxClose(rx); 146 | free(rx); 147 | 148 | return res ? (nMsgs > 0 ? EXIT_SUCCESS : EXIT_RXNODATA) : EXIT_OTHERFAIL; 149 | } 150 | 151 | /* ****************************************************************************************************************** */ 152 | // eof 153 | -------------------------------------------------------------------------------- /ubloxcfg/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ######################################################################################################################## 2 | # 3 | # ubloxcfg -- u-blox positioning receivers configuration library 4 | # 5 | # Copyright (c) Philippe Kehl (flipflip at oinkzwurgl dot org) and contributors 6 | # 7 | # This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public 8 | # License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later 9 | # version. 10 | # 11 | # This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied 12 | # warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License along with this program. 15 | # If not, see . 16 | # 17 | ######################################################################################################################## 18 | 19 | # GENERAL ============================================================================================================== 20 | 21 | cmake_minimum_required(VERSION 3.16) 22 | include(../cmake/setup.cmake) 23 | 24 | project(ubloxcfg 25 | LANGUAGES C 26 | VERSION ${FF_VERSION_NUMBER} 27 | DESCRIPTION "ubloxcfg library" 28 | ) 29 | 30 | 31 | # COMPILER SETUP ======================================================================================================= 32 | 33 | set(CMAKE_C_STANDARD 99) 34 | set(CMAKE_C_EXTENSIONS OFF) 35 | set(CMAKE_C_STANDARD_REQUIRED ON) 36 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wpedantic -Werror \ 37 | -Wshadow -Wunused-parameter -Wformat -Wpointer-arith -Wundef") 38 | set(CMAKE_C_FLAGS_RELEASE "-O3") 39 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 40 | if(NOT CMAKE_BUILD_TYPE) 41 | set(CMAKE_BUILD_TYPE Release) 42 | endif() 43 | if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug") 44 | add_compile_definitions(NDEBUG) 45 | endif() 46 | 47 | 48 | # DEPENDENCIES ========================================================================================================= 49 | 50 | find_package(Perl REQUIRED) 51 | 52 | 53 | # GENERATED CODE ======================================================================================================= 54 | 55 | 56 | if(NOT NO_CODEGEN) 57 | file(GLOB JSONC_FILES *.jsonc) 58 | set(GEN_FILES "${PROJECT_SOURCE_DIR}/ubloxcfg_gen.h;${PROJECT_SOURCE_DIR}/ubloxcfg_gen.c") 59 | message(STATUS "ff: JSONC_FILES=${JSONC_FILES}") 60 | message(STATUS "ff: GEN_FILES=${GEN_FILES}") 61 | 62 | add_custom_command( 63 | OUTPUT ${GEN_FILES} 64 | COMMAND ${PERL_EXECUTABLE} ${PROJECT_SOURCE_DIR}/ubloxcfg_gen.pl ${PROJECT_SOURCE_DIR}/ubloxcfg_gen ${JSONC_FILES} 65 | DEPENDS ${JSONC_FILES} ${PROJECT_SOURCE_DIR}/ubloxcfg_gen.pl 66 | ) 67 | 68 | add_custom_target(ubloxcfg-generated ALL DEPENDS ${GEN_FILES}) 69 | endif() 70 | 71 | # SHARED LIBRARY ======================================================================================================= 72 | 73 | file(GLOB C_FILES *.c) 74 | file(GLOB H_FILES *.h) 75 | message(STATUS "ff: C_FILES=${C_FILES}") 76 | message(STATUS "ff: H_FILES=${H_FILES}") 77 | 78 | list(APPEND CMAKE_INSTALL_RPATH $ORIGIN) 79 | list(APPEND CMAKE_INSTALL_RPATH $ORIGIN/../lib) 80 | 81 | add_library(${PROJECT_NAME} SHARED ${C_FILES} ${GEN_FILES}) 82 | 83 | if(NOT NO_CODEGEN) 84 | add_dependencies(${PROJECT_NAME} ubloxcfg-generated) 85 | endif() 86 | 87 | target_include_directories(${PROJECT_NAME} 88 | PUBLIC 89 | $ 90 | $ 91 | ) 92 | 93 | target_link_libraries(${PROJECT_NAME} 94 | PUBLIC 95 | PRIVATE 96 | ) 97 | 98 | set_target_properties(${PROJECT_NAME} 99 | PROPERTIES 100 | VERSION ${PROJECT_VERSION} 101 | ) 102 | 103 | 104 | # TESTS ================================================================================================================ 105 | 106 | message(STATUS "ff: BUILD_TESTING=${BUILD_TESTING}") 107 | 108 | if (NOT BUILD_TESTING STREQUAL "OFF") 109 | 110 | add_executable(${PROJECT_NAME}-test test/test_ubloxcfg.c) 111 | target_link_libraries(${PROJECT_NAME}-test ${PROJECT_NAME}) 112 | 113 | endif() 114 | 115 | 116 | # INSTALL ============================================================================================================== 117 | 118 | include(GNUInstallDirs) # Provides nice relative paths wrt CMAKE_INSTALL_PREFIX 119 | set(PROJECT_RUNTIME_DIR ${CMAKE_INSTALL_FULL_BINDIR}) 120 | set(PROJECT_LIBRARY_DIR ${CMAKE_INSTALL_FULL_LIBDIR}) 121 | set(PROJECT_INCLUDE_DIR ${CMAKE_INSTALL_FULL_INCLUDEDIR}/${PROJECT_NAME}) 122 | set(PROJECT_DATA_DIR ${CMAKE_INSTALL_FULL_DATAROOTDIR}/${PROJECT_NAME}) 123 | set(PROJECT_DOC_DIR ${CMAKE_INSTALL_FULL_DOCDIR}) 124 | 125 | # Headers 126 | install(FILES ${H_FILES} 127 | DESTINATION ${PROJECT_INCLUDE_DIR} 128 | ) 129 | 130 | # Library 131 | install(TARGETS ${PROJECT_NAME} 132 | EXPORT ${PROJECT_NAME}-targets 133 | LIBRARY DESTINATION ${PROJECT_LIBRARY_DIR} 134 | ) 135 | 136 | # Documentation 137 | install( 138 | FILES 139 | ${PROJECT_SOURCE_DIR}/README.md 140 | ${PROJECT_SOURCE_DIR}/LICENSE 141 | DESTINATION ${PROJECT_DOC_DIR} 142 | ) 143 | 144 | ############# 145 | 146 | # Test 147 | if (NOT BUILD_TESTING STREQUAL "OFF") 148 | install(TARGETS ${PROJECT_NAME}-test 149 | EXPORT ${PROJECT_NAME}-targets 150 | RUNTIME DESTINATION ${PROJECT_RUNTIME_DIR} 151 | ) 152 | endif() 153 | 154 | # CMake target config 155 | install(EXPORT ${PROJECT_NAME}-targets 156 | NAMESPACE ${PROJECT_NAMESPACE_PREFIX} 157 | FILE ${PROJECT_NAME}-targets.cmake 158 | DESTINATION lib/cmake/${PROJECT_NAME} 159 | ) 160 | 161 | # CMake config 162 | include(CMakePackageConfigHelpers) 163 | set(TARGET1 ${PROJECT_NAME}) 164 | configure_package_config_file( 165 | ${CMAKE_CURRENT_SOURCE_DIR}/../cmake/config.cmake.in 166 | ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake 167 | INSTALL_DESTINATION lib/cmake/${PROJECT_NAME} 168 | NO_SET_AND_CHECK_MACRO 169 | NO_CHECK_REQUIRED_COMPONENTS_MACRO 170 | ) 171 | write_basic_package_version_file( 172 | ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake 173 | VERSION "${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}" 174 | COMPATIBILITY AnyNewerVersion 175 | ) 176 | install( 177 | FILES 178 | ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake 179 | ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake 180 | DESTINATION lib/cmake/${PROJECT_NAME} 181 | ) 182 | 183 | # pkg-config config 184 | include(CMakePackageConfigHelpers) 185 | set(TARGET1 ${PROJECT_NAME}) 186 | configure_package_config_file( 187 | ${CMAKE_CURRENT_SOURCE_DIR}/../cmake/config.pc.in 188 | ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc 189 | INSTALL_DESTINATION lib/cmake/${PROJECT_NAME} 190 | NO_SET_AND_CHECK_MACRO 191 | NO_CHECK_REQUIRED_COMPONENTS_MACRO 192 | ) 193 | install( 194 | FILES 195 | ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc 196 | DESTINATION lib/pkgconfig 197 | ) 198 | 199 | ######################################################################################################################## 200 | -------------------------------------------------------------------------------- /ubloxcfg/LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ######################################################################################################################## 2 | 3 | .PHONY: default 4 | default: 5 | @echo "Make what? Try 'make help'!" 6 | @exit 1 7 | 8 | # Defaults (keep in sync with help screen below) 9 | BUILD_TYPE = Debug 10 | INSTALL_PREFIX = install 11 | BUILD_TESTING = 12 | VERBOSE = 0 13 | 14 | # User vars 15 | -include config.mk 16 | 17 | # A unique ID for this exact config we're using 18 | configuid=$(shell echo "$(BUILD_TYPE) $(INSTALL_PREFIX) $(BUILD_TESTING) ${FF_VERSION_STRING} $$(uname -a)" | md5sum | cut -d " " -f1) 19 | 20 | .PHONY: help 21 | help: 22 | @echo "Usage:" 23 | @echo 24 | @echo " make [INSTALL_PREFIX=...] [BUILD_TYPE=Debug|Release] [BUILD_TESTING=|ON|OFF] [FF_VERSION_STRING=x.x.x-gggggggg] [VERBOSE=1]" 25 | @echo 26 | @echo "Where possible s are:" 27 | @echo 28 | @echo " clean Clean build directory" 29 | @echo " cmake Configure" 30 | @echo " build Build" 31 | @echo " test Run tests" 32 | @echo " install Install (into INSTALL_PREFIX path)" 33 | @echo " doc Generate documentation (into build directory)" 34 | @echo " doc-dev Generate documentation and start webserver to view it" 35 | @echo 36 | @echo "Typically you want to do something like this:" 37 | @echo 38 | @echo " make install INSTALL_PREFIX=~/ubloxcfg" 39 | @echo 40 | @echo "Notes:" 41 | @echo 42 | @echo "- All s but 'clean' require that the same command-line variables are passed" 43 | @echo "- Command-line variables can be stored into a config.mk file, which is automatically loaded" 44 | @echo "- 'make ci' runs the CI (more or less) like on Github. INSTALL_PREFIX and BUILD_TYPE have no effect here." 45 | @echo 46 | 47 | ######################################################################################################################## 48 | 49 | TOUCH := touch 50 | MKDIR := mkdir 51 | ECHO := echo 52 | RM := rm 53 | CMAKE := cmake 54 | DOXYGEN := doxygen 55 | NICE := nice 56 | CAT := cat 57 | PYTHON := python 58 | SED := sed 59 | LN := ln 60 | 61 | ifeq ($(VERBOSE),1) 62 | V = 63 | V1 = 64 | V2 = 65 | V12 = 66 | RM += -v 67 | MV += -v 68 | CP += -v 69 | MKDIR += -v 70 | else 71 | ZIP += -q 72 | UNZIP += -q 73 | V = @ 74 | V1 = > /dev/null 75 | V2 = 2> /dev/null 76 | V12 = 2>&1 > /dev/null 77 | endif 78 | 79 | fancyterm := true 80 | ifeq ($(TERM),dumb) 81 | fancyterm := false 82 | endif 83 | ifeq ($(TERM),) 84 | fancyterm := false 85 | endif 86 | ifneq ($(MSYSTEM),) 87 | fancyterm := false 88 | endif 89 | ifeq ($(fancyterm),true) 90 | HLW="\\e[1m" 91 | HLO="\\e[m" 92 | else 93 | HLW= 94 | HLO= 95 | endif 96 | 97 | # Disable all built-in rules 98 | .SUFFIXES: 99 | 100 | ######################################################################################################################## 101 | 102 | CMAKE_ARGS_BUILD := 103 | CMAKE_ARGS_INSTALL := 104 | CMAKE_ARGS := -DCMAKE_INSTALL_PREFIX=$(INSTALL_PREFIX) 105 | CMAKE_ARGS += -DCMAKE_BUILD_TYPE=$(BUILD_TYPE) 106 | ifneq ($(BUILD_TESTING),) 107 | CMAKE_ARGS += -DBUILD_TESTING=$(BUILD_TESTING) 108 | endif 109 | ifneq ($(FF_VERSION_STRING),) 110 | CMAKE_ARGS += -DVERSION_STRING=$(FF_VERSION_STRING) 111 | endif 112 | 113 | ifeq ($(BUILD_TYPE),Release) 114 | CMAKE_ARGS_INSTALL += --strip 115 | endif 116 | 117 | MAKEFLAGS = --no-print-directory 118 | 119 | ifneq ($(VERBOSE),0) 120 | CMAKE_ARGS_BUILD += --verbose 121 | endif 122 | 123 | ifeq ($(GITHUB_WORKSPACE),) 124 | CMAKE_ARGS_BUILD = --parallel $(shell nproc --ignore=2) 125 | NICE_BUILD=$(NICE) -19 126 | else 127 | CMAKE_ARGS_BUILD = --parallel 4 128 | NICE_BUILD= 129 | endif 130 | 131 | BUILD_DIR = build/$(BUILD_TYPE) 132 | 133 | # "All-in-one" targets 134 | .PHONY: clean 135 | clean: 136 | $(V)$(RM) -rf $(BUILD_DIR) 137 | 138 | .PHONY: distclean 139 | distclean: 140 | $(V)$(RM) -rf install build core.[123456789]* 141 | 142 | $(BUILD_DIR): 143 | $(V)$(MKDIR) -p $@ 144 | 145 | # Detect changed build config 146 | ifneq ($(MAKECMDGOALS),) 147 | ifneq ($(MAKECMDGOALS),help) 148 | ifneq ($(MAKECMDGOALS),pre-commit) 149 | ifneq ($(MAKECMDGOALS),ci) 150 | ifneq ($(MAKECMDGOALS),distclean) 151 | ifneq ($(MAKECMDGOALS),doc) 152 | builddiruid=$(shell $(CAT) $(BUILD_DIR)/.make-uid 2>/dev/null || echo "none") 153 | ifneq ($(builddiruid),$(configuid)) 154 | dummy=$(shell $(RM) -vf $(BUILD_DIR)/.make-uid)) 155 | endif 156 | endif 157 | endif 158 | endif 159 | endif 160 | endif 161 | endif 162 | 163 | $(BUILD_DIR)/.make-uid: | $(BUILD_DIR) 164 | $(V)$(ECHO) $(configuid) > $@ 165 | 166 | # ---------------------------------------------------------------------------------------------------------------------- 167 | 168 | .PHONY: cmake 169 | cmake: $(BUILD_DIR)/.make-cmake 170 | 171 | deps_cmake := Makefile $(wildcard config.mk) $(sort $(wildcard CMakeLists.txt */CMakeLists.txt cmake/*)) 172 | 173 | $(BUILD_DIR)/.make-cmake: $(deps_cmake) $(BUILD_DIR)/.make-uid 174 | @echo "$(HLW)***** Configure ($(BUILD_TYPE)) *****$(HLO)" 175 | $(V)$(CMAKE) -B $(BUILD_DIR) $(CMAKE_ARGS) 176 | $(V)$(TOUCH) $@ 177 | 178 | # ---------------------------------------------------------------------------------------------------------------------- 179 | 180 | .PHONY: build 181 | build: $(BUILD_DIR)/.make-build 182 | 183 | deps_build = $(sort $(wildcard ubloxcfg/* ffxx/* ffapps/* ffapps/*/* cfgtool/*)) 184 | 185 | $(BUILD_DIR)/.make-build: $(deps_build) $(BUILD_DIR)/.make-cmake $(BUILD_DIR)/.make-uid 186 | @echo "$(HLW)***** Build ($(BUILD_TYPE)) *****$(HLO)" 187 | $(V)$(NICE_BUILD) $(CMAKE) --build $(BUILD_DIR) $(CMAKE_ARGS_BUILD) -- -k 188 | $(V)$(TOUCH) $@ 189 | 190 | # ---------------------------------------------------------------------------------------------------------------------- 191 | 192 | .PHONY: install 193 | install: $(BUILD_DIR)/.make-install 194 | 195 | $(BUILD_DIR)/.make-install: $(BUILD_DIR)/.make-build 196 | @echo "$(HLW)***** Install ($(BUILD_TYPE)) *****$(HLO)" 197 | $(V)$(CMAKE) --install $(BUILD_DIR) $(CMAKE_ARGS_INSTALL) 198 | $(V)$(TOUCH) $@ 199 | 200 | # ---------------------------------------------------------------------------------------------------------------------- 201 | 202 | .PHONY: test 203 | test: $(BUILD_DIR)/.make-build 204 | @echo "$(HLW)***** Test ($(BUILD_TYPE)) *****$(HLO)" 205 | ifeq ($(VERBOSE),1) 206 | $(V)$(BUILD_DIR)/ubloxcfg/ubloxcfg-test -v 207 | else 208 | $(V)$(BUILD_DIR)/ubloxcfg/ubloxcfg-test 209 | endif 210 | 211 | # ---------------------------------------------------------------------------------------------------------------------- 212 | 213 | .PHONY: doc 214 | doc: $(BUILD_DIR)/.make-doc 215 | @echo "now run: xdg-open $(BUILD_DIR)/ubloxcfg/doc/index.html" 216 | 217 | $(BUILD_DIR)/.make-doc: $(BUILD_DIR)/.make-build ubloxcfg/Doxyfile 218 | @echo "$(HLW)***** Doc ($(BUILD_TYPE)) *****$(HLO)" 219 | $(V)( \ 220 | cat ubloxcfg/Doxyfile; \ 221 | echo "PROJECT_NUMBER = $$(cat $(BUILD_DIR)/FF_VERSION_STRING || echo 'unknown revision')"; \ 222 | echo "OUTPUT_DIRECTORY = $(BUILD_DIR)/ubloxcfg"; \ 223 | echo "INPUT = ubloxcfg"; \ 224 | ) | $(DOXYGEN) - 225 | $(V)$(TOUCH) $@ 226 | 227 | .PHONY: doc-dev 228 | doc-dev: $(BUILD_DIR)/.make-doc 229 | $(V)(cd $(BUILD_DIR)/ubloxcfg/doc && $(PYTHON) -m http.server 8000) 230 | 231 | # ---------------------------------------------------------------------------------------------------------------------- 232 | 233 | # .PHONY: ci 234 | # ci: $(BUILD_DIR)/.ci-bookworm $(BUILD_DIR)/.ci-noetic $(BUILD_DIR)/.ci-humble $(BUILD_DIR)/.ci-jazzy 235 | 236 | # $(BUILD_DIR)/.ci-bookworm: $(deps) 237 | # @echo "$(HLW)***** CI (bookworm) *****$(HLO)" 238 | # ifeq ($(FPSDK_IMAGE),) 239 | # $(V)docker/docker.sh run bookworm-ci ./docker/ci.sh 240 | # $(V)$(TOUCH) $@ 241 | # else 242 | # @echo "This ($@) should not run inside Docker!" 243 | # @false 244 | # endif 245 | 246 | # ---------------------------------------------------------------------------------------------------------------------- 247 | 248 | # .PHONY: pre-commit 249 | # pre-commit: | $(BUILD_DIR) 250 | # @echo "$(HLW)***** pre-commit checks *****$(HLO)" 251 | # $(V)$(MKDIR) -p $(BUILD_DIR)/.bin 252 | # $(V)$(LN) -sf /usr/bin/clang-format-17 $(BUILD_DIR)/.bin/clang-format 253 | # $(V)export PATH=$(BUILD_DIR)/.bin:$$PATH; pre-commit run --all-files --hook-stage manual || return 1 254 | 255 | ######################################################################################################################## 256 | -------------------------------------------------------------------------------- /cfgtool/cfgtool_status.c: -------------------------------------------------------------------------------- 1 | // clang-format off 2 | /* ****************************************************************************************************************** */ 3 | // u-blox positioning receivers configuration tool 4 | // 5 | // Copyright (c) Philippe Kehl (flipflip at oinkzwurgl dot org) and contributors 6 | // 7 | // This program is free software: you can redistribute it and/or modify it under the terms of the 8 | // GNU General Public License as published by the Free Software Foundation, either version 3 of the 9 | // License, or (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 12 | // even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | // See the GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License along with this program. 16 | // If not, see . 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include "cfgtool_util.h" 24 | 25 | #include "ff_rx.h" 26 | #include "ff_ubx.h" 27 | #include "ff_epoch.h" 28 | 29 | #include "cfgtool_status.h" 30 | 31 | /* ****************************************************************************************************************** */ 32 | 33 | const char *statusHelp(void) 34 | { 35 | return 36 | // ----------------------------------------------------------------------------- 37 | "Command 'status':\n" 38 | "\n" 39 | " Usage: cfgtool status -p [-n] [-x]\n" 40 | "\n" 41 | " Connects to the receiver and outputs the navigation status for each\n" 42 | " detected epoch. This requires navigation messages, such as UBX-NAV-PVT to\n" 43 | " be enabled. The program stops when SIGINT (e.g. CTRL-C)"NOT_WIN(", SIGHUP")"\n" 44 | " or SIGTERM is received.\n" 45 | "\n"; 46 | } 47 | 48 | /* ****************************************************************************************************************** */ 49 | 50 | static bool gAbort; 51 | 52 | static void _sigHandler(int signal) 53 | { 54 | if ( (signal == SIGINT) || (signal == SIGTERM) NOT_WIN(|| (signal == SIGHUP)) ) 55 | { 56 | PRINT("Aborting..."); 57 | gAbort = true; 58 | } 59 | } 60 | 61 | typedef struct INFO_s 62 | { 63 | uint32_t nEpoch; 64 | uint32_t nNmea; 65 | uint32_t nUbx; 66 | uint32_t nRtcm3; 67 | uint32_t nSpartn; 68 | uint32_t nNova; 69 | uint32_t nGarb; 70 | uint32_t nMsgs; 71 | } INFO_t; 72 | 73 | typedef enum STATUS_COLOUR_e 74 | { 75 | STATUS_COLOUR_NOFIX, STATUS_COLOUR_MASKED, STATUS_COLOUR_FIXOK, 76 | STATUS_COLOUR_OFF 77 | } STATUS_COLOUR_t; 78 | 79 | static void _statusColour(const STATUS_COLOUR_t colour) 80 | { 81 | #ifdef _WIN32 82 | switch (colour) 83 | { 84 | case STATUS_COLOUR_NOFIX: 85 | SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_INTENSITY); 86 | break; 87 | case STATUS_COLOUR_MASKED: 88 | SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY); 89 | break; 90 | case STATUS_COLOUR_FIXOK: 91 | SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN | FOREGROUND_INTENSITY); 92 | break; 93 | case STATUS_COLOUR_OFF: 94 | SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); 95 | break; 96 | } 97 | #else 98 | switch (colour) 99 | { 100 | case STATUS_COLOUR_NOFIX: 101 | ioOutputStr("\e[1;31m"); 102 | break; 103 | case STATUS_COLOUR_MASKED: 104 | ioOutputStr("\e[1;36m"); 105 | break; 106 | case STATUS_COLOUR_FIXOK: 107 | ioOutputStr("\e[1;32m"); 108 | break; 109 | case STATUS_COLOUR_OFF: 110 | ioOutputStr("\e[m"); 111 | break; 112 | } 113 | #endif 114 | } 115 | 116 | #define COLOUR(col) if (colours) { _statusColour(CONCAT(STATUS_COLOUR_, col)); } 117 | 118 | static bool _printInfo(const bool colours, const INFO_t *info, const EPOCH_t *epoch) 119 | { 120 | ioOutputStr("%4u %4u %4u %4u %4u %4u %5u | ", 121 | info->nUbx, info->nNmea, info->nRtcm3, info->nSpartn, info->nNova, info->nGarb, epoch != NULL ? epoch->seq : 0); 122 | 123 | const char *epochStr = "no navigation data"; 124 | 125 | if (epoch != NULL) 126 | { 127 | switch (epoch->fix) 128 | { 129 | case EPOCH_FIX_UNKNOWN: 130 | break; 131 | case EPOCH_FIX_NOFIX: 132 | COLOUR(NOFIX); 133 | break; 134 | case EPOCH_FIX_DRONLY: 135 | case EPOCH_FIX_TIME: 136 | case EPOCH_FIX_S2D: 137 | case EPOCH_FIX_S3D: 138 | case EPOCH_FIX_S3D_DR: 139 | case EPOCH_FIX_RTK_FLOAT: 140 | case EPOCH_FIX_RTK_FIXED: 141 | case EPOCH_FIX_RTK_FLOAT_DR: 142 | case EPOCH_FIX_RTK_FIXED_DR: 143 | if (epoch->fixOk) 144 | { 145 | COLOUR(FIXOK); 146 | } 147 | else 148 | { 149 | COLOUR(MASKED); 150 | } 151 | break; 152 | } 153 | 154 | epochStr = epoch->str; 155 | } 156 | 157 | ioOutputStr("%s", epochStr); 158 | ioWriteOutput(true); 159 | 160 | COLOUR(OFF); 161 | 162 | ioOutputStr("\n"); 163 | return ioWriteOutput(true); 164 | } 165 | 166 | int statusRun(const char *portArg, const bool extraInfo, const bool noProbe) 167 | { 168 | RX_OPTS_t opts = RX_OPTS_DEFAULT(); 169 | if (noProbe) 170 | { 171 | opts.autobaud = false; 172 | opts.detect = false; 173 | } 174 | RX_t *rx = rxInit(portArg, &opts); 175 | if ( (rx == NULL) || !rxOpen(rx) ) 176 | { 177 | free(rx); 178 | return EXIT_RXFAIL; 179 | } 180 | 181 | DEBUG_CFG_t debugCfg; 182 | debugGetCfg(&debugCfg); 183 | 184 | (void)extraInfo; 185 | 186 | INFO_t info; 187 | memset(&info, 0, sizeof(info)); 188 | 189 | gAbort = false; 190 | signal(SIGINT, _sigHandler); 191 | signal(SIGTERM, _sigHandler); 192 | NOT_WIN( signal(SIGHUP, _sigHandler) ); 193 | 194 | EPOCH_t coll; 195 | EPOCH_t epoch; 196 | epochInit(&coll); 197 | 198 | PRINT("Dumping receiver status..."); 199 | 200 | ioOutputStr("UBX NMEA RTCM SPAR NOVA GARB Epoch | %s\n", epochStrHeader()); 201 | ioWriteOutput(false); 202 | 203 | uint64_t lastEpoch = TIME(); 204 | 205 | while (!gAbort) 206 | { 207 | const uint64_t now = TIME(); 208 | PARSER_MSG_t *msg = rxGetNextMessage(rx); 209 | if (msg != NULL) 210 | { 211 | info.nMsgs++; 212 | if (epochCollect(&coll, msg, &epoch)) 213 | { 214 | info.nEpoch++; 215 | lastEpoch = now; 216 | if (!_printInfo(debugCfg.colour, &info, &epoch)) 217 | { 218 | break; 219 | } 220 | } 221 | switch (msg->type) 222 | { 223 | case PARSER_MSGTYPE_UBX: 224 | info.nUbx++; 225 | if (UBX_CLSID(msg->data) == UBX_INF_CLSID) 226 | { 227 | switch (UBX_MSGID(msg->data)) 228 | { 229 | case UBX_INF_WARNING_MSGID: 230 | case UBX_INF_ERROR_MSGID: 231 | WARNING("%s: %s", msg->name, msg->info); 232 | break; 233 | } 234 | } 235 | break; 236 | case PARSER_MSGTYPE_NMEA: 237 | if ( (msg->name[8] == 'T') && (msg->name[9] == 'X') && (msg->name[10] == 'T') && // "NMEA-GP-TXT" 238 | ( (msg->info[0] == 'W') || (msg->info[0] == 'E') ) ) // "WARNING: ...", "ERROR: ..." 239 | { 240 | WARNING("%s: %s", msg->name, msg->info); 241 | } 242 | info.nNmea++; 243 | break; 244 | case PARSER_MSGTYPE_RTCM3: 245 | info.nRtcm3++; 246 | break; 247 | case PARSER_MSGTYPE_SPARTN: 248 | info.nSpartn++; 249 | break; 250 | case PARSER_MSGTYPE_NOVATEL: 251 | info.nNova++; 252 | break; 253 | case PARSER_MSGTYPE_GARBAGE: 254 | info.nGarb++; 255 | break; 256 | } 257 | } 258 | // No data, yield 259 | else 260 | { 261 | SLEEP(5); 262 | } 263 | if ( (now - lastEpoch) > 5000 ) 264 | { 265 | _printInfo(debugCfg.colour, &info, NULL); 266 | lastEpoch = now; 267 | } 268 | } 269 | bool res = ioWriteOutput(true); 270 | 271 | rxClose(rx); 272 | free(rx); 273 | 274 | return res ? (info.nMsgs > 0 ? EXIT_SUCCESS : EXIT_RXNODATA) : EXIT_OTHERFAIL; 275 | } 276 | 277 | /* ****************************************************************************************************************** */ 278 | // eof 279 | -------------------------------------------------------------------------------- /ubloxcfg/ubloxcfg-99-test.jsonc: -------------------------------------------------------------------------------- 1 | // ubloxcfg -- u-blox positioning receivers configuration library 2 | { 3 | "sources": [ 4 | 5 | ], "items": [ 6 | 7 | // ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 8 | // Test items 9 | { "id" : "0x10fe0001", "name" : "CFG-UBLOXCFGTEST-L", "size" : 0, "type" : "L", "title" : "ubloxcfg library test item type L" }, 10 | { "id" : "0x20fe0011", "name" : "CFG-UBLOXCFGTEST-U1", "size" : 1, "type" : "U1", "title" : "ubloxcfg library test item type U1" }, 11 | { "id" : "0x30fe0012", "name" : "CFG-UBLOXCFGTEST-U2", "size" : 2, "type" : "U2", "title" : "ubloxcfg library test item type U2" }, 12 | { "id" : "0x40fe0013", "name" : "CFG-UBLOXCFGTEST-U4", "size" : 4, "type" : "U4", "title" : "ubloxcfg library test item type U4" }, 13 | { "id" : "0x50fe0014", "name" : "CFG-UBLOXCFGTEST-U8", "size" : 8, "type" : "U8", "title" : "ubloxcfg library test item type U8" }, 14 | { "id" : "0x20fe0021", "name" : "CFG-UBLOXCFGTEST-I1", "size" : 1, "type" : "I1", "title" : "ubloxcfg library test item type I1" }, 15 | { "id" : "0x30fe0022", "name" : "CFG-UBLOXCFGTEST-I2", "size" : 2, "type" : "I2", "title" : "ubloxcfg library test item type I2" }, 16 | { "id" : "0x40fe0023", "name" : "CFG-UBLOXCFGTEST-I4", "size" : 4, "type" : "I4", "title" : "ubloxcfg library test item type I4" }, 17 | { "id" : "0x50fe0024", "name" : "CFG-UBLOXCFGTEST-I8", "size" : 8, "type" : "I8", "title" : "ubloxcfg library test item type I8" }, 18 | { "id" : "0x20fe0031", "name" : "CFG-UBLOXCFGTEST-X1", "size" : 1, "type" : "X1", "title" : "ubloxcfg library test item type X1", 19 | "consts" : [ { "name" : "FIRST", "value" : "0x01", "title" : "first bit (LSB)" }, 20 | { "name" : "SECOND", "value" : "0x02", "title" : "second bit" }, 21 | { "name" : "LAST", "value" : "0x80", "title" : "last bit (MSB)" } ] }, 22 | { "id" : "0x30fe0032", "name" : "CFG-UBLOXCFGTEST-X2", "size" : 2, "type" : "X2", "title" : "ubloxcfg library test item type X2", 23 | "consts" : [ { "name" : "FIRST", "value" : "0x0001", "title" : "first bit (LSB)" }, 24 | { "name" : "SECOND", "value" : "0x0002", "title" : "second bit" }, 25 | { "name" : "LAST", "value" : "0x8000", "title" : "last bit (MSB)" } ] }, 26 | { "id" : "0x40fe0033", "name" : "CFG-UBLOXCFGTEST-X4", "size" : 4, "type" : "X4", "title" : "ubloxcfg library test item type X4", 27 | "consts" : [ { "name" : "FIRST", "value" : "0x00000001", "title" : "first bit (LSB)" }, 28 | { "name" : "SECOND", "value" : "0x00000002", "title" : "second bit" }, 29 | { "name" : "LAST", "value" : "0x80000000", "title" : "last bit (MSB)" } ] }, 30 | { "id" : "0x50fe0034", "name" : "CFG-UBLOXCFGTEST-X8", "size" : 8, "type" : "X8", "title" : "ubloxcfg library test item type X8", 31 | "consts" : [ { "name" : "FIRST", "value" : "0x0000000000000001", "title" : "first bit (LSB)" }, 32 | { "name" : "SECOND", "value" : "0x0000000000000002", "title" : "second bit" }, 33 | { "name" : "LAST", "value" : "0x8000000000000000", "title" : "last bit (MSB)" } ] }, 34 | { "id" : "0x40fe0041", "name" : "CFG-UBLOXCFGTEST-R4", "size" : 4, "type" : "R4", "title" : "ubloxcfg library test item type R4" }, 35 | { "id" : "0x50fe0042", "name" : "CFG-UBLOXCFGTEST-R8", "size" : 8, "type" : "R8", "title" : "ubloxcfg library test item type R8" }, 36 | { "id" : "0x20fe0041", "name" : "CFG-UBLOXCFGTEST-E1", "size" : 1, "type" : "E1", "title" : "ubloxcfg library test item type E1", 37 | "consts" : [ { "name" : "ONE", "value" : "1", "title" : "test value 1" }, 38 | { "name" : "TWO", "value" : "2", "title" : "test value 2" }, 39 | { "name" : "THREE", "value" : "3", "title" : "test value 3" }, 40 | { "name" : "MINUS_ONE", "value" : "-1", "title" : "test value -1" }, 41 | { "name" : "FOUR_HEX", "value" : "0x04", "title" : "test value 0x04" } ] }, 42 | { "id" : "0x30fe0042", "name" : "CFG-UBLOXCFGTEST-E2", "size" : 2, "type" : "E2", "title" : "ubloxcfg library test item type E2", 43 | "consts" : [ { "name" : "ONE", "value" : "1", "title" : "test value 1" }, 44 | { "name" : "TWO", "value" : "2", "title" : "test value 2" }, 45 | { "name" : "THREE", "value" : "3", "title" : "test value 3" }, 46 | { "name" : "MINUS_ONE", "value" : "-1", "title" : "test value -1" }, 47 | { "name" : "FOUR_HEX", "value" : "0x0004", "title" : "test value 0x0004" } ] }, 48 | { "id" : "0x40fe0043", "name" : "CFG-UBLOXCFGTEST-E4", "size" : 4, "type" : "E4", "title" : "ubloxcfg library test item type E4", 49 | "consts" : [ { "name" : "ONE", "value" : "1", "title" : "test value 1" }, 50 | { "name" : "TWO", "value" : "2", "title" : "test value 2" }, 51 | { "name" : "THREE", "value" : "3", "title" : "test value 3" }, 52 | { "name" : "MINUS_ONE", "value" : "-1", "title" : "test value -1" }, 53 | { "name" : "FOUR_HEX", "value" : "0x00000004", "title" : "test value 0x00000004" } ] } 54 | // Undocumented (unknown) items for test 55 | //{ "id" : "0x10fe0ff1", "name" : "CFG-UBLOXCFGTEST-NOPE_L", "size" : 0, "type" : "L", "title" : "ubloxcfg library test inexistent item size 0" }, 56 | //{ "id" : "0x20fe0ff2", "name" : "CFG-UBLOXCFGTEST-NOPE_U1", "size" : 1, "type" : "U1", "title" : "ubloxcfg library test inexistent item size 1" }, 57 | //{ "id" : "0x30fe0ff3", "name" : "CFG-UBLOXCFGTEST-NOPE_U2", "size" : 2, "type" : "U2", "title" : "ubloxcfg library test inexistent item size 2" }, 58 | //{ "id" : "0x40fe0ff4", "name" : "CFG-UBLOXCFGTEST-NOPE_U4", "size" : 4, "type" : "U4", "title" : "ubloxcfg library test inexistent item size 4" }, 59 | //{ "id" : "0x50fe0ff5", "name" : "CFG-UBLOXCFGTEST-NOPE_U8", "size" : 8, "type" : "U8", "title" : "ubloxcfg library test inexistent item size 8" }, 60 | // ..and a few more in the range 0x.0fe0f00 .. 0x.0fe0fff! 61 | // ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 62 | ] 63 | } -------------------------------------------------------------------------------- /ff/ff_debug.c: -------------------------------------------------------------------------------- 1 | // clang-format off 2 | // flipflip's colourful (printf style) debugging stuff 3 | // 4 | // Copyright (c) Philippe Kehl (flipflip at oinkzwurgl dot org) and contributors 5 | // https://oinkzwurgl.org/projaeggd/ubloxcfg/ 6 | // 7 | // This program is free software: you can redistribute it and/or modify it under the terms of the 8 | // GNU General Public License as published by the Free Software Foundation, either version 3 of the 9 | // License, or (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 12 | // even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | // See the GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License along with this program. 16 | // If not, see . 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #ifndef _WIN32 25 | # include 26 | # include 27 | # include 28 | #endif 29 | #ifdef _WIN32 30 | # define NOGDI 31 | # include 32 | #endif 33 | 34 | #include "ff_debug.h" 35 | 36 | /* ****************************************************************************************************************** */ 37 | 38 | static void _debugLog(const DEBUG_LEVEL_t level, const char *line, const DEBUG_CFG_t *cfg) 39 | { 40 | (void)cfg; 41 | (void)level; 42 | fputs(line, stderr); 43 | } 44 | 45 | static DEBUG_CFG_t gCfg = 46 | { 47 | .level = DEBUG_LEVEL_PRINT, 48 | .colour = false, 49 | .mark = NULL, 50 | .func = _debugLog, 51 | .arg = NULL, 52 | }; 53 | 54 | void debugSetup(const DEBUG_CFG_t *cfg) 55 | { 56 | memcpy(&gCfg, cfg, sizeof(gCfg)); 57 | if (gCfg.func == NULL) 58 | { 59 | gCfg.func = _debugLog; 60 | } 61 | if (gCfg.level < DEBUG_LEVEL_ERROR) 62 | { 63 | gCfg.level = DEBUG_LEVEL_ERROR; 64 | } 65 | if (gCfg.level > DEBUG_LEVEL_TRACE) 66 | { 67 | gCfg.level = DEBUG_LEVEL_TRACE; 68 | } 69 | } 70 | 71 | void debugGetCfg(DEBUG_CFG_t *cfg) 72 | { 73 | if (cfg != NULL) 74 | { 75 | memcpy(cfg, &gCfg, sizeof(gCfg)); 76 | } 77 | } 78 | 79 | typedef enum DEBUG_COLOUR_e 80 | { 81 | LOG_COLOUR_ERROR, LOG_COLOUR_WARNING, LOG_COLOUR_NOTICE, LOG_COLOUR_PRINT, 82 | LOG_COLOUR_DEBUG, LOG_COLOUR_TRACE, LOG_COLOUR_OFF 83 | } DEBUG_COLOUR_t; 84 | 85 | static void _logColour(const DEBUG_LEVEL_t level, const DEBUG_COLOUR_t colour) 86 | { 87 | if (gCfg.colour) 88 | { 89 | #ifdef _WIN32 90 | switch (colour) 91 | { 92 | case LOG_COLOUR_ERROR: 93 | SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_INTENSITY); 94 | break; 95 | case LOG_COLOUR_WARNING: 96 | SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY); 97 | break; 98 | case LOG_COLOUR_NOTICE: 99 | SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY); 100 | break; 101 | case LOG_COLOUR_OFF: 102 | case LOG_COLOUR_PRINT: 103 | SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); 104 | break; 105 | case LOG_COLOUR_DEBUG: 106 | SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_BLUE); 107 | break; 108 | case LOG_COLOUR_TRACE: 109 | SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN | FOREGROUND_BLUE); 110 | break; 111 | } 112 | gCfg.func(level, "", &gCfg); 113 | #else 114 | switch (colour) 115 | { 116 | case LOG_COLOUR_ERROR: 117 | gCfg.func(level, "\e[1;31m", &gCfg); 118 | break; 119 | case LOG_COLOUR_WARNING: 120 | gCfg.func(level, "\e[1;33m", &gCfg); 121 | break; 122 | case LOG_COLOUR_NOTICE: 123 | gCfg.func(level, "\e[1m", &gCfg); 124 | break; 125 | case LOG_COLOUR_PRINT: 126 | gCfg.func(level, "\e[m", &gCfg); 127 | break; 128 | case LOG_COLOUR_DEBUG: 129 | gCfg.func(level, "\e[0;36m", &gCfg); 130 | break; 131 | case LOG_COLOUR_TRACE: 132 | gCfg.func(level, "\e[0;35m", &gCfg); 133 | break; 134 | case LOG_COLOUR_OFF: 135 | gCfg.func(level, "\e[m", &gCfg); 136 | break; 137 | } 138 | #endif 139 | } 140 | } 141 | 142 | static void _log(const DEBUG_LEVEL_t level, const DEBUG_COLOUR_t colour, const char *fmt, va_list args) 143 | { 144 | if (gCfg.level < level) 145 | { 146 | return; 147 | } 148 | char fmtMod[200]; 149 | fmtMod[0] = '\0'; 150 | int len = 0; 151 | if ( (gCfg.mark != NULL) && (gCfg.mark[0] != '\0') ) 152 | { 153 | len += snprintf(&fmtMod[len], sizeof(fmtMod) - len, "%s: ", gCfg.mark); 154 | } 155 | snprintf(&fmtMod[len], sizeof(fmtMod) - len, "%s\n", fmt); 156 | fmtMod[sizeof(fmtMod)-2] = '\n'; 157 | fmtMod[sizeof(fmtMod)-1] = '\0'; 158 | _logColour(level, colour); 159 | char buf[1024]; 160 | vsnprintf(buf, sizeof(buf), fmtMod, args); 161 | gCfg.func(level, buf, &gCfg); 162 | _logColour(level, LOG_COLOUR_OFF); 163 | } 164 | 165 | void _hexdump(const DEBUG_LEVEL_t level, const DEBUG_COLOUR_t colour, const void *data, const int size, const char *fmt, va_list args) 166 | { 167 | if (gCfg.level < level) 168 | { 169 | return; 170 | } 171 | if (fmt != NULL) 172 | { 173 | _log(level, colour, fmt, args); 174 | } 175 | 176 | char mark[200]; 177 | mark[0] = '\0'; 178 | if ( (gCfg.mark != NULL) && (gCfg.mark[0] != '\0') ) 179 | { 180 | snprintf(mark, sizeof(mark), "%s: ", gCfg.mark); 181 | } 182 | 183 | const char i2hex[] = "0123456789abcdef"; 184 | const uint8_t *pData = (const uint8_t *)data; 185 | for (int ix = 0; ix < size; ) 186 | { 187 | char str[70]; 188 | memset(str, ' ', sizeof(str)); 189 | str[50] = '|'; 190 | str[67] = '|'; 191 | str[68] = '\0'; 192 | for (int ix2 = 0; (ix2 < 16) && ((ix + ix2) < size); ix2++) 193 | { 194 | // 1 2 3 4 5 6 195 | // 012345678901234567890123456789012345678901234567890123456789012345678 196 | // xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx |................|\0 197 | // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 198 | const uint8_t c = pData[ix + ix2]; 199 | int pos1 = 3 * ix2; 200 | int pos2 = 51 + ix2; 201 | if (ix2 > 7) 202 | { 203 | pos1++; 204 | } 205 | str[pos1 ] = i2hex[ (c >> 4) & 0xf ]; 206 | str[pos1 + 1] = i2hex[ c & 0xf ]; 207 | 208 | str[pos2] = isprint((int)c) ? c : '.'; 209 | } 210 | _logColour(level, colour); 211 | char buf[1024]; 212 | snprintf(buf, sizeof(buf), "%s0x%04" PRIx8 " %05d %s\n", mark, ix, ix, str); 213 | gCfg.func(level, buf, &gCfg); 214 | _logColour(level, LOG_COLOUR_OFF); 215 | ix += 16; 216 | } 217 | } 218 | 219 | void ERROR(const char *fmt, ...) 220 | { 221 | va_list args; 222 | va_start(args, fmt); 223 | _log(DEBUG_LEVEL_ERROR, LOG_COLOUR_ERROR, fmt, args); 224 | va_end(args); 225 | } 226 | 227 | void WARNING(const char *fmt, ...) 228 | { 229 | va_list args; 230 | va_start(args, fmt); 231 | _log(DEBUG_LEVEL_WARNING, LOG_COLOUR_WARNING, fmt, args); 232 | va_end(args); 233 | } 234 | 235 | void PRINT(const char *fmt, ...) 236 | { 237 | va_list args; 238 | va_start(args, fmt); 239 | _log(DEBUG_LEVEL_PRINT, LOG_COLOUR_PRINT, fmt, args); 240 | va_end(args); 241 | } 242 | 243 | void NOTICE(const char *fmt, ...) 244 | { 245 | va_list args; 246 | va_start(args, fmt); 247 | _log(DEBUG_LEVEL_NOTICE, LOG_COLOUR_NOTICE, fmt, args); 248 | va_end(args); 249 | } 250 | 251 | void DEBUG(const char *fmt, ...) 252 | { 253 | va_list args; 254 | va_start(args, fmt); 255 | _log(DEBUG_LEVEL_DEBUG, LOG_COLOUR_DEBUG, fmt, args); 256 | va_end(args); 257 | } 258 | 259 | bool isDEBUG(void) 260 | { 261 | return (gCfg.level >= DEBUG_LEVEL_DEBUG); 262 | } 263 | 264 | void TRACE(const char *fmt, ...) 265 | { 266 | va_list args; 267 | va_start(args, fmt); 268 | _log(DEBUG_LEVEL_TRACE, LOG_COLOUR_TRACE, fmt, args); 269 | va_end(args); 270 | } 271 | 272 | bool isTRACE(void) 273 | { 274 | return (gCfg.level >= DEBUG_LEVEL_TRACE); 275 | } 276 | 277 | void DEBUG_HEXDUMP(const void *data, const int size, const char *fmt, ...) 278 | { 279 | va_list args; 280 | va_start(args, fmt); 281 | _hexdump(DEBUG_LEVEL_DEBUG, LOG_COLOUR_DEBUG, data, size, fmt, args); 282 | va_end(args); 283 | } 284 | 285 | void TRACE_HEXDUMP(const void *data, const int size, const char *fmt, ...) 286 | { 287 | va_list args; 288 | va_start(args, fmt); 289 | _hexdump(DEBUG_LEVEL_TRACE, LOG_COLOUR_TRACE, data, size, fmt, args); 290 | va_end(args); 291 | } 292 | 293 | void PANIC_AND_EXIT(const char *fmt, ...) 294 | { 295 | va_list args; 296 | va_start(args, fmt); 297 | vfprintf(stderr, fmt, args); 298 | va_end(args); 299 | fputs("\n", stderr); 300 | #ifndef _WIN32 301 | void *frames[100]; 302 | const int nFrames = backtrace(frames, sizeof(frames)); 303 | backtrace_symbols_fd(frames, nFrames, STDERR_FILENO); 304 | #endif 305 | exit(255); 306 | } 307 | 308 | void DEBUGGER_BREAK(void) 309 | { 310 | #ifdef _WIN32 311 | DebugBreak(); 312 | #else 313 | raise(SIGTRAP); 314 | #endif 315 | } 316 | 317 | 318 | /* ****************************************************************************************************************** */ 319 | // eof 320 | -------------------------------------------------------------------------------- /cfgtool/cfgtool_util.c: -------------------------------------------------------------------------------- 1 | // clang-format off 2 | /* ****************************************************************************************************************** */ 3 | // u-blox positioning receivers configuration tool 4 | // 5 | // Copyright (c) Philippe Kehl (flipflip at oinkzwurgl dot org) and contributors 6 | // 7 | // This program is free software: you can redistribute it and/or modify it under the terms of the 8 | // GNU General Public License as published by the Free Software Foundation, either version 3 of the 9 | // License, or (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 12 | // even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | // See the GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License along with this program. 16 | // If not, see . 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include "ubloxcfg/ubloxcfg.h" 29 | 30 | #include "cfgtool_util.h" 31 | 32 | #define INPUT_MAX_LINE_LEN 2000 33 | 34 | static char gInName[PATH_MAX]; 35 | static FILE *gInFile; 36 | int gInLineNr; 37 | bool gOutOverwrite; 38 | 39 | static char gOutName[PATH_MAX]; 40 | FILE *gOutFile; 41 | int gOutLineNr; 42 | 43 | void ioSetInput(const char *name, FILE *file) 44 | { 45 | TRACE("ioSetInput(%s, %p)", name, file); 46 | if ( (name == NULL) || (name[0] == '\0') ) 47 | { 48 | return; 49 | } 50 | snprintf(gInName, sizeof(gInName), "%s", name); 51 | gInFile = file; 52 | gInLineNr = 0; 53 | } 54 | 55 | void ioSetOutput(const char *name, FILE *file, const bool overwrite) 56 | { 57 | TRACE("ioSetOutput(%s, %p, %d)", name, file, overwrite); 58 | if ( (name == NULL) || (name[0] == '\0') ) 59 | { 60 | return; 61 | } 62 | snprintf(gOutName, sizeof(gOutName), "%s", name); 63 | gOutFile = file; 64 | gOutLineNr = 0; 65 | gOutOverwrite = overwrite; 66 | } 67 | 68 | IO_LINE_t *ioGetNextInputLine(void) 69 | { 70 | static char line[INPUT_MAX_LINE_LEN]; 71 | static IO_LINE_t resLine; 72 | resLine.line = NULL; 73 | resLine.lineLen = 0; 74 | bool res = false; 75 | // get next useful line from input 76 | while (fgets(line, sizeof(line), gInFile) != NULL) 77 | { 78 | gInLineNr++; 79 | char *pLine = line; 80 | 81 | // remove comments 82 | char *comment = strchr(pLine, '#'); 83 | if (comment != NULL) 84 | { 85 | *comment = '\0'; 86 | } 87 | 88 | // remove leading space 89 | while (isspace(*pLine) != 0) 90 | { 91 | pLine++; 92 | } 93 | 94 | // all whitespace? 95 | if (*pLine == '\0') 96 | { 97 | continue; 98 | } 99 | 100 | // remove trailing whitespace 101 | int inLineLen = strlen(pLine); 102 | char *pEnd = pLine + inLineLen - 1; 103 | while( (pEnd > pLine) && (isspace(*pEnd) != 0) ) 104 | { 105 | pEnd--; 106 | inLineLen--; 107 | } 108 | pEnd[1] = '\0'; 109 | 110 | resLine.line = pLine; 111 | resLine.lineLen = inLineLen; 112 | resLine.lineNr = gInLineNr; 113 | resLine.file = gInName; 114 | res = true; 115 | break; 116 | } 117 | 118 | return res ? &resLine : NULL; 119 | } 120 | 121 | int ioReadInput(uint8_t *data, const int size) 122 | { 123 | int res = 0; 124 | if ( (data != NULL) && (size > 0) ) 125 | { 126 | if (feof(gInFile) != 0) // FIXME: why does this flag on /dev/tty... devices? 127 | { 128 | res = -1; 129 | } 130 | else 131 | { 132 | // TODO: only read as much as is currently available 133 | res = fread(data, 1, size, gInFile); 134 | } 135 | } 136 | return res; 137 | } 138 | 139 | 140 | static char gOutputBuf[1024 * 1024] = { 0 }; 141 | static int gOutputBufSize = 0; 142 | 143 | void ioOutputStr(const char *fmt, ...) 144 | { 145 | const int totSize = sizeof(gOutputBuf); 146 | if (gOutputBufSize >= totSize) 147 | { 148 | return; 149 | } 150 | 151 | const int remSize = totSize - gOutputBufSize; 152 | 153 | va_list args; 154 | va_start(args, fmt); 155 | const int writeSize = vsnprintf(&gOutputBuf[gOutputBufSize], remSize, fmt, args); 156 | va_end(args); 157 | 158 | if (writeSize > remSize) 159 | { 160 | gOutputBufSize = totSize; 161 | } 162 | else 163 | { 164 | gOutputBufSize += writeSize; 165 | } 166 | } 167 | 168 | void ioAddOutputBin(const uint8_t *data, const int size) 169 | { 170 | const int totSize = sizeof(gOutputBuf); 171 | if (gOutputBufSize >= totSize) 172 | { 173 | return; 174 | } 175 | 176 | const int remSize = totSize - gOutputBufSize; 177 | if (remSize < size) 178 | { 179 | return; 180 | } 181 | 182 | memcpy(&gOutputBuf[gOutputBufSize], data, size); 183 | gOutputBufSize += size; 184 | } 185 | 186 | void ioAddOutputHex(const uint8_t *data, const int size, const int wordsPerLine, const bool ugly) 187 | { 188 | const int bytesPerLine = wordsPerLine * 4; 189 | for (int ix = 0; ix < size; ix++) 190 | { 191 | const int pos = ix % bytesPerLine; 192 | if (pos > 0) 193 | { 194 | ioOutputStr((pos % 4) == 0 ? " " : " "); 195 | } 196 | ioOutputStr(ugly ? "%02" PRIX8 : "%02" PRIx8, data[ix]); 197 | if ( (pos == (bytesPerLine - 1)) || (ix == (size - 1)) ) 198 | { 199 | ioOutputStr("\n"); 200 | } 201 | } 202 | } 203 | 204 | void ioAddOutputC(const uint8_t *data, const int size, const int wordsPerLine, const char *indent) 205 | { 206 | const int bytesPerLine = wordsPerLine * 4; 207 | for (int ix = 0; ix < size; ix++) 208 | { 209 | const int pos = ix % bytesPerLine; 210 | if (pos == 0) 211 | { 212 | ioOutputStr("%s", indent); 213 | } 214 | if (pos > 0) 215 | { 216 | ioOutputStr((pos % 4) == 0 ? " " : " "); 217 | } 218 | ioOutputStr("0x%02"PRIx8"%s", data[ix], (ix + 1) == size ? "" : ","); 219 | if ( (pos == (bytesPerLine - 1)) || (ix == (size - 1)) ) 220 | { 221 | ioOutputStr("\n"); 222 | } 223 | } 224 | } 225 | 226 | void ioAddOutputHexdump(const uint8_t *data, const int size) 227 | { 228 | const char i2hex[] = "0123456789abcdef"; 229 | const uint8_t *pData = data; 230 | for (int ix = 0; ix < size; ) 231 | { 232 | char str[70]; 233 | memset(str, ' ', sizeof(str)); 234 | str[50] = '|'; 235 | str[67] = '|'; 236 | str[68] = '\0'; 237 | for (int ix2 = 0; (ix2 < 16) && ((ix + ix2) < size); ix2++) 238 | { 239 | // 1 2 3 4 5 6 240 | // 012345678901234567890123456789012345678901234567890123456789012345678 241 | // xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx |................|\0 242 | // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 243 | const uint8_t c = pData[ix + ix2]; 244 | int pos1 = 3 * ix2; 245 | int pos2 = 51 + ix2; 246 | if (ix2 > 7) 247 | { 248 | pos1++; 249 | } 250 | str[pos1 ] = i2hex[ (c >> 4) & 0xf ]; 251 | str[pos1 + 1] = i2hex[ c & 0xf ]; 252 | 253 | str[pos2] = isprint((int)c) ? c : '.'; 254 | } 255 | ioOutputStr("0x%04"PRIx8" %05d %s\n", ix, ix, str); 256 | ix += 16; 257 | } 258 | } 259 | 260 | bool ioWriteOutput(const bool append) 261 | { 262 | const int totSize = sizeof(gOutputBuf); 263 | if (gOutputBufSize >= totSize) 264 | { 265 | WARNING("Too much output data, not writing to '%s'!", gOutName); 266 | return false; 267 | } 268 | 269 | const char *failStr = NULL; 270 | bool res = true; 271 | if ( (gOutFile != stdout) && (gOutFile != stderr) ) 272 | { 273 | if (!append && !gOutOverwrite && (access(gOutName, F_OK) == 0)) 274 | { 275 | failStr = "File already exists"; 276 | res = false; 277 | } 278 | 279 | if (res) 280 | { 281 | gOutFile = fopen(gOutName, append ? "a" : "w"); 282 | if (gOutFile == NULL) 283 | { 284 | failStr = strerror(errno); 285 | res = false; 286 | } 287 | } 288 | } 289 | 290 | if (res) 291 | { 292 | if (!append) 293 | { 294 | PRINT("Writing output to '%s'.", gOutName); 295 | } 296 | TRACE("Writing output to '%s' (%d bytes).", gOutName, gOutputBufSize); 297 | res = (int)fwrite(gOutputBuf, 1, gOutputBufSize, gOutFile) == gOutputBufSize; 298 | } 299 | 300 | gOutputBufSize = 0; 301 | 302 | if (!res) 303 | { 304 | WARNING("Failed writing '%s': %s", gOutName, failStr == NULL ? "Unknown error" : failStr); 305 | } 306 | return res; 307 | } 308 | 309 | /* ****************************************************************************************************************** */ 310 | 311 | bool layersStringToFlags(const char *layers, bool *ram, bool *bbr, bool *flash, bool *def) 312 | { 313 | char tmp[200]; 314 | if (snprintf(tmp, sizeof(tmp), "%s", layers) >= (int)sizeof(tmp)) 315 | { 316 | return false; 317 | } 318 | 319 | bool res = true; 320 | char *tok = strtok(tmp, ","); 321 | while (tok != NULL) 322 | { 323 | UBLOXCFG_LAYER_t layer; 324 | if (ubloxcfg_layerFromName(tok, &layer)) 325 | { 326 | switch (layer) 327 | { 328 | case UBLOXCFG_LAYER_RAM: 329 | if (ram != NULL) 330 | { 331 | *ram = true; 332 | } 333 | break; 334 | case UBLOXCFG_LAYER_BBR: 335 | if (bbr != NULL) 336 | { 337 | *bbr = true; 338 | } 339 | break; 340 | case UBLOXCFG_LAYER_FLASH: 341 | if (flash != NULL) 342 | { 343 | *flash = true; 344 | } 345 | break; 346 | case UBLOXCFG_LAYER_DEFAULT: 347 | if (def != NULL) 348 | { 349 | *def = true; 350 | } 351 | break; 352 | } 353 | } 354 | else 355 | { 356 | WARNING("Illegal layer '%s' in '%s'!", tok, layers); 357 | res = false; 358 | break; 359 | } 360 | tok = strtok(NULL, ","); 361 | } 362 | 363 | return res; 364 | } 365 | 366 | /* ****************************************************************************************************************** */ 367 | // eof 368 | --------------------------------------------------------------------------------