From edba85d1e208d2e885a141c806685b24cc098790 Mon Sep 17 00:00:00 2001 From: "Dr.-Ing. Amilcar do Carmo Lucas" Date: Fri, 13 Nov 2026 14:06:05 +0100 Subject: [PATCH 1/2] feat!: port ArduPilot log loader to PlotJuggler 4 Update the plugin to version 0.2.0 for PlotJuggler 4.1 and plotjuggler_sdk 0.40.0 using the C ABI, C++20, and Qt 6. - Publish timestamped topic records through the SDK and reset state between imports. - Preserve parameter snapshots, message logs, GPS synchronization, optional labels, and XML descriptions as dataset metadata. - Handle repeated parameters, snapshot-only logs, cancellation, and file and timestamp errors. - Retain catkin and ament integration and document Conan, ROS, Docker, installation, and testing workflows. - Prepare and cache SDK packages once per platform, share them across CI variants, and test both built and installed plugins. - Expand smoke tests for timestamps, MSG layouts, imports, parameters, snapshots, configuration, and failures. Validation: actionlint, four Linux label configurations, offline Conan package restores, installed-plugin tests, and catkin/ament CMake builds. Windows, macOS, and the full Docker image were not tested. BREAKING CHANGE: PlotJuggler 3 and Qt 5 binaries are incompatible. The message timeline is now /2. Message Timeline/index, and field descriptions are available in dataset metadata instead of tooltips. Signed-off-by: Dr.-Ing. Amilcar do Carmo Lucas --- .dockerignore | 7 + .github/workflows/build.yml | 260 +++++------ .gitignore | 2 + CMakeLists.txt | 179 +++----- DataLoadAPBin/dataload_apbin.cpp | 335 +++++++------- DataLoadAPBin/dataload_apbin.h | 29 +- DataLoadAPBin/manifest.json | 9 + Dockerfile | 60 +-- README.md | 289 +++++++----- conanfile.txt | 16 +- package.xml | 5 +- tests/CMakeLists.txt | 37 +- tests/pj_plugin_smoketest.cpp | 730 ++++++++++++++++++++----------- tests/test_plugin.sh | 10 +- 14 files changed, 1089 insertions(+), 879 deletions(-) create mode 100644 .dockerignore create mode 100644 DataLoadAPBin/manifest.json diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..835b9e2 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,7 @@ +.git +.venv +build +tests/build +artifacts +plugin_install +CMakeUserPresets.json diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7abff50..0c98360 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,5 +1,4 @@ -name: Build plugin - +name: Build PlotJuggler 4 plugin on: push: branches: [main] @@ -8,21 +7,17 @@ on: workflow_dispatch: env: - # Single source of truth: both the clone and the cache key derive from this. - PJ_TAG: '3.9.2' + # Export and restore Conan archives with the same tested Conan version. + CONAN_VERSION: '2.34.0' jobs: - # Build PlotJuggler once per platform and cache the install tree. Hoisted out of - # the plugin matrix so it is not rebuilt once per build configuration. - plotjuggler: - name: PlotJuggler (${{ matrix.platform.label }}) + # Prepare the SDK once per platform and share its Conan packages. Hoisted out + # of the plugin matrix so dependencies are not rebuilt for each label variant. + sdk: + name: PlotJuggler SDK (${{ matrix.platform.label }}) runs-on: ${{ matrix.platform.os }} container: - # Ubuntu is built inside a 22.04 container rather than on a 24.04 runner so - # the artifacts keep the older libstdc++/glibc floor: a binary built against - # GCC 13 needs GLIBCXX_3.4.32 and will not load on Ubuntu 22.04, while a - # 22.04 build loads on both. This also matches the Dockerfile exactly, so a - # CI failure reproduces locally with `docker build`. + # Keep the SDK and plugin on the same Ubuntu 22.04 libstdc++/glibc floor. image: ${{ matrix.platform.container || '' }} strategy: fail-fast: false @@ -30,176 +25,149 @@ jobs: platform: - { os: ubuntu-latest, container: 'ubuntu:22.04', label: ubuntu-22.04 } - { os: windows-2022, label: windows-2022 } - steps: - # GITHUB_WORKSPACE is backslash-separated on Windows; normalise it so a - # single bash step can hand the path to cmake on every platform. - - name: Resolve install prefix - shell: bash - run: echo "PJ_INSTALL=${GITHUB_WORKSPACE//\\//}/pj_install" >> "$GITHUB_ENV" - - # The label is part of the key because runner.os alone cannot tell a 22.04 - # container build from a build on the runner's own newer userland. - - name: Cache PlotJuggler install - id: cache - uses: actions/cache@v6 - with: - path: pj_install - key: ${{ matrix.platform.label }}-plotjuggler-${{ env.PJ_TAG }} - - - name: Install PlotJuggler dependencies - if: steps.cache.outputs.cache-hit != 'true' && runner.os == 'Linux' - # No sudo: the container runs as root. python3 matters -- CMakeLists falls - # back to an empty LogMessageDescriptions.h without it, silently dropping - # the field tooltips from the built plugin. + - name: Install Linux SDK build tools + if: runner.os == 'Linux' + # Install git before checkout; the container runs as root. run: | apt-get update apt-get install -y --no-install-recommends \ - build-essential cmake git ca-certificates python3 zstd \ - qtbase5-dev libqt5svg5-dev libqt5websockets5-dev libqt5opengl5-dev \ - libqt5x11extras5-dev libprotoc-dev libzmq3-dev liblz4-dev libzstd-dev - - - name: Install Qt - if: steps.cache.outputs.cache-hit != 'true' && runner.os == 'Windows' - uses: jurplel/install-qt-action@v4 + build-essential cmake git ca-certificates python3 python3-venv zstd + - uses: actions/checkout@v7 + - uses: actions/setup-python@v6 + if: runner.os == 'Windows' with: - version: '5.15.2' - arch: 'win64_msvc2019_64' - - - name: Clone PlotJuggler - if: steps.cache.outputs.cache-hit != 'true' + python-version: '3.11' + - name: Set up Conan and detect compiler profile shell: bash - run: git clone --depth 1 --branch "$PJ_TAG" https://github.com/facontidavide/PlotJuggler.git plotjuggler - - - name: Configure PlotJuggler - if: steps.cache.outputs.cache-hit != 'true' - shell: bash - # CMAKE_POLICY_VERSION_MINIMUM is insurance: PlotJuggler 3.9.2 ships - # third-party directories declaring cmake_minimum_required(VERSION 3.0), - # which CMake 4 rejects outright. Ignored by CMake older than 3.31. run: | - cmake -S plotjuggler -B pj_build \ - -DCMAKE_INSTALL_PREFIX="$PJ_INSTALL" \ - -DCMAKE_BUILD_TYPE=RelWithDebInfo \ - -DCMAKE_POLICY_VERSION_MINIMUM=3.5 - - - name: Build & install PlotJuggler - if: steps.cache.outputs.cache-hit != 'true' + export CONAN_HOME="${RUNNER_TEMP//\\//}/conan-home" + if [ "$RUNNER_OS" = "Linux" ]; then + python3 -m venv "$RUNNER_TEMP/conan-env" + source "$RUNNER_TEMP/conan-env/bin/activate" + fi + python -m pip install "conan==${CONAN_VERSION}" + conan profile detect + mkdir -p sdk-cache + # Conan returns a Windows path on Windows; normalise it for Bash. + profile="$(conan profile path default)" + cp "${profile//\\//}" sdk-cache/default.profile + - name: Cache SDK Conan packages + id: sdk-cache + uses: actions/cache@v6 + with: + path: sdk-cache + # Include the compiler profile, ABI platform, dependency pins and + # archive version. Label options do not affect the SDK packages. + key: sdk-v1-${{ matrix.platform.label }}-conan-${{ env.CONAN_VERSION }}-Release-cpp20-${{ hashFiles('conanfile.txt', 'sdk-cache/default.profile') }} + - name: Prepare pinned SDK and export Conan packages + if: steps.sdk-cache.outputs.cache-hit != 'true' shell: bash - run: cmake --build pj_build --config RelWithDebInfo --target install --parallel "$(nproc || echo 2)" + run: | + export CONAN_HOME="${RUNNER_TEMP//\\//}/conan-home" + if [ "$RUNNER_OS" = "Linux" ]; then + source "$RUNNER_TEMP/conan-env/bin/activate" + fi + conan remote add plotjuggler https://plotjuggler.jfrog.io/artifactory/api/conan/plotjuggler-conan + conan install . -of sdk-build --build=missing -s build_type=Release \ + -s compiler.cppstd=20 --lockfile-out=sdk-cache/conan.lock + # Save packages portably, rather than copying Conan's path-dependent + # cache database. The isolated Conan home contains only this SDK graph. + conan cache save '*:*' --no-source --file=sdk-cache/conan-packages.tgz + - name: Share SDK packages with plugin jobs + uses: actions/upload-artifact@v7 + with: + name: ConanSDK-${{ matrix.platform.label }} + path: sdk-cache/ + if-no-files-found: error plugin: name: ${{ matrix.config.name }} (${{ matrix.platform.label }}) - needs: plotjuggler + needs: sdk runs-on: ${{ matrix.platform.os }} container: image: ${{ matrix.platform.container || '' }} strategy: - # Never let one configuration mask the others. fail-fast: false matrix: + # Use a supported host runner while keeping the Ubuntu 22.04 container's + # libstdc++/glibc floor. This also matches the default Docker base image. platform: - { os: ubuntu-latest, container: 'ubuntu:22.04', label: ubuntu-22.04 } - { os: windows-2022, label: windows-2022 } config: - - name: units - units: 'ON' - rcou: 'OFF' - - name: units-rcou - units: 'ON' - rcou: 'ON' - - name: plain - units: 'OFF' - rcou: 'OFF' - + - { name: plain, units: 'OFF', rcou: 'OFF' } + - { name: units, units: 'ON', rcou: 'OFF' } + - { name: rcou, units: 'OFF', rcou: 'ON' } + - { name: units-rcou, units: 'ON', rcou: 'ON' } steps: - # Before checkout, so that actions/checkout finds git and makes a real clone - # instead of falling back to a source tarball. - - name: Install plugin dependencies + - name: Install Linux build tools if: runner.os == 'Linux' + # Install git before checkout so it creates a clone rather than falling + # back to an archive. The container runs as root, so sudo is unnecessary. run: | apt-get update apt-get install -y --no-install-recommends \ - build-essential cmake git ca-certificates python3 zstd \ - qtbase5-dev libqt5svg5-dev libqt5websockets5-dev libqt5opengl5-dev \ - libqt5x11extras5-dev - - - name: Checkout plugin - uses: actions/checkout@v7 - - - name: Resolve install prefix - shell: bash - run: echo "PJ_INSTALL=${GITHUB_WORKSPACE//\\//}/pj_install" >> "$GITHUB_ENV" - - # The plotjuggler job has already populated this key, so a miss means - # something is wrong and should fail loudly rather than rebuild silently. - - name: Restore PlotJuggler install - uses: actions/cache/restore@v6 - with: - path: pj_install - key: ${{ matrix.platform.label }}-plotjuggler-${{ env.PJ_TAG }} - fail-on-cache-miss: true - - - name: Install Qt + build-essential cmake git ca-certificates python3 python3-venv qt6-base-dev + - uses: actions/checkout@v7 + - name: Install Windows Qt 6 if: runner.os == 'Windows' uses: jurplel/install-qt-action@v4 with: - version: '5.15.2' - arch: 'win64_msvc2019_64' - - - name: Configure plugin + version: '6.8.3' + arch: win64_msvc2022_64 + - uses: actions/setup-python@v6 + if: runner.os == 'Windows' + with: + python-version: '3.11' + - name: Download prepared SDK packages + uses: actions/download-artifact@v8 + with: + name: ConanSDK-${{ matrix.platform.label }} + path: sdk-cache + - name: Restore SDK packages and generate plugin toolchain shell: bash run: | - cmake -S . -B build \ - -Dplotjuggler_DIR="$PJ_INSTALL/lib/cmake/plotjuggler" \ - -DCMAKE_BUILD_TYPE=Release \ - -DADD_UNITS=${{ matrix.config.units }} \ - -DADD_RCOU_FUNCTION_LABELS=${{ matrix.config.rcou }} - - - name: Build plugin - shell: bash - run: cmake --build build --config Release --parallel "$(nproc || echo 2)" - - - name: Install plugin - shell: bash - run: cmake --install build --prefix plugin_install --config Release - - - name: Build smoke test + export CONAN_HOME="${RUNNER_TEMP//\\//}/conan-home" + # Keep Linux Python isolated from system packages, as in Docker. + if [ "$RUNNER_OS" = "Linux" ]; then + python3 -m venv "$RUNNER_TEMP/conan-env" + source "$RUNNER_TEMP/conan-env/bin/activate" + fi + python -m pip install "conan==${CONAN_VERSION}" + conan cache restore sdk-cache/conan-packages.tgz + # Use the producer's profile and revisions. Missing packages fail + # instead of silently downloading or rebuilding the SDK per variant. + conan install . -of build --build=never --no-remote \ + -pr:h sdk-cache/default.profile -pr:b sdk-cache/default.profile \ + -s build_type=Release -s compiler.cppstd=20 --lockfile=sdk-cache/conan.lock + - name: Configure and build shell: bash run: | - cmake -S tests -B tests/build \ - -DPJ_INCLUDE_DIR="$PJ_INSTALL/include" \ - -DCMAKE_BUILD_TYPE=Release - cmake --build tests/build --config Release --parallel "$(nproc || echo 2)" - - # Loads the plugin exactly as PlotJuggler does and parses a real log, so a - # plugin that builds but cannot be loaded fails here instead of in a user's - # hands. The --expect-* flags additionally assert that this job's CMake - # options actually reached the binary, which a build log cannot tell you. - # offscreen because CI has no display. - - name: Smoke test plugin + cmake -S . -B build -DCMAKE_TOOLCHAIN_FILE=build/conan_toolchain.cmake \ + -DCMAKE_BUILD_TYPE=Release -DADD_UNITS=${{ matrix.config.units }} \ + -DADD_RCOU_FUNCTION_LABELS=${{ matrix.config.rcou }} + cmake --build build --config Release --parallel 2 + - name: Test plugin and install + # Check both build and installed binaries so install-time library paths + # are exercised. Verify every label combination, including plain. shell: bash - env: - QT_QPA_PLATFORM: offscreen run: | - if [ -x tests/build/pj_plugin_smoketest ]; then - smoketest=tests/build/pj_plugin_smoketest - else - smoketest=tests/build/Release/pj_plugin_smoketest.exe + ctest --test-dir build -C Release --output-on-failure --no-tests=error + cmake --install build --prefix plugin_install --config Release + smoketest=build/tests/pj_plugin_smoketest + if [ "$RUNNER_OS" = "Windows" ]; then + smoketest=build/tests/Release/pj_plugin_smoketest.exe fi plugin="$(find plugin_install -type f \( -name '*.so' -o -name '*.dll' \) -print -quit)" - # --verify is unconditional so that the all-OFF 'plain' configuration is - # asserted too, not merely reported. - expect=(--verify) - if [ "${{ matrix.config.units }}" = "ON" ]; then - expect+=(--expect-units) + if [ -z "$plugin" ]; then + echo "No installed plugin library found" >&2 + exit 1 fi - if [ "${{ matrix.config.rcou }}" = "ON" ]; then - expect+=(--expect-rcou) - fi - echo "Testing $plugin ${expect[*]}" + expect=(--verify) + if [ "${{ matrix.config.units }}" = "ON" ]; then expect+=(--expect-units); fi + if [ "${{ matrix.config.rcou }}" = "ON" ]; then expect+=(--expect-rcou); fi "$smoketest" "$plugin" tests/logs/00000001.BIN "${expect[@]}" - - name: Upload plugin artifact uses: actions/upload-artifact@v7 with: @@ -222,9 +190,11 @@ jobs: - name: Download all plugin artifacts uses: actions/download-artifact@v8 with: + # SDK transfer artifacts contain dependencies, not release plugins. + pattern: DataAPBin-* path: artifacts - # Each artifact holds a single shared library under bin/. Flatten them + # Each artifact holds a single shared library under lib/. Flatten them # into uniquely named assets, keeping the real extension so a downloaded # asset is still recognisable as a plugin. - name: Collect release assets diff --git a/.gitignore b/.gitignore index 080b357..d1b3ecd 100644 --- a/.gitignore +++ b/.gitignore @@ -33,3 +33,5 @@ /CMakeLists.txt.user build/* tests/build/ +.venv/ +CMakeUserPresets.json diff --git a/CMakeLists.txt b/CMakeLists.txt index ed8bcd8..496c65a 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,134 +1,77 @@ -cmake_minimum_required(VERSION 3.7) -cmake_policy(SET CMP0068 NEW) -project(plotjuggler_apbin_plugins) - -set(CMAKE_CXX_STANDARD 17) +cmake_minimum_required(VERSION 3.22) +project(plotjuggler_apbin_plugins VERSION 0.2.0 LANGUAGES CXX) +set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) -#--- Basic Qt setup -set(CMAKE_AUTOMOC ON) -set(CMAKE_AUTOUIC ON) -set(CMAKE_INCLUDE_CURRENT_DIR ON) - -find_package(Qt5 REQUIRED COMPONENTS Core Concurrent Widgets Xml Svg) - -# Generate embedded log message descriptions header at build time -find_program(PYTHON3_EXECUTABLE python3 python) -if(NOT PYTHON3_EXECUTABLE) - message(STATUS "Python3 not found; logmessage header generation will create an empty header at build time") -else() - set(GEN_LOGMSG_HDR_OUT ${CMAKE_CURRENT_BINARY_DIR}/LogMessageDescriptions.h) - add_custom_command( - OUTPUT ${GEN_LOGMSG_HDR_OUT} - COMMAND ${PYTHON3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/DataLoadAPBin/scripts/generate_LogMessageDescriptions_header.py - ${CMAKE_CURRENT_SOURCE_DIR}/DataLoadAPBin/LogMessageDescriptions - ${GEN_LOGMSG_HDR_OUT} - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/DataLoadAPBin/scripts/generate_LogMessageDescriptions_header.py - COMMENT "Generating LogMessageDescriptions.h from available XML files" - VERBATIM - ) - add_custom_target(gen_logmsg_hdr DEPENDS ${GEN_LOGMSG_HDR_OUT}) -endif() +find_package(Qt6 REQUIRED COMPONENTS Core) +find_package(Python3 REQUIRED COMPONENTS Interpreter) +include(CTest) -#--- Find PlotJuggler and its dependencies, and set paths +# Preserve ROS workspace registration while consuming the standalone SDK. +# PlotJuggler itself is a runtime application, not a plugin build dependency. if(CATKIN_DEVEL_PREFIX OR catkin_FOUND OR CATKIN_BUILD_BINARY_PACKAGE) - # --- Build with CATKIN (ROS1) --- - message(STATUS "COMPILING_WITH_CATKIN") - find_package(catkin REQUIRED COMPONENTS plotjuggler) - include_directories(${catkin_INCLUDE_DIRS}) - set(PJ_LIBS ${catkin_LIBRARIES}) - + find_package(catkin REQUIRED) + catkin_package() + set(PJ_PLUGIN_INSTALL_DIRECTORY "${CATKIN_PACKAGE_BIN_DESTINATION}") elseif(DEFINED ENV{AMENT_PREFIX_PATH}) - # --- Build with AMENT (ROS2) --- - message(STATUS "COMPILING_WITH_AMENT") find_package(ament_cmake REQUIRED) - find_package(plotjuggler REQUIRED) - include_directories(${plotjuggler_INCLUDE_DIR}) - set(PJ_LIBS ${plotjuggler_LIBRARIES}) + set(COMPILING_WITH_AMENT TRUE) + set(PJ_PLUGIN_INSTALL_DIRECTORY "lib/${PROJECT_NAME}") else() - # --- Build without any ROS support (standalone) --- - message(STATUS "COMPILING STANDALONE") - find_package(plotjuggler REQUIRED) - # This is the critical line for moc to find the PJ::DataLoader interface - include_directories(${plotjuggler_INCLUDE_DIR}) - set(PJ_LIBS ${plotjuggler_LIBRARIES}) + set(PJ_PLUGIN_INSTALL_DIRECTORY lib) endif() - -#-------------- Switch units support ---------------- -OPTION(ADD_UNITS "Add units support" OFF) -IF(ADD_UNITS) - add_compile_definitions("LABEL_WITH_UNIT") - message(STATUS "Enabling field units define.") -ENDIF(ADD_UNITS) - - -#-------------- Switch RCOU/RCO2 function labels ---------------- -OPTION(ADD_RCOU_FUNCTION_LABELS "Add RCOU/RCO2 servo function labels" OFF) -IF(ADD_RCOU_FUNCTION_LABELS) - add_compile_definitions("LABEL_RCOU_FUNCTION") - message(STATUS "Enabling RCOU/RCO2 function labels define.") -ENDIF(ADD_RCOU_FUNCTION_LABELS) - - -#------- Create the library ------- -add_library(DataAPBin SHARED - DataLoadAPBin/dataload_apbin.h - DataLoadAPBin/dataload_apbin.cpp -) - -# Link against both plotjuggler libraries and the required Qt modules. -target_link_libraries(DataAPBin PRIVATE - ${PJ_LIBS} - Qt5::Core - Qt5::Concurrent - Qt5::Widgets - Qt5::Xml - Qt5::Svg -) - -# Ensure generated header is available and included -if(TARGET gen_logmsg_hdr) - add_dependencies(DataAPBin gen_logmsg_hdr) - target_include_directories(DataAPBin PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) +# Consume the same SDK as PlotJuggler 4.1 (conanfile.txt), or build a local +# SDK checkout. No link to the PlotJuggler application or datastore is needed. +set(PJ_SDK_SOURCE_DIR "" CACHE PATH "Optional plotjuggler_sdk 0.40.0 source checkout") +if(PJ_SDK_SOURCE_DIR) + set(PJ_BUILD_TESTS OFF CACHE BOOL "" FORCE) + set(PJ_BUILD_PORTED_PLUGINS OFF CACHE BOOL "" FORCE) + add_subdirectory("${PJ_SDK_SOURCE_DIR}" "${CMAKE_BINARY_DIR}/sdk") else() - # still add build dir to include path so an empty autogenerated header may be placed there by other tooling - target_include_directories(DataAPBin PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) + if(BUILD_TESTING) + find_package(plotjuggler_sdk 0.40.0 REQUIRED COMPONENTS plugin_sdk plugin_host) + else() + find_package(plotjuggler_sdk 0.40.0 REQUIRED COMPONENTS plugin_sdk) + endif() endif() -if (COMPILING_WITH_AMENT) - ament_target_dependencies(DataAPBin plotjuggler) +option(ADD_UNITS "Append units to field names" OFF) +option(ADD_RCOU_FUNCTION_LABELS "Append servo functions to RCOU/RCO2 field names" OFF) + +file(GLOB LOGMSG_XML CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/DataLoadAPBin/LogMessageDescriptions/*.xml") +set(GEN_LOGMSG_HDR_OUT "${CMAKE_CURRENT_BINARY_DIR}/LogMessageDescriptions.h") +add_custom_command(OUTPUT "${GEN_LOGMSG_HDR_OUT}" + COMMAND "${Python3_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/DataLoadAPBin/scripts/generate_LogMessageDescriptions_header.py" + "${CMAKE_CURRENT_SOURCE_DIR}/DataLoadAPBin/LogMessageDescriptions" "${GEN_LOGMSG_HDR_OUT}" + DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/DataLoadAPBin/scripts/generate_LogMessageDescriptions_header.py" ${LOGMSG_XML} + COMMENT "Embedding ArduPilot log message descriptions" + VERBATIM) + +add_library(DataAPBin SHARED DataLoadAPBin/dataload_apbin.cpp DataLoadAPBin/dataload_apbin.h "${GEN_LOGMSG_HDR_OUT}") +target_include_directories(DataAPBin PRIVATE "${CMAKE_CURRENT_BINARY_DIR}") +target_link_libraries(DataAPBin PRIVATE plotjuggler_sdk::plugin_sdk Qt6::Core) +target_compile_options(DataAPBin PRIVATE $<$:/utf-8>) +target_compile_definitions(DataAPBin PRIVATE + $<$:LABEL_WITH_UNIT> + $<$:LABEL_RCOU_FUNCTION>) +# The SDK installs the manifest using CMAKE_INSTALL_LIBDIR. Keep it beside the +# plugin in standalone, catkin and ament install trees. +set(CMAKE_INSTALL_LIBDIR "${PJ_PLUGIN_INSTALL_DIRECTORY}") +pj_configure_plugin(DataAPBin + FAMILIES data_source + MANIFEST_FILE "${CMAKE_CURRENT_SOURCE_DIR}/DataLoadAPBin/manifest.json" + MANIFEST_HEADER generated/apbin_manifest.hpp + MANIFEST_VAR kAPBinManifest) +install(TARGETS DataAPBin + RUNTIME DESTINATION "${PJ_PLUGIN_INSTALL_DIRECTORY}" + LIBRARY DESTINATION "${PJ_PLUGIN_INSTALL_DIRECTORY}") + +if(BUILD_TESTING) + add_subdirectory(tests) endif() -# We need to tell Qt this is a plugin. -target_compile_definitions(DataAPBin PRIVATE QT_PLUGIN) - - -#------- Installation and RPATH for macOS ------- -set(CMAKE_MACOSX_RPATH ON) -set(CMAKE_SKIP_BUILD_RPATH FALSE) -set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) -set(CMAKE_INSTALL_RPATH "@executable_path/../Frameworks") -set(CMAKE_INSTALL_RPATH_USE_LINK_PATH FALSE) - -set_target_properties(DataAPBin PROPERTIES - INSTALL_NAME_DIR "@rpath" -) - -if(CATKIN_DEVEL_PREFIX OR catkin_FOUND OR CATKIN_BUILD_BINARY_PACKAGE) - set(PJ_PLUGIN_INSTALL_DIRECTORY ${CATKIN_PACKAGE_BIN_DESTINATION}) -elseif(DEFINED ENV{AMENT_PREFIX_PATH}) - set(PJ_PLUGIN_INSTALL_DIRECTORY lib/${PROJECT_NAME}) -else() - set(PJ_PLUGIN_INSTALL_DIRECTORY bin) -endif() - -install( - TARGETS - DataAPBin - DESTINATION - ${PJ_PLUGIN_INSTALL_DIRECTORY} ) - -if (COMPILING_WITH_AMENT) +if(COMPILING_WITH_AMENT) ament_package() endif() diff --git a/DataLoadAPBin/dataload_apbin.cpp b/DataLoadAPBin/dataload_apbin.cpp index dff8cba..ab85379 100644 --- a/DataLoadAPBin/dataload_apbin.cpp +++ b/DataLoadAPBin/dataload_apbin.cpp @@ -19,6 +19,14 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include "apbin_manifest.hpp" #include "LogMessageDescriptions.h" #include #include @@ -56,19 +64,36 @@ bool is_nearly(double val, int val2) } } -DataLoadAPBIN::DataLoadAPBIN() +namespace { +PJ::Timestamp timestamp_ns(double seconds) { - extensions.push_back("BIN"); // TODO : this doesn't work for now as tolower() is hardcoded. - qRegisterMetaType>(); - qRegisterMetaType>(); + const long double ns = static_cast(seconds) * 1e9L; + if (!std::isfinite(ns) || ns <= static_cast(std::numeric_limits::min()) || + ns >= static_cast(std::numeric_limits::max())) + throw std::runtime_error("ArduPilot timestamp is outside the nanosecond range"); + return static_cast(std::round(ns)); +} } -const std::vector& DataLoadAPBIN::compatibleFileExtensions() const +std::string DataLoadAPBIN::saveConfig() const { - return extensions; + return QJsonDocument(QJsonObject{{"filepath", _filepath}}).toJson(QJsonDocument::Compact).toStdString(); } -bool DataLoadAPBIN::readDataFromFile(FileLoadInfo* info, PlotDataMapRef& plot_data) +PJ::Status DataLoadAPBIN::loadConfig(std::string_view config_json) +{ + QJsonParseError error; + const auto doc = QJsonDocument::fromJson(QByteArray(config_json.data(), static_cast(config_json.size())), &error); + if (error.error != QJsonParseError::NoError || !doc.isObject()) + return PJ::unexpected("ArduPilot Bin configuration must be a JSON object"); + const auto filepath = doc.object().value("filepath"); + if (!filepath.isString() || filepath.toString().isEmpty()) + return PJ::unexpected("ArduPilot Bin requires a non-empty filepath"); + _filepath = filepath.toString(); + return PJ::okStatus(); +} + +PJ::Status DataLoadAPBIN::importData() try { // Reset all per-load state. Without this, member variables persist across // file loads in the same PlotJuggler session: stale has_instance / instance_offset @@ -89,17 +114,30 @@ bool DataLoadAPBIN::readDataFromFile(FileLoadInfo* info, PlotDataMapRef& plot_da multipliers.clear(); units.clear(); - QFile file(info->filename); + _parameters.clear(); + _status_texts.clear(); + for (auto& label : _servo_function_labels) label.clear(); + _message_tooltips.clear(); + _field_tooltips.clear(); + _start_plot_time = 0.0; + _time_offset = 0.0; + + QFile file(_filepath); if (!file.open(QFile::ReadOnly)) { - return false; + return PJ::unexpected("Cannot open ArduPilot log: " + file.errorString().toStdString()); } const QByteArray file_array = file.readAll(); - const int32_t file_size = file_array.size(); + if (file.error() != QFile::NoError) + return PJ::unexpected("Cannot read ArduPilot log: " + file.errorString().toStdString()); + if (file_array.size() > std::numeric_limits::max()) + return PJ::unexpected("ArduPilot logs larger than 4 GiB are not supported"); + if (file_array.isEmpty()) + return PJ::unexpected("ArduPilot log is empty"); const uint8_t* buf = reinterpret_cast(file_array.data()); - const uint32_t len = file_array.size(); + const uint32_t len = static_cast(file_array.size()); uint32_t total_bytes_used = 0; uint32_t bytes_skipped{ 0 }; @@ -121,8 +159,17 @@ bool DataLoadAPBIN::readDataFromFile(FileLoadInfo* info, PlotDataMapRef& plot_da std::chrono::duration publish_ms{ 0 }; #endif + auto progress = runtimeHost().progressStart("Loading ArduPilot Bin", static_cast(len) + 1, true); + if (!progress) return progress; + uint32_t next_progress = 0; while (true) { + if (runtimeHost().isStopRequested()) return PJ::unexpected("ArduPilot import cancelled"); + if (total_bytes_used >= next_progress) + { + if (!runtimeHost().progressUpdate(total_bytes_used)) return PJ::unexpected("ArduPilot import cancelled"); + next_progress = total_bytes_used > len - std::min(len, 65536u) ? len : total_bytes_used + 65536u; + } // check if end of file is reached if (len - total_bytes_used < LOG_PACKET_HEADER_LEN) { @@ -415,10 +462,10 @@ bool DataLoadAPBIN::readDataFromFile(FileLoadInfo* info, PlotDataMapRef& plot_da #ifdef LABEL_RCOU_FUNCTION // save servo functions - QRegExp rx("SERVO(\\d+)_FUNCTION"); - if (rx.indexIn(QString::fromStdString(name)) != -1) { + const auto match = QRegularExpression("^SERVO(\\d+)_FUNCTION$").match(QString::fromStdString(name)); + if (match.hasMatch()) { bool is_int = false; - int servo_idx = rx.cap(1).toInt(&is_int); + int servo_idx = match.captured(1).toInt(&is_int); if (is_int && servo_idx > 0 && servo_idx <= 32) { const int function_id = static_cast(param->value); @@ -504,6 +551,14 @@ bool DataLoadAPBIN::readDataFromFile(FileLoadInfo* info, PlotDataMapRef& plot_da auto apply_mult_start = std::chrono::high_resolution_clock::now(); #endif apply_multipliers(); + // TimeUS has a fixed meaning even in older logs without FMTU/MULT. + for (auto& [message, instances] : messages_map) + { + const auto time = field_name2idx.at(message).find("TimeUS"); + if (time == field_name2idx.at(message).end()) continue; + for (auto& [instance, data] : instances) + for (auto& value : data.at(time->second).second) value *= 1e-6; + } #ifdef DEBUG_RUNTIME auto apply_mult_end = std::chrono::high_resolution_clock::now(); apply_mult_ms += (apply_mult_end - apply_mult_start); @@ -568,126 +623,79 @@ bool DataLoadAPBIN::readDataFromFile(FileLoadInfo* info, PlotDataMapRef& plot_da std::printf("-------------- END --------------\n\n"); #endif - // -------------------- publish to plotjuggler -------------------- // -#ifdef QT_CORE_LIB - load_log_messages(info->filename); -#else - load_log_messages(info->filename); -#endif + // PlotJuggler 4 stores records by topic and field, with nanosecond timestamps. + load_log_messages(_filepath); #ifdef DEBUG_RUNTIME auto publish_start = std::chrono::high_resolution_clock::now(); #endif - // iterate through messages - for (const auto& msg_it : messages_map) + QJsonObject descriptions; + uint64_t records_written = 0; + for (const auto& [msg_name, instances] : messages_map) { - const std::string& msg_name = msg_it.first; - - // get message id for message name - const uint8_t& msg_id = msg_name2id[msg_name]; - - // only publish messages to plotjuggler, which have the "TimeUS" field! - auto time_idx_it = field_name2idx[msg_name].find("TimeUS"); - if (time_idx_it == field_name2idx[msg_name].end()) - { - std::printf("Ignoring message '%s' because it has no 'TimeUS' field!\n", msg_name.c_str()); - continue; - } - - // iterate through instances - const auto& instances_map = msg_it.second; - for (const auto& inst_it : instances_map) + const uint8_t msg_id = msg_name2id.at(msg_name); + const auto& indices = field_name2idx.at(msg_name); + const auto time_it = indices.find("TimeUS"); + if (time_it == indices.end()) continue; + for (const auto& [instance, msg_data] : instances) { - const message_data& msg_data = inst_it.second; - - // iterate through fields - - // extract timestamps from message data - const uint8_t& time_idx = field_name2idx[msg_name]["TimeUS"]; - const std::vector& timestamps = msg_data[time_idx].second; - - size_t idx = 0; - bool message_desc_assigned = false; - std::string message_desc; - auto mit = _message_tooltips.find(msg_name); - if (mit != _message_tooltips.end()) message_desc = mit->second; - for (const auto& field : msg_data) + const auto time_idx = time_it->second; + const auto& timestamps = msg_data.at(time_idx).second; + std::string topic_name = "/" + msg_name; + if (has_instance[msg_id]) topic_name += "/#" + std::to_string(instance); + auto topic = writeHost().ensureTopic(topic_name); + if (!topic) return PJ::unexpected(topic.error()); + std::vector columns; + std::vector record; + for (size_t idx = 0; idx < msg_data.size(); ++idx) { - if ( idx == time_idx || ( has_instance[msg_id] && (idx == instance_idx[msg_id]) ) ) - { - idx++; - continue; - } - - const std::string instance_name = "#" + std::to_string(inst_it.first); - const std::string& field_name = field.first; - - std::string series_name; - - if ( !has_instance[msg_id] ) - { - series_name = "/" + msg_name + "/" + field_name; - } - else - { - series_name = "/" + msg_name + "/" + instance_name + "/" + field_name; - } - + if (idx == time_idx || (has_instance[msg_id] && static_cast(idx) == instance_idx[msg_id])) continue; + const auto& field = msg_data[idx]; + if (field.second.size() != timestamps.size()) + return PJ::unexpected("Inconsistent ArduPilot field lengths in " + topic_name); + std::string field_name = field.first; #ifdef LABEL_RCOU_FUNCTION - // label servo functions - if (msg_name == "RCOU" || msg_name == "RCO2") { - QRegExp re(R"(C(\d+))"); - if(re.indexIn(QString::fromStdString(field_name)) != -1) { - int label_idx = re.cap(1).toInt() - 1; // is 1-based - - if(label_idx >= 0 && label_idx < 32 && !_servo_function_labels[label_idx].empty()) { - series_name = series_name + " (" + _servo_function_labels[label_idx] + ")"; - } + if (msg_name == "RCOU" || msg_name == "RCO2") + { + const auto match = QRegularExpression("^C(\\d+)$").match(QString::fromStdString(field.first)); + if (match.hasMatch()) + { + const int servo = match.captured(1).toInt() - 1; + if (servo >= 0 && servo < 32 && !_servo_function_labels[servo].empty()) + field_name += " (" + _servo_function_labels[servo] + ")"; } } #endif - - #ifdef LABEL_WITH_UNIT - std::string unit_str = get_unit(msg_name, field_name); - if ( !unit_str.empty() ) - { - series_name = series_name + "\t[" + unit_str + "]"; - } + const auto unit = get_unit(msg_name, field.first); + if (!unit.empty()) field_name += "\t[" + unit + "]"; #endif - - auto series = plot_data.addNumeric(series_name); - - // Prefer per-field descriptions. Only attach message description to the - // first series for this message instance that does not have a field description. - std::string field_desc; - auto fit_map_it = _field_tooltips.find(msg_name); - if (fit_map_it != _field_tooltips.end()) - { - auto fit = fit_map_it->second.find(field_name); - if (fit != fit_map_it->second.end()) - { - field_desc = fit->second; - } - } - - if (!field_desc.empty()) + auto handle = writeHost().ensureField(*topic, field_name, PJ::PrimitiveType::kFloat64); + if (!handle) return PJ::unexpected(handle.error()); + columns.push_back(idx); + record.push_back({*handle, 0.0}); + std::string description; + const auto message = _field_tooltips.find(msg_name); + if (message != _field_tooltips.end()) { - series->second.setAttribute(PJ::TOOL_TIP, QString::fromStdString(field_desc)); + const auto field_desc = message->second.find(field.first); + if (field_desc != message->second.end()) description = field_desc->second; } - else if (!message_desc_assigned && !message_desc.empty()) + if (description.empty()) { - // attach message description once for this instance - series->second.setAttribute(PJ::TOOL_TIP, QString::fromStdString(message_desc)); - message_desc_assigned = true; + const auto message_desc = _message_tooltips.find(msg_name); + if (message_desc != _message_tooltips.end()) description = message_desc->second; } - - for (size_t i = 0; i < field.second.size(); i++) - { - const double& msg_time = timestamps[i]; - PlotData::Point point(msg_time, field.second[i]); - series->second.pushBack(point); - } - idx++; + if (!description.empty()) descriptions.insert(QString::fromStdString(topic_name + "/" + field_name), QString::fromStdString(description)); + } + if (record.empty()) continue; + for (size_t row = 0; row < timestamps.size(); ++row) + { + if ((row % 1024) == 0 && runtimeHost().isStopRequested()) return PJ::unexpected("ArduPilot import cancelled"); + for (size_t column = 0; column < columns.size(); ++column) + record[column].value = msg_data[columns[column]].second[row]; + auto status = writeHost().appendBoundRecord(*topic, timestamp_ns(timestamps[row]), record); + if (!status) return status; + ++records_written; } } } @@ -732,48 +740,80 @@ bool DataLoadAPBIN::readDataFromFile(FileLoadInfo* info, PlotDataMapRef& plot_da } #endif - // Now, add the parameters as time series. + // Group snapshot fields into rows: one sparse row per parameter would + // otherwise allocate a quadratic number of null cells in the column store. + std::map> parameters; + size_t parameter_rows = 0; for (const auto& param : _parameters) { - auto series = plot_data.addNumeric(std::string("/1. Parameters/") + param.name); - series->second.pushBack({300, param.value}); + auto& values = parameters[param.name]; + values.push_back(param.value); + parameter_rows = std::max(parameter_rows, values.size()); } - - + if (!parameters.empty()) + { + auto topic = writeHost().ensureTopic("/1. Parameters"); + if (!topic) return PJ::unexpected(topic.error()); + for (size_t row = 0; row < parameter_rows; ++row) + { + std::vector record; + // Carry the last value forward so the latest row contains every parameter. + // Omitted fields become null in the datastore and hide earlier values. + for (const auto& [name, values] : parameters) + record.push_back({name, values[std::min(row, values.size() - 1)]}); + auto status = writeHost().appendRecord(*topic, timestamp_ns(300.0), record); + if (!status) return status; + ++records_written; + } + } + std::vector message_log; + message_log.reserve(_status_texts.size()); #ifdef DEBUG_MESSAGES std::printf("Message Log\n---------------"); #endif - - for(int i = 0; i < _status_texts.size(); i++) + for (size_t i = 0; i < _status_texts.size(); ++i) { #ifdef DEBUG_MESSAGES - std::printf("\n %llu: %s", _status_texts[i].timestamp, _status_texts[i].msg.c_str()); + std::printf("\n %llu: %s", static_cast(_status_texts[i].timestamp), _status_texts[i].msg.c_str()); #endif - // change "/" to "\" if a status_text contains one so it doesn't create a child entry std::string msg = _status_texts[i].msg; - size_t start_pos = 0; - while((start_pos = msg.find('/', start_pos)) != std::string::npos) { - msg.replace(start_pos, 1, "\\"); - start_pos += 2; // Handles cases where the replacement also contains the search string - } - - auto time_s = static_cast(_status_texts[i].timestamp)/1e6; - - auto& timeline = plot_data.getOrCreateNumeric("/2. Message Timeline"); - timeline.pushBack({time_s + _time_offset, (double)(i + 1)}); - - auto series = plot_data.addNumeric(std::string("/3. Message Log/") + std::to_string(i + 1) + ". " + msg); - series->second.pushBack({0.0, time_s - _start_plot_time}); + std::replace(msg.begin(), msg.end(), '/', '\\'); + const double time_s = static_cast(_status_texts[i].timestamp) / 1e6; + auto timeline = writeHost().ensureTopic("/2. Message Timeline"); + if (!timeline) return PJ::unexpected(timeline.error()); + auto status = writeHost().appendRecord(*timeline, timestamp_ns(time_s + _time_offset), {{"index", static_cast(i + 1)}}); + if (!status) return status; + ++records_written; + message_log.push_back({std::to_string(i + 1) + ". " + msg, time_s - _start_plot_time}); } - #ifdef DEBUG_MESSAGES std::printf("\n---------------\n"); #endif - - return true; + if (!message_log.empty()) + { + auto log = writeHost().ensureTopic("/3. Message Log"); + if (!log) return PJ::unexpected(log.error()); + auto status = writeHost().appendRecord(*log, timestamp_ns(0.0), message_log); + if (!status) return status; + ++records_written; + } + if (records_written == 0) return PJ::unexpected("No supported ArduPilot data found in log"); + // The current scalar write API has no per-field tooltip setter. Keep the + // descriptions in the dataset metadata, available in the host's inspector. + const auto metadata = QJsonDocument(QJsonObject{{"format", "ArduPilot DataFlash"}, {"field_descriptions", descriptions}}).toJson(QJsonDocument::Compact); + if (auto status = runtimeHost().setDatasetMetadata(metadata.toStdString()); !status) + runtimeHost().reportMessage(PJ::DataSourceMessageLevel::kWarning, status.error()); + if (!runtimeHost().progressUpdate(static_cast(len) + 1)) return PJ::unexpected("ArduPilot import cancelled"); + return PJ::okStatus(); +} +catch (const std::exception& error) +{ + return PJ::unexpected(std::string("ArduPilot import failed: ") + error.what()); } +PJ_DATA_SOURCE_PLUGIN(DataLoadAPBIN, kAPBinManifest) + std::string DataLoadAPBIN::format_default_value(float val) { std::ostringstream ss; ss << std::fixed << std::setprecision(2) << val; @@ -949,8 +989,8 @@ void DataLoadAPBIN::handle_message_received(const struct log_Format& fmt, const DataLoadAPBIN::message_data DataLoadAPBIN::create_message_data(const struct log_Format& fmt) { - QString labelStr(fmt.labels); - labelStr.truncate(MAX_LABELS_SIZE); + const auto end = std::find(std::begin(fmt.labels), std::end(fmt.labels), '\0'); + QString labelStr = QString::fromLatin1(fmt.labels, end - std::begin(fmt.labels)); QStringList labels_list; if (labelStr.size() > 0) { @@ -973,7 +1013,7 @@ uint32_t DataLoadAPBIN::get_field_byte_offset(const uint8_t& msg_id, const uint8 { // raise error, because fmt does not exist! std::fprintf(stderr, "ERROR: FMT for message %u does not exist!\n", msg_id); - exit(EXIT_FAILURE); + throw std::runtime_error("Missing ArduPilot message format"); } // get information from FMT @@ -994,7 +1034,7 @@ uint32_t DataLoadAPBIN::get_field_byte_offset(const uint8_t& msg_id, const uint8 { // raise error, because format type definition is missing std::fprintf(stderr, "ERROR: format type '%c' is not defined!\n", format[idx]); - exit(EXIT_FAILURE); + throw std::runtime_error("Missing ArduPilot message format"); } data_offset += format_types_it->second; } @@ -1156,6 +1196,7 @@ void DataLoadAPBIN::apply_multipliers(void) // iterate through fields for (int idx = 0; idx < msg_data.size(); idx++) { + if (msg_data[idx].first == "TimeUS") continue; // get multiplier descriptor char const char& field_multiplier_char = format_units[msg_id].multipliers[idx]; diff --git a/DataLoadAPBin/dataload_apbin.h b/DataLoadAPBin/dataload_apbin.h index 326e0d3..09e29ac 100644 --- a/DataLoadAPBin/dataload_apbin.h +++ b/DataLoadAPBin/dataload_apbin.h @@ -13,9 +13,8 @@ #pragma once -#include -#include -#include "PlotJuggler/dataloader_base.h" +#include +#include #include "logformat.h" #include #include @@ -24,29 +23,17 @@ using namespace PJ; -class DataLoadAPBIN : public DataLoader +class DataLoadAPBIN : public PJ::FileSourceBase { - Q_OBJECT - Q_PLUGIN_METADATA(IID "facontidavide.PlotJuggler3.DataLoader") - Q_INTERFACES(PJ::DataLoader) - public: - DataLoadAPBIN(); - virtual const std::vector& compatibleFileExtensions() const override; - - bool readDataFromFile(PJ::FileLoadInfo* fileload_info, PlotDataMapRef& destination) override; - + uint64_t extraCapabilities() const override { return PJ::kCapabilityDirectIngest; } + std::string saveConfig() const override; + PJ::Status loadConfig(std::string_view config_json) override; + PJ::Status importData() override; ~DataLoadAPBIN() override = default; - virtual const char* name() const override - { - return "ArduPilot Bin"; - } - -protected: - private: - std::vector extensions; + QString _filepath; // message_data holds the data of a message for each timestamp diff --git a/DataLoadAPBin/manifest.json b/DataLoadAPBin/manifest.json new file mode 100644 index 0000000..af90385 --- /dev/null +++ b/DataLoadAPBin/manifest.json @@ -0,0 +1,9 @@ +{ + "id": "ardupilot-bin", + "name": "ArduPilot Bin", + "version": "0.2.0", + "description": "Load ArduPilot DataFlash binary logs", + "min_plotjuggler_version": "4.1.0", + "min_sdk_required": "0.40.0", + "file_extensions": [".bin"] +} diff --git a/Dockerfile b/Dockerfile index 6208406..2fe7fba 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,44 +1,26 @@ -FROM ubuntu:22.04 AS build-stage - -ARG PJ_TAG=3.9.2 - -############################################################################### -# Install dependencies. -############################################################################### -# General dependencies. -RUN apt update && apt install -y build-essential cmake git -# PlotJuggler dependencies. -RUN apt update && apt -y install qtbase5-dev libqt5svg5-dev libqt5websockets5-dev \ - libqt5opengl5-dev libqt5x11extras5-dev libprotoc-dev libzmq3-dev \ - liblz4-dev libzstd-dev - -############################################################################### -# Compile PlotJuggler -############################################################################### -WORKDIR /plotjuggler_ws/src -RUN git clone --depth 1 --branch ${PJ_TAG} https://github.com/facontidavide/PlotJuggler.git PlotJuggler -# Build PlotJuggler. This will take a long time. -WORKDIR /plotjuggler_ws -RUN cmake -S src/PlotJuggler -B build/PlotJuggler -DCMAKE_INSTALL_PREFIX=install \ - && cmake --build build/PlotJuggler --config RelWithDebInfo --target install -j"$(nproc)" - -############################################################################### -# Compile the plugin -############################################################################### +ARG BASE_IMAGE=ubuntu:22.04 +FROM ${BASE_IMAGE} AS build-stage +# Build tools and Qt Core. Conan lives in a virtual environment so this also +# works on distributions whose system Python is externally managed. +RUN apt-get update && apt-get install -y --no-install-recommends \ + build-essential cmake git ca-certificates python3 python3-venv qt6-base-dev \ + && python3 -m venv /opt/conan \ + && /opt/conan/bin/python -m pip install 'conan>=2,<3' +ENV PATH="/opt/conan/bin:${PATH}" +WORKDIR /apbin_plugin +COPY . . ARG ADD_UNITS=OFF ARG ADD_RCOU_FUNCTION_LABELS=OFF - -COPY --link . /apbin_plugin - -WORKDIR /apbin_plugin/build -# Ensure a fresh build folder -RUN rm -Rf * \ - && cmake -Dplotjuggler_DIR="/plotjuggler_ws/install/lib/cmake/plotjuggler" -DADD_UNITS=${ADD_UNITS} -DADD_RCOU_FUNCTION_LABELS=${ADD_RCOU_FUNCTION_LABELS} .. \ - && make -j"$(nproc)" \ - && make install \ +# Compile and test the plugin against the SDK, then collect the export artifacts. +RUN conan profile detect \ + && conan remote add plotjuggler https://plotjuggler.jfrog.io/artifactory/api/conan/plotjuggler-conan \ + && conan install . -of build --build=missing -s build_type=Release -s compiler.cppstd=20 \ + && cmake -S . -B build -DCMAKE_TOOLCHAIN_FILE=build/conan_toolchain.cmake \ + -DCMAKE_BUILD_TYPE=Release -DADD_UNITS=${ADD_UNITS} -DADD_RCOU_FUNCTION_LABELS=${ADD_RCOU_FUNCTION_LABELS} \ + && cmake --build build --parallel \ + && ctest --test-dir build --output-on-failure \ && mkdir /artifacts \ - && cp libDataAPBin.so /artifacts - + && cp build/libDataAPBin.so build/DataAPBin.pjmanifest.json /artifacts/ FROM scratch AS export-stage # Move the plugin to a fresh filesystem that can be exported easily. -COPY --from=build-stage /artifacts / \ No newline at end of file +COPY --from=build-stage /artifacts/ / diff --git a/README.md b/README.md index ff75458..f4ab170 100644 --- a/README.md +++ b/README.md @@ -1,143 +1,212 @@ # plotjuggler-apbin-plugins -This repository contains the [ArduPilot Dataflash](https://ardupilot.org/copter/docs/common-logs.html) plugin for [PlotJuggler](https://github.com/facontidavide/PlotJuggler). +ArduPilot [DataFlash binary log](https://ardupilot.org/copter/docs/common-logs.html) +loader for [PlotJuggler 4](https://github.com/PlotJuggler/PlotJuggler). +Plugin version **0.2.0** targets PlotJuggler **4.1.0** and its **plotjuggler_sdk 0.40.0**. +It uses the SDK's C ABI data-source interface, C++20, and Qt 6 Core. +PlotJuggler 3 / Qt 5 binaries are incompatible with this version. -## Install PlotJuggler +## Get the plugin and PlotJuggler -To build any plugin for PlotJuggler, PlotJuggler must be installed on your system. -For detailed instructions on how to install PlotJuggler please have a look at the [Installation](https://github.com/facontidavide/PlotJuggler#installation) section of the PlotJuggler repository. +Clone this repository to build the plugin: -If you have ROS installed, you can install PlotJuggler using: +```sh +git clone https://github.com/ArduPilot/plotjuggler-apbin-plugins +cd plotjuggler-apbin-plugins +``` - sudo apt install ros-$ROS_DISTRO-plotjuggler-ros +Prebuilt Ubuntu and Windows plugins are available on the +[GitHub Releases](https://github.com/ArduPilot/plotjuggler-apbin-plugins/releases) +page. Choose a release built for PlotJuggler 4; older PlotJuggler 3 plugins +cannot be used with the current application. + +To run the plugin, install a compatible PlotJuggler application using its +[installation instructions](https://github.com/PlotJuggler/PlotJuggler#installation). +The application is not required to compile the plugin. + +## Build + +Install a C++20 compiler, CMake 3.22+, Python 3, Conan 2, and Qt 6 development +files. Use a Qt 6 kit compatible with the application: the target PlotJuggler checkout +pins Qt 6.12.0. On Windows use the same architecture and MSVC runtime as the app. +The SDK is Qt independent; the plugin only uses Qt Core and creates no widgets. +You do not need to build or install the PlotJuggler application to build this plugin. + +On Ubuntu, install `build-essential cmake qt6-base-dev python3 python3-venv`. +Then, from this repository: + +```sh +python3 -m venv .venv +source .venv/bin/activate +python3 -m pip install 'conan>=2,<3' +conan profile detect # once, if no default profile exists +conan remote add plotjuggler https://plotjuggler.jfrog.io/artifactory/api/conan/plotjuggler-conan +conan install . -of build --build=missing -s build_type=Release -s compiler.cppstd=20 +cmake -S . -B build -DCMAKE_TOOLCHAIN_FILE=build/conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Release +cmake --build build --config Release --parallel +ctest --test-dir build -C Release --output-on-failure +cmake --install build --config Release --prefix plugin_install +``` -## (Optional) Build plotjuggler-apbin-plugin +Pass `-DCMAKE_PREFIX_PATH=` if Qt is not found. On Windows run in a +Visual Studio developer shell, create the environment with `python -m venv .venv`, +and activate it with `.venv\Scripts\Activate.ps1` in PowerShell or +`.venv\Scripts\activate.bat` in cmd. Continue from the pip installation step, +using `python` instead of `python3`. The virtual environment also works on Ubuntu +24.04 and other distributions that prevent pip from changing system Python. +An existing installed SDK can also be used directly with +`-Dplotjuggler_sdk_DIR=/lib/cmake/plotjuggler_sdk`, without Conan. + +### Build against SDK sources + +`-DPJ_SDK_SOURCE_DIR=` builds the SDK in-tree. +Its CMake dependencies (`fmt`, `FastFloat`, `nlohmann_json`) must be installed +or supplied through `CMAKE_PREFIX_PATH`. The SDK's own tests and ported plugins +are disabled; this plugin's tests remain enabled. This is useful when validating +against the SDK release pinned in PlotJuggler's `conanfile.txt`. + +### Build in a ROS workspace + +ROS 1 catkin and ROS 2 ament integration are retained. Source your ROS environment +and place the plugin repository under the workspace's `src/` directory. Install +Qt 6 and SDK 0.40.0 first; the plugin no longer links against the PlotJuggler +application. For an installed SDK, build from the workspace root. + +Use the system Python that provides your ROS modules. The commands below use +`/usr/bin/python3` on Ubuntu and explicitly select it for CMake, including when +Conan's virtual environment is still active. +Build with: + +```sh +# ROS 1, using catkin_tools +catkin build plotjuggler_apbin_plugins --cmake-args \ + -Dplotjuggler_sdk_DIR=/absolute/path/to/sdk/lib/cmake/plotjuggler_sdk \ + -DPYTHON_EXECUTABLE=/usr/bin/python3 -DPython3_EXECUTABLE=/usr/bin/python3 + +# ROS 2 +colcon build --packages-select plotjuggler_apbin_plugins --cmake-args \ + -Dplotjuggler_sdk_DIR=/absolute/path/to/sdk/lib/cmake/plotjuggler_sdk \ + -DPython3_EXECUTABLE=/usr/bin/python3 +``` -If you wish to build `plotjuggler-apbin-plugin` follow these steps. +Alternatively, run the Conan setup above through `conan install` in the plugin +repository, then pass the absolute path to `build/conan_toolchain.cmake` with +`-DCMAKE_TOOLCHAIN_FILE=...` +in the workspace command's `--cmake-args`, replacing `-Dplotjuggler_sdk_DIR=...` +and retaining the Python options above. This keeps ROS's `catkin_pkg` and +`ament_package` modules visible; Conan's isolated Python does not include them. +You can also run `deactivate` before the workspace build. If a package was +already configured with the virtual environment's Python, retain the explicit +Python options to replace the cached interpreter paths. -### 1. Clone the repository +Add `-DCMAKE_PREFIX_PATH=` if needed. The runtime dependency requires +PlotJuggler 4.1.0 or newer; a ROS +distribution's PlotJuggler 3 package is incompatible. -``` -git clone https://github.com/ArduPilot/plotjuggler-apbin-plugins -``` +Both ROS install trees place the plugin and its manifest under +`lib/plotjuggler_apbin_plugins`. Add that directory to PlotJuggler's plugin folders +as described below. The catkin devel tree places the shared library under `lib`. -### 2a. Compile via Docker - -This requires that you have Docker installed in your system. - -1. `cd` into the cloned repository. - -2. Prepare a new folder with - ```bash - mkdir artifacts - ``` - -3. Build the plugin with - ```bash - docker build -o type=local,dest=artifacts . - ``` - This command will clone and build PlotJuggler anew, which takes a lot of time. - - You can pass build arguments with the `--build-arg` option. - Build arguments include: - - `ADD_UNITS[=OFF]`: Set to `ON` to enable the display of units in the logged fields. Read at the end for more information. - - `ADD_RCOU_FUNCTION_LABELS[=OFF]`: Set to `ON` to enable the display the channel function next to its name. -[=OFF]`: Set to `ON` to enable the display of units in the logged fields. Read at the end for more information. - - `BASE_IMAGE[=ubuntu:22.04]`: Specify the OS image to build off of. It is known that using a different OS than your host OS may result in the plugin not working. - - `PJ_TAG[=3.9.2]`: The PlotJuggler git branch or tag to use when cloing and compiling PlotJuggler. - -Once compilation is finished, you will find your `.so` plugin in the `artifacts` folder you created previously. - -### 2b. Compile locally - -1. Clone and compile PlotJuggler [following the instructions](https://github.com/facontidavide/PlotJuggler/blob/main/COMPILE.md). - Make a note of the workspace folder you created (where the `src`, `build` and `install` folders live). -1. Install the dependencies: - The plugin uses Qt as dependency. - Since PlotJuggler also depends on Qt, chances are high that you already have it installed. - On Ubuntu Qt can be installed with: - - ```bash - sudo apt -y install qtbase5-dev libqt5svg5-dev - ``` - -2. The optional features are selected with cmake options, both `OFF` by default: - - `-DADD_UNITS=ON` displays the units of the logged fields (read at the end). - - `-DADD_RCOU_FUNCTION_LABELS=ON` displays the channel function next to its name. - -3. Compile using cmake: - - ```bash - export PJ_WS= - export LIBRARY_PATH="$LIBRARY_PATH:$PJ_WS/install/lib" - mkdir build; cd build - cmake -DCMAKE_PREFIX_PATH="$PJ_WS/install/lib/cmake/plotjuggler" -DCMAKE_LIBRARY_PATH="$PJ_WS/install/lib;$PJ_WS/build/PlotJuggler" .. - make - sudo make install - ``` - -### Testing a built plugin - -`tests/` holds a headless check that loads a plugin the way PlotJuggler does and -parses the small log in `tests/logs/`, without starting the GUI. -It also verifies that the cmake options above actually reached the binary, and on -Linux reports whether the plugin's libstdc++ requirement is satisfied by your -system — which is what catches a plugin built on a newer distro than the one -running it. - -```bash -cmake -S tests -B tests/build -DPJ_INCLUDE_DIR="$PJ_WS/install/include" -cmake --build tests/build -./tests/test_plugin.sh build/libDataAPBin.so -``` +### Notes for building on macOS -Point it at a plugin downloaded from CI or a release to check it before use. +Qt dependencies may not be found automatically. With Homebrew Qt 6, pass +`-DCMAKE_PREFIX_PATH="$(brew --prefix qt)"` to CMake; also include the installed +SDK prefix if you are building without Conan. The current official PlotJuggler +app bundle permits third-party plugin libraries, so the old workaround that +re-signed the application is no longer needed. -### Notes for building on MacOS +### Optional labels -Qt dependencies may not be found automatically. -If you run into issues, try this `cmake` command instead: +Both options default to `OFF`: -```bash -cmake -DCMAKE_PREFIX_PATH="/opt/homebrew/opt/qt@5;$PJ_WS/install/lib/cmake/plotjuggler" -DCMAKE_LIBRARY_PATH="$PJ_WS/install/lib;$PJ_WS/build/PlotJuggler" .. -``` +* `-DADD_UNITS=ON` appends units to field names. +* `-DADD_RCOU_FUNCTION_LABELS=ON` appends servo functions to RCOU/RCO2 channel names. -If using this plugin with the new official PlotJuggler .dmg releases, you may run into signing and security issues. -This command allows running a custom plugin on a signed version of PlotJuggler: +Build and run CTest for each configuration you use. **Be careful:** changing +either option changes series names. A saved layout created without units or servo +labels cannot resolve those series after enabling the corresponding option, and +vice versa. Use the same label configuration when opening a saved layout. -```bash -sudo codesign --force --deep --sign - /Applications/PlotJuggler.app +### Docker + +```sh +mkdir -p artifacts +docker build --output type=local,dest=artifacts . ``` -This likely adds your signature to the app so your plugin and the official .dmg now share a common signature. +Build arguments: `BASE_IMAGE` (default `ubuntu:22.04`), `ADD_UNITS`, and +`ADD_RCOU_FUNCTION_LABELS` (both default `OFF`). The image builds the SDK through +Conan and tests the plugin; it does not compile the PlotJuggler GUI. +Pass an argument with `--build-arg`, for example `--build-arg ADD_UNITS=ON`. +The exported `libDataAPBin.so` and `DataAPBin.pjmanifest.json` are placed in +`artifacts/`; copy them to a PlotJuggler plugin folder. + +Choose a base image whose libstdc++ and glibc requirements are supported by the +host running PlotJuggler. A plugin built on a newer distribution may fail to +load on an older one. The default Ubuntu 22.04 base preserves compatibility with +22.04 and newer hosts; `tests/test_plugin.sh` reports the binary's ABI floor. + +## Install and load logs + +The standalone install tree contains `lib/libDataAPBin.so` on Linux, +`lib/DataAPBin.dll` on Windows, or `lib/libDataAPBin.dylib` on macOS, plus the +SDK-generated `DataAPBin.pjmanifest.json` sidecar in the same directory. +Check **App -> Preferences -> Plugins** to find the default plugin folders or add +a custom folder. Copy the binary and sidecar there, then restart PlotJuggler so +it scans the folder. This also applies when adding a folder in Preferences. -## Install plotjuggler-apbin-plugin +You can instead launch the PlotJuggler executable with `--plugin-dir `. +For a source build, use the launch scripts **from the PlotJuggler repository**: -PlotJuggler looks for plugins in specific folders. -Check **App->Preferences->Plugins** in PlotJuggler to find out which they are and add more if you wish to. +```sh +/absolute/path/to/PlotJuggler/run.sh --plugin-dir /absolute/path/to/plugin_install/lib +``` -If you have added a folder, you will need to restart PlotJuggler for the change to take effect. +On Windows use `C:\path\to\PlotJuggler\run.bat --plugin-dir `. +Open an ArduPilot `.bin` or `.BIN` +file with the **ArduPilot Bin** data source. The host passes its path through the +SDK's `filepath` configuration property. -### For prebuilt binaries +The loader preserves message/instance/field paths, multipliers, GPS time +synchronization, parameter defaults, and message text. Timestamps passed to the +SDK are nanoseconds. When GPS time is unavailable, TimeUS uses seconds since boot, +including older logs without FMTU. Every import resets the decoding state. -You can find a pre-built plugin for Ubuntu and Windows in the [Github Releases](https://github.com/ArduPilot/plotjuggler-apbin-plugins/releases) page. -Copy that binary to one of the PlotJuggler plugin folders. +The message timeline is now `/2. Message Timeline/index`, since PlotJuggler 4 +represents scalar series as a topic plus field. The SDK's scalar write API has +no per-field tooltip setter; XML descriptions are retained in dataset metadata +under `field_descriptions`, available in the metadata inspector. -### For Docker-built binaries +## Test a downloaded or locally built binary -If you used Docker to compile the plugin, copy the build artifact from the `artifacts` folder to one of the PlotJuggler plugin folders. +The headless helper loads the binary through the same SDK library loader as +PlotJuggler 4 and binds recording write/runtime services. It verifies the real +log in `tests/logs`, repeated imports, parameter/message-only logs, old and new +MSG layouts, timestamp units, configuration roundtrips, cancellation, and +file/host failures. -### For locally-built binaries +```sh +build/tests/pj_plugin_smoketest build/libDataAPBin.so tests/logs/00000001.BIN --verify +``` -If you compiled the plugin in your host system, the plugin has been installed to `/usr/local/bin/`. +Use `--expect-units` and/or `--expect-rcou` together with `--verify` for enabled +label options. On Windows the DLL is under `build/Release` and the helper is +under `build/tests/Release` when using a multi-configuration generator. -Ensure that PlotJuggler scans for plugins in this folder or copy the plugin in one of the folders PlotJuggler already scans. +To build the helper independently, for example to test a downloaded plugin: -## Displaying units +```sh +cmake -S tests -B tests/build -DCMAKE_PREFIX_PATH= -DCMAKE_BUILD_TYPE=Release +cmake --build tests/build --config Release --parallel +``` -This plugin allows the units of logged fields to be appended to the logged field names. +With a multi-configuration Windows generator, this helper is under +`tests/build/Release`. -**Be careful:** +On Linux, `tests/test_plugin.sh [log]` uses this independent helper and +also reports the libstdc++ ABI floor. To use the helper from the main build, +select its path explicitly: -If you created a PlotJuggler layout without units and then enable the units, the layout will be unusable and vice-versa. -This is because the units are part of the field name; hence, the original field name no longer exists. +```sh +SMOKETEST=build/tests/pj_plugin_smoketest tests/test_plugin.sh build/libDataAPBin.so --verify +``` diff --git a/conanfile.txt b/conanfile.txt index c586403..26ea3d9 100644 --- a/conanfile.txt +++ b/conanfile.txt @@ -1,12 +1,6 @@ - [requires] - protobuf/3.21.12 - mosquitto/2.0.18 - zeromq/4.3.5 - zlib/1.2.13 +[requires] +plotjuggler_sdk/0.40.0 - [options] - zeromq*:shared=False - - [generators] - CMakeDeps - CMakeToolchain +[generators] +CMakeDeps +CMakeToolchain diff --git a/package.xml b/package.xml index b559f2a..2bf98b0 100644 --- a/package.xml +++ b/package.xml @@ -1,7 +1,7 @@ plotjuggler_apbin_plugins - 0.1.0 + 0.2.0 PlotJuggler ArduPilot Bin plugins Pierre KANCIR @@ -14,7 +14,8 @@ catkin ament_cmake - plotjuggler + + plotjuggler diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index f72582a..b4c7dcd 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,21 +1,20 @@ -cmake_minimum_required(VERSION 3.16) -project(pj_plugin_smoketest CXX) - -set(CMAKE_CXX_STANDARD 17) -set(CMAKE_CXX_STANDARD_REQUIRED ON) - -# Deliberately no find_package(plotjuggler): the plugin under test is dlopened, so -# it carries its own copy of plotjuggler_base. All this harness needs is the -# headers that declare the DataLoader interface. Avoiding the package config also -# avoids PlotJuggler 3.16's exported target, whose link interface references -# fmt::fmt and lua::lua without ever looking them up. -set(PJ_INCLUDE_DIR "" CACHE PATH "PlotJuggler install include directory") -if(NOT PJ_INCLUDE_DIR) - message(FATAL_ERROR "Set -DPJ_INCLUDE_DIR=/include") +cmake_minimum_required(VERSION 3.22) +if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) + project(pj_plugin_smoketest LANGUAGES CXX) + find_package(plotjuggler_sdk 0.40.0 REQUIRED COMPONENTS plugin_host) + find_package(Qt6 REQUIRED COMPONENTS Core) endif() - -find_package(Qt5 REQUIRED COMPONENTS Core Widgets Xml) - add_executable(pj_plugin_smoketest pj_plugin_smoketest.cpp) -target_include_directories(pj_plugin_smoketest PRIVATE ${PJ_INCLUDE_DIR}) -target_link_libraries(pj_plugin_smoketest PRIVATE Qt5::Core Qt5::Widgets Qt5::Xml) +target_compile_features(pj_plugin_smoketest PRIVATE cxx_std_20) +target_link_libraries(pj_plugin_smoketest PRIVATE plotjuggler_sdk::plugin_host Qt6::Core) +if(TARGET DataAPBin) + set(_verify --verify) + if(ADD_UNITS) + list(APPEND _verify --expect-units) + endif() + if(ADD_RCOU_FUNCTION_LABELS) + list(APPEND _verify --expect-rcou) + endif() + add_test(NAME apbin_load_and_lifecycle + COMMAND pj_plugin_smoketest $ "${CMAKE_CURRENT_SOURCE_DIR}/logs/00000001.BIN" ${_verify}) +endif() diff --git a/tests/pj_plugin_smoketest.cpp b/tests/pj_plugin_smoketest.cpp index 4940992..86432e2 100644 --- a/tests/pj_plugin_smoketest.cpp +++ b/tests/pj_plugin_smoketest.cpp @@ -1,294 +1,502 @@ -// Headless smoke test for a PlotJuggler DataLoader plugin. +// Headless test through PlotJuggler 4's SDK loader and service registry. // -// Usage: pj_plugin_smoketest [logfile.bin] [--verify] [--expect-units] [--expect-rcou] +// Usage: pj_plugin_smoketest [logfile.bin] [--verify] [--expect-units] +// [--expect-rcou] // -// Exercises exactly what PlotJuggler does when it loads a plugin and opens a -// file, but without a GUI and without ever blocking: QPluginLoader, the -// qobject_cast to PJ::DataLoader, then readDataFromFile() on a real log. -// -// Without --verify the build configuration is only reported. With --verify it is -// asserted: the plugin must have been built with exactly the options named by -// --expect-units / --expect-rcou, and any option not named must be OFF. Both -// options work by changing series names, so the name of one known channel pins -// the build down exactly. Asserting the all-OFF case matters as much as the -// others -- an option wrongly forced on in the source looks fine otherwise. -// -// Exit code 0 means every requested check passed. - +// Without --verify, the helper checks loading, parsing and +// lifecycle behavior. With --verify, it also asserts the exact label +// configuration and a known sample from tests/logs/00000001.BIN. Exit code 0 +// means every requested check passed. +#include +#include +#include +#include +#include +#include +#include #include +#include #include -#include +#include +#include +#include +#include +#include +#include +#include #include #include -#include -#include -#include - -#include "PlotJuggler/dataloader_base.h" -#include "PlotJuggler/plotdata.h" - -namespace -{ -// tests/logs/00000001.BIN has SERVO1_FUNCTION set to Throttle, so this channel -// carries a function label whenever LABEL_RCOU_FUNCTION is compiled in, and a -// microsecond unit whenever LABEL_WITH_UNIT is. That makes exactly one of the -// four spellings below correct for any given build. -const char* const kChannel = "/RCOU/C1"; -const char* const kFunction = " (Throttle)"; -const char* const kUnit = "\t[us]"; - -std::string expectedName(bool with_units, bool with_rcou) -{ - std::string name = kChannel; - if (with_rcou) - { - name += kFunction; - } - if (with_units) - { - name += kUnit; - } - return name; +namespace { +std::string str(PJ_string_view_t s) { + return std::string(s.data ? s.data : "", s.size); } - -std::string describe(bool with_units, bool with_rcou) -{ - return std::string("units=") + (with_units ? "ON" : "OFF") + " rcou=" + (with_rcou ? "ON" : "OFF"); +void require(bool condition, const std::string& message) { + if (!condition) throw std::runtime_error(message); } - -void printUsage(const char* argv0) -{ - fprintf(stderr, - "usage: %s [logfile.bin] [--verify] [--expect-units] [--expect-rcou]\n", - argv0); +void ok(PJ::Status status) { + if (!status) throw std::runtime_error(status.error()); } -} // namespace - -int main(int argc, char** argv) -{ - std::string plugin_path; - std::string log_path; - bool expect_units = false; - bool expect_rcou = false; - bool verify = false; - - for (int i = 1; i < argc; ++i) - { - const std::string arg = argv[i]; - if (arg == "--verify") - { - verify = true; - } - else if (arg == "--expect-units") - { - expect_units = true; - } - else if (arg == "--expect-rcou") - { - expect_rcou = true; - } - else if (arg == "-h" || arg == "--help") - { - printUsage(argv[0]); - return 0; - } - else if (arg.rfind("--", 0) == 0) - { - fprintf(stderr, "unknown option: %s\n", arg.c_str()); - printUsage(argv[0]); - return 2; +using Samples = std::vector>; +void compareSeries(const std::map& expected, + const std::map& actual) { + require(expected.size() == actual.size(), + "repeated import changed the number of series"); + for (const auto& [name, samples] : expected) { + require(actual.count(name) != 0 && actual.at(name).size() == samples.size(), + "repeated import changed " + name); + const auto& loaded = actual.at(name); + for (size_t i = 0; i < samples.size(); ++i) { + // ArduPilot records unavailable values as NaN, which compares unequal to + // itself. + require( + samples[i].first == loaded[i].first && + (samples[i].second == loaded[i].second || + (std::isnan(samples[i].second) && std::isnan(loaded[i].second))), + "repeated import changed sample " + std::to_string(i) + " of " + + name); } - else if (plugin_path.empty()) - { - plugin_path = arg; - } - else if (log_path.empty()) - { - log_path = arg; - } - else - { - printUsage(argv[0]); - return 2; - } - } - - if (plugin_path.empty()) - { - printUsage(argv[0]); - return 2; } - if (log_path.empty() && (verify || expect_units || expect_rcou)) - { - fprintf(stderr, "FAIL: --verify needs a log file to check series names against\n"); - return 2; - } - if ((expect_units || expect_rcou) && !verify) - { - fprintf(stderr, "FAIL: --expect-* only means something with --verify\n"); - return 2; - } - - // A QApplication must exist before the plugin is instantiated: the plugin - // links Qt Widgets, and constructing a QWidget without one aborts. - QApplication app(argc, argv); - - const QFileInfo plugin_info(QString::fromStdString(plugin_path)); - if (!plugin_info.isFile()) - { - fprintf(stderr, "FAIL: no such plugin file: %s\n", plugin_path.c_str()); - return 2; +} +struct RecordingHost { + std::map topics; + std::map, std::string> fields; + std::map series; + std::map>> last_rows; + std::string metadata; + bool cancel = false, cancel_progress = false, fail_writes = false, + progress_finished = false; + uint64_t progress_total = 0, progress_step = 0; + static bool ensureTopic(void* ctx, PJ_string_view_t name, + PJ_topic_handle_t* out, PJ_error_t* error) noexcept { + auto& h = *static_cast(ctx); + if (h.fail_writes) { + PJ::sdk::fillError(error, 1, "test", "write refused"); + return false; + } + for (const auto& [id, topic] : h.topics) + if (topic == str(name)) { + *out = {id}; + return true; + } + out->id = static_cast(h.topics.size() + 1); + h.topics[out->id] = str(name); + return true; } - - // Must be absolute: QPluginLoader resolves a relative path against - // QCoreApplication::libraryPaths(), never the working directory, so a - // perfectly good relative path is reported as "The shared library was not - // found." -- see locatePlugin() in qpluginloader.cpp. - const QString qplugin = plugin_info.absoluteFilePath(); - - QPluginLoader loader(qplugin); - QObject* instance = loader.instance(); - if (!instance) - { - // This is where an ABI mismatch surfaces, e.g. a missing GLIBCXX version. - fprintf(stderr, "FAIL: could not load %s\n %s\n", qPrintable(qplugin), - qPrintable(loader.errorString())); - return 1; + static bool ensureField(void* ctx, PJ_topic_handle_t topic, + PJ_string_view_t name, PJ_primitive_type_t type, + PJ_field_handle_t* out, PJ_error_t*) noexcept { + auto& h = *static_cast(ctx); + if (type != PJ_PRIMITIVE_TYPE_FLOAT64 || !h.topics.count(topic.id)) + return false; + for (const auto& [key, field] : h.fields) + if (key.first == topic.id && field == str(name)) { + *out = {topic, key.second}; + return true; + } + const auto id = static_cast(h.fields.size() + 1); + h.fields[{topic.id, id}] = str(name); + *out = {topic, id}; + return true; } - - auto* dataloader = qobject_cast(instance); - if (!dataloader) - { - fprintf(stderr, "FAIL: library loaded but is not a PJ::DataLoader plugin\n"); - return 1; + static bool appendBound(void* ctx, PJ_topic_handle_t topic, int64_t ts, + const PJ_bound_field_value_t* values, uint64_t count, + PJ_error_t*) noexcept { + auto& h = *static_cast(ctx); + // The datastore fills omitted fields with null in each row. + auto& row = h.last_rows[h.topics.at(topic.id)]; + row.clear(); + for (const auto& [key, name] : h.fields) + if (key.first == topic.id) row[name] = std::nullopt; + for (uint64_t i = 0; i < count; ++i) { + const auto& v = values[i]; + const auto key = std::make_pair(topic.id, v.field.id); + if (v.field.topic.id != topic.id || !h.fields.count(key) || + v.value.type != PJ_PRIMITIVE_TYPE_FLOAT64) + return false; + if (!v.is_null) { + row[h.fields.at(key)] = v.value.data.as_float64; + h.series[h.topics.at(topic.id) + "/" + h.fields.at(key)].emplace_back( + ts, v.value.data.as_float64); + } + } + return true; } - - printf("OK : loaded DataLoader plugin \"%s\"\n", dataloader->name()); - printf(" extensions:"); - for (const char* ext : dataloader->compatibleFileExtensions()) - { - printf(" %s", ext); + static bool appendNamed(void* ctx, PJ_topic_handle_t topic, int64_t ts, + const PJ_named_field_value_t* values, uint64_t count, + PJ_error_t* error) noexcept { + std::vector bound; + bound.reserve(count); + for (uint64_t i = 0; i < count; ++i) { + PJ_field_handle_t field{}; + if (!ensureField(ctx, topic, values[i].name, values[i].value.type, &field, + error)) + return false; + bound.push_back({.field = field, + .is_null = values[i].is_null, + .value = values[i].value}); + } + return appendBound(ctx, topic, ts, bound.data(), bound.size(), error); } - printf("\n"); - - if (log_path.empty()) - { - printf("OK : load-only check passed (pass a log file to also test parsing)\n"); - return 0; + static PJ_source_write_host_vtable_t writeVtable() { + PJ_source_write_host_vtable_t vt{}; + vt.abi_version = PJ_ABI_VERSION; + vt.struct_size = sizeof(vt); + vt.ensure_topic = ensureTopic; + vt.ensure_field = ensureField; + vt.append_record = appendNamed; + vt.append_bound_record = appendBound; + return vt; } - - const QString qlog = QString::fromStdString(log_path); - if (!QFileInfo::exists(qlog)) - { - fprintf(stderr, "FAIL: no such log file: %s\n", log_path.c_str()); - return 2; + static PJ_data_source_runtime_host_vtable_t runtimeVtable() { + PJ_data_source_runtime_host_vtable_t vt{}; + vt.protocol_version = 1; + vt.struct_size = sizeof(vt); + vt.progress_start = [](void* ctx, PJ_string_view_t, uint64_t total, bool, + PJ_error_t*) noexcept { + auto& h = *static_cast(ctx); + h.progress_total = total; + h.progress_finished = false; + return true; + }; + vt.progress_update = [](void* ctx, uint64_t step) noexcept { + auto& h = *static_cast(ctx); + h.progress_step = step; + return !h.cancel_progress; + }; + vt.progress_finish = [](void* ctx) noexcept { + static_cast(ctx)->progress_finished = true; + }; + vt.is_stop_requested = [](void* ctx) noexcept { + return static_cast(ctx)->cancel; + }; + vt.set_dataset_metadata = [](void* ctx, PJ_string_view_t json, + PJ_error_t*) noexcept { + static_cast(ctx)->metadata = str(json); + return true; + }; + return vt; } - - PJ::PlotDataMapRef data; - PJ::FileLoadInfo info; - info.filename = qlog; - - bool parsed = false; - try - { - parsed = dataloader->readDataFromFile(&info, data); +}; +std::string config(const QString& path) { + return QJsonDocument(QJsonObject{{"filepath", path}}) + .toJson(QJsonDocument::Compact) + .toStdString(); +} +void addFormat(QByteArray& bytes, uint8_t type, uint8_t length, + const char* name, const char* format, const char* labels) { + QByteArray fmt(89, '\0'); + fmt[0] = char(0xa3); + fmt[1] = char(0x95); + fmt[2] = char(128); + fmt[3] = char(type); + fmt[4] = char(length); + std::memcpy(fmt.data() + 5, name, std::min(4, std::strlen(name))); + std::memcpy(fmt.data() + 9, format, std::strlen(format)); + std::memcpy(fmt.data() + 25, labels, std::strlen(labels)); + bytes += fmt; +} +template +void appendLE(QByteArray& bytes, T value) { + bytes.append(reinterpret_cast(&value), sizeof(value)); +} +QString syntheticLog(const QString& directory, bool modern_msg, + bool gps = false, uint64_t time_us = 2000000) { + QByteArray bytes; + addFormat(bytes, 42, 15, "TEST", "Qf", "TimeUS,Value"); + addFormat(bytes, 43, modern_msg ? 77 : 75, "MSG", modern_msg ? "QBBZ" : "QZ", + modern_msg ? "TimeUS,ID,Seq,Message" : "TimeUS,Message"); + if (gps) addFormat(bytes, 44, 18, "GPS", "QHIB", "TimeUS,GWk,GMS,NSats"); + bytes.append(char(0xa3)); + bytes.append(char(0x95)); + bytes.append(char(42)); + appendLE(bytes, time_us); + appendLE(bytes, float(42.5)); + if (gps) { + bytes.append(char(0xa3)); + bytes.append(char(0x95)); + bytes.append(char(44)); + appendLE(bytes, uint64_t(2000000)); + appendLE(bytes, uint16_t(2200)); + appendLE(bytes, uint32_t(100000)); + bytes.append(char(6)); } - catch (const std::exception& err) - { - fprintf(stderr, "FAIL: exception while parsing: %s\n", err.what()); - return 1; + bytes.append(char(0xa3)); + bytes.append(char(0x95)); + bytes.append(char(43)); + appendLE(bytes, uint64_t(3000000)); + if (modern_msg) { + bytes.append(char(7)); + bytes.append(char(0)); } - - if (!parsed) - { - fprintf(stderr, "FAIL: readDataFromFile() returned false\n"); - return 1; + QByteArray text(64, '\0'); + std::memcpy(text.data(), "hello/world", 11); + bytes += text; + const auto path = directory + (modern_msg ? "/modern.BIN" : "/legacy.bin"); + QFile file(path); + require(file.open(QFile::WriteOnly), "cannot create fixture"); + require(file.write(bytes) == bytes.size(), "cannot write fixture"); + return path; +} +QString snapshotOnlyLog(const QString& directory, bool parameters, + bool messages) { + QByteArray bytes; + addFormat(bytes, 45, 35, "PARM", "QNff", "TimeUS,Name,Value,Default"); + addFormat(bytes, 43, 75, "MSG", "QZ", "TimeUS,Message"); + if (parameters) { + bytes.append(char(0xa3)); + bytes.append(char(0x95)); + bytes.append(char(45)); + appendLE(bytes, uint64_t(2000000)); + QByteArray name(16, '\0'); + std::memcpy(name.data(), "SNAPSHOT", 8); + bytes += name; + appendLE(bytes, float(42.5)); + appendLE(bytes, float(0)); } - - size_t samples = 0; - for (const auto& series : data.numeric) - { - samples += series.second.size(); + if (messages) { + bytes.append(char(0xa3)); + bytes.append(char(0x95)); + bytes.append(char(43)); + appendLE(bytes, uint64_t(3000000)); + QByteArray text(64, '\0'); + std::memcpy(text.data(), "snapshot/message", 16); + bytes += text; } - - printf("OK : parsed \"%s\"\n", qPrintable(QFileInfo(qlog).fileName())); - printf(" numeric series: %zu (%zu samples)\n", data.numeric.size(), samples); - printf(" string series : %zu\n", data.strings.size()); - - if (data.numeric.empty()) - { - fprintf(stderr, "FAIL: parsing reported success but produced no numeric series\n"); - return 1; + const auto path = directory + "/snapshots.bin"; + QFile file(path); + require(file.open(QFile::WriteOnly), "cannot create snapshot fixture"); + require(file.write(bytes) == bytes.size(), "cannot write snapshot fixture"); + return path; +} +QString repeatedParameterLog(const QString& directory) { + const auto path = syntheticLog(directory, false); + QByteArray bytes; + addFormat(bytes, 45, 35, "PARM", "QNff", "TimeUS,Name,Value,Default"); + // Unequal occurrence counts exercise null cells in grouped parameter rows. + for (const auto& [name, value] : + {std::pair{"STATIC", 10.0f}, std::pair{"TWICE", 20.0f}, + std::pair{"THRICE", 30.0f}, std::pair{"TWICE", 21.0f}, + std::pair{"THRICE", 31.0f}, std::pair{"THRICE", 32.0f}}) { + bytes.append(char(0xa3)); + bytes.append(char(0x95)); + bytes.append(char(45)); + appendLE(bytes, uint64_t(4000000)); + QByteArray param_name(16, '\0'); + std::memcpy(param_name.data(), name, std::strlen(name)); + bytes += param_name; + appendLE(bytes, value); + appendLE(bytes, 0.0f); } - - // Which of the four spellings of the reference channel is present tells us - // exactly which ifdefs were compiled in. Requiring the other three to be - // absent is what catches a flag stuck on -- or stuck off -- in the source. - const std::string wanted = expectedName(expect_units, expect_rcou); - std::vector found; - for (bool units : { false, true }) - { - for (bool rcou : { false, true }) - { - const std::string candidate = expectedName(units, rcou); - if (data.numeric.count(candidate) != 0) - { - found.push_back(candidate); - printf(" built with : %s\n", describe(units, rcou).c_str()); - } + QFile file(path); + require(file.open(QFile::Append), "cannot append parameter fixture"); + require(file.write(bytes) == bytes.size(), "cannot write parameter fixture"); + return path; +} +} // namespace +int main(int argc, char** argv) { + QCoreApplication app(argc, argv); + try { + require(argc >= 2, + "usage: pj_plugin_smoketest [log] [--verify] " + "[--expect-units] [--expect-rcou]"); + bool verify = false, units = false, rcou = false; + QString log; + for (int i = 2; i < argc; ++i) { + const std::string arg = argv[i]; + if (arg == "--verify") + verify = true; + else if (arg == "--expect-units") + units = true; + else if (arg == "--expect-rcou") + rcou = true; + else if (log.isEmpty() && !arg.starts_with("--")) + log = QString::fromLocal8Bit(argv[i]); + else + throw std::runtime_error("unknown argument: " + arg); } - } - - if (found.empty()) - { - fprintf(stderr, "FAIL: reference channel %s not found in this log under any\n", kChannel); - fprintf(stderr, " expected name. Names starting with %s:\n", kChannel); - std::vector nearby; - for (const auto& series : data.numeric) - { - if (series.first.rfind(kChannel, 0) == 0) - { - nearby.push_back(series.first); + require(verify || (!units && !rcou), "--expect-* requires --verify"); + auto library = PJ::DataSourceLibrary::load(std::filesystem::path(argv[1])); + require(library.has_value(), library ? "" : library.error()); + auto source = library->createHandle(); + require(source.valid(), "plugin instance creation failed"); + const auto manifest = + QJsonDocument::fromJson(QByteArray::fromStdString(source.manifest())) + .object(); + require(manifest.value("id").toString() == "ardupilot-bin", + "wrong plugin id"); + require(manifest.value("file_extensions").toArray().contains(".bin"), + "missing .bin extension"); + require(source.capabilities() == + (PJ::kCapabilityFiniteImport | PJ::kCapabilityDirectIngest), + "wrong capabilities"); + std::puts("OK: loaded PlotJuggler 4 ArduPilot Bin data source"); + if (log.isEmpty()) { + require(!verify, "--verify requires the reference log"); + return 0; + } + RecordingHost host; + const auto write_vt = RecordingHost::writeVtable(); + const auto runtime_vt = RecordingHost::runtimeVtable(); + PJ::ServiceRegistryBuilder registry; + registry.registerService("pj.source_write.v1", 1, {&host, &write_vt}); + registry.registerService("pj.runtime.v1", 1, {&host, &runtime_vt}); + ok(source.bind(registry.view())); + require(!source.loadConfig("{"), "invalid JSON accepted"); + require(!source.loadConfig("{}"), "missing filepath accepted"); + require(!source.loadConfig("{\"filepath\":42}"), + "non-string filepath accepted"); + ok(source.loadConfig(config(QFileInfo(log).absoluteFilePath()))); + std::string saved; + ok(source.saveConfig(saved)); + require(QJsonDocument::fromJson(QByteArray::fromStdString(saved)) + .object() + .value("filepath") + .toString() == QFileInfo(log).absoluteFilePath(), + "config roundtrip failed"); + ok(source.start()); + require(source.currentState() == PJ::DataSourceState::kStopped, + "finite import did not finish"); + require(host.progress_finished && host.progress_step == host.progress_total, + "progress did not finish"); + require(!host.series.empty(), "no samples loaded"); + // The reference log has SERVO1_FUNCTION=Throttle and RCOU.C1 in + // microseconds. Its full name therefore identifies exactly which of the + // four label builds is loaded, including the all-OFF case. A flag forced ON + // or OFF fails here. + std::string wanted = "/RCOU/C1"; + if (rcou) wanted += " (Throttle)"; + if (units) wanted += "\t[us]"; + if (verify) + require(host.series.count(wanted) && !host.series.at(wanted).empty(), + "wrong build labels: expected " + wanted); + // Independently decoded first RCOU sample: TimeUS=28416489, C1=1002. + if (verify) + require(host.series.at(wanted).front() == + std::pair{28416489000LL, 1002.0}, + "reference RCOU sample changed"); + require(!QJsonDocument::fromJson(QByteArray::fromStdString(host.metadata)) + .object() + .value("field_descriptions") + .toObject() + .isEmpty(), + "embedded descriptions missing"); + const auto first = host.series; + host = RecordingHost{}; + ok(source.start()); + compareSeries(first, host.series); + QTemporaryDir directory; + require(directory.isValid(), "temporary directory unavailable"); + host = RecordingHost{}; + ok(source.loadConfig(config(repeatedParameterLog(directory.path())))); + ok(source.start()); + const auto& parameter_row = host.last_rows.at("/1. Parameters"); + require(parameter_row.size() == 3 && + parameter_row.at("STATIC Default: 0") == 10.0 && + parameter_row.at("TWICE Default: 0") == 21.0 && + parameter_row.at("THRICE Default: 0") == 32.0, + "repeated parameters hide values in the latest snapshot"); + const auto& changes = + host.series.at("/1. Parameters/TWICE Default: 0"); + require( + changes.size() >= 2 && + changes[0] == std::pair{300000000000LL, 20.0} && + changes[1] == std::pair{300000000000LL, 21.0}, + "parameter changes or snapshot timestamp lost"); + // Short logs can contain useful parameters/messages without numeric data. + for (const auto [parameters, messages] : + {std::pair{true, false}, std::pair{false, true}, + std::pair{true, true}}) { + host = RecordingHost{}; + ok(source.loadConfig( + config(snapshotOnlyLog(directory.path(), parameters, messages)))); + ok(source.start()); + require(source.currentState() == PJ::DataSourceState::kStopped && + host.progress_finished && + host.progress_step == host.progress_total, + "snapshot-only import did not finish"); + require( + host.series.size() == (parameters ? 1u : 0u) + (messages ? 2u : 0u), + "snapshot-only import lost data or leaked previous series"); + if (parameters) + require(host.series.at("/1. Parameters/SNAPSHOT Default: 0") == + Samples{{300000000000LL, 42.5}}, + "parameter-only value or timestamp lost"); + if (messages) { + require(host.series.at("/2. Message Timeline/index") == + Samples{{3000000000LL, 1.0}}, + "message-only timeline lost"); + require(host.series.at("/3. Message Log/1. snapshot\\message") == + Samples{{0, 3.0}}, + "message-only text or relative time lost"); } } - std::sort(nearby.begin(), nearby.end()); - for (const auto& name : nearby) - { - fprintf(stderr, " %s\n", name.c_str()); + host = RecordingHost{}; + ok(source.loadConfig( + config(snapshotOnlyLog(directory.path(), false, false)))); + require(!source.start() && host.series.empty() && host.progress_finished, + "format-only log without supported data accepted"); + // A GNSS-aligned import followed by a boot-time import checks offset reset. + for (const auto [modern, gps] : + {std::pair{false, false}, std::pair{true, true}, + std::pair{true, false}}) { + const auto path = syntheticLog(directory.path(), modern, gps); + host = RecordingHost{}; + ok(source.loadConfig(config(path))); + ok(source.start()); + const int64_t time_ns = gps ? 1646524882000000000LL : 2000000000LL; + require(host.series.at("/TEST/Value") == Samples{{time_ns, 42.5}}, + "TimeUS/GPS conversion or state reset failed"); + require(host.series.at("/2. Message Timeline/index") == + Samples{{time_ns + 1000000000LL, 1.0}}, + "MSG layout or stale GPS offset"); + require(host.series.at("/3. Message Log/1. hello\\world") == + Samples{{0, gps ? 1.0 : 3.0}}, + "MSG text or stale start time"); + require(host.series.size() == (gps ? 6u : 3u), + "parameters/messages leaked from previous log"); } - if (nearby.empty()) + host = RecordingHost{}; + host.cancel = true; + require(!source.start() && + source.currentState() == PJ::DataSourceState::kFailed && + host.series.empty(), + "stop request ignored"); + host = RecordingHost{}; + host.cancel_progress = true; + require(!source.start() && host.progress_finished && host.series.empty(), + "progress cancellation ignored"); + host = RecordingHost{}; + host.fail_writes = true; + require(!source.start() && + source.currentState() == PJ::DataSourceState::kFailed, + "host write error ignored"); + host = RecordingHost{}; + ok(source.loadConfig(config(directory.path() + "/missing.bin"))); + require(!source.start(), "missing file accepted"); + const auto empty = directory.path() + "/empty.bin"; { - fprintf(stderr, " (none)\n"); + QFile f(empty); + require(f.open(QFile::WriteOnly), "cannot create empty fixture"); } - return 1; - } - - if (found.size() > 1) - { - fprintf(stderr, "FAIL: reference channel matched %zu spellings at once, so the\n", found.size()); - fprintf(stderr, " naming is ambiguous and this check cannot be trusted\n"); - return 1; - } - - if (!verify) - { - // Nothing was asserted, so just report what the build looks like. - printf("OK : parse check passed (pass --verify to assert the build\n"); - printf(" configuration as well)\n"); + ok(source.loadConfig(config(empty))); + require(!source.start(), "empty file accepted"); + host = RecordingHost{}; + ok(source.loadConfig( + config(syntheticLog(directory.path(), false, false, UINT64_MAX)))); + require(!source.start() && + source.currentState() == PJ::DataSourceState::kFailed && + host.progress_finished, + "timestamp overflow or exception cleanup failed"); + std::printf( + "OK: real log (%zu series), repeated imports and parameters, " + "snapshot-only logs, both MSG " + "layouts, " + "nanosecond timestamps, config, cancellation and errors\n", + first.size()); return 0; - } - - if (found.front() != wanted) - { - fprintf(stderr, "FAIL: wrong build configuration\n"); - fprintf(stderr, " expected %s -> \"%s\"\n", describe(expect_units, expect_rcou).c_str(), - wanted.c_str()); - fprintf(stderr, " actual -> \"%s\"\n", found.front().c_str()); - fprintf(stderr, " ADD_UNITS/ADD_RCOU_FUNCTION_LABELS are not reaching the binary\n"); + } catch (const std::exception& error) { + std::fprintf(stderr, "FAIL: %s\n", error.what()); return 1; } - - printf("OK : build configuration matches %s\n", describe(expect_units, expect_rcou).c_str()); - return 0; } diff --git a/tests/test_plugin.sh b/tests/test_plugin.sh index 6ff92bc..3ceefc1 100755 --- a/tests/test_plugin.sh +++ b/tests/test_plugin.sh @@ -7,11 +7,11 @@ # 1. ABI floor - which libstdc++/glibc the plugin demands, and whether this # host can satisfy it. This is what catches "built on a newer # distro than the user runs". Linux only. -# 2. Plugin load - QPluginLoader + cast to PJ::DataLoader, as PlotJuggler does. -# 3. Parse - readDataFromFile() on a real ArduPilot .bin. +# 2. Plugin load - SDK DataSourceLibrary + C ABI, as PlotJuggler 4 does. +# 3. Parse - SDK start() on a real ArduPilot .bin and lifecycle regressions. # # Build the helper it drives first: -# cmake -S tests -B tests/build -DPJ_INCLUDE_DIR=/include +# cmake -S tests -B tests/build -DCMAKE_PREFIX_PATH= # cmake --build tests/build set -uo pipefail @@ -64,14 +64,12 @@ fi echo "=== 2/3. Plugin load and parse ===" if [ ! -x "$SMOKETEST" ]; then echo " SKIP: $SMOKETEST not built." >&2 - echo " cmake -S $SCRIPT_DIR -B $SCRIPT_DIR/build -DPJ_INCLUDE_DIR=/include" >&2 + echo " cmake -S $SCRIPT_DIR -B $SCRIPT_DIR/build -DCMAKE_PREFIX_PATH=" >&2 echo " cmake --build $SCRIPT_DIR/build" >&2 [ "$abi_ok" -eq 1 ] || exit 1 exit 3 fi -# offscreen so this runs over SSH and in CI with no display attached -export QT_QPA_PLATFORM=offscreen "$SMOKETEST" "$PLUGIN" "$LOG" "$@" result=$? From d59eb4a2c2e1983210c8b80f366a9152a9ffc0ff Mon Sep 17 00:00:00 2001 From: "Dr.-Ing. Amilcar do Carmo Lucas" Date: Fri, 13 Nov 2026 15:35:22 +0100 Subject: [PATCH 2/2] feat: bundle ArduPilot JSON log descriptions Replace the XML description loader with the published Copter and Plane JSON metadata, embedded at build time for offline use. - Select descriptions using the log's firmware banner and fall back to the other vehicle's metadata when fields are missing. - Retain older-only field descriptions and enum entries in legacy JSON. - Validate and compact metadata during header generation, preserving UTF-8 and MSVC string-literal limits. - Rebuild the generated header when metadata changes and document how to refresh the snapshots. - Test vehicle selection, legacy fallbacks, malformed metadata, and UTF-8 chunk boundaries. Validated all four Linux label configurations, installed plugins, and catkin/ament builds. Native Windows and macOS builds were not run. Signed-off-by: Dr.-Ing. Amilcar do Carmo Lucas --- CMakeLists.txt | 8 +- .../LogMessageDescriptions/Copter.xml | 11928 --------------- .../Copter_LegacyDescriptions.json | 176 + .../Copter_LogMessages.json.xz | Bin 0 -> 41256 bytes .../LogMessageDescriptions/Plane.xml | 12362 ---------------- .../Plane_LegacyDescriptions.json | 199 + .../Plane_LogMessages.json.xz | Bin 0 -> 42736 bytes DataLoadAPBin/dataload_apbin.cpp | 116 +- DataLoadAPBin/dataload_apbin.h | 6 +- .../generate_LogMessageDescriptions_header.py | 158 +- README.md | 19 +- tests/CMakeLists.txt | 2 + tests/pj_plugin_smoketest.cpp | 61 +- tests/test_metadata_generator.py | 55 + 14 files changed, 636 insertions(+), 24454 deletions(-) delete mode 100644 DataLoadAPBin/LogMessageDescriptions/Copter.xml create mode 100644 DataLoadAPBin/LogMessageDescriptions/Copter_LegacyDescriptions.json create mode 100644 DataLoadAPBin/LogMessageDescriptions/Copter_LogMessages.json.xz delete mode 100644 DataLoadAPBin/LogMessageDescriptions/Plane.xml create mode 100644 DataLoadAPBin/LogMessageDescriptions/Plane_LegacyDescriptions.json create mode 100644 DataLoadAPBin/LogMessageDescriptions/Plane_LogMessages.json.xz create mode 100644 tests/test_metadata_generator.py diff --git a/CMakeLists.txt b/CMakeLists.txt index 496c65a..4e9f6ed 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,12 +40,16 @@ endif() option(ADD_UNITS "Append units to field names" OFF) option(ADD_RCOU_FUNCTION_LABELS "Append servo functions to RCOU/RCO2 field names" OFF) -file(GLOB LOGMSG_XML CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/DataLoadAPBin/LogMessageDescriptions/*.xml") +set(LOGMSG_JSON + "${CMAKE_CURRENT_SOURCE_DIR}/DataLoadAPBin/LogMessageDescriptions/Copter_LogMessages.json.xz" + "${CMAKE_CURRENT_SOURCE_DIR}/DataLoadAPBin/LogMessageDescriptions/Plane_LogMessages.json.xz" + "${CMAKE_CURRENT_SOURCE_DIR}/DataLoadAPBin/LogMessageDescriptions/Copter_LegacyDescriptions.json" + "${CMAKE_CURRENT_SOURCE_DIR}/DataLoadAPBin/LogMessageDescriptions/Plane_LegacyDescriptions.json") set(GEN_LOGMSG_HDR_OUT "${CMAKE_CURRENT_BINARY_DIR}/LogMessageDescriptions.h") add_custom_command(OUTPUT "${GEN_LOGMSG_HDR_OUT}" COMMAND "${Python3_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/DataLoadAPBin/scripts/generate_LogMessageDescriptions_header.py" "${CMAKE_CURRENT_SOURCE_DIR}/DataLoadAPBin/LogMessageDescriptions" "${GEN_LOGMSG_HDR_OUT}" - DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/DataLoadAPBin/scripts/generate_LogMessageDescriptions_header.py" ${LOGMSG_XML} + DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/DataLoadAPBin/scripts/generate_LogMessageDescriptions_header.py" ${LOGMSG_JSON} COMMENT "Embedding ArduPilot log message descriptions" VERBATIM) diff --git a/DataLoadAPBin/LogMessageDescriptions/Copter.xml b/DataLoadAPBin/LogMessageDescriptions/Copter.xml deleted file mode 100644 index 5d766a3..0000000 --- a/DataLoadAPBin/LogMessageDescriptions/Copter.xml +++ /dev/null @@ -1,11928 +0,0 @@ - - - - - - IMU accelerometer data - - - Time since system startup - - - accelerometer sensor instance number - - - time since system startup this sample was taken - - - acceleration along X axis - - - acceleration along Y axis - - - acceleration along Z axis - - - - - Automatic Dependent Serveillance - Broadcast detected vehicle information - - - Time since system startup - - - Transponder address - - - Vehicle latitude - - - Vehicle longitude - - - Vehicle altitude - - - Vehicle heading - - - Vehicle horizontal velocity - - - Vehicle vertical velocity - - - Transponder squawk code - - - - - Backup AHRS data - - - Time since system startup - - - Estimated roll - - - Estimated pitch - - - Estimated yaw - - - Estimated altitude - - - Estimated latitude - - - Estimated longitude - - - Estimated attitude quaternion component 1 - - - Estimated attitude quaternion component 2 - - - Estimated attitude quaternion component 3 - - - Estimated attitude quaternion component 4 - - - - - Contents of 'position report' AIS message, see: https://gpsd.gitlab.io/gpsd/AIVDM.html#_types_1_2_and_3_position_report_class_a - - - Time since system startup - - - Message Type - - - Repeat Indicator - - - MMSI - - - Navigation Status - - - Rate of Turn (ROT) - - - Speed Over Ground (SOG) - - - Position Accuracy - - - Longitude - - - Latitude - - - Course Over Ground (COG) - - - True Heading (HDG) - - - Time Stamp - - - Maneuver Indicator - - - RAIM flag - - - Radio status - - - - - Contents of 'Base Station Report' AIS message, see: https://gpsd.gitlab.io/gpsd/AIVDM.html#_type_4_base_station_report - - - Time since system startup - - - Repeat Indicator - - - MMSI - - - Year (UTC) - - - Month (UTC) - - - Day (UTC) - - - Hour (UTC) - - - Minute (UTC) - - - Second (UTC) - - - Fix quality - - - Longitude - - - Latitude - - - Type of EPFD - - - RAIM flag - - - Radio status - - - - - Contents of 'static and voyage related data' AIS message, see: https://gpsd.gitlab.io/gpsd/AIVDM.html#_type_5_static_and_voyage_related_data - - - Time since system startup - - - Repeat Indicator - - - MMSI - - - AIS Version - - - IMO Number - - - Call Sign - - - Vessel Name - - - Ship Type - - - Dimension to Bow - - - Dimension to Stern - - - Dimension to Port - - - Dimension to Starboard - - - Position Fix Type - - - Draught - - - Destination - - - DTE - - - - - Raw AIS AVDIM messages contents, see: https://gpsd.gitlab.io/gpsd/AIVDM.html#_aivdmaivdo_sentence_layer - - - Time since system startup - - - count of fragments in the currently accumulating message - - - fragment number of this sentence - - - sequential message ID for multi-sentence messages - - - data payload - - - - - Attitude control attitude - - - Timestamp of the current Attitude loop - - - vehicle desired roll - - - achieved vehicle roll - - - vehicle desired pitch - - - achieved vehicle pitch - - - vehicle desired yaw - - - achieved vehicle yaw - - - attitude delta time - - - - - Angle of attack and Side Slip Angle values - - - Time since system startup - - - Angle of Attack calculated from airspeed, wind vector,velocity vector - - - Side Slip Angle calculated from airspeed, wind vector,velocity vector - - - - - helicopter AutoRotation Head Speed (ARHS) controller information - - - Time since system startup - - - Normalised target head speed - - - Normalised measured head speed - - - Head speed controller error - - - P-term for head speed controller response - - - FF-term for head speed controller response - - - - - Arming status changes - - - Time since system startup - - - true if vehicle is now armed - - - arming bitmask at time of arming - - - 2 - - - 4 - - - 8 - - - 16 - - - 32 - - - 64 - - - 128 - - - 256 - - - 512 - - - 1024 - - - 2048 - - - 4096 - - - 8192 - - - 16384 - - - 32768 - - - 65536 - - - 131072 - - - 262144 - - - 524288 - - - 1048576 - - - 2097152 - - - - - true if arm/disarm was forced - - - method used for arming - - - 0 - - - 1 - - - 2 - - - 3 - - - 4 - - - 5 - only disarm uses this... - - - 6 - only disarm uses this... - - - 7 - only disarm uses this... - - - 8 - only disarm uses this... - - - 9 - only disarm uses this... - - - 10 - only disarm uses this... - - - 11 - only disarm uses this... - - - 12 - only disarm uses this... - - - 13 - only disarm uses this... - - - 14 - only disarm uses this... - - - 15 - only disarm uses this... - - - 16 - only disarm uses this... - - - 17 - only disarm uses this... - - - 18 - only disarm uses this... - - - 19 - only disarm uses this... - - - 20 - only disarm uses this... - - - 21 - only disarm uses this... - - - 22 - only disarm uses this... - - - 23 - only disarm uses this... - - - 24 - only disarm uses this... - - - 25 - only disarm uses this... - - - 26 - only disarm uses this... - - - 27 - only disarm uses this... - - - 28 - only disarm uses this... - - - 29 - only disarm uses this... - - - 30 - only disarm uses this... - - - 31 - only disarm uses this... - - - 32 - only disarm uses this... - - - 33 - only disarm uses this... - - - 34 - - - 35 - - - 36 - - - 37 - - - 38 - - - 100 - - - - - - - Helicopter AutoROTation (AROT) information - - - Time since system startup - - - Landed Reason state flags - - - 1 - true if below 1 m/s - - - 2 - true if collective below land col min - - - 4 - passes inertial nav is_still() check - - - - - - - Helicopter AutoRotation Speed Controller (ARSC) information - - - Time since system startup - - - Desired forward velocity - - - Target forward velocity - - - Measured forward velocity - - - Velocity to acceleration P-term component - - - Velocity to acceleration I-term component - - - Velocity to acceleration D-term component - - - Velocity to acceleration feed forward component - - - Accel limit flag - - - Forward acceleration target - - - Lateral acceleration target - - - - - Airspeed sensor data - - - Time since system startup - - - Airspeed sensor instance number - - - Current airspeed - - - Pressure difference between static and dynamic port - - - Temperature used for calculation - - - Raw pressure less offset - - - Offset from parameter - - - True if sensor is being used - - - True if sensor is healthy - - - Probability sensor is healthy - - - innovation test ratio - - - Primary instance number. If equal to I then this sensor is primary sensor - - - - - AirSim simulation data - - - Time since system startup - - - Simulation's timestamp - - - Simulation's roll - - - Simulation's pitch - - - Simulation's yaw - - - Simulated gyroscope, X-axis - - - Simulated gyroscope, Y-axis - - - Simulated gyroscope, Z-axis - - - - - More AirSim simulation data - - - Time since system startup - - - simulation's acceleration, X-axis - - - simulation's acceleration, Y-axis - - - simulation's acceleration, Z-axis - - - simulation's velocity, X-axis - - - simulation's velocity, Y-axis - - - simulation's velocity, Z-axis - - - simulation's position, X-axis - - - simulation's position, Y-axis - - - simulation's position, Z-axis - - - simulation's gps altitude - - - simulation's earth-frame speed-down - - - - - AutoTune data packet - - - Time since system startup - - - current angle - - - current angular rate - - - - - Heli AutoTune data packet - - - Time since system startup - - - current motor command - - - current target angular rate - - - current angular rate - - - current target angle - - - current angle - - - - - Heli AutoTune - - - Time since system startup - - - which axis is currently being tuned - - - step in autotune process - - - target dwell frequency - - - measured gain of dwell - - - measured phase of dwell - - - new rate gain FF term - - - new rate gain P term - - - new rate gain D term - - - new angle P term - - - new max accel term - - - - - Scale factors for attitude controller - - - Time since system startup - - - Angle P scale X - - - Angle P scale Y - - - Angle P scale Z - - - PD scale X - - - PD scale Y - - - PD scale Z - - - I scale X - - - I scale Y - - - I scale Z - - - - - Heli AutoTune Sweep packet - - - Time since system startup - - - current frequency for motor input to rate - - - current response gain for motor input to rate - - - current response phase for motor input to rate - - - current frequency for target rate to rate - - - current response gain for target rate to rate - - - current response phase for target rate to rate - - - - - Canonical vehicle attitude - - - Time since system startup - - - vehicle desired roll - - - achieved vehicle roll - - - vehicle desired pitch - - - achieved vehicle pitch - - - vehicle desired yaw - - - achieved vehicle yaw - - - active EKF type - - - - - Copter/QuadPlane AutoTune - - - Time since system startup - - - which axis is currently being tuned - - - step in autotune process - - - target angle or rate, depending on tuning step - - - measured minimum target angle or rate - - - measured maximum target angle or rate - - - new rate gain P term - - - new rate gain D term - - - new angle P term - - - maximum measured twitching acceleration - - - - - Auxiliary function invocation information - - - Time since system startup - - - ID of triggered function - - - 0 - aux switch disabled - - - 2 - flip - - - 3 - change to simple mode - - - 4 - change to RTL flight mode - - - 5 - save current position as level - - - 7 - save mission waypoint or RTL if in auto mode - - - 9 - trigger camera servo or relay - - - 10 - allow enabling or disabling rangefinder in flight which helps avoid surface tracking when you are far above the ground - - - 11 - allow enabling or disabling fence in flight - - - 12 - UNUSED - - - 13 - change to simple mode in middle, super simple at top - - - 14 - low = disabled, middle = leveled, high = leveled and limited - - - 15 - enable/disable the crop sprayer - - - 16 - change to auto flight mode - - - 17 - auto tune - - - 18 - change to LAND flight mode - - - 19 - Operate cargo grippers low=off, middle=neutral, high=on - - - 21 - Parachute enable/disable - - - 22 - Parachute release - - - 23 - Parachute disable, enable, release with 3 position switch - - - 24 - Reset auto mission to start from first command - - - 25 - enable/disable the roll and pitch rate feed forward - - - 26 - enable/disable the roll, pitch and yaw accel limiting - - - 27 - Retract Mount1 - - - 28 - Relay pin on/off (only supports first relay) - - - 29 - Landing gear controller - - - 30 - Play lost vehicle sound - - - 31 - Emergency Stop Switch - - - 32 - Motor On/Off switch - - - 33 - Brake flight mode - - - 34 - Relay2 pin on/off - - - 35 - Relay3 pin on/off - - - 36 - Relay4 pin on/off - - - 37 - change to THROW flight mode - - - 38 - enable AP_Avoidance library - - - 39 - enable precision loiter - - - 40 - enable object avoidance using proximity sensors (ie. horizontal lidar) - - - 41 - UNUSED - - - 42 - change to SmartRTL flight mode - - - 43 - enable inverted flight - - - 44 - winch enable/disable - - - 45 - winch control - - - 46 - enable RC Override - - - 47 - user function #1 - - - 48 - user function #2 - - - 49 - user function #3 - - - 50 - learn cruise throttle (Rover) - - - 51 - manual mode - - - 52 - acro mode - - - 53 - steering mode - - - 54 - hold mode - - - 55 - guided mode - - - 56 - loiter mode - - - 57 - follow mode - - - 58 - clear waypoints - - - 59 - simple mode - - - 60 - zigzag mode - - - 61 - zigzag save waypoint - - - 62 - learn compass offsets - - - 63 - rover sailboat tack - - - 64 - reverse throttle input - - - 65 - disable GPS for testing - - - 66 - Relay5 pin on/off - - - 67 - Relay6 pin on/off - - - 68 - stabilize mode - - - 69 - poshold mode - - - 70 - althold mode - - - 71 - flowhold mode - - - 72 - circle mode - - - 73 - drift mode - - - 74 - Sailboat motoring 3pos - - - 75 - Surface tracking upwards or downwards - - - 76 - Standby mode - - - 77 - takeoff - - - 78 - control RunCam device - - - 79 - control RunCam OSD - - - 80 - align visual odometry camera's attitude to AHRS - - - 81 - disarm vehicle - - - 82 - disable, enable and force Q assist - - - 83 - zigzag auto switch - - - 84 - enable / disable airmode for copter - - - 85 - generator control - - - 86 - disable terrain following in CRUISE/FBWB modes - - - 87 - select CROW mode for diff spoilers;high disables,mid forces progressive - - - 88 - three-position switch to set soaring mode - - - 89 - force flare, throttle forced idle, pitch to LAND_PITCH_DEG, tilts up - - - 90 - change EKF data source set between primary, secondary and tertiary - - - 91 - calibrate airspeed ratio - - - 92 - Fly-By-Wire-A - - - 93 - used in separate branch MISSION_RELATIVE - - - 94 - VTX power level - - - 95 - enables FBWA taildragger takeoff mode. Once this feature is enabled it will stay enabled until the aircraft goes above TKOFF_TDRAG_SPD1 airspeed, changes mode, or the pitch goes above the initial pitch when this is engaged or goes below 0 pitch. When enabled the elevator will be forced to TKOFF_TDRAG_ELEV. This option allows for easier takeoffs on taildraggers in FBWA mode, and also makes it easier to test auto-takeoff steering handling in FBWA. - - - 96 - trigger re-reading of mode switch - - - 97 - flag for windvane direction offset input, used with windvane type 2 - - - 98 - mode training - - - 99 - AUTO RTL via DO_LAND_START - - - 100 - disable first IMU (for IMU failure testing) - - - 101 - disable second IMU (for IMU failure testing) - - - 102 - Momentary switch to cycle camera modes - - - 103 - trigger lane switch attempt - - - 104 - trigger yaw reset attempt - - - 105 - disable GPS yaw for testing - - - 106 - equivalent to AIRSPEED_USE 0 - - - 107 - fixed wing auto tune - - - 108 - QRTL mode - - - 109 - use Custom Controller - - - 110 - disable third IMU (for IMU failure testing) - - - 111 - allows for manually running starter - - - 112 - change AHRS_EKF_TYPE - - - 113 - Retract Mount2 - - - 150 - CRUISE mode - - - 151 - Turtle mode - flip over after crash - - - 152 - reset simple mode reference heading to current - - - 153 - arm or disarm vehicle - - - 154 - arm or disarm vehicle enabling airmode - - - 155 - trim to current servo and RC - - - 156 - clear torqeedo error - - - 157 - Force long FS action to FBWA for landing out of range - - - 158 - optical flow calibration - - - 159 - enable or disable land detection for GPS based manual modes preventing land detection and maintainting set_throttle_mix_max - - - 160 - enable/disable weathervaning - - - 161 - initialize turbine start sequence - - - 162 - FFT notch tuning function - - - 163 - Mount earth frame yaw lock forced on all axes, for all mounts - - - 164 - Pauses logging if under logging rate control - - - 165 - ARM on high, MOTOR_ESTOP on low - - - 166 - start recording on high, stop recording on low - - - 167 - camera zoom high = zoom in, middle = hold, low = zoom out - - - 168 - camera manual focus. high = long shot, middle = stop focus, low = close shot - - - 169 - camera auto focus - - - 170 - QuadPlane QStabilize mode - - - 171 - Calibrate compasses (disarmed only) - - - 172 - Battery MPPT Power enable. high = ON, mid = auto (controlled by mppt/batt driver), low = OFF. This effects all MPPTs. - - - 173 - Abort Glide-slope or VTOL landing during payload place or do_land type mission items - - - 174 - camera image tracking - - - 175 - camera lens selection - - - 176 - force enabled VTOL forward throttle method - - - 177 - mount LRF enable/disable - - - 178 - e.g. pause movement towards waypoint - - - 179 - AP_ICEngine start stop - - - 180 - auto tune tuning switch to test or revert gains - - - 181 - quicktune 3 position switch - - - 182 - in-flight AHRS autotrim - - - 183 - Fixed Wing AUTOLAND Mode - - - 184 - system ID as an aux switch - - - 185 - mount lock modes for roll and pitch axes, for all mounts that support it - - - 186 - Lock mount target to current ROI seen and switch mount to GPS Targeting mode - - - 201 - roll input - - - 202 - pitch input - - - 203 - throttle pilot input - - - 204 - yaw pilot input - - - 207 - mainsail input - - - 208 - flap input - - - 209 - VTOL manual forward throttle - - - 210 - manual airbrake control - - - 211 - walking robot height input - - - 212 - mount1 roll input - - - 213 - mount1 pitch input - - - 214 - mount1 yaw input - - - 215 - mount2 roll input - - - 216 - mount3 pitch input - - - 217 - mount4 yaw input - - - 218 - allows for throttle on slider - - - 219 - use a transmitter knob or slider for in-flight tuning - - - 220 - use another transmitter knob or slider for in-flight tuning - - - 300 - - - 301 - - - 302 - - - 303 - - - 304 - - - 305 - - - 306 - - - 307 - - - 308 - - - 309 - - - 310 - - - 311 - - - 312 - - - 313 - - - 314 - - - 315 - - - 316 - emergency scripting disablement - - - 317 - - - - - switch position when function triggered - - - 0 - indicates auxiliary switch is in the low position (pwm <1200) - - - 1 - indicates auxiliary switch is in the middle position (pwm >1200, <1800) - - - 2 - indicates auxiliary switch is in the high position (pwm >1800) - - - - - source of auxiliary function invocation - - - 0 - Source index is RC channel index - - - 1 - Source index is RC channel index - - - 2 - Source index is button index - - - 3 - Source index is MAVLink channel number - - - 4 - Source index is mission item index - - - 5 - Source index is not used (always 0) - - - - - index within source. 0 indexed. Invalid for scripting. - - - true if function was successful - - - - - Barometer dynamic data - - - Time since system startup - - - barometer sensor instance number - - - calculated dynamic pressure in the bodyframe X-axis - - - calculated dynamic pressure in the bodyframe Y-axis - - - calculated dynamic pressure in the bodyframe Z-axis - - - - - Gathered Barometer data - - - Time since system startup - - - barometer sensor instance number - - - calculated altitude - - - altitude AMSL - - - measured atmospheric pressure - - - measured atmospheric temperature - - - derived climb rate from primary barometer - - - time last sample was taken - - - raw adjustment of barometer altitude, zeroed on calibration, possibly set by GCS - - - temperature on ground, specified by parameter or measured while on ground - - - true if barometer is considered healthy - - - compensated atmospheric pressure - - - - - Gathered battery data - - - Time since system startup - - - battery instance number - - - measured voltage - - - estimated resting voltage - - - measured current - - - consumed Ah, current * time - - - consumed Wh, energy this battery has expended - - - measured temperature - - - estimated battery resistance - - - remaining percentage - - - health - - - state of health percentage. 0 if unknown - - - - - Battery cell voltage information - - - Time since system startup - - - battery instance number - - - battery voltage - - - first cell voltage - - - second cell voltage - - - third cell voltage - - - fourth cell voltage - - - fifth cell voltage - - - sixth cell voltage - - - seventh cell voltage - - - eighth cell voltage - - - ninth cell voltage - - - tenth cell voltage - - - eleventh cell voltage - - - twelfth cell voltage - - - - - Battery cell voltage information - - - Time since system startup - - - battery instance number - - - thirteenth cell voltage - - - fourteenth cell voltage - - - - - Beacon information - - - Time since system startup - - - True if beacon sensor is healthy - - - Number of beacons being used - - - Distance to first beacon - - - Distance to second beacon - - - Distance to third beacon - - - Distance to fourth beacon - - - Calculated beacon position, x-axis - - - Calculated beacon position, y-axis - - - Calculated beacon position, z-axis - - - - - CANFD Frame - - - Time since system startup - - - bus number - - - frame identifier - - - data length code - - - data 0 - - - data 1 - - - data 2 - - - data 3 - - - data 4 - - - data 5 - - - data 6 - - - data 7 - - - - - Camera shutter information - - - Time since system startup - - - Instance number - - - Image number - - - milliseconds since start of GPS week - - - weeks since 5 Jan 1980 - - - current latitude - - - current longitude - - - current altitude - - - current altitude relative to home - - - altitude as reported by GPS - - - current vehicle roll - - - current vehicle pitch - - - current vehicle yaw - - - - - Info from GetNodeInfo request - - - Time since system startup - - - Driver index - - - Node ID - - - Hardware ID, part 1 - - - Hardware ID, part 2 - - - Name string - - - major revision id - - - minor revision id - - - AP_Periph git hash - - - - - CAN Frame - - - Time since system startup - - - bus number - - - frame identifier - - - data length code - - - byte 0 - - - byte 1 - - - byte 2 - - - byte 3 - - - byte 4 - - - byte 5 - - - byte 6 - - - byte 7 - - - - - CAN Bus Statistics - - - Time since system startup - - - driver index - - - transmit success count - - - transmit request count - - - transmit reject count - - - transmit overflow count - - - transmit timeout count - - - transmit abort count - - - receive count - - - receive overflow count - - - receive error count - - - bus offset error count - - - ESC successful send count - - - Servo successful send count - - - ESC/Servo failed-to-send count - - - - - Custom Controller data - - - Time since system startup - - - controller type - - - 0 - - - 1 - - - 2 - - - - - true if controller is active - - - - - Uploaded mission command information - - - Time since system startup - - - Total number of mission commands - - - This command's offset in mission - - - Command type - - - Parameter 1 - - - Parameter 2 - - - Parameter 3 - - - Parameter 4 - - - Command latitude - - - Command longitude - - - Command altitude - - - Frame used for position - - - - - Servo feedback data - - - Time since system startup - - - Servo number this data relates to - - - Current servo position - - - Force being applied - - - Current servo movement speed - - - Amount of rated power being applied - - - commanded servo position - - - Voltage - - - Current - - - motor temperature - - - PCB temperature - - - error flags - - - - - Control Tuning information - - - Time since system startup - - - throttle input - - - angle boost - - - throttle output - - - calculated hover throttle - - - desired altitude - - - achieved altitude - - - barometric altitude - - - desired rangefinder altitude - - - achieved rangefinder altitude - - - terrain altitude - - - desired climb rate - - - climb rate - - - - - Generic 16-bit-signed-integer storage - - - Time since system startup - - - Data type identifier - - - Value - - - - - Generic 32-bit-signed-integer storage - - - Time since system startup - - - Data type identifier - - - Value - - - - - DCM Estimator Data - - - Time since system startup - - - estimated roll - - - estimated pitch - - - estimated yaw - - - lowest estimated gyro drift error - - - difference between measured yaw and DCM yaw estimate - - - wind velocity, to-the-North component - - - wind velocity, to-the-East component - - - wind velocity, Up-to-Down component - - - synthetic (equivalent) airspeed - - - - - Generic float storage - - - Time since system startup - - - Data type identifier - - - Value - - - - - DataFlash-Over-MAVLink statistics - - - Time since system startup - - - Current block number - - - Number of times we rejected a write to the backend - - - Number of blocks sent from the retry queue - - - Number of resends of unacknowledged data made - - - Average number of blocks on the free list - - - Minimum number of blocks on the free list - - - Maximum number of blocks on the free list - - - Average number of blocks on the pending list - - - Minimum number of blocks on the pending list - - - Maximum number of blocks on the pending list - - - Average number of blocks on the sent list - - - Minimum number of blocks on the sent list - - - Maximum number of blocks on the sent list - - - - - Onboard logging statistics - - - Time since system startup - - - Number of times we rejected a write to the backend - - - Current block number - - - Current write offset - - - Minimum free space in write buffer in last time period - - - Maximum free space in write buffer in last time period - - - Average free space in write buffer in last time period - - - - - Deepstall Landing data - - - Time since system startup - - - Deepstall landing stage - - - Target heading - - - Landing point latitude - - - Landing point longitude - - - Landing point altitude - - - Crosstrack error - - - Expected travel distance vehicle will travel from this point - - - L1 controller crosstrack integrator value - - - wind estimate loiter angle flown - - - Deepstall steering PID desired value - - - Deepstall steering PID Proportional response component - - - Deepstall steering PID Integral response component - - - Deepstall steering PID Derivative response component - - - - - Generic 16-bit-unsigned-integer storage - - - Time since system startup - - - Data type identifier - - - Value - - - - - Generic 32-bit-unsigned-integer storage - - - Time since system startup - - - Data type identifier - - - Value - - - - - External AHRS data - - - Time since system startup - - - euler roll - - - euler pitch - - - euler yaw - - - velocity north - - - velocity east - - - velocity down - - - latitude - - - longitude - - - altitude AMSL - - - nav status flags - - - - - External AHRS variances - - - Time since system startup - - - velocity variance - - - position variance - - - height variance - - - magnetic variance, X - - - magnetic variance, Y - - - magnetic variance, Z - - - true airspeed variance - - - - - EFI per-cylinder information - - - Time since system startup - - - Cylinder this data belongs to - - - Ignition timing - - - Injection time - - - Cylinder head temperature - - - Exhaust gas temperature - - - Estimated lambda coefficient (dimensionless ratio) - - - Cylinder2 head temperature - - - Cylinder2 Exhaust gas temperature - - - Index of the publishing ECU - - - - - Status received from ESCs via Extended DShot telemetry v2 - - - microseconds since system startup - - - ESC instance number - - - current stress level (commutation effort), scaled to [0..255] - - - maximum stress level (commutation effort) since arming, scaled to [0..15] - - - status bits - - - 1 - true if the message contains up-to-date stress data - - - 2 - true if the message contains up-to-date status data - - - 4 - true if the last status had the "alert" bit (e.g. demag) - - - 8 - true if the last status had the "warning" bit (e.g. desync) - - - 16 - true if the last status had the "error" bit (e.g. stall) - - - - - - - Electronic Fuel Injection system data - - - Time since system startup - - - Reported engine load - - - Reported engine RPM - - - Spark Dwell Time - - - Atmospheric pressure - - - Intake manifold pressure - - - Intake manifold temperature - - - Engine Coolant Temperature - - - Oil Pressure - - - Oil temperature - - - Fuel Pressure - - - Fuel Consumption Rate - - - Consumed fuel volume - - - Throttle Position - - - Index of the publishing ECU - - - - - Electronic Fuel Injection system data - redux - - - Time since system startup - - - True if EFI is healthy - - - Engine state - - - General error - - - Crankshaft sensor status - - - Temperature status - - - Fuel pressure status - - - Oil pressure status - - - Detonation status - - - Misfire status - - - Debris status - - - Spark plug usage - - - Index of the publishing ECU - - - - - Electronic Fuel Injection data - Hirth specific Status information - - - Time since system startup - - - Error Excess Temperature Bitfield - - - 1 - true if CHT1 is too low - - - 2 - true if CHT1 is too high - - - 4 - true if CHT1 Enrichment is active - - - 8 - true if CHT2 is too low - - - 16 - true if CHT2 is too high - - - 32 - true if CHT2 Enrichment is active - - - 64 - true if EGT1 is too low - - - 128 - true if EGT1 is too high - - - 256 - true if EGT1 Enrichment is active - - - 512 - true if EGT2 is too low - - - 1024 - true if EGT2 is too high - - - 2048 - true if EGT2 Enrichment is active - - - - - Sensor Status Bitfield - - - 2 - true if engine temperature sensor is OK - - - 4 - true if air temperature sensor is OK - - - 8 - true if intake air pressure sensor is OK - - - 16 - true if throttle sensor is OK - - - - - CRC failure count - - - ACK failure count - - - Uptime between 2 messages - - - Throttle output as received by the engine - - - Modified throttle_to_hirth output sent to the engine - - - - - Specifically coded error messages - - - Time since system startup - - - Subsystem in which the error occurred - - - 1 - - - 2 - - - 3 - - - 4 - not used - - - 5 - - - 6 - - - 7 - not used - - - 8 - - - 9 - - - 10 - - - 11 - - - 12 - - - 13 - - - 14 - not used - - - 15 - - - 16 - - - 17 - - - 18 - - - 19 - - - 20 - - - 21 - - - 22 - - - 23 - - - 24 - - - 25 - - - 26 - - - 27 - - - 28 - - - 29 - - - 30 - - - 31 - - - - - Subsystem-specific error code - - - - - Feedback received from ESCs - - - microseconds since system startup - - - ESC instance number - - - reported motor rotation rate - - - reported motor rotation rate without slew adjustment - - - Perceived input voltage for the ESC - - - Perceived current through the ESC - - - ESC temperature in centi-degrees C - - - current consumed total mAh - - - measured motor temperature in centi-degrees C - - - error rate - - - - - ESC extended telemetry data - - - Time since system startup - - - starts from 0 - - - input duty cycle in percent - - - output duty cycle in percent - - - manufacturer-specific status flags - - - Power percentage - - - - - Specifically coded event messages - - - Time since system startup - - - Event identifier - - - 10 - - - 11 - - - 15 - - - 17 - - - 18 - - - 19 - - - 21 - - - 22 - - - 25 - - - 26 - - - 27 - - - 28 - - - 29 - - - 30 - - - 31 - - - 32 - - - 33 - - - 34 - - - 35 - - - 36 - - - 37 - - - 38 - - - 39 - - - 41 - - - 42 - - - 43 - - - 44 - - - 45 - - - 46 - - - 47 - - - 49 - - - 50 - - - 51 - - - 52 - - - 53 - - - 54 - - - 55 - - - 56 - - - 57 - - - 58 - Heli only - - - 59 - Heli only - - - 60 - - - 61 - - - 62 - - - 63 - - - 64 - - - 65 - - - 66 - - - 67 - - - 71 - - - 72 - - - 73 - - - 74 - - - 75 - - - 76 - - - 77 - - - 78 - - - 79 - - - 80 - - - 81 - - - 82 - - - 83 - - - 85 - - - 86 - - - 87 - - - 90 - - - 163 - - - 164 - - - 165 - - - 166 - - - - - - - Filter Center Message - per motor - - - microseconds since system startup - - - instance - - - total number of active harmonic notches - - - First harmonic centre frequency for motor 1 - - - First harmonic centre frequency for motor 2 - - - First harmonic centre frequency for motor 3 - - - First harmonic centre frequency for motor 4 - - - First harmonic centre frequency for motor 5 - - - First harmonic centre frequency for motor 6 - - - Second harmonic centre frequency for motor 1 - - - Second harmonic centre frequency for motor 2 - - - Second harmonic centre frequency for motor 3 - - - Second harmonic centre frequency for motor 4 - - - Second harmonic centre frequency for motor 5 - - - Second harmonic centre frequency for motor 6 - - - - - Filter Center Message - - - microseconds since system startup - - - instance - - - notch centre frequency - - - 2nd harmonic frequency - - - - - Fence status - development diagnostic message - - - Time since system startup - - - bitmask of enabled fences - - - bitmask of automatically enabled fences - - - bitmask of configured-in-parameters fences - - - bitmask of enabled fences - - - bitmask of currently disabled fences - - - current vehicle altitude - - - - - https://ardupilot.org/copter/docs/flowhold-mode.html - FlowHold mode messages - - - Time since system startup - - - Filtered flow rate, X-Axis - - - Filtered flow rate, Y-Axis - - - Target lean angle, X-Axis - - - Target lean angle, Y-Axis - - - Flow sensor quality. If this value falls below FHLD_QUAL_MIN parameter, FlowHold will act just like AltHold. - - - Integral part of PI controller, X-Axis - - - Integral part of PI controller, Y-Axis - - - - - Height estimation using optical flow sensor - - - Time since system startup - - - Delta flow rate, X-Axis - - - Delta flow rate, Y-Axis - - - Integrated delta velocity rate, X-Axis - - - Integrated delta velocity rate, Y-Axis - - - Estimated Height - - - Delta Height - - - Height offset - - - Height estimate from inertial navigation library - - - Last used INS height in optical flow sensor height estimation calculations - - - Time between optical flow sensor updates. This should be less than 500ms for performing the height estimation calculations - - - - - File data - - - File name - - - Offset into the file of this block - - - Length of this data block - - - File data of this block - - - - - https://ardupilot.org/dev/docs/code-overview-adding-a-new-log-message.html - Message defining the format of messages in this file - - - unique-to-this-log identifier for message being defined - - - the number of bytes taken up by this message (including all headers) - - - name of the message being defined - - - character string defining the C-storage-type of the fields in this message - - - the labels of the message being defined - - - - - Message defining units and multipliers used for fields of other messages - - - Time since system startup - - - numeric reference to associated FMT message - - - each character refers to a UNIT message. The unit at an offset corresponds to the field at the same offset in FMT.Format - - - each character refers to a MULT message. The multiplier at an offset corresponds to the field at the same offset in FMT.Format - - - - - currently loaded Geo Fence points - - - Time since system startup - - - total number of stored items - - - index in current sequence - - - point type - - - point latitude - - - point longitude - - - vertex cound in polygon if applicable - - - radius of circle if applicable - - - - - Follow library diagnostic data - - - Time since system startup (microseconds) - - - Target latitude (degrees * 1E7) - - - Target longitude (degrees * 1E7) - - - Target absolute altitude (centimeters) - - - Target velocity, North (m/s) - - - Target velocity, East (m/s) - - - Target velocity, Down (m/s) - - - Vehicle estimated latitude (degrees * 1E7) - - - Vehicle estimated longitude (degrees * 1E7) - - - Vehicle estimated altitude (centimeters) - - - Vehicle estimated altitude Frame - - - - - Filter Tuning Message - per motor - - - microseconds since system startup - - - instance - - - number of active harmonic notches - - - desired harmonic notch centre frequency for motor 1 - - - desired harmonic notch centre frequency for motor 2 - - - desired harmonic notch centre frequency for motor 3 - - - desired harmonic notch centre frequency for motor 4 - - - desired harmonic notch centre frequency for motor 5 - - - desired harmonic notch centre frequency for motor 6 - - - desired harmonic notch centre frequency for motor 7 - - - desired harmonic notch centre frequency for motor 8 - - - desired harmonic notch centre frequency for motor 9 - - - desired harmonic notch centre frequency for motor 10 - - - desired harmonic notch centre frequency for motor 11 - - - desired harmonic notch centre frequency for motor 12 - - - - - FFT Filter Tuning - - - microseconds since system startup - - - peak noise frequency as an energy-weighted average of roll and pitch peak frequencies - - - bandwidth of weighted peak frequency where edges are determined by FFT_ATT_REF - - - signal-to-noise ratio on the roll axis - - - signal-to-noise ratio on the pitch axis - - - signal-to-noise ratio on the yaw axis - - - harmonic fit on roll of the highest noise peak to the second highest noise peak - - - harmonic fit on pitch of the highest noise peak to the second highest noise peak - - - harmonic fit on yaw of the highest noise peak to the second highest noise peak - - - FFT health, X-axis - - - FFT health, Y-axis - - - FFT health, Z-axis - - - FFT cycle time - - - - - FFT Noise Frequency Peak - - - microseconds since system startup - - - peak id where 0 is the centre peak, 1 is the lower shoulder and 2 is the upper shoulder - - - noise frequency of the peak on roll - - - noise frequency of the peak on pitch - - - noise frequency of the peak on yaw - - - bandwidth of the peak frequency on roll where edges are determined by FFT_ATT_REF - - - bandwidth of the peak frequency on pitch where edges are determined by FFT_ATT_REF - - - bandwidth of the peak frequency on yaw where edges are determined by FFT_ATT_REF - - - signal-to-noise ratio on the roll axis - - - signal-to-noise ratio on the pitch axis - - - signal-to-noise ratio on the yaw axis - - - power spectral density bin energy of the peak on roll - - - power spectral density bin energy of the peak on roll - - - power spectral density bin energy of the peak on roll - - - - - Additional FFT Noise Frequency Peak - - - microseconds since system startup - - - update axis - - - Peak 1 frequency - - - Peak 2 frequency - - - Peak 3 Frequency - - - Peak 1 noise bandwidth - - - Peak 2 noise bandwidth - - - Peak 3 noise bandwidth - - - Peak 1 Maximum energy - - - Peak 2 Maximum energy - - - Peak 3 Maximum energy - - - - - Filter Tuning Message - - - microseconds since system startup - - - instance - - - desired harmonic notch centre frequency - - - - - Simulated Glider Angles and coefficients - - - Time since system startup - - - alpha angle - - - beta angle - - - lift coefficent - - - roll coffecient - - - yaw coefficient - - - - - Solo Gimbal measurements - - - Time since system startup - - - sum of time across measurements in this packet - - - delta-angle sum, x-axis - - - delta-angle sum, y-axis - - - delta-angle sum, z-axis - - - delta-velocity sum, x-axis - - - delta-velocity sum, y-axis - - - delta-velocity sum, z-axis - - - joint angle, x - - - joint angle, y - - - joint angle, z - - - - - Solo Gimbal estimation and demands - - - Time since system startup - - - Solo Gimbal EKF status bits - - - Solo Gimbal EKF estimate of gimbal angle, x-axis - - - Solo Gimbal EKF estimate of gimbal angle, y-axis - - - Solo Gimbal EKF estimate of gimbal angle, y-axis - - - Angular velocity demand around x-axis - - - Angular velocity demand around y-axis - - - Angular velocity demand around z-axis - - - Angular position target around x-axis - - - Angular position target around y-axis - - - Angular position target around z-axis - - - - - GPS accuracy information - - - Time since system startup - - - GPS instance number - - - vertical dilution of precision - - - horizontal position accuracy - - - vertical position accuracy - - - speed accuracy - - - yaw accuracy - - - true if vertical velocity is available - - - time since system startup this sample was taken - - - system time delta between the last two reported positions - - - altitude above WGS-84 ellipsoid; INT32_MIN (-2147483648) if unknown - - - RTCM fragments used - - - RTCM fragments discarded - - - - - Information received from GNSS systems attached to the autopilot - - - Time since system startup - - - GPS instance number - - - GPS Fix type; 2D fix, 3D fix etc. - - - 0 - No GPS connected/detected - - - 1 - Receiving valid GPS messages but no lock - - - 2 - Receiving valid messages and 2D lock - - - 3 - Receiving valid messages and 3D lock - - - 4 - Receiving valid messages and 3D lock with differential improvements - - - 5 - Receiving valid messages and 3D RTK Float - - - 6 - Receiving valid messages and 3D RTK Fixed - - - - - milliseconds since start of GPS Week - - - weeks since 5 Jan 1980 - - - number of satellites visible - - - horizontal dilution of precision - - - latitude - - - longitude - - - altitude - - - ground speed - - - ground course - - - vertical speed - - - vehicle yaw - - - boolean value indicating whether this GPS is in use - - - - - GPS Yaw - - - Time since system startup - - - instance - - - reported heading,deg - - - antenna separation,m - - - vertical antenna separation,m - - - minimum tolerable vertical antenna separation,m - - - maximum tolerable vertical antenna separation,m - - - 1 if have yaw - - - - - Raw uBlox data - - - Time since system startup - - - receiver TimeOfWeek measurement - - - GPS week - - - number of space vehicles seen - - - space vehicle number of first vehicle - - - carrier phase measurement - - - pseudorange measurement - - - Doppler measurement - - - measurement quality index - - - carrier-to-noise density ratio - - - loss of lock indicator - - - - - Raw uBlox data - header - - - Time since system startup - - - receiver TimeOfWeek measurement - - - GPS week - - - GPS leap seconds - - - number of space-vehicle measurements to follow - - - receiver tracking status bitfield - - - - - Raw uBlox data - space-vehicle data - - - Time since system startup - - - Pseudorange measurement - - - Carrier phase measurement - - - Doppler measurement - - - GNSS identifier - - - Satellite identifier - - - GLONASS frequency slot - - - carrier phase locktime counter - - - carrier-to-noise density ratio - - - estimated pseudorange measurement standard deviation - - - estimated carrier phase measurement standard deviation - - - estimated Doppler measurement standard deviation - - - tracking status bitfield - - - - - Guided mode attitude target information - - - Time since system startup - - - Type of guided mode - - - Target attitude, Roll - - - Target attitude, Pitch - - - Target attitude, Yaw - - - Roll rate - - - Pitch rate - - - Yaw rate - - - Thrust - - - Climb rate - - - - - Guided mode position target information - - - Time since system startup - - - Type of guided mode - - - Target position, X-Axis - - - Target position, Y-Axis - - - Target position, Z-Axis - - - Target position, Z-Axis is alt above terrain - - - Target velocity, X-Axis - - - Target velocity, Y-Axis - - - Target velocity, Z-Axis - - - Target acceleration, X-Axis - - - Target acceleration, Y-Axis - - - Target acceleration, Z-Axis - - - - - IMU gyroscope data - - - Time since system startup - - - gyroscope sensor instance number - - - time since system startup this sample was taken - - - measured rotation rate about X axis - - - measured rotation rate about Y axis - - - measured rotation rate about Z axis - - - - - IMU Heater data - - - Time since system startup - - - Current IMU temperature - - - Target IMU temperature - - - Proportional portion of response - - - Integral portion of response - - - Controller output to heating element - - - - - Helicopter related messages - - - Time since system startup - - - Instance, 0=Main, 1=Tail - - - Desired rotor speed - - - Estimated rotor speed - - - Governor Output - - - Throttle output - - - throttle ramp up - - - RSC state - - - - - Hygrometer data - - - Time since system startup - - - sensor ID - - - percentage humidity - - - temperature in degrees C - - - - - ICM20789 diagnostics - - - Time since system startup - - - raw temperature from sensor - - - raw pressure from sensor - - - pressure - - - temperature - - - - - https://ardupilot.org/copter/docs/common-ie24-fuelcell.html - Intelligent Energy Fuel Cell generator (legacy protocol) - - - Time since system startup - - - Fuel remaining - - - stack power module power draw - - - output power - - - error codes - - - 1 - Minor internal error is to be ignored - - - 10 - - - 11 - - - 20 - - - 21 - - - 30 - - - 31 - - - 32 - - - 33 - - - 40 - - - - - - - https://ardupilot.org/copter/docs/common-ie24-fuelcell.html - Intelligent Energy Fuel Cell generator - - - Time since system startup - - - Fuel remaining - - - Inlet pressure - - - battery voltage - - - output power - - - stack power module power draw - - - fault number - - - battery power draw - - - generator state - - - 0 - - - 1 - - - 2 - - - 3 - - - 4 - - - - - error code - - - 1 - Minor internal error is to be ignored - - - 10 - - - 11 - - - 20 - - - 21 - - - 30 - - - 31 - - - 32 - - - 33 - - - 40 - - - - - sub-error code - - - - - InertialLabs AHRS data1 - - - Time since system startup - - - GPS INS time (round) - - - Gyro X - - - Gyro Y - - - Gyro z - - - Accelerometer X - - - Accelerometer Y - - - Accelerometer Z - - - - - InertialLabs AHRS data2 - - - Time since system startup - - - GPS INS time (round) - - - Magnetometer X - - - Magnetometer Y - - - Magnetometer Z - - - - - InertialLabs AHRS data3 - - - Time since system startup - - - GPS INS time (round) - - - Static pressure - - - Differential pressure - - - Temperature - - - Baro altitude - - - true airspeed - - - Wind velocity north - - - Wind velocity east - - - Wind velocity down - - - Air Data Unit status - - - - - InertialLabs AHRS data4 - - - Time since system startup - - - GNSS Position timestamp - - - GPS Week - - - Number of satellites - - - Indicator of new update of GPS data - - - GNSS Latitude - - - GNSS Longitude - - - GNSS Altitude - - - GNSS Track over ground - - - GNSS Horizontal speed - - - GNSS Vertical speed - - - - - InertialLabs AHRS data5 - - - Time since system startup - - - GNSS Position timestamp - - - fix type - - - GNSS spoofing status - - - GNSS jamming status - - - GNSS Info1 - - - GNSS Info2 - - - GNSS Angles position type - - - - - InertialLabs AHRS data6 - - - Time since system startup - - - GNSS Position timestamp - - - GNSS Heading timestamp - - - GNSS Heading - - - GNSS Pitch - - - GNSS GDOP - - - GNSS PDOP - - - GNSS HDOP - - - GNSS VDOP - - - GNSS TDOP - - - - - InertialLabs AHRS data7 - - - Time since system startup - - - GPS INS time (round) - - - euler roll - - - euler pitch - - - euler yaw - - - velocity north - - - velocity east - - - velocity down - - - latitude - - - longitude - - - altitude MSL - - - USW1 - - - USW2 - - - Supply voltage - - - - - InertialLabs AHRS data8 - - - Time since system startup - - - GPS INS time (round) - - - position variance north - - - position variance east - - - position variance down - - - velocity variance north - - - velocity variance east - - - velocity variance down - - - - - Inertial Measurement Unit data - - - Time since system startup - - - IMU sensor instance number - - - measured rotation rate about X axis - - - measured rotation rate about Y axis - - - measured rotation rate about Z axis - - - acceleration along X axis - - - acceleration along Y axis - - - acceleration along Z axis - - - gyroscope error count - - - accelerometer error count - - - IMU temperature - - - gyroscope health - - - accelerometer health - - - gyroscope measurement rate - - - accelerometer measurement rate - - - - - IOMCU diagnostic information - - - Time since system startup - - - Status Read error count (zeroed on successful read) - - - Free memory - - - IOMCU uptime - - - Number of packets received by IOMCU - - - Protocol failures on MCU side - - - Reported number of failures on IOMCU side - - - Number of delayed packets received by MCU - - - - - IMU Register unexpected value change - - - Time since system startup - - - bus ID - - - device register bank - - - device register - - - unexpected value - - - - - InertialSensor Batch Logging Data - - - Time since system startup - - - batch sequence number - - - sample sequence number - - - x-axis sample value - - - y-axis sample value - - - z-axis sample value - - - - - InertialSensor Batch Logging Header - - - Time since system startup - - - batch sequence number - - - indicates if this is accel or gyro data - - - IMU sensor instance - - - multiplier to be applied to samples in this batch - - - samples in this batch - - - timestamp of first sample - - - rate at which samples have been collected - - - - - Log data received from JSON simulator - - - Time since system startup (us) - - - Simulation's timestamp (s) - - - Simulation's roll (rad) - - - Simulation's pitch (rad) - - - Simulation's yaw (rad) - - - Simulated gyroscope, X-axis (rad/sec) - - - Simulated gyroscope, Y-axis (rad/sec) - - - Simulated gyroscope, Z-axis (rad/sec) - - - - - Log data received from JSON simulator - - - Time since system startup (us) - - - simulation's velocity, North-axis (m/s) - - - simulation's velocity, East-axis (m/s) - - - simulation's velocity, Down-axis (m/s) - - - simulation's acceleration, X-axis (m/s^2) - - - simulation's acceleration, Y-axis (m/s^2) - - - simulation's acceleration, Z-axis (m/s^2) - - - simulation's acceleration, North (m/s^2) - - - simulation's acceleration, East (m/s^2) - - - simulation's acceleration, Down (m/s^2) - - - - - Slope Landing data - - - Time since system startup - - - progress through landing sequence - - - Landing flags - - - Slope-specific landing flags - - - Slope to landing point - - - Initial slope to landing point - - - Rangefinder correction - - - Height for flare timing. - - - - - Land Detector State - - - Time since system startup - - - boolean state flags - - - 1 - - - 2 - - - 4 - - - 8 - - - 16 - - - 32 - - - 64 - - - 128 - - - 256 - - - 256 - - - 512 - - - 1024 - - - - - landing_detector pass count - - - - - Landing gear information - - - Time since system startup - - - Current landing gear state - - - -1 - - - 0 - - - 1 - - - 2 - - - 3 - - - - - Weight on wheels state - - - -1 - - - 0 - - - 1 - - - - - - - Gathered Loweheiser EFI/Governor telemetry - - - Time since system startup - - - target system ID - - - target component ID - - - command - - - efi index - - - desired engine state (0:EFI off 1:EFI on) - - - desired governor state (0:Governor off 1:Governor on) - - - manual throttle value - - - desired electric start - - - - - Gathered Loweheiser EFI/Governor telemetry - - - Time since system startup - - - EFI/Gov sensor instance number - - - battery voltage - - - battery current - - - generator current - - - throttle input - - - EFI battery voltage - - - generator RPM - - - EFI pulse-width - - - fuel flow - - - fuel consumed - - - EFI pressure - - - EFI manifold air temperature - - - cylinder head temperature - - - throttle position sensor - - - - - Information received from compasses - - - Time since system startup - - - magnetometer sensor instance number - - - magnetic field strength in body frame - - - magnetic field strength in body frame - - - magnetic field strength in body frame - - - magnetic field offset in body frame - - - magnetic field offset in body frame - - - magnetic field offset in body frame - - - motor interference magnetic field offset in body frame - - - motor interference magnetic field offset in body frame - - - motor interference magnetic field offset in body frame - - - true if the compass is considered healthy - - - time measurement was taken - - - - - Magnetometer high resolution data - - - Time since system startup - - - CAN node - - - sensor ID on node - - - CAN bus - - - X axis field - - - y axis field - - - z axis field - - - - - GCS MAVLink link statistics - - - Time since system startup - - - mavlink channel number - - - transmitted packet count - - - received packet count - - - perceived number of packets we never received - - - compact representation of some state of the channel - - - 1 - - - 2 - - - 4 - - - 8 - - - 16 - - - - - stream slowdown is the number of ms being added to each message to fit within bandwidth - - - times buffer was full when a message was going to be sent - - - time MAV_GCS_SYSID heartbeat (or manual control) last seen - - - - - MAVLink command we have just executed - - - Time since system startup - - - target system for command - - - target component for command - - - source system for command - - - source component for command - - - command frame - - - mavlink command enum value - - - first parameter from mavlink packet - - - second parameter from mavlink packet - - - third parameter from mavlink packet - - - fourth parameter from mavlink packet - - - X coordinate from mavlink packet - - - Y coordinate from mavlink packet - - - Z coordinate from mavlink packet - - - command result being returned from autopilot - - - true if this command arrived via a COMMAND_LONG rather than COMMAND_INT - - - - - MCU voltage and temprature monitering - - - Time since system startup - - - Temperature - - - Voltage - - - Voltage min - - - Voltage max - - - - - Executed mission command information; emitted when we start to run an item - - - Time since system startup - - - Total number of mission commands - - - This command's offset in mission - - - Command type - - - Parameter 1 - - - Parameter 2 - - - Parameter 3 - - - Parameter 4 - - - Command latitude - - - Command longitude - - - Command altitude - - - Frame used for position - - - - - MMC3416 compass data - - - Time since system startup - - - new measurement X axis - - - new measurement Y axis - - - new measurement Z axis - - - new offset X axis - - - new offset Y axis - - - new offset Z axis - - - - - Mount's desired and actual roll, pitch and yaw angles - - - Time since system startup - - - Instance number - - - Mount mode - - - Desired roll - - - Actual roll - - - Desired pitch - - - Actual pitch - - - Desired yaw in body frame - - - Actual yaw in body frame - - - Desired yaw in earth frame - - - Actual yaw in earth frame - - - Rangefinder distance - - - - - vehicle control mode information - - - Time since system startup - - - vehicle-specific mode number - - - alias for Mode - - - reason for entering this mode; enumeration value - - - 0 - - - 1 - - - 2 - - - 3 - - - 4 - - - 5 - - - 6 - - - 7 - - - 8 - - - 9 - - - 10 - - - 11 - - - 12 - - - 13 - - - 14 - - - 15 - - - 16 - - - 17 - - - 18 - - - 19 - - - 20 - - - 21 - - - 22 - - - 23 - - - 24 - - - 25 - general failsafes, prefer specific failsafes over this as much as possible - - - 26 - - - 27 - - - 28 - - - 29 - - - 30 - - - 31 - - - 32 - - - 33 - - - 34 - - - 35 - - - 36 - - - 37 - - - 38 - - - 39 - - - 40 - - - 41 - - - 42 - - - 43 - - - 44 - - - 45 - - - 46 - - - 47 - - - 48 - - - 49 - - - 50 - - - 51 - - - 52 - - - 53 - - - 54 - - - 55 - - - - - - - Main loop performance monitoring message. - - - Time since system startup - - - Loop delay so far - - - Current task - - - Internal error mask - - - Count of internal error occurances - - - Internal Error line - - - MAVLink message currently being processed - - - MAVLink command currently being processed - - - If semaphore taken, line of semaphore take call - - - count of SPI transactions - - - count of i2c transactions - - - - - Motor mixer information - - - Time since system startup - - - Maximum motor compensation gain - - - Ratio between detected battery voltage and maximum battery voltage - - - Throttle limit set due to battery current limitations - - - Maximum average throttle that can be used to maintain attitude control, derived from throttle mix params - - - Throttle output - - - bit 0 motor failed, bit 1 motors balanced, should be 2 in normal flight - - - - - Textual messages - - - Time since system startup - - - identifier for chunks making up a message - - - chunk sequence number within message identified by ID - - - message text - - - - - Message mapping from single character to numeric multiplier - - - Time since system startup - - - character referenced by FMTU - - - numeric multiplier - - - - - EKF2 beacon sensor diagnostics - - - Time since system startup - - - EKF2 core this data is for - - - Beacon sensor ID - - - Beacon range - - - Beacon range innovation - - - sqrt of beacon range innovation variance - - - Beacon range innovation consistency test ratio - - - Beacon north position - - - Beacon east position - - - Beacon down position - - - High estimate of vertical position offset of beacons rel to EKF origin - - - Low estimate of vertical position offset of beacons rel to EKF origin - - - always zero - - - always zero - - - always zero - - - - - EKF2 estimator outputs - - - Time since system startup - - - EKF2 core this data is for - - - Estimated roll - - - Estimated pitch - - - Estimated yaw - - - Estimated velocity (North component) - - - Estimated velocity (East component) - - - Estimated velocity (Down component) - - - Filtered derivative of vertical position (down) - - - Estimated distance from origin (North component) - - - Estimated distance from origin (East component) - - - Estimated distance from origin (Down component) - - - Estimated gyro bias, X axis - - - Estimated gyro bias, Y axis - - - Estimated gyro bias, Z axis - - - Height of origin above WGS-84 - - - - - EKF2 estimator secondary outputs - - - Time since system startup - - - EKF2 core this data is for - - - Estimated accelerometer Z bias - - - Gyro Scale Factor (X-axis) - - - Gyro Scale Factor (Y-axis) - - - Gyro Scale Factor (Z-axis) - - - Estimated wind velocity (moving-to-North component) - - - Estimated wind velocity (moving-to-East component) - - - Magnetic field strength (North component) - - - Magnetic field strength (East component) - - - Magnetic field strength (Down component) - - - Magnetic field strength (body X-axis) - - - Magnetic field strength (body Y-axis) - - - Magnetic field strength (body Z-axis) - - - Magnetometer used for data - - - - - EKF2 innovations - - - Time since system startup - - - EKF2 core this data is for - - - Innovation in velocity (North component) - - - Innovation in velocity (East component) - - - Innovation in velocity (Down component) - - - Innovation in position (North component) - - - Innovation in position (East component) - - - Innovation in position (Down component) - - - Innovation in magnetic field strength (X-axis component) - - - Innovation in magnetic field strength (Y-axis component) - - - Innovation in magnetic field strength (Z-axis component) - - - Innovation in vehicle yaw - - - Innovation in true-airspeed - - - Accumulated relative error of this core with respect to active primary core - - - A consolidated error score where higher numbers are less healthy - - - - - EKF2 variances SV, SP, SH and SM are probably best described as 'Squared Innovation Test Ratios' where values <1 tells us the measurement was accepted and >1 tells us it was rejected. They represent the square of the (innovation / maximum allowed innovation) where the innovation is the difference between predicted and measured value and the maximum allowed innovation is determined from the uncertainty of the measurement, uncertainty of the prediction and scaled using the number of standard deviations set by the innovation gate parameter for that measurement, eg EK2_MAG_I_GATE, EK2_HGT_I_GATE, etc - - - Time since system startup - - - EKF2 core this data is for - - - Square root of the velocity variance - - - Square root of the position variance - - - Square root of the height variance - - - Magnetic field variance - - - tilt error convergence metric - - - Filtered error in roll/pitch estimate - - - Most recent position reset (North component) - - - Most recent position reset (East component) - - - Filter fault status - - - Filter timeout status bitmask (0:position measurement, 1:velocity measurement, 2:height measurement, 3:magnetometer measurement, 4:airspeed measurement) - - - Filter solution status - - - 1 - attitude estimate valid - - - 2 - horizontal velocity estimate valid - - - 4 - vertical velocity estimate valid - - - 8 - relative horizontal position estimate valid - - - 16 - absolute horizontal position estimate valid - - - 32 - vertical position estimate valid - - - 64 - terrain height estimate valid - - - 128 - in constant position mode - - - 256 - expected good relative horizontal position estimate - used before takeoff - - - 512 - expected good absolute horizontal position estimate - used before takeoff - - - 1024 - optical flow takeoff has been detected - - - 2048 - compensating for baro errors during takeoff - - - 4096 - compensating for baro errors during touchdown - - - 8192 - using GPS position - - - 16384 - GPS glitching is affecting navigation accuracy - - - 32768 - can use GPS for navigation - - - 65536 - has ever been healthy - - - 131072 - rejecting airspeed data - - - 262144 - dead reckoning (e.g. no position or velocity source) - - - - - Filter GPS status - - - Primary core index - - - - - EKF2 Sensor innovations (primary core) and general dumping ground - - - Time since system startup - - - EKF2 core this data is for - - - Normalised flow variance - - - Optical flow LOS rate vector innovations from the main nav filter (X-axis) - - - Optical flow LOS rate vector innovations from the main nav filter (Y-axis) - - - Optical flow LOS rate innovation from terrain offset estimator - - - Height above ground level - - - Estimated vertical position of the terrain relative to the nav filter zero datum - - - Range finder innovations - - - Measured range - - - Filter ground offset state error - - - Magnitude of angular error - - - Magnitude of velocity error - - - Magnitude of position error - - - - - EKF2 quaternion defining the rotation from NED to XYZ (autopilot) axes - - - Time since system startup - - - EKF2 core this data is for - - - Quaternion a term - - - Quaternion b term - - - Quaternion c term - - - Quaternion d term - - - - - EKF2 timing information - - - Time since system startup - - - EKF core this message instance applies to - - - count of samples used to create this message - - - smallest IMU sample interval - - - largest IMU sample interval - - - low-passed achieved average time step rate for the EKF (minimum) - - - low-passed achieved average time step rate for the EKF (maximum) - - - accumulated measurement time interval for the delta angle (minimum) - - - accumulated measurement time interval for the delta angle (maximum) - - - accumulated measurement time interval for the delta velocity (minimum) - - - accumulated measurement time interval for the delta velocity (maximum) - - - - - EKF Yaw Estimator States - - - Time since system startup - - - EKF core this data is for - - - GSF yaw estimate (deg) - - - GSF yaw estimate 1-Sigma uncertainty (deg) - - - Yaw estimate from individual EKF filter 0 (deg) - - - Yaw estimate from individual EKF filter 1 (deg) - - - Yaw estimate from individual EKF filter 2 (deg) - - - Yaw estimate from individual EKF filter 3 (deg) - - - Yaw estimate from individual EKF filter 4 (deg) - - - Weighting applied to yaw estimate from individual EKF filter 0 - - - Weighting applied to yaw estimate from individual EKF filter 1 - - - Weighting applied to yaw estimate from individual EKF filter 2 - - - Weighting applied to yaw estimate from individual EKF filter 3 - - - Weighting applied to yaw estimate from individual EKF filter 4 - - - - - EKF Yaw Estimator Innovations - - - Time since system startup - - - EKF core this data is for - - - North velocity innovation from individual EKF filter 0 (m/s) - - - North velocity innovation from individual EKF filter 1 (m/s) - - - North velocity innovation from individual EKF filter 2 (m/s) - - - North velocity innovation from individual EKF filter 3 (m/s) - - - North velocity innovation from individual EKF filter 4 (m/s) - - - East velocity innovation from individual EKF filter 0 (m/s) - - - East velocity innovation from individual EKF filter 1 (m/s) - - - East velocity innovation from individual EKF filter 2 (m/s) - - - East velocity innovation from individual EKF filter 3 (m/s) - - - East velocity innovation from individual EKF filter 4 (m/s) - - - - - Named Value Float messages; messages sent to GCS via NAMED_VALUE_FLOAT - - - Time since system startup - - - Name of float - - - Value of float - - - - - Named Value String messages; messages sent to GCS via NAMED_VALUE_STRING - - - Time since system startup - - - Name of string - - - Value of string - - - - - Object avoidance (Bendy Ruler) diagnostics - - - Time since system startup - - - Type of BendyRuler currently active - - - True if Bendy Ruler avoidance is being used - - - Best yaw chosen to avoid obstacle - - - Current vehicle yaw - - - Desired pitch chosen to avoid obstacle - - - True if BendyRuler resisted changing bearing and continued in last calculated bearing - - - Margin from path to obstacle on best yaw chosen - - - Destination latitude - - - Destination longitude - - - Desired alt above EKF Origin - - - Intermediate location chosen for avoidance - - - Intermediate location chosen for avoidance - - - Intermediate alt chosen for avoidance above EKF origin - - - - - Object avoidance (Dijkstra) diagnostics - - - Time since system startup - - - Dijkstra avoidance library state - - - Dijkstra library error condition - - - Destination point in calculated path to destination - - - Number of points in path to destination - - - Destination latitude - - - Destination longitude - - - Object Avoidance chosen destination point latitude - - - Object Avoidance chosen destination point longitude - - - - - Object avoidance path planning visgraph points - - - Time since system startup - - - Visgraph version, increments each time the visgraph is re-generated - - - point number in visgraph - - - Latitude - - - longitude - - - - - Optical flow sensor data - - - Time since system startup - - - Estimated sensor data quality - - - Sensor flow rate, X-axis - - - Sensor flow rate,Y-axis - - - derived rotational velocity, X-axis - - - derived rotational velocity, Y-axis - - - - - Optical Flow Calibration sample - - - Time since system startup - - - Axis (X=0 Y=1) - - - Sample number - - - Flow rate - - - Body rate - - - Los pred - - - - - Vehicle navigation origin or other notable position - - - Time since system startup - - - Position type - - - 0 - - - 1 - - - - - Position latitude - - - Position longitude - - - Position altitude - - - - - parameter value - - - Time since system startup - - - parameter name - - - parameter value - - - default parameter value for this board and config - - - - - Proportional/Integral/Derivative gain values for vertical acceleration - - - Time since system startup - - - desired value - - - achieved value - - - error between target and achieved - - - proportional part of PID - - - integral part of PID - - - derivative part of PID - - - controller feed-forward portion of response - - - controller derivative feed-forward portion of response - - - scaler applied to D gain to reduce limit cycling - - - slew rate used in slew limiter - - - bitmask of PID state flags - - - 1 - true if the output is saturated, I term anti windup is active - - - 2 - true if the PD sum limit is active - - - 4 - true if the controller was reset - - - 8 - true if the I term has been set externally including reseting to 0 - - - - - - - Proportional/Integral/Derivative gain values for East/West velocity - - - Time since system startup - - - desired value - - - achieved value - - - error between target and achieved - - - proportional part of PID - - - integral part of PID - - - derivative part of PID - - - controller feed-forward portion of response - - - controller derivative feed-forward portion of response - - - scaler applied to D gain to reduce limit cycling - - - slew rate used in slew limiter - - - bitmask of PID state flags - - - 1 - true if the output is saturated, I term anti windup is active - - - 2 - true if the PD sum limit is active - - - 4 - true if the controller was reset - - - 8 - true if the I term has been set externally including reseting to 0 - - - - - - - Proportional/Integral/Derivative gain values for North/South velocity - - - Time since system startup - - - desired value - - - achieved value - - - error between target and achieved - - - proportional part of PID - - - integral part of PID - - - derivative part of PID - - - controller feed-forward portion of response - - - controller derivative feed-forward portion of response - - - scaler applied to D gain to reduce limit cycling - - - slew rate used in slew limiter - - - bitmask of PID state flags - - - 1 - true if the output is saturated, I term anti windup is active - - - 2 - true if the PD sum limit is active - - - 4 - true if the controller was reset - - - 8 - true if the I term has been set externally including reseting to 0 - - - - - - - Proportional/Integral/Derivative gain values for Pitch rate - - - Time since system startup - - - desired value - - - achieved value - - - error between target and achieved - - - proportional part of PID - - - integral part of PID - - - derivative part of PID - - - controller feed-forward portion of response - - - controller derivative feed-forward portion of response - - - scaler applied to D gain to reduce limit cycling - - - slew rate used in slew limiter - - - bitmask of PID state flags - - - 1 - true if the output is saturated, I term anti windup is active - - - 2 - true if the PD sum limit is active - - - 4 - true if the controller was reset - - - 8 - true if the I term has been set externally including reseting to 0 - - - - - - - Proportional/Integral/Derivative gain values for Roll rate - - - Time since system startup - - - desired value - - - achieved value - - - error between target and achieved - - - proportional part of PID - - - integral part of PID - - - derivative part of PID - - - controller feed-forward portion of response - - - controller derivative feed-forward portion of response - - - scaler applied to D gain to reduce limit cycling - - - slew rate used in slew limiter - - - bitmask of PID state flags - - - 1 - true if the output is saturated, I term anti windup is active - - - 2 - true if the PD sum limit is active - - - 4 - true if the controller was reset - - - 8 - true if the I term has been set externally including reseting to 0 - - - - - - - Proportional/Integral/Derivative gain values for ground steering yaw rate - - - Time since system startup - - - desired value - - - achieved value - - - error between target and achieved - - - proportional part of PID - - - integral part of PID - - - derivative part of PID - - - controller feed-forward portion of response - - - controller derivative feed-forward portion of response - - - scaler applied to D gain to reduce limit cycling - - - slew rate used in slew limiter - - - bitmask of PID state flags - - - 1 - true if the output is saturated, I term anti windup is active - - - 2 - true if the PD sum limit is active - - - 4 - true if the controller was reset - - - 8 - true if the I term has been set externally including reseting to 0 - - - - - - - Proportional/Integral/Derivative gain values for Yaw rate - - - Time since system startup - - - desired value - - - achieved value - - - error between target and achieved - - - proportional part of PID - - - integral part of PID - - - derivative part of PID - - - controller feed-forward portion of response - - - controller derivative feed-forward portion of response - - - scaler applied to D gain to reduce limit cycling - - - slew rate used in slew limiter - - - bitmask of PID state flags - - - 1 - true if the output is saturated, I term anti windup is active - - - 2 - true if the PD sum limit is active - - - 4 - true if the controller was reset - - - 8 - true if the I term has been set externally including reseting to 0 - - - - - - - Precision Landing messages - - - Time since system startup - - - True if Precision Landing is healthy - - - True if landing target is detected - - - Target position relative to vehicle, X-Axis (0 if target not found) - - - Target position relative to vehicle, Y-Axis (0 if target not found) - - - Target velocity relative to vehicle, X-Axis (0 if target not found) - - - Target velocity relative to vehicle, Y-Axis (0 if target not found) - - - Target's relative to origin position as 3-D Vector, X-Axis - - - Target's relative to origin position as 3-D Vector, Y-Axis - - - Target's relative to origin position as 3-D Vector, Z-Axis - - - Time when target was last detected - - - EKF's outlier count - - - Type of estimator used - - - - - autopilot system performance and general data dumping ground - - - Time since system startup - - - Main loop rate - - - Number of long loops detected - - - Number of measurement loops for this message - - - Maximum loop time - - - Free memory available - - - System processor load - - - Internal error line number; last line number on which a internal error was detected - - - Internal error mask; which internal errors have been detected - - - 1 - - - 2 - - - 4 - - - 8 - - - 16 - - - 32 - - - 64 - - - 128 - - - 256 - - - 512 - - - 1024 - - - 2048 - - - 4096 - - - 8192 - - - 16384 - - - 32768 - - - 65536 - - - 131072 - - - 262144 - - - 524288 - - - 1048576 - - - 2097152 - - - 4194304 - - - 8388608 - - - 16777216 - - - 33554432 - - - 67108864 - - - 134217728 - - - 268435456 - - - 536870912 - - - 1073741824 - - - - - Internal error count; how many internal errors have been detected - - - Number of SPI transactions processed - - - Number of i2c transactions processed - - - Number of i2c interrupts serviced - - - number of microseconds being added to each loop to address scheduler overruns - - - RTC time, time since Unix epoch - - - - - Canonical vehicle position - - - Time since system startup - - - Canonical vehicle latitude - - - Canonical vehicle longitude - - - Canonical vehicle altitude - - - Canonical vehicle altitude relative to home - - - Canonical vehicle altitude relative to navigation origin - - - - - System power information - - - Time since system startup - - - Flight board voltage - - - Servo rail voltage - - - System power flags - - - 1 - main brick power supply valid - - - 2 - main servo power supply valid for FMU - - - 4 - USB power is connected - - - 8 - peripheral supply is in over-current state - - - 16 - hi-power peripheral supply is in over-current state - - - 32 - Power status has changed since boot - - - - - Accumulated System power flags; all flags which have ever been set - - - 1 - main brick power supply valid - - - 2 - main servo power supply valid for FMU - - - 4 - USB power is connected - - - 8 - peripheral supply is in over-current state - - - 16 - hi-power peripheral supply is in over-current state - - - 32 - Power status has changed since boot - - - - - Hardware Safety Switch status - - - - - Plane Parameter Tuning data - - - Time since system startup - - - Parameter set being tuned - - - Parameter being tuned - - - Current parameter value - - - Center value (startpoint of current modifications) of parameter being tuned - - - - - Proximity Filtered sensor data - - - Time since system startup - - - Pitch(instance) at which the obstacle is at. 0th layer {-75,-45} degrees. 1st layer {-45,-15} degrees. 2nd layer {-15, 15} degrees. 3rd layer {15, 45} degrees. 4th layer {45,75} degrees. Minimum distance in each layer will be logged. - - - True if proximity sensor is healthy - - - Nearest object in sector surrounding 0-degrees - - - Nearest object in sector surrounding 45-degrees - - - Nearest object in sector surrounding 90-degrees - - - Nearest object in sector surrounding 135-degrees - - - Nearest object in sector surrounding 180-degrees - - - Nearest object in sector surrounding 225-degrees - - - Nearest object in sector surrounding 270-degrees - - - Nearest object in sector surrounding 315-degrees - - - Nearest object in upwards direction - - - Angle to closest object - - - Distance to closest object - - - - - Proximity Raw sensor data - - - Time since system startup - - - Pitch(instance) at which the obstacle is at. 0th layer {-75,-45} degrees. 1st layer {-45,-15} degrees. 2nd layer {-15, 15} degrees. 3rd layer {15, 45} degrees. 4th layer {45,75} degrees. Minimum distance in each layer will be logged. - - - Nearest object in sector surrounding 0-degrees - - - Nearest object in sector surrounding 45-degrees - - - Nearest object in sector surrounding 90-degrees - - - Nearest object in sector surrounding 135-degrees - - - Nearest object in sector surrounding 180-degrees - - - Nearest object in sector surrounding 225-degrees - - - Nearest object in sector surrounding 270-degrees - - - Nearest object in sector surrounding 315-degrees - - - - - Position Control Down - - - Time since system startup - - - Desired position relative to EKF origin + Offsets - - - Target position relative to EKF origin - - - Position relative to EKF origin - - - Desired velocity Down - - - Target velocity Down - - - Velocity Down - - - Desired acceleration Down - - - Target acceleration Down - - - Acceleration Down - - - - - Position Control East - - - Time since system startup - - - Desired position relative to EKF origin + Offsets - - - Target position relative to EKF origin - - - Position relative to EKF origin - - - Desired velocity East - - - Target velocity East - - - Velocity East - - - Desired acceleration East - - - Target acceleration East - - - Acceleration East - - - - - Position Control North - - - Time since system startup - - - Desired position relative to EKF origin - - - Target position relative to EKF origin - - - Position relative to EKF origin - - - Desired velocity North - - - Target velocity North - - - Velocity North - - - Desired acceleration North - - - Target acceleration North - - - Acceleration North - - - - - Position Control Offsets Down - - - Time since system startup - - - Target position offset Down - - - Position offset Down - - - Target velocity offset Down - - - Velocity offset Down - - - Target acceleration offset Down - - - Acceleration offset Down - - - - - Position Control Offsets East - - - Time since system startup - - - Target position offset East - - - Position offset East - - - Target velocity offset East - - - Velocity offset East - - - Target acceleration offset East - - - Acceleration offset East - - - - - Position Control Offsets North - - - Time since system startup - - - Target position offset North - - - Position offset North - - - Target velocity offset North - - - Velocity offset North - - - Target acceleration offset North - - - Acceleration offset North - - - - - Position Control Offsets Terrain (Down) - - - Time since system startup - - - Target position offset Terrain - - - Position offset Terrain - - - Target velocity offset Terrain - - - Velocity offset Terrain - - - Target acceleration offset Terrain - - - Acceleration offset Terrain - - - - - https://ardupilot.org/copter/docs/tuning.html#in-flight-tuning - Parameter Tuning information - - - Time since system startup - - - Parameter being tuned - - - Normalized value used inside tuning() function - - - Tuning minimum limit - - - Tuning maximum limit - - - normalaised control input (normalised -1 to 1 value) - - - - - Quicktune - - - Time since system startup - - - number of parameter being tuned - - - slew rate - - - test gain for current axis and PID element - - - name of parameter being being tuned - - - - - Telemetry radio statistics - - - Time since system startup - - - RSSI - - - RSSI reported from remote radio - - - number of bytes in radio ready to be sent - - - local noise floor - - - local noise floor reported from remote radio - - - damaged packet count - - - fixed damaged packet count - - - - - Rally point information - - - Time since system startup - - - total number of rally points onboard - - - this rally point's sequence number - - - latitude of rally point - - - longitude of rally point - - - altitude of rally point - - - altitude frame flags - - - - - Replay Airspeed Sensor Header - - - airspeed instance number - - - number of airspeed instances - - - - - Replay Airspeed Sensor Instance data - - - measured airspeed - - - timestamp of measured airspeed - - - indicator of airspeed sensor health - - - true if airspeed is configured to be used - - - airspeed instance number - - - - - Desired and achieved vehicle attitude rates. Not logged in Fixed Wing Plane modes. - - - Time since system startup - - - vehicle desired roll rate - - - achieved vehicle roll rate - - - normalized output for Roll - - - vehicle desired pitch rate - - - vehicle pitch rate - - - normalized output for Pitch - - - vehicle desired yaw rate - - - achieved vehicle yaw rate - - - normalized output for Yaw - - - desired vehicle vertical acceleration - - - achieved vehicle vertical acceleration - - - percentage of vertical thrust output current being used - - - vertical thrust output slew rate - - - - - Replay Data Beacon Header - - - zero, unused - - - zero, unused - - - zero, unused - - - zero, unused - - - origin latitude - - - origin longitude - - - origin altitude - - - vehicle_position_ned_returncode,get_origin_returncode,enabled - - - number of beacons - - - - - Replay Data Beacon Instance - - - last update from this beacon instance - - - beacon distance from origin, X-axis - - - beacon distance from origin, Y-axis - - - beacon distance from origin, Z-axis - - - distance to beacon - - - beacon data health - - - beacon instance number - - - - - Replay body odometry data - - - data quality measure - - - delta-position-X - - - delta-position-Y - - - delta-position-Z - - - delta-angle-X - - - delta-angle-Y - - - delta-angle-Z - - - delta-time - - - data timestamp - - - zero, unused - - - zero, unused - - - zero, unused - - - zero, unused - - - - - Replay Data Barometer Header - - - primary barometer instance number - - - number of barometer sensors - - - - - Replay Data Barometer Instance - - - timestamp of barometer data - - - barometer altitude estimate - - - barometer sensor health indication - - - barometer instance number - - - - - Raw RC data - - - Time since system startup - - - data arrival timestamp - - - Protocol currently being decoded - - - Number of valid bytes in message - - - first quartet of bytes - - - second quartet of bytes - - - third quartet of bytes - - - fourth quartet of bytes - - - fifth quartet of bytes - - - sixth quartet of bytes - - - seventh quartet of bytes - - - eight quartet of bytes - - - ninth quartet of bytes - - - tenth quartet of bytes - - - - - (More) RC input channels to vehicle - - - Time since system startup - - - channel 15 input - - - channel 16 input - - - bitmask of RC channels being overridden by mavlink input - - - bitmask of RC state flags - - - 1 - true if the system is receiving good RC values - - - 2 - true if the system is current in RC failsafe - - - 4 - true if the RC Protocol library is indicating the RC receiver is indicating failsafe via its protocol - - - - - - - RC input channels to vehicle - - - Time since system startup - - - channel 1 input - - - channel 2 input - - - channel 3 input - - - channel 4 input - - - channel 5 input - - - channel 6 input - - - channel 7 input - - - channel 8 input - - - channel 9 input - - - channel 10 input - - - channel 11 input - - - channel 12 input - - - channel 13 input - - - channel 14 input - - - - - Servo channel output values 15 to 18 - - - Time since system startup - - - channel 15 output - - - channel 16 output - - - channel 17 output - - - channel 18 output - - - - - Servo channel output values 19 to 32 - - - Time since system startup - - - channel 19 output - - - channel 20 output - - - channel 21 output - - - channel 22 output - - - channel 23 output - - - channel 24 output - - - channel 25 output - - - channel 26 output - - - channel 27 output - - - channel 28 output - - - channel 29 output - - - channel 30 output - - - channel 31 output - - - channel 32 output - - - - - Servo channel output values 1 to 14 - - - Time since system startup - - - channel 1 output - - - channel 2 output - - - channel 3 output - - - channel 4 output - - - channel 5 output - - - channel 6 output - - - channel 7 output - - - channel 8 output - - - channel 9 output - - - channel 10 output - - - channel 11 output - - - channel 12 output - - - channel 13 output - - - channel 14 output - - - - - Relay state - - - Time since system startup - - - relay instance number - - - current state - - - - - Replay external position data - - - external position estimate, X-axis - - - external position estimate, Y-axis - - - external position estimate, Z-axis - - - external attitude quaternion - - - external attitude quaternion - - - external attitude quaternion - - - external attitude quaternion - - - external position error estimate - - - external attitude error estimate - - - timestamp on external error estimate - - - timestamp of last external reset - - - delay on external data - - - - - Replay Event (EKF2) - - - external event injected into EKF - - - 0 - - - 1 - - - 9 - - - 10 - - - 11 - - - 12 - - - 13 - - - 14 - - - 15 - - - - - - - Replay Event (EKF3) - - - external event injected into EKF - - - 0 - - - 1 - - - 9 - - - 10 - - - 11 - - - 12 - - - 13 - - - 14 - - - 15 - - - - - - - Replay external velocity data - - - external velocity estimate, X-axis - - - external velocity estimate, Y-axis - - - external velocity estimate, Z-axis - - - error in velocity estimate - - - timestamp of velocity estimate - - - delay in external velocity data - - - - - Replay Euler Yaw event - - - externally supplied yaw angle - - - error in externally supplied yaw angle - - - timestamp associated with yaw angle and yaw angle error - - - number that needs documenting - - - - - RealFlight mode messages - - - Time since system startup - - - delta time between this frame and the previous frame - - - frames-per-second implied by the current delta time - - - - - Rangefinder sensor information - - - Time since system startup - - - rangefinder instance number this data is from - - - Reported distance from sensor - - - Sensor state - - - 0 - - - 1 - - - 2 - - - 3 - - - 4 - - - - - Sensor orientation - - - 0 - - - 1 - - - 2 - - - 3 - - - 4 - - - 5 - - - 6 - - - 7 - - - 8 - - - 9 - - - 10 - - - 11 - - - 12 - - - 13 - - - 14 - - - 15 - - - 16 - - - 17 - - - 18 - - - 19 - - - 20 - - - 21 - - - 22 - - - 23 - - - 24 - - - 25 - - - 26 - same as ROTATION_ROLL_180_YAW_270 - - - 27 - same as ROTATION_ROLL_180_YAW_90 - - - 28 - - - 29 - - - 30 - - - 31 - - - 32 - - - 33 - - - 34 - - - 35 - - - 36 - - - 37 - - - 38 - this is actually, roll 90, pitch 68.8, yaw 293.3 - - - 39 - - - 40 - - - 41 - - - 42 - - - 43 - - - 44 - - - 100 - - - 101 - - - 102 - - - 103 - - - - - Signal quality. -1 means invalid, 0 is no signal, 100 is perfect signal - - - - - Replay FRame data - Finished frame - - - accumulated method calls made during frame - - - 1 - - - 2 - - - 4 - - - 8 - - - 16 - - - 32 - - - - - true if we are not keeping up with IMU loop rate - - - - - Replay FRame Header - - - Time since system startup - - - Time flying - - - - - Replay FRame - aNother frame header - - - home latitude - - - home latitude - - - home altitude AMSL - - - EAS to TAS factor - - - available memory - - - AHRS trim X - - - AHRS trim Y - - - AHRS trim Z - - - AHRS Vehicle Class - - - configured EKF type - - - 0 - - - 1 - - - - - bitmask of boolean state - - - 1 - - - 2 - - - 4 - - - 8 - - - 16 - - - 32 - - - 64 - - - 128 - - - - - - - Replay Data GPS Header - - - number of GPS sensors - - - instance number of primary sensor - - - - - Replay Data GPS Instance, infrequently changing data - - - antenna body-frame offset, X-axis - - - antenna body-frame offset, Y-axis - - - antenna body-frame offset, Z-axis - - - GPS time lag - - - various GPS flags - - - 1 - - - 2 - - - 4 - - - 8 - - - 16 - - - 32 - - - - - GPS fix status - - - number of satellites GPS is using - - - GPS sensor instance number - - - - - Replay Data GPS Instance - rapidly changing data - - - GPS data timestamp - - - GPS velocity, North - - - GPS velocity, East - - - GPS velocity, Down - - - speed accuracy - - - GPS yaw - - - GPS yaw accuracy - - - timestamp of GPS yaw estimate - - - latitude - - - longitude - - - altitude - - - horizontal accuracy - - - vertical accuracy - - - HDOP - - - GPS sensor instance number - - - - - Richenpower generator telemetry - - - Time since system startup - - - total generator runtime - - - time until generator requires maintenance - - - bitmask of error received from generator - - - current generator RPM - - - output voltage - - - output current - - - generator mode; idle/run/charge/balance - - - - - Replay Inertial Sensor header - - - INS loop rate - - - primary gyro index - - - primary accel index - - - INS loop-delta-t - - - accel count - - - gyro count - - - - - Replay Inertial Sensor instance data - - - x-axis delta-velocity - - - y-axis delta-velocity - - - z-axis delta-velocity - - - x-axis delta-angle - - - y-axis delta-angle - - - z-axis delta-angle - - - delta-velocity-delta-time - - - delta-angle-delta-time - - - use-accel, use-gyro, delta-vel-valid, delta-accel-valid - - - IMU instance - - - - - Replay Data Magnetometer Header - - - vehicle declination - - - true if the compass library is marking itself as available - - - number of compass instances - - - true if compass autodeclination is enabled - - - number of enabled compass instances - - - true if compass learning of offsets is enabled - - - true if compasses are consistent - - - index of first usable compass - - - - - Replay Data Magnetometer Instance - - - last update time for magnetometer data - - - mag sensor offset, X-axis - - - mag sensor offset, Y-axis - - - mag sensor offset, Z-axis - - - field strength, X-axis - - - field strength, Y-axis - - - field strength, Z-axis - - - true if compass is being used for yaw - - - sensor health - - - compass has scale factor - - - magnetometer instance number - - - - - Replay optical flow data - - - raw flow rate, X-axis - - - raw flow rate, Y-axis - - - gyro rate, X-axis - - - gyro rate, Y-axis - - - measurement timestamp - - - gyro rate, X-axis - - - body-frame offset, Y-axis - - - body-frame offset, Z-axis - - - sensor height override - - - flow quality measurement - - - - - Data from RPM sensors - - - Time since system startup - - - Instance - - - Sensor's rpm measurement - - - Signal quality - - - Sensor Health (Bool) - - - - - Replay Data Rangefinder Header - - - rangefinder ground clearance for downward-facing rangefinders - - - rangefinder maximum distance for downward-facing rangefinders - - - number of rangefinder instances - - - - - Replay Data Rangefinder Instance - - - rangefinder body-frame offset, X-axis - - - rangefinder body-frame offset, Y-axis - - - rangefinder body-frame offset, Z-axis - - - Measured rangefinder distance - - - orientation - - - status - - - rangefinder instance number - - - - - Replay Set Lat Lng event - - - latitude - - - longitude - - - position accuracy, 1-StD - - - timestamp of latitude/longitude - - - - - Replay Set Origin event (EKF2) - - - origin latitude - - - origin longitude - - - origin altitude - - - - - Replay Set Origin event (EKF3) - - - origin latitude - - - origin longitude - - - origin altitude - - - - - Received Signal Strength Indicator for RC receiver - - - Time since system startup - - - RSSI - - - RX Link Quality - - - - - Information about RTC clock resets - - - Time since system startup - - - old time - - - new time - - - - - GPS atmospheric perturbation data - - - Time since system startup - - - mavlink channel number this data was received on - - - ID field from RTCM packet - - - RTCM packet length - - - calculated crc32 for the packet - - - - - Attitude controller time deltas - - - Time since system startup - - - current time delta - - - current time delta average - - - Max time delta since last log output - - - Min time delta since last log output - - - - - Replay Terrain SRTM Altitude - - - altitude above origin in meters - - - - - Replay Data Visual Odometry data - - - offset, x-axis - - - offset, y-axis - - - offset, z-axis - - - data delay - - - sensor health - - - sensor enabled - - - - - Replay set-default-airspeed event (EKF2) - - - default airspeed - - - uncertainty in default airspeed - - - - - Replay set-default-airspeed event (EKF3) - - - default airspeed - - - uncertainty in default airspeed - - - - - Replay wheel odometry data - - - delta-angle - - - delta-time - - - data timestamp - - - sensor body-frame offset, x-axis - - - sensor body-frame offset, y-axis - - - sensor body-frame offset, z-axis - - - wheel radius - - - - - Simple Avoidance messages - - - Time since system startup - - - True if Simple Avoidance is active - - - Desired velocity, X-Axis (Velocity before Avoidance) - - - Desired velocity, Y-Axis (Velocity before Avoidance) - - - Desired velocity, Z-Axis (Velocity before Avoidance) - - - Modified velocity, X-Axis (Velocity after Avoidance) - - - Modified velocity, Y-Axis (Velocity after Avoidance) - - - Modified velocity, Z-Axis (Velocity after Avoidance) - - - True if vehicle is backing away - - - - - Simulated Blimp Sin-Angles - - - Time since system startup - - - sin(x angle) - - - sin(y angle) - - - sin(z angle) - - - - - Simulated Blimp Angles - - - Time since system startup - - - x angle - - - y angle - - - z angle - - - - - Simulated Blimp Angles - - - Time since system startup - - - x earth-frame angle - - - y earth-frame angle - - - z earth-frame angle - - - - - Simulated Blimp Body-Frame accelerations - - - Time since system startup - - - x-axis acceleration - - - y-axis acceleration - - - z-axis acceleration - - - - - Simulated Blimp Rotational Accelerations - - - Time since system startup - - - acceleration around X axis - - - acceleration around Y axis - - - acceleration around Z axis - - - - - Swift Health Data - - - Time since system startup - - - Number of packet CRC errors on serial connection - - - Timestamp of last raw data injection to GPS - - - Current number of integer ambiguity hypotheses - - - - - Swift Time Data - - - Time since system startup - - - GPS week number - - - Milliseconds through GPS week - - - residual of milliseconds rounding in ns - - - GPIO pin levels - - - time quality - - - - - Scripting runtime stats - - - Time since system startup - - - script name - - - run time - - - total memory usage of all scripts - - - run memory usage - - - - - Simulated Glider Drop control outputs - - - Time since system startup - - - aileron output - - - elevator output - - - rudder output - - - - - Debug message for SCurve internal error - - - Time since system startup - - - duration of the raised cosine jerk profile - - - maximum value of the raised cosine jerk profile - - - initial velocity magnitude - - - maximum constant acceleration - - - maximum constant velocity - - - Length of the path - - - maximum value of the raised cosine jerk profile - - - segment duration - - - segment duration - - - segment duration - - - segment duration - - - - - Simulated Blimp Fin Angles - - - Time since system startup - - - fin 0 angle - - - fin 1 angle - - - fin 2 angle - - - fin 3 angle - - - - - Simulated Blimp Servo Angles - - - Time since system startup - - - fin 0 servo angle - - - fin 1 servo angle - - - fin 2 servo angle - - - fin 3 servo angle - - - - - Simulated Blimp Fin Forces - - - Time since system startup - - - Fin 0 normal force - - - Fin 1 normal force - - - Fin 2 normal force - - - Fin 3 normal force - - - - - Simulated Blimp Fin Thrust - - - Time since system startup - - - Fin 0 tangential thrust - - - Fin 1 tangential thrust - - - Fin 2 tangential thrust - - - Fin 3 tangential thrust - - - - - Simulated Blimp Fin Velocities - - - Time since system startup - - - fin 0 velocity - - - fin 1 velocity - - - fin 2 velocity - - - fin 3 velocity - - - - - System ID data - - - Time since system startup - - - Time reference for waveform - - - Current waveform sample - - - Instantaneous waveform frequency - - - Delta angle, X-Axis - - - Delta angle, Y-Axis - - - Delta angle, Z-Axis - - - Delta velocity, X-Axis - - - Delta velocity, Y-Axis - - - Delta velocity, Z-Axis - - - - - System ID settings - - - Time since system startup - - - The axis which is being excited - - - Magnitude of the chirp waveform - - - Frequency at the start of chirp - - - Frequency at the end of chirp - - - Time to reach maximum amplitude of chirp - - - Time at constant frequency before chirp starts - - - Time taken to complete chirp waveform - - - Time to reach zero amplitude after chirp finishes - - - - - SITL simulator state - - - Time since system startup - - - Simulated roll - - - Simulated pitch - - - Simulated yaw - - - Simulated altitude - - - Simulated latitude - - - Simulated longitude - - - Attitude quaternion component 1 - - - Attitude quaternion component 2 - - - Attitude quaternion component 3 - - - Attitude quaternion component 4 - - - - - Additional simulator state - - - Time since system startup - - - North position from home - - - East position from home - - - Down position from home - - - Velocity north - - - Velocity east - - - Velocity down - - - Airspeed - - - Achieved simulation speedup value - - - Number of times simulation paused for serial0 output - - - - - Simulation data - - - Time since system startup - - - Velocity - North component - - - Velocity - East component - - - Velocity - Down component - - - Acceleration - North component - - - Acceleration - East component - - - Acceleration - Down component - - - Position - North component - - - Position - East component - - - Position - Down component - - - - - More Simulated Glider Dropped Calculations - - - Time since system startup - - - altitude in feet - - - equivalent airspeed in knots - - - true airspeed in knots - - - air density - - - lift - - - drag - - - lift/drag ratio - - - elevator output - - - aileron output - - - rudder output - - - Angle of Attack - - - Side Slip Angle - - - air pressire - - - z-axis body-frame acceleration - - - - - Simulated Glider Dropped Calculations - - - Time since system startup - - - altitude in feet - - - altitude in metres - - - equivalent airspeed - - - true airspeed - - - air density - - - lift - - - drag - - - lift/drag ratio - - - elevator output - - - angle of attack - - - X-axis force - - - Y-axis force - - - Z-axis force - - - air pressure - - - - - Slung payload - - - Time since system startup - - - 1 if payload is landed, 0 otherwise - - - Tension ratio, 1 if line is taut, 0 if slack - - - Line length - - - Payload position as offset from vehicle in North direction - - - Payload position as offset from vehicle in East direction - - - Payload position as offset from vehicle in Down direction - - - Payload velocity in North direction - - - Payload velocity in East direction - - - Payload velocity in Down direction - - - Payload acceleration in North direction - - - Payload acceleration in East direction - - - Payload acceleration in Down direction - - - Force on vehicle in North direction - - - Force on vehicle in East direction - - - Force on vehicle in Down direction - - - - - Log data received from JSON simulator 1 - - - Time since system startup (us) - - - Slave instance - - - magic JSON protocol key - - - Slave instance's desired frame rate - - - Slave instance's current frame count - - - 1 if the servo outputs are being used from this instance - - - - - Log data received from JSON simulator 2 - - - Time since system startup - - - Slave instance - - - channel 1 output - - - channel 2 output - - - channel 3 output - - - channel 4 output - - - channel 5 output - - - channel 6 output - - - channel 7 output - - - channel 8 output - - - channel 9 output - - - channel 10 output - - - channel 11 output - - - channel 12 output - - - channel 13 output - - - channel 14 output - - - - - Simulated Blimp Mass and COG - - - Time since system startup - - - mass - - - gravity - - - centre-of-gravity, z-axis - - - - - Smoothed sensor data fed to EKF to avoid inconsistencies - - - Time since system startup - - - Angular Velocity (around x-axis) - - - Angular Velocity (around y-axis) - - - Angular Velocity (around z-axis) - - - Velocity (along x-axis) - - - Velocity (along y-axis) - - - Velocity (along z-axis) - - - Roll - - - Pitch - - - Yaw - - - DCM Roll - - - DCM Pitch - - - DCM Yaw - - - - - Simulated Volz servo information - - - Time since system startup - - - Volz servo ID - - - Current Simulated Position - - - Desired Simulated Position - - - simulated servo voltage - - - simulated servo current - - - simulated PCB Temperature - - - simulated motor Temperature - - - - - Simulated Blimp Rotational forces - - - Time since system startup - - - zero - - - zero - - - zero - - - - - Transformed Simulated Blimp Rotational forces - - - Time since system startup - - - x-axis wobble rotational force - - - y-axis wobble rotational force - - - z-axis wobble rotational force - - - - - Simulated Blimp Torques - - - Time since system startup - - - torque around x axis - - - torque around y axis - - - torque around z axis - - - - - SmartRTL statistics - - - Time since system startup - - - true if SmartRTL could be used right now - - - number of points currently in use - - - maximum number of points that could be used - - - most recent internal action taken by SRTL library - - - 0 - - - 1 - - - 2 - - - 3 - - - 4 - - - 5 - - - 6 - - - 7 - - - 9 - - - 10 - - - 11 - - - - - point associated with most recent action (North component) - - - point associated with most recent action (East component) - - - point associated with most recent action (Down component) - - - - - Simulated Blimp Servo Inputs - - - Time since system startup - - - fin 0 servo angle input - - - fin 1 servo angle input - - - fin 2 servo angle input - - - fin 3 servo angle input - - - - - Stack information - - - Time since system startup - - - thread ID - - - thread priority - - - total stack - - - free stack - - - thread name - - - - - Surface distance measurement - - - Time since system startup - - - Instance - - - Surface distance status - - - 1 - true if rangefinder has been set to enable by vehicle - - - 2 - true if rangefinder is considered unhealthy - - - 4 - true if the last healthy rangefinder reading is no longer valid - - - 8 - true if a measurement glitch detected - - - - - Raw Distance - - - Filtered Distance - - - Terrain Offset - - - - - Helicopter swashplate logging - - - Time since system startup - - - Swashplate instance - - - Blade pitch angle contribution from collective - - - Total blade pitch angle contribution from cyclic - - - Blade pitch angle contribution from pitch cyclic - - - Blade pitch angle contribution from roll cyclic - - - - - Temperature Calibration Information - - - Time since system startup - - - temperature calibration instance number - - - sensor type (0==accel, 1==gyro) - - - current temperature - - - x-axis sample sum - - - y-axis sample sum - - - z-axis sample sum - - - sample count - - - - - Temperature Sensor Data - - - Time since system startup - - - temperature sensor instance - - - temperature - - - - - Terrain database information - - - Time since system startup - - - Terrain database status - - - 0 - not enabled - - - 1 - no terrain data for current location - - - 2 - terrain data available - - - - - Current vehicle latitude - - - Current vehicle longitude - - - terrain Tile spacing - - - current Terrain height - - - Vehicle height above terrain - - - Number of tile requests outstanding - - - Number of tiles in memory - - - terrain reference offset for arming altitude - - - - - Tether state - - - Time since system startup - - - Tether length - - - Force on vehicle in North direction - - - Force on vehicle in East direction - - - Force on vehicle in Down direction - - - - - https://ardupilot.org/copter/docs/throw-mode.html - Throw Mode messages - - - Time since system startup - - - Current stage of the Throw Mode - - - Magnitude of the velocity vector - - - Vertical Velocity - - - Magnitude of the vector of the current acceleration - - - Vertical earth frame accelerometer value - - - True if a throw has been detected since entering this mode - - - True if the vehicle is upright - - - True if the vehicle is within 0.5 m of the demanded height - - - True if the vehicle is within 0.5 m of the demanded horizontal position - - - - - Maximum thrust limitation based on battery voltage in Toy Mode - - - Time since system startup - - - Filtered battery voltage - - - Thrust multiplier between 0 and 1 to limit the output thrust based on battery voltage - - - Motor 1 pwm output - - - Motor 2 pwm output - - - Motor 3 pwm output - - - Motor 4 pwm output - - - - - Camera shutter information - - - Time since system startup - - - Instance number - - - Image number - - - milliseconds since start of GPS week - - - weeks since 5 Jan 1980 - - - current latitude - - - current longitude - - - current altitude - - - current altitude relative to home - - - altitude as reported by GPS - - - current vehicle roll - - - current vehicle pitch - - - current vehicle yaw - - - - - Torqeedo Motor Param - - - Time since system startup - - - instance - - - Motor RPM - - - Motor power - - - Motor voltage - - - Motor current - - - ESC Temp - - - Motor Temp - - - - - Torqeedo Motor Status - - - Time since system startup - - - instance - - - Motor status flags - - - Motor error flags - - - - - Torqeedo Status - - - Time since system startup - - - instance - - - Health - - - Desired Motor Speed (-1000 to 1000) - - - Motor Speed (-1000 to 1000) - - - Success Count - - - Error Count - - - - - Torqeedo System Setup - - - Time since system startup - - - instance - - - Flags - - - Motor type - - - Motor software version - - - Battery capacity - - - Battery charge percentage - - - Battery type - - - Master software version - - - - - Torqeedo System State - - - Time since system startup - - - instance - - - Flags bitmask - - - Master error code - - - Motor voltage - - - Motor current - - - Motor power - - - Motor RPM - - - Motor Temp (higher of pcb or stator) - - - Battery charge percentage - - - Battery voltage - - - Battery current - - - - - Time synchronisation response information - - - Time since system startup - - - system ID this data is for - - - round trip time for this system - - - - - UART stats - - - Time since system startup - - - instance - - - transmitted data rate bytes per second - - - received data rate bytes per second, this is all incoming data, it may not all be processed by the driver using this port. - - - Data rate of dropped received bytes, ideally should be 0. This is the difference between the received data rate and the processed data rate. - - - - - uBlox-specific GPS information (part 1) - - - Time since system startup - - - GPS instance number - - - noise level as measured by GPS - - - jamming indicator; higher is more likely jammed - - - antenna power indicator; 2 is don't know - - - automatic gain control monitor - - - bitmask for messages which haven't been seen - - - - - uBlox-specific GPS information (part 2) - - - Time since system startup - - - GPS instance number - - - imbalance of I part of complex signal - - - magnitude of I part of complex signal - - - imbalance of Q part of complex signal - - - magnitude of Q part of complex signal - - - - - uBlox specific UBX-TIM-TM2 logging, see uBlox interface description - - - Time since system startup - - - GPS instance number - - - Channel (i.e. EXTINT) upon which the pulse was measured - - - Bitmask - - - Rising edge counter - - - Week number of last rising edge - - - Tow of rising edge - - - Millisecond fraction of tow of rising edge in nanoseconds - - - Week number of last falling edge - - - Tow of falling edge - - - Millisecond fraction of tow of falling edge in nanoseconds - - - Accuracy estimate - - - - - Message mapping from single character to SI unit - - - Time since system startup - - - character referenced by FMTU - - - Unit - SI where available - - - - - Ardupilot version - - - Time since system startup - - - Board type - - - 3 - - - 7 - - - 10 - - - 12 - - - 13 - - - 99 - - - - - Board subtype - - - -1 - - - 1000 - - - 1001 - - - 1002 - - - 1003 - - - 1005 - - - 1006 - - - 1009 - - - 1010 - - - 1012 - - - 1013 - - - 1014 - - - 1015 - - - 1016 - - - 1018 - - - 1020 - - - 1022 - - - 1023 - - - 1024 - - - 1025 - - - 1026 - - - 1027 - - - 1028 - - - 1029 - - - 1030 - - - - - Major version number - - - Minor version number - - - Patch number - - - Firmware type - - - Github commit - - - Firmware version string - - - Board ID - - - Build vehicle type - - - 1 - - - 2 - - - 3 - - - 4 - - - 5 - - - 6 - - - 7 - - - 8 - - - 9 - - - 10 - - - 11 - - - 12 - - - 13 - - - - - Filter version - - - IOMCU MCU ID - - - IOMCU CPU ID - - - - - Processed (acceleration) vibration information - - - Time since system startup - - - Vibration instance number - - - Primary accelerometer filtered vibration, x-axis - - - Primary accelerometer filtered vibration, y-axis - - - Primary accelerometer filtered vibration, z-axis - - - Number of clipping events on 1st accelerometer - - - - - Visual Odometry - - - System time - - - Time period this data covers - - - Angular change for body-frame roll axis - - - Angular change for body-frame pitch axis - - - Angular change for body-frame z axis - - - Position change for body-frame X axis (Forward-Back) - - - Position change for body-frame Y axis (Right-Left) - - - Position change for body-frame Z axis (Down-Up) - - - Confidence - - - - - Vision Position - - - System time - - - Remote system time - - - Corrected system time - - - Position X-axis (North-South) - - - Position Y-axis (East-West) - - - Position Z-axis (Down-Up) - - - Roll lean angle - - - Pitch lean angle - - - Yaw angle - - - Position estimate error - - - Attitude estimate error - - - Position reset counter - - - Ignored - - - Quality - - - - - Vision Velocity - - - System time - - - Remote system time - - - Corrected system time - - - Velocity X-axis (North-South) - - - Velocity Y-axis (East-West) - - - Velocity Z-axis (Down-Up) - - - Velocity estimate error - - - Velocity reset counter - - - Ignored - - - Quality - - - - - VectorNav Attitude data - - - Time since system startup - - - Attitude quaternion 1 - - - Attitude quaternion 2 - - - Attitude quaternion 3 - - - Attitude quaternion 4 - - - Yaw - - - Pitch - - - Roll - - - Yaw unceratainty - - - Pitch uncertainty - - - Roll uncertainty - - - - - VectorNav IMU data - - - Time since system startup - - - Temprature - - - Pressure - - - Magnetic feild X-axis - - - Magnetic feild Y-axis - - - Magnetic feild Z-axis - - - Acceleration X-axis - - - Acceleration Y-axis - - - Acceleration Z-axis - - - Rotation rate X-axis - - - Rotation rate Y-axis - - - Rotation rate Z-axis - - - - - VectorNav INS Kalman Filter data - - - Time since system startup - - - VectorNav INS health status - - - Latitude - - - Longitude - - - Altitude - - - Velocity Northing - - - Velocity Easting - - - Velocity Downing - - - Filter estimated position uncertainty - - - Filter estimated Velocity uncertainty - - - - - Log message for video stabilisation software such as Gyroflow - - - Time since system startup - - - measured rotation rate about X axis - - - measured rotation rate about Y axis - - - measured rotation rate about Z axis - - - acceleration along X axis - - - acceleration along Y axis - - - acceleration along Z axis - - - Estimated attitude quaternion component 1 - - - Estimated attitude quaternion component 2 - - - Estimated attitude quaternion component 3 - - - Estimated attitude quaternion component 4 - - - - - Watchdog diagnostics - - - Time since system startup - - - current task number - - - internal error mast - - - internal error count - - - line internal error was raised on - - - mavlink message being acted on - - - mavlink command being acted on - - - line semaphore was taken on - - - fault_line - - - fault_type - - - fault address - - - fault thread priority - - - ICS regiuster - - - long return address - - - Thread name - - - - - Wheel encoder measurements - - - Time since system startup - - - First wheel distance travelled - - - Quality measurement of Dist0 - - - Second wheel distance travelled - - - Quality measurement of Dist1 - - - - - Winch - - - Time since system startup - - - Healthy - - - Reached end of thread - - - Motor is moving - - - Clutch is engaged (motor can move freely) - - - 0 is Relaxed, 1 is Position Control, 2 is Rate Control - - - Desired Length - - - Estimated Length - - - Desired Rate - - - Tension on line - - - Voltage to Motor - - - Motor temperature - - - - - Windvane readings - - - Time since system startup - - - raw apparent wind direction direct from sensor, in body-frame - - - Apparent wind direction, in body-frame - - - True wind direction - - - raw wind speed direct from sensor - - - Apparent wind Speed - - - True wind speed - - - - - EKF3 beacon sensor diagnostics - - - Time since system startup - - - EKF3 core this data is for - - - Beacon sensor ID - - - Beacon range - - - Beacon range innovation - - - sqrt of beacon range innovation variance - - - Beacon range innovation consistency test ratio - - - Beacon north position - - - Beacon east position - - - Beacon down position - - - High estimate of vertical position offset of beacons rel to EKF origin - - - Low estimate of vertical position offset of beacons rel to EKF origin - - - North position of receiver rel to EKF origin - - - East position of receiver rel to EKF origin - - - Down position of receiver rel to EKF origin - - - - - EKF3 estimator outputs - - - Time since system startup - - - EKF3 core this data is for - - - Estimated roll - - - Estimated pitch - - - Estimated yaw - - - Estimated velocity (North component) - - - Estimated velocity (East component) - - - Estimated velocity (Down component) - - - Filtered derivative of vertical position (down) - - - Estimated distance from origin (North component) - - - Estimated distance from origin (East component) - - - Estimated distance from origin (Down component) - - - Estimated gyro bias, X axis - - - Estimated gyro bias, Y axis - - - Estimated gyro bias, Z axis - - - Height of origin above WGS-84 - - - - - EKF3 estimator secondary outputs - - - Time since system startup - - - EKF3 core this data is for - - - Estimated accelerometer X bias - - - Estimated accelerometer Y bias - - - Estimated accelerometer Z bias - - - Estimated wind velocity (moving-to-North component) - - - Estimated wind velocity (moving-to-East component) - - - Magnetic field strength (North component) - - - Magnetic field strength (East component) - - - Magnetic field strength (Down component) - - - Magnetic field strength (body X-axis) - - - Magnetic field strength (body Y-axis) - - - Magnetic field strength (body Z-axis) - - - Innovation in vehicle drag acceleration (X-axis component) - - - Innovation in vehicle drag acceleration (Y-axis component) - - - Innovation in vehicle sideslip - - - - - EKF3 innovations - - - Time since system startup - - - EKF3 core this data is for - - - Innovation in velocity (North component) - - - Innovation in velocity (East component) - - - Innovation in velocity (Down component) - - - Innovation in position (North component) - - - Innovation in position (East component) - - - Innovation in position (Down component) - - - Innovation in magnetic field strength (X-axis component) - - - Innovation in magnetic field strength (Y-axis component) - - - Innovation in magnetic field strength (Z-axis component) - - - Innovation in vehicle yaw - - - Innovation in true-airspeed - - - Accumulated relative error of this core with respect to active primary core - - - A consolidated error score where higher numbers are less healthy - - - - - EKF3 variances. SV, SP, SH and SM are probably best described as 'Squared Innovation Test Ratios' where values <1 tells us the measurement was accepted and >1 tells us it was rejected. They represent the square of the (innovation / maximum allowed innovation) where the innovation is the difference between predicted and measured value and the maximum allowed innovation is determined from the uncertainty of the measurement, uncertainty of the prediction and scaled using the number of standard deviations set by the innovation gate parameter for that measurement, eg EK3_MAG_I_GATE, EK3_HGT_I_GATE, etc - - - Time since system startup - - - EKF3 core this data is for - - - Square root of the velocity variance - - - Square root of the position variance - - - Square root of the height variance - - - Magnetic field variance - - - Square root of the total airspeed variance - - - Filtered error in roll/pitch estimate - - - Most recent position reset (North component) - - - Most recent position reset (East component) - - - Filter fault status - - - Filter timeout status bitmask (0:position measurement, 1:velocity measurement, 2:height measurement, 3:magnetometer measurement, 4:airspeed measurement, 5:drag measurement) - - - Filter solution status - - - 1 - attitude estimate valid - - - 2 - horizontal velocity estimate valid - - - 4 - vertical velocity estimate valid - - - 8 - relative horizontal position estimate valid - - - 16 - absolute horizontal position estimate valid - - - 32 - vertical position estimate valid - - - 64 - terrain height estimate valid - - - 128 - in constant position mode - - - 256 - expected good relative horizontal position estimate - used before takeoff - - - 512 - expected good absolute horizontal position estimate - used before takeoff - - - 1024 - optical flow takeoff has been detected - - - 2048 - compensating for baro errors during takeoff - - - 4096 - compensating for baro errors during touchdown - - - 8192 - using GPS position - - - 16384 - GPS glitching is affecting navigation accuracy - - - 32768 - can use GPS for navigation - - - 65536 - has ever been healthy - - - 131072 - rejecting airspeed data - - - 262144 - dead reckoning (e.g. no position or velocity source) - - - - - Filter GPS status - - - Primary core index - - - - - EKF3 Sensor innovations (primary core) and general dumping ground - - - Time since system startup - - - EKF3 core this data is for - - - Normalised flow variance - - - Optical flow LOS rate vector innovations from the main nav filter (X-axis) - - - Optical flow LOS rate vector innovations from the main nav filter (Y-axis) - - - Optical flow LOS rate innovation from terrain offset estimator - - - Height above ground level - - - Estimated vertical position of the terrain relative to the nav filter zero datum - - - Range finder innovations - - - Measured range - - - Filter ground offset state error - - - Magnitude of angular error - - - Magnitude of velocity error - - - Magnitude of position error - - - - - EKF3 Body Frame Odometry errors - - - Time since system startup - - - EKF3 core this data is for - - - Innovation in velocity (X-axis) - - - Innovation in velocity (Y-axis) - - - Innovation in velocity (Z-axis) - - - Variance in velocity (X-axis) - - - Variance in velocity (Y-axis) - - - Variance in velocity (Z-axis) - - - - - EKF3 diagnostic data for on-ground-and-not-moving check - - - Time since system startup - - - EKF core this message instance applies to - - - True of on ground and not moving - - - Gyroscope length ratio - - - Accelerometer length ratio - - - Gyroscope rate of change ratio - - - Accelerometer rate of change ratio - - - - - EKF3 sensor selection - - - Time since system startup - - - EKF3 core this data is for - - - compass selection index - - - barometer selection index - - - GPS selection index - - - airspeed selection index - - - Source Set (primary=0/secondary=1/tertiary=2) - - - GPS good to align - - - Waiting for GPS checks to pass - - - Magnetometer fusion (0=not fusing/1=fuse yaw/2=fuse mag) - - - - - EKF3 quaternion defining the rotation from NED to XYZ (autopilot) axes - - - Time since system startup - - - EKF3 core this data is for - - - Quaternion a term - - - Quaternion b term - - - Quaternion c term - - - Quaternion d term - - - - - EKF3 timing information - - - Time since system startup - - - EKF core this message instance applies to - - - count of samples used to create this message - - - smallest IMU sample interval - - - largest IMU sample interval - - - low-passed achieved average time step rate for the EKF (minimum) - - - low-passed achieved average time step rate for the EKF (maximum) - - - accumulated measurement time interval for the delta angle (minimum) - - - accumulated measurement time interval for the delta angle (maximum) - - - accumulated measurement time interval for the delta velocity (minimum) - - - accumulated measurement time interval for the delta velocity (maximum) - - - - - EKF3 Yaw Estimator States - - - Time since system startup - - - EKF3 core this data is for - - - Tilt Error Variance from symbolic equations (rad^2) - - - Tilt Error Variance from difference method (rad^2) - - - - - EKF3 State variances (primary core) - - - Time since system startup - - - EKF3 core this data is for - - - Variance for state 0 (attitude quaternion) - - - Variance for state 1 (attitude quaternion) - - - Variance for state 2 (attitude quaternion) - - - Variance for state 3 (attitude quaternion) - - - Variance for state 4 (velocity-north) - - - Variance for state 5 (velocity-east) - - - Variance for state 6 (velocity-down) - - - Variance for state 7 (position-north) - - - Variance for state 8 (position-east) - - - Variance for state 9 (position-down) - - - Variance for state 10 (delta-angle-bias-x) - - - Variance for state 11 (delta-angle-bias-y) - - - - - more EKF3 State Variances (primary core) - - - Time since system startup - - - EKF3 core this data is for - - - Variance for state 12 (delta-angle-bias-z) - - - Variance for state 13 (delta-velocity-bias-x) - - - Variance for state 14 (delta-velocity-bias-y) - - - Variance for state 15 (delta-velocity-bias-z) - - - Variance for state 16 (Earth-frame mag-field-bias-x) - - - Variance for state 17 (Earth-frame mag-field-bias-y) - - - Variance for state 18 (Earth-frame mag-field-bias-z) - - - Variance for state 19 (body-frame mag-field-bias-x) - - - Variance for state 20 (body-frame mag-field-bias-y) - - - Variance for state 21 (body-frame mag-field-bias-z) - - - Variance for state 22 (wind-north) - - - Variance for state 23 (wind-east) - - - - - EKF Yaw Estimator States - - - Time since system startup - - - EKF core this data is for - - - GSF yaw estimate (deg) - - - GSF yaw estimate 1-Sigma uncertainty (deg) - - - Yaw estimate from individual EKF filter 0 (deg) - - - Yaw estimate from individual EKF filter 1 (deg) - - - Yaw estimate from individual EKF filter 2 (deg) - - - Yaw estimate from individual EKF filter 3 (deg) - - - Yaw estimate from individual EKF filter 4 (deg) - - - Weighting applied to yaw estimate from individual EKF filter 0 - - - Weighting applied to yaw estimate from individual EKF filter 1 - - - Weighting applied to yaw estimate from individual EKF filter 2 - - - Weighting applied to yaw estimate from individual EKF filter 3 - - - Weighting applied to yaw estimate from individual EKF filter 4 - - - - - EKF Yaw Estimator Innovations - - - Time since system startup - - - EKF core this data is for - - - North velocity innovation from individual EKF filter 0 (m/s) - - - North velocity innovation from individual EKF filter 1 (m/s) - - - North velocity innovation from individual EKF filter 2 (m/s) - - - North velocity innovation from individual EKF filter 3 (m/s) - - - North velocity innovation from individual EKF filter 4 (m/s) - - - East velocity innovation from individual EKF filter 0 (m/s) - - - East velocity innovation from individual EKF filter 1 (m/s) - - - East velocity innovation from individual EKF filter 2 (m/s) - - - East velocity innovation from individual EKF filter 3 (m/s) - - - East velocity innovation from individual EKF filter 4 (m/s) - - - - diff --git a/DataLoadAPBin/LogMessageDescriptions/Copter_LegacyDescriptions.json b/DataLoadAPBin/LogMessageDescriptions/Copter_LegacyDescriptions.json new file mode 100644 index 0000000..df82739 --- /dev/null +++ b/DataLoadAPBin/LogMessageDescriptions/Copter_LegacyDescriptions.json @@ -0,0 +1,176 @@ +{ + "source": "Descriptions and enum entries retained from the previous bundled XML for older logs", + "logformats": [ + { + "name": "GPS", + "fields": [ + { + "name": "Status", + "units": "", + "type": "uint8_t", + "enum": { + "name": "AP_GPS::GPS_Status", + "entries": [ + { + "name": "NO_FIX", + "value": 1, + "description": "Receiving valid GPS messages but no lock" + }, + { + "name": "GPS_OK_FIX_2D", + "value": 2, + "description": "Receiving valid messages and 2D lock" + }, + { + "name": "GPS_OK_FIX_3D", + "value": 3, + "description": "Receiving valid messages and 3D lock" + }, + { + "name": "GPS_OK_FIX_3D_DGPS", + "value": 4, + "description": "Receiving valid messages and 3D lock with differential improvements" + }, + { + "name": "GPS_OK_FIX_3D_RTK_FLOAT", + "value": 5, + "description": "Receiving valid messages and 3D RTK Float" + }, + { + "name": "GPS_OK_FIX_3D_RTK_FIXED", + "value": 6, + "description": "Receiving valid messages and 3D RTK Fixed" + } + ] + } + } + ] + }, + { + "name": "HRSC", + "fields": [ + { + "name": "Stat", + "units": "", + "type": "uint8_t", + "description": "RSC state" + } + ] + }, + { + "name": "LDET", + "fields": [ + { + "name": "Flags", + "units": "", + "type": "uint16_t", + "bitmask": { + "name": "Copter::LandDetectorLoggingFlag", + "entries": [ + { + "name": "LARGE_ANGLE_REQUEST", + "value": 256 + } + ] + } + } + ] + }, + { + "name": "RFRN", + "fields": [ + { + "name": "Flags", + "units": "", + "type": "uint8_t", + "bitmask": { + "name": "AP_DAL::RFRNFlags", + "entries": [ + { + "name": "AHRS_AIRSPEED_SENSOR_ENABLED", + "value": 8 + } + ] + } + } + ] + }, + { + "name": "RTC", + "fields": [ + { + "name": "old_utc", + "units": "μs", + "type": "uint64_t", + "description": "old time" + }, + { + "name": "new_utc", + "units": "μs", + "type": "uint64_t", + "description": "new time" + } + ] + }, + { + "name": "SBLM", + "fields": [ + { + "name": "TimeUS", + "units": "", + "type": "uint64_t", + "description": "Time since system startup" + }, + { + "name": "RAx", + "units": "", + "type": "float", + "description": "acceleration around X axis" + }, + { + "name": "RAy", + "units": "", + "type": "float", + "description": "acceleration around Y axis" + }, + { + "name": "RAz", + "units": "", + "type": "float", + "description": "acceleration around Z axis" + } + ], + "description": "Simulated Blimp Rotational Accelerations" + }, + { + "name": "VER", + "fields": [ + { + "name": "BST", + "units": "", + "type": "uint16_t", + "enum": { + "name": "HAL_BOARD_SUBTYPE", + "entries": [ + { + "name": "HAL_BOARD_SUBTYPE_LINUX_AERO", + "value": 1015 + } + ] + } + } + ] + }, + { + "name": "XKF5", + "fields": [ + { + "name": "offset", + "units": "UNKNOWN", + "type": "int16_t * 100", + "description": "Estimated vertical position of the terrain relative to the nav filter zero datum" + } + ] + } + ] +} diff --git a/DataLoadAPBin/LogMessageDescriptions/Copter_LogMessages.json.xz b/DataLoadAPBin/LogMessageDescriptions/Copter_LogMessages.json.xz new file mode 100644 index 0000000000000000000000000000000000000000..ddcb0d84e7f6251795631cc269b7d49097154f36 GIT binary patch literal 41256 zcmV(uKw3TfEgQ_sOX~FNB-ft zJei;je#H@xhhKEVmpwRtDMOOZ+l14%rMRYMzj(X3sJw^|)+k{y5z!0&Wrl6t_L&Q) z%^}6mnPm%wMTXW2@kFW?D*AkJjeJv#d67k#&!F9j61svP{k?*MqorK%1F{{Gm8fuB z7$b8aGlNUo;o5Xg9qkEyNdb3nuiX?IUpupP6@OoNA<%@#rFI@vLP7UtpFhROvkze7 z(nN{&`;Ey_QGNs>t*TT9z08;hY;)ZJP1n?jhM5cR{}lF_F`-!>jYM6#eDKq(Gsr<1 zEj=5pG5%R=3CnNuUeo6>=wpc^UXh#y$M>9ZOd>-P?V>(;6n$I&N&5W z@Y}+|1OP(#S#JST;k&Z>CXUKnv3&P8yUZdM61E% zMG8>c{ed41fo0zkoWvl_zWpP)@&%re5_a3GCU>Dz7Zs?qW?Ne@`41zXQ30C~98P3J z($1F1?pD6jtB49AUTT7piRa6{c4XVjGCS&>XIn(^@5j5)`!oDxyZJ=teHU5`zOw^hhlf^_AR6)TopJX z9XJ1RzG}3@anF@?A^D8diP?pCRVz^R;PbzppFPVn{JD`HDUGD0m3I+dLbpk)s9(xT z=a+~)(WX}mKTBhwJ@j*Wz&s7}v^^d+rQSj0$cnEz&|`LLgn)H1_vN}<@vfB>#YqOH zTNt9B+I|QQ6_LA;G^ULG-;B}Z;pzW(wrJx&MhLeQ_ENGoAi?MC(NU^u<#!b$%i#9JXujZOKr`gl(6c z#UM$aWmf&EtOK@6Zi8B0iyA~`W8p#Qa5Il%iGA6OWY3MnG_TV%-?hYuDEq%pTqMw2 zEyjOIylg&(!6|1`>5hlepT{xzgx97%I->Ug{|94%7ibY#&nLK})|j-TUbr9BIVcZ4 zr7cq3ZuiALI+$%pl#8~dCA>)*&yW)M(OUahOKd`C{a@uZ*x;M}J@^cTSp0#-pOP#U8lYn`P#QB}myOLDW

gDOCvbbOiIpdMeF+Q}8@F2NhFj~&3wU_15MA+|2W90<*>tucEVJg5UyFEc~mV79I`+IZLXh5VDjf%TOzlUMB; zF4u)BKm>D}HlcqwT-czp&*cF}PTRk5{aZ&X)T{P4t1#USIupKUEPy@&eY<6S<3Ivh}gYb7qi)J|O z(e0*WD7$YqLwS37lFg`V4+*s`eTmB~2ZA9J|rE0E6wM02k&D( zihYv+Gl1Hei~QxIBV6UPL=~^fPv8jI0i5VWkhwxtrt|@pYV+g$H~=xw=8@6h9LhFe zl$632z*GLS3Nl zi~SkMG2{DVUy#TQZ8m|0x9S1xS-xR18XZic&QF>|Q5HNvo^^Z~m7;RY#EY)s;1;vsq-;?Ig--Pc56Cpmy3FFNt{+b;gAT+J6Ui8N zsvD%fNO9guzA>t_Qr+R9$Z^Z6*rmrBg0nyf)BU>m-C*hx_hR_ZY>TAPsu3nDUSp}b zQaYNUC*lDt|9RP@VO(#|9GSD=E|vR`=Hv;RVYpHuFiGV8)C5QZMFOM_V{CO~|1ljZ zQU+}Psqq@?>xJX~HgfI$zELJEa-2bI+IzkXg|uVXS342nh=@UZl|=_SIz|U6;2Q%~ z>$TLtQa=m#STFalVo`2Uv#%HX86{ibDyGcE-b;NoOsgZHImSVcX~Xh=M&b5+%;+W~ zNrJ?(DLBFfNsqBb6=}nipJ-X_od@~l5H2Wo_5p>&x9Gom2mDfkx)q+cO z`|+^U*qM?v6{5bF*p;Yq6m`}l9sc>0!IQTxKzL{c21%Af2E9>t6`(fUXXnSFqN_T5 zxh~Cogme5o3M)f($joIIq`fB1fN*I5(kt<;OH}8;L?3zdN+S^d&>C$@TgU1oLL_w9 zY_YQHx!MIMDv}!p!ZQBP3K~ZMq=>GNxIvxUW27Mhp!H1vLo*f@lcRV%g!L3dbXvFd zOSm_PC;(B#opD(G|Ftl#0dNZ#ijaTfq^Hf@sd*O-(g3=q^PoIo&-6)2+62Ch#0O_Z z0j>j1O;}H0n<(kew%73dEmqQ-xNJDF@X5|6#v@FX5lA5ykiugswyups> zUD74Dys9sO$NgTMwS5^DEh-y^4k8pLC81s@cCOVZOyC%;@eS$OETTR|Y)6S_>fCtD z_0cgmMZ^6r2iHaDOHO4y1gl0B|5B{MX#AffF-(tTAWajt*VyPJa_6WgltjfYRwz&@ z`18lWAdcA|5iO;D!B@FG1qb0EXCXgaMJr7wjYBUWSS3aD^tx9*G)X0 zIUUd8U`+Q6P|>#j+Y@wy4Xr)xBs%)eDS;)u+00Q&F8(B(w~Kk~iRk1bvK4TvUCiJ= zpreH~jh;fa%VK7!ERDnK9AMlrfyd2^!b6w64;E25y{%Rn5SYyW&?s0SBP*1_OE`@w zF2;$Mr)!h$K>JjH4U7C)$$APqug_FXTEJup*PCebbX@HfBwqE#6lem0sC1`)i@&7S z@VM%E9~re$z@;+R3;UriVRz>8#s3wXD}f8Up}Wy%1n{b7UKnEgN5CJp^?~&#@`JZ6 z8r*qp81mocW_lPuxmMd+1O&k4_P~?y@iw60j=Bp1u`e7QsA7VG^%{6V`HewNYEGu4 zUqvcJAJ@q};1K}k{aqlsUeN*qrW^g1QdD>~cs&`jW*b8d4A&gWmu&w7SD%Xm z8Gl^>F7MSJMz1LR<4Vm!22}hf=~{J(>wtbs=$@rI8m~5OsOXQSv?hYH0SZiuEVq8) z?odliM4S9l`R3iL#iG_})*PkZN@SS{1h zQq98G8Hs57%&qi!{)()GWF_mufhIqaGWlMe4n={}%(cshe0vf$`M?%Xa3?=W-N1=~ z`J**uqG-5G|1=(qS6WWcUe%P@w>2qa0aT0tPf>JH>ijuLR})vzf)b2A9(SVHY7g)@ zU453{3j-@&evy#`6@0{ja7!1IBK~Rs{Lf9(BUfAdH!`90J7KdhRUlK|Y&K#o3n@_yaWdsL)wMChwV`s^UUGJ#$cijpnTVNP&0bEV zGhC)?oHDRDx^(Pm_1AeFvRsanQ)eYWp7?x(|fKvITDa!Pd@uDZCUY ztU%c~F3ybtrcEQ^36YO_*)F|$^<6F#nDz)qGLp}0Z-Zy`Ji^CdGfv)8Q=y}bDIVSy zJoy(l?YeWu_)hCa$o+Ca7jL&{ohep~+*jzxx|6!R+hhrmqFb}!XW-z$viGB|!6lufSZqKfriS8WwX3=bLm95~1t44Gar z#_kcVuL~jkY6b|o`_P{$O${4Lze*p|lCeK=Qd^;Ae6=wgXhf}qVmXR7rDTK0LG~!K z3!bqqwlX=dsh}awJX2zHv(aopdjy2H4>Y#;?GLSjcNS%Xw5>v^6m*8f7LK{5iQ8DL zE0#R4>4Rpx6-36wWJsGQIG_sR3)i(^OyYuY=>bYs&?t*4s{W!>D;sU*fPf%f?9EYz zhJ2^Zz-|BSu(Nr|em?x|=3IMv=QMIm-SnV^z&Lr^$@An8td#JJimC6zGK_igc0LJP z0zdv&04!jK0FoIg&!4f|v&N>%(2PCz;ybu~)JAh$d`2gcKZ<(=tm%%?PtKbn3Z;O* zmJ+bMd(_742lUiSSd6nyuM-C}Y}5-xdz0uvZGoGdUf-eCY?XB4(|Xr)Y^(_|HmoL8 z_6uGqjh5j{S1w7qCkdcvJa08pd)p{p(Bm5UST#s2f-d2`r^vjZyJ1Qmt`FMSaOMp6 z#oD1I5-toC+1J&9b&A&W-sRZe)Lk_yBHr@sG6r+q-F#6pR&?00?mXH>$vEW3pUIc5 zA(X;8t~`7xkgCsmTW(InoW6?gp>x1Mvax@OOJeSowpR&F006wsRRnVE9Da()E>s34 zH8;VsaCGDxo*kcoS@OvXvNJX|`Vnvffnsr8^8J3kZ|K4=OgS9<(emz6O%>%7;g}M5 zRbk<4-2_6=NH;j8_P)c#tpG>}r-KA;jrPU;TKcs#dhGoj_(MCtDpQg<1AE{86IGJc zg%nPm(v7G*B=h2U6cs3mS_>b=cC05$h!P0`AwSzyvDg{t{*?%SpaGAS=1Rs5FRZKg ztD{;!y{C$BFm~al1#e@E_QUi#$5L+?4+`DZgRrpTylW#W0pGsEhI!xxMK}k1!)`-c zgh_)A%0+VhPEa2Xs4pMw9=!;=^fILrstTzY^$tGalj#SxlZC zgB{xsHq?BD>o7TTWoexMDef}0Y#d>Z*`UnXKQs4ZrG8K{(m#`NII7yG52)UXusBM_ zPWih__h<@$>`vSM>_0J5Ka%M_ps2qKD!A0ta!2WDhjE9F$Wf&LhzcQ;5Z!gc>G;7n zcP+=dU-?KvKQiPHUlYBnBY8DSd(t!{jp>)Dc0!GRh}E_Z?H%ctHo)lZ9SR{Ym*I+q zfM0egMdpzPR2C#*O$3250527^81iE_xNN~4l}vc^_42=G#-b;kpTpTrFkty85IiP6 zp`+MOl>WmgQNKV{>3A2Z`{6^F!#XH}=uWsxq-9Spuvu%f#5y{5Ejm#r&(kmtyYc{?PY%sEpZw7pw)Q1`z zSoN{IegFYA->I#1BrDTU0C^*Wko69+td;+yuT-+os~tb~I$4(k!#B4a*9eSRLT)xq z?3Wg}c^opJ!~27A_!@W>cdSx&{sbJ$Xm$mz=$brq9}CEj$f zVeYC$&^MR+Z6;YfGH#LAUBW{yy0m8yJ+czRANe1B9c^r^OUePvrqD{0LPBnf%!yobkY;w%4d@kP(MoPgL1p92yMvbTuuoUjDmVG7S!XArRx~r z2YMEX65V!}M$KD}&*miLu`GgwYMujN2=GOkLDEXrPHU{lzN!y03r>iq^WGEok z;5-4r*20L)lCXZQKTqvQ4FWUH#?fBVqI19rb4nI8qnwUYC1WFVcjax@1}V%5FUW~= zrk2W{K^iA5V+yoGu+;}A^bC7Il}dVUQPIt^Hf}TwNq$iu27|Sn)=>zmg;6+J>!CsA zOG~Z4Vqy@SmBFxV4BB_& z_2*p@$-O6MA%5?CsiD+ZG!W3jGH!)#6XV@gB!nbfz?C1g6IzV_Dj8Y>;}H$2$wVWY z?%!6qIHHd}fJ6#gj5CY5Ud<)WMmSFh-0KKOKaqg#1CcN%+&K{n-9l5yQ>Afj|9y&_#AU*aKw4jQCdQv7Ml-b&Kj=CESn ziK+5}s2|b!;p(cQteA>K5#d-%afA8ARUIe@v*2z+rU}g@25%Tln>hZ=-SG@eN(AVCN#bqi8s<{ej!A z__}9W50g-U3Dah*A)?kBoueOr+Q~WM>>~9(MRd}2gdxNZEbK2$v(z?(3HHZ~>%#4i zaHe^JlHsP)N#Z{QhKcEH>?$1X4Dq#q)t`kYqXmU$rTK;RrKf~%WA#LTzf)h=I$ej~BLmWY8@1 zy|>zi^9a;mV$Uf*&?S8a+<7ecq?(4^=RQm0iSzzZ0RiXt<~qa<-w{g9b3wIG?i$$& zpf<86&?_qaBojh9=b;?o`@I0~RHn)<1xf(_0b6E8k`D)dh>A2)7#tAC!OVFX?>@xx zYc@xDgdG!0gH*pRPvMKD|8k#3=a9n(DO<^ArTijGv1T&CtdO|1at_WhP!}J4OAL;P zh#OAKcyy{I@VI?dH^Nw*o&Zt-UklXWaBhYjPyo>)QqbC6Wn(_%W`$poiv=km_YtdH zbkgK-zn>CdwA2|3+-ypFj%n}oj6dhFuZTV*b?WR=C-%MVFQK)|--~Jp`|iNr4xcQ+ zsDV%M#aiRwn#7ZE`yGCF%PY<7R8Pqz8OgdkPrzy`hM=j)16Ecc3@n=%s^_DmH_)7Z zElw03?Sw#)E{PyLH#CGl?sp>Ak?7Ypu~6UFeSJ#=P6++{e@)MKe+c(`%V9kUzJKa? zLEWRwollb5FRt}j-7b)amt0gyVTNhq6#dMYhsz=u%S}7x>9OgUKRB{U@3F5kK3Q@z z*;gBnTBh%-YDfigzdcKh7E=V%RCcT^S0W75w?liqj2`B&HYPH1kjuEJMYP6impg6z|jkm z8R&phdwB~kH{#G-iZ4Wu*N1uA%HmiifPPW_BQ-^AHTzA02jB3BPL^^KBPuTBL?_(&BC6e3AsRv>mY5jfz=Xi|hA4@v)dY5gnH&z2c zS8LxkP1<_- z!~SQWFPDKjiE#ib zlC$}|oy9LvmmhXzDEud~e&^p$01xA6J8HSRcAYUnFT0G~=1wmSoO8~GlFwU#c zQW@UZy#*%vpR2fD($A2@8Nk339yPzNV=GmKvsJw#d_UDJM!W8Xv(v6LzbP(Idm%?= zq!Cwk1%6F^T^l|5HU=K!*6X>-;DVR|nxqR)r~bO~d_vi6LV)rYLI%Ro&BXcHjv<)< zD86ELBY;?J$k z<%eRfVL6^|K(RWm6tOzQ@m`42(y=QBH)EYrOWx1X(~oPOWl_ThUaxjWfch9#y52R# zUu%W8z`y;v!s-_0!B3c$y1ZQM(s86gBWni{s6vR>)b;{8JX4CQ?^gj5H_Z^t>w-4~s;|f>AVSUW1%3~t?$RYbr zpycOPEtuy*Ra~v%id2dCaONKTvBJ|BxLlfoto?4+xk~Ts@h}kdfqiU*yf#!le}{?S z98n%%uC zKP;~xP$t-x8cQ1A$?7514_g}nde=cc;2{F*nth^-I$(*xV?&i@Y`ypTcM0AHtK*4= zV?1F;*UC-i4g*M4*g~jJX!_K-Eg)DXAcJ`-xkz~Y4-r(^B#eg;ZV9z;V_T_ed7524ut3SH-G#i-zf4^fM%3?G!%C7pLS9M|4=EM?y3Bsg2hG61;2spenx zD0Fi@lTdR+T9^tuSdV0!q5=M~i3g6IWV3(~ckUhYxZ;-Ox-7}bW&lol4wbSG)GhYI zq=4nNoMlDx<-$mQ*B0-jUh?J{8_S($yNHJ4ZkGQRHPtFkccXU(78VvNUq0ByIYhRR zv*=yV=l`3#%dNrfPad2o2Tp$yz`4UR2g+kOjWli7C|QHtpGcJftzm#$ zW{&H0#cM`Pp8KDSUhsBSXT0a~&;KkY`Pf_UmChVa_Ry6`yW3{>(=g7s7>}*zM3s$h7TSl*G^4cRV%T#)5kMFxrpFc;0RCn8{xPx zw_klshb}D|U=3eW_HM8~*RJ>w3tUGm$!-pT>ts%_gnzVDRm4LxBN370GiVKy;Pw+B z<)i5Kgv)>#9yjT6GozBx$(^4*R6Ya;aDdx)F2M7n*OLlGSMrR%b~lG-yesTt4wh zMWKAfr%9GqFbUS(X3hD+O;O2sob5-%Iq5{L)MZ{bzu=I+Fzdf|SV7U@AA_*?*~S8$ z1HV#@CTp>_xaG^DqGYG5E*L_GK!o)xXJ9SOASy*_1hJx0g0?V!C3pmKO6Q_7CIgl< za?5w&L1(;aSUTPajzLQlf1H7ryQXo?(BQHIuEqCmENgxxri>C%cRfg^?1^DO0hk_P z1E_m*iSv1@M%o5>o3YVsB|_=x;t7o)+ zJQtt5*bY)R%$`!0=7?CsF&XYK6V-})ICj8!01vuEx*Ni+D<_Nd4l7_GJ4oC*Ib%Y0 zf;*d2$|l0yQ#p#;Z{sIN@iFQO8PHOTILL2H3T-!vQ*sX$ZTX-bIfUDya>s!{!Yh(8 z*!;o*@B9Tjo%r=ggTF}jxd!UY2;EGISoVi8vVz$^__+-cts`JTK#y%9^tPoX1 z>;3fcz^6|InC09y9q<<~v8T`j4UbV;zFOSOGj=3+H0}y$oPC|NkJw7`mzxo=%Ikf8 zX^eb)jznFAjX$)<8m^yRrNlCMPd;F8O2tWTeb241=r6^!TQ#wvnf#3l;+jl6Af7dL zI*=rFe=FfrW;VJwzD1hFa4-}Y%$)7tcjEz|zT%zi2Cpp;C=PzP&d!uC{TipKR8$~D zC+&#pgejl^(Z^FPg#8P&!Y-1Vc7`;QpIM3H&LZ^?g`)VBS8?@VyRD3m(~Q$h4wP3` zTJUS~UZVZRmZ>LPPLQEf{x49tc#Pv`VFQSv98U#Le2^^1#g8ZzGY7iGR$~GRk%)a& zY{-UvFW#zTJJ3cw|DM4* z0;sG4USz(IYM%~oH}|+!HS|yNy3t+ueCqnb4KlWhUb0R*)FkH+@=kU<^yFc{h_{)f zf@qqw!CUrK&*$Q8b|?88rYXOy%qIZY`JcHS{QHiWdnnoAaO>&{H1(yei~ouTj$a@@ zs$xupr&v;)4CLAg=Fa7~A)t8DwWUSwV)MLk&23SE#JbooGwbPY-xhRC_klU4)5*po za+GrW*{9u+7Gi97rA%1~&gyC1Mzr9+qK>7NdlCzsAWWLEQKr_Orp*Xk`g5w12rlb> zQMEe`{%e?oEU(8Ze3fdZCs$1Z;&cbfxQM2sB1T9i^j?amHoDrS=1q#6J8sLPf$IuyQ zciKp;CW0k(!;&Du9^ljv^es6RYPqc1B}Q>mlq(7l3u|lNu3(zAoLYZ|<(wR7cm6JQ zQ)#x{scI_-!{y^`Cr!P6t>!It?kK8%4H*=FlvL8LrD{^z8N@I!t#%-{?_dD3Yqs;k zvh6o&gYeHvVZS82RzU}TP!}qk6kjNuN@Y7asOPDqct$LCK4{@D=|fQR`r;6|p+g3u zF@$JpT(T;9Cdx1P!?2g}#?)M{0z9y0o>S~( zh2`y_+!7f%)fk*CYn8S&+vBX^?^^SG?sG35k$35l4Jq!BKp3E8W=`hWFhDG#Wk=p*IWu!24OX=8&uP|;oL zUH#B2RkcF>G(2yS=8<#;us@(efSfiT5)~m6;EMQb*4H3oWc?)x+*Pe1jISCb<;Ght z1x~1L1h`@N5KqY?Ko_g4!D_#GtvS~ZH|p2#WM&b;3NV%4?IQXOdg_q#*0cTG8IX%H zJ%E<%%odrs-CRuUSz%7MbNe$~66{OQr4lX3 z7!LWO+&ZoYVTq&|U$@WHgjn40Y$v%t{gb6;p?9|Q8Z!@=B zH~n)8U$7rR2D}$u8@Jz{p%JARxQcI0^Y-!EUQ#fF6%gw@0Fq`CuIK*6ki-^`wA9!! z4HFjGEs;?XfLRT6qE~Rojp~~4L9+Lm_!fd}$`{Y`O}Ro{`@Alx+6TME_)it@@X6zA zuGTZK0-h!fc+lkzdv61^_jmPt5uWD*O=Y zJcGOk*9|2*tm;n|1&3^};UMOZb~LIUx6Z|2IJckesXw58Xk_*nU$6si9vj@cMy>9Z zR6~bfqb%rIeVe4#G`#qrk7J@-osoINQ;YgReD`MoGb?S@Cpk*Wq^J9-nRrW$&HVIN+Nqd`U z*QiH6yTRDuYe+&jNXdFh-Vyr#6~xUtzrW&b?A700Mg!eR-I8%@L0SKO-4*g@p{Ga8 z7~>RID{hzIRu_Nl9m()#H~T<%H`Dw+3a5|;-{C|LS*GN~_p!p8HdEL}vc({d-Cafa z0P`ZZoq~zQGonJpf2|A2ARhv^3$tn0qlcUhZdt{+fU^p(W1l=8B}cG_!U3lINZB$E z+OeGa;ntP-3`c$;EQ|cv8znA04BJ?S(j}g{XsBXI8KrH($Uzx27B;^7kW5xGS4{-@ z-Lt0XMHcB`ZEEo|t#A4K)HnD+P_ye^ZJBcRpRnsEE^tI!i8MB9a`aj=Z6UzU;a1lP zRc=}W3|3YJcCAf0LHf1YYL1g z-SlT3A+8r9k9dK0>;JqV5q$Je2(34y;olHOxe#azVpS1Kb@ksRrBLNB6x!;7x~a~^ z2LPAsS2ElX@{(Fq3wUCkKHU)Q>idD7cK{sHPT)#)uLNr+&g$_ANiratQmD+wi(GXyaSv91viMG((s?Qh4)&!lcsQ=muMBg~b>KeOR- z2f1QI`8tU}Wq{!8$p__4+oM%kUkmm6^%V0g0W}&|UhvhBz874rQNW{@aro8nVFM?a z`f!Xr>Y16%(@ne%U6t~Zip!88Wxc`+yi>l&_m0nh)*TLXsRN||vC&qVZcV~>9+B3S ztRei{PRGH3IhlnG`XHGb;8Q*(&nOyRG5>#D5i@H@O?=uZ9D=bvyr?6$GWgi()XV+K z&d&FAT^8p5OEl2T@rUsUjmTOk(77k~5zDuXD^zLVR1Q3{VVK}O;+N!H&8^cL=X|IB z!{a&w>24~0wnm7P!1j5d>m)k&*6C^bOi;c0S-JNJK9FzYgD-@WjoomyGelqH)Y z7bBaBjiGC7YDZ6Iqut=E`Iw>^T^mev`o`YznqP`D8H-t^x=V(FuwlQ+@@t>GY$b2( z?X(|}kyzFGi~o&=7c|*!gQQ=wA;-Hf(wwSAZ20z`VCc<@Lu(%cU@c@P?K;eHwQA!% z7K)V|EYpe<)pQbUhlfcUVMVClzG4)cT#|MIk7=vm&z&r(UjKvjMi1gRRaNkNFmX@WM~WbLY$5JFP=i9I*<3#$8FFsQgMiXt$sLuaL~ zLFGs_l80>F!snwgi$RMw3LRb?(`Q;#s6#abC#G3qvx-X!>OqeS;fa`8Xg2->0TZ3J z<1s^Jvkk{@KXyk$?<^0DpN__ugHi%xRCJrO(1HLvJzZd`3Kb@N5hE0Xc4&nnDu=Qy zS6#}YSqM>`3YaiaqcJ3HGe(}9;XT6_dPsqTkC>xSt!Fok!jw$Sx(2;!QW`Yag6&py zV?R;)hykT3gjXf}Jh!^epO>MSe>6g{4l6Fy9$4F2SbjWVZIf9;Lrb+&h&Jx>(TZ}P zcktTB`#g|gq+!9xA*F)cm^=CKRA?o#qhjPcNX+w1_2jj2$GjDX;gfv=r(U@91A%>u zlRy_yz6WXa*Dd#o&vi)FSA#l)Tai`7r;G|Qvcs{)-=}1M#n?>tGdG?!)c%t`XMu+_ z=a2)-mts*Dnei*D`un%yCdLdvQPPPR!|G`w8N~U51_}urE>B*GA+<{N|Jj&W?dK=92G}MsOdERLnnX#1vG8UkE82Q^^k!gHVLa zg1&9*HMP~E&HNWH_GTMDHoS(z1Si9&4s5@(fLEaC84>5lqT0(<1KM01KMqw#tsaY> zM3nHtaEn`)5xDV-%7+YwCTk0d1)6QsoQ7u`>i8+T z1q@SPxBQUcxhY|#JWugRU-t2uF9lV3-RCqeW%MQ2){(UqSPIO(so7hcL#`QrN^!huk5>%FSLSi-UVn(% zn6HpKpiZommT;S62$GxjHobPAzBcON8jh>bw{l@nNZ}nccfbs&YG`#Oe_^b1~>D;zDHNv8d^m%&6 zP<<}L$n4ScX?!lHDeVt>OL4VoNRgw%;<|9Nc&we)IpB`nOmLJDBY}zfWC~8n`XC&* zP2r~FS|?hM|BQ?>as5Sog;}r@w977LV#|sN0K67#QiI#Zo6ql=K>FgPlvtwj#;9mB zOL+j&QMxV4+mtSQ$CY4wEi#gc_{cB7dFg=?+lrffuVy$8X5^1F3%Fs^WDI=wn8AZ! ztsuL71sda84MhZm45Kwtfy4iTAjWm;{vo}R3~^zG0OEKJ04U2XXCEj98{oJKS!DD< zAhIT9^=mxhoySg9kN=YPm4*72gI+M+{TBFxH2pgPCs7yI`t7zb=G%dP1(x-_UkuFM zyd4M+PR9G03wj9T?YL6`cDk6E4ea7K2d8Ns`QAUo#af3~w7D^0x@}(Zkk`;+g5Ec( z;LJRyh!*y>)8XO`O;i4Gl~YbO)DF6Y&#>3S((J(bx?sPi*ueI#I9bUGUr^#2G24Jq zMtw)taVm6H4pB_R1=^o;Q0Vy6I5Yqma9FXc7Fb&e4I zH|!Ym=T-lz)tXMi?t%^%f%zX$-uZvuw|ZMB2#0VROhRmh^`8%^dqcx`Y!Gd{PeU!y z@p1og#)SXHNZ(wZuGASGrX2HB$=ClQ8O!Kbe1wwAN9PqR4CJ8~lJ-0_cde1MH5cjlWRE36ZLo2$SZ&35)E+3>G7$Q_Xe zUJuga%93nMi12HLX5TI!ZbyUkX896sM?_4)U$Zgu17-vfo@BrAMgCk+NVt-}J_DQh z3MMN#Su89*N54k*P?1h@EjnGdr`~GhTjA?Mrtn6)wIFCl_k4|uP$a*LJ8jBbVK)R9 zfmShb&KX}@>($xZQ9hr0BP_R#uxy;1xG0p-( zU>|R|%#LBeL+!UeP~(Qi@^REy=7%tABj79}k4eWTf|6rOzeQ%D7w|yK7y+F#_WG2j zO$VWFLD~m>>8^e7QtxY(@$6PI$syG9uiXQ;qfWpVC$#n~pMd8l7DbnDbxjFCcLh_6 zbB_Ovcdjt+odBUJsHdq#$@pkDAd1)W5P_nz-zqBj<{xUO8V1nF77$9j{CuOT$Pe|* zLzc98=nMeZ=LExnnJq2C?teu3IkV`33#o%PpZoz_j)3|6gunR2&@eUA4EAW>$#0WP z*Gjw#06N~tOHd(@iv@ny+g{(m{WXNsv$edHexOU~-WkFyFl_!%SN_YdbPLSaqUEv^ z&|OjbB7p6D4cs5)T`Kfib=;EykxFqdG~Wa9B=$ZzW!L|2`vMChj+@~zLe&+C`od=w zG!8C2G!4B2XfTR}lDUq>X08VKa)zX=RLB>RqDg#t6&;O4Mg_ocmcpF87W zo=|V2RobiAGt2n(kTT+NO0**$)bN9zx^fX!^Iexly)>86%CSBOhU4p~ZGVAtPO>J^*v4#N#sIuU%-;%E;(26z z(B!{>&M5s5;Ai*chUn|gKT_YJI;R5M$s;SScynEnD*+oSa_pE<9ml-7eRKo=+PYPR zfmVrE1V`AvGV24k;{DrzU%vpUdW#G|xodJXEK{qHH50lblmAP`aB43EJ8}IEg}>8) ztF+*nAIiFW61n=0bl^!3sFGj5*w8_`egSyT$e)18shLt)Q@^uHi+x0F^G934lC~W~ z3wO{C2XMEX0=6(+WRQU(0ahH@>7LB}B(PO&cN1s&w+C_Zq(tZ0-2ZV0J|N6Y*ZT&* zU^dlArv2(7 z6c9$lEt7(ZSA0~spp~0hXft&)cNq8TLa__<4F#^0?YSxo%-kPu5*1dt1P=t+r`3UOgJp^Was`;~*bgDo&(VHbZYV5b8yx0LUVFQIAzs zk+_Q)%~b^|Yla4M#toK6;bGJP0v{t$n<-g+H8}%n9wD@MJuv`|Fea!VG!})_tg)*+ zXvln^Tit(H2`nLtM4@+zYsZtSMhWqSVy6*k{2)q`gReDbL@Ws)CJsJVJjjj>u+aB$ zo*D+ghOb9~Y_|1P;PQH)G~dj6^y83U)K2Rb=1t!9)Hsu4F#Bb9{nh_oh6UQjl}E|+ z_YvliA{GBmOhm4X^)q0rrPjjH+2rj;=PFzsYHExGh-cH8$TNHht0Lel>rErb7y~u* z17J+u{}b?m&4=0Bl?*|um(@gX;iKMkANm~@@;?!4<#-MYmiBEQFAGYmjo&40rwNo#h)({%f#@(8E`~*0x3<4w|9Xsi=&9B(4}eVC4Pax=CAc==~4ky^al{-B#oB0yvulDfZ;y?-UJu# zeb?a0Wmhml3rY)xGWMP29YxCbbAEs!?ggdx(EIUjTR|Ik%1U`Ak*my%cz8DpT5+wU zi1Sh~Q!1)@VBXe*%hLF&Qi@eRTASfez!cFhBX*cDR^MrrpOkEEHhyK8FNTael^%^G zOLg1c-!=+E{qeZWFptThSUND%^+>_V^*iG)aMj^jpV>Fmb3io zCi~Qc+tc%di4ys&o~*hR#)M|X@K-C!*XdCP4df0ElBHB~xewj~kz~qH$$k~q#-&8GhQ!|hf0MQRL?X5X{rl$6 zu|MKES4oHlZw!*@{KV{WZ%e1RE$q4QN02GuAB!7%f^w%Ta7a)$1bm_0P#5w$4N~lR z`{2!S96CjeC3Yld`d!c5Ae*HCBS750S)qlKVuX4nKeLSgaG04n zSwJyeXI%ICz=BwXd83TVd33d?t<^}Z5#=%?jdyX19thuDLpE_Qn)}pX!>%xFd58ON zryL&e?{MV6juKu%Urd4~34aUN7Q`*WIpm#b-|pEO^)#?)>|btJeXtp>`Oz&dekL8T znZLPY=dSveDM8={4eA%WjtQ$K!h#iUL1lG%2H>6f&b2V3u&ZbU)xUdpoZ(LrH&V?rW^|#RU9ee( zVdO)8=Lj12wAX8kuPgLL1F)@Q;aY{gi#S572cc8gS%Kg?9Lh02;mV~J<_n^x(WuMM zj92O&JnS(0B_((kQ5nIF{pIA>ES1BW(mT}+u@&$Q=GXnxF&sz-dePLo_;*Tftc0j2 ztO@dKP10oOkI`X29sjeQzIF_0F*}0jZC}JAq^HtGpW{t1Rw<3@%H!=BfHBc;`OfxO z>R+ObG(qPpgY5aEK{4tr1-zDd!mMV$Yx(cOYUS^KK{6HKMm5_ zR9|~OlH0ynWGV9Qi?wf7+&uvecCsL*$SF6s`ua&+%Wdoh2BT*-M&A{Xt7 zk#fcZTi|Z`Rz7A;?%}HPWC)x9;WU7~!)jWDKY~9@d(k60Udkeac&NFD4RFd>Q7ajc z#%5$a(LR!t%YI%58rgs`R{a=TM5Jj^>+1vgvLc!lUw#05A`?GRfRC$f!v~>-HnEeX z-J3kQnp`$rc_6;mu?KqyGpKT13I96e<_Q4Hl`l;{c?2@BKx#j&bO)p!N4?#2^{hiA z0HTIc0idHVx5It=ZXyQ8-sUqH8M5PGTrw{2!=ec9`>6rpp`Jt_DiPA*H#*4Kb{P!Z z(_$R8j3pWwQ+YKi8&G8Kv3W-$RJyJJ=iSNn;}4EfjcQ9dcP*AZp~WOgnH<+PV-R!p zYV@hB8P)|Anqo%jlxb_R4clgJ;R>W=CLIM$XwRtav-8W_$Cp3UGfU<`>g;2lBy{xN zPiScG1+wX2-V^I(o^%FW=+%_2slXj@j?U~*sCsG%L^r)?Z0D&xn8#H5tn*LzO$xt= zC9}?d>iMRAVbP@mAc5sMO3N*`QK*eTq_As0%Ow@7bF&1tdFnbT{XWExxmw_u&7rVR zk@kHsWMdEIQKUYmYm)#p2%f$z9?x6a%p&&G-kr zN$$bo!smm5<TTzP3^NHGe@ft^~=$*4Lnu*{UyS$$BY$nkkm*OYjS>^XnR_6&0bD1N8bS6EKY>wu z4f@bGh{}fWD&xi=1kR*&@h`XjEsjhogaWa4h3*d;Ec5K693S7Gxx1*T{HaqphgTTO z+fR(a_Xw(%5fbbXV*&C4995O*ZBLA*C8}}cwD>yf2oRE}3_uukoQ_OS;1DreON89j zH#AlJF;XCLgqa}Pg?8_=-FTcVs~7plap09qSF(@8?80}< zg{u?-OH~xKMZpKa>oO50?L(XMGN6Y`wtl~en|0l<033FB5+$j4yt&Kp5ifH6^(8m36OkpdgAl5B5X)^2)SSGQsCEyGIBx3?eUu@NW z|5+agRbSo!8AVp=GJb!vz=yp9akXQ)--TsjY%SP`#j8`nz58P1Z`d9J5-=k)S$C2q zo=45c4eA1xx9=Z9JSE3FUN`gn9pXf-Av$%EwMh~JtD!{%LRQ?q&*e-_kJ3QhQ-i6+ z>vx6kCAa39mcSthf3ekiPkwxJ1qBll!*+rIBcx;Z5roxL8y#TURGB(EhtW{b;Db~Y zd66?>%`H@2-`WT58EDj5VdbE4>}(C@G8$Z}$awyzkt!C!13p~FBVYH_Uc znphNH;zE%QSH3Pw|65CS+t6&wo4q;@uDQ%2IDE?Ysd{0^Bk3hfb>eaGu7>>6Gi?%2LFe**{x^#@;$>t+sod5 z^zEvgs?0bdnNqD5(_W`gY)~&C_-uZU>emZ3cBJs<(?L zgk@`nIhu28AA~1tTPn)3+qH}aP42IDMD(_ zdTs=2(^1#ciBHWql+jsu6c{>k(tcr&E^WUTp^IxLa2qTb6Jly)`es7~yt0?p>=H$7 zWT2jKyF4}I)3hj?RK@H4B+X=V4Lu~E^|FHR{h2{3;v~f+K2Tyi^{Q;h7sG5Wt(B0ZlRJM>932< zwagcuUE&QwOpw0!5^ww-$_NO_-hlN+K7{%pUgKqu&5_ zV0D{Vo0Ejz@@E_LHXiO&rb6`}J8=zpRZY#l~@xTJO7tJZH)uSZ*<8Z3{|6O6W1oFy&Mm~_4M zB z#H`L{?42X11=BM{c%GI$B6Q3E&0;5trqz?``jc-`i4|&9?S%tTA%S14sfT|kj#>ct zx&h0by0ZXh*g6#i3`^N66HXvpZ3oBwg=XJ?JALcNE1N&#J_GVn*rfkA&_M0)A@Zqy zD(`5{`pLpz+!5pj8Z0!}y0R$k^^T>&0P;R+7;L4+VAg;U8{jbV#W#k5fm3M}{=-!} ziKIF86JC@S-H9VIrHs$)dx}FsI8m-!=&$e#R4;vyaRGd_Yd6&soM581oxB5ZCeMP% zg&8HQI|a6*obtjfI1?BZ6MvKy1wYPZGv(T`T*M5(X2E}^kpv6P*w%xRvx8h~3O!K| zPbQ(6VSLL<`o#LQ%wH>oG^SpI(BR&uw$XrfZdcpsy!lXo@4f1)hIH?Nem)LHA9^!+!B-d*5}c$`2R(>9F;z2$OBNV( zxPktKl&k}Xti&1zMcSV#IF_gjs$_nYI+ci{L>f&!L;wb_bGC6!yYrXt`u5#Vq3v=~ zqeNlw{&2v8g7D`98UUL5hwRV}Zl1VFjG1gm z49Ur<12%n|H+4t!pr+7NsLsN!uHd*iDptBasakU|1qh&qT`m82%$TZ5fsd|rX-hg? z-+TJ1h?d$O{u_p`l@8Q`8yOfxi!Zm!d|s>^o!2mJhgg^b%PaPEsdIHWdmuNY6(iXp zaFXNXsbNncXA_Lt24{(EQVv1uWkAY8H@?eOc|1@nw5I93aHcS;oKSD}w9A zgewh`T=k|D$*p=+wmYW@UTfSDXBX0mXm4bdO$4%G1}Vr>Z8nup_7R{lV&vsGIk9r0 zLM@cWgQn^s7kVQ{lCOk?+gLzf3vgGZte($qMG}28R65I@SQEBq@O?K-H~)lEENf$( zK)*3}e?@T26fjr^oSIYsqj@uo8433g%XnQaZ9HUf0e~*}Wp;(Cl-pFBt=R!o)JYFY zdJ*V0v%K`mLC%60Kz^6{%O(78I_qkSyDh+c=7=`=o8!@iZU^=A&D2vD5aXp9>(!T; zZ+>0plNOIl_7CbuPWYCugy$gyFw_U-(KC^Mn?8Qlh zzR@Ty66?L9S_@em%9-t>@iU5z;wdS=d#eeuG9=1C>?UdgMW*q^+N=0%T^ z8z60N+3!9u+O-&7|FaQe=o`(X@1PH=X!;Px-&k(P38V!|F?EwW%L_vJS~ubyw(NI) z0tU$?{}Fp9Kr{$w>836C;*xIi zJaFxjI$oi~Q9>P@lW^baT;we%q|*LWLQvP1u0Z%+f!U*)S6GXdhm}TCyKgVJ4vCLu zVDB0p<&@Ukv6ud6%|`ebv*t%ppOzhKnJbI$eS;8=qWXG|o|%MkR!$R#{(RgF0^_8^ zNz{^p0aLwgizpiJHU~gea&Pj4%#1fh=Cvhf7g{z0;6Dybd!39yQC1EClW=?+X}lt< zSN32*LU6n(x^KyEu~Et%xuuMZIcCks=`~c&C%TLJ?2Kqi|iF@8kZgyjgx>_f80?z#c=fB@%C_ z3}ebK06(Tuw)lB=khS|}M8*(m?1A-J>xtIb8gK*&6@Z9EnsVR_VX_~_pmFlKS+f?w zzP{A0eGrK#_mONVUe)2aj&n~SMgPvS$^a_q)bB-J?wgkeB^I$84|Mu8&T~8Ut&|!_ z(Fuz30BJ)i9qH1W(VGkz-#oIOJ%J8C#LLfJcO;!KUwAEIA+L>`&a)kn2h#uQ1aU-Y z(*sw_$xoF6k#O~!y(|FJbBgWkp~%Pp6Y_aCL_RI8N?CT?m!#=BL3u%~+&z0cMZDOg z)o-hYQYd&KGFB&vdk_!L&jHi=tLFDjHi`H%WTGMf9 zoWtp(Mtz1)El~*E&nSnOS%ndpYY+Lzd<5%XqZ&hjBpf|bo5DYh7(?3upm$;|PhGC* zp(vUrT@dSq#gL=fBJegQkCl0nwWV6zxK)OXlL0y zU;i0~qq{nyBal488W17$S>i1DW#7^gWvyA1N#P0L;GKH$p5pfH^Z;OGH;$S_aLbx^ zlF4>BUQ{Esaut?c-`@+jysgsLk~0vdRC&@SuVLZA-xZ4}+arti4a5MvcoL|+p_$1S~4q0=Z5@<^mUq6`?j#kABgNfk1#r5*(gAm%%JH! zhr8^T8%b}!5Vy8NtX_!bX(fXPbq2rlUh^Om%CVPiYry9#9M z#Cm(Xz>6q5e5m;rM?^Hr7(JctGd%Sl_iKl~PTpp?HUPDEJ1w#7uNY$UxsrtQ4+MfS z>QWx&I}q%EV&==g0iLul9PzDn_R1qq|H_LqkPp%Iu4Ct2#W`h|KMSUPRAd4j({ua=3(ysaAw?h>qA?l>n`+QtY+HwQg{}E%F zt1Noxmbo>9W|vAa58jYU zS+g@%<(UntmqD0r*7CRECc*^WiR`QmW0~8ml@n1hv8@>g^`n7#HJyEEK^w3vDNhr=kSs;Frev+N=4-Z34|Z8nA0o9ELc zt7G4+tZpupgZ_sLZvB4C&i-I}@MXU183)F52Fxh~Znf3r1DK19-sK7G|F;X{&ix z-vcVHNhzNC>)LFa6?Y_~$sTf$7*Qsd_8fZ^^E|wKW&_rufTz%UR9PjpunSs_YeXU}1X$T}}gc zGs&iaLN)fl!f9!>M%cvIBxs2sG&zc){aD~o*48!Fa(U74swO>Oo>$r|79Glp_|cTI z2)EK@Cz(uoP}HHBU7ML0?Nr)q8XbrisIQfuKmtMX*+3ZGo+0M*yeAM>H4jNS_i7|o zUEB2ad=-YpGlGlX+wH#%2=08n{Ju!y^U(=*i>=l21qfG4F5pw305WzqwQi7Q{yWPR zdMgVoLA<|8E);4gAq5v+EIyy^(GTyq7Q@54rkWI>MH(lFvtGr8knTutc5MS`j zO>Cx_oGU$|^mwX7c02W4GM`3~hrw*!kb@QOIVl%}(G$l;3w#z!r-a7aRGD=K`C2mpKKE8c zw_{{&EX^9kh=mQL#GJgFCM1=MO3Ure!R9+S@(|J_MYM;){=J|?U?kGB>lOq{{p_KN zfuPCMnjl&$0Dr`J{Jzj@-G)g#5$Uq>8pm8@L_j}<8-RudOXIyb*=3AM+|mRw-=fj& zxY>c)@n!}{9gp=;o(WMfjp|)c>-pW!DRpAKZGQ2$Ozx!0yq-<3PT`@=?ym$bZUs&zWlo)Vi@=^>4xfIOsi~D!>qToLs4?uj>B}K( z2auHbD$%zDGrkl1^Df?|H@Yo~onqE7$$cT7zN7T1^`aLlK-YR>zHJmSxa&15C^K)7 z3TP*Ca4P{zcDsP5eJ*iS>=}hY2;6eH2lR8u}t=V32EcY&SM?-VE&E zcP7(|!N4GQGB}ti2y!`6*^nd9z0I3++|LGke^`g+;Eyn?(u+?tV{kRV96q_sg*X=0 z0lo|7e*?O;;yqg8z=;k@!sDbw+}cQKp=^7~Uv|wtrlj6HQnc)k4@rjcZV}4UPIq)X zK?6q6$zY9MW_;F^v*dc3`T`NYczK8}-dA+|wAW0}21O(?BenF6GWFTOhpwkh=>(tx zDxbQqsfufMCNk$PwBAnqvJ?N5%~&%#1r*0)A_mk$7G=gduoF#*MTvIF`3&%9{*-c} zv|}6E5HlDDm(NjM24`>%x#<0xh?AFuqRsgXws*Q?FJyz_1M7DoyIIkRhXD)1P)yFd zU=AMLYnGQEKwx?Jn1Q6;A9d=3)0!ef|M{lfIF`aV>f%Z(LRm)xkhAYMlhruB!TB`w z%FgPD{nHm5^GwrztC6%4p%7<2u9-s4oJTF-QTSiAGk_NT^8AcpO6$yY*1P3#6iRyfLn`V6HwGbtjAG z`i!{(66?EAaXs^FeDK)Cubyf5EgL%HH95B)?@=e1eOL(%P;*;eB;>3!Q4Dxiv~ z+0S<_0QS&ekNcbUH-L?O-_SZR8d{1Ew{2e1X^($x9_6V)rg}C zmQ4w@qv=j(pj`EjiE(Gr22y0q-R(PVQ+ek*!U>yMfrIBoR;F(s9y4(~j|`s!#}*TPVV{6q3mz!>`RbJBQuQjL7x;QwOnmTQm zx)!N1)dYe!38hY34c1eI7a&w2}2%ZA$r)MBX%NF!j z?LobY2ZkbMUl#butBkNS|=u@T{Hr)#Cu^g=09${`+Ahj#K5slQ3(mc zj!T)wRdACUmRd!g`W}tqrlMkkKG_%Fbw8pyoO)lks;z$Wer+tKP&j`_-}TyoE?MS! z!U9Kr3atb55-^=^K9Z!i6a8#!TAb=G=lgJP#QlIhgS?h5bu|Lp0Wy7_L1ALv8(1b0 zLd(+;nPN2S!#;;bpMxL;xJSjjM$W%_{ug+Q6FwG|BbzK4sG^msIe`0z9iBq%tso_hTzX*XS8^6mE^B>I+Ae*dt;)yQJp*9V5>ewhODngstkB# zqht~^r@tQ&j3))$T=uU-Jwe^%Lti$HcP7p@v(i6!k9$mTuW^1!3QUo*G4&PpMt$ih z+oE^yR@b_1HxYSel3e)B1{emm<)@}F^Dsw8heCcs@W)G)`wRCFBI_wh zBw~ASNy8)j&(VR1;i>RYtvYTb+D)YA2x7I~&-aj@%FSZ4bCit{9_p z^nIN`zBozuUaq|`frlw2^;iiD3NLV59PuFk4fkY{qZW8*K!{zAXtj*l`H({R*2-Rv zT6NIDtrE=xuj5~8<_z&!_~V)=2vkOgu|gHEu_3>Wne!2-UrY4|de4;imrI66o^%=& z$_~04U3Htn<^%rCT_}L%gC9A-r@-C!6`hc*v3u#Y5ntn!f}%@_t#v3`dwPH<8U$<1ihDS8M(ZBZfNoJv;V>8!~hCH*Ga z+*~`^W72l&>O+VIR&wO@C{pZy-+@q8noJ#VQ16Sv!~UK*&T!+MHB|95`X5)-qzuqw zj42$RUGxFf3hv-5M%?`8c`XT9KkC;41xo@9ZEiLyvp3C}uCRg&93Z_{&%_@T@evwm3jEO2Wnmu|4u6S<2X2~reF4~ZJGjtP zpkoFgR(@@K98>xK$)ujQ^NWm^Z4F+`#}*eFK`Go$%QjOWp4+(kubH%50|28w4gnd7!hsOYTu-el~(fc0xP?J$o}lb%m@4A<2fAM~ykq<6SX zk=|LN%6)?4A+O$4wz~fg8s+$X*$HzpVFih@IZK62Iim%!XecbX3!nY0c+T0>a%Qmfz6iUY>XTAgKHcQe z4*T%g_p&)!JVF(<^Jy9WC3_+DI#P#nTg3Z$;&{O4znuzXROL~rW1_0*2mQIEsw&@g z@$ec?{;Lri22&F!n-}rNs|BY4?5oeabLXnHYSnMTwCjRXU8&ia7mjTRGJ6t2!!>AQ zoL3RYo!^n97x@MRmi@8(aSlWN)e)g$>^*LdA!@8F<3yB_a)S(Xt}#wSf&R!Sb1wDC@EAk6`JWq0)&xy(dtSlX&Oq%Z={$vb@l>nW0fvCE&#HCseSSs8V0 zoC6R7aH)jb_X%Zg`mf>bpaG5T4@-)CyHEIg2n>I_C$%DYx&(8Mfzw>{RbgoOmC#cgb=WLW+zgl4 z#KHF!dl@%K)s#4RIOaq$hm|p>`I6+Ulo7a*>zHLTZ#1 z#n>0IeP8UxwL*rqwBX{I^VsM#m!%g=zu)ufnjEd@Y~twXLoQZDb)}2A64dX%*%sg9 z8yjs_kxdlCc^}p-t!C$LoGFB1@3s_(9^`6Y`kx^7>yM;wRb=n=hL6%M9yd2`w*W9o z&=l4hBB$65)3F-COtsb8?}idm(la0$Q0G&L0T&3VDP26>ovmGghUk*S(HgbEdi-I) zn;wl~;GNql`bdeO-_G@$Y~9oLO2Ie7`#{)NJ+=xiEq7KHO3EL#0cAIXFysdL2K2)_S zlb?(Z|8El+Dc9zV?QFxIUWna15s5a==3CX8FCkXL1@dtn63G|Z_K^dh0OR#qTQ+x2 zPy!`iVU>c~*+ImJB*10j{Cb8oCPVz|?|*Hap0Ub=znYK$u{o5p8V&26s9BshsMoaV z-$^%_rI&t!@8DQ>m4qf5*;2lnJhJC;VH>#lO2jBFcIF@x_b$FFa z`))x1IbKhCne;}qscG{H?kw37Wi9SB8%`Te%l+1IL_yOfThbd}jPJqo@yi!oK zq&8FDZG9k6Hdg{?)fMwrtRKuV?X*NBHkcVW1=!J?%-0uD!?~jovsG3D)bUmPaTOH_ z5^!k^O;vT(-vko#@TL{*b@Nm#0g3_rLCYbUlNg-$_v1&d)X}jXEo7fx@1?QiiT?iAN=mO3tsZCbDX!= zIy|$wSo_tc9CDV@X(E6BK_EAKs&n<%4C|L>&T1QXI5i&HfAsRv6u@%`POX}PD7FSF z{uYzWRvgv_d^pUKCC>zr7U zNC5c;=eo@ObYf#JgXg9vN>cg(0q1+!C1T14m*xp1?6l`p!pI{VF#JA`hCA2ak@UH` z<`|NwyMJ&%7eQ(9Pysjk%xZ(P-kXv+Z`eS%D6Dl2!GsS&={ShjOdH%QHZU|YT-#XI zc@;@) zLVmzSYu|vteuxGWzR#V%U z%#r6lc-YmsKG~`o5ew0;9V7@^%Z-0e7tS2(0isJg_sKC|MZwX#4y&XQ5l7a&OPLiL z=I%f^h*sHB-%3pN<^F+le4FPxwonu^oHqu-g~p3v7}}9Np$hvg*`G!a#wu~R7QI+; zX*|{7CR{&*8r=k7G>9I3I!s!|e)+rrm{YFKNN9@Te$2T+6~Tdes&e+D2i zLAFG@`IcMziV+`AKq??n8*o%#0dB>|ux_8SvLsK0|2z978vGz!-@04ZKdKHX2Lm?%rz8Bf*jOQRTk?xl z8D+I#d7Y?p{|0+{^gudk$|m*hKc5O2Zzh-7r#UgKa(Q$V>=zyC-E;~kb7l-7cKVly z^k*5WqAwTJtuAR5TU^mfIBY;Q0(`NG93Cr9to(a_1XApZuQ^d6Hs(L zQd#%Vt60d)pVy()b}MAf^V0zD5X=PQ=pXqHT-@2|=45!&&aB}9h!{-2V>nBNz|4B_ zzczW+U!XHER1!6!9kJ+yET{#`dK1;1D?~4m zr&%*!(eRU45|9lEX7sC@XVUlYiG9uZ z+GdB7t!kE#uZpk7RC5pxI-upttJu;BKe`}1s_@H!o^1osDA0nh76_xcBa8{9>4E{z zFdlIkGGtbcZ4VWn5v<~h>h^6^{w3ei=qgY{{-YwM5%2{7Fi_!2>_o4v{oITHzU7sP zHhUgbc!@Gi&YW~&iO_&3#FhZaKFGO~7TG?(JR^gIhejC<5w7bTIvMu*rcJj9sLdph zDbrC2xUXT9QF%Bcm=j$kAm3#}vM|k9rqt1h+!1-(0Rj`S^&uh>Rz|WuBgL?!HLMzt zn(i4Dsfc1~Jmitc7C=AsoTxz#!Boua_D_M8d~%IJ>?)Wg<$tbHmN*>8opwg;SmZ5V zmMgs-M8cp%NoX5J*KO*61t>CuM#59G7P?t5H+jH|dnX4vWkdjyv9sjUfwztm7xr*^ zfZQQzd#cCGua`oJi-Km3_I#vf0thYot#NXs9e}~r;^hP}_704-k8)pKR$~uK(IJhh zWo}rog0D#g3brX^0A)>5-^oNxe&WKuc$sav;TxxJgc_x7r8^!^@_y!?m*a^FOavcZ zRH(p^o^m4b642vr2%J$LL=_#$uR5lMxRWr#mO}v{15bcMiHpf!t9D=H@M3|0_3&!& zyj3fUvzdzr1@nxj(|M2yJqtzgci|0>;Ul}Ecv#${ctC6)N-o<~07eLr?3%fL&MUot z7;yX62-HPvkpCE)z5g3xJJNA1A<=O^Ub%N+@BV<@2-{JV z`LTx&LUQ4oR43k||Iu;-<_Jyh1T8nb4b#99{4ALcCRckSz=#su?`N_ycaIzzI@QeWhr8Xn zegIf(OA$%75|icQCUq0g$1IOHtA~JB{ZX&bLyMC z|7&7SNFlCyaMw0!iw`E=UL{z+ANk-wu+OpT?a*NR=gV?s=aM?~a#WETl2Ga`uKsuK%KH>x8I^o)%-$yYb z$}sB39FN@`RFWj4mvQoc;+=Ap7+>(Rpa~8B!q%i=iH^XJ!DT)RsW5J>Yi+uXVax6b z#VpswsxFb=Q&~f?xafDF&1MMZ#Xn=lC8BS|H8L7?SeJ?sV`K^I?AoX}f<{7@A zgWk8%=m{YVnSFE4_Nb)0X*PIjMo*F7VEU7WLz?GM_KtIiSuUJbgok<9S7f_2P_@D> zoH;V_s=%(a1}U{${)$)J`?hRXtew9!x~34n$>)iWKO__VVr_;J(^+e>%HCXz^yKZ( zC!ZqOV?E@S=60eXnq5)Njk$l_;@NCtsMX^T+G;1}u>lIpZJ_e=RhxCExw$~v1d*zY zO$0LN>~jjia>Zb=HWiW)H0S24s$|_QqN*0iCcPNj7NOJY4>z6<-Y!>~RhLua=Ti7! zO~uqi;`A$e#gKl=T}^6vXQrFmQOHO8&&>j2h_FGGHIeSLn7yuBV<;18ZC>V@1AM76 zJ33BGTE?I!PRH-`J7%nbHnesMwj!E-pZ>vfM9E`hcG|7ttn-$-H2AJIi%ta&?@Yql zT<-^avL9HwlA`Z-vR(ai_+8mF8!w4-=Qf4rALL^9{bKkhR}S0DJzR~Vxn&fTsnE|L zG?BYj6lrbwSYn%Rytd=-dD6+czC(R*Q7}0-!ZZ|Y(R^`Z*-Q6uk}7sfCD|=Fas7qq zvv?)PsqlY7`)Z=kvlEqJ_ckd53jT{X%cj~h{dWF117gz}qiL00PuL%xx^kk&cmP)Dxko=V;Yoe}9%;AsB6 zPKhqSXvBGGNDQXcEc45Z8XO5_mg$E$+1svEA_3{~oqTiOWw1dnv@?rZoe7Q`k(^Wj zT+29XNc9$K9#w)vk z4{ok>46Q?s1egfo^UM7V#uTFqbjbggVA;8G)T#hiDoc%kNMMMN@2^xIOE?*J1eG(h zLX=9!#W91wU4h|4Q`oJwU|}-8VSSO{u)B6{{vU$_f@fMa1+=r%!9!=q`oMEAQ!Yc{ zrF&op)c?0UufywqrMKeLJdKn>a5?QUv@?n!EHQl7VWpx*oObNgRlGjn1VOt<_L|O5fe`dc4xU5)?-5m*D8%g|>7{1@n4f9~;<=b&}9x97~;>)+OV0}ER1wq5e zmU*!I%LPF}KO>kp-VVr@v9Or*#o|lIsEX!Cwz(7X@|e31W;4~Uzy%|^P4j~=y!NTZ zu2t6wC`jYP9ku+W-%#p37z_M5=Ynd?v-G~U2&#rUAofvBFzP{~&QbqIcNtIuU6i+* z^*DUeHnL6o{5&M}N$`}x{>tnw0rFJfXpwJw5U-qE330!l zt3?beDf(V9p=c5|Fq%C1$17vBF9vx}I*F36-d%kc04D*!TZfs9l+3e21o;q3dK)P|*STb* zeD)AyAVdhRPbTF4V0}O!3F)ezD55#WduNvZOv9QhP6>4}$cKClG7z2mdFRnCV=~Rc zw3MQ@q(kwk*FyU)Py0=4_79#6f&I_tD@zJyfKAMU+2{1b^Pba_{hjFhK|T@}%CEF)8!`vKHjHaRUWHRVInwdf_$}7!tq48P4kg zNB&;TmQ(N7Qw`H0)Cg|oa=L)FL4BDHx8t1BUAwe2C)4c3ml`*aL`1lp*BOEQOk_rj z&~7&hcQdxfwcu`*TOAbds0x1o)dPmfFY0J>I zleS$hHnD-(m*-o}uXLzG*IBJhh|kArp$j||rXX>*R{Kyg#3tV{944By5;YO~1Rp|F z+Y63x3H^1~@<1_r%l5mq?k0ox<&aB{GqAy39Hy@Z~lt011 ze>?%F!J4;u2Ycv~l|KYLxkd;@2l=)^42pqr4QS$ncC=|ftsvY8v`Y#yY z!29|Mxnqgy01J(JXzdEMh%tk(_+@So_wC)#xbYJ6(AV5FC z<2U*>VuoyoRMASbA`}`AcI}3>RuvP|Mqy6%o`!r^Hs-uhEML^zJfXpn)Y* zsih(Tp-$cRe#w#KcKrjJc*lI;OWthz{0^*bnLu~qV}AN5Q3Gw@N`c_u>U`Q|_%JnB z&AUHPOKke)H*KLqgA&NYSKwk?)A#3GBLa5vT>O)3f}al}0Js`95LBLrl=`$f3@jTn z53XfEg6ZmIbNWJDoB5_f$Msg376l!FfrX}Fsv!IAtOEP+N%0d#Xm~42p>amBd4;izMC%2AC4^;M0OV7-mJ| zhhF?^;K8jGucjm=UmU5QtvRp;j$I)wu5uE@re?WAAM}CISQ*@@fuNH`QC#0DI2O{z z{*hk3@pq9(tuK~O19%vB!PtsQJrJ31RpD}Z-oT^`#kQwcFNtmQ!%-pPFL&19N+N>< zFH>aioCR&uxzf0xSe8Pi(Lg64!m50?b<`F@l>cVyxGXGl+oCTBZnqJ8f$V^{o0*w0 z%;!&vvOqGzcu}IoHuN7|5i9cjg)Vzi<8V}Ad$`@D_{QT*sT+Tqb~J2FLrggv>s#jt z`-E|}SMjqkf7d4q@HI%y&f|IU-fts_kis(KVx2D@4lOVf$?S`)-$-L%*${lP&@^Hk z_Cj6?-QMPAbC8S)aPYQVapeJNu}}mN84YSyMxm-Kp-W7g4;b5(ugQ~L1*a(rN1VBRY>6DQF}h0lvvM zx(GL(qRK-=#a_Vpo#Y8zKqD(IADa@Wi4C5FqVs|k1~d25TBV&JC2oxaY{mAlwjJL6P8F>o7`0T>kiw~H2btTgMoWVc9S`laLIDNh=*CO zZ`ZAX4deO_-D~7#@|jhE*MbRUbej+rVJE_jhpNWjjs^!2`Bbw7=7!8}QQvy8@3)X*-38>thg;H0|N)+V`jyM%@%_xAm1j4B+9A(2R$`zTe{<@+m1nIzib7pwM zlOWOTTt*2|{tM%m_&|*As4y-7?3wZe9na{X$UyBRbKw8^SfmXlPV;`E^f}YI^RFLB zWKwOThkY<^gD^K5VlvyN>-DBFn^;ICqTQ8#?fvzo)1Us+5Sxin!8tAh)wf$0|A{2@Y93-tujXD{|?mbWc8D|6J=EUx83|dkciXpGo3NI$RNzZt5whbP=9u0@_bFPd7cv zJZR!`Pg&g*B;(dNB)5Lok$pak!`t_JOr6&MS*N?S_Zxt2{AQhcl2Jy@lnnaIsji+0 z1WO~9n42yIVpjQ2JIB4y;gJ40V;l$S+oDv{)k*l`f zu~%b_N0FF<$s#(_QyqkJ1Dug~V#a%QRphC1rB{zCx1=t3mo%)RI;I_uOz32~89uBVsitMVCsr&(fVk$cvw){I?w*S_wXD?}&x zR$W}UATC9?o7&RJxcR%0R4_bElPo*MrE-g znhzyBxZGaMT9{|siVvWTU16AvNIGv!(*5SmD|UOwpihi`3>lDcrV-@JJ)hWqZ^Y|# zO;YV7otEBv=*z*bhHrBq~ITtz>{Ml*qh*Ra^` zFv}QnUobM?zV{1TS&mku%J%Zhf-6hH26h@7s1I%FZ3%xme4A*MKGU%xQ?9s*DX|gI@oat0bKj_E6hxUxqFv_#Tg8iIhzuRF zCbX`VjS$9DnjUl5TxeYU`IR*45<}laz~%%YEcu<}6kIX_n?7)7@wfoH*HmEtHqqp4 znoMSB{VqcF(R;fy;}Y-vQY%O=-n0$4Awg|}ZIP;ef8lR(tqBvS0qIH#aSn-l&p%Dq z@7h300+=44Ngj7A1?Uj-)FbWCsZwi?erjiWWoQDU?ypf`p!DWIL8eOaeytymHqaL(`laItem=giO0 zy4E`55b##4gjrZ02jFD^EdjKOIQEta+t$Yc5K~Upck~kP&3{TlZ2LC7+W^POBSkJ{ zzIa`(%SNO|)9vZ(Cfl&aVf?7mo|^bav0tTFe0PaXO}=<~0upR|MLwGP|EcE#NE4E{ zbDNN`z`vZ&)ELA=keR5X9roG}$#O3un9)sZhl?3#z5Ihf|7?DKaDHu4 z^8Cu~(Y(c*pAYNbs9NGIwWj}-ch4n4Fo@(#V0V*sx#HalBfHIhu@&+)HGCGTO7LodiPFe+>3KlQWEY+I235aN?t#H(do zVALhP(k$K-ZFwpwaE^oyHZsOMA;$#f*Jiuq!mXlb6@7=-#B4uQtp4do82kRh1QoG_ zNA%dM(wD2Ikru)bcg8`xIz#Ex+~C6Z!mQ|sqB4aU$e+Srla#(T{f-cR7i6#yXoUvC%a_57+?CuE=#JxJj>M31gvs3Y_m zU=qsa^i?TOczvKOsv5n;MpB_bT!FN~;Gw+Qz!B`TxwY&3$`#uS1Z3i#UfzBEPuf!s zP4<~;5<%zWSQO=HO^Kt%^>#Bva$+Q|P{opgnhki(be$&t^%~Ubv9Ef4JcAG05dISx^y392R$ zW=t&7?8kBiZ5BBz3Ee$IM+Fm(k}x73G=_a?bxW@AbBhney;{wBbTT)p$`Aud+D+{s z`LuP9`oQ$vGi3vHn;P5OaR&0NQb#~nuVyAg6-Xg8C-f3D&W(S)j4&ZbwZWI>(hKwJ zG1x8zgR1R;Pk1k=H}HQTK>IPApF zJ^tnsONQgwu*c9z6m}^)5a{tki8yx-qu3ZUT!{^uGzl42URIXKvgd1Tm1N@$gdPL+ zzC9DG#$IWAufe(@78@+FFfe>R?1ymGqWvSEvM2O}+kVSunp}vRk|qq$I;%SLR_%Dv z);b0CfdGgX>uw9Q=ZP@3mlvNW&i-L4AzozCitk77C4?_v2agr|MFKDDA!hHN12hAF zkxt|0XwW*w^yolIe*r}p7?`l?(*yGsRc+#7=$23Uz-8#7(AR-Qj;3A(F@9nMkB$4R zYpK(9AoP|8K!5NZ;p;599GJZ@$Bz)M3Az7%mTw5EXEV@jt2dGcc#A2gE#`Y&WFyf8?UbCv$a_S6x=eJtV!1S(;LUjRrFifq^Ga|g9+``n3DRp)i4^tN zoLuE)_#^B<>ww=At#C*@=-gNuOG!e7aq}ebC@R_NN!*I(*&hwdk0&^b7AX z#zJh5+8GtxdR43<(e`^=MvTZ>GPR?2{Z2eTAm&_$<01R!xG`Xn}bHsXo5oQZQH_Q4*EMbH+C zSon+JITJxYw%6WCY7GielCuGQ7Bf4+frpbU6Ea>)#?=W==-qgNNEM0ZByK;&Momj{ zVCyRBdXba5zq9^`+Lehma5q{PY3N8&%NclVSeUzT*9rrIGA~RmV^ToI`wI?v%2qL0 zGIsh4kNU@YmDJKm$-4+Z+a7P4Bg3mLVdNO1O1n=MYM;AsOvK)OGz=ltLb+#^u3Oew z7;k)5O7ZLpI!oXGJxxT4>TFsak+S3%|*n40UJR{a-mB1%?2+iWLRKNgH zFv#Q&EQ2KwT*p^)F=l2kv*WiW(2TRu=lNSom_^9j`(f%)?MtC8aoHe{a%br3 z(O*!a4I?o5ZNC7zmX1iKk}2v(Hsz_Hc*AMPu5lhOoI>FM$j z^ZWh{QqY3NH+Wz_1>pL#JOm53Ech@Y5I84wP#7ou&R^O{SiUV+Tk7ZlXu)vlg!wNL z*yVfch{7?jbzGUW5e|WzZ&X6o>t5+rr*1T48d-gwMN)5n>C7EX*0tJu`GBTYZ%22;@Lm`L3fO_W%5WJjb#D`iN%)lwHp<@^9&nRBzV zxnrDvSjTZXdl3salyxrKuqnFe`xN`}K*>Axi_gsxwC(h;OU?~5NVd@6snC2z$Ztw4?H>^2GB^$%#sv*YWxffK#ei|_s zf2x4g%6PW-DxwUNrDP+pD>HKsT-#TPs1d$I`=wQ>NSChGARZVT5kNQ%~ zpL(4;0aO2PzQgmwfW#8x_?WCkyBVUX+-P_VTfV7JE}IJ1ZYekSz+Y+j3Nrxyp#yi? zs}UvA5tzN2U_tiK%;3p8)7f&!In;k7uiM zcGl6mPsKP34)g$`slGks@o0h!WMm}AjCyLw8b%%+M2LyCAD17`et{(YjDQReoHWO{ zBF(JSz*M}AIw8SVRj5?`O3LBsPSyM1o-;!fU4O$b6fKQYZ3^zy3X6=dHoPG>6Gl|5 zMmpQ2%#IPBn6zaC_k*r*O@^jQ{iVm3q&{9yHN&;7n*q6dt@8TQN;pE!;!rM}{4i|6 ziF$u7%$cQQO$gRL)wWw32rzeh17gO_k?-XwX}bQ}X}iWQl$H|EUICIltADJg5bANJ zbf$>F*%3f~=o#NAcq3t-qA)eO-aEBGREdfMif+&-<^)PC7joxOt+tz?w38qkcmsAD zqs`Br$WV9cj|j7(#zU)?_Xf{iPBZ771v54zAMuq~+1Mcgl&g1{B@0la`*&5IKw)xd zpVFYjB%&Ylaoz=5kHpX}SPH$19ns(0s|h{1=jn*sd*>*#lPm>eiAD_2B>W8b(@E`n z)6dWw)Rtn&;-$K57gWd~oqWTN zHaw6yJ;HC{;()ug0i8yZap@;P&a<>6+Z-b|)!f|I!X7ss;``*Az6{oY3}hQoTsw7N z{biD^VSd9-KC`xe%k#a}j@HWqjU+0e31bnW}YP>HTpn?(j-@18R0&Xa7g zCF$Y?n5XH5Gt7$b*c>Zry-`G41y}nKWUOo$XavrQ$2Vv^qvxb3!CT5(={)+EH66{n z>VjQrs%0P<4<3g?)BGe)4FxgK5873V*RoA#?fbdEdZBdT8Ekas;hle)U&prFrV2zQ zi8Zc!FNgmg{@L6|3+$Bg&kvafOArl?s9CJjg{F*_zK3&=6#PJOc}hJbDnJ=s%#R3( zFuPDVXdZg~VT;Hr(IOn3AxpNG7I7C%qJ)KyX86z^r61=~iKYOmTZODXp5opteRD6RvsCG@)tD-o`{plJ^^ExM~{~745jb9 zr&gj>v+Z_sIc%bSUx*u`fQ z5yj6HIQ`{*9=H>pFTXN3(&QJiZYo+h@O(~ zM)g4pJNXc6WWby0a%N61i17c$| z$;{Z}j#GUSoYmq}f`nY&`Y0pnQtB(7Q%JwNf&jJC*Ihb!5;iPpaDU!$aX1HwY!kkVMO&{ zO{nrTiDGoMOm7oHj@(xbT*zK()N-u$iV=FWzTUaRQcP&3Ng6Fnw&gO+l5<=ZS&}pt zK%ymG_R5c$K~5CuMhot=Q)~vv%GCLQX>&nj=>7v;+R!A<-2-q`C-XU0*B8vbN0&u24)x9Em}~;#~5UU7fA zsM@d+4~L_*we(L&9`9{8!bBuS>GCm*!?8cP(JVFHo=}VK)5$=~Wf?)1wVc1XJO7{H zBw)@o-ZxXW3B$AH3p#;n!syezkq7-L6k$D6TZRt)<&DGZ$J2YP>zO7T7#j_xhT8Gv zG+<>U9>QT#pZ(M#{p*sxGz?w#@c+wPG-}FB=sSv(tIv9_aB{lGf+Bla$e>|^uQ8L0 z6FP0#3H4@g@fOAqQ}q$QShtYK7$(7SPE#?1dx!IDzwpzkatj0jaRok&1u7 z5`Fq%*)yFdJZs>W`fB*`+4EJdCdB9B9*`^FEfEW>L%!e{IyOb>iaE+<#{WC?=J%@u za$jv5wyEZVJ3>&#JMVsRu~2qRGc*{ArZ^$?)#M|c{d zr;|99R%2r)SU$zS6Z0MGvpkh%(*v`#>rix&NmBB|I7uaD#QXT-3)bkJ$*CY#ER_;h6%9Se8w;Qvl_c zBn*dQvbtak>@iVx?PH9WpwgWkP0(4x5+7>BgrIz-J14 zXJ{uR$TNai@&|Q)fyRiLJ%FAytv8wo+PI$KP@KH*%(bm!6%`O1mb=@m{2x;!s#TzU zn1ZD;k39#$JK$ctl@vP}*=s$Q`|1BfeHt%Wd%YssJ#*frMrFBxaYIiVpIhy)6k7sh z+_kP%ak^wH=ChZ#7Yys8(A&KYe_W7nvQ%{C-es|~gi^#yaZ5xJo^ZJ!0yq%~nP6Bk z$~%d!j@#(931hQGT!LD*WUN_+OD%yZNov<=CQ`+|g!fbdz_FmdR^%eR6!JSTHq%Sr z5X=f{u9%lC6-)cFngjQaGHj!a311XA^(%Cr(4`#OE)xZOj#PXuADKtG<#)H;g;H$c z+!dms9?0$_vh4+s`v|ttd<3({S{iAk zO~n+xqg=zAWLdMC?NbQUxE!MyIIbJA7fCKno=19G=}r{oFBf6acykSJdcIKvOOm`= zpa&7VeGAX&O4d61cXHx^huZKq2u)4vj3kO`s|jwj0*=P{*&^}8-(^s3kR7v8+2b}; zY#(GRfASMHL!O$|$wgHjtV3V=BcUpczTm_%vpFE7_#qsC%$q2#))A>EcKbrBNS@gA z8ec$lphP^tNCHz#)OO2iCR2Pc9{nY+cxUSTu~o%9Vq=NkVrakOXoLJwqY#s`}$YkH?S6rqKyV670;W6#G`Xl!-Q8~9 zm{azVcw%WyXF>fFBkURdAYity(~g>UV2e7ldlvtV!3+&IG96`-6U&Ex-0(qLKxL%> z4xrw~6_ZPlP)qG#Rb3GTcYr6&G(gCZ)T{3rEC5*CqnrRKA9XoALDQG`0)X%vGHmoC z9-X4z5@qN3k9A8WBOSUP2%~S;IJy5Y%TSUf3D?bch=rN(GCdoQVEGe>oe!(jsa^Bd z!gORBQn?HoKYgl2x)2b!*%6?_&%%wRV_uo}|8{j%ycTkn3vd&;8J?w!shZ(nMlUEA zxc@{C8j8al(S^S}>9MthE@tPAMcd5+8^T8Mv z?IlqXt(#wy2m=lV@DWm@4;(PU8mMLRx(G$K$;J_`!WLm2ZP>esesD{ zus%D|*WC$mpthm!Ge3@@@fwSiX&C=+a6Zz{f~9*m>cA%fD8?I{qxqg*ZmoIllO1|s z^#NAIrODl7E1*kVg7cB;bt?XCpp#3oHMIU>hKx% zJz3q;Pit`~3*E4WD?GVRsU+3zMTh@fDaW|0kqKd(0}*W|_7%7Lj@AHZIvo#hOibkh zU-!>`7OQ$A_y!yf)lMvC6H)ppPP|ou6@P}bJ!RId*22^dC$nX!6muI=f zdOx3B8UyrsHD%(S&sPKR{S7;8Nj$o^X5)w1r12%-OJHdV@HBp7&z6r*X1Gvil>_y? zfC2{9h0+uq5qCX}2PE?@LuN{hh1^&2KpZ!^Gi-TKX7*JsJmta7D2HkX@fBSi-#7Wm oHa3O80E=XJ?A}Am+5iEB!UDU(FtTN~X|cp-`vL#}000D8TBDphbN~PV literal 0 HcmV?d00001 diff --git a/DataLoadAPBin/LogMessageDescriptions/Plane.xml b/DataLoadAPBin/LogMessageDescriptions/Plane.xml deleted file mode 100644 index 54770c7..0000000 --- a/DataLoadAPBin/LogMessageDescriptions/Plane.xml +++ /dev/null @@ -1,12362 +0,0 @@ - - - - - - IMU accelerometer data - - - Time since system startup - - - accelerometer sensor instance number - - - time since system startup this sample was taken - - - acceleration along X axis - - - acceleration along Y axis - - - acceleration along Z axis - - - - - Automatic Dependent Serveillance - Broadcast detected vehicle information - - - Time since system startup - - - Transponder address - - - Vehicle latitude - - - Vehicle longitude - - - Vehicle altitude - - - Vehicle heading - - - Vehicle horizontal velocity - - - Vehicle vertical velocity - - - Transponder squawk code - - - - - Normalised pre-mixer control surface outputs - - - Time since system startup - - - Pre-mixer value for aileron output (between -4500 and 4500) - - - Pre-mixer value for elevator output (between -4500 and 4500) - - - Pre-mixer value for throttle output (between -100 and 100) - - - Pre-mixer value for rudder output (between -4500 and 4500) - - - Pre-mixer value for flaps output (between 0 and 100) - - - Pre-mixer value for steering output (between -4500 and 4500) - - - Surface movement / airspeed scaling value - - - - - Backup AHRS data - - - Time since system startup - - - Estimated roll - - - Estimated pitch - - - Estimated yaw - - - Estimated altitude - - - Estimated latitude - - - Estimated longitude - - - Estimated attitude quaternion component 1 - - - Estimated attitude quaternion component 2 - - - Estimated attitude quaternion component 3 - - - Estimated attitude quaternion component 4 - - - - - Contents of 'position report' AIS message, see: https://gpsd.gitlab.io/gpsd/AIVDM.html#_types_1_2_and_3_position_report_class_a - - - Time since system startup - - - Message Type - - - Repeat Indicator - - - MMSI - - - Navigation Status - - - Rate of Turn (ROT) - - - Speed Over Ground (SOG) - - - Position Accuracy - - - Longitude - - - Latitude - - - Course Over Ground (COG) - - - True Heading (HDG) - - - Time Stamp - - - Maneuver Indicator - - - RAIM flag - - - Radio status - - - - - Contents of 'Base Station Report' AIS message, see: https://gpsd.gitlab.io/gpsd/AIVDM.html#_type_4_base_station_report - - - Time since system startup - - - Repeat Indicator - - - MMSI - - - Year (UTC) - - - Month (UTC) - - - Day (UTC) - - - Hour (UTC) - - - Minute (UTC) - - - Second (UTC) - - - Fix quality - - - Longitude - - - Latitude - - - Type of EPFD - - - RAIM flag - - - Radio status - - - - - Contents of 'static and voyage related data' AIS message, see: https://gpsd.gitlab.io/gpsd/AIVDM.html#_type_5_static_and_voyage_related_data - - - Time since system startup - - - Repeat Indicator - - - MMSI - - - AIS Version - - - IMO Number - - - Call Sign - - - Vessel Name - - - Ship Type - - - Dimension to Bow - - - Dimension to Stern - - - Dimension to Port - - - Dimension to Starboard - - - Position Fix Type - - - Draught - - - Destination - - - DTE - - - - - Raw AIS AVDIM messages contents, see: https://gpsd.gitlab.io/gpsd/AIVDM.html#_aivdmaivdo_sentence_layer - - - Time since system startup - - - count of fragments in the currently accumulating message - - - fragment number of this sentence - - - sequential message ID for multi-sentence messages - - - data payload - - - - - Attitude control attitude - - - Timestamp of the current Attitude loop - - - vehicle desired roll - - - achieved vehicle roll - - - vehicle desired pitch - - - achieved vehicle pitch - - - vehicle desired yaw - - - achieved vehicle yaw - - - attitude delta time - - - - - Angle of attack and Side Slip Angle values - - - Time since system startup - - - Angle of Attack calculated from airspeed, wind vector,velocity vector - - - Side Slip Angle calculated from airspeed, wind vector,velocity vector - - - - - Arming status changes - - - Time since system startup - - - true if vehicle is now armed - - - arming bitmask at time of arming - - - 2 - - - 4 - - - 8 - - - 16 - - - 32 - - - 64 - - - 128 - - - 256 - - - 512 - - - 1024 - - - 2048 - - - 4096 - - - 8192 - - - 16384 - - - 32768 - - - 65536 - - - 131072 - - - 262144 - - - 524288 - - - 1048576 - - - 2097152 - - - - - true if arm/disarm was forced - - - method used for arming - - - 0 - - - 1 - - - 2 - - - 3 - - - 4 - - - 5 - only disarm uses this... - - - 6 - only disarm uses this... - - - 7 - only disarm uses this... - - - 8 - only disarm uses this... - - - 9 - only disarm uses this... - - - 10 - only disarm uses this... - - - 11 - only disarm uses this... - - - 12 - only disarm uses this... - - - 13 - only disarm uses this... - - - 14 - only disarm uses this... - - - 15 - only disarm uses this... - - - 16 - only disarm uses this... - - - 17 - only disarm uses this... - - - 18 - only disarm uses this... - - - 19 - only disarm uses this... - - - 20 - only disarm uses this... - - - 21 - only disarm uses this... - - - 22 - only disarm uses this... - - - 23 - only disarm uses this... - - - 24 - only disarm uses this... - - - 25 - only disarm uses this... - - - 26 - only disarm uses this... - - - 27 - only disarm uses this... - - - 28 - only disarm uses this... - - - 29 - only disarm uses this... - - - 30 - only disarm uses this... - - - 31 - only disarm uses this... - - - 32 - only disarm uses this... - - - 33 - only disarm uses this... - - - 34 - - - 35 - - - 36 - - - 37 - - - 38 - - - 100 - - - - - - - Airspeed sensor data - - - Time since system startup - - - Airspeed sensor instance number - - - Current airspeed - - - Pressure difference between static and dynamic port - - - Temperature used for calculation - - - Raw pressure less offset - - - Offset from parameter - - - True if sensor is being used - - - True if sensor is healthy - - - Probability sensor is healthy - - - innovation test ratio - - - Primary instance number. If equal to I then this sensor is primary sensor - - - - - AirSim simulation data - - - Time since system startup - - - Simulation's timestamp - - - Simulation's roll - - - Simulation's pitch - - - Simulation's yaw - - - Simulated gyroscope, X-axis - - - Simulated gyroscope, Y-axis - - - Simulated gyroscope, Z-axis - - - - - More AirSim simulation data - - - Time since system startup - - - simulation's acceleration, X-axis - - - simulation's acceleration, Y-axis - - - simulation's acceleration, Z-axis - - - simulation's velocity, X-axis - - - simulation's velocity, Y-axis - - - simulation's velocity, Z-axis - - - simulation's position, X-axis - - - simulation's position, Y-axis - - - simulation's position, Z-axis - - - simulation's gps altitude - - - simulation's earth-frame speed-down - - - - - AutoTune data packet - - - Time since system startup - - - current angle - - - current angular rate - - - - - Plane AutoTune - - - Time since system startup - - - tuning axis - - - tuning state - - - control surface deflection - - - P slew rate - - - D slew rate - - - FF value single sample - - - FF value - - - P value - - - I value - - - D value - - - action taken - - - Rate maximum - - - time constant - - - - - Scale factors for attitude controller - - - Time since system startup - - - Angle P scale X - - - Angle P scale Y - - - Angle P scale Z - - - PD scale X - - - PD scale Y - - - PD scale Z - - - I scale X - - - I scale Y - - - I scale Z - - - - - Canonical vehicle attitude - - - Time since system startup - - - vehicle desired roll - - - achieved vehicle roll - - - vehicle desired pitch - - - achieved vehicle pitch - - - vehicle desired yaw - - - achieved vehicle yaw - - - active EKF type - - - - - Copter/QuadPlane AutoTune - - - Time since system startup - - - which axis is currently being tuned - - - step in autotune process - - - target angle or rate, depending on tuning step - - - measured minimum target angle or rate - - - measured maximum target angle or rate - - - new rate gain P term - - - new rate gain D term - - - new angle P term - - - maximum measured twitching acceleration - - - - - Auxiliary function invocation information - - - Time since system startup - - - ID of triggered function - - - 0 - aux switch disabled - - - 2 - flip - - - 3 - change to simple mode - - - 4 - change to RTL flight mode - - - 5 - save current position as level - - - 7 - save mission waypoint or RTL if in auto mode - - - 9 - trigger camera servo or relay - - - 10 - allow enabling or disabling rangefinder in flight which helps avoid surface tracking when you are far above the ground - - - 11 - allow enabling or disabling fence in flight - - - 12 - UNUSED - - - 13 - change to simple mode in middle, super simple at top - - - 14 - low = disabled, middle = leveled, high = leveled and limited - - - 15 - enable/disable the crop sprayer - - - 16 - change to auto flight mode - - - 17 - auto tune - - - 18 - change to LAND flight mode - - - 19 - Operate cargo grippers low=off, middle=neutral, high=on - - - 21 - Parachute enable/disable - - - 22 - Parachute release - - - 23 - Parachute disable, enable, release with 3 position switch - - - 24 - Reset auto mission to start from first command - - - 25 - enable/disable the roll and pitch rate feed forward - - - 26 - enable/disable the roll, pitch and yaw accel limiting - - - 27 - Retract Mount1 - - - 28 - Relay pin on/off (only supports first relay) - - - 29 - Landing gear controller - - - 30 - Play lost vehicle sound - - - 31 - Emergency Stop Switch - - - 32 - Motor On/Off switch - - - 33 - Brake flight mode - - - 34 - Relay2 pin on/off - - - 35 - Relay3 pin on/off - - - 36 - Relay4 pin on/off - - - 37 - change to THROW flight mode - - - 38 - enable AP_Avoidance library - - - 39 - enable precision loiter - - - 40 - enable object avoidance using proximity sensors (ie. horizontal lidar) - - - 41 - UNUSED - - - 42 - change to SmartRTL flight mode - - - 43 - enable inverted flight - - - 44 - winch enable/disable - - - 45 - winch control - - - 46 - enable RC Override - - - 47 - user function #1 - - - 48 - user function #2 - - - 49 - user function #3 - - - 50 - learn cruise throttle (Rover) - - - 51 - manual mode - - - 52 - acro mode - - - 53 - steering mode - - - 54 - hold mode - - - 55 - guided mode - - - 56 - loiter mode - - - 57 - follow mode - - - 58 - clear waypoints - - - 59 - simple mode - - - 60 - zigzag mode - - - 61 - zigzag save waypoint - - - 62 - learn compass offsets - - - 63 - rover sailboat tack - - - 64 - reverse throttle input - - - 65 - disable GPS for testing - - - 66 - Relay5 pin on/off - - - 67 - Relay6 pin on/off - - - 68 - stabilize mode - - - 69 - poshold mode - - - 70 - althold mode - - - 71 - flowhold mode - - - 72 - circle mode - - - 73 - drift mode - - - 74 - Sailboat motoring 3pos - - - 75 - Surface tracking upwards or downwards - - - 76 - Standby mode - - - 77 - takeoff - - - 78 - control RunCam device - - - 79 - control RunCam OSD - - - 80 - align visual odometry camera's attitude to AHRS - - - 81 - disarm vehicle - - - 82 - disable, enable and force Q assist - - - 83 - zigzag auto switch - - - 84 - enable / disable airmode for copter - - - 85 - generator control - - - 86 - disable terrain following in CRUISE/FBWB modes - - - 87 - select CROW mode for diff spoilers;high disables,mid forces progressive - - - 88 - three-position switch to set soaring mode - - - 89 - force flare, throttle forced idle, pitch to LAND_PITCH_DEG, tilts up - - - 90 - change EKF data source set between primary, secondary and tertiary - - - 91 - calibrate airspeed ratio - - - 92 - Fly-By-Wire-A - - - 93 - used in separate branch MISSION_RELATIVE - - - 94 - VTX power level - - - 95 - enables FBWA taildragger takeoff mode. Once this feature is enabled it will stay enabled until the aircraft goes above TKOFF_TDRAG_SPD1 airspeed, changes mode, or the pitch goes above the initial pitch when this is engaged or goes below 0 pitch. When enabled the elevator will be forced to TKOFF_TDRAG_ELEV. This option allows for easier takeoffs on taildraggers in FBWA mode, and also makes it easier to test auto-takeoff steering handling in FBWA. - - - 96 - trigger re-reading of mode switch - - - 97 - flag for windvane direction offset input, used with windvane type 2 - - - 98 - mode training - - - 99 - AUTO RTL via DO_LAND_START - - - 100 - disable first IMU (for IMU failure testing) - - - 101 - disable second IMU (for IMU failure testing) - - - 102 - Momentary switch to cycle camera modes - - - 103 - trigger lane switch attempt - - - 104 - trigger yaw reset attempt - - - 105 - disable GPS yaw for testing - - - 106 - equivalent to AIRSPEED_USE 0 - - - 107 - fixed wing auto tune - - - 108 - QRTL mode - - - 109 - use Custom Controller - - - 110 - disable third IMU (for IMU failure testing) - - - 111 - allows for manually running starter - - - 112 - change AHRS_EKF_TYPE - - - 113 - Retract Mount2 - - - 150 - CRUISE mode - - - 151 - Turtle mode - flip over after crash - - - 152 - reset simple mode reference heading to current - - - 153 - arm or disarm vehicle - - - 154 - arm or disarm vehicle enabling airmode - - - 155 - trim to current servo and RC - - - 156 - clear torqeedo error - - - 157 - Force long FS action to FBWA for landing out of range - - - 158 - optical flow calibration - - - 159 - enable or disable land detection for GPS based manual modes preventing land detection and maintainting set_throttle_mix_max - - - 160 - enable/disable weathervaning - - - 161 - initialize turbine start sequence - - - 162 - FFT notch tuning function - - - 163 - Mount earth frame yaw lock forced on all axes, for all mounts - - - 164 - Pauses logging if under logging rate control - - - 165 - ARM on high, MOTOR_ESTOP on low - - - 166 - start recording on high, stop recording on low - - - 167 - camera zoom high = zoom in, middle = hold, low = zoom out - - - 168 - camera manual focus. high = long shot, middle = stop focus, low = close shot - - - 169 - camera auto focus - - - 170 - QuadPlane QStabilize mode - - - 171 - Calibrate compasses (disarmed only) - - - 172 - Battery MPPT Power enable. high = ON, mid = auto (controlled by mppt/batt driver), low = OFF. This effects all MPPTs. - - - 173 - Abort Glide-slope or VTOL landing during payload place or do_land type mission items - - - 174 - camera image tracking - - - 175 - camera lens selection - - - 176 - force enabled VTOL forward throttle method - - - 177 - mount LRF enable/disable - - - 178 - e.g. pause movement towards waypoint - - - 179 - AP_ICEngine start stop - - - 180 - auto tune tuning switch to test or revert gains - - - 181 - quicktune 3 position switch - - - 182 - in-flight AHRS autotrim - - - 183 - Fixed Wing AUTOLAND Mode - - - 184 - system ID as an aux switch - - - 185 - mount lock modes for roll and pitch axes, for all mounts that support it - - - 186 - Lock mount target to current ROI seen and switch mount to GPS Targeting mode - - - 201 - roll input - - - 202 - pitch input - - - 203 - throttle pilot input - - - 204 - yaw pilot input - - - 207 - mainsail input - - - 208 - flap input - - - 209 - VTOL manual forward throttle - - - 210 - manual airbrake control - - - 211 - walking robot height input - - - 212 - mount1 roll input - - - 213 - mount1 pitch input - - - 214 - mount1 yaw input - - - 215 - mount2 roll input - - - 216 - mount3 pitch input - - - 217 - mount4 yaw input - - - 218 - allows for throttle on slider - - - 219 - use a transmitter knob or slider for in-flight tuning - - - 220 - use another transmitter knob or slider for in-flight tuning - - - 300 - - - 301 - - - 302 - - - 303 - - - 304 - - - 305 - - - 306 - - - 307 - - - 308 - - - 309 - - - 310 - - - 311 - - - 312 - - - 313 - - - 314 - - - 315 - - - 316 - emergency scripting disablement - - - 317 - - - - - switch position when function triggered - - - 0 - indicates auxiliary switch is in the low position (pwm <1200) - - - 1 - indicates auxiliary switch is in the middle position (pwm >1200, <1800) - - - 2 - indicates auxiliary switch is in the high position (pwm >1800) - - - - - source of auxiliary function invocation - - - 0 - Source index is RC channel index - - - 1 - Source index is RC channel index - - - 2 - Source index is button index - - - 3 - Source index is MAVLink channel number - - - 4 - Source index is mission item index - - - 5 - Source index is not used (always 0) - - - - - index within source. 0 indexed. Invalid for scripting. - - - true if function was successful - - - - - Barometer dynamic data - - - Time since system startup - - - barometer sensor instance number - - - calculated dynamic pressure in the bodyframe X-axis - - - calculated dynamic pressure in the bodyframe Y-axis - - - calculated dynamic pressure in the bodyframe Z-axis - - - - - Gathered Barometer data - - - Time since system startup - - - barometer sensor instance number - - - calculated altitude - - - altitude AMSL - - - measured atmospheric pressure - - - measured atmospheric temperature - - - derived climb rate from primary barometer - - - time last sample was taken - - - raw adjustment of barometer altitude, zeroed on calibration, possibly set by GCS - - - temperature on ground, specified by parameter or measured while on ground - - - true if barometer is considered healthy - - - compensated atmospheric pressure - - - - - Gathered battery data - - - Time since system startup - - - battery instance number - - - measured voltage - - - estimated resting voltage - - - measured current - - - consumed Ah, current * time - - - consumed Wh, energy this battery has expended - - - measured temperature - - - estimated battery resistance - - - remaining percentage - - - health - - - state of health percentage. 0 if unknown - - - - - BlackBox data1 - - - Time since system startup - - - Latitude - - - Longitude - - - altitude above sea level - - - euler roll - - - euler pitch - - - euler yaw - - - velocity north - - - velocity east - - - velocity down - - - - - BlackBox data2 - - - Time since system startup - - - X axis gyro - - - Y axis gyro - - - Z axis gyro - - - accel X axis (front) - - - accel Y axis (right) - - - accel Z axis (down) - - - - - Battery cell voltage information - - - Time since system startup - - - battery instance number - - - battery voltage - - - first cell voltage - - - second cell voltage - - - third cell voltage - - - fourth cell voltage - - - fifth cell voltage - - - sixth cell voltage - - - seventh cell voltage - - - eighth cell voltage - - - ninth cell voltage - - - tenth cell voltage - - - eleventh cell voltage - - - twelfth cell voltage - - - - - Battery cell voltage information - - - Time since system startup - - - battery instance number - - - thirteenth cell voltage - - - fourteenth cell voltage - - - - - Beacon information - - - Time since system startup - - - True if beacon sensor is healthy - - - Number of beacons being used - - - Distance to first beacon - - - Distance to second beacon - - - Distance to third beacon - - - Distance to fourth beacon - - - Calculated beacon position, x-axis - - - Calculated beacon position, y-axis - - - Calculated beacon position, z-axis - - - - - CANFD Frame - - - Time since system startup - - - bus number - - - frame identifier - - - data length code - - - data 0 - - - data 1 - - - data 2 - - - data 3 - - - data 4 - - - data 5 - - - data 6 - - - data 7 - - - - - Camera shutter information - - - Time since system startup - - - Instance number - - - Image number - - - milliseconds since start of GPS week - - - weeks since 5 Jan 1980 - - - current latitude - - - current longitude - - - current altitude - - - current altitude relative to home - - - altitude as reported by GPS - - - current vehicle roll - - - current vehicle pitch - - - current vehicle yaw - - - - - Info from GetNodeInfo request - - - Time since system startup - - - Driver index - - - Node ID - - - Hardware ID, part 1 - - - Hardware ID, part 2 - - - Name string - - - major revision id - - - minor revision id - - - AP_Periph git hash - - - - - CAN Frame - - - Time since system startup - - - bus number - - - frame identifier - - - data length code - - - byte 0 - - - byte 1 - - - byte 2 - - - byte 3 - - - byte 4 - - - byte 5 - - - byte 6 - - - byte 7 - - - - - CAN Bus Statistics - - - Time since system startup - - - driver index - - - transmit success count - - - transmit request count - - - transmit reject count - - - transmit overflow count - - - transmit timeout count - - - transmit abort count - - - receive count - - - receive overflow count - - - receive error count - - - bus offset error count - - - ESC successful send count - - - Servo successful send count - - - ESC/Servo failed-to-send count - - - - - Custom Controller data - - - Time since system startup - - - controller type - - - 0 - - - 1 - - - 2 - - - - - true if controller is active - - - - - Uploaded mission command information - - - Time since system startup - - - Total number of mission commands - - - This command's offset in mission - - - Command type - - - Parameter 1 - - - Parameter 2 - - - Parameter 3 - - - Parameter 4 - - - Command latitude - - - Command longitude - - - Command altitude - - - Frame used for position - - - - - Servo feedback data - - - Time since system startup - - - Servo number this data relates to - - - Current servo position - - - Force being applied - - - Current servo movement speed - - - Amount of rated power being applied - - - commanded servo position - - - Voltage - - - Current - - - motor temperature - - - PCB temperature - - - error flags - - - - - Control Tuning information - - - Time since system startup - - - desired roll - - - achieved roll - - - desired pitch assuming pitch trims are already applied - - - achieved pitch assuming pitch trims are already applied,ie "0deg" is level flight trimmed pitch attitude as shown on artificial horizon level line. - - - scaled output throttle - - - scaled output rudder - - - demanded speed-height-controller throttle - - - airspeed estimate (or measurement if airspeed sensor healthy and ARSPD_USE>0) - - - airspeed type ( old estimate or source of new estimate) - - - 0 - - - 1 - - - 2 - - - 3 - - - 4 - - - - - equivalent to true airspeed ratio - - - groundspeed undershoot when flying with minimum groundspeed - - - - - DCM Estimator Data - - - Time since system startup - - - estimated roll - - - estimated pitch - - - estimated yaw - - - lowest estimated gyro drift error - - - difference between measured yaw and DCM yaw estimate - - - wind velocity, to-the-North component - - - wind velocity, to-the-East component - - - wind velocity, Up-to-Down component - - - synthetic (equivalent) airspeed - - - - - DataFlash-Over-MAVLink statistics - - - Time since system startup - - - Current block number - - - Number of times we rejected a write to the backend - - - Number of blocks sent from the retry queue - - - Number of resends of unacknowledged data made - - - Average number of blocks on the free list - - - Minimum number of blocks on the free list - - - Maximum number of blocks on the free list - - - Average number of blocks on the pending list - - - Minimum number of blocks on the pending list - - - Maximum number of blocks on the pending list - - - Average number of blocks on the sent list - - - Minimum number of blocks on the sent list - - - Maximum number of blocks on the sent list - - - - - Onboard logging statistics - - - Time since system startup - - - Number of times we rejected a write to the backend - - - Current block number - - - Current write offset - - - Minimum free space in write buffer in last time period - - - Maximum free space in write buffer in last time period - - - Average free space in write buffer in last time period - - - - - Deepstall Landing data - - - Time since system startup - - - Deepstall landing stage - - - Target heading - - - Landing point latitude - - - Landing point longitude - - - Landing point altitude - - - Crosstrack error - - - Expected travel distance vehicle will travel from this point - - - L1 controller crosstrack integrator value - - - wind estimate loiter angle flown - - - Deepstall steering PID desired value - - - Deepstall steering PID Proportional response component - - - Deepstall steering PID Integral response component - - - Deepstall steering PID Derivative response component - - - - - External AHRS data - - - Time since system startup - - - euler roll - - - euler pitch - - - euler yaw - - - velocity north - - - velocity east - - - velocity down - - - latitude - - - longitude - - - altitude AMSL - - - nav status flags - - - - - External AHRS variances - - - Time since system startup - - - velocity variance - - - position variance - - - height variance - - - magnetic variance, X - - - magnetic variance, Y - - - magnetic variance, Z - - - true airspeed variance - - - - - EFI per-cylinder information - - - Time since system startup - - - Cylinder this data belongs to - - - Ignition timing - - - Injection time - - - Cylinder head temperature - - - Exhaust gas temperature - - - Estimated lambda coefficient (dimensionless ratio) - - - Cylinder2 head temperature - - - Cylinder2 Exhaust gas temperature - - - Index of the publishing ECU - - - - - Status received from ESCs via Extended DShot telemetry v2 - - - microseconds since system startup - - - ESC instance number - - - current stress level (commutation effort), scaled to [0..255] - - - maximum stress level (commutation effort) since arming, scaled to [0..15] - - - status bits - - - 1 - true if the message contains up-to-date stress data - - - 2 - true if the message contains up-to-date status data - - - 4 - true if the last status had the "alert" bit (e.g. demag) - - - 8 - true if the last status had the "warning" bit (e.g. desync) - - - 16 - true if the last status had the "error" bit (e.g. stall) - - - - - - - Electronic Fuel Injection system data - - - Time since system startup - - - Reported engine load - - - Reported engine RPM - - - Spark Dwell Time - - - Atmospheric pressure - - - Intake manifold pressure - - - Intake manifold temperature - - - Engine Coolant Temperature - - - Oil Pressure - - - Oil temperature - - - Fuel Pressure - - - Fuel Consumption Rate - - - Consumed fuel volume - - - Throttle Position - - - Index of the publishing ECU - - - - - Electronic Fuel Injection system data - redux - - - Time since system startup - - - True if EFI is healthy - - - Engine state - - - General error - - - Crankshaft sensor status - - - Temperature status - - - Fuel pressure status - - - Oil pressure status - - - Detonation status - - - Misfire status - - - Debris status - - - Spark plug usage - - - Index of the publishing ECU - - - - - Electronic Fuel Injection data - Hirth specific Status information - - - Time since system startup - - - Error Excess Temperature Bitfield - - - 1 - true if CHT1 is too low - - - 2 - true if CHT1 is too high - - - 4 - true if CHT1 Enrichment is active - - - 8 - true if CHT2 is too low - - - 16 - true if CHT2 is too high - - - 32 - true if CHT2 Enrichment is active - - - 64 - true if EGT1 is too low - - - 128 - true if EGT1 is too high - - - 256 - true if EGT1 Enrichment is active - - - 512 - true if EGT2 is too low - - - 1024 - true if EGT2 is too high - - - 2048 - true if EGT2 Enrichment is active - - - - - Sensor Status Bitfield - - - 2 - true if engine temperature sensor is OK - - - 4 - true if air temperature sensor is OK - - - 8 - true if intake air pressure sensor is OK - - - 16 - true if throttle sensor is OK - - - - - CRC failure count - - - ACK failure count - - - Uptime between 2 messages - - - Throttle output as received by the engine - - - Modified throttle_to_hirth output sent to the engine - - - - - Specifically coded error messages - - - Time since system startup - - - Subsystem in which the error occurred - - - 1 - - - 2 - - - 3 - - - 4 - not used - - - 5 - - - 6 - - - 7 - not used - - - 8 - - - 9 - - - 10 - - - 11 - - - 12 - - - 13 - - - 14 - not used - - - 15 - - - 16 - - - 17 - - - 18 - - - 19 - - - 20 - - - 21 - - - 22 - - - 23 - - - 24 - - - 25 - - - 26 - - - 27 - - - 28 - - - 29 - - - 30 - - - 31 - - - - - Subsystem-specific error code - - - - - Feedback received from ESCs - - - microseconds since system startup - - - ESC instance number - - - reported motor rotation rate - - - reported motor rotation rate without slew adjustment - - - Perceived input voltage for the ESC - - - Perceived current through the ESC - - - ESC temperature in centi-degrees C - - - current consumed total mAh - - - measured motor temperature in centi-degrees C - - - error rate - - - - - ESC extended telemetry data - - - Time since system startup - - - starts from 0 - - - input duty cycle in percent - - - output duty cycle in percent - - - manufacturer-specific status flags - - - Power percentage - - - - - Specifically coded event messages - - - Time since system startup - - - Event identifier - - - 10 - - - 11 - - - 15 - - - 17 - - - 18 - - - 19 - - - 21 - - - 22 - - - 25 - - - 26 - - - 27 - - - 28 - - - 29 - - - 30 - - - 31 - - - 32 - - - 33 - - - 34 - - - 35 - - - 36 - - - 37 - - - 38 - - - 39 - - - 41 - - - 42 - - - 43 - - - 44 - - - 45 - - - 46 - - - 47 - - - 49 - - - 50 - - - 51 - - - 52 - - - 53 - - - 54 - - - 55 - - - 56 - - - 57 - - - 58 - Heli only - - - 59 - Heli only - - - 60 - - - 61 - - - 62 - - - 63 - - - 64 - - - 65 - - - 66 - - - 67 - - - 71 - - - 72 - - - 73 - - - 74 - - - 75 - - - 76 - - - 77 - - - 78 - - - 79 - - - 80 - - - 81 - - - 82 - - - 83 - - - 85 - - - 86 - - - 87 - - - 90 - - - 163 - - - 164 - - - 165 - - - 166 - - - - - - - Filter Center Message - per motor - - - microseconds since system startup - - - instance - - - total number of active harmonic notches - - - First harmonic centre frequency for motor 1 - - - First harmonic centre frequency for motor 2 - - - First harmonic centre frequency for motor 3 - - - First harmonic centre frequency for motor 4 - - - First harmonic centre frequency for motor 5 - - - First harmonic centre frequency for motor 6 - - - Second harmonic centre frequency for motor 1 - - - Second harmonic centre frequency for motor 2 - - - Second harmonic centre frequency for motor 3 - - - Second harmonic centre frequency for motor 4 - - - Second harmonic centre frequency for motor 5 - - - Second harmonic centre frequency for motor 6 - - - - - Filter Center Message - - - microseconds since system startup - - - instance - - - notch centre frequency - - - 2nd harmonic frequency - - - - - Fence status - development diagnostic message - - - Time since system startup - - - bitmask of enabled fences - - - bitmask of automatically enabled fences - - - bitmask of configured-in-parameters fences - - - bitmask of enabled fences - - - bitmask of currently disabled fences - - - current vehicle altitude - - - - - File data - - - File name - - - Offset into the file of this block - - - Length of this data block - - - File data of this block - - - - - https://ardupilot.org/dev/docs/code-overview-adding-a-new-log-message.html - Message defining the format of messages in this file - - - unique-to-this-log identifier for message being defined - - - the number of bytes taken up by this message (including all headers) - - - name of the message being defined - - - character string defining the C-storage-type of the fields in this message - - - the labels of the message being defined - - - - - Message defining units and multipliers used for fields of other messages - - - Time since system startup - - - numeric reference to associated FMT message - - - each character refers to a UNIT message. The unit at an offset corresponds to the field at the same offset in FMT.Format - - - each character refers to a MULT message. The multiplier at an offset corresponds to the field at the same offset in FMT.Format - - - - - currently loaded Geo Fence points - - - Time since system startup - - - total number of stored items - - - index in current sequence - - - point type - - - point latitude - - - point longitude - - - vertex cound in polygon if applicable - - - radius of circle if applicable - - - - - Follow library diagnostic data - - - Time since system startup (microseconds) - - - Target latitude (degrees * 1E7) - - - Target longitude (degrees * 1E7) - - - Target absolute altitude (centimeters) - - - Target velocity, North (m/s) - - - Target velocity, East (m/s) - - - Target velocity, Down (m/s) - - - Vehicle estimated latitude (degrees * 1E7) - - - Vehicle estimated longitude (degrees * 1E7) - - - Vehicle estimated altitude (centimeters) - - - Vehicle estimated altitude Frame - - - - - Filter Tuning Message - per motor - - - microseconds since system startup - - - instance - - - number of active harmonic notches - - - desired harmonic notch centre frequency for motor 1 - - - desired harmonic notch centre frequency for motor 2 - - - desired harmonic notch centre frequency for motor 3 - - - desired harmonic notch centre frequency for motor 4 - - - desired harmonic notch centre frequency for motor 5 - - - desired harmonic notch centre frequency for motor 6 - - - desired harmonic notch centre frequency for motor 7 - - - desired harmonic notch centre frequency for motor 8 - - - desired harmonic notch centre frequency for motor 9 - - - desired harmonic notch centre frequency for motor 10 - - - desired harmonic notch centre frequency for motor 11 - - - desired harmonic notch centre frequency for motor 12 - - - - - FFT Filter Tuning - - - microseconds since system startup - - - peak noise frequency as an energy-weighted average of roll and pitch peak frequencies - - - bandwidth of weighted peak frequency where edges are determined by FFT_ATT_REF - - - signal-to-noise ratio on the roll axis - - - signal-to-noise ratio on the pitch axis - - - signal-to-noise ratio on the yaw axis - - - harmonic fit on roll of the highest noise peak to the second highest noise peak - - - harmonic fit on pitch of the highest noise peak to the second highest noise peak - - - harmonic fit on yaw of the highest noise peak to the second highest noise peak - - - FFT health, X-axis - - - FFT health, Y-axis - - - FFT health, Z-axis - - - FFT cycle time - - - - - FFT Noise Frequency Peak - - - microseconds since system startup - - - peak id where 0 is the centre peak, 1 is the lower shoulder and 2 is the upper shoulder - - - noise frequency of the peak on roll - - - noise frequency of the peak on pitch - - - noise frequency of the peak on yaw - - - bandwidth of the peak frequency on roll where edges are determined by FFT_ATT_REF - - - bandwidth of the peak frequency on pitch where edges are determined by FFT_ATT_REF - - - bandwidth of the peak frequency on yaw where edges are determined by FFT_ATT_REF - - - signal-to-noise ratio on the roll axis - - - signal-to-noise ratio on the pitch axis - - - signal-to-noise ratio on the yaw axis - - - power spectral density bin energy of the peak on roll - - - power spectral density bin energy of the peak on roll - - - power spectral density bin energy of the peak on roll - - - - - Additional FFT Noise Frequency Peak - - - microseconds since system startup - - - update axis - - - Peak 1 frequency - - - Peak 2 frequency - - - Peak 3 Frequency - - - Peak 1 noise bandwidth - - - Peak 2 noise bandwidth - - - Peak 3 noise bandwidth - - - Peak 1 Maximum energy - - - Peak 2 Maximum energy - - - Peak 3 Maximum energy - - - - - Filter Tuning Message - - - microseconds since system startup - - - instance - - - desired harmonic notch centre frequency - - - - - Forward Throttle calculations - - - Time since system startup - - - forward throttle scaler - - - quadplane forward pitch limit - - - navigation pitch lower limit - - - demanded navigation pitch - - - quadplane forward throttle - - - upper limit for navigation pitch - - - - - Simulated Glider Angles and coefficients - - - Time since system startup - - - alpha angle - - - beta angle - - - lift coefficent - - - roll coffecient - - - yaw coefficient - - - - - GPS accuracy information - - - Time since system startup - - - GPS instance number - - - vertical dilution of precision - - - horizontal position accuracy - - - vertical position accuracy - - - speed accuracy - - - yaw accuracy - - - true if vertical velocity is available - - - time since system startup this sample was taken - - - system time delta between the last two reported positions - - - altitude above WGS-84 ellipsoid; INT32_MIN (-2147483648) if unknown - - - RTCM fragments used - - - RTCM fragments discarded - - - - - Information received from GNSS systems attached to the autopilot - - - Time since system startup - - - GPS instance number - - - GPS Fix type; 2D fix, 3D fix etc. - - - 0 - No GPS connected/detected - - - 1 - Receiving valid GPS messages but no lock - - - 2 - Receiving valid messages and 2D lock - - - 3 - Receiving valid messages and 3D lock - - - 4 - Receiving valid messages and 3D lock with differential improvements - - - 5 - Receiving valid messages and 3D RTK Float - - - 6 - Receiving valid messages and 3D RTK Fixed - - - - - milliseconds since start of GPS Week - - - weeks since 5 Jan 1980 - - - number of satellites visible - - - horizontal dilution of precision - - - latitude - - - longitude - - - altitude - - - ground speed - - - ground course - - - vertical speed - - - vehicle yaw - - - boolean value indicating whether this GPS is in use - - - - - GPS Yaw - - - Time since system startup - - - instance - - - reported heading,deg - - - antenna separation,m - - - vertical antenna separation,m - - - minimum tolerable vertical antenna separation,m - - - maximum tolerable vertical antenna separation,m - - - 1 if have yaw - - - - - Raw uBlox data - - - Time since system startup - - - receiver TimeOfWeek measurement - - - GPS week - - - number of space vehicles seen - - - space vehicle number of first vehicle - - - carrier phase measurement - - - pseudorange measurement - - - Doppler measurement - - - measurement quality index - - - carrier-to-noise density ratio - - - loss of lock indicator - - - - - Raw uBlox data - header - - - Time since system startup - - - receiver TimeOfWeek measurement - - - GPS week - - - GPS leap seconds - - - number of space-vehicle measurements to follow - - - receiver tracking status bitfield - - - - - Raw uBlox data - space-vehicle data - - - Time since system startup - - - Pseudorange measurement - - - Carrier phase measurement - - - Doppler measurement - - - GNSS identifier - - - Satellite identifier - - - GLONASS frequency slot - - - carrier phase locktime counter - - - carrier-to-noise density ratio - - - estimated pseudorange measurement standard deviation - - - estimated carrier phase measurement standard deviation - - - estimated Doppler measurement standard deviation - - - tracking status bitfield - - - - - IMU gyroscope data - - - Time since system startup - - - gyroscope sensor instance number - - - time since system startup this sample was taken - - - measured rotation rate about X axis - - - measured rotation rate about Y axis - - - measured rotation rate about Z axis - - - - - IMU Heater data - - - Time since system startup - - - Current IMU temperature - - - Target IMU temperature - - - Proportional portion of response - - - Integral portion of response - - - Controller output to heating element - - - - - Helicopter related messages - - - Time since system startup - - - Instance, 0=Main, 1=Tail - - - Desired rotor speed - - - Estimated rotor speed - - - Governor Output - - - Throttle output - - - throttle ramp up - - - RSC state - - - - - Hygrometer data - - - Time since system startup - - - sensor ID - - - percentage humidity - - - temperature in degrees C - - - - - ICM20789 diagnostics - - - Time since system startup - - - raw temperature from sensor - - - raw pressure from sensor - - - pressure - - - temperature - - - - - https://ardupilot.org/copter/docs/common-ie24-fuelcell.html - Intelligent Energy Fuel Cell generator (legacy protocol) - - - Time since system startup - - - Fuel remaining - - - stack power module power draw - - - output power - - - error codes - - - 1 - Minor internal error is to be ignored - - - 10 - - - 11 - - - 20 - - - 21 - - - 30 - - - 31 - - - 32 - - - 33 - - - 40 - - - - - - - https://ardupilot.org/copter/docs/common-ie24-fuelcell.html - Intelligent Energy Fuel Cell generator - - - Time since system startup - - - Fuel remaining - - - Inlet pressure - - - battery voltage - - - output power - - - stack power module power draw - - - fault number - - - battery power draw - - - generator state - - - 0 - - - 1 - - - 2 - - - 3 - - - 4 - - - - - error code - - - 1 - Minor internal error is to be ignored - - - 10 - - - 11 - - - 20 - - - 21 - - - 30 - - - 31 - - - 32 - - - 33 - - - 40 - - - - - sub-error code - - - - - InertialLabs AHRS data1 - - - Time since system startup - - - GPS INS time (round) - - - Gyro X - - - Gyro Y - - - Gyro z - - - Accelerometer X - - - Accelerometer Y - - - Accelerometer Z - - - - - InertialLabs AHRS data2 - - - Time since system startup - - - GPS INS time (round) - - - Magnetometer X - - - Magnetometer Y - - - Magnetometer Z - - - - - InertialLabs AHRS data3 - - - Time since system startup - - - GPS INS time (round) - - - Static pressure - - - Differential pressure - - - Temperature - - - Baro altitude - - - true airspeed - - - Wind velocity north - - - Wind velocity east - - - Wind velocity down - - - Air Data Unit status - - - - - InertialLabs AHRS data4 - - - Time since system startup - - - GNSS Position timestamp - - - GPS Week - - - Number of satellites - - - Indicator of new update of GPS data - - - GNSS Latitude - - - GNSS Longitude - - - GNSS Altitude - - - GNSS Track over ground - - - GNSS Horizontal speed - - - GNSS Vertical speed - - - - - InertialLabs AHRS data5 - - - Time since system startup - - - GNSS Position timestamp - - - fix type - - - GNSS spoofing status - - - GNSS jamming status - - - GNSS Info1 - - - GNSS Info2 - - - GNSS Angles position type - - - - - InertialLabs AHRS data6 - - - Time since system startup - - - GNSS Position timestamp - - - GNSS Heading timestamp - - - GNSS Heading - - - GNSS Pitch - - - GNSS GDOP - - - GNSS PDOP - - - GNSS HDOP - - - GNSS VDOP - - - GNSS TDOP - - - - - InertialLabs AHRS data7 - - - Time since system startup - - - GPS INS time (round) - - - euler roll - - - euler pitch - - - euler yaw - - - velocity north - - - velocity east - - - velocity down - - - latitude - - - longitude - - - altitude MSL - - - USW1 - - - USW2 - - - Supply voltage - - - - - InertialLabs AHRS data8 - - - Time since system startup - - - GPS INS time (round) - - - position variance north - - - position variance east - - - position variance down - - - velocity variance north - - - velocity variance east - - - velocity variance down - - - - - Inertial Measurement Unit data - - - Time since system startup - - - IMU sensor instance number - - - measured rotation rate about X axis - - - measured rotation rate about Y axis - - - measured rotation rate about Z axis - - - acceleration along X axis - - - acceleration along Y axis - - - acceleration along Z axis - - - gyroscope error count - - - accelerometer error count - - - IMU temperature - - - gyroscope health - - - accelerometer health - - - gyroscope measurement rate - - - accelerometer measurement rate - - - - - IOMCU diagnostic information - - - Time since system startup - - - Status Read error count (zeroed on successful read) - - - Free memory - - - IOMCU uptime - - - Number of packets received by IOMCU - - - Protocol failures on MCU side - - - Reported number of failures on IOMCU side - - - Number of delayed packets received by MCU - - - - - IMU Register unexpected value change - - - Time since system startup - - - bus ID - - - device register bank - - - device register - - - unexpected value - - - - - InertialSensor Batch Logging Data - - - Time since system startup - - - batch sequence number - - - sample sequence number - - - x-axis sample value - - - y-axis sample value - - - z-axis sample value - - - - - InertialSensor Batch Logging Header - - - Time since system startup - - - batch sequence number - - - indicates if this is accel or gyro data - - - IMU sensor instance - - - multiplier to be applied to samples in this batch - - - samples in this batch - - - timestamp of first sample - - - rate at which samples have been collected - - - - - Log data received from JSON simulator - - - Time since system startup (us) - - - Simulation's timestamp (s) - - - Simulation's roll (rad) - - - Simulation's pitch (rad) - - - Simulation's yaw (rad) - - - Simulated gyroscope, X-axis (rad/sec) - - - Simulated gyroscope, Y-axis (rad/sec) - - - Simulated gyroscope, Z-axis (rad/sec) - - - - - Log data received from JSON simulator - - - Time since system startup (us) - - - simulation's velocity, North-axis (m/s) - - - simulation's velocity, East-axis (m/s) - - - simulation's velocity, Down-axis (m/s) - - - simulation's acceleration, X-axis (m/s^2) - - - simulation's acceleration, Y-axis (m/s^2) - - - simulation's acceleration, Z-axis (m/s^2) - - - simulation's acceleration, North (m/s^2) - - - simulation's acceleration, East (m/s^2) - - - simulation's acceleration, Down (m/s^2) - - - - - Slope Landing data - - - Time since system startup - - - progress through landing sequence - - - Landing flags - - - Slope-specific landing flags - - - Slope to landing point - - - Initial slope to landing point - - - Rangefinder correction - - - Height for flare timing. - - - - - Landing gear information - - - Time since system startup - - - Current landing gear state - - - -1 - - - 0 - - - 1 - - - 2 - - - 3 - - - - - Weight on wheels state - - - -1 - - - 0 - - - 1 - - - - - - - Gathered Loweheiser EFI/Governor telemetry - - - Time since system startup - - - target system ID - - - target component ID - - - command - - - efi index - - - desired engine state (0:EFI off 1:EFI on) - - - desired governor state (0:Governor off 1:Governor on) - - - manual throttle value - - - desired electric start - - - - - Gathered Loweheiser EFI/Governor telemetry - - - Time since system startup - - - EFI/Gov sensor instance number - - - battery voltage - - - battery current - - - generator current - - - throttle input - - - EFI battery voltage - - - generator RPM - - - EFI pulse-width - - - fuel flow - - - fuel consumed - - - EFI pressure - - - EFI manifold air temperature - - - cylinder head temperature - - - throttle position sensor - - - - - Information received from compasses - - - Time since system startup - - - magnetometer sensor instance number - - - magnetic field strength in body frame - - - magnetic field strength in body frame - - - magnetic field strength in body frame - - - magnetic field offset in body frame - - - magnetic field offset in body frame - - - magnetic field offset in body frame - - - motor interference magnetic field offset in body frame - - - motor interference magnetic field offset in body frame - - - motor interference magnetic field offset in body frame - - - true if the compass is considered healthy - - - time measurement was taken - - - - - Magnetometer high resolution data - - - Time since system startup - - - CAN node - - - sensor ID on node - - - CAN bus - - - X axis field - - - y axis field - - - z axis field - - - - - GCS MAVLink link statistics - - - Time since system startup - - - mavlink channel number - - - transmitted packet count - - - received packet count - - - perceived number of packets we never received - - - compact representation of some state of the channel - - - 1 - - - 2 - - - 4 - - - 8 - - - 16 - - - - - stream slowdown is the number of ms being added to each message to fit within bandwidth - - - times buffer was full when a message was going to be sent - - - time MAV_GCS_SYSID heartbeat (or manual control) last seen - - - - - MAVLink command we have just executed - - - Time since system startup - - - target system for command - - - target component for command - - - source system for command - - - source component for command - - - command frame - - - mavlink command enum value - - - first parameter from mavlink packet - - - second parameter from mavlink packet - - - third parameter from mavlink packet - - - fourth parameter from mavlink packet - - - X coordinate from mavlink packet - - - Y coordinate from mavlink packet - - - Z coordinate from mavlink packet - - - command result being returned from autopilot - - - true if this command arrived via a COMMAND_LONG rather than COMMAND_INT - - - - - MCU voltage and temprature monitering - - - Time since system startup - - - Temperature - - - Voltage - - - Voltage min - - - Voltage max - - - - - Executed mission command information; emitted when we start to run an item - - - Time since system startup - - - Total number of mission commands - - - This command's offset in mission - - - Command type - - - Parameter 1 - - - Parameter 2 - - - Parameter 3 - - - Parameter 4 - - - Command latitude - - - Command longitude - - - Command altitude - - - Frame used for position - - - - - MMC3416 compass data - - - Time since system startup - - - new measurement X axis - - - new measurement Y axis - - - new measurement Z axis - - - new offset X axis - - - new offset Y axis - - - new offset Z axis - - - - - Mount's desired and actual roll, pitch and yaw angles - - - Time since system startup - - - Instance number - - - Mount mode - - - Desired roll - - - Actual roll - - - Desired pitch - - - Actual pitch - - - Desired yaw in body frame - - - Actual yaw in body frame - - - Desired yaw in earth frame - - - Actual yaw in earth frame - - - Rangefinder distance - - - - - vehicle control mode information - - - Time since system startup - - - vehicle-specific mode number - - - alias for Mode - - - reason for entering this mode; enumeration value - - - 0 - - - 1 - - - 2 - - - 3 - - - 4 - - - 5 - - - 6 - - - 7 - - - 8 - - - 9 - - - 10 - - - 11 - - - 12 - - - 13 - - - 14 - - - 15 - - - 16 - - - 17 - - - 18 - - - 19 - - - 20 - - - 21 - - - 22 - - - 23 - - - 24 - - - 25 - general failsafes, prefer specific failsafes over this as much as possible - - - 26 - - - 27 - - - 28 - - - 29 - - - 30 - - - 31 - - - 32 - - - 33 - - - 34 - - - 35 - - - 36 - - - 37 - - - 38 - - - 39 - - - 40 - - - 41 - - - 42 - - - 43 - - - 44 - - - 45 - - - 46 - - - 47 - - - 48 - - - 49 - - - 50 - - - 51 - - - 52 - - - 53 - - - 54 - - - 55 - - - - - - - Main loop performance monitoring message. - - - Time since system startup - - - Loop delay so far - - - Current task - - - Internal error mask - - - Count of internal error occurances - - - Internal Error line - - - MAVLink message currently being processed - - - MAVLink command currently being processed - - - If semaphore taken, line of semaphore take call - - - count of SPI transactions - - - count of i2c transactions - - - - - Motor mixer information - - - Time since system startup - - - Maximum motor compensation gain - - - Ratio between detected battery voltage and maximum battery voltage - - - Throttle limit set due to battery current limitations - - - Maximum average throttle that can be used to maintain attitude control, derived from throttle mix params - - - Throttle output - - - bit 0 motor failed, bit 1 motors balanced, should be 2 in normal flight - - - - - Textual messages - - - Time since system startup - - - identifier for chunks making up a message - - - chunk sequence number within message identified by ID - - - message text - - - - - Message mapping from single character to numeric multiplier - - - Time since system startup - - - character referenced by FMTU - - - numeric multiplier - - - - - EKF2 beacon sensor diagnostics - - - Time since system startup - - - EKF2 core this data is for - - - Beacon sensor ID - - - Beacon range - - - Beacon range innovation - - - sqrt of beacon range innovation variance - - - Beacon range innovation consistency test ratio - - - Beacon north position - - - Beacon east position - - - Beacon down position - - - High estimate of vertical position offset of beacons rel to EKF origin - - - Low estimate of vertical position offset of beacons rel to EKF origin - - - always zero - - - always zero - - - always zero - - - - - EKF2 estimator outputs - - - Time since system startup - - - EKF2 core this data is for - - - Estimated roll - - - Estimated pitch - - - Estimated yaw - - - Estimated velocity (North component) - - - Estimated velocity (East component) - - - Estimated velocity (Down component) - - - Filtered derivative of vertical position (down) - - - Estimated distance from origin (North component) - - - Estimated distance from origin (East component) - - - Estimated distance from origin (Down component) - - - Estimated gyro bias, X axis - - - Estimated gyro bias, Y axis - - - Estimated gyro bias, Z axis - - - Height of origin above WGS-84 - - - - - EKF2 estimator secondary outputs - - - Time since system startup - - - EKF2 core this data is for - - - Estimated accelerometer Z bias - - - Gyro Scale Factor (X-axis) - - - Gyro Scale Factor (Y-axis) - - - Gyro Scale Factor (Z-axis) - - - Estimated wind velocity (moving-to-North component) - - - Estimated wind velocity (moving-to-East component) - - - Magnetic field strength (North component) - - - Magnetic field strength (East component) - - - Magnetic field strength (Down component) - - - Magnetic field strength (body X-axis) - - - Magnetic field strength (body Y-axis) - - - Magnetic field strength (body Z-axis) - - - Magnetometer used for data - - - - - EKF2 innovations - - - Time since system startup - - - EKF2 core this data is for - - - Innovation in velocity (North component) - - - Innovation in velocity (East component) - - - Innovation in velocity (Down component) - - - Innovation in position (North component) - - - Innovation in position (East component) - - - Innovation in position (Down component) - - - Innovation in magnetic field strength (X-axis component) - - - Innovation in magnetic field strength (Y-axis component) - - - Innovation in magnetic field strength (Z-axis component) - - - Innovation in vehicle yaw - - - Innovation in true-airspeed - - - Accumulated relative error of this core with respect to active primary core - - - A consolidated error score where higher numbers are less healthy - - - - - EKF2 variances SV, SP, SH and SM are probably best described as 'Squared Innovation Test Ratios' where values <1 tells us the measurement was accepted and >1 tells us it was rejected. They represent the square of the (innovation / maximum allowed innovation) where the innovation is the difference between predicted and measured value and the maximum allowed innovation is determined from the uncertainty of the measurement, uncertainty of the prediction and scaled using the number of standard deviations set by the innovation gate parameter for that measurement, eg EK2_MAG_I_GATE, EK2_HGT_I_GATE, etc - - - Time since system startup - - - EKF2 core this data is for - - - Square root of the velocity variance - - - Square root of the position variance - - - Square root of the height variance - - - Magnetic field variance - - - tilt error convergence metric - - - Filtered error in roll/pitch estimate - - - Most recent position reset (North component) - - - Most recent position reset (East component) - - - Filter fault status - - - Filter timeout status bitmask (0:position measurement, 1:velocity measurement, 2:height measurement, 3:magnetometer measurement, 4:airspeed measurement) - - - Filter solution status - - - 1 - attitude estimate valid - - - 2 - horizontal velocity estimate valid - - - 4 - vertical velocity estimate valid - - - 8 - relative horizontal position estimate valid - - - 16 - absolute horizontal position estimate valid - - - 32 - vertical position estimate valid - - - 64 - terrain height estimate valid - - - 128 - in constant position mode - - - 256 - expected good relative horizontal position estimate - used before takeoff - - - 512 - expected good absolute horizontal position estimate - used before takeoff - - - 1024 - optical flow takeoff has been detected - - - 2048 - compensating for baro errors during takeoff - - - 4096 - compensating for baro errors during touchdown - - - 8192 - using GPS position - - - 16384 - GPS glitching is affecting navigation accuracy - - - 32768 - can use GPS for navigation - - - 65536 - has ever been healthy - - - 131072 - rejecting airspeed data - - - 262144 - dead reckoning (e.g. no position or velocity source) - - - - - Filter GPS status - - - Primary core index - - - - - EKF2 Sensor innovations (primary core) and general dumping ground - - - Time since system startup - - - EKF2 core this data is for - - - Normalised flow variance - - - Optical flow LOS rate vector innovations from the main nav filter (X-axis) - - - Optical flow LOS rate vector innovations from the main nav filter (Y-axis) - - - Optical flow LOS rate innovation from terrain offset estimator - - - Height above ground level - - - Estimated vertical position of the terrain relative to the nav filter zero datum - - - Range finder innovations - - - Measured range - - - Filter ground offset state error - - - Magnitude of angular error - - - Magnitude of velocity error - - - Magnitude of position error - - - - - EKF2 quaternion defining the rotation from NED to XYZ (autopilot) axes - - - Time since system startup - - - EKF2 core this data is for - - - Quaternion a term - - - Quaternion b term - - - Quaternion c term - - - Quaternion d term - - - - - EKF2 timing information - - - Time since system startup - - - EKF core this message instance applies to - - - count of samples used to create this message - - - smallest IMU sample interval - - - largest IMU sample interval - - - low-passed achieved average time step rate for the EKF (minimum) - - - low-passed achieved average time step rate for the EKF (maximum) - - - accumulated measurement time interval for the delta angle (minimum) - - - accumulated measurement time interval for the delta angle (maximum) - - - accumulated measurement time interval for the delta velocity (minimum) - - - accumulated measurement time interval for the delta velocity (maximum) - - - - - EKF Yaw Estimator States - - - Time since system startup - - - EKF core this data is for - - - GSF yaw estimate (deg) - - - GSF yaw estimate 1-Sigma uncertainty (deg) - - - Yaw estimate from individual EKF filter 0 (deg) - - - Yaw estimate from individual EKF filter 1 (deg) - - - Yaw estimate from individual EKF filter 2 (deg) - - - Yaw estimate from individual EKF filter 3 (deg) - - - Yaw estimate from individual EKF filter 4 (deg) - - - Weighting applied to yaw estimate from individual EKF filter 0 - - - Weighting applied to yaw estimate from individual EKF filter 1 - - - Weighting applied to yaw estimate from individual EKF filter 2 - - - Weighting applied to yaw estimate from individual EKF filter 3 - - - Weighting applied to yaw estimate from individual EKF filter 4 - - - - - EKF Yaw Estimator Innovations - - - Time since system startup - - - EKF core this data is for - - - North velocity innovation from individual EKF filter 0 (m/s) - - - North velocity innovation from individual EKF filter 1 (m/s) - - - North velocity innovation from individual EKF filter 2 (m/s) - - - North velocity innovation from individual EKF filter 3 (m/s) - - - North velocity innovation from individual EKF filter 4 (m/s) - - - East velocity innovation from individual EKF filter 0 (m/s) - - - East velocity innovation from individual EKF filter 1 (m/s) - - - East velocity innovation from individual EKF filter 2 (m/s) - - - East velocity innovation from individual EKF filter 3 (m/s) - - - East velocity innovation from individual EKF filter 4 (m/s) - - - - - Navigation Tuning information - e.g. vehicle destination - - - Time since system startup - - - distance to the current navigation waypoint - - - bearing to the current navigation waypoint - - - the vehicle's desired heading - - - difference between current vehicle height and target height - - - the vehicle's current distance from the current travel segment - - - integration of the vehicle's crosstrack error - - - difference between vehicle's airspeed and desired airspeed - - - target latitude - - - target longitude - - - target altitude WP - - - target altitude TECS - - - target airspeed - - - - - Named Value Float messages; messages sent to GCS via NAMED_VALUE_FLOAT - - - Time since system startup - - - Name of float - - - Value of float - - - - - Named Value String messages; messages sent to GCS via NAMED_VALUE_STRING - - - Time since system startup - - - Name of string - - - Value of string - - - - - Object avoidance (Bendy Ruler) diagnostics - - - Time since system startup - - - Type of BendyRuler currently active - - - True if Bendy Ruler avoidance is being used - - - Best yaw chosen to avoid obstacle - - - Current vehicle yaw - - - Desired pitch chosen to avoid obstacle - - - True if BendyRuler resisted changing bearing and continued in last calculated bearing - - - Margin from path to obstacle on best yaw chosen - - - Destination latitude - - - Destination longitude - - - Desired alt above EKF Origin - - - Intermediate location chosen for avoidance - - - Intermediate location chosen for avoidance - - - Intermediate alt chosen for avoidance above EKF origin - - - - - Object avoidance (Dijkstra) diagnostics - - - Time since system startup - - - Dijkstra avoidance library state - - - Dijkstra library error condition - - - Destination point in calculated path to destination - - - Number of points in path to destination - - - Destination latitude - - - Destination longitude - - - Object Avoidance chosen destination point latitude - - - Object Avoidance chosen destination point longitude - - - - - Object avoidance path planning visgraph points - - - Time since system startup - - - Visgraph version, increments each time the visgraph is re-generated - - - point number in visgraph - - - Latitude - - - longitude - - - - - Optical flow sensor data - - - Time since system startup - - - Estimated sensor data quality - - - Sensor flow rate, X-axis - - - Sensor flow rate,Y-axis - - - derived rotational velocity, X-axis - - - derived rotational velocity, Y-axis - - - - - Optical Flow Calibration sample - - - Time since system startup - - - Axis (X=0 Y=1) - - - Sample number - - - Flow rate - - - Body rate - - - Los pred - - - - - OFfboard-Guided - an advanced version of GUIDED for companion computers that includes rate/s. - - - Time since system startup - - - target airspeed cm - - - target airspeed accel - - - target alt - - - target alt velocity (rate of change) - - - target alt frame (MAVLink) - - - target heading - - - target heading lim - - - target alt frame (Location) - - - - - Vehicle navigation origin or other notable position - - - Time since system startup - - - Position type - - - 0 - - - 1 - - - - - Position latitude - - - Position longitude - - - Position altitude - - - - - parameter value - - - Time since system startup - - - parameter name - - - parameter value - - - default parameter value for this board and config - - - - - Proportional/Integral/Derivative gain values for vertical acceleration - - - Time since system startup - - - desired value - - - achieved value - - - error between target and achieved - - - proportional part of PID - - - integral part of PID - - - derivative part of PID - - - controller feed-forward portion of response - - - controller derivative feed-forward portion of response - - - scaler applied to D gain to reduce limit cycling - - - slew rate used in slew limiter - - - bitmask of PID state flags - - - 1 - true if the output is saturated, I term anti windup is active - - - 2 - true if the PD sum limit is active - - - 4 - true if the controller was reset - - - 8 - true if the I term has been set externally including reseting to 0 - - - - - - - Proportional/Integral/Derivative gain values for East/West velocity - - - Time since system startup - - - desired value - - - achieved value - - - error between target and achieved - - - proportional part of PID - - - integral part of PID - - - derivative part of PID - - - controller feed-forward portion of response - - - controller derivative feed-forward portion of response - - - scaler applied to D gain to reduce limit cycling - - - slew rate used in slew limiter - - - bitmask of PID state flags - - - 1 - true if the output is saturated, I term anti windup is active - - - 2 - true if the PD sum limit is active - - - 4 - true if the controller was reset - - - 8 - true if the I term has been set externally including reseting to 0 - - - - - - - Plane Proportional/Integral/Derivative gain values for Heading when using COMMAND_INT control. - - - Time since system startup - - - desired value - - - achieved value - - - error between target and achieved - - - proportional part of PID - - - integral part of PID - - - derivative part of PID - - - controller feed-forward portion of response - - - controller derivative feed-forward portion of response - - - scaler applied to D gain to reduce limit cycling - - - slew rate - - - bitmask of PID state flags - - - 1 - true if the output is saturated, I term anti windup is active - - - 2 - true if the PD sum limit is active - - - 4 - true if the controller was reset - - - 8 - true if the I term has been set externally including reseting to 0 - - - - - - - Proportional/Integral/Derivative gain values for North/South velocity - - - Time since system startup - - - desired value - - - achieved value - - - error between target and achieved - - - proportional part of PID - - - integral part of PID - - - derivative part of PID - - - controller feed-forward portion of response - - - controller derivative feed-forward portion of response - - - scaler applied to D gain to reduce limit cycling - - - slew rate used in slew limiter - - - bitmask of PID state flags - - - 1 - true if the output is saturated, I term anti windup is active - - - 2 - true if the PD sum limit is active - - - 4 - true if the controller was reset - - - 8 - true if the I term has been set externally including reseting to 0 - - - - - - - Proportional/Integral/Derivative gain values for Pitch rate - - - Time since system startup - - - desired value - - - achieved value - - - error between target and achieved - - - proportional part of PID - - - integral part of PID - - - derivative part of PID - - - controller feed-forward portion of response - - - controller derivative feed-forward portion of response - - - scaler applied to D gain to reduce limit cycling - - - slew rate used in slew limiter - - - bitmask of PID state flags - - - 1 - true if the output is saturated, I term anti windup is active - - - 2 - true if the PD sum limit is active - - - 4 - true if the controller was reset - - - 8 - true if the I term has been set externally including reseting to 0 - - - - - - - Proportional/Integral/Derivative gain values for Roll rate - - - Time since system startup - - - desired value - - - achieved value - - - error between target and achieved - - - proportional part of PID - - - integral part of PID - - - derivative part of PID - - - controller feed-forward portion of response - - - controller derivative feed-forward portion of response - - - scaler applied to D gain to reduce limit cycling - - - slew rate used in slew limiter - - - bitmask of PID state flags - - - 1 - true if the output is saturated, I term anti windup is active - - - 2 - true if the PD sum limit is active - - - 4 - true if the controller was reset - - - 8 - true if the I term has been set externally including reseting to 0 - - - - - - - Proportional/Integral/Derivative gain values for ground steering yaw rate - - - Time since system startup - - - desired value - - - achieved value - - - error between target and achieved - - - proportional part of PID - - - integral part of PID - - - derivative part of PID - - - controller feed-forward portion of response - - - controller derivative feed-forward portion of response - - - scaler applied to D gain to reduce limit cycling - - - slew rate used in slew limiter - - - bitmask of PID state flags - - - 1 - true if the output is saturated, I term anti windup is active - - - 2 - true if the PD sum limit is active - - - 4 - true if the controller was reset - - - 8 - true if the I term has been set externally including reseting to 0 - - - - - - - Proportional/Integral/Derivative gain values for Yaw rate - - - Time since system startup - - - desired value - - - achieved value - - - error between target and achieved - - - proportional part of PID - - - integral part of PID - - - derivative part of PID - - - controller feed-forward portion of response - - - controller derivative feed-forward portion of response - - - scaler applied to D gain to reduce limit cycling - - - slew rate used in slew limiter - - - bitmask of PID state flags - - - 1 - true if the output is saturated, I term anti windup is active - - - 2 - true if the PD sum limit is active - - - 4 - true if the controller was reset - - - 8 - true if the I term has been set externally including reseting to 0 - - - - - - - QuadPlane Proportional/Integral/Derivative gain values for vertical acceleration - - - Time since system startup - - - desired value - - - achieved value - - - error between target and achieved - - - proportional part of PID - - - integral part of PID - - - derivative part of PID - - - controller feed-forward portion of response - - - controller derivative feed-forward portion of response - - - scaler applied to D gain to reduce limit cycling - - - slew rate - - - bitmask of PID state flags - - - 1 - true if the output is saturated, I term anti windup is active - - - 2 - true if the PD sum limit is active - - - 4 - true if the controller was reset - - - 8 - true if the I term has been set externally including reseting to 0 - - - - - - - QuadPlane Proportional/Integral/Derivative gain values for Pitch rate - - - Time since system startup - - - desired value - - - achieved value - - - error between target and achieved - - - proportional part of PID - - - integral part of PID - - - derivative part of PID - - - controller feed-forward portion of response - - - controller derivative feed-forward portion of response - - - scaler applied to D gain to reduce limit cycling - - - slew rate - - - bitmask of PID state flags - - - 1 - true if the output is saturated, I term anti windup is active - - - 2 - true if the PD sum limit is active - - - 4 - true if the controller was reset - - - 8 - true if the I term has been set externally including reseting to 0 - - - - - - - QuadPlane Proportional/Integral/Derivative gain values for Roll rate - - - Time since system startup - - - desired value - - - achieved value - - - error between target and achieved - - - proportional part of PID - - - integral part of PID - - - derivative part of PID - - - controller feed-forward portion of response - - - controller derivative feed-forward portion of response - - - scaler applied to D gain to reduce limit cycling - - - slew rate - - - bitmask of PID state flags - - - 1 - true if the output is saturated, I term anti windup is active - - - 2 - true if the PD sum limit is active - - - 4 - true if the controller was reset - - - 8 - true if the I term has been set externally including reseting to 0 - - - - - - - QuadPlane Proportional/Integral/Derivative gain values for Yaw rate - - - Time since system startup - - - desired value - - - achieved value - - - error between target and achieved - - - proportional part of PID - - - integral part of PID - - - derivative part of PID - - - controller feed-forward portion of response - - - controller derivative feed-forward portion of response - - - scaler applied to D gain to reduce limit cycling - - - slew rate - - - bitmask of PID state flags - - - 1 - true if the output is saturated, I term anti windup is active - - - 2 - true if the PD sum limit is active - - - 4 - true if the controller was reset - - - 8 - true if the I term has been set externally including reseting to 0 - - - - - - - Precision Landing messages - - - Time since system startup - - - True if Precision Landing is healthy - - - True if landing target is detected - - - Target position relative to vehicle, X-Axis (0 if target not found) - - - Target position relative to vehicle, Y-Axis (0 if target not found) - - - Target velocity relative to vehicle, X-Axis (0 if target not found) - - - Target velocity relative to vehicle, Y-Axis (0 if target not found) - - - Target's relative to origin position as 3-D Vector, X-Axis - - - Target's relative to origin position as 3-D Vector, Y-Axis - - - Target's relative to origin position as 3-D Vector, Z-Axis - - - Time when target was last detected - - - EKF's outlier count - - - Type of estimator used - - - - - autopilot system performance and general data dumping ground - - - Time since system startup - - - Main loop rate - - - Number of long loops detected - - - Number of measurement loops for this message - - - Maximum loop time - - - Free memory available - - - System processor load - - - Internal error line number; last line number on which a internal error was detected - - - Internal error mask; which internal errors have been detected - - - 1 - - - 2 - - - 4 - - - 8 - - - 16 - - - 32 - - - 64 - - - 128 - - - 256 - - - 512 - - - 1024 - - - 2048 - - - 4096 - - - 8192 - - - 16384 - - - 32768 - - - 65536 - - - 131072 - - - 262144 - - - 524288 - - - 1048576 - - - 2097152 - - - 4194304 - - - 8388608 - - - 16777216 - - - 33554432 - - - 67108864 - - - 134217728 - - - 268435456 - - - 536870912 - - - 1073741824 - - - - - Internal error count; how many internal errors have been detected - - - Number of SPI transactions processed - - - Number of i2c transactions processed - - - Number of i2c interrupts serviced - - - number of microseconds being added to each loop to address scheduler overruns - - - RTC time, time since Unix epoch - - - - - Canonical vehicle position - - - Time since system startup - - - Canonical vehicle latitude - - - Canonical vehicle longitude - - - Canonical vehicle altitude - - - Canonical vehicle altitude relative to home - - - Canonical vehicle altitude relative to navigation origin - - - - - System power information - - - Time since system startup - - - Flight board voltage - - - Servo rail voltage - - - System power flags - - - 1 - main brick power supply valid - - - 2 - main servo power supply valid for FMU - - - 4 - USB power is connected - - - 8 - peripheral supply is in over-current state - - - 16 - hi-power peripheral supply is in over-current state - - - 32 - Power status has changed since boot - - - - - Accumulated System power flags; all flags which have ever been set - - - 1 - main brick power supply valid - - - 2 - main servo power supply valid for FMU - - - 4 - USB power is connected - - - 8 - peripheral supply is in over-current state - - - 16 - hi-power peripheral supply is in over-current state - - - 32 - Power status has changed since boot - - - - - Hardware Safety Switch status - - - - - Plane Parameter Tuning data - - - Time since system startup - - - Parameter set being tuned - - - Parameter being tuned - - - Current parameter value - - - Center value (startpoint of current modifications) of parameter being tuned - - - - - Proximity Filtered sensor data - - - Time since system startup - - - Pitch(instance) at which the obstacle is at. 0th layer {-75,-45} degrees. 1st layer {-45,-15} degrees. 2nd layer {-15, 15} degrees. 3rd layer {15, 45} degrees. 4th layer {45,75} degrees. Minimum distance in each layer will be logged. - - - True if proximity sensor is healthy - - - Nearest object in sector surrounding 0-degrees - - - Nearest object in sector surrounding 45-degrees - - - Nearest object in sector surrounding 90-degrees - - - Nearest object in sector surrounding 135-degrees - - - Nearest object in sector surrounding 180-degrees - - - Nearest object in sector surrounding 225-degrees - - - Nearest object in sector surrounding 270-degrees - - - Nearest object in sector surrounding 315-degrees - - - Nearest object in upwards direction - - - Angle to closest object - - - Distance to closest object - - - - - Proximity Raw sensor data - - - Time since system startup - - - Pitch(instance) at which the obstacle is at. 0th layer {-75,-45} degrees. 1st layer {-45,-15} degrees. 2nd layer {-15, 15} degrees. 3rd layer {15, 45} degrees. 4th layer {45,75} degrees. Minimum distance in each layer will be logged. - - - Nearest object in sector surrounding 0-degrees - - - Nearest object in sector surrounding 45-degrees - - - Nearest object in sector surrounding 90-degrees - - - Nearest object in sector surrounding 135-degrees - - - Nearest object in sector surrounding 180-degrees - - - Nearest object in sector surrounding 225-degrees - - - Nearest object in sector surrounding 270-degrees - - - Nearest object in sector surrounding 315-degrees - - - - - Position Control Down - - - Time since system startup - - - Desired position relative to EKF origin + Offsets - - - Target position relative to EKF origin - - - Position relative to EKF origin - - - Desired velocity Down - - - Target velocity Down - - - Velocity Down - - - Desired acceleration Down - - - Target acceleration Down - - - Acceleration Down - - - - - Position Control East - - - Time since system startup - - - Desired position relative to EKF origin + Offsets - - - Target position relative to EKF origin - - - Position relative to EKF origin - - - Desired velocity East - - - Target velocity East - - - Velocity East - - - Desired acceleration East - - - Target acceleration East - - - Acceleration East - - - - - Position Control North - - - Time since system startup - - - Desired position relative to EKF origin - - - Target position relative to EKF origin - - - Position relative to EKF origin - - - Desired velocity North - - - Target velocity North - - - Velocity North - - - Desired acceleration North - - - Target acceleration North - - - Acceleration North - - - - - Position Control Offsets Down - - - Time since system startup - - - Target position offset Down - - - Position offset Down - - - Target velocity offset Down - - - Velocity offset Down - - - Target acceleration offset Down - - - Acceleration offset Down - - - - - Position Control Offsets East - - - Time since system startup - - - Target position offset East - - - Position offset East - - - Target velocity offset East - - - Velocity offset East - - - Target acceleration offset East - - - Acceleration offset East - - - - - Position Control Offsets North - - - Time since system startup - - - Target position offset North - - - Position offset North - - - Target velocity offset North - - - Velocity offset North - - - Target acceleration offset North - - - Acceleration offset North - - - - - Position Control Offsets Terrain (Down) - - - Time since system startup - - - Target position offset Terrain - - - Position offset Terrain - - - Target velocity offset Terrain - - - Velocity offset Terrain - - - Target acceleration offset Terrain - - - Acceleration offset Terrain - - - - - Quadplane Braking - - - Time since system startup - - - braking speed scaler - - - upper limit for navigation pitch - - - upper limit for back transition pitch - - - demanded navigation pitch - - - - - Quadplane position data - - - Time since system startup - - - Position control state - - - 0 - - - 1 - - - 2 - - - 3 - - - 4 - - - 5 - - - 6 - - - 7 - - - 8 - - - - - Distance to next waypoint - - - Target speed - - - Target acceleration - - - True if landing point is overshot or heading off by more than 60 degrees - - - - - QuadPlane vertical tuning message - - - Time since system startup - - - throttle input - - - angle boost - - - throttle output - - - calculated hover throttle - - - desired altitude - - - achieved altitude - - - barometric altitude - - - desired climb rate - - - climb rate - - - transition throttle mix value - - - Transition state: 0-AirspeedWait,1-Timer,2-Done / TailSitter: 0-FW Wait,1-VTOL Wait,2-Done - - - bitmask of assistance flags - - - 1 - true if VTOL assist is active - - - 2 - true if assistance is forced - - - 4 - true if assistance due to low airspeed - - - 8 - true if assistance due to low altitude - - - 16 - true if assistance due to attitude error - - - 32 - true if forcing use of fixed wing controllers - - - 64 - true if recovering from a spin - - - - - - - Quicktune - - - Time since system startup - - - number of parameter being tuned - - - slew rate - - - test gain for current axis and PID element - - - name of parameter being being tuned - - - - - Telemetry radio statistics - - - Time since system startup - - - RSSI - - - RSSI reported from remote radio - - - number of bytes in radio ready to be sent - - - local noise floor - - - local noise floor reported from remote radio - - - damaged packet count - - - fixed damaged packet count - - - - - Rally point information - - - Time since system startup - - - total number of rally points onboard - - - this rally point's sequence number - - - latitude of rally point - - - longitude of rally point - - - altitude of rally point - - - altitude frame flags - - - - - Replay Airspeed Sensor Header - - - airspeed instance number - - - number of airspeed instances - - - - - Replay Airspeed Sensor Instance data - - - measured airspeed - - - timestamp of measured airspeed - - - indicator of airspeed sensor health - - - true if airspeed is configured to be used - - - airspeed instance number - - - - - Desired and achieved vehicle attitude rates. Not logged in Fixed Wing Plane modes. - - - Time since system startup - - - vehicle desired roll rate - - - achieved vehicle roll rate - - - normalized output for Roll - - - vehicle desired pitch rate - - - vehicle pitch rate - - - normalized output for Pitch - - - vehicle desired yaw rate - - - achieved vehicle yaw rate - - - normalized output for Yaw - - - desired vehicle vertical acceleration - - - achieved vehicle vertical acceleration - - - percentage of vertical thrust output current being used - - - vertical thrust output slew rate - - - - - Replay Data Beacon Header - - - zero, unused - - - zero, unused - - - zero, unused - - - zero, unused - - - origin latitude - - - origin longitude - - - origin altitude - - - vehicle_position_ned_returncode,get_origin_returncode,enabled - - - number of beacons - - - - - Replay Data Beacon Instance - - - last update from this beacon instance - - - beacon distance from origin, X-axis - - - beacon distance from origin, Y-axis - - - beacon distance from origin, Z-axis - - - distance to beacon - - - beacon data health - - - beacon instance number - - - - - Replay body odometry data - - - data quality measure - - - delta-position-X - - - delta-position-Y - - - delta-position-Z - - - delta-angle-X - - - delta-angle-Y - - - delta-angle-Z - - - delta-time - - - data timestamp - - - zero, unused - - - zero, unused - - - zero, unused - - - zero, unused - - - - - Replay Data Barometer Header - - - primary barometer instance number - - - number of barometer sensors - - - - - Replay Data Barometer Instance - - - timestamp of barometer data - - - barometer altitude estimate - - - barometer sensor health indication - - - barometer instance number - - - - - Raw RC data - - - Time since system startup - - - data arrival timestamp - - - Protocol currently being decoded - - - Number of valid bytes in message - - - first quartet of bytes - - - second quartet of bytes - - - third quartet of bytes - - - fourth quartet of bytes - - - fifth quartet of bytes - - - sixth quartet of bytes - - - seventh quartet of bytes - - - eight quartet of bytes - - - ninth quartet of bytes - - - tenth quartet of bytes - - - - - (More) RC input channels to vehicle - - - Time since system startup - - - channel 15 input - - - channel 16 input - - - bitmask of RC channels being overridden by mavlink input - - - bitmask of RC state flags - - - 1 - true if the system is receiving good RC values - - - 2 - true if the system is current in RC failsafe - - - 4 - true if the RC Protocol library is indicating the RC receiver is indicating failsafe via its protocol - - - - - - - RC input channels to vehicle - - - Time since system startup - - - channel 1 input - - - channel 2 input - - - channel 3 input - - - channel 4 input - - - channel 5 input - - - channel 6 input - - - channel 7 input - - - channel 8 input - - - channel 9 input - - - channel 10 input - - - channel 11 input - - - channel 12 input - - - channel 13 input - - - channel 14 input - - - - - Servo channel output values 15 to 18 - - - Time since system startup - - - channel 15 output - - - channel 16 output - - - channel 17 output - - - channel 18 output - - - - - Servo channel output values 19 to 32 - - - Time since system startup - - - channel 19 output - - - channel 20 output - - - channel 21 output - - - channel 22 output - - - channel 23 output - - - channel 24 output - - - channel 25 output - - - channel 26 output - - - channel 27 output - - - channel 28 output - - - channel 29 output - - - channel 30 output - - - channel 31 output - - - channel 32 output - - - - - Servo channel output values 1 to 14 - - - Time since system startup - - - channel 1 output - - - channel 2 output - - - channel 3 output - - - channel 4 output - - - channel 5 output - - - channel 6 output - - - channel 7 output - - - channel 8 output - - - channel 9 output - - - channel 10 output - - - channel 11 output - - - channel 12 output - - - channel 13 output - - - channel 14 output - - - - - Relay state - - - Time since system startup - - - relay instance number - - - current state - - - - - Replay external position data - - - external position estimate, X-axis - - - external position estimate, Y-axis - - - external position estimate, Z-axis - - - external attitude quaternion - - - external attitude quaternion - - - external attitude quaternion - - - external attitude quaternion - - - external position error estimate - - - external attitude error estimate - - - timestamp on external error estimate - - - timestamp of last external reset - - - delay on external data - - - - - Replay Event (EKF2) - - - external event injected into EKF - - - 0 - - - 1 - - - 9 - - - 10 - - - 11 - - - 12 - - - 13 - - - 14 - - - 15 - - - - - - - Replay Event (EKF3) - - - external event injected into EKF - - - 0 - - - 1 - - - 9 - - - 10 - - - 11 - - - 12 - - - 13 - - - 14 - - - 15 - - - - - - - Replay external velocity data - - - external velocity estimate, X-axis - - - external velocity estimate, Y-axis - - - external velocity estimate, Z-axis - - - error in velocity estimate - - - timestamp of velocity estimate - - - delay in external velocity data - - - - - Replay Euler Yaw event - - - externally supplied yaw angle - - - error in externally supplied yaw angle - - - timestamp associated with yaw angle and yaw angle error - - - number that needs documenting - - - - - RealFlight mode messages - - - Time since system startup - - - delta time between this frame and the previous frame - - - frames-per-second implied by the current delta time - - - - - Rangefinder sensor information - - - Time since system startup - - - rangefinder instance number this data is from - - - Reported distance from sensor - - - Sensor state - - - 0 - - - 1 - - - 2 - - - 3 - - - 4 - - - - - Sensor orientation - - - 0 - - - 1 - - - 2 - - - 3 - - - 4 - - - 5 - - - 6 - - - 7 - - - 8 - - - 9 - - - 10 - - - 11 - - - 12 - - - 13 - - - 14 - - - 15 - - - 16 - - - 17 - - - 18 - - - 19 - - - 20 - - - 21 - - - 22 - - - 23 - - - 24 - - - 25 - - - 26 - same as ROTATION_ROLL_180_YAW_270 - - - 27 - same as ROTATION_ROLL_180_YAW_90 - - - 28 - - - 29 - - - 30 - - - 31 - - - 32 - - - 33 - - - 34 - - - 35 - - - 36 - - - 37 - - - 38 - this is actually, roll 90, pitch 68.8, yaw 293.3 - - - 39 - - - 40 - - - 41 - - - 42 - - - 43 - - - 44 - - - 100 - - - 101 - - - 102 - - - 103 - - - - - Signal quality. -1 means invalid, 0 is no signal, 100 is perfect signal - - - - - Replay FRame data - Finished frame - - - accumulated method calls made during frame - - - 1 - - - 2 - - - 4 - - - 8 - - - 16 - - - 32 - - - - - true if we are not keeping up with IMU loop rate - - - - - Replay FRame Header - - - Time since system startup - - - Time flying - - - - - Replay FRame - aNother frame header - - - home latitude - - - home latitude - - - home altitude AMSL - - - EAS to TAS factor - - - available memory - - - AHRS trim X - - - AHRS trim Y - - - AHRS trim Z - - - AHRS Vehicle Class - - - configured EKF type - - - 0 - - - 1 - - - - - bitmask of boolean state - - - 1 - - - 2 - - - 4 - - - 8 - - - 16 - - - 32 - - - 64 - - - 128 - - - - - - - Replay Data GPS Header - - - number of GPS sensors - - - instance number of primary sensor - - - - - Replay Data GPS Instance, infrequently changing data - - - antenna body-frame offset, X-axis - - - antenna body-frame offset, Y-axis - - - antenna body-frame offset, Z-axis - - - GPS time lag - - - various GPS flags - - - 1 - - - 2 - - - 4 - - - 8 - - - 16 - - - 32 - - - - - GPS fix status - - - number of satellites GPS is using - - - GPS sensor instance number - - - - - Replay Data GPS Instance - rapidly changing data - - - GPS data timestamp - - - GPS velocity, North - - - GPS velocity, East - - - GPS velocity, Down - - - speed accuracy - - - GPS yaw - - - GPS yaw accuracy - - - timestamp of GPS yaw estimate - - - latitude - - - longitude - - - altitude - - - horizontal accuracy - - - vertical accuracy - - - HDOP - - - GPS sensor instance number - - - - - Richenpower generator telemetry - - - Time since system startup - - - total generator runtime - - - time until generator requires maintenance - - - bitmask of error received from generator - - - current generator RPM - - - output voltage - - - output current - - - generator mode; idle/run/charge/balance - - - - - Replay Inertial Sensor header - - - INS loop rate - - - primary gyro index - - - primary accel index - - - INS loop-delta-t - - - accel count - - - gyro count - - - - - Replay Inertial Sensor instance data - - - x-axis delta-velocity - - - y-axis delta-velocity - - - z-axis delta-velocity - - - x-axis delta-angle - - - y-axis delta-angle - - - z-axis delta-angle - - - delta-velocity-delta-time - - - delta-angle-delta-time - - - use-accel, use-gyro, delta-vel-valid, delta-accel-valid - - - IMU instance - - - - - Replay Data Magnetometer Header - - - vehicle declination - - - true if the compass library is marking itself as available - - - number of compass instances - - - true if compass autodeclination is enabled - - - number of enabled compass instances - - - true if compass learning of offsets is enabled - - - true if compasses are consistent - - - index of first usable compass - - - - - Replay Data Magnetometer Instance - - - last update time for magnetometer data - - - mag sensor offset, X-axis - - - mag sensor offset, Y-axis - - - mag sensor offset, Z-axis - - - field strength, X-axis - - - field strength, Y-axis - - - field strength, Z-axis - - - true if compass is being used for yaw - - - sensor health - - - compass has scale factor - - - magnetometer instance number - - - - - Replay optical flow data - - - raw flow rate, X-axis - - - raw flow rate, Y-axis - - - gyro rate, X-axis - - - gyro rate, Y-axis - - - measurement timestamp - - - gyro rate, X-axis - - - body-frame offset, Y-axis - - - body-frame offset, Z-axis - - - sensor height override - - - flow quality measurement - - - - - Data from RPM sensors - - - Time since system startup - - - Instance - - - Sensor's rpm measurement - - - Signal quality - - - Sensor Health (Bool) - - - - - Replay Data Rangefinder Header - - - rangefinder ground clearance for downward-facing rangefinders - - - rangefinder maximum distance for downward-facing rangefinders - - - number of rangefinder instances - - - - - Replay Data Rangefinder Instance - - - rangefinder body-frame offset, X-axis - - - rangefinder body-frame offset, Y-axis - - - rangefinder body-frame offset, Z-axis - - - Measured rangefinder distance - - - orientation - - - status - - - rangefinder instance number - - - - - Replay Set Lat Lng event - - - latitude - - - longitude - - - position accuracy, 1-StD - - - timestamp of latitude/longitude - - - - - Replay Set Origin event (EKF2) - - - origin latitude - - - origin longitude - - - origin altitude - - - - - Replay Set Origin event (EKF3) - - - origin latitude - - - origin longitude - - - origin altitude - - - - - Received Signal Strength Indicator for RC receiver - - - Time since system startup - - - RSSI - - - RX Link Quality - - - - - Information about RTC clock resets - - - Time since system startup - - - old time - - - new time - - - - - GPS atmospheric perturbation data - - - Time since system startup - - - mavlink channel number this data was received on - - - ID field from RTCM packet - - - RTCM packet length - - - calculated crc32 for the packet - - - - - Replay Terrain SRTM Altitude - - - altitude above origin in meters - - - - - Replay Data Visual Odometry data - - - offset, x-axis - - - offset, y-axis - - - offset, z-axis - - - data delay - - - sensor health - - - sensor enabled - - - - - Replay set-default-airspeed event (EKF2) - - - default airspeed - - - uncertainty in default airspeed - - - - - Replay set-default-airspeed event (EKF3) - - - default airspeed - - - uncertainty in default airspeed - - - - - Replay wheel odometry data - - - delta-angle - - - delta-time - - - data timestamp - - - sensor body-frame offset, x-axis - - - sensor body-frame offset, y-axis - - - sensor body-frame offset, z-axis - - - wheel radius - - - - - Simple Avoidance messages - - - Time since system startup - - - True if Simple Avoidance is active - - - Desired velocity, X-Axis (Velocity before Avoidance) - - - Desired velocity, Y-Axis (Velocity before Avoidance) - - - Desired velocity, Z-Axis (Velocity before Avoidance) - - - Modified velocity, X-Axis (Velocity after Avoidance) - - - Modified velocity, Y-Axis (Velocity after Avoidance) - - - Modified velocity, Z-Axis (Velocity after Avoidance) - - - True if vehicle is backing away - - - - - Simulated Blimp Sin-Angles - - - Time since system startup - - - sin(x angle) - - - sin(y angle) - - - sin(z angle) - - - - - Simulated Blimp Angles - - - Time since system startup - - - x angle - - - y angle - - - z angle - - - - - Simulated Blimp Angles - - - Time since system startup - - - x earth-frame angle - - - y earth-frame angle - - - z earth-frame angle - - - - - Simulated Blimp Body-Frame accelerations - - - Time since system startup - - - x-axis acceleration - - - y-axis acceleration - - - z-axis acceleration - - - - - Simulated Blimp Rotational Accelerations - - - Time since system startup - - - acceleration around X axis - - - acceleration around Y axis - - - acceleration around Z axis - - - - - Swift Health Data - - - Time since system startup - - - Number of packet CRC errors on serial connection - - - Timestamp of last raw data injection to GPS - - - Current number of integer ambiguity hypotheses - - - - - Swift Time Data - - - Time since system startup - - - GPS week number - - - Milliseconds through GPS week - - - residual of milliseconds rounding in ns - - - GPIO pin levels - - - time quality - - - - - Scripting runtime stats - - - Time since system startup - - - script name - - - run time - - - total memory usage of all scripts - - - run memory usage - - - - - Simulated Glider Drop control outputs - - - Time since system startup - - - aileron output - - - elevator output - - - rudder output - - - - - Debug message for SCurve internal error - - - Time since system startup - - - duration of the raised cosine jerk profile - - - maximum value of the raised cosine jerk profile - - - initial velocity magnitude - - - maximum constant acceleration - - - maximum constant velocity - - - Length of the path - - - maximum value of the raised cosine jerk profile - - - segment duration - - - segment duration - - - segment duration - - - segment duration - - - - - Simulated Blimp Fin Angles - - - Time since system startup - - - fin 0 angle - - - fin 1 angle - - - fin 2 angle - - - fin 3 angle - - - - - Simulated Blimp Servo Angles - - - Time since system startup - - - fin 0 servo angle - - - fin 1 servo angle - - - fin 2 servo angle - - - fin 3 servo angle - - - - - Simulated Blimp Fin Forces - - - Time since system startup - - - Fin 0 normal force - - - Fin 1 normal force - - - Fin 2 normal force - - - Fin 3 normal force - - - - - Simulated Blimp Fin Thrust - - - Time since system startup - - - Fin 0 tangential thrust - - - Fin 1 tangential thrust - - - Fin 2 tangential thrust - - - Fin 3 tangential thrust - - - - - Simulated Blimp Fin Velocities - - - Time since system startup - - - fin 0 velocity - - - fin 1 velocity - - - fin 2 velocity - - - fin 3 velocity - - - - - System ID data - - - Time since system startup - - - Time reference for waveform - - - Current waveform sample - - - Instantaneous waveform frequency - - - Delta angle, X-Axis - - - Delta angle, Y-Axis - - - Delta angle, Z-Axis - - - Delta velocity, X-Axis - - - Delta velocity, Y-Axis - - - Delta velocity, Z-Axis - - - - - System ID data for Plane - - - Time since system startup - - - Desired Roll Angle - - - Roll Angle - - - Desired Pitch Angle - - - Pitch Angle - - - Desired Roll Rate - - - Measured Roll Rate - - - Desired Pitch Rate - - - Measured Pitch Rate - - - Aileron - - - Elevator - - - Speed_Scalar - - - EAS2TAS - - - - - System ID settings - - - Time since system startup - - - The axis which is being excited - - - Magnitude of the chirp waveform - - - Frequency at the start of chirp - - - Frequency at the end of chirp - - - Time to reach maximum amplitude of chirp - - - Time at constant frequency before chirp starts - - - Time taken to complete chirp waveform - - - Time to reach zero amplitude after chirp finishes - - - - - SITL simulator state - - - Time since system startup - - - Simulated roll - - - Simulated pitch - - - Simulated yaw - - - Simulated altitude - - - Simulated latitude - - - Simulated longitude - - - Attitude quaternion component 1 - - - Attitude quaternion component 2 - - - Attitude quaternion component 3 - - - Attitude quaternion component 4 - - - - - Additional simulator state - - - Time since system startup - - - North position from home - - - East position from home - - - Down position from home - - - Velocity north - - - Velocity east - - - Velocity down - - - Airspeed - - - Achieved simulation speedup value - - - Number of times simulation paused for serial0 output - - - - - Simulation data - - - Time since system startup - - - Velocity - North component - - - Velocity - East component - - - Velocity - Down component - - - Acceleration - North component - - - Acceleration - East component - - - Acceleration - Down component - - - Position - North component - - - Position - East component - - - Position - Down component - - - - - More Simulated Glider Dropped Calculations - - - Time since system startup - - - altitude in feet - - - equivalent airspeed in knots - - - true airspeed in knots - - - air density - - - lift - - - drag - - - lift/drag ratio - - - elevator output - - - aileron output - - - rudder output - - - Angle of Attack - - - Side Slip Angle - - - air pressire - - - z-axis body-frame acceleration - - - - - Simulated Glider Dropped Calculations - - - Time since system startup - - - altitude in feet - - - altitude in metres - - - equivalent airspeed - - - true airspeed - - - air density - - - lift - - - drag - - - lift/drag ratio - - - elevator output - - - angle of attack - - - X-axis force - - - Y-axis force - - - Z-axis force - - - air pressure - - - - - Slung payload - - - Time since system startup - - - 1 if payload is landed, 0 otherwise - - - Tension ratio, 1 if line is taut, 0 if slack - - - Line length - - - Payload position as offset from vehicle in North direction - - - Payload position as offset from vehicle in East direction - - - Payload position as offset from vehicle in Down direction - - - Payload velocity in North direction - - - Payload velocity in East direction - - - Payload velocity in Down direction - - - Payload acceleration in North direction - - - Payload acceleration in East direction - - - Payload acceleration in Down direction - - - Force on vehicle in North direction - - - Force on vehicle in East direction - - - Force on vehicle in Down direction - - - - - Log data received from JSON simulator 1 - - - Time since system startup (us) - - - Slave instance - - - magic JSON protocol key - - - Slave instance's desired frame rate - - - Slave instance's current frame count - - - 1 if the servo outputs are being used from this instance - - - - - Log data received from JSON simulator 2 - - - Time since system startup - - - Slave instance - - - channel 1 output - - - channel 2 output - - - channel 3 output - - - channel 4 output - - - channel 5 output - - - channel 6 output - - - channel 7 output - - - channel 8 output - - - channel 9 output - - - channel 10 output - - - channel 11 output - - - channel 12 output - - - channel 13 output - - - channel 14 output - - - - - Simulated Blimp Mass and COG - - - Time since system startup - - - mass - - - gravity - - - centre-of-gravity, z-axis - - - - - Smoothed sensor data fed to EKF to avoid inconsistencies - - - Time since system startup - - - Angular Velocity (around x-axis) - - - Angular Velocity (around y-axis) - - - Angular Velocity (around z-axis) - - - Velocity (along x-axis) - - - Velocity (along y-axis) - - - Velocity (along z-axis) - - - Roll - - - Pitch - - - Yaw - - - DCM Roll - - - DCM Pitch - - - DCM Yaw - - - - - Simulated Volz servo information - - - Time since system startup - - - Volz servo ID - - - Current Simulated Position - - - Desired Simulated Position - - - simulated servo voltage - - - simulated servo current - - - simulated PCB Temperature - - - simulated motor Temperature - - - - - https://ardupilot.org/plane/docs/soaring.html - Logged data from soaring feature - - - microseconds since system startup - - - Estimate of vertical speed of surrounding airmass - - - Thermal strength estimate - - - Thermal radius estimate - - - Thermal position estimate north from home - - - Thermal position estimate east from home - - - Aircraft position north from home - - - Aircraft position east from home - - - Aircraft altitude - - - Wind speed north - - - Wind speed east - - - Estimate of achievable climbrate in thermal - - - - - https://ardupilot.org/plane/docs/soaring.html - Soaring Cruise-phase data - - - Time since system startup - - - body-frame wind estimate, x-axis - - - body-frame wind estimate, z-axis - - - estimated thermal vertical speed - - - expected climb-rate lower-limit - - - expected climb-rate upper-limit - - - calculated optimal speed to fly - - - - - Simulated Blimp Rotational forces - - - Time since system startup - - - zero - - - zero - - - zero - - - - - Transformed Simulated Blimp Rotational forces - - - Time since system startup - - - x-axis wobble rotational force - - - y-axis wobble rotational force - - - z-axis wobble rotational force - - - - - Simulated Blimp Torques - - - Time since system startup - - - torque around x axis - - - torque around y axis - - - torque around z axis - - - - - SmartRTL statistics - - - Time since system startup - - - true if SmartRTL could be used right now - - - number of points currently in use - - - maximum number of points that could be used - - - most recent internal action taken by SRTL library - - - 0 - - - 1 - - - 2 - - - 3 - - - 4 - - - 5 - - - 6 - - - 7 - - - 9 - - - 10 - - - 11 - - - - - point associated with most recent action (North component) - - - point associated with most recent action (East component) - - - point associated with most recent action (Down component) - - - - - Simulated Blimp Servo Inputs - - - Time since system startup - - - fin 0 servo angle input - - - fin 1 servo angle input - - - fin 2 servo angle input - - - fin 3 servo angle input - - - - - Stack information - - - Time since system startup - - - thread ID - - - thread priority - - - total stack - - - free stack - - - thread name - - - - - Current status of the aircraft - - - Time since system startup - - - True if aircraft is probably flying - - - Probability that the aircraft is flying - - - Arm status of the aircraft - - - State of the safety switch - - - True if crash is detected - - - True when vehicle is not moving in any axis - - - Current stage of the flight - - - True if impact is detected - - - True if throttle is suppressed - - - - - Helicopter swashplate logging - - - Time since system startup - - - Swashplate instance - - - Blade pitch angle contribution from collective - - - Total blade pitch angle contribution from cyclic - - - Blade pitch angle contribution from pitch cyclic - - - Blade pitch angle contribution from roll cyclic - - - - - Temperature Calibration Information - - - Time since system startup - - - temperature calibration instance number - - - sensor type (0==accel, 1==gyro) - - - current temperature - - - x-axis sample sum - - - y-axis sample sum - - - z-axis sample sum - - - sample count - - - - - http://ardupilot.org/plane/docs/tecs-total-energy-control-system-for-speed-height-tuning-guide.html - Additional information about the Total Energy Control System - - - Time since system startup - - - Potential energy weighting - - - Kinetic energy weighting - - - Energy balance demand - - - Energy balance estimate - - - Energy balance rate demand - - - Energy balance rate estimate - - - Energy balance rate demand + Energy balance rate error*pitch_damping - - - Minimum integrator value - - - Maximum integrator value - - - Energy balance error integral - - - Pitch demand kinetic energy integral - - - Throttle min - - - Throttle max - - - - - http://ardupilot.org/plane/docs/tecs-total-energy-control-system-for-speed-height-tuning-guide.html - Additional additional information about the Total Energy Control System - - - Time since system startup - - - Kinetic Energy Dot (1st derivative of KE) - - - Potential Energy Dot (1st derivative of PE) - - - Kinetic Energy Dot Demand - - - Potential Energy Dot Demand - - - Total energy error - - - Total energy dot error (1st derivative of total energy error) - - - feed-forward throttle - - - integrator limit based on throttle values - - - integrator limit based on throttle values - - - integrator state for throttle - - - lower limit for potential energy error - - - upper limit for potential energy error - - - - - http://ardupilot.org/plane/docs/tecs-total-energy-control-system-for-speed-height-tuning-guide.html - Additional additional additional information about the Total Energy Control System - - - Time since system startup - - - estimate of potential energy - - - estimate of kinetic energy - - - demanded potential energy - - - demanded kinetic energy - - - - - http://ardupilot.org/plane/docs/tecs-total-energy-control-system-for-speed-height-tuning-guide.html - Information about the Total Energy Control System - - - Time since system startup - - - height estimate (UP) currently in use by TECS - - - current climb rate ("delta-height") - - - height demand received by TECS - - - height demand after rate limiting and filtering that TECS is currently trying to achieve - - - climb rate TECS is currently trying to achieve - - - True AirSpeed TECS is currently trying to achieve - - - current estimated True AirSpeed - - - x-axis acceleration estimate ("delta-speed") - - - throttle output - - - pitch output - - - pitch lower limit - - - pitch upper limit - - - demanded acceleration output ("delta-speed demand") - - - flags - - - 1 - - - 2 - - - 4 - - - 8 - - - - - - - Temperature Sensor Data - - - Time since system startup - - - temperature sensor instance - - - temperature - - - - - Terrain database information - - - Time since system startup - - - Terrain database status - - - 0 - not enabled - - - 1 - no terrain data for current location - - - 2 - terrain data available - - - - - Current vehicle latitude - - - Current vehicle longitude - - - terrain Tile spacing - - - current Terrain height - - - Vehicle height above terrain - - - Number of tile requests outstanding - - - Number of tiles in memory - - - terrain reference offset for arming altitude - - - - - Tether state - - - Time since system startup - - - Tether length - - - Force on vehicle in North direction - - - Force on vehicle in East direction - - - Force on vehicle in Down direction - - - - - Tiltrotor tilt values - - - Time since system startup - - - Current tilt angle, 0 deg vertical, 90 deg horizontal - - - Front left tilt angle, 0 deg vertical, 90 deg horizontal - - - Front right tilt angle, 0 deg vertical, 90 deg horizontal - - - - - Camera shutter information - - - Time since system startup - - - Instance number - - - Image number - - - milliseconds since start of GPS week - - - weeks since 5 Jan 1980 - - - current latitude - - - current longitude - - - current altitude - - - current altitude relative to home - - - altitude as reported by GPS - - - current vehicle roll - - - current vehicle pitch - - - current vehicle yaw - - - - - Torqeedo Motor Param - - - Time since system startup - - - instance - - - Motor RPM - - - Motor power - - - Motor voltage - - - Motor current - - - ESC Temp - - - Motor Temp - - - - - Torqeedo Motor Status - - - Time since system startup - - - instance - - - Motor status flags - - - Motor error flags - - - - - Torqeedo Status - - - Time since system startup - - - instance - - - Health - - - Desired Motor Speed (-1000 to 1000) - - - Motor Speed (-1000 to 1000) - - - Success Count - - - Error Count - - - - - Torqeedo System Setup - - - Time since system startup - - - instance - - - Flags - - - Motor type - - - Motor software version - - - Battery capacity - - - Battery charge percentage - - - Battery type - - - Master software version - - - - - Torqeedo System State - - - Time since system startup - - - instance - - - Flags bitmask - - - Master error code - - - Motor voltage - - - Motor current - - - Motor power - - - Motor RPM - - - Motor Temp (higher of pcb or stator) - - - Battery charge percentage - - - Battery voltage - - - Battery current - - - - - tailsitter speed scaling values - - - Time since system startup - - - throttle scaling used for tilt motors - - - speed scaling used for control surfaces method from Q_TAILSIT_GSCMSK - - - minimum output throttle calculated from disk thoery gain scale with Q_TAILSIT_MIN_VO - - - - - Time synchronisation response information - - - Time since system startup - - - system ID this data is for - - - round trip time for this system - - - - - UART stats - - - Time since system startup - - - instance - - - transmitted data rate bytes per second - - - received data rate bytes per second, this is all incoming data, it may not all be processed by the driver using this port. - - - Data rate of dropped received bytes, ideally should be 0. This is the difference between the received data rate and the processed data rate. - - - - - uBlox-specific GPS information (part 1) - - - Time since system startup - - - GPS instance number - - - noise level as measured by GPS - - - jamming indicator; higher is more likely jammed - - - antenna power indicator; 2 is don't know - - - automatic gain control monitor - - - bitmask for messages which haven't been seen - - - - - uBlox-specific GPS information (part 2) - - - Time since system startup - - - GPS instance number - - - imbalance of I part of complex signal - - - magnitude of I part of complex signal - - - imbalance of Q part of complex signal - - - magnitude of Q part of complex signal - - - - - uBlox specific UBX-TIM-TM2 logging, see uBlox interface description - - - Time since system startup - - - GPS instance number - - - Channel (i.e. EXTINT) upon which the pulse was measured - - - Bitmask - - - Rising edge counter - - - Week number of last rising edge - - - Tow of rising edge - - - Millisecond fraction of tow of rising edge in nanoseconds - - - Week number of last falling edge - - - Tow of falling edge - - - Millisecond fraction of tow of falling edge in nanoseconds - - - Accuracy estimate - - - - - Message mapping from single character to SI unit - - - Time since system startup - - - character referenced by FMTU - - - Unit - SI where available - - - - - Variometer data - - - Time since system startup - - - always zero - - - filtered and constrained airspeed - - - AHRS altitude - - - AHRS roll - - - estimated air vertical speed - - - low-pass filtered air vertical speed - - - raw climb rate - - - filtered climb rate - - - expected sink rate relative to air in thermalling turn - - - average acceleration along X axis - - - detected bias in average acceleration along X axis - - - - - Ardupilot version - - - Time since system startup - - - Board type - - - 3 - - - 7 - - - 10 - - - 12 - - - 13 - - - 99 - - - - - Board subtype - - - -1 - - - 1000 - - - 1001 - - - 1002 - - - 1003 - - - 1005 - - - 1006 - - - 1009 - - - 1010 - - - 1012 - - - 1013 - - - 1014 - - - 1015 - - - 1016 - - - 1018 - - - 1020 - - - 1022 - - - 1023 - - - 1024 - - - 1025 - - - 1026 - - - 1027 - - - 1028 - - - 1029 - - - 1030 - - - - - Major version number - - - Minor version number - - - Patch number - - - Firmware type - - - Github commit - - - Firmware version string - - - Board ID - - - Build vehicle type - - - 1 - - - 2 - - - 3 - - - 4 - - - 5 - - - 6 - - - 7 - - - 8 - - - 9 - - - 10 - - - 11 - - - 12 - - - 13 - - - - - Filter version - - - IOMCU MCU ID - - - IOMCU CPU ID - - - - - Processed (acceleration) vibration information - - - Time since system startup - - - Vibration instance number - - - Primary accelerometer filtered vibration, x-axis - - - Primary accelerometer filtered vibration, y-axis - - - Primary accelerometer filtered vibration, z-axis - - - Number of clipping events on 1st accelerometer - - - - - Visual Odometry - - - System time - - - Time period this data covers - - - Angular change for body-frame roll axis - - - Angular change for body-frame pitch axis - - - Angular change for body-frame z axis - - - Position change for body-frame X axis (Forward-Back) - - - Position change for body-frame Y axis (Right-Left) - - - Position change for body-frame Z axis (Down-Up) - - - Confidence - - - - - Vision Position - - - System time - - - Remote system time - - - Corrected system time - - - Position X-axis (North-South) - - - Position Y-axis (East-West) - - - Position Z-axis (Down-Up) - - - Roll lean angle - - - Pitch lean angle - - - Yaw angle - - - Position estimate error - - - Attitude estimate error - - - Position reset counter - - - Ignored - - - Quality - - - - - Vision Velocity - - - System time - - - Remote system time - - - Corrected system time - - - Velocity X-axis (North-South) - - - Velocity Y-axis (East-West) - - - Velocity Z-axis (Down-Up) - - - Velocity estimate error - - - Velocity reset counter - - - Ignored - - - Quality - - - - - VectorNav Attitude data - - - Time since system startup - - - Attitude quaternion 1 - - - Attitude quaternion 2 - - - Attitude quaternion 3 - - - Attitude quaternion 4 - - - Yaw - - - Pitch - - - Roll - - - Yaw unceratainty - - - Pitch uncertainty - - - Roll uncertainty - - - - - VectorNav IMU data - - - Time since system startup - - - Temprature - - - Pressure - - - Magnetic feild X-axis - - - Magnetic feild Y-axis - - - Magnetic feild Z-axis - - - Acceleration X-axis - - - Acceleration Y-axis - - - Acceleration Z-axis - - - Rotation rate X-axis - - - Rotation rate Y-axis - - - Rotation rate Z-axis - - - - - VectorNav INS Kalman Filter data - - - Time since system startup - - - VectorNav INS health status - - - Latitude - - - Longitude - - - Altitude - - - Velocity Northing - - - Velocity Easting - - - Velocity Downing - - - Filter estimated position uncertainty - - - Filter estimated Velocity uncertainty - - - - - Log message for video stabilisation software such as Gyroflow - - - Time since system startup - - - measured rotation rate about X axis - - - measured rotation rate about Y axis - - - measured rotation rate about Z axis - - - acceleration along X axis - - - acceleration along Y axis - - - acceleration along Z axis - - - Estimated attitude quaternion component 1 - - - Estimated attitude quaternion component 2 - - - Estimated attitude quaternion component 3 - - - Estimated attitude quaternion component 4 - - - - - Watchdog diagnostics - - - Time since system startup - - - current task number - - - internal error mast - - - internal error count - - - line internal error was raised on - - - mavlink message being acted on - - - mavlink command being acted on - - - line semaphore was taken on - - - fault_line - - - fault_type - - - fault address - - - fault thread priority - - - ICS regiuster - - - long return address - - - Thread name - - - - - Wheel encoder measurements - - - Time since system startup - - - First wheel distance travelled - - - Quality measurement of Dist0 - - - Second wheel distance travelled - - - Quality measurement of Dist1 - - - - - Winch - - - Time since system startup - - - Healthy - - - Reached end of thread - - - Motor is moving - - - Clutch is engaged (motor can move freely) - - - 0 is Relaxed, 1 is Position Control, 2 is Rate Control - - - Desired Length - - - Estimated Length - - - Desired Rate - - - Tension on line - - - Voltage to Motor - - - Motor temperature - - - - - Windvane readings - - - Time since system startup - - - raw apparent wind direction direct from sensor, in body-frame - - - Apparent wind direction, in body-frame - - - True wind direction - - - raw wind speed direct from sensor - - - Apparent wind Speed - - - True wind speed - - - - - EKF3 beacon sensor diagnostics - - - Time since system startup - - - EKF3 core this data is for - - - Beacon sensor ID - - - Beacon range - - - Beacon range innovation - - - sqrt of beacon range innovation variance - - - Beacon range innovation consistency test ratio - - - Beacon north position - - - Beacon east position - - - Beacon down position - - - High estimate of vertical position offset of beacons rel to EKF origin - - - Low estimate of vertical position offset of beacons rel to EKF origin - - - North position of receiver rel to EKF origin - - - East position of receiver rel to EKF origin - - - Down position of receiver rel to EKF origin - - - - - EKF3 estimator outputs - - - Time since system startup - - - EKF3 core this data is for - - - Estimated roll - - - Estimated pitch - - - Estimated yaw - - - Estimated velocity (North component) - - - Estimated velocity (East component) - - - Estimated velocity (Down component) - - - Filtered derivative of vertical position (down) - - - Estimated distance from origin (North component) - - - Estimated distance from origin (East component) - - - Estimated distance from origin (Down component) - - - Estimated gyro bias, X axis - - - Estimated gyro bias, Y axis - - - Estimated gyro bias, Z axis - - - Height of origin above WGS-84 - - - - - EKF3 estimator secondary outputs - - - Time since system startup - - - EKF3 core this data is for - - - Estimated accelerometer X bias - - - Estimated accelerometer Y bias - - - Estimated accelerometer Z bias - - - Estimated wind velocity (moving-to-North component) - - - Estimated wind velocity (moving-to-East component) - - - Magnetic field strength (North component) - - - Magnetic field strength (East component) - - - Magnetic field strength (Down component) - - - Magnetic field strength (body X-axis) - - - Magnetic field strength (body Y-axis) - - - Magnetic field strength (body Z-axis) - - - Innovation in vehicle drag acceleration (X-axis component) - - - Innovation in vehicle drag acceleration (Y-axis component) - - - Innovation in vehicle sideslip - - - - - EKF3 innovations - - - Time since system startup - - - EKF3 core this data is for - - - Innovation in velocity (North component) - - - Innovation in velocity (East component) - - - Innovation in velocity (Down component) - - - Innovation in position (North component) - - - Innovation in position (East component) - - - Innovation in position (Down component) - - - Innovation in magnetic field strength (X-axis component) - - - Innovation in magnetic field strength (Y-axis component) - - - Innovation in magnetic field strength (Z-axis component) - - - Innovation in vehicle yaw - - - Innovation in true-airspeed - - - Accumulated relative error of this core with respect to active primary core - - - A consolidated error score where higher numbers are less healthy - - - - - EKF3 variances. SV, SP, SH and SM are probably best described as 'Squared Innovation Test Ratios' where values <1 tells us the measurement was accepted and >1 tells us it was rejected. They represent the square of the (innovation / maximum allowed innovation) where the innovation is the difference between predicted and measured value and the maximum allowed innovation is determined from the uncertainty of the measurement, uncertainty of the prediction and scaled using the number of standard deviations set by the innovation gate parameter for that measurement, eg EK3_MAG_I_GATE, EK3_HGT_I_GATE, etc - - - Time since system startup - - - EKF3 core this data is for - - - Square root of the velocity variance - - - Square root of the position variance - - - Square root of the height variance - - - Magnetic field variance - - - Square root of the total airspeed variance - - - Filtered error in roll/pitch estimate - - - Most recent position reset (North component) - - - Most recent position reset (East component) - - - Filter fault status - - - Filter timeout status bitmask (0:position measurement, 1:velocity measurement, 2:height measurement, 3:magnetometer measurement, 4:airspeed measurement, 5:drag measurement) - - - Filter solution status - - - 1 - attitude estimate valid - - - 2 - horizontal velocity estimate valid - - - 4 - vertical velocity estimate valid - - - 8 - relative horizontal position estimate valid - - - 16 - absolute horizontal position estimate valid - - - 32 - vertical position estimate valid - - - 64 - terrain height estimate valid - - - 128 - in constant position mode - - - 256 - expected good relative horizontal position estimate - used before takeoff - - - 512 - expected good absolute horizontal position estimate - used before takeoff - - - 1024 - optical flow takeoff has been detected - - - 2048 - compensating for baro errors during takeoff - - - 4096 - compensating for baro errors during touchdown - - - 8192 - using GPS position - - - 16384 - GPS glitching is affecting navigation accuracy - - - 32768 - can use GPS for navigation - - - 65536 - has ever been healthy - - - 131072 - rejecting airspeed data - - - 262144 - dead reckoning (e.g. no position or velocity source) - - - - - Filter GPS status - - - Primary core index - - - - - EKF3 Sensor innovations (primary core) and general dumping ground - - - Time since system startup - - - EKF3 core this data is for - - - Normalised flow variance - - - Optical flow LOS rate vector innovations from the main nav filter (X-axis) - - - Optical flow LOS rate vector innovations from the main nav filter (Y-axis) - - - Optical flow LOS rate innovation from terrain offset estimator - - - Height above ground level - - - Estimated vertical position of the terrain relative to the nav filter zero datum - - - Range finder innovations - - - Measured range - - - Filter ground offset state error - - - Magnitude of angular error - - - Magnitude of velocity error - - - Magnitude of position error - - - - - EKF3 Body Frame Odometry errors - - - Time since system startup - - - EKF3 core this data is for - - - Innovation in velocity (X-axis) - - - Innovation in velocity (Y-axis) - - - Innovation in velocity (Z-axis) - - - Variance in velocity (X-axis) - - - Variance in velocity (Y-axis) - - - Variance in velocity (Z-axis) - - - - - EKF3 diagnostic data for on-ground-and-not-moving check - - - Time since system startup - - - EKF core this message instance applies to - - - True of on ground and not moving - - - Gyroscope length ratio - - - Accelerometer length ratio - - - Gyroscope rate of change ratio - - - Accelerometer rate of change ratio - - - - - EKF3 sensor selection - - - Time since system startup - - - EKF3 core this data is for - - - compass selection index - - - barometer selection index - - - GPS selection index - - - airspeed selection index - - - Source Set (primary=0/secondary=1/tertiary=2) - - - GPS good to align - - - Waiting for GPS checks to pass - - - Magnetometer fusion (0=not fusing/1=fuse yaw/2=fuse mag) - - - - - EKF3 quaternion defining the rotation from NED to XYZ (autopilot) axes - - - Time since system startup - - - EKF3 core this data is for - - - Quaternion a term - - - Quaternion b term - - - Quaternion c term - - - Quaternion d term - - - - - EKF3 timing information - - - Time since system startup - - - EKF core this message instance applies to - - - count of samples used to create this message - - - smallest IMU sample interval - - - largest IMU sample interval - - - low-passed achieved average time step rate for the EKF (minimum) - - - low-passed achieved average time step rate for the EKF (maximum) - - - accumulated measurement time interval for the delta angle (minimum) - - - accumulated measurement time interval for the delta angle (maximum) - - - accumulated measurement time interval for the delta velocity (minimum) - - - accumulated measurement time interval for the delta velocity (maximum) - - - - - EKF3 Yaw Estimator States - - - Time since system startup - - - EKF3 core this data is for - - - Tilt Error Variance from symbolic equations (rad^2) - - - Tilt Error Variance from difference method (rad^2) - - - - - EKF3 State variances (primary core) - - - Time since system startup - - - EKF3 core this data is for - - - Variance for state 0 (attitude quaternion) - - - Variance for state 1 (attitude quaternion) - - - Variance for state 2 (attitude quaternion) - - - Variance for state 3 (attitude quaternion) - - - Variance for state 4 (velocity-north) - - - Variance for state 5 (velocity-east) - - - Variance for state 6 (velocity-down) - - - Variance for state 7 (position-north) - - - Variance for state 8 (position-east) - - - Variance for state 9 (position-down) - - - Variance for state 10 (delta-angle-bias-x) - - - Variance for state 11 (delta-angle-bias-y) - - - - - more EKF3 State Variances (primary core) - - - Time since system startup - - - EKF3 core this data is for - - - Variance for state 12 (delta-angle-bias-z) - - - Variance for state 13 (delta-velocity-bias-x) - - - Variance for state 14 (delta-velocity-bias-y) - - - Variance for state 15 (delta-velocity-bias-z) - - - Variance for state 16 (Earth-frame mag-field-bias-x) - - - Variance for state 17 (Earth-frame mag-field-bias-y) - - - Variance for state 18 (Earth-frame mag-field-bias-z) - - - Variance for state 19 (body-frame mag-field-bias-x) - - - Variance for state 20 (body-frame mag-field-bias-y) - - - Variance for state 21 (body-frame mag-field-bias-z) - - - Variance for state 22 (wind-north) - - - Variance for state 23 (wind-east) - - - - - EKF Yaw Estimator States - - - Time since system startup - - - EKF core this data is for - - - GSF yaw estimate (deg) - - - GSF yaw estimate 1-Sigma uncertainty (deg) - - - Yaw estimate from individual EKF filter 0 (deg) - - - Yaw estimate from individual EKF filter 1 (deg) - - - Yaw estimate from individual EKF filter 2 (deg) - - - Yaw estimate from individual EKF filter 3 (deg) - - - Yaw estimate from individual EKF filter 4 (deg) - - - Weighting applied to yaw estimate from individual EKF filter 0 - - - Weighting applied to yaw estimate from individual EKF filter 1 - - - Weighting applied to yaw estimate from individual EKF filter 2 - - - Weighting applied to yaw estimate from individual EKF filter 3 - - - Weighting applied to yaw estimate from individual EKF filter 4 - - - - - EKF Yaw Estimator Innovations - - - Time since system startup - - - EKF core this data is for - - - North velocity innovation from individual EKF filter 0 (m/s) - - - North velocity innovation from individual EKF filter 1 (m/s) - - - North velocity innovation from individual EKF filter 2 (m/s) - - - North velocity innovation from individual EKF filter 3 (m/s) - - - North velocity innovation from individual EKF filter 4 (m/s) - - - East velocity innovation from individual EKF filter 0 (m/s) - - - East velocity innovation from individual EKF filter 1 (m/s) - - - East velocity innovation from individual EKF filter 2 (m/s) - - - East velocity innovation from individual EKF filter 3 (m/s) - - - East velocity innovation from individual EKF filter 4 (m/s) - - - - diff --git a/DataLoadAPBin/LogMessageDescriptions/Plane_LegacyDescriptions.json b/DataLoadAPBin/LogMessageDescriptions/Plane_LegacyDescriptions.json new file mode 100644 index 0000000..ee87198 --- /dev/null +++ b/DataLoadAPBin/LogMessageDescriptions/Plane_LegacyDescriptions.json @@ -0,0 +1,199 @@ +{ + "source": "Descriptions and enum entries retained from the previous bundled XML for older logs", + "logformats": [ + { + "name": "GPS", + "fields": [ + { + "name": "Status", + "units": "", + "type": "uint8_t", + "enum": { + "name": "AP_GPS::GPS_Status", + "entries": [ + { + "name": "NO_FIX", + "value": 1, + "description": "Receiving valid GPS messages but no lock" + }, + { + "name": "GPS_OK_FIX_2D", + "value": 2, + "description": "Receiving valid messages and 2D lock" + }, + { + "name": "GPS_OK_FIX_3D", + "value": 3, + "description": "Receiving valid messages and 3D lock" + }, + { + "name": "GPS_OK_FIX_3D_DGPS", + "value": 4, + "description": "Receiving valid messages and 3D lock with differential improvements" + }, + { + "name": "GPS_OK_FIX_3D_RTK_FLOAT", + "value": 5, + "description": "Receiving valid messages and 3D RTK Float" + }, + { + "name": "GPS_OK_FIX_3D_RTK_FIXED", + "value": 6, + "description": "Receiving valid messages and 3D RTK Fixed" + } + ] + } + } + ] + }, + { + "name": "HRSC", + "fields": [ + { + "name": "Stat", + "units": "", + "type": "uint8_t", + "description": "RSC state" + } + ] + }, + { + "name": "QBRK", + "fields": [ + { + "name": "QBPLCD", + "units": "", + "type": "int32_t", + "description": "upper limit for back transition pitch" + } + ] + }, + { + "name": "QPOS", + "fields": [ + { + "name": "State", + "units": "", + "type": "uint8_t", + "enum": { + "name": "QuadPlane::position_control_state", + "entries": [ + { + "name": "QPOS_LAND_DESCEND", + "value": 5 + }, + { + "name": "QPOS_LAND_ABORT", + "value": 6 + }, + { + "name": "QPOS_LAND_FINAL", + "value": 7 + }, + { + "name": "QPOS_LAND_COMPLETE", + "value": 8 + } + ] + } + } + ] + }, + { + "name": "RFRN", + "fields": [ + { + "name": "Flags", + "units": "", + "type": "uint8_t", + "bitmask": { + "name": "AP_DAL::RFRNFlags", + "entries": [ + { + "name": "AHRS_AIRSPEED_SENSOR_ENABLED", + "value": 8 + } + ] + } + } + ] + }, + { + "name": "RTC", + "fields": [ + { + "name": "old_utc", + "units": "μs", + "type": "uint64_t", + "description": "old time" + }, + { + "name": "new_utc", + "units": "μs", + "type": "uint64_t", + "description": "new time" + } + ] + }, + { + "name": "SBLM", + "fields": [ + { + "name": "TimeUS", + "units": "", + "type": "uint64_t", + "description": "Time since system startup" + }, + { + "name": "RAx", + "units": "", + "type": "float", + "description": "acceleration around X axis" + }, + { + "name": "RAy", + "units": "", + "type": "float", + "description": "acceleration around Y axis" + }, + { + "name": "RAz", + "units": "", + "type": "float", + "description": "acceleration around Z axis" + } + ], + "description": "Simulated Blimp Rotational Accelerations" + }, + { + "name": "VER", + "fields": [ + { + "name": "BST", + "units": "", + "type": "uint16_t", + "enum": { + "name": "HAL_BOARD_SUBTYPE", + "entries": [ + { + "name": "HAL_BOARD_SUBTYPE_LINUX_AERO", + "value": 1015 + } + ] + } + } + ] + }, + { + "name": "XKF5", + "fields": [ + { + "name": "offset", + "units": "UNKNOWN", + "type": "int16_t * 100", + "description": "Estimated vertical position of the terrain relative to the nav filter zero datum" + } + ] + } + ] +} diff --git a/DataLoadAPBin/LogMessageDescriptions/Plane_LogMessages.json.xz b/DataLoadAPBin/LogMessageDescriptions/Plane_LogMessages.json.xz new file mode 100644 index 0000000000000000000000000000000000000000..cc807342b213b8837cf93c0e6a8a3370de0eb913 GIT binary patch literal 42736 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 M`vL#}000D8S_Ox5kpKVy literal 0 HcmV?d00001 diff --git a/DataLoadAPBin/dataload_apbin.cpp b/DataLoadAPBin/dataload_apbin.cpp index ab85379..370d624 100644 --- a/DataLoadAPBin/dataload_apbin.cpp +++ b/DataLoadAPBin/dataload_apbin.cpp @@ -15,11 +15,11 @@ #include #include #include -#include #include #include #include #include +#include #include #include #include @@ -40,7 +40,6 @@ #include #include #include -#include // Debugging //#define DEBUG_RUNTIME @@ -624,7 +623,7 @@ PJ::Status DataLoadAPBIN::importData() try #endif // PlotJuggler 4 stores records by topic and field, with nanosecond timestamps. - load_log_messages(_filepath); + load_log_messages(); #ifdef DEBUG_RUNTIME auto publish_start = std::chrono::high_resolution_clock::now(); #endif @@ -1099,71 +1098,68 @@ std::string DataLoadAPBIN::get_unit(const std::string& msg_name, const std::stri } -void DataLoadAPBIN::load_log_messages(const QString& datafile_path) +void DataLoadAPBIN::load_log_messages() { - // Helper to parse a QXmlStreamReader and merge descriptions - auto parseXml = [&](QXmlStreamReader &xml) { - while (!xml.atEnd() && !xml.hasError()) + // A firmware banner identifies which vehicle's descriptions take precedence. + // Without one, merge Copter followed by Plane as the previous loader did. + enum class Vehicle { unknown, copter, plane }; + auto vehicle = Vehicle::unknown; + for (const auto& text : _status_texts) + { + if (text.msg.starts_with("ArduCopter V")) { vehicle = Vehicle::copter; break; } + if (text.msg.starts_with("ArduPlane V")) { vehicle = Vehicle::plane; break; } + } + + auto parseJson = [&](const std::string& content, bool overwrite) { + QJsonParseError error; + const auto document = QJsonDocument::fromJson(QByteArray::fromStdString(content), &error); + if (error.error != QJsonParseError::NoError || !document.isObject()) { - xml.readNext(); - if (xml.isStartElement() && xml.name() == QLatin1String("logformat")) + qWarning() << "Warning: embedded log message JSON parse error:" << error.errorString(); + return; + } + for (const auto& item : document.object().value("logformats").toArray()) + { + const auto message = item.toObject(); + const auto name = message.value("name").toString().toStdString(); + if (name.empty()) continue; + const auto description = message.value("description").toString().trimmed().toStdString(); + if (!description.empty() && (overwrite || _message_tooltips[name].empty())) + _message_tooltips[name] = description; + for (const auto& item_field : message.value("fields").toArray()) { - QString msgName = xml.attributes().value(QLatin1String("name")).toString(); - QString msgDesc; - - // process children until end of this logformat - while (!(xml.isEndElement() && xml.name() == QLatin1String("logformat"))) - { - xml.readNext(); - if (xml.isStartElement()) - { - if (xml.name() == QLatin1String("description")) - { - msgDesc = xml.readElementText().trimmed(); - _message_tooltips[msgName.toStdString()] = msgDesc.toStdString(); - } - else if (xml.name() == QLatin1String("field")) - { - QString fieldName = xml.attributes().value(QLatin1String("name")).toString(); - // read inside field until end - while (!(xml.isEndElement() && xml.name() == QLatin1String("field"))) - { - xml.readNext(); - if (xml.isStartElement() && xml.name() == QLatin1String("description")) - { - QString fdesc = xml.readElementText().trimmed(); - _field_tooltips[msgName.toStdString()][fieldName.toStdString()] = fdesc.toStdString(); - } - } - } - } - } + const auto field = item_field.toObject(); + const auto field_name = field.value("name").toString().toStdString(); + const auto field_description = field.value("description").toString().trimmed().toStdString(); + if (!field_name.empty() && !field_description.empty() && + (overwrite || _field_tooltips[name][field_name].empty())) + _field_tooltips[name][field_name] = field_description; } } }; - // First, parse embedded XMLs compiled into the library (if present). - // Use a sanity check on the embedded string rather than relying on sizeof. - const std::string& embedded = GetEmbeddedLogMessagesXml(); - if (!embedded.empty()) + // Prefer the matching vehicle's current descriptions. Legacy descriptions + // and the other vehicle fill gaps in the matching snapshot. + if (vehicle == Vehicle::copter) { - const char* emb = embedded.c_str(); - size_t emb_len = embedded.size(); - // require a minimal length and at least one '<' character after skipping whitespace - if (emb_len > 10) - { - size_t i = 0; - while (i < emb_len && std::isspace(static_cast(emb[i]))) ++i; - if (i < emb_len && emb[i] == '<') - { - QXmlStreamReader xmlEmbedded(QString::fromUtf8(emb, static_cast(emb_len))); - parseXml(xmlEmbedded); - if (xmlEmbedded.hasError()) - { - qDebug() << "Warning: embedded log message XML parse error:" << xmlEmbedded.errorString(); - } - } - } + parseJson(GetEmbeddedCopterLogMessagesJson(), true); + parseJson(GetEmbeddedCopterLegacyDescriptionsJson(), false); + parseJson(GetEmbeddedPlaneLogMessagesJson(), false); + parseJson(GetEmbeddedPlaneLegacyDescriptionsJson(), false); + } + else if (vehicle == Vehicle::plane) + { + parseJson(GetEmbeddedPlaneLogMessagesJson(), true); + parseJson(GetEmbeddedPlaneLegacyDescriptionsJson(), false); + parseJson(GetEmbeddedCopterLogMessagesJson(), false); + parseJson(GetEmbeddedCopterLegacyDescriptionsJson(), false); + } + else + { + parseJson(GetEmbeddedCopterLogMessagesJson(), true); + parseJson(GetEmbeddedPlaneLogMessagesJson(), true); + parseJson(GetEmbeddedPlaneLegacyDescriptionsJson(), false); + parseJson(GetEmbeddedCopterLegacyDescriptionsJson(), false); } } diff --git a/DataLoadAPBin/dataload_apbin.h b/DataLoadAPBin/dataload_apbin.h index 09e29ac..51146e9 100644 --- a/DataLoadAPBin/dataload_apbin.h +++ b/DataLoadAPBin/dataload_apbin.h @@ -97,10 +97,10 @@ class DataLoadAPBIN : public PJ::FileSourceBase // get unit string for a field std::string get_unit(const std::string& msg_name, const std::string& field_name); - // load human readable descriptions from LogMessages.xml - void load_log_messages(const QString& datafile_path); + // load human readable descriptions from bundled JSON metadata + void load_log_messages(); - // tooltips/descriptions loaded from LogMessages.xml + // tooltips/descriptions loaded from ArduPilot log metadata std::map _message_tooltips; std::map> _field_tooltips; diff --git a/DataLoadAPBin/scripts/generate_LogMessageDescriptions_header.py b/DataLoadAPBin/scripts/generate_LogMessageDescriptions_header.py index 95e07e9..59564f4 100644 --- a/DataLoadAPBin/scripts/generate_LogMessageDescriptions_header.py +++ b/DataLoadAPBin/scripts/generate_LogMessageDescriptions_header.py @@ -1,32 +1,24 @@ #!/usr/bin/env python3 -""" -Generate a C header containing raw string literals with embedded XML -for files from https://autotest.ardupilot.org/LogMessages/ (i.e. Plane.xml and Copter.xml) -If they are missing, emit empty strings so the code compiles but no embedded content is used. +"""Embed bundled ArduPilot JSON log descriptions in a C++ header. -Usage: - generate_LogMessageDescriptions_header.py +Usage: generate_LogMessageDescriptions_header.py -The script reads any xml files in and merges them into a single header file. -Any updates to the XML files requires rebuilding the project to embed the new content. +The compressed Copter and Plane snapshots come from the firmware metadata +directories. Legacy JSON retains older descriptions and enum entries missing +from those snapshots. Updating any input requires rebuilding the plugin. MSVC caps a single string literal at 16380 single-byte characters (error C2026), -and the merged XML is roughly a megabyte, so the content is emitted as an array of -smaller chunks that are joined back together at runtime. Adjacent-literal +so content is emitted in smaller chunks joined at runtime. Adjacent literal concatenation would not help: that has its own 65535 byte cap. """ -import sys +import json +import lzma import os +import sys -# Comfortably below the MSVC limit of 16380 single-byte characters per string literal. +# Comfortably below the MSVC limit of 16380 single-byte characters per literal. MAX_CHUNK_BYTES = 16000 -def read_file_safe(path): - try: - with open(path, 'r', encoding='utf-8') as f: - return f.read() - except Exception: - return '' def split_utf8_chunks(content, max_bytes=MAX_CHUNK_BYTES): """Split content into chunks of at most max_bytes, never inside a UTF-8 character.""" @@ -40,95 +32,69 @@ def split_utf8_chunks(content, max_bytes=MAX_CHUNK_BYTES): end -= 1 chunks.append(data[start:end].decode('utf-8')) start = end - return chunks + return chunks or [''] -def make_chunked_raw_strings(name, content): - # Use a delimiter unlikely to appear in XML. - delim = 'XML_DELIM' - chunks = split_utf8_chunks(content) - if not chunks: - # An empty array is not valid C++, so always emit at least one chunk. - chunks = [''] - lines = [] - lines.append('static const char* const ' + name + 'Chunks[] = {') - for chunk in chunks: +def make_chunked_raw_strings(name, content): + # Choose a delimiter that does not terminate a raw string in this data. + for index in range(100): + delim = 'APJSON' + str(index) + if ')' + delim + '"' not in content: + break + else: + raise ValueError(f'Could not choose a raw-string delimiter for {name}') + lines = ['static const char* const ' + name + 'Chunks[] = {'] + for chunk in split_utf8_chunks(content): lines.append('R"' + delim + '(' + chunk + ')' + delim + '",') - lines.append('};\n') - lines.append('inline const std::string& ' + name + '()') - lines.append('{') - lines.append(' static const std::string joined = []() {') - lines.append(' std::string result;') - lines.append(' result.reserve(' + str(len(content.encode('utf-8'))) + ');') - lines.append(' for (const char* chunk : ' + name + 'Chunks)') - lines.append(' {') - lines.append(' result += chunk;') - lines.append(' }') - lines.append(' return result;') - lines.append(' }();') - lines.append(' return joined;') - lines.append('}\n') + lines.extend([ + '};', + 'inline const std::string& ' + name + '()', + '{', + ' static const std::string joined = []() {', + ' std::string result;', + ' result.reserve(' + str(len(content.encode('utf-8'))) + ');', + ' for (const char* chunk : ' + name + 'Chunks)', + ' {', + ' result += chunk;', + ' }', + ' return result;', + ' }();', + ' return joined;', + '}', + ]) return '\n'.join(lines) -def main(): - if len(sys.argv) < 3: - print('Usage: generate_LogMessageDescriptions_header.py ') - return 2 - input_dir = sys.argv[1] - out_path = sys.argv[2] - - contents = [] - contents.append('/* Auto-generated by generate_LogMessageDescriptions_header.py */') - contents.append('#pragma once') - contents.append('') - contents.append('#include ') - contents.append('\n') - - # Read any XML files in the input directory and merge them into one embedded variable. - merged = [] - if os.path.isdir(input_dir): - for entry in sorted(os.listdir(input_dir)): - # accept files with .xml extension (case-insensitive) or any file - if not os.path.isfile(os.path.join(input_dir, entry)): - continue - _, ext = os.path.splitext(entry) - if ext.lower() != '.xml': - # skip non-XML files - continue - fpath = os.path.join(input_dir, entry) - xml = read_file_safe(fpath) - if not xml: - continue - # strip BOM if present - if xml.startswith('\ufeff'): - xml = xml.lstrip('\ufeff') - merged.append(xml) - # Strip XML prologs and wrap merged content in a single root so the parser - # can consume multiple files as one well-formed XML document. - processed = [] - for xml in merged: - s = xml.lstrip() - if s.startswith('') - if idx != -1: - s = s[idx+2:] - processed.append(s) +def read_json(path): + """Decode, validate and compact a JSON snapshot for embedding.""" + opener = lzma.open if path.endswith('.xz') else open + with opener(path, 'rt', encoding='utf-8') as source: + content = source.read() + data = json.loads(content) + if not isinstance(data, dict) or not isinstance(data.get('logformats'), list): + raise ValueError(f'{path}: expected a logformats array') + return json.dumps(data, ensure_ascii=False, separators=(',', ':'), allow_nan=False) - merged_inner = '\n'.join(processed) - if merged_inner: - merged_content = '\n' + merged_inner + '\n' - else: - merged_content = '' - contents.append(make_chunked_raw_strings('GetEmbeddedLogMessagesXml', merged_content)) - - # Write header directory (ensure parent exists) +def main(): + if len(sys.argv) != 3: + print('Usage: generate_LogMessageDescriptions_header.py ') + return 2 + input_dir, out_path = sys.argv[1:] + contents = ['/* Auto-generated by generate_LogMessageDescriptions_header.py */', + '#pragma once', '', '#include ', ''] + for vehicle in ('Copter', 'Plane'): + for suffix in ('LogMessages.json.xz', 'LegacyDescriptions.json'): + filename = vehicle + '_' + suffix + name = 'GetEmbedded' + vehicle + ('LogMessagesJson' if suffix.startswith('LogMessages') + else 'LegacyDescriptionsJson') + contents.append(make_chunked_raw_strings(name, read_json(os.path.join(input_dir, filename)))) os.makedirs(os.path.dirname(out_path) or '.', exist_ok=True) - with open(out_path, 'w', encoding='utf-8') as out: + # Keep LF endings on Windows so chunk sizes stay within MSVC's byte limit. + with open(out_path, 'w', encoding='utf-8', newline='\n') as out: out.write('\n'.join(contents)) - return 0 + if __name__ == '__main__': sys.exit(main()) diff --git a/README.md b/README.md index f4ab170..013e232 100644 --- a/README.md +++ b/README.md @@ -174,8 +174,23 @@ including older logs without FMTU. Every import resets the decoding state. The message timeline is now `/2. Message Timeline/index`, since PlotJuggler 4 represents scalar series as a topic plus field. The SDK's scalar write API has -no per-field tooltip setter; XML descriptions are retained in dataset metadata -under `field_descriptions`, available in the metadata inspector. +no per-field tooltip setter; descriptions are retained in dataset metadata under +`field_descriptions`, available in the metadata inspector. + +Copter and Plane descriptions are bundled for offline use from compressed JSON +snapshots in `DataLoadAPBin/LogMessageDescriptions`. The Copter snapshot can be +refreshed from [ArduPilot's published metadata](https://firmware.ardupilot.org/Copter/latest/__METADATA__/LogMessages.json.xz); +the Plane snapshot comes from the corresponding Plane firmware metadata. Save +them as `Copter_LogMessages.json.xz` and `Plane_LogMessages.json.xz`. Their +`firmware.git_sha` identifies the snapshot's source revision. Rebuild the plugin +after updating either file. Small legacy JSON files retain descriptions and enum +entries for older logs that are absent from the newer snapshots; the loader uses +the descriptions, while the enum entries are kept for reference. When a log +contains an ArduCopter or ArduPlane firmware banner, the matching JSON takes +precedence; otherwise the snapshots are merged, with Plane taking precedence for +shared fields. Legacy +descriptions and the other vehicle's metadata fill missing fields. These snapshots +may differ from the log's firmware version. ## Test a downloaded or locally built binary diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index b4c7dcd..b7ab94a 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -17,4 +17,6 @@ if(TARGET DataAPBin) endif() add_test(NAME apbin_load_and_lifecycle COMMAND pj_plugin_smoketest $ "${CMAKE_CURRENT_SOURCE_DIR}/logs/00000001.BIN" ${_verify}) + add_test(NAME apbin_metadata_generator + COMMAND "${Python3_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/test_metadata_generator.py") endif() diff --git a/tests/pj_plugin_smoketest.cpp b/tests/pj_plugin_smoketest.cpp index 86432e2..f7dd23b 100644 --- a/tests/pj_plugin_smoketest.cpp +++ b/tests/pj_plugin_smoketest.cpp @@ -238,6 +238,37 @@ QString syntheticLog(const QString& directory, bool modern_msg, require(file.write(bytes) == bytes.size(), "cannot write fixture"); return path; } +QString metadataLog(const QString& directory, const std::string& banner) { + QByteArray bytes; + addFormat(bytes, 42, 15, "CTUN", "Qf", "TimeUS,ThO"); + addFormat(bytes, 43, 15, "PIDW", "Qf", "TimeUS,Act"); + addFormat(bytes, 44, 15, "ATIS", "Qf", "TimeUS,pAcc"); + addFormat(bytes, 45, 19, "SBLM", "Qff", "TimeUS,RAx,Extra"); + if (!banner.empty()) addFormat(bytes, 46, 75, "MSG", "QZ", "TimeUS,Message"); + for (uint8_t type : {42, 43, 44, 45}) { + bytes.append(char(0xa3)); + bytes.append(char(0x95)); + bytes.append(char(type)); + appendLE(bytes, uint64_t(2000000)); + appendLE(bytes, float(1.0)); + if (type == 45) appendLE(bytes, float(2.0)); + } + if (!banner.empty()) { + bytes.append(char(0xa3)); + bytes.append(char(0x95)); + bytes.append(char(46)); + appendLE(bytes, uint64_t(1000000)); + QByteArray text(64, '\0'); + std::memcpy(text.data(), banner.data(), + std::min(banner.size(), 64)); + bytes += text; + } + const auto path = directory + "/metadata.bin"; + QFile file(path); + require(file.open(QFile::WriteOnly), "cannot create metadata fixture"); + require(file.write(bytes) == bytes.size(), "cannot write metadata fixture"); + return path; +} QString snapshotOnlyLog(const QString& directory, bool parameters, bool messages) { QByteArray bytes; @@ -387,6 +418,33 @@ int main(int argc, char** argv) { compareSeries(first, host.series); QTemporaryDir directory; require(directory.isValid(), "temporary directory unavailable"); + // CTUN.ThO differs between vehicle metadata; PIDW and ATIS are new JSON + // entries, while SBLM exists only in the retained legacy descriptions. + for (const auto& [banner, throttle] : + {std::pair{"ArduCopter V4.7.0", "throttle output"}, + std::pair{"ArduPlane V4.7.0", "scaled output throttle"}, + std::pair{"", "scaled output throttle"}}) { + host = RecordingHost{}; + ok(source.loadConfig(config(metadataLog(directory.path(), banner)))); + ok(source.start()); + const auto descriptions = + QJsonDocument::fromJson(QByteArray::fromStdString(host.metadata)) + .object() + .value("field_descriptions") + .toObject(); + require(descriptions.value("/CTUN/ThO").toString() == throttle, + "wrong vehicle's JSON field description"); + require(descriptions.value("/PIDW/Act").toString() == "achieved value", + "new JSON field description missing"); + require(descriptions.value("/ATIS/pAcc").toString() == + "Shaped pitch acceleration target", + "other vehicle's JSON fallback missing"); + require(descriptions.value("/SBLM/RAx").toString() == + "acceleration around X axis" && + descriptions.value("/SBLM/Extra").toString() == + "Simulated Blimp Rotational Accelerations", + "legacy field or message description lost"); + } host = RecordingHost{}; ok(source.loadConfig(config(repeatedParameterLog(directory.path())))); ok(source.start()); @@ -489,7 +547,8 @@ int main(int argc, char** argv) { host.progress_finished, "timestamp overflow or exception cleanup failed"); std::printf( - "OK: real log (%zu series), repeated imports and parameters, " + "OK: real log (%zu series), JSON descriptions, repeated imports and " + "parameters, " "snapshot-only logs, both MSG " "layouts, " "nanosecond timestamps, config, cancellation and errors\n", diff --git a/tests/test_metadata_generator.py b/tests/test_metadata_generator.py new file mode 100644 index 0000000..798f8f4 --- /dev/null +++ b/tests/test_metadata_generator.py @@ -0,0 +1,55 @@ +"""Check offline JSON header generation and portable raw-string boundaries.""" +import importlib.util +import json +import lzma +from pathlib import Path +import subprocess +import sys +import tempfile +import unittest + +SCRIPT = (Path(__file__).resolve().parents[1] / 'DataLoadAPBin/scripts' / + 'generate_LogMessageDescriptions_header.py') +spec = importlib.util.spec_from_file_location('log_descriptions', SCRIPT) +generator = importlib.util.module_from_spec(spec) +spec.loader.exec_module(generator) + + +class MetadataGeneratorTest(unittest.TestCase): + def test_utf8_chunk_boundary(self): + text = 'a' * 15999 + 'ü' + 'b' * 17000 + chunks = generator.split_utf8_chunks(text) + self.assertEqual(''.join(chunks), text) + self.assertTrue(all(len(chunk.encode('utf-8')) <= 16000 for chunk in chunks)) + + def test_generates_valid_lf_header_and_rejects_invalid_snapshot(self): + with tempfile.TemporaryDirectory() as temp: + root = Path(temp) + content = json.dumps({'logformats': [{'name': 'TEST', 'description': 'µ )APJSON0', + 'fields': [{'name': 'F', 'enum': {'name': 'Status', + 'entries': [{'name': 'GOOD', 'value': 1, + 'description': 'Valid'}]}}]}]}, + ensure_ascii=False) + for vehicle in ('Copter', 'Plane'): + with lzma.open(root / f'{vehicle}_LogMessages.json.xz', 'wt', encoding='utf-8') as output: + output.write(content) + (root / f'{vehicle}_LegacyDescriptions.json').write_text(content, encoding='utf-8') + header = root / 'generated.h' + subprocess.run([sys.executable, str(SCRIPT), str(root), str(header)], check=True) + generated = header.read_bytes() + self.assertNotIn(b'\r\n', generated) + self.assertIn(b'R"APJSON1(', generated) + self.assertIn('µ'.encode('utf-8'), generated) + self.assertIn(b'"name":"GOOD"', generated) + self.assertIn(b'"description":"Valid"', generated) + + with lzma.open(root / 'Copter_LogMessages.json.xz', 'wt', encoding='utf-8') as output: + output.write('{}') + result = subprocess.run([sys.executable, str(SCRIPT), str(root), str(header)], + capture_output=True, text=True) + self.assertNotEqual(result.returncode, 0) + self.assertIn('expected a logformats array', result.stderr) + + +if __name__ == '__main__': + unittest.main()