diff --git a/.editorconfig b/.editorconfig
index 2c73f926bdb5ab..2ceadeedf2bd00 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -13,8 +13,9 @@ indent_style = space
indent_size = 4
end_of_line = lf
charset = utf-8
-trim_trailing_whitespace = false # These are the correct rules for APM coding standards, but fixing up old files causes git spam
-insert_final_newline = false
+# These are the correct rules for APM coding standards, but fixing up old files causes git spam
+trim_trailing_whitespace = false
+insert_final_newline = true
[*.mk]
indent_style = tab
diff --git a/.github/workflows/cygwin_build.yml b/.github/workflows/cygwin_build.yml
index 4157e219af2d6c..4b174721603596 100644
--- a/.github/workflows/cygwin_build.yml
+++ b/.github/workflows/cygwin_build.yml
@@ -1,6 +1,140 @@
name: Cygwin Build
-on: [push, pull_request, workflow_dispatch]
+on:
+ push:
+ paths-ignore:
+ # remove other vehicles
+ - 'AntennaTracker/**'
+ - 'Blimp/**'
+ # remove non SITL HAL
+ - 'libraries/AP_HAL_ChibiOS/**'
+ - 'libraries/AP_HAL_ESP32/**'
+ # remove non SITL directories
+ - 'Tools/AP_Bootloader/**'
+ - 'Tools/AP_Periph/**'
+ - 'Tools/CHDK-Script/**'
+ - 'Tools/CPUInfo/**'
+ - 'Tools/CodeStyle/**'
+ - 'Tools/FilterTestTool/**'
+ - 'Tools/Frame_params/**'
+ - 'Tools/GIT_Test/**'
+ - 'Tools/Hello/**'
+ - 'Tools/IO_Firmware/**'
+ - 'Tools/Linux_HAL_Essentials/**'
+ - 'Tools/LogAnalyzer/**'
+ - 'Tools/Pozyx/**'
+ - 'Tools/PrintVersion.py'
+ - 'Tools/Replay/**'
+ - 'Tools/UDP_Proxy/**'
+ - 'Tools/Vicon/**'
+ - 'Tools/bootloaders/**'
+ - 'Tools/completion/**'
+ - 'Tools/debug/**'
+ - 'Tools/environment_install/**'
+ - 'Tools/geotag/**'
+ - 'Tools/gittools/**'
+ - 'Tools/mavproxy_modules/**'
+ - 'Tools/simulink/**'
+ - 'Tools/vagrant/**'
+ # Discard python file from Tools/scripts as not used
+ - 'Tools/scripts/**.py'
+ - 'Tools/scripts/build_sizes/**'
+ - 'Tools/scripts/build_tests/**'
+ - 'Tools/scripts/CAN/**'
+ - 'Tools/scripts/signing/**'
+ # Remove autotest
+ - 'Tools/autotest/**'
+ # Remove markdown files as irrelevant
+ - '**.md'
+ # Remove dotfile at root directory
+ - './.dir-locals.el'
+ - './.dockerignore'
+ - './.editorconfig'
+ - './.flake8'
+ - './.gitattributes'
+ - './.github'
+ - './.gitignore'
+ - './.pre-commit-config.yaml'
+ - './.pydevproject'
+ - './.valgrind-suppressions'
+ - './.valgrindrc'
+ - 'Dockerfile'
+ - 'Vagrantfile'
+ - 'Makefile'
+ # Remove some directories check
+ - '.vscode/**'
+ - '.github/ISSUE_TEMPLATE/**'
+ # Remove change on other workflows
+ - '.github/workflows/test_environment.yml'
+
+ pull_request:
+ paths-ignore:
+ # remove other vehicles
+ - 'AntennaTracker/**'
+ - 'Blimp/**'
+ # remove non SITL HAL
+ - 'libraries/AP_HAL_ChibiOS/**'
+ - 'libraries/AP_HAL_ESP32/**'
+ # remove non SITL directories
+ - 'Tools/AP_Bootloader/**'
+ - 'Tools/AP_Periph/**'
+ - 'Tools/bootloaders/**'
+ - 'Tools/CHDK-Script/**'
+ - 'Tools/CodeStyle/**'
+ - 'Tools/completion/**'
+ - 'Tools/CPUInfo/**'
+ - 'Tools/debug/**'
+ - 'Tools/environment_install/**'
+ - 'Tools/FilterTestTool/**'
+ - 'Tools/Frame_params/**'
+ - 'Tools/geotag/**'
+ - 'Tools/GIT_Test/**'
+ - 'Tools/gittools/**'
+ - 'Tools/Hello/**'
+ - 'Tools/IO_Firmware/**'
+ - 'Tools/Linux_HAL_Essentials/**'
+ - 'Tools/LogAnalyzer/**'
+ - 'Tools/mavproxy_modules/**'
+ - 'Tools/Pozyx/**'
+ - 'Tools/PrintVersion.py'
+ - 'Tools/Replay/**'
+ - 'Tools/simulink/**'
+ - 'Tools/UDP_Proxy/**'
+ - 'Tools/vagrant/**'
+ - 'Tools/Vicon/**'
+ # Discard python file from Tools/scripts as not used
+ - 'Tools/scripts/**.py'
+ - 'Tools/scripts/build_sizes/**'
+ - 'Tools/scripts/build_tests/**'
+ - 'Tools/scripts/CAN/**'
+ - 'Tools/scripts/signing/**'
+ # Remove autotest
+ - 'Tools/autotest/**'
+ # Remove markdown files as irrelevant
+ - '**.md'
+ # Remove dotfile at root directory
+ - './.dir-locals.el'
+ - './.dockerignore'
+ - './.editorconfig'
+ - './.flake8'
+ - './.gitattributes'
+ - './.github'
+ - './.gitignore'
+ - './.pre-commit-config.yaml'
+ - './.pydevproject'
+ - './.valgrind-suppressions'
+ - './.valgrindrc'
+ - 'Dockerfile'
+ - 'Vagrantfile'
+ - 'Makefile'
+ # Remove some directories check
+ - '.vscode/**'
+ - '.github/ISSUE_TEMPLATE/**'
+ # Remove change on other workflows
+ - '.github/workflows/test_environment.yml'
+
+ workflow_dispatch:
+
concurrency:
group: ci-${{github.workflow}}-${{ github.ref }}
cancel-in-progress: true
diff --git a/.github/workflows/esp32_build.yml b/.github/workflows/esp32_build.yml
index f24d8190d5608f..d61477b32dbf36 100644
--- a/.github/workflows/esp32_build.yml
+++ b/.github/workflows/esp32_build.yml
@@ -1,6 +1,144 @@
name: ESP32 Build
-on: [push, pull_request, workflow_dispatch]
+on:
+ push:
+ paths-ignore:
+ # remove non copter and plane vehicles
+ - 'AntennaTracker/**'
+ - 'ArduSub/**'
+ - 'Blimp/**'
+ - 'Rover/**'
+ # remove non esp32 HAL
+ - 'libraries/AP_HAL_ChibiOS/**'
+ - 'libraries/AP_HAL_SITL/**'
+ # remove non SITL directories
+ - 'Tools/AP_Bootloader/**'
+ - 'Tools/AP_Periph/**'
+ - 'Tools/bootloaders/**'
+ - 'Tools/CHDK-Script/**'
+ - 'Tools/CodeStyle/**'
+ - 'Tools/completion/**'
+ - 'Tools/CPUInfo/**'
+ - 'Tools/debug/**'
+ - 'Tools/environment_install/**'
+ - 'Tools/FilterTestTool/**'
+ - 'Tools/Frame_params/**'
+ - 'Tools/geotag/**'
+ - 'Tools/GIT_Test/**'
+ - 'Tools/gittools/**'
+ - 'Tools/Hello/**'
+ - 'Tools/IO_Firmware/**'
+ - 'Tools/Linux_HAL_Essentials/**'
+ - 'Tools/LogAnalyzer/**'
+ - 'Tools/mavproxy_modules/**'
+ - 'Tools/Pozyx/**'
+ - 'Tools/PrintVersion.py'
+ - 'Tools/Replay/**'
+ - 'Tools/simulink/**'
+ - 'Tools/UDP_Proxy/**'
+ - 'Tools/vagrant/**'
+ - 'Tools/Vicon/**'
+ # Discard python file from Tools/scripts as not used
+ - 'Tools/scripts/**.py'
+ - 'Tools/scripts/build_sizes/**'
+ - 'Tools/scripts/build_tests/**'
+ - 'Tools/scripts/CAN/**'
+ - 'Tools/scripts/signing/**'
+ # Remove autotest
+ - 'Tools/autotest/**'
+ # Remove markdown files as irrelevant
+ - '**.md'
+ # Remove dotfile at root directory
+ - './.dir-locals.el'
+ - './.dockerignore'
+ - './.editorconfig'
+ - './.flake8'
+ - './.gitattributes'
+ - './.github'
+ - './.gitignore'
+ - './.pre-commit-config.yaml'
+ - './.pydevproject'
+ - './.valgrind-suppressions'
+ - './.valgrindrc'
+ - 'Dockerfile'
+ - 'Vagrantfile'
+ - 'Makefile'
+ # Remove some directories check
+ - '.vscode/**'
+ - '.github/ISSUE_TEMPLATE/**'
+ # Remove change on other workflows
+ - '.github/workflows/test_environment.yml'
+
+ pull_request:
+ paths-ignore:
+ # remove non copter and plane vehicles
+ - 'AntennaTracker/**'
+ - 'ArduSub/**'
+ - 'Blimp/**'
+ - 'Rover/**'
+ # remove non esp32 HAL
+ - 'libraries/AP_HAL_ChibiOS/**'
+ - 'libraries/AP_HAL_SITL/**'
+ # remove non SITL directories
+ - 'Tools/AP_Bootloader/**'
+ - 'Tools/AP_Periph/**'
+ - 'Tools/bootloaders/**'
+ - 'Tools/CHDK-Script/**'
+ - 'Tools/CodeStyle/**'
+ - 'Tools/completion/**'
+ - 'Tools/CPUInfo/**'
+ - 'Tools/debug/**'
+ - 'Tools/environment_install/**'
+ - 'Tools/FilterTestTool/**'
+ - 'Tools/Frame_params/**'
+ - 'Tools/geotag/**'
+ - 'Tools/GIT_Test/**'
+ - 'Tools/gittools/**'
+ - 'Tools/Hello/**'
+ - 'Tools/IO_Firmware/**'
+ - 'Tools/Linux_HAL_Essentials/**'
+ - 'Tools/LogAnalyzer/**'
+ - 'Tools/mavproxy_modules/**'
+ - 'Tools/Pozyx/**'
+ - 'Tools/PrintVersion.py'
+ - 'Tools/Replay/**'
+ - 'Tools/simulink/**'
+ - 'Tools/UDP_Proxy/**'
+ - 'Tools/vagrant/**'
+ - 'Tools/Vicon/**'
+ # Discard python file from Tools/scripts as not used
+ - 'Tools/scripts/**.py'
+ - 'Tools/scripts/build_sizes/**'
+ - 'Tools/scripts/build_tests/**'
+ - 'Tools/scripts/CAN/**'
+ - 'Tools/scripts/signing/**'
+ # Remove autotest
+ - 'Tools/autotest/**'
+ # Remove markdown files as irrelevant
+ - '**.md'
+ # Remove dotfile at root directory
+ - './.dir-locals.el'
+ - './.dockerignore'
+ - './.editorconfig'
+ - './.flake8'
+ - './.gitattributes'
+ - './.github'
+ - './.gitignore'
+ - './.pre-commit-config.yaml'
+ - './.pydevproject'
+ - './.valgrind-suppressions'
+ - './.valgrindrc'
+ - 'Dockerfile'
+ - 'Vagrantfile'
+ - 'Makefile'
+ # Remove some directories check
+ - '.vscode/**'
+ - '.github/ISSUE_TEMPLATE/**'
+ # Remove change on other workflows
+ - '.github/workflows/test_environment.yml'
+
+ workflow_dispatch:
+
concurrency:
group: ci-${{github.workflow}}-${{ github.ref }}
cancel-in-progress: true
diff --git a/.github/workflows/macos_build.yml b/.github/workflows/macos_build.yml
index e9e54b8d9b8190..67e736006e902e 100644
--- a/.github/workflows/macos_build.yml
+++ b/.github/workflows/macos_build.yml
@@ -1,6 +1,140 @@
name: Macos Build
-on: [push, pull_request, workflow_dispatch]
+on:
+ push:
+ paths-ignore:
+ # remove other env install scripts
+ - 'Tools/environment_install/APM_install.sh'
+ - 'Tools/environment_install/install-ROS-ubuntu.sh'
+ - 'Tools/environment_install/install-prereqs-arch.sh'
+ - 'Tools/environment_install/install-prereqs-ubuntu.sh'
+ - 'Tools/environment_install/install-prereqs-windows-andAPMSource.ps1'
+ - 'Tools/environment_install/install-prereqs-windows.ps1'
+ # remove non esp32 HAL
+ - 'libraries/AP_HAL_ESP32/**'
+ # remove non SITL non stm32 directories
+ - 'Tools/AP_Bootloader/**'
+ - 'Tools/AP_Periph/**'
+ - 'Tools/CHDK-Script/**'
+ - 'Tools/CodeStyle/**'
+ - 'Tools/completion/**'
+ - 'Tools/CPUInfo/**'
+ - 'Tools/debug/**'
+ - 'Tools/FilterTestTool/**'
+ - 'Tools/Frame_params/**'
+ - 'Tools/geotag/**'
+ - 'Tools/GIT_Test/**'
+ - 'Tools/gittools/**'
+ - 'Tools/Hello/**'
+ - 'Tools/Linux_HAL_Essentials/**'
+ - 'Tools/LogAnalyzer/**'
+ - 'Tools/mavproxy_modules/**'
+ - 'Tools/Pozyx/**'
+ - 'Tools/PrintVersion.py'
+ - 'Tools/Replay/**'
+ - 'Tools/simulink/**'
+ - 'Tools/UDP_Proxy/**'
+ - 'Tools/vagrant/**'
+ - 'Tools/Vicon/**'
+ # Discard python file from Tools/scripts as not used
+ - 'Tools/scripts/**.py'
+ - 'Tools/scripts/build_sizes/**'
+ - 'Tools/scripts/build_tests/**'
+ - 'Tools/scripts/CAN/**'
+ - 'Tools/scripts/signing/**'
+ # Remove autotests stuff
+ - 'Tools/autotest/**'
+ # Remove markdown files as irrelevant
+ - '**.md'
+ # Remove dotfile at root directory
+ - './.dir-locals.el'
+ - './.dockerignore'
+ - './.editorconfig'
+ - './.flake8'
+ - './.gitattributes'
+ - './.github'
+ - './.gitignore'
+ - './.pre-commit-config.yaml'
+ - './.pydevproject'
+ - './.valgrind-suppressions'
+ - './.valgrindrc'
+ - 'Dockerfile'
+ - 'Vagrantfile'
+ - 'Makefile'
+ # Remove some directories check
+ - '.vscode/**'
+ - '.github/ISSUE_TEMPLATE/**'
+ # Remove change on other workflows
+ - '.github/workflows/test_environment.yml'
+
+ pull_request:
+ paths-ignore:
+ # remove other env install scripts
+ - 'Tools/environment_install/APM_install.sh'
+ - 'Tools/environment_install/install-ROS-ubuntu.sh'
+ - 'Tools/environment_install/install-prereqs-arch.sh'
+ - 'Tools/environment_install/install-prereqs-ubuntu.sh'
+ - 'Tools/environment_install/install-prereqs-windows-andAPMSource.ps1'
+ - 'Tools/environment_install/install-prereqs-windows.ps1'
+ # remove non esp32 HAL
+ - 'libraries/AP_HAL_ESP32/**'
+ # remove non SITL non stm32 directories
+ - 'Tools/AP_Bootloader/**'
+ - 'Tools/AP_Periph/**'
+ - 'Tools/CHDK-Script/**'
+ - 'Tools/CodeStyle/**'
+ - 'Tools/completion/**'
+ - 'Tools/CPUInfo/**'
+ - 'Tools/debug/**'
+ - 'Tools/FilterTestTool/**'
+ - 'Tools/Frame_params/**'
+ - 'Tools/geotag/**'
+ - 'Tools/GIT_Test/**'
+ - 'Tools/gittools/**'
+ - 'Tools/Hello/**'
+ - 'Tools/Linux_HAL_Essentials/**'
+ - 'Tools/LogAnalyzer/**'
+ - 'Tools/mavproxy_modules/**'
+ - 'Tools/Pozyx/**'
+ - 'Tools/PrintVersion.py'
+ - 'Tools/Replay/**'
+ - 'Tools/simulink/**'
+ - 'Tools/UDP_Proxy/**'
+ - 'Tools/vagrant/**'
+ - 'Tools/Vicon/**'
+ # Discard python file from Tools/scripts as not used
+ - 'Tools/scripts/**.py'
+ - 'Tools/scripts/build_sizes/**'
+ - 'Tools/scripts/build_tests/**'
+ - 'Tools/scripts/CAN/**'
+ - 'Tools/scripts/signing/**'
+ # Remove autotests stuff
+ - 'Tools/autotest/**'
+ # Remove markdown files as irrelevant
+ - '**.md'
+ # Remove dotfile at root directory
+ - './.dir-locals.el'
+ - './.dockerignore'
+ - './.editorconfig'
+ - './.flake8'
+ - './.gitattributes'
+ - './.github'
+ - './.gitignore'
+ - './.pre-commit-config.yaml'
+ - './.pydevproject'
+ - './.valgrind-suppressions'
+ - './.valgrindrc'
+ - 'Dockerfile'
+ - 'Vagrantfile'
+ - 'Makefile'
+ # Remove some directories check
+ - '.vscode/**'
+ - '.github/ISSUE_TEMPLATE/**'
+ # Remove change on other workflows
+ - '.github/workflows/test_environment.yml'
+
+ workflow_dispatch:
+
concurrency:
group: ci-${{github.workflow}}-${{ github.ref }}
cancel-in-progress: true
diff --git a/.github/workflows/test_ccache.yml b/.github/workflows/test_ccache.yml
index 3f3ba047dfcf4c..ef1961c363afc9 100644
--- a/.github/workflows/test_ccache.yml
+++ b/.github/workflows/test_ccache.yml
@@ -1,9 +1,124 @@
name: test ccache
-on: [push, pull_request, workflow_dispatch]
-# paths:
-# - "*"
-# - "!README.md" <-- don't rebuild on doc change
+on:
+ push:
+ paths-ignore:
+ # remove other vehicles
+ - 'AntennaTracker/**'
+ - 'ArduPlane/**'
+ - 'ArduSub/**'
+ - 'Blimp/**'
+ - 'Rover/**'
+ # remove non chibios HAL
+ - 'libraries/AP_HAL_Linux/**'
+ - 'libraries/AP_HAL_ESP32/**'
+ - 'libraries/AP_HAL_SITL/**'
+ # remove non stm directories
+ - 'Tools/CHDK-Script/**'
+ - 'Tools/CodeStyle/**'
+ - 'Tools/completion/**'
+ - 'Tools/debug/**'
+ - 'Tools/environment_install/**'
+ - 'Tools/FilterTestTool/**'
+ - 'Tools/Frame_params/**'
+ - 'Tools/geotag/**'
+ - 'Tools/GIT_Test/**'
+ - 'Tools/gittools/**'
+ - 'Tools/Hello/**'
+ - 'Tools/LogAnalyzer/**'
+ - 'Tools/mavproxy_modules/**'
+ - 'Tools/Pozyx/**'
+ - 'Tools/PrintVersion.py'
+ - 'Tools/Replay/**'
+ - 'Tools/simulink/**'
+ - 'Tools/UDP_Proxy/**'
+ - 'Tools/vagrant/**'
+ - 'Tools/Vicon/**'
+ # Remove autotests stuff
+ - 'Tools/autotest/**'
+ # Remove markdown files as irrelevant
+ - '**.md'
+ # Remove dotfile at root directory
+ - './.dir-locals.el'
+ - './.dockerignore'
+ - './.editorconfig'
+ - './.flake8'
+ - './.gitattributes'
+ - './.github'
+ - './.gitignore'
+ - './.pre-commit-config.yaml'
+ - './.pydevproject'
+ - './.valgrind-suppressions'
+ - './.valgrindrc'
+ - 'Dockerfile'
+ - 'Vagrantfile'
+ - 'Makefile'
+ # Remove some directories check
+ - '.vscode/**'
+ - '.github/ISSUE_TEMPLATE/**'
+ # Remove change on other workflows
+ - '.github/workflows/test_environment.yml'
+
+ pull_request:
+ paths-ignore:
+ # remove other vehicles
+ - 'AntennaTracker/**'
+ - 'ArduPlane/**'
+ - 'ArduSub/**'
+ - 'Blimp/**'
+ - 'Rover/**'
+ # remove non chibios HAL
+ - 'libraries/AP_HAL_Linux/**'
+ - 'libraries/AP_HAL_ESP32/**'
+ - 'libraries/AP_HAL_SITL/**'
+ # remove non stm directories
+ - 'Tools/CHDK-Script/**'
+ - 'Tools/CodeStyle/**'
+ - 'Tools/completion/**'
+ - 'Tools/debug/**'
+ - 'Tools/environment_install/**'
+ - 'Tools/FilterTestTool/**'
+ - 'Tools/Frame_params/**'
+ - 'Tools/geotag/**'
+ - 'Tools/GIT_Test/**'
+ - 'Tools/gittools/**'
+ - 'Tools/Hello/**'
+ - 'Tools/LogAnalyzer/**'
+ - 'Tools/mavproxy_modules/**'
+ - 'Tools/Pozyx/**'
+ - 'Tools/PrintVersion.py'
+ - 'Tools/Replay/**'
+ - 'Tools/simulink/**'
+ - 'Tools/UDP_Proxy/**'
+ - 'Tools/vagrant/**'
+ - 'Tools/Vicon/**'
+ # Remove autotests stuff
+ - 'Tools/autotest/**'
+ # Remove markdown files as irrelevant
+ - '**.md'
+ # Remove dotfile at root directory
+ - './.dir-locals.el'
+ - './.dockerignore'
+ - './.editorconfig'
+ - './.flake8'
+ - './.gitattributes'
+ - './.github'
+ - './.gitignore'
+ - './.pre-commit-config.yaml'
+ - './.pydevproject'
+ - './.valgrind-suppressions'
+ - './.valgrindrc'
+ - 'Dockerfile'
+ - 'Vagrantfile'
+ - 'Makefile'
+ # Remove some directories check
+ - '.vscode/**'
+ - '.github/ISSUE_TEMPLATE/**'
+ # Remove change on other workflows
+ - '.github/workflows/test_environment.yml'
+
+ workflow_dispatch:
+
concurrency:
group: ci-${{github.workflow}}-${{ github.ref }}
cancel-in-progress: true
@@ -11,7 +126,7 @@ concurrency:
jobs:
build:
runs-on: ubuntu-20.04
- container: ardupilot/ardupilot-dev-${{ matrix.toolchain }}:latest
+ container: ardupilot/ardupilot-dev-${{ matrix.toolchain }}:v0.0.29
strategy:
fail-fast: false # don't cancel if a job from the matrix fails
matrix:
@@ -29,5 +144,5 @@ jobs:
run: |
PATH="/usr/lib/ccache:/opt/gcc-arm-none-eabi-${{matrix.gcc}}/bin:$PATH"
Tools/scripts/build_tests/test_ccache.py --boards MatekF405,MatekF405-bdshot --min-cache-pct=75
- Tools/scripts/build_tests/test_ccache.py --boards CubeOrange,Durandal --min-cache-pct=75
+ Tools/scripts/build_tests/test_ccache.py --boards Durandal,Pixhawk6X --min-cache-pct=70
diff --git a/.github/workflows/test_chibios.yml b/.github/workflows/test_chibios.yml
index bf0a4f78dc9526..e9082244ad09a0 100644
--- a/.github/workflows/test_chibios.yml
+++ b/.github/workflows/test_chibios.yml
@@ -1,10 +1,132 @@
name: test chibios
-on: [push, pull_request, workflow_dispatch]
+on:
+ push:
+ paths-ignore:
+ # remove non chibios HAL
+ - 'libraries/AP_HAL_Linux/**'
+ - 'libraries/AP_HAL_ESP32/**'
+ - 'libraries/AP_HAL_SITL/**'
+ # remove non stm directories
+ - 'Tools/CHDK-Script/**'
+ - 'Tools/CodeStyle/**'
+ - 'Tools/completion/**'
+ - 'Tools/debug/**'
+ - 'Tools/environment_install/**'
+ - 'Tools/FilterTestTool/**'
+ - 'Tools/Frame_params/**'
+ - 'Tools/geotag/**'
+ - 'Tools/GIT_Test/**'
+ - 'Tools/gittools/**'
+ - 'Tools/Hello/**'
+ - 'Tools/LogAnalyzer/**'
+ - 'Tools/mavproxy_modules/**'
+ - 'Tools/Pozyx/**'
+ - 'Tools/PrintVersion.py'
+ - 'Tools/Replay/**'
+ - 'Tools/simulink/**'
+ - 'Tools/UDP_Proxy/**'
+ - 'Tools/vagrant/**'
+ - 'Tools/Vicon/**'
+ # Remove vehicles autotest we need support of test_build_option.py in the Tools/autotest directory
+ - 'Tools/autotest/antennatracker.py'
+ - 'Tools/autotest/arduplane.py'
+ - 'Tools/autotest/ardusub.py'
+ - 'Tools/autotest/balancebot.py'
+ - 'Tools/autotest/location.txt'
+ - 'Tools/autotest/quadplane.py'
+ - 'Tools/autotest/rover.py'
+ - 'Tools/autotest/sailboat.py'
+ - 'Tools/autotest/swarminit.txt'
+ # Remove markdown files as irrelevant
+ - '**.md'
+ # Remove dotfile at root directory
+ - './.dir-locals.el'
+ - './.dockerignore'
+ - './.editorconfig'
+ - './.flake8'
+ - './.gitattributes'
+ - './.github'
+ - './.gitignore'
+ - './.pre-commit-config.yaml'
+ - './.pydevproject'
+ - './.valgrind-suppressions'
+ - './.valgrindrc'
+ - 'Dockerfile'
+ - 'Vagrantfile'
+ - 'Makefile'
+ # Remove some directories check
+ - '.vscode/**'
+ - '.github/ISSUE_TEMPLATE/**'
+ # Remove change on other workflows
+ - '.github/workflows/test_environment.yml'
+
+ pull_request:
+ paths-ignore:
+ # remove non chibios HAL
+ - 'libraries/AP_HAL_Linux/**'
+ - 'libraries/AP_HAL_ESP32/**'
+ - 'libraries/AP_HAL_SITL/**'
+ # remove non stm directories
+ - 'Tools/CHDK-Script/**'
+ - 'Tools/CodeStyle/**'
+ - 'Tools/completion/**'
+ - 'Tools/debug/**'
+ - 'Tools/environment_install/**'
+ - 'Tools/FilterTestTool/**'
+ - 'Tools/Frame_params/**'
+ - 'Tools/geotag/**'
+ - 'Tools/GIT_Test/**'
+ - 'Tools/gittools/**'
+ - 'Tools/Hello/**'
+ - 'Tools/LogAnalyzer/**'
+ - 'Tools/mavproxy_modules/**'
+ - 'Tools/Pozyx/**'
+ - 'Tools/PrintVersion.py'
+ - 'Tools/Replay/**'
+ - 'Tools/simulink/**'
+ - 'Tools/UDP_Proxy/**'
+ - 'Tools/vagrant/**'
+ - 'Tools/Vicon/**'
+ # Remove vehicles autotest we need support of test_build_option.py in the Tools/autotest directory
+ - 'Tools/autotest/antennatracker.py'
+ - 'Tools/autotest/arduplane.py'
+ - 'Tools/autotest/ardusub.py'
+ - 'Tools/autotest/autotest.py'
+ - 'Tools/autotest/balancebot.py'
+ - 'Tools/autotest/common.py'
+ - 'Tools/autotest/examples.py'
+ - 'Tools/autotest/quadplane.py'
+ - 'Tools/autotest/rover.py'
+ - 'Tools/autotest/sailboat.py'
+ - 'Tools/autotest/**.txt'
+ - 'Tools/autotest/logger_metadata/**'
+ - 'Tools/autotest/param_metadata/**'
+ # Remove markdown files as irrelevant
+ - '**.md'
+ # Remove dotfile at root directory
+ - './.dir-locals.el'
+ - './.dockerignore'
+ - './.editorconfig'
+ - './.flake8'
+ - './.gitattributes'
+ - './.github'
+ - './.gitignore'
+ - './.pre-commit-config.yaml'
+ - './.pydevproject'
+ - './.valgrind-suppressions'
+ - './.valgrindrc'
+ - 'Dockerfile'
+ - 'Vagrantfile'
+ - 'Makefile'
+ # Remove some directories check
+ - '.vscode/**'
+ - '.github/ISSUE_TEMPLATE/**'
+ # Remove change on other workflows
+ - '.github/workflows/test_environment.yml'
+
+ workflow_dispatch:
-# paths:
-# - "*"
-# - "!README.md" <-- don't rebuild on doc change
concurrency:
group: ci-${{github.workflow}}-${{ github.ref }}
cancel-in-progress: true
@@ -12,7 +134,7 @@ concurrency:
jobs:
build:
runs-on: ubuntu-20.04
- container: ardupilot/ardupilot-dev-${{ matrix.toolchain }}:latest
+ container: ardupilot/ardupilot-dev-${{ matrix.toolchain }}:v0.0.29
strategy:
fail-fast: false # don't cancel if a job from the matrix fails
matrix:
@@ -30,35 +152,19 @@ jobs:
revo-mini,
MatekF405-Wing,
CubeOrange-ODID,
+ CubeRedPrimary-bootloader,
configure-all,
build-options-defaults-test,
signing
]
toolchain: [
- chibios, # GCC-6
+ chibios,
#chibios-clang,
]
- gcc: [6, 10]
+ gcc: [10]
exclude:
- gcc: 10
toolchain: chibios-clang
- - gcc: 6
- config: fmuv2-plane
- - gcc: 6
- config: revo-mini
- - gcc: 6
- config: MatekF405-Wing
- - gcc: 6
- config: periph-build
- - gcc: 6
- config: CubeOrange-ODID
- - gcc: 6
- config: signing
- - gcc: 6
- config: fmuv3-bootloader
- include:
- - config: stm32h7
- toolchain: chibios-py2
steps:
# git checkout the PR
diff --git a/.github/workflows/test_coverage.yml b/.github/workflows/test_coverage.yml
index 8feaabfe2da503..b6c5403ac77f90 100644
--- a/.github/workflows/test_coverage.yml
+++ b/.github/workflows/test_coverage.yml
@@ -15,7 +15,7 @@ jobs:
build:
runs-on: ubuntu-20.04
container:
- image: ardupilot/ardupilot-dev-${{ matrix.type }}:latest
+ image: ardupilot/ardupilot-dev-${{ matrix.type }}:v0.0.29
options: --privileged
strategy:
fail-fast: false # don't cancel if a job from the matrix fails
@@ -59,8 +59,8 @@ jobs:
- name: Configure CAN
if: ${{ matrix.config == 'sitltest-can'}}
run: |
- sudo apt update
- sudo apt -y linux-modules-extra-$(uname -r)
+ sudo apt-get update
+ sudo apt-get -y install can-utils iproute2 linux-modules-extra-$(uname -r)
sudo modprobe vcan
sudo ip link add dev vcan0 type vcan
sudo ip link set up vcan0
diff --git a/.github/workflows/test_dds.yml b/.github/workflows/test_dds.yml
index 4ebe109d6ff944..77cdb854fa104e 100644
--- a/.github/workflows/test_dds.yml
+++ b/.github/workflows/test_dds.yml
@@ -1,9 +1,138 @@
name: test dds
-on: [push, pull_request, workflow_dispatch]
-# paths:
-# - "*"
-# - "!README.md" <-- don't rebuild on doc change
+on:
+ push:
+ paths-ignore:
+ # remove not tests vehicles
+ - 'AntennaTracker/**'
+ - 'ArduSub/**'
+ - 'Blimp/**'
+ - 'Rover/**'
+ # remove esp32 HAL
+ - 'libraries/AP_HAL_ESP32/**'
+ # remove non SITL directories
+ - 'Tools/AP_Bootloader/**'
+ - 'Tools/bootloaders/**'
+ - 'Tools/CHDK-Script/**'
+ - 'Tools/CodeStyle/**'
+ - 'Tools/completion/**'
+ - 'Tools/CPUInfo/**'
+ - 'Tools/debug/**'
+ - 'Tools/environment_install/**'
+ - 'Tools/FilterTestTool/**'
+ - 'Tools/Frame_params/**'
+ - 'Tools/geotag/**'
+ - 'Tools/GIT_Test/**'
+ - 'Tools/gittools/**'
+ - 'Tools/Hello/**'
+ - 'Tools/IO_Firmware/**'
+ - 'Tools/LogAnalyzer/**'
+ - 'Tools/mavproxy_modules/**'
+ - 'Tools/Pozyx/**'
+ - 'Tools/PrintVersion.py'
+ - 'Tools/Replay/**'
+ - 'Tools/simulink/**'
+ - 'Tools/UDP_Proxy/**'
+ - 'Tools/vagrant/**'
+ - 'Tools/Vicon/**'
+ # Discard python file from Tools/scripts as not used
+ - 'Tools/scripts/**.py'
+ - 'Tools/scripts/build_sizes/**'
+ - 'Tools/scripts/build_tests/**'
+ - 'Tools/scripts/CAN/**'
+ - 'Tools/scripts/signing/**'
+ # Remove autotests stuff
+ - 'Tools/autotest/**'
+ # Remove markdown files as irrelevant
+ - '**.md'
+ # Remove dotfile at root directory
+ - './.dir-locals.el'
+ - './.dockerignore'
+ - './.editorconfig'
+ - './.flake8'
+ - './.gitattributes'
+ - './.github'
+ - './.gitignore'
+ - './.pre-commit-config.yaml'
+ - './.pydevproject'
+ - './.valgrind-suppressions'
+ - './.valgrindrc'
+ - 'Dockerfile'
+ - 'Vagrantfile'
+ - 'Makefile'
+ # Remove some directories check
+ - '.vscode/**'
+ - '.github/ISSUE_TEMPLATE/**'
+ # Remove change on other workflows
+ - '.github/workflows/test_environment.yml'
+
+ pull_request:
+ paths-ignore:
+ # remove not tests vehicles
+ - 'AntennaTracker/**'
+ - 'ArduSub/**'
+ - 'Rover/**'
+ - 'Blimp/**'
+ # remove esp32 HAL
+ - 'libraries/AP_HAL_ESP32/**'
+ # remove non SITL directories
+ - 'Tools/AP_Bootloader/**'
+ - 'Tools/CHDK-Script/**'
+ - 'Tools/CPUInfo/**'
+ - 'Tools/CodeStyle/**'
+ - 'Tools/FilterTestTool/**'
+ - 'Tools/Frame_params/**'
+ - 'Tools/GIT_Test/**'
+ - 'Tools/Hello/**'
+ - 'Tools/IO_Firmware/**'
+ - 'Tools/LogAnalyzer/**'
+ - 'Tools/Pozyx/**'
+ - 'Tools/PrintVersion.py'
+ - 'Tools/Replay/**'
+ - 'Tools/UDP_Proxy/**'
+ - 'Tools/Vicon/**'
+ - 'Tools/bootloaders/**'
+ - 'Tools/completion/**'
+ - 'Tools/debug/**'
+ - 'Tools/environment_install/**'
+ - 'Tools/geotag/**'
+ - 'Tools/gittools/**'
+ - 'Tools/mavproxy_modules/**'
+ - 'Tools/simulink/**'
+ - 'Tools/vagrant/**'
+ # Discard python file from Tools/scripts as not used
+ - 'Tools/scripts/**.py'
+ - 'Tools/scripts/build_sizes/**'
+ - 'Tools/scripts/build_tests/**'
+ - 'Tools/scripts/CAN/**'
+ - 'Tools/scripts/signing/**'
+ # Remove autotests stuff
+ - 'Tools/autotest/**'
+ # Remove markdown files as irrelevant
+ - '**.md'
+ # Remove dotfile at root directory
+ - './.dir-locals.el'
+ - './.dockerignore'
+ - './.editorconfig'
+ - './.flake8'
+ - './.gitattributes'
+ - './.github'
+ - './.gitignore'
+ - './.pre-commit-config.yaml'
+ - './.pydevproject'
+ - './.valgrind-suppressions'
+ - './.valgrindrc'
+ - 'Dockerfile'
+ - 'Vagrantfile'
+ - 'Makefile'
+ # Remove some directories check
+ - '.vscode/**'
+ - '.github/ISSUE_TEMPLATE/**'
+ # Remove change on other workflows
+ - '.github/workflows/test_environment.yml'
+
+ workflow_dispatch:
+
concurrency:
group: ci-${{github.workflow}}-${{ github.ref }}
cancel-in-progress: true
diff --git a/.github/workflows/test_environment.yml b/.github/workflows/test_environment.yml
index ebd3124d3942ae..01bcb5f60dc2da 100644
--- a/.github/workflows/test_environment.yml
+++ b/.github/workflows/test_environment.yml
@@ -3,6 +3,15 @@ on:
schedule:
- cron: '0 0 * * 6' # every saturday at midnight
workflow_dispatch:
+ push:
+ paths:
+ - '.github/workflows/test_environment.yml'
+ - 'Tools/environment_install/**'
+
+ pull_request:
+ paths:
+ - '.github/workflows/test_environment.yml'
+ - 'Tools/environment_install/**'
concurrency:
@@ -25,6 +34,8 @@ jobs:
name: focal
- os: ubuntu
name: jammy
+ - os: ubuntu
+ name: lunar
- os: archlinux
name: latest
- os: debian
@@ -104,6 +115,7 @@ jobs:
run: |
git config --global --add safe.directory ${GITHUB_WORKSPACE}
source ~/.bashrc
+ source $HOME/venv-ardupilot/bin/activate || true
git config --global --add safe.directory /__w/ardupilot/ardupilot
./waf configure
./waf rover
@@ -117,6 +129,7 @@ jobs:
run: |
git config --global --add safe.directory ${GITHUB_WORKSPACE}
source ~/.bashrc
+ source $HOME/venv-ardupilot/bin/activate || true
case ${{matrix.os}} in
*"archlinux"*)
export PATH=/opt/gcc-arm-none-eabi-10-2020-q4-major/bin:$PATH
diff --git a/.github/workflows/test_linux_sbc.yml b/.github/workflows/test_linux_sbc.yml
index 3db0df687afc17..943360ca08b701 100644
--- a/.github/workflows/test_linux_sbc.yml
+++ b/.github/workflows/test_linux_sbc.yml
@@ -1,9 +1,133 @@
name: test Linux SBC
-on: [push, pull_request, workflow_dispatch]
-# paths:
-# - "*"
-# - "!README.md" <-- don't rebuild on doc change
+on:
+ push:
+ paths-ignore:
+ # remove non LINUX HAL
+ - 'libraries/AP_HAL_ChibiOS/**'
+ - 'libraries/AP_HAL_ESP32/**'
+ - 'libraries/AP_HAL_SITL/**'
+ # remove non SITL directories
+ - 'Tools/AP_Bootloader/**'
+ - 'Tools/AP_Periph/**'
+ - 'Tools/bootloaders/**'
+ - 'Tools/CHDK-Script/**'
+ - 'Tools/CodeStyle/**'
+ - 'Tools/completion/**'
+ - 'Tools/CPUInfo/**'
+ - 'Tools/debug/**'
+ - 'Tools/environment_install/**'
+ - 'Tools/FilterTestTool/**'
+ - 'Tools/Frame_params/**'
+ - 'Tools/geotag/**'
+ - 'Tools/GIT_Test/**'
+ - 'Tools/gittools/**'
+ - 'Tools/Hello/**'
+ - 'Tools/IO_Firmware/**'
+ - 'Tools/LogAnalyzer/**'
+ - 'Tools/mavproxy_modules/**'
+ - 'Tools/Pozyx/**'
+ - 'Tools/PrintVersion.py'
+ - 'Tools/Replay/**'
+ - 'Tools/simulink/**'
+ - 'Tools/UDP_Proxy/**'
+ - 'Tools/vagrant/**'
+ - 'Tools/Vicon/**'
+ # Discard file from Tools/scripts as not used
+ - 'Tools/scripts/build_sizes/**'
+ - 'Tools/scripts/build_tests/**'
+ - 'Tools/scripts/CAN/**'
+ - 'Tools/scripts/signing/**'
+ # Remove autotests stuff
+ - 'Tools/autotest/**'
+ # Remove markdown files as irrelevant
+ - '**.md'
+ # Remove dotfile at root directory
+ - './.dir-locals.el'
+ - './.dockerignore'
+ - './.editorconfig'
+ - './.flake8'
+ - './.gitattributes'
+ - './.github'
+ - './.gitignore'
+ - './.pre-commit-config.yaml'
+ - './.pydevproject'
+ - './.valgrind-suppressions'
+ - './.valgrindrc'
+ - 'Dockerfile'
+ - 'Vagrantfile'
+ - 'Makefile'
+ # Remove some directories check
+ - '.vscode/**'
+ - '.github/ISSUE_TEMPLATE/**'
+ # Remove change on other workflows
+ - '.github/workflows/test_environment.yml'
+
+ pull_request:
+ paths-ignore:
+ # remove non LINUX HAL
+ - 'libraries/AP_HAL_ChibiOS/**'
+ - 'libraries/AP_HAL_ESP32/**'
+ - 'libraries/AP_HAL_SITL/**'
+ # remove non SITL directories
+ - 'Tools/AP_Bootloader/**'
+ - 'Tools/AP_Periph/**'
+ - 'Tools/bootloaders/**'
+ - 'Tools/CHDK-Script/**'
+ - 'Tools/CodeStyle/**'
+ - 'Tools/completion/**'
+ - 'Tools/CPUInfo/**'
+ - 'Tools/debug/**'
+ - 'Tools/environment_install/**'
+ - 'Tools/FilterTestTool/**'
+ - 'Tools/Frame_params/**'
+ - 'Tools/geotag/**'
+ - 'Tools/GIT_Test/**'
+ - 'Tools/gittools/**'
+ - 'Tools/Hello/**'
+ - 'Tools/IO_Firmware/**'
+ - 'Tools/LogAnalyzer/**'
+ - 'Tools/mavproxy_modules/**'
+ - 'Tools/Pozyx/**'
+ - 'Tools/PrintVersion.py'
+ - 'Tools/Replay/**'
+ - 'Tools/simulink/**'
+ - 'Tools/UDP_Proxy/**'
+ - 'Tools/vagrant/**'
+ - 'Tools/Vicon/**'
+ # Discard python file from Tools/scripts as not used
+ - 'Tools/scripts/**.py'
+ - 'Tools/scripts/build_sizes/**'
+ - 'Tools/scripts/build_tests/**'
+ - 'Tools/scripts/CAN/**'
+ - 'Tools/scripts/signing/**'
+ # Remove autotests stuff
+ - 'Tools/autotest/**'
+ # Remove markdown files as irrelevant
+ - '**.md'
+ # Remove dotfile at root directory
+ - './.dir-locals.el'
+ - './.dockerignore'
+ - './.editorconfig'
+ - './.flake8'
+ - './.gitattributes'
+ - './.github'
+ - './.gitignore'
+ - './.pre-commit-config.yaml'
+ - './.pydevproject'
+ - './.valgrind-suppressions'
+ - './.valgrindrc'
+ - 'Dockerfile'
+ - 'Vagrantfile'
+ - 'Makefile'
+ # Remove some directories check
+ - '.vscode/**'
+ - '.github/ISSUE_TEMPLATE/**'
+ # Remove change on other workflows
+ - '.github/workflows/test_environment.yml'
+
+ workflow_dispatch:
+
concurrency:
group: ci-${{github.workflow}}-${{ github.ref }}
cancel-in-progress: true
@@ -11,7 +135,7 @@ concurrency:
jobs:
build:
runs-on: ubuntu-20.04
- container: ardupilot/ardupilot-dev-${{ matrix.toolchain }}:latest
+ container: ardupilot/ardupilot-dev-${{ matrix.toolchain }}:v0.0.29
strategy:
fail-fast: false # don't cancel if a job from the matrix fails
matrix:
diff --git a/.github/workflows/test_replay.yml b/.github/workflows/test_replay.yml
index fb3d3b2d761e2f..462fa6477e2873 100644
--- a/.github/workflows/test_replay.yml
+++ b/.github/workflows/test_replay.yml
@@ -1,27 +1,146 @@
name: test replay
-on:
+on:
push:
- paths-ignore: # ignore vehicle only changes
+ paths-ignore:
+ # remove other vehicles
- 'AntennaTracker/**'
+ - 'ArduCopter/**'
- 'ArduPlane/**'
- 'ArduSub/**'
- - 'Rover/**'
- 'Blimp/**'
- - 'ArduCopter/**'
+ - 'Rover/**'
+ # remove non SITL HAL
+ - 'libraries/AP_HAL_ChibiOS/**'
+ - 'libraries/AP_HAL_ESP32/**'
+ # remove non SITL directories
+ - 'Tools/AP_Bootloader/**'
+ - 'Tools/AP_Periph/**'
+ - 'Tools/bootloaders/**'
+ - 'Tools/CHDK-Script/**'
+ - 'Tools/CodeStyle/**'
+ - 'Tools/completion/**'
+ - 'Tools/CPUInfo/**'
+ - 'Tools/debug/**'
+ - 'Tools/environment_install/**'
+ - 'Tools/FilterTestTool/**'
+ - 'Tools/Frame_params/**'
+ - 'Tools/geotag/**'
+ - 'Tools/GIT_Test/**'
+ - 'Tools/gittools/**'
+ - 'Tools/Hello/**'
+ - 'Tools/IO_Firmware/**'
+ - 'Tools/Linux_HAL_Essentials/**'
+ - 'Tools/LogAnalyzer/**'
+ - 'Tools/mavproxy_modules/**'
+ - 'Tools/Pozyx/**'
+ - 'Tools/PrintVersion.py'
+ - 'Tools/simulink/**'
+ - 'Tools/UDP_Proxy/**'
+ - 'Tools/vagrant/**'
+ - 'Tools/Vicon/**'
+ # Discard python file from Tools/scripts as not used
+ - 'Tools/scripts/**.py'
+ - 'Tools/scripts/build_sizes/**'
+ - 'Tools/scripts/build_tests/**'
+ - 'Tools/scripts/CAN/**'
+ - 'Tools/scripts/signing/**'
+ # Remove autotests stuff
+ - 'Tools/autotest/**'
+ # Remove markdown files as irrelevant
+ - '**.md'
+ # Remove dotfile at root directory
+ - './.dir-locals.el'
+ - './.dockerignore'
+ - './.editorconfig'
+ - './.flake8'
+ - './.gitattributes'
+ - './.github'
+ - './.gitignore'
+ - './.pre-commit-config.yaml'
+ - './.pydevproject'
+ - './.valgrind-suppressions'
+ - './.valgrindrc'
+ - 'Dockerfile'
+ - 'Vagrantfile'
+ - 'Makefile'
+ # Remove some directories check
+ - '.vscode/**'
+ - '.github/ISSUE_TEMPLATE/**'
+ # Remove change on other workflows
+ - '.github/workflows/test_environment.yml'
pull_request:
- paths-ignore: # ignore vehicle only changes
+ paths-ignore:
+ # remove other vehicles
- 'AntennaTracker/**'
+ - 'ArduCopter/**'
- 'ArduPlane/**'
- 'ArduSub/**'
- - 'Rover/**'
- 'Blimp/**'
- - 'ArduCopter/**'
+ - 'Rover/**'
+ # remove non SITL HAL
+ - 'libraries/AP_HAL_ChibiOS/**'
+ - 'libraries/AP_HAL_ESP32/**'
+ # remove non SITL directories
+ - 'Tools/AP_Bootloader/**'
+ - 'Tools/AP_Periph/**'
+ - 'Tools/bootloaders/**'
+ - 'Tools/CHDK-Script/**'
+ - 'Tools/CodeStyle/**'
+ - 'Tools/completion/**'
+ - 'Tools/CPUInfo/**'
+ - 'Tools/debug/**'
+ - 'Tools/environment_install/**'
+ - 'Tools/FilterTestTool/**'
+ - 'Tools/Frame_params/**'
+ - 'Tools/geotag/**'
+ - 'Tools/GIT_Test/**'
+ - 'Tools/gittools/**'
+ - 'Tools/Hello/**'
+ - 'Tools/IO_Firmware/**'
+ - 'Tools/Linux_HAL_Essentials/**'
+ - 'Tools/LogAnalyzer/**'
+ - 'Tools/mavproxy_modules/**'
+ - 'Tools/Pozyx/**'
+ - 'Tools/PrintVersion.py'
+ - 'Tools/simulink/**'
+ - 'Tools/UDP_Proxy/**'
+ - 'Tools/vagrant/**'
+ - 'Tools/Vicon/**'
+ # Discard python file from Tools/scripts as not used
+ - 'Tools/scripts/**.py'
+ - 'Tools/scripts/build_sizes/**'
+ - 'Tools/scripts/build_tests/**'
+ - 'Tools/scripts/CAN/**'
+ - 'Tools/scripts/signing/**'
+ # Remove autotests stuff
+ - 'Tools/autotest/**'
+ # Remove markdown files as irrelevant
+ - '**.md'
+ # Remove dotfile at root directory
+ - './.dir-locals.el'
+ - './.dockerignore'
+ - './.editorconfig'
+ - './.flake8'
+ - './.gitattributes'
+ - './.github'
+ - './.gitignore'
+ - './.pre-commit-config.yaml'
+ - './.pydevproject'
+ - './.valgrind-suppressions'
+ - './.valgrindrc'
+ - 'Dockerfile'
+ - 'Vagrantfile'
+ - 'Makefile'
+ # Remove some directories check
+ - '.vscode/**'
+ - '.github/ISSUE_TEMPLATE/**'
+ # Remove change on other workflows
+ - '.github/workflows/test_environment.yml'
workflow_dispatch:
-
concurrency:
group: ci-${{github.workflow}}-${{ github.ref }}
cancel-in-progress: true
@@ -29,7 +148,7 @@ concurrency:
jobs:
build:
runs-on: ubuntu-20.04
- container: ardupilot/ardupilot-dev-${{ matrix.toolchain }}:latest
+ container: ardupilot/ardupilot-dev-${{ matrix.toolchain }}:v0.0.29
strategy:
fail-fast: false # don't cancel if a job from the matrix fails
matrix:
diff --git a/.github/workflows/test_scripting.yml b/.github/workflows/test_scripting.yml
index 67074fe019bde3..8fbc8a10d7d150 100644
--- a/.github/workflows/test_scripting.yml
+++ b/.github/workflows/test_scripting.yml
@@ -22,7 +22,7 @@ concurrency:
jobs:
test-scripting:
runs-on: ubuntu-20.04
- container: ardupilot/ardupilot-dev-base:latest
+ container: ardupilot/ardupilot-dev-base:v0.0.29
steps:
# git checkout the PR
- uses: actions/checkout@v3
diff --git a/.github/workflows/test_scripts.yml b/.github/workflows/test_scripts.yml
index 1f73fa05677367..410037f5ba6e63 100644
--- a/.github/workflows/test_scripts.yml
+++ b/.github/workflows/test_scripts.yml
@@ -9,7 +9,7 @@ concurrency:
jobs:
build:
runs-on: ubuntu-20.04
- container: ardupilot/ardupilot-dev-base:latest
+ container: ardupilot/ardupilot-dev-base:v0.0.29
strategy:
fail-fast: false # don't cancel if a job from the matrix fails
matrix:
diff --git a/.github/workflows/test_sitl_copter.yml b/.github/workflows/test_sitl_copter.yml
index 0d76aed9048b33..e72c244ed8aae6 100644
--- a/.github/workflows/test_sitl_copter.yml
+++ b/.github/workflows/test_sitl_copter.yml
@@ -2,20 +2,155 @@ name: test copter
on:
push:
- paths-ignore: # ignore vehicle only changes not for copter
+ paths-ignore:
+ # remove other vehicles
- 'AntennaTracker/**'
- 'ArduPlane/**'
- 'ArduSub/**'
- - 'Rover/**'
- 'Blimp/**'
+ - 'Rover/**'
+ # remove non SITL HAL
+ - 'libraries/AP_HAL_ChibiOS/**'
+ - 'libraries/AP_HAL_ESP32/**'
+ # remove non SITL directories
+ - 'Tools/AP_Bootloader/**'
+ - 'Tools/AP_Periph/**'
+ - 'Tools/bootloaders/**'
+ - 'Tools/CHDK-Script/**'
+ - 'Tools/CodeStyle/**'
+ - 'Tools/completion/**'
+ - 'Tools/CPUInfo/**'
+ - 'Tools/debug/**'
+ - 'Tools/environment_install/**'
+ - 'Tools/FilterTestTool/**'
+ - 'Tools/Frame_params/**'
+ - 'Tools/geotag/**'
+ - 'Tools/GIT_Test/**'
+ - 'Tools/gittools/**'
+ - 'Tools/Hello/**'
+ - 'Tools/IO_Firmware/**'
+ - 'Tools/Linux_HAL_Essentials/**'
+ - 'Tools/LogAnalyzer/**'
+ - 'Tools/Pozyx/**'
+ - 'Tools/PrintVersion.py'
+ - 'Tools/simulink/**'
+ - 'Tools/UDP_Proxy/**'
+ - 'Tools/vagrant/**'
+ - 'Tools/Vicon/**'
+ # Discard python file from Tools/scripts as not used
+ - 'Tools/scripts/**.py'
+ - 'Tools/scripts/build_sizes/**'
+ - 'Tools/scripts/build_tests/**'
+ - 'Tools/scripts/CAN/**'
+ - 'Tools/scripts/signing/**'
+ # Remove other vehicles autotest
+ - 'Tools/autotest/antennatracker.py'
+ - 'Tools/autotest/arduplane.py'
+ - 'Tools/autotest/ardusub.py'
+ - 'Tools/autotest/balancebot.py'
+ - 'Tools/autotest/location.txt'
+ - 'Tools/autotest/quadplane.py'
+ - 'Tools/autotest/rover.py'
+ - 'Tools/autotest/sailboat.py'
+ - 'Tools/autotest/swarminit.txt'
+ # Remove markdown files as irrelevant
+ - '**.md'
+ # Remove dotfile at root directory
+ - './.dir-locals.el'
+ - './.dockerignore'
+ - './.editorconfig'
+ - './.flake8'
+ - './.gitattributes'
+ - './.github'
+ - './.gitignore'
+ - './.pre-commit-config.yaml'
+ - './.pydevproject'
+ - './.valgrind-suppressions'
+ - './.valgrindrc'
+ - 'Dockerfile'
+ - 'Vagrantfile'
+ - 'Makefile'
+ # Remove some directories check
+ - '.vscode/**'
+ - '.github/ISSUE_TEMPLATE/**'
+ # Remove change on other workflows
+ - '.github/workflows/test_environment.yml'
+
pull_request:
- paths-ignore: # ignore vehicle only changes not for copter
+ paths-ignore:
+ # remove other vehicles
- 'AntennaTracker/**'
- 'ArduPlane/**'
- 'ArduSub/**'
- - 'Rover/**'
- 'Blimp/**'
+ - 'Rover/**'
+ # remove non SITL HAL
+ - 'libraries/AP_HAL_ChibiOS/**'
+ - 'libraries/AP_HAL_ESP32/**'
+ # remove non SITL directories
+ - 'Tools/AP_Bootloader/**'
+ - 'Tools/AP_Periph/**'
+ - 'Tools/bootloaders/**'
+ - 'Tools/CHDK-Script/**'
+ - 'Tools/CodeStyle/**'
+ - 'Tools/completion/**'
+ - 'Tools/CPUInfo/**'
+ - 'Tools/debug/**'
+ - 'Tools/environment_install/**'
+ - 'Tools/FilterTestTool/**'
+ - 'Tools/Frame_params/**'
+ - 'Tools/geotag/**'
+ - 'Tools/GIT_Test/**'
+ - 'Tools/gittools/**'
+ - 'Tools/Hello/**'
+ - 'Tools/IO_Firmware/**'
+ - 'Tools/Linux_HAL_Essentials/**'
+ - 'Tools/LogAnalyzer/**'
+ - 'Tools/Pozyx/**'
+ - 'Tools/PrintVersion.py'
+ - 'Tools/simulink/**'
+ - 'Tools/UDP_Proxy/**'
+ - 'Tools/vagrant/**'
+ - 'Tools/Vicon/**'
+ # Discard python file from Tools/scripts as not used
+ - 'Tools/scripts/**.py'
+ - 'Tools/scripts/build_sizes/**'
+ - 'Tools/scripts/build_tests/**'
+ - 'Tools/scripts/CAN/**'
+ - 'Tools/scripts/signing/**'
+ # Remove other vehicles autotest
+ - 'Tools/autotest/antennatracker.py'
+ - 'Tools/autotest/arduplane.py'
+ - 'Tools/autotest/ardusub.py'
+ - 'Tools/autotest/balancebot.py'
+ - 'Tools/autotest/location.txt'
+ - 'Tools/autotest/quadplane.py'
+ - 'Tools/autotest/rover.py'
+ - 'Tools/autotest/sailboat.py'
+ - 'Tools/autotest/swarminit.txt'
+ # Remove markdown files as irrelevant
+ - '**.md'
+ # Remove dotfile at root directory
+ - './.dir-locals.el'
+ - './.dockerignore'
+ - './.editorconfig'
+ - './.flake8'
+ - './.gitattributes'
+ - './.github'
+ - './.gitignore'
+ - './.pre-commit-config.yaml'
+ - './.pydevproject'
+ - './.valgrind-suppressions'
+ - './.valgrindrc'
+ - 'Dockerfile'
+ - 'Vagrantfile'
+ - 'Makefile'
+ # Remove some directories check
+ - '.vscode/**'
+ - '.github/ISSUE_TEMPLATE/**'
+ # Remove change on other workflows
+ - '.github/workflows/test_environment.yml'
workflow_dispatch:
@@ -26,7 +161,7 @@ concurrency:
jobs:
build:
runs-on: ubuntu-20.04
- container: ardupilot/ardupilot-dev-${{ matrix.toolchain }}:latest
+ container: ardupilot/ardupilot-dev-${{ matrix.toolchain }}:v0.0.29
strategy:
fail-fast: false # don't cancel if a job from the matrix fails
matrix:
@@ -72,7 +207,7 @@ jobs:
needs: build # don't try to launch the tests matrix if it doesn't build first, profit from caching for fast build
runs-on: ubuntu-20.04
container:
- image: ardupilot/ardupilot-dev-base:latest
+ image: ardupilot/ardupilot-dev-base:v0.0.29
options: --privileged --cap-add=SYS_PTRACE --security-opt apparmor=unconfined --security-opt seccomp=unconfined
strategy:
fail-fast: false # don't cancel if a job from the matrix fails
@@ -140,7 +275,7 @@ jobs:
build-gcc-heli:
runs-on: ubuntu-20.04
container:
- image: ardupilot/ardupilot-dev-base:latest
+ image: ardupilot/ardupilot-dev-base:v0.0.29
options: --privileged --cap-add=SYS_PTRACE --security-opt apparmor=unconfined --security-opt seccomp=unconfined
steps:
# git checkout the PR
@@ -175,7 +310,7 @@ jobs:
autotest-heli:
needs: build-gcc-heli # don't try to launch the tests matrix if it doesn't build first, profit from caching for fast build
runs-on: ubuntu-20.04
- container: ardupilot/ardupilot-dev-base:latest
+ container: ardupilot/ardupilot-dev-base:v0.0.29
strategy:
fail-fast: false # don't cancel if a job from the matrix fails
matrix:
diff --git a/.github/workflows/test_sitl_periph.yml b/.github/workflows/test_sitl_periph.yml
index 514f814ffa5c55..7c8d8d14150dbf 100644
--- a/.github/workflows/test_sitl_periph.yml
+++ b/.github/workflows/test_sitl_periph.yml
@@ -2,22 +2,154 @@ name: test ap_periph
on:
push:
- paths-ignore: # ignore vehicle only changes
+ paths-ignore:
+ # remove other vehicles than copter
- 'AntennaTracker/**'
- 'ArduPlane/**'
- 'ArduSub/**'
- - 'Rover/**'
- 'Blimp/**'
- - 'ArduCopter/**'
+ - 'Rover/**'
+ # remove non SITL HAL
+ - 'libraries/AP_HAL_ChibiOS/**'
+ - 'libraries/AP_HAL_ESP32/**'
+ # remove non SITL directories
+ - 'Tools/bootloaders/**'
+ - 'Tools/CHDK-Script/**'
+ - 'Tools/CodeStyle/**'
+ - 'Tools/completion/**'
+ - 'Tools/CPUInfo/**'
+ - 'Tools/debug/**'
+ - 'Tools/environment_install/**'
+ - 'Tools/FilterTestTool/**'
+ - 'Tools/Frame_params/**'
+ - 'Tools/geotag/**'
+ - 'Tools/GIT_Test/**'
+ - 'Tools/gittools/**'
+ - 'Tools/Hello/**'
+ - 'Tools/IO_Firmware/**'
+ - 'Tools/Linux_HAL_Essentials/**'
+ - 'Tools/LogAnalyzer/**'
+ - 'Tools/Pozyx/**'
+ - 'Tools/PrintVersion.py'
+ - 'Tools/Replay/**'
+ - 'Tools/simulink/**'
+ - 'Tools/UDP_Proxy/**'
+ - 'Tools/vagrant/**'
+ - 'Tools/Vicon/**'
+ # Discard python file from Tools/scripts as not used
+ - 'Tools/scripts/**.py'
+ - 'Tools/scripts/build_sizes/**'
+ - 'Tools/scripts/build_tests/**'
+ - 'Tools/scripts/CAN/**'
+ - 'Tools/scripts/signing/**'
+ # Remove other vehicles autotest keep only coptertest
+ - 'Tools/autotest/antennatracker.py'
+ - 'Tools/autotest/arduplane.py'
+ - 'Tools/autotest/ardusub.py'
+ - 'Tools/autotest/balancebot.py'
+ - 'Tools/autotest/helicopter.py'
+ - 'Tools/autotest/location.txt'
+ - 'Tools/autotest/quadplane.py'
+ - 'Tools/autotest/rover.py'
+ - 'Tools/autotest/sailboat.py'
+ - 'Tools/autotest/swarminit.txt'
+ # Remove markdown files as irrelevant
+ - '**.md'
+ # Remove dotfile at root directory
+ - './.dir-locals.el'
+ - './.dockerignore'
+ - './.editorconfig'
+ - './.flake8'
+ - './.gitattributes'
+ - './.github'
+ - './.gitignore'
+ - './.pre-commit-config.yaml'
+ - './.pydevproject'
+ - './.valgrind-suppressions'
+ - './.valgrindrc'
+ - 'Dockerfile'
+ - 'Vagrantfile'
+ - 'Makefile'
+ # Remove some directories check
+ - '.vscode/**'
+ - '.github/ISSUE_TEMPLATE/**'
+ # Remove change on other workflows
+ - '.github/workflows/test_environment.yml'
pull_request:
- paths-ignore: # ignore vehicle only changes
+ paths-ignore:
+ # remove other vehicles than copter
- 'AntennaTracker/**'
- 'ArduPlane/**'
- 'ArduSub/**'
- - 'Rover/**'
- 'Blimp/**'
- - 'ArduCopter/**'
+ - 'Rover/**'
+ # remove non SITL HAL
+ - 'libraries/AP_HAL_ChibiOS/**'
+ - 'libraries/AP_HAL_ESP32/**'
+ # remove non SITL directories
+ - 'Tools/bootloaders/**'
+ - 'Tools/CHDK-Script/**'
+ - 'Tools/CodeStyle/**'
+ - 'Tools/completion/**'
+ - 'Tools/CPUInfo/**'
+ - 'Tools/debug/**'
+ - 'Tools/environment_install/**'
+ - 'Tools/FilterTestTool/**'
+ - 'Tools/Frame_params/**'
+ - 'Tools/geotag/**'
+ - 'Tools/GIT_Test/**'
+ - 'Tools/gittools/**'
+ - 'Tools/Hello/**'
+ - 'Tools/IO_Firmware/**'
+ - 'Tools/Linux_HAL_Essentials/**'
+ - 'Tools/LogAnalyzer/**'
+ - 'Tools/Pozyx/**'
+ - 'Tools/PrintVersion.py'
+ - 'Tools/Replay/**'
+ - 'Tools/simulink/**'
+ - 'Tools/UDP_Proxy/**'
+ - 'Tools/vagrant/**'
+ - 'Tools/Vicon/**'
+ # Discard python file from Tools/scripts as not used
+ - 'Tools/scripts/**.py'
+ - 'Tools/scripts/build_sizes/**'
+ - 'Tools/scripts/build_tests/**'
+ - 'Tools/scripts/CAN/**'
+ - 'Tools/scripts/signing/**'
+ # Remove other vehicles autotest keep only coptertest
+ - 'Tools/autotest/antennatracker.py'
+ - 'Tools/autotest/arduplane.py'
+ - 'Tools/autotest/ardusub.py'
+ - 'Tools/autotest/balancebot.py'
+ - 'Tools/autotest/helicopter.py'
+ - 'Tools/autotest/location.txt'
+ - 'Tools/autotest/quadplane.py'
+ - 'Tools/autotest/rover.py'
+ - 'Tools/autotest/sailboat.py'
+ - 'Tools/autotest/swarminit.txt'
+ # Remove markdown files as irrelevant
+ - '**.md'
+ # Remove dotfile at root directory
+ - './.dir-locals.el'
+ - './.dockerignore'
+ - './.editorconfig'
+ - './.flake8'
+ - './.gitattributes'
+ - './.github'
+ - './.gitignore'
+ - './.pre-commit-config.yaml'
+ - './.pydevproject'
+ - './.valgrind-suppressions'
+ - './.valgrindrc'
+ - 'Dockerfile'
+ - 'Vagrantfile'
+ - 'Makefile'
+ # Remove some directories check
+ - '.vscode/**'
+ - '.github/ISSUE_TEMPLATE/**'
+ # Remove change on other workflows
+ - '.github/workflows/test_environment.yml'
workflow_dispatch:
@@ -28,7 +160,7 @@ concurrency:
jobs:
build-gcc-ap_periph:
runs-on: ubuntu-20.04
- container: ardupilot/ardupilot-dev-periph:latest
+ container: ardupilot/ardupilot-dev-periph:v0.0.29
steps:
# git checkout the PR
- uses: actions/checkout@v3
@@ -69,7 +201,7 @@ jobs:
needs: build-gcc-ap_periph # don't try to launch the tests matrix if it doesn't build first, profit from caching for fast build
runs-on: ubuntu-20.04
container:
- image: ardupilot/ardupilot-dev-periph:latest
+ image: ardupilot/ardupilot-dev-periph:v0.0.29
options: --privileged
strategy:
fail-fast: false # don't cancel if a job from the matrix fails
diff --git a/.github/workflows/test_sitl_plane.yml b/.github/workflows/test_sitl_plane.yml
index 172aa820d0868b..b04962e8b9f94a 100644
--- a/.github/workflows/test_sitl_plane.yml
+++ b/.github/workflows/test_sitl_plane.yml
@@ -1,21 +1,157 @@
name: test plane
-on:
+on:
push:
- paths-ignore: # ignore vehicle only changes not for plane
+ paths-ignore:
+ # remove other vehicles
- 'AntennaTracker/**'
+ - 'ArduCopter/**'
- 'ArduSub/**'
- - 'Rover/**'
- 'Blimp/**'
- - 'ArduCopter/**'
+ - 'Rover/**'
+ # remove non SITL HAL
+ - 'libraries/AP_HAL_ChibiOS/**'
+ - 'libraries/AP_HAL_ESP32/**'
+ # remove non SITL directories
+ - 'Tools/AP_Bootloader/**'
+ - 'Tools/AP_Periph/**'
+ - 'Tools/bootloaders/**'
+ - 'Tools/CHDK-Script/**'
+ - 'Tools/CodeStyle/**'
+ - 'Tools/completion/**'
+ - 'Tools/CPUInfo/**'
+ - 'Tools/debug/**'
+ - 'Tools/environment_install/**'
+ - 'Tools/FilterTestTool/**'
+ - 'Tools/Frame_params/**'
+ - 'Tools/geotag/**'
+ - 'Tools/GIT_Test/**'
+ - 'Tools/gittools/**'
+ - 'Tools/Hello/**'
+ - 'Tools/IO_Firmware/**'
+ - 'Tools/Linux_HAL_Essentials/**'
+ - 'Tools/LogAnalyzer/**'
+ - 'Tools/Pozyx/**'
+ - 'Tools/PrintVersion.py'
+ - 'Tools/Replay/**'
+ - 'Tools/simulink/**'
+ - 'Tools/UDP_Proxy/**'
+ - 'Tools/vagrant/**'
+ - 'Tools/Vicon/**'
+ # Discard python file from Tools/scripts as not used
+ - 'Tools/scripts/**.py'
+ - 'Tools/scripts/build_sizes/**'
+ - 'Tools/scripts/build_tests/**'
+ - 'Tools/scripts/CAN/**'
+ - 'Tools/scripts/signing/**'
+ # Remove other vehicles autotest
+ - 'Tools/autotest/antennatracker.py'
+ - 'Tools/autotest/arducopter.py'
+ - 'Tools/autotest/ardusub.py'
+ - 'Tools/autotest/balancebot.py'
+ - 'Tools/autotest/helicopter.py'
+ - 'Tools/autotest/location.txt'
+ - 'Tools/autotest/rover.py'
+ - 'Tools/autotest/sailboat.py'
+ - 'Tools/autotest/swarminit.txt'
+ # Remove markdown files as irrelevant
+ - '**.md'
+ # Remove dotfile at root directory
+ - './.dir-locals.el'
+ - './.dockerignore'
+ - './.editorconfig'
+ - './.flake8'
+ - './.gitattributes'
+ - './.github'
+ - './.gitignore'
+ - './.pre-commit-config.yaml'
+ - './.pydevproject'
+ - './.valgrind-suppressions'
+ - './.valgrindrc'
+ - 'Dockerfile'
+ - 'Vagrantfile'
+ - 'Makefile'
+ # Remove some directories check
+ - '.vscode/**'
+ - '.github/ISSUE_TEMPLATE/**'
+ # Remove change on other workflows
+ - '.github/workflows/test_environment.yml'
pull_request:
- paths-ignore: # ignore vehicle only changes not for plane
+ paths-ignore:
+ # remove other vehicles
- 'AntennaTracker/**'
+ - 'ArduCopter/**'
- 'ArduSub/**'
- - 'Rover/**'
- 'Blimp/**'
- - 'ArduCopter/**'
+ - 'Rover/**'
+ # remove non SITL HAL
+ - 'libraries/AP_HAL_ChibiOS/**'
+ - 'libraries/AP_HAL_ESP32/**'
+ # remove non SITL directories
+ - 'Tools/AP_Bootloader/**'
+ - 'Tools/AP_Periph/**'
+ - 'Tools/bootloaders/**'
+ - 'Tools/CHDK-Script/**'
+ - 'Tools/CodeStyle/**'
+ - 'Tools/completion/**'
+ - 'Tools/CPUInfo/**'
+ - 'Tools/debug/**'
+ - 'Tools/environment_install/**'
+ - 'Tools/FilterTestTool/**'
+ - 'Tools/Frame_params/**'
+ - 'Tools/geotag/**'
+ - 'Tools/GIT_Test/**'
+ - 'Tools/gittools/**'
+ - 'Tools/Hello/**'
+ - 'Tools/IO_Firmware/**'
+ - 'Tools/Linux_HAL_Essentials/**'
+ - 'Tools/LogAnalyzer/**'
+ - 'Tools/Pozyx/**'
+ - 'Tools/PrintVersion.py'
+ - 'Tools/Replay/**'
+ - 'Tools/simulink/**'
+ - 'Tools/UDP_Proxy/**'
+ - 'Tools/vagrant/**'
+ - 'Tools/Vicon/**'
+ # Discard python file from Tools/scripts as not used
+ - 'Tools/scripts/**.py'
+ - 'Tools/scripts/build_sizes/**'
+ - 'Tools/scripts/build_tests/**'
+ - 'Tools/scripts/CAN/**'
+ - 'Tools/scripts/signing/**'
+ # Remove other vehicles autotest
+ - 'Tools/autotest/antennatracker.py'
+ - 'Tools/autotest/arducopter.py'
+ - 'Tools/autotest/ardusub.py'
+ - 'Tools/autotest/balancebot.py'
+ - 'Tools/autotest/helicopter.py'
+ - 'Tools/autotest/location.txt'
+ - 'Tools/autotest/rover.py'
+ - 'Tools/autotest/sailboat.py'
+ - 'Tools/autotest/swarminit.txt'
+ # Remove markdown files as irrelevant
+ - '**.md'
+ # Remove dotfile at root directory
+ - './.dir-locals.el'
+ - './.dockerignore'
+ - './.editorconfig'
+ - './.flake8'
+ - './.gitattributes'
+ - './.github'
+ - './.gitignore'
+ - './.pre-commit-config.yaml'
+ - './.pydevproject'
+ - './.valgrind-suppressions'
+ - './.valgrindrc'
+ - 'Dockerfile'
+ - 'Vagrantfile'
+ - 'Makefile'
+ # Remove some directories check
+ - '.vscode/**'
+ - '.github/ISSUE_TEMPLATE/**'
+ # Remove change on other workflows
+ - '.github/workflows/test_environment.yml'
workflow_dispatch:
@@ -26,7 +162,7 @@ concurrency:
jobs:
build:
runs-on: ubuntu-20.04
- container: ardupilot/ardupilot-dev-${{ matrix.toolchain }}:latest
+ container: ardupilot/ardupilot-dev-${{ matrix.toolchain }}:v0.0.29
strategy:
fail-fast: false # don't cancel if a job from the matrix fails
matrix:
@@ -72,7 +208,7 @@ jobs:
needs: build # don't try to launch the tests matrix if it doesn't build first, profit from caching for fast build
runs-on: ubuntu-20.04
container:
- image: ardupilot/ardupilot-dev-base:latest
+ image: ardupilot/ardupilot-dev-base:v0.0.29
options: --privileged --cap-add=SYS_PTRACE --security-opt apparmor=unconfined --security-opt seccomp=unconfined
strategy:
fail-fast: false # don't cancel if a job from the matrix fails
diff --git a/.github/workflows/test_sitl_rover.yml b/.github/workflows/test_sitl_rover.yml
index 12f9b0ff2c66f5..baf8ae40d9cd60 100644
--- a/.github/workflows/test_sitl_rover.yml
+++ b/.github/workflows/test_sitl_rover.yml
@@ -1,21 +1,156 @@
name: test rover
-on:
+on:
push:
- paths-ignore: # ignore vehicle only changes not for rover
+ paths-ignore:
+ # remove other vehicles
- 'AntennaTracker/**'
+ - 'ArduCopter/**'
- 'ArduPlane/**'
- 'ArduSub/**'
- 'Blimp/**'
- - 'ArduCopter/**'
+ # remove non SITL HAL
+ - 'libraries/AP_HAL_ChibiOS/**'
+ - 'libraries/AP_HAL_ESP32/**'
+ # remove non SITL directories
+ - 'Tools/AP_Bootloader/**'
+ - 'Tools/AP_Periph/**'
+ - 'Tools/bootloaders/**'
+ - 'Tools/CHDK-Script/**'
+ - 'Tools/CodeStyle/**'
+ - 'Tools/completion/**'
+ - 'Tools/CPUInfo/**'
+ - 'Tools/debug/**'
+ - 'Tools/environment_install/**'
+ - 'Tools/FilterTestTool/**'
+ - 'Tools/Frame_params/**'
+ - 'Tools/geotag/**'
+ - 'Tools/GIT_Test/**'
+ - 'Tools/gittools/**'
+ - 'Tools/Hello/**'
+ - 'Tools/IO_Firmware/**'
+ - 'Tools/Linux_HAL_Essentials/**'
+ - 'Tools/LogAnalyzer/**'
+ - 'Tools/Pozyx/**'
+ - 'Tools/PrintVersion.py'
+ - 'Tools/Replay/**'
+ - 'Tools/simulink/**'
+ - 'Tools/UDP_Proxy/**'
+ - 'Tools/vagrant/**'
+ - 'Tools/Vicon/**'
+ # Discard python file from Tools/scripts as not used
+ - 'Tools/scripts/**.py'
+ - 'Tools/scripts/build_sizes/**'
+ - 'Tools/scripts/build_tests/**'
+ - 'Tools/scripts/CAN/**'
+ - 'Tools/scripts/signing/**'
+ # Remove other vehicles autotest
+ - 'Tools/autotest/antennatracker.py'
+ - 'Tools/autotest/arducopter.py'
+ - 'Tools/autotest/arduplane.py'
+ - 'Tools/autotest/ardusub.py'
+ - 'Tools/autotest/helicopter.py'
+ - 'Tools/autotest/location.txt'
+ - 'Tools/autotest/quadplane.py'
+ - 'Tools/autotest/swarminit.txt'
+ # Remove markdown files as irrelevant
+ - '**.md'
+ # Remove dotfile at root directory
+ - './.dir-locals.el'
+ - './.dockerignore'
+ - './.editorconfig'
+ - './.flake8'
+ - './.gitattributes'
+ - './.github'
+ - './.gitignore'
+ - './.pre-commit-config.yaml'
+ - './.pydevproject'
+ - './.valgrind-suppressions'
+ - './.valgrindrc'
+ - 'Dockerfile'
+ - 'Vagrantfile'
+ - 'Makefile'
+ # Remove some directories check
+ - '.vscode/**'
+ - '.github/ISSUE_TEMPLATE/**'
+ # Remove change on other workflows
+ - '.github/workflows/test_environment.yml'
+
pull_request:
- paths-ignore: # ignore vehicle only changes not for rover
+ paths-ignore:
+ # remove other vehicles
- 'AntennaTracker/**'
+ - 'ArduCopter/**'
- 'ArduPlane/**'
- 'ArduSub/**'
- 'Blimp/**'
- - 'ArduCopter/**'
+ # remove non SITL HAL
+ - 'libraries/AP_HAL_ChibiOS/**'
+ - 'libraries/AP_HAL_ESP32/**'
+ # remove non SITL directories
+ - 'Tools/AP_Bootloader/**'
+ - 'Tools/AP_Periph/**'
+ - 'Tools/bootloaders/**'
+ - 'Tools/CHDK-Script/**'
+ - 'Tools/CodeStyle/**'
+ - 'Tools/completion/**'
+ - 'Tools/CPUInfo/**'
+ - 'Tools/debug/**'
+ - 'Tools/environment_install/**'
+ - 'Tools/FilterTestTool/**'
+ - 'Tools/Frame_params/**'
+ - 'Tools/geotag/**'
+ - 'Tools/GIT_Test/**'
+ - 'Tools/gittools/**'
+ - 'Tools/Hello/**'
+ - 'Tools/IO_Firmware/**'
+ - 'Tools/Linux_HAL_Essentials/**'
+ - 'Tools/LogAnalyzer/**'
+ - 'Tools/Pozyx/**'
+ - 'Tools/PrintVersion.py'
+ - 'Tools/Replay/**'
+ - 'Tools/simulink/**'
+ - 'Tools/UDP_Proxy/**'
+ - 'Tools/vagrant/**'
+ - 'Tools/Vicon/**'
+ # Discard python file from Tools/scripts as not used
+ - 'Tools/scripts/**.py'
+ - 'Tools/scripts/build_sizes/**'
+ - 'Tools/scripts/build_tests/**'
+ - 'Tools/scripts/CAN/**'
+ - 'Tools/scripts/signing/**'
+ # Remove other vehicles autotest
+ - 'Tools/autotest/antennatracker.py'
+ - 'Tools/autotest/arducopter.py'
+ - 'Tools/autotest/arduplane.py'
+ - 'Tools/autotest/ardusub.py'
+ - 'Tools/autotest/helicopter.py'
+ - 'Tools/autotest/location.txt'
+ - 'Tools/autotest/quadplane.py'
+ - 'Tools/autotest/swarminit.txt'
+ # Remove markdown files as irrelevant
+ - '**.md'
+ # Remove dotfile at root directory
+ - './.dir-locals.el'
+ - './.dockerignore'
+ - './.editorconfig'
+ - './.flake8'
+ - './.gitattributes'
+ - './.github'
+ - './.gitignore'
+ - './.pre-commit-config.yaml'
+ - './.pydevproject'
+ - './.valgrind-suppressions'
+ - './.valgrindrc'
+ - 'Dockerfile'
+ - 'Vagrantfile'
+ - 'Makefile'
+ # Remove some directories check
+ - '.vscode/**'
+ - '.github/ISSUE_TEMPLATE/**'
+ # Remove change on other workflows
+ - '.github/workflows/test_environment.yml'
workflow_dispatch:
@@ -26,7 +161,7 @@ concurrency:
jobs:
build:
runs-on: ubuntu-20.04
- container: ardupilot/ardupilot-dev-${{ matrix.toolchain }}:latest
+ container: ardupilot/ardupilot-dev-${{ matrix.toolchain }}:v0.0.29
strategy:
fail-fast: false # don't cancel if a job from the matrix fails
matrix:
@@ -72,7 +207,7 @@ jobs:
needs: build # don't try to launch the tests matrix if it doesn't build first, profit from caching for fast build
runs-on: ubuntu-20.04
container:
- image: ardupilot/ardupilot-dev-base:latest
+ image: ardupilot/ardupilot-dev-base:v0.0.29
options: --privileged --cap-add=SYS_PTRACE --security-opt apparmor=unconfined --security-opt seccomp=unconfined
strategy:
fail-fast: false # don't cancel if a job from the matrix fails
diff --git a/.github/workflows/test_sitl_sub.yml b/.github/workflows/test_sitl_sub.yml
index 7f7c7f16e08ed4..d54ee417776c5a 100644
--- a/.github/workflows/test_sitl_sub.yml
+++ b/.github/workflows/test_sitl_sub.yml
@@ -2,20 +2,158 @@ name: test sub
on:
push:
- paths-ignore: # ignore vehicle only changes not for sub
+ paths-ignore:
+ # remove other vehicles
- 'AntennaTracker/**'
+ - 'ArduCopter/**'
- 'ArduPlane/**'
- - 'Rover/**'
- 'Blimp/**'
- - 'ArduCopter/**'
+ - 'Rover/**'
+ # remove non SITL HAL
+ - 'libraries/AP_HAL_ChibiOS/**'
+ - 'libraries/AP_HAL_ESP32/**'
+ # remove non SITL directories
+ - 'Tools/AP_Bootloader/**'
+ - 'Tools/AP_Periph/**'
+ - 'Tools/bootloaders/**'
+ - 'Tools/CHDK-Script/**'
+ - 'Tools/CodeStyle/**'
+ - 'Tools/completion/**'
+ - 'Tools/CPUInfo/**'
+ - 'Tools/debug/**'
+ - 'Tools/environment_install/**'
+ - 'Tools/FilterTestTool/**'
+ - 'Tools/Frame_params/**'
+ - 'Tools/geotag/**'
+ - 'Tools/GIT_Test/**'
+ - 'Tools/gittools/**'
+ - 'Tools/Hello/**'
+ - 'Tools/IO_Firmware/**'
+ - 'Tools/Linux_HAL_Essentials/**'
+ - 'Tools/LogAnalyzer/**'
+ - 'Tools/Pozyx/**'
+ - 'Tools/PrintVersion.py'
+ - 'Tools/Replay/**'
+ - 'Tools/simulink/**'
+ - 'Tools/UDP_Proxy/**'
+ - 'Tools/vagrant/**'
+ - 'Tools/Vicon/**'
+ # Discard python file from Tools/scripts as not used
+ - 'Tools/scripts/**.py'
+ - 'Tools/scripts/build_sizes/**'
+ - 'Tools/scripts/build_tests/**'
+ - 'Tools/scripts/CAN/**'
+ - 'Tools/scripts/signing/**'
+ # Remove other vehicles autotest
+ - 'Tools/autotest/antennatracker.py'
+ - 'Tools/autotest/arducopter.py'
+ - 'Tools/autotest/arduplane.py'
+ - 'Tools/autotest/balancebot.py'
+ - 'Tools/autotest/helicopter.py'
+ - 'Tools/autotest/location.txt'
+ - 'Tools/autotest/quadplane.py'
+ - 'Tools/autotest/rover.py'
+ - 'Tools/autotest/sailboat.py'
+ - 'Tools/autotest/swarminit.txt'
+ # Remove markdown files as irrelevant
+ - '**.md'
+ # Remove dotfile at root directory
+ - './.dir-locals.el'
+ - './.dockerignore'
+ - './.editorconfig'
+ - './.flake8'
+ - './.gitattributes'
+ - './.github'
+ - './.gitignore'
+ - './.pre-commit-config.yaml'
+ - './.pydevproject'
+ - './.valgrind-suppressions'
+ - './.valgrindrc'
+ - 'Dockerfile'
+ - 'Vagrantfile'
+ - 'Makefile'
+ # Remove some directories check
+ - '.vscode/**'
+ - '.github/ISSUE_TEMPLATE/**'
+ # Remove change on other workflows
+ - '.github/workflows/test_environment.yml'
pull_request:
- paths-ignore: # ignore vehicle only changes not for sub
+ paths-ignore:
+ # remove other vehicles
- 'AntennaTracker/**'
+ - 'ArduCopter/**'
- 'ArduPlane/**'
- - 'Rover/**'
- 'Blimp/**'
- - 'ArduCopter/**'
+ - 'Rover/**'
+ # remove non SITL HAL
+ - 'libraries/AP_HAL_ChibiOS/**'
+ - 'libraries/AP_HAL_ESP32/**'
+ # remove non SITL directories
+ - 'Tools/AP_Bootloader/**'
+ - 'Tools/AP_Periph/**'
+ - 'Tools/bootloaders/**'
+ - 'Tools/CHDK-Script/**'
+ - 'Tools/CodeStyle/**'
+ - 'Tools/completion/**'
+ - 'Tools/CPUInfo/**'
+ - 'Tools/debug/**'
+ - 'Tools/environment_install/**'
+ - 'Tools/FilterTestTool/**'
+ - 'Tools/Frame_params/**'
+ - 'Tools/geotag/**'
+ - 'Tools/GIT_Test/**'
+ - 'Tools/gittools/**'
+ - 'Tools/Hello/**'
+ - 'Tools/IO_Firmware/**'
+ - 'Tools/Linux_HAL_Essentials/**'
+ - 'Tools/LogAnalyzer/**'
+ - 'Tools/Pozyx/**'
+ - 'Tools/PrintVersion.py'
+ - 'Tools/Replay/**'
+ - 'Tools/simulink/**'
+ - 'Tools/UDP_Proxy/**'
+ - 'Tools/vagrant/**'
+ - 'Tools/Vicon/**'
+ # Discard python file from Tools/scripts as not used
+ - 'Tools/scripts/**.py'
+ - 'Tools/scripts/build_sizes/**'
+ - 'Tools/scripts/build_tests/**'
+ - 'Tools/scripts/CAN/**'
+ - 'Tools/scripts/signing/**'
+ # Remove other vehicles autotest
+ - 'Tools/autotest/antennatracker.py'
+ - 'Tools/autotest/arducopter.py'
+ - 'Tools/autotest/arduplane.py'
+ - 'Tools/autotest/balancebot.py'
+ - 'Tools/autotest/helicopter.py'
+ - 'Tools/autotest/location.txt'
+ - 'Tools/autotest/quadplane.py'
+ - 'Tools/autotest/rover.py'
+ - 'Tools/autotest/sailboat.py'
+ - 'Tools/autotest/swarminit.txt'
+ # Remove markdown files as irrelevant
+ - '**.md'
+ # Remove dotfile at root directory
+ - './.dir-locals.el'
+ - './.dockerignore'
+ - './.editorconfig'
+ - './.flake8'
+ - './.gitattributes'
+ - './.github'
+ - './.gitignore'
+ - './.pre-commit-config.yaml'
+ - './.pydevproject'
+ - './.valgrind-suppressions'
+ - './.valgrindrc'
+ - 'Dockerfile'
+ - 'Vagrantfile'
+ - 'Makefile'
+ # Remove some directories check
+ - '.vscode/**'
+ - '.github/ISSUE_TEMPLATE/**'
+ # Remove change on other workflows
+ - '.github/workflows/test_environment.yml'
workflow_dispatch:
@@ -26,7 +164,7 @@ concurrency:
jobs:
build:
runs-on: ubuntu-20.04
- container: ardupilot/ardupilot-dev-${{ matrix.toolchain }}:latest
+ container: ardupilot/ardupilot-dev-${{ matrix.toolchain }}:v0.0.29
strategy:
fail-fast: false # don't cancel if a job from the matrix fails
matrix:
@@ -72,7 +210,7 @@ jobs:
needs: build # don't try to launch the tests matrix if it doesn't build first, profit from caching for fast build
runs-on: ubuntu-20.04
container:
- image: ardupilot/ardupilot-dev-base:latest
+ image: ardupilot/ardupilot-dev-base:v0.0.29
options: --privileged --cap-add=SYS_PTRACE --security-opt apparmor=unconfined --security-opt seccomp=unconfined
strategy:
fail-fast: false # don't cancel if a job from the matrix fails
diff --git a/.github/workflows/test_sitl_tracker.yml b/.github/workflows/test_sitl_tracker.yml
index f31761beab52fa..e57e038d47f3b1 100644
--- a/.github/workflows/test_sitl_tracker.yml
+++ b/.github/workflows/test_sitl_tracker.yml
@@ -1,21 +1,159 @@
name: test tracker
-on:
+on:
push:
- paths-ignore: # ignore vehicle only changes
+ paths-ignore:
+ # remove other vehicles
+ - 'ArduCopter/**'
- 'ArduPlane/**'
- 'ArduSub/**'
- - 'Rover/**'
- 'Blimp/**'
- - 'ArduCopter/**'
+ - 'Rover/**'
+ # remove non SITL HAL
+ - 'libraries/AP_HAL_ChibiOS/**'
+ - 'libraries/AP_HAL_ESP32/**'
+ # remove non SITL directories
+ - 'Tools/AP_Bootloader/**'
+ - 'Tools/AP_Periph/**'
+ - 'Tools/bootloaders/**'
+ - 'Tools/CHDK-Script/**'
+ - 'Tools/CodeStyle/**'
+ - 'Tools/completion/**'
+ - 'Tools/CPUInfo/**'
+ - 'Tools/debug/**'
+ - 'Tools/environment_install/**'
+ - 'Tools/FilterTestTool/**'
+ - 'Tools/Frame_params/**'
+ - 'Tools/geotag/**'
+ - 'Tools/GIT_Test/**'
+ - 'Tools/gittools/**'
+ - 'Tools/Hello/**'
+ - 'Tools/IO_Firmware/**'
+ - 'Tools/Linux_HAL_Essentials/**'
+ - 'Tools/LogAnalyzer/**'
+ - 'Tools/Pozyx/**'
+ - 'Tools/PrintVersion.py'
+ - 'Tools/Replay/**'
+ - 'Tools/simulink/**'
+ - 'Tools/UDP_Proxy/**'
+ - 'Tools/vagrant/**'
+ - 'Tools/Vicon/**'
+ # Discard python file from Tools/scripts as not used
+ - 'Tools/scripts/**.py'
+ - 'Tools/scripts/build_sizes/**'
+ - 'Tools/scripts/build_tests/**'
+ - 'Tools/scripts/CAN/**'
+ - 'Tools/scripts/signing/**'
+ # Remove other vehicles autotest
+ - 'Tools/autotest/arducopter.py'
+ - 'Tools/autotest/arduplane.py'
+ - 'Tools/autotest/ardusub.py'
+ - 'Tools/autotest/balancebot.py'
+ - 'Tools/autotest/helicopter.py'
+ - 'Tools/autotest/location.txt'
+ - 'Tools/autotest/quadplane.py'
+ - 'Tools/autotest/rover.py'
+ - 'Tools/autotest/sailboat.py'
+ - 'Tools/autotest/swarminit.txt'
+ # Remove markdown files as irrelevant
+ - '**.md'
+ # Remove dotfile at root directory
+ - './.dir-locals.el'
+ - './.dockerignore'
+ - './.editorconfig'
+ - './.flake8'
+ - './.gitattributes'
+ - './.github'
+ - './.gitignore'
+ - './.pre-commit-config.yaml'
+ - './.pydevproject'
+ - './.valgrind-suppressions'
+ - './.valgrindrc'
+ - 'Dockerfile'
+ - 'Vagrantfile'
+ - 'Makefile'
+ # Remove some directories check
+ - '.vscode/**'
+ - '.github/ISSUE_TEMPLATE/**'
+ # Remove change on other workflows
+ - '.github/workflows/test_environment.yml'
pull_request:
- paths-ignore: # ignore vehicle only changes
+ paths-ignore:
+ # remove other vehicles
+ - 'ArduCopter/**'
- 'ArduPlane/**'
- 'ArduSub/**'
- - 'Rover/**'
- 'Blimp/**'
- - 'ArduCopter/**'
+ - 'Rover/**'
+ # remove non SITL HAL
+ - 'libraries/AP_HAL_ChibiOS/**'
+ - 'libraries/AP_HAL_ESP32/**'
+ # remove non SITL directories
+ - 'Tools/AP_Bootloader/**'
+ - 'Tools/AP_Periph/**'
+ - 'Tools/bootloaders/**'
+ - 'Tools/CHDK-Script/**'
+ - 'Tools/CodeStyle/**'
+ - 'Tools/completion/**'
+ - 'Tools/CPUInfo/**'
+ - 'Tools/debug/**'
+ - 'Tools/environment_install/**'
+ - 'Tools/FilterTestTool/**'
+ - 'Tools/Frame_params/**'
+ - 'Tools/geotag/**'
+ - 'Tools/GIT_Test/**'
+ - 'Tools/gittools/**'
+ - 'Tools/Hello/**'
+ - 'Tools/IO_Firmware/**'
+ - 'Tools/Linux_HAL_Essentials/**'
+ - 'Tools/LogAnalyzer/**'
+ - 'Tools/Pozyx/**'
+ - 'Tools/PrintVersion.py'
+ - 'Tools/Replay/**'
+ - 'Tools/simulink/**'
+ - 'Tools/UDP_Proxy/**'
+ - 'Tools/vagrant/**'
+ - 'Tools/Vicon/**'
+ # Discard python file from Tools/scripts as not used
+ - 'Tools/scripts/**.py'
+ - 'Tools/scripts/build_sizes/**'
+ - 'Tools/scripts/build_tests/**'
+ - 'Tools/scripts/CAN/**'
+ - 'Tools/scripts/signing/**'
+ # Remove other vehicles autotest
+ - 'Tools/autotest/arducopter.py'
+ - 'Tools/autotest/arduplane.py'
+ - 'Tools/autotest/ardusub.py'
+ - 'Tools/autotest/balancebot.py'
+ - 'Tools/autotest/helicopter.py'
+ - 'Tools/autotest/location.txt'
+ - 'Tools/autotest/quadplane.py'
+ - 'Tools/autotest/rover.py'
+ - 'Tools/autotest/sailboat.py'
+ - 'Tools/autotest/swarminit.txt'
+ # Remove markdown files as irrelevant
+ - '**.md'
+ # Remove dotfile at root directory
+ - './.dir-locals.el'
+ - './.dockerignore'
+ - './.editorconfig'
+ - './.flake8'
+ - './.gitattributes'
+ - './.github'
+ - './.gitignore'
+ - './.pre-commit-config.yaml'
+ - './.pydevproject'
+ - './.valgrind-suppressions'
+ - './.valgrindrc'
+ - 'Dockerfile'
+ - 'Vagrantfile'
+ - 'Makefile'
+ # Remove some directories check
+ - '.vscode/**'
+ - '.github/ISSUE_TEMPLATE/**'
+ # Remove change on other workflows
+ - '.github/workflows/test_environment.yml'
workflow_dispatch:
@@ -26,7 +164,7 @@ concurrency:
jobs:
build:
runs-on: ubuntu-20.04
- container: ardupilot/ardupilot-dev-${{ matrix.toolchain }}:latest
+ container: ardupilot/ardupilot-dev-${{ matrix.toolchain }}:v0.0.29
strategy:
fail-fast: false # don't cancel if a job from the matrix fails
matrix:
@@ -72,7 +210,7 @@ jobs:
needs: build # don't try to launch the tests matrix if it doesn't build first, profit from caching for fast build
runs-on: ubuntu-20.04
container:
- image: ardupilot/ardupilot-dev-base:latest
+ image: ardupilot/ardupilot-dev-base:v0.0.29
options: --privileged --cap-add=SYS_PTRACE --security-opt apparmor=unconfined --security-opt seccomp=unconfined
strategy:
fail-fast: false # don't cancel if a job from the matrix fails
diff --git a/.github/workflows/test_size.yml b/.github/workflows/test_size.yml
index 3e3f08fa6e5536..26c42d2c67ba7f 100644
--- a/.github/workflows/test_size.yml
+++ b/.github/workflows/test_size.yml
@@ -1,9 +1,59 @@
name: test size
-on: [pull_request]
-# paths:
-# - "*"
-# - "!README.md" <-- don't rebuild on doc change
+on:
+ pull_request:
+ paths-ignore: # ignore autotest stuffs
+ - 'Tools/autotest/**'
+ # Remove markdown files as irrelevant
+ - '**.md'
+ # Remove dotfile at root directory
+ - './.dir-locals.el'
+ - './.dockerignore'
+ - './.editorconfig'
+ - './.flake8'
+ - './.gitattributes'
+ - './.github'
+ - './.gitignore'
+ - './.pre-commit-config.yaml'
+ - './.pydevproject'
+ - './.valgrind-suppressions'
+ - './.valgrindrc'
+ - 'Dockerfile'
+ - 'Vagrantfile'
+ - 'Makefile'
+ # Remove some directories check
+ - '.vscode/**'
+ - '.github/ISSUE_TEMPLATE/**'
+ # Remove generic tools
+ - 'Tools/CHDK-Script/**'
+ - 'Tools/CodeStyle/**'
+ - 'Tools/completion/**'
+ - 'Tools/CPUInfo/**'
+ - 'Tools/debug/**'
+ - 'Tools/environment_install/**'
+ - 'Tools/FilterTestTool/**'
+ - 'Tools/geotag/**'
+ - 'Tools/GIT_Test/**'
+ - 'Tools/gittools/**'
+ - 'Tools/Hello/**'
+ - 'Tools/Linux_HAL_Essentials/**'
+ - 'Tools/LogAnalyzer/**'
+ - 'Tools/mavproxy_modules/**'
+ - 'Tools/Pozyx/**'
+ - 'Tools/PrintVersion.py'
+ - 'Tools/simulink/**'
+ - 'Tools/UDP_Proxy/**'
+ - 'Tools/vagrant/**'
+ - 'Tools/Vicon/**'
+ # remove non CHIBIOS HAL
+ - 'libraries/AP_HAL_SITL/**'
+ - 'libraries/AP_HAL_ESP32/**'
+ - 'libraries/AP_HAL_Linux/**'
+ # Remove change on other workflows
+ - '.github/workflows/test_environment.yml'
+ workflow_dispatch:
+
+
concurrency:
group: ci-${{github.workflow}}-${{ github.ref }}
cancel-in-progress: true
@@ -11,7 +61,7 @@ concurrency:
jobs:
build:
runs-on: ubuntu-20.04
- container: ardupilot/ardupilot-dev-${{ matrix.toolchain }}:latest
+ container: ardupilot/ardupilot-dev-${{ matrix.toolchain }}:v0.0.29
strategy:
fail-fast: false # don't cancel if a job from the matrix fails
matrix:
@@ -23,6 +73,7 @@ jobs:
MatekF405,
Pixhawk1-1M,
MatekF405-CAN, # see special "build bootloader" code below
+ DrotekP3Pro, # see special "build bootloader" code below
Hitec-Airspeed, # see special code for Periph below (3 places!)
f103-GPS # see special code for Periph below (3 places!)
]
@@ -65,7 +116,8 @@ jobs:
if [ "${{matrix.config}}" = "Hitec-Airspeed" ] ||
[ "${{matrix.config}}" = "f103-GPS" ]; then
AP_PERIPH=1
- elif [ "${{matrix.config}}" = "MatekF405-CAN" ]; then
+ elif [ "${{matrix.config}}" = "MatekF405-CAN" ] ||
+ [ "${{matrix.config}}" = "DrotekP3Pro" ]; then
BOOTLOADER=1
fi
if [ $BOOTLOADER -eq 1 ]; then
@@ -138,7 +190,8 @@ jobs:
if [ "${{matrix.config}}" = "Hitec-Airspeed" ] ||
[ "${{matrix.config}}" = "f103-GPS" ]; then
AP_PERIPH=1
- elif [ "${{matrix.config}}" = "MatekF405-CAN" ]; then
+ elif [ "${{matrix.config}}" = "MatekF405-CAN" ] ||
+ [ "${{matrix.config}}" = "DrotekP3Pro" ]; then
BOOTLOADER=1
fi
if [ $BOOTLOADER -eq 1 ]; then
@@ -230,7 +283,8 @@ jobs:
if [ "${{matrix.config}}" = "Hitec-Airspeed" ] ||
[ "${{matrix.config}}" = "f103-GPS" ]; then
AP_PERIPH=1
- elif [ "${{matrix.config}}" = "MatekF405-CAN" ]; then
+ elif [ "${{matrix.config}}" = "MatekF405-CAN" ] ||
+ [ "${{matrix.config}}" = "DrotekP3Pro" ]; then
BOOTLOADER=1
fi
if [ $AP_PERIPH -eq 1 ]; then
@@ -251,42 +305,3 @@ jobs:
shell: bash
run: |
diff -r $GITHUB_WORKSPACE/base_branch_bin_no_versions $GITHUB_WORKSPACE/pr_bin_no_versions --exclude=*.elf --exclude=*.apj || true
-
- - name: elf_diff compare with ${{ github.event.pull_request.base.ref }}
- shell: bash
- run: |
- # we don't use weasyprint so manually pull the elf_diff deps reduce install size and time
- python3 -m pip install -U --no-deps elf_diff GitPython Jinja2 MarkupSafe PyYAML anytree dict2xml gitdb progressbar2 python-utils setuptools-git smmap
- mkdir elf_diff
- BIN_PREFIX="arm-none-eabi-"
- if [ "${{ matrix.toolchain }}" = "armhf" ]; then
- BIN_PREFIX="arm-linux-gnueabihf-"
- fi
- BOOTLOADER=0
- AP_PERIPH=0
- if [ "${{matrix.config}}" = "Hitec-Airspeed" ] ||
- [ "${{matrix.config}}" = "f103-GPS" ]; then
- AP_PERIPH=1
- elif [ "${{matrix.config}}" = "MatekF405-CAN" ]; then
- BOOTLOADER=1
- fi
-
- if [ $AP_PERIPH -eq 1 ]; then
- TO_CHECK="AP_Periph"
- elif [ $BOOTLOADER -eq 1 ]; then
- TO_CHECK="AP_Bootloader"
- else
- TO_CHECK="arduplane arducopter"
- fi
- for CHECK in $TO_CHECK; do
- python3 -m elf_diff --bin_prefix="$BIN_PREFIX" --html_dir=elf_diff/AP_Periph $GITHUB_WORKSPACE/base_branch_bin/$CHECK $GITHUB_WORKSPACE/pr_bin/$CHECK
- done
-
- zip -r elf_diff.zip elf_diff
-
- - name: Archive elf_diff output
- uses: actions/upload-artifact@v3
- with:
- name: ELF_DIFF_${{matrix.config}}
- path: elf_diff.zip
- retention-days: 14
diff --git a/.github/workflows/test_unit_tests.yml b/.github/workflows/test_unit_tests.yml
index 54c660ea6b818a..933ee4f21064f0 100644
--- a/.github/workflows/test_unit_tests.yml
+++ b/.github/workflows/test_unit_tests.yml
@@ -1,9 +1,98 @@
name: test unit tests and sitl building
-on: [push, pull_request, workflow_dispatch]
-# paths:
-# - "*"
-# - "!README.md" <-- don't rebuild on doc change
+on:
+ push:
+ paths-ignore:
+ # Remove markdown files as irrelevant
+ - '**.md'
+ # Remove dotfile at root directory
+ - './.dir-locals.el'
+ - './.dockerignore'
+ - './.editorconfig'
+ - './.gitattributes'
+ - './.github'
+ - './.gitignore'
+ - './.valgrind-suppressions'
+ - './.valgrindrc'
+ - 'Dockerfile'
+ - 'Vagrantfile'
+ - 'Makefile'
+ # Remove some directories check
+ - '.vscode/**'
+ - '.github/ISSUE_TEMPLATE/**'
+ # Remove generic tools
+ - 'Tools/CHDK-Script/**'
+ - 'Tools/CodeStyle/**'
+ - 'Tools/completion/**'
+ - 'Tools/CPUInfo/**'
+ - 'Tools/debug/**'
+ - 'Tools/environment_install/**'
+ - 'Tools/FilterTestTool/**'
+ - 'Tools/geotag/**'
+ - 'Tools/GIT_Test/**'
+ - 'Tools/gittools/**'
+ - 'Tools/Hello/**'
+ - 'Tools/Linux_HAL_Essentials/**'
+ - 'Tools/LogAnalyzer/**'
+ - 'Tools/mavproxy_modules/**'
+ - 'Tools/Pozyx/**'
+ - 'Tools/PrintVersion.py'
+ - 'Tools/simulink/**'
+ - 'Tools/UDP_Proxy/**'
+ - 'Tools/vagrant/**'
+ - 'Tools/Vicon/**'
+ # remove non SITL HAL
+ - 'libraries/AP_HAL_ChibiOS/**'
+ - 'libraries/AP_HAL_ESP32/**'
+ # Remove change on other workflows
+ - '.github/workflows/test_environment.yml'
+ pull_request:
+ paths-ignore:
+ # Remove markdown files as irrelevant
+ - '**.md'
+ # Remove dotfile at root directory
+ - './.dir-locals.el'
+ - './.dockerignore'
+ - './.editorconfig'
+ - './.gitattributes'
+ - './.github'
+ - './.gitignore'
+ - './.valgrind-suppressions'
+ - './.valgrindrc'
+ - 'Dockerfile'
+ - 'Vagrantfile'
+ - 'Makefile'
+ # Remove some directories check
+ - '.vscode/**'
+ - '.github/ISSUE_TEMPLATE/**'
+ # Remove generic tools
+ - 'Tools/CHDK-Script/**'
+ - 'Tools/CPUInfo/**'
+ - 'Tools/CodeStyle/**'
+ - 'Tools/FilterTestTool/**'
+ - 'Tools/GIT_Test/**'
+ - 'Tools/Hello/**'
+ - 'Tools/Linux_HAL_Essentials/**'
+ - 'Tools/LogAnalyzer/**'
+ - 'Tools/Pozyx/**'
+ - 'Tools/PrintVersion.py'
+ - 'Tools/completion/**'
+ - 'Tools/debug/**'
+ - 'Tools/environment_install/**'
+ - 'Tools/geotag/**'
+ - 'Tools/gittools/**'
+ - 'Tools/mavproxy_modules/**'
+ - 'Tools/simulink/**'
+ - 'Tools/vagrant/**'
+ - 'Tools/UDP_Proxy/**'
+ - 'Tools/Vicon/**'
+ # remove non SITL HAL
+ - 'libraries/AP_HAL_ChibiOS/**'
+ - 'libraries/AP_HAL_ESP32/**'
+ # Remove change on other workflows
+ - '.github/workflows/test_environment.yml'
+ workflow_dispatch:
+
concurrency:
group: ci-${{github.workflow}}-${{ github.ref }}
cancel-in-progress: true
@@ -12,7 +101,7 @@ jobs:
build:
runs-on: ubuntu-20.04
container:
- image: ardupilot/ardupilot-dev-${{ matrix.toolchain }}:latest
+ image: ardupilot/ardupilot-dev-${{ matrix.toolchain }}:v0.0.29
options: --user 1001
strategy:
fail-fast: false # don't cancel if a job from the matrix fails
diff --git a/.gitignore b/.gitignore
index 58913bfed4d3dd..823d39ed5aeb10 100644
--- a/.gitignore
+++ b/.gitignore
@@ -111,7 +111,8 @@ GRTAGS
GTAGS
*.apj
.gdbinit
-/.vscode
+.vscode/*
+!.vscode/extensions.json
/.history
Parameters.html
Parameters.md
@@ -125,6 +126,7 @@ parameters.edn
LogMessages.html
LogMessages.rst
LogMessages.xml
+LogMessages.md
# JetBrains IDE files
.idea/*
# CMake
diff --git a/.gitmodules b/.gitmodules
index ff6918a69b89bd..fbfe76753a51d6 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -34,8 +34,8 @@
[submodule "modules/Micro-XRCE-DDS-Client"]
path = modules/Micro-XRCE-DDS-Client
url = https://github.com/ardupilot/Micro-XRCE-DDS-Client.git
- branch = develop
+ branch = master
[submodule "modules/Micro-CDR"]
path = modules/Micro-CDR
url = https://github.com/ardupilot/Micro-CDR.git
- branch = develop
+ branch = master
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 9cd87421bcf78e..01af44c5848bf7 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -41,7 +41,12 @@ repos:
hooks:
- id: format-xmllint
files: libraries/AP_DDS/dds_xrce_profile.xml
-# Disable isort and mypy temporarily due to config conflicts
+ - repo: https://github.com/psf/black
+ rev: 23.1.0
+ hooks:
+ - id: black
+ files: libraries\/AP_DDS\/(wscript|.*\.py)$
+
# # Use to sort python imports by name and put system import first.
# - repo: https://github.com/pycqa/isort
# rev: 5.12.0
diff --git a/.semaphore/semaphore.yml b/.semaphore/semaphore.yml
deleted file mode 100644
index 19c75718d99a4d..00000000000000
--- a/.semaphore/semaphore.yml
+++ /dev/null
@@ -1,104 +0,0 @@
-version: v1.0
-name: ArduPilot Semaphore CI
-
-agent:
- machine:
- type: e1-standard-2
- os_image: ubuntu1804
-
-# Auto-cancel both running and queued pipelines on a new push
-auto_cancel:
- running:
- when: "true"
-
-# Shared accross all tasks
-global_job_config:
- prologue:
- commands:
- - checkout
- - git submodule update --init --recursive --depth 1 --no-single-branch
- - virtualenv --python=python2.7 --system-site-packages python2-env
- - VIRTUAL_ENV_DISABLE_PROMPT=1 source python2-env/bin/activate
- - sudo apt-get update && sudo apt-get install --no-install-recommends -y lsb-release software-properties-common && sudo apt purge -y gcc g++
- - export SKIP_AP_EXT_ENV=1
- - export SKIP_AP_GRAPHIC_ENV=1
- - export SKIP_AP_COV_ENV=1
- - export SKIP_AP_GIT_CHECK=1
- - ./Tools/environment_install/install-prereqs-ubuntu.sh -y
- - mkdir -p ~/.ccache
- - echo "base_dir = /home/semaphore/${SEMAPHORE_GIT_DIR}" > ~/.ccache/ccache.conf
- - echo "compression = true" >> ~/.ccache/ccache.conf
- - echo "compression_level = 6" >> ~/.ccache/ccache.conf
- - echo "max_size = 400M" >> ~/.ccache/ccache.conf
- - PATH="/home/semaphore/.local/bin:$PATH"
-
- epilogue:
- always:
- commands:
- - git submodule deinit --force .
-
-blocks:
- - name: "Building"
- task:
- jobs:
- - name: "Linux_boards-1"
- commands:
- - source /home/semaphore/.profile
- - cache restore ccache-$SEMAPHORE_GIT_BRANCH-$SEMAPHORE_JOB_NAME-1,ccache-master-$SEMAPHORE_JOB_NAME-1
- - CI_BUILD_TARGET="navio" ./Tools/scripts/build_ci.sh
- - cache store ccache-$SEMAPHORE_GIT_BRANCH-$SEMAPHORE_JOB_NAME-1 ~/.ccache
- - cache restore ccache-$SEMAPHORE_GIT_BRANCH-$SEMAPHORE_JOB_NAME-2,ccache-master-$SEMAPHORE_JOB_NAME-2
- - CI_BUILD_TARGET="bbbmini" ./Tools/scripts/build_ci.sh
- - cache store ccache-$SEMAPHORE_GIT_BRANCH-$SEMAPHORE_JOB_NAME-2 ~/.ccache
- - cache restore ccache-$SEMAPHORE_GIT_BRANCH-$SEMAPHORE_JOB_NAME-3,ccache-master-$SEMAPHORE_JOB_NAME-3
- - CI_BUILD_TARGET="bhat" ./Tools/scripts/build_ci.sh
- - cache store ccache-$SEMAPHORE_GIT_BRANCH-$SEMAPHORE_JOB_NAME-3 ~/.ccache
-
- - name: "SITL"
- commands:
- - source /home/semaphore/.profile
- - cache restore ccache-$SEMAPHORE_GIT_BRANCH-$SEMAPHORE_JOB_NAME-1,ccache-master-$SEMAPHORE_JOB_NAME-1
- - CI_BUILD_TARGET="sitl" ./Tools/scripts/build_ci.sh
- - cache store ccache-$SEMAPHORE_GIT_BRANCH-$SEMAPHORE_JOB_NAME-1 ~/.ccache
- - cache restore ccache-$SEMAPHORE_GIT_BRANCH-$SEMAPHORE_JOB_NAME-2,ccache-master-$SEMAPHORE_JOB_NAME-2
- - CI_BUILD_TARGET="configure-all" ./Tools/scripts/build_ci.sh
- - cache store ccache-$SEMAPHORE_GIT_BRANCH-$SEMAPHORE_JOB_NAME-2 ~/.ccache
-
- - name: "Linux_boards-2"
- commands:
- - source /home/semaphore/.profile
- - cache restore ccache-$SEMAPHORE_GIT_BRANCH-$SEMAPHORE_JOB_NAME-1,ccache-master-$SEMAPHORE_JOB_NAME-1
- - CI_BUILD_TARGET="bebop" ./Tools/scripts/build_ci.sh
- - cache store ccache-$SEMAPHORE_GIT_BRANCH-$SEMAPHORE_JOB_NAME-1 ~/.ccache
- - cache restore ccache-$SEMAPHORE_GIT_BRANCH-$SEMAPHORE_JOB_NAME-2,ccache-master-$SEMAPHORE_JOB_NAME-2
- - CI_BUILD_TARGET="linux" ./Tools/scripts/build_ci.sh
- - cache store ccache-$SEMAPHORE_GIT_BRANCH-$SEMAPHORE_JOB_NAME-2 ~/.ccache
- - cache restore ccache-$SEMAPHORE_GIT_BRANCH-$SEMAPHORE_JOB_NAME-3,ccache-master-$SEMAPHORE_JOB_NAME-3
- - CI_BUILD_TARGET="navio2" ./Tools/scripts/build_ci.sh
- - cache store ccache-$SEMAPHORE_GIT_BRANCH-$SEMAPHORE_JOB_NAME-3 ~/.ccache
-
- - name: "Linux_boards-3"
- commands:
- - source /home/semaphore/.profile
- - cache restore ccache-$SEMAPHORE_GIT_BRANCH-$SEMAPHORE_JOB_NAME-1,ccache-master-$SEMAPHORE_JOB_NAME-1
- - CI_BUILD_TARGET="erlebrain2" ./Tools/scripts/build_ci.sh
- - cache store ccache-$SEMAPHORE_GIT_BRANCH-$SEMAPHORE_JOB_NAME-1 ~/.ccache
- - cache restore ccache-$SEMAPHORE_GIT_BRANCH-$SEMAPHORE_JOB_NAME-2,ccache-master-$SEMAPHORE_JOB_NAME-2
- - CI_BUILD_TARGET="pxfmini" ./Tools/scripts/build_ci.sh
- - cache store ccache-$SEMAPHORE_GIT_BRANCH-$SEMAPHORE_JOB_NAME-2 ~/.ccache
- - cache restore ccache-$SEMAPHORE_GIT_BRANCH-$SEMAPHORE_JOB_NAME-3,ccache-master-$SEMAPHORE_JOB_NAME-3
- - CI_BUILD_TARGET="pxf" ./Tools/scripts/build_ci.sh
- - cache store ccache-$SEMAPHORE_GIT_BRANCH-$SEMAPHORE_JOB_NAME-3 ~/.ccache
-
- - name: "Chibios_boards"
- commands:
- - source /home/semaphore/.profile
- - cache restore ccache-$SEMAPHORE_GIT_BRANCH-$SEMAPHORE_JOB_NAME-1,ccache-master-$SEMAPHORE_JOB_NAME-1
- - CI_BUILD_TARGET="fmuv3" ./Tools/scripts/build_ci.sh
- - cache store ccache-$SEMAPHORE_GIT_BRANCH-$SEMAPHORE_JOB_NAME-1 ~/.ccache
- - cache restore ccache-$SEMAPHORE_GIT_BRANCH-$SEMAPHORE_JOB_NAME-2,ccache-master-$SEMAPHORE_JOB_NAME-2
- - CI_BUILD_TARGET="revo-mini" ./Tools/scripts/build_ci.sh
- - cache store ccache-$SEMAPHORE_GIT_BRANCH-$SEMAPHORE_JOB_NAME-2 ~/.ccache
- - cache restore ccache-$SEMAPHORE_GIT_BRANCH-$SEMAPHORE_JOB_NAME-3,ccache-master-$SEMAPHORE_JOB_NAME-3
- - CI_BUILD_TARGET="MatekF405-Wing" ./Tools/scripts/build_ci.sh
- - cache store ccache-$SEMAPHORE_GIT_BRANCH-$SEMAPHORE_JOB_NAME-3 ~/.ccache
\ No newline at end of file
diff --git a/.vscode/extensions.json b/.vscode/extensions.json
index e9cd876a0b91cf..4284ec07442f18 100644
--- a/.vscode/extensions.json
+++ b/.vscode/extensions.json
@@ -1,11 +1,13 @@
{
"recommendations": [
+ "augustocdias.tasks-shell-input",
+ "bierner.markdown-mermaid",
"ms-vscode.cpptools",
"sumneko.lua",
"ms-python.python",
"ms-python.vscode-pylance",
"streetsidesoftware.code-spell-checker",
"chiehyu.vscode-astyle",
- "ardupilot-org.ardupilot-devenv"
+ "ardupilot-org.ardupilot-devenv",
]
}
diff --git a/.vscode/settings.json b/.vscode/settings.default.json
similarity index 100%
rename from .vscode/settings.json
rename to .vscode/settings.default.json
diff --git a/AntennaTracker/GCS_Mavlink.cpp b/AntennaTracker/GCS_Mavlink.cpp
index 02c48c6b94f38e..c5581708ab3584 100644
--- a/AntennaTracker/GCS_Mavlink.cpp
+++ b/AntennaTracker/GCS_Mavlink.cpp
@@ -412,7 +412,7 @@ MAV_RESULT GCS_MAVLINK_Tracker::_handle_command_preflight_calibration_baro(const
return ret;
}
-MAV_RESULT GCS_MAVLINK_Tracker::handle_command_component_arm_disarm(const mavlink_command_long_t &packet)
+MAV_RESULT GCS_MAVLINK_Tracker::handle_command_component_arm_disarm(const mavlink_command_int_t &packet)
{
if (is_equal(packet.param1,1.0f)) {
tracker.arm_servos();
@@ -425,11 +425,8 @@ MAV_RESULT GCS_MAVLINK_Tracker::handle_command_component_arm_disarm(const mavlin
return MAV_RESULT_UNSUPPORTED;
}
-MAV_RESULT GCS_MAVLINK_Tracker::handle_command_long_packet(const mavlink_command_long_t &packet)
+MAV_RESULT GCS_MAVLINK_Tracker::handle_command_long_packet(const mavlink_command_long_t &packet, const mavlink_message_t &msg)
{
- // do command
- send_text(MAV_SEVERITY_INFO,"Command received: ");
-
switch(packet.command) {
case MAV_CMD_DO_SET_SERVO:
@@ -447,7 +444,7 @@ MAV_RESULT GCS_MAVLINK_Tracker::handle_command_long_packet(const mavlink_command
return MAV_RESULT_ACCEPTED;
default:
- return GCS_MAVLINK::handle_command_long_packet(packet);
+ return GCS_MAVLINK::handle_command_long_packet(packet, msg);
}
}
diff --git a/AntennaTracker/GCS_Mavlink.h b/AntennaTracker/GCS_Mavlink.h
index 5dcaaeda496655..d7bfc34a954a80 100644
--- a/AntennaTracker/GCS_Mavlink.h
+++ b/AntennaTracker/GCS_Mavlink.h
@@ -9,6 +9,8 @@ class GCS_MAVLINK_Tracker : public GCS_MAVLINK
using GCS_MAVLINK::GCS_MAVLINK;
+ uint8_t sysid_my_gcs() const override;
+
protected:
// telem_delay is not used by Tracker but is pure virtual, thus
@@ -16,11 +18,10 @@ class GCS_MAVLINK_Tracker : public GCS_MAVLINK
// as currently Tracker may brick XBees
uint32_t telem_delay() const override { return 0; }
- uint8_t sysid_my_gcs() const override;
- MAV_RESULT handle_command_component_arm_disarm(const mavlink_command_long_t &packet) override;
+ MAV_RESULT handle_command_component_arm_disarm(const mavlink_command_int_t &packet) override;
MAV_RESULT _handle_command_preflight_calibration_baro(const mavlink_message_t &msg) override;
- MAV_RESULT handle_command_long_packet(const mavlink_command_long_t &packet) override;
+ MAV_RESULT handle_command_long_packet(const mavlink_command_long_t &packet, const mavlink_message_t &msg) override;
int32_t global_position_int_relative_alt() const override {
return 0; // what if we have been picked up and carried somewhere?
diff --git a/AntennaTracker/Tracker.cpp b/AntennaTracker/Tracker.cpp
index e7e1a384587e7d..f3284e985ec353 100644
--- a/AntennaTracker/Tracker.cpp
+++ b/AntennaTracker/Tracker.cpp
@@ -64,7 +64,6 @@ const AP_Scheduler::Task Tracker::scheduler_tasks[] = {
SCHED_TASK_CLASS(AP_Logger, &tracker.logger, periodic_tasks, 50, 300, 65),
#endif
SCHED_TASK_CLASS(AP_InertialSensor, &tracker.ins, periodic, 50, 50, 70),
- SCHED_TASK_CLASS(AP_Notify, &tracker.notify, update, 50, 100, 75),
SCHED_TASK(one_second_loop, 1, 3900, 80),
SCHED_TASK(stats_update, 1, 200, 90),
};
diff --git a/AntennaTracker/system.cpp b/AntennaTracker/system.cpp
index 191c236294a131..3e296c3fa5a77f 100644
--- a/AntennaTracker/system.cpp
+++ b/AntennaTracker/system.cpp
@@ -59,9 +59,6 @@ void Tracker::init_ardupilot()
// initialise AP_Logger library
logger.setVehicle_Startup_Writer(FUNCTOR_BIND(&tracker, &Tracker::Log_Write_Vehicle_Startup_Messages, void));
- // set serial ports non-blocking
- serial_manager.set_blocking_writes_all(false);
-
// initialise rc channels including setting mode
rc().convert_options(RC_Channel::AUX_FUNC::ARMDISARM_UNUSED, RC_Channel::AUX_FUNC::ARMDISARM);
rc().init();
diff --git a/AntennaTracker/version.h b/AntennaTracker/version.h
index 1adb76acba8a9a..ff55bece071f3e 100644
--- a/AntennaTracker/version.h
+++ b/AntennaTracker/version.h
@@ -6,13 +6,13 @@
#include "ap_version.h"
-#define THISFIRMWARE "AntennaTracker V4.3.0-dev"
+#define THISFIRMWARE "AntennaTracker V4.5.0-dev"
// the following line is parsed by the autotest scripts
-#define FIRMWARE_VERSION 4,3,0,FIRMWARE_VERSION_TYPE_DEV
+#define FIRMWARE_VERSION 4,5,0,FIRMWARE_VERSION_TYPE_DEV
#define FW_MAJOR 4
-#define FW_MINOR 3
+#define FW_MINOR 5
#define FW_PATCH 0
#define FW_TYPE FIRMWARE_VERSION_TYPE_DEV
diff --git a/ArduCopter/AP_Arming.cpp b/ArduCopter/AP_Arming.cpp
index 8f7ae7186612ea..1bdbc630bc2a9d 100644
--- a/ArduCopter/AP_Arming.cpp
+++ b/ArduCopter/AP_Arming.cpp
@@ -1,5 +1,10 @@
#include "Copter.h"
+#pragma GCC diagnostic push
+#if defined(__clang__)
+#pragma GCC diagnostic ignored "-Wbitwise-instead-of-logical"
+#endif
+
bool AP_Arming_Copter::pre_arm_checks(bool display_failure)
{
const bool passed = run_pre_arm_checks(display_failure);
@@ -18,11 +23,12 @@ bool AP_Arming_Copter::run_pre_arm_checks(bool display_failure)
// check if motor interlock and either Emergency Stop aux switches are used
// at the same time. This cannot be allowed.
+ bool passed = true;
if (rc().find_channel_for_option(RC_Channel::AUX_FUNC::MOTOR_INTERLOCK) &&
(rc().find_channel_for_option(RC_Channel::AUX_FUNC::MOTOR_ESTOP) ||
rc().find_channel_for_option(RC_Channel::AUX_FUNC::ARM_EMERGENCY_STOP))){
check_failed(display_failure, "Interlock/E-Stop Conflict");
- return false;
+ passed = false;
}
// check if motor interlock aux switch is in use
@@ -30,17 +36,22 @@ bool AP_Arming_Copter::run_pre_arm_checks(bool display_failure)
// otherwise exit immediately.
if (copter.ap.using_interlock && copter.ap.motor_interlock_switch) {
check_failed(display_failure, "Motor Interlock Enabled");
- return false;
+ passed = false;
}
if (!disarm_switch_checks(display_failure)) {
- return false;
+ passed = false;
}
// always check motors
char failure_msg[50] {};
if (!copter.motors->arming_checks(ARRAY_SIZE(failure_msg), failure_msg)) {
check_failed(display_failure, "Motors: %s", failure_msg);
+ passed = false;
+ }
+
+ // If not passed all checks return false
+ if (!passed) {
return false;
}
@@ -49,6 +60,7 @@ bool AP_Arming_Copter::run_pre_arm_checks(bool display_failure)
return mandatory_checks(display_failure);
}
+ // bitwise & ensures all checks are run
return parameter_checks(display_failure)
& oa_checks(display_failure)
& gcs_failsafe_check(display_failure)
@@ -212,19 +224,6 @@ bool AP_Arming_Copter::parameter_checks(bool display_failure)
}
#if FRAME_CONFIG == HELI_FRAME
- if (copter.g2.frame_class.get() != AP_Motors::MOTOR_FRAME_HELI_QUAD &&
- copter.g2.frame_class.get() != AP_Motors::MOTOR_FRAME_HELI_DUAL &&
- copter.g2.frame_class.get() != AP_Motors::MOTOR_FRAME_HELI) {
- check_failed(ARMING_CHECK_PARAMETERS, display_failure, "Invalid Heli FRAME_CLASS");
- return false;
- }
-
- // check helicopter parameters
- if (!copter.motors->parameter_check(display_failure)) {
- check_failed(ARMING_CHECK_PARAMETERS, display_failure, "Heli motors checks failed");
- return false;
- }
-
char fail_msg[50];
// check input manager parameters
if (!copter.input_manager.parameter_check(fail_msg, ARRAY_SIZE(fail_msg))) {
@@ -332,6 +331,7 @@ bool AP_Arming_Copter::rc_calibration_checks(bool display_failure)
copter.channel_yaw
};
+ // bitwise & ensures all checks are run
copter.ap.pre_arm_rc_check = rc_checks_copter_sub(display_failure, channels)
& AP_Arming::rc_calibration_checks(display_failure);
@@ -623,7 +623,7 @@ bool AP_Arming_Copter::arm_checks(AP_Arming::Method method)
const char *rc_item = "Throttle";
#endif
// check throttle is not too high - skips checks if arming from GCS/scripting in Guided,Guided_NoGPS or Auto
- if (!((method == AP_Arming::Method::MAVLINK || method == AP_Arming::Method::SCRIPTING) && (copter.flightmode->mode_number() == Mode::Number::GUIDED || copter.flightmode->mode_number() == Mode::Number::GUIDED_NOGPS || copter.flightmode->mode_number() == Mode::Number::AUTO))) {
+ if (!((AP_Arming::method_is_GCS(method) || method == AP_Arming::Method::SCRIPTING) && (copter.flightmode->mode_number() == Mode::Number::GUIDED || copter.flightmode->mode_number() == Mode::Number::GUIDED_NOGPS || copter.flightmode->mode_number() == Mode::Number::AUTO))) {
// above top of deadband is too always high
if (copter.get_pilot_desired_climb_rate(copter.channel_throttle->get_control_in()) > 0.0f) {
check_failed(ARMING_CHECK_RC, true, "%s too high", rc_item);
@@ -790,7 +790,7 @@ bool AP_Arming_Copter::disarm(const AP_Arming::Method method, bool do_disarm_che
// do not allow disarm via mavlink if we think we are flying:
if (do_disarm_checks &&
- method == AP_Arming::Method::MAVLINK &&
+ AP_Arming::method_is_GCS(method) &&
!copter.ap.land_complete) {
return false;
}
@@ -845,3 +845,5 @@ bool AP_Arming_Copter::disarm(const AP_Arming::Method method, bool do_disarm_che
return true;
}
+
+#pragma GCC diagnostic pop
diff --git a/ArduCopter/AP_ExternalControl_Copter.cpp b/ArduCopter/AP_ExternalControl_Copter.cpp
new file mode 100644
index 00000000000000..e5f1f49ec74213
--- /dev/null
+++ b/ArduCopter/AP_ExternalControl_Copter.cpp
@@ -0,0 +1,37 @@
+/*
+ external control library for copter
+ */
+
+
+#include "AP_ExternalControl_Copter.h"
+#if AP_EXTERNAL_CONTROL_ENABLED
+
+#include "Copter.h"
+
+/*
+ set linear velocity and yaw rate. Pass NaN for yaw_rate_rads to not control yaw
+ velocity is in earth frame, NED, m/s
+*/
+bool AP_ExternalControl_Copter::set_linear_velocity_and_yaw_rate(const Vector3f &linear_velocity, float yaw_rate_rads)
+{
+ if (!ready_for_external_control()) {
+ return false;
+ }
+ const float yaw_rate_cds = isnan(yaw_rate_rads)? 0: degrees(yaw_rate_rads)*100;
+
+ // Copter velocity is positive if aicraft is moving up which is opposite the incoming NED frame.
+ Vector3f velocity_NEU_ms {
+ linear_velocity.x,
+ linear_velocity.y,
+ -linear_velocity.z };
+ Vector3f velocity_up_cms = velocity_NEU_ms * 100;
+ copter.mode_guided.set_velocity(velocity_up_cms, false, 0, !isnan(yaw_rate_rads), yaw_rate_cds);
+ return true;
+}
+
+bool AP_ExternalControl_Copter::ready_for_external_control()
+{
+ return copter.flightmode->in_guided_mode() && copter.motors->armed();
+}
+
+#endif // AP_EXTERNAL_CONTROL_ENABLED
diff --git a/ArduCopter/AP_ExternalControl_Copter.h b/ArduCopter/AP_ExternalControl_Copter.h
new file mode 100644
index 00000000000000..e9a879106ebef0
--- /dev/null
+++ b/ArduCopter/AP_ExternalControl_Copter.h
@@ -0,0 +1,26 @@
+/*
+ external control library for copter
+ */
+#pragma once
+
+#include
+
+#if AP_EXTERNAL_CONTROL_ENABLED
+
+class AP_ExternalControl_Copter : public AP_ExternalControl {
+public:
+ /*
+ Set linear velocity and yaw rate. Pass NaN for yaw_rate_rads to not control yaw.
+ Velocity is in earth frame, NED [m/s].
+ Yaw is in earth frame, NED [rad/s].
+ */
+ bool set_linear_velocity_and_yaw_rate(const Vector3f &linear_velocity, float yaw_rate_rads) override;
+private:
+ /*
+ Return true if Copter is ready to handle external control data.
+ Currently checks mode and arm states.
+ */
+ bool ready_for_external_control();
+};
+
+#endif // AP_EXTERNAL_CONTROL_ENABLED
diff --git a/ArduCopter/Copter.cpp b/ArduCopter/Copter.cpp
index 1241b5f9b2336d..8bbbc186c19e14 100644
--- a/ArduCopter/Copter.cpp
+++ b/ArduCopter/Copter.cpp
@@ -178,7 +178,9 @@ const AP_Scheduler::Task Copter::scheduler_tasks[] = {
SCHED_TASK_CLASS(AC_Sprayer, &copter.sprayer, update, 3, 90, 54),
#endif
SCHED_TASK(three_hz_loop, 3, 75, 57),
+#if AP_SERVORELAYEVENTS_ENABLED
SCHED_TASK_CLASS(AP_ServoRelayEvents, &copter.ServoRelayEvents, update_events, 50, 75, 60),
+#endif
SCHED_TASK_CLASS(AP_Baro, &copter.barometer, accumulate, 50, 90, 63),
#if AC_PRECLAND_ENABLED
SCHED_TASK(update_precland, 400, 50, 69),
@@ -189,7 +191,6 @@ const AP_Scheduler::Task Copter::scheduler_tasks[] = {
#if LOGGING_ENABLED == ENABLED
SCHED_TASK(loop_rate_logging, LOOP_RATE, 50, 75),
#endif
- SCHED_TASK_CLASS(AP_Notify, &copter.notify, update, 50, 90, 78),
SCHED_TASK(one_hz_loop, 1, 100, 81),
SCHED_TASK(ekf_check, 10, 75, 84),
SCHED_TASK(check_vibration, 10, 50, 87),
@@ -446,6 +447,26 @@ bool Copter::has_ekf_failsafed() const
#endif // AP_SCRIPTING_ENABLED
+// returns true if vehicle is landing. Only used by Lua scripts
+bool Copter::is_landing() const
+{
+ return flightmode->is_landing();
+}
+
+// returns true if vehicle is taking off. Only used by Lua scripts
+bool Copter::is_taking_off() const
+{
+ return flightmode->is_taking_off();
+}
+
+bool Copter::current_mode_requires_mission() const
+{
+#if MODE_AUTO_ENABLED == ENABLED
+ return flightmode == &mode_auto;
+#else
+ return false;
+#endif
+}
// rc_loops - reads user input from transmitter/receiver
// called at 100hz
@@ -562,6 +583,11 @@ void Copter::ten_hz_logging_loop()
g2.winch.write_log();
}
#endif
+#if HAL_MOUNT_ENABLED
+ if (should_log(MASK_LOG_CAMERA)) {
+ camera_mount.write_log();
+ }
+#endif
}
// twentyfive_hz_logging - should be run at 25hz
@@ -588,7 +614,7 @@ void Copter::twentyfive_hz_logging()
#endif
}
-// three_hz_loop - 3.3hz loop
+// three_hz_loop - 3hz loop
void Copter::three_hz_loop()
{
// check if we've lost contact with the ground station
@@ -718,7 +744,7 @@ void Copter::update_super_simple_bearing(bool force_update)
void Copter::read_AHRS(void)
{
- // we tell AHRS to skip INS update as we have already done it in fast_loop()
+ // we tell AHRS to skip INS update as we have already done it in FAST_TASK.
ahrs.update(true);
}
diff --git a/ArduCopter/Copter.h b/ArduCopter/Copter.h
index bde520ce01befe..b6d5ce552fb2ac 100644
--- a/ArduCopter/Copter.h
+++ b/ArduCopter/Copter.h
@@ -100,6 +100,11 @@
#include "AP_Rally.h" // Rally point library
#include "AP_Arming.h"
+#include
+#if AP_EXTERNAL_CONTROL_ENABLED
+#include "AP_ExternalControl_Copter.h"
+#endif
+
#include
#if AP_BEACON_ENABLED
#include
@@ -193,6 +198,9 @@ class Copter : public AP_Vehicle {
friend class AP_AdvancedFailsafe_Copter;
#endif
friend class AP_Arming_Copter;
+#if AP_EXTERNAL_CONTROL_ENABLED
+ friend class AP_ExternalControl_Copter;
+#endif
friend class ToyMode;
friend class RC_Channel_Copter;
friend class RC_Channels_Copter;
@@ -226,6 +234,7 @@ class Copter : public AP_Vehicle {
friend class ModeZigZag;
friend class ModeAutorotate;
friend class ModeTurtle;
+ friend class AP_ExternalControl_Copter;
Copter(void);
@@ -319,6 +328,12 @@ class Copter : public AP_Vehicle {
AP_OpticalFlow optflow;
#endif
+ // external control library
+#if AP_EXTERNAL_CONTROL_ENABLED
+ AP_ExternalControl_Copter external_control;
+#endif
+
+
// system time in milliseconds of last recorded yaw reset from ekf
uint32_t ekfYawReset_ms;
int8_t ekf_primary_core;
@@ -680,6 +695,8 @@ class Copter : public AP_Vehicle {
// returns true if the EKF failsafe has triggered
bool has_ekf_failsafed() const override;
#endif // AP_SCRIPTING_ENABLED
+ bool is_landing() const override;
+ bool is_taking_off() const override;
void rc_loop();
void throttle_loop();
void update_batt_compass(void);
@@ -851,9 +868,13 @@ class Copter : public AP_Vehicle {
// called when an attempt to change into a mode is unsuccessful:
void mode_change_failed(const Mode *mode, const char *reason);
uint8_t get_mode() const override { return (uint8_t)flightmode->mode_number(); }
+ bool current_mode_requires_mission() const override;
void update_flight_mode();
void notify_flight_mode();
+ // Check if this mode can be entered from the GCS
+ bool gcs_mode_enabled(const Mode::Number mode_num);
+
// mode_land.cpp
void set_mode_land_with_pause(ModeReason reason);
bool landing_with_GPS();
diff --git a/ArduCopter/GCS_Copter.h b/ArduCopter/GCS_Copter.h
index e00ec46f37b59d..4e419add63084b 100644
--- a/ArduCopter/GCS_Copter.h
+++ b/ArduCopter/GCS_Copter.h
@@ -28,9 +28,10 @@ class GCS_Copter : public GCS
bool simple_input_active() const override;
bool supersimple_input_active() const override;
+ uint8_t sysid_this_mav() const override;
+
protected:
- uint8_t sysid_this_mav() const override;
// minimum amount of time (in microseconds) that must remain in
// the main scheduler loop before we are allowed to send any
diff --git a/ArduCopter/GCS_Mavlink.cpp b/ArduCopter/GCS_Mavlink.cpp
index 9250a7928404f2..3b1e612e6c20df 100644
--- a/ArduCopter/GCS_Mavlink.cpp
+++ b/ArduCopter/GCS_Mavlink.cpp
@@ -579,6 +579,14 @@ const struct GCS_MAVLINK::stream_entries GCS_MAVLINK::all_stream_entries[] = {
MAV_STREAM_TERMINATOR // must have this at end of stream_entries
};
+MISSION_STATE GCS_MAVLINK_Copter::mission_state(const class AP_Mission &mission) const
+{
+ if (copter.mode_auto.paused()) {
+ return MISSION_STATE_PAUSED;
+ }
+ return GCS_MAVLINK::mission_state(mission);
+}
+
bool GCS_MAVLINK_Copter::handle_guided_request(AP_Mission::Mission_Command &cmd)
{
#if MODE_AUTO_ENABLED == ENABLED
@@ -728,18 +736,18 @@ MAV_RESULT GCS_MAVLINK_Copter::handle_command_int_do_reposition(const mavlink_co
#endif
}
-MAV_RESULT GCS_MAVLINK_Copter::handle_command_int_packet(const mavlink_command_int_t &packet)
+MAV_RESULT GCS_MAVLINK_Copter::handle_command_int_packet(const mavlink_command_int_t &packet, const mavlink_message_t &msg)
{
switch(packet.command) {
- case MAV_CMD_DO_FOLLOW:
#if MODE_FOLLOW_ENABLED == ENABLED
+ case MAV_CMD_DO_FOLLOW:
// param1: sysid of target to follow
if ((packet.param1 > 0) && (packet.param1 <= 255)) {
copter.g2.follow.set_target_sysid((uint8_t)packet.param1);
return MAV_RESULT_ACCEPTED;
}
+ return MAV_RESULT_DENIED;
#endif
- return MAV_RESULT_UNSUPPORTED;
case MAV_CMD_DO_REPOSITION:
return handle_command_int_do_reposition(packet);
@@ -749,17 +757,17 @@ MAV_RESULT GCS_MAVLINK_Copter::handle_command_int_packet(const mavlink_command_i
return handle_command_pause_continue(packet);
default:
- return GCS_MAVLINK::handle_command_int_packet(packet);
+ return GCS_MAVLINK::handle_command_int_packet(packet, msg);
}
}
#if HAL_MOUNT_ENABLED
-MAV_RESULT GCS_MAVLINK_Copter::handle_command_mount(const mavlink_command_long_t &packet)
+MAV_RESULT GCS_MAVLINK_Copter::handle_command_mount(const mavlink_command_long_t &packet, const mavlink_message_t &msg)
{
switch (packet.command) {
case MAV_CMD_DO_MOUNT_CONTROL:
// if vehicle has a camera mount but it doesn't do pan control then yaw the entire vehicle instead
- if ((copter.camera_mount.get_mount_type() != copter.camera_mount.MountType::Mount_Type_None) &&
+ if ((copter.camera_mount.get_mount_type() != AP_Mount::Type::None) &&
!copter.camera_mount.has_pan_control()) {
copter.flightmode->auto_yaw.set_yaw_angle_rate((float)packet.param3, 0.0f);
}
@@ -767,11 +775,11 @@ MAV_RESULT GCS_MAVLINK_Copter::handle_command_mount(const mavlink_command_long_t
default:
break;
}
- return GCS_MAVLINK::handle_command_mount(packet);
+ return GCS_MAVLINK::handle_command_mount(packet, msg);
}
#endif
-MAV_RESULT GCS_MAVLINK_Copter::handle_command_long_packet(const mavlink_command_long_t &packet)
+MAV_RESULT GCS_MAVLINK_Copter::handle_command_long_packet(const mavlink_command_long_t &packet, const mavlink_message_t &msg)
{
switch(packet.command) {
@@ -818,16 +826,6 @@ MAV_RESULT GCS_MAVLINK_Copter::handle_command_long_packet(const mavlink_command_
}
return MAV_RESULT_ACCEPTED;
-#if MODE_FOLLOW_ENABLED == ENABLED
- case MAV_CMD_DO_FOLLOW:
- // param1: sysid of target to follow
- if ((packet.param1 > 0) && (packet.param1 <= 255)) {
- copter.g2.follow.set_target_sysid((uint8_t)packet.param1);
- return MAV_RESULT_ACCEPTED;
- }
- return MAV_RESULT_FAILED;
-#endif
-
case MAV_CMD_CONDITION_YAW:
// param1 : target angle [0-360]
// param2 : speed during change [deg per second]
@@ -938,23 +936,6 @@ MAV_RESULT GCS_MAVLINK_Copter::handle_command_long_packet(const mavlink_command_
return MAV_RESULT_FAILED;
#endif
-#if AP_LANDINGGEAR_ENABLED
- case MAV_CMD_AIRFRAME_CONFIGURATION: {
- // Param 1: Select which gear, not used in ArduPilot
- // Param 2: 0 = Deploy, 1 = Retract
- // For safety, anything other than 1 will deploy
- switch ((uint8_t)packet.param2) {
- case 1:
- copter.landinggear.set_position(AP_LandingGear::LandingGear_Retract);
- return MAV_RESULT_ACCEPTED;
- default:
- copter.landinggear.set_position(AP_LandingGear::LandingGear_Deploy);
- return MAV_RESULT_ACCEPTED;
- }
- return MAV_RESULT_FAILED;
- }
-#endif
-
/* Solo user presses Fly button */
case MAV_CMD_SOLO_BTN_FLY_CLICK: {
if (copter.failsafe.radio) {
@@ -1022,14 +1003,8 @@ MAV_RESULT GCS_MAVLINK_Copter::handle_command_long_packet(const mavlink_command_
return MAV_RESULT_ACCEPTED;
}
- // pause or resume an auto mission
- case MAV_CMD_DO_PAUSE_CONTINUE: {
- mavlink_command_int_t packet_int;
- GCS_MAVLINK_Copter::convert_COMMAND_LONG_to_COMMAND_INT(packet, packet_int);
- return handle_command_pause_continue(packet_int);
- }
default:
- return GCS_MAVLINK::handle_command_long_packet(packet);
+ return GCS_MAVLINK::handle_command_long_packet(packet, msg);
}
}
@@ -1061,7 +1036,7 @@ void GCS_MAVLINK_Copter::handle_mount_message(const mavlink_message_t &msg)
switch (msg.msgid) {
case MAVLINK_MSG_ID_MOUNT_CONTROL:
// if vehicle has a camera mount but it doesn't do pan control then yaw the entire vehicle instead
- if ((copter.camera_mount.get_mount_type() != copter.camera_mount.MountType::Mount_Type_None) &&
+ if ((copter.camera_mount.get_mount_type() != AP_Mount::Type::None) &&
!copter.camera_mount.has_pan_control()) {
copter.flightmode->auto_yaw.set_yaw_angle_rate(
mavlink_msg_mount_control_get_input_c(&msg) * 0.01f,
@@ -1089,6 +1064,20 @@ void GCS_MAVLINK_Copter::handle_manual_control_axes(const mavlink_manual_control
manual_override(copter.channel_yaw, packet.r, 1000, 2000, tnow);
}
+// sanity check velocity or acceleration vector components are numbers
+// (e.g. not NaN) and below 1000. vec argument units are in meters/second or
+// metres/second/second
+bool GCS_MAVLINK_Copter::sane_vel_or_acc_vector(const Vector3f &vec) const
+{
+ for (uint8_t i=0; i<3; i++) {
+ // consider velocity invalid if any component nan or >1000(m/s or m/s/s)
+ if (isnan(vec[i]) || fabsf(vec[i]) > 1000) {
+ return false;
+ }
+ }
+ return true;
+}
+
void GCS_MAVLINK_Copter::handleMessage(const mavlink_message_t &msg)
{
#if MODE_GUIDED_ENABLED == ENABLED
@@ -1249,8 +1238,13 @@ void GCS_MAVLINK_Copter::handleMessage(const mavlink_message_t &msg)
// prepare velocity
Vector3f vel_vector;
if (!vel_ignore) {
- // convert to cm
- vel_vector = Vector3f(packet.vx * 100.0f, packet.vy * 100.0f, -packet.vz * 100.0f);
+ vel_vector = Vector3f{packet.vx, packet.vy, -packet.vz};
+ if (!sane_vel_or_acc_vector(vel_vector)) {
+ // input is not valid so stop
+ copter.mode_guided.init(true);
+ return;
+ }
+ vel_vector *= 100; // m/s -> cm/s
// rotate to body-frame if necessary
if (packet.coordinate_frame == MAV_FRAME_BODY_NED || packet.coordinate_frame == MAV_FRAME_BODY_OFFSET_NED) {
copter.rotate_body_frame_to_NE(vel_vector.x, vel_vector.y);
@@ -1345,8 +1339,13 @@ void GCS_MAVLINK_Copter::handleMessage(const mavlink_message_t &msg)
// prepare velocity
Vector3f vel_vector;
if (!vel_ignore) {
- // convert to cm
- vel_vector = Vector3f(packet.vx * 100.0f, packet.vy * 100.0f, -packet.vz * 100.0f);
+ vel_vector = Vector3f{packet.vx, packet.vy, -packet.vz};
+ if (!sane_vel_or_acc_vector(vel_vector)) {
+ // input is not valid so stop
+ copter.mode_guided.init(true);
+ return;
+ }
+ vel_vector *= 100; // m/s -> cm/s
}
// prepare acceleration
diff --git a/ArduCopter/GCS_Mavlink.h b/ArduCopter/GCS_Mavlink.h
index 2c0828aae47657..cb33755d89d7f9 100644
--- a/ArduCopter/GCS_Mavlink.h
+++ b/ArduCopter/GCS_Mavlink.h
@@ -30,10 +30,10 @@ class GCS_MAVLINK_Copter : public GCS_MAVLINK
MAV_RESULT handle_command_do_set_roi(const Location &roi_loc) override;
MAV_RESULT handle_preflight_reboot(const mavlink_command_long_t &packet, const mavlink_message_t &msg) override;
#if HAL_MOUNT_ENABLED
- MAV_RESULT handle_command_mount(const mavlink_command_long_t &packet) override;
+ MAV_RESULT handle_command_mount(const mavlink_command_long_t &packet, const mavlink_message_t &msg) override;
#endif
- MAV_RESULT handle_command_int_packet(const mavlink_command_int_t &packet) override;
- MAV_RESULT handle_command_long_packet(const mavlink_command_long_t &packet) override;
+ MAV_RESULT handle_command_int_packet(const mavlink_command_int_t &packet, const mavlink_message_t &msg) override;
+ MAV_RESULT handle_command_long_packet(const mavlink_command_long_t &packet, const mavlink_message_t &msg) override;
MAV_RESULT handle_command_int_do_reposition(const mavlink_command_int_t &packet);
MAV_RESULT handle_command_pause_continue(const mavlink_command_int_t &packet);
@@ -55,6 +55,13 @@ class GCS_MAVLINK_Copter : public GCS_MAVLINK
private:
+ // sanity check velocity or acceleration vector components are numbers
+ // (e.g. not NaN) and below 1000. vec argument units are in meters/second or
+ // metres/second/second
+ bool sane_vel_or_acc_vector(const Vector3f &vec) const;
+
+ MISSION_STATE mission_state(const class AP_Mission &mission) const override;
+
void handleMessage(const mavlink_message_t &msg) override;
void handle_command_ack(const mavlink_message_t &msg) override;
bool handle_guided_request(AP_Mission::Mission_Command &cmd) override;
diff --git a/ArduCopter/Parameters.cpp b/ArduCopter/Parameters.cpp
index 579a1baa446504..334c4b02934414 100644
--- a/ArduCopter/Parameters.cpp
+++ b/ArduCopter/Parameters.cpp
@@ -162,7 +162,7 @@ const AP_Param::Info Copter::var_info[] = {
// @Param: FS_GCS_ENABLE
// @DisplayName: Ground Station Failsafe Enable
// @Description: Controls whether failsafe will be invoked (and what action to take) when connection with Ground station is lost for at least 5 seconds. See FS_OPTIONS param for additional actions, or for cases allowing Mission continuation, when GCS failsafe is enabled.
- // @Values: 0:Disabled/NoAction,1:RTL,2:RTL or Continue with Mission in Auto Mode (Removed in 4.0+-see FS_OPTIONS),3:SmartRTL or RTL,4:SmartRTL or Land,5:Land,6:Auto DO_LAND_START or RTL
+ // @Values: 0:Disabled/NoAction,1:RTL,2:RTL or Continue with Mission in Auto Mode (Removed in 4.0+-see FS_OPTIONS),3:SmartRTL or RTL,4:SmartRTL or Land,5:Land,6:Auto DO_LAND_START or RTL,7:Brake or Land
// @User: Standard
GSCALAR(failsafe_gcs, "FS_GCS_ENABLE", FS_GCS_DISABLED),
@@ -449,9 +449,11 @@ const AP_Param::Info Copter::var_info[] = {
GOBJECT(camera, "CAM", AP_Camera),
#endif
+#if AP_RELAY_ENABLED
// @Group: RELAY_
// @Path: ../libraries/AP_Relay/AP_Relay.cpp
GOBJECT(relay, "RELAY_", AP_Relay),
+#endif
#if PARACHUTE == ENABLED
// @Group: CHUTE_
@@ -1038,6 +1040,7 @@ const AP_Param::GroupInfo ParametersG2::var_info[] = {
// @Description: set which surface to track in surface tracking
// @Values: 0:Do not track, 1:Ground, 2:Ceiling
// @User: Advanced
+ // @RebootRequired: True
AP_GROUPINFO("SURFTRAK_MODE", 51, ParametersG2, surftrak_mode, (uint8_t)Copter::SurfaceTracking::Surface::GROUND),
// @Param: FS_DR_ENABLE
@@ -1215,6 +1218,15 @@ const AP_Param::GroupInfo ParametersG2::var_info2[] = {
// @User: Advanced
AP_GROUPINFO("TKOFF_THR_MAX", 6, ParametersG2, takeoff_throttle_max, 0.9),
+#if HAL_WITH_ESC_TELEM && FRAME_CONFIG != HELI_FRAME
+ // @Param: TKOFF_RPM_MAX
+ // @DisplayName: Takeoff Check RPM maximum
+ // @Description: Takeoff is not permitted until motors report no more than this RPM. Set to zero to disable check
+ // @Range: 0 10000
+ // @User: Standard
+ AP_GROUPINFO("TKOFF_RPM_MAX", 7, ParametersG2, takeoff_rpm_max, 0),
+#endif
+
// ID 62 is reserved for the AP_SUBGROUPEXTENSION
AP_GROUPEND
diff --git a/ArduCopter/Parameters.h b/ArduCopter/Parameters.h
index 15f719224c585e..18a32dd25fc184 100644
--- a/ArduCopter/Parameters.h
+++ b/ArduCopter/Parameters.h
@@ -681,6 +681,7 @@ class ParametersG2 {
AP_Float takeoff_throttle_max;
#if HAL_WITH_ESC_TELEM && FRAME_CONFIG != HELI_FRAME
AP_Int16 takeoff_rpm_min;
+ AP_Int16 takeoff_rpm_max;
#endif
#if WEATHERVANE_ENABLED == ENABLED
diff --git a/ArduCopter/RC_Channel.cpp b/ArduCopter/RC_Channel.cpp
index 03d398c67a3c42..f400694b451b38 100644
--- a/ArduCopter/RC_Channel.cpp
+++ b/ArduCopter/RC_Channel.cpp
@@ -37,9 +37,14 @@ void RC_Channel_Copter::mode_switch_changed(modeswitch_pos_t new_pos)
}
}
+bool RC_Channels_Copter::in_rc_failsafe() const
+{
+ return copter.failsafe.radio;
+}
+
bool RC_Channels_Copter::has_valid_input() const
{
- if (copter.failsafe.radio) {
+ if (in_rc_failsafe()) {
return false;
}
if (copter.failsafe.radio_counter != 0) {
diff --git a/ArduCopter/RC_Channel.h b/ArduCopter/RC_Channel.h
index 576135f91f438d..6d9d9f9426801c 100644
--- a/ArduCopter/RC_Channel.h
+++ b/ArduCopter/RC_Channel.h
@@ -31,6 +31,7 @@ class RC_Channels_Copter : public RC_Channels
public:
bool has_valid_input() const override;
+ bool in_rc_failsafe() const override;
RC_Channel *get_arming_channel(void) const override;
diff --git a/ArduCopter/ReleaseNotes.txt b/ArduCopter/ReleaseNotes.txt
index 9ca8364d6cbc23..dcc974b5829b53 100644
--- a/ArduCopter/ReleaseNotes.txt
+++ b/ArduCopter/ReleaseNotes.txt
@@ -1,5 +1,311 @@
ArduPilot Copter Release Notes:
------------------------------------------------------------------
+Copter 4.4.0 18-Aug-2023 / 4.4.0-beta5 12-Aug-2023
+Changes from 4.4.0-beta4
+1) Autopilots specific changes
+ - SIYI N7 support
+2) Bug fixes
+ - DroneCAN airspeed sensor fix to handle missing packets
+ - DroneCAN GPS RTK injection fix
+ - Notch filter gyro glitch caused by race condition fixed
+------------------------------------------------------------------
+Copter 4.4.0-beta4 27-July-2023
+Changes from 4.4.0-beta3
+1) Autopilots specific changes
+ - Diatone-Mamba-MK4-H743v2 uses SPL06 baro (was DPS280)
+ - DMA for I2C disabled on F7 and H7 boards
+ - Foxeer H743v1 default serial protocol config fixes
+ - HeeWing-F405 and F405v2 support
+ - iFlight BlitzF7 support
+2) Scripts may take action based on VTOL motor loss
+3) Bug fixes
+ - BLHeli returns battery status requested via MSP (avoids hang when using esc-configurator)
+ - CRSFv3 rescans at baudrates to avoid RX loss
+ - EK3_ABIAS_P_NSE param range fix
+ - Scripting restart memory corruption bug fixed
+ - Siyi A8/ZR10 driver fix to avoid crash if serial port not configured
+------------------------------------------------------------------
+Copter 4.4.0-beta3 03-July-2023
+Changes from 4.4.0-beta2
+1) Autopilots specific changes
+ - Holybro KakuteH7-Wing support
+ - JFB100 external watchdog GPIO support added
+ - Pixhawk1-bdshot support
+ - Pixhawk6X-bdshot support
+ - SpeedyBeeF4 loses bdshot support
+2) Device drivers
+ - added LP5562 I2C LED driver
+ - added IS31FL3195 LED driver
+3) TradHeli gets minor fix to RSC servo output range
+4) Camera and Gimbal related changes
+ - DO_SET_ROI_NONE command support added
+5) Applet changes
+ - added QUIK_MAX_REDUCE parameter to VTOL quicktune lua applet
+6) Bug fixes
+ - ADSB sensor loss of transceiver message less spammy
+ - AutoTune Yaw rate max fixed
+ - EKF vertical velocity reset fixed on loss of GPS
+ - GPS pre-arm failure message clarified
+ - SERVOx_PROTOCOL "SToRM32 Gimbal Serial" value renamed to "Gimbal" because also used by Siyi
+ - SERIALx_OPTION "Swap" renamed to "SwapTXRX" for clarity
+ - SBF GPS ellipsoid height fixed
+ - Ublox M10S GPS auto configuration fixed
+ - ZigZag mode user takeoff fixed (users could not takeoff in ZigZag mode previously)
+------------------------------------------------------------------
+Copter 4.4.0-beta2 05-Jun-2023
+Changes from 4.4.0-beta1
+1) Autopilots specific changes
+ - FlywooF745 update to motor pin output mapping and baro
+ - FoxeerH743 support
+ - JFB100 support
+ - Mamba-F405v2 supports ICM42688
+ - Matek-F405-TE/VTOL support
+ - Matek-H743 IMU SPI slowed to 1Mhz to avoid init issues
+ - SpeedyBee-405-Wing support
+2) Copter specfic fixes and enhancements
+ - RTL speed fix so changes to WPNAV_SPEED have no effect if RTL_SPEED is non-zero
+ - RTL mode accepts do-change-speed commands from GCS
+3) AHRS/EKF related fixes and Enhancements
+ - EKF allocation failure handled to avoid watchdog
+ - EKF3 accel bias calculation fix and tuning for greater robustness
+ - Airspeed sensor remains enabled during dead-reckoning (few copters have airspeed sensors)
+ - Wind speed estimates updates reduced while dead-reckoning
+4) Other Enhancements
+ - Attitude control slew limits always calculated (helps tuning reporting and analysis)
+ - INA228 and INA238 I2C battery monitor support
+ - LOG_DISARMED=3 logs while disarmed but discards log if never eventually armed
+ - LOG_DARM_RATEMAX reduces logging while disarmed
+ - Serial LEDs threading enhancement to support longer lengths without dshot interference
+4) Bug fixes
+ - Analog battery monitor2 current parameter default fixed
+ - AutoTune fix for loading Yaw Rate D gains
+ - BRD_SAFETYOPTION parameter documentation fix (ActiveForSafetyEnable and Disable were reversed)
+ - Compassmot fix to protect against bad gyro biases from GSF yaw
+ - ICE engine fix for starting after reaching a specified altitude
+ - LED thread locking fix to avoid watchdog
+ - Logging rotation on disarm disabled if Replay logging active (avoids gaps in logs)
+ - RC input on IOMCU bug fix (RC might not be regained if lost)
+ - Serial passthrough fixed
+5) Custom build server fix to which features are included/excluded
+------------------------------------------------------------------
+Copter 4.4.0-beta1 19-Apr-2023
+Changes from 4.3.6
+1) New autopilots supported
+ - ESP32
+ - Flywoo Goku F405S AIO
+ - Foxeer H743v1
+ - MambaF405-2022B
+ - PixPilot-V3
+ - PixSurveyA2
+ - rFCU H743
+ - ThePeach K1/R1
+2) Autopilot specific changes
+ - Bi-Directional DShot support for CubeOrangePlus-bdshot, CUAVNora+, MatekF405TE/VTOL-bdshot, MatekL431, Pixhawk6C-bdshot, QioTekZealotH743-bdshot
+ - Bi-Directional DShot up to 8 channels on MatekH743
+ - BlueRobotics Navigator supports baro on I2C bus 6
+ - BMP280 baro only for BeastF7, KakuteF4, KakuteF7Mini, MambaF405, MatekF405, Omnibusf4 to reduce code size (aka "flash")
+ - CSRF and Hott telemetry disabled by default on some low power boards (aka "minimised boards")
+ - Foxeer Reaper F745 supports external compasses
+ - OmnibusF4 support for BMI270 IMU
+ - OmnibusF7V2-bdshot support removed
+ - KakuteF7 regains displayport, frees up DMA from unused serial port
+ - KakuteH7v2 gets second battery sensor
+ - MambaH743v4 supports VTX
+ - MatekF405-Wing supports InvensenseV3 IMUs
+ - PixPilot-V6 heater enabled
+ - Raspberry 64OS startup crash fixed
+ - ReaperF745AIO serial protocol defaults fixed
+ - SkystarsH7HD (non-bdshot) removed as users should always use -bdshot version
+ - Skyviper loses many unnecessary features to save flash
+ - UBlox GPS only for AtomRCF405NAVI, BeastF7, MatekF405, Omnibusf4 to reduce code size (aka "flash")
+ - VRBrain-v52 and VRCore-v10 features reduced to save flash
+3) Driver enhancements
+ - ARK RTK GPS support
+ - BMI088 IMU filtering and timing improved, ignores bad data
+ - CRSF OSD may display disarmed state after flight mode (enabled using RC_OPTIONS)
+ - Daiwa winch baud rate obeys SERIALx_BAUD parameter
+ - EFI supports fuel pressure and ignition voltage reporting and battery failsafe
+ - ICM45686 IMU support
+ - ICM20602 uses fast reset instead of full reset on bad temperature sample (avoids occasional very high offset)
+ - ICM45686 supports fast sampling
+ - MAX31865 temp sensor support
+ - MB85RS256TY-32k, PB85RS128C and PB85RS2MC FRAM support
+ - MMC3416 compass orientation fix
+ - MPPT battery monitor reliability improvements, enable/disable aux function and less spammy
+ - Multiple USD-D1-CAN radar support
+ - NMEA output rate configurable (see NMEA_RATE_MS)
+ - NMEA output supports PASHR message (see NMEA_MSG_EN)
+ - OSD supports average resting cell voltage (see OSD_ACRVOLT_xxx params)
+ - Rockblock satellite modem support
+ - Serial baud support for 2Mbps (only some hardware supports this speed)
+ - SF45b lidar filtering reduced (allows detecting smaller obstacles
+ - SmartAudio 2.0 learns all VTX power levels)
+ - UAVCAN ESCs report error count using ESC Telemetry
+ - Unicore GPS (e.g. UM982) support
+ - VectorNav 100 external AHRS support
+ - 5 IMUs supported
+4) EKF related enhancements
+ - Baro compensation using wind estimates works when climbing or descending (see BAROx_WCF_UP/DN)
+ - External AHRS support for enabling only some sensors (e.g. IMU, Baro, Compass) see EAHRS_SENSORS
+ - Magnetic field tables updated
+ - Non-compass initial yaw alignment uses GPS course over GSF (mostly affects Planes and Rover)
+5) Control and navigation enhancements
+ - AutoTune of attitude control yaw D gain (set AUTOTUNE_AXES=8)
+ - Circle moode and Loiter Turns command supports counter-clockwise rotation (set CIRCLE_RATE to negative number)
+ - DO_SET_ROI_NONE command turns off ROI
+ - JUMP_TAG mission item support
+ - Missions can be stored on SD card (see BRD_SD_MISSION)
+ - NAV_SCRIPT_TIME command accepts floating point arguments
+ - Pause/Resume returns success if mission is already paused or resumed
+ - Payload Place enhancements
+ - Descent speed is configurable (see PLDP_SPEED_DN)
+ - Manual release supported (detects pilot release of gripper)
+ - Post release delay is configurable (see PLDP_DELAY)
+ - Range finder range used to protect against premature release (see PLDP_RNG_MIN)
+ - Touchdown detection threshold is configurable (see PLDP_THRESH)
+ - Position controller angle max adjusted inflight with CH6 Tuning knob (set TUNE=59)
+ - Surface tracking time constant allows tuning response (see SURFTRAK_TC)
+ - Takeoff throttle max is configurable (see TKOFF_TH_MAX)
+ - Throttle-Gain boost increases attitude control gains when throttle high (see ATC_THR_G_BOOST)
+ - Waypoint navigation cornering acceleration is configurable (see WPNAV_ACCEL_C)
+ - WeatherVane into the wind in Auto and Guided modes (see WVANE_ENABLE)
+6) TradHeli specific enhancements
+ - Manual autorotation support
+ - Improved collect to yaw compensation
+7) Filtering enhancements
+ - FFT notch can be run based on filtered data
+ - Warn of motor noise at RPM frequency using FFT
+ - In-flight FFT can better track low frequency noise
+ - In-flight FFT logging improved
+ - IMU data can be read and replayed for FFT analysis
+8) Camera and gimbal enhancements
+ - BMMCC support included in Servo driver
+ - DJI RS2/RS3-Pro gimbal support
+ - Dual camera support (see CAM2_TYPE)
+ - Gimbal/Mount2 can be moved to retracted or neutral position
+ - Gremsy ZIO support
+ - IMAGE_START_CAPTURE, SET_CAMERA_ZOOM/FOCUS, VIDEO_START/STOP_CAPTURE command support
+ - Paramters renamed and rescaled
+ - CAM_TRIGG_TYPE renamed to CAM1_TYPE and options have changed
+ - CAM_DURATION renamed to CAM1_DURATION and scaled in seconds
+ - CAM_FEEDBACK_PIN/POL renamed to CAM1_FEEBAK_PIN/POL
+ - CAM_MIN_INTERVAL renamed to CAM1_INTRVAL_MIN and scaled in seconds
+ - CAM_TRIGG_DIST renamed to CAMx_TRIGG_DIST and accepts fractional values
+ - RunCam2 4k support
+ - ViewPro camera gimbal support
+9) Logging changes
+ - BARD msg includes 3-axis dynamic pressure useful for baro compensation of wind estimate
+ - MCU log msg includes main CPU temp and voltage (was part of POWR message)
+ - RCOut banner message always included in Logs
+ - SCR message includes memory usage of all running scripts
+ - CANS message includes CAN bus tx/rx statistics
+ - OFCA (optical flow calibration log message) units added
+ - Home location not logged to CMD message
+ - MOTB message includes throttle output
+10) Scripting enhancements
+ - Copter deadreckoning upgraded to applet
+ - EFI Skypower driver gets improved telem messages and bug fixes
+ - Generator throttle control example added
+ - Heap max increased by allowing heap to be split across multiple underlying OS heaps
+ - Hexsoon LEDs applet
+ - Logging from scripts supports more formats
+ - Parameters can be removed or reordered
+ - Parameter description support (scripts must be in AP's applet or driver directory)
+ - Rangefinder driver support
+ - Runcam_on_arm applet starts recording when vehicle is armed
+ - Safety switch, E-Stop and motor interlock support
+ - Scripts can restart all scripts
+ - Script_Controller applet supports inflight switching of active scripts
+11) Custom build server enhancements
+ - AIS support for displaying nearby boats can be included
+ - Battery, Camera and Compass drivers can be included/excluded
+ - EKF3 wind estimation can be included/excluded
+ - PCA9685, ToshibaLED, PLAY_TUNE notify drivers can be included/excluded
+ - Preclanding can be included/excluded
+ - RichenPower generator can be included/excluded
+ - RC SRXL protocol can be excluded
+ - SIRF GPSs can be included/excluded
+12) Safety related enhancements and fixes
+ - Arming check for high throttle skipped when arming in Auto mode
+ - Arming check for servo outputs skipped when SERVOx_FUNCTION is scripting
+ - Arming check fix if both "All" and other bitmasks are selected (previously only ran the other checks)
+ - "EK3 sources require RangeFinder" pre-arm check fix when user only sets up 2nd rangefinder (e.g. 1st is disabled)
+ - Pre-arm check that low and critical battery failsafe thresholds are different
+ - Pre-arm message fixed if 2nd EKF core unhealthy
+ - Pre-arm check if reboot required to enabled IMU batch sampling (used for vibe analysis)
+ - RC failsafe (aka throttle failsafe) option to change to Brake mode
+ - RC failsafe timeout configurable (see RC_FS_TIMEOUT)
+ - Takeoff check of motor RPM (see TKOFF_RPM_MIN)
+ - Turtle mode warns user to raise throttle to arm
+13) Minor enhancements
+ - Boot time reduced by improving parameter conversion efficiency
+ - BRD_SAFETYENABLE parameter renamed to BRD_SAFETY_DEFLT
+ - Compass calibration auxiliary switch function (set RCx_OPTION=171)
+ - Disable IMU3 auxiliary switch function (set RCx_OPTION=110)
+ - Frame type sent to GCS defaults to multicopter to ease first time setup
+ - Rangefinder and FS_OPTIONS param conversion code reduced (affects when upgrading from 3.6 or earlier)
+ - MAVFTP supports file renaming
+ - MAVLink in-progress reply to some requests for calibration from GCS
+14) Bug fixes:
+ - ADSB telemetry and callsign fixes
+ - Battery pct reported to GCS limited to 0% to 100% range
+ - Bi-directional DShot fix on H7 boards after system time wrap (more complete fix than in 4.3.6)
+ - DisplayPort OSD screen reliability improvement on heavily loaded OSDs especially F4 boards
+ - DisplayPort OSD artificial horizon better matches actual horizon
+ - EFI Serial MS bug fix to avoid possible infinite loop
+ - EKF3 Replay fix when COMPASS_LEARN=3
+ - ESC Telemetry external temp reporting fix
+ - Fence upload works even if Auto mode is excluded from firmware
+ - FMT messages logged even when Fence is exncluded from firmware (e.g. unselected when using custom build server)
+ - Guided mode slow yaw fix
+ - Hardfault avoided if user changes INS_LOG_BAT_CNT while batch sampling running
+ - ICM20649 temp sensor tolerate increased to avoid unnecessary FIFO reset
+ - IMU detection bug fix to avoid duplicates
+ - IMU temp cal fix when using auxiliary IMU
+ - Message Interval fix for restoring default rate https://github.com/ArduPilot/ardupilot/pull/21947
+ - RADIO_STATUS messages slow-down feature never completely stops messages from being sent
+ - SERVOx_TRIM value output momentarily if SERVOx_FUNCTION is changed from Disabled to RCPassThru, RCIN1, etc. Avoids momentary divide-by-zero
+ - Scripting file system open fix
+ - Scripting PWM source deletion crash fix
+ - MAVFTP fix for low baudrates (4800 baud and lower)
+ - ModalAI VOXL reset handling fix
+ - MPU6500 IMU fast sampling rate to 4k (was 1K)
+ - NMEA GPGGA output fixed for GPS quality, num sats and hdop
+ - Position control reset avoided even with very uneven main loop rate due to high CPU load
+ - SingleCopter and CoaxCopter fix to fin centering when using DShot
+ - SystemID mode fix to write PID log messages
+ - Terrain offset increased from 15m to 30m (see TERRAIN_OFS_MAX)to reduce chance of "clamping"
+ - Throttle notch FFT tuning param fix
+ - VTX protects against pitmode changes when not enabled or vehicle disarmed
+15) Developer specific items
+ - DroneCAN replaces UAVCAN
+ - FlighAxis simulator rangefinder fixed
+ - Scripts in applet and drivers directory checked using linter
+ - Simulator supports main loop timing jitter (see SIM_TIME_JITTER)
+ - Simulink model and init scripts
+ - SITL on hardware support (useful to demo servos moving in response to simulated flight)
+ - SITL parameter definitions added (some, not all)
+ - Webots 2023a simulator support
+ - XPlane support for wider range of aircraft
+------------------------------------------------------------------
+Copter 4.3.8-beta1 12-Aug-2023
+Changes from 4.3.7
+1) Bug fixes
+ - DroneCAN GPS RTK injection fix
+ - INAxxx battery monitors allow for battery reset remaining
+ - Notch filter gyro glitch caused by race condition fixed
+ - Scripting restart memory corruption bug fixed
+------------------------------------------------------------------
+Copter 4.3.7 31-May-2023 / 4.3.7-beta1 24-May-2023
+Changes from 4.3.6
+1) Bug fixes
+ a) EKF3 accel bias calculations bug fix
+ b) EKF3 accel bias process noise adjusted for greater robustness
+ c) GSF yaw numerical stability fix caused by compassmot
+ d) INS batch sampler fix to avoid watchdog if INS_LOG_BAT_CNT changed without rebooting
+ e) Memory corruption bug in the STM32H757 (very rare)
+ f) RC input on IOMCU bug fix (RC might not be regained if lost)
+------------------------------------------------------------------
Copter 4.3.6 05-Apr-2023 / 4.3.6-beta1, 4.3.6--beta2 27-Mar-2023
Changes from 4.3.5
1) Bi-directional DShot fix for possible motor stop approx 72min after startup
diff --git a/ArduCopter/config.h b/ArduCopter/config.h
index a260b6cba4ec67..7a7b6900c2fa7d 100644
--- a/ArduCopter/config.h
+++ b/ArduCopter/config.h
@@ -27,6 +27,7 @@
/// change in your local copy of APM_Config.h.
///
#include "APM_Config.h"
+#include
//////////////////////////////////////////////////////////////////////////////
@@ -146,8 +147,8 @@
//////////////////////////////////////////////////////////////////////////////
// Nav-Guided - allows external nav computer to control vehicle
-#ifndef NAV_GUIDED
- # define NAV_GUIDED !HAL_MINIMIZE_FEATURES
+#ifndef AC_NAV_GUIDED
+ # define AC_NAV_GUIDED ENABLED
#endif
//////////////////////////////////////////////////////////////////////////////
@@ -189,7 +190,7 @@
//////////////////////////////////////////////////////////////////////////////
// Follow - follow another vehicle or GCS
#ifndef MODE_FOLLOW_ENABLED
-# define MODE_FOLLOW_ENABLED !HAL_MINIMIZE_FEATURES
+# define MODE_FOLLOW_ENABLED AP_FOLLOW_ENABLED
#endif
//////////////////////////////////////////////////////////////////////////////
@@ -201,7 +202,7 @@
//////////////////////////////////////////////////////////////////////////////
// GuidedNoGPS mode - control vehicle's angles from GCS
#ifndef MODE_GUIDED_NOGPS_ENABLED
-# define MODE_GUIDED_NOGPS_ENABLED !HAL_MINIMIZE_FEATURES
+# define MODE_GUIDED_NOGPS_ENABLED ENABLED
#endif
//////////////////////////////////////////////////////////////////////////////
@@ -237,7 +238,7 @@
//////////////////////////////////////////////////////////////////////////////
// System ID - conduct system identification tests on vehicle
#ifndef MODE_SYSTEMID_ENABLED
-# define MODE_SYSTEMID_ENABLED !HAL_MINIMIZE_FEATURES
+# define MODE_SYSTEMID_ENABLED ENABLED
#endif
//////////////////////////////////////////////////////////////////////////////
@@ -249,19 +250,19 @@
//////////////////////////////////////////////////////////////////////////////
// ZigZag - allow vehicle to fly in a zigzag manner with predefined point A B
#ifndef MODE_ZIGZAG_ENABLED
-# define MODE_ZIGZAG_ENABLED !HAL_MINIMIZE_FEATURES
+# define MODE_ZIGZAG_ENABLED ENABLED
#endif
//////////////////////////////////////////////////////////////////////////////
// Turtle - allow vehicle to be flipped over after a crash
#ifndef MODE_TURTLE_ENABLED
-# define MODE_TURTLE_ENABLED !HAL_MINIMIZE_FEATURES && !defined(DISABLE_DSHOT) && FRAME_CONFIG != HELI_FRAME
+# define MODE_TURTLE_ENABLED HAL_DSHOT_ENABLED && FRAME_CONFIG != HELI_FRAME
#endif
//////////////////////////////////////////////////////////////////////////////
// Flowhold - use optical flow to hover in place
#ifndef MODE_FLOWHOLD_ENABLED
-# define MODE_FLOWHOLD_ENABLED !HAL_MINIMIZE_FEATURES && AP_OPTICALFLOW_ENABLED
+# define MODE_FLOWHOLD_ENABLED AP_OPTICALFLOW_ENABLED
#endif
//////////////////////////////////////////////////////////////////////////////
@@ -269,17 +270,18 @@
//////////////////////////////////////////////////////////////////////////////
// Weathervane - allow vehicle to yaw into wind
#ifndef WEATHERVANE_ENABLED
-# define WEATHERVANE_ENABLED !HAL_MINIMIZE_FEATURES
+# define WEATHERVANE_ENABLED ENABLED
#endif
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
// Autorotate - autonomous auto-rotation - helicopters only
+#ifndef MODE_AUTOROTATE_ENABLED
#if CONFIG_HAL_BOARD == HAL_BOARD_SITL
#if FRAME_CONFIG == HELI_FRAME
#ifndef MODE_AUTOROTATE_ENABLED
- # define MODE_AUTOROTATE_ENABLED !HAL_MINIMIZE_FEATURES
+ # define MODE_AUTOROTATE_ENABLED ENABLED
#endif
#else
# define MODE_AUTOROTATE_ENABLED DISABLED
@@ -287,6 +289,7 @@
#else
# define MODE_AUTOROTATE_ENABLED DISABLED
#endif
+#endif
//////////////////////////////////////////////////////////////////////////////
// RADIO CONFIGURATION
@@ -561,7 +564,7 @@
#endif
#ifndef AC_OAPATHPLANNER_ENABLED
- #define AC_OAPATHPLANNER_ENABLED !HAL_MINIMIZE_FEATURES
+ #define AC_OAPATHPLANNER_ENABLED ENABLED
#endif
#if MODE_FOLLOW_ENABLED && !AC_AVOID_ENABLED
diff --git a/ArduCopter/defines.h b/ArduCopter/defines.h
index b3cd317f76e68a..d5c55be60fea14 100644
--- a/ArduCopter/defines.h
+++ b/ArduCopter/defines.h
@@ -151,6 +151,7 @@ enum LoggingParameters {
#define FS_GCS_ENABLED_ALWAYS_SMARTRTL_OR_LAND 4
#define FS_GCS_ENABLED_ALWAYS_LAND 5
#define FS_GCS_ENABLED_AUTO_RTL_OR_RTL 6
+#define FS_GCS_ENABLED_BRAKE_OR_LAND 7
// EKF failsafe definitions (FS_EKF_ACTION parameter)
#define FS_EKF_ACTION_LAND 1 // switch to LAND mode on EKF failsafe
diff --git a/ArduCopter/events.cpp b/ArduCopter/events.cpp
index 69e4edb3b11735..94077c5088040c 100644
--- a/ArduCopter/events.cpp
+++ b/ArduCopter/events.cpp
@@ -187,6 +187,9 @@ void Copter::failsafe_gcs_on_event(void)
case FS_GCS_ENABLED_AUTO_RTL_OR_RTL:
desired_action = FailsafeAction::AUTO_DO_LAND_START;
break;
+ case FS_GCS_ENABLED_BRAKE_OR_LAND:
+ desired_action = FailsafeAction::BRAKE_LAND;
+ break;
default: // if an invalid parameter value is set, the fallback is RTL
desired_action = FailsafeAction::RTL;
}
diff --git a/ArduCopter/mode.cpp b/ArduCopter/mode.cpp
index 516de29c84ce51..d1e0822b200bdb 100644
--- a/ArduCopter/mode.cpp
+++ b/ArduCopter/mode.cpp
@@ -194,6 +194,52 @@ void Copter::mode_change_failed(const Mode *mode, const char *reason)
}
}
+// Check if this mode can be entered from the GCS
+bool Copter::gcs_mode_enabled(const Mode::Number mode_num)
+{
+ // List of modes that can be blocked, index is bit number in parameter bitmask
+ static const uint8_t mode_list [] {
+ (uint8_t)Mode::Number::STABILIZE,
+ (uint8_t)Mode::Number::ACRO,
+ (uint8_t)Mode::Number::ALT_HOLD,
+ (uint8_t)Mode::Number::AUTO,
+ (uint8_t)Mode::Number::GUIDED,
+ (uint8_t)Mode::Number::LOITER,
+ (uint8_t)Mode::Number::CIRCLE,
+ (uint8_t)Mode::Number::DRIFT,
+ (uint8_t)Mode::Number::SPORT,
+ (uint8_t)Mode::Number::FLIP,
+ (uint8_t)Mode::Number::AUTOTUNE,
+ (uint8_t)Mode::Number::POSHOLD,
+ (uint8_t)Mode::Number::BRAKE,
+ (uint8_t)Mode::Number::THROW,
+ (uint8_t)Mode::Number::AVOID_ADSB,
+ (uint8_t)Mode::Number::GUIDED_NOGPS,
+ (uint8_t)Mode::Number::SMART_RTL,
+ (uint8_t)Mode::Number::FLOWHOLD,
+ (uint8_t)Mode::Number::FOLLOW,
+ (uint8_t)Mode::Number::ZIGZAG,
+ (uint8_t)Mode::Number::SYSTEMID,
+ (uint8_t)Mode::Number::AUTOROTATE,
+ (uint8_t)Mode::Number::AUTO_RTL,
+ (uint8_t)Mode::Number::TURTLE
+ };
+
+ if (!block_GCS_mode_change((uint8_t)mode_num, mode_list, ARRAY_SIZE(mode_list))) {
+ return true;
+ }
+
+ // Mode disabled, try and grab a mode name to give a better warning.
+ Mode *new_flightmode = mode_from_mode_num(mode_num);
+ if (new_flightmode != nullptr) {
+ mode_change_failed(new_flightmode, "GCS entry disabled (FLTMODE_GCSBLOCK)");
+ } else {
+ notify_no_such_mode((uint8_t)mode_num);
+ }
+
+ return false;
+}
+
// set_mode - change flight mode and perform any necessary initialisation
// optional force parameter used to force the flight mode change (used only first time mode is set)
// returns true if mode was successfully set
@@ -218,6 +264,11 @@ bool Copter::set_mode(Mode::Number mode, ModeReason reason)
return true;
}
+ // Check if GCS mode change is disabled via parameter
+ if ((reason == ModeReason::GCS_COMMAND) && !gcs_mode_enabled(mode)) {
+ return false;
+ }
+
#if MODE_AUTO_ENABLED == ENABLED
if (mode == Mode::Number::AUTO_RTL) {
// Special case for AUTO RTL, not a true mode, just AUTO in disguise
diff --git a/ArduCopter/mode.h b/ArduCopter/mode.h
index dc417f51c6c837..28c78411797a85 100644
--- a/ArduCopter/mode.h
+++ b/ArduCopter/mode.h
@@ -2,6 +2,7 @@
#include "Copter.h"
#include
+#include // TODO why is this needed if Copter.h includes this
class Parameters;
class ParametersG2;
@@ -462,6 +463,7 @@ class ModeAuto : public Mode {
// pause continue in auto mode
bool pause() override;
bool resume() override;
+ bool paused() const;
bool loiter_start();
void rtl_start();
@@ -483,10 +485,6 @@ class ModeAuto : public Mode {
bool requires_terrain_failsafe() const override { return true; }
- // return true if this flight mode supports user takeoff
- // must_nagivate is true if mode must also control horizontal position
- virtual bool has_user_takeoff(bool must_navigate) const override { return false; }
-
void payload_place_start();
// for GCS_MAVLink to call:
@@ -569,7 +567,7 @@ class ModeAuto : public Mode {
void do_loiter_to_alt(const AP_Mission::Mission_Command& cmd);
void do_spline_wp(const AP_Mission::Mission_Command& cmd);
void get_spline_from_cmd(const AP_Mission::Mission_Command& cmd, const Location& default_loc, Location& dest_loc, Location& next_dest_loc, bool& next_dest_loc_is_spline);
-#if NAV_GUIDED == ENABLED
+#if AC_NAV_GUIDED == ENABLED
void do_nav_guided_enable(const AP_Mission::Mission_Command& cmd);
void do_guided_limits(const AP_Mission::Mission_Command& cmd);
#endif
@@ -607,7 +605,7 @@ class ModeAuto : public Mode {
bool verify_nav_wp(const AP_Mission::Mission_Command& cmd);
bool verify_circle(const AP_Mission::Mission_Command& cmd);
bool verify_spline_wp(const AP_Mission::Mission_Command& cmd);
-#if NAV_GUIDED == ENABLED
+#if AC_NAV_GUIDED == ENABLED
bool verify_nav_guided_enable(const AP_Mission::Mission_Command& cmd);
#endif
bool verify_nav_delay(const AP_Mission::Mission_Command& cmd);
@@ -960,6 +958,10 @@ class ModeFlowHold : public Mode {
class ModeGuided : public Mode {
public:
+#if AP_EXTERNAL_CONTROL_ENABLED
+ friend class AP_ExternalControl_Copter;
+#endif
+
// inherit constructor
using Mode::Mode;
Number mode_number() const override { return Number::GUIDED; }
@@ -1318,6 +1320,10 @@ class ModeRTL : public Mode {
bool use_pilot_yaw() const override;
+ bool set_speed_xy(float speed_xy_cms) override;
+ bool set_speed_up(float speed_up_cms) override;
+ bool set_speed_down(float speed_down_cms) override;
+
// RTL states
enum class SubMode : uint8_t {
STARTING,
@@ -1717,6 +1723,7 @@ class ModeAvoidADSB : public ModeGuided {
};
+#if AP_FOLLOW_ENABLED
class ModeFollow : public ModeGuided {
public:
@@ -1746,6 +1753,7 @@ class ModeFollow : public ModeGuided {
uint32_t last_log_ms; // system time of last time desired velocity was logging
};
+#endif
class ModeZigZag : public Mode {
@@ -1781,6 +1789,7 @@ class ModeZigZag : public Mode {
bool has_manual_throttle() const override { return false; }
bool allows_arming(AP_Arming::Method method) const override { return true; }
bool is_autopilot() const override { return true; }
+ bool has_user_takeoff(bool must_navigate) const override { return true; }
// save current position as A or B. If both A and B have been saved move to the one specified
void save_or_move_to_destination(Destination ab_dest);
diff --git a/ArduCopter/mode_auto.cpp b/ArduCopter/mode_auto.cpp
index 77be3560749f48..cdf41a4f7aa47c 100644
--- a/ArduCopter/mode_auto.cpp
+++ b/ArduCopter/mode_auto.cpp
@@ -136,7 +136,7 @@ void ModeAuto::run()
case SubMode::NAVGUIDED:
case SubMode::NAV_SCRIPT_TIME:
-#if NAV_GUIDED == ENABLED || AP_SCRIPTING_ENABLED
+#if AC_NAV_GUIDED == ENABLED || AP_SCRIPTING_ENABLED
nav_guided_run();
#endif
break;
@@ -502,7 +502,7 @@ void ModeAuto::circle_start()
set_submode(SubMode::CIRCLE);
}
-#if NAV_GUIDED == ENABLED
+#if AC_NAV_GUIDED == ENABLED
// auto_nav_guided_start - hand over control to external navigation controller in AUTO mode
void ModeAuto::nav_guided_start()
{
@@ -519,7 +519,7 @@ void ModeAuto::nav_guided_start()
// set submode
set_submode(SubMode::NAVGUIDED);
}
-#endif //NAV_GUIDED
+#endif //AC_NAV_GUIDED
bool ModeAuto::is_landing() const
{
@@ -647,7 +647,7 @@ bool ModeAuto::start_command(const AP_Mission::Mission_Command& cmd)
do_spline_wp(cmd);
break;
-#if NAV_GUIDED == ENABLED
+#if AC_NAV_GUIDED == ENABLED
case MAV_CMD_NAV_GUIDED_ENABLE: // 92 accept navigation commands from external nav computer
do_nav_guided_enable(cmd);
break;
@@ -719,7 +719,7 @@ bool ModeAuto::start_command(const AP_Mission::Mission_Command& cmd)
#endif //AP_FENCE_ENABLED
break;
-#if NAV_GUIDED == ENABLED
+#if AC_NAV_GUIDED == ENABLED
case MAV_CMD_DO_GUIDED_LIMITS: // 220 accept guided mode limits
do_guided_limits(cmd);
break;
@@ -892,7 +892,7 @@ bool ModeAuto::verify_command(const AP_Mission::Mission_Command& cmd)
cmd_complete = verify_spline_wp(cmd);
break;
-#if NAV_GUIDED == ENABLED
+#if AC_NAV_GUIDED == ENABLED
case MAV_CMD_NAV_GUIDED_ENABLE:
cmd_complete = verify_nav_guided_enable(cmd);
break;
@@ -1033,7 +1033,7 @@ void ModeAuto::circle_run()
attitude_control->input_thrust_vector_heading(pos_control->get_thrust_vector(), auto_yaw.get_heading());
}
-#if NAV_GUIDED == ENABLED || AP_SCRIPTING_ENABLED
+#if AC_NAV_GUIDED == ENABLED || AP_SCRIPTING_ENABLED
// auto_nav_guided_run - allows control by external navigation controller
// called by auto_run at 100hz or more
void ModeAuto::nav_guided_run()
@@ -1041,7 +1041,7 @@ void ModeAuto::nav_guided_run()
// call regular guided flight mode run function
copter.mode_guided.run();
}
-#endif // NAV_GUIDED || AP_SCRIPTING_ENABLED
+#endif // AC_NAV_GUIDED || AP_SCRIPTING_ENABLED
// auto_loiter_run - loiter in AUTO flight mode
// called by auto_run at 100hz or more
@@ -1751,7 +1751,7 @@ void ModeAuto::get_spline_from_cmd(const AP_Mission::Mission_Command& cmd, const
}
}
-#if NAV_GUIDED == ENABLED
+#if AC_NAV_GUIDED == ENABLED
// do_nav_guided_enable - initiate accepting commands from external nav computer
void ModeAuto::do_nav_guided_enable(const AP_Mission::Mission_Command& cmd)
{
@@ -1770,7 +1770,7 @@ void ModeAuto::do_guided_limits(const AP_Mission::Mission_Command& cmd)
cmd.content.guided_limits.alt_max * 100.0f, // convert meters to cm
cmd.content.guided_limits.horiz_max * 100.0f); // convert meters to cm
}
-#endif // NAV_GUIDED
+#endif // AC_NAV_GUIDED
// do_nav_delay - Delay the next navigation command
void ModeAuto::do_nav_delay(const AP_Mission::Mission_Command& cmd)
@@ -1892,7 +1892,7 @@ void ModeAuto::do_mount_control(const AP_Mission::Mission_Command& cmd)
{
#if HAL_MOUNT_ENABLED
// if vehicle has a camera mount but it doesn't do pan control then yaw the entire vehicle instead
- if ((copter.camera_mount.get_mount_type() != copter.camera_mount.MountType::Mount_Type_None) &&
+ if ((copter.camera_mount.get_mount_type() != AP_Mount::Type::None) &&
!copter.camera_mount.has_pan_control()) {
auto_yaw.set_yaw_angle_rate(cmd.content.mount_control.yaw,0.0f);
}
@@ -2188,7 +2188,7 @@ bool ModeAuto::verify_spline_wp(const AP_Mission::Mission_Command& cmd)
return false;
}
-#if NAV_GUIDED == ENABLED
+#if AC_NAV_GUIDED == ENABLED
// verify_nav_guided - check if we have breached any limits
bool ModeAuto::verify_nav_guided_enable(const AP_Mission::Mission_Command& cmd)
{
@@ -2200,7 +2200,7 @@ bool ModeAuto::verify_nav_guided_enable(const AP_Mission::Mission_Command& cmd)
// check time and position limits
return copter.mode_guided.limit_check();
}
-#endif // NAV_GUIDED
+#endif // AC_NAV_GUIDED
// verify_nav_delay - check if we have waited long enough
bool ModeAuto::verify_nav_delay(const AP_Mission::Mission_Command& cmd)
@@ -2251,4 +2251,9 @@ bool ModeAuto::resume()
return true;
}
+bool ModeAuto::paused() const
+{
+ return wp_nav->paused();
+}
+
#endif
diff --git a/ArduCopter/mode_brake.cpp b/ArduCopter/mode_brake.cpp
index 55d71f1c63f484..65a353ebc78296 100644
--- a/ArduCopter/mode_brake.cpp
+++ b/ArduCopter/mode_brake.cpp
@@ -61,6 +61,7 @@ void ModeBrake::run()
pos_control->set_pos_target_z_from_climb_rate_cm(0.0f);
pos_control->update_z_controller();
+ // MAV_CMD_SOLO_BTN_PAUSE_CLICK (Solo only) is used to set the timeout.
if (_timeout_ms != 0 && millis()-_timeout_start >= _timeout_ms) {
if (!copter.set_mode(Mode::Number::LOITER, ModeReason::BRAKE_TIMEOUT)) {
copter.set_mode(Mode::Number::ALT_HOLD, ModeReason::BRAKE_TIMEOUT);
@@ -68,6 +69,16 @@ void ModeBrake::run()
}
}
+/**
+ * Set a timeout for the brake mode
+ *
+ * @param timeout_ms [in] timeout in milliseconds
+ *
+ * @note MAV_CMD_SOLO_BTN_PAUSE_CLICK (Solo only) is used to set the timeout.
+ * If the timeout is reached, the mode will switch to loiter or alt hold depending on the current mode.
+ * If timeout_ms is 0, the timeout is disabled.
+ *
+*/
void ModeBrake::timeout_to_loiter_ms(uint32_t timeout_ms)
{
_timeout_start = millis();
diff --git a/ArduCopter/mode_circle.cpp b/ArduCopter/mode_circle.cpp
index c86de8856df188..1c73b807dd3dce 100644
--- a/ArduCopter/mode_circle.cpp
+++ b/ArduCopter/mode_circle.cpp
@@ -1,4 +1,5 @@
#include "Copter.h"
+#include
#if MODE_CIRCLE_ENABLED == ENABLED
@@ -20,6 +21,18 @@ bool ModeCircle::init(bool ignore_checks)
// initialise circle controller including setting the circle center based on vehicle speed
copter.circle_nav->init();
+#if HAL_MOUNT_ENABLED
+ AP_Mount *s = AP_Mount::get_singleton();
+
+ // Check if the CIRCLE_OPTIONS parameter have roi_at_center
+ if (copter.circle_nav->roi_at_center()) {
+ Vector3p loc = copter.circle_nav->get_center();
+ loc.z = 0;
+ Location circle_center(loc, Location::AltFrame::ABOVE_TERRAIN);
+ s->set_roi_target(circle_center);
+ }
+#endif
+
// set auto yaw circle mode
auto_yaw.set_mode(AutoYaw::Mode::CIRCLE);
diff --git a/ArduCopter/mode_follow.cpp b/ArduCopter/mode_follow.cpp
index afa348503b084c..a0649c5956c24f 100644
--- a/ArduCopter/mode_follow.cpp
+++ b/ArduCopter/mode_follow.cpp
@@ -20,6 +20,15 @@ bool ModeFollow::init(const bool ignore_checks)
gcs().send_text(MAV_SEVERITY_WARNING, "Set FOLL_ENABLE = 1");
return false;
}
+
+#if HAL_MOUNT_ENABLED
+ AP_Mount *mount = AP_Mount::get_singleton();
+ // follow the lead vehicle using sysid
+ if (g2.follow.option_is_enabled(AP_Follow::Option::MOUNT_FOLLOW_ON_ENTER) && mount != nullptr) {
+ mount->set_target_sysid(g2.follow.get_target_sysid());
+ }
+#endif
+
// re-use guided mode
return ModeGuided::init(ignore_checks);
}
diff --git a/ArduCopter/mode_guided.cpp b/ArduCopter/mode_guided.cpp
index fd313a1c0d0831..4d0f9e3154cfb2 100644
--- a/ArduCopter/mode_guided.cpp
+++ b/ArduCopter/mode_guided.cpp
@@ -100,7 +100,7 @@ void ModeGuided::run()
bool ModeGuided::allows_arming(AP_Arming::Method method) const
{
// always allow arming from the ground station or scripting
- if (method == AP_Arming::Method::MAVLINK || method == AP_Arming::Method::SCRIPTING) {
+ if (AP_Arming::method_is_GCS(method) || method == AP_Arming::Method::SCRIPTING) {
return true;
}
@@ -1087,7 +1087,6 @@ uint32_t ModeGuided::wp_distance() const
return get_horizontal_distance_cm(inertial_nav.get_position_xy_cm(), guided_pos_target_cm.tofloat().xy());
case SubMode::PosVelAccel:
return pos_control->get_pos_error_xy_cm();
- break;
default:
return 0;
}
@@ -1102,7 +1101,6 @@ int32_t ModeGuided::wp_bearing() const
return get_bearing_cd(inertial_nav.get_position_xy_cm(), guided_pos_target_cm.tofloat().xy());
case SubMode::PosVelAccel:
return pos_control->get_bearing_to_target_cd();
- break;
case SubMode::TakeOff:
case SubMode::Accel:
case SubMode::VelAccel:
diff --git a/ArduCopter/mode_rtl.cpp b/ArduCopter/mode_rtl.cpp
index e6ae505e8214a6..795e483e93423a 100644
--- a/ArduCopter/mode_rtl.cpp
+++ b/ArduCopter/mode_rtl.cpp
@@ -554,4 +554,22 @@ bool ModeRTL::use_pilot_yaw(void) const
return allow_yaw_option || land_repositioning || final_landing;
}
+bool ModeRTL::set_speed_xy(float speed_xy_cms)
+{
+ copter.wp_nav->set_speed_xy(speed_xy_cms);
+ return true;
+}
+
+bool ModeRTL::set_speed_up(float speed_up_cms)
+{
+ copter.wp_nav->set_speed_up(speed_up_cms);
+ return true;
+}
+
+bool ModeRTL::set_speed_down(float speed_down_cms)
+{
+ copter.wp_nav->set_speed_down(speed_down_cms);
+ return true;
+}
+
#endif
diff --git a/ArduCopter/mode_turtle.cpp b/ArduCopter/mode_turtle.cpp
index 99c5d2b08d73c1..74dc49421ecff6 100644
--- a/ArduCopter/mode_turtle.cpp
+++ b/ArduCopter/mode_turtle.cpp
@@ -163,7 +163,7 @@ void ModeTurtle::run()
Vector2f input{sign_roll, sign_pitch};
motors_input = input.normalized() * 0.5;
// we bypass spin min and friends in the deadzone because we only want spin up when the sticks are moved
- motors_output = !is_zero(flip_power) ? motors->thrust_to_actuator(flip_power) : 0.0f;
+ motors_output = !is_zero(flip_power) ? motors->thr_lin.thrust_to_actuator(flip_power) : 0.0f;
}
// actually write values to the motors
diff --git a/ArduCopter/motor_test.cpp b/ArduCopter/motor_test.cpp
index 6efd17d41f5d37..5c5deae8995cd7 100644
--- a/ArduCopter/motor_test.cpp
+++ b/ArduCopter/motor_test.cpp
@@ -101,6 +101,13 @@ bool Copter::mavlink_motor_control_check(const GCS_MAVLINK &gcs_chan, bool check
return false;
}
+ // Check Motor test is allowed
+ char failure_msg[50] {};
+ if (!motors->motor_test_checks(ARRAY_SIZE(failure_msg), failure_msg)) {
+ gcs_chan.send_text(MAV_SEVERITY_CRITICAL,"%s: %s", mode, failure_msg);
+ return false;
+ }
+
// check rc has been calibrated
if (check_rc && !arming.rc_calibration_checks(true)) {
gcs_chan.send_text(MAV_SEVERITY_CRITICAL,"%s: RC not calibrated", mode);
diff --git a/ArduCopter/sensors.cpp b/ArduCopter/sensors.cpp
index fd103ee21895f8..589561b8cfe406 100644
--- a/ArduCopter/sensors.cpp
+++ b/ArduCopter/sensors.cpp
@@ -6,8 +6,6 @@ void Copter::read_barometer(void)
barometer.update();
baro_alt = barometer.get_altitude() * 100.0f;
-
- motors->set_air_density_ratio(barometer.get_air_density_ratio());
}
void Copter::init_rangefinder(void)
diff --git a/ArduCopter/system.cpp b/ArduCopter/system.cpp
index 4e1527e2fc569f..221a92bb9a2700 100644
--- a/ArduCopter/system.cpp
+++ b/ArduCopter/system.cpp
@@ -92,7 +92,9 @@ void Copter::init_ardupilot()
// motors initialised so parameters can be sent
ap.initialised_params = true;
+#if AP_RELAY_ENABLED
relay.init();
+#endif
/*
* setup the 'main loop is dead' check. Note that this relies on
@@ -151,8 +153,10 @@ void Copter::init_ardupilot()
barometer.set_log_baro_bit(MASK_LOG_IMU);
barometer.calibrate();
+#if RANGEFINDER_ENABLED == ENABLED
// initialise rangefinder
init_rangefinder();
+#endif
#if HAL_PROXIMITY_ENABLED
// init proximity sensor
@@ -196,11 +200,6 @@ void Copter::init_ardupilot()
set_land_complete(true);
set_land_complete_maybe(true);
- // we don't want writes to the serial port to cause us to pause
- // mid-flight, so set the serial ports non-blocking once we are
- // ready to fly
- serial_manager.set_blocking_writes_all(false);
-
// enable CPU failsafe
failsafe_enable();
diff --git a/ArduCopter/takeoff_check.cpp b/ArduCopter/takeoff_check.cpp
index f3b55ec45fb3d1..48f172a02cc366 100644
--- a/ArduCopter/takeoff_check.cpp
+++ b/ArduCopter/takeoff_check.cpp
@@ -30,7 +30,7 @@ void Copter::takeoff_check()
// check ESCs are sending RPM at expected level
uint32_t motor_mask = motors->get_motor_mask();
const bool telem_active = AP::esc_telem().is_telemetry_active(motor_mask);
- const bool rpm_adequate = AP::esc_telem().are_motors_running(motor_mask, g2.takeoff_rpm_min);
+ const bool rpm_adequate = AP::esc_telem().are_motors_running(motor_mask, g2.takeoff_rpm_min, g2.takeoff_rpm_max);
// if RPM is at the expected level clear block
if (telem_active && rpm_adequate) {
@@ -49,7 +49,7 @@ void Copter::takeoff_check()
if (!telem_active) {
gcs().send_text(MAV_SEVERITY_CRITICAL, "%s waiting for ESC RPM", prefix_str);
} else if (!rpm_adequate) {
- gcs().send_text(MAV_SEVERITY_CRITICAL, "%s ESC RPM too low", prefix_str);
+ gcs().send_text(MAV_SEVERITY_CRITICAL, "%s ESC RPM out of range", prefix_str);
}
}
#endif
diff --git a/ArduCopter/version.h b/ArduCopter/version.h
index 35ee178e09076a..aca789abdc19fa 100644
--- a/ArduCopter/version.h
+++ b/ArduCopter/version.h
@@ -6,13 +6,13 @@
#include "ap_version.h"
-#define THISFIRMWARE "ArduCopter V4.4.0-dev"
+#define THISFIRMWARE "ArduCopter V4.5.0-dev"
// the following line is parsed by the autotest scripts
-#define FIRMWARE_VERSION 4,4,0,FIRMWARE_VERSION_TYPE_DEV
+#define FIRMWARE_VERSION 4,5,0,FIRMWARE_VERSION_TYPE_DEV
#define FW_MAJOR 4
-#define FW_MINOR 4
+#define FW_MINOR 5
#define FW_PATCH 0
#define FW_TYPE FIRMWARE_VERSION_TYPE_DEV
diff --git a/ArduPlane/AP_Arming.cpp b/ArduPlane/AP_Arming.cpp
index 54fdc5592f961c..7ab5e92b8e9901 100644
--- a/ArduPlane/AP_Arming.cpp
+++ b/ArduPlane/AP_Arming.cpp
@@ -14,6 +14,17 @@ const AP_Param::GroupInfo AP_Arming_Plane::var_info[] = {
// index 3 was RUDDER and should not be used
+#if AP_PLANE_BLACKBOX_LOGGING
+ // @Param: BBOX_SPD
+ // @DisplayName: Blackbox speed
+ // @Description: This is a 3D GPS speed threshold above which we will force arm the vehicle to start logging. WARNING: This should only be used on a vehicle with no propellers attached to the flight controller and when the flight controller is not in control of the vehicle.
+ // @Units: m/s
+ // @Increment: 1
+ // @Range: 1 20
+ // @User: Advanced
+ AP_GROUPINFO("BBOX_SPD", 4, AP_Arming_Plane, blackbox_speed, 5),
+#endif // AP_PLANE_BLACKBOX_LOGGING
+
AP_GROUPEND
};
@@ -42,7 +53,7 @@ bool AP_Arming_Plane::pre_arm_checks(bool display_failure)
}
//are arming checks disabled?
if (checks_to_perform == 0) {
- return true;
+ return mandatory_checks(display_failure);
}
if (hal.util->was_watchdog_armed()) {
// on watchdog reset bypass arming checks to allow for
@@ -91,22 +102,19 @@ bool AP_Arming_Plane::pre_arm_checks(bool display_failure)
ret = false;
}
+ ret &= rc_received_if_enabled_check(display_failure);
+
#if HAL_QUADPLANE_ENABLED
ret &= quadplane_checks(display_failure);
#endif
- if (plane.control_mode == &plane.mode_auto && plane.mission.num_commands() <= 1) {
- check_failed(display_failure, "No mission loaded");
- ret = false;
- }
-
// check adsb avoidance failsafe
if (plane.failsafe.adsb) {
check_failed(display_failure, "ADSB threat detected");
ret = false;
}
- if (plane.g2.flight_options & FlightOptions::CENTER_THROTTLE_TRIM){
+ if (plane.flight_option_enabled(FlightOptions::CENTER_THROTTLE_TRIM)){
int16_t trim = plane.channel_throttle->get_radio_trim();
if (trim < 1250 || trim > 1750) {
check_failed(display_failure, "Throttle trim not near center stick(%u)",trim );
@@ -129,6 +137,19 @@ bool AP_Arming_Plane::pre_arm_checks(bool display_failure)
return ret;
}
+bool AP_Arming_Plane::mandatory_checks(bool display_failure)
+{
+ bool ret = true;
+
+ ret &= rc_received_if_enabled_check(display_failure);
+
+ // Call parent class checks
+ ret &= AP_Arming::mandatory_checks(display_failure);
+
+ return ret;
+}
+
+
#if HAL_QUADPLANE_ENABLED
bool AP_Arming_Plane::quadplane_checks(bool display_failure)
{
@@ -304,7 +325,7 @@ bool AP_Arming_Plane::arm(const AP_Arming::Method method, const bool do_arming_c
bool AP_Arming_Plane::disarm(const AP_Arming::Method method, bool do_disarm_checks)
{
if (do_disarm_checks &&
- (method == AP_Arming::Method::MAVLINK ||
+ (AP_Arming::method_is_GCS(method) ||
method == AP_Arming::Method::RUDDER)) {
if (plane.is_flying()) {
// don't allow mavlink or rudder disarm while flying
@@ -377,6 +398,27 @@ void AP_Arming_Plane::update_soft_armed()
delay_arming = false;
}
+
+#if AP_PLANE_BLACKBOX_LOGGING
+ if (blackbox_speed > 0) {
+ const float speed3d = plane.gps.status() >= AP_GPS::GPS_OK_FIX_3D?plane.gps.velocity().length():0;
+ const uint32_t now = AP_HAL::millis();
+ if (speed3d > blackbox_speed) {
+ last_over_3dspeed_ms = now;
+ }
+ if (!_armed && speed3d > blackbox_speed) {
+ // force safety on so we don't run motors
+ hal.rcout->force_safety_on();
+ AP_Param::set_by_name("RC_PROTOCOLS", 0);
+ arm(Method::BLACKBOX, false);
+ gcs().send_text(MAV_SEVERITY_WARNING, "BlackBox: arming at %.1f m/s", speed3d);
+ }
+ if (_armed && now - last_over_3dspeed_ms > 20000U) {
+ gcs().send_text(MAV_SEVERITY_WARNING, "BlackBox: disarming at %.1f m/s", speed3d);
+ disarm(Method::BLACKBOX, false);
+ }
+ }
+#endif
}
/*
@@ -416,3 +458,21 @@ bool AP_Arming_Plane::mission_checks(bool report)
#endif
return ret;
}
+
+// Checks rc has been received if it is configured to be used
+bool AP_Arming_Plane::rc_received_if_enabled_check(bool display_failure)
+{
+ if (rc().enabled_protocols() == 0) {
+ // No protocols enabled, will never get RC, don't block arming
+ return true;
+ }
+
+ // If RC failsafe is enabled we must receive RC before arming
+ if ((Plane::ThrFailsafe(plane.g.throttle_fs_enabled.get()) == Plane::ThrFailsafe::Enabled) &&
+ !(rc().has_had_rc_receiver() || rc().has_had_rc_override())) {
+ check_failed(display_failure, "Waiting for RC");
+ return false;
+ }
+
+ return true;
+}
diff --git a/ArduPlane/AP_Arming.h b/ArduPlane/AP_Arming.h
index afce68ae116955..b340ecdfc2f81e 100644
--- a/ArduPlane/AP_Arming.h
+++ b/ArduPlane/AP_Arming.h
@@ -2,6 +2,10 @@
#include
+#ifndef AP_PLANE_BLACKBOX_LOGGING
+#define AP_PLANE_BLACKBOX_LOGGING 0
+#endif
+
/*
a plane specific arming class
*/
@@ -29,6 +33,9 @@ class AP_Arming_Plane : public AP_Arming
void update_soft_armed();
bool get_delay_arming() const { return delay_arming; };
+ // mandatory checks that cannot be bypassed. This function will only be called if ARMING_CHECK is zero or arming forced
+ bool mandatory_checks(bool display_failure) override;
+
protected:
bool ins_checks(bool report) override;
bool terrain_database_required() const override;
@@ -36,10 +43,18 @@ class AP_Arming_Plane : public AP_Arming
bool quadplane_checks(bool display_failure);
bool mission_checks(bool report) override;
+ // Checks rc has been received if it is configured to be used
+ bool rc_received_if_enabled_check(bool display_failure);
+
private:
void change_arm_state(void);
// oneshot with duration AP_ARMING_DELAY_MS used by quadplane to delay spoolup after arming:
// ignored unless OPTION_DELAY_ARMING or OPTION_TILT_DISARMED is set
bool delay_arming;
+
+#if AP_PLANE_BLACKBOX_LOGGING
+ AP_Float blackbox_speed;
+ uint32_t last_over_3dspeed_ms;
+#endif
};
diff --git a/ArduPlane/ArduPlane.cpp b/ArduPlane/ArduPlane.cpp
index d832d8fed3a342..61d76425333278 100644
--- a/ArduPlane/ArduPlane.cpp
+++ b/ArduPlane/ArduPlane.cpp
@@ -63,7 +63,7 @@ const AP_Scheduler::Task Plane::scheduler_tasks[] = {
SCHED_TASK(check_short_failsafe, 50, 100, 9),
SCHED_TASK(update_speed_height, 50, 200, 12),
SCHED_TASK(update_throttle_hover, 100, 90, 24),
- SCHED_TASK(read_control_switch, 7, 100, 27),
+ SCHED_TASK_CLASS(RC_Channels, (RC_Channels*)&plane.g2.rc_channels, read_mode_switch, 7, 100, 27),
SCHED_TASK(update_GPS_50Hz, 50, 300, 30),
SCHED_TASK(update_GPS_10Hz, 10, 400, 33),
SCHED_TASK(navigate, 10, 150, 36),
@@ -77,10 +77,11 @@ const AP_Scheduler::Task Plane::scheduler_tasks[] = {
SCHED_TASK(ekf_check, 10, 75, 54),
SCHED_TASK_CLASS(GCS, (GCS*)&plane._gcs, update_receive, 300, 500, 57),
SCHED_TASK_CLASS(GCS, (GCS*)&plane._gcs, update_send, 300, 750, 60),
+#if AP_SERVORELAYEVENTS_ENABLED
SCHED_TASK_CLASS(AP_ServoRelayEvents, &plane.ServoRelayEvents, update_events, 50, 150, 63),
+#endif
SCHED_TASK_CLASS(AP_BattMonitor, &plane.battery, read, 10, 300, 66),
SCHED_TASK_CLASS(AP_Baro, &plane.barometer, accumulate, 50, 150, 69),
- SCHED_TASK_CLASS(AP_Notify, &plane.notify, update, 50, 300, 72),
SCHED_TASK(read_rangefinder, 50, 100, 78),
#if AP_ICENGINE_ENABLED
SCHED_TASK_CLASS(AP_ICEngine, &plane.g2.ice_control, update, 10, 100, 81),
@@ -203,7 +204,13 @@ void Plane::ahrs_update()
*/
void Plane::update_speed_height(void)
{
- if (control_mode->does_auto_throttle()) {
+ bool should_run_tecs = control_mode->does_auto_throttle();
+#if HAL_QUADPLANE_ENABLED
+ if (quadplane.should_disable_TECS()) {
+ should_run_tecs = false;
+ }
+#endif
+ if (should_run_tecs) {
// Call TECS 50Hz update. Note that we call this regardless of
// throttle suppressed, as this needs to be running for
// takeoff detection
@@ -238,7 +245,12 @@ void Plane::update_logging10(void)
ahrs.Write_AOA_SSA();
} else if (log_faster) {
ahrs.Write_AOA_SSA();
- }
+ }
+#if HAL_MOUNT_ENABLED
+ if (should_log(MASK_LOG_CAMERA)) {
+ camera_mount.write_log();
+ }
+#endif
}
/*
@@ -255,7 +267,9 @@ void Plane::update_logging25(void)
if (should_log(MASK_LOG_CTUN)) {
Log_Write_Control_Tuning();
- AP::ins().write_notch_log_messages();
+ if (!should_log(MASK_LOG_NOTCH_FULLRATE)) {
+ AP::ins().write_notch_log_messages();
+ }
#if HAL_GYROFFT_ENABLED
gyro_fft.write_log_messages();
#endif
@@ -303,7 +317,7 @@ void Plane::one_second_loop()
adsb.set_max_speed(aparm.airspeed_max);
#endif
- if (g2.flight_options & FlightOptions::ENABLE_DEFAULT_AIRSPEED) {
+ if (flight_option_enabled(FlightOptions::ENABLE_DEFAULT_AIRSPEED)) {
// use average of min and max airspeed as default airspeed fusion with high variance
ahrs.writeDefaultAirSpeed((float)((aparm.airspeed_min + aparm.airspeed_max)/2),
(float)((aparm.airspeed_max - aparm.airspeed_min)/2));
@@ -511,12 +525,6 @@ void Plane::update_alt()
{
barometer.update();
-#if HAL_QUADPLANE_ENABLED
- if (quadplane.available()) {
- quadplane.motors->set_air_density_ratio(barometer.get_air_density_ratio());
- }
-#endif
-
// calculate the sink rate.
float sink_rate;
Vector3f vel;
@@ -543,7 +551,14 @@ void Plane::update_alt()
}
#endif
- if (control_mode->does_auto_throttle() && !throttle_suppressed) {
+ bool should_run_tecs = control_mode->does_auto_throttle();
+#if HAL_QUADPLANE_ENABLED
+ if (quadplane.should_disable_TECS()) {
+ should_run_tecs = false;
+ }
+#endif
+
+ if (should_run_tecs && !throttle_suppressed) {
float distance_beyond_land_wp = 0;
if (flight_stage == AP_FixedWing::FlightStage::LAND &&
@@ -553,7 +568,7 @@ void Plane::update_alt()
tecs_target_alt_cm = relative_target_altitude_cm();
- if (control_mode == &mode_rtl && !rtl.done_climb && (g2.rtl_climb_min > 0 || (plane.g2.flight_options & FlightOptions::CLIMB_BEFORE_TURN))) {
+ if (control_mode == &mode_rtl && !rtl.done_climb && (g2.rtl_climb_min > 0 || (plane.flight_option_enabled(FlightOptions::CLIMB_BEFORE_TURN)))) {
// ensure we do the initial climb in RTL. We add an extra
// 10m in the demanded height to push TECS to climb
// quickly
@@ -855,9 +870,30 @@ bool Plane::set_land_descent_rate(float descent_rate)
#endif
return false;
}
-
#endif // AP_SCRIPTING_ENABLED
+// returns true if vehicle is landing.
+bool Plane::is_landing() const
+{
+#if HAL_QUADPLANE_ENABLED
+ if (plane.quadplane.in_vtol_land_descent()) {
+ return true;
+ }
+#endif
+ return control_mode->is_landing();
+}
+
+// returns true if vehicle is taking off.
+bool Plane::is_taking_off() const
+{
+#if HAL_QUADPLANE_ENABLED
+ if (plane.quadplane.in_vtol_takeoff()) {
+ return true;
+ }
+#endif
+ return control_mode->is_taking_off();
+}
+
// correct AHRS pitch for TRIM_PITCH_CD in non-VTOL modes, and return VTOL view in VTOL
void Plane::get_osd_roll_pitch_rad(float &roll, float &pitch) const
{
@@ -870,7 +906,7 @@ void Plane::get_osd_roll_pitch_rad(float &roll, float &pitch) const
#endif
pitch = ahrs.pitch;
roll = ahrs.roll;
- if (!(g2.flight_options & FlightOptions::OSD_REMOVE_TRIM_PITCH_CD)) { // correct for TRIM_PITCH_CD
+ if (!(flight_option_enabled(FlightOptions::OSD_REMOVE_TRIM_PITCH_CD))) { // correct for TRIM_PITCH_CD
pitch -= g.pitch_trim_cd * 0.01 * DEG_TO_RAD;
}
}
@@ -887,4 +923,10 @@ void Plane::update_current_loc(void)
relative_altitude *= -1.0f;
}
+// check if FLIGHT_OPTION is enabled
+bool Plane::flight_option_enabled(FlightOptions flight_option) const
+{
+ return g2.flight_options & flight_option;
+}
+
AP_HAL_MAIN_CALLBACKS(&plane);
diff --git a/ArduPlane/Attitude.cpp b/ArduPlane/Attitude.cpp
index 0b51098b43ce00..90484121cb60ba 100644
--- a/ArduPlane/Attitude.cpp
+++ b/ArduPlane/Attitude.cpp
@@ -50,7 +50,7 @@ float Plane::calc_speed_scaler(void)
speed_scaler = 1;
}
if (!plane.ahrs.airspeed_sensor_enabled() &&
- (plane.g2.flight_options & FlightOptions::SURPRESS_TKOFF_SCALING) &&
+ (plane.flight_option_enabled(FlightOptions::SURPRESS_TKOFF_SCALING)) &&
(plane.flight_stage == AP_FixedWing::FlightStage::TAKEOFF)) { //scaling is surpressed during climb phase of automatic takeoffs with no airspeed sensor being used due to problems with inaccurate airspeed estimates
return MIN(speed_scaler, 1.0f) ;
}
@@ -145,7 +145,7 @@ float Plane::stabilize_roll_get_roll_out()
disable_integrator = true;
}
return rollController.get_servo_out(nav_roll_cd - ahrs.roll_sensor, speed_scaler, disable_integrator,
- ground_mode && !(plane.g2.flight_options & FlightOptions::DISABLE_GROUND_PID_SUPPRESSION));
+ ground_mode && !(plane.flight_option_enabled(FlightOptions::DISABLE_GROUND_PID_SUPPRESSION)));
}
/*
@@ -208,23 +208,29 @@ float Plane::stabilize_pitch_get_pitch_out()
}
return pitchController.get_servo_out(demanded_pitch - ahrs.pitch_sensor, speed_scaler, disable_integrator,
- ground_mode && !(plane.g2.flight_options & FlightOptions::DISABLE_GROUND_PID_SUPPRESSION));
+ ground_mode && !(plane.flight_option_enabled(FlightOptions::DISABLE_GROUND_PID_SUPPRESSION)));
}
/*
this gives the user control of the aircraft in stabilization modes, only used in Stabilize Mode
+ to be moved to mode_stabilize.cpp in future
*/
-void Plane::stabilize_stick_mixing_direct()
+void ModeStabilize::stabilize_stick_mixing_direct()
{
- if (!stick_mixing_enabled()) {
+ if (!plane.stick_mixing_enabled()) {
return;
}
+#if HAL_QUADPLANE_ENABLED
+ if (!plane.quadplane.allow_stick_mixing()) {
+ return;
+ }
+#endif
float aileron = SRV_Channels::get_output_scaled(SRV_Channel::k_aileron);
- aileron = channel_roll->stick_mixing(aileron);
+ aileron = plane.channel_roll->stick_mixing(aileron);
SRV_Channels::set_output_scaled(SRV_Channel::k_aileron, aileron);
float elevator = SRV_Channels::get_output_scaled(SRV_Channel::k_elevator);
- elevator = channel_pitch->stick_mixing(elevator);
+ elevator = plane.channel_pitch->stick_mixing(elevator);
SRV_Channels::set_output_scaled(SRV_Channel::k_elevator, elevator);
}
@@ -249,6 +255,7 @@ void Plane::stabilize_stick_mixing_fbw()
#if QAUTOTUNE_ENABLED
control_mode == &mode_qautotune ||
#endif
+ !quadplane.allow_stick_mixing() ||
#endif // HAL_QUADPLANE_ENABLED
control_mode == &mode_training) {
return;
@@ -268,7 +275,7 @@ void Plane::stabilize_stick_mixing_fbw()
nav_roll_cd += roll_input * roll_limit_cd;
nav_roll_cd = constrain_int32(nav_roll_cd, -roll_limit_cd, roll_limit_cd);
- if ((control_mode == &mode_loiter) && (plane.g2.flight_options & FlightOptions::ENABLE_LOITER_ALT_CONTROL)) {
+ if ((control_mode == &mode_loiter) && (plane.flight_option_enabled(FlightOptions::ENABLE_LOITER_ALT_CONTROL))) {
// loiter is using altitude control based on the pitch stick, don't use it again here
return;
}
@@ -300,38 +307,57 @@ void Plane::stabilize_stick_mixing_fbw()
*/
void Plane::stabilize_yaw()
{
+ bool ground_steering = false;
if (landing.is_flaring()) {
// in flaring then enable ground steering
- steering_control.ground_steering = true;
+ ground_steering = true;
} else {
// otherwise use ground steering when no input control and we
// are below the GROUND_STEER_ALT
- steering_control.ground_steering = (channel_roll->get_control_in() == 0 &&
+ ground_steering = (channel_roll->get_control_in() == 0 &&
fabsf(relative_altitude) < g.ground_steer_alt);
if (!landing.is_ground_steering_allowed()) {
// don't use ground steering on landing approach
- steering_control.ground_steering = false;
+ ground_steering = false;
}
}
/*
- first calculate steering_control.steering for a nose or tail
+ first calculate steering for a nose or tail
wheel. We use "course hold" mode for the rudder when either performing
a flare (when the wings are held level) or when in course hold in
FBWA mode (when we are below GROUND_STEER_ALT)
*/
+ float steering_output = 0.0;
if (landing.is_flaring() ||
- (steer_state.hold_course_cd != -1 && steering_control.ground_steering)) {
- calc_nav_yaw_course();
- } else if (steering_control.ground_steering) {
- calc_nav_yaw_ground();
+ (steer_state.hold_course_cd != -1 && ground_steering)) {
+ steering_output = calc_nav_yaw_course();
+ } else if (ground_steering) {
+ steering_output = calc_nav_yaw_ground();
}
/*
- now calculate steering_control.rudder for the rudder
+ now calculate rudder for the rudder
*/
- calc_nav_yaw_coordinated();
+ const float rudder_output = calc_nav_yaw_coordinated();
+
+ if (!ground_steering) {
+ // Not doing ground steering, output rudder on steering channel
+ SRV_Channels::set_output_scaled(SRV_Channel::k_rudder, rudder_output);
+ SRV_Channels::set_output_scaled(SRV_Channel::k_steering, rudder_output);
+
+ } else if (!SRV_Channels::function_assigned(SRV_Channel::k_steering)) {
+ // Ground steering active but no steering output configured, output steering on rudder channel
+ SRV_Channels::set_output_scaled(SRV_Channel::k_rudder, steering_output);
+ SRV_Channels::set_output_scaled(SRV_Channel::k_steering, steering_output);
+
+ } else {
+ // Ground steering with both steering and rudder channels
+ SRV_Channels::set_output_scaled(SRV_Channel::k_rudder, rudder_output);
+ SRV_Channels::set_output_scaled(SRV_Channel::k_steering, steering_output);
+ }
+
}
/*
@@ -339,35 +365,21 @@ void Plane::stabilize_yaw()
*/
void Plane::stabilize()
{
- if (control_mode == &mode_manual) {
- // reset steering controls
- steer_state.locked_course = false;
- steer_state.locked_course_err = 0;
- return;
- }
-
uint32_t now = AP_HAL::millis();
- bool allow_stick_mixing = true;
#if HAL_QUADPLANE_ENABLED
if (quadplane.available()) {
- quadplane.transition->set_FW_roll_pitch(nav_pitch_cd, nav_roll_cd, allow_stick_mixing);
+ quadplane.transition->set_FW_roll_pitch(nav_pitch_cd, nav_roll_cd);
}
#endif
if (now - last_stabilize_ms > 2000) {
- // if we haven't run the rate controllers for 2 seconds then
- // reset the integrators
- rollController.reset_I();
- pitchController.reset_I();
- yawController.reset_I();
-
- // and reset steering controls
- steer_state.locked_course = false;
- steer_state.locked_course_err = 0;
+ // if we haven't run the rate controllers for 2 seconds then reset
+ control_mode->reset_controllers();
}
last_stabilize_ms = now;
- if (control_mode == &mode_training) {
+ if (control_mode == &mode_training ||
+ control_mode == &mode_manual) {
plane.control_mode->run();
#if AP_SCRIPTING_ENABLED
} else if (nav_scripting_active()) {
@@ -377,47 +389,20 @@ void Plane::stabilize()
const float elevator = pitchController.get_rate_out(nav_scripting.pitch_rate_dps, speed_scaler);
SRV_Channels::set_output_scaled(SRV_Channel::k_aileron, aileron);
SRV_Channels::set_output_scaled(SRV_Channel::k_elevator, elevator);
+ float rudder = 0;
if (yawController.rate_control_enabled()) {
- float rudder = nav_scripting.rudder_offset_pct * 45;
+ rudder = nav_scripting.rudder_offset_pct * 45;
if (nav_scripting.run_yaw_rate_controller) {
rudder += yawController.get_rate_out(nav_scripting.yaw_rate_dps, speed_scaler, false);
} else {
yawController.reset_I();
}
- steering_control.rudder = rudder;
- }
-#endif
- } else if (control_mode == &mode_acro) {
- plane.control_mode->run();
- } else if (control_mode == &mode_stabilize) {
- stabilize_roll();
- stabilize_pitch();
- if (allow_stick_mixing) {
- stabilize_stick_mixing_direct();
- }
- stabilize_yaw();
-#if HAL_QUADPLANE_ENABLED
- } else if (control_mode->is_vtol_mode() && !quadplane.tailsitter.in_vtol_transition(now)) {
- // run controlers specific to this mode
- plane.control_mode->run();
-
- // we also stabilize using fixed wing surfaces
- if (plane.control_mode->mode_number() == Mode::Number::QACRO) {
- plane.mode_acro.run();
- } else {
- stabilize_roll();
- stabilize_pitch();
}
+ SRV_Channels::set_output_scaled(SRV_Channel::k_rudder, rudder);
+ SRV_Channels::set_output_scaled(SRV_Channel::k_steering, rudder);
#endif
} else {
- // Direct stick mixing functionality has been removed, so as not to remove all stick mixing from the user completely
- // the old direct option is now used to enable fbw mixing, this is easier than doing a param conversion.
- if (allow_stick_mixing && ((g.stick_mixing == StickMixing::FBW) || (g.stick_mixing == StickMixing::DIRECT_REMOVED))) {
- stabilize_stick_mixing_fbw();
- }
- stabilize_roll();
- stabilize_pitch();
- stabilize_yaw();
+ plane.control_mode->run();
}
/*
@@ -453,14 +438,6 @@ void Plane::calc_throttle()
}
float commanded_throttle = TECS_controller.get_throttle_demand();
-
- // Received an external msg that guides throttle in the last 3 seconds?
- if (control_mode->is_guided_mode() &&
- plane.guided_state.last_forced_throttle_ms > 0 &&
- millis() - plane.guided_state.last_forced_throttle_ms < 3000) {
- commanded_throttle = plane.guided_state.forced_throttle;
- }
-
SRV_Channels::set_output_scaled(SRV_Channel::k_throttle, commanded_throttle);
}
@@ -471,7 +448,7 @@ void Plane::calc_throttle()
/*
calculate yaw control for coordinated flight
*/
-void Plane::calc_nav_yaw_coordinated()
+int16_t Plane::calc_nav_yaw_coordinated()
{
const float speed_scaler = get_speed_scaler();
bool disable_integrator = false;
@@ -505,35 +482,35 @@ void Plane::calc_nav_yaw_coordinated()
commanded_rudder += rudder_in;
}
- steering_control.rudder = constrain_int16(commanded_rudder, -4500, 4500);
-
if (!using_rate_controller) {
/*
When not running the yaw rate controller, we need to reset the rate
*/
yawController.reset_rate_PID();
}
+
+ return constrain_int16(commanded_rudder, -4500, 4500);
}
/*
calculate yaw control for ground steering with specific course
*/
-void Plane::calc_nav_yaw_course(void)
+int16_t Plane::calc_nav_yaw_course(void)
{
// holding a specific navigation course on the ground. Used in
// auto-takeoff and landing
int32_t bearing_error_cd = nav_controller->bearing_error_cd();
- steering_control.steering = steerController.get_steering_out_angle_error(bearing_error_cd);
+ int16_t steering = steerController.get_steering_out_angle_error(bearing_error_cd);
if (stick_mixing_enabled()) {
- steering_control.steering = channel_rudder->stick_mixing(steering_control.steering);
+ steering = channel_rudder->stick_mixing(steering);
}
- steering_control.steering = constrain_int16(steering_control.steering, -4500, 4500);
+ return constrain_int16(steering, -4500, 4500);
}
/*
calculate yaw control for ground steering
*/
-void Plane::calc_nav_yaw_ground(void)
+int16_t Plane::calc_nav_yaw_ground(void)
{
if (gps.ground_speed() < 1 &&
is_zero(get_throttle_input()) &&
@@ -542,8 +519,7 @@ void Plane::calc_nav_yaw_ground(void)
// manual rudder control while still
steer_state.locked_course = false;
steer_state.locked_course_err = 0;
- steering_control.steering = rudder_input();
- return;
+ return rudder_input();
}
// if we haven't been steering for 1s then clear locked course
@@ -570,15 +546,16 @@ void Plane::calc_nav_yaw_ground(void)
}
}
+ int16_t steering;
if (!steer_state.locked_course) {
// use a rate controller at the pilot specified rate
- steering_control.steering = steerController.get_steering_out_rate(steer_rate);
+ steering = steerController.get_steering_out_rate(steer_rate);
} else {
// use a error controller on the summed error
int32_t yaw_error_cd = -ToDeg(steer_state.locked_course_err)*100;
- steering_control.steering = steerController.get_steering_out_angle_error(yaw_error_cd);
+ steering = steerController.get_steering_out_angle_error(yaw_error_cd);
}
- steering_control.steering = constrain_int16(steering_control.steering, -4500, 4500);
+ return constrain_int16(steering, -4500, 4500);
}
@@ -587,17 +564,7 @@ void Plane::calc_nav_yaw_ground(void)
*/
void Plane::calc_nav_pitch()
{
- // Calculate the Pitch of the plane
- // --------------------------------
int32_t commanded_pitch = TECS_controller.get_pitch_demand();
-
- // Received an external msg that guides roll in the last 3 seconds?
- if (control_mode->is_guided_mode() &&
- plane.guided_state.last_forced_rpy_ms.y > 0 &&
- millis() - plane.guided_state.last_forced_rpy_ms.y < 3000) {
- commanded_pitch = plane.guided_state.forced_rpy_cd.y;
- }
-
nav_pitch_cd = constrain_int32(commanded_pitch, pitch_limit_min_cd, aparm.pitch_limit_max_cd.get());
}
@@ -608,43 +575,6 @@ void Plane::calc_nav_pitch()
void Plane::calc_nav_roll()
{
int32_t commanded_roll = nav_controller->nav_roll_cd();
-
- // Received an external msg that guides roll in the last 3 seconds?
- if (control_mode->is_guided_mode() &&
- plane.guided_state.last_forced_rpy_ms.x > 0 &&
- millis() - plane.guided_state.last_forced_rpy_ms.x < 3000) {
- commanded_roll = plane.guided_state.forced_rpy_cd.x;
-#if OFFBOARD_GUIDED == ENABLED
- // guided_state.target_heading is radians at this point between -pi and pi ( defaults to -4 )
- } else if ((control_mode == &mode_guided) && (guided_state.target_heading_type != GUIDED_HEADING_NONE) ) {
- uint32_t tnow = AP_HAL::millis();
- float delta = (tnow - guided_state.target_heading_time_ms) * 1e-3f;
- guided_state.target_heading_time_ms = tnow;
-
- float error = 0.0f;
- if (guided_state.target_heading_type == GUIDED_HEADING_HEADING) {
- error = wrap_PI(guided_state.target_heading - AP::ahrs().yaw);
- } else {
- Vector2f groundspeed = AP::ahrs().groundspeed_vector();
- error = wrap_PI(guided_state.target_heading - atan2f(-groundspeed.y, -groundspeed.x) + M_PI);
- }
-
- float bank_limit = degrees(atanf(guided_state.target_heading_accel_limit/GRAVITY_MSS)) * 1e2f;
-
- g2.guidedHeading.update_error(error, delta); // push error into AC_PID , possible improvement is to use update_all instead.?
-
- float i = g2.guidedHeading.get_i(); // get integrator TODO
- if (((is_negative(error) && !guided_state.target_heading_limit_low) || (is_positive(error) && !guided_state.target_heading_limit_high))) {
- i = g2.guidedHeading.get_i();
- }
-
- float desired = g2.guidedHeading.get_p() + i + g2.guidedHeading.get_d();
- guided_state.target_heading_limit_low = (desired <= -bank_limit);
- guided_state.target_heading_limit_high = (desired >= bank_limit);
- commanded_roll = constrain_float(desired, -bank_limit, bank_limit);
-#endif // OFFBOARD_GUIDED == ENABLED
- }
-
nav_roll_cd = constrain_int32(commanded_roll, -roll_limit_cd, roll_limit_cd);
update_load_factor();
}
diff --git a/ArduPlane/GCS_Mavlink.cpp b/ArduPlane/GCS_Mavlink.cpp
index b75509936d17e9..99160eccea0c7e 100644
--- a/ArduPlane/GCS_Mavlink.cpp
+++ b/ArduPlane/GCS_Mavlink.cpp
@@ -133,7 +133,7 @@ void GCS_MAVLINK_Plane::send_attitude() const
float p = ahrs.pitch;
float y = ahrs.yaw;
- if (!(plane.g2.flight_options & FlightOptions::GCS_REMOVE_TRIM_PITCH_CD)) {
+ if (!(plane.flight_option_enabled(FlightOptions::GCS_REMOVE_TRIM_PITCH_CD))) {
p -= radians(plane.g.pitch_trim_cd * 0.01f);
}
@@ -711,7 +711,7 @@ void GCS_MAVLINK_Plane::packetReceived(const mavlink_status_t &status,
#if HAL_ADSB_ENABLED
plane.avoidance_adsb.handle_msg(msg);
#endif
-#if AP_SCRIPTING_ENABLED
+#if AP_SCRIPTING_ENABLED && AP_FOLLOW_ENABLED
// pass message to follow library
plane.g2.follow.handle_msg(msg);
#endif
@@ -950,7 +950,7 @@ MAV_RESULT GCS_MAVLINK_Plane::handle_command_int_guided_slew_commands(const mavl
}
-MAV_RESULT GCS_MAVLINK_Plane::handle_command_int_packet(const mavlink_command_int_t &packet)
+MAV_RESULT GCS_MAVLINK_Plane::handle_command_int_packet(const mavlink_command_int_t &packet, const mavlink_message_t &msg)
{
switch(packet.command) {
@@ -963,22 +963,22 @@ MAV_RESULT GCS_MAVLINK_Plane::handle_command_int_packet(const mavlink_command_in
case MAV_CMD_GUIDED_CHANGE_HEADING:
return handle_command_int_guided_slew_commands(packet);
+#if AP_SCRIPTING_ENABLED && AP_FOLLOW_ENABLED
case MAV_CMD_DO_FOLLOW:
-#if AP_SCRIPTING_ENABLED
// param1: sysid of target to follow
if ((packet.param1 > 0) && (packet.param1 <= 255)) {
plane.g2.follow.set_target_sysid((uint8_t)packet.param1);
return MAV_RESULT_ACCEPTED;
}
+ return MAV_RESULT_DENIED;
#endif
- return MAV_RESULT_FAILED;
-
+
default:
- return GCS_MAVLINK::handle_command_int_packet(packet);
+ return GCS_MAVLINK::handle_command_int_packet(packet, msg);
}
}
-MAV_RESULT GCS_MAVLINK_Plane::handle_command_long_packet(const mavlink_command_long_t &packet)
+MAV_RESULT GCS_MAVLINK_Plane::handle_command_long_packet(const mavlink_command_long_t &packet, const mavlink_message_t &msg)
{
switch(packet.command) {
@@ -1102,18 +1102,8 @@ MAV_RESULT GCS_MAVLINK_Plane::handle_command_long_packet(const mavlink_command_l
return MAV_RESULT_ACCEPTED;
#endif
-#if AP_SCRIPTING_ENABLED
- case MAV_CMD_DO_FOLLOW:
- // param1: sysid of target to follow
- if ((packet.param1 > 0) && (packet.param1 <= 255)) {
- plane.g2.follow.set_target_sysid((uint8_t)packet.param1);
- return MAV_RESULT_ACCEPTED;
- }
- return MAV_RESULT_FAILED;
-#endif
-
default:
- return GCS_MAVLINK::handle_command_long_packet(packet);
+ return GCS_MAVLINK::handle_command_long_packet(packet, msg);
}
}
@@ -1316,6 +1306,7 @@ MAV_RESULT GCS_MAVLINK_Plane::handle_command_do_set_mission_current(const mavlin
return result;
}
+#if AP_MAVLINK_MISSION_SET_CURRENT_ENABLED
void GCS_MAVLINK_Plane::handle_mission_set_current(AP_Mission &mission, const mavlink_message_t &msg)
{
// if you change this you must change handle_command_do_set_mission_current
@@ -1325,6 +1316,7 @@ void GCS_MAVLINK_Plane::handle_mission_set_current(AP_Mission &mission, const ma
plane.mission.resume();
}
}
+#endif
uint64_t GCS_MAVLINK_Plane::capabilities() const
{
diff --git a/ArduPlane/GCS_Mavlink.h b/ArduPlane/GCS_Mavlink.h
index 849efe8a17306b..7d391fcc5acbe1 100644
--- a/ArduPlane/GCS_Mavlink.h
+++ b/ArduPlane/GCS_Mavlink.h
@@ -11,18 +11,21 @@ class GCS_MAVLINK_Plane : public GCS_MAVLINK
using GCS_MAVLINK::GCS_MAVLINK;
+ uint8_t sysid_my_gcs() const override;
+
protected:
uint32_t telem_delay() const override;
+#if AP_MAVLINK_MISSION_SET_CURRENT_ENABLED
void handle_mission_set_current(AP_Mission &mission, const mavlink_message_t &msg) override;
+#endif
- uint8_t sysid_my_gcs() const override;
bool sysid_enforce() const override;
MAV_RESULT handle_command_preflight_calibration(const mavlink_command_long_t &packet, const mavlink_message_t &msg) override;
- MAV_RESULT handle_command_int_packet(const mavlink_command_int_t &packet) override;
- MAV_RESULT handle_command_long_packet(const mavlink_command_long_t &packet) override;
+ MAV_RESULT handle_command_int_packet(const mavlink_command_int_t &packet, const mavlink_message_t &msg) override;
+ MAV_RESULT handle_command_long_packet(const mavlink_command_long_t &packet, const mavlink_message_t &msg) override;
MAV_RESULT handle_command_do_set_mission_current(const mavlink_command_long_t &packet) override;
void send_position_target_global_int() override;
diff --git a/ArduPlane/Log.cpp b/ArduPlane/Log.cpp
index f8b1a3ac576491..5925050cb0795c 100644
--- a/ArduPlane/Log.cpp
+++ b/ArduPlane/Log.cpp
@@ -62,6 +62,9 @@ void Plane::Log_Write_FullRate(void)
if (should_log(MASK_LOG_ATTITUDE_FULLRATE)) {
Log_Write_Attitude();
}
+ if (should_log(MASK_LOG_NOTCH_FULLRATE)) {
+ AP::ins().write_notch_log_messages();
+ }
}
@@ -110,6 +113,7 @@ void Plane::Log_Write_Control_Tuning()
logger.WriteBlock(&pkt, sizeof(pkt));
}
+#if OFFBOARD_GUIDED == ENABLED
struct PACKED log_OFG_Guided {
LOG_PACKET_HEADER;
uint64_t time_us;
@@ -125,7 +129,6 @@ struct PACKED log_OFG_Guided {
// Write a OFG Guided packet.
void Plane::Log_Write_OFG_Guided()
{
-#if OFFBOARD_GUIDED == ENABLED
struct log_OFG_Guided pkt = {
LOG_PACKET_HEADER_INIT(LOG_OFG_MSG),
time_us : AP_HAL::micros64(),
@@ -138,8 +141,8 @@ void Plane::Log_Write_OFG_Guided()
target_heading_limit : guided_state.target_heading_accel_limit
};
logger.WriteBlock(&pkt, sizeof(pkt));
-#endif
}
+#endif
struct PACKED log_Nav_Tuning {
LOG_PACKET_HEADER;
@@ -219,6 +222,7 @@ struct PACKED log_AETR {
float throttle;
float rudder;
float flap;
+ float steering;
float speed_scaler;
};
@@ -232,6 +236,7 @@ void Plane::Log_Write_AETR()
,throttle : SRV_Channels::get_output_scaled(SRV_Channel::k_throttle)
,rudder : SRV_Channels::get_output_scaled(SRV_Channel::k_rudder)
,flap : SRV_Channels::get_slew_limited_output_scaled(SRV_Channel::k_flap_auto)
+ ,steering : SRV_Channels::get_output_scaled(SRV_Channel::k_steering)
,speed_scaler : get_speed_scaler(),
};
@@ -374,8 +379,8 @@ const struct LogStructure Plane::log_structure[] = {
// @Field: CRt: climb rate
// @Field: TMix: transition throttle mix value
// @Field: Sscl: speed scalar for tailsitter control surfaces
-// @Field: Trn: Transistion state
-// @Field: Ast: Q assist active state
+// @Field: Trn: Transition state: 0-AirspeedWait,1-Timer,2-Done / TailSitter: 0-FW Wait,1-VTOL Wait,2-Done
+// @Field: Ast: Q assist active
#if HAL_QUADPLANE_ENABLED
{ LOG_QTUN_MSG, sizeof(QuadPlane::log_QControl_Tuning),
"QTUN", "QffffffeccffBB", "TimeUS,ThI,ABst,ThO,ThH,DAlt,Alt,BAlt,DCRt,CRt,TMix,Sscl,Trn,Ast", "s----mmmnn----", "F----00000-0--" , true },
@@ -422,15 +427,17 @@ const struct LogStructure Plane::log_structure[] = {
// @LoggerMessage: AETR
// @Description: Normalised pre-mixer control surface outputs
// @Field: TimeUS: Time since system startup
-// @Field: Ail: Pre-mixer value for aileron output (between -4500 to 4500)
-// @Field: Elev: Pre-mixer value for elevator output (between -4500 to 4500)
-// @Field: Thr: Pre-mixer value for throttle output (between -4500 to 4500)
-// @Field: Rudd: Pre-mixer value for rudder output (between -4500 to 4500)
-// @Field: Flap: Pre-mixer value for flaps output (between -4500 to 4500)
+// @Field: Ail: Pre-mixer value for aileron output (between -4500 and 4500)
+// @Field: Elev: Pre-mixer value for elevator output (between -4500 and 4500)
+// @Field: Thr: Pre-mixer value for throttle output (between -100 and 100)
+// @Field: Rudd: Pre-mixer value for rudder output (between -4500 and 4500)
+// @Field: Flap: Pre-mixer value for flaps output (between 0 and 100)
+// @Field: Steer: Pre-mixer value for steering output (between -4500 and 4500)
// @Field: SS: Surface movement / airspeed scaling value
{ LOG_AETR_MSG, sizeof(log_AETR),
- "AETR", "Qffffff", "TimeUS,Ail,Elev,Thr,Rudd,Flap,SS", "s------", "F------" , true },
+ "AETR", "Qfffffff", "TimeUS,Ail,Elev,Thr,Rudd,Flap,Steer,SS", "s-------", "F-------" , true },
+#if OFFBOARD_GUIDED == ENABLED
// @LoggerMessage: OFG
// @Description: OFfboard-Guided - an advanced version of GUIDED for companion computers that includes rate/s.
// @Field: TimeUS: Time since system startup
@@ -443,6 +450,7 @@ const struct LogStructure Plane::log_structure[] = {
// @Field: HdgA: target heading lim
{ LOG_OFG_MSG, sizeof(log_OFG_Guided),
"OFG", "QffffBff", "TimeUS,Arsp,ArspA,Alt,AltA,AltF,Hdg,HdgA", "s-------", "F-------" , true },
+#endif
};
void Plane::Log_Write_Vehicle_Startup_Messages()
diff --git a/ArduPlane/Parameters.cpp b/ArduPlane/Parameters.cpp
index 83c1924e4287b2..73f0d4a65a420d 100644
--- a/ArduPlane/Parameters.cpp
+++ b/ArduPlane/Parameters.cpp
@@ -38,6 +38,14 @@ const AP_Param::Info Plane::var_info[] = {
// @User: Standard
ASCALAR(autotune_level, "AUTOTUNE_LEVEL", 6),
+ // @Param: AUTOTUNE_OPTIONS
+ // @DisplayName: Autotune options bitmask
+ // @Description: Autotune specific options
+ // @Bitmask: 0: Disable FLTD update
+ // @Bitmask: 1: Disable FLTT update
+ // @User: Advanced
+ ASCALAR(autotune_options, "AUTOTUNE_OPTIONS", 0),
+
// @Param: TELEM_DELAY
// @DisplayName: Telemetry startup delay
// @Description: The amount of time (in seconds) to delay radio telemetry to prevent an Xbee bricking on power up
@@ -424,8 +432,8 @@ const AP_Param::Info Plane::var_info[] = {
// @Param: FS_LONG_ACTN
// @DisplayName: Long failsafe action
- // @Description: The action to take on a long (FS_LONG_TIMEOUT seconds) failsafe event. If the aircraft was in a stabilization or manual mode when failsafe started and a long failsafe occurs then it will change to RTL mode if FS_LONG_ACTN is 0 or 1, and will change to FBWA if FS_LONG_ACTN is set to 2. If the aircraft was in an auto mode (such as AUTO or GUIDED) when the failsafe started then it will continue in the auto mode if FS_LONG_ACTN is set to 0, will change to RTL mode if FS_LONG_ACTN is set to 1 and will change to FBWA mode if FS_LONG_ACTN is set to 2. If FS_LONG_ACTION is set to 3, the parachute will be deployed (make sure the chute is configured and enabled).
- // @Values: 0:Continue,1:ReturnToLaunch,2:Glide,3:Deploy Parachute
+ // @Description: The action to take on a long (FS_LONG_TIMEOUT seconds) failsafe event. If the aircraft was in a stabilization or manual mode when failsafe started and a long failsafe occurs then it will change to RTL mode if FS_LONG_ACTN is 0 or 1, and will change to FBWA if FS_LONG_ACTN is set to 2. If the aircraft was in an auto mode (such as AUTO or GUIDED) when the failsafe started then it will continue in the auto mode if FS_LONG_ACTN is set to 0, will change to RTL mode if FS_LONG_ACTN is set to 1 and will change to FBWA mode if FS_LONG_ACTN is set to 2. If FS_LONG_ACTN is set to 3, the parachute will be deployed (make sure the chute is configured and enabled). If FS_LONG_ACTN is set to 4 the aircraft will switch to mode AUTO with the current waypoint if it is not already in mode AUTO, unless it is in the middle of a landing sequence.
+ // @Values: 0:Continue,1:ReturnToLaunch,2:Glide,3:Deploy Parachute,4:Auto
// @User: Standard
GSCALAR(fs_action_long, "FS_LONG_ACTN", FS_ACTION_LONG_CONTINUE),
@@ -605,17 +613,10 @@ const AP_Param::Info Plane::var_info[] = {
// @User: Standard
GSCALAR(dspoiler_rud_rate, "DSPOILR_RUD_RATE", DSPOILR_RUD_RATE_DEFAULT),
- // @Param: SYS_NUM_RESETS
- // @DisplayName: Num Resets
- // @Description: Number of APM board resets
- // @ReadOnly: True
- // @User: Advanced
- GSCALAR(num_resets, "SYS_NUM_RESETS", 0),
-
// @Param: LOG_BITMASK
// @DisplayName: Log bitmask
// @Description: Bitmap of what on-board log types to enable. This value is made up of the sum of each of the log types you want to be saved. It is usually best just to enable all basic log types by setting this to 65535.
- // @Bitmask: 0:Fast Attitude,1:Medium Attitude,2:GPS,3:Performance,4:Control Tuning,5:Navigation Tuning,7:IMU,8:Mission Commands,9:Battery Monitor,10:Compass,11:TECS,12:Camera,13:RC Input-Output,14:Rangefinder,19:Raw IMU,20:Fullrate Attitude,21:Video Stabilization
+ // @Bitmask: 0:Fast Attitude,1:Medium Attitude,2:GPS,3:Performance,4:Control Tuning,5:Navigation Tuning,7:IMU,8:Mission Commands,9:Battery Monitor,10:Compass,11:TECS,12:Camera,13:RC Input-Output,14:Rangefinder,19:Raw IMU,20:Fullrate Attitude,21:Video Stabilization,22:Fullrate Notch
// @User: Advanced
GSCALAR(log_bitmask, "LOG_BITMASK", DEFAULT_LOG_BITMASK),
@@ -754,9 +755,11 @@ const AP_Param::Info Plane::var_info[] = {
// @Path: AP_Arming.cpp,../libraries/AP_Arming/AP_Arming.cpp
GOBJECT(arming, "ARMING_", AP_Arming_Plane),
+#if AP_RELAY_ENABLED
// @Group: RELAY_
// @Path: ../libraries/AP_Relay/AP_Relay.cpp
GOBJECT(relay, "RELAY_", AP_Relay),
+#endif
#if PARACHUTE == ENABLED
// @Group: CHUTE_
@@ -1092,6 +1095,7 @@ const AP_Param::GroupInfo ParametersG2::var_info[] = {
// @Bitmask: 10: Adjust mid-throttle to be TRIM_THROTTLE in non-auto throttle modes except MANUAL
// @Bitmask: 11: Disable suppression of fixed wing rate gains in ground mode
// @Bitmask: 12: Enable FBWB style loiter altitude control
+ // @Bitmask: 13: Indicate takeoff waiting for neutral rudder with flight control surfaces
// @User: Advanced
AP_GROUPINFO("FLIGHT_OPTIONS", 13, ParametersG2, flight_options, 0),
@@ -1239,7 +1243,7 @@ const AP_Param::GroupInfo ParametersG2::var_info[] = {
// @Bitmask: 0: Servo 1, 1: Servo 2, 2: Servo 3, 3: Servo 4, 4: Servo 5, 5: Servo 6, 6: Servo 7, 7: Servo 8, 8: Servo 9, 9: Servo 10, 10: Servo 11, 11: Servo 12, 12: Servo 13, 13: Servo 14, 14: Servo 15
AP_GROUPINFO("ONESHOT_MASK", 32, ParametersG2, oneshot_mask, 0),
-#if AP_SCRIPTING_ENABLED
+#if AP_SCRIPTING_ENABLED && AP_FOLLOW_ENABLED
// @Group: FOLL
// @Path: ../libraries/AP_Follow/AP_Follow.cpp
AP_SUBGROUPINFO(follow, "FOLL", 33, ParametersG2, AP_Follow),
@@ -1251,17 +1255,12 @@ const AP_Param::GroupInfo ParametersG2::var_info[] = {
// @Bitmask: 0:Roll,1:Pitch,2:Yaw
// @User: Standard
AP_GROUPINFO("AUTOTUNE_AXES", 34, ParametersG2, axis_bitmask, 7),
-
-
AP_GROUPEND
};
ParametersG2::ParametersG2(void) :
unused_integer{1}
-#if AP_ICENGINE_ENABLED
- ,ice_control(plane.rpm_sensor)
-#endif
#if HAL_SOARING_ENABLED
,soaring_controller(plane.TECS_controller, plane.aparm)
#endif
diff --git a/ArduPlane/Parameters.h b/ArduPlane/Parameters.h
index db02c44565e8be..3045ff8eda7e02 100644
--- a/ArduPlane/Parameters.h
+++ b/ArduPlane/Parameters.h
@@ -43,7 +43,7 @@ class Parameters {
//
k_param_format_version = 0,
k_param_software_type, // unused;
- k_param_num_resets,
+ k_param_num_resets, // unused
k_param_NavEKF2,
k_param_g2,
k_param_avoidance_adsb,
@@ -356,6 +356,7 @@ class Parameters {
k_param_fence, // vehicle fence - unused
k_param_acro_yaw_rate,
k_param_takeoff_throttle_max_t,
+ k_param_autotune_options,
};
AP_Int16 format_version;
@@ -434,7 +435,6 @@ class Parameters {
AP_Float mixing_gain;
AP_Int16 mixing_offset;
AP_Int16 dspoiler_rud_rate;
- AP_Int16 num_resets;
AP_Int32 log_bitmask;
AP_Int32 RTL_altitude_cm;
AP_Int16 pitch_trim_cd;
@@ -551,7 +551,7 @@ class ParametersG2 {
AC_PID guidedHeading{5000.0, 0.0, 0.0, 0 , 10.0, 5.0, 5.0 , 5.0 , 0.2};
#endif
-#if AP_SCRIPTING_ENABLED
+#if AP_SCRIPTING_ENABLED && AP_FOLLOW_ENABLED
AP_Follow follow;
#endif
diff --git a/ArduPlane/Plane.h b/ArduPlane/Plane.h
index 087e86cd414ab2..5369536a434466 100644
--- a/ArduPlane/Plane.h
+++ b/ArduPlane/Plane.h
@@ -83,6 +83,10 @@
#include
#include // Landing Gear library
#include
+#include
+#if AP_EXTERNAL_CONTROL_ENABLED
+#include
+#endif
#include "GCS_Mavlink.h"
#include "GCS_Plane.h"
@@ -190,6 +194,7 @@ class Plane : public AP_Vehicle {
// flight modes convenience array
AP_Int8 *flight_modes = &g.flight_mode1;
+ const uint8_t num_flight_modes = 6;
AP_FixedWing::Rangefinder_State rangefinder_state;
@@ -210,16 +215,6 @@ class Plane : public AP_Vehicle {
bool training_manual_roll; // user has manual roll control
bool training_manual_pitch; // user has manual pitch control
- /*
- keep steering and rudder control separated until we update servos,
- to allow for a separate wheel servo from rudder servo
- */
- struct {
- bool ground_steering; // are we doing ground steering?
- int16_t steering; // value for nose/tail wheel
- int16_t rudder; // value for rudder
- } steering_control;
-
// should throttle be pass-thru in guided?
bool guided_throttle_passthru;
@@ -227,6 +222,9 @@ class Plane : public AP_Vehicle {
// external failsafe boards during baro and airspeed calibration
bool in_calibration;
+ // are we currently in long failsafe but have postponed it in MODE TAKEOFF until min level alt is reached
+ bool long_failsafe_pending;
+
// GCS selection
GCS_Plane _gcs; // avoid using this; use gcs()
GCS_Plane &gcs() { return _gcs; }
@@ -386,6 +384,7 @@ class Plane : public AP_Vehicle {
// Ground speed
// The amount current ground speed is below min ground speed. Centimeters per second
int32_t groundspeed_undershoot;
+ bool groundspeed_undershoot_is_valid;
// Difference between current altitude and desired altitude. Centimeters
int32_t altitude_error_cm;
@@ -401,11 +400,13 @@ class Plane : public AP_Vehicle {
struct {
uint32_t last_tkoff_arm_time;
uint32_t last_check_ms;
+ uint32_t rudder_takeoff_warn_ms;
uint32_t last_report_ms;
bool launchTimerStarted;
uint8_t accel_event_counter;
uint32_t accel_event_ms;
uint32_t start_time_ms;
+ bool waiting_for_rudder_neutral;
} takeoff_state;
// ground steering controller state
@@ -503,6 +504,9 @@ class Plane : public AP_Vehicle {
// how much correction have we added for terrain data
float terrain_correction;
+
+ // last home altitude for detecting changes
+ int32_t last_home_alt_cm;
} auto_state;
#if AP_SCRIPTING_ENABLED
@@ -686,6 +690,9 @@ class Plane : public AP_Vehicle {
// The amount of time we should stay in a loiter for the Loiter Time command. Milliseconds.
uint32_t time_max_ms;
+
+ // current value of loiter radius in metres used by the controller
+ float radius;
} loiter;
// Conditional command
@@ -767,6 +774,11 @@ class Plane : public AP_Vehicle {
AP_Param param_loader {var_info};
+ // dummy implementation of external control
+#if AP_EXTERNAL_CONTROL_ENABLED
+ AP_ExternalControl external_control;
+#endif
+
static const AP_Scheduler::Task scheduler_tasks[];
static const AP_Param::Info var_info[];
@@ -859,12 +871,11 @@ class Plane : public AP_Vehicle {
float stabilize_roll_get_roll_out();
void stabilize_pitch();
float stabilize_pitch_get_pitch_out();
- void stabilize_stick_mixing_direct();
void stabilize_stick_mixing_fbw();
void stabilize_yaw();
- void calc_nav_yaw_coordinated();
- void calc_nav_yaw_course(void);
- void calc_nav_yaw_ground(void);
+ int16_t calc_nav_yaw_coordinated();
+ int16_t calc_nav_yaw_course(void);
+ int16_t calc_nav_yaw_ground(void);
// Log.cpp
uint32_t last_log_fast_ms;
@@ -966,7 +977,6 @@ class Plane : public AP_Vehicle {
// control_modes.cpp
void read_control_switch();
uint8_t readSwitch(void) const;
- void reset_control_switch();
void autotune_start(void);
void autotune_restore(void);
void autotune_enable(bool enable);
@@ -974,6 +984,10 @@ class Plane : public AP_Vehicle {
bool mode_allows_autotuning(void);
uint8_t get_mode() const override { return (uint8_t)control_mode->mode_number(); }
Mode *mode_from_mode_num(const enum Mode::Number num);
+ bool current_mode_requires_mission() const override {
+ return control_mode == &mode_auto;
+ }
+
bool autotuning;
// events.cpp
@@ -1021,11 +1035,13 @@ class Plane : public AP_Vehicle {
void update_fly_forward(void);
void update_flight_stage();
void set_flight_stage(AP_FixedWing::FlightStage fs);
+ bool flight_option_enabled(FlightOptions flight_option) const;
// navigation.cpp
void loiter_angle_reset(void);
void loiter_angle_update(void);
void navigate();
+ void check_home_alt_change(void);
void calc_airspeed_errors();
float mode_auto_target_airspeed_cm();
void calc_gndspeed_undershoot();
@@ -1064,6 +1080,7 @@ class Plane : public AP_Vehicle {
bool should_log(uint32_t mask);
int8_t throttle_percentage(void);
void notify_mode(const Mode& mode);
+ bool gcs_mode_enabled(const Mode::Number mode_num) const;
// takeoff.cpp
bool auto_takeoff_check(void);
@@ -1079,7 +1096,6 @@ class Plane : public AP_Vehicle {
// servos.cpp
void set_servos_idle(void);
void set_servos();
- void set_servos_manual_passthrough(void);
void set_servos_controlled(void);
void set_servos_old_elevons(void);
void set_servos_flaps(void);
@@ -1099,6 +1115,7 @@ class Plane : public AP_Vehicle {
void channel_function_mixer(SRV_Channel::Aux_servo_function_t func1_in, SRV_Channel::Aux_servo_function_t func2_in,
SRV_Channel::Aux_servo_function_t func1_out, SRV_Channel::Aux_servo_function_t func2_out) const;
void flaperon_update();
+ void indicate_waiting_for_rud_neutral_to_takeoff(void);
// is_flying.cpp
void update_is_flying_5Hz(void);
@@ -1226,6 +1243,8 @@ class Plane : public AP_Vehicle {
public:
void failsafe_check(void);
+ bool is_landing() const override;
+ bool is_taking_off() const override;
#if AP_SCRIPTING_ENABLED
bool set_target_location(const Location& target_loc) override;
bool get_target_location(Location& target_loc) override;
diff --git a/ArduPlane/RC_Channel.cpp b/ArduPlane/RC_Channel.cpp
index 1da0108f6ce95c..e476982eb85c09 100644
--- a/ArduPlane/RC_Channel.cpp
+++ b/ArduPlane/RC_Channel.cpp
@@ -16,9 +16,14 @@ int8_t RC_Channels_Plane::flight_mode_channel_number() const
return plane.g.flight_mode_channel.get();
}
+bool RC_Channels_Plane::in_rc_failsafe() const
+{
+ return (plane.rc_failsafe_active() || plane.failsafe.rc_failsafe);
+}
+
bool RC_Channels_Plane::has_valid_input() const
{
- if (plane.rc_failsafe_active() || plane.failsafe.rc_failsafe) {
+ if (in_rc_failsafe()) {
return false;
}
if (plane.failsafe.throttle_counter != 0) {
@@ -45,8 +50,7 @@ void RC_Channel_Plane::do_aux_function_change_mode(const Mode::Number number,
// return to flight mode switch's flight mode if we are currently
// in this mode
if (plane.control_mode->mode_number() == number) {
-// TODO: rc().reset_mode_switch();
- plane.reset_control_switch();
+ rc().reset_mode_switch();
}
}
}
@@ -355,7 +359,7 @@ bool RC_Channel_Plane::do_aux_function(const aux_func_t ch_option, const AuxSwit
break;
case AUX_FUNC::MODE_SWITCH_RESET:
- plane.reset_control_switch();
+ rc().reset_mode_switch();
break;
case AUX_FUNC::CRUISE:
diff --git a/ArduPlane/RC_Channel.h b/ArduPlane/RC_Channel.h
index 35663554a51e0f..7ecc352c32aa8b 100644
--- a/ArduPlane/RC_Channel.h
+++ b/ArduPlane/RC_Channel.h
@@ -13,6 +13,9 @@ class RC_Channel_Plane : public RC_Channel
AuxSwitchPos ch_flag) override;
bool do_aux_function(aux_func_t ch_option, AuxSwitchPos) override;
+ // called when the mode switch changes position:
+ void mode_switch_changed(modeswitch_pos_t new_pos) override;
+
private:
void do_aux_function_change_mode(Mode::Number number,
@@ -42,10 +45,13 @@ class RC_Channels_Plane : public RC_Channels
return &obj_channels[chan];
}
+ bool in_rc_failsafe() const override;
bool has_valid_input() const override;
RC_Channel *get_arming_channel(void) const override;
+ void read_mode_switch() override;
+
protected:
// note that these callbacks are not presently used on Plane:
diff --git a/ArduPlane/ReleaseNotes.txt b/ArduPlane/ReleaseNotes.txt
index 70036d3c84690e..6cdec344fadd06 100644
--- a/ArduPlane/ReleaseNotes.txt
+++ b/ArduPlane/ReleaseNotes.txt
@@ -1,3 +1,356 @@
+Release 4.4.0 18th August 2023
+------------------------------
+
+No changes from beta5
+
+Release 4.4.0-beta5 11th August 2023
+------------------------------------
+
+Changes from 4.4.0-beta4
+
+- fixed handling of missing DroneCAN airspeed packet
+- fixed reset of target altitude in plane GUIDED mode
+- added SIYI N7 flight controller
+- fixed auto-enable of fence with forced arm
+- fixed race condition that caused notch filter gyro glitches
+- fixed bug with RTK injection for DroneCAN
+
+Release 4.4.0 beta4
+-------------------
+
+Changes from 4.4.0-beta3
+
+1) flight controller specific changes
+ - Diatone-Mamba-MK4-H743v2 uses SPL06 baro (was DPS280)
+ - DMA for I2C disabled on F7 and H7 boards
+ - Foxeer H743v1 default serial protocol config fixes
+ - HeeWing-F405 and F405v2 support
+ - iFlight BlitzF7 support
+2) Scripts may take action based on VTOL motor loss
+3) Bug fixes
+ - BLHeli returns battery status requested via MSP (avoids hang when using esc-configurator)
+ - CRSFv3 rescans at baudrates to avoid RX loss
+ - EK3_ABIAS_P_NSE param range fix
+ - Scripting restart memory corruption bug fixed
+ - Siyi A8/ZR10 driver fix to avoid crash if serial port not configured
+
+Release 4.4.0 beta3
+-------------------
+
+This is the third beta of plane 4.4.0. This includes some important
+fixes since beta2
+
+1) flight controller specific changes
+ - Holybro KakuteH7-Wing support
+ - JFB100 external watchdog GPIO support added
+ - Pixhawk1-bdshot support
+ - Pixhawk6X-bdshot support
+ - SpeedyBeeF4 loses bdshot support
+
+3) Camera and Gimbal related changes
+ - DO_SET_ROI_NONE command support added
+
+4) Bug fixes
+ - ADSB sensor loss of transceiver message less spammy
+ - AutoTune Yaw rate max fixed
+ - EKF vertical velocity reset fixed on loss of GPS
+ - GPS pre-arm failure message clarified
+ - SERVOx_PROTOCOL "SToRM32 Gimbal Serial" value renamed to "Gimbal" because also used by Siyi
+ - SERIALx_OPTION "Swap" renamed to "SwapTXRX" for clarity
+ - SBF GPS ellipsoid height fixed
+ - Ublox M10S GPS auto configuration fixed
+ - ZigZag mode user takeoff fixed (users could not takeoff in ZigZag mode previously)
+ - fixed memory corruption bug with scripting restart
+
+5) Device drivers
+ - added LP5562 I2C LED driver
+ - added IS31FL3195 LED driver
+
+6) Applet changes
+ - added QUIK_MAX_REDUCE parameter to VTOL quicktune lua applet
+
+7) Plane specific changes
+ - fixed takeoff mode to ensure climb to takeoff alt before turning
+ - fixed error in quadplane wait for rudder neutral
+ - improved handling of forward throttle during VTOL landing
+ - fixed TECS state reset in VTOL auto modes
+ - fixed early exit from loiter to alt
+ - fixed display of started airspeed wait on forward transition
+
+
+Release 4.4.0 beta2
+-------------------
+
+This is the second beta of plane 4.4.0. This includes some important
+fixes since beta1.
+
+The full list of changes is:
+
+ - added SpeedyBeeF405WING, JSB100 and FoxeerH743
+ - added LOG_DISARMED=3 support and LOG_DARM_RATEMAX
+ - fixed error handling for being out of memory in EKF initialisation
+ - fixed a bug in RC input handling on the IOMCU
+ - fixed a bug handling ICE engine start after altitude reached
+ - adjust EKF3 accel bias process noise for greater robustness
+ - fixed an EKF3 bug in accel bias calculations
+ - cope with compassmot impacting GSF yaw numerical stability
+ - fixed an AUTOTUNE/QAUTOTUNE bug in yaw tuning
+ - support INA228 and INA238 I2C battery monitors
+ - always log rate PID slew limiters even when slew limit is zero
+ - added MambaF4050v2 for new IMU, bdshot and DMA on UART1
+ - update for FoxeerH743v1 GA release
+ - reduced IMU init speed on MatekH743
+ - move LED serial processing to its own thread
+ - fixed parameter documentation for BRD_SAFETYOPTION
+ - don't reject airspeed using EKF innovation if dead-reckoning
+ - fixed USB pass-thru on 2nd USB endpoint
+
+Release 4.3.7 31st May 2023
+---------------------------
+
+This stable release is for the 4.3.x stable series and is being done
+because of a serious bug that has been found with RC input on boards
+that use an IOMCU for RC input (boards with a separate set of 8 "main"
+outputs from "aux" outputs).
+
+The bug was that when RC input is lost and the receiver is one that
+uses "no pulses" for loss of RC input then there is a chance that when
+the RC link is regained that ArduPilot will not regain RC control and
+will continue in RC failsafe.
+
+The bug is an old one, first introduced in the 4.0.6 release in
+September 2020. The bug does not occur often which is why it has been
+such a long time before it was noticed. We would like to thank CUAV
+for noticing and reporting the bug!
+
+This release also has some other changes, some of which are to sync
+with the Copter 4.3.6 release (which will go to 4.3.7 with this RC
+input bug fix) and some are other bugs found since the 4.3.5 plane
+release.
+
+This release skips the 4.3.6 number to sync with copter.
+
+The full list of changes is:
+
+ - fixed a fault in the INS batch sampler code if you change the INS_LOG_BAT_CNT parameter without rebooting
+ - fixed the RC input on IOMCU bug explained above
+ - fixed a bug in ICE engine control if you do a "delay engine start" mission command while flying
+ - added MCU voltage monitoring for the H757 microcontroller (eg. CubeOrangePlus)
+ - servo gimbal mount yaw handling fix (only affects 3-axis servo gimbals)
+ - PiccoloCAN fix for ESC voltage and current scaling
+ - Gremsy gimbal fix when attached to autopilot's serial3 (or higher)
+ - added CubeOrangePlus-bdshot build
+ - fixed a bug in handling bad UART data in the megasquirt serial EFI driver
+ - added -g option for configuring with debug symbols without full debug (helped with RCIN bug diagnosis)
+ - fixed airmode switch for QACRO and QSTABILIZE modes
+ - fixed a rare memory corruption bug in the STM32H757
+ - fixed an EKF3 bug in accel bias calculations
+ - adjust EKF3 accel bias process noise for greater robustness
+ - cope with compassmot impacting GSF yaw numerical stability
+
+
+Please test and report any issues!
+
+Release 4.4.0 beta1
+-------------------
+
+This is the first beta of plane 4.4.0. It is a big release with lots
+of changes. Many thanks to all the people who have contributed!
+
+1) New autopilots supported
+ - ESP32
+ - Flywoo Goku F405S AIO
+ - Foxeer H743v1
+ - MambaF405-2022B
+ - PixPilot-V3
+ - PixSurveyA2
+ - rFCU H743
+ - ThePeach K1/R1
+
+2) Autopilot specific changes
+ - Bi-Directional DShot support for CubeOrangePlus-bdshot, CUAVNora+, MatekF405TE/VTOL-bdshot, MatekL431, Pixhawk6C-bdshot, QioTekZealotH743-bdshot
+ - Bi-Directional DShot up to 8 channels on MatekH743
+ - BlueRobotics Navigator supports baro on I2C bus 6
+ - BMP280 baro only for BeastF7, KakuteF4, KakuteF7Mini, MambaF405, MatekF405, Omnibusf4 to reduce code size (aka "flash")
+ - CSRF and Hott telemetry disabled by default on some low power boards (aka "minimised boards")
+ - Foxeer Reaper F745 supports external compasses
+ - OmnibusF4 support for BMI270 IMU
+ - OmnibusF7V2-bdshot support removed
+ - KakuteF7 regains displayport, frees up DMA from unused serial port
+ - KakuteH7v2 gets second battery sensor
+ - MambaH743v4 supports VTX
+ - MatekF405-Wing supports InvensenseV3 IMUs
+ - PixPilot-V6 heater enabled
+ - Raspberry 64OS startup crash fixed
+ - ReaperF745AIO serial protocol defaults fixed
+ - SkystarsH7HD (non-bdshot) removed as users should always use -bdshot version
+ - Skyviper loses many unnecessary features to save flash
+ - UBlox GPS only for AtomRCF405NAVI, BeastF7, MatekF405, Omnibusf4 to reduce code size (aka "flash")
+ - VRBrain-v52 and VRCore-v10 features reduced to save flash
+
+3) Driver enhancements
+ - ARK RTK GPS support
+ - BMI088 IMU filtering and timing improved, ignores bad data
+ - CRSF OSD may display disarmed state after flight mode (enabled using RC_OPTIONS)
+ - Daiwa winch baud rate obeys SERIALx_BAUD parameter
+ - EFI supports fuel pressure and ignition voltage reporting and battery failsafe
+ - ICM45686 IMU support
+ - ICM20602 uses fast reset instead of full reset on bad temperature sample (avoids occasional very high offset)
+ - ICM45686 supports fast sampling
+ - MAX31865 temp sensor support
+ - MB85RS256TY-32k, PB85RS128C and PB85RS2MC FRAM support
+ - MMC3416 compass orientation fix
+ - MPPT battery monitor reliability improvements, enable/disable aux function and less spammy
+ - Multiple USD-D1-CAN radar support
+ - NMEA output rate configurable (see NMEA_RATE_MS)
+ - NMEA output supports PASHR message (see NMEA_MSG_EN)
+ - OSD supports average resting cell voltage (see OSD_ACRVOLT_xxx params)
+ - Rockblock satellite modem support
+ - Serial baud support for 2Mbps (only some hardware supports this speed)
+ - SF45b lidar filtering reduced (allows detecting smaller obstacles
+ - SmartAudio 2.0 learns all VTX power levels)
+ - UAVCAN ESCs report error count using ESC Telemetry
+ - Unicore GPS (e.g. UM982) support
+ - VectorNav 100 external AHRS support
+ - 5 IMUs supported
+
+4) EKF related enhancements
+ - Baro compensation using wind estimates works when climbing or descending (see BAROx_WCF_UP/DN)
+ - External AHRS support for enabling only some sensors (e.g. IMU, Baro, Compass) see EAHRS_SENSORS
+ - Magnetic field tables updated
+ - Non-compass initial yaw alignment uses GPS course over GSF (mostly affects Planes and Rover)
+
+5) Control and navigation enhancements
+ - AutoTune of attitude control yaw D gain (set AUTOTUNE_AXES=8)
+ - DO_SET_ROI_NONE command turns off ROI
+ - JUMP_TAG mission item support
+ - Missions can be stored on SD card (see BRD_SD_MISSION)
+ - NAV_SCRIPT_TIME command accepts floating point arguments
+ - Pause/Resume returns success if mission is already paused or resumed
+ - Payload Place support via lua script in quadplanes
+
+7) Filtering enhancements
+ - FFT notch can be run based on filtered data
+ - Warn of motor noise at RPM frequency using FFT
+ - In-flight FFT can better track low frequency noise
+ - In-flight FFT logging improved
+ - IMU data can be read and replayed for FFT analysis
+
+8) Camera and gimbal enhancements
+ - BMMCC support included in Servo driver
+ - DJI RS2/RS3-Pro gimbal support
+ - Dual camera support (see CAM2_TYPE)
+ - Gimbal/Mount2 can be moved to retracted or neutral position
+ - Gremsy ZIO support
+ - IMAGE_START_CAPTURE, SET_CAMERA_ZOOM/FOCUS, VIDEO_START/STOP_CAPTURE command support
+ - Paramters renamed and rescaled
+ i) CAM_TRIGG_TYPE renamed to CAM1_TYPE and options have changed
+ ii) CAM_DURATION renamed to CAM1_DURATION and scaled in seconds
+ iii) CAM_FEEDBACK_PIN/POL renamed to CAM1_FEEBAK_PIN/POL
+ iv) CAM_MIN_INTERVAL renamed to CAM1_INTRVAL_MIN and scaled in seconds
+ v) CAM_TRIGG_DIST renamed to CAMx_TRIGG_DIST and accepts fractional values
+ - RunCam2 4k support
+ - ViewPro camera gimbal support
+
+9) Logging changes
+ - BARO msg includes 3-axis dynamic pressure useful for baro compensation of wind estimate
+ - MCU log msg includes main CPU temp and voltage (was part of POWR message)
+ - RCOut banner message always included in Logs
+ - SCR message includes memory usage of all running scripts
+ - CANS message includes CAN bus tx/rx statistics
+ - OFCA (optical flow calibration log message) units added
+ - Home location not logged to CMD message
+ - MOTB message includes throttle output
+
+10) Scripting enhancements
+ - Generator throttle control example added
+ - Heap max increased by allowing heap to be split across multiple underlying OS heaps
+ - Hexsoon LEDs applet
+ - Logging from scripts supports more formats
+ - Parameters can be removed or reordered
+ - Parameter description support (scripts must be in AP's applet or driver directory)
+ - Rangefinder driver support
+ - Runcam_on_arm applet starts recording when vehicle is armed
+ - Safety switch, E-Stop and motor interlock support
+ - Scripts can restart all scripts
+ - Script_Controller applet supports inflight switching of active scripts
+
+11) Custom build server enhancements
+ - AIS support for displaying nearby boats can be included
+ - Battery, Camera and Compass drivers can be included/excluded
+ - EKF3 wind estimation can be included/excluded
+ - PCA9685, ToshibaLED, PLAY_TUNE notify drivers can be included/excluded
+ - RichenPower generator can be included/excluded
+ - RC SRXL protocol can be excluded
+ - SIRF GPSs can be included/excluded
+
+12) Safety related enhancements and fixes
+ - "EK3 sources require RangeFinder" pre-arm check fix when user only sets up 2nd rangefinder (e.g. 1st is disabled)
+ - Pre-arm check that low and critical battery failsafe thresholds are different
+ - Pre-arm message fixed if 2nd EKF core unhealthy
+ - Pre-arm check if reboot required to enabled IMU batch sampling (used for vibe analysis)
+
+13) Minor enhancements
+ - Boot time reduced by improving parameter conversion efficiency
+ - BRD_SAFETYENABLE parameter renamed to BRD_SAFETY_DEFLT
+ - Compass calibration auxiliary switch function (set RCx_OPTION=171)
+ - Disable IMU3 auxiliary switch function (set RCx_OPTION=110)
+ - MAVFTP supports file renaming
+ - MAVLink in-progress reply to some requests for calibration from GCS
+
+14) Bug fixes:
+ - ADSB telemetry and callsign fixes
+ - Battery pct reported to GCS limited to 0% to 100% range
+ - Bi-directional DShot fix on H7 boards after system time wrap (more complete fix than in 4.3.6)
+ - DisplayPort OSD screen reliability improvement on heavily loaded OSDs especially F4 boards
+ - DisplayPort OSD artificial horizon better matches actual horizon
+ - EFI Serial MS bug fix to avoid possible infinite loop
+ - EKF3 Replay fix when COMPASS_LEARN=3
+ - ESC Telemetry external temp reporting fix
+ - Fence upload works even if Auto mode is excluded from firmware
+ - FMT messages logged even when Fence is exncluded from firmware (e.g. unselected when using custom build server)
+ - Hardfault avoided if user changes INS_LOG_BAT_CNT while batch sampling running
+ - ICM20649 temp sensor tolerate increased to avoid unnecessary FIFO reset
+ - IMU detection bug fix to avoid duplicates
+ - IMU temp cal fix when using auxiliary IMU
+ - Message Interval fix for restoring default rate https://github.com/ArduPilot/ardupilot/pull/21947
+ - RADIO_STATUS messages slow-down feature never completely stops messages from being sent
+ - SERVOx_TRIM value output momentarily if SERVOx_FUNCTION is changed from Disabled to RCPassThru, RCIN1, etc. Avoids momentary divide-by-zero
+ - Scripting file system open fix
+ - Scripting PWM source deletion crash fix
+ - MAVFTP fix for low baudrates (4800 baud and lower)
+ - ModalAI VOXL reset handling fix
+ - MPU6500 IMU fast sampling rate to 4k (was 1K)
+ - NMEA GPGGA output fixed for GPS quality, num sats and hdop
+ - Position control reset avoided even with very uneven main loop rate due to high CPU load
+ - Terrain offset increased from 15m to 30m (see TERRAIN_OFS_MAX) to reduce chance of "clamping"
+ - Throttle notch FFT tuning param fix
+
+15) Developer specific items
+ - DroneCAN replaces UAVCAN
+ - FlighAxis simulator rangefinder fixed
+ - Scripts in applet and drivers directory checked using linter
+ - Simulator supports main loop timing jitter (see SIM_TIME_JITTER)
+ - Simulink model and init scripts
+ - SITL on hardware support (useful to demo servos moving in response to simulated flight)
+ - SITL parameter definitions added (some, not all)
+ - Webots 2023a simulator support
+ - XPlane support for wider range of aircraft
+
+16) Plane specific changes
+ - new aerobatics scripting system with flexible schedules
+ - added plane-3d SITL model
+ - added quadlane landing abort AUX switch
+ - added TKOFF_GND_PITCH for taildragger takeoff
+ - new ACRO_LOCKING=2 mode for quaternion locking with yaw rate controller
+ - allow yaw rate autotune in modes other than AUTOTUNE
+ - use a cone for QRTL climb close to home
+ - added Y4 VTOL config for quadplanes
+ - added throttle scaling for vectored yaw
+ - added turn corrdination to yaw AUTOTUNE
+ - added Q_OPTION for motor tilt when disarmed in fixed wing modes
+
+
Release 4.3.5 26th March 2023
------------------------------
diff --git a/ArduPlane/altitude.cpp b/ArduPlane/altitude.cpp
index 6387edef12aad0..04aa72b2707469 100644
--- a/ArduPlane/altitude.cpp
+++ b/ArduPlane/altitude.cpp
@@ -28,6 +28,27 @@ void Plane::adjust_altitude_target()
control_mode->update_target_altitude();
}
+void Plane::check_home_alt_change(void)
+{
+ int32_t home_alt_cm = ahrs.get_home().alt;
+ if (home_alt_cm != auto_state.last_home_alt_cm && hal.util->get_soft_armed()) {
+ // cope with home altitude changing
+ const int32_t alt_change_cm = home_alt_cm - auto_state.last_home_alt_cm;
+ if (next_WP_loc.terrain_alt) {
+ /*
+ next_WP_loc for terrain alt WP are quite strange. They
+ have terrain_alt=1, but also have relative_alt=0 and
+ have been calculated to be relative to home. We need to
+ adjust for the change in home alt
+ */
+ next_WP_loc.alt += alt_change_cm;
+ }
+ // reset TECS to force the field elevation estimate to reset
+ TECS_controller.reset();
+ }
+ auto_state.last_home_alt_cm = home_alt_cm;
+}
+
/*
setup for a gradual glide slope to the next waypoint, if appropriate
*/
diff --git a/ArduPlane/commands_logic.cpp b/ArduPlane/commands_logic.cpp
index b6d017a53a7295..2edc79b158e5c3 100644
--- a/ArduPlane/commands_logic.cpp
+++ b/ArduPlane/commands_logic.cpp
@@ -1062,7 +1062,7 @@ bool Plane::verify_landing_vtol_approach(const AP_Mission::Mission_Command &cmd)
{
// validate that the vehicle is at least the expected distance away from the loiter point
// require an angle total of at least 2 centidegrees, due to special casing of 1 centidegree
- if (((fabsf(cmd.content.location.get_distance(current_loc) - abs_radius) > 5.0f) &&
+ if (((fabsF(cmd.content.location.get_distance(current_loc) - abs_radius) > 5.0f) &&
(cmd.content.location.get_distance(current_loc) < abs_radius)) ||
(labs(loiter.sum_cd) < 2)) {
nav_controller->update_loiter(cmd.content.location, abs_radius, direction);
@@ -1078,7 +1078,7 @@ bool Plane::verify_landing_vtol_approach(const AP_Mission::Mission_Command &cmd)
const float breakout_direction_rad = radians(vtol_approach_s.approach_direction_deg + (direction > 0 ? 270 : 90));
// breakout when within 5 degrees of the opposite direction
- if (fabsf(wrap_PI(ahrs.yaw - breakout_direction_rad)) < radians(5.0f)) {
+ if (fabsF(wrap_PI(ahrs.yaw - breakout_direction_rad)) < radians(5.0f)) {
gcs().send_text(MAV_SEVERITY_INFO, "Starting VTOL land approach path");
vtol_approach_s.approach_stage = APPROACH_LINE;
set_next_WP(cmd.content.location);
diff --git a/ArduPlane/config.h b/ArduPlane/config.h
index ba29c2062d8015..a8c6c890c96cb0 100644
--- a/ArduPlane/config.h
+++ b/ArduPlane/config.h
@@ -238,7 +238,7 @@
#endif
#ifndef OFFBOARD_GUIDED
- #define OFFBOARD_GUIDED !HAL_MINIMIZE_FEATURES
+ #define OFFBOARD_GUIDED 1
#endif
//////////////////////////////////////////////////////////////////////////////
diff --git a/ArduPlane/control_modes.cpp b/ArduPlane/control_modes.cpp
index 8caeae82042799..7f15e0e2663f90 100644
--- a/ArduPlane/control_modes.cpp
+++ b/ArduPlane/control_modes.cpp
@@ -98,61 +98,23 @@ Mode *Plane::mode_from_mode_num(const enum Mode::Number num)
return ret;
}
-void Plane::read_control_switch()
+void RC_Channels_Plane::read_mode_switch()
{
- static bool switch_debouncer;
- uint8_t switchPosition = readSwitch();
-
- // If switchPosition = 255 this indicates that the mode control channel input was out of range
- // If we get this value we do not want to change modes.
- if(switchPosition == 255) return;
-
- if (!rc().has_valid_input()) {
- // ignore the mode switch channel if there is no valid RC input
- return;
- }
-
- if (millis() - failsafe.last_valid_rc_ms > 100) {
+ if (millis() - plane.failsafe.last_valid_rc_ms > 100) {
// only use signals that are less than 0.1s old.
return;
}
-
- if (oldSwitchPosition != switchPosition) {
-
- if (switch_debouncer == false) {
- // this ensures that mode switches only happen if the
- // switch changes for 2 reads. This prevents momentary
- // spikes in the mode control channel from causing a mode
- // switch
- switch_debouncer = true;
- return;
- }
-
- set_mode_by_number((enum Mode::Number)flight_modes[switchPosition].get(), ModeReason::RC_COMMAND);
-
- oldSwitchPosition = switchPosition;
- }
-
- switch_debouncer = false;
-
+ RC_Channels::read_mode_switch();
}
-uint8_t Plane::readSwitch(void) const
+void RC_Channel_Plane::mode_switch_changed(modeswitch_pos_t new_pos)
{
- uint16_t pulsewidth = RC_Channels::get_radio_in(g.flight_mode_channel - 1);
- if (pulsewidth <= 900 || pulsewidth >= 2200) return 255; // This is an error condition
- if (pulsewidth <= 1230) return 0;
- if (pulsewidth <= 1360) return 1;
- if (pulsewidth <= 1490) return 2;
- if (pulsewidth <= 1620) return 3;
- if (pulsewidth <= 1749) return 4; // Software Manual
- return 5; // Hardware Manual
-}
+ if (new_pos < 0 || (uint8_t)new_pos > plane.num_flight_modes) {
+ // should not have been called
+ return;
+ }
-void Plane::reset_control_switch()
-{
- oldSwitchPosition = 254;
- read_control_switch();
+ plane.set_mode_by_number((Mode::Number)plane.flight_modes[new_pos].get(), ModeReason::RC_COMMAND);
}
/*
diff --git a/ArduPlane/defines.h b/ArduPlane/defines.h
index e880eef494b3a0..c7389daf49bdca 100644
--- a/ArduPlane/defines.h
+++ b/ArduPlane/defines.h
@@ -8,6 +8,8 @@
#define MIN_AIRSPEED_MIN 5 // m/s, used for arming check and speed scaling
+#define TAKEOFF_RUDDER_WARNING_TIMEOUT 3000 //ms that GCS warning about not returning arming rudder to neutral repeats
+
// failsafe
// ----------------------
enum failsafe_state {
@@ -42,6 +44,7 @@ enum failsafe_action_long {
FS_ACTION_LONG_RTL = 1,
FS_ACTION_LONG_GLIDE = 2,
FS_ACTION_LONG_PARACHUTE = 3,
+ FS_ACTION_LONG_AUTO = 4,
};
// type of stick mixing enabled
@@ -120,6 +123,7 @@ enum log_messages {
#define MASK_LOG_IMU_RAW (1UL<<19)
#define MASK_LOG_ATTITUDE_FULLRATE (1U<<20)
#define MASK_LOG_VIDEO_STABILISATION (1UL<<21)
+#define MASK_LOG_NOTCH_FULLRATE (1UL<<22)
enum {
CRASH_DETECT_ACTION_BITMASK_DISABLED = 0,
@@ -161,7 +165,7 @@ enum FlightOptions {
CENTER_THROTTLE_TRIM = (1<<10),
DISABLE_GROUND_PID_SUPPRESSION = (1<<11),
ENABLE_LOITER_ALT_CONTROL = (1<<12),
-
+ INDICATE_WAITING_FOR_RUDDER_NEUTRAL = (1<<13),
};
enum CrowFlapOptions {
diff --git a/ArduPlane/events.cpp b/ArduPlane/events.cpp
index 9c2a215608ce78..122b3dc361d211 100644
--- a/ArduPlane/events.cpp
+++ b/ArduPlane/events.cpp
@@ -107,6 +107,7 @@ void Plane::failsafe_short_on_event(enum failsafe_state fstype, ModeReason reaso
void Plane::failsafe_long_on_event(enum failsafe_state fstype, ModeReason reason)
{
+
// This is how to handle a long loss of control signal failsafe.
// If the GCS is locked up we allow control to revert to RC
RC_Channels::clear_overrides();
@@ -124,6 +125,14 @@ void Plane::failsafe_long_on_event(enum failsafe_state fstype, ModeReason reason
case Mode::Number::CIRCLE:
case Mode::Number::LOITER:
case Mode::Number::THERMAL:
+ case Mode::Number::TAKEOFF:
+ if (plane.flight_stage == AP_FixedWing::FlightStage::TAKEOFF && !(g.fs_action_long == FS_ACTION_LONG_GLIDE || g.fs_action_long == FS_ACTION_LONG_PARACHUTE)) {
+ // don't failsafe if in inital climb of TAKEOFF mode and FS action is not parachute or glide
+ // long failsafe will be re-called if still in fs after initial climb
+ long_failsafe_pending = true;
+ break;
+ }
+
if(plane.emergency_landing) {
set_mode(mode_fbwa, reason); // emergency landing switch overrides normal action to allow out of range landing
break;
@@ -131,9 +140,13 @@ void Plane::failsafe_long_on_event(enum failsafe_state fstype, ModeReason reason
if(g.fs_action_long == FS_ACTION_LONG_PARACHUTE) {
#if PARACHUTE == ENABLED
parachute_release();
+ //stop motors to avoide parachute tangling
+ plane.arming.disarm(AP_Arming::Method::PARACHUTE_RELEASE, false);
#endif
} else if (g.fs_action_long == FS_ACTION_LONG_GLIDE) {
set_mode(mode_fbwa, reason);
+ } else if (g.fs_action_long == FS_ACTION_LONG_AUTO) {
+ set_mode(mode_auto, reason);
} else {
set_mode(mode_rtl, reason);
}
@@ -166,24 +179,32 @@ void Plane::failsafe_long_on_event(enum failsafe_state fstype, ModeReason reason
case Mode::Number::AVOID_ADSB:
case Mode::Number::GUIDED:
+
if(g.fs_action_long == FS_ACTION_LONG_PARACHUTE) {
#if PARACHUTE == ENABLED
parachute_release();
+ //stop motors to avoide parachute tangling
+ plane.arming.disarm(AP_Arming::Method::PARACHUTE_RELEASE, false);
#endif
} else if (g.fs_action_long == FS_ACTION_LONG_GLIDE) {
set_mode(mode_fbwa, reason);
+ } else if (g.fs_action_long == FS_ACTION_LONG_AUTO) {
+ set_mode(mode_auto, reason);
} else if (g.fs_action_long == FS_ACTION_LONG_RTL) {
set_mode(mode_rtl, reason);
}
break;
case Mode::Number::RTL:
+ if (g.fs_action_long == FS_ACTION_LONG_AUTO) {
+ set_mode(mode_auto, reason);
+ }
+ break;
#if HAL_QUADPLANE_ENABLED
case Mode::Number::QLAND:
case Mode::Number::QRTL:
case Mode::Number::LOITER_ALT_QLAND:
#endif
- case Mode::Number::TAKEOFF:
case Mode::Number::INITIALISING:
break;
}
@@ -204,6 +225,7 @@ void Plane::failsafe_short_off_event(ModeReason reason)
void Plane::failsafe_long_off_event(ModeReason reason)
{
+ long_failsafe_pending = false;
// We're back in radio contact with RC or GCS
if (reason == ModeReason:: GCS_FAILSAFE) {
gcs().send_text(MAV_SEVERITY_WARNING, "GCS Failsafe Off");
diff --git a/ArduPlane/mode.cpp b/ArduPlane/mode.cpp
index 63559a50dd9950..a9af6555b7a6a4 100644
--- a/ArduPlane/mode.cpp
+++ b/ArduPlane/mode.cpp
@@ -32,6 +32,9 @@ bool Mode::enter()
// cancel inverted flight
plane.auto_state.inverted_flight = false;
+
+ // cancel waiting for rudder neutral
+ plane.takeoff_state.waiting_for_rudder_neutral = false;
// don't cross-track when starting a mission
plane.auto_state.next_wp_crosstrack = false;
@@ -56,6 +59,7 @@ bool Mode::enter()
plane.guided_state.target_heading_type = GUIDED_HEADING_NONE;
plane.guided_state.target_airspeed_cm = -1; // same as above, although an airspeed of -1 is rare on plane.
plane.guided_state.target_alt = -1; // same as above, although a target alt of -1 is rare on plane.
+ plane.guided_state.target_alt_time_ms = 0;
plane.guided_state.last_target_alt = 0;
#endif
@@ -85,6 +89,9 @@ bool Mode::enter()
// initialize speed variable used in AUTO and GUIDED for DO_CHANGE_SPEED commands
plane.new_airspeed_cm = -1;
+
+ // clear postponed long failsafe if mode change (from GCS) occurs before recall of long failsafe
+ plane.long_failsafe_pending = false;
#if HAL_QUADPLANE_ENABLED
quadplane.mode_enter();
@@ -197,3 +204,40 @@ bool Mode::_pre_arm_checks(size_t buflen, char *buffer) const
#endif
return true;
}
+
+void Mode::run()
+{
+ // Direct stick mixing functionality has been removed, so as not to remove all stick mixing from the user completely
+ // the old direct option is now used to enable fbw mixing, this is easier than doing a param conversion.
+ if ((plane.g.stick_mixing == StickMixing::FBW) || (plane.g.stick_mixing == StickMixing::DIRECT_REMOVED)) {
+ plane.stabilize_stick_mixing_fbw();
+ }
+ plane.stabilize_roll();
+ plane.stabilize_pitch();
+ plane.stabilize_yaw();
+}
+
+// Reset rate and steering controllers
+void Mode::reset_controllers()
+{
+ // reset integrators
+ plane.rollController.reset_I();
+ plane.pitchController.reset_I();
+ plane.yawController.reset_I();
+
+ // reset steering controls
+ plane.steer_state.locked_course = false;
+ plane.steer_state.locked_course_err = 0;
+}
+
+bool Mode::is_taking_off() const
+{
+ return (plane.flight_stage == AP_FixedWing::FlightStage::TAKEOFF);
+}
+
+// Helper to output to both k_rudder and k_steering servo functions
+void Mode::output_rudder_and_steering(float val)
+{
+ SRV_Channels::set_output_scaled(SRV_Channel::k_rudder, val);
+ SRV_Channels::set_output_scaled(SRV_Channel::k_steering, val);
+}
diff --git a/ArduPlane/mode.h b/ArduPlane/mode.h
index 46e56c284c4a7d..4da472cd063929 100644
--- a/ArduPlane/mode.h
+++ b/ArduPlane/mode.h
@@ -65,7 +65,7 @@ class Mode
void exit();
// run controllers specific to this mode
- virtual void run() {};
+ virtual void run();
// returns a unique number specific to this mode
virtual Number mode_number() const = 0;
@@ -79,6 +79,9 @@ class Mode
// returns true if the vehicle can be armed in this mode
bool pre_arm_checks(size_t buflen, char *buffer) const;
+ // Reset rate and steering controllers
+ void reset_controllers();
+
//
// methods that sub classes should override to affect movement of the vehicle in this mode
//
@@ -125,6 +128,13 @@ class Mode
// handle a guided target request from GCS
virtual bool handle_guided_request(Location target_loc) { return false; }
+ // true if is landing
+ virtual bool is_landing() const { return false; }
+
+ // true if is taking
+ virtual bool is_taking_off() const;
+
+
protected:
// subclasses override this to perform checks before entering the mode
@@ -136,6 +146,9 @@ class Mode
// mode specific pre-arm checks
virtual bool _pre_arm_checks(size_t buflen, char *buffer) const;
+ // Helper to output to both k_rudder and k_steering servo functions
+ void output_rudder_and_steering(float val);
+
#if HAL_QUADPLANE_ENABLED
// References for convenience, used by QModes
AC_PosControl*& pos_control;
@@ -206,6 +219,8 @@ class ModeAuto : public Mode
bool mode_allows_autotuning() const override { return true; }
+ bool is_landing() const override;
+
protected:
bool _enter() override;
@@ -355,6 +370,8 @@ class ModeManual : public Mode
// methods that affect movement of the vehicle in this mode
void update() override;
+
+ void run() override;
};
@@ -398,6 +415,12 @@ class ModeStabilize : public Mode
// methods that affect movement of the vehicle in this mode
void update() override;
+
+ void run() override;
+
+private:
+ void stabilize_stick_mixing_direct();
+
};
class ModeTraining : public Mode
diff --git a/ArduPlane/mode_acro.cpp b/ArduPlane/mode_acro.cpp
index 5bfeea2f81b920..acf0f497523d80 100644
--- a/ArduPlane/mode_acro.cpp
+++ b/ArduPlane/mode_acro.cpp
@@ -104,22 +104,24 @@ void ModeAcro::stabilize()
SRV_Channels::set_output_scaled(SRV_Channel::k_elevator, plane.pitchController.get_rate_out(pitch_rate, speed_scaler));
}
- plane.steering_control.steering = plane.rudder_input();
-
+ float rudder_output;
if (plane.g.acro_yaw_rate > 0 && plane.yawController.rate_control_enabled()) {
// user has asked for yaw rate control with yaw rate scaled by ACRO_YAW_RATE
const float rudd_expo = plane.rudder_in_expo(true);
const float yaw_rate = (rudd_expo/SERVO_MAX) * plane.g.acro_yaw_rate;
- plane.steering_control.steering = plane.steering_control.rudder = plane.yawController.get_rate_out(yaw_rate, speed_scaler, false);
- } else if (plane.g2.flight_options & FlightOptions::ACRO_YAW_DAMPER) {
+ rudder_output = plane.yawController.get_rate_out(yaw_rate, speed_scaler, false);
+ } else if (plane.flight_option_enabled(FlightOptions::ACRO_YAW_DAMPER)) {
// use yaw controller
- plane.calc_nav_yaw_coordinated();
+ rudder_output = plane.calc_nav_yaw_coordinated();
} else {
/*
manual rudder
*/
- plane.steering_control.rudder = plane.steering_control.steering;
+ rudder_output = plane.rudder_input();
}
+
+ output_rudder_and_steering(rudder_output);
+
}
/*
@@ -215,7 +217,7 @@ void ModeAcro::stabilize_quaternion()
// call to rate controllers
SRV_Channels::set_output_scaled(SRV_Channel::k_aileron, plane.rollController.get_rate_out(desired_rates.x, speed_scaler));
SRV_Channels::set_output_scaled(SRV_Channel::k_elevator, plane.pitchController.get_rate_out(desired_rates.y, speed_scaler));
- plane.steering_control.steering = plane.steering_control.rudder = plane.yawController.get_rate_out(desired_rates.z, speed_scaler, false);
+ output_rudder_and_steering(plane.yawController.get_rate_out(desired_rates.z, speed_scaler, false));
acro_state.roll_active_last = roll_active;
acro_state.pitch_active_last = pitch_active;
diff --git a/ArduPlane/mode_auto.cpp b/ArduPlane/mode_auto.cpp
index 548dd0b2618b8a..6ebf3546ef1690 100644
--- a/ArduPlane/mode_auto.cpp
+++ b/ArduPlane/mode_auto.cpp
@@ -159,3 +159,8 @@ bool ModeAuto::_pre_arm_checks(size_t buflen, char *buffer) const
// Note that this bypasses the base class checks
return true;
}
+
+bool ModeAuto::is_landing() const
+{
+ return (plane.flight_stage == AP_FixedWing::FlightStage::LAND);
+}
diff --git a/ArduPlane/mode_guided.cpp b/ArduPlane/mode_guided.cpp
index 900b084f8ca596..2d712c75987222 100644
--- a/ArduPlane/mode_guided.cpp
+++ b/ArduPlane/mode_guided.cpp
@@ -35,9 +35,67 @@ void ModeGuided::update()
return;
}
#endif
- plane.calc_nav_roll();
- plane.calc_nav_pitch();
- plane.calc_throttle();
+
+ // Received an external msg that guides roll in the last 3 seconds?
+ if (plane.guided_state.last_forced_rpy_ms.x > 0 &&
+ millis() - plane.guided_state.last_forced_rpy_ms.x < 3000) {
+ plane.nav_roll_cd = constrain_int32(plane.guided_state.forced_rpy_cd.x, -plane.roll_limit_cd, plane.roll_limit_cd);
+ plane.update_load_factor();
+
+#if OFFBOARD_GUIDED == ENABLED
+ // guided_state.target_heading is radians at this point between -pi and pi ( defaults to -4 )
+ // This function is used in Guided and AvoidADSB, check for guided
+ } else if ((plane.control_mode == &plane.mode_guided) && (plane.guided_state.target_heading_type != GUIDED_HEADING_NONE) ) {
+ uint32_t tnow = AP_HAL::millis();
+ float delta = (tnow - plane.guided_state.target_heading_time_ms) * 1e-3f;
+ plane.guided_state.target_heading_time_ms = tnow;
+
+ float error = 0.0f;
+ if (plane.guided_state.target_heading_type == GUIDED_HEADING_HEADING) {
+ error = wrap_PI(plane.guided_state.target_heading - AP::ahrs().yaw);
+ } else {
+ Vector2f groundspeed = AP::ahrs().groundspeed_vector();
+ error = wrap_PI(plane.guided_state.target_heading - atan2f(-groundspeed.y, -groundspeed.x) + M_PI);
+ }
+
+ float bank_limit = degrees(atanf(plane.guided_state.target_heading_accel_limit/GRAVITY_MSS)) * 1e2f;
+ bank_limit = MIN(bank_limit, plane.roll_limit_cd);
+
+ plane.g2.guidedHeading.update_error(error, delta); // push error into AC_PID , possible improvement is to use update_all instead.?
+
+ float i = plane.g2.guidedHeading.get_i(); // get integrator TODO
+ if (((is_negative(error) && !plane.guided_state.target_heading_limit_low) || (is_positive(error) && !plane.guided_state.target_heading_limit_high))) {
+ i = plane.g2.guidedHeading.get_i();
+ }
+
+ float desired = plane.g2.guidedHeading.get_p() + i + plane.g2.guidedHeading.get_d();
+ plane.guided_state.target_heading_limit_low = (desired <= -bank_limit);
+ plane.guided_state.target_heading_limit_high = (desired >= bank_limit);
+
+ plane.nav_roll_cd = constrain_int32(desired, -bank_limit, bank_limit);
+ plane.update_load_factor();
+
+#endif // OFFBOARD_GUIDED == ENABLED
+ } else {
+ plane.calc_nav_roll();
+ }
+
+ if (plane.guided_state.last_forced_rpy_ms.y > 0 &&
+ millis() - plane.guided_state.last_forced_rpy_ms.y < 3000) {
+ plane.nav_pitch_cd = constrain_int32(plane.guided_state.forced_rpy_cd.y, plane.pitch_limit_min_cd, plane.aparm.pitch_limit_max_cd.get());
+ } else {
+ plane.calc_nav_pitch();
+ }
+
+ // Received an external msg that guides throttle in the last 3 seconds?
+ if (plane.aparm.throttle_cruise > 1 &&
+ plane.guided_state.last_forced_throttle_ms > 0 &&
+ millis() - plane.guided_state.last_forced_throttle_ms < 3000) {
+ SRV_Channels::set_output_scaled(SRV_Channel::k_throttle, plane.guided_state.forced_throttle);
+ } else {
+ plane.calc_throttle();
+ }
+
}
void ModeGuided::navigate()
diff --git a/ArduPlane/mode_loiter.cpp b/ArduPlane/mode_loiter.cpp
index e7b07c9db127e9..05ce3a69568572 100644
--- a/ArduPlane/mode_loiter.cpp
+++ b/ArduPlane/mode_loiter.cpp
@@ -9,7 +9,7 @@ bool ModeLoiter::_enter()
// make sure the local target altitude is the same as the nav target used for loiter nav
// this allows us to do FBWB style stick control
/*IGNORE_RETURN(plane.next_WP_loc.get_alt_cm(Location::AltFrame::ABSOLUTE, plane.target_altitude.amsl_cm));*/
- if (plane.stick_mixing_enabled() && (plane.g2.flight_options & FlightOptions::ENABLE_LOITER_ALT_CONTROL)) {
+ if (plane.stick_mixing_enabled() && (plane.flight_option_enabled(FlightOptions::ENABLE_LOITER_ALT_CONTROL))) {
plane.set_target_altitude_current();
}
@@ -21,7 +21,7 @@ bool ModeLoiter::_enter()
void ModeLoiter::update()
{
plane.calc_nav_roll();
- if (plane.stick_mixing_enabled() && (plane.g2.flight_options & FlightOptions::ENABLE_LOITER_ALT_CONTROL)) {
+ if (plane.stick_mixing_enabled() && plane.flight_option_enabled(FlightOptions::ENABLE_LOITER_ALT_CONTROL)) {
plane.update_fbwb_speed_height();
} else {
plane.calc_nav_pitch();
@@ -42,8 +42,7 @@ bool ModeLoiter::isHeadingLinedUp(const Location loiterCenterLoc, const Location
// Return true if current heading is aligned to vector to targetLoc.
// Tolerance is initially 10 degrees and grows at 10 degrees for each loiter circle completed.
- const uint16_t loiterRadius = abs(plane.aparm.loiter_radius);
- if (loiterCenterLoc.get_distance(targetLoc) < loiterRadius + loiterRadius*0.05) {
+ if (loiterCenterLoc.get_distance(targetLoc) < 1.05f * fabsf(plane.loiter.radius)) {
/* Whenever next waypoint is within the loiter radius plus 5%,
maintaining loiter would prevent us from ever pointing toward the next waypoint.
Hence break out of loiter immediately
@@ -94,7 +93,7 @@ bool ModeLoiter::isHeadingLinedUp_cd(const int32_t bearing_cd)
void ModeLoiter::navigate()
{
- if (plane.g2.flight_options & FlightOptions::ENABLE_LOITER_ALT_CONTROL) {
+ if (plane.flight_option_enabled(FlightOptions::ENABLE_LOITER_ALT_CONTROL)) {
// update the WP alt from the global target adjusted by update_fbwb_speed_height
plane.next_WP_loc.set_alt_cm(plane.target_altitude.amsl_cm, Location::AltFrame::ABSOLUTE);
}
@@ -112,7 +111,7 @@ void ModeLoiter::navigate()
void ModeLoiter::update_target_altitude()
{
- if (plane.stick_mixing_enabled() && (plane.g2.flight_options & FlightOptions::ENABLE_LOITER_ALT_CONTROL)) {
+ if (plane.stick_mixing_enabled() && (plane.flight_option_enabled(FlightOptions::ENABLE_LOITER_ALT_CONTROL))) {
return;
}
Mode::update_target_altitude();
diff --git a/ArduPlane/mode_manual.cpp b/ArduPlane/mode_manual.cpp
index 68535f96186ba7..1f8fcd702cd14e 100644
--- a/ArduPlane/mode_manual.cpp
+++ b/ArduPlane/mode_manual.cpp
@@ -5,9 +5,30 @@ void ModeManual::update()
{
SRV_Channels::set_output_scaled(SRV_Channel::k_aileron, plane.roll_in_expo(false));
SRV_Channels::set_output_scaled(SRV_Channel::k_elevator, plane.pitch_in_expo(false));
- plane.steering_control.steering = plane.steering_control.rudder = plane.rudder_in_expo(false);
+ output_rudder_and_steering(plane.rudder_in_expo(false));
+ float throttle = plane.get_throttle_input(true);
+
+
+#if HAL_QUADPLANE_ENABLED
+ if (quadplane.available() && quadplane.option_is_set(QuadPlane::OPTION::IDLE_GOV_MANUAL)) {
+ // for quadplanes it can be useful to run the idle governor in MANUAL mode
+ // as it prevents the VTOL motors from running
+ int8_t min_throttle = plane.aparm.throttle_min.get();
+
+ // apply idle governor
+#if AP_ICENGINE_ENABLED
+ plane.g2.ice_control.update_idle_governor(min_throttle);
+#endif
+ throttle = MAX(throttle, min_throttle);
+ }
+#endif
+ SRV_Channels::set_output_scaled(SRV_Channel::k_throttle, throttle);
plane.nav_roll_cd = ahrs.roll_sensor;
plane.nav_pitch_cd = ahrs.pitch_sensor;
}
+void ModeManual::run()
+{
+ reset_controllers();
+}
diff --git a/ArduPlane/mode_qacro.cpp b/ArduPlane/mode_qacro.cpp
index d1c69de4e3e0df..b74a4343841611 100644
--- a/ArduPlane/mode_qacro.cpp
+++ b/ArduPlane/mode_qacro.cpp
@@ -32,6 +32,13 @@ void ModeQAcro::update()
*/
void ModeQAcro::run()
{
+ const uint32_t now = AP_HAL::millis();
+ if (quadplane.tailsitter.in_vtol_transition(now)) {
+ // Tailsitters in FW pull up phase of VTOL transition run FW controllers
+ Mode::run();
+ return;
+ }
+
if (quadplane.throttle_wait) {
quadplane.set_desired_spool_state(AP_Motors::DesiredSpoolState::GROUND_IDLE);
attitude_control->set_throttle_out(0, true, 0);
@@ -64,6 +71,9 @@ void ModeQAcro::run()
// output pilot's throttle without angle boost
attitude_control->set_throttle_out(throttle_out, false, 10.0f);
}
+
+ // Stabilize with fixed wing surfaces
+ plane.mode_acro.run();
}
#endif
diff --git a/ArduPlane/mode_qautotune.cpp b/ArduPlane/mode_qautotune.cpp
index d74cf792b5d05c..28bf977128faf2 100644
--- a/ArduPlane/mode_qautotune.cpp
+++ b/ArduPlane/mode_qautotune.cpp
@@ -21,9 +21,20 @@ void ModeQAutotune::update()
void ModeQAutotune::run()
{
+ const uint32_t now = AP_HAL::millis();
+ if (quadplane.tailsitter.in_vtol_transition(now)) {
+ // Tailsitters in FW pull up phase of VTOL transition run FW controllers
+ Mode::run();
+ return;
+ }
+
#if QAUTOTUNE_ENABLED
quadplane.qautotune.run();
#endif
+
+ // Stabilize with fixed wing surfaces
+ plane.stabilize_roll();
+ plane.stabilize_pitch();
}
void ModeQAutotune::_exit()
diff --git a/ArduPlane/mode_qhover.cpp b/ArduPlane/mode_qhover.cpp
index 13c1a4c4e65edb..1fe4848296a0c6 100644
--- a/ArduPlane/mode_qhover.cpp
+++ b/ArduPlane/mode_qhover.cpp
@@ -24,6 +24,13 @@ void ModeQHover::update()
*/
void ModeQHover::run()
{
+ const uint32_t now = AP_HAL::millis();
+ if (quadplane.tailsitter.in_vtol_transition(now)) {
+ // Tailsitters in FW pull up phase of VTOL transition run FW controllers
+ Mode::run();
+ return;
+ }
+
if (quadplane.throttle_wait) {
quadplane.set_desired_spool_state(AP_Motors::DesiredSpoolState::GROUND_IDLE);
attitude_control->set_throttle_out(0, true, 0);
@@ -32,6 +39,10 @@ void ModeQHover::run()
} else {
quadplane.hold_hover(quadplane.get_pilot_desired_climb_rate_cms());
}
+
+ // Stabilize with fixed wing surfaces
+ plane.stabilize_roll();
+ plane.stabilize_pitch();
}
#endif
diff --git a/ArduPlane/mode_qloiter.cpp b/ArduPlane/mode_qloiter.cpp
index 26ef2bf214f33c..e39ad63559ed42 100644
--- a/ArduPlane/mode_qloiter.cpp
+++ b/ArduPlane/mode_qloiter.cpp
@@ -28,6 +28,13 @@ void ModeQLoiter::update()
// run quadplane loiter controller
void ModeQLoiter::run()
{
+ const uint32_t now = AP_HAL::millis();
+ if (quadplane.tailsitter.in_vtol_transition(now)) {
+ // Tailsitters in FW pull up phase of VTOL transition run FW controllers
+ Mode::run();
+ return;
+ }
+
if (quadplane.throttle_wait) {
quadplane.set_desired_spool_state(AP_Motors::DesiredSpoolState::GROUND_IDLE);
attitude_control->set_throttle_out(0, true, 0);
@@ -35,6 +42,10 @@ void ModeQLoiter::run()
pos_control->relax_z_controller(0);
loiter_nav->clear_pilot_desired_acceleration();
loiter_nav->init_target();
+
+ // Stabilize with fixed wing surfaces
+ plane.stabilize_roll();
+ plane.stabilize_pitch();
return;
}
if (!quadplane.motors->armed()) {
@@ -45,7 +56,6 @@ void ModeQLoiter::run()
loiter_nav->soften_for_landing();
}
- const uint32_t now = AP_HAL::millis();
if (now - quadplane.last_loiter_ms > 500) {
loiter_nav->clear_pilot_desired_acceleration();
loiter_nav->init_target();
@@ -112,6 +122,10 @@ void ModeQLoiter::run()
quadplane.set_climb_rate_cms(quadplane.get_pilot_desired_climb_rate_cms());
}
quadplane.run_z_controller();
+
+ // Stabilize with fixed wing surfaces
+ plane.stabilize_roll();
+ plane.stabilize_pitch();
}
#endif
diff --git a/ArduPlane/mode_qrtl.cpp b/ArduPlane/mode_qrtl.cpp
index 75d82b48225fab..16e805a40d5c05 100644
--- a/ArduPlane/mode_qrtl.cpp
+++ b/ArduPlane/mode_qrtl.cpp
@@ -86,6 +86,13 @@ void ModeQRTL::update()
*/
void ModeQRTL::run()
{
+ const uint32_t now = AP_HAL::millis();
+ if (quadplane.tailsitter.in_vtol_transition(now)) {
+ // Tailsitters in FW pull up phase of VTOL transition run FW controllers
+ Mode::run();
+ return;
+ }
+
switch (submode) {
case SubMode::climb: {
// request zero velocity
@@ -165,6 +172,10 @@ void ModeQRTL::run()
break;
}
}
+
+ // Stabilize with fixed wing surfaces
+ plane.stabilize_roll();
+ plane.stabilize_pitch();
}
/*
@@ -184,7 +195,7 @@ void ModeQRTL::update_target_altitude()
initially approach at RTL_ALT_CM, then drop down to QRTL_ALT based on maximum sink rate from TECS,
giving time to lose speed before we transition
*/
- const float radius = MAX(fabsf(plane.aparm.loiter_radius), fabsf(plane.g.rtl_radius));
+ const float radius = MAX(fabsf(float(plane.aparm.loiter_radius)), fabsf(float(plane.g.rtl_radius)));
const float rtl_alt_delta = MAX(0, plane.g.RTL_altitude_cm*0.01 - plane.quadplane.qrtl_alt);
const float sink_time = rtl_alt_delta / MAX(0.6*plane.TECS_controller.get_max_sinkrate(), 1);
const float sink_dist = plane.aparm.airspeed_cruise_cm * 0.01 * sink_time;
@@ -209,7 +220,7 @@ bool ModeQRTL::allows_throttle_nudging() const
// Return the radius from destination at which pure VTOL flight should be used, no transition to FW
float ModeQRTL::get_VTOL_return_radius() const
{
- return MAX(fabsf(plane.aparm.loiter_radius), fabsf(plane.g.rtl_radius)) * 1.5;
+ return MAX(fabsf(float(plane.aparm.loiter_radius)), fabsf(float(plane.g.rtl_radius))) * 1.5;
}
#endif
diff --git a/ArduPlane/mode_qstabilize.cpp b/ArduPlane/mode_qstabilize.cpp
index 2c8da2d96885aa..39f168fd736d55 100644
--- a/ArduPlane/mode_qstabilize.cpp
+++ b/ArduPlane/mode_qstabilize.cpp
@@ -40,15 +40,28 @@ void ModeQStabilize::update()
// quadplane stabilize mode
void ModeQStabilize::run()
{
+ const uint32_t now = AP_HAL::millis();
+ if (quadplane.tailsitter.in_vtol_transition(now)) {
+ // Tailsitters in FW pull up phase of VTOL transition run FW controllers
+ Mode::run();
+ return;
+ }
+
// special check for ESC calibration in QSTABILIZE
if (quadplane.esc_calibration != 0) {
quadplane.run_esc_calibration();
+ plane.stabilize_roll();
+ plane.stabilize_pitch();
return;
}
// normal QSTABILIZE mode
float pilot_throttle_scaled = quadplane.get_pilot_throttle();
quadplane.hold_stabilize(pilot_throttle_scaled);
+
+ // Stabilize with fixed wing surfaces
+ plane.stabilize_roll();
+ plane.stabilize_pitch();
}
// set the desired roll and pitch for a tailsitter
diff --git a/ArduPlane/mode_rtl.cpp b/ArduPlane/mode_rtl.cpp
index fbe368b2bc573b..417eb6170f22ef 100644
--- a/ArduPlane/mode_rtl.cpp
+++ b/ArduPlane/mode_rtl.cpp
@@ -47,7 +47,7 @@ void ModeRTL::update()
plane.calc_throttle();
bool alt_threshold_reached = false;
- if (plane.g2.flight_options & FlightOptions::CLIMB_BEFORE_TURN) {
+ if (plane.flight_option_enabled(FlightOptions::CLIMB_BEFORE_TURN)) {
// Climb to ALT_HOLD_RTL before turning. This overrides RTL_CLIMB_MIN.
alt_threshold_reached = plane.current_loc.alt > plane.next_WP_loc.alt;
} else if (plane.g2.rtl_climb_min > 0) {
diff --git a/ArduPlane/mode_stabilize.cpp b/ArduPlane/mode_stabilize.cpp
index 7414d575065724..b73dfb6fc26506 100644
--- a/ArduPlane/mode_stabilize.cpp
+++ b/ArduPlane/mode_stabilize.cpp
@@ -7,3 +7,10 @@ void ModeStabilize::update()
plane.nav_pitch_cd = 0;
}
+void ModeStabilize::run()
+{
+ plane.stabilize_roll();
+ plane.stabilize_pitch();
+ stabilize_stick_mixing_direct();
+ plane.stabilize_yaw();
+}
diff --git a/ArduPlane/mode_takeoff.cpp b/ArduPlane/mode_takeoff.cpp
index 6e1984a7d9527e..bed8ebb65e2ea0 100644
--- a/ArduPlane/mode_takeoff.cpp
+++ b/ArduPlane/mode_takeoff.cpp
@@ -1,5 +1,6 @@
#include "mode.h"
#include "Plane.h"
+#include
/*
mode takeoff parameters
@@ -40,7 +41,7 @@ const AP_Param::GroupInfo ModeTakeoff::var_info[] = {
// @Units: m
// @User: Standard
AP_GROUPINFO("DIST", 4, ModeTakeoff, target_dist, 200),
-
+
// @Param: GND_PITCH
// @DisplayName: Takeoff run pitch demand
// @Description: Degrees of pitch angle demanded during the takeoff run before speed reaches TKOFF_ROTATE_SPD. For taildraggers set to 3-point ground pitch angle and use TKOFF_TDRAG_ELEV to prevent nose tipover. For nose-wheel steer aircraft set to the ground pitch angle and if a reduction in nose-wheel load is required as speed rises, use a positive offset in TKOFF_GND_PITCH of up to 5 degrees above the angle on ground, starting at the mesured pitch angle and incrementing in 1 degree steps whilst checking for premature rotation and takeoff with each increment. To increase nose-wheel load, use a negative TKOFF_TDRAG_ELEV and refer to notes on TKOFF_TDRAG_ELEV before making adjustments.
@@ -68,61 +69,75 @@ bool ModeTakeoff::_enter()
void ModeTakeoff::update()
{
+ // don't setup waypoints if we dont have a valid position and home!
+ if (!(plane.current_loc.initialised() && AP::ahrs().home_is_set())) {
+ plane.calc_nav_roll();
+ plane.calc_nav_pitch();
+ SRV_Channels::set_output_scaled(SRV_Channel::k_throttle, 0.0);
+ return;
+ }
+
+ const float alt = target_alt;
+ const float dist = target_dist;
if (!takeoff_started) {
+ const uint16_t altitude = plane.relative_ground_altitude(false,true);
+ const float direction = degrees(ahrs.yaw);
// see if we will skip takeoff as already flying
if (plane.is_flying() && (millis() - plane.started_flying_ms > 10000U) && ahrs.groundspeed() > 3) {
- gcs().send_text(MAV_SEVERITY_INFO, "Takeoff skipped - circling");
+ if (altitude >= alt) {
+ gcs().send_text(MAV_SEVERITY_INFO, "Above TKOFF alt - loitering");
+ plane.next_WP_loc = plane.current_loc;
+ takeoff_started = true;
+ plane.set_flight_stage(AP_FixedWing::FlightStage::NORMAL);
+ } else {
+ gcs().send_text(MAV_SEVERITY_INFO, "Climbing to TKOFF alt then loitering");
+ plane.next_WP_loc = plane.current_loc;
+ plane.next_WP_loc.alt += ((alt - altitude) *100);
+ plane.next_WP_loc.offset_bearing(direction, dist);
+ takeoff_started = true;
+ plane.set_flight_stage(AP_FixedWing::FlightStage::NORMAL);
+ }
+ // not flying so do a full takeoff sequence
+ } else {
+ // setup target waypoint and alt for loiter at dist and alt from start
+
+ start_loc = plane.current_loc;
plane.prev_WP_loc = plane.current_loc;
plane.next_WP_loc = plane.current_loc;
- takeoff_started = true;
- plane.set_flight_stage(AP_FixedWing::FlightStage::NORMAL);
- }
- }
+ plane.next_WP_loc.alt += alt*100.0;
+ plane.next_WP_loc.offset_bearing(direction, dist);
- if (!takeoff_started) {
- // setup target location 1.5 times loiter radius from the
- // takeoff point, at a height of TKOFF_ALT
- const float dist = target_dist;
- const float alt = target_alt;
- const float direction = degrees(ahrs.yaw);
+ plane.crash_state.is_crashed = false;
- start_loc = plane.current_loc;
- plane.prev_WP_loc = plane.current_loc;
- plane.next_WP_loc = plane.current_loc;
- plane.next_WP_loc.alt += alt*100.0;
- plane.next_WP_loc.offset_bearing(direction, dist);
-
- plane.crash_state.is_crashed = false;
+ plane.auto_state.takeoff_pitch_cd = level_pitch * 100;
- plane.auto_state.takeoff_pitch_cd = level_pitch * 100;
+ plane.set_flight_stage(AP_FixedWing::FlightStage::TAKEOFF);
- plane.set_flight_stage(AP_FixedWing::FlightStage::TAKEOFF);
-
- if (!plane.throttle_suppressed) {
- gcs().send_text(MAV_SEVERITY_INFO, "Takeoff to %.0fm at %.1fm to %.1f deg",
- alt, dist, direction);
- takeoff_started = true;
+ if (!plane.throttle_suppressed) {
+ gcs().send_text(MAV_SEVERITY_INFO, "Takeoff to %.0fm for %.1fm heading %.1f deg",
+ alt, dist, direction);
+ takeoff_started = true;
+ }
}
}
// we finish the initial level takeoff if we climb past
// TKOFF_LVL_ALT or we pass the target location. The check for
// target location prevents us flying forever if we can't climb
+ // reset the loiter waypoint target to be correct bearing and dist
+ // from starting location in case original yaw used to set it was off due to EKF
+ // reset or compass interference from max throttle
if (plane.flight_stage == AP_FixedWing::FlightStage::TAKEOFF &&
(plane.current_loc.alt - start_loc.alt >= level_alt*100 ||
- start_loc.get_distance(plane.current_loc) >= target_dist)) {
- // reached level alt, re-calculate bearing to cope with systems with no compass
- // or with poor initial compass
- float direction = start_loc.get_bearing_to(plane.current_loc) * 0.01;
- float dist_done = start_loc.get_distance(plane.current_loc);
- const float dist = target_dist;
-
- plane.next_WP_loc = plane.current_loc;
- plane.next_WP_loc.offset_bearing(direction, MAX(dist-dist_done, 0));
- plane.next_WP_loc.alt = start_loc.alt + target_alt*100.0;
+ start_loc.get_distance(plane.current_loc) >= dist)) {
+ // reset the target loiter waypoint using current yaw which should be close to correct starting heading
+ const float direction = start_loc.get_bearing_to(plane.current_loc) * 0.01;
+ plane.next_WP_loc = start_loc;
+ plane.next_WP_loc.offset_bearing(direction, dist);
+ plane.next_WP_loc.alt += alt*100.0;
plane.set_flight_stage(AP_FixedWing::FlightStage::NORMAL);
-
+
#if AP_FENCE_ENABLED
plane.fence.auto_enable_fence_after_takeoff();
#endif
@@ -136,6 +151,11 @@ void ModeTakeoff::update()
plane.calc_nav_roll();
plane.calc_nav_pitch();
plane.calc_throttle();
+ //check if in long failsafe, if it is recall long failsafe now to get fs action via events call
+ if (plane.long_failsafe_pending) {
+ plane.long_failsafe_pending = false;
+ plane.failsafe_long_on_event(FAILSAFE_LONG, ModeReason::MODE_TAKEOFF_FAILSAFE);
+ }
}
}
diff --git a/ArduPlane/mode_training.cpp b/ArduPlane/mode_training.cpp
index 9215fe0aba34d5..23c81fbcc288f8 100644
--- a/ArduPlane/mode_training.cpp
+++ b/ArduPlane/mode_training.cpp
@@ -63,5 +63,7 @@ void ModeTraining::run()
}
}
- plane.stabilize_yaw();
+ // Always manual rudder control
+ output_rudder_and_steering(plane.rudder_in_expo(false));
+
}
diff --git a/ArduPlane/motor_test.cpp b/ArduPlane/motor_test.cpp
index cfc640cab9859e..67dee708b50b7b 100644
--- a/ArduPlane/motor_test.cpp
+++ b/ArduPlane/motor_test.cpp
@@ -87,6 +87,14 @@ MAV_RESULT QuadPlane::mavlink_motor_test_start(mavlink_channel_t chan, uint8_t m
gcs().send_text(MAV_SEVERITY_INFO, "Must be disarmed for motor test");
return MAV_RESULT_FAILED;
}
+
+ // Check Motor test is allowed
+ char failure_msg[50] {};
+ if (!motors->motor_test_checks(ARRAY_SIZE(failure_msg), failure_msg)) {
+ gcs().send_text(MAV_SEVERITY_CRITICAL,"Motor Test: %s", failure_msg);
+ return MAV_RESULT_FAILED;
+ }
+
// if test has not started try to start it
if (!motor_test.running) {
// start test
diff --git a/ArduPlane/navigation.cpp b/ArduPlane/navigation.cpp
index 16ceb260351585..b60b442646e69d 100644
--- a/ArduPlane/navigation.cpp
+++ b/ArduPlane/navigation.cpp
@@ -58,7 +58,7 @@ void Plane::loiter_angle_update(void)
}
}
if (terrain_status_ok &&
- fabsf(altitude_agl - target_altitude.terrain_alt_cm*0.01) < 5) {
+ fabsF(altitude_agl - target_altitude.terrain_alt_cm*0.01) < 5) {
reached_target_alt = true;
} else
#endif
@@ -95,6 +95,8 @@ void Plane::navigate()
return;
}
+ check_home_alt_change();
+
// waypoint distance from plane
// ----------------------------
auto_state.wp_distance = current_loc.get_distance(next_WP_loc);
@@ -157,9 +159,9 @@ void Plane::calc_airspeed_errors()
// FBW_B/cruise airspeed target
if (!failsafe.rc_failsafe && (control_mode == &mode_fbwb || control_mode == &mode_cruise)) {
- if (g2.flight_options & FlightOptions::CRUISE_TRIM_AIRSPEED) {
+ if (flight_option_enabled(FlightOptions::CRUISE_TRIM_AIRSPEED)) {
target_airspeed_cm = aparm.airspeed_cruise_cm;
- } else if (g2.flight_options & FlightOptions::CRUISE_TRIM_THROTTLE) {
+ } else if (flight_option_enabled(FlightOptions::CRUISE_TRIM_THROTTLE)) {
float control_min = 0.0f;
float control_mid = 0.0f;
const float control_max = channel_throttle->get_range();
@@ -244,9 +246,10 @@ void Plane::calc_airspeed_errors()
// but only when this is faster than the target airspeed commanded
// above.
if (control_mode->does_auto_throttle() &&
- aparm.min_gndspeed_cm > 0 &&
- control_mode != &mode_circle) {
- int32_t min_gnd_target_airspeed = airspeed_measured*100 + groundspeed_undershoot;
+ groundspeed_undershoot_is_valid &&
+ control_mode != &mode_circle) {
+ float EAS_undershoot = (int32_t)((float)groundspeed_undershoot / ahrs.get_EAS2TAS());
+ int32_t min_gnd_target_airspeed = airspeed_measured*100 + EAS_undershoot;
if (min_gnd_target_airspeed > target_airspeed_cm) {
target_airspeed_cm = min_gnd_target_airspeed;
}
@@ -276,16 +279,18 @@ void Plane::calc_gndspeed_undershoot()
{
// Use the component of ground speed in the forward direction
// This prevents flyaway if wind takes plane backwards
- if (gps.status() >= AP_GPS::GPS_OK_FIX_2D) {
- Vector2f gndVel = ahrs.groundspeed_vector();
+ Vector3f velNED;
+ if (ahrs.have_inertial_nav() && ahrs.get_velocity_NED(velNED)) {
const Matrix3f &rotMat = ahrs.get_rotation_body_to_ned();
Vector2f yawVect = Vector2f(rotMat.a.x,rotMat.b.x);
if (!yawVect.is_zero()) {
yawVect.normalize();
- float gndSpdFwd = yawVect * gndVel;
- groundspeed_undershoot = (aparm.min_gndspeed_cm > 0) ? (aparm.min_gndspeed_cm - gndSpdFwd*100) : 0;
+ float gndSpdFwd = yawVect * velNED.xy();
+ groundspeed_undershoot_is_valid = aparm.min_gndspeed_cm > 0;
+ groundspeed_undershoot = groundspeed_undershoot_is_valid ? (aparm.min_gndspeed_cm - gndSpdFwd*100) : 0;
}
} else {
+ groundspeed_undershoot_is_valid = false;
groundspeed_undershoot = 0;
}
}
@@ -344,6 +349,9 @@ void Plane::update_loiter(uint16_t radius)
}
}
+ // the radius actually being used by the controller is required by other functions
+ loiter.radius = (float)radius;
+
update_loiter_update_nav(radius);
if (loiter.start_time_ms == 0) {
diff --git a/ArduPlane/qautotune.h b/ArduPlane/qautotune.h
index 1a1bf6e873fdc2..3ec890ac3dc3f9 100644
--- a/ArduPlane/qautotune.h
+++ b/ArduPlane/qautotune.h
@@ -8,7 +8,7 @@
#include "quadplane.h"
#ifndef QAUTOTUNE_ENABLED
- #define QAUTOTUNE_ENABLED HAL_QUADPLANE_ENABLED && !HAL_MINIMIZE_FEATURES
+ #define QAUTOTUNE_ENABLED HAL_QUADPLANE_ENABLED
#endif
#if QAUTOTUNE_ENABLED
diff --git a/ArduPlane/quadplane.cpp b/ArduPlane/quadplane.cpp
index 5d308773ca172e..5a8a895f1ef6ba 100644
--- a/ArduPlane/quadplane.cpp
+++ b/ArduPlane/quadplane.cpp
@@ -1546,7 +1546,8 @@ void SLT_Transition::update()
quadplane.assisted_flight = true;
// update transition state for vehicles using airspeed wait
if (!in_forced_transition) {
- if (transition_state != TRANSITION_AIRSPEED_WAIT) {
+ const bool show_message = transition_state != TRANSITION_AIRSPEED_WAIT || transition_start_ms == 0;
+ if (show_message) {
gcs().send_text(MAV_SEVERITY_INFO, "Transition started airspeed %.1f", (double)aspeed);
}
transition_state = TRANSITION_AIRSPEED_WAIT;
@@ -2366,7 +2367,7 @@ void QuadPlane::vtol_position_controller(void)
case QPOS_APPROACH:
if (in_vtol_mode()) {
- // this means we're not running update_transition() and
+ // this means we're not running transition update code and
// thus not doing qassist checking, force POSITION1 mode
// now. We don't expect this to trigger, it is a failsafe
// for a logic error
@@ -2406,7 +2407,7 @@ void QuadPlane::vtol_position_controller(void)
const float aspeed_threshold = MAX(plane.aparm.airspeed_min-2, assist_speed);
// run fixed wing navigation
- plane.nav_controller->update_waypoint(plane.current_loc, loc);
+ plane.nav_controller->update_waypoint(plane.auto_state.crosstrack ? plane.prev_WP_loc : plane.current_loc, loc);
// use TECS for throttle
SRV_Channels::set_output_scaled(SRV_Channel::k_throttle, plane.TECS_controller.get_throttle_demand());
@@ -2473,10 +2474,11 @@ void QuadPlane::vtol_position_controller(void)
const uint32_t min_airbrake_ms = 1000;
if (poscontrol.get_state() == QPOS_AIRBRAKE &&
poscontrol.time_since_state_start_ms() > min_airbrake_ms &&
- (aspeed < aspeed_threshold ||
- fabsf(degrees(closing_vel.angle(desired_closing_vel))) > 60 ||
- closing_speed > MAX(desired_closing_speed*1.2, desired_closing_speed+2) ||
- labs(plane.ahrs.roll_sensor - plane.nav_roll_cd) > attitude_error_threshold_cd ||
+ (aspeed < aspeed_threshold || // too low airspeed
+ fabsf(degrees(closing_vel.angle(desired_closing_vel))) > 60 || // wrong direction
+ closing_speed > MAX(desired_closing_speed*1.2, desired_closing_speed+2) || // too fast
+ closing_speed < desired_closing_speed*0.5 || // too slow ground speed
+ labs(plane.ahrs.roll_sensor - plane.nav_roll_cd) > attitude_error_threshold_cd || // bad attitude
labs(plane.ahrs.pitch_sensor - plane.nav_pitch_cd) > attitude_error_threshold_cd)) {
gcs().send_text(MAV_SEVERITY_INFO,"VTOL position1 v=%.1f d=%.1f h=%.1f dc=%.1f",
(double)groundspeed,
@@ -2488,6 +2490,18 @@ void QuadPlane::vtol_position_controller(void)
// switch to vfwd for throttle control
vel_forward.integrator = SRV_Channels::get_output_scaled(SRV_Channel::k_throttle);
+
+ // adjust the initial forward throttle based on our desired and actual closing speed
+ // this allows for significant initial forward throttle
+ // when we have a strong headwind, but low throttle in the usual case where
+ // we want to slow down ready for POSITION2
+ vel_forward.integrator = linear_interpolate(0, vel_forward.integrator,
+ closing_speed,
+ 1.2*desired_closing_speed, 0.5*desired_closing_speed);
+
+ // limit our initial forward throttle in POSITION1 to be 0.5 of cruise throttle
+ vel_forward.integrator = constrain_float(vel_forward.integrator, 0, plane.aparm.throttle_cruise*0.5);
+
vel_forward.last_ms = now_ms;
}
@@ -2949,15 +2963,15 @@ void QuadPlane::takeoff_controller(void)
// don't takeoff up until rudder is re-centered after rudder arming
if (plane.arming.last_arm_method() == AP_Arming::Method::RUDDER &&
(takeoff_last_run_ms == 0 ||
- now - takeoff_last_run_ms < 1000) &&
+ now - takeoff_last_run_ms > 1000) &&
!plane.seen_neutral_rudder &&
spool_state <= AP_Motors::DesiredSpoolState::GROUND_IDLE) {
// start motor spinning if not spinning already so user sees it is armed
set_desired_spool_state(AP_Motors::DesiredSpoolState::GROUND_IDLE);
takeoff_start_time_ms = now;
- if (now - rudder_takeoff_warn_ms > 3000) {
- gcs().send_text(MAV_SEVERITY_WARNING, "takeoff wait rudder release");
- rudder_takeoff_warn_ms = now;
+ if (now - plane.takeoff_state.rudder_takeoff_warn_ms > TAKEOFF_RUDDER_WARNING_TIMEOUT) {
+ gcs().send_text(MAV_SEVERITY_WARNING, "Takeoff waiting for rudder release");
+ plane.takeoff_state.rudder_takeoff_warn_ms = now;
}
return;
}
@@ -3226,7 +3240,8 @@ bool QuadPlane::do_vtol_land(const AP_Mission::Mission_Command& cmd)
plane.crash_state.is_crashed = false;
// also update nav_controller for status output
- plane.nav_controller->update_waypoint(plane.current_loc, plane.next_WP_loc);
+ plane.nav_controller->update_waypoint(plane.auto_state.crosstrack ? plane.prev_WP_loc : plane.current_loc,
+ plane.next_WP_loc);
poscontrol_init_approach();
return true;
@@ -4097,6 +4112,10 @@ Vector2f QuadPlane::landing_desired_closing_velocity()
float tecs_land_airspeed = plane.TECS_controller.get_land_airspeed();
if (is_positive(tecs_land_airspeed)) {
land_speed = tecs_land_airspeed;
+ } else {
+ // use half way between min airspeed and cruise if
+ // TECS_LAND_AIRSPEED not set
+ land_speed = 0.5*(land_speed+plane.aparm.airspeed_min);
}
target_speed = MIN(target_speed, eas2tas * land_speed);
@@ -4138,12 +4157,16 @@ float QuadPlane::get_land_airspeed(void)
return approach_speed;
}
+ if (qstate == QPOS_AIRBRAKE) {
+ // during airbraking ask TECS to slow us to stall speed
+ return plane.aparm.airspeed_min;
+ }
+
// calculate speed based on landing desired velocity
Vector2f vel = landing_desired_closing_velocity();
- const Vector3f wind = plane.ahrs.wind_estimate();
+ const Vector2f wind = plane.ahrs.wind_estimate().xy();
const float eas2tas = plane.ahrs.get_EAS2TAS();
- vel.x -= wind.x;
- vel.y -= wind.y;
+ vel -= wind;
vel /= eas2tas;
return vel.length();
}
@@ -4349,7 +4372,7 @@ MAV_VTOL_STATE SLT_Transition::get_mav_vtol_state() const
}
// Set FW roll and pitch limits and keep TECS informed
-void SLT_Transition::set_FW_roll_pitch(int32_t& nav_pitch_cd, int32_t& nav_roll_cd, bool& allow_stick_mixing)
+void SLT_Transition::set_FW_roll_pitch(int32_t& nav_pitch_cd, int32_t& nav_roll_cd)
{
if (quadplane.in_vtol_mode() || quadplane.in_vtol_airbrake()) {
// not in FW flight
@@ -4528,4 +4551,31 @@ bool QuadPlane::abort_landing(void)
return true;
}
+// Should we allow stick mixing from the pilot
+bool QuadPlane::allow_stick_mixing() const
+{
+ if (!available()) {
+ // Quadplane not enabled
+ return true;
+ }
+ // Ask transition logic
+ return transition->allow_stick_mixing();
+}
+
+/*
+ return true if we should disable TECS in the current flight state
+ this ensures that TECS resets when we change height in a VTOL mode
+ */
+bool QuadPlane::should_disable_TECS() const
+{
+ if (in_vtol_land_descent()) {
+ return true;
+ }
+ if (plane.control_mode == &plane.mode_guided &&
+ plane.auto_state.vtol_loiter) {
+ return true;
+ }
+ return false;
+}
+
#endif // HAL_QUADPLANE_ENABLED
diff --git a/ArduPlane/quadplane.h b/ArduPlane/quadplane.h
index d87709562c3dc6..ae65c3768e1666 100644
--- a/ArduPlane/quadplane.h
+++ b/ArduPlane/quadplane.h
@@ -47,6 +47,7 @@ class QuadPlane
friend class Tailsitter_Transition;
friend class Mode;
+ friend class ModeManual;
friend class ModeAuto;
friend class ModeRTL;
friend class ModeAvoidADSB;
@@ -180,6 +181,15 @@ class QuadPlane
*/
bool in_vtol_land_descent(void) const;
+ // Should we allow stick mixing from the pilot
+ bool allow_stick_mixing() const;
+
+ /*
+ should we disable the TECS controller?
+ only called when in an auto-throttle mode
+ */
+ bool should_disable_TECS() const;
+
private:
AP_AHRS &ahrs;
@@ -223,9 +233,6 @@ class QuadPlane
// check for quadplane assistance needed
bool should_assist(float aspeed, bool have_airspeed);
- // update transition handling
- void update_transition(void);
-
// check for an EKF yaw reset
void check_yaw_reset(void);
@@ -583,7 +590,6 @@ class QuadPlane
AP_Float maximum_takeoff_airspeed;
uint32_t takeoff_start_time_ms;
uint32_t takeoff_time_limit_ms;
- uint32_t rudder_takeoff_warn_ms;
float last_land_final_agl;
diff --git a/ArduPlane/radio.cpp b/ArduPlane/radio.cpp
index 02fa2f79e8ba4e..7a28ca11f59f1a 100644
--- a/ArduPlane/radio.cpp
+++ b/ArduPlane/radio.cpp
@@ -139,6 +139,7 @@ void Plane::rudder_arm_disarm_check()
arming.arm(AP_Arming::Method::RUDDER);
rudder_arm_timer = 0;
seen_neutral_rudder = false;
+ takeoff_state.rudder_takeoff_warn_ms = now;
}
} else {
// not at full right rudder
@@ -221,7 +222,7 @@ int16_t Plane::rudder_input(void)
return 0;
}
- if ((g2.flight_options & FlightOptions::DIRECT_RUDDER_ONLY) &&
+ if ((flight_option_enabled(FlightOptions::DIRECT_RUDDER_ONLY)) &&
!(control_mode == &mode_manual || control_mode == &mode_stabilize || control_mode == &mode_acro)) {
// the user does not want any input except in these modes
return 0;
@@ -277,7 +278,10 @@ void Plane::control_failsafe()
}
}
- if (ThrFailsafe(g.throttle_fs_enabled.get()) != ThrFailsafe::Enabled) {
+ const bool allow_failsafe_bypass = !arming.is_armed() && !is_flying() && (rc().enabled_protocols() != 0);
+ const bool has_had_input = rc().has_had_rc_receiver() || rc().has_had_rc_override();
+ if ((ThrFailsafe(g.throttle_fs_enabled.get()) != ThrFailsafe::Enabled) || (allow_failsafe_bypass && !has_had_input)) {
+ // If not flying and disarmed don't trigger failsafe until RC has been received for the fist time
return;
}
@@ -435,8 +439,8 @@ bool Plane::throttle_at_zero(void) const
/* true if throttle stick is at idle position...if throttle trim has been moved
to center stick area in conjunction with sprung throttle, cannot use in_trim, must use rc_min
*/
- if (((!(g2.flight_options & FlightOptions::CENTER_THROTTLE_TRIM) && channel_throttle->in_trim_dz()) ||
- (g2.flight_options & FlightOptions::CENTER_THROTTLE_TRIM && channel_throttle->in_min_dz()))) {
+ if (((!(flight_option_enabled(FlightOptions::CENTER_THROTTLE_TRIM) && channel_throttle->in_trim_dz())) ||
+ (flight_option_enabled(FlightOptions::CENTER_THROTTLE_TRIM)&& channel_throttle->in_min_dz()))) {
return true;
}
return false;
diff --git a/ArduPlane/reverse_thrust.cpp b/ArduPlane/reverse_thrust.cpp
index 04033d00f665ac..f64f37b276d6b3 100644
--- a/ArduPlane/reverse_thrust.cpp
+++ b/ArduPlane/reverse_thrust.cpp
@@ -144,7 +144,7 @@ float Plane::get_throttle_input(bool no_deadzone) const
float Plane::get_adjusted_throttle_input(bool no_deadzone) const
{
if ((plane.channel_throttle->get_type() != RC_Channel::ControlType::RANGE) ||
- (g2.flight_options & FlightOptions::CENTER_THROTTLE_TRIM) == 0) {
+ (flight_option_enabled(FlightOptions::CENTER_THROTTLE_TRIM)) == 0) {
return get_throttle_input(no_deadzone);
}
float ret = channel_throttle->get_range() * throttle_curve(aparm.throttle_cruise * 0.01, 0, 0.5 + 0.5*channel_throttle->norm_input());
diff --git a/ArduPlane/servos.cpp b/ArduPlane/servos.cpp
index 11f50fabd8494c..ae6f3c69c5fc17 100644
--- a/ArduPlane/servos.cpp
+++ b/ArduPlane/servos.cpp
@@ -376,32 +376,6 @@ void Plane::set_servos_idle(void)
SRV_Channels::output_ch_all();
}
-/*
- pass through channels in manual mode
- */
-void Plane::set_servos_manual_passthrough(void)
-{
- SRV_Channels::set_output_scaled(SRV_Channel::k_aileron, roll_in_expo(false));
- SRV_Channels::set_output_scaled(SRV_Channel::k_elevator, pitch_in_expo(false));
- SRV_Channels::set_output_scaled(SRV_Channel::k_rudder, rudder_in_expo(false));
- float throttle = get_throttle_input(true);
- SRV_Channels::set_output_scaled(SRV_Channel::k_throttle, throttle);
-
-#if HAL_QUADPLANE_ENABLED
- if (quadplane.available() && quadplane.option_is_set(QuadPlane::OPTION::IDLE_GOV_MANUAL)) {
- // for quadplanes it can be useful to run the idle governor in MANUAL mode
- // as it prevents the VTOL motors from running
- int8_t min_throttle = aparm.throttle_min.get();
-
- // apply idle governor
-#if AP_ICENGINE_ENABLED
- g2.ice_control.update_idle_governor(min_throttle);
-#endif
- throttle = MAX(throttle, min_throttle);
- SRV_Channels::set_output_scaled(SRV_Channel::k_throttle, throttle);
- }
-#endif
-}
/*
Scale the throttle to conpensate for battery voltage drop
@@ -572,7 +546,7 @@ void Plane::set_servos_controlled(void)
control_mode == &mode_autotune) {
// a manual throttle mode
if (!rc().has_valid_input()) {
- SRV_Channels::set_output_scaled(SRV_Channel::k_throttle, 0.0);
+ SRV_Channels::set_output_scaled(SRV_Channel::k_throttle, g.throttle_passthru_stabilize ? 0.0 : MAX(min_throttle,0));
} else if (g.throttle_passthru_stabilize) {
// manual pass through of throttle while in FBWA or
// STABILIZE mode with THR_PASS_STAB set
@@ -845,34 +819,7 @@ void Plane::set_servos(void)
return;
}
- /*
- see if we are doing ground steering.
- */
- if (!steering_control.ground_steering) {
- // we are not at an altitude for ground steering. Set the nose
- // wheel to the rudder just in case the barometer has drifted
- // a lot
- steering_control.steering = steering_control.rudder;
- } else if (!SRV_Channels::function_assigned(SRV_Channel::k_steering)) {
- // we are within the ground steering altitude but don't have a
- // dedicated steering channel. Set the rudder to the ground
- // steering output
- steering_control.rudder = steering_control.steering;
- }
-
- // clear ground_steering to ensure manual control if the yaw stabilizer doesn't run
- steering_control.ground_steering = false;
-
- if (control_mode == &mode_training) {
- steering_control.rudder = rudder_in_expo(false);
- }
-
- SRV_Channels::set_output_scaled(SRV_Channel::k_rudder, steering_control.rudder);
- SRV_Channels::set_output_scaled(SRV_Channel::k_steering, steering_control.steering);
-
- if (control_mode == &mode_manual) {
- set_servos_manual_passthrough();
- } else {
+ if (control_mode != &mode_manual) {
set_servos_controlled();
}
@@ -968,6 +915,23 @@ void Plane::landing_neutral_control_surface_servos(void)
}
+/*
+ sets rudder/vtail , and elevon to indicator positions that we are in a rudder arming waiting for neutral stick state
+*/
+void Plane::indicate_waiting_for_rud_neutral_to_takeoff(void)
+{
+ if (takeoff_state.waiting_for_rudder_neutral) {
+ SRV_Channels::set_output_scaled(SRV_Channel::k_rudder, 0);
+ channel_function_mixer(SRV_Channel::k_rudder, SRV_Channel::k_elevator, SRV_Channel::k_vtail_right, SRV_Channel::k_vtail_left);
+ if (!SRV_Channels::function_assigned(SRV_Channel::k_rudder) && !SRV_Channels::function_assigned(SRV_Channel::k_vtail_left)) {
+ // if no rudder indication possible, neutral elevons during wait becuase on takeoff stance they are usually both full up
+ SRV_Channels::set_output_scaled(SRV_Channel::k_elevon_right, 0);
+ SRV_Channels::set_output_scaled(SRV_Channel::k_elevon_left, 0);
+ }
+ }
+}
+
+
/*
run configured output mixer. This takes calculated servo_out values
for each channel and calculates PWM values, then pushes them to
@@ -998,6 +962,11 @@ void Plane::servos_output(void)
// set control surface servos to neutral
landing_neutral_control_surface_servos();
+
+ // set rudder arm waiting for neutral control throws (rudder neutral, aileron/rt vtail/rt elevon to full right)
+ if (flight_option_enabled(FlightOptions::INDICATE_WAITING_FOR_RUDDER_NEUTRAL)) {
+ indicate_waiting_for_rud_neutral_to_takeoff();
+ }
// support MANUAL_RCMASK
if (g2.manual_rc_mask.get() != 0 && control_mode == &mode_manual) {
diff --git a/ArduPlane/system.cpp b/ArduPlane/system.cpp
index 149aa273e36587..6f21b75abc7519 100644
--- a/ArduPlane/system.cpp
+++ b/ArduPlane/system.cpp
@@ -42,17 +42,15 @@ void Plane::init_ardupilot()
#endif
rc().init();
+#if AP_RELAY_ENABLED
relay.init();
+#endif
// initialise notify system
notify.init();
notify_mode(*control_mode);
init_rc_out_main();
-
- // keep a record of how many resets have happened. This can be
- // used to detect in-flight resets
- g.num_resets.set_and_save(g.num_resets+1);
// init baro
barometer.init();
@@ -142,7 +140,7 @@ void Plane::init_ardupilot()
// set the correct flight mode
// ---------------------------
- reset_control_switch();
+ rc().reset_mode_switch();
// initialise sensor
#if AP_OPTICALFLOW_ENABLED
@@ -197,11 +195,6 @@ void Plane::startup_ground(void)
// reset last heartbeat time, so we don't trigger failsafe on slow
// startup
gcs().sysid_myggcs_seen(AP_HAL::millis());
-
- // we don't want writes to the serial port to cause us to pause
- // mid-flight, so set the serial ports non-blocking once we are
- // ready to fly
- serial_manager.set_blocking_writes_all(false);
}
@@ -225,6 +218,40 @@ static bool mode_reason_is_landing_sequence(const ModeReason reason)
}
#endif // AP_FENCE_ENABLED
+// Check if this mode can be entered from the GCS
+bool Plane::gcs_mode_enabled(const Mode::Number mode_num) const
+{
+ // List of modes that can be blocked, index is bit number in parameter bitmask
+ static const uint8_t mode_list [] {
+ (uint8_t)Mode::Number::MANUAL,
+ (uint8_t)Mode::Number::CIRCLE,
+ (uint8_t)Mode::Number::STABILIZE,
+ (uint8_t)Mode::Number::TRAINING,
+ (uint8_t)Mode::Number::ACRO,
+ (uint8_t)Mode::Number::FLY_BY_WIRE_A,
+ (uint8_t)Mode::Number::FLY_BY_WIRE_B,
+ (uint8_t)Mode::Number::CRUISE,
+ (uint8_t)Mode::Number::AUTOTUNE,
+ (uint8_t)Mode::Number::AUTO,
+ (uint8_t)Mode::Number::LOITER,
+ (uint8_t)Mode::Number::TAKEOFF,
+ (uint8_t)Mode::Number::AVOID_ADSB,
+ (uint8_t)Mode::Number::GUIDED,
+ (uint8_t)Mode::Number::THERMAL,
+#if HAL_QUADPLANE_ENABLED
+ (uint8_t)Mode::Number::QSTABILIZE,
+ (uint8_t)Mode::Number::QHOVER,
+ (uint8_t)Mode::Number::QLOITER,
+ (uint8_t)Mode::Number::QACRO,
+#if QAUTOTUNE_ENABLED
+ (uint8_t)Mode::Number::QAUTOTUNE
+#endif
+#endif
+ };
+
+ return !block_GCS_mode_change((uint8_t)mode_num, mode_list, ARRAY_SIZE(mode_list));
+}
+
bool Plane::set_mode(Mode &new_mode, const ModeReason reason)
{
@@ -274,6 +301,12 @@ bool Plane::set_mode(Mode &new_mode, const ModeReason reason)
}
#endif
+ // Check if GCS mode change is disabled via parameter
+ if ((reason == ModeReason::GCS_COMMAND) && !gcs_mode_enabled(new_mode.mode_number())) {
+ gcs().send_text(MAV_SEVERITY_NOTICE,"Mode change to %s denied, GCS entry disabled (FLTMODE_GCSBLOCK)", new_mode.name());
+ return false;
+ }
+
// backup current control_mode and previous_mode
Mode &old_previous_mode = *previous_mode;
Mode &old_mode = *control_mode;
diff --git a/ArduPlane/tailsitter.cpp b/ArduPlane/tailsitter.cpp
index 815aac3c65ed01..3c8fe77d728402 100644
--- a/ArduPlane/tailsitter.cpp
+++ b/ArduPlane/tailsitter.cpp
@@ -302,11 +302,11 @@ void Tailsitter::output(void)
*/
if (!is_negative(transition_throttle_vtol)) {
// Q_TAILSIT_THR_VT is positive use it until transition is complete
- throttle = motors->actuator_to_thrust(MIN(transition_throttle_vtol*0.01,1.0));
+ throttle = motors->thr_lin.actuator_to_thrust(MIN(transition_throttle_vtol*0.01,1.0));
} else {
throttle = motors->get_throttle_hover();
// work out equivelent motors throttle level for cruise
- throttle = MAX(throttle,motors->actuator_to_thrust(plane.aparm.throttle_cruise.get() * 0.01));
+ throttle = MAX(throttle,motors->thr_lin.actuator_to_thrust(plane.aparm.throttle_cruise.get() * 0.01));
}
SRV_Channels::set_output_scaled(SRV_Channel::k_rudder, 0.0);
@@ -321,7 +321,7 @@ void Tailsitter::output(void)
// convert the hover throttle to the same output that would result if used via AP_Motors
// apply expo, battery scaling and SPIN min/max.
- throttle = motors->thrust_to_actuator(throttle);
+ throttle = motors->thr_lin.thrust_to_actuator(throttle);
// override AP_MotorsTailsitter throttles during back transition
@@ -880,7 +880,7 @@ bool Tailsitter_Transition::show_vtol_view() const
return show_vtol;
}
-void Tailsitter_Transition::set_FW_roll_pitch(int32_t& nav_pitch_cd, int32_t& nav_roll_cd, bool& allow_stick_mixing)
+void Tailsitter_Transition::set_FW_roll_pitch(int32_t& nav_pitch_cd, int32_t& nav_roll_cd)
{
uint32_t now = AP_HAL::millis();
if (tailsitter.in_vtol_transition(now)) {
@@ -892,7 +892,6 @@ void Tailsitter_Transition::set_FW_roll_pitch(int32_t& nav_pitch_cd, int32_t& na
// multiply by 0.1 to convert (degrees/second * milliseconds) to centi degrees
nav_pitch_cd = constrain_float(vtol_transition_initial_pitch + (tailsitter.transition_rate_vtol * dt) * 0.1f, -8500, 8500);
nav_roll_cd = 0;
- allow_stick_mixing = false;
} else if (transition_state == TRANSITION_DONE) {
// still in FW, reset transition starting point
@@ -908,12 +907,24 @@ void Tailsitter_Transition::set_FW_roll_pitch(int32_t& nav_pitch_cd, int32_t& na
} else {
nav_pitch_cd = pitch_limit_cd;
nav_roll_cd = 0;
- allow_stick_mixing = false;
}
}
}
}
+bool Tailsitter_Transition::allow_stick_mixing() const
+{
+ // Transitioning into VTOL flight, inital pitch up
+ if (tailsitter.in_vtol_transition()) {
+ return false;
+ }
+ // Transitioning into fixed wing flight, leveling off
+ if ((transition_state == TRANSITION_DONE) && (fw_limit_start_ms != 0)) {
+ return false;
+ }
+ return true;
+}
+
bool Tailsitter_Transition::set_VTOL_roll_pitch_limit(int32_t& nav_roll_cd, int32_t& nav_pitch_cd)
{
if (vtol_limit_start_ms == 0) {
diff --git a/ArduPlane/tailsitter.h b/ArduPlane/tailsitter.h
index 1d91fa49e589b7..4f2ff33c3ba370 100644
--- a/ArduPlane/tailsitter.h
+++ b/ArduPlane/tailsitter.h
@@ -159,7 +159,9 @@ friend class Tailsitter;
bool show_vtol_view() const override;
- void set_FW_roll_pitch(int32_t& nav_pitch_cd, int32_t& nav_roll_cd, bool& allow_stick_mixing) override;
+ void set_FW_roll_pitch(int32_t& nav_pitch_cd, int32_t& nav_roll_cd) override;
+
+ bool allow_stick_mixing() const override;
MAV_VTOL_STATE get_mav_vtol_state() const override;
diff --git a/ArduPlane/takeoff.cpp b/ArduPlane/takeoff.cpp
index 31aeab02295f07..2b316fe8e0b0ef 100644
--- a/ArduPlane/takeoff.cpp
+++ b/ArduPlane/takeoff.cpp
@@ -29,6 +29,24 @@ bool Plane::auto_takeoff_check(void)
}
takeoff_state.last_check_ms = now;
+
+ //check if waiting for rudder neutral after rudder arm
+ if (plane.arming.last_arm_method() == AP_Arming::Method::RUDDER &&
+ !seen_neutral_rudder) {
+ // we were armed with rudder but have not seen rudder neutral yet
+ takeoff_state.waiting_for_rudder_neutral = true;
+ // warn if we have been waiting a long time
+ if (now - takeoff_state.rudder_takeoff_warn_ms > TAKEOFF_RUDDER_WARNING_TIMEOUT) {
+ gcs().send_text(MAV_SEVERITY_WARNING, "Takeoff waiting for rudder release");
+ takeoff_state.rudder_takeoff_warn_ms = now;
+ }
+ // since we are still waiting, dont takeoff
+ return false;
+ } else {
+ // we did not arm by rudder or rudder has returned to neutral
+ // make sure we dont indicate we are in the waiting state with servo position indicator
+ takeoff_state.waiting_for_rudder_neutral = false;
+ }
// Check for bad GPS
if (gps.status() < AP_GPS::GPS_OK_FIX_3D) {
@@ -36,7 +54,7 @@ bool Plane::auto_takeoff_check(void)
return false;
}
- bool do_takeoff_attitude_check = !(g2.flight_options & FlightOptions::DISABLE_TOFF_ATTITUDE_CHK);
+ bool do_takeoff_attitude_check = !(flight_option_enabled(FlightOptions::DISABLE_TOFF_ATTITUDE_CHK));
#if HAL_QUADPLANE_ENABLED
// disable attitude check on tailsitters
do_takeoff_attitude_check = !quadplane.tailsitter.enabled();
diff --git a/ArduPlane/tiltrotor.cpp b/ArduPlane/tiltrotor.cpp
index 5591fb3b6d1733..0c40e47d1be95f 100644
--- a/ArduPlane/tiltrotor.cpp
+++ b/ArduPlane/tiltrotor.cpp
@@ -54,7 +54,7 @@ const AP_Param::GroupInfo Tiltrotor::var_info[] = {
// @Param: YAW_ANGLE
// @DisplayName: Tilt minimum angle for vectored yaw
- // @Description: This is the angle of the tilt servos when in VTOL mode and at minimum output. This needs to be set for Q_TILT_TYPE=3 to enable vectored control for yaw of tricopter tilt quadplanes. This is also used to limit the forwards travel of bicopter tilts when in VTOL modes
+ // @Description: This is the angle of the tilt servos when in VTOL mode and at minimum output (fully back). This needs to be set in addition to Q_TILT_TYPE=2, to enable vectored control for yaw in tilt quadplanes. This is also used to limit the forward travel of bicopter tilts(Q_TILT_TYPE=3) when in VTOL modes.
// @Range: 0 30
AP_GROUPINFO("YAW_ANGLE", 7, Tiltrotor, tilt_yaw_angle, 0),
diff --git a/ArduPlane/transition.h b/ArduPlane/transition.h
index 9ddc1d5b5f5790..b31e45ff040ece 100644
--- a/ArduPlane/transition.h
+++ b/ArduPlane/transition.h
@@ -40,7 +40,7 @@ class Transition
virtual bool show_vtol_view() const = 0;
- virtual void set_FW_roll_pitch(int32_t& nav_pitch_cd, int32_t& nav_roll_cd, bool& allow_stick_mixing) {};
+ virtual void set_FW_roll_pitch(int32_t& nav_pitch_cd, int32_t& nav_roll_cd) {};
virtual bool set_FW_roll_limit(int32_t& roll_limit_cd) { return false; }
@@ -56,6 +56,8 @@ class Transition
virtual void set_last_fw_pitch(void) {}
+ virtual bool allow_stick_mixing() const { return true; }
+
protected:
// refences for convenience
@@ -87,7 +89,7 @@ class SLT_Transition : public Transition
bool show_vtol_view() const override;
- void set_FW_roll_pitch(int32_t& nav_pitch_cd, int32_t& nav_roll_cd, bool& allow_stick_mixing) override;
+ void set_FW_roll_pitch(int32_t& nav_pitch_cd, int32_t& nav_roll_cd) override;
bool set_FW_roll_limit(int32_t& roll_limit_cd) override;
diff --git a/ArduPlane/version.h b/ArduPlane/version.h
index 59de573b2b2254..cdf466f7155fb6 100644
--- a/ArduPlane/version.h
+++ b/ArduPlane/version.h
@@ -6,13 +6,13 @@
#include "ap_version.h"
-#define THISFIRMWARE "ArduPlane V4.4.0-dev"
+#define THISFIRMWARE "ArduPlane V4.5.0-dev"
// the following line is parsed by the autotest scripts
-#define FIRMWARE_VERSION 4,4,0,FIRMWARE_VERSION_TYPE_DEV
+#define FIRMWARE_VERSION 4,5,0,FIRMWARE_VERSION_TYPE_DEV
#define FW_MAJOR 4
-#define FW_MINOR 4
+#define FW_MINOR 5
#define FW_PATCH 0
#define FW_TYPE FIRMWARE_VERSION_TYPE_DEV
diff --git a/ArduPlane/wscript b/ArduPlane/wscript
index 1386bd7b7c1c9d..4dd670ccc34a52 100644
--- a/ArduPlane/wscript
+++ b/ArduPlane/wscript
@@ -28,7 +28,6 @@ def build(bld):
'AP_Devo_Telem',
'AP_OSD',
'AC_AutoTune',
- 'AP_KDECAN',
'AP_Follow',
],
)
diff --git a/ArduSub/AP_Arming_Sub.cpp b/ArduSub/AP_Arming_Sub.cpp
index 7eb1589a8178d4..84789a10f664cc 100644
--- a/ArduSub/AP_Arming_Sub.cpp
+++ b/ArduSub/AP_Arming_Sub.cpp
@@ -134,7 +134,7 @@ bool AP_Arming_Sub::arm(AP_Arming::Method method, bool do_arming_checks)
sub.motors.armed(true);
// log flight mode in case it was changed while vehicle was disarmed
- AP::logger().Write_Mode(sub.control_mode, sub.control_mode_reason);
+ AP::logger().Write_Mode((uint8_t)sub.control_mode, sub.control_mode_reason);
// reenable failsafe
sub.mainloop_failsafe_enable();
diff --git a/ArduSub/ArduSub.cpp b/ArduSub/ArduSub.cpp
index 918a189eb34130..b8ded91fddc343 100644
--- a/ArduSub/ArduSub.cpp
+++ b/ArduSub/ArduSub.cpp
@@ -80,7 +80,6 @@ const AP_Scheduler::Task Sub::scheduler_tasks[] = {
SCHED_TASK(three_hz_loop, 3, 75, 21),
SCHED_TASK(update_turn_counter, 10, 50, 24),
SCHED_TASK_CLASS(AP_Baro, &sub.barometer, accumulate, 50, 90, 27),
- SCHED_TASK_CLASS(AP_Notify, &sub.notify, update, 50, 90, 30),
SCHED_TASK(one_hz_loop, 1, 100, 33),
SCHED_TASK_CLASS(GCS, (GCS*)&sub._gcs, update_receive, 400, 180, 36),
SCHED_TASK_CLASS(GCS, (GCS*)&sub._gcs, update_send, 400, 550, 39),
@@ -102,6 +101,9 @@ const AP_Scheduler::Task Sub::scheduler_tasks[] = {
#if AP_GRIPPER_ENABLED
SCHED_TASK_CLASS(AP_Gripper, &sub.g2.gripper, update, 10, 75, 75),
#endif
+#if STATS_ENABLED == ENABLED
+ SCHED_TASK(stats_update, 1, 200, 76),
+#endif
#ifdef USERHOOK_FASTLOOP
SCHED_TASK(userhook_FastLoop, 100, 75, 78),
#endif
@@ -138,7 +140,7 @@ void Sub::run_rate_controller()
pos_control.set_dt(last_loop_time_s);
//don't run rate controller in manual or motordetection modes
- if (control_mode != MANUAL && control_mode != MOTOR_DETECT) {
+ if (control_mode != Mode::Number::MANUAL && control_mode != Mode::Number::MOTOR_DETECT) {
// run low level rate controllers that only require IMU data and set loop time
attitude_control.rate_controller_run();
}
@@ -199,7 +201,7 @@ void Sub::ten_hz_logging_loop()
if (should_log(MASK_LOG_RCOUT)) {
logger.Write_RCOUT();
}
- if (should_log(MASK_LOG_NTUN) && (mode_requires_GPS(control_mode) || !mode_has_manual_throttle(control_mode))) {
+ if (should_log(MASK_LOG_NTUN) && (sub.flightmode->requires_GPS() || !sub.flightmode->has_manual_throttle())) {
pos_control.write_log();
}
if (should_log(MASK_LOG_IMU) || should_log(MASK_LOG_IMU_FAST) || should_log(MASK_LOG_IMU_RAW)) {
@@ -208,6 +210,11 @@ void Sub::ten_hz_logging_loop()
if (should_log(MASK_LOG_CTUN)) {
attitude_control.control_monitor_log();
}
+#if HAL_MOUNT_ENABLED
+ if (should_log(MASK_LOG_CAMERA)) {
+ camera_mount.write_log();
+ }
+#endif
}
// twentyfive_hz_logging_loop
@@ -253,7 +260,9 @@ void Sub::three_hz_loop()
fence_check();
#endif // AP_FENCE_ENABLED
+#if AP_SERVORELAYEVENTS_ENABLED
ServoRelayEvents.update_events();
+#endif
}
// one_hz_loop - runs at 1Hz
@@ -346,4 +355,15 @@ bool Sub::get_wp_crosstrack_error_m(float &xtrack_error) const
return true;
}
+#if STATS_ENABLED == ENABLED
+/*
+ update AP_Stats
+*/
+void Sub::stats_update(void)
+{
+ g2.stats.set_flying(motors.armed());
+ g2.stats.update();
+}
+#endif
+
AP_HAL_MAIN_CALLBACKS(&sub);
diff --git a/ArduSub/GCS_Mavlink.cpp b/ArduSub/GCS_Mavlink.cpp
index f078629041daf0..a753490e8eba13 100644
--- a/ArduSub/GCS_Mavlink.cpp
+++ b/ArduSub/GCS_Mavlink.cpp
@@ -21,10 +21,10 @@ MAV_MODE GCS_MAVLINK_Sub::base_mode() const
// the APM flight mode and has a well defined meaning in the
// ArduPlane documentation
switch (sub.control_mode) {
- case AUTO:
- case GUIDED:
- case CIRCLE:
- case POSHOLD:
+ case Mode::Number::AUTO:
+ case Mode::Number::GUIDED:
+ case Mode::Number::CIRCLE:
+ case Mode::Number::POSHOLD:
_base_mode |= MAV_MODE_FLAG_GUIDED_ENABLED;
// note that MAV_MODE_FLAG_AUTO_ENABLED does not match what
// APM does in any mode, as that is defined as "system finds its own goal
@@ -50,7 +50,7 @@ MAV_MODE GCS_MAVLINK_Sub::base_mode() const
uint32_t GCS_Sub::custom_mode() const
{
- return sub.control_mode;
+ return (uint32_t)sub.control_mode;
}
MAV_STATE GCS_MAVLINK_Sub::vehicle_system_status() const
@@ -448,7 +448,7 @@ MAV_RESULT GCS_MAVLINK_Sub::handle_command_do_set_roi(const Location &roi_loc)
if (!roi_loc.check_latlng()) {
return MAV_RESULT_FAILED;
}
- sub.set_auto_yaw_roi(roi_loc);
+ sub.mode_auto.set_auto_yaw_roi(roi_loc);
return MAV_RESULT_ACCEPTED;
}
@@ -460,17 +460,17 @@ bool GCS_MAVLINK_Sub::set_home(const Location& loc, bool _lock) {
}
-MAV_RESULT GCS_MAVLINK_Sub::handle_command_long_packet(const mavlink_command_long_t &packet)
+MAV_RESULT GCS_MAVLINK_Sub::handle_command_long_packet(const mavlink_command_long_t &packet, const mavlink_message_t &msg)
{
switch (packet.command) {
case MAV_CMD_NAV_LOITER_UNLIM:
- if (!sub.set_mode(POSHOLD, ModeReason::GCS_COMMAND)) {
+ if (!sub.set_mode(Mode::Number::POSHOLD, ModeReason::GCS_COMMAND)) {
return MAV_RESULT_FAILED;
}
return MAV_RESULT_ACCEPTED;
case MAV_CMD_NAV_LAND:
- if (!sub.set_mode(SURFACE, ModeReason::GCS_COMMAND)) {
+ if (!sub.set_mode(Mode::Number::SURFACE, ModeReason::GCS_COMMAND)) {
return MAV_RESULT_FAILED;
}
return MAV_RESULT_ACCEPTED;
@@ -483,7 +483,7 @@ MAV_RESULT GCS_MAVLINK_Sub::handle_command_long_packet(const mavlink_command_lon
if ((packet.param1 >= 0.0f) &&
(packet.param1 <= 360.0f) &&
(is_zero(packet.param4) || is_equal(packet.param4,1.0f))) {
- sub.set_auto_yaw_look_at_heading(packet.param1, packet.param2, (int8_t)packet.param3, (uint8_t)packet.param4);
+ sub.mode_auto.set_auto_yaw_look_at_heading(packet.param1, packet.param2, (int8_t)packet.param3, (uint8_t)packet.param4);
return MAV_RESULT_ACCEPTED;
}
return MAV_RESULT_FAILED;
@@ -500,7 +500,7 @@ MAV_RESULT GCS_MAVLINK_Sub::handle_command_long_packet(const mavlink_command_lon
return MAV_RESULT_FAILED;
case MAV_CMD_MISSION_START:
- if (sub.motors.armed() && sub.set_mode(AUTO, ModeReason::GCS_COMMAND)) {
+ if (sub.motors.armed() && sub.set_mode(Mode::Number::AUTO, ModeReason::GCS_COMMAND)) {
return MAV_RESULT_ACCEPTED;
}
return MAV_RESULT_FAILED;
@@ -516,7 +516,7 @@ MAV_RESULT GCS_MAVLINK_Sub::handle_command_long_packet(const mavlink_command_lon
return MAV_RESULT_ACCEPTED;
default:
- return GCS_MAVLINK::handle_command_long_packet(packet);
+ return GCS_MAVLINK::handle_command_long_packet(packet, msg);
}
}
@@ -588,7 +588,7 @@ void GCS_MAVLINK_Sub::handleMessage(const mavlink_message_t &msg)
// descend at up to WPNAV_SPEED_DN
climb_rate_cms = (packet.thrust - 0.5f) * 2.0f * sub.wp_nav.get_default_speed_down();
}
- sub.guided_set_angle(Quaternion(packet.q[0],packet.q[1],packet.q[2],packet.q[3]), climb_rate_cms);
+ sub.mode_guided.guided_set_angle(Quaternion(packet.q[0],packet.q[1],packet.q[2],packet.q[3]), climb_rate_cms);
break;
}
@@ -598,7 +598,7 @@ void GCS_MAVLINK_Sub::handleMessage(const mavlink_message_t &msg)
mavlink_msg_set_position_target_local_ned_decode(&msg, &packet);
// exit if vehicle is not in Guided mode or Auto-Guided mode
- if ((sub.control_mode != GUIDED) && !(sub.control_mode == AUTO && sub.auto_mode == Auto_NavGuided)) {
+ if ((sub.control_mode != Mode::Number::GUIDED) && !(sub.control_mode == Mode::Number::AUTO && sub.auto_mode == Auto_NavGuided)) {
break;
}
@@ -606,34 +606,32 @@ void GCS_MAVLINK_Sub::handleMessage(const mavlink_message_t &msg)
if (packet.coordinate_frame != MAV_FRAME_LOCAL_NED &&
packet.coordinate_frame != MAV_FRAME_LOCAL_OFFSET_NED &&
packet.coordinate_frame != MAV_FRAME_BODY_NED &&
- packet.coordinate_frame != MAV_FRAME_BODY_OFFSET_NED) {
+ packet.coordinate_frame != MAV_FRAME_BODY_OFFSET_NED &&
+ packet.coordinate_frame != MAV_FRAME_BODY_FRD) {
break;
}
bool pos_ignore = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_POS_IGNORE;
bool vel_ignore = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_VEL_IGNORE;
bool acc_ignore = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_ACC_IGNORE;
-
- /*
- * for future use:
- * bool force = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_FORCE;
- * bool yaw_ignore = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_YAW_IGNORE;
- * bool yaw_rate_ignore = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_YAW_RATE_IGNORE;
- */
+ bool yaw_ignore = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_YAW_IGNORE;
+ bool yaw_rate_ignore = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_YAW_RATE_IGNORE;
// prepare position
Vector3f pos_vector;
if (!pos_ignore) {
// convert to cm
pos_vector = Vector3f(packet.x * 100.0f, packet.y * 100.0f, -packet.z * 100.0f);
- // rotate to body-frame if necessary
+ // rotate from body-frame if necessary
if (packet.coordinate_frame == MAV_FRAME_BODY_NED ||
+ packet.coordinate_frame == MAV_FRAME_BODY_FRD ||
packet.coordinate_frame == MAV_FRAME_BODY_OFFSET_NED) {
sub.rotate_body_frame_to_NE(pos_vector.x, pos_vector.y);
}
// add body offset if necessary
if (packet.coordinate_frame == MAV_FRAME_LOCAL_OFFSET_NED ||
packet.coordinate_frame == MAV_FRAME_BODY_NED ||
+ packet.coordinate_frame == MAV_FRAME_BODY_FRD ||
packet.coordinate_frame == MAV_FRAME_BODY_OFFSET_NED) {
pos_vector += sub.inertial_nav.get_position_neu_cm();
}
@@ -644,19 +642,31 @@ void GCS_MAVLINK_Sub::handleMessage(const mavlink_message_t &msg)
if (!vel_ignore) {
// convert to cm
vel_vector = Vector3f(packet.vx * 100.0f, packet.vy * 100.0f, -packet.vz * 100.0f);
- // rotate to body-frame if necessary
- if (packet.coordinate_frame == MAV_FRAME_BODY_NED || packet.coordinate_frame == MAV_FRAME_BODY_OFFSET_NED) {
+ // rotate from body-frame if necessary
+ if (packet.coordinate_frame == MAV_FRAME_BODY_NED || packet.coordinate_frame == MAV_FRAME_BODY_FRD || packet.coordinate_frame == MAV_FRAME_BODY_OFFSET_NED) {
sub.rotate_body_frame_to_NE(vel_vector.x, vel_vector.y);
}
}
+ // prepare yaw
+ float yaw_cd = 0.0f;
+ bool yaw_relative = false;
+ float yaw_rate_cds = 0.0f;
+ if (!yaw_ignore) {
+ yaw_cd = ToDeg(packet.yaw) * 100.0f;
+ yaw_relative = packet.coordinate_frame == MAV_FRAME_BODY_OFFSET_NED;
+ }
+ if (!yaw_rate_ignore) {
+ yaw_rate_cds = ToDeg(packet.yaw_rate) * 100.0f;
+ }
+
// send request
if (!pos_ignore && !vel_ignore && acc_ignore) {
- sub.guided_set_destination_posvel(pos_vector, vel_vector);
+ sub.mode_guided.guided_set_destination_posvel(pos_vector, vel_vector, !yaw_ignore, yaw_cd, !yaw_rate_ignore, yaw_rate_cds, yaw_relative);
} else if (pos_ignore && !vel_ignore && acc_ignore) {
- sub.guided_set_velocity(vel_vector);
+ sub.mode_guided.guided_set_velocity(vel_vector, !yaw_ignore, yaw_cd, !yaw_rate_ignore, yaw_rate_cds, yaw_relative);
} else if (!pos_ignore && vel_ignore && acc_ignore) {
- sub.guided_set_destination(pos_vector);
+ sub.mode_guided.guided_set_destination(pos_vector, !yaw_ignore, yaw_cd, !yaw_rate_ignore, yaw_rate_cds, yaw_relative);
}
break;
@@ -668,9 +678,9 @@ void GCS_MAVLINK_Sub::handleMessage(const mavlink_message_t &msg)
mavlink_msg_set_position_target_global_int_decode(&msg, &packet);
// exit if vehicle is not in Guided, Auto-Guided, or Depth Hold modes
- if ((sub.control_mode != GUIDED)
- && !(sub.control_mode == AUTO && sub.auto_mode == Auto_NavGuided)
- && !(sub.control_mode == ALT_HOLD)) {
+ if ((sub.control_mode != Mode::Number::GUIDED)
+ && !(sub.control_mode == Mode::Number::AUTO && sub.auto_mode == Auto_NavGuided)
+ && !(sub.control_mode == Mode::Number::ALT_HOLD)) {
break;
}
@@ -686,7 +696,7 @@ void GCS_MAVLINK_Sub::handleMessage(const mavlink_message_t &msg)
* bool yaw_rate_ignore = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_YAW_RATE_IGNORE;
*/
- if (!z_ignore && sub.control_mode == ALT_HOLD) { // Control only target depth when in ALT_HOLD
+ if (!z_ignore && sub.control_mode == Mode::Number::ALT_HOLD) { // Control only target depth when in ALT_HOLD
sub.pos_control.set_pos_target_z_cm(packet.alt*100);
break;
}
@@ -715,11 +725,11 @@ void GCS_MAVLINK_Sub::handleMessage(const mavlink_message_t &msg)
}
if (!pos_ignore && !vel_ignore && acc_ignore) {
- sub.guided_set_destination_posvel(pos_neu_cm, Vector3f(packet.vx * 100.0f, packet.vy * 100.0f, -packet.vz * 100.0f));
+ sub.mode_guided.guided_set_destination_posvel(pos_neu_cm, Vector3f(packet.vx * 100.0f, packet.vy * 100.0f, -packet.vz * 100.0f));
} else if (pos_ignore && !vel_ignore && acc_ignore) {
- sub.guided_set_velocity(Vector3f(packet.vx * 100.0f, packet.vy * 100.0f, -packet.vz * 100.0f));
+ sub.mode_guided.guided_set_velocity(Vector3f(packet.vx * 100.0f, packet.vy * 100.0f, -packet.vz * 100.0f));
} else if (!pos_ignore && vel_ignore && acc_ignore) {
- sub.guided_set_destination(pos_neu_cm);
+ sub.mode_guided.guided_set_destination(pos_neu_cm);
}
break;
@@ -794,7 +804,7 @@ int16_t GCS_MAVLINK_Sub::high_latency_target_altitude() const
UNUSED_RESULT(ahrs.get_location(global_position_current));
//return units are m
- if (sub.control_mode == AUTO || sub.control_mode == GUIDED) {
+ if (sub.control_mode == Mode::Number::AUTO || sub.control_mode == Mode::Number::GUIDED) {
return 0.01 * (global_position_current.alt + sub.pos_control.get_pos_error_z_cm());
}
return 0;
@@ -804,7 +814,7 @@ int16_t GCS_MAVLINK_Sub::high_latency_target_altitude() const
uint8_t GCS_MAVLINK_Sub::high_latency_tgt_heading() const
{
// return units are deg/2
- if (sub.control_mode == AUTO || sub.control_mode == GUIDED) {
+ if (sub.control_mode == Mode::Number::AUTO || sub.control_mode == Mode::Number::GUIDED) {
// need to convert -18000->18000 to 0->360/2
return wrap_360_cd(sub.wp_nav.get_wp_bearing_to_destination()) / 200;
}
@@ -814,7 +824,7 @@ uint8_t GCS_MAVLINK_Sub::high_latency_tgt_heading() const
uint16_t GCS_MAVLINK_Sub::high_latency_tgt_dist() const
{
// return units are dm
- if (sub.control_mode == AUTO || sub.control_mode == GUIDED) {
+ if (sub.control_mode == Mode::Number::AUTO || sub.control_mode == Mode::Number::GUIDED) {
return MIN(sub.wp_nav.get_wp_distance_to_destination() * 0.001, UINT16_MAX);
}
return 0;
@@ -823,7 +833,7 @@ uint16_t GCS_MAVLINK_Sub::high_latency_tgt_dist() const
uint8_t GCS_MAVLINK_Sub::high_latency_tgt_airspeed() const
{
// return units are m/s*5
- if (sub.control_mode == AUTO || sub.control_mode == GUIDED) {
+ if (sub.control_mode == Mode::Number::AUTO || sub.control_mode == Mode::Number::GUIDED) {
return MIN((sub.pos_control.get_vel_desired_cms().length()/100) * 5, UINT8_MAX);
}
return 0;
diff --git a/ArduSub/GCS_Mavlink.h b/ArduSub/GCS_Mavlink.h
index 937224027c1949..c1b65dfb910973 100644
--- a/ArduSub/GCS_Mavlink.h
+++ b/ArduSub/GCS_Mavlink.h
@@ -8,6 +8,7 @@ class GCS_MAVLINK_Sub : public GCS_MAVLINK {
using GCS_MAVLINK::GCS_MAVLINK;
+ uint8_t sysid_my_gcs() const override;
protected:
uint32_t telem_delay() const override {
@@ -16,12 +17,10 @@ class GCS_MAVLINK_Sub : public GCS_MAVLINK {
MAV_RESULT handle_flight_termination(const mavlink_command_long_t &packet) override;
- uint8_t sysid_my_gcs() const override;
-
MAV_RESULT handle_command_do_set_roi(const Location &roi_loc) override;
MAV_RESULT _handle_command_preflight_calibration_baro(const mavlink_message_t &msg) override;
MAV_RESULT _handle_command_preflight_calibration(const mavlink_command_long_t &packet, const mavlink_message_t &msg) override;
- MAV_RESULT handle_command_long_packet(const mavlink_command_long_t &packet) override;
+ MAV_RESULT handle_command_long_packet(const mavlink_command_long_t &packet, const mavlink_message_t &msg) override;
// override sending of scaled_pressure3 to send on-board temperature:
void send_scaled_pressure3() override;
diff --git a/ArduSub/GCS_Sub.cpp b/ArduSub/GCS_Sub.cpp
index d535a823e6b6c0..b57839c9bc842e 100644
--- a/ArduSub/GCS_Sub.cpp
+++ b/ArduSub/GCS_Sub.cpp
@@ -30,12 +30,12 @@ void GCS_Sub::update_vehicle_sensor_status_flags()
MAV_SYS_STATUS_SENSOR_XY_POSITION_CONTROL;
switch (sub.control_mode) {
- case ALT_HOLD:
- case AUTO:
- case GUIDED:
- case CIRCLE:
- case SURFACE:
- case POSHOLD:
+ case Mode::Number::ALT_HOLD:
+ case Mode::Number::AUTO:
+ case Mode::Number::GUIDED:
+ case Mode::Number::CIRCLE:
+ case Mode::Number::SURFACE:
+ case Mode::Number::POSHOLD:
control_sensors_enabled |= MAV_SYS_STATUS_SENSOR_Z_ALTITUDE_CONTROL;
control_sensors_health |= MAV_SYS_STATUS_SENSOR_Z_ALTITUDE_CONTROL;
control_sensors_enabled |= MAV_SYS_STATUS_SENSOR_XY_POSITION_CONTROL;
diff --git a/ArduSub/Log.cpp b/ArduSub/Log.cpp
index 1dbf759d6ab938..f2649bc8417a92 100644
--- a/ArduSub/Log.cpp
+++ b/ArduSub/Log.cpp
@@ -278,7 +278,7 @@ const struct LogStructure Sub::log_structure[] = {
void Sub::Log_Write_Vehicle_Startup_Messages()
{
// only 200(?) bytes are guaranteed by AP_Logger
- logger.Write_Mode(control_mode, control_mode_reason);
+ logger.Write_Mode((uint8_t)control_mode, control_mode_reason);
ahrs.Log_Write_Home_And_Origin();
gps.Write_AP_Logger_Log_Startup_messages();
}
diff --git a/ArduSub/Parameters.cpp b/ArduSub/Parameters.cpp
index 75afeb22ca1c65..e7162c5ebcf1b7 100644
--- a/ArduSub/Parameters.cpp
+++ b/ArduSub/Parameters.cpp
@@ -409,9 +409,11 @@ const AP_Param::Info Sub::var_info[] = {
GOBJECT(camera, "CAM", AP_Camera),
#endif
+#if AP_RELAY_ENABLED
// @Group: RELAY_
// @Path: ../libraries/AP_Relay/AP_Relay.cpp
GOBJECT(relay, "RELAY_", AP_Relay),
+#endif
// @Group: COMPASS_
// @Path: ../libraries/AP_Compass/AP_Compass.cpp
@@ -620,7 +622,11 @@ const AP_Param::Info Sub::var_info[] = {
2nd group of parameters
*/
const AP_Param::GroupInfo ParametersG2::var_info[] = {
-
+#if STATS_ENABLED == ENABLED
+ // @Group: STAT
+ // @Path: ../libraries/AP_Stats/AP_Stats.cpp
+ AP_SUBGROUPINFO(stats, "STAT", 1, ParametersG2, AP_Stats),
+#endif
#if HAL_PROXIMITY_ENABLED
// @Group: PRX
// @Path: ../libraries/AP_Proximity/AP_Proximity.cpp
@@ -695,22 +701,7 @@ void Sub::load_parameters()
AP_Param::set_frame_type_flags(AP_PARAM_FRAME_SUB);
convert_old_parameters();
-
- AP_Param::set_default_by_name("BRD_SAFETY_DEFLT", 0);
- AP_Param::set_default_by_name("ARMING_CHECK",
- AP_Arming::ARMING_CHECK_RC |
- AP_Arming::ARMING_CHECK_VOLTAGE |
- AP_Arming::ARMING_CHECK_BATTERY);
- AP_Param::set_default_by_name("CIRCLE_RATE", 2.0f);
- AP_Param::set_default_by_name("ATC_ACCEL_Y_MAX", 110000.0f);
- AP_Param::set_default_by_name("RC3_TRIM", 1100);
- AP_Param::set_default_by_name("COMPASS_OFFS_MAX", 1000);
- AP_Param::set_default_by_name("INS_GYR_CAL", 0);
- AP_Param::set_default_by_name("MNT1_TYPE", 1);
- AP_Param::set_default_by_name("MNT1_DEFLT_MODE", MAV_MOUNT_MODE_RC_TARGETING);
- AP_Param::set_default_by_name("MNT1_RC_RATE", 30);
- AP_Param::set_default_by_name("RC7_OPTION", 214); // MOUNT1_YAW
- AP_Param::set_default_by_name("RC8_OPTION", 213); // MOUNT1_PITCH
+ AP_Param::set_defaults_from_table(defaults_table, ARRAY_SIZE(defaults_table));
// We should ignore this parameter since ROVs are neutral buoyancy
AP_Param::set_by_name("MOT_THST_HOVER", 0.5);
diff --git a/ArduSub/Parameters.h b/ArduSub/Parameters.h
index eeff0a26935c14..12e300732e66f7 100644
--- a/ArduSub/Parameters.h
+++ b/ArduSub/Parameters.h
@@ -5,6 +5,8 @@
#include
#include
+#include
+#include
#if AP_SCRIPTING_ENABLED
#include
@@ -318,6 +320,10 @@ class Parameters {
class ParametersG2 {
public:
ParametersG2(void);
+#if STATS_ENABLED == ENABLED
+ // vehicle statistics
+ AP_Stats stats;
+#endif
// var_info for holding Parameter information
static const struct AP_Param::GroupInfo var_info[];
@@ -344,3 +350,22 @@ class ParametersG2 {
extern const AP_Param::Info var_info[];
+// Sub-specific default parameters
+static const struct AP_Param::defaults_table_struct defaults_table[] = {
+ { "BRD_SAFETY_DEFLT", 0 },
+ { "ARMING_CHECK", AP_Arming::ARMING_CHECK_RC |
+ AP_Arming::ARMING_CHECK_VOLTAGE |
+ AP_Arming::ARMING_CHECK_BATTERY},
+ { "CIRCLE_RATE", 2.0f},
+ { "ATC_ACCEL_Y_MAX", 110000.0f},
+ { "RC3_TRIM", 1100},
+ { "COMPASS_OFFS_MAX", 1000},
+ { "INS_GYR_CAL", 0},
+ { "MNT1_TYPE", 1},
+ { "MNT1_DEFLT_MODE", MAV_MOUNT_MODE_RC_TARGETING},
+ { "MNT1_RC_RATE", 30},
+ { "RC7_OPTION", 214}, // MOUNT1_YAW
+ { "RC8_OPTION", 213}, // MOUNT1_PITCH
+ { "MOT_PWM_MIN", 1100},
+ { "MOT_PWM_MAX", 1900},
+};
diff --git a/ArduSub/RC_Channel.h b/ArduSub/RC_Channel.h
index 7b7139a1e946bd..e7ee787b509356 100644
--- a/ArduSub/RC_Channel.h
+++ b/ArduSub/RC_Channel.h
@@ -25,6 +25,9 @@ class RC_Channels_Sub : public RC_Channels
return &obj_channels[chan];
}
+ // tell the gimbal code all is good with RC input:
+ bool in_rc_failsafe() const override { return false; };
+
protected:
// note that these callbacks are not presently used on Plane:
diff --git a/ArduSub/Sub.cpp b/ArduSub/Sub.cpp
index bd73ce41a6bf15..4275ddb7109d46 100644
--- a/ArduSub/Sub.cpp
+++ b/ArduSub/Sub.cpp
@@ -25,7 +25,7 @@ const AP_HAL::HAL& hal = AP_HAL::get_HAL();
*/
Sub::Sub()
: logger(g.log_bitmask),
- control_mode(MANUAL),
+ control_mode(Mode::Number::MANUAL),
motors(MAIN_LOOP_RATE),
auto_mode(Auto_WP),
guided_mode(Guided_WP),
@@ -37,7 +37,8 @@ Sub::Sub()
wp_nav(inertial_nav, ahrs_view, pos_control, attitude_control),
loiter_nav(inertial_nav, ahrs_view, pos_control, attitude_control),
circle_nav(inertial_nav, ahrs_view, pos_control),
- param_loader(var_info)
+ param_loader(var_info),
+ flightmode(&mode_manual)
{
#if CONFIG_HAL_BOARD != HAL_BOARD_SITL
failsafe.pilot_input = true;
diff --git a/ArduSub/Sub.h b/ArduSub/Sub.h
index 95205f84b260fc..72f6193542991f 100644
--- a/ArduSub/Sub.h
+++ b/ArduSub/Sub.h
@@ -71,6 +71,7 @@
#include "Parameters.h"
#include "AP_Arming_Sub.h"
#include "GCS_Sub.h"
+#include "mode.h"
#include // Optical Flow library
@@ -108,6 +109,17 @@ class Sub : public AP_Vehicle {
friend class ParametersG2;
friend class AP_Arming_Sub;
friend class RC_Channels_Sub;
+ friend class Mode;
+ friend class ModeManual;
+ friend class ModeStabilize;
+ friend class ModeAcro;
+ friend class ModeAlthold;
+ friend class ModeGuided;
+ friend class ModePoshold;
+ friend class ModeAuto;
+ friend class ModeCircle;
+ friend class ModeSurface;
+ friend class ModeMotordetect;
Sub(void);
@@ -190,9 +202,9 @@ class Sub : public AP_Vehicle {
// This is the state of the flight control system
// There are multiple states defined such as STABILIZE, ACRO,
- control_mode_t control_mode;
+ Mode::Number control_mode;
- control_mode_t prev_control_mode;
+ Mode::Number prev_control_mode;
#if RCMAP_ENABLED == ENABLED
RCMapper rcmap;
@@ -234,12 +246,6 @@ class Sub : public AP_Vehicle {
AP_Motors6DOF motors;
- // Auto
- AutoMode auto_mode; // controls which auto controller is run
-
- // Guided
- GuidedMode guided_mode; // controls which controller is run (pos or vel)
-
// Circle
bool circle_pilot_yaw_override; // true if pilot is overriding yaw
@@ -289,6 +295,9 @@ class Sub : public AP_Vehicle {
// Navigation Yaw control
// auto flight mode's yaw mode
uint8_t auto_yaw_mode;
+
+ // Parameter to set yaw rate only
+ bool yaw_rate_only;
// Yaw will point at this location if auto_yaw_mode is set to AUTO_YAW_ROI
Vector3f roi_WP;
@@ -416,61 +425,7 @@ class Sub : public AP_Vehicle {
bool verify_wait_delay();
bool verify_within_distance();
bool verify_yaw();
- bool acro_init(void);
- void acro_run();
- void get_pilot_desired_angle_rates(int16_t roll_in, int16_t pitch_in, int16_t yaw_in, float &roll_out, float &pitch_out, float &yaw_out);
- bool althold_init(void);
- void althold_run();
- bool auto_init(void);
- void auto_run();
- void auto_wp_start(const Vector3f& destination);
- void auto_wp_start(const Location& dest_loc);
- void auto_wp_run();
- void auto_circle_movetoedge_start(const Location &circle_center, float radius_m, bool ccw_turn);
- void auto_circle_start();
- void auto_circle_run();
- void auto_nav_guided_start();
- void auto_nav_guided_run();
- bool auto_loiter_start();
- void auto_loiter_run();
- uint8_t get_default_auto_yaw_mode(bool rtl) const;
- void set_auto_yaw_mode(uint8_t yaw_mode);
- void set_auto_yaw_look_at_heading(float angle_deg, float turn_rate_dps, int8_t direction, uint8_t relative_angle);
- void set_auto_yaw_roi(const Location &roi_location);
- float get_auto_heading(void);
- bool circle_init(void);
- void circle_run();
- bool guided_init(bool ignore_checks = false);
- void guided_pos_control_start();
- void guided_vel_control_start();
- void guided_posvel_control_start();
- void guided_angle_control_start();
- bool guided_set_destination(const Vector3f& destination);
- bool guided_set_destination(const Location& dest_loc);
- void guided_set_velocity(const Vector3f& velocity);
- bool guided_set_destination_posvel(const Vector3f& destination, const Vector3f& velocity);
- void guided_set_angle(const Quaternion &q, float climb_rate_cms);
- void guided_run();
- void guided_pos_control_run();
- void guided_vel_control_run();
- void guided_posvel_control_run();
- void guided_angle_control_run();
- void guided_limit_clear();
- void guided_limit_set(uint32_t timeout_ms, float alt_min_cm, float alt_max_cm, float horiz_max_cm);
- void guided_limit_init_time_and_pos();
- bool guided_limit_check();
-
- bool poshold_init(void);
- void poshold_run();
-
- bool motordetect_init();
- void motordetect_run();
-
- bool stabilize_init(void);
- void stabilize_run();
- void control_depth();
- bool manual_init(void);
- void manual_run();
+
void failsafe_sensors_check(void);
void failsafe_crash_check();
void failsafe_ekf_check(void);
@@ -484,15 +439,12 @@ class Sub : public AP_Vehicle {
void mainloop_failsafe_enable();
void mainloop_failsafe_disable();
void fence_check();
- bool set_mode(control_mode_t mode, ModeReason reason);
- bool set_mode(const uint8_t mode, const ModeReason reason) override;
+ bool set_mode(Mode::Number mode, ModeReason reason);
+ bool set_mode(const uint8_t new_mode, const ModeReason reason) override;
uint8_t get_mode() const override { return (uint8_t)control_mode; }
void update_flight_mode();
- void exit_mode(control_mode_t old_control_mode, control_mode_t new_control_mode);
- bool mode_requires_GPS(control_mode_t mode);
- bool mode_has_manual_throttle(control_mode_t mode);
- bool mode_allows_arming(control_mode_t mode, bool arming_from_gcs);
- void notify_flight_mode(control_mode_t mode);
+ void exit_mode(Mode::Number old_control_mode, Mode::Number new_control_mode);
+ void notify_flight_mode();
void read_inertia();
void update_surface_and_bottom_detector();
void set_surfaced(bool at_surface);
@@ -563,8 +515,7 @@ class Sub : public AP_Vehicle {
void failsafe_internal_temperature_check();
void failsafe_terrain_act(void);
- bool auto_terrain_recover_start(void);
- void auto_terrain_recover_run(void);
+
void translate_wpnav_rp(float &lateral_out, float &forward_out);
void translate_circle_nav_rp(float &lateral_out, float &forward_out);
@@ -573,6 +524,8 @@ class Sub : public AP_Vehicle {
bool surface_init(void);
void surface_run();
+ void stats_update();
+
uint16_t get_pilot_speed_dn() const;
void convert_old_parameters(void);
@@ -608,6 +561,24 @@ class Sub : public AP_Vehicle {
static_assert(_failsafe_priorities[ARRAY_SIZE(_failsafe_priorities) - 1] == -1,
"_failsafe_priorities is missing the sentinel");
+ Mode *mode_from_mode_num(const Mode::Number num);
+ void exit_mode(Mode *&old_flightmode, Mode *&new_flightmode);
+
+ Mode *flightmode;
+ ModeManual mode_manual;
+ ModeStabilize mode_stabilize;
+ ModeAcro mode_acro;
+ ModeAlthold mode_althold;
+ ModeAuto mode_auto;
+ ModeGuided mode_guided;
+ ModePoshold mode_poshold;
+ ModeCircle mode_circle;
+ ModeSurface mode_surface;
+ ModeMotordetect mode_motordetect;
+
+ // Auto
+ AutoSubMode auto_mode; // controls which auto controller is run
+ GuidedSubMode guided_mode;
public:
void mainloop_failsafe_check();
diff --git a/ArduSub/commands_logic.cpp b/ArduSub/commands_logic.cpp
index 855f8b0adf6862..f35eac79675ef5 100644
--- a/ArduSub/commands_logic.cpp
+++ b/ArduSub/commands_logic.cpp
@@ -124,7 +124,7 @@ bool Sub::start_command(const AP_Mission::Mission_Command& cmd)
// called by mission library in mission.update()
bool Sub::verify_command_callback(const AP_Mission::Mission_Command& cmd)
{
- if (control_mode == AUTO) {
+ if (control_mode == Mode::Number::AUTO) {
bool cmd_complete = verify_command(cmd);
// send message to GCS
@@ -207,8 +207,8 @@ void Sub::exit_mission()
AP_Notify::events.mission_complete = 1;
// Try to enter loiter, if that fails, go to depth hold
- if (!auto_loiter_start()) {
- set_mode(ALT_HOLD, ModeReason::MISSION_END);
+ if (!mode_auto.auto_loiter_start()) {
+ set_mode(Mode::Number::ALT_HOLD, ModeReason::MISSION_END);
}
}
@@ -243,7 +243,7 @@ void Sub::do_nav_wp(const AP_Mission::Mission_Command& cmd)
loiter_time_max = cmd.p1;
// Set wp navigation target
- auto_wp_start(target_loc);
+ mode_auto.auto_wp_start(target_loc);
}
// do_surface - initiate surface procedure
@@ -279,12 +279,12 @@ void Sub::do_surface(const AP_Mission::Mission_Command& cmd)
}
// Go to wp location
- auto_wp_start(target_location);
+ mode_auto.auto_wp_start(target_location);
}
void Sub::do_RTL()
{
- auto_wp_start(ahrs.get_home());
+ mode_auto.auto_wp_start(ahrs.get_home());
}
// do_loiter_unlimited - start loitering with no end conditions
@@ -323,7 +323,7 @@ void Sub::do_loiter_unlimited(const AP_Mission::Mission_Command& cmd)
}
// start way point navigator and provide it the desired location
- auto_wp_start(target_loc);
+ mode_auto.auto_wp_start(target_loc);
}
// do_circle - initiate moving in a circle
@@ -362,7 +362,7 @@ void Sub::do_circle(const AP_Mission::Mission_Command& cmd)
const bool circle_direction_ccw = cmd.content.location.loiter_ccw;
// move to edge of circle (verify_circle) will ensure we begin circling once we reach the edge
- auto_circle_movetoedge_start(circle_center, circle_radius_m, circle_direction_ccw);
+ mode_auto.auto_circle_movetoedge_start(circle_center, circle_radius_m, circle_direction_ccw);
}
// do_loiter_time - initiate loitering at a point for a given time period
@@ -383,10 +383,10 @@ void Sub::do_nav_guided_enable(const AP_Mission::Mission_Command& cmd)
{
if (cmd.p1 > 0) {
// initialise guided limits
- guided_limit_init_time_and_pos();
+ mode_auto.guided_limit_init_time_and_pos();
// set navigation target
- auto_nav_guided_start();
+ mode_auto.auto_nav_guided_start();
}
}
#endif // NAV_GUIDED
@@ -410,7 +410,7 @@ void Sub::do_nav_delay(const AP_Mission::Mission_Command& cmd)
// do_guided_limits - pass guided limits to guided controller
void Sub::do_guided_limits(const AP_Mission::Mission_Command& cmd)
{
- guided_limit_set(cmd.p1 * 1000, // convert seconds to ms
+ mode_guided.guided_limit_set(cmd.p1 * 1000, // convert seconds to ms
cmd.content.guided_limits.alt_min * 100.0f, // convert meters to cm
cmd.content.guided_limits.alt_max * 100.0f, // convert meters to cm
cmd.content.guided_limits.horiz_max * 100.0f); // convert meters to cm
@@ -459,7 +459,7 @@ bool Sub::verify_surface(const AP_Mission::Mission_Command& cmd)
// TODO get xy target from current wp destination, because current location may be acceptance-radius away from original destination
Location target_location(cmd.content.location.lat, cmd.content.location.lng, 0, Location::AltFrame::ABOVE_HOME);
- auto_wp_start(target_location);
+ mode_auto.auto_wp_start(target_location);
// advance to next state
auto_surface_state = AUTO_SURFACE_STATE_ASCEND;
@@ -529,13 +529,13 @@ bool Sub::verify_circle(const AP_Mission::Mission_Command& cmd)
}
// start circling
- auto_circle_start();
+ mode_auto.auto_circle_start();
}
return false;
}
// check if we have completed circling
- return fabsf(circle_nav.get_angle_total()/M_2PI) >= LOWBYTE(cmd.p1);
+ return fabsf(sub.circle_nav.get_angle_total()/M_2PI) >= LOWBYTE(cmd.p1);
}
#if NAV_GUIDED == ENABLED
@@ -548,7 +548,7 @@ bool Sub::verify_nav_guided_enable(const AP_Mission::Mission_Command& cmd)
}
// check time and position limits
- return guided_limit_check();
+ return mode_auto.guided_limit_check();
}
#endif // NAV_GUIDED
@@ -579,7 +579,7 @@ void Sub::do_within_distance(const AP_Mission::Mission_Command& cmd)
void Sub::do_yaw(const AP_Mission::Mission_Command& cmd)
{
- set_auto_yaw_look_at_heading(
+ sub.mode_auto.set_auto_yaw_look_at_heading(
cmd.content.yaw.angle_deg,
cmd.content.yaw.turn_rate_dps,
cmd.content.yaw.direction,
@@ -614,7 +614,7 @@ bool Sub::verify_yaw()
{
// set yaw mode if it has been changed (the waypoint controller often retakes control of yaw as it executes a new waypoint command)
if (auto_yaw_mode != AUTO_YAW_LOOK_AT_HEADING) {
- set_auto_yaw_mode(AUTO_YAW_LOOK_AT_HEADING);
+ sub.mode_auto.set_auto_yaw_mode(AUTO_YAW_LOOK_AT_HEADING);
}
// check if we are within 2 degrees of the target heading
@@ -629,7 +629,7 @@ bool Sub::verify_yaw()
bool Sub::do_guided(const AP_Mission::Mission_Command& cmd)
{
// only process guided waypoint if we are in guided mode
- if (control_mode != GUIDED && !(control_mode == AUTO && auto_mode == Auto_NavGuided)) {
+ if (control_mode != Mode::Number::GUIDED && !(control_mode == Mode::Number::AUTO && auto_mode == Auto_NavGuided)) {
return false;
}
@@ -638,7 +638,7 @@ bool Sub::do_guided(const AP_Mission::Mission_Command& cmd)
case MAV_CMD_NAV_WAYPOINT: {
// set wp_nav's destination
- return guided_set_destination(cmd.content.location);
+ return sub.mode_guided.guided_set_destination(cmd.content.location);
}
case MAV_CMD_CONDITION_YAW:
@@ -681,7 +681,7 @@ void Sub::do_set_home(const AP_Mission::Mission_Command& cmd)
// TO-DO: add support for other features of MAV_CMD_DO_SET_ROI including pointing at a given waypoint
void Sub::do_roi(const AP_Mission::Mission_Command& cmd)
{
- set_auto_yaw_roi(cmd.content.location);
+ sub.mode_auto.set_auto_yaw_roi(cmd.content.location);
}
// point the camera to a specified angle
diff --git a/ArduSub/config.h b/ArduSub/config.h
index d09d7e351c129b..4a517afe13adbb 100644
--- a/ArduSub/config.h
+++ b/ArduSub/config.h
@@ -190,6 +190,12 @@
# define LOGGING_ENABLED ENABLED
#endif
+// Statistics
+#ifndef STATS_ENABLED
+ # define STATS_ENABLED (AP_STATS_ENABLED ? ENABLED : DISABLED)
+#endif
+
+
// Default logging bitmask
#ifndef DEFAULT_LOG_BITMASK
# define DEFAULT_LOG_BITMASK \
diff --git a/ArduSub/control_acro.cpp b/ArduSub/control_acro.cpp
deleted file mode 100644
index 959ad69f8e8117..00000000000000
--- a/ArduSub/control_acro.cpp
+++ /dev/null
@@ -1,162 +0,0 @@
-#include "Sub.h"
-
-
-/*
- * control_acro.pde - init and run calls for acro flight mode
- */
-
-// acro_init - initialise acro controller
-bool Sub::acro_init()
-{
- // set target altitude to zero for reporting
- pos_control.set_pos_target_z_cm(0);
-
- // attitude hold inputs become thrust inputs in acro mode
- // set to neutral to prevent chaotic behavior (esp. roll/pitch)
- set_neutral_controls();
-
- return true;
-}
-
-// acro_run - runs the acro controller
-// should be called at 100hz or more
-void Sub::acro_run()
-{
- float target_roll, target_pitch, target_yaw;
-
- // if not armed set throttle to zero and exit immediately
- if (!motors.armed()) {
- motors.set_desired_spool_state(AP_Motors::DesiredSpoolState::GROUND_IDLE);
- attitude_control.set_throttle_out(0,true,g.throttle_filt);
- attitude_control.relax_attitude_controllers();
- return;
- }
-
- motors.set_desired_spool_state(AP_Motors::DesiredSpoolState::THROTTLE_UNLIMITED);
-
- // convert the input to the desired body frame rate
- get_pilot_desired_angle_rates(channel_roll->get_control_in(), channel_pitch->get_control_in(), channel_yaw->get_control_in(), target_roll, target_pitch, target_yaw);
-
- // run attitude controller
- attitude_control.input_rate_bf_roll_pitch_yaw(target_roll, target_pitch, target_yaw);
-
- // output pilot's throttle without angle boost
- attitude_control.set_throttle_out(channel_throttle->norm_input(), false, g.throttle_filt);
-
- //control_in is range 0-1000
- //radio_in is raw pwm value
- motors.set_forward(channel_forward->norm_input());
- motors.set_lateral(channel_lateral->norm_input());
-}
-
-
-// get_pilot_desired_angle_rates - transform pilot's roll pitch and yaw input into a desired lean angle rates
-// returns desired angle rates in centi-degrees-per-second
-void Sub::get_pilot_desired_angle_rates(int16_t roll_in, int16_t pitch_in, int16_t yaw_in, float &roll_out, float &pitch_out, float &yaw_out)
-{
- float rate_limit;
- Vector3f rate_ef_level, rate_bf_level, rate_bf_request;
-
- // apply circular limit to pitch and roll inputs
- float total_in = norm(pitch_in, roll_in);
-
- if (total_in > ROLL_PITCH_INPUT_MAX) {
- float ratio = (float)ROLL_PITCH_INPUT_MAX / total_in;
- roll_in *= ratio;
- pitch_in *= ratio;
- }
-
- // calculate roll, pitch rate requests
- if (g.acro_expo <= 0) {
- rate_bf_request.x = roll_in * g.acro_rp_p;
- rate_bf_request.y = pitch_in * g.acro_rp_p;
- } else {
- // expo variables
- float rp_in, rp_in3, rp_out;
-
- // range check expo
- if (g.acro_expo > 1.0f) {
- g.acro_expo.set(1.0f);
- }
-
- // roll expo
- rp_in = float(roll_in)/ROLL_PITCH_INPUT_MAX;
- rp_in3 = rp_in*rp_in*rp_in;
- rp_out = (g.acro_expo * rp_in3) + ((1 - g.acro_expo) * rp_in);
- rate_bf_request.x = ROLL_PITCH_INPUT_MAX * rp_out * g.acro_rp_p;
-
- // pitch expo
- rp_in = float(pitch_in)/ROLL_PITCH_INPUT_MAX;
- rp_in3 = rp_in*rp_in*rp_in;
- rp_out = (g.acro_expo * rp_in3) + ((1 - g.acro_expo) * rp_in);
- rate_bf_request.y = ROLL_PITCH_INPUT_MAX * rp_out * g.acro_rp_p;
- }
-
- // calculate yaw rate request
- rate_bf_request.z = yaw_in * g.acro_yaw_p;
-
- // calculate earth frame rate corrections to pull the vehicle back to level while in ACRO mode
-
- if (g.acro_trainer != ACRO_TRAINER_DISABLED) {
- // Calculate trainer mode earth frame rate command for roll
- int32_t roll_angle = wrap_180_cd(ahrs.roll_sensor);
- rate_ef_level.x = -constrain_int32(roll_angle, -ACRO_LEVEL_MAX_ANGLE, ACRO_LEVEL_MAX_ANGLE) * g.acro_balance_roll;
-
- // Calculate trainer mode earth frame rate command for pitch
- int32_t pitch_angle = wrap_180_cd(ahrs.pitch_sensor);
- rate_ef_level.y = -constrain_int32(pitch_angle, -ACRO_LEVEL_MAX_ANGLE, ACRO_LEVEL_MAX_ANGLE) * g.acro_balance_pitch;
-
- // Calculate trainer mode earth frame rate command for yaw
- rate_ef_level.z = 0;
-
- // Calculate angle limiting earth frame rate commands
- if (g.acro_trainer == ACRO_TRAINER_LIMITED) {
- if (roll_angle > aparm.angle_max) {
- rate_ef_level.x -= g.acro_balance_roll*(roll_angle-aparm.angle_max);
- } else if (roll_angle < -aparm.angle_max) {
- rate_ef_level.x -= g.acro_balance_roll*(roll_angle+aparm.angle_max);
- }
-
- if (pitch_angle > aparm.angle_max) {
- rate_ef_level.y -= g.acro_balance_pitch*(pitch_angle-aparm.angle_max);
- } else if (pitch_angle < -aparm.angle_max) {
- rate_ef_level.y -= g.acro_balance_pitch*(pitch_angle+aparm.angle_max);
- }
- }
-
- // convert earth-frame level rates to body-frame level rates
- attitude_control.euler_rate_to_ang_vel(attitude_control.get_att_target_euler_cd()*radians(0.01f), rate_ef_level, rate_bf_level);
-
- // combine earth frame rate corrections with rate requests
- if (g.acro_trainer == ACRO_TRAINER_LIMITED) {
- rate_bf_request.x += rate_bf_level.x;
- rate_bf_request.y += rate_bf_level.y;
- rate_bf_request.z += rate_bf_level.z;
- } else {
- float acro_level_mix = constrain_float(1-MAX(MAX(abs(roll_in), abs(pitch_in)), abs(yaw_in))/4500.0, 0, 1)*ahrs.cos_pitch();
-
- // Scale leveling rates by stick input
- rate_bf_level = rate_bf_level*acro_level_mix;
-
- // Calculate rate limit to prevent change of rate through inverted
- rate_limit = fabsf(fabsf(rate_bf_request.x)-fabsf(rate_bf_level.x));
- rate_bf_request.x += rate_bf_level.x;
- rate_bf_request.x = constrain_float(rate_bf_request.x, -rate_limit, rate_limit);
-
- // Calculate rate limit to prevent change of rate through inverted
- rate_limit = fabsf(fabsf(rate_bf_request.y)-fabsf(rate_bf_level.y));
- rate_bf_request.y += rate_bf_level.y;
- rate_bf_request.y = constrain_float(rate_bf_request.y, -rate_limit, rate_limit);
-
- // Calculate rate limit to prevent change of rate through inverted
- rate_limit = fabsf(fabsf(rate_bf_request.z)-fabsf(rate_bf_level.z));
- rate_bf_request.z += rate_bf_level.z;
- rate_bf_request.z = constrain_float(rate_bf_request.z, -rate_limit, rate_limit);
- }
- }
-
- // hand back rate request
- roll_out = rate_bf_request.x;
- pitch_out = rate_bf_request.y;
- yaw_out = rate_bf_request.z;
-}
diff --git a/ArduSub/control_althold.cpp b/ArduSub/control_althold.cpp
deleted file mode 100644
index a420cfe3149ea7..00000000000000
--- a/ArduSub/control_althold.cpp
+++ /dev/null
@@ -1,120 +0,0 @@
-#include "Sub.h"
-
-
-/*
- * control_althold.pde - init and run calls for althold, flight mode
- */
-
-// althold_init - initialise althold controller
-bool Sub::althold_init()
-{
- if(!control_check_barometer()) {
- return false;
- }
-
- // initialize vertical maximum speeds and acceleration
- // sets the maximum speed up and down returned by position controller
- pos_control.set_max_speed_accel_z(-get_pilot_speed_dn(), g.pilot_speed_up, g.pilot_accel_z);
- pos_control.set_correction_speed_accel_z(-get_pilot_speed_dn(), g.pilot_speed_up, g.pilot_accel_z);
-
- // initialise position and desired velocity
- pos_control.init_z_controller();
-
- last_pilot_heading = ahrs.yaw_sensor;
-
- return true;
-}
-
-// althold_run - runs the althold controller
-// should be called at 100hz or more
-void Sub::althold_run()
-{
- uint32_t tnow = AP_HAL::millis();
-
- // initialize vertical speeds and acceleration
- pos_control.set_max_speed_accel_z(-get_pilot_speed_dn(), g.pilot_speed_up, g.pilot_accel_z);
-
- if (!motors.armed()) {
- motors.set_desired_spool_state(AP_Motors::DesiredSpoolState::GROUND_IDLE);
- // Sub vehicles do not stabilize roll/pitch/yaw when not auto-armed (i.e. on the ground, pilot has never raised throttle)
- attitude_control.set_throttle_out(0.5,true,g.throttle_filt);
- attitude_control.relax_attitude_controllers();
- pos_control.relax_z_controller(motors.get_throttle_hover());
- last_pilot_heading = ahrs.yaw_sensor;
- return;
- }
-
- motors.set_desired_spool_state(AP_Motors::DesiredSpoolState::THROTTLE_UNLIMITED);
-
- // get pilot desired lean angles
- float target_roll, target_pitch;
-
- // Check if set_attitude_target_no_gps is valid
- if (tnow - sub.set_attitude_target_no_gps.last_message_ms < 5000) {
- float target_yaw;
- Quaternion(
- set_attitude_target_no_gps.packet.q
- ).to_euler(
- target_roll,
- target_pitch,
- target_yaw
- );
- target_roll = degrees(target_roll);
- target_pitch = degrees(target_pitch);
- target_yaw = degrees(target_yaw);
-
- attitude_control.input_euler_angle_roll_pitch_yaw(target_roll * 1e2f, target_pitch * 1e2f, target_yaw * 1e2f, true);
- return;
- }
-
- get_pilot_desired_lean_angles(channel_roll->get_control_in(), channel_pitch->get_control_in(), target_roll, target_pitch, attitude_control.get_althold_lean_angle_max_cd());
-
- // get pilot's desired yaw rate
- float target_yaw_rate = get_pilot_desired_yaw_rate(channel_yaw->get_control_in());
-
- // call attitude controller
- if (!is_zero(target_yaw_rate)) { // call attitude controller with rate yaw determined by pilot input
- attitude_control.input_euler_angle_roll_pitch_euler_rate_yaw(target_roll, target_pitch, target_yaw_rate);
- last_pilot_heading = ahrs.yaw_sensor;
- last_pilot_yaw_input_ms = tnow; // time when pilot last changed heading
-
- } else { // hold current heading
-
- // this check is required to prevent bounce back after very fast yaw maneuvers
- // the inertia of the vehicle causes the heading to move slightly past the point when pilot input actually stopped
- if (tnow < last_pilot_yaw_input_ms + 250) { // give 250ms to slow down, then set target heading
- target_yaw_rate = 0; // Stop rotation on yaw axis
-
- // call attitude controller with target yaw rate = 0 to decelerate on yaw axis
- attitude_control.input_euler_angle_roll_pitch_euler_rate_yaw(target_roll, target_pitch, target_yaw_rate);
- last_pilot_heading = ahrs.yaw_sensor; // update heading to hold
-
- } else { // call attitude controller holding absolute absolute bearing
- attitude_control.input_euler_angle_roll_pitch_yaw(target_roll, target_pitch, last_pilot_heading, true);
- }
- }
-
- control_depth();
-
- motors.set_forward(channel_forward->norm_input());
- motors.set_lateral(channel_lateral->norm_input());
-}
-
-void Sub::control_depth() {
- float target_climb_rate_cm_s = get_pilot_desired_climb_rate(channel_throttle->get_control_in());
- target_climb_rate_cm_s = constrain_float(target_climb_rate_cm_s, -get_pilot_speed_dn(), g.pilot_speed_up);
-
- // desired_climb_rate returns 0 when within the deadzone.
- //we allow full control to the pilot, but as soon as there's no input, we handle being at surface/bottom
- if (fabsf(target_climb_rate_cm_s) < 0.05f) {
- if (ap.at_surface) {
- pos_control.set_pos_target_z_cm(MIN(pos_control.get_pos_target_z_cm(), g.surface_depth - 5.0f)); // set target to 5 cm below surface level
- } else if (ap.at_bottom) {
- pos_control.set_pos_target_z_cm(MAX(inertial_nav.get_position_z_up_cm() + 10.0f, pos_control.get_pos_target_z_cm())); // set target to 10 cm above bottom
- }
- }
-
- pos_control.set_pos_target_z_from_climb_rate_cm(target_climb_rate_cm_s);
- pos_control.update_z_controller();
-
-}
diff --git a/ArduSub/control_circle.cpp b/ArduSub/control_circle.cpp
deleted file mode 100644
index fca637e9bf8f3f..00000000000000
--- a/ArduSub/control_circle.cpp
+++ /dev/null
@@ -1,86 +0,0 @@
-#include "Sub.h"
-
-/*
- * control_circle.pde - init and run calls for circle flight mode
- */
-
-// circle_init - initialise circle controller flight mode
-bool Sub::circle_init()
-{
- if (!position_ok()) {
- return false;
- }
-
- circle_pilot_yaw_override = false;
-
- // initialize speeds and accelerations
- pos_control.set_max_speed_accel_xy(wp_nav.get_default_speed_xy(), wp_nav.get_wp_acceleration());
- pos_control.set_correction_speed_accel_xy(wp_nav.get_default_speed_xy(), wp_nav.get_wp_acceleration());
- pos_control.set_max_speed_accel_z(-get_pilot_speed_dn(), g.pilot_speed_up, g.pilot_accel_z);
- pos_control.set_correction_speed_accel_z(-get_pilot_speed_dn(), g.pilot_speed_up, g.pilot_accel_z);
-
- // initialise circle controller including setting the circle center based on vehicle speed
- circle_nav.init();
-
- return true;
-}
-
-// circle_run - runs the circle flight mode
-// should be called at 100hz or more
-void Sub::circle_run()
-{
- float target_yaw_rate = 0;
- float target_climb_rate = 0;
-
- // update parameters, to allow changing at runtime
- pos_control.set_max_speed_accel_xy(wp_nav.get_default_speed_xy(), wp_nav.get_wp_acceleration());
- pos_control.set_max_speed_accel_z(-get_pilot_speed_dn(), g.pilot_speed_up, g.pilot_accel_z);
-
- // if not armed set throttle to zero and exit immediately
- if (!motors.armed()) {
- // To-Do: add some initialisation of position controllers
- motors.set_desired_spool_state(AP_Motors::DesiredSpoolState::GROUND_IDLE);
- // Sub vehicles do not stabilize roll/pitch/yaw when disarmed
- attitude_control.set_throttle_out(0,true,g.throttle_filt);
- attitude_control.relax_attitude_controllers();
- circle_nav.init();
- return;
- }
-
- // process pilot inputs
- // get pilot's desired yaw rate
- target_yaw_rate = get_pilot_desired_yaw_rate(channel_yaw->get_control_in());
- if (!is_zero(target_yaw_rate)) {
- circle_pilot_yaw_override = true;
- }
-
- // get pilot desired climb rate
- target_climb_rate = get_pilot_desired_climb_rate(channel_throttle->get_control_in());
-
- // set motors to full range
- motors.set_desired_spool_state(AP_Motors::DesiredSpoolState::THROTTLE_UNLIMITED);
-
- // run circle controller
- failsafe_terrain_set_status(circle_nav.update());
-
- ///////////////////////
- // update xy outputs //
-
- float lateral_out, forward_out;
- translate_circle_nav_rp(lateral_out, forward_out);
-
- // Send to forward/lateral outputs
- motors.set_lateral(lateral_out);
- motors.set_forward(forward_out);
-
- // call attitude controller
- if (circle_pilot_yaw_override) {
- attitude_control.input_euler_angle_roll_pitch_euler_rate_yaw(channel_roll->get_control_in(), channel_pitch->get_control_in(), target_yaw_rate);
- } else {
- attitude_control.input_euler_angle_roll_pitch_yaw(channel_roll->get_control_in(), channel_pitch->get_control_in(), circle_nav.get_yaw(), true);
- }
-
- // update altitude target and call position controller
- pos_control.set_pos_target_z_from_climb_rate_cm(target_climb_rate);
- pos_control.update_z_controller();
-}
diff --git a/ArduSub/control_guided.cpp b/ArduSub/control_guided.cpp
deleted file mode 100644
index 3c13e04b231182..00000000000000
--- a/ArduSub/control_guided.cpp
+++ /dev/null
@@ -1,563 +0,0 @@
-#include "Sub.h"
-
-/*
- * Init and run calls for guided flight mode
- */
-
-#define GUIDED_POSVEL_TIMEOUT_MS 3000 // guided mode's position-velocity controller times out after 3seconds with no new updates
-#define GUIDED_ATTITUDE_TIMEOUT_MS 1000 // guided mode's attitude controller times out after 1 second with no new updates
-
-static Vector3p posvel_pos_target_cm;
-static Vector3f posvel_vel_target_cms;
-static uint32_t update_time_ms;
-
-struct {
- uint32_t update_time_ms;
- float roll_cd;
- float pitch_cd;
- float yaw_cd;
- float climb_rate_cms;
-} static guided_angle_state = {0,0.0f, 0.0f, 0.0f, 0.0f};
-
-struct Guided_Limit {
- uint32_t timeout_ms; // timeout (in seconds) from the time that guided is invoked
- float alt_min_cm; // lower altitude limit in cm above home (0 = no limit)
- float alt_max_cm; // upper altitude limit in cm above home (0 = no limit)
- float horiz_max_cm; // horizontal position limit in cm from where guided mode was initiated (0 = no limit)
- uint32_t start_time;// system time in milliseconds that control was handed to the external computer
- Vector3f start_pos; // start position as a distance from home in cm. used for checking horiz_max limit
-} guided_limit;
-
-// guided_init - initialise guided controller
-bool Sub::guided_init(bool ignore_checks)
-{
- if (!position_ok() && !ignore_checks) {
- return false;
- }
-
- // start in position control mode
- guided_pos_control_start();
- return true;
-}
-
-// initialise guided mode's position controller
-void Sub::guided_pos_control_start()
-{
- // set to position control mode
- guided_mode = Guided_WP;
-
- // initialise waypoint controller
- wp_nav.wp_and_spline_init();
-
- // initialise wpnav to stopping point at current altitude
- // To-Do: set to current location if disarmed?
- // To-Do: set to stopping point altitude?
- Vector3f stopping_point;
- wp_nav.get_wp_stopping_point(stopping_point);
-
- // no need to check return status because terrain data is not used
- wp_nav.set_wp_destination(stopping_point, false);
-
- // initialise yaw
- set_auto_yaw_mode(get_default_auto_yaw_mode(false));
-}
-
-// initialise guided mode's velocity controller
-void Sub::guided_vel_control_start()
-{
- // set guided_mode to velocity controller
- guided_mode = Guided_Velocity;
-
- // initialize vertical maximum speeds and acceleration
- pos_control.set_max_speed_accel_z(-get_pilot_speed_dn(), g.pilot_speed_up, g.pilot_accel_z);
- pos_control.set_correction_speed_accel_z(-get_pilot_speed_dn(), g.pilot_speed_up, g.pilot_accel_z);
-
- // initialise velocity controller
- pos_control.init_z_controller();
- pos_control.init_xy_controller();
-}
-
-// initialise guided mode's posvel controller
-void Sub::guided_posvel_control_start()
-{
- // set guided_mode to velocity controller
- guided_mode = Guided_PosVel;
-
- // set vertical speed and acceleration
- pos_control.set_max_speed_accel_z(wp_nav.get_default_speed_down(), wp_nav.get_default_speed_up(), wp_nav.get_accel_z());
- pos_control.set_correction_speed_accel_z(wp_nav.get_default_speed_down(), wp_nav.get_default_speed_up(), wp_nav.get_accel_z());
-
- // initialise velocity controller
- pos_control.init_z_controller();
- pos_control.init_xy_controller();
-
- // pilot always controls yaw
- set_auto_yaw_mode(AUTO_YAW_HOLD);
-}
-
-// initialise guided mode's angle controller
-void Sub::guided_angle_control_start()
-{
- // set guided_mode to velocity controller
- guided_mode = Guided_Angle;
-
- // set vertical speed and acceleration
- pos_control.set_max_speed_accel_z(wp_nav.get_default_speed_down(), wp_nav.get_default_speed_up(), wp_nav.get_accel_z());
- pos_control.set_correction_speed_accel_z(wp_nav.get_default_speed_down(), wp_nav.get_default_speed_up(), wp_nav.get_accel_z());
-
- // initialise velocity controller
- pos_control.init_z_controller();
-
- // initialise targets
- guided_angle_state.update_time_ms = AP_HAL::millis();
- guided_angle_state.roll_cd = ahrs.roll_sensor;
- guided_angle_state.pitch_cd = ahrs.pitch_sensor;
- guided_angle_state.yaw_cd = ahrs.yaw_sensor;
- guided_angle_state.climb_rate_cms = 0.0f;
-
- // pilot always controls yaw
- set_auto_yaw_mode(AUTO_YAW_HOLD);
-}
-
-// guided_set_destination - sets guided mode's target destination
-// Returns true if the fence is enabled and guided waypoint is within the fence
-// else return false if the waypoint is outside the fence
-bool Sub::guided_set_destination(const Vector3f& destination)
-{
- // ensure we are in position control mode
- if (guided_mode != Guided_WP) {
- guided_pos_control_start();
- }
-
-#if AP_FENCE_ENABLED
- // reject destination if outside the fence
- const Location dest_loc(destination, Location::AltFrame::ABOVE_ORIGIN);
- if (!fence.check_destination_within_fence(dest_loc)) {
- AP::logger().Write_Error(LogErrorSubsystem::NAVIGATION, LogErrorCode::DEST_OUTSIDE_FENCE);
- // failure is propagated to GCS with NAK
- return false;
- }
-#endif
-
- // no need to check return status because terrain data is not used
- wp_nav.set_wp_destination(destination, false);
-
- // log target
- Log_Write_GuidedTarget(guided_mode, destination, Vector3f());
- return true;
-}
-
-// sets guided mode's target from a Location object
-// returns false if destination could not be set (probably caused by missing terrain data)
-// or if the fence is enabled and guided waypoint is outside the fence
-bool Sub::guided_set_destination(const Location& dest_loc)
-{
- // ensure we are in position control mode
- if (guided_mode != Guided_WP) {
- guided_pos_control_start();
- }
-
-#if AP_FENCE_ENABLED
- // reject destination outside the fence.
- // Note: there is a danger that a target specified as a terrain altitude might not be checked if the conversion to alt-above-home fails
- if (!fence.check_destination_within_fence(dest_loc)) {
- AP::logger().Write_Error(LogErrorSubsystem::NAVIGATION, LogErrorCode::DEST_OUTSIDE_FENCE);
- // failure is propagated to GCS with NAK
- return false;
- }
-#endif
-
- if (!wp_nav.set_wp_destination_loc(dest_loc)) {
- // failure to set destination can only be because of missing terrain data
- AP::logger().Write_Error(LogErrorSubsystem::NAVIGATION, LogErrorCode::FAILED_TO_SET_DESTINATION);
- // failure is propagated to GCS with NAK
- return false;
- }
-
- // log target
- Log_Write_GuidedTarget(guided_mode, Vector3f(dest_loc.lat, dest_loc.lng, dest_loc.alt),Vector3f());
- return true;
-}
-
-// guided_set_velocity - sets guided mode's target velocity
-void Sub::guided_set_velocity(const Vector3f& velocity)
-{
- // check we are in velocity control mode
- if (guided_mode != Guided_Velocity) {
- guided_vel_control_start();
- }
-
- update_time_ms = AP_HAL::millis();
-
- // set position controller velocity target
- pos_control.set_vel_desired_cms(velocity);
-}
-
-// set guided mode posvel target
-bool Sub::guided_set_destination_posvel(const Vector3f& destination, const Vector3f& velocity)
-{
- // check we are in velocity control mode
- if (guided_mode != Guided_PosVel) {
- guided_posvel_control_start();
- }
-
-#if AP_FENCE_ENABLED
- // reject destination if outside the fence
- const Location dest_loc(destination, Location::AltFrame::ABOVE_ORIGIN);
- if (!fence.check_destination_within_fence(dest_loc)) {
- AP::logger().Write_Error(LogErrorSubsystem::NAVIGATION, LogErrorCode::DEST_OUTSIDE_FENCE);
- // failure is propagated to GCS with NAK
- return false;
- }
-#endif
-
- update_time_ms = AP_HAL::millis();
- posvel_pos_target_cm = destination.topostype();
- posvel_vel_target_cms = velocity;
-
- pos_control.input_pos_vel_accel_xy(posvel_pos_target_cm.xy(), posvel_vel_target_cms.xy(), Vector2f());
- float dz = posvel_pos_target_cm.z;
- pos_control.input_pos_vel_accel_z(dz, posvel_vel_target_cms.z, 0);
- posvel_pos_target_cm.z = dz;
-
- // log target
- Log_Write_GuidedTarget(guided_mode, destination, velocity);
- return true;
-}
-
-// set guided mode angle target
-void Sub::guided_set_angle(const Quaternion &q, float climb_rate_cms)
-{
- // check we are in velocity control mode
- if (guided_mode != Guided_Angle) {
- guided_angle_control_start();
- }
-
- // convert quaternion to euler angles
- q.to_euler(guided_angle_state.roll_cd, guided_angle_state.pitch_cd, guided_angle_state.yaw_cd);
- guided_angle_state.roll_cd = ToDeg(guided_angle_state.roll_cd) * 100.0f;
- guided_angle_state.pitch_cd = ToDeg(guided_angle_state.pitch_cd) * 100.0f;
- guided_angle_state.yaw_cd = wrap_180_cd(ToDeg(guided_angle_state.yaw_cd) * 100.0f);
-
- guided_angle_state.climb_rate_cms = climb_rate_cms;
- guided_angle_state.update_time_ms = AP_HAL::millis();
-}
-
-// guided_run - runs the guided controller
-// should be called at 100hz or more
-void Sub::guided_run()
-{
- // call the correct auto controller
- switch (guided_mode) {
-
- case Guided_WP:
- // run position controller
- guided_pos_control_run();
- break;
-
- case Guided_Velocity:
- // run velocity controller
- guided_vel_control_run();
- break;
-
- case Guided_PosVel:
- // run position-velocity controller
- guided_posvel_control_run();
- break;
-
- case Guided_Angle:
- // run angle controller
- guided_angle_control_run();
- break;
- }
-}
-
-// guided_pos_control_run - runs the guided position controller
-// called from guided_run
-void Sub::guided_pos_control_run()
-{
- // if motors not enabled set throttle to zero and exit immediately
- if (!motors.armed()) {
- motors.set_desired_spool_state(AP_Motors::DesiredSpoolState::GROUND_IDLE);
- // Sub vehicles do not stabilize roll/pitch/yaw when disarmed
- attitude_control.set_throttle_out(0,true,g.throttle_filt);
- attitude_control.relax_attitude_controllers();
- wp_nav.wp_and_spline_init();
- return;
- }
-
- // process pilot's yaw input
- float target_yaw_rate = 0;
- if (!failsafe.pilot_input) {
- // get pilot's desired yaw rate
- target_yaw_rate = get_pilot_desired_yaw_rate(channel_yaw->get_control_in());
- if (!is_zero(target_yaw_rate)) {
- set_auto_yaw_mode(AUTO_YAW_HOLD);
- }
- }
-
- // set motors to full range
- motors.set_desired_spool_state(AP_Motors::DesiredSpoolState::THROTTLE_UNLIMITED);
-
- // run waypoint controller
- failsafe_terrain_set_status(wp_nav.update_wpnav());
-
- float lateral_out, forward_out;
- translate_wpnav_rp(lateral_out, forward_out);
-
- // Send to forward/lateral outputs
- motors.set_lateral(lateral_out);
- motors.set_forward(forward_out);
-
- // WP_Nav has set the vertical position control targets
- // run the vertical position controller and set output throttle
- pos_control.update_z_controller();
-
- // call attitude controller
- if (auto_yaw_mode == AUTO_YAW_HOLD) {
- // roll & pitch & yaw rate from pilot
- attitude_control.input_euler_angle_roll_pitch_euler_rate_yaw(channel_roll->get_control_in(), channel_pitch->get_control_in(), target_yaw_rate);
- } else {
- // roll, pitch from pilot, yaw heading from auto_heading()
- attitude_control.input_euler_angle_roll_pitch_yaw(channel_roll->get_control_in(), channel_pitch->get_control_in(), get_auto_heading(), true);
- }
-}
-
-// guided_vel_control_run - runs the guided velocity controller
-// called from guided_run
-void Sub::guided_vel_control_run()
-{
- // ifmotors not enabled set throttle to zero and exit immediately
- if (!motors.armed()) {
- motors.set_desired_spool_state(AP_Motors::DesiredSpoolState::GROUND_IDLE);
- // Sub vehicles do not stabilize roll/pitch/yaw when disarmed
- attitude_control.set_throttle_out(0,true,g.throttle_filt);
- attitude_control.relax_attitude_controllers();
- // initialise velocity controller
- pos_control.init_z_controller();
- pos_control.init_xy_controller();
- return;
- }
-
- // process pilot's yaw input
- float target_yaw_rate = 0;
- if (!failsafe.pilot_input) {
- // get pilot's desired yaw rate
- target_yaw_rate = get_pilot_desired_yaw_rate(channel_yaw->get_control_in());
- if (!is_zero(target_yaw_rate)) {
- set_auto_yaw_mode(AUTO_YAW_HOLD);
- }
- }
-
- // set motors to full range
- motors.set_desired_spool_state(AP_Motors::DesiredSpoolState::THROTTLE_UNLIMITED);
-
- // set velocity to zero if no updates received for 3 seconds
- uint32_t tnow = AP_HAL::millis();
- if (tnow - update_time_ms > GUIDED_POSVEL_TIMEOUT_MS && !pos_control.get_vel_desired_cms().is_zero()) {
- pos_control.set_vel_desired_cms(Vector3f(0,0,0));
- }
-
- pos_control.stop_pos_xy_stabilisation();
- // call velocity controller which includes z axis controller
- pos_control.update_xy_controller();
- pos_control.update_z_controller();
-
- float lateral_out, forward_out;
- translate_pos_control_rp(lateral_out, forward_out);
-
- // Send to forward/lateral outputs
- motors.set_lateral(lateral_out);
- motors.set_forward(forward_out);
-
- // call attitude controller
- if (auto_yaw_mode == AUTO_YAW_HOLD) {
- // roll & pitch & yaw rate from pilot
- attitude_control.input_euler_angle_roll_pitch_euler_rate_yaw(channel_roll->get_control_in(), channel_pitch->get_control_in(), target_yaw_rate);
- } else {
- // roll, pitch from pilot, yaw heading from auto_heading()
- attitude_control.input_euler_angle_roll_pitch_yaw(channel_roll->get_control_in(), channel_pitch->get_control_in(), get_auto_heading(), true);
- }
-}
-
-// guided_posvel_control_run - runs the guided posvel controller
-// called from guided_run
-void Sub::guided_posvel_control_run()
-{
- // if motors not enabled set throttle to zero and exit immediately
- if (!motors.armed()) {
- motors.set_desired_spool_state(AP_Motors::DesiredSpoolState::GROUND_IDLE);
- // Sub vehicles do not stabilize roll/pitch/yaw when disarmed
- attitude_control.set_throttle_out(0,true,g.throttle_filt);
- attitude_control.relax_attitude_controllers();
- // initialise velocity controller
- pos_control.init_z_controller();
- pos_control.init_xy_controller();
- return;
- }
-
- // process pilot's yaw input
- float target_yaw_rate = 0;
-
- if (!failsafe.pilot_input) {
- // get pilot's desired yaw rate
- target_yaw_rate = get_pilot_desired_yaw_rate(channel_yaw->get_control_in());
- if (!is_zero(target_yaw_rate)) {
- set_auto_yaw_mode(AUTO_YAW_HOLD);
- }
- }
-
- // set motors to full range
- motors.set_desired_spool_state(AP_Motors::DesiredSpoolState::THROTTLE_UNLIMITED);
-
- // set velocity to zero if no updates received for 3 seconds
- uint32_t tnow = AP_HAL::millis();
- if (tnow - update_time_ms > GUIDED_POSVEL_TIMEOUT_MS && !posvel_vel_target_cms.is_zero()) {
- posvel_vel_target_cms.zero();
- }
-
- // advance position target using velocity target
- posvel_pos_target_cm += (posvel_vel_target_cms * pos_control.get_dt()).topostype();
-
- // send position and velocity targets to position controller
- pos_control.input_pos_vel_accel_xy(posvel_pos_target_cm.xy(), posvel_vel_target_cms.xy(), Vector2f());
- float pz = posvel_pos_target_cm.z;
- pos_control.input_pos_vel_accel_z(pz, posvel_vel_target_cms.z, 0);
- posvel_pos_target_cm.z = pz;
-
- // run position controller
- pos_control.update_xy_controller();
- pos_control.update_z_controller();
-
- float lateral_out, forward_out;
- translate_pos_control_rp(lateral_out, forward_out);
-
- // Send to forward/lateral outputs
- motors.set_lateral(lateral_out);
- motors.set_forward(forward_out);
-
- // call attitude controller
- if (auto_yaw_mode == AUTO_YAW_HOLD) {
- // roll & pitch & yaw rate from pilot
- attitude_control.input_euler_angle_roll_pitch_euler_rate_yaw(channel_roll->get_control_in(), channel_pitch->get_control_in(), target_yaw_rate);
- } else {
- // roll, pitch from pilot, yaw heading from auto_heading()
- attitude_control.input_euler_angle_roll_pitch_yaw(channel_roll->get_control_in(), channel_pitch->get_control_in(), get_auto_heading(), true);
- }
-}
-
-// guided_angle_control_run - runs the guided angle controller
-// called from guided_run
-void Sub::guided_angle_control_run()
-{
- // if motors not enabled set throttle to zero and exit immediately
- if (!motors.armed()) {
- motors.set_desired_spool_state(AP_Motors::DesiredSpoolState::GROUND_IDLE);
- // Sub vehicles do not stabilize roll/pitch/yaw when disarmed
- attitude_control.set_throttle_out(0.0f,true,g.throttle_filt);
- attitude_control.relax_attitude_controllers();
- // initialise velocity controller
- pos_control.init_z_controller();
- return;
- }
-
- // constrain desired lean angles
- float roll_in = guided_angle_state.roll_cd;
- float pitch_in = guided_angle_state.pitch_cd;
- float total_in = norm(roll_in, pitch_in);
- float angle_max = MIN(attitude_control.get_althold_lean_angle_max_cd(), aparm.angle_max);
- if (total_in > angle_max) {
- float ratio = angle_max / total_in;
- roll_in *= ratio;
- pitch_in *= ratio;
- }
-
- // wrap yaw request
- float yaw_in = wrap_180_cd(guided_angle_state.yaw_cd);
-
- // constrain climb rate
- float climb_rate_cms = constrain_float(guided_angle_state.climb_rate_cms, -wp_nav.get_default_speed_down(), wp_nav.get_default_speed_up());
-
- // check for timeout - set lean angles and climb rate to zero if no updates received for 3 seconds
- uint32_t tnow = AP_HAL::millis();
- if (tnow - guided_angle_state.update_time_ms > GUIDED_ATTITUDE_TIMEOUT_MS) {
- roll_in = 0.0f;
- pitch_in = 0.0f;
- climb_rate_cms = 0.0f;
- }
-
- // set motors to full range
- motors.set_desired_spool_state(AP_Motors::DesiredSpoolState::THROTTLE_UNLIMITED);
-
- // call attitude controller
- attitude_control.input_euler_angle_roll_pitch_yaw(roll_in, pitch_in, yaw_in, true);
-
- // call position controller
- pos_control.set_pos_target_z_from_climb_rate_cm(climb_rate_cms);
- pos_control.update_z_controller();
-}
-
-// Guided Limit code
-
-// guided_limit_clear - clear/turn off guided limits
-void Sub::guided_limit_clear()
-{
- guided_limit.timeout_ms = 0;
- guided_limit.alt_min_cm = 0.0f;
- guided_limit.alt_max_cm = 0.0f;
- guided_limit.horiz_max_cm = 0.0f;
-}
-
-// guided_limit_set - set guided timeout and movement limits
-void Sub::guided_limit_set(uint32_t timeout_ms, float alt_min_cm, float alt_max_cm, float horiz_max_cm)
-{
- guided_limit.timeout_ms = timeout_ms;
- guided_limit.alt_min_cm = alt_min_cm;
- guided_limit.alt_max_cm = alt_max_cm;
- guided_limit.horiz_max_cm = horiz_max_cm;
-}
-
-// guided_limit_init_time_and_pos - initialise guided start time and position as reference for limit checking
-// only called from AUTO mode's auto_nav_guided_start function
-void Sub::guided_limit_init_time_and_pos()
-{
- // initialise start time
- guided_limit.start_time = AP_HAL::millis();
-
- // initialise start position from current position
- guided_limit.start_pos = inertial_nav.get_position_neu_cm();
-}
-
-// guided_limit_check - returns true if guided mode has breached a limit
-// used when guided is invoked from the NAV_GUIDED_ENABLE mission command
-bool Sub::guided_limit_check()
-{
- // check if we have passed the timeout
- if ((guided_limit.timeout_ms > 0) && (AP_HAL::millis() - guided_limit.start_time >= guided_limit.timeout_ms)) {
- return true;
- }
-
- // get current location
- const Vector3f& curr_pos = inertial_nav.get_position_neu_cm();
-
- // check if we have gone below min alt
- if (!is_zero(guided_limit.alt_min_cm) && (curr_pos.z < guided_limit.alt_min_cm)) {
- return true;
- }
-
- // check if we have gone above max alt
- if (!is_zero(guided_limit.alt_max_cm) && (curr_pos.z > guided_limit.alt_max_cm)) {
- return true;
- }
-
- // check if we have gone beyond horizontal limit
- if (guided_limit.horiz_max_cm > 0.0f) {
- const float horiz_move = get_horizontal_distance_cm(guided_limit.start_pos.xy(), curr_pos.xy());
- if (horiz_move > guided_limit.horiz_max_cm) {
- return true;
- }
- }
-
- // if we got this far we must be within limits
- return false;
-}
diff --git a/ArduSub/control_manual.cpp b/ArduSub/control_manual.cpp
deleted file mode 100644
index 93e821740a12b4..00000000000000
--- a/ArduSub/control_manual.cpp
+++ /dev/null
@@ -1,36 +0,0 @@
-#include "Sub.h"
-
-// manual_init - initialise manual controller
-bool Sub::manual_init()
-{
- // set target altitude to zero for reporting
- pos_control.set_pos_target_z_cm(0);
-
- // attitude hold inputs become thrust inputs in manual mode
- // set to neutral to prevent chaotic behavior (esp. roll/pitch)
- set_neutral_controls();
-
- return true;
-}
-
-// manual_run - runs the manual (passthrough) controller
-// should be called at 100hz or more
-void Sub::manual_run()
-{
- // if not armed set throttle to zero and exit immediately
- if (!motors.armed()) {
- motors.set_desired_spool_state(AP_Motors::DesiredSpoolState::GROUND_IDLE);
- attitude_control.set_throttle_out(0,true,g.throttle_filt);
- attitude_control.relax_attitude_controllers();
- return;
- }
-
- motors.set_desired_spool_state(AP_Motors::DesiredSpoolState::THROTTLE_UNLIMITED);
-
- motors.set_roll(channel_roll->norm_input());
- motors.set_pitch(channel_pitch->norm_input());
- motors.set_yaw(channel_yaw->norm_input() * g.acro_yaw_p / ACRO_YAW_P);
- motors.set_throttle(channel_throttle->norm_input());
- motors.set_forward(channel_forward->norm_input());
- motors.set_lateral(channel_lateral->norm_input());
-}
diff --git a/ArduSub/control_stabilize.cpp b/ArduSub/control_stabilize.cpp
deleted file mode 100644
index 356ce2479be1d6..00000000000000
--- a/ArduSub/control_stabilize.cpp
+++ /dev/null
@@ -1,69 +0,0 @@
-#include "Sub.h"
-
-// stabilize_init - initialise stabilize controller
-bool Sub::stabilize_init()
-{
- // set target altitude to zero for reporting
- pos_control.set_pos_target_z_cm(0);
- last_pilot_heading = ahrs.yaw_sensor;
-
- return true;
-}
-
-// stabilize_run - runs the main stabilize controller
-// should be called at 100hz or more
-void Sub::stabilize_run()
-{
- uint32_t tnow = AP_HAL::millis();
- float target_roll, target_pitch;
-
- // if not armed set throttle to zero and exit immediately
- if (!motors.armed()) {
- motors.set_desired_spool_state(AP_Motors::DesiredSpoolState::GROUND_IDLE);
- attitude_control.set_throttle_out(0,true,g.throttle_filt);
- attitude_control.relax_attitude_controllers();
- last_pilot_heading = ahrs.yaw_sensor;
- return;
- }
-
- motors.set_desired_spool_state(AP_Motors::DesiredSpoolState::THROTTLE_UNLIMITED);
-
- // convert pilot input to lean angles
- // To-Do: convert get_pilot_desired_lean_angles to return angles as floats
- get_pilot_desired_lean_angles(channel_roll->get_control_in(), channel_pitch->get_control_in(), target_roll, target_pitch, aparm.angle_max);
-
- // get pilot's desired yaw rate
- float target_yaw_rate = get_pilot_desired_yaw_rate(channel_yaw->get_control_in());
-
- // call attitude controller
- // update attitude controller targets
-
- if (!is_zero(target_yaw_rate)) { // call attitude controller with rate yaw determined by pilot input
- attitude_control.input_euler_angle_roll_pitch_euler_rate_yaw(target_roll, target_pitch, target_yaw_rate);
- last_pilot_heading = ahrs.yaw_sensor;
- last_pilot_yaw_input_ms = tnow; // time when pilot last changed heading
-
- } else { // hold current heading
-
- // this check is required to prevent bounce back after very fast yaw maneuvers
- // the inertia of the vehicle causes the heading to move slightly past the point when pilot input actually stopped
- if (tnow < last_pilot_yaw_input_ms + 250) { // give 250ms to slow down, then set target heading
- target_yaw_rate = 0; // Stop rotation on yaw axis
-
- // call attitude controller with target yaw rate = 0 to decelerate on yaw axis
- attitude_control.input_euler_angle_roll_pitch_euler_rate_yaw(target_roll, target_pitch, target_yaw_rate);
- last_pilot_heading = ahrs.yaw_sensor; // update heading to hold
-
- } else { // call attitude controller holding absolute absolute bearing
- attitude_control.input_euler_angle_roll_pitch_yaw(target_roll, target_pitch, last_pilot_heading, true);
- }
- }
-
- // output pilot's throttle
- attitude_control.set_throttle_out(channel_throttle->norm_input(), false, g.throttle_filt);
-
- //control_in is range -1000-1000
- //radio_in is raw pwm value
- motors.set_forward(channel_forward->norm_input());
- motors.set_lateral(channel_lateral->norm_input());
-}
diff --git a/ArduSub/control_surface.cpp b/ArduSub/control_surface.cpp
deleted file mode 100644
index 407b04ab5a88ec..00000000000000
--- a/ArduSub/control_surface.cpp
+++ /dev/null
@@ -1,63 +0,0 @@
-#include "Sub.h"
-
-
-bool Sub::surface_init()
-{
- if(!control_check_barometer()) {
- return false;
- }
-
- // initialize vertical speeds and acceleration
- pos_control.set_max_speed_accel_z(-get_pilot_speed_dn(), g.pilot_speed_up, g.pilot_accel_z);
- pos_control.set_correction_speed_accel_z(-get_pilot_speed_dn(), g.pilot_speed_up, g.pilot_accel_z);
-
- // initialise position and desired velocity
- pos_control.init_z_controller();
-
- return true;
-
-}
-
-void Sub::surface_run()
-{
- float target_roll, target_pitch;
-
- // if not armed set throttle to zero and exit immediately
- if (!motors.armed()) {
- motors.output_min();
- motors.set_desired_spool_state(AP_Motors::DesiredSpoolState::GROUND_IDLE);
- attitude_control.set_throttle_out(0,true,g.throttle_filt);
- attitude_control.relax_attitude_controllers();
- pos_control.init_z_controller();
- return;
- }
-
- // Already at surface, hold depth at surface
- if (ap.at_surface) {
- set_mode(ALT_HOLD, ModeReason::SURFACE_COMPLETE);
- }
-
- // convert pilot input to lean angles
- // To-Do: convert get_pilot_desired_lean_angles to return angles as floats
- get_pilot_desired_lean_angles(channel_roll->get_control_in(), channel_pitch->get_control_in(), target_roll, target_pitch, aparm.angle_max);
-
- // get pilot's desired yaw rate
- float target_yaw_rate = get_pilot_desired_yaw_rate(channel_yaw->get_control_in());
-
- // call attitude controller
- attitude_control.input_euler_angle_roll_pitch_euler_rate_yaw(target_roll, target_pitch, target_yaw_rate);
-
- // set target climb rate
- float cmb_rate = constrain_float(fabsf(wp_nav.get_default_speed_up()), 1, pos_control.get_max_speed_up_cms());
-
- // record desired climb rate for logging
- desired_climb_rate = cmb_rate;
-
- // update altitude target and call position controller
- pos_control.set_pos_target_z_from_climb_rate_cm(cmb_rate);
- pos_control.update_z_controller();
-
- // pilot has control for repositioning
- motors.set_forward(channel_forward->norm_input());
- motors.set_lateral(channel_lateral->norm_input());
-}
diff --git a/ArduSub/defines.h b/ArduSub/defines.h
index b3c7109f10fda4..170b466966cbdf 100644
--- a/ArduSub/defines.h
+++ b/ArduSub/defines.h
@@ -26,21 +26,8 @@ enum autopilot_yaw_mode {
AUTO_YAW_LOOK_AT_HEADING = 3, // point towards a particular angle (not pilot input accepted)
AUTO_YAW_LOOK_AHEAD = 4, // point in the direction the vehicle is moving
AUTO_YAW_RESETTOARMEDYAW = 5, // point towards heading at time motors were armed
- AUTO_YAW_CORRECT_XTRACK = 6 // steer the sub in order to correct for crosstrack error during line following
-};
-
-// Auto Pilot Modes enumeration
-enum control_mode_t : uint8_t {
- STABILIZE = 0, // manual angle with manual depth/throttle
- ACRO = 1, // manual body-frame angular rate with manual depth/throttle
- ALT_HOLD = 2, // manual angle with automatic depth/throttle
- AUTO = 3, // fully automatic waypoint control using mission commands
- GUIDED = 4, // fully automatic fly to coordinate or fly at velocity/direction using GCS immediate commands
- CIRCLE = 7, // automatic circular flight with automatic throttle
- SURFACE = 9, // automatically return to surface, pilot maintains horizontal control
- POSHOLD = 16, // automatic position hold with manual override, with automatic throttle
- MANUAL = 19, // Pass-through input with no stabilization
- MOTOR_DETECT = 20 // Automatically detect motors orientation
+ AUTO_YAW_CORRECT_XTRACK = 6, // steer the sub in order to correct for crosstrack error during line following
+ AUTO_YAW_RATE = 7 // steer the sub with the desired yaw rate
};
// Acro Trainer types
@@ -55,32 +42,7 @@ enum control_mode_t : uint8_t {
#define WP_YAW_BEHAVIOR_LOOK_AHEAD 3 // auto pilot will look ahead during missions and rtl (primarily meant for traditional helicotpers)
#define WP_YAW_BEHAVIOR_CORRECT_XTRACK 4 // point towards intermediate position target during line following
-// Auto modes
-enum AutoMode {
- Auto_WP,
- Auto_CircleMoveToEdge,
- Auto_Circle,
- Auto_NavGuided,
- Auto_Loiter,
- Auto_TerrainRecover
-};
-
-// Guided modes
-enum GuidedMode {
- Guided_WP,
- Guided_Velocity,
- Guided_PosVel,
- Guided_Angle,
-};
-// RTL states
-enum RTLState {
- RTL_InitialClimb,
- RTL_ReturnHome,
- RTL_LoiterAtHome,
- RTL_FinalDescent,
- RTL_Land
-};
// Logging parameters - only 32 messages are available to the vehicle here.
enum LoggingParameters {
diff --git a/ArduSub/failsafe.cpp b/ArduSub/failsafe.cpp
index 4b2fa212b7eeb6..5c0d08d32499cf 100644
--- a/ArduSub/failsafe.cpp
+++ b/ArduSub/failsafe.cpp
@@ -88,9 +88,9 @@ void Sub::failsafe_sensors_check()
gcs().send_text(MAV_SEVERITY_CRITICAL, "Depth sensor error!");
AP::logger().Write_Error(LogErrorSubsystem::FAILSAFE_SENSORS, LogErrorCode::BAD_DEPTH);
- if (control_mode == ALT_HOLD || control_mode == SURFACE || mode_requires_GPS(control_mode)) {
+ if (control_mode == Mode::Number::ALT_HOLD || control_mode == Mode::Number::SURFACE || sub.flightmode->requires_GPS()) {
// This should always succeed
- if (!set_mode(MANUAL, ModeReason::BAD_DEPTH)) {
+ if (!set_mode(Mode::Number::MANUAL, ModeReason::BAD_DEPTH)) {
// We should never get here
arming.disarm(AP_Arming::Method::BADFLOWOFCONTROL);
}
@@ -156,7 +156,7 @@ void Sub::handle_battery_failsafe(const char* type_str, const int8_t action)
switch((Failsafe_Action)action) {
case Failsafe_Action_Surface:
- set_mode(SURFACE, ModeReason::BATTERY_FAILSAFE);
+ set_mode(Mode::Number::SURFACE, ModeReason::BATTERY_FAILSAFE);
break;
case Failsafe_Action_Disarm:
arming.disarm(AP_Arming::Method::BATTERYFAILSAFE);
@@ -299,7 +299,7 @@ void Sub::failsafe_leak_check()
// Handle failsafe action
if (failsafe.leak && g.failsafe_leak == FS_LEAK_SURFACE && motors.armed()) {
- set_mode(SURFACE, ModeReason::LEAK_FAILSAFE);
+ set_mode(Mode::Number::SURFACE, ModeReason::LEAK_FAILSAFE);
}
}
@@ -352,11 +352,11 @@ void Sub::failsafe_gcs_check()
if (g.failsafe_gcs == FS_GCS_DISARM) {
arming.disarm(AP_Arming::Method::GCSFAILSAFE);
} else if (g.failsafe_gcs == FS_GCS_HOLD && motors.armed()) {
- if (!set_mode(ALT_HOLD, ModeReason::GCS_FAILSAFE)) {
+ if (!set_mode(Mode::Number::ALT_HOLD, ModeReason::GCS_FAILSAFE)) {
arming.disarm(AP_Arming::Method::GCS_FAILSAFE_HOLDFAILED);
}
} else if (g.failsafe_gcs == FS_GCS_SURFACE && motors.armed()) {
- if (!set_mode(SURFACE, ModeReason::GCS_FAILSAFE)) {
+ if (!set_mode(Mode::Number::SURFACE, ModeReason::GCS_FAILSAFE)) {
arming.disarm(AP_Arming::Method::GCS_FAILSAFE_SURFACEFAILED);
}
}
@@ -380,7 +380,7 @@ void Sub::failsafe_crash_check()
}
// return immediately if we are not in an angle stabilized flight mode
- if (control_mode == ACRO || control_mode == MANUAL) {
+ if (control_mode == Mode::Number::ACRO || control_mode == Mode::Number::MANUAL) {
last_crash_check_pass_ms = tnow;
failsafe.crash = false;
return;
@@ -425,7 +425,7 @@ void Sub::failsafe_crash_check()
void Sub::failsafe_terrain_check()
{
// trigger with 5 seconds of failures while in AUTO mode
- bool valid_mode = (control_mode == AUTO || control_mode == GUIDED);
+ bool valid_mode = (control_mode == Mode::Number::AUTO || control_mode == Mode::Number::GUIDED);
bool timeout = (failsafe.terrain_last_failure_ms - failsafe.terrain_first_failure_ms) > FS_TERRAIN_TIMEOUT_MS;
bool trigger_event = valid_mode && timeout;
@@ -470,7 +470,7 @@ void Sub::failsafe_terrain_on_event()
AP::logger().Write_Error(LogErrorSubsystem::FAILSAFE_TERRAIN, LogErrorCode::FAILSAFE_OCCURRED);
// If rangefinder is enabled, we can recover from this failsafe
- if (!rangefinder_state.enabled || !auto_terrain_recover_start()) {
+ if (!rangefinder_state.enabled || !sub.mode_auto.auto_terrain_recover_start()) {
failsafe_terrain_act();
}
@@ -482,14 +482,14 @@ void Sub::failsafe_terrain_act()
{
switch (g.failsafe_terrain) {
case FS_TERRAIN_HOLD:
- if (!set_mode(POSHOLD, ModeReason::TERRAIN_FAILSAFE)) {
- set_mode(ALT_HOLD, ModeReason::TERRAIN_FAILSAFE);
+ if (!set_mode(Mode::Number::POSHOLD, ModeReason::TERRAIN_FAILSAFE)) {
+ set_mode(Mode::Number::ALT_HOLD, ModeReason::TERRAIN_FAILSAFE);
}
AP_Notify::events.failsafe_mode_change = 1;
break;
case FS_TERRAIN_SURFACE:
- set_mode(SURFACE, ModeReason::TERRAIN_FAILSAFE);
+ set_mode(Mode::Number::SURFACE, ModeReason::TERRAIN_FAILSAFE);
AP_Notify::events.failsafe_mode_change = 1;
break;
diff --git a/ArduSub/fence.cpp b/ArduSub/fence.cpp
index 7d89c89cae1ee4..c39e84aebf5319 100644
--- a/ArduSub/fence.cpp
+++ b/ArduSub/fence.cpp
@@ -16,7 +16,7 @@ void Sub::fence_check()
const uint8_t orig_breaches = fence.get_breaches();
// check for new breaches; new_breaches is bitmask of fence types breached
- const uint8_t new_breaches = fence.check();
+ const uint8_t new_breaches = sub.fence.check();
// if there is a new breach take action
if (new_breaches) {
diff --git a/ArduSub/flight_mode.cpp b/ArduSub/flight_mode.cpp
deleted file mode 100644
index 521586923fd8fc..00000000000000
--- a/ArduSub/flight_mode.cpp
+++ /dev/null
@@ -1,230 +0,0 @@
-#include "Sub.h"
-
-// change flight mode and perform any necessary initialisation
-// returns true if mode was successfully set
-bool Sub::set_mode(control_mode_t mode, ModeReason reason)
-{
- // boolean to record if flight mode could be set
- bool success = false;
-
- // return immediately if we are already in the desired mode
- if (mode == control_mode) {
- prev_control_mode = control_mode;
-
- control_mode_reason = reason;
- return true;
- }
-
- switch (mode) {
- case ACRO:
- success = acro_init();
- break;
-
- case STABILIZE:
- success = stabilize_init();
- break;
-
- case ALT_HOLD:
- success = althold_init();
- break;
-
- case AUTO:
- success = auto_init();
- break;
-
- case CIRCLE:
- success = circle_init();
- break;
-
- case GUIDED:
- success = guided_init();
- break;
-
- case SURFACE:
- success = surface_init();
- break;
-
-#if POSHOLD_ENABLED == ENABLED
- case POSHOLD:
- success = poshold_init();
- break;
-#endif
-
- case MANUAL:
- success = manual_init();
- break;
-
- case MOTOR_DETECT:
- success = motordetect_init();
- break;
-
- default:
- success = false;
- break;
- }
-
- // update flight mode
- if (success) {
- // perform any cleanup required by previous flight mode
- exit_mode(control_mode, mode);
-
- prev_control_mode = control_mode;
-
- control_mode = mode;
- control_mode_reason = reason;
- logger.Write_Mode(control_mode, control_mode_reason);
- gcs().send_message(MSG_HEARTBEAT);
-
- // update notify object
- notify_flight_mode(control_mode);
-
-#if AP_CAMERA_ENABLED
- camera.set_is_auto_mode(control_mode == AUTO);
-#endif
-
-#if AP_FENCE_ENABLED
- // pilot requested flight mode change during a fence breach indicates pilot is attempting to manually recover
- // this flight mode change could be automatic (i.e. fence, battery, GPS or GCS failsafe)
- // but it should be harmless to disable the fence temporarily in these situations as well
- fence.manual_recovery_start();
-#endif
- } else {
- // Log error that we failed to enter desired flight mode
- AP::logger().Write_Error(LogErrorSubsystem::FLIGHT_MODE, LogErrorCode(mode));
- }
-
- // return success or failure
- return success;
-}
-
-bool Sub::set_mode(const uint8_t new_mode, const ModeReason reason)
-{
- static_assert(sizeof(control_mode_t) == sizeof(new_mode), "The new mode can't be mapped to the vehicles mode number");
- return sub.set_mode((control_mode_t)new_mode, reason);
-}
-
-// update_flight_mode - calls the appropriate attitude controllers based on flight mode
-// called at 100hz or more
-void Sub::update_flight_mode()
-{
- switch (control_mode) {
- case ACRO:
- acro_run();
- break;
-
- case STABILIZE:
- stabilize_run();
- break;
-
- case ALT_HOLD:
- althold_run();
- break;
-
- case AUTO:
- auto_run();
- break;
-
- case CIRCLE:
- circle_run();
- break;
-
- case GUIDED:
- guided_run();
- break;
-
- case SURFACE:
- surface_run();
- break;
-
-#if POSHOLD_ENABLED == ENABLED
- case POSHOLD:
- poshold_run();
- break;
-#endif
-
- case MANUAL:
- manual_run();
- break;
-
- case MOTOR_DETECT:
- motordetect_run();
- break;
-
- default:
- break;
- }
-}
-
-// exit_mode - high level call to organise cleanup as a flight mode is exited
-void Sub::exit_mode(control_mode_t old_control_mode, control_mode_t new_control_mode)
-{
- // stop mission when we leave auto mode
- if (old_control_mode == AUTO) {
- if (mission.state() == AP_Mission::MISSION_RUNNING) {
- mission.stop();
- }
-#if HAL_MOUNT_ENABLED
- camera_mount.set_mode_to_default();
-#endif // HAL_MOUNT_ENABLED
- }
-}
-
-// returns true or false whether mode requires GPS
-bool Sub::mode_requires_GPS(control_mode_t mode)
-{
- switch (mode) {
- case AUTO:
- case GUIDED:
- case CIRCLE:
- case POSHOLD:
- return true;
- default:
- return false;
- }
-
- return false;
-}
-
-// mode_has_manual_throttle - returns true if the flight mode has a manual throttle (i.e. pilot directly controls throttle)
-bool Sub::mode_has_manual_throttle(control_mode_t mode)
-{
- switch (mode) {
- case ACRO:
- case STABILIZE:
- case MANUAL:
- return true;
- default:
- return false;
- }
-
- return false;
-}
-
-// mode_allows_arming - returns true if vehicle can be armed in the specified mode
-// arming_from_gcs should be set to true if the arming request comes from the ground station
-bool Sub::mode_allows_arming(control_mode_t mode, bool arming_from_gcs)
-{
- return (mode_has_manual_throttle(mode)
- || mode == ALT_HOLD
- || mode == POSHOLD
- || (arming_from_gcs&& mode == GUIDED)
- );
-}
-
-// notify_flight_mode - sets notify object based on flight mode. Only used for OreoLED notify device
-void Sub::notify_flight_mode(control_mode_t mode)
-{
- switch (mode) {
- case AUTO:
- case GUIDED:
- case CIRCLE:
- case SURFACE:
- // autopilot modes
- AP_Notify::flags.autopilot_mode = true;
- break;
- default:
- // all other are manual flight modes
- AP_Notify::flags.autopilot_mode = false;
- break;
- }
-}
diff --git a/ArduSub/joystick.cpp b/ArduSub/joystick.cpp
index bbbd19c3464cc9..5f0f83fe9de98f 100644
--- a/ArduSub/joystick.cpp
+++ b/ArduSub/joystick.cpp
@@ -1,4 +1,5 @@
#include "Sub.h"
+#include "mode.h"
// Functions that will handle joystick/gamepad input
// ----------------------------------------------------------------------------
@@ -34,7 +35,7 @@ void Sub::init_joystick()
lights1 = RC_Channels::rc_channel(8)->get_radio_min();
lights2 = RC_Channels::rc_channel(9)->get_radio_min();
- set_mode(MANUAL, ModeReason::RC_COMMAND); // Initialize flight mode
+ set_mode(Mode::Number::MANUAL, ModeReason::RC_COMMAND); // Initialize flight mode
if (g.numGainSettings < 1) {
g.numGainSettings.set_and_save(1);
@@ -157,28 +158,28 @@ void Sub::handle_jsbutton_press(uint8_t _button, bool shift, bool held)
break;
case JSButton::button_function_t::k_mode_manual:
- set_mode(MANUAL, ModeReason::RC_COMMAND);
+ set_mode(Mode::Number::MANUAL, ModeReason::RC_COMMAND);
break;
case JSButton::button_function_t::k_mode_stabilize:
- set_mode(STABILIZE, ModeReason::RC_COMMAND);
+ set_mode(Mode::Number::STABILIZE, ModeReason::RC_COMMAND);
break;
case JSButton::button_function_t::k_mode_depth_hold:
- set_mode(ALT_HOLD, ModeReason::RC_COMMAND);
+ set_mode(Mode::Number::ALT_HOLD, ModeReason::RC_COMMAND);
break;
case JSButton::button_function_t::k_mode_auto:
- set_mode(AUTO, ModeReason::RC_COMMAND);
+ set_mode(Mode::Number::AUTO, ModeReason::RC_COMMAND);
break;
case JSButton::button_function_t::k_mode_guided:
- set_mode(GUIDED, ModeReason::RC_COMMAND);
+ set_mode(Mode::Number::GUIDED, ModeReason::RC_COMMAND);
break;
case JSButton::button_function_t::k_mode_circle:
- set_mode(CIRCLE, ModeReason::RC_COMMAND);
+ set_mode(Mode::Number::CIRCLE, ModeReason::RC_COMMAND);
break;
case JSButton::button_function_t::k_mode_acro:
- set_mode(ACRO, ModeReason::RC_COMMAND);
+ set_mode(Mode::Number::ACRO, ModeReason::RC_COMMAND);
break;
case JSButton::button_function_t::k_mode_poshold:
- set_mode(POSHOLD, ModeReason::RC_COMMAND);
+ set_mode(Mode::Number::POSHOLD, ModeReason::RC_COMMAND);
break;
case JSButton::button_function_t::k_mount_center:
@@ -359,6 +360,7 @@ void Sub::handle_jsbutton_press(uint8_t _button, bool shift, bool held)
controls_reset_since_input_hold = !input_hold_engaged;
}
break;
+#if AP_RELAY_ENABLED
case JSButton::button_function_t::k_relay_1_on:
relay.on(0);
break;
@@ -423,10 +425,12 @@ void Sub::handle_jsbutton_press(uint8_t _button, bool shift, bool held)
relay.on(3);
}
break;
+#endif
////////////////////////////////////////////////
// Servo functions
// TODO: initialize
+#if AP_SERVORELAYEVENTS_ENABLED
case JSButton::button_function_t::k_servo_1_inc:
{
SRV_Channel* chan = SRV_Channels::srv_channel(SERVO_CHAN_1 - 1); // 0-indexed
@@ -557,6 +561,7 @@ void Sub::handle_jsbutton_press(uint8_t _button, bool shift, bool held)
ServoRelayEvents.do_set_servo(SERVO_CHAN_3, chan->get_trim()); // 1-indexed
}
break;
+#endif // AP_SERVORELAYEVENTS_ENABLED
case JSButton::button_function_t::k_roll_pitch_toggle:
if (!held) {
@@ -595,6 +600,7 @@ void Sub::handle_jsbutton_release(uint8_t _button, bool shift) {
// Act based on the function assigned to this button
switch (get_button(_button)->function(shift)) {
+#if AP_RELAY_ENABLED
case JSButton::button_function_t::k_relay_1_momentary:
relay.off(0);
break;
@@ -607,6 +613,8 @@ void Sub::handle_jsbutton_release(uint8_t _button, bool shift) {
case JSButton::button_function_t::k_relay_4_momentary:
relay.off(3);
break;
+#endif
+#if AP_SERVORELAYEVENTS_ENABLED
case JSButton::button_function_t::k_servo_1_min_momentary:
case JSButton::button_function_t::k_servo_1_max_momentary:
{
@@ -628,6 +636,7 @@ void Sub::handle_jsbutton_release(uint8_t _button, bool shift) {
ServoRelayEvents.do_set_servo(SERVO_CHAN_3, chan->get_trim()); // 1-indexed
}
break;
+#endif
}
}
diff --git a/ArduSub/mode.cpp b/ArduSub/mode.cpp
new file mode 100644
index 00000000000000..323836c2f94abb
--- /dev/null
+++ b/ArduSub/mode.cpp
@@ -0,0 +1,292 @@
+#include "Sub.h"
+
+/*
+ constructor for Mode object
+ */
+Mode::Mode(void) :
+ g(sub.g),
+ g2(sub.g2),
+ inertial_nav(sub.inertial_nav),
+ ahrs(sub.ahrs),
+ motors(sub.motors),
+ channel_roll(sub.channel_roll),
+ channel_pitch(sub.channel_pitch),
+ channel_throttle(sub.channel_throttle),
+ channel_yaw(sub.channel_yaw),
+ channel_forward(sub.channel_forward),
+ channel_lateral(sub.channel_lateral),
+ position_control(&sub.pos_control),
+ attitude_control(&sub.attitude_control),
+ G_Dt(sub.G_Dt)
+{ };
+
+// return the static controller object corresponding to supplied mode
+Mode *Sub::mode_from_mode_num(const Mode::Number mode)
+{
+ Mode *ret = nullptr;
+
+ switch (mode) {
+ case Mode::Number::MANUAL:
+ ret = &mode_manual;
+ break;
+ case Mode::Number::STABILIZE:
+ ret = &mode_stabilize;
+ break;
+ case Mode::Number::ACRO:
+ ret = &mode_acro;
+ break;
+ case Mode::Number::ALT_HOLD:
+ ret = &mode_althold;
+ break;
+ case Mode::Number::POSHOLD:
+ ret = &mode_poshold;
+ break;
+ case Mode::Number::AUTO:
+ ret = &mode_auto;
+ break;
+ case Mode::Number::GUIDED:
+ ret = &mode_guided;
+ break;
+ case Mode::Number::CIRCLE:
+ ret = &mode_circle;
+ break;
+ case Mode::Number::SURFACE:
+ ret = &mode_surface;
+ break;
+ case Mode::Number::MOTOR_DETECT:
+ ret = &mode_motordetect;
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+
+// set_mode - change flight mode and perform any necessary initialisation
+// optional force parameter used to force the flight mode change (used only first time mode is set)
+// returns true if mode was successfully set
+// Some modes can always be set successfully but the return state of other flight modes should be checked and the caller should deal with failures appropriately
+bool Sub::set_mode(Mode::Number mode, ModeReason reason)
+{
+
+ // return immediately if we are already in the desired mode
+ if (mode == control_mode) {
+ control_mode_reason = reason;
+ return true;
+ }
+
+ Mode *new_flightmode = mode_from_mode_num((Mode::Number)mode);
+ if (new_flightmode == nullptr) {
+ notify_no_such_mode((uint8_t)mode);
+ return false;
+ }
+
+ if (new_flightmode->requires_GPS() &&
+ !sub.position_ok()) {
+ gcs().send_text(MAV_SEVERITY_WARNING, "Mode change failed: %s requires position", new_flightmode->name());
+ AP::logger().Write_Error(LogErrorSubsystem::FLIGHT_MODE, LogErrorCode(mode));
+ return false;
+ }
+
+ // check for valid altitude if old mode did not require it but new one does
+ // we only want to stop changing modes if it could make things worse
+ if (!sub.control_check_barometer() && // maybe use ekf_alt_ok() instead?
+ flightmode->has_manual_throttle() &&
+ !new_flightmode->has_manual_throttle()) {
+ gcs().send_text(MAV_SEVERITY_WARNING, "Mode change failed: %s need alt estimate", new_flightmode->name());
+ AP::logger().Write_Error(LogErrorSubsystem::FLIGHT_MODE, LogErrorCode(mode));
+ return false;
+ }
+
+ if (!new_flightmode->init(false)) {
+ gcs().send_text(MAV_SEVERITY_WARNING,"Flight mode change failed %s", new_flightmode->name());
+ AP::logger().Write_Error(LogErrorSubsystem::FLIGHT_MODE, LogErrorCode(mode));
+ return false;
+ }
+
+ // perform any cleanup required by previous flight mode
+ exit_mode(flightmode, new_flightmode);
+
+ // store previous flight mode (only used by tradeheli's autorotation)
+ prev_control_mode = control_mode;
+
+ // update flight mode
+ flightmode = new_flightmode;
+ control_mode = mode;
+ control_mode_reason = reason;
+ logger.Write_Mode((uint8_t)control_mode, reason);
+ gcs().send_message(MSG_HEARTBEAT);
+
+ // update notify object
+ notify_flight_mode();
+
+ // return success
+ return true;
+}
+
+// exit_mode - high level call to organise cleanup as a flight mode is exited
+void Sub::exit_mode(Mode::Number old_control_mode, Mode::Number new_control_mode)
+{
+ // stop mission when we leave auto mode
+ if (old_control_mode == Mode::Number::AUTO) {
+ if (mission.state() == AP_Mission::MISSION_RUNNING) {
+ mission.stop();
+ }
+#if HAL_MOUNT_ENABLED
+ camera_mount.set_mode_to_default();
+#endif // HAL_MOUNT_ENABLED
+ }
+}
+
+bool Sub::set_mode(const uint8_t new_mode, const ModeReason reason)
+{
+ static_assert(sizeof(Mode::Number) == sizeof(new_mode), "The new mode can't be mapped to the vehicles mode number");
+ return sub.set_mode(static_cast(new_mode), reason);
+}
+
+// update_flight_mode - calls the appropriate attitude controllers based on flight mode
+// called at 100hz or more
+void Sub::update_flight_mode()
+{
+ flightmode->run();
+}
+
+// exit_mode - high level call to organise cleanup as a flight mode is exited
+void Sub::exit_mode(Mode *&old_flightmode, Mode *&new_flightmode){
+#if HAL_MOUNT_ENABLED
+ camera_mount.set_mode_to_default();
+#endif // HAL_MOUNT_ENABLED
+}
+
+// notify_flight_mode - sets notify object based on current flight mode. Only used for OreoLED notify device
+void Sub::notify_flight_mode()
+{
+ AP_Notify::flags.autopilot_mode = flightmode->is_autopilot();
+ AP_Notify::flags.flight_mode = (uint8_t)control_mode;
+ notify.set_flight_mode_str(flightmode->name4());
+}
+
+
+// get_pilot_desired_angle_rates - transform pilot's roll pitch and yaw input into a desired lean angle rates
+// returns desired angle rates in centi-degrees-per-second
+void Mode::get_pilot_desired_angle_rates(int16_t roll_in, int16_t pitch_in, int16_t yaw_in, float &roll_out, float &pitch_out, float &yaw_out)
+{
+ float rate_limit;
+ Vector3f rate_ef_level, rate_bf_level, rate_bf_request;
+
+ // apply circular limit to pitch and roll inputs
+ float total_in = norm(pitch_in, roll_in);
+
+ if (total_in > ROLL_PITCH_INPUT_MAX) {
+ float ratio = (float)ROLL_PITCH_INPUT_MAX / total_in;
+ roll_in *= ratio;
+ pitch_in *= ratio;
+ }
+
+ // calculate roll, pitch rate requests
+ if (g.acro_expo <= 0) {
+ rate_bf_request.x = roll_in * g.acro_rp_p;
+ rate_bf_request.y = pitch_in * g.acro_rp_p;
+ } else {
+ // expo variables
+ float rp_in, rp_in3, rp_out;
+
+ // range check expo
+ if (g.acro_expo > 1.0f) {
+ g.acro_expo.set(1.0f);
+ }
+
+ // roll expo
+ rp_in = float(roll_in)/ROLL_PITCH_INPUT_MAX;
+ rp_in3 = rp_in*rp_in*rp_in;
+ rp_out = (g.acro_expo * rp_in3) + ((1 - g.acro_expo) * rp_in);
+ rate_bf_request.x = ROLL_PITCH_INPUT_MAX * rp_out * g.acro_rp_p;
+
+ // pitch expo
+ rp_in = float(pitch_in)/ROLL_PITCH_INPUT_MAX;
+ rp_in3 = rp_in*rp_in*rp_in;
+ rp_out = (g.acro_expo * rp_in3) + ((1 - g.acro_expo) * rp_in);
+ rate_bf_request.y = ROLL_PITCH_INPUT_MAX * rp_out * g.acro_rp_p;
+ }
+
+ // calculate yaw rate request
+ rate_bf_request.z = yaw_in * g.acro_yaw_p;
+
+ // calculate earth frame rate corrections to pull the vehicle back to level while in ACRO mode
+
+ if (g.acro_trainer != ACRO_TRAINER_DISABLED) {
+ // Calculate trainer mode earth frame rate command for roll
+ int32_t roll_angle = wrap_180_cd(ahrs.roll_sensor);
+ rate_ef_level.x = -constrain_int32(roll_angle, -ACRO_LEVEL_MAX_ANGLE, ACRO_LEVEL_MAX_ANGLE) * g.acro_balance_roll;
+
+ // Calculate trainer mode earth frame rate command for pitch
+ int32_t pitch_angle = wrap_180_cd(ahrs.pitch_sensor);
+ rate_ef_level.y = -constrain_int32(pitch_angle, -ACRO_LEVEL_MAX_ANGLE, ACRO_LEVEL_MAX_ANGLE) * g.acro_balance_pitch;
+
+ // Calculate trainer mode earth frame rate command for yaw
+ rate_ef_level.z = 0;
+
+ // Calculate angle limiting earth frame rate commands
+ if (g.acro_trainer == ACRO_TRAINER_LIMITED) {
+ if (roll_angle > sub.aparm.angle_max) {
+ rate_ef_level.x -= g.acro_balance_roll*(roll_angle-sub.aparm.angle_max);
+ } else if (roll_angle < -sub.aparm.angle_max) {
+ rate_ef_level.x -= g.acro_balance_roll*(roll_angle+sub.aparm.angle_max);
+ }
+
+ if (pitch_angle > sub.aparm.angle_max) {
+ rate_ef_level.y -= g.acro_balance_pitch*(pitch_angle-sub.aparm.angle_max);
+ } else if (pitch_angle < -sub.aparm.angle_max) {
+ rate_ef_level.y -= g.acro_balance_pitch*(pitch_angle+sub.aparm.angle_max);
+ }
+ }
+
+ // convert earth-frame level rates to body-frame level rates
+ attitude_control->euler_rate_to_ang_vel(attitude_control->get_att_target_euler_cd()*radians(0.01f), rate_ef_level, rate_bf_level);
+
+ // combine earth frame rate corrections with rate requests
+ if (g.acro_trainer == ACRO_TRAINER_LIMITED) {
+ rate_bf_request.x += rate_bf_level.x;
+ rate_bf_request.y += rate_bf_level.y;
+ rate_bf_request.z += rate_bf_level.z;
+ } else {
+ float acro_level_mix = constrain_float(1-MAX(MAX(abs(roll_in), abs(pitch_in)), abs(yaw_in))/4500.0, 0, 1)*ahrs.cos_pitch();
+
+ // Scale leveling rates by stick input
+ rate_bf_level = rate_bf_level*acro_level_mix;
+
+ // Calculate rate limit to prevent change of rate through inverted
+ rate_limit = fabsf(fabsf(rate_bf_request.x)-fabsf(rate_bf_level.x));
+ rate_bf_request.x += rate_bf_level.x;
+ rate_bf_request.x = constrain_float(rate_bf_request.x, -rate_limit, rate_limit);
+
+ // Calculate rate limit to prevent change of rate through inverted
+ rate_limit = fabsf(fabsf(rate_bf_request.y)-fabsf(rate_bf_level.y));
+ rate_bf_request.y += rate_bf_level.y;
+ rate_bf_request.y = constrain_float(rate_bf_request.y, -rate_limit, rate_limit);
+
+ // Calculate rate limit to prevent change of rate through inverted
+ rate_limit = fabsf(fabsf(rate_bf_request.z)-fabsf(rate_bf_level.z));
+ rate_bf_request.z += rate_bf_level.z;
+ rate_bf_request.z = constrain_float(rate_bf_request.z, -rate_limit, rate_limit);
+ }
+ }
+
+ // hand back rate request
+ roll_out = rate_bf_request.x;
+ pitch_out = rate_bf_request.y;
+ yaw_out = rate_bf_request.z;
+}
+
+
+bool Mode::set_mode(Mode::Number mode, ModeReason reason)
+{
+ return sub.set_mode(mode, reason);
+}
+
+GCS_Sub &Mode::gcs()
+{
+ return sub.gcs();
+}
diff --git a/ArduSub/mode.h b/ArduSub/mode.h
new file mode 100644
index 00000000000000..584f5b26d315db
--- /dev/null
+++ b/ArduSub/mode.h
@@ -0,0 +1,449 @@
+#pragma once
+
+#include "Sub.h"
+class Parameters;
+class ParametersG2;
+
+class GCS_Sub;
+
+// Guided modes
+enum GuidedSubMode {
+ Guided_WP,
+ Guided_Velocity,
+ Guided_PosVel,
+ Guided_Angle,
+};
+
+// Auto modes
+enum AutoSubMode {
+ Auto_WP,
+ Auto_CircleMoveToEdge,
+ Auto_Circle,
+ Auto_NavGuided,
+ Auto_Loiter,
+ Auto_TerrainRecover
+};
+
+// RTL states
+enum RTLState {
+ RTL_InitialClimb,
+ RTL_ReturnHome,
+ RTL_LoiterAtHome,
+ RTL_FinalDescent,
+ RTL_Land
+};
+
+class Mode
+{
+
+public:
+
+ // Auto Pilot Modes enumeration
+ enum class Number : uint8_t {
+ STABILIZE = 0, // manual angle with manual depth/throttle
+ ACRO = 1, // manual body-frame angular rate with manual depth/throttle
+ ALT_HOLD = 2, // manual angle with automatic depth/throttle
+ AUTO = 3, // fully automatic waypoint control using mission commands
+ GUIDED = 4, // fully automatic fly to coordinate or fly at velocity/direction using GCS immediate commands
+ CIRCLE = 7, // automatic circular flight with automatic throttle
+ SURFACE = 9, // automatically return to surface, pilot maintains horizontal control
+ POSHOLD = 16, // automatic position hold with manual override, with automatic throttle
+ MANUAL = 19, // Pass-through input with no stabilization
+ MOTOR_DETECT = 20 // Automatically detect motors orientation
+ };
+
+ // constructor
+ Mode(void);
+
+ // do not allow copying
+ CLASS_NO_COPY(Mode);
+
+ // child classes should override these methods
+ virtual bool init(bool ignore_checks) { return true; }
+ virtual void run() = 0;
+ virtual bool requires_GPS() const = 0;
+ virtual bool has_manual_throttle() const = 0;
+ virtual bool allows_arming(bool from_gcs) const = 0;
+ virtual bool is_autopilot() const { return false; }
+ virtual bool in_guided_mode() const { return false; }
+
+ // return a string for this flightmode
+ virtual const char *name() const = 0;
+ virtual const char *name4() const = 0;
+
+ // functions for reporting to GCS
+ virtual bool get_wp(Location &loc) { return false; }
+ virtual int32_t wp_bearing() const { return 0; }
+ virtual uint32_t wp_distance() const { return 0; }
+ virtual float crosstrack_error() const { return 0.0f; }
+
+
+ // pilot input processing
+ void get_pilot_desired_accelerations(float &right_out, float &front_out) const;
+ void get_pilot_desired_angle_rates(int16_t roll_in, int16_t pitch_in, int16_t yaw_in, float &roll_out, float &pitch_out, float &yaw_out);
+
+
+protected:
+
+ // navigation support functions
+ virtual void run_autopilot() {}
+
+ // helper functions
+ bool is_disarmed_or_landed() const;
+
+ // functions to control landing
+ // in modes that support landing
+ void land_run_horizontal_control();
+ void land_run_vertical_control(bool pause_descent = false);
+
+ // convenience references to avoid code churn in conversion:
+ Parameters &g;
+ ParametersG2 &g2;
+ AP_InertialNav &inertial_nav;
+ AP_AHRS &ahrs;
+ AP_Motors6DOF &motors;
+ RC_Channel *&channel_roll;
+ RC_Channel *&channel_pitch;
+ RC_Channel *&channel_throttle;
+ RC_Channel *&channel_yaw;
+ RC_Channel *&channel_forward;
+ RC_Channel *&channel_lateral;
+ AC_PosControl *position_control;
+ AC_AttitudeControl_Sub *attitude_control;
+ // TODO: channels
+ float &G_Dt;
+
+public:
+ // Navigation Yaw control
+ class AutoYaw
+ {
+
+ public:
+ // mode(): current method of determining desired yaw:
+ autopilot_yaw_mode mode() const
+ {
+ return (autopilot_yaw_mode)_mode;
+ }
+ void set_mode_to_default(bool rtl);
+ void set_mode(autopilot_yaw_mode new_mode);
+ autopilot_yaw_mode default_mode(bool rtl) const;
+
+ void set_rate(float new_rate_cds);
+
+ // set_roi(...): set a "look at" location:
+ void set_roi(const Location &roi_location);
+
+ void set_fixed_yaw(float angle_deg,
+ float turn_rate_dps,
+ int8_t direction,
+ bool relative_angle);
+
+ private:
+
+ // yaw_cd(): main product of AutoYaw; the heading:
+ float yaw_cd();
+
+ // rate_cds(): desired yaw rate in centidegrees/second:
+ float rate_cds();
+
+ float look_ahead_yaw();
+ float roi_yaw();
+
+ // auto flight mode's yaw mode
+ uint8_t _mode = AUTO_YAW_LOOK_AT_NEXT_WP;
+
+ // Yaw will point at this location if mode is set to AUTO_YAW_ROI
+ Vector3f roi;
+
+ // bearing from current location to the ROI
+ float _roi_yaw;
+
+ // yaw used for YAW_FIXED yaw_mode
+ int32_t _fixed_yaw;
+
+ // Deg/s we should turn
+ int16_t _fixed_yaw_slewrate;
+
+ // heading when in yaw_look_ahead_yaw
+ float _look_ahead_yaw;
+
+ // used to reduce update rate to 100hz:
+ uint8_t roi_yaw_counter;
+
+ GuidedSubMode guided_mode;
+
+ };
+ static AutoYaw auto_yaw;
+
+ // pass-through functions to reduce code churn on conversion;
+ // these are candidates for moving into the Mode base
+ // class.
+ bool set_mode(Mode::Number mode, ModeReason reason);
+ GCS_Sub &gcs();
+
+ // end pass-through functions
+};
+
+class ModeManual : public Mode
+{
+
+public:
+ // inherit constructor
+ using Mode::Mode;
+ virtual void run() override;
+ bool init(bool ignore_checks) override;
+ bool requires_GPS() const override { return false; }
+ bool has_manual_throttle() const override { return true; }
+ bool allows_arming(bool from_gcs) const override { return true; }
+ bool is_autopilot() const override { return false; }
+
+protected:
+
+ const char *name() const override { return "MANUAL"; }
+ const char *name4() const override { return "MANU"; }
+};
+
+
+class ModeAcro : public Mode
+{
+
+public:
+ // inherit constructor
+ using Mode::Mode;
+
+ virtual void run() override;
+
+ bool init(bool ignore_checks) override;
+ bool requires_GPS() const override { return false; }
+ bool has_manual_throttle() const override { return true; }
+ bool allows_arming(bool from_gcs) const override { return true; }
+ bool is_autopilot() const override { return false; }
+
+protected:
+
+ const char *name() const override { return "ACRO"; }
+ const char *name4() const override { return "ACRO"; }
+};
+
+
+class ModeStabilize : public Mode
+{
+
+public:
+ // inherit constructor
+ using Mode::Mode;
+
+ virtual void run() override;
+
+ bool init(bool ignore_checks) override;
+ bool requires_GPS() const override { return false; }
+ bool has_manual_throttle() const override { return true; }
+ bool allows_arming(bool from_gcs) const override { return true; }
+ bool is_autopilot() const override { return false; }
+
+protected:
+
+ const char *name() const override { return "STABILIZE"; }
+ const char *name4() const override { return "STAB"; }
+};
+
+
+class ModeAlthold : public Mode
+{
+
+public:
+ // inherit constructor
+ using Mode::Mode;
+
+ virtual void run() override;
+
+ bool init(bool ignore_checks) override;
+ bool requires_GPS() const override { return false; }
+ bool has_manual_throttle() const override { return false; }
+ bool allows_arming(bool from_gcs) const override { return true; }
+ bool is_autopilot() const override { return false; }
+ void control_depth();
+
+protected:
+
+ const char *name() const override { return "ALT_HOLD"; }
+ const char *name4() const override { return "ALTH"; }
+};
+
+
+class ModeGuided : public Mode
+{
+
+public:
+ // inherit constructor
+ using Mode::Mode;
+
+ virtual void run() override;
+
+ bool init(bool ignore_checks) override;
+ bool requires_GPS() const override { return true; }
+ bool has_manual_throttle() const override { return false; }
+ bool allows_arming(bool from_gcs) const override { return true; }
+ bool is_autopilot() const override { return true; }
+ bool guided_limit_check();
+ void guided_limit_init_time_and_pos();
+ void guided_set_angle(const Quaternion &q, float climb_rate_cms, bool use_yaw_rate, float yaw_rate_rads);
+ void guided_set_angle(const Quaternion&, float);
+ void guided_limit_set(uint32_t timeout_ms, float alt_min_cm, float alt_max_cm, float horiz_max_cm);
+ bool guided_set_destination_posvel(const Vector3f& destination, const Vector3f& velocity);
+ bool guided_set_destination_posvel(const Vector3f& destination, const Vector3f& velocity, bool use_yaw, float yaw_cd, bool use_yaw_rate, float yaw_rate_cds, bool relative_yaw);
+ bool guided_set_destination(const Vector3f& destination);
+ bool guided_set_destination(const Location&);
+ bool guided_set_destination(const Vector3f& destination, bool use_yaw, float yaw_cd, bool use_yaw_rate, float yaw_rate_cds, bool relative_yaw);
+ void guided_set_velocity(const Vector3f& velocity);
+ void guided_set_velocity(const Vector3f& velocity, bool use_yaw, float yaw_cd, bool use_yaw_rate, float yaw_rate_cds, bool relative_yaw);
+ void guided_set_yaw_state(bool use_yaw, float yaw_cd, bool use_yaw_rate, float yaw_rate_cds, bool relative_angle);
+ float get_auto_heading();
+ void guided_limit_clear();
+ void set_auto_yaw_mode(autopilot_yaw_mode yaw_mode);
+
+protected:
+
+ const char *name() const override { return "GUIDED"; }
+ const char *name4() const override { return "GUID"; }
+ autopilot_yaw_mode get_default_auto_yaw_mode(bool rtl) const;
+
+private:
+ void guided_pos_control_run();
+ void guided_vel_control_run();
+ void guided_posvel_control_run();
+ void guided_angle_control_run();
+ void guided_takeoff_run();
+ void guided_pos_control_start();
+ void guided_vel_control_start();
+ void guided_posvel_control_start();
+ void guided_angle_control_start();
+};
+
+
+
+class ModeAuto : public ModeGuided
+{
+
+public:
+ // inherit constructor
+ using ModeGuided::ModeGuided;
+
+ virtual void run() override;
+
+ bool init(bool ignore_checks) override;
+ bool requires_GPS() const override { return true; }
+ bool has_manual_throttle() const override { return false; }
+ bool allows_arming(bool from_gcs) const override { return true; }
+ bool is_autopilot() const override { return true; }
+ bool auto_loiter_start();
+ void auto_wp_start(const Vector3f& destination);
+ void auto_wp_start(const Location& dest_loc);
+ void auto_circle_movetoedge_start(const Location &circle_center, float radius_m, bool ccw_turn);
+ void auto_circle_start();
+ void auto_nav_guided_start();
+ void set_auto_yaw_roi(const Location &roi_location);
+ void set_auto_yaw_look_at_heading(float angle_deg, float turn_rate_dps, int8_t direction, uint8_t relative_angle);
+ void set_yaw_rate(float turn_rate_dps);
+ bool auto_terrain_recover_start();
+
+protected:
+
+ const char *name() const override { return "AUTO"; }
+ const char *name4() const override { return "AUTO"; }
+
+private:
+ void auto_wp_run();
+ void auto_circle_run();
+ void auto_nav_guided_run();
+ void auto_loiter_run();
+ void auto_terrain_recover_run();
+};
+
+
+class ModePoshold : public ModeAlthold
+{
+
+public:
+ // inherit constructor
+ using ModeAlthold::ModeAlthold;
+
+ virtual void run() override;
+
+ bool init(bool ignore_checks) override;
+
+ bool requires_GPS() const override { return false; }
+ bool has_manual_throttle() const override { return false; }
+ bool allows_arming(bool from_gcs) const override { return true; }
+ bool is_autopilot() const override { return true; }
+
+protected:
+
+ const char *name() const override { return "POSHOLD"; }
+ const char *name4() const override { return "POSH"; }
+};
+
+
+class ModeCircle : public Mode
+{
+
+public:
+ // inherit constructor
+ using Mode::Mode;
+
+ virtual void run() override;
+
+ bool init(bool ignore_checks) override;
+ bool requires_GPS() const override { return true; }
+ bool has_manual_throttle() const override { return false; }
+ bool allows_arming(bool from_gcs) const override { return true; }
+ bool is_autopilot() const override { return true; }
+
+protected:
+
+ const char *name() const override { return "CIRCLE"; }
+ const char *name4() const override { return "CIRC"; }
+};
+
+class ModeSurface : public Mode
+{
+
+public:
+ // inherit constructor
+ using Mode::Mode;
+
+ virtual void run() override;
+
+ bool init(bool ignore_checks) override;
+ bool requires_GPS() const override { return true; }
+ bool has_manual_throttle() const override { return false; }
+ bool allows_arming(bool from_gcs) const override { return true; }
+ bool is_autopilot() const override { return true; }
+
+protected:
+
+ const char *name() const override { return "SURFACE"; }
+ const char *name4() const override { return "SURF"; }
+};
+
+
+class ModeMotordetect : public Mode
+{
+
+public:
+ // inherit constructor
+ using Mode::Mode;
+
+ virtual void run() override;
+
+ bool init(bool ignore_checks) override;
+ bool requires_GPS() const override { return true; }
+ bool has_manual_throttle() const override { return false; }
+ bool allows_arming(bool from_gcs) const override { return true; }
+ bool is_autopilot() const override { return true; }
+
+protected:
+
+ const char *name() const override { return "MOTORDETECT"; }
+ const char *name4() const override { return "DETE"; }
+};
diff --git a/ArduSub/mode_acro.cpp b/ArduSub/mode_acro.cpp
new file mode 100644
index 00000000000000..29b1e61891667c
--- /dev/null
+++ b/ArduSub/mode_acro.cpp
@@ -0,0 +1,46 @@
+#include "Sub.h"
+
+
+
+#include "Sub.h"
+
+
+bool ModeAcro::init(bool ignore_checks) {
+ // set target altitude to zero for reporting
+ position_control->set_pos_target_z_cm(0);
+
+ // attitude hold inputs become thrust inputs in acro mode
+ // set to neutral to prevent chaotic behavior (esp. roll/pitch)
+ sub.set_neutral_controls();
+
+ return true;
+}
+
+void ModeAcro::run()
+{
+ float target_roll, target_pitch, target_yaw;
+
+ // if not armed set throttle to zero and exit immediately
+ if (!motors.armed()) {
+ motors.set_desired_spool_state(AP_Motors::DesiredSpoolState::GROUND_IDLE);
+ attitude_control->set_throttle_out(0,true,g.throttle_filt);
+ attitude_control->relax_attitude_controllers();
+ return;
+ }
+
+ motors.set_desired_spool_state(AP_Motors::DesiredSpoolState::THROTTLE_UNLIMITED);
+
+ // convert the input to the desired body frame rate
+ get_pilot_desired_angle_rates(channel_roll->get_control_in(), channel_pitch->get_control_in(), channel_yaw->get_control_in(), target_roll, target_pitch, target_yaw);
+
+ // run attitude controller
+ attitude_control->input_rate_bf_roll_pitch_yaw(target_roll, target_pitch, target_yaw);
+
+ // output pilot's throttle without angle boost
+ attitude_control->set_throttle_out(channel_throttle->norm_input(), false, g.throttle_filt);
+
+ //control_in is range 0-1000
+ //radio_in is raw pwm value
+ motors.set_forward(channel_forward->norm_input());
+ motors.set_lateral(channel_lateral->norm_input());
+}
diff --git a/ArduSub/mode_althold.cpp b/ArduSub/mode_althold.cpp
new file mode 100644
index 00000000000000..3282054d7329ad
--- /dev/null
+++ b/ArduSub/mode_althold.cpp
@@ -0,0 +1,114 @@
+#include "Sub.h"
+
+
+bool ModeAlthold::init(bool ignore_checks) {
+ if(!sub.control_check_barometer()) {
+ return false;
+ }
+
+ // initialize vertical maximum speeds and acceleration
+ // sets the maximum speed up and down returned by position controller
+ position_control->set_max_speed_accel_z(-sub.get_pilot_speed_dn(), g.pilot_speed_up, g.pilot_accel_z);
+ position_control->set_correction_speed_accel_z(-sub.get_pilot_speed_dn(), g.pilot_speed_up, g.pilot_accel_z);
+
+ // initialise position and desired velocity
+ position_control->init_z_controller();
+
+ sub.last_pilot_heading = ahrs.yaw_sensor;
+
+ return true;
+}
+
+// althold_run - runs the althold controller
+// should be called at 100hz or more
+void ModeAlthold::run()
+{
+ uint32_t tnow = AP_HAL::millis();
+
+ // initialize vertical speeds and acceleration
+ position_control->set_max_speed_accel_z(-sub.get_pilot_speed_dn(), g.pilot_speed_up, g.pilot_accel_z);
+
+ if (!motors.armed()) {
+ motors.set_desired_spool_state(AP_Motors::DesiredSpoolState::GROUND_IDLE);
+ // Sub vehicles do not stabilize roll/pitch/yaw when not auto-armed (i.e. on the ground, pilot has never raised throttle)
+ attitude_control->set_throttle_out(0.5,true,g.throttle_filt);
+ attitude_control->relax_attitude_controllers();
+ position_control->relax_z_controller(motors.get_throttle_hover());
+ sub.last_pilot_heading = ahrs.yaw_sensor;
+ return;
+ }
+
+ motors.set_desired_spool_state(AP_Motors::DesiredSpoolState::THROTTLE_UNLIMITED);
+
+ // get pilot desired lean angles
+ float target_roll, target_pitch;
+
+ // Check if set_attitude_target_no_gps is valid
+ if (tnow - sub.set_attitude_target_no_gps.last_message_ms < 5000) {
+ float target_yaw;
+ Quaternion(
+ sub.set_attitude_target_no_gps.packet.q
+ ).to_euler(
+ target_roll,
+ target_pitch,
+ target_yaw
+ );
+ target_roll = degrees(target_roll);
+ target_pitch = degrees(target_pitch);
+ target_yaw = degrees(target_yaw);
+
+ attitude_control->input_euler_angle_roll_pitch_yaw(target_roll * 1e2f, target_pitch * 1e2f, target_yaw * 1e2f, true);
+ return;
+ }
+
+ sub.get_pilot_desired_lean_angles(channel_roll->get_control_in(), channel_pitch->get_control_in(), target_roll, target_pitch, attitude_control->get_althold_lean_angle_max_cd());
+
+ // get pilot's desired yaw rate
+ float target_yaw_rate = sub.get_pilot_desired_yaw_rate(channel_yaw->get_control_in());
+
+ // call attitude controller
+ if (!is_zero(target_yaw_rate)) { // call attitude controller with rate yaw determined by pilot input
+ attitude_control->input_euler_angle_roll_pitch_euler_rate_yaw(target_roll, target_pitch, target_yaw_rate);
+ sub.last_pilot_heading = ahrs.yaw_sensor;
+ sub.last_pilot_yaw_input_ms = tnow; // time when pilot last changed heading
+
+ } else { // hold current heading
+
+ // this check is required to prevent bounce back after very fast yaw maneuvers
+ // the inertia of the vehicle causes the heading to move slightly past the point when pilot input actually stopped
+ if (tnow < sub.last_pilot_yaw_input_ms + 250) { // give 250ms to slow down, then set target heading
+ target_yaw_rate = 0; // Stop rotation on yaw axis
+
+ // call attitude controller with target yaw rate = 0 to decelerate on yaw axis
+ attitude_control->input_euler_angle_roll_pitch_euler_rate_yaw(target_roll, target_pitch, target_yaw_rate);
+ sub.last_pilot_heading = ahrs.yaw_sensor; // update heading to hold
+
+ } else { // call attitude controller holding absolute absolute bearing
+ attitude_control->input_euler_angle_roll_pitch_yaw(target_roll, target_pitch, sub.last_pilot_heading, true);
+ }
+ }
+
+ control_depth();
+
+ motors.set_forward(channel_forward->norm_input());
+ motors.set_lateral(channel_lateral->norm_input());
+}
+
+void ModeAlthold::control_depth() {
+ float target_climb_rate_cm_s = sub.get_pilot_desired_climb_rate(channel_throttle->get_control_in());
+ target_climb_rate_cm_s = constrain_float(target_climb_rate_cm_s, -sub.get_pilot_speed_dn(), g.pilot_speed_up);
+
+ // desired_climb_rate returns 0 when within the deadzone.
+ //we allow full control to the pilot, but as soon as there's no input, we handle being at surface/bottom
+ if (fabsf(target_climb_rate_cm_s) < 0.05f) {
+ if (sub.ap.at_surface) {
+ position_control->set_pos_target_z_cm(MIN(position_control->get_pos_target_z_cm(), g.surface_depth - 5.0f)); // set target to 5 cm below surface level
+ } else if (sub.ap.at_bottom) {
+ position_control->set_pos_target_z_cm(MAX(inertial_nav.get_position_z_up_cm() + 10.0f, position_control->get_pos_target_z_cm())); // set target to 10 cm above bottom
+ }
+ }
+
+ position_control->set_pos_target_z_from_climb_rate_cm(target_climb_rate_cm_s);
+ position_control->update_z_controller();
+
+}
diff --git a/ArduSub/control_auto.cpp b/ArduSub/mode_auto.cpp
similarity index 54%
rename from ArduSub/control_auto.cpp
rename to ArduSub/mode_auto.cpp
index 4631e8dcef1809..87ad912976b5cf 100644
--- a/ArduSub/control_auto.cpp
+++ b/ArduSub/mode_auto.cpp
@@ -7,42 +7,38 @@
* While in the auto flight mode, navigation or do/now commands can be run.
* Code in this file implements the navigation commands
*/
-
-// auto_init - initialise auto controller
-bool Sub::auto_init()
-{
- if (!position_ok() || mission.num_commands() < 2) {
+bool ModeAuto::init(bool ignore_checks) {
+ if (!sub.position_ok() || sub.mission.num_commands() < 2) {
return false;
}
- auto_mode = Auto_Loiter;
+ sub.auto_mode = Auto_Loiter;
// stop ROI from carrying over from previous runs of the mission
// To-Do: reset the yaw as part of auto_wp_start when the previous command was not a wp command to remove the need for this special ROI check
- if (auto_yaw_mode == AUTO_YAW_ROI) {
+ if (sub.auto_yaw_mode == AUTO_YAW_ROI) {
set_auto_yaw_mode(AUTO_YAW_HOLD);
}
// initialise waypoint controller
- wp_nav.wp_and_spline_init();
+ sub.wp_nav.wp_and_spline_init();
// clear guided limits
guided_limit_clear();
// start/resume the mission (based on MIS_RESTART parameter)
- mission.start_or_resume();
+ sub.mission.start_or_resume();
return true;
}
// auto_run - runs the appropriate auto controller
// according to the current auto_mode
-// should be called at 100hz or more
-void Sub::auto_run()
+void ModeAuto::run()
{
- mission.update();
+ sub.mission.update();
// call the correct auto controller
- switch (auto_mode) {
+ switch (sub.auto_mode) {
case Auto_WP:
case Auto_CircleMoveToEdge:
@@ -70,42 +66,42 @@ void Sub::auto_run()
}
// auto_wp_start - initialises waypoint controller to implement flying to a particular destination
-void Sub::auto_wp_start(const Vector3f& destination)
+void ModeAuto::auto_wp_start(const Vector3f& destination)
{
- auto_mode = Auto_WP;
+ sub.auto_mode = Auto_WP;
// initialise wpnav (no need to check return status because terrain data is not used)
- wp_nav.set_wp_destination(destination, false);
+ sub.wp_nav.set_wp_destination(destination, false);
// initialise yaw
// To-Do: reset the yaw only when the previous navigation command is not a WP. this would allow removing the special check for ROI
- if (auto_yaw_mode != AUTO_YAW_ROI) {
+ if (sub.auto_yaw_mode != AUTO_YAW_ROI) {
set_auto_yaw_mode(get_default_auto_yaw_mode(false));
}
}
// auto_wp_start - initialises waypoint controller to implement flying to a particular destination
-void Sub::auto_wp_start(const Location& dest_loc)
+void ModeAuto::auto_wp_start(const Location& dest_loc)
{
- auto_mode = Auto_WP;
+ sub.auto_mode = Auto_WP;
// send target to waypoint controller
- if (!wp_nav.set_wp_destination_loc(dest_loc)) {
+ if (!sub.wp_nav.set_wp_destination_loc(dest_loc)) {
// failure to set destination can only be because of missing terrain data
- failsafe_terrain_on_event();
+ sub.failsafe_terrain_on_event();
return;
}
// initialise yaw
// To-Do: reset the yaw only when the previous navigation command is not a WP. this would allow removing the special check for ROI
- if (auto_yaw_mode != AUTO_YAW_ROI) {
+ if (sub.auto_yaw_mode != AUTO_YAW_ROI) {
set_auto_yaw_mode(get_default_auto_yaw_mode(false));
}
}
// auto_wp_run - runs the auto waypoint controller
// called by auto_run at 100hz or more
-void Sub::auto_wp_run()
+void ModeAuto::auto_wp_run()
{
// if not armed set throttle to zero and exit immediately
if (!motors.armed()) {
@@ -114,17 +110,17 @@ void Sub::auto_wp_run()
// call attitude controller
// Sub vehicles do not stabilize roll/pitch/yaw when disarmed
motors.set_desired_spool_state(AP_Motors::DesiredSpoolState::GROUND_IDLE);
- attitude_control.set_throttle_out(0,true,g.throttle_filt);
- attitude_control.relax_attitude_controllers();
- wp_nav.wp_and_spline_init(); // Reset xy target
+ attitude_control->set_throttle_out(0,true,g.throttle_filt);
+ attitude_control->relax_attitude_controllers();
+ sub.wp_nav.wp_and_spline_init(); // Reset xy target
return;
}
// process pilot's yaw input
float target_yaw_rate = 0;
- if (!failsafe.pilot_input) {
+ if (!sub.failsafe.pilot_input) {
// get pilot's desired yaw rate
- target_yaw_rate = get_pilot_desired_yaw_rate(channel_yaw->get_control_in());
+ target_yaw_rate = sub.get_pilot_desired_yaw_rate(channel_yaw->get_control_in());
if (!is_zero(target_yaw_rate)) {
set_auto_yaw_mode(AUTO_YAW_HOLD);
}
@@ -137,13 +133,13 @@ void Sub::auto_wp_run()
// TODO logic for terrain tracking target going below fence limit
// TODO implement waypoint radius individually for each waypoint based on cmd.p2
// TODO fix auto yaw heading to switch to something appropriate when mission complete and switches to loiter
- failsafe_terrain_set_status(wp_nav.update_wpnav());
+ sub.failsafe_terrain_set_status(sub.wp_nav.update_wpnav());
///////////////////////
// update xy outputs //
float lateral_out, forward_out;
- translate_wpnav_rp(lateral_out, forward_out);
+ sub.translate_wpnav_rp(lateral_out, forward_out);
// Send to forward/lateral outputs
motors.set_lateral(lateral_out);
@@ -151,52 +147,52 @@ void Sub::auto_wp_run()
// WP_Nav has set the vertical position control targets
// run the vertical position controller and set output throttle
- pos_control.update_z_controller();
+ position_control->update_z_controller();
////////////////////////////
// update attitude output //
// get pilot desired lean angles
float target_roll, target_pitch;
- get_pilot_desired_lean_angles(channel_roll->get_control_in(), channel_pitch->get_control_in(), target_roll, target_pitch, aparm.angle_max);
+ sub.get_pilot_desired_lean_angles(channel_roll->get_control_in(), channel_pitch->get_control_in(), target_roll, target_pitch, sub.aparm.angle_max);
// call attitude controller
- if (auto_yaw_mode == AUTO_YAW_HOLD) {
+ if (sub.auto_yaw_mode == AUTO_YAW_HOLD) {
// roll & pitch & yaw rate from pilot
- attitude_control.input_euler_angle_roll_pitch_euler_rate_yaw(target_roll, target_pitch, target_yaw_rate);
+ attitude_control->input_euler_angle_roll_pitch_euler_rate_yaw(target_roll, target_pitch, target_yaw_rate);
} else {
// roll, pitch from pilot, yaw heading from auto_heading()
- attitude_control.input_euler_angle_roll_pitch_yaw(target_roll, target_pitch, get_auto_heading(), true);
+ attitude_control->input_euler_angle_roll_pitch_yaw(target_roll, target_pitch, get_auto_heading(), true);
}
}
// auto_circle_movetoedge_start - initialise waypoint controller to move to edge of a circle with it's center at the specified location
-// we assume the caller has set the circle's circle with circle_nav.set_center()
+// we assume the caller has set the circle's circle with sub.circle_nav.set_center()
// we assume the caller has performed all required GPS_ok checks
-void Sub::auto_circle_movetoedge_start(const Location &circle_center, float radius_m, bool ccw_turn)
+void ModeAuto::auto_circle_movetoedge_start(const Location &circle_center, float radius_m, bool ccw_turn)
{
// set circle center
- circle_nav.set_center(circle_center);
+ sub.circle_nav.set_center(circle_center);
// set circle radius
if (!is_zero(radius_m)) {
- circle_nav.set_radius_cm(radius_m * 100.0f);
+ sub.circle_nav.set_radius_cm(radius_m * 100.0f);
}
// set circle direction by using rate
- float current_rate = circle_nav.get_rate();
+ float current_rate = sub.circle_nav.get_rate();
current_rate = ccw_turn ? -fabsf(current_rate) : fabsf(current_rate);
- circle_nav.set_rate(current_rate);
+ sub.circle_nav.set_rate(current_rate);
// check our distance from edge of circle
Vector3f circle_edge_neu;
- circle_nav.get_closest_point_on_circle(circle_edge_neu);
+ sub.circle_nav.get_closest_point_on_circle(circle_edge_neu);
float dist_to_edge = (inertial_nav.get_position_neu_cm() - circle_edge_neu).length();
// if more than 3m then fly to edge
if (dist_to_edge > 300.0f) {
// set the state to move to the edge of the circle
- auto_mode = Auto_CircleMoveToEdge;
+ sub.auto_mode = Auto_CircleMoveToEdge;
// convert circle_edge_neu to Location
Location circle_edge(circle_edge_neu, Location::AltFrame::ABOVE_ORIGIN);
@@ -205,14 +201,14 @@ void Sub::auto_circle_movetoedge_start(const Location &circle_center, float radi
circle_edge.set_alt_cm(circle_center.alt, circle_center.get_alt_frame());
// initialise wpnav to move to edge of circle
- if (!wp_nav.set_wp_destination_loc(circle_edge)) {
+ if (!sub.wp_nav.set_wp_destination_loc(circle_edge)) {
// failure to set destination can only be because of missing terrain data
- failsafe_terrain_on_event();
+ sub.failsafe_terrain_on_event();
}
// if we are outside the circle, point at the edge, otherwise hold yaw
- float dist_to_center = get_horizontal_distance_cm(inertial_nav.get_position_xy_cm().topostype(), circle_nav.get_center().xy());
- if (dist_to_center > circle_nav.get_radius() && dist_to_center > 500) {
+ float dist_to_center = get_horizontal_distance_cm(inertial_nav.get_position_xy_cm().topostype(), sub.circle_nav.get_center().xy());
+ if (dist_to_center > sub.circle_nav.get_radius() && dist_to_center > 500) {
set_auto_yaw_mode(get_default_auto_yaw_mode(false));
} else {
// vehicle is within circle so hold yaw to avoid spinning as we move to edge of circle
@@ -225,23 +221,23 @@ void Sub::auto_circle_movetoedge_start(const Location &circle_center, float radi
// auto_circle_start - initialises controller to fly a circle in AUTO flight mode
// assumes that circle_nav object has already been initialised with circle center and radius
-void Sub::auto_circle_start()
+void ModeAuto::auto_circle_start()
{
- auto_mode = Auto_Circle;
+ sub.auto_mode = Auto_Circle;
// initialise circle controller
- circle_nav.init(circle_nav.get_center(), circle_nav.center_is_terrain_alt(), circle_nav.get_rate());
+ sub.circle_nav.init(sub.circle_nav.get_center(), sub.circle_nav.center_is_terrain_alt(), sub.circle_nav.get_rate());
}
// auto_circle_run - circle in AUTO flight mode
// called by auto_run at 100hz or more
-void Sub::auto_circle_run()
+void ModeAuto::auto_circle_run()
{
// call circle controller
- failsafe_terrain_set_status(circle_nav.update());
+ sub.failsafe_terrain_set_status(sub.circle_nav.update());
float lateral_out, forward_out;
- translate_circle_nav_rp(lateral_out, forward_out);
+ sub.translate_circle_nav_rp(lateral_out, forward_out);
// Send to forward/lateral outputs
motors.set_lateral(lateral_out);
@@ -249,50 +245,47 @@ void Sub::auto_circle_run()
// WP_Nav has set the vertical position control targets
// run the vertical position controller and set output throttle
- pos_control.update_z_controller();
+ position_control->update_z_controller();
// roll & pitch from waypoint controller, yaw rate from pilot
- attitude_control.input_euler_angle_roll_pitch_yaw(channel_roll->get_control_in(), channel_pitch->get_control_in(), circle_nav.get_yaw(), true);
+ attitude_control->input_euler_angle_roll_pitch_yaw(channel_roll->get_control_in(), channel_pitch->get_control_in(), sub.circle_nav.get_yaw(), true);
}
#if NAV_GUIDED == ENABLED
// auto_nav_guided_start - hand over control to external navigation controller in AUTO mode
-void Sub::auto_nav_guided_start()
+void ModeAuto::auto_nav_guided_start()
{
- auto_mode = Auto_NavGuided;
-
- // call regular guided flight mode initialisation
- guided_init(true);
-
+ sub.mode_guided.init(true);
+ sub.auto_mode = Auto_NavGuided;
// initialise guided start time and position as reference for limit checking
- guided_limit_init_time_and_pos();
+ sub.mode_auto.guided_limit_init_time_and_pos();
}
// auto_nav_guided_run - allows control by external navigation controller
// called by auto_run at 100hz or more
-void Sub::auto_nav_guided_run()
+void ModeAuto::auto_nav_guided_run()
{
// call regular guided flight mode run function
- guided_run();
+ sub.mode_guided.run();
}
#endif // NAV_GUIDED
// auto_loiter_start - initialises loitering in auto mode
// returns success/failure because this can be called by exit_mission
-bool Sub::auto_loiter_start()
+bool ModeAuto::auto_loiter_start()
{
// return failure if GPS is bad
- if (!position_ok()) {
+ if (!sub.position_ok()) {
return false;
}
- auto_mode = Auto_Loiter;
+ sub.auto_mode = Auto_Loiter;
// calculate stopping point
Vector3f stopping_point;
- wp_nav.get_wp_stopping_point(stopping_point);
+ sub.wp_nav.get_wp_stopping_point(stopping_point);
// initialise waypoint controller target to stopping point
- wp_nav.set_wp_destination(stopping_point);
+ sub.wp_nav.set_wp_destination(stopping_point);
// hold yaw at current heading
set_auto_yaw_mode(AUTO_YAW_HOLD);
@@ -302,35 +295,35 @@ bool Sub::auto_loiter_start()
// auto_loiter_run - loiter in AUTO flight mode
// called by auto_run at 100hz or more
-void Sub::auto_loiter_run()
+void ModeAuto::auto_loiter_run()
{
// if not armed set throttle to zero and exit immediately
if (!motors.armed()) {
motors.set_desired_spool_state(AP_Motors::DesiredSpoolState::GROUND_IDLE);
// Sub vehicles do not stabilize roll/pitch/yaw when disarmed
- attitude_control.set_throttle_out(0,true,g.throttle_filt);
- attitude_control.relax_attitude_controllers();
+ attitude_control->set_throttle_out(0,true,g.throttle_filt);
+ attitude_control->relax_attitude_controllers();
- wp_nav.wp_and_spline_init(); // Reset xy target
+ sub.wp_nav.wp_and_spline_init(); // Reset xy target
return;
}
// accept pilot input of yaw
float target_yaw_rate = 0;
- if (!failsafe.pilot_input) {
- target_yaw_rate = get_pilot_desired_yaw_rate(channel_yaw->get_control_in());
+ if (!sub.failsafe.pilot_input) {
+ target_yaw_rate = sub.get_pilot_desired_yaw_rate(channel_yaw->get_control_in());
}
// set motors to full range
motors.set_desired_spool_state(AP_Motors::DesiredSpoolState::THROTTLE_UNLIMITED);
// run waypoint and z-axis position controller
- failsafe_terrain_set_status(wp_nav.update_wpnav());
+ sub.failsafe_terrain_set_status(sub.wp_nav.update_wpnav());
///////////////////////
// update xy outputs //
float lateral_out, forward_out;
- translate_wpnav_rp(lateral_out, forward_out);
+ sub.translate_wpnav_rp(lateral_out, forward_out);
// Send to forward/lateral outputs
motors.set_lateral(lateral_out);
@@ -338,113 +331,41 @@ void Sub::auto_loiter_run()
// WP_Nav has set the vertical position control targets
// run the vertical position controller and set output throttle
- pos_control.update_z_controller();
+ position_control->update_z_controller();
// get pilot desired lean angles
float target_roll, target_pitch;
- get_pilot_desired_lean_angles(channel_roll->get_control_in(), channel_pitch->get_control_in(), target_roll, target_pitch, aparm.angle_max);
+ sub.get_pilot_desired_lean_angles(channel_roll->get_control_in(), channel_pitch->get_control_in(), target_roll, target_pitch, sub.aparm.angle_max);
// roll & pitch & yaw rate from pilot
- attitude_control.input_euler_angle_roll_pitch_euler_rate_yaw(target_roll, target_pitch, target_yaw_rate);
-}
-
-// get_default_auto_yaw_mode - returns auto_yaw_mode based on WP_YAW_BEHAVIOR parameter
-// set rtl parameter to true if this is during an RTL
-uint8_t Sub::get_default_auto_yaw_mode(bool rtl) const
-{
- switch (g.wp_yaw_behavior) {
-
- case WP_YAW_BEHAVIOR_NONE:
- return AUTO_YAW_HOLD;
- break;
-
- case WP_YAW_BEHAVIOR_LOOK_AT_NEXT_WP_EXCEPT_RTL:
- if (rtl) {
- return AUTO_YAW_HOLD;
- } else {
- return AUTO_YAW_LOOK_AT_NEXT_WP;
- }
- break;
-
- case WP_YAW_BEHAVIOR_LOOK_AHEAD:
- return AUTO_YAW_LOOK_AHEAD;
- break;
-
- case WP_YAW_BEHAVIOR_CORRECT_XTRACK:
- return AUTO_YAW_CORRECT_XTRACK;
- break;
-
- case WP_YAW_BEHAVIOR_LOOK_AT_NEXT_WP:
- default:
- return AUTO_YAW_LOOK_AT_NEXT_WP;
- break;
- }
+ attitude_control->input_euler_angle_roll_pitch_euler_rate_yaw(target_roll, target_pitch, target_yaw_rate);
}
-// set_auto_yaw_mode - sets the yaw mode for auto
-void Sub::set_auto_yaw_mode(uint8_t yaw_mode)
-{
- // return immediately if no change
- if (auto_yaw_mode == yaw_mode) {
- return;
- }
- auto_yaw_mode = yaw_mode;
-
- // perform initialisation
- switch (auto_yaw_mode) {
-
- case AUTO_YAW_LOOK_AT_NEXT_WP:
- // wpnav will initialise heading when wpnav's set_destination method is called
- break;
-
- case AUTO_YAW_ROI:
- // point towards a location held in yaw_look_at_WP
- yaw_look_at_WP_bearing = ahrs.yaw_sensor;
- break;
-
- case AUTO_YAW_LOOK_AT_HEADING:
- // keep heading pointing in the direction held in yaw_look_at_heading
- // caller should set the yaw_look_at_heading
- break;
-
- case AUTO_YAW_LOOK_AHEAD:
- // Commanded Yaw to automatically look ahead.
- yaw_look_ahead_bearing = ahrs.yaw_sensor;
- break;
-
- case AUTO_YAW_RESETTOARMEDYAW:
- // initial_armed_bearing will be set during arming so no init required
- break;
- }
-}
// set_auto_yaw_look_at_heading - sets the yaw look at heading for auto mode
-void Sub::set_auto_yaw_look_at_heading(float angle_deg, float turn_rate_dps, int8_t direction, uint8_t relative_angle)
+void ModeAuto::set_auto_yaw_look_at_heading(float angle_deg, float turn_rate_dps, int8_t direction, uint8_t relative_angle)
{
- // get current yaw target
- int32_t curr_yaw_target = attitude_control.get_att_target_euler_cd().z;
+ // get current yaw
+ int32_t curr_yaw_target = attitude_control->get_att_target_euler_cd().z;
// get final angle, 1 = Relative, 0 = Absolute
if (relative_angle == 0) {
// absolute angle
- yaw_look_at_heading = wrap_360_cd(angle_deg * 100);
+ sub.yaw_look_at_heading = wrap_360_cd(angle_deg * 100);
} else {
// relative angle
if (direction < 0) {
angle_deg = -angle_deg;
}
- yaw_look_at_heading = wrap_360_cd((angle_deg*100+curr_yaw_target));
+ sub.yaw_look_at_heading = wrap_360_cd((angle_deg * 100 + curr_yaw_target));
}
// get turn speed
- // TODO actually implement this, right now, yaw_look_at_heading_slew is unused
- // see AP_Float _slew_yaw in AC_AttitudeControl
if (is_zero(turn_rate_dps)) {
// default to regular auto slew rate
- yaw_look_at_heading_slew = AUTO_YAW_SLEW_RATE;
+ sub.yaw_look_at_heading_slew = AUTO_YAW_SLEW_RATE;
} else {
- int32_t turn_rate = (wrap_180_cd(yaw_look_at_heading - curr_yaw_target) / 100) / turn_rate_dps;
- yaw_look_at_heading_slew = constrain_int32(turn_rate, 1, 360); // deg / sec
+ sub.yaw_look_at_heading_slew = MIN(turn_rate_dps, AUTO_YAW_SLEW_RATE); // deg / sec
}
// set yaw mode
@@ -453,8 +374,19 @@ void Sub::set_auto_yaw_look_at_heading(float angle_deg, float turn_rate_dps, int
// TO-DO: restore support for clockwise and counter clockwise rotation held in cmd.content.yaw.direction. 1 = clockwise, -1 = counterclockwise
}
+
+// sets the desired yaw rate
+void ModeAuto::set_yaw_rate(float turn_rate_dps)
+{
+ // set sub to desired yaw rate
+ sub.yaw_look_at_heading_slew = MIN(turn_rate_dps, AUTO_YAW_SLEW_RATE); // deg / sec
+
+ // set yaw mode
+ set_auto_yaw_mode(AUTO_YAW_RATE);
+}
+
// set_auto_yaw_roi - sets the yaw to look at roi for auto mode
-void Sub::set_auto_yaw_roi(const Location &roi_location)
+void ModeAuto::set_auto_yaw_roi(const Location &roi_location)
{
// if location is zero lat, lon and altitude turn off ROI
if (roi_location.alt == 0 && roi_location.lat == 0 && roi_location.lng == 0) {
@@ -462,20 +394,20 @@ void Sub::set_auto_yaw_roi(const Location &roi_location)
set_auto_yaw_mode(get_default_auto_yaw_mode(false));
#if HAL_MOUNT_ENABLED
// switch off the camera tracking if enabled
- if (camera_mount.get_mode() == MAV_MOUNT_MODE_GPS_POINT) {
- camera_mount.set_mode_to_default();
+ if (sub.camera_mount.get_mode() == MAV_MOUNT_MODE_GPS_POINT) {
+ sub.camera_mount.set_mode_to_default();
}
#endif // HAL_MOUNT_ENABLED
} else {
#if HAL_MOUNT_ENABLED
// check if mount type requires us to rotate the sub
- if (!camera_mount.has_pan_control()) {
- if (roi_location.get_vector_from_origin_NEU(roi_WP)) {
+ if (!sub.camera_mount.has_pan_control()) {
+ if (roi_location.get_vector_from_origin_NEU(sub.roi_WP)) {
set_auto_yaw_mode(AUTO_YAW_ROI);
}
}
// send the command to the camera mount
- camera_mount.set_roi_target(roi_location);
+ sub.camera_mount.set_roi_target(roi_location);
// TO-DO: expand handling of the do_nav_roi to support all modes of the MAVLink. Currently we only handle mode 4 (see below)
// 0: do nothing
@@ -485,70 +417,18 @@ void Sub::set_auto_yaw_roi(const Location &roi_location)
// 4: point at a target given a target id (can't be implemented)
#else
// if we have no camera mount aim the sub at the location
- if (roi_location.get_vector_from_origin_NEU(roi_WP)) {
+ if (roi_location.get_vector_from_origin_NEU(sub.roi_WP)) {
set_auto_yaw_mode(AUTO_YAW_ROI);
}
#endif // HAL_MOUNT_ENABLED
}
}
-// get_auto_heading - returns target heading depending upon auto_yaw_mode
-// 100hz update rate
-float Sub::get_auto_heading()
-{
- switch (auto_yaw_mode) {
-
- case AUTO_YAW_ROI:
- // point towards a location held in roi_WP
- return get_roi_yaw();
- break;
-
- case AUTO_YAW_LOOK_AT_HEADING:
- // keep heading pointing in the direction held in yaw_look_at_heading with no pilot input allowed
- return yaw_look_at_heading;
- break;
-
- case AUTO_YAW_LOOK_AHEAD:
- // Commanded Yaw to automatically look ahead.
- return get_look_ahead_yaw();
- break;
-
- case AUTO_YAW_RESETTOARMEDYAW:
- // changes yaw to be same as when quad was armed
- return initial_armed_bearing;
- break;
-
- case AUTO_YAW_CORRECT_XTRACK: {
- // TODO return current yaw if not in appropriate mode
- // Bearing of current track (centidegrees)
- float track_bearing = get_bearing_cd(wp_nav.get_wp_origin().xy(), wp_nav.get_wp_destination().xy());
-
- // Bearing from current position towards intermediate position target (centidegrees)
- const Vector2f target_vel_xy{pos_control.get_vel_target_cms().x, pos_control.get_vel_target_cms().y};
- float angle_error = 0.0f;
- if (target_vel_xy.length() >= pos_control.get_max_speed_xy_cms() * 0.1f) {
- const float desired_angle_cd = degrees(target_vel_xy.angle()) * 100.0f;
- angle_error = wrap_180_cd(desired_angle_cd - track_bearing);
- }
- float angle_limited = constrain_float(angle_error, -g.xtrack_angle_limit * 100.0f, g.xtrack_angle_limit * 100.0f);
- return wrap_360_cd(track_bearing + angle_limited);
- }
- break;
-
- case AUTO_YAW_LOOK_AT_NEXT_WP:
- default:
- // point towards next waypoint.
- // we don't use wp_bearing because we don't want the vehicle to turn too much during flight
- return wp_nav.get_yaw();
- break;
- }
-}
-
// Return true if it is possible to recover from a rangefinder failure
-bool Sub::auto_terrain_recover_start()
+bool ModeAuto::auto_terrain_recover_start()
{
// Check rangefinder status to see if recovery is possible
- switch (rangefinder.status_orient(ROTATION_PITCH_270)) {
+ switch (sub.rangefinder.status_orient(ROTATION_PITCH_270)) {
case RangeFinder::Status::OutOfRangeLow:
case RangeFinder::Status::OutOfRangeHigh:
@@ -556,7 +436,7 @@ bool Sub::auto_terrain_recover_start()
// RangeFinder::Good if just one valid sample was obtained recently, but ::rangefinder_state.alt_healthy
// requires several consecutive valid readings for wpnav to accept rangefinder data
case RangeFinder::Status::Good:
- auto_mode = Auto_TerrainRecover;
+ sub.auto_mode = Auto_TerrainRecover;
break;
// Not connected or no data
@@ -565,21 +445,21 @@ bool Sub::auto_terrain_recover_start()
}
// Initialize recovery timeout time
- fs_terrain_recover_start_ms = AP_HAL::millis();
+ sub.fs_terrain_recover_start_ms = AP_HAL::millis();
// Stop mission
- mission.stop();
+ sub.mission.stop();
// Reset xy target
- loiter_nav.clear_pilot_desired_acceleration();
- loiter_nav.init_target();
+ sub.loiter_nav.clear_pilot_desired_acceleration();
+ sub.loiter_nav.init_target();
// Reset z axis controller
- pos_control.relax_z_controller(motors.get_throttle_hover());
+ position_control->relax_z_controller(motors.get_throttle_hover());
// initialize vertical maximum speeds and acceleration
- pos_control.set_max_speed_accel_z(wp_nav.get_default_speed_down(), wp_nav.get_default_speed_up(), wp_nav.get_accel_z());
- pos_control.set_correction_speed_accel_z(wp_nav.get_default_speed_down(), wp_nav.get_default_speed_up(), wp_nav.get_accel_z());
+ position_control->set_max_speed_accel_z(sub.wp_nav.get_default_speed_down(), sub.wp_nav.get_default_speed_up(), sub.wp_nav.get_accel_z());
+ position_control->set_correction_speed_accel_z(sub.wp_nav.get_default_speed_down(), sub.wp_nav.get_default_speed_up(), sub.wp_nav.get_accel_z());
gcs().send_text(MAV_SEVERITY_WARNING, "Attempting auto failsafe recovery");
return true;
@@ -588,7 +468,7 @@ bool Sub::auto_terrain_recover_start()
// Attempt recovery from terrain failsafe
// If recovery is successful resume mission
// If recovery fails revert to failsafe action
-void Sub::auto_terrain_recover_run()
+void ModeAuto::auto_terrain_recover_run()
{
float target_climb_rate = 0;
static uint32_t rangefinder_recovery_ms = 0;
@@ -596,23 +476,23 @@ void Sub::auto_terrain_recover_run()
// if not armed set throttle to zero and exit immediately
if (!motors.armed()) {
motors.set_desired_spool_state(AP_Motors::DesiredSpoolState::GROUND_IDLE);
- attitude_control.set_throttle_out(0,true,g.throttle_filt);
- attitude_control.relax_attitude_controllers();
+ attitude_control->set_throttle_out(0,true,g.throttle_filt);
+ attitude_control->relax_attitude_controllers();
- loiter_nav.init_target(); // Reset xy target
- pos_control.relax_z_controller(motors.get_throttle_hover()); // Reset z axis controller
+ sub.loiter_nav.init_target(); // Reset xy target
+ position_control->relax_z_controller(motors.get_throttle_hover()); // Reset z axis controller
return;
}
- switch (rangefinder.status_orient(ROTATION_PITCH_270)) {
+ switch (sub.rangefinder.status_orient(ROTATION_PITCH_270)) {
case RangeFinder::Status::OutOfRangeLow:
- target_climb_rate = wp_nav.get_default_speed_up();
+ target_climb_rate = sub.wp_nav.get_default_speed_up();
rangefinder_recovery_ms = 0;
break;
case RangeFinder::Status::OutOfRangeHigh:
- target_climb_rate = wp_nav.get_default_speed_down();
+ target_climb_rate = sub.wp_nav.get_default_speed_down();
rangefinder_recovery_ms = 0;
break;
@@ -620,21 +500,21 @@ void Sub::auto_terrain_recover_run()
target_climb_rate = 0; // Attempt to hold current depth
- if (rangefinder_state.alt_healthy) {
+ if (sub.rangefinder_state.alt_healthy) {
// Start timer as soon as rangefinder is healthy
if (rangefinder_recovery_ms == 0) {
rangefinder_recovery_ms = AP_HAL::millis();
- pos_control.relax_z_controller(motors.get_throttle_hover()); // Reset alt hold targets
+ position_control->relax_z_controller(motors.get_throttle_hover()); // Reset alt hold targets
}
// 1.5 seconds of healthy rangefinder means we can resume mission with terrain enabled
if (AP_HAL::millis() > rangefinder_recovery_ms + 1500) {
gcs().send_text(MAV_SEVERITY_INFO, "Terrain failsafe recovery successful!");
- failsafe_terrain_set_status(true); // Reset failsafe timers
- failsafe.terrain = false; // Clear flag
- auto_mode = Auto_Loiter; // Switch back to loiter for next iteration
- mission.resume(); // Resume mission
+ sub.failsafe_terrain_set_status(true); // Reset failsafe timers
+ sub.failsafe.terrain = false; // Clear flag
+ sub.auto_mode = Auto_Loiter; // Switch back to loiter for next iteration
+ sub.mission.resume(); // Resume mission
rangefinder_recovery_ms = 0; // Reset for subsequent recoveries
}
@@ -646,25 +526,25 @@ void Sub::auto_terrain_recover_run()
// Terrain failsafe recovery has failed, terrain data is not available
// and rangefinder is not connected, or has stopped responding
gcs().send_text(MAV_SEVERITY_CRITICAL, "Terrain failsafe recovery failure: No Rangefinder!");
- failsafe_terrain_act();
+ sub.failsafe_terrain_act();
rangefinder_recovery_ms = 0;
return;
}
// exit on failure (timeout)
- if (AP_HAL::millis() > fs_terrain_recover_start_ms + FS_TERRAIN_RECOVER_TIMEOUT_MS) {
+ if (AP_HAL::millis() > sub.fs_terrain_recover_start_ms + FS_TERRAIN_RECOVER_TIMEOUT_MS) {
// Recovery has failed, revert to failsafe action
gcs().send_text(MAV_SEVERITY_CRITICAL, "Terrain failsafe recovery timeout!");
- failsafe_terrain_act();
+ sub.failsafe_terrain_act();
}
// run loiter controller
- loiter_nav.update();
+ sub.loiter_nav.update();
///////////////////////
// update xy targets //
float lateral_out, forward_out;
- translate_wpnav_rp(lateral_out, forward_out);
+ sub.translate_wpnav_rp(lateral_out, forward_out);
// Send to forward/lateral outputs
motors.set_lateral(lateral_out);
@@ -672,8 +552,8 @@ void Sub::auto_terrain_recover_run()
/////////////////////
// update z target //
- pos_control.set_pos_target_z_from_climb_rate_cm(target_climb_rate);
- pos_control.update_z_controller();
+ position_control->set_pos_target_z_from_climb_rate_cm(target_climb_rate);
+ position_control->update_z_controller();
////////////////////////////
// update angular targets //
@@ -681,11 +561,11 @@ void Sub::auto_terrain_recover_run()
float target_pitch = 0;
// convert pilot input to lean angles
- // To-Do: convert get_pilot_desired_lean_angles to return angles as floats
- get_pilot_desired_lean_angles(channel_roll->get_control_in(), channel_pitch->get_control_in(), target_roll, target_pitch, aparm.angle_max);
+ // To-Do: convert sub.get_pilot_desired_lean_angles to return angles as floats
+ sub.get_pilot_desired_lean_angles(channel_roll->get_control_in(), channel_pitch->get_control_in(), target_roll, target_pitch, sub.aparm.angle_max);
float target_yaw_rate = 0;
// call attitude controller
- attitude_control.input_euler_angle_roll_pitch_euler_rate_yaw(target_roll, target_pitch, target_yaw_rate);
+ attitude_control->input_euler_angle_roll_pitch_euler_rate_yaw(target_roll, target_pitch, target_yaw_rate);
}
diff --git a/ArduSub/mode_circle.cpp b/ArduSub/mode_circle.cpp
new file mode 100644
index 00000000000000..28be79dbad54cd
--- /dev/null
+++ b/ArduSub/mode_circle.cpp
@@ -0,0 +1,86 @@
+#include "Sub.h"
+
+/*
+ * control_circle.pde - init and run calls for circle flight mode
+ */
+
+// circle_init - initialise circle controller flight mode
+bool ModeCircle::init(bool ignore_checks)
+{
+ if (!sub.position_ok()) {
+ return false;
+ }
+
+ sub.circle_pilot_yaw_override = false;
+
+ // initialize speeds and accelerations
+ position_control->set_max_speed_accel_xy(sub.wp_nav.get_default_speed_xy(), sub.wp_nav.get_wp_acceleration());
+ position_control->set_correction_speed_accel_xy(sub.wp_nav.get_default_speed_xy(), sub.wp_nav.get_wp_acceleration());
+ position_control->set_max_speed_accel_z(-sub.get_pilot_speed_dn(), g.pilot_speed_up, g.pilot_accel_z);
+ position_control->set_correction_speed_accel_z(-sub.get_pilot_speed_dn(), g.pilot_speed_up, g.pilot_accel_z);
+
+ // initialise circle controller including setting the circle center based on vehicle speed
+ sub.circle_nav.init();
+
+ return true;
+}
+
+// circle_run - runs the circle flight mode
+// should be called at 100hz or more
+void ModeCircle::run()
+{
+ float target_yaw_rate = 0;
+ float target_climb_rate = 0;
+
+ // update parameters, to allow changing at runtime
+ position_control->set_max_speed_accel_xy(sub.wp_nav.get_default_speed_xy(), sub.wp_nav.get_wp_acceleration());
+ position_control->set_max_speed_accel_z(-sub.get_pilot_speed_dn(), g.pilot_speed_up, g.pilot_accel_z);
+
+ // if not armed set throttle to zero and exit immediately
+ if (!motors.armed()) {
+ // To-Do: add some initialisation of position controllers
+ motors.set_desired_spool_state(AP_Motors::DesiredSpoolState::GROUND_IDLE);
+ // Sub vehicles do not stabilize roll/pitch/yaw when disarmed
+ attitude_control->set_throttle_out(0,true,g.throttle_filt);
+ attitude_control->relax_attitude_controllers();
+ sub.circle_nav.init();
+ return;
+ }
+
+ // process pilot inputs
+ // get pilot's desired yaw rate
+ target_yaw_rate = sub.get_pilot_desired_yaw_rate(channel_yaw->get_control_in());
+ if (!is_zero(target_yaw_rate)) {
+ sub.circle_pilot_yaw_override = true;
+ }
+
+ // get pilot desired climb rate
+ target_climb_rate = sub.get_pilot_desired_climb_rate(channel_throttle->get_control_in());
+
+ // set motors to full range
+ motors.set_desired_spool_state(AP_Motors::DesiredSpoolState::THROTTLE_UNLIMITED);
+
+ // run circle controller
+ sub.failsafe_terrain_set_status(sub.circle_nav.update());
+
+ ///////////////////////
+ // update xy outputs //
+
+ float lateral_out, forward_out;
+ sub.translate_circle_nav_rp(lateral_out, forward_out);
+
+ // Send to forward/lateral outputs
+ motors.set_lateral(lateral_out);
+ motors.set_forward(forward_out);
+
+ // call attitude controller
+ if (sub.circle_pilot_yaw_override) {
+ attitude_control->input_euler_angle_roll_pitch_euler_rate_yaw(channel_roll->get_control_in(), channel_pitch->get_control_in(), target_yaw_rate);
+ } else {
+ attitude_control->input_euler_angle_roll_pitch_yaw(channel_roll->get_control_in(), channel_pitch->get_control_in(), sub.circle_nav.get_yaw(), true);
+ }
+
+ // update altitude target and call position controller
+ position_control->set_pos_target_z_from_climb_rate_cm(target_climb_rate);
+ position_control->update_z_controller();
+}
diff --git a/ArduSub/mode_guided.cpp b/ArduSub/mode_guided.cpp
new file mode 100644
index 00000000000000..25857bf5c94e64
--- /dev/null
+++ b/ArduSub/mode_guided.cpp
@@ -0,0 +1,866 @@
+#include "Sub.h"
+
+/*
+ * Init and run calls for guided flight mode
+ */
+
+#define GUIDED_POSVEL_TIMEOUT_MS 3000 // guided mode's position-velocity controller times out after 3seconds with no new updates
+#define GUIDED_ATTITUDE_TIMEOUT_MS 1000 // guided mode's attitude controller times out after 1 second with no new updates
+
+static Vector3p posvel_pos_target_cm;
+static Vector3f posvel_vel_target_cms;
+static uint32_t update_time_ms;
+
+struct {
+ uint32_t update_time_ms;
+ float roll_cd;
+ float pitch_cd;
+ float yaw_cd;
+ float climb_rate_cms;
+} static guided_angle_state = {0,0.0f, 0.0f, 0.0f, 0.0f};
+
+struct Guided_Limit {
+ uint32_t timeout_ms; // timeout (in seconds) from the time that guided is invoked
+ float alt_min_cm; // lower altitude limit in cm above home (0 = no limit)
+ float alt_max_cm; // upper altitude limit in cm above home (0 = no limit)
+ float horiz_max_cm; // horizontal position limit in cm from where guided mode was initiated (0 = no limit)
+ uint32_t start_time;// system time in milliseconds that control was handed to the external computer
+ Vector3f start_pos; // start position as a distance from home in cm. used for checking horiz_max limit
+} guided_limit;
+
+// guided_init - initialise guided controller
+bool ModeGuided::init(bool ignore_checks)
+{
+ if (!sub.position_ok() && !ignore_checks) {
+ return false;
+ }
+
+ // start in position control mode
+ guided_pos_control_start();
+ return true;
+}
+
+// get_default_auto_yaw_mode - returns auto_yaw_mode based on WP_YAW_BEHAVIOR parameter
+// set rtl parameter to true if this is during an RTL
+autopilot_yaw_mode ModeGuided::get_default_auto_yaw_mode(bool rtl) const
+{
+ switch (g.wp_yaw_behavior) {
+
+ case WP_YAW_BEHAVIOR_NONE:
+ return AUTO_YAW_HOLD;
+ break;
+
+ case WP_YAW_BEHAVIOR_LOOK_AT_NEXT_WP_EXCEPT_RTL:
+ if (rtl) {
+ return AUTO_YAW_HOLD;
+ } else {
+ return AUTO_YAW_LOOK_AT_NEXT_WP;
+ }
+ break;
+
+ case WP_YAW_BEHAVIOR_LOOK_AHEAD:
+ return AUTO_YAW_LOOK_AHEAD;
+ break;
+
+ case WP_YAW_BEHAVIOR_CORRECT_XTRACK:
+ return AUTO_YAW_CORRECT_XTRACK;
+ break;
+
+ case WP_YAW_BEHAVIOR_LOOK_AT_NEXT_WP:
+ default:
+ return AUTO_YAW_LOOK_AT_NEXT_WP;
+ break;
+ }
+}
+
+
+// initialise guided mode's position controller
+void ModeGuided::guided_pos_control_start()
+{
+ // set to position control mode
+ sub.guided_mode = Guided_WP;
+
+ // initialise waypoint controller
+ sub.wp_nav.wp_and_spline_init();
+
+ // initialise wpnav to stopping point at current altitude
+ // To-Do: set to current location if disarmed?
+ // To-Do: set to stopping point altitude?
+ Vector3f stopping_point;
+ sub.wp_nav.get_wp_stopping_point(stopping_point);
+
+ // no need to check return status because terrain data is not used
+ sub.wp_nav.set_wp_destination(stopping_point, false);
+
+ // initialise yaw
+ set_auto_yaw_mode(get_default_auto_yaw_mode(false));
+}
+
+// initialise guided mode's velocity controller
+void ModeGuided::guided_vel_control_start()
+{
+ // set guided_mode to velocity controller
+ sub.guided_mode = Guided_Velocity;
+
+ // initialize vertical maximum speeds and acceleration
+ position_control->set_max_speed_accel_z(-sub.get_pilot_speed_dn(), g.pilot_speed_up, g.pilot_accel_z);
+ position_control->set_correction_speed_accel_z(-sub.get_pilot_speed_dn(), g.pilot_speed_up, g.pilot_accel_z);
+
+ // initialise velocity controller
+ position_control->init_z_controller();
+ position_control->init_xy_controller();
+
+ // pilot always controls yaw
+ set_auto_yaw_mode(AUTO_YAW_HOLD);
+}
+
+// initialise guided mode's posvel controller
+void ModeGuided::guided_posvel_control_start()
+{
+ // set guided_mode to velocity controller
+ sub.guided_mode = Guided_PosVel;
+
+ // set vertical speed and acceleration
+ position_control->set_max_speed_accel_z(sub.wp_nav.get_default_speed_down(), sub.wp_nav.get_default_speed_up(), sub.wp_nav.get_accel_z());
+ position_control->set_correction_speed_accel_z(sub.wp_nav.get_default_speed_down(), sub.wp_nav.get_default_speed_up(), sub.wp_nav.get_accel_z());
+
+ // initialise velocity controller
+ position_control->init_z_controller();
+ position_control->init_xy_controller();
+
+ // pilot always controls yaw
+ set_auto_yaw_mode(AUTO_YAW_HOLD);
+}
+
+// initialise guided mode's angle controller
+void ModeGuided::guided_angle_control_start()
+{
+ // set guided_mode to velocity controller
+ sub.guided_mode = Guided_Angle;
+
+ // set vertical speed and acceleration
+ position_control->set_max_speed_accel_z(sub.wp_nav.get_default_speed_down(), sub.wp_nav.get_default_speed_up(), sub.wp_nav.get_accel_z());
+ position_control->set_correction_speed_accel_z(sub.wp_nav.get_default_speed_down(), sub.wp_nav.get_default_speed_up(), sub.wp_nav.get_accel_z());
+
+ // initialise velocity controller
+ position_control->init_z_controller();
+
+ // initialise targets
+ guided_angle_state.update_time_ms = AP_HAL::millis();
+ guided_angle_state.roll_cd = ahrs.roll_sensor;
+ guided_angle_state.pitch_cd = ahrs.pitch_sensor;
+ guided_angle_state.yaw_cd = ahrs.yaw_sensor;
+ guided_angle_state.climb_rate_cms = 0.0f;
+
+ // pilot always controls yaw
+ set_auto_yaw_mode(AUTO_YAW_HOLD);
+}
+
+// guided_set_destination - sets guided mode's target destination
+// Returns true if the fence is enabled and guided waypoint is within the fence
+// else return false if the waypoint is outside the fence
+bool ModeGuided::guided_set_destination(const Vector3f& destination)
+{
+ // ensure we are in position control mode
+ if (sub.guided_mode != Guided_WP) {
+ guided_pos_control_start();
+ }
+
+#if AP_FENCE_ENABLED
+ // reject destination if outside the fence
+ const Location dest_loc(destination, Location::AltFrame::ABOVE_ORIGIN);
+ if (!sub.fence.check_destination_within_fence(dest_loc)) {
+ AP::logger().Write_Error(LogErrorSubsystem::NAVIGATION, LogErrorCode::DEST_OUTSIDE_FENCE);
+ // failure is propagated to GCS with NAK
+ return false;
+ }
+#endif
+
+ // no need to check return status because terrain data is not used
+ sub.wp_nav.set_wp_destination(destination, false);
+
+ // log target
+ sub.Log_Write_GuidedTarget(sub.guided_mode, destination, Vector3f());
+ return true;
+}
+
+// sets guided mode's target from a Location object
+// returns false if destination could not be set (probably caused by missing terrain data)
+// or if the fence is enabled and guided waypoint is outside the fence
+bool ModeGuided::guided_set_destination(const Location& dest_loc)
+{
+ // ensure we are in position control mode
+ if (sub.guided_mode != Guided_WP) {
+ guided_pos_control_start();
+ }
+
+#if AP_FENCE_ENABLED
+ // reject destination outside the fence.
+ // Note: there is a danger that a target specified as a terrain altitude might not be checked if the conversion to alt-above-home fails
+ if (!sub.fence.check_destination_within_fence(dest_loc)) {
+ AP::logger().Write_Error(LogErrorSubsystem::NAVIGATION, LogErrorCode::DEST_OUTSIDE_FENCE);
+ // failure is propagated to GCS with NAK
+ return false;
+ }
+#endif
+
+ if (!sub.wp_nav.set_wp_destination_loc(dest_loc)) {
+ // failure to set destination can only be because of missing terrain data
+ AP::logger().Write_Error(LogErrorSubsystem::NAVIGATION, LogErrorCode::FAILED_TO_SET_DESTINATION);
+ // failure is propagated to GCS with NAK
+ return false;
+ }
+
+ // log target
+ sub.Log_Write_GuidedTarget(sub.guided_mode, Vector3f(dest_loc.lat, dest_loc.lng, dest_loc.alt),Vector3f());
+ return true;
+}
+
+// guided_set_destination - sets guided mode's target destination and target heading
+// Returns true if the fence is enabled and guided waypoint is within the fence
+// else return false if the waypoint is outside the fence
+bool ModeGuided::guided_set_destination(const Vector3f& destination, bool use_yaw, float yaw_cd, bool use_yaw_rate, float yaw_rate_cds, bool relative_yaw)
+{
+ // ensure we are in position control mode
+ if (sub.guided_mode != Guided_WP) {
+ guided_pos_control_start();
+ }
+
+#if AP_FENCE_ENABLED
+ // reject destination if outside the fence
+ const Location dest_loc(destination, Location::AltFrame::ABOVE_ORIGIN);
+ if (!sub.fence.check_destination_within_fence(dest_loc)) {
+ AP::logger().Write_Error(LogErrorSubsystem::NAVIGATION, LogErrorCode::DEST_OUTSIDE_FENCE);
+ // failure is propagated to GCS with NAK
+ return false;
+ }
+#endif
+
+ // set yaw state
+ guided_set_yaw_state(use_yaw, yaw_cd, use_yaw_rate, yaw_rate_cds, relative_yaw);
+
+ update_time_ms = AP_HAL::millis();
+
+ // no need to check return status because terrain data is not used
+ sub.wp_nav.set_wp_destination(destination, false);
+
+ // log target
+ sub.Log_Write_GuidedTarget(sub.guided_mode, destination, Vector3f());
+ return true;
+}
+
+// guided_set_velocity - sets guided mode's target velocity
+void ModeGuided::guided_set_velocity(const Vector3f& velocity)
+{
+ // check we are in velocity control mode
+ if (sub.guided_mode != Guided_Velocity) {
+ guided_vel_control_start();
+ }
+
+ update_time_ms = AP_HAL::millis();
+
+ // set position controller velocity target
+ position_control->set_vel_desired_cms(velocity);
+}
+
+// guided_set_velocity - sets guided mode's target velocity
+void ModeGuided::guided_set_velocity(const Vector3f& velocity, bool use_yaw, float yaw_cd, bool use_yaw_rate, float yaw_rate_cds, bool relative_yaw)
+{
+ // check we are in velocity control mode
+ if (sub.guided_mode != Guided_Velocity) {
+ guided_vel_control_start();
+ }
+
+ // set yaw state
+ guided_set_yaw_state(use_yaw, yaw_cd, use_yaw_rate, yaw_rate_cds, relative_yaw);
+
+ update_time_ms = AP_HAL::millis();
+
+ // set position controller velocity target
+ position_control->set_vel_desired_cms(velocity);
+
+}
+
+// set guided mode posvel target
+bool ModeGuided::guided_set_destination_posvel(const Vector3f& destination, const Vector3f& velocity)
+{
+ // check we are in velocity control mode
+ if (sub.guided_mode != Guided_PosVel) {
+ guided_posvel_control_start();
+ }
+
+#if AP_FENCE_ENABLED
+ // reject destination if outside the fence
+ const Location dest_loc(destination, Location::AltFrame::ABOVE_ORIGIN);
+ if (!sub.fence.check_destination_within_fence(dest_loc)) {
+ AP::logger().Write_Error(LogErrorSubsystem::NAVIGATION, LogErrorCode::DEST_OUTSIDE_FENCE);
+ // failure is propagated to GCS with NAK
+ return false;
+ }
+#endif
+
+ update_time_ms = AP_HAL::millis();
+ posvel_pos_target_cm = destination.topostype();
+ posvel_vel_target_cms = velocity;
+
+ position_control->input_pos_vel_accel_xy(posvel_pos_target_cm.xy(), posvel_vel_target_cms.xy(), Vector2f());
+ float dz = posvel_pos_target_cm.z;
+ position_control->input_pos_vel_accel_z(dz, posvel_vel_target_cms.z, 0);
+ posvel_pos_target_cm.z = dz;
+
+ // log target
+ sub.Log_Write_GuidedTarget(sub.guided_mode, destination, velocity);
+ return true;
+}
+
+// set guided mode posvel target
+bool ModeGuided::guided_set_destination_posvel(const Vector3f& destination, const Vector3f& velocity, bool use_yaw, float yaw_cd, bool use_yaw_rate, float yaw_rate_cds, bool relative_yaw)
+{
+ // check we are in velocity control mode
+ if (sub.guided_mode != Guided_PosVel) {
+ guided_posvel_control_start();
+ }
+
+ #if AP_FENCE_ENABLED
+ // reject destination if outside the fence
+ const Location dest_loc(destination, Location::AltFrame::ABOVE_ORIGIN);
+ if (!sub.fence.check_destination_within_fence(dest_loc)) {
+ AP::logger().Write_Error(LogErrorSubsystem::NAVIGATION, LogErrorCode::DEST_OUTSIDE_FENCE);
+ // failure is propagated to GCS with NAK
+ return false;
+ }
+ #endif
+
+ // set yaw state
+ guided_set_yaw_state(use_yaw, yaw_cd, use_yaw_rate, yaw_rate_cds, relative_yaw);
+
+ update_time_ms = AP_HAL::millis();
+
+ posvel_pos_target_cm = destination.topostype();
+ posvel_vel_target_cms = velocity;
+
+ position_control->input_pos_vel_accel_xy(posvel_pos_target_cm.xy(), posvel_vel_target_cms.xy(), Vector2f());
+ float dz = posvel_pos_target_cm.z;
+ position_control->input_pos_vel_accel_z(dz, posvel_vel_target_cms.z, 0);
+ posvel_pos_target_cm.z = dz;
+
+ // log target
+ sub.Log_Write_GuidedTarget(sub.guided_mode, destination, velocity);
+ return true;
+}
+
+// set guided mode angle target
+void ModeGuided::guided_set_angle(const Quaternion &q, float climb_rate_cms)
+{
+ // check we are in velocity control mode
+ if (sub.guided_mode != Guided_Angle) {
+ guided_angle_control_start();
+ }
+
+ // convert quaternion to euler angles
+ q.to_euler(guided_angle_state.roll_cd, guided_angle_state.pitch_cd, guided_angle_state.yaw_cd);
+ guided_angle_state.roll_cd = ToDeg(guided_angle_state.roll_cd) * 100.0f;
+ guided_angle_state.pitch_cd = ToDeg(guided_angle_state.pitch_cd) * 100.0f;
+ guided_angle_state.yaw_cd = wrap_180_cd(ToDeg(guided_angle_state.yaw_cd) * 100.0f);
+
+ guided_angle_state.climb_rate_cms = climb_rate_cms;
+ guided_angle_state.update_time_ms = AP_HAL::millis();
+}
+
+// helper function to set yaw state and targets
+void ModeGuided::guided_set_yaw_state(bool use_yaw, float yaw_cd, bool use_yaw_rate, float yaw_rate_cds, bool relative_angle)
+{
+ float current_yaw = wrap_2PI(AP::ahrs().get_yaw());
+ float euler_yaw_angle;
+ float yaw_error;
+
+ euler_yaw_angle = wrap_2PI((yaw_cd * 0.01f));
+ yaw_error = wrap_PI(euler_yaw_angle - current_yaw);
+
+ int direction = 0;
+ if (yaw_error < 0){
+ direction = -1;
+ } else {
+ direction = 1;
+ }
+
+ /*
+ case 1: target yaw only
+ case 2: target yaw and yaw rate
+ case 3: target yaw rate only
+ case 4: hold current yaw
+ */
+ if (use_yaw && !use_yaw_rate) {
+ sub.yaw_rate_only = false;
+ sub.mode_auto.set_auto_yaw_look_at_heading(yaw_cd * 0.01f, 0.0f, direction, relative_angle);
+ } else if (use_yaw && use_yaw_rate) {
+ sub.yaw_rate_only = false;
+ sub.mode_auto.set_auto_yaw_look_at_heading(yaw_cd * 0.01f, yaw_rate_cds * 0.01f, direction, relative_angle);
+ } else if (!use_yaw && use_yaw_rate) {
+ sub.yaw_rate_only = true;
+ sub.mode_auto.set_yaw_rate(yaw_rate_cds * 0.01f);
+ } else{
+ sub.yaw_rate_only = false;
+ set_auto_yaw_mode(AUTO_YAW_HOLD);
+ }
+}
+
+// guided_run - runs the guided controller
+// should be called at 100hz or more
+void ModeGuided::run()
+{
+ // call the correct auto controller
+ switch (sub.guided_mode) {
+
+ case Guided_WP:
+ // run position controller
+ guided_pos_control_run();
+ break;
+
+ case Guided_Velocity:
+ // run velocity controller
+ guided_vel_control_run();
+ break;
+
+ case Guided_PosVel:
+ // run position-velocity controller
+ guided_posvel_control_run();
+ break;
+
+ case Guided_Angle:
+ // run angle controller
+ guided_angle_control_run();
+ break;
+ }
+}
+
+// guided_pos_control_run - runs the guided position controller
+// called from guided_run
+void ModeGuided::guided_pos_control_run()
+{
+ // if motors not enabled set throttle to zero and exit immediately
+ if (!motors.armed()) {
+ motors.set_desired_spool_state(AP_Motors::DesiredSpoolState::GROUND_IDLE);
+ // Sub vehicles do not stabilize roll/pitch/yaw when disarmed
+ attitude_control->set_throttle_out(0,true,g.throttle_filt);
+ attitude_control->relax_attitude_controllers();
+ sub.wp_nav.wp_and_spline_init();
+ return;
+ }
+
+ // process pilot's yaw input
+ float target_yaw_rate = 0;
+ if (!sub.failsafe.pilot_input) {
+ // get pilot's desired yaw rate
+ target_yaw_rate = sub.get_pilot_desired_yaw_rate(channel_yaw->get_control_in());
+ if (!is_zero(target_yaw_rate)) {
+ set_auto_yaw_mode(AUTO_YAW_HOLD);
+ } else{
+ if (sub.yaw_rate_only){
+ set_auto_yaw_mode(AUTO_YAW_RATE);
+ } else{
+ set_auto_yaw_mode(AUTO_YAW_LOOK_AT_HEADING);
+ }
+ }
+ }
+
+ // set motors to full range
+ motors.set_desired_spool_state(AP_Motors::DesiredSpoolState::THROTTLE_UNLIMITED);
+
+ // run waypoint controller
+ sub.failsafe_terrain_set_status(sub.wp_nav.update_wpnav());
+
+ float lateral_out, forward_out;
+ sub.translate_wpnav_rp(lateral_out, forward_out);
+
+ // Send to forward/lateral outputs
+ motors.set_lateral(lateral_out);
+ motors.set_forward(forward_out);
+
+ // WP_Nav has set the vertical position control targets
+ // run the vertical position controller and set output throttle
+ position_control->update_z_controller();
+
+ // call attitude controller
+ if (sub.auto_yaw_mode == AUTO_YAW_HOLD) {
+ // roll & pitch & yaw rate from pilot
+ attitude_control->input_euler_angle_roll_pitch_euler_rate_yaw(channel_roll->get_control_in(), channel_pitch->get_control_in(), target_yaw_rate);
+ } else if (sub.auto_yaw_mode == AUTO_YAW_LOOK_AT_HEADING) {
+ // roll, pitch from pilot, yaw & yaw_rate from auto_control
+ target_yaw_rate = sub.yaw_look_at_heading_slew * 100.0;
+ attitude_control->input_euler_angle_roll_pitch_slew_yaw(channel_roll->get_control_in(), channel_pitch->get_control_in(), get_auto_heading(), target_yaw_rate);
+ } else if (sub.auto_yaw_mode == AUTO_YAW_RATE) {
+ // roll, pitch from pilot, yaw_rate from auto_control
+ target_yaw_rate = sub.yaw_look_at_heading_slew * 100.0;
+ attitude_control->input_euler_angle_roll_pitch_euler_rate_yaw(channel_roll->get_control_in(), channel_pitch->get_control_in(), target_yaw_rate);
+ } else {
+ // roll, pitch from pilot, yaw heading from auto_heading()
+ attitude_control->input_euler_angle_roll_pitch_yaw(channel_roll->get_control_in(), channel_pitch->get_control_in(), get_auto_heading(), true);
+ }
+}
+
+// guided_vel_control_run - runs the guided velocity controller
+// called from guided_run
+void ModeGuided::guided_vel_control_run()
+{
+ // ifmotors not enabled set throttle to zero and exit immediately
+ if (!motors.armed()) {
+ motors.set_desired_spool_state(AP_Motors::DesiredSpoolState::GROUND_IDLE);
+ // Sub vehicles do not stabilize roll/pitch/yaw when disarmed
+ attitude_control->set_throttle_out(0,true,g.throttle_filt);
+ attitude_control->relax_attitude_controllers();
+ // initialise velocity controller
+ position_control->init_z_controller();
+ position_control->init_xy_controller();
+ return;
+ }
+
+ // process pilot's yaw input
+ float target_yaw_rate = 0;
+ if (!sub.failsafe.pilot_input) {
+ // get pilot's desired yaw rate
+ target_yaw_rate = sub.get_pilot_desired_yaw_rate(channel_yaw->get_control_in());
+ if (!is_zero(target_yaw_rate)) {
+ set_auto_yaw_mode(AUTO_YAW_HOLD);
+ } else{
+ if (sub.yaw_rate_only){
+ set_auto_yaw_mode(AUTO_YAW_RATE);
+ } else{
+ set_auto_yaw_mode(AUTO_YAW_LOOK_AT_HEADING);
+ }
+ }
+ }
+
+ // set motors to full range
+ motors.set_desired_spool_state(AP_Motors::DesiredSpoolState::THROTTLE_UNLIMITED);
+
+ // set velocity to zero if no updates received for 3 seconds
+ uint32_t tnow = AP_HAL::millis();
+ if (tnow - update_time_ms > GUIDED_POSVEL_TIMEOUT_MS && !position_control->get_vel_desired_cms().is_zero()) {
+ position_control->set_vel_desired_cms(Vector3f(0,0,0));
+ }
+
+ position_control->stop_pos_xy_stabilisation();
+ // call velocity controller which includes z axis controller
+ position_control->update_xy_controller();
+
+ position_control->set_pos_target_z_from_climb_rate_cm(position_control->get_vel_desired_cms().z);
+ position_control->update_z_controller();
+
+ float lateral_out, forward_out;
+ sub.translate_pos_control_rp(lateral_out, forward_out);
+
+ // Send to forward/lateral outputs
+ motors.set_lateral(lateral_out);
+ motors.set_forward(forward_out);
+
+ // call attitude controller
+ if (sub.auto_yaw_mode == AUTO_YAW_HOLD) {
+ // roll & pitch & yaw rate from pilot
+ attitude_control->input_euler_angle_roll_pitch_euler_rate_yaw(channel_roll->get_control_in(), channel_pitch->get_control_in(), target_yaw_rate);
+ } else if (sub.auto_yaw_mode == AUTO_YAW_LOOK_AT_HEADING) {
+ // roll, pitch from pilot, yaw & yaw_rate from auto_control
+ target_yaw_rate = sub.yaw_look_at_heading_slew * 100.0;
+ attitude_control->input_euler_angle_roll_pitch_slew_yaw(channel_roll->get_control_in(), channel_pitch->get_control_in(), get_auto_heading(), target_yaw_rate);
+ } else if (sub.auto_yaw_mode == AUTO_YAW_RATE) {
+ // roll, pitch from pilot, yaw_rate from auto_control
+ target_yaw_rate = sub.yaw_look_at_heading_slew * 100.0;
+ attitude_control->input_euler_angle_roll_pitch_euler_rate_yaw(channel_roll->get_control_in(), channel_pitch->get_control_in(), target_yaw_rate);
+ } else {
+ // roll, pitch from pilot, yaw heading from auto_heading()
+ attitude_control->input_euler_angle_roll_pitch_yaw(channel_roll->get_control_in(), channel_pitch->get_control_in(), get_auto_heading(), true);
+ }
+}
+
+// guided_posvel_control_run - runs the guided posvel controller
+// called from guided_run
+void ModeGuided::guided_posvel_control_run()
+{
+ // if motors not enabled set throttle to zero and exit immediately
+ if (!motors.armed()) {
+ motors.set_desired_spool_state(AP_Motors::DesiredSpoolState::GROUND_IDLE);
+ // Sub vehicles do not stabilize roll/pitch/yaw when disarmed
+ attitude_control->set_throttle_out(0,true,g.throttle_filt);
+ attitude_control->relax_attitude_controllers();
+ // initialise velocity controller
+ position_control->init_z_controller();
+ position_control->init_xy_controller();
+ return;
+ }
+
+ // process pilot's yaw input
+ float target_yaw_rate = 0;
+
+ if (!sub.failsafe.pilot_input) {
+ // get pilot's desired yaw rate
+ target_yaw_rate = sub.get_pilot_desired_yaw_rate(channel_yaw->get_control_in());
+ if (!is_zero(target_yaw_rate)) {
+ set_auto_yaw_mode(AUTO_YAW_HOLD);
+ } else{
+ if (sub.yaw_rate_only){
+ set_auto_yaw_mode(AUTO_YAW_RATE);
+ } else{
+ set_auto_yaw_mode(AUTO_YAW_LOOK_AT_HEADING);
+ }
+ }
+ }
+
+ // set motors to full range
+ motors.set_desired_spool_state(AP_Motors::DesiredSpoolState::THROTTLE_UNLIMITED);
+
+ // set velocity to zero if no updates received for 3 seconds
+ uint32_t tnow = AP_HAL::millis();
+ if (tnow - update_time_ms > GUIDED_POSVEL_TIMEOUT_MS && !posvel_vel_target_cms.is_zero()) {
+ posvel_vel_target_cms.zero();
+ }
+
+ // advance position target using velocity target
+ posvel_pos_target_cm += (posvel_vel_target_cms * position_control->get_dt()).topostype();
+
+ // send position and velocity targets to position controller
+ position_control->input_pos_vel_accel_xy(posvel_pos_target_cm.xy(), posvel_vel_target_cms.xy(), Vector2f());
+ float pz = posvel_pos_target_cm.z;
+ position_control->input_pos_vel_accel_z(pz, posvel_vel_target_cms.z, 0);
+ posvel_pos_target_cm.z = pz;
+
+ // run position controller
+ position_control->update_xy_controller();
+ position_control->update_z_controller();
+
+ float lateral_out, forward_out;
+ sub.translate_pos_control_rp(lateral_out, forward_out);
+
+ // Send to forward/lateral outputs
+ motors.set_lateral(lateral_out);
+ motors.set_forward(forward_out);
+
+ // call attitude controller
+ if (sub.auto_yaw_mode == AUTO_YAW_HOLD) {
+ // roll & pitch & yaw rate from pilot
+ attitude_control->input_euler_angle_roll_pitch_euler_rate_yaw(channel_roll->get_control_in(), channel_pitch->get_control_in(), target_yaw_rate);
+ } else if (sub.auto_yaw_mode == AUTO_YAW_LOOK_AT_HEADING) {
+ // roll, pitch from pilot, yaw & yaw_rate from auto_control
+ target_yaw_rate = sub.yaw_look_at_heading_slew * 100.0;
+ attitude_control->input_euler_angle_roll_pitch_slew_yaw(channel_roll->get_control_in(), channel_pitch->get_control_in(), get_auto_heading(), target_yaw_rate);
+ } else if (sub.auto_yaw_mode == AUTO_YAW_RATE) {
+ // roll, pitch from pilot, and yaw_rate from auto_control
+ target_yaw_rate = sub.yaw_look_at_heading_slew * 100.0;
+ attitude_control->input_euler_angle_roll_pitch_euler_rate_yaw(channel_roll->get_control_in(), channel_pitch->get_control_in(), target_yaw_rate);
+ } else {
+ // roll, pitch from pilot, yaw heading from auto_heading()
+ attitude_control->input_euler_angle_roll_pitch_yaw(channel_roll->get_control_in(), channel_pitch->get_control_in(), get_auto_heading(), true);
+ }
+}
+
+// guided_angle_control_run - runs the guided angle controller
+// called from guided_run
+void ModeGuided::guided_angle_control_run()
+{
+ // if motors not enabled set throttle to zero and exit immediately
+ if (!motors.armed()) {
+ motors.set_desired_spool_state(AP_Motors::DesiredSpoolState::GROUND_IDLE);
+ // Sub vehicles do not stabilize roll/pitch/yaw when disarmed
+ attitude_control->set_throttle_out(0.0f,true,g.throttle_filt);
+ attitude_control->relax_attitude_controllers();
+ // initialise velocity controller
+ position_control->init_z_controller();
+ return;
+ }
+
+ // constrain desired lean angles
+ float roll_in = guided_angle_state.roll_cd;
+ float pitch_in = guided_angle_state.pitch_cd;
+ float total_in = norm(roll_in, pitch_in);
+ float angle_max = MIN(attitude_control->get_althold_lean_angle_max_cd(), sub.aparm.angle_max);
+ if (total_in > angle_max) {
+ float ratio = angle_max / total_in;
+ roll_in *= ratio;
+ pitch_in *= ratio;
+ }
+
+ // wrap yaw request
+ float yaw_in = wrap_180_cd(guided_angle_state.yaw_cd);
+
+ // constrain climb rate
+ float climb_rate_cms = constrain_float(guided_angle_state.climb_rate_cms, -sub.wp_nav.get_default_speed_down(), sub.wp_nav.get_default_speed_up());
+
+ // check for timeout - set lean angles and climb rate to zero if no updates received for 3 seconds
+ uint32_t tnow = AP_HAL::millis();
+ if (tnow - guided_angle_state.update_time_ms > GUIDED_ATTITUDE_TIMEOUT_MS) {
+ roll_in = 0.0f;
+ pitch_in = 0.0f;
+ climb_rate_cms = 0.0f;
+ }
+
+ // set motors to full range
+ motors.set_desired_spool_state(AP_Motors::DesiredSpoolState::THROTTLE_UNLIMITED);
+
+ // call attitude controller
+ attitude_control->input_euler_angle_roll_pitch_yaw(roll_in, pitch_in, yaw_in, true);
+
+ // call position controller
+ position_control->set_pos_target_z_from_climb_rate_cm(climb_rate_cms);
+ position_control->update_z_controller();
+}
+
+// Guided Limit code
+
+// guided_limit_clear - clear/turn off guided limits
+void ModeGuided::guided_limit_clear()
+{
+ guided_limit.timeout_ms = 0;
+ guided_limit.alt_min_cm = 0.0f;
+ guided_limit.alt_max_cm = 0.0f;
+ guided_limit.horiz_max_cm = 0.0f;
+}
+
+
+// set_auto_yaw_mode - sets the yaw mode for auto
+void ModeGuided::set_auto_yaw_mode(autopilot_yaw_mode yaw_mode)
+{
+ // return immediately if no change
+ if (sub.auto_yaw_mode == yaw_mode) {
+ return;
+ }
+ sub.auto_yaw_mode = yaw_mode;
+
+ // perform initialisation
+ switch (sub.auto_yaw_mode) {
+
+ case AUTO_YAW_HOLD:
+ // pilot controls the heading
+ break;
+
+ case AUTO_YAW_LOOK_AT_NEXT_WP:
+ // wpnav will initialise heading when wpnav's set_destination method is called
+ break;
+
+ case AUTO_YAW_ROI:
+ // point towards a location held in yaw_look_at_WP
+ sub.yaw_look_at_WP_bearing = ahrs.yaw_sensor;
+ break;
+
+ case AUTO_YAW_LOOK_AT_HEADING:
+ // keep heading pointing in the direction held in yaw_look_at_heading
+ // caller should set the yaw_look_at_heading
+ break;
+
+ case AUTO_YAW_LOOK_AHEAD:
+ // Commanded Yaw to automatically look ahead.
+ sub.yaw_look_ahead_bearing = ahrs.yaw_sensor;
+ break;
+
+ case AUTO_YAW_RESETTOARMEDYAW:
+ // initial_armed_bearing will be set during arming so no init required
+ break;
+
+ case AUTO_YAW_RATE:
+ // set target yaw rate to yaw_look_at_heading_slew
+ break;
+ }
+}
+
+// get_auto_heading - returns target heading depending upon auto_yaw_mode
+// 100hz update rate
+float ModeGuided::get_auto_heading()
+{
+ switch (sub.auto_yaw_mode) {
+
+ case AUTO_YAW_ROI:
+ // point towards a location held in roi_WP
+ return sub.get_roi_yaw();
+ break;
+
+ case AUTO_YAW_LOOK_AT_HEADING:
+ // keep heading pointing in the direction held in yaw_look_at_heading with no pilot input allowed
+ return sub.yaw_look_at_heading;
+ break;
+
+ case AUTO_YAW_LOOK_AHEAD:
+ // Commanded Yaw to automatically look ahead.
+ return sub.get_look_ahead_yaw();
+ break;
+
+ case AUTO_YAW_RESETTOARMEDYAW:
+ // changes yaw to be same as when quad was armed
+ return sub.initial_armed_bearing;
+ break;
+
+ case AUTO_YAW_CORRECT_XTRACK: {
+ // TODO return current yaw if not in appropriate mode
+ // Bearing of current track (centidegrees)
+ float track_bearing = get_bearing_cd(sub.wp_nav.get_wp_origin().xy(), sub.wp_nav.get_wp_destination().xy());
+
+ // Bearing from current position towards intermediate position target (centidegrees)
+ const Vector2f target_vel_xy{position_control->get_vel_target_cms().x, position_control->get_vel_target_cms().y};
+ float angle_error = 0.0f;
+ if (target_vel_xy.length() >= position_control->get_max_speed_xy_cms() * 0.1f) {
+ const float desired_angle_cd = degrees(target_vel_xy.angle()) * 100.0f;
+ angle_error = wrap_180_cd(desired_angle_cd - track_bearing);
+ }
+ float angle_limited = constrain_float(angle_error, -g.xtrack_angle_limit * 100.0f, g.xtrack_angle_limit * 100.0f);
+ return wrap_360_cd(track_bearing + angle_limited);
+ }
+ break;
+
+ case AUTO_YAW_LOOK_AT_NEXT_WP:
+ default:
+ // point towards next waypoint.
+ // we don't use wp_bearing because we don't want the vehicle to turn too much during flight
+ return sub.wp_nav.get_yaw();
+ break;
+ }
+}
+// guided_limit_set - set guided timeout and movement limits
+void ModeGuided::guided_limit_set(uint32_t timeout_ms, float alt_min_cm, float alt_max_cm, float horiz_max_cm)
+{
+ guided_limit.timeout_ms = timeout_ms;
+ guided_limit.alt_min_cm = alt_min_cm;
+ guided_limit.alt_max_cm = alt_max_cm;
+ guided_limit.horiz_max_cm = horiz_max_cm;
+}
+
+// guided_limit_init_time_and_pos - initialise guided start time and position as reference for limit checking
+// only called from AUTO mode's auto_nav_guided_start function
+void ModeGuided::guided_limit_init_time_and_pos()
+{
+ // initialise start time
+ guided_limit.start_time = AP_HAL::millis();
+
+ // initialise start position from current position
+ guided_limit.start_pos = inertial_nav.get_position_neu_cm();
+}
+
+// guided_limit_check - returns true if guided mode has breached a limit
+// used when guided is invoked from the NAV_GUIDED_ENABLE mission command
+bool ModeGuided::guided_limit_check()
+{
+ // check if we have passed the timeout
+ if ((guided_limit.timeout_ms > 0) && (AP_HAL::millis() - guided_limit.start_time >= guided_limit.timeout_ms)) {
+ return true;
+ }
+
+ // get current location
+ const Vector3f& curr_pos = inertial_nav.get_position_neu_cm();
+
+ // check if we have gone below min alt
+ if (!is_zero(guided_limit.alt_min_cm) && (curr_pos.z < guided_limit.alt_min_cm)) {
+ return true;
+ }
+
+ // check if we have gone above max alt
+ if (!is_zero(guided_limit.alt_max_cm) && (curr_pos.z > guided_limit.alt_max_cm)) {
+ return true;
+ }
+
+ // check if we have gone beyond horizontal limit
+ if (guided_limit.horiz_max_cm > 0.0f) {
+ const float horiz_move = get_horizontal_distance_cm(guided_limit.start_pos.xy(), curr_pos.xy());
+ if (horiz_move > guided_limit.horiz_max_cm) {
+ return true;
+ }
+ }
+
+ // if we got this far we must be within limits
+ return false;
+}
diff --git a/ArduSub/mode_manual.cpp b/ArduSub/mode_manual.cpp
new file mode 100644
index 00000000000000..9d6e29892ea91a
--- /dev/null
+++ b/ArduSub/mode_manual.cpp
@@ -0,0 +1,35 @@
+#include "Sub.h"
+
+
+bool ModeManual::init(bool ignore_checks) {
+ // set target altitude to zero for reporting
+ position_control->set_pos_target_z_cm(0);
+
+ // attitude hold inputs become thrust inputs in manual mode
+ // set to neutral to prevent chaotic behavior (esp. roll/pitch)
+ sub.set_neutral_controls();
+
+ return true;
+}
+
+// manual_run - runs the manual (passthrough) controller
+// should be called at 100hz or more
+void ModeManual::run()
+{
+ // if not armed set throttle to zero and exit immediately
+ if (!sub.motors.armed()) {
+ sub.motors.set_desired_spool_state(AP_Motors::DesiredSpoolState::GROUND_IDLE);
+ attitude_control->set_throttle_out(0,true,g.throttle_filt);
+ attitude_control->relax_attitude_controllers();
+ return;
+ }
+
+ sub.motors.set_desired_spool_state(AP_Motors::DesiredSpoolState::THROTTLE_UNLIMITED);
+
+ sub.motors.set_roll(channel_roll->norm_input());
+ sub.motors.set_pitch(channel_pitch->norm_input());
+ sub.motors.set_yaw(channel_yaw->norm_input() * g.acro_yaw_p / ACRO_YAW_P);
+ sub.motors.set_throttle(channel_throttle->norm_input());
+ sub.motors.set_forward(channel_forward->norm_input());
+ sub.motors.set_lateral(channel_lateral->norm_input());
+}
diff --git a/ArduSub/control_motordetect.cpp b/ArduSub/mode_motordetect.cpp
similarity index 96%
rename from ArduSub/control_motordetect.cpp
rename to ArduSub/mode_motordetect.cpp
index 1718de53b421d5..370e1838ce1829 100644
--- a/ArduSub/control_motordetect.cpp
+++ b/ArduSub/mode_motordetect.cpp
@@ -45,7 +45,7 @@ namespace {
static int16_t current_direction;
}
-bool Sub::motordetect_init()
+bool ModeMotordetect::init(bool ignore_checks)
{
current_motor = 0;
md_state = STANDBY;
@@ -53,7 +53,7 @@ bool Sub::motordetect_init()
return true;
}
-void Sub::motordetect_run()
+void ModeMotordetect::run()
{
// if not armed set throttle to zero and exit immediately
if (!motors.armed()) {
@@ -167,8 +167,8 @@ void Sub::motordetect_run()
break;
}
case DONE:
- control_mode = prev_control_mode;
- arming.disarm(AP_Arming::Method::MOTORDETECTDONE);
+ set_mode(sub.prev_control_mode, ModeReason::MISSION_END);
+ sub.arming.disarm(AP_Arming::Method::MOTORDETECTDONE);
break;
}
}
diff --git a/ArduSub/control_poshold.cpp b/ArduSub/mode_poshold.cpp
similarity index 50%
rename from ArduSub/control_poshold.cpp
rename to ArduSub/mode_poshold.cpp
index 46121952ae054a..8c1b389464c1ab 100644
--- a/ArduSub/control_poshold.cpp
+++ b/ArduSub/mode_poshold.cpp
@@ -7,47 +7,47 @@
#if POSHOLD_ENABLED == ENABLED
// poshold_init - initialise PosHold controller
-bool Sub::poshold_init()
+bool ModePoshold::init(bool ignore_checks)
{
// fail to initialise PosHold mode if no GPS lock
- if (!position_ok()) {
+ if (!sub.position_ok()) {
return false;
}
// initialize vertical speeds and acceleration
- pos_control.set_max_speed_accel_xy(wp_nav.get_default_speed_xy(), wp_nav.get_wp_acceleration());
- pos_control.set_correction_speed_accel_xy(wp_nav.get_default_speed_xy(), wp_nav.get_wp_acceleration());
- pos_control.set_max_speed_accel_z(-get_pilot_speed_dn(), g.pilot_speed_up, g.pilot_accel_z);
- pos_control.set_correction_speed_accel_z(-get_pilot_speed_dn(), g.pilot_speed_up, g.pilot_accel_z);
+ position_control->set_max_speed_accel_xy(sub.wp_nav.get_default_speed_xy(), sub.wp_nav.get_wp_acceleration());
+ position_control->set_correction_speed_accel_xy(sub.wp_nav.get_default_speed_xy(), sub.wp_nav.get_wp_acceleration());
+ position_control->set_max_speed_accel_z(-sub.get_pilot_speed_dn(), g.pilot_speed_up, g.pilot_accel_z);
+ position_control->set_correction_speed_accel_z(-sub.get_pilot_speed_dn(), g.pilot_speed_up, g.pilot_accel_z);
// initialise position and desired velocity
- pos_control.init_xy_controller_stopping_point();
- pos_control.init_z_controller();
+ position_control->init_xy_controller_stopping_point();
+ position_control->init_z_controller();
// Stop all thrusters
- attitude_control.set_throttle_out(0.5f ,true, g.throttle_filt);
- attitude_control.relax_attitude_controllers();
- pos_control.relax_z_controller(0.5f);
+ attitude_control->set_throttle_out(0.5f ,true, g.throttle_filt);
+ attitude_control->relax_attitude_controllers();
+ position_control->relax_z_controller(0.5f);
- last_pilot_heading = ahrs.yaw_sensor;
+ sub.last_pilot_heading = ahrs.yaw_sensor;
return true;
}
// poshold_run - runs the PosHold controller
// should be called at 100hz or more
-void Sub::poshold_run()
+void ModePoshold::run()
{
uint32_t tnow = AP_HAL::millis();
// When unarmed, disable motors and stabilization
if (!motors.armed()) {
motors.set_desired_spool_state(AP_Motors::DesiredSpoolState::GROUND_IDLE);
// Sub vehicles do not stabilize roll/pitch/yaw when not auto-armed (i.e. on the ground, pilot has never raised throttle)
- attitude_control.set_throttle_out(0.5f ,true, g.throttle_filt);
- attitude_control.relax_attitude_controllers();
- pos_control.init_xy_controller_stopping_point();
- pos_control.relax_z_controller(0.5f);
- last_pilot_heading = ahrs.yaw_sensor;
+ attitude_control->set_throttle_out(0.5f ,true, g.throttle_filt);
+ attitude_control->relax_attitude_controllers();
+ position_control->init_xy_controller_stopping_point();
+ position_control->relax_z_controller(0.5f);
+ sub.last_pilot_heading = ahrs.yaw_sensor;
return;
}
@@ -62,15 +62,15 @@ void Sub::poshold_run()
float lateral_out = 0;
float forward_out = 0;
- if (position_ok()) {
+ if (sub.position_ok()) {
// Allow pilot to reposition the sub
if (fabsf(pilot_lateral) > 0.1 || fabsf(pilot_forward) > 0.1) {
- pos_control.init_xy_controller_stopping_point();
+ position_control->init_xy_controller_stopping_point();
}
- translate_pos_control_rp(lateral_out, forward_out);
- pos_control.update_xy_controller();
+ sub.translate_pos_control_rp(lateral_out, forward_out);
+ position_control->update_xy_controller();
} else {
- pos_control.init_xy_controller_stopping_point();
+ position_control->init_xy_controller_stopping_point();
}
motors.set_forward(forward_out + pilot_forward);
motors.set_lateral(lateral_out + pilot_lateral);
@@ -78,32 +78,32 @@ void Sub::poshold_run()
// Update attitude //
// get pilot's desired yaw rate
- float target_yaw_rate = get_pilot_desired_yaw_rate(channel_yaw->get_control_in());
+ float target_yaw_rate = sub.get_pilot_desired_yaw_rate(channel_yaw->get_control_in());
// convert pilot input to lean angles
// To-Do: convert get_pilot_desired_lean_angles to return angles as floats
float target_roll, target_pitch;
- get_pilot_desired_lean_angles(channel_roll->get_control_in(), channel_pitch->get_control_in(), target_roll, target_pitch, aparm.angle_max);
+ sub.get_pilot_desired_lean_angles(channel_roll->get_control_in(), channel_pitch->get_control_in(), target_roll, target_pitch, sub.aparm.angle_max);
// update attitude controller targets
if (!is_zero(target_yaw_rate)) { // call attitude controller with rate yaw determined by pilot input
- attitude_control.input_euler_angle_roll_pitch_euler_rate_yaw(target_roll, target_pitch, target_yaw_rate);
- last_pilot_heading = ahrs.yaw_sensor;
- last_pilot_yaw_input_ms = tnow; // time when pilot last changed heading
+ attitude_control->input_euler_angle_roll_pitch_euler_rate_yaw(target_roll, target_pitch, target_yaw_rate);
+ sub.last_pilot_heading = ahrs.yaw_sensor;
+ sub.last_pilot_yaw_input_ms = tnow; // time when pilot last changed heading
} else { // hold current heading
// this check is required to prevent bounce back after very fast yaw maneuvers
// the inertia of the vehicle causes the heading to move slightly past the point when pilot input actually stopped
- if (tnow < last_pilot_yaw_input_ms + 250) { // give 250ms to slow down, then set target heading
+ if (tnow < sub.last_pilot_yaw_input_ms + 250) { // give 250ms to slow down, then set target heading
target_yaw_rate = 0; // Stop rotation on yaw axis
// call attitude controller with target yaw rate = 0 to decelerate on yaw axis
- attitude_control.input_euler_angle_roll_pitch_euler_rate_yaw(target_roll, target_pitch, target_yaw_rate);
- last_pilot_heading = ahrs.yaw_sensor; // update heading to hold
+ attitude_control->input_euler_angle_roll_pitch_euler_rate_yaw(target_roll, target_pitch, target_yaw_rate);
+ sub.last_pilot_heading = ahrs.yaw_sensor; // update heading to hold
} else { // call attitude controller holding absolute absolute bearing
- attitude_control.input_euler_angle_roll_pitch_yaw(target_roll, target_pitch, last_pilot_heading, true);
+ attitude_control->input_euler_angle_roll_pitch_yaw(target_roll, target_pitch, sub.last_pilot_heading, true);
}
}
diff --git a/ArduSub/mode_stabilize.cpp b/ArduSub/mode_stabilize.cpp
new file mode 100644
index 00000000000000..cd75be241b6c2c
--- /dev/null
+++ b/ArduSub/mode_stabilize.cpp
@@ -0,0 +1,68 @@
+#include "Sub.h"
+
+
+bool ModeStabilize::init(bool ignore_checks) {
+ // set target altitude to zero for reporting
+ position_control->set_pos_target_z_cm(0);
+ sub.last_pilot_heading = ahrs.yaw_sensor;
+
+ return true;
+ return true;
+}
+
+void ModeStabilize::run()
+{
+ uint32_t tnow = AP_HAL::millis();
+ float target_roll, target_pitch;
+
+ // if not armed set throttle to zero and exit immediately
+ if (!motors.armed()) {
+ motors.set_desired_spool_state(AP_Motors::DesiredSpoolState::GROUND_IDLE);
+ attitude_control->set_throttle_out(0,true,g.throttle_filt);
+ attitude_control->relax_attitude_controllers();
+ sub.last_pilot_heading = ahrs.yaw_sensor;
+ return;
+ }
+
+ motors.set_desired_spool_state(AP_Motors::DesiredSpoolState::THROTTLE_UNLIMITED);
+
+ // convert pilot input to lean angles
+ // To-Do: convert sub.get_pilot_desired_lean_angles to return angles as floats
+ // TODO2: move into mode.h
+ sub.get_pilot_desired_lean_angles(channel_roll->get_control_in(), channel_pitch->get_control_in(), target_roll, target_pitch, sub.aparm.angle_max);
+
+ // get pilot's desired yaw rate
+ float target_yaw_rate = sub.get_pilot_desired_yaw_rate(channel_yaw->get_control_in());
+
+ // call attitude controller
+ // update attitude controller targets
+
+ if (!is_zero(target_yaw_rate)) { // call attitude controller with rate yaw determined by pilot input
+ attitude_control->input_euler_angle_roll_pitch_euler_rate_yaw(target_roll, target_pitch, target_yaw_rate);
+ sub.last_pilot_heading = ahrs.yaw_sensor;
+ sub.last_pilot_yaw_input_ms = tnow; // time when pilot last changed heading
+
+ } else { // hold current heading
+
+ // this check is required to prevent bounce back after very fast yaw maneuvers
+ // the inertia of the vehicle causes the heading to move slightly past the point when pilot input actually stopped
+ if (tnow < sub.last_pilot_yaw_input_ms + 250) { // give 250ms to slow down, then set target heading
+ target_yaw_rate = 0; // Stop rotation on yaw axis
+
+ // call attitude controller with target yaw rate = 0 to decelerate on yaw axis
+ attitude_control->input_euler_angle_roll_pitch_euler_rate_yaw(target_roll, target_pitch, target_yaw_rate);
+ sub.last_pilot_heading = ahrs.yaw_sensor; // update heading to hold
+
+ } else { // call attitude controller holding absolute absolute bearing
+ attitude_control->input_euler_angle_roll_pitch_yaw(target_roll, target_pitch, sub.last_pilot_heading, true);
+ }
+ }
+
+ // output pilot's throttle
+ attitude_control->set_throttle_out(channel_throttle->norm_input(), false, g.throttle_filt);
+
+ //control_in is range -1000-1000
+ //radio_in is raw pwm value
+ motors.set_forward(channel_forward->norm_input());
+ motors.set_lateral(channel_lateral->norm_input());
+}
diff --git a/ArduSub/mode_surface.cpp b/ArduSub/mode_surface.cpp
new file mode 100644
index 00000000000000..6bab07a067b860
--- /dev/null
+++ b/ArduSub/mode_surface.cpp
@@ -0,0 +1,63 @@
+#include "Sub.h"
+
+
+bool ModeSurface::init(bool ignore_checks)
+{
+ if(!sub.control_check_barometer()) {
+ return false;
+ }
+
+ // initialize vertical speeds and acceleration
+ position_control->set_max_speed_accel_z(-sub.get_pilot_speed_dn(), g.pilot_speed_up, g.pilot_accel_z);
+ position_control->set_correction_speed_accel_z(-sub.get_pilot_speed_dn(), g.pilot_speed_up, g.pilot_accel_z);
+
+ // initialise position and desired velocity
+ position_control->init_z_controller();
+
+ return true;
+
+}
+
+void ModeSurface::run()
+{
+ float target_roll, target_pitch;
+
+ // if not armed set throttle to zero and exit immediately
+ if (!motors.armed()) {
+ motors.output_min();
+ motors.set_desired_spool_state(AP_Motors::DesiredSpoolState::GROUND_IDLE);
+ attitude_control->set_throttle_out(0,true,g.throttle_filt);
+ attitude_control->relax_attitude_controllers();
+ position_control->init_z_controller();
+ return;
+ }
+
+ // Already at surface, hold depth at surface
+ if (sub.ap.at_surface) {
+ set_mode(Mode::Number::ALT_HOLD, ModeReason::SURFACE_COMPLETE);
+ }
+
+ // convert pilot input to lean angles
+ // To-Do: convert sub.get_pilot_desired_lean_angles to return angles as floats
+ sub.get_pilot_desired_lean_angles(channel_roll->get_control_in(), channel_pitch->get_control_in(), target_roll, target_pitch, sub.aparm.angle_max);
+
+ // get pilot's desired yaw rate
+ float target_yaw_rate = sub.get_pilot_desired_yaw_rate(channel_yaw->get_control_in());
+
+ // call attitude controller
+ attitude_control->input_euler_angle_roll_pitch_euler_rate_yaw(target_roll, target_pitch, target_yaw_rate);
+
+ // set target climb rate
+ float cmb_rate = constrain_float(fabsf(sub.wp_nav.get_default_speed_up()), 1, position_control->get_max_speed_up_cms());
+
+ // record desired climb rate for logging
+ sub.desired_climb_rate = cmb_rate;
+
+ // update altitude target and call position controller
+ position_control->set_pos_target_z_from_climb_rate_cm(cmb_rate);
+ position_control->update_z_controller();
+
+ // pilot has control for repositioning
+ motors.set_forward(channel_forward->norm_input());
+ motors.set_lateral(channel_lateral->norm_input());
+}
diff --git a/ArduSub/motors.cpp b/ArduSub/motors.cpp
index 5d33b5052b40e4..9e25f51513e605 100644
--- a/ArduSub/motors.cpp
+++ b/ArduSub/motors.cpp
@@ -10,7 +10,7 @@ void Sub::enable_motor_output()
void Sub::motors_output()
{
// Motor detection mode controls the thrusters directly
- if (control_mode == MOTOR_DETECT){
+ if (control_mode == Mode::Number::MOTOR_DETECT){
return;
}
// check if we are performing the motor test
diff --git a/ArduSub/surface_bottom_detector.cpp b/ArduSub/surface_bottom_detector.cpp
index 4a1b4cd215edd2..0338e77c99d4c3 100644
--- a/ArduSub/surface_bottom_detector.cpp
+++ b/ArduSub/surface_bottom_detector.cpp
@@ -7,7 +7,7 @@ static uint32_t bottom_detector_count = 0;
static uint32_t surface_detector_count = 0;
static float current_depth = 0;
-// checks if we have have hit bottom or surface and updates the ap.at_bottom and ap.at_surface flags
+// checks if we have hit bottom or surface and updates the ap.at_bottom and ap.at_surface flags
// called at MAIN_LOOP_RATE
// ToDo: doesn't need to be called this fast
void Sub::update_surface_and_bottom_detector()
diff --git a/ArduSub/system.cpp b/ArduSub/system.cpp
index 7ac209a87f17b1..487abe625e063a 100644
--- a/ArduSub/system.cpp
+++ b/ArduSub/system.cpp
@@ -19,6 +19,11 @@ void Sub::init_ardupilot()
can_mgr.init();
#endif
+#if STATS_ENABLED == ENABLED
+ // initialise stats module
+ g2.stats.init();
+#endif
+
// init cargo gripper
#if AP_GRIPPER_ENABLED
g2.gripper.init();
@@ -70,7 +75,9 @@ void Sub::init_ardupilot()
init_rc_out(); // sets up motors and output to escs
init_joystick(); // joystick initialization
+#if AP_RELAY_ENABLED
relay.init();
+#endif
/*
* setup the 'main loop is dead' check. Note that this relies on
@@ -97,7 +104,7 @@ void Sub::init_ardupilot()
#if HAL_MOUNT_ENABLED
// initialise camera mount
camera_mount.init();
- // This step ncessary so the servo is properly initialized
+ // This step is necessary so that the servo is properly initialized
camera_mount.set_angle_target(0, 0, 0, false);
// for some reason the call to set_angle_targets changes the mode to mavlink targeting!
camera_mount.set_mode(MAV_MOUNT_MODE_RC_TARGETING);
@@ -164,11 +171,6 @@ void Sub::init_ardupilot()
g2.scripting.init();
#endif // AP_SCRIPTING_ENABLED
- // we don't want writes to the serial port to cause us to pause
- // mid-flight, so set the serial ports non-blocking once we are
- // ready to fly
- serial_manager.set_blocking_writes_all(false);
-
// enable CPU failsafe
mainloop_failsafe_enable();
diff --git a/ArduSub/wscript b/ArduSub/wscript
index de8dc48a7b984e..89da451ee21e7f 100644
--- a/ArduSub/wscript
+++ b/ArduSub/wscript
@@ -18,7 +18,6 @@ def build(bld):
'AP_Beacon',
'AP_TemperatureSensor',
'AP_Arming',
- 'AP_KDECAN',
'AP_OSD',
],
)
diff --git a/BUILD.md b/BUILD.md
index 0143d70da6258a..9124d7acb7d3d1 100644
--- a/BUILD.md
+++ b/BUILD.md
@@ -8,18 +8,17 @@ git clone --recursive https://github.com/ArduPilot/ardupilot.git
cd ardupilot
```
-Ardupilot is gradually moving from the make-based build system to
-[Waf](https://waf.io/). The instructions below should be enough for you to
-build Ardupilot, but you can also read more about the build system in the
+You can also read more about the build system in the
[Waf Book](https://waf.io/book/).
-Waf should always be called from the ardupilot's root directory. Differently
-from the make-based build, with Waf there's a configure step to choose the
-board to be used (default is `sitl`).
+waf should always be called from the locally cloned ardupilot root directory for the local branch you are trying to build from.
+
+**Note**
+Do not run `waf` with `sudo`! This leads to permission and environment problems.
## Basic usage ##
-There are several commands in the build system for advanced usages, but here we
+There are several commands in the build system for advanced usage, but here we
list some basic and more used commands as example.
* **Build ArduCopter**
@@ -164,6 +163,18 @@ list some basic and more used commands as example.
./waf --targets tests/test_math
```
+* **Use clang instead of gcc**
+
+ Currently, gcc is the default on linux, and clang is used for MacOS.
+ Building with clang on linux can be accomplished by setting the CXX
+ environment variables during the configure step, e.g.:
+
+ ```
+ CXX=clang++ CC=clang ./waf configure --board=sitl
+ ```
+
+ Note: Your clang binary names may differ.
+
* **Other options**
It's possible to see all available commands and options:
diff --git a/Blimp/AP_Arming.cpp b/Blimp/AP_Arming.cpp
index c72d250cc2dbc8..ea36c2c1f0d873 100644
--- a/Blimp/AP_Arming.cpp
+++ b/Blimp/AP_Arming.cpp
@@ -107,7 +107,7 @@ bool AP_Arming_Blimp::parameter_checks(bool display_failure)
// failsafe parameter checks
if (blimp.g.failsafe_throttle) {
// check throttle min is above throttle failsafe trigger and that the trigger is above ppm encoder's loss-of-signal value of 900
- if (blimp.channel_down->get_radio_min() <= blimp.g.failsafe_throttle_value+10 || blimp.g.failsafe_throttle_value < 910) {
+ if (blimp.channel_up->get_radio_min() <= blimp.g.failsafe_throttle_value+10 || blimp.g.failsafe_throttle_value < 910) {
check_failed(ARMING_CHECK_PARAMETERS, display_failure, "Check FS_THR_VALUE");
return false;
}
diff --git a/Blimp/Blimp.cpp b/Blimp/Blimp.cpp
index 9c9f457b137162..ff5327006738d9 100644
--- a/Blimp/Blimp.cpp
+++ b/Blimp/Blimp.cpp
@@ -53,7 +53,7 @@ const AP_Scheduler::Task Blimp::scheduler_tasks[] = {
FAST_TASK_CLASS(AP_InertialSensor, &blimp.ins, update),
// send outputs to the motors library immediately
FAST_TASK(motors_output),
- // run EKF state estimator (expensive)
+ // run EKF state estimator (expensive)
FAST_TASK(read_AHRS),
// Inertial Nav
FAST_TASK(read_inertia),
@@ -72,7 +72,9 @@ const AP_Scheduler::Task Blimp::scheduler_tasks[] = {
SCHED_TASK(arm_motors_check, 10, 50, 18),
SCHED_TASK(update_altitude, 10, 100, 21),
SCHED_TASK(three_hz_loop, 3, 75, 24),
+#if AP_SERVORELAYEVENTS_ENABLED
SCHED_TASK_CLASS(AP_ServoRelayEvents, &blimp.ServoRelayEvents, update_events, 50, 75, 27),
+#endif
SCHED_TASK_CLASS(AP_Baro, &blimp.barometer, accumulate, 50, 90, 30),
#if LOGGING_ENABLED == ENABLED
SCHED_TASK(full_rate_logging, 50, 50, 33),
@@ -215,12 +217,27 @@ void Blimp::read_AHRS(void)
ahrs.update(true);
IGNORE_RETURN(ahrs.get_velocity_NED(vel_ned));
- IGNORE_RETURN(ahrs.get_relative_position_NED_home(pos_ned));
+ IGNORE_RETURN(ahrs.get_relative_position_NED_origin(pos_ned));
vel_yaw = ahrs.get_yaw_rate_earth();
Vector2f vel_xy_filtd = vel_xy_filter.apply({vel_ned.x, vel_ned.y});
vel_ned_filtd = {vel_xy_filtd.x, vel_xy_filtd.y, vel_z_filter.apply(vel_ned.z)};
vel_yaw_filtd = vel_yaw_filter.apply(vel_yaw);
+
+ AP::logger().WriteStreaming("VNF", "TimeUS,X,XF,Y,YF,Z,ZF,Yaw,YawF,PX,PY,PZ,PYaw", "Qffffffffffff",
+ AP_HAL::micros64(),
+ vel_ned.x,
+ vel_ned_filtd.x,
+ vel_ned.y,
+ vel_ned_filtd.y,
+ vel_ned.z,
+ vel_ned_filtd.z,
+ vel_yaw,
+ vel_yaw_filtd,
+ pos_ned.x,
+ pos_ned.y,
+ pos_ned.z,
+ blimp.ahrs.get_yaw());
}
// read baro and log control tuning
diff --git a/Blimp/Blimp.h b/Blimp/Blimp.h
index 0c6e7a2627e37e..8923e6bd1ceb38 100644
--- a/Blimp/Blimp.h
+++ b/Blimp/Blimp.h
@@ -59,6 +59,7 @@
#include "config.h"
#include "Fins.h"
+#include "Loiter.h"
#include "RC_Channel.h" // RC Channel Library
@@ -91,8 +92,10 @@ class Blimp : public AP_Vehicle
friend class ModeLand;
friend class ModeVelocity;
friend class ModeLoiter;
+ friend class ModeRTL;
friend class Fins;
+ friend class Loiter;
Blimp(void);
@@ -108,7 +111,7 @@ class Blimp : public AP_Vehicle
// primary input control channels
RC_Channel *channel_right;
RC_Channel *channel_front;
- RC_Channel *channel_down;
+ RC_Channel *channel_up;
RC_Channel *channel_yaw;
AP_Logger logger;
@@ -191,6 +194,7 @@ class Blimp : public AP_Vehicle
// Motor Output
Fins *motors;
+ Loiter *loiter;
int32_t _home_bearing;
uint32_t _home_distance;
@@ -360,8 +364,8 @@ class Blimp : public AP_Vehicle
void Log_Write_Data(LogDataID id, float value);
void Log_Write_Parameter_Tuning(uint8_t param, float tuning_val, float tune_min, float tune_max);
void Log_Write_GuidedTarget(uint8_t target_type, const Vector3f& pos_target, const Vector3f& vel_target);
- void Log_Write_SysID_Setup(uint8_t systemID_axis, float waveform_magnitude, float frequency_start, float frequency_stop, float time_fade_in, float time_const_freq, float time_record, float time_fade_out);
- void Log_Write_SysID_Data(float waveform_time, float waveform_sample, float waveform_freq, float angle_x, float angle_y, float angle_z, float accel_x, float accel_y, float accel_z);
+
+
void Log_Write_Vehicle_Startup_Messages();
void log_init(void);
void Write_FINI(float right, float front, float down, float yaw);
@@ -378,7 +382,7 @@ class Blimp : public AP_Vehicle
void notify_flight_mode();
// mode_land.cpp
- void set_mode_land_with_pause(ModeReason reason);
+ void set_mode_land_failsafe(ModeReason reason);
bool landing_with_GPS();
// // motors.cpp
@@ -430,6 +434,7 @@ class Blimp : public AP_Vehicle
ModeLand mode_land;
ModeVelocity mode_velocity;
ModeLoiter mode_loiter;
+ ModeRTL mode_rtl;
// mode.cpp
Mode *mode_from_mode_num(const Mode::Number mode);
diff --git a/Blimp/Fins.h b/Blimp/Fins.h
index e51a465b3690b9..6e225580385e32 100644
--- a/Blimp/Fins.h
+++ b/Blimp/Fins.h
@@ -10,6 +10,7 @@ class Fins
{
public:
friend class Blimp;
+ friend class Loiter;
enum motor_frame_class {
MOTOR_FRAME_UNDEFINED = 0,
@@ -70,7 +71,7 @@ class Fins
int8_t _num_added;
-//MIR This should probably become private in future.
+ //MIR This should probably become private in future.
public:
float right_out; //input right movement, negative for left, +1 to -1
float front_out; //input front/forwards movement, negative for backwards, +1 to -1
@@ -95,7 +96,7 @@ class Fins
float get_throttle()
{
//Only for Mavlink - essentially just an indicator of how hard the fins are working.
- //Note that this is the unconstrained version, so if the higher level control gives too high input,
+ //Note that this is the unconstrained version, so if the higher level control gives too high input,
//throttle will be displayed as more than 100.
return fmaxf(fmaxf(fabsf(down_out),fabsf(front_out)), fmaxf(fabsf(right_out),fabsf(yaw_out)));
}
diff --git a/Blimp/GCS_Blimp.h b/Blimp/GCS_Blimp.h
index c07facca56b98c..830e0abc209431 100644
--- a/Blimp/GCS_Blimp.h
+++ b/Blimp/GCS_Blimp.h
@@ -25,10 +25,10 @@ class GCS_Blimp : public GCS
bool vehicle_initialised() const override;
-protected:
-
uint8_t sysid_this_mav() const override;
+protected:
+
// minimum amount of time (in microseconds) that must remain in
// the main scheduler loop before we are allowed to send any
// mavlink messages. We want to prioritise the main flight
diff --git a/Blimp/GCS_Mavlink.cpp b/Blimp/GCS_Mavlink.cpp
index 515a2870b6b9c4..5ffabf5ef9f5c7 100644
--- a/Blimp/GCS_Mavlink.cpp
+++ b/Blimp/GCS_Mavlink.cpp
@@ -52,8 +52,8 @@ void GCS_MAVLINK_Blimp::send_position_target_global_int()
}
static constexpr uint16_t POSITION_TARGET_TYPEMASK_LAST_BYTE = 0xF000;
static constexpr uint16_t TYPE_MASK = POSITION_TARGET_TYPEMASK_VX_IGNORE | POSITION_TARGET_TYPEMASK_VY_IGNORE | POSITION_TARGET_TYPEMASK_VZ_IGNORE |
- POSITION_TARGET_TYPEMASK_AX_IGNORE | POSITION_TARGET_TYPEMASK_AY_IGNORE | POSITION_TARGET_TYPEMASK_AZ_IGNORE |
- POSITION_TARGET_TYPEMASK_YAW_IGNORE | POSITION_TARGET_TYPEMASK_YAW_RATE_IGNORE | POSITION_TARGET_TYPEMASK_LAST_BYTE;
+ POSITION_TARGET_TYPEMASK_AX_IGNORE | POSITION_TARGET_TYPEMASK_AY_IGNORE | POSITION_TARGET_TYPEMASK_AZ_IGNORE |
+ POSITION_TARGET_TYPEMASK_YAW_IGNORE | POSITION_TARGET_TYPEMASK_YAW_RATE_IGNORE | POSITION_TARGET_TYPEMASK_LAST_BYTE;
mavlink_msg_position_target_global_int_send(
chan,
@@ -102,11 +102,11 @@ int16_t GCS_MAVLINK_Blimp::vfr_hud_throttle() const
*/
void GCS_MAVLINK_Blimp::send_pid_tuning()
{
- if(blimp.control_mode == Mode::Number::MANUAL || blimp.control_mode == Mode::Number::LAND) {
+ if (blimp.control_mode == Mode::Number::MANUAL || blimp.control_mode == Mode::Number::LAND) {
//No PIDs are used in Manual or Land mode.
return;
}
-
+
static const int8_t axes[] = {
PID_SEND::VELX,
PID_SEND::VELY,
@@ -466,30 +466,17 @@ MAV_RESULT GCS_MAVLINK_Blimp::handle_command_int_do_reposition(const mavlink_com
return MAV_RESULT_ACCEPTED;
}
-MAV_RESULT GCS_MAVLINK_Blimp::handle_command_int_packet(const mavlink_command_int_t &packet)
+MAV_RESULT GCS_MAVLINK_Blimp::handle_command_int_packet(const mavlink_command_int_t &packet, const mavlink_message_t &msg)
{
switch (packet.command) {
- case MAV_CMD_DO_FOLLOW:
- return MAV_RESULT_UNSUPPORTED;
-
case MAV_CMD_DO_REPOSITION:
return handle_command_int_do_reposition(packet);
default:
- return GCS_MAVLINK::handle_command_int_packet(packet);
- }
-}
-
-MAV_RESULT GCS_MAVLINK_Blimp::handle_command_mount(const mavlink_command_long_t &packet)
-{
- // if the mount doesn't do pan control then yaw the entire vehicle instead:
- switch (packet.command) {
- default:
- break;
+ return GCS_MAVLINK::handle_command_int_packet(packet, msg);
}
- return GCS_MAVLINK::handle_command_mount(packet);
}
-MAV_RESULT GCS_MAVLINK_Blimp::handle_command_long_packet(const mavlink_command_long_t &packet)
+MAV_RESULT GCS_MAVLINK_Blimp::handle_command_long_packet(const mavlink_command_long_t &packet, const mavlink_message_t &msg)
{
switch (packet.command) {
@@ -515,7 +502,7 @@ MAV_RESULT GCS_MAVLINK_Blimp::handle_command_long_packet(const mavlink_command_l
return MAV_RESULT_FAILED;
default:
- return GCS_MAVLINK::handle_command_long_packet(packet);
+ return GCS_MAVLINK::handle_command_long_packet(packet, msg);
}
}
diff --git a/Blimp/GCS_Mavlink.h b/Blimp/GCS_Mavlink.h
index 3e2d67d7d4015c..100d06f0dd46b9 100644
--- a/Blimp/GCS_Mavlink.h
+++ b/Blimp/GCS_Mavlink.h
@@ -26,9 +26,8 @@ class GCS_MAVLINK_Blimp : public GCS_MAVLINK
void send_position_target_global_int() override;
MAV_RESULT handle_command_do_set_roi(const Location &roi_loc) override;
- MAV_RESULT handle_command_mount(const mavlink_command_long_t &packet) override;
- MAV_RESULT handle_command_int_packet(const mavlink_command_int_t &packet) override;
- MAV_RESULT handle_command_long_packet(const mavlink_command_long_t &packet) override;
+ MAV_RESULT handle_command_int_packet(const mavlink_command_int_t &packet, const mavlink_message_t &msg) override;
+ MAV_RESULT handle_command_long_packet(const mavlink_command_long_t &packet, const mavlink_message_t &msg) override;
MAV_RESULT handle_command_int_do_reposition(const mavlink_command_int_t &packet);
@@ -74,7 +73,7 @@ class GCS_MAVLINK_Blimp : public GCS_MAVLINK
POSZ = 7,
POSYAW = 8,
};
-
+
#if HAL_HIGH_LATENCY2_ENABLED
uint8_t high_latency_wind_speed() const override;
uint8_t high_latency_wind_direction() const override;
diff --git a/Blimp/Log.cpp b/Blimp/Log.cpp
index 6b74b028fd2e2f..cda675619688bc 100644
--- a/Blimp/Log.cpp
+++ b/Blimp/Log.cpp
@@ -30,7 +30,7 @@ struct PACKED log_FINO {
//Write a fin input packet
void Blimp::Write_FINI(float right, float front, float down, float yaw)
{
- const struct log_FINI pkt{
+ const struct log_FINI pkt {
LOG_PACKET_HEADER_INIT(LOG_FINI_MSG),
time_us : AP_HAL::micros64(),
Right : right,
@@ -44,7 +44,7 @@ void Blimp::Write_FINI(float right, float front, float down, float yaw)
//Write a fin output packet
void Blimp::Write_FINO(float *amp, float *off)
{
- const struct log_FINO pkt{
+ const struct log_FINO pkt {
LOG_PACKET_HEADER_INIT(LOG_FINO_MSG),
time_us : AP_HAL::micros64(),
Fin1_Amp : amp[0],
@@ -92,7 +92,9 @@ void Blimp::Log_Write_PIDs()
// Write an attitude packet
void Blimp::Log_Write_Attitude()
{
-
+ //Attitude targets are all zero since Blimp doesn't have attitude control,
+ //but the rest of the log message is useful.
+ ahrs.Write_Attitude(Vector3f{0,0,0});
}
// Write an EKF and POS packet
@@ -232,7 +234,6 @@ tuning_max : tune_max
logger.WriteBlock(&pkt_tune, sizeof(pkt_tune));
}
-
// type and unit information can be found in
// libraries/AP_Logger/Logstructure.h; search for "log_Units" for
// units and "Format characters" for field type information
@@ -247,8 +248,10 @@ const struct LogStructure Blimp::log_structure[] = {
// @Field: D: Down
// @Field: Y: Yaw
- { LOG_FINI_MSG, sizeof(log_FINI),
- "FINI", "Qffff", "TimeUS,R,F,D,Y", "s----", "F----" },
+ {
+ LOG_FINI_MSG, sizeof(log_FINI),
+ "FINI", "Qffff", "TimeUS,R,F,D,Y", "s----", "F----"
+ },
// @LoggerMessage: FINO
// @Description: Fin output
@@ -262,8 +265,10 @@ const struct LogStructure Blimp::log_structure[] = {
// @Field: F4A: Fin 4 Amplitude
// @Field: F4O: Fin 4 Offset
- { LOG_FINO_MSG, sizeof(log_FINO),
- "FINO", "Qffffffff", "TimeUS,F1A,F1O,F2A,F2O,F3A,F3O,F4A,F4O", "s--------", "F--------" },
+ {
+ LOG_FINO_MSG, sizeof(log_FINO),
+ "FINO", "Qffffffff", "TimeUS,F1A,F1O,F2A,F2O,F3A,F3O,F4A,F4O", "s--------", "F--------"
+ },
// @LoggerMessage: PIDD,PIVN,PIVE,PIVD,PIVY
// @Description: Proportional/Integral/Derivative gain values
@@ -278,16 +283,26 @@ const struct LogStructure Blimp::log_structure[] = {
// @Field: Dmod: scaler applied to D gain to reduce limit cycling
// @Field: SRate: slew rate
// @Field: Limit: 1 if I term is limited due to output saturation
- { LOG_PIDD_MSG, sizeof(log_PID),
- "PIDD", PID_FMT, PID_LABELS, PID_UNITS, PID_MULTS },
- { LOG_PIVN_MSG, sizeof(log_PID),
- "PIVN", PID_FMT, PID_LABELS, PID_UNITS, PID_MULTS },
- { LOG_PIVE_MSG, sizeof(log_PID),
- "PIVE", PID_FMT, PID_LABELS, PID_UNITS, PID_MULTS },
- { LOG_PIVD_MSG, sizeof(log_PID),
- "PIVD", PID_FMT, PID_LABELS, PID_UNITS, PID_MULTS },
- { LOG_PIVY_MSG, sizeof(log_PID),
- "PIVY", PID_FMT, PID_LABELS, PID_UNITS, PID_MULTS },
+ {
+ LOG_PIDD_MSG, sizeof(log_PID),
+ "PIDD", PID_FMT, PID_LABELS, PID_UNITS, PID_MULTS
+ },
+ {
+ LOG_PIVN_MSG, sizeof(log_PID),
+ "PIVN", PID_FMT, PID_LABELS, PID_UNITS, PID_MULTS
+ },
+ {
+ LOG_PIVE_MSG, sizeof(log_PID),
+ "PIVE", PID_FMT, PID_LABELS, PID_UNITS, PID_MULTS
+ },
+ {
+ LOG_PIVD_MSG, sizeof(log_PID),
+ "PIVD", PID_FMT, PID_LABELS, PID_UNITS, PID_MULTS
+ },
+ {
+ LOG_PIVY_MSG, sizeof(log_PID),
+ "PIVY", PID_FMT, PID_LABELS, PID_UNITS, PID_MULTS
+ },
// @LoggerMessage: PTUN
// @Description: Parameter Tuning information
@@ -403,8 +418,6 @@ void Blimp::Log_Write_Data(LogDataID id, uint16_t value) {}
void Blimp::Log_Write_Data(LogDataID id, float value) {}
void Blimp::Log_Write_Parameter_Tuning(uint8_t param, float tuning_val, float tune_min, float tune_max) {}
void Blimp::Log_Write_GuidedTarget(uint8_t target_type, const Vector3f& pos_target, const Vector3f& vel_target) {}
-void Blimp::Log_Write_SysID_Setup(uint8_t systemID_axis, float waveform_magnitude, float frequency_start, float frequency_stop, float time_fade_in, float time_const_freq, float time_record, float time_fade_out) {}
-void Blimp::Log_Write_SysID_Data(float waveform_time, float waveform_sample, float waveform_freq, float angle_x, float angle_y, float angle_z, float accel_x, float accel_y, float accel_z) {}
void Blimp::Log_Write_Vehicle_Startup_Messages() {}
void Blimp::log_init(void) {}
diff --git a/Blimp/Loiter.cpp b/Blimp/Loiter.cpp
new file mode 100644
index 00000000000000..8c6b5d5e7aea7c
--- /dev/null
+++ b/Blimp/Loiter.cpp
@@ -0,0 +1,202 @@
+#include "Blimp.h"
+
+#define MA 0.99
+#define MO (1-MA)
+
+void Loiter::run(Vector3f& target_pos, float& target_yaw, Vector4b axes_disabled)
+{
+ const float dt = blimp.scheduler.get_last_loop_time_s();
+
+ float scaler_xz_n;
+ float xz_out = fabsf(blimp.motors->front_out) + fabsf(blimp.motors->down_out);
+ if (xz_out > 1) {
+ scaler_xz_n = 1 / xz_out;
+ } else {
+ scaler_xz_n = 1;
+ }
+ scaler_xz = scaler_xz*MA + scaler_xz_n*MO;
+
+ float scaler_yyaw_n;
+ float yyaw_out = fabsf(blimp.motors->right_out) + fabsf(blimp.motors->yaw_out);
+ if (yyaw_out > 1) {
+ scaler_yyaw_n = 1 / yyaw_out;
+ } else {
+ scaler_yyaw_n = 1;
+ }
+ scaler_yyaw = scaler_yyaw*MA + scaler_yyaw_n*MO;
+
+ AP::logger().WriteStreaming("BSC", "TimeUS,xz,yyaw,xzn,yyawn",
+ "Qffff",
+ AP_HAL::micros64(),
+ scaler_xz, scaler_yyaw, scaler_xz_n, scaler_yyaw_n);
+
+ float yaw_ef = blimp.ahrs.get_yaw();
+ Vector3f err_xyz = target_pos - blimp.pos_ned;
+ float err_yaw = wrap_PI(target_yaw - yaw_ef);
+
+ Vector4b zero;
+ if ((fabsf(err_xyz.x) < blimp.g.pid_dz) || !blimp.motors->_armed || (blimp.g.dis_mask & (1<<(2-1)))) {
+ zero.x = true;
+ }
+ if ((fabsf(err_xyz.y) < blimp.g.pid_dz) || !blimp.motors->_armed || (blimp.g.dis_mask & (1<<(1-1)))) {
+ zero.y = true;
+ }
+ if ((fabsf(err_xyz.z) < blimp.g.pid_dz) || !blimp.motors->_armed || (blimp.g.dis_mask & (1<<(3-1)))) {
+ zero.z = true;
+ }
+ if ((fabsf(err_yaw) < blimp.g.pid_dz) || !blimp.motors->_armed || (blimp.g.dis_mask & (1<<(4-1)))) {
+ zero.yaw = true;
+ }
+
+ //Disabled means "don't update PIDs or output anything at all". Zero means actually output zero thrust. I term is limited in either case."
+ Vector4b limit = zero || axes_disabled;
+
+ Vector3f target_vel_ef;
+ if (!axes_disabled.x && !axes_disabled.y) target_vel_ef = {blimp.pid_pos_xy.update_all(target_pos, blimp.pos_ned, dt, {(float)limit.x, (float)limit.y, (float)limit.z}), 0};
+ if (!axes_disabled.z) {
+ target_vel_ef.z = blimp.pid_pos_z.update_all(target_pos.z, blimp.pos_ned.z, dt, limit.z);
+ }
+
+ float target_vel_yaw = 0;
+ if (!axes_disabled.yaw) {
+ target_vel_yaw = blimp.pid_pos_yaw.update_error(wrap_PI(target_yaw - yaw_ef), dt, limit.yaw);
+ blimp.pid_pos_yaw.set_target_rate(target_yaw);
+ blimp.pid_pos_yaw.set_actual_rate(yaw_ef);
+ }
+
+ Vector3f target_vel_ef_c{constrain_float(target_vel_ef.x, -blimp.g.max_vel_xy, blimp.g.max_vel_xy),
+ constrain_float(target_vel_ef.y, -blimp.g.max_vel_xy, blimp.g.max_vel_xy),
+ constrain_float(target_vel_ef.z, -blimp.g.max_vel_z, blimp.g.max_vel_z)};
+ float target_vel_yaw_c = constrain_float(target_vel_yaw, -blimp.g.max_vel_yaw, blimp.g.max_vel_yaw);
+
+ Vector2f target_vel_ef_c_scaled_xy = {target_vel_ef_c.x * scaler_xz, target_vel_ef_c.y * scaler_yyaw};
+ Vector2f vel_ned_filtd_scaled_xy = {blimp.vel_ned_filtd.x * scaler_xz, blimp.vel_ned_filtd.y * scaler_yyaw};
+
+ Vector2f actuator;
+ if (!axes_disabled.x && !axes_disabled.y) actuator = blimp.pid_vel_xy.update_all(target_vel_ef_c_scaled_xy, vel_ned_filtd_scaled_xy, dt, {(float)limit.x, (float)limit.y});
+ float act_down = 0;
+ if (!axes_disabled.z) {
+ act_down = blimp.pid_vel_z.update_all(target_vel_ef_c.z * scaler_xz, blimp.vel_ned_filtd.z * scaler_xz, dt, limit.z);
+ }
+ blimp.rotate_NE_to_BF(actuator);
+ float act_yaw = 0;
+ if (!axes_disabled.yaw) {
+ act_yaw = blimp.pid_vel_yaw.update_all(target_vel_yaw_c * scaler_yyaw, blimp.vel_yaw_filtd * scaler_yyaw, dt, limit.yaw);
+ }
+
+ if (!blimp.motors->armed()) {
+ blimp.pid_pos_xy.set_integrator(Vector2f(0,0));
+ blimp.pid_pos_z.set_integrator(0);
+ blimp.pid_pos_yaw.set_integrator(0);
+ blimp.pid_vel_xy.set_integrator(Vector2f(0,0));
+ blimp.pid_vel_z.set_integrator(0);
+ blimp.pid_vel_yaw.set_integrator(0);
+ target_pos = blimp.pos_ned;
+ target_yaw = blimp.ahrs.get_yaw();
+ }
+
+ if (zero.x) {
+ blimp.motors->front_out = 0;
+ } else if (axes_disabled.x);
+ else {
+ blimp.motors->front_out = actuator.x;
+ }
+ if (zero.y) {
+ blimp.motors->right_out = 0;
+ } else if (axes_disabled.y);
+ else {
+ blimp.motors->right_out = actuator.y;
+ }
+ if (zero.z) {
+ blimp.motors->down_out = 0;
+ } else if (axes_disabled.z);
+ else {
+ blimp.motors->down_out = act_down;
+ }
+ if (zero.yaw) {
+ blimp.motors->yaw_out = 0;
+ } else if (axes_disabled.yaw);
+ else {
+ blimp.motors->yaw_out = act_yaw;
+ }
+
+ AP::logger().Write_PSCN(target_pos.x * 100.0, blimp.pos_ned.x * 100.0, 0.0, target_vel_ef_c.x * 100.0, blimp.vel_ned_filtd.x * 100.0, 0.0, 0.0, 0.0);
+ AP::logger().Write_PSCE(target_pos.y * 100.0, blimp.pos_ned.y * 100.0, 0.0, target_vel_ef_c.y * 100.0, blimp.vel_ned_filtd.y * 100.0, 0.0, 0.0, 0.0);
+ AP::logger().Write_PSCD(-target_pos.z * 100.0, -blimp.pos_ned.z * 100.0, 0.0, -target_vel_ef_c.z * 100.0, -blimp.vel_ned_filtd.z * 100.0, 0.0, 0.0, 0.0);
+}
+
+void Loiter::run_vel(Vector3f& target_vel_ef, float& target_vel_yaw, Vector4b axes_disabled)
+{
+ const float dt = blimp.scheduler.get_last_loop_time_s();
+
+ Vector4b zero;
+ if (!blimp.motors->_armed || (blimp.g.dis_mask & (1<<(2-1)))) {
+ zero.x = true;
+ }
+ if (!blimp.motors->_armed || (blimp.g.dis_mask & (1<<(1-1)))) {
+ zero.y = true;
+ }
+ if (!blimp.motors->_armed || (blimp.g.dis_mask & (1<<(3-1)))) {
+ zero.z = true;
+ }
+ if (!blimp.motors->_armed || (blimp.g.dis_mask & (1<<(4-1)))) {
+ zero.yaw = true;
+ }
+ //Disabled means "don't update PIDs or output anything at all". Zero means actually output zero thrust. I term is limited in either case."
+ Vector4b limit = zero || axes_disabled;
+
+ Vector3f target_vel_ef_c{constrain_float(target_vel_ef.x, -blimp.g.max_vel_xy, blimp.g.max_vel_xy),
+ constrain_float(target_vel_ef.y, -blimp.g.max_vel_xy, blimp.g.max_vel_xy),
+ constrain_float(target_vel_ef.z, -blimp.g.max_vel_z, blimp.g.max_vel_z)};
+ float target_vel_yaw_c = constrain_float(target_vel_yaw, -blimp.g.max_vel_yaw, blimp.g.max_vel_yaw);
+
+ Vector2f target_vel_ef_c_scaled_xy = {target_vel_ef_c.x * scaler_xz, target_vel_ef_c.y * scaler_yyaw};
+ Vector2f vel_ned_filtd_scaled_xy = {blimp.vel_ned_filtd.x * scaler_xz, blimp.vel_ned_filtd.y * scaler_yyaw};
+
+ Vector2f actuator;
+ if (!axes_disabled.x && !axes_disabled.y) actuator = blimp.pid_vel_xy.update_all(target_vel_ef_c_scaled_xy, vel_ned_filtd_scaled_xy, dt, {(float)limit.x, (float)limit.y});
+ float act_down = 0;
+ if (!axes_disabled.z) {
+ act_down = blimp.pid_vel_z.update_all(target_vel_ef_c.z * scaler_xz, blimp.vel_ned_filtd.z * scaler_xz, dt, limit.z);
+ }
+ blimp.rotate_NE_to_BF(actuator);
+ float act_yaw = 0;
+ if (!axes_disabled.yaw) {
+ act_yaw = blimp.pid_vel_yaw.update_all(target_vel_yaw_c * scaler_yyaw, blimp.vel_yaw_filtd * scaler_yyaw, dt, limit.yaw);
+ }
+
+ if (!blimp.motors->armed()) {
+ blimp.pid_vel_xy.set_integrator(Vector2f(0,0));
+ blimp.pid_vel_z.set_integrator(0);
+ blimp.pid_vel_yaw.set_integrator(0);
+ }
+
+ if (zero.x) {
+ blimp.motors->front_out = 0;
+ } else if (axes_disabled.x);
+ else {
+ blimp.motors->front_out = actuator.x;
+ }
+ if (zero.y) {
+ blimp.motors->right_out = 0;
+ } else if (axes_disabled.y);
+ else {
+ blimp.motors->right_out = actuator.y;
+ }
+ if (zero.z) {
+ blimp.motors->down_out = 0;
+ } else if (axes_disabled.z);
+ else {
+ blimp.motors->down_out = act_down;
+ }
+ if (zero.yaw) {
+ blimp.motors->yaw_out = 0;
+ } else if (axes_disabled.yaw);
+ else {
+ blimp.motors->yaw_out = act_yaw;
+ }
+
+ AP::logger().Write_PSCN(0.0, blimp.pos_ned.x * 100.0, 0.0, target_vel_ef_c.x * 100.0, blimp.vel_ned_filtd.x * 100.0, 0.0, 0.0, 0.0);
+ AP::logger().Write_PSCE(0.0, blimp.pos_ned.y * 100.0, 0.0, target_vel_ef_c.y * 100.0, blimp.vel_ned_filtd.y * 100.0, 0.0, 0.0, 0.0);
+ AP::logger().Write_PSCD(0.0, -blimp.pos_ned.z * 100.0, 0.0, -target_vel_ef_c.z * 100.0, -blimp.vel_ned_filtd.z * 100.0, 0.0, 0.0, 0.0);
+}
diff --git a/Blimp/Loiter.h b/Blimp/Loiter.h
new file mode 100644
index 00000000000000..c21fdd57c6f251
--- /dev/null
+++ b/Blimp/Loiter.h
@@ -0,0 +1,59 @@
+#pragma once
+
+class Vector4b
+{
+public:
+ bool x;
+ bool y;
+ bool z;
+ bool yaw;
+
+ constexpr Vector4b()
+ : x(0)
+ , y(0)
+ , z(0)
+ , yaw(0) {}
+
+ constexpr Vector4b(const bool x0, const bool y0, const bool z0, const bool yaw0)
+ : x(x0)
+ , y(y0)
+ , z(z0)
+ , yaw(yaw0) {}
+
+ Vector4b operator &&(const Vector4b &v)
+ {
+ Vector4b temp{x && v.x, y && v.y, z && v.z, yaw && v.yaw};
+ return temp;
+ }
+
+ Vector4b operator ||(const Vector4b &v)
+ {
+ Vector4b temp{x || v.x, y || v.y, z || v.z, yaw || v.yaw};
+ return temp;
+ }
+
+};
+
+
+
+class Loiter
+{
+public:
+ friend class Blimp;
+ friend class Fins;
+
+ float scaler_xz;
+ float scaler_yyaw;
+
+ //constructor
+ Loiter(uint16_t loop_rate)
+ {
+ scaler_xz = 1;
+ scaler_yyaw = 1;
+ };
+
+ //Run Loiter controller with target position and yaw in global frame. Expects to be called at loop rate.
+ void run(Vector3f& target_pos, float& target_yaw, Vector4b axes_disabled);
+ //Run Loiter controller with target velocity and velocity in global frame. Expects to be called at loop rate.
+ void run_vel(Vector3f& target_vel, float& target_vel_yaw, Vector4b axes_disabled);
+};
diff --git a/Blimp/Parameters.cpp b/Blimp/Parameters.cpp
index 487d0981146b01..6956f1eda58433 100644
--- a/Blimp/Parameters.cpp
+++ b/Blimp/Parameters.cpp
@@ -53,15 +53,6 @@ const AP_Param::Info Blimp::var_info[] = {
// @Increment: .5
GSCALAR(throttle_filt, "PILOT_THR_FILT", 0),
- // @Param: PILOT_TKOFF_ALT
- // @DisplayName: Pilot takeoff altitude
- // @Description: Altitude that altitude control modes will climb to when a takeoff is triggered with the throttle stick.
- // @User: Standard
- // @Units: cm
- // @Range: 0.0 1000.0
- // @Increment: 10
- GSCALAR(pilot_takeoff_alt, "PILOT_TKOFF_ALT", PILOT_TKOFF_ALT_DEFAULT),
-
// @Param: PILOT_THR_BHV
// @DisplayName: Throttle stick behavior
// @Description: Bitmask containing various throttle stick options. TX with sprung throttle can set PILOT_THR_BHV to "1" so motor feedback when landed starts from mid-stick instead of bottom of stick.
@@ -184,7 +175,7 @@ const AP_Param::Info Blimp::var_info[] = {
// @Param: LOG_BITMASK
// @DisplayName: Log bitmask
// @Description: Bitmap of what log types to enable in on-board logger. This value is made up of the sum of each of the log types you want to be saved. On boards supporting microSD cards or other large block-storage devices it is usually best just to enable all basic log types by setting this to 65535.
- // @Bitmask: 0:Fast Attitude,1:Medium Attitude,2:GPS,3:System Performance,4:Control Tuning,6:RC Input,7:IMU,9:Battery Monitor,10:RC Output,11:Optical Flow,12:PID,13:Compass
+ // @Bitmask: 0:Fast Attitude,1:Medium Attitude,2:GPS,3:System Performance,4:Control Tuning,6:RC Input,7:IMU,9:Battery Monitor,10:RC Output,12:PID,13:Compass
// @User: Standard
GSCALAR(log_bitmask, "LOG_BITMASK", DEFAULT_LOG_BITMASK),
@@ -272,12 +263,20 @@ const AP_Param::Info Blimp::var_info[] = {
// @Param: DIS_MASK
// @DisplayName: Disable output mask
- // @Description: Mask for disabling one or more of the 4 output axis in mode Velocity or Loiter
+ // @Description: Mask for disabling (setting to zero) one or more of the 4 output axis in mode Velocity or Loiter
// @Values: 0:All enabled,1:Right,2:Front,4:Down,8:Yaw,3:Down and Yaw only,12:Front & Right only
// @Bitmask: 0:Right,1:Front,2:Down,3:Yaw
// @User: Standard
GSCALAR(dis_mask, "DIS_MASK", 0),
+ // @Param: PID_DZ
+ // @DisplayName: Deadzone for the position PIDs
+ // @Description: Output 0 thrust signal when blimp is within this distance (in meters) of the target position. Warning: If this param is greater than MAX_POS_XY param then the blimp won't move at all in the XY plane in Loiter mode as it does not allow more than a second's lag. Same for the other axes.
+ // @Units: m
+ // @Range: 0.1 1
+ // @User: Standard
+ GSCALAR(pid_dz, "PID_DZ", 0),
+
// @Param: RC_SPEED
// @DisplayName: ESC Update Speed
// @Description: This is the speed in Hertz that your ESCs will receive updates
diff --git a/Blimp/Parameters.h b/Blimp/Parameters.h
index c819ad0ab46543..8ec466d62c0c6d 100644
--- a/Blimp/Parameters.h
+++ b/Blimp/Parameters.h
@@ -87,7 +87,7 @@ class Parameters
k_param_log_bitmask,
k_param_throttle_filt,
k_param_throttle_behavior,
- k_param_pilot_takeoff_alt,
+ k_param_pilot_takeoff_alt, //unused
// AP_ADSB Library
k_param_adsb,
@@ -110,6 +110,7 @@ class Parameters
k_param_max_pos_yaw,
k_param_simple_mode,
k_param_dis_mask,
+ k_param_pid_dz,
//
// 90: misc2
@@ -135,7 +136,7 @@ class Parameters
k_param_gcs2,
k_param_serial_manager,
k_param_gcs3,
- k_param_gcs_pid_mask, // 126
+ k_param_gcs_pid_mask,
k_param_gcs4,
k_param_gcs5,
k_param_gcs6,
@@ -213,7 +214,6 @@ class Parameters
AP_Float throttle_filt;
AP_Int16 throttle_behavior;
- AP_Float pilot_takeoff_alt;
AP_Int8 failsafe_gcs; // ground station failsafe behavior
AP_Int16 gps_hdop_good; // GPS Hdop value at or below this value represent a good position
@@ -254,6 +254,7 @@ class Parameters
AP_Int8 simple_mode;
AP_Int16 dis_mask;
+ AP_Float pid_dz;
AP_Int8 rtl_alt_type;
diff --git a/Blimp/RC_Channel.cpp b/Blimp/RC_Channel.cpp
index 39682160ae5dc1..7709867cf25c4a 100644
--- a/Blimp/RC_Channel.cpp
+++ b/Blimp/RC_Channel.cpp
@@ -36,6 +36,11 @@ void RC_Channel_Blimp::mode_switch_changed(modeswitch_pos_t new_pos)
}
}
+bool RC_Channels_Blimp::in_rc_failsafe() const
+{
+ return blimp.failsafe.radio;
+}
+
bool RC_Channels_Blimp::has_valid_input() const
{
if (blimp.failsafe.radio) {
@@ -101,7 +106,7 @@ bool RC_Channel_Blimp::do_aux_function(const aux_func_t ch_option, const AuxSwit
case AUX_FUNC::SAVE_TRIM:
if ((ch_flag == AuxSwitchPos::HIGH) &&
(blimp.control_mode <= Mode::Number::MANUAL) &&
- (blimp.channel_down->get_control_in() == 0)) {
+ (blimp.channel_up->get_control_in() == 0)) {
blimp.save_trim();
}
break;
diff --git a/Blimp/RC_Channel.h b/Blimp/RC_Channel.h
index 80e53ceda23028..ec37259794cb82 100644
--- a/Blimp/RC_Channel.h
+++ b/Blimp/RC_Channel.h
@@ -30,6 +30,7 @@ class RC_Channels_Blimp : public RC_Channels
public:
bool has_valid_input() const override;
+ bool in_rc_failsafe() const override;
RC_Channel *get_arming_channel(void) const override;
diff --git a/Blimp/config.h b/Blimp/config.h
index 10cac9ea72bf7b..9c5908f65fed98 100644
--- a/Blimp/config.h
+++ b/Blimp/config.h
@@ -22,13 +22,6 @@
# define ARMING_DELAY_SEC 2.0f
#endif
-//////////////////////////////////////////////////////////////////////////////
-// FRAME_CONFIG
-//
-#ifndef FRAME_CONFIG
-# define FRAME_CONFIG MULTICOPTER_FRAME
-#endif
-
//////////////////////////////////////////////////////////////////////////////
// PWM control
// default RC speed in Hz
@@ -36,53 +29,6 @@
# define RC_FAST_SPEED 490
#endif
-//////////////////////////////////////////////////////////////////////////////
-// Rangefinder
-//
-
-#ifndef RANGEFINDER_ENABLED
-# define RANGEFINDER_ENABLED ENABLED
-#endif
-
-#ifndef RANGEFINDER_HEALTH_MAX
-# define RANGEFINDER_HEALTH_MAX 3 // number of good reads that indicates a healthy rangefinder
-#endif
-
-#ifndef RANGEFINDER_TIMEOUT_MS
-# define RANGEFINDER_TIMEOUT_MS 1000 // rangefinder filter reset if no updates from sensor in 1 second
-#endif
-
-#ifndef RANGEFINDER_GAIN_DEFAULT
-# define RANGEFINDER_GAIN_DEFAULT 0.8f // gain for controlling how quickly rangefinder range adjusts target altitude (lower means slower reaction)
-#endif
-
-#ifndef SURFACE_TRACKING_TIMEOUT_MS
-# define SURFACE_TRACKING_TIMEOUT_MS 1000 // surface tracking target alt will reset to current rangefinder alt after this many milliseconds without a good rangefinder alt
-#endif
-
-#ifndef RANGEFINDER_WPNAV_FILT_HZ
-# define RANGEFINDER_WPNAV_FILT_HZ 0.25f // filter frequency for rangefinder altitude provided to waypoint navigation class
-#endif
-
-#ifndef RANGEFINDER_TILT_CORRECTION // by disable tilt correction for use of range finder data by EKF
-# define RANGEFINDER_TILT_CORRECTION ENABLED
-#endif
-
-#ifndef RANGEFINDER_GLITCH_ALT_CM
-# define RANGEFINDER_GLITCH_ALT_CM 200 // amount of rangefinder change to be considered a glitch
-#endif
-
-#ifndef RANGEFINDER_GLITCH_NUM_SAMPLES
-# define RANGEFINDER_GLITCH_NUM_SAMPLES 3 // number of rangefinder glitches in a row to take new reading
-#endif
-
-//////////////////////////////////////////////////////////////////////////////
-// Proximity sensor
-//
-#ifndef PROXIMITY_ENABLED
-# define PROXIMITY_ENABLED ENABLED
-#endif
-
#ifndef MAV_SYSTEM_ID
# define MAV_SYSTEM_ID 1
#endif
@@ -125,100 +71,9 @@
# define EKF_ORIGIN_MAX_DIST_M 50000 // EKF origin and waypoints (including home) must be within 50km
#endif
-//////////////////////////////////////////////////////////////////////////////
-// OPTICAL_FLOW
-#ifndef OPTFLOW
-# define OPTFLOW ENABLED
-#endif
-
-//////////////////////////////////////////////////////////////////////////////
-// Auto Tuning
-#ifndef AUTOTUNE_ENABLED
-# define AUTOTUNE_ENABLED ENABLED
-#endif
-
-//////////////////////////////////////////////////////////////////////////////
-// Parachute release
-#ifndef PARACHUTE
-# define PARACHUTE HAL_PARACHUTE_ENABLED
-#endif
-
-//////////////////////////////////////////////////////////////////////////////
-// Acro - fly vehicle in acrobatic mode
-#ifndef MODE_ACRO_ENABLED
-# define MODE_ACRO_ENABLED ENABLED
-#endif
-
-//////////////////////////////////////////////////////////////////////////////
-// Auto mode - allows vehicle to trace waypoints and perform automated actions
-#ifndef MODE_AUTO_ENABLED
-# define MODE_AUTO_ENABLED ENABLED
-#endif
-
-//////////////////////////////////////////////////////////////////////////////
-// Brake mode - bring vehicle to stop
-#ifndef MODE_BRAKE_ENABLED
-# define MODE_BRAKE_ENABLED ENABLED
-#endif
-
-//////////////////////////////////////////////////////////////////////////////
-// Circle - fly vehicle around a central point
-#ifndef MODE_CIRCLE_ENABLED
-# define MODE_CIRCLE_ENABLED ENABLED
-#endif
-
-//////////////////////////////////////////////////////////////////////////////
-// Drift - fly vehicle in altitude-held, coordinated-turn mode
-#ifndef MODE_DRIFT_ENABLED
-# define MODE_DRIFT_ENABLED ENABLED
-#endif
-
-//////////////////////////////////////////////////////////////////////////////
-// flip - fly vehicle in flip in pitch and roll direction mode
-#ifndef MODE_FLIP_ENABLED
-# define MODE_FLIP_ENABLED ENABLED
-#endif
-
-//////////////////////////////////////////////////////////////////////////////
-// Guided mode - control vehicle's position or angles from GCS
-#ifndef MODE_GUIDED_ENABLED
-# define MODE_GUIDED_ENABLED ENABLED
-#endif
-
-//////////////////////////////////////////////////////////////////////////////
-// Loiter mode - allows vehicle to hold global position
-#ifndef MODE_LOITER_ENABLED
-# define MODE_LOITER_ENABLED ENABLED
-#endif
-
-//////////////////////////////////////////////////////////////////////////////
-// Position Hold - enable holding of global position
-#ifndef MODE_POSHOLD_ENABLED
-# define MODE_POSHOLD_ENABLED ENABLED
-#endif
-
-//////////////////////////////////////////////////////////////////////////////
-// RTL - Return To Launch
-#ifndef MODE_RTL_ENABLED
-# define MODE_RTL_ENABLED ENABLED
-#endif
-
-//////////////////////////////////////////////////////////////////////////////
-// SmartRTL - allows vehicle to retrace a (loop-eliminated) breadcrumb home
-#ifndef MODE_SMARTRTL_ENABLED
-# define MODE_SMARTRTL_ENABLED ENABLED
-#endif
-
-//////////////////////////////////////////////////////////////////////////////
-// RADIO CONFIGURATION
-//////////////////////////////////////////////////////////////////////////////
-//////////////////////////////////////////////////////////////////////////////
-
-
//////////////////////////////////////////////////////////////////////////////
// FLIGHT_MODE
//
-
#ifndef FLIGHT_MODE_1
# define FLIGHT_MODE_1 Mode::Number::MANUAL
#endif
@@ -238,7 +93,6 @@
# define FLIGHT_MODE_6 Mode::Number::MANUAL
#endif
-
//////////////////////////////////////////////////////////////////////////////
// Throttle Failsafe
//
@@ -246,188 +100,17 @@
# define FS_THR_VALUE_DEFAULT 975
#endif
-//////////////////////////////////////////////////////////////////////////////
-// Takeoff
-//
-#ifndef PILOT_TKOFF_ALT_DEFAULT
-# define PILOT_TKOFF_ALT_DEFAULT 0 // default final alt above home for pilot initiated takeoff
-#endif
-
-
-//////////////////////////////////////////////////////////////////////////////
-// Landing
-//
-#ifndef LAND_SPEED
-# define LAND_SPEED 50 // the descent speed for the final stage of landing in cm/s
-#endif
-#ifndef LAND_REPOSITION_DEFAULT
-# define LAND_REPOSITION_DEFAULT 1 // by default the pilot can override roll/pitch during landing
-#endif
-#ifndef LAND_WITH_DELAY_MS
-# define LAND_WITH_DELAY_MS 4000 // default delay (in milliseconds) when a land-with-delay is triggered during a failsafe event
-#endif
-#ifndef LAND_CANCEL_TRIGGER_THR
-# define LAND_CANCEL_TRIGGER_THR 700 // land is cancelled by input throttle above 700
-#endif
-#ifndef LAND_RANGEFINDER_MIN_ALT_CM
-#define LAND_RANGEFINDER_MIN_ALT_CM 200
-#endif
-
-//////////////////////////////////////////////////////////////////////////////
-// Landing Detector
-//
-#ifndef LAND_DETECTOR_TRIGGER_SEC
-# define LAND_DETECTOR_TRIGGER_SEC 1.0f // number of seconds to detect a landing
-#endif
-#ifndef LAND_DETECTOR_MAYBE_TRIGGER_SEC
-# define LAND_DETECTOR_MAYBE_TRIGGER_SEC 0.2f // number of seconds that means we might be landed (used to reset horizontal position targets to prevent tipping over)
-#endif
-#ifndef LAND_DETECTOR_ACCEL_LPF_CUTOFF
-# define LAND_DETECTOR_ACCEL_LPF_CUTOFF 1.0f // frequency cutoff of land detector accelerometer filter
-#endif
-#ifndef LAND_DETECTOR_ACCEL_MAX
-# define LAND_DETECTOR_ACCEL_MAX 1.0f // vehicle acceleration must be under 1m/s/s
-#endif
-
-//////////////////////////////////////////////////////////////////////////////
-// Flight mode definitions
-//
-
-// Acro Mode
-#ifndef ACRO_RP_P
-# define ACRO_RP_P 4.5f
-#endif
-
-#ifndef ACRO_YAW_P
-# define ACRO_YAW_P 4.5f
-#endif
-
-#ifndef ACRO_LEVEL_MAX_ANGLE
-# define ACRO_LEVEL_MAX_ANGLE 3000
-#endif
-
-#ifndef ACRO_BALANCE_ROLL
-#define ACRO_BALANCE_ROLL 1.0f
-#endif
-
-#ifndef ACRO_BALANCE_PITCH
-#define ACRO_BALANCE_PITCH 1.0f
-#endif
-
-#ifndef ACRO_RP_EXPO_DEFAULT
-#define ACRO_RP_EXPO_DEFAULT 0.3f
-#endif
-
-#ifndef ACRO_Y_EXPO_DEFAULT
-#define ACRO_Y_EXPO_DEFAULT 0.0f
-#endif
-
-#ifndef ACRO_THR_MID_DEFAULT
-#define ACRO_THR_MID_DEFAULT 0.0f
-#endif
-
-// RTL Mode
-#ifndef RTL_ALT_FINAL
-# define RTL_ALT_FINAL 0 // the altitude the vehicle will move to as the final stage of Returning to Launch. Set to zero to land.
-#endif
-
-#ifndef RTL_ALT
-# define RTL_ALT 1500 // default alt to return to home in cm, 0 = Maintain current altitude
-#endif
-
-#ifndef RTL_ALT_MIN
-# define RTL_ALT_MIN 200 // min height above ground for RTL (i.e 2m)
-#endif
-
-#ifndef RTL_CLIMB_MIN_DEFAULT
-# define RTL_CLIMB_MIN_DEFAULT 0 // vehicle will always climb this many cm as first stage of RTL
-#endif
-
-#ifndef RTL_ABS_MIN_CLIMB
-# define RTL_ABS_MIN_CLIMB 250 // absolute minimum initial climb
-#endif
-
-#ifndef RTL_CONE_SLOPE_DEFAULT
-# define RTL_CONE_SLOPE_DEFAULT 3.0f // slope of RTL cone (height / distance). 0 = No cone
-#endif
-
-#ifndef RTL_MIN_CONE_SLOPE
-# define RTL_MIN_CONE_SLOPE 0.5f // minimum slope of cone
-#endif
-
-#ifndef RTL_LOITER_TIME
-# define RTL_LOITER_TIME 5000 // Time (in milliseconds) to loiter above home before beginning final descent
-#endif
-
-// AUTO Mode
-#ifndef WP_YAW_BEHAVIOR_DEFAULT
-# define WP_YAW_BEHAVIOR_DEFAULT WP_YAW_BEHAVIOR_LOOK_AT_NEXT_WP_EXCEPT_RTL
-#endif
-
-#ifndef YAW_LOOK_AHEAD_MIN_SPEED
-# define YAW_LOOK_AHEAD_MIN_SPEED 100 // minimum ground speed in cm/s required before blimp is aimed at ground course
-#endif
-
-//////////////////////////////////////////////////////////////////////////////
-// Stabilize Rate Control
-//
-#ifndef ROLL_PITCH_YAW_INPUT_MAX
-# define ROLL_PITCH_YAW_INPUT_MAX 4500 // roll, pitch and yaw input range
-#endif
-#ifndef DEFAULT_ANGLE_MAX
-# define DEFAULT_ANGLE_MAX 4500 // ANGLE_MAX parameters default value
-#endif
-
-//////////////////////////////////////////////////////////////////////////////
-// Stop mode defaults
-//
-#ifndef BRAKE_MODE_SPEED_Z
-# define BRAKE_MODE_SPEED_Z 250 // z-axis speed in cm/s in Brake Mode
-#endif
-#ifndef BRAKE_MODE_DECEL_RATE
-# define BRAKE_MODE_DECEL_RATE 750 // acceleration rate in cm/s/s in Brake Mode
-#endif
-
-//////////////////////////////////////////////////////////////////////////////
-// PosHold parameter defaults
-//
-#ifndef POSHOLD_BRAKE_RATE_DEFAULT
-# define POSHOLD_BRAKE_RATE_DEFAULT 8 // default POSHOLD_BRAKE_RATE param value. Rotation rate during braking in deg/sec
-#endif
-#ifndef POSHOLD_BRAKE_ANGLE_DEFAULT
-# define POSHOLD_BRAKE_ANGLE_DEFAULT 3000 // default POSHOLD_BRAKE_ANGLE param value. Max lean angle during braking in centi-degrees
-#endif
-
//////////////////////////////////////////////////////////////////////////////
// Throttle control defaults
//
-
#ifndef THR_DZ_DEFAULT
# define THR_DZ_DEFAULT 100 // the deadzone above and below mid throttle while in althold or loiter
#endif
-// default maximum vertical velocity and acceleration the pilot may request
-#ifndef PILOT_VELZ_MAX
-# define PILOT_VELZ_MAX 250 // maximum vertical velocity in cm/s
-#endif
-#ifndef PILOT_ACCEL_Z_DEFAULT
-# define PILOT_ACCEL_Z_DEFAULT 250 // vertical acceleration in cm/s/s while altitude is under pilot control
-#endif
-
#ifndef AUTO_DISARMING_DELAY
# define AUTO_DISARMING_DELAY 10
#endif
-//////////////////////////////////////////////////////////////////////////////
-// Throw mode configuration
-//
-#ifndef THROW_HIGH_SPEED
-# define THROW_HIGH_SPEED 500.0f // vehicle much reach this total 3D speed in cm/s (or be free falling)
-#endif
-#ifndef THROW_VERTICAL_SPEED
-# define THROW_VERTICAL_SPEED 50.0f // motors start when vehicle reaches this total 3D speed in cm/s
-#endif
-
//////////////////////////////////////////////////////////////////////////////
// Logging control
//
diff --git a/Blimp/defines.h b/Blimp/defines.h
index f356e77600f551..0a73072a1aea5f 100644
--- a/Blimp/defines.h
+++ b/Blimp/defines.h
@@ -10,111 +10,6 @@
#define ENABLE ENABLED
#define DISABLE DISABLED
-// Autopilot Yaw Mode enumeration
-enum autopilot_yaw_mode {
- AUTO_YAW_HOLD = 0, // pilot controls the heading
- AUTO_YAW_LOOK_AT_NEXT_WP = 1, // point towards next waypoint (no pilot input accepted)
- AUTO_YAW_ROI = 2, // point towards a location held in roi (no pilot input accepted)
- AUTO_YAW_FIXED = 3, // point towards a particular angle (no pilot input accepted)
- AUTO_YAW_LOOK_AHEAD = 4, // point in the direction the blimp is moving
- AUTO_YAW_RESETTOARMEDYAW = 5, // point towards heading at time motors were armed
- AUTO_YAW_RATE = 6, // turn at a specified rate (held in auto_yaw_rate)
- AUTO_YAW_CIRCLE = 7, // use AC_Circle's provided yaw (used during Loiter-Turns commands)
-};
-
-// Frame types
-#define UNDEFINED_FRAME 0
-#define MULTICOPTER_FRAME 1
-#define HELI_FRAME 2
-
-// Tuning enumeration
-enum tuning_func {
- TUNING_NONE = 0, //
- TUNING_STABILIZE_ROLL_PITCH_KP = 1, // stabilize roll/pitch angle controller's P term
- TUNING_STABILIZE_YAW_KP = 3, // stabilize yaw heading controller's P term
- TUNING_RATE_ROLL_PITCH_KP = 4, // body frame roll/pitch rate controller's P term
- TUNING_RATE_ROLL_PITCH_KI = 5, // body frame roll/pitch rate controller's I term
- TUNING_YAW_RATE_KP = 6, // body frame yaw rate controller's P term
- TUNING_THROTTLE_RATE_KP = 7, // throttle rate controller's P term (desired rate to acceleration or motor output)
- TUNING_WP_SPEED = 10, // maximum speed to next way point (0 to 10m/s)
- TUNING_LOITER_POSITION_KP = 12, // loiter distance controller's P term (position error to speed)
- TUNING_HELI_EXTERNAL_GYRO = 13, // TradHeli specific external tail gyro gain
- TUNING_ALTITUDE_HOLD_KP = 14, // altitude hold controller's P term (alt error to desired rate)
- TUNING_RATE_ROLL_PITCH_KD = 21, // body frame roll/pitch rate controller's D term
- TUNING_VEL_XY_KP = 22, // loiter rate controller's P term (speed error to tilt angle)
- TUNING_ACRO_RP_KP = 25, // acro controller's P term. converts pilot input to a desired roll, pitch or yaw rate
- TUNING_YAW_RATE_KD = 26, // body frame yaw rate controller's D term
- TUNING_VEL_XY_KI = 28, // loiter rate controller's I term (speed error to tilt angle)
- TUNING_AHRS_YAW_KP = 30, // ahrs's compass effect on yaw angle (0 = very low, 1 = very high)
- TUNING_AHRS_KP = 31, // accelerometer effect on roll/pitch angle (0=low)
- TUNING_ACCEL_Z_KP = 34, // accel based throttle controller's P term
- TUNING_ACCEL_Z_KI = 35, // accel based throttle controller's I term
- TUNING_ACCEL_Z_KD = 36, // accel based throttle controller's D term
- TUNING_DECLINATION = 38, // compass declination in radians
- TUNING_CIRCLE_RATE = 39, // circle turn rate in degrees (hard coded to about 45 degrees in either direction)
- TUNING_ACRO_YAW_KP = 40, // acro controller's P term. converts pilot input to a desired roll, pitch or yaw rate
- TUNING_RANGEFINDER_GAIN = 41, // rangefinder gain
- TUNING_EKF_VERTICAL_POS = 42, // unused
- TUNING_EKF_HORIZONTAL_POS = 43, // unused
- TUNING_EKF_ACCEL_NOISE = 44, // unused
- TUNING_RC_FEEL_RP = 45, // roll-pitch input smoothing
- TUNING_RATE_PITCH_KP = 46, // body frame pitch rate controller's P term
- TUNING_RATE_PITCH_KI = 47, // body frame pitch rate controller's I term
- TUNING_RATE_PITCH_KD = 48, // body frame pitch rate controller's D term
- TUNING_RATE_ROLL_KP = 49, // body frame roll rate controller's P term
- TUNING_RATE_ROLL_KI = 50, // body frame roll rate controller's I term
- TUNING_RATE_ROLL_KD = 51, // body frame roll rate controller's D term
- TUNING_RATE_PITCH_FF = 52, // body frame pitch rate controller FF term
- TUNING_RATE_ROLL_FF = 53, // body frame roll rate controller FF term
- TUNING_RATE_YAW_FF = 54, // body frame yaw rate controller FF term
- TUNING_RATE_MOT_YAW_HEADROOM = 55, // motors yaw headroom minimum
- TUNING_RATE_YAW_FILT = 56, // yaw rate input filter
- UNUSED = 57, // was winch control
- TUNING_SYSTEM_ID_MAGNITUDE = 58 // magnitude of the system ID signal
-};
-
-// Yaw behaviours during missions - possible values for WP_YAW_BEHAVIOR parameter
-#define WP_YAW_BEHAVIOR_NONE 0 // auto pilot will never control yaw during missions or rtl (except for DO_CONDITIONAL_YAW command received)
-#define WP_YAW_BEHAVIOR_LOOK_AT_NEXT_WP 1 // auto pilot will face next waypoint or home during rtl
-#define WP_YAW_BEHAVIOR_LOOK_AT_NEXT_WP_EXCEPT_RTL 2 // auto pilot will face next waypoint except when doing RTL at which time it will stay in it's last
-#define WP_YAW_BEHAVIOR_LOOK_AHEAD 3 // auto pilot will look ahead during missions and rtl (primarily meant for traditional helicopters)
-
-// Auto modes
-enum AutoMode {
- Auto_TakeOff,
- Auto_WP,
- Auto_Land,
- Auto_RTL,
- Auto_CircleMoveToEdge,
- Auto_Circle,
- Auto_Spline,
- Auto_NavGuided,
- Auto_Loiter,
- Auto_LoiterToAlt,
- Auto_NavPayloadPlace,
-};
-
-// Guided modes
-enum GuidedMode {
- Guided_TakeOff,
- Guided_WP,
- Guided_Velocity,
- Guided_PosVel,
- Guided_Angle,
-};
-
-enum PayloadPlaceStateType {
- PayloadPlaceStateType_FlyToLocation,
- PayloadPlaceStateType_Descent_Start,
- PayloadPlaceStateType_Descent,
- PayloadPlaceStateType_Release,
- PayloadPlaceStateType_Releasing,
- PayloadPlaceStateType_Delay,
- PayloadPlaceStateType_Ascent_Start,
- PayloadPlaceStateType_Ascent,
- PayloadPlaceStateType_Done,
-};
-
// bit options for DEV_OPTIONS parameter
enum DevOptions {
DevOptionADSBMAVLink = 1,
@@ -184,8 +79,7 @@ enum LoggingParameters {
// EKF failsafe definitions (FS_EKF_ACTION parameter)
#define FS_EKF_ACTION_LAND 1 // switch to LAND mode on EKF failsafe
-#define FS_EKF_ACTION_ALTHOLD 2 // switch to ALTHOLD mode on EKF failsafe
-#define FS_EKF_ACTION_LAND_EVEN_STABILIZE 3 // switch to Land mode on EKF failsafe even if in a manual flight mode like stabilize
+#define FS_EKF_ACTION_LAND_EVEN_MANUAL 3 // switch to Land mode on EKF failsafe even if in Manual mode
// for PILOT_THR_BHV parameter
#define THR_BEHAVE_FEEDBACK_FROM_MID_STICK (1<<0)
diff --git a/Blimp/ekf_check.cpp b/Blimp/ekf_check.cpp
index 8bc678922f0b5b..fd524b99ab91a5 100644
--- a/Blimp/ekf_check.cpp
+++ b/Blimp/ekf_check.cpp
@@ -148,16 +148,16 @@ void Blimp::failsafe_ekf_event()
AP::logger().Write_Error(LogErrorSubsystem::FAILSAFE_EKFINAV, LogErrorCode::FAILSAFE_OCCURRED);
// does this mode require position?
- if (!blimp.flightmode->requires_GPS() && (g.fs_ekf_action != FS_EKF_ACTION_LAND_EVEN_STABILIZE)) {
+ if (!blimp.flightmode->requires_GPS() && (g.fs_ekf_action != FS_EKF_ACTION_LAND_EVEN_MANUAL)) {
return;
}
// take action based on fs_ekf_action parameter
switch (g.fs_ekf_action) {
case FS_EKF_ACTION_LAND:
- case FS_EKF_ACTION_LAND_EVEN_STABILIZE:
+ case FS_EKF_ACTION_LAND_EVEN_MANUAL:
default:
- set_mode_land_with_pause(ModeReason::EKF_FAILSAFE);
+ set_mode_land_failsafe(ModeReason::EKF_FAILSAFE);
break;
}
}
diff --git a/Blimp/events.cpp b/Blimp/events.cpp
index cbd778cd6ca69f..452f624c5b879f 100644
--- a/Blimp/events.cpp
+++ b/Blimp/events.cpp
@@ -98,8 +98,8 @@ void Blimp::failsafe_gcs_check()
const uint32_t gcs_last_seen_ms = gcs().sysid_myggcs_last_seen_time_ms();
if (gcs_last_seen_ms == 0) {
- return;
- }
+ return;
+ }
// calc time since last gcs update
// note: this only looks at the heartbeat from the device id set by g.sysid_my_gcs
@@ -148,7 +148,7 @@ void Blimp::do_failsafe_action(Failsafe_Action action, ModeReason reason)
case Failsafe_Action_None:
return;
case Failsafe_Action_Land:
- set_mode_land_with_pause(reason);
+ set_mode_land_failsafe(reason);
break;
case Failsafe_Action_Terminate: {
arming.disarm(AP_Arming::Method::FAILSAFE_ACTION_TERMINATE);
diff --git a/Blimp/mode.cpp b/Blimp/mode.cpp
index 511ac6be5bbc84..b7d80bd906100f 100644
--- a/Blimp/mode.cpp
+++ b/Blimp/mode.cpp
@@ -16,9 +16,10 @@ Mode::Mode(void) :
inertial_nav(blimp.inertial_nav),
ahrs(blimp.ahrs),
motors(blimp.motors),
+ loiter(blimp.loiter),
channel_right(blimp.channel_right),
channel_front(blimp.channel_front),
- channel_down(blimp.channel_down),
+ channel_up(blimp.channel_up),
channel_yaw(blimp.channel_yaw),
G_Dt(blimp.G_Dt)
{ };
@@ -41,6 +42,9 @@ Mode *Blimp::mode_from_mode_num(const Mode::Number mode)
case Mode::Number::LOITER:
ret = &mode_loiter;
break;
+ case Mode::Number::RTL:
+ ret = &mode_rtl;
+ break;
default:
break;
}
@@ -136,7 +140,7 @@ void Blimp::update_flight_mode()
// exit_mode - high level call to organise cleanup as a flight mode is exited
void Blimp::exit_mode(Mode *&old_flightmode,
- Mode *&new_flightmode){}
+ Mode *&new_flightmode) {}
// notify_flight_mode - sets notify object based on current flight mode. Only used for OreoLED notify device
void Blimp::notify_flight_mode()
@@ -152,18 +156,23 @@ void Mode::update_navigation()
run_autopilot();
}
-// returns desired angle in centi-degrees
-void Mode::get_pilot_desired_accelerations(float &right_out, float &front_out) const
+// returns desired thrust/acceleration
+void Mode::get_pilot_input(Vector3f &pilot, float &yaw)
{
// throttle failsafe check
if (blimp.failsafe.radio || !blimp.ap.rc_receiver_present) {
- right_out = 0;
- front_out = 0;
+ pilot.y = 0;
+ pilot.x = 0;
+ pilot.z = 0;
+ yaw = 0;
return;
}
- // fetch roll and pitch inputs
- right_out = channel_right->get_control_in();
- front_out = channel_front->get_control_in();
+ // fetch pilot inputs
+ pilot.y = channel_right->get_control_in() / float(RC_SCALE);
+ pilot.x = channel_front->get_control_in() / float(RC_SCALE);
+ //TODO: need to make this channel_up instead, and then have it .negative. before being sent to pilot.z -> this is "throttle" channel, so higher = up.
+ pilot.z = -channel_up->get_control_in() / float(RC_SCALE);
+ yaw = channel_yaw->get_control_in() / float(RC_SCALE);
}
bool Mode::is_disarmed_or_landed() const
diff --git a/Blimp/mode.h b/Blimp/mode.h
index ed9e60353f0f7d..8a990fbb31b30c 100644
--- a/Blimp/mode.h
+++ b/Blimp/mode.h
@@ -17,6 +17,7 @@ class Mode
MANUAL = 1, // manual control
VELOCITY = 2, // velocity mode
LOITER = 3, // loiter mode (position hold)
+ RTL = 4, // rtl
};
// constructor
@@ -83,7 +84,7 @@ class Mode
void update_navigation();
// pilot input processing
- void get_pilot_desired_accelerations(float &right_out, float &front_out) const;
+ void get_pilot_input(Vector3f &pilot, float &yaw);
protected:
@@ -104,72 +105,14 @@ class Mode
AP_InertialNav &inertial_nav;
AP_AHRS &ahrs;
Fins *&motors;
+ Loiter *&loiter;
RC_Channel *&channel_right;
RC_Channel *&channel_front;
- RC_Channel *&channel_down;
+ RC_Channel *&channel_up;
RC_Channel *&channel_yaw;
float &G_Dt;
public:
- // Navigation Yaw control
- class AutoYaw
- {
-
- public:
- // mode(): current method of determining desired yaw:
- autopilot_yaw_mode mode() const
- {
- return (autopilot_yaw_mode)_mode;
- }
- void set_mode_to_default(bool rtl);
- void set_mode(autopilot_yaw_mode new_mode);
- autopilot_yaw_mode default_mode(bool rtl) const;
-
- void set_rate(float new_rate_cds);
-
- // set_roi(...): set a "look at" location:
- void set_roi(const Location &roi_location);
-
- void set_fixed_yaw(float angle_deg,
- float turn_rate_dps,
- int8_t direction,
- bool relative_angle);
-
- private:
-
- // yaw_cd(): main product of AutoYaw; the heading:
- float yaw_cd();
-
- // rate_cds(): desired yaw rate in centidegrees/second:
- float rate_cds();
-
- float look_ahead_yaw();
- float roi_yaw();
-
- // auto flight mode's yaw mode
- uint8_t _mode = AUTO_YAW_LOOK_AT_NEXT_WP;
-
- // Yaw will point at this location if mode is set to AUTO_YAW_ROI
- Vector3f roi;
-
- // bearing from current location to the ROI
- float _roi_yaw;
-
- // yaw used for YAW_FIXED yaw_mode
- int32_t _fixed_yaw;
-
- // Deg/s we should turn
- int16_t _fixed_yaw_slewrate;
-
- // heading when in yaw_look_ahead_yaw
- float _look_ahead_yaw;
-
- // used to reduce update rate to 100hz:
- uint8_t roi_yaw_counter;
-
- };
- static AutoYaw auto_yaw;
-
// pass-through functions to reduce code churn on conversion;
// these are candidates for moving into the Mode base
// class.
@@ -304,7 +247,6 @@ class ModeLoiter : public Mode
private:
Vector3f target_pos;
float target_yaw;
- float loop_period;
};
class ModeLand : public Mode
@@ -347,3 +289,43 @@ class ModeLand : public Mode
private:
};
+
+class ModeRTL : public Mode
+{
+
+public:
+ // inherit constructor
+ using Mode::Mode;
+
+ virtual bool init(bool ignore_checks) override;
+ virtual void run() override;
+
+ bool requires_GPS() const override
+ {
+ return true;
+ }
+ bool has_manual_throttle() const override
+ {
+ return false;
+ }
+ bool allows_arming(bool from_gcs) const override
+ {
+ return true;
+ };
+ bool is_autopilot() const override
+ {
+ return false;
+ //TODO
+ }
+
+protected:
+
+ const char *name() const override
+ {
+ return "RTL";
+ }
+ const char *name4() const override
+ {
+ return "RTL";
+ }
+};
diff --git a/Blimp/mode_land.cpp b/Blimp/mode_land.cpp
index f6e334839e1d04..640e69ef528df8 100644
--- a/Blimp/mode_land.cpp
+++ b/Blimp/mode_land.cpp
@@ -13,12 +13,11 @@ void ModeLand::run()
motors->down_out = 0;
}
-// set_mode_land_with_pause - sets mode to LAND and triggers 4 second delay before descent starts
-// this is always called from a failsafe so we trigger notification to pilot
-void Blimp::set_mode_land_with_pause(ModeReason reason)
+// set_mode_land_failsafe - sets mode to LAND
+// this is always called from a failsafe so we trigger notification to pilot
+void Blimp::set_mode_land_failsafe(ModeReason reason)
{
set_mode(Mode::Number::LAND, reason);
- //TODO: Add pause
// alert pilot to mode change
AP_Notify::events.failsafe_mode_change = 1;
diff --git a/Blimp/mode_loiter.cpp b/Blimp/mode_loiter.cpp
index 71e2794c2bbae3..725a702480815a 100644
--- a/Blimp/mode_loiter.cpp
+++ b/Blimp/mode_loiter.cpp
@@ -3,66 +3,47 @@
* Init and run calls for loiter flight mode
*/
+//Number of seconds of movement that the target position can be ahead of actual position.
+#define POS_LAG 1
- bool ModeLoiter::init(bool ignore_checks){
+bool ModeLoiter::init(bool ignore_checks)
+{
target_pos = blimp.pos_ned;
target_yaw = blimp.ahrs.get_yaw();
return true;
- }
+}
//Runs the main loiter controller
void ModeLoiter::run()
{
const float dt = blimp.scheduler.get_last_loop_time_s();
-
- Vector3f pilot;
- pilot.x = channel_front->get_control_in() / float(RC_SCALE) * g.max_pos_xy * dt;
- pilot.y = channel_right->get_control_in() / float(RC_SCALE) * g.max_pos_xy * dt;
- pilot.z = channel_down->get_control_in() / float(RC_SCALE) * g.max_pos_z * dt;
- float pilot_yaw = channel_yaw->get_control_in() / float(RC_SCALE) * g.max_pos_yaw * dt;
- if (g.simple_mode == 0){
+ Vector3f pilot;
+ float pilot_yaw;
+ get_pilot_input(pilot, pilot_yaw);
+ pilot.x *= g.max_pos_xy * dt;
+ pilot.y *= g.max_pos_xy * dt;
+ pilot.z *= g.max_pos_z * dt;
+ pilot_yaw *= g.max_pos_yaw * dt;
+
+ if (g.simple_mode == 0) {
//If simple mode is disabled, input is in body-frame, thus needs to be rotated.
blimp.rotate_BF_to_NE(pilot.xy());
}
- target_pos.x += pilot.x;
- target_pos.y += pilot.y;
- target_pos.z += pilot.z;
- target_yaw = wrap_PI(target_yaw + pilot_yaw);
-
- //Pos controller's output becomes target for velocity controller
- Vector3f target_vel_ef{blimp.pid_pos_xy.update_all(target_pos, blimp.pos_ned, dt, {0,0,0}), 0};
- target_vel_ef.z = blimp.pid_pos_z.update_all(target_pos.z, blimp.pos_ned.z, dt);
- float yaw_ef = blimp.ahrs.get_yaw();
- float target_vel_yaw = blimp.pid_pos_yaw.update_error(wrap_PI(target_yaw - yaw_ef), dt);
- blimp.pid_pos_yaw.set_target_rate(target_yaw);
- blimp.pid_pos_yaw.set_actual_rate(yaw_ef);
-
- Vector3f target_vel_ef_c{constrain_float(target_vel_ef.x, -g.max_vel_xy, g.max_vel_xy),
- constrain_float(target_vel_ef.y, -g.max_vel_xy, g.max_vel_xy),
- constrain_float(target_vel_ef.z, -g.max_vel_z, g.max_vel_z)};
- float target_vel_yaw_c = constrain_float(target_vel_yaw, -g.max_vel_yaw, g.max_vel_yaw);
-
- Vector2f actuator = blimp.pid_vel_xy.update_all(target_vel_ef_c, blimp.vel_ned_filtd, dt, {0,0,0});
- float act_down = blimp.pid_vel_z.update_all(target_vel_ef_c.z, blimp.vel_ned_filtd.z, dt);
- blimp.rotate_NE_to_BF(actuator);
- float act_yaw = blimp.pid_vel_yaw.update_all(target_vel_yaw_c, blimp.vel_yaw_filtd, dt);
- if(!(blimp.g.dis_mask & (1<<(2-1)))){
- motors->front_out = actuator.x;
+ if (fabsf(target_pos.x-blimp.pos_ned.x) < (g.max_pos_xy*POS_LAG)) {
+ target_pos.x += pilot.x;
}
- if(!(blimp.g.dis_mask & (1<<(1-1)))){
- motors->right_out = actuator.y;
+ if (fabsf(target_pos.y-blimp.pos_ned.y) < (g.max_pos_xy*POS_LAG)) {
+ target_pos.y += pilot.y;
}
- if(!(blimp.g.dis_mask & (1<<(3-1)))){
- motors->down_out = act_down;
+ if (fabsf(target_pos.z-blimp.pos_ned.z) < (g.max_pos_z*POS_LAG)) {
+ target_pos.z += pilot.z;
}
- if(!(blimp.g.dis_mask & (1<<(4-1)))){
- motors->yaw_out = act_yaw;
+ if (fabsf(wrap_PI(target_yaw-ahrs.get_yaw())) < (g.max_pos_yaw*POS_LAG)) {
+ target_yaw = wrap_PI(target_yaw + pilot_yaw);
}
- AP::logger().Write_PSCN(target_pos.x * 100.0, blimp.pos_ned.x * 100.0, 0.0, target_vel_ef_c.x * 100.0, blimp.vel_ned_filtd.x * 100.0, 0.0, 0.0, 0.0);
- AP::logger().Write_PSCE(target_pos.y * 100.0, blimp.pos_ned.y * 100.0, 0.0, target_vel_ef_c.y * 100.0, blimp.vel_ned_filtd.y * 100.0, 0.0, 0.0, 0.0);
- AP::logger().Write_PSCD(-target_pos.z * 100.0, -blimp.pos_ned.z * 100.0, 0.0, -target_vel_ef_c.z * 100.0, -blimp.vel_ned_filtd.z * 100.0, 0.0, 0.0, 0.0);
+ blimp.loiter->run(target_pos, target_yaw, Vector4b{false,false,false,false});
}
diff --git a/Blimp/mode_manual.cpp b/Blimp/mode_manual.cpp
index 1183b4bd7a1ad1..30a9eb7bbaffff 100644
--- a/Blimp/mode_manual.cpp
+++ b/Blimp/mode_manual.cpp
@@ -6,8 +6,11 @@
// Runs the main manual controller
void ModeManual::run()
{
- motors->right_out = channel_right->get_control_in() / float(RC_SCALE);
- motors->front_out = channel_front->get_control_in() / float(RC_SCALE);
- motors->yaw_out = channel_yaw->get_control_in() / float(RC_SCALE);
- motors->down_out = channel_down->get_control_in() / float(RC_SCALE);
+ Vector3f pilot;
+ float pilot_yaw;
+ get_pilot_input(pilot, pilot_yaw);
+ motors->right_out = pilot.y;
+ motors->front_out = pilot.x;
+ motors->yaw_out = pilot_yaw;
+ motors->down_out = pilot.z;
}
diff --git a/Blimp/mode_rtl.cpp b/Blimp/mode_rtl.cpp
new file mode 100644
index 00000000000000..c1b593cd9c9331
--- /dev/null
+++ b/Blimp/mode_rtl.cpp
@@ -0,0 +1,20 @@
+#include "Blimp.h"
+/*
+ * Init and run calls for rtl flight mode
+ */
+
+//Number of seconds of movement that the target position can be ahead of actual position.
+#define POS_LAG 1
+
+bool ModeRTL::init(bool ignore_checks)
+{
+ return true;
+}
+
+//Runs the main rtl controller
+void ModeRTL::run()
+{
+ Vector3f target_pos = {0,0,0};
+ float target_yaw = 0;
+ blimp.loiter->run(target_pos, target_yaw, Vector4b{false,false,false,false});
+}
diff --git a/Blimp/mode_velocity.cpp b/Blimp/mode_velocity.cpp
index a333d6cbc29440..ae6011c619fb48 100644
--- a/Blimp/mode_velocity.cpp
+++ b/Blimp/mode_velocity.cpp
@@ -8,34 +8,17 @@
// Runs the main velocity controller
void ModeVelocity::run()
{
- const float dt = blimp.scheduler.get_last_loop_time_s();
-
Vector3f target_vel;
- target_vel.x = channel_front->get_control_in() / float(RC_SCALE) * g.max_vel_xy;
- target_vel.y = channel_right->get_control_in() / float(RC_SCALE) * g.max_vel_xy;
- blimp.rotate_BF_to_NE(target_vel.xy());
- target_vel.z = channel_down->get_control_in() / float(RC_SCALE) * g.max_vel_z;
- float target_vel_yaw = channel_yaw->get_control_in() / float(RC_SCALE) * g.max_vel_yaw;
-
- Vector2f actuator = blimp.pid_vel_xy.update_all(target_vel, blimp.vel_ned_filtd, dt, {0,0,0});
- blimp.rotate_NE_to_BF(actuator);
- float act_down = blimp.pid_vel_z.update_all(target_vel.z, blimp.vel_ned_filtd.z, dt);
- float act_yaw = blimp.pid_vel_yaw.update_all(target_vel_yaw, blimp.vel_yaw_filtd, dt);
-
- if(!(blimp.g.dis_mask & (1<<(2-1)))){
- motors->front_out = actuator.x;
- }
- if(!(blimp.g.dis_mask & (1<<(1-1)))){
- motors->right_out = actuator.y;
- }
- if(!(blimp.g.dis_mask & (1<<(3-1)))){
- motors->down_out = act_down;
- }
- if(!(blimp.g.dis_mask & (1<<(4-1)))){
- motors->yaw_out = act_yaw;
+ float target_vel_yaw;
+ get_pilot_input(target_vel, target_vel_yaw);
+ target_vel.x *= g.max_vel_xy;
+ target_vel.y *= g.max_vel_xy;
+ if (g.simple_mode == 0) {
+ //If simple mode is disabled, input is in body-frame, thus needs to be rotated.
+ blimp.rotate_BF_to_NE(target_vel.xy());
}
+ target_vel.z *= g.max_vel_z;
+ target_vel_yaw *= g.max_vel_yaw;
- AP::logger().Write_PSCN(0.0, blimp.pos_ned.x * 100.0, 0.0, 0.0, blimp.vel_ned_filtd.x * 100.0, 0.0, 0.0, 0.0);
- AP::logger().Write_PSCE(0.0, blimp.pos_ned.y * 100.0, 0.0, 0.0, blimp.vel_ned_filtd.y * 100.0, 0.0, 0.0, 0.0);
- AP::logger().Write_PSCD(0.0, -blimp.pos_ned.z * 100.0, 0.0, 0.0, -blimp.vel_ned_filtd.z * 100.0, 0.0, 0.0, 0.0);
+ blimp.loiter->run_vel(target_vel, target_vel_yaw, Vector4b{false,false,false,false});
}
diff --git a/Blimp/motors.cpp b/Blimp/motors.cpp
index c2034774880f41..35ba08b90cce93 100644
--- a/Blimp/motors.cpp
+++ b/Blimp/motors.cpp
@@ -18,7 +18,7 @@ void Blimp::arm_motors_check()
}
// ensure throttle is down
- if (channel_down->get_control_in() > 0) { //MIR what dow we do with this?
+ if (channel_up->get_control_in() > 0) { //MIR what dow we do with this?
arming_counter = 0;
return;
}
diff --git a/Blimp/radio.cpp b/Blimp/radio.cpp
index e7640c44c2aa96..861c057820a5fc 100644
--- a/Blimp/radio.cpp
+++ b/Blimp/radio.cpp
@@ -8,23 +8,23 @@ void Blimp::default_dead_zones()
{
channel_right->set_default_dead_zone(20);
channel_front->set_default_dead_zone(20);
- channel_down->set_default_dead_zone(30);
+ channel_up->set_default_dead_zone(30);
channel_yaw->set_default_dead_zone(20);
rc().channel(CH_6)->set_default_dead_zone(0);
}
void Blimp::init_rc_in()
{
- channel_right = rc().channel(rcmap.roll()-1);
- channel_front = rc().channel(rcmap.pitch()-1);
- channel_down = rc().channel(rcmap.throttle()-1);
- channel_yaw = rc().channel(rcmap.yaw()-1);
+ channel_right = rc().channel(rcmap.roll()-1);
+ channel_front = rc().channel(rcmap.pitch()-1);
+ channel_up = rc().channel(rcmap.throttle()-1);
+ channel_yaw = rc().channel(rcmap.yaw()-1);
// set rc channel ranges
channel_right->set_angle(RC_SCALE);
channel_front->set_angle(RC_SCALE);
channel_yaw->set_angle(RC_SCALE);
- channel_down->set_angle(RC_SCALE);
+ channel_up->set_angle(RC_SCALE);
// set default dead zones
default_dead_zones();
@@ -58,14 +58,14 @@ void Blimp::read_radio()
if (rc().read_input()) {
ap.new_radio_frame = true;
- set_throttle_and_failsafe(channel_down->get_radio_in());
- set_throttle_zero_flag(channel_down->get_control_in());
+ set_throttle_and_failsafe(channel_up->get_radio_in());
+ set_throttle_zero_flag(channel_up->get_control_in());
// RC receiver must be attached if we've just got input
ap.rc_receiver_present = true;
const float dt = (tnow_ms - last_radio_update_ms)*1.0e-3f;
- rc_throttle_control_in_filter.apply(channel_down->get_control_in(), dt);
+ rc_throttle_control_in_filter.apply(channel_up->get_control_in(), dt);
last_radio_update_ms = tnow_ms;
return;
}
diff --git a/Blimp/system.cpp b/Blimp/system.cpp
index cec5103bb53aac..f3d8bdc08e69f1 100644
--- a/Blimp/system.cpp
+++ b/Blimp/system.cpp
@@ -46,6 +46,7 @@ void Blimp::init_ardupilot()
// allocate the motors class
allocate_motors();
+ loiter = new Loiter(blimp.scheduler.get_loop_rate_hz());
// initialise rc channels including setting mode
rc().convert_options(RC_Channel::AUX_FUNC::ARMDISARM_UNUSED, RC_Channel::AUX_FUNC::ARMDISARM);
@@ -58,7 +59,9 @@ void Blimp::init_ardupilot()
// motors initialised so parameters can be sent
ap.initialised_params = true;
+#if AP_RELAY_ENABLED
relay.init();
+#endif
/*
* setup the 'main loop is dead' check. Note that this relies on
@@ -87,11 +90,6 @@ void Blimp::init_ardupilot()
g2.scripting.init();
#endif // AP_SCRIPTING_ENABLED
- // we don't want writes to the serial port to cause us to pause
- // mid-flight, so set the serial ports non-blocking once we are
- // ready to fly
- serial_manager.set_blocking_writes_all(false);
-
ins.set_log_raw_bit(MASK_LOG_IMU_RAW);
// setup fin output
diff --git a/Blimp/version.h b/Blimp/version.h
index a922ff5c4c1e02..e5bfa27c87be87 100644
--- a/Blimp/version.h
+++ b/Blimp/version.h
@@ -6,14 +6,14 @@
#include "ap_version.h"
-#define THISFIRMWARE "Blimp V4.3.0-dev"
+#define THISFIRMWARE "Blimp V4.5.0-dev"
// the following line is parsed by the autotest scripts
-#define FIRMWARE_VERSION 4,3,0,FIRMWARE_VERSION_TYPE_DEV
+#define FIRMWARE_VERSION 4,5,0,FIRMWARE_VERSION_TYPE_DEV
#define FW_MAJOR 4
-#define FW_MINOR 3
+#define FW_MINOR 5
#define FW_PATCH 0
#define FW_TYPE FIRMWARE_VERSION_TYPE_DEV
-#include
\ No newline at end of file
+#include
diff --git a/Blimp/wscript b/Blimp/wscript
index a45b13a3137502..34cb8c170490e0 100644
--- a/Blimp/wscript
+++ b/Blimp/wscript
@@ -7,9 +7,7 @@ def build(bld):
name=vehicle + '_libs',
ap_vehicle=vehicle,
ap_libraries=bld.ap_common_vehicle_libraries() + [
- 'AC_AttitudeControl',
'AC_InputManager',
- 'AC_WPNav',
'AP_InertialNav',
'AP_RCMapper',
'AP_Avoidance',
@@ -27,5 +25,4 @@ def build(bld):
program_name='blimp',
program_groups=['bin', 'blimp'],
use=vehicle + '_libs',
- defines=['FRAME_CONFIG=MULTICOPTER_FRAME'],
)
diff --git a/Dockerfile b/Dockerfile
index f0be5d2aaa6090..495c843488054b 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,4 +1,6 @@
-FROM ubuntu:20.04
+ARG BASE_IMAGE="ubuntu"
+ARG TAG="22.04"
+FROM ${BASE_IMAGE}:${TAG}
WORKDIR /ardupilot
ARG DEBIAN_FRONTEND=noninteractive
diff --git a/README.md b/README.md
index 36994430d4fcbc..7b603fc1632425 100644
--- a/README.md
+++ b/README.md
@@ -77,7 +77,7 @@ It is continually being expanded to provide support for new emerging vehicle typ
The ArduPilot project is licensed under the GNU General Public
License, version 3.
-- [Overview of license](https://dev.ardupilot.com/wiki/license-gplv3)
+- [Overview of license](https://ardupilot.org/dev/docs/license-gplv3.html)
- [Full Text](https://github.com/ArduPilot/ardupilot/blob/master/COPYING.txt)
diff --git a/Rover/AP_Arming.cpp b/Rover/AP_Arming.cpp
index c952f7d9652b55..dc0f717d173e59 100644
--- a/Rover/AP_Arming.cpp
+++ b/Rover/AP_Arming.cpp
@@ -59,7 +59,7 @@ bool AP_Arming_Rover::gps_checks(bool display_failure)
return false;
}
- // ensure position esetimate is ok
+ // ensure position estimate is ok
if (!rover.ekf_position_ok()) {
// vehicle level position estimate checks
check_failed(display_failure, "Need Position Estimate");
@@ -78,7 +78,7 @@ bool AP_Arming_Rover::pre_arm_checks(bool report)
//are arming checks disabled?
if (checks_to_perform == 0) {
- return true;
+ return mandatory_checks(report);
}
if (rover.g2.sailboat.sail_enabled() && !rover.g2.windvane.enabled()) {
@@ -196,9 +196,6 @@ bool AP_Arming_Rover::mode_checks(bool report)
if (!rover.control_mode->allows_arming()) {
check_failed(report, "Mode not armable");
return false;
- } else if (rover.control_mode == &rover.mode_auto && rover.mode_auto.mission.num_commands() <= 1) {
- check_failed(report, "AUTO requires mission");
- return false;
}
return true;
}
diff --git a/Rover/AP_Rally.cpp b/Rover/AP_Rally.cpp
index 1a836159645eff..b0daf506f10856 100644
--- a/Rover/AP_Rally.cpp
+++ b/Rover/AP_Rally.cpp
@@ -13,11 +13,13 @@
along with this program. If not, see .
*/
-#include
+#include "AP_Rally.h"
+
+#if HAL_RALLY_ENABLED
#include "Rover.h"
-#include "AP_Rally.h"
+#include
bool AP_Rally_Rover::is_valid(const Location &rally_point) const
{
@@ -28,3 +30,5 @@ bool AP_Rally_Rover::is_valid(const Location &rally_point) const
#endif
return true;
}
+
+#endif // HAL_RALLY_ENABLED
diff --git a/Rover/AP_Rally.h b/Rover/AP_Rally.h
index 0055dcb1e5e93e..197d6c92797fff 100644
--- a/Rover/AP_Rally.h
+++ b/Rover/AP_Rally.h
@@ -15,7 +15,8 @@
#pragma once
#include
-#include
+
+#if HAL_RALLY_ENABLED
class AP_Rally_Rover : public AP_Rally
{
@@ -28,3 +29,5 @@ class AP_Rally_Rover : public AP_Rally
private:
bool is_valid(const Location &rally_point) const override;
};
+
+#endif // HAL_RALLY_ENABLED
diff --git a/Rover/GCS_Mavlink.cpp b/Rover/GCS_Mavlink.cpp
index 92d17426514e46..dc419cfcd39095 100644
--- a/Rover/GCS_Mavlink.cpp
+++ b/Rover/GCS_Mavlink.cpp
@@ -398,8 +398,10 @@ bool GCS_MAVLINK_Rover::try_send_message(enum ap_message id)
void GCS_MAVLINK_Rover::packetReceived(const mavlink_status_t &status, const mavlink_message_t &msg)
{
+#if AP_FOLLOW_ENABLED
// pass message to follow library
rover.g2.follow.handle_msg(msg);
+#endif
GCS_MAVLINK::packetReceived(status, msg);
}
@@ -635,7 +637,7 @@ bool GCS_MAVLINK_Rover::set_home(const Location& loc, bool _lock) {
return rover.set_home(loc, _lock);
}
-MAV_RESULT GCS_MAVLINK_Rover::handle_command_int_packet(const mavlink_command_int_t &packet)
+MAV_RESULT GCS_MAVLINK_Rover::handle_command_int_packet(const mavlink_command_int_t &packet, const mavlink_message_t &msg)
{
switch (packet.command) {
@@ -655,40 +657,27 @@ MAV_RESULT GCS_MAVLINK_Rover::handle_command_int_packet(const mavlink_command_in
rover.control_mode->set_reversed(is_equal(packet.param1,1.0f));
return MAV_RESULT_ACCEPTED;
+ case MAV_CMD_NAV_RETURN_TO_LAUNCH:
+ if (rover.set_mode(rover.mode_rtl, ModeReason::GCS_COMMAND)) {
+ return MAV_RESULT_ACCEPTED;
+ }
+ return MAV_RESULT_FAILED;
+
default:
- return GCS_MAVLINK::handle_command_int_packet(packet);
+ return GCS_MAVLINK::handle_command_int_packet(packet, msg);
}
}
-MAV_RESULT GCS_MAVLINK_Rover::handle_command_long_packet(const mavlink_command_long_t &packet)
+MAV_RESULT GCS_MAVLINK_Rover::handle_command_long_packet(const mavlink_command_long_t &packet, const mavlink_message_t &msg)
{
switch (packet.command) {
- case MAV_CMD_NAV_RETURN_TO_LAUNCH:
- if (rover.set_mode(rover.mode_rtl, ModeReason::GCS_COMMAND)) {
- return MAV_RESULT_ACCEPTED;
- }
- return MAV_RESULT_FAILED;
-
case MAV_CMD_MISSION_START:
if (rover.set_mode(rover.mode_auto, ModeReason::GCS_COMMAND)) {
return MAV_RESULT_ACCEPTED;
}
return MAV_RESULT_FAILED;
- case MAV_CMD_DO_CHANGE_SPEED:
- // param1 : unused
- // param2 : new speed in m/s
- if (!rover.control_mode->set_desired_speed(packet.param2)) {
- return MAV_RESULT_FAILED;
- }
- return MAV_RESULT_ACCEPTED;
-
- case MAV_CMD_DO_SET_REVERSE:
- // param1 : Direction (0=Forward, 1=Reverse)
- rover.control_mode->set_reversed(is_equal(packet.param1,1.0f));
- return MAV_RESULT_ACCEPTED;
-
case MAV_CMD_NAV_SET_YAW_SPEED:
{
// param1 : yaw angle to adjust direction by in centidegress
@@ -723,7 +712,7 @@ MAV_RESULT GCS_MAVLINK_Rover::handle_command_long_packet(const mavlink_command_l
packet.param4);
default:
- return GCS_MAVLINK::handle_command_long_packet(packet);
+ return GCS_MAVLINK::handle_command_long_packet(packet, msg);
}
}
diff --git a/Rover/GCS_Mavlink.h b/Rover/GCS_Mavlink.h
index 028c92f497a6b4..3e7ccacc31327e 100644
--- a/Rover/GCS_Mavlink.h
+++ b/Rover/GCS_Mavlink.h
@@ -16,8 +16,8 @@ class GCS_MAVLINK_Rover : public GCS_MAVLINK
bool sysid_enforce() const override;
MAV_RESULT _handle_command_preflight_calibration(const mavlink_command_long_t &packet, const mavlink_message_t &msg) override;
- MAV_RESULT handle_command_int_packet(const mavlink_command_int_t &packet) override;
- MAV_RESULT handle_command_long_packet(const mavlink_command_long_t &packet) override;
+ MAV_RESULT handle_command_int_packet(const mavlink_command_int_t &packet, const mavlink_message_t &msg) override;
+ MAV_RESULT handle_command_long_packet(const mavlink_command_long_t &packet, const mavlink_message_t &msg) override;
MAV_RESULT handle_command_int_do_reposition(const mavlink_command_int_t &packet);
void send_position_target_global_int() override;
diff --git a/Rover/Parameters.cpp b/Rover/Parameters.cpp
index 792e50153461d6..24783eb2a33e7b 100644
--- a/Rover/Parameters.cpp
+++ b/Rover/Parameters.cpp
@@ -27,7 +27,7 @@ const AP_Param::Info Rover::var_info[] = {
// @Param: INITIAL_MODE
// @DisplayName: Initial driving mode
// @Description: This selects the mode to start in on boot. This is useful for when you want to start in AUTO mode on boot without a receiver. Usually used in combination with when AUTO_TRIGGER_PIN or AUTO_KICKSTART.
- // @Values: 0:Manual,1:Acro,3:Steering,4:Hold,5:Loiter,6:Follow,7:Simple,10:Auto,11:RTL,12:SmartRTL,15:Guided
+ // @CopyValuesFrom: MODE1
// @User: Advanced
GSCALAR(initial_mode, "INITIAL_MODE", Mode::Number::MANUAL),
@@ -171,7 +171,7 @@ const AP_Param::Info Rover::var_info[] = {
// @Param: MODE1
// @DisplayName: Mode1
- // @Values: 0:Manual,1:Acro,3:Steering,4:Hold,5:Loiter,6:Follow,7:Simple,10:Auto,11:RTL,12:SmartRTL,15:Guided
+ // @Values: 0:Manual,1:Acro,3:Steering,4:Hold,5:Loiter,6:Follow,7:Simple,8:Dock,9:Circle,10:Auto,11:RTL,12:SmartRTL,15:Guided
// @User: Standard
// @Description: Driving mode for switch position 1 (910 to 1230 and above 2049)
GSCALAR(mode1, "MODE1", Mode::Number::MANUAL),
@@ -221,9 +221,11 @@ const AP_Param::Info Rover::var_info[] = {
// @Path: ../libraries/AP_Baro/AP_Baro.cpp
GOBJECT(barometer, "BARO", AP_Baro),
+#if AP_RELAY_ENABLED
// @Group: RELAY_
// @Path: ../libraries/AP_Relay/AP_Relay.cpp
GOBJECT(relay, "RELAY_", AP_Relay),
+#endif
// @Group: RCMAP_
// @Path: ../libraries/AP_RCMapper/AP_RCMapper.cpp
@@ -515,9 +517,11 @@ const AP_Param::GroupInfo ParametersG2::var_info[] = {
// @User: Standard
AP_GROUPINFO("CRASH_ANGLE", 22, ParametersG2, crash_angle, 0),
+#if AP_FOLLOW_ENABLED
// @Group: FOLL
// @Path: ../libraries/AP_Follow/AP_Follow.cpp
AP_SUBGROUPINFO(follow, "FOLL", 23, ParametersG2, AP_Follow),
+#endif
// @Param: FRAME_TYPE
// @DisplayName: Frame Type
@@ -544,7 +548,7 @@ const AP_Param::GroupInfo ParametersG2::var_info[] = {
// @Path: ../libraries/AP_WheelEncoder/AP_WheelRateControl.cpp
AP_SUBGROUPINFO(wheel_rate_control, "WRC", 27, ParametersG2, AP_WheelRateControl),
-#if AP_RALLY == ENABLED
+#if HAL_RALLY_ENABLED
// @Group: RALLY_
// @Path: AP_Rally.cpp,../libraries/AP_Rally/AP_Rally.cpp
AP_SUBGROUPINFO(rally, "RALLY_", 28, ParametersG2, AP_Rally_Rover),
@@ -694,6 +698,10 @@ const AP_Param::GroupInfo ParametersG2::var_info[] = {
// @User: Standard
AP_GROUPINFO("FS_GCS_TIMEOUT", 56, ParametersG2, fs_gcs_timeout, 5),
+ // @Group: CIRC
+ // @Path: mode_circle.cpp
+ AP_SUBGROUPINFO(mode_circle, "CIRC", 57, ParametersG2, ModeCircle),
+
AP_GROUPEND
};
@@ -735,7 +743,7 @@ ParametersG2::ParametersG2(void)
#if AP_BEACON_ENABLED
beacon(),
#endif
- motors(rover.ServoRelayEvents, wheel_rate_control),
+ motors(wheel_rate_control),
wheel_rate_control(wheel_encoder),
attitude_control(),
smart_rtl(),
@@ -746,7 +754,9 @@ ParametersG2::ParametersG2(void)
proximity(),
#endif
avoid(),
+#if AP_FOLLOW_ENABLED
follow(),
+#endif
windvane(),
pos_control(attitude_control),
wp_nav(attitude_control, pos_control),
diff --git a/Rover/Parameters.h b/Rover/Parameters.h
index 3c3040ce5304bb..035d16f4d0ffb4 100644
--- a/Rover/Parameters.h
+++ b/Rover/Parameters.h
@@ -316,13 +316,13 @@ class ParametersG2 {
AP_Beacon beacon;
#endif
- // Motor library
- AP_MotorsUGV motors;
-
// wheel encoders
AP_WheelEncoder wheel_encoder;
AP_WheelRateControl wheel_rate_control;
+ // Motor library
+ AP_MotorsUGV motors;
+
// steering and throttle controller
AR_AttitudeControl attitude_control;
@@ -360,8 +360,10 @@ class ParametersG2 {
// pitch/roll angle for crash check
AP_Int8 crash_angle;
+#if AP_FOLLOW_ENABLED
// follow mode library
AP_Follow follow;
+#endif
// frame type for vehicle (used for vectored motor vehicles and custom motor configs)
AP_Int8 frame_type;
@@ -379,8 +381,10 @@ class ParametersG2 {
AP_Gripper gripper;
#endif
+#if HAL_RALLY_ENABLED
// Rally point library
AP_Rally_Rover rally;
+#endif
// Simple mode types
AP_Int8 simple_type;
@@ -438,6 +442,8 @@ class ParametersG2 {
// FS GCS timeout trigger time
AP_Float fs_gcs_timeout;
+
+ class ModeCircle mode_circle;
};
extern const AP_Param::Info var_info[];
diff --git a/Rover/RC_Channel.cpp b/Rover/RC_Channel.cpp
index e83a9fd0d011a2..e799f38a70fd24 100644
--- a/Rover/RC_Channel.cpp
+++ b/Rover/RC_Channel.cpp
@@ -62,9 +62,14 @@ void RC_Channel_Rover::init_aux_function(const aux_func_t ch_option, const AuxSw
}
+bool RC_Channels_Rover::in_rc_failsafe() const
+{
+ return rover.failsafe.bits & FAILSAFE_EVENT_THROTTLE;
+}
+
bool RC_Channels_Rover::has_valid_input() const
{
- if (rover.failsafe.bits & FAILSAFE_EVENT_THROTTLE) {
+ if (in_rc_failsafe()) {
return false;
}
return true;
@@ -209,10 +214,12 @@ bool RC_Channel_Rover::do_aux_function(const aux_func_t ch_option, const AuxSwit
do_aux_function_change_mode(rover.mode_loiter, ch_flag);
break;
+#if MODE_FOLLOW_ENABLED == ENABLED
// Set mode to Follow
case AUX_FUNC::FOLLOW:
do_aux_function_change_mode(rover.mode_follow, ch_flag);
break;
+#endif
// set mode to Simple
case AUX_FUNC::SIMPLE:
diff --git a/Rover/RC_Channel.h b/Rover/RC_Channel.h
index 844b4c1b9069d4..d25d714aa261cd 100644
--- a/Rover/RC_Channel.h
+++ b/Rover/RC_Channel.h
@@ -32,6 +32,7 @@ class RC_Channels_Rover : public RC_Channels
public:
+ bool in_rc_failsafe() const override;
bool has_valid_input() const override;
RC_Channel *get_arming_channel(void) const override;
diff --git a/Rover/Rover.cpp b/Rover/Rover.cpp
index 2ef70f1c9e9868..4b6497382b48dd 100644
--- a/Rover/Rover.cpp
+++ b/Rover/Rover.cpp
@@ -96,7 +96,9 @@ const AP_Scheduler::Task Rover::scheduler_tasks[] = {
SCHED_TASK_CLASS(RC_Channels, (RC_Channels*)&rover.g2.rc_channels, read_mode_switch, 7, 200, 57),
SCHED_TASK_CLASS(RC_Channels, (RC_Channels*)&rover.g2.rc_channels, read_aux_all, 10, 200, 60),
SCHED_TASK_CLASS(AP_BattMonitor, &rover.battery, read, 10, 300, 63),
+#if AP_SERVORELAYEVENTS_ENABLED
SCHED_TASK_CLASS(AP_ServoRelayEvents, &rover.ServoRelayEvents, update_events, 50, 200, 66),
+#endif
#if AP_GRIPPER_ENABLED
SCHED_TASK_CLASS(AP_Gripper, &rover.g2.gripper, update, 10, 75, 69),
#endif
@@ -116,7 +118,6 @@ const AP_Scheduler::Task Rover::scheduler_tasks[] = {
SCHED_TASK(fence_check, 10, 200, 84),
SCHED_TASK(ekf_check, 10, 100, 87),
SCHED_TASK_CLASS(ModeSmartRTL, &rover.mode_smartrtl, save_position, 3, 200, 90),
- SCHED_TASK_CLASS(AP_Notify, &rover.notify, update, 50, 300, 93),
SCHED_TASK(one_second_loop, 1, 1500, 96),
#if HAL_SPRAYER_ENABLED
SCHED_TASK_CLASS(AC_Sprayer, &rover.g2.sprayer, update, 3, 90, 99),
@@ -206,6 +207,14 @@ bool Rover::set_steering_and_throttle(float steering, float throttle)
return true;
}
+// get steering and throttle (-1 to +1) (for use by scripting)
+bool Rover::get_steering_and_throttle(float& steering, float& throttle)
+{
+ steering = g2.motors.get_steering() / 4500.0;
+ throttle = g2.motors.get_throttle() * 0.01;
+ return true;
+}
+
// set desired turn rate (degrees/sec) and speed (m/s). Used for scripting
bool Rover::set_desired_turn_rate_and_speed(float turn_rate, float speed)
{
@@ -420,6 +429,11 @@ void Rover::update_logging2(void)
gyro_fft.write_log_messages();
#endif
}
+#if HAL_MOUNT_ENABLED
+ if (should_log(MASK_LOG_CAMERA)) {
+ camera_mount.write_log();
+ }
+#endif
}
diff --git a/Rover/Rover.h b/Rover/Rover.h
index f11bae3d600f9d..fd22073c5bbbdb 100644
--- a/Rover/Rover.h
+++ b/Rover/Rover.h
@@ -43,6 +43,11 @@
#include
#include
#include
+#include
+#include
+#if AP_EXTERNAL_CONTROL_ENABLED
+#include
+#endif
// Configuration
#include "defines.h"
@@ -83,6 +88,7 @@ class Rover : public AP_Vehicle {
friend class Mode;
friend class ModeAcro;
friend class ModeAuto;
+ friend class ModeCircle;
friend class ModeGuided;
friend class ModeHold;
friend class ModeLoiter;
@@ -90,7 +96,9 @@ class Rover : public AP_Vehicle {
friend class ModeManual;
friend class ModeRTL;
friend class ModeSmartRTL;
+#if MODE_FOLLOW_ENABLED == ENABLED
friend class ModeFollow;
+#endif
friend class ModeSimple;
#if MODE_DOCK_ENABLED == ENABLED
friend class ModeDock;
@@ -139,6 +147,11 @@ class Rover : public AP_Vehicle {
// Arming/Disarming management class
AP_Arming_Rover arming;
+ // dummy external control implementation
+#if AP_EXTERNAL_CONTROL_ENABLED
+ AP_ExternalControl external_control;
+#endif
+
#if AP_OPTICALFLOW_ENABLED
AP_OpticalFlow optflow;
#endif
@@ -235,7 +248,9 @@ class Rover : public AP_Vehicle {
ModeSteering mode_steering;
ModeRTL mode_rtl;
ModeSmartRTL mode_smartrtl;
+#if MODE_FOLLOW_ENABLED == ENABLED
ModeFollow mode_follow;
+#endif
ModeSimple mode_simple;
#if MODE_DOCK_ENABLED == ENABLED
ModeDock mode_dock;
@@ -257,6 +272,7 @@ class Rover : public AP_Vehicle {
bool set_target_location(const Location& target_loc) override;
bool set_target_velocity_NED(const Vector3f& vel_ned) override;
bool set_steering_and_throttle(float steering, float throttle) override;
+ bool get_steering_and_throttle(float& steering, float& throttle) override;
// set desired turn rate (degrees/sec) and speed (m/s). Used for scripting
bool set_desired_turn_rate_and_speed(float turn_rate, float speed) override;
bool set_desired_speed(float speed) override;
@@ -359,9 +375,14 @@ class Rover : public AP_Vehicle {
void init_ardupilot() override;
void startup_ground(void);
void update_ahrs_flyforward();
+ bool gcs_mode_enabled(const Mode::Number mode_num) const;
bool set_mode(Mode &new_mode, ModeReason reason);
bool set_mode(const uint8_t new_mode, ModeReason reason) override;
uint8_t get_mode() const override { return (uint8_t)control_mode->mode_number(); }
+ bool current_mode_requires_mission() const override {
+ return control_mode == &mode_auto;
+ }
+
void startup_INS_ground(void);
void notify_mode(const Mode *new_mode);
uint8_t check_digital_pin(uint8_t pin);
diff --git a/Rover/config.h b/Rover/config.h
index 77b2981c5fbcc5..7a280e88f3497a 100644
--- a/Rover/config.h
+++ b/Rover/config.h
@@ -31,13 +31,6 @@
#error XXX
#endif
-//////////////////////////////////////////////////////////////////////////////
-// RALLY POINTS
-//
-#ifndef AP_RALLY
- #define AP_RALLY ENABLED
-#endif
-
//////////////////////////////////////////////////////////////////////////////
// NAVL1
//
@@ -67,6 +60,12 @@
# define MODE_DOCK_ENABLED AC_PRECLAND_ENABLED
#endif
+//////////////////////////////////////////////////////////////////////////////
+// Follow mode - allows vehicle to follow target
+#ifndef MODE_FOLLOW_ENABLED
+# define MODE_FOLLOW_ENABLED AP_FOLLOW_ENABLED
+#endif
+
//////////////////////////////////////////////////////////////////////////////
// Developer Items
diff --git a/Rover/mode.cpp b/Rover/mode.cpp
index 1509b724367388..842789c1006698 100644
--- a/Rover/mode.cpp
+++ b/Rover/mode.cpp
@@ -531,12 +531,17 @@ Mode *Rover::mode_from_mode_num(const enum Mode::Number num)
case Mode::Number::LOITER:
ret = &mode_loiter;
break;
+#if MODE_FOLLOW_ENABLED == ENABLED
case Mode::Number::FOLLOW:
ret = &mode_follow;
break;
+#endif
case Mode::Number::SIMPLE:
ret = &mode_simple;
break;
+ case Mode::Number::CIRCLE:
+ ret = &g2.mode_circle;
+ break;
case Mode::Number::AUTO:
ret = &mode_auto;
break;
diff --git a/Rover/mode.h b/Rover/mode.h
index 761602b6ff501e..2ae7a90b2463d3 100644
--- a/Rover/mode.h
+++ b/Rover/mode.h
@@ -22,6 +22,7 @@ class Mode
#if MODE_DOCK_ENABLED == ENABLED
DOCK = 8,
#endif
+ CIRCLE = 9,
AUTO = 10,
RTL = 11,
SMART_RTL = 12,
@@ -252,6 +253,12 @@ class ModeAuto : public Mode
// return if external control is allowed in this mode (Guided or Guided-within-Auto)
bool in_guided_mode() const override { return _submode == Auto_Guided || _submode == Auto_NavScriptTime; }
+ // return heading (in degrees) and cross track error (in meters) for reporting to ground station (NAV_CONTROLLER_OUTPUT message)
+ float wp_bearing() const override;
+ float nav_bearing() const override;
+ float crosstrack_error() const override;
+ float get_desired_lat_accel() const override;
+
// return distance (in meters) to destination
float get_distance_to_destination() const override;
@@ -295,6 +302,7 @@ class ModeAuto : public Mode
Auto_Guided, // handover control to external navigation system from within auto mode
Auto_Stop, // stop the vehicle as quickly as possible
Auto_NavScriptTime, // accept targets from lua scripts while NAV_SCRIPT_TIME commands are executing
+ Auto_Circle, // circle a given location
} _submode;
private:
@@ -322,6 +330,8 @@ class ModeAuto : public Mode
bool verify_loiter_time(const AP_Mission::Mission_Command& cmd);
bool verify_nav_guided_enable(const AP_Mission::Mission_Command& cmd);
bool verify_nav_set_yaw_speed();
+ bool do_circle(const AP_Mission::Mission_Command& cmd);
+ bool verify_circle(const AP_Mission::Mission_Command& cmd);
void do_wait_delay(const AP_Mission::Mission_Command& cmd);
void do_within_distance(const AP_Mission::Mission_Command& cmd);
bool verify_wait_delay();
@@ -385,6 +395,95 @@ class ModeAuto : public Mode
AP_Mission_ChangeDetector mis_change_detector;
};
+class ModeCircle : public Mode
+{
+public:
+
+ // need a constructor for parameters
+ ModeCircle();
+
+ // Does not allow copies
+ CLASS_NO_COPY(ModeCircle);
+
+ uint32_t mode_number() const override { return CIRCLE; }
+ const char *name4() const override { return "CIRC"; }
+
+ // initialise with specific center location, radius (in meters) and direction
+ // replaces use of _enter when initialised from within Auto mode
+ bool set_center(const Location& center_loc, float radius_m, bool dir_ccw);
+
+ // methods that affect movement of the vehicle in this mode
+ void update() override;
+
+ bool is_autopilot_mode() const override { return true; }
+
+ // return desired heading (in degrees) and cross track error (in meters) for reporting to ground station (NAV_CONTROLLER_OUTPUT message)
+ float wp_bearing() const override;
+ float nav_bearing() const override;
+ float crosstrack_error() const override { return dist_to_edge_m; }
+ float get_desired_lat_accel() const override;
+
+ // set desired speed in m/s
+ bool set_desired_speed(float speed_ms) override;
+
+ // return distance (in meters) to destination
+ float get_distance_to_destination() const override { return _distance_to_destination; }
+
+ // get or set desired location
+ bool get_desired_location(Location& destination) const override WARN_IF_UNUSED;
+
+ // return total angle in radians that vehicle has circled
+ // fabsf is used so that full rotations in either direction are counted
+ float get_angle_total_rad() const { return fabsf(angle_total_rad); }
+
+ static const struct AP_Param::GroupInfo var_info[];
+
+protected:
+
+ AP_Float radius; // circle radius in meters
+ AP_Float speed; // vehicle speed in m/s. If zero uses WP_SPEED
+ AP_Int8 direction; // direction 0:clockwise, 1:counter-clockwise
+
+ // initialise mode
+ bool _enter() override;
+
+ // initialise target_yaw_rad using the vehicle's position and yaw
+ // if there is no current position estimate target_yaw_rad is set to vehicle yaw
+ void init_target_yaw_rad();
+
+ // limit config speed so that lateral acceleration is within limits
+ // outputs warning to user if speed is reduced
+ void check_config_speed();
+
+ // ensure config radius is no smaller then vehicle's TURN_RADIUS
+ // radius is increased if necessary and warning is output to the user
+ void check_config_radius();
+
+ // enum for Direction parameter
+ enum class Direction {
+ CW = 0,
+ CCW = 1
+ };
+
+ // local members
+ struct {
+ Location center_loc; // circle center as a Location
+ Vector2f center_pos; // circle center as an offset (in meters) from the EKF origin
+ float radius; // circle radius
+ float speed; // desired speed around circle in m/s
+ Direction dir; // direction, 0:clockwise, 1:counter-clockwise
+ } config;
+ struct {
+ float speed; // vehicle's target speed around circle in m/s
+ float yaw_rad; // earth-frame angle of tarrget point on the circle
+ Vector2p pos; // latest position target sent to position controller
+ Vector2f vel; // latest velocity target sent to position controller
+ Vector2f accel; // latest accel target sent to position controller
+ } target;
+ float angle_total_rad; // total angle in radians that vehicle has circled
+ bool reached_edge; // true once vehicle has reached edge of circle
+ float dist_to_edge_m; // distance to edge of circle in meters (equivalent to crosstrack error)
+};
class ModeGuided : public Mode
{
@@ -690,6 +789,7 @@ class ModeInitializing : public Mode
bool _enter() override { return false; };
};
+#if MODE_FOLLOW_ENABLED == ENABLED
class ModeFollow : public Mode
{
public:
@@ -724,6 +824,7 @@ class ModeFollow : public Mode
float _desired_speed; // desired speed in m/s
};
+#endif
class ModeSimple : public Mode
{
diff --git a/Rover/mode_auto.cpp b/Rover/mode_auto.cpp
index b7cf77163cf0b0..5be1d1eba0a7c1 100644
--- a/Rover/mode_auto.cpp
+++ b/Rover/mode_auto.cpp
@@ -145,6 +145,10 @@ void ModeAuto::update()
case Auto_NavScriptTime:
rover.mode_guided.update();
break;
+
+ case Auto_Circle:
+ rover.g2.mode_circle.update();
+ break;
}
}
@@ -158,6 +162,102 @@ void ModeAuto::calc_throttle(float target_speed, bool avoidance_enabled)
Mode::calc_throttle(target_speed, avoidance_enabled);
}
+// return heading (in degrees) to target destination (aka waypoint)
+float ModeAuto::wp_bearing() const
+{
+ switch (_submode) {
+ case Auto_WP:
+ return g2.wp_nav.wp_bearing_cd() * 0.01f;
+ case Auto_HeadingAndSpeed:
+ case Auto_Stop:
+ return 0.0f;
+ case Auto_RTL:
+ return rover.mode_rtl.wp_bearing();
+ case Auto_Loiter:
+ return rover.mode_loiter.wp_bearing();
+ case Auto_Guided:
+ case Auto_NavScriptTime:
+ return rover.mode_guided.wp_bearing();
+ case Auto_Circle:
+ return rover.g2.mode_circle.wp_bearing();
+ }
+
+ // this line should never be reached
+ return 0.0f;
+}
+
+// return short-term target heading in degrees (i.e. target heading back to line between waypoints)
+float ModeAuto::nav_bearing() const
+{
+ switch (_submode) {
+ case Auto_WP:
+ return g2.wp_nav.nav_bearing_cd() * 0.01f;
+ case Auto_HeadingAndSpeed:
+ case Auto_Stop:
+ return 0.0f;
+ case Auto_RTL:
+ return rover.mode_rtl.nav_bearing();
+ case Auto_Loiter:
+ return rover.mode_loiter.nav_bearing();
+ case Auto_Guided:
+ case Auto_NavScriptTime:
+ return rover.mode_guided.nav_bearing();
+ case Auto_Circle:
+ return rover.g2.mode_circle.nav_bearing();
+ }
+
+ // this line should never be reached
+ return 0.0f;
+}
+
+// return cross track error (i.e. vehicle's distance from the line between waypoints)
+float ModeAuto::crosstrack_error() const
+{
+ switch (_submode) {
+ case Auto_WP:
+ return g2.wp_nav.crosstrack_error();
+ case Auto_HeadingAndSpeed:
+ case Auto_Stop:
+ return 0.0f;
+ case Auto_RTL:
+ return rover.mode_rtl.crosstrack_error();
+ case Auto_Loiter:
+ return rover.mode_loiter.crosstrack_error();
+ case Auto_Guided:
+ case Auto_NavScriptTime:
+ return rover.mode_guided.crosstrack_error();
+ case Auto_Circle:
+ return rover.g2.mode_circle.crosstrack_error();
+ }
+
+ // this line should never be reached
+ return 0.0f;
+}
+
+// return desired lateral acceleration
+float ModeAuto::get_desired_lat_accel() const
+{
+ switch (_submode) {
+ case Auto_WP:
+ return g2.wp_nav.get_lat_accel();
+ case Auto_HeadingAndSpeed:
+ case Auto_Stop:
+ return 0.0f;
+ case Auto_RTL:
+ return rover.mode_rtl.get_desired_lat_accel();
+ case Auto_Loiter:
+ return rover.mode_loiter.get_desired_lat_accel();
+ case Auto_Guided:
+ case Auto_NavScriptTime:
+ return rover.mode_guided.get_desired_lat_accel();
+ case Auto_Circle:
+ return rover.g2.mode_circle.get_desired_lat_accel();
+ }
+
+ // this line should never be reached
+ return 0.0f;
+}
+
// return distance (in meters) to destination
float ModeAuto::get_distance_to_destination() const
{
@@ -175,6 +275,8 @@ float ModeAuto::get_distance_to_destination() const
case Auto_Guided:
case Auto_NavScriptTime:
return rover.mode_guided.get_distance_to_destination();
+ case Auto_Circle:
+ return rover.g2.mode_circle.get_distance_to_destination();
}
// this line should never be reached
@@ -201,7 +303,9 @@ bool ModeAuto::get_desired_location(Location& destination) const
return rover.mode_loiter.get_desired_location(destination);
case Auto_Guided:
case Auto_NavScriptTime:
- return rover.mode_guided.get_desired_location(destination);\
+ return rover.mode_guided.get_desired_location(destination);
+ case Auto_Circle:
+ return rover.g2.mode_circle.get_desired_location(destination);
}
// we should never reach here but just in case
@@ -242,7 +346,8 @@ bool ModeAuto::reached_destination() const
case Auto_Guided:
case Auto_NavScriptTime:
return rover.mode_guided.reached_destination();
- break;
+ case Auto_Circle:
+ return rover.g2.mode_circle.reached_destination();
}
// we should never reach here but just in case, return true to allow missions to continue
@@ -266,6 +371,8 @@ bool ModeAuto::set_desired_speed(float speed)
case Auto_Guided:
case Auto_NavScriptTime:
return rover.mode_guided.set_desired_speed(speed);
+ case Auto_Circle:
+ return rover.g2.mode_circle.set_desired_speed(speed);
}
return false;
}
@@ -428,6 +535,9 @@ bool ModeAuto::start_command(const AP_Mission::Mission_Command& cmd)
case MAV_CMD_NAV_LOITER_TIME: // Loiter for specified time
return do_nav_wp(cmd, true);
+ case MAV_CMD_NAV_LOITER_TURNS:
+ return do_circle(cmd);
+
case MAV_CMD_NAV_GUIDED_ENABLE: // accept navigation commands from external nav computer
do_nav_guided_enable(cmd);
break;
@@ -570,6 +680,9 @@ bool ModeAuto::verify_command(const AP_Mission::Mission_Command& cmd)
case MAV_CMD_NAV_LOITER_UNLIM:
return verify_loiter_unlimited(cmd);
+ case MAV_CMD_NAV_LOITER_TURNS:
+ return verify_circle(cmd);
+
case MAV_CMD_NAV_LOITER_TIME:
return verify_loiter_time(cmd);
@@ -808,6 +921,34 @@ bool ModeAuto::verify_nav_set_yaw_speed()
return true;
}
+bool ModeAuto::do_circle(const AP_Mission::Mission_Command& cmd)
+{
+ // retrieve and sanitize target location
+ Location circle_center = cmd.content.location;
+ circle_center.sanitize(rover.current_loc);
+
+ // calculate radius
+ uint16_t circle_radius_m = HIGHBYTE(cmd.p1); // circle radius held in high byte of p1
+ if (cmd.id == MAV_CMD_NAV_LOITER_TURNS &&
+ cmd.type_specific_bits & (1U << 0)) {
+ // special storage handling allows for larger radii
+ circle_radius_m *= 10;
+ }
+
+ // initialise circle mode
+ if (g2.mode_circle.set_center(circle_center, circle_radius_m, cmd.content.location.loiter_ccw)) {
+ _submode = Auto_Circle;
+ return true;
+ }
+ return false;
+}
+
+bool ModeAuto::verify_circle(const AP_Mission::Mission_Command& cmd)
+{
+ // check if we have completed circling
+ return ((g2.mode_circle.get_angle_total_rad() / M_2PI) >= LOWBYTE(cmd.p1));
+}
+
/********************************************************************************/
// Condition (May) commands
/********************************************************************************/
diff --git a/Rover/mode_circle.cpp b/Rover/mode_circle.cpp
new file mode 100644
index 00000000000000..42d6f63833b79b
--- /dev/null
+++ b/Rover/mode_circle.cpp
@@ -0,0 +1,273 @@
+#include "Rover.h"
+
+#define AR_CIRCLE_ACCEL_DEFAULT 1.0 // default acceleration in m/s/s if not specified by user
+#define AR_CIRCLE_RADIUS_MIN 0.5 // minimum radius in meters
+#define AR_CIRCLE_REACHED_EDGE_DIST 0.2 // vehicle has reached edge if within 0.2m
+
+const AP_Param::GroupInfo ModeCircle::var_info[] = {
+
+ // @Param: _RADIUS
+ // @DisplayName: Circle Radius
+ // @Description: Vehicle will circle the center at this distance
+ // @Units: m
+ // @Range: 0 100
+ // @Increment: 1
+ // @User: Standard
+ AP_GROUPINFO("_RADIUS", 1, ModeCircle, radius, 20),
+
+ // @Param: _SPEED
+ // @DisplayName: Circle Speed
+ // @Description: Vehicle will move at this speed around the circle. If set to zero WP_SPEED will be used
+ // @Units: m/s
+ // @Range: 0 10
+ // @Increment: 0.1
+ // @User: Standard
+ AP_GROUPINFO("_SPEED", 2, ModeCircle, speed, 0),
+
+ // @Param: _DIR
+ // @DisplayName: Circle Direction
+ // @Description: Circle Direction
+ // @Values: 0:Clockwise, 1:Counter-Clockwise
+ // @User: Standard
+ AP_GROUPINFO("_DIR", 3, ModeCircle, direction, 0),
+
+ AP_GROUPEND
+};
+
+ModeCircle::ModeCircle() : Mode()
+{
+ AP_Param::setup_object_defaults(this, var_info);
+}
+
+// initialise with specific center location, radius (in meters) and direction
+// replaces use of _enter when initialised from within Auto mode
+bool ModeCircle::set_center(const Location& center_loc, float radius_m, bool dir_ccw)
+{
+ Vector2f center_pos_cm;
+ if (!center_loc.get_vector_xy_from_origin_NE(center_pos_cm)) {
+ return false;
+ }
+ if (!_enter()) {
+ return false;
+ }
+
+ // convert center position from cm to m
+ config.center_pos = center_pos_cm * 0.01;
+
+ // set radius
+ config.radius = MAX(fabsf(radius_m), AR_CIRCLE_RADIUS_MIN);
+ check_config_radius();
+
+ // set direction
+ config.dir = dir_ccw ? Direction::CCW : Direction::CW;
+
+ // set target yaw rad (target point on circle)
+ init_target_yaw_rad();
+
+ // record center as location (only used for reporting)
+ config.center_loc = center_loc;
+
+ return true;
+}
+
+// initialize dock mode
+bool ModeCircle::_enter()
+{
+ // capture starting point and yaw
+ if (!AP::ahrs().get_relative_position_NE_origin(config.center_pos)) {
+ return false;
+ }
+ config.radius = MAX(fabsf(radius), AR_CIRCLE_RADIUS_MIN);
+ check_config_radius();
+
+ config.dir = (direction == 1) ? Direction::CCW : Direction::CW;
+ config.speed = is_positive(speed) ? speed : g2.wp_nav.get_default_speed();
+ target.yaw_rad = AP::ahrs().get_yaw();
+ target.speed = 0;
+
+ // check speed around circle does not lead to excessive lateral acceleration
+ check_config_speed();
+
+ // calculate speed, accel and jerk limits
+ // otherwise the vehicle uses wp_nav default speed limit
+ float atc_accel_max = MIN(g2.attitude_control.get_accel_max(), g2.attitude_control.get_decel_max());
+ if (!is_positive(atc_accel_max)) {
+ atc_accel_max = AR_CIRCLE_ACCEL_DEFAULT;
+ }
+ const float accel_max = is_positive(g2.wp_nav.get_default_accel()) ? MIN(g2.wp_nav.get_default_accel(), atc_accel_max) : atc_accel_max;
+ const float jerk_max = is_positive(g2.wp_nav.get_default_jerk()) ? g2.wp_nav.get_default_jerk() : accel_max;
+
+ // initialise position controller
+ g2.pos_control.set_limits(config.speed, accel_max, g2.attitude_control.get_turn_lat_accel_max(), jerk_max);
+ g2.pos_control.init();
+
+ // initialise angles covered and reached_edge state
+ angle_total_rad = 0;
+ reached_edge = false;
+ dist_to_edge_m = 0;
+
+ return true;
+}
+
+// initialise target_yaw_rad using the vehicle's position and yaw
+// if there is no current position estimate target_yaw_rad is set to 0
+void ModeCircle::init_target_yaw_rad()
+{
+ // if no position estimate use vehicle yaw
+ Vector2f curr_pos_NE;
+ if (!AP::ahrs().get_relative_position_NE_origin(curr_pos_NE)) {
+ target.yaw_rad = AP::ahrs().yaw;
+ return;
+ }
+
+ // calc vector from circle center to vehicle
+ Vector2f center_to_veh = (curr_pos_NE - config.center_pos);
+ float dist_m = center_to_veh.length();
+
+ // if current position is exactly at the center of the circle return vehicle yaw
+ if (is_zero(dist_m)) {
+ target.yaw_rad = AP::ahrs().yaw;
+ } else {
+ target.yaw_rad = center_to_veh.angle();
+ }
+}
+
+void ModeCircle::update()
+{
+ // get current position
+ Vector2f curr_pos;
+ const bool position_ok = AP::ahrs().get_relative_position_NE_origin(curr_pos);
+
+ // if no position estimate stop vehicle
+ if (!position_ok) {
+ stop_vehicle();
+ return;
+ }
+
+ // check if vehicle has reached edge of circle
+ const Vector2f center_to_veh = curr_pos - config.center_pos;
+ _distance_to_destination = center_to_veh.length();
+ dist_to_edge_m = fabsf(_distance_to_destination - config.radius);
+ if (!reached_edge) {
+ const float dist_thresh_m = MAX(rover.g2.turn_radius, AR_CIRCLE_REACHED_EDGE_DIST);
+ reached_edge = dist_to_edge_m <= dist_thresh_m;
+ }
+
+ // accelerate speed up to desired speed
+ const float speed_max = reached_edge ? config.speed : 0.0;
+ const float speed_change_max = (g2.pos_control.get_accel_max() * 0.5 * rover.G_Dt);
+ const float accel_fb = constrain_float(speed_max - target.speed, -speed_change_max, speed_change_max);
+ target.speed += accel_fb;
+
+ // calculate angular rate and update target angle
+ const float circumference = 2.0 * M_PI * config.radius;
+ const float angular_rate_rad = (target.speed / circumference) * M_2PI * (config.dir == Direction::CW ? 1.0 : -1.0);
+ const float angle_dt = angular_rate_rad * rover.G_Dt;
+ target.yaw_rad = wrap_PI(target.yaw_rad + angle_dt);
+ angle_total_rad += angle_dt;
+
+ // calculate target point's position, velocity and acceleration
+ target.pos = config.center_pos.topostype();
+ target.pos.offset_bearing(degrees(target.yaw_rad), config.radius);
+
+ // velocity is perpendicular to angle from the circle's center to the target point on the edge of the circle
+ target.vel = Vector2f(target.speed, 0);
+ target.vel.rotate(target.yaw_rad + radians(90));
+
+ // acceleration is towards center of circle and is speed^2 / radius
+ target.accel = Vector2f(-sq(target.speed) / config.radius, accel_fb / rover.G_Dt);
+ target.accel.rotate(target.yaw_rad);
+
+ g2.pos_control.set_pos_vel_accel_target(target.pos, target.vel, target.accel);
+ g2.pos_control.update(rover.G_Dt);
+
+ // get desired speed and turn rate from pos_control
+ const float desired_speed = g2.pos_control.get_desired_speed();
+ const float desired_turn_rate = g2.pos_control.get_desired_turn_rate_rads();
+
+ // run steering and throttle controllers
+ calc_steering_from_turn_rate(desired_turn_rate);
+ calc_throttle(desired_speed, true);
+}
+
+// return desired heading (in degrees) and cross track error (in meters) for reporting to ground station (NAV_CONTROLLER_OUTPUT message)
+float ModeCircle::wp_bearing() const
+{
+ Vector2f curr_pos_NE;
+ if (!AP::ahrs().get_relative_position_NE_origin(curr_pos_NE)) {
+ return 0;
+ }
+ // calc vector from circle center to vehicle
+ Vector2f veh_to_center = (config.center_pos - curr_pos_NE);
+ if (veh_to_center.is_zero()) {
+ return 0;
+ }
+ return degrees(veh_to_center.angle());
+}
+
+float ModeCircle::nav_bearing() const
+{
+ // get position error as a vector from the current position to the target position
+ const Vector2p pos_error = g2.pos_control.get_pos_error();
+ if (pos_error.is_zero()) {
+ return 0;
+ }
+ return degrees(pos_error.angle());
+}
+
+float ModeCircle::get_desired_lat_accel() const
+{
+ return g2.pos_control.get_desired_lat_accel();
+}
+
+// set desired speed in m/s
+bool ModeCircle::set_desired_speed(float speed_ms)
+{
+ if (is_positive(speed_ms)) {
+ config.speed = speed_ms;
+
+ // check desired speed does not lead to excessive lateral acceleration
+ check_config_speed();
+
+ // update position controller limits if required
+ if (config.speed > g2.pos_control.get_speed_max()) {
+ g2.pos_control.set_limits(config.speed, g2.pos_control.get_accel_max(), g2.pos_control.get_lat_accel_max(), g2.pos_control.get_jerk_max());
+ }
+ return true;
+ }
+
+ return false;
+}
+
+// return desired location
+bool ModeCircle::get_desired_location(Location& destination) const
+{
+ destination = config.center_loc;
+ return true;
+}
+
+// limit config speed so that lateral acceleration is within limits
+// assumes that config.radius and attitude controller lat accel max have been set
+// outputs warning to user if speed is reduced
+void ModeCircle::check_config_speed()
+{
+ // calculate maximum speed based on radius and max lateral acceleration max
+ const float speed_max = MAX(safe_sqrt(g2.attitude_control.get_turn_lat_accel_max() * config.radius), 0);
+
+ if (config.speed > speed_max) {
+ config.speed = speed_max;
+ gcs().send_text(MAV_SEVERITY_WARNING, "Circle: max speed is %4.1f", (double)config.speed);
+ }
+}
+
+// ensure config radius is no smaller then vehicle's TURN_RADIUS
+// assumes that config.radius has been set
+// radius is increased if necessary and warning is output to the user
+void ModeCircle::check_config_radius()
+{
+ // ensure radius is at least as large as vehicle's turn radius
+ if (config.radius < rover.g2.turn_radius) {
+ config.radius = rover.g2.turn_radius;
+ gcs().send_text(MAV_SEVERITY_WARNING, "Circle: radius increased to TURN_RADIUS (%4.1f)", (double)rover.g2.turn_radius);
+ }
+}
diff --git a/Rover/mode_follow.cpp b/Rover/mode_follow.cpp
index 437cb53deb8445..964a81a102a6ba 100644
--- a/Rover/mode_follow.cpp
+++ b/Rover/mode_follow.cpp
@@ -1,5 +1,6 @@
#include "Rover.h"
+#if MODE_FOLLOW_ENABLED
// initialize follow mode
bool ModeFollow::_enter()
{
@@ -94,3 +95,5 @@ bool ModeFollow::set_desired_speed(float speed)
_desired_speed = speed;
return true;
}
+
+#endif // MODE_FOLLOW_ENABLED
diff --git a/Rover/mode_rtl.cpp b/Rover/mode_rtl.cpp
index b9a8ee49649e17..e896c5151fc878 100644
--- a/Rover/mode_rtl.cpp
+++ b/Rover/mode_rtl.cpp
@@ -11,7 +11,7 @@ bool ModeRTL::_enter()
g2.wp_nav.init(MAX(0, g2.rtl_speed));
// set target to the closest rally point or home
-#if AP_RALLY == ENABLED
+#if HAL_RALLY_ENABLED
if (!g2.wp_nav.set_desired_location(g2.rally.calc_best_rally_or_home_location(rover.current_loc, ahrs.get_home().alt))) {
return false;
}
diff --git a/Rover/release-notes.txt b/Rover/release-notes.txt
index 4a80f680be59b6..155075b3aced54 100644
--- a/Rover/release-notes.txt
+++ b/Rover/release-notes.txt
@@ -1,5 +1,277 @@
Rover Release Notes:
------------------------------------------------------------------
+Rover 4.4.0-beta5 12-Aug-2023
+Changes from 4.4.0-beta4
+1) Autopilots specific changes
+ - SIYI N7 support
+2) Bug fixes
+ - DroneCAN airspeed sensor fix to handle missing packets
+ - DroneCAN GPS RTK injection fix
+ - Notch filter gyro glitch caused by race condition fixed
+------------------------------------------------------------------
+Rover 4.4.0-beta4 27-July-2023
+Changes from 4.4.0-beta3
+1) Autopilots specific changes
+ - Diatone-Mamba-MK4-H743v2 uses SPL06 baro (was DPS280)
+ - DMA for I2C disabled on F7 and H7 boards
+ - Foxeer H743v1 default serial protocol config fixes
+ - HeeWing-F405 and F405v2 support
+ - iFlight BlitzF7 support
+2) Rover specific enhancements
+ - QuikTune Lua script
+ - Circle mode safety improvements including handling when CIRC_SPEED set too high
+ - Velocity controller I-term build-up avoided when steering reaches limits
+3) Bug fixes
+ - BLHeli returns battery status requested via MSP (avoids hang when using esc-configurator)
+ - CRSFv3 rescans at baudrates to avoid RX loss
+ - EK3_ABIAS_P_NSE param range fix
+ - Scripting restart memory corruption bug fixed
+ - Siyi A8/ZR10 driver fix to avoid crash if serial port not configured
+------------------------------------------------------------------
+Rover 4.4.0-beta3 03-July-2023
+Changes from 4.4.0-beta2
+1) Autopilots specific changes
+ - Holybro KakuteH7-Wing support
+ - JFB100 external watchdog GPIO support added
+ - Pixhawk1-bdshot support
+ - Pixhawk6X-bdshot support
+ - SpeedyBeeF4 loses bdshot support
+2) Device drivers
+ - added LP5562 I2C LED driver
+ - added IS31FL3195 LED driver
+3) Circle mode accuracy improvement
+4) Camera and Gimbal related changes
+ - DO_SET_ROI_NONE command support added
+5) Bug fixes
+ - ADSB sensor loss of transceiver message less spammy
+ - EKF vertical velocity reset fixed on loss of GPS
+ - GPS pre-arm failure message clarified
+ - SERVOx_PROTOCOL "SToRM32 Gimbal Serial" value renamed to "Gimbal" because also used by Siyi
+ - SERIALx_OPTION "Swap" renamed to "SwapTXRX" for clarity
+ - SBF GPS ellipsoid height fixed
+ - Ublox M10S GPS auto configuration fixed
+------------------------------------------------------------------
+Rover 4.4.0-beta2 05-Jun-2023
+Changes from 4.4.0-beta1
+1) Autopilots specific changes
+ - FlywooF745 update to motor pin output mapping and baro
+ - FoxeerH743 support
+ - JFB100 support
+ - Mamba-F405v2 supports ICM42688
+ - Matek-F405-TE/VTOL support
+ - Matek-H743 IMU SPI slowed to 1Mhz to avoid init issues
+ - SpeedyBee-405-Wing support
+2) Rover specific changes
+ - Circle mode and Auto mode LOITER_TURNS support
+ - Dock mode added to INITIAL_MODE and MODE1 parameter list
+3) AHRS/EKF related fixes and Enhancements
+ - EKF allocation failure handled to avoid watchdog
+ - EKF3 accel bias calculation fix and tuning for greater robustness
+ - Airspeed sensor remains enabled during dead-reckoning (few copters have airspeed sensors)
+ - Wind speed estimates updates reduced while dead-reckoning
+4) Other Enhancements
+ - Attitude control slew limits always calculated (helps tuning reporting and analysis)
+ - INA228 and INA238 I2C battery monitor support
+ - LOG_DISARMED=3 logs while disarmed but discards log if never eventually armed
+ - LOG_DARM_RATEMAX reduces logging while disarmed
+ - Serial LEDs threading enhancement to support longer lengths without dshot interference
+4) Bug fixes
+ - Analog battery monitor2 current parameter default fixed
+ - AutoTune fix for loading Yaw Rate D gains
+ - BRD_SAFETYOPTION parameter documentation fix (ActiveForSafetyEnable and Disable were reversed)
+ - Compassmot fix to protect against bad gyro biases from GSF yaw
+ - ICE engine fix for starting after reaching a specified altitude
+ - LED thread locking fix to avoid watchdog
+ - Logging rotation on disarm disabled if Replay logging active (avoids gaps in logs)
+ - RC input on IOMCU bug fix (RC might not be regained if lost)
+ - Serial passthrough fixed
+5) Custom build server fix to which features are included/excluded
+------------------------------------------------------------------
+Rover 4.4.0-beta1 19-Apr-2023
+Changes from 4.3.0-beta12
+1) New autopilots supported
+ - ESP32
+ - Flywoo Goku F405S AIO
+ - Foxeer H743v1
+ - MambaF405-2022B
+ - PixPilot-V3
+ - PixSurveyA2
+ - rFCU H743
+ - ThePeach K1/R1
+2) Autopilot specific changes
+ - Bi-Directional DShot support for CubeOrangePlus-bdshot, CUAVNora+, MatekF405TE/VTOL-bdshot, MatekL431, Pixhawk6C-bdshot, QioTekZealotH743-bdshot
+ - Bi-Directional DShot up to 8 channels on MatekH743
+ - BlueRobotics Navigator supports baro on I2C bus 6
+ - BMP280 baro only for BeastF7, KakuteF4, KakuteF7Mini, MambaF405, MatekF405, Omnibusf4 to reduce code size (aka "flash")
+ - CSRF and Hott telemetry disabled by default on some low power boards (aka "minimised boards")
+ - Foxeer Reaper F745 supports external compasses
+ - OmnibusF4 support for BMI270 IMU
+ - OmnibusF7V2-bdshot support removed
+ - KakuteF7 regains displayport, frees up DMA from unused serial port
+ - KakuteH7v2 gets second battery sensor
+ - MambaH743v4 supports VTX
+ - MatekF405-Wing supports InvensenseV3 IMUs
+ - PixPilot-V6 heater enabled
+ - Raspberry 64OS startup crash fixed
+ - ReaperF745AIO serial protocol defaults fixed
+ - SkystarsH7HD (non-bdshot) removed as users should always use -bdshot version
+ - Skyviper loses many unnecessary features to save flash
+ - UBlox GPS only for AtomRCF405NAVI, BeastF7, MatekF405, Omnibusf4 to reduce code size (aka "flash")
+ - VRBrain-v52 and VRCore-v10 features reduced to save flash
+3) Driver enhancements
+ - ARK RTK GPS support
+ - BMI088 IMU filtering and timing improved, ignores bad data
+ - CRSF OSD may display disarmed state after flight mode (enabled using RC_OPTIONS)
+ - Daiwa winch baud rate obeys SERIALx_BAUD parameter
+ - EFI supports fuel pressure and ignition voltage reporting and battery failsafe
+ - ICM45686 IMU support
+ - ICM20602 uses fast reset instead of full reset on bad temperature sample (avoids occasional very high offset)
+ - ICM45686 supports fast sampling
+ - MAX31865 temp sensor support
+ - MB85RS256TY-32k, PB85RS128C and PB85RS2MC FRAM support
+ - MMC3416 compass orientation fix
+ - MPPT battery monitor reliability improvements, enable/disable aux function and less spammy
+ - Multiple USD-D1-CAN radar support
+ - NMEA output rate configurable (see NMEA_RATE_MS)
+ - NMEA output supports PASHR message (see NMEA_MSG_EN)
+ - OSD supports average resting cell voltage (see OSD_ACRVOLT_xxx params)
+ - Rockblock satellite modem support
+ - Serial baud support for 2Mbps (only some hardware supports this speed)
+ - SF45b lidar filtering reduced (allows detecting smaller obstacles
+ - SmartAudio 2.0 learns all VTX power levels)
+ - UAVCAN ESCs report error count using ESC Telemetry
+ - Unicore GPS (e.g. UM982) support
+ - VectorNav 100 external AHRS support
+ - 5 IMUs supported
+4) EKF related enhancements
+ - Baro compensation using wind estimates works when climbing or descending (see BAROx_WCF_UP/DN)
+ - External AHRS support for enabling only some sensors (e.g. IMU, Baro, Compass) see EAHRS_SENSORS
+ - Magnetic field tables updated
+ - Non-compass initial yaw alignment uses GPS course over GSF (mostly affects Planes and Rover)
+5) Control and navigation enhancements
+ - DO_SET_ROI_NONE command turns off ROI
+ - JUMP_TAG mission item support
+ - Manual mode steering expo configurable (see MANUAL_STR_EXPO)
+ - Missions can be stored on SD card (see BRD_SD_MISSION)
+ - NAV_SCRIPT_TIME command accepts floating point arguments
+ - Pause/Resume returns success if mission is already paused or resumed
+8) Camera and gimbal enhancements
+ - BMMCC support included in Servo driver
+ - DJI RS2/RS3-Pro gimbal support
+ - Dual camera support (see CAM2_TYPE)
+ - Gimbal/Mount2 can be moved to retracted or neutral position
+ - Gremsy ZIO support
+ - IMAGE_START_CAPTURE, SET_CAMERA_ZOOM/FOCUS, VIDEO_START/STOP_CAPTURE command support
+ - Paramters renamed and rescaled
+ - CAM_TRIGG_TYPE renamed to CAM1_TYPE and options have changed
+ - CAM_DURATION renamed to CAM1_DURATION and scaled in seconds
+ - CAM_FEEDBACK_PIN/POL renamed to CAM1_FEEBAK_PIN/POL
+ - CAM_MIN_INTERVAL renamed to CAM1_INTRVAL_MIN and scaled in seconds
+ - CAM_TRIGG_DIST renamed to CAMx_TRIGG_DIST and accepts fractional values
+ - RunCam2 4k support
+ - ViewPro camera gimbal support
+8) Logging changes
+ - BARD msg includes 3-axis dynamic pressure useful for baro compensation of wind estimate
+ - MCU log msg includes main CPU temp and voltage (was part of POWR message)
+ - RCOut banner message always included in Logs
+ - SCR message includes memory usage of all running scripts
+ - CANS message includes CAN bus tx/rx statistics
+ - Home location not logged to CMD message
+ - MOTB message includes throttle output
+9) Scripting enhancements
+ - EFI Skypower driver gets improved telem messages and bug fixes
+ - Generator throttle control example added
+ - Heap max increased by allowing heap to be split across multiple underlying OS heaps
+ - Hexsoon LEDs applet
+ - Logging from scripts supports more formats
+ - Parameters can be removed or reordered
+ - Parameter description support (scripts must be in AP's applet or driver directory)
+ - Rangefinder driver support
+ - Runcam_on_arm applet starts recording when vehicle is armed
+ - Safety switch, E-Stop and motor interlock support
+ - Scripts can restart all scripts
+ - Script_Controller applet supports inflight switching of active scripts
+10) Custom build server enhancements
+ - AIS support for displaying nearby boats can be included
+ - Battery, Camera and Compass drivers can be included/excluded
+ - EKF3 wind estimation can be included/excluded
+ - PCA9685, ToshibaLED, PLAY_TUNE notify drivers can be included/excluded
+ - RichenPower generator can be included/excluded
+ - RC SRXL protocol can be excluded
+ - SIRF GPSs can be included/excluded
+11) Safety related enhancements and fixes
+ - Arming check for servo outputs skipped when SERVOx_FUNCTION is scripting
+ - Arming check fix if both "All" and other bitmasks are selected (previously only ran the other checks)
+ - GCS failsafe timeout is configurable (see FS_GCS_TIMEOUT)
+ - "EK3 sources require RangeFinder" pre-arm check fix when user only sets up 2nd rangefinder (e.g. 1st is disabled)
+ - Pre-arm check that low and critical battery failsafe thresholds are different
+ - Pre-arm message fixed if 2nd EKF core unhealthy
+ - Pre-arm check if reboot required to enabled IMU batch sampling (used for vibe analysis)
+ - RC failsafe timeout configurable (see RC_FS_TIMEOUT)
+12) Minor enhancements
+ - Boot time reduced by improving parameter conversion efficiency
+ - BRD_SAFETYENABLE parameter renamed to BRD_SAFETY_DEFLT
+ - Compass calibration auxiliary switch function (set RCx_OPTION=171)
+ - Disable IMU3 auxiliary switch function (set RCx_OPTION=110)
+ - Rangefinder and FS_OPTIONS param conversion code reduced (affects when upgrading from 3.6 or earlier)
+ - MAVFTP supports file renaming
+ - MAVLink in-progress reply to some requests for calibration from GCS
+13) Bug fixes:
+ - ADSB telemetry and callsign fixes
+ - Battery pct reported to GCS limited to 0% to 100% range
+ - Bi-directional DShot fix on H7 boards after system time wrap (more complete fix than in 4.3.6)
+ - DisplayPort OSD screen reliability improvement on heavily loaded OSDs especially F4 boards
+ - DisplayPort OSD artificial horizon better matches actual horizon
+ - EFI Serial MS bug fix to avoid possible infinite loop
+ - EKF3 Replay fix when COMPASS_LEARN=3
+ - ESC Telemetry external temp reporting fix
+ - Fence upload works even if Auto mode is excluded from firmware
+ - FMT messages logged even when Fence is exncluded from firmware (e.g. unselected when using custom build server)
+ - Hardfault avoided if user changes INS_LOG_BAT_CNT while batch sampling running
+ - ICM20649 temp sensor tolerate increased to avoid unnecessary FIFO reset
+ - IMU detection bug fix to avoid duplicates
+ - IMU temp cal fix when using auxiliary IMU
+ - Message Interval fix for restoring default rate https://github.com/ArduPilot/ardupilot/pull/21947
+ - RADIO_STATUS messages slow-down feature never completely stops messages from being sent
+ - SERVOx_TRIM value output momentarily if SERVOx_FUNCTION is changed from Disabled to RCPassThru, RCIN1, etc. Avoids momentary divide-by-zero
+ - Scripting file system open fix
+ - Scripting PWM source deletion crash fix
+ - MAVFTP fix for low baudrates (4800 baud and lower)
+ - ModalAI VOXL reset handling fix
+ - MPU6500 IMU fast sampling rate to 4k (was 1K)
+ - NMEA GPGGA output fixed for GPS quality, num sats and hdop
+ - Position control reset avoided even with very uneven main loop rate due to high CPU load
+ - Throttle notch FFT tuning param fix
+ - VTX protects against pitmode changes when not enabled or vehicle disarmed
+14) Developer specific items
+ - DroneCAN replaces UAVCAN
+ - FlighAxis simulator rangefinder fixed
+ - Scripts in applet and drivers directory checked using linter
+ - Simulator supports main loop timing jitter (see SIM_TIME_JITTER)
+ - Simulink model and init scripts
+ - SITL on hardware support (useful to demo servos moving in response to simulated flight)
+ - SITL parameter definitions added (some, not all)
+ - Webots 2023a simulator support
+ - XPlane support for wider range of aircraft
+------------------------------------------------------------------
+Rover 4.3.0-beta14 12-Aug-2023
+Changes from 4.3.0-beta13
+1) Bug fixes
+ - DroneCAN GPS RTK injection fix
+ - INAxxx battery monitors allow for battery reset remaining
+ - Notch filter gyro glitch caused by race condition fixed
+ - Scripting restart memory corruption bug fixed
+------------------------------------------------------------------
+Rover 4.3.0-beta13 27-Mar-2023
+Changes from 4.3.0-beta12
+1) Bug fixes
+ a) EKF3 accel bias calculations bug fix
+ b) EKF3 accel bias process noise adjusted for greater robustness
+ c) GSF yaw numerical stability fix caused by compassmot
+ d) INS batch sampler fix to avoid watchdog if INS_LOG_BAT_CNT changed without rebooting
+ e) Memory corruption bug in the STM32H757 (very rare)
+ f) RC input on IOMCU bug fix (RC might not be regained if lost)
+------------------------------------------------------------------
Rover 4.3.0-beta11/beta12 27-Mar-2023
Changes from 4.3.0-beta10
1) Bi-directional DShot fix for possible motor stop approx 72min after startup
diff --git a/Rover/system.cpp b/Rover/system.cpp
index bd6ed6b1ccf68e..10cc4a975ba34d 100644
--- a/Rover/system.cpp
+++ b/Rover/system.cpp
@@ -107,7 +107,9 @@ void Rover::init_ardupilot()
optflow.init(MASK_LOG_OPTFLOW);
#endif // AP_OPTICALFLOW_ENABLED
+#if AP_RELAY_ENABLED
relay.init();
+#endif
#if HAL_MOUNT_ENABLED
// initialise camera mount
@@ -186,10 +188,6 @@ void Rover::startup_ground(void)
#if AP_SCRIPTING_ENABLED
g2.scripting.init();
#endif // AP_SCRIPTING_ENABLED
-
- // we don't want writes to the serial port to cause us to pause
- // so set serial ports non-blocking once we are ready to drive
- serial_manager.set_blocking_writes_all(false);
}
// update the ahrs flyforward setting which can allow
@@ -221,6 +219,30 @@ void Rover::update_ahrs_flyforward()
ahrs.set_fly_forward(flyforward);
}
+// Check if this mode can be entered from the GCS
+bool Rover::gcs_mode_enabled(const Mode::Number mode_num) const
+{
+ // List of modes that can be blocked, index is bit number in parameter bitmask
+ static const uint8_t mode_list [] {
+ (uint8_t)Mode::Number::MANUAL,
+ (uint8_t)Mode::Number::ACRO,
+ (uint8_t)Mode::Number::STEERING,
+ (uint8_t)Mode::Number::LOITER,
+ (uint8_t)Mode::Number::FOLLOW,
+ (uint8_t)Mode::Number::SIMPLE,
+ (uint8_t)Mode::Number::CIRCLE,
+ (uint8_t)Mode::Number::AUTO,
+ (uint8_t)Mode::Number::RTL,
+ (uint8_t)Mode::Number::SMART_RTL,
+ (uint8_t)Mode::Number::GUIDED,
+#if MODE_DOCK_ENABLED == ENABLED
+ (uint8_t)Mode::Number::DOCK
+#endif
+ };
+
+ return !block_GCS_mode_change((uint8_t)mode_num, mode_list, ARRAY_SIZE(mode_list));
+}
+
bool Rover::set_mode(Mode &new_mode, ModeReason reason)
{
if (control_mode == &new_mode) {
@@ -228,6 +250,12 @@ bool Rover::set_mode(Mode &new_mode, ModeReason reason)
return true;
}
+ // Check if GCS mode change is disabled via parameter
+ if ((reason == ModeReason::GCS_COMMAND) && !gcs_mode_enabled((Mode::Number)new_mode.mode_number())) {
+ gcs().send_text(MAV_SEVERITY_NOTICE,"Mode change to %s denied, GCS entry disabled (FLTMODE_GCSBLOCK)", new_mode.name4());
+ return false;
+ }
+
Mode &old_mode = *control_mode;
if (!new_mode.enter()) {
// Log error that we failed to enter desired flight mode
diff --git a/Rover/version.h b/Rover/version.h
index 6ec99cb1d6b818..11b034f62f7d68 100644
--- a/Rover/version.h
+++ b/Rover/version.h
@@ -6,13 +6,13 @@
#include "ap_version.h"
-#define THISFIRMWARE "ArduRover V4.4.0-dev"
+#define THISFIRMWARE "ArduRover V4.5.0-dev"
// the following line is parsed by the autotest scripts
-#define FIRMWARE_VERSION 4,4,0,FIRMWARE_VERSION_TYPE_DEV
+#define FIRMWARE_VERSION 4,5,0,FIRMWARE_VERSION_TYPE_DEV
#define FW_MAJOR 4
-#define FW_MINOR 4
+#define FW_MINOR 5
#define FW_PATCH 0
#define FW_TYPE FIRMWARE_VERSION_TYPE_DEV
diff --git a/Tools/AP_Bootloader/AP_Bootloader.cpp b/Tools/AP_Bootloader/AP_Bootloader.cpp
index d383905f3a7a79..f42271208073ba 100644
--- a/Tools/AP_Bootloader/AP_Bootloader.cpp
+++ b/Tools/AP_Bootloader/AP_Bootloader.cpp
@@ -63,6 +63,8 @@ AP_FlashIface_JEDEC ext_flash;
int main(void)
{
+ custom_startup();
+
#ifdef STM32F427xx
if (BOARD_FLASH_SIZE > 1024 && check_limit_flash_1M()) {
board_info.fw_size = (1024 - (FLASH_BOOTLOADER_LOAD_KB + APP_START_OFFSET_KB))*1024;
@@ -161,6 +163,14 @@ int main(void)
}
#endif
+#if EXT_FLASH_SIZE_MB
+ while (!ext_flash.init()) {
+ // keep trying until we get it working
+ // there's no future without it
+ chThdSleep(chTimeMS2I(20));
+ }
+#endif
+
if (try_boot) {
jump_to_app();
}
@@ -174,14 +184,6 @@ int main(void)
flash_init();
-#if EXT_FLASH_SIZE_MB
- while (!ext_flash.init()) {
- // keep trying until we get it working
- // there's no future without it
- chThdSleep(chTimeMS2I(20));
- }
-#endif
-
#if AP_BOOTLOADER_FLASH_FROM_SD_ENABLED
if (flash_from_sd()) {
jump_to_app();
diff --git a/Tools/AP_Bootloader/bl_protocol.cpp b/Tools/AP_Bootloader/bl_protocol.cpp
index c4577cd2312e15..28004b66aaadb1 100644
--- a/Tools/AP_Bootloader/bl_protocol.cpp
+++ b/Tools/AP_Bootloader/bl_protocol.cpp
@@ -316,12 +316,17 @@ jump_to_app()
#elif defined(STM32L4)
rccDisableAPB1R1(~0);
rccDisableAPB1R2(~0);
+#elif defined(STM32L4PLUS)
+ rccDisableAPB1R1(~0);
+ rccDisableAPB1R2(~0);
#else
rccDisableAPB1(~0);
#endif
rccDisableAPB2(~0);
-#if HAL_USE_SERIAL_USB == TRUE
+#if HAL_USE_SERIAL_USB == TRUE
+#if !defined(STM32_OTG2_IS_OTG1)
rccResetOTG_FS();
+#endif
#if defined(rccResetOTG_HS)
rccResetOTG_HS();
#endif
diff --git a/Tools/AP_Bootloader/board_types.txt b/Tools/AP_Bootloader/board_types.txt
index af66dca9c15b9f..8f12c807694a40 100644
--- a/Tools/AP_Bootloader/board_types.txt
+++ b/Tools/AP_Bootloader/board_types.txt
@@ -177,8 +177,8 @@ AP_HW_QioTekAdeptF407 1065
AP_HW_QioTekAdeptF427 1066
AP_HW_FlyingMoonF407 1067
AP_HW_FlyingMoonF427 1068
-AP_HW_CUBERED 1069
-AP_HW_CUBERED_IO 1070
+AP_HW_CUBERED_PRIMARY 1069
+AP_HW_CUBERED_SECONDARY 1070
AP_HW_GreenSight_UltraBlue 1071
AP_HW_GreenSight_microBlue 1072
AP_HW_MAMBAH743_V4 1073
@@ -217,11 +217,28 @@ AP_HW_rGNSS 1103
AP_HW_AEROFOX_AIRSPEED_DLVR 1104
AP_HW_KakuteH7-Wing 1105
AP_HW_SpeedyBeeF405WING 1106
-
-
AP_HW_PixSurveyA-IND 1107
-
+AP_HW_SPRACINGH7RF 1108
+AP_HW_AEROFOX_GNSS_F9P 1109
AP_HW_JFB110 1110
+AP_HW_SDMODELH7V1 1111
+AP_HW_FlyingMoonH743 1112
+AP_HW_YJUAV_A6 1113
+AP_HW_YJUAV_A6Nano 1114
+AP_HW_ACNS_CM4PILOT 1115
+AP_HW_ACNS_F405AIO 1116
+AP_HW_BLITZF7 1117
+AP_HW_RADIX2HD 1118
+AP_HW_HEEWING_F405 1119
+AP_HW_PodmanH7 1120
+AP_HW_mRo-M10053 1121
+AP_HW_mRo-M10044 1122
+AP_HW_SIYI_N7 1123
+AP_HW_mRoCZOEM_revG 1124
+AP_HW_BETAFPV_F405 1125
+AP_HW_QioTekAdeptH743 1126
+AP_HW_YJUAV_A6SE 1127
+AP_HW_QioTekAdept_6C 1128
AP_HW_ESP32_PERIPH 1205
AP_HW_ESP32S3_PERIPH 1206
@@ -231,6 +248,10 @@ AP_HW_CUBEBLACK_PERIPH 1401
AP_HW_PIXRACER_PERIPH 1402
AP_HW_SWBOOMBOARD_PERIPH 1403
+# IDs 5000-5099 reserved for Carbonix
+# IDs 5100-5199 reserved for SYPAQ Systems
+# IDs 6000-6099 reserved for SpektreWorks
+
# OpenDroneID enabled boards. Use 10000 + the base board ID
AP_HW_CubeOrange_ODID 10140
AP_HW_Pixhawk6_ODID 10053
diff --git a/Tools/AP_Bootloader/custom.cpp b/Tools/AP_Bootloader/custom.cpp
new file mode 100644
index 00000000000000..ef5f7ef434d38b
--- /dev/null
+++ b/Tools/AP_Bootloader/custom.cpp
@@ -0,0 +1,52 @@
+/*
+ custom code for specific boards
+ */
+#include
+#include "ch.h"
+#include "hal.h"
+#include "support.h"
+
+#ifdef AP_BOOTLOADER_CUSTOM_HERE4
+/*
+ reset here4 LEDs
+*/
+static void bootloader_custom_Here4(void)
+{
+ for (uint8_t n=0; n<10; n++) {
+ const uint8_t num_leds = 4;
+ const uint32_t min_bits = num_leds*25+50;
+ const uint8_t num_leading_zeros = 8-min_bits%8 + 50;
+ const uint32_t output_stream_byte_length = (min_bits+7)/8;
+ palSetLineMode(HAL_GPIO_PIN_LED_DI, PAL_MODE_OUTPUT_PUSHPULL);
+ palSetLineMode(HAL_GPIO_PIN_LED_SCK, PAL_MODE_OUTPUT_PUSHPULL);
+ int l = 100;
+ while (l--) {
+ for (uint32_t i=0; i> 16);
- mcu_des_t des = mcu_descriptions[STM32_UNKNOWN];
+ uint8_t *endp = &revstr[max - 1];
+ uint8_t *strp = revstr;
for (const auto &desc : mcu_descriptions) {
if (mcuid == desc.mcuid) {
- des = desc;
+ // copy the string in:
+ const char *tmp = desc.desc;
+ while (strp < endp && *tmp) {
+ *strp++ = *tmp++;
+ }
break;
}
}
- for (const auto &rev : silicon_revs) {
- if (rev.revid == revid) {
- des.rev = rev.rev;
- }
- }
-
- uint8_t *endp = &revstr[max - 1];
- uint8_t *strp = revstr;
-
- while (strp < endp && *des.desc) {
- *strp++ = *des.desc++;
- }
-
+ // comma-separated:
if (strp < endp) {
*strp++ = ',';
}
- if (strp < endp) {
- *strp++ = des.rev;
+ for (const auto &rev : silicon_revs) {
+ if (rev.revid == revid) {
+ if (strp < endp) {
+ *strp++ = rev.rev;
+ }
+ }
}
return strp - revstr;
@@ -464,3 +469,4 @@ void port_setbaud(uint32_t baudrate)
#endif
}
#endif // BOOTLOADER_DEV_LIST
+
diff --git a/Tools/AP_Bootloader/support.h b/Tools/AP_Bootloader/support.h
index 13f3085ba3be92..d0ffe1503f83fa 100644
--- a/Tools/AP_Bootloader/support.h
+++ b/Tools/AP_Bootloader/support.h
@@ -44,6 +44,8 @@ void led_on(unsigned led);
void led_off(unsigned led);
void led_toggle(unsigned led);
+void custom_startup(void);
+
// printf to debug uart (or USB)
extern "C" {
void uprintf(const char *fmt, ...) FMT_PRINTF(1,2);
@@ -55,7 +57,6 @@ void led_pulses(uint8_t npulses);
typedef struct mcu_des_t {
uint16_t mcuid;
const char *desc;
- char rev;
} mcu_des_t;
typedef struct mcu_rev_t {
diff --git a/Tools/AP_Periph/AP_Periph.cpp b/Tools/AP_Periph/AP_Periph.cpp
index 975167cec15f34..c4f71cbdc34dfc 100644
--- a/Tools/AP_Periph/AP_Periph.cpp
+++ b/Tools/AP_Periph/AP_Periph.cpp
@@ -100,6 +100,10 @@ void AP_Periph_FW::init()
can_start();
+#ifdef HAL_PERIPH_ENABLE_NETWORKING
+ networking.init();
+#endif
+
#if HAL_GCS_ENABLED
stm32_watchdog_pat();
gcs().init();
@@ -159,6 +163,10 @@ void AP_Periph_FW::init()
battery.lib.init();
#endif
+#ifdef HAL_PERIPH_ENABLE_RCIN
+ rcin_init();
+#endif
+
#if defined(HAL_PERIPH_NEOPIXEL_COUNT_WITHOUT_NOTIFY) || defined(HAL_PERIPH_ENABLE_RC_OUT)
hal.rcout->init();
#endif
@@ -185,7 +193,11 @@ void AP_Periph_FW::init()
}
}
#endif
-
+
+#if AP_KDECAN_ENABLED
+ kdecan.init();
+#endif
+
#ifdef HAL_PERIPH_ENABLE_AIRSPEED
#if CONFIG_HAL_BOARD == HAL_BOARD_CHIBIOS
const bool pins_enabled = ChibiOS::I2CBus::check_select_pins(0x01);
@@ -219,7 +231,7 @@ void AP_Periph_FW::init()
}
#endif
-#ifdef HAL_PERIPH_ENABLE_PRX
+#if HAL_PROXIMITY_ENABLED
if (proximity.get_type(0) != AP_Proximity::Type::None && g.proximity_port >= 0) {
auto *uart = hal.serial(g.proximity_port);
if (uart != nullptr) {
@@ -238,6 +250,15 @@ void AP_Periph_FW::init()
hwesc_telem.init(hal.serial(HAL_PERIPH_HWESC_SERIAL_PORT));
#endif
+#ifdef HAL_PERIPH_ENABLE_ESC_APD
+ for (uint8_t i = 0; i < ESC_NUMBERS; i++) {
+ const uint8_t port = g.esc_serial_port[i];
+ if (port < SERIALMANAGER_NUM_PORTS) { // skip bad ports
+ apd_esc_telem[i] = new ESC_APD_Telem (hal.serial(port), g.pole_count[i]);
+ }
+ }
+#endif
+
#ifdef HAL_PERIPH_ENABLE_MSP
if (g.msp_port >= 0) {
msp_init(hal.serial(g.msp_port));
@@ -252,6 +273,10 @@ void AP_Periph_FW::init()
nmea.init();
#endif
+#ifdef HAL_PERIPH_ENABLE_RPM
+ rpm_sensor.init();
+#endif
+
#ifdef HAL_PERIPH_ENABLE_NOTIFY
notify.init();
#endif
@@ -259,7 +284,7 @@ void AP_Periph_FW::init()
#if AP_SCRIPTING_ENABLED
scripting.init();
#endif
- start_ms = AP_HAL::native_millis();
+ start_ms = AP_HAL::millis();
}
#if (defined(HAL_PERIPH_NEOPIXEL_COUNT_WITHOUT_NOTIFY) && HAL_PERIPH_NEOPIXEL_COUNT_WITHOUT_NOTIFY == 8) || defined(HAL_PERIPH_ENABLE_NOTIFY)
@@ -277,7 +302,7 @@ void AP_Periph_FW::update_rainbow()
if (rainbow_done) {
return;
}
- uint32_t now = AP_HAL::native_millis();
+ uint32_t now = AP_HAL::millis();
if (now - start_ms > 1500) {
rainbow_done = true;
#if defined (HAL_PERIPH_ENABLE_NOTIFY)
@@ -361,7 +386,7 @@ void AP_Periph_FW::update()
#endif
static uint32_t last_led_ms;
- uint32_t now = AP_HAL::native_millis();
+ uint32_t now = AP_HAL::millis();
if (now - last_led_ms > 1000) {
last_led_ms = now;
#ifdef HAL_GPIO_PIN_LED
@@ -413,13 +438,13 @@ void AP_Periph_FW::update()
#if CONFIG_HAL_BOARD == HAL_BOARD_CHIBIOS && CH_DBG_ENABLE_STACK_CHECK == TRUE
static uint32_t last_debug_ms;
- if ((g.debug&(1< 5000) {
+ if (debug_option_is_set(DebugOptions::SHOW_STACK) && now - last_debug_ms > 5000) {
last_debug_ms = now;
show_stack_free();
}
#endif
- if ((g.debug&(1< 15000) {
+ if (debug_option_is_set(DebugOptions::AUTOREBOOT) && AP_HAL::millis() > 15000) {
// attempt reboot with HOLD after 15s
periph.prepare_reboot();
#if CONFIG_HAL_BOARD == HAL_BOARD_CHIBIOS
@@ -436,6 +461,10 @@ void AP_Periph_FW::update()
}
#endif
+#ifdef HAL_PERIPH_ENABLE_RCIN
+ rcin_update();
+#endif
+
static uint32_t fiftyhz_last_update_ms;
if (now - fiftyhz_last_update_ms >= 20) {
// update at 50Hz
@@ -457,12 +486,23 @@ void AP_Periph_FW::update()
temperature_sensor.update();
#endif
+#ifdef HAL_PERIPH_ENABLE_RPM
+ if (now - rpm_last_update_ms >= 100) {
+ rpm_last_update_ms = now;
+ rpm_sensor.update();
+ }
+#endif
+
#if HAL_LOGGING_ENABLED
logger.periodic_tasks();
#endif
can_update();
+#ifdef HAL_PERIPH_ENABLE_NETWORKING
+ networking.update();
+#endif
+
#if (defined(HAL_PERIPH_NEOPIXEL_COUNT_WITHOUT_NOTIFY) && HAL_PERIPH_NEOPIXEL_COUNT_WITHOUT_NOTIFY == 8) || defined(HAL_PERIPH_ENABLE_NOTIFY)
update_rainbow();
#endif
diff --git a/Tools/AP_Periph/AP_Periph.h b/Tools/AP_Periph/AP_Periph.h
index d9fa52efb06d97..4fa3f664ccd8ed 100644
--- a/Tools/AP_Periph/AP_Periph.h
+++ b/Tools/AP_Periph/AP_Periph.h
@@ -13,17 +13,27 @@
#include
#include
#include
+#include
#include
#include
#include
#include "../AP_Bootloader/app_comms.h"
#include
#include "hwing_esc.h"
-#include
+#include
+#include
#include
#include
#include
-
+#include
+#include
+#include
+#include
+#if HAL_WITH_ESC_TELEM
+#include
+#endif
+#include
+#include "rc_in.h"
#include
#if HAL_NMEA_OUTPUT_ENABLED && !(HAL_GCS_ENABLED && defined(HAL_PERIPH_ENABLE_GPS))
@@ -35,6 +45,8 @@
#include "GCS_MAVLink.h"
#endif
+#include "esc_apd_telem.h"
+
#if defined(HAL_PERIPH_NEOPIXEL_COUNT_WITHOUT_NOTIFY) || defined(HAL_PERIPH_ENABLE_NCP5623_LED_WITHOUT_NOTIFY) || defined(HAL_PERIPH_ENABLE_NCP5623_BGR_LED_WITHOUT_NOTIFY) || defined(HAL_PERIPH_ENABLE_TOSHIBA_LED_WITHOUT_NOTIFY)
#define AP_PERIPH_HAVE_LED_WITHOUT_NOTIFY
#endif
@@ -69,6 +81,9 @@ extern "C" {
void can_printf(const char *fmt, ...) FMT_PRINTF(1,2);
}
+struct CanardInstance;
+struct CanardRxTransfer;
+
class AP_Periph_FW {
public:
AP_Periph_FW();
@@ -147,6 +162,11 @@ class AP_Periph_FW {
AP_Baro baro;
#endif
+#ifdef HAL_PERIPH_ENABLE_RPM
+ AP_RPM rpm_sensor;
+ uint32_t rpm_last_update_ms;
+#endif
+
#ifdef HAL_PERIPH_ENABLE_BATTERY
struct AP_Periph_Battery {
void handle_battery_failsafe(const char* type_str, const int8_t action) { }
@@ -161,7 +181,7 @@ class AP_Periph_FW {
// This allows you to change the protocol and it continues to use the one at boot.
// Without this, changing away from UAVCAN causes loss of comms and you can't
// change the rest of your params or verify it succeeded.
- AP_CANManager::Driver_Type can_protocol_cached[HAL_NUM_CAN_IFACES];
+ AP_CAN::Protocol can_protocol_cached[HAL_NUM_CAN_IFACES];
#endif
#ifdef HAL_PERIPH_ENABLE_MSP
@@ -201,7 +221,7 @@ class AP_Periph_FW {
uint32_t last_sample_ms;
#endif
-#ifdef HAL_PERIPH_ENABLE_PRX
+#if HAL_PROXIMITY_ENABLED
AP_Proximity proximity;
#endif
@@ -227,7 +247,16 @@ class AP_Periph_FW {
AP_EFI efi;
uint32_t efi_update_ms;
#endif
+
+#if AP_KDECAN_ENABLED
+ AP_KDECAN kdecan;
+#endif
+#ifdef HAL_PERIPH_ENABLE_ESC_APD
+ ESC_APD_Telem *apd_esc_telem[APD_ESC_INSTANCES];
+ void apd_esc_telem_update();
+#endif
+
#ifdef HAL_PERIPH_ENABLE_RC_OUT
#if HAL_WITH_ESC_TELEM
AP_ESC_Telem esc_telem;
@@ -251,6 +280,16 @@ class AP_Periph_FW {
void rcout_handle_safety_state(uint8_t safety_state);
#endif
+#ifdef HAL_PERIPH_ENABLE_RCIN
+ void rcin_init();
+ void rcin_update();
+ void can_send_RCInput(uint8_t quality, uint16_t *values, uint8_t nvalues, bool in_failsafe, bool quality_valid);
+ bool rcin_initialised;
+ uint32_t rcin_last_sent_RCInput_ms;
+ const char *rcin_rc_protocol; // protocol currently being decoded
+ Parameters_RCIN g_rcin;
+#endif
+
#if AP_TEMPERATURE_SENSOR_ENABLED
AP_TemperatureSensor temperature_sensor;
#endif
@@ -283,6 +322,10 @@ class AP_Periph_FW {
AP_Logger logger;
#endif
+#ifdef HAL_PERIPH_ENABLE_NETWORKING
+ AP_Networking networking;
+#endif
+
#if HAL_GCS_ENABLED
GCS_Periph _gcs;
#endif
@@ -301,16 +344,52 @@ class AP_Periph_FW {
static AP_Periph_FW *_singleton;
- enum {
- DEBUG_SHOW_STACK,
- DEBUG_AUTOREBOOT
+ enum class DebugOptions {
+ SHOW_STACK = 0,
+ AUTOREBOOT = 1,
+ ENABLE_STATS = 2,
};
+ // check if an option is set
+ bool debug_option_is_set(const DebugOptions option) const {
+ return (uint8_t(g.debug.get()) & (1U<= 3
// @Param: CAN3_BAUDRATE
// @DisplayName: Bitrate of CAN3 interface
- // @Description: Bit rate can be set up to from 10000 to 1000000
- // @Range: 10000 1000000
- // @User: Advanced
- // @RebootRequired: True
+ // @CopyFieldsFrom: CAN_BAUDRATE
GARRAY(can_baudrate, 2, "CAN3_BAUDRATE", 1000000),
// @Param: CAN3_PROTOCOL
- // @DisplayName: Enable use of specific protocol to be used on this port
- // @Description: Enabling this option starts selected protocol that will use this virtual driver. At least one CAN port must be UAVCAN or else CAN1 gets set to UAVCAN
- // @Values: 0:Disabled,1:UAVCAN,4:PiccoloCAN,5:CANTester,6:EFI_NWPMU,7:USD1,8:KDECAN
- // @User: Advanced
- // @RebootRequired: True
- GARRAY(can_protocol, 2, "CAN3_PROTOCOL", AP_CANManager::Driver_Type_DroneCAN),
+ // @CopyFieldsFrom: CAN_PROTOCOL
+ GARRAY(can_protocol, 2, "CAN3_PROTOCOL", float(AP_CAN::Protocol::DroneCAN)),
#endif
#if HAL_CANFD_SUPPORTED
@@ -158,11 +152,9 @@ const AP_Param::Info AP_Periph_FW::var_info[] = {
#if HAL_NUM_CAN_IFACES >= 2
// @Param: CAN2_FDBAUDRATE
+ // @CopyFieldsFrom: CAN_FDBAUDRATE
// @DisplayName: Set up bitrate for data section on CAN2
// @Description: This sets the bitrate for the data section of CAN2.
- // @Values: 1:1M, 2:2M, 4:4M, 5:5M, 8:8M
- // @User: Advanced
- // @RebootRequired: True
GARRAY(can_fdbaudrate, 1, "CAN2_FDBAUDRATE", HAL_CANFD_SUPPORTED),
#endif
#endif
@@ -179,7 +171,7 @@ const AP_Param::Info AP_Periph_FW::var_info[] = {
// @Param: DEBUG
// @DisplayName: Debug
// @Description: Debug
- // @Bitmask: 0:Disabled, 1:Show free stack space, 2:Auto Reboot after 15sec
+ // @Bitmask: 0:Disabled, 1:Show free stack space, 2:Auto Reboot after 15sec, 3:Enable sending stats
// @User: Advanced
GSCALAR(debug, "DEBUG", 0),
@@ -343,13 +335,13 @@ const AP_Param::Info AP_Periph_FW::var_info[] = {
GSCALAR(hardpoint_rate, "HARDPOINT_RATE", 100),
#endif
-#ifdef HAL_PERIPH_ENABLE_HWESC
+#if defined(HAL_PERIPH_ENABLE_HWESC) || defined(HAL_PERIPH_ENABLE_ESC_APD)
// @Param: ESC_NUMBER
// @DisplayName: ESC number
// @Description: This is the ESC number to report as in UAVCAN ESC telemetry feedback packets.
// @Increment: 1
// @User: Advanced
- GSCALAR(esc_number, "ESC_NUMBER", 0),
+ GARRAY(esc_number, 0, "ESC_NUMBER", 0),
#endif
#ifdef HAL_PERIPH_ENABLE_RC_OUT
@@ -483,7 +475,7 @@ const AP_Param::Info AP_Periph_FW::var_info[] = {
GOBJECT(efi, "EFI", AP_EFI),
#endif
-#ifdef HAL_PERIPH_ENABLE_PRX
+#if HAL_PROXIMITY_ENABLED
// @Param: PRX_BAUDRATE
// @DisplayName: Proximity Sensor serial baudrate
// @Description: Proximity Sensor serial baudrate.
@@ -515,7 +507,7 @@ const AP_Param::Info AP_Periph_FW::var_info[] = {
// @Group: PRX
// @Path: ../libraries/AP_Proximity/AP_Proximity.cpp
GOBJECT(proximity, "PRX", AP_Proximity),
-#endif
+#endif // HAL_PROXIMITY_ENABLED
#if HAL_NMEA_OUTPUT_ENABLED
// @Group: NMEA_
@@ -523,6 +515,72 @@ const AP_Param::Info AP_Periph_FW::var_info[] = {
GOBJECT(nmea, "NMEA_", AP_NMEA_Output),
#endif
+#if AP_KDECAN_ENABLED
+ // @Group: KDE_
+ // @Path: ../libraries/AP_KDECAN/AP_KDECAN.cpp
+ GOBJECT(kdecan, "KDE_", AP_KDECAN),
+#endif
+
+#if defined(HAL_PERIPH_ENABLE_ESC_APD)
+ GARRAY(pole_count, 0, "ESC_NUM_POLES", 22),
+#endif
+
+#if defined(HAL_PERIPH_ENABLE_ESC_APD)
+ // @Param: ESC_APD_SERIAL_1
+ // @DisplayName: ESC APD Serial 1
+ // @Description: Which serial port to use for APD ESC data
+ // @Range: 0 6
+ // @Increment: 1
+ // @User: Advanced
+ // @RebootRequired: True
+ GARRAY(esc_serial_port, 0, "ESC_APD_SERIAL_1", APD_ESC_SERIAL_0),
+
+ #if APD_ESC_INSTANCES > 1
+ GARRAY(esc_number, 1, "ESC_NUMBER2", 1),
+
+ GARRAY(pole_count, 1, "ESC_NUM_POLES2", 22),
+
+ // @Param: ESC_APD_SERIAL_2
+ // @DisplayName: ESC APD Serial 2
+ // @Description: Which serial port to use for APD ESC data
+ // @Range: 0 6
+ // @Increment: 1
+ // @User: Advanced
+ // @RebootRequired: True
+ GARRAY(esc_serial_port, 1, "ESC_APD_SERIAL_2", APD_ESC_SERIAL_1),
+ #endif
+#endif
+
+#ifdef HAL_PERIPH_ENABLE_NETWORKING
+ // @Group: NET_
+ // @Path: ../libraries/AP_Networking/AP_Networking.cpp
+ GOBJECT(networking, "NET_", AP_Networking),
+#endif
+
+#ifdef HAL_PERIPH_ENABLE_RPM
+ // @Group: RPM
+ // @Path: ../libraries/AP_RPM/AP_RPM.cpp
+ GOBJECT(rpm_sensor, "RPM", AP_RPM),
+#endif
+
+#ifdef HAL_PERIPH_ENABLE_RCIN
+ // @Group: RC
+ // @Path: rc_in.cpp
+ GOBJECT(g_rcin, "RC", Parameters_RCIN),
+#endif
+
+#if AP_SIM_ENABLED
+ // @Group: SIM_
+ // @Path: ../libraries/SITL/SITL.cpp
+ GOBJECT(sitl, "SIM_", SITL::SIM),
+
+#if AP_AHRS_ENABLED
+ // @Group: AHRS_
+ // @Path: ../libraries/AP_AHRS/AP_AHRS.cpp
+ GOBJECT(ahrs, "AHRS_", AP_AHRS),
+#endif
+#endif // AP_SIM_ENABLED
+
AP_VAREND
};
diff --git a/Tools/AP_Periph/Parameters.h b/Tools/AP_Periph/Parameters.h
index 63322b10d467c6..03b9ba62825dfb 100644
--- a/Tools/AP_Periph/Parameters.h
+++ b/Tools/AP_Periph/Parameters.h
@@ -30,7 +30,7 @@ class Parameters {
k_param_hardpoint_id,
k_param_hardpoint_rate,
k_param_baro_enable,
- k_param_esc_number,
+ k_param_esc_number0,
k_param_battery,
k_param_debug,
k_param_serial_number,
@@ -70,6 +70,17 @@ class Parameters {
k_param_proximity_port,
k_param_proximity_max_rate,
k_param_nmea,
+ k_param_kdecan,
+ k_param_pole_count0,
+ k_param_esc_serial_port0,
+ k_param_esc_number1,
+ k_param_pole_count1,
+ k_param_esc_serial_port1,
+ k_param_networking,
+ k_param_rpm_sensor,
+ k_param_g_rcin,
+ k_param_sitl,
+ k_param_ahrs,
};
AP_Int16 format_version;
@@ -77,7 +88,7 @@ class Parameters {
AP_Int32 can_baudrate[HAL_NUM_CAN_IFACES];
#if HAL_NUM_CAN_IFACES >= 2
- AP_Enum can_protocol[HAL_NUM_CAN_IFACES];
+ AP_Enum can_protocol[HAL_NUM_CAN_IFACES];
#endif
#if AP_CAN_SLCAN_ENABLED
@@ -103,7 +114,7 @@ class Parameters {
AP_Int16 rangefinder_max_rate;
#endif
-#ifdef HAL_PERIPH_ENABLE_PRX
+#if HAL_PROXIMITY_ENABLED
AP_Int32 proximity_baud;
AP_Int8 proximity_port;
AP_Int16 proximity_max_rate;
@@ -120,8 +131,21 @@ class Parameters {
AP_Int8 hardpoint_rate;
#endif
-#ifdef HAL_PERIPH_ENABLE_HWESC
- AP_Int8 esc_number;
+#if defined(HAL_PERIPH_ENABLE_HWESC) || defined(HAL_PERIPH_ENABLE_ESC_APD)
+ #if defined ESC_NUMBERS
+ #error "ESC_NUMBERS should not have been previously defined"
+ #endif
+ #if defined(APD_ESC_INSTANCES)
+ #define ESC_NUMBERS APD_ESC_INSTANCES
+ #else
+ #define ESC_NUMBERS 2
+ #endif // defined(APD_ESC_INSTANCES)
+ AP_Int8 esc_number[ESC_NUMBERS];
+ AP_Int8 esc_serial_port[ESC_NUMBERS];
+#endif
+
+#if defined(ESC_NUMBERS)
+ AP_Int8 pole_count[ESC_NUMBERS];
#endif
#ifdef HAL_PERIPH_ENABLE_GPS
@@ -169,6 +193,7 @@ class Parameters {
#else
static constexpr uint8_t can_fdmode = 0;
#endif
+ AP_Int8 node_stats;
Parameters() {}
};
diff --git a/Tools/AP_Periph/ReleaseNotes.txt b/Tools/AP_Periph/ReleaseNotes.txt
index 76666579839791..5165da3b526307 100644
--- a/Tools/AP_Periph/ReleaseNotes.txt
+++ b/Tools/AP_Periph/ReleaseNotes.txt
@@ -1,3 +1,19 @@
+Release 1.5.1 23rd July 2023
+---------------------------
+
+This is a major release with the following changes:
+
+- support serial tunnelling over DroneCAN
+- raised CAN priority of MovingBaseline data
+- support APD ESC telemetry
+- support DroneCAN and CAN statistics reporting
+- support KDECAN to DroneCAN translation
+
+The serial tunnelling support allows for uCenter to be used over
+DroneCAN with the serial tunnelling panel in the DroneCAN GUI
+tool. This allows for monitoring of uBlox GPS over a telemetry link,
+and update of F9P firmware over DroneCAN
+
Release 1.5.0 27th Mar 2023
---------------------------
diff --git a/Tools/AP_Periph/adsb.cpp b/Tools/AP_Periph/adsb.cpp
index 0e44461eb7ff36..fe80b39081ec89 100644
--- a/Tools/AP_Periph/adsb.cpp
+++ b/Tools/AP_Periph/adsb.cpp
@@ -23,6 +23,7 @@
#ifdef HAL_PERIPH_ENABLE_ADSB
#include
+#include
extern const AP_HAL::HAL &hal;
@@ -52,6 +53,15 @@ void AP_Periph_FW::adsb_init(void)
}
}
+static mavlink_message_t chan_buffer;
+mavlink_message_t* mavlink_get_channel_buffer(uint8_t chan) {
+ return &chan_buffer;
+}
+
+static mavlink_status_t chan_status;
+mavlink_status_t* mavlink_get_channel_status(uint8_t chan) {
+ return &chan_status;
+}
/*
update ADSB subsystem
@@ -84,4 +94,62 @@ void AP_Periph_FW::adsb_update(void)
}
}
+/*
+ map an ADSB_VEHICLE MAVLink message to a UAVCAN TrafficReport message
+ */
+void AP_Periph_FW::can_send_ADSB(struct __mavlink_adsb_vehicle_t &msg)
+{
+ ardupilot_equipment_trafficmonitor_TrafficReport pkt {};
+ pkt.timestamp.usec = 0;
+ pkt.icao_address = msg.ICAO_address;
+ pkt.tslc = msg.tslc;
+ pkt.latitude_deg_1e7 = msg.lat;
+ pkt.longitude_deg_1e7 = msg.lon;
+ pkt.alt_m = msg.altitude * 1e-3;
+
+ pkt.heading = radians(msg.heading * 1e-2);
+
+ pkt.velocity[0] = cosf(pkt.heading) * msg.hor_velocity * 1e-2;
+ pkt.velocity[1] = sinf(pkt.heading) * msg.hor_velocity * 1e-2;
+ pkt.velocity[2] = -msg.ver_velocity * 1e-2;
+
+ pkt.squawk = msg.squawk;
+ memcpy(pkt.callsign, msg.callsign, MIN(sizeof(msg.callsign),sizeof(pkt.callsign)));
+ if (msg.flags & 0x8000) {
+ pkt.source = ARDUPILOT_EQUIPMENT_TRAFFICMONITOR_TRAFFICREPORT_SOURCE_ADSB_UAT;
+ } else {
+ pkt.source = ARDUPILOT_EQUIPMENT_TRAFFICMONITOR_TRAFFICREPORT_SOURCE_ADSB;
+ }
+
+ pkt.traffic_type = msg.emitter_type;
+
+ if ((msg.flags & ADSB_FLAGS_VALID_ALTITUDE) != 0 && msg.altitude_type == 0) {
+ pkt.alt_type = ARDUPILOT_EQUIPMENT_TRAFFICMONITOR_TRAFFICREPORT_ALT_TYPE_PRESSURE_AMSL;
+ } else if ((msg.flags & ADSB_FLAGS_VALID_ALTITUDE) != 0 && msg.altitude_type == 1) {
+ pkt.alt_type = ARDUPILOT_EQUIPMENT_TRAFFICMONITOR_TRAFFICREPORT_ALT_TYPE_WGS84;
+ } else {
+ pkt.alt_type = ARDUPILOT_EQUIPMENT_TRAFFICMONITOR_TRAFFICREPORT_ALT_TYPE_ALT_UNKNOWN;
+ }
+
+ pkt.lat_lon_valid = (msg.flags & ADSB_FLAGS_VALID_COORDS) != 0;
+ pkt.heading_valid = (msg.flags & ADSB_FLAGS_VALID_HEADING) != 0;
+ pkt.velocity_valid = (msg.flags & ADSB_FLAGS_VALID_VELOCITY) != 0;
+ pkt.callsign_valid = (msg.flags & ADSB_FLAGS_VALID_CALLSIGN) != 0;
+ pkt.ident_valid = (msg.flags & ADSB_FLAGS_VALID_SQUAWK) != 0;
+ pkt.simulated_report = (msg.flags & ADSB_FLAGS_SIMULATED) != 0;
+
+ // these flags are not in common.xml
+ pkt.vertical_velocity_valid = (msg.flags & 0x0080) != 0;
+ pkt.baro_valid = (msg.flags & 0x0100) != 0;
+
+ uint8_t buffer[ARDUPILOT_EQUIPMENT_TRAFFICMONITOR_TRAFFICREPORT_MAX_SIZE] {};
+ uint16_t total_size = ardupilot_equipment_trafficmonitor_TrafficReport_encode(&pkt, buffer, !periph.canfdout());
+
+ canard_broadcast(ARDUPILOT_EQUIPMENT_TRAFFICMONITOR_TRAFFICREPORT_SIGNATURE,
+ ARDUPILOT_EQUIPMENT_TRAFFICMONITOR_TRAFFICREPORT_ID,
+ CANARD_TRANSFER_PRIORITY_LOWEST,
+ &buffer[0],
+ total_size);
+}
+
#endif // HAL_PERIPH_ENABLE_ADSB
diff --git a/Tools/AP_Periph/can.cpp b/Tools/AP_Periph/can.cpp
index 1c340a9e12b28f..d35568f4f4c848 100644
--- a/Tools/AP_Periph/can.cpp
+++ b/Tools/AP_Periph/can.cpp
@@ -59,6 +59,8 @@ extern AP_Periph_FW periph;
#ifndef HAL_CAN_POOL_SIZE
#if HAL_CANFD_SUPPORTED
#define HAL_CAN_POOL_SIZE 16000
+#elif GPS_MOVING_BASELINE
+ #define HAL_CAN_POOL_SIZE 8000
#else
#define HAL_CAN_POOL_SIZE 4000
#endif
@@ -122,7 +124,7 @@ static struct dronecan_protocol_t {
uint8_t dna_interface = 1;
} dronecan;
-#if CONFIG_HAL_BOARD == HAL_BOARD_CHIBIOS && defined(HAL_GPIO_PIN_TERMCAN1)
+#if CONFIG_HAL_BOARD == HAL_BOARD_CHIBIOS && defined(HAL_GPIO_PIN_TERMCAN1) && (HAL_NUM_CAN_IFACES >= 2)
static ioline_t can_term_lines[] = {
HAL_GPIO_PIN_TERMCAN1
@@ -180,7 +182,9 @@ SLCAN::CANIface AP_Periph_FW::slcan_interface;
* Node status variables
*/
static uavcan_protocol_NodeStatus node_status;
-
+#if HAL_ENABLE_SENDING_STATS
+static dronecan_protocol_Stats protocol_stats;
+#endif
/**
* Returns a pseudo random integer in a given range
*/
@@ -204,13 +208,13 @@ static void readUniqueID(uint8_t* out_uid)
/*
handle a GET_NODE_INFO request
*/
-static void handle_get_node_info(CanardInstance* ins,
+static void handle_get_node_info(CanardInstance* canard_instance,
CanardRxTransfer* transfer)
{
uint8_t buffer[UAVCAN_PROTOCOL_GETNODEINFO_RESPONSE_MAX_SIZE] {};
uavcan_protocol_GetNodeInfoResponse pkt {};
- node_status.uptime_sec = AP_HAL::native_millis() / 1000U;
+ node_status.uptime_sec = AP_HAL::millis() / 1000U;
pkt.status = node_status;
pkt.software_version.major = AP::fwversion().major;
@@ -237,7 +241,7 @@ static void handle_get_node_info(CanardInstance* ins,
uint16_t total_size = uavcan_protocol_GetNodeInfoResponse_encode(&pkt, buffer, !periph.canfdout());
- const int16_t resp_res = canardRequestOrRespond(ins,
+ const int16_t resp_res = canardRequestOrRespond(canard_instance,
transfer->source_node_id,
UAVCAN_PROTOCOL_GETNODEINFO_SIGNATURE,
UAVCAN_PROTOCOL_GETNODEINFO_ID,
@@ -261,7 +265,7 @@ static void handle_get_node_info(CanardInstance* ins,
/*
handle parameter GetSet request
*/
-static void handle_param_getset(CanardInstance* ins, CanardRxTransfer* transfer)
+static void handle_param_getset(CanardInstance* canard_instance, CanardRxTransfer* transfer)
{
// param fetch all can take a long time, so pat watchdog
stm32_watchdog_pat();
@@ -346,7 +350,7 @@ static void handle_param_getset(CanardInstance* ins, CanardRxTransfer* transfer)
uint8_t buffer[UAVCAN_PROTOCOL_PARAM_GETSET_RESPONSE_MAX_SIZE] {};
uint16_t total_size = uavcan_protocol_param_GetSetResponse_encode(&pkt, buffer, !periph.canfdout());
- canardRequestOrRespond(ins,
+ canardRequestOrRespond(canard_instance,
transfer->source_node_id,
UAVCAN_PROTOCOL_PARAM_GETSET_SIGNATURE,
UAVCAN_PROTOCOL_PARAM_GETSET_ID,
@@ -368,7 +372,7 @@ static void handle_param_getset(CanardInstance* ins, CanardRxTransfer* transfer)
/*
handle parameter executeopcode request
*/
-static void handle_param_executeopcode(CanardInstance* ins, CanardRxTransfer* transfer)
+static void handle_param_executeopcode(CanardInstance* canard_instance, CanardRxTransfer* transfer)
{
uavcan_protocol_param_ExecuteOpcodeRequest req;
if (uavcan_protocol_param_ExecuteOpcodeRequest_decode(transfer, &req)) {
@@ -406,7 +410,7 @@ static void handle_param_executeopcode(CanardInstance* ins, CanardRxTransfer* tr
uint8_t buffer[UAVCAN_PROTOCOL_PARAM_EXECUTEOPCODE_RESPONSE_MAX_SIZE] {};
uint16_t total_size = uavcan_protocol_param_ExecuteOpcodeResponse_encode(&pkt, buffer, !periph.canfdout());
- canardRequestOrRespond(ins,
+ canardRequestOrRespond(canard_instance,
transfer->source_node_id,
UAVCAN_PROTOCOL_PARAM_EXECUTEOPCODE_SIGNATURE,
UAVCAN_PROTOCOL_PARAM_EXECUTEOPCODE_ID,
@@ -424,15 +428,10 @@ static void handle_param_executeopcode(CanardInstance* ins, CanardRxTransfer* tr
);
}
-static void canard_broadcast(uint64_t data_type_signature,
- uint16_t data_type_id,
- uint8_t priority,
- const void* payload,
- uint16_t payload_len);
static void processTx(void);
static void processRx(void);
-static void handle_begin_firmware_update(CanardInstance* ins, CanardRxTransfer* transfer)
+static void handle_begin_firmware_update(CanardInstance* canard_instance, CanardRxTransfer* transfer)
{
#if HAL_RAM_RESERVE_START >= 256
// setup information on firmware request at start of ram
@@ -450,14 +449,14 @@ static void handle_begin_firmware_update(CanardInstance* ins, CanardRxTransfer*
comms->server_node_id = transfer->source_node_id;
}
memcpy(comms->path, req.image_file_remote_path.path.data, req.image_file_remote_path.path.len);
- comms->my_node_id = canardGetLocalNodeID(ins);
+ comms->my_node_id = canardGetLocalNodeID(canard_instance);
uint8_t buffer[UAVCAN_PROTOCOL_FILE_BEGINFIRMWAREUPDATE_RESPONSE_MAX_SIZE] {};
uavcan_protocol_file_BeginFirmwareUpdateResponse reply {};
reply.error = UAVCAN_PROTOCOL_FILE_BEGINFIRMWAREUPDATE_RESPONSE_ERROR_OK;
uint32_t total_size = uavcan_protocol_file_BeginFirmwareUpdateResponse_encode(&reply, buffer, !periph.canfdout());
- canardRequestOrRespond(ins,
+ canardRequestOrRespond(canard_instance,
transfer->source_node_id,
UAVCAN_PROTOCOL_FILE_BEGINFIRMWAREUPDATE_SIGNATURE,
UAVCAN_PROTOCOL_FILE_BEGINFIRMWAREUPDATE_ID,
@@ -484,16 +483,16 @@ static void handle_begin_firmware_update(CanardInstance* ins, CanardRxTransfer*
// the node_id
periph.prepare_reboot();
#if CONFIG_HAL_BOARD == HAL_BOARD_CHIBIOS
- set_fast_reboot((rtc_boot_magic)(RTC_BOOT_CANBL | canardGetLocalNodeID(ins)));
+ set_fast_reboot((rtc_boot_magic)(RTC_BOOT_CANBL | canardGetLocalNodeID(canard_instance)));
NVIC_SystemReset();
#endif
}
-static void handle_allocation_response(CanardInstance* ins, CanardRxTransfer* transfer)
+static void handle_allocation_response(CanardInstance* canard_instance, CanardRxTransfer* transfer)
{
// Rule C - updating the randomized time interval
dronecan.send_next_node_id_allocation_request_at_ms =
- AP_HAL::native_millis() + UAVCAN_PROTOCOL_DYNAMIC_NODE_ID_ALLOCATION_MIN_REQUEST_PERIOD_MS +
+ AP_HAL::millis() + UAVCAN_PROTOCOL_DYNAMIC_NODE_ID_ALLOCATION_MIN_REQUEST_PERIOD_MS +
get_random_range(UAVCAN_PROTOCOL_DYNAMIC_NODE_ID_ALLOCATION_MAX_FOLLOWUP_DELAY_MS);
if (transfer->source_node_id == CANARD_BROADCAST_NODE_ID)
@@ -527,7 +526,7 @@ static void handle_allocation_response(CanardInstance* ins, CanardRxTransfer* tr
printf("Matching allocation response: %d\n", msg.unique_id.len);
} else {
// Allocation complete - copying the allocated node ID from the message
- canardSetLocalNodeID(ins, msg.node_id);
+ canardSetLocalNodeID(canard_instance, msg.node_id);
printf("IF%d Node ID allocated: %d\n", dronecan.dna_interface, msg.node_id);
#if defined(HAL_PERIPH_ENABLE_GPS) && (HAL_NUM_CAN_IFACES >= 2) && GPS_MOVING_BASELINE
@@ -553,7 +552,7 @@ static uint32_t buzzer_len_ms;
/*
handle BeepCommand
*/
-static void handle_beep_command(CanardInstance* ins, CanardRxTransfer* transfer)
+static void handle_beep_command(CanardInstance* canard_instance, CanardRxTransfer* transfer)
{
uavcan_equipment_indication_BeepCommand req;
if (uavcan_equipment_indication_BeepCommand_decode(transfer, &req)) {
@@ -565,7 +564,7 @@ static void handle_beep_command(CanardInstance* ins, CanardRxTransfer* transfer)
hal.rcout->init();
hal.util->toneAlarm_init(AP_Notify::Notify_Buzz_Builtin);
}
- buzzer_start_ms = AP_HAL::native_millis();
+ buzzer_start_ms = AP_HAL::millis();
buzzer_len_ms = req.duration*1000;
#ifdef HAL_PERIPH_ENABLE_BUZZER_WITHOUT_NOTIFY
float volume = constrain_float(periph.g.buzz_volume/100.0f, 0, 1);
@@ -581,7 +580,7 @@ static void handle_beep_command(CanardInstance* ins, CanardRxTransfer* transfer)
static void can_buzzer_update(void)
{
if (buzzer_start_ms != 0) {
- uint32_t now = AP_HAL::native_millis();
+ uint32_t now = AP_HAL::millis();
if (now - buzzer_start_ms > buzzer_len_ms) {
hal.util->toneAlarm_set_buzzer_tone(0, 0, 0);
buzzer_start_ms = 0;
@@ -596,7 +595,7 @@ static uint8_t safety_state;
/*
handle SafetyState
*/
-static void handle_safety_state(CanardInstance* ins, CanardRxTransfer* transfer)
+static void handle_safety_state(CanardInstance* canard_instance, CanardRxTransfer* transfer)
{
ardupilot_indication_SafetyState req;
if (ardupilot_indication_SafetyState_decode(transfer, &req)) {
@@ -612,7 +611,7 @@ static void handle_safety_state(CanardInstance* ins, CanardRxTransfer* transfer)
/*
handle ArmingStatus
*/
-static void handle_arming_status(CanardInstance* ins, CanardRxTransfer* transfer)
+static void handle_arming_status(CanardInstance* canard_instance, CanardRxTransfer* transfer)
{
uavcan_equipment_safety_ArmingStatus req;
if (uavcan_equipment_safety_ArmingStatus_decode(transfer, &req)) {
@@ -625,7 +624,7 @@ static void handle_arming_status(CanardInstance* ins, CanardRxTransfer* transfer
/*
handle gnss::RTCMStream
*/
-static void handle_RTCMStream(CanardInstance* ins, CanardRxTransfer* transfer)
+static void handle_RTCMStream(CanardInstance* canard_instance, CanardRxTransfer* transfer)
{
uavcan_equipment_gnss_RTCMStream req;
if (uavcan_equipment_gnss_RTCMStream_decode(transfer, &req)) {
@@ -638,7 +637,7 @@ static void handle_RTCMStream(CanardInstance* ins, CanardRxTransfer* transfer)
handle gnss::MovingBaselineData
*/
#if GPS_MOVING_BASELINE
-static void handle_MovingBaselineData(CanardInstance* ins, CanardRxTransfer* transfer)
+static void handle_MovingBaselineData(CanardInstance* canard_instance, CanardRxTransfer* transfer)
{
ardupilot_gnss_MovingBaselineData msg;
if (ardupilot_gnss_MovingBaselineData_decode(transfer, &msg)) {
@@ -737,7 +736,7 @@ static void set_rgb_led(uint8_t red, uint8_t green, uint8_t blue)
/*
handle lightscommand
*/
-static void handle_lightscommand(CanardInstance* ins, CanardRxTransfer* transfer)
+static void handle_lightscommand(CanardInstance* canard_instance, CanardRxTransfer* transfer)
{
uavcan_equipment_indication_LightsCommand req;
if (uavcan_equipment_indication_LightsCommand_decode(transfer, &req)) {
@@ -767,7 +766,7 @@ static void handle_lightscommand(CanardInstance* ins, CanardRxTransfer* transfer
#endif // AP_PERIPH_HAVE_LED_WITHOUT_NOTIFY
#ifdef HAL_PERIPH_ENABLE_RC_OUT
-static void handle_esc_rawcommand(CanardInstance* ins, CanardRxTransfer* transfer)
+static void handle_esc_rawcommand(CanardInstance* canard_instance, CanardRxTransfer* transfer)
{
uavcan_equipment_esc_RawCommand cmd;
if (uavcan_equipment_esc_RawCommand_decode(transfer, &cmd)) {
@@ -780,7 +779,7 @@ static void handle_esc_rawcommand(CanardInstance* ins, CanardRxTransfer* transfe
periph.last_esc_raw_command_ms = AP_HAL::millis();
}
-static void handle_act_command(CanardInstance* ins, CanardRxTransfer* transfer)
+static void handle_act_command(CanardInstance* canard_instance, CanardRxTransfer* transfer)
{
uavcan_equipment_actuator_ArrayCommand cmd;
if (uavcan_equipment_actuator_ArrayCommand_decode(transfer, &cmd)) {
@@ -802,7 +801,7 @@ static void handle_act_command(CanardInstance* ins, CanardRxTransfer* transfer)
#endif // HAL_PERIPH_ENABLE_RC_OUT
#if defined(HAL_PERIPH_ENABLE_NOTIFY)
-static void handle_notify_state(CanardInstance* ins, CanardRxTransfer* transfer)
+static void handle_notify_state(CanardInstance* canard_instance, CanardRxTransfer* transfer)
{
ardupilot_indication_NotifyState msg;
if (ardupilot_indication_NotifyState_decode(transfer, &msg)) {
@@ -830,7 +829,7 @@ static void can_safety_LED_update(void)
palWriteLine(HAL_GPIO_PIN_SAFE_LED, SAFE_LED_ON);
break;
case ARDUPILOT_INDICATION_SAFETYSTATE_STATUS_SAFETY_ON: {
- uint32_t now = AP_HAL::native_millis();
+ uint32_t now = AP_HAL::millis();
if (now - last_update_ms > 100) {
last_update_ms = now;
static uint8_t led_counter;
@@ -859,7 +858,7 @@ static void can_safety_button_update(void)
{
static uint32_t last_update_ms;
static uint8_t counter;
- uint32_t now = AP_HAL::native_millis();
+ uint32_t now = AP_HAL::millis();
// send at 10Hz when pressed
if (palReadLine(HAL_GPIO_PIN_SAFE_BUTTON) != HAL_SAFE_BUTTON_ON) {
counter = 0;
@@ -880,18 +879,18 @@ static void can_safety_button_update(void)
uint8_t buffer[ARDUPILOT_INDICATION_BUTTON_MAX_SIZE] {};
uint16_t total_size = ardupilot_indication_Button_encode(&pkt, buffer, !periph.canfdout());
- canard_broadcast(ARDUPILOT_INDICATION_BUTTON_SIGNATURE,
- ARDUPILOT_INDICATION_BUTTON_ID,
- CANARD_TRANSFER_PRIORITY_LOW,
- &buffer[0],
- total_size);
+ periph.canard_broadcast(ARDUPILOT_INDICATION_BUTTON_SIGNATURE,
+ ARDUPILOT_INDICATION_BUTTON_ID,
+ CANARD_TRANSFER_PRIORITY_LOW,
+ &buffer[0],
+ total_size);
}
#endif // HAL_GPIO_PIN_SAFE_BUTTON
/**
* This callback is invoked by the library when a new message or request or response is received.
*/
-static void onTransferReceived(CanardInstance* ins,
+static void onTransferReceived(CanardInstance* canard_instance,
CanardRxTransfer* transfer)
{
#ifdef HAL_GPIO_PIN_LED_CAN1
@@ -907,21 +906,21 @@ static void onTransferReceived(CanardInstance* ins,
* Dynamic node ID allocation protocol.
* Taking this branch only if we don't have a node ID, ignoring otherwise.
*/
- if (canardGetLocalNodeID(ins) == CANARD_BROADCAST_NODE_ID) {
+ if (canardGetLocalNodeID(canard_instance) == CANARD_BROADCAST_NODE_ID) {
if (transfer->transfer_type == CanardTransferTypeBroadcast &&
transfer->data_type_id == UAVCAN_PROTOCOL_DYNAMIC_NODE_ID_ALLOCATION_ID) {
- handle_allocation_response(ins, transfer);
+ handle_allocation_response(canard_instance, transfer);
}
return;
}
switch (transfer->data_type_id) {
case UAVCAN_PROTOCOL_GETNODEINFO_ID:
- handle_get_node_info(ins, transfer);
+ handle_get_node_info(canard_instance, transfer);
break;
case UAVCAN_PROTOCOL_FILE_BEGINFIRMWAREUPDATE_ID:
- handle_begin_firmware_update(ins, transfer);
+ handle_begin_firmware_update(canard_instance, transfer);
break;
case UAVCAN_PROTOCOL_RESTARTNODE_ID:
@@ -936,60 +935,66 @@ static void onTransferReceived(CanardInstance* ins,
break;
case UAVCAN_PROTOCOL_PARAM_GETSET_ID:
- handle_param_getset(ins, transfer);
+ handle_param_getset(canard_instance, transfer);
break;
case UAVCAN_PROTOCOL_PARAM_EXECUTEOPCODE_ID:
- handle_param_executeopcode(ins, transfer);
+ handle_param_executeopcode(canard_instance, transfer);
break;
#if defined(HAL_PERIPH_ENABLE_BUZZER_WITHOUT_NOTIFY) || defined (HAL_PERIPH_ENABLE_NOTIFY)
case UAVCAN_EQUIPMENT_INDICATION_BEEPCOMMAND_ID:
- handle_beep_command(ins, transfer);
+ handle_beep_command(canard_instance, transfer);
break;
#endif
#if defined(HAL_GPIO_PIN_SAFE_LED) || defined(HAL_PERIPH_ENABLE_RC_OUT)
case ARDUPILOT_INDICATION_SAFETYSTATE_ID:
- handle_safety_state(ins, transfer);
+ handle_safety_state(canard_instance, transfer);
break;
#endif
case UAVCAN_EQUIPMENT_SAFETY_ARMINGSTATUS_ID:
- handle_arming_status(ins, transfer);
+ handle_arming_status(canard_instance, transfer);
break;
#ifdef HAL_PERIPH_ENABLE_GPS
case UAVCAN_EQUIPMENT_GNSS_RTCMSTREAM_ID:
- handle_RTCMStream(ins, transfer);
+ handle_RTCMStream(canard_instance, transfer);
break;
#if GPS_MOVING_BASELINE
case ARDUPILOT_GNSS_MOVINGBASELINEDATA_ID:
- handle_MovingBaselineData(ins, transfer);
+ handle_MovingBaselineData(canard_instance, transfer);
break;
#endif
+#endif // HAL_PERIPH_ENABLE_GPS
+
+#if AP_UART_MONITOR_ENABLED
+ case UAVCAN_TUNNEL_TARGETTED_ID:
+ periph.handle_tunnel_Targetted(canard_instance, transfer);
+ break;
#endif
-
+
#if defined(AP_PERIPH_HAVE_LED_WITHOUT_NOTIFY) || defined(HAL_PERIPH_ENABLE_NOTIFY)
case UAVCAN_EQUIPMENT_INDICATION_LIGHTSCOMMAND_ID:
- handle_lightscommand(ins, transfer);
+ handle_lightscommand(canard_instance, transfer);
break;
#endif
#ifdef HAL_PERIPH_ENABLE_RC_OUT
case UAVCAN_EQUIPMENT_ESC_RAWCOMMAND_ID:
- handle_esc_rawcommand(ins, transfer);
+ handle_esc_rawcommand(canard_instance, transfer);
break;
case UAVCAN_EQUIPMENT_ACTUATOR_ARRAYCOMMAND_ID:
- handle_act_command(ins, transfer);
+ handle_act_command(canard_instance, transfer);
break;
#endif
#ifdef HAL_PERIPH_ENABLE_NOTIFY
case ARDUPILOT_INDICATION_NOTIFYSTATE_ID:
- handle_notify_state(ins, transfer);
+ handle_notify_state(canard_instance, transfer);
break;
#endif
}
@@ -1003,7 +1008,7 @@ static void onTransferReceived(CanardInstance* ins,
* If the callback returns false, the library will ignore the transfer.
* All transfers that are addressed to other nodes are always ignored.
*/
-static bool shouldAcceptTransfer(const CanardInstance* ins,
+static bool shouldAcceptTransfer(const CanardInstance* canard_instance,
uint64_t* out_data_type_signature,
uint16_t data_type_id,
CanardTransferType transfer_type,
@@ -1011,7 +1016,7 @@ static bool shouldAcceptTransfer(const CanardInstance* ins,
{
(void)source_node_id;
- if (canardGetLocalNodeID(ins) == CANARD_BROADCAST_NODE_ID)
+ if (canardGetLocalNodeID(canard_instance) == CANARD_BROADCAST_NODE_ID)
{
/*
* If we're in the process of allocation of dynamic node ID, accept only relevant transfers.
@@ -1069,7 +1074,14 @@ static bool shouldAcceptTransfer(const CanardInstance* ins,
*out_data_type_signature = ARDUPILOT_GNSS_MOVINGBASELINEDATA_SIGNATURE;
return true;
#endif
+#endif // HAL_PERIPH_ENABLE_GPS
+
+#if AP_UART_MONITOR_ENABLED
+ case UAVCAN_TUNNEL_TARGETTED_ID:
+ *out_data_type_signature = UAVCAN_TUNNEL_TARGETTED_SIGNATURE;
+ return true;
#endif
+
#ifdef HAL_PERIPH_ENABLE_RC_OUT
case UAVCAN_EQUIPMENT_ESC_RAWCOMMAND_ID:
*out_data_type_signature = UAVCAN_EQUIPMENT_ESC_RAWCOMMAND_SIGNATURE;
@@ -1134,24 +1146,22 @@ static uint8_t* get_tid_ptr(uint32_t transfer_desc)
return &tid_map_ptr->next->tid;
}
-static void canard_broadcast(uint64_t data_type_signature,
- uint16_t data_type_id,
- uint8_t priority,
- const void* payload,
- uint16_t payload_len)
+bool AP_Periph_FW::canard_broadcast(uint64_t data_type_signature,
+ uint16_t data_type_id,
+ uint8_t priority,
+ const void* payload,
+ uint16_t payload_len)
{
if (canardGetLocalNodeID(&dronecan.canard) == CANARD_BROADCAST_NODE_ID) {
- return;
+ return false;
}
uint8_t *tid_ptr = get_tid_ptr(MAKE_TRANSFER_DESCRIPTOR(data_type_signature, data_type_id, 0, CANARD_BROADCAST_NODE_ID));
if (tid_ptr == nullptr) {
- return;
+ return false;
}
-#if DEBUG_PKTS
- const int16_t res =
-#endif
- canardBroadcast(&dronecan.canard,
+
+ const int16_t res = canardBroadcast(&dronecan.canard,
data_type_signature,
data_type_id,
tid_ptr,
@@ -1171,6 +1181,14 @@ static void canard_broadcast(uint64_t data_type_signature,
can_printf("Tx error %d\n", res);
}
#endif
+#if HAL_ENABLE_SENDING_STATS
+ if (res <= 0) {
+ protocol_stats.tx_errors++;
+ } else {
+ protocol_stats.tx_frames += res;
+ }
+#endif
+ return res > 0;
}
static void processTx(void)
@@ -1185,23 +1203,23 @@ static void processTx(void)
#endif
// push message with 1s timeout
bool sent = true;
- const uint64_t deadline = AP_HAL::native_micros64() + 1000000;
+ const uint64_t deadline = AP_HAL::micros64() + 1000000;
// try sending to all interfaces
- for (auto &ins : instances) {
- if (ins.iface == NULL) {
+ for (auto &_ins : instances) {
+ if (_ins.iface == NULL) {
continue;
}
#if CANARD_MULTI_IFACE
- if (!(txf->iface_mask & (1U<iface_mask & (1U<<_ins.index))) {
continue;
}
#endif
#if HAL_NUM_CAN_IFACES >= 2
- if (periph.can_protocol_cached[ins.index] != AP_CANManager::Driver_Type_DroneCAN) {
+ if (periph.can_protocol_cached[_ins.index] != AP_CAN::Protocol::DroneCAN) {
continue;
}
#endif
- if (ins.iface->send(txmsg, deadline, 0) <= 0) {
+ if (_ins.iface->send(txmsg, deadline, 0) <= 0) {
sent = false;
}
}
@@ -1214,6 +1232,9 @@ static void processTx(void)
if (dronecan.tx_fail_count < 8) {
dronecan.tx_fail_count++;
} else {
+#if HAL_ENABLE_SENDING_STATS
+ protocol_stats.tx_errors++;
+#endif
canardPopTxQueue(&dronecan.canard);
}
break;
@@ -1221,6 +1242,51 @@ static void processTx(void)
}
}
+#if HAL_ENABLE_SENDING_STATS
+static void update_rx_protocol_stats(int16_t res)
+{
+ switch (res) {
+ case CANARD_OK:
+ protocol_stats.rx_frames++;
+ break;
+ case -CANARD_ERROR_OUT_OF_MEMORY:
+ protocol_stats.rx_error_oom++;
+ break;
+ case -CANARD_ERROR_INTERNAL:
+ protocol_stats.rx_error_internal++;
+ break;
+ case -CANARD_ERROR_RX_INCOMPATIBLE_PACKET:
+ protocol_stats.rx_ignored_not_wanted++;
+ break;
+ case -CANARD_ERROR_RX_WRONG_ADDRESS:
+ protocol_stats.rx_ignored_wrong_address++;
+ break;
+ case -CANARD_ERROR_RX_NOT_WANTED:
+ protocol_stats.rx_ignored_not_wanted++;
+ break;
+ case -CANARD_ERROR_RX_MISSED_START:
+ protocol_stats.rx_error_missed_start++;
+ break;
+ case -CANARD_ERROR_RX_WRONG_TOGGLE:
+ protocol_stats.rx_error_wrong_toggle++;
+ break;
+ case -CANARD_ERROR_RX_UNEXPECTED_TID:
+ protocol_stats.rx_ignored_unexpected_tid++;
+ break;
+ case -CANARD_ERROR_RX_SHORT_FRAME:
+ protocol_stats.rx_error_short_frame++;
+ break;
+ case -CANARD_ERROR_RX_BAD_CRC:
+ protocol_stats.rx_error_bad_crc++;
+ break;
+ default:
+ // mark all other errors as internal
+ protocol_stats.rx_error_internal++;
+ break;
+ }
+}
+#endif
+
static void processRx(void)
{
AP_HAL::CANFrame rxmsg;
@@ -1229,7 +1295,7 @@ static void processRx(void)
continue;
}
#if HAL_NUM_CAN_IFACES >= 2
- if (periph.can_protocol_cached[ins.index] != AP_CANManager::Driver_Type_DroneCAN) {
+ if (periph.can_protocol_cached[ins.index] != AP_CAN::Protocol::DroneCAN) {
continue;
}
#endif
@@ -1257,21 +1323,26 @@ static void processRx(void)
#if CANARD_MULTI_IFACE
rx_frame.iface_id = ins.index;
#endif
-#if DEBUG_PKTS
- const int16_t res =
-#endif
- canardHandleRxFrame(&dronecan.canard, &rx_frame, timestamp);
-#if DEBUG_PKTS
- if (res < 0 &&
- res != -CANARD_ERROR_RX_NOT_WANTED &&
- res != -CANARD_ERROR_RX_WRONG_ADDRESS &&
- res != -CANARD_ERROR_RX_MISSED_START) {
- printf("Rx error %d, IF%d %lx: ", res, ins.index, rx_frame.id);
- for (uint8_t i = 0; i < rx_frame.data_len; i++) {
- printf("%02x", rx_frame.data[i]);
+
+ const int16_t res = canardHandleRxFrame(&dronecan.canard, &rx_frame, timestamp);
+#if HAL_ENABLE_SENDING_STATS
+ if (res == -CANARD_ERROR_RX_MISSED_START) {
+ // this might remaining frames from a message that we don't accept, so check
+ uint64_t dummy_signature;
+ if (shouldAcceptTransfer(&dronecan.canard,
+ &dummy_signature,
+ extractDataType(rx_frame.id),
+ extractTransferType(rx_frame.id),
+ 1)) { // doesn't matter what we pass here
+ update_rx_protocol_stats(res);
+ } else {
+ protocol_stats.rx_ignored_not_wanted++;
}
- printf("\n");
+ } else {
+ update_rx_protocol_stats(res);
}
+#else
+ (void)res;
#endif
}
}
@@ -1286,18 +1357,58 @@ static uint16_t pool_peak_percent()
static void node_status_send(void)
{
- uint8_t buffer[UAVCAN_PROTOCOL_NODESTATUS_MAX_SIZE];
- node_status.uptime_sec = AP_HAL::millis() / 1000U;
+ {
+ uint8_t buffer[UAVCAN_PROTOCOL_NODESTATUS_MAX_SIZE];
+ node_status.uptime_sec = AP_HAL::millis() / 1000U;
- node_status.vendor_specific_status_code = hal.util->available_memory();
+ node_status.vendor_specific_status_code = hal.util->available_memory();
- uint32_t len = uavcan_protocol_NodeStatus_encode(&node_status, buffer, !periph.canfdout());
+ uint32_t len = uavcan_protocol_NodeStatus_encode(&node_status, buffer, !periph.canfdout());
- canard_broadcast(UAVCAN_PROTOCOL_NODESTATUS_SIGNATURE,
- UAVCAN_PROTOCOL_NODESTATUS_ID,
- CANARD_TRANSFER_PRIORITY_LOW,
- buffer,
- len);
+ periph.canard_broadcast(UAVCAN_PROTOCOL_NODESTATUS_SIGNATURE,
+ UAVCAN_PROTOCOL_NODESTATUS_ID,
+ CANARD_TRANSFER_PRIORITY_LOW,
+ buffer,
+ len);
+ }
+#if HAL_ENABLE_SENDING_STATS
+ if (periph.debug_option_is_set(AP_Periph_FW::DebugOptions::ENABLE_STATS)) {
+ {
+ uint8_t buffer[DRONECAN_PROTOCOL_STATS_MAX_SIZE];
+ uint32_t len = dronecan_protocol_Stats_encode(&protocol_stats, buffer, !periph.canfdout());
+ periph.canard_broadcast(DRONECAN_PROTOCOL_STATS_SIGNATURE,
+ DRONECAN_PROTOCOL_STATS_ID,
+ CANARD_TRANSFER_PRIORITY_LOWEST,
+ buffer,
+ len);
+ }
+ for (auto &ins : instances) {
+ uint8_t buffer[DRONECAN_PROTOCOL_CANSTATS_MAX_SIZE];
+ dronecan_protocol_CanStats can_stats;
+ const AP_HAL::CANIface::bus_stats_t *bus_stats = ins.iface->get_statistics();
+ if (bus_stats == nullptr) {
+ return;
+ }
+ can_stats.interface = ins.index;
+ can_stats.tx_requests = bus_stats->tx_requests;
+ can_stats.tx_rejected = bus_stats->tx_rejected;
+ can_stats.tx_overflow = bus_stats->tx_overflow;
+ can_stats.tx_success = bus_stats->tx_success;
+ can_stats.tx_timedout = bus_stats->tx_timedout;
+ can_stats.tx_abort = bus_stats->tx_abort;
+ can_stats.rx_received = bus_stats->rx_received;
+ can_stats.rx_overflow = bus_stats->rx_overflow;
+ can_stats.rx_errors = bus_stats->rx_errors;
+ can_stats.busoff_errors = bus_stats->num_busoff_err;
+ uint32_t len = dronecan_protocol_CanStats_encode(&can_stats, buffer, !periph.canfdout());
+ periph.canard_broadcast(DRONECAN_PROTOCOL_CANSTATS_SIGNATURE,
+ DRONECAN_PROTOCOL_CANSTATS_ID,
+ CANARD_TRANSFER_PRIORITY_LOWEST,
+ buffer,
+ len);
+ }
+ }
+#endif
}
@@ -1382,12 +1493,12 @@ static void process1HzTasks(uint64_t timestamp_usec)
#if 0
// test code for watchdog reset
- if (AP_HAL::native_millis() > 15000) {
+ if (AP_HAL::millis() > 15000) {
while (true) ;
}
#endif
#if CONFIG_HAL_BOARD == HAL_BOARD_CHIBIOS
- if (AP_HAL::native_millis() > 30000) {
+ if (AP_HAL::millis() > 30000) {
// use RTC to mark that we have been running fine for
// 30s. This is used along with watchdog resets to ensure the
// user has a chance to load a fixed firmware
@@ -1407,7 +1518,7 @@ static bool can_do_dna()
return true;
}
- const uint32_t now = AP_HAL::native_millis();
+ const uint32_t now = AP_HAL::millis();
static uint8_t node_id_allocation_transfer_id = 0;
@@ -1472,7 +1583,7 @@ void AP_Periph_FW::can_start()
{
node_status.health = UAVCAN_PROTOCOL_NODESTATUS_HEALTH_OK;
node_status.mode = UAVCAN_PROTOCOL_NODESTATUS_MODE_INITIALIZATION;
- node_status.uptime_sec = AP_HAL::native_millis() / 1000U;
+ node_status.uptime_sec = AP_HAL::millis() / 1000U;
if (g.can_node >= 0 && g.can_node < 128) {
PreferredNodeID = g.can_node;
@@ -1485,12 +1596,12 @@ void AP_Periph_FW::can_start()
#if AP_PERIPH_ENFORCE_AT_LEAST_ONE_PORT_IS_UAVCAN_1MHz && HAL_NUM_CAN_IFACES >= 2
bool has_uavcan_at_1MHz = false;
for (uint8_t i=0; idisable_interrupts_save();
uint16_t value = pwm_hardpoint.highest_pwm;
@@ -1600,7 +1711,7 @@ void AP_Periph_FW::hwesc_telem_update()
const HWESC_Telem::HWESC &t = hwesc_telem.get_telem();
uavcan_equipment_esc_Status pkt {};
- pkt.esc_index = g.esc_number;
+ pkt.esc_index = g.esc_number[0]; // only supports a single ESC
pkt.voltage = t.voltage;
pkt.current = t.current;
pkt.temperature = C_TO_KELVIN(MAX(t.mos_temperature, t.cap_temperature));
@@ -1671,12 +1782,46 @@ void AP_Periph_FW::esc_telem_update()
}
}
#endif // HAL_WITH_ESC_TELEM
-#endif // HAL_PERIPH_ENABLE_RC_OUT
+#ifdef HAL_PERIPH_ENABLE_ESC_APD
+void AP_Periph_FW::apd_esc_telem_update()
+{
+ for(uint8_t i = 0; i < ARRAY_SIZE(apd_esc_telem); i++) {
+ if (apd_esc_telem[i] == nullptr) {
+ continue;
+ }
+ ESC_APD_Telem &esc = *apd_esc_telem[i];
+
+ if (esc.update()) {
+ const ESC_APD_Telem::telem &t = esc.get_telem();
+
+ uavcan_equipment_esc_Status pkt {};
+ static_assert(APD_ESC_INSTANCES <= ARRAY_SIZE(g.esc_number), "There must be an ESC instance number for each APD ESC");
+ pkt.esc_index = g.esc_number[i];
+ pkt.voltage = t.voltage;
+ pkt.current = t.current;
+ pkt.temperature = t.temperature;
+ pkt.rpm = t.rpm;
+ pkt.power_rating_pct = t.power_rating_pct;
+ pkt.error_count = t.error_count;
+
+ uint8_t buffer[UAVCAN_EQUIPMENT_ESC_STATUS_MAX_SIZE] {};
+ uint16_t total_size = uavcan_equipment_esc_Status_encode(&pkt, buffer, !periph.canfdout());
+ canard_broadcast(UAVCAN_EQUIPMENT_ESC_STATUS_SIGNATURE,
+ UAVCAN_EQUIPMENT_ESC_STATUS_ID,
+ CANARD_TRANSFER_PRIORITY_LOW,
+ &buffer[0],
+ total_size);
+ }
+ }
+
+}
+#endif // HAL_PERIPH_ENABLE_ESC_APD
+#endif // HAL_PERIPH_ENABLE_RC_OUT
void AP_Periph_FW::can_update()
{
- const uint32_t now = AP_HAL::native_millis();
+ const uint32_t now = AP_HAL::millis();
const uint32_t led_pattern = 0xAAAA;
const uint32_t led_change_period = 50;
static uint8_t led_idx = 0;
@@ -1704,7 +1849,7 @@ void AP_Periph_FW::can_update()
static uint32_t last_1Hz_ms;
if (now - last_1Hz_ms >= 1000) {
last_1Hz_ms = now;
- process1HzTasks(AP_HAL::native_micros64());
+ process1HzTasks(AP_HAL::micros64());
}
#if CONFIG_HAL_BOARD == HAL_BOARD_SITL
@@ -1713,6 +1858,9 @@ void AP_Periph_FW::can_update()
{
can_mag_update();
can_gps_update();
+#if AP_UART_MONITOR_ENABLED
+ send_serial_monitor_data();
+#endif
can_battery_update();
can_baro_update();
can_airspeed_update();
@@ -1733,6 +1881,9 @@ void AP_Periph_FW::can_update()
#ifdef HAL_PERIPH_ENABLE_HWESC
hwesc_telem_update();
#endif
+#ifdef HAL_PERIPH_ENABLE_ESC_APD
+ apd_esc_telem_update();
+#endif
#ifdef HAL_PERIPH_ENABLE_MSP
msp_sensor_update();
#endif
@@ -1779,7 +1930,7 @@ void AP_Periph_FW::can_mag_update(void)
#if AP_PERIPH_PROBE_CONTINUOUS
if (compass.get_count() == 0) {
static uint32_t last_probe_ms;
- uint32_t now = AP_HAL::native_millis();
+ uint32_t now = AP_HAL::millis();
if (now - last_probe_ms >= 1000) {
last_probe_ms = now;
compass.init();
@@ -1820,7 +1971,7 @@ void AP_Periph_FW::can_mag_update(void)
void AP_Periph_FW::can_battery_update(void)
{
#ifdef HAL_PERIPH_ENABLE_BATTERY
- const uint32_t now_ms = AP_HAL::native_millis();
+ const uint32_t now_ms = AP_HAL::millis();
if (now_ms - battery.last_can_send_ms < 100) {
return;
}
@@ -2114,9 +2265,11 @@ void AP_Periph_FW::send_moving_baseline_msg()
} else
#endif
{
+ // we use MEDIUM priority on this data as we need to get all
+ // the data through for RTK moving baseline yaw to work
canard_broadcast(ARDUPILOT_GNSS_MOVINGBASELINEDATA_SIGNATURE,
ARDUPILOT_GNSS_MOVINGBASELINEDATA_ID,
- CANARD_TRANSFER_PRIORITY_LOW,
+ CANARD_TRANSFER_PRIORITY_MEDIUM,
&buffer[0],
total_size);
}
@@ -2219,7 +2372,7 @@ void AP_Periph_FW::can_airspeed_update(void)
}
#if AP_PERIPH_PROBE_CONTINUOUS
if (!airspeed.healthy()) {
- uint32_t now = AP_HAL::native_millis();
+ uint32_t now = AP_HAL::millis();
static uint32_t last_probe_ms;
if (now - last_probe_ms >= 1000) {
last_probe_ms = now;
@@ -2227,7 +2380,7 @@ void AP_Periph_FW::can_airspeed_update(void)
}
}
#endif
- uint32_t now = AP_HAL::native_millis();
+ uint32_t now = AP_HAL::millis();
if (now - last_airspeed_update_ms < 50) {
// max 20Hz data
return;
@@ -2247,8 +2400,6 @@ void AP_Periph_FW::can_airspeed_update(void)
}
uavcan_equipment_air_data_RawAirData pkt {};
- pkt.differential_pressure = press;
- pkt.static_air_temperature = temp;
// unfilled elements are NaN
pkt.static_pressure = nanf("");
@@ -2256,6 +2407,21 @@ void AP_Periph_FW::can_airspeed_update(void)
pkt.differential_pressure_sensor_temperature = nanf("");
pkt.pitot_temperature = nanf("");
+ // populate the elements we have
+ pkt.differential_pressure = press;
+ pkt.static_air_temperature = temp;
+
+ // if a Pitot tube temperature sensor is available, use it
+#if AP_TEMPERATURE_SENSOR_ENABLED
+ for (uint8_t i=0; i= 1000) {
last_probe_ms = now;
@@ -2287,10 +2453,10 @@ void AP_Periph_FW::can_rangefinder_update(void)
}
}
#endif
- uint32_t now = AP_HAL::native_millis();
+ uint32_t now = AP_HAL::millis();
static uint32_t last_update_ms;
if (g.rangefinder_max_rate > 0 &&
- now - last_update_ms < 1000/g.rangefinder_max_rate) {
+ now - last_update_ms < uint32_t(1000/g.rangefinder_max_rate)) {
// limit to max rate
return;
}
@@ -2355,12 +2521,12 @@ void AP_Periph_FW::can_rangefinder_update(void)
void AP_Periph_FW::can_proximity_update()
{
-#ifdef HAL_PERIPH_ENABLE_PRX
+#if HAL_PROXIMITY_ENABLED
if (proximity.get_type(0) == AP_Proximity::Type::None) {
return;
}
- uint32_t now = AP_HAL::native_millis();
+ uint32_t now = AP_HAL::millis();
static uint32_t last_update_ms;
if (g.proximity_max_rate > 0 &&
now - last_update_ms < 1000/g.proximity_max_rate) {
@@ -2419,66 +2585,6 @@ void AP_Periph_FW::can_proximity_update()
#endif
}
-#ifdef HAL_PERIPH_ENABLE_ADSB
-/*
- map an ADSB_VEHICLE MAVLink message to a UAVCAN TrafficReport message
- */
-void AP_Periph_FW::can_send_ADSB(struct __mavlink_adsb_vehicle_t &msg)
-{
- ardupilot_equipment_trafficmonitor_TrafficReport pkt {};
- pkt.timestamp.usec = 0;
- pkt.icao_address = msg.ICAO_address;
- pkt.tslc = msg.tslc;
- pkt.latitude_deg_1e7 = msg.lat;
- pkt.longitude_deg_1e7 = msg.lon;
- pkt.alt_m = msg.altitude * 1e-3;
-
- pkt.heading = radians(msg.heading * 1e-2);
-
- pkt.velocity[0] = cosf(pkt.heading) * msg.hor_velocity * 1e-2;
- pkt.velocity[1] = sinf(pkt.heading) * msg.hor_velocity * 1e-2;
- pkt.velocity[2] = -msg.ver_velocity * 1e-2;
-
- pkt.squawk = msg.squawk;
- memcpy(pkt.callsign, msg.callsign, MIN(sizeof(msg.callsign),sizeof(pkt.callsign)));
- if (msg.flags & 0x8000) {
- pkt.source = ARDUPILOT_EQUIPMENT_TRAFFICMONITOR_TRAFFICREPORT_SOURCE_ADSB_UAT;
- } else {
- pkt.source = ARDUPILOT_EQUIPMENT_TRAFFICMONITOR_TRAFFICREPORT_SOURCE_ADSB;
- }
-
- pkt.traffic_type = msg.emitter_type;
-
- if ((msg.flags & ADSB_FLAGS_VALID_ALTITUDE) != 0 && msg.altitude_type == 0) {
- pkt.alt_type = ARDUPILOT_EQUIPMENT_TRAFFICMONITOR_TRAFFICREPORT_ALT_TYPE_PRESSURE_AMSL;
- } else if ((msg.flags & ADSB_FLAGS_VALID_ALTITUDE) != 0 && msg.altitude_type == 1) {
- pkt.alt_type = ARDUPILOT_EQUIPMENT_TRAFFICMONITOR_TRAFFICREPORT_ALT_TYPE_WGS84;
- } else {
- pkt.alt_type = ARDUPILOT_EQUIPMENT_TRAFFICMONITOR_TRAFFICREPORT_ALT_TYPE_ALT_UNKNOWN;
- }
-
- pkt.lat_lon_valid = (msg.flags & ADSB_FLAGS_VALID_COORDS) != 0;
- pkt.heading_valid = (msg.flags & ADSB_FLAGS_VALID_HEADING) != 0;
- pkt.velocity_valid = (msg.flags & ADSB_FLAGS_VALID_VELOCITY) != 0;
- pkt.callsign_valid = (msg.flags & ADSB_FLAGS_VALID_CALLSIGN) != 0;
- pkt.ident_valid = (msg.flags & ADSB_FLAGS_VALID_SQUAWK) != 0;
- pkt.simulated_report = (msg.flags & ADSB_FLAGS_SIMULATED) != 0;
-
- // these flags are not in common.xml
- pkt.vertical_velocity_valid = (msg.flags & 0x0080) != 0;
- pkt.baro_valid = (msg.flags & 0x0100) != 0;
-
- uint8_t buffer[ARDUPILOT_EQUIPMENT_TRAFFICMONITOR_TRAFFICREPORT_MAX_SIZE] {};
- uint16_t total_size = ardupilot_equipment_trafficmonitor_TrafficReport_encode(&pkt, buffer, !periph.canfdout());
-
- canard_broadcast(ARDUPILOT_EQUIPMENT_TRAFFICMONITOR_TRAFFICREPORT_SIGNATURE,
- ARDUPILOT_EQUIPMENT_TRAFFICMONITOR_TRAFFICREPORT_ID,
- CANARD_TRANSFER_PRIORITY_LOW,
- &buffer[0],
- total_size);
-}
-#endif // HAL_PERIPH_ENABLE_ADSB
-
#ifdef HAL_PERIPH_ENABLE_EFI
/*
@@ -2665,7 +2771,6 @@ void AP_Periph_FW::can_efi_update(void)
}
#endif // HAL_PERIPH_ENABLE_EFI
-
// printf to CAN LogMessage for debugging
void can_printf(const char *fmt, ...)
{
@@ -2693,11 +2798,11 @@ void can_printf(const char *fmt, ...)
uint8_t buffer_packet[UAVCAN_PROTOCOL_DEBUG_LOGMESSAGE_MAX_SIZE] {};
const uint32_t len = uavcan_protocol_debug_LogMessage_encode(&pkt, buffer_packet, !periph.canfdout());
- canard_broadcast(UAVCAN_PROTOCOL_DEBUG_LOGMESSAGE_SIGNATURE,
- UAVCAN_PROTOCOL_DEBUG_LOGMESSAGE_ID,
- CANARD_TRANSFER_PRIORITY_LOW,
- buffer_packet,
- len);
+ periph.canard_broadcast(UAVCAN_PROTOCOL_DEBUG_LOGMESSAGE_SIGNATURE,
+ UAVCAN_PROTOCOL_DEBUG_LOGMESSAGE_ID,
+ CANARD_TRANSFER_PRIORITY_LOW,
+ buffer_packet,
+ len);
}
#else
@@ -2711,11 +2816,11 @@ void can_printf(const char *fmt, ...)
uint32_t len = uavcan_protocol_debug_LogMessage_encode(&pkt, buffer, !periph.canfdout());
- canard_broadcast(UAVCAN_PROTOCOL_DEBUG_LOGMESSAGE_SIGNATURE,
- UAVCAN_PROTOCOL_DEBUG_LOGMESSAGE_ID,
- CANARD_TRANSFER_PRIORITY_LOW,
- buffer,
- len);
+ periph.canard_broadcast(UAVCAN_PROTOCOL_DEBUG_LOGMESSAGE_SIGNATURE,
+ UAVCAN_PROTOCOL_DEBUG_LOGMESSAGE_ID,
+ CANARD_TRANSFER_PRIORITY_LOW,
+ buffer,
+ len);
#endif
}
diff --git a/Tools/AP_Periph/esc_apd_telem.cpp b/Tools/AP_Periph/esc_apd_telem.cpp
new file mode 100644
index 00000000000000..fccc2663312bbb
--- /dev/null
+++ b/Tools/AP_Periph/esc_apd_telem.cpp
@@ -0,0 +1,97 @@
+/*
+ ESC Telemetry for the APD HV Pro ESC
+
+ Protocol is here: https://docs.powerdrives.net/products/hv_pro/uart-telemetry-output
+ */
+#include "esc_apd_telem.h"
+#include
+#include
+#include
+#include
+
+#ifdef HAL_PERIPH_ENABLE_ESC_APD
+
+extern const AP_HAL::HAL& hal;
+
+#define TELEM_HEADER 0x9B
+#define TELEM_LEN 0x16
+
+ESC_APD_Telem::ESC_APD_Telem (AP_HAL::UARTDriver *_uart, float num_poles) :
+ pole_count(num_poles),
+ uart(_uart) {
+ uart->begin(115200);
+}
+
+bool ESC_APD_Telem::update() {
+ uint32_t n = uart->available();
+ if (n == 0) {
+ return false;
+ }
+
+ // don't read too much in one loop to prevent too high CPU load
+ if (n > 50) {
+ n = 50;
+ }
+
+ bool ret = false;
+
+ while (n--) {
+ uint8_t b = uart->read();
+ received.bytes[len++] = b;
+
+ // check the packet size first
+ if ((size_t)len >= sizeof(received.packet)) {
+ // we have a full packet, check the stop byte
+ if (received.packet.stop == 65535) {
+ // valid stop byte, check the CRC
+ if (crc_fletcher16(received.bytes, 18) == received.packet.checksum) {
+ // valid packet, copy the data we need and reset length
+ decoded.voltage = le16toh(received.packet.voltage) * 1e-2f;
+ decoded.temperature = convert_temperature(le16toh(received.packet.temperature));
+ decoded.current = le16toh(received.packet.bus_current) * (1 / 12.5f);
+ decoded.rpm = le32toh(received.packet.erpm) / pole_count;
+ decoded.power_rating_pct = le16toh(received.packet.motor_duty) * 1e-2f;
+ ret = true;
+ len = 0;
+ } else {
+ // we have an invalid packet, shift it back a byte
+ shift_buffer();
+ }
+ } else {
+ // invalid stop byte, we've lost sync, shift the packet by 1 byte
+ shift_buffer();
+ }
+
+ }
+ }
+ return ret;
+}
+
+// shift the decode buffer left by 1 byte, and rewind the progress
+void ESC_APD_Telem::shift_buffer(void) {
+ memmove(received.bytes, received.bytes + 1, sizeof(received.bytes) - 1);
+ len--;
+}
+
+// convert the raw ESC temperature to a useful value (in Kelvin)
+// based on the 1.1 example C code found here https://docs.powerdrives.net/products/hv_pro/uart-telemetry-output
+float ESC_APD_Telem::convert_temperature(uint16_t raw) const {
+ const float series_resistor = 10000;
+ const float nominal_resistance = 10000;
+ const float nominal_temperature = 25;
+ const float b_coefficent = 3455;
+
+
+ const float Rntc = series_resistor / ((4096 / float(raw)) - 1);
+
+ float temperature = Rntc / nominal_resistance; // (R/Ro)
+ temperature = logf(temperature); // ln(R/Ro)
+ temperature /= b_coefficent; // 1/B * ln(R/Ro)
+ temperature += 1 / C_TO_KELVIN(nominal_temperature); // + (1/To)
+ temperature = 1 / temperature; // invert
+
+ // the example code rejected anything below 0C, or above 200C, the 200C clamp makes some sense, the below 0C is harder to accept
+ return temperature;
+}
+
+#endif // HAL_PERIPH_ENABLE_ESC_APD
diff --git a/Tools/AP_Periph/esc_apd_telem.h b/Tools/AP_Periph/esc_apd_telem.h
new file mode 100644
index 00000000000000..42f2f416ad6112
--- /dev/null
+++ b/Tools/AP_Periph/esc_apd_telem.h
@@ -0,0 +1,61 @@
+/*
+ ESC Telemetry for APD ESC.
+ */
+
+#pragma once
+
+#include
+
+#ifdef HAL_PERIPH_ENABLE_ESC_APD
+
+class ESC_APD_Telem {
+public:
+ ESC_APD_Telem (AP_HAL::UARTDriver *_uart, float num_poles);
+ bool update();
+
+ CLASS_NO_COPY(ESC_APD_Telem);
+
+ struct telem {
+ uint32_t error_count;
+ float voltage;
+ float current;
+ float temperature; // kelvin
+ int32_t rpm;
+ uint8_t power_rating_pct;
+ };
+
+ const telem &get_telem(void) {
+ return decoded;
+ }
+
+private:
+ AP_HAL::UARTDriver *uart;
+
+ union {
+ struct PACKED {
+ uint16_t voltage;
+ uint16_t temperature;
+ int16_t bus_current;
+ uint16_t reserved0;
+ uint32_t erpm;
+ uint16_t input_duty;
+ uint16_t motor_duty;
+ uint16_t reserved1;
+ uint16_t checksum; // 16 bit fletcher checksum
+ uint16_t stop; // should always be 65535 on a valid packet
+ } packet;
+ uint8_t bytes[22];
+ } received;
+ static_assert(sizeof(received.packet) == sizeof(received.bytes), "The packet must be the same size as the raw buffer");
+
+ uint8_t len;
+
+ struct telem decoded;
+
+ float pole_count;
+
+ float convert_temperature(uint16_t raw) const;
+ void shift_buffer(void);
+};
+
+#endif // HAL_PERIPH_ENABLE_ESC_APD
diff --git a/Tools/AP_Periph/hwing_esc.cpp b/Tools/AP_Periph/hwing_esc.cpp
index a79862f3cf6d0e..13d30eb8d68dcb 100644
--- a/Tools/AP_Periph/hwing_esc.cpp
+++ b/Tools/AP_Periph/hwing_esc.cpp
@@ -39,7 +39,7 @@ bool HWESC_Telem::update()
}
// we expect at least 50ms idle between frames
- uint32_t now = AP_HAL::native_millis();
+ uint32_t now = AP_HAL::millis();
bool frame_gap = (now - last_read_ms) > 10;
last_read_ms = now;
diff --git a/Tools/AP_Periph/rc_in.cpp b/Tools/AP_Periph/rc_in.cpp
new file mode 100644
index 00000000000000..f5f577adc6e448
--- /dev/null
+++ b/Tools/AP_Periph/rc_in.cpp
@@ -0,0 +1,180 @@
+/*
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+ */
+
+#include
+
+#ifdef HAL_PERIPH_ENABLE_RCIN
+
+#ifndef AP_PERIPH_RC1_PORT_DEFAULT
+#define AP_PERIPH_RC1_PORT_DEFAULT -1
+#endif
+
+#ifndef AP_PERIPH_RC1_PORT_OPTIONS_DEFAULT
+#define AP_PERIPH_RC1_PORT_OPTIONS_DEFAULT 0
+#endif
+
+#include
+#include "AP_Periph.h"
+#include
+
+extern const AP_HAL::HAL &hal;
+
+const AP_Param::GroupInfo Parameters_RCIN::var_info[] {
+ // RC_PROTOCOLS copied from RC_Channel/RC_Channels_Varinfo.h
+ // @Param: RC_PROTOCOLS
+ // @DisplayName: RC protocols enabled
+ // @Description: Bitmask of enabled RC protocols. Allows narrowing the protocol detection to only specific types of RC receivers which can avoid issues with incorrect detection. Set to 1 to enable all protocols.
+ // @User: Advanced
+ // @Bitmask: 0:All,1:PPM,2:IBUS,3:SBUS,4:SBUS_NI,5:DSM,6:SUMD,7:SRXL,8:SRXL2,9:CRSF,10:ST24,11:FPORT,12:FPORT2,13:FastSBUS
+ AP_GROUPINFO("_PROTOCOLS", 1, Parameters_RCIN, rcin_protocols, 1),
+
+ // RC_PROTOCOLS copied from RC_Channel/RC_Channels_Varinfo.h
+ // @Param: RC_MSGRATE
+ // @DisplayName: DroneCAN RC Message rate
+ // @Description: Rate at which RC input is sent via DroneCAN
+ // @User: Advanced
+ // @Increment: 1
+ // @Range: 0 255
+ // @Units: Hz
+ AP_GROUPINFO("_MSGRATE", 2, Parameters_RCIN, rcin_rate_hz, 50),
+
+ // @Param: RC1_PORT
+ // @DisplayName: RC input port
+ // @Description: This is the serial port number where SERIALx_PROTOCOL will be set to RC input.
+ // @Range: 0 10
+ // @Increment: 1
+ // @User: Advanced
+ // @RebootRequired: True
+ AP_GROUPINFO("_PORT", 3, Parameters_RCIN, rcin1_port, AP_PERIPH_RC1_PORT_DEFAULT),
+
+ // @Param: RC1_PORT_OPTIONS
+ // @DisplayName: RC input port serial options
+ // @Description: This is the serial port number where SERIALx_PROTOCOL will be set to RC input.
+ // @Description: Control over UART options. The InvertRX option controls invert of the receive pin. The InvertTX option controls invert of the transmit pin. The HalfDuplex option controls half-duplex (onewire) mode, where both transmit and receive is done on the transmit wire. The Swap option allows the RX and TX pins to be swapped on STM32F7 based boards.
+ // @Bitmask: 0:InvertRX, 1:InvertTX, 2:HalfDuplex, 3:SwapTXRX, 4: RX_PullDown, 5: RX_PullUp, 6: TX_PullDown, 7: TX_PullUp, 8: RX_NoDMA, 9: TX_NoDMA, 10: Don't forward mavlink to/from, 11: DisableFIFO, 12: Ignore Streamrate
+ AP_GROUPINFO("1_PORT_OPTIONS", 4, Parameters_RCIN, rcin1_port_options, AP_PERIPH_RC1_PORT_OPTIONS_DEFAULT),
+ // @RebootRequired: True
+
+ AP_GROUPEND
+};
+
+Parameters_RCIN::Parameters_RCIN(void)
+{
+ AP_Param::setup_object_defaults(this, var_info);
+}
+
+void AP_Periph_FW::rcin_init()
+{
+ if (g_rcin.rcin1_port == 0) {
+ return;
+ }
+
+ // init uart for serial RC
+ auto *uart = hal.serial(g_rcin.rcin1_port);
+ if (uart == nullptr) {
+ return;
+ }
+
+ uart->set_options(g_rcin.rcin1_port_options);
+
+ serial_manager.set_protocol_and_baud(
+ g_rcin.rcin1_port,
+ AP_SerialManager::SerialProtocol_RCIN,
+ 115200 // baud doesn't matter; RC Protocol autobauds
+ );
+
+ auto &rc = AP::RC();
+ rc.init();
+ rc.set_rc_protocols(g_rcin.rcin_protocols);
+ rc.add_uart(uart);
+
+ rcin_initialised = true;
+}
+
+void AP_Periph_FW::rcin_update()
+{
+ if (!rcin_initialised) {
+ return;
+ }
+
+ auto &rc = AP::RC();
+ if (!rc.new_input()) {
+ return;
+ }
+
+ // log discovered protocols:
+ auto new_rc_protocol = rc.protocol_name();
+ if (new_rc_protocol != rcin_rc_protocol) {
+ can_printf("Decoding (%s)", new_rc_protocol);
+ rcin_rc_protocol = new_rc_protocol;
+ }
+
+ // decimate the input to a parameterized rate
+ const uint8_t rate_hz = g_rcin.rcin_rate_hz;
+ if (rate_hz == 0) {
+ return;
+ }
+
+ const auto now_ms = AP_HAL::millis();
+ const auto interval_ms = 1000U / rate_hz;
+ if (now_ms - rcin_last_sent_RCInput_ms < interval_ms) {
+ return;
+ }
+ rcin_last_sent_RCInput_ms = now_ms;
+
+ // extract data and send CAN packet:
+ const uint8_t num_channels = rc.num_channels();
+ uint16_t channels[MAX_RCIN_CHANNELS];
+ rc.read(channels, num_channels);
+ const int16_t rssi = rc.get_RSSI();
+
+ can_send_RCInput((uint8_t)rssi, channels, num_channels, rc.failsafe_active(), rssi > 0 && rssi <256);
+}
+
+/*
+ send an RCInput CAN message
+ */
+void AP_Periph_FW::can_send_RCInput(uint8_t quality, uint16_t *values, uint8_t nvalues, bool in_failsafe, bool quality_valid)
+{
+ uint16_t status = 0;
+ if (quality_valid) {
+ status |= DRONECAN_SENSORS_RC_RCINPUT_STATUS_QUALITY_VALID;
+ }
+ if (in_failsafe) {
+ status |= DRONECAN_SENSORS_RC_RCINPUT_STATUS_FAILSAFE;
+ }
+
+ // assemble packet
+ dronecan_sensors_rc_RCInput pkt {};
+ pkt.quality = quality;
+ pkt.status = status;
+ pkt.rcin.len = nvalues;
+ for (uint8_t i=0; i.
+ */
+/*
+ handle tunnelling of serial data over DroneCAN
+ */
+
+#include
+#include "AP_Periph.h"
+
+#if AP_UART_MONITOR_ENABLED
+
+#include
+
+extern const AP_HAL::HAL &hal;
+
+#define TUNNEL_LOCK_KEY 0xf2e460e4U
+
+#ifndef TUNNEL_DEBUG
+#define TUNNEL_DEBUG 0
+#endif
+
+#if TUNNEL_DEBUG
+# define debug(fmt, args...) can_printf(fmt "\n", ##args)
+#else
+# define debug(fmt, args...)
+#endif
+
+/*
+ get the default port to tunnel if the client requests port -1
+ */
+int8_t AP_Periph_FW::get_default_tunnel_serial_port(void) const
+{
+ int8_t uart_num = -1;
+#ifdef HAL_PERIPH_ENABLE_GPS
+ if (uart_num == -1) {
+ uart_num = g.gps_port;
+ }
+#endif
+#ifdef HAL_PERIPH_ENABLE_RANGEFINDER
+ if (uart_num == -1) {
+ uart_num = g.rangefinder_port;
+ }
+#endif
+#ifdef HAL_PERIPH_ENABLE_ADSB
+ if (uart_num == -1) {
+ uart_num = g.adsb_port;
+ }
+#endif
+#if HAL_PROXIMITY_ENABLED
+ if (uart_num == -1) {
+ uart_num = g.proximity_port;
+ }
+#endif
+ return uart_num;
+}
+
+/*
+ handle tunnel data
+ */
+void AP_Periph_FW::handle_tunnel_Targetted(CanardInstance* canard_ins, CanardRxTransfer* transfer)
+{
+ uavcan_tunnel_Targetted pkt;
+ if (uavcan_tunnel_Targetted_decode(transfer, &pkt)) {
+ return;
+ }
+ if (pkt.target_node != canardGetLocalNodeID(canard_ins)) {
+ return;
+ }
+ if (uart_monitor.buffer == nullptr) {
+ uart_monitor.buffer = new ByteBuffer(1024);
+ if (uart_monitor.buffer == nullptr) {
+ return;
+ }
+ }
+ int8_t uart_num = pkt.serial_id;
+ if (uart_num == -1) {
+ uart_num = get_default_tunnel_serial_port();
+ }
+ if (uart_num < 0) {
+ return;
+ }
+ auto *uart = hal.serial(uart_num);
+ if (uart == nullptr) {
+ return;
+ }
+ if (uart_monitor.uart_num != uart_num && uart_monitor.uart != nullptr) {
+ // remove monitor from previous uart
+ hal.serial(uart_monitor.uart_num)->set_monitor_read_buffer(nullptr);
+ }
+ uart_monitor.uart_num = uart_num;
+ if (uart != uart_monitor.uart) {
+ // change of uart or expired, clear old data
+ uart_monitor.buffer->clear();
+ uart_monitor.uart = uart;
+ uart_monitor.baudrate = 0;
+ }
+ if (uart_monitor.uart == nullptr) {
+ return;
+ }
+ /*
+ allow for locked state to change at any time, so users can
+ switch between locked and unlocked while connected
+ */
+ const bool was_locked = uart_monitor.locked;
+ uart_monitor.locked = (pkt.options & UAVCAN_TUNNEL_TARGETTED_OPTION_LOCK_PORT) != 0;
+ if (uart_monitor.locked) {
+ uart_monitor.uart->lock_port(TUNNEL_LOCK_KEY, TUNNEL_LOCK_KEY);
+ } else {
+ uart_monitor.uart->lock_port(0,0);
+ }
+ uart_monitor.node_id = transfer->source_node_id;
+ uart_monitor.protocol = pkt.protocol.protocol;
+ if (pkt.baudrate != uart_monitor.baudrate || !was_locked) {
+ if (uart_monitor.locked && pkt.baudrate != 0) {
+ // ensure we have enough buffer space for a uBlox fw update and fast uCenter data
+ uart_monitor.uart->begin_locked(pkt.baudrate, 2048, 2048, TUNNEL_LOCK_KEY);
+ debug("begin_locked %u", unsigned(pkt.baudrate));
+ }
+ uart_monitor.baudrate = pkt.baudrate;
+ }
+ uart_monitor.uart->set_monitor_read_buffer(uart_monitor.buffer);
+ uart_monitor.last_request_ms = AP_HAL::millis();
+
+ // write to device
+ if (pkt.buffer.len > 0) {
+ if (uart_monitor.locked) {
+ debug("write_locked %u", unsigned(pkt.buffer.len));
+ uart_monitor.uart->write_locked(pkt.buffer.data, pkt.buffer.len, TUNNEL_LOCK_KEY);
+ } else {
+ uart_monitor.uart->write(pkt.buffer.data, pkt.buffer.len);
+ }
+ } else {
+ debug("locked keepalive");
+ }
+}
+
+/*
+ send tunnelled serial data
+ */
+void AP_Periph_FW::send_serial_monitor_data()
+{
+ if (uart_monitor.uart == nullptr ||
+ uart_monitor.node_id == 0 ||
+ uart_monitor.buffer == nullptr) {
+ return;
+ }
+ const uint32_t last_req_ms = uart_monitor.last_request_ms;
+ const uint32_t now_ms = AP_HAL::millis();
+ if (now_ms - last_req_ms >= 3000) {
+ // stop sending and unlock, but don't release the buffer
+ if (uart_monitor.locked) {
+ debug("unlock");
+ uart_monitor.uart->lock_port(0, 0);
+ }
+ uart_monitor.uart = nullptr;
+ return;
+ }
+ if (uart_monitor.locked) {
+ /*
+ when the port is locked nobody is reading the uart so the
+ monitor doesn't fill. We read here to ensure it fills
+ */
+ uint8_t buf[120];
+ for (uint8_t i=0; i<8; i++) {
+ if (uart_monitor.uart->read_locked(buf, sizeof(buf), TUNNEL_LOCK_KEY) <= 0) {
+ break;
+ }
+ }
+ }
+ uint8_t sends = 8;
+ while (uart_monitor.buffer->available() > 0 && sends-- > 0) {
+ uint32_t n;
+ const uint8_t *buf = uart_monitor.buffer->readptr(n);
+ if (n == 0) {
+ return;
+ }
+ // broadcast data as tunnel packets, can be used for uCenter debug and device fw update
+ uavcan_tunnel_Targetted pkt {};
+ n = MIN(n, sizeof(pkt.buffer.data));
+ pkt.target_node = uart_monitor.node_id;
+ pkt.protocol.protocol = uart_monitor.protocol;
+ pkt.buffer.len = n;
+ pkt.baudrate = uart_monitor.baudrate;
+ memcpy(pkt.buffer.data, buf, n);
+
+ uint8_t buffer[UAVCAN_TUNNEL_TARGETTED_MAX_SIZE] {};
+ const uint16_t total_size = uavcan_tunnel_Targetted_encode(&pkt, buffer, !canfdout());
+
+ debug("read %u", unsigned(n));
+
+ if (!canard_broadcast(UAVCAN_TUNNEL_TARGETTED_SIGNATURE,
+ UAVCAN_TUNNEL_TARGETTED_ID,
+ CANARD_TRANSFER_PRIORITY_MEDIUM,
+ &buffer[0],
+ total_size)) {
+ break;
+ }
+ uart_monitor.buffer->advance(n);
+ }
+}
+#endif // AP_UART_MONITOR_ENABLED
diff --git a/Tools/AP_Periph/wscript b/Tools/AP_Periph/wscript
index d6a733b5ffafd0..30f09bb36dfcd6 100644
--- a/Tools/AP_Periph/wscript
+++ b/Tools/AP_Periph/wscript
@@ -38,11 +38,13 @@ def build(bld):
'AP_BoardConfig',
'AP_BattMonitor',
'AP_CANManager',
+ 'AP_KDECAN',
'AP_Param',
'StorageManager',
'AP_FlashStorage',
'AP_RAMTRON',
'AP_GPS',
+ 'AP_Networking',
'AP_SerialManager',
'AP_RTC',
'AP_Compass',
@@ -68,7 +70,16 @@ def build(bld):
'AP_Stats',
'AP_EFI',
'AP_CheckFirmware',
+ 'AP_RPM',
'AP_Proximity',
+ 'AP_RCProtocol',
+ 'AP_AHRS',
+ 'AP_Terrain',
+ 'AP_Torqeedo',
+ 'AP_Volz_Protocol',
+ 'AP_SBusOut',
+ 'AP_RobotisServo',
+ 'AP_FETtecOneWire',
]
bld.ap_stlib(
name= 'AP_Periph_libs',
diff --git a/Tools/CPUInfo/CPUInfo.cpp b/Tools/CPUInfo/CPUInfo.cpp
index 9802c9f93a418c..a20db4924d95d6 100644
--- a/Tools/CPUInfo/CPUInfo.cpp
+++ b/Tools/CPUInfo/CPUInfo.cpp
@@ -26,6 +26,7 @@ const AP_HAL::HAL& hal = AP_HAL::get_HAL();
// On H750 we want to measure external flash to ram performance
#if defined(EXT_FLASH_SIZE_MB) && EXT_FLASH_SIZE_MB>0 && defined(STM32H7)
+#include "ch.h"
#define DISABLE_CACHES
#endif
@@ -44,7 +45,9 @@ AP_ESC_Telem telem;
void setup() {
#ifdef DISABLE_CACHES
+#if !HAL_XIP_ENABLED // can't disable DCache in memory-mapped mode
SCB_DisableDCache();
+#endif
SCB_DisableICache();
#endif
ekf.init();
@@ -97,6 +100,7 @@ volatile uint8_t mbuf1[128], mbuf2[128];
volatile uint64_t v_64 = 1;
volatile uint64_t v_out_64 = 1;
+#pragma GCC diagnostic error "-Wframe-larger-than=2000"
static void show_timings(void)
{
diff --git a/Tools/CPUInfo/output-PixFlamingo.txt b/Tools/CPUInfo/output-PixFlamingo.txt
new file mode 100755
index 00000000000000..b33cc18a18bd2b
--- /dev/null
+++ b/Tools/CPUInfo/output-PixFlamingo.txt
@@ -0,0 +1,71 @@
+SYSCLK 120MHz
+Type sizes:
+char : 1
+short : 2
+int : 4
+long : 4
+long long : 8
+bool : 1
+void* : 4
+printing NaN: nan
+printing +Inf: inf
+printing -Inf: -inf
+
+Operation timings:
+Note: timings for some operations are very data dependent
+nop 0.0105 usec/call
+micros() 0.9710 usec/call
+micros16() 0.1179 usec/call
+millis() 2.0830 usec/call
+millis16() 2.1672 usec/call
+micros64() 1.0273 usec/call
+fadd 0.0648 usec/call
+fsub 0.0630 usec/call
+fmul 0.0656 usec/call
+fdiv /= 0.1738 usec/call
+fdiv 2/x 0.1668 usec/call
+dadd 0.8870 usec/call
+dsub 0.8592 usec/call
+dmul 0.4650 usec/call
+ddiv 0.5958 usec/call
+sinf() 1.3428 usec/call
+cosf() 1.2680 usec/call
+arm_sin_f32() 0.4202 usec/call
+arm_cos_f32() 0.4472 usec/call
+tanf() 2.0798 usec/call
+acosf() 1.3822 usec/call
+asinf() 1.4354 usec/call
+atan2f() 2.0736 usec/call
+sqrtf() 0.1790 usec/call
+sin() 1.3470 usec/call
+cos() 1.2674 usec/call
+tan() 2.0820 usec/call
+acos() 1.3848 usec/call
+asin() 1.4472 usec/call
+atan2() 2.0726 usec/call
+sqrt() 0.1834 usec/call
+arm_sqrt_f32() 0.2216 usec/call
+sq() 0.0490 usec/call
+powf(v,2) 0.0478 usec/call
+powf(v,3.1) 6.9318 usec/call
+EKF 48.7400 usec/call
+iadd8 0.0854 usec/call
+isub8 0.0850 usec/call
+imul8 0.0820 usec/call
+idiv8 0.0870 usec/call
+iadd16 0.0584 usec/call
+isub16 0.0630 usec/call
+imul16 0.0602 usec/call
+idiv16 0.1202 usec/call
+iadd32 0.0478 usec/call
+isub32 0.0544 usec/call
+imul32 0.0496 usec/call
+idiv32 0.0884 usec/call
+iadd64 0.0990 usec/call
+isub64 0.1028 usec/call
+imul64 0.1518 usec/call
+idiv64 0.9588 usec/call
+memcpy128 0.9161 usec/call
+memset128 1.0854 usec/call
+delay(1) 1018.43 usec/call
+SEM 2.2314 usec/call
diff --git a/Tools/CPUInfo/output-esp32-classic.txt b/Tools/CPUInfo/output-esp32-classic.txt
new file mode 100644
index 00000000000000..54d9c2e446169d
--- /dev/null
+++ b/Tools/CPUInfo/output-esp32-classic.txt
@@ -0,0 +1,94 @@
+rst:0x10 (RTCWDT_RTC_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
+configsip: 0, SPIWP:0xee
+clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
+mode:DIO, clock div:1
+load:0x3fff0030,len:5232
+load:0x40078000,len:14264
+load:0x40080400,len:4244
+entry 0x40080664
+I (334) cpu_start: Pro cpu up.
+I (334) cpu_start: Application information:
+I (334) cpu_start: ELF file SHA256: 69635451ea60f4bd...
+I (337) cpu_start: ESP-IDF: v4.2.4-209-g527a23d63f
+I (344) cpu_start: Starting app cpu, entry point is 0x40081c50
+I (0) cpu_start: App cpu up.
+I (354) heap_init: Initializing. RAM available for dynamic allocation:
+I (361) heap_init: At 3FFAE6E0 len 00001920 (6 KiB): DRAM
+I (367) heap_init: At 3FFBF160 len 00020EA0 (131 KiB): DRAM
+I (373) heap_init: At 3FFE0440 len 00003AE0 (14 KiB): D/IRAM
+I (379) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM
+I (386) heap_init: At 400954F8 len 0000AB08 (42 KiB): IRAM
+I (392) cpu_start: Pro cpu start user code
+I (410) spi_flash: detected chip: generic
+I (410) spi_flash: flash io: qio
+I (410) esp_core_dump_uart: Init core dump to UART
+I (413) cpu_start: Starting scheduler on PRO CPU.
+I (0) cpu_start: Starting scheduler on APP CPU.
+SYSCLK 0MHz
+Type sizes:
+char : 1
+short : 2
+int : 4
+long : 4
+long long : 8
+bool : 1
+void* : 4
+printing NaN: nan
+printing +Inf: inf
+printing -Inf: -inf
+
+Operation timings:
+Note: timings for some operations are very data dependent
+nop 0.0049 usec/call
+micros() 0.5432 usec/call
+micros16() 0.5979 usec/call
+millis() 0.9198 usec/call
+millis16() 0.9713 usec/call
+micros64() 0.5536 usec/call
+fadd 0.0634 usec/call
+fsub 0.0624 usec/call
+fmul 0.0624 usec/call
+fdiv /= 0.2504 usec/call
+fdiv 2/x 0.2428 usec/call
+dadd 0.2940 usec/call
+dsub 0.3306 usec/call
+dmul 0.2638 usec/call
+ddiv 0.2430 usec/call
+sinf() 0.9574 usec/call
+cosf() 0.8554 usec/call
+tanf() 1.4338 usec/call
+acosf() 2.1064 usec/call
+asinf() 1.7080 usec/call
+atan2f() 3.0798 usec/call
+sqrtf() 0.4264 usec/call
+sin() 0.9496 usec/call
+cos() 0.8504 usec/call
+tan() 1.4314 usec/call
+acos() 12.1722 usec/call
+asin() 11.5936 usec/call
+atan2() 3.8804 usec/call
+sqrt() 0.4268 usec/call
+sq() 0.0516 usec/call
+powf(v,2) 0.0516 usec/call
+powf(v,3.1) 3.0752 usec/call
+EKF 16.2000 usec/call
+iadd8 0.0674 usec/call
+isub8 0.0676 usec/call
+imul8 0.0718 usec/call
+idiv8 0.0862 usec/call
+iadd16 0.0672 usec/call
+isub16 0.0676 usec/call
+imul16 0.0718 usec/call
+idiv16 0.0852 usec/call
+iadd32 0.0610 usec/call
+isub32 0.0614 usec/call
+imul32 0.0612 usec/call
+idiv32 0.0654 usec/call
+iadd64 0.1232 usec/call
+isub64 0.1232 usec/call
+imul64 0.1712 usec/call
+idiv64 0.3848 usec/call
+memcpy128 0.5094 usec/call
+memset128 0.3917 usec/call
+delay(1) 164.9920 usec/call
+SEM 6.1196 usec/call
diff --git a/Tools/GIT_Test/GIT_Success.txt b/Tools/GIT_Test/GIT_Success.txt
index cce4dddf532196..54dfab7eb55bac 100644
--- a/Tools/GIT_Test/GIT_Success.txt
+++ b/Tools/GIT_Test/GIT_Success.txt
@@ -173,4 +173,7 @@ Ava Falkner
Emre Can Suiçmez
Yacine Thabet - 57
Greg Poulos
-Torre Orazio
\ No newline at end of file
+Torre Orazio
+seba czapnik
+Ramy Gad
+Matthew R. Cunningham
\ No newline at end of file
diff --git a/Tools/IO_Firmware/iofirmware_dshot_highpolh.bin b/Tools/IO_Firmware/iofirmware_dshot_highpolh.bin
new file mode 100755
index 00000000000000..441aa59e79f6c7
Binary files /dev/null and b/Tools/IO_Firmware/iofirmware_dshot_highpolh.bin differ
diff --git a/Tools/IO_Firmware/iofirmware_dshot_lowpolh.bin b/Tools/IO_Firmware/iofirmware_dshot_lowpolh.bin
new file mode 100755
index 00000000000000..0bce6c10f1ecd1
Binary files /dev/null and b/Tools/IO_Firmware/iofirmware_dshot_lowpolh.bin differ
diff --git a/Tools/IO_Firmware/iofirmware_f103_8MHz_highpolh.bin b/Tools/IO_Firmware/iofirmware_f103_8MHz_highpolh.bin
index d148daded7da40..82065f85eb99b0 100755
Binary files a/Tools/IO_Firmware/iofirmware_f103_8MHz_highpolh.bin and b/Tools/IO_Firmware/iofirmware_f103_8MHz_highpolh.bin differ
diff --git a/Tools/IO_Firmware/iofirmware_f103_8MHz_lowpolh.bin b/Tools/IO_Firmware/iofirmware_f103_8MHz_lowpolh.bin
index b3036b63edd7aa..9897dce49e79c2 100755
Binary files a/Tools/IO_Firmware/iofirmware_f103_8MHz_lowpolh.bin and b/Tools/IO_Firmware/iofirmware_f103_8MHz_lowpolh.bin differ
diff --git a/Tools/IO_Firmware/iofirmware_f103_dshot_highpolh.bin b/Tools/IO_Firmware/iofirmware_f103_dshot_highpolh.bin
new file mode 100644
index 00000000000000..2c1bd7e9d57eb8
Binary files /dev/null and b/Tools/IO_Firmware/iofirmware_f103_dshot_highpolh.bin differ
diff --git a/Tools/IO_Firmware/iofirmware_f103_dshot_lowpolh.bin b/Tools/IO_Firmware/iofirmware_f103_dshot_lowpolh.bin
new file mode 100644
index 00000000000000..6276596b429b01
Binary files /dev/null and b/Tools/IO_Firmware/iofirmware_f103_dshot_lowpolh.bin differ
diff --git a/Tools/IO_Firmware/iofirmware_f103_highpolh.bin b/Tools/IO_Firmware/iofirmware_f103_highpolh.bin
new file mode 100644
index 00000000000000..8a21b6e17ebc70
Binary files /dev/null and b/Tools/IO_Firmware/iofirmware_f103_highpolh.bin differ
diff --git a/Tools/IO_Firmware/iofirmware_f103_lowpolh.bin b/Tools/IO_Firmware/iofirmware_f103_lowpolh.bin
new file mode 100644
index 00000000000000..1723b089d741cc
Binary files /dev/null and b/Tools/IO_Firmware/iofirmware_f103_lowpolh.bin differ
diff --git a/Tools/IO_Firmware/iofirmware_highpolh.bin b/Tools/IO_Firmware/iofirmware_highpolh.bin
index 3f308f141ffa12..12aa45dc089501 100755
Binary files a/Tools/IO_Firmware/iofirmware_highpolh.bin and b/Tools/IO_Firmware/iofirmware_highpolh.bin differ
diff --git a/Tools/IO_Firmware/iofirmware_lowpolh.bin b/Tools/IO_Firmware/iofirmware_lowpolh.bin
index defcab7926f50f..63e9f7040c6e49 100755
Binary files a/Tools/IO_Firmware/iofirmware_lowpolh.bin and b/Tools/IO_Firmware/iofirmware_lowpolh.bin differ
diff --git a/Tools/Replay/LR_MsgHandler.cpp b/Tools/Replay/LR_MsgHandler.cpp
index 8b9d2bd4315111..cbdca233afaf68 100644
--- a/Tools/Replay/LR_MsgHandler.cpp
+++ b/Tools/Replay/LR_MsgHandler.cpp
@@ -289,6 +289,12 @@ void LR_MsgHandler_REPH::process_message(uint8_t *msgbytes)
AP::dal().handle_message(msg, ekf2, ekf3);
}
+void LR_MsgHandler_RSLL::process_message(uint8_t *msgbytes)
+{
+ MSG_CREATE(RSLL, msgbytes);
+ AP::dal().handle_message(msg, ekf2, ekf3);
+}
+
void LR_MsgHandler_REVH::process_message(uint8_t *msgbytes)
{
MSG_CREATE(REVH, msgbytes);
diff --git a/Tools/Replay/LR_MsgHandler.h b/Tools/Replay/LR_MsgHandler.h
index b258f496e728a0..4e30a6571d35ce 100644
--- a/Tools/Replay/LR_MsgHandler.h
+++ b/Tools/Replay/LR_MsgHandler.h
@@ -57,6 +57,12 @@ class LR_MsgHandler_REPH : public LR_MsgHandler_EKF
void process_message(uint8_t *msg) override;
};
+class LR_MsgHandler_RSLL : public LR_MsgHandler_EKF
+{
+ using LR_MsgHandler_EKF::LR_MsgHandler_EKF;
+ void process_message(uint8_t *msg) override;
+};
+
class LR_MsgHandler_REVH : public LR_MsgHandler_EKF
{
using LR_MsgHandler_EKF::LR_MsgHandler_EKF;
diff --git a/Tools/Replay/LogReader.cpp b/Tools/Replay/LogReader.cpp
index d36c3da3fe9e19..9a84053ab81ada 100644
--- a/Tools/Replay/LogReader.cpp
+++ b/Tools/Replay/LogReader.cpp
@@ -118,6 +118,8 @@ bool LogReader::handle_log_format_msg(const struct log_Format &f)
msgparser[f.type] = new LR_MsgHandler_ROFH(formats[f.type], ekf2, ekf3);
} else if (streq(name, "REPH")) {
msgparser[f.type] = new LR_MsgHandler_REPH(formats[f.type], ekf2, ekf3);
+ } else if (streq(name, "RSLL")) {
+ msgparser[f.type] = new LR_MsgHandler_RSLL(formats[f.type], ekf2, ekf3);
} else if (streq(name, "REVH")) {
msgparser[f.type] = new LR_MsgHandler_REVH(formats[f.type], ekf2, ekf3);
} else if (streq(name, "RWOH")) {
diff --git a/Tools/ardupilotwaf/ap_library.py b/Tools/ardupilotwaf/ap_library.py
index 9c7b42f7749890..b49010ae06001c 100644
--- a/Tools/ardupilotwaf/ap_library.py
+++ b/Tools/ardupilotwaf/ap_library.py
@@ -270,11 +270,15 @@ def double_precision_check(tasks):
double_tasks.append([library, s])
src = str(t.inputs[0]).split('/')[-2:]
- if src in double_tasks:
- single_precision_option='-fsingle-precision-constant'
+ double_library = t.env.DOUBLE_PRECISION_LIBRARIES.get(src[0],False)
+
+ if double_library or src in double_tasks:
t.env.CXXFLAGS = t.env.CXXFLAGS[:]
- if single_precision_option in t.env.CXXFLAGS:
- t.env.CXXFLAGS.remove(single_precision_option)
+ for opt in ['-fsingle-precision-constant', '-cl-single-precision-constant']:
+ try:
+ t.env.CXXFLAGS.remove(opt)
+ except ValueError:
+ pass
t.env.CXXFLAGS.append("-DALLOW_DOUBLE_MATH_FUNCTIONS")
@@ -321,3 +325,4 @@ def configure(cfg):
cfg.env.AP_LIB_EXTRA_CXXFLAGS = dict()
cfg.env.AP_LIB_EXTRA_CFLAGS = dict()
cfg.env.DOUBLE_PRECISION_SOURCES = dict()
+ cfg.env.DOUBLE_PRECISION_LIBRARIES = dict()
diff --git a/Tools/ardupilotwaf/ardupilotwaf.py b/Tools/ardupilotwaf/ardupilotwaf.py
index 4ef709a99051ce..75c9975b826bd7 100644
--- a/Tools/ardupilotwaf/ardupilotwaf.py
+++ b/Tools/ardupilotwaf/ardupilotwaf.py
@@ -34,6 +34,7 @@
'AP_HAL',
'AP_HAL_Empty',
'AP_InertialSensor',
+ 'AP_KDECAN',
'AP_Math',
'AP_Mission',
'AP_DAL',
@@ -63,6 +64,7 @@
'AP_Module',
'AP_Button',
'AP_ICEngine',
+ 'AP_Networking',
'AP_Frsky_Telem',
'AP_FlashStorage',
'AP_Relay',
@@ -113,6 +115,7 @@
'AP_AIS',
'AP_OpenDroneID',
'AP_CheckFirmware',
+ 'AP_ExternalControl',
]
def get_legacy_defines(sketch_name, bld):
@@ -302,6 +305,8 @@ def ap_program(bld,
for group in program_groups:
_grouped_programs.setdefault(group, {}).update({tg.name : tg})
+ return tg
+
@conf
def ap_example(bld, **kw):
@@ -353,7 +358,7 @@ def ap_stlib_target(self):
self.target = '#%s' % os.path.join('lib', self.target)
@conf
-def ap_find_tests(bld, use=[]):
+def ap_find_tests(bld, use=[], DOUBLE_PRECISION_SOURCES=[]):
if not bld.env.HAS_GTEST:
return
@@ -367,7 +372,7 @@ def ap_find_tests(bld, use=[]):
includes = [bld.srcnode.abspath() + '/tests/']
for f in bld.path.ant_glob(incl='*.cpp'):
- ap_program(
+ t = ap_program(
bld,
features=features,
includes=includes,
@@ -378,6 +383,16 @@ def ap_find_tests(bld, use=[]):
use_legacy_defines=False,
cxxflags=['-Wno-undef'],
)
+ filename = os.path.basename(f.abspath())
+ if filename in DOUBLE_PRECISION_SOURCES:
+ t.env.CXXFLAGS = t.env.CXXFLAGS[:]
+ single_precision_option='-fsingle-precision-constant'
+ if single_precision_option in t.env.CXXFLAGS:
+ t.env.CXXFLAGS.remove(single_precision_option)
+ single_precision_option='-cl-single-precision-constant'
+ if single_precision_option in t.env.CXXFLAGS:
+ t.env.CXXFLAGS.remove(single_precision_option)
+ t.env.CXXFLAGS.append("-DALLOW_DOUBLE_MATH_FUNCTIONS")
_versions = []
@@ -564,6 +579,11 @@ def options(opt):
help='''Specify the port to be used with the --upload option. For example a port of /dev/ttyS10 indicates that serial port 10 shuld be used.
''')
+ g.add_option('--upload-force',
+ action='store_true',
+ help='''Override board type check and continue loading. Same as using uploader.py --force.
+''')
+
g = opt.ap_groups['check']
g.add_option('--check-verbose',
diff --git a/Tools/ardupilotwaf/boards.py b/Tools/ardupilotwaf/boards.py
index d8dae5af9f46da..36fbce5d709ba4 100644
--- a/Tools/ardupilotwaf/boards.py
+++ b/Tools/ardupilotwaf/boards.py
@@ -47,29 +47,24 @@ def srcpath(path):
env.SRCROOT = srcpath('')
self.configure_env(cfg, env)
+ # Setup scripting:
env.DEFINES.update(
- AP_SCRIPTING_ENABLED = 0,
+ LUA_32BITS = 1,
)
- # Setup scripting, had to defer this to allow checking board size
- if ((not cfg.options.disable_scripting) and
- (not cfg.env.DISABLE_SCRIPTING) and
- ((cfg.env.BOARD_FLASH_SIZE is None) or
- (cfg.env.BOARD_FLASH_SIZE == []) or
- (cfg.env.BOARD_FLASH_SIZE > 1024))):
+ env.AP_LIBRARIES += [
+ 'AP_Scripting',
+ 'AP_Scripting/lua/src',
+ ]
+ if cfg.options.enable_scripting:
env.DEFINES.update(
AP_SCRIPTING_ENABLED = 1,
- LUA_32BITS = 1,
- )
-
- env.AP_LIBRARIES += [
- 'AP_Scripting',
- 'AP_Scripting/lua/src',
- ]
-
- else:
- cfg.options.disable_scripting = True
+ )
+ elif cfg.options.disable_scripting:
+ env.DEFINES.update(
+ AP_SCRIPTING_ENABLED = 0,
+ )
# allow GCS disable for AP_DAL example
if cfg.options.no_gcs:
@@ -248,16 +243,20 @@ def configure_env(self, cfg, env):
if 'clang' in cfg.env.COMPILER_CC:
env.CFLAGS += [
'-fcolor-diagnostics',
-
'-Wno-gnu-designator',
'-Wno-inconsistent-missing-override',
'-Wno-mismatched-tags',
'-Wno-gnu-variable-sized-type-not-at-end',
'-Werror=implicit-fallthrough',
+ '-cl-single-precision-constant',
+ ]
+ env.CXXFLAGS += [
+ '-cl-single-precision-constant',
]
else:
env.CFLAGS += [
'-Wno-format-contains-nul',
+ '-fsingle-precision-constant', # force const vals to be float , not double. so 100.0 means 100.0f
]
if self.cc_version_gte(cfg, 7, 4):
env.CXXFLAGS += [
@@ -265,6 +264,7 @@ def configure_env(self, cfg, env):
]
env.CXXFLAGS += [
'-fcheck-new',
+ '-fsingle-precision-constant',
]
if cfg.env.DEBUG:
@@ -275,6 +275,10 @@ def configure_env(self, cfg, env):
env.DEFINES.update(
HAL_DEBUG_BUILD = 1,
)
+ elif cfg.options.debug_symbols:
+ env.CFLAGS += [
+ '-g',
+ ]
if cfg.env.COVERAGE:
env.CFLAGS += [
'-fprofile-arcs',
@@ -442,6 +446,7 @@ def configure_env(self, cfg, env):
DRONECAN_CXX_WRAPPERS = 1,
USE_USER_HELPERS = 1,
CANARD_ENABLE_DEADLINE = 1,
+ CANARD_ALLOCATE_SEM=1
)
@@ -546,7 +551,11 @@ def add_dynamic_boards_esp32():
continue
hwdef = os.path.join(dirname, d, 'hwdef.dat')
if os.path.exists(hwdef):
- newclass = type(d, (esp32,), {'name': d})
+ mcu_esp32s3 = True if (d[0:7] == "esp32s3") else False
+ if mcu_esp32s3:
+ newclass = type(d, (esp32s3,), {'name': d})
+ else:
+ newclass = type(d, (esp32,), {'name': d})
def get_boards_names():
add_dynamic_boards_chibios()
@@ -628,7 +637,7 @@ def configure_env(self, cfg, env):
CONFIG_HAL_BOARD = 'HAL_BOARD_SITL',
CONFIG_HAL_BOARD_SUBTYPE = 'HAL_BOARD_SUBTYPE_NONE',
AP_SCRIPTING_CHECKS = 1, # SITL should always do runtime scripting checks
- HAL_PROBE_EXTERNAL_I2C_BAROS = 1,
+ AP_BARO_PROBE_EXTERNAL_I2C_BUSES = 1,
)
cfg.define('AP_SIM_ENABLED', 1)
@@ -638,14 +647,19 @@ def configure_env(self, cfg, env):
cfg.define('AP_OPENDRONEID_ENABLED', 1)
cfg.define('AP_SIGNED_FIRMWARE', 0)
+ cfg.define('AP_NOTIFY_LP5562_BUS', 2)
+ cfg.define('AP_NOTIFY_LP5562_ADDR', 0x30)
+
if self.with_can:
cfg.define('HAL_NUM_CAN_IFACES', 2)
env.DEFINES.update(CANARD_MULTI_IFACE=1,
CANARD_IFACE_ALL = 0x3,
- CANARD_ENABLE_CANFD = 1)
+ CANARD_ENABLE_CANFD = 1,
+ CANARD_ENABLE_ASSERTS = 1)
env.CXXFLAGS += [
- '-Werror=float-equal'
+ '-Werror=float-equal',
+ '-Werror=missing-declarations',
]
if cfg.options.ubsan or cfg.options.ubsan_abort:
@@ -692,10 +706,9 @@ def configure_env(self, cfg, env):
'AP_CSVReader',
]
- if not cfg.env.AP_PERIPH:
- env.AP_LIBRARIES += [
- 'SITL',
- ]
+ env.AP_LIBRARIES += [
+ 'SITL',
+ ]
if cfg.options.enable_sfml:
if not cfg.check_SFML(env):
@@ -762,6 +775,34 @@ def configure_env(self, cfg, env):
'-m32',
]
+ # whitelist of compilers which we should build with -Werror
+ gcc_whitelist = frozenset([
+ ('11','3','0'),
+ ('12','1','0'),
+ ])
+
+ # initialise werr_enabled from defaults:
+ werr_enabled = bool('g++' in cfg.env.COMPILER_CXX and cfg.env.CC_VERSION in gcc_whitelist)
+
+ # now process overrides to that default:
+ if (cfg.options.Werror is not None and
+ cfg.options.Werror == cfg.options.disable_Werror):
+ cfg.fatal("Asked to both enable and disable Werror")
+
+ if cfg.options.Werror is not None:
+ werr_enabled = cfg.options.Werror
+ elif cfg.options.disable_Werror is not None:
+ werr_enabled = not cfg.options.disable_Werror
+
+ if werr_enabled:
+ cfg.msg("Enabling -Werror", "yes")
+ if '-Werror' not in env.CXXFLAGS:
+ env.CXXFLAGS += [ '-Werror' ]
+ else:
+ cfg.msg("Enabling -Werror", "no")
+ if '-Werror' in env.CXXFLAGS:
+ env.CXXFLAGS.remove('-Werror')
+
def get_name(self):
return self.__class__.__name__
@@ -769,14 +810,24 @@ def get_name(self):
class sitl_periph_gps(sitl):
def configure_env(self, cfg, env):
cfg.env.AP_PERIPH = 1
- cfg.env.DISABLE_SCRIPTING = 1
super(sitl_periph_gps, self).configure_env(cfg, env)
env.DEFINES.update(
HAL_BUILD_AP_PERIPH = 1,
PERIPH_FW = 1,
- CAN_APP_NODE_NAME = '"org.ardupilot.ap_periph_gps"',
- AP_AIRSPEED_ENABLED = 0,
+ CAN_APP_NODE_NAME = '"org.ardupilot.ap_periph"',
HAL_PERIPH_ENABLE_GPS = 1,
+ HAL_PERIPH_ENABLE_AIRSPEED = 1,
+ HAL_PERIPH_ENABLE_MAG = 1,
+ HAL_PERIPH_ENABLE_BARO = 1,
+ HAL_PERIPH_ENABLE_RANGEFINDER = 1,
+ HAL_PERIPH_ENABLE_BATTERY = 1,
+ HAL_PERIPH_ENABLE_EFI = 1,
+ HAL_PERIPH_ENABLE_RPM = 1,
+ HAL_PERIPH_ENABLE_RC_OUT = 1,
+ AP_AIRSPEED_ENABLED = 1,
+ AP_AIRSPEED_AUTOCAL_ENABLE = 0,
+ AP_AHRS_ENABLED = 1,
+ AP_UART_MONITOR_ENABLED = 1,
HAL_CAN_DEFAULT_NODE_ID = 0,
HAL_RAM_RESERVE_START = 0,
APJ_BOARD_ID = 100,
@@ -787,18 +838,25 @@ def configure_env(self, cfg, env):
HAL_RALLY_ENABLED = 0,
AP_SCHEDULER_ENABLED = 0,
CANARD_ENABLE_TAO_OPTION = 1,
+ AP_RCPROTOCOL_ENABLED = 0,
CANARD_ENABLE_CANFD = 1,
CANARD_MULTI_IFACE = 1,
HAL_CANMANAGER_ENABLED = 0,
COMPASS_CAL_ENABLED = 0,
COMPASS_MOT_ENABLED = 0,
COMPASS_LEARN_ENABLED = 0,
- AP_BATTERY_ESC_ENABLED = 0,
+ AP_BATTERY_ESC_ENABLED = 1,
HAL_EXTERNAL_AHRS_ENABLED = 0,
HAL_GENERATOR_ENABLED = 0,
AP_STATS_ENABLED = 0,
HAL_SUPPORT_RCOUT_SERIAL = 0,
AP_CAN_SLCAN_ENABLED = 0,
+ HAL_PROXIMITY_ENABLED = 0,
+ AP_SCRIPTING_ENABLED = 0,
+ HAL_NAVEKF2_AVAILABLE = 0,
+ HAL_NAVEKF3_AVAILABLE = 0,
+ HAL_PWM_COUNT = 32,
+ HAL_WITH_ESC_TELEM = 1,
)
@@ -827,7 +885,7 @@ def expand_path(p):
env.DEFINES.update(
ENABLE_HEAP = 0,
CONFIG_HAL_BOARD_SUBTYPE = 'HAL_BOARD_SUBTYPE_ESP32_%s' % tt.upper() ,
- ALLOW_DOUBLE_MATH_FUNCTIONS = '1',
+ HAL_HAVE_HARDWARE_DOUBLE = '1',
)
env.AP_LIBRARIES += [
@@ -852,6 +910,7 @@ def expand_path(p):
'-Wno-sign-compare',
'-fno-inline-functions',
'-mlongcalls',
+ '-fno-threadsafe-statics',
'-DCYGWIN_BUILD']
env.CXXFLAGS.remove('-Werror=undef')
env.CXXFLAGS.remove('-Werror=shadow')
@@ -881,6 +940,9 @@ def build(self, bld):
def get_name(self):
return self.__class__.__name__
+class esp32s3(esp32):
+ abstract = True
+ toolchain = 'xtensa-esp32s3-elf'
class chibios(Board):
abstract = True
@@ -910,7 +972,6 @@ def configure_env(self, cfg, env):
env.CFLAGS += cfg.env.CPU_FLAGS + [
'-Wlogical-op',
'-Wframe-larger-than=1300',
- '-fsingle-precision-constant',
'-Wno-attributes',
'-fno-exceptions',
'-Wall',
@@ -967,6 +1028,7 @@ def configure_env(self, cfg, env):
bldnode = cfg.bldnode.make_node(self.name)
env.BUILDROOT = bldnode.make_node('').abspath()
+
env.LINKFLAGS = cfg.env.CPU_FLAGS + [
'-fomit-frame-pointer',
'-falign-functions=16',
@@ -988,7 +1050,7 @@ def configure_env(self, cfg, env):
'-L%s' % env.BUILDROOT,
'-L%s' % cfg.srcnode.make_node('modules/ChibiOS/os/common/startup/ARMCMx/compilers/GCC/ld/').abspath(),
'-L%s' % cfg.srcnode.make_node('libraries/AP_HAL_ChibiOS/hwdef/common/').abspath(),
- '-Wl,-Map,Linker.map,--cref,--gc-sections,--no-warn-mismatch,--library-path=/ld,--script=ldscript.ld,--defsym=__process_stack_size__=%s,--defsym=__main_stack_size__=%s' % (cfg.env.PROCESS_STACK, cfg.env.MAIN_STACK)
+ '-Wl,-Map,Linker.map,%s--cref,--gc-sections,--no-warn-mismatch,--library-path=/ld,--script=ldscript.ld,--defsym=__process_stack_size__=%s,--defsym=__main_stack_size__=%s' % ("--print-memory-usage," if cfg.env.EXT_FLASH_SIZE_MB > 0 and cfg.env.INT_FLASH_PRIMARY == 0 else "", cfg.env.PROCESS_STACK, cfg.env.MAIN_STACK)
]
if cfg.env.DEBUG:
@@ -1001,6 +1063,11 @@ def configure_env(self, cfg, env):
'-g3',
]
+ if cfg.env.COMPILER_CXX == "g++":
+ if not self.cc_version_gte(cfg, 10, 2):
+ # require at least 10.2 compiler
+ cfg.fatal("ChibiOS build requires g++ version 10.2.1 or later, found %s" % '.'.join(cfg.env.CC_VERSION))
+
if cfg.env.ENABLE_ASSERTS:
cfg.msg("Enabling ChibiOS asserts", "yes")
env.CFLAGS += [ '-DHAL_CHIBIOS_ENABLE_ASSERTS' ]
@@ -1012,7 +1079,7 @@ def configure_env(self, cfg, env):
if cfg.env.SAVE_TEMPS:
env.CXXFLAGS += [ '-S', '-save-temps=obj' ]
- if cfg.options.disable_watchdog or cfg.env.DEBUG:
+ if cfg.options.disable_watchdog:
cfg.msg("Disabling Watchdog", "yes")
env.CFLAGS += [ '-DDISABLE_WATCHDOG' ]
env.CXXFLAGS += [ '-DDISABLE_WATCHDOG' ]
@@ -1056,13 +1123,14 @@ def configure_env(self, cfg, env):
]
# whitelist of compilers which we should build with -Werror
- gcc_whitelist = [
+ gcc_whitelist = frozenset([
('4','9','3'),
('6','3','1'),
('9','2','1'),
('9','3','1'),
('10','2','1'),
- ]
+ ('11','3','0'),
+ ])
if cfg.env.HAL_CANFD_SUPPORTED:
env.DEFINES.update(CANARD_ENABLE_CANFD=1)
diff --git a/Tools/ardupilotwaf/build_summary.py b/Tools/ardupilotwaf/build_summary.py
index d7002543965ce7..6a0abacc827f7c 100644
--- a/Tools/ardupilotwaf/build_summary.py
+++ b/Tools/ardupilotwaf/build_summary.py
@@ -49,6 +49,7 @@
'size_bss': 'BSS (B)',
'size_total': 'Total Flash Used (B)',
'size_free_flash': 'Free Flash (B)',
+ 'ext_flash_used': 'External Flash Used (B)',
}
def text(label, text=''):
@@ -170,14 +171,19 @@ def _build_summary(bld):
def _parse_size_output(s, s_all, totals=False):
# Get the size of .crash_log to remove it from .bss reporting
+ # also get external flash size if applicable
crash_log_size = None
+ ext_flash_used = 0
if s_all is not None:
lines = s_all.splitlines()[1:]
for line in lines:
if ".crash_log" in line:
row = line.strip().split()
crash_log_size = int(row[1])
- break
+ if ".extflash" in line:
+ row = line.strip().split()
+ if int(row[1]) > 0:
+ ext_flash_used = int(row[1])
import re
pattern = re.compile("^.*TOTALS.*$")
@@ -203,8 +209,9 @@ def _parse_size_output(s, s_all, totals=False):
size_data=int(row[1]),
size_bss=size_bss,
# Total Flash Cost = Data + Text
- size_total=int(row[0]) + int(row[1]),
+ size_total=int(row[0]) + int(row[1]) - ext_flash_used,
size_free_flash=size_free_flash,
+ ext_flash_used= ext_flash_used if ext_flash_used else None,
))
return l
@@ -285,4 +292,5 @@ def configure(cfg):
'size_bss',
'size_total',
'size_free_flash',
+ 'ext_flash_used',
]
diff --git a/Tools/ardupilotwaf/chibios.py b/Tools/ardupilotwaf/chibios.py
index 2c7d35bbc43205..83c41cb81dba7f 100644
--- a/Tools/ardupilotwaf/chibios.py
+++ b/Tools/ardupilotwaf/chibios.py
@@ -64,11 +64,13 @@ def run(self):
if not self.wsl2_prereq_checks():
return
print("If this takes takes too long here, try power-cycling your hardware\n")
- cmd = "{} '{}/uploader.py' '{}'".format('python.exe', upload_tools, src.abspath())
+ cmd = "{} -u '{}/uploader.py' '{}'".format('python.exe', upload_tools, src.abspath())
else:
cmd = "{} '{}/uploader.py' '{}'".format(self.env.get_flat('PYTHON'), upload_tools, src.abspath())
if upload_port is not None:
cmd += " '--port' '%s'" % upload_port
+ if self.generator.bld.options.upload_force:
+ cmd += " '--force'"
return self.exec_command(cmd)
def wsl2_prereq_checks(self):
@@ -455,7 +457,8 @@ def setup_canmgr_build(cfg):
'DRONECAN_CXX_WRAPPERS=1',
'USE_USER_HELPERS=1',
'CANARD_ENABLE_DEADLINE=1',
- 'CANARD_MULTI_IFACE=1'
+ 'CANARD_MULTI_IFACE=1',
+ 'CANARD_ALLOCATE_SEM=1'
]
if cfg.env.HAL_CANFD_SUPPORTED:
@@ -492,6 +495,8 @@ def load_env_vars(env):
else:
env[k] = v
print("env set %s=%s" % (k, v))
+ if env.DEBUG or env.DEBUG_SYMBOLS:
+ env.CHIBIOS_BUILD_FLAGS += ' ENABLE_DEBUG_SYMBOLS=yes'
if env.ENABLE_ASSERTS:
env.CHIBIOS_BUILD_FLAGS += ' ENABLE_ASSERTS=yes'
if env.ENABLE_MALLOC_GUARD:
@@ -647,13 +652,22 @@ def build(bld):
bld(
# create the file modules/ChibiOS/include_dirs
- rule="touch Makefile && BUILDDIR=${BUILDDIR_REL} CRASHCATCHER=${CC_ROOT_REL} CHIBIOS=${CH_ROOT_REL} AP_HAL=${AP_HAL_REL} ${CHIBIOS_BUILD_FLAGS} ${CHIBIOS_BOARD_NAME} ${MAKE} pass -f '${BOARD_MK}'",
+ rule="touch Makefile && BUILDDIR=${BUILDDIR_REL} BUILDROOT=${BUILDROOT} CRASHCATCHER=${CC_ROOT_REL} CHIBIOS=${CH_ROOT_REL} AP_HAL=${AP_HAL_REL} ${CHIBIOS_BUILD_FLAGS} ${CHIBIOS_BOARD_NAME} ${MAKE} pass -f '${BOARD_MK}'",
group='dynamic_sources',
target=bld.bldnode.find_or_declare('modules/ChibiOS/include_dirs')
)
+ bld(
+ # create the file modules/ChibiOS/include_dirs
+ rule="echo // BUILD_FLAGS: ${BUILDDIR_REL} ${BUILDROOT} ${CC_ROOT_REL} ${CH_ROOT_REL} ${AP_HAL_REL} ${CHIBIOS_BUILD_FLAGS} ${CHIBIOS_BOARD_NAME} ${HAL_MAX_STACK_FRAME_SIZE} > chibios_flags.h",
+ group='dynamic_sources',
+ target=bld.bldnode.find_or_declare('chibios_flags.h')
+ )
+
common_src = [bld.bldnode.find_or_declare('hwdef.h'),
bld.bldnode.find_or_declare('hw.dat'),
+ bld.bldnode.find_or_declare('ldscript.ld'),
+ bld.bldnode.find_or_declare('common.ld'),
bld.bldnode.find_or_declare('modules/ChibiOS/include_dirs')]
common_src += bld.path.ant_glob('libraries/AP_HAL_ChibiOS/hwdef/common/*.[ch]')
common_src += bld.path.ant_glob('libraries/AP_HAL_ChibiOS/hwdef/common/*.mk')
@@ -665,7 +679,7 @@ def build(bld):
if bld.env.ENABLE_CRASHDUMP:
ch_task = bld(
# build libch.a from ChibiOS sources and hwdef.h
- rule="BUILDDIR='${BUILDDIR_REL}' CRASHCATCHER='${CC_ROOT_REL}' CHIBIOS='${CH_ROOT_REL}' AP_HAL=${AP_HAL_REL} ${CHIBIOS_BUILD_FLAGS} ${CHIBIOS_BOARD_NAME} ${HAL_MAX_STACK_FRAME_SIZE} '${MAKE}' -j%u lib -f '${BOARD_MK}'" % bld.options.jobs,
+ rule="BUILDDIR='${BUILDDIR_REL}' BUILDROOT='${BUILDROOT}' CRASHCATCHER='${CC_ROOT_REL}' CHIBIOS='${CH_ROOT_REL}' AP_HAL=${AP_HAL_REL} ${CHIBIOS_BUILD_FLAGS} ${CHIBIOS_BOARD_NAME} ${HAL_MAX_STACK_FRAME_SIZE} '${MAKE}' -j%u lib -f '${BOARD_MK}'" % bld.options.jobs,
group='dynamic_sources',
source=common_src,
target=[bld.bldnode.find_or_declare('modules/ChibiOS/libch.a'), bld.bldnode.find_or_declare('modules/ChibiOS/libcc.a')]
@@ -673,7 +687,7 @@ def build(bld):
else:
ch_task = bld(
# build libch.a from ChibiOS sources and hwdef.h
- rule="BUILDDIR='${BUILDDIR_REL}' CHIBIOS='${CH_ROOT_REL}' AP_HAL=${AP_HAL_REL} ${CHIBIOS_BUILD_FLAGS} ${CHIBIOS_BOARD_NAME} ${HAL_MAX_STACK_FRAME_SIZE} '${MAKE}' -j%u lib -f '${BOARD_MK}'" % bld.options.jobs,
+ rule="BUILDDIR='${BUILDDIR_REL}' BUILDROOT='${BUILDROOT}' CHIBIOS='${CH_ROOT_REL}' AP_HAL=${AP_HAL_REL} ${CHIBIOS_BUILD_FLAGS} ${CHIBIOS_BOARD_NAME} ${HAL_MAX_STACK_FRAME_SIZE} '${MAKE}' -j%u lib -f '${BOARD_MK}'" % bld.options.jobs,
group='dynamic_sources',
source=common_src,
target=bld.bldnode.find_or_declare('modules/ChibiOS/libch.a')
@@ -703,6 +717,7 @@ def build(bld):
'fopen', 'fflush', 'fwrite', 'fread', 'fputs', 'fgets',
'clearerr', 'fseek', 'ferror', 'fclose', 'tmpfile', 'getc', 'ungetc', 'feof',
'ftell', 'freopen', 'remove', 'vfprintf', 'fscanf',
- '_gettimeofday', '_times', '_times_r', '_gettimeofday_r', 'time', 'clock' ]
+ '_gettimeofday', '_times', '_times_r', '_gettimeofday_r', 'time', 'clock',
+ '_sbrk', '_sbrk_r', '_malloc_r', '_calloc_r', '_free_r']
for w in wraplist:
bld.env.LINKFLAGS += ['-Wl,--wrap,%s' % w]
diff --git a/Tools/ardupilotwaf/cmake.py b/Tools/ardupilotwaf/cmake.py
index 9ec9691c150ae1..0616de6128ed6f 100644
--- a/Tools/ardupilotwaf/cmake.py
+++ b/Tools/ardupilotwaf/cmake.py
@@ -23,7 +23,7 @@
the configuration to set a minimum version required for cmake. Example::
def configure(cfg):
- cfg.CMAKE_MIN_VERSION = '3.5.2'
+ cfg.env.CMAKE_MIN_VERSION = '3.5.2'
cfg.load('cmake')
Usage example::
diff --git a/Tools/ardupilotwaf/dronecangen.py b/Tools/ardupilotwaf/dronecangen.py
index d4101be9ec9850..f6e067da3ea237 100644
--- a/Tools/ardupilotwaf/dronecangen.py
+++ b/Tools/ardupilotwaf/dronecangen.py
@@ -66,9 +66,6 @@ def configure(cfg):
"""
setup environment for uavcan header generator
"""
- cfg.load('python')
- cfg.check_python_version(minver=(2,7,0))
-
env = cfg.env
env.DC_DSDL_COMPILER_DIR = cfg.srcnode.make_node('modules/DroneCAN/dronecan_dsdlc/').abspath()
env.DC_DSDL_COMPILER = env.DC_DSDL_COMPILER_DIR + '/dronecan_dsdlc.py'
diff --git a/Tools/ardupilotwaf/embed.py b/Tools/ardupilotwaf/embed.py
index d833b40c977459..ccc9673985ea10 100755
--- a/Tools/ardupilotwaf/embed.py
+++ b/Tools/ardupilotwaf/embed.py
@@ -34,7 +34,7 @@ def embed_file(out, f, idx, embedded_name, uncompressed):
print("Padded %u bytes for %s to %u" % (pad, embedded_name, len(contents)))
crc = crc32(bytearray(contents))
- write_encode(out, 'static const uint8_t ap_romfs_%u[] = {' % idx)
+ write_encode(out, '__EXTFLASHFUNC__ static const uint8_t ap_romfs_%u[] = {' % idx)
compressed = tempfile.NamedTemporaryFile()
if uncompressed:
diff --git a/Tools/ardupilotwaf/esp32.py b/Tools/ardupilotwaf/esp32.py
index 8631abff3c2d3a..20a9528860de18 100644
--- a/Tools/ardupilotwaf/esp32.py
+++ b/Tools/ardupilotwaf/esp32.py
@@ -18,7 +18,8 @@
import subprocess
def configure(cfg):
-
+ mcu_esp32s3 = True if (cfg.variant[0:7] == "esp32s3") else False
+ target = "esp32s3" if mcu_esp32s3 else "esp32"
bldnode = cfg.bldnode.make_node(cfg.variant)
def srcpath(path):
return cfg.srcnode.make_node(path).abspath()
@@ -30,13 +31,13 @@ def bldpath(path):
#define env and location for the cmake esp32 file
env = cfg.env
- env.AP_HAL_ESP32 = srcpath('libraries/AP_HAL_ESP32/targets/esp-idf')
+ env.AP_HAL_ESP32 = srcpath('libraries/AP_HAL_ESP32/targets/'+target+'/esp-idf')
env.AP_PROGRAM_FEATURES += ['esp32_ap_program']
env.ESP_IDF_PREFIX_REL = 'esp-idf'
prefix_node = bldnode.make_node(env.ESP_IDF_PREFIX_REL)
-
+ env.ESP32_TARGET = target
env.BUILDROOT = bldpath('')
env.SRCROOT = srcpath('')
env.APJ_TOOL = srcpath('Tools/scripts/apj_tool.py')
@@ -63,10 +64,11 @@ def pre_build(self):
lib_vars['ARDUPILOT_CMD'] = self.cmd
lib_vars['ARDUPILOT_LIB'] = self.bldnode.find_or_declare('lib/').abspath()
lib_vars['ARDUPILOT_BIN'] = self.bldnode.find_or_declare('lib/bin').abspath()
+ target = self.env.ESP32_TARGET
esp_idf = self.cmake(
name='esp-idf',
cmake_vars=lib_vars,
- cmake_src='libraries/AP_HAL_ESP32/targets/esp-idf',
+ cmake_src='libraries/AP_HAL_ESP32/targets/'+target+'/esp-idf',
cmake_bld='esp-idf_build',
)
diff --git a/Tools/ardupilotwaf/mavgen.py b/Tools/ardupilotwaf/mavgen.py
index 0dec86207594d4..5af076ac3f4b48 100644
--- a/Tools/ardupilotwaf/mavgen.py
+++ b/Tools/ardupilotwaf/mavgen.py
@@ -94,8 +94,5 @@ def configure(cfg):
"""
setup environment for mavlink header generator
"""
- cfg.load('python')
- cfg.check_python_version(minver=(2,7,0))
-
env = cfg.env
env.MAVLINK_DIR = cfg.srcnode.make_node('modules/mavlink/').abspath()
diff --git a/Tools/autotest/ArduPlane_Tests/GUIDEDToAUTO/mission.txt b/Tools/autotest/ArduPlane_Tests/GUIDEDToAUTO/mission.txt
new file mode 100644
index 00000000000000..12bb5ed5f65e6b
--- /dev/null
+++ b/Tools/autotest/ArduPlane_Tests/GUIDEDToAUTO/mission.txt
@@ -0,0 +1,36 @@
+QGC WPL 110
+0 0 0 16 0.000000 0.000000 0.000000 0.000000 -27.272924 151.290848 10.000000 1
+1 0 10 84 0.000000 0.000000 0.000000 0.000000 -27.272924 151.290848 10.000000 1
+2 0 10 16 0.000000 0.000000 0.000000 0.000000 -27.272705 151.298172 100.000000 1
+3 0 10 16 0.000000 0.000000 0.000000 0.000000 -27.277561 151.337250 100.000000 1
+4 0 10 16 0.000000 0.000000 0.000000 0.000000 -27.281748 151.335953 100.000000 1
+5 0 10 16 0.000000 0.000000 0.000000 0.000000 -27.275724 151.289932 100.000000 1
+6 0 10 16 0.000000 0.000000 0.000000 0.000000 -27.297457 151.285629 100.000000 1
+7 0 10 16 0.000000 0.000000 0.000000 0.000000 -27.308109 151.354279 100.000000 1
+8 0 10 16 0.000000 0.000000 0.000000 0.000000 -27.330292 151.374268 90.000000 1
+9 0 10 16 0.000000 0.000000 0.000000 0.000000 -27.330435 151.375977 70.000000 1
+10 0 10 16 0.000000 0.000000 0.000000 0.000000 -27.332638 151.376099 70.000000 1
+11 0 10 16 0.000000 0.000000 0.000000 0.000000 -27.334694 151.376144 70.000000 1
+12 0 10 16 0.000000 0.000000 0.000000 0.000000 -27.333776 151.374146 70.000000 1
+13 0 10 16 0.000000 0.000000 0.000000 0.000000 -27.331438 151.378159 70.000000 1
+14 0 0 177 9.000000 4.000000 0.000000 0.000000 0.000000 0.000000 0.000000 1
+15 0 10 16 0.000000 0.000000 0.000000 0.000000 -27.334566 151.375366 40.000000 1
+16 0 0 178 0.000000 20.000000 0.000000 0.000000 0.000000 0.000000 0.000000 1
+17 0 10 16 0.000000 0.000000 0.000000 0.000000 -27.334840 151.377234 40.000000 1
+18 0 10 16 0.000000 0.000000 0.000000 0.000000 -27.333933 151.376849 35.000000 1
+19 0 10 85 0.000000 0.000000 0.000000 0.000000 -27.332676 151.376511 0.000000 1
+20 0 10 84 0.000000 0.000000 0.000000 0.000000 -27.332659 151.376511 35.000000 1
+21 0 0 178 0.000000 24.000000 0.000000 0.000000 0.000000 0.000000 0.000000 1
+22 0 10 16 0.000000 0.000000 0.000000 0.000000 -27.332201 151.376511 100.000000 1
+23 0 10 16 0.000000 0.000000 0.000000 0.000000 -27.330381 151.374191 100.000000 1
+24 0 10 16 0.000000 0.000000 0.000000 0.000000 -27.308224 151.354538 100.000000 1
+25 0 10 16 0.000000 0.000000 0.000000 0.000000 -27.297340 151.285385 100.000000 1
+26 0 10 16 0.000000 0.000000 0.000000 0.000000 -27.275724 151.289932 100.000000 1
+27 0 10 16 0.000000 0.000000 0.000000 0.000000 -27.281631 151.335953 100.000000 1
+28 0 10 16 0.000000 0.000000 0.000000 0.000000 -27.277679 151.337128 100.000000 1
+29 0 10 16 0.000000 0.000000 0.000000 0.000000 -27.272587 151.298294 100.000000 1
+30 0 10 16 0.000000 0.000000 0.000000 0.000000 -27.271564 151.291473 30.000000 1
+31 0 0 178 0.000000 20.000000 0.000000 0.000000 0.000000 0.000000 0.000000 1
+32 0 10 16 0.000000 0.000000 0.000000 0.000000 -27.271054 151.290211 25.000000 1
+33 0 10 16 0.000000 0.000000 0.000000 0.000000 -27.273310 151.290222 15.000000 1
+34 0 10 85 0.000000 0.000000 0.000000 0.000000 -27.274887 151.289918 0.000000 1
diff --git a/Tools/autotest/ArduPlane_Tests/LordEAHRS/ap1.txt b/Tools/autotest/ArduPlane_Tests/MicroStrainEAHRS/ap1.txt
similarity index 100%
rename from Tools/autotest/ArduPlane_Tests/LordEAHRS/ap1.txt
rename to Tools/autotest/ArduPlane_Tests/MicroStrainEAHRS/ap1.txt
diff --git a/Tools/autotest/antennatracker.py b/Tools/autotest/antennatracker.py
index ba452956aafd92..cea2a37fa09ba5 100644
--- a/Tools/autotest/antennatracker.py
+++ b/Tools/autotest/antennatracker.py
@@ -122,27 +122,21 @@ def SERVOTEST(self):
# magically changes to SERVOTEST (3)
for value in 1900, 1200:
channel = 1
- self.run_cmd(mavutil.mavlink.MAV_CMD_DO_SET_SERVO,
- channel,
- value,
- 0,
- 0,
- 0,
- 0,
- 0,
- timeout=1)
+ self.run_cmd(
+ mavutil.mavlink.MAV_CMD_DO_SET_SERVO,
+ p1=channel,
+ p2=value,
+ timeout=1,
+ )
self.wait_servo_channel_value(channel, value)
for value in 1300, 1670:
channel = 2
- self.run_cmd(mavutil.mavlink.MAV_CMD_DO_SET_SERVO,
- channel,
- value,
- 0,
- 0,
- 0,
- 0,
- 0,
- timeout=1)
+ self.run_cmd(
+ mavutil.mavlink.MAV_CMD_DO_SET_SERVO,
+ p1=channel,
+ p2=value,
+ timeout=1,
+ )
self.wait_servo_channel_value(channel, value)
def SCAN(self):
diff --git a/Tools/autotest/arducopter.py b/Tools/autotest/arducopter.py
index 3aafe1a4f3a77a..cff00c76d66756 100644
--- a/Tools/autotest/arducopter.py
+++ b/Tools/autotest/arducopter.py
@@ -11,7 +11,6 @@
import shutil
import time
import numpy
-import operator
from pymavlink import quaternion
from pymavlink import mavutil
@@ -124,19 +123,6 @@ def get_disarm_delay(self):
def set_autodisarm_delay(self, delay):
self.set_parameter("DISARM_DELAY", delay)
- def user_takeoff(self, alt_min=30, timeout=30, max_err=5):
- '''takeoff using mavlink takeoff command'''
- self.run_cmd(mavutil.mavlink.MAV_CMD_NAV_TAKEOFF,
- 0, # param1
- 0, # param2
- 0, # param3
- 0, # param4
- 0, # param5
- 0, # param6
- alt_min # param7
- )
- self.wait_for_alt(alt_min, timeout=timeout, max_err=max_err)
-
def takeoff(self,
alt_min=30,
takeoff_throttle=1700,
@@ -155,17 +141,10 @@ def takeoff(self,
self.user_takeoff(alt_min=alt_min, timeout=timeout, max_err=max_err)
else:
self.set_rc(3, takeoff_throttle)
- self.wait_for_alt(alt_min=alt_min, timeout=timeout, max_err=max_err)
+ self.wait_altitude(alt_min-1, alt_min+max_err, relative=True, timeout=timeout)
self.hover()
self.progress("TAKEOFF COMPLETE")
- def wait_for_alt(self, alt_min=30, timeout=30, max_err=5):
- """Wait for minimum altitude to be reached."""
- self.wait_altitude(alt_min - 1,
- (alt_min + max_err),
- relative=True,
- timeout=timeout)
-
def land_and_disarm(self, timeout=60):
"""Land the quad."""
self.progress("STARTING LANDING")
@@ -177,7 +156,7 @@ def wait_landed_and_disarmed(self, min_alt=6, timeout=60):
m = self.mav.recv_match(type='GLOBAL_POSITION_INT', blocking=True)
alt = m.relative_alt / 1000.0 # mm -> m
if alt > min_alt:
- self.wait_for_alt(min_alt, timeout=timeout)
+ self.wait_altitude(min_alt-1, min_alt+5, relative=True, timeout=timeout)
# self.wait_statustext("SIM Hit ground", timeout=timeout)
self.wait_disarmed()
@@ -709,6 +688,47 @@ def ThrottleFailsafe(self, side=60, timeout=360):
self.set_parameter('FS_THR_ENABLE', 0)
self.reboot_sitl()
+ def ThrottleFailsafePassthrough(self):
+ '''check servo passthrough on RC failsafe. Make sure it doesn't glitch to the bad RC input value'''
+ channel = 7
+ trim_value = 1450
+ self.set_parameters({
+ 'RC%u_MIN' % channel: 1000,
+ 'RC%u_MAX' % channel: 2000,
+ 'SERVO%u_MIN' % channel: 1000,
+ 'SERVO%u_MAX' % channel: 2000,
+ 'SERVO%u_TRIM' % channel: trim_value,
+ 'SERVO%u_FUNCTION' % channel: 146, # scaled passthrough for channel 7
+ 'FS_THR_ENABLE': 1,
+ 'RC_FS_TIMEOUT': 10,
+ 'SERVO_RC_FS_MSK': 1 << (channel-1),
+ })
+
+ self.reboot_sitl()
+
+ self.context_set_message_rate_hz('SERVO_OUTPUT_RAW', 200)
+
+ self.set_rc(channel, 1799)
+ expected_servo_output_value = 1778 # 1778 because of weird trim
+ self.wait_servo_channel_value(channel, expected_servo_output_value)
+ # receiver goes into failsafe with wild override values:
+
+ def ensure_SERVO_values_never_input(mav, m):
+ if m.get_type() != "SERVO_OUTPUT_RAW":
+ return
+ value = getattr(m, "servo%u_raw" % channel)
+ if value != expected_servo_output_value and value != trim_value:
+ raise NotAchievedException("Bad servo value %u received" % value)
+
+ self.install_message_hook_context(ensure_SERVO_values_never_input)
+ self.progress("Forcing receiver into failsafe")
+ self.set_rc_from_map({
+ 3: 800,
+ channel: 1300,
+ })
+ self.wait_servo_channel_value(channel, trim_value)
+ self.delay_sim_time(10)
+
# Tests all actions and logic behind the GCS failsafe
def GCSFailsafe(self, side=60, timeout=360):
'''Test GCS Failsafe'''
@@ -1120,7 +1140,7 @@ def VibrationFailsafe(self):
self.change_mode("LAND")
# check vehicle descends to 2m or less within 40 seconds
- self.wait_altitude(-5, 2, timeout=40, relative=True)
+ self.wait_altitude(-5, 2, timeout=50, relative=True)
# force disarm of vehicle (it will likely not automatically disarm)
self.disarm_vehicle(force=True)
@@ -1139,11 +1159,14 @@ def test_takeoff_check_mode(self, mode, user_takeoff=False):
self.context_collect('STATUSTEXT')
self.arm_vehicle()
if user_takeoff:
- self.run_cmd(mavutil.mavlink.MAV_CMD_NAV_TAKEOFF, 0, 0, 0, 0, 0, 0, 10)
+ self.run_cmd(
+ mavutil.mavlink.MAV_CMD_NAV_TAKEOFF,
+ p7=10,
+ )
else:
self.set_rc(3, 1700)
# we may never see ourselves as armed in a heartbeat
- self.wait_statustext("Takeoff blocked: ESC RPM too low", check_context=True)
+ self.wait_statustext("Takeoff blocked: ESC RPM out of range", check_context=True)
self.context_pop()
self.zero_throttle()
self.disarm_vehicle()
@@ -1168,6 +1191,21 @@ def TakeoffCheck(self):
self.test_takeoff_check_mode("POSHOLD")
# self.test_takeoff_check_mode("SPORT")
+ self.set_parameters({
+ "AHRS_EKF_TYPE": 10,
+ 'SIM_ESC_TELEM': 1,
+ 'TKOFF_RPM_MIN': 1,
+ 'TKOFF_RPM_MAX': 3,
+ })
+ self.test_takeoff_check_mode("STABILIZE")
+ self.test_takeoff_check_mode("ACRO")
+ self.test_takeoff_check_mode("LOITER")
+ self.test_takeoff_check_mode("ALT_HOLD")
+ # self.test_takeoff_check_mode("FLOWHOLD")
+ self.test_takeoff_check_mode("GUIDED", True)
+ self.test_takeoff_check_mode("POSHOLD")
+ # self.test_takeoff_check_mode("SPORT")
+
def assert_dataflash_message_field_level_at(self,
mtype,
field,
@@ -2088,7 +2126,7 @@ def ModeFlip(self):
self.progress("Regaining altitude")
self.change_mode('ALT_HOLD')
- self.wait_for_alt(20, max_err=40)
+ self.wait_altitude(19, 60, relative=True)
self.progress("Flipping in pitch")
self.set_rc(2, 1700)
@@ -2428,7 +2466,7 @@ def AutoTuneSwitch(self):
raise NotAchievedException("AUTOTUNE gains not present in pilot testing")
# land without changing mode
self.set_rc(3, 1000)
- self.wait_for_alt(0)
+ self.wait_altitude(-1, 5, relative=True)
self.wait_disarmed()
# Check gains are still there after disarm
if (rlld == self.get_parameter("ATC_RAT_RLL_D") or
@@ -2582,7 +2620,23 @@ def CANGPSCopterMission(self):
"CAN_P1_DRIVER": 1,
"GPS_TYPE": 9,
"GPS_TYPE2": 9,
- "SIM_GPS2_DISABLE": 0,
+ # disable simulated GPS, so only via DroneCAN
+ "SIM_GPS_DISABLE": 1,
+ "SIM_GPS2_DISABLE": 1,
+ # this ensures we use DroneCAN baro and compass
+ "SIM_BARO_COUNT" : 0,
+ "SIM_MAG1_DEVID" : 0,
+ "SIM_MAG2_DEVID" : 0,
+ "SIM_MAG3_DEVID" : 0,
+ "COMPASS_USE2" : 0,
+ "COMPASS_USE3" : 0,
+ # use DroneCAN rangefinder
+ "RNGFND1_TYPE" : 24,
+ "RNGFND1_MAX_CM" : 11000,
+ # use DroneCAN battery monitoring, and enforce with a arming voltage
+ "BATT_MONITOR" : 8,
+ "BATT_ARM_VOLT" : 12.0,
+ "SIM_SPEEDUP": 2,
})
self.context_push()
@@ -2650,16 +2704,12 @@ def CANGPSCopterMission(self):
raise NotAchievedException("Failed ordering for requested CASE:", case)
if len(case[4]):
self.context_collect('STATUSTEXT')
- self.run_cmd(mavutil.mavlink.MAV_CMD_COMPONENT_ARM_DISARM,
- 1, # ARM
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- timeout=10,
- want_result=mavutil.mavlink.MAV_RESULT_FAILED)
+ self.run_cmd(
+ mavutil.mavlink.MAV_CMD_COMPONENT_ARM_DISARM,
+ p1=1, # ARM
+ timeout=10,
+ want_result=mavutil.mavlink.MAV_RESULT_FAILED,
+ )
self.wait_statustext(case[4], check_context=True)
self.context_stop_collecting('STATUSTEXT')
self.progress("############################### All GPS Order Cases Tests Passed")
@@ -2667,23 +2717,34 @@ def CANGPSCopterMission(self):
self.set_parameter("ARMING_CHECK", 1)
self.stop_sup_program(instance=0)
self.start_sup_program(instance=0, args="-M")
+ self.stop_sup_program(instance=1)
+ self.start_sup_program(instance=1, args="-M")
self.delay_sim_time(2)
self.context_collect('STATUSTEXT')
- self.run_cmd(mavutil.mavlink.MAV_CMD_COMPONENT_ARM_DISARM,
- 1, # ARM
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- timeout=10,
- want_result=mavutil.mavlink.MAV_RESULT_FAILED)
- self.wait_statustext("Node {} unhealthy".format(gps1_nodeid), check_context=True)
+ self.run_cmd(
+ mavutil.mavlink.MAV_CMD_COMPONENT_ARM_DISARM,
+ p1=1, # ARM
+ timeout=10,
+ want_result=mavutil.mavlink.MAV_RESULT_FAILED,
+ )
+ self.wait_statustext(".*Node .* unhealthy", check_context=True, regex=True)
self.stop_sup_program(instance=0)
self.start_sup_program(instance=0)
+ self.stop_sup_program(instance=1)
+ self.start_sup_program(instance=1)
self.context_stop_collecting('STATUSTEXT')
self.context_pop()
+
+ self.set_parameters({
+ # use DroneCAN ESCs for flight
+ "CAN_D1_UC_ESC_BM" : 0x0f,
+ # this stops us using local servo output, guaranteeing we are
+ # flying on DroneCAN ESCs
+ "SIM_CAN_SRV_MSK" : 0xFF,
+ # we can do the flight faster
+ "SIM_SPEEDUP" : 5,
+ })
+
self.CopterMission()
def TakeoffAlt(self):
@@ -3629,14 +3690,10 @@ def Parachute(self):
self.progress("Test triggering with mavlink message")
self.takeoff(20)
- self.run_cmd(mavutil.mavlink.MAV_CMD_DO_PARACHUTE,
- 2, # release
- 0,
- 0,
- 0,
- 0,
- 0,
- 0)
+ self.run_cmd(
+ mavutil.mavlink.MAV_CMD_DO_PARACHUTE,
+ p1=2, # release
+ )
self.wait_statustext('BANG', timeout=60)
self.disarm_vehicle(force=True)
self.reboot_sitl()
@@ -3654,15 +3711,10 @@ def Parachute(self):
self.progress("Test mavlink triggering")
self.takeoff(20)
- self.run_cmd(mavutil.mavlink.MAV_CMD_DO_PARACHUTE,
- mavutil.mavlink.PARACHUTE_DISABLE, # param1
- 0, # param2
- 0, # param3
- 0, # param4
- 0, # param5
- 0, # param6
- 0 # param7
- )
+ self.run_cmd(
+ mavutil.mavlink.MAV_CMD_DO_PARACHUTE,
+ p1=mavutil.mavlink.PARACHUTE_DISABLE,
+ )
ok = False
try:
self.wait_statustext('BANG', timeout=2)
@@ -3670,15 +3722,10 @@ def Parachute(self):
ok = True
if not ok:
raise NotAchievedException("Disabled parachute fired")
- self.run_cmd(mavutil.mavlink.MAV_CMD_DO_PARACHUTE,
- mavutil.mavlink.PARACHUTE_ENABLE, # param1
- 0, # param2
- 0, # param3
- 0, # param4
- 0, # param5
- 0, # param6
- 0 # param7
- )
+ self.run_cmd(
+ mavutil.mavlink.MAV_CMD_DO_PARACHUTE,
+ p1=mavutil.mavlink.PARACHUTE_ENABLE,
+ )
ok = False
try:
self.wait_statustext('BANG', timeout=2)
@@ -3693,15 +3740,10 @@ def Parachute(self):
# parachute should not fire if you go from disabled to release:
self.takeoff(20)
- self.run_cmd(mavutil.mavlink.MAV_CMD_DO_PARACHUTE,
- mavutil.mavlink.PARACHUTE_RELEASE,
- 0, # param2
- 0, # param3
- 0, # param4
- 0, # param5
- 0, # param6
- 0 # param7
- )
+ self.run_cmd(
+ mavutil.mavlink.MAV_CMD_DO_PARACHUTE,
+ p1=mavutil.mavlink.PARACHUTE_RELEASE,
+ )
ok = False
try:
self.wait_statustext('BANG', timeout=2)
@@ -3711,24 +3753,14 @@ def Parachute(self):
raise NotAchievedException("Parachute fired when going straight from disabled to release")
# now enable then release parachute:
- self.run_cmd(mavutil.mavlink.MAV_CMD_DO_PARACHUTE,
- mavutil.mavlink.PARACHUTE_ENABLE, # param1
- 0, # param2
- 0, # param3
- 0, # param4
- 0, # param5
- 0, # param6
- 0 # param7
- )
- self.run_cmd(mavutil.mavlink.MAV_CMD_DO_PARACHUTE,
- mavutil.mavlink.PARACHUTE_RELEASE,
- 0, # param2
- 0, # param3
- 0, # param4
- 0, # param5
- 0, # param6
- 0 # param7
- )
+ self.run_cmd(
+ mavutil.mavlink.MAV_CMD_DO_PARACHUTE,
+ p1=mavutil.mavlink.PARACHUTE_ENABLE,
+ )
+ self.run_cmd(
+ mavutil.mavlink.MAV_CMD_DO_PARACHUTE,
+ p1=mavutil.mavlink.PARACHUTE_RELEASE,
+ )
self.wait_statustext('BANG! Parachute deployed', timeout=2)
self.disarm_vehicle(force=True)
self.reboot_sitl()
@@ -3775,15 +3807,16 @@ def MotorTest(self, timeout=60):
# default frame is "+" - start motor of 2 is "B", which is
# motor 1... see
# https://ardupilot.org/copter/docs/connect-escs-and-motors.html
- self.run_cmd(mavutil.mavlink.MAV_CMD_DO_MOTOR_TEST,
- 2, # start motor
- mavutil.mavlink.MOTOR_TEST_THROTTLE_PWM,
- pwm_in, # pwm-to-output
- 2, # timeout in seconds
- 2, # number of motors to output
- 0, # compass learning
- 0,
- timeout=timeout)
+ self.run_cmd(
+ mavutil.mavlink.MAV_CMD_DO_MOTOR_TEST,
+ p1=2, # start motor
+ p2=mavutil.mavlink.MOTOR_TEST_THROTTLE_PWM,
+ p3=pwm_in, # pwm-to-output
+ p4=2, # timeout in seconds
+ p5=2, # number of motors to output
+ p6=0, # compass learning
+ timeout=timeout,
+ )
# long timeouts here because there's a pause before we start motors
self.wait_servo_channel_value(1, pwm_in, timeout=10)
self.wait_servo_channel_value(4, pwm_in, timeout=10)
@@ -3796,15 +3829,16 @@ def MotorTest(self, timeout=60):
# min/max are used.
expected_pwm = 1000 + (self.get_parameter("RC3_MAX") - self.get_parameter("RC3_MIN")) * percentage/100.0
self.progress("expected pwm=%f" % expected_pwm)
- self.run_cmd(mavutil.mavlink.MAV_CMD_DO_MOTOR_TEST,
- 2, # start motor
- mavutil.mavlink.MOTOR_TEST_THROTTLE_PERCENT,
- percentage, # pwm-to-output
- 2, # timeout in seconds
- 2, # number of motors to output
- 0, # compass learning
- 0,
- timeout=timeout)
+ self.run_cmd(
+ mavutil.mavlink.MAV_CMD_DO_MOTOR_TEST,
+ p1=2, # start motor
+ p2=mavutil.mavlink.MOTOR_TEST_THROTTLE_PERCENT,
+ p3=percentage, # pwm-to-output
+ p4=2, # timeout in seconds
+ p5=2, # number of motors to output
+ p6=0, # compass learning
+ timeout=timeout,
+ )
self.wait_servo_channel_value(1, expected_pwm, timeout=10)
self.wait_servo_channel_value(4, expected_pwm, timeout=10)
self.wait_statustext("finished motor test")
@@ -3852,7 +3886,7 @@ def PrecisionLanding(self):
new_pos = self.mav.location()
delta = self.get_distance(target, new_pos)
self.progress("Landed %f metres from target position" % delta)
- max_delta = 1
+ max_delta = 1.5
if delta > max_delta:
raise NotAchievedException("Did not land close enough to target position (%fm > %fm" % (delta, max_delta))
@@ -4569,7 +4603,7 @@ def precision_loiter_to_pos(self, x, y, z, timeout=40):
# determine if we've successfully navigated to close to
# where we should be:
dist = math.sqrt(delta_ef.x * delta_ef.x + delta_ef.y * delta_ef.y)
- dist_max = 0.15
+ dist_max = 1
self.progress("dist=%f want <%f" % (dist, dist_max))
if dist < dist_max:
# success! We've gotten within our target distance
@@ -4647,6 +4681,7 @@ def PayLoadPlaceMission(self):
except Exception as e:
self.print_exception_caught(e)
+ self.disarm_vehicle(force=True)
ex = e
self.context_pop()
@@ -4814,15 +4849,10 @@ def ManualThrottleModeChange(self):
self.progress("Check setting an invalid mode")
self.run_cmd(
mavutil.mavlink.MAV_CMD_DO_SET_MODE,
- mavutil.mavlink.MAV_MODE_FLAG_CUSTOM_MODE_ENABLED,
- 126,
- 0,
- 0,
- 0,
- 0,
- 0,
+ p1=mavutil.mavlink.MAV_MODE_FLAG_CUSTOM_MODE_ENABLED,
+ p2=126,
want_result=mavutil.mavlink.MAV_RESULT_FAILED,
- timeout=1
+ timeout=1,
)
self.set_rc(3, 1000)
self.run_cmd_do_set_mode("ACRO")
@@ -4871,14 +4901,12 @@ def do_yaw_rate(self, yaw_rate):
'''yaw aircraft in guided/rate mode'''
self.run_cmd(
mavutil.mavlink.MAV_CMD_CONDITION_YAW,
- 60, # target angle
- 0, # degrees/second
- 1, # -1 is counter-clockwise, 1 clockwise
- 1, # 1 for relative, 0 for absolute
- 0, # p5
- 0, # p6
- 0, # p7
- quiet=True)
+ p1=60, # target angle
+ p2=0, # degrees/second
+ p3=1, # -1 is counter-clockwise, 1 clockwise
+ p4=1, # 1 for relative, 0 for absolute
+ quiet=True,
+ )
def setup_servo_mount(self, roll_servo=5, pitch_servo=6, yaw_servo=7):
'''configure a rpy servo mount; caller responsible for required rebooting'''
@@ -4905,11 +4933,12 @@ def get_mount_roll_pitch_yaw_deg(self):
def set_mount_mode(self, mount_mode):
'''set mount mode'''
- self.run_cmd(mavutil.mavlink.MAV_CMD_DO_MOUNT_CONFIGURE,
- mount_mode,
- 0, # stabilize roll (unsupported)
- 0, # stabilize pitch (unsupported)
- 0, 0, 0, 0)
+ self.run_cmd(
+ mavutil.mavlink.MAV_CMD_DO_MOUNT_CONFIGURE,
+ p1=mount_mode,
+ p2=0, # stabilize roll (unsupported)
+ p3=0, # stabilize pitch (unsupported)
+ )
def Mount(self):
'''Test Camera/Antenna Mount'''
@@ -4975,14 +5004,16 @@ def Mount(self):
self.do_pitch(0) # level vehicle
self.wait_pitch(0, despitch_tolerance)
self.set_mount_mode(mavutil.mavlink.MAV_MOUNT_MODE_MAVLINK_TARGETING)
- self.run_cmd(mavutil.mavlink.MAV_CMD_DO_GIMBAL_MANAGER_PITCHYAW,
- -20, # pitch angle in degrees
- 0, # yaw angle in degrees
- 0, # pitch rate in degrees (NaN to ignore)
- 0, # yaw rate in degrees (NaN to ignore)
- 0, # flags (0=Body-frame, 16/GIMBAL_MANAGER_FLAGS_YAW_LOCK=Earth Frame)
- 0, # unused
- 0) # gimbal id
+ self.run_cmd(
+ mavutil.mavlink.MAV_CMD_DO_GIMBAL_MANAGER_PITCHYAW,
+ p1=-20, # pitch angle in degrees
+ p2=0, # yaw angle in degrees
+ p3=0, # pitch rate in degrees (NaN to ignore)
+ p4=0, # yaw rate in degrees (NaN to ignore)
+ p5=0, # flags (0=Body-frame, 16/GIMBAL_MANAGER_FLAGS_YAW_LOCK=Earth Frame)
+ p6=0, # unused
+ p7=0, # gimbal id
+ )
self.test_mount_pitch(-20, 1, mavutil.mavlink.MAV_MOUNT_MODE_MAVLINK_TARGETING)
# point gimbal at specified location
@@ -5126,27 +5157,35 @@ def Mount(self):
20)
roi_alt = 0
self.progress("Using MAV_CMD_DO_SET_ROI_LOCATION")
- self.run_cmd(mavutil.mavlink.MAV_CMD_DO_SET_ROI_LOCATION,
- 0,
- 0,
- 0,
- 0,
- roi_lat,
- roi_lon,
- roi_alt,
- )
+ self.run_cmd(
+ mavutil.mavlink.MAV_CMD_DO_SET_ROI_LOCATION,
+ p5=roi_lat,
+ p6=roi_lon,
+ p7=roi_alt,
+ )
+ self.test_mount_pitch(-52, 5, mavutil.mavlink.MAV_MOUNT_MODE_GPS_POINT)
+ self.progress("Using MAV_CMD_DO_SET_ROI_LOCATION")
+ # start by pointing the gimbal elsewhere with a
+ # known-working command:
+ self.run_cmd(
+ mavutil.mavlink.MAV_CMD_DO_SET_ROI_LOCATION,
+ p5=roi_lat + 1,
+ p6=roi_lon + 1,
+ p7=roi_alt,
+ )
+ # now point it with command_int:
+ self.run_cmd_int(
+ mavutil.mavlink.MAV_CMD_DO_SET_ROI_LOCATION,
+ p5=int(roi_lat * 1e7),
+ p6=int(roi_lon * 1e7),
+ p7=roi_alt,
+ frame=mavutil.mavlink.MAV_FRAME_GLOBAL_RELATIVE_ALT,
+ )
self.test_mount_pitch(-52, 5, mavutil.mavlink.MAV_MOUNT_MODE_GPS_POINT)
self.progress("Using MAV_CMD_DO_SET_ROI_NONE")
- self.run_cmd(mavutil.mavlink.MAV_CMD_DO_SET_ROI_NONE,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- )
+ self.run_cmd(mavutil.mavlink.MAV_CMD_DO_SET_ROI_NONE)
+ self.run_cmd_int(mavutil.mavlink.MAV_CMD_DO_SET_ROI_NONE)
self.test_mount_pitch(0, 1, mavutil.mavlink.MAV_MOUNT_MODE_RC_TARGETING)
start = self.mav.location()
@@ -5156,15 +5195,12 @@ def Mount(self):
-200)
roi_alt = 0
self.progress("Using MAV_CMD_DO_SET_ROI")
- self.run_cmd(mavutil.mavlink.MAV_CMD_DO_SET_ROI,
- 0,
- 0,
- 0,
- 0,
- roi_lat,
- roi_lon,
- roi_alt,
- )
+ self.run_cmd(
+ mavutil.mavlink.MAV_CMD_DO_SET_ROI,
+ p5=roi_lat,
+ p6=roi_lon,
+ p7=roi_alt,
+ )
self.test_mount_pitch(-7.5, 1, mavutil.mavlink.MAV_MOUNT_MODE_GPS_POINT)
start = self.mav.location()
@@ -5214,15 +5250,10 @@ def Mount(self):
20)
roi_alt = 0
self.progress("Using MAV_CMD_DO_SET_ROI_SYSID")
- self.run_cmd(mavutil.mavlink.MAV_CMD_DO_SET_ROI_SYSID,
- self.mav.source_system,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- )
+ self.run_cmd(
+ mavutil.mavlink.MAV_CMD_DO_SET_ROI_SYSID,
+ p1=self.mav.source_system,
+ )
self.mav.mav.global_position_int_send(
0, # time boot ms
int(roi_lat * 1e7),
@@ -5236,6 +5267,11 @@ def Mount(self):
)
self.test_mount_pitch(-89, 5, mavutil.mavlink.MAV_MOUNT_MODE_SYSID_TARGET, hold=2)
+ self.run_cmd(mavutil.mavlink.MAV_CMD_DO_SET_ROI_NONE)
+ self.run_cmd_int(
+ mavutil.mavlink.MAV_CMD_DO_SET_ROI_SYSID,
+ p1=self.mav.source_system,
+ )
self.mav.mav.global_position_int_send(
0, # time boot ms
int(roi_lat * 1e7),
@@ -5294,15 +5330,12 @@ def MountYawVehicleForMountROI(self):
-100)
roi_alt = 0
self.progress("Using MAV_CMD_DO_SET_ROI")
- self.run_cmd(mavutil.mavlink.MAV_CMD_DO_SET_ROI,
- 0,
- 0,
- 0,
- 0,
- roi_lat,
- roi_lon,
- roi_alt,
- )
+ self.run_cmd(
+ mavutil.mavlink.MAV_CMD_DO_SET_ROI,
+ p5=roi_lat,
+ p6=roi_lon,
+ p7=roi_alt,
+ )
self.progress("Waiting for vehicle to point towards ROI")
self.wait_heading(225, timeout=600, minimum_duration=2)
@@ -5336,15 +5369,12 @@ def MountYawVehicleForMountROI(self):
bearing = self.bearing_to(there)
self.wait_heading(bearing, timeout=600, minimum_duration=2)
- self.run_cmd(mavutil.mavlink.MAV_CMD_DO_SET_ROI,
- 0,
- 0,
- 0,
- 0,
- roi_lat,
- roi_lon,
- roi_alt,
- )
+ self.run_cmd(
+ mavutil.mavlink.MAV_CMD_DO_SET_ROI,
+ p5=roi_lat,
+ p6=roi_lon,
+ p7=roi_alt,
+ )
self.progress("Wait for vehicle to point sssse due to moving")
self.wait_heading(170, timeout=600, minimum_duration=1)
@@ -6753,8 +6783,8 @@ def OBSTACLE_DISTANCE_3D(self):
self.context_pop()
self.reboot_sitl()
- def fly_proximity_avoidance_test_corners(self):
- self.start_subtest("Corners")
+ def AC_Avoidance_Proximity(self):
+ '''Test proximity avoidance slide behaviour'''
self.context_push()
ex = None
try:
@@ -6793,14 +6823,14 @@ def ProximitySensors(self):
})
sensors = [ # tuples of name, prx_type
('sf45b', 8, {
- mavutil.mavlink.MAV_SENSOR_ROTATION_NONE: 285,
- mavutil.mavlink.MAV_SENSOR_ROTATION_YAW_45: 256,
- mavutil.mavlink.MAV_SENSOR_ROTATION_YAW_90: 1131,
- mavutil.mavlink.MAV_SENSOR_ROTATION_YAW_135: 1283,
- mavutil.mavlink.MAV_SENSOR_ROTATION_YAW_180: 625,
- mavutil.mavlink.MAV_SENSOR_ROTATION_YAW_225: 968,
- mavutil.mavlink.MAV_SENSOR_ROTATION_YAW_270: 760,
- mavutil.mavlink.MAV_SENSOR_ROTATION_YAW_315: 762,
+ mavutil.mavlink.MAV_SENSOR_ROTATION_NONE: 270,
+ mavutil.mavlink.MAV_SENSOR_ROTATION_YAW_45: 258,
+ mavutil.mavlink.MAV_SENSOR_ROTATION_YAW_90: 1146,
+ mavutil.mavlink.MAV_SENSOR_ROTATION_YAW_135: 632,
+ mavutil.mavlink.MAV_SENSOR_ROTATION_YAW_180: 629,
+ mavutil.mavlink.MAV_SENSOR_ROTATION_YAW_225: 972,
+ mavutil.mavlink.MAV_SENSOR_ROTATION_YAW_270: 774,
+ mavutil.mavlink.MAV_SENSOR_ROTATION_YAW_315: 774,
}),
('rplidara2', 5, {
mavutil.mavlink.MAV_SENSOR_ROTATION_NONE: 277,
@@ -6860,8 +6890,8 @@ def ProximitySensors(self):
"Distance too great (%s) (want=%s != got=%s)" %
(name, wants, gots))
- def fly_proximity_avoidance_test_alt_no_avoid(self):
- self.start_subtest("Alt-no-avoid")
+ def AC_Avoidance_Proximity_AVOID_ALT_MIN(self):
+ '''Test proximity avoidance with AVOID_ALT_MIN'''
self.context_push()
ex = None
try:
@@ -6871,9 +6901,11 @@ def fly_proximity_avoidance_test_alt_no_avoid(self):
})
self.set_analog_rangefinder_parameters()
self.reboot_sitl()
- tstart = self.get_sim_time()
+
self.change_mode('LOITER')
self.wait_ekf_happy()
+
+ tstart = self.get_sim_time()
while True:
if self.armed():
break
@@ -6889,14 +6921,8 @@ def fly_proximity_avoidance_test_alt_no_avoid(self):
mavutil.mavlink.MAV_SENSOR_ROTATION_NONE, # orientation
255 # covariance
)
- self.send_cmd(mavutil.mavlink.MAV_CMD_COMPONENT_ARM_DISARM,
- 1, # ARM
- 0,
- 0,
- 0,
- 0,
- 0,
- 0)
+ self.send_mavlink_arm_command()
+
self.takeoff(15, mode='LOITER')
self.progress("Poking vehicle; should avoid")
@@ -6924,7 +6950,7 @@ def shove(a, b):
if self.get_sim_time_cached() - tstart > 10:
break
vel = self.get_body_frame_velocity()
- if vel.length() > 0.3:
+ if vel.length() > 0.5:
raise NotAchievedException("Moved too much (%s)" %
(str(vel),))
shove(None, None)
@@ -6939,27 +6965,11 @@ def shove(a, b):
if ex is not None:
raise ex
- def AC_Avoidance_Proximity(self):
- '''Test proximity avoidance slide behaviour'''
- self.fly_proximity_avoidance_test_alt_no_avoid()
- self.fly_proximity_avoidance_test_corners()
-
def AC_Avoidance_Fence(self):
'''Test fence avoidance slide behaviour'''
- self.context_push()
- ex = None
- try:
- self.load_fence("copter-avoidance-fence.txt")
- self.set_parameter("FENCE_ENABLE", 1)
- self.check_avoidance_corners()
- except Exception as e:
- self.print_exception_caught(e)
- ex = e
- self.context_pop()
- self.clear_fence()
- self.disarm_vehicle(force=True)
- if ex is not None:
- raise ex
+ self.load_fence("copter-avoidance-fence.txt")
+ self.set_parameter("FENCE_ENABLE", 1)
+ self.check_avoidance_corners()
def global_position_int_for_location(self, loc, time_boot, heading=0):
return self.mav.mav.global_position_int_encode(
@@ -7673,13 +7683,7 @@ def fly_rangefinder_mavlink_distance_sensor(self):
self.run_cmd(
mavutil.mavlink.MAV_CMD_AIRFRAME_CONFIGURATION,
- 0,
- 0, # deploy
- 0,
- 0,
- 0,
- 0,
- 0
+ p2=0, # deploy
)
self.context_collect("STATUSTEXT")
@@ -7737,29 +7741,19 @@ def fly_rangefinder_mavlink_distance_sensor(self):
def GSF(self):
'''test the Gaussian Sum filter'''
- ex = None
self.context_push()
- try:
- self.set_parameter("EK2_ENABLE", 1)
- self.reboot_sitl()
- self.takeoff(20, mode='LOITER')
- self.set_rc(2, 1400)
- self.delay_sim_time(5)
- self.set_rc(2, 1500)
- self.progress("Path: %s" % self.current_onboard_log_filepath())
- dfreader = self.dfreader_for_current_onboard_log()
- self.do_RTL()
- except Exception as e:
- self.progress("Caught exception: %s" %
- self.get_exception_stacktrace(e))
- ex = e
-
+ self.set_parameter("EK2_ENABLE", 1)
+ self.reboot_sitl()
+ self.takeoff(20, mode='LOITER')
+ self.set_rc(2, 1400)
+ self.delay_sim_time(5)
+ self.set_rc(2, 1500)
+ self.progress("Path: %s" % self.current_onboard_log_filepath())
+ dfreader = self.dfreader_for_current_onboard_log()
+ self.do_RTL()
self.context_pop()
self.reboot_sitl()
- if ex is not None:
- raise ex
-
# ensure log messages present
want = set(["XKY0", "XKY1", "NKY0", "NKY1"])
still_want = want
@@ -7769,6 +7763,46 @@ def GSF(self):
raise NotAchievedException("Did not get %s" % want)
still_want.remove(m.get_type())
+ def GSF_reset(self):
+ '''test the Gaussian Sum filter based Emergency reset'''
+ self.context_push()
+ self.set_parameters({
+ "COMPASS_ORIENT": 4, # yaw 180
+ "COMPASS_USE2": 0, # disable backup compasses to avoid pre-arm failures
+ "COMPASS_USE3": 0,
+ })
+ self.reboot_sitl()
+ self.change_mode('GUIDED')
+ self.wait_ready_to_arm()
+
+ # record starting position
+ startpos = self.mav.recv_match(type='LOCAL_POSITION_NED', blocking=True)
+ self.progress("startpos=%s" % str(startpos))
+
+ # arm vehicle and takeoff to at least 5m
+ self.arm_vehicle()
+ expected_alt = 5
+ self.user_takeoff(alt_min=expected_alt)
+
+ # watch for emergency yaw reset
+ self.wait_text("EKF3 IMU. emergency yaw reset", timeout=5, regex=True)
+
+ # record how far vehicle flew off
+ endpos = self.mav.recv_match(type='LOCAL_POSITION_NED', blocking=True)
+ delta_x = endpos.x - startpos.x
+ delta_y = endpos.y - startpos.y
+ dist_m = math.sqrt(delta_x*delta_x + delta_y*delta_y)
+ self.progress("GSF yaw reset triggered at %f meters" % dist_m)
+
+ self.do_RTL()
+ self.context_pop()
+ self.reboot_sitl()
+
+ # ensure vehicle did not fly too far
+ dist_m_max = 8
+ if dist_m > dist_m_max:
+ raise NotAchievedException("GSF reset failed, vehicle flew too far (%f > %f)" % (dist_m, dist_m_max))
+
def fly_rangefinder_mavlink(self):
self.fly_rangefinder_mavlink_distance_sensor()
@@ -7917,6 +7951,7 @@ def RangeFinderDrivers(self):
("benewake_tf03", 27),
("gyus42v2", 31),
("teraranger_serial", 35),
+ ("nooploop_tofsense", 37),
]
while len(drivers):
do_drivers = drivers[0:3]
@@ -8321,7 +8356,9 @@ def FlyEachFrame(self):
'heli-compound': "wrong binary, different takeoff regime",
'heli-dual': "wrong binary, different takeoff regime",
'heli': "wrong binary, different takeoff regime",
+ 'heli-gas': "wrong binary, different takeoff regime",
'heli-blade360': "wrong binary, different takeoff regime",
+ "quad-can" : "needs CAN periph",
}
for frame in sorted(copter_vinfo_options["frames"].keys()):
self.start_subtest("Testing frame (%s)" % str(frame))
@@ -8723,13 +8760,10 @@ def MAV_CMD_CONDITION_YAW_absolute(self):
target = initial_heading
self.run_cmd(
mavutil.mavlink.MAV_CMD_CONDITION_YAW,
- target, # target angle
- 10, # degrees/second
- 1, # -1 is counter-clockwise, 1 clockwise
- 0, # 1 for relative, 0 for absolute
- 0, # p5
- 0, # p6
- 0, # p7
+ p1=target, # target angle
+ p2=10, # degrees/second
+ p3=1, # -1 is counter-clockwise, 1 clockwise
+ p4=0, # 1 for relative, 0 for absolute
)
self.wait_heading(target, minimum_duration=2, timeout=50)
@@ -8747,13 +8781,10 @@ def rate_watcher(mav, m):
part_way_target = initial_heading + 10
self.run_cmd(
mavutil.mavlink.MAV_CMD_CONDITION_YAW,
- target, # target angle
- degsecond, # degrees/second
- 1, # -1 is counter-clockwise, 1 clockwise
- 0, # 1 for relative, 0 for absolute
- 0, # p5
- 0, # p6
- 0, # p7
+ p1=target, # target angle
+ p2=degsecond, # degrees/second
+ p3=1, # -1 is counter-clockwise, 1 clockwise
+ p4=0, # 1 for relative, 0 for absolute
)
self.wait_heading(part_way_target)
self.wait_heading(target, minimum_duration=2)
@@ -8763,13 +8794,10 @@ def rate_watcher(mav, m):
part_way_target = initial_heading + 30
self.run_cmd(
mavutil.mavlink.MAV_CMD_CONDITION_YAW,
- target, # target angle
- degsecond, # degrees/second
- -1, # -1 is counter-clockwise, 1 clockwise
- 0, # 1 for relative, 0 for absolute
- 0, # p5
- 0, # p6
- 0, # p7
+ p1=target, # target angle
+ p2=degsecond, # degrees/second
+ p3=-1, # -1 is counter-clockwise, 1 clockwise
+ p4=0, # 1 for relative, 0 for absolute
)
self.wait_heading(part_way_target)
self.wait_heading(target, minimum_duration=2)
@@ -8824,10 +8852,10 @@ def RefindGPS(self):
'''Refind the GPS and attempt to RTL rather than continue to land'''
# https://github.com/ArduPilot/ardupilot/issues/14236
self.progress("arm the vehicle and takeoff in Guided")
- self.takeoff(20, mode='GUIDED')
+ self.takeoff(50, mode='GUIDED')
self.progress("fly 50m North (or whatever)")
old_pos = self.mav.recv_match(type='GLOBAL_POSITION_INT', blocking=True)
- self.fly_guided_move_global_relative_alt(50, 0, 20)
+ self.fly_guided_move_global_relative_alt(50, 0, 50)
self.set_parameter('GPS_TYPE', 0)
self.drain_mav()
tstart = self.get_sim_time()
@@ -9127,9 +9155,6 @@ def DO_CHANGE_SPEED(self):
def AUTO_LAND_TO_BRAKE(self):
'''ensure terrain altitude is taken into account when braking'''
- self.load_mission('mission.txt')
- home_loc = self.get_home_tuple_from_mission("mission.txt")
-
self.set_parameters({
"PLND_ACC_P_NSE": 2.500000,
"PLND_ALT_MAX": 8.000000,
@@ -9167,8 +9192,9 @@ def AUTO_LAND_TO_BRAKE(self):
self.set_analog_rangefinder_parameters()
+ self.load_mission('mission.txt')
self.customise_SITL_commandline([
- "--home", "%s,%s,%s,%s" % home_loc
+ "--home", self.sitl_home_string_from_mission("mission.txt"),
])
self.set_parameter('AUTO_OPTIONS', 3)
@@ -9481,111 +9507,105 @@ def IMUConsistency(self):
def Sprayer(self):
"""Test sprayer functionality."""
self.context_push()
- ex = None
- try:
- rc_ch = 9
- pump_ch = 5
- spinner_ch = 6
- pump_ch_min = 1050
- pump_ch_trim = 1520
- pump_ch_max = 1950
- spinner_ch_min = 975
- spinner_ch_trim = 1510
- spinner_ch_max = 1975
- self.set_parameters({
- "SPRAY_ENABLE": 1,
+ rc_ch = 9
+ pump_ch = 5
+ spinner_ch = 6
+ pump_ch_min = 1050
+ pump_ch_trim = 1520
+ pump_ch_max = 1950
+ spinner_ch_min = 975
+ spinner_ch_trim = 1510
+ spinner_ch_max = 1975
- "SERVO%u_FUNCTION" % pump_ch: 22,
- "SERVO%u_MIN" % pump_ch: pump_ch_min,
- "SERVO%u_TRIM" % pump_ch: pump_ch_trim,
- "SERVO%u_MAX" % pump_ch: pump_ch_max,
+ self.set_parameters({
+ "SPRAY_ENABLE": 1,
- "SERVO%u_FUNCTION" % spinner_ch: 23,
- "SERVO%u_MIN" % spinner_ch: spinner_ch_min,
- "SERVO%u_TRIM" % spinner_ch: spinner_ch_trim,
- "SERVO%u_MAX" % spinner_ch: spinner_ch_max,
+ "SERVO%u_FUNCTION" % pump_ch: 22,
+ "SERVO%u_MIN" % pump_ch: pump_ch_min,
+ "SERVO%u_TRIM" % pump_ch: pump_ch_trim,
+ "SERVO%u_MAX" % pump_ch: pump_ch_max,
- "SIM_SPR_ENABLE": 1,
- "SIM_SPR_PUMP": pump_ch,
- "SIM_SPR_SPIN": spinner_ch,
+ "SERVO%u_FUNCTION" % spinner_ch: 23,
+ "SERVO%u_MIN" % spinner_ch: spinner_ch_min,
+ "SERVO%u_TRIM" % spinner_ch: spinner_ch_trim,
+ "SERVO%u_MAX" % spinner_ch: spinner_ch_max,
- "RC%u_OPTION" % rc_ch: 15,
- "LOG_DISARMED": 1,
- })
+ "SIM_SPR_ENABLE": 1,
+ "SIM_SPR_PUMP": pump_ch,
+ "SIM_SPR_SPIN": spinner_ch,
- self.reboot_sitl()
+ "RC%u_OPTION" % rc_ch: 15,
+ "LOG_DISARMED": 1,
+ })
- self.wait_ready_to_arm()
- self.arm_vehicle()
+ self.reboot_sitl()
+
+ self.wait_ready_to_arm()
+ self.arm_vehicle()
+
+ self.progress("test bootup state - it's zero-output!")
+ self.wait_servo_channel_value(spinner_ch, 0)
+ self.wait_servo_channel_value(pump_ch, 0)
+
+ self.progress("Enable sprayer")
+ self.set_rc(rc_ch, 2000)
+
+ self.progress("Testing zero-speed state")
+ self.wait_servo_channel_value(spinner_ch, spinner_ch_min)
+ self.wait_servo_channel_value(pump_ch, pump_ch_min)
+
+ self.progress("Testing turning it off")
+ self.set_rc(rc_ch, 1000)
+ self.wait_servo_channel_value(spinner_ch, spinner_ch_min)
+ self.wait_servo_channel_value(pump_ch, pump_ch_min)
+
+ self.progress("Testing turning it back on")
+ self.set_rc(rc_ch, 2000)
+ self.wait_servo_channel_value(spinner_ch, spinner_ch_min)
+ self.wait_servo_channel_value(pump_ch, pump_ch_min)
+
+ self.takeoff(30, mode='LOITER')
+
+ self.progress("Testing speed-ramping")
+ self.set_rc(1, 1700) # start driving forward
+
+ # this is somewhat empirical...
+ self.wait_servo_channel_value(
+ pump_ch,
+ 1458,
+ timeout=60,
+ comparator=lambda x, y : abs(x-y) < 5
+ )
+
+ self.progress("Turning it off again")
+ self.set_rc(rc_ch, 1000)
+ self.wait_servo_channel_value(spinner_ch, spinner_ch_min)
+ self.wait_servo_channel_value(pump_ch, pump_ch_min)
+
+ self.start_subtest("Checking mavlink commands")
+ self.progress("Starting Sprayer")
+ self.run_cmd(mavutil.mavlink.MAV_CMD_DO_SPRAYER, p1=1)
+
+ self.progress("Testing speed-ramping")
+ self.wait_servo_channel_value(
+ pump_ch,
+ 1458,
+ timeout=60,
+ comparator=lambda x, y : abs(x-y) < 5
+ )
+
+ self.start_subtest("Stopping Sprayer")
+ self.run_cmd(mavutil.mavlink.MAV_CMD_DO_SPRAYER, p1=0)
+
+ self.wait_servo_channel_value(pump_ch, pump_ch_min)
- self.progress("test bootup state - it's zero-output!")
- self.wait_servo_channel_value(spinner_ch, 0)
- self.wait_servo_channel_value(pump_ch, 0)
-
- self.progress("Enable sprayer")
- self.set_rc(rc_ch, 2000)
-
- self.progress("Testing zero-speed state")
- self.wait_servo_channel_value(spinner_ch, spinner_ch_min)
- self.wait_servo_channel_value(pump_ch, pump_ch_min)
-
- self.progress("Testing turning it off")
- self.set_rc(rc_ch, 1000)
- self.wait_servo_channel_value(spinner_ch, spinner_ch_min)
- self.wait_servo_channel_value(pump_ch, pump_ch_min)
-
- self.progress("Testing turning it back on")
- self.set_rc(rc_ch, 2000)
- self.wait_servo_channel_value(spinner_ch, spinner_ch_min)
- self.wait_servo_channel_value(pump_ch, pump_ch_min)
-
- self.takeoff(30, mode='LOITER')
-
- self.progress("Testing speed-ramping")
- self.set_rc(1, 1700) # start driving forward
-
- # this is somewhat empirical...
- self.wait_servo_channel_value(pump_ch, 1458, timeout=60)
-
- self.progress("Turning it off again")
- self.set_rc(rc_ch, 1000)
- self.wait_servo_channel_value(spinner_ch, spinner_ch_min)
- self.wait_servo_channel_value(pump_ch, pump_ch_min)
-
- self.start_subtest("Checking mavlink commands")
- self.progress("Starting Sprayer")
- self.run_cmd(mavutil.mavlink.MAV_CMD_DO_SPRAYER,
- 1, # p1
- 0, # p2
- 0, # p3
- 0, # p4
- 0, # p5
- 0, # p6
- 0) # p7
-
- self.progress("Testing speed-ramping")
- self.wait_servo_channel_value(pump_ch, 1458, timeout=60, comparator=operator.gt)
- self.start_subtest("Stopping Sprayer")
- self.run_cmd(mavutil.mavlink.MAV_CMD_DO_SPRAYER,
- 0, # p1
- 0, # p2
- 0, # p3
- 0, # p4
- 0, # p5
- 0, # p6
- 0) # p7
- self.wait_servo_channel_value(pump_ch, pump_ch_min)
-
- self.progress("Sprayer OK")
- except Exception as e:
- self.print_exception_caught(e)
- ex = e
self.context_pop()
+
self.disarm_vehicle(force=True)
self.reboot_sitl()
- if ex:
- raise ex
+
+ self.progress("Sprayer OK")
def tests1a(self):
'''return list of all tests'''
@@ -9618,6 +9638,7 @@ def tests1b(self):
self.BrakeMode,
self.RecordThenPlayMission,
self.ThrottleFailsafe,
+ self.ThrottleFailsafePassthrough,
self.GCSFailsafe,
self.CustomController,
])
@@ -9632,12 +9653,14 @@ def tests1c(self):
self.StabilityPatch,
self.OBSTACLE_DISTANCE_3D,
self.AC_Avoidance_Proximity,
+ self.AC_Avoidance_Proximity_AVOID_ALT_MIN,
self.AC_Avoidance_Fence,
self.AC_Avoidance_Beacon,
self.BaroWindCorrection,
self.SetpointGlobalPos,
self.ThrowDoubleDrop,
self.SetpointGlobalVel,
+ self.SetpointBadVel,
self.SplineTerrain,
self.TakeoffCheck,
])
@@ -9763,10 +9786,41 @@ def AHRSTrimLand(self):
self.reboot_sitl()
self.wait_ready_to_arm()
self.takeoff(alt_min=20, mode='LOITER')
- self.land_and_disarm()
+ self.do_RTL()
self.context_pop()
self.reboot_sitl()
+ def turn_safety_x(self, value):
+ self.mav.mav.set_mode_send(
+ self.mav.target_system,
+ mavutil.mavlink.MAV_MODE_FLAG_DECODE_POSITION_SAFETY,
+ value)
+
+ def turn_safety_off(self):
+ self.turn_safety_x(0)
+
+ def turn_safety_on(self):
+ self.turn_safety_x(1)
+
+ def SafetySwitch(self):
+ '''test safety switch behaviour'''
+ self.wait_ready_to_arm()
+
+ self.turn_safety_on()
+ self.assert_prearm_failure("safety switch")
+
+ self.turn_safety_off()
+ self.wait_ready_to_arm()
+
+ self.takeoff(2, mode='LOITER')
+ self.turn_safety_on()
+
+ self.wait_servo_channel_value(1, 0)
+ self.turn_safety_off()
+
+ self.change_mode('LAND')
+ self.wait_disarmed()
+
def GuidedYawRate(self):
'''ensuer guided yaw rate is not affected by rate of sewt-attitude messages'''
self.takeoff(30, mode='GUIDED')
@@ -9799,6 +9853,92 @@ def GuidedYawRate(self):
self.do_RTL()
+ def test_rplidar(self, sim_device_name, expected_distances):
+ '''plonks a Copter with a RPLidarA2 in the middle of a simulated field
+ of posts and checks that the measurements are what we expect.'''
+ self.set_parameters({
+ "SERIAL5_PROTOCOL": 11,
+ "PRX1_TYPE": 5,
+ })
+ self.customise_SITL_commandline([
+ "--uartF=sim:%s:" % sim_device_name,
+ "--home", "51.8752066,14.6487840,0,0", # SITL has "posts" here
+ ])
+
+ self.wait_ready_to_arm()
+
+ wanting_distances = copy.copy(expected_distances)
+ tstart = self.get_sim_time()
+ timeout = 60
+ while True:
+ now = self.get_sim_time_cached()
+ if now - tstart > timeout:
+ raise NotAchievedException("Did not get all distances")
+ m = self.mav.recv_match(type="DISTANCE_SENSOR",
+ blocking=True,
+ timeout=1)
+ if m is None:
+ continue
+ self.progress("Got (%s)" % str(m))
+ if m.orientation not in wanting_distances:
+ continue
+ if abs(m.current_distance - wanting_distances[m.orientation]) > 5:
+ self.progress("Wrong distance orient=%u want=%u got=%u" %
+ (m.orientation,
+ wanting_distances[m.orientation],
+ m.current_distance))
+ continue
+ self.progress("Correct distance for orient %u (want=%u got=%u)" %
+ (m.orientation,
+ wanting_distances[m.orientation],
+ m.current_distance))
+ del wanting_distances[m.orientation]
+ if len(wanting_distances.items()) == 0:
+ break
+
+ def RPLidarA2(self):
+ '''test Raspberry Pi Lidar A2'''
+ expected_distances = {
+ mavutil.mavlink.MAV_SENSOR_ROTATION_NONE: 276,
+ mavutil.mavlink.MAV_SENSOR_ROTATION_YAW_45: 256,
+ mavutil.mavlink.MAV_SENSOR_ROTATION_YAW_90: 1130,
+ mavutil.mavlink.MAV_SENSOR_ROTATION_YAW_135: 1286,
+ mavutil.mavlink.MAV_SENSOR_ROTATION_YAW_180: 626,
+ mavutil.mavlink.MAV_SENSOR_ROTATION_YAW_225: 971,
+ mavutil.mavlink.MAV_SENSOR_ROTATION_YAW_270: 762,
+ mavutil.mavlink.MAV_SENSOR_ROTATION_YAW_315: 792,
+ }
+
+ self.test_rplidar("rplidara2", expected_distances)
+
+ def RPLidarA1(self):
+ '''test Raspberry Pi Lidar A1'''
+ return # we don't send distances when too long?
+ expected_distances = {
+ mavutil.mavlink.MAV_SENSOR_ROTATION_NONE: 276,
+ mavutil.mavlink.MAV_SENSOR_ROTATION_YAW_45: 256,
+ mavutil.mavlink.MAV_SENSOR_ROTATION_YAW_90: 800,
+ mavutil.mavlink.MAV_SENSOR_ROTATION_YAW_135: 800,
+ mavutil.mavlink.MAV_SENSOR_ROTATION_YAW_180: 626,
+ mavutil.mavlink.MAV_SENSOR_ROTATION_YAW_225: 800,
+ mavutil.mavlink.MAV_SENSOR_ROTATION_YAW_270: 762,
+ mavutil.mavlink.MAV_SENSOR_ROTATION_YAW_315: 792,
+ }
+
+ self.test_rplidar("rplidara1", expected_distances)
+
+ def BrakeZ(self):
+ '''check jerk limit correct in Brake mode'''
+ self.set_parameter('PSC_JERK_Z', 3)
+ self.takeoff(50, mode='GUIDED')
+ vx, vy, vz_up = (0, 0, -1)
+ self.test_guided_local_velocity_target(vx=vx, vy=vy, vz_up=vz_up, timeout=10)
+
+ self.wait_for_local_velocity(vx=vx, vy=vy, vz_up=vz_up, timeout=10)
+ self.change_mode('BRAKE')
+ self.wait_for_local_velocity(vx=0, vy=0, vz_up=0, timeout=10)
+ self.land_and_disarm()
+
def tests2b(self): # this block currently around 9.5mins here
'''return list of all tests'''
ret = ([
@@ -9819,6 +9959,7 @@ def tests2b(self): # this block currently around 9.5mins here
self.AltEstimation,
self.EKFSource,
self.GSF,
+ self.GSF_reset,
self.AP_Avoidance,
self.SMART_RTL,
self.RTL_TO_RALLY,
@@ -9854,6 +9995,11 @@ def tests2b(self): # this block currently around 9.5mins here
self.IMUConsistency,
self.AHRSTrimLand,
self.GuidedYawRate,
+ self.NoArmWithoutMissionItems,
+ self.RPLidarA1,
+ self.RPLidarA2,
+ self.SafetySwitch,
+ self.BrakeZ,
])
return ret
diff --git a/Tools/autotest/arduplane.py b/Tools/autotest/arduplane.py
index 6f426449ab8491..05a415b841cec8 100644
--- a/Tools/autotest/arduplane.py
+++ b/Tools/autotest/arduplane.py
@@ -20,8 +20,12 @@
from common import NotAchievedException
from common import PreconditionFailedException
from common import WaitModeTimeout
+from common import OldpymavlinkException
+from common import Test
+
from pymavlink.rotmat import Vector3
from pysim import vehicleinfo
+from pysim import util
import operator
@@ -318,78 +322,83 @@ def inside_loop(self, count=1):
def set_attitude_target(self, tolerance=10):
"""Test setting of attitude target in guided mode."""
self.change_mode("GUIDED")
-# self.set_parameter("STALL_PREVENTION", 0)
-
- state_roll_over = "roll-over"
- state_stabilize_roll = "stabilize-roll"
- state_hold = "hold"
- state_roll_back = "roll-back"
- state_done = "done"
- tstart = self.get_sim_time()
+ steps = [{"name": "roll-over", "roll": 60, "pitch": 0, "yaw": 0, "throttle": 0, "type_mask": 0b10000001},
+ {"name": "roll-back", "roll": 0, "pitch": 0, "yaw": 0, "throttle": 0, "type_mask": 0b10000001},
+ {"name": "pitch-up+throttle", "roll": 0, "pitch": 20, "yaw": 0, "throttle": 1, "type_mask": 0b11000010},
+ {"name": "pitch-back", "roll": 0, "pitch": 0, "yaw": 0, "throttle": 0, "type_mask": 0b10000010}]
+ state_wait = "wait"
+ state_hold = "hold"
try:
- state = state_roll_over
- while state != state_done:
-
- m = self.mav.recv_match(type='ATTITUDE',
- blocking=True,
- timeout=0.1)
- now = self.get_sim_time_cached()
- if now - tstart > 20:
- raise AutoTestTimeoutException("Manuevers not completed")
- if m is None:
- continue
-
- r = math.degrees(m.roll)
- if state == state_roll_over:
- target_roll_degrees = 60
- if abs(r - target_roll_degrees) < tolerance:
- state = state_stabilize_roll
- stabilize_start = now
- elif state == state_stabilize_roll:
- # just give it a little time to sort it self out
- if now - stabilize_start > 2:
- state = state_hold
- hold_start = now
- elif state == state_hold:
- target_roll_degrees = 60
- if now - hold_start > tolerance:
- state = state_roll_back
- if abs(r - target_roll_degrees) > tolerance:
- raise NotAchievedException("Failed to hold attitude")
- elif state == state_roll_back:
- target_roll_degrees = 0
- if abs(r - target_roll_degrees) < tolerance:
- state = state_done
- else:
- raise ValueError("Unknown state %s" % str(state))
-
- m_nav = self.mav.messages['NAV_CONTROLLER_OUTPUT']
- self.progress("%s Roll: %f desired=%f set=%f" %
- (state, r, m_nav.nav_roll, target_roll_degrees))
-
- time_boot_millis = 0 # FIXME
- target_system = 1 # FIXME
- target_component = 1 # FIXME
- type_mask = 0b10000001 ^ 0xFF # FIXME
- # attitude in radians:
- q = quaternion.Quaternion([math.radians(target_roll_degrees),
- 0,
- 0])
- roll_rate_radians = 0.5
- pitch_rate_radians = 0
- yaw_rate_radians = 0
- thrust = 1.0
- self.mav.mav.set_attitude_target_send(time_boot_millis,
- target_system,
- target_component,
- type_mask,
- q,
- roll_rate_radians,
- pitch_rate_radians,
- yaw_rate_radians,
- thrust)
+ for step in steps:
+ step_start = self.get_sim_time_cached()
+ state = state_wait
+ state_start = self.get_sim_time_cached()
+ while True:
+ m = self.mav.recv_match(type='ATTITUDE',
+ blocking=True,
+ timeout=0.1)
+ now = self.get_sim_time_cached()
+ if now - step_start > 30:
+ raise AutoTestTimeoutException("Manuevers not completed")
+ if m is None:
+ continue
+
+ angle_error = 0
+ if (step["type_mask"] & 0b00000001) or (step["type_mask"] == 0b10000000):
+ angle_error += abs(math.degrees(m.roll) - step["roll"])
+
+ if (step["type_mask"] & 0b00000010) or (step["type_mask"] == 0b10000000):
+ angle_error += abs(math.degrees(m.pitch) - step["pitch"])
+
+ if (step["type_mask"] & 0b00000100) or (step["type_mask"] == 0b10000000):
+ # Strictly we should angle wrap, by plane doesn't support yaw correctly anyway so its not tested here
+ angle_error += abs(math.degrees(m.yaw) - step["yaw"])
+
+ # Note were not checking throttle, however the SITL plane needs full throttle to meet the
+ # target pitch attitude, Pitch test will fail without throttle override
+
+ if state == state_wait:
+ # Reduced tolerance for initial trigger
+ if angle_error < (tolerance * 0.25):
+ state = state_hold
+ state_start = now
+
+ # Allow 10 seconds to reach attitude
+ if (now - state_start) > 10:
+ raise NotAchievedException(step["name"] + ": Failed to get to set attitude")
+
+ elif state == state_hold:
+ # Give 2 seconds to stabilize
+ if (now - state_start) > 2 and not (angle_error < tolerance):
+ raise NotAchievedException(step["name"] + ": Failed to hold set attitude")
+
+ # Hold for 10 seconds
+ if (now - state_start) > 12:
+ # move onto next step
+ self.progress("%s Done" % (step["name"]))
+ break
+
+ self.progress("%s %s error: %f" % (step["name"], state, angle_error))
+
+ time_boot_millis = 0 # FIXME
+ target_system = 1 # FIXME
+ target_component = 1 # FIXME
+ type_mask = step["type_mask"] ^ 0xFF # FIXME
+ # attitude in radians:
+ q = quaternion.Quaternion([math.radians(step["roll"]),
+ math.radians(step["pitch"]),
+ math.radians(step["yaw"])])
+ self.mav.mav.set_attitude_target_send(time_boot_millis,
+ target_system,
+ target_component,
+ type_mask,
+ q,
+ 0, # roll rate, not used in AP
+ 0, # pitch rate, not used in AP
+ 0, # yaw rate, not used in AP
+ step["throttle"])
except Exception as e:
self.change_mode('FBWA')
self.set_rc(3, 1700)
@@ -559,19 +568,156 @@ def DO_REPOSITION(self):
self.location_offset_ne(loc, 500, 500)
new_alt = 100
+ self.run_cmd_int(
+ mavutil.mavlink.MAV_CMD_DO_REPOSITION,
+ p5=int(loc.lat * 1e7),
+ p6=int(loc.lng * 1e7),
+ p7=new_alt, # alt
+ frame=mavutil.mavlink.MAV_FRAME_GLOBAL_RELATIVE_ALT,
+ )
+ self.wait_altitude(new_alt-10, new_alt, timeout=30, relative=True)
+
+ self.install_terrain_handlers_context()
+
+ self.location_offset_ne(loc, 500, 500)
+ terrain_height_wanted = 150
self.run_cmd_int(
mavutil.mavlink.MAV_CMD_DO_REPOSITION,
0,
0,
0,
0,
- int(loc.lat * 1e7),
- int(loc.lng * 1e7),
- new_alt, # alt
- frame=mavutil.mavlink.MAV_FRAME_GLOBAL_RELATIVE_ALT_INT,
+ int(loc.lat*1e7),
+ int(loc.lng*1e7),
+ terrain_height_wanted, # alt
+ frame=mavutil.mavlink.MAV_FRAME_GLOBAL_TERRAIN_ALT,
+ )
+
+ # move to specific terrain-relative altitude and hold for seconds
+ tstart = self.get_sim_time_cached()
+ achieve_start = None
+ tr = None
+ while True:
+ if self.get_sim_time_cached() - tstart > 120:
+ raise NotAchievedException("Did not move to correct terrain alt")
+
+ m = self.mav.recv_match(type='TERRAIN_REPORT',
+ blocking=True,
+ timeout=1)
+ tr = m
+ terrain_height_achieved = m.current_height
+ self.progress("terrain_alt=%f want=%f" %
+ (terrain_height_achieved, terrain_height_wanted))
+ if m is None:
+ continue
+ if abs(terrain_height_wanted - terrain_height_achieved) > 5:
+ if achieve_start is not None:
+ self.progress("Achieve stop")
+ achieve_start = None
+ elif achieve_start is None:
+ self.progress("Achieve start")
+ achieve_start = self.get_sim_time_cached()
+ if achieve_start is not None:
+ if self.get_sim_time_cached() - achieve_start > 10:
+ break
+ m = self.mav.recv_match(type='GLOBAL_POSITION_INT',
+ blocking=True,
+ timeout=1)
+ self.progress("TR: %s" % tr)
+ self.progress("GPI: %s" % m)
+ min_delta = 4
+ delta = abs(m.relative_alt/1000.0 - tr.current_height)
+ if abs(delta < min_delta):
+ raise NotAchievedException("Expected altitude delta (want=%f got=%f)" %
+ (min_delta, delta))
+
+ self.fly_home_land_and_disarm(timeout=180)
+
+ def ExternalPositionEstimate(self):
+ '''Test mavlink EXTERNAL_POSITION_ESTIMATE command'''
+ if not hasattr(mavutil.mavlink, 'MAV_CMD_EXTERNAL_POSITION_ESTIMATE'):
+ raise OldpymavlinkException("pymavlink too old; upgrade pymavlink to get MAV_CMD_EXTERNAL_POSITION_ESTIMATE") # noqa
+ self.change_mode("TAKEOFF")
+ self.wait_ready_to_arm()
+ self.arm_vehicle()
+ self.wait_altitude(48, 52, relative=True)
+
+ loc = self.mav.location()
+ self.location_offset_ne(loc, 2000, 2000)
+
+ # setting external position fail while we have GPS lock
+ self.progress("set new position with GPS")
+ self.run_cmd_int(
+ mavutil.mavlink.MAV_CMD_EXTERNAL_POSITION_ESTIMATE,
+ p1=self.get_sim_time()-1, # transmit time
+ p2=0.5, # processing delay
+ p3=50, # accuracy
+ p5=int(loc.lat * 1e7),
+ p6=int(loc.lng * 1e7),
+ p7=float("NaN"), # alt
+ frame=mavutil.mavlink.MAV_FRAME_GLOBAL,
+ want_result=mavutil.mavlink.MAV_RESULT_FAILED,
+ )
+
+ self.progress("disable the GPS")
+ self.run_auxfunc(
+ 65,
+ 2,
+ want_result=mavutil.mavlink.MAV_RESULT_ACCEPTED
+ )
+
+ # fly for a bit to get into non-aiding state
+ self.progress("waiting 20 seconds")
+ tstart = self.get_sim_time()
+ while self.get_sim_time() < tstart + 20:
+ self.wait_heartbeat()
+
+ self.progress("getting base position")
+ gpi = self.mav.recv_match(
+ type='GLOBAL_POSITION_INT',
+ blocking=True,
+ timeout=5
+ )
+ loc = mavutil.location(gpi.lat*1e-7, gpi.lon*1e-7, 0, 0)
+
+ self.progress("set new position with no GPS")
+ self.run_cmd_int(
+ mavutil.mavlink.MAV_CMD_EXTERNAL_POSITION_ESTIMATE,
+ p1=self.get_sim_time()-1, # transmit time
+ p2=0.5, # processing delay
+ p3=50, # accuracy
+ p5=gpi.lat+1,
+ p6=gpi.lon+1,
+ p7=float("NaN"), # alt
+ frame=mavutil.mavlink.MAV_FRAME_GLOBAL,
+ want_result=mavutil.mavlink.MAV_RESULT_ACCEPTED
+ )
+
+ self.progress("waiting 3 seconds")
+ tstart = self.get_sim_time()
+ while self.get_sim_time() < tstart + 3:
+ self.wait_heartbeat()
+
+ gpi2 = self.mav.recv_match(
+ type='GLOBAL_POSITION_INT',
+ blocking=True,
+ timeout=5
+ )
+ loc2 = mavutil.location(gpi2.lat*1e-7, gpi2.lon*1e-7, 0, 0)
+ dist = self.get_distance(loc, loc2)
+
+ self.progress("dist is %.1f" % dist)
+ if dist > 200:
+ raise NotAchievedException("Position error dist=%.1f" % dist)
+
+ self.progress("re-enable the GPS")
+ self.run_auxfunc(
+ 65,
+ 0,
+ want_result=mavutil.mavlink.MAV_RESULT_ACCEPTED
)
- self.wait_altitude(new_alt-10, new_alt, timeout=30, relative=True)
+ self.progress("flying home")
self.fly_home_land_and_disarm()
def DeepStall(self):
@@ -625,18 +771,18 @@ def fly_deepstall_relative(self):
self.change_mode("AUTO")
self.wait_ready_to_arm()
self.arm_vehicle()
- self.progress("Waiting for deepstall messages")
-
- # note that the following two don't necessarily happen in this
- # order, but at very high speedups we may miss the elevator
- # PWM if we first look for the text (due to the get_sim_time()
- # in wait_servo_channel_value)
- self.context_collect('STATUSTEXT')
+ self.wait_current_waypoint(4)
# assume elevator is on channel 2:
self.wait_servo_channel_value(2, deepstall_elevator_pwm, timeout=240)
- self.wait_text("Deepstall: Entry: ", check_context=True)
+ self.progress("Waiting for stage DEEPSTALL_STAGE_LAND")
+ self.assert_receive_message(
+ 'DEEPSTALL',
+ condition='DEEPSTALL.stage==6',
+ timeout=240,
+ )
+ self.progress("Reached stage DEEPSTALL_STAGE_LAND")
self.disarm_wait(timeout=120)
self.set_current_waypoint(0, check_afterwards=False)
@@ -725,13 +871,9 @@ def DO_CHANGE_SPEED_mavlink(self):
self.change_mode("GUIDED")
self.run_cmd_int(
mavutil.mavlink.MAV_CMD_DO_REPOSITION,
- 0,
- 0,
- 0,
- 0,
- 12345, # lat* 1e7
- 12345, # lon* 1e7
- 100 # alt
+ p5=12345, # lat* 1e7
+ p6=12345, # lon* 1e7
+ p7=100 # alt
)
self.delay_sim_time(10)
self.progress("Ensuring initial speed is known and relatively constant")
@@ -743,13 +885,11 @@ def DO_CHANGE_SPEED_mavlink(self):
new_target_groundspeed = initial_speed + 5
self.run_cmd(
mavutil.mavlink.MAV_CMD_DO_CHANGE_SPEED,
- 1, # groundspeed
- new_target_groundspeed,
- -1, # throttle / no change
- 0, # absolute values
- 0,
- 0,
- 0)
+ p1=1, # groundspeed
+ p2=new_target_groundspeed,
+ p3=-1, # throttle / no change
+ p4=0, # absolute values
+ )
self.wait_groundspeed(new_target_groundspeed-0.5, new_target_groundspeed+0.5, timeout=40)
self.progress("Adding some wind, ensuring groundspeed holds")
self.set_parameter("SIM_WIND_SPD", 5)
@@ -760,25 +900,21 @@ def DO_CHANGE_SPEED_mavlink(self):
# clear target groundspeed
self.run_cmd(
mavutil.mavlink.MAV_CMD_DO_CHANGE_SPEED,
- 1, # groundspeed
- 0,
- -1, # throttle / no change
- 0, # absolute values
- 0,
- 0,
- 0)
+ p1=1, # groundspeed
+ p2=0,
+ p3=-1, # throttle / no change
+ p4=0, # absolute values
+ )
self.progress("Setting airspeed")
new_target_airspeed = initial_speed + 5
self.run_cmd(
mavutil.mavlink.MAV_CMD_DO_CHANGE_SPEED,
- 0, # airspeed
- new_target_airspeed,
- -1, # throttle / no change
- 0, # absolute values
- 0,
- 0,
- 0)
+ p1=0, # airspeed
+ p2=new_target_airspeed,
+ p3=-1, # throttle / no change
+ p4=0, # absolute values
+ )
self.wait_airspeed(new_target_airspeed-0.5, new_target_airspeed+0.5)
self.progress("Adding some wind, hoping groundspeed increases/decreases")
self.set_parameters({
@@ -1169,29 +1305,28 @@ def GCSFailsafe(self):
'''Ensure Long-Failsafe works on GCS loss'''
self.start_subtest("Test Failsafe: RTL")
self.load_sample_mission()
- self.set_parameter("RTL_AUTOLAND", 1)
- self.change_mode("AUTO")
- self.takeoff()
self.set_parameters({
"FS_GCS_ENABL": 1,
"FS_LONG_ACTN": 1,
+ "RTL_AUTOLAND": 1,
+ "SYSID_MYGCS": self.mav.source_system,
})
+ self.takeoff()
+ self.change_mode('LOITER')
self.progress("Disconnecting GCS")
self.set_heartbeat_rate(0)
- self.wait_mode("RTL", timeout=5)
+ self.wait_mode("RTL", timeout=10)
self.set_heartbeat_rate(self.speedup)
self.end_subtest("Completed RTL Failsafe test")
self.start_subtest("Test Failsafe: FBWA Glide")
self.set_parameters({
- "RTL_AUTOLAND": 1,
"FS_LONG_ACTN": 2,
})
- self.change_mode("AUTO")
- self.takeoff()
+ self.change_mode('AUTO')
self.progress("Disconnecting GCS")
self.set_heartbeat_rate(0)
- self.wait_mode("FBWA", timeout=5)
+ self.wait_mode("FBWA", timeout=10)
self.set_heartbeat_rate(self.speedup)
self.end_subtest("Completed FBWA Failsafe test")
@@ -1296,6 +1431,31 @@ def wait_circling_point_with_radius(self, loc, want_radius, epsilon=5.0, min_cir
on_radius_start_heading = None
circle_time_start = 0
+ def MODE_SWITCH_RESET(self):
+ '''test the MODE_SWITCH_RESET auxiliary function'''
+ self.set_parameters({
+ "RC9_OPTION": 96,
+ })
+
+ self.progress("Using RC to change modes")
+ self.set_rc(8, 1500)
+ self.wait_mode('FBWA')
+
+ self.progress("Killing RC to engage RC failsafe")
+ self.set_parameter('SIM_RC_FAIL', 1)
+ self.wait_mode('RTL')
+
+ self.progress("Reinstating RC")
+ self.set_parameter('SIM_RC_FAIL', 0)
+
+ self.progress("Ensuring we don't automatically revert mode")
+ self.delay_sim_time(2)
+ self.assert_mode_is('RTL')
+
+ self.progress("Ensuring MODE_SWITCH_RESET switch resets to pre-failsafe mode")
+ self.set_rc(9, 2000)
+ self.wait_mode('FBWA')
+
def FenceStatic(self):
'''Test Basic Fence Functionality'''
ex = None
@@ -1844,6 +2004,7 @@ def AIRSPEED_AUTOCAL(self):
self.fly_home_land_and_disarm()
def deadreckoning_main(self, disable_airspeed_sensor=False):
+ self.reboot_sitl()
self.wait_ready_to_arm()
self.gpi = None
self.simstate = None
@@ -1887,13 +2048,11 @@ def validate_global_position_int_against_simstate(mav, m):
self.location_offset_ne(loc, 500, 500)
self.run_cmd_int(
mavutil.mavlink.MAV_CMD_DO_REPOSITION,
- 0,
- mavutil.mavlink.MAV_DO_REPOSITION_FLAGS_CHANGE_MODE,
- 0,
- 0,
- int(loc.lat * 1e7),
- int(loc.lng * 1e7),
- 100, # alt
+ p1=0,
+ p2=mavutil.mavlink.MAV_DO_REPOSITION_FLAGS_CHANGE_MODE,
+ p5=int(loc.lat * 1e7),
+ p6=int(loc.lng * 1e7),
+ p7=100, # alt
frame=mavutil.mavlink.MAV_FRAME_GLOBAL_RELATIVE_ALT_INT,
)
self.wait_location(loc, accuracy=100)
@@ -2825,9 +2984,11 @@ def fly_external_AHRS(self, sim, eahrs_type, mission):
self.reboot_sitl()
self.delay_sim_time(5)
self.progress("Running accelcal")
- self.run_cmd(mavutil.mavlink.MAV_CMD_PREFLIGHT_CALIBRATION,
- 0, 0, 0, 0, 4, 0, 0,
- timeout=5)
+ self.run_cmd(
+ mavutil.mavlink.MAV_CMD_PREFLIGHT_CALIBRATION,
+ p5=4,
+ timeout=5,
+ )
self.wait_ready_to_arm()
self.arm_vehicle()
@@ -2913,7 +3074,7 @@ def WindEstimates(self):
self.wait_and_maintain_wind_estimate(
5, 45,
speed_tolerance=1,
- timeout=20
+ timeout=30
)
self.fly_home_land_and_disarm()
@@ -2921,9 +3082,9 @@ def VectorNavEAHRS(self):
'''Test VectorNav EAHRS support'''
self.fly_external_AHRS("VectorNav", 1, "ap1.txt")
- def LordEAHRS(self):
- '''Test LORD Microstrain EAHRS support'''
- self.fly_external_AHRS("LORD", 2, "ap1.txt")
+ def MicroStrainEAHRS(self):
+ '''Test MicroStrain EAHRS support'''
+ self.fly_external_AHRS("MicroStrain", 2, "ap1.txt")
def get_accelvec(self, m):
return Vector3(m.xacc, m.yacc, m.zacc) * 0.001 * 9.81
@@ -2986,13 +3147,17 @@ def IMUTempCal(self):
self.set_parameter("SIM_IMUT_FIXED", 12)
self.progress("Running accel cal")
- self.run_cmd(mavutil.mavlink.MAV_CMD_PREFLIGHT_CALIBRATION,
- 0, 0, 0, 0, 4, 0, 0,
- timeout=5)
+ self.run_cmd(
+ mavutil.mavlink.MAV_CMD_PREFLIGHT_CALIBRATION,
+ p5=4,
+ timeout=5,
+ )
self.progress("Running gyro cal")
- self.run_cmd(mavutil.mavlink.MAV_CMD_PREFLIGHT_CALIBRATION,
- 0, 0, 0, 0, 1, 0, 0,
- timeout=5)
+ self.run_cmd(
+ mavutil.mavlink.MAV_CMD_PREFLIGHT_CALIBRATION,
+ p5=1,
+ timeout=5,
+ )
self.set_parameters({
"SIM_IMUT_FIXED": 0,
"INS_TCAL1_ENABLE": 2,
@@ -3232,13 +3397,9 @@ def fail_speed():
loc = self.mav.location()
self.run_cmd_int(
mavutil.mavlink.MAV_CMD_DO_REPOSITION,
- 0,
- 0,
- 0,
- 0,
- int(loc.lat * 1e7),
- int(loc.lng * 1e7),
- 50 # alt
+ p5=int(loc.lat * 1e7),
+ p6=int(loc.lng * 1e7),
+ p7=50, # alt
)
self.delay_sim_time(5)
# create an airspeed sensor error by freezing to the
@@ -3249,13 +3410,10 @@ def fail_speed():
self.set_parameter("SIM_ARSPD_FAIL", m.airspeed)
self.run_cmd(
mavutil.mavlink.MAV_CMD_DO_CHANGE_SPEED,
- 0, # airspeed
- 30,
- -1, # throttle / no change
- 0, # absolute values
- 0,
- 0,
- 0
+ p1=0, # airspeed
+ p2=30,
+ p3=-1, # throttle / no change
+ p4=0, # absolute values
)
self.wait_statustext(text="EKF3 lane switch", timeout=30, the_function=fail_speed, check_context=True)
if self.lane_switches != [1, 0, 1, 0, 1]:
@@ -3592,6 +3750,7 @@ def FlyEachFrame(self):
"quadplane-tilttrivec": "loses attitude control and crashes",
"plane-ice" : "needs ICE control channel for ignition",
"quadplane-ice" : "needs ICE control channel for ignition",
+ "quadplane-can" : "needs CAN periph",
}
for frame in sorted(vinfo_options["frames"].keys()):
self.start_subtest("Testing frame (%s)" % str(frame))
@@ -3676,13 +3835,9 @@ def WatchdogHome(self):
new_home.altitude = new_home.altitude + 300000 # 300 metres
self.run_cmd_int(
mavutil.mavlink.MAV_CMD_DO_SET_HOME,
- 0, # p1,
- 0, # p2,
- 0, # p3,
- 0, # p4,
- new_home.latitude,
- new_home.longitude,
- new_home.altitude/1000.0, # mm => m
+ p5=new_home.latitude,
+ p6=new_home.longitude,
+ p7=new_home.altitude/1000.0, # mm => m
)
old_bootcount = self.get_parameter('STAT_BOOTCNT')
self.progress("Forcing watchdog reset")
@@ -3759,6 +3914,18 @@ def AUTOTUNE(self):
self.change_mode('FBWA')
self.fly_home_land_and_disarm(timeout=tdelta+240)
+ def AutotuneFiltering(self):
+ '''Test AutoTune mode with filter updates disabled'''
+ self.set_parameters({
+ "AUTOTUNE_OPTIONS": 3,
+ # some filtering is required for autotune to complete
+ "RLL_RATE_FLTD": 10,
+ "PTCH_RATE_FLTD": 10,
+ "RLL_RATE_FLTT": 20,
+ "PTCH_RATE_FLTT": 20,
+ })
+ self.AUTOTUNE()
+
def LandingDrift(self):
'''Circuit with baro drift'''
self.customise_SITL_commandline([], wipe=True)
@@ -4342,25 +4509,13 @@ def MissionJumpTags_missing_jump_target(self, target_system=1, target_component=
self.progress("Checking incorrect tag behaviour")
self.run_cmd(
mavutil.mavlink.MAV_CMD_DO_JUMP_TAG,
- jump_target + 1, # p1
- 0, # p2
- 0, # p3
- 0, # p4
- 0, # p5
- 0, # p6
- 0, # p7
+ p1=jump_target + 1,
want_result=mavutil.mavlink.MAV_RESULT_FAILED
)
self.progress("Checking correct tag behaviour")
self.run_cmd(
mavutil.mavlink.MAV_CMD_DO_JUMP_TAG,
- jump_target, # p1
- 0, # p2
- 0, # p3
- 0, # p4
- 0, # p5
- 0, # p6
- 0, # p7
+ p1=jump_target,
)
self.assert_current_waypoint(4)
@@ -4398,13 +4553,7 @@ def MissionJumpTags_jump_tag_at_end_of_mission(self, target_system=1, target_com
self.arm_vehicle()
self.run_cmd(
mavutil.mavlink.MAV_CMD_DO_JUMP_TAG,
- 17, # p1
- 0, # p2
- 0, # p3
- 0, # p4
- 0, # p5
- 0, # p6
- 0, # p7
+ p1=17,
want_result=mavutil.mavlink.MAV_RESULT_FAILED
)
self.disarm_vehicle()
@@ -4448,8 +4597,10 @@ def AltResetBadGPS(self):
# reboot to clear potentially bad state
def trigger_airspeed_cal(self):
- self.run_cmd(mavutil.mavlink.MAV_CMD_PREFLIGHT_CALIBRATION,
- 0, 0, 1, 0, 0, 0, 0)
+ self.run_cmd(
+ mavutil.mavlink.MAV_CMD_PREFLIGHT_CALIBRATION,
+ p3=1,
+ )
def AirspeedCal(self):
'''test Airspeed calibration'''
@@ -4466,7 +4617,7 @@ def AirspeedCal(self):
self.start_subtest('0 airspeed sensors')
self.set_parameter('ARSPD_TYPE', 0)
self.reboot_sitl()
- self.wait_statustext('No airspeed sensor present or enabled', check_context=True)
+ self.wait_statustext('No airspeed sensor', check_context=True)
self.trigger_airspeed_cal()
self.delay_sim_time(5)
if self.statustext_in_collections('Airspeed 1 calibrated'):
@@ -4486,6 +4637,43 @@ def AirspeedCal(self):
self.reboot_sitl()
+ def RunMissionScript(self):
+ '''Test run_mission.py script'''
+ script = os.path.join('Tools', 'autotest', 'run_mission.py')
+ self.stop_SITL()
+ util.run_cmd([
+ util.reltopdir(script),
+ self.binary,
+ 'plane',
+ self.generic_mission_filepath_for_filename("flaps.txt"),
+ ])
+ self.start_SITL()
+
+ def MAV_CMD_GUIDED_CHANGE_ALTITUDE(self):
+ '''test handling of MAV_CMD_GUIDED_CHANGE_ALTITUDE'''
+ self.takeoff(30, relative=True)
+ self.change_mode('GUIDED')
+ for alt in 50, 70:
+ self.run_cmd_int(
+ mavutil.mavlink.MAV_CMD_GUIDED_CHANGE_ALTITUDE,
+ p7=alt,
+ frame=mavutil.mavlink.MAV_FRAME_GLOBAL_RELATIVE_ALT,
+ )
+ self.wait_altitude(alt-1, alt+1, timeout=30, relative=True)
+
+ # test for #24535
+ self.change_mode('LOITER')
+ self.delay_sim_time(5)
+ self.change_mode('GUIDED')
+ self.wait_altitude(
+ alt-3, # NOTE: reuse of alt from above loop!
+ alt+3,
+ minimum_duration=10,
+ timeout=30,
+ relative=True,
+ )
+ self.fly_home_land_and_disarm()
+
def tests(self):
'''return list of all tests'''
ret = super(AutoTestPlane, self).tests()
@@ -4537,7 +4725,7 @@ def tests(self):
self.TerrainMission,
self.TerrainLoiter,
self.VectorNavEAHRS,
- self.LordEAHRS,
+ self.MicroStrainEAHRS,
self.Deadreckoning,
self.DeadreckoningNoAirSpeed,
self.EKFlaneswitch,
@@ -4556,6 +4744,7 @@ def tests(self):
self.DCMFallback,
self.MAVFTP,
self.AUTOTUNE,
+ self.AutotuneFiltering,
self.MegaSquirt,
self.MSP_DJI,
self.SpeedToFly,
@@ -4565,12 +4754,17 @@ def tests(self):
self.EmbeddedParamParser,
self.AerobaticsScripting,
self.MANUAL_CONTROL,
+ self.RunMissionScript,
self.WindEstimates,
self.AltResetBadGPS,
self.AirspeedCal,
self.MissionJumpTags,
- self.GCSFailsafe,
+ Test(self.GCSFailsafe, speedup=8),
self.SDCardWPTest,
+ self.NoArmWithoutMissionItems,
+ self.MODE_SWITCH_RESET,
+ self.ExternalPositionEstimate,
+ self.MAV_CMD_GUIDED_CHANGE_ALTITUDE,
])
return ret
diff --git a/Tools/autotest/ardusub.py b/Tools/autotest/ardusub.py
index 58a5f6805c91a0..a6af0aba9c06c6 100644
--- a/Tools/autotest/ardusub.py
+++ b/Tools/autotest/ardusub.py
@@ -375,15 +375,11 @@ def reboot_sitl(self):
"""Reboot SITL instance and wait it to reconnect."""
# out battery is reset to full on reboot. So reduce it to 10%
# and wait for it to go above 50.
- self.run_cmd(mavutil.mavlink.MAV_CMD_BATTERY_RESET,
- 255, # battery mask
- 10, # percentage
- 0,
- 0,
- 0,
- 0,
- 0,
- 0)
+ self.run_cmd(
+ mavutil.mavlink.MAV_CMD_BATTERY_RESET,
+ p1=255, # battery mask
+ p2=10, # percentage
+ )
self.run_cmd_reboot()
tstart = time.time()
while True:
@@ -392,14 +388,10 @@ def reboot_sitl(self):
# ask for the message:
batt = None
try:
- self.send_cmd(mavutil.mavlink.MAV_CMD_REQUEST_MESSAGE,
- mavutil.mavlink.MAVLINK_MSG_ID_BATTERY_STATUS,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0)
+ self.send_cmd(
+ mavutil.mavlink.MAV_CMD_REQUEST_MESSAGE,
+ p1=mavutil.mavlink.MAVLINK_MSG_ID_BATTERY_STATUS,
+ )
batt = self.mav.recv_match(type='BATTERY_STATUS',
blocking=True,
timeout=1)
diff --git a/Tools/autotest/autotest.py b/Tools/autotest/autotest.py
index a19bdf335300d5..207bf3e7137357 100755
--- a/Tools/autotest/autotest.py
+++ b/Tools/autotest/autotest.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
"""
ArduPilot automatic test suite.
@@ -21,6 +21,7 @@
import time
import traceback
+import blimp
import rover
import arducopter
import arduplane
@@ -380,6 +381,7 @@ def find_specific_test_to_run(step):
tester_class_map = {
+ "test.Blimp": blimp.AutoTestBlimp,
"test.Copter": arducopter.AutoTestCopter,
"test.CopterTests1a": arducopter.AutoTestCopterTests1a, # 8m43s
"test.CopterTests1b": arducopter.AutoTestCopterTests1b, # 8m5s
@@ -399,8 +401,9 @@ def find_specific_test_to_run(step):
"test.CAN": arducopter.AutoTestCAN,
}
-suplementary_test_binary_map = {
- "test.CAN": ["sitl_periph_gps.AP_Periph", "sitl_periph_gps.AP_Periph.1"],
+supplementary_test_binary_map = {
+ "test.CAN": ["sitl_periph_gps:AP_Periph:0:Tools/autotest/default_params/periph.parm,Tools/autotest/default_params/quad-periph.parm", # noqa: E501
+ "sitl_periph_gps:AP_Periph:1:Tools/autotest/default_params/periph.parm"],
}
@@ -485,6 +488,11 @@ def run_step(step):
return util.build_replay(board='SITL')
if vehicle_binary is not None:
+ try:
+ binary = binary_path(step, debug=opts.debug)
+ os.unlink(binary)
+ except (FileNotFoundError, ValueError):
+ pass
if len(vehicle_binary.split(".")) == 1:
return util.build_SITL(vehicle_binary, **build_opts)
else:
@@ -499,24 +507,31 @@ def run_step(step):
if step.startswith("defaults"):
vehicle = step[9:]
return get_default_params(vehicle, binary)
+
+ # see if we need any supplementary binaries
supplementary_binaries = []
- if step in suplementary_test_binary_map:
- for supplementary_test_binary in suplementary_test_binary_map[step]:
- config_name = supplementary_test_binary.split('.')[0]
- binary_name = supplementary_test_binary.split('.')[1]
- instance_num = 0
- if len(supplementary_test_binary.split('.')) >= 3:
- instance_num = int(supplementary_test_binary.split('.')[2])
- supplementary_binaries.append([util.reltopdir(os.path.join('build',
- config_name,
- 'bin',
- binary_name)),
- '-I {}'.format(instance_num)])
- # we are running in conjunction with a supplementary app
- # can't have speedup
- opts.speedup = 1.0
- else:
- supplementary_binaries = []
+ for k in supplementary_test_binary_map.keys():
+ if step.startswith(k):
+ # this test needs to use supplementary binaries
+ for supplementary_test_binary in supplementary_test_binary_map[k]:
+ a = supplementary_test_binary.split(':')
+ if len(a) != 4:
+ raise ValueError("Bad supplementary_test_binary %s" % supplementary_test_binary)
+ config_name = a[0]
+ binary_name = a[1]
+ instance_num = int(a[2])
+ param_file = a[3].split(",")
+ bin_path = util.reltopdir(os.path.join('build', config_name, 'bin', binary_name))
+ customisation = '-I {}'.format(instance_num)
+ sup_binary = {"binary" : bin_path,
+ "customisation" : customisation,
+ "param_file" : param_file}
+ supplementary_binaries.append(sup_binary)
+ # we are running in conjunction with a supplementary app
+ # can't have speedup
+ opts.speedup = 1.0
+ break
+
fly_opts = {
"viewerip": opts.viewerip,
"use_map": opts.map,
@@ -802,7 +817,7 @@ def run_tests(steps):
return passed
-vehicle_list = ['Sub', 'Copter', 'Plane', 'Tracker', 'Rover', 'QuadPlane', 'BalanceBot', 'Helicopter', 'Sailboat']
+vehicle_list = ['Sub', 'Copter', 'Plane', 'Tracker', 'Rover', 'QuadPlane', 'BalanceBot', 'Helicopter', 'Sailboat', 'Blimp']
def list_subtests():
@@ -1115,6 +1130,7 @@ def format_epilog(self, formatter):
'build.Blimp',
'defaults.Blimp',
+ 'test.Blimp',
'build.SITLPeriphGPS',
'test.CAN',
diff --git a/Tools/autotest/bisect-helper.py b/Tools/autotest/bisect-helper.py
index e0da93182ef33d..e0aafe56587335 100755
--- a/Tools/autotest/bisect-helper.py
+++ b/Tools/autotest/bisect-helper.py
@@ -2,6 +2,10 @@
'''A helper script for bisecting common problems when working with ArduPilot
+When running bisections, you should
+
+export SITL_PANIC_EXIT=1
+
Bisect between a commit which builds and one which doesn't,
finding the first commit which broke the build with a
specific failure:
@@ -115,7 +119,6 @@ def run_program(self, prefix, cmd_list):
'''run cmd_list, spewing and setting output in self'''
self.progress("Running (%s)" % " ".join(cmd_list))
p = subprocess.Popen(cmd_list,
- bufsize=1,
stdin=None,
close_fds=True,
stdout=subprocess.PIPE,
@@ -184,6 +187,10 @@ def __init__(self, opts):
super(BisectBuild, self).__init__(opts)
def run(self):
+ if self.opts.build_failure_string is None:
+ self.progress("--build-failure-string is required when using --build")
+ self.exit_abort()
+
self.update_submodules()
self.build() # may exit with skip or fail
self.exit_pass()
@@ -273,7 +280,7 @@ def run(self):
if code == self.exit_fail_code():
with open("/tmp/fail-counts", "a") as f:
- print("Failed on run %u" % (i+1,), file=f)
+ f.write("Failed on run %u\n" % (i+1,))
if ignore:
self.progress("Ignoring this run")
continue
@@ -282,6 +289,8 @@ def run(self):
self.git_reset()
+ self.progress("Exit code is %u" % code)
+
sys.exit(code)
@@ -294,8 +303,7 @@ def run(self):
help="Help bisect a build failure")
parser.add_option("--build-failure-string",
type='string',
- default=None,
- help="If supplied, must be present in"
+ help="Must be present in"
"build output to count as a failure")
group_autotest = optparse.OptionGroup(parser, "Run-AutoTest Options")
diff --git a/Tools/autotest/blimp.py b/Tools/autotest/blimp.py
new file mode 100644
index 00000000000000..e180ea04882d33
--- /dev/null
+++ b/Tools/autotest/blimp.py
@@ -0,0 +1,131 @@
+'''
+Fly Blimp in SITL
+
+AP_FLAKE8_CLEAN
+'''
+
+from __future__ import print_function
+import os
+import shutil
+
+from pymavlink import mavutil
+
+from common import AutoTest
+
+# get location of scripts
+testdir = os.path.dirname(os.path.realpath(__file__))
+SITL_START_LOCATION = mavutil.location(-35.362938, 149.165085, 584, 270)
+
+# Flight mode switch positions are set-up in arducopter.param to be
+# switch 1 = Circle
+# switch 2 = Land
+# switch 3 = RTL
+# switch 4 = Auto
+# switch 5 = Loiter
+# switch 6 = Stabilize
+
+
+class AutoTestBlimp(AutoTest):
+ @staticmethod
+ def get_not_armable_mode_list():
+ return []
+
+ @staticmethod
+ def get_not_disarmed_settable_modes_list():
+ return []
+
+ @staticmethod
+ def get_no_position_not_settable_modes_list():
+ return []
+
+ @staticmethod
+ def get_position_armable_modes_list():
+ return []
+
+ @staticmethod
+ def get_normal_armable_modes_list():
+ return []
+
+ def log_name(self):
+ return "Blimp"
+
+ def default_mode(self):
+ return "MANUAL"
+
+ def test_filepath(self):
+ return os.path.realpath(__file__)
+
+ def default_speedup(self):
+ return 100
+
+ def set_current_test_name(self, name):
+ self.current_test_name_directory = "Blimp_Tests/" + name + "/"
+
+ def sitl_start_location(self):
+ return SITL_START_LOCATION
+
+ def sitl_streamrate(self):
+ return 5
+
+ def vehicleinfo_key(self):
+ return 'Blimp'
+
+ def default_frame(self):
+ return "Blimp"
+
+ def apply_defaultfile_parameters(self):
+ # Blimp passes in a defaults_filepath in place of applying
+ # parameters afterwards.
+ pass
+
+ def defaults_filepath(self):
+ return self.model_defaults_filepath(self.frame)
+
+ def wait_disarmed_default_wait_time(self):
+ return 120
+
+ def close(self):
+ super(AutoTestBlimp, self).close()
+
+ # [2014/05/07] FC Because I'm doing a cross machine build
+ # (source is on host, build is on guest VM) I cannot hard link
+ # This flag tells me that I need to copy the data out
+ if self.copy_tlog:
+ shutil.copy(self.logfile, self.buildlog)
+
+ def is_blimp(self):
+ return True
+
+ def get_stick_arming_channel(self):
+ return int(self.get_parameter("RCMAP_YAW"))
+
+ def get_disarm_delay(self):
+ return int(self.get_parameter("DISARM_DELAY"))
+
+ def set_autodisarm_delay(self, delay):
+ self.set_parameter("DISARM_DELAY", delay)
+
+ def Speed(self):
+ '''test we can move'''
+ self.change_mode('MANUAL')
+ self.wait_ready_to_arm()
+ self.arm_vehicle()
+
+ # make sure we don't drift:
+ start = self.mav.location()
+ self.set_rc(2, 2000)
+ self.wait_distance_to_location(start, 2, 10, timeout=40)
+ self.disarm_vehicle()
+
+ def tests(self):
+ '''return list of all tests'''
+ # ret = super(AutoTestBlimp, self).tests()
+ ret = []
+ ret.extend([
+ self.Speed,
+ ])
+ return ret
+
+ def disabled_tests(self):
+ return {
+ }
diff --git a/Tools/autotest/check_autotest_speedup.py b/Tools/autotest/check_autotest_speedup.py
index a601dcc5e99201..81bf13edfe064b 100755
--- a/Tools/autotest/check_autotest_speedup.py
+++ b/Tools/autotest/check_autotest_speedup.py
@@ -38,7 +38,6 @@ def run_program(self, prefix, cmd_list):
'''run cmd_list, spewing and setting output in self'''
self.progress("Running (%s)" % " ".join(cmd_list))
p = subprocess.Popen(cmd_list,
- bufsize=1,
stdin=None,
close_fds=True,
stdout=subprocess.PIPE,
diff --git a/Tools/autotest/common.py b/Tools/autotest/common.py
index 6ce9a81cc187e0..09f5f0b84262de 100644
--- a/Tools/autotest/common.py
+++ b/Tools/autotest/common.py
@@ -37,6 +37,7 @@
from pymavlink import mavextra
from pymavlink.rotmat import Vector3
from pymavlink import quaternion
+from pymavlink.generator import mavgen
from pysim import util, vehicleinfo
@@ -167,6 +168,11 @@ class NotAchievedException(ErrorException):
pass
+class OldpymavlinkException(ErrorException):
+ """Thrown when a new feature is required from pymavlink"""
+ pass
+
+
class YawSpeedNotAchievedException(NotAchievedException):
"""Thrown when fails to achieve given yaw speed."""
pass
@@ -196,11 +202,14 @@ def __init__(self):
self.heartbeat_interval_ms = 1000
self.original_heartbeat_interval_ms = None
self.installed_scripts = []
+ self.installed_modules = []
+ self.overridden_message_rates = {}
# https://stackoverflow.com/questions/616645/how-do-i-duplicate-sys-stdout-to-a-log-file-in-python
class TeeBoth(object):
- def __init__(self, name, mode, mavproxy_logfile):
+ def __init__(self, name, mode, mavproxy_logfile, suppress_stdout=False):
+ self.suppress_stdout = suppress_stdout
self.file = open(name, mode)
self.stdout = sys.stdout
self.stderr = sys.stderr
@@ -219,7 +228,8 @@ def close(self):
def write(self, data):
self.file.write(data)
- self.stdout.write(data)
+ if not self.suppress_stdout:
+ self.stdout.write(data)
def flush(self):
self.file.flush()
@@ -1650,13 +1660,27 @@ def sitl_streamrate(self):
"""Allow subclasses to override SITL streamrate."""
return 10
+ def adjust_ardupilot_port(self, port):
+ '''adjust port in case we do not wish to use the default range (5760 and 5501 etc)'''
+ return port
+
+ def spare_network_port(self, offset=0):
+ '''returns a network port which should be able to be bound'''
+ if offset > 2:
+ raise ValueError("offset too large")
+ return 8000 + offset
+
def autotest_connection_string_to_ardupilot(self):
- return "tcp:127.0.0.1:5760"
+ return "tcp:127.0.0.1:%u" % self.adjust_ardupilot_port(5760)
+
+ def sitl_rcin_port(self, offset=0):
+ if offset > 2:
+ raise ValueError("offset too large")
+ return 5501 + offset
def mavproxy_options(self):
"""Returns options to be passed to MAVProxy."""
ret = [
- '--sitl=127.0.0.1:5502',
'--streamrate=%u' % self.sitl_streamrate(),
'--target-system=%u' % self.sysid_thismav(),
'--target-component=1',
@@ -1865,26 +1889,13 @@ def reboot_check_valgrind_log(self):
shutil.move(valgrind_log, backup_valgrind_log)
def run_cmd_reboot(self):
- self.run_cmd(mavutil.mavlink.MAV_CMD_PREFLIGHT_REBOOT_SHUTDOWN,
- 1, # confirmation
- 1, # reboot autopilot
- 0,
- 0,
- 0,
- 0,
- 0,
- 0)
+ self.run_cmd(
+ mavutil.mavlink.MAV_CMD_PREFLIGHT_REBOOT_SHUTDOWN,
+ p1=1, # reboot autopilot
+ )
def run_cmd_run_prearms(self):
- self.run_cmd(mavutil.mavlink.MAV_CMD_RUN_PREARM_CHECKS,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0)
+ self.run_cmd(mavutil.mavlink.MAV_CMD_RUN_PREARM_CHECKS)
def run_cmd_enable_high_latency(self, new_state):
p1 = 0
@@ -1893,13 +1904,7 @@ def run_cmd_enable_high_latency(self, new_state):
self.run_cmd(
mavutil.mavlink.MAV_CMD_CONTROL_HIGH_LATENCY,
- p1, # p1 - enable/disable
- 0, # p2
- 0, # p3
- 0, # p4
- 0, # p5
- 0, # p6
- 0, # p7
+ p1=p1, # enable/disable
)
def reboot_sitl_mav(self, required_bootcount=None, force=False):
@@ -1939,13 +1944,10 @@ def reboot_sitl_mav(self, required_bootcount=None, force=False):
p6 = 20190226 # magic force-reboot value
self.send_cmd(
mavutil.mavlink.MAV_CMD_PREFLIGHT_REBOOT_SHUTDOWN,
- 1,
- 1,
- 0,
- 0,
- 0,
- p6,
- 0)
+ p1=1,
+ p2=1,
+ p6=p6,
+ )
do_context = True
if do_context:
self.context_push()
@@ -2035,12 +2037,13 @@ def scripting_restart(self):
self.progress("Restarting Scripting")
self.run_cmd_int(
mavutil.mavlink.MAV_CMD_SCRIPTING,
- mavutil.mavlink.SCRIPTING_CMD_STOP_AND_RESTART,
- 0, 0, 0, 0, 0, 0,
- timeout=5)
+ p1=mavutil.mavlink.SCRIPTING_CMD_STOP_AND_RESTART,
+ timeout=5,
+ )
def set_streamrate(self, streamrate, timeout=20, stream=mavutil.mavlink.MAV_DATA_STREAM_ALL):
'''set MAV_DATA_STREAM_ALL; timeout is wallclock time'''
+ self.do_timesync_roundtrip(timeout_in_wallclock=True)
tstart = time.time()
while True:
if time.time() - tstart > timeout:
@@ -2137,34 +2140,19 @@ def get_sim_parameter_documentation_get_whitelist(self):
"SIM_ACC1_BIAS_Y",
"SIM_ACC1_BIAS_Z",
"SIM_ACC1_RND",
- "SIM_ACC1_SCAL_X",
- "SIM_ACC1_SCAL_Y",
- "SIM_ACC1_SCAL_Z",
"SIM_ACC2_BIAS_X",
"SIM_ACC2_BIAS_Y",
"SIM_ACC2_BIAS_Z",
"SIM_ACC2_RND",
- "SIM_ACC2_SCAL_X",
- "SIM_ACC2_SCAL_Y",
- "SIM_ACC2_SCAL_Z",
"SIM_ACC3_BIAS_X",
"SIM_ACC3_BIAS_Y",
"SIM_ACC3_BIAS_Z",
"SIM_ACC3_RND",
- "SIM_ACC3_SCAL_X",
- "SIM_ACC3_SCAL_Y",
- "SIM_ACC3_SCAL_Z",
"SIM_ACC4_RND",
- "SIM_ACC4_SCAL_X",
- "SIM_ACC4_SCAL_Y",
- "SIM_ACC4_SCAL_Z",
"SIM_ACC4_BIAS_X",
"SIM_ACC4_BIAS_Y",
"SIM_ACC4_BIAS_Z",
"SIM_ACC5_RND",
- "SIM_ACC5_SCAL_X",
- "SIM_ACC5_SCAL_Y",
- "SIM_ACC5_SCAL_Z",
"SIM_ACC5_BIAS_X",
"SIM_ACC5_BIAS_Y",
"SIM_ACC5_BIAS_Z",
@@ -2221,7 +2209,6 @@ def get_sim_parameter_documentation_get_whitelist(self):
"SIM_BARO_WCF_RGT",
"SIM_BARO_WCF_UP",
"SIM_BATT_CAP_AH",
- "SIM_BATT_VOLTAGE",
"SIM_BAUDLIMIT_EN",
"SIM_DRIFT_SPEED",
"SIM_DRIFT_TIME",
@@ -2255,7 +2242,6 @@ def get_sim_parameter_documentation_get_whitelist(self):
"SIM_GPS2_POS_X",
"SIM_GPS2_POS_Y",
"SIM_GPS2_POS_Z",
- "SIM_GPS2_TYPE",
"SIM_GPS2_VERR_X",
"SIM_GPS2_VERR_Y",
"SIM_GPS2_VERR_Z",
@@ -2276,30 +2262,14 @@ def get_sim_parameter_documentation_get_whitelist(self):
"SIM_GPS_POS_X",
"SIM_GPS_POS_Y",
"SIM_GPS_POS_Z",
- "SIM_GPS_TYPE",
"SIM_GPS_VERR_X",
"SIM_GPS_VERR_Y",
"SIM_GPS_VERR_Z",
"SIM_GYR1_RND",
- "SIM_GYR1_SCALE_X",
- "SIM_GYR1_SCALE_Y",
- "SIM_GYR1_SCALE_Z",
"SIM_GYR2_RND",
- "SIM_GYR2_SCALE_X",
- "SIM_GYR2_SCALE_Y",
- "SIM_GYR2_SCALE_Z",
"SIM_GYR3_RND",
- "SIM_GYR3_SCALE_X",
- "SIM_GYR3_SCALE_Y",
- "SIM_GYR3_SCALE_Z",
"SIM_GYR4_RND",
- "SIM_GYR4_SCALE_X",
- "SIM_GYR4_SCALE_Y",
- "SIM_GYR4_SCALE_Z",
"SIM_GYR5_RND",
- "SIM_GYR5_SCALE_X",
- "SIM_GYR5_SCALE_Y",
- "SIM_GYR5_SCALE_Z",
"SIM_GYR_FAIL_MSK",
"SIM_GYR_FILE_RW",
"SIM_IE24_ENABLE",
@@ -2424,7 +2394,6 @@ def get_sim_parameter_documentation_get_whitelist(self):
"SIM_INS_THR_MIN",
"SIM_LED_LAYOUT",
"SIM_LOOP_DELAY",
- "SIM_MAG1_DEVID",
"SIM_MAG1_SCALING",
"SIM_MAG2_DEVID",
"SIM_MAG2_DIA_X",
@@ -2484,7 +2453,6 @@ def get_sim_parameter_documentation_get_whitelist(self):
"SIM_RC_CHANCOUNT",
"SIM_RICH_CTRL",
"SIM_RICH_ENABLE",
- "SIM_SAFETY_STATE",
"SIM_SERVO_SPEED",
"SIM_SHIP_DSIZE",
"SIM_SHIP_ENABLE",
@@ -2785,6 +2753,8 @@ def all_log_format_ids(self):
continue
if "#if AC_PRECLAND_ENABLED" in line:
continue
+ if "#if OFFBOARD_GUIDED == ENABLED" in line:
+ continue
if "#end" in line:
continue
if "LOG_COMMON_STRUCTURES" in line:
@@ -2961,7 +2931,7 @@ def LoggerDocumentation(self):
REPLAY_MSGS = ['RFRH', 'RFRF', 'REV2', 'RSO2', 'RWA2', 'REV3', 'RSO3', 'RWA3', 'RMGI',
'REY3', 'RFRN', 'RISH', 'RISI', 'RISJ', 'RBRH', 'RBRI', 'RRNH', 'RRNI',
'RGPH', 'RGPI', 'RGPJ', 'RASH', 'RASI', 'RBCH', 'RBCI', 'RVOH', 'RMGH',
- 'ROFH', 'REPH', 'REVH', 'RWOH', 'RBOH']
+ 'ROFH', 'REPH', 'REVH', 'RWOH', 'RBOH', 'RSLL']
docco_ids = {}
for thing in tree.logformat:
@@ -3366,17 +3336,19 @@ def do_timesync_roundtrip(self, quiet=False, timeout_in_wallclock=False):
self.progress("Received: %s" % str(m))
if m is None:
continue
- if m.tc1 == 0:
- self.progress("this is a timesync request, which we don't answer")
- continue
if m.ts1 % 1000 != self.mav.source_system:
self.progress("this isn't a response to our timesync (%s)" % (m.ts1 % 1000))
continue
+ if m.tc1 == 0:
+ # this should also not happen:
+ self.progress("this is a timesync request, which we don't answer")
+ continue
if int(m.ts1 / 1000) != self.timesync_number:
self.progress("this isn't the one we just sent")
continue
if m.get_srcSystem() != self.mav.target_system:
- self.progress("response from system other than our target")
+ self.progress("response from system other than our target (want=%u got=%u" %
+ (self.mav.target_system, m.get_srcSystem()))
continue
# no component check ATM because we send broadcast...
# if m.get_srcComponent() != self.mav.target_component:
@@ -3449,6 +3421,14 @@ def HIGH_LATENCY2(self):
raise NotAchievedException("Air Temperature not received from HIGH_LATENCY2")
self.HIGH_LATENCY2_links()
+ def context_set_message_rate_hz(self, id, rate_hz):
+ overridden_message_rates = self.context_get().overridden_message_rates
+
+ if id not in overridden_message_rates:
+ overridden_message_rates[id] = self.get_message_rate(id)
+
+ self.set_message_rate_hz(id, rate_hz)
+
def HIGH_LATENCY2_links(self):
self.start_subtest("SerialProtocol_MAVLinkHL links")
@@ -3463,7 +3443,7 @@ def HIGH_LATENCY2_links(self):
self.reboot_sitl()
mav2 = mavutil.mavlink_connection(
- "tcp:localhost:5763",
+ "tcp:localhost:%u" % self.adjust_ardupilot_port(5763),
robust_parsing=True,
source_system=7,
source_component=7,
@@ -3873,14 +3853,9 @@ def run_auxfunc(self,
want_result=mavutil.mavlink.MAV_RESULT_ACCEPTED):
self.run_cmd(
mavutil.mavlink.MAV_CMD_DO_AUX_FUNCTION,
- function, # p1
- level, # p2
- 0, # p3
- 0, # p4
- 0, # p5
- 0, # p6
- 0, # p7
- want_result=want_result
+ p1=function,
+ p2=level,
+ want_result=want_result,
)
def assert_mission_count(self, expected):
@@ -3950,13 +3925,27 @@ def message_has_field_values(self, m, fieldvalues, verbose=True, epsilon=None):
else:
equal = got == value
+ value_string = value
+ got_string = got
+ enum_name = m.fieldenums_by_name.get(fieldname, None)
+ if enum_name is not None:
+ enum = mavutil.mavlink.enums[enum_name]
+ if value not in enum:
+ raise ValueError("Expected value %s not in enum %s" % (value, enum_name))
+ if got not in enum:
+ raise ValueError("Received value %s not in enum %s" % (value, enum_name))
+ value_string = "%s (%s)" % (value, enum[value].name)
+ got_string = "%s (%s)" % (got, enum[got].name)
+
if not equal:
+ # see if this is an enumerated field:
+ self.progress(self.dump_message_verbose(m))
self.progress("Expected %s.%s to be %s, got %s" %
- (m.get_type(), fieldname, value, got))
+ (m.get_type(), fieldname, value_string, got_string))
return False
if verbose:
self.progress("%s.%s has expected value %s" %
- (m.get_type(), fieldname, value))
+ (m.get_type(), fieldname, value_string))
return True
def assert_message_field_values(self, m, fieldvalues, verbose=True, epsilon=None):
@@ -3964,7 +3953,16 @@ def assert_message_field_values(self, m, fieldvalues, verbose=True, epsilon=None
return
raise NotAchievedException("Did not get expected field values")
- def assert_received_message_field_values(self, message, fieldvalues, verbose=True, very_verbose=False, epsilon=None):
+ def assert_cached_message_field_values(self, message, fieldvalues, verbose=True, very_verbose=False, epsilon=None):
+ '''checks the most-recently received instance of message to ensure it
+ has the correct field values'''
+ m = self.get_cached_message(message)
+ self.assert_message_field_values(m, fieldvalues, verbose=verbose, epsilon=epsilon)
+ return m
+
+ def assert_received_message_field_values(self, message, fieldvalues, verbose=True, very_verbose=False, epsilon=None, poll=False): # noqa
+ if poll:
+ self.poll_message(message)
m = self.assert_receive_message(message, verbose=verbose, very_verbose=very_verbose)
self.assert_message_field_values(m, fieldvalues, verbose=verbose, epsilon=epsilon)
return m
@@ -4215,6 +4213,18 @@ def install_test_script_context(self, scriptname):
self.install_test_script(scriptname)
self.context_get().installed_scripts.append(scriptname)
+ def install_test_modules_context(self):
+ '''installs test modules which will be removed when the context goes
+ away'''
+ self.install_test_modules()
+ self.context_get().installed_modules.append("test")
+
+ def install_mavlink_module_context(self):
+ '''installs mavlink module which will be removed when the context goes
+ away'''
+ self.install_mavlink_module()
+ self.context_get().installed_modules.append("mavlink")
+
def install_applet_script_context(self, scriptname):
'''installs an applet script which will be removed when the context goes
away'''
@@ -4488,16 +4498,17 @@ def load_rally(self, filename):
def load_sample_mission(self):
self.load_mission(self.sample_mission_filename())
+ def generic_mission_filepath_for_filename(self, filename):
+ return os.path.join(testdir, "Generic_Missions", filename)
+
def load_generic_mission(self, filename, strict=True):
return self.load_mission_from_filepath(
- os.path.join(testdir, "Generic_Missions"),
- filename,
+ self.generic_mission_filepath_for_filename(filename),
strict=strict)
def load_mission(self, filename, strict=True):
return self.load_mission_from_filepath(
- self.current_test_name_directory,
- filename,
+ os.path.join(testdir, self.current_test_name_directory, filename),
strict=strict)
def wp_to_mission_item_int(self, wp):
@@ -4524,40 +4535,54 @@ def wp_to_mission_item_int(self, wp):
wp.z)
return wp_int
- def mission_from_filepath(self, filepath, filename, target_system=1, target_component=1):
+ def mission_from_filepath(self, filepath, target_system=1, target_component=1):
'''returns a list of mission-item-ints from filepath'''
- self.progress("Loading mission (%s)" % filename)
- path = os.path.join(testdir, filepath, filename)
+ print("filepath: %s" % filepath)
+ self.progress("Loading mission (%s)" % os.path.basename(filepath))
wploader = mavwp.MAVWPLoader(
target_system=target_system,
target_component=target_component
)
- wploader.load(path)
+ wploader.load(filepath)
return [self.wp_to_mission_item_int(x) for x in wploader.wpoints]
+ def sitl_home_string_from_mission(self, filename):
+ '''return a string of the form "lat,lng,yaw,alt" from the home
+ location in a mission file'''
+ return "%s,%s,%s,%s" % self.get_home_tuple_from_mission(filename)
+
+ def sitl_home_string_from_mission_filepath(self, filepath):
+ '''return a string of the form "lat,lng,yaw,alt" from the home
+ location in a mission file'''
+ return "%s,%s,%s,%s" % self.get_home_tuple_from_mission_filepath(filepath)
+
def get_home_tuple_from_mission(self, filename):
'''gets item 0 from the mission file, returns a tuple suitable for
passing to customise_SITL_commandline as --home. Yaw will be
0, so the caller may want to fill that in
'''
- items = self.mission_from_filepath(
- self.current_test_name_directory,
- filename,
+ return self.get_home_tuple_from_mission_filepath(
+ os.path.join(testdir, self.current_test_name_directory, filename)
)
+
+ def get_home_tuple_from_mission_filepath(self, filepath):
+ '''gets item 0 from the mission file, returns a tuple suitable for
+ passing to customise_SITL_commandline as --home. Yaw will be
+ 0, so the caller may want to fill that in
+ '''
+ items = self.mission_from_filepath(filepath)
home_item = items[0]
return (home_item.x * 1e-7, home_item.y * 1e-7, home_item.z, 0)
# TODO: rename the following to "upload_mission_from_filepath"
def load_mission_from_filepath(self,
filepath,
- filename,
target_system=1,
target_component=1,
strict=True,
reset_current_wp=True):
wpoints_int = self.mission_from_filepath(
filepath,
- filename,
target_system=target_system,
target_component=target_component
)
@@ -4862,7 +4887,7 @@ def set_rc_from_map(self, _map, timeout=20):
def rc_thread_main(self):
chan16 = [1000] * 16
- sitl_output = mavutil.mavudp("127.0.0.1:5501", input=False)
+ sitl_output = mavutil.mavudp("127.0.0.1:%u" % self.sitl_rcin_port(), input=False)
buf = None
while True:
@@ -4981,17 +5006,23 @@ def arming_test_mission(self):
else:
return None
- def set_safetyswitch_on(self):
- self.set_safetyswitch(1)
+ def set_safetyswitch_on(self, **kwargs):
+ self.set_safetyswitch(1, **kwargs)
- def set_safetyswitch_off(self):
- self.set_safetyswitch(0)
+ def set_safetyswitch_off(self, **kwargs):
+ self.set_safetyswitch(0, **kwargs)
def set_safetyswitch(self, value, target_system=1, target_component=1):
self.mav.mav.set_mode_send(
target_system,
mavutil.mavlink.MAV_MODE_FLAG_DECODE_POSITION_SAFETY,
value)
+ self.wait_sensor_state(
+ mavutil.mavlink.MAV_SYS_STATUS_SENSOR_MOTOR_OUTPUTS,
+ True, not value, True,
+ verbose=True,
+ timeout=30
+ )
def armed(self):
"""Return true if vehicle is armed and safetyoff"""
@@ -4999,36 +5030,13 @@ def armed(self):
return self.mav.motors_armed()
def send_mavlink_arm_command(self):
- target_sysid = 1
- target_compid = 1
- self.mav.mav.command_long_send(
- target_sysid,
- target_compid,
+ self.send_cmd(
mavutil.mavlink.MAV_CMD_COMPONENT_ARM_DISARM,
- 1, # confirmation
- 1, # ARM
- 0,
- 0,
- 0,
- 0,
- 0,
- 0)
+ p1=1, # ARM
+ )
def send_mavlink_run_prearms_command(self):
- target_sysid = 1
- target_compid = 1
- self.mav.mav.command_long_send(
- target_sysid,
- target_compid,
- mavutil.mavlink.MAV_CMD_RUN_PREARM_CHECKS,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0)
+ self.send_cmd(mavutil.mavlink.MAV_CMD_RUN_PREARM_CHECKS)
def analog_rangefinder_parameters(self):
return {
@@ -5044,43 +5052,29 @@ def set_analog_rangefinder_parameters(self):
def send_debug_trap(self, timeout=6000):
self.progress("Sending trap to autopilot")
- self.run_cmd(mavutil.mavlink.MAV_CMD_DEBUG_TRAP,
- 32451, # magic number to trap
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- timeout=timeout)
+ self.run_cmd(
+ mavutil.mavlink.MAV_CMD_DEBUG_TRAP,
+ p1=32451, # magic number to trap
+ timeout=timeout,
+ )
def try_arm(self, result=True, expect_msg=None, timeout=60):
"""Send Arming command, wait for the expected result and statustext."""
self.progress("Try arming and wait for expected result")
self.drain_mav()
- self.run_cmd(mavutil.mavlink.MAV_CMD_COMPONENT_ARM_DISARM,
- 1, # ARM
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- want_result=mavutil.mavlink.MAV_RESULT_ACCEPTED if result else mavutil.mavlink.MAV_RESULT_FAILED,
- timeout=timeout)
+ self.run_cmd(
+ mavutil.mavlink.MAV_CMD_COMPONENT_ARM_DISARM,
+ p1=1, # ARM
+ want_result=mavutil.mavlink.MAV_RESULT_ACCEPTED if result else mavutil.mavlink.MAV_RESULT_FAILED,
+ timeout=timeout,
+ )
if expect_msg is not None:
self.wait_statustext(
expect_msg,
timeout=timeout,
the_function=lambda: self.send_cmd(
mavutil.mavlink.MAV_CMD_COMPONENT_ARM_DISARM,
- 1, # ARM
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
+ p1=1, # ARM
target_sysid=None,
target_compid=None,
))
@@ -5092,15 +5086,12 @@ def arm_vehicle(self, timeout=20, force=False):
if force:
p2 = 2989
try:
- self.run_cmd(mavutil.mavlink.MAV_CMD_COMPONENT_ARM_DISARM,
- 1, # ARM
- p2,
- 0,
- 0,
- 0,
- 0,
- 0,
- timeout=timeout)
+ self.run_cmd(
+ mavutil.mavlink.MAV_CMD_COMPONENT_ARM_DISARM,
+ p1=1, # ARM
+ p2=p2,
+ timeout=timeout,
+ )
except ValueError as e:
# statustexts are queued; give it a second to arrive:
self.delay_sim_time(5)
@@ -5126,30 +5117,23 @@ def disarm_vehicle(self, timeout=60, force=False):
p2 = 0
if force:
p2 = 21196 # magic force disarm value
- self.run_cmd(mavutil.mavlink.MAV_CMD_COMPONENT_ARM_DISARM,
- 0, # DISARM
- p2,
- 0,
- 0,
- 0,
- 0,
- 0,
- timeout=timeout)
+ self.run_cmd(
+ mavutil.mavlink.MAV_CMD_COMPONENT_ARM_DISARM,
+ p1=0, # DISARM
+ p2=p2,
+ timeout=timeout,
+ )
self.wait_disarmed()
def disarm_vehicle_expect_fail(self):
'''disarm, checking first that non-forced disarm fails, then doing a forced disarm'''
self.progress("Disarm - expect to fail")
- self.run_cmd(mavutil.mavlink.MAV_CMD_COMPONENT_ARM_DISARM,
- 0, # DISARM
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- timeout=10,
- want_result=mavutil.mavlink.MAV_RESULT_FAILED)
+ self.run_cmd(
+ mavutil.mavlink.MAV_CMD_COMPONENT_ARM_DISARM,
+ p1=0, # DISARM
+ timeout=10,
+ want_result=mavutil.mavlink.MAV_RESULT_FAILED,
+ )
self.progress("Disarm - forced")
self.disarm_vehicle(force=True)
@@ -5639,7 +5623,7 @@ def context_stop_collecting(self, msg_type):
del context.collections[msg_type]
return ret
- def context_pop(self):
+ def context_pop(self, process_interaction_allowed=True):
"""Set parameters to origin values in reverse order."""
dead = self.contexts.pop()
# remove hooks first; these hooks can raise exceptions which
@@ -5648,13 +5632,19 @@ def context_pop(self):
self.remove_message_hook(hook)
for script in dead.installed_scripts:
self.remove_installed_script(script)
+ for (message_id, interval_us) in dead.overridden_message_rates.items():
+ self.set_message_interval(message_id, interval_us)
+ for module in dead.installed_modules:
+ print("Removing module (%s)" % module)
+ self.remove_installed_modules(module)
if dead.sitl_commandline_customised and len(self.contexts):
self.contexts[-1].sitl_commandline_customised = True
dead_parameters_dict = {}
for p in dead.parameters:
dead_parameters_dict[p[0]] = p[1]
- self.set_parameters(dead_parameters_dict, add_to_context=False)
+ if process_interaction_allowed:
+ self.set_parameters(dead_parameters_dict, add_to_context=False)
if getattr(self, "old_binary", None) is not None:
self.stop_SITL()
@@ -5699,18 +5689,29 @@ def sysid_thismav(self):
def run_cmd_int(self,
command,
- p1,
- p2,
- p3,
- p4,
- x,
- y,
- z,
+ p1=0,
+ p2=0,
+ p3=0,
+ p4=0,
+ x=0,
+ y=0,
+ z=0,
want_result=mavutil.mavlink.MAV_RESULT_ACCEPTED,
timeout=10,
target_sysid=None,
target_compid=None,
- frame=mavutil.mavlink.MAV_FRAME_GLOBAL_INT):
+ frame=mavutil.mavlink.MAV_FRAME_GLOBAL_INT,
+ p5=None,
+ p6=None,
+ p7=None,
+ ):
+
+ if p5 is not None:
+ x = p5
+ if p6 is not None:
+ y = p6
+ if p7 is not None:
+ z = p7
if target_sysid is None:
target_sysid = self.sysid_thismav()
@@ -5737,13 +5738,13 @@ def run_cmd_int(self,
def send_cmd(self,
command,
- p1,
- p2,
- p3,
- p4,
- p5,
- p6,
- p7,
+ p1=0,
+ p2=0,
+ p3=0,
+ p4=0,
+ p5=0,
+ p6=0,
+ p7=0,
target_sysid=None,
target_compid=None,
mav=None,
@@ -5787,13 +5788,13 @@ def send_cmd(self,
def run_cmd(self,
command,
- p1,
- p2,
- p3,
- p4,
- p5,
- p6,
- p7,
+ p1=0,
+ p2=0,
+ p3=0,
+ p4=0,
+ p5=0,
+ p6=0,
+ p7=0,
want_result=mavutil.mavlink.MAV_RESULT_ACCEPTED,
target_sysid=None,
target_compid=None,
@@ -5854,13 +5855,7 @@ def set_current_waypoint_using_mav_cmd_do_set_mission_current(
target_sysid=1,
target_compid=1):
self.run_cmd(mavutil.mavlink.MAV_CMD_DO_SET_MISSION_CURRENT,
- seq,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
+ p1=seq,
timeout=1,
target_sysid=target_sysid,
target_compid=target_compid)
@@ -5993,13 +5988,8 @@ def get_bearing(loc1, loc2):
def send_cmd_do_set_mode(self, mode):
self.send_cmd(
mavutil.mavlink.MAV_CMD_DO_SET_MODE,
- mavutil.mavlink.MAV_MODE_FLAG_CUSTOM_MODE_ENABLED,
- self.get_mode_from_mode_mapping(mode),
- 0,
- 0,
- 0,
- 0,
- 0
+ p1=mavutil.mavlink.MAV_MODE_FLAG_CUSTOM_MODE_ENABLED,
+ p2=self.get_mode_from_mode_mapping(mode),
)
def assert_mode(self, mode):
@@ -6080,15 +6070,10 @@ def run_cmd_do_set_mode(self,
custom_mode = self.get_mode_from_mode_mapping(mode)
self.run_cmd(
mavutil.mavlink.MAV_CMD_DO_SET_MODE,
- base_mode,
- custom_mode,
- 0,
- 0,
- 0,
- 0,
- 0,
+ p1=base_mode,
+ p2=custom_mode,
want_result=want_result,
- timeout=timeout
+ timeout=timeout,
)
def do_set_mode_via_command_long(self, mode, timeout=30):
@@ -6180,13 +6165,10 @@ def guided_achieve_heading(self, heading, accuracy=None):
raise NotAchievedException("Did not achieve heading")
self.run_cmd(
mavutil.mavlink.MAV_CMD_CONDITION_YAW,
- heading, # target angle
- 10, # degrees/second
- 1, # -1 is counter-clockwise, 1 clockwise
- 0, # 1 for relative, 0 for absolute
- 0, # p5
- 0, # p6
- 0, # p7
+ p1=heading, # target angle
+ p2=10, # degrees/second
+ p3=1, # -1 is counter-clockwise, 1 clockwise
+ p4=0, # 1 for relative, 0 for absolute
)
m = self.mav.recv_match(type='VFR_HUD', blocking=True)
self.progress("heading=%d want=%d" % (m.heading, int(heading)))
@@ -6207,15 +6189,12 @@ def assert_heading(self, heading, accuracy=1):
def do_set_relay(self, relay_num, on_off, timeout=10):
"""Set relay with a command long message."""
self.progress("Set relay %d to %d" % (relay_num, on_off))
- self.run_cmd(mavutil.mavlink.MAV_CMD_DO_SET_RELAY,
- relay_num,
- on_off,
- 0,
- 0,
- 0,
- 0,
- 0,
- timeout=timeout)
+ self.run_cmd(
+ mavutil.mavlink.MAV_CMD_DO_SET_RELAY,
+ p1=relay_num,
+ p2=on_off,
+ timeout=timeout,
+ )
def do_set_relay_mavproxy(self, relay_num, on_off):
"""Set relay with mavproxy."""
@@ -6229,15 +6208,11 @@ def do_fence_en_or_dis_able(self, value, want_result=mavutil.mavlink.MAV_RESULT_
p1 = 1
else:
p1 = 0
- self.run_cmd(mavutil.mavlink.MAV_CMD_DO_FENCE_ENABLE,
- p1, # param1
- 0, # param2
- 0, # param3
- 0, # param4
- 0, # param5
- 0, # param6
- 0, # param7
- want_result=want_result)
+ self.run_cmd(
+ mavutil.mavlink.MAV_CMD_DO_FENCE_ENABLE,
+ p1=p1, # param1
+ want_result=want_result,
+ )
def do_fence_enable(self, want_result=mavutil.mavlink.MAV_RESULT_ACCEPTED):
self.do_fence_en_or_dis_able(True, want_result=want_result)
@@ -6771,7 +6746,7 @@ def get_speed_vector(self, timeout=1):
return Vector3(msg.vx, msg.vy, msg.vz)
"""Wait for a given speed vector."""
- def wait_speed_vector(self, speed_vector, accuracy=0.2, timeout=30, **kwargs):
+ def wait_speed_vector(self, speed_vector, accuracy=0.3, timeout=30, **kwargs):
def validator(value2, target2):
return (math.fabs(value2.x - target2.x) <= accuracy and
math.fabs(value2.y - target2.y) <= accuracy and
@@ -7184,6 +7159,10 @@ def wait_waypoint(self,
raise WaitWaypointTimeout("Timed out waiting for waypoint %u of %u" %
(wpnum_end, wpnum_end))
+ def get_cached_message(self, message_type):
+ '''returns the most-recently received instance of message_type'''
+ return self.mav.messages[message_type]
+
def mode_is(self, mode, cached=False, drain_mav=True):
if not cached:
self.wait_heartbeat(drain_mav=drain_mav)
@@ -7207,6 +7186,10 @@ def wait_mode(self, mode, timeout=60):
raise WaitModeTimeout("Did not change mode")
self.progress("Got mode %s" % mode)
+ def assert_mode_is(self, mode):
+ if not self.mode_is(mode):
+ raise NotAchievedException("Expected mode %s" % str(mode))
+
def wait_gps_sys_status_not_present_or_enabled_and_healthy(self, timeout=30):
self.progress("Waiting for GPS health")
tstart = self.get_sim_time_cached()
@@ -7309,6 +7292,19 @@ def assert_fence_disabled(self, timeout=2):
# Check fence is not enabled
self.assert_not_receiving_message('FENCE_STATUS', timeout=timeout)
+ def NoArmWithoutMissionItems(self):
+ '''ensure we can't arm in auto mode without mission items present'''
+ # load a trivial mission
+ items = []
+ items.append((mavutil.mavlink.MAV_CMD_NAV_WAYPOINT, 1000, 0, 20000),)
+ items.append((mavutil.mavlink.MAV_CMD_NAV_RETURN_TO_LAUNCH, 0, 0, 0))
+ self.upload_simple_relhome_mission(items)
+
+ self.change_mode('AUTO')
+ self.clear_mission(mavutil.mavlink.MAV_MISSION_TYPE_ALL)
+ self.assert_prearm_failure('Mode requires mission',
+ other_prearm_failures_fatal=False)
+
def assert_prearm_failure(self,
expected_statustext,
timeout=5,
@@ -7453,6 +7449,7 @@ def wait_ekf_flags(self, required_value, error_bits, timeout=30):
self.progress("Waiting for EKF value %u" % required_value)
last_print_time = 0
tstart = self.get_sim_time()
+ m = None
while timeout is None or self.get_sim_time_cached() < tstart + timeout:
m = self.mav.recv_match(type='EKF_STATUS_REPORT', blocking=True, timeout=timeout)
if m is None:
@@ -7468,6 +7465,11 @@ def wait_ekf_flags(self, required_value, error_bits, timeout=30):
if everything_ok:
self.progress("EKF Flags OK")
return True
+ m_str = str(m)
+ if m is not None:
+ m_str = self.dump_message_verbose(m)
+ self.progress("Last EKF_STATUS_REPORT message:")
+ self.progress(m_str)
raise AutoTestTimeoutException("Failed to get EKF.flags=%u" %
required_value)
@@ -7606,6 +7608,19 @@ def install_script(self, source, scriptname, install_name=None):
self.progress("Copying (%s) to (%s)" % (source, dest))
shutil.copy(source, dest)
+ def install_test_modules(self):
+ source = os.path.join(self.rootdir(), "libraries", "AP_Scripting", "tests", "modules", "test")
+ dest = os.path.join("scripts", "modules", "test")
+ self.progress("Copying (%s) to (%s)" % (source, dest))
+ shutil.copytree(source, dest)
+
+ def install_mavlink_module(self):
+ dest = os.path.join("scripts", "modules", "mavlink")
+ ardupilotmega_xml = os.path.join(self.rootdir(), "modules", "mavlink",
+ "message_definitions", "v1.0", "ardupilotmega.xml")
+ mavgen.mavgen(mavgen.Opts(output=dest, wire_protocol='2.0', language='Lua'), [ardupilotmega_xml])
+ self.progress("Installed mavlink module")
+
def install_example_script(self, scriptname):
source = self.script_example_source_path(scriptname)
self.install_script(source, scriptname)
@@ -7627,6 +7642,15 @@ def remove_installed_script(self, scriptname):
except OSError:
pass
+ def remove_installed_modules(self, modulename):
+ dest = os.path.join("scripts", "modules", modulename)
+ try:
+ shutil.rmtree(dest)
+ except IOError:
+ pass
+ except OSError:
+ pass
+
def get_mavlink_connection_going(self):
# get a mavlink connection going
try:
@@ -7650,6 +7674,10 @@ def get_mavlink_connection_going(self):
self.mav.mav.set_send_callback(self.send_message_hook, self)
self.mav.idle_hooks.append(self.idle_hook)
+ # we need to wait for a heartbeat here. If we don't then
+ # self.mav.target_system will be zero because it hasn't
+ # "locked on" to a target system yet.
+ self.wait_heartbeat()
self.set_streamrate(self.sitl_streamrate())
def show_test_timings_key_sorter(self, t):
@@ -7737,14 +7765,14 @@ def check_logs(self, name):
util.run_cmd('/bin/cp build/sitl/bin/* %s' % to_dir,
directory=util.reltopdir('.'))
- def run_one_test(self, test, interact=False):
+ def run_one_test(self, test, interact=False, suppress_stdout=False):
'''new-style run-one-test used by run_tests'''
for i in range(0, test.attempts-1):
- result = self.run_one_test_attempt(test, interact=interact, attempt=i+2)
+ result = self.run_one_test_attempt(test, interact=interact, attempt=i+2, suppress_stdout=suppress_stdout)
if result.passed:
return result
self.progress("Run attempt failed. Retrying")
- return self.run_one_test_attempt(test, interact=interact, attempt=1)
+ return self.run_one_test_attempt(test, interact=interact, attempt=1, suppress_stdout=suppress_stdout)
def print_exception_caught(self, e, send_statustext=True):
self.progress("Exception caught: %s" %
@@ -7761,7 +7789,31 @@ def progress_file_content(self, filepath):
for line in f:
self.progress(line.rstrip())
- def run_one_test_attempt(self, test, interact=False, attempt=1):
+ def dump_process_status(self, result):
+ '''used to show where the SITL process is upto. Often caused when
+ we've lost contact'''
+
+ if self.sitl.isalive():
+ self.progress("pexpect says it is alive")
+ for tool in "dumpstack.sh", "dumpcore.sh":
+ tool_filepath = os.path.join(self.rootdir(), 'Tools', 'scripts', tool)
+ if util.run_cmd([tool_filepath, str(self.sitl.pid)]) != 0:
+ reason = "Failed %s" % (tool,)
+ self.progress(reason)
+ result.reason = reason
+ result.passed = False
+ else:
+ self.progress("pexpect says it is dead")
+
+ # try dumping the process status file for more information:
+ status_filepath = "/proc/%u/status" % self.sitl.pid
+ self.progress("Checking for status filepath (%s)" % status_filepath)
+ if os.path.exists(status_filepath):
+ self.progress_file_content(status_filepath)
+ else:
+ self.progress("... does not exist")
+
+ def run_one_test_attempt(self, test, interact=False, attempt=1, suppress_stdout=False):
'''called by run_one_test to actually run the test in a retry loop'''
name = test.name
desc = test.description
@@ -7774,7 +7826,7 @@ def run_one_test_attempt(self, test, interact=False, attempt=1):
test_output_filename = self.buildlogs_path("%s-%s.txt" %
(self.log_name(), name))
- tee = TeeBoth(test_output_filename, 'w', self.mavproxy_logfile)
+ tee = TeeBoth(test_output_filename, 'w', self.mavproxy_logfile, suppress_stdout=suppress_stdout)
start_message_hooks = self.mav.message_hooks
@@ -7821,12 +7873,6 @@ def run_one_test_attempt(self, test, interact=False, attempt=1):
if ex is not None:
passed = False
- try:
- self.context_pop()
- except Exception as e:
- self.print_exception_caught(e, send_statustext=False)
- passed = False
-
result = Result(test)
ardupilot_alive = False
@@ -7836,29 +7882,17 @@ def run_one_test_attempt(self, test, interact=False, attempt=1):
except Exception:
# process is dead
self.progress("No heartbeat after test", send_statustext=False)
- if self.sitl.isalive():
- self.progress("pexpect says it is alive")
- for tool in "dumpstack.sh", "dumpcore.sh":
- tool_filepath = os.path.join(self.rootdir(), 'Tools', 'scripts', tool)
- if util.run_cmd([tool_filepath, str(self.sitl.pid)]) != 0:
- self.progress("Failed %s" % (tool,))
- result.description
- result.passed = False
- return result
- else:
- self.progress("pexpect says it is dead")
-
- # try dumping the process status file for more information:
- status_filepath = "/proc/%u/status" % self.sitl.pid
- self.progress("Checking for status filepath (%s)" % status_filepath)
- if os.path.exists(status_filepath):
- self.progress_file_content(status_filepath)
- else:
- self.progress("... does not exist")
+ self.dump_process_status(result)
passed = False
reset_needed = True
+ try:
+ self.context_pop(process_interaction_allowed=ardupilot_alive)
+ except Exception as e:
+ self.print_exception_caught(e, send_statustext=False)
+ passed = False
+
# if we haven't already reset ArduPilot because it's dead,
# then ensure the vehicle was disarmed at the end of the test.
# If it wasn't then the test is considered failed:
@@ -7878,7 +7912,7 @@ def run_one_test_attempt(self, test, interact=False, attempt=1):
self.progress("Force-rebooting SITL")
self.reboot_sitl() # that'll learn it
passed = False
- elif not passed: # implicit reboot after a failed test:
+ elif ardupilot_alive and not passed: # implicit reboot after a failed test:
self.progress("Test failed but ArduPilot process alive; rebooting")
self.reboot_sitl() # that'll learn it
@@ -7906,7 +7940,7 @@ def run_one_test_attempt(self, test, interact=False, attempt=1):
# pop off old contexts to clean up message hooks etc
while len(self.contexts) > old_contexts_length:
try:
- self.context_pop()
+ self.context_pop(process_interaction_allowed=ardupilot_alive)
except Exception as e:
self.print_exception_caught(e, send_statustext=False)
self.progress("Done popping extra contexts")
@@ -7954,7 +7988,7 @@ def run_one_test_attempt(self, test, interact=False, attempt=1):
def defaults_filepath(self):
return None
- def start_mavproxy(self):
+ def start_mavproxy(self, sitl_rcin_port=None):
self.start_mavproxy_count += 1
if self.mavproxy is not None:
return self.mavproxy
@@ -7966,11 +8000,17 @@ def start_mavproxy(self):
if self.valgrind or self.callgrind:
pexpect_timeout *= 10
+ if sitl_rcin_port is None:
+ sitl_rcin_port = self.sitl_rcin_port()
+
mavproxy = util.start_MAVProxy_SITL(
self.vehicleinfo_key(),
+ master='tcp:127.0.0.1:%u' % self.adjust_ardupilot_port(5762),
logfile=self.mavproxy_logfile,
options=self.mavproxy_options(),
- pexpect_timeout=pexpect_timeout)
+ pexpect_timeout=pexpect_timeout,
+ sitl_rcin_port=sitl_rcin_port,
+ )
mavproxy.expect(r'Telemetry log: (\S+)\r\n')
self.logfile = mavproxy.match.group(1)
self.progress("LOGFILE %s" % self.logfile)
@@ -7989,7 +8029,9 @@ def stop_mavproxy(self, mavproxy):
util.pexpect_close(mavproxy)
self._mavproxy = None
- def start_SITL(self, binary=None, **sitl_args):
+ def start_SITL(self, binary=None, sitl_home=None, **sitl_args):
+ if sitl_home is None:
+ sitl_home = self.sitl_home()
start_sitl_args = {
"breakpoints": self.breakpoints,
"disable_breakpoints": self.disable_breakpoints,
@@ -7997,7 +8039,7 @@ def start_SITL(self, binary=None, **sitl_args):
"gdb_no_tui": self.gdb_no_tui,
"gdbserver": self.gdbserver,
"lldb": self.lldb,
- "home": self.sitl_home(),
+ "home": sitl_home,
"speedup": self.speedup,
"valgrind": self.valgrind,
"callgrind": self.callgrind,
@@ -8016,15 +8058,24 @@ def start_SITL(self, binary=None, **sitl_args):
self.sitl = util.start_SITL(binary, **start_sitl_args)
self.expect_list_add(self.sitl)
self.sup_prog = []
+ count = 0
for sup_binary in self.sup_binaries:
self.progress("Starting Supplementary Program ", sup_binary)
- start_sitl_args["customisations"] = [sup_binary[1]]
+ start_sitl_args["customisations"] = [sup_binary['customisation']]
start_sitl_args["supplementary"] = True
- sup_prog_link = util.start_SITL(sup_binary[0], **start_sitl_args)
+ start_sitl_args["stdout_prefix"] = "%s-%u" % (os.path.basename(sup_binary['binary']), count)
+ start_sitl_args["defaults_filepath"] = sup_binary['param_file']
+ sup_prog_link = util.start_SITL(sup_binary['binary'], **start_sitl_args)
self.sup_prog.append(sup_prog_link)
self.expect_list_add(sup_prog_link)
+ count += 1
+
+ # mavlink will have disconnected here. Explicitly reconnect,
+ # or the first packet we send will be lost:
+ if self.mav is not None:
+ self.mav.reconnect()
- def get_suplementary_programs(self):
+ def get_supplementary_programs(self):
return self.sup_prog
def stop_sup_program(self, instance=None):
@@ -8057,23 +8108,18 @@ def start_sup_program(self, instance=None, args=None):
"callgrind": self.callgrind,
"wipe": True,
}
- if instance is None:
- for sup_binary in self.sup_binaries:
- start_sitl_args["customisations"] = [sup_binary[1]]
- if args is not None:
- start_sitl_args["customisations"] = [sup_binary[1], args]
- start_sitl_args["supplementary"] = True
- sup_prog_link = util.start_SITL(sup_binary[0], **start_sitl_args)
- self.sup_prog.append(sup_prog_link) # add to list
- self.expect_list_add(sup_prog_link) # add to expect list
- else:
- # start only the instance passed
- start_sitl_args["customisations"] = [self.sup_binaries[instance][1]]
+ for i in range(len(self.sup_binaries)):
+ if instance is not None and instance != i:
+ continue
+ sup_binary = self.sup_binaries[i]
+ start_sitl_args["customisations"] = [sup_binary['customisation']]
if args is not None:
- start_sitl_args["customisations"] = [self.sup_binaries[instance][1], args]
+ start_sitl_args["customisations"] = [sup_binary['customisation'], args]
start_sitl_args["supplementary"] = True
- sup_prog_link = util.start_SITL(self.sup_binaries[instance][0], **start_sitl_args)
- self.sup_prog[instance] = sup_prog_link # add to list
+ start_sitl_args["defaults_filepath"] = sup_binary['param_file']
+ sup_prog_link = util.start_SITL(sup_binary['binary'], **start_sitl_args)
+ time.sleep(1)
+ self.sup_prog[i] = sup_prog_link # add to list
self.expect_list_add(sup_prog_link) # add to expect list
def sitl_is_running(self):
@@ -8293,14 +8339,8 @@ def poll_home_position(self, quiet=True, timeout=30):
try:
self.run_cmd(
mavutil.mavlink.MAV_CMD_GET_HOME_POSITION,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- quiet=quiet)
+ quiet=quiet,
+ )
except ValueError:
continue
m = self.mav.messages.get("HOME_POSITION", None)
@@ -8384,11 +8424,11 @@ def SetHome(self):
start_loc = self.sitl_start_location()
self.progress("SITL start loc: %s" % str(start_loc))
delta = abs(orig_home.latitude * 1.0e-7 - start_loc.lat)
- if delta > 0.000001:
+ if delta > 0.000006:
raise ValueError("homes differ in lat got=%f vs want=%f delta=%f" %
(orig_home.latitude * 1.0e-7, start_loc.lat, delta))
delta = abs(orig_home.longitude * 1.0e-7 - start_loc.lng)
- if delta > 0.000001:
+ if delta > 0.000006:
raise ValueError("homes differ in lon got=%f vs want=%f delta=%f" %
(orig_home.longitude * 1.0e-7, start_loc.lng, delta))
if self.is_rover():
@@ -8402,15 +8442,12 @@ def SetHome(self):
new_y = orig_home.longitude + 2000
new_z = orig_home.altitude + 300000 # 300 metres
print("new home: %s %s %s" % (str(new_x), str(new_y), str(new_z)))
- self.run_cmd_int(mavutil.mavlink.MAV_CMD_DO_SET_HOME,
- 0, # p1,
- 0, # p2,
- 0, # p3,
- 0, # p4,
- new_x,
- new_y,
- new_z/1000.0, # mm => m
- )
+ self.run_cmd_int(
+ mavutil.mavlink.MAV_CMD_DO_SET_HOME,
+ p5=new_x,
+ p6=new_y,
+ p7=new_z/1000.0, # mm => m
+ )
home = self.poll_home_position()
self.progress("home: %s" % str(home))
@@ -8440,43 +8477,35 @@ def SetHome(self):
self.progress("Waiting for EKF to start")
self.wait_ready_to_arm()
self.progress("now use lat=0, lon=0 to reset home to current location")
- self.run_cmd_int(mavutil.mavlink.MAV_CMD_DO_SET_HOME,
- 0, # p1,
- 0, # p2,
- 0, # p3,
- 0, # p4,
- 0, # lat
- 0, # lon
- new_z/1000.0, # mm => m
- )
+ self.run_cmd_int(
+ mavutil.mavlink.MAV_CMD_DO_SET_HOME,
+ p5=0, # lat
+ p6=0, # lon
+ p7=new_z/1000.0, # mm => m
+ )
home = self.poll_home_position()
self.progress("home: %s" % str(home))
if self.distance_to_home(use_cached_home=True) > 1:
raise NotAchievedException("Setting home to current location did not work")
self.progress("Setting home elsewhere again")
- self.run_cmd_int(mavutil.mavlink.MAV_CMD_DO_SET_HOME,
- 0, # p1,
- 0, # p2,
- 0, # p3,
- 0, # p4,
- new_x,
- new_y,
- new_z/1000.0, # mm => m
- )
+ self.run_cmd_int(
+ mavutil.mavlink.MAV_CMD_DO_SET_HOME,
+ p5=new_x,
+ p6=new_y,
+ p7=new_z/1000.0, # mm => m
+ )
if self.distance_to_home() < 10:
raise NotAchievedException("Setting home to location did not work")
self.progress("use param1=1 to reset home to current location")
- self.run_cmd_int(mavutil.mavlink.MAV_CMD_DO_SET_HOME,
- 1, # p1,
- 0, # p2,
- 0, # p3,
- 0, # p4,
- 37, # lat
- 21, # lon
- new_z/1000.0, # mm => m
- )
+ self.run_cmd_int(
+ mavutil.mavlink.MAV_CMD_DO_SET_HOME,
+ p1=1, # use current location
+ p5=37, # lat
+ p6=21, # lon
+ p7=new_z/1000.0, # mm => m
+ )
home = self.poll_home_position()
self.progress("home: %s" % str(home))
if self.distance_to_home() > 1:
@@ -8490,33 +8519,18 @@ def SetHome(self):
def zero_mag_offset_parameters(self, compass_count=3):
self.progress("Zeroing Mag OFS parameters")
self.get_sim_time()
- self.run_cmd(mavutil.mavlink.MAV_CMD_PREFLIGHT_SET_SENSOR_OFFSETS,
- 2, # param1 (compass0)
- 0, # param2
- 0, # param3
- 0, # param4
- 0, # param5
- 0, # param6
- 0 # param7
- )
- self.run_cmd(mavutil.mavlink.MAV_CMD_PREFLIGHT_SET_SENSOR_OFFSETS,
- 5, # param1 (compass1)
- 0, # param2
- 0, # param3
- 0, # param4
- 0, # param5
- 0, # param6
- 0 # param7
- )
- self.run_cmd(mavutil.mavlink.MAV_CMD_PREFLIGHT_SET_SENSOR_OFFSETS,
- 6, # param1 (compass2)
- 0, # param2
- 0, # param3
- 0, # param4
- 0, # param5
- 0, # param6
- 0 # param7
- )
+ self.run_cmd(
+ mavutil.mavlink.MAV_CMD_PREFLIGHT_SET_SENSOR_OFFSETS,
+ p1=2, # param1 (compass0)
+ )
+ self.run_cmd(
+ mavutil.mavlink.MAV_CMD_PREFLIGHT_SET_SENSOR_OFFSETS,
+ p1=5, # param1 (compass1)
+ )
+ self.run_cmd(
+ mavutil.mavlink.MAV_CMD_PREFLIGHT_SET_SENSOR_OFFSETS,
+ p1=6, # param1 (compass2)
+ )
self.progress("zeroed mag parameters")
params = [
[("SIM_MAG1_OFS1_X", "COMPASS_OFS_X", 0),
@@ -8600,17 +8614,15 @@ def reset_pos_and_start_magcal(mavproxy, tmask):
mavproxy.send("sitl_stop\n")
mavproxy.send("sitl_attitude 0 0 0\n")
self.get_sim_time()
- self.run_cmd(mavutil.mavlink.MAV_CMD_DO_START_MAG_CAL,
- tmask, # p1: mag_mask
- 0, # p2: retry
- 0, # p3: autosave
- 0, # p4: delay
- 0, # param5
- 0, # param6
- 0, # param7
- want_result=mavutil.mavlink.MAV_RESULT_ACCEPTED,
- timeout=20,
- )
+ self.run_cmd(
+ mavutil.mavlink.MAV_CMD_DO_START_MAG_CAL,
+ p1=tmask, # p1: mag_mask
+ p2=0, # retry
+ p3=0, # autosave
+ p4=0, # delay
+ want_result=mavutil.mavlink.MAV_RESULT_ACCEPTED,
+ timeout=20,
+ )
mavproxy.send("sitl_magcal\n")
def do_prep_mag_cal_test(mavproxy, params):
@@ -8718,29 +8730,19 @@ def do_test_mag_cal(mavproxy, params, compass_tnumber):
self.progress("Calibration progress compass ID %d: %s%%" % (cid, str(reached_pct[cid])))
if cid == 0 and 13 <= reached_pct[0] <= 15:
self.progress("Request again to start calibration, it shouldn't restart from 0")
- self.run_cmd(mavutil.mavlink.MAV_CMD_DO_START_MAG_CAL,
- target_mask,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- want_result=mavutil.mavlink.MAV_RESULT_ACCEPTED,
- timeout=20,
- )
+ self.run_cmd(
+ mavutil.mavlink.MAV_CMD_DO_START_MAG_CAL,
+ p1=target_mask,
+ want_result=mavutil.mavlink.MAV_RESULT_ACCEPTED,
+ timeout=20,
+ )
if reached_pct[0] > 30:
- self.run_cmd(mavutil.mavlink.MAV_CMD_DO_CANCEL_MAG_CAL,
- target_mask, # p1: mag_mask
- 0, # param2
- 0, # param3
- 0, # param4
- 0, # param5
- 0, # param6
- 0, # param7
- want_result=mavutil.mavlink.MAV_RESULT_ACCEPTED,
- )
+ self.run_cmd(
+ mavutil.mavlink.MAV_CMD_DO_CANCEL_MAG_CAL,
+ p1=target_mask,
+ want_result=mavutil.mavlink.MAV_RESULT_ACCEPTED,
+ )
if tstop is None:
tstop = self.get_sim_time_cached()
if tstop is not None:
@@ -8836,17 +8838,12 @@ def do_test_mag_cal(mavproxy, params, compass_tnumber):
self.check_zeros_mag_orient()
self.progress("Send acceptation and check value")
self.wait_heartbeat()
- self.run_cmd(mavutil.mavlink.MAV_CMD_DO_ACCEPT_MAG_CAL,
- target_mask, # p1: mag_mask
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- want_result=mavutil.mavlink.MAV_RESULT_ACCEPTED,
- timeout=20,
- )
+ self.run_cmd(
+ mavutil.mavlink.MAV_CMD_DO_ACCEPT_MAG_CAL,
+ p1=target_mask, # p1: mag_mask
+ want_result=mavutil.mavlink.MAV_RESULT_ACCEPTED,
+ timeout=20,
+ )
self.check_mag_parameters(params, compass_tnumber)
self.verify_parameter_values({"COMPASS_ORIENT": self.get_parameter("SIM_MAG1_ORIENT")})
for count in range(2, compass_tnumber + 1):
@@ -8868,17 +8865,15 @@ def do_test_mag_cal(mavproxy, params, compass_tnumber):
self.set_parameter("COMPASS_ORIENT%d" % count, self.get_parameter("SIM_MAG%d_ORIENT" % count))
self.arm_vehicle()
self.progress("Test calibration rejection when armed")
- self.run_cmd(mavutil.mavlink.MAV_CMD_DO_START_MAG_CAL,
- target_mask, # p1: mag_mask
- 0, # p2: retry
- 0, # p3: autosave
- 0, # p4: delay
- 0, # param5
- 0, # param6
- 0, # param7
- want_result=mavutil.mavlink.MAV_RESULT_FAILED,
- timeout=20,
- )
+ self.run_cmd(
+ mavutil.mavlink.MAV_CMD_DO_START_MAG_CAL,
+ p1=target_mask, # p1: mag_mask
+ p2=0, # retry
+ p3=0, # autosave
+ p4=0, # delay
+ want_result=mavutil.mavlink.MAV_RESULT_FAILED,
+ timeout=20,
+ )
self.disarm_vehicle()
self.mavproxy_unload_module(mavproxy, "relay")
self.mavproxy_unload_module(mavproxy, "sitl_calibration")
@@ -9148,16 +9143,18 @@ def FixedYawCalibration(self):
ss = self.assert_receive_message('SIMSTATE', timeout=1, verbose=True)
- self.run_cmd(mavutil.mavlink.MAV_CMD_FIXED_MAG_CAL_YAW,
- math.degrees(ss.yaw), # param1
- 0, # param2
- 0, # param3
- 0, # param4
+ self.run_cmd(
+ mavutil.mavlink.MAV_CMD_FIXED_MAG_CAL_YAW,
+ p1=math.degrees(ss.yaw),
+ )
+ self.verify_parameter_values(wanted)
- 0, # param5
- 0, # param6
- 0 # param7
- )
+ # run same command but as command_int:
+ self.zero_mag_offset_parameters()
+ self.run_cmd_int(
+ mavutil.mavlink.MAV_CMD_FIXED_MAG_CAL_YAW,
+ p1=math.degrees(ss.yaw),
+ )
self.verify_parameter_values(wanted)
self.progress("Rebooting and making sure we could arm with these values")
@@ -9444,6 +9441,16 @@ def ArmFeatures(self):
self.progress("default disarm_vehicle() call")
self.disarm_vehicle()
+ self.start_subtest("Arm/disarm vehicle with COMMAND_INT")
+ self.run_cmd_int(
+ mavutil.mavlink.MAV_CMD_COMPONENT_ARM_DISARM,
+ p1=1, # ARM
+ )
+ self.run_cmd_int(
+ mavutil.mavlink.MAV_CMD_COMPONENT_ARM_DISARM,
+ p1=0, # DISARM
+ )
+
self.progress("arm with mavproxy")
mavproxy = self.start_mavproxy()
if not self.mavproxy_arm_vehicle(mavproxy):
@@ -9579,6 +9586,8 @@ def ArmFeatures(self):
self.set_rc(interlock_channel, 1000)
self.start_subtest("Test all mode arming")
+ self.wait_ready_to_arm()
+
if self.arming_test_mission() is not None:
self.load_mission(self.arming_test_mission())
@@ -9605,16 +9614,11 @@ def ArmFeatures(self):
else:
self.progress("Not armable mode : %s" % mode)
self.change_mode(mode)
- self.run_cmd(mavutil.mavlink.MAV_CMD_COMPONENT_ARM_DISARM,
- 1, # ARM
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- want_result=mavutil.mavlink.MAV_RESULT_FAILED
- )
+ self.run_cmd(
+ mavutil.mavlink.MAV_CMD_COMPONENT_ARM_DISARM,
+ p1=1, # ARM
+ want_result=mavutil.mavlink.MAV_RESULT_FAILED,
+ )
self.progress("PASS not able to arm in mode : %s" % mode)
if mode in self.get_position_armable_modes_list():
self.progress("Armable mode needing Position : %s" % mode)
@@ -9627,16 +9631,11 @@ def ArmFeatures(self):
self.progress("Not armable mode without Position : %s" % mode)
self.wait_gps_disable()
self.change_mode(mode)
- self.run_cmd(mavutil.mavlink.MAV_CMD_COMPONENT_ARM_DISARM,
- 1, # ARM
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- want_result=mavutil.mavlink.MAV_RESULT_FAILED
- )
+ self.run_cmd(
+ mavutil.mavlink.MAV_CMD_COMPONENT_ARM_DISARM,
+ p1=1, # ARM
+ want_result=mavutil.mavlink.MAV_RESULT_FAILED,
+ )
self.set_parameter("SIM_GPS_DISABLE", 0)
self.wait_ekf_happy() # EKF may stay unhappy for a while
self.progress("PASS not able to arm without Position in mode : %s" % mode)
@@ -9726,15 +9725,12 @@ def set_message_rate_hz(self, id, rate_hz, mav=None):
set_interval = rate_hz
else:
set_interval = self.rate_to_interval_us(rate_hz)
- self.run_cmd(mavutil.mavlink.MAV_CMD_SET_MESSAGE_INTERVAL,
- id,
- set_interval,
- 0,
- 0,
- 0,
- 0,
- 0,
- mav=mav)
+ self.run_cmd(
+ mavutil.mavlink.MAV_CMD_SET_MESSAGE_INTERVAL,
+ p1=id,
+ p2=set_interval,
+ mav=mav,
+ )
def send_get_message_interval(self, victim_message, mav=None):
if mav is None:
@@ -9754,6 +9750,25 @@ def send_get_message_interval(self, victim_message, mav=None):
0,
0)
+ def get_message_interval(self, victim_message, mav=None):
+ '''returns message interval in microseconds'''
+ self.send_get_message_interval(victim_message, mav=mav)
+ m = self.assert_receive_message('MESSAGE_INTERVAL', timeout=1, mav=mav)
+ if m.message_id != victim_message:
+ raise NotAchievedException("Unexpected ID in MESSAGE_INTERVAL")
+ return m.interval_us
+
+ def set_message_interval(self, victim_message, interval_us, mav=None):
+ '''sets message interval in microseconds'''
+ if type(victim_message) == str:
+ victim_message = eval("mavutil.mavlink.MAVLINK_MSG_ID_%s" % victim_message)
+ self.run_cmd(
+ mavutil.mavlink.MAV_CMD_SET_MESSAGE_INTERVAL,
+ p1=victim_message,
+ p2=interval_us,
+ mav=mav,
+ )
+
def test_rate(self,
desc,
in_rate,
@@ -9910,18 +9925,14 @@ def send_poll_message(self, message_id, target_sysid=None, target_compid=None, q
mav = self.mav
if type(message_id) == str:
message_id = eval("mavutil.mavlink.MAVLINK_MSG_ID_%s" % message_id)
- self.send_cmd(mavutil.mavlink.MAV_CMD_REQUEST_MESSAGE,
- message_id,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- target_sysid=target_sysid,
- target_compid=target_compid,
- quiet=quiet,
- mav=mav)
+ self.send_cmd(
+ mavutil.mavlink.MAV_CMD_REQUEST_MESSAGE,
+ p1=message_id,
+ target_sysid=target_sysid,
+ target_compid=target_compid,
+ quiet=quiet,
+ mav=mav,
+ )
def poll_message(self, message_id, timeout=10, quiet=False, mav=None):
if mav is None:
@@ -9935,7 +9946,7 @@ def poll_message(self, message_id, timeout=10, quiet=False, mav=None):
mavutil.mavlink.MAV_RESULT_ACCEPTED,
timeout,
quiet=quiet,
- mav=mav
+ mav=mav,
)
while True:
if self.get_sim_time_cached() - tstart > timeout:
@@ -9987,10 +9998,11 @@ def clear_mission(self, mission_type, target_system=1, target_component=1):
'''
if mission_type == mavutil.mavlink.MAV_MISSION_TYPE_ALL:
# recurse
- if not self.is_tracker() and not self.is_plane():
+ if not self.is_tracker() and not self.is_blimp():
self.clear_mission(mavutil.mavlink.MAV_MISSION_TYPE_FENCE)
- self.clear_mission(mavutil.mavlink.MAV_MISSION_TYPE_MISSION)
- if not self.is_sub() and not self.is_tracker():
+ if not self.is_blimp():
+ self.clear_mission(mavutil.mavlink.MAV_MISSION_TYPE_MISSION)
+ if not self.is_sub() and not self.is_tracker() and not self.is_blimp():
self.clear_mission(mavutil.mavlink.MAV_MISSION_TYPE_RALLY)
self.last_wp_load = time.time()
return
@@ -9999,16 +10011,11 @@ def clear_mission(self, mission_type, target_system=1, target_component=1):
target_component,
0,
mission_type)
- m = self.assert_receive_message('MISSION_ACK', timeout=5)
- if m.target_system != self.mav.mav.srcSystem:
- raise NotAchievedException("ACK not targetted at correct system want=%u got=%u" %
- (self.mav.mav.srcSystem, m.target_system))
- if m.target_component != self.mav.mav.srcComponent:
- raise NotAchievedException("ACK not targetted at correct component want=%u got=%u" %
- (self.mav.mav.srcComponent, m.target_component))
- if m.type != mavutil.mavlink.MAV_MISSION_ACCEPTED:
- raise NotAchievedException("Expected MAV_MISSION_ACCEPTED got %s" %
- (mavutil.mavlink.enums["MAV_MISSION_RESULT"][m.type].name,))
+ self.assert_received_message_field_values('MISSION_ACK', {
+ "target_system": self.mav.mav.srcSystem,
+ "target_component": self.mav.mav.srcComponent,
+ "type": mavutil.mavlink.MAV_MISSION_ACCEPTED,
+ })
if mission_type == mavutil.mavlink.MAV_MISSION_TYPE_MISSION:
self.last_wp_load = time.time()
@@ -10511,6 +10518,78 @@ def send_yaw_rate(rate, target=None):
self.do_RTL(distance_min=0, distance_max=wp_accuracy)
self.disarm_vehicle()
+ def SetpointBadVel(self, timeout=30):
+ '''try feeding in a very, very bad velocity and make sure it is ignored'''
+ self.takeoff(mode='GUIDED')
+ # following values from a real log:
+ target_speed = Vector3(-3.6019095525029597e+30,
+ 1.7796490496925177e-41,
+ 3.0557017120313744e-26)
+
+ self.progress("Feeding in bad global data, hoping we don't move")
+
+ def send_speed_vector_global_int(vector , mav_frame):
+ self.mav.mav.set_position_target_global_int_send(
+ 0, # timestamp
+ self.sysid_thismav(), # target system_id
+ 1, # target component id
+ mav_frame,
+ MAV_POS_TARGET_TYPE_MASK.POS_IGNORE |
+ MAV_POS_TARGET_TYPE_MASK.ACC_IGNORE |
+ MAV_POS_TARGET_TYPE_MASK.YAW_IGNORE |
+ MAV_POS_TARGET_TYPE_MASK.YAW_RATE_IGNORE,
+ 0,
+ 0,
+ 0,
+ vector.x, # vx
+ vector.y, # vy
+ vector.z, # vz
+ 0, # afx
+ 0, # afy
+ 0, # afz
+ 0, # yaw
+ 0, # yawrate
+ )
+ self.wait_speed_vector(
+ Vector3(0, 0, 0),
+ timeout=timeout,
+ called_function=lambda plop, empty: send_speed_vector_global_int(target_speed, mavutil.mavlink.MAV_FRAME_GLOBAL_RELATIVE_ALT), # noqa
+ minimum_duration=10
+ )
+
+ self.progress("Feeding in bad local data, hoping we don't move")
+
+ def send_speed_vector_local_ned(vector , mav_frame):
+ self.mav.mav.set_position_target_local_ned_send(
+ 0, # timestamp
+ self.sysid_thismav(), # target system_id
+ 1, # target component id
+ mav_frame,
+ MAV_POS_TARGET_TYPE_MASK.POS_IGNORE |
+ MAV_POS_TARGET_TYPE_MASK.ACC_IGNORE |
+ MAV_POS_TARGET_TYPE_MASK.YAW_IGNORE |
+ MAV_POS_TARGET_TYPE_MASK.YAW_RATE_IGNORE,
+ 0,
+ 0,
+ 0,
+ vector.x, # vx
+ vector.y, # vy
+ vector.z, # vz
+ 0, # afx
+ 0, # afy
+ 0, # afz
+ 0, # yaw
+ 0, # yawrate
+ )
+ self.wait_speed_vector(
+ Vector3(0, 0, 0),
+ timeout=timeout,
+ called_function=lambda plop, empty: send_speed_vector_local_ned(target_speed, mavutil.mavlink.MAV_FRAME_LOCAL_NED), # noqa
+ minimum_duration=10
+ )
+
+ self.do_RTL()
+
def SetpointGlobalVel(self, timeout=30):
"""Test set position message in guided mode."""
# Disable heading and yaw rate test on rover type
@@ -10873,6 +10952,9 @@ def send_yaw_rate_vel(rate, vector, mav_frame):
self.do_RTL(distance_min=0, distance_max=wp_accuracy)
self.disarm_vehicle()
+ def is_blimp(self):
+ return False
+
def is_copter(self):
return False
@@ -11240,27 +11322,19 @@ def test_parameter_checks_poscontrol(self, param_prefix):
self.wait_ready_to_arm()
self.context_push()
self.set_parameter("%s_POSXY_P" % param_prefix, -1)
- self.run_cmd(mavutil.mavlink.MAV_CMD_COMPONENT_ARM_DISARM,
- 1, # ARM
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- timeout=4,
- want_result=mavutil.mavlink.MAV_RESULT_FAILED)
+ self.run_cmd(
+ mavutil.mavlink.MAV_CMD_COMPONENT_ARM_DISARM,
+ p1=1, # ARM
+ timeout=4,
+ want_result=mavutil.mavlink.MAV_RESULT_FAILED,
+ )
self.context_pop()
- self.run_cmd(mavutil.mavlink.MAV_CMD_COMPONENT_ARM_DISARM,
- 1, # ARM
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- timeout=4,
- want_result=mavutil.mavlink.MAV_RESULT_ACCEPTED)
+ self.run_cmd(
+ mavutil.mavlink.MAV_CMD_COMPONENT_ARM_DISARM,
+ p1=1, # ARM
+ timeout=4,
+ want_result=mavutil.mavlink.MAV_RESULT_ACCEPTED,
+ )
self.disarm_vehicle()
def assert_not_receiving_message(self, message, timeout=1, mav=None):
@@ -11344,13 +11418,7 @@ def AdvancedFailsafe(self):
self.context_collect("STATUSTEXT")
self.run_cmd(
mavutil.mavlink.MAV_CMD_DO_FLIGHTTERMINATION,
- 1, # terminate
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
+ p1=1, # terminate
)
self.wait_statustext("Terminating due to GCS request", check_context=True)
self.context_pop()
@@ -11390,9 +11458,10 @@ def NMEAOutput(self):
'''Test AHRS NMEA Output can be read by out NMEA GPS'''
self.set_parameter("SERIAL5_PROTOCOL", 20) # serial5 is NMEA output
self.set_parameter("GPS_TYPE2", 5) # GPS2 is NMEA
+ port = self.spare_network_port()
self.customise_SITL_commandline([
- "--uartE=tcp:6735", # GPS2 is NMEA....
- "--uartF=tcpclient:127.0.0.1:6735", # serial5 spews to localhost:6735
+ "--uartE=tcp:%u" % port, # GPS2 is NMEA....
+ "--uartF=tcpclient:127.0.0.1:%u" % port, # serial5 spews to localhost port
])
self.do_timesync_roundtrip()
self.wait_gps_fix_type_gte(3)
@@ -11552,6 +11621,17 @@ def ahrstrim_preflight_cal(self):
self.progress("Correct value %.4f for %s error %.2f%%" %
(v, pname, error_pct))
+ def user_takeoff(self, alt_min=30, timeout=30, max_err=5):
+ '''takeoff using mavlink takeoff command'''
+ self.run_cmd(
+ mavutil.mavlink.MAV_CMD_NAV_TAKEOFF,
+ p7=alt_min, # param7
+ )
+ self.wait_altitude(alt_min - 1,
+ (alt_min + max_err),
+ relative=True,
+ timeout=timeout)
+
def ahrstrim_attitude_correctness(self):
self.wait_ready_to_arm()
HOME = self.sitl_start_location()
@@ -11663,14 +11743,8 @@ def Button(self):
# try to arm the vehicle:
self.run_cmd(
mavutil.mavlink.MAV_CMD_COMPONENT_ARM_DISARM,
- 1, # ARM
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- want_result=mavutil.mavlink.MAV_RESULT_FAILED
+ p1=1, # ARM
+ want_result=mavutil.mavlink.MAV_RESULT_FAILED,
)
self.assert_prearm_failure("Motors Emergency Stopped",
other_prearm_failures_fatal=False)
@@ -12001,10 +12075,11 @@ def FRSkyPassThroughStatustext(self):
"RPM1_TYPE": 10, # enable RPM output
"TERRAIN_ENABLE": 0,
})
+ port = self.spare_network_port()
self.customise_SITL_commandline([
- "--uartF=tcp:6735" # serial5 spews to localhost:6735
+ "--uartF=tcp:%u" % port # serial5 spews to localhost port
])
- frsky = FRSkyPassThrough(("127.0.0.1", 6735),
+ frsky = FRSkyPassThrough(("127.0.0.1", port),
get_time=self.get_sim_time_cached)
# waiting until we are ready to arm should ensure our wanted
@@ -12021,14 +12096,10 @@ def FRSkyPassThroughStatustext(self):
self.context_collect('STATUSTEXT')
command = mavutil.mavlink.MAV_CMD_PREFLIGHT_CALIBRATION
- self.send_cmd(command,
- 0, # p1
- 0, # p2
- 1, # p3, baro
- 0, # p4
- 0, # p5
- 0, # p6
- 0) # p7
+ self.send_cmd(
+ command,
+ p3=1, # p3, baro
+ )
# this is a test for asynchronous handling of mavlink messages:
self.run_cmd_get_ack(command, mavutil.mavlink.MAV_RESULT_IN_PROGRESS, 2)
self.run_cmd_get_ack(command, mavutil.mavlink.MAV_RESULT_ACCEPTED, 5)
@@ -12095,10 +12166,11 @@ def FRSkyPassThroughSensorIDs(self):
"SERIAL5_PROTOCOL": 10, # serial5 is FRSky passthrough
"RPM1_TYPE": 10, # enable RPM output
})
+ port = self.spare_network_port()
self.customise_SITL_commandline([
- "--uartF=tcp:6735" # serial5 spews to localhost:6735
+ "--uartF=tcp:%u" % port # serial5 spews to localhost port
])
- frsky = FRSkyPassThrough(("127.0.0.1", 6735),
+ frsky = FRSkyPassThrough(("127.0.0.1", port),
get_time=self.get_sim_time_cached)
self.wait_ready_to_arm()
@@ -12249,10 +12321,11 @@ def run_cmd_via_mavlite_get_ack(self, frsky, sport_to_mavlite, command, want_res
def FRSkyMAVlite(self):
'''Test FrSky MAVlite serial output'''
self.set_parameter("SERIAL5_PROTOCOL", 10) # serial5 is FRSky passthrough
+ port = self.spare_network_port()
self.customise_SITL_commandline([
- "--uartF=tcp:6735" # serial5 spews to localhost:6735
+ "--uartF=tcp:%u" % port # serial5 spews to localhost port
])
- frsky = FRSkyPassThrough(("127.0.0.1", 6735))
+ frsky = FRSkyPassThrough(("127.0.0.1", port))
frsky.connect()
sport_to_mavlite = SPortToMAVlite()
@@ -12523,10 +12596,11 @@ def FRSkySPort(self):
'''Test FrSky SPort mode'''
self.set_parameter("SERIAL5_PROTOCOL", 4) # serial5 is FRSky sport
self.set_parameter("RPM1_TYPE", 10) # enable SITL RPM sensor
+ port = self.spare_network_port()
self.customise_SITL_commandline([
- "--uartF=tcp:6735" # serial5 spews to localhost:6735
+ "--uartF=tcp:%u" % port # serial5 spews to localhost port
])
- frsky = FRSkySPort(("127.0.0.1", 6735), verbose=True)
+ frsky = FRSkySPort(("127.0.0.1", port), verbose=True)
self.wait_ready_to_arm()
# we need to start the engine to get some RPM readings, we do it for plane only
@@ -12595,24 +12669,21 @@ def FRSkySPort(self):
def FRSkyD(self):
'''Test FrSkyD serial output'''
self.set_parameter("SERIAL5_PROTOCOL", 3) # serial5 is FRSky output
+ port = self.spare_network_port()
self.customise_SITL_commandline([
- "--uartF=tcp:6735" # serial5 spews to localhost:6735
+ "--uartF=tcp:%u" % port # serial5 spews to localhost port
])
- frsky = FRSkyD(("127.0.0.1", 6735))
+ frsky = FRSkyD(("127.0.0.1", port))
self.wait_ready_to_arm()
m = self.assert_receive_message('GLOBAL_POSITION_INT', timeout=1)
gpi_abs_alt = int((m.alt+500) / 1000) # mm -> m
# grab a battery-remaining percentage
- self.run_cmd(mavutil.mavlink.MAV_CMD_BATTERY_RESET,
- 255, # battery mask
- 96, # percentage
- 0,
- 0,
- 0,
- 0,
- 0,
- 0)
+ self.run_cmd(
+ mavutil.mavlink.MAV_CMD_BATTERY_RESET,
+ p1=255, # battery mask
+ p2=96, # percentage
+ )
m = self.assert_receive_message('BATTERY_STATUS', timeout=1)
want_battery_remaining_pct = m.battery_remaining
@@ -12717,10 +12788,11 @@ def test_ltm_s(self, ltm):
def LTM(self):
'''Test LTM serial output'''
self.set_parameter("SERIAL5_PROTOCOL", 25) # serial5 is LTM output
+ port = self.spare_network_port()
self.customise_SITL_commandline([
- "--uartF=tcp:6735" # serial5 spews to localhost:6735
+ "--uartF=tcp:%u" % port # serial5 spews to localhost port
])
- ltm = LTM(("127.0.0.1", 6735))
+ ltm = LTM(("127.0.0.1", port))
self.wait_ready_to_arm()
wants = {
@@ -12759,10 +12831,11 @@ def DEVO(self):
'''Test DEVO serial output'''
self.context_push()
self.set_parameter("SERIAL5_PROTOCOL", 17) # serial5 is DEVO output
+ port = self.spare_network_port()
self.customise_SITL_commandline([
- "--uartF=tcp:6735" # serial5 spews to localhost:6735
+ "--uartF=tcp:%u" % port # serial5 spews to localhost port
])
- devo = DEVO(("127.0.0.1", 6735))
+ devo = DEVO(("127.0.0.1", port))
self.wait_ready_to_arm()
m = self.assert_receive_message('GLOBAL_POSITION_INT', timeout=1)
@@ -12831,10 +12904,11 @@ def MSP_DJI(self):
'''Test MSP DJI serial output'''
self.set_parameter("SERIAL5_PROTOCOL", 33) # serial5 is MSP DJI output
self.set_parameter("MSP_OPTIONS", 1) # telemetry (unpolled) mode
+ port = self.spare_network_port()
self.customise_SITL_commandline([
- "--uartF=tcp:6735" # serial5 spews to localhost:6735
+ "--uartF=tcp:%u" % port # serial5 spews to localhost port
])
- msp = MSP_DJI(("127.0.0.1", 6735))
+ msp = MSP_DJI(("127.0.0.1", port))
self.wait_ready_to_arm()
tstart = self.get_sim_time()
@@ -12858,10 +12932,11 @@ def CRSF(self):
ex = None
try:
self.set_parameter("SERIAL5_PROTOCOL", 23) # serial5 is RCIN input
+ port = self.spare_network_port()
self.customise_SITL_commandline([
- "--uartF=tcp:6735" # serial5 reads from to localhost:6735
+ "--uartF=tcp:%u" % port # serial5 reads from to localhost port
])
- crsf = CRSF(("127.0.0.1", 6735))
+ crsf = CRSF(("127.0.0.1", port))
crsf.connect()
self.progress("Writing vtx_frame")
@@ -12882,6 +12957,27 @@ def CRSF(self):
if ex is not None:
raise ex
+ def CompassPrearms(self):
+ '''test compass prearm checks'''
+ self.wait_ready_to_arm()
+ # XY are checked specially:
+ for axis in 'X', 'Y': # ArduPilot only checks these two axes
+ self.context_push()
+ self.set_parameter(f"COMPASS_OFS2_{axis}", 1000)
+ self.assert_prearm_failure("Compasses inconsistent")
+ self.context_pop()
+ self.wait_ready_to_arm()
+
+ # now test the total anglular difference:
+ self.context_push()
+ self.set_parameters({
+ "COMPASS_OFS2_X": 1000,
+ "COMPASS_OFS2_Y": -1000,
+ "COMPASS_OFS2_Z": -10000,
+ })
+ self.assert_prearm_failure("Compasses inconsistent")
+ self.context_pop()
+
def AHRS_ORIENTATION(self):
'''test AHRS_ORIENTATION parameter works'''
self.context_push()
@@ -12910,23 +13006,26 @@ def GPSTypes(self):
# if gps_type is None we auto-detect
sim_gps = [
# (0, "NONE"),
- (1, "UBLOX", None, "u-blox"),
- (5, "NMEA", 5, "NMEA"),
- (6, "SBP", None, "SBP"),
- # (7, "SBP2", 9, "SBP2"), # broken, "waiting for config data"
- (8, "NOVA", 15, "NOVA"), # no attempt to auto-detect this in AP_GPS
+ (1, "UBLOX", None, "u-blox", 5, 'detected'),
+ (5, "NMEA", 5, "NMEA", 5, 'detected'),
+ (6, "SBP", None, "SBP", 5, 'detected'),
+ # (7, "SBP2", 9, "SBP2", 5), # broken, "waiting for config data"
+ (8, "NOVA", 15, "NOVA", 5, 'detected'), # no attempt to auto-detect this in AP_GPS
+ (11, "GSOF", 11, "GSOF", 5, 'detected'),
+ (19, "MSP", 19, "MSP", 32, 'specified'), # no attempt to auto-detect this in AP_GPS
# (9, "FILE"),
]
self.context_collect("STATUSTEXT")
- for (sim_gps_type, name, gps_type, detect_name) in sim_gps:
+ for (sim_gps_type, name, gps_type, detect_name, serial_protocol, detect_prefix) in sim_gps:
self.start_subtest("Checking GPS type %s" % name)
self.set_parameter("SIM_GPS_TYPE", sim_gps_type)
+ self.set_parameter("SERIAL3_PROTOCOL", serial_protocol)
if gps_type is None:
gps_type = 1 # auto-detect
self.set_parameter("GPS_TYPE", gps_type)
self.context_clear_collection('STATUSTEXT')
self.reboot_sitl()
- self.wait_statustext("detected as %s" % detect_name, check_context=True)
+ self.wait_statustext("%s as %s" % (detect_prefix, detect_name), check_context=True)
n = self.poll_home_position(timeout=120)
distance = self.get_distance_int(orig, n)
if distance > 1:
@@ -12992,6 +13091,7 @@ def MultipleGPS(self):
(msg, m.alt, gpi_alt))
introduced_error = 10 # in metres
self.set_parameter("SIM_GPS2_ALT_OFS", introduced_error)
+ self.do_timesync_roundtrip()
m = self.assert_receive_message("GPS2_RAW")
if abs((m.alt-introduced_error*1000) - gpi_alt) > 100:
raise NotAchievedException("skewed Alt (%s) discrepancy; %d+%d vs %d" %
@@ -13010,9 +13110,11 @@ def MultipleGPS(self):
if abs(new_gpi_alt2 - m.alt) > 100:
raise NotAchievedException("Failover not detected")
- def fetch_file_via_ftp(self, path):
+ def fetch_file_via_ftp(self, path, timeout=20):
'''returns the content of the FTP'able file at path'''
+ self.progress("Retrieving (%s) using MAVProxy" % path)
mavproxy = self.start_mavproxy()
+ mavproxy.expect("Saved .* parameters to")
ex = None
tmpfile = tempfile.NamedTemporaryFile(mode='r', delete=False)
try:
@@ -13021,9 +13123,18 @@ def fetch_file_via_ftp(self, path):
mavproxy.send("ftp set debug 1\n") # so we get the "Terminated session" message
mavproxy.send("ftp get %s %s\n" % (path, tmpfile.name))
mavproxy.expect("Getting")
- self.delay_sim_time(2)
- mavproxy.send("ftp status\n")
- mavproxy.expect("No transfer in progress")
+ tstart = self.get_sim_time()
+ while True:
+ now = self.get_sim_time()
+ if now - tstart > timeout:
+ raise NotAchievedException("expected complete transfer")
+ self.progress("Polling status")
+ mavproxy.send("ftp status\n")
+ try:
+ mavproxy.expect("No transfer in progress", timeout=1)
+ break
+ except Exception:
+ continue
# terminate the connection, or it may still be in progress the next time an FTP is attempted:
mavproxy.send("ftp cancel\n")
mavproxy.expect("Terminated session")
@@ -13176,7 +13287,11 @@ def autotest(self, tests=None, allow_skips=True):
disabled = {}
skip_list = []
tests = []
+ seen_test_name = set()
for test in all_tests:
+ if test.name in seen_test_name:
+ raise ValueError("Duplicate test name %s" % test.name)
+ seen_test_name.add(test.name)
if test.name in disabled:
self.progress("##### %s is skipped: %s" % (test, disabled[test.name]))
skip_list.append((test, disabled[test.name]))
@@ -13319,25 +13434,17 @@ def load_default_params_file(self, filename):
def send_pause_command(self):
'''pause AUTO/GUIDED modes'''
- self.run_cmd(mavutil.mavlink.MAV_CMD_DO_PAUSE_CONTINUE,
- 0, # 0: pause, 1: continue
- 0, # param2
- 0, # param3
- 0, # param4
- 0, # param5
- 0, # param6
- 0) # param7
+ self.run_cmd(
+ mavutil.mavlink.MAV_CMD_DO_PAUSE_CONTINUE,
+ p1=0, # 0: pause, 1: continue
+ )
def send_resume_command(self):
'''resume AUTO/GUIDED modes'''
- self.run_cmd(mavutil.mavlink.MAV_CMD_DO_PAUSE_CONTINUE,
- 1, # 0: pause, 1: continue
- 0, # param2
- 0, # param3
- 0, # param4
- 0, # param5
- 0, # param6
- 0) # param7
+ self.run_cmd(
+ mavutil.mavlink.MAV_CMD_DO_PAUSE_CONTINUE,
+ p1=1, # 0: pause, 1: continue
+ )
def enum_state_name(self, enum_name, state, pretrim=None):
e = mavutil.mavlink.enums[enum_name]
diff --git a/Tools/autotest/default_params/blimp.parm b/Tools/autotest/default_params/blimp.parm
index 192455b115c7b9..a790eec33454f5 100644
--- a/Tools/autotest/default_params/blimp.parm
+++ b/Tools/autotest/default_params/blimp.parm
@@ -38,6 +38,18 @@ RC7_TRIM 1500
RC8_MAX 2000
RC8_MIN 1000
RC8_TRIM 1500
+SERVO1_MAX 2200
+SERVO1_MIN 500
+SERVO1_TRIM 1350
+SERVO2_MAX 2200
+SERVO2_MIN 500
+SERVO2_TRIM 1350
+SERVO3_MAX 2200
+SERVO3_MIN 500
+SERVO3_TRIM 1350
+SERVO4_MAX 2200
+SERVO4_MIN 500
+SERVO4_TRIM 1350
# setting servo functions for the four fins
SERVO1_FUNCTION 33
@@ -76,16 +88,18 @@ INS_ACC3SCAL_Z 1.000
ARMING_RUDDER 0
GCS_PID_MASK 255
+SIM_SERVO_SPEED 0.06
+LOG_BITMASK 65535
# default PID params for position and velocity-controlled modes
-MAX_POS_XY 0.3
+MAX_POS_XY 0.15
MAX_POS_YAW 0.3
MAX_POS_Z 0.15
-MAX_VEL_XY 0.4
-MAX_VEL_YAW 0.5
+MAX_VEL_XY 0.2
+MAX_VEL_YAW 0.4
MAX_VEL_Z 0.2
-VELXY_D 0.0
+VELXY_D 1.0
VELXY_FF 0.0
VELXY_FLTD 3.0
VELXY_FLTE 3.0
@@ -98,7 +112,7 @@ VELYAW_FLTD 3.0
VELYAW_FLTE 3.0
VELYAW_I 0.8
VELYAW_IMAX 5.0
-VELYAW_P 15.0
+VELYAW_P 10.0
VELZ_D 0.0
VELZ_FF 0.0
VELZ_FLTD 3.0
diff --git a/Tools/autotest/default_params/copter-heli-dual.parm b/Tools/autotest/default_params/copter-heli-dual.parm
index d12d6725f63c4a..5b5e58adda58a6 100644
--- a/Tools/autotest/default_params/copter-heli-dual.parm
+++ b/Tools/autotest/default_params/copter-heli-dual.parm
@@ -1,9 +1,9 @@
FRAME_CLASS 11
ATC_ANG_PIT_P 4.5
ATC_ANG_YAW_P 4.5
-ATC_RAT_PIT_D 0.0012
-ATC_RAT_PIT_P 0.001
-ATC_RAT_PIT_FF 0.17
+ATC_RAT_PIT_D 0.0005
+ATC_RAT_PIT_P 0.02
+ATC_RAT_PIT_FF 0.0
ATC_RAT_YAW_D 0.0015
ATC_RAT_YAW_P 0.14685
ATC_HOVR_ROL_TRM 0
diff --git a/Tools/autotest/default_params/copter-heli-gas.parm b/Tools/autotest/default_params/copter-heli-gas.parm
new file mode 100644
index 00000000000000..38269b2d2aa68e
--- /dev/null
+++ b/Tools/autotest/default_params/copter-heli-gas.parm
@@ -0,0 +1,9 @@
+H_RSC_IDLE 14
+H_RSC_MODE 3
+H_RSC_RAMP_TIME 10
+H_RSC_RUNUP_TIME 15
+H_RSC_THRCRV_0 27
+H_RSC_THRCRV_25 32
+H_RSC_THRCRV_50 45
+H_RSC_THRCRV_75 75
+H_RSC_THRCRV_100 100
\ No newline at end of file
diff --git a/Tools/autotest/default_params/copter-heli.parm b/Tools/autotest/default_params/copter-heli.parm
index 08a836dd01f97f..994bf370801ecf 100644
--- a/Tools/autotest/default_params/copter-heli.parm
+++ b/Tools/autotest/default_params/copter-heli.parm
@@ -70,7 +70,7 @@ ATC_ACCEL_Y_MAX 60000
ATC_HOVR_ROL_TRM 320
H_COL_MAX 1740
H_COL_MIN 1460
-H_COL_ANG_MAX 10
+H_COL_ANG_MAX 12
H_COL_ANG_MIN -2
H_RSC_MODE 2
H_RSC_SETPOINT 66
diff --git a/Tools/autotest/default_params/copter-winch.parm b/Tools/autotest/default_params/copter-winch.parm
new file mode 100644
index 00000000000000..4f2279c00d9927
--- /dev/null
+++ b/Tools/autotest/default_params/copter-winch.parm
@@ -0,0 +1,6 @@
+# servo winch type
+# winch connected to servo output channel 9
+# rc input chnanel 9 used by pilot to control winch
+WINCH_TYPE 1
+SERVO9_FUNCTION 88
+RC9_OPTION 45
diff --git a/Tools/autotest/default_params/periph.parm b/Tools/autotest/default_params/periph.parm
new file mode 100644
index 00000000000000..0e39124d3732ad
--- /dev/null
+++ b/Tools/autotest/default_params/periph.parm
@@ -0,0 +1,19 @@
+# parameters for SITL peripheral
+
+GPS_TYPE 1
+COMPASS_ENABLE 1
+BARO_ENABLE 1
+ARSPD_TYPE 100
+RNGFND1_TYPE 100
+RNGFND1_MAX_CM 12000
+BATT_MONITOR 4
+
+# by default disable motors/servos, overridden in vehicle specific parameters
+OUT1_FUNCTION -1
+OUT2_FUNCTION -1
+OUT3_FUNCTION -1
+OUT4_FUNCTION -1
+OUT5_FUNCTION -1
+OUT6_FUNCTION -1
+OUT7_FUNCTION -1
+OUT8_FUNCTION -1
diff --git a/Tools/autotest/default_params/plane-jsbsim.parm b/Tools/autotest/default_params/plane-jsbsim.parm
index e53e15acd64f26..a77ec1084ef7d1 100644
--- a/Tools/autotest/default_params/plane-jsbsim.parm
+++ b/Tools/autotest/default_params/plane-jsbsim.parm
@@ -7,6 +7,7 @@ TRIM_THROTTLE 50
LIM_PITCH_MIN -2000
LIM_PITCH_MAX 2500
LIM_ROLL_CD 6500
+LAND_DISARMDELAY 3
LAND_PITCH_CD 100
LAND_FLARE_SEC 3
ARSPD_USE 1
diff --git a/Tools/autotest/default_params/quad-can.parm b/Tools/autotest/default_params/quad-can.parm
new file mode 100644
index 00000000000000..0fe872319e3659
--- /dev/null
+++ b/Tools/autotest/default_params/quad-can.parm
@@ -0,0 +1,8 @@
+CAN_P1_DRIVER 1
+CAN_D1_UC_ESC_BM 0x0F
+SIM_CAN_SRV_MSK 0xFf
+SIM_VIB_MOT_MAX 270
+GPS_TYPE 9
+RNGFND1_TYPE 24
+RNGFND1_MAX_CM 11000
+BATT_MONITOR 8
diff --git a/Tools/autotest/default_params/quad-periph.parm b/Tools/autotest/default_params/quad-periph.parm
new file mode 100644
index 00000000000000..2e29723e09d2eb
--- /dev/null
+++ b/Tools/autotest/default_params/quad-periph.parm
@@ -0,0 +1,17 @@
+# extra parameters for SITL peripheral quadplane
+
+SIM_CAN_SRV_MSK 0x0f
+
+# ESCs
+OUT1_FUNCTION 33
+OUT1_MIN 1000
+OUT1_MAX 2000
+OUT2_FUNCTION 34
+OUT2_MIN 1000
+OUT2_MAX 2000
+OUT3_FUNCTION 35
+OUT3_MIN 1000
+OUT3_MAX 2000
+OUT4_FUNCTION 36
+OUT4_MIN 1000
+OUT4_MAX 2000
diff --git a/Tools/autotest/default_params/quadplane-can.parm b/Tools/autotest/default_params/quadplane-can.parm
new file mode 100644
index 00000000000000..3971389f992640
--- /dev/null
+++ b/Tools/autotest/default_params/quadplane-can.parm
@@ -0,0 +1,13 @@
+CAN_P1_DRIVER 1
+CAN_D1_UC_ESC_BM 0xF0
+CAN_D1_UC_ESC_OF 4
+CAN_D1_UC_SRV_BM 0x0F
+CAN_D1_UC_OPTION 16
+SIM_CAN_SRV_MSK 0xfff
+SIM_VIB_MOT_MAX 270
+GPS_TYPE 9
+ARSPD_TYPE 8
+RNGFND1_TYPE 24
+RNGFND1_MAX_CM 11000
+RNGFND_LANDING 1
+BATT_MONITOR 8
diff --git a/Tools/autotest/default_params/quadplane-periph.parm b/Tools/autotest/default_params/quadplane-periph.parm
new file mode 100644
index 00000000000000..dc7a19687b6122
--- /dev/null
+++ b/Tools/autotest/default_params/quadplane-periph.parm
@@ -0,0 +1,23 @@
+# extra parameters for SITL peripheral quadplane
+
+SIM_CAN_SRV_MSK 0xff
+
+# control surfaces
+OUT1_FUNCTION 51
+OUT2_FUNCTION 52
+OUT3_FUNCTION 53
+OUT4_FUNCTION 54
+
+# ESCs
+OUT5_FUNCTION 33
+OUT5_MIN 1000
+OUT5_MAX 2000
+OUT6_FUNCTION 34
+OUT6_MIN 1000
+OUT6_MAX 2000
+OUT7_FUNCTION 35
+OUT7_MIN 1000
+OUT7_MAX 2000
+OUT8_FUNCTION 36
+OUT8_MIN 1000
+OUT8_MAX 2000
diff --git a/Tools/autotest/helicopter.py b/Tools/autotest/helicopter.py
index 4a3ee9b64a42e4..b910b762441ed4 100644
--- a/Tools/autotest/helicopter.py
+++ b/Tools/autotest/helicopter.py
@@ -152,7 +152,13 @@ def takeoff(self,
self.progress("Raising rotor speed")
self.set_rc(8, 2000)
self.progress("wait for rotor runup to complete")
- self.wait_servo_channel_value(8, 1659, timeout=10)
+ if self.get_parameter("H_RSC_MODE") == 4:
+ self.context_collect('STATUSTEXT')
+ self.wait_statustext("Governor Engaged", check_context=True)
+ elif self.get_parameter("H_RSC_MODE") == 3:
+ self.wait_rpm(1, 1300, 1400)
+ else:
+ self.wait_servo_channel_value(8, 1659, timeout=10)
# wait for motor runup
self.delay_sim_time(20)
@@ -161,7 +167,7 @@ def takeoff(self,
self.user_takeoff(alt_min=alt_min)
else:
self.set_rc(3, takeoff_throttle)
- self.wait_for_alt(alt_min=alt_min, timeout=timeout)
+ self.wait_altitude(alt_min-1, alt_min+5, relative=True, timeout=timeout)
self.hover()
self.progress("TAKEOFF COMPLETE")
@@ -199,6 +205,18 @@ def FlyEachFrame(self):
self.do_RTL()
self.set_rc(8, 1000)
+ def governortest(self):
+ '''Test Heli Internal Throttle Curve and Governor'''
+ self.customise_SITL_commandline(
+ ["--defaults", ','.join(self.model_defaults_filepath('heli-gas')), ],
+ model="heli-gas",
+ wipe=True,
+ )
+ self.set_parameter("H_RSC_MODE", 4)
+ self.takeoff(10)
+ self.do_RTL()
+ self.set_rc(8, 1000)
+
def hover(self):
self.progress("Setting hover collective")
self.set_rc(3, 1500)
@@ -285,7 +303,7 @@ def StabilizeTakeOff(self):
if abs(m.relative_alt) > 100:
raise NotAchievedException("Took off prematurely")
self.progress("Pushing throttle past half-way")
- self.set_rc(3, 1600)
+ self.set_rc(3, 1650)
self.progress("Monitoring takeoff")
self.wait_altitude(6.9, 8, relative=True)
@@ -383,20 +401,27 @@ def ManAutoRotation(self, timeout=600):
self.context_collect('STATUSTEXT')
self.change_mode('STABILIZE')
self.progress("Triggering manual autorotation by disabling interlock")
- self.set_rc(3, 1300)
+ self.set_rc(3, 1000)
self.set_rc(8, 1000)
- self.wait_servo_channel_value(8, 1200, timeout=3)
+ self.wait_servo_channel_value(8, 1199, timeout=3)
self.progress("channel 8 set to autorotation window")
+ # wait to establish autorotation
+ self.delay_sim_time(2)
+
self.set_rc(8, 2000)
self.wait_servo_channel_value(8, 1659, timeout=AROT_RAMP_TIME * 1.1)
+ # give time for engine to power up
+ self.set_rc(3, 1400)
+ self.delay_sim_time(2)
+
self.progress("in-flight power recovery")
- self.set_rc(3, 1700)
+ self.set_rc(3, 1500)
self.delay_sim_time(5)
# initiate autorotation again
- self.set_rc(3, 1200)
+ self.set_rc(3, 1000)
self.set_rc(8, 1000)
self.wait_statustext(r"SIM Hit ground at ([0-9.]+) m/s",
@@ -793,6 +818,7 @@ def tests(self):
self.SplineWaypoint,
self.AutoRotation,
self.ManAutoRotation,
+ self.governortest,
self.FlyEachFrame,
self.AirspeedDrivers,
self.TurbineStart,
diff --git a/Tools/autotest/jsb_sim/runsim.py b/Tools/autotest/jsb_sim/runsim.py
deleted file mode 100755
index 416a4e97697d06..00000000000000
--- a/Tools/autotest/jsb_sim/runsim.py
+++ /dev/null
@@ -1,385 +0,0 @@
-#!/usr/bin/env python
-"""
- Run a jsbsim model as a child process.
-"""
-from __future__ import print_function
-import atexit
-import errno
-import fdpexpect
-import math
-import os
-import select
-import signal
-import socket
-import struct
-import sys
-import time
-
-import pexpect
-from pymavlink import fgFDM
-
-from .. pysim import util
-
-
-class control_state(object):
- def __init__(self):
- self.aileron = 0
- self.elevator = 0
- self.throttle = 0
- self.rudder = 0
- self.ground_height = 0
-
-sitl_state = control_state()
-
-
-def interpret_address(addrstr):
- """Interpret a IP:port string."""
- a = addrstr.split(':')
- a[1] = int(a[1])
- return tuple(a)
-
-
-def jsb_set(variable, value):
- """Set a JSBSim variable."""
- global jsb_console
- jsb_console.send('set %s %s\r\n' % (variable, value))
-
-
-def setup_template(home):
- """Setup aircraft/Rascal/reset.xml ."""
- global opts
- v = home.split(',')
- if len(v) != 4:
- print("home should be lat,lng,alt,hdg - '%s'" % home)
- sys.exit(1)
- latitude = float(v[0])
- longitude = float(v[1])
- altitude = float(v[2])
- heading = float(v[3])
- sitl_state.ground_height = altitude
- template = os.path.join('aircraft', 'Rascal', 'reset_template.xml')
- reset = os.path.join('aircraft', 'Rascal', 'reset.xml')
- xml = open(template).read() % {'LATITUDE': str(latitude),
- 'LONGITUDE': str(longitude),
- 'HEADING': str(heading)}
- open(reset, mode='w').write(xml)
- print("Wrote %s" % reset)
-
- baseport = int(opts.simout.split(':')[1])
-
- template = os.path.join('jsb_sim', 'fgout_template.xml')
- out = os.path.join('jsb_sim', 'fgout.xml')
- xml = open(template).read() % {'FGOUTPORT': str(baseport+3)}
- open(out, mode='w').write(xml)
- print("Wrote %s" % out)
-
- template = os.path.join('jsb_sim', 'rascal_test_template.xml')
- out = os.path.join('jsb_sim', 'rascal_test.xml')
- xml = open(template).read() % {'JSBCONSOLEPORT': str(baseport+4)}
- open(out, mode='w').write(xml)
- print("Wrote %s" % out)
-
-
-def process_sitl_input(buf):
- """Process control changes from SITL sim."""
- control = list(struct.unpack('<14H', buf))
- pwm = control[:11]
- (speed, direction, turbulance) = control[11:]
-
- global wind
- wind.speed = speed*0.01
- wind.direction = direction*0.01
- wind.turbulance = turbulance*0.01
-
- aileron = (pwm[0]-1500)/500.0
- elevator = (pwm[1]-1500)/500.0
- throttle = (pwm[2]-1000)/1000.0
- if opts.revthr:
- throttle = 1.0 - throttle
- rudder = (pwm[3]-1500)/500.0
-
- if opts.elevon:
- # fake an elevon plane
- ch1 = aileron
- ch2 = elevator
- aileron = (ch2-ch1)/2.0
- # the minus does away with the need for RC2_REVERSED=-1
- elevator = -(ch2+ch1)/2.0
-
- if opts.vtail:
- # fake an elevon plane
- ch1 = elevator
- ch2 = rudder
- # this matches VTAIL_OUTPUT==2
- elevator = (ch2-ch1)/2.0
- rudder = (ch2+ch1)/2.0
-
- buf = ''
- if aileron != sitl_state.aileron:
- buf += 'set fcs/aileron-cmd-norm %s\n' % aileron
- sitl_state.aileron = aileron
- if elevator != sitl_state.elevator:
- buf += 'set fcs/elevator-cmd-norm %s\n' % elevator
- sitl_state.elevator = elevator
- if rudder != sitl_state.rudder:
- buf += 'set fcs/rudder-cmd-norm %s\n' % rudder
- sitl_state.rudder = rudder
- if throttle != sitl_state.throttle:
- buf += 'set fcs/throttle-cmd-norm %s\n' % throttle
- sitl_state.throttle = throttle
- buf += 'step\n'
- global jsb_console
- jsb_console.send(buf)
-
-
-def update_wind(wind):
- """Update wind simulation."""
- (speed, direction) = wind.current()
- jsb_set('atmosphere/psiw-rad', math.radians(direction))
- jsb_set('atmosphere/wind-mag-fps', speed/0.3048)
-
-
-def process_jsb_input(buf, simtime):
- """Process FG FDM input from JSBSim."""
- global fdm, fg_out, sim_out
- fdm.parse(buf)
- if fg_out:
- try:
- agl = fdm.get('agl', units='meters')
- fdm.set('altitude', agl+sitl_state.ground_height, units='meters')
- fdm.set('rpm', sitl_state.throttle*1000)
- fg_out.send(fdm.pack())
- except socket.error as e:
- if e.errno not in [errno.ECONNREFUSED]:
- raise
-
- timestamp = int(simtime*1.0e6)
-
- simbuf = struct.pack(' 0.1:
- update_wind(wind)
- last_wind_update = tnow
-
- if tnow - last_report > 3:
- print("FPS %u asl=%.1f agl=%.1f roll=%.1f pitch=%.1f a=(%.2f %.2f %.2f) AR=%.1f" % (
- frame_count / (time.time() - last_report),
- fdm.get('altitude', units='meters'),
- fdm.get('agl', units='meters'),
- fdm.get('phi', units='degrees'),
- fdm.get('theta', units='degrees'),
- fdm.get('A_X_pilot', units='mpss'),
- fdm.get('A_Y_pilot', units='mpss'),
- fdm.get('A_Z_pilot', units='mpss'),
- achieved_rate))
-
- frame_count = 0
- last_report = time.time()
-
- if new_frame:
- now = time.time()
- if now < last_wall_time + scaled_frame_time:
- time.sleep(last_wall_time+scaled_frame_time - now)
- now = time.time()
-
- if now > last_wall_time and now - last_wall_time < 0.1:
- rate = 1.0/(now - last_wall_time)
- achieved_rate = (0.98*achieved_rate) + (0.02*rate)
- if achieved_rate < opts.rate*opts.speedup:
- scaled_frame_time *= 0.999
- else:
- scaled_frame_time *= 1.001
-
- last_wall_time = now
-
-
-def exit_handler():
- """Exit the sim."""
- print("running exit handler")
- signal.signal(signal.SIGINT, signal.SIG_IGN)
- signal.signal(signal.SIGTERM, signal.SIG_IGN)
- # JSBSim really doesn't like to die ...
- if getattr(jsb, 'pid', None) is not None:
- os.kill(jsb.pid, signal.SIGKILL)
- jsb_console.send('quit\n')
- jsb.close(force=True)
- util.pexpect_close_all()
- sys.exit(1)
-
-signal.signal(signal.SIGINT, exit_handler)
-signal.signal(signal.SIGTERM, exit_handler)
-
-try:
- main_loop()
-except Exception as ex:
- print(ex)
- exit_handler()
- raise
diff --git a/Tools/autotest/locations.txt b/Tools/autotest/locations.txt
index ce3cf76fed012e..3717b3613f9899 100644
--- a/Tools/autotest/locations.txt
+++ b/Tools/autotest/locations.txt
@@ -56,6 +56,7 @@ Elvenes=68.871422,17.986690,17,256
Kawachi=35.879129,140.339683,7,0
SpringValley=-35.280252,149.005821,597.3,5
SpringValley2=-35.28240059,149.00542037,582,10
+SpringValley3=-35.28240515,149.00716878,579,12.6
Pyramid=29.9764,31.1339,0,0
AAMEastField=39.842288,-105.212928,1809,106
HachinoheMine=40.4539496,141.5419051,56,270
diff --git a/Tools/autotest/logger_metadata/emit_md.py b/Tools/autotest/logger_metadata/emit_md.py
new file mode 100644
index 00000000000000..d6d1cb78778ba4
--- /dev/null
+++ b/Tools/autotest/logger_metadata/emit_md.py
@@ -0,0 +1,82 @@
+import os
+import time
+import emitter
+
+class MDEmitter(emitter.Emitter):
+ def preface(self):
+ if os.getenv('BRDOC') is not None:
+ now = time.strftime('%Y-%m-%dT%H:%M:%S%z')
+ now = now[:-2] + ':' + now[-2:]
+ return '\n'.join((
+ '+++',
+ 'title = "Onboard Log Messages"',
+ 'description = "Message listing for DataFlash autopilot logs."',
+ f'date = {now}',
+ 'template = "docs/page.html"',
+ 'sort_by = "weight"',
+ 'weight = 30',
+ 'draft = false',
+ '[extra]',
+ 'toc = true',
+ 'top = false',
+ '+++\n',
+ '',
+ 'This is a list of log messages which may be present in DataFlash (`.bin`) '
+ 'logs produced and stored onboard ArduSub vehicles (see [Log Parameters]'
+ '(../parameters/#log-parameters) for creation details). '
+ 'It is possible to [add a new message]'
+ '(https://ardupilot.org/dev/docs/code-overview-adding-a-new-log-message.html) '
+ 'by modifying the firmware.\n',
+ 'DataFlash logs can be downloaded and analysed '
+ '[from a computer](http://www.ardusub.com/reference/data-logging.html#downloading) '
+ 'or [through BlueOS]'
+ '(@/software/onboard/BlueOS-1.1/advanced-usage/index.md#log-browser).\n'
+ ))
+
+ return """
+
+
+Onboard Message Log Messages
+
+
+This is a list of log messages which may be present in logs produced and stored onboard ArduPilot vehicles.
+
+
+[toc exclude="Onboard Message Log Messages"]
+
+"""
+ def postface(self):
+ return ""
+
+ def start(self):
+ self.fh = open("LogMessages.md", mode='w')
+ print(self.preface(), file=self.fh)
+
+ def emit(self, doccos, enumerations=None):
+ self.start()
+ for docco in doccos:
+ print(f'## {docco.name}', file=self.fh)
+ desc = ''
+ if docco.description is not None:
+ desc += docco.description
+ if docco.url is not None:
+ desc += f' ([Read more...]({docco.url}))'
+ print(desc, file=self.fh)
+ print("\n|FieldName|Description|\n|---|---|", file=self.fh)
+ for f in docco.fields_order:
+ if "description" in docco.fields[f]:
+ fdesc = docco.fields[f]["description"]
+ else:
+ fdesc = ""
+ print(f'|{f}|{fdesc}|', file=self.fh)
+ print("", file=self.fh)
+ self.stop()
+
+ def stop(self):
+ print(self.postface(), file=self.fh)
+ self.fh.close()
diff --git a/Tools/autotest/logger_metadata/enum_parse.py b/Tools/autotest/logger_metadata/enum_parse.py
index 24ff2106653a02..50c026a21651f3 100755
--- a/Tools/autotest/logger_metadata/enum_parse.py
+++ b/Tools/autotest/logger_metadata/enum_parse.py
@@ -72,6 +72,11 @@ def match_enum_line(self, line):
# Match: " FRED = 17, // optional comment"
m = re.match("\s*([A-Z0-9_a-z]+) *= *(\w+) *,?(?: *// *(.*) *)?$",
line)
+ if m is not None:
+ return (None, None, None)
+ # Match: " FRED = FOO(17), // optional comment"
+ m = re.match("\s*([A-Z0-9_a-z]+) *= *(\w+) *\\( *(\w+) *\\) *,?(?: *// *(.*) *)?$",
+ line)
if m is not None:
return (None, None, None)
diff --git a/Tools/autotest/logger_metadata/parse.py b/Tools/autotest/logger_metadata/parse.py
index f7d4bd9e715690..d66d557cf3b131 100755
--- a/Tools/autotest/logger_metadata/parse.py
+++ b/Tools/autotest/logger_metadata/parse.py
@@ -11,6 +11,7 @@
import emit_html
import emit_rst
import emit_xml
+import emit_md
import enum_parse
from enum_parse import EnumDocco
@@ -50,6 +51,7 @@ def __init__(self, vehicle):
emit_html.HTMLEmitter(),
emit_rst.RSTEmitter(),
emit_xml.XMLEmitter(),
+ emit_md.MDEmitter(),
]
class Docco(object):
diff --git a/Tools/autotest/param_metadata/param.py b/Tools/autotest/param_metadata/param.py
index 8120e0ad771088..f7db128834a3bb 100644
--- a/Tools/autotest/param_metadata/param.py
+++ b/Tools/autotest/param_metadata/param.py
@@ -4,6 +4,9 @@ def __init__(self, name, real_path):
self.name = name
self.real_path = real_path
+ def change_name(self, name):
+ self.name = name
+
class Vehicle(object):
def __init__(self, name, path, reference=None):
@@ -47,6 +50,7 @@ def has_param(self, pname):
'Volatile',
'ReadOnly',
'Calibration',
+ 'Vector3Parameter',
]
# Follow SI units conventions from:
@@ -124,6 +128,7 @@ def has_param(self, pname):
'RPM' : 'Revolutions Per Minute',
'kg/m/m' : 'kilograms per square meter', # metre is the SI unit name, meter is the american spelling of it
'kg/m/m/m': 'kilograms per cubic meter',
+ 'litres' : 'litres',
}
required_param_fields = [
diff --git a/Tools/autotest/param_metadata/param_parse.py b/Tools/autotest/param_metadata/param_parse.py
index fce23c9c10a276..7f5f9c21202dee 100755
--- a/Tools/autotest/param_metadata/param_parse.py
+++ b/Tools/autotest/param_metadata/param_parse.py
@@ -111,7 +111,7 @@ def lua_applets():
# AP_Vehicle also has parameters rooted at "", but isn't referenced
# from the vehicle in any way:
-ap_vehicle_lib = Library("") # the "" is tacked onto the front of param name
+ap_vehicle_lib = Library("", reference="VEHICLE") # the "" is tacked onto the front of param name
setattr(ap_vehicle_lib, "Path", os.path.join('..', 'libraries', 'AP_Vehicle', 'AP_Vehicle.cpp'))
libraries.append(ap_vehicle_lib)
@@ -352,11 +352,25 @@ def process_library(vehicle, library, pathprefix=None):
# applicable for this vehicle.
continue
- p.path = path # Add path. Later deleted - only used for duplicates
- if library.check_duplicates and library.has_param(p.name):
- error("Duplicate parameter %s in %s" % (p.name, library.name))
- continue
- library.params.append(p)
+ if getattr(p, 'Vector3Parameter', None) is not None:
+ params_to_add = []
+ for axis in 'X', 'Y', 'Z':
+ new_p = copy.copy(p)
+ new_p.change_name(p.name + "_" + axis)
+ for a in ["Description"]:
+ if hasattr(new_p, a):
+ current = getattr(new_p, a)
+ setattr(new_p, a, current + " (%s-axis)" % axis)
+ params_to_add.append(new_p)
+ else:
+ params_to_add = [p]
+
+ for p in params_to_add:
+ p.path = path # Add path. Later deleted - only used for duplicates
+ if library.check_duplicates and library.has_param(p.name):
+ error("Duplicate parameter %s in %s" % (p.name, library.name))
+ continue
+ library.params.append(p)
group_matches = prog_groups.findall(p_text)
debug("Found %u groups" % len(group_matches))
@@ -434,6 +448,9 @@ def clean_param(param):
new_valueList.append(":".join([start, end]))
param.Values = ",".join(new_valueList)
+ if hasattr(param, "Vector3Parameter"):
+ delattr(param, "Vector3Parameter")
+
def do_copy_values(vehicle_params, libraries, param):
if not hasattr(param, "CopyValuesFrom"):
@@ -441,6 +458,10 @@ def do_copy_values(vehicle_params, libraries, param):
# so go and find the values...
wanted_name = param.CopyValuesFrom
+ if hasattr(param, 'Vector3Parameter'):
+ suffix = param.name[-2:]
+ wanted_name += suffix
+
del param.CopyValuesFrom
for x in vehicle_params:
name = x.name
@@ -470,6 +491,11 @@ def do_copy_fields(vehicle_params, libraries, param):
# so go and find the values...
wanted_name = param.CopyFieldsFrom
del param.CopyFieldsFrom
+
+ if hasattr(param, 'Vector3Parameter'):
+ suffix = param.name[-2:]
+ wanted_name += suffix
+
for x in vehicle_params:
name = x.name
(v, name) = name.split(":")
diff --git a/Tools/autotest/pysim/aircraft.py b/Tools/autotest/pysim/aircraft.py
deleted file mode 100644
index f3981648733131..00000000000000
--- a/Tools/autotest/pysim/aircraft.py
+++ /dev/null
@@ -1,112 +0,0 @@
-import math
-import random
-import time
-import util
-
-from pymavlink.rotmat import Vector3, Matrix3
-
-
-class Aircraft(object):
- """A basic aircraft class."""
- def __init__(self):
- self.home_latitude = 0
- self.home_longitude = 0
- self.home_altitude = 0
- self.ground_level = 0
- self.frame_height = 0.0
-
- self.latitude = self.home_latitude
- self.longitude = self.home_longitude
- self.altitude = self.home_altitude
-
- self.dcm = Matrix3()
-
- # rotation rate in body frame
- self.gyro = Vector3(0, 0, 0) # rad/s
-
- self.velocity = Vector3(0, 0, 0) # m/s, North, East, Down
- self.position = Vector3(0, 0, 0) # m North, East, Down
- self.mass = 0.0
- self.update_frequency = 50 # in Hz
- self.gravity = 9.80665 # m/s/s
- self.accelerometer = Vector3(0, 0, -self.gravity)
-
- self.wind = util.Wind('0,0,0')
- self.time_base = time.time()
- self.time_now = self.time_base + 100*1.0e-6
-
- self.gyro_noise = math.radians(0.1)
- self.accel_noise = 0.3
-
- def on_ground(self, position=None):
- """Return true if we are on the ground."""
- if position is None:
- position = self.position
- return (-position.z) + self.home_altitude <= self.ground_level + self.frame_height
-
- def update_position(self):
- """Update lat/lon/alt from position."""
-
- bearing = math.degrees(math.atan2(self.position.y, self.position.x))
- distance = math.sqrt(self.position.x**2 + self.position.y**2)
-
- (self.latitude, self.longitude) = util.gps_newpos(self.home_latitude, self.home_longitude,
- bearing, distance)
-
- self.altitude = self.home_altitude - self.position.z
-
- velocity_body = self.dcm.transposed() * self.velocity
-
- self.accelerometer = self.accel_body.copy()
-
- def set_yaw_degrees(self, yaw_degrees):
- """Rotate to the given yaw."""
- (roll, pitch, yaw) = self.dcm.to_euler()
- yaw = math.radians(yaw_degrees)
- self.dcm.from_euler(roll, pitch, yaw)
-
- def time_advance(self, deltat):
- """Advance time by deltat in seconds."""
- self.time_now += deltat
-
- def setup_frame_time(self, rate, speedup):
- """Setup frame_time calculation."""
- self.rate = rate
- self.speedup = speedup
- self.frame_time = 1.0/rate
- self.scaled_frame_time = self.frame_time/speedup
- self.last_wall_time = time.time()
- self.achieved_rate = rate
-
- def adjust_frame_time(self, rate):
- """Adjust frame_time calculation."""
- self.rate = rate
- self.frame_time = 1.0/rate
- self.scaled_frame_time = self.frame_time/self.speedup
-
- def sync_frame_time(self):
- """Try to synchronise simulation time with wall clock time, taking
- into account desired speedup."""
- now = time.time()
- if now < self.last_wall_time + self.scaled_frame_time:
- time.sleep(self.last_wall_time+self.scaled_frame_time - now)
- now = time.time()
-
- if now > self.last_wall_time and now - self.last_wall_time < 0.1:
- rate = 1.0/(now - self.last_wall_time)
- self.achieved_rate = (0.98*self.achieved_rate) + (0.02*rate)
- if self.achieved_rate < self.rate*self.speedup:
- self.scaled_frame_time *= 0.999
- else:
- self.scaled_frame_time *= 1.001
-
- self.last_wall_time = now
-
- def add_noise(self, throttle):
- """Add noise based on throttle level (from 0..1)."""
- self.gyro += Vector3(random.gauss(0, 1),
- random.gauss(0, 1),
- random.gauss(0, 1)) * throttle * self.gyro_noise
- self.accel_body += Vector3(random.gauss(0, 1),
- random.gauss(0, 1),
- random.gauss(0, 1)) * throttle * self.accel_noise
diff --git a/Tools/autotest/pysim/testwind.py b/Tools/autotest/pysim/testwind.py
deleted file mode 100755
index c76f68f3fc949d..00000000000000
--- a/Tools/autotest/pysim/testwind.py
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/usr/bin/env python
-"""
-simple test of wind generation code
-"""
-from __future__ import print_function
-import time
-import util
-from pymavlink.rotmat import Vector3
-
-wind = util.Wind('7,90,0.1')
-
-t0 = time.time()
-velocity = Vector3(0, 0, 0)
-
-t = 0
-deltat = 0.01
-
-while t < 60:
- print("%.4f %f" % (t, wind.drag(velocity, deltat=deltat).length()))
- t += deltat
diff --git a/Tools/autotest/pysim/util.py b/Tools/autotest/pysim/util.py
index 2776488c8526aa..cd028f756effa3 100644
--- a/Tools/autotest/pysim/util.py
+++ b/Tools/autotest/pysim/util.py
@@ -7,7 +7,6 @@
import atexit
import math
import os
-import random
import re
import shlex
import signal
@@ -15,11 +14,9 @@
import sys
import tempfile
import time
-from math import acos, atan2, cos, pi, sqrt
-import pexpect
-from pymavlink.rotmat import Vector3, Matrix3
+import pexpect
if sys.version_info[0] >= 3:
ENCODING = 'ascii'
@@ -403,6 +400,34 @@ def isalive(self):
return True
+class PSpawnStdPrettyPrinter(object):
+ '''a fake filehandle-like object which prefixes a string to all lines
+ before printing to stdout/stderr. To be used to pass to
+ pexpect.spawn's logfile argument
+ '''
+ def __init__(self, output=sys.stdout, prefix="stdout"):
+ self.output = output
+ self.prefix = prefix
+ self.buffer = ""
+
+ def close(self):
+ self.print_prefixed_line(self.buffer)
+
+ def write(self, data):
+ self.buffer += data
+ lines = self.buffer.split("\n")
+ self.buffer = lines[-1]
+ lines.pop()
+ for line in lines:
+ self.print_prefixed_line(line)
+
+ def print_prefixed_line(self, line):
+ print("%s: %s" % (self.prefix, line), file=self.output)
+
+ def flush(self):
+ pass
+
+
def start_SITL(binary,
valgrind=False,
callgrind=False,
@@ -413,6 +438,7 @@ def start_SITL(binary,
home=None,
model=None,
speedup=1,
+ sim_rate_hz=None,
defaults_filepath=None,
unhide_parameters=False,
gdbserver=False,
@@ -421,7 +447,8 @@ def start_SITL(binary,
customisations=[],
lldb=False,
enable_fgview_output=False,
- supplementary=False):
+ supplementary=False,
+ stdout_prefix=None):
if model is None and not supplementary:
raise ValueError("model must not be None")
@@ -479,7 +506,7 @@ def start_SITL(binary,
'-d',
'-m',
'-S', 'ardupilot-gdb',
- 'gdb', '-x', '/tmp/x.gdb', binary, '--args'])
+ 'gdb', '--cd', os.getcwd(), '-x', '/tmp/x.gdb', binary, '--args'])
elif lldb:
f = open("/tmp/x.lldb", "w")
for breakingpoint in breakpoints:
@@ -505,15 +532,10 @@ def start_SITL(binary,
if home is not None:
cmd.extend(['--home', home])
cmd.extend(['--model', model])
- if speedup != 1:
+ if speedup is not None and speedup != 1:
cmd.extend(['--speedup', str(speedup)])
- if defaults_filepath is not None:
- if type(defaults_filepath) == list:
- defaults = [reltopdir(path) for path in defaults_filepath]
- if len(defaults):
- cmd.extend(['--defaults', ",".join(defaults)])
- else:
- cmd.extend(['--defaults', reltopdir(defaults_filepath)])
+ if sim_rate_hz is not None:
+ cmd.extend(['--rate', str(sim_rate_hz)])
if unhide_parameters:
cmd.extend(['--unhide-groups'])
# somewhere for MAVProxy to connect to:
@@ -521,8 +543,21 @@ def start_SITL(binary,
if not enable_fgview_output:
cmd.append("--disable-fgview")
+ if defaults_filepath is not None:
+ if type(defaults_filepath) == list:
+ defaults = [reltopdir(path) for path in defaults_filepath]
+ if len(defaults):
+ cmd.extend(['--defaults', ",".join(defaults)])
+ else:
+ cmd.extend(['--defaults', reltopdir(defaults_filepath)])
+
cmd.extend(customisations)
+ pexpect_logfile_prefix = stdout_prefix
+ if pexpect_logfile_prefix is None:
+ pexpect_logfile_prefix = os.path.basename(binary)
+ pexpect_logfile = PSpawnStdPrettyPrinter(prefix=pexpect_logfile_prefix)
+
if (gdb or lldb) and sys.platform == "darwin" and os.getenv('DISPLAY'):
global windowID
# on MacOS record the window IDs so we can close them later
@@ -560,7 +595,7 @@ def start_SITL(binary,
# AP gets a redirect-stdout-to-filehandle option. So, in the
# meantime, return a dummy:
return pexpect.spawn("true", ["true"],
- logfile=sys.stdout,
+ logfile=pexpect_logfile,
encoding=ENCODING,
timeout=5)
else:
@@ -568,10 +603,8 @@ def start_SITL(binary,
first = cmd[0]
rest = cmd[1:]
- child = pexpect.spawn(first, rest, logfile=sys.stdout, encoding=ENCODING, timeout=5)
+ child = pexpect.spawn(first, rest, logfile=pexpect_logfile, encoding=ENCODING, timeout=5)
pexpect_autoclose(child)
- # give time for parameters to properly setup
- time.sleep(3)
if gdb or lldb:
# if we run GDB we do so in an xterm. "Waiting for
# connection" is never going to appear on xterm's output.
@@ -603,11 +636,15 @@ def MAVProxy_version():
def start_MAVProxy_SITL(atype,
aircraft=None,
setup=False,
- master='tcp:127.0.0.1:5762',
+ master=None,
options=[],
+ sitl_rcin_port=5501,
pexpect_timeout=60,
logfile=sys.stdout):
"""Launch mavproxy connected to a SITL instance."""
+ if master is None:
+ raise ValueError("Expected a master")
+
local_mp_modules_dir = os.path.abspath(
os.path.join(__file__, '..', '..', '..', 'mavproxy_modules'))
env = dict(os.environ)
@@ -616,11 +653,11 @@ def start_MAVProxy_SITL(atype,
if old is not None:
env['PYTHONPATH'] += os.path.pathsep + old
- import pexpect
global close_list
cmd = []
cmd.append(mavproxy_cmd())
cmd.extend(['--master', master])
+ cmd.extend(['--sitl', "localhost:%u" % sitl_rcin_port])
if setup:
cmd.append('--setup')
if aircraft is None:
@@ -641,8 +678,6 @@ def start_MAVProxy_SITL(atype,
def expect_setup_callback(e, callback):
"""Setup a callback that is called once a second while waiting for
patterns."""
- import pexpect
-
def _expect_callback(pattern, timeout=e.timeout):
tstart = time.time()
while time.time() < tstart + timeout:
@@ -707,51 +742,6 @@ def check_parent(parent_pid=None):
sys.exit(1)
-def EarthRatesToBodyRates(dcm, earth_rates):
- """Convert the angular velocities from earth frame to
- body frame. Thanks to James Goppert for the formula
-
- all inputs and outputs are in radians
-
- returns a gyro vector in body frame, in rad/s .
- """
- from math import sin, cos
-
- (phi, theta, psi) = dcm.to_euler()
- phiDot = earth_rates.x
- thetaDot = earth_rates.y
- psiDot = earth_rates.z
-
- p = phiDot - psiDot * sin(theta)
- q = cos(phi) * thetaDot + sin(phi) * psiDot * cos(theta)
- r = cos(phi) * psiDot * cos(theta) - sin(phi) * thetaDot
- return Vector3(p, q, r)
-
-
-def BodyRatesToEarthRates(dcm, gyro):
- """Convert the angular velocities from body frame to
- earth frame.
-
- all inputs and outputs are in radians/s
-
- returns a earth rate vector.
- """
- from math import sin, cos, tan, fabs
-
- p = gyro.x
- q = gyro.y
- r = gyro.z
-
- (phi, theta, psi) = dcm.to_euler()
-
- phiDot = p + tan(theta) * (q * sin(phi) + r * cos(phi))
- thetaDot = q * cos(phi) - r * sin(phi)
- if fabs(cos(theta)) < 1.0e-20:
- theta += 1.0e-10
- psiDot = (q * sin(phi) + r * cos(phi)) / cos(theta)
- return Vector3(phiDot, thetaDot, psiDot)
-
-
def gps_newpos(lat, lon, bearing, distance):
"""Extrapolate latitude/longitude given a heading and distance
thanks to http://www.movable-type.co.uk/scripts/latlong.html .
@@ -802,132 +792,6 @@ def gps_bearing(lat1, lon1, lat2, lon2):
return bearing
-class Wind(object):
- """A wind generation object."""
- def __init__(self, windstring, cross_section=0.1):
- a = windstring.split(',')
- if len(a) != 3:
- raise RuntimeError("Expected wind in speed,direction,turbulance form, not %s" % windstring)
- self.speed = float(a[0]) # m/s
- self.direction = float(a[1]) # direction the wind is going in
- self.turbulance = float(a[2]) # turbulance factor (standard deviation)
-
- # the cross-section of the aircraft to wind. This is multiplied by the
- # difference in the wind and the velocity of the aircraft to give the acceleration
- self.cross_section = cross_section
-
- # the time constant for the turbulance - the average period of the
- # changes over time
- self.turbulance_time_constant = 5.0
-
- # wind time record
- self.tlast = time.time()
-
- # initial turbulance multiplier
- self.turbulance_mul = 1.0
-
- def current(self, deltat=None):
- """Return current wind speed and direction as a tuple
- speed is in m/s, direction in degrees."""
- if deltat is None:
- tnow = time.time()
- deltat = tnow - self.tlast
- self.tlast = tnow
-
- # update turbulance random walk
- w_delta = math.sqrt(deltat) * (1.0 - random.gauss(1.0, self.turbulance))
- w_delta -= (self.turbulance_mul - 1.0) * (deltat / self.turbulance_time_constant)
- self.turbulance_mul += w_delta
- speed = self.speed * math.fabs(self.turbulance_mul)
- return speed, self.direction
-
- # Calculate drag.
- def drag(self, velocity, deltat=None):
- """Return current wind force in Earth frame. The velocity parameter is
- a Vector3 of the current velocity of the aircraft in earth frame, m/s ."""
- from math import radians
-
- # (m/s, degrees) : wind vector as a magnitude and angle.
- (speed, direction) = self.current(deltat=deltat)
- # speed = self.speed
- # direction = self.direction
-
- # Get the wind vector.
- w = toVec(speed, radians(direction))
-
- obj_speed = velocity.length()
-
- # Compute the angle between the object vector and wind vector by taking
- # the dot product and dividing by the magnitudes.
- d = w.length() * obj_speed
- if d == 0:
- alpha = 0
- else:
- alpha = acos((w * velocity) / d)
-
- # Get the relative wind speed and angle from the object. Note that the
- # relative wind speed includes the velocity of the object; i.e., there
- # is a headwind equivalent to the object's speed even if there is no
- # absolute wind.
- (rel_speed, beta) = apparent_wind(speed, obj_speed, alpha)
-
- # Return the vector of the relative wind, relative to the coordinate
- # system.
- relWindVec = toVec(rel_speed, beta + atan2(velocity.y, velocity.x))
-
- # Combine them to get the acceleration vector.
- return Vector3(acc(relWindVec.x, drag_force(self, relWindVec.x)), acc(relWindVec.y, drag_force(self, relWindVec.y)), 0)
-
-
-def apparent_wind(wind_sp, obj_speed, alpha):
- """http://en.wikipedia.org/wiki/Apparent_wind
-
- Returns apparent wind speed and angle of apparent wind. Alpha is the angle
- between the object and the true wind. alpha of 0 rads is a headwind; pi a
- tailwind. Speeds should always be positive."""
- delta = wind_sp * cos(alpha)
- x = wind_sp**2 + obj_speed**2 + 2 * obj_speed * delta
- rel_speed = sqrt(x)
- if rel_speed == 0:
- beta = pi
- else:
- beta = acos((delta + obj_speed) / rel_speed)
-
- return rel_speed, beta
-
-
-def drag_force(wind, sp):
- """See http://en.wikipedia.org/wiki/Drag_equation
-
- Drag equation is F(a) = cl * p/2 * v^2 * a, where cl : drag coefficient
- (let's assume it's low, .e.g., 0.2), p : density of air (assume about 1
- kg/m^3, the density just over 1500m elevation), v : relative speed of wind
- (to the body), a : area acted on (this is captured by the cross_section
- parameter).
-
- So then we have
- F(a) = 0.2 * 1/2 * v^2 * cross_section = 0.1 * v^2 * cross_section."""
- return (sp**2.0) * 0.1 * wind.cross_section
-
-
-def acc(val, mag):
- """ Function to make the force vector. relWindVec is the direction the apparent
- wind comes *from*. We want to compute the accleration vector in the direction
- the wind blows to."""
- if val == 0:
- return mag
- else:
- return (val / abs(val)) * (0 - mag)
-
-
-def toVec(magnitude, angle):
- """Converts a magnitude and angle (radians) to a vector in the xy plane."""
- v = Vector3(magnitude, 0, 0)
- m = Matrix3()
- m.from_euler(0, 0, angle)
- return m.transposed() * v
-
-
def constrain(value, minv, maxv):
"""Constrain a value to a range."""
if value < minv:
diff --git a/Tools/autotest/pysim/vehicleinfo.py b/Tools/autotest/pysim/vehicleinfo.py
index fbcb2b54df0d60..9709dcd917e0d2 100644
--- a/Tools/autotest/pysim/vehicleinfo.py
+++ b/Tools/autotest/pysim/vehicleinfo.py
@@ -149,6 +149,11 @@ def __init__(self):
"waf_target": "bin/arducopter-heli",
"default_params_filename": "default_params/copter-heli.parm",
},
+ "heli-gas": {
+ "waf_target": "bin/arducopter-heli",
+ "default_params_filename": ["default_params/copter-heli.parm",
+ "default_params/copter-heli-gas.parm"],
+ },
"heli-dual": {
"waf_target": "bin/arducopter-heli",
"default_params_filename": ["default_params/copter-heli.parm",
@@ -183,6 +188,11 @@ def __init__(self):
"default_params_filename": ["default_params/copter.parm",
"models/Callisto.param"],
},
+ "quad-can": {
+ "waf_target": "bin/arducopter",
+ "default_params_filename": ["default_params/copter.parm", "default_params/quad-can.parm"],
+ "periph_params_filename": ["default_params/periph.parm", "default_params/quad-periph.parm"],
+ },
},
},
"Helicopter": {
@@ -192,6 +202,11 @@ def __init__(self):
"waf_target": "bin/arducopter-heli",
"default_params_filename": "default_params/copter-heli.parm",
},
+ "heli-gas": {
+ "waf_target": "bin/arducopter-heli",
+ "default_params_filename": ["default_params/copter-heli.parm",
+ "default_params/copter-heli-gas.parm"],
+ },
"heli-dual": {
"waf_target": "bin/arducopter-heli",
"default_params_filename": ["default_params/copter-heli.parm",
@@ -250,6 +265,11 @@ def __init__(self):
"waf_target": "bin/arduplane",
"default_params_filename": ["default_params/quadplane.parm", "default_params/plane-ice.parm", "default_params/quadplane-ice.parm"],
},
+ "quadplane-can": {
+ "waf_target": "bin/arduplane",
+ "default_params_filename": ["default_params/quadplane.parm", "default_params/quadplane-can.parm"],
+ "periph_params_filename": ["default_params/periph.parm", "default_params/quadplane-periph.parm"],
+ },
"firefly": {
"waf_target": "bin/arduplane",
"default_params_filename": "default_params/firefly.parm",
@@ -409,6 +429,7 @@ def __init__(self):
"gps": {
"configure_target": "sitl_periph_gps",
"waf_target": "bin/AP_Periph",
+ "default_params_filename": "default_params/periph.parm",
},
}
},
diff --git a/Tools/autotest/quadplane.py b/Tools/autotest/quadplane.py
index 9168130492cc17..afedf93ce76103 100644
--- a/Tools/autotest/quadplane.py
+++ b/Tools/autotest/quadplane.py
@@ -388,17 +388,20 @@ def fly_qautotune(self):
break
self.wait_disarmed()
- def takeoff(self, height, mode):
+ def takeoff(self, height, mode, timeout=30):
"""climb to specified height and set throttle to 1500"""
self.set_current_waypoint(0, check_afterwards=False)
self.change_mode(mode)
self.wait_ready_to_arm()
self.arm_vehicle()
+ if mode == 'GUIDED':
+ self.user_takeoff(alt_min=height, timeout=timeout)
+ return
self.set_rc(3, 1800)
self.wait_altitude(height,
height+5,
relative=True,
- timeout=30)
+ timeout=timeout)
self.set_rc(3, 1500)
def do_RTL(self):
@@ -894,6 +897,19 @@ def LoiterAltQLand_Terrain(self,
self.reset_SITL_commandline()
self.context_pop()
+ def GUIDEDToAUTO(self):
+ '''Test using GUIDED mode for takeoff before shifting to auto'''
+ self.load_mission("mission.txt")
+ self.takeoff(30, mode='GUIDED')
+
+ # extra checks would go here
+ self.assert_not_receiving_message('CAMERA_FEEDBACK')
+
+ self.change_mode('AUTO')
+ self.wait_current_waypoint(3)
+ self.change_mode('QRTL')
+ self.wait_disarmed(timeout=240)
+
def Tailsitter(self):
'''tailsitter test'''
self.set_parameter('Q_FRAME_CLASS', 10)
@@ -1227,6 +1243,7 @@ def tests(self):
self.ICEngine,
self.ICEngineMission,
self.MidAirDisarmDisallowed,
+ self.GUIDEDToAUTO,
self.BootInAUTO,
self.Ship,
self.MAV_CMD_NAV_LOITER_TO_ALT,
diff --git a/Tools/autotest/rover.py b/Tools/autotest/rover.py
index 64e83424f12705..e9fd5376daa3c1 100644
--- a/Tools/autotest/rover.py
+++ b/Tools/autotest/rover.py
@@ -320,27 +320,13 @@ def Sprayer(self):
self.start_subtest("Checking mavlink commands")
self.change_mode("MANUAL")
self.progress("Starting Sprayer")
- self.run_cmd(mavutil.mavlink.MAV_CMD_DO_SPRAYER,
- 1, # p1
- 0, # p2
- 0, # p3
- 0, # p4
- 0, # p5
- 0, # p6
- 0) # p7
+ self.run_cmd(mavutil.mavlink.MAV_CMD_DO_SPRAYER, p1=1)
self.progress("Testing speed-ramping")
self.set_rc(3, 1700) # start driving forward
self.wait_servo_channel_value(pump_ch, 1690, timeout=60, comparator=operator.gt)
self.start_subtest("Stopping Sprayer")
- self.run_cmd(mavutil.mavlink.MAV_CMD_DO_SPRAYER,
- 0, # p1
- 0, # p2
- 0, # p3
- 0, # p4
- 0, # p5
- 0, # p6
- 0) # p7
+ self.run_cmd(mavutil.mavlink.MAV_CMD_DO_SPRAYER, p1=0)
self.wait_servo_channel_value(pump_ch, pump_ch_min)
self.set_rc(3, 1000) # start driving forward
@@ -356,38 +342,21 @@ def Sprayer(self):
def DriveMaxRCIN(self, timeout=30):
"""Drive rover at max RC inputs"""
- self.context_push()
- ex = None
-
- try:
- self.progress("Testing max RC inputs")
- self.change_mode("MANUAL")
-
- self.wait_ready_to_arm()
- self.arm_vehicle()
-
- self.set_rc(3, 2000)
- self.set_rc(1, 1000)
+ self.progress("Testing max RC inputs")
+ self.change_mode("MANUAL")
- tstart = self.get_sim_time()
- while self.get_sim_time_cached() - tstart < timeout:
- m = self.mav.recv_match(type='VFR_HUD', blocking=True, timeout=1)
- if m is not None:
- self.progress("Current speed: %f" % m.groundspeed)
+ self.wait_ready_to_arm()
+ self.arm_vehicle()
- # reduce throttle
- self.set_rc(3, 1500)
- self.set_rc(1, 1500)
+ self.set_rc(3, 2000)
+ self.set_rc(1, 1000)
- except Exception as e:
- self.print_exception_caught(e)
- ex = e
+ tstart = self.get_sim_time()
+ while self.get_sim_time_cached() - tstart < timeout:
+ m = self.assert_receive_message('VFR_HUD')
+ self.progress("Current speed: %f" % m.groundspeed)
self.disarm_vehicle()
- self.context_pop()
-
- if ex:
- raise ex
#################################################
# AUTOTEST ALL
@@ -621,11 +590,61 @@ def ServoRelayEvents(self):
raise NotAchievedException(
"Pin mask unchanged after relay cmd")
self.progress("Pin mask changed after relay command")
+ self.do_set_relay(0, 0)
+
+ self.set_message_rate_hz("RELAY_STATUS", 10)
+
+ # default configuration for relays in sim have one relay:
+ self.assert_received_message_field_values('RELAY_STATUS', {
+ "present": 3,
+ "on": 0,
+ })
+ self.do_set_relay(0, 1)
+ self.assert_received_message_field_values('RELAY_STATUS', {
+ "present": 3,
+ "on": 1,
+ })
+ self.do_set_relay(1, 1)
+ self.assert_received_message_field_values('RELAY_STATUS', {
+ "present": 3,
+ "on": 3,
+ })
+ self.do_set_relay(0, 0)
+ self.do_set_relay(1, 0)
+ self.assert_received_message_field_values('RELAY_STATUS', {
+ "present": 3,
+ "on": 0,
+ })
+
+ # add another servo:
+ self.set_parameter("RELAY_PIN6", 14)
+ self.assert_received_message_field_values('RELAY_STATUS', {
+ "present": 35,
+ "on": 0,
+ })
+ self.do_set_relay(5, 1)
+ self.assert_received_message_field_values('RELAY_STATUS', {
+ "present": 35,
+ "on": 32,
+ })
+ self.do_set_relay(0, 1)
+ self.assert_received_message_field_values('RELAY_STATUS', {
+ "present": 35,
+ "on": 33,
+ })
+ self.do_set_relay(5, 0)
+ self.assert_received_message_field_values('RELAY_STATUS', {
+ "present": 35,
+ "on": 1,
+ })
+
+ self.set_message_rate_hz("RELAY_STATUS", 0)
def MAVProxy_SetModeUsingSwitch(self):
"""Set modes via mavproxy switch"""
+ port = self.sitl_rcin_port(offset=1)
self.customise_SITL_commandline([
- "--rc-in-port", "5502",
+ "--rc-in-port", str(port),
])
ex = None
try:
@@ -637,7 +656,7 @@ def MAVProxy_SetModeUsingSwitch(self):
(4, 'AUTO'),
(5, 'AUTO'), # non-existant mode, should stay in RTL
(6, 'MANUAL')]
- mavproxy = self.start_mavproxy()
+ mavproxy = self.start_mavproxy(sitl_rcin_port=port)
for (num, expected) in fnoo:
mavproxy.send('switch %u\n' % num)
self.wait_mode(expected)
@@ -1194,7 +1213,7 @@ def DO_SET_MODE(self):
self.do_set_mode_via_command_long("HOLD")
self.do_set_mode_via_command_long("MANUAL")
- def InitialMode(self):
+ def RoverInitialMode(self):
'''test INITIAL_MODE parameter works'''
# from mavproxy_rc.py
self.wait_ready_to_arm()
@@ -4772,13 +4791,12 @@ def MotorTest(self):
self.wait_ready_to_arm()
self.run_cmd(
mavutil.mavlink.MAV_CMD_DO_MOTOR_TEST,
- 1, # p1 - motor instance
- mavutil.mavlink.MOTOR_TEST_THROTTLE_PWM, # p2 - throttle type
- magic_throttle_value, # p3 - throttle
- 5, # p4 - timeout
- 1, # p5 - motor count
- 0, # p6 - test order (see MOTOR_TEST_ORDER)
- 0, # p7
+ p1=1, # motor instance
+ p2=mavutil.mavlink.MOTOR_TEST_THROTTLE_PWM, # throttle type
+ p3=magic_throttle_value, # throttle
+ p4=5, # timeout
+ p5=1, # motor count
+ p6=0, # test order (see MOTOR_TEST_ORDER)
)
self.wait_armed()
self.progress("Waiting for magic throttle value")
@@ -5220,15 +5238,19 @@ def test_scripting_internal_test(self):
self.context_push()
- test_scripts = ["scripting_test.lua", "math.lua", "strings.lua"]
- success_text = ["Internal tests passed", "Math tests passed", "String tests passed"]
+ test_scripts = ["scripting_test.lua", "math.lua", "strings.lua", "mavlink_test.lua"]
+ success_text = ["Internal tests passed", "Math tests passed", "String tests passed", "Received heartbeat from"]
+ named_value_float_types = ["test"]
messages = []
+ named_value_float = []
def my_message_hook(mav, message):
- if message.get_type() != 'STATUSTEXT':
- return
- messages.append(message)
+ if message.get_type() == 'STATUSTEXT':
+ messages.append(message)
+ # also sniff for named value float messages
+ if message.get_type() == 'NAMED_VALUE_FLOAT':
+ named_value_float.append(message)
self.install_message_hook_context(my_message_hook)
self.set_parameters({
@@ -5236,6 +5258,8 @@ def my_message_hook(mav, message):
"SCR_HEAP_SIZE": 1024000,
"SCR_VM_I_COUNT": 1000000,
})
+ self.install_test_modules_context()
+ self.install_mavlink_module_context()
for script in test_scripts:
self.install_test_script_context(script)
self.reboot_sitl()
@@ -5253,9 +5277,21 @@ def my_message_hook(mav, message):
if text in m.text:
script_success = True
success = script_success and success
- self.progress("Success")
if not success:
- raise NotAchievedException("Scripting internal test failed")
+ raise NotAchievedException("Failed to receive STATUS_TEXT")
+ else:
+ self.progress("Success STATUS_TEXT")
+
+ for type in named_value_float_types:
+ script_success = False
+ for m in named_value_float:
+ if type == m.name:
+ script_success = True
+ success = script_success and success
+ if not success:
+ raise NotAchievedException("Failed to receive NAMED_VALUE_FLOAT")
+ else:
+ self.progress("Success NAMED_VALUE_FLOAT")
def test_scripting_hello_world(self):
self.start_subtest("Scripting hello world")
@@ -5910,18 +5946,14 @@ def MAV_CMD_DO_SET_MISSION_CURRENT(self, target_sysid=None, target_compid=1):
self.set_current_waypoint_using_mav_cmd_do_set_mission_current(2)
- self.run_cmd(mavutil.mavlink.MAV_CMD_DO_SET_MISSION_CURRENT,
- 17,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- timeout=1,
- target_sysid=target_sysid,
- target_compid=target_compid,
- want_result=mavutil.mavlink.MAV_RESULT_FAILED)
+ self.run_cmd(
+ mavutil.mavlink.MAV_CMD_DO_SET_MISSION_CURRENT,
+ p1=17,
+ timeout=1,
+ target_sysid=target_sysid,
+ target_compid=target_compid,
+ want_result=mavutil.mavlink.MAV_RESULT_FAILED,
+ )
def FlashStorage(self):
'''Test flash storage (for parameters etc)'''
@@ -6180,7 +6212,8 @@ def AutoDock(self):
def PrivateChannel(self):
'''test the serial option bit specifying a mavlink channel as private'''
global mav2
- mav2 = mavutil.mavlink_connection("tcp:localhost:5763",
+ port = self.adjust_ardupilot_port(5763)
+ mav2 = mavutil.mavlink_connection("tcp:localhost:%u" % port,
robust_parsing=True,
source_system=7,
source_component=7)
@@ -6281,6 +6314,84 @@ def printmessage(mav, m):
# both the vehicle and this tests's special heartbeat
raise NotAchievedException("Got heartbeat on private channel from non-vehicle")
+ def MAV_CMD_DO_SET_REVERSE(self):
+ '''test MAV_CMD_DO_SET_REVERSE command'''
+ self.change_mode('GUIDED')
+ self.wait_ready_to_arm()
+ self.arm_vehicle()
+
+ here = self.mav.location()
+ target_loc = self.offset_location_ne(here, 2000, 0)
+ self.send_guided_mission_item(target_loc)
+
+ self.wait_groundspeed(3, 100, minimum_duration=5)
+
+ for method in self.run_cmd, self.run_cmd_int:
+ self.progress("Forwards!")
+ method(mavutil.mavlink.MAV_CMD_DO_SET_REVERSE, p1=0)
+ self.wait_heading(0)
+
+ self.progress("Backwards!")
+ method(mavutil.mavlink.MAV_CMD_DO_SET_REVERSE, p1=1)
+ self.wait_heading(180)
+
+ self.progress("Forwards!")
+ method(mavutil.mavlink.MAV_CMD_DO_SET_REVERSE, p1=0)
+ self.wait_heading(0)
+
+ self.disarm_vehicle()
+
+ def MAV_CMD_NAV_RETURN_TO_LAUNCH(self):
+ '''test MAV_CMD_NAV_RETURN_TO_LAUNCH mavlink command'''
+ self.change_mode('GUIDED')
+ self.wait_ready_to_arm()
+ self.arm_vehicle()
+
+ here = self.mav.location()
+ target_loc = self.offset_location_ne(here, 2000, 0)
+ self.send_guided_mission_item(target_loc)
+ self.wait_distance_to_home(20, 100)
+
+ self.run_cmd(mavutil.mavlink.MAV_CMD_NAV_RETURN_TO_LAUNCH)
+ self.wait_mode('RTL')
+
+ self.change_mode('GUIDED')
+
+ self.run_cmd_int(mavutil.mavlink.MAV_CMD_NAV_RETURN_TO_LAUNCH)
+ self.wait_mode('RTL')
+
+ self.wait_distance_to_home(0, 5, timeout=30)
+ self.disarm_vehicle()
+
+ def MAV_CMD_DO_CHANGE_SPEED(self):
+ '''test MAV_CMD_NAV_RETURN_TO_LAUNCH mavlink command'''
+ self.change_mode('GUIDED')
+ self.wait_ready_to_arm()
+ self.arm_vehicle()
+
+ original_loc = self.mav.location()
+ here = original_loc
+ target_loc = self.offset_location_ne(here, 2000, 0)
+ self.send_guided_mission_item(target_loc)
+ self.wait_distance_to_home(20, 100)
+
+ speeds = 3, 7, 12, 4
+
+ for speed in speeds:
+ self.run_cmd(mavutil.mavlink.MAV_CMD_DO_CHANGE_SPEED, p2=speed)
+ self.wait_groundspeed(speed-0.5, speed+0.5, minimum_duration=5)
+
+ self.send_guided_mission_item(original_loc)
+
+ for speed in speeds:
+ self.run_cmd_int(mavutil.mavlink.MAV_CMD_DO_CHANGE_SPEED, p2=speed)
+ self.wait_groundspeed(speed-0.5, speed+0.5, minimum_duration=5)
+
+ self.change_mode('RTL')
+
+ self.wait_distance_to_home(0, 5, timeout=30)
+ self.disarm_vehicle()
+
def tests(self):
'''return list of all tests'''
ret = super(AutoTestRover, self).tests()
@@ -6294,7 +6405,6 @@ def tests(self):
self.DriveRTL,
self.SmartRTL,
self.DriveSquare,
- self.DriveMaxRCIN,
self.DriveMission,
# self.DriveBrake, # disabled due to frequent failures
self.GetBanner,
@@ -6315,6 +6425,7 @@ def tests(self):
self.SET_ATTITUDE_TARGET,
self.SET_POSITION_TARGET_LOCAL_NED,
self.MAV_CMD_DO_SET_MISSION_CURRENT,
+ self.MAV_CMD_DO_CHANGE_SPEED,
self.Button,
self.Rally,
self.Offboard,
@@ -6348,12 +6459,16 @@ def tests(self):
self.DepthFinder,
self.ChangeModeByNumber,
self.EStopAtBoot,
+ self.MAV_CMD_NAV_RETURN_TO_LAUNCH,
self.StickMixingAuto,
self.AutoDock,
self.PrivateChannel,
self.GCSFailsafe,
- self.InitialMode,
+ self.RoverInitialMode,
self.DriveMaxRCIN,
+ self.NoArmWithoutMissionItems,
+ self.CompassPrearms,
+ self.MAV_CMD_DO_SET_REVERSE,
])
return ret
diff --git a/Tools/autotest/run_in_terminal_window.sh b/Tools/autotest/run_in_terminal_window.sh
index 86bd86a2d16200..7a83f1c565dacd 100755
--- a/Tools/autotest/run_in_terminal_window.sh
+++ b/Tools/autotest/run_in_terminal_window.sh
@@ -43,7 +43,7 @@ elif [ -n "$DISPLAY" -a -n "$(which gnome-terminal)" ]; then
gnome-terminal -e "$*"
elif [ -n "$STY" ]; then
# We are running inside of screen, try to start it there
- screen -X screen -t "$name" $*
+ screen -X screen -t "$name" bash -c "cd $PWD; $*"
else
filename="/tmp/$name.log"
echo "RiTW: Window access not found, logging to $filename"
diff --git a/Tools/autotest/run_mission.py b/Tools/autotest/run_mission.py
new file mode 100755
index 00000000000000..99a0bc519868f5
--- /dev/null
+++ b/Tools/autotest/run_mission.py
@@ -0,0 +1,107 @@
+#!/usr/bin/python3
+
+'''
+Run a mission in SITL
+
+AP_FLAKE8_CLEAN
+'''
+
+import common
+import os
+import sys
+import argparse
+
+from pysim import util
+
+
+class RunMission(common.AutoTest):
+ def __init__(self, vehicle_binary, model, mission_filepath, speedup=None, sim_rate_hz=None):
+ super(RunMission, self).__init__(vehicle_binary)
+ self.mission_filepath = mission_filepath
+ self.model = model
+ self.speedup = speedup
+ self.sim_rate_hz = sim_rate_hz
+
+ if self.speedup is None:
+ self.speedup = 100
+
+ def vehicleinfo_key(self):
+ '''magically guess vehicleinfo_key from filepath'''
+ path = self.binary.lower()
+ if "plane" in path:
+ return "ArduPlane"
+ if "copter" in path:
+ return "ArduCopter"
+ raise ValueError("Can't determine vehicleinfo_key from binary path")
+
+ def run(self):
+ self.start_SITL(
+ binary=self.binary,
+ model=self.model,
+ sitl_home=self.sitl_home_string_from_mission_filepath(self.mission_filepath),
+ speedup=self.speedup,
+ sim_rate_hz=self.sim_rate_hz,
+ defaults_filepath=self.model_defaults_filepath(self.model),
+ )
+ self.get_mavlink_connection_going()
+
+ # hack; Plane defaults are annoying... we should do better
+ # here somehow.
+ if self.vehicleinfo_key() == "ArduPlane":
+ self.set_parameter("RTL_AUTOLAND", 1)
+
+ self.load_mission_from_filepath(self.mission_filepath, strict=False)
+ self.change_mode('AUTO')
+ self.set_streamrate(1)
+ self.wait_ready_to_arm()
+ self.arm_vehicle()
+ self.wait_disarmed(timeout=600)
+ self.stop_SITL()
+
+
+if __name__ == "__main__":
+ ''' main program '''
+ os.environ['PYTHONUNBUFFERED'] = '1'
+
+ if sys.platform != "darwin":
+ os.putenv('TMPDIR', util.reltopdir('tmp'))
+
+ parser = argparse.ArgumentParser("run_mission.py")
+ parser.add_argument(
+ 'vehicle_binary',
+ type=str,
+ help='vehicle binary to use'
+ )
+ parser.add_argument(
+ 'model',
+ type=str,
+ help='vehicle model to use'
+ )
+ parser.add_argument(
+ 'mission_filepath',
+ type=str,
+ help='mission file path'
+ )
+ parser.add_argument(
+ '--speedup',
+ type=int,
+ help='simulation speedup',
+ default=None,
+ )
+ parser.add_argument(
+ '--sim-rate-hz',
+ type=int,
+ help='simulation physics rate',
+ default=None,
+ )
+
+ args = parser.parse_args()
+
+ x = RunMission(
+ args.vehicle_binary,
+ args.model,
+ args.mission_filepath,
+ speedup=args.speedup,
+ sim_rate_hz=args.sim_rate_hz
+ )
+ x.run()
diff --git a/Tools/autotest/sim_vehicle.py b/Tools/autotest/sim_vehicle.py
index 6a788cb5bfb76f..61f8a08453354a 100755
--- a/Tools/autotest/sim_vehicle.py
+++ b/Tools/autotest/sim_vehicle.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
"""
Framework to start a simulated vehicle and connect it to MAVProxy.
@@ -415,7 +415,8 @@ def do_build(opts, frame_options):
for piece in pieces:
cmd_configure.extend(piece)
- run_cmd_blocking("Configure waf", cmd_configure, check=True)
+ if not cmd_opts.no_configure:
+ run_cmd_blocking("Configure waf", cmd_configure, check=True)
if opts.clean:
run_cmd_blocking("Building clean", [waf_light, "clean"])
@@ -646,13 +647,10 @@ def start_antenna_tracker(opts):
oldpwd = os.getcwd()
os.chdir(vehicledir)
tracker_uarta = "tcp:127.0.0.1:" + str(5760 + 10 * tracker_instance)
- if cmd_opts.build_system == "waf":
- binary_basedir = "build/sitl"
- exe = os.path.join(root_dir,
- binary_basedir,
- "bin/antennatracker")
- else:
- exe = os.path.join(vehicledir, "AntennaTracker.elf")
+ binary_basedir = "build/sitl"
+ exe = os.path.join(root_dir,
+ binary_basedir,
+ "bin/antennatracker")
run_in_terminal_window("AntennaTracker",
["nice",
exe,
@@ -662,13 +660,24 @@ def start_antenna_tracker(opts):
os.chdir(oldpwd)
-def start_CAN_GPS(opts):
- """Compile and run the sitl_periph_gps"""
+def start_CAN_Periph(opts, frame_info):
+ """Compile and run the sitl_periph"""
global can_uarta
progress("Preparing sitl_periph_gps")
options = vinfo.options["sitl_periph_gps"]['frames']['gps']
- do_build(opts, options)
+ defaults_path = frame_info.get('periph_params_filename', None)
+ if defaults_path is None:
+ defaults_path = options.get('default_params_filename', None)
+
+ if not isinstance(defaults_path, list):
+ defaults_path = [defaults_path]
+
+ # add in path and make a comma separated list
+ defaults_path = ','.join([util.relcurdir(os.path.join(autotest_dir, p)) for p in defaults_path])
+
+ if not cmd_opts.no_rebuild:
+ do_build(opts, options)
exe = os.path.join(root_dir, 'build/sitl_periph_gps', 'bin/AP_Periph')
cmd = ["nice"]
cmd_name = "sitl_periph_gps"
@@ -691,6 +700,9 @@ def start_CAN_GPS(opts):
cmd.extend(["-x", gdb_commands_file.name])
cmd.append("--args")
cmd.append(exe)
+ if defaults_path is not None:
+ cmd.append("--defaults")
+ cmd.append(defaults_path)
run_in_terminal_window(cmd_name, cmd)
@@ -771,7 +783,7 @@ def start_vehicle(binary, opts, stuff, spawns=None):
print("The parameter file (%s) does not exist" % (x,))
sys.exit(1)
path = ",".join(paths)
- if cmd_opts.count > 1:
+ if cmd_opts.count > 1 or opts.auto_sysid:
# we are in a subdirectory when using -n
path = os.path.join("..", path)
progress("Using defaults from (%s)" % (path,))
@@ -860,7 +872,7 @@ def start_mavproxy(opts, stuff):
for i in instances:
if not opts.no_extra_ports:
- ports = [p + 10 * i for p in [14550, 14551]]
+ ports = [14550 + 10 * i]
for port in ports:
if under_vagrant():
# We're running inside of a vagrant guest; forward our
@@ -1031,6 +1043,10 @@ def generate_frame_help():
action='store_true',
default=False,
help="don't rebuild before starting ardupilot")
+group_build.add_option("--no-configure",
+ action='store_true',
+ default=False,
+ help="don't run waf configure before building")
group_build.add_option("-D", "--debug",
action='store_true',
default=False,
@@ -1048,11 +1064,6 @@ def generate_frame_help():
default=None,
type='string',
help="override SITL build target")
-group_build.add_option("-s", "--build-system",
- default="waf",
- type='choice',
- choices=["make", "waf"],
- help="build system to use")
group_build.add_option("--enable-math-check-indexes",
default=False,
action="store_true",
@@ -1134,10 +1145,10 @@ def generate_frame_help():
group_sim.add_option("", "--enable-onvif",
action="store_true",
help="enable onvif camera control sim using AntennaTracker")
-group_sim.add_option("", "--can-gps",
+group_sim.add_option("", "--can-peripherals",
action='store_true',
default=False,
- help="start a DroneCAN GPS instance (use Tools/scripts/CAN/can_sitl_nodev.sh first)")
+ help="start a DroneCAN peripheral instance (use Tools/scripts/CAN/can_sitl_nodev.sh first)")
group_sim.add_option("-A", "--sitl-instance-args",
type='string',
default=None,
@@ -1475,8 +1486,8 @@ def generate_frame_help():
if cmd_opts.tracker:
start_antenna_tracker(cmd_opts)
-if cmd_opts.can_gps:
- start_CAN_GPS(cmd_opts)
+if cmd_opts.can_peripherals or frame_infos.get('periph_params_filename', None) is not None:
+ start_CAN_Periph(cmd_opts, frame_infos)
if cmd_opts.custom_location:
location = [(float)(x) for x in cmd_opts.custom_location.split(",")]
@@ -1540,13 +1551,11 @@ def generate_frame_help():
if cmd_opts.vehicle_binary is not None:
vehicle_binary = cmd_opts.vehicle_binary
- elif cmd_opts.build_system == "waf":
+ else:
binary_basedir = "build/sitl"
vehicle_binary = os.path.join(root_dir,
binary_basedir,
frame_infos["waf_target"])
- else:
- vehicle_binary = os.path.join(vehicle_dir, cmd_opts.vehicle + ".elf")
if not os.path.exists(vehicle_binary):
print("Vehicle binary (%s) does not exist" % (vehicle_binary,))
diff --git a/Tools/autotest/test_build_options.py b/Tools/autotest/test_build_options.py
index bb665a20135f7f..839269415554c9 100755
--- a/Tools/autotest/test_build_options.py
+++ b/Tools/autotest/test_build_options.py
@@ -74,7 +74,14 @@ def must_have_defines_for_board(self, board):
'AP_COMPASS_AK8963_ENABLED',
'AP_COMPASS_AK09916_ENABLED',
'AP_COMPASS_ICM20948_ENABLED',
- ])
+ ]),
+ "CubeBlack": frozenset([
+ 'AP_BARO_MS56XX_ENABLED',
+ 'AP_COMPASS_LSM303D_ENABLED',
+ 'AP_COMPASS_AK8963_ENABLED',
+ 'AP_COMPASS_AK09916_ENABLED',
+ 'AP_COMPASS_ICM20948_ENABLED',
+ ]),
}
return must_have_defines.get(board, frozenset([]))
@@ -294,12 +301,13 @@ def disable_in_turn_check_sizes(self, feature, sizes_nothing_disabled):
def run_disable_in_turn(self):
options = self.get_build_options_from_ardupilot_tree()
- if self.match_glob is not None:
- options = list(filter(lambda x : fnmatch.fnmatch(x.define, self.match_glob), options))
count = 1
for feature in sorted(options, key=lambda x : x.define):
+ if self.match_glob is not None:
+ if not fnmatch.fnmatch(feature.define, self.match_glob):
+ continue
with open("/tmp/run-disable-in-turn-progress", "w") as f:
- print(f.write(f"{count}/{len(options)} {feature.define}\n"))
+ f.write(f"{count}/{len(options)} {feature.define}\n")
# if feature.define < "WINCH_ENABLED":
# count += 1
# continue
@@ -316,12 +324,15 @@ def run_disable_in_turn(self):
def run_enable_in_turn(self):
options = self.get_build_options_from_ardupilot_tree()
- if self.match_glob is not None:
- options = list(filter(lambda x : fnmatch.fnmatch(x.define, self.match_glob), options))
count = 1
for feature in options:
+ if self.match_glob is not None:
+ if not fnmatch.fnmatch(feature.define, self.match_glob):
+ continue
self.progress("Enabling feature %s(%s) (%u/%u)" %
(feature.label, feature.define, count, len(options)))
+ with open("/tmp/run-enable-in-turn-progress", "w") as f:
+ f.write(f"{count}/{len(options)} {feature.define}\n")
self.test_enable_feature(feature, options)
count += 1
diff --git a/Tools/autotest/web-firmware/Tools/FilterTool/FileSaver.js b/Tools/autotest/web-firmware/Tools/FilterTool/FileSaver.js
deleted file mode 100644
index 5d204aee15a8d7..00000000000000
--- a/Tools/autotest/web-firmware/Tools/FilterTool/FileSaver.js
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
-* FileSaver.js
-* A saveAs() FileSaver implementation.
-*
-* By Eli Grey, http://eligrey.com
-*
-* License : https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md (MIT)
-* source : http://purl.eligrey.com/github/FileSaver.js
-*/
-
-// The one and only way of getting global scope in all environments
-// https://stackoverflow.com/q/3277182/1008999
-var _global = typeof window === 'object' && window.window === window
- ? window : typeof self === 'object' && self.self === self
- ? self : typeof global === 'object' && global.global === global
- ? global
- : this
-
-function bom (blob, opts) {
- if (typeof opts === 'undefined') opts = { autoBom: false }
- else if (typeof opts !== 'object') {
- console.warn('Deprecated: Expected third argument to be a object')
- opts = { autoBom: !opts }
- }
-
- // prepend BOM for UTF-8 XML and text/* types (including HTML)
- // note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF
- if (opts.autoBom && /^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) {
- return new Blob([String.fromCharCode(0xFEFF), blob], { type: blob.type })
- }
- return blob
-}
-
-function download (url, name, opts) {
- var xhr = new XMLHttpRequest()
- xhr.open('GET', url)
- xhr.responseType = 'blob'
- xhr.onload = function () {
- saveAs(xhr.response, name, opts)
- }
- xhr.onerror = function () {
- console.error('could not download file')
- }
- xhr.send()
-}
-
-function corsEnabled (url) {
- var xhr = new XMLHttpRequest()
- // use sync to avoid popup blocker
- xhr.open('HEAD', url, false)
- try {
- xhr.send()
- } catch (e) {}
- return xhr.status >= 200 && xhr.status <= 299
-}
-
-// `a.click()` doesn't work for all browsers (#465)
-function click (node) {
- try {
- node.dispatchEvent(new MouseEvent('click'))
- } catch (e) {
- var evt = document.createEvent('MouseEvents')
- evt.initMouseEvent('click', true, true, window, 0, 0, 0, 80,
- 20, false, false, false, false, 0, null)
- node.dispatchEvent(evt)
- }
-}
-
-// Detect WebView inside a native macOS app by ruling out all browsers
-// We just need to check for 'Safari' because all other browsers (besides Firefox) include that too
-// https://www.whatismybrowser.com/guides/the-latest-user-agent/macos
-var isMacOSWebView = _global.navigator && /Macintosh/.test(navigator.userAgent) && /AppleWebKit/.test(navigator.userAgent) && !/Safari/.test(navigator.userAgent)
-
-var saveAs = _global.saveAs || (
- // probably in some web worker
- (typeof window !== 'object' || window !== _global)
- ? function saveAs () { /* noop */ }
-
- // Use download attribute first if possible (#193 Lumia mobile) unless this is a macOS WebView
- : ('download' in HTMLAnchorElement.prototype && !isMacOSWebView)
- ? function saveAs (blob, name, opts) {
- var URL = _global.URL || _global.webkitURL
- var a = document.createElement('a')
- name = name || blob.name || 'download'
-
- a.download = name
- a.rel = 'noopener' // tabnabbing
-
- // TODO: detect chrome extensions & packaged apps
- // a.target = '_blank'
-
- if (typeof blob === 'string') {
- // Support regular links
- a.href = blob
- if (a.origin !== location.origin) {
- corsEnabled(a.href)
- ? download(blob, name, opts)
- : click(a, a.target = '_blank')
- } else {
- click(a)
- }
- } else {
- // Support blobs
- a.href = URL.createObjectURL(blob)
- setTimeout(function () { URL.revokeObjectURL(a.href) }, 4E4) // 40s
- setTimeout(function () { click(a) }, 0)
- }
- }
-
- // Use msSaveOrOpenBlob as a second approach
- : 'msSaveOrOpenBlob' in navigator
- ? function saveAs (blob, name, opts) {
- name = name || blob.name || 'download'
-
- if (typeof blob === 'string') {
- if (corsEnabled(blob)) {
- download(blob, name, opts)
- } else {
- var a = document.createElement('a')
- a.href = blob
- a.target = '_blank'
- setTimeout(function () { click(a) })
- }
- } else {
- navigator.msSaveOrOpenBlob(bom(blob, opts), name)
- }
- }
-
- // Fallback to using FileReader and a popup
- : function saveAs (blob, name, opts, popup) {
- // Open a popup immediately do go around popup blocker
- // Mostly only available on user interaction and the fileReader is async so...
- popup = popup || open('', '_blank')
- if (popup) {
- popup.document.title =
- popup.document.body.innerText = 'downloading...'
- }
-
- if (typeof blob === 'string') return download(blob, name, opts)
-
- var force = blob.type === 'application/octet-stream'
- var isSafari = /constructor/i.test(_global.HTMLElement) || _global.safari
- var isChromeIOS = /CriOS\/[\d]+/.test(navigator.userAgent)
-
- if ((isChromeIOS || (force && isSafari) || isMacOSWebView) && typeof FileReader !== 'undefined') {
- // Safari doesn't allow downloading of blob URLs
- var reader = new FileReader()
- reader.onloadend = function () {
- var url = reader.result
- url = isChromeIOS ? url : url.replace(/^data:[^;]*;/, 'data:attachment/file;')
- if (popup) popup.location.href = url
- else location = url
- popup = null // reverse-tabnabbing #460
- }
- reader.readAsDataURL(blob)
- } else {
- var URL = _global.URL || _global.webkitURL
- var url = URL.createObjectURL(blob)
- if (popup) popup.location = url
- else location.href = url
- popup = null // reverse-tabnabbing #460
- setTimeout(function () { URL.revokeObjectURL(url) }, 4E4) // 40s
- }
- }
-)
-
-_global.saveAs = saveAs.saveAs = saveAs
-
-if (typeof module !== 'undefined') {
- module.exports = saveAs;
-}
diff --git a/Tools/autotest/web-firmware/Tools/FilterTool/app.py b/Tools/autotest/web-firmware/Tools/FilterTool/app.py
deleted file mode 100644
index 76ded1b765fe86..00000000000000
--- a/Tools/autotest/web-firmware/Tools/FilterTool/app.py
+++ /dev/null
@@ -1,16 +0,0 @@
-import os
-from flask import Flask
-from flask import render_template
-
-# A flask app to allow hosting filter tool locally
-
-this_path = os.path.dirname(os.path.realpath(__file__))
-
-app = Flask(__name__, template_folder=this_path, static_folder=this_path)
-
-@app.route('/')
-def index():
- return render_template('index.html')
-
-if __name__ == "__main__":
- app.run()
diff --git a/Tools/autotest/web-firmware/Tools/FilterTool/filters.js b/Tools/autotest/web-firmware/Tools/FilterTool/filters.js
deleted file mode 100644
index b68bc3b67371b3..00000000000000
--- a/Tools/autotest/web-firmware/Tools/FilterTool/filters.js
+++ /dev/null
@@ -1,1196 +0,0 @@
-function calc_lowpass_alpha_dt(dt, cutoff_freq)
-{
- if (dt <= 0.0 || cutoff_freq <= 0.0) {
- return 1.0;
- }
- var rc = 1.0/(Math.PI*2*cutoff_freq);
- return dt/(dt+rc);
-}
-
-function PID(sample_rate,kP,kI,kD,filtE,filtD) {
-
- this._kP = kP;
- this._kI = kI;
- this._kD = kD;
-
- this._dt = 1.0/sample_rate;
- this.E_alpha = calc_lowpass_alpha_dt(this._dt,filtE)
- this.D_alpha = calc_lowpass_alpha_dt(this._dt,filtD)
-
- this._error = 0.0;
- this._derivative = 0.0;
- this._integrator = 0.0;
-
- this.reset = function(sample) {
- this._error = 0.0;
- this._derivative = 0.0;
- this._integrator = 0.0;
- }
-
- this.apply = function(error) {
-
- var error_last = this._error;
- this._error += this.E_alpha * (error - this._error);
-
- var derivative = (this._error - error_last) / this._dt;
- this._derivative += this.D_alpha * (derivative - this._derivative)
-
- this._integrator += this._error * this._kI * this._dt;
-
- var P_out = this._error * this._kP;
- var D_out = this._derivative * this._kD;
-
- return P_out + this._integrator + D_out;
- }
- return this;
-}
-
-function LPF_1P(sample_rate,cutoff) {
- this.reset = function(sample) {
- this.value = sample;
- }
- if (cutoff <= 0) {
- this.apply = function(sample) {
- return sample;
- }
- return this;
- }
- this.alpha = calc_lowpass_alpha_dt(1.0/sample_rate,cutoff)
- this.value = 0.0;
- this.apply = function(sample) {
- this.value += this.alpha * (sample - this.value);
- return this.value;
- }
- return this;
-}
-
-function DigitalBiquadFilter(sample_freq, cutoff_freq) {
- this.delay_element_1 = 0;
- this.delay_element_2 = 0;
- this.cutoff_freq = cutoff_freq;
-
- if (cutoff_freq <= 0) {
- // zero cutoff means pass-thru
- this.reset = function(sample) {
- }
- this.apply = function(sample) {
- return sample;
- }
- return this;
- }
-
- var fr = sample_freq/cutoff_freq;
- var ohm = Math.tan(Math.PI/fr);
- var c = 1.0+2.0*Math.cos(Math.PI/4.0)*ohm + ohm*ohm;
-
- this.b0 = ohm*ohm/c;
- this.b1 = 2.0*this.b0;
- this.b2 = this.b0;
- this.a1 = 2.0*(ohm*ohm-1.0)/c;
- this.a2 = (1.0-2.0*Math.cos(Math.PI/4.0)*ohm+ohm*ohm)/c;
- this.initialised = false;
-
- this.apply = function(sample) {
- if (!this.initialised) {
- this.reset(sample);
- this.initialised = true;
- }
- var delay_element_0 = sample - this.delay_element_1 * this.a1 - this.delay_element_2 * this.a2;
- var output = delay_element_0 * this.b0 + this.delay_element_1 * this.b1 + this.delay_element_2 * this.b2;
-
- this.delay_element_2 = this.delay_element_1;
- this.delay_element_1 = delay_element_0;
- return output;
- }
-
- this.reset = function(sample) {
- this.delay_element_1 = this.delay_element_2 = sample * (1.0 / (1 + this.a1 + this.a2));
- }
-
- return this;
-}
-
-function sq(v) {
- return v*v;
-}
-
-function constrain_float(v,vmin,vmax) {
- if (v < vmin) {
- return vmin;
- }
- if (v > vmax) {
- return vmax;
- }
- return v;
-}
-
-function NotchFilter(sample_freq,center_freq_hz,bandwidth_hz,attenuation_dB) {
- this.sample_freq = sample_freq;
- this.center_freq_hz = center_freq_hz;
- this.bandwidth_hz = bandwidth_hz;
- this.attenuation_dB = attenuation_dB;
- this.need_reset = true;
- this.initialised = false;
-
- this.calculate_A_and_Q = function() {
- this.A = Math.pow(10.0, -this.attenuation_dB / 40.0);
- if (this.center_freq_hz > 0.5 * this.bandwidth_hz) {
- var octaves = Math.log2(this.center_freq_hz / (this.center_freq_hz - this.bandwidth_hz / 2.0)) * 2.0;
- this.Q = Math.sqrt(Math.pow(2.0, octaves)) / (Math.pow(2.0, octaves) - 1.0);
- } else {
- this.Q = 0.0;
- }
- }
-
- this.init_with_A_and_Q = function() {
- if ((this.center_freq_hz > 0.0) && (this.center_freq_hz < 0.5 * this.sample_freq) && (this.Q > 0.0)) {
- var omega = 2.0 * Math.PI * this.center_freq_hz / this.sample_freq;
- var alpha = Math.sin(omega) / (2 * this.Q);
- this.b0 = 1.0 + alpha*sq(this.A);
- this.b1 = -2.0 * Math.cos(omega);
- this.b2 = 1.0 - alpha*sq(this.A);
- this.a0_inv = 1.0/(1.0 + alpha);
- this.a1 = this.b1;
- this.a2 = 1.0 - alpha;
- this.initialised = true;
- } else {
- this.initialised = false;
- }
- }
-
- // check center frequency is in the allowable range
- if ((center_freq_hz > 0.5 * bandwidth_hz) && (center_freq_hz < 0.5 * sample_freq)) {
- this.calculate_A_and_Q();
- this.init_with_A_and_Q();
- } else {
- this.initialised = false;
- }
-
- this.apply = function(sample) {
- if (!this.initialised || this.need_reset) {
- // if we have not been initialised when return the input
- // sample as output and update delayed samples
- this.signal1 = sample;
- this.signal2 = sample;
- this.ntchsig = sample;
- this.ntchsig1 = sample;
- this.ntchsig2 = sample;
- this.need_reset = false;
- return sample;
- }
- this.ntchsig2 = this.ntchsig1;
- this.ntchsig1 = this.ntchsig;
- this.ntchsig = sample;
- var output = (this.ntchsig*this.b0 + this.ntchsig1*this.b1 + this.ntchsig2*this.b2 - this.signal1*this.a1 - this.signal2*this.a2) * this.a0_inv;
- this.signal2 = this.signal1;
- this.signal1 = output;
- return output;
- }
-
- this.reset = function(sample) {
- this.need_reset = true;
- this.apply(sample);
- }
-
- return this;
-}
-
-function HarmonicNotchFilter(sample_freq,enable,mode,freq,bw,att,ref,fm_rat,hmncs,opts) {
- this.notches = []
- var chained = 1;
- var dbl = false;
- var triple = false;
- var composite_notches = 1;
- if (opts & 1) {
- dbl = true;
- composite_notches = 2;
- } else if (opts & 16) {
- triple = true;
- composite_notches = 3;
- }
-
- this.reset = function(sample) {
- for (n in this.notches) {
- this.notches[n].reset(sample);
- }
- }
-
- if (enable <= 0) {
- this.apply = function(sample) {
- return sample;
- }
- return this;
- }
-
- if (mode == 0) {
- // fixed notch
- }
- if (mode == 1) {
- var motors_throttle = Math.max(0,get_form("Throttle"));
- var throttle_freq = freq * Math.max(fm_rat,Math.sqrt(motors_throttle / ref));
- freq = throttle_freq;
- }
- if (mode == 2) {
- var rpm = get_form("RPM1");
- freq = Math.max(rpm/60.0,freq) * ref;
- }
- if (mode == 5) {
- var rpm = get_form("RPM2");
- freq = Math.max(rpm/60.0,freq) * ref;
- }
- if (mode == 3) {
- if (opts & 2) {
- chained = get_form("NUM_MOTORS");
- }
- var rpm = get_form("ESC_RPM");
- freq = Math.max(rpm/60.0,freq) * ref;
- }
- for (var n=0;n<8;n++) {
- var fmul = n+1;
- if (hmncs & (1< 1) {
- var notch_center_double;
- // only enable the filter if its center frequency is below the nyquist frequency
- notch_center_double = notch_center * (1.0 - notch_spread);
- if (notch_center_double < nyquist_limit) {
- this.notches.push(new NotchFilter(sample_freq,notch_center_double,bandwidth_hz/composite_notches,att));
- }
- // only enable the filter if its center frequency is below the nyquist frequency
- notch_center_double = notch_center * (1.0 + notch_spread);
- if (notch_center_double < nyquist_limit) {
- this.notches.push(new NotchFilter(sample_freq,notch_center_double,bandwidth_hz/composite_notches,att));
- }
- }
- }
- }
- }
- this.apply = function(sample) {
- for (n in this.notches) {
- sample = this.notches[n].apply(sample);
- }
- return sample;
- }
-}
-
-function get_form(vname) {
- var v = parseFloat(document.getElementById(vname).value);
- setCookie(vname, v);
- return v;
-}
-
-function run_filters(filters,freq,sample_rate,samples,fast_filters = null,fast_sample_rate = null) {
-
- for (var j=0;j= best_fit_offset) {
- var index = i - best_fit_offset;
- X.data[index][0] = Math.sin(t * kt);
- X.data[index][1] = Math.cos(t * kt);
- y.data[index][0] = output;
- }
- }
-
- // Z = a*sin(t*kt + p) + O
- var ABO = ML.MatrixLib.solve(X, y);
-
- var amplitude = Math.sqrt(ABO.get(0,0)*ABO.get(0,0) + ABO.get(1,0)*ABO.get(1,0));
- var phase = Math.atan2(ABO.get(1,0),ABO.get(0,0)) * (-180.0 / Math.PI);
- // var DC_offset = ABO.get(2,0);
-
- return [amplitude,phase];
-}
-
-var chart_attenuation;
-var chart_phase;
-var freq_log_scale;
-
-function get_filters(sample_rate) {
- var filters = []
- filters.push(new HarmonicNotchFilter(sample_rate,
- get_form("INS_HNTCH_ENABLE"),
- get_form("INS_HNTCH_MODE"),
- get_form("INS_HNTCH_FREQ"),
- get_form("INS_HNTCH_BW"),
- get_form("INS_HNTCH_ATT"),
- get_form("INS_HNTCH_REF"),
- get_form("INS_HNTCH_FM_RAT"),
- get_form("INS_HNTCH_HMNCS"),
- get_form("INS_HNTCH_OPTS")));
- filters.push(new HarmonicNotchFilter(sample_rate,
- get_form("INS_HNTC2_ENABLE"),
- get_form("INS_HNTC2_MODE"),
- get_form("INS_HNTC2_FREQ"),
- get_form("INS_HNTC2_BW"),
- get_form("INS_HNTC2_ATT"),
- get_form("INS_HNTC2_REF"),
- get_form("INS_HNTC2_FM_RAT"),
- get_form("INS_HNTC2_HMNCS"),
- get_form("INS_HNTC2_OPTS")));
- filters.push(new DigitalBiquadFilter(sample_rate,get_form("INS_GYRO_FILTER")));
-
- return filters;
-}
-
-function calculate_filter() {
- var sample_rate = get_form("GyroSampleRate");
- var freq_max = get_form("MaxFreq");
- var samples = 1000;
- var freq_step = 0.1;
- var filters = get_filters(sample_rate);
-
- var use_dB = document.getElementById("ScaleLog").checked;
- setCookie("Scale", use_dB ? "Log" : "Linear");
- var use_RPM = document.getElementById("freq_Scale_RPM").checked;
- setCookie("feq_unit", use_RPM ? "RPM" : "Hz");
- var unwrap_pahse = document.getElementById("ScaleUnWrap").checked;
- setCookie("PhaseScale", unwrap_pahse ? "unwrap" : "wrap");
- var attenuation = []
- var phase_lag = []
- var min_phase_lag = 0.0;
- var max_phase_lag = 0.0;
- var phase_wrap = 0.0;
- var min_atten = 0.0;
- var max_atten = 1.0;
- var last_phase = 0.0;
- var atten_string = "Magnitude";
- if (use_dB) {
- max_atten = 0;
- min_atten = -10;
- atten_string = "Magnitude (dB)";
- }
- var freq_string = "Frequency (Hz)";
- if (use_RPM) {
- freq_string = "Frequency (RPM)";
- }
-
- // start at zero
- attenuation.push({x:0, y:1});
- phase_lag.push({x:0, y:0});
-
- for (freq=freq_step; freq<=freq_max; freq+=freq_step) {
- var v = run_filters(filters, freq, sample_rate, samples);
- var aten = v[0];
- var phase = v[1] + phase_wrap;
- if (use_dB) {
- // show power in decibels
- aten = 20 * Math.log10(aten);
- }
- var freq_value = freq;
- if (use_RPM) {
- freq_value *= 60;
- }
- if (unwrap_pahse) {
- var phase_diff = phase - last_phase;
- if (phase_diff > 180) {
- phase_wrap -= 360.0;
- phase -= 360.0;
- } else if (phase_diff < -180) {
- phase_wrap += 360.0;
- phase += 360.0;
- }
- }
- attenuation.push({x:freq_value, y:aten});
- phase_lag.push({x:freq_value, y:-phase});
-
- min_atten = Math.min(min_atten, aten);
- max_atten = Math.max(max_atten, aten);
- min_phase_lag = Math.min(min_phase_lag, phase)
- max_phase_lag = Math.max(max_phase_lag, phase)
- last_phase = phase;
- }
-
- if (unwrap_pahse) {
- min_phase_lag = Math.floor((min_phase_lag-10)/10)*10;
- min_phase_lag = Math.min(Math.max(-get_form("MaxPhaseLag"), min_phase_lag), 0);
- max_phase_lag = Math.ceil((max_phase_lag+10)/10)*10;
- max_phase_lag = Math.min(get_form("MaxPhaseLag"), max_phase_lag);
- } else {
- min_phase_lag = -180;
- max_phase_lag = 180;
- }
-
- if (use_RPM) {
- freq_max *= 60.0;
- }
-
- var freq_log = document.getElementById("freq_ScaleLog").checked;
- setCookie("feq_scale", freq_log ? "Log" : "Linear");
- if ((freq_log_scale != null) && (freq_log_scale != freq_log)) {
- // Scale changed, no easy way to update, delete chart and re-draw
- chart_attenuation.clear();
- chart_attenuation.destroy();
- chart_attenuation = null;
- chart_phase.clear();
- chart_phase.destroy();
- chart_phase = null;
- }
- freq_log_scale = freq_log;
-
- if (chart_attenuation) {
- chart_attenuation.data.datasets[0].data = attenuation;
- chart_attenuation.options.scales.xAxes[0].ticks.max = freq_max;
- chart_attenuation.options.scales.xAxes[0].scaleLabel.labelString = freq_string
- chart_attenuation.options.scales.yAxes[0].ticks.min = min_atten
- chart_attenuation.options.scales.yAxes[0].ticks.max = max_atten;
- chart_attenuation.options.scales.yAxes[0].scaleLabel.labelString = atten_string;
- chart_attenuation.update();
- } else {
- chart_attenuation = new Chart("Attenuation", {
- type : "scatter",
- data: {
- datasets: [
- {
- label: 'Magnitude',
- yAxisID: 'Magnitude',
- pointRadius: 0,
- hitRadius: 8,
- borderColor: "rgba(0,0,255,1.0)",
- pointBackgroundColor: "rgba(0,0,255,1.0)",
- data: attenuation,
- showLine: true,
- fill: false
- },
- ]
- },
- options: {
- aspectRatio: 3,
- legend: {display: false},
- scales: {
- yAxes: [
- {
- scaleLabel: { display: true, labelString: atten_string },
- id: 'Magnitude',
- ticks: {min:min_atten, max:max_atten}
- },
- ],
- xAxes: [
- {
- type: (freq_log ? "logarithmic" : "linear"),
- scaleLabel: { display: true, labelString: freq_string },
- ticks:
- {
- min:0.0,
- max:freq_max,
- callback: function(value, index, ticks) {
- return value;
- },
- }
- }
- ],
- },
- tooltips: {
- callbacks: {
- label: function(tooltipItem, data) {
- // round tooltip to two decimal places
- return tooltipItem.xLabel.toFixed(2) + ', ' + tooltipItem.yLabel.toFixed(2);
- }
- }
- }
- }
- });
- }
-
-
- if (chart_phase) {
- chart_phase.data.datasets[0].data = phase_lag;
- chart_phase.options.scales.xAxes[0].ticks.max = freq_max;
- chart_phase.options.scales.xAxes[0].scaleLabel.labelString = freq_string
- chart_phase.options.scales.yAxes[0].ticks.min = -max_phase_lag;
- chart_phase.options.scales.yAxes[0].ticks.max = -min_phase_lag;
- chart_phase.update();
- } else {
- chart_phase = new Chart("Phase", {
- type : "scatter",
- data: {
- datasets: [
- {
- label: 'Phase',
- yAxisID: 'Phase',
- pointRadius: 0,
- hitRadius: 8,
- borderColor: "rgba(255,0,0,1.0)",
- pointBackgroundColor: "rgba(255,0,0,1.0)",
- data: phase_lag,
- showLine: true,
- fill: false
- }
- ]
- },
- options: {
- aspectRatio: 3,
- legend: {display: false},
- scales: {
- yAxes: [
- {
- scaleLabel: { display: true, labelString: "Phase (deg)" },
- id: 'Phase',
- ticks: {min:-max_phase_lag, max:-min_phase_lag}
- }
- ],
- xAxes: [
- {
- type: (freq_log ? "logarithmic" : "linear"),
- scaleLabel: { display: true, labelString: freq_string },
- ticks:
- {
- min:0.0,
- max:freq_max,
- callback: function(value, index, ticks) {
- return value;
- },
- }
- }
- ],
- },
- tooltips: {
- callbacks: {
- label: function(tooltipItem, data) {
- // round tooltip to two decimal places
- return tooltipItem.xLabel.toFixed(2) + ', ' + tooltipItem.yLabel.toFixed(2);
- }
- }
- }
- }
- });
- }
-}
-
-var PID_attenuation;
-var PID_phase;
-var PID_freq_log_scale;
-
-function calculate_pid(axis_id) {
- //var sample_rate = get_form("GyroSampleRate");
- var PID_rate = get_form("SCHED_LOOP_RATE")
- var filters = []
- var freq_max = get_form("PID_MaxFreq");
- var samples = 1000;
- var freq_step = 0.1;
-
- // default to roll axis
- var axis_prefix = "ATC_RAT_RLL_";
- if (axis_id == "CalculatePitch") {
- var axis_prefix = "ATC_RAT_PIT_";
- document.getElementById("PID_title").innerHTML = "Pitch axis";
- } else if (axis_id == "CalculateYaw") {
- var axis_prefix = "ATC_RAT_YAW_";
- document.getElementById("PID_title").innerHTML = "Yaw axis";
- } else {
- document.getElementById("PID_title").innerHTML = "Roll axis";
- }
-
- filters.push(new PID(PID_rate,
- get_form(axis_prefix + "P"),
- get_form(axis_prefix + "I"),
- get_form(axis_prefix + "D"),
- get_form(axis_prefix + "FLTE"),
- get_form(axis_prefix + "FLTD")));
-
- var use_dB = document.getElementById("PID_ScaleLog").checked;
- setCookie("PID_Scale", use_dB ? "Log" : "Linear");
- var use_RPM = document.getElementById("PID_freq_Scale_RPM").checked;
- setCookie("PID_feq_unit", use_RPM ? "RPM" : "Hz");
- var unwrap_pahse = document.getElementById("PID_ScaleUnWrap").checked;
- setCookie("PID_PhaseScale", unwrap_pahse ? "unwrap" : "wrap");
- var attenuation = []
- var phase_lag = []
- var min_phase_lag = 0.0;
- var max_phase_lag = 0.0;
- var phase_wrap = 0.0;
- var min_atten = Infinity;
- var max_atten = -Infinity;
- var last_phase = 0.0;
- var atten_string = "Gain";
- if (use_dB) {
- max_atten = 0;
- min_atten = -10;
- atten_string = "Gain (dB)";
- }
- var freq_string = "Frequency (Hz)";
- if (use_RPM) {
- freq_string = "Frequency (RPM)";
- }
-
- var fast_filters = null;
- var fast_sample_rate = null;
- if (document.getElementById("PID_filtering_Post").checked) {
- fast_sample_rate = get_form("GyroSampleRate");
- fast_filters = get_filters(fast_sample_rate);
- }
- setCookie("filtering", fast_filters == null ? "Pre" : "Post");
-
-
- for (freq=freq_step; freq<=freq_max; freq+=freq_step) {
- var v = run_filters(filters, freq, PID_rate, samples, fast_filters, fast_sample_rate);
- var aten = v[0];
- var phase = v[1] + phase_wrap;
- if (use_dB) {
- // show power in decibels
- aten = 20 * Math.log10(aten);
- }
- var freq_value = freq;
- if (use_RPM) {
- freq_value *= 60;
- }
- if (unwrap_pahse) {
- var phase_diff = phase - last_phase;
- if (phase_diff > 180) {
- phase_wrap -= 360.0;
- phase -= 360.0;
- } else if (phase_diff < -180) {
- phase_wrap += 360.0;
- phase += 360.0;
- }
- }
- attenuation.push({x:freq_value, y:aten});
- phase_lag.push({x:freq_value, y:-phase});
-
- min_atten = Math.min(min_atten, aten);
- max_atten = Math.max(max_atten, aten);
- min_phase_lag = Math.min(min_phase_lag, phase)
- max_phase_lag = Math.max(max_phase_lag, phase)
- last_phase = phase;
- }
-
- if (use_RPM) {
- freq_max *= 60.0;
- }
-
- var mean_atten = (min_atten + max_atten) * 0.5;
- var atten_range = Math.max((max_atten - min_atten) * 0.5 * 1.1, 1.0);
- min_atten = mean_atten - atten_range;
- max_atten = mean_atten + atten_range;
-
- if (unwrap_pahse) {
- min_phase_lag = Math.floor((min_phase_lag-10)/10)*10;
- min_phase_lag = Math.min(Math.max(-get_form("PID_MaxPhaseLag"), min_phase_lag), 0);
- max_phase_lag = Math.ceil((max_phase_lag+10)/10)*10;
- max_phase_lag = Math.min(get_form("PID_MaxPhaseLag"), max_phase_lag);
- } else {
- min_phase_lag = -180;
- max_phase_lag = 180;
- }
-
- var freq_log = document.getElementById("PID_freq_ScaleLog").checked;
- setCookie("PID_feq_scale", use_dB ? "Log" : "Linear");
- if ((PID_freq_log_scale != null) && (PID_freq_log_scale != freq_log)) {
- // Scale changed, no easy way to update, delete chart and re-draw
- PID_attenuation.clear();
- PID_attenuation.destroy();
- PID_attenuation = null;
- PID_phase.clear();
- PID_phase.destroy();
- PID_phase = null;
- }
- PID_freq_log_scale = freq_log;
-
- if (PID_attenuation) {
- PID_attenuation.data.datasets[0].data = attenuation;
- PID_attenuation.options.scales.xAxes[0].ticks.max = freq_max;
- PID_attenuation.options.scales.xAxes[0].scaleLabel.labelString = freq_string
- PID_attenuation.options.scales.yAxes[0].ticks.min = min_atten
- PID_attenuation.options.scales.yAxes[0].ticks.max = max_atten;
- PID_attenuation.options.scales.yAxes[0].scaleLabel.labelString = atten_string;
- PID_attenuation.update();
- } else {
- PID_attenuation = new Chart("PID_Attenuation", {
- type : "scatter",
- data: {
- datasets: [
- {
- label: 'Gain',
- yAxisID: 'Gain',
- pointRadius: 0,
- hitRadius: 8,
- borderColor: "rgba(0,0,255,1.0)",
- pointBackgroundColor: "rgba(0,0,255,1.0)",
- data: attenuation,
- showLine: true,
- fill: false
- },
- ]
- },
- options: {
- aspectRatio: 3,
- legend: {display: false},
- scales: {
- yAxes: [
- {
- scaleLabel: { display: true, labelString: atten_string },
- id: 'Gain',
- position: 'left',
- ticks: {min:min_atten, max:max_atten}
- },
- ],
- xAxes: [
- {
- type: (freq_log ? "logarithmic" : "linear"),
- scaleLabel: { display: true, labelString: freq_string },
- ticks:
- {
- min:0.0,
- max:freq_max,
- callback: function(value, index, ticks) {
- return value;
- },
- }
- }
- ],
- },
- tooltips: {
- callbacks: {
- label: function(tooltipItem, data) {
- // round tooltip to two decimal places
- return tooltipItem.xLabel.toFixed(2) + ', ' + tooltipItem.yLabel.toFixed(2);
- }
- }
- }
- }
- });
- }
-
-
- if (PID_phase) {
- PID_phase.data.datasets[0].data = phase_lag;
- PID_phase.options.scales.xAxes[0].ticks.max = freq_max;
- PID_phase.options.scales.xAxes[0].scaleLabel.labelString = freq_string
- PID_phase.options.scales.yAxes[0].ticks.min = -max_phase_lag;
- PID_phase.options.scales.yAxes[0].ticks.max = -min_phase_lag;
- PID_phase.update();
- } else {
- PID_phase = new Chart("PID_Phase", {
- type : "scatter",
- data: {
- datasets: [
- {
- label: 'PhaseLag',
- yAxisID: 'PhaseLag',
- pointRadius: 0,
- hitRadius: 8,
- borderColor: "rgba(255,0,0,1.0)",
- pointBackgroundColor: "rgba(255,0,0,1.0)",
- data: phase_lag,
- showLine: true,
- fill: false
- }
- ]
- },
- options: {
- aspectRatio: 3,
- legend: {display: false},
- scales: {
- yAxes: [
- {
- scaleLabel: { display: true, labelString: "Phase (deg)" },
- id: 'PhaseLag',
- ticks: {min:-max_phase_lag, max:-min_phase_lag}
- }
- ],
- xAxes: [
- {
- type: (freq_log ? "logarithmic" : "linear"),
- scaleLabel: { display: true, labelString: freq_string },
- ticks:
- {
- min:0.0,
- max:freq_max,
- callback: function(value, index, ticks) {
- return value;
- },
- }
- }
- ],
- },
- tooltips: {
- callbacks: {
- label: function(tooltipItem, data) {
- // round tooltip to two decimal places
- return tooltipItem.xLabel.toFixed(2) + ', ' + tooltipItem.yLabel.toFixed(2);
- }
- }
- }
- }
- });
- }
-}
-
-function load() {
- var url_string = (window.location.href).toLowerCase();
- if (url_string.indexOf('?') == -1) {
- // no query params, load from cookies
- load_cookies();
- return;
- }
-
- // populate from query's
- var params = new URL(url_string).searchParams;
- var sections = ["params", "PID_params"];
- for (var j = 0; j -1 ? cookie.substr(0, eqPos) : cookie;
- document.cookie = name + "=;expires=Thu, 01 Jan 1970 00:00:00 GMT";
- }
-}
-
-function save_parameters() {
- var params = "";
- var inputs = document.forms["params"].getElementsByTagName("input");
- for (const v in inputs) {
- var name = "" + inputs[v].name;
- if (name.startsWith("INS_")) {
- var value = inputs[v].value;
- params += name + "," + value + "\n";
- }
- }
- var blob = new Blob([params], { type: "text/plain;charset=utf-8" });
- saveAs(blob, "filter.param");
-}
-
-async function load_parameters(file) {
- var text = await file.text();
- var lines = text.split('\n');
- for (i in lines) {
- var line = lines[i];
- line = line.replace("Q_A_RAT_","ATC_RAT_");
- v = line.split(/[\s,=\t]+/);
- if (v.length >= 2) {
- var vname = v[0];
- var value = v[1];
- var fvar = document.getElementById(vname);
- if (fvar) {
- fvar.value = value;
- console.log("set " + vname + "=" + value);
- }
- }
- }
- fill_docs();
- update_all_hidden();
- calculate_filter();
-}
-
-function fill_docs()
-{
- var inputs = document.forms["params"].getElementsByTagName("input");
- for (const v in inputs) {
- var name = inputs[v].name;
- var doc = document.getElementById(name + ".doc");
- if (!doc) {
- continue;
- }
- if (inputs[v].onchange == null) {
- inputs[v].onchange = fill_docs;
- }
- var value = parseFloat(inputs[v].value);
- if (name.endsWith("_ENABLE")) {
- if (value >= 1) {
- doc.innerHTML = "Enabled";
- } else {
- doc.innerHTML = "Disabled";
- }
- } else if (name.endsWith("_MODE")) {
- switch (Math.floor(value)) {
- case 0:
- doc.innerHTML = "Fixed notch";
- break;
- case 1:
- doc.innerHTML = "Throttle";
- break;
- case 2:
- doc.innerHTML = "RPM Sensor 1";
- break;
- case 3:
- doc.innerHTML = "ESC Telemetry";
- break;
- case 4:
- doc.innerHTML = "Dynamic FFT";
- break;
- case 5:
- doc.innerHTML = "RPM Sensor 2";
- break;
- default:
- doc.innerHTML = "INVALID";
- break;
- }
- } else if (name.endsWith("_OPTS")) {
- var ival = Math.floor(value);
- var bits = [];
- if (ival & 1) {
- bits.push("Double Notch");
- }
- if (ival & 2) {
- bits.push("Dynamic Harmonic");
- }
- if (ival & 4) {
- bits.push("Loop Rate");
- }
- if (ival & 8) {
- bits.push("All IMUs Rate");
- }
- if ((ival & 16) && (ival & 1) == 0) {
- bits.push("Triple Notch");
- }
- doc.innerHTML = bits.join(", ");
- } else if (name.endsWith("_HMNCS")) {
- var ival = Math.floor(value);
- var bits = [];
- if (ival & 1) {
- bits.push("Fundamental");
- }
- if (ival & 2) {
- bits.push("1st Harmonic");
- }
- if (ival & 4) {
- bits.push("2nd Harmonic");
- }
- if (ival & 8) {
- bits.push("3rd Harmonic");
- }
- if (ival & 16) {
- bits.push("4th Harmonic");
- }
- if (ival & 32) {
- bits.push("5th Harmonic");
- }
- if (ival & 64) {
- bits.push("6th Harmonic");
- }
- doc.innerHTML = bits.join(", ");
- }
-
- }
-}
-
-// update all hidden params, to be called at init
-function update_all_hidden()
-{
- var enable_params = ["INS_HNTCH_ENABLE", "INS_HNTC2_ENABLE"];
- for (var i=-0;i 0;
- var prefix = enable_param.split("_ENABLE")[0];
-
- // find all elements with same prefix
- var inputs = document.forms["params"].getElementsByTagName("*");
- for (var i=-0;i 0)) {
- continue;
- }
-
- var mode = Math.floor(get_form(mode_params[j]))
- for (var k =0; k < mode_options[i][0].length; k++) {
- if (mode == mode_options[i][0][k]) {
- hide = false;
- }
- }
- }
- document.getElementById(mode_options[i][1]).hidden = hide;
- }
-}
-
-function check_nyquist()
-{
- var checks = [["GyroSampleRate", "MaxFreq", "MaxFreq_warning"],
- ["SCHED_LOOP_RATE", "PID_MaxFreq", "PID_MaxFreq_warning"]];
-
- for (var i = 0; i < checks.length; i++) {
- var freq_limit = get_form(checks[i][0]) * 0.5;
- var sample_rate = document.getElementById(checks[i][1]);
- if (parseFloat(sample_rate.value) > freq_limit) {
- sample_rate.value = freq_limit;
- document.getElementById(checks[i][2]).innerHTML = "Nyquist limit of half sample rate";
- } else {
- document.getElementById(checks[i][2]).innerHTML = "";
- }
- }
-}
diff --git a/Tools/autotest/web-firmware/Tools/FilterTool/index.html b/Tools/autotest/web-firmware/Tools/FilterTool/index.html
deleted file mode 100644
index c092d1b8b98e92..00000000000000
--- a/Tools/autotest/web-firmware/Tools/FilterTool/index.html
+++ /dev/null
@@ -1,378 +0,0 @@
-
-
-
-
-ArduPilot Filter Analysis
-
-
-
-
-
-
-
-
-ArduPilot Filter Analysis
-
-The following form will display the attenuation and phase lag for an
-ArduPilot 4.2 filter setup.
-
-
-
-
-
-
-
-
-
-
-
-
-PIDs
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/Tools/bootloaders/ACNS-CM4Pilot_bl.bin b/Tools/bootloaders/ACNS-CM4Pilot_bl.bin
new file mode 100755
index 00000000000000..971f486cead951
Binary files /dev/null and b/Tools/bootloaders/ACNS-CM4Pilot_bl.bin differ
diff --git a/Tools/bootloaders/ACNS-F405AIO_bl.bin b/Tools/bootloaders/ACNS-F405AIO_bl.bin
new file mode 100755
index 00000000000000..5961638f2bb3f8
Binary files /dev/null and b/Tools/bootloaders/ACNS-F405AIO_bl.bin differ
diff --git a/Tools/bootloaders/AeroFox-GNSS_F9P_bl.bin b/Tools/bootloaders/AeroFox-GNSS_F9P_bl.bin
new file mode 100755
index 00000000000000..302e89c7cf4ac3
Binary files /dev/null and b/Tools/bootloaders/AeroFox-GNSS_F9P_bl.bin differ
diff --git a/Tools/bootloaders/BETAFPV-F405_bl.bin b/Tools/bootloaders/BETAFPV-F405_bl.bin
new file mode 100644
index 00000000000000..bbc0f20d09e28b
Binary files /dev/null and b/Tools/bootloaders/BETAFPV-F405_bl.bin differ
diff --git a/Tools/bootloaders/BETAFPV-F405_bl.hex b/Tools/bootloaders/BETAFPV-F405_bl.hex
new file mode 100644
index 00000000000000..be0553cc247074
--- /dev/null
+++ b/Tools/bootloaders/BETAFPV-F405_bl.hex
@@ -0,0 +1,898 @@
+:020000040800F2
+:1000000000060020E1010008E3010008E301000808
+:10001000E3010008E3010008E3010008E301000830
+:10002000E3010008E3010008E3010008B52F000820
+:10003000E3010008E3010008E3010008E301000810
+:10004000E3010008E3010008E3010008E301000800
+:10005000E3010008E30100085D3200088532000872
+:10006000AD320008D5320008FD320008E301000877
+:10007000E3010008E3010008E3010008E3010008D0
+:10008000E3010008E3010008E3010008E3010008C0
+:10009000E3010008E3010008E3010008253300083C
+:1000A000E3010008E3010008E3010008E3010008A0
+:1000B000F9330008E3010008E3010008E301000848
+:1000C000E3010008E3010008E3010008E301000880
+:1000D000E3010008E3010008E3010008E301000870
+:1000E00089330008E3010008E3010008E301000888
+:1000F000E3010008E3010008E3010008E301000850
+:10010000E3010008E3010008E3010008E30100083F
+:10011000E3010008E3010008E3010008E30100082F
+:10012000E3010008E3010008E3010008E30100081F
+:10013000E3010008E3010008E3010008E30100080F
+:10014000E3010008E3010008E30100086927000853
+:10015000E3010008E3010008E3010008E3010008EF
+:10016000E3010008E3010008E3010008E3010008DF
+:10017000E3010008E3010008E3010008E3010008CF
+:10018000E3010008E3010008E3010008E3010008BF
+:10019000E3010008E3010008E3010008E3010008AF
+:1001A000E3010008E3010008E3010008E30100089F
+:1001B000E3010008E3010008E3010008E30100088F
+:1001C000E3010008E3010008E3010008E30100087F
+:1001D000E3010008E3010008E3010008E30100086F
+:1001E00002E000F000F8FEE772B6374880F30888B6
+:1001F000364880F3098836483649086040F20000E6
+:10020000CCF200004EF63471CEF200010860BFF36C
+:100210004F8FBFF36F8F40F20000C0F2F0004EF638
+:100220008851CEF200010860BFF34F8FBFF36F8F8C
+:100230004FF00000E1EE100A4EF63C71CEF20001E4
+:100240000860062080F31488BFF36F8F01F054FF1D
+:1002500002F04EFE4FF055301F491B4A91423CBF01
+:1002600041F8040BFAE71D49184A91423CBF41F896
+:10027000040BFAE71A491B4A1B4B9A423EBF51F83E
+:10028000040B42F8040BF8E700201849184A914281
+:100290003CBF41F8040BFAE701F032FF02F07CFEAC
+:1002A000144C154DAC4203DA54F8041B8847F9E7A7
+:1002B00000F042F8114C124DAC4203DA54F8041B22
+:1002C0008847F9E701F01ABF00060020002200204D
+:1002D0000000000808ED00E00000002000060020FB
+:1002E000C0370008002200204022002040220020C9
+:1002F000602E0020E0010008E0010008E001000895
+:10030000E00100082DE9F04F2DED108AC1F80CD066
+:10031000C3689D46BDEC108ABDE8F08F002383F3CF
+:1003200011882846A047002001F082FAFEE701F07C
+:10033000EBF900DFFEE7000038B500F061FB01F0EB
+:10034000ABFE054601F0CEFE0446D8B90F4B9D42E8
+:100350001AD001339D4218BF044641F2883504BFCC
+:1003600001240025002001F0A1FE0CB100F076F878
+:1003700000F0EAFC00F09AFB284600F0B7F800F025
+:100380006DF8F9E70025EDE70546EBE7010007B05A
+:1003900008B500F05DFBA0F120035842584108BDAC
+:1003A00007B541F21203022101A8ADF8043000F0B4
+:1003B0006DFB03B05DF804FB38B5302383F311887F
+:1003C000174803680BB101F0FFFA164A14480023DE
+:1003D0004FF47A7101F0EEFA002383F31188124C86
+:1003E000236813B12368013B2360636813B163681A
+:1003F000013B63600D4D2B7833B963687BB90220F4
+:1004000000F01CFC322363602B78032B07D1636858
+:100410002BB9022000F012FC4FF47A73636038BDF0
+:1004200040220020B9030008602300205822002049
+:10043000084B187003280CD8DFE800F00805020804
+:10044000022000F0F3BB022000F0E6BB024B0022CA
+:100450005A60704758220020602300201F4B204A1A
+:1004600010B51C461968013136D004339342F9D1D6
+:100470006268A24230D31B4B9B6803F1006303F513
+:1004800040439A4228D2002000F02AFB0220FFF7C6
+:10049000CFFF154B1A6C00221A64196E1A66196E7A
+:1004A000596C5A64596E5A665A6E1A6942F0005273
+:1004B0001A611A6922F000521A611B6972B64FF074
+:1004C000E0233021C3F8084DD4E9003281F31188CC
+:1004D0009D4683F30888104710BD00BF00C0000888
+:1004E00020C0000800220020003802402DE9F04F13
+:1004F00093B0AA4B00902022FF210AA89D6800F02B
+:10050000CDFBA74A1378A3B9A64801210360117057
+:10051000302383F3118803680BB101F055FAA24A26
+:10052000A04800234FF47A7101F044FA002383F3CA
+:100530001188009B13B19D4B009A1A609C4A009C45
+:100540001378032B1EBF00231370984A4FF0000A44
+:1005500018BF5360D3465646D146012000F066FBD3
+:1005600024B1924B1B68002B00F01182002000F098
+:100570006FFA0390039B002BF2DB012000F04CFB91
+:10058000039B213B162BE8D801A252F823F000BFB1
+:10059000ED05000815060008A90600085B0500081F
+:1005A0005B0500085B050008330700080309000825
+:1005B0001D0800087F080008A7080008CD080008EB
+:1005C0005B050008DF0800085B050008510900080A
+:1005D0008D0600085B05000895090008F90500086C
+:1005E0008D0600085B0500087F0800080220FFF761
+:1005F000CFFE002840F0F581009B0221BAF1000FE8
+:1006000008BF1C4605A841F21233ADF8143000F0C3
+:100610003DFAA2E74FF47A7000F01AFA071EEBDBFE
+:100620000220FFF7B5FE0028E6D0013F052F00F2BB
+:10063000DA81DFE807F0030A0D101336052305936E
+:10064000042105A800F022FA17E054480421F9E734
+:1006500058480421F6E758480421F3E74FF01C08F6
+:10066000404600F03FFA08F104080590042105A86F
+:1006700000F00CFAB8F12C0FF2D1012000FA07F7C4
+:1006800047EA0B0B5FFA8BFB4FF0000900F052FBBF
+:1006900026B10BF00B030B2B08BF0024FFF780FEE5
+:1006A0005BE746480421CDE7002EA5D00BF00B03F5
+:1006B0000B2BA1D10220FFF76BFE074600289BD031
+:1006C000012000F00DFA0220FFF7B2FE00265FFACB
+:1006D00086F8404600F014FA044690B100214046E6
+:1006E00000F01EFA01360028F1D1BA46044641F264
+:1006F0001213022105A8ADF814303E4600F0C6F9E9
+:100700002BE70120FFF794FE2546244B9B68AB4264
+:1007100007D9284600F0E6F9013040F0678104353A
+:10072000F3E7234B00251D70204BBA465D603E4623
+:10073000ACE7002E3FF460AF0BF00B030B2B7FF404
+:100740005BAF0220FFF774FE322000F081F9B0F1B8
+:100750000008FFF651AF18F003077FF44DAF0F4AC2
+:10076000926808EB050393423FF646AFB8F5807FE9
+:100770003FF742AF124B0193B84523DD4FF47A7037
+:1007800000F066F90390039A002AFFF635AF019B4B
+:10079000039A03F8012B0137EDE700BF0022002088
+:1007A0005C23002040220020B903000860230020C1
+:1007B0005822002004220020082200200C220020C1
+:1007C0005C220020C820FFF7E3FD074600283FF425
+:1007D00013AF1F2D11D8C5F1200242450AAB25F0F9
+:1007E000030028BF424683490192184400F030FAC2
+:1007F000019A8048FF2100F051FA4FEAA8037D4991
+:100800000193C8F38702284600F050FA06460028F4
+:100810003FF46DAF019B05EB830537E70220FFF73F
+:10082000B7FD00283FF4E8AE00F0A6F900283FF439
+:10083000E3AE0027B846704B9B68BB4218D91F2F08
+:1008400011D80A9B01330ED027F0030312AA1344D8
+:1008500053F8203C05934046042205A900F09EFA77
+:1008600004378046E7E7384600F03CF90590F2E7A8
+:10087000CDF81480042105A800F008F906E700234C
+:10088000642104A8049300F0F7F800287FF4B4AEC4
+:100890000220FFF77DFD00283FF4AEAE049800F083
+:1008A00053F90590E6E70023642104A8049300F0BF
+:1008B000E3F800287FF4A0AE0220FFF769FD0028CE
+:1008C0003FF49AAE049800F04FF9EAE70220FFF7F0
+:1008D0005FFD00283FF490AE00F05EF9E1E70220F2
+:1008E000FFF756FD00283FF487AE05A9142000F05D
+:1008F00059F904210746049004A800F0C7F83946C6
+:10090000B9E7322000F0A4F8071EFFF675AEBB076A
+:100910007FF472AE384A926807EB090393423FF6C0
+:100920006BAE0220FFF734FD00283FF465AE27F0E0
+:1009300003074F44B9453FF4A9AE484600F0D2F84A
+:100940000421059005A800F0A1F809F10409F1E7D8
+:100950004FF47A70FFF71CFD00283FF44DAE00F015
+:100960000BF9002844D00A9B01330BD008220AA9B6
+:10097000002000F09BF900283AD02022FF210AA88D
+:1009800000F08CF9FFF70CFD1C4800F057FF13B086
+:10099000BDE8F08F002E3FF42FAE0BF00B030B2BB6
+:1009A0007FF42AAE0023642105A8059300F064F8C3
+:1009B000074600287FF420AE0220FFF7E9FC8046BE
+:1009C00000283FF419AEFFF7EBFC41F2883000F04D
+:1009D00035FF059800F0E0F9464600F0ABF93C46DB
+:1009E000BBE5064652E64FF0000905E6BA467EE64C
+:1009F00037467CE65C22002000220020A086010011
+:100A00007047000070B50F4B1B780133DBB2012B30
+:100A10000C4611D80C4D29684FF47A730E6AA2FB6C
+:100A20000332014622462846B047844204D1074B90
+:100A300000221A70012070BD4FF4FA7000F0FEFE23
+:100A40000020F8E710220020082600209423002030
+:100A500007B50023024601210DF107008DF807308C
+:100A6000FFF7D0FF20B19DF8070003B05DF804FB4D
+:100A70004FF0FF30F9E700000A4608B50421FFF700
+:100A8000C1FF80F00100C0B2404208BD30B4054C47
+:100A90002368DD69044B0A46AC460146204630BC5B
+:100AA000604700BF08260020A086010070B501F055
+:100AB000E5F9094E094D30800024286833888342C7
+:100AC00008D901F0D5F92B6804440133B4F5404F3F
+:100AD0002B60F2D370BD00BF962300206823002056
+:100AE00001F08EBA00F1006000F5404000687047E8
+:100AF00000F10060920000F5404001F00DBA0000E6
+:100B0000054B1A68054B1B889B1A834202D9104477
+:100B100001F0AEB900207047682300209623002022
+:100B200038B5084D044629B128682044BDE838404E
+:100B300001F0BEB92868204401F0A2F90028F3D0E2
+:100B400038BD00BF6823002010F003030AD1B0F5C0
+:100B5000047F05D200F10050A0F51040D0F8003815
+:100B6000184670470023FBE700F10050A0F5104045
+:100B7000D0F8100A70470000064991F8243033B1CC
+:100B80000023086A81F824300822FFF7B1BF012052
+:100B9000704700BF6C230020014B1868704700BFEE
+:100BA000002004E070B5194B1D68194B0138C5F3DE
+:100BB0000B0408442D0C04221E88A6420BD15C684D
+:100BC0000A46013C824213460FD214F9016F4EB11E
+:100BD00002F8016BF6E7013A03F10803ECD1814218
+:100BE0000B4602D22C2203F8012B0A4A0524168850
+:100BF000AE4204D1984284BF967803F8016B013C61
+:100C000002F10402F3D1581A70BD00BF002004E0C5
+:100C1000DC340008C8340008022802BF024B4FF43D
+:100C200000129A61704700BF00040240022802BF10
+:100C3000014B20229A61704700040240022801BF44
+:100C4000024A536983F02003536170470004024055
+:100C500010B50023934203D0CC5CC4540133F9E7B0
+:100C600010BD000010B5013810F9013F3BB191F9FA
+:100C700000409C4203D11AB10131013AF4E71AB1A4
+:100C800091F90020981A10BD1046FCE70346024671
+:100C9000D01A12F9011B0029FAD170470244034609
+:100CA000934202D003F8011BFAE770472DE9F8439D
+:100CB0001F4D144695F824200746884652BBDFF89E
+:100CC00070909CB395F824302BB92022FF21484620
+:100CD0002F62FFF7E3FF95F82400C0F10802A2425B
+:100CE00028BF2246D6B24146920005EB8000FFF7AE
+:100CF000AFFF95F82430A41B1E44F6B2082E17440B
+:100D00009044E4B285F82460DBD1FFF735FF00287A
+:100D1000D7D108E02B6A03EB82038342CFD0FFF7E1
+:100D20002BFF0028CBD10020BDE8F8830120FBE792
+:100D30006C230020024B1A78024B1A70704700BFD8
+:100D4000942300201022002010B50F4C0F4800F013
+:100D5000B5F821460D4800F0DDF824680C48626DB6
+:100D6000D2F8043843F00203C2F8043800F066FDFC
+:100D70000849204600F0D4F9626DD2F8043823F017
+:100D80000203C2F8043810BDA83500080826002068
+:100D900040420F00B03500087047000030B5094DE3
+:100DA0000A4491420DD011F8013B5840082340F30A
+:100DB0000004013B2C4013F0FF0384EA5000F6D1FD
+:100DC000EFE730BD2083B8ED02684368114301604E
+:100DD00003B118477047000013B5446BD4F894343E
+:100DE0001A681178042915D1217C022912D11979A8
+:100DF000128901238B4013420CD101A904F14C004C
+:100E000001F032FFD4F89444019B21790246206816
+:100E100000F0D0F902B010BD143001F0B5BE0000F2
+:100E20004FF0FF33143001F0AFBE00004C3001F042
+:100E300087BF00004FF0FF334C3001F081BF00004E
+:100E4000143001F083BE00004FF0FF31143001F088
+:100E50007DBE00004C3001F053BF00004FF0FF3268
+:100E60004C3001F04DBF00000020704710B5D0F8A5
+:100E700094341A6811780429044617D1017C022998
+:100E800014D15979528901238B4013420ED1143069
+:100E900001F016FE024648B1D4F894444FF4807332
+:100EA00061792068BDE8104000F072B910BD000003
+:100EB000406BFFF7DBBF0000704700007FB5124BAF
+:100EC000036000234360C0E90233012502260F4B73
+:100ED000057404460290019300F1840229460096AD
+:100EE0004FF48073143001F0C7FD094B0294CDE933
+:100EF000006304F523724FF48073294604F14C001B
+:100F000001F08EFE04B070BDFC340008B10E000884
+:100F1000D90D00080B68302282F311880A7903EB9F
+:100F2000820290614A79093243F822008A7912B12B
+:100F300003EB820398610223C0F894140374002029
+:100F400080F311887047000038B5037F044613B161
+:100F500090F85430ABB9201D01250221FFF734FF72
+:100F600004F1140025776FF0010100F08FFC84F884
+:100F7000545004F14C006FF00101BDE8384000F01E
+:100F800085BC38BD10B5012104460430FFF71CFFB5
+:100F90000023237784F8543010BD000038B5044690
+:100FA0000025143001F080FD04F14C00257701F09C
+:100FB0004FFE201D84F854500121FFF705FF204605
+:100FC000BDE83840FFF752BF90F8443003F06003AB
+:100FD000202B07D190F84520212A4FF0000303D899
+:100FE0001F2A06D800207047222AFBD1C0E90E3301
+:100FF00003E0034A82630722C2630364012070474F
+:101000001122002037B5D0F894341A6811780429D9
+:1010100004461AD1017C022917D1197912890123BA
+:101020008B40134211D100F14C05284601F0D0FE4F
+:1010300058B101A9284601F017FED4F89444019B49
+:1010400021790246206800F0B5F803B030BD0000F9
+:10105000F0B500EB810385B09E6904460D46FEB1F4
+:10106000302383F3118804EB8507301D0821FFF737
+:10107000ABFEFB685B691B6806F14C001BB101907D
+:1010800001F000FE019803A901F0EEFD024648B10F
+:10109000039B2946204600F08DF8002383F3118836
+:1010A00005B0F0BDFB685A691268002AF5D01B8AAA
+:1010B000013B1340F1D104F14402EAE7093138B5AC
+:1010C00050F82140DCB1302383F31188D4F8942404
+:1010D0001368527903EB8203DB689B695D6845B155
+:1010E00004216018FFF770FE294604F1140001F096
+:1010F000F1FC2046FFF7BAFE002383F3118838BDC8
+:101100007047000001F050B8012303700023C0E9CC
+:101110000133C36183620362C36243620363704746
+:1011200038B50446302383F311880025C0E9035500
+:10113000C0E90555416001F047F80223237085F3AB
+:101140001188284638BD000070B500EB81030546C4
+:101150005069DA600E46144618B110220021FFF7DC
+:101160009DFDA06918B110220021FFF797FD3146BF
+:101170002846BDE8704001F0F1B80000826802F036
+:10118000011282600022C0E90422826101F072B97A
+:10119000F0B400EB81044789E4680125A4698D401F
+:1011A0003D43458123600023A2606360F0BC01F0F1
+:1011B0008DB90000F0B400EB81040789E4680125D3
+:1011C00064698D403D43058123600023A260636014
+:1011D000F0BC01F007BA000070B5022300250446F8
+:1011E0000370C0E90255C0E90455C564856180F803
+:1011F000345001F04FF863681B6823B1294620463C
+:10120000BDE87040184770BD0378052B10B5044643
+:101210000AD080F850300523037043681B680BB177
+:10122000042198470023A36010BD00000178052920
+:1012300006D190F85020436802701B6803B118472C
+:101240007047000070B590F83430044613B10023A5
+:1012500080F8343004F14402204601F02DF963682F
+:101260009B68B3B994F8443013F0600535D0002181
+:10127000204601F0CDFB0021204601F0BFFB636852
+:101280001B6813B1062120469847062384F83430A2
+:1012900070BD204698470028E4D0B4F84A30E26B8D
+:1012A0009A4288BFE36394F94430E56B002B4FF01A
+:1012B000300380F20381002D00F0F280092284F8CF
+:1012C000342083F311880021D4E90E232046FFF750
+:1012D00071FF002383F31188DAE794F8452003F0C7
+:1012E0007F0343EA022340F20232934200F0C580BA
+:1012F00021D8B3F5807F48D00DD8012B3FD0022BE9
+:1013000000F09380002BB2D104F14C02A2630222C0
+:10131000E2632364C1E7B3F5817F00F09B80B3F5FE
+:10132000407FA4D194F84630012BA0D1B4F84C30C2
+:1013300043F0020332E0B3F5006F4DD017D8B3F598
+:10134000A06F31D0A3F5C063012B90D8636894F8E7
+:1013500046205E6894F84710B4F848302046B047FD
+:10136000002884D04368A3630368E3631AE0B3F5FD
+:10137000106F36D040F6024293427FF478AF5C4B58
+:10138000A3630223E3630023C3E794F84630012BF1
+:101390007FF46DAFB4F84C3023F00203C4E90E556E
+:1013A000A4F84C30256478E7B4F84430B3F5A06F66
+:1013B0000ED194F8463084F84E30204600F0C2FF3B
+:1013C00063681B6813B101212046984703232370EB
+:1013D0000023C4E90E339CE704F14F03A363012308
+:1013E000C3E72378042B10D1302383F311882046E0
+:1013F000FFF7C4FE85F311880321636884F84F501A
+:1014000021701B680BB12046984794F84630002B9A
+:10141000DED084F84F300423237063681B68002BF0
+:10142000D6D0022120469847D2E794F848301D06CE
+:1014300003F00F0120460AD501F030F8012804D04E
+:1014400002287FF414AF2B4B9AE72B4B98E701F05F
+:1014500017F8F3E794F84630002B7FF408AF94F8C0
+:10146000483013F00F01B3D01A06204602D501F020
+:10147000E3FAADE701F0D6FAAAE794F84630002B7C
+:101480007FF4F5AE94F8483013F00F01A0D01B069E
+:10149000204602D501F0BCFA9AE701F0AFFA97E7CF
+:1014A000142284F8342083F311882B462A462946D7
+:1014B0002046FFF76DFE85F31188E9E65DB1152240
+:1014C00084F8342083F311880021D4E90E232046C8
+:1014D000FFF75EFEFDE60B2284F8342083F31188CB
+:1014E0002B462A4629462046FFF764FEE3E700BF65
+:1014F0002C350008243500082835000838B590F848
+:1015000034300446002B3ED0063BDAB20F2A34D8E2
+:101510000F2B32D8DFE803F0373131082232313176
+:101520003131313131313737C56BB0F84A309D42F6
+:1015300014D2C3681B8AB5FBF3F203FB12556DB9D5
+:10154000302383F311882B462A462946FFF732FEC3
+:1015500085F311880A2384F834300EE0142384F8CC
+:101560003430302383F3118800231A46194620466D
+:10157000FFF70EFE002383F3118838BD036C03B11F
+:1015800098470023E7E70021204601F041FA0021B7
+:10159000204601F033FA63681B6813B10621204628
+:1015A00098470623D7E7000010B590F83430142B85
+:1015B000044629D017D8062B05D001D81BB110BD81
+:1015C000093B022BFBD80021204601F021FA002123
+:1015D000204601F013FA63681B6813B10621204608
+:1015E0009847062319E0152BE9D10B2380F83430F6
+:1015F000302383F3118800231A461946FFF7DAFDDA
+:10160000002383F31188DAE7C3689B695B68002BCA
+:10161000D5D1036C03B19847002384F83430CEE76A
+:1016200000230375826803691B6899689142FBD2A5
+:101630005A68036042601060586070470023037569
+:10164000826803691B6899689142FBD85A680360F5
+:10165000426010605860704708B50846302383F335
+:1016600011880B7D032B05D0042B0DD02BB983F3F0
+:10167000118808BD8B6900221A604FF0FF33836127
+:10168000FFF7CEFF0023F2E7D1E9003213605A6082
+:10169000F3E70000FFF7C4BF054BD9680875186869
+:1016A00002681A60536001220275D860FEF72ABEF4
+:1016B0009823002030B50C4BDD684B1C87B00446E6
+:1016C0000FD02B46094A684600F074F92046FFF710
+:1016D000E3FF009B13B1684600F076F9A86907B0F4
+:1016E00030BDFFF7D9FFF9E798230020591600080D
+:1016F000044B1A68DB6890689B68984294BF00208E
+:101700000120704798230020084B10B51C68D8684A
+:1017100022681A60536001222275DC60FFF78EFF99
+:1017200001462046BDE81040FEF7ECBD982300209E
+:10173000044B1A68DB6892689B689A4201D9FFF7EC
+:10174000E3BF70479823002038B5074C0749084885
+:10175000012300252370656001F072FB02232370D2
+:1017600085F3118838BD00BF0026002034350008FD
+:101770009823002000F05EB9EFF3118020B9EFF359
+:101780000583302282F311887047000010B530B90C
+:10179000EFF30584C4F3080414B180F3118810BD7D
+:1017A000FFF7C6FF84F31188F9E70000034A516888
+:1017B00053685B1A9842FBD8704700BF001000E0E6
+:1017C0008B60022308618B82084670478368A3F10F
+:1017D000840243F8142C026943F8442C426943F80C
+:1017E000402C094A43F8242CC26843F8182C0222E2
+:1017F00003F80C2C002203F80B2C044A43F8102C9D
+:10180000A3F12000704700BF1D03000898230020AB
+:1018100008B5FFF7DBFFBDE80840FFF73BBF00005E
+:10182000024BDB6898610F20FFF736BF982300203A
+:10183000302383F31188FFF7F3BF000008B501469A
+:10184000302383F311880820FFF734FF002383F34C
+:10185000118808BD064BDB6839B1426818605A60D0
+:10186000136043600420FFF725BF4FF0FF3070473F
+:10187000982300200368984206D01A6802605060DE
+:1018800099611846FFF706BF7047000038B5044657
+:101890000D462068844200D138BD036823605C6037
+:1018A0008561FFF7F7FEF4E710B503689C68A24274
+:1018B0000CD85C688A600B604C6021605960996844
+:1018C0008A1A9A604FF0FF33836010BD1B68121BA9
+:1018D000ECE700000A2938BF0A2170B504460D461E
+:1018E0000A26601901F0A6FA01F092FA041BA5423B
+:1018F00003D8751C2E460446F3E70A2E04D9BDE82A
+:101900007040012001F0DCBA70BD0000F8B5144B46
+:101910000D46D96103F1100141600A2A19698260FC
+:1019200038BF0A22016048601861A818144601F007
+:1019300073FA0A2701F06CFA431BA342064606D34A
+:101940007C1C281901F076FA27463546F2E70A2F63
+:1019500004D9BDE8F840012001F0B2BAF8BD00BFDB
+:1019600098230020F8B506460D4601F051FA0F4ABB
+:10197000134653F8107F9F4206D12A46014630464F
+:10198000BDE8F840FFF7C2BFD169BB68441A2C1903
+:1019900028BF2C46A34202D92946FFF79BFF2246C7
+:1019A00031460348BDE8F840FFF77EBF982300208A
+:1019B000A823002010B4C0E9032300235DF8044BE2
+:1019C0004361FFF7CFBF000010B5194C236998425F
+:1019D0000DD0D0E90032816813605A609A680A44D9
+:1019E0009A60002303604FF0FF33A36110BD2346CC
+:1019F000026843F8102F53600022026022699A4265
+:101A000003D1BDE8104001F00FBA936881680B4420
+:101A1000936001F0FDF92269E1699268441AA242DB
+:101A2000E4D91144BDE81040091AFFF753BF00BFC5
+:101A3000982300202DE9F047DFF8BC8008F110075B
+:101A40002C4ED8F8105001F0E3F9D8F81C40AA68E1
+:101A5000031B9A423ED81444D5E900324FF00009E6
+:101A6000C8F81C4013605A60C5F80090D8F81030D0
+:101A7000B34201D101F0D8F989F31188D5E90331D6
+:101A800028469847302383F311886B69002BD8D000
+:101A900001F0BEF96A69A0EB04094A4582460DD2FD
+:101AA000022001F00DFA0022D8F81030B34208D11C
+:101AB00051462846BDE8F047FFF728BF121A2244D6
+:101AC000F2E712EB090938BF4A4629463846FFF7C4
+:101AD000EBFEB5E7D8F81030B34208D01444211A11
+:101AE000C8F81C00A960BDE8F047FFF7F3BEBDE8E9
+:101AF000F08700BFA8230020982300200020704713
+:101B0000FEE70000704700004FF0FF307047000014
+:101B100002290CD0032904D00129074818BF00204E
+:101B20007047032A05D8054800EBC20070470448F7
+:101B300070470020704700BF0C36000820220020AC
+:101B4000C035000870B59AB00546084601A914468C
+:101B500000F0C2F801A8FFF799F8431C5B00C5E943
+:101B600000340022237003236370C6B201AB023439
+:101B70001046D1B28E4204F1020401D81AB070BDF1
+:101B800013F8011B04F8021C04F8010C0132F0E701
+:101B900008B5302383F311880348FFF733FA002395
+:101BA00083F3118808BD00BF0826002090F8443058
+:101BB00003F01F02012A07D190F845200B2A03D118
+:101BC0000023C0E90E3315E003F06003202B08D199
+:101BD000B0F848302BB990F84520212A03D81F2AA5
+:101BE00004D8FFF7F1B9222AEBD0FAE7034A82635F
+:101BF0000722C26303640120704700BF182200203F
+:101C000007B5052917D8DFE801F0191603191920BF
+:101C1000302383F31188104A01900121FFF794FAD1
+:101C200001980E4A0221FFF78FFA0D48FFF7B6F927
+:101C3000002383F3118803B05DF804FB302383F3A2
+:101C400011880748FFF780F9F2E7302383F3118802
+:101C50000348FFF797F9EBE7603500088435000883
+:101C60000826002038B50C4D0C4C0D492A4604F1CD
+:101C70000800FFF767FF05F1CA0204F110000949E7
+:101C8000FFF760FF05F5CA7204F118000649BDE8C8
+:101C90003840FFF757BF00BFD02A00202022002085
+:101CA000403500084A3500085535000870B504462F
+:101CB00008460D46FEF7EAFFC6B220460134037817
+:101CC0000BB9184670BD32462946FEF7CBFF0028F7
+:101CD000F3D10120F6E700002DE9F84F05460C4648
+:101CE000FEF7D4FF2B49C6B22846FFF7DFFF08B145
+:101CF0000536F6B228492846FFF7D8FF08B1103656
+:101D0000F6B2632E0DD8DFF88C80DFF88C90234F6D
+:101D1000DFF890A0DFF890B02E7846B92670BDE8C5
+:101D2000F88F29462046BDE8F84F01F0AFBB252EBD
+:101D30002BD1072241462846FEF794FF58B9DBF81D
+:101D400000302360DBF804306360DBF80830A36008
+:101D500007350C34E0E7082249462846FEF782FFA3
+:101D600098B90F4BA21C197809090232C95D02F813
+:101D7000041C13F8011B01F00F015345C95D02F863
+:101D8000031CF0D118340835C6E704F8016B01359F
+:101D9000C2E700BF2C360008553500084136000860
+:101DA000107AFF1F1C7AFF1F34360008BFF34F8FD5
+:101DB000024AD368DB03FCD4704700BF003C0240FA
+:101DC00008B5094B1B7873B9FFF7F0FF074B1A6989
+:101DD000002ABFBF064A5A6002F188325A601A6868
+:101DE00022F480621A6008BD2E2D0020003C0240C3
+:101DF0002301674508B50B4B1B7893B9FFF7D6FF56
+:101E0000094B1A6942F000421A611A6842F4805282
+:101E10001A601A6822F480521A601A6842F48062CA
+:101E20001A6008BD2E2D0020003C02400B28F0B5A2
+:101E300016D80C4C0C4923787BB90C4D0E460C235C
+:101E40004FF0006255F8047B46F8042B013B13F079
+:101E5000FF033A44F6D10123237051F82000F0BD6E
+:101E60000020FCE7602D0020302D002054360008B3
+:101E7000014B53F820007047543600080C2070477F
+:101E80000B2810B5044601D9002010BDFFF7CEFF86
+:101E9000064B53F824301844C21A0BB90120F4E75A
+:101EA00012680132F0D1043BF6E700BF5436000857
+:101EB0000B2838B5044628D8FFF75EFCFFF776FFFD
+:101EC000FFF77EFF124AF323D360E300DBB243F453
+:101ED000007343F002031361136943F48033136109
+:101EE00005462046FFF762FFFFF7A0FF094B53F8B6
+:101EF000241000F0E9F82846FFF77CFFFFF746FCC6
+:101F00002046BDE83840FFF7BBBF002038BD00BF0A
+:101F1000003C02405436000812F001032DE9F04164
+:101F200005460E4614464BD18218B2F1016F61D8B6
+:101F3000314B1B6813F001035CD0304FFFF71CFCE2
+:101F4000FFF73EFFF323FB60FFF730FF314640F21F
+:101F50000128032C18D824F00104284E0C446D1AD3
+:101F600040F20118A142336905EB01072AD123F0A1
+:101F700001033361FFF73EFFFFF708FC0120BDE8D6
+:101F8000F081043C0435E4E7AB07E4D13B6923F47A
+:101F900040733B613B6943EA08033B6151F8046BC2
+:101FA0002E60BFF34F8FFFF701FF2B689E42E8D0F2
+:101FB0003B6923F001033B61FFF71CFFFFF7E6FBE2
+:101FC0000020DCE723F440733361336943EA0803FC
+:101FD00033610B883B80BFF34F8FFFF7E7FE3F88ED
+:101FE00031F8023BBFB2BB42BCD0336923F00103DE
+:101FF0003361E1E71846C2E700380240003C024086
+:10200000084908B50B7828B11BB9FFF7D9FE0123A1
+:102010000B7008BD002BFCD0BDE808400870FFF72E
+:10202000E9BE00BF2E2D002010B50244064BD2B2EF
+:10203000904200D110BD441C00B253F8200041F87A
+:10204000040BE0B2F4E700BF502800400F4B30B55E
+:102050001C6F240407D41C6F44F400741C671C6FAD
+:1020600044F400441C670A4C236843F480732360E3
+:102070000244084BD2B2904200D130BD441C00B2A1
+:1020800051F8045B43F82050E0B2F4E70038024016
+:10209000007000405028004007B5012201A900202F
+:1020A000FFF7C2FF019803B05DF804FB13B50446C7
+:1020B000FFF7F2FFA04205D0012201A90020019400
+:1020C000FFF7C4FF02B010BD70470000034B1A6851
+:1020D0001AB9034AD2F874281A607047642D002098
+:1020E0000030024008B5FFF7F1FF024B1868C0F35B
+:1020F000407008BD642D002070470000FEE700001E
+:102100000A4B0B480B4A90420BD30B4BDA1C121AAA
+:10211000C11E22F003028B4238BF00220021FEF7CD
+:10212000BDBD53F8041B40F8041BECE70038000861
+:10213000602E0020602E0020602E002070B5D0E9B7
+:1021400015439E6800224FF0FF3504EB4213510106
+:10215000D3F800090028BEBFD3F8000940F0804042
+:10216000C3F80009D3F8000B0028BEBFD3F8000B5A
+:1021700040F08040C3F8000B013263189642C3F868
+:102180000859C3F8085BE0D24FF00113C4F81C38BB
+:1021900070BD0000890141F02001016103699B06C7
+:1021A000FCD41220FFF702BB10B5054C2046FEF709
+:1021B000ABFF4FF0A0436365024BA36510BD00BFAA
+:1021C000682D0020A836000870B50378012B05465D
+:1021D00050D12A4B446D98421BD1294B5A6B42F087
+:1021E00080025A635A6D42F080025A655A6D5A69EC
+:1021F00042F080025A615A6922F080025A610E212F
+:1022000043205B6900F022FC1E4BE3601E4BC4F8C8
+:1022100000380023C4F8003EC02323606E6D4FF4E5
+:102220000413A3633369002BFCDA012333610C2010
+:10223000FFF7BCFA3369DB07FCD41220FFF7B6FACC
+:102240003369002BFCDA0026A6602846FFF776FFEC
+:102250006B68C4F81068DB68C4F81468C4F81C68BC
+:102260004BB90A4BA3614FF0FF336361A36843F09E
+:102270000103A36070BD064BF4E700BF682D00208A
+:10228000003802404014004003002002003C30C0EF
+:10229000083C30C0F8B5446D054600212046FFF7E4
+:1022A00079FFA96D00234FF001128F68C4F834380C
+:1022B0004FF00066C4F81C284FF0FF3004EB4312C7
+:1022C00001339F42C2F80069C2F8006BC2F80809E6
+:1022D000C2F8080BF2D20B686A6DEB6563621023DB
+:1022E0001361166916F01006FBD11220FFF75EFA93
+:1022F000D4F8003823F4FE63C4F80038A36943F42B
+:10230000402343F01003A3610923C4F81038C4F834
+:1023100014380A4BEB604FF0C043C4F8103B084B35
+:10232000C4F8003BC4F81069C4F80039EB6D03F140
+:10233000100243F48013EA65A362F8BD84360008F6
+:1023400040800010426D90F84E10D2F8003823F40F
+:10235000FE6343EA0113C2F8003870472DE9F843E1
+:1023600000EB8103456DDA68166806F00306731EFC
+:10237000022B05EB41130C4680460FFA81F94FEA18
+:1023800041104FF00001C3F8101B4FF0010104F1A0
+:10239000100398BFB60401FA03F391698EBF334E60
+:1023A00006F1805606F5004600293AD0578A04F116
+:1023B0005801490137436F50D5F81C180B43C5F835
+:1023C0001C382B180021C3F8101953690127611E0E
+:1023D000A7409BB3138A928B9B08012A88BF534363
+:1023E000D8F85C20981842EA034301F1400205EB5B
+:1023F0008202C8F85C00214653602846FFF7CAFEF7
+:1024000008EB8900C3681B8A43EA8453483464019B
+:102410001E432E51D5F81C381F43C5F81C78BDE863
+:10242000F88305EB4917D7F8001B21F40041C7F8E2
+:10243000001BD5F81C1821EA0303C0E704F13F0391
+:1024400005EB83030A4A5A6028462146FFF7A2FE9D
+:1024500005EB4910D0F8003923F40043C0F80039E7
+:10246000D5F81C3823EA0707D7E700BF0080001023
+:1024700000040002826D1268C265FFF75FBE0000B3
+:102480005831436D49015B5813F4004004D013F4F4
+:10249000001F0CBF02200120704700004831436D2F
+:1024A00049015B5813F4004004D013F4001F0CBF23
+:1024B000022001207047000000EB8101CB68196AFF
+:1024C0000B6813604B6853607047000000EB81039A
+:1024D00030B5DD68AA691368D36019B9402B84BF91
+:1024E000402313606B8A1468426D1C44013CB4FBAA
+:1024F000F3F46343033323F0030302EB411043EA95
+:10250000C44343F0C043C0F8103B2B6803F00303FF
+:10251000012B09B20ED1D2F8083802EB411013F4A6
+:10252000807FD0F8003B14BF43F0805343F000534A
+:10253000C0F8003B02EB4112D2F8003B43F00443E9
+:10254000C2F8003B30BD00002DE9F041244D6E6D16
+:1025500006EB40130446D3F8087BC3F8087B380722
+:102560000AD5D6F81438190706D505EB8403214699
+:10257000DB6828465B689847FA071FD5D6F81438F9
+:10258000DB071BD505EB8403D968CCB98B69488A76
+:102590005A68B2FBF0F600FB16228AB91868DA68AE
+:1025A00090420DD2121AC3E90024302383F311881C
+:1025B0000B482146FFF78AFF84F31188BDE8F081BC
+:1025C000012303FA04F26B8923EA02036B81CB68CF
+:1025D000002BF3D021460248BDE8F041184700BF68
+:1025E000682D002000EB810370B5DD68436D6C69D8
+:1025F0002668E6604A0156BB1A444FF40020C2F830
+:1026000010092A6802F00302012A0AB20ED1D3F897
+:10261000080803EB421410F4807FD4F8000914BFBB
+:1026200040F0805040F00050C4F8000903EB421223
+:10263000D2F8000940F00440C2F80009D3F8340889
+:10264000012202FA01F10143C3F8341870BD19B92F
+:10265000402E84BF4020206020682E8A8419013CCF
+:10266000B4FBF6F440EAC44040F000501A44C6E718
+:102670002DE9F8433B4D6E6D06EB40130446D3F84D
+:102680000889C3F8088918F0010F4FEA40171AD0DB
+:10269000D6F81038DB0716D505EB8003D9684B69EF
+:1026A0001868DA68904230D2121A4FF000091A60A6
+:1026B000C3F80490302383F3118821462846FFF79E
+:1026C00091FF89F3118818F0800F1CD0D6F83438A8
+:1026D0000126A640334216D005EB84036D6DD3F876
+:1026E0000CC0DCF814200134E4B2D2F800E005EBB1
+:1026F00004342F445168714515D3D5F8343823EA92
+:102700000606C5F83468BDE8F883012303FA04F22D
+:102710002B8923EA02032B818B68002BD3D021461F
+:1027200028469847CFE7BCF81000AEEB0103834280
+:1027300028BF0346D7F8180980B2B3EB800FE2D860
+:102740009068A0F1040959F8048FC4F80080A0EB48
+:1027500009089844B8F1040FF5D818440B44906068
+:102760005360C7E7682D00202DE9F74FA24C656D37
+:102770006E69AB691E4016F480586E6107D0204622
+:10278000FEF72AFD03B0BDE8F04F00F047BC002E75
+:1027900012DAD5F8003E98489B071EBFD5F8003ED8
+:1027A00023F00303C5F8003ED5F8043823F00103F5
+:1027B000C5F80438FEF73AFD370505D58E48FFF712
+:1027C000BDFC8D48FEF720FDB0040CD5D5F80838C7
+:1027D00013F0060FEB6823F470530CBF43F410534F
+:1027E00043F4A053EB6031071BD56368DB681BB96A
+:1027F000AB6923F00803AB612378052B0CD1D5F826
+:10280000003E7D489A071EBFD5F8003E23F0030323
+:10281000C5F8003EFEF70AFD6368DB680BB1764839
+:102820009847F30274D4B70227D5D4F85490DFF850
+:10283000C8B100274FF0010A09EB4712D2F8003B5C
+:1028400003F44023B3F5802F11D1D2F8003B002BC5
+:102850000DDA62890AFA07F322EA0303638104EBC3
+:102860008703DB68DB6813B1394658469847A36D88
+:1028700001379B68FFB29F42DED9F00617D5676D1E
+:102880003A6AC2F30A1002F00F0302F4F012B2F532
+:10289000802F00F08580B2F5402F08D104EB830330
+:1028A0000022DB681B6A07F5805790426AD130032B
+:1028B000D5F8184813D5E10302D50020FFF744FEF0
+:1028C000A20302D50120FFF73FFE630302D50220D9
+:1028D000FFF73AFE270302D50320FFF735FE750305
+:1028E0007FF550AFE00702D50020FFF7C1FEA1073A
+:1028F00002D50120FFF7BCFE620702D50220FFF7D8
+:10290000B7FE23077FF53EAF0320FFF7B1FE39E79F
+:10291000636DDFF8E4A0019300274FF00109A36D78
+:102920009B685FFA87FB9B453FF67DAF019B03EBFE
+:102930004B13D3F8001901F44021B1F5802F1FD1BA
+:10294000D3F8001900291BDAD3F8001941F090419F
+:10295000C3F80019D3F800190029FBDB5946606D54
+:10296000FFF718FC218909FA0BF321EA03032381FD
+:1029700004EB8B03DB689B6813B1594650469847BC
+:102980000137CCE7910708BFD7F80080072A98BF26
+:1029900003F8018B02F1010298BF4FEA182884E77F
+:1029A000023304EB830207F580575268D2F818C04F
+:1029B000DCF80820DCE9001CA1EB0C0C00218842AB
+:1029C0000AD104EB830463689B699A6802449A60A5
+:1029D0005A6802445A606AE711F0030F08BFD7F83B
+:1029E00000808C4588BF02F8018B01F1010188BF8E
+:1029F0004FEA1828E3E700BF682D0020436D03EB82
+:102A00004111D1F8003B43F40013C1F8003B70477B
+:102A1000436D03EB4111D1F8003943F40013C1F8C1
+:102A200000397047436D03EB4111D1F8003B23F4AB
+:102A30000013C1F8003B7047436D03EB4111D1F81F
+:102A4000003923F40013C1F80039704700F16043E6
+:102A500003F561430901C9B283F80013012200F0B4
+:102A60001F039A4043099B0003F1604303F5614350
+:102A7000C3F880211A60704730B5039C017204339B
+:102A800004FB0325C0E90653049B03630021059B57
+:102A9000C160C0E90000C0E90422C0E90842C0E901
+:102AA0000A11436330BD0000416A0022C0E90411ED
+:102AB000C0E90A22C2606FF00101FEF7E7BE000024
+:102AC000D0E90432934201D1C2680AB9181D704797
+:102AD0000020704703691960C2680132C260C26990
+:102AE000134482690361934224BF436A0361002156
+:102AF000FEF7C0BE38B504460D46E3683BB16269D7
+:102B0000131D1268A3621344E362002007E0237AD6
+:102B100033B929462046FEF79DFE0028EDDA38BD80
+:102B20006FF00100FBE70000C368C269013BC360AE
+:102B30004369134482694361934224BF436A4361FA
+:102B400000238362036B03B11847704770B53023CD
+:102B5000044683F31188866A3EB9FFF7CBFF05462A
+:102B600018B186F31188284670BDA36AE26A13F88B
+:102B7000015BA362934202D32046FFF7D5FF0023F7
+:102B800083F31188EFE700002DE9F84F04460E4665
+:102B9000174698464FF0300989F311880025AA4658
+:102BA000D4F828B0BBF1000F09D141462046FFF709
+:102BB000A1FF20B18BF311882846BDE8F88FD4E936
+:102BC0000A12A7EB050B521A934528BF9346BBF197
+:102BD000400F1BD9334601F1400251F8040B43F872
+:102BE000040B9142F9D1A36A40334036A3624035C9
+:102BF000D4E90A239A4202D32046FFF795FF8AF3CD
+:102C00001188BD42D8D289F31188C9E730465A46A7
+:102C1000FEF71EF8A36A5B445E44A3625D44E7E7E7
+:102C200010B5029C0172043303FB0421C0E90613B2
+:102C30000023C0E90A33039B0363049BC460C0E91B
+:102C40000000C0E90422C0E90842436310BD00004F
+:102C5000026AC260426AC0E904220022C0E90A2274
+:102C60006FF00101FEF712BED0E904239A4201D1B0
+:102C7000C26822B9184650F8043B0B607047002325
+:102C80001846FAE7C368C2690133C3604369134455
+:102C900082694361934224BF436A43610021FEF786
+:102CA000E9BD000038B504460D46E3683BB1236931
+:102CB0001A1DA262E2691344E362002007E0237A4E
+:102CC00033B929462046FEF7C5FD0028EDDA38BDA8
+:102CD0006FF00100FBE7000003691960C268013A68
+:102CE000C260C269134482690361934224BF436A8C
+:102CF000036100238362036B03B118477047000030
+:102D000070B530230D460446114683F31188866A58
+:102D10002EB9FFF7C7FF10B186F3118870BDA36A03
+:102D20001D70A36AE26A01339342A36204D3E1698E
+:102D300020460439FFF7D0FF002080F31188EDE72B
+:102D40002DE9F84F04460D46904699464FF0300A5B
+:102D50008AF311880026B346A76A4FB94946204630
+:102D6000FFF7A0FF20B187F311883046BDE8F88F48
+:102D7000D4E90A073A1AA8EB0607974228BF174674
+:102D8000402F1BD905F1400355F8042B40F8042BC4
+:102D90009D42F9D1A36A4033A3624036D4E90A23A5
+:102DA0009A4204D3E16920460439FFF795FF8BF37B
+:102DB00011884645D9D28AF31188CDE729463A468B
+:102DC000FDF746FFA36A3B443D44A3623E44E5E76A
+:102DD000D0E904239A4217D1C3689BB1836A8BB1AF
+:102DE000043B9B1A0ED01360C368013BC360C369E8
+:102DF0001A44836902619A4224BF436A0361002333
+:102E000083620123184670470023FBE700F030B9C6
+:102E10004FF08043586A70474FF080430022586358
+:102E20001A610222DA6070474FF080430022DA60B4
+:102E3000704700004FF0804358637047FEE7000082
+:102E400070B51B4B01630025044686B0586085624F
+:102E50000E4600F0BFF804F11003C4E904334FF04C
+:102E6000FF33C4E90635C4E90044A560E562FFF715
+:102E7000CFFF2B460246C4E9082304F134010D4A72
+:102E8000256580232046FEF79BFC0123E0600A4A6B
+:102E90000375009272680192B268CDE90223074B74
+:102EA0006846CDE90435FEF7B3FC06B070BD00BF3F
+:102EB00000260020B4360008B93600083D2E000870
+:102EC000024AD36A1843D062704700BF982300209B
+:102ED0004B6843608B688360CB68C3600B69436158
+:102EE0004B6903628B6943620B68036070470000A3
+:102EF00008B5264B26481A6940F2FF110A431A61A9
+:102F00001A6922F4FF7222F001021A611A691A6B1F
+:102F10000A431A631A6D0A431A651E4A1B6D11464D
+:102F2000FFF7D6FF02F11C0100F58060FFF7D0FF2C
+:102F300002F1380100F58060FFF7CAFF02F1540189
+:102F400000F58060FFF7C4FF02F1700100F58060BA
+:102F5000FFF7BEFF02F18C0100F58060FFF7B8FFBC
+:102F600002F1A80100F58060FFF7B2FF02F1C40191
+:102F700000F58060FFF7ACFF02F1E00100F5806032
+:102F8000FFF7A6FFBDE8084000F0EEB800380240A9
+:102F900000000240C036000808B500F059FAFEF7FC
+:102FA000D3FBFFF793F8BDE80840FEF75BBE0000D7
+:102FB00070470000EFF3098305494A6B22F00102D4
+:102FC0004A63683383F30988002383F311887047C9
+:102FD00000EF00E0302080F3118862B60C4B0D4A00
+:102FE000D96821F4E0610904090C0A43DA60D3F8D6
+:102FF000FC20094942F08072C3F8FC200A6842F0C4
+:1030000001020A602022DA7783F82200704700BFAD
+:1030100000ED00E00003FA05001000E010B53023D9
+:1030200083F311880E4B5B6813F4006314D0F1EE48
+:10303000103AEFF30984683C4FF08073E361094B69
+:10304000DB6B236684F30988FEF752FB10B1064B55
+:10305000A36110BD054BFBE783F31188F9E700BFBF
+:1030600000ED00E000EF00E02F030008320300084D
+:103070000F4B1A6C42F001021A641A6E42F0010200
+:103080001A660C4A1B6E936843F0010393604FF07D
+:10309000804353229A624FF0FF32DA6200229A6133
+:1030A0005A63DA605A6001225A611A60704700BFA1
+:1030B00000380240002004E04FF0804208B511695A
+:1030C000D3680B40D9B2C9439B07116107D53023A0
+:1030D00083F31188FEF74EFB002383F3118808BDAC
+:1030E0001F4B1A696FEAC2526FEAD2521A611A690B
+:1030F000C2F308021A614FF0FF301A695A69586129
+:1031000000215A6959615A691A6A62F080521A623A
+:103110001A6A02F080521A621A6A5A6A58625A6A25
+:1031200059625A6A1A6C42F080521A641A6E42F05E
+:1031300080521A661A6E0B4A106840F48070106054
+:10314000186F00F44070B0F5007F1EBF4FF4803060
+:1031500018671967536823F40073536000F054B97B
+:103160000038024000700040334B4FF080521A6428
+:10317000324A4FF4404111601A6842F001021A606D
+:103180001A689107FCD59A6822F003029A602A4BCC
+:103190009A6812F00C02FBD1196801F0F90119606C
+:1031A0009A601A6842F480321A601A689203FCD559
+:1031B0005A6F42F001025A671F4B5A6F9007FCD5B5
+:1031C0001F4A5A601A6842F080721A601B4A53689C
+:1031D0005904FCD5184B1A689201FCD5194A9A601B
+:1031E000194B1A68194B9A42194B21D1194A116887
+:1031F000194A91421CD140F205121A60144A136810
+:1032000003F00F03052BFAD10B4B9A6842F0020230
+:103210009A609A6802F00C02082AFAD15A6C42F4B9
+:1032200080425A645A6E42F480425A665B6E70471E
+:1032300040F20572E1E700BF003802400070004034
+:103240000854400700948838002004E011640020EE
+:10325000003C024000ED00E041C20F41074A08B5C2
+:10326000536903F00103536123B1054A13680BB19D
+:1032700050689847BDE80840FFF7D0BE003C0140C9
+:10328000E02D0020074A08B5536903F0020353619B
+:1032900023B1054A93680BB1D0689847BDE8084050
+:1032A000FFF7BCBE003C0140E02D0020074A08B5F6
+:1032B000536903F00403536123B1054A13690BB149
+:1032C00050699847BDE80840FFF7A8BE003C0140A0
+:1032D000E02D0020074A08B5536903F00803536145
+:1032E00023B1054A93690BB1D0699847BDE80840FE
+:1032F000FFF794BE003C0140E02D0020074A08B5CE
+:10330000536903F01003536123B1054A136A0BB1EB
+:10331000506A9847BDE80840FFF780BE003C014076
+:10332000E02D0020164B10B55C6904F478725A61E8
+:10333000A30604D5134A936A0BB1D06A9847600676
+:1033400004D5104A136B0BB1506B9847210604D576
+:103350000C4A936B0BB1D06B9847E20504D5094A30
+:10336000136C0BB1506C9847A30504D5054A936CB8
+:103370000BB1D06C9847BDE81040FFF74FBE00BFBF
+:10338000003C0140E02D0020194B10B55C6904F4AD
+:103390007C425A61620504D5164A136D0BB1506D1B
+:1033A0009847230504D5134A936D0BB1D06D984708
+:1033B000E00404D50F4A136E0BB1506E9847A10478
+:1033C00004D50C4A936E0BB1D06E9847620404D5B5
+:1033D000084A136F0BB1506F9847230404D5054A70
+:1033E000936F0BB1D06F9847BDE81040FFF716BE42
+:1033F000003C0140E02D002008B5FFF75DFEBDE870
+:103400000840FFF70BBE0000062108B50846FFF78D
+:103410001DFB06210720FFF719FB06210820FFF7F7
+:1034200015FB06210920FFF711FB06210A20FFF7F3
+:103430000DFB06211720FFF709FB06212820FFF7C7
+:1034400005FBBDE8084007211C20FFF7FFBA00007C
+:1034500008B5FFF745FE00F00BF8FDF753FEFDF74A
+:103460002BFDFFF7A5FDBDE80840FFF7CFBC00002E
+:103470000023054A19460133102BC2E9001102F15D
+:103480000802F8D1704700BFE02D0020034611F874
+:10349000012B03F8012B002AF9D1704753544D3307
+:1034A00032463F3F3F0053544D333246343078006C
+:1034B00053544D3332463432780053544D333246F0
+:1034C0003434365858000000012033000010410009
+:1034D00001105A00031059000710310000000000CD
+:1034E0009C34000813040000A634000819040000EE
+:1034F000B034000821040000BA34000800000000C5
+:10350000350E0008210E00085D0E0008490E000867
+:10351000550E0008410E00082D0E0008190E000877
+:10352000690E00080000000001000000000000001B
+:103530006330000030350008F02300200026002012
+:103540004172647550696C6F740025424F4152445A
+:10355000252D424C002553455249414C2500000081
+:10356000020000000000000051100008BD1000081B
+:1035700040004000A02A0020B02A002002000000E5
+:10358000000000000300000000000000011100081E
+:103590000000000010000000C02A00200000000011
+:1035A0000100000000000000682D00200101020061
+:1035B000011C0008111B0008AD1B0008911B00082E
+:1035C00043000000C835000809024300020100C0A2
+:1035D0003209040000010202010005240010010567
+:1035E00024010001042402020524060001070582CB
+:1035F000030800FF09040100020A0000000705019A
+:103600000240000007058102400000001200000097
+:10361000143600081201100102000040091241573F
+:1036200000020102030100000403090425424F4186
+:1036300052442500424554414650562D46343035BB
+:10364000003031323334353637383941424344451E
+:103650004600000000400000004000000040000064
+:103660000040000000000100000002000000020015
+:103670000000020000000200000002000000020042
+:10368000000002000000000045120008FD140008C0
+:10369000A915000840004000C82D0020C82D0020BA
+:1036A00001000000D82D0020800000004001000033
+:1036B000030000006D61696E0069646C65000000C4
+:1036C0000001806A00000000AAAAAAAA0001006402
+:1036D000FFFF00000000000000A00A0040040001FD
+:1036E00000000000AAAAAAAA40000001DFFF000013
+:1036F00000000000000000000000000000000000CA
+:10370000AAAAAAAA00000000FFFF00000000000013
+:10371000000000000000000000000000AAAAAAAA01
+:1037200000000000FFFF000000000000000000009B
+:103730000000000000000000AAAAAAAA00000000E1
+:10374000FFFF00000000000000000000000000007B
+:1037500000000000AAAAAAAA00000000FFFF0000C3
+:103760000000000000000000000000000000000059
+:10377000AAAAAAAA00000000FFFF000000000000A3
+:103780000000000000000000000000000A0000002F
+:103790000000000003000000000000000000000026
+:1037A0000000000000000000000000000000000019
+:1037B0000000000000000000000000000000000009
+:1037C000650400000000000000400F000000000041
+:1037D000FF009600000000080096000000000800AE
+:1037E000040000002836000800000000000000006F
+:1037F00000000000000000000000000000000000C9
+:00000001FF
diff --git a/Tools/bootloaders/BlitzF745AIO_bl.bin b/Tools/bootloaders/BlitzF745AIO_bl.bin
new file mode 100644
index 00000000000000..236d1232ad9c58
Binary files /dev/null and b/Tools/bootloaders/BlitzF745AIO_bl.bin differ
diff --git a/Tools/bootloaders/BlitzF745AIO_bl.hex b/Tools/bootloaders/BlitzF745AIO_bl.hex
new file mode 100644
index 00000000000000..bc63584f781b8a
--- /dev/null
+++ b/Tools/bootloaders/BlitzF745AIO_bl.hex
@@ -0,0 +1,931 @@
+:020000040800F2
+:1000000000060120010200080302000803020008A4
+:1000100003020008030200080302000803020008AC
+:10002000030200080302000803020008B1310008BF
+:10003000030200080302000803020008030200088C
+:10004000030200080302000803020008030200087C
+:100050000302000803020008593400088134000834
+:10006000A9340008D1340008F9340008030200085C
+:10007000030200080302000803020008030200084C
+:10008000030200080302000803020008030200083C
+:1000900003020008030200080302000821350008DB
+:1000A000030200080302000803020008030200081C
+:1000B000F5350008030200080302000803020008E7
+:1000C00003020008030200080302000803020008FC
+:1000D00003020008030200080302000803020008EC
+:1000E0008535000803020008030200080302000827
+:1000F00003020008030200080302000803020008CC
+:1001000003020008030200080302000803020008BB
+:1001100003020008030200080302000803020008AB
+:10012000030200080302000803020008030200089B
+:10013000030200080302000803020008030200088B
+:100140000302000803020008030200082529000832
+:10015000030200080302000803020008030200086B
+:10016000030200080302000803020008030200085B
+:10017000030200080302000803020008030200084B
+:10018000030200080302000803020008030200083B
+:10019000030200080302000803020008030200082B
+:1001A000030200080302000803020008030200081B
+:1001B000030200080302000803020008030200080B
+:1001C00003020008030200080302000803020008FB
+:1001D00003020008030200080302000803020008EB
+:1001E00003020008030200080302000803020008DB
+:1001F00003020008030200080302000803020008CB
+:1002000002E000F000F8FEE772B6374880F3088895
+:10021000364880F3098836483649086040F20000C5
+:10022000CCF200004EF63471CEF200010860BFF34C
+:100230004F8FBFF36F8F40F20000C0F2F0004EF618
+:100240008851CEF200010860BFF34F8FBFF36F8F6C
+:100250004FF00000E1EE100A4EF63C71CEF20001C4
+:100260000860062080F31488BFF36F8F01F0B4FF9D
+:1002700002F030FF4FF055301F491B4A91423CBFFE
+:1002800041F8040BFAE71D49184A91423CBF41F876
+:10029000040BFAE71A491B4A1B4B9A423EBF51F81E
+:1002A000040B42F8040BF8E700201849184A914261
+:1002B0003CBF41F8040BFAE701F0CCFF02F06AFF03
+:1002C000144C154DAC4203DA54F8041B8847F9E787
+:1002D00000F042F8114C124DAC4203DA54F8041B02
+:1002E0008847F9E701F0B4BF000601200022012091
+:1002F0000000000808ED00E00000012000060120D9
+:10030000B0390008002201205C2201206022012077
+:10031000882E0120000200080002000800020008E8
+:10032000000200082DE9F04F2DED108AC1F80CD025
+:10033000D0F80CD0BDEC108ABDE8F08F002383F319
+:1003400011882846A047002001F0DCFAFEE701F002
+:100350003DFA00DFFEE7000038B501F0FDFE05467E
+:1003600001F030FF0446D8B90F4B9D421AD001333B
+:100370009D4218BF044641F2883504BF0124002580
+:10038000002001F0F3FE0CB100F078F800F030FD31
+:1003900000F0EEFB284600F0F5F800F06FF8F9E702
+:1003A0000025EDE70546EBE7010007B008B500F0D2
+:1003B000B1FBA0F120035842584108BD07B541F2F6
+:1003C0001203022101A8ADF8043000F0C1FB03B014
+:1003D0005DF804FB38B572B6302383F3118862B63A
+:1003E000174803680BB101F05BFB164A1448002361
+:1003F0004FF47A7101F04AFB002383F31188124C09
+:10040000236813B12368013B2360636813B16368F9
+:10041000013B63600D4D2B7833B963687BB90220D3
+:1004200000F068FC322363602B78032B07D16368EC
+:100430002BB9022000F05EFC4FF47A73636038BD84
+:1004400060220120D50300088023012078220120AA
+:10045000084B187003280CD8DFE800F008050208E4
+:10046000022000F045BC022000F040BC024B0022FC
+:100470005A6070477822012080230120F8B53C4B58
+:100480003C4A1C461968013170D004339342F9D1BB
+:100490006268A2426AD3384B9B6803F1006303F59C
+:1004A000C0339A4262D2002000F07CFB0220FFF7AA
+:1004B000CFFF324B00211A6C19641A6E19661A6E3E
+:1004C0005A6C59645A6E59665A6E1A6942F0005253
+:1004D0001A611A6922F000521A611B6972B64FF054
+:1004E000E023C3F8084DD4E90004BFF34F8FBFF3F6
+:1004F0006F8F234AC2F88410BFF34F8F536923F4E0
+:1005000080335361BFF34F8FD2F88030C3F3C905F6
+:10051000C3F34E335B0143F6E07603EA060C29464B
+:100520004CEA81770139C2F87472F9D2203B13F199
+:10053000200FF2D1BFF34F8FBFF36F8FBFF34F8FF9
+:10054000BFF36F8F536923F4003353610023C2F864
+:100550005032BFF34F8FBFF36F8F72B6302383F3E8
+:10056000118862B6854680F308882047F8BD00BF31
+:10057000008001082080010800220120003802408C
+:1005800000ED00E02DE9F04F93B0B64B0090202233
+:10059000FF210AA89D6800F0D5FBB34A1378B3B9D0
+:1005A000B24801211170036072B6302383F31188C1
+:1005B00062B603680BB101F073FAAD4AAB48002391
+:1005C0004FF47A7101F062FA002383F31188009BE3
+:1005D00013B1A84B009A1A60A74A009C1378032B0A
+:1005E0001EBF00231370A34A4FF0000A18BF5360C8
+:1005F000D3465646D146012000F07AFB24B19D4BEC
+:100600001B68002B00F02782002000F083FA039083
+:10061000039B002BF2DB012000F068FB039B213BD6
+:100620001F2BE8D801A252F823F000BFAD06000846
+:10063000D506000869070008F7050008F705000857
+:10064000F7050008FB070008CB090008E5080008CB
+:10065000470900086F09000895090008F705000818
+:10066000A7090008F7050008190A00084D07000847
+:10067000F70500085D0A0008B90600084D070008E4
+:10068000F705000847090008F7050008F705000806
+:10069000F7050008F7050008F7050008F70500084A
+:1006A000F7050008F7050008690700080220FFF7B2
+:1006B0007DFE002840F0F981009B0221BAF1000F75
+:1006C00008BF1C4605A841F21233ADF8143000F003
+:1006D0003FFA90E74FF47A7000F01CFA071EEBDB4C
+:1006E0000220FFF763FE0028E6D0013F052F00F24D
+:1006F000DE81DFE807F0030A0D10133605230593AA
+:10070000042105A800F024FA17E056480421F9E76F
+:100710005A480421F6E75A480421F3E74FF01C0831
+:10072000404600F041FA08F104080590042105A8AC
+:1007300000F00EFAB8F12C0FF2D1012000FA07F701
+:1007400047EA0B0B5FFA8BFB4FF0000900F046FB0A
+:1007500026B10BF00B030B2B08BF0024FFF72EFE76
+:1007600049E748480421CDE7002EA5D00BF00B0344
+:100770000B2BA1D10220FFF719FE074600289BD0C2
+:10078000012000F00FFA0220FFF762FE00265FFA58
+:1007900086F8404600F016FA0446B0B10399A1F17C
+:1007A000400251425141404600F01CFA01360028F7
+:1007B000EDD1BA46044641F21213022105A8ADF864
+:1007C00014303E4600F0C4F915E70120FFF740FE63
+:1007D0002546244B9B68AB4207D9284600F0E4F934
+:1007E000013040F067810435F3E7234B00251D708D
+:1007F000204BBA465D603E46A8E7002E3FF45CAF52
+:100800000BF00B030B2B7FF457AF0220FFF720FEFA
+:10081000322000F07FF9B0F10008FFF64DAF18F07C
+:1008200003077FF449AF0F4A926808EB0503934230
+:100830003FF642AFB8F5807F3FF73EAF124B0193D2
+:10084000B84523DD4FF47A7000F064F90390039A01
+:10085000002AFFF631AF019B039A03F8012B013701
+:10086000EDE700BF002201207C230120602201204F
+:10087000D5030008802301207822012004220120D2
+:10088000082201200C2201207C220120C820FFF731
+:100890008DFD074600283FF40FAF1F2D11D8C5F17D
+:1008A000200242450AAB25F0030028BF4246834997
+:1008B0000192184400F020FA019A8048FF2100F0CC
+:1008C00041FA4FEAA8037D490193C8F387022846FD
+:1008D00000F040FA064600283FF46DAF019B05EB9F
+:1008E000830533E70220FFF761FD00283FF4E4AE03
+:1008F00000F0A4F900283FF4DFAE0027B846704BA3
+:100900009B68BB4218D91F2F11D80A9B01330ED008
+:1009100027F0030312AA134453F8203C05934046E2
+:10092000042205A900F08EFA04378046E7E738462E
+:1009300000F03AF90590F2E7CDF81480042105A8FB
+:1009400000F006F902E70023642104A8049300F0F4
+:10095000F5F800287FF4B0AE0220FFF727FD00284D
+:100960003FF4AAAE049800F051F90590E6E70023A1
+:10097000642104A8049300F0E1F800287FF49CAE01
+:100980000220FFF713FD00283FF496AE049800F014
+:100990004DF9EAE70220FFF709FD00283FF48CAE8D
+:1009A00000F05CF9E1E70220FFF700FD00283FF4CA
+:1009B00083AE05A9142000F057F9042107460490DE
+:1009C00004A800F0C5F83946B9E7322000F0A2F8D3
+:1009D000071EFFF671AEBB077FF46EAE384A926811
+:1009E00007EB090393423FF667AE0220FFF7DEFCF8
+:1009F00000283FF461AE27F003074F44B9453FF4A8
+:100A0000A5AE484600F0D0F80421059005A800F0F6
+:100A10009FF809F10409F1E74FF47A70FFF7C6FC7B
+:100A200000283FF449AE00F009F9002844D00A9BA1
+:100A300001330BD008220AA9002000F08BF900280E
+:100A40003AD02022FF210AA800F07CF9FFF7B6FC7B
+:100A50001C4800F05FFF13B0BDE8F08F002E3FF49C
+:100A60002BAE0BF00B030B2B7FF426AE002364217F
+:100A700005A8059300F062F8074600287FF41CAE35
+:100A80000220FFF793FC804600283FF415AEFFF7E5
+:100A900095FC41F2883000F03DFF059800F0D0F958
+:100AA000464600F09BF93C46A5E506464EE64FF06B
+:100AB000000901E6BA467EE637467CE67C22012044
+:100AC00000220120A086010070B50F4B1B78013376
+:100AD000DBB2012B0C4611D80C4D29684FF47A7308
+:100AE0000E6AA2FB0332014622462846B0478442E2
+:100AF00004D1074B00221A70012070BD4FF4FA7028
+:100B000000F008FF0020F8E710220120282601202D
+:100B1000B423012007B50023024601210DF107008F
+:100B20008DF80730FFF7D0FF20B19DF8070003B024
+:100B30005DF804FB4FF0FF30F9E700000A4608B506
+:100B40000421FFF7C1FF80F00100C0B2404208BDA0
+:100B500030B4054C2368DD69044B0A46AC460146B7
+:100B6000204630BC604700BF28260120A086010037
+:100B700070B501F0E3F9094E094D30800024286872
+:100B80003388834208D901F0D3F92B680444013338
+:100B9000B4F5C03F2B60F2D370BD00BFB623012077
+:100BA0008823012001F08CBA00F1006000F5C0300C
+:100BB0000068704700F10060920000F5C03001F05D
+:100BC0000BBA0000054B1A68054B1B889B1A834221
+:100BD00002D9104401F0ACB90020704788230120ED
+:100BE000B623012038B5084D044629B128682044B1
+:100BF000BDE8384001F0BCB92868204401F0A0F9F4
+:100C00000028F3D038BD00BF8823012010F0030373
+:100C100009D1B0F5846F04D200F10050A0F5712025
+:100C20000368184670470023FBE7000000F10050FE
+:100C3000A0F57120D0F8200470470000064991F813
+:100C4000243033B10023086A81F824300822FFF7EA
+:100C5000B1BF0120704700BF8C230120014B1868F1
+:100C6000704700BF002004E0F0B51E4B1D6801383E
+:100C70002E0C0A181C48C5F30B04032335460788BD
+:100C8000A7420BD144680B46013C934218461BD245
+:100C900014F9010F48B103F8010BF6E7013B00F12D
+:100CA0000800ECD191420ED20B4618462C24B6F522
+:100CB000805F00F8014B0AD1824202D94122981C80
+:100CC0005A70401AF0BD0846B6F5805FF9D041F27F
+:100CD00001039D42F5D18242F3D95A2300F8013B2A
+:100CE000EFE700BF002004E014220120704700005D
+:100CF000704700007047000010B50023934203D0F6
+:100D0000CC5CC4540133F9E710BD000010B50138C4
+:100D100010F9013F3BB191F900409C4203D11AB157
+:100D20000131013AF4E71AB191F90020981A10BD87
+:100D30001046FCE703460246D01A12F9011B0029AF
+:100D4000FAD1704702440346934202D003F8011BD4
+:100D5000FAE770472DE9F8431F4D144695F8242013
+:100D60000746884652BBDFF870909CB395F8243054
+:100D70002BB92022FF2148462F62FFF7E3FF95F8A9
+:100D80002400C0F10802A24228BF2246D6B2414642
+:100D9000920005EB8000FFF7AFFF95F82430A41B0D
+:100DA0001E44F6B2082E17449044E4B285F824603D
+:100DB000DBD1FFF743FF0028D7D108E02B6A03EB14
+:100DC00082038342CFD0FFF739FF0028CBD1002028
+:100DD000BDE8F8830120FBE78C230120024B1A7841
+:100DE000024B1A70704700BFB4230120102201206B
+:100DF00010B50F4C0F4800F0BBF821460D4800F02D
+:100E0000E3F824680C48E26ED2F8043843F0020399
+:100E1000C2F8043800F07EFD0849204600F0E2F9EF
+:100E2000E26ED2F8043823F00203C2F8043810BD91
+:100E3000703700082826012040420F00783700084C
+:100E40007047000030B5094D0A4491420DD011F8A9
+:100E5000013B5840082340F30004013B2C4013F0B1
+:100E6000FF0384EA5000F6D1EFE730BD2083B8EDF0
+:100E700072B6302383F3118862B670470268436804
+:100E80001143016003B118477047000013B5446B6C
+:100E9000D4F894341A681178042915D1217C0229D8
+:100EA00012D11979128901238B4013420CD101A967
+:100EB00004F14C0001F0CCFFD4F89444019B21795B
+:100EC0000246206800F0DAF902B010BD143001F0DB
+:100ED00051BF00004FF0FF33143001F04BBF000052
+:100EE0004C3002F021B800004FF0FF334C3002F0DC
+:100EF0001BB80000143001F021BF00004FF0FF319B
+:100F0000143001F01BBF00004C3001F0EDBF0000B9
+:100F10004FF0FF324C3001F0E7BF00000020704777
+:100F200010B5D0F894341A6811780429044617D102
+:100F3000017C022914D15979528901238B40134233
+:100F40000ED1143001F0B4FE024648B1D4F89444F6
+:100F50004FF4807361792068BDE8104000F07CB9DF
+:100F600010BD0000406BFFF7DBBF000070470000C2
+:100F70007FB5124B036000234360C0E902330125B3
+:100F800002260F4B057404460290019300F184027F
+:100F9000294600964FF48073143001F065FE094B2A
+:100FA0000294CDE9006304F523724FF4807329465F
+:100FB00004F14C0001F028FF04B070BDC4360008F5
+:100FC000650F00088D0E000808B50A68FFF750FF8E
+:100FD0000B7902EB830318624B790D3342F823003F
+:100FE0008B7913B102EB830210620223C0F89414D0
+:100FF0000374002080F3118808BD000038B5037F1A
+:10100000044613B190F85430ABB9201D01250221DC
+:10101000FFF734FF04F1140025776FF0010100F0B1
+:10102000A1FC84F8545004F14C006FF00101BDE8BC
+:10103000384000F097BC38BD10B50121044604309B
+:10104000FFF71CFF0023237784F8543010BD000005
+:1010500038B504460025143001F01EFE04F14C00A2
+:10106000257701F0E9FE201D84F854500121FFF797
+:1010700005FF2046BDE83840FFF752BF90F85C30CE
+:1010800003F06003202B07D190F85D20212A4FF058
+:10109000000303D81F2A06D800207047222AFBD15C
+:1010A000C0E9143303E0034A026507224265836501
+:1010B000012070472C22012037B5D0F894341A68EB
+:1010C0001178042904461AD1017C022917D1197913
+:1010D000128901238B40134211D100F14C0528469F
+:1010E00001F068FF58B101A9284601F0B1FED4F81B
+:1010F0009444019B21790246206800F0BFF803B0B8
+:1011000030BD0000F0B500EB810385B01E6A0446D7
+:101110000D46F6B104EB8507301D0821FFF7A8FE48
+:10112000FFF7ACFEFB685B691B6806F14C001BB166
+:10113000019001F09BFE019803A901F089FE02468F
+:1011400048B1039B2946204600F098F8002383F31A
+:10115000118805B0F0BDFB685A691268002AF5D005
+:101160001B8A013B1340F1D104F15C02EAE7000065
+:101170000D3138B550F82140D4B1FFF779FED4F8DD
+:1011800094241368527903EB8203DB689B695D68E2
+:1011900045B104216018FFF771FE294604F11400DF
+:1011A00001F090FD2046FFF7BBFE002383F311887A
+:1011B00038BD00007047000072B6302383F31188F9
+:1011C00062B6704701F0CAB810B501230446282260
+:1011D00000F8243B0021FFF7B5FD0023C4E90133EB
+:1011E00010BD000038B50025FFF7E6FF0446C0E952
+:1011F0000355C0E90555C0E90755416001F0BEF847
+:101200000223237085F31188284638BD70B500EBA2
+:10121000810305465069DA600E46144618B1102263
+:101220000021FFF78FFDA06918B110220021FFF700
+:1012300089FD31462846BDE8704001F069B90000DB
+:10124000826802F0011282600022C0E90422C0E933
+:101250000622026201F0E8B9F0B400EB810447898C
+:10126000E4680125A4698D403D4345812360002346
+:10127000A2606360F0BC01F003BA0000F0B400EBC0
+:1012800081040789E468012564698D403D43058137
+:1012900023600023A2606360F0BC01F07FBA00000D
+:1012A00070B50223002504460370C0E90255C0E969
+:1012B0000455C0E906554566056280F84C5001F0BA
+:1012C000C3F863681B6823B129462046BDE8704017
+:1012D000184770BD0378052B10B504460AD080F876
+:1012E00068300523037043681B680BB104219847DD
+:1012F0000023A36010BD00000178052906D190F8F5
+:101300006820436802701B6803B1184770470000EB
+:1013100070B590F84C30044613B1002380F84C307F
+:1013200004F15C02204601F0A1F963689B68B3B93F
+:1013300094F85C3013F0600533D00021204601F0B2
+:1013400059FC0021204601F04BFC63681B6813B177
+:10135000062120469847062384F84C3070BD20466D
+:1013600098470028E4D0B4F86230626D9A4288BF92
+:10137000636594F95C30656D002B80F20281002D6D
+:1013800000F0F180092384F84C30FFF715FF0021AD
+:10139000D4E914232046FFF771FF002383F311885B
+:1013A000DCE794F85D2003F07F0343EA022340F278
+:1013B0000232934200F0C48021D8B3F5807F48D038
+:1013C0000DD8012B3FD0022B00F09280002BB4D11E
+:1013D00004F16402226502226265A365C3E7B3F5E6
+:1013E000817F00F09A80B3F5407FA6D194F85E30FB
+:1013F000012BA2D1B4F8643043F0020332E0B3F51C
+:10140000006F4DD017D8B3F5A06F31D0A3F5C063EE
+:10141000012B92D8636894F85E205E6894F85F10A0
+:10142000B4F860302046B047002886D04368236572
+:10143000036863651AE0B3F5106F36D040F60242D8
+:1014400093427FF47AAF5B4B2365022363650023ED
+:10145000C3E794F85E30012B7FF46FAFB4F86430CB
+:1014600023F00203C4E91455A4F86430A5657AE7B3
+:10147000B4F85C30B3F5A06F0ED194F85E3084F808
+:101480006630204601F038F863681B6813B101210B
+:1014900020469847032323700023C4E914339CE7B4
+:1014A00004F1670323650123C3E72378042B0FD1DD
+:1014B0002046FFF781FEFFF7C3FE85F31188032165
+:1014C000636884F8675021701B680BB12046984709
+:1014D00094F85E30002BDFD084F86730042323704B
+:1014E00063681B68002BD7D0022120469847D3E7BA
+:1014F00094F860301D0603F00F0120460AD501F074
+:10150000A7F8012804D002287FF417AF2A4B9BE7E5
+:101510002A4B99E701F08EF8F3E794F85E30002B40
+:101520007FF40BAF94F8603013F00F01B4D01A06BB
+:10153000204602D501F072FBAEE701F065FBABE798
+:1015400094F85E30002B7FF4F8AE94F8603013F01E
+:101550000F01A1D01B06204602D501F04BFB9BE7F3
+:1015600001F03EFB98E7142384F84C30FFF724FE8B
+:101570002A462B4629462046FFF76EFE85F3118842
+:10158000ECE65DB1152384F84C30FFF715FE002121
+:10159000D4E914232046FFF75FFEFEE60B2384F810
+:1015A0004C30FFF709FE2A462B4629462046FFF716
+:1015B00065FEE3E7F4360008EC360008F036000874
+:1015C00038B590F84C300446002B3CD0063BDAB2DC
+:1015D0000F2A32D80F2B30D8DFE803F0352F2F0831
+:1015E00021302F2F2F2F2F2F2F2F3535456DB0F86E
+:1015F00062309D4213D2C3681B8AB5FBF3F203FB32
+:10160000125565B9FFF7D8FD2A462B462946FFF744
+:1016100035FE85F311880A2384F84C300DE014233D
+:1016200084F84C30FFF7C8FD00231A4619462046BF
+:10163000FFF712FE002383F3118838BD836D03B1D9
+:1016400098470023E8E70021204601F0D3FA002163
+:10165000204601F0C5FA63681B6813B106212046D5
+:1016600098470623D8E7000010B590F84C30142BAB
+:10167000044628D017D8062B05D001D81BB110BDC1
+:10168000093B022BFBD80021204601F0B3FA0021D0
+:10169000204601F0A5FA63681B6813B106212046B5
+:1016A0009847062318E0152BE9D10B2380F84C301E
+:1016B000FFF782FD00231A461946FFF7DFFD0023DE
+:1016C00083F31188DBE7C3689B695B68002BD6D185
+:1016D000836D03B19847002384F84C30CFE70000B6
+:1016E00000230375826803691B6899689142FBD2E5
+:1016F0005A680360426010605860704700230375A9
+:10170000826803691B6899689142FBD85A68036034
+:10171000426010605860704708B5084672B63023C2
+:1017200083F3118862B60B7D032B05D0042B0DD0FB
+:101730002BB983F3118808BD8B6900221A604FF022
+:10174000FF338361FFF7CCFF0023F2E7D1E90032DA
+:1017500013605A60F3E70000FFF7C2BF054BD9687A
+:101760000875186802681A60536001220275D86013
+:10177000FEF7D8BDB823012030B50C4BDD684B1CFB
+:1017800087B004460FD02B46094A684600F07EF920
+:101790002046FFF7E3FF009B13B1684600F080F995
+:1017A000A86907B030BDFFF7D9FFF9E7B8230120DA
+:1017B00019170008044B1A68DB6890689B68984208
+:1017C00094BF002001207047B8230120084B10B5BA
+:1017D0001C68D86822681A60536001222275DC6098
+:1017E000FFF78CFF01462046BDE81040FEF79ABD8A
+:1017F000B8230120044B1A68DB6892689B689A4200
+:1018000001D9FFF7E3BF7047B823012038B5074C73
+:1018100007490848012300252370656001F002FC98
+:101820000223237085F3118838BD00BF20260120D4
+:10183000FC360008B823012000F068B9EFF31180EE
+:1018400030B9EFF30583302272B682F3118862B6A5
+:101850007047000010B530B9EFF30584C4F30804F5
+:1018600014B180F3118810BDFFF7C4FF84F3118811
+:10187000F9E70000034A516853685B1A9842FBD8A5
+:10188000704700BF001000E072B6302383F3118868
+:1018900062B670478B60022308618B8208467047EE
+:1018A0008368A3F1840243F8142C026943F8442CA2
+:1018B000426943F8402C094A43F8242CC26843F893
+:1018C000182C022203F80C2C002203F80B2C044ADB
+:1018D00043F8102CA3F12000704700BF3D0300081F
+:1018E000B823012008B5FFF7DBFFBDE80840FFF78C
+:1018F00033BF0000024BDB6898610F20FFF72EBF5B
+:10190000B823012008B5FFF7BFFFBDE80840FFF787
+:10191000F1BF000008B501460820FFF7B5FFFFF74B
+:101920002BFF002383F3118808BD0000064BDB6802
+:1019300039B1426818605A60136043600420FFF7B1
+:101940001BBF4FF0FF307047B82301200368984257
+:1019500006D01A680260506099611846FFF7FCBE15
+:101960007047000038B504460D462068844200D117
+:1019700038BD036823605C608561FFF7EDFEF4E726
+:1019800010B503689C68A2420CD85C688A600B6042
+:101990004C602160596099688A1A9A604FF0FF3351
+:1019A000836010BD1B68121BECE700000A2938BFDA
+:1019B0000A2170B504460D460A26601901F02CFB79
+:1019C00001F018FB041BA54203D8751C2E460446E3
+:1019D000F3E70A2E04D9BDE87040012001F062BB94
+:1019E00070BD0000F8B5144B0D46D96103F110012C
+:1019F00041600A2A1969826038BF0A220160486082
+:101A00001861A818144601F0F9FA0A2701F0F2FA51
+:101A1000431BA342064606D37C1C281901F0FCFA9E
+:101A200027463546F2E70A2F04D9BDE8F8400120E1
+:101A300001F038BBF8BD00BFB8230120F8B5064659
+:101A40000D4601F0D7FA0F4A134653F8107F9F4214
+:101A500006D12A4601463046BDE8F840FFF7C2BF2E
+:101A6000D169BB68441A2C1928BF2C46A34202D95D
+:101A70002946FFF79BFF224631460348BDE8F84060
+:101A8000FFF77EBFB8230120C823012010B4C0E9AE
+:101A9000032300235DF8044B4361FFF7CFBF000031
+:101AA00010B5194C236998420DD0D0E900328168F5
+:101AB00013605A609A680A449A60002303604FF0EA
+:101AC000FF33A36110BD2346026843F8102F536013
+:101AD0000022026022699A4203D1BDE8104001F061
+:101AE00095BA936881680B44936001F083FA226988
+:101AF000E1699268441AA242E4D91144BDE8104059
+:101B0000091AFFF753BF00BFB82301202DE9F047A2
+:101B1000DFF8C08008F110072D4ED8F8105001F002
+:101B200069FAD8F81C40AA68031B9A4240D81444AA
+:101B3000D5E900324FF00009C8F81C4013605A6024
+:101B4000C5F80090D8F81030B34201D101F05EFA28
+:101B500089F31188D5E903312846984772B63023B6
+:101B600083F3118862B66B69002BD6D001F042FA7C
+:101B70006A69A0EB04094A4582460DD2022001F0B1
+:101B800091FA0022D8F81030B34208D151462846C5
+:101B9000BDE8F047FFF726BF121A2244F2E712EB26
+:101BA000090938BF4A4629463846FFF7E9FEB3E738
+:101BB000D8F81030B34208D01444211AC8F81C00D9
+:101BC000A960BDE8F047FFF7F1BEBDE8F08700BFB0
+:101BD000C8230120B823012000207047FEE7000041
+:101BE000704700004FF0FF307047000072B630239E
+:101BF00083F3118862B6704702290CD0032904D000
+:101C00000129074818BF00207047032A05D8054856
+:101C100000EBC2007047044870470020704700BFC7
+:101C2000D43700083C2201208837000870B59AB0EC
+:101C30000546084601A9144600F0BEF801A8FFF7C2
+:101C400079F8431C5B00C5E90034002223700323AC
+:101C50006370C6B201AB02341046D1B28E4204F1B9
+:101C6000020401D81AB070BD13F8011B04F8021C5D
+:101C700004F8010C0132F0E708B50448FFF7B6FF9D
+:101C8000FFF71AFA002383F3118808BD28260120E4
+:101C900090F85C3003F01F02012A07D190F85D2014
+:101CA0000B2A03D10023C0E9143315E003F06003CD
+:101CB000202B08D1B0F860302BB990F85D20212A94
+:101CC00003D81F2A04D8FFF7D9B9222AEBD0FAE7A4
+:101CD000034A02650722426583650120704700BF01
+:101CE0003322012007B5052916D8DFE801F01815C1
+:101CF0000318181E104A0121FFF778FF0190FFF723
+:101D000085FA01980D4A0221FFF780FA0C48FFF787
+:101D10009FF9002383F3118803B05DF804FB0848A2
+:101D2000FFF764FFFFF76AF9F3E70548FFF75EFF87
+:101D3000FFF782F9EDE700BF283700084C370008AD
+:101D40002826012038B50C4D0C4C0D492A4604F1CB
+:101D50000800FFF76BFF05F1CA0204F11000094902
+:101D6000FFF764FF05F5CA7204F118000649BDE8E3
+:101D70003840FFF75BBF00BFF02A01203C22012062
+:101D800008370008123700081D37000870B50446F0
+:101D900008460D46FEF7CEFFC6B220460134037852
+:101DA0000BB9184670BD32462946FEF7AFFF002832
+:101DB000F3D10120F6E700002DE9F84F05460C4667
+:101DC000FEF7B8FF2B49C6B22846FFF7DFFF08B180
+:101DD0000536F6B228492846FFF7D8FF08B1103675
+:101DE000F6B2632E0DD8DFF88C80DFF88C90234F8D
+:101DF000DFF890A0DFF890B02E7846B92670BDE8E5
+:101E0000F88F29462046BDE8F84F01F03DBC252E4D
+:101E10002BD1072241462846FEF778FF58B9DBF858
+:101E200000302360DBF804306360DBF80830A36027
+:101E300007350C34E0E7082249462846FEF766FFDE
+:101E400098B90F4BA21C197809090232C95D02F832
+:101E5000041C13F8011B01F00F015345C95D02F882
+:101E6000031CF0D118340835C6E704F8016B0135BE
+:101E7000C2E700BFF43700081D3700080938000822
+:101E800020F4F01F2CF4F01FFC370008BFF34F8F35
+:101E9000024AD368DB03FCD4704700BF003C024019
+:101EA00008B5074B1B7853B9FFF7F0FF054B1A69CC
+:101EB000002ABFBF044A5A6002F188325A6008BD46
+:101EC0004E2D0120003C02402301674508B5054B1B
+:101ED0001B7833B9FFF7DAFF034A136943F0004375
+:101EE000136108BD4E2D0120003C02400728F0B5CB
+:101EF00016D80C4C0C4923787BB90C4D0E460823A0
+:101F00004FF0006255F8047B46F8042B013B13F0B8
+:101F1000FF033A44F6D10123237051F82000F0BDAD
+:101F20000020FCE7702D0120502D01201C380008F6
+:101F3000014B53F8200070471C38000808207047F8
+:101F4000072810B5044601D9002010BDFFF7CEFFC9
+:101F5000064B53F824301844C21A0BB90120F4E799
+:101F600012680132F0D1043BF6E700BF1C380008CC
+:101F7000072838B5044628D8FFF760FCFFF786FF2E
+:101F8000FFF78EFF124AF323D360E300DBB243F482
+:101F9000007343F002031361136943F48033136148
+:101FA00005462046FFF772FFFFF7A0FF094B53F8E5
+:101FB000241000F0E9F82846FFF788FFFFF74AFCF5
+:101FC0002046BDE83840FFF7BBBF002038BD00BF4A
+:101FD000003C02401C38000812F001032DE9F041DA
+:101FE00005460E4614464BD18218B2F1016F61D8F6
+:101FF000314B1B6813F001035CD0304FFFF71EFC20
+:10200000FFF74EFFF323FB60FFF740FF314640F23E
+:102010000128032C18D824F00104284E0C446D1A12
+:1020200040F20118A142336905EB01072AD123F0E0
+:1020300001033361FFF74AFFFFF70CFC0120BDE805
+:10204000F081043C0435E4E7AB07E4D13B6923F4B9
+:1020500040733B613B6943EA08033B6151F8046B01
+:102060002E60BFF34F8FFFF711FF2B689E42E8D021
+:102070003B6923F001033B61FFF728FFFFF7EAFB11
+:102080000020DCE723F440733361336943EA08033B
+:1020900033610B883B80BFF34F8FFFF7F7FE3F881C
+:1020A00031F8023BBFB2BB42BCD0336923F001031D
+:1020B0003361E1E71846C2E700380240003C0240C5
+:1020C000084908B50B7828B11BB9FFF7E9FE0123D1
+:1020D0000B7008BD002BFCD0BDE808400870FFF76E
+:1020E000F5BE00BF4E2D012010B50244064BD2B202
+:1020F000904200D110BD441C00B253F8200041F8BA
+:10210000040BE0B2F4E700BF502800400F4B30B59D
+:102110001C6F240407D41C6F44F400741C671C6FEC
+:1021200044F400441C670A4C236843F48073236022
+:102130000244084BD2B2904200D130BD441C00B2E0
+:1021400051F8045B43F82050E0B2F4E70038024055
+:10215000007000405028004007B5012201A900206E
+:10216000FFF7C2FF019803B05DF804FB13B5044606
+:10217000FFF7F2FFA04205D0012201A9002001943F
+:10218000FFF7C4FF02B010BD0144BFF34F8F064BF1
+:10219000884204D3BFF34F8FBFF36F8F7047C3F8EC
+:1021A0005C022030F4E700BF00ED00E0034B1A684A
+:1021B0001AB9034AD2F874281A607047742D0120A6
+:1021C0000030024008B5FFF7F1FF024B1868C0F37A
+:1021D000407008BD742D012070B5BFF34F8FBFF361
+:1021E0006F8F1A4A0021C2F85012BFF34F8FBFF30E
+:1021F0006F8F536943F400335361BFF34F8FBFF3C5
+:102200006F8FC2F88410BFF34F8FD2F88030C3F3C2
+:10221000C900C3F34E335B0143F6E07403EA0406DE
+:10222000014646EA81750139C2F86052F9D2203B75
+:1022300013F1200FF2D1BFF34F8F536943F4803372
+:102240005361BFF34F8FBFF36F8F70BD00ED00E0A0
+:10225000FEE7000070B5214B2148224A904237D357
+:10226000214BDA1C121AC11E22F003028B4238BF26
+:1022700000220021FEF766FD1C4A0023C2F88430CC
+:10228000BFF34F8FD2F88030C3F3C900C3F34E338E
+:102290005B0143F6E07403EA0406014646EA8175F1
+:1022A0000139C2F86C52F9D2203B13F1200FF2D160
+:1022B000BFF34F8FBFF36F8FBFF34F8FBFF36F8F9E
+:1022C0000023C2F85032BFF34F8FBFF36F8F70BD42
+:1022D00053F8041B40F8041BC0E700BF0C3A000889
+:1022E000882E0120882E0120882E012000ED00E09C
+:1022F00070B5D0E91B439E6800224FF0FF3504EB18
+:1023000042135101D3F800090028BEBFD3F80009D9
+:1023100040F08040C3F80009D3F8000B0028BEBF8E
+:10232000D3F8000B40F08040C3F8000B0132631873
+:102330009642C3F80859C3F8085BE0D24FF0011386
+:10234000C4F81C3870BD0000890141F02001016112
+:1023500003699B06FCD41220FFF78CBA10B5054C1C
+:102360002046FEF731FF4FF0A043E366024B2367A0
+:1023700010BD00BF782D01206038000870B50378CB
+:10238000012B054650D12A4BC46E98421BD1294BD4
+:102390005A6B42F080025A635A6D42F080025A65CD
+:1023A0005A6D5A6942F080025A615A6922F08002DD
+:1023B0005A610E2143205B6900F03AFC1E4BE3603A
+:1023C0001E4BC4F800380023C4F8003EC02323602D
+:1023D000EE6E4FF40413A3633369002BFCDA012380
+:1023E00033610C20FFF746FA3369DB07FCD4122077
+:1023F000FFF740FA3369002BFCDA0026A660284676
+:10240000FFF776FF6B68C4F81068DB68C4F81468DF
+:10241000C4F81C684BB90A4BA3614FF0FF336361EA
+:10242000A36843F00103A36070BD064BF4E700BF4F
+:10243000782D0120003802404014004003002002A3
+:10244000003C30C0083C30C0F8B5C46E05460021E1
+:102450002046FFF779FF296F00234FF001128F68A4
+:10246000C4F834384FF00066C4F81C284FF0FF3031
+:1024700004EB431201339F42C2F80069C2F8006BBB
+:10248000C2F80809C2F8080BF2D20B68EA6E6B6753
+:10249000636210231361166916F01006FBD1122037
+:1024A000FFF7E8F9D4F8003823F4FE63C4F80038E5
+:1024B000A36943F4402343F01003A3610923C4F844
+:1024C0001038C4F814380A4BEB604FF0C043C4F81E
+:1024D000103B084BC4F8003BC4F81069C4F800393D
+:1024E0006B6F03F1100243F480136A67A362F8BDB7
+:1024F0003C38000840800010C26E90F86610D2F898
+:10250000003823F4FE6343EA0113C2F80038704731
+:102510002DE9F84300EB8103C56EDA68166806F012
+:102520000306731E022B05EB41130C4680460FFA7F
+:1025300081F94FEA41104FF00001C3F8101B4FF032
+:10254000010104F1100398BFB60401FA03F3916985
+:102550008EBF334E06F1805606F5004600293AD06C
+:10256000578A04F15801490137436F50D5F81C18B8
+:102570000B43C5F81C382B180021C3F810195369F8
+:102580000127611EA7409BB3138A928B9B08012AE7
+:1025900088BF5343D8F87420981842EA034301F1E6
+:1025A000400205EB8202C8F87400214653602846B9
+:1025B000FFF7CAFE08EB8900C3681B8A43EA84530D
+:1025C000483464011E432E51D5F81C381F43C5F80A
+:1025D0001C78BDE8F88305EB4917D7F8001B21F4F8
+:1025E0000041C7F8001BD5F81C1821EA0303C0E717
+:1025F00004F13F0305EB83030A4A5A60284621464B
+:10260000FFF7A2FE05EB4910D0F8003923F4004390
+:10261000C0F80039D5F81C3823EA0707D7E700BF10
+:102620000080001000040002026F12684267FFF78A
+:102630005FBE00005831C36E49015B5813F400407F
+:1026400004D013F4001F0CBF0220012070470000CB
+:102650004831C36E49015B5813F4004004D013F4B1
+:10266000001F0CBF022001207047000000EB810119
+:10267000CB68196A0B6813604B68536070470000A1
+:1026800000EB810330B5DD68AA691368D36019B91E
+:10269000402B84BF402313606B8A1468C26E1C44B5
+:1026A000013CB4FBF3F46343033323F0030302EB75
+:1026B000411043EAC44343F0C043C0F8103B2B68C9
+:1026C00003F00303012B09B20ED1D2F8083802EB54
+:1026D000411013F4807FD0F8003B14BF43F08053C7
+:1026E00043F00053C0F8003B02EB4112D2F8003B2C
+:1026F00043F00443C2F8003B30BD00002DE9F04137
+:10270000254DEE6E06EB40130446D3F8087BC3F864
+:10271000087B38070AD5D6F81438190706D505EB13
+:1027200084032146DB6828465B689847FA0721D571
+:10273000D6F81438DB071DD505EB8403D968DCB95E
+:102740008B69488A5A68B2FBF0F600FB16229AB9E8
+:102750001868DA6890420FD2121AC3E9002472B6E0
+:10276000302383F3118862B60B482146FFF788FFB8
+:1027700084F31188BDE8F081012303FA04F26B8928
+:1027800023EA02036B81CB68002BF3D02146024879
+:10279000BDE8F041184700BF782D012000EB810310
+:1027A00070B5DD68C36E6C692668E6604A0156BB89
+:1027B0001A444FF40020C2F810092A6802F00302FC
+:1027C000012A0AB20ED1D3F8080803EB421410F420
+:1027D000807FD4F8000914BF40F0805040F00050D2
+:1027E000C4F8000903EB4212D2F8000940F004409B
+:1027F000C2F80009D3F83408012202FA01F10143BA
+:10280000C3F8341870BD19B9402E84BF4020206031
+:1028100020682E8A8419013CB4FBF6F440EAC440D7
+:1028200040F000501A44C6E72DE9F8433C4DEE6EE7
+:1028300006EB40130446D3F80889C3F8088918F05A
+:10284000010F4FEA40171CD0D6F81038DB0718D517
+:1028500005EB8003D9684B691868DA68904232D278
+:10286000121A4FF000091A60C3F8049072B63023B0
+:1028700083F3118862B621462846FFF78FFF89F35C
+:10288000118818F0800F1CD0D6F834380126A640E5
+:10289000334216D005EB8403ED6ED3F80CC0DCF8A0
+:1028A00014200134E4B2D2F800E005EB04342F44E4
+:1028B0005168714515D3D5F8343823EA0606C5F8B2
+:1028C0003468BDE8F883012303FA04F22B8923EA74
+:1028D00002032B818B68002BD3D0214628469847D2
+:1028E000CFE7BCF81000AEEB0103834228BF0346DC
+:1028F000D7F8180980B2B3EB800FE2D89068A0F146
+:10290000040959F8048FC4F80080A0EB0908984422
+:10291000B8F1040FF5D818440B4490605360C7E732
+:10292000782D01202DE9F74FAC4CE56E6E69AB694F
+:102930001E4016F480586E6107D02046FEF7B0FCAA
+:1029400003B0BDE8F04F00F06BBC002E12DAD5F8F2
+:10295000003EA2489B071EBFD5F8003E23F00303AC
+:10296000C5F8003ED5F8043823F00103C5F8043853
+:10297000FEF7C2FC370505D59848FFF7B9FC974824
+:10298000FEF7A8FCB0040CD5D5F8083813F0060FF4
+:10299000EB6823F470530CBF43F4105343F4A0537B
+:1029A000EB6031071BD56368DB681BB9AB6923F0AB
+:1029B0000803AB612378052B0CD1D5F8003E87487E
+:1029C0009A071EBFD5F8003E23F00303C5F8003E6A
+:1029D000FEF792FC6368DB680BB180489847F3020E
+:1029E00000F18980B70227D5D4F86C90DFF8ECB1FC
+:1029F00000274FF0010A09EB4712D2F8003B03F41D
+:102A00004023B3F5802F11D1D2F8003B002B0DDA13
+:102A100062890AFA07F322EA0303638104EB87035E
+:102A2000DB68DB6813B1394658469847236F013796
+:102A30009B68FFB29F42DED9F00617D5E76E3A6A6F
+:102A4000C2F30A1002F00F0302F4F012B2F5802F65
+:102A500000F09980B2F5402F08D104EB83030022E7
+:102A6000DB681B6A07F5805790427ED13303D5F8A7
+:102A700018481DD5E70302D50020FFF73FFEA50348
+:102A800002D50120FFF73AFE600302D50220FFF7CE
+:102A900035FE210302D50320FFF730FEE20202D506
+:102AA0000420FFF72BFEA30202D50520FFF726FE28
+:102AB00077037FF545AFE60702D50020FFF7B4FEA8
+:102AC000A50702D50120FFF7AFFE600702D502205F
+:102AD000FFF7AAFE210702D50320FFF7A5FEE206B5
+:102AE00002D50420FFF7A0FEA3067FF529AF05203D
+:102AF000FFF79AFE24E7E36EDFF8E0A001930027DA
+:102B00004FF00109236F9B685FFA87FB9B453FF6F7
+:102B100069AF019B03EB4B13D3F8001901F440217B
+:102B2000B1F5802F1FD1D3F8001900291BDAD3F893
+:102B3000001941F09041C3F80019D3F80019002999
+:102B4000FBDB5946E06EFFF7FFFB218909FA0BF327
+:102B500021EA0303238104EB8B03DB689B6813B139
+:102B60005946504698470137CCE7910708BFD7F838
+:102B70000080072A98BF03F8018B02F1010298BF79
+:102B80004FEA182870E7023304EB830207F58057F9
+:102B90005268D2F818C0DCF80820DCE9001CA1EB70
+:102BA0000C0C002188420AD104EB830463689B6902
+:102BB0009A6802449A605A6802445A6056E711F0D3
+:102BC000030F08BFD7F800808C4588BF02F8018B3F
+:102BD00001F1010188BF4FEA1828E3E7782D0120B1
+:102BE000C36E03EB4111D1F8003B43F40013C1F86D
+:102BF000003B7047C36E03EB4111D1F8003943F439
+:102C00000013C1F800397047C36E03EB4111D1F8CE
+:102C1000003B23F40013C1F8003B7047C36E03EB85
+:102C20004111D1F8003923F40013C1F8003970477D
+:102C300000F1604303F561430901C9B283F8001351
+:102C4000012200F01F039A4043099B0003F16043F7
+:102C500003F56143C3F880211A60704772B63023D0
+:102C600083F3118862B6704730B5039C0172043358
+:102C700004FB0325C0E90653049B03630021059B65
+:102C8000C160C0E90000C0E90422C0E90842C0E90F
+:102C90000A11436330BD0000416A0022C0E90411FB
+:102CA000C0E90A22C2606FF00101FEF75BBE0000BE
+:102CB000D0E90432934201D1C2680AB9181D7047A5
+:102CC0000020704703691960C2680132C260C2699E
+:102CD000134482690361934224BF436A0361002164
+:102CE000FEF734BE38B504460D46E3683BB1626971
+:102CF000131D1268A3621344E362002007E0237AE5
+:102D000033B929462046FEF711FE0028EDDA38BD1A
+:102D10006FF00100FBE70000C368C269013BC360BC
+:102D20004369134482694361934224BF436A436108
+:102D300000238362036B03B11847704770B5FFF738
+:102D40008DFF866A04463EB9FFF7CCFF054618B1F1
+:102D500086F31188284670BDA36AE26A13F8015B06
+:102D6000A362934202D32046FFF7D6FF002383F3EA
+:102D70001188EFE72DE9F0479846FFF76FFF002530
+:102D800004460E461746A946D4F828A0BAF1000F0B
+:102D900009D141462046FFF7A5FF20B18AF31188EB
+:102DA0002846BDE8F087D4E90A12A7EB050A521AB3
+:102DB000924528BF9246BAF1400F1BD9334601F124
+:102DC000400251F8040B43F8040B9142F9D1A36A75
+:102DD00040334036A3624035D4E90A239A4202D3F5
+:102DE0002046FFF799FF89F31188BD42D8D2FFF73B
+:102DF00035FFC9E730465246FDF77EFFA36A5344CC
+:102E00005644A3625544E7E710B5029C01720433AF
+:102E100003FB0421C0E906130023C0E90A33039B26
+:102E20000363049BC460C0E90000C0E90422C0E958
+:102E30000842436310BD0000026AC260426AC0E9F2
+:102E400004220022C0E90A226FF00101FEF78ABDC8
+:102E5000D0E904239A4201D1C26822B9184650F839
+:102E6000043B0B60704700231846FAE7C368C26949
+:102E70000133C3604369134482694361934224BFB1
+:102E8000436A43610021FEF761BD000038B5044686
+:102E90000D46E3683BB123691A1DA262E26913443F
+:102EA000E362002007E0237A33B929462046FEF783
+:102EB0003DFD0028EDDA38BD6FF00100FBE70000B2
+:102EC00003691960C268013AC260C2691344826929
+:102ED0000361934224BF436A036100238362036B4F
+:102EE00003B118477047000070B5FFF7B7FE866A58
+:102EF0000D46044611462EB9FFF7C8FF10B186F300
+:102F0000118870BDA36A1D70A36AE26A01339342FF
+:102F1000A36204D3E16920460439FFF7D1FF002002
+:102F200080F31188EDE700002DE9F0479946FFF79F
+:102F300095FE002604460D469046B246A76A4FB954
+:102F400049462046FFF7A2FF20B187F3118830469B
+:102F5000BDE8F087D4E90A073A1AA8EB06079742BA
+:102F600028BF1746402F1BD905F1400355F8042B05
+:102F700040F8042B9D42F9D1A36A4033A362403646
+:102F8000D4E90A239A4204D3E16920460439FFF7C1
+:102F900097FF8AF311884645D9D2FFF75FFECDE748
+:102FA00029463A46FDF7A8FEA36A3B443D44A36286
+:102FB0003E44E5E7D0E904239A4217D1C3689BB1A8
+:102FC000836A8BB1043B9B1A0ED01360C368013B2C
+:102FD000C360C3691A44836902619A4224BF436A89
+:102FE0000361002383620123184670470023FBE737
+:102FF00000F042B94FF08043586A70474FF0804369
+:10300000002258631A610222DA6070474FF0804351
+:103010000022DA60704700004FF080435863704729
+:10302000FEE7000070B51B4B01630025044686B027
+:10303000586085620E4600F0CBF804F11003C4E935
+:1030400004334FF0FF33C4E90635C4E90044A560FA
+:10305000E562FFF7CFFF2B460246C4E9082304F1DF
+:1030600034010D4A256580232046FEF713FC012319
+:10307000E0600A4A0375009272680192B268CDE975
+:103080000223074B6846CDE90435FEF72BFC06B05A
+:1030900070BD00BF202601206C3800087138000880
+:1030A00021300008024AD36A1843D062704700BF3B
+:1030B000B82301204B6843608B688360CB68C36092
+:1030C0000B6943614B6903628B6943620B68036060
+:1030D0007047000008B52C4B2C481A6940F2FF716C
+:1030E0000A431A611A6922F4FF6222F007021A6188
+:1030F0001A691A6B0A431A631A6D0A431A65244A3D
+:103100001B6D1146FFF7D6FF02F11C0100F5806030
+:10311000FFF7D0FF02F1380100F58060FFF7CAFF2A
+:1031200002F1540100F58060FFF7C4FF02F1700165
+:1031300000F58060FFF7BEFF02F18C0100F58060B2
+:10314000FFF7B8FF02F1A80100F58060FFF7B2FFBA
+:1031500002F1C40100F58060FFF7ACFF02F1E0016D
+:1031600000F58060FFF7A6FF02F1FC0100F580602A
+:10317000FFF7A0FF02F58C7100F58060FFF79AFF62
+:10318000BDE8084000F0EEB8003802400000024000
+:103190007838000808B500F059FAFEF737FBFFF75A
+:1031A00005F8BDE80840FEF7CDBD000070470000FF
+:1031B000EFF3098305494A6B22F001024A63683341
+:1031C00083F30988002383F31188704700EF00E040
+:1031D000302080F3118862B60D4B0E4AD96821F475
+:1031E000E0610904090C0A43DA60D3F8FC200A49BB
+:1031F00042F08072C3F8FC20084AC2F8B01F116880
+:1032000041F0010111602022DA7783F82200704733
+:1032100000ED00E00003FA0555CEACC5001000E05B
+:1032200010B572B6302383F3118862B60E4B5B681B
+:1032300013F4006314D0F1EE103AEFF30984683C04
+:103240004FF08073E361094BDB6B236684F30988DD
+:10325000FEF7B0FA10B1064BA36110BD054BFBE7BA
+:1032600083F31188F9E700BF00ED00E000EF00E014
+:103270004F030008520300080F4B1A6C42F0010282
+:103280001A641A6E42F001021A660C4A1B6E9368A9
+:1032900043F0010393604FF080436B229A624FF03A
+:1032A000FF32DA6200229A615A63DA605A600122C0
+:1032B0005A611A60704700BF00380240002004E0E5
+:1032C0004FF0804208B51169D3680B40D9B2C943A9
+:1032D0009B07116109D572B6302383F3118862B65A
+:1032E000FEF7AAFA002383F3118808BD1B4B1A6965
+:1032F0006FEA42526FEA52521A611A69C2F30A0225
+:103300001A614FF0FF301A695A69586100215A69F1
+:1033100059615A691A6A62F080521A621A6A02F096
+:1033200080521A621A6A5A6A58625A6A59625A6A0A
+:103330000B4A106840F480701060186F00F4407001
+:10334000B0F5007F1EBF4FF48030186719675368CF
+:1033500023F40073536000F055B900BF00380240F9
+:1033600000700040374B4FF080521A64364A4FF4D9
+:10337000404111601A6842F001021A601A6892070F
+:10338000FCD59A6822F003029A602E4B9A6812F0DC
+:103390000C02FBD1196801F0F90119609A601A68F2
+:1033A00042F480321A601A689003FCD55A6F42F0DA
+:1033B00001025A67234B5A6F9107FCD5234A5A6082
+:1033C0001A6842F080721A601F4B5A685204FCD58A
+:1033D0001A6842F480321A605A68D003FCD51A6821
+:1033E00042F400321A60184A53689903FCD5154B11
+:1033F0001A689201FCD5164A9A6040F20112C3F88D
+:103400008C200022C3F89020124A40F20733136048
+:10341000136803F00F03072BFAD10A4B9A6842F0A6
+:1034200002029A609A6802F00C02082AFAD15A6CD9
+:1034300042F480425A645A6E42F480425A665B6E8D
+:10344000704700BF0038024000700040086C40091F
+:1034500000948838003C0240074A08B5536903F0DD
+:103460000103536123B1054A13680BB150689847B3
+:10347000BDE80840FFF7D4BE003C0140082E012003
+:10348000074A08B5536903F00203536123B1054AA3
+:1034900093680BB1D0689847BDE80840FFF7C0BEFD
+:1034A000003C0140082E0120074A08B5536903F08B
+:1034B0000403536123B1054A13690BB1506998475E
+:1034C000BDE80840FFF7ACBE003C0140082E0120DB
+:1034D000074A08B5536903F00803536123B1054A4D
+:1034E00093690BB1D0699847BDE80840FFF798BED3
+:1034F000003C0140082E0120074A08B5536903F03B
+:103500001003536123B1054A136A0BB1506A9847FF
+:10351000BDE80840FFF784BE003C0140082E0120B2
+:10352000164B10B55C6904F478725A61A30604D591
+:10353000134A936A0BB1D06A9847600604D5104AC3
+:10354000136B0BB1506B9847210604D50C4A936B53
+:103550000BB1D06B9847E20504D5094A136C0BB147
+:10356000506C9847A30504D5054A936C0BB1D06CF9
+:103570009847BDE81040FFF753BE00BF003C014034
+:10358000082E0120194B10B55C6904F47C425A6185
+:10359000620504D5164A136D0BB1506D984723058B
+:1035A00004D5134A936D0BB1D06D9847E00404D550
+:1035B0000F4A136E0BB1506E9847A10404D50C4A04
+:1035C000936E0BB1D06E9847620404D5084A136F0E
+:1035D0000BB1506F9847230404D5054A936F0BB184
+:1035E000D06F9847BDE81040FFF71ABE003C01407D
+:1035F000082E012008B5FFF763FEBDE80840FFF77D
+:103600000FBE0000062108B50846FFF711FB062192
+:103610000720FFF70DFB06210820FFF709FB062115
+:103620000920FFF705FB06210A20FFF701FB062111
+:103630001720FFF7FDFA06212820FFF7F9FABDE869
+:10364000084007211C20FFF7F3BA000008B5FFF778
+:103650004DFE00F00BF8FDF7B5FDFDF787FCFFF719
+:10366000A5FDBDE80840FFF7C3BC00000023054AE4
+:1036700019460133102BC2E9001102F10802F8D1FA
+:10368000704700BF082E0120034611F8012B03F8F4
+:10369000012B002AF9D1704753544D3332463F3F36
+:1036A0003F3F3F3F0053544D333246375B347C3508
+:1036B0005D780053544D333246375B367C375D7846
+:1036C0000000000000000000E90E0008D50E000810
+:1036D000110F0008FD0E0008090F0008F50E000884
+:1036E000E10E0008CD0E00081D0F000800000000CC
+:1036F000010000000000000063300000F836000800
+:1037000010240120202601204172647550696C6FDD
+:10371000740025424F415244252D424C002553450B
+:103720005249414C2500000002000000000000004A
+:10373000051100087111000840004000C02A012056
+:10374000D02A012002000000000000000300000059
+:1037500000000000B511000800000000100000008B
+:10376000E02A01200000000001000000000000002D
+:10377000782D012001010200E51C0008F91B00085A
+:10378000911C0008791C00084300000090370008D5
+:1037900009024300020100C03209040000010202D4
+:1037A0000100052400100105240100010424020287
+:1037B0000524060001070582030800FF0904010033
+:1037C000020A00000007050102400000070581020F
+:1037D0004000000012000000DC3700081201100158
+:1037E00002000040091241570002010203010000DB
+:1037F0000403090425424F4152442500426C697478
+:103800007A4637343541494F00303132333435361A
+:1038100037383941424344454600000000800000EB
+:103820000080000000800000008000000000020016
+:10383000000004000000040000000400000000007C
+:1038400011130008C1150008691600084000400067
+:10385000F02D0120F02D012001000000002E01209C
+:103860008000000040010000050000006D61696EED
+:103870000069646C650000005555956A0000000001
+:10388000AAAAAAAAAAA92A6410F8000000000000A7
+:1038900000A00A005555555500000000AAAAAAAA82
+:1038A000AAAAAAAA00000000000000000000000070
+:1038B0005555555500000000AAAAAAAAAAAAAAAA64
+:1038C00000000000000000000000000055555555A4
+:1038D00000000000AAAAAAAAAAAAAA2A0000000018
+:1038E0000000000000000000555555550000000084
+:1038F000AAAAAAAAAAA9AAAA100000000000000069
+:10390000000000005555555500000000AAAAAAAABB
+:10391000AAAAAAAA000000000000000000000000FF
+:103920005555555500000000AAAAAAAAAAAAAAAAF3
+:103930000000000000000000000000000500000082
+:10394000000000000A0000000A0000000000000063
+:103950000000000000000000000000000000000067
+:103960000000000000000000000000000000000057
+:103970000000000000000000000000000000000047
+:103980000000000000000000000000000000000037
+:103990000000000000000000000000000000000027
+:1039A0000000000000000000000000000000000017
+:1039B0005D0400000000000000800E000000000018
+:1039C000FF000000000000009836000849040000D5
+:1039D000A536000851040000B33600080096000028
+:1039E000000008009600000000080000040000002D
+:1039F000F037000800000000000000000000000098
+:0C3A0000000000000000000000000000BA
+:00000001FF
diff --git a/Tools/bootloaders/C-RTK2_HP_bl.bin b/Tools/bootloaders/C-RTK2_HP_bl.bin
new file mode 100755
index 00000000000000..5b55d1ed6ca7fc
Binary files /dev/null and b/Tools/bootloaders/C-RTK2_HP_bl.bin differ
diff --git a/Tools/bootloaders/CarbonixF405_bl.bin b/Tools/bootloaders/CarbonixF405_bl.bin
new file mode 100755
index 00000000000000..ece35d93d1fa21
Binary files /dev/null and b/Tools/bootloaders/CarbonixF405_bl.bin differ
diff --git a/Tools/bootloaders/CarbonixL496_bl.bin b/Tools/bootloaders/CarbonixL496_bl.bin
new file mode 100755
index 00000000000000..1641ea80d491d1
Binary files /dev/null and b/Tools/bootloaders/CarbonixL496_bl.bin differ
diff --git a/Tools/bootloaders/CubePilot-CANMod_bl.bin b/Tools/bootloaders/CubePilot-CANMod_bl.bin
new file mode 100755
index 00000000000000..7207f0293c9a74
Binary files /dev/null and b/Tools/bootloaders/CubePilot-CANMod_bl.bin differ
diff --git a/Tools/bootloaders/CubePilot-CANMod_bl.hex b/Tools/bootloaders/CubePilot-CANMod_bl.hex
new file mode 100644
index 00000000000000..50dbce36b192a9
--- /dev/null
+++ b/Tools/bootloaders/CubePilot-CANMod_bl.hex
@@ -0,0 +1,1972 @@
+:020000040800F2
+:1000000000060020F505000815320008CD31000873
+:10001000F5310008CD310008ED310008F705000882
+:10002000F7050008F7050008F7050008D5410008A6
+:10003000F7050008F7050008F7050008F7050008B0
+:10004000F7050008F7050008F7050008F7050008A0
+:10005000F7050008F7050008517200087D720008D6
+:10006000A9720008D572000801730008F70500089E
+:10007000F7050008F7050008F7050008F705000870
+:10008000F7050008F7050008F70500087D310008AE
+:10009000A531000891310008B93100082D7300081E
+:1000A000F7050008F7050008F7050008F705000840
+:1000B000F7050008F7050008F7050008F705000830
+:1000C000F7050008F7050008F7050008F705000820
+:1000D000F7050008F7050008F7050008F705000810
+:1000E00091730008F7050008F7050008F7050008F8
+:1000F000F7050008F7050008F7050008F7050008F0
+:10010000F7050008F705000819740008F70500084E
+:10011000F7050008F7050008F7050008F7050008CF
+:10012000F7050008F7050008F7050008F7050008BF
+:10013000F7050008F7050008F7050008F7050008AF
+:10014000F7050008F7050008F7050008F70500089F
+:10015000F7050008F7050008F7050008F70500088F
+:10016000F7050008F7050008F7050008F70500087F
+:10017000F705000899680008F7050008F70500086A
+:10018000F7050008F705000805740008F7050008E2
+:10019000F7050008F7050008F7050008F70500084F
+:1001A000F7050008F7050008F7050008F70500083F
+:1001B000F7050008F7050008F7050008F70500082F
+:1001C000F7050008F7050008F7050008F70500081F
+:1001D000F705000885680008F7050008F70500081E
+:1001E000F7050008F7050008F7050008F7050008FF
+:1001F000F7050008F7050008F7050008F7050008EF
+:10020000F7050008F7050008F7050008F7050008DE
+:10021000F7050008F7050008F7050008F7050008CE
+:10022000F7050008F7050008F7050008F7050008BE
+:10023000F7050008F7050008F7050008F7050008AE
+:10024000F7050008F7050008F7050008F70500089E
+:10025000F7050008F7050008F7050008F70500088E
+:10026000F7050008F7050008F7050008F70500087E
+:10027000F7050008F7050008F7050008F70500086E
+:10028000F7050008F7050008F7050008F70500085E
+:10029000F7050008F7050008F7050008F70500084E
+:1002A000F7050008F7050008F7050008F70500083E
+:1002B000F7050008F7050008F7050008F70500082E
+:1002C000F7050008F7050008F7050008F70500081E
+:1002D000F7050008F7050008F7050008F70500080E
+:1002E0007918000800000000000000000000000075
+:1002F00053B94AB9002908BF00281CBF4FF0FF318D
+:100300004FF0FF3000F074B9ADF1080C6DE904CE88
+:1003100000F006F8DDF804E0DDE9022304B07047E0
+:100320002DE9F047089D04468E46002B4DD18A42A8
+:10033000944669D9B2FA82F252B101FA02F3C2F1DB
+:10034000200120FA01F10CFA02FC41EA030E94406C
+:100350004FEA1C48210CBEFBF8F61FFA8CF708FB8D
+:1003600016E341EA034306FB07F199420AD91CEB65
+:10037000030306F1FF3080F01F81994240F21C8197
+:10038000023E63445B1AA4B2B3FBF8F008FB1033DF
+:1003900044EA034400FB07F7A7420AD91CEB040414
+:1003A00000F1FF3380F00A81A74240F207816444E4
+:1003B000023840EA0640E41B00261DB1D440002369
+:1003C000C5E900433146BDE8F0878B4209D9002DCD
+:1003D00000F0EF800026C5E9000130463146BDE857
+:1003E000F087B3FA83F6002E4AD18B4202D38242C1
+:1003F00000F2F980841A61EB030301209E46002D70
+:10040000E0D0C5E9004EDDE702B9FFDEB2FA82F2C4
+:10041000002A40F09280A1EB0C014FEA1C471FFA22
+:100420008CFE0126200CB1FBF7F307FB131140EA09
+:1004300001410EFB03F0884208D91CEB010103F1D6
+:10044000FF3802D2884200F2CB804346091AA4B298
+:10045000B1FBF7F007FB101144EA01440EFB00FE6C
+:10046000A64508D91CEB040400F1FF3102D2A645D1
+:1004700000F2BB800846A4EB0E0440EA03409CE770
+:10048000C6F12007B34022FA07FC4CEA030C20FA1D
+:1004900007F401FA06F31C43F9404FEA1C4900FA3D
+:1004A00006F3B1FBF9F8200C1FFA8CFE09FB1811BA
+:1004B00040EA014108FB0EF0884202FA06F20BD92D
+:1004C0001CEB010108F1FF3A80F08880884240F27D
+:1004D0008580A8F102086144091AA4B2B1FBF9F0C1
+:1004E00009FB101144EA014100FB0EFE8E4508D9BC
+:1004F0001CEB010100F1FF346CD28E456AD9023841
+:10050000614440EA0840A0FB0294A1EB0E01A14225
+:10051000C846A64656D353D05DB1B3EB080261EB93
+:100520000E0101FA07F722FA06F3F1401F43C5E96D
+:10053000007100263146BDE8F087C2F12003D840A3
+:100540000CFA02FC21FA03F3914001434FEA1C47E5
+:100550001FFA8CFEB3FBF7F007FB10360B0C43EAD7
+:10056000064300FB0EF69E4204FA02F408D91CEB87
+:10057000030300F1FF382FD29E422DD90238634485
+:100580009B1B89B2B3FBF7F607FB163341EA034125
+:1005900006FB0EF38B4208D91CEB010106F1FF3874
+:1005A00016D28B4214D9023E6144C91A46EA00466B
+:1005B00038E72E46284605E70646E3E61846F8E6FD
+:1005C0004B45A9D2B9EB020864EB0C0E0138A3E746
+:1005D0004646EAE7204694E74046D1E7D0467BE727
+:1005E000023B614432E7304609E76444023842E79F
+:1005F000704700BF02E000F000F8FEE772B637482F
+:1006000080F30888364880F3098836483649086000
+:1006100040F20000CCF200004EF63471CEF2000140
+:100620000860BFF34F8FBFF36F8F40F20000C0F23E
+:10063000F0004EF68851CEF200010860BFF34F8FF4
+:10064000BFF36F8F4FF00000E1EE100A4EF63C71E1
+:10065000CEF200010860062080F31488BFF36F8F8C
+:1006600005F090FB06F094FB4FF055301F491B4AF4
+:1006700091423CBF41F8040BFAE71D49184A9142E8
+:100680003CBF41F8040BFAE71A491B4A1B4B9A423C
+:100690003EBF51F8040B42F8040BF8E7002018495C
+:1006A000184A91423CBF41F8040BFAE705F0A8FB59
+:1006B00006F0F0FB144C154DAC4203DA54F8041B61
+:1006C0008847F9E700F042F8114C124DAC4203DACA
+:1006D00054F8041B8847F9E705F090BB000600209A
+:1006E000002200200000000808ED00E000000020CB
+:1006F00000060020507A000800220020D0220020AE
+:10070000D0220020E8820020E0020008E402000875
+:10071000E4020008E40200082DE9F04F2DED108AF4
+:10072000C1F80CD0D0F80CD0BDEC108ABDE8F08F29
+:10073000002383F311882846A047002004F0ECFD35
+:10074000FEE704F045FD00DFFEE70000F8B505F028
+:100750009DFA074605F00CFB0546B8BB204B9F42AF
+:1007600034D001339F4234D027F0FF021D4B9A4210
+:1007700032D12E4642F21074F8B200F0ADFE00F015
+:10078000B1FE08B10024264601F09EFB20B10024F2
+:10079000032000F07BF8264635B1134B9F4203D06F
+:1007A000002405F0DDFA2646002005F079FA0EB1A6
+:1007B00000F082F801F016FA00F0B8FE01F0DCF863
+:1007C000204600F01DF900F077F8F9E72E460024E6
+:1007D000D5E704460126D2E7064641F28834CEE743
+:1007E000010007B0000008B0263A09B008B501F0D2
+:1007F0008FF8A0F120035842584108BD07B541F2D7
+:100800001203022101A8ADF8043001F09FF803B0F3
+:100810005DF804FB38B5302383F31188174803686B
+:100820000BB104F045FE0023154A4FF47A711348CA
+:1008300004F034FE002383F31188124C236813B1B3
+:100840002368013B2360636813B16368013B636005
+:100850000D4D2B7833B963687BB9022001F044F960
+:10086000322363602B78032B07D163682BB90220F6
+:1008700001F03AF94FF47A73636038BDD02200205A
+:1008800015080008F0230020E8220020084B18700B
+:1008900003280CD8DFE800F008050208022001F068
+:1008A00021B9022001F01CB9024B00225A607047A6
+:1008B000E8220020F0230020F8B501F005FB30B15C
+:1008C000464B03221A700022454B5A60F8BD454B37
+:1008D000454A1C4619680131F8D004339342F9D1D6
+:1008E0006268424B9A42F1D9414B9B6803F1006325
+:1008F00003F580239A42E9D205F006FA05F018FACA
+:10090000002001F05FF80220FFF7C0FF394B002103
+:100910009A6C99641A6F19671A6FDA6CD9645A6FF6
+:1009200059675A6F1A6D19659A6F99679B6F324BA9
+:10093000D3F8802042F00072C3F88020D3F88020E2
+:1009400022F00072C3F88020D3F8803072B64FF0E6
+:10095000E023C3F8084DD4E90004BFF34F8FBFF381
+:100960006F8F264AC2F88410BFF34F8F536923F468
+:1009700080335361BFF34F8FD2F8803043F6E07677
+:10098000C3F3C905C3F34E335B0103EA060C2946E2
+:100990004CEA81770139C2F87472F9D2203B13F125
+:1009A000200FF2D1BFF34F8FBFF36F8FBFF34F8F85
+:1009B000BFF36F8F536923F4003353610023C2F8F0
+:1009C0005032BFF34F8FBFF36F8F302383F3118803
+:1009D000854680F30888204778E700BFE82200209A
+:1009E000F02300200000040820000408FFFF030893
+:1009F00000220020004502580044025800ED00E0AB
+:100A00002DE9F04F93B0B74B2022FF2100900AA8A8
+:100A10009D6801F091F8B44A1378A3B90121B34855
+:100A200011700360302383F3118803680BB104F065
+:100A30003FFD0023AE4A4FF47A71AC4804F02EFD1E
+:100A4000002383F31188009B13B1AA4B009A1A600C
+:100A5000A94A1378032B03D000231370A54A5360CF
+:100A60004FF0000A009CD3465646D146012001F0C3
+:100A700039F824B19F4B1B68002B00F02C8200201A
+:100A800000F046FF0390039B002B01DA00F0A2FD6B
+:100A9000039B002BEDDB012001F022F8039B213B9F
+:100AA0001F2BE3D801A252F823F000BF2D0B000842
+:100AB000550B0008E90B00086D0A00086D0A0008D4
+:100AC0006D0A00087B0C00084B0E0008650D00083D
+:100AD000C70D0008EF0D0008150E00086D0A00088C
+:100AE000270E00086D0A0008990E0008CD0B0008BB
+:100AF0006D0A0008DD0E0008390B0008CD0B000858
+:100B00006D0A0008C70D00086D0A00086D0A00088C
+:100B10006D0A00086D0A00086D0A00086D0A0008D9
+:100B20006D0A00086D0A0008E90B00080220FFF7B3
+:100B30005DFE002840F0F981009B022105A8BAF172
+:100B4000000F08BF1C4641F21233ADF8143000F01C
+:100B5000FDFE8BE74FF47A7000F0DAFE071EEBDB48
+:100B60000220FFF743FE0028E6D0013F052F00F2E8
+:100B7000DE81DFE807F0030A0D1013360523042198
+:100B800005A8059300F0E2FE17E004215548F9E7B7
+:100B900004215A48F6E704215948F3E74FF01C08AE
+:100BA000404608F1040800F00FFF0421059005A855
+:100BB00000F0CCFEB8F12C0FF2D101204FF000096B
+:100BC00000FA07F747EA0B0B5FFA8BFB01F000F81E
+:100BD00026B10BF00B030B2B08BF0024FFF70EFE12
+:100BE00044E704214748CDE7002EA5D00BF00B03C6
+:100BF0000B2BA1D10220FFF7F9FD074600289BD05F
+:100C00000120002600F0DEFE0220FFF73FFE5FFA23
+:100C100086F8404600F0E6FE0446B0B1039940462F
+:100C20000136A1F140025142514100F0EBFE002893
+:100C3000EDD1BA46044641F21213022105A83E4600
+:100C4000ADF8143000F082FE10E725460120FFF7D2
+:100C50001DFE244B9B68AB4207D9284600F0B4FE2A
+:100C6000013040F067810435F3E70025224BBA4696
+:100C70003E461D701F4B5D60A8E7002E3FF45CAF41
+:100C80000BF00B030B2B7FF457AF0220FFF7FEFD99
+:100C9000322000F03DFEB0F10008FFF64DAF18F035
+:100CA00003077FF449AF0F4A08EB050392689342AC
+:100CB0003FF642AFB8F5807F3FF73EAF124BB845E5
+:100CC000019323DD4FF47A7000F022FE0390039A23
+:100CD000002AFFF631AF039A0137019B03F8012B7D
+:100CE000EDE700BF00220020EC230020D0220020EE
+:100CF00015080008F0230020E8220020042200202C
+:100D0000082200200C220020EC220020C820FFF73F
+:100D10006DFD074600283FF40FAF1F2D11D8C5F118
+:100D200020020AAB25F0030084494245184428BF3D
+:100D30004246019200F0DAFE019AFF217F4800F05E
+:100D4000FBFE4FEAA803C8F387027C4928460193BB
+:100D500000F0FAFE064600283FF46DAF019B05EB5C
+:100D6000830533E70220FFF741FD00283FF4E4AE9E
+:100D700000F066FE00283FF4DFAE0027B846704B57
+:100D80009B68BB4218D91F2F11D80A9B01330ED084
+:100D900027F0030312AA134453F8203C059340465E
+:100DA000042205A9043701F079F88046E7E73846C0
+:100DB00000F00AFE0590F2E7CDF81480042105A8A2
+:100DC00000F0C4FD02E70023642104A8049300F0AE
+:100DD000B3FD00287FF4B0AE0220FFF707FD002826
+:100DE0003FF4AAAE049800F021FE0590E6E7002348
+:100DF000642104A8049300F09FFD00287FF49CAEBA
+:100E00000220FFF7F3FC00283FF496AE049800F0B0
+:100E10000FFEEAE70220FFF7E9FC00283FF48CAE62
+:100E200000F01EFEE1E70220FFF7E0FC00283FF49F
+:100E300083AE05A9142000F019FE07460421049092
+:100E400004A800F083FD3946B9E7322000F060FDC8
+:100E5000071EFFF671AEBB077FF46EAE384A07EB94
+:100E60000903926893423FF667AE0220FFF7BEFC8B
+:100E700000283FF461AE27F003074F44B9453FF423
+:100E8000A5AE484609F1040900F09EFD0421059035
+:100E900005A800F05BFDF1E74FF47A70FFF7A6FCC0
+:100EA00000283FF449AE00F0CBFD002844D00A9B57
+:100EB00001330BD008220AA9002000F045FE0028CB
+:100EC0003AD02022FF210AA800F036FEFFF796FC58
+:100ED0001C4804F027FA13B0BDE8F08F002E3FF451
+:100EE0002BAE0BF00B030B2B7FF426AE00236421FB
+:100EF00005A8059300F020FD074600287FF41CAEEE
+:100F00000220FFF773FC804600283FF415AEFFF780
+:100F100075FC41F2883004F005FA059800F0A4FE53
+:100F200046463C4600F054FEA0E506464EE64FF02D
+:100F3000000901E6BA467EE637467CE6EC22002050
+:100F400000220020A0860100094A49F269001368C6
+:100F500099B21B0C00FB013344F250611360054B46
+:100F6000186882B2000C01FB0200186080B2704762
+:100F700014220020102200200021102210B5044667
+:100F800000F0DAFD034B03CB206061601868A060BD
+:100F900010BD00BF00E8F11F2DE9F041ADF5527D15
+:100FA0000D46002140F2751270AC074612A811914F
+:100FB00000F0C2FD4FF4C4720021204600F0BCFDD9
+:100FC0000DF1440802F02EF94FF47A72244BB0FB75
+:100FD000F2F0186093E80700012384E807000DF59C
+:100FE000F1702382FFF7C8FF43F204731D4907A87D
+:100FF000238406F001FB24230DF2F3220DF13C0CB7
+:1010000084F8323107AB1E46083203CE664542F8FB
+:10101000080C42F8041C3346F5D130684146106094
+:101020000122204600F042FE002380B2E97E0393B5
+:10103000AB7E029305F1190301930123009306A3EC
+:10104000D3E90023CDE90480384602F0A3FC0DF576
+:10105000527DBDE8F08100BF9E6AC421818A46EEC0
+:10106000F8230020287600082DE9F043224DBBB07C
+:1010700002F0D8F840F2ED22AB68C31A934232D99D
+:1010800006AF2B4628220021A860384602F032FE27
+:1010900005F10E0000F048FD002604465FFA80F9D5
+:1010A00005F10E08F3B2F100994501F1280107D9C5
+:1010B00008EB060308223846013602F01BFEF1E772
+:1010C000082301220534297B0C48A4B2CDE9023261
+:1010D0000B4B01933023CDE90474009304A3D3E9AF
+:1010E000002302F057FC3BB0BDE8F083AFF3008073
+:1010F00078F6339F93CACD8DA05D00201034002078
+:10110000AD5D0020F0B58B8AC9B006460C46013BA8
+:101110009BB2C92B47D8274D2F7B27BB05F10C036A
+:101120000822394600933B46204602F0A7FC7B1C70
+:10113000FAB2D9001F46A38A013B9A4205DA0E3261
+:1011400000232A4400920822EEE700230022C5E98A
+:1011500000230023AB6085F8D730C5F8D8302B7B4F
+:101160000BB9E37E2B7306AD8122002127A800F086
+:10117000E3FC0122294627A800F064FE002380B288
+:10118000E17E0393A37E029304F1190301932823C4
+:10119000CDE904500093304604A3D3E9002302F0C4
+:1011A000F9FBFFF761FF49B0F0BD00BF2641727245
+:1011B000DF25D7B7A05D002070B50D4614461E464A
+:1011C00002F04AFB50B9022E10D1012C0ED112A30D
+:1011D000D3E900230120C5E9002307E0282C10D023
+:1011E00005D8012C09D0052C0FD0002070BD302C63
+:1011F000FBD10BA3D3E90023ECE70BA3D3E9002336
+:10120000E8E70BA3D3E90023E4E70BA3D3E900232A
+:10121000E0E700BFAFF30080401DA12026812A0B2C
+:1012200078F6339F93CACD8D9E6AC421818A46EE9B
+:1012300026417272DF25D7B7F017304A39059E561E
+:101240002DE9F04F8DB080460D4602AF02F004FB51
+:10125000044600285BD12B7E022B1BD1EB8A012B8D
+:1012600018D101F0DFFF0646FFF76EFE03464FF48C
+:10127000C87006F51676DFF81892B3FBF0F202FBA1
+:10128000103316FA83F3C9F80030EB7E33B97B4B89
+:1012900000221A702C37BD46BDE8F08FAB8AE6B24B
+:1012A0000134013BB3420CD907F10803E1000822E5
+:1012B00028461E4401F0F8010023009602F0DEFBF0
+:1012C000ECE707F11800FFF757FE324607F1180167
+:1012D00007F1080006F012F90028D8D10F2E08D81F
+:1012E000664B1E70D9F80030A3F51673C9F80030AC
+:1012F000D0E7FB1DF87101460722009303462846FC
+:1013000002F0BCFBF979404602F09EFAC2E7EB8A94
+:10131000282B26D010D8012B1ED0052BBAD1BFF315
+:101320004F8F5749574BCA6802F4E0621343CB60B2
+:10133000BFF34F8F00BFFDE7302BABD16B7EE9468B
+:10134000514C0133627BDBB2934203D1EA7E237BB3
+:101350009A420BD0CD469DE729464046FFF71CFE3A
+:1013600098E729464046FFF7CDFE93E74FF0000887
+:1013700007F1180310222846A7F818804146009369
+:10138000012302F07BFBAE8A023EB6B2F31C9B1037
+:101390009B000733DB08A9EBC3039D460DF1080A48
+:1013A0001FFA88F34FEAC8019E4201F110010AD9E1
+:1013B0000AEB08030822284608F1010800930023DD
+:1013C00002F05CFBECE794F8D70000F00BFBD4F8DC
+:1013D000D810054619B994F8D70000F013FBD4F8DB
+:1013E000D83033449D4205D294F8D7000021013013
+:1013F00000F008FB4FEA960B4FF000081FFA88F147
+:101400008B45D4E9003209D90AEB8801012203EBAC
+:10141000880008F1010800F097FBEFE7F31894F853
+:10142000D70042F10002C4E90032D4F8D83006EB0C
+:101430000308C4F8D88000F0D5FA804509D394F8A1
+:10144000D730D4F8D8000133401B84F8D730C4F823
+:10145000D800FF2E0D4D09D80023237300F0F0FAB9
+:1014600000F032FD288108B9FFF726FA23689B0AAD
+:1014700001332B810023A3606CE700BF09340020F7
+:1014800000ED00E00400FA05A05D0020F823002034
+:101490000C340020F8B50E4C02260E4FA4F58053F4
+:1014A00043F8307C237E3BB965692DB1284600F0B6
+:1014B00089FD284606F00AF82046A4F5A55400F058
+:1014C00081FD012EA4F1100400D1F8BD0126E5E74D
+:1014D00020590020F0760008014B1870704700BFBB
+:1014E0000424002010B54FF040540C4B22689A425F
+:1014F00012D1627D0A4B0B481A70C922237D0E302F
+:10150000094900F8023C00F0F1FAE02200212046EF
+:1015100000F012FB012010BD0020FCE79AAD44C58D
+:1015200004240020A05D00201600003037B500F034
+:10153000CBFC1F4C1F4D022301221F496B712368F6
+:101540002881204604F580545B6898470122D4F82E
+:10155000B03404F5966018495B6898470023174932
+:101560004FF480520193164B16480093164B02F02D
+:1015700045F9164B197811B1124802F065F901F0DE
+:1015800051FE0446FFF7E0FC4FF4C873B0FBF3F2E2
+:1015900002FB130304F5167010FA83F00C4B18606D
+:1015A00004F0E6FB08B10F232B8103B030BD00BF70
+:1015B00040340020F823002040420F00082400207F
+:1015C000B911000810340020411200080424002042
+:1015D0000C3400202DE9F04F9C4D2DED028B93B083
+:1015E000DFF890A29A4F284602F000FA034600283E
+:1015F0003DD00024974E0E94A046ADF84440A1463D
+:10160000CDE90F44027B8DF844200FAA9968406809
+:1016100003C21B6843F000430E93336804F22C545A
+:10162000D3F810B001F000FE10EB0A02CDF80090E4
+:10163000304606F5A55641F100030EA9D84740F6FD
+:1016400058230028C8BF48F0010810369C42E4D156
+:10165000B8F1000F05D0284602F0CCF987F80090C9
+:10166000C1E73B78072B00F2DF8001333B7000239A
+:101670000DF12C084FF0010A0A93ADF834300B93AA
+:10168000C8F804309FED6B8B0026724C37462368F8
+:101690004FF0000B0DF11D0207A920468DF81CA08C
+:1016A0008DF81DB08DED008BD3F808905B46C847D0
+:1016B0009DF81C90B9F1000F1ED0102259460EA8BB
+:1016C00000F03AFA236808AA0AA95F6920460DF1DA
+:1016D0001E03B8470FAB4F4698E8030083E80300AA
+:1016E0009DF834300EA928468DF844300A9B0E939D
+:1016F000DDE9082302F046FB06F22C5640F658239B
+:1017000004F5A5549E4204F11004C0D1002FBBD1B2
+:10171000284602F0A1F8002840D14F4E01F082FD8A
+:10172000336898423AD301F07DFD0446FFF70CFC84
+:101730004FF4C87304F516748DF82870B0FBF3F2FB
+:1017400002FB130314FA83F33360444E377817B95E
+:1017500001238DF82830C7F110040EA8FFF70CFC08
+:101760000EABE4B20DF12900D919062C28BF0624CE
+:101770002246013400F0BAF90AABE4B228460393DA
+:10178000182304940293364B0193012300932BA357
+:10179000D3E9002302F0A2F80023337001F042FDE8
+:1017A000304A314C1368C31AB3F57A7F2FD31060D7
+:1017B00001F03AFD02460B46284602F025F928467C
+:1017C00002F04AF818B3237B0EAF284E002B14BF4B
+:1017D00003230223737101F025FD4FF47A73012274
+:1017E0003946B0FBF3F03060304600F003FB1823BD
+:1017F00080B202931E4B019340F25513CDE9037062
+:10180000009328460FA3D3E9002302F067F8237B57
+:101810002BB1FFF729FC237B002B7FF4E1AE13B043
+:10182000BDEC028BBDE8F08F284602F0E3F81EE71E
+:10183000AFF300800000000000000000401DA12068
+:1018400026812A0BF1C6A7C1D068080F10340020EA
+:10185000855E0020403400200C3400200934002034
+:1018600008340020805E0020A05D0020F8230020C6
+:10187000845E002040420F0008B5064800F0D6FF05
+:10188000054800F0D3FF054A05490020BDE808409F
+:1018900005F016BE40340020F0480020E05E002035
+:1018A000951400082DE9F84F4FF47A7306460D465B
+:1018B000002402FB03F7DFF85080DFF8509098F91E
+:1018C00000305FFA84FA5A1C01D0A34212D159F8B1
+:1018D00024002A4631460368D3F820B03B46D84757
+:1018E000854207D1074B012083F800A0BDE8F88F9F
+:1018F0000124E4E7002CFBD04FF4FA7003F012FD52
+:101900000020F3E7CC5E0020182200201C220020DB
+:10191000002307B5024601210DF107008DF80730BD
+:10192000FFF7C0FF20B19DF8070003B05DF804FB8E
+:101930004FF0FF30F9E700000A46042108B5FFF731
+:10194000B1FF80F00100C0B2404208BD074B0A461B
+:1019500030B41978064B53F82140014623682046DD
+:10196000DD69044BAC4630BC604700BFCC5E002054
+:101970001C220020A086010070B5104C0025104EDE
+:1019800003F0EAFF20803068238883420CD80025CA
+:101990002088013803F0DCFF23880544013BB5F5BE
+:1019A000802F2380F4D370BD03F0D2FF3368054449
+:1019B0000133B5F5802F3360E5D3E8E7CE5E002034
+:1019C000885E002004F0A6B800F1006000F58020D9
+:1019D0000068704700F10060920000F5802004F07C
+:1019E0001DB80000054B1A68054B1B889B1A8342E3
+:1019F00002D9104403F0ACBF00207047885E00207D
+:101A0000CE5E002038B50446074D29B12868204431
+:101A1000BDE8384003F0B4BF2868204403F09EFFBF
+:101A20000028F3D038BD00BF885E0020002070473A
+:101A300000F1FF5000F58F10D0F80008704700004B
+:101A4000064991F8243033B100230822086A81F84E
+:101A50002430FFF7BFBF0120704700BF8C5E00201D
+:101A6000014B1868704700BF0010005C194B01382B
+:101A70000322084470B51D68174BC5F30B042D0CE9
+:101A80001E88A6420BD15C680A46013C824213467E
+:101A90000FD214F9016F4EB102F8016BF6E7013A6B
+:101AA00003F10803ECD181420B4602D22C2203F849
+:101AB000012B0424094A1688AE4204D1984284BFFF
+:101AC000967803F8016B013C02F10402F3D1581A35
+:101AD00070BD00BF0010005C242200207C7600084E
+:101AE000704700007047000070470000002310B5E9
+:101AF000934203D0CC5CC4540133F9E710BD00001D
+:101B0000013810B510F9013F3BB191F900409C42FA
+:101B100003D11AB10131013AF4E71AB191F9002069
+:101B2000981A10BD1046FCE703460246D01A12F977
+:101B3000011B0029FAD1704702440346934202D0A8
+:101B400003F8011BFAE770472DE9F8431F4D1446CF
+:101B50000746884695F8242052BBDFF870909CB366
+:101B600095F824302BB92022FF2148462F62FFF739
+:101B7000E3FF95F824004146C0F1080205EB800020
+:101B8000A24228BF2246D6B29200FFF7AFFF95F8D7
+:101B90002430A41B17441E449044E4B2F6B2082E2D
+:101BA00085F82460DBD1FFF74BFF0028D7D108E090
+:101BB0002B6A03EB82038342CFD0FFF741FF00285B
+:101BC000CBD10020BDE8F8830120FBE78C5E00202C
+:101BD000024B1A78024B1A70704700BFCC5E00208F
+:101BE0001822002038B51A4C1A4D204602F0B8FED3
+:101BF0002946204602F0E0FE2D681748D5F89020CF
+:101C0000D2F8043843F00203C2F8043803F08AFB28
+:101C10001249284602F0DEFFD5F89020104DD2F888
+:101C20000438286823F002030E49A042C2F80438A1
+:101C30004FF4E1330B6001D002F0F0FD6868A04280
+:101C400004D00849BDE8384002F0E8BD38BD00BF07
+:101C5000C06500201C78000840420F00247800086E
+:101C60001C220020B45E00200C4B70B50C4D0446C5
+:101C70001E780C4B55F826209A420DD00A4B0021B5
+:101C800018221846FFF758FF0460014655F8260051
+:101C9000BDE8704002F0C2BD70BD00BFCC5E002048
+:101CA0001C220020C0650020B45E00202DE9F04712
+:101CB0000D46044600219046284640F27912FFF76F
+:101CC0003BFF234620220021284604F1220702F090
+:101CD00011F8231D022220212846C02602F00AF80E
+:101CE000631D03222221284602F004F8A31D0322CB
+:101CF0002521284601F0FEFF04F1080310222821C7
+:101D0000284601F0F7FF04F1100308223821284685
+:101D100001F0F0FF04F1110308224021284601F0F0
+:101D2000E9FF04F1120308224821284601F0E2FFEE
+:101D300004F1140320225021284601F0DBFF04F1B6
+:101D4000180340227021284601F0D4FF04F120033B
+:101D50000822B021284601F0CDFF04F1210308221A
+:101D6000B821284601F0C6FF314608363B46082216
+:101D70002846013701F0BEFFB6F5A07FF4D1002759
+:101D800004F1330A04F1320308223146284601F0F7
+:101D9000B1FF94F832304FEAC7099F4209F5A476A3
+:101DA00015D3B8F1000F08D1314609F24F1604F5EA
+:101DB00099730722284601F09DFF27463B1B94F8A4
+:101DC000322193420CD3F01DC008BDE8F0870AEB26
+:101DD0000703082231462846013701F08BFFD8E778
+:101DE00007F233133146082228460836013701F03E
+:101DF00081FFE3E713B5044608460021202223466D
+:101E000001900160C0F8031001F074FF231D0198D8
+:101E10000222202101F06EFF631D0198032222217E
+:101E200001F068FFA31D01980322252101F062FF44
+:101E3000019804F108031022282101F05BFF07201C
+:101E400002B010BDF8B50E460546144600218122A9
+:101E50003046FFF771FE2B4608220021304601F084
+:101E600049FF7CB90F246B1C07220821304601F082
+:101E700041FF01235F1C6A78013B934204D3E01DBC
+:101E8000C008F8BD0824F4E7EB19214608223046C3
+:101E900001F030FF08343B46ECE7000030B50A445F
+:101EA000084D91420DD011F8013B5840082340F3F2
+:101EB0000004013B2C4013F0FF0384EA5000F6D1EC
+:101EC000EFE730BD2083B8ED384A73B510686B4634
+:101ED00051686A4603C308233549364805F01EFB9E
+:101EE000044670B9344A6B46106851686A4603C3A9
+:101EF000082332492F4805F011FB044630BB0A2065
+:101F000022E00369B3F5E01FECD8418B40F2374281
+:101F10009142E7D12A4A024402F110018B42E1D3F7
+:101F2000103B244900209D1AFFF7B8FF04F1180167
+:101F300006462A460020FFF7B1FFA3689E42D1D192
+:101F4000E3689842CED1002002B070BD0369B3F5BA
+:101F5000E01F22D8B0F8661040F2374291421ED1FD
+:101F6000174A024402F15C018B421AD35C3B1149CF
+:101F700000209D1AFFF792FF04F1640106462A46ED
+:101F80000020FFF78BFFA268034696420BD1E06862
+:101F9000834214BF0D200020D6E70B20D4E70C208D
+:101FA000D2E71020D0E70D20CEE700BF8C760008E6
+:101FB000DCFF1B00000004089576000890FF1B0062
+:101FC0000800FCF710B5037C044613B9006805F05F
+:101FD0008DFA204610BD00000023BFF35B8FC36065
+:101FE000BFF35B8FBFF35B8F8360BFF35B8F704783
+:101FF000BFF35B8F0068BFF35B8F704770B505461A
+:102000000C30FFF7F5FF044605F108063046FFF7F0
+:10201000EFFFA04206D96D683046FFF7E9FF25447F
+:10202000281A70BD3046FFF7E3FF201AF9E70000D9
+:1020300070B505464068A0B105F10C0605F1080031
+:10204000FFF7D6FF04463046FFF7D2FF844204F183
+:10205000FF34304694BF6D680025FFF7C9FF2C445C
+:10206000201A70BD38B50C460546FFF7C7FFA042E1
+:1020700010D305F10800FFF7BBFF04446868BFF305
+:102080005B8FB4FBF0F100FB11440120AC60BFF3A7
+:102090005B8F38BD0020FCE72DE9F0411446074670
+:1020A0000D46FFF7C5FF844228BF0446D4B1B846A9
+:1020B00058F80C6B4046FFF79BFF304428604046C1
+:1020C0007E68FFF795FF331A9C4203D801206C60AD
+:1020D000BDE8F081A41B6B603B682044AB60E86006
+:1020E0000220F5E72046F3E738B50C460546FFF732
+:1020F0009FFFA04210D305F10C00FFF779FF0444C5
+:102100006868BFF35B8FB4FBF0F100FB1144012062
+:10211000EC60BFF35B8F38BD0020FCE72DE9FF4189
+:102120008846694607466C46FFF7B6FF002506B2AB
+:1021300004EBC606B4420AD0626808EB05012068C9
+:102140000834FFF7D3FC54F8043C1D44F2E7294659
+:102150003846FFF7C9FF284604B0BDE8F08100000B
+:10216000F8B505460C300F46FFF742FF05F10806AB
+:1021700004463046FFF73CFFA042304688BF6C68FB
+:10218000FFF736FF201A386020B12C683046FFF781
+:102190002FFF2044F8BD000073B5144606460D46D7
+:1021A000FFF72CFF8442019028BF0446DCB101A94F
+:1021B0003046FFF7D5FF019B33B93268C5E90233DA
+:1021C000C5E9002401200CE09C42286038BF01943E
+:1021D000019884426860F5D93368241A0220AB6004
+:1021E000EC6002B070BD2046FBE700002DE9FF4126
+:1021F0000F4669466C46FFF7CFFF00B2002604EB9E
+:10220000C005AC4209D0D4F80480B81954F8081BB2
+:1022100042464644FFF76AFCF3E7304604B0BDE8A7
+:10222000F081000038B50546FFF7E0FF044601469F
+:102230002846FFF717FF204638BD0000302383F300
+:10224000118862B670470000002383F3118862B6DC
+:1022500070470000012070477047000010B413461B
+:10226000026814680022A4465DF8044B6047000031
+:1022700000F5805090F859047047000000F5805038
+:1022800090F852047047000000F5805090F958040F
+:10229000704700004E20704700F5805208B5FFF7E8
+:1022A000CDFFD2F89834D2F894041844D2F8903480
+:1022B0001844D2F878341844D2F888341844D2F844
+:1022C00084341844FFF7C0FF08BD00002DE9F74F24
+:1022D0000C4600F580511F46054691F85234904651
+:1022E000BDF830909BB1D1F874340133C1F8743427
+:1022F00023689A0006D4237B082B0BD9627B0AB192
+:102300000F2B07D9D1F878340133C1F878344FF066
+:10231000FF300FE0FFF792FFEB6AD3F8C42012F40E
+:10232000001A0AD0D1F87C3400200133C1F87C3483
+:10233000FFF78AFF03B0BDE8F08F22684FF0480B2B
+:10234000D3F8C460002A6B6AC6F30446B4BF42F0F7
+:10235000804292041BFB063BCBF8002023685B0005
+:102360004FEA066344BF42F00052CBF80020227BC4
+:1023700043EA02437201CBF80430607B18B343F4A4
+:102380004013CBF80430D1F8A4340133C1F8A4349D
+:10239000AB1803F58353197B41F020011973207B9F
+:1023A000019200F09DFF0330019A80105FFA8AF3DA
+:1023B0000AF1010A83420DDA04EB83010BEB83037C
+:1023C00049689960F2E7AB1803F58353197B60F312
+:1023D0004511E3E70121EB6A04F10C00B140C3F8B9
+:1023E000D010AB18214603F58253C3E9048705EBEF
+:1023F000461303F58253183351F804CB814243F856
+:1024000004CBF9D109882A442846198041F268038F
+:10241000D65002F5805209F0030392F86C1043F095
+:10242000100321F01F010B43214682F86C30424615
+:10243000FFF70AFF3B46CDF8309003B0BDE8F04F00
+:1024400000F014BF2DE9F04700F58056044696F8D9
+:102450005254002D40F00181037C032B40F0928008
+:102460002B4628462F465FFA83FC944510DA01EB91
+:10247000CC0E51F83CC0BCF1000F04DBDEF804C008
+:10248000BCF1000F02DB01370133ECE70130FBE761
+:10249000FFF7D4FEE36AF0B9D3F8800040F0020001
+:1024A000C3F880004E23E06A002F6ED1D0F8803050
+:1024B00043F00103C0F88030694B6A4A1B6803F19E
+:1024C000805303F52C539B009342A36240F2AF80EC
+:1024D000654800F0A1FE4D2842D8DFF884814FEA1C
+:1024E000004EDFF88891D8F800C04EEA8C0EC3F891
+:1024F00084E00CF1805303F52C539B00636100EBE7
+:102500000C03D4F82CC0C8F80030C0F14E03DCF83E
+:10251000800040F03000CCF880004FF0000CD4F880
+:102520001480E6465FFA8CF08242BCDD01EBC00A03
+:1025300051F83000002810DBDAF804A0BAF1000FDF
+:102540000BDA09EA00400AF07F0A40EA0A0040F08C
+:10255000084048F82E000EF1010E0CF1010CE1E7E5
+:102560009A6922F001029A6100F05CFE0646E36A75
+:102570009B69D90704D500F055FE831BFA2BF6D9C9
+:10258000FFF762FE2846BDE8F087B7EB530F3DD258
+:10259000DFF8CCE04FEA074CDEF800304CEA830C61
+:1025A000C0F888C003F1805003EB4703002700F513
+:1025B0002C50CEF80030BC468000A061E06AD0F814
+:1025C000803043F00C03C0F88030D4F818E0FBB240
+:1025D0009A427FF771AF51F8330001EBC30800282E
+:1025E000D8F8043001DB002B0EDB20F0604023F034
+:1025F000604340F0005043F000434EF83C000EEBC7
+:10260000CC000CF1010C43600137E0E7836923F053
+:102610000103836100F006FE0646E36A9B69DA0760
+:10262000AED500F0FFFD831BFA2BF6D9A8E7E26ACE
+:10263000936923F00103936100F0F4FD0746E36A18
+:102640009B69DB0705D500F0EDFDC31BFA2BF6D91E
+:1026500096E7012586F8525492E7002592E700BFDD
+:10266000DC5E0020FCB50040A07600080000FF07FB
+:1026700013B500F580540191606CFFF7D9FC1F2859
+:102680000AD920220199606CFFF748FDA0F12003D0
+:102690005842584102B010BD0020FBE700F58050C1
+:1026A00008B5FFF7CBFD406CFFF796FCBDE808408E
+:1026B000FFF7CABD002202608281426082607047DB
+:1026C0000022002310B5C0E90023002304460C308B
+:1026D00020F8043CFFF7EEFF204610BD2DE9F0473F
+:1026E000074688B09A46884607F580546846914662
+:1026F000FFF7A4FDFFF7E4FF606CFFF77FFC1F28E6
+:102700002DD920226946606CFFF78CFD202826D148
+:1027100094F852341BB303AD444605AB2E4608343F
+:1027200003CE9E4244F8080C44F8041C3546F5D10B
+:102730003068414620603846B388A380DDE9002335
+:10274000C9E90023BDF808304A46AAF80030FFF76F
+:102750007BFD534608B0BDE8F04700F075BD002092
+:10276000FFF772FD08B0BDE8F08700002DE9F84FD3
+:102770000023064600F58154054688461034C0E91A
+:102780000133274B46F8303B374638462037FFF7B2
+:1027900097FFA742F9D105F580544FF4805305F512
+:1027A000A3594FF0000A26630026676405F5835796
+:1027B00009F110094FF0000B1037E663C4E90D363C
+:1027C000012384F8403084F84830A7F118002037FE
+:1027D00047E910ABFFF76EFF47F8286C4F45F4D17F
+:1027E000B8F1010F84F85884A4F85A64A4F85C6422
+:1027F000A4F85E6484F86064A4F86264A4F8646475
+:10280000A4F8666484F8686402D9064800F004FD00
+:10281000054B284653F82830EB62BDE8F88F00BF1F
+:10282000F0760008C4760008E0760008044B10B586
+:10283000197804464A1C1A70FFF798FF204610BD0D
+:10284000D95E00202DE9F04700295FD0304F314894
+:10285000B7FBF1F581428CBF0A201120431EB5FB66
+:10286000F0FC00FB1C50DCB220B1022B1846F5D85E
+:10287000002037E00CF1FF35B5F5806F32D2C4EBA4
+:10288000C4094FF47A7009F103034FEAE308C3F374
+:10289000C70308F1010AA4EB030E08FB00085FFA66
+:1028A0008EF65AFA8EFEB8FBFEFEBEF5617F1BDC8B
+:1028B0001FFA8EF4581C56FA80F00CFB00FCB7FB94
+:1028C000FCFC6145D4D1013BDBB20F2BD0D8711E8B
+:1028D0000020C9B2072905D8107101201480558045
+:1028E00053719171BDE8F08709F1FF334FEAE30EB0
+:1028F000C3F3C7030EF10108E41A0EFB0000E6B2B1
+:1029000058FA84F4B0FBF4F4A4B2D3E70846E9E73C
+:1029100000B4C4043F420F0038B540F27772C36A76
+:10292000154CC3F8BC200722C36AC3F8C82022682C
+:10293000C16A930043F4C023C1F8A03002F1805370
+:1029400002F16C01C56A03F52C53EA3289009B0041
+:10295000226041F0E061094AC361C5F8C01003F587
+:10296000D87103F56A7341629342836202D90448C5
+:1029700000F052FC38BD00BFDC5E0020FCB500401A
+:10298000A07600082DE9F04F00F58055994689B0F2
+:10299000044695F858348A469046022B04D90027FD
+:1029A000384609B0BDE8F08F9E4A52F8231009B9A5
+:1029B00042F823009C49C4F80CA00B7884F81090CE
+:1029C000C3B9FFF73BFC994BD3F8EC2042F480727B
+:1029D000C3F8EC20D3F8942042F48072C3F894201A
+:1029E000D3F8942022F48072C3F8942001230B7052
+:1029F000FFF72AFC95F851346BB9FFF71FFC8C4A9E
+:102A000095F85834D35CEBB1012B24D0012385F821
+:102A10005134FFF719FCFFF711FCE26A936923F0C8
+:102A20001003936100F0FEFB0746E36A9E6916F00F
+:102A3000080617D000F0F6FBC31BFA2BF5D9FFF7F9
+:102A400003FCACE70321132001F032FD0321152024
+:102A500001F02EFDDAE70321142001F029FD032106
+:102A60001620F5E79A6942F001029A6100F0DAFB5C
+:102A70000746E36A9A69D00705D400F0D3FBC31B6D
+:102A8000FA2BF6D9DBE79A69002704F5825B42F05E
+:102A900002020BF1100B9A61E36A5F65FFF7D4FB4A
+:102AA000686CFFF799FA202200216846FFF744F886
+:102AB00002A8FFF7FFFD6A460BEB06030DF1180EA7
+:102AC000069794460833BCE80300F44543F8080C25
+:102AD00043F8041C6246F4D1DCF80000203618608C
+:102AE000B6F5806F9CF804201A71DCD1002304F540
+:102AF000A252514620461A3285F8503485F8533494
+:102B0000FFF7A0FE074690B9E26A936923F001033C
+:102B1000936100F087FB0546E36A9B69D9077FF55F
+:102B20003EAF00F07FFB431BFA2BF5D937E795F852
+:102B30005F6495F85E243602C5F86CA4E36A46EA41
+:102B4000426695F860241643B5F85C2446EA0246CE
+:102B5000DE61B8F1000F29D004F5A35241462046AA
+:102B60000232FFF76FFE90B9E26A936923F0010326
+:102B7000936100F057FB0546E36A9B69DA077FF52E
+:102B80000EAF00F04FFB431BFA2BF5D907E795F882
+:102B9000683495F867141B01C5F87084E26A43EA4B
+:102BA0000123B5F8641443EA0143D360E36A0026C5
+:102BB0002046C3F8BC60FFF7AFFE85F859646FF09C
+:102BC0004042E36AB9F1030F1A651A4AE36A5A658B
+:102BD0004FF00222E36A9A654FF0FF32E36AC3F8CE
+:102BE000E0204FF00302E36ADA65E26A936943F496
+:102BF000407393613FF4D4AEE26A936923F001031A
+:102C0000936100F00FFB0646E36A9B69DB0705D57D
+:102C100000F008FB831BFA2BF6D9C0E6012385F8E8
+:102C20005234BDE6D05E0020D85E00200044025839
+:102C3000D8760008550200022DE9F04F054689B00C
+:102C400090469946002741F2680A00F58056EB6AE3
+:102C5000D3F8D830FB40D8074AD505EB47124FEAE6
+:102C6000471B52441379190742D4D6F880340133F4
+:102C7000C6F8803413799A0605EB0B0248BFD6F8E4
+:102C8000A834524444BF0133C6F8A834137943F042
+:102C900008031371DB0723D596F8533403B305F506
+:102CA00082546846FFF70CFD03AB18345C4404F112
+:102CB000080C2068083454F8041C1A46644503C202
+:102CC0001346F6D12068694610602846A2889A808B
+:102CD0000123ADF808302B68CDE90089DB6B9847FC
+:102CE000D6F8543423B1D6F89C340133C6F89C345A
+:102CF0000137202FABD109B0BDE8F08F2DE9F04F9F
+:102D00000F468DB0044600F08FFA82468946002FA8
+:102D10005BD1E36AD3F8A02012F4FE0F03D10020A8
+:102D20000DB0BDE8F08FD3F8A420920141BF04F5A7
+:102D30008051D1F894240132C1F89424D3F8A4200E
+:102D40005606ECD0D3F8A450E669C5F30525482310
+:102D5000E8464FF0000B03FB05664046FFF7AAFC70
+:102D6000326851004ABF22F06043C2F38A4343F005
+:102D70000043920048BF43F080430093736813F40C
+:102D800000131BBF012304F580528DF80D308DF820
+:102D90000D301EBFD2F8AC340133C2F8AC34F38826
+:102DA00003F00F038DF80C309DF80C0000F098FA3A
+:102DB0005FFA8BF3984225D9F2180CA90BF1010B9D
+:102DC000127A0B4403F82C2CEEE7012FA7D1E36A0B
+:102DD000D3F8B02012F4FE0FA1D0D3F8B42095019F
+:102DE00041BF04F58051D1F894240132C1F89424F4
+:102DF000D3F8B420500692D0D3F8B450266AC5F365
+:102E00000525A4E7EFB9E36AC3F8A85004A807AD05
+:102E1000FFF756FC98E80F0007C52B8000232046DB
+:102E200004A9ADF81830236804F58054DB6BCDE9B4
+:102E300004A9984758B1D4F88C340133C4F88C34C1
+:102E40006EE7012FE2D1E36AC3F8B850DEE7D4F8A9
+:102E5000903401200133C4F8903461E7F8B5054699
+:102E60000F4600F58054012639462846FFF746FFF5
+:102E700010B184F85364F7E7D4F8543423B1D4F88C
+:102E80009C340133C4F89C34F8BD0000C36AF0B52B
+:102E90001A6C12F47F0F2BD01B6C00F5805441F29A
+:102EA00068054FF0010CC4F8A0340023471900EB6B
+:102EB00043125E012A44117911F0020F15D049071F
+:102EC00013D4B959C66A0CFA01F1D6F8CCE011EA6C
+:102ED0000E0F0AD0C6F8D410117941F00401117117
+:102EE000D4F888240132C4F888240133202BDED1A1
+:102EF000F0BD00002B4B70B51E561B5C012B30D86B
+:102F0000294D2A4A55F8233052F8264013B349B3C5
+:102F1000236D9A0510D54FF40073236500F084F9F2
+:102F200050EA01020B4602D0013861F1000302466B
+:102F300055F82600FFF780FE236D9B012CD54FF03E
+:102F4000007255F82630226503F58053012283F87C
+:102F5000592421E001232365102323654FF4805376
+:102F6000236570BD236DDA0702D4236D5B0706D598
+:102F70000523002155F826002365FFF76FFF236D19
+:102F8000D80602D4236D590606D55023012155F8E1
+:102F900026002365FFF762FF55F82600BDE8704064
+:102FA000FFF774BFDC760008D05E0020E0760008F2
+:102FB00008B5FFF743F9FFF769FFBDE80840FFF7E1
+:102FC00043B90000C36AD3F8C00010F07C5005D0AC
+:102FD000D3F8C40080F40010C0F3405070470000E4
+:102FE00000F5805008B5FFF729F9406CFFF706F8A7
+:102FF000FFF72AF943090CBF0120002008BD00009B
+:1030000000F5805393F8592462B1C16A8A6922F0AD
+:1030100001028A61D3F898240132C3F8982400226F
+:1030200083F85924704700002DE9F74300F58251D9
+:1030300098460025FFF702F9103141F2680E4FF073
+:10304000010900F5805C00EB4514744423795E07A8
+:103050001CD4DB061AD58E69C36A09FA06F6D3F8C2
+:10306000CC703E4212D04F6801970F689742019F83
+:1030700077EB08070AD2C3F8D460237943F004033E
+:103080002371DCF884340133CCF8843401352031E9
+:10309000202DD8D103B0BDE8F043FFF7D5B800002C
+:1030A000F8B51E4600230F46054613701446FFF779
+:1030B00097FF80F0010038701EB12846FFF782FFAD
+:1030C0002070F8BD2DE9F04F85B099460D46804639
+:1030D000164691F800B0DDE90EA302931378019330
+:1030E00000F0A2F82B7804460F4613B93378002B72
+:1030F00042D022463B464046FFF796FFFFF758FF77
+:10310000FFF77EFF4B4632462946FFF7C9FF2B7873
+:1031100033B1BBF1000F03D0012005B0BDE8F08F43
+:10312000337813B1019B002BF6D108F5805303933C
+:103130005445029B77EB03031ED2039BD3F8540440
+:10314000D0B10368AAEB0401DB6889B298474B460B
+:10315000324629464046FFF7A3FF2B7813B1BBF157
+:10316000000FD9D1337813B1019B002BD4D100F0DB
+:103170005BF804460F46DBE70020CEE7002108B5E8
+:103180000846FFF7B7FEBDE8084001F05BB8000055
+:1031900008B501210020FFF7ADFEBDE8084001F0B1
+:1031A00051B8000008B500210120FFF7A3FEBDE8DB
+:1031B000084001F047B80000012108B50846FFF7B4
+:1031C00099FEBDE8084001F03DB8000000B59BB095
+:1031D000EFF3098168226846FEF788FCEFF3058368
+:1031E000014B9B6BFEE700BF00ED00E008B5FFF769
+:1031F000EDFF000000B59BB0EFF30981682268463F
+:10320000FEF774FCEFF30583014B5B6BFEE700BF39
+:1032100000ED00E0FEE700000FB408B5029802F0F0
+:103220000DF8FEE702F0D2BC02F0AABC02F0A8BC86
+:1032300013B56C46031D84E8060094E8030083E898
+:103240000500012002B010BD73B58568019155B12C
+:103250001B885B0707D4D0E900369B6B9847019A1F
+:10326000C1B23046A847012002B070BDF0B58668F3
+:1032700089B005460C465EB1BDF838305B070AD40C
+:10328000D0E900379B6B98472246C1B23846B04719
+:10329000012009B0F0BD0022002301F10806CDE9AC
+:1032A000002300230A46ADF8083003AB106808324B
+:1032B00052F8041C1C46B24203C42346F6D11068DF
+:1032C00020609288A280FFF7B1FF0423ADF8083098
+:1032D0002B68CDE90001DB6B694628469847D7E7A4
+:1032E000082817D909280CD00A280CD00B280CD094
+:1032F0000C280CD00D280CD00E2814BF40203020F4
+:1033000070470C2070471020704714207047182019
+:1033100070472020704700002DE9F041056A15B97B
+:103320000162BDE8F0814B68AC4623F06047C3F30F
+:103330008A464FEAD37EC3F3807816EA230638BF65
+:103340003E462B465A68BEEBD27F22F060440AD03C
+:10335000002A18DAA40CB44217D19D420FD10D6097
+:10336000DEE71346EEE7A74207D102F08044C2F33E
+:10337000807242450BD054B1EFE708D2EDE7CCF8AC
+:1033800000100B60CDE7B44201D0B442E5D81A6812
+:103390009C46002AE5D11960C3E700002DE9F047FB
+:1033A000089D01F0070400EBD1004FF47F494FEA7C
+:1033B000D508224405F00705944201D1BDE8F08705
+:1033C00004F0070705F0070A111B08EBD50E574557
+:1033D0003E4613F80EC038BF5646C6F108068E4268
+:1033E00028BF0E46E108415C34443544B94029FA0F
+:1033F00006F721FA0AF1FFB28CEA010147FA0AF74F
+:1034000039408CEA010C03F80EC0D5E780EA0120B0
+:10341000082341F2210201B2013B4000002980B2A1
+:10342000B8BF504013F0FF03F5D1704738B50C46D4
+:103430008D18A54200D138BD14F8011BFFF7E6FF37
+:10344000F7E7000002684AB1136801890360C38886
+:1034500001339BB29942C38038BF03811046704745
+:1034600070B588B0044620220D4668460021FEF75C
+:1034700063FB20460495FFF7E5FF024660B16B460B
+:10348000054608AE1C46083503CCB44245F8080C86
+:1034900045F8041C2346F5D1104608B070BD000065
+:1034A000082817D909280CD00A280CD00B280CD0D2
+:1034B0000C280CD00D280CD00E2814BF4020302032
+:1034C00070470C2070471020704714207047182058
+:1034D0007047202070470000082817D90C280CD905
+:1034E00010280CD914280CD918280CD920280CD94C
+:1034F00030288CBF0F200E207047092070470A200B
+:1035000070470B2070470C2070470D20704700005B
+:103510002DE9F843078C0446072F1ED900254FF6E6
+:10352000FF73D0E90298C5F12006A5F1200029FA21
+:1035300005F1083508FA06F628FA00F03143014390
+:103540001846C9B2FFF762FF402D0346EBD13A4659
+:10355000E169BDE8F843FFF769BF4FF6FF70BDE8CA
+:10356000F883000010B54B6823B9CA8A63F30902D7
+:10357000CA8210BDC4681A681C60C360438A013BDC
+:1035800043824A60EFE700002DE9F84F1D46CB8AE1
+:103590000F468146C3F30901924605290B4630D0F8
+:1035A0000020AAB207F11A049EB21FFA80F8042E76
+:1035B0000FD8904503F1010306D30A44FB8A62F356
+:1035C00009030120FB821AE01AF800600130E6547A
+:1035D000EAE79045F1D2A1F1050B1C237C68BBFB07
+:1035E000F3F203FB12BB1FFA8BF6002C45D14846C1
+:1035F000FFF728FF044638B978606FF00200BDE895
+:10360000F88F4FF00008E6E7002606607860ADB25C
+:103610004FF0000B454510D90AEB0803221D13F8A3
+:10362000011B08F101089155B1B21FFA88F81B2956
+:103630002BD0454506F10106F1D8FB8AC3F30902F8
+:10364000154465F30903BCE701321C4692B22368B6
+:10365000002BF9D16B1F0B441C21B3FBF1F3013399
+:103660009BB29A42D3D2BBF1000FD0D14846FFF7AC
+:10367000E9FE20B9C4F800B0BFE70122E7E7C0F8CF
+:1036800000B05E4620600446C1E74545D5D94846AE
+:10369000FFF7D8FE08B92060AFE7C0F800B00026F9
+:1036A00020600446B6E700002DE9F04F1C460746AF
+:1036B00088462DED028B83B05B690192002B00F0F0
+:1036C0009A80238C2BB1E269002A00F09480072BAA
+:1036D00035D807F10C00FFF7B5FE054638B96FF095
+:1036E0000205284603B0BDEC028BBDE8F08F142222
+:1036F0000021FEF721FA228CE16905F10800FEF7AE
+:10370000F5F9208C48F00041013080B2FFF7E4FE6B
+:10371000FFF7C6FE013880B2208401302874384695
+:103720006369228C1B782A4403F01F0363F03F0374
+:10373000137269602946FFF7EFFD0125D1E74FF0CD
+:10374000000900F10C034FF0800A4E464D4608EE8A
+:10375000103A18EE100AFFF775FE83460028BED017
+:1037600014220021FEF7E8F9002E3AD1019B022233
+:10377000ABF808300BF1080E1FFA82FC218C0CF11B
+:103780000100BCF1060F80B201D88E422BD3FFF7A7
+:10379000A3FE8E4208BF4FF0400AFFF781FE626928
+:1037A0000138013512781BFA80F1013002F01F0256
+:1037B0002DB242EA491289F001094AEA020A48F0A8
+:1037C000004281F808A059468BF810003846CBF823
+:1037D00004204FF0000AFFF79FFD238CB342B8D1BD
+:1037E0007FE70022C6E7E169895D01360EF8021025
+:1037F000B6B20132C0E76FF0010572E7F8B51546C1
+:103800000E462C22002104461F46FEF795F9069B22
+:10381000B5F5001FA760636004F10C00079B34BF7F
+:103820006A094FF6FF72A6616362002397B29A425B
+:1038300005D80023036027826382A382F8BD066057
+:10384000013330462036F2E703781BB94BB2002B28
+:10385000C8BF01707047000000787047F8B50C468B
+:10386000C969074609B9238CABBB257E1F2D32D809
+:10387000387818BB228C072A2AD8268A36F0030308
+:1038800029D14FF6FF70FFF7D1FD20F00100310282
+:103890004FF6FF72400441EA0561400C41EA4025C1
+:1038A000234629463846FFF7FFFE62691378013345
+:1038B000DBB21F2B88BF00231370F8BD218A2D06B1
+:1038C00045EA012505432046FFF722FE0246E7E7C9
+:1038D0006FF00300F1E76FF00100EEE770B58AB01A
+:1038E000044616460021282268461D46FEF724F9A4
+:1038F000BDF8383069462046ADF810300F9B05936F
+:103900009DF840308DF81830119B0793BDF8483072
+:10391000CDE90265ADF82030FFF7A0FF0AB070BD19
+:103920002DE9F041D36905460C4616460BB9138CB8
+:103930004BBB377E1F2F26D895F80080B8F1000FBB
+:1039400024D03046FFF7E4FD3378210202462846B2
+:1039500041EAC331338A41EA080141EA076141EA99
+:103960000341334641F08001FFF79EFE3378012B7F
+:1039700007D1726913780133DBB21F2B88BF002394
+:103980001370BDE8F0816FF00100FAE76FF00300FB
+:10399000F7E70000F0B58BB004460D46174600214E
+:1039A000282268461E46FEF7C7F89DF84C30294687
+:1039B00020465A1E534253416A468DF800309DF806
+:1039C0004030ADF81030119B05939DF848308DF8CC
+:1039D0001830149B0793BDF85430CDE90276ADF84A
+:1039E0002030FFF79DFF0BB0F0BD0000006A00B172
+:1039F00004307047036A1A680262C2681A60C360C2
+:103A0000438A013B438270472DE9F041D0F81C8086
+:103A100014461D46184E4146002709B9BDE8F081FD
+:103A2000D1E90223A21A65EB0303964277EB030365
+:103A30001ED2C3698B420DD1FFF794FDC3691B6889
+:103A4000C361C3680B60438AC160013BC1694382A3
+:103A50008846E2E7FFF786FD0B68C8F80030C368C8
+:103A60000B60438AC160013B4382D8F80010D4E761
+:103A700088460968D1E700BF80841E002DE9F04F19
+:103A80008BB00D4614469B46DDF8509080460028CA
+:103A900000F01881B9F1000F00F01481531E3F2B84
+:103AA00000F21081012A03D1BBF1000F40F00A811E
+:103AB0000023CDE90833B8F81430B5EBC30F4FEA53
+:103AC000C30703D300200BB0BDE8F08F2B199F4232
+:103AD000D8F80C3036BF7F1B2746FFB21BB9D8F889
+:103AE0001030002B7AD0272D4DD8C5F128060023A1
+:103AF0002946B742009308ABD8F808002CBFF6B2AD
+:103B00003E46A7EB060A354432465FFA8AFAFFF7CB
+:103B100045FCB8F81430282103F10053053BDB00C5
+:103B20000493D8F80C300393039B13B1BAF1000F40
+:103B30002CD1D8F8100040B1BAF1000F05D008AB75
+:103B40005246691A0096FFF729FC38B2002FB9D007
+:103B500066070AD00AAB624203EBD40102F0070207
+:103B600011F8083C134101F8083C082C3DD9102CF1
+:103B700040F2B580202C40F2B780BBF1000F00F07E
+:103B80009C80082335E0BA460026C2E7049BE02B60
+:103B900028BFE02306930B44AB42059315D95A1B6B
+:103BA0000398691A0096924508AB00F1040034BFEF
+:103BB0005246D2B20792FFF7F1FB079A1644AAEBDE
+:103BC000020A1544F6B25FFA8AFA049B069A05992E
+:103BD0009B1A0493039B1B680393A5E700933A4643
+:103BE00008AB2946D8F80800ADE7BBF1000F13D0A9
+:103BF0000123B4EBC30F6BD0082C12D89DF82030F2
+:103C0000621E23FA02F2D50706D54FF0FF3202FA00
+:103C100004F423438DF820309DF8203089F80030DB
+:103C200051E7102C12D8BDF82030621E23FA02F2A0
+:103C3000D10706D54FF0FF3202FA04F42343ADF862
+:103C40002030BDF82030A9F800303CE7202C0FD8F8
+:103C50000899631E21FA03F3DA0705D54FF0FF3206
+:103C600002FA04F40C430894089BC9F800302AE7D0
+:103C7000402C2AD0611EC4F12102A4F12103DDE908
+:103C8000086526FA01F105FA02F225FA03F3114359
+:103C90001943CB0711D50122A4F12003C4F120015F
+:103CA00002FA03F322FA01F1A2400B43524263EB02
+:103CB000430332432B43CDE90823DDE90823C9E957
+:103CC000002300E76FF00100FDE66FF00800FAE660
+:103CD000082CA1D9102CB4D9202CEED8C4E7BBF104
+:103CE000000FAED0022384E7BBF1000FBCD0042349
+:103CF0007FE70000012A30B5144638BF012485B0A3
+:103D00000025402C28BF4024012ACDE9025518D8AF
+:103D10001B788DF8083063070AD004AB624203EBCE
+:103D2000D40502F0070215F8083C934005F8083C5A
+:103D3000034600912246002102A8FFF72FFB05B0A1
+:103D400030BD082AE4D9102A03D81B88ADF8083002
+:103D5000E1E7202A95BF1B68D3E900230293CDE950
+:103D60000223D8E710B5CB681BB98B600B618B823F
+:103D700010BDC4681A681C60C360438A013B43825B
+:103D8000CA60F0E72DE9F04F93B004460D46CDE947
+:103D900003230B681806C3F3C01147BFC3F3C03B2E
+:103DA000C3F306264FF0020B0E46002B80F2FF8174
+:103DB00013F0C04940F0FB812A7B002A00F0F78114
+:103DC000BBF1020F03D02078B04240F0F381C3F37F
+:103DD0000460079003F07F00059059B3C3F3074ACE
+:103DE0007606059B2A4446EA0B4692F80380002299
+:103DF00046EA83460023CDE908235FEAD81346EA62
+:103E00000A06029369D0059B524608A920460093F2
+:103E10005B466768B847002800F0CF81E76987B93B
+:103E2000314604F10C00FFF71BFB0746C8B96FF0E1
+:103E3000020056E0C3F30F2A590608BF0AF0030A2E
+:103E4000CEE73B699E420DD03F68002FF9D1314645
+:103E500004F10C00FFF704FB07460028E7D0E369F4
+:103E60003B60E761FE7D08F01F03C6F384060693FE
+:103E7000F01A9B1B1FFA80FC0028B8BF0CF1200031
+:103E80001FFA83FCB8BF00B2002BD7E90221BCBFE8
+:103E90000CF120031BB252EA010636D0039EDFF874
+:103EA000D8C2B21A049E66EB01010026944576EB57
+:103EB000010C2AD395F80DE097F81AC0E64518D101
+:103EC000029E002E79D001281FDC7868E8B9A94E3F
+:103ED000964270EB010216D337E0E76927B96FF01D
+:103EE0000C0013B0BDE8F08F3B699E42BAD03F682A
+:103EF000F4E7A048904276EB010201D30020F0E7FE
+:103F0000029A002AFAD00F2B18DCFA7D4FEA8803B8
+:103F10003946204602F0030203F07C031343FB758D
+:103F2000FFF720FB6B7BBB76029B3BB9FB7DC3F3AA
+:103F30008402013262F38603FB75D0E76A7BBB7EA5
+:103F40009A42DBD1029B002B37D04FEA9813022B09
+:103F500033D0039B142200210DA8BB60049BFB609F
+:103F6000FDF7EAFD039B0AA920460A93049BADF8DE
+:103F70003EA00B932B1D8DF840B00C932B7B013B87
+:103F8000DBB2ADF83C30069B8DF84130079B8DF8D5
+:103F90004230059B8DF8433094F8283083F00103BC
+:103FA0008DF84430A3689847FB7DC3F38403013345
+:103FB00003F01F039B02FB82A0E7FB7DC8F34012C6
+:103FC000B2EBD31F40F0FC80C3F38403069A934204
+:103FD00040F0F98002994FEA98122B7B00294DD0CE
+:103FE000D2075DD4032B40F2F180039BAE1D39460E
+:103FF00004F10C00BB603246049BFB602B7B033B4F
+:10400000DBB2FFF7C1FA00280CDA39462046FFF789
+:10401000A9FAFB7DC3F38403013303F01F039B0262
+:10402000FB8204E7AB88DDE908843B834FF6FF732E
+:10403000C9F12000A9F1200228FA09F109F10809C3
+:1040400004FA00F024FA02F2014318461143C9B2FF
+:10405000FFF7DCF9B9F1400F0346E9D1B8823146E8
+:104060002A7B033AD2B2FFF7E1F9FB7DB882DA434B
+:10407000C2F3C01262F3C713FB753FE782B92E1D6E
+:10408000013B394604F10C00DBB23246FFF77CFA03
+:104090000028BADB2A7B3146B88A013AD2B2E2E77D
+:1040A000F98A013BC1F30901DAB204295CD8281D61
+:1040B000002307F11B069A4208D910F801CB0133FF
+:1040C00006F801C00131DBB20529F4D1039993420E
+:1040D0000A9138BF043304992CBF002355FA83F3A7
+:1040E0000B9107F11B010C9179680E930D91291D1D
+:1040F000FB8AADF83EA0C3F309038DF840B01A4423
+:10410000069B8DF84130079BADF83C208DF842307E
+:10411000059B8DF8433094F8283083F001038DF827
+:1041200044300023B88A7B602A7B013AFFF77EF98E
+:104130003B8BB882834203D1A3680AA920469847E3
+:1041400020460AA9FFF70EFEFB7DBA8AC3F384035B
+:10415000013303F01F039B02FB823B8B9A420CBF8F
+:1041600000206FF01000BCE67B68002BAED005206D
+:1041700006E000BF40420F0080841E001C30334622
+:104180001E68002EFAD1091A2E1D081D184401EBD5
+:10419000090C5FFA89F3BCF11B0F97D89A4295D9A5
+:1041A00016F8013B09F1010900F8013BEFE76FF058
+:1041B000090096E66FF00A0093E66FF00B0090E6B8
+:1041C0006FF00D008DE66FF00E008AE66FF00F00C5
+:1041D00087E600BFEFF30983054968334A6B22F095
+:1041E00001024A6383F30988002383F3118870472F
+:1041F00000EF00E0302080F3118862B60D4B0E4ACC
+:10420000D96821F4E0610904090C0A430B49DA601A
+:10421000D3F8FC2042F08072C3F8FC20084AC2F8B0
+:10422000B01F116841F0010111602022DA7783F894
+:104230002200704700ED00E00003FA0555CEACC542
+:10424000001000E0302310B583F311880E4B5B683B
+:1042500013F4006314D0F1EE103AEFF309844FF039
+:104260008073683CE361094BDB6B236684F3098848
+:1042700000F0A2FF10B1064BA36110BD054BFBE798
+:1042800083F31188F9E700BF00ED00E000EF00E0E4
+:1042900043070008460700080268436811430160AD
+:1042A00003B1184770470000024A136843F0C00387
+:1042B000136070470078004013B50E4C204600F0A4
+:1042C000A1FA04F1140000234FF400720A4900948B
+:1042D00000F05EF9094B4FF40072094904F138000F
+:1042E000009400F0D7F9074A074BC4E9172302B03E
+:1042F00010BD00BFE45E0020505F0020A94200080E
+:10430000506100200078004000E1F505037C30B5E5
+:10431000214C002918BF0C46012B0CD11F4B984291
+:1043200009D11F4B9A6C42F080429A641A6F42F096
+:1043300080421A671B6F2268036EC16D03EB520344
+:104340008466B3FBF2F36268150442BF23F00705ED
+:1043500003F0070343EA4503CB60A36843F040033F
+:104360004B60E36843F001038B6042F4967343F0C3
+:1043700001030B604FF0FF330B62510505D512F0BE
+:10438000102205D0B2F1805F04D080F8643030BDD7
+:104390007F23FAE73F23F8E730770008E45E002048
+:1043A000004502582DE9F047C66D05463768F469A7
+:1043B000210734621AD014F0080118BF4FF480713D
+:1043C000E20748BF41F02001A3074FF0300348BF88
+:1043D00041F04001600748BF41F0800183F311883C
+:1043E000281DFFF759FF002383F31188E2050AD542
+:1043F000302383F311884FF48061281DFFF74CFFB1
+:10440000002383F311884FF030094FF0000A14F0B5
+:10441000200838D13B0616D54FF0300905F1380A8F
+:10442000200610D589F31188504600F067F900285E
+:1044300036DA0821281DFFF72FFF27F080033360AD
+:10444000002383F31188790614D5620612D5302330
+:1044500083F31188D5E913239A4208D12B6C33B129
+:1044600027F040071021281DFFF716FF37600023B3
+:1044700083F31188E30618D5AA6E1369ABB15069AE
+:10448000BDE8F047184789F31188736A284695F804
+:104490006410194000F0D0F98AF31188F469B6E786
+:1044A000B06288F31188F469BAE7BDE8F0870000CC
+:1044B000090100F16043012203F56143C9B283F8A9
+:1044C000001300F01F039A4043099B0003F160436F
+:1044D00003F56143C3F880211A607047F8B51546AB
+:1044E000826804460B46AA4200D28568A169266903
+:1044F000761AB5420BD218462A46FDF7F7FAA36999
+:104500002B44A3612846A3685B1BA360F8BD0CD9AC
+:10451000AF1B18463246FDF7E9FA3A46E1683044E7
+:10452000FDF7E4FAE3683B44EBE718462A46FDF75B
+:10453000DDFAE368E5E7000083689342F7B50446D7
+:10454000154600D28568D4E90460361AB5420BD20C
+:104550002A46FDF7CBFA63692B4463612846A368BA
+:104560005B1BA36003B0F0BD0DD93246AF1B0191B8
+:10457000FDF7BCFA01993A46E0683144FDF7B6FA16
+:10458000E3683B44E9E72A46FDF7B0FAE368E4E76D
+:1045900010B50A440024C361029B8460C1600261BB
+:1045A0000362C0E90000C0E9051110BD08B5D0E9FB
+:1045B0000532934201D1826882B9826801328260F9
+:1045C0005A1C426119700021D0E904329A4224BF7A
+:1045D000C368436100F0C2FE002008BD4FF0FF3009
+:1045E000FBE7000070B5302304460E4683F31188C4
+:1045F000A568A5B1A368A269013BA360531CA36190
+:1046000015782269934224BFE368A361E3690BB183
+:1046100020469847002383F31188284607E0314657
+:10462000204600F08BFE0028E2DA85F3118870BD89
+:104630002DE9F74F04460E4617469846D0F81C90D1
+:104640004FF0300A8AF311884FF0000B154665B120
+:104650002A4631462046FFF741FF034660B94146EE
+:10466000204600F06BFE0028F1D0002383F3118870
+:10467000781B03B0BDE8F08FB9F1000F03D00190B3
+:104680002046C847019B8BF31188ED1A1E448AF31C
+:104690001188DCE7C160C361009B82600362C0E9EE
+:1046A00005111144C0E9000001617047F8B50446E6
+:1046B0000D461646302383F31188A768A7B1A36877
+:1046C000013BA36063695A1C62611D70D4E9043226
+:1046D0009A4224BFE3686361E3690BB120469847BF
+:1046E000002080F3118807E03146204600F026FEC6
+:1046F0000028E2DA87F31188F8BD0000D0E905232D
+:1047000010B59A4201D182687AB9826800210132DB
+:1047100082605A1C82611C7803699A4224BFC36874
+:10472000836100F01BFE204610BD4FF0FF30FBE719
+:104730002DE9F74F04460E4617469846D0F81C90D0
+:104740004FF0300A8AF311884FF0000B154665B11F
+:104750002A4631462046FFF7EFFE034660B9414640
+:10476000204600F0EBFD0028F1D0002383F31188F0
+:10477000781B03B0BDE8F08FB9F1000F03D00190B2
+:104780002046C847019B8BF31188ED1A1E448AF31B
+:104790001188DCE7026843681143016003B11847E0
+:1047A000704700001430FFF743BF00004FF0FF33A5
+:1047B0001430FFF73DBF00003830FFF7B9BF0000ED
+:1047C0004FF0FF333830FFF7B3BF00001430FFF76E
+:1047D00009BF00004FF0FF311430FFF703BF0000A6
+:1047E0003830FFF763BF00004FF0FF323830FFF77B
+:1047F0005DBF0000012914BF6FF013000020704757
+:10480000FFF75ABD044B036000234360C0E9023345
+:1048100001230374704700BF4877000810B53023A8
+:10482000044683F31188FFF771FD022300202374EF
+:1048300080F3118810BD000038B5C36904460D46E9
+:104840001BB904210844FFF7A5FF294604F1140011
+:10485000FFF7ACFE002806DA201D4FF40061BDE82A
+:104860003840FFF797BF38BD0268436811430160C5
+:1048700003B118477047000013B5406B00F5805432
+:10488000D4F8A4381A681178042914D1017C0229BB
+:1048900011D11979012312898B4013420BD101A93F
+:1048A0004C3002F02BF9D4F8A4480246019B217940
+:1048B000206800F0DFF902B010BD0000143002F0F3
+:1048C000ADB800004FF0FF33143002F0A7B800007D
+:1048D0004C3002F07FB900004FF0FF334C3002F053
+:1048E00079B90000143002F07BB800004FF0FF31BE
+:1048F000143002F075B800004C3002F04BB90000E3
+:104900004FF0FF324C3002F045B9000000207047F4
+:1049100010B500F58054D4F8A4381A681178042929
+:1049200017D1017C022914D15979012352898B4076
+:1049300013420ED1143002F00DF8024648B1D4F8FB
+:10494000A4484FF4407361792068BDE8104000F03E
+:104950007FB910BD406BFFF7DBBF00007047000060
+:104960007FB5124B0125042604460360002305741D
+:1049700000F1840243602946C0E902330C4B0290E7
+:10498000143001934FF44073009601F0BFFF094BC0
+:1049900004F69442294604F14C000294CDE90063E8
+:1049A0004FF4407302F086F804B070BD70770008D1
+:1049B00055490008794800080A68302383F31188B4
+:1049C0000B790B3342F823004B79133342F8230061
+:1049D0008B7913B10B3342F8230000F58053C3F8F1
+:1049E000A41802230374002080F31188704700008C
+:1049F00038B5037F044613B190F85430ABB90125A4
+:104A0000201D0221FFF730FF04F114006FF00101B7
+:104A1000257700F0AFFC04F14C0084F854506FF09F
+:104A20000101BDE8384000F0A5BC38BD10B501213A
+:104A300004460430FFF718FF0023237784F854302E
+:104A400010BD000038B504460025143001F076FF93
+:104A500004F14C00257702F045F8201D84F85450ED
+:104A60000121FFF701FF2046BDE83840FFF750BFA6
+:104A700090F8803003F06003202B06D190F881205D
+:104A80000023212A03D81F2A06D800207047222A93
+:104A9000FBD1C0E91D3303E0034A42670722826766
+:104AA000C3670120704700BF3C22002037B500F5E6
+:104AB0008055D5F8A4381A68117804291AD1017CD8
+:104AC000022917D11979012312898B40134211D180
+:104AD00000F14C04204602F0C5F858B101A9204667
+:104AE00002F00CF8D5F8A4480246019B2179206811
+:104AF00000F0C0F803B030BD01F10B03F0B550F881
+:104B0000236085B004460D46FEB1302383F311883F
+:104B100004EB8507301D0821FFF7A6FEFB6806F1B0
+:104B20004C005B691B681BB1019001F0F5FF019817
+:104B300003A901F0E3FF024648B1039B2946204642
+:104B400000F098F8002383F3118805B0F0BDFB68EE
+:104B50005A691268002AF5D01B8A013B1340F1D133
+:104B600004F18002EAE70000133138B550F8214023
+:104B7000ECB1302383F3118804F58053D3F8A428D3
+:104B80001368527903EB8203DB689B695D6845B16A
+:104B900004216018FFF768FE294604F1140001F0B3
+:104BA000E3FE2046FFF7B4FE002383F3118838BDEF
+:104BB0007047000001F0B6B901234022002110B572
+:104BC000044600F8303BFCF7B7FF0023C4E901338B
+:104BD00010BD000010B53023044683F31188242251
+:104BE000416000210C30FCF7A7FF204601F0BCF922
+:104BF00002230020237080F3118810BD70B500EBF4
+:104C00008103054650690E461446DA6018B1102239
+:104C10000021FCF791FFA06918B110220021FCF7D8
+:104C20008BFF31462846BDE8704001F09DBA000078
+:104C300083682022002103F0011310B5044683602D
+:104C40001030FCF779FF2046BDE8104001F018BB9A
+:104C5000F0B4012500EB810447898D40E4683D43B1
+:104C6000A469458123600023A2606360F0BC01F069
+:104C700035BB0000F0B4012500EB810407898D40AD
+:104C8000E4683D436469058123600023A26063609A
+:104C9000F0BC01F0ABBB000070B502230025044658
+:104CA000242203702946C0F888500C3040F8045C78
+:104CB000FCF742FF204684F8705001F0E9F9636880
+:104CC0001B6823B129462046BDE87040184770BDD7
+:104CD0000378052B10B504460AD080F88C300523E4
+:104CE000037043681B680BB1042198470023A3603D
+:104CF00010BD00000178052906D190F88C2043688A
+:104D000002701B6803B118477047000070B590F837
+:104D10007030044613B1002380F8703004F1800233
+:104D2000204601F0D1FA63689B68B3B994F88030EB
+:104D300013F0600535D00021204601F0C3FD0021AD
+:104D4000204601F0B3FD63681B6813B106212046BD
+:104D50009847062384F8703070BD20469847002895
+:104D6000E4D0B4F88630A26F9A4288BFA36794F962
+:104D70008030A56F002B4FF0300380F20381002DAF
+:104D800000F0F280092284F8702083F3118800215A
+:104D90002046D4E91D23FFF76DFF002383F311881C
+:104DA000DAE794F8812003F07F0343EA022340F21C
+:104DB0000232934200F0C58021D8B3F5807F48D0FD
+:104DC0000DD8012B3FD0022B00F09380002BB2D1E5
+:104DD00004F1880262670222A267E367C1E7B3F5C4
+:104DE000817F00F09B80B3F5407FA4D194F882309E
+:104DF000012BA0D1B4F8883043F0020332E0B3F5C0
+:104E0000006F4DD017D8B3F5A06F31D0A3F5C063B4
+:104E1000012B90D86368204694F882205E6894F84D
+:104E20008310B4F88430B047002884D043686367A7
+:104E30000368A3671AE0B3F5106F36D040F602425C
+:104E400093427FF478AF5C4B63670223A367002330
+:104E5000C3E794F88230012B7FF46DAFB4F888304B
+:104E600023F00203A4F88830C4E91D55E56778E70C
+:104E7000B4F88030B3F5A06F0ED194F8823020469C
+:104E800084F88A3001F062F963681B6813B101216C
+:104E900020469847032323700023C4E91D339CE771
+:104EA00004F18B0363670123C3E72378042B10D13C
+:104EB000302383F311882046FFF7BAFE85F311886B
+:104EC0000321636884F88B5021701B680BB1204666
+:104ED000984794F88230002BDED084F88B3004237E
+:104EE000237063681B68002BD6D0022120469847A8
+:104EF000D2E794F8843020461D0603F00F010AD54E
+:104F000001F0D4F9012804D002287FF414AF2B4B10
+:104F10009AE72B4B98E701F0BBF9F3E794F882305E
+:104F2000002B7FF408AF94F8843013F00F01B3D056
+:104F30001A06204602D501F0DDFCADE701F0CEFCFB
+:104F4000AAE794F88230002B7FF4F5AE94F8843011
+:104F500013F00F01A0D01B06204602D501F0B2FCD1
+:104F60009AE701F0A3FC97E7142284F8702083F3FA
+:104F700011882B462A4629462046FFF769FE85F30D
+:104F80001188E9E65DB1152284F8702083F3118859
+:104F900000212046D4E91D23FFF75AFEFDE60B222F
+:104FA00084F8702083F311882B462A462946204630
+:104FB000FFF760FEE3E700BFA077000898770008DE
+:104FC0009C77000838B590F870300446002B3ED02E
+:104FD000063BDAB20F2A34D80F2B32D8DFE803F0C1
+:104FE00037313108223231313131313131313737D6
+:104FF000856FB0F886309D4214D2C3681B8AB5FB1A
+:10500000F3F203FB12556DB9302383F311882B465D
+:105010002A462946FFF72EFE85F311880A2384F8D5
+:1050200070300EE0142384F87030302383F311883D
+:10503000002320461A461946FFF70AFE002383F391
+:10504000118838BDC36F03B198470023E7E70021FB
+:10505000204601F037FC0021204601F027FC636860
+:105060001B6813B10621204698470623D7E70000A6
+:1050700010B590F870300446142B29D017D8062BA1
+:1050800005D001D81BB110BD093B022BFBD8002174
+:10509000204601F017FC0021204601F007FC636860
+:1050A0001B6813B1062120469847062319E0152BEB
+:1050B000E9D10B2380F87030302383F3118800236B
+:1050C0001A461946FFF7D6FD002383F31188DAE765
+:1050D000C3689B695B68002BD5D1C36F03B1984748
+:1050E000002384F87030CEE70023826803750369DB
+:1050F0001B6899689142FBD25A6803604260106055
+:105100005860704700238268037503691B689968BB
+:105110009142FBD85A680360426010605860704743
+:1051200008B50846302383F311880B7D032B05D087
+:10513000042B0DD02BB983F3118808BD8B69002295
+:105140001A604FF0FF338361FFF7CEFF0023F2E7D1
+:10515000D1E9003213605A60F3E70000FFF7C4BFE3
+:10516000054BD96808751868026853601A600122F7
+:10517000D8600275FBF7D0BA506300200C4B30B5F5
+:10518000DD684B1C87B004460FD02B46094A6846A1
+:1051900000F084F92046FFF7E3FF009B13B1684657
+:1051A00000F086F9A86907B030BDFFF7D9FFF9E72D
+:1051B0005063002021510008044B1A68DB68906896
+:1051C0009B68984294BF00200120704750630020E4
+:1051D000084B10B51C68D868226853601A60012219
+:1051E000DC602275FFF78EFF01462046BDE81040C7
+:1051F000FBF792BA50630020044B1A68DB68926890
+:105200009B689A4201D9FFF7E3BF704750630020C3
+:1052100038B5074C0123002506490748237065600F
+:1052200001F05EFD0223237085F3118838BD00BFB5
+:10523000B8650020A87700085063002008B572B652
+:10524000044B186500F07AFC00F05CFD024B032271
+:105250001A70FEE750630020B865002000F05EB9C8
+:10526000EFF3118020B9EFF30583302282F3118828
+:105270007047000010B530B9EFF30584C4F308049B
+:1052800014B180F3118810BDFFF7B6FF84F31188C5
+:10529000F9E70000034A516853685B1A9842FBD84B
+:1052A000704700BF001000E08B60022308610846D1
+:1052B0008B8270478368A3F1840243F8142C02693F
+:1052C00043F8442C426943F8402C094A43F8242C03
+:1052D000C268A3F1200043F8182C022203F80C2C1A
+:1052E000002203F80B2C034A43F8102C704700BF30
+:1052F000310700085063002008B5FFF7DBFFBDE869
+:105300000840FFF72BBF0000024BDB6898610F20BD
+:10531000FFF726BF50630020302383F31188FFF787
+:10532000F3BF000008B50146302383F3118808203D
+:10533000FFF724FF002383F3118808BD064BDB68C9
+:1053400039B1426818605A60136043600420FFF767
+:1053500015BF4FF0FF30704750630020036898423C
+:1053600006D01A680260506018469961FFF7F6BED1
+:105370007047000038B504460D462068844200D1CD
+:1053800038BD036823605C608561FFF7E7FEF4E7E2
+:10539000036810B59C68A2420CD85C688A600B60F8
+:1053A0004C602160596099688A1A9A604FF0FF3307
+:1053B000836010BD121B1B68ECE700000A2938BF90
+:1053C0000A2170B504460D460A26601901F080FCDA
+:1053D00001F068FC041BA54203D8751C04462E4648
+:1053E000F3E70A2E04D90120BDE8704001F0B8BCF3
+:1053F00070BD0000F8B5144B0D460A2A4FF00A079D
+:10540000D96103F11001826038BF0A224160196935
+:105410001446016048601861A81801F049FC01F0C9
+:1054200041FC431B0646A34206D37C1C2819274691
+:10543000354601F04DFCF2E70A2F04D90120BDE802
+:10544000F84001F08DBCF8BD50630020F8B5064669
+:105450000D4601F027FC0F4A134653F8107F9F4278
+:1054600006D12A4601463046BDE8F840FFF7C2BFE4
+:10547000D169BB68441A2C1928BF2C46A34202D913
+:105480002946FFF79BFF224631460348BDE8F84016
+:10549000FFF77EBF5063002060630020C0E9032354
+:1054A000002310B45DF8044B4361FFF7CFBF000049
+:1054B00010B5194C236998420DD08168D0E90032AB
+:1054C00013605A609A680A449A60002303604FF0A0
+:1054D000FF33A36110BD0268234643F8102F5360C9
+:1054E0000022026022699A4203D1BDE8104001F017
+:1054F000E9BB936881680B44936001F0D3FB226998
+:10550000E1699268441AA242E4D91144BDE810400E
+:10551000091AFFF753BF00BF506300202DE9F04781
+:10552000DFF8BC8008F110072C4ED8F8105001F0BD
+:10553000B9FBD8F81C40AA68031B9A423ED8144411
+:105540004FF00009D5E90032C8F81C4013605A60DA
+:10555000C5F80090D8F81030B34201D101F0B2FB89
+:1055600089F31188D5E9033128469847302383F31E
+:1055700011886B69002BD8D001F094FB6A69A0EB0D
+:10558000040982464A450DD2022001F0E9FB0022BF
+:10559000D8F81030B34208D151462846BDE8F0474C
+:1055A000FFF728BF121A2244F2E712EB0909294635
+:1055B000384638BF4A46FFF7EBFEB5E7D8F810305B
+:1055C000B34208D01444C8F81C00211AA960BDE8F1
+:1055D000F047FFF7F3BEBDE8F08700BF606300202F
+:1055E0005063002000207047FEE700007047000075
+:1055F0004FF0FF307047000002290CD0032904D07F
+:105600000129074818BF00207047032A05D805481C
+:1056100000EBC2007047044870470020704700BF8D
+:10562000807800084C2200203478000870B59AB0C9
+:1056300005460846144601A900F0C2F801A8FCF787
+:1056400073FA431C0022C6B25B001046C5E9003461
+:1056500023700323023404F8013C01ABD1B20234BD
+:105660008E4201D81AB070BD13F8011B013204F844
+:10567000010C04F8021CF1E708B5302383F311880C
+:105680000348FFF713FA002383F3118808BD00BF16
+:10569000C065002090F8803003F01F02012A07D176
+:1056A00090F881200B2A03D10023C0E91D3315E0B7
+:1056B00003F06003202B08D1B0F884302BB990F8A8
+:1056C0008120212A03D81F2A04D8FFF7D1B9222A22
+:1056D000EBD0FAE7034A426707228267C3670120DB
+:1056E000704700BF4322002007B5052917D8DFE81F
+:1056F00001F0191603191920302383F31188104A79
+:1057000001210190FFF77AFA019802210D4AFFF773
+:1057100075FA0D48FFF796F9002383F3118803B05B
+:105720005DF804FB302383F311880748FFF760F925
+:10573000F2E7302383F311880348FFF777F9EBE7AB
+:10574000D4770008F8770008C065002038B50C4D04
+:105750000C4C2A460C4904F10800FFF767FF05F1DD
+:10576000CA0204F110000949FFF760FF05F5CA728B
+:1057700004F118000649BDE83840FFF757BF00BFE5
+:10578000987E00204C220020B4770008BE770008E5
+:10579000C977000870B5044608460D46FCF7C4F901
+:1057A000C6B22046013403780BB9184670BD3246A4
+:1057B0002946FCF7A5F90028F3D10120F6E70000FF
+:1057C0002DE9F04705460C46FCF7AEF92A49C6B26A
+:1057D0002846FFF7DFFF08B10936F6B22749284609
+:1057E000FFF7D8FF08B11036F6B2632E0BD8DFF8FA
+:1057F0008880DFF88890224FDFF890A02E7846B995
+:105800002670BDE8F08729462046BDE8F04701F044
+:10581000F3BE252E2CD1072241462846FCF770F90D
+:1058200060B9184B224603F1100153F8040B8B4268
+:1058300042F8040BF9D107351034DFE70822494656
+:105840002846FCF75DF998B9A21C0F4B1978023273
+:105850000909C95D02F8041C13F8011B01F00F01CE
+:105860005345C95D02F8031CF0D118340835C5E76B
+:10587000013504F8016BC1E7A0780008C97700087A
+:10588000B9780008A878000800E8F11F0CE8F11FBB
+:10589000BFF34F8F044B1A695107FCD1D3F8102185
+:1058A0005207F8D1704700BF0020005208B50D4BD9
+:1058B0001B78ABB9FFF7ECFF0B4BDA68D10704D5C7
+:1058C0000A4A5A6002F188325A60D3F80C21D20792
+:1058D00006D5064AC3F8042102F18832C3F8042130
+:1058E00008BD00BFF680002000200052230167455C
+:1058F00008B5114B1B78F3B9104B1A69510703D542
+:10590000DA6842F04002DA60D3F81021520705D578
+:10591000D3F80C2142F04002C3F80C21FFF7B8FF86
+:10592000064BDA6842F00102DA60D3F80C2142F04B
+:105930000102C3F80C2108BDF680002000200052AF
+:105940000F289ABF00F580604004002070470000D7
+:105950004FF4003070470000102070470F2808B542
+:105960000BD8FFF7EDFF00F500330268013204D1D8
+:1059700004308342F9D1012008BD0020FCE700007B
+:105980000F2870B5054645D8FFF76AFC224CFFF793
+:105990007FFF0646FFF78AFF4FF0FF33072D636155
+:1059A000C4F8143120D82361FFF772FF2B0243F0B3
+:1059B0002403E360E36843F08003E36023695A074C
+:1059C000FCD42846FFF764FF4FF40031FFF7B8FF1F
+:1059D00000F074F93046FFF78BFFFFF74BFC2846C9
+:1059E000BDE87040FFF7BABFC4F81031FFF750FFB1
+:1059F000A5F108031B0243F02403C4F80C31D4F8CA
+:105A00000C3143F08003C4F80C31D4F810315B073B
+:105A1000FBD4D6E7002070BD002000522DE9F84FDE
+:105A200040EA020305460C461746D80602D000207D
+:105A3000BDE8F88F27F01F07DFF8D4B0FFF736FF77
+:105A40002744BC4203D10120FFF752FFF0E7202298
+:105A50002946204601F052FD10B920352034F0E7E8
+:105A60002B4605F120021E68711CE0D104339A42D6
+:105A7000F9D1FFF7F5FB05F17843234AB3F5801F11
+:105A8000224B28BF9A4603F1040338BF9046A2F187
+:105A9000080228BF9846A3F108033ABF9146DA46A8
+:105AA0009946FFF7F5FEC8F80060A5EB040CD9F89D
+:105AB000002004F11C0142F00202C9F80020221F5C
+:105AC000DAF8006016F00506FAD152F8043F8A426F
+:105AD0004CF80230F4D1BFF34F8FFFF7D9FE4FF0EF
+:105AE000FF32C8F80020D9F8002022F00202C9F8DD
+:105AF0000020FFF7BFFB20222146284601F0FEFCD4
+:105B00000028AAD030469FE71420005210210052EE
+:105B10001020005210B5084C237828B11BB9FFF7AC
+:105B2000C5FE0123237010BD002BFCD02070BDE802
+:105B30001040FFF7DDBE00BFF680002008B54FF42F
+:105B400000314FF0005000F0CBF800210B4800F07E
+:105B5000C7F84FF400214FF0105000F0C1F84FF497
+:105B60007C414FF4806000F0BBF84FF480314FF07F
+:105B70006050BDE8084000F0B3B800BF000100303D
+:105B800070B5104E82B0FFF76BFB054601F08AF846
+:105B9000326803469042336037BF0B4A0A49516866
+:105BA000146836BF0131D1E900415160041928461B
+:105BB00041F100010191FFF75DFB2046019902B020
+:105BC00070BD00BFF88000200081002070B5124E2B
+:105BD00082B0FFF745FB054601F064F832680346E2
+:105BE0009042336037BF0D4A0C495168146836BF84
+:105BF0000131D1E9004151600419284641F1000109
+:105C00000191FFF737FB4FF47A7200232046019988
+:105C1000FAF76EFB02B070BDF88000200081002012
+:105C20000244074BD2B210B5904200D110BD441CC3
+:105C300000B253F8200041F8040BE0B2F4E700BFD3
+:105C4000504000580E4B30B51C6F240405D41C6F17
+:105C50001C671C6F44F400441C670A4C0244236810
+:105C6000D2B243F480732360074B904200D130BD21
+:105C7000441C51F8045B00B243F82050E0B2F4E752
+:105C800000440258004802585040005807B501220D
+:105C900001A90020FFF7C4FF019803B05DF804FBE1
+:105CA00013B50446FFF7F2FFA04205D0012201A977
+:105CB00000200194FFF7C6FF02B010BD0144BFF3FE
+:105CC0004F8F064B884204D3BFF34F8FBFF36F8FC4
+:105CD0007047C3F85C022030F4E700BF00ED00E03D
+:105CE0000144BFF34F8F064B884204D3BFF34F8F5D
+:105CF000BFF36F8F7047C3F870022030F4E700BF26
+:105D000000ED00E070470000074B45F255521A6065
+:105D100002225A6040F6FF729A604CF6CC421A603A
+:105D20000122024B1A707047004800580C81002075
+:105D3000034B1B781BB1034B4AF6AA221A6070472B
+:105D40000C81002000480058034B1A681AB9034A16
+:105D5000D2F8D0241A607047088100200040025811
+:105D6000024B4FF48032C3F8D024704700400258F1
+:105D700008B5FFF7E9FF024B1868C0F3806008BD63
+:105D80000881002070B5BFF34F8FBFF36F8F1A4AA1
+:105D90000021C2F85012BFF34F8FBFF36F8F5369CA
+:105DA00043F400335361BFF34F8FBFF36F8FC2F8DB
+:105DB0008410BFF34F8FD2F8803043F6E074C3F302
+:105DC000C900C3F34E335B0103EA0406014646EA09
+:105DD00081750139C2F86052F9D2203B13F1200FCE
+:105DE000F2D1BFF34F8F536943F480335361BFF354
+:105DF0004F8FBFF36F8F70BD00ED00E0FEE7000036
+:105E0000214B2248224A70B5904237D3214BC11E04
+:105E1000DA1C121A22F003028B4238BF0022002142
+:105E2000FBF78AFE1C4A0023C2F88430BFF34F8F71
+:105E3000D2F8803043F6E074C3F3C900C3F34E33A5
+:105E40005B0103EA0406014646EA81750139C2F89E
+:105E50006C52F9D2203B13F1200FF2D1BFF34F8FD8
+:105E6000BFF36F8FBFF34F8FBFF36F8F0023C2F865
+:105E70005032BFF34F8FBFF36F8F70BD53F8041BC9
+:105E800040F8041BC0E700BF207B0008E882002028
+:105E9000E8820020E882002000ED00E0054B996BCD
+:105EA00021EA000199631A6E22EA00021A661B6E4B
+:105EB000704700BF0045025870B5D0E92443002266
+:105EC0004FF0FF359E6804EB42135101D3F80009EF
+:105ED000002805DAD3F8000940F08040C3F8000933
+:105EE000D3F8000B002805DAD3F8000B40F080400F
+:105EF000C3F8000B013263189642C3F80859C3F87F
+:105F0000085BE0D24FF00113C4F81C3870BD0000EC
+:105F1000890141F02001016103699B06FCD4122034
+:105F2000FFF7B8B910B50A4C2046FEF745FE094BFD
+:105F3000C4F89030084BC4F89430084C2046FEF763
+:105F40003BFE074BC4F89030064BC4F8943010BDAC
+:105F50001081002000000840F0780008AC8100208B
+:105F600000000440FC78000870B503780546012B5A
+:105F700058D13F4BD0F89040984254D13D4B0E2120
+:105F800065209A6B42F000629A631A6E42F00062DA
+:105F90001A661B6E384BD3F8802042F00062C3F8BB
+:105FA0008020D3F8802022F00062C3F88020D3F84C
+:105FB0008030FEF77DFA314BE360314BC4F8003896
+:105FC0000023D5F89060C4F8003EC02323604FF44E
+:105FD0000413A3633369002BFCDA01230C20336123
+:105FE000FFF758F93369DB07FCD41220FFF752F9A9
+:105FF0003369002BFCDA00262846A660FFF75CFF19
+:106000006B68C4F81068DB68C4F81468C4F81C68CE
+:1060100063BB1C4BA3614FF0FF336361A36843F084
+:106020000103A36070BD184B9842C9D1114B4FF0CA
+:1060300080609A6B42F000729A631A6E42F00072AE
+:106040001A661B6E0C4BD3F8802042F00072C3F826
+:106050008020D3F8802022F00072C3F88020D3F88B
+:106060008030FFF71BFF0E214D20A2E7074BD1E741
+:10607000108100200045025800440258401400409E
+:1060800003002002003C30C0AC810020083C30C03E
+:10609000F8B5D0F89040054600214FF00066204644
+:1060A000FFF736FFD5F8941000234FF001128F68E8
+:1060B0004FF0FF30C4F83438C4F81C2804EB431206
+:1060C00001339F42C2F80069C2F8006BC2F80809A8
+:1060D000C2F8080BF2D20B68D5F89020C5F89830BA
+:1060E000636210231361166916F01006FBD11220AB
+:1060F000FFF7D0F8D4F8003823F4FE63C4F8003872
+:10610000A36943F4402343F01003A3610923C4F8B7
+:106110001038C4F814380B4BEB604FF0C043C4F890
+:10612000103B094BC4F8003BC4F81069C4F80039AF
+:10613000D5F8983003F1100243F48013C5F8982085
+:10614000A362F8BDCC78000840800010D0F8902001
+:1061500090F88A10D2F8003823F4FE6343EA011362
+:10616000C2F80038704700002DE9F84300EB8103C6
+:10617000D0F890500C468046DA680FFA81F9480151
+:10618000166806F00306731E022B05EB41134FF051
+:10619000000194BFB604384EC3F8101B4FF0010144
+:1061A00004F1100398BF06F1805601FA03F39169D8
+:1061B00098BF06F5004600293AD0578A04F15801E5
+:1061C000374349016F50D5F81C180B430021C5F81F
+:1061D0001C382B180127C3F81019A7405369611EFA
+:1061E0009BB3138A928B9B08012A88BF5343D8F82C
+:1061F0009820981842EA034301F140022146C8F86A
+:106200009800284605EB82025360FFF781FE08EBF9
+:106210008900C3681B8A43EA845348341E436401DF
+:106220002E51D5F81C381F43C5F81C78BDE8F883FB
+:1062300005EB4917D7F8001B21F40041C7F8001BF4
+:10624000D5F81C1821EA0303C0E704F13F030B4A09
+:106250002846214605EB83035A60FFF759FE05EBFC
+:106260004910D0F8003923F40043C0F80039D5F8BC
+:106270001C3823EA0707D7E700800010000400025B
+:10628000D0F894201268C0F89820FFF715BE0000DF
+:106290005831D0F8903049015B5813F4004004D0D5
+:1062A00013F4001F0CBF0220012070474831D0F8C2
+:1062B000903049015B5813F4004004D013F4001FE0
+:1062C0000CBF02200120704700EB8101CB68196AE6
+:1062D0000B6813604B6853607047000000EB81034C
+:1062E00030B5DD68AA691368D36019B9402B84BF43
+:1062F000402313606B8A1468D0F890201C4402EB92
+:106300004110013C09B2B4FBF3F46343033323F0BF
+:10631000030343EAC44343F0C043C0F8103B2B6877
+:1063200003F00303012B0ED1D2F8083802EB411021
+:1063300013F4807FD0F8003B14BF43F0805343F048
+:106340000053C0F8003B02EB4112D2F8003B43F08F
+:106350000443C2F8003B30BD2DE9F041D0F8906015
+:1063600005460C4606EB4113D3F8087B3A07C3F801
+:10637000087B08D5D6F814381B0704D500EB810339
+:10638000DB685B689847FA071FD5D6F81438DB0737
+:106390001BD505EB8403D968CCB98B69488A5A6848
+:1063A000B2FBF0F600FB16228AB91868DA68904250
+:1063B0000DD2121AC3E90024302383F31188214639
+:1063C0002846FFF78BFF84F31188BDE8F081012395
+:1063D00003FA04F26B8923EA02036B81CB68002B7A
+:1063E000F3D021462846BDE8F041184700EB810371
+:1063F0004A0170B5DD68D0F890306C692668E660B7
+:1064000056BB1A444FF40020C2F810092A6802F063
+:106410000302012A0AB20ED1D3F8080803EB421492
+:1064200010F4807FD4F8000914BF40F0805040F091
+:106430000050C4F8000903EB4212D2F8000940F002
+:106440000440C2F800090122D3F8340802FA01F12D
+:106450000143C3F8341870BD19B9402E84BF4020E1
+:10646000206020681A442E8A8419013CB4FBF6F49B
+:1064700040EAC44040F00050C6E700002DE9F84370
+:10648000D0F8906005460C464F0106EB4113D3F857
+:10649000088918F0010FC3F808891CD0D6F8103805
+:1064A000DB0718D500EB8103D3F80CC0DCF81430FF
+:1064B000D3F800E0DA68964530D2A2EB0E024FF036
+:1064C00000091A60C3F80490302383F31188FFF7A2
+:1064D0008DFF89F3118818F0800F1DD0D6F834385D
+:1064E0000126A640334217D005EB84030134D5F8CA
+:1064F0009050D3F80CC0E4B22F44DCF8142005EB24
+:106500000434D2F800E05168714514D3D5F834381A
+:1065100023EA0606C5F83468BDE8F883012303FAC8
+:1065200001F2038923EA02030381DCF80830002B1F
+:10653000D1D09847CFE7AEEB0103BCF810008342FF
+:1065400028BF0346D7F8180980B2B3EB800FE3D811
+:106550009068A0F1040959F8048FC4F80080A0EBFA
+:1065600009089844B8F1040FF5D818440B4490601A
+:106570005360C8E72DE9F84FD0F8905004466E6993
+:10658000AB691E4016F480586E6103D0BDE8F84F29
+:10659000FEF782BB002E12DAD5F8003E9B0705D02D
+:1065A000D5F8003E23F00303C5F8003ED5F80438C3
+:1065B000204623F00103C5F80438FEF79BFB37059E
+:1065C00005D52046FFF778FC2046FEF781FBB00496
+:1065D0000CD5D5F8083813F0060FEB6823F4705388
+:1065E0000CBF43F4105343F4A053EB6031071BD5A9
+:1065F0006368DB681BB9AB6923F00803AB612378E0
+:10660000052B0CD1D5F8003E9A0705D0D5F8003EF1
+:1066100023F00303C5F8003E2046FEF76BFB6368DA
+:10662000DB680BB120469847F30200F1BA80B7024D
+:1066300026D5D4F8909000274FF0010A09EB4712B5
+:10664000D2F8003B03F44023B3F5802F11D1D2F8E8
+:10665000003B002B0DDA62890AFA07F322EA0303F2
+:10666000638104EB8703DB68DB6813B1394620469E
+:1066700098470137D4F89430FFB29B689F42DDD928
+:10668000F00619D5D4F89000026AC2F30A1702F096
+:106690000F0302F4F012B2F5802F00F0CA80B2F5B9
+:1066A000402F09D104EB8303002200F58050DB6802
+:1066B0001B6A974240F0B0803003D5F8185835D5A2
+:1066C000E90303D500212046FFF746FEAA0303D5C0
+:1066D00001212046FFF740FE6B0303D5022120462F
+:1066E000FFF73AFE2F0303D503212046FFF734FEC0
+:1066F000E80203D504212046FFF72EFEA90203D5A8
+:1067000005212046FFF728FE6A0203D50621204610
+:10671000FFF722FE2B0203D507212046FFF71CFEC0
+:10672000EF0103D508212046FFF716FE700340F164
+:10673000A780E90703D500212046FFF79FFEAA079F
+:1067400003D501212046FFF799FE6B0703D50221EF
+:106750002046FFF793FE2F0703D503212046FFF7BE
+:106760008DFEEE0603D504212046FFF787FEA8061E
+:1067700003D505212046FFF781FE690603D50621D2
+:106780002046FFF77BFE2A0603D507212046FFF7A8
+:1067900075FEEB0574D520460821BDE8F84FFFF7DC
+:1067A0006DBED4F890904FF0000B4FF0010AD4F872
+:1067B00094305FFA8BF79B689F423FF638AF09EB46
+:1067C0004713D3F8002902F44022B2F5802F20D1DC
+:1067D000D3F80029002A1CDAD3F8002942F09042AD
+:1067E000C3F80029D3F80029002AFBDB3946D4F886
+:1067F0009000FFF78DFB22890AFA07F322EA0303D0
+:10680000238104EB8703DB689B6813B1394620467C
+:1068100098470BF1010BCAE7910701D1D0F800802E
+:10682000072A02F101029CBF03F8018B4FEA1828E6
+:106830003FE704EB830300F58050DA68D2F818C014
+:10684000DCF80820DCE9001CA1EB0C0C00218F42D5
+:1068500008D1DB689B699A683A449A605A683A445E
+:106860005A6029E711F0030F01D1D0F800808C4560
+:1068700001F1010184BF02F8018B4FEA1828E6E715
+:10688000BDE8F88F08B50348FFF774FEBDE808407F
+:10689000FDF7D8BC1081002008B50348FFF76AFE59
+:1068A000BDE80840FDF7CEBCAC810020D0F89030A8
+:1068B00003EB4111D1F8003B43F40013C1F8003B56
+:1068C00070470000D0F8903003EB4111D1F8003947
+:1068D00043F40013C1F8003970470000D0F890303D
+:1068E00003EB4111D1F8003B23F40013C1F8003B46
+:1068F00070470000D0F8903003EB4111D1F8003917
+:1069000023F40013C1F800397047000030B5043398
+:10691000039C0172002104FB0325C160C0E90653FA
+:10692000049B0363059BC0E90000C0E90422C0E9A1
+:106930000842C0E90A11436330BD00000022416AE9
+:10694000C260C0E90411C0E90A226FF00101FEF73C
+:1069500011BD0000D0E90432934201D1C2680AB9E6
+:10696000181D704700207047036919600021C26834
+:106970000132C260C269134482699342036124BF39
+:10698000436A0361FEF7EABC38B504460D46E36886
+:106990003BB162690020131D1268A3621344E362D5
+:1069A00007E0237A33B929462046FEF7C7FC0028C2
+:1069B000EDDA38BD6FF00100FBE70000C368C26983
+:1069C000013BC3604369134482699342436124BF1E
+:1069D000436A436100238362036B03B11847704726
+:1069E00070B53023044683F31188866A3EB9FFF7F9
+:1069F000CBFF054618B186F31188284670BDA36AFF
+:106A0000E26A13F8015B9342A36202D32046FFF7C8
+:106A1000D5FF002383F31188EFE700002DE9F84F3D
+:106A200004460E46174698464FF0300989F3118800
+:106A30000025AA46D4F828B0BBF1000F09D1414681
+:106A40002046FFF7A1FF20B18BF311882846BDE84F
+:106A5000F88FD4E90A12A7EB050B521A934528BF09
+:106A60009346BBF1400F1BD9334601F1400251F868
+:106A7000040B914243F8040BF9D1A36A4036403528
+:106A80004033A362D4E90A239A4202D32046FFF797
+:106A900095FF8AF31188BD42D8D289F31188C9E7DE
+:106AA00030465A46FBF722F8A36A5E445D445B44D5
+:106AB000A362E7E710B5029C0433017203FB0421D3
+:106AC000C460C0E906130023C0E90A33039B0363D3
+:106AD000049BC0E90000C0E90422C0E90842436306
+:106AE00010BD0000026A6FF00101C260426AC0E995
+:106AF00004220022C0E90A22FEF73CBCD0E90423AC
+:106B00009A4201D1C26822B9184650F8043B0B6082
+:106B1000704700231846FAE7C3680021C2690133B1
+:106B2000C3604369134482699342436124BF436A4B
+:106B30004361FEF713BC000038B504460D46E36818
+:106B40003BB1236900201A1DA262E2691344E3628B
+:106B500007E0237A33B929462046FEF7EFFB0028E9
+:106B6000EDDA38BD6FF00100FBE700000369196042
+:106B7000C268013AC260C2691344826993420361E8
+:106B800024BF436A036100238362036B03B1184788
+:106B90007047000070B530230D460446114683F35C
+:106BA0001188866A2EB9FFF7C7FF10B186F31188E6
+:106BB00070BDA36A1D70A36AE26A01339342A362A7
+:106BC00004D3E16920460439FFF7D0FF002080F3A9
+:106BD0001188EDE72DE9F84F04460D469046994699
+:106BE0004FF0300A8AF311880026B346A76A4FB9DE
+:106BF00049462046FFF7A0FF20B187F311883046B1
+:106C0000BDE8F88FD4E90A073A1AA8EB06079742BD
+:106C100028BF1746402F1BD905F1400355F8042B18
+:106C20009D4240F8042BF9D1A36A40364033A36259
+:106C3000D4E90A239A4204D3E16920460439FFF7D4
+:106C400095FF8BF311884645D9D28AF31188CDE799
+:106C500029463A46FAF74AFFA36A3D443E443B447C
+:106C6000A362E5E7D0E904239A4217D1C3689BB138
+:106C7000836A8BB1043B9B1A0ED01360C368013B3F
+:106C8000C360C3691A4483699A42026124BF436A9C
+:106C90000361002383620123184670470023FBE74A
+:106CA00000F01CB9014B586A704700BF000C00404F
+:106CB000034B002258631A610222DA60704700BF5A
+:106CC000000C0040014B0022DA607047000C0040CD
+:106CD000014B5863704700BF000C0040FEE7000006
+:106CE00070B51B4B0025044686B058600E46856281
+:106CF0000163FDF77FFA04F11003A560E562C4E9C2
+:106D000004334FF0FF33C4E90044C4E90635FFF70C
+:106D1000C9FF2B46024604F134012046C4E908238A
+:106D200080230C4A2565FEF7BFFA01230A4AE0607A
+:106D300000920375684672680192B268CDE9022339
+:106D4000064BCDE90435FEF7D7FA06B070BD00BF9B
+:106D5000B8650020087900080D790008DD6C00088E
+:106D6000024AD36A1843D062704700BF50630020C4
+:106D70004B6843608B688360CB68C3600B69436179
+:106D80004B6903628B6943620B68036070470000C4
+:106D900008B53A4B40F2FF713948D3F888200A43CE
+:106DA000C3F88820D3F8882022F4FF6222F007027B
+:106DB000C3F88820D3F88830324B1A6C0A431A641F
+:106DC0009A6E0A439A66304A9B6E1146FFF7D0FFCF
+:106DD00000F5806002F11C01FFF7CAFF00F580603A
+:106DE00002F13801FFF7C4FF00F5806002F15401A1
+:106DF000FFF7BEFF00F5806002F17001FFF7B8FFFA
+:106E000000F5806002F18C01FFF7B2FF00F58060B1
+:106E100002F1A801FFF7ACFF00F5806002F1C401A8
+:106E2000FFF7A6FF00F5806002F1E001FFF7A0FF89
+:106E300000F5806002F1FC01FFF79AFF02F58C710A
+:106E400000F58060FFF794FF00F03CF90F4BD3F89A
+:106E5000902242F00102C3F89022D3F8942242F02B
+:106E60000102C3F894220522C3F898204FF0605223
+:106E7000C3F89C20064AC3F8A02008BD004402586D
+:106E800000000258004502581479000800ED00E0A7
+:106E90001F00080308B500F0F3FAFEF7B9F90C4B30
+:106EA000DA6B42F04002DA635A6E22F040025A6610
+:106EB0005B6E084B1A6842F008021A601A6842F0CA
+:106EC00004021A60FEF740FFBDE80840FEF73EBC32
+:106ED0000045025800180248704700000E4B9A6C9B
+:106EE00042F008029A641A6F42F008021A670B4ACD
+:106EF0001B6FD36B43F00803D363C722084B9A621E
+:106F00004FF0FF32DA6200229A615A63DA605A6007
+:106F100001225A611A607047004502580010005C57
+:106F2000000C0040094A08B51169D3680B40D9B27A
+:106F30009B076FEA0101116107D5302383F31188A4
+:106F4000FEF78CF9002383F3118808BD000C004084
+:106F5000044BDA6B0243DA635A6E104358665B6E79
+:106F6000704700BF00450258524BD3F8802062F0B2
+:106F7000004270B5C3F880200024D3F8802002F0CE
+:106F80000042C3F88020D3F88020D3F884204FF04B
+:106F9000FF32C3F88420D3F88410C3F88440D3F8B8
+:106FA0008410D96F41F0FF4141F4FF0141F4DF410A
+:106FB00041F07F01D967D96F21F0FF4121F4FF0132
+:106FC00021F4DF4121F07F01D967D96FD3F8881010
+:106FD0006FEA41516FEA5151C3F88810D3F8881015
+:106FE000C1F30A01C3F88810D3F88810D3F89010C1
+:106FF000C3F89020D3F89010C3F89040D3F89010C5
+:10700000D3F89410C3F89420D3F89410C3F89440A4
+:10701000D3F89410D3F89810C3F89820D3F89810A8
+:10702000C3F89840D3F89810D3F88C10C3F88C208C
+:10703000D3F88C10C3F88C40D3F88C10D3F89C1084
+:10704000C3F89C20D3F89C20C3F89C40D3F89C3014
+:1070500000F0EAF9184A0623C2F89830174BC2F834
+:107060009C30174BC2F8A0300523C2F89430536A05
+:1070700043F480335362C2F88440BFF34F8FD2F899
+:10708000803043F6E074C3F3C900C3F34E335B01B1
+:1070900003EA0406014646EA81750139C2F87452D2
+:1070A000F9D2203B13F1200FF2D1BFF34F8FBFF382
+:1070B0006F8F70BD0044025800ED00E00000043006
+:1070C0001D000C0308B50122504BC3F80821504B9A
+:1070D0005A6D42F002025A65DA6F42F00202DA6734
+:1070E0000422DB6F4B4BDA605A689104FCD54A4AA4
+:1070F0001A6001229A60494ADA6000221A614FF44C
+:1071000040429A61434B9A699204FCD51A6842F452
+:1071100080721A60424B1A6F12F4407F04D04FF411
+:1071200080321A6700221A671A6842F001021A6058
+:107130003B4B1A685007FCD500221A611A6912F0FD
+:107140003802FBD1012119604FF0804159605A6724
+:10715000344ADA62344A1A611A6842F480321A6098
+:107160002F4B1A689103FCD51A6842F480521A60BA
+:107170001A689204FCD52D4A2D499A6200225A635E
+:10718000196301F57C01DA6301F5E77199635A64CB
+:10719000284A1A64284ADA621A6842F0A8521A6029
+:1071A0001F4B1A6802F02852B2F1285FF9D1482229
+:1071B0009A614FF48862DA6140221A621F4ADA64E7
+:1071C0001F4A1A651F4A5A651F4A9A6532231F4A89
+:1071D0001360136803F00F03022BFAD1104A1369EE
+:1071E00043F003031361136903F03803182BFAD13A
+:1071F0004FF00050FFF7ACFE4FF08040FFF7A8FEC5
+:107200004FF00040BDE80840FFF7A2BE00800051EB
+:10721000004502580048025800C000F00400000178
+:10722000004402580000FF010088900832206000EE
+:1072300063020901470E0508DD0BBF012000002095
+:10724000000001100910E0000001011000200052B0
+:107250004FF0B04208B5D2F8883003F00103C2F80D
+:10726000883023B1044A13680BB150689847BDE8D1
+:107270000840FCF7E7BF00BF608200204FF0B0423B
+:1072800008B5D2F8883003F00203C2F8883023B181
+:10729000044A93680BB1D0689847BDE80840FCF7F2
+:1072A000D1BF00BF608200204FF0B04208B5D2F8D5
+:1072B000883003F00403C2F8883023B1044A13690C
+:1072C0000BB150699847BDE80840FCF7BBBF00BF51
+:1072D000608200204FF0B04208B5D2F8883003F049
+:1072E0000803C2F8883023B1044A93690BB1D0690E
+:1072F0009847BDE80840FCF7A5BF00BF60820020AA
+:107300004FF0B04208B5D2F8883003F01003C2F84D
+:10731000883023B1044A136A0BB1506A9847BDE81C
+:107320000840FCF78FBF00BF608200204FF0B043E1
+:1073300010B5D3F8884004F47872C3F88820A30607
+:1073400004D5124A936A0BB1D06A9847600604D5F7
+:107350000E4A136B0BB1506B9847210604D50B4AAC
+:10736000936B0BB1D06B9847E20504D5074A136CB9
+:107370000BB1506C9847A30504D5044A936C0BB12C
+:10738000D06C9847BDE81040FCF75CBF60820020DD
+:107390004FF0B04310B5D3F8884004F47C42C3F8F2
+:1073A0008820620504D5164A136D0BB1506D9847BD
+:1073B000230504D5124A936D0BB1D06D9847E004B4
+:1073C00004D50F4A136E0BB1506E9847A10404D533
+:1073D0000B4A936E0BB1D06E9847620404D5084AED
+:1073E000136F0BB1506F9847230404D5044A936F71
+:1073F0000BB1D06F9847BDE81040FCF723BF00BF2A
+:107400006082002008B50348FCF7CCFFBDE80840C7
+:10741000FCF718BFE45E002008B5FFF783FDBDE868
+:107420000840FCF70FBF0000062108B50846FDF72D
+:107430003FF806210720FDF73BF806210820FDF75D
+:1074400037F806210920FDF733F806210A20FDF759
+:107450002FF806211720FDF72BF806212820FDF72D
+:1074600027F809217A20FDF723F807213220FDF7BC
+:107470001FF80C215220BDE80840FDF719B80000A4
+:1074800008B5FFF771FD00F00DF8FDF7B9F9FDF74C
+:1074900091FBFDF763FAFFF71FFDBDE80840FFF71A
+:1074A000FFBB00000023054A19460133102BC2E937
+:1074B000001102F10802F8D1704700BF608200207D
+:1074C0000B460146184600F003B8000000F00EB865
+:1074D00010B5054C13462CB10A4601460220AFF305
+:1074E000008010BD2046FCE700000000024B014672
+:1074F000186800F035B800BF6C22002010B50139C3
+:107500000244904201D1002005E0037811F8014FB8
+:10751000A34201D0181B10BD0130F2E72DE9F04164
+:10752000A3B1C91A17780144044603F1FF3C8C4209
+:10753000204601D9002009E00578BD4204F101048C
+:10754000F5D10CEB0405D618A54201D1BDE8F081B8
+:1075500015F8018D16F801EDF045F5D0E7E70000CC
+:1075600037B5002944D051F8043C0190002BA1F11B
+:107570000404B8BFE41800F047F81E4A01981368E5
+:1075800033B96360146003B0BDE8304000F042B826
+:10759000A34208D9256861198B4201BF19685B684D
+:1075A00049192160EDE71A465B680BB1A342FAD98D
+:1075B00011685518A5420BD1246821445418A342E0
+:1075C0001160E0D11C685B68536021441160DAE708
+:1075D00002D90C230360D6E7256861198B4204BFEA
+:1075E00019685B68636004BF491921605460CAE789
+:1075F00003B030BDE0820020034611F8012B03F8F0
+:10760000012B002AF9D17047014800F009B800BFEA
+:10761000E4820020014800F005B800BFE4820020A9
+:107620007047000070470000636F6D2E63756265E0
+:1076300070696C6F742E4375626550696C6F74432A
+:10764000414E4D6F642D70657269706800000000D6
+:1076500053544D333248373F3F3F0053544D33323C
+:10766000483733782F3732780053544D3332483708
+:1076700034332F3735332F373530000001105A009F
+:1076800003105900012058000320560040A2E4F1E5
+:10769000646891060041A3E5F26569920700000065
+:1076A00043414E464449666163653A204D657373B4
+:1076B0006167652052414D204F766572666C6F7729
+:1076C000210000004261642043414E4966616365C8
+:1076D00020696E6465782E00000100000001FF0043
+:1076E00000A0004000A400400000000000000000D6
+:1076F000852900085D220008C530000855220008D1
+:10770000CD220008DD260008452400089522000847
+:107710009922000871220008592200089D260008BD
+:107720007D220008313200088922000871260008F5
+:1077300000960000000000000000000000000000B3
+:10774000000000000000000000000000C147000829
+:10775000AD470008E9470008D5470008E1470008A1
+:10776000CD470008B9470008A5470008F5470008BD
+:1077700000000000D9480008C54800080149000879
+:10778000ED480008F9480008E5480008D14800081D
+:10779000BD4800080D49000800000000010000007D
+:1077A0000000000063300000A4770008A8630020F8
+:1077B000B86500204172647550696C6F7400254291
+:1077C0004F415244252D424C002553455249414CCE
+:1077D000250000000200000000000000F94A000837
+:1077E000694B000840004000687E0020787E002041
+:1077F0000200000000000000030000000000000084
+:10780000B14B00080000000010000000887E00203E
+:1078100000000000010000000000000010810020B6
+:1078200001010200E9560008F955000895560008C4
+:1078300079560008430000003C7800080902430024
+:10784000020100C032090400000102020100052407
+:107850000010010524010001042402020524060091
+:1078600001070582030800FF09040100020A000065
+:1078700000070501024000000705810240000000EA
+:107880001200000088780008120110010200004078
+:107890000912415700020102030100000403090418
+:1078A00025424F41524425004375626550696C6F13
+:1078B000742D43414E4D6F640030313233343536D0
+:1078C000373839414243444546000000000000007B
+:1078D0000D4D0008C54F00087150000840004000E1
+:1078E00048820020488200200100000058820020C9
+:1078F00080000000400100000800000000010000BE
+:1079000000100000080000006D61696E0069646C81
+:10791000650000000000802A00000000AAAAAAAAB0
+:1079200000000024FFFF00000000000000A00A008B
+:107930000028000000000000AAAAAAAA0000000077
+:10794000FFFF0000000090090000000000000000A0
+:1079500000000000AAAAAAAA00000000FFFF000081
+:1079600000000000000000000A000000000000000D
+:10797000AAAAAAAA00000000FFFF000099000000C8
+:10798000000000000080020000000000AAAAAAAACD
+:1079900000400100FFFF0000000000700700000031
+:1079A0000000000000000000AAAAAAAA000000002F
+:1079B000FFFF0000000000000000000005000000C4
+:1079C00000000000A5AAAAAA00000000FCFF000019
+:1079D00000000000000000000000000000000000A7
+:1079E000AAAAAAAA00000000FFFF000000000000F1
+:1079F000000000000000000000000000AAAAAAAADF
+:107A000000000000FFFF0000000000000000000078
+:107A10000000000000000000AAAAAAAA00000000BE
+:107A2000FFFF000000000000000000000000000058
+:107A300000000000AAAAAAAA00000000FFFF0000A0
+:107A40000000000000000000D888FF7F0100000057
+:107A500037040000000000000000180000000000D3
+:107A6000FE2A0100D2040000FF000000C0650020D3
+:107A7000E45E00200000000050760008830400004F
+:107A80005B7600085004000069760008009600004C
+:107A9000000008009600000000080000040000003C
+:107AA0009C780008000000000000000000000000BA
+:107AB0000000000000000000000000007022002014
+:107AC00000000000000000000000000000000000B6
+:107AD00000000000000000000000000000000000A6
+:107AE0000000000000000000000000000000000096
+:107AF0000000000000000000000000000000000086
+:107B00000000000000000000000000000000000075
+:107B10000000000000000000000000000000000065
+:00000001FF
diff --git a/Tools/bootloaders/CubeRedPrimary_bl.bin b/Tools/bootloaders/CubeRedPrimary_bl.bin
new file mode 100755
index 00000000000000..8070aaf1ad3780
Binary files /dev/null and b/Tools/bootloaders/CubeRedPrimary_bl.bin differ
diff --git a/Tools/bootloaders/CubeRedPrimary_bl.hex b/Tools/bootloaders/CubeRedPrimary_bl.hex
new file mode 100644
index 00000000000000..5f48f1dbe44db9
--- /dev/null
+++ b/Tools/bootloaders/CubeRedPrimary_bl.hex
@@ -0,0 +1,1780 @@
+:020000040800F2
+:1000000000060020F50500088D24000841240008A2
+:10001000692400084124000861240008F70500084D
+:10002000F7050008F7050008F70500084D6000080F
+:10003000F7050008F7050008F7050008F7050008B0
+:10004000F7050008F7050008F7050008F7050008A0
+:10005000F7050008F7050008216400084D64000852
+:1000600079640008A5640008D1640008F705000859
+:10007000F7050008F7050008F7050008F705000870
+:10008000F7050008F7050008F7050008F705000860
+:10009000F7050008F7050008F7050008FD640008EB
+:1000A000F7050008F7050008F7050008F705000840
+:1000B000F7050008F7050008F7050008F705000830
+:1000C000F7050008F7050008F7050008F705000820
+:1000D000F7050008F7050008E9650008F7050008BE
+:1000E00061650008F7050008F7050008F705000836
+:1000F000F7050008F7050008F7050008F7050008F0
+:10010000F7050008F7050008FD650008F705000879
+:10011000F7050008F7050008F7050008F7050008CF
+:10012000F7050008F7050008F7050008F7050008BF
+:10013000F7050008F7050008F7050008F7050008AF
+:10014000F7050008F7050008F7050008F70500089F
+:10015000F7050008F7050008F7050008F70500088F
+:10016000F7050008F7050008F7050008F70500087F
+:10017000F705000801580008F7050008F705000812
+:10018000F7050008F7050008F7050008F70500085F
+:10019000F7050008F7050008F7050008F70500084F
+:1001A000F7050008F7050008F7050008F70500083F
+:1001B000D5650008F7050008F7050008F7050008F1
+:1001C000F7050008F7050008F7050008F70500081F
+:1001D000F7050008ED570008F7050008F7050008C7
+:1001E000F7050008F7050008F7050008F7050008FF
+:1001F000F7050008F7050008F7050008F7050008EF
+:10020000F7050008F7050008F7050008F7050008DE
+:10021000F7050008F7050008F7050008F7050008CE
+:10022000F7050008F70500086D4C0008F705000801
+:10023000F7050008F7050008F7050008F7050008AE
+:10024000F7050008F7050008F7050008F70500089E
+:10025000F7050008F7050008F7050008F70500088E
+:10026000F7050008F7050008F7050008F70500087E
+:10027000F7050008F7050008F7050008F70500086E
+:10028000F7050008F7050008F7050008F70500085E
+:10029000F7050008F7050008F7050008F70500084E
+:1002A000F7050008F7050008F7050008F70500083E
+:1002B000F7050008F7050008F7050008F70500082E
+:1002C000F7050008F7050008F7050008F70500081E
+:1002D000F7050008F7050008F7050008F70500080E
+:1002E000D9070008092100081924000800000000AF
+:1002F00053B94AB9002908BF00281CBF4FF0FF318D
+:100300004FF0FF3000F074B9ADF1080C6DE904CE88
+:1003100000F006F8DDF804E0DDE9022304B07047E0
+:100320002DE9F047089D04468E46002B4DD18A42A8
+:10033000944669D9B2FA82F252B101FA02F3C2F1DB
+:10034000200120FA01F10CFA02FC41EA030E94406C
+:100350004FEA1C48210CBEFBF8F61FFA8CF708FB8D
+:1003600016E341EA034306FB07F199420AD91CEB65
+:10037000030306F1FF3080F01F81994240F21C8197
+:10038000023E63445B1AA4B2B3FBF8F008FB1033DF
+:1003900044EA034400FB07F7A7420AD91CEB040414
+:1003A00000F1FF3380F00A81A74240F207816444E4
+:1003B000023840EA0640E41B00261DB1D440002369
+:1003C000C5E900433146BDE8F0878B4209D9002DCD
+:1003D00000F0EF800026C5E9000130463146BDE857
+:1003E000F087B3FA83F6002E4AD18B4202D38242C1
+:1003F00000F2F980841A61EB030301209E46002D70
+:10040000E0D0C5E9004EDDE702B9FFDEB2FA82F2C4
+:10041000002A40F09280A1EB0C014FEA1C471FFA22
+:100420008CFE0126200CB1FBF7F307FB131140EA09
+:1004300001410EFB03F0884208D91CEB010103F1D6
+:10044000FF3802D2884200F2CB804346091AA4B298
+:10045000B1FBF7F007FB101144EA01440EFB00FE6C
+:10046000A64508D91CEB040400F1FF3102D2A645D1
+:1004700000F2BB800846A4EB0E0440EA03409CE770
+:10048000C6F12007B34022FA07FC4CEA030C20FA1D
+:1004900007F401FA06F31C43F9404FEA1C4900FA3D
+:1004A00006F3B1FBF9F8200C1FFA8CFE09FB1811BA
+:1004B00040EA014108FB0EF0884202FA06F20BD92D
+:1004C0001CEB010108F1FF3A80F08880884240F27D
+:1004D0008580A8F102086144091AA4B2B1FBF9F0C1
+:1004E00009FB101144EA014100FB0EFE8E4508D9BC
+:1004F0001CEB010100F1FF346CD28E456AD9023841
+:10050000614440EA0840A0FB0294A1EB0E01A14225
+:10051000C846A64656D353D05DB1B3EB080261EB93
+:100520000E0101FA07F722FA06F3F1401F43C5E96D
+:10053000007100263146BDE8F087C2F12003D840A3
+:100540000CFA02FC21FA03F3914001434FEA1C47E5
+:100550001FFA8CFEB3FBF7F007FB10360B0C43EAD7
+:10056000064300FB0EF69E4204FA02F408D91CEB87
+:10057000030300F1FF382FD29E422DD90238634485
+:100580009B1B89B2B3FBF7F607FB163341EA034125
+:1005900006FB0EF38B4208D91CEB010106F1FF3874
+:1005A00016D28B4214D9023E6144C91A46EA00466B
+:1005B00038E72E46284605E70646E3E61846F8E6FD
+:1005C0004B45A9D2B9EB020864EB0C0E0138A3E746
+:1005D0004646EAE7204694E74046D1E7D0467BE727
+:1005E000023B614432E7304609E76444023842E79F
+:1005F000704700BF02E000F000F8FEE772B637482F
+:1006000080F30888364880F3098836483649086000
+:1006100040F20000CCF200004EF63471CEF2000140
+:100620000860BFF34F8FBFF36F8F40F20000C0F23E
+:10063000F0004EF68851CEF200010860BFF34F8FF4
+:10064000BFF36F8F4FF00000E1EE100A4EF63C71E1
+:10065000CEF200010860062080F31488BFF36F8F8C
+:1006600004F06CFA05F05CFC4FF055301F491B4A52
+:1006700091423CBF41F8040BFAE71D49184A9142E8
+:100680003CBF41F8040BFAE71A491B4A1B4B9A423C
+:100690003EBF51F8040B42F8040BF8E7002018495C
+:1006A000184A91423CBF41F8040BFAE704F084FA7F
+:1006B00005F0A6FC144C154DAC4203DA54F8041BAB
+:1006C0008847F9E700F050F8114C124DAC4203DABC
+:1006D00054F8041B8847F9E704F06CBA00060020C0
+:1006E000002200200000000808ED00E000000020CB
+:1006F00000060020506E000800220020C8220020C2
+:10070000C8220020B04A0020E0020008EC020008E5
+:10071000EC020008EC0200082DE9F04F2DED108AE4
+:10072000C1F80CD0D0F80CD0BDEC108ABDE8F08F29
+:10073000002383F311882846A047002003F096FB8E
+:10074000FEE703F0AFFA00DFFEE70000054B10B54F
+:1007500004460360806810B103685B6898472046D0
+:1007600010BD00BF5069000870B500F027FD04F00F
+:100770000BF9054604F0D8F90446B8B9144B9D426C
+:1007800016D001339D4241F2883512BF0446002540
+:100790000124104E002004F001F9304601F0D6FA91
+:1007A00040B944F6206003F067FBF6E70025F0E768
+:1007B0000546EEE70CB100F091F800F0F1FE00F014
+:1007C00069FD284600F028F900F088F8F9E700BF35
+:1007D000010007B0C82200200448054B054A036009
+:1007E00000230549836005F063BF00BFC8220020D5
+:1007F00050690008002500204D07000808B500F0EA
+:1008000015FDA0F120035842584108BD07B5042149
+:1008100001900DEB010000F027FD03B05DF804FB33
+:1008200007B541F21203022101A8ADF8043000F02F
+:100830001BFD03B05DF804FB38B5302383F311884A
+:10084000174803680BB103F0F5FB0023154A4FF47A
+:100850007A71134803F0E4FB002383F31188124CF0
+:10086000236813B12368013B2360636813B1636895
+:10087000013B63600D4D2B7833B963687BB902206F
+:1008800000F0CEFD322363602B78032B07D1636821
+:100890002BB9022000F0C4FD4FF47A73636038BDB9
+:1008A00058230020390800087824002070230020F5
+:1008B000084B187003280CD8DFE800F00805020880
+:1008C000022000F0A5BD022000F098BD024B0022DE
+:1008D0005A6070477023002078240020F7B54648FE
+:1008E00001A901F0B3FB002800F08480434B444A87
+:1008F0001C46196801317AD004339342F9D16268F9
+:10090000404B9A4273D9404B9B6803F1006303F557
+:1009100000339A426BD2002000F0E2FC0220FFF785
+:10092000C7FF3A4B00219A6C99641A6F19671A6FC6
+:10093000DA6CD9645A6F59675A6F1A6D19659A6FD4
+:1009400099679B6F324BD3F8802042F00072C3F856
+:100950008020D3F8802022F00072C3F88020D3F8E2
+:10096000803072B64FF0E023C3F8084DD4E900049C
+:10097000BFF34F8FBFF36F8F264AC2F88410BFF3C7
+:100980004F8F536923F480335361BFF34F8FD2F8F5
+:10099000803043F6E076C3F3C905C3F34E335B0101
+:1009A00003EA060C29464CEA81770139C2F87472D1
+:1009B000F9D2203B13F1200FF2D1BFF34F8FBFF3D9
+:1009C0006F8FBFF34F8FBFF36F8F536923F40033E3
+:1009D00053610023C2F85032BFF34F8FBFF36F8FC4
+:1009E000302383F31188854680F308882047024826
+:1009F00000F074FE03B0F0BDC82200200000020821
+:100A000020000208FFFF01080022002000450258D4
+:100A10000044025800ED00E02DE9F04FB04B9DB0CE
+:100A20002022FF21079014A89E68DB68069300F03F
+:100A300061FDAC4A1378A3B90121AB481170036082
+:100A4000302383F3118803680BB103F0F3FA00231A
+:100A5000A64A4FF47A71A44803F0E2FA002383F324
+:100A60001188079B13B1A24B079A1A60A14A137809
+:100A7000032B03D0002313709D4A53600023079D6E
+:100A80001F469B46CDE90433012000F0C1FC25B18F
+:100A9000974B1B68002B00F05783002000F0C6FB2B
+:100AA0000C900C9B002BF2DB012000F0A7FC0C9BB0
+:100AB000213B1F2BE8D801A252F823F03D0B000880
+:100AC000650B0008FB0B0008890A0008890A00086A
+:100AD000890A0008A90E0008C3100008650F000865
+:100AE00041100008671000088D100008890A0008EE
+:100AF0009F100008890A00080B110008DD0B000890
+:100B0000890A00084F1100088F0C0008C70D000863
+:100B1000890A0008B90F0008890A0008890A000834
+:100B2000890A0008890A0008890A0008890A000859
+:100B3000890A0008890A0008FB0B00080220FFF759
+:100B40005DFE002840F02B83079B0221059A0FA829
+:100B5000002A08BF1D4641F21233ADF83C3000F0C8
+:100B600083FB91E74FF47A7000F060FB041EEBDB2F
+:100B70000220FFF743FE0028E6D0013C052C00F2DE
+:100B80001083DFE804F0030A0D1013370523042156
+:100B90000FA80F9300F068FB17E004215048F9E715
+:100BA00004215548F6E704215448F3E74FF01C08A8
+:100BB000404608F1040800F095FB04210F900FA8AF
+:100BC00000F052FBB8F12C0FF2D10120049B4FF042
+:100BD000000B00FA04F41C43E3B2049300F0D6FCCB
+:100BE0002FB1049B03F00B030B2B08BF0025FFF76D
+:100BF00017FE49E704214248CCE7002FA4D0049B0C
+:100C000003F00B030B2B9FD10220FFF7F7FD0446E7
+:100C1000002899D00120002700F062FB0220FFF796
+:100C200047FE5FFA87F8404600F06AFB0546B0B120
+:100C30000C9940460137A1F140025142514100F068
+:100C40006FFB0028EDD10546059441F212130221F5
+:100C50000FA82746ADF83C3000F006FB14E72E46FF
+:100C60000120FFF725FE1E4B9B68B34207D9304693
+:100C700000F038FB013040F097820436F3E700269D
+:100C80001C4B274605941E70194B5E60A6E7002F8B
+:100C90003FF45AAF049B03F00B030B2B7FF454AFCC
+:100CA00064210DA800F0D6FA804600287FF44CAFEE
+:100CB0000220FFF7A3FD044600283FF445AFDFF80C
+:100CC00048908DF82F80D9F82420D9F8203053434C
+:100CD0000D9A93421AD20B4800F0ACFB34E700BFE8
+:100CE0000022002074240020582300203908000826
+:100CF00078240020702300200422002008220020F5
+:100D00000C220020F4670008C8220020BE48474695
+:100D1000C24600F08FFBFFF783FD01210DF12F008C
+:100D200000F0A2FA0D9B534541D900230EAA394683
+:100D30004846CDE90E330FAB00F0D4FC002884D038
+:100D400001F0ACFB0E9B00EB030801210DF12F001D
+:100D500000F08AFA01F0A2FB404520D9484600F095
+:100D6000FBFE80B964210D9BA848013701FB0AF105
+:100D7000B1FBF3F18DF82F10C9B200F05BFBD9F88D
+:100D800020309A44CEE701F089FB0F9B1844404580
+:100D90003FF65BAF01F082FB0E9B00EB03080E9B5E
+:100DA0004FF47A70A3FB000303F066F8CDE76423E9
+:100DB00001210DF12F0027468DF82F3000F054FA55
+:100DC000002306930AE7002F3FF4BEAE049B03F016
+:100DD0000B030B2B7FF4B8AE0220FFF769FD322026
+:100DE00000F024FA041EFFF6AFAE069BA046E318FF
+:100DF0000893874B089ADB689A423FF6A5AEB4F594
+:100E0000807F3FF7A1AEDFF80CA24FF000094C4500
+:100E10000EDD4FF47A7000F009FA0C900C9B002B59
+:100E2000FFF692AE0C9B09F101090AF8013BEEE7CF
+:100E3000C820FFF7E3FC044600283FF485AE0027F6
+:100E4000DFF8D491CDE90E77B8F1000F02D1274633
+:100E5000089BB6E70FAB6F4A0699484602930EAB64
+:100E60003A44394401930DAB0093434601F056F8E0
+:100E700000283FF4EAAE01F013FB0D9B8A4609906F
+:100E80001F44A8EB030801F00BFB099A0E9B9B186B
+:100E90004AF10002834272EB0103F4D2484600F0AB
+:100EA0005BFE0028EFD1CFE7002F3FF44DAE049B4F
+:100EB00003F00B030B2B7FF447AE0220FFF7F8FC87
+:100EC000322000F0B3F9B0F10008FFF63DAE18F0A3
+:100ED00003047FF439AE4E4A08EB0603926893424E
+:100EE0003FF632AEB8F5807F3FF72EAEDFF82491A3
+:100EF000A0450DDD4FF47A7000F098F90C900C9B32
+:100F0000002BFFF621AE0C9B013409F8013BEFE703
+:100F1000C820FFF773FC044600283FF415AE1F2ECF
+:100F200011D8C6F1200214AB26F00300394942451E
+:100F3000184428BF4246089200F0AAFA089AFF21F6
+:100F4000344800F0D7FAC8F38702324930464FEAF6
+:100F5000A80900F0D7FA074600283FF476AE06EB62
+:100F600089063BE60220FFF749FC00283FF4ECAD80
+:100F700000F0F4F900283FF4E7AD0024A046244B2C
+:100F80009B68A34258D91F2C11D8149B01330ED053
+:100F900024F003031CAA134453F8203C0F9340464B
+:100FA00004220FA9043401F0B7F88046E7E7204691
+:100FB00000F098F90F90F2E764210EA800F04AF9CA
+:100FC000044600287FF4C0AD0220FFF717FC00287C
+:100FD0003FF4BAAD0E9BA046DFF83CA003F0030936
+:100FE0000E99A1EB0901A14218D9214604230FAAA9
+:100FF000504600F0DFFF404604220FA901F08CF8B4
+:1010000004348046ECE700BF196800083168000826
+:101010000022002074230020C8220020B9F1000F14
+:101020000AD04B460FAA624800F0C4FF40464A4629
+:101030000FA901F071F880464046FFF7E7FBCDE5C8
+:10104000002364210FA80F9300F004F900287FF417
+:101050007BAD0220FFF7D2FB00283FF475AD0F985F
+:1010600000F072F9E9E7002364210FA80F9300F064
+:10107000F1F800287FF468AD0220FFF7BFFB0028DD
+:101080003FF462AD0F9800F061F9D6E70220FFF758
+:10109000B5FB00283FF458AD00F070F9CDE7022011
+:1010A000FFF7ACFB00283FF44FAD0FA9142000F070
+:1010B0006BF90890FFF7AAFB08990FA800F0D4F885
+:1010C0008CE5322000F0B2F8041EFFF63DADA30718
+:1010D0007FF43AAD374A04EB0B03926893423FF634
+:1010E00033AD0220FFF78AFB00283FF42DAD24F03A
+:1010F00003045C44A3453FF471AD58460BF1040B67
+:1011000000F0F0F8FFF782FBF4E74FF47A70FFF796
+:1011100075FB00283FF418AD00F020F9002845D0F9
+:10112000149B01330BD0082214A9002000F0EAF927
+:1011300000283BD02022FF2114A800F0DBF9FFF7A4
+:101140006FFB1D4802F098FE1DB0BDE8F08F002F28
+:101150003FF4FAAC049B03F00B030B2B7FF4F4ACCD
+:10116000002364210FA80F9300F074F804460028B0
+:101170007FF4EAAC0220FFF741FB804600283FF4F1
+:10118000E3ACFFF74DFB41F2883002F075FE0F989B
+:1011900000F048FA4746254600F0F8F974E407469F
+:1011A0001CE54FF0000BCFE405944EE53C464CE5C2
+:1011B000C822002000220020A08601007047000005
+:1011C0002DE9F84F4FF47A7306460D46002402FBD2
+:1011D00003F7DFF85080DFF8509098F900305FFA9D
+:1011E00084FA5A1C01D0A34212D159F824002A468D
+:1011F00031460368D3F820B03B46D847854207D133
+:10120000074B012083F800A0BDE8F88F0124E4E734
+:10121000002CFBD04FF4FA7002F02EFE0020F3E712
+:10122000C42400201022002014220020002307B52F
+:10123000024601210DF107008DF80730FFF7C0FFCE
+:1012400020B19DF8070003B05DF804FB4FF0FF30BC
+:10125000F9E700000A46042108B5FFF7B1FF80F066
+:101260000100C0B2404208BD074B0A4630B41978AD
+:10127000064B53F82140014623682046DD69044BA4
+:10128000AC4630BC604700BFC424002014220020BC
+:10129000A086010070B5104C0025104E03F020F917
+:1012A00020803068238883420CD8002520880138AC
+:1012B00003F012F923880544013BB5F5802F238004
+:1012C000F4D370BD03F008F9336805440133B5F574
+:1012D000003F3360E5D3E8E7C624002080240020E7
+:1012E00003F0DCB900F1006000F5003000687047E1
+:1012F00000F10060920000F5003003F053B90000E7
+:10130000054B1A68054B1B889B1A834202D910446F
+:1013100003F0E2B80020704780240020C62400209B
+:1013200038B50446074D29B128682044BDE8384047
+:1013300003F0EAB82868204403F0D4F80028F3D07A
+:1013400038BD00BF802400200020704700F1FF500E
+:1013500000F58F10D0F8000870470000064991F89A
+:10136000243033B100230822086A81F82430FFF7C3
+:10137000BFBF0120704700BF84240020014B1868C4
+:10138000704700BF0010005C194B0138032208446D
+:1013900070B51D68174BC5F30B042D0C1E88A642B3
+:1013A0000BD15C680A46013C824213460FD214F905
+:1013B000016F4EB102F8016BF6E7013A03F1080341
+:1013C000ECD181420B4602D22C2203F8012B0424DB
+:1013D000094A1688AE4204D1984284BF967803F831
+:1013E000016B013C02F10402F3D1581A70BD00BF39
+:1013F0000010005C1C2200206C680008022803D149
+:10140000024B4FF400129A61704700BF0018025857
+:10141000022802D1014B20229A617047001802581D
+:10142000022804D1024A536983F0200353617047B4
+:10143000001802580FB4124B30B51A78B5B042B943
+:101440000122104910481A704FF461430B6001F0FB
+:10145000B1FE39AB0C4C389AC82102A8019300F0B8
+:10146000EDFF2368C8280246DD6902A9074B28BFA3
+:10147000C8222046A84735B0BDE8304004B07047C8
+:10148000C8240020CC24002024250020A0860100B0
+:10149000002310B5934203D0CC5CC4540133F9E768
+:1014A00010BD0000013810B510F9013F3BB191F9B2
+:1014B00000409C4203D11AB10131013AF4E71AB15C
+:1014C00091F90020981A10BD1046FCE70138013947
+:1014D00010F9013F11F9012F0BB19342F8D0981A7E
+:1014E0007047000003460246D01A12F9011B00297A
+:1014F000FAD1704702440346934202D003F8011B1D
+:10150000FAE770472DE9F8431F4D14460746884611
+:1015100095F8242052BBDFF870909CB395F82430E6
+:101520002BB92022FF2148462F62FFF7E3FF95F8F1
+:1015300024004146C0F1080205EB8000A24228BF0A
+:101540002246D6B29200FFF7A3FF95F82430A41BE1
+:1015500017441E449044E4B2F6B2082E85F8246085
+:10156000DBD1FFF7FBFE0028D7D108E02B6A03EBA5
+:1015700082038342CFD0FFF7F1FE0028CBD10020B9
+:10158000BDE8F8830120FBE784240020024B1A7891
+:10159000024B1A70704700BFC424002010220020A4
+:1015A00038B51A4C1A4D204601F0A6FE29462046B1
+:1015B00001F0CEFE2D681748D5F89020D2F80438F7
+:1015C00043F00203C2F8043802F056FC12492846E0
+:1015D00001F0CCFFD5F89020104DD2F804382868DF
+:1015E00023F002030E49A042C2F804384FF4E1335D
+:1015F0000B6001D001F0DEFD6868A04204D008490C
+:10160000BDE8384001F0D6BD38BD00BF002C002039
+:10161000946B000840420F009C6B000814220020CD
+:10162000AC2400200C4B70B50C4D04461E780C4BBE
+:1016300055F826209A420DD00A4B00211822184650
+:10164000FFF758FF0460014655F82600BDE87040DA
+:1016500001F0B0BD70BD00BFC424002014220020E2
+:10166000002C0020AC24002080697047C0697047BE
+:10167000006A7047406A7047806A7047F0B5ADF203
+:10168000044D0E46054600214FF47F7201A80091DB
+:10169000FFF730FF2C6A744301362B6A7343A34271
+:1016A00016D92B686A46214628465F684FF4806346
+:1016B000B84770B16A464FF4806312F8011BFF29E6
+:1016C0000AD1013B9BB2002BF7D104F58064E4E71B
+:1016D00001200DF2044DF0BD0020FAE78068036898
+:1016E000DB69184730B5456A85B004468D420FD393
+:1016F0000568CDE90023026A03ABAD6A5143A847F0
+:1017000020B1206A039BC31A5842584105B030BD2E
+:101710000020FBE7F0B5C56987B004468D4212D3BF
+:101720000C9F866905687143CDE9013705AB0093CD
+:101730006D69036AA84720B1A069059BC31A584286
+:10174000584107B0F0BD0020FBE70000F0B566236C
+:1017500089B0002405464FF480768068079403A979
+:10176000CDE90336CDE9054403685B699847A8686D
+:1017700022462146036800941F692346B847A8689B
+:101780009923079403A9CDE90336CDE905440368FD
+:101790005B699847A86822462146036800941D6942
+:1017A0002346A84709B0F0BD254B2DE9F04F1B7823
+:1017B0009FB0002504468DF828304FF09F0E8068BA
+:1017C0004FF00123ADF8295005A90995CDE905E3AE
+:1017D000CDE9075503685B699847A068032229464D
+:1017E000036800922A461E690AABB04730B394F8EA
+:1017F0008C200C21134B01FB02339DF828101A7921
+:1018000091421BD19DF829205B799A4216D1A0689C
+:101810004FF05A0C0C4B082605A90996CDE905C3D3
+:10182000CDE9075503685B699847A0682A462946B1
+:10183000036800961F690AABB84738B900204BE12E
+:10184000DC67000824690008002500010422B34970
+:101850000AA804F067FF05460028EFD1BDF82C3038
+:101860006FF48277A3813B44012BE7D8079605A943
+:10187000CDE90A00A06803685B699847A0682A461A
+:101880002946036800961E690AABB0470028D5D0E8
+:10189000DDE90A361A0202F4706242EA1662FF2A91
+:1018A000CCD11B0E26F07F4650222946142B2661F0
+:1018B0000AA828BF1423A373FFF71CFEA06807968D
+:1018C00005A903685B699847A068A37B294602685D
+:1018D0009B0000930AAB16692A46B0470028ADD09A
+:1018E0000B990029AADBC9086FF07E43149D4FF0C5
+:1018F000010E994228BF1946C5F303130EFA03F2ED
+:1019000021FA03F303916161A261E361002B95D099
+:101910002646A44600274FF002081EAAC7F3460336
+:1019200002EB830353F834AC07F001031B01DA1D0B
+:101930000EFA03F908FA02F2A2EB090202EA0A021D
+:10194000DA401AD003F108090F330EFA02F2216AC5
+:1019500008FA03F30EFA09FBCCF830208A42A3EB15
+:101960000B0B0BEA0A0A2AFA09F98CF82C90A36AE5
+:1019700088BF2262934288BFA26201370CF1100C2B
+:10198000042FCAD1236A4FF0020C039A4FF0010EC4
+:10199000139F9A4224BFB2FBF3F1616207F00F017B
+:1019A00038BF01234FF0090201F1010138BF636222
+:1019B0004900336B33B3531C0EFA02F8A2F1050948
+:1019C0000CFA03F30EFA09FAA3EB080302F1FF384D
+:1019D0000CFA08F83B40A8EB0A08D34008EA0708CD
+:1019E00028FA09F87BD0012B7BD0022B7BD0032B6C
+:1019F00008BF4FF47A735FFA88F808FB0333736308
+:101A00004B43B36307321036252AD2D115F0C04FAD
+:101A1000C5F3417369D0012B69D0022B0CBF4FF481
+:101A20007A634FF47A43C5F3046202FB0333E3663F
+:101A30004B432367199B9E075CD0062384F87430C0
+:101A400015F4005F05F00F03C5F3042514BF402211
+:101A50000822013305FB02255B00A5675D430A9B55
+:101A60009F02E5677FF5EAAE0C9BC3F30722C3F341
+:101A7000421103F01F0384F8802084F8881084F852
+:101A80008130002A3FF4DAAE189BC3F3025213F4FC
+:101A9000401F84F883207FF4D1AEDE0602D5042AED
+:101AA0007FF4CCAE03F40072002A14BF012200229E
+:101AB00084F8872004D0DD0324D5002384F88930FE
+:101AC000179B1A0722D5002384F88630702384F8E8
+:101AD0008530012384F88D301FB0BDE8F08F0123DD
+:101AE00089E7102387E7802385E710239BE74FF4DE
+:101AF000807398E7590701D550239FE713F0780FBB
+:101B00009ED09BE69903DBD50123D7E75B07E0D5A1
+:101B1000012384F886300523D9E700BF7C680008DC
+:101B200030B58BB000240546806803924FF0012247
+:101B3000059105A9CDE90624CDE90844026852695A
+:101B40009047A8680121039B02680091214615690E
+:101B50002246A8470BB030BD13B50446A068036801
+:101B6000DB6C98470028F9D10DF1070294F8851035
+:101B70002046FFF7D5FF94F886309DF807001BB18B
+:101B800000F0010002B010BDC043C0F3C010F9E77F
+:101B900030B54FF001238BB00024054680688DF8E6
+:101BA0000F20059105A9CDE90634CDE90844036865
+:101BB0005B699847A86801220DF10F010368009442
+:101BC0001D692346A8470BB030BD0000F7B5174686
+:101BD0000DF1070206461D46FFF7A2FF68B19DF80A
+:101BE000074039469DF82020304624EA05042A4063
+:101BF00022438DF80720FFF7CBFF03B0F0BD0000B4
+:101C000030B54FF4807389B0002405468068039195
+:101C100003A9CDE90434CDE9064403685B6998471C
+:101C2000A86822462146036800941D692346A847F8
+:101C300009B030BD10B5044623682046DB6A9847DA
+:101C40000028F9D110BD000010B590F8743004469A
+:101C50005BB1FFF7EFFF012394F87410204684F87E
+:101C60008E30BDE81040FFF7CBBF012010BD000053
+:101C700010B590F87430044653B1FFF7DBFF012331
+:101C80002046042184F88E30BDE81040FFF7B8BF2D
+:101C9000012010BDF0B590F883308BB00446042BC2
+:101CA00050D100270DF10E0205218DF80E708DF830
+:101CB0000F70FFF735FF00282FD00DF10F023521EF
+:101CC0002046FFF72DFF40B320461F4EFFF7BCFF15
+:101CD0002046FFF7AFFF05AD0FCE0FC5336805A94E
+:101CE0009DF80E202B609DF80F30A06843F0020392
+:101CF0008DF810208DF80F308DF8113003685B6976
+:101D00009847A068022204A9036800971D693B4612
+:101D1000A84720B92046FFF7ABFF002010E020467F
+:101D2000FFF7A6FF0DF10F0235212046FFF7F8FE61
+:101D30000028F2D09DF80F309B07EED50123636099
+:101D40000BB0F0BD0120FBE7E06700082DE9F3418F
+:101D5000002304468068A36010B103685B6898475D
+:101D60000025264E264F0C2301A839465FFA85F838
+:101D70006B439A5900F072FA019BA0680022A3609D
+:101D8000019210B103685B689847019810B103682D
+:101D90005B689847A368E3B141F2883084F88C808F
+:101DA00002F06AF82046FFF7D1FC1E2002F064F82A
+:101DB0002046FFF7F9FC054688B994F88C300C22D0
+:101DC00010485343F158FFF735FB284602B0BDE8F1
+:101DD000F0810135032DC6D10B4800F059FB204698
+:101DE000FFF758FF0C2294F88C3005465343F15806
+:101DF00008B90648E7E70648E5E700BF2469000898
+:101E0000E424002084680008FA680008AE6800082E
+:101E1000D86800082DE9F041044688B00F46164600
+:101E2000FFF712FF2046FFF705FF0025C722A06835
+:101E30004FF48073079503A9CDE90323CDE9055538
+:101E400003685B699847A0682A462946036800959D
+:101E5000D3F810802B46C047054630B92046FFF71F
+:101E600007FF284608B0BDE8F081E36E3B60236FB2
+:101E70003360F3E72DE9F041002588B01F460446A2
+:101E80000E460E9B00F1400CA8463D60016B81B1EF
+:101E9000A9420ED391420CD8B6FBF1FE01FB1E61A4
+:101EA00039B9416B90F82C800F9D1960816B2960C6
+:101EB000154610306045E9D16DB3AB1962699342A4
+:101EC00029D82046FFF7C0FE2046FFF7B3FE4FF4A7
+:101ED0001453A06803A9CDF80C80CDE90436002680
+:101EE000CDE9066603685B699847A06832463146CB
+:101EF00003680096D3F810803346C0470646204654
+:101F00002EB9FFF7B5FE304608B0BDE8F081FFF707
+:101F1000AFFE3D60F7E70026F5E700002DE9F04150
+:101F20008669054688B00F46B3429046B1FBF6FC81
+:101F300006FB1C1C28BF3346A6EB0C0C00269C4558
+:101F4000644628BF1C46FFF77FFE2846FFF772FE57
+:101F50000222A86803A9164B0597CDE90323CDE912
+:101F6000066603685B699847A8682246414603688D
+:101F700000961F693346B847064628462EB9FFF734
+:101F800077FE304608B0BDE8F081FFF771FE0E9B8A
+:101F90001C60AB6FAA696343B3FBF2F30F9A136043
+:101FA000EA6F109B5443AA69B4FBF2F41C60E8E7A3
+:101FB000002500012DE9F04FCE18436989B0044691
+:101FC0009E420F46914639D83D464FF40458DFF8FB
+:101FD00078A0FFF72FFEAE4234D994F88030A6EBFC
+:101FE000050B94F8882003A903930023BBF5806FA9
+:101FF000A0680693636828BF4FF4806B0595012B9A
+:1020000014BF43465346012A049394F8813008BF15
+:1020100003F1FF33079303685B699847A068A9EB56
+:1020200007030268CDF800B02B44D2F810B00022AC
+:102030001146D84718B105F58065CCE7002009B0F6
+:10204000BDE8F08F0120FAE700ED0003F0B504468B
+:1020500089B00E46FFF7EEFD94F887502DB194F845
+:1020600089302BB1012B24D00025284609B0F0BDC2
+:1020700094F880300393F02306934FF404530493B1
+:102080006368012B04BF1D4B04930023059394F850
+:102090008130A06803A9079303685B699847A0682B
+:1020A000314603689B6998470546642001F0E4FEC9
+:1020B000DBE720460027FFF7C7FD2046FFF7BAFD04
+:1020C00008238122852120460097FFF77FFD0546E2
+:1020D00018B92046FFF7CCFDC7E794F88030069783
+:1020E0000393074B04936368012B04BF054B0493D0
+:1020F0000023059394F88130013BCAE700ED00030B
+:102100000021001000ED0013014B024A1A607047D5
+:10211000E42400204C6A000830B50A44084D91427E
+:102120000DD011F8013B5840082340F30004013B57
+:102130002C4013F0FF0384EA5000F6D1EFE730BDE6
+:102140002083B8ED70470000704700000020704702
+:102150000020704713B56C4600F1140384E80600B4
+:1021600094E8030083E8050002B010BD002070472A
+:1021700013B56C4600F10C0384E8060094E80300F4
+:1021800083E8050002B010BD0023C0E903337047A7
+:1021900082B002AB03E9060002B07047704700004E
+:1021A00000207047704700000020704700207047F3
+:1021B0000120704782B0002002A901E90C0002B0A2
+:1021C000704700000020704700207047036B1A79A9
+:1021D000034B53F832309B699868C0F34010704746
+:1021E000E46900080B6883634B6843638B68C363CF
+:1021F000CB6803640B6943647047000038B5036B18
+:102200000446154D1B7955F8330001F0AFFCD4E9B5
+:102210000B231B7955F8331002F1300349689942BA
+:1022200018D000231363E26A5363D4E90B12537C82
+:10223000581E137C92681B0443EA002313438B63EC
+:10224000D4E90B131B79303155F83300BDE8384021
+:1022500001F020BC38BD00BFE4690008F8B51D4F8F
+:1022600005460E4611463868FFF730F978BB7468AA
+:102270003B7924B394F82C209A420BD02468F8E7D9
+:102280000122B52100F00EF9736823603B79746078
+:1022900084F82C30482004F015FA68B1002202714D
+:1022A000C0E90322C0E90522027A42F00702027265
+:1022B000094AC0E90B47026028602846F8BD402063
+:1022C00004F000FA04460028DAD12C60F5E7002378
+:1022D0002B60F2E7EC240020F4690008044B10B5F1
+:1022E00004460360406A08B104F0EAF9204610BDD4
+:1022F0009869000810B50446FFF7F0FF204604F087
+:10230000DDF9204610BD000008B519B1FFF776FFD2
+:10231000012008BD036B1A79024B53F8320001F01B
+:1023200029FCF5E7E46900082DE9FF41DDF8288084
+:102330000546174603911FFA88F60293FFF75EFFE2
+:1023400002ABBAB203A9E86A009600F0BFF80446EF
+:1023500038B900212846FFF7D7FF204604B0BDE872
+:10236000F081AFB92B6B05F134011A79134B53F897
+:102370003200B8F1000F19D101F09AFB80F001048E
+:10238000E4B23346E86ADDE9022100F0C5F8E0E78F
+:10239000029B83B92B6B3A46084805F134011C793E
+:1023A000039B50F8340001F099FBE7E7029B42469B
+:1023B00001F0AAFBE2E70024E3E700BFE4690008BC
+:1023C00013B504460191FFF719FF019A236B04F13D
+:1023D00034011879054B53F8300001F0ABFB0021B4
+:1023E0002046FFF791FF012002B010BDE46900080C
+:1023F00010B50446FFF702FF236B1A79054B53F81B
+:10240000320001F0A5FB00212046FFF77DFF0120EF
+:1024100010BD00BFE4690008054B064A1A6000229F
+:102420001A719A60044ADA6040F21F121A827047E9
+:10243000EC2400201B69000800E1F50500F07EBADD
+:1024400000B59BB0EFF3098168226846FFF720F8DA
+:10245000EFF30583014B9B6BFEE700BF00ED00E04F
+:1024600008B5FFF7EDFF000000B59BB0EFF3098161
+:1024700068226846FFF70CF8EFF30583014B5B6BAE
+:10248000FEE700BF00ED00E0FEE70000FEE7000011
+:102490000FB408B5029801F07BFCFEE702F014BA15
+:1024A00002F0ECB938B5084B044615460175436097
+:1024B0000A21243002F0A6FA04F128002A460A2153
+:1024C00002F0A0FA204638BD606A0008F8B51E4642
+:1024D0001B6805460C4617461BB9236863B90124DF
+:1024E00008E0BDF818203146806A02F0A3FA0028FF
+:1024F000F3D100242046F8BD21463A46686A02F02E
+:10250000CFFA04460028EAD13368002BF1D0A86A3C
+:1025100002F0FAFAEEE7000038B50D46114604461F
+:102520001A4611B1806A02F0ADFA2DB12946606AEF
+:10253000BDE8384002F0E0BA38BD00000368002171
+:102540001B68184703790BB10022027118467047C7
+:1025500003685B681847000003791BB90123037106
+:1025600018467047002070477047000010B50446B9
+:1025700004F0A4F8204610BDF0B500F10B0423468A
+:102580000D46B1FBF2F102FB115707F13006392E6F
+:10259000C8BF07F13706954203F8016DF0D2421E1D
+:1025A000E11A13F8015B9C4202F8015FF9D108447B
+:1025B000F0BD00002DE9F04F804687B015464FF082
+:1025C00000090C4614F8013B002B3BD0252B08D00A
+:1025D000D8F800201946404609F10109D268904711
+:1025E00049E14B782D2B06BF8C1C0123002301935E
+:1025F00023782B2B06BF01340127002794F800A075
+:10260000BAF1300F0CBF01344FF0200A23782A2B87
+:102610001CD16178023455F804BB2E2943D12178AE
+:1026200081B12A2921D0661C0020A1F13002344654
+:10263000D2B2092A1DD80A2316F8011B03FB002079
+:102640000029F2D1484607B0BDE8F08F4FF0000BEB
+:1026500014F8011B0029F5D0A1F13002D2B2092AE9
+:10266000DBD80A2303FB0B2BF2E76178023455F821
+:10267000040B01F0DF024C2A17D121780029E1D0A8
+:10268000782904F101041FD8622900F20081582939
+:102690001AD84E2900F23081442900F0918049294E
+:1026A00000F08E8010E00020E3E7A1F141027829DC
+:1026B000D2B209D862290BD8582905D84E293BD85F
+:1026C000442978D0492976D02E468DF80C1056E052
+:1026D000A1F16306152EF7D80FF2040C5CF826F072
+:1026E00071270008B7270008C9260008C926000876
+:1026F000C9260008C9260008B7270008C92600080F
+:10270000C9260008C9260008C9260008C9260008ED
+:102710004728000835290008C9260008C9260008EE
+:1027200087270008C926000831290008C9260008A3
+:10273000C926000835290008A1F14F02092AC3D88B
+:1027400001A050F822F000BF4728000835290008F2
+:10275000C9260008C9260008C9260008C92600089D
+:1027600031290008C9260008C926000835290008B3
+:102770002E464FF0200A56F8042B8DF80C2003AD9E
+:102780000DF10D002BE02E4647F6FF726A4B56F80E
+:10279000045B002808BF1046002D08BF1D462A46CE
+:1027A0002F18104612F8011B11B1B91A0029F8DAD6
+:1027B0004FF0200A13E02E46192A56F8041B02D8BF
+:1027C0002E4656F8041B002936DA2D2249428DF890
+:1027D0000C200DF10D000A2203ADFFF7CDFE471BC3
+:1027E0000199ABEB070323EAE372002945D1002BE3
+:1027F000C2F1000B1EDD29782D2901D02B290DD126
+:10280000BAF1300F0AD1D8F800304046019209F1F0
+:102810000109DB68013F98470135019AD8F800307B
+:10282000514640460192DB6898471BF1010B019A23
+:10283000F4D191443B4615E01FB12B228DF80C20BA
+:10284000C7E703A8C7E708222E4603A856F8041BCB
+:10285000C2E7D8F80020404615F8011BD268019362
+:102860009047019B013BF4D5002FA8BFB9445D46BA
+:102870002DB9D94435462146A3E69346DAE7D8F880
+:10288000003051464046013DDB689847F0E7A1F132
+:102890006302152A3FF618AF01A353F822F000BFD8
+:1028A00071270008C1270008C9260008C9260008AA
+:1028B000C9260008C9260008C1270008C926000843
+:1028C000C9260008C9260008C9260008C92600082C
+:1028D0004728000835290008C9260008C92600082D
+:1028E00087270008C926000831290008C9260008E2
+:1028F000C926000835290008A1F14F02092A3FF630
+:10290000E3AE01A353F822F0472800083529000858
+:10291000C9260008C9260008C9260008C9260008DB
+:1029200031290008C9260008C926000835290008F1
+:102930000A2289E7102287E7786A0008F0B5054681
+:1029400087B016461F460C4689B14A1E0023294609
+:1029500001A800F05FF83A46314601A8FFF72AFEC9
+:10296000049BA3423CBF0022EA5407B0F0BD0A46D4
+:10297000ECE70000D0E902239A421FBF4268D1541D
+:10298000C36801331ABFC36000206FF001007047B5
+:10299000D0E903239A421FBF4268D25C013303612E
+:1029A00014BF10466FF001007047000003692BB19F
+:1029B000013B426803610020D15470476FF0010071
+:1029C0007047000038B504460846D4E903315B1A65
+:1029D000934228BF13461D4663682A461944FEF7F2
+:1029E00057FD236928462B44236138BD38B504467A
+:1029F000D0E902301B1A934228BF13461D46636874
+:102A00002A461844FEF744FDE36828462B44E36059
+:102A100038BD000010B5C0E90223034C0023C0E913
+:102A20000041036110BD00BF806A00088A0710B52D
+:102A300004461DD50378042B1AD143681B682BB1BB
+:102A40000522027098472378052B01D102232370B9
+:102A5000302383F31188002104F1080001F026FAE5
+:102A6000002383F31188E069BDE8104002F0BCB98F
+:102A7000CB0704D50248BDE8104001F089B910BD6C
+:102A8000986A000810B5044C204600F0FBFF034A8A
+:102A90000023C4E9062310BD042500200050005285
+:102AA00010B503780446012B12D10E4B98420FD17A
+:102AB00002460D49102002F069F90C4BE0615A6B97
+:102AC00042F480425A63DA6D42F48042DA65DB6D8B
+:102AD0006268A36992685A60054A1A601B22DA602C
+:102AE00010BD00BF042500202D2A00080045025813
+:102AF0001500020182691B2310B5D360D1E90030B3
+:102B000013F44C4406D19B011461D06103F440439B
+:102B1000536110BD0024184313F4406F1461CC6856
+:102B2000D4615061F5D08B689361F2E730B5846968
+:102B30001B25C069E5600068836104F12003C3615F
+:102B400002234261013A03614223C3601623836278
+:102B5000CB682261E361D1E90023134312F4406F93
+:102B6000636101D08B68A361C36843F00103C36054
+:102B700030BD000030B5D0E90640006804F1200502
+:102B80008561C36108234261013A036146230D69EF
+:102B9000C36016238362CB682261E361D1E900231D
+:102BA000134312F4406F43EA854343F0806363614B
+:102BB00001D08B68A361C36843F00103C36030BDDB
+:102BC0008069036823F0040310B5CC680360002318
+:102BD0000361C4618361D1E900430969234343EA86
+:102BE000814343F04063436112B14FF010431360DF
+:102BF00010BD000083691A6842F002021A601A6868
+:102C00009207FCD41A6842F004021A607047000070
+:102C10008269936810B5D3609B0704461DD503787D
+:102C2000032B1AD143681B682BB105220270984709
+:102C30002378052B01D102232370302383F31188DD
+:102C4000002104F1080001F031F9002383F3118819
+:102C5000E069BDE8104002F0C7B810BD02684368E3
+:102C60001143016003B1184770470000024A13681E
+:102C700043F0C003136070470044004013B50E4C8E
+:102C8000204600F08BFA04F1140000234FF4007288
+:102C90000A49009400F048F9094B4FF400720949C1
+:102CA00004F13800009400F0C1F9074A074BC4E969
+:102CB000172302B010BD00BF24250020902500205E
+:102CC0006D2C0008902700200044004000E1F5052D
+:102CD000037C30B5214C002918BF0C46012B0CD1C8
+:102CE0001F4B984209D11F4B9A6C42F400329A64F0
+:102CF0001A6F42F400321A671B6F2268036EC16DAF
+:102D000003EB52038466B3FBF2F36268150442BF1F
+:102D100023F0070503F0070343EA4503CB60A368EC
+:102D200043F040034B60E36843F001038B6042F4DF
+:102D3000967343F001030B604FF0FF330B625105B4
+:102D400005D512F0102205D0B2F1805F04D080F8D2
+:102D5000643030BD7F23FAE73F23F8E7A86A000814
+:102D600024250020004502582DE9F047C66D054690
+:102D70003768F469210734621AD014F0080118BFCB
+:102D80004FF48071E20748BF41F02001A3074FF0E4
+:102D9000300348BF41F04001600748BF41F0800167
+:102DA00083F31188281DFFF759FF002383F311884F
+:102DB000E2050AD5302383F311884FF48061281D82
+:102DC000FFF74CFF002383F311884FF030094FF0D9
+:102DD000000A14F0200838D13B0616D54FF0300910
+:102DE00005F1380A200610D589F31188504600F005
+:102DF00051F9002836DA0821281DFFF72FFF27F0A8
+:102E000080033360002383F31188790614D56206AA
+:102E100012D5302383F31188D5E913239A4208D1C0
+:102E20002B6C33B127F040071021281DFFF716FF48
+:102E30003760002383F31188E30618D5AA6E13695F
+:102E4000ABB15069BDE8F047184789F31188736A40
+:102E5000284695F86410194000F0BAF98AF31188F1
+:102E6000F469B6E7B06288F31188F469BAE7BDE89F
+:102E7000F0870000F8B51546826804460B46AA4262
+:102E800000D28568A1692669761AB5420BD2184628
+:102E90002A46FEF7FDFAA3692B44A3612846A368DE
+:102EA0005B1BA360F8BD0CD9AF1B18463246FEF77A
+:102EB000EFFA3A46E1683044FEF7EAFAE3683B4449
+:102EC000EBE718462A46FEF7E3FAE368E5E7000079
+:102ED00083689342F7B50446154600D28568D4E965
+:102EE0000460361AB5420BD22A46FEF7D1FA63695E
+:102EF0002B4463612846A3685B1BA36003B0F0BD4D
+:102F00000DD93246AF1B0191FEF7C2FA01993A463C
+:102F1000E0683144FEF7BCFAE3683B44E9E72A463F
+:102F2000FEF7B6FAE368E4E710B50A440024C3618B
+:102F3000029B8460C16002610362C0E90000C0E9D5
+:102F4000051110BD08B5D0E90532934201D1826860
+:102F500082B98268013282605A1C42611970002174
+:102F6000D0E904329A4224BFC368436100F0B8FF3D
+:102F7000002008BD4FF0FF30FBE7000070B53023A4
+:102F800004460E4683F31188A568A5B1A368A2691B
+:102F9000013BA360531CA36115782269934224BFAF
+:102FA000E368A361E3690BB120469847002383F3EC
+:102FB0001188284607E03146204600F081FF0028AE
+:102FC000E2DA85F3118870BD2DE9F74F04460E460D
+:102FD00017469846D0F81C904FF0300A8AF31188B3
+:102FE0004FF0000B154665B12A4631462046FFF7E3
+:102FF00041FF034660B94146204600F061FF0028CA
+:10300000F1D0002383F31188781B03B0BDE8F08F63
+:10301000B9F1000F03D001902046C847019B8BF304
+:103020001188ED1A1E448AF31188DCE7C160C36180
+:10303000009B82600362C0E905111144C0E90000F1
+:1030400001617047F8B504460D461646302383F3F8
+:103050001188A768A7B1A368013BA36063695A1CE4
+:1030600062611D70D4E904329A4224BFE36863614F
+:10307000E3690BB120469847002080F3118807E0F0
+:103080003146204600F01CFF0028E2DA87F3118861
+:10309000F8BD0000D0E9052310B59A4201D182683D
+:1030A0007AB982680021013282605A1C82611C78E0
+:1030B00003699A4224BFC368836100F011FF204670
+:1030C00010BD4FF0FF30FBE72DE9F74F04460E46E9
+:1030D00017469846D0F81C904FF0300A8AF31188B2
+:1030E0004FF0000B154665B12A4631462046FFF7E2
+:1030F000EFFE034660B94146204600F0E1FE00289D
+:10310000F1D0002383F31188781B03B0BDE8F08F62
+:10311000B9F1000F03D001902046C847019B8BF303
+:103120001188ED1A1E448AF31188DCE702684368AF
+:103130001143016003B11847704700001430FFF7D6
+:1031400043BF00004FF0FF331430FFF73DBF0000D6
+:103150003830FFF7B9BF00004FF0FF333830FFF7CA
+:10316000B3BF00001430FFF709BF00004FF0FF317C
+:103170001430FFF703BF00003830FFF763BF0000D3
+:103180004FF0FF323830FFF75DBF0000012914BF58
+:103190006FF0130000207047FFF770BD044B036011
+:1031A00000234360C0E9023301230374704700BF6A
+:1031B000C06A000810B53023044683F31188FFF776
+:1031C00087FD02230020237480F3118810BD0000C6
+:1031D00038B5C36904460D461BB904210844FFF7FE
+:1031E000A5FF294604F11400FFF7ACFE002806DA1B
+:1031F000201D4FF40061BDE83840FFF797BF38BD90
+:10320000026843681143016003B11847704700002A
+:1032100013B5406B00F58054D4F8A4381A681178BF
+:10322000042914D1017C022911D1197901231289B1
+:103230008B4013420BD101A94C3002F029FCD4F889
+:10324000A4480246019B2179206800F0DFF902B012
+:1032500010BD0000143002F0ABBB00004FF0FF3394
+:10326000143002F0A5BB00004C3002F07DBC000021
+:103270004FF0FF334C3002F077BC0000143002F006
+:1032800079BB00004FF0FF31143002F073BB000037
+:103290004C3002F049BC00004FF0FF324C3002F0DD
+:1032A00043BC00000020704710B500F58054D4F8EE
+:1032B000A4381A681178042917D1017C022914D185
+:1032C0005979012352898B4013420ED1143002F0F8
+:1032D0000BFB024648B1D4F8A4484FF4407361791F
+:1032E0002068BDE8104000F07FB910BD406BFFF7CB
+:1032F000DBBF0000704700007FB5124B012504269C
+:10330000044603600023057400F1840243602946EB
+:10331000C0E902330C4B0290143001934FF4407318
+:10332000009602F0BDFA094B04F69442294604F1D6
+:103330004C000294CDE900634FF4407302F084FB2B
+:1033400004B070BDE86A0008ED32000811320008D0
+:103350000A68302383F311880B790B3342F823007A
+:103360004B79133342F823008B7913B10B3342F8B6
+:10337000230000F58053C3F8A4180223037400202F
+:1033800080F311887047000038B5037F044613B1FD
+:1033900090F85430ABB90125201D0221FFF730FF12
+:1033A00004F114006FF00101257700F0A5FD04F190
+:1033B0004C0084F854506FF00101BDE8384000F033
+:1033C0009BBD38BD10B5012104460430FFF718FF3E
+:1033D0000023237784F8543010BD000038B504462C
+:1033E0000025143002F074FA04F14C00257702F045
+:1033F00043FB201D84F854500121FFF701FF2046B4
+:10340000BDE83840FFF750BF90F8803003F060030C
+:10341000202B06D190F881200023212A03D81F2ACF
+:1034200006D800207047222AFBD1C0E91D3303E0F3
+:10343000034A426707228267C3670120704700BFC3
+:103440003422002037B500F58055D5F8A4381A6825
+:10345000117804291AD1017C022917D11979012385
+:1034600012898B40134211D100F14C04204602F026
+:10347000C3FB58B101A9204602F00AFBD5F8A448C5
+:103480000246019B2179206800F0C0F803B030BDEE
+:1034900001F10B03F0B550F8236085B004460D46EA
+:1034A000FEB1302383F3118804EB8507301D08211A
+:1034B000FFF7A6FEFB6806F14C005B691B681BB1B9
+:1034C000019002F0F3FA019803A902F0E1FA024632
+:1034D00048B1039B2946204600F098F8002383F367
+:1034E000118805B0F0BDFB685A691268002AF5D052
+:1034F0001B8A013B1340F1D104F18002EAE700008E
+:10350000133138B550F82140ECB1302383F31188E2
+:1035100004F58053D3F8A4281368527903EB82038F
+:10352000DB689B695D6845B104216018FFF768FEA0
+:10353000294604F1140002F0E1F92046FFF7B4FE39
+:10354000002383F3118838BD7047000001F09EBC52
+:1035500001234022002110B5044600F8303BFDF75E
+:10356000C9FF0023C4E9013310BD000010B53023AA
+:10357000044683F311882422416000210C30FDF7BA
+:10358000B9FF204601F0A4FC02230020237080F341
+:10359000118810BD70B500EB8103054650690E46D9
+:1035A0001446DA6018B110220021FDF7A3FFA069CC
+:1035B00018B110220021FDF79DFF31462846BDE8D5
+:1035C000704001F085BD000083682022002103F0D7
+:1035D000011310B5044683601030FDF78BFF2046C1
+:1035E000BDE8104001F000BEF0B4012500EB8104FD
+:1035F00047898D40E4683D43A469458123600023E9
+:10360000A2606360F0BC01F01DBE0000F0B40125B3
+:1036100000EB810407898D40E4683D4364690581BE
+:1036200023600023A2606360F0BC01F093BE000041
+:1036300070B5022300250446242203702946C0F8F1
+:1036400088500C3040F8045CFDF754FF204684F8A5
+:10365000705001F0D1FC63681B6823B129462046F5
+:10366000BDE87040184770BD0378052B10B50446BF
+:103670000AD080F88C300523037043681B680BB1B7
+:10368000042198470023A36010BD0000017805299C
+:1036900006D190F88C20436802701B6803B118476C
+:1036A0007047000070B590F87030044613B10023E5
+:1036B00080F8703004F18002204601F0B9FD6368A3
+:1036C0009B68B3B994F8803013F0600535D00021C1
+:1036D000204602F0ABF80021204602F09BF8636818
+:1036E0001B6813B1062120469847062384F87030E2
+:1036F00070BD204698470028E4D0B4F88630A26F09
+:103700009A4288BFA36794F98030A56F002B4FF0D1
+:10371000300380F20381002D00F0F280092284F84A
+:10372000702083F3118800212046D4E91D23FFF780
+:103730006DFF002383F31188DAE794F8812003F00A
+:103740007F0343EA022340F20232934200F0C58035
+:1037500021D8B3F5807F48D00DD8012B3FD0022B64
+:1037600000F09380002BB2D104F18802626702223C
+:10377000A267E367C1E7B3F5817F00F09B80B3F5F3
+:10378000407FA4D194F88230012BA0D1B4F88830C6
+:1037900043F0020332E0B3F5006F4DD017D8B3F514
+:1037A000A06F31D0A3F5C063012B90D86368204689
+:1037B00094F882205E6894F88310B4F88430B0479F
+:1037C000002884D0436863670368A3671AE0B3F5F1
+:1037D000106F36D040F6024293427FF478AF5C4BD4
+:1037E00063670223A3670023C3E794F88230012BA9
+:1037F0007FF46DAFB4F8883023F00203A4F888306A
+:10380000C4E91D55E56778E7B4F88030B3F5A06FDB
+:103810000ED194F88230204684F88A3001F04AFCB8
+:1038200063681B6813B10121204698470323237066
+:103830000023C4E91D339CE704F18B036367012374
+:10384000C3E72378042B10D1302383F3118820465B
+:10385000FFF7BAFE85F311880321636884F88B5063
+:1038600021701B680BB12046984794F88230002BDA
+:10387000DED084F88B300423237063681B68002B30
+:10388000D6D0022120469847D2E794F884302046CB
+:103890001D0603F00F010AD501F0BCFC012804D07D
+:1038A00002287FF414AF2B4B9AE72B4B98E701F0DB
+:1038B000A3FCF3E794F88230002B7FF408AF94F870
+:1038C000843013F00F01B3D01A06204602D501F060
+:1038D000C5FFADE701F0B6FFAAE794F88230002BF0
+:1038E0007FF4F5AE94F8843013F00F01A0D01B06DE
+:1038F000204602D501F09AFF9AE701F08BFF97E787
+:10390000142284F8702083F311882B462A46294616
+:103910002046FFF769FE85F31188E9E65DB11522BF
+:1039200084F8702083F3118800212046D4E91D23F8
+:10393000FFF75AFEFDE60B2284F8702083F311880E
+:103940002B462A4629462046FFF760FEE3E700BFE4
+:10395000186B0008106B0008146B000838B590F85D
+:1039600070300446002B3ED0063BDAB20F2A34D822
+:103970000F2B32D8DFE803F03731310822323131F2
+:103980003131313131313737856FB0F886309D4272
+:1039900014D2C3681B8AB5FBF3F203FB12556DB951
+:1039A000302383F311882B462A462946FFF72EFE43
+:1039B00085F311880A2384F870300EE0142384F80C
+:1039C0007030302383F31188002320461A461946AD
+:1039D000FFF70AFE002383F3118838BDC36F03B1DC
+:1039E00098470023E7E70021204601F01FFF002150
+:1039F000204601F00FFF63681B6813B106212046C3
+:103A000098470623D7E7000010B590F870300446B9
+:103A1000142B29D017D8062B05D001D81BB110BD07
+:103A2000093B022BFBD80021204601F0FFFE0021BC
+:103A3000204601F0EFFE63681B6813B106212046A3
+:103A40009847062319E0152BE9D10B2380F8703035
+:103A5000302383F3118800231A461946FFF7D6FD59
+:103A6000002383F31188DAE7C3689B695B68002B46
+:103A7000D5D1C36F03B19847002384F87030CEE7E7
+:103A8000FFF700B8012100230170C0E901330C30B9
+:103A900000F028B910B53023044683F31188416043
+:103AA000FEF7FEFF02230020237080F3118810BD73
+:103AB00010B53023044683F31188032304F8083B30
+:103AC000FFF718F84FF0FF31204600F0E1F900232E
+:103AD00083F31188C01A18BF012010BD38B5044601
+:103AE000302585F31188032504F8085BFFF71EF8DD
+:103AF0004FF0FF31204600F0CBF9002383F311880B
+:103B0000C01A18BF012038BD38B50446302585F3EA
+:103B10001188042504F8085BFFF72CF84FF0FF31FB
+:103B2000204600F0B5F9002383F31188C01A18BFAE
+:103B3000012038BD10B53023044683F31188FFF708
+:103B40003FF806232370002383F3118810BD000083
+:103B500010B53023044683F31188FFF74BF8022396
+:103B60002370002383F3118810BD00000C3000F097
+:103B7000D5B800000C3000F0DBB8000000238268EC
+:103B8000037503691B6899689142FBD25A68036008
+:103B900042601060586070470023826803750369B3
+:103BA0001B6899689142FBD85A68036042601060B4
+:103BB0005860704708B50846302383F311880A7DA2
+:103BC0000023052A06D8DFE802F00B050503120ED4
+:103BD000826913604FF0FF338361FFF7CFFF00234B
+:103BE00083F3118808BD8269936801339360D0E93B
+:103BF000003213605A60EDE7FFF7C0BF054BD9688C
+:103C000008751868026853601A600122D86002754E
+:103C1000FCF782BD902900200C4B30B5DD684B1CB1
+:103C200087B004460FD02B46094A684600F0F8F9E1
+:103C30002046FFF7E3FF009B13B1684600F0FAF956
+:103C4000A86907B030BDFFF7D9FFF9E79029002038
+:103C5000B53B000838B50C4D04468161EB688168BE
+:103C60009A68914203D8BDE83840FFF787BF1846ED
+:103C7000FFF792FF01230146EC6020462375BDE863
+:103C80003840FCF749BD00BF90290020044B1A685A
+:103C9000DB6890689B68984294BF002001207047C1
+:103CA00090290020084B10B51C68D8682268536022
+:103CB0001A600122DC602275FFF76EFF0146204684
+:103CC000BDE81040FCF728BD90290020044B1A687D
+:103CD000DB6892689B689A4201D9FFF7E3BF70479F
+:103CE00090290020C0E90000816070478368013B93
+:103CF000002B10B583600CDA074BDC684368A061C9
+:103D0000206063601C6044600520FFF777FFA069B6
+:103D100010BD0020FCE700BF9029002008B530232B
+:103D200083F31188FFF7E2FF002383F3118808BDB6
+:103D300008B5302383F3118883680133002B836037
+:103D400007DC036800211A68026050601846FFF71C
+:103D500081FF002383F3118808BD000038B50123DB
+:103D6000084C00252370656001F082FF01F0A8FF78
+:103D70000549064802F07CF80223237085F3118878
+:103D800038BD00BFF82B0020206B000890290020D0
+:103D900008B572B6044B186500F062FD00F030FE05
+:103DA000024B03221A70FEE790290020F82B002016
+:103DB00000F076B9EFF3118020B9EFF305833022DC
+:103DC00082F311887047000010B530B9EFF3058415
+:103DD000C4F3080414B180F3118810BDFFF776FF17
+:103DE00084F31188F9E70000034A516853685B1AAD
+:103DF0009842FBD8704700BF001000E08B600223A0
+:103E0000086108468B8270478368A3F1840243F8F7
+:103E1000142C026943F8442C426943F8402C094AA7
+:103E200043F8242CC268A3F1200043F8182C022286
+:103E300003F80C2C002203F80B2C034A43F8102C37
+:103E4000704700BF310700089029002008B5FFF730
+:103E5000DBFFBDE80840FFF7CFBE0000024BDB6888
+:103E600098610F20FFF7CABE90290020302383F30A
+:103E70001188FFF7F3BF000008B50146302383F334
+:103E800011880820FFF7C8FE002383F3118808BDBE
+:103E9000054BDB6821B1036098610320FFF7BCBECE
+:103EA0004FF0FF30704700BF9029002003682BB10E
+:103EB0000022026018469961FFF79EBE704700001D
+:103EC000064BDB6839B1426818605A601360436082
+:103ED0000420FFF7A1BE4FF0FF307047902900206B
+:103EE0000368984206D01A680260506018469961CB
+:103EF000FFF782BE7047000038B504460D462068C3
+:103F0000844200D138BD036823605C608561FFF79F
+:103F100073FEF4E7036810B59C68A2420CD85C6895
+:103F20008A600B604C602160596099688A1A9A60B7
+:103F30004FF0FF33836010BD121B1B68ECE70000DD
+:103F40000A2938BF0A2170B504460D460A266019B1
+:103F500001F088FE01F070FE041BA54203D8751C19
+:103F600004462E46F3E70A2E04D90120BDE870402E
+:103F700001F0BEBF70BD0000F8B5144B0D460A2A13
+:103F80004FF00A07D96103F11001826038BF0A229D
+:103F9000416019691446016048601861A81801F071
+:103FA00051FE01F049FE431B0646A34206D37C1C8A
+:103FB00028192746354601F055FEF2E70A2F04D9A5
+:103FC0000120BDE8F84001F093BFF8BD9029002022
+:103FD000F8B506460D4601F02FFE0F4A134653F87A
+:103FE000107F9F4206D12A4601463046BDE8F84080
+:103FF000FFF7C2BFD169BB68441A2C1928BF2C46F1
+:10400000A34202D92946FFF79BFF224631460348C7
+:10401000BDE8F840FFF77EBF90290020A0290020CE
+:10402000C0E90323002310B45DF8044B4361FFF79C
+:10403000CFBF000010B5194C236998420DD081689C
+:10404000D0E9003213605A609A680A449A600023EB
+:1040500003604FF0FF33A36110BD0268234643F8AD
+:10406000102F53600022026022699A4203D1BDE8FA
+:10407000104001F0F1BD936881680B44936001F03A
+:10408000DBFD2269E1699268441AA242E4D9114435
+:10409000BDE81040091AFFF753BF00BF9029002068
+:1040A0002DE9F047DFF8BC8008F110072C4ED8F856
+:1040B000105001F0C1FDD8F81C40AA68031B9A42B9
+:1040C0003ED814444FF00009D5E90032C8F81C402E
+:1040D00013605A60C5F80090D8F81030B34201D18F
+:1040E00001F0BAFD89F31188D5E9033128469847D4
+:1040F000302383F311886B69002BD8D001F09CFD2D
+:104100006A69A0EB040982464A450DD2022001F0FB
+:10411000EFFE0022D8F81030B34208D151462846AD
+:10412000BDE8F047FFF728BF121A2244F2E712EB6E
+:1041300009092946384638BF4A46FFF7EBFEB5E77E
+:10414000D8F81030B34208D01444C8F81C00211A23
+:10415000A960BDE8F047FFF7F3BEBDE8F08700BFF8
+:10416000A02900209029002000207047FEE70000D1
+:10417000704700004FF0FF307047000002290CD05C
+:10418000032904D00129074818BF00207047032ADB
+:1041900005D8054800EBC20070470448704700206E
+:1041A000704700BFF86B000844220020AC6B000889
+:1041B00070B59AB005460846144601A900F0C2F849
+:1041C00001A8FDF78FF9431C0022C6B25B00104620
+:1041D000C5E9003423700323023404F8013C01AB29
+:1041E000D1B202348E4201D81AB070BD13F8011B4F
+:1041F000013204F8010C04F8021CF1E708B5302381
+:1042000083F311880348FFF71DF9002383F3118816
+:1042100008BD00BF002C002090F8803003F01F0282
+:10422000012A07D190F881200B2A03D10023C0E98D
+:104230001D3315E003F06003202B08D1B0F8843063
+:104240002BB990F88120212A03D81F2A04D8FFF720
+:10425000DBB8222AEBD0FAE7034A426707228267DB
+:10426000C3670120704700BF3B22002007B5052926
+:1042700017D8DFE801F0191603191920302383F34A
+:104280001188104A01210190FFF784F90198022159
+:104290000D4AFFF77FF90D48FFF7A0F8002383F3DD
+:1042A000118803B05DF804FB302383F311880748BD
+:1042B000FFF76AF8F2E7302383F311880348FFF72A
+:1042C00081F8EBE74C6B0008706B0008002C0020B5
+:1042D00038B50C4D0C4C2A460C4904F10800FFF788
+:1042E00067FF05F1CA0204F110000949FFF760FFFA
+:1042F00005F5CA7204F118000649BDE83840FFF719
+:1043000057BF00BFD8440020442200202C6B000877
+:10431000366B0008416B000870B5044608460D4630
+:10432000FDF7E0F8C6B22046013403780BB9184611
+:1043300070BD32462946FDF7B5F80028F3D10120BB
+:10434000F6E700002DE9F04705460C46FDF7CAF8F0
+:104350002B49C6B22846FFF7DFFF08B10736F6B291
+:1043600028492846FFF7D8FF08B11036F6B2632E69
+:104370000BD8DFF88C80DFF88C90234FDFF894A007
+:104380002E7846B92670BDE8F08729462046BDE85C
+:10439000F04702F01BBA252E2ED1072241462846AF
+:1043A000FDF780F870B9194B224603F10C0153F860
+:1043B000040B8B4242F8040BF9D11B8807350E34ED
+:1043C0001380DDE7082249462846FDF76BF898B9C7
+:1043D000A21C0F4B197802320909C95D02F8041CAE
+:1043E00013F8011B01F00F015345C95D02F8031CCE
+:1043F000F0D118340835C3E7013504F8016BBFE785
+:10440000186C0008416B00082F6C0008206C000835
+:1044100000E8F11F0CE8F11FBFF34F8F044B1A693E
+:104420005107FCD1D3F810215207F8D1704700BFD3
+:104430000020005208B50D4B1B78ABB9FFF7ECFF1D
+:104440000B4BDA68D10704D50A4A5A6002F1883268
+:104450005A60D3F80C21D20706D5064AC3F80421C6
+:1044600002F18832C3F8042108BD00BF364700209E
+:10447000002000522301674508B5114B1B78F3B9A2
+:10448000104B1A69510703D5DA6842F04002DA602E
+:10449000D3F81021520705D5D3F80C2142F0400281
+:1044A000C3F80C21FFF7B8FF064BDA6842F00102AF
+:1044B000DA60D3F80C2142F00102C3F80C2108BDE8
+:1044C00036470020002000520F289ABF00F5806078
+:1044D00040040020704700004FF400307047000097
+:1044E000102070470F2808B50BD8FFF7EDFF00F537
+:1044F00000330268013204D104308342F9D1012033
+:1045000008BD0020FCE700000F2870B5054645D81F
+:10451000FFF750FC224CFFF77FFF0646FFF78AFFAC
+:104520004FF0FF33072D6361C4F8143120D82361A5
+:10453000FFF772FF2B0243F02403E360E36843F0CC
+:104540008003E36023695A07FCD42846FFF764FF21
+:104550004FF40031FFF7B8FF00F02EFA3046FFF7B6
+:104560008BFFFFF731FC2846BDE87040FFF7BABF6C
+:10457000C4F81031FFF750FFA5F108031B0243F008
+:104580002403C4F80C31D4F80C3143F08003C4F890
+:104590000C31D4F810315B07FBD4D6E7002070BD96
+:1045A000002000522DE9F84F40EA020305460C4670
+:1045B0001746D80602D00020BDE8F88F27F01F0765
+:1045C000DFF8D4B0FFF736FF2744BC4203D1012007
+:1045D000FFF752FFF0E720222946204602F0A2F81A
+:1045E00010B920352034F0E72B4605F120021E6873
+:1045F000711CE0D104339A42F9D1FFF7DBFB05F1DE
+:104600007843234AB3F5801F224B28BF9A4603F113
+:10461000040338BF9046A2F1080228BF9846A3F1D0
+:1046200008033ABF9146DA469946FFF7F5FEC8F807
+:104630000060A5EB040CD9F8002004F11C0142F045
+:104640000202C9F80020221FDAF8006016F0050601
+:10465000FAD152F8043F8A424CF80230F4D1BFF349
+:104660004F8FFFF7D9FE4FF0FF32C8F80020D9F87E
+:10467000002022F00202C9F80020FFF7A5FB20224B
+:104680002146284602F04EF80028AAD030469FE77F
+:1046900014200052102100521020005210B5084C76
+:1046A000237828B11BB9FFF7C5FE0123237010BD85
+:1046B000002BFCD02070BDE81040FFF7DDBE00BF2E
+:1046C000364700202DE9F04F0D4685B0814658B1A0
+:1046D00011F00D0614BF2022082211F008030193E7
+:1046E00004D0431E03426AD0002435E0002E37D0A8
+:1046F00009F11F0121F01F094FF00108324F05F0A9
+:104700000403DFF8D0A005EA080BBBF1000F32D09C
+:104710007869C0072FD408F101080C37B8F1060FEB
+:10472000F3D19EB9294D4946A819019201F0EAFA40
+:10473000044600283AD11836019A782EF3D149461A
+:1047400001F0E0FA0446002830D1019A4946204899
+:1047500001F0D8FA044668BB204605B0BDE8F08FEA
+:104760000029C9D101462846029201F0CBFA04463D
+:10477000E0B9029AC0E713B178694107CBD5AC071D
+:1047800002D578698007C6D5019911B1786901070A
+:10479000C1D51820494600FB08A0CDE9022301F04D
+:1047A000B1FA0446DDE902230028B4D04A460021CC
+:1047B000204601E04A460021FCF79CFECCE7024679
+:1047C000002E95D198E700BF406C00086847002094
+:1047D00038470020504700200021FFF773BF00003A
+:1047E0000121FFF76FBF0000F8B5144D0124182711
+:1047F000134E40F2FF3200210120FCF77BFE07FB45
+:10480000046001342A6955F80C1F01F067FA062C80
+:10481000F5D137254FF4C0542046FFF7E1FF01469C
+:1048200028B122460748BDE8F84001F057BAC4EB6A
+:10483000C404013D4FEAD404EED1F8BD406C000839
+:1048400050470020384700200421FFF73BBF0000FD
+:104850004843FFF7C1BF000008B101F0C5BA704777
+:1048600038B5054D00240334696855F80C0B00F089
+:10487000B5F8122CF7D138BD406C000870B5104E59
+:1048800082B0FFF797FA054601F0D6F93268034681
+:104890009042336037BF0B4A0A495168146836BFEB
+:1048A0000131D1E9004151600419284641F100016C
+:1048B0000191FFF789FA2046019902B070BD00BF4F
+:1048C000E0470020E847002070B5124E82B0FFF7A5
+:1048D00071FA054601F0B0F9326803469042336040
+:1048E00037BF0D4A0C495168146836BF0131D1E910
+:1048F000004151600419284641F100010191FFF780
+:1049000063FA4FF47A72002320460199FBF7F0FC1A
+:1049100002B070BDE0470020E84700200244074B8A
+:10492000D2B210B5904200D110BD441C00B253F871
+:10493000200041F8040BE0B2F4E700BF50400058FB
+:104940000E4B30B51C6F240405D41C6F1C671C6F04
+:1049500044F400441C670A4C02442368D2B243F476
+:1049600080732360074B904200D130BD441C51F846
+:10497000045B00B243F82050E0B2F4E70044025870
+:10498000004802585040005807B5012201A90020F4
+:10499000FFF7C4FF019803B05DF804FB13B50446AC
+:1049A000FFF7F2FFA04205D0012201A900200194E7
+:1049B000FFF7C6FF02B010BD0144BFF34F8F064B97
+:1049C000884204D3BFF34F8FBFF36F8F7047C3F894
+:1049D0005C022030F4E700BF00ED00E00144BFF3CB
+:1049E0004F8F064B884204D3BFF34F8FBFF36F8FB7
+:1049F0007047C3F870022030F4E700BF00ED00E01C
+:104A00007047000070B5054616460C46012010217F
+:104A1000FFF71EFF286046733CB1204636B1FFF712
+:104A200013FF2B68186000B19C6070BDFFF7D8FEC3
+:104A3000F7E7000070B50E461546044600B30B6854
+:104A400043608368934210D213B10068FFF704FFFC
+:104A5000637B28462BB1FFF7F7FE206020B9A060EA
+:104A600070BDFFF7BDFEF8E7A560206805F11F01E6
+:104A7000306021F01F01FFF79FFF01202073EFE757
+:104A80000120EDE710B5044640B10068884205D129
+:104A9000606808B1FCF7FCFC0023237310BD000024
+:104AA00070B50E461546044620B383689A4210D965
+:104AB00013B10068FFF7D0FE637B28462BB1FFF7E8
+:104AC000C3FE206020B9A06070BDFFF789FEF8E743
+:104AD000A560316819B12A462068FCF7D9FC206826
+:104AE00005F11F01306021F01F01FFF777FF012062
+:104AF0002073E9E70120E7E720B103688B4204BF98
+:104B0000002303737047000008B10023037370474C
+:104B1000034B1A681AB9034AD2F8D0241A607047B6
+:104B2000F04700200040025808B5FFF7F1FF024BA4
+:104B30001868C0F3806008BDF047002070B5BFF36F
+:104B40004F8FBFF36F8F1A4A0021C2F85012BFF384
+:104B50004F8FBFF36F8F536943F400335361BFF33B
+:104B60004F8FBFF36F8FC2F88410BFF34F8FD2F80F
+:104B7000803043F6E074C3F3C900C3F34E335B01E6
+:104B800003EA0406014646EA81750139C2F860521B
+:104B9000F9D2203B13F1200FF2D1BFF34F8F5369AD
+:104BA00043F480335361BFF34F8FBFF36F8F70BDFA
+:104BB00000ED00E0FEE70000214B2248224A70B5DC
+:104BC000904237D3214BC11EDA1C121A22F0030285
+:104BD0008B4238BF00220021FCF78CFC1C4A0023CA
+:104BE000C2F88430BFF34F8FD2F8803043F6E074C0
+:104BF000C3F3C900C3F34E335B0103EA0406014665
+:104C000046EA81750139C2F86C52F9D2203B13F1A2
+:104C1000200FF2D1BFF34F8FBFF36F8FBFF34F8FD2
+:104C2000BFF36F8F0023C2F85032BFF34F8FBFF333
+:104C30006F8F70BD53F8041B40F8041BC0E700BF22
+:104C4000186F0008B04A0020B04A0020B04A002087
+:104C500000ED00E003681A6899685A6043681BB168
+:104C600042EA014180681847704700004FF0A443B2
+:104C700010B51C68E00702D52848FFF7EBFFA10735
+:104C800002D52748FFF7E6FF620702D52548FFF760
+:104C9000E1FF230702D52448FFF7DCFFE00602D539
+:104CA0002248FFF7D7FFA10602D52148FFF7D2FF20
+:104CB000620602D51F48FFF7CDFF230602D51E4826
+:104CC000FFF7C8FFE00502D51C48FFF7C3FFA105A9
+:104CD00002D51B48FFF7BEFF620502D51948FFF752
+:104CE000B9FF230502D51848FFF7B4FFE00402D549
+:104CF0001648FFF7AFFFA10402D51548FFF7AAFF3A
+:104D0000620402D51348FFF7A5FF230402D5124819
+:104D1000FFF7A0FFBDE8104001F0D0B9F847002030
+:104D200004480020104800201C480020284800208B
+:104D300034480020404800204C48002058480020BB
+:104D400064480020704800207C48002088480020EB
+:104D500094480020A0480020AC48002030B5094B02
+:104D60000021094C10200725196054F8042B013844
+:104D7000C3E90121D16003F10C0311615560F4D145
+:104D800030BD00BFF4470020886C00080F28F0B544
+:104D90000AD9102806D10F230020114C01272568BD
+:104DA000984203D9002018E00346F6E707FA00F618
+:104DB000354213D10C23354343432560181D23444A
+:104DC000C3E90212074B20445A6B42F001025A63B6
+:104DD000DA6D42F00102DA65DB6DF0BD0130DFE72C
+:104DE000F4470020004502580368D968DA68C9070B
+:104DF00022F03F02DA6002D51A689207FCD507223A
+:104E00005A607047054B996B21EA000199631A6E4D
+:104E100022EA00021A661B6E704700BF0045025866
+:104E200070B5D0E9244300224FF0FF359E6804EBB3
+:104E300042135101D3F80009002805DAD3F800091C
+:104E400040F08040C3F80009D3F8000B002805DAD1
+:104E5000D3F8000B40F08040C3F8000B0132631818
+:104E60009642C3F80859C3F8085BE0D24FF001132B
+:104E7000C4F81C3870BD0000890141F020010161B7
+:104E800003699B06FCD41220FEF7AEBF10B50A4C96
+:104E90002046FEF75DFB094BC4F89030084BC4F880
+:104EA0009430084C2046FEF753FB074BC4F8903073
+:104EB000064BC4F8943010BDB848002000000840EC
+:104EC000EC6C00085449002000000440F86C000815
+:104ED00070B503780546012B58D13F4BD0F8904070
+:104EE000984254D13D4B0E2165209A6B42F00062EE
+:104EF0009A631A6E42F000621A661B6E384BD3F842
+:104F0000802042F00062C3F88020D3F8802022F095
+:104F10000062C3F88020D3F8803000F0ABFC314B46
+:104F2000E360314BC4F800380023D5F89060C4F832
+:104F3000003EC02323604FF40413A3633369002BA6
+:104F4000FCDA01230C203361FEF74EFF3369DB07E7
+:104F5000FCD41220FEF748FF3369002BFCDA002650
+:104F60002846A660FFF75CFF6B68C4F81068DB6832
+:104F7000C4F81468C4F81C6863BB1C4BA3614FF0F1
+:104F8000FF336361A36843F00103A36070BD184B56
+:104F90009842C9D1114B4FF080609A6B42F0007279
+:104FA0009A631A6E42F000721A661B6E0C4BD3F8AD
+:104FB000802042F00072C3F88020D3F8802022F0D5
+:104FC0000072C3F88020D3F88030FFF71BFF0E215A
+:104FD0004D20A2E7074BD1E7B84800200045025812
+:104FE000004402584014004003002002003C30C03E
+:104FF00054490020083C30C0F8B5D0F89040054630
+:1050000000214FF000662046FFF736FFD5F89410D8
+:1050100000234FF001128F684FF0FF30C4F834388E
+:10502000C4F81C2804EB431201339F42C2F8006904
+:10503000C2F8006BC2F80809C2F8080BF2D20B687C
+:10504000D5F89020C5F89830636210231361166973
+:1050500016F01006FBD11220FEF7C6FED4F8003879
+:1050600023F4FE63C4F80038A36943F4402343F0FB
+:105070001003A3610923C4F81038C4F814380B4B8B
+:10508000EB604FF0C043C4F8103B094BC4F8003B41
+:10509000C4F81069C4F80039D5F8983003F110024B
+:1050A00043F48013C5F89820A362F8BDC86C0008CB
+:1050B00040800010D0F8902090F88A10D2F8003884
+:1050C00023F4FE6343EA0113C2F80038704700007E
+:1050D0002DE9F84300EB8103D0F890500C46804650
+:1050E000DA680FFA81F94801166806F00306731EA4
+:1050F000022B05EB41134FF0000194BFB604384E6C
+:10510000C3F8101B4FF0010104F1100398BF06F122
+:10511000805601FA03F3916998BF06F5004600290D
+:105120003AD0578A04F15801374349016F50D5F8F6
+:105130001C180B430021C5F81C382B180127C3F895
+:105140001019A7405369611E9BB3138A928B9B0869
+:10515000012A88BF5343D8F89820981842EA03439D
+:1051600001F140022146C8F89800284605EB82026A
+:105170005360FFF781FE08EB8900C3681B8A43EA8E
+:10518000845348341E4364012E51D5F81C381F4304
+:10519000C5F81C78BDE8F88305EB4917D7F8001B64
+:1051A00021F40041C7F8001BD5F81C1821EA0303BD
+:1051B000C0E704F13F030B4A2846214605EB830371
+:1051C0005A60FFF759FE05EB4910D0F8003923F477
+:1051D0000043C0F80039D5F81C3823EA0707D7E7A1
+:1051E0000080001000040002D0F894201268C0F87B
+:1051F0009820FFF715BE00005831D0F890304901D3
+:105200005B5813F4004004D013F4001F0CBF0220BD
+:10521000012070474831D0F8903049015B5813F4B1
+:10522000004004D013F4001F0CBF0220012070477F
+:1052300000EB8101CB68196A0B6813604B685360FF
+:105240007047000000EB810330B5DD68AA69136880
+:10525000D36019B9402B84BF402313606B8A146854
+:10526000D0F890201C4402EB4110013C09B2B4FB81
+:10527000F3F46343033323F0030343EAC44343F0EB
+:10528000C043C0F8103B2B6803F00303012B0ED181
+:10529000D2F8083802EB411013F4807FD0F8003BBD
+:1052A00014BF43F0805343F00053C0F8003B02EBBF
+:1052B0004112D2F8003B43F00443C2F8003B30BD3A
+:1052C0002DE9F041D0F8906005460C4606EB4113FD
+:1052D000D3F8087B3A07C3F8087B08D5D6F814380A
+:1052E0001B0704D500EB8103DB685B689847FA076E
+:1052F0001FD5D6F81438DB071BD505EB8403D96816
+:10530000CCB98B69488A5A68B2FBF0F600FB1622CA
+:105310008AB91868DA6890420DD2121AC3E90024DB
+:10532000302383F3118821462846FFF78BFF84F34F
+:105330001188BDE8F081012303FA04F26B8923EAA6
+:1053400002036B81CB68002BF3D021462846BDE8D1
+:10535000F041184700EB81034A0170B5DD68D0F8D1
+:1053600090306C692668E66056BB1A444FF4002002
+:10537000C2F810092A6802F00302012A0AB20ED10B
+:10538000D3F8080803EB421410F4807FD4F8000926
+:1053900014BF40F0805040F00050C4F8000903EB07
+:1053A0004212D2F8000940F00440C2F8000901227C
+:1053B000D3F8340802FA01F10143C3F8341870BD80
+:1053C00019B9402E84BF4020206020681A442E8ADC
+:1053D0008419013CB4FBF6F440EAC44040F00050AC
+:1053E000C6E700002DE9F843D0F8906005460C466A
+:1053F0004F0106EB4113D3F8088918F0010FC3F8E9
+:1054000008891CD0D6F81038DB0718D500EB8103CB
+:10541000D3F80CC0DCF81430D3F800E0DA68964515
+:1054200030D2A2EB0E024FF000091A60C3F80490CC
+:10543000302383F31188FFF78DFF89F3118818F06B
+:10544000800F1DD0D6F834380126A640334217D03D
+:1054500005EB84030134D5F89050D3F80CC0E4B2C6
+:105460002F44DCF8142005EB0434D2F800E0516836
+:10547000714514D3D5F8343823EA0606C5F83468E4
+:10548000BDE8F883012303FA01F2038923EA02034A
+:105490000381DCF80830002BD1D09847CFE7AEEB82
+:1054A0000103BCF81000834228BF0346D7F818094F
+:1054B00080B2B3EB800FE3D89068A0F1040959F8EB
+:1054C000048FC4F80080A0EB09089844B8F1040FD9
+:1054D000F5D818440B4490605360C8E72DE9F84FA5
+:1054E000D0F8905004466E69AB691E4016F480589F
+:1054F0006E6103D0BDE8F84FFEF79AB8002E12DABD
+:10550000D5F8003E9B0705D0D5F8003E23F00303F5
+:10551000C5F8003ED5F80438204623F00103C5F84D
+:105520000438FEF7B3F8370505D52046FFF778FCB9
+:105530002046FEF799F8B0040CD5D5F8083813F0DA
+:10554000060FEB6823F470530CBF43F4105343F47D
+:10555000A053EB6031071BD56368DB681BB9AB69EF
+:1055600023F00803AB612378052B0CD1D5F8003E5E
+:105570009A0705D0D5F8003E23F00303C5F8003E96
+:105580002046FEF783F86368DB680BB12046984736
+:10559000F30200F1BA80B70226D5D4F89090002724
+:1055A0004FF0010A09EB4712D2F8003B03F4402305
+:1055B000B3F5802F11D1D2F8003B002B0DDA6289B0
+:1055C0000AFA07F322EA0303638104EB8703DB682B
+:1055D000DB6813B13946204698470137D4F8943038
+:1055E000FFB29B689F42DDD9F00619D5D4F8900030
+:1055F000026AC2F30A1702F00F0302F4F012B2F5C6
+:10560000802F00F0CA80B2F5402F09D104EB83034C
+:10561000002200F58050DB681B6A974240F0B080A2
+:105620003003D5F8185835D5E90303D500212046B5
+:10563000FFF746FEAA0303D501212046FFF740FEEF
+:105640006B0303D502212046FFF73AFE2F0303D553
+:1056500003212046FFF734FEE80203D5042120464B
+:10566000FFF72EFEA90203D505212046FFF728FEED
+:105670006A0203D506212046FFF722FE2B0203D53E
+:1056800007212046FFF71CFEEF0103D50821204625
+:10569000FFF716FE700340F1A780E90703D500214C
+:1056A0002046FFF79FFEAA0703D501212046FFF7FA
+:1056B00099FE6B0703D502212046FFF793FE2F07C3
+:1056C00003D503212046FFF78DFEEE0603D5042106
+:1056D0002046FFF787FEA80603D505212046FFF7E1
+:1056E00081FE690603D506212046FFF77BFE2A06C8
+:1056F00003D507212046FFF775FEEB0574D520463C
+:105700000821BDE8F84FFFF76DBED4F890904FF038
+:10571000000B4FF0010AD4F894305FFA8BF79B68C6
+:105720009F423FF638AF09EB4713D3F8002902F444
+:105730004022B2F5802F20D1D3F80029002A1CDAAC
+:10574000D3F8002942F09042C3F80029D3F8002989
+:10575000002AFBDB3946D4F89000FFF78DFB228945
+:105760000AFA07F322EA0303238104EB8703DB68C9
+:105770009B6813B13946204698470BF1010BCAE7E5
+:10578000910701D1D0F80080072A02F101029CBFE5
+:1057900003F8018B4FEA18283FE704EB830300F579
+:1057A0008050DA68D2F818C0DCF80820DCE9001C68
+:1057B000A1EB0C0C00218F4208D1DB689B699A6831
+:1057C0003A449A605A683A445A6029E711F0030F44
+:1057D00001D1D0F800808C4501F1010184BF02F8AD
+:1057E000018B4FEA1828E6E7BDE8F88F08B50348B3
+:1057F000FFF774FEBDE8084000F060BCB848002028
+:1058000008B50348FFF76AFEBDE8084000F056BC43
+:1058100054490020D0F8903003EB4111D1F8003BFF
+:1058200043F40013C1F8003B70470000D0F89030FB
+:1058300003EB4111D1F8003943F40013C1F80039EA
+:1058400070470000D0F8903003EB4111D1F8003BD5
+:1058500023F40013C1F8003B70470000D0F89030EB
+:1058600003EB4111D1F8003923F40013C1F80039DA
+:1058700070470000090100F16043012203F5614314
+:10588000C9B283F8001300F01F039A4043099B003C
+:1058900003F1604303F56143C3F880211A60704748
+:1058A00030B50433039C0172002104FB0325C16061
+:1058B000C0E90653049B0363059BC0E90000C0E9EF
+:1058C0000422C0E90842C0E90A11436330BD000068
+:1058D0000022416AC260C0E90411C0E90A226FF0E7
+:1058E0000101FEF709BB0000D0E90432934201D167
+:1058F000C2680AB9181D7047002070470369196013
+:105900000021C2680132C260C269134482699342B5
+:10591000036124BF436A0361FEF7E2BA38B5044667
+:105920000D46E3683BB162690020131D1268A36253
+:105930001344E36207E0237A33B929462046FEF791
+:10594000BFFA0028EDDA38BD6FF00100FBE7000078
+:10595000C368C269013BC3604369134482699342CF
+:10596000436124BF436A436100238362036B03B135
+:105970001847704770B53023044683F31188866A50
+:105980003EB9FFF7CBFF054618B186F311882846CC
+:1059900070BDA36AE26A13F8015B9342A36202D36B
+:1059A0002046FFF7D5FF002383F31188EFE70000BF
+:1059B0002DE9F84F04460E46174698464FF0300939
+:1059C00089F311880025AA46D4F828B0BBF1000F4E
+:1059D00009D141462046FFF7A1FF20B18BF3118882
+:1059E0002846BDE8F88FD4E90A12A7EB050B521A36
+:1059F000934528BF9346BBF1400F1BD9334601F1B5
+:105A0000400251F8040B914243F8040BF9D1A36A08
+:105A1000403640354033A362D4E90A239A4202D388
+:105A20002046FFF795FF8AF31188BD42D8D289F34B
+:105A30001188C9E730465A46FBF72AFDA36A5E443F
+:105A40005D445B44A362E7E710B5029C0433017236
+:105A500003FB0421C460C0E906130023C0E90A3334
+:105A6000039B0363049BC0E90000C0E90422C0E972
+:105A70000842436310BD0000026A6FF00101C2607A
+:105A8000426AC0E904220022C0E90A22FEF734BAC1
+:105A9000D0E904239A4201D1C26822B9184650F8CD
+:105AA000043B0B60704700231846FAE7C3680021E7
+:105AB000C2690133C36043691344826993424361FD
+:105AC00024BF436A4361FEF70BBA000038B50446B1
+:105AD0000D46E3683BB1236900201A1DA262E2690A
+:105AE0001344E36207E0237A33B929462046FEF7E0
+:105AF000E7F90028EDDA38BD6FF00100FBE70000A0
+:105B000003691960C268013AC260C26913448269BC
+:105B10009342036124BF436A036100238362036BE2
+:105B200003B118477047000070B530230D46044696
+:105B3000114683F31188866A2EB9FFF7C7FF10B1AB
+:105B400086F3118870BDA36A1D70A36AE26A0133EF
+:105B50009342A36204D3E16920460439FFF7D0FFE2
+:105B6000002080F31188EDE72DE9F84F04460D463B
+:105B7000904699464FF0300A8AF311880026B346C2
+:105B8000A76A4FB949462046FFF7A0FF20B187F327
+:105B900011883046BDE8F88FD4E90A073A1AA8EB15
+:105BA0000607974228BF1746402F1BD905F140032F
+:105BB00055F8042B9D4240F8042BF9D1A36A4036D6
+:105BC0004033A362D4E90A239A4204D3E169204610
+:105BD0000439FFF795FF8BF311884645D9D28AF334
+:105BE0001188CDE729463A46FBF752FCA36A3D44AB
+:105BF0003E443B44A362E5E7D0E904239A4217D12F
+:105C0000C3689BB1836A8BB1043B9B1A0ED01360AF
+:105C1000C368013BC360C3691A4483699A42026145
+:105C200024BF436A0361002383620123184670473F
+:105C30000023FBE700F06CBA014B586A704700BFC5
+:105C4000000C0040034B002258631A610222DA6004
+:105C5000704700BF000C0040014B0022DA60704723
+:105C6000000C0040014B5863704700BF000C00401F
+:105C7000024B034A1A60034A5A607047084A0020E0
+:105C8000B04A002000000220074B494210B55C6872
+:105C9000201A08401968821A8A4203D3A24201D806
+:105CA0005A6010BD0020FCE7084A002008B53023E8
+:105CB00083F31188FFF7E8FF002383F3118808BD01
+:105CC00004480121044B03600023C0E901330C3078
+:105CD000FEF708B8104A0020AD5C0008CB1D083A5A
+:105CE00023F00703591A521A012110B4D2080024D4
+:105CF000C0E9004384600C301C605A605DF8044BBE
+:105D0000FDF7F0BF2DE9F84F364ECD1D0F460028A8
+:105D100018BF0646082A4FEAD50538BF082206F103
+:105D20000C08341D91464046FDF7F8FF09F10701C4
+:105D3000C9F1000E224624686CB94046FDF7F8FF11
+:105D40003368CBB308224946E8009847044698B325
+:105D500040E9026730E004EB010CD4F804A00CEA3F
+:105D60000E0C0AF10100ACF1080304EBC0009842EC
+:105D7000E0D9A0EB0C0CB5EBEC0F4FEAEC0BD9D84B
+:105D80009C421CD204F10802AB45A3EB02024FEA8D
+:105D9000E202626009D9691CED43206803EBC1028D
+:105DA0005D44556043F8310022601C465F60404608
+:105DB00044F8086BFDF7BCFF2046BDE8F88FAA4504
+:105DC000216802D111602346EFE7013504EBC503DA
+:105DD00044F8351003F10801401AC01058601360F0
+:105DE000F1E700BF104A0020F8B550F8043C044623
+:105DF00050F8085CA0F1080607332F1D0C35DB08AE
+:105E000040F8043C2846FDF789FF3B469F421A684C
+:105E100001D0B34228D20AB1964225D244F8082CC8
+:105E200054F8042C1E60013254F8081C06EBC20022
+:105E3000814206D14868024444F8042C0A6844F8B8
+:105E4000082C5868411C03EBC1018E4207D154F85D
+:105E5000042C013202445A6054F8082C1A60284677
+:105E6000BDE8F840FDF764BF1346CFE7FEE700004A
+:105E700070B51B4B0025044686B058600E468562FF
+:105E8000016300F0F3F804F11003A560E562C4E9D2
+:105E900004334FF0FF33C4E90044C4E90635FFF78B
+:105EA000CBFE2B46024604F134012046C4E9082308
+:105EB00080230C4A2565FDF7A1FF01230A4AE06013
+:105EC00000920375684672680192B268CDE90223B8
+:105ED000064BCDE90435FDF7B9FF06B070BD00BF34
+:105EE000F82B0020046D0008096D00086D5E0008A5
+:105EF000024AD36A1843D062704700BF902900203D
+:105F00004B6843608B688360CB68C3600B694361F7
+:105F10004B6903628B6943620B6803607047000042
+:105F200008B5324B40F2FF70196C014319649A6E48
+:105F300002432F489A662F4A9B6E1146FFF7E0FFF7
+:105F400000F5806002F11C01FFF7DAFF00F58060C8
+:105F500002F13801FFF7D4FF00F5806002F154012F
+:105F6000FFF7CEFF00F5806002F17001FFF7C8FF78
+:105F700000F5806002F18C01FFF7C2FF00F5806040
+:105F800002F1A801FFF7BCFF00F5806002F1C40137
+:105F9000FFF7B6FF00F5806002F1E001FFF7B0FF08
+:105FA00000F5806002F1FC01FFF7AAFF02F58C7199
+:105FB00000F58060FFF7A4FF00F06CF90E4BD3F8FA
+:105FC000902242F00102C3F89022D3F8942242F0CA
+:105FD0000102C3F894220522C3F898204FF06052C2
+:105FE000C3F89C20054AC3F8A02008BD004502580C
+:105FF00000000258106D000800ED00E01F000803CB
+:1060000008B500F033FBFDF7A9FE0D4BDA6B42F04B
+:106010004002DA635A6E22F040025A665B6E094B08
+:106020001A6842F008021A601A6842F004021A6004
+:10603000FEF76EFDFEF7D8FBBDE80840FEF748B955
+:10604000004502580018024870470000EFF309832A
+:10605000054968334A6B22F001024A6383F30988D9
+:10606000002383F31188704700EF00E0302080F3B5
+:10607000118862B60D4B0E4AD96821F4E06109041B
+:10608000090C0A430B49DA60D3F8FC2042F0807215
+:10609000C3F8FC20084AC2F8B01F116841F00101A2
+:1060A00011602022DA7783F82200704700ED00E0CB
+:1060B0000003FA0555CEACC5001000E0302310B542
+:1060C00083F311880E4B5B6813F4006314D0F1EE78
+:1060D000103AEFF309844FF08073683CE361094B99
+:1060E000DB6B236684F30988FDF7D0FD10B1064B06
+:1060F000A36110BD054BFBE783F31188F9E700BFEF
+:1061000000ED00E000EF00E043070008460700084C
+:106110000E4B9A6C42F008029A641A6F42F0080221
+:106120001A670B4A1B6FD36B43F00803D363C72274
+:10613000084B9A624FF0FF32DA6200229A615A638A
+:10614000DA605A6001225A611A60704700450258AD
+:106150000010005C000C0040094A08B51169D368C2
+:106160000B40D9B29B076FEA0101116107D53023BB
+:1061700083F31188FDF71CFE002383F3118808BD0B
+:10618000000C0040044BDA6B0243DA635A6E104392
+:1061900058665B6E704700BF0045025808B53C4B1F
+:1061A0004FF0FF31D3F8802062F00042C3F8802026
+:1061B000D3F8802002F00042C3F88020D3F880207A
+:1061C000D3F88420C3F88410D3F884200022C3F8C5
+:1061D0008420D3F88400D86F40F0FF4040F4FF00E3
+:1061E00040F4DF4040F07F00D867D86F20F0FF40D8
+:1061F00020F4FF0020F4DF4020F07F00D867D86F44
+:10620000D3F888006FEA40506FEA5050C3F8880016
+:10621000D3F88800C0F30A00C3F88800D3F88800D8
+:10622000D3F89000C3F89010D3F89000C3F89020F2
+:10623000D3F89000D3F89400C3F89410D3F89400E6
+:10624000C3F89420D3F89400D3F89800C3F89810BA
+:10625000D3F89800C3F89820D3F89800D3F88C00AE
+:10626000C3F88C10D3F88C00C3F88C20D3F88C00C2
+:10627000D3F89C00C3F89C10D3F89C10C3F89C2062
+:10628000D3F89C30FEF76AFDBDE8084000F0BEB9C7
+:106290000044025808B50122504BC3F80821504B66
+:1062A0005A6D42F002025A65DA6F42F00202DA6772
+:1062B0000422DB6F4B4BDA605A689104FCD54A4AE2
+:1062C0001A6001229A60494ADA6000221A614FF48A
+:1062D00040429A61434B9A699204FCD51A6842F491
+:1062E00080721A60424B1A6F12F4407F04D04FF450
+:1062F00080321A6700221A671A6842F001021A6097
+:106300003B4B1A685007FCD500221A611A6912F03B
+:106310003802FBD1012119604FF0804159605A6762
+:10632000344ADA62344A1A611A6842F480321A60D6
+:106330002F4B1A689103FCD51A6842F480521A60F8
+:106340001A689204FCD52D4A2D499A6200225A639C
+:10635000196301F57C01DA6301F5E77199635A6409
+:10636000284A1A64284ADA621A6842F0A8521A6067
+:106370001F4B1A6802F02852B2F1285FF9D1482267
+:106380009A614FF48862DA6140221A621F4ADA6425
+:106390001F4A1A651F4A5A651F4A9A6532231F4AC7
+:1063A0001360136803F00F03022BFAD1104A13692C
+:1063B00043F003031361136903F03803182BFAD178
+:1063C0004FF00050FFF7DEFE4FF08040FFF7DAFE9F
+:1063D0004FF00040BDE80840FFF7D4BE00800051F8
+:1063E000004502580048025800C000F004000001B7
+:1063F000004402580000FF0100889008322060002D
+:1064000063020901470E0508DD0BBF0120000020D3
+:10641000000001100910E0000001011000200052EE
+:106420004FF0B04208B5D2F8883003F00103C2F84B
+:10643000883023B1044A13680BB150689847BDE80F
+:106440000840FFF73BBE00BF284A00204FF0B04293
+:1064500008B5D2F8883003F00203C2F8883023B1BF
+:10646000044A93680BB1D0689847BDE80840FFF72D
+:1064700025BE00BF284A00204FF0B04208B5D2F830
+:10648000883003F00403C2F8883023B1044A13694A
+:106490000BB150699847BDE80840FFF70FBE00BF39
+:1064A000284A00204FF0B04208B5D2F8883003F0F7
+:1064B0000803C2F8883023B1044A93690BB1D0694C
+:1064C0009847BDE80840FFF7F9BD00BF284A002003
+:1064D0004FF0B04208B5D2F8883003F01003C2F88C
+:1064E000883023B1044A136A0BB1506A9847BDE85B
+:1064F0000840FFF7E3BD00BF284A00204FF0B0433B
+:1065000010B5D3F8884004F47872C3F88820A30645
+:1065100004D5124A936A0BB1D06A9847600604D535
+:106520000E4A136B0BB1506B9847210604D50B4AEA
+:10653000936B0BB1D06B9847E20504D5074A136CF7
+:106540000BB1506C9847A30504D5044A936C0BB16A
+:10655000D06C9847BDE81040FFF7B0BD284A002036
+:106560004FF0B04310B5D3F8884004F47C42C3F830
+:106570008820620504D5164A136D0BB1506D9847FB
+:10658000230504D5124A936D0BB1D06D9847E004F2
+:1065900004D50F4A136E0BB1506E9847A10404D571
+:1065A0000B4A936E0BB1D06E9847620404D5084A2B
+:1065B000136F0BB1506F9847230404D5044A936FAF
+:1065C0000BB1D06F9847BDE81040FFF777BD00BF13
+:1065D000284A002008B50348FCF71AFBBDE808402C
+:1065E000FFF76CBD0425002008B50348FCF7BCFB91
+:1065F000BDE80840FFF762BD2425002008B5FFF77D
+:10660000ABFDBDE80840FFF759BD0000062108B505
+:106610000846FFF72FF906210720FFF72BF906217F
+:106620000820FFF727F906210920FFF723F90621A3
+:106630000A20FFF71FF906211720FFF71BF9062193
+:106640002820FFF717F909217A20FFF713F90A210B
+:106650005C20FFF70FF907213220FFF70BF90C211F
+:106660002620BDE80840FFF705B9000008B5FFF790
+:1066700095FD00F00FF8FCF78FFDFCF767FFFCF7C6
+:1066800039FEFDF7FDF9FFF7DFFCBDE80840FFF735
+:10669000D1BA00000023054A19460133102BC2E984
+:1066A000001102F10802F8D1704700BF284A00200B
+:1066B0000B460146184600F027B80000FEF7CCB89C
+:1066C000FFF7FCBF012838BF012010B50446204663
+:1066D000FEF782F830B900F007F808B900F00CF8BE
+:1066E0008047F4E710BD0000024B1868BFF35B8FD2
+:1066F000704700BFA84A002008B5062000F04AF8FD
+:106700000120FDF733FD000010B5054C13462CB1F8
+:106710000A4601460220AFF3008010BD2046FCE788
+:106720000000000010B501390244904201D1002060
+:1067300005E0037811F8014FA34201D0181B10BDEA
+:106740000130F2E71F2938B504460D4604D9162357
+:1067500003604FF0FF3038BD426C12B152F8213067
+:106760004BB9204600F030F82A4601462046BDE8E5
+:10677000384000F017B8012B0AD0591C03D116235A
+:1067800003600120E7E7002442F8254028469847A7
+:106790000020E0E7024B01461868FFF7D3BF00BFB7
+:1067A0006422002038B5074D0023044608461146F0
+:1067B0002B60FDF7DFFC431C02D12B6803B1236083
+:1067C00038BD00BFAC4A0020FDF7CEBC034611F82F
+:1067D000012B03F8012B002AF9D1704700000000BB
+:1067E00001000000000100010000000000000000A6
+:1067F0000000000052657175657374656420746FE4
+:10680000206572617365206D6F7265207468616EBA
+:106810002077652063616E0A0045726173652043CD
+:106820006F6D6D616E642052656365697665640A9B
+:106830000050435420444F4E453A2025640A00003E
+:1068400053544D333248373F3F3F0053544D33325A
+:10685000483733782F3732780053544D3332483726
+:1068600034332F3735332F373530000001105A00BD
+:10687000031059000120580003205600534644508D
+:10688000000000004A454445433A204661696C6572
+:106890006420746F2064657465637420666C617332
+:1068A00068206465766963653A2025730A004A4565
+:1068B0004445433A204661696C656420746F2063E7
+:1068C0006F6E66696720666C6173682064657669BF
+:1068D00063653A2025730A004A454445433A2044FB
+:1068E0006574656374656420466C617368204465F3
+:1068F000766963653A2025730A0045787420466CF2
+:10690000617368204E6F7420466F756E64210000BD
+:106910006D74323571007732357100773235712DF3
+:10692000647472001069000820BA000000000000C2
+:1069300016690008EF400000000000001B69000815
+:10694000EF700000000000000000000000000000E8
+:106950004D1D0008B51F0008691600086D160008D7
+:10696000151700081D1F000871160008751600088D
+:10697000151E0008E5160008751E0008591B0008C2
+:106980007D160008791600084D200008DD16000865
+:1069900000000000000000000000000000000000F7
+:1069A000452100088924000889240008492100089D
+:1069B0004D210008512100085521000889240008B4
+:1069C00089240008892400086D210008712100082D
+:1069D00089210008912100089D210008A1210008BB
+:1069E000A52100080425002001000000000000008F
+:1069F00000000000DD220008F52200084521000803
+:106A0000B121000829230008E5210008C12300085E
+:106A1000F123000855210008C9210008B52100080C
+:106A2000C52100086D210008712100088921000896
+:106A3000912100089D210008A1210008A52100083E
+:106A4000CD21000800000000000000005D220008C9
+:106A5000A9210008AD21000800000000000000008E
+:106A600051250008592500083D2500084525000846
+:106A7000692500086D250008286E756C6C290000DA
+:106A800000000000ED290008C5290008752900084C
+:106A900091290008AD2900084D444D4120666169E7
+:106AA0006C75726500000000009600000000000098
+:106AB00000000000000000000000000000000000D6
+:106AC00000000000593100084531000881310008FC
+:106AD0006D31000879310008653100085131000836
+:106AE0003D3100088D3100080000000071320008BF
+:106AF0005D320008993200088532000891320008A2
+:106B00007D3200086932000855320008A5320008BD
+:106B100000000000010000000000000063300000E1
+:106B20001C6B0008E8290020F82B002043756265E3
+:106B300050696C6F7400437562655265642D424CF8
+:106B4000002553455249414C250000000200000039
+:106B500000000000913400080135000840004000AA
+:106B6000A8440020B84400200200000000000000FB
+:106B7000030000000000000049350008000000008C
+:106B800010000000C84400200000000001000000C8
+:106B900000000000B8480020010102006D4200081A
+:106BA0007D41000819420008FD4100084300000033
+:106BB000B46B000809024300020100C0320904005E
+:106BC000000102020100052400100105240100015A
+:106BD000042402020524060001070582030800FFC1
+:106BE00009040100020A000000070501024000003C
+:106BF000070581024000000012000000006C000840
+:106C00001201100102000040AE2D591000020102D5
+:106C1000030100000403090425424F4152442500AA
+:106C2000437562655265645072696D6172790030B6
+:106C300031323334353637383941424344454600E2
+:106C400000000020000002000200000000010030EF
+:106C50000000000008000000000000240000080000
+:106C6000040000000004000000FC0000020000001E
+:106C70000000043000800000080000000000003820
+:106C8000000001000100000040000052800000529E
+:106C9000C000005200010052400100528001005229
+:106CA000C001005200020052400200528002005215
+:106CB000C002005200030052400300528003005201
+:106CC000C00300520004005200000000A536000876
+:106CD0005D390008093A000840004000F0490020F2
+:106CE000F049002001000000004A00208000000060
+:106CF000400100000800000000010000001000003A
+:106D0000080000006D61696E0069646C6500000038
+:106D10000000802A00000000AAAAAAAA00000024FD
+:106D2000FFFF00000000000000A00A00200020007B
+:106D300000000000AAAAAAAA00000000FFFF0000AD
+:106D40000009000000090000000000000000000031
+:106D5000AAAAAAAA00000000FFFF0000000000008D
+:106D6000000000000028800A00000000AAAAAAAAC9
+:106D700000140000FFFF0000000070070090990061
+:106D80002000000000000000AAAAAAAA000000003B
+:106D9000FFFF0000000900000000000010000000DC
+:106DA00000000000AAAAAAAA00000000FBFF000041
+:106DB00000000000000000000104000000000000CE
+:106DC000AAAAAAAA00000000FEFF0000000000001E
+:106DD000000000000000000000000000AAAAAAAA0B
+:106DE00000000000FFFF00000000000000000000A5
+:106DF0000000000000000000AAAAAAAA00000000EB
+:106E0000FFFF000000000000000000000000000084
+:106E100000000000AAAAAAAA00000000FFFF0000CC
+:106E20000000000000000000000000000000000062
+:106E3000AAAAAAAA00000000FFFF000000000000AC
+:106E400000000000DC94FF7F010000000000000053
+:106E50002D0400000000000000001A0000000002E5
+:106E6000FF000000002C002024250020000000006E
+:106E700040680008830400004B68000850040000CC
+:106E80005968000800960000000008009600000005
+:106E90000008000004000000146C0008000000005E
+:106EA00000000000000000000000000000000000E2
+:106EB0000000000068220020000000000000000028
+:106EC00000000000000000000000000000000000C2
+:106ED00000000000000000000000000000000000B2
+:106EE00000000000000000000000000000000000A2
+:106EF0000000000000000000000000000000000092
+:106F00000000000000000000000000000000000081
+:086F1000000000000000000079
+:00000001FF
diff --git a/Tools/bootloaders/CubeRedSecondary_bl.bin b/Tools/bootloaders/CubeRedSecondary_bl.bin
new file mode 100755
index 00000000000000..403e7e859e420b
Binary files /dev/null and b/Tools/bootloaders/CubeRedSecondary_bl.bin differ
diff --git a/Tools/bootloaders/CubeRedSecondary_bl.hex b/Tools/bootloaders/CubeRedSecondary_bl.hex
new file mode 100644
index 00000000000000..6f4adbe5be9c81
--- /dev/null
+++ b/Tools/bootloaders/CubeRedSecondary_bl.hex
@@ -0,0 +1,667 @@
+:020000040800F2
+:1000000000060020E1020008E3020008E302000805
+:10001000E3020008E3020008E3020008E30200082C
+:10002000E3020008E3020008E3020008F1200008F0
+:10003000E3020008E3020008E3020008E30200080C
+:10004000E3020008E3020008E3020008E3020008FC
+:10005000E3020008E3020008BD240008E9240008C8
+:1000600015250008412500086D250008E302000859
+:10007000E3020008E3020008E3020008E3020008CC
+:10008000E3020008E3020008E3020008E3020008BC
+:10009000E3020008E3020008E302000899250008D3
+:1000A000E3020008E3020008E3020008E30200089C
+:1000B000E3020008E3020008E3020008E30200088C
+:1000C000E3020008E3020008E3020008E30200087C
+:1000D000E3020008E3020008E3020008E30200086C
+:1000E000FD250008E3020008E3020008E30200081F
+:1000F000E3020008E3020008E3020008E30200084C
+:10010000E3020008E302000899260008E302000861
+:10011000E3020008E3020008E3020008E30200082B
+:10012000E3020008E3020008E3020008E30200081B
+:10013000E3020008E3020008E3020008E30200080B
+:10014000E3020008E3020008E3020008E3020008FB
+:10015000E3020008E3020008E3020008E3020008EB
+:10016000E3020008E3020008E3020008E3020008DB
+:10017000E3020008E3020008E3020008E3020008CB
+:10018000E3020008E3020008712600088526000843
+:10019000E3020008E3020008E3020008E3020008AB
+:1001A000E3020008E3020008E3020008E30200089B
+:1001B000E3020008E3020008E3020008E30200088B
+:1001C000E3020008E3020008E3020008E30200087B
+:1001D000E3020008E3020008E3020008E30200086B
+:1001E000E3020008E3020008E3020008E30200085B
+:1001F000E3020008E3020008E3020008E30200084B
+:10020000E3020008E3020008E3020008E30200083A
+:10021000E3020008E3020008E3020008E30200082A
+:10022000E3020008E3020008E3020008E30200081A
+:10023000E3020008E3020008E3020008E30200080A
+:10024000E3020008E3020008E3020008E3020008FA
+:10025000E3020008E3020008E3020008E3020008EA
+:10026000E3020008E3020008E3020008E3020008DA
+:10027000E3020008E3020008E3020008E3020008CA
+:10028000E3020008E3020008E3020008E3020008BA
+:10029000E3020008E3020008E3020008E3020008AA
+:1002A000E3020008E3020008E3020008E30200089A
+:1002B000E3020008E3020008E3020008E30200088A
+:1002C000E3020008E3020008E3020008E30200087A
+:1002D000E3020008E3020008E3020008E30200086A
+:1002E00002E000F000F8FEE772B6374880F30888B5
+:1002F000364880F3098836483649086040F20000E5
+:10030000CCF200004EF63471CEF200010860BFF36B
+:100310004F8FBFF36F8F40F20000C0F2F0004EF637
+:100320008851CEF200010860BFF34F8FBFF36F8F8B
+:100330004FF00000E1EE100A4EF63C71CEF20001E3
+:100340000860062080F31488BFF36F8F01F028FD4A
+:1003500001F02AFE4FF055301F491B4A91423CBF25
+:1003600041F8040BFAE71D49184A91423CBF41F895
+:10037000040BFAE71A491B4A1B4B9A423EBF51F83D
+:10038000040B42F8040BF8E700201849184A914280
+:100390003CBF41F8040BFAE701F040FD01F086FE96
+:1003A000144C154DAC4203DA54F8041B8847F9E7A6
+:1003B00000F042F8114C124DAC4203DA54F8041B21
+:1003C0008847F9E701F028BD000600200022002040
+:1003D0000000000808ED00E00000002000060020FA
+:1003E000582900080022002030220020302200205E
+:1003F000702F0020E0020008E0020008E002000880
+:10040000E00200082DE9F04F2DED108AC1F80CD064
+:10041000D0F80CD0BDEC108ABDE8F08F002383F338
+:1004200011882846A047002001F08CF9FEE701F072
+:10043000FFF800DFFEE7000038B500F0ADFB01F08B
+:100440006FFC054601F0A2FC0446D0B90F4B9D425B
+:1004500019D001339D4242F2107512BF04460025A7
+:100460000124002001F066FC0CB100F077F800F0E8
+:1004700023FD00F0EFFB284600F0F0F800F06EF8E6
+:10048000F9E70025EDE70546EBE700BF010007B0FF
+:1004900008B500F0ABFBA0F120035842584108BD5D
+:1004A00007B541F21203022101A8ADF8043000F0B3
+:1004B000BBFB03B05DF804FB38B5302383F3118830
+:1004C000174803680BB101F0FBF90023154A4FF4FC
+:1004D0007A71134801F0EAF9002383F31188124C72
+:1004E000236813B12368013B2360636813B1636819
+:1004F000013B63600D4D2B7833B963687BB90220F3
+:1005000000F070FC322363602B78032B07D1636803
+:100510002BB9022000F066FC4FF47A73636038BD9B
+:1005200030220020B9040008502300204822002077
+:10053000084B187003280CD8DFE800F00805020803
+:10054000022000F045BC022000F038BC024B002223
+:100550005A6070474822002050230020F8B5394BDC
+:10056000394A1C46196801316BD004339342F9D1E2
+:100570006268364B9A4264D9354B9B6803F100633D
+:1005800003F500339A425CD2002000F089FB022080
+:10059000FFF7CEFF2F4B00219A6C99641A6F1967F1
+:1005A0001A6FDA6CD9645A6F59675A6F1A6D1965E8
+:1005B0009A6F99679B6F72B64FF0E023C3F8084DAE
+:1005C000D4E90004BFF34F8FBFF36F8F224AC2F804
+:1005D0008410BFF34F8F536923F480335361BFF30B
+:1005E0004F8FD2F8803043F6E076C3F3C905C3F3EA
+:1005F0004E335B0103EA060C29464CEA8177013948
+:10060000C2F87472F9D2203B13F1200FF2D1BFF37C
+:100610004F8FBFF36F8FBFF34F8FBFF36F8F536950
+:1006200023F4003353610023C2F85032BFF34F8FDD
+:10063000BFF36F8F302383F31188854680F30888DA
+:100640002047F8BD0000020820000208FFFF010853
+:10065000002200200045025800ED00E02DE9F04F97
+:1006600093B0B44B2022FF2100900AA89D6800F0AF
+:10067000CDFBB14A1378A3B90121B04811700360D2
+:10068000302383F3118803680BB101F019F90023BB
+:10069000AB4A4FF47A71A94801F008F9002383F3BB
+:1006A0001188009B13B1A74B009A1A60A64A1378D1
+:1006B000032B03D000231370A24A53604FF0000AAB
+:1006C000009CD3465646D146012000F081FB24B160
+:1006D0009C4B1B68002B00F02682002000F086FA5D
+:1006E0000390039B002BF2DB012000F067FB039BD0
+:1006F000213B1F2BE8D801A252F823F07D07000808
+:10070000A507000839080008C9060008C90600083E
+:10071000C9060008CB0800089B0A0008B5090008B4
+:10072000170A00083F0A0008650A0008C906000801
+:10073000770A0008C9060008E90A00081D08000831
+:10074000C90600082D0B0008890700081D080008CD
+:10075000C9060008170A0008C9060008C9060008EB
+:10076000C9060008C9060008C9060008C90600082D
+:10077000C9060008C9060008390800080220FFF76A
+:1007800087FE002840F0F981009B022105A8BAF1FC
+:10079000000F08BF1C4641F21233ADF8143000F0D0
+:1007A00043FA91E74FF47A7000F020FA071EEBDB72
+:1007B0000220FFF76DFE0028E6D0013F052F00F272
+:1007C000DE81DFE807F0030A0D101336052304214C
+:1007D00005A8059300F028FA17E004215548F9E729
+:1007E00004215A48F6E704215948F3E74FF01C0862
+:1007F000404608F1040800F055FA0421059005A8C8
+:1008000000F012FAB8F12C0FF2D101204FF00009DC
+:1008100000FA07F747EA0B0B5FFA8BFB00F042FB8D
+:1008200026B10BF00B030B2B08BF0024FFF738FE9B
+:100830004AE704214748CDE7002EA5D00BF00B0373
+:100840000B2BA1D10220FFF723FE074600289BD0E7
+:100850000120002600F024FA0220FFF769FE5FFA6B
+:1008600086F8404600F02CFA0446B0B103994046A1
+:100870000136A1F140025142514100F031FA002805
+:10088000EDD1BA46044641F21213022105A83E46B4
+:10089000ADF8143000F0C8F916E725460120FFF73F
+:1008A00047FE244B9B68AB4207D9284600F0FAF973
+:1008B000013040F067810435F3E70025224BBA464A
+:1008C0003E461D701F4B5D60A8E7002E3FF45CAFF5
+:1008D0000BF00B030B2B7FF457AF0220FFF728FE22
+:1008E000322000F083F9B0F10008FFF64DAF18F0A8
+:1008F00003077FF449AF0F4A08EB05039268934260
+:100900003FF642AFB8F5807F3FF73EAF124BB84598
+:10091000019323DD4FF47A7000F068F90390039A95
+:10092000002AFFF631AF039A0137019B03F8012B30
+:10093000EDE700BF002200204C23002030220020E1
+:10094000B90400085023002048220020042200207F
+:10095000082200200C2200204C220020C820FFF793
+:1009600097FD074600283FF40FAF1F2D11D8C5F1A2
+:1009700020020AAB25F0030084494245184428BFF1
+:100980004246019200F038FA019AFF217F4800F0B8
+:100990003DFA4FEAA803C8F387027C492846019331
+:1009A00000F03CFA064600283FF46DAF019B05EBD2
+:1009B000830533E70220FFF76BFD00283FF4E4AE28
+:1009C00000F0ACF900283FF4DFAE0027B846704BCA
+:1009D0009B68BB4218D91F2F11D80A9B01330ED038
+:1009E00027F0030312AA134453F8203C0593404612
+:1009F000042205A9043700F087FA8046E7E7384665
+:100A000000F050F90590F2E7CDF81480042105A814
+:100A100000F00AF902E70023642104A8049300F01F
+:100A2000F9F800287FF4B0AE0220FFF731FD00286E
+:100A30003FF4AAAE049800F067F90590E6E70023BA
+:100A4000642104A8049300F0E5F800287FF49CAE2C
+:100A50000220FFF71DFD00283FF496AE049800F039
+:100A600055F9EAE70220FFF713FD00283FF48CAEAA
+:100A700000F064F9E1E70220FFF70AFD00283FF4E7
+:100A800083AE05A9142000F05FF907460421049005
+:100A900004A800F0C9F83946B9E7322000F0A6F8FA
+:100AA000071EFFF671AEBB077FF46EAE384A07EB48
+:100AB0000903926893423FF667AE0220FFF7E8FC15
+:100AC00000283FF461AE27F003074F44B9453FF4D7
+:100AD000A5AE484609F1040900F0E4F804210590A8
+:100AE00005A800F0A1F8F1E74FF47A70FFF7D0FC09
+:100AF00000283FF449AE00F011F9002844D00A9BC9
+:100B000001330BD008220AA9002000F087F9002841
+:100B10003AD02022FF210AA800F078F9FFF7C0FCA4
+:100B20001C4800F015FE13B0BDE8F08F002E3FF416
+:100B30002BAE0BF00B030B2B7FF426AE00236421AE
+:100B400005A8059300F066F8074600287FF41CAE60
+:100B50000220FFF79DFC804600283FF415AEFFF70A
+:100B60009FFC41F2883000F0F3FD059800F0B2F9E7
+:100B700046463C4600F096F9A6E506464EE64FF09E
+:100B8000000901E6BA467EE637467CE64C220020A4
+:100B900000220020A086010070470000104B70B5B5
+:100BA0001B780C460133DBB2012B12D80D4B1D68AC
+:100BB0004FF47A732968A2FB033222460E6A01467B
+:100BC0002846B047844204D1074B002201201A7006
+:100BD00070BD4FF4FA7000F0BBFD0020F8E700BFD5
+:100BE00010220020142200209C230020002307B59F
+:100BF000024601210DF107008DF80730FFF7CEFF07
+:100C000020B19DF8070003B05DF804FB4FF0FF3002
+:100C1000F9E700000A46042108B5FFF7BFFF80F09E
+:100C20000100C0B2404208BD074B0A4630B41978F3
+:100C3000064B53F82140014623682046DD69044BEA
+:100C4000AC4630BC604700BF9C230020142200202B
+:100C5000A086010070B5104C0025104E00F038FF42
+:100C600020803068238883420CD8002520880138F2
+:100C700000F02AFF23880544013BB5F5802F23802F
+:100C8000F4D370BD00F020FF336805440133B5F59F
+:100C9000003F3360E5D3E8E79E230020582300207F
+:100CA00000F0F4BF00F1006000F50030006870470C
+:100CB00000F10060920000F5003000F06BBF000012
+:100CC000054B1A68054B1B889B1A834202D91044B6
+:100CD00000F0FABE00207047582300209E23002019
+:100CE00038B50446074D29B128682044BDE838408E
+:100CF00000F002BF2868204400F0ECFE0028F3D08A
+:100D000038BD00BF582300200020704700F1FF507D
+:100D100000F58F10D0F8000870470000064991F8E0
+:100D2000243033B100230822086A81F82430FFF709
+:100D3000BFBF0120704700BF5C230020014B186833
+:100D4000704700BF0010005C194B013803220844B3
+:100D500070B51D68174BC5F30B042D0C1E88A642F9
+:100D60000BD15C680A46013C824213460FD214F94B
+:100D7000016F4EB102F8016BF6E7013A03F1080387
+:100D8000ECD181420B4602D22C2203F8012B042421
+:100D9000094A1688AE4204D1984284BF967803F877
+:100DA000016B013C02F10402F3D1581A70BD00BF7F
+:100DB0000010005C18220020B8270008022803D188
+:100DC000024B4FF080629A61704700BF000C0258DE
+:100DD000022803D1024B4FF480629A61704700BF32
+:100DE000000C0258022804D1024A536983F480633C
+:100DF00053617047000C0258002310B5934203D092
+:100E0000CC5CC4540133F9E710BD00000244034632
+:100E1000934202D003F8011BFAE770472DE9F8432B
+:100E20001F4D14460746884695F8242052BBDFF82C
+:100E300070909CB395F824302BB92022FF214846AE
+:100E40002F62FFF7E3FF95F824004146C0F1080246
+:100E500005EB8000A24228BF2246D6B29200FFF7DF
+:100E6000CBFF95F82430A41B17441E449044E4B2F1
+:100E7000F6B2082E85F82460DBD1FFF74FFF00287B
+:100E8000D7D108E02B6A03EB82038342CFD0FFF770
+:100E900045FF0028CBD10020BDE8F8830120FBE707
+:100EA0005C230020024B1A78024B1A70704700BF77
+:100EB0009C23002010220020034B04490B60044BAC
+:100EC000186800F01BBB00BF80841E008423002034
+:100ED00014220020094B1822002110B504461846A0
+:100EE000FFF794FF064A074B01461278046053F857
+:100EF0002200BDE8104000F001BB00BF84230020A9
+:100F00009C2300201422002030B50A44084D914251
+:100F10000DD011F8013B5840082340F30004013B79
+:100F20002C4013F0FF0384EA5000F6D1EFE730BD08
+:100F30002083B8ED026843681143016003B118478C
+:100F400070470000024A136843F0C0031360704703
+:100F500000780040024A136843F0C00313607047F2
+:100F6000007C004037B51A4C1A4D204600F0BAFA02
+:100F700004F11400009400234FF40072164900F0AD
+:100F800077F94FF40072154904F138000094144BBE
+:100F900000F0F0F9134BC4E91735134C204600F06C
+:100FA000A1FA04F1140000234FF400720F490094D9
+:100FB00000F05EF90E4B4FF400720E4904F1380058
+:100FC000009400F0D7F90C4BC4E9173503B030BDDD
+:100FD000A023002000E1F5057824002078280020D7
+:100FE000450F0008007800400C24002078260020DF
+:100FF000550F0008782A0020007C0040037C30B5A3
+:10100000274C002918BF0C46012B0CD1254B9842C8
+:1010100036D1254B9A6C42F080429A641A6F42F0A6
+:1010200080421A671B6F2268036EC16D03EB520387
+:101030008466B3FBF2F36268150442BF23F0070530
+:1010400003F0070343EA4503CB60A36843F0400382
+:101050004B60E36843F001038B6042F4967343F006
+:1010600001030B604FF0FF330B62510505D512F001
+:10107000102211D0B2F1805F10D080F8643030BD02
+:101080000A4B9842CFD1084B9A6C42F000429A64C6
+:101090001A6F42F00042C4E77F23EEE73F23ECE7FC
+:1010A000C8270008A0230020004502580C24002077
+:1010B0002DE9F047C66D05463768F46921073462AB
+:1010C0001AD014F0080118BF4FF48071E20748BF2E
+:1010D00041F02001A3074FF0300348BF41F0400129
+:1010E000600748BF41F0800183F31188281DFFF796
+:1010F00021FF002383F31188E2050AD5302383F30F
+:1011000011884FF48061281DFFF714FF002383F33B
+:1011100011884FF030094FF0000A14F0200838D140
+:101120003B0616D54FF0300905F1380A200610D5D8
+:1011300089F31188504600F051F9002836DA082169
+:10114000281DFFF7F7FE27F080033360002383F3A9
+:101150001188790614D5620612D5302383F31188DD
+:10116000D5E913239A4208D12B6C33B127F04007FD
+:101170001021281DFFF7DEFE3760002383F311885E
+:10118000E30618D5AA6E1369ABB15069BDE8F04704
+:10119000184789F31188736A284695F86410194036
+:1011A00000F0BAF98AF31188F469B6E7B06288F3FF
+:1011B0001188F469BAE7BDE8F0870000F8B5154674
+:1011C000826804460B46AA4200D28568A169266956
+:1011D000761AB5420BD218462A46FFF70DFEA369D0
+:1011E0002B44A3612846A3685B1BA360F8BD0CD900
+:1011F000AF1B18463246FFF7FFFD3A46E168304420
+:10120000FFF7FAFDE3683B44EBE718462A46FFF791
+:10121000F3FDE368E5E7000083689342F7B5044611
+:10122000154600D28568D4E90460361AB5420BD25F
+:101230002A46FFF7E1FD63692B4463612846A368F2
+:101240005B1BA36003B0F0BD0DD93246AF1B01910B
+:10125000FFF7D2FD01993A46E0683144FFF7CCFD33
+:10126000E3683B44E9E72A46FFF7C6FDE368E4E7A5
+:1012700010B50A440024C361029B8460C16002610E
+:101280000362C0E90000C0E9051110BD08B5D0E94E
+:101290000532934201D1826882B98268013282604C
+:1012A0005A1C426119700021D0E904329A4224BFCD
+:1012B000C368436100F068FA002008BD4FF0FF30BA
+:1012C000FBE7000070B5302304460E4683F3118817
+:1012D000A568A5B1A368A269013BA360531CA361E3
+:1012E00015782269934224BFE368A361E3690BB1D7
+:1012F00020469847002383F31188284607E03146AB
+:10130000204600F031FA0028E2DA85F3118870BD3A
+:101310002DE9F74F04460E4617469846D0F81C9024
+:101320004FF0300A8AF311884FF0000B154665B173
+:101330002A4631462046FFF741FF034660B9414641
+:10134000204600F011FA0028F1D0002383F3118821
+:10135000781B03B0BDE8F08FB9F1000F03D0019006
+:101360002046C847019B8BF31188ED1A1E448AF36F
+:101370001188DCE7C160C361009B82600362C0E941
+:1013800005111144C0E9000001617047F8B5044639
+:101390000D461646302383F31188A768A7B1A368CA
+:1013A000013BA36063695A1C62611D70D4E9043279
+:1013B0009A4224BFE3686361E3690BB12046984712
+:1013C000002080F3118807E03146204600F0CCF978
+:1013D0000028E2DA87F31188F8BD0000D0E9052380
+:1013E00010B59A4201D182687AB98268002101322F
+:1013F00082605A1C82611C7803699A4224BFC368C8
+:10140000836100F0C1F9204610BD4FF0FF30FBE7CB
+:101410002DE9F74F04460E4617469846D0F81C9023
+:101420004FF0300A8AF311884FF0000B154665B172
+:101430002A4631462046FFF7EFFE034660B9414693
+:10144000204600F091F90028F1D0002383F31188A1
+:10145000781B03B0BDE8F08FB9F1000F03D0019005
+:101460002046C847019B8BF31188ED1A1E448AF36E
+:101470001188DCE7026843681143016003B1184733
+:10148000704700001430FFF743BF00004FF0FF33F8
+:101490001430FFF73DBF00003830FFF7B9BF000040
+:1014A0004FF0FF333830FFF7B3BF00001430FFF7C1
+:1014B00009BF00004FF0FF311430FFF703BF0000F9
+:1014C0003830FFF763BF00004FF0FF323830FFF7CE
+:1014D0005DBF0000012914BF6FF0130000207047AA
+:1014E000FFF740BD044B036000234360C0E90233B3
+:1014F00001230374704700BFE027000810B53023B4
+:10150000044683F31188FFF779FD0223002023743A
+:1015100080F3118810BD000038B5C36904460D463C
+:101520001BB904210844FFF7A5FF294604F1140064
+:10153000FFF7ACFE002806DA201D4FF40061BDE87D
+:101540003840FFF797BF38BD0023826803750369F1
+:101550001B6899689142FBD25A6803604260106030
+:101560005860704700238268037503691B68996897
+:101570009142FBD85A68036042601060586070471F
+:1015800008B50846302383F311880B7D032B05D063
+:10159000042B0DD02BB983F3118808BD8B69002271
+:1015A0001A604FF0FF338361FFF7CEFF0023F2E7AD
+:1015B000D1E9003213605A60F3E70000FFF7C4BFBF
+:1015C000054BD96808751868026853601A600122D3
+:1015D000D8600275FEF716BF782C00200C4B30B592
+:1015E000DD684B1C87B004460FD02B46094A68467D
+:1015F00000F05CF92046FFF7E3FF009B13B168465B
+:1016000000F05EF9A86907B030BDFFF7D9FFF9E730
+:10161000782C002081150008044B1A68DB6890685C
+:101620009B68984294BF002001207047782C0020CE
+:10163000084B10B51C68D868226853601A600122F4
+:10164000DC602275FFF78EFF01462046BDE81040A2
+:10165000FEF7D8BE782C0020044B1A68DB6892682D
+:101660009B689A4201D9FFF7E3BF7047782C0020AE
+:1016700038B5074C012300250649074823706560EB
+:1016800000F03AFC0223237085F3118838BD00BFB7
+:10169000E02E00200C280008782C002000F046B92D
+:1016A000EFF3118020B9EFF30583302282F3118824
+:1016B0007047000010B530B9EFF30584C4F3080497
+:1016C00014B180F3118810BDFFF7C6FF84F31188B1
+:1016D000F9E700008B600223086108468B8270479F
+:1016E0008368A3F1840243F8142C026943F8442C64
+:1016F000426943F8402C094A43F8242CC268A3F1FC
+:10170000200043F8182C022203F80C2C002203F8C6
+:101710000B2C034A43F8102C704700BF1D0400082F
+:10172000782C002008B5FFF7DBFFBDE80840FFF785
+:1017300045BF0000024BDB6898610F20FFF740BFF8
+:10174000782C0020302383F31188FFF7F3BF0000CB
+:1017500008B50146302383F311880820FFF73EFFC8
+:10176000002383F3118808BD064BDB6839B142685A
+:1017700018605A60136043600420FFF72FBF4FF0DA
+:10178000FF307047782C00200368984206D01A6812
+:101790000260506018469961FFF710BF7047000063
+:1017A000036810B59C68A2420CD85C688A600B6024
+:1017B0004C602160596099688A1A9A604FF0FF3333
+:1017C000836010BD121B1B68ECE700000A2938BFBC
+:1017D0000A2170B504460D460A26601900F084FB04
+:1017E00000F06CFB041BA54203D8751C04462E4672
+:1017F000F3E70A2E04D90120BDE8704000F0BCBB1D
+:1018000070BD0000F8B5144B0D460A2A4FF00A07C8
+:10181000D96103F11001826038BF0A224160196961
+:101820001446016048601861A81800F04DFB00F0F4
+:1018300045FB431B0646A34206D37C1C28192746BA
+:10184000354600F051FBF2E70A2F04D90120BDE82C
+:10185000F84000F091BBF8BD782C0020F8B50646A2
+:101860000D4600F02BFB0F4A134653F8107F9F42A2
+:1018700006D12A4601463046BDE8F840FFF7C2BF10
+:10188000D169BB68441A2C1928BF2C46A34202D93F
+:101890002946FFF79BFF224631460348BDE8F84042
+:1018A000FFF77EBF782C0020882C0020C0E903239E
+:1018B000002310B45DF8044B4361FFF7CFBF000075
+:1018C00010B5194C236998420DD08168D0E90032D7
+:1018D00013605A609A680A449A60002303604FF0CC
+:1018E000FF33A36110BD0268234643F8102F5360F5
+:1018F0000022026022699A4203D1BDE8104000F044
+:10190000EDBA936881680B44936000F0D7FA2269BE
+:10191000E1699268441AA242E4D91144BDE810403A
+:10192000091AFFF753BF00BF782C00202DE9F047BC
+:10193000DFF8BC8008F110072C4ED8F8105000F0EA
+:10194000BDFAD8F81C40AA68031B9A423ED814443A
+:101950004FF00009D5E90032C8F81C4013605A6006
+:10196000C5F80090D8F81030B34201D100F0B6FAB3
+:1019700089F31188D5E9033128469847302383F34A
+:1019800011886B69002BD8D000F098FA6A69A0EB37
+:10199000040982464A450DD2022000F0EDFA0022E9
+:1019A000D8F81030B34208D151462846BDE8F04778
+:1019B000FFF728BF121A2244F2E712EB0909294661
+:1019C000384638BF4A46FFF7EBFEB5E7D8F8103087
+:1019D000B34208D01444C8F81C00211AA960BDE81D
+:1019E000F047FFF7F3BEBDE8F08700BF882C00206A
+:1019F000782C002000207047FEE7000070470000B0
+:101A00004FF0FF3070470000BFF34F8F044B1A694F
+:101A10005107FCD1D3F810215207F8D1704700BF0D
+:101A20000020005208B50D4B1B78ABB9FFF7ECFF57
+:101A30000B4BDA68D10704D50A4A5A6002F18832A2
+:101A40005A60D3F80C21D20706D5064AC3F8042100
+:101A500002F18832C3F8042108BD00BFE82E00203F
+:101A6000002000522301674508B5114B1B78F3B9DC
+:101A7000104B1A69510703D5DA6842F04002DA6068
+:101A8000D3F81021520705D5D3F80C2142F04002BB
+:101A9000C3F80C21FFF7B8FF064BDA6842F00102E9
+:101AA000DA60D3F80C2142F00102C3F80C2108BD22
+:101AB000E82E0020002000520F289ABF00F5806019
+:101AC00040040020704700004FF4003070470000D1
+:101AD000102070470F2808B50BD8FFF7EDFF00F571
+:101AE00000330268013204D104308342F9D101206D
+:101AF00008BD0020FCE700000F2870B5054645D85A
+:101B0000FFF7CEFD224CFFF77FFF0646FFF78AFF67
+:101B10004FF0FF33072D6361C4F8143120D82361DF
+:101B2000FFF772FF2B0243F02403E360E36843F006
+:101B30008003E36023695A07FCD42846FFF764FF5B
+:101B40004FF40031FFF7B8FF00F002F93046FFF71D
+:101B50008BFFFFF7AFFD2846BDE87040FFF7BABF27
+:101B6000C4F81031FFF750FFA5F108031B0243F042
+:101B70002403C4F80C31D4F80C3143F08003C4F8CA
+:101B80000C31D4F810315B07FBD4D6E7002070BDD0
+:101B9000002000522DE9F84F40EA020305460C46AA
+:101BA0001746D80602D00020BDE8F88F27F01F079F
+:101BB000DFF8D4B0FFF736FF2744BC4203D1012041
+:101BC000FFF752FFF0E720222946204600F0CEFD25
+:101BD00010B920352034F0E72B4605F120021E68AD
+:101BE000711CE0D104339A42F9D1FFF759FD05F198
+:101BF0007843234AB3F5801F224B28BF9A4603F14E
+:101C0000040338BF9046A2F1080228BF9846A3F10A
+:101C100008033ABF9146DA469946FFF7F5FEC8F841
+:101C20000060A5EB040CD9F8002004F11C0142F07F
+:101C30000202C9F80020221FDAF8006016F005063B
+:101C4000FAD152F8043F8A424CF80230F4D1BFF383
+:101C50004F8FFFF7D9FE4FF0FF32C8F80020D9F8B8
+:101C6000002022F00202C9F80020FFF723FD202205
+:101C70002146284600F07AFD0028AAD030469FE78A
+:101C800014200052102100521020005210B5084CB0
+:101C9000237828B11BB9FFF7C5FE0123237010BDBF
+:101CA000002BFCD02070BDE81040FFF7DDBE00BF68
+:101CB000E82E00200244074BD2B210B5904200D16A
+:101CC00010BD441C00B253F8200041F8040BE0B2F0
+:101CD000F4E700BF504000580E4B30B51C6F240491
+:101CE00005D41C6F1C671C6F44F400441C670A4C2D
+:101CF00002442368D2B243F480732360074B9042BE
+:101D000000D130BD441C51F8045B00B243F82050B0
+:101D1000E0B2F4E70044025800480258504000582E
+:101D200007B5012201A90020FFF7C4FF019803B005
+:101D30005DF804FB13B50446FFF7F2FFA04205D09F
+:101D4000012201A900200194FFF7C6FF02B010BDD7
+:101D50000144BFF34F8F064B884204D3BFF34F8F2C
+:101D6000BFF36F8F7047C3F85C022030F4E700BF09
+:101D700000ED00E0034B1A681AB9034AD2F8D024E8
+:101D80001A607047EC2E00200040025808B5FFF79B
+:101D9000F1FF024B1868C0F3806008BDEC2E0020F4
+:101DA00070B5BFF34F8FBFF36F8F1A4A0021C2F88F
+:101DB0005012BFF34F8FBFF36F8F536943F400335B
+:101DC0005361BFF34F8FBFF36F8FC2F88410BFF31F
+:101DD0004F8FD2F8803043F6E074C3F3C900C3F3E9
+:101DE0004E335B0103EA0406014646EA8175013978
+:101DF000C2F86052F9D2203B13F1200FF2D1BFF3A9
+:101E00004F8F536943F480335361BFF34F8FBFF358
+:101E10006F8F70BD00ED00E0FEE70000214B22480F
+:101E2000224A70B5904237D3214BC11EDA1C121AD8
+:101E300022F003028B4238BF00220021FEF7E6FFAA
+:101E40001C4A0023C2F88430BFF34F8FD2F8803091
+:101E500043F6E074C3F3C900C3F34E335B0103EAF6
+:101E60000406014646EA81750139C2F86C52F9D27E
+:101E7000203B13F1200FF2D1BFF34F8FBFF36F8FD1
+:101E8000BFF34F8FBFF36F8F0023C2F85032BFF301
+:101E90004F8FBFF36F8F70BD53F8041B40F8041BC6
+:101EA000C0E700BF88290008702F0020702F002095
+:101EB000702F002000ED00E000F07CB9014B586A63
+:101EC000704700BF000C0040034B002258631A61AA
+:101ED0000222DA60704700BF000C0040014B002274
+:101EE000DA607047000C0040014B5863704700BF38
+:101EF000000C0040FEE7000070B51B4B00250446B7
+:101F000086B058600E468562016300F001F904F165
+:101F10001003A560E562C4E904334FF0FF33C4E960
+:101F20000044C4E90635FFF7C9FF2B46024604F119
+:101F300034012046C4E9082380230C4A2565FFF7B5
+:101F4000C9FB01230A4AE060009203756846726883
+:101F50000192B268CDE90223064BCDE90435FFF7C3
+:101F6000E1FB06B070BD00BFE02E0020182800087D
+:101F70001D280008F51E0008024AD36A1843D062E3
+:101F8000704700BF782C00204B6843608B688360EB
+:101F9000CB68C3600B6943614B6903628B69436221
+:101FA0000B6803607047000008B53A4B40F2FF71C0
+:101FB0003948D3F888200A43C3F88820D3F888200A
+:101FC00022F4FF6222F00702C3F88820D3F8883099
+:101FD000324B1A6C0A431A649A6E0A439A66304A64
+:101FE0009B6E1146FFF7D0FF00F5806002F11C01E7
+:101FF000FFF7CAFF00F5806002F13801FFF7C4FF68
+:1020000000F5806002F15401FFF7BEFF00F580602B
+:1020100002F17001FFF7B8FF00F5806002F18C015A
+:10202000FFF7B2FF00F5806002F1A801FFF7ACFFF7
+:1020300000F5806002F1C401FFF7A6FF00F58060A3
+:1020400002F1E001FFF7A0FF00F5806002F1FC0162
+:10205000FFF79AFF02F58C7100F58060FFF794FF9F
+:1020600000F066F90F4BD3F8902242F00102C3F85A
+:102070009022D3F8942242F00102C3F89422052260
+:10208000C3F898204FF06052C3F89C20064AC3F86A
+:10209000A02008BD00440258000002580045025824
+:1020A0002428000800ED00E01F00080308B500F038
+:1020B00041FBFFF7DDFA0B4BDA6B42F04002DA63CB
+:1020C0005A6E22F040025A665B6E074B1A6842F065
+:1020D00008021A601A6842F004021A60BDE808405B
+:1020E000FFF748BE0045025800180248704700003C
+:1020F000EFF30983054968334A6B22F001024A6312
+:1021000083F30988002383F31188704700EF00E010
+:10211000302080F3118862B60D4B0E4AD96821F445
+:10212000E0610904090C0A430B49DA60D3F8FC208A
+:1021300042F08072C3F8FC20084AC2F8B01F116850
+:1021400041F0010111602022DA7783F82200704704
+:1021500000ED00E00003FA0555CEACC5001000E02C
+:10216000302310B583F311880E4B5B6813F40063C2
+:1021700014D0F1EE103AEFF309844FF08073683C0D
+:10218000E361094BDB6B236684F30988FFF744FAAC
+:1021900010B1064BA36110BD054BFBE783F311881B
+:1021A000F9E700BF00ED00E000EF00E02F040008B9
+:1021B000320400080E4B9A6C42F008029A641A6FBF
+:1021C00042F008021A670B4A1B6FD36B43F00803F7
+:1021D000D363C722084B9A624FF0FF32DA620022C3
+:1021E0009A615A63DA605A6001225A611A60704734
+:1021F000004502580010005C000C0040094A08B578
+:102200001169D3680B40D9B29B076FEA01011161D4
+:1022100007D5302383F31188FFF740FA002383F3B7
+:10222000118808BD000C0040044BDA6B0243DA63EE
+:102230005A6E104358665B6E704700BF00450258E7
+:102240003A4B4FF0FF31D3F8802062F00042C3F8E0
+:102250008020D3F8802002F00042C3F88020D3F819
+:102260008020D3F88420C3F88410D3F8842000227F
+:10227000C3F88420D3F88400D86F40F0FF4040F4C6
+:10228000FF0040F4DF4040F07F00D867D86F20F0B7
+:10229000FF4020F4FF0020F4DF4020F07F00D867EB
+:1022A000D86FD3F888006FEA40506FEA5050C3F8F7
+:1022B0008800D3F88800C0F30A00C3F88800D3F878
+:1022C0008800D3F89000C3F89010D3F89000C3F8BA
+:1022D0009020D3F89000D3F89400C3F89410D3F86A
+:1022E0009400C3F89420D3F89400D3F89800C3F86E
+:1022F0009810D3F89800C3F89820D3F89800D3F832
+:102300008C00C3F88C10D3F88C00C3F88C20D3F861
+:102310008C00D3F89C00C3F89C10D3F89C10C3F831
+:102320009C20D3F89C3000F0BFB900BF0044025895
+:1023300008B50122504BC3F80821504B5A6D42F0AA
+:1023400002025A65DA6F42F00202DA670422DB6F9A
+:102350004B4BDA605A689104FCD54A4A1A60012254
+:102360009A60494ADA6000221A614FF440429A6149
+:10237000434B9A699204FCD51A6842F480721A6041
+:10238000424B1A6F12F4407F04D04FF480321A6728
+:1023900000221A671A6842F001021A603B4B1A6861
+:1023A0005007FCD500221A611A6912F03802FBD1DD
+:1023B000012119604FF0804159605A67344ADA624E
+:1023C000344A1A611A6842F480321A602F4B1A6834
+:1023D0009103FCD51A6842F480521A601A6892047C
+:1023E000FCD52D4A2D499A6200225A63196301F5E2
+:1023F0007C01DA6301F5E77199635A64284A1A642B
+:10240000284ADA621A6842F0A8521A601F4B1A680A
+:1024100002F02852B2F1285FF9D148229A614FF4B4
+:102420008862DA6140221A621F4ADA641F4A1A651A
+:102430001F4A5A651F4A9A6532231F4A1360136860
+:1024400003F00F03022BFAD1104A136943F0030380
+:102450001361136903F03803182BFAD14FF00050C1
+:10246000FFF7E2FE4FF08040FFF7DEFE4FF0004046
+:10247000BDE80840FFF7D8BE008000510045025873
+:102480000048025800C000F0040000010044025857
+:102490000000FF01008890083220600063020901FB
+:1024A000470E0508DD0BBF012000002000000110D1
+:1024B0000910E00000010110002000524FF0B0426E
+:1024C00008B5D2F8883003F00103C2F8883023B190
+:1024D000044A13680BB150689847BDE80840FFF7FD
+:1024E0003FBE00BFF02E00204FF0B04208B5D2F83A
+:1024F000883003F00203C2F8883023B1044A93689D
+:102500000BB1D0689847BDE80840FFF729BE00BF6F
+:10251000F02E00204FF0B04208B5D2F8883003F01A
+:102520000403C2F8883023B1044A13690BB150691F
+:102530009847BDE80840FFF713BE00BFF02E00200B
+:102540004FF0B04208B5D2F8883003F00803C2F863
+:10255000883023B1044A93690BB1D0699847BDE82C
+:102560000840FFF7FDBD00BFF02E00204FF0B04245
+:1025700008B5D2F8883003F01003C2F8883023B1D0
+:10258000044A136A0BB1506A9847BDE80840FFF748
+:10259000E7BD00BFF02E00204FF0B04310B5D3F8D8
+:1025A000884004F47872C3F88820A30604D5124A40
+:1025B000936A0BB1D06A9847600604D50E4A136B34
+:1025C0000BB1506B9847210604D50B4A936B0BB1A6
+:1025D000D06B9847E20504D5074A136C0BB1506CD9
+:1025E0009847A30504D5044A936C0BB1D06C984767
+:1025F000BDE81040FFF7B4BDF02E00204FF0B0430F
+:1026000010B5D3F8884004F47C42C3F888206205F2
+:1026100004D5164A136D0BB1506D9847230504D5A8
+:10262000124A936D0BB1D06D9847E00404D50F4A60
+:10263000136E0BB1506E9847A10404D50B4A936EEC
+:102640000BB1D06E9847620404D5084A136F0BB1E2
+:10265000506F9847230404D5044A936F0BB1D06F91
+:102660009847BDE81040FFF77BBD00BFF02E00206B
+:1026700008B50348FEF71CFDBDE80840FFF770BD34
+:10268000A023002008B50348FEF712FDBDE808406E
+:10269000FFF766BD0C24002008B5FFF7AFFDBDE8CD
+:1026A0000840FFF75DBD0000062108B5084600F0B0
+:1026B0002BF80621072000F027F80621082000F05B
+:1026C00023F80621092000F01FF806210A2000F057
+:1026D0001BF80621172000F017F80621282000F02B
+:1026E00013F809217A2000F00FF80721322000F0BA
+:1026F0000BF80C21522000F007F80C215320BDE804
+:10270000084000F001B80000090100F16043012217
+:1027100003F56143C9B283F8001300F01F039A4028
+:1027200043099B0003F1604303F56143C3F8802133
+:102730001A60704708B5FFF783FD00F009F8FEF74F
+:10274000CFFEFFF7D3FCBDE80840FFF7B5BB0000A4
+:102750000023054A19460133102BC2E9001102F18A
+:102760000802F8D1704700BFF02E002010B50139E3
+:102770000244904201D1002005E0037811F8014F96
+:10278000A34201D0181B10BD0130F2E753544D3362
+:102790003248373F3F3F0053544D33324837337848
+:1027A0002F3732780053544D3332483734332F3774
+:1027B00035332F373530000001105A00031059000F
+:1027C0000120580003205600009600000000000081
+:1027D00000000000000000000000000000000000F9
+:1027E00000000000A11400088D140008C91400089E
+:1027F000B5140008C1140008AD14000899140008AD
+:1028000085140008D514000863300000082800086B
+:10281000D02C0020E02E00206D61696E0069646C90
+:10282000650000000000002800000000AAAAAAAA73
+:1028300000000024FFFF0000000000000000000076
+:102840000000000000000000AAAAAAAA00000000E0
+:10285000FFFF00000000000000000000000000007A
+:1028600000000000AAAAAAAA00000000FFFF0000C2
+:102870000000000000000000000010000000000048
+:10288000AAAAAAAA00000000FFFF000000000000A2
+:10289000000000000A80020000000000AAAAAAAA04
+:1028A00005400100FFFF00008800007007000000E5
+:1028B0000000000000000000AAAAAAAA0000000070
+:1028C000FFFF00000000000000000000000000000A
+:1028D00000000000AAAAAAAA00000000FFFF000052
+:1028E00000000000000000000000000000000000E8
+:1028F000AAAAAAAA00000000FFFF00000000000032
+:10290000000000000000000000000000AAAAAAAA1F
+:1029100000000000FFFF00000000000000000000B9
+:102920000000000000000000AAAAAAAA00000000FF
+:10293000FFFF000000000000000000000000000099
+:1029400000000000AAAAAAAA00000000FFFF0000E1
+:1029500000000000000000002E0400000000000045
+:1029600000001A0000000000FF000000A02300206B
+:10297000000000008C27000883040000972700084F
+:0829800050040000A527000827
+:00000001FF
diff --git a/Tools/bootloaders/FlyingMoonF407_bl.hex b/Tools/bootloaders/FlyingMoonF407_bl.hex
new file mode 100644
index 00000000000000..41779613836713
--- /dev/null
+++ b/Tools/bootloaders/FlyingMoonF407_bl.hex
@@ -0,0 +1,1008 @@
+:020000040800F2
+:1000000000060020E1010008E3010008E301000808
+:10001000E3010008E3010008E3010008E301000830
+:10002000E3010008E3010008E30100081D360008B1
+:10003000E3010008E3010008E3010008E301000810
+:10004000E3010008E3010008E3010008E301000800
+:10005000E3010008E3010008C9380008F13800088E
+:10006000193900084139000869390008E30100081E
+:10007000E3010008E3010008E3010008E3010008D0
+:10008000E3010008E3010008E3010008E3010008C0
+:10009000E3010008E3010008E301000891390008CA
+:1000A000E3010008E3010008E3010008E3010008A0
+:1000B000E3010008E3010008E3010008E301000890
+:1000C000E3010008E3010008E3010008E301000880
+:1000D000E3010008E3010008E3010008E301000870
+:1000E000F5390008E3010008E3010008E301000816
+:1000F000E3010008E3010008E3010008E301000850
+:10010000E3010008E3010008793A0008E301000870
+:10011000E3010008653A0008E3010008E301000874
+:10012000E3010008E3010008E3010008E30100081F
+:10013000E3010008E3010008E3010008E30100080F
+:10014000E3010008E3010008E3010008C52D0008F1
+:10015000E3010008E3010008E3010008E3010008EF
+:10016000E3010008E3010008E3010008E3010008DF
+:10017000E3010008E3010008E3010008E3010008CF
+:10018000E3010008E3010008E3010008E3010008BF
+:10019000E3010008E3010008E3010008E3010008AF
+:1001A000E3010008E3010008E3010008E30100089F
+:1001B000E3010008E3010008E3010008E30100088F
+:1001C000E3010008E3010008E3010008E30100087F
+:1001D000E3010008E3010008E3010008E30100086F
+:1001E00002E000F000F8FEE772B6374880F30888B6
+:1001F000364880F3098836483649086040F20000E6
+:10020000CCF200004EF63471CEF200010860BFF36C
+:100210004F8FBFF36F8F40F20000C0F2F0004EF638
+:100220008851CEF200010860BFF34F8FBFF36F8F8C
+:100230004FF00000E1EE100A4EF63C71CEF20001E4
+:100240000860062080F31488BFF36F8F02F082FAF3
+:1002500003F082F94FF055301F491B4A91423CBFD1
+:1002600041F8040BFAE71D49184A91423CBF41F896
+:10027000040BFAE71A491B4A1B4B9A423EBF51F83E
+:10028000040B42F8040BF8E700201849184A914281
+:100290003CBF41F8040BFAE702F060FA03F0B0F952
+:1002A000144C154DAC4203DA54F8041B8847F9E7A7
+:1002B00000F042F8114C124DAC4203DA54F8041B22
+:1002C0008847F9E702F048BA000600200022002023
+:1002D0000000000808ED00E00000002000060020FB
+:1002E000883E0008002200204C22002050220020DE
+:1002F000F0300020E0010008E0010008E001000803
+:10030000E00100082DE9F04F2DED108AC1F80CD066
+:10031000C3689D46BDEC108ABDE8F08F002383F3CF
+:1003200011882846A047002001F0B0FDFEE701F04B
+:1003300019FD00DFFEE7000038B502F0DBF90546E5
+:1003400002F0FEF90446D8B90F4B9D421AD0013392
+:100350009D4218BF044641F2883504BF01240025A0
+:10036000002002F0D1F90CB100F076F800F012FD97
+:1003700000F0AEFB284600F0B7F800F06DF8F9E7A2
+:100380000025EDE70546EBE7010007B008B500F0F2
+:100390006BFBA0F120035842584108BD07B541F25C
+:1003A0001203022101A8ADF8043000F07BFB03B07A
+:1003B0005DF804FB38B5302383F3118817480368D0
+:1003C0000BB101F02FFE164A144800234FF47A7146
+:1003D00001F01EFE002383F31188124C236813B131
+:1003E0002368013B2360636813B16368013B63606A
+:1003F0000D4D2B7833B963687BB9022000F03CFCCB
+:10040000322363602B78032B07D163682BB902205A
+:1004100000F032FC4FF47A73636038BD5022002044
+:10042000B50300087023002068220020084B1870D4
+:1004300003280CD8DFE800F008050208022000F0CD
+:100440000BBC022000F0FABB024B00225A6070473E
+:1004500068220020702300201F4B204A10B51C4644
+:100460001968013136D004339342F9D16268A2424F
+:1004700030D31B4B9B6803F1006303F580439A4222
+:1004800028D2002000F03EFB0220FFF7CFFF154BE3
+:100490001A6C00221A64196E1A66196E596C5A6425
+:1004A000596E5A665A6E1A6942F000521A611A69F8
+:1004B00022F000521A611B6972B64FF0E02330211E
+:1004C000C3F8084DD4E9003281F311889D4683F3C7
+:1004D0000888104710BD00BF0040000820400008F9
+:1004E00000220020003802402DE9F04F93B0AA4BC3
+:1004F00000902022FF210AA89D6800F0F5FBA74A82
+:100500001378A3B9A648012103601170302383F347
+:10051000118803680BB101F085FDA24AA0480023B1
+:100520004FF47A7101F074FD002383F31188009B6E
+:1005300013B19D4B009A1A609C4A009C1378032BC0
+:100540001EBF00231370984A4FF0000A18BF536073
+:10055000D3465646D146012000F07EFB24B1924B93
+:100560001B68002B00F01182002000F07DFA039040
+:10057000039B002BF2DB012000F060FB039B213B7F
+:10058000162BE8D801A252F823F000BFE9050008B5
+:1005900011060008A50600085705000857050008C1
+:1005A000570500082F070008FF0800081908000871
+:1005B0007B080008A3080008C908000857050008C0
+:1005C000DB080008570500084D09000889060008E7
+:1005D0005705000891090008F5050008890600087C
+:1005E000570500087B0800080220FFF7CFFE00280F
+:1005F00040F0F581009B0221BAF1000F08BF1C46B4
+:1006000005A841F21233ADF8143000F04BFAA2E71E
+:100610004FF47A7000F028FA071EEBDB0220FFF798
+:10062000B5FE0028E6D0013F052F00F2DA81DFE8B1
+:1006300007F0030A0D10133605230593042105A8BE
+:1006400000F030FA17E054480421F9E75848042133
+:10065000F6E758480421F3E74FF01C08404600F045
+:1006600053FA08F104080590042105A800F01AFACD
+:10067000B8F12C0FF2D1012000FA07F747EA0B0B73
+:100680005FFA8BFB4FF0000900F07AFB26B10BF00C
+:100690000B030B2B08BF0024FFF780FE5BE74648E7
+:1006A0000421CDE7002EA5D00BF00B030B2BA1D11D
+:1006B0000220FFF76BFE074600289BD0012000F0C8
+:1006C00021FA0220FFF7B2FE00265FFA86F84046C4
+:1006D00000F028FA044690B10021404600F032FABA
+:1006E00001360028F1D1BA46044641F21213022124
+:1006F00005A8ADF814303E4600F0D4F92BE70120F0
+:10070000FFF794FE2546244B9B68AB4207D9284649
+:1007100000F0FAF9013040F067810435F3E7234B2C
+:1007200000251D70204BBA465D603E46ACE7002EAA
+:100730003FF460AF0BF00B030B2B7FF45BAF022099
+:10074000FFF774FE322000F08FF9B0F10008FFF6D9
+:1007500051AF18F003077FF44DAF0F4A926808EBD2
+:10076000050393423FF646AFB8F5807F3FF742AFAF
+:10077000124B0193B84523DD4FF47A7000F074F901
+:100780000390039A002AFFF635AF019B039A03F802
+:10079000012B0137EDE700BF002200206C23002071
+:1007A00050220020B503000870230020682200209A
+:1007B00004220020082200200C2200206C220020AD
+:1007C000C820FFF7E3FD074600283FF413AF1F2DB5
+:1007D00011D8C5F1200242450AAB25F0030028BF1D
+:1007E000424683490192184400F058FA019A804821
+:1007F000FF2100F079FA4FEAA8037D490193C8F37D
+:100800008702284600F078FA064600283FF46DAFCC
+:10081000019B05EB830537E70220FFF7B7FD0028B2
+:100820003FF4E8AE00F0BAF900283FF4E3AE002749
+:10083000B846704B9B68BB4218D91F2F11D80A9B32
+:1008400001330ED027F0030312AA134453F8203CBF
+:1008500005934046042205A900F0FEFA04378046BD
+:10086000E7E7384600F050F90590F2E7CDF814803C
+:10087000042105A800F016F906E70023642104A866
+:10088000049300F005F900287FF4B4AE0220FFF7CE
+:100890007DFD00283FF4AEAE049800F067F90590A6
+:1008A000E6E70023642104A8049300F0F1F800288F
+:1008B0007FF4A0AE0220FFF769FD00283FF49AAE56
+:1008C000049800F063F9EAE70220FFF75FFD0028D3
+:1008D0003FF490AE00F072F9E1E70220FFF756FD19
+:1008E00000283FF487AE05A9142000F06DF904211B
+:1008F0000746049004A800F0D5F83946B9E732203D
+:1009000000F0B2F8071EFFF675AEBB077FF472AEBB
+:10091000384A926807EB090393423FF66BAE022018
+:10092000FFF734FD00283FF465AE27F003074F447E
+:10093000B9453FF4A9AE484600F0E6F80421059019
+:1009400005A800F0AFF809F10409F1E74FF47A7057
+:10095000FFF71CFD00283FF44DAE00F01FF9002802
+:1009600044D00A9B01330BD008220AA9002000F0D2
+:10097000C3F900283AD02022FF210AA800F0B4F9D8
+:10098000FFF70CFD1C4801F087FA13B0BDE8F08FAB
+:10099000002E3FF42FAE0BF00B030B2B7FF42AAE8F
+:1009A0000023642105A8059300F072F8074600288B
+:1009B0007FF420AE0220FFF7E9FC804600283FF4D8
+:1009C00019AEFFF7EBFC41F2883001F065FA0598AB
+:1009D00000F020FA464600F0D3F93C46BBE5064657
+:1009E00052E64FF0000905E6BA467EE637467CE659
+:1009F0006C22002000220020A08601002DE9F84F83
+:100A00004FF47A73DFF85880DFF8589006460D46A9
+:100A100002FB03F7002498F900305A1C5FFA84FAAD
+:100A200001D0A34212D159F8240003682A46D3F812
+:100A300020B031463B46D847854207D1074B0120BD
+:100A400083F800A0BDE8F88F0124E4E7002CFBD078
+:100A50004FF4FA7001F020FA0020F3E7B8230020E9
+:100A6000102200201422002007B500230246012195
+:100A70000DF107008DF80730FFF7C0FF20B19DF89A
+:100A8000070003B05DF804FB4FF0FF30F9E700000A
+:100A90000A4608B50421FFF7B1FF80F00100C0B29B
+:100AA000404208BD30B4074B0A461978064B53F84C
+:100AB00021402368DD69054B0146AC46204630BC29
+:100AC000604700BFB823002014220020A086010048
+:100AD00070B501F001FD094E094D308000242868F1
+:100AE0003388834208D901F0F1FC2B6804440133B8
+:100AF000B4F5804F2B60F2D370BD00BFBA23002045
+:100B00007823002001F0AABD00F1006000F58040CC
+:100B10000068704700F10060920000F5804001F02D
+:100B200029BD0000054B1A68054B1B889B1A8342A0
+:100B300002D9104401F0CABC00207047782300207D
+:100B4000BA23002038B5084D044629B1286820444E
+:100B5000BDE8384001F0DABC2868204401F0BEFC52
+:100B60000028F3D038BD00BF7823002010F0030325
+:100B70000AD1B0F5047F05D200F10050A0F5104075
+:100B8000D0F80038184670470023FBE700F100500A
+:100B9000A0F51040D0F8100A70470000064991F8FF
+:100BA000243033B10023086A81F824300822FFF78B
+:100BB000B1BF0120704700BF7C230020014B1868A3
+:100BC000704700BF002004E070B5194B1D68194B39
+:100BD0000138C5F30B0408442D0C04221E88A642DC
+:100BE0000BD15C680A46013C824213460FD214F9CD
+:100BF000016F4EB102F8016BF6E7013A03F1080309
+:100C0000ECD181420B4602D22C2203F8012B0A4A76
+:100C100005241688AE4204D1984284BF967803F822
+:100C2000016B013C02F10402F3D1581A70BD00BF00
+:100C3000002004E0683B0008543B0008022803D170
+:100C4000044B08229A6170470128FCD1014B042211
+:100C5000F8E700BF00100240022804D1054B4FF412
+:100C600000229A6170470128FCD1024B4FF4802288
+:100C7000F7E700BF00100240022805D1064A536979
+:100C800083F00803536170470128FCD1024A53697D
+:100C900083F00403F6E700BF0010024010B5002304
+:100CA000934203D0CC5CC4540133F9E710BD00007B
+:100CB00010B5013810F9013F3BB191F900409C4259
+:100CC00003D11AB10131013AF4E71AB191F90020C8
+:100CD000981A10BD1046FCE703460246D01A12F9D6
+:100CE000011B0029FAD1704702440346934202D007
+:100CF00003F8011BFAE770472DE9F8431F4D14462E
+:100D000095F824200746884652BBDFF870909CB3C4
+:100D100095F824302BB92022FF2148462F62FFF797
+:100D2000E3FF95F82400C0F10802A24228BF224642
+:100D3000D6B24146920005EB8000FFF7AFFF95F871
+:100D40002430A41B1E44F6B2082E17449044E4B28B
+:100D500085F82460DBD1FFF721FF0028D7D108E018
+:100D60002B6A03EB82038342CFD0FFF717FF0028E3
+:100D7000CBD10020BDE8F8830120FBE77C230020D5
+:100D8000024B1A78024B1A70704700BFB82300203C
+:100D90001022002038B5194C194D204600F0BCFB3C
+:100DA0002946204600F0E4FB2D6816486A6DD2F80B
+:100DB000043843F00203C2F8043801F06DF8124918
+:100DC000284600F0DBFC6A6D104DD2F80438286824
+:100DD0000F4923F00203C2F80438A0424FF4E13374
+:100DE0000B6001D000F0F8FA6868A04204D0BDE8BA
+:100DF0003840074900F0F0BA38BD00BF98280020FD
+:100E0000703C000840420F00783C0008142200208B
+:100E1000A423002070B50C4B0C4D1E780C4B55F8DC
+:100E200026209A4204460DD00A4B0021142218466F
+:100E3000FFF75AFF0460014655F82600BDE87040F0
+:100E400000F0CABA70BD00BFB823002014220020F1
+:100E500098280020A423002030B5094D0A4491426F
+:100E60000DD011F8013B5840082340F30004013B2A
+:100E70002C4013F0FF0384EA5000F6D1EFE730BDB9
+:100E80002083B8ED026843681143016003B118473D
+:100E900070470000024AD36843F0C003D360704734
+:100EA0000050004010B5054C054A0021204600F0D6
+:100EB00071FA044A044BC4E9972310BDBC230020F7
+:100EC000950E00080050004080DE8002234A037C1B
+:100ED000002918BF0A46012B30B5C0F868220CD192
+:100EE0001F4B984209D11F4B196C41F480111964B2
+:100EF000196E41F4801119661B6EB2F90450146822
+:100F0000D0F86032D0F85C12002D03EB5403B3FB31
+:100F1000F4F3BEBF23F0070503F0070343EA4503DC
+:100F200094888B60D38843F040030B61138943F0AE
+:100F300001034B6144F4045343F02C03CB6004F4ED
+:100F4000A05400230B60B4F5806F0B684B680CBF96
+:100F50007F23FF2380F8643230BD00BF883B000848
+:100F6000BC230020003802402DE9F041D0F85C623B
+:100F7000F7683368DA0504469DB20DD5302383F354
+:100F800011884FF480610430FFF77CFF6FF48073A9
+:100F90003360002383F31188302383F3118804F135
+:100FA000040815F02F033AD183F31188380615D5BC
+:100FB000290613D5302383F3118804F1380000F09B
+:100FC00065F900284EDA0821201DFFF75BFF4FF678
+:100FD0007F733B40F360002383F311887A0616D5B4
+:100FE0006B0614D5302383F31188D4E913239A4276
+:100FF0000AD1236C43B127F040073F041021201D84
+:101000003F0CFFF73FFFF760002383F31188D4F80C
+:101010006822D36843B3BDE8F041106918472B0735
+:1010200014D015F0080F0CBF00214FF48071E807B1
+:1010300048BF41F02001AA0748BF41F040016B07BB
+:1010400048BF41F080014046FFF71CFFAD067368C2
+:1010500005D594F864122046194000F0CBF93568A4
+:10106000ADB29EE77060B6E7BDE8F081F8B5154611
+:1010700082680669AA420B46816938BF8568761A7C
+:10108000B54204460BD218462A46FFF707FEA3696D
+:101090002B44A361A3685B1BA3602846F8BD0CD951
+:1010A00018463246FFF7FAFDAF1BE1683A46304476
+:1010B000FFF7F4FDE3683B44EBE718462A46FFF7E9
+:1010C000EDFDE368E5E7000083689342F7B5154658
+:1010D000044638BF8568D0E90460361AB5420BD2A1
+:1010E0002A46FFF7DBFD63692B446361A36828464A
+:1010F0005B1BA36003B0F0BD0DD932460191FFF731
+:10110000CDFD0199E068AF1B3A463144FFF7C6FDBB
+:10111000E3683B44E9E72A46FFF7C0FDE368E4E7FC
+:1011200010B50A440024C361029B8460C0E900003A
+:10113000C0E90511C1600261036210BD08B5D0E9C4
+:101140000532934201D1826882B98268013282609D
+:101150005A1C42611970D0E904329A4224BFC36814
+:101160004361002100F0B4FE002008BD4FF0FF30C5
+:10117000FBE7000070B5302304460E4683F3118868
+:10118000A568A5B1A368A269013BA360531CA36134
+:1011900015782269934224BFE368A361E3690BB128
+:1011A00020469847002383F31188284607E03146FC
+:1011B000204600F07DFE0028E2DA85F3118870BD3C
+:1011C0002DE9F74F04460E4617469846D0F81C9076
+:1011D0004FF0300A8AF311884FF0000B154665B1C5
+:1011E0002A4631462046FFF741FF034660B9414693
+:1011F000204600F05DFE0028F1D0002383F3118823
+:10120000781B03B0BDE8F08FB9F1000F03D0019057
+:101210002046C847019B8BF31188ED1A1E448AF3C0
+:101220001188DCE7C0E90511C160C3611144009B6E
+:101230008260C0E90000016103627047F8B50446AE
+:101240000D461646302383F31188A768A7B1A3681B
+:10125000013BA36063695A1C62611D70D4E90432CA
+:101260009A4224BFE3686361E3690BB12046984763
+:10127000002080F3118807E03146204600F018FE78
+:101280000028E2DA87F31188F8BD0000D0E90523D1
+:101290009A4210B501D182687AB9826801328260BF
+:1012A0005A1C82611C7803699A4224BFC368836117
+:1012B000002100F00DFE204610BD4FF0FF30FBE78F
+:1012C0002DE9F74F04460E4617469846D0F81C9075
+:1012D0004FF0300A8AF311884FF0000B154665B1C4
+:1012E0002A4631462046FFF7EFFE034660B94146E5
+:1012F000204600F0DDFD0028F1D0002383F31188A3
+:10130000781B03B0BDE8F08FB9F1000F03D0019056
+:101310002046C847019B8BF31188ED1A1E448AF3BF
+:101320001188DCE7026843681143016003B1184784
+:10133000704700001430FFF743BF00004FF0FF3349
+:101340001430FFF73DBF00003830FFF7B9BF000091
+:101350004FF0FF333830FFF7B3BF00001430FFF712
+:1013600009BF00004FF0FF311430FFF703BF00004A
+:101370003830FFF763BF00004FF0FF323830FFF71F
+:101380005DBF0000012914BF6FF0130000207047FB
+:10139000FFF788BD37B515460E4A0260002242604D
+:1013A000C0E902220122044602740B46009000F1BB
+:1013B0005C014FF480721430FFF7B2FE00942B46AC
+:1013C0004FF4807204F5AE7104F13800FFF72AFF84
+:1013D00003B030BD9C3B000810B53023044683F3B6
+:1013E0001188FFF773FD02232374002080F3118816
+:1013F00010BD000038B5C36904460D461BB9042171
+:101400000844FFF78FFF294604F11400FFF796FE0A
+:10141000002806DA201D4FF40061BDE83840FFF7D0
+:1014200081BF38BD026843681143016003B11847AA
+:101430007047000013B5446BD4F894341A681178DF
+:10144000042915D1217C022912D11979128901238D
+:101450008B4013420CD101A904F14C0001F032FF82
+:10146000D4F89444019B21790246206800F0D0F919
+:1014700002B010BD143001F0B5BE00004FF0FF33D4
+:10148000143001F0AFBE00004C3001F087BF000007
+:101490004FF0FF334C3001F081BF0000143001F0F9
+:1014A00083BE00004FF0FF31143001F07DBE00001C
+:1014B0004C3001F053BF00004FF0FF324C3001F0D0
+:1014C0004DBF00000020704710B5D0F894341A6862
+:1014D00011780429044617D1017C022914D15979C5
+:1014E000528901238B4013420ED1143001F016FEB5
+:1014F000024648B1D4F894444FF48073617920686F
+:10150000BDE8104000F072B910BD0000406BFFF75D
+:10151000DBBF0000704700007FB5124B0360002363
+:101520004360C0E90233012502260F4B05740446CF
+:101530000290019300F18402294600964FF48073D3
+:10154000143001F0C7FD094B0294CDE9006304F5A6
+:1015500023724FF48073294604F14C0001F08EFE93
+:1015600004B070BDC43B00080D1500083514000818
+:101570000B68302282F311880A7903EB82029061B2
+:101580004A79093243F822008A7912B103EB8203C7
+:1015900098610223C0F894140374002080F311882A
+:1015A0007047000038B5037F044613B190F85430FB
+:1015B000ABB9201D01250221FFF734FF04F114000F
+:1015C00025776FF0010100F08FFC84F8545004F18E
+:1015D0004C006FF00101BDE8384000F085BC38BD1B
+:1015E00010B5012104460430FFF71CFF00232377C8
+:1015F00084F8543010BD000038B50446002514307E
+:1016000001F080FD04F14C00257701F04FFE201D14
+:1016100084F854500121FFF705FF2046BDE838400B
+:10162000FFF752BF90F8443003F06003202B07D13E
+:1016300090F84520212A4FF0000303D81F2A06D82E
+:1016400000207047222AFBD1C0E90E3303E0034A91
+:1016500082630722C2630364012070471C220020BA
+:1016600037B5D0F894341A681178042904461AD191
+:10167000017C022917D11979128901238B40134269
+:1016800011D100F14C05284601F0D0FE58B101A956
+:10169000284601F017FED4F89444019B21790246B4
+:1016A000206800F0B5F803B030BD0000F0B500EBE5
+:1016B000810385B09E6904460D46FEB1302383F355
+:1016C000118804EB8507301D0821FFF7ABFEFB688E
+:1016D0005B691B6806F14C001BB1019001F000FE34
+:1016E000019803A901F0EEFD024648B1039B29468B
+:1016F000204600F08DF8002383F3118805B0F0BD7B
+:10170000FB685A691268002AF5D01B8A013B134016
+:10171000F1D104F14402EAE7093138B550F821402B
+:10172000DCB1302383F31188D4F894241368527900
+:1017300003EB8203DB689B695D6845B10421601897
+:10174000FFF770FE294604F1140001F0F1FC204679
+:10175000FFF7BAFE002383F3118838BD70470000FD
+:1017600001F050B8012303700023C0E90133C361C5
+:1017700083620362C36243620363704738B5044601
+:10178000302383F311880025C0E90355C0E90555CE
+:10179000416001F047F80223237085F31188284641
+:1017A00038BD000070B500EB810305465069DA6072
+:1017B0000E46144618B110220021FFF795FAA069D1
+:1017C00018B110220021FFF78FFA31462846BDE8F4
+:1017D000704001F0F1B80000826802F001128260EE
+:1017E0000022C0E90422826101F072B9F0B400EB7A
+:1017F00081044789E4680125A4698D403D43458102
+:1018000023600023A2606360F0BC01F08DB900008A
+:10181000F0B400EB81040789E468012564698D4018
+:101820003D43058123600023A2606360F0BC01F0AA
+:1018300007BA000070B50223002504460370C0E912
+:101840000255C0E90455C564856180F8345001F043
+:101850004FF863681B6823B129462046BDE87040F5
+:10186000184770BD0378052B10B504460AD080F8E0
+:1018700050300523037043681B680BB1042198475F
+:101880000023A36010BD00000178052906D190F85F
+:101890005020436802701B6803B11847704700006E
+:1018A00070B590F83430044613B1002380F834301A
+:1018B00004F14402204601F02DF963689B68B3B936
+:1018C00094F8443013F0600535D00021204601F033
+:1018D000CDFB0021204601F0BFFB63681B6813B1FC
+:1018E000062120469847062384F8343070BD2046F0
+:1018F00098470028E4D0B4F84A30E26B9A4288BF97
+:10190000E36394F94430E56B002B4FF0300380F231
+:101910000381002D00F0F280092284F8342083F343
+:1019200011880021D4E90E232046FFF771FF002320
+:1019300083F31188DAE794F8452003F07F0343EA44
+:10194000022340F20232934200F0C58021D8B3F561
+:10195000807F48D00DD8012B3FD0022B00F0938020
+:10196000002BB2D104F14C02A2630222E263236491
+:10197000C1E7B3F5817F00F09B80B3F5407FA4D130
+:1019800094F84630012BA0D1B4F84C3043F0020358
+:1019900032E0B3F5006F4DD017D8B3F5A06F31D05A
+:1019A000A3F5C063012B90D8636894F846205E6865
+:1019B00094F84710B4F848302046B047002884D047
+:1019C0004368A3630368E3631AE0B3F5106F36D08E
+:1019D00040F6024293427FF478AF5C4BA36302234C
+:1019E000E3630023C3E794F84630012B7FF46DAF27
+:1019F000B4F84C3023F00203C4E90E55A4F84C307F
+:101A0000256478E7B4F84430B3F5A06F0ED194F8AC
+:101A1000463084F84E30204600F0C2FF63681B68F1
+:101A200013B1012120469847032323700023C4E902
+:101A30000E339CE704F14F03A3630123C3E723782C
+:101A4000042B10D1302383F311882046FFF7C4FE06
+:101A500085F311880321636884F84F5021701B6857
+:101A60000BB12046984794F84630002BDED084F81E
+:101A70004F300423237063681B68002BD6D00221EB
+:101A800020469847D2E794F848301D0603F00F012E
+:101A900020460AD501F030F8012804D002287FF44E
+:101AA00014AF2B4B9AE72B4B98E701F017F8F3E7AD
+:101AB00094F84630002B7FF408AF94F8483013F0C8
+:101AC0000F01B3D01A06204602D501F0E3FAADE7C4
+:101AD00001F0D6FAAAE794F84630002B7FF4F5AE71
+:101AE00094F8483013F00F01A0D01B06204602D511
+:101AF00001F0BCFA9AE701F0AFFA97E7142284F8F4
+:101B0000342083F311882B462A4629462046FFF7C6
+:101B10006DFE85F31188E9E65DB1152284F8342065
+:101B200083F311880021D4E90E232046FFF75EFEDF
+:101B3000FDE60B2284F8342083F311882B462A46D5
+:101B400029462046FFF764FEE3E700BFF43B0008A8
+:101B5000EC3B0008F03B000838B590F83430044600
+:101B6000002B3ED0063BDAB20F2A34D80F2B32D8E6
+:101B7000DFE803F037313108223231313131313190
+:101B800031313737C56BB0F84A309D4214D2C36843
+:101B90001B8AB5FBF3F203FB12556DB9302383F3B7
+:101BA00011882B462A462946FFF732FE85F3118815
+:101BB0000A2384F834300EE0142384F834303023C0
+:101BC00083F3118800231A4619462046FFF70EFEBC
+:101BD000002383F3118838BD036C03B198470023B9
+:101BE000E7E70021204601F041FA0021204601F0FC
+:101BF00033FA63681B6813B1062120469847062311
+:101C0000D7E7000010B590F83430142B044629D0E3
+:101C100017D8062B05D001D81BB110BD093B022BEC
+:101C2000FBD80021204601F021FA0021204601F0D6
+:101C300013FA63681B6813B10621204698470623F0
+:101C400019E0152BE9D10B2380F83430302383F3CE
+:101C5000118800231A461946FFF7DAFD002383F3A3
+:101C60001188DAE7C3689B695B68002BD5D1036CE8
+:101C700003B19847002384F83430CEE7002303757E
+:101C8000826803691B6899689142FBD25A680360B5
+:101C900042601060586070470023037582680369D2
+:101CA0001B6899689142FBD85A68036042601060D3
+:101CB0005860704708B50846302383F311880B7DC0
+:101CC000032B05D0042B0DD02BB983F3118808BD4D
+:101CD0008B6900221A604FF0FF338361FFF7CEFF5C
+:101CE0000023F2E7D1E9003213605A60F3E7000005
+:101CF000FFF7C4BF054BD9680875186802681A60F9
+:101D0000536001220275D860FEF7FCBA2826002035
+:101D100030B50C4BDD684B1C87B004460FD02B460A
+:101D2000094A684600F074F92046FFF7E3FF009B7C
+:101D300013B1684600F076F9A86907B030BDFFF727
+:101D4000D9FFF9E728260020B51C0008044B1A68C3
+:101D5000DB6890689B68984294BF00200120704720
+:101D600028260020084B10B51C68D86822681A6025
+:101D7000536001222275DC60FFF78EFF014620468A
+:101D8000BDE81040FEF7BEBA28260020044B1A68B2
+:101D9000DB6892689B689A4201D9FFF7E3BF7047FE
+:101DA0002826002038B5074C07490848012300259C
+:101DB0002370656001F078FB0223237085F311889E
+:101DC00038BD00BF90280020FC3B000828260020DA
+:101DD00000F05EB9EFF3118020B9EFF305833022F4
+:101DE00082F311887047000010B530B9EFF3058415
+:101DF000C4F3080414B180F3118810BDFFF7C6FFC7
+:101E000084F31188F9E70000034A516853685B1AAC
+:101E10009842FBD8704700BF001000E08B6002239F
+:101E200008618B82084670478368A3F1840243F8F7
+:101E3000142C026943F8442C426943F8402C094AA7
+:101E400043F8242CC26843F8182C022203F80C2C07
+:101E5000002203F80B2C044A43F8102CA3F12000B5
+:101E6000704700BF1D0300082826002008B5FFF7B3
+:101E7000DBFFBDE80840FFF73BBF0000024BDB681B
+:101E800098610F20FFF736BF28260020302383F308
+:101E90001188FFF7F3BF000008B50146302383F334
+:101EA00011880820FFF734FF002383F3118808BD51
+:101EB000064BDB6839B1426818605A6013604360B2
+:101EC0000420FFF725BF4FF0FF3070472826002081
+:101ED0000368984206D01A680260506099611846FB
+:101EE000FFF706BF7047000038B504460D4620686E
+:101EF000844200D138BD036823605C608561FFF7D0
+:101F0000F7FEF4E710B503689C68A2420CD85C6841
+:101F10008A600B604C602160596099688A1A9A60E7
+:101F20004FF0FF33836010BD1B68121BECE700000D
+:101F30000A2938BF0A2170B504460D460A266019E1
+:101F400001F0AAFA01F092FA041BA54203D8751C0D
+:101F50002E460446F3E70A2E04D9BDE8704001205E
+:101F600001F0E2BA70BD0000F8B5144B0D46D9611E
+:101F700003F1100141600A2A1969826038BF0A2200
+:101F8000016048601861A818144601F075FA0A2724
+:101F900001F06CFA431BA342064606D37C1C2819A9
+:101FA00001F07AFA27463546F2E70A2F04D9BDE850
+:101FB000F840012001F0B8BAF8BD00BF2826002083
+:101FC000F8B506460D4601F051FA0F4A134653F88C
+:101FD000107F9F4206D12A4601463046BDE8F840B0
+:101FE000FFF7C2BFD169BB68441A2C1928BF2C4621
+:101FF000A34202D92946FFF79BFF224631460348F8
+:10200000BDE8F840FFF77EBF2826002038260020D4
+:1020100010B4C0E9032300235DF8044B4361FFF7CC
+:10202000CFBF000010B5194C236998420DD0D0E9FC
+:102030000032816813605A609A680A449A600023EB
+:1020400003604FF0FF33A36110BD2346026843F8DD
+:10205000102F53600022026022699A4203D1BDE82A
+:10206000104001F013BA936881680B44936001F04B
+:10207000FDF92269E1699268441AA242E4D9114447
+:10208000BDE81040091AFFF753BF00BF2826002003
+:102090002DE9F047DFF8BC8008F110072C4ED8F886
+:1020A000105001F0E3F9D8F81C40AA68031B9A42CB
+:1020B0003ED81444D5E900324FF00009C8F81C405E
+:1020C00013605A60C5F80090D8F81030B34201D1BF
+:1020D00001F0DCF989F31188D5E9033128469847E6
+:1020E000302383F311886B69002BD8D001F0BEF93F
+:1020F0006A69A0EB04094A4582460DD2022001F02C
+:1021000013FA0022D8F81030B34208D151462846BD
+:10211000BDE8F047FFF728BF121A2244F2E712EB9E
+:10212000090938BF4A4629463846FFF7EBFEB5E7AE
+:10213000D8F81030B34208D01444211AC8F81C0053
+:10214000A960BDE8F047FFF7F3BEBDE8F08700BF28
+:10215000382600202826002000207047FEE70000D7
+:10216000704700004FF0FF307047000002290CD08C
+:10217000032904D00129074818BF00207047032A0B
+:1021800005D8054800EBC20070470448704700209E
+:10219000704700BFD43C00082C220020883C000877
+:1021A00070B59AB00546084601A9144600F0C2F879
+:1021B00001A8FEF791FD431C5B00C5E90034002235
+:1021C000237003236370C6B201AB02341046D1B250
+:1021D0008E4204F1020401D81AB070BD13F8011B3D
+:1021E00004F8021C04F8010C0132F0E708B53023B2
+:1021F00083F311880348FFF733FA002383F3118830
+:1022000008BD00BF9828002090F8443003F01F025A
+:10221000012A07D190F845200B2A03D10023C0E9F9
+:102220000E3315E003F06003202B08D1B0F84830DE
+:102230002BB990F84520212A03D81F2A04D8FFF78C
+:10224000F1B9222AEBD0FAE7034A82630722C2637C
+:1022500003640120704700BF2322002007B5052931
+:1022600017D8DFE801F0191603191920302383F37A
+:102270001188104A01900121FFF794FA01980E4A43
+:102280000221FFF78FFA0D48FFF7B6F9002383F319
+:10229000118803B05DF804FB302383F311880748ED
+:1022A000FFF780F9F2E7302383F311880348FFF743
+:1022B00097F9EBE7283C00084C3C000898280020E0
+:1022C00038B50C4D0C4C0D492A4604F10800FFF7B7
+:1022D00067FF05F1CA0204F110000949FFF760FF2A
+:1022E00005F5CA7204F118000649BDE83840FFF749
+:1022F00057BF00BF602D00202C220020083C0008A2
+:10230000123C00081D3C000870B5044608460D4606
+:10231000FEF7E2FCC6B22046013403780BB918463A
+:1023200070BD32462946FEF7C3FC0028F3D10120D8
+:10233000F6E700002DE9F04705460C46FEF7CCFC19
+:102340002B49C6B22846FFF7DFFF08B10736F6B2C1
+:1023500028492846FFF7D8FF08B11036F6B2632E99
+:102360000BD8DFF88C80DFF88C90234FDFF894A037
+:102370002E7846B92670BDE8F08729462046BDE88C
+:10238000F04701F0C9BB252E2ED107224146284631
+:10239000FEF78EFC70B9194B224603F10C0153F87D
+:1023A000040B42F8040B8B42F9D11B8813800735CC
+:1023B0000E34DDE7082249462846FEF779FC98B935
+:1023C0000F4BA21C197809090232C95D02F8041CDE
+:1023D00013F8011B01F00F015345C95D02F8031CFE
+:1023E000F0D118340835C3E704F8016B0135BFE7B5
+:1023F000F43C00081D3C00080B3D0008FC3C0008B4
+:10240000107AFF1F1C7AFF1FBFF34F8F024AD36859
+:10241000DB03FCD4704700BF003C024008B5094B09
+:102420001B7873B9FFF7F0FF074B1A69002ABFBF8B
+:10243000064A5A6002F188325A601A6822F48062B1
+:102440001A6008BDBE2F0020003C024023016745F2
+:1024500008B50B4B1B7893B9FFF7D6FF094B1A69E8
+:1024600042F000421A611A6842F480521A601A68F7
+:1024700022F480521A601A6842F480621A6008BD21
+:10248000BE2F0020003C02400B28F0B516D80C4CA3
+:102490000C4923787BB90C4D0E460C234FF000629B
+:1024A00055F8047B46F8042B013B13F0FF033A4434
+:1024B000F6D10123237051F82000F0BD0020FCE785
+:1024C000F02F0020C02F00201C3D0008014B53F8C6
+:1024D000200070471C3D00080C2070470B2810B5E9
+:1024E000044601D9002010BDFFF7CEFF064B53F87C
+:1024F00024301844C21A0BB90120F4E712680132E3
+:10250000F0D1043BF6E700BF1C3D00080B2838B5AE
+:10251000044628D8FFF75EFCFFF776FFFFF77EFF43
+:10252000124AF323D360E300DBB243F4007343F0B9
+:1025300002031361136943F4803313610546204697
+:10254000FFF762FFFFF7A0FF094B53F8241000F0DC
+:10255000E9F82846FFF77CFFFFF746FC2046BDE878
+:102560003840FFF7BBBF002038BD00BF003C024031
+:102570001C3D000812F001032DE9F04105460E460E
+:1025800014464BD18218B2F1016F61D8314B1B68F0
+:1025900013F001035CD0304FFFF71CFCFFF73EFF48
+:1025A000F323FB60FFF730FF314640F20128032C94
+:1025B00018D824F00104284E0C446D1A40F201187A
+:1025C000A142336905EB01072AD123F001033361EE
+:1025D000FFF73EFFFFF708FC0120BDE8F081043C57
+:1025E0000435E4E7AB07E4D13B6923F440733B6176
+:1025F0003B6943EA08033B6151F8046B2E60BFF36B
+:102600004F8FFFF701FF2B689E42E8D03B6923F014
+:1026100001033B61FFF71CFFFFF7E6FB0020DCE74F
+:1026200023F440733361336943EA080333610B8851
+:102630003B80BFF34F8FFFF7E7FE3F8831F8023B47
+:10264000BFB2BB42BCD0336923F001033361E1E781
+:102650001846C2E700380240003C0240084908B56D
+:102660000B7828B11BB9FFF7D9FE01230B7008BD09
+:10267000002BFCD0BDE808400870FFF7E9BE00BFA2
+:10268000BE2F002010B50244064BD2B2904200D1BA
+:1026900010BD441C00B253F8200041F8040BE0B216
+:1026A000F4E700BF502800400F4B30B51C6F2404E6
+:1026B00007D41C6F44F400741C671C6F44F400447E
+:1026C0001C670A4C236843F4807323600244084B60
+:1026D000D2B2904200D130BD441C00B251F8045B2C
+:1026E00043F82050E0B2F4E70038024000700040A8
+:1026F0005028004007B5012201A90020FFF7C2FFC2
+:10270000019803B05DF804FB13B50446FFF7F2FF30
+:10271000A04205D0012201A900200194FFF7C4FFC7
+:1027200002B010BD70470000034B1A681AB9034A83
+:10273000D2F874281A607047F42F0020003002404D
+:1027400008B5FFF7F1FF024B1868C0F3407008BDF1
+:10275000F42F002070470000FEE700000A4B0B48F2
+:102760000B4A90420BD30B4BDA1C121AC11E22F0FB
+:1027700003028B4238BF00220021FEF7B5BA53F89E
+:10278000041B40F8041BECE7D43E0008F0300020A6
+:10279000F0300020F030002070B5D0E915439E687D
+:1027A00000224FF0FF3504EB42135101D3F800092A
+:1027B0000028BEBFD3F8000940F08040C3F80009EC
+:1027C000D3F8000B0028BEBFD3F8000B40F08040C8
+:1027D000C3F8000B013263189642C3F80859C3F8D6
+:1027E000085BE0D24FF00113C4F81C3870BD000044
+:1027F000890141F02001016103699B06FCD412208C
+:10280000FFF702BB10B5054C2046FEF7ABFF4FF0BB
+:10281000A0436365024BA36510BD00BFF82F0020E5
+:10282000703D000870B50378012B054650D12A4B46
+:10283000446D98421BD1294B5A6B42F080025A6377
+:102840005A6D42F080025A655A6D5A6942F0800210
+:102850005A615A6922F080025A610E2143205B6955
+:1028600000F022FC1E4BE3601E4BC4F8003800232E
+:10287000C4F8003EC02323606E6D4FF40413A363BD
+:102880003369002BFCDA012333610C20FFF7BCFA1B
+:102890003369DB07FCD41220FFF7B6FA3369002B4B
+:1028A000FCDA0026A6602846FFF776FF6B68C4F8BE
+:1028B0001068DB68C4F81468C4F81C684BB90A4B8C
+:1028C000A3614FF0FF336361A36843F00103A3608A
+:1028D00070BD064BF4E700BFF82F0020003802401F
+:1028E0004014004003002002003C30C0083C30C0CF
+:1028F000F8B5446D054600212046FFF779FFA96D24
+:1029000000234FF001128F68C4F834384FF000668E
+:10291000C4F81C284FF0FF3004EB431201339F42F0
+:10292000C2F80069C2F8006BC2F80809C2F8080BC7
+:10293000F2D20B686A6DEB6563621023136116694E
+:1029400016F01006FBD11220FFF75EFAD4F800381B
+:1029500023F4FE63C4F80038A36943F4402343F032
+:102960001003A3610923C4F81038C4F814380A4BC3
+:10297000EB604FF0C043C4F8103B084BC4F8003B79
+:10298000C4F81069C4F80039EB6D03F1100243F488
+:102990008013EA65A362F8BD4C3D0008408000103A
+:1029A000426D90F84E10D2F8003823F4FE6343EAEB
+:1029B0000113C2F8003870472DE9F84300EB81039A
+:1029C000456DDA68166806F00306731E022B05EBE8
+:1029D00041130C4680460FFA81F94FEA41104FF03F
+:1029E0000001C3F8101B4FF0010104F1100398BF60
+:1029F000B60401FA03F391698EBF334E06F1805697
+:102A000006F5004600293AD0578A04F158014901D9
+:102A100037436F50D5F81C180B43C5F81C382B18DA
+:102A20000021C3F8101953690127611EA7409BB309
+:102A3000138A928B9B08012A88BF5343D8F85C20E5
+:102A4000981842EA034301F1400205EB8202C8F8FC
+:102A50005C00214653602846FFF7CAFE08EB890058
+:102A6000C3681B8A43EA8453483464011E432E51D1
+:102A7000D5F81C381F43C5F81C78BDE8F88305EB72
+:102A80004917D7F8001B21F40041C7F8001BD5F8FF
+:102A90001C1821EA0303C0E704F13F0305EB83039D
+:102AA0000A4A5A6028462146FFF7A2FE05EB491064
+:102AB000D0F8003923F40043C0F80039D5F81C38A9
+:102AC00023EA0707D7E700BF0080001000040002D8
+:102AD000826D1268C265FFF75FBE00005831436D1A
+:102AE00049015B5813F4004004D013F4001F0CBFDD
+:102AF00002200120704700004831436D49015B58B6
+:102B000013F4004004D013F4001F0CBF0220012076
+:102B10007047000000EB8101CB68196A0B681360F5
+:102B20004B6853607047000000EB810330B5DD68EF
+:102B3000AA691368D36019B9402B84BF402313607E
+:102B40006B8A1468426D1C44013CB4FBF3F463438C
+:102B5000033323F0030302EB411043EAC44343F081
+:102B6000C043C0F8103B2B6803F00303012B09B2EC
+:102B70000ED1D2F8083802EB411013F4807FD0F860
+:102B8000003B14BF43F0805343F00053C0F8003BB8
+:102B900002EB4112D2F8003B43F00443C2F8003B81
+:102BA00030BD00002DE9F041244D6E6D06EB401361
+:102BB0000446D3F8087BC3F8087B38070AD5D6F853
+:102BC0001438190706D505EB84032146DB6828462F
+:102BD0005B689847FA071FD5D6F81438DB071BD572
+:102BE00005EB8403D968CCB98B69488A5A68B2FB73
+:102BF000F0F600FB16228AB91868DA6890420DD206
+:102C0000121AC3E90024302383F311880B482146AC
+:102C1000FFF78AFF84F31188BDE8F081012303FAEE
+:102C200004F26B8923EA02036B81CB68002BF3D09B
+:102C300021460248BDE8F041184700BFF82F0020A8
+:102C400000EB810370B5DD68436D6C692668E66052
+:102C50004A0156BB1A444FF40020C2F810092A68F2
+:102C600002F00302012A0AB20ED1D3F8080803EBDE
+:102C7000421410F4807FD4F8000914BF40F0805053
+:102C800040F00050C4F8000903EB4212D2F80009EA
+:102C900040F00440C2F80009D3F83408012202FAD7
+:102CA00001F10143C3F8341870BD19B9402E84BF37
+:102CB0004020206020682E8A8419013CB4FBF6F481
+:102CC00040EAC44040F000501A44C6E72DE9F843FA
+:102CD0003B4D6E6D06EB40130446D3F80889C3F8EC
+:102CE000088918F0010F4FEA40171AD0D6F81038AB
+:102CF000DB0716D505EB8003D9684B691868DA68DD
+:102D0000904230D2121A4FF000091A60C3F80490B2
+:102D1000302383F3118821462846FFF791FF89F37A
+:102D2000118818F0800F1CD0D6F834380126A64040
+:102D3000334216D005EB84036D6DD3F80CC0DCF87C
+:102D400014200134E4B2D2F800E005EB04342F443F
+:102D50005168714515D3D5F8343823EA0606C5F80D
+:102D60003468BDE8F883012303FA04F22B8923EACF
+:102D700002032B818B68002BD3D02146284698472D
+:102D8000CFE7BCF81000AEEB0103834228BF034637
+:102D9000D7F8180980B2B3EB800FE2D89068A0F1A1
+:102DA000040959F8048FC4F80080A0EB090898447E
+:102DB000B8F1040FF5D818440B4490605360C7E78E
+:102DC000F82F00202DE9F74FA24C656D6E69AB69B5
+:102DD0001E4016F480586E6107D02046FEF72AFD8B
+:102DE00003B0BDE8F04F00F04DBC002E12DAD5F86C
+:102DF000003E98489B071EBFD5F8003E23F0030312
+:102E0000C5F8003ED5F8043823F00103C5F80438AE
+:102E1000FEF73AFD370505D58E48FFF7BDFC8D4816
+:102E2000FEF720FDB0040CD5D5F8083813F0060FD6
+:102E3000EB6823F470530CBF43F4105343F4A053D6
+:102E4000EB6031071BD56368DB681BB9AB6923F006
+:102E50000803AB612378052B0CD1D5F8003E7D48E3
+:102E60009A071EBFD5F8003E23F00303C5F8003EC5
+:102E7000FEF70AFD6368DB680BB176489847F302FA
+:102E800074D4B70227D5D4F85490DFF8C8B100271E
+:102E90004FF0010A09EB4712D2F8003B03F440233C
+:102EA000B3F5802F11D1D2F8003B002B0DDA6289E7
+:102EB0000AFA07F322EA0303638104EB8703DB6862
+:102EC000DB6813B1394658469847A36D01379B68B4
+:102ED000FFB29F42DED9F00617D5676D3A6AC2F39A
+:102EE0000A1002F00F0302F4F012B2F5802F00F086
+:102EF0008580B2F5402F08D104EB83030022DB6804
+:102F00001B6A07F5805790426AD13003D5F81848FC
+:102F100013D5E10302D50020FFF744FEA20302D53A
+:102F20000120FFF73FFE630302D50220FFF73AFEC0
+:102F3000270302D50320FFF735FE75037FF550AF59
+:102F4000E00702D50020FFF7C1FEA10702D501204E
+:102F5000FFF7BCFE620702D50220FFF7B7FE23078A
+:102F60007FF53EAF0320FFF7B1FE39E7636DDFF871
+:102F7000E4A0019300274FF00109A36D9B685FFA5D
+:102F800087FB9B453FF67DAF019B03EB4B13D3F8CB
+:102F9000001901F44021B1F5802F1FD1D3F8001999
+:102FA00000291BDAD3F8001941F09041C3F8001949
+:102FB000D3F800190029FBDB5946606DFFF718FCB8
+:102FC000218909FA0BF321EA0303238104EB8B0324
+:102FD000DB689B6813B15946504698470137CCE7E8
+:102FE000910708BFD7F80080072A98BF03F8018B24
+:102FF00002F1010298BF4FEA182884E7023304EB7C
+:10300000830207F580575268D2F818C0DCF8082010
+:10301000DCE9001CA1EB0C0C002188420AD104EB76
+:10302000830463689B699A6802449A605A68024400
+:103030005A606AE711F0030F08BFD7F800808C458B
+:1030400088BF02F8018B01F1010188BF4FEA1828FF
+:10305000E3E700BFF82F0020436D03EB4111D1F8E7
+:10306000003B43F40013C1F8003B7047436D03EB92
+:103070004111D1F8003943F40013C1F80039704709
+:10308000436D03EB4111D1F8003B23F40013C1F869
+:10309000003B7047436D03EB4111D1F8003923F435
+:1030A0000013C1F80039704700F1604303F5614334
+:1030B0000901C9B283F80013012200F01F039A40EE
+:1030C00043099B0003F1604303F56143C3F880218A
+:1030D0001A60704730B5039C0172043304FB03256A
+:1030E000C0E90653049B03630021059BC160C0E94E
+:1030F0000000C0E90422C0E90842C0E90A114363A4
+:1031000030BD0000416A0022C0E90411C0E90A2272
+:10311000C2606FF00101FEF7E7BE0000D0E90432A3
+:10312000934201D1C2680AB9181D70470020704748
+:1031300003691960C2680132C260C26913448269BE
+:103140000361934224BF436A03610021FEF7C0BEBE
+:1031500038B504460D46E3683BB16269131D126839
+:10316000A3621344E362002007E0237A33B92946BF
+:103170002046FEF79DFE0028EDDA38BD6FF0010015
+:10318000FBE70000C368C269013BC36043691344A5
+:1031900082694361934224BF436A4361002383628F
+:1031A000036B03B11847704770B53023044683F3AF
+:1031B0001188866A3EB9FFF7CBFF054618B186F342
+:1031C0001188284670BDA36AE26A13F8015BA36206
+:1031D000934202D32046FFF7D5FF002383F31188E3
+:1031E000EFE700002DE9F84F04460E4617469846D3
+:1031F0004FF0300989F311880025AA46D4F828B089
+:10320000BBF1000F09D141462046FFF7A1FF20B1D5
+:103210008BF311882846BDE8F88FD4E90A12A7EB92
+:10322000050B521A934528BF9346BBF1400F1BD99B
+:10323000334601F1400251F8040B43F8040B91426C
+:10324000F9D1A36A40334036A3624035D4E90A235A
+:103250009A4202D32046FFF795FF8AF31188BD42B8
+:10326000D8D289F31188C9E730465A46FDF716FDD2
+:10327000A36A5B445E44A3625D44E7E710B5029C29
+:103280000172043303FB0421C0E906130023C0E9E3
+:103290000A33039B0363049BC460C0E90000C0E9D8
+:1032A0000422C0E90842436310BD0000026AC26004
+:1032B000426AC0E904220022C0E90A226FF001013B
+:1032C000FEF712BED0E904239A4201D1C26822B9A6
+:1032D000184650F8043B0B60704700231846FAE785
+:1032E000C368C2690133C36043691344826943619F
+:1032F000934224BF436A43610021FEF7E9BD000009
+:1033000038B504460D46E3683BB123691A1DA26235
+:10331000E2691344E362002007E0237A33B92946C7
+:103320002046FEF7C5FD0028EDDA38BD6FF001003C
+:10333000FBE7000003691960C268013AC260C26914
+:10334000134482690361934224BF436A03610023EB
+:103350008362036B03B118477047000070B53023D8
+:103360000D460446114683F31188866A2EB9FFF78D
+:10337000C7FF10B186F3118870BDA36A1D70A36AE0
+:10338000E26A01339342A36204D3E169204604391F
+:10339000FFF7D0FF002080F31188EDE72DE9F84F0B
+:1033A00004460D46904699464FF0300A8AF311883C
+:1033B0000026B346A76A4FB949462046FFF7A0FF4B
+:1033C00020B187F311883046BDE8F88FD4E90A07A9
+:1033D0003A1AA8EB0607974228BF1746402F1BD979
+:1033E00005F1400355F8042B40F8042B9D42F9D118
+:1033F000A36A4033A3624036D4E90A239A4204D335
+:10340000E16920460439FFF795FF8BF311884645A3
+:10341000D9D28AF31188CDE729463A46FDF73EFC1A
+:10342000A36A3B443D44A3623E44E5E7D0E904235C
+:103430009A4217D1C3689BB1836A8BB1043B9B1A34
+:103440000ED01360C368013BC360C3691A4483692B
+:1034500002619A4224BF436A03610023836201230D
+:10346000184670470023FBE700F036B9014B586A55
+:10347000704700BF000C0040034B002258631A61E4
+:103480000222DA60704700BF000C0040014B0022AE
+:10349000DA607047000C0040014B5863704700BF72
+:1034A000000C0040FEE7000070B51B4B01630025D7
+:1034B000044686B0586085620E4600F0BFF804F1FD
+:1034C0001003C4E904334FF0FF33C4E90635C4E9FF
+:1034D0000044A560E562FFF7C9FF2B460246C4E938
+:1034E000082304F134010D4A256580232046FEF7A8
+:1034F00095FC0123E0600A4A03750092726801920C
+:10350000B268CDE90223074B6846CDE90435FEF7E2
+:10351000ADFC06B070BD00BF902800207C3D0008C7
+:10352000813D0008A5340008024AD36A1843D062DE
+:10353000704700BF282600204B6843608B6883607B
+:10354000CB68C3600B6943614B6903628B6943625B
+:103550000B6803607047000008B5264B26481A69BF
+:1035600040F2FF110A431A611A6922F4FF7222F035
+:1035700001021A611A691A6B0A431A631A6D0A4327
+:103580001A651E4A1B6D1146FFF7D6FF02F11C019A
+:1035900000F58060FFF7D0FF02F1380100F5806090
+:1035A000FFF7CAFF02F1540100F58060FFF7C4FF86
+:1035B00002F1700100F58060FFF7BEFF02F18C019F
+:1035C00000F58060FFF7B8FF02F1A80100F5806008
+:1035D000FFF7B2FF02F1C40100F58060FFF7ACFF16
+:1035E00002F1E00100F58060FFF7A6FFBDE80840AA
+:1035F00000F0F0B80038024000000240883D0008AA
+:1036000008B500F069FAFEF7CDFBFFF78DF8BDE8CD
+:103610000840FEF755BE000070470000EFF3098335
+:1036200005494A6B22F001024A63683383F3098833
+:10363000002383F31188704700EF00E0302080F30F
+:10364000118862B60C4B0D4AD96821F4E061090477
+:10365000090C0A43DA60D3F8FC20094942F0807271
+:10366000C3F8FC200A6842F001020A602022DA77DF
+:1036700083F82200704700BF00ED00E00003FA0568
+:10368000001000E010B5302383F311880E4B5B6807
+:1036900013F4006314D0F1EE103AEFF30984683CA0
+:1036A0004FF08073E361094BDB6B236684F3098879
+:1036B000FEF74CFB10B1064BA36110BD054BFBE7B9
+:1036C00083F31188F9E700BF00ED00E000EF00E0B0
+:1036D0002F030008320300080E4B1A6C42F0080258
+:1036E0001A641A6E42F008021A660B4A1B6E93683F
+:1036F00043F008039360094B53229A624FF0FF3264
+:10370000DA6200229A615A63DA605A6001225A61D1
+:103710001A60704700380240002004E0000C0040AE
+:10372000094A08B51169D3680B40D9B2C9439B0750
+:10373000116107D5302383F31188FEF749FB00237D
+:1037400083F3118808BD00BF000C00401F4B1A69AD
+:103750006FEAC2526FEAD2521A611A69C2F30802C2
+:103760001A614FF0FF301A695A69586100215A698D
+:1037700059615A691A6A62F080521A621A6A02F032
+:1037800080521A621A6A5A6A58625A6A59625A6AA6
+:103790001A6C42F080521A641A6E42F080521A6615
+:1037A0001A6E0B4A106840F480701060186F00F4B5
+:1037B0004070B0F5007F1EBF4FF480301867196766
+:1037C000536823F40073536000F05EB90038024080
+:1037D00000700040334B4FF080521A64324A4FF46D
+:1037E000404111601A6842F001021A601A6891079C
+:1037F000FCD59A6822F003029A602A4B9A6812F06C
+:103800000C02FBD1196801F0F90119609A601A687D
+:1038100042F480321A601A689203FCD55A6F42F063
+:1038200001025A671F4B5A6F9007FCD51F4A5A6016
+:103830001A6842F080721A601B4A53685904FCD51A
+:10384000184B1A689201FCD5194A9A60194B1A68EC
+:10385000194B9A42194B21D1194A1168194A9142C0
+:103860001CD140F205121A60144A136803F00F03CA
+:10387000052BFAD10B4B9A6842F002029A609A68C3
+:1038800002F00C02082AFAD15A6C42F480425A64BF
+:103890005A6E42F480425A665B6E704740F205727F
+:1038A000E1E700BF003802400070004008544007C4
+:1038B00000948838002004E011640020003C02409D
+:1038C00000ED00E041C20F41074A08B5536903F01B
+:1038D0000103536123B1054A13680BB1506898473F
+:1038E000BDE80840FFF7CEBE003C0140703000202C
+:1038F000074A08B5536903F00203536123B1054A2F
+:1039000093680BB1D0689847BDE80840FFF7BABE8E
+:10391000003C014070300020074A08B5536903F0AD
+:103920000403536123B1054A13690BB150699847E9
+:10393000BDE80840FFF7A6BE003C01407030002003
+:10394000074A08B5536903F00803536123B1054AD8
+:1039500093690BB1D0699847BDE80840FFF792BE64
+:10396000003C014070300020074A08B5536903F05D
+:103970001003536123B1054A136A0BB1506A98478B
+:10398000BDE80840FFF77EBE003C014070300020DB
+:10399000164B10B55C6904F478725A61A30604D51D
+:1039A000134A936A0BB1D06A9847600604D5104A4F
+:1039B000136B0BB1506B9847210604D50C4A936BDF
+:1039C0000BB1D06B9847E20504D5094A136C0BB1D3
+:1039D000506C9847A30504D5054A936C0BB1D06C85
+:1039E0009847BDE81040FFF74DBE00BF003C0140C6
+:1039F00070300020194B10B55C6904F47C425A61A8
+:103A0000620504D5164A136D0BB1506D9847230516
+:103A100004D5134A936D0BB1D06D9847E00404D5DB
+:103A20000F4A136E0BB1506E9847A10404D50C4A8F
+:103A3000936E0BB1D06E9847620404D5084A136F99
+:103A40000BB1506F9847230404D5054A936F0BB10F
+:103A5000D06F9847BDE81040FFF714BE003C01400E
+:103A60007030002008B50348FDF77EFABDE8084035
+:103A7000FFF708BEBC23002008B5FFF751FEBDE8E4
+:103A80000840FFF7FFBD0000062108B50846FFF714
+:103A90000BFB06210720FFF707FB06210820FFF795
+:103AA00003FB06210920FFF7FFFA06210A20FFF792
+:103AB000FBFA06211720FFF7F7FA06212820FFF767
+:103AC000F3FA07213220FFF7EFFABDE808400C2196
+:103AD0003520FFF7E9BA000008B5FFF737FE00F020
+:103AE0000DF8FDF755FCFDF73BFEFDF713FDFFF765
+:103AF00093FDBDE80840FFF7B7BC00000023054A6E
+:103B000019460133102BC2E9001102F10802F8D165
+:103B1000704700BF70300020034611F8012B03F8F6
+:103B2000012B002AF9D1704753544D3332463F3FA1
+:103B30003F0053544D3332463430780053544D33A4
+:103B400032463432780053544D333246343436588A
+:103B500058000000012033000010410001105A00FD
+:103B6000031059000710310000000000283B000836
+:103B700013040000323B0008190400003C3B00081D
+:103B800021040000463B00080096000000000000F1
+:103B90000000000000000000000000000000000025
+:103BA000511300083D13000879130008651300083D
+:103BB000711300085D13000849130008351300084D
+:103BC0008513000800000000911400087D1400080F
+:103BD000B9140008A5140008B11400089D140008C9
+:103BE0008914000875140008C514000800000000BE
+:103BF000010000000000000063300000F83B0008F6
+:103C000080260020902800204172647550696C6FF6
+:103C1000740025424F415244252D424C0025534506
+:103C20005249414C25000000020000000000000045
+:103C3000AD1600081917000840004000302D002084
+:103C4000402D0020020000000000000003000000E2
+:103C5000000000005D1700080000000010000000D8
+:103C6000502D0020000000000100000000000000B6
+:103C7000F82F0020010102005D2200086D210008DC
+:103C800009220008ED21000843000000903C0008D4
+:103C900009024300020100C03209040000010202CF
+:103CA0000100052400100105240100010424020282
+:103CB0000524060001070582030800FF090401002E
+:103CC000020A00000007050102400000070581020A
+:103CD0004000000012000000DC3C0008120110014E
+:103CE00002000040091241570002010203010000D6
+:103CF0000403090425424F4152442500466C79696A
+:103D00006E674D6F6F6E463430370030313233346A
+:103D100035363738394142434445460000400000BB
+:103D200000400000004000000040000000000100D2
+:103D3000000002000000020000000200000002007B
+:103D4000000002000000020000000200000000006D
+:103D5000A1180008591B0008051C0008400040007D
+:103D6000583000205830002001000000683000204A
+:103D70008000000040010000030000006D61696EDA
+:103D80000069646C650000000001802A00000000EA
+:103D9000AAAAAAAA00010024FFFF00000000000058
+:103DA00000A00A000000000100000000AAAAAAA8C2
+:103DB00000000001FFFF0000000000000000000004
+:103DC0000000000200000000AAAAAAAA0000000148
+:103DD000FFFF0000000000000000080020000000BD
+:103DE00000000000AAAAAAAA10000000FFFF00001D
+:103DF000000800000000000050000040000000002B
+:103E0000AAAAAAAA00000040FFFF000000000000CC
+:103E1000000000000000000000000000AAAAAAAAFA
+:103E200000000000FFFF0000000000000000000094
+:103E30000000000000000000AAAAAAAA00000000DA
+:103E4000FFFF000000000000000000000000000074
+:103E5000000000000A000000000000000300000055
+:103E60000000000000000000000000000000000052
+:103E70000000000000000000000000000000000042
+:103E800000000000000000002B0400000000000003
+:103E900000C00F0000000000FF0000009828002074
+:103EA000BC230020009600000000080096000000DF
+:103EB0000008000004000000F03C000800000000C2
+:103EC00000000000000000000000000000000000F2
+:043ED00000000000EE
+:00000001FF
diff --git a/Tools/bootloaders/FlyingMoonF427_bl.bin b/Tools/bootloaders/FlyingMoonF427_bl.bin
index 3b3eef5e5d4e71..cfe512ea48419b 100755
Binary files a/Tools/bootloaders/FlyingMoonF427_bl.bin and b/Tools/bootloaders/FlyingMoonF427_bl.bin differ
diff --git a/Tools/bootloaders/FlyingMoonF427_bl.hex b/Tools/bootloaders/FlyingMoonF427_bl.hex
new file mode 100644
index 00000000000000..3112aadcbf429d
--- /dev/null
+++ b/Tools/bootloaders/FlyingMoonF427_bl.hex
@@ -0,0 +1,1016 @@
+:020000040800F2
+:1000000000060020E1010008E3010008E301000808
+:10001000E3010008E3010008E3010008E301000830
+:10002000E3010008E3010008E30100086936000865
+:10003000E3010008E3010008E3010008E301000810
+:10004000E3010008E3010008E3010008E301000800
+:10005000E3010008E30100081939000841390008EC
+:100060006939000891390008B9390008E30100082E
+:10007000E3010008E3010008E3010008E3010008D0
+:10008000E3010008E3010008E3010008E3010008C0
+:10009000E3010008E3010008E3010008E13900087A
+:1000A000E3010008E3010008E3010008E3010008A0
+:1000B000E3010008E3010008E3010008E301000890
+:1000C000E3010008E3010008E3010008E301000880
+:1000D000E3010008E3010008E3010008E301000870
+:1000E000453A0008E3010008E3010008E3010008C5
+:1000F000E3010008E3010008E3010008E301000850
+:10010000E3010008E3010008C93A0008E301000820
+:10011000E3010008B53A0008E3010008E301000824
+:10012000E3010008E3010008E3010008E30100081F
+:10013000E3010008E3010008E3010008E30100080F
+:10014000E3010008E3010008E3010008112E0008A4
+:10015000E3010008E3010008E3010008E3010008EF
+:10016000E3010008E3010008E3010008E3010008DF
+:10017000E3010008E3010008E3010008E3010008CF
+:10018000E3010008E3010008E3010008E3010008BF
+:10019000E3010008E3010008E3010008E3010008AF
+:1001A000E3010008E3010008E3010008E30100089F
+:1001B000E3010008E3010008E3010008E30100088F
+:1001C000E3010008E3010008E3010008E30100087F
+:1001D000E3010008E3010008E3010008E30100086F
+:1001E00002E000F000F8FEE772B6374880F30888B6
+:1001F000364880F3098836483649086040F20000E6
+:10020000CCF200004EF63471CEF200010860BFF36C
+:100210004F8FBFF36F8F40F20000C0F2F0004EF638
+:100220008851CEF200010860BFF34F8FBFF36F8F8C
+:100230004FF00000E1EE100A4EF63C71CEF20001E4
+:100240000860062080F31488BFF36F8F02F0A8FACD
+:1002500003F0A8F94FF055301F491B4A91423CBFAB
+:1002600041F8040BFAE71D49184A91423CBF41F896
+:10027000040BFAE71A491B4A1B4B9A423EBF51F83E
+:10028000040B42F8040BF8E700201849184A914281
+:100290003CBF41F8040BFAE702F086FA03F0D6F906
+:1002A000144C154DAC4203DA54F8041B8847F9E7A7
+:1002B00000F042F8114C124DAC4203DA54F8041B22
+:1002C0008847F9E702F06EBA0006002000220020FD
+:1002D0000000000808ED00E00000002000060020FB
+:1002E000083F0008002200204C220020502200205D
+:1002F00020310020E0010008E0010008E0010008D2
+:10030000E00100082DE9F04F2DED108AC1F80CD066
+:10031000C3689D46BDEC108ABDE8F08F002383F3CF
+:1003200011882846A047002001F0BAFDFEE701F041
+:1003300023FD00DFFEE7000038B502F005FA40B10A
+:10034000174B6FF03F01002259720F211A729972F8
+:10035000DA7202F0DFF9054602F018FA0446D8B95D
+:10036000104B9D421AD001339D4218BF044641F202
+:10037000883504BF01240025002002F0D5F90CB116
+:1003800000F078F800F014FD00F0B0FB284600F013
+:10039000B9F800F06FF8F9E70025EDE70546EBE75F
+:1003A00000220020010007B008B500F06BFBA0F1AF
+:1003B00020035842584108BD07B541F212030221FB
+:1003C00001A8ADF8043000F07BFB03B05DF804FB3E
+:1003D00038B5302383F31188174803680BB101F057
+:1003E0002BFE164A144800234FF47A7101F01AFECE
+:1003F000002383F31188124C236813B12368013B57
+:100400002360636813B16368013B63600D4D2B7813
+:1004100033B963687BB9022000F03CFC322363608F
+:100420002B78032B07D163682BB9022000F032FC34
+:100430004FF47A73636038BD50220020D103000866
+:100440007023002068220020084B187003280CD865
+:10045000DFE800F008050208022000F00BBC0220D3
+:1004600000F0FABB024B00225A607047682200205D
+:10047000702300201F4B204A10B51C46196801311B
+:1004800036D004339342F9D16268A24230D31B4B79
+:100490009B6803F1006303F580439A4228D2002051
+:1004A00000F03EFB0220FFF7CFFF154B1A6C002235
+:1004B0001A64196E1A66196E596C5A64596E5A6626
+:1004C0005A6E1A6942F000521A611A6922F00052FB
+:1004D0001A611B6972B64FF0E0233021C3F8084D52
+:1004E000D4E9003281F311889D4683F308881047D0
+:1004F00010BD00BF0040000820400008002200207E
+:10050000003802402DE9F04F93B0AA4B0090202212
+:10051000FF210AA89D6800F0F5FBA74A1378A3B94C
+:10052000A648012103601170302383F3118803680A
+:100530000BB101F081FDA24AA04800234FF47A716B
+:1005400001F070FD002383F31188009B13B19D4BD4
+:10055000009A1A609C4A009C1378032B1EBF00234C
+:100560001370984A4FF0000A18BF5360D34656469E
+:10057000D146012000F07EFB24B1924B1B68002B7A
+:1005800000F01182002000F07DFA0390039B002B05
+:10059000F2DB012000F060FB039B213B162BE8D827
+:1005A00001A252F823F000BF050600082D0600083E
+:1005B000C1060008730500087305000873050008EC
+:1005C0004B0700081B0900083508000897080008B9
+:1005D000BF080008E508000873050008F7080008D0
+:1005E0007305000869090008A506000873050008DE
+:1005F000AD09000811060008A506000873050008EB
+:10060000970800080220FFF7CFFE002840F0F58190
+:10061000009B0221BAF1000F08BF1C4605A841F259
+:100620001233ADF8143000F04BFAA2E74FF47A70B1
+:1006300000F028FA071EEBDB0220FFF7B5FE0028CA
+:10064000E6D0013F052F00F2DA81DFE807F0030A68
+:100650000D10133605230593042105A800F030FA88
+:1006600017E054480421F9E758480421F6E75848B0
+:100670000421F3E74FF01C08404600F053FA08F15C
+:1006800004080590042105A800F01AFAB8F12C0F0F
+:10069000F2D1012000FA07F747EA0B0B5FFA8BFB58
+:1006A0004FF0000900F07AFB26B10BF00B030B2B87
+:1006B00008BF0024FFF780FE5BE746480421CDE732
+:1006C000002EA5D00BF00B030B2BA1D10220FFF7BE
+:1006D0006BFE074600289BD0012000F021FA022083
+:1006E000FFF7B2FE00265FFA86F8404600F028FACF
+:1006F000044690B10021404600F032FA013600284D
+:10070000F1D1BA46044641F21213022105A8ADF810
+:1007100014303E4600F0D4F92BE70120FFF794FE99
+:100720002546244B9B68AB4207D9284600F0FAF9CE
+:10073000013040F067810435F3E7234B00251D703D
+:10074000204BBA465D603E46ACE7002E3FF460AFFA
+:100750000BF00B030B2B7FF45BAF0220FFF774FE53
+:10076000322000F08FF9B0F10008FFF651AF18F019
+:1007700003077FF44DAF0F4A926808EB05039342DD
+:100780003FF646AFB8F5807F3FF742AF124B01937B
+:10079000B84523DD4FF47A7000F074F90390039AA2
+:1007A000002AFFF635AF019B039A03F8012B0137AE
+:1007B000EDE700BF002200206C2300205022002023
+:1007C000D1030008702300206822002004220020AA
+:1007D000082200200C2200206C220020C820FFF7F5
+:1007E000E3FD074600283FF413AF1F2D11D8C5F1D4
+:1007F000200242450AAB25F0030028BF4246834948
+:100800000192184400F058FA019A8048FF2100F044
+:1008100079FA4FEAA8037D490193C8F38702284675
+:1008200000F078FA064600283FF46DAF019B05EB17
+:10083000830537E70220FFF7B7FD00283FF4E8AE55
+:1008400000F0BAF900283FF4E3AE0027B846704B39
+:100850009B68BB4218D91F2F11D80A9B01330ED0B9
+:1008600027F0030312AA134453F8203C0593404693
+:10087000042205A900F0FAFA04378046E7E7384673
+:1008800000F050F90590F2E7CDF81480042105A896
+:1008900000F016F906E70023642104A8049300F091
+:1008A00005F900287FF4B4AE0220FFF77DFD002893
+:1008B0003FF4AEAE049800F067F90590E6E7002338
+:1008C000642104A8049300F0F1F800287FF4A0AE9E
+:1008D0000220FFF769FD00283FF49AAE049800F06B
+:1008E00063F9EAE70220FFF75FFD00283FF490AECE
+:1008F00000F072F9E1E70220FFF756FD00283FF40F
+:1009000087AE05A9142000F06DF904210746049074
+:1009100004A800F0D5F83946B9E7322000F0B2F863
+:10092000071EFFF675AEBB077FF472AE384A9268B9
+:1009300007EB090393423FF66BAE0220FFF734FD4D
+:1009400000283FF465AE27F003074F44B9453FF454
+:10095000A9AE484600F0E6F80421059005A800F08D
+:10096000AFF809F10409F1E74FF47A70FFF71CFDC5
+:1009700000283FF44DAE00F01FF9002844D00A9B38
+:1009800001330BD008220AA9002000F0C3F9002887
+:100990003AD02022FF210AA800F0B4F9FFF70CFD9D
+:1009A0001C4801F083FA13B0BDE8F08F002E3FF42D
+:1009B0002FAE0BF00B030B2B7FF42AAE0023642128
+:1009C00005A8059300F072F8074600287FF420AED2
+:1009D0000220FFF7E9FC804600283FF419AEFFF73C
+:1009E000EBFC41F2883001F061FA059800F01CFA46
+:1009F000464600F0D3F93C46BBE5064652E64FF0CA
+:100A0000000905E6BA467EE637467CE66C22002001
+:100A100000220020A08601002DE9F84F4FF47A73E0
+:100A2000DFF85880DFF8589006460D4602FB03F7C2
+:100A3000002498F900305A1C5FFA84FA01D0A342CE
+:100A400012D159F8240003682A46D3F820B0314661
+:100A50003B46D847854207D1074B012083F800A0C9
+:100A6000BDE8F88F0124E4E7002CFBD04FF4FA70C6
+:100A700001F01CFA0020F3E7B82300201022002028
+:100A80001422002007B50023024601210DF10700C2
+:100A90008DF80730FFF7C0FF20B19DF8070003B0C5
+:100AA0005DF804FB4FF0FF30F9E700000A4608B597
+:100AB0000421FFF7B1FF80F00100C0B2404208BD41
+:100AC00030B4074B0A461978064B53F82140236887
+:100AD000DD69054B0146AC46204630BC604700BF8F
+:100AE000B823002014220020A086010070B501F078
+:100AF000FDFC094E094D308000242868338883426C
+:100B000008D901F0EDFC2B6804440133B4F5804FA3
+:100B10002B60F2D370BD00BFBA23002078230020E1
+:100B200001F0ACBD00F1006000F580400068704746
+:100B300000F10060920000F5804001F02BBD000044
+:100B4000054B1A68054B1B889B1A834202D9104437
+:100B500001F0C6BC0020704778230020BA23002093
+:100B600038B5084D044629B128682044BDE838400E
+:100B700001F0D6BC2868204401F0BAFC0028F3D06C
+:100B800038BD00BF7823002010F003030AD1B0F570
+:100B9000047F05D200F10050A0F51040D0F80038D5
+:100BA000184670470023FBE700F10050A0F5104005
+:100BB000D0F8100A70470000064991F8243033B18C
+:100BC0000023086A81F824300822FFF7B1BF012012
+:100BD000704700BF7C230020014B1868704700BF9E
+:100BE000002004E070B5194B1D68194B0138C5F39E
+:100BF0000B0408442D0C04221E88A6420BD15C680D
+:100C00000A46013C824213460FD214F9016F4EB1DD
+:100C100002F8016BF6E7013A03F10803ECD18142D7
+:100C20000B4602D22C2203F8012B0A4A052416880F
+:100C3000AE4204D1984284BF967803F8016B013C20
+:100C400002F10402F3D1581A70BD00BF002004E085
+:100C5000B83B0008A43B0008022803D1044B08223B
+:100C60009A6170470128FCD1014B0422F8E700BFCC
+:100C700000100240022804D1054B4FF400229A6173
+:100C800070470128FCD1024B4FF48022F7E700BFE8
+:100C900000100240022805D1064A536983F0080378
+:100CA000536170470128FCD1024A536983F0040361
+:100CB000F6E700BF0010024010B50023934203D0B6
+:100CC000CC5CC4540133F9E710BD000010B5013805
+:100CD00010F9013F3BB191F900409C4203D11AB198
+:100CE0000131013AF4E71AB191F90020981A10BDC8
+:100CF0001046FCE703460246D01A12F9011B0029F0
+:100D0000FAD1704702440346934202D003F8011B14
+:100D1000FAE770472DE9F8431F4D144695F8242053
+:100D20000746884652BBDFF870909CB395F8243094
+:100D30002BB92022FF2148462F62FFF7E3FF95F8E9
+:100D40002400C0F10802A24228BF2246D6B2414682
+:100D5000920005EB8000FFF7AFFF95F82430A41B4D
+:100D60001E44F6B2082E17449044E4B285F824607D
+:100D7000DBD1FFF721FF0028D7D108E02B6A03EB76
+:100D800082038342CFD0FFF717FF0028CBD100208A
+:100D9000BDE8F8830120FBE77C230020024B1A7892
+:100DA000024B1A70704700BFB823002010220020A9
+:100DB00038B5174C174D204600F0B8FB29462046A1
+:100DC00000F0E0FB2D6814486A6D936B23F4002358
+:100DD000936301F06BF81149284600F0D9FC6A6D65
+:100DE0000F4D936B28680F4943F400239363A0428F
+:100DF0004FF4E1330B6001D000F0F8FA6868A042CC
+:100E000004D0BDE83840074900F0F0BA38BD00BF53
+:100E100098280020C03C000840420F00C83C000851
+:100E200014220020A423002070B50C4B0C4D1E781A
+:100E30000C4B55F826209A4204460DD00A4B00214F
+:100E400014221846FFF75EFF0460014655F826009D
+:100E5000BDE8704000F0CABA70BD00BFB8230020E2
+:100E60001422002098280020A423002030B5094D2A
+:100E70000A4491420DD011F8013B5840082340F339
+:100E80000004013B2C4013F0FF0384EA5000F6D12C
+:100E9000EFE730BD2083B8ED02684368114301607D
+:100EA00003B1184770470000024AD36843F0C003FB
+:100EB000D36070470050004010B5054C054A002132
+:100EC000204600F071FA044A044BC4E9972310BD90
+:100ED000BC230020A90E00080050004080DE8002E4
+:100EE000234A037C002918BF0A46012B30B5C0F8FD
+:100EF00068220CD11F4B984209D11F4B196C41F449
+:100F000080111964196E41F4801119661B6EB2F9D3
+:100F100004501468D0F86032D0F85C12002D03EB56
+:100F20005403B3FBF4F3BEBF23F0070503F007033C
+:100F300043EA450394888B60D38843F040030B61F8
+:100F4000138943F001034B6144F4045343F02C0331
+:100F5000CB6004F4A05400230B60B4F5806F0B68E1
+:100F60004B680CBF7F23FF2380F8643230BD00BF85
+:100F7000D83B0008BC230020003802402DE9F04196
+:100F8000D0F85C62F7683368DA0504469DB20DD587
+:100F9000302383F311884FF480610430FFF77CFF26
+:100FA0006FF480733360002383F31188302383F35D
+:100FB000118804F1040815F02F033AD183F3118846
+:100FC000380615D5290613D5302383F3118804F18B
+:100FD000380000F065F900284EDA0821201DFFF7DF
+:100FE0005BFF4FF67F733B40F360002383F3118870
+:100FF0007A0616D56B0614D5302383F31188D4E90D
+:1010000013239A420AD1236C43B127F040073F04CF
+:101010001021201D3F0CFFF73FFFF760002383F3F3
+:101020001188D4F86822D36843B3BDE8F041106951
+:1010300018472B0714D015F0080F0CBF00214FF4F0
+:101040008071E80748BF41F02001AA0748BF41F07E
+:1010500040016B0748BF41F080014046FFF71CFF8D
+:10106000AD06736805D594F864122046194000F067
+:10107000CBF93568ADB29EE77060B6E7BDE8F081A8
+:10108000F8B5154682680669AA420B46816938BFE1
+:101090008568761AB54204460BD218462A46FFF7F1
+:1010A0000BFEA3692B44A361A3685B1BA3602846C6
+:1010B000F8BD0CD918463246FFF7FEFDAF1BE168BC
+:1010C0003A463044FFF7F8FDE3683B44EBE7184647
+:1010D0002A46FFF7F1FDE368E5E7000083689342E5
+:1010E000F7B51546044638BF8568D0E90460361A5E
+:1010F000B5420BD22A46FFF7DFFD63692B446361DB
+:10110000A36828465B1BA36003B0F0BD0DD932462F
+:101110000191FFF7D1FD0199E068AF1B3A463144D8
+:10112000FFF7CAFDE3683B44E9E72A46FFF7C4FD41
+:10113000E368E4E710B50A440024C361029B8460BD
+:10114000C0E90000C0E90511C1600261036210BD81
+:1011500008B5D0E90532934201D1826882B982682C
+:10116000013282605A1C42611970D0E904329A42FD
+:1011700024BFC3684361002100F0B4FE002008BD15
+:101180004FF0FF30FBE7000070B5302304460E46F9
+:1011900083F31188A568A5B1A368A269013BA36088
+:1011A000531CA36115782269934224BFE368A361AD
+:1011B000E3690BB120469847002383F31188284642
+:1011C00007E03146204600F07DFE0028E2DA85F394
+:1011D000118870BD2DE9F74F04460E461746984614
+:1011E000D0F81C904FF0300A8AF311884FF0000BB2
+:1011F000154665B12A4631462046FFF741FF0346B2
+:1012000060B94146204600F05DFE0028F1D0002381
+:1012100083F31188781B03B0BDE8F08FB9F1000F9C
+:1012200003D001902046C847019B8BF31188ED1A2B
+:101230001E448AF31188DCE7C0E90511C160C3616F
+:101240001144009B8260C0E90000016103627047A5
+:10125000F8B504460D461646302383F31188A76877
+:10126000A7B1A368013BA36063695A1C62611D704A
+:10127000D4E904329A4224BFE3686361E3690BB1A5
+:1012800020469847002080F3118807E03146204629
+:1012900000F018FE0028E2DA87F31188F8BD00009C
+:1012A000D0E905239A4210B501D182687AB98268E3
+:1012B000013282605A1C82611C7803699A4224BF01
+:1012C000C3688361002100F00DFE204610BD4FF081
+:1012D000FF30FBE72DE9F74F04460E4617469846C8
+:1012E000D0F81C904FF0300A8AF311884FF0000BB1
+:1012F000154665B12A4631462046FFF7EFFE034604
+:1013000060B94146204600F0DDFD0028F1D0002301
+:1013100083F31188781B03B0BDE8F08FB9F1000F9B
+:1013200003D001902046C847019B8BF31188ED1A2A
+:101330001E448AF31188DCE70268436811430160A8
+:1013400003B11847704700001430FFF743BF000097
+:101350004FF0FF331430FFF73DBF00003830FFF788
+:10136000B9BF00004FF0FF333830FFF7B3BF0000C4
+:101370001430FFF709BF00004FF0FF311430FFF7C2
+:1013800003BF00003830FFF763BF00004FF0FF32AB
+:101390003830FFF75DBF0000012914BF6FF0130064
+:1013A00000207047FFF788BD37B515460E4A02602A
+:1013B00000224260C0E902220122044602740B4668
+:1013C000009000F15C014FF480721430FFF7B2FE20
+:1013D00000942B464FF4807204F5AE7104F138008E
+:1013E000FFF72AFF03B030BDEC3B000810B53023F7
+:1013F000044683F31188FFF773FD02232374002052
+:1014000080F3118810BD000038B5C36904460D464D
+:101410001BB904210844FFF78FFF294604F114008B
+:10142000FFF796FE002806DA201D4FF40061BDE8A4
+:101430003840FFF781BF38BD02684368114301603F
+:1014400003B118477047000013B5446BD4F89434C7
+:101450001A681178042915D1217C022912D1197931
+:10146000128901238B4013420CD101A904F14C00D5
+:1014700001F04EFFD4F89444019B21790246206884
+:1014800000F0D0F902B010BD143001F0D1BE000060
+:101490004FF0FF33143001F0CBBE00004C3001F0B0
+:1014A000A3BF00004FF0FF334C3001F09DBF0000A0
+:1014B000143001F09FBE00004FF0FF31143001F0F6
+:1014C00099BE00004C3001F06FBF00004FF0FF32BA
+:1014D0004C3001F069BF00000020704710B5D0F813
+:1014E00094341A6811780429044617D1017C022922
+:1014F00014D15979528901238B4013420ED11430F3
+:1015000001F032FE024648B1D4F894444FF480739F
+:1015100061792068BDE8104000F072B910BD00008C
+:10152000406BFFF7DBBF0000704700007FB5124B38
+:10153000036000234360C0E90233012502260F4BFC
+:10154000057404460290019300F184022946009636
+:101550004FF48073143001F0E3FD094B0294CDE9A0
+:10156000006304F523724FF48073294604F14C00A4
+:1015700001F0AAFE04B070BD143C0008211500085B
+:10158000491400080B68302282F311880A7903EBB2
+:10159000820290614A79093243F822008A7912B1B5
+:1015A00003EB820398610223C0F8941403740020B3
+:1015B00080F311887047000038B5037F044613B1EB
+:1015C00090F85430ABB9201D01250221FFF734FFFC
+:1015D00004F1140025776FF0010100F08FFC84F80E
+:1015E000545004F14C006FF00101BDE8384000F0A8
+:1015F00085BC38BD10B5012104460430FFF71CFF3F
+:101600000023237784F8543010BD000038B5044619
+:101610000025143001F09CFD04F14C00257701F009
+:101620006BFE201D84F854500121FFF705FF204672
+:10163000BDE83840FFF752BF90F8443003F0600334
+:10164000202B07D190F84520212A4FF0000303D822
+:101650001F2A06D800207047222AFBD1C0E90E338A
+:1016600003E0034A82630722C263036401207047D8
+:101670001C22002037B5D0F894341A681178042958
+:1016800004461AD1017C022917D119791289012344
+:101690008B40134211D100F14C05284601F0ECFEBD
+:1016A00058B101A9284601F033FED4F89444019BB7
+:1016B00021790246206800F0B5F803B030BD000083
+:1016C000F0B500EB810385B09E6904460D46FEB17E
+:1016D000302383F3118804EB8507301D0821FFF7C1
+:1016E000ABFEFB685B691B6806F14C001BB1019007
+:1016F00001F01CFE019803A901F00AFE024648B160
+:10170000039B2946204600F08DF8002383F31188BF
+:1017100005B0F0BDFB685A691268002AF5D01B8A33
+:10172000013B1340F1D104F14402EAE7093138B535
+:1017300050F82140DCB1302383F31188D4F894248D
+:101740001368527903EB8203DB689B695D6845B1DE
+:1017500004216018FFF770FE294604F1140001F01F
+:101760000DFD2046FFF7BAFE002383F3118838BD34
+:101770007047000001F06CB8012303700023C0E93A
+:101780000133C36183620362C362436203637047D0
+:1017900038B50446302383F311880025C0E903558A
+:1017A000C0E90555416001F063F80223237085F319
+:1017B0001188284638BD000070B500EB810305464E
+:1017C0005069DA600E46144618B110220021FFF766
+:1017D00099FAA06918B110220021FFF793FA314657
+:1017E0002846BDE8704001F00DB90000826802F0A3
+:1017F000011282600022C0E90422826101F08EB9E8
+:10180000F0B400EB81044789E4680125A4698D40A8
+:101810003D43458123600023A2606360F0BC01F07A
+:10182000A9B90000F0B400EB81040789E468012540
+:1018300064698D403D43058123600023A26063609D
+:10184000F0BC01F023BA000070B502230025044665
+:101850000370C0E90255C0E90455C564856180F88C
+:10186000345001F06BF863681B6823B129462046A9
+:10187000BDE87040184770BD0378052B10B50446CD
+:101880000AD080F850300523037043681B680BB101
+:10189000042198470023A36010BD000001780529AA
+:1018A00006D190F85020436802701B6803B11847B6
+:1018B0007047000070B590F83430044613B100232F
+:1018C00080F8343004F14402204601F049F963689D
+:1018D0009B68B3B994F8443013F0600535D000210B
+:1018E000204601F0E9FB0021204601F0DBFB6368A4
+:1018F0001B6813B1062120469847062384F834302C
+:1019000070BD204698470028E4D0B4F84A30E26B16
+:101910009A4288BFE36394F94430E56B002B4FF0A3
+:10192000300380F20381002D00F0F280092284F858
+:10193000342083F311880021D4E90E232046FFF7D9
+:1019400071FF002383F31188DAE794F8452003F050
+:101950007F0343EA022340F20232934200F0C58043
+:1019600021D8B3F5807F48D00DD8012B3FD0022B72
+:1019700000F09380002BB2D104F14C02A26302224A
+:10198000E2632364C1E7B3F5817F00F09B80B3F588
+:10199000407FA4D194F84630012BA0D1B4F84C304C
+:1019A00043F0020332E0B3F5006F4DD017D8B3F522
+:1019B000A06F31D0A3F5C063012B90D8636894F871
+:1019C00046205E6894F84710B4F848302046B04787
+:1019D000002884D04368A3630368E3631AE0B3F587
+:1019E000106F36D040F6024293427FF478AF5C4BE2
+:1019F000A3630223E3630023C3E794F84630012B7B
+:101A00007FF46DAFB4F84C3023F00203C4E90E55F7
+:101A1000A4F84C30256478E7B4F84430B3F5A06FEF
+:101A20000ED194F8463084F84E30204600F0DEFFA8
+:101A300063681B6813B10121204698470323237074
+:101A40000023C4E90E339CE704F14F03A363012391
+:101A5000C3E72378042B10D1302383F31188204669
+:101A6000FFF7C4FE85F311880321636884F84F50A3
+:101A700021701B680BB12046984794F84630002B24
+:101A8000DED084F84F300423237063681B68002B7A
+:101A9000D6D0022120469847D2E794F848301D0658
+:101AA00003F00F0120460AD501F04CF8012804D0BC
+:101AB00002287FF414AF2B4B9AE72B4B98E701F0E9
+:101AC00033F8F3E794F84630002B7FF408AF94F82E
+:101AD000483013F00F01B3D01A06204602D501F0AA
+:101AE000FFFAADE701F0F2FAAAE794F84630002BCE
+:101AF0007FF4F5AE94F8483013F00F01A0D01B0628
+:101B0000204602D501F0D8FA9AE701F0CBFA97E720
+:101B1000142284F8342083F311882B462A46294660
+:101B20002046FFF76DFE85F31188E9E65DB11522C9
+:101B300084F8342083F311880021D4E90E23204651
+:101B4000FFF75EFEFDE60B2284F8342083F3118854
+:101B50002B462A4629462046FFF764FEE3E700BFEE
+:101B6000443C00083C3C0008403C000838B590F874
+:101B700034300446002B3ED0063BDAB20F2A34D86C
+:101B80000F2B32D8DFE803F0373131082232313100
+:101B90003131313131313737C56BB0F84A309D4280
+:101BA00014D2C3681B8AB5FBF3F203FB12556DB95F
+:101BB000302383F311882B462A462946FFF732FE4D
+:101BC00085F311880A2384F834300EE0142384F856
+:101BD0003430302383F3118800231A4619462046F7
+:101BE000FFF70EFE002383F3118838BD036C03B1A9
+:101BF00098470023E7E70021204601F05DFA002125
+:101C0000204601F04FFA63681B6813B10621204695
+:101C100098470623D7E7000010B590F83430142B0E
+:101C2000044629D017D8062B05D001D81BB110BD0A
+:101C3000093B022BFBD80021204601F03DFA002190
+:101C4000204601F02FFA63681B6813B10621204675
+:101C50009847062319E0152BE9D10B2380F834307F
+:101C6000302383F3118800231A461946FFF7DAFD63
+:101C7000002383F31188DAE7C3689B695B68002B54
+:101C8000D5D1036C03B19847002384F83430CEE7F4
+:101C900000230375826803691B6899689142FBD22F
+:101CA0005A680360426010605860704700230375F3
+:101CB000826803691B6899689142FBD85A6803607F
+:101CC000426010605860704708B50846302383F3BF
+:101CD00011880B7D032B05D0042B0DD02BB983F37A
+:101CE000118808BD8B6900221A604FF0FF338361B1
+:101CF000FFF7CEFF0023F2E7D1E9003213605A600C
+:101D0000F3E70000FFF7C4BF054BD96808751868F2
+:101D100002681A60536001220275D860FEF7F2BAB9
+:101D20002826002030B50C4BDD684B1C87B00446DC
+:101D30000FD02B46094A684600F074F92046FFF799
+:101D4000E3FF009B13B1684600F076F9A86907B07D
+:101D500030BDFFF7D9FFF9E728260020C91C00088D
+:101D6000044B1A68DB6890689B68984294BF002017
+:101D70000120704728260020084B10B51C68D86841
+:101D800022681A60536001222275DC60FFF78EFF23
+:101D900001462046BDE81040FEF7B4BA28260020D0
+:101DA000044B1A68DB6892689B689A4201D9FFF776
+:101DB000E3BF70472826002038B5074C074908487C
+:101DC000012300252370656001F094FB022323703A
+:101DD00085F3118838BD00BF902800204C3C0008D6
+:101DE0002826002000F05EB9EFF3118020B9EFF350
+:101DF0000583302282F311887047000010B530B996
+:101E0000EFF30584C4F3080414B180F3118810BD06
+:101E1000FFF7C6FF84F31188F9E70000034A516811
+:101E200053685B1A9842FBD8704700BF001000E06F
+:101E30008B60022308618B82084670478368A3F198
+:101E4000840243F8142C026943F8442C426943F895
+:101E5000402C094A43F8242CC26843F8182C02226B
+:101E600003F80C2C002203F80B2C044A43F8102C26
+:101E7000A3F12000704700BF1D03000828260020A2
+:101E800008B5FFF7DBFFBDE80840FFF73BBF0000E8
+:101E9000024BDB6898610F20FFF736BF2826002031
+:101EA000302383F31188FFF7F3BF000008B5014624
+:101EB000302383F311880820FFF734FF002383F3D6
+:101EC000118808BD064BDB6839B1426818605A605A
+:101ED000136043600420FFF725BF4FF0FF307047C9
+:101EE000282600200368984206D01A6802605060D5
+:101EF00099611846FFF706BF7047000038B50446E1
+:101F00000D462068844200D138BD036823605C60C0
+:101F10008561FFF7F7FEF4E710B503689C68A242FD
+:101F20000CD85C688A600B604C60216059609968CD
+:101F30008A1A9A604FF0FF33836010BD1B68121B32
+:101F4000ECE700000A2938BF0A2170B504460D46A7
+:101F50000A26601901F0C6FA01F0AEFA041BA54288
+:101F600003D8751C2E460446F3E70A2E04D9BDE8B3
+:101F70007040012001F0FEBA70BD0000F8B5144BAE
+:101F80000D46D96103F1100141600A2A1969826086
+:101F900038BF0A22016048601861A818144601F091
+:101FA00091FA0A2701F088FA431BA342064606D39A
+:101FB0007C1C281901F096FA27463546F2E70A2FCD
+:101FC00004D9BDE8F840012001F0D4BAF8BD00BF43
+:101FD00028260020F8B506460D4601F06DFA0F4A96
+:101FE000134653F8107F9F4206D12A4601463046D9
+:101FF000BDE8F840FFF7C2BFD169BB68441A2C198D
+:1020000028BF2C46A34202D92946FFF79BFF224650
+:1020100031460348BDE8F840FFF77EBF2826002080
+:102020003826002010B4C0E9032300235DF8044BD8
+:102030004361FFF7CFBF000010B5194C23699842E8
+:102040000DD0D0E90032816813605A609A680A4462
+:102050009A60002303604FF0FF33A36110BD234655
+:10206000026843F8102F53600022026022699A42EE
+:1020700003D1BDE8104001F02FBA936881680B448A
+:10208000936001F019FA2269E1699268441AA24248
+:10209000E4D91144BDE81040091AFFF753BF00BF4F
+:1020A000282600202DE9F047DFF8BC8008F1100752
+:1020B0002C4ED8F8105001F0FFF9D8F81C40AA684F
+:1020C000031B9A423ED81444D5E900324FF0000970
+:1020D000C8F81C4013605A60C5F80090D8F810305A
+:1020E000B34201D101F0F8F989F31188D5E9033140
+:1020F00028469847302383F311886B69002BD8D08A
+:1021000001F0DAF96A69A0EB04094A4582460DD26A
+:10211000022001F02FFA0022D8F81030B34208D183
+:1021200051462846BDE8F047FFF728BF121A22445F
+:10213000F2E712EB090938BF4A4629463846FFF74D
+:10214000EBFEB5E7D8F81030B34208D01444211A9A
+:10215000C8F81C00A960BDE8F047FFF7F3BEBDE872
+:10216000F08700BF38260020282600200020704776
+:10217000FEE70000704700004FF0FF30704700009E
+:1021800002290CD0032904D00129074818BF0020D8
+:102190007047032A05D8054800EBC2007047044881
+:1021A00070470020704700BF243D00082C2200200B
+:1021B000D83C000870B59AB00546084601A91446F7
+:1021C00000F0C2F801A8FEF795FD431C5B00C5E9CD
+:1021D00000340022237003236370C6B201AB0234C3
+:1021E0001046D1B28E4204F1020401D81AB070BD7B
+:1021F00013F8011B04F8021C04F8010C0132F0E78B
+:1022000008B5302383F311880348FFF733FA00231E
+:1022100083F3118808BD00BF9828002090F844304F
+:1022200003F01F02012A07D190F845200B2A03D1A1
+:102230000023C0E90E3315E003F06003202B08D122
+:10224000B0F848302BB990F84520212A03D81F2A2E
+:1022500004D8FFF7F1B9222AEBD0FAE7034A8263E8
+:102260000722C26303640120704700BF23220020BD
+:1022700007B5052917D8DFE801F019160319192049
+:10228000302383F31188104A01900121FFF794FA5B
+:1022900001980E4A0221FFF78FFA0D48FFF7B6F9B1
+:1022A000002383F3118803B05DF804FB302383F32C
+:1022B00011880748FFF780F9F2E7302383F311888C
+:1022C0000348FFF797F9EBE7783C00089C3C0008CF
+:1022D0009828002038B50C4D0C4C0D492A4604F1C5
+:1022E0000800FFF767FF05F1CA0204F11000094971
+:1022F000FFF760FF05F5CA7204F118000649BDE852
+:102300003840FFF757BF00BF602D00202C2200206F
+:10231000583C0008623C00086D3C000870B504465B
+:1023200008460D46FEF7E6FCC6B2204601340378A7
+:102330000BB9184670BD32462946FEF7C7FC002887
+:10234000F3D10120F6E700002DE9F04705460C46E1
+:10235000FEF7D0FC2B49C6B22846FFF7DFFF08B1D5
+:102360000736F6B228492846FFF7D8FF08B11036DD
+:10237000F6B2632E0BD8DFF88C80DFF88C90234FF9
+:10238000DFF894A02E7846B92670BDE8F08729467C
+:102390002046BDE8F04701F0E7BB252E2ED10722ED
+:1023A00041462846FEF792FC70B9194B224603F1CC
+:1023B0000C0153F8040B42F8040B8B42F9D11B8833
+:1023C000138007350E34DDE7082249462846FEF71C
+:1023D0007DFC98B90F4BA21C197809090232C95D1E
+:1023E00002F8041C13F8011B01F00F015345C95DED
+:1023F00002F8031CF0D118340835C3E704F8016B68
+:102400000135BFE7443D00086D3C00085B3D000816
+:102410004C3D0008107AFF1F1C7AFF1FBFF34F8F3F
+:10242000024AD368DB03FCD4704700BF003C024083
+:1024300008B5094B1B7873B9FFF7F0FF074B1A6912
+:10244000002ABFBF064A5A6002F188325A601A68F1
+:1024500022F480621A6008BDBE2F0020003C0240BA
+:102460002301674508B50B4B1B7893B9FFF7D6FFDF
+:10247000094B1A6942F000421A611A6842F480520C
+:102480001A601A6822F480521A601A6842F4806254
+:102490001A6008BDBE2F0020003C02401728F0B58E
+:1024A00016D80C4C0C4923787BB90C4D0E461823DA
+:1024B0004FF0006255F8047B46F8042B013B13F003
+:1024C000FF033A44F6D10123237051F82000F0BDF8
+:1024D0000020FCE720300020C02F00206C3D0008C9
+:1024E000014B53F8200070476C3D000818207047DE
+:1024F000172810B5044601D9002010BDFFF7CEFF04
+:10250000064B53F824301844C21A0BB90120F4E7E3
+:1025100012680132F0D1043BF6E700BF6C3D0008C1
+:10252000172870B504462FD8FFF75EFC1749FFF750
+:1025300075FFFFF77DFFF323CB600C23B4FBF3F2B1
+:1025400003FB1245D30143EAC503DBB243F4007336
+:1025500043F002030B610B6943F480330B610646C1
+:102560002046FFF75BFFFFF799FF094B53F8241054
+:1025700000F0E8F83046FFF775FFFFF73FFC204614
+:10258000BDE87040FFF7B4BF002070BD003C0240C2
+:102590006C3D000812F001032DE9F04105460E469E
+:1025A00014464BD18218B2F1026F61D8314B1B68CF
+:1025B00013F001035CD0304FFFF716FCFFF738FF34
+:1025C000F323FB60FFF72AFF314640F20128032C7A
+:1025D00018D824F00104284E0C446D1A40F201185A
+:1025E000A142336905EB01072AD123F001033361CE
+:1025F000FFF738FFFFF702FC0120BDE8F081043C43
+:102600000435E4E7AB07E4D13B6923F440733B6155
+:102610003B6943EA08033B6151F8046B2E60BFF34A
+:102620004F8FFFF7FBFE2B689E42E8D03B6923F0FB
+:1026300001033B61FFF716FFFFF7E0FB0020DCE73B
+:1026400023F440733361336943EA080333610B8831
+:102650003B80BFF34F8FFFF7E1FE3F8831F8023B2D
+:10266000BFB2BB42BCD0336923F001033361E1E761
+:102670001846C2E700380240003C0240084908B54D
+:102680000B7828B11BB9FFF7D3FE01230B7008BDEF
+:10269000002BFCD0BDE808400870FFF7E3BE00BF88
+:1026A000BE2F002010B50244064BD2B2904200D19A
+:1026B00010BD441C00B253F8200041F8040BE0B2F6
+:1026C000F4E700BF502800400F4B30B51C6F2404C6
+:1026D00007D41C6F44F400741C671C6F44F400445E
+:1026E0001C670A4C236843F4807323600244084B40
+:1026F000D2B2904200D130BD441C00B251F8045B0C
+:1027000043F82050E0B2F4E7003802400070004087
+:102710005028004007B5012201A90020FFF7C2FFA1
+:10272000019803B05DF804FB13B50446FFF7F2FF10
+:10273000A04205D0012201A900200194FFF7C4FFA7
+:1027400002B010BD70470000094B5A88B2F5805F97
+:1027500010460BD022F0020341F20102934205D051
+:1027600041F20703C31A584258417047012070478D
+:10277000002004E0034B1A681AB9034AD2F87428FF
+:102780001A607047243000200030024008B5FFF77F
+:10279000F1FF024B1868C0F3407008BD24300020E0
+:1027A00070470000FEE700000A4B0B480B4A9042BE
+:1027B0000BD30B4BDA1C121AC11E22F003028B4200
+:1027C00038BF00220021FEF79DBA53F8041B40F8E1
+:1027D000041BECE7543F000820310020203100208A
+:1027E0002031002070B5D0E915439E6800224FF0DB
+:1027F000FF3504EB42135101D3F800090028BEBF96
+:10280000D3F8000940F08040C3F80009D3F8000B6A
+:102810000028BEBFD3F8000B40F08040C3F8000B87
+:10282000013263189642C3F80859C3F8085BE0D236
+:102830004FF00113C4F81C3870BD0000890141F04D
+:102840002001016103699B06FCD41220FFF7E6BA60
+:1028500010B5054C2046FEF78FFF4FF0A04363658F
+:10286000024BA36510BD00BF28300020F03D0008DA
+:1028700070B50378012B054650D12A4B446D984220
+:102880001BD1294B5A6B42F080025A635A6D42F0B9
+:1028900080025A655A6D5A6942F080025A615A693B
+:1028A00022F080025A610E2143205B6900F022FC75
+:1028B0001E4BE3601E4BC4F800380023C4F8003EF2
+:1028C000C02323606E6D4FF45023A3633369002B44
+:1028D000FCDA012333610C20FFF7A0FA3369DB0730
+:1028E000FCD41220FFF79AFA3369002BFCDA002699
+:1028F000A6602846FFF776FF6B68C4F81068DB68AF
+:10290000C4F81468C4F81C684BB90A4BA3614FF0B3
+:10291000FF336361A36843F00103A36070BD064BFE
+:10292000F4E700BF28300020003802404014004087
+:1029300003002002003C30C0083C30C0F8B5446DB4
+:10294000054600212046FFF779FFA96D00234FF0CF
+:1029500001128F68C4F834384FF00066C4F81C28A0
+:102960004FF0FF3004EB431201339F42C2F800697D
+:10297000C2F8006BC2F80809C2F8080BF2D20B6863
+:102980006A6DEB65636210231361166916F0100619
+:10299000FBD11220FFF742FAD4F8003823F4FE638B
+:1029A000C4F80038A36943F4402343F01003A36143
+:1029B0000923C4F81038C4F814380A4BEB604FF000
+:1029C000C043C4F8103B084BC4F8003BC4F810697E
+:1029D000C4F80039EB6D03F1100243F48013EA658B
+:1029E000A362F8BDCC3D000840800010426D90F815
+:1029F0004E10D2F8003823F4FE6343EA0113C2F804
+:102A0000003870472DE9F84300EB8103456DDA6823
+:102A1000166806F00306731E022B05EB41130C46E5
+:102A200080460FFA81F94FEA41104FF00001C3F8D8
+:102A3000101B4FF0010104F1100398BFB60401FA16
+:102A400003F391698EBF334E06F1805606F50046BA
+:102A500000293AD0578A04F15801490137436F5091
+:102A6000D5F81C180B43C5F81C382B180021C3F8E7
+:102A7000101953690127611EA7409BB3138A928BDB
+:102A80009B08012A88BF5343D8F85C20981842EA73
+:102A9000034301F1400205EB8202C8F85C002146C5
+:102AA00053602846FFF7CAFE08EB8900C3681B8AFB
+:102AB00043EA8453483464011E432E51D5F81C3830
+:102AC0001F43C5F81C78BDE8F88305EB4917D7F814
+:102AD000001B21F40041C7F8001BD5F81C1821EA9F
+:102AE0000303C0E704F13F0305EB83030A4A5A607E
+:102AF00028462146FFF7A2FE05EB4910D0F8003921
+:102B000023F40043C0F80039D5F81C3823EA07073E
+:102B1000D7E700BF0080001000040002826D126839
+:102B2000C265FFF75FBE00005831436D49015B5835
+:102B300013F4004004D013F4001F0CBF0220012046
+:102B4000704700004831436D49015B5813F4004061
+:102B500004D013F4001F0CBF0220012070470000B6
+:102B600000EB8101CB68196A0B6813604B685360F6
+:102B70007047000000EB810330B5DD68AA69136877
+:102B8000D36019B9402B84BF402313606B8A14684B
+:102B9000426D1C44013CB4FBF3F46343033323F064
+:102BA000030302EB411043EAC44343F0C043C0F8BF
+:102BB000103B2B6803F00303012B09B20ED1D2F8AE
+:102BC000083802EB411013F4807FD0F8003B14BFAB
+:102BD00043F0805343F00053C0F8003B02EB411236
+:102BE000D2F8003B43F00443C2F8003B30BD000084
+:102BF0002DE9F041244D6E6D06EB40130446D3F8E9
+:102C0000087BC3F8087B38070AD5D6F814381907AB
+:102C100006D505EB84032146DB6828465B689847A8
+:102C2000FA071FD5D6F81438DB071BD505EB84034C
+:102C3000D968CCB98B69488A5A68B2FBF0F600FBB8
+:102C400016228AB91868DA6890420DD2121AC3E9BE
+:102C50000024302383F311880B482146FFF78AFFB5
+:102C600084F31188BDE8F081012303FA04F26B8933
+:102C700023EA02036B81CB68002BF3D02146024884
+:102C8000BDE8F041184700BF2830002000EB810369
+:102C900070B5DD68436D6C692668E6604A0156BB15
+:102CA0001A444FF40020C2F810092A6802F0030207
+:102CB000012A0AB20ED1D3F8080803EB421410F42B
+:102CC000807FD4F8000914BF40F0805040F00050DD
+:102CD000C4F8000903EB4212D2F8000940F00440A6
+:102CE000C2F80009D3F83408012202FA01F10143C5
+:102CF000C3F8341870BD19B9402E84BF402020603D
+:102D000020682E8A8419013CB4FBF6F440EAC440E2
+:102D100040F000501A44C6E72DE9F8433B4D6E6D74
+:102D200006EB40130446D3F80889C3F8088918F065
+:102D3000010F4FEA40171AD0D6F81038DB0716D526
+:102D400005EB8003D9684B691868DA68904230D285
+:102D5000121A4FF000091A60C3F80490302383F36D
+:102D6000118821462846FFF791FF89F3118818F052
+:102D7000800F1CD0D6F834380126A640334216D036
+:102D800005EB84036D6DD3F80CC0DCF8142001341E
+:102D9000E4B2D2F800E005EB04342F4451687145E9
+:102DA00015D3D5F8343823EA0606C5F83468BDE8EB
+:102DB000F883012303FA04F22B8923EA02032B810F
+:102DC0008B68002BD3D0214628469847CFE7BCF824
+:102DD0001000AEEB0103834228BF0346D7F8180961
+:102DE00080B2B3EB800FE2D89068A0F1040959F8E3
+:102DF000048FC4F80080A0EB09089844B8F1040FD0
+:102E0000F5D818440B4490605360C7E72830002081
+:102E10002DE9F74FA24C656D6E69AB691E4016F443
+:102E200080586E6107D02046FEF70EFD03B0BDE866
+:102E3000F04F00F04DBC002E12DAD5F8003E984855
+:102E40009B071EBFD5F8003E23F00303C5F8003EE4
+:102E5000D5F8043823F00103C5F80438FEF71EFD49
+:102E6000370505D58E48FFF7BDFC8D48FEF704FDFC
+:102E7000B0040CD5D5F8083813F0060FEB6823F42E
+:102E800070530CBF43F4105343F4A053EB6031076D
+:102E90001BD56368DB681BB9AB6923F00803AB6122
+:102EA0002378052B0CD1D5F8003E7D489A071EBF2C
+:102EB000D5F8003E23F00303C5F8003EFEF7EEFC14
+:102EC0006368DB680BB176489847F30274D4B702A5
+:102ED00027D5D4F85490DFF8C8B100274FF0010A85
+:102EE00009EB4712D2F8003B03F44023B3F5802FDF
+:102EF00011D1D2F8003B002B0DDA62890AFA07F3F0
+:102F000022EA0303638104EB8703DB68DB6813B108
+:102F1000394658469847A36D01379B68FFB29F42D8
+:102F2000DED9F00617D5676D3A6AC2F30A1002F0CF
+:102F30000F0302F4F012B2F5802F00F08580B2F595
+:102F4000402F08D104EB83030022DB681B6A07F5DE
+:102F5000805790426AD13003D5F8184813D5E10361
+:102F600002D50020FFF744FEA20302D50120FFF79F
+:102F70003FFE630302D50220FFF73AFE270302D586
+:102F80000320FFF735FE75037FF550AFE00702D54C
+:102F90000020FFF7C1FEA10702D50120FFF7BCFE0C
+:102FA000620702D50220FFF7B7FE23077FF53EAF89
+:102FB0000320FFF7B1FE39E7636DDFF8E4A001936A
+:102FC00000274FF00109A36D9B685FFA87FB9B45C3
+:102FD0003FF67DAF019B03EB4B13D3F8001901F4CF
+:102FE0004021B1F5802F1FD1D3F8001900291BDA39
+:102FF000D3F8001941F09041C3F80019D3F8001933
+:103000000029FBDB5946606DFFF718FC218909FA9E
+:103010000BF321EA0303238104EB8B03DB689B683A
+:1030200013B15946504698470137CCE7910708BF7E
+:10303000D7F80080072A98BF03F8018B02F101023C
+:1030400098BF4FEA182884E7023304EB830207F5A0
+:1030500080575268D2F818C0DCF80820DCE9001C60
+:10306000A1EB0C0C002188420AD104EB83046368B5
+:103070009B699A6802449A605A6802445A606AE7F7
+:1030800011F0030F08BFD7F800808C4588BF02F805
+:10309000018B01F1010188BF4FEA1828E3E700BF67
+:1030A00028300020436D03EB4111D1F8003B43F47D
+:1030B0000013C1F8003B7047436D03EB4111D1F899
+:1030C000003943F40013C1F800397047436D03EB36
+:1030D0004111D1F8003B23F40013C1F8003B7047C5
+:1030E000436D03EB4111D1F8003923F40013C1F80B
+:1030F0000039704700F1604303F561430901C9B22B
+:1031000083F80013012200F01F039A4043099B003B
+:1031100003F1604303F56143C3F880211A607047EF
+:1031200030B5039C0172043304FB0325C0E9065348
+:10313000049B03630021059BC160C0E90000C0E956
+:103140000422C0E90842C0E90A11436330BD00000F
+:10315000416A0022C0E90411C0E90A22C2606FF08E
+:103160000101FEF7CBBE0000D0E90432934201D149
+:10317000C2680AB9181D70470020704703691960BA
+:10318000C2680132C260C26913448269036193421A
+:1031900024BF436A03610021FEF7A4BE38B504468C
+:1031A0000D46E3683BB16269131D1268A3621344C4
+:1031B000E362002007E0237A33B929462046FEF770
+:1031C00081FE0028EDDA38BD6FF00100FBE700005A
+:1031D000C368C269013BC3604369134482694361A8
+:1031E000934224BF436A436100238362036B03B1AC
+:1031F0001847704770B53023044683F31188866AF8
+:103200003EB9FFF7CBFF054618B186F31188284673
+:1032100070BDA36AE26A13F8015BA362934202D312
+:103220002046FFF7D5FF002383F31188EFE7000066
+:103230002DE9F84F04460E46174698464FF03009E0
+:1032400089F311880025AA46D4F828B0BBF1000FF5
+:1032500009D141462046FFF7A1FF20B18BF3118829
+:103260002846BDE8F88FD4E90A12A7EB050B521ADD
+:10327000934528BF9346BBF1400F1BD9334601F15C
+:10328000400251F8040B43F8040B9142F9D1A36AB0
+:1032900040334036A3624035D4E90A239A4202D330
+:1032A0002046FFF795FF8AF31188BD42D8D289F3F3
+:1032B0001188C9E730465A46FDF7FEFCA36A5B4415
+:1032C0005E44A3625D44E7E710B5029C01720433DB
+:1032D00003FB0421C0E906130023C0E90A33039B62
+:1032E0000363049BC460C0E90000C0E90422C0E994
+:1032F0000842436310BD0000026AC260426AC0E92E
+:1033000004220022C0E90A226FF00101FEF7F6BD97
+:10331000D0E904239A4201D1C26822B9184650F874
+:10332000043B0B60704700231846FAE7C368C26984
+:103330000133C3604369134482694361934224BFEC
+:10334000436A43610021FEF7CDBD000038B5044655
+:103350000D46E3683BB123691A1DA262E26913447A
+:10336000E362002007E0237A33B929462046FEF7BE
+:10337000A9FD0028EDDA38BD6FF00100FBE7000081
+:1033800003691960C268013AC260C2691344826964
+:103390000361934224BF436A036100238362036B8A
+:1033A00003B118477047000070B530230D4604463E
+:1033B000114683F31188866A2EB9FFF7C7FF10B153
+:1033C00086F3118870BDA36A1D70A36AE26A013397
+:1033D0009342A36204D3E16920460439FFF7D0FF8A
+:1033E000002080F31188EDE72DE9F84F04460D46E3
+:1033F000904699464FF0300A8AF311880026B3466A
+:10340000A76A4FB949462046FFF7A0FF20B187F3CE
+:1034100011883046BDE8F88FD4E90A073A1AA8EBBC
+:103420000607974228BF1746402F1BD905F14003D6
+:1034300055F8042B40F8042B9D42F9D1A36A403380
+:10344000A3624036D4E90A239A4204D3E1692046B4
+:103450000439FFF795FF8BF311884645D9D28AF3DB
+:103460001188CDE729463A46FDF726FCA36A3B447E
+:103470003D44A3623E44E5E7D0E904239A4217D1D4
+:10348000C3689BB1836A8BB1043B9B1A0ED0136057
+:10349000C368013BC360C3691A44836902619A42ED
+:1034A00024BF436A036100238362012318467047E7
+:1034B0000023FBE700F036B9014B586A704700BFA4
+:1034C000000C0040034B002258631A610222DA60AC
+:1034D000704700BF000C0040014B0022DA607047CB
+:1034E000000C0040014B5863704700BF000C0040C7
+:1034F000FEE7000070B51B4B01630025044686B053
+:10350000586085620E4600F0BFF804F11003C4E96C
+:1035100004334FF0FF33C4E90635C4E90044A56025
+:10352000E562FFF7C9FF2B460246C4E9082304F110
+:1035300034010D4A256580232046FEF779FC0123DE
+:10354000E0600A4A0375009272680192B268CDE9A0
+:103550000223074B6846CDE90435FEF791FC06B01F
+:1035600070BD00BF90280020FC3D0008013E00080F
+:10357000F1340008024AD36A1843D062704700BF92
+:10358000282600204B6843608B688360CB68C3604B
+:103590000B6943614B6903628B6943620B6803608B
+:1035A0007047000008B5264B26481A6940F2FF1103
+:1035B0000A431A611A6922F4FF7222F001021A61A9
+:1035C0001A691A6B0A431A631A6D0A431A651E4A6E
+:1035D0001B6D1146FFF7D6FF02F11C0100F580605C
+:1035E000FFF7D0FF02F1380100F58060FFF7CAFF56
+:1035F00002F1540100F58060FFF7C4FF02F1700191
+:1036000000F58060FFF7BEFF02F18C0100F58060DD
+:10361000FFF7B8FF02F1A80100F58060FFF7B2FFE5
+:1036200002F1C40100F58060FFF7ACFF02F1E00198
+:1036300000F58060FFF7A6FFBDE8084000F0F0B895
+:103640000038024000000240083E000808B500F0C3
+:103650006BFAFEF7B1FBFFF78DF8BDE80840FEF707
+:1036600039BE000070470000EFF3098305494A6B3B
+:1036700022F001024A63683383F30988002383F34D
+:103680001188704700EF00E0302080F3118862B6A7
+:103690000C4B0D4AD96821F4E0610904090C0A4376
+:1036A000DA60D3F8FC20094942F08072C3F8FC20AC
+:1036B0000A6842F001020A602022DA7783F82200C9
+:1036C000704700BF00ED00E00003FA05001000E0C5
+:1036D00010B5302383F311880E4B5B6813F400633D
+:1036E00014D0F1EE103AEFF30984683C4FF0807388
+:1036F000E361094BDB6B236684F30988FEF730FB3B
+:1037000010B1064BA36110BD054BFBE783F3118895
+:10371000F9E700BF00ED00E000EF00E02F03000834
+:10372000320300080E4B1A6C42F008021A641A6E3B
+:1037300042F008021A660B4A1B6E936843F00803B6
+:103740009360094B53229A624FF0FF32DA620022F3
+:103750009A615A63DA605A6001225A611A607047AE
+:1037600000380240002004E0000C0040094A08B57F
+:103770001169D3680B40D9B2C9439B07116107D5C2
+:10378000302383F31188FEF72DFB002383F3118888
+:1037900008BD00BF000C00401F4B1A696FEAC252FF
+:1037A0006FEAD2521A611A69C2F308021A614FF025
+:1037B000FF301A695A69586100215A6959615A697A
+:1037C0001A6A62F080521A621A6A02F080521A6211
+:1037D0001A6A5A6A58625A6A59625A6A1A6C42F0EC
+:1037E00080521A641A6E42F080521A661A6E0B4AA0
+:1037F000106840F480701060186F00F44070B0F5ED
+:10380000007F1EBF4FF4803018671967536823F498
+:103810000073536000F060B900380240007000404F
+:10382000344B4FF080521A64334A4FF440411160D8
+:103830001A6842F001021A601A689107FCD59A686A
+:1038400022F003029A602B4B9A6812F00C02FBD113
+:10385000196801F0F90119609A601A6842F480321F
+:103860001A601A689203FCD55A6F42F001025A6737
+:10387000204B5A6F9007FCD5204A5A601A6842F0D4
+:1038800080721A601C4A53685904FCD5194B1A6897
+:103890009201FCD51A4A9A600322C3F88C20194B76
+:1038A0001A68194B9A42194B21D1194A1168194AC1
+:1038B00091421CD140F205121A60144A136803F0B9
+:1038C0000F03052BFAD10B4B9A6842F002029A6063
+:1038D0009A6802F00C02082AFAD15A6C42F480422B
+:1038E0005A645A6E42F480425A665B6E704740F2E8
+:1038F0000572E1E7003802400070004008544007BC
+:1039000000948838002004E011640020003C02404C
+:1039100000ED00E041C20F41074A08B5536903F0CA
+:103920000103536123B1054A13680BB150689847EE
+:10393000BDE80840FFF7CCBE003C0140A0300020AD
+:10394000074A08B5536903F00203536123B1054ADE
+:1039500093680BB1D0689847BDE80840FFF7B8BE40
+:10396000003C0140A0300020074A08B5536903F02D
+:103970000403536123B1054A13690BB15069984799
+:10398000BDE80840FFF7A4BE003C0140A030002085
+:10399000074A08B5536903F00803536123B1054A88
+:1039A00093690BB1D0699847BDE80840FFF790BE16
+:1039B000003C0140A0300020074A08B5536903F0DD
+:1039C0001003536123B1054A136A0BB1506A98473B
+:1039D000BDE80840FFF77CBE003C0140A03000205D
+:1039E000164B10B55C6904F478725A61A30604D5CD
+:1039F000134A936A0BB1D06A9847600604D5104AFF
+:103A0000136B0BB1506B9847210604D50C4A936B8E
+:103A10000BB1D06B9847E20504D5094A136C0BB182
+:103A2000506C9847A30504D5054A936C0BB1D06C34
+:103A30009847BDE81040FFF74BBE00BF003C014077
+:103A4000A0300020194B10B55C6904F47C425A6127
+:103A5000620504D5164A136D0BB1506D98472305C6
+:103A600004D5134A936D0BB1D06D9847E00404D58B
+:103A70000F4A136E0BB1506E9847A10404D50C4A3F
+:103A8000936E0BB1D06E9847620404D5084A136F49
+:103A90000BB1506F9847230404D5054A936F0BB1BF
+:103AA000D06F9847BDE81040FFF712BE003C0140C0
+:103AB000A030002008B50348FDF760FABDE80840D3
+:103AC000FFF706BEBC23002008B5FFF74FFEBDE898
+:103AD0000840FFF7FDBD0000062108B50846FFF7C6
+:103AE00009FB06210720FFF705FB06210820FFF749
+:103AF00001FB06210920FFF7FDFA06210A20FFF746
+:103B0000F9FA06211720FFF7F5FA06212820FFF71A
+:103B1000F1FA07213220FFF7EDFABDE808400C2149
+:103B20003520FFF7E7BA000008B5FFF735FE00F0D3
+:103B30000DF8FDF737FCFDF71DFEFDF7F5FCFFF76F
+:103B400091FDBDE80840FFF7B5BC00000023054A21
+:103B500019460133102BC2E9001102F10802F8D115
+:103B6000704700BFA0300020034611F8012B03F876
+:103B7000012B002AF9D1704753544D3332463F3F51
+:103B80003F0053544D3332463430780053544D3354
+:103B900032463432780053544D333246343436583A
+:103BA00058000000012033000010410001105A00AD
+:103BB000031059000710310000000000783B000896
+:103BC00013040000823B0008190400008C3B00082D
+:103BD00021040000963B0008009600000000000051
+:103BE00000000000000000000000000000000000D5
+:103BF00065130008511300088D130008791300089D
+:103C000085130008711300085D13000849130008AC
+:103C10009913000800000000A51400089114000882
+:103C2000CD140008B9140008C5140008B114000828
+:103C30009D14000889140008D91400080000000031
+:103C4000010000000000000063300000483C000854
+:103C500080260020902800204172647550696C6FA6
+:103C6000740025424F415244252D424C00255345B6
+:103C70005249414C250000000200000000000000F5
+:103C8000C11600082D17000840004000302D00200C
+:103C9000402D002002000000000000000300000092
+:103CA0000000000071170008000000001000000074
+:103CB000502D002000000000010000000000000066
+:103CC0002830002001010200712200088121000833
+:103CD0001D2200080122000843000000E03C00080B
+:103CE00009024300020100C032090400000102027F
+:103CF0000100052400100105240100010424020232
+:103D00000524060001070582030800FF09040100DD
+:103D1000020A0000000705010240000007058102B9
+:103D200040000000120000002C3D000812011001AC
+:103D30000200004009124157000201020301000085
+:103D40000403090425424F4152442500466C796919
+:103D50006E674D6F6F6E4634323700303132333418
+:103D6000353637383941424344454600004000006B
+:103D70000040000000400000004000000000010082
+:103D8000000002000000020000000200000002002B
+:103D900000000200000002000000020000400000DD
+:103DA0000040000000400000004000000000010052
+:103DB00000000200000002000000020000000200FB
+:103DC00000000200000002000000020000000000ED
+:103DD000B51800086D1B0008191C000840004000C1
+:103DE000883000208830002001000000983000203A
+:103DF0008000000040010000030000006D61696E5A
+:103E00000069646C650000000001802A0000000069
+:103E1000AAAAAAAA00010024FFFF000000000000D7
+:103E200000A00A001500000100000000AAAAAAA82C
+:103E300015000001FFFF000000000000000000006E
+:103E40000000000200000000AAAAAAAA00000001C7
+:103E5000FFFF00000000000000000800200000003C
+:103E600000000000AAAAAAAA10000000FFFF00009C
+:103E7000000800000000000050001040000000009A
+:103E8000AAAAAAAA00001040FFFF0000000000003C
+:103E9000000000000000000000000000AAAAAAAA7A
+:103EA00000000000FFFF0000000000000000000014
+:103EB0000000000000000000AAAAAAAA000000005A
+:103EC000FFFF0000000000000000000000000000F4
+:103ED000000000000A0000000000000003000000D5
+:103EE00000000000000000000000000000000000D2
+:103EF00000000000000000000000000000000000C2
+:103F000000000000000000002C0400000000000081
+:103F100000C01F0000000000FF00000098280020E3
+:103F2000BC2300200096000000000800960000005E
+:103F30000008000004000000403D000800000000F0
+:103F40000000000000000000000000000000000071
+:043F5000000000006D
+:00000001FF
diff --git a/Tools/bootloaders/FlyingMoonH743_bl.bin b/Tools/bootloaders/FlyingMoonH743_bl.bin
new file mode 100755
index 00000000000000..164be17ef0a78c
Binary files /dev/null and b/Tools/bootloaders/FlyingMoonH743_bl.bin differ
diff --git a/Tools/bootloaders/FlyingMoonH743_bl.hex b/Tools/bootloaders/FlyingMoonH743_bl.hex
new file mode 100644
index 00000000000000..e7d480ecfd9558
--- /dev/null
+++ b/Tools/bootloaders/FlyingMoonH743_bl.hex
@@ -0,0 +1,1113 @@
+:020000040800F2
+:1000000000060020E1020008E3020008E302000805
+:10001000E3020008E3020008E3020008E30200082C
+:10002000E3020008E3020008E3020008353B000891
+:10003000E3020008E3020008E3020008E30200080C
+:10004000E3020008E3020008E3020008E3020008FC
+:10005000E3020008E3020008193F0008453F0008DA
+:10006000713F00089D3F0008C93F0008E3020008F7
+:10007000E3020008E3020008E3020008E3020008CC
+:10008000E3020008E3020008E3020008E3020008BC
+:10009000E3020008E3020008E3020008F53F00085D
+:1000A000E3020008E3020008E3020008E30200089C
+:1000B000E1400008E3020008E3020008E302000850
+:1000C000E3020008E3020008E3020008E30200087C
+:1000D000E3020008E3020008E3020008E30200086C
+:1000E00059400008E3020008E3020008E3020008A8
+:1000F000E3020008E3020008E3020008E30200084C
+:10010000E3020008E3020008E3020008E30200083B
+:10011000E3020008CD400008E3020008E302000803
+:10012000E3020008E3020008E3020008E30200081B
+:10013000E3020008E3020008E3020008E30200080B
+:10014000E3020008E3020008E3020008E3020008FB
+:10015000E3020008E3020008E3020008E3020008EB
+:10016000E3020008E3020008E3020008E3020008DB
+:10017000E3020008C1340008E3020008E3020008BB
+:10018000E3020008E3020008E3020008E3020008BB
+:10019000E3020008E3020008E3020008E3020008AB
+:1001A000E3020008E3020008E3020008E30200089B
+:1001B000E3020008E3020008E3020008E30200088B
+:1001C000E3020008E3020008E3020008E30200087B
+:1001D000E3020008AD340008E3020008E30200086F
+:1001E000E3020008E3020008E3020008E30200085B
+:1001F000E3020008E3020008E3020008E30200084B
+:10020000E3020008E3020008E3020008E30200083A
+:10021000E3020008E3020008E3020008E30200082A
+:10022000E3020008E3020008E3020008E30200081A
+:10023000E3020008E3020008E3020008E30200080A
+:10024000E3020008E3020008E3020008E3020008FA
+:10025000E3020008E3020008E3020008E3020008EA
+:10026000E3020008E3020008E3020008E3020008DA
+:10027000E3020008E3020008E3020008E3020008CA
+:10028000E3020008E3020008E3020008E3020008BA
+:10029000E3020008E3020008E3020008E3020008AA
+:1002A000E3020008E3020008E3020008E30200089A
+:1002B000E3020008E3020008E3020008E30200088A
+:1002C000E3020008E3020008E3020008E30200087A
+:1002D000E3020008E3020008E3020008E30200086A
+:1002E00002E000F000F8FEE772B6374880F30888B5
+:1002F000364880F3098836483649086040F20000E5
+:10030000CCF200004EF63471CEF200010860BFF36B
+:100310004F8FBFF36F8F40F20000C0F2F0004EF637
+:100320008851CEF200010860BFF34F8FBFF36F8F8B
+:100330004FF00000E1EE100A4EF63C71CEF20001E3
+:100340000860062080F31488BFF36F8F02F024FB4F
+:1003500003F042FB4FF055301F491B4A91423CBF0E
+:1003600041F8040BFAE71D49184A91423CBF41F895
+:10037000040BFAE71A491B4A1B4B9A423EBF51F83D
+:10038000040B42F8040BF8E700201849184A914280
+:100390003CBF41F8040BFAE702F03CFB03F0A0FB82
+:1003A000144C154DAC4203DA54F8041B8847F9E7A6
+:1003B00000F042F8114C124DAC4203DA54F8041B21
+:1003C0008847F9E702F024BB000600200022002045
+:1003D0000000000808ED00E00000002000060020FA
+:1003E0000845000800220020642200206822002026
+:1003F000C4470020E0020008E0020008E002000814
+:10040000E00200082DE9F04F2DED108AC1F80CD064
+:10041000D0F80CD0BDEC108ABDE8F08F002383F338
+:1004200011882846A047002001F02CFEFEE701F0CD
+:1004300095FD00DFFEE7000038B502F06DFA0546D5
+:1004400002F0A0FA0446D0B90F4B9D4219D00133F7
+:100450009D4241F2883512BF044600250124002048
+:1004600002F064FA0CB100F077F800F071FD00F0D2
+:100470001BFC284600F010F900F06EF8F9E70025A3
+:10048000EDE70546EBE700BF010007B008B500F057
+:10049000D7FBA0F120035842584108BD07B541F2EF
+:1004A0001203022101A8ADF8043000F0E7FB03B00D
+:1004B0005DF804FB38B5302383F3118817480368CF
+:1004C0000BB101F0ABFE0023154A4FF47A711348CB
+:1004D00001F09AFE002383F31188124C236813B1B4
+:1004E0002368013B2360636813B16368013B636069
+:1004F0000D4D2B7833B963687BB9022000F09AFC6C
+:10050000322363602B78032B07D163682BB9022059
+:1005100000F090FC4FF47A73636038BD68220020CD
+:10052000B50400088823002080220020084B1870A2
+:1005300003280CD8DFE800F008050208022000F0CC
+:1005400069BC022000F058BC024B00225A60704780
+:100550008022002088230020F8B5494B494A1C46D8
+:100560001968013100F08A8004339342F8D162683F
+:10057000454B9A4240F28280444B9B6803F10063F2
+:1005800003F500339A4279D2002000F0A7FB022045
+:10059000FFF7CCFF3E4B0021D3F8E820C3F8E8106A
+:1005A000D3F81021C3F81011D3F81021D3F8EC20A0
+:1005B000C3F8EC10D3F81421C3F81411D3F81421A4
+:1005C000D3F8F020C3F8F010D3F81821C3F81811AD
+:1005D000D3F81821D3F8802042F00072C3F88020AD
+:1005E000D3F8802022F00072C3F88020D3F8803046
+:1005F00072B64FF0E023C3F8084DD4E90004BFF30E
+:100600004F8FBFF36F8F234AC2F88410BFF34F8F11
+:10061000536923F480335361BFF34F8FD2F8803096
+:1006200043F6E076C3F3C905C3F34E335B0103EA37
+:10063000060C29464CEA81770139C2F87472F9D266
+:10064000203B13F1200FF2D1BFF34F8FBFF36F8F19
+:10065000BFF34F8FBFF36F8F536923F400335361A0
+:100660000023C2F85032BFF34F8FBFF36F8F302398
+:1006700083F31188854680F308882047F8BD00BFC2
+:100680000000020820000208FFFF010800220020ED
+:100690000044025800ED00E02DE9F04F93B0B44B58
+:1006A0002022FF2100900AA89D6800F0FBFBB14AC0
+:1006B0001378A3B90121B04811700360302383F38C
+:1006C000118803680BB101F0A9FD0023AB4A4FF478
+:1006D0007A71A94801F098FD002383F31188009BEB
+:1006E00013B1A74B009A1A60A64A1378032B03D0C4
+:1006F00000231370A24A53604FF0000A009CD346B7
+:100700005646D146012000F085FB24B19C4B1B6866
+:10071000002B00F02682002000F092FA0390039B49
+:10072000002BF2DB012000F067FB039B213B1F2B1A
+:10073000E8D801A252F823F0B9070008E107000841
+:1007400075080008050700080507000805070008E8
+:1007500007090008D70A0008F1090008530A000831
+:100760007B0A0008A10A000805070008B30A000870
+:1007700005070008250B00085908000805070008B0
+:10078000690B0008C507000859080008050700089C
+:10079000530A0008050700080507000805070008B8
+:1007A00005070008050700080507000805070008F9
+:1007B00005070008750800080220FFF767FE0028FB
+:1007C00040F0F981009B022105A8BAF1000F08BF93
+:1007D0001C4641F21233ADF8143000F04FFA91E7A5
+:1007E0004FF47A7000F02CFA071EEBDB0220FFF7C3
+:1007F0004DFE0028E6D0013F052F00F2DE81DFE844
+:1008000007F0030A0D1013360523042105A80593EC
+:1008100000F034FA17E004215548F9E704215A485A
+:10082000F6E704215948F3E74FF01C08404608F169
+:10083000040800F055FA0421059005A800F01EFAFE
+:10084000B8F12C0FF2D101204FF0000900FA07F7A0
+:1008500047EA0B0B5FFA8BFB00F070FB26B10BF045
+:100860000B030B2B08BF0024FFF718FE4AE70421F7
+:100870004748CDE7002EA5D00BF00B030B2BA1D1E1
+:100880000220FFF703FE074600289BD00120002628
+:1008900000F024FA0220FFF749FE5FFA86F840468E
+:1008A00000F02CFA0446B0B1039940460136A1F19C
+:1008B00040025142514100F031FA0028EDD1BA46D0
+:1008C000044641F21213022105A83E46ADF8143049
+:1008D00000F0D4F916E725460120FFF727FE244B48
+:1008E0009B68AB4207D9284600F0FAF9013040F086
+:1008F00067810435F3E70025224BBA463E461D705A
+:100900001F4B5D60A8E7002E3FF45CAF0BF00B03BC
+:100910000B2B7FF457AF0220FFF708FE322000F0C8
+:100920008FF9B0F10008FFF64DAF18F003077FF420
+:1009300049AF0F4A08EB0503926893423FF642AF76
+:10094000B8F5807F3FF73EAF124BB845019323DDEA
+:100950004FF47A7000F074F90390039A002AFFF6BE
+:1009600031AF039A0137019B03F8012BEDE700BF7C
+:10097000002200208423002068220020B504000803
+:10098000882300208022002004220020082200204A
+:100990000C22002084220020C820FFF777FD0746A4
+:1009A00000283FF40FAF1F2D11D8C5F120020AAB6C
+:1009B00025F0030084494245184428BF424601926D
+:1009C00000F04AFA019AFF217F4800F06BFA4FEAE3
+:1009D000A803C8F387027C492846019300F06AFA0D
+:1009E000064600283FF46DAF019B05EB830533E716
+:1009F0000220FFF74BFD00283FF4E4AE00F0ACF915
+:100A000000283FF4DFAE0027B846704B9B68BB421E
+:100A100018D91F2F11D80A9B01330ED027F00303DA
+:100A200012AA134453F8203C05934046042205A91A
+:100A3000043700F0F1FA8046E7E7384600F050F955
+:100A40000590F2E7CDF81480042105A800F016F90E
+:100A500002E70023642104A8049300F005F90028AC
+:100A60007FF4B0AE0220FFF711FD00283FF4AAAEDC
+:100A7000049800F067F90590E6E70023642104A8D4
+:100A8000049300F0F1F800287FF49CAE0220FFF7F9
+:100A9000FDFC00283FF496AE049800F055F9EAE713
+:100AA0000220FFF7F3FC00283FF48CAE00F064F95D
+:100AB000E1E70220FFF7EAFC00283FF483AE05A936
+:100AC000142000F05FF907460421049004A800F008
+:100AD000D5F83946B9E7322000F0B2F8071EFFF624
+:100AE00071AEBB077FF46EAE384A07EB090392681C
+:100AF00093423FF667AE0220FFF7C8FC00283FF4A0
+:100B000061AE27F003074F44B9453FF4A5AE484610
+:100B100009F1040900F0E4F80421059005A800F0AB
+:100B2000ADF8F1E74FF47A70FFF7B0FC00283FF41E
+:100B300049AE00F011F9002844D00A9B01330BD0D4
+:100B400008220AA9002000F0B5F900283AD0202296
+:100B5000FF210AA800F0A6F9FFF7A0FC1C4801F04D
+:100B600097FA13B0BDE8F08F002E3FF42BAE0BF0D8
+:100B70000B030B2B7FF426AE0023642105A80593FD
+:100B800000F072F8074600287FF41CAE0220FFF741
+:100B90007DFC804600283FF415AEFFF77FFC41F254
+:100BA000883001F075FA059800F014FA46463C4684
+:100BB00000F0C4F9A6E506464EE64FF0000901E64E
+:100BC000BA467EE637467CE68422002000220020DA
+:100BD000A08601002DE9F84F4FF47A7306460D46C2
+:100BE000002402FB03F7DFF85080DFF8509098F9FB
+:100BF00000305FFA84FA5A1C01D0A34212D159F88E
+:100C000024002A4631460368D3F820B03B46D84733
+:100C1000854207D1074B012083F800A0BDE8F88F7B
+:100C20000124E4E7002CFBD04FF4FA7001F030FA15
+:100C30000020F3E7D42300201022002014220020FB
+:100C4000002307B5024601210DF107008DF807309A
+:100C5000FFF7C0FF20B19DF8070003B05DF804FB6B
+:100C60004FF0FF30F9E700000A46042108B5FFF70E
+:100C7000B1FF80F00100C0B2404208BD074B0A46F8
+:100C800030B41978064B53F82140014623682046BA
+:100C9000DD69044BAC4630BC604700BFD423002064
+:100CA00014220020A086010070B50A4E00240A4DCF
+:100CB00001F00AFD308028683388834208D901F0AA
+:100CC000FFFC2B6804440133B4F5003F2B60F2D3E2
+:100CD00070BD00BFD62300209023002001F0D2BDBC
+:100CE00000F1006000F500300068704700F100601E
+:100CF000920000F5003001F049BD0000054B1A6874
+:100D0000054B1B889B1A834202D9104401F0D8BCC2
+:100D10000020704790230020D623002038B50446D9
+:100D2000074D29B128682044BDE8384001F0E0BCF7
+:100D30002868204401F0CAFC0028F3D038BD00BF69
+:100D4000902300200020704700F1FF5000F58F1025
+:100D5000D0F8000870470000064991F8243033B1FC
+:100D600000230822086A81F82430FFF7BFBF012062
+:100D7000704700BF94230020014B1868704700BFE4
+:100D80000010005C194B01380322084470B51D683F
+:100D9000174BC5F30B042D0C1E88A6420BD15C68C3
+:100DA0000A46013C824213460FD214F9016F4EB13C
+:100DB00002F8016BF6E7013A03F10803ECD1814236
+:100DC0000B4602D22C2203F8012B0424094A168870
+:100DD000AE4204D1984284BF967803F8016B013C7F
+:100DE00002F10402F3D1581A70BD00BF0010005C7C
+:100DF0001C220020E4410008022803D1044B0822F1
+:100E00009A6170470128FCD1014B0422F8E700BF2A
+:100E100000100258022804D1054B4FF400229A61B9
+:100E200070470128FCD1024B4FF48022F7E700BF46
+:100E300000100258022805D1064A536983F00803BE
+:100E4000536170470128FCD1024A536983F00403BF
+:100E5000F6E700BF00100258002310B5934203D0FC
+:100E6000CC5CC4540133F9E710BD0000013810B563
+:100E700010F9013F3BB191F900409C4203D11AB1F6
+:100E80000131013AF4E71AB191F90020981A10BD26
+:100E90001046FCE703460246D01A12F9011B00294E
+:100EA000FAD1704702440346934202D003F8011B73
+:100EB000FAE770472DE9F8431F4D14460746884668
+:100EC00095F8242052BBDFF870909CB395F824303D
+:100ED0002BB92022FF2148462F62FFF7E3FF95F848
+:100EE00024004146C0F1080205EB8000A24228BF61
+:100EF0002246D6B29200FFF7AFFF95F82430A41B2C
+:100F000017441E449044E4B2F6B2082E85F82460DB
+:100F1000DBD1FFF721FF0028D7D108E02B6A03EBD4
+:100F200082038342CFD0FFF717FF0028CBD10020E8
+:100F3000BDE8F8830120FBE794230020024B1A78D8
+:100F4000024B1A70704700BFD423002010220020EB
+:100F500038B51A4C1A4D204600F0C8FB29462046E9
+:100F600000F0F0FB2D681748D5F89020D2F804382F
+:100F700043F00203C2F8043801F08AF81249284607
+:100F800000F0EEFCD5F89020104DD2F80438286817
+:100F900023F002030E49A042C2F804384FF4E133B3
+:100FA0000B6001D000F000FB6868A04204D0084943
+:100FB000BDE8384000F0F8BA38BD00BFB82A0020BC
+:100FC000E042000840420F00E842000814220020DE
+:100FD000BC2300200C4B70B50C4D04461E780C4B06
+:100FE00055F826209A420DD00A4B002118221846A7
+:100FF000FFF758FF0460014655F82600BDE8704031
+:1010000000F0D2BA70BD00BFD4230020142200200B
+:10101000B82A0020BC23002030B50A44084D914274
+:101020000DD011F8013B5840082340F30004013B68
+:101030002C4013F0FF0384EA5000F6D1EFE730BDF7
+:101040002083B8ED026843681143016003B118477B
+:1010500070470000024A136843F0C00313607047F2
+:101060000050004013B50E4C204600F091FA04F1F8
+:10107000140000234FF400720A49009400F04EF966
+:10108000094B4FF40072094904F13800009400F054
+:10109000C7F9074A074BC4E9172302B010BD00BFC8
+:1010A000D8230020442400205510000844260020A6
+:1010B0000050004000E1F505037C30B5244C0029C8
+:1010C00018BF0C46012B11D1224B98420ED1224B56
+:1010D000D3F8E82042F48012C3F8E820D3F81021B6
+:1010E00042F48012C3F81021D3F810312268036E45
+:1010F000C16D03EB52038466B3FBF2F3626815041F
+:1011000042BF23F0070503F0070343EA4503CB6022
+:10111000A36843F040034B60E36843F001038B6036
+:1011200042F4967343F001030B604FF0FF330B6200
+:10113000510505D512F0102205D0B2F1805F04D020
+:1011400080F8643030BD7F23FAE73F23F8E700BF23
+:10115000F4410008D8230020004402582DE9F0474C
+:10116000C66D05463768F469210734621AD014F059
+:10117000080118BF4FF48071E20748BF41F0200119
+:10118000A3074FF0300348BF41F04001600748BF5C
+:1011900041F0800183F31188281DFFF753FF0023DE
+:1011A00083F31188E2050AD5302383F311884FF4C5
+:1011B0008061281DFFF746FF002383F311884FF05D
+:1011C00030094FF0000A14F0200838D13B0616D53C
+:1011D0004FF0300905F1380A200610D589F311883F
+:1011E000504600F051F9002836DA0821281DFFF793
+:1011F00029FF27F080033360002383F311887906E9
+:1012000014D5620612D5302383F31188D5E9132350
+:101210009A4208D12B6C33B127F040071021281DCA
+:10122000FFF710FF3760002383F31188E30618D51A
+:10123000AA6E1369ABB15069BDE8F047184789F34E
+:101240001188736A284695F86410194000F0BAF9BD
+:101250008AF31188F469B6E7B06288F31188F469FB
+:10126000BAE7BDE8F0870000F8B515468268044685
+:101270000B46AA4200D28568A1692669761AB54252
+:101280000BD218462A46FFF7E7FDA3692B44A3615A
+:101290002846A3685B1BA360F8BD0CD9AF1B18469A
+:1012A0003246FFF7D9FD3A46E1683044FFF7D4FDF6
+:1012B000E3683B44EBE718462A46FFF7CDFDE368B9
+:1012C000E5E7000083689342F7B50446154600D26F
+:1012D0008568D4E90460361AB5420BD22A46FFF776
+:1012E000BBFD63692B4463612846A3685B1BA36055
+:1012F00003B0F0BD0DD93246AF1B0191FFF7ACFD35
+:1013000001993A46E0683144FFF7A6FDE3683B44A3
+:10131000E9E72A46FFF7A0FDE368E4E710B50A44D1
+:101320000024C361029B8460C16002610362C0E962
+:101330000000C0E9051110BD08B5D0E9053293429F
+:1013400001D1826882B98268013282605A1C42618E
+:1013500019700021D0E904329A4224BFC368436166
+:1013600000F0B2FE002008BD4FF0FF30FBE70000A8
+:1013700070B5302304460E4683F31188A568A5B1E5
+:10138000A368A269013BA360531CA361157822697D
+:10139000934224BFE368A361E3690BB120469847F9
+:1013A000002383F31188284607E03146204600F0E9
+:1013B0007BFE0028E2DA85F3118870BD2DE9F74F36
+:1013C00004460E4617469846D0F81C904FF0300A57
+:1013D0008AF311884FF0000B154665B12A46314655
+:1013E0002046FFF741FF034660B94146204600F022
+:1013F0005BFE0028F1D0002383F31188781B03B033
+:10140000BDE8F08FB9F1000F03D001902046C84726
+:10141000019B8BF31188ED1A1E448AF31188DCE7D7
+:10142000C160C361009B82600362C0E90511114481
+:10143000C0E9000001617047F8B504460D46164644
+:10144000302383F31188A768A7B1A368013BA36089
+:1014500063695A1C62611D70D4E904329A4224BF48
+:10146000E3686361E3690BB120469847002080F38D
+:10147000118807E03146204600F016FE0028E2DA27
+:1014800087F31188F8BD0000D0E9052310B59A4212
+:1014900001D182687AB982680021013282605A1CC7
+:1014A00082611C7803699A4224BFC368836100F09B
+:1014B0000BFE204610BD4FF0FF30FBE72DE9F74F44
+:1014C00004460E4617469846D0F81C904FF0300A56
+:1014D0008AF311884FF0000B154665B12A46314654
+:1014E0002046FFF7EFFE034660B94146204600F074
+:1014F000DBFD0028F1D0002383F31188781B03B0B3
+:10150000BDE8F08FB9F1000F03D001902046C84725
+:10151000019B8BF31188ED1A1E448AF31188DCE7D6
+:10152000026843681143016003B118477047000027
+:101530001430FFF743BF00004FF0FF331430FFF7C4
+:101540003DBF00003830FFF7B9BF00004FF0FF3358
+:101550003830FFF7B3BF00001430FFF709BF0000B9
+:101560004FF0FF311430FFF703BF00003830FFF7B2
+:1015700063BF00004FF0FF323830FFF75DBF00005F
+:10158000012914BF6FF0130000207047FFF76ABDF8
+:10159000044B036000234360C0E90233012303745A
+:1015A000704700BF0C42000810B53023044683F397
+:1015B0001188FFF781FD02230020237480F3118836
+:1015C00010BD000038B5C36904460D461BB904219F
+:1015D0000844FFF7A5FF294604F11400FFF7ACFE0D
+:1015E000002806DA201D4FF40061BDE83840FFF7FF
+:1015F00097BF38BD026843681143016003B11847C3
+:101600007047000013B5406B00F58054D4F8A4383F
+:101610001A681178042914D1017C022911D1197991
+:10162000012312898B4013420BD101A94C3002F0E7
+:101630008FF8D4F8A4480246019B2179206800F075
+:10164000DFF902B010BD0000143002F011B8000044
+:101650004FF0FF33143002F00BB800004C3002F0B2
+:10166000E3B800004FF0FF334C3002F0DDB800006B
+:10167000143001F0DFBF00004FF0FF31143001F0F3
+:10168000D9BF00004C3002F0AFB800004FF0FF327D
+:101690004C3002F0A9B800000020704710B500F5EA
+:1016A0008054D4F8A4381A681178042917D1017C21
+:1016B000022914D15979012352898B4013420ED14A
+:1016C000143001F071FF024648B1D4F8A4484FF439
+:1016D000407361792068BDE8104000F07FB910BD0B
+:1016E000406BFFF7DBBF0000704700007FB5124B77
+:1016F00001250426044603600023057400F18402DA
+:1017000043602946C0E902330C4B02901430019328
+:101710004FF44073009601F023FF094B04F6944206
+:10172000294604F14C000294CDE900634FF4407364
+:1017300001F0EAFF04B070BD34420008E116000871
+:10174000051600080A68302383F311880B790B33E0
+:1017500042F823004B79133342F823008B7913B1FD
+:101760000B3342F8230000F58053C3F8A41802237A
+:101770000374002080F311887047000038B5037FA0
+:10178000044613B190F85430ABB90125201D022155
+:10179000FFF730FF04F114006FF00101257700F02E
+:1017A0009FFC04F14C0084F854506FF00101BDE837
+:1017B000384000F095BC38BD10B501210446043016
+:1017C000FFF718FF0023237784F8543010BD000082
+:1017D00038B504460025143001F0DAFE04F14C005F
+:1017E000257701F0A9FF201D84F854500121FFF74F
+:1017F00001FF2046BDE83840FFF750BF90F8803029
+:1018000003F06003202B06D190F881200023212AC9
+:1018100003D81F2A06D800207047222AFBD1C0E92E
+:101820001D3303E0034A426707228267C367012032
+:10183000704700BF3422002037B500F58055D5F839
+:10184000A4381A68117804291AD1017C022917D109
+:101850001979012312898B40134211D100F14C04F4
+:10186000204602F029F858B101A9204601F070FF86
+:10187000D5F8A4480246019B2179206800F0C0F801
+:1018800003B030BD01F10B03F0B550F8236085B013
+:1018900004460D46FEB1302383F3118804EB85071F
+:1018A000301D0821FFF7A6FEFB6806F14C005B69BE
+:1018B0001B681BB1019001F059FF019803A901F0C9
+:1018C00047FF024648B1039B2946204600F098F89E
+:1018D000002383F3118805B0F0BDFB685A691268D4
+:1018E000002AF5D01B8A013B1340F1D104F180029C
+:1018F000EAE70000133138B550F82140ECB130234D
+:1019000083F3118804F58053D3F8A428136852791F
+:1019100003EB8203DB689B695D6845B104216018B5
+:10192000FFF768FE294604F1140001F047FE204647
+:10193000FFF7B4FE002383F3118838BD7047000021
+:1019400001F0FEB801234022002110B5044600F842
+:10195000303BFFF7A7FA0023C4E9013310BD0000B4
+:1019600010B53023044683F31188242241600021FE
+:101970000C30FFF797FA204601F004F9022300200B
+:10198000237080F3118810BD70B500EB810305460C
+:1019900050690E461446DA6018B110220021FFF794
+:1019A00081FAA06918B110220021FFF77BFA3146B5
+:1019B0002846BDE8704001F0EBB9000083682022A2
+:1019C000002103F0011310B5044683601030FFF7C7
+:1019D00069FA2046BDE8104001F066BAF0B401256E
+:1019E00000EB810447898D40E4683D43A46945814B
+:1019F00023600023A2606360F0BC01F083BA0000A2
+:101A0000F0B4012500EB810407898D40E4683D4373
+:101A10006469058123600023A2606360F0BC01F06B
+:101A2000F9BA000070B50223002504462422037091
+:101A30002946C0F888500C3040F8045CFFF732FAB1
+:101A4000204684F8705001F037F963681B6823B1B1
+:101A500029462046BDE87040184770BD0378052B25
+:101A600010B504460AD080F88C3005230370436813
+:101A70001B680BB1042198470023A36010BD000030
+:101A80000178052906D190F88C20436802701B6804
+:101A900003B118477047000070B590F870300446E5
+:101AA00013B1002380F8703004F18002204601F069
+:101AB0001FFA63689B68B3B994F8803013F060052F
+:101AC00035D00021204601F011FD0021204601F013
+:101AD00001FD63681B6813B1062120469847062361
+:101AE00084F8703070BD204698470028E4D0B4F8E0
+:101AF0008630A26F9A4288BFA36794F98030A56FA1
+:101B0000002B4FF0300380F20381002D00F0F280B3
+:101B1000092284F8702083F3118800212046D4E93B
+:101B20001D23FFF76DFF002383F31188DAE794F894
+:101B3000812003F07F0343EA022340F20232934202
+:101B400000F0C58021D8B3F5807F48D00DD8012B97
+:101B50003FD0022B00F09380002BB2D104F1880219
+:101B600062670222A267E367C1E7B3F5817F00F0F5
+:101B70009B80B3F5407FA4D194F88230012BA0D193
+:101B8000B4F8883043F0020332E0B3F5006F4DD073
+:101B900017D8B3F5A06F31D0A3F5C063012B90D84F
+:101BA0006368204694F882205E6894F88310B4F845
+:101BB0008430B047002884D0436863670368A36714
+:101BC0001AE0B3F5106F36D040F6024293427FF42C
+:101BD00078AF5C4B63670223A3670023C3E794F8E5
+:101BE0008230012B7FF46DAFB4F8883023F002030C
+:101BF000A4F88830C4E91D55E56778E7B4F880306B
+:101C0000B3F5A06F0ED194F88230204684F88A3064
+:101C100001F0B0F863681B6813B1012120469847B2
+:101C2000032323700023C4E91D339CE704F18B03D5
+:101C300063670123C3E72378042B10D1302383F398
+:101C400011882046FFF7BAFE85F3118803216368E7
+:101C500084F88B5021701B680BB12046984794F88C
+:101C60008230002BDED084F88B300423237063682D
+:101C70001B68002BD6D0022120469847D2E794F863
+:101C8000843020461D0603F00F010AD501F022F929
+:101C9000012804D002287FF414AF2B4B9AE72B4B7A
+:101CA00098E701F009F9F3E794F88230002B7FF40C
+:101CB00008AF94F8843013F00F01B3D01A06204611
+:101CC00002D501F02BFCADE701F01CFCAAE794F86B
+:101CD0008230002B7FF4F5AE94F8843013F00F01BE
+:101CE000A0D01B06204602D501F000FC9AE701F0C7
+:101CF000F1FB97E7142284F8702083F311882B46B8
+:101D00002A4629462046FFF769FE85F31188E9E651
+:101D10005DB1152284F8702083F3118800212046DC
+:101D2000D4E91D23FFF75AFEFDE60B2284F870204C
+:101D300083F311882B462A4629462046FFF760FE8A
+:101D4000E3E700BF644200085C420008604200080C
+:101D500038B590F870300446002B3ED0063BDAB21E
+:101D60000F2A34D80F2B32D8DFE803F0373131088F
+:101D7000223231313131313131313737856FB0F87D
+:101D800086309D4214D2C3681B8AB5FBF3F203FB75
+:101D900012556DB9302383F311882B462A46294604
+:101DA000FFF72EFE85F311880A2384F870300EE0C9
+:101DB000142384F87030302383F3118800232046E5
+:101DC0001A461946FFF70AFE002383F3118838BD2F
+:101DD000C36F03B198470023E7E70021204601F0D5
+:101DE00085FB0021204601F075FB63681B6813B179
+:101DF0000621204698470623D7E7000010B590F843
+:101E000070300446142B29D017D8062B05D001D8E2
+:101E10001BB110BD093B022BFBD80021204601F06D
+:101E200065FB0021204601F055FB63681B6813B178
+:101E3000062120469847062319E0152BE9D10B23EC
+:101E400080F87030302383F3118800231A46194636
+:101E5000FFF7D6FD002383F31188DAE7C3689B6997
+:101E60005B68002BD5D1C36F03B19847002384F87A
+:101E70007030CEE700238268037503691B68996898
+:101E80009142FBD25A68036042601060586070470C
+:101E900000238268037503691B6899689142FBD827
+:101EA0005A680360426010605860704708B5084681
+:101EB000302383F311880B7D032B05D0042B0DD029
+:101EC0002BB983F3118808BD8B6900221A604FF08B
+:101ED000FF338361FFF7CEFF0023F2E7D1E9003241
+:101EE00013605A60F3E70000FFF7C4BF054BD968E1
+:101EF00008751868026853601A600122D86002757C
+:101F0000FEF780BA482800200C4B30B5DD684B1C2A
+:101F100087B004460FD02B46094A684600F074F992
+:101F20002046FFF7E3FF009B13B1684600F076F907
+:101F3000A86907B030BDFFF7D9FFF9E748280020AE
+:101F4000AD1E0008044B1A68DB6890689B689842D5
+:101F500094BF00200120704748280020084B10B58E
+:101F60001C68D868226853601A600122DC60227500
+:101F7000FFF78EFF01462046BDE81040FEF742BA4B
+:101F800048280020044B1A68DB6892689B689A42D4
+:101F900001D9FFF7E3BF70474828002038B5074C48
+:101FA00001230025064907482370656001F0BCFC49
+:101FB0000223237085F3118838BD00BFB02A0020AA
+:101FC0006C4200084828002000F05EB9EFF3118051
+:101FD00020B9EFF30583302282F3118870470000A7
+:101FE00010B530B9EFF30584C4F3080414B180F3DD
+:101FF000118810BDFFF7C6FF84F31188F9E70000D0
+:10200000034A516853685B1A9842FBD8704700BF77
+:10201000001000E08B600223086108468B82704745
+:102020008368A3F1840243F8142C026943F8442C1A
+:10203000426943F8402C094A43F8242CC268A3F1B2
+:10204000200043F8182C022203F80C2C002203F87D
+:102050000B2C034A43F8102C704700BF1D040008E6
+:102060004828002008B5FFF7DBFFBDE80840FFF770
+:102070003BBF0000024BDB6898610F20FFF736BFC3
+:1020800048280020302383F31188FFF7F3BF0000B6
+:1020900008B50146302383F311880820FFF734FF89
+:1020A000002383F3118808BD064BDB6839B1426811
+:1020B00018605A60136043600420FFF725BF4FF09B
+:1020C000FF307047482800200368984206D01A68FD
+:1020D0000260506018469961FFF706BF7047000024
+:1020E00038B504460D462068844200D138BD0368E7
+:1020F00023605C608561FFF7F7FEF4E7036810B5C5
+:102100009C68A2420CD85C688A600B604C602160BD
+:10211000596099688A1A9A604FF0FF33836010BD46
+:10212000121B1B68ECE700000A2938BF0A2170B5B2
+:1021300004460D460A26601901F0F0FB01F0DCFBB5
+:10214000041BA54203D8751C04462E46F3E70A2E4D
+:1021500004D90120BDE8704001F026BC70BD00002C
+:10216000F8B5144B0D460A2A4FF00A07D96103F15E
+:102170001001826038BF0A2241601969144601606B
+:1021800048601861A81801F0BBFB01F0B5FB431BC8
+:102190000646A34206D37C1C28192746354601F083
+:1021A000BDFBF2E70A2F04D90120BDE8F84001F099
+:1021B000FBBBF8BD48280020F8B506460D4601F0E7
+:1021C0009BFB0F4A134653F8107F9F4206D12A46C5
+:1021D00001463046BDE8F840FFF7C2BFD169BB6891
+:1021E000441A2C1928BF2C46A34202D92946FFF7CE
+:1021F0009BFF224631460348BDE8F840FFF77EBF0B
+:102200004828002058280020C0E90323002310B4E8
+:102210005DF8044B4361FFF7CFBF000010B5194CC8
+:10222000236998420DD08168D0E9003213605A606A
+:102230009A680A449A60002303604FF0FF33A36159
+:1022400010BD0268234643F8102F5360002202603D
+:1022500022699A4203D1BDE8104001F059BB93684E
+:1022600081680B44936001F047FB2269E169926841
+:10227000441AA242E4D91144BDE81040091AFFF7FC
+:1022800053BF00BF482800202DE9F047DFF8BC808D
+:1022900008F110072C4ED8F8105001F02DFBD8F89B
+:1022A0001C40AA68031B9A423ED814444FF0000910
+:1022B000D5E90032C8F81C4013605A60C5F8009098
+:1022C000D8F81030B34201D101F022FB89F3118814
+:1022D000D5E9033128469847302383F311886B6989
+:1022E000002BD8D001F008FB6A69A0EB04098246F4
+:1022F0004A450DD2022001F057FB0022D8F81030D9
+:10230000B34208D151462846BDE8F047FFF728BF41
+:10231000121A2244F2E712EB09092946384638BF5F
+:102320004A46FFF7EBFEB5E7D8F81030B34208D0C5
+:102330001444C8F81C00211AA960BDE8F047FFF753
+:10234000F3BEBDE8F08700BF5828002048280020D1
+:1023500000207047FEE70000704700004FF0FF309C
+:102360007047000002290CD0032904D00129074836
+:1023700018BF00207047032A05D8054800EBC200AB
+:102380007047044870470020704700BF444300086E
+:1023900044220020F842000870B59AB0054608466D
+:1023A000144601A900F0C2F801A8FEF773FD431C12
+:1023B0000022C6B25B001046C5E900342370032337
+:1023C000023404F8013C01ABD1B202348E4201D890
+:1023D0001AB070BD13F8011B013204F8010C04F8A7
+:1023E000021CF1E708B5302383F311880348FFF797
+:1023F00023FA002383F3118808BD00BFB82A002008
+:1024000090F8803003F01F02012A07D190F8812054
+:102410000B2A03D10023C0E91D3315E003F060034C
+:10242000202B08D1B0F884302BB990F88120212AD4
+:1024300003D81F2A04D8FFF7E1B9222AEBD0FAE724
+:10244000034A426707228267C3670120704700BFC3
+:102450003B22002007B5052917D8DFE801F019163F
+:1024600003191920302383F31188104A01210190A8
+:10247000FFF78AFA019802210D4AFFF785FA0D4805
+:10248000FFF7A6F9002383F3118803B05DF804FB7E
+:10249000302383F311880748FFF770F9F2E7302300
+:1024A00083F311880348FFF787F9EBE798420008A8
+:1024B000BC420008B82A002038B50C4D0C4C2A4606
+:1024C0000C4904F10800FFF767FF05F1CA0204F1A7
+:1024D00010000949FFF760FF05F5CA7204F1180002
+:1024E0000649BDE83840FFF757BF00BF90430020C2
+:1024F0004422002078420008824200088D420008F1
+:1025000070B5044608460D46FEF7C4FCC6B2204628
+:10251000013403780BB9184670BD32462946FEF7E0
+:10252000A5FC0028F3D10120F6E700002DE9F047D3
+:1025300005460C46FEF7AEFC2B49C6B22846FFF70F
+:10254000DFFF08B10736F6B228492846FFF7D8FF63
+:1025500008B11036F6B2632E0BD8DFF88C80DFF8A6
+:102560008C90234FDFF894A02E7846B92670BDE8F2
+:10257000F08729462046BDE8F04701F015BE252E1C
+:102580002ED1072241462846FEF770FC70B9194B40
+:10259000224603F10C0153F8040B8B4242F8040B62
+:1025A000F9D11B8807350E341380DDE70822494630
+:1025B0002846FEF75BFC98B9A21C0F4B1978023233
+:1025C0000909C95D02F8041C13F8011B01F00F0191
+:1025D0005345C95D02F8031CF0D118340835C3E730
+:1025E000013504F8016BBFE7644300088D42000821
+:1025F0007B4300086C43000800E8F11F0CE8F11F62
+:10260000BFF34F8F044B1A695107FCD1D3F8102147
+:102610005207F8D1704700BF0020005208B50D4B9B
+:102620001B78ABB9FFF7ECFF0B4BDA68D10704D589
+:102630000A4A5A6002F188325A60D3F80C21D20754
+:1026400006D5064AC3F8042102F18832C3F80421F2
+:1026500008BD00BFEE450020002000522301674561
+:1026600008B5114B1B78F3B9104B1A69510703D504
+:10267000DA6842F04002DA60D3F81021520705D53B
+:10268000D3F80C2142F04002C3F80C21FFF7B8FF49
+:10269000064BDA6842F00102DA60D3F80C2142F00E
+:1026A0000102C3F80C2108BDEE45002000200052B5
+:1026B0000F289ABF00F5806040040020704700009A
+:1026C0004FF4003070470000102070470F2808B505
+:1026D0000BD8FFF7EDFF00F500330268013204D19B
+:1026E00004308342F9D1012008BD0020FCE700003E
+:1026F0000F2870B5054645D8FFF768FC224CFFF758
+:102700007FFF0646FFF78AFF4FF0FF33072D636117
+:10271000C4F8143120D82361FFF772FF2B0243F075
+:102720002403E360E36843F08003E36023695A070E
+:10273000FCD42846FFF764FF4FF40031FFF7B8FFE1
+:1027400000F002F93046FFF78BFFFFF749FC2846FF
+:10275000BDE87040FFF7BABFC4F81031FFF750FF73
+:10276000A5F108031B0243F02403C4F80C31D4F88C
+:102770000C3143F08003C4F80C31D4F810315B07FE
+:10278000FBD4D6E7002070BD002000522DE9F84FA1
+:1027900040EA020305460C461746D80602D0002040
+:1027A000BDE8F88F27F01F07DFF8D4B0FFF736FF3A
+:1027B0002744BC4203D10120FFF752FFF0E720225B
+:1027C0002946204601F0E0FC10B920352034F0E71E
+:1027D0002B4605F120021E68711CE0D104339A4299
+:1027E000F9D1FFF7F3FB05F17843234AB3F5801FD6
+:1027F000224B28BF9A4603F1040338BF9046A2F14A
+:10280000080228BF9846A3F108033ABF9146DA466A
+:102810009946FFF7F5FEC8F80060A5EB040CD9F85F
+:10282000002004F11C0142F00202C9F80020221F1E
+:10283000DAF8006016F00506FAD152F8043F8A4231
+:102840004CF80230F4D1BFF34F8FFFF7D9FE4FF0B1
+:10285000FF32C8F80020D9F8002022F00202C9F89F
+:102860000020FFF7BDFB20222146284601F08CFC0A
+:102870000028AAD030469FE71420005210210052B1
+:102880001020005210B5084C237828B11BB9FFF76F
+:10289000C5FE0123237010BD002BFCD02070BDE8C5
+:1028A0001040FFF7DDBE00BFEE4500200244074B9D
+:1028B000D2B210B5904200D110BD441C00B253F802
+:1028C000200041F8040BE0B2F4E700BF504000588C
+:1028D0000E4B30B51C6F240405D41C6F1C671C6F95
+:1028E00044F400441C670A4C02442368D2B243F407
+:1028F00080732360074B904200D130BD441C51F8D7
+:10290000045B00B243F82050E0B2F4E70044025800
+:10291000004802585040005807B5012201A9002084
+:10292000FFF7C4FF019803B05DF804FB13B504463C
+:10293000FFF7F2FFA04205D0012201A90020019477
+:10294000FFF7C6FF02B010BD0144BFF34F8F064B27
+:10295000884204D3BFF34F8FBFF36F8F7047C3F824
+:102960005C022030F4E700BF00ED00E0034B1A6882
+:102970001AB9034AD2F8D0241A607047F0450020F3
+:102980000040025808B5FFF7F1FF024B1868C0F38A
+:10299000806008BDF045002070B5BFF34F8FBFF3D6
+:1029A0006F8F1A4A0021C2F85012BFF34F8FBFF346
+:1029B0006F8F536943F400335361BFF34F8FBFF3FD
+:1029C0006F8FC2F88410BFF34F8FD2F8803043F678
+:1029D000E074C3F3C900C3F34E335B0103EA04069A
+:1029E000014646EA81750139C2F86052F9D2203BAE
+:1029F00013F1200FF2D1BFF34F8F536943F48033AB
+:102A00005361BFF34F8FBFF36F8F70BD00ED00E0D8
+:102A1000FEE70000214B2248224A70B5904237D38E
+:102A2000214BC11EDA1C121A22F003028B4238BF5E
+:102A300000220021FEF736FA1C4A0023C2F8843037
+:102A4000BFF34F8FD2F8803043F6E074C3F3C90070
+:102A5000C3F34E335B0103EA0406014646EA81757F
+:102A60000139C2F86C52F9D2203B13F1200FF2D198
+:102A7000BFF34F8FBFF36F8FBFF34F8FBFF36F8FD6
+:102A80000023C2F85032BFF34F8FBFF36F8F70BD7A
+:102A900053F8041B40F8041BC0E700BF6C45000856
+:102AA000C4470020C4470020C447002000ED00E0D8
+:102AB000074BD3F8D81021EA0001C3F8D810D3F897
+:102AC000002122EA0002C3F80021D3F80031704748
+:102AD0000044025870B5D0E9244300224FF0FF357E
+:102AE0009E6804EB42135101D3F80009002805DA6F
+:102AF000D3F8000940F08040C3F80009D3F8000B78
+:102B0000002805DAD3F8000B40F08040C3F8000B32
+:102B1000013263189642C3F80859C3F8085BE0D243
+:102B20004FF00113C4F81C3870BD0000890141F05A
+:102B30002001016103699B06FCD41220FFF760BAF3
+:102B400010B50A4C2046FEF7FDFE094BC4F8903044
+:102B5000084BC4F89430084C2046FEF7F3FE074BB0
+:102B6000C4F89030064BC4F8943010BDF4450020F2
+:102B700000000840B04300089046002000000440D8
+:102B8000BC43000870B503780546012B5CD1434B6C
+:102B9000D0F89040984258D1414B0E216520D3F88F
+:102BA000D82042F00062C3F8D820D3F8002142F0C8
+:102BB0000062C3F80021D3F80021D3F8802042F04E
+:102BC0000062C3F88020D3F8802022F00062C3F8AE
+:102BD0008020D3F8803000F0ADFC324BE360324B04
+:102BE000C4F800380023D5F89060C4F8003EC02334
+:102BF00023604FF40413A3633369002BFCDA012331
+:102C00000C203361FFF7FCF93369DB07FCD4122099
+:102C1000FFF7F6F93369002BFCDA00262846A66098
+:102C2000FFF758FF6B68C4F81068DB68C4F81468D5
+:102C3000C4F81C6883BB1D4BA3614FF0FF33636175
+:102C4000A36843F00103A36070BD194B9842C9D13A
+:102C5000134B4FF08060D3F8D82042F00072C3F8D5
+:102C6000D820D3F8002142F00072C3F80021D3F835
+:102C70000021D3F8802042F00072C3F88020D3F8FE
+:102C8000802022F00072C3F88020D3F88030FFF754
+:102C90000FFF0E214D209EE7064BCDE7F4450020A7
+:102CA000004402584014004003002002003C30C0A1
+:102CB00090460020083C30C0F8B5D0F8904005465A
+:102CC00000214FF000662046FFF730FFD5F8941042
+:102CD00000234FF001128F684FF0FF30C4F83438F2
+:102CE000C4F81C2804EB431201339F42C2F8006968
+:102CF000C2F8006BC2F80809C2F8080BF2D20B68E0
+:102D0000D5F89020C5F898306362102313611669D6
+:102D100016F01006FBD11220FFF772F9D4F8003834
+:102D200023F4FE63C4F80038A36943F4402343F05E
+:102D30001003A3610923C4F81038C4F814380B4BEE
+:102D4000EB604FF0C043C4F8103B094BC4F8003BA4
+:102D5000C4F81069C4F80039D5F8983003F11002AE
+:102D600043F48013C5F89820A362F8BD8C43000893
+:102D700040800010D0F8902090F88A10D2F80038E7
+:102D800023F4FE6343EA0113C2F8003870470000E1
+:102D90002DE9F84300EB8103D0F890500C468046B3
+:102DA000DA680FFA81F94801166806F00306731E07
+:102DB000022B05EB41134FF0000194BFB604384ECF
+:102DC000C3F8101B4FF0010104F1100398BF06F186
+:102DD000805601FA03F3916998BF06F50046002971
+:102DE0003AD0578A04F15801374349016F50D5F85A
+:102DF0001C180B430021C5F81C382B180127C3F8F9
+:102E00001019A7405369611E9BB3138A928B9B08CC
+:102E1000012A88BF5343D8F89820981842EA034300
+:102E200001F140022146C8F89800284605EB8202CD
+:102E30005360FFF77BFE08EB8900C3681B8A43EAF7
+:102E4000845348341E4364012E51D5F81C381F4367
+:102E5000C5F81C78BDE8F88305EB4917D7F8001BC7
+:102E600021F40041C7F8001BD5F81C1821EA030320
+:102E7000C0E704F13F030B4A2846214605EB8303D4
+:102E80005A60FFF753FE05EB4910D0F8003923F4E0
+:102E90000043C0F80039D5F81C3823EA0707D7E704
+:102EA0000080001000040002D0F894201268C0F8DE
+:102EB0009820FFF70FBE00005831D0F8903049013C
+:102EC0005B5813F4004004D013F4001F0CBF022021
+:102ED000012070474831D0F8903049015B5813F415
+:102EE000004004D013F4001F0CBF022001207047E3
+:102EF00000EB8101CB68196A0B6813604B68536063
+:102F00007047000000EB810330B5DD68AA691368E3
+:102F1000D36019B9402B84BF402313606B8A1468B7
+:102F2000D0F890201C4402EB4110013C09B2B4FBE4
+:102F3000F3F46343033323F0030343EAC44343F04E
+:102F4000C043C0F8103B2B6803F00303012B0ED1E4
+:102F5000D2F8083802EB411013F4807FD0F8003B20
+:102F600014BF43F0805343F00053C0F8003B02EB22
+:102F70004112D2F8003B43F00443C2F8003B30BD9D
+:102F80002DE9F041D0F8906005460C4606EB411360
+:102F9000D3F8087B3A07C3F8087B08D5D6F814386D
+:102FA0001B0704D500EB8103DB685B689847FA07D1
+:102FB0001FD5D6F81438DB071BD505EB8403D96879
+:102FC000CCB98B69488A5A68B2FBF0F600FB16222E
+:102FD0008AB91868DA6890420DD2121AC3E900243F
+:102FE000302383F3118821462846FFF78BFF84F3B3
+:102FF0001188BDE8F081012303FA04F26B8923EA0A
+:1030000002036B81CB68002BF3D021462846BDE834
+:10301000F041184700EB81034A0170B5DD68D0F834
+:1030200090306C692668E66056BB1A444FF4002065
+:10303000C2F810092A6802F00302012A0AB20ED16E
+:10304000D3F8080803EB421410F4807FD4F8000989
+:1030500014BF40F0805040F00050C4F8000903EB6A
+:103060004212D2F8000940F00440C2F800090122DF
+:10307000D3F8340802FA01F10143C3F8341870BDE3
+:1030800019B9402E84BF4020206020681A442E8A3F
+:103090008419013CB4FBF6F440EAC44040F000500F
+:1030A000C6E700002DE9F843D0F8906005460C46CD
+:1030B0004F0106EB4113D3F8088918F0010FC3F84C
+:1030C00008891CD0D6F81038DB0718D500EB81032F
+:1030D000D3F80CC0DCF81430D3F800E0DA68964579
+:1030E00030D2A2EB0E024FF000091A60C3F8049030
+:1030F000302383F31188FFF78DFF89F3118818F0CF
+:10310000800F1DD0D6F834380126A640334217D0A0
+:1031100005EB84030134D5F89050D3F80CC0E4B229
+:103120002F44DCF8142005EB0434D2F800E0516899
+:10313000714514D3D5F8343823EA0606C5F8346847
+:10314000BDE8F883012303FA01F2038923EA0203AD
+:103150000381DCF80830002BD1D09847CFE7AEEBE5
+:103160000103BCF81000834228BF0346D7F81809B2
+:1031700080B2B3EB800FE3D89068A0F1040959F84E
+:10318000048FC4F80080A0EB09089844B8F1040F3C
+:10319000F5D818440B4490605360C8E72DE9F84F08
+:1031A000D0F8905004466E69AB691E4016F4805802
+:1031B0006E6103D0BDE8F84FFEF734BC002E12DA82
+:1031C000D5F8003E9B0705D0D5F8003E23F0030359
+:1031D000C5F8003ED5F80438204623F00103C5F8B1
+:1031E0000438FEF74DFC370505D52046FFF772FC85
+:1031F0002046FEF733FCB0040CD5D5F8083813F0A0
+:10320000060FEB6823F470530CBF43F4105343F4E0
+:10321000A053EB6031071BD56368DB681BB9AB6952
+:1032200023F00803AB612378052B0CD1D5F8003EC1
+:103230009A0705D0D5F8003E23F00303C5F8003EF9
+:103240002046FEF71DFC6368DB680BB120469847FB
+:10325000F30200F1BA80B70226D5D4F89090002787
+:103260004FF0010A09EB4712D2F8003B03F4402368
+:10327000B3F5802F11D1D2F8003B002B0DDA628913
+:103280000AFA07F322EA0303638104EB8703DB688E
+:10329000DB6813B13946204698470137D4F894309B
+:1032A000FFB29B689F42DDD9F00619D5D4F8900093
+:1032B000026AC2F30A1702F00F0302F4F012B2F529
+:1032C000802F00F0CA80B2F5402F09D104EB8303B0
+:1032D000002200F58050DB681B6A974240F0B08006
+:1032E0003003D5F8185835D5E90303D50021204619
+:1032F000FFF746FEAA0303D501212046FFF740FE53
+:103300006B0303D502212046FFF73AFE2F0303D5B6
+:1033100003212046FFF734FEE80203D504212046AE
+:10332000FFF72EFEA90203D505212046FFF728FE50
+:103330006A0203D506212046FFF722FE2B0203D5A1
+:1033400007212046FFF71CFEEF0103D50821204688
+:10335000FFF716FE700340F1A780E90703D50021AF
+:103360002046FFF79FFEAA0703D501212046FFF75D
+:1033700099FE6B0703D502212046FFF793FE2F0726
+:1033800003D503212046FFF78DFEEE0603D5042169
+:103390002046FFF787FEA80603D505212046FFF744
+:1033A00081FE690603D506212046FFF77BFE2A062B
+:1033B00003D507212046FFF775FEEB0574D520469F
+:1033C0000821BDE8F84FFFF76DBED4F890904FF09C
+:1033D000000B4FF0010AD4F894305FFA8BF79B682A
+:1033E0009F423FF638AF09EB4713D3F8002902F4A8
+:1033F0004022B2F5802F20D1D3F80029002A1CDA10
+:10340000D3F8002942F09042C3F80029D3F80029EC
+:10341000002AFBDB3946D4F89000FFF787FB2289AE
+:103420000AFA07F322EA0303238104EB8703DB682C
+:103430009B6813B13946204698470BF1010BCAE748
+:10344000910701D1D0F80080072A02F101029CBF48
+:1034500003F8018B4FEA18283FE704EB830300F5DC
+:103460008050DA68D2F818C0DCF80820DCE9001CCB
+:10347000A1EB0C0C00218F4208D1DB689B699A6894
+:103480003A449A605A683A445A6029E711F0030FA7
+:1034900001D1D0F800808C4501F1010184BF02F810
+:1034A000018B4FEA1828E6E7BDE8F88F08B5034816
+:1034B000FFF774FEBDE8084000F074BBF44500203F
+:1034C00008B50348FFF76AFEBDE8084000F06ABB94
+:1034D00090460020D0F8903003EB4111D1F8003B2A
+:1034E00043F40013C1F8003B70470000D0F890305F
+:1034F00003EB4111D1F8003943F40013C1F800394E
+:1035000070470000D0F8903003EB4111D1F8003B38
+:1035100023F40013C1F8003B70470000D0F890304E
+:1035200003EB4111D1F8003923F40013C1F800393D
+:1035300070470000090100F16043012203F5614377
+:10354000C9B283F8001300F01F039A4043099B009F
+:1035500003F1604303F56143C3F880211A607047AB
+:1035600030B50433039C0172002104FB0325C160C4
+:10357000C0E90653049B0363059BC0E90000C0E952
+:103580000422C0E90842C0E90A11436330BD0000CB
+:103590000022416AC260C0E90411C0E90A226FF04A
+:1035A0000101FEF79DBD0000D0E90432934201D134
+:1035B000C2680AB9181D7047002070470369196076
+:1035C0000021C2680132C260C26913448269934219
+:1035D000036124BF436A0361FEF776BD38B5044634
+:1035E0000D46E3683BB162690020131D1268A362B7
+:1035F0001344E36207E0237A33B929462046FEF7F5
+:1036000053FD0028EDDA38BD6FF00100FBE7000044
+:10361000C368C269013BC360436913448269934232
+:10362000436124BF436A436100238362036B03B198
+:103630001847704770B53023044683F31188866AB3
+:103640003EB9FFF7CBFF054618B186F3118828462F
+:1036500070BDA36AE26A13F8015B9342A36202D3CE
+:103660002046FFF7D5FF002383F31188EFE7000022
+:103670002DE9F84F04460E46174698464FF030099C
+:1036800089F311880025AA46D4F828B0BBF1000FB1
+:1036900009D141462046FFF7A1FF20B18BF31188E5
+:1036A0002846BDE8F88FD4E90A12A7EB050B521A99
+:1036B000934528BF9346BBF1400F1BD9334601F118
+:1036C000400251F8040B914243F8040BF9D1A36A6C
+:1036D000403640354033A362D4E90A239A4202D3EC
+:1036E0002046FFF795FF8AF31188BD42D8D289F3AF
+:1036F0001188C9E730465A46FDF7AEFBA36A5E441F
+:103700005D445B44A362E7E710B5029C0433017299
+:1037100003FB0421C460C0E906130023C0E90A3397
+:10372000039B0363049BC0E90000C0E90422C0E9D5
+:103730000842436310BD0000026A6FF00101C260DD
+:10374000426AC0E904220022C0E90A22FEF7C8BC8E
+:10375000D0E904239A4201D1C26822B9184650F830
+:10376000043B0B60704700231846FAE7C36800214A
+:10377000C2690133C3604369134482699342436160
+:1037800024BF436A4361FEF79FBC000038B504467E
+:103790000D46E3683BB1236900201A1DA262E2696D
+:1037A0001344E36207E0237A33B929462046FEF743
+:1037B0007BFC0028EDDA38BD6FF00100FBE700006C
+:1037C00003691960C268013AC260C2691344826920
+:1037D0009342036124BF436A036100238362036B46
+:1037E00003B118477047000070B530230D460446FA
+:1037F000114683F31188866A2EB9FFF7C7FF10B10F
+:1038000086F3118870BDA36A1D70A36AE26A013352
+:103810009342A36204D3E16920460439FFF7D0FF45
+:10382000002080F31188EDE72DE9F84F04460D469E
+:10383000904699464FF0300A8AF311880026B34625
+:10384000A76A4FB949462046FFF7A0FF20B187F38A
+:1038500011883046BDE8F88FD4E90A073A1AA8EB78
+:103860000607974228BF1746402F1BD905F1400392
+:1038700055F8042B9D4240F8042BF9D1A36A403639
+:103880004033A362D4E90A239A4204D3E169204673
+:103890000439FFF795FF8BF311884645D9D28AF397
+:1038A0001188CDE729463A46FDF7D6FAA36A3D448A
+:1038B0003E443B44A362E5E7D0E904239A4217D192
+:1038C000C3689BB1836A8BB1043B9B1A0ED0136013
+:1038D000C368013BC360C3691A4483699A420261A9
+:1038E00024BF436A036100238362012318467047A3
+:1038F0000023FBE700F080B94FF08043586A70471F
+:103900004FF08043002258631A610222DA60704748
+:103910004FF080430022DA60704700004FF0804390
+:1039200058637047FEE7000070B51B4B0025044646
+:1039300086B058600E468562016300F00BF904F111
+:103940001003A560E562C4E904334FF0FF33C4E916
+:103950000044C4E90635FFF7CFFF2B46024604F1C9
+:1039600034012046C4E9082380230C4A2565FEF76C
+:1039700051FB01230A4AE0600092037568467268B1
+:103980000192B268CDE90223064BCDE90435FEF77A
+:1039900069FB06B070BD00BFB02A0020C843000814
+:1039A000CD43000825390008024AD36A1843D06283
+:1039B000704700BF482800204B6843608B688360D5
+:1039C000CB68C3600B6943614B6903628B694362D7
+:1039D0000B6803607047000008B53C4B40F2FF7174
+:1039E0003B48D3F888200A43C3F88820D3F88820BE
+:1039F00022F4FF6222F00702C3F88820D3F888205F
+:103A0000D3F8E0200A43C3F8E020D3F808210A43A2
+:103A1000C3F808212F4AD3F808311146FFF7CCFF2D
+:103A200000F5806002F11C01FFF7C6FF00F5806021
+:103A300002F13801FFF7C0FF00F5806002F1540188
+:103A4000FFF7BAFF00F5806002F17001FFF7B4FFE5
+:103A500000F5806002F18C01FFF7AEFF00F5806099
+:103A600002F1A801FFF7A8FF00F5806002F1C40190
+:103A7000FFF7A2FF00F5806002F1E001FFF79CFF75
+:103A800000F5806002F1FC01FFF796FF02F58C71F2
+:103A900000F58060FFF790FF00F074F90E4BD3F84B
+:103AA000902242F00102C3F89022D3F8942242F00F
+:103AB0000102C3F894220522C3F898204FF0605207
+:103AC000C3F89C20054AC3F8A02008BD0044025852
+:103AD00000000258D443000800ED00E01F00080376
+:103AE00008B500F031FBFEF759FA0F4BD3F8DC2094
+:103AF00042F04002C3F8DC20D3F8042122F0400257
+:103B0000C3F80421D3F80431084B1A6842F00802C4
+:103B10001A601A6842F004021A60FEF727FFBDE837
+:103B20000840FEF7C9BC00BF004402580018024814
+:103B300070470000EFF30983054968334A6B22F0B0
+:103B400001024A6383F30988002383F311887047D5
+:103B500000EF00E0302080F3118862B60D4B0E4A72
+:103B6000D96821F4E0610904090C0A430B49DA60C1
+:103B7000D3F8FC2042F08072C3F8FC20084AC2F857
+:103B8000B01F116841F0010111602022DA7783F83B
+:103B90002200704700ED00E00003FA0555CEACC5E9
+:103BA000001000E0302310B583F311880E4B5B68E2
+:103BB00013F4006314D0F1EE103AEFF309844FF0E0
+:103BC0008073683CE361094BDB6B236684F30988EF
+:103BD000FEF7B8F910B1064BA36110BD054BFBE72A
+:103BE00083F31188F9E700BF00ED00E000EF00E08B
+:103BF0002F04000832040008114BD3F8E82042F0EB
+:103C00000102C3F8E820D3F8102142F00102C3F802
+:103C100010210C4AD3F81031D36B43F00103D36366
+:103C20004FF08043C7229A624FF0FF32DA620022DF
+:103C30009A615A63DA605A6001225A611A607047C9
+:103C4000004402580010005C4FF0804208B5116932
+:103C5000D3680B40D9B29B076FEA0101116107D508
+:103C6000302383F31188FEF7AFF9002383F3118823
+:103C700008BD0000064BD3F8DC200243C3F8DC206B
+:103C8000D3F804211043C3F80401D3F8043170477A
+:103C9000004402583A4B4FF0FF31D3F8802062F0D5
+:103CA0000042C3F88020D3F8802002F00042C3F81D
+:103CB0008020D3F88020D3F88420C3F88410D3F870
+:103CC00084200022C3F88420D3F88400D86F40F009
+:103CD000FF4040F4FF0040F4DF4040F07F00D86731
+:103CE000D86F20F0FF4020F4FF0020F4DF4020F0E8
+:103CF0007F00D867D86FD3F888006FEA40506FEA2A
+:103D00005050C3F88800D3F88800C0F30A00C3F805
+:103D10008800D3F88800D3F89000C3F89010D3F847
+:103D20009000C3F89020D3F89000D3F89400C3F823
+:103D30009410D3F89400C3F89420D3F89400D3F8E7
+:103D40009800C3F89810D3F89800C3F89820D3F8D7
+:103D50009800D3F88C00C3F88C10D3F88C00C3F80B
+:103D60008C20D3F88C00D3F89C00C3F89C10D3F8B7
+:103D70009C10C3F89C20D3F89C3000F0B9B900BF68
+:103D80000044025808B50122534BC3F80821534B95
+:103D9000D3F8F42042F00202C3F8F420D3F81C2137
+:103DA00042F00202C3F81C210222D3F81C314C4B12
+:103DB000DA605A689104FCD54A4A1A6001229A6076
+:103DC000494ADA6000221A614FF440429A61444B3A
+:103DD0009A699204FCD51A6842F480721A603F4BCB
+:103DE0001A6F12F4407F04D04FF480321A67002219
+:103DF0001A671A6842F001021A60384B1A685007B5
+:103E0000FCD500221A611A6912F03802FBD1012197
+:103E100019604FF0804159605A67344ADA62344A77
+:103E20001A611A6842F480321A602C4B1A689103A6
+:103E3000FCD51A6842F480521A601A689204FCD5C4
+:103E40002C4A2D499A6200225A63196301F57C01BC
+:103E5000DA6301F2E71199635A64284A1A64284A1E
+:103E6000DA621A6842F0A8521A601C4B1A6802F013
+:103E70002852B2F1285FF9D148229A614FF4886242
+:103E8000DA6140221A621F4ADA641F4A1A651F4A21
+:103E90005A651F4A9A6532231E4A1360136803F05D
+:103EA0000F03022BFAD10D4A136943F00303136188
+:103EB000136903F03803182BFAD14FF00050FFF7C5
+:103EC000D9FE4FF08040FFF7D5FE4FF00040BDE82F
+:103ED0000840FFF7CFBE00BF0080005100440258E9
+:103EE0000048025800C000F0020000010000FF017D
+:103EF000008890081210200063020901470E05088F
+:103F0000DD0BBF0120000020000001100910E000BF
+:103F100000010110002000524FF0B04208B5D2F865
+:103F2000883003F00103C2F8883023B1044A1368D3
+:103F30000BB150689847BDE80840FFF733BE00BF9B
+:103F4000444700204FF0B04208B5D2F8883003F063
+:103F50000203C2F8883023B1044A93680BB1D068D9
+:103F60009847BDE80840FFF71DBE00BF444700204A
+:103F70004FF0B04208B5D2F8883003F00403C2F81D
+:103F8000883023B1044A13690BB150699847BDE8E2
+:103F90000840FFF707BE00BF444700204FF0B04283
+:103FA00008B5D2F8883003F00803C2F8883023B18E
+:103FB000044A93690BB1D0699847BDE80840FFF700
+:103FC000F1BD00BF444700204FF0B04208B5D2F821
+:103FD000883003F01003C2F8883023B1044A136A12
+:103FE0000BB1506A9847BDE80840FFF7DBBD00BF42
+:103FF000444700204FF0B04310B5D3F8884004F494
+:104000007872C3F88820A30604D5124A936A0BB1CC
+:10401000D06A9847600604D50E4A136B0BB1506BFB
+:104020009847210604D50B4A936B0BB1D06B984788
+:10403000E20504D5074A136C0BB1506C9847A305F1
+:1040400004D5044A936C0BB1D06C9847BDE810407E
+:10405000FFF7A8BD444700204FF0B04310B5D3F898
+:10406000884004F47C42C3F88820620504D5164ACF
+:10407000136D0BB1506D9847230504D5124A936D0B
+:104080000BB1D06D9847E00404D50F4A136E0BB105
+:10409000506E9847A10404D50B4A936E0BB1D06EB5
+:1040A0009847620404D5084A136F0BB1506F9847C4
+:1040B000230404D5044A936F0BB1D06F9847BDE831
+:1040C0001040FFF76FBD00BF4447002008B503480C
+:1040D000FDF744F8BDE80840FFF764BDD823002091
+:1040E00008B5FFF7B1FDBDE80840FFF75BBD000074
+:1040F000062108B50846FFF71DFA06210720FFF73D
+:1041000019FA06210820FFF715FA06210920FFF702
+:1041100011FA06210A20FFF70DFA06211720FFF7F2
+:1041200009FA06212820FFF705FA09217A20FFF76E
+:1041300001FA07211C20FFF7FDF90C213520BDE80D
+:104140000840FFF7F7B9000008B5FFF7A3FD00F03E
+:104150000DF8FDF71BFAFDF7F3FBFDF7C5FAFFF7C6
+:10416000E7FCBDE80840FFF7C5BB00000023054A97
+:1041700019460133102BC2E9001102F10802F8D1EF
+:10418000704700BF4447002010B5013902449042F7
+:1041900001D1002005E0037811F8014FA34201D0BE
+:1041A000181B10BD0130F2E7034611F8012B03F88C
+:1041B000012B002AF9D1704753544D333248373F11
+:1041C0003F3F0053544D3332483733782F373278DE
+:1041D0000053544D3332483734332F3735332F376C
+:1041E0003530000001105A0003105900012058001A
+:1041F00003205600009600000000000000000000B0
+:1042000000000000000000000000000000000000AE
+:104210004D150008391500087515000861150008CE
+:104220006D150008591500084515000831150008DE
+:1042300081150008000000006516000851160008EE
+:104240008D160008791600088516000871160008FA
+:104250005D160008491600089916000800000000C5
+:104260000100000000000000633000006842000808
+:10427000A0280020B02A00204172647550696C6F3C
+:10428000740025424F415244252D424C0025534590
+:104290005249414C250000000200000000000000CF
+:1042A00085180008F5180008400040006043002011
+:1042B0007043002002000000000000000300000026
+:1042C000000000003D190008000000001000000080
+:1042D00080430020000000000100000000000000FA
+:1042E000F445002001010200552400086523000860
+:1042F00001240008E52300084300000000430008F3
+:1043000009024300020100C0320904000001020258
+:10431000010005240010010524010001042402020B
+:104320000524060001070582030800FF09040100B7
+:10433000020A000000070501024000000705810293
+:1043400040000000120000004C4300081201100160
+:10435000020000400912415700020102030100005F
+:104360000403090425424F4152442500466C7969F3
+:104370006E674D6F6F6E48373433003031323334EF
+:104380003536373839414243444546000000000085
+:10439000991A0008511D0008FD1D0008400040004A
+:1043A0002C4700202C470020010000003C47002043
+:1043B0008000000040010000080000000001000033
+:1043C00000100000080000006D61696E0069646CF7
+:1043D000650000000001912A00000000AAAA8AAA34
+:1043E00000011124FFFF00000000000000A00A00EF
+:1043F0001500000000000000AAAAAAAA15000000EB
+:10440000FFFF0000000000000000000000000002AC
+:1044100000000000AAAAAAAA00000001FFFF0000F5
+:104420000000000000000800200000000000000064
+:10443000AAAAAAAA10000000FFFF000000080000BE
+:10444000000000005000004000000000AAAAAAAA34
+:1044500000000040FFFF000000000000000000001E
+:104460000000000000000000AAAAAAAA00000000A4
+:10447000FFFF00000000000000000000000000003E
+:1044800000000000AAAAAAAA00000000FFFF000086
+:10449000000000000000000000000000000000001C
+:1044A000AAAAAAAA00000000FFFF00000000000066
+:1044B000000000000000000000000000AAAAAAAA54
+:1044C00000000000FFFF00000000000000000000EE
+:1044D0000000000000000000AAAAAAAA0000000034
+:1044E000FFFF0000000000000000000000000000CE
+:1044F00000000000AAAAAAAA00000000FFFF000016
+:10450000000000000000000058040000000000004F
+:1045100000001E0000000000FF000000B82A00207C
+:10452000D823002000000000B841000883040000E8
+:10453000C341000850040000D1410008009600006B
+:1045400000000800960000000008000004000000C1
+:1045500060430008000000000000000000000000B0
+:0C4560000000000000000000000000004F
+:00000001FF
diff --git a/Tools/bootloaders/FlywooF745v2_bl.bin b/Tools/bootloaders/FlywooF745v2_bl.bin
deleted file mode 100755
index 9646eaf81724f8..00000000000000
Binary files a/Tools/bootloaders/FlywooF745v2_bl.bin and /dev/null differ
diff --git a/Tools/bootloaders/FlywooF745v2_bl.hex b/Tools/bootloaders/FlywooF745v2_bl.hex
deleted file mode 100644
index 72347bd710d365..00000000000000
--- a/Tools/bootloaders/FlywooF745v2_bl.hex
+++ /dev/null
@@ -1,1021 +0,0 @@
-:020000040800F2
-:100000000006012001020008690F0008210F000806
-:10001000490F0008210F0008410F000803020008E3
-:100020000302000803020008030200080928000870
-:10003000030200080302000803020008030200088C
-:10004000030200080302000803020008030200087C
-:1000500003020008030200087D390008A5390008E2
-:10006000CD390008F53900081D3A000803020008E0
-:10007000030200080302000803020008030200084C
-:10008000030200080302000803020008030200083C
-:10009000030200080302000803020008453A0008B2
-:1000A000030200080302000803020008030200081C
-:1000B0002D3B0008030200080302000803020008A9
-:1000C00003020008030200080302000803020008FC
-:1000D00003020008193B000803020008030200089D
-:1000E000A93A0008030200080302000803020008FE
-:1000F00003020008030200080302000803020008CC
-:1001000003020008030200080302000803020008BB
-:1001100003020008030200080302000803020008AB
-:10012000030200080302000803020008030200089B
-:10013000030200080302000803020008030200088B
-:10014000030200080302000803020008C92F000888
-:10015000030200080302000803020008030200086B
-:10016000030200080302000803020008030200085B
-:10017000030200080302000803020008030200084B
-:10018000030200080302000803020008030200083B
-:10019000030200080302000803020008030200082B
-:1001A000030200080302000803020008030200081B
-:1001B000030200080302000803020008030200080B
-:1001C00003020008030200080302000803020008FB
-:1001D00003020008030200080302000803020008EB
-:1001E00003020008030200080302000803020008DB
-:1001F00003020008030200080302000803020008CB
-:1002000002E000F000F8FEE772B63A4880F3088892
-:10021000394880F3098839484EF60851CEF200017A
-:10022000086040F20000CCF200004EF63471CEF2CD
-:1002300000010860BFF34F8FBFF36F8F40F20000E3
-:10024000C0F2F0004EF68851CEF200010860BFF314
-:100250004F8FBFF36F8F4FF00000E1EE100A4EF6A4
-:100260003C71CEF200010860062080F31488BFF3D1
-:100270006F8F02F089FB02F02BFB03F021FA4FF0A5
-:1002800055301F491B4A91423CBF41F8040BFAE725
-:100290001C49194A91423CBF41F8040BFAE71A493C
-:1002A0001A4A1B4B9A423EBF51F8040B42F8040B0A
-:1002B000F8E700201749184A91423CBF41F8040B67
-:1002C000FAE702F043FB03F05BFA144C144DAC4226
-:1002D00003DA54F8041B8847F9E700F041F8114CA1
-:1002E000114DAC4203DA54F8041B8847F9E702F0D9
-:1002F0002BBB0000000601200022012000000008A6
-:100300000000012000060120403F000800220120DB
-:1003100070220120702201206030012000020008BC
-:100320000002000800020008000200082DE9F04F5A
-:100330002DED108AC1F80CD0D0F80CD0BDEC108A8D
-:10034000BDE8F08F002383F311882846A0470020E2
-:1003500001F060FEFEE701F0D5FD00DFFEE70000E2
-:1003600038B502F011FA054602F044FA0446D8B94D
-:100370000F4B9D421AD001339D4218BF044641F2F3
-:10038000883504BF01240025002002F007FA0CB1D3
-:1003900000F078F800F062FD00F00CFC284600F058
-:1003A000FDF800F06FF8F9E70025EDE70546EBE70B
-:1003B000010007B008B500F0C9FBA0F120035842C6
-:1003C000584108BD07B541F21203022101A8ADF85A
-:1003D000043000F0D9FB03B05DF804FB38B572B609
-:1003E000202383F3118862B61748C3680BB101F06C
-:1003F00099FE164A144800234FF47A7101F056FE14
-:10040000002383F31188124C236813B12368013B46
-:100410002360636813B16368013B63600D4D2B7803
-:1004200033B963687BB9022000F092FC3223636029
-:100430002B78032B07D163682BB9022000F088FCCE
-:100440004FF47A73636038BD70220120DD03000829
-:100450008C23012084220120084B187003280CD81B
-:10046000DFE800F008050208022000F067BC022067
-:1004700000F05ABC024B00225A60704784220120CF
-:100480008C230120F8B5404B404A1C4619680131C5
-:1004900079D004339342F9D16268A24273D33C4BC2
-:1004A0009B6803F1006303F5C0339A426BD20020CE
-:1004B00000F09AFB0220FFF7CFFF364B00211A6CA9
-:1004C00019641A6E19661A6E5A6C59645A6E596616
-:1004D0005A6E5A6942F080025A615A6922F08002CB
-:1004E0005A615A691A6942F000521A611A6922F077
-:1004F00000521A611B6972B64FF0E023C3F8084D31
-:10050000D4E90004BFF34F8FBFF36F8F224AC2F8C4
-:100510008410BFF34F8F536923F480335361BFF3CB
-:100520004F8FD2F88030C3F3C905C3F34E335B015C
-:1005300043F6E07603EA060C29464CEA8177013956
-:10054000C2F87472F9D2203B13F1200FF2D1BFF33D
-:100550004F8FBFF36F8FBFF34F8FBFF36F8F536911
-:1005600023F4003353610023C2F85032BFF34F8F9E
-:10057000BFF36F8F72B6202383F3118862B685466E
-:1005800080F308882047F8BD00800108208001081A
-:10059000002201200038024000ED00E02DE9F04F7C
-:1005A00093B0B64B00902022FF210AA89D6800F06E
-:1005B000FFFBB34A1378B3B9B24801211170C3608D
-:1005C00072B6202383F3118862B6C3680BB101F0C1
-:1005D000A9FDAD4AAB4800234FF47A7101F066FDE6
-:1005E000002383F31188009B13B1A84B009A1A6073
-:1005F000A74A009C1378032B1EBF00231370A34A45
-:100600004FF0000A18BF5360D3465646D14601202A
-:1006100000F094FB24B19D4B1B68002B00F0278257
-:10062000002000F093FA0390039B002BF2DB0120E3
-:1006300000F07AFB039B213B1F2BE8D801A252F864
-:1006400023F000BFC5060008ED060008810700087A
-:100650000F0600080F0600080F0600081308000820
-:10066000E3090008FD0800085F0900088709000881
-:10067000AD0900080F060008BF0900080F060008B2
-:10068000310A0008650700080F060008750A00080F
-:10069000D1060008650700080F0600085F0900087A
-:1006A0000F0600080F0600080F0600080F060008D6
-:1006B0000F0600080F0600080F0600080F060008C6
-:1006C000810700080220FFF775FE002840F0F9813D
-:1006D000009B0221BAF1000F08BF1C4605A841F299
-:1006E0001233ADF8143000F04FFA90E74FF47A70FF
-:1006F00000F02CFA071EEBDB0220FFF75BFE002860
-:10070000E6D0013F052F00F2DE81DFE807F0030AA3
-:100710000D10133605230593042105A800F034FAC3
-:1007200017E056480421F9E75A480421F6E75A48E9
-:100730000421F3E74FF01C08404600F057FA08F197
-:1007400004080590042105A800F01EFAB8F12C0F4A
-:10075000F2D1012000FA07F747EA0B0B5FFA8BFB97
-:100760004FF0000900F070FB26B10BF00B030B2BD0
-:1007700008BF0024FFF726FE49E748480421CDE7DB
-:10078000002EA5D00BF00B030B2BA1D10220FFF7FD
-:1007900011FE074600289BD0012000F025FA022018
-:1007A000FFF75AFE00265FFA86F8404600F02CFA62
-:1007B0000446B0B10399A1F1400251425141404673
-:1007C00000F032FA01360028EDD1BA46044641F273
-:1007D0001213022105A8ADF814303E4600F0D4F9FA
-:1007E00015E70120FFF738FE2546244B9B68AB42F6
-:1007F00007D9284600F0FAF9013040F06781043546
-:10080000F3E7234B00251D70204BBA465D603E4642
-:10081000A8E7002E3FF45CAF0BF00B030B2B7FF42B
-:1008200057AF0220FFF718FE322000F08FF9B0F129
-:100830000008FFF64DAF18F003077FF449AF0F4AE9
-:10084000926808EB050393423FF642AFB8F5807F0C
-:100850003FF73EAF124B0193B84523DD4FF47A705A
-:1008600000F074F90390039A002AFFF631AF019B60
-:10087000039A03F8012B0137EDE700BF00220120A6
-:100880008823012070220120DD0300088C23012031
-:100890008422012004220120082201200C220120B0
-:1008A00088220120C820FFF785FD074600283FF475
-:1008B0000FAF1F2D11D8C5F1200242450AAB25F01C
-:1008C000030028BF424683490192184400F04AFAC7
-:1008D000019A8048FF2100F06BFA4FEAA8037D4996
-:1008E0000193C8F38702284600F06AFA06460028FA
-:1008F0003FF46DAF019B05EB830533E70220FFF763
-:1009000059FD00283FF4E4AE00F0BAF900283FF4A6
-:10091000DFAE0027B846704B9B68BB4218D91F2F2B
-:1009200011D80A9B01330ED027F0030312AA1344F7
-:1009300053F8203C05934046042205A900F016FB1D
-:1009400004378046E7E7384600F050F90590F2E7B3
-:10095000CDF81480042105A800F016F902E7002361
-:10096000642104A8049300F005F900287FF4B0AED8
-:100970000220FFF71FFD00283FF4AAAE049800F004
-:1009800067F90590E6E70023642104A8049300F0CA
-:10099000F1F800287FF49CAE0220FFF70BFD002841
-:1009A0003FF496AE049800F063F9EAE70220FFF7FF
-:1009B00001FD00283FF48CAE00F072F9E1E702205F
-:1009C000FFF7F8FC00283FF483AE05A9142000F0DF
-:1009D0006DF904210746049004A800F0D5F83946C3
-:1009E000B9E7322000F0B2F8071EFFF671AEBB0780
-:1009F0007FF46EAE384A926807EB090393423FF6E4
-:100A000067AE0220FFF7D6FC00283FF461AE27F066
-:100A100003074F44B9453FF4A5AE484600F0E6F859
-:100A20000421059005A800F0AFF809F10409F1E7E9
-:100A30004FF47A70FFF7BEFC00283FF449AE00F097
-:100A40001FF9002844D00A9B01330BD008220AA9C1
-:100A5000002000F0B5F900283AD02022FF210AA892
-:100A600000F0A6F9FFF7AEFC1C4801F0DBFA13B06A
-:100A7000BDE8F08F002E3FF42BAE0BF00B030B2BD9
-:100A80007FF426AE0023642105A8059300F072F8D8
-:100A9000074600287FF41CAE0220FFF78BFC80463F
-:100AA00000283FF415AEFFF78DFC41F2883001F0CD
-:100AB000B9FA059800F012FA464600F0C5F93C462E
-:100AC000A5E506464EE64FF0000901E6BA467EE689
-:100AD00037467CE68822012000220120A086010002
-:100AE0002DE9F84F4FF47A73DFF85880DFF858900B
-:100AF00006460D4602FB03F7002498F900305A1C05
-:100B00005FFA84FA01D0A34212D159F82400036895
-:100B10002A46D3F820B031463B46D847854207D114
-:100B2000074B012083F800A0BDE8F88F0124E4E71B
-:100B3000002CFBD04FF4FA7001F074FA0020F3E7B8
-:100B4000D8230120102201201422012007B5002300
-:100B5000024601210DF107008DF80730FFF7C0FFB5
-:100B600020B19DF8070003B05DF804FB4FF0FF30A3
-:100B7000F9E700000A4608B50421FFF7B1FF80F04D
-:100B80000100C0B2404208BD30B4074B0A46197894
-:100B9000064B53F821402368DD69054B0146AC46FE
-:100BA000204630BC604700BFD8230120142201201A
-:100BB000A086010070B501F0D9FC094E094D3080C6
-:100BC000002428683388834208D901F0C9FC2B68C7
-:100BD00004440133B4F5C03F2B60F2D370BD00BFB5
-:100BE000DA2301209423012001F082BD00F100608E
-:100BF00000F5C0300068704700F10060920000F519
-:100C0000C03001F001BD0000054B1A68054B1B8880
-:100C10009B1A834202D9104401F0A2BC0020704705
-:100C200094230120DA23012038B5084D044629B168
-:100C300028682044BDE8384001F0B2BC2868204450
-:100C400001F096FC0028F3D038BD00BF94230120AA
-:100C500010F0030309D1B0F5846F04D200F1005005
-:100C6000A0F571200368184670470023FBE70000D9
-:100C700000F10050A0F57120D0F82004704700006A
-:100C8000064991F8243033B10023086A81F82430F2
-:100C90000822FFF7B1BF0120704700BF9823012051
-:100CA000014B1868704700BF002004E0F0B51C4BF2
-:100CB000024618681B4B5D6893F90840C0F30B07A8
-:100CC0000326000CB3F800C0BC4518D15D6893F949
-:100CD0000840B0F5805F17D041F20103984208BF89
-:100CE0005A24013A0A44013D0B4693420ED215F9AB
-:100CF000016F581C66B100F8016C0346F5E7013E30
-:100D000003F10C03DED1E4E74124EAE7184605E0ED
-:100D10002C2582421D7001D9981C5C70401AF0BDD0
-:100D2000002004E01C220120022802BF024B4FF0E9
-:100D300000529A61704700BF00080240022802BFBB
-:100D4000024B4FF400529A61704700BF0008024006
-:100D5000022801BF024A536983F40053536170476C
-:100D60000008024010B50023934203D0CC5CC45469
-:100D70000133F9E710BD000010B5013810F9013F4B
-:100D80003BB191F900409C4203D11AB10131013AC3
-:100D9000F4E71AB191F90020981A10BD1046FCE74B
-:100DA00003460246D01A12F9011B0029FAD17047F6
-:100DB00002440346934202D003F8011BFAE770474E
-:100DC0002DE9F8431F4D144695F824200746884620
-:100DD00052BBDFF870909CB395F824302BB92022D9
-:100DE000FF2148462F62FFF7E3FF95F82400C0F18A
-:100DF0000802A24228BF2246D6B24146920005EB25
-:100E00008000FFF7AFFF95F82430A41B1E44F6B214
-:100E1000082E17449044E4B285F82460DBD1FFF734
-:100E20002FFF0028D7D108E02B6A03EB820383420F
-:100E3000CFD0FFF725FF0028CBD10020BDE8F883F5
-:100E40000120FBE798230120024B1A78024B1A700D
-:100E5000704700BFD82301201022012038B5194C5B
-:100E6000194D204600F0E2FB2946204600F00AFC1E
-:100E70002D681648EA6ED2F8043843F00203C2F82F
-:100E8000043801F0CFF82846114900F009FDEA6E58
-:100E9000104DD2F8043828680F4923F00203C2F835
-:100EA0000438A0424FF4E1330B6001D000F01AFB8C
-:100EB0006868A04204D0BDE83840074900F012BB82
-:100EC00038BD00BF002801200C3D000840420F0043
-:100ED000143D000814220120C023012070B50C4BE2
-:100EE0000C4D1E780C4B55F826209A4204460DD026
-:100EF0000A4B002118221846FFF75AFF04600146EA
-:100F000055F82600BDE8704000F0ECBA70BD00BF97
-:100F1000D82301201422012000280120C023012011
-:100F200000B59BB0EFF3098168226846FFF71AFF0E
-:100F3000EFF30583014B9B6BFEE700BF00ED00E084
-:100F400008B5FFF7EDFF000000B59BB0EFF3098196
-:100F500068226846FFF706FFEFF30583014B5B6BE2
-:100F6000FEE700BF00ED00E0FEE7000030B5094DF0
-:100F70000A4491420DD011F8013B5840082340F338
-:100F80000004013B2C4013F0FF0384EA5000F6D12B
-:100F9000EFE730BD2083B8ED72B6202383F31188CC
-:100FA00062B67047026843681143016003B1184795
-:100FB00070470000024A136843F0C0031360704793
-:100FC0000010014013B50E4C204600F07FFA04F1EA
-:100FD00014000C49009400234FF4807200F044F98F
-:100FE000094B0A4900944FF4807204F1380000F074
-:100FF000B9F9074A074BC4E9172302B010BD00BF77
-:10100000DC23012048240120B50F000848250120D9
-:101010000010014000F36F0630B5037C214C00291D
-:1010200018BF0C46012B0CD11F4B984209D11F4B06
-:101030005A6C42F010025A645A6E42F010025A661C
-:101040005B6E2268036EC16D846603EB5203B3FBD3
-:10105000F2F36268150442BF23F0070503F00703AB
-:1010600043EA4503CB60A36843F040034B60E36869
-:1010700043F001038B6042F4967343F001030B606D
-:101080004FF0FF330B62510505D512F0102205D049
-:10109000B2F1805F04D080F8643030BD7F23FAE77E
-:1010A0003F23F8E7083C0008DC2301200038024019
-:1010B0002DE9F047C66D3768F469346221070546AB
-:1010C00017D014F0080118BF8021E20748BF41F093
-:1010D0002001A30748BF41F04001600748BF41F429
-:1010E0008071281DFFF758FFFFF75CFF002383F393
-:1010F0001188E20509D54FF40071281DFFF74CFF58
-:10110000FFF750FF002383F311884FF0000914F01C
-:10111000200835D13B0614D505F13809200610D535
-:101120004846FFF739FF00F04FF9002835DA08216B
-:10113000281DFFF737FF27F080033360002383F378
-:101140001188790613D5620611D5FFF725FFD5E979
-:1011500013239A4208D12B6C33B11021281D27F09C
-:101160004007FFF71FFF3760002383F31188E30672
-:1011700018D5AA6E1369ABB1BDE8F047506918479E
-:10118000FFF70AFF736A95F864102846194000F0CB
-:10119000B5F989F31188F469B9E7B06288F3118869
-:1011A000F469BBE7BDE8F08772B6202383F31188AA
-:1011B00062B67047F8B5154682680669AA420B46C2
-:1011C000816938BF8568761AB54204460BD2184645
-:1011D0002A46FFF7C7FDA3692B44A361A3685B1BE5
-:1011E000A3602846F8BD0CD918463246FFF7BAFD71
-:1011F000AF1BE1683A463044FFF7B4FDE3683B4477
-:10120000EBE718462A46FFF7ADFDE368E5E7000087
-:1012100083689342F7B51546044638BF8568D0E920
-:101220000460361AB5420BD22A46FFF79BFD63696C
-:101230002B446361A36828465B1BA36003B0F0BD29
-:101240000DD932460191FFF78DFD0199E068AF1B82
-:101250003A463144FFF786FDE3683B44E9E72A4616
-:10126000FFF780FDE368E4E710B50A440024C3619A
-:10127000029B8460C0E90000C0E90511C160026101
-:10128000036210BD08B5D0E90532934201D18268EE
-:1012900082B98268013282605A1C42611970D0E9B9
-:1012A00004329A4224BFC3684361002100F0D6FE95
-:1012B000002008BD4FF0FF30FBE7000070B504468A
-:1012C0000D46FFF771FFA668A6B1A368A269013BAE
-:1012D000A360531CA36115782269934224BFE3687D
-:1012E000A361E3690BB120469847002383F311887B
-:1012F000284607E02946204600F0A0FE0028E2DA52
-:1013000086F3118870BD00002DE9F84FD0F81CA0BD
-:101310009946FFF749FF04460E46904615464FF0A2
-:10132000000B65B12A4631462046FFF743FF0746CA
-:1013300060B94946204600F081FE0028F1D0002324
-:1013400083F31188A8EB0500BDE8F88FBAF1000F10
-:1013500001D02046D0478BF31188ED1B3E44FFF7A8
-:1013600023FFDEE7C0E90511C160C3611144009BA2
-:101370008260C0E90000016103627047F8B504466D
-:101380000D461646FFF710FFA768A7B1A368013BFB
-:10139000A36063695A1C62611D70D4E904329A42E9
-:1013A00024BFE3686361E3690BB1204698470020DE
-:1013B00080F3118807E03146204600F03FFE002808
-:1013C000E2DA87F31188F8BDD0E905239A4210B517
-:1013D00001D182687AB98268013282605A1C8261C6
-:1013E0001C7803699A4224BFC3688361002100F01E
-:1013F00035FE204610BD4FF0FF30FBE72DE9F84FDA
-:10140000D0F81CA09946FFF7CFFE04460E46904642
-:1014100015464FF0000B65B12A4631462046FFF7CE
-:10142000F7FE074660B94946204600F007FE00284F
-:10143000F1D0002383F31188A8EB0500BDE8F88FF5
-:10144000BAF1000F01D02046D0478BF31188ED1B75
-:101450003E44FFF7A9FEDEE772B6202383F311882E
-:1014600062B67047026843681143016003B11847D0
-:10147000704700001430FFF747BF00004FF0FF3304
-:101480001430FFF741BF00003830FFF7B7BF00004E
-:101490004FF0FF333830FFF7B1BF00001430FFF7D3
-:1014A0000DBF00004FF0FF311430FFF707BF000001
-:1014B0003830FFF763BF00004FF0FF323830FFF7DE
-:1014C0005DBF000000207047FFF77CBD044B036048
-:1014D0000023C0E90233436001230374704700BF57
-:1014E000203C000810B50446FFF7B6FFFFF794FD57
-:1014F00002232374002383F3118810BD38B5C36918
-:1015000004460D461BB904210844FFF7ABFF2946EA
-:1015100004F11400FFF7B6FE002806DA201D4FF490
-:101520008061BDE83840FFF79DBF38BD72B620230B
-:1015300083F3118862B67047026843681143016003
-:1015400003B118477047000013B5446BD4F89434C6
-:101550001A681178042915D1217C022912D1197930
-:10156000128901238B4013420CD101A904F14C00D4
-:1015700001F0AEFFD4F89444019B21790246206823
-:1015800000F0DAF902B010BD143001F033BF0000F2
-:101590004FF0FF33143001F02DBF00004C3002F04B
-:1015A00003B800004FF0FF334C3001F0FDBF0000E6
-:1015B000143001F003BF00004FF0FF31143001F090
-:1015C000FDBE00004C3001F0CFBF00004FF0FF32F5
-:1015D0004C3001F0C9BF00000020704710B5D0F8B2
-:1015E00094341A6811780429044617D1017C022921
-:1015F00014D15979528901238B4013420ED11430F2
-:1016000001F096FE024648B1D4F894444FF480733A
-:1016100061792068BDE8104000F07CB910BD000081
-:10162000406BFFF7DBBF0000704700007FB5124B37
-:10163000036000234360C0E90233012502260F4BFB
-:10164000057404460290019300F184022946009635
-:101650004FF48073143001F047FE094B0294CDE93A
-:10166000006304F523724FF48073294604F14C00A3
-:1016700001F00AFF04B070BD483C000821160008C4
-:101680004915000808B50A68FFF750FF0B7902EB0F
-:10169000830318624B790D3342F823008B7913B121
-:1016A00002EB8302106202230374C0F89414002337
-:1016B00083F3118808BD000038B5037F044613B1D9
-:1016C00090F85430ABB9201D01250221FFF734FFFB
-:1016D00004F1140025776FF0010100F0CBFC84F8D1
-:1016E000545004F14C006FF00101BDE8384000F0A7
-:1016F000C1BC38BD10B5012104460430FFF71CFF02
-:101700000023237784F8543010BD000038B5044618
-:101710000025143001F000FE04F14C00257701F0A3
-:10172000CBFE201D84F854500121FFF705FF204611
-:10173000BDE83840FFF752BF90F85C3003F060031B
-:10174000202B07D190F85D20212A4FF0000303D809
-:101750001F2A06D800207047222AFBD1C0E9143383
-:1017600003E0034A02650722426583650120704752
-:101770004022012037B5D0F894341A681178042932
-:1017800004461AD1017C022917D119791289012343
-:101790008B40134211D100F14C05284601F04AFF5D
-:1017A00058B101A9284601F093FED4F89444019B56
-:1017B00021790246206800F0BFF803B030BD000078
-:1017C000F0B500EB810385B01E6A04460D46F6B104
-:1017D00004EB8507301D0821FFF7A8FEFFF7ACFEDC
-:1017E000FB685B691B6806F14C001BB1019001F0BE
-:1017F0007DFE019803A901F06BFE024648B1039BF0
-:101800002946204600F098F8002383F3118805B09C
-:10181000F0BDFB685A691268002AF5D01B8A013BAB
-:101820001340F1D104F15C02EAE700000D3138B554
-:1018300050F82140D4B1FFF779FED4F8942413680E
-:10184000527903EB8203DB689B695D6845B1042133
-:101850006018FFF771FE294604F1140001F072FDD3
-:101860002046FFF7BBFE002383F3118838BD00003C
-:101870007047000072B6202383F3118862B6704768
-:1018800001F0F8B810B501230446282200F8243BE3
-:101890000021FFF78DFA0023C4E9013310BD0000D9
-:1018A00038B50025FFF7E6FF0446C0E90355C0E957
-:1018B0000555C0E90755416001F0ECF8022323709B
-:1018C00085F3118838BD000070B500EB8103054633
-:1018D0005069DA600E46144618B110220021FFF755
-:1018E00067FAA06918B110220021FFF761FA3146AA
-:1018F0002846BDE8704001F097B90000826802F008
-:10190000011282600022C0E90422C0E906220262BC
-:1019100001F016BAF0B400EB81044789E4680125B0
-:10192000A4698D403D43458123600023A26063602C
-:10193000F0BC01F031BA0000F0B400EB810407897B
-:10194000E468012564698D403D43058123600023DF
-:10195000A2606360F0BC01F0ADBA000070B5022374
-:10196000002504460370C0E90255C0E90455C0E9EA
-:1019700006554566056280F84C5001F0F1F8636841
-:101980001B6823B129462046BDE87040184770BD4A
-:10199000037880F868300523037043681B6810B52E
-:1019A00004460BB1042198470023A36010BD00003A
-:1019B00090F86820436802701B680BB10521184736
-:1019C0007047000070B590F84C30044613B1002306
-:1019D00080F84C3004F15C02204601F0D3F96368D2
-:1019E0009B68B3B994F85C3013F0600533D00021E4
-:1019F000204601F03FFC0021204601F031FC6368E5
-:101A00001B6813B1062120469847062384F84C3002
-:101A100070BD204698470028E4D0B4F86230626D6B
-:101A20009A4288BF636594F95C30656D002B80F243
-:101A30000281002D00F0F180092384F84C30FFF77B
-:101A400019FF0021D4E914232046FFF775FF002376
-:101A500083F31188DCE794F85D2003F07F0343EA09
-:101A6000022340F20232934200F0C48021D8B3F541
-:101A7000807F48D00DD8012B3FD0022B00F0928000
-:101A8000002BB4D104F16402226502226265A365D1
-:101A9000C3E7B3F5817F00F09A80B3F5407FA6D10C
-:101AA00094F85E30012BA2D1B4F8643043F0020305
-:101AB00032E0B3F5006F4DD017D8B3F5A06F31D039
-:101AC000A3F5C063012B92D8636894F85E205E682A
-:101AD00094F85F10B4F860302046B047002886D0F4
-:101AE00043682365036863651AE0B3F5106F36D069
-:101AF00040F6024293427FF47AAF5B4B23650223A8
-:101B000063650023C3E794F85E30012B7FF46FAF69
-:101B1000B4F8643023F00203C4E91455A4F8643027
-:101B2000A5657AE7B4F85C30B3F5A06F0ED194F8F0
-:101B30005E3084F86630204601F06AF863681B68FE
-:101B400013B1012120469847032323700023C4E9E1
-:101B500014339CE704F1670323650123C3E723786B
-:101B6000042B0FD12046FFF785FEFFF7C7FE85F354
-:101B700011880321636884F8675021701B680BB1DA
-:101B80002046984794F85E30002BDFD084F8673009
-:101B90000423237063681B68002BD7D002212046E2
-:101BA0009847D3E794F860301D0603F00F012046F4
-:101BB0000AD501F0D9F8012804D002287FF417AF24
-:101BC0002A4B9BE72A4B99E701F0C0F8F3E794F81A
-:101BD0005E30002B7FF40BAF94F8603013F00F01F0
-:101BE000B4D01A06204602D501F058FBAEE701F04A
-:101BF0004BFBABE794F85E30002B7FF4F8AE94F823
-:101C0000603013F00F01A1D01B06204602D501F071
-:101C100031FB9BE701F024FB98E7142384F84C3058
-:101C2000FFF728FE2A462B4629462046FFF772FE7C
-:101C300085F31188ECE65DB1152384F84C30FFF78D
-:101C400019FE0021D4E914232046FFF763FEFEE6C7
-:101C50000B2384F84C30FFF70DFE2A462B4629460D
-:101C60002046FFF769FEE3E7783C0008703C000877
-:101C7000743C000838B590F84C300446002B3CD03A
-:101C8000063BDAB20F2A32D80F2B30D8DFE803F048
-:101C9000352F2F0821302F2F2F2F2F2F2F2F353576
-:101CA000456DB0F862309D4213D2C3681B8AB5FB04
-:101CB000F3F203FB125565B9FFF7DCFD2A462B460C
-:101CC0002946FFF739FE85F311880A2384F84C3042
-:101CD0000DE0142384F84C30FFF7CCFD00231A46A6
-:101CE00019462046FFF716FE002383F3118838BDFE
-:101CF000836D03B198470023E8E70021204601F0F7
-:101D0000B9FA0021204601F0ABFA63681B6813B1F1
-:101D10000621204698470623D8E7000010B590F822
-:101D20004C30142B044628D017D8062B05D001D8E8
-:101D30001BB110BD093B022BFBD80021204601F04E
-:101D400099FA0021204601F08BFA63681B6813B1F1
-:101D5000062120469847062318E0152BE9D10B23CE
-:101D600080F84C30FFF786FD00231A461946FFF72E
-:101D7000E3FD002383F31188DBE7C3689B695B689D
-:101D8000002BD6D1836D03B19847002384F84C30E3
-:101D9000CFE70000024B0022C3E900339A6070478E
-:101DA00048260120002303748268054B1B6899684C
-:101DB0009142FBD25A6803604260106058607047DD
-:101DC0004826012008B572B6202383F3118862B635
-:101DD000037C032B05D0042B0DD02BB983F3118882
-:101DE00008BD436900221A604FF0FF334361FFF7DB
-:101DF000D9FF0023F2E7D0E9003213605A60F3E71D
-:101E0000002303748268054B1B6899689142FBD8D4
-:101E10005A6803604260106058607047482601208D
-:101E2000054B19690874186802681A6053601861D4
-:101E300001230374FEF77ABA4826012030B54B1C03
-:101E40000B4D87B0044610D02B690A4A01A800F058
-:101E50002DF92046FFF7E4FF049B13B101A800F021
-:101E600061F92B69586907B030BDFFF7D9FFF8E772
-:101E700048260120C51D000838B50C4D41612B696D
-:101E800081689A689142044603D8BDE83840FFF75C
-:101E900089BF1846FFF7B4FF01232C610146237464
-:101EA0002046BDE83840FEF741BA00BF4826012071
-:101EB000044B1A681B6990689B68984294BF002085
-:101EC000012070474826012010B5084C236820697E
-:101ED0001A6822605460012223611A74FFF790FF90
-:101EE00001462069BDE81040FEF720BA48260120CF
-:101EF00008B5FFF7DDFF18B1BDE80840FFF7E4BF04
-:101F000008BD0000FFF7E0BFFEE7000010B50C4C75
-:101F1000FFF740FF00F0BCF80A498022204600F09D
-:101F200043F8012344F8180C037400F07DFC0023EF
-:101F300083F3118862B60448BDE8104000F054B83D
-:101F4000702601207C3C00088C3C000800F024B97D
-:101F5000EFF3118030B9EFF30583202272B682F3DC
-:101F6000118862B67047000010B530B9EFF30584F0
-:101F7000C4F3080414B180F3118810BDFFF7B8FF53
-:101F800084F31188F9E70000034A516853685B1A2B
-:101F90009842FBD8704700BF001000E072B62023C3
-:101FA00083F3118862B67047826002220282704712
-:101FB0008368A3F17C0243F80C2C026943F83C2CA3
-:101FC000426943F8382C074A43F81C2CC26843F88E
-:101FD000102C022203F8082C002203F8072CA3F18E
-:101FE000180070474503000810B5FFF7D7FFFFF74B
-:101FF000DFFF00210446FFF73FFF002383F3118832
-:10200000204610BD024B1B6958610F20FFF708BF27
-:102010004826012008B5FFF7C1FFBDE80840FFF7DB
-:10202000F1BF000008B501460820FFF7B7FFFFF732
-:1020300005FF002383F3118808BD000049B1064B5A
-:1020400042681B6918605A60136043600420FFF700
-:10205000F5BE4FF0FF3070474826012003689842D4
-:1020600006D01A680260506059611846FFF79ABEA0
-:102070007047000038B504460D462068844200D100
-:1020800038BD036823605C604561FFF78BFEF4E7B1
-:10209000054B03F11402C3E905224FF0FF31002282
-:1020A000C3E90712704700BF4826012070B51C4ED7
-:1020B000C0E9032305460C4601F0EEFA334653F817
-:1020C000142F9A420DD13062C5E901242A600A2CEE
-:1020D0002CBF00190A30C6E90555BDE8704001F073
-:1020E000C9BA316A431AE31838BF1C469368A34241
-:1020F00002D9081901F0CCFA73699A6894420CD895
-:102100005A68AC602B606A6015609A685D60121B4B
-:102110009A604FF0FF33F36170BD1B68A41AECE7BF
-:102120004826012038B51B4C636998420DD0D0E990
-:10213000003213605A6000228168C2609A680A44C3
-:102140009A604FF0FF33E36138BD2246036842F8DE
-:10215000143F002193425A60C16003D1BDE838406A
-:1021600001F090BA9A688168256A0A449A6001F081
-:1021700093FA63699A68411B8A42E5D9AB181D1A24
-:10218000092D206A98BF01F10A02BDE838401044C9
-:1021900001F07EBA482601202DE9F041194C0027B4
-:1021A00004F11406656901F077FA236AAA68C11A76
-:1021B0008A4217D813442362D5E9003213605A606B
-:1021C0006369D5F80C80EF60B34201D101F05AFA8F
-:1021D00087F311882869C04772B6202383F31188DA
-:1021E00062B6DFE76169B14209D013441B1ABDE84A
-:1021F000F0410A2B2CBFC0180A3001F049BABDE8E3
-:10220000F08100BF4826012000207047FEE7000053
-:10221000704700004FF0FF307047000072B6202377
-:1022200083F3118862B6704702290CD0032904D0C9
-:102230000129074818BF00207047032A05D8054820
-:1022400000EBC2007047044870470020704700BF91
-:10225000703D000850220120243D000870B59AB05E
-:102260000546084601A9144600F0BEF801A8FEF78D
-:1022700097FD431C5B00C5E9003400222370032353
-:102280006370C6B201AB02341046D1B28E4204F183
-:10229000020401D81AB070BD13F8011B04F8021C27
-:1022A00004F8010C0132F0E708B50448FFF7B6FF67
-:1022B000FFF760FA002383F3118808BD002801208E
-:1022C00090F85C3003F01F02012A07D190F85D20DE
-:1022D0000B2A03D10023C0E9143315E003F0600397
-:1022E000202B08D1B0F860302BB990F85D20212A5E
-:1022F00003D81F2A04D8FFF71FBA222AEBD0FAE727
-:10230000034A02650722426583650120704700BFCA
-:102310004722012007B5052916D8DFE801F0181576
-:102320000318181E104A0121FFF778FF0190FFF7EC
-:10233000CBFA01980D4A0221FFF7C6FA0C48FFF7C5
-:10234000E5F9002383F3118803B05DF804FB084826
-:10235000FFF764FFFFF7B0F9F3E70548FFF75EFF0B
-:10236000FFF7C8F9EDE700BFC43C0008E83C0008EF
-:102370000028012038B50C4D0C4C0D492A4604F1BB
-:102380000800FFF76BFF05F1CA0204F110000949CC
-:10239000FFF764FF05F5CA7204F118000649BDE8AD
-:1023A0003840FFF75BBF00BFC82C0120502201203E
-:1023B000A43C0008AE3C0008B93C000870B50446D7
-:1023C00008460D46FEF7ECFCC6B220460134037801
-:1023D0000BB9184670BD32462946FEF7CDFC0028E1
-:1023E000F3D10120F6E700002DE9F84F05460C4631
-:1023F000FEF7D6FC2B49C6B22846FFF7DFFF08B12F
-:102400000536F6B228492846FFF7D8FF08B110363E
-:10241000F6B2632E0DD8DFF88C80DFF88C90234F56
-:10242000DFF890A0DFF890B02E7846B92670BDE8AE
-:10243000F88F29462046BDE8F84F01F0C7BB252E8E
-:102440002BD1072241462846FEF796FC58B9DBF807
-:1024500000302360DBF804306360DBF80830A360F1
-:1024600007350C34E0E7082249462846FEF784FC8D
-:1024700098B90F4BA21C197809090232C95D02F8FC
-:10248000041C13F8011B01F00F015345C95D02F84C
-:10249000031CF0D118340835C6E704F8016B013588
-:1024A000C2E700BF903D0008B93C0008A53D000808
-:1024B00020F4F01F2CF4F01F983D0008BFF34F8F5D
-:1024C000024AD368DB03FCD4704700BF003C0240E3
-:1024D00008B5074B1B7853B9FFF7F0FF054B1A6996
-:1024E000002ABFBF044A5A6002F188325A6008BD10
-:1024F000262F0120003C02402301674508B5054B0B
-:102500001B7833B9FFF7DAFF034A136943F000433E
-:10251000136108BD262F0120003C02400728F0B5BA
-:1025200016D80C4C0C4923787BB90C4D0E46082369
-:102530004FF0006255F8047B46F8042B013B13F082
-:10254000FF033A44F6D10123237051F82000F0BD77
-:102550000020FCE7482F0120282F0120B83D00086B
-:10256000014B53F820007047B83D00080820704721
-:10257000072810B5044601D9002010BDFFF7CEFF93
-:10258000064B53F824301844C21A0BB90120F4E763
-:1025900012680132F0D1043BF6E700BFB83D0008F5
-:1025A000072838B5044628D8FFF7D2FCFFF786FF86
-:1025B000FFF78EFF124AF323D360E300DBB243F44C
-:1025C000007343F002031361136943F48033136112
-:1025D00005462046FFF772FFFFF7A0FF094B53F8AF
-:1025E000241000F0E9F82846FFF788FFFFF7BCFC4D
-:1025F0002046BDE83840FFF7BBBF002038BD00BF14
-:10260000003C0240B83D000812F001032DE9F04102
-:1026100005460E4614464BD18218B2F1016F61D8BF
-:10262000314B1B6813F001035CD0304FFFF790FC77
-:10263000FFF74EFFF323FB60FFF740FF314640F208
-:102640000128032C18D824F00104284E0C446D1ADC
-:1026500040F20118A142336905EB01072AD123F0AA
-:1026600001033361FFF74AFFFFF77EFC0120BDE85D
-:10267000F081043C0435E4E7AB07E4D13B6923F483
-:1026800040733B613B6943EA08033B6151F8046BCB
-:102690002E60BFF34F8FFFF711FF2B689E42E8D0EB
-:1026A0003B6923F001033B61FFF728FFFFF75CFC68
-:1026B0000020DCE723F440733361336943EA080305
-:1026C00033610B883B80BFF34F8FFFF7F7FE3F88E6
-:1026D00031F8023BBFB2BB42BCD0336923F00103E7
-:1026E0003361E1E71846C2E700380240003C02408F
-:1026F000084908B50B7828B11BB9FFF7E9FE01239B
-:102700000B7008BD002BFCD0BDE808400870FFF737
-:10271000F5BE00BF262F012010B50244064BD2B2F1
-:10272000904200D110BD441C00B253F8200041F883
-:10273000040BE0B2F4E700BF502800400F4B30B567
-:102740001C6F240407D41C6F44F400741C671C6FB6
-:1027500044F400441C670A4C236843F480732360EC
-:102760000244084BD2B2904200D130BD441C00B2AA
-:1027700051F8045B43F82050E0B2F4E7003802401F
-:10278000007000405028004007B5012201A9002038
-:10279000FFF7C2FF019803B05DF804FB13B50446D0
-:1027A000FFF7F2FFA04205D0012201A90020019409
-:1027B000FFF7C4FF02B010BD0144BFF34F8F064BBB
-:1027C000884204D3BFF34F8FBFF36F8F7047C3F8B6
-:1027D0005C022030F4E700BF00ED00E0034B1A6814
-:1027E0001AB9034AD2F874281A6070474C2F012096
-:1027F0000030024008B5FFF7F1FF024B1868C0F344
-:10280000407008BD4C2F0120EFF3098305494A6B46
-:1028100022F001024A63683383F30988002383F3BB
-:102820001188704700EF00E0202080F3118862B625
-:102830000D4B0E4AD96821F4E0610904090C0A43E2
-:10284000DA60D3F8FC200A4942F08072C3F8FC2019
-:10285000084AC2F8B01F116841F00101116010224E
-:10286000DA7783F82200704700ED00E00003FA05F4
-:1028700055CEACC5001000E010B572B6202383F32E
-:10288000118862B60E4B5B6813F4006314D0F1EE4E
-:10289000103AEFF30984683C4FF08073E361094B11
-:1028A000DB6B236684F30988FFF702FB10B1064B4C
-:1028B000A36110BD054BFBE783F31188F9E700BF67
-:1028C00000ED00E000EF00E0570300085A030008A5
-:1028D00070B5BFF34F8FBFF36F8F1A4A0021C2F854
-:1028E0005012BFF34F8FBFF36F8F536943F4003320
-:1028F0005361BFF34F8FBFF36F8FC2F88410BFF3E4
-:102900004F8FD2F88030C3F3C900C3F34E335B015D
-:1029100043F6E07403EA0406014646EA817501398C
-:10292000C2F86052F9D2203B13F1200FF2D1BFF36D
-:102930004F8F536943F480335361BFF34F8FBFF31D
-:102940006F8F70BD00ED00E0FEE700000A4B0B4802
-:102950000B4A90420BD30B4BDA1C121AC11E22F009
-:1029600003028B4238BF00220021FEF721BA53F840
-:10297000041B40F8041BECE7B03F00086030012066
-:1029800060300120603001207047000070B5D0E950
-:102990001B439E6800224FF0FF3504EB42135101A8
-:1029A000D3F800090028BEBFD3F8000940F08040EA
-:1029B000C3F80009D3F8000B0028BEBFD3F8000B02
-:1029C00040F08040C3F8000B013263189642C3F810
-:1029D0000859C3F8085BE0D24FF00113C4F81C3863
-:1029E00070BD00001D4B03EB80022DE9F043D2F8CF
-:1029F0000CC0DD6EDCF81420461CD2F800E005EBBC
-:102A0000063605EB4018516871450AD3D5F83438BD
-:102A1000012202FA00F023EA0000C5F83408BDE8FC
-:102A2000F083BCF81040AEEB0103A34228BF23465D
-:102A3000D8F81849A4B2B3EB840FF0D89468A4F185
-:102A4000040959F8047F3760A4EB09071F44042FD9
-:102A5000F7D81C440B4494605360D4E7502F0120F6
-:102A6000890141F02001016103699B06FCD4122019
-:102A7000FFF78ABA10B5054C2046FEF703FF4FF06A
-:102A8000A043E366024B236710BD00BF502F012017
-:102A9000FC3D000870B50378012B054650D12A4B48
-:102AA000C46E98421BD1294B5A6B42F080025A6384
-:102AB0005A6D42F080025A655A6D5A6942F080029E
-:102AC0005A615A6922F080025A610E2143205B69E3
-:102AD00000F0EEFB1E4BE3601E4BC4F800380023F1
-:102AE000C4F8003EC0232360EE6E4FF40413A363CA
-:102AF0003369002BFCDA012333610C20FFF744FA21
-:102B00003369DB07FCD41220FFF73EFA3369002B50
-:102B1000FCDA0026A6602846FFF738FF6B68C4F889
-:102B20001068DB68C4F81468C4F81C684BB90A4B19
-:102B3000A3614FF0FF336361A36843F00103A36017
-:102B400070BD064BF4E700BF502F01200038024053
-:102B50004014004003002002003C30C0083C30C05C
-:102B6000F8B5C46E054600212046FFF779FF296FAE
-:102B700000234FF001128F68C4F834384FF000661C
-:102B8000C4F81C284FF0FF3004EB431201339F427E
-:102B9000C2F80069C2F8006BC2F80809C2F8080B55
-:102BA000F2D20B68EA6E6B676362102313611669D9
-:102BB00016F01006FBD11220FFF7E6F9D4F8003822
-:102BC00023F4FE63C4F80038A36943F4402343F0C0
-:102BD0001003A3610923C4F81038C4F814380A4B51
-:102BE000EB604FF0C043C4F8103B084BC4F8003B07
-:102BF000C4F81069C4F800396B6F03F1100243F494
-:102C000080136A67A362F8BDD83D000840800010B9
-:102C1000C26E90F86610D2F8003823F4FE6343EADF
-:102C20000113C2F8003870472DE9F84300EB810327
-:102C3000C56EDA68166806F00306731E022B05EBF4
-:102C400041130C4680460FFA81F94FEA41104FF0CC
-:102C50000001C3F8101B4FF0010104F1100398BFED
-:102C6000B60401FA03F391698EBF334E06F1805624
-:102C700006F5004600293AD0578A04F15801490167
-:102C800037436F50D5F81C180B43C5F81C382B1868
-:102C90000021C3F8101953690127611EA7409BB397
-:102CA000138A928B9B08012A88BF5343D8F874205B
-:102CB000981842EA034301F1400205EB8202C8F88A
-:102CC0007400214653602846FFF7CAFE08EB8900CE
-:102CD000C3681B8A43EA8453483464011E432E515F
-:102CE000D5F81C381F43C5F81C78BDE8F88305EB00
-:102CF0004917D7F8001B21F40041C7F8001BD5F88D
-:102D00001C1821EA0303C0E704F13F0305EB83032A
-:102D10000A4A5A6028462146FFF7A2FE05EB4910F1
-:102D2000D0F8003923F40043C0F80039D5F81C3836
-:102D300023EA0707D7E700BF008000100004000265
-:102D4000026F12684267FFF721BE00005831C36E60
-:102D500049015B5813F4004004D013F4001F0CBF6A
-:102D600002200120704700004831C36E49015B58C2
-:102D700013F4004004D013F4001F0CBF0220012004
-:102D80007047000000EB8101CB68196A0B68136083
-:102D90004B6853607047000000EB810330B5DD687D
-:102DA000AA691368D36019B9402B84BF402313600C
-:102DB0006B8A1468C26E1C44013CB4FBF3F4634399
-:102DC000033323F0030302EB411043EAC44343F00F
-:102DD000C043C0F8103B2B6803F00303012B09B27A
-:102DE0000ED1D2F8083802EB411013F4807FD0F8EE
-:102DF000003B14BF43F0805343F00053C0F8003B46
-:102E000002EB4112D2F8003B43F00443C2F8003B0E
-:102E100030BD00002DE9F041254DEE6E06EB40136C
-:102E20000446D3F8087BC3F8087B38070AD5D6F8E0
-:102E30001438190706D505EB84032146DB682846BC
-:102E40005B689847FA0721D5D6F81438DB071DD5FB
-:102E500005EB8403D968DCB98B69488A5A68B2FBF0
-:102E6000F0F600FB16229AB91868DA6890420FD281
-:102E7000121AC3E9002472B6202383F3118862B6C4
-:102E80000B482146FFF788FF84F31188BDE8F081E5
-:102E9000012303FA04F26B8923EA02036B81CB68F6
-:102EA000002BF3D021460248BDE8F041184700BF8F
-:102EB000502F012000EB810370B5DD68C36E6C6993
-:102EC0002668E6604A0156BB1A444FF40020C2F857
-:102ED00010092A6802F00302012A0AB20ED1D3F8BF
-:102EE000080803EB421410F4807FD4F8000914BFE3
-:102EF00040F0805040F00050C4F8000903EB42124B
-:102F0000D2F8000940F00440C2F80009D3F83408B0
-:102F1000012202FA01F10143C3F8341870BD19B956
-:102F2000402E84BF4020206020682E8A8419013CF6
-:102F3000B4FBF6F440EAC44040F000501A44C6E73F
-:102F4000F8B504461F48C56E05EB4413D3F808696D
-:102F5000C3F80869F10719D5D5F81038DA0715D57F
-:102F600000EB8403D9684B691F68DA6897421AD26C
-:102F7000D21B00271A605F6072B6202383F311888A
-:102F800062B62146FFF796FF87F31188330617D5FF
-:102F9000D5F834280123A340134211D02046BDE8C0
-:102FA000F840FFF71FBD012303FA04F2038923EA67
-:102FB000020303818B68002BE8D021469847E5E7A0
-:102FC000F8BD00BF502F01202DE9F74FA34CE66E4E
-:102FD0007569B3691D4015F48058756107D02046A6
-:102FE000FEF7BCFC03B0BDE8F04FFFF745BC002D79
-:102FF00012DAD6F8003E99489F071EBFD6F8003E69
-:1030000023F00303C6F8003ED6F8043823F001038A
-:10301000C6F80438FEF7CCFC280505D58F48FFF725
-:10302000B5FC8E48FEF7B4FCA9040CD5D6F80838D8
-:1030300013F0060FF36823F470530CBF43F41053DE
-:1030400043F4A053F3602A0704D56368DB680BB12F
-:1030500082489847EB0200F18A80AF0227D5D4F866
-:103060006C90DFF8F8B100274FF0010A09EB471226
-:10307000D2F8003B03F44023B3F5802F11D1D2F8EE
-:10308000003B002B0DDA62890AFA07F322EA0303F8
-:10309000638104EB8703DB68DB6813B1394658466C
-:1030A0009847236F01379B68FFB29F42DED9E8063D
-:1030B00018D5E76E3A6AC2F30A1002F00F0302F461
-:1030C000F012B2F5802F00F09D80B2F5402F09D1AB
-:1030D00004EB83030022DB681B6A07F580579042EC
-:1030E00040F082802B03D6F818481DD5E70302D59F
-:1030F0000020FFF78FFEA60302D50120FFF78AFE0E
-:10310000600302D50220FFF785FE210302D50320CC
-:10311000FFF780FEE20202D50420FFF77BFEA30248
-:1031200002D50520FFF776FE6F037FF55BAFE6075C
-:1031300002D50020FFF704FFA50702D50120FFF705
-:10314000FFFE600702D50220FFF7FAFE210702D535
-:103150000320FFF7F5FEE20602D50420FFF7F0FE9C
-:10316000A3067FF53FAF0520FFF7EAFE3AE7E36EDF
-:10317000DFF8E8B0019300274FF0010A236F9B6846
-:103180005FFA87F999453FF668AF019B03EB491356
-:10319000D3F8002902F44022B2F5802F22D1D3F8CF
-:1031A0000029002A1EDAD3F8002942F09042C3F821
-:1031B0000029D3F80029002AFBDBE06E4946FFF71F
-:1031C0004FFC22890AFA09F322EA0303238104EB64
-:1031D0008903DB689B6813B14946584698474846BF
-:1031E000FFF700FC0137C9E7910708BFD7F8008057
-:1031F000072A98BF03F8018B02F1010298BF4FEA3A
-:1032000018286CE7023304EB830207F580575268F5
-:10321000D2F818C0DCF80820DCE9001CA1EB0C0C8B
-:10322000002188420AD104EB830463689B699A6891
-:1032300002449A605A6802445A6053E711F0030F3F
-:1032400008BFD7F800808C4588BF02F8018B01F1D8
-:10325000010188BF4FEA1828E3E700BF502F012083
-:10326000C36E03EB4111D1F8003B43F40013C1F8E6
-:10327000003B7047C36E03EB4111D1F8003943F4B2
-:103280000013C1F800397047C36E03EB4111D1F848
-:10329000003B23F40013C1F8003B7047C36E03EBFF
-:1032A0004111D1F8003923F40013C1F800397047F7
-:1032B00000F1604303F561430901C9B283F80013CB
-:1032C000012200F01F039A4043099B0003F1604371
-:1032D00003F56143C3F880211A60704772B620235A
-:1032E00083F3118862B6704730B5039C01720433D2
-:1032F00004FB0325C0E90653049B03630021059BDF
-:10330000C160C0E90000C0E90422C0E90842C0E988
-:103310000A11436330BD0000416A0022C0E9041174
-:10332000C0E90A22C2606FF00101FEF7A3BE0000EF
-:10333000D0E90432934201D1C2680AB9181D70471E
-:103340000020704703691960C2680132C260C26917
-:10335000134482690361934224BF436A03610021DD
-:10336000FEF77CBE38B504460D46E3683BB16269A2
-:10337000131D1268A3621344E362002007E0237A5E
-:1033800033B929462046FEF759FE0028EDDA38BD4C
-:103390006FF00100FBE70000C368C269013BC36036
-:1033A0004369134482694361934224BF436A436182
-:1033B00000238362036B03B11847704770B5FFF7B2
-:1033C0008DFF866A04463EB9FFF7CCFF054618B16B
-:1033D00086F31188284670BDA36AE26A13F8015B80
-:1033E000A362934202D32046FFF7D6FF002383F364
-:1033F0001188EFE72DE9F0479846FFF76FFF0025AA
-:1034000004460E461746A946D4F828A0BAF1000F84
-:1034100009D141462046FFF7A5FF20B18AF3118864
-:103420002846BDE8F087D4E90A12A7EB050A521A2C
-:10343000924528BF9246BAF1400F1BD9334601F19D
-:10344000400251F8040B43F8040B9142F9D1A36AEE
-:1034500040334036A3624035D4E90A239A4202D36E
-:103460002046FFF799FF89F31188BD42D8D2FFF7B4
-:1034700035FFC9E730465246FDF774FCA36A534452
-:103480005644A3625544E7E710B5029C0172043329
-:1034900004FB0321C0E906130023C0E90A33039BA0
-:1034A0000363049BC460C0E90000C0E90422C0E9D2
-:1034B0000842436310BD0000026AC260426AC0E96C
-:1034C00004220022C0E90A226FF00101FEF7D2BDFA
-:1034D000D0E904239A4201D1C26822B9184650F8B3
-:1034E000043B0B607047002070470000C368C2694E
-:1034F0000133C3604369134482694361934224BF2B
-:10350000436A43610021FEF7A9BD000038B50446B7
-:103510000D46E3683BB123691A1DA262E2691344B8
-:10352000E362002007E0237A33B929462046FEF7FC
-:1035300085FD0028EDDA38BD6FF00100FBE70000E3
-:1035400003691960C268013AC260C26913448269A2
-:103550000361934224BF436A036100238362036BC8
-:1035600003B118477047000070B5FFF7B7FE866AD1
-:103570000D46044611462EB9FFF7C8FF10B186F379
-:10358000118870BDA36A1D70A36AE26A0133934279
-:10359000A36204D3E16920460439FFF7D1FF00207C
-:1035A00080F31188EDE700002DE9F0479946FFF719
-:1035B00095FE002604460D469046B246A76A4FB9CE
-:1035C00049462046FFF7A2FF20B187F31188304615
-:1035D000BDE8F087D4E90A073A1AA8EB0607974234
-:1035E00028BF1746402F1BD905F1400355F8042B7F
-:1035F00040F8042B9D42F9D1A36A4033A3624036C0
-:10360000D4E90A239A4204D3E16920460439FFF73A
-:1036100097FF8AF311884645D9D2FFF75FFECDE7C1
-:1036200029463A46FDF79EFBA36A3B443D44A3620C
-:103630003E44E5E7D0E904239A4217D1C3689BB121
-:10364000836A8BB1043B9B1A0ED01360C368013BA5
-:10365000C360C3691A44836902619A4224BF436A02
-:103660000361002383620123184670470023FBE7B0
-:1036700000F094B84FF08043002258631A61022290
-:10368000DA6070474FF080430022DA607047000034
-:103690004FF08043586370474FF08043586A70473B
-:1036A0004B6843608B688360CB68C3600B69436180
-:1036B0004B6903628B6943620B68036070470000CB
-:1036C00008B52C4B2C481A6940F2FF710A431A6165
-:1036D0001A6922F4FF6222F007021A611A691A6B52
-:1036E0000A431A631A6D0A431A65244A1B6D114670
-:1036F000FFF7D6FF02F11C0100F58060FFF7D0FF55
-:1037000002F1380100F58060FFF7CAFF02F15401B1
-:1037100000F58060FFF7C4FF02F1700100F58060E2
-:10372000FFF7BEFF02F18C0100F58060FFF7B8FFE4
-:1037300002F1A80100F58060FFF7B2FF02F1C401B9
-:1037400000F58060FFF7ACFF02F1E00100F580605A
-:10375000FFF7A6FF02F1FC0100F58060FFF7A0FF74
-:1037600002F58C7100F58060FFF79AFFBDE8084014
-:1037700000F08AB80038024000000240083E00080D
-:1037800008B500F003FAFEF7C1FBFFF727F8BDE824
-:103790000840FEF7EFBD0000704700000F4B1A6CA9
-:1037A00042F001021A641A6E42F001021A660C4AD3
-:1037B0001B6E936843F0010393604FF080436B22CC
-:1037C0009A624FF0FF32DA6200229A615A63DA603D
-:1037D0005A6001225A611A60704700BF00380240E7
-:1037E000002004E04FF0804208B51169D3680B4017
-:1037F000D9B2C9439B07116109D572B6202383F35F
-:10380000118862B6FEF7A2FB002383F3118808BD7E
-:103810001B4B1A696FEA42526FEA52521A611A69D7
-:10382000C2F30A021A614FF0FF301A695A695861EF
-:1038300000215A6959615A691A6A62F080521A6203
-:103840001A6A02F080521A621A6A5A6A58625A6AEE
-:1038500059625A6A0B4A106840F480701060186F01
-:1038600000F44070B0F5007F1EBF4FF48030186741
-:103870001967536823F40073536000F05FB900BF09
-:103880000038024000700040374B4FF080521A64FD
-:10389000364A4FF4404111601A6842F001021A6042
-:1038A0001A689207FCD59A6822F003029A602E4BA0
-:1038B0009A6812F00C02FBD1196801F0F901196045
-:1038C0009A601A6842F480321A601A689003FCD534
-:1038D0005A6F42F001025A67234B5A6F9107FCD589
-:1038E000234A5A601A6842F080721A601F4B5A6865
-:1038F0005204FCD51A6842F480321A605A68D00328
-:10390000FCD51A6842F400321A60184A53689903C9
-:10391000FCD5154B1A689201FCD5164A9A6040F204
-:103920000112C3F88C200022C3F89020124A40F202
-:1039300007331360136803F00F03072BFAD10A4B08
-:103940009A6842F002029A609A6802F00C02082A11
-:10395000FAD15A6C42F480425A645A6E42F4804260
-:103960005A665B6E704700BF00380240007000402E
-:10397000086C400900948838003C0240074A08B5AA
-:10398000536903F00103536123B1054A13680BB176
-:1039900050689847BDE80840FEF76EBF003C014004
-:1039A000E02F0120074A08B5536903F00203536171
-:1039B00023B1054A93680BB1D0689847BDE8084029
-:1039C000FEF75ABF003C0140E02F0120074A08B52E
-:1039D000536903F00403536123B1054A13690BB122
-:1039E00050699847BDE80840FEF746BF003C0140DB
-:1039F000E02F0120074A08B5536903F0080353611B
-:103A000023B1054A93690BB1D0699847BDE80840D6
-:103A1000FEF732BF003C0140E02F0120074A08B505
-:103A2000536903F01003536123B1054A136A0BB1C4
-:103A3000506A9847BDE80840FEF71EBF003C0140B1
-:103A4000E02F0120164B10B55C6904F478725A61BE
-:103A5000A30604D5134A936A0BB1D06A984760064F
-:103A600004D5104A136B0BB1506B9847210604D54F
-:103A70000C4A936B0BB1D06B9847E20504D5094A09
-:103A8000136C0BB1506C9847A30504D5054A936C91
-:103A90000BB1D06C9847BDE81040FEF7EDBE00BFFB
-:103AA000003C0140E02F0120194B10B55C6904F483
-:103AB0007C425A61620504D5164A136D0BB1506DF4
-:103AC0009847230504D5134A936D0BB1D06D9847E1
-:103AD000E00404D50F4A136E0BB1506E9847A10451
-:103AE00004D50C4A936E0BB1D06E9847620404D58E
-:103AF000084A136F0BB1506F9847230404D5054A49
-:103B0000936F0BB1D06F9847BDE81040FEF7B4BE7D
-:103B1000003C0140E02F012008B50348FDF7C8FA3A
-:103B2000BDE80840FEF7A8BEDC23012008B5FFF77A
-:103B300059FEBDE80840FEF79FBE0000062108B50B
-:103B40000846FFF7B5FB06210720FFF7B1FB06216A
-:103B50000820FFF7ADFB06210920FFF7A9FB06218E
-:103B60000A20FFF7A5FB06211720FFF7A1FB06217E
-:103B70002820FFF79DFB07211C20FFF799FBBDE8DC
-:103B800008400C212520FFF793BB000008B5FFF784
-:103B90003FFE00F00DF8FDF797FCFDF771FEFDF715
-:103BA00043FDFFF7F9FDBDE80840FFF761BD0000E8
-:103BB0000023054A19460133102BC2E9001102F116
-:103BC0000802F8D1704700BFE02F0120034611F82A
-:103BD000012B03F8012B002AF9D1704753544D33C0
-:103BE00032463F3F3F3F3F3F0053544D333246370D
-:103BF0005B347C355D780053544D333246375B3649
-:103C00007C375D7800000000009600000000000096
-:103C100000000000000000000000000000000000A4
-:103C200000000000911400087D140008B914000879
-:103C3000A5140008B11400089D1400088914000898
-:103C400075140008C514000800000000A515000840
-:103C500091150008CD150008B9150008C515000814
-:103C6000B11500089D15000889150008D915000830
-:103C70000000000001000000000000006D61696E9E
-:103C80000000000069646C6500000000843C0008CE
-:103C9000882601200028012001000000091F0008DB
-:103CA000000000004172647550696C6F7400254219
-:103CB0004F415244252D424C002553455249414C19
-:103CC000250000000200000000000000C1170008ED
-:103CD0002D18000840004000982C0120A82C01203D
-:103CE00002000000000000000300000000000000CF
-:103CF000711800080000000010000000B82C01201E
-:103D0000000000000100000000000000502F012012
-:103D1000010102001523000829220008C122000821
-:103D2000A9220008430000002C3D000809024300BE
-:103D3000020100C032090400000102020100052452
-:103D400000100105240100010424020205240600DC
-:103D500001070582030800FF09040100020A0000B0
-:103D60000007050102400000070581024000000035
-:103D700012000000783D000812011001020000400E
-:103D80000912415700020102030100000403090463
-:103D900025424F4152442500466C79776F6F463774
-:103DA00034357632003031323334353637383941B4
-:103DB00042434445460000000080000000800000AF
-:103DC00000800000008000000000020000000400ED
-:103DD000000004000000040000000000C5190008F5
-:103DE000751C00081D1D000840004000C82F012060
-:103DF000C82F012001000000D82F01208000000002
-:103E000040010000050000000001A82A0000000099
-:103E1000AAAAAAAA00011424FFFF000000000000C3
-:103E200070A70A000000000100000000AAAAAAAAC8
-:103E300000000001FFFF0000000000000000000083
-:103E40000000000400000000AAAAAAAA00000000C6
-:103E5000FFDF000000000000000000000000000084
-:103E600000000000AAAAAAAA00000000FFFF0000AC
-:103E70000000000000000000000100000000000041
-:103E8000AAAAAAAA00010000FFFF0000000000008B
-:103E9000000000000000000000000000AAAAAAAA7A
-:103EA00000000000FFFF0000000000000000000014
-:103EB0000000000000000000AAAAAAAA000000005A
-:103EC000FFFF0000000000000000000000000000F4
-:103ED000000000000A0000000000000003000000D5
-:103EE00000000000000000000000000000000000D2
-:103EF00000000000000000000000000000000000C2
-:103F000000000000000000000000000000000000B1
-:103F100000000000000000000000000000000000A1
-:103F20000000000000000000000000000000000091
-:103F30000000000000000000000000000000000081
-:103F4000030400000000000000800E0000000000DC
-:103F5000FF00000000280120DC23012000000000F9
-:103F6000DC3B00083F00000049040000E93B00087A
-:103F70003F00000051040000F73B00083F00000034
-:103F800000960000000008009600000000080000F5
-:103F9000040000008C3D000800000000000000004C
-:103FA0000000000000000000000000000000000011
-:00000001FF
diff --git a/Tools/bootloaders/G4-ESC_bl.bin b/Tools/bootloaders/G4-ESC_bl.bin
new file mode 100755
index 00000000000000..a74d693052b40f
Binary files /dev/null and b/Tools/bootloaders/G4-ESC_bl.bin differ
diff --git a/Tools/bootloaders/HEEWING-F405_bl.bin b/Tools/bootloaders/HEEWING-F405_bl.bin
new file mode 100644
index 00000000000000..2968e956648df0
Binary files /dev/null and b/Tools/bootloaders/HEEWING-F405_bl.bin differ
diff --git a/Tools/bootloaders/HEEWING-F405_bl.hex b/Tools/bootloaders/HEEWING-F405_bl.hex
new file mode 100644
index 00000000000000..77446fa70fcbcf
--- /dev/null
+++ b/Tools/bootloaders/HEEWING-F405_bl.hex
@@ -0,0 +1,1008 @@
+:020000040800F2
+:1000000000060020E1010008E3010008E301000808
+:10001000E3010008E3010008E3010008E301000830
+:10002000E3010008E3010008E301000821360008AD
+:10003000E3010008E3010008E3010008E301000810
+:10004000E3010008E3010008E3010008E301000800
+:10005000E3010008E3010008C9380008F13800088E
+:10006000193900084139000869390008E30100081E
+:10007000E3010008E3010008E3010008E3010008D0
+:10008000E3010008E3010008E3010008E3010008C0
+:10009000E3010008E3010008E301000891390008CA
+:1000A000E3010008E3010008E3010008E3010008A0
+:1000B000793A0008E3010008E3010008E3010008C1
+:1000C000E3010008E3010008E3010008E301000880
+:1000D000E3010008653A0008E3010008E3010008B5
+:1000E000F5390008E3010008E3010008E301000816
+:1000F000E3010008E3010008E3010008E301000850
+:10010000E3010008E3010008E3010008E30100083F
+:10011000E3010008E3010008E3010008E30100082F
+:10012000E3010008E3010008E3010008E30100081F
+:10013000E3010008E3010008E3010008E30100080F
+:10014000E3010008E3010008E3010008D52D0008E1
+:10015000E3010008E3010008E3010008E3010008EF
+:10016000E3010008E3010008E3010008E3010008DF
+:10017000E3010008E3010008E3010008E3010008CF
+:10018000E3010008E3010008E3010008E3010008BF
+:10019000E3010008E3010008E3010008E3010008AF
+:1001A000E3010008E3010008E3010008E30100089F
+:1001B000E3010008E3010008E3010008E30100088F
+:1001C000E3010008E3010008E3010008E30100087F
+:1001D000E3010008E3010008E3010008E30100086F
+:1001E00002E000F000F8FEE772B6374880F30888B6
+:1001F000364880F3098836483649086040F20000E6
+:10020000CCF200004EF63471CEF200010860BFF36C
+:100210004F8FBFF36F8F40F20000C0F2F0004EF638
+:100220008851CEF200010860BFF34F8FBFF36F8F8C
+:100230004FF00000E1EE100A4EF63C71CEF20001E4
+:100240000860062080F31488BFF36F8F02F08AFAEB
+:1002500003F084F94FF055301F491B4A91423CBFCF
+:1002600041F8040BFAE71D49184A91423CBF41F896
+:10027000040BFAE71A491B4A1B4B9A423EBF51F83E
+:10028000040B42F8040BF8E700201849184A914281
+:100290003CBF41F8040BFAE702F068FA03F0B2F948
+:1002A000144C154DAC4203DA54F8041B8847F9E7A7
+:1002B00000F042F8114C124DAC4203DA54F8041B22
+:1002C0008847F9E702F050BA00060020002200201B
+:1002D0000000000808ED00E00000002000060020FB
+:1002E000883E0008002200204C22002050220020DE
+:1002F000F0300020E0010008E0010008E001000803
+:10030000E00100082DE9F04F2DED108AC1F80CD066
+:10031000C3689D46BDEC108ABDE8F08F002383F3CF
+:1003200011882846A047002001F0B8FDFEE701F043
+:1003300021FD00DFFEE7000038B502F0E3F90546D5
+:1003400002F006FA0446D8B90F4B9D421AD0013389
+:100350009D4218BF044641F2883504BF01240025A0
+:10036000002002F0D9F90CB100F076F800F016FD8B
+:1003700000F0B0FB284600F0B9F800F06DF8F9E79E
+:100380000025EDE70546EBE7010007B008B500F0F2
+:100390006DFBA0F120035842584108BD07B541F25A
+:1003A0001203022101A8ADF8043000F07DFB03B078
+:1003B0005DF804FB38B5302383F3118817480368D0
+:1003C0000BB101F037FE164A144800234FF47A713E
+:1003D00001F026FE002383F31188124C236813B129
+:1003E0002368013B2360636813B16368013B63606A
+:1003F0000D4D2B7833B963687BB9022000F040FCC7
+:10040000322363602B78032B07D163682BB902205A
+:1004100000F036FC4FF47A73636038BD5022002040
+:10042000B50300087023002068220020084B1870D4
+:1004300003280CD8DFE800F008050208022000F0CD
+:100440000FBC022000F0FCBB024B00225A60704738
+:1004500068220020702300201F4B204A10B51C4644
+:100460001968013137D004339342F9D162681C4BCB
+:100470009A4230D91B4B9B6803F1006303F580332C
+:100480009A4228D2002000F03FFB0220FFF7CEFF67
+:10049000154B1A6C00221A64196E1A66196E596C83
+:1004A0005A64596E5A665A6E1A6942F000521A61BD
+:1004B0001A6922F000521A611B6972B64FF0E023EC
+:1004C0003021C3F8084DD4E9003281F311889D46EC
+:1004D00083F30888104710BD0000010820000108C0
+:1004E000FFFF000800220020003802402DE9F04FF5
+:1004F00093B0AA4B00902022FF210AA89D6800F02B
+:10050000F7FBA74A1378A3B9A6480121036011702D
+:10051000302383F3118803680BB101F08BFDA24AED
+:10052000A04800234FF47A7101F07AFD002383F391
+:100530001188009B13B19D4B009A1A609C4A009C45
+:100540001378032B1EBF00231370984A4FF0000A44
+:1005500018BF5360D3465646D146012000F080FBB9
+:1005600024B1924B1B68002B00F01182002000F098
+:100570007DFA0390039B002BF2DB012000F060FB6F
+:10058000039B213B162BE8D801A252F823F000BFB1
+:10059000ED05000815060008A90600085B0500081F
+:1005A0005B0500085B050008330700080309000825
+:1005B0001D0800087F080008A7080008CD080008EB
+:1005C0005B050008DF0800085B050008510900080A
+:1005D0008D0600085B05000895090008F90500086C
+:1005E0008D0600085B0500087F0800080220FFF761
+:1005F000CDFE002840F0F581009B0221BAF1000FEA
+:1006000008BF1C4605A841F21233ADF8143000F0C3
+:100610004BFAA2E74FF47A7000F028FA071EEBDBE2
+:100620000220FFF7B3FE0028E6D0013F052F00F2BD
+:10063000DA81DFE807F0030A0D101336052305936E
+:10064000042105A800F030FA17E054480421F9E726
+:1006500058480421F6E758480421F3E74FF01C08F6
+:10066000404600F053FA08F104080590042105A85B
+:1006700000F01AFAB8F12C0FF2D1012000FA07F7B6
+:1006800047EA0B0B5FFA8BFB4FF0000900F07CFB95
+:1006900026B10BF00B030B2B08BF0024FFF77EFEE7
+:1006A0005BE746480421CDE7002EA5D00BF00B03F5
+:1006B0000B2BA1D10220FFF769FE074600289BD033
+:1006C000012000F021FA0220FFF7B0FE00265FFAB9
+:1006D00086F8404600F028FA044690B100214046D2
+:1006E00000F032FA01360028F1D1BA46044641F250
+:1006F0001213022105A8ADF814303E4600F0D4F9DB
+:100700002BE70120FFF792FE2546244B9B68AB4266
+:1007100007D9284600F0FAF9013040F06781043526
+:10072000F3E7234B00251D70204BBA465D603E4623
+:10073000ACE7002E3FF460AF0BF00B030B2B7FF404
+:100740005BAF0220FFF772FE322000F08FF9B0F1AC
+:100750000008FFF651AF18F003077FF44DAF0F4AC2
+:10076000926808EB050393423FF646AFB8F5807FE9
+:100770003FF742AF124B0193B84523DD4FF47A7037
+:1007800000F074F90390039A002AFFF635AF019B3D
+:10079000039A03F8012B0137EDE700BF0022002088
+:1007A0006C23002050220020B50300087023002095
+:1007B0006822002004220020082200200C220020B1
+:1007C0006C220020C820FFF7E1FD074600283FF417
+:1007D00013AF1F2D11D8C5F1200242450AAB25F0F9
+:1007E000030028BF424683490192184400F05AFA98
+:1007F000019A8048FF2100F07BFA4FEAA8037D4967
+:100800000193C8F38702284600F07AFA06460028CA
+:100810003FF46DAF019B05EB830537E70220FFF73F
+:10082000B5FD00283FF4E8AE00F0BAF900283FF427
+:10083000E3AE0027B846704B9B68BB4218D91F2F08
+:1008400011D80A9B01330ED027F0030312AA1344D8
+:1008500053F8203C05934046042205A900F000FB14
+:1008600004378046E7E7384600F050F90590F2E794
+:10087000CDF81480042105A800F016F906E700233E
+:10088000642104A8049300F005F900287FF4B4AEB5
+:100890000220FFF77BFD00283FF4AEAE049800F085
+:1008A00067F90590E6E70023642104A8049300F0AB
+:1008B000F1F800287FF4A0AE0220FFF767FD0028C2
+:1008C0003FF49AAE049800F063F9EAE70220FFF7DC
+:1008D0005DFD00283FF490AE00F072F9E1E70220E0
+:1008E000FFF754FD00283FF487AE05A9142000F05F
+:1008F0006DF904210746049004A800F0D5F83946A4
+:10090000B9E7322000F0B2F8071EFFF675AEBB075C
+:100910007FF472AE384A926807EB090393423FF6C0
+:100920006BAE0220FFF732FD00283FF465AE27F0E2
+:1009300003074F44B9453FF4A9AE484600F0E6F836
+:100940000421059005A800F0AFF809F10409F1E7CA
+:100950004FF47A70FFF71AFD00283FF44DAE00F017
+:100960001FF9002844D00A9B01330BD008220AA9A2
+:10097000002000F0C5F900283AD02022FF210AA863
+:1009800000F0B6F9FFF70AFD1C4801F08DFA13B02C
+:10099000BDE8F08F002E3FF42FAE0BF00B030B2BB6
+:1009A0007FF42AAE0023642105A8059300F072F8B5
+:1009B000074600287FF420AE0220FFF7E7FC8046C0
+:1009C00000283FF419AEFFF7E9FC41F2883001F04E
+:1009D0006BFA059800F022FA464600F0D5F93C463D
+:1009E000BBE5064652E64FF0000905E6BA467EE64C
+:1009F00037467CE66C22002000220020A086010001
+:100A00002DE9F84F4FF47A73DFF85880DFF85890EB
+:100A100006460D4602FB03F7002498F900305A1CE5
+:100A20005FFA84FA01D0A34212D159F82400036876
+:100A30002A46D3F820B031463B46D847854207D1F5
+:100A4000074B012083F800A0BDE8F88F0124E4E7FC
+:100A5000002CFBD04FF4FA7001F026FA0020F3E7E7
+:100A6000B8230020102200201422002007B5002304
+:100A7000024601210DF107008DF80730FFF7C0FF96
+:100A800020B19DF8070003B05DF804FB4FF0FF3084
+:100A9000F9E700000A4608B50421FFF7B1FF80F02E
+:100AA0000100C0B2404208BD30B4074B0A46197875
+:100AB000064B53F821402368DD69054B0146AC46DF
+:100AC000204630BC604700BFB8230020142200201D
+:100AD000A086010070B501F007FD094E094D308078
+:100AE000002428683388834208D901F0F7FC2B687A
+:100AF00004440133B4F5803F2B60F2D370BD00BFD6
+:100B0000BA2300207823002001F0B0BD00F100607E
+:100B100000F580300068704700F10060920000F539
+:100B2000803001F02FBD0000054B1A68054B1B8873
+:100B30009B1A834202D9104401F0D0BC00207047B8
+:100B400078230020BA23002038B5084D044629B187
+:100B500028682044BDE8384001F0E0BC2868204403
+:100B600001F0C4FC0028F3D038BD00BF782300207A
+:100B700010F003030AD1B0F5047F05D200F1005054
+:100B8000A0F51040D0F80038184670470023FBE766
+:100B900000F10050A0F51040D0F8100A7047000096
+:100BA000064991F8243033B10023086A81F82430D3
+:100BB0000822FFF7B1BF0120704700BF7C2300204F
+:100BC000014B1868704700BF002004E070B5194B56
+:100BD0001D68194B0138C5F30B0408442D0C042281
+:100BE0001E88A6420BD15C680A46013C824213462D
+:100BF0000FD214F9016F4EB102F8016BF6E7013A1A
+:100C000003F10803ECD181420B4602D22C2203F8F7
+:100C1000012B0A4A05241688AE4204D1984284BFAB
+:100C2000967803F8016B013C02F10402F3D1581AE3
+:100C300070BD00BF002004E0683B0008543B000882
+:100C4000022804D1054B4FF000529A6170470128E9
+:100C5000FCD1024B4FF00042F7E700BF0008024012
+:100C6000022804D1054B4FF400529A6170470128C5
+:100C7000FCD1024B4FF40042F7E700BF00080240EE
+:100C8000022805D1064A536983F400535361704723
+:100C90000128FCD1024A536983F40043F6E700BF00
+:100CA0000008024010B50023934203D0CC5CC4542A
+:100CB0000133F9E710BD000010B5013810F9013F0C
+:100CC0003BB191F900409C4203D11AB10131013A84
+:100CD000F4E71AB191F90020981A10BD1046FCE70C
+:100CE00003460246D01A12F9011B0029FAD17047B7
+:100CF00002440346934202D003F8011BFAE770470F
+:100D00002DE9F8431F4D144695F8242007468846E0
+:100D100052BBDFF870909CB395F824302BB9202299
+:100D2000FF2148462F62FFF7E3FF95F82400C0F14A
+:100D30000802A24228BF2246D6B24146920005EBE5
+:100D40008000FFF7AFFF95F82430A41B1E44F6B2D5
+:100D5000082E17449044E4B285F82460DBD1FFF7F5
+:100D60001FFF0028D7D108E02B6A03EB82038342E0
+:100D7000CFD0FFF715FF0028CBD10020BDE8F883C6
+:100D80000120FBE77C230020024B1A78024B1A70EB
+:100D9000704700BFB82300201022002038B5194C3E
+:100DA000194D204600F0C0FB2946204600F0E8FB24
+:100DB0002D6816486A6DD2F8043843F00203C2F871
+:100DC000043801F071F81249284600F0DFFC6A6D22
+:100DD000104DD2F8043828680F4923F00203C2F8F6
+:100DE0000438A0424FF4E1330B6001D000F0FCFA6C
+:100DF0006868A04204D0BDE83840074900F0F4BA62
+:100E000038BD00BF98280020703C000840420F0009
+:100E1000783C000814220020A423002070B50C4B5D
+:100E20000C4D1E780C4B55F826209A4204460DD0E6
+:100E30000A4B002114221846FFF75AFF04600146AE
+:100E400055F82600BDE8704000F0CEBA70BD00BF76
+:100E5000B82300201422002098280020A42300207A
+:100E600030B5094D0A4491420DD011F8013B58406C
+:100E7000082340F30004013B2C4013F0FF0384EAF5
+:100E80005000F6D1EFE730BD2083B8ED026843682B
+:100E90001143016003B1184770470000024AD3684C
+:100EA00043F0C003D36070470010014010B5084CF8
+:100EB000084A0021204600F075FA074BC4F85C325E
+:100EC00003F1454303F52D43C4F8603210BD00BF64
+:100ED000BC2300209D0E000800100140234A037C23
+:100EE000002918BF0A46012B30B5C0F868220CD182
+:100EF0001F4B984209D11F4B596C41F010015964A6
+:100F0000596E41F0100159665B6EB2F904501468D5
+:100F1000D0F86032D0F85C12002D03EB5403B3FB21
+:100F2000F4F3BEBF23F0070503F0070343EA4503CC
+:100F300094888B60D38843F040030B61138943F09E
+:100F400001034B6144F4045343F02C03CB6004F4DD
+:100F5000A05400230B60B4F5806F0B684B680CBF86
+:100F60007F23FF2380F8643230BD00BF883B000838
+:100F7000BC230020003802402DE9F041D0F85C622B
+:100F8000F7683368DA0504469DB20DD5302383F344
+:100F900011884FF480610430FFF778FF6FF480739D
+:100FA0003360002383F31188302383F3118804F125
+:100FB000040815F02F033AD183F31188380615D5AC
+:100FC000290613D5302383F3118804F1380000F08B
+:100FD00065F900284EDA0821201DFFF757FF4FF66C
+:100FE0007F733B40F360002383F311887A0616D5A4
+:100FF0006B0614D5302383F31188D4E913239A4266
+:101000000AD1236C43B127F040073F041021201D73
+:101010003F0CFFF73BFFF760002383F31188D4F800
+:101020006822D36843B3BDE8F041106918472B0725
+:1010300014D015F0080F0CBF00214FF48071E807A1
+:1010400048BF41F02001AA0748BF41F040016B07AB
+:1010500048BF41F080014046FFF718FFAD067368B6
+:1010600005D594F864122046194000F0CBF9356894
+:10107000ADB29EE77060B6E7BDE8F081F8B5154601
+:1010800082680669AA420B46816938BF8568761A6C
+:10109000B54204460BD218462A46FFF703FEA36961
+:1010A0002B44A361A3685B1BA3602846F8BD0CD941
+:1010B00018463246FFF7F6FDAF1BE1683A4630446A
+:1010C000FFF7F0FDE3683B44EBE718462A46FFF7DD
+:1010D000E9FDE368E5E7000083689342F7B515464C
+:1010E000044638BF8568D0E90460361AB5420BD291
+:1010F0002A46FFF7D7FD63692B446361A36828463E
+:101100005B1BA36003B0F0BD0DD932460191FFF720
+:10111000C9FD0199E068AF1B3A463144FFF7C2FDB3
+:10112000E3683B44E9E72A46FFF7BCFDE368E4E7F0
+:1011300010B50A440024C361029B8460C0E900002A
+:10114000C0E90511C1600261036210BD08B5D0E9B4
+:101150000532934201D1826882B98268013282608D
+:101160005A1C42611970D0E904329A4224BFC36804
+:101170004361002100F0B4FE002008BD4FF0FF30B5
+:10118000FBE7000070B5302304460E4683F3118858
+:10119000A568A5B1A368A269013BA360531CA36124
+:1011A00015782269934224BFE368A361E3690BB118
+:1011B00020469847002383F31188284607E03146EC
+:1011C000204600F07DFE0028E2DA85F3118870BD2C
+:1011D0002DE9F74F04460E4617469846D0F81C9066
+:1011E0004FF0300A8AF311884FF0000B154665B1B5
+:1011F0002A4631462046FFF741FF034660B9414683
+:10120000204600F05DFE0028F1D0002383F3118812
+:10121000781B03B0BDE8F08FB9F1000F03D0019047
+:101220002046C847019B8BF31188ED1A1E448AF3B0
+:101230001188DCE7C0E90511C160C3611144009B5E
+:101240008260C0E90000016103627047F8B504469E
+:101250000D461646302383F31188A768A7B1A3680B
+:10126000013BA36063695A1C62611D70D4E90432BA
+:101270009A4224BFE3686361E3690BB12046984753
+:10128000002080F3118807E03146204600F018FE68
+:101290000028E2DA87F31188F8BD0000D0E90523C1
+:1012A0009A4210B501D182687AB9826801328260AF
+:1012B0005A1C82611C7803699A4224BFC368836107
+:1012C000002100F00DFE204610BD4FF0FF30FBE77F
+:1012D0002DE9F74F04460E4617469846D0F81C9065
+:1012E0004FF0300A8AF311884FF0000B154665B1B4
+:1012F0002A4631462046FFF7EFFE034660B94146D5
+:10130000204600F0DDFD0028F1D0002383F3118892
+:10131000781B03B0BDE8F08FB9F1000F03D0019046
+:101320002046C847019B8BF31188ED1A1E448AF3AF
+:101330001188DCE7026843681143016003B1184774
+:10134000704700001430FFF743BF00004FF0FF3339
+:101350001430FFF73DBF00003830FFF7B9BF000081
+:101360004FF0FF333830FFF7B3BF00001430FFF702
+:1013700009BF00004FF0FF311430FFF703BF00003A
+:101380003830FFF763BF00004FF0FF323830FFF70F
+:101390005DBF0000012914BF6FF0130000207047EB
+:1013A000FFF784BD37B515460E4A02600022426041
+:1013B000C0E902220122044602740B46009000F1AB
+:1013C0005C014FF480721430FFF7B2FE00942B469C
+:1013D0004FF4807204F5AE7104F13800FFF72AFF74
+:1013E00003B030BD9C3B000810B53023044683F3A6
+:1013F0001188FFF773FD02232374002080F3118806
+:1014000010BD000038B5C36904460D461BB9042160
+:101410000844FFF78FFF294604F11400FFF796FEFA
+:10142000002806DA201D4FF40061BDE83840FFF7C0
+:1014300081BF38BD026843681143016003B118479A
+:101440007047000013B5446BD4F894341A681178CF
+:10145000042915D1217C022912D11979128901237D
+:101460008B4013420CD101A904F14C0001F032FF72
+:10147000D4F89444019B21790246206800F0D0F909
+:1014800002B010BD143001F0B5BE00004FF0FF33C4
+:10149000143001F0AFBE00004C3001F087BF0000F7
+:1014A0004FF0FF334C3001F081BF0000143001F0E9
+:1014B00083BE00004FF0FF31143001F07DBE00000C
+:1014C0004C3001F053BF00004FF0FF324C3001F0C0
+:1014D0004DBF00000020704710B5D0F894341A6852
+:1014E00011780429044617D1017C022914D15979B5
+:1014F000528901238B4013420ED1143001F016FEA5
+:10150000024648B1D4F894444FF48073617920685E
+:10151000BDE8104000F072B910BD0000406BFFF74D
+:10152000DBBF0000704700007FB5124B0360002353
+:101530004360C0E90233012502260F4B05740446BF
+:101540000290019300F18402294600964FF48073C3
+:10155000143001F0C7FD094B0294CDE9006304F596
+:1015600023724FF48073294604F14C0001F08EFE83
+:1015700004B070BDC43B00081D15000845140008E8
+:101580000B68302282F311880A7903EB82029061A2
+:101590004A79093243F822008A7912B103EB8203B7
+:1015A00098610223C0F894140374002080F311881A
+:1015B0007047000038B5037F044613B190F85430EB
+:1015C000ABB9201D01250221FFF734FF04F11400FF
+:1015D00025776FF0010100F08FFC84F8545004F17E
+:1015E0004C006FF00101BDE8384000F085BC38BD0B
+:1015F00010B5012104460430FFF71CFF00232377B8
+:1016000084F8543010BD000038B50446002514306D
+:1016100001F080FD04F14C00257701F04FFE201D04
+:1016200084F854500121FFF705FF2046BDE83840FB
+:10163000FFF752BF90F8443003F06003202B07D12E
+:1016400090F84520212A4FF0000303D81F2A06D81E
+:1016500000207047222AFBD1C0E90E3303E0034A81
+:1016600082630722C2630364012070471C220020AA
+:1016700037B5D0F894341A681178042904461AD181
+:10168000017C022917D11979128901238B40134259
+:1016900011D100F14C05284601F0D0FE58B101A946
+:1016A000284601F017FED4F89444019B21790246A4
+:1016B000206800F0B5F803B030BD0000F0B500EBD5
+:1016C000810385B09E6904460D46FEB1302383F345
+:1016D000118804EB8507301D0821FFF7ABFEFB687E
+:1016E0005B691B6806F14C001BB1019001F000FE24
+:1016F000019803A901F0EEFD024648B1039B29467B
+:10170000204600F08DF8002383F3118805B0F0BD6A
+:10171000FB685A691268002AF5D01B8A013B134006
+:10172000F1D104F14402EAE7093138B550F821401B
+:10173000DCB1302383F31188D4F8942413685279F0
+:1017400003EB8203DB689B695D6845B10421601887
+:10175000FFF770FE294604F1140001F0F1FC204669
+:10176000FFF7BAFE002383F3118838BD70470000ED
+:1017700001F050B8012303700023C0E90133C361B5
+:1017800083620362C36243620363704738B50446F1
+:10179000302383F311880025C0E90355C0E90555BE
+:1017A000416001F047F80223237085F31188284631
+:1017B00038BD000070B500EB810305465069DA6062
+:1017C0000E46144618B110220021FFF791FAA069C5
+:1017D00018B110220021FFF78BFA31462846BDE8E8
+:1017E000704001F0F1B80000826802F001128260DE
+:1017F0000022C0E90422826101F072B9F0B400EB6A
+:1018000081044789E4680125A4698D403D434581F1
+:1018100023600023A2606360F0BC01F08DB900007A
+:10182000F0B400EB81040789E468012564698D4008
+:101830003D43058123600023A2606360F0BC01F09A
+:1018400007BA000070B50223002504460370C0E902
+:101850000255C0E90455C564856180F8345001F033
+:101860004FF863681B6823B129462046BDE87040E5
+:10187000184770BD0378052B10B504460AD080F8D0
+:1018800050300523037043681B680BB1042198474F
+:101890000023A36010BD00000178052906D190F84F
+:1018A0005020436802701B6803B11847704700005E
+:1018B00070B590F83430044613B1002380F834300A
+:1018C00004F14402204601F02DF963689B68B3B926
+:1018D00094F8443013F0600535D00021204601F023
+:1018E000CDFB0021204601F0BFFB63681B6813B1EC
+:1018F000062120469847062384F8343070BD2046E0
+:1019000098470028E4D0B4F84A30E26B9A4288BF86
+:10191000E36394F94430E56B002B4FF0300380F221
+:101920000381002D00F0F280092284F8342083F333
+:1019300011880021D4E90E232046FFF771FF002310
+:1019400083F31188DAE794F8452003F07F0343EA34
+:10195000022340F20232934200F0C58021D8B3F551
+:10196000807F48D00DD8012B3FD0022B00F0938010
+:10197000002BB2D104F14C02A2630222E263236481
+:10198000C1E7B3F5817F00F09B80B3F5407FA4D120
+:1019900094F84630012BA0D1B4F84C3043F0020348
+:1019A00032E0B3F5006F4DD017D8B3F5A06F31D04A
+:1019B000A3F5C063012B90D8636894F846205E6855
+:1019C00094F84710B4F848302046B047002884D037
+:1019D0004368A3630368E3631AE0B3F5106F36D07E
+:1019E00040F6024293427FF478AF5C4BA36302233C
+:1019F000E3630023C3E794F84630012B7FF46DAF17
+:101A0000B4F84C3023F00203C4E90E55A4F84C306E
+:101A1000256478E7B4F84430B3F5A06F0ED194F89C
+:101A2000463084F84E30204600F0C2FF63681B68E1
+:101A300013B1012120469847032323700023C4E9F2
+:101A40000E339CE704F14F03A3630123C3E723781C
+:101A5000042B10D1302383F311882046FFF7C4FEF6
+:101A600085F311880321636884F84F5021701B6847
+:101A70000BB12046984794F84630002BDED084F80E
+:101A80004F300423237063681B68002BD6D00221DB
+:101A900020469847D2E794F848301D0603F00F011E
+:101AA00020460AD501F030F8012804D002287FF43E
+:101AB00014AF2B4B9AE72B4B98E701F017F8F3E79D
+:101AC00094F84630002B7FF408AF94F8483013F0B8
+:101AD0000F01B3D01A06204602D501F0E3FAADE7B4
+:101AE00001F0D6FAAAE794F84630002B7FF4F5AE61
+:101AF00094F8483013F00F01A0D01B06204602D501
+:101B000001F0BCFA9AE701F0AFFA97E7142284F8E3
+:101B1000342083F311882B462A4629462046FFF7B6
+:101B20006DFE85F31188E9E65DB1152284F8342055
+:101B300083F311880021D4E90E232046FFF75EFECF
+:101B4000FDE60B2284F8342083F311882B462A46C5
+:101B500029462046FFF764FEE3E700BFF43B000898
+:101B6000EC3B0008F03B000838B590F834300446F0
+:101B7000002B3ED0063BDAB20F2A34D80F2B32D8D6
+:101B8000DFE803F037313108223231313131313180
+:101B900031313737C56BB0F84A309D4214D2C36833
+:101BA0001B8AB5FBF3F203FB12556DB9302383F3A7
+:101BB00011882B462A462946FFF732FE85F3118805
+:101BC0000A2384F834300EE0142384F834303023B0
+:101BD00083F3118800231A4619462046FFF70EFEAC
+:101BE000002383F3118838BD036C03B198470023A9
+:101BF000E7E70021204601F041FA0021204601F0EC
+:101C000033FA63681B6813B1062120469847062300
+:101C1000D7E7000010B590F83430142B044629D0D3
+:101C200017D8062B05D001D81BB110BD093B022BDC
+:101C3000FBD80021204601F021FA0021204601F0C6
+:101C400013FA63681B6813B10621204698470623E0
+:101C500019E0152BE9D10B2380F83430302383F3BE
+:101C6000118800231A461946FFF7DAFD002383F393
+:101C70001188DAE7C3689B695B68002BD5D1036CD8
+:101C800003B19847002384F83430CEE7002303756E
+:101C9000826803691B6899689142FBD25A680360A5
+:101CA00042601060586070470023037582680369C2
+:101CB0001B6899689142FBD85A68036042601060C3
+:101CC0005860704708B50846302383F311880B7DB0
+:101CD000032B05D0042B0DD02BB983F3118808BD3D
+:101CE0008B6900221A604FF0FF338361FFF7CEFF4C
+:101CF0000023F2E7D1E9003213605A60F3E70000F5
+:101D0000FFF7C4BF054BD9680875186802681A60E8
+:101D1000536001220275D860FEF7F4BA282600202D
+:101D200030B50C4BDD684B1C87B004460FD02B46FA
+:101D3000094A684600F074F92046FFF7E3FF009B6C
+:101D400013B1684600F076F9A86907B030BDFFF717
+:101D5000D9FFF9E728260020C51C0008044B1A68A3
+:101D6000DB6890689B68984294BF00200120704710
+:101D700028260020084B10B51C68D86822681A6015
+:101D8000536001222275DC60FFF78EFF014620467A
+:101D9000BDE81040FEF7B6BA28260020044B1A68AA
+:101DA000DB6892689B689A4201D9FFF7E3BF7047EE
+:101DB0002826002038B5074C07490848012300258C
+:101DC0002370656001F072FB0223237085F3118894
+:101DD00038BD00BF90280020FC3B000828260020CA
+:101DE00000F05EB9EFF3118020B9EFF305833022E4
+:101DF00082F311887047000010B530B9EFF3058405
+:101E0000C4F3080414B180F3118810BDFFF7C6FFB6
+:101E100084F31188F9E70000034A516853685B1A9C
+:101E20009842FBD8704700BF001000E08B6002238F
+:101E300008618B82084670478368A3F1840243F8E7
+:101E4000142C026943F8442C426943F8402C094A97
+:101E500043F8242CC26843F8182C022203F80C2CF7
+:101E6000002203F80B2C044A43F8102CA3F12000A5
+:101E7000704700BF1D0300082826002008B5FFF7A3
+:101E8000DBFFBDE80840FFF73BBF0000024BDB680B
+:101E900098610F20FFF736BF28260020302383F3F8
+:101EA0001188FFF7F3BF000008B50146302383F324
+:101EB00011880820FFF734FF002383F3118808BD41
+:101EC000064BDB6839B1426818605A6013604360A2
+:101ED0000420FFF725BF4FF0FF3070472826002071
+:101EE0000368984206D01A680260506099611846EB
+:101EF000FFF706BF7047000038B504460D4620685E
+:101F0000844200D138BD036823605C608561FFF7BF
+:101F1000F7FEF4E710B503689C68A2420CD85C6831
+:101F20008A600B604C602160596099688A1A9A60D7
+:101F30004FF0FF33836010BD1B68121BECE70000FD
+:101F40000A2938BF0A2170B504460D460A266019D1
+:101F500001F0A6FA01F092FA041BA54203D8751C01
+:101F60002E460446F3E70A2E04D9BDE8704001204E
+:101F700001F0DCBA70BD0000F8B5144B0D46D96114
+:101F800003F1100141600A2A1969826038BF0A22F0
+:101F9000016048601861A818144601F073FA0A2716
+:101FA00001F06CFA431BA342064606D37C1C281999
+:101FB00001F076FA27463546F2E70A2F04D9BDE844
+:101FC000F840012001F0B2BAF8BD00BF2826002079
+:101FD000F8B506460D4601F051FA0F4A134653F87C
+:101FE000107F9F4206D12A4601463046BDE8F840A0
+:101FF000FFF7C2BFD169BB68441A2C1928BF2C4611
+:10200000A34202D92946FFF79BFF224631460348E7
+:10201000BDE8F840FFF77EBF2826002038260020C4
+:1020200010B4C0E9032300235DF8044B4361FFF7BC
+:10203000CFBF000010B5194C236998420DD0D0E9EC
+:102040000032816813605A609A680A449A600023DB
+:1020500003604FF0FF33A36110BD2346026843F8CD
+:10206000102F53600022026022699A4203D1BDE81A
+:10207000104001F00FBA936881680B44936001F03F
+:10208000FDF92269E1699268441AA242E4D9114437
+:10209000BDE81040091AFFF753BF00BF28260020F3
+:1020A0002DE9F047DFF8BC8008F110072C4ED8F876
+:1020B000105001F0E3F9D8F81C40AA68031B9A42BB
+:1020C0003ED81444D5E900324FF00009C8F81C404E
+:1020D00013605A60C5F80090D8F81030B34201D1AF
+:1020E00001F0D8F989F31188D5E9033128469847DA
+:1020F000302383F311886B69002BD8D001F0BEF92F
+:102100006A69A0EB04094A4582460DD2022001F01B
+:102110000DFA0022D8F81030B34208D151462846B3
+:10212000BDE8F047FFF728BF121A2244F2E712EB8E
+:10213000090938BF4A4629463846FFF7EBFEB5E79E
+:10214000D8F81030B34208D01444211AC8F81C0043
+:10215000A960BDE8F047FFF7F3BEBDE8F08700BF18
+:10216000382600202826002000207047FEE70000C7
+:10217000704700004FF0FF307047000002290CD07C
+:10218000032904D00129074818BF00207047032AFB
+:1021900005D8054800EBC20070470448704700208E
+:1021A000704700BFD43C00082C220020883C000867
+:1021B00070B59AB00546084601A9144600F0C2F869
+:1021C00001A8FEF78DFD431C5B00C5E90034002229
+:1021D000237003236370C6B201AB02341046D1B240
+:1021E0008E4204F1020401D81AB070BD13F8011B2D
+:1021F00004F8021C04F8010C0132F0E708B53023A2
+:1022000083F311880348FFF733FA002383F311881F
+:1022100008BD00BF9828002090F8443003F01F024A
+:10222000012A07D190F845200B2A03D10023C0E9E9
+:102230000E3315E003F06003202B08D1B0F84830CE
+:102240002BB990F84520212A03D81F2A04D8FFF77C
+:10225000F1B9222AEBD0FAE7034A82630722C2636C
+:1022600003640120704700BF2322002007B5052921
+:1022700017D8DFE801F0191603191920302383F36A
+:102280001188104A01900121FFF794FA01980E4A33
+:102290000221FFF78FFA0D48FFF7B6F9002383F309
+:1022A000118803B05DF804FB302383F311880748DD
+:1022B000FFF780F9F2E7302383F311880348FFF733
+:1022C00097F9EBE7283C00084C3C000898280020D0
+:1022D00038B50C4D0C4C0D492A4604F10800FFF7A7
+:1022E00067FF05F1CA0204F110000949FFF760FF1A
+:1022F00005F5CA7204F118000649BDE83840FFF739
+:1023000057BF00BF602D00202C220020083C000891
+:10231000123C00081D3C000870B5044608460D46F6
+:10232000FEF7DEFCC6B22046013403780BB918462E
+:1023300070BD32462946FEF7BFFC0028F3D10120CC
+:10234000F6E700002DE9F84F05460C46FEF7C8FCFD
+:102350002B49C6B22846FFF7DFFF08B10536F6B2B3
+:1023600028492846FFF7D8FF08B11036F6B2632E89
+:102370000DD8DFF88C80DFF88C90234FDFF890A029
+:10238000DFF890B02E7846B92670BDE8F88F294660
+:102390002046BDE8F84F01F0BFBB252E2BD1072208
+:1023A00041462846FEF788FC58B9DBF80030236028
+:1023B000DBF804306360DBF80830A36007350C34C9
+:1023C000E0E7082249462846FEF776FC98B90F4B0D
+:1023D000A21C197809090232C95D02F8041C13F81D
+:1023E000011B01F00F015345C95D02F8031CF0D138
+:1023F00018340835C6E704F8016B0135C2E700BFA1
+:10240000F43C00081D3C0008093D0008107AFF1F3D
+:102410001C7AFF1FFC3C0008BFF34F8F024AD368B1
+:10242000DB03FCD4704700BF003C024008B5094BF9
+:102430001B7873B9FFF7F0FF074B1A69002ABFBF7B
+:10244000064A5A6002F188325A601A6822F48062A1
+:102450001A6008BDBE2F0020003C024023016745E2
+:1024600008B50B4B1B7893B9FFF7D6FF094B1A69D8
+:1024700042F000421A611A6842F480521A601A68E7
+:1024800022F480521A601A6842F480621A6008BD11
+:10249000BE2F0020003C02400B28F0B516D80C4C93
+:1024A0000C4923787BB90C4D0E460C234FF000628B
+:1024B00055F8047B46F8042B013B13F0FF033A4424
+:1024C000F6D10123237051F82000F0BD0020FCE775
+:1024D000F02F0020C02F00201C3D0008014B53F8B6
+:1024E000200070471C3D00080C2070470B2810B5D9
+:1024F000044601D9002010BDFFF7CEFF064B53F86C
+:1025000024301844C21A0BB90120F4E712680132D2
+:10251000F0D1043BF6E700BF1C3D00080B2838B59E
+:10252000044628D8FFF75EFCFFF776FFFFF77EFF33
+:10253000124AF323D360E300DBB243F4007343F0A9
+:1025400002031361136943F4803313610546204687
+:10255000FFF762FFFFF7A0FF094B53F8241000F0CC
+:10256000E9F82846FFF77CFFFFF746FC2046BDE868
+:102570003840FFF7BBBF002038BD00BF003C024021
+:102580001C3D000812F001032DE9F04105460E46FE
+:1025900014464BD18218B2F1016F61D8314B1B68E0
+:1025A00013F001035CD0304FFFF71CFCFFF73EFF38
+:1025B000F323FB60FFF730FF314640F20128032C84
+:1025C00018D824F00104284E0C446D1A40F201186A
+:1025D000A142336905EB01072AD123F001033361DE
+:1025E000FFF73EFFFFF708FC0120BDE8F081043C47
+:1025F0000435E4E7AB07E4D13B6923F440733B6166
+:102600003B6943EA08033B6151F8046B2E60BFF35A
+:102610004F8FFFF701FF2B689E42E8D03B6923F004
+:1026200001033B61FFF71CFFFFF7E6FB0020DCE73F
+:1026300023F440733361336943EA080333610B8841
+:102640003B80BFF34F8FFFF7E7FE3F8831F8023B37
+:10265000BFB2BB42BCD0336923F001033361E1E771
+:102660001846C2E700380240003C0240084908B55D
+:102670000B7828B11BB9FFF7D9FE01230B7008BDF9
+:10268000002BFCD0BDE808400870FFF7E9BE00BF92
+:10269000BE2F002010B50244064BD2B2904200D1AA
+:1026A00010BD441C00B253F8200041F8040BE0B206
+:1026B000F4E700BF502800400F4B30B51C6F2404D6
+:1026C00007D41C6F44F400741C671C6F44F400446E
+:1026D0001C670A4C236843F4807323600244084B50
+:1026E000D2B2904200D130BD441C00B251F8045B1C
+:1026F00043F82050E0B2F4E7003802400070004098
+:102700005028004007B5012201A90020FFF7C2FFB1
+:10271000019803B05DF804FB13B50446FFF7F2FF20
+:10272000A04205D0012201A900200194FFF7C4FFB7
+:1027300002B010BD70470000034B1A681AB9034A73
+:10274000D2F874281A607047F42F0020003002403D
+:1027500008B5FFF7F1FF024B1868C0F3407008BDE1
+:10276000F42F002070470000FEE700000A4B0B48E2
+:102770000B4A90420BD30B4BDA1C121AC11E22F0EB
+:1027800003028B4238BF00220021FEF7B1BA53F892
+:10279000041B40F8041BECE7D43E0008F030002096
+:1027A000F0300020F030002070B5D0E915439E686D
+:1027B00000224FF0FF3504EB42135101D3F800091A
+:1027C0000028BEBFD3F8000940F08040C3F80009DC
+:1027D000D3F8000B0028BEBFD3F8000B40F08040B8
+:1027E000C3F8000B013263189642C3F80859C3F8C6
+:1027F000085BE0D24FF00113C4F81C3870BD000034
+:10280000890141F02001016103699B06FCD412207B
+:10281000FFF702BB10B5054C2046FEF7ABFF4FF0AB
+:10282000A0436365024BA36510BD00BFF82F0020D5
+:10283000703D000870B50378012B054650D12A4B36
+:10284000446D98421BD1294B5A6B42F080025A6367
+:102850005A6D42F080025A655A6D5A6942F0800200
+:102860005A615A6922F080025A610E2143205B6945
+:1028700000F022FC1E4BE3601E4BC4F8003800231E
+:10288000C4F8003EC02323606E6D4FF40413A363AD
+:102890003369002BFCDA012333610C20FFF7BCFA0B
+:1028A0003369DB07FCD41220FFF7B6FA3369002B3B
+:1028B000FCDA0026A6602846FFF776FF6B68C4F8AE
+:1028C0001068DB68C4F81468C4F81C684BB90A4B7C
+:1028D000A3614FF0FF336361A36843F00103A3607A
+:1028E00070BD064BF4E700BFF82F0020003802400F
+:1028F0004014004003002002003C30C0083C30C0BF
+:10290000F8B5446D054600212046FFF779FFA96D13
+:1029100000234FF001128F68C4F834384FF000667E
+:10292000C4F81C284FF0FF3004EB431201339F42E0
+:10293000C2F80069C2F8006BC2F80809C2F8080BB7
+:10294000F2D20B686A6DEB6563621023136116693E
+:1029500016F01006FBD11220FFF75EFAD4F800380B
+:1029600023F4FE63C4F80038A36943F4402343F022
+:102970001003A3610923C4F81038C4F814380A4BB3
+:10298000EB604FF0C043C4F8103B084BC4F8003B69
+:10299000C4F81069C4F80039EB6D03F1100243F478
+:1029A0008013EA65A362F8BD4C3D0008408000102A
+:1029B000426D90F84E10D2F8003823F4FE6343EADB
+:1029C0000113C2F8003870472DE9F84300EB81038A
+:1029D000456DDA68166806F00306731E022B05EBD8
+:1029E00041130C4680460FFA81F94FEA41104FF02F
+:1029F0000001C3F8101B4FF0010104F1100398BF50
+:102A0000B60401FA03F391698EBF334E06F1805686
+:102A100006F5004600293AD0578A04F158014901C9
+:102A200037436F50D5F81C180B43C5F81C382B18CA
+:102A30000021C3F8101953690127611EA7409BB3F9
+:102A4000138A928B9B08012A88BF5343D8F85C20D5
+:102A5000981842EA034301F1400205EB8202C8F8EC
+:102A60005C00214653602846FFF7CAFE08EB890048
+:102A7000C3681B8A43EA8453483464011E432E51C1
+:102A8000D5F81C381F43C5F81C78BDE8F88305EB62
+:102A90004917D7F8001B21F40041C7F8001BD5F8EF
+:102AA0001C1821EA0303C0E704F13F0305EB83038D
+:102AB0000A4A5A6028462146FFF7A2FE05EB491054
+:102AC000D0F8003923F40043C0F80039D5F81C3899
+:102AD00023EA0707D7E700BF0080001000040002C8
+:102AE000826D1268C265FFF75FBE00005831436D0A
+:102AF00049015B5813F4004004D013F4001F0CBFCD
+:102B000002200120704700004831436D49015B58A5
+:102B100013F4004004D013F4001F0CBF0220012066
+:102B20007047000000EB8101CB68196A0B681360E5
+:102B30004B6853607047000000EB810330B5DD68DF
+:102B4000AA691368D36019B9402B84BF402313606E
+:102B50006B8A1468426D1C44013CB4FBF3F463437C
+:102B6000033323F0030302EB411043EAC44343F071
+:102B7000C043C0F8103B2B6803F00303012B09B2DC
+:102B80000ED1D2F8083802EB411013F4807FD0F850
+:102B9000003B14BF43F0805343F00053C0F8003BA8
+:102BA00002EB4112D2F8003B43F00443C2F8003B71
+:102BB00030BD00002DE9F041244D6E6D06EB401351
+:102BC0000446D3F8087BC3F8087B38070AD5D6F843
+:102BD0001438190706D505EB84032146DB6828461F
+:102BE0005B689847FA071FD5D6F81438DB071BD562
+:102BF00005EB8403D968CCB98B69488A5A68B2FB63
+:102C0000F0F600FB16228AB91868DA6890420DD2F5
+:102C1000121AC3E90024302383F311880B4821469C
+:102C2000FFF78AFF84F31188BDE8F081012303FADE
+:102C300004F26B8923EA02036B81CB68002BF3D08B
+:102C400021460248BDE8F041184700BFF82F002098
+:102C500000EB810370B5DD68436D6C692668E66042
+:102C60004A0156BB1A444FF40020C2F810092A68E2
+:102C700002F00302012A0AB20ED1D3F8080803EBCE
+:102C8000421410F4807FD4F8000914BF40F0805043
+:102C900040F00050C4F8000903EB4212D2F80009DA
+:102CA00040F00440C2F80009D3F83408012202FAC7
+:102CB00001F10143C3F8341870BD19B9402E84BF27
+:102CC0004020206020682E8A8419013CB4FBF6F471
+:102CD00040EAC44040F000501A44C6E72DE9F843EA
+:102CE0003B4D6E6D06EB40130446D3F80889C3F8DC
+:102CF000088918F0010F4FEA40171AD0D6F810389B
+:102D0000DB0716D505EB8003D9684B691868DA68CC
+:102D1000904230D2121A4FF000091A60C3F80490A2
+:102D2000302383F3118821462846FFF791FF89F36A
+:102D3000118818F0800F1CD0D6F834380126A64030
+:102D4000334216D005EB84036D6DD3F80CC0DCF86C
+:102D500014200134E4B2D2F800E005EB04342F442F
+:102D60005168714515D3D5F8343823EA0606C5F8FD
+:102D70003468BDE8F883012303FA04F22B8923EABF
+:102D800002032B818B68002BD3D02146284698471D
+:102D9000CFE7BCF81000AEEB0103834228BF034627
+:102DA000D7F8180980B2B3EB800FE2D89068A0F191
+:102DB000040959F8048FC4F80080A0EB090898446E
+:102DC000B8F1040FF5D818440B4490605360C7E77E
+:102DD000F82F00202DE9F74FA24C656D6E69AB69A5
+:102DE0001E4016F480586E6107D02046FEF72AFD7B
+:102DF00003B0BDE8F04F00F047BC002E12DAD5F862
+:102E0000003E98489B071EBFD5F8003E23F0030301
+:102E1000C5F8003ED5F8043823F00103C5F804389E
+:102E2000FEF73AFD370505D58E48FFF7BDFC8D4806
+:102E3000FEF720FDB0040CD5D5F8083813F0060FC6
+:102E4000EB6823F470530CBF43F4105343F4A053C6
+:102E5000EB6031071BD56368DB681BB9AB6923F0F6
+:102E60000803AB612378052B0CD1D5F8003E7D48D3
+:102E70009A071EBFD5F8003E23F00303C5F8003EB5
+:102E8000FEF70AFD6368DB680BB176489847F302EA
+:102E900074D4B70227D5D4F85490DFF8C8B100270E
+:102EA0004FF0010A09EB4712D2F8003B03F440232C
+:102EB000B3F5802F11D1D2F8003B002B0DDA6289D7
+:102EC0000AFA07F322EA0303638104EB8703DB6852
+:102ED000DB6813B1394658469847A36D01379B68A4
+:102EE000FFB29F42DED9F00617D5676D3A6AC2F38A
+:102EF0000A1002F00F0302F4F012B2F5802F00F076
+:102F00008580B2F5402F08D104EB83030022DB68F3
+:102F10001B6A07F5805790426AD13003D5F81848EC
+:102F200013D5E10302D50020FFF744FEA20302D52A
+:102F30000120FFF73FFE630302D50220FFF73AFEB0
+:102F4000270302D50320FFF735FE75037FF550AF49
+:102F5000E00702D50020FFF7C1FEA10702D501203E
+:102F6000FFF7BCFE620702D50220FFF7B7FE23077A
+:102F70007FF53EAF0320FFF7B1FE39E7636DDFF861
+:102F8000E4A0019300274FF00109A36D9B685FFA4D
+:102F900087FB9B453FF67DAF019B03EB4B13D3F8BB
+:102FA000001901F44021B1F5802F1FD1D3F8001989
+:102FB00000291BDAD3F8001941F09041C3F8001939
+:102FC000D3F800190029FBDB5946606DFFF718FCA8
+:102FD000218909FA0BF321EA0303238104EB8B0314
+:102FE000DB689B6813B15946504698470137CCE7D8
+:102FF000910708BFD7F80080072A98BF03F8018B14
+:1030000002F1010298BF4FEA182884E7023304EB6B
+:10301000830207F580575268D2F818C0DCF8082000
+:10302000DCE9001CA1EB0C0C002188420AD104EB66
+:10303000830463689B699A6802449A605A680244F0
+:103040005A606AE711F0030F08BFD7F800808C457B
+:1030500088BF02F8018B01F1010188BF4FEA1828EF
+:10306000E3E700BFF82F0020436D03EB4111D1F8D7
+:10307000003B43F40013C1F8003B7047436D03EB82
+:103080004111D1F8003943F40013C1F800397047F9
+:10309000436D03EB4111D1F8003B23F40013C1F859
+:1030A000003B7047436D03EB4111D1F8003923F425
+:1030B0000013C1F80039704700F1604303F5614324
+:1030C0000901C9B283F80013012200F01F039A40DE
+:1030D00043099B0003F1604303F56143C3F880217A
+:1030E0001A60704730B5039C0172043304FB03255A
+:1030F000C0E90653049B03630021059BC160C0E93E
+:103100000000C0E90422C0E90842C0E90A11436393
+:1031100030BD0000416A0022C0E90411C0E90A2262
+:10312000C2606FF00101FEF7E7BE0000D0E9043293
+:10313000934201D1C2680AB9181D70470020704738
+:1031400003691960C2680132C260C26913448269AE
+:103150000361934224BF436A03610021FEF7C0BEAE
+:1031600038B504460D46E3683BB16269131D126829
+:10317000A3621344E362002007E0237A33B92946AF
+:103180002046FEF79DFE0028EDDA38BD6FF0010005
+:10319000FBE70000C368C269013BC3604369134495
+:1031A00082694361934224BF436A4361002383627F
+:1031B000036B03B11847704770B53023044683F39F
+:1031C0001188866A3EB9FFF7CBFF054618B186F332
+:1031D0001188284670BDA36AE26A13F8015BA362F6
+:1031E000934202D32046FFF7D5FF002383F31188D3
+:1031F000EFE700002DE9F84F04460E4617469846C3
+:103200004FF0300989F311880025AA46D4F828B078
+:10321000BBF1000F09D141462046FFF7A1FF20B1C5
+:103220008BF311882846BDE8F88FD4E90A12A7EB82
+:10323000050B521A934528BF9346BBF1400F1BD98B
+:10324000334601F1400251F8040B43F8040B91425C
+:10325000F9D1A36A40334036A3624035D4E90A234A
+:103260009A4202D32046FFF795FF8AF31188BD42A8
+:10327000D8D289F31188C9E730465A46FDF712FDC6
+:10328000A36A5B445E44A3625D44E7E710B5029C19
+:103290000172043303FB0421C0E906130023C0E9D3
+:1032A0000A33039B0363049BC460C0E90000C0E9C8
+:1032B0000422C0E90842436310BD0000026AC260F4
+:1032C000426AC0E904220022C0E90A226FF001012B
+:1032D000FEF712BED0E904239A4201D1C26822B996
+:1032E000184650F8043B0B60704700231846FAE775
+:1032F000C368C2690133C36043691344826943618F
+:10330000934224BF436A43610021FEF7E9BD0000F8
+:1033100038B504460D46E3683BB123691A1DA26225
+:10332000E2691344E362002007E0237A33B92946B7
+:103330002046FEF7C5FD0028EDDA38BD6FF001002C
+:10334000FBE7000003691960C268013AC260C26904
+:10335000134482690361934224BF436A03610023DB
+:103360008362036B03B118477047000070B53023C8
+:103370000D460446114683F31188866A2EB9FFF77D
+:10338000C7FF10B186F3118870BDA36A1D70A36AD0
+:10339000E26A01339342A36204D3E169204604390F
+:1033A000FFF7D0FF002080F31188EDE72DE9F84FFB
+:1033B00004460D46904699464FF0300A8AF311882C
+:1033C0000026B346A76A4FB949462046FFF7A0FF3B
+:1033D00020B187F311883046BDE8F88FD4E90A0799
+:1033E0003A1AA8EB0607974228BF1746402F1BD969
+:1033F00005F1400355F8042B40F8042B9D42F9D108
+:10340000A36A4033A3624036D4E90A239A4204D324
+:10341000E16920460439FFF795FF8BF31188464593
+:10342000D9D28AF31188CDE729463A46FDF73AFC0E
+:10343000A36A3B443D44A3623E44E5E7D0E904234C
+:103440009A4217D1C3689BB1836A8BB1043B9B1A24
+:103450000ED01360C368013BC360C3691A4483691B
+:1034600002619A4224BF436A0361002383620123FD
+:10347000184670470023FBE700F030B94FF0804357
+:10348000586A70474FF08043002258631A61022245
+:10349000DA6070474FF080430022DA607047000026
+:1034A0004FF0804358637047FEE7000070B51B4B38
+:1034B00001630025044686B0586085620E4600F020
+:1034C000BFF804F11003C4E904334FF0FF33C4E93B
+:1034D0000635C4E90044A560E562FFF7CFFF2B463F
+:1034E0000246C4E9082304F134010D4A256580230E
+:1034F0002046FEF79BFC0123E0600A4A0375009218
+:1035000072680192B268CDE90223074B6846CDE9A3
+:103510000435FEF7B3FC06B070BD00BF9028002054
+:103520007C3D0008813D0008A9340008024AD36AA6
+:103530001843D062704700BF282600204B684360C4
+:103540008B688360CB68C3600B6943614B6903621E
+:103550008B6943620B6803607047000008B5264B17
+:1035600026481A6940F2FF110A431A611A6922F4C7
+:10357000FF7222F001021A611A691A6B0A431A6378
+:103580001A6D0A431A651E4A1B6D1146FFF7D6FFD6
+:1035900002F11C0100F58060FFF7D0FF02F1380155
+:1035A00000F58060FFF7CAFF02F1540100F580606A
+:1035B000FFF7C4FF02F1700100F58060FFF7BEFF66
+:1035C00002F18C0100F58060FFF7B8FF02F1A8015D
+:1035D00000F58060FFF7B2FF02F1C40100F58060E2
+:1035E000FFF7ACFF02F1E00100F58060FFF7A6FFF6
+:1035F000BDE8084000F0EEB800380240000002408C
+:10360000883D000808B500F067FAFEF7D3FBFFF726
+:1036100093F8BDE80840FEF75BBE0000704700006D
+:10362000EFF3098305494A6B22F001024A636833CC
+:1036300083F30988002383F31188704700EF00E0CB
+:10364000302080F3118862B60C4B0D4AD96821F402
+:10365000E0610904090C0A43DA60D3F8FC20094947
+:1036600042F08072C3F8FC200A6842F001020A604E
+:103670002022DA7783F82200704700BF00ED00E0D7
+:103680000003FA05001000E010B5302383F3118821
+:103690000E4B5B6813F4006314D0F1EE103AEFF3B5
+:1036A0000984683C4FF08073E361094BDB6B236650
+:1036B00084F30988FEF752FB10B1064BA36110BDDD
+:1036C000054BFBE783F31188F9E700BF00ED00E04D
+:1036D00000EF00E02F030008320300080F4B1A6CC4
+:1036E00042F001021A641A6E42F001021A660C4A94
+:1036F0001B6E936843F0010393604FF080435322A5
+:103700009A624FF0FF32DA6200229A615A63DA60FD
+:103710005A6001225A611A60704700BF00380240A7
+:10372000002004E04FF0804208B51169D3680B40D7
+:10373000D9B2C9439B07116107D5302383F31188A0
+:10374000FEF74EFB002383F3118808BD1F4B1A6957
+:103750006FEAC2526FEAD2521A611A69C2F30802C2
+:103760001A614FF0FF301A695A69586100215A698D
+:1037700059615A691A6A62F080521A621A6A02F032
+:1037800080521A621A6A5A6A58625A6A59625A6AA6
+:103790001A6C42F080521A641A6E42F080521A6615
+:1037A0001A6E0B4A106840F480701060186F00F4B5
+:1037B0004070B0F5007F1EBF4FF480301867196766
+:1037C000536823F40073536000F05EB90038024080
+:1037D00000700040334B4FF080521A64324A4FF46D
+:1037E000404111601A6842F001021A601A6891079C
+:1037F000FCD59A6822F003029A602A4B9A6812F06C
+:103800000C02FBD1196801F0F90119609A601A687D
+:1038100042F480321A601A689203FCD55A6F42F063
+:1038200001025A671F4B5A6F9007FCD51F4A5A6016
+:103830001A6842F080721A601B4A53685904FCD51A
+:10384000184B1A689201FCD5194A9A60194B1A68EC
+:10385000194B9A42194B21D1194A1168194A9142C0
+:103860001CD140F205121A60144A136803F00F03CA
+:10387000052BFAD10B4B9A6842F002029A609A68C3
+:1038800002F00C02082AFAD15A6C42F480425A64BF
+:103890005A6E42F480425A665B6E704740F205727F
+:1038A000E1E700BF003802400070004008544007C4
+:1038B00000948838002004E011640020003C02409D
+:1038C00000ED00E041C20F41074A08B5536903F01B
+:1038D0000103536123B1054A13680BB1506898473F
+:1038E000BDE80840FFF7D0BE003C0140703000202A
+:1038F000074A08B5536903F00203536123B1054A2F
+:1039000093680BB1D0689847BDE80840FFF7BCBE8C
+:10391000003C014070300020074A08B5536903F0AD
+:103920000403536123B1054A13690BB150699847E9
+:10393000BDE80840FFF7A8BE003C01407030002001
+:10394000074A08B5536903F00803536123B1054AD8
+:1039500093690BB1D0699847BDE80840FFF794BE62
+:10396000003C014070300020074A08B5536903F05D
+:103970001003536123B1054A136A0BB1506A98478B
+:10398000BDE80840FFF780BE003C014070300020D9
+:10399000164B10B55C6904F478725A61A30604D51D
+:1039A000134A936A0BB1D06A9847600604D5104A4F
+:1039B000136B0BB1506B9847210604D50C4A936BDF
+:1039C0000BB1D06B9847E20504D5094A136C0BB1D3
+:1039D000506C9847A30504D5054A936C0BB1D06C85
+:1039E0009847BDE81040FFF74FBE00BF003C0140C4
+:1039F00070300020194B10B55C6904F47C425A61A8
+:103A0000620504D5164A136D0BB1506D9847230516
+:103A100004D5134A936D0BB1D06D9847E00404D5DB
+:103A20000F4A136E0BB1506E9847A10404D50C4A8F
+:103A3000936E0BB1D06E9847620404D5084A136F99
+:103A40000BB1506F9847230404D5054A936F0BB10F
+:103A5000D06F9847BDE81040FFF716BE003C01400C
+:103A60007030002008B50348FDF786FABDE808402D
+:103A7000FFF70ABEBC23002008B5FFF753FEBDE8E0
+:103A80000840FFF701BE0000062108B50846FFF711
+:103A900013FB06210720FFF70FFB06210820FFF785
+:103AA0000BFB06210920FFF707FB06210A20FFF781
+:103AB00003FB06211720FFF7FFFA06212820FFF756
+:103AC000FBFA07211C20FFF7F7FABDE808400C219C
+:103AD0002520FFF7F1BA000008B5FFF737FE00F028
+:103AE0000DF8FDF75DFCFDF743FEFDF71BFDFFF74D
+:103AF00095FDBDE80840FFF7BFBC00000023054A64
+:103B000019460133102BC2E9001102F10802F8D165
+:103B1000704700BF70300020034611F8012B03F8F6
+:103B2000012B002AF9D1704753544D3332463F3FA1
+:103B30003F0053544D3332463430780053544D33A4
+:103B400032463432780053544D333246343436588A
+:103B500058000000012033000010410001105A00FD
+:103B6000031059000710310000000000283B000836
+:103B700013040000323B0008190400003C3B00081D
+:103B800021040000463B00080096000000000000F1
+:103B90000000000000000000000000000000000025
+:103BA000611300084D1300088913000875130008FD
+:103BB000811300086D13000859130008451300080D
+:103BC0009513000800000000A11400088D140008DF
+:103BD000C9140008B5140008C1140008AD14000889
+:103BE0009914000885140008D5140008000000008E
+:103BF000010000000000000063300000F83B0008F6
+:103C000080260020902800204172647550696C6FF6
+:103C1000740025424F415244252D424C0025534506
+:103C20005249414C25000000020000000000000045
+:103C3000BD1600082917000840004000302D002064
+:103C4000402D0020020000000000000003000000E2
+:103C5000000000006D1700080000000010000000C8
+:103C6000502D0020000000000100000000000000B6
+:103C7000F82F0020010102006D2200087D210008BC
+:103C800019220008FD21000843000000903C0008B4
+:103C900009024300020100C03209040000010202CF
+:103CA0000100052400100105240100010424020282
+:103CB0000524060001070582030800FF090401002E
+:103CC000020A00000007050102400000070581020A
+:103CD0004000000012000000DC3C0008120110014E
+:103CE00002000040091241570002010203010000D6
+:103CF0000403090425424F415244250048454557D5
+:103D0000494E472D46343035003031323334353664
+:103D10003738394142434445460000000040000026
+:103D200000400000004000000040000000000100D2
+:103D3000000002000000020000000200000002007B
+:103D4000000002000000020000000200000000006D
+:103D5000B1180008691B0008151C0008400040004D
+:103D6000583000205830002001000000683000204A
+:103D70008000000040010000030000006D61696EDA
+:103D80000069646C650000000001A82A00000000C2
+:103D9000AAAAAAAA00011424FFFF00000000000044
+:103DA00070A70A000000000000000000AAAAAAAA4A
+:103DB00000000000FFFF0000000000000000000005
+:103DC0000001005400000000AAAAAAAA00010010E5
+:103DD000FF5F000000000000000000000000000085
+:103DE00000000000AAAAAAAA00000000FFFF00002D
+:103DF00000000000000000000000000000000000C3
+:103E0000AAAAAAAA00000000FFFF0000000000000C
+:103E1000000000000000000000000000AAAAAAAAFA
+:103E200000000000FFFF0000000000000000000094
+:103E30000000000000000000AAAAAAAA00000000DA
+:103E4000FFFF000000000000000000000000000074
+:103E5000000000000A000000000000000300000055
+:103E60000000000000000000000000000000000052
+:103E70000000000000000000000000000000000042
+:103E800000000000000000005F04000000000000CF
+:103E900000000F0000000000FF0000009828002034
+:103EA000BC230020009600000000080096000000DF
+:103EB0000008000004000000F03C000800000000C2
+:103EC00000000000000000000000000000000000F2
+:043ED00000000000EE
+:00000001FF
diff --git a/Tools/bootloaders/HEEWING-F405v2_bl.bin b/Tools/bootloaders/HEEWING-F405v2_bl.bin
new file mode 100644
index 00000000000000..376332445e3de3
Binary files /dev/null and b/Tools/bootloaders/HEEWING-F405v2_bl.bin differ
diff --git a/Tools/bootloaders/HEEWING-F405v2_bl.hex b/Tools/bootloaders/HEEWING-F405v2_bl.hex
new file mode 100644
index 00000000000000..f84422570b8325
--- /dev/null
+++ b/Tools/bootloaders/HEEWING-F405v2_bl.hex
@@ -0,0 +1,1008 @@
+:020000040800F2
+:1000000000060020E1010008E3010008E301000808
+:10001000E3010008E3010008E3010008E301000830
+:10002000E3010008E3010008E301000821360008AD
+:10003000E3010008E3010008E3010008E301000810
+:10004000E3010008E3010008E3010008E301000800
+:10005000E3010008E3010008C9380008F13800088E
+:10006000193900084139000869390008E30100081E
+:10007000E3010008E3010008E3010008E3010008D0
+:10008000E3010008E3010008E3010008E3010008C0
+:10009000E3010008E3010008E301000891390008CA
+:1000A000E3010008E3010008E3010008E3010008A0
+:1000B000793A0008E3010008E3010008E3010008C1
+:1000C000E3010008E3010008E3010008E301000880
+:1000D000E3010008653A0008E3010008E3010008B5
+:1000E000F5390008E3010008E3010008E301000816
+:1000F000E3010008E3010008E3010008E301000850
+:10010000E3010008E3010008E3010008E30100083F
+:10011000E3010008E3010008E3010008E30100082F
+:10012000E3010008E3010008E3010008E30100081F
+:10013000E3010008E3010008E3010008E30100080F
+:10014000E3010008E3010008E3010008D52D0008E1
+:10015000E3010008E3010008E3010008E3010008EF
+:10016000E3010008E3010008E3010008E3010008DF
+:10017000E3010008E3010008E3010008E3010008CF
+:10018000E3010008E3010008E3010008E3010008BF
+:10019000E3010008E3010008E3010008E3010008AF
+:1001A000E3010008E3010008E3010008E30100089F
+:1001B000E3010008E3010008E3010008E30100088F
+:1001C000E3010008E3010008E3010008E30100087F
+:1001D000E3010008E3010008E3010008E30100086F
+:1001E00002E000F000F8FEE772B6374880F30888B6
+:1001F000364880F3098836483649086040F20000E6
+:10020000CCF200004EF63471CEF200010860BFF36C
+:100210004F8FBFF36F8F40F20000C0F2F0004EF638
+:100220008851CEF200010860BFF34F8FBFF36F8F8C
+:100230004FF00000E1EE100A4EF63C71CEF20001E4
+:100240000860062080F31488BFF36F8F02F08AFAEB
+:1002500003F084F94FF055301F491B4A91423CBFCF
+:1002600041F8040BFAE71D49184A91423CBF41F896
+:10027000040BFAE71A491B4A1B4B9A423EBF51F83E
+:10028000040B42F8040BF8E700201849184A914281
+:100290003CBF41F8040BFAE702F068FA03F0B2F948
+:1002A000144C154DAC4203DA54F8041B8847F9E7A7
+:1002B00000F042F8114C124DAC4203DA54F8041B22
+:1002C0008847F9E702F050BA00060020002200201B
+:1002D0000000000808ED00E00000002000060020FB
+:1002E000883E0008002200204C22002050220020DE
+:1002F000F0300020E0010008E0010008E001000803
+:10030000E00100082DE9F04F2DED108AC1F80CD066
+:10031000C3689D46BDEC108ABDE8F08F002383F3CF
+:1003200011882846A047002001F0B8FDFEE701F043
+:1003300021FD00DFFEE7000038B502F0E3F90546D5
+:1003400002F006FA0446D8B90F4B9D421AD0013389
+:100350009D4218BF044641F2883504BF01240025A0
+:10036000002002F0D9F90CB100F076F800F016FD8B
+:1003700000F0B0FB284600F0B9F800F06DF8F9E79E
+:100380000025EDE70546EBE7010007B008B500F0F2
+:100390006DFBA0F120035842584108BD07B541F25A
+:1003A0001203022101A8ADF8043000F07DFB03B078
+:1003B0005DF804FB38B5302383F3118817480368D0
+:1003C0000BB101F037FE164A144800234FF47A713E
+:1003D00001F026FE002383F31188124C236813B129
+:1003E0002368013B2360636813B16368013B63606A
+:1003F0000D4D2B7833B963687BB9022000F040FCC7
+:10040000322363602B78032B07D163682BB902205A
+:1004100000F036FC4FF47A73636038BD5022002040
+:10042000B50300087023002068220020084B1870D4
+:1004300003280CD8DFE800F008050208022000F0CD
+:100440000FBC022000F0FCBB024B00225A60704738
+:1004500068220020702300201F4B204A10B51C4644
+:100460001968013137D004339342F9D162681C4BCB
+:100470009A4230D91B4B9B6803F1006303F580332C
+:100480009A4228D2002000F03FFB0220FFF7CEFF67
+:10049000154B1A6C00221A64196E1A66196E596C83
+:1004A0005A64596E5A665A6E1A6942F000521A61BD
+:1004B0001A6922F000521A611B6972B64FF0E023EC
+:1004C0003021C3F8084DD4E9003281F311889D46EC
+:1004D00083F30888104710BD0000010820000108C0
+:1004E000FFFF000800220020003802402DE9F04FF5
+:1004F00093B0AA4B00902022FF210AA89D6800F02B
+:10050000F7FBA74A1378A3B9A6480121036011702D
+:10051000302383F3118803680BB101F08BFDA24AED
+:10052000A04800234FF47A7101F07AFD002383F391
+:100530001188009B13B19D4B009A1A609C4A009C45
+:100540001378032B1EBF00231370984A4FF0000A44
+:1005500018BF5360D3465646D146012000F080FBB9
+:1005600024B1924B1B68002B00F01182002000F098
+:100570007DFA0390039B002BF2DB012000F060FB6F
+:10058000039B213B162BE8D801A252F823F000BFB1
+:10059000ED05000815060008A90600085B0500081F
+:1005A0005B0500085B050008330700080309000825
+:1005B0001D0800087F080008A7080008CD080008EB
+:1005C0005B050008DF0800085B050008510900080A
+:1005D0008D0600085B05000895090008F90500086C
+:1005E0008D0600085B0500087F0800080220FFF761
+:1005F000CDFE002840F0F581009B0221BAF1000FEA
+:1006000008BF1C4605A841F21233ADF8143000F0C3
+:100610004BFAA2E74FF47A7000F028FA071EEBDBE2
+:100620000220FFF7B3FE0028E6D0013F052F00F2BD
+:10063000DA81DFE807F0030A0D101336052305936E
+:10064000042105A800F030FA17E054480421F9E726
+:1006500058480421F6E758480421F3E74FF01C08F6
+:10066000404600F053FA08F104080590042105A85B
+:1006700000F01AFAB8F12C0FF2D1012000FA07F7B6
+:1006800047EA0B0B5FFA8BFB4FF0000900F07CFB95
+:1006900026B10BF00B030B2B08BF0024FFF77EFEE7
+:1006A0005BE746480421CDE7002EA5D00BF00B03F5
+:1006B0000B2BA1D10220FFF769FE074600289BD033
+:1006C000012000F021FA0220FFF7B0FE00265FFAB9
+:1006D00086F8404600F028FA044690B100214046D2
+:1006E00000F032FA01360028F1D1BA46044641F250
+:1006F0001213022105A8ADF814303E4600F0D4F9DB
+:100700002BE70120FFF792FE2546244B9B68AB4266
+:1007100007D9284600F0FAF9013040F06781043526
+:10072000F3E7234B00251D70204BBA465D603E4623
+:10073000ACE7002E3FF460AF0BF00B030B2B7FF404
+:100740005BAF0220FFF772FE322000F08FF9B0F1AC
+:100750000008FFF651AF18F003077FF44DAF0F4AC2
+:10076000926808EB050393423FF646AFB8F5807FE9
+:100770003FF742AF124B0193B84523DD4FF47A7037
+:1007800000F074F90390039A002AFFF635AF019B3D
+:10079000039A03F8012B0137EDE700BF0022002088
+:1007A0006C23002050220020B50300087023002095
+:1007B0006822002004220020082200200C220020B1
+:1007C0006C220020C820FFF7E1FD074600283FF417
+:1007D00013AF1F2D11D8C5F1200242450AAB25F0F9
+:1007E000030028BF424683490192184400F05AFA98
+:1007F000019A8048FF2100F07BFA4FEAA8037D4967
+:100800000193C8F38702284600F07AFA06460028CA
+:100810003FF46DAF019B05EB830537E70220FFF73F
+:10082000B5FD00283FF4E8AE00F0BAF900283FF427
+:10083000E3AE0027B846704B9B68BB4218D91F2F08
+:1008400011D80A9B01330ED027F0030312AA1344D8
+:1008500053F8203C05934046042205A900F000FB14
+:1008600004378046E7E7384600F050F90590F2E794
+:10087000CDF81480042105A800F016F906E700233E
+:10088000642104A8049300F005F900287FF4B4AEB5
+:100890000220FFF77BFD00283FF4AEAE049800F085
+:1008A00067F90590E6E70023642104A8049300F0AB
+:1008B000F1F800287FF4A0AE0220FFF767FD0028C2
+:1008C0003FF49AAE049800F063F9EAE70220FFF7DC
+:1008D0005DFD00283FF490AE00F072F9E1E70220E0
+:1008E000FFF754FD00283FF487AE05A9142000F05F
+:1008F0006DF904210746049004A800F0D5F83946A4
+:10090000B9E7322000F0B2F8071EFFF675AEBB075C
+:100910007FF472AE384A926807EB090393423FF6C0
+:100920006BAE0220FFF732FD00283FF465AE27F0E2
+:1009300003074F44B9453FF4A9AE484600F0E6F836
+:100940000421059005A800F0AFF809F10409F1E7CA
+:100950004FF47A70FFF71AFD00283FF44DAE00F017
+:100960001FF9002844D00A9B01330BD008220AA9A2
+:10097000002000F0C5F900283AD02022FF210AA863
+:1009800000F0B6F9FFF70AFD1C4801F08DFA13B02C
+:10099000BDE8F08F002E3FF42FAE0BF00B030B2BB6
+:1009A0007FF42AAE0023642105A8059300F072F8B5
+:1009B000074600287FF420AE0220FFF7E7FC8046C0
+:1009C00000283FF419AEFFF7E9FC41F2883001F04E
+:1009D0006BFA059800F022FA464600F0D5F93C463D
+:1009E000BBE5064652E64FF0000905E6BA467EE64C
+:1009F00037467CE66C22002000220020A086010001
+:100A00002DE9F84F4FF47A73DFF85880DFF85890EB
+:100A100006460D4602FB03F7002498F900305A1CE5
+:100A20005FFA84FA01D0A34212D159F82400036876
+:100A30002A46D3F820B031463B46D847854207D1F5
+:100A4000074B012083F800A0BDE8F88F0124E4E7FC
+:100A5000002CFBD04FF4FA7001F026FA0020F3E7E7
+:100A6000B8230020102200201422002007B5002304
+:100A7000024601210DF107008DF80730FFF7C0FF96
+:100A800020B19DF8070003B05DF804FB4FF0FF3084
+:100A9000F9E700000A4608B50421FFF7B1FF80F02E
+:100AA0000100C0B2404208BD30B4074B0A46197875
+:100AB000064B53F821402368DD69054B0146AC46DF
+:100AC000204630BC604700BFB8230020142200201D
+:100AD000A086010070B501F007FD094E094D308078
+:100AE000002428683388834208D901F0F7FC2B687A
+:100AF00004440133B4F5803F2B60F2D370BD00BFD6
+:100B0000BA2300207823002001F0B0BD00F100607E
+:100B100000F580300068704700F10060920000F539
+:100B2000803001F02FBD0000054B1A68054B1B8873
+:100B30009B1A834202D9104401F0D0BC00207047B8
+:100B400078230020BA23002038B5084D044629B187
+:100B500028682044BDE8384001F0E0BC2868204403
+:100B600001F0C4FC0028F3D038BD00BF782300207A
+:100B700010F003030AD1B0F5047F05D200F1005054
+:100B8000A0F51040D0F80038184670470023FBE766
+:100B900000F10050A0F51040D0F8100A7047000096
+:100BA000064991F8243033B10023086A81F82430D3
+:100BB0000822FFF7B1BF0120704700BF7C2300204F
+:100BC000014B1868704700BF002004E070B5194B56
+:100BD0001D68194B0138C5F30B0408442D0C042281
+:100BE0001E88A6420BD15C680A46013C824213462D
+:100BF0000FD214F9016F4EB102F8016BF6E7013A1A
+:100C000003F10803ECD181420B4602D22C2203F8F7
+:100C1000012B0A4A05241688AE4204D1984284BFAB
+:100C2000967803F8016B013C02F10402F3D1581AE3
+:100C300070BD00BF002004E0683B0008543B000882
+:100C4000022804D1054B4FF000529A6170470128E9
+:100C5000FCD1024B4FF00042F7E700BF0008024012
+:100C6000022804D1054B4FF400529A6170470128C5
+:100C7000FCD1024B4FF40042F7E700BF00080240EE
+:100C8000022805D1064A536983F400535361704723
+:100C90000128FCD1024A536983F40043F6E700BF00
+:100CA0000008024010B50023934203D0CC5CC4542A
+:100CB0000133F9E710BD000010B5013810F9013F0C
+:100CC0003BB191F900409C4203D11AB10131013A84
+:100CD000F4E71AB191F90020981A10BD1046FCE70C
+:100CE00003460246D01A12F9011B0029FAD17047B7
+:100CF00002440346934202D003F8011BFAE770470F
+:100D00002DE9F8431F4D144695F8242007468846E0
+:100D100052BBDFF870909CB395F824302BB9202299
+:100D2000FF2148462F62FFF7E3FF95F82400C0F14A
+:100D30000802A24228BF2246D6B24146920005EBE5
+:100D40008000FFF7AFFF95F82430A41B1E44F6B2D5
+:100D5000082E17449044E4B285F82460DBD1FFF7F5
+:100D60001FFF0028D7D108E02B6A03EB82038342E0
+:100D7000CFD0FFF715FF0028CBD10020BDE8F883C6
+:100D80000120FBE77C230020024B1A78024B1A70EB
+:100D9000704700BFB82300201022002038B5194C3E
+:100DA000194D204600F0C0FB2946204600F0E8FB24
+:100DB0002D6816486A6DD2F8043843F00203C2F871
+:100DC000043801F071F81249284600F0DFFC6A6D22
+:100DD000104DD2F8043828680F4923F00203C2F8F6
+:100DE0000438A0424FF4E1330B6001D000F0FCFA6C
+:100DF0006868A04204D0BDE83840074900F0F4BA62
+:100E000038BD00BF98280020703C000840420F0009
+:100E1000783C000814220020A423002070B50C4B5D
+:100E20000C4D1E780C4B55F826209A4204460DD0E6
+:100E30000A4B002114221846FFF75AFF04600146AE
+:100E400055F82600BDE8704000F0CEBA70BD00BF76
+:100E5000B82300201422002098280020A42300207A
+:100E600030B5094D0A4491420DD011F8013B58406C
+:100E7000082340F30004013B2C4013F0FF0384EAF5
+:100E80005000F6D1EFE730BD2083B8ED026843682B
+:100E90001143016003B1184770470000024AD3684C
+:100EA00043F0C003D36070470010014010B5084CF8
+:100EB000084A0021204600F075FA074BC4F85C325E
+:100EC00003F1454303F52D43C4F8603210BD00BF64
+:100ED000BC2300209D0E000800100140234A037C23
+:100EE000002918BF0A46012B30B5C0F868220CD182
+:100EF0001F4B984209D11F4B596C41F010015964A6
+:100F0000596E41F0100159665B6EB2F904501468D5
+:100F1000D0F86032D0F85C12002D03EB5403B3FB21
+:100F2000F4F3BEBF23F0070503F0070343EA4503CC
+:100F300094888B60D38843F040030B61138943F09E
+:100F400001034B6144F4045343F02C03CB6004F4DD
+:100F5000A05400230B60B4F5806F0B684B680CBF86
+:100F60007F23FF2380F8643230BD00BF883B000838
+:100F7000BC230020003802402DE9F041D0F85C622B
+:100F8000F7683368DA0504469DB20DD5302383F344
+:100F900011884FF480610430FFF778FF6FF480739D
+:100FA0003360002383F31188302383F3118804F125
+:100FB000040815F02F033AD183F31188380615D5AC
+:100FC000290613D5302383F3118804F1380000F08B
+:100FD00065F900284EDA0821201DFFF757FF4FF66C
+:100FE0007F733B40F360002383F311887A0616D5A4
+:100FF0006B0614D5302383F31188D4E913239A4266
+:101000000AD1236C43B127F040073F041021201D73
+:101010003F0CFFF73BFFF760002383F31188D4F800
+:101020006822D36843B3BDE8F041106918472B0725
+:1010300014D015F0080F0CBF00214FF48071E807A1
+:1010400048BF41F02001AA0748BF41F040016B07AB
+:1010500048BF41F080014046FFF718FFAD067368B6
+:1010600005D594F864122046194000F0CBF9356894
+:10107000ADB29EE77060B6E7BDE8F081F8B5154601
+:1010800082680669AA420B46816938BF8568761A6C
+:10109000B54204460BD218462A46FFF703FEA36961
+:1010A0002B44A361A3685B1BA3602846F8BD0CD941
+:1010B00018463246FFF7F6FDAF1BE1683A4630446A
+:1010C000FFF7F0FDE3683B44EBE718462A46FFF7DD
+:1010D000E9FDE368E5E7000083689342F7B515464C
+:1010E000044638BF8568D0E90460361AB5420BD291
+:1010F0002A46FFF7D7FD63692B446361A36828463E
+:101100005B1BA36003B0F0BD0DD932460191FFF720
+:10111000C9FD0199E068AF1B3A463144FFF7C2FDB3
+:10112000E3683B44E9E72A46FFF7BCFDE368E4E7F0
+:1011300010B50A440024C361029B8460C0E900002A
+:10114000C0E90511C1600261036210BD08B5D0E9B4
+:101150000532934201D1826882B98268013282608D
+:101160005A1C42611970D0E904329A4224BFC36804
+:101170004361002100F0B4FE002008BD4FF0FF30B5
+:10118000FBE7000070B5302304460E4683F3118858
+:10119000A568A5B1A368A269013BA360531CA36124
+:1011A00015782269934224BFE368A361E3690BB118
+:1011B00020469847002383F31188284607E03146EC
+:1011C000204600F07DFE0028E2DA85F3118870BD2C
+:1011D0002DE9F74F04460E4617469846D0F81C9066
+:1011E0004FF0300A8AF311884FF0000B154665B1B5
+:1011F0002A4631462046FFF741FF034660B9414683
+:10120000204600F05DFE0028F1D0002383F3118812
+:10121000781B03B0BDE8F08FB9F1000F03D0019047
+:101220002046C847019B8BF31188ED1A1E448AF3B0
+:101230001188DCE7C0E90511C160C3611144009B5E
+:101240008260C0E90000016103627047F8B504469E
+:101250000D461646302383F31188A768A7B1A3680B
+:10126000013BA36063695A1C62611D70D4E90432BA
+:101270009A4224BFE3686361E3690BB12046984753
+:10128000002080F3118807E03146204600F018FE68
+:101290000028E2DA87F31188F8BD0000D0E90523C1
+:1012A0009A4210B501D182687AB9826801328260AF
+:1012B0005A1C82611C7803699A4224BFC368836107
+:1012C000002100F00DFE204610BD4FF0FF30FBE77F
+:1012D0002DE9F74F04460E4617469846D0F81C9065
+:1012E0004FF0300A8AF311884FF0000B154665B1B4
+:1012F0002A4631462046FFF7EFFE034660B94146D5
+:10130000204600F0DDFD0028F1D0002383F3118892
+:10131000781B03B0BDE8F08FB9F1000F03D0019046
+:101320002046C847019B8BF31188ED1A1E448AF3AF
+:101330001188DCE7026843681143016003B1184774
+:10134000704700001430FFF743BF00004FF0FF3339
+:101350001430FFF73DBF00003830FFF7B9BF000081
+:101360004FF0FF333830FFF7B3BF00001430FFF702
+:1013700009BF00004FF0FF311430FFF703BF00003A
+:101380003830FFF763BF00004FF0FF323830FFF70F
+:101390005DBF0000012914BF6FF0130000207047EB
+:1013A000FFF784BD37B515460E4A02600022426041
+:1013B000C0E902220122044602740B46009000F1AB
+:1013C0005C014FF480721430FFF7B2FE00942B469C
+:1013D0004FF4807204F5AE7104F13800FFF72AFF74
+:1013E00003B030BD9C3B000810B53023044683F3A6
+:1013F0001188FFF773FD02232374002080F3118806
+:1014000010BD000038B5C36904460D461BB9042160
+:101410000844FFF78FFF294604F11400FFF796FEFA
+:10142000002806DA201D4FF40061BDE83840FFF7C0
+:1014300081BF38BD026843681143016003B118479A
+:101440007047000013B5446BD4F894341A681178CF
+:10145000042915D1217C022912D11979128901237D
+:101460008B4013420CD101A904F14C0001F032FF72
+:10147000D4F89444019B21790246206800F0D0F909
+:1014800002B010BD143001F0B5BE00004FF0FF33C4
+:10149000143001F0AFBE00004C3001F087BF0000F7
+:1014A0004FF0FF334C3001F081BF0000143001F0E9
+:1014B00083BE00004FF0FF31143001F07DBE00000C
+:1014C0004C3001F053BF00004FF0FF324C3001F0C0
+:1014D0004DBF00000020704710B5D0F894341A6852
+:1014E00011780429044617D1017C022914D15979B5
+:1014F000528901238B4013420ED1143001F016FEA5
+:10150000024648B1D4F894444FF48073617920685E
+:10151000BDE8104000F072B910BD0000406BFFF74D
+:10152000DBBF0000704700007FB5124B0360002353
+:101530004360C0E90233012502260F4B05740446BF
+:101540000290019300F18402294600964FF48073C3
+:10155000143001F0C7FD094B0294CDE9006304F596
+:1015600023724FF48073294604F14C0001F08EFE83
+:1015700004B070BDC43B00081D15000845140008E8
+:101580000B68302282F311880A7903EB82029061A2
+:101590004A79093243F822008A7912B103EB8203B7
+:1015A00098610223C0F894140374002080F311881A
+:1015B0007047000038B5037F044613B190F85430EB
+:1015C000ABB9201D01250221FFF734FF04F11400FF
+:1015D00025776FF0010100F08FFC84F8545004F17E
+:1015E0004C006FF00101BDE8384000F085BC38BD0B
+:1015F00010B5012104460430FFF71CFF00232377B8
+:1016000084F8543010BD000038B50446002514306D
+:1016100001F080FD04F14C00257701F04FFE201D04
+:1016200084F854500121FFF705FF2046BDE83840FB
+:10163000FFF752BF90F8443003F06003202B07D12E
+:1016400090F84520212A4FF0000303D81F2A06D81E
+:1016500000207047222AFBD1C0E90E3303E0034A81
+:1016600082630722C2630364012070471C220020AA
+:1016700037B5D0F894341A681178042904461AD181
+:10168000017C022917D11979128901238B40134259
+:1016900011D100F14C05284601F0D0FE58B101A946
+:1016A000284601F017FED4F89444019B21790246A4
+:1016B000206800F0B5F803B030BD0000F0B500EBD5
+:1016C000810385B09E6904460D46FEB1302383F345
+:1016D000118804EB8507301D0821FFF7ABFEFB687E
+:1016E0005B691B6806F14C001BB1019001F000FE24
+:1016F000019803A901F0EEFD024648B1039B29467B
+:10170000204600F08DF8002383F3118805B0F0BD6A
+:10171000FB685A691268002AF5D01B8A013B134006
+:10172000F1D104F14402EAE7093138B550F821401B
+:10173000DCB1302383F31188D4F8942413685279F0
+:1017400003EB8203DB689B695D6845B10421601887
+:10175000FFF770FE294604F1140001F0F1FC204669
+:10176000FFF7BAFE002383F3118838BD70470000ED
+:1017700001F050B8012303700023C0E90133C361B5
+:1017800083620362C36243620363704738B50446F1
+:10179000302383F311880025C0E90355C0E90555BE
+:1017A000416001F047F80223237085F31188284631
+:1017B00038BD000070B500EB810305465069DA6062
+:1017C0000E46144618B110220021FFF791FAA069C5
+:1017D00018B110220021FFF78BFA31462846BDE8E8
+:1017E000704001F0F1B80000826802F001128260DE
+:1017F0000022C0E90422826101F072B9F0B400EB6A
+:1018000081044789E4680125A4698D403D434581F1
+:1018100023600023A2606360F0BC01F08DB900007A
+:10182000F0B400EB81040789E468012564698D4008
+:101830003D43058123600023A2606360F0BC01F09A
+:1018400007BA000070B50223002504460370C0E902
+:101850000255C0E90455C564856180F8345001F033
+:101860004FF863681B6823B129462046BDE87040E5
+:10187000184770BD0378052B10B504460AD080F8D0
+:1018800050300523037043681B680BB1042198474F
+:101890000023A36010BD00000178052906D190F84F
+:1018A0005020436802701B6803B11847704700005E
+:1018B00070B590F83430044613B1002380F834300A
+:1018C00004F14402204601F02DF963689B68B3B926
+:1018D00094F8443013F0600535D00021204601F023
+:1018E000CDFB0021204601F0BFFB63681B6813B1EC
+:1018F000062120469847062384F8343070BD2046E0
+:1019000098470028E4D0B4F84A30E26B9A4288BF86
+:10191000E36394F94430E56B002B4FF0300380F221
+:101920000381002D00F0F280092284F8342083F333
+:1019300011880021D4E90E232046FFF771FF002310
+:1019400083F31188DAE794F8452003F07F0343EA34
+:10195000022340F20232934200F0C58021D8B3F551
+:10196000807F48D00DD8012B3FD0022B00F0938010
+:10197000002BB2D104F14C02A2630222E263236481
+:10198000C1E7B3F5817F00F09B80B3F5407FA4D120
+:1019900094F84630012BA0D1B4F84C3043F0020348
+:1019A00032E0B3F5006F4DD017D8B3F5A06F31D04A
+:1019B000A3F5C063012B90D8636894F846205E6855
+:1019C00094F84710B4F848302046B047002884D037
+:1019D0004368A3630368E3631AE0B3F5106F36D07E
+:1019E00040F6024293427FF478AF5C4BA36302233C
+:1019F000E3630023C3E794F84630012B7FF46DAF17
+:101A0000B4F84C3023F00203C4E90E55A4F84C306E
+:101A1000256478E7B4F84430B3F5A06F0ED194F89C
+:101A2000463084F84E30204600F0C2FF63681B68E1
+:101A300013B1012120469847032323700023C4E9F2
+:101A40000E339CE704F14F03A3630123C3E723781C
+:101A5000042B10D1302383F311882046FFF7C4FEF6
+:101A600085F311880321636884F84F5021701B6847
+:101A70000BB12046984794F84630002BDED084F80E
+:101A80004F300423237063681B68002BD6D00221DB
+:101A900020469847D2E794F848301D0603F00F011E
+:101AA00020460AD501F030F8012804D002287FF43E
+:101AB00014AF2B4B9AE72B4B98E701F017F8F3E79D
+:101AC00094F84630002B7FF408AF94F8483013F0B8
+:101AD0000F01B3D01A06204602D501F0E3FAADE7B4
+:101AE00001F0D6FAAAE794F84630002B7FF4F5AE61
+:101AF00094F8483013F00F01A0D01B06204602D501
+:101B000001F0BCFA9AE701F0AFFA97E7142284F8E3
+:101B1000342083F311882B462A4629462046FFF7B6
+:101B20006DFE85F31188E9E65DB1152284F8342055
+:101B300083F311880021D4E90E232046FFF75EFECF
+:101B4000FDE60B2284F8342083F311882B462A46C5
+:101B500029462046FFF764FEE3E700BFF43B000898
+:101B6000EC3B0008F03B000838B590F834300446F0
+:101B7000002B3ED0063BDAB20F2A34D80F2B32D8D6
+:101B8000DFE803F037313108223231313131313180
+:101B900031313737C56BB0F84A309D4214D2C36833
+:101BA0001B8AB5FBF3F203FB12556DB9302383F3A7
+:101BB00011882B462A462946FFF732FE85F3118805
+:101BC0000A2384F834300EE0142384F834303023B0
+:101BD00083F3118800231A4619462046FFF70EFEAC
+:101BE000002383F3118838BD036C03B198470023A9
+:101BF000E7E70021204601F041FA0021204601F0EC
+:101C000033FA63681B6813B1062120469847062300
+:101C1000D7E7000010B590F83430142B044629D0D3
+:101C200017D8062B05D001D81BB110BD093B022BDC
+:101C3000FBD80021204601F021FA0021204601F0C6
+:101C400013FA63681B6813B10621204698470623E0
+:101C500019E0152BE9D10B2380F83430302383F3BE
+:101C6000118800231A461946FFF7DAFD002383F393
+:101C70001188DAE7C3689B695B68002BD5D1036CD8
+:101C800003B19847002384F83430CEE7002303756E
+:101C9000826803691B6899689142FBD25A680360A5
+:101CA00042601060586070470023037582680369C2
+:101CB0001B6899689142FBD85A68036042601060C3
+:101CC0005860704708B50846302383F311880B7DB0
+:101CD000032B05D0042B0DD02BB983F3118808BD3D
+:101CE0008B6900221A604FF0FF338361FFF7CEFF4C
+:101CF0000023F2E7D1E9003213605A60F3E70000F5
+:101D0000FFF7C4BF054BD9680875186802681A60E8
+:101D1000536001220275D860FEF7F4BA282600202D
+:101D200030B50C4BDD684B1C87B004460FD02B46FA
+:101D3000094A684600F074F92046FFF7E3FF009B6C
+:101D400013B1684600F076F9A86907B030BDFFF717
+:101D5000D9FFF9E728260020C51C0008044B1A68A3
+:101D6000DB6890689B68984294BF00200120704710
+:101D700028260020084B10B51C68D86822681A6015
+:101D8000536001222275DC60FFF78EFF014620467A
+:101D9000BDE81040FEF7B6BA28260020044B1A68AA
+:101DA000DB6892689B689A4201D9FFF7E3BF7047EE
+:101DB0002826002038B5074C07490848012300258C
+:101DC0002370656001F072FB0223237085F3118894
+:101DD00038BD00BF90280020FC3B000828260020CA
+:101DE00000F05EB9EFF3118020B9EFF305833022E4
+:101DF00082F311887047000010B530B9EFF3058405
+:101E0000C4F3080414B180F3118810BDFFF7C6FFB6
+:101E100084F31188F9E70000034A516853685B1A9C
+:101E20009842FBD8704700BF001000E08B6002238F
+:101E300008618B82084670478368A3F1840243F8E7
+:101E4000142C026943F8442C426943F8402C094A97
+:101E500043F8242CC26843F8182C022203F80C2CF7
+:101E6000002203F80B2C044A43F8102CA3F12000A5
+:101E7000704700BF1D0300082826002008B5FFF7A3
+:101E8000DBFFBDE80840FFF73BBF0000024BDB680B
+:101E900098610F20FFF736BF28260020302383F3F8
+:101EA0001188FFF7F3BF000008B50146302383F324
+:101EB00011880820FFF734FF002383F3118808BD41
+:101EC000064BDB6839B1426818605A6013604360A2
+:101ED0000420FFF725BF4FF0FF3070472826002071
+:101EE0000368984206D01A680260506099611846EB
+:101EF000FFF706BF7047000038B504460D4620685E
+:101F0000844200D138BD036823605C608561FFF7BF
+:101F1000F7FEF4E710B503689C68A2420CD85C6831
+:101F20008A600B604C602160596099688A1A9A60D7
+:101F30004FF0FF33836010BD1B68121BECE70000FD
+:101F40000A2938BF0A2170B504460D460A266019D1
+:101F500001F0A6FA01F092FA041BA54203D8751C01
+:101F60002E460446F3E70A2E04D9BDE8704001204E
+:101F700001F0DCBA70BD0000F8B5144B0D46D96114
+:101F800003F1100141600A2A1969826038BF0A22F0
+:101F9000016048601861A818144601F073FA0A2716
+:101FA00001F06CFA431BA342064606D37C1C281999
+:101FB00001F076FA27463546F2E70A2F04D9BDE844
+:101FC000F840012001F0B2BAF8BD00BF2826002079
+:101FD000F8B506460D4601F051FA0F4A134653F87C
+:101FE000107F9F4206D12A4601463046BDE8F840A0
+:101FF000FFF7C2BFD169BB68441A2C1928BF2C4611
+:10200000A34202D92946FFF79BFF224631460348E7
+:10201000BDE8F840FFF77EBF2826002038260020C4
+:1020200010B4C0E9032300235DF8044B4361FFF7BC
+:10203000CFBF000010B5194C236998420DD0D0E9EC
+:102040000032816813605A609A680A449A600023DB
+:1020500003604FF0FF33A36110BD2346026843F8CD
+:10206000102F53600022026022699A4203D1BDE81A
+:10207000104001F00FBA936881680B44936001F03F
+:10208000FDF92269E1699268441AA242E4D9114437
+:10209000BDE81040091AFFF753BF00BF28260020F3
+:1020A0002DE9F047DFF8BC8008F110072C4ED8F876
+:1020B000105001F0E3F9D8F81C40AA68031B9A42BB
+:1020C0003ED81444D5E900324FF00009C8F81C404E
+:1020D00013605A60C5F80090D8F81030B34201D1AF
+:1020E00001F0D8F989F31188D5E9033128469847DA
+:1020F000302383F311886B69002BD8D001F0BEF92F
+:102100006A69A0EB04094A4582460DD2022001F01B
+:102110000DFA0022D8F81030B34208D151462846B3
+:10212000BDE8F047FFF728BF121A2244F2E712EB8E
+:10213000090938BF4A4629463846FFF7EBFEB5E79E
+:10214000D8F81030B34208D01444211AC8F81C0043
+:10215000A960BDE8F047FFF7F3BEBDE8F08700BF18
+:10216000382600202826002000207047FEE70000C7
+:10217000704700004FF0FF307047000002290CD07C
+:10218000032904D00129074818BF00207047032AFB
+:1021900005D8054800EBC20070470448704700208E
+:1021A000704700BFD43C00082C220020883C000867
+:1021B00070B59AB00546084601A9144600F0C2F869
+:1021C00001A8FEF78DFD431C5B00C5E90034002229
+:1021D000237003236370C6B201AB02341046D1B240
+:1021E0008E4204F1020401D81AB070BD13F8011B2D
+:1021F00004F8021C04F8010C0132F0E708B53023A2
+:1022000083F311880348FFF733FA002383F311881F
+:1022100008BD00BF9828002090F8443003F01F024A
+:10222000012A07D190F845200B2A03D10023C0E9E9
+:102230000E3315E003F06003202B08D1B0F84830CE
+:102240002BB990F84520212A03D81F2A04D8FFF77C
+:10225000F1B9222AEBD0FAE7034A82630722C2636C
+:1022600003640120704700BF2322002007B5052921
+:1022700017D8DFE801F0191603191920302383F36A
+:102280001188104A01900121FFF794FA01980E4A33
+:102290000221FFF78FFA0D48FFF7B6F9002383F309
+:1022A000118803B05DF804FB302383F311880748DD
+:1022B000FFF780F9F2E7302383F311880348FFF733
+:1022C00097F9EBE7283C00084C3C000898280020D0
+:1022D00038B50C4D0C4C0D492A4604F10800FFF7A7
+:1022E00067FF05F1CA0204F110000949FFF760FF1A
+:1022F00005F5CA7204F118000649BDE83840FFF739
+:1023000057BF00BF602D00202C220020083C000891
+:10231000123C00081D3C000870B5044608460D46F6
+:10232000FEF7DEFCC6B22046013403780BB918462E
+:1023300070BD32462946FEF7BFFC0028F3D10120CC
+:10234000F6E700002DE9F04705460C46FEF7C8FC0D
+:102350002B49C6B22846FFF7DFFF08B10736F6B2B1
+:1023600028492846FFF7D8FF08B11036F6B2632E89
+:102370000BD8DFF88C80DFF88C90234FDFF894A027
+:102380002E7846B92670BDE8F08729462046BDE87C
+:10239000F04701F0C1BB252E2ED107224146284629
+:1023A000FEF78AFC70B9194B224603F10C0153F871
+:1023B000040B42F8040B8B42F9D11B8813800735BC
+:1023C0000E34DDE7082249462846FEF775FC98B929
+:1023D0000F4BA21C197809090232C95D02F8041CCE
+:1023E00013F8011B01F00F015345C95D02F8031CEE
+:1023F000F0D118340835C3E704F8016B0135BFE7A5
+:10240000F43C00081D3C00080B3D0008FC3C0008A3
+:10241000107AFF1F1C7AFF1FBFF34F8F024AD36849
+:10242000DB03FCD4704700BF003C024008B5094BF9
+:102430001B7873B9FFF7F0FF074B1A69002ABFBF7B
+:10244000064A5A6002F188325A601A6822F48062A1
+:102450001A6008BDBE2F0020003C024023016745E2
+:1024600008B50B4B1B7893B9FFF7D6FF094B1A69D8
+:1024700042F000421A611A6842F480521A601A68E7
+:1024800022F480521A601A6842F480621A6008BD11
+:10249000BE2F0020003C02400B28F0B516D80C4C93
+:1024A0000C4923787BB90C4D0E460C234FF000628B
+:1024B00055F8047B46F8042B013B13F0FF033A4424
+:1024C000F6D10123237051F82000F0BD0020FCE775
+:1024D000F02F0020C02F00201C3D0008014B53F8B6
+:1024E000200070471C3D00080C2070470B2810B5D9
+:1024F000044601D9002010BDFFF7CEFF064B53F86C
+:1025000024301844C21A0BB90120F4E712680132D2
+:10251000F0D1043BF6E700BF1C3D00080B2838B59E
+:10252000044628D8FFF75EFCFFF776FFFFF77EFF33
+:10253000124AF323D360E300DBB243F4007343F0A9
+:1025400002031361136943F4803313610546204687
+:10255000FFF762FFFFF7A0FF094B53F8241000F0CC
+:10256000E9F82846FFF77CFFFFF746FC2046BDE868
+:102570003840FFF7BBBF002038BD00BF003C024021
+:102580001C3D000812F001032DE9F04105460E46FE
+:1025900014464BD18218B2F1016F61D8314B1B68E0
+:1025A00013F001035CD0304FFFF71CFCFFF73EFF38
+:1025B000F323FB60FFF730FF314640F20128032C84
+:1025C00018D824F00104284E0C446D1A40F201186A
+:1025D000A142336905EB01072AD123F001033361DE
+:1025E000FFF73EFFFFF708FC0120BDE8F081043C47
+:1025F0000435E4E7AB07E4D13B6923F440733B6166
+:102600003B6943EA08033B6151F8046B2E60BFF35A
+:102610004F8FFFF701FF2B689E42E8D03B6923F004
+:1026200001033B61FFF71CFFFFF7E6FB0020DCE73F
+:1026300023F440733361336943EA080333610B8841
+:102640003B80BFF34F8FFFF7E7FE3F8831F8023B37
+:10265000BFB2BB42BCD0336923F001033361E1E771
+:102660001846C2E700380240003C0240084908B55D
+:102670000B7828B11BB9FFF7D9FE01230B7008BDF9
+:10268000002BFCD0BDE808400870FFF7E9BE00BF92
+:10269000BE2F002010B50244064BD2B2904200D1AA
+:1026A00010BD441C00B253F8200041F8040BE0B206
+:1026B000F4E700BF502800400F4B30B51C6F2404D6
+:1026C00007D41C6F44F400741C671C6F44F400446E
+:1026D0001C670A4C236843F4807323600244084B50
+:1026E000D2B2904200D130BD441C00B251F8045B1C
+:1026F00043F82050E0B2F4E7003802400070004098
+:102700005028004007B5012201A90020FFF7C2FFB1
+:10271000019803B05DF804FB13B50446FFF7F2FF20
+:10272000A04205D0012201A900200194FFF7C4FFB7
+:1027300002B010BD70470000034B1A681AB9034A73
+:10274000D2F874281A607047F42F0020003002403D
+:1027500008B5FFF7F1FF024B1868C0F3407008BDE1
+:10276000F42F002070470000FEE700000A4B0B48E2
+:102770000B4A90420BD30B4BDA1C121AC11E22F0EB
+:1027800003028B4238BF00220021FEF7B1BA53F892
+:10279000041B40F8041BECE7D43E0008F030002096
+:1027A000F0300020F030002070B5D0E915439E686D
+:1027B00000224FF0FF3504EB42135101D3F800091A
+:1027C0000028BEBFD3F8000940F08040C3F80009DC
+:1027D000D3F8000B0028BEBFD3F8000B40F08040B8
+:1027E000C3F8000B013263189642C3F80859C3F8C6
+:1027F000085BE0D24FF00113C4F81C3870BD000034
+:10280000890141F02001016103699B06FCD412207B
+:10281000FFF702BB10B5054C2046FEF7ABFF4FF0AB
+:10282000A0436365024BA36510BD00BFF82F0020D5
+:10283000703D000870B50378012B054650D12A4B36
+:10284000446D98421BD1294B5A6B42F080025A6367
+:102850005A6D42F080025A655A6D5A6942F0800200
+:102860005A615A6922F080025A610E2143205B6945
+:1028700000F022FC1E4BE3601E4BC4F8003800231E
+:10288000C4F8003EC02323606E6D4FF40413A363AD
+:102890003369002BFCDA012333610C20FFF7BCFA0B
+:1028A0003369DB07FCD41220FFF7B6FA3369002B3B
+:1028B000FCDA0026A6602846FFF776FF6B68C4F8AE
+:1028C0001068DB68C4F81468C4F81C684BB90A4B7C
+:1028D000A3614FF0FF336361A36843F00103A3607A
+:1028E00070BD064BF4E700BFF82F0020003802400F
+:1028F0004014004003002002003C30C0083C30C0BF
+:10290000F8B5446D054600212046FFF779FFA96D13
+:1029100000234FF001128F68C4F834384FF000667E
+:10292000C4F81C284FF0FF3004EB431201339F42E0
+:10293000C2F80069C2F8006BC2F80809C2F8080BB7
+:10294000F2D20B686A6DEB6563621023136116693E
+:1029500016F01006FBD11220FFF75EFAD4F800380B
+:1029600023F4FE63C4F80038A36943F4402343F022
+:102970001003A3610923C4F81038C4F814380A4BB3
+:10298000EB604FF0C043C4F8103B084BC4F8003B69
+:10299000C4F81069C4F80039EB6D03F1100243F478
+:1029A0008013EA65A362F8BD4C3D0008408000102A
+:1029B000426D90F84E10D2F8003823F4FE6343EADB
+:1029C0000113C2F8003870472DE9F84300EB81038A
+:1029D000456DDA68166806F00306731E022B05EBD8
+:1029E00041130C4680460FFA81F94FEA41104FF02F
+:1029F0000001C3F8101B4FF0010104F1100398BF50
+:102A0000B60401FA03F391698EBF334E06F1805686
+:102A100006F5004600293AD0578A04F158014901C9
+:102A200037436F50D5F81C180B43C5F81C382B18CA
+:102A30000021C3F8101953690127611EA7409BB3F9
+:102A4000138A928B9B08012A88BF5343D8F85C20D5
+:102A5000981842EA034301F1400205EB8202C8F8EC
+:102A60005C00214653602846FFF7CAFE08EB890048
+:102A7000C3681B8A43EA8453483464011E432E51C1
+:102A8000D5F81C381F43C5F81C78BDE8F88305EB62
+:102A90004917D7F8001B21F40041C7F8001BD5F8EF
+:102AA0001C1821EA0303C0E704F13F0305EB83038D
+:102AB0000A4A5A6028462146FFF7A2FE05EB491054
+:102AC000D0F8003923F40043C0F80039D5F81C3899
+:102AD00023EA0707D7E700BF0080001000040002C8
+:102AE000826D1268C265FFF75FBE00005831436D0A
+:102AF00049015B5813F4004004D013F4001F0CBFCD
+:102B000002200120704700004831436D49015B58A5
+:102B100013F4004004D013F4001F0CBF0220012066
+:102B20007047000000EB8101CB68196A0B681360E5
+:102B30004B6853607047000000EB810330B5DD68DF
+:102B4000AA691368D36019B9402B84BF402313606E
+:102B50006B8A1468426D1C44013CB4FBF3F463437C
+:102B6000033323F0030302EB411043EAC44343F071
+:102B7000C043C0F8103B2B6803F00303012B09B2DC
+:102B80000ED1D2F8083802EB411013F4807FD0F850
+:102B9000003B14BF43F0805343F00053C0F8003BA8
+:102BA00002EB4112D2F8003B43F00443C2F8003B71
+:102BB00030BD00002DE9F041244D6E6D06EB401351
+:102BC0000446D3F8087BC3F8087B38070AD5D6F843
+:102BD0001438190706D505EB84032146DB6828461F
+:102BE0005B689847FA071FD5D6F81438DB071BD562
+:102BF00005EB8403D968CCB98B69488A5A68B2FB63
+:102C0000F0F600FB16228AB91868DA6890420DD2F5
+:102C1000121AC3E90024302383F311880B4821469C
+:102C2000FFF78AFF84F31188BDE8F081012303FADE
+:102C300004F26B8923EA02036B81CB68002BF3D08B
+:102C400021460248BDE8F041184700BFF82F002098
+:102C500000EB810370B5DD68436D6C692668E66042
+:102C60004A0156BB1A444FF40020C2F810092A68E2
+:102C700002F00302012A0AB20ED1D3F8080803EBCE
+:102C8000421410F4807FD4F8000914BF40F0805043
+:102C900040F00050C4F8000903EB4212D2F80009DA
+:102CA00040F00440C2F80009D3F83408012202FAC7
+:102CB00001F10143C3F8341870BD19B9402E84BF27
+:102CC0004020206020682E8A8419013CB4FBF6F471
+:102CD00040EAC44040F000501A44C6E72DE9F843EA
+:102CE0003B4D6E6D06EB40130446D3F80889C3F8DC
+:102CF000088918F0010F4FEA40171AD0D6F810389B
+:102D0000DB0716D505EB8003D9684B691868DA68CC
+:102D1000904230D2121A4FF000091A60C3F80490A2
+:102D2000302383F3118821462846FFF791FF89F36A
+:102D3000118818F0800F1CD0D6F834380126A64030
+:102D4000334216D005EB84036D6DD3F80CC0DCF86C
+:102D500014200134E4B2D2F800E005EB04342F442F
+:102D60005168714515D3D5F8343823EA0606C5F8FD
+:102D70003468BDE8F883012303FA04F22B8923EABF
+:102D800002032B818B68002BD3D02146284698471D
+:102D9000CFE7BCF81000AEEB0103834228BF034627
+:102DA000D7F8180980B2B3EB800FE2D89068A0F191
+:102DB000040959F8048FC4F80080A0EB090898446E
+:102DC000B8F1040FF5D818440B4490605360C7E77E
+:102DD000F82F00202DE9F74FA24C656D6E69AB69A5
+:102DE0001E4016F480586E6107D02046FEF72AFD7B
+:102DF00003B0BDE8F04F00F047BC002E12DAD5F862
+:102E0000003E98489B071EBFD5F8003E23F0030301
+:102E1000C5F8003ED5F8043823F00103C5F804389E
+:102E2000FEF73AFD370505D58E48FFF7BDFC8D4806
+:102E3000FEF720FDB0040CD5D5F8083813F0060FC6
+:102E4000EB6823F470530CBF43F4105343F4A053C6
+:102E5000EB6031071BD56368DB681BB9AB6923F0F6
+:102E60000803AB612378052B0CD1D5F8003E7D48D3
+:102E70009A071EBFD5F8003E23F00303C5F8003EB5
+:102E8000FEF70AFD6368DB680BB176489847F302EA
+:102E900074D4B70227D5D4F85490DFF8C8B100270E
+:102EA0004FF0010A09EB4712D2F8003B03F440232C
+:102EB000B3F5802F11D1D2F8003B002B0DDA6289D7
+:102EC0000AFA07F322EA0303638104EB8703DB6852
+:102ED000DB6813B1394658469847A36D01379B68A4
+:102EE000FFB29F42DED9F00617D5676D3A6AC2F38A
+:102EF0000A1002F00F0302F4F012B2F5802F00F076
+:102F00008580B2F5402F08D104EB83030022DB68F3
+:102F10001B6A07F5805790426AD13003D5F81848EC
+:102F200013D5E10302D50020FFF744FEA20302D52A
+:102F30000120FFF73FFE630302D50220FFF73AFEB0
+:102F4000270302D50320FFF735FE75037FF550AF49
+:102F5000E00702D50020FFF7C1FEA10702D501203E
+:102F6000FFF7BCFE620702D50220FFF7B7FE23077A
+:102F70007FF53EAF0320FFF7B1FE39E7636DDFF861
+:102F8000E4A0019300274FF00109A36D9B685FFA4D
+:102F900087FB9B453FF67DAF019B03EB4B13D3F8BB
+:102FA000001901F44021B1F5802F1FD1D3F8001989
+:102FB00000291BDAD3F8001941F09041C3F8001939
+:102FC000D3F800190029FBDB5946606DFFF718FCA8
+:102FD000218909FA0BF321EA0303238104EB8B0314
+:102FE000DB689B6813B15946504698470137CCE7D8
+:102FF000910708BFD7F80080072A98BF03F8018B14
+:1030000002F1010298BF4FEA182884E7023304EB6B
+:10301000830207F580575268D2F818C0DCF8082000
+:10302000DCE9001CA1EB0C0C002188420AD104EB66
+:10303000830463689B699A6802449A605A680244F0
+:103040005A606AE711F0030F08BFD7F800808C457B
+:1030500088BF02F8018B01F1010188BF4FEA1828EF
+:10306000E3E700BFF82F0020436D03EB4111D1F8D7
+:10307000003B43F40013C1F8003B7047436D03EB82
+:103080004111D1F8003943F40013C1F800397047F9
+:10309000436D03EB4111D1F8003B23F40013C1F859
+:1030A000003B7047436D03EB4111D1F8003923F425
+:1030B0000013C1F80039704700F1604303F5614324
+:1030C0000901C9B283F80013012200F01F039A40DE
+:1030D00043099B0003F1604303F56143C3F880217A
+:1030E0001A60704730B5039C0172043304FB03255A
+:1030F000C0E90653049B03630021059BC160C0E93E
+:103100000000C0E90422C0E90842C0E90A11436393
+:1031100030BD0000416A0022C0E90411C0E90A2262
+:10312000C2606FF00101FEF7E7BE0000D0E9043293
+:10313000934201D1C2680AB9181D70470020704738
+:1031400003691960C2680132C260C26913448269AE
+:103150000361934224BF436A03610021FEF7C0BEAE
+:1031600038B504460D46E3683BB16269131D126829
+:10317000A3621344E362002007E0237A33B92946AF
+:103180002046FEF79DFE0028EDDA38BD6FF0010005
+:10319000FBE70000C368C269013BC3604369134495
+:1031A00082694361934224BF436A4361002383627F
+:1031B000036B03B11847704770B53023044683F39F
+:1031C0001188866A3EB9FFF7CBFF054618B186F332
+:1031D0001188284670BDA36AE26A13F8015BA362F6
+:1031E000934202D32046FFF7D5FF002383F31188D3
+:1031F000EFE700002DE9F84F04460E4617469846C3
+:103200004FF0300989F311880025AA46D4F828B078
+:10321000BBF1000F09D141462046FFF7A1FF20B1C5
+:103220008BF311882846BDE8F88FD4E90A12A7EB82
+:10323000050B521A934528BF9346BBF1400F1BD98B
+:10324000334601F1400251F8040B43F8040B91425C
+:10325000F9D1A36A40334036A3624035D4E90A234A
+:103260009A4202D32046FFF795FF8AF31188BD42A8
+:10327000D8D289F31188C9E730465A46FDF712FDC6
+:10328000A36A5B445E44A3625D44E7E710B5029C19
+:103290000172043303FB0421C0E906130023C0E9D3
+:1032A0000A33039B0363049BC460C0E90000C0E9C8
+:1032B0000422C0E90842436310BD0000026AC260F4
+:1032C000426AC0E904220022C0E90A226FF001012B
+:1032D000FEF712BED0E904239A4201D1C26822B996
+:1032E000184650F8043B0B60704700231846FAE775
+:1032F000C368C2690133C36043691344826943618F
+:10330000934224BF436A43610021FEF7E9BD0000F8
+:1033100038B504460D46E3683BB123691A1DA26225
+:10332000E2691344E362002007E0237A33B92946B7
+:103330002046FEF7C5FD0028EDDA38BD6FF001002C
+:10334000FBE7000003691960C268013AC260C26904
+:10335000134482690361934224BF436A03610023DB
+:103360008362036B03B118477047000070B53023C8
+:103370000D460446114683F31188866A2EB9FFF77D
+:10338000C7FF10B186F3118870BDA36A1D70A36AD0
+:10339000E26A01339342A36204D3E169204604390F
+:1033A000FFF7D0FF002080F31188EDE72DE9F84FFB
+:1033B00004460D46904699464FF0300A8AF311882C
+:1033C0000026B346A76A4FB949462046FFF7A0FF3B
+:1033D00020B187F311883046BDE8F88FD4E90A0799
+:1033E0003A1AA8EB0607974228BF1746402F1BD969
+:1033F00005F1400355F8042B40F8042B9D42F9D108
+:10340000A36A4033A3624036D4E90A239A4204D324
+:10341000E16920460439FFF795FF8BF31188464593
+:10342000D9D28AF31188CDE729463A46FDF73AFC0E
+:10343000A36A3B443D44A3623E44E5E7D0E904234C
+:103440009A4217D1C3689BB1836A8BB1043B9B1A24
+:103450000ED01360C368013BC360C3691A4483691B
+:1034600002619A4224BF436A0361002383620123FD
+:10347000184670470023FBE700F030B94FF0804357
+:10348000586A70474FF08043002258631A61022245
+:10349000DA6070474FF080430022DA607047000026
+:1034A0004FF0804358637047FEE7000070B51B4B38
+:1034B00001630025044686B0586085620E4600F020
+:1034C000BFF804F11003C4E904334FF0FF33C4E93B
+:1034D0000635C4E90044A560E562FFF7CFFF2B463F
+:1034E0000246C4E9082304F134010D4A256580230E
+:1034F0002046FEF79BFC0123E0600A4A0375009218
+:1035000072680192B268CDE90223074B6846CDE9A3
+:103510000435FEF7B3FC06B070BD00BF9028002054
+:103520007C3D0008813D0008A9340008024AD36AA6
+:103530001843D062704700BF282600204B684360C4
+:103540008B688360CB68C3600B6943614B6903621E
+:103550008B6943620B6803607047000008B5264B17
+:1035600026481A6940F2FF110A431A611A6922F4C7
+:10357000FF7222F001021A611A691A6B0A431A6378
+:103580001A6D0A431A651E4A1B6D1146FFF7D6FFD6
+:1035900002F11C0100F58060FFF7D0FF02F1380155
+:1035A00000F58060FFF7CAFF02F1540100F580606A
+:1035B000FFF7C4FF02F1700100F58060FFF7BEFF66
+:1035C00002F18C0100F58060FFF7B8FF02F1A8015D
+:1035D00000F58060FFF7B2FF02F1C40100F58060E2
+:1035E000FFF7ACFF02F1E00100F58060FFF7A6FFF6
+:1035F000BDE8084000F0EEB800380240000002408C
+:10360000883D000808B500F067FAFEF7D3FBFFF726
+:1036100093F8BDE80840FEF75BBE0000704700006D
+:10362000EFF3098305494A6B22F001024A636833CC
+:1036300083F30988002383F31188704700EF00E0CB
+:10364000302080F3118862B60C4B0D4AD96821F402
+:10365000E0610904090C0A43DA60D3F8FC20094947
+:1036600042F08072C3F8FC200A6842F001020A604E
+:103670002022DA7783F82200704700BF00ED00E0D7
+:103680000003FA05001000E010B5302383F3118821
+:103690000E4B5B6813F4006314D0F1EE103AEFF3B5
+:1036A0000984683C4FF08073E361094BDB6B236650
+:1036B00084F30988FEF752FB10B1064BA36110BDDD
+:1036C000054BFBE783F31188F9E700BF00ED00E04D
+:1036D00000EF00E02F030008320300080F4B1A6CC4
+:1036E00042F001021A641A6E42F001021A660C4A94
+:1036F0001B6E936843F0010393604FF080435322A5
+:103700009A624FF0FF32DA6200229A615A63DA60FD
+:103710005A6001225A611A60704700BF00380240A7
+:10372000002004E04FF0804208B51169D3680B40D7
+:10373000D9B2C9439B07116107D5302383F31188A0
+:10374000FEF74EFB002383F3118808BD1F4B1A6957
+:103750006FEAC2526FEAD2521A611A69C2F30802C2
+:103760001A614FF0FF301A695A69586100215A698D
+:1037700059615A691A6A62F080521A621A6A02F032
+:1037800080521A621A6A5A6A58625A6A59625A6AA6
+:103790001A6C42F080521A641A6E42F080521A6615
+:1037A0001A6E0B4A106840F480701060186F00F4B5
+:1037B0004070B0F5007F1EBF4FF480301867196766
+:1037C000536823F40073536000F05EB90038024080
+:1037D00000700040334B4FF080521A64324A4FF46D
+:1037E000404111601A6842F001021A601A6891079C
+:1037F000FCD59A6822F003029A602A4B9A6812F06C
+:103800000C02FBD1196801F0F90119609A601A687D
+:1038100042F480321A601A689203FCD55A6F42F063
+:1038200001025A671F4B5A6F9007FCD51F4A5A6016
+:103830001A6842F080721A601B4A53685904FCD51A
+:10384000184B1A689201FCD5194A9A60194B1A68EC
+:10385000194B9A42194B21D1194A1168194A9142C0
+:103860001CD140F205121A60144A136803F00F03CA
+:10387000052BFAD10B4B9A6842F002029A609A68C3
+:1038800002F00C02082AFAD15A6C42F480425A64BF
+:103890005A6E42F480425A665B6E704740F205727F
+:1038A000E1E700BF003802400070004008544007C4
+:1038B00000948838002004E011640020003C02409D
+:1038C00000ED00E041C20F41074A08B5536903F01B
+:1038D0000103536123B1054A13680BB1506898473F
+:1038E000BDE80840FFF7D0BE003C0140703000202A
+:1038F000074A08B5536903F00203536123B1054A2F
+:1039000093680BB1D0689847BDE80840FFF7BCBE8C
+:10391000003C014070300020074A08B5536903F0AD
+:103920000403536123B1054A13690BB150699847E9
+:10393000BDE80840FFF7A8BE003C01407030002001
+:10394000074A08B5536903F00803536123B1054AD8
+:1039500093690BB1D0699847BDE80840FFF794BE62
+:10396000003C014070300020074A08B5536903F05D
+:103970001003536123B1054A136A0BB1506A98478B
+:10398000BDE80840FFF780BE003C014070300020D9
+:10399000164B10B55C6904F478725A61A30604D51D
+:1039A000134A936A0BB1D06A9847600604D5104A4F
+:1039B000136B0BB1506B9847210604D50C4A936BDF
+:1039C0000BB1D06B9847E20504D5094A136C0BB1D3
+:1039D000506C9847A30504D5054A936C0BB1D06C85
+:1039E0009847BDE81040FFF74FBE00BF003C0140C4
+:1039F00070300020194B10B55C6904F47C425A61A8
+:103A0000620504D5164A136D0BB1506D9847230516
+:103A100004D5134A936D0BB1D06D9847E00404D5DB
+:103A20000F4A136E0BB1506E9847A10404D50C4A8F
+:103A3000936E0BB1D06E9847620404D5084A136F99
+:103A40000BB1506F9847230404D5054A936F0BB10F
+:103A5000D06F9847BDE81040FFF716BE003C01400C
+:103A60007030002008B50348FDF786FABDE808402D
+:103A7000FFF70ABEBC23002008B5FFF753FEBDE8E0
+:103A80000840FFF701BE0000062108B50846FFF711
+:103A900013FB06210720FFF70FFB06210820FFF785
+:103AA0000BFB06210920FFF707FB06210A20FFF781
+:103AB00003FB06211720FFF7FFFA06212820FFF756
+:103AC000FBFA07211C20FFF7F7FABDE808400C219C
+:103AD0002520FFF7F1BA000008B5FFF737FE00F028
+:103AE0000DF8FDF75DFCFDF743FEFDF71BFDFFF74D
+:103AF00095FDBDE80840FFF7BFBC00000023054A64
+:103B000019460133102BC2E9001102F10802F8D165
+:103B1000704700BF70300020034611F8012B03F8F6
+:103B2000012B002AF9D1704753544D3332463F3FA1
+:103B30003F0053544D3332463430780053544D33A4
+:103B400032463432780053544D333246343436588A
+:103B500058000000012033000010410001105A00FD
+:103B6000031059000710310000000000283B000836
+:103B700013040000323B0008190400003C3B00081D
+:103B800021040000463B00080096000000000000F1
+:103B90000000000000000000000000000000000025
+:103BA000611300084D1300088913000875130008FD
+:103BB000811300086D13000859130008451300080D
+:103BC0009513000800000000A11400088D140008DF
+:103BD000C9140008B5140008C1140008AD14000889
+:103BE0009914000885140008D5140008000000008E
+:103BF000010000000000000063300000F83B0008F6
+:103C000080260020902800204172647550696C6FF6
+:103C1000740025424F415244252D424C0025534506
+:103C20005249414C25000000020000000000000045
+:103C3000BD1600082917000840004000302D002064
+:103C4000402D0020020000000000000003000000E2
+:103C5000000000006D1700080000000010000000C8
+:103C6000502D0020000000000100000000000000B6
+:103C7000F82F0020010102006D2200087D210008BC
+:103C800019220008FD21000843000000903C0008B4
+:103C900009024300020100C03209040000010202CF
+:103CA0000100052400100105240100010424020282
+:103CB0000524060001070582030800FF090401002E
+:103CC000020A00000007050102400000070581020A
+:103CD0004000000012000000DC3C0008120110014E
+:103CE00002000040091241570002010203010000D6
+:103CF0000403090425424F415244250048454557D5
+:103D0000494E472D46343035763200303132333427
+:103D100035363738394142434445460000400000BB
+:103D200000400000004000000040000000000100D2
+:103D3000000002000000020000000200000002007B
+:103D4000000002000000020000000200000000006D
+:103D5000B1180008691B0008151C0008400040004D
+:103D6000583000205830002001000000683000204A
+:103D70008000000040010000030000006D61696EDA
+:103D80000069646C650000000001A82A00000000C2
+:103D9000AAAAAAAA00011424FFFF00000000000044
+:103DA00070A70A000000000000000000AAAAAAAA4A
+:103DB00000000000FFFF0000000000000000000005
+:103DC0000001005400000000AAAAAAAA00010010E5
+:103DD000FF5F000000000000000000000000000085
+:103DE00000000000AAAAAAAA00000000FFFF00002D
+:103DF00000000000000000000000000000000000C3
+:103E0000AAAAAAAA00000000FFFF0000000000000C
+:103E1000000000000000000000000000AAAAAAAAFA
+:103E200000000000FFFF0000000000000000000094
+:103E30000000000000000000AAAAAAAA00000000DA
+:103E4000FFFF000000000000000000000000000074
+:103E5000000000000A000000000000000300000055
+:103E60000000000000000000000000000000000052
+:103E70000000000000000000000000000000000042
+:103E800000000000000000005F04000000000000CF
+:103E900000000F0000000000FF0000009828002034
+:103EA000BC230020009600000000080096000000DF
+:103EB0000008000004000000F03C000800000000C2
+:103EC00000000000000000000000000000000000F2
+:043ED00000000000EE
+:00000001FF
diff --git a/Tools/bootloaders/Here4AP_bl.bin b/Tools/bootloaders/Here4AP_bl.bin
new file mode 100755
index 00000000000000..48b6b0ff5634b3
Binary files /dev/null and b/Tools/bootloaders/Here4AP_bl.bin differ
diff --git a/Tools/bootloaders/Hitec-Airspeed_bl.bin b/Tools/bootloaders/Hitec-Airspeed_bl.bin
index 1c310178927e03..702c2df8a322e4 100755
Binary files a/Tools/bootloaders/Hitec-Airspeed_bl.bin and b/Tools/bootloaders/Hitec-Airspeed_bl.bin differ
diff --git a/Tools/bootloaders/Hitec-Airspeed_bl.elf b/Tools/bootloaders/Hitec-Airspeed_bl.elf
index 694494725e7a99..ea39d2e94d3aa5 100755
Binary files a/Tools/bootloaders/Hitec-Airspeed_bl.elf and b/Tools/bootloaders/Hitec-Airspeed_bl.elf differ
diff --git a/Tools/bootloaders/Hitec-Airspeed_bl.hex b/Tools/bootloaders/Hitec-Airspeed_bl.hex
index 5e23727410fe5f..b51c935d30018f 100644
--- a/Tools/bootloaders/Hitec-Airspeed_bl.hex
+++ b/Tools/bootloaders/Hitec-Airspeed_bl.hex
@@ -1,19 +1,19 @@
:020000040800F2
-:1000000000090020F5040008052900080929000856
-:10001000612900080929000835290008F7040008AB
-:10002000F7040008F7040008F70400083537000853
+:1000000000090020F5040008492C0008012C000814
+:10001000292C0008012C0008212C0008F7040008F6
+:10002000F7040008F7040008F7040008193C00086A
:10003000F7040008F7040008F7040008F7040008B4
:10004000F7040008F7040008F7040008F7040008A4
-:10005000F7040008F7040008354900085D49000866
-:1000600085490008AD490008D5490008F704000893
+:10005000F7040008F70400088D4F0008B54F0008AA
+:10006000DD4F0008055000082D500008F704000877
:10007000F7040008F7040008F7040008F704000874
:10008000F7040008F7040008F7040008F704000864
-:10009000F70400086926000879260008FD490008D1
+:10009000F7040008E12B0008F12B00085550000878
:1000A000F7040008F7040008F7040008F704000844
-:1000B000E54A0008F7040008F7040008F704000800
+:1000B0003D510008F7040008F7040008F7040008A1
:1000C000F7040008F7040008F7040008F704000824
-:1000D000F7040008D14A0008F7040008F7040008F4
-:1000E000614A0008F7040008F7040008F704000854
+:1000D000F704000829510008F7040008F704000895
+:1000E000B9500008F7040008F7040008F7040008F6
:1000F000F7040008F7040008F7040008F7040008F4
:10010000F7040008F7040008F7040008F7040008E3
:10011000F7040008F7040008F7040008F7040008D3
@@ -29,7 +29,7 @@
:1001B000F7040008F7040008F7040008F704000833
:1001C000F7040008F7040008F7040008F704000823
:1001D000F7040008F7040008F7040008F704000813
-:1001E00049180008000000000000000000000000A6
+:1001E0007D16000800000000000000000000000074
:1001F00053B94AB9002908BF00281CBF4FF0FF318E
:100200004FF0FF3000F074B9ADF1080C6DE904CE89
:1002100000F006F8DDF804E0DDE9022304B07047E1
@@ -78,1201 +78,1283 @@
:1004C0004B45A9D2B9EB020864EB0C0E0138A3E747
:1004D0004646EAE7204694E74046D1E7D0467BE728
:1004E000023B614432E7304609E76444023842E7A0
-:1004F000704700BF02E000F000F8FEE772B63A482D
-:1005000080F30888394880F3098839484EF6085145
-:10051000CEF20001086040F20000CCF200004EF67E
-:100520003471CEF200010860BFF34F8FBFF36F8FBD
-:1005300040F20000C0F2F0004EF68851CEF2000109
-:100540000860BFF34F8FBFF36F8F4FF00000E1EEF5
-:10055000100A4EF63C71CEF200010860062080F3CE
-:100560001488BFF36F8F04F077F804F053F804F0A9
-:100570009DF84FF055301F491B4A91423CBF41F84E
-:10058000040BFAE71C49194A91423CBF41F8040B9D
-:10059000FAE71A491A4A1B4B9A423EBF51F8040B1C
-:1005A00042F8040BF8E700201749184A91423CBF73
-:1005B00041F8040BFAE704F031F804F0BDF8144CEC
-:1005C000144DAC4203DA54F8041B8847F9E700F0F5
-:1005D00041F8114C114DAC4203DA54F8041B884722
-:1005E000F9E704F019B8000000090020001100200C
-:1005F000000000080001002000090020304F000822
-:10060000001100208C110020901100207C3B002064
-:10061000E0010008E4010008E4010008E40100082A
-:100620002DE9F04F2DED108AC1F80CD0C3689D461E
-:10063000BDEC108ABDE8F08F002383F311882846B3
-:10064000A047002003F0F2FCFEE703F06BFC00DFA4
-:10065000FEE70000F8B503F083FF074603F0D4FF80
-:10066000044688BB1D4B9F422ED001339F422ED0A3
-:100670001B4B27F0FF029A422CD1F8B200F02EFD5E
-:10068000264642F2107500F033FF00F02DFD08B948
-:100690000646054634B1134B9F4203D003F0ACFF2E
-:1006A00000252E46002003F065FF0EB100F062F831
-:1006B00001F040FA00F03EFF01F02CF9284600F06E
-:1006C000ADF800F057F8F9E726460025DBE70546C8
-:1006D0000126D8E706464FF47A75D4E7010007B043
-:1006E000000008B0263A09B008B501F0E5F8A0F11D
-:1006F00020035842584108BD07B541F212030221B8
-:1007000001A8ADF8043001F0F5F803B05DF804FB82
-:1007100010B5202383F311881248C3680BB103F08E
-:10072000FDFC114A0F4800234FF47A7103F0BAFC24
-:10073000002383F311880D4C236813B12368013B18
-:100740002360636813B16368013B6360084B1B78E7
-:1007500033B9636823B9022001F07AF93223636068
-:1007600010BD00BF9011002011070008AC1200203E
-:10077000A411002038B5234A234B1968013140D019
-:1007800004339342F9D1214C1F4DD4F80428AA42D6
-:1007900037D31F4B9B6803F1006303F5D0439A42A4
-:1007A0002FD203F0FBFE03F00DFF002001F0CCF888
-:1007B000184B0220187001F043F9174B9A6D002274
-:1007C0009A65996F9A67996FD96DDA65D96FDA670B
-:1007D000D96F196E1A66D3F88010C3F88020D3F849
-:1007E000803072B64FF0E0232021C3F8085DD4F8C2
-:1007F0000038D4F8042881F311889D4683F30888D3
-:10080000104738BD20680008006800080060000834
-:1008100000110020A4110020001002402DE9F04F2B
-:1008200093B0AC4B00902022FF210AA89D6801F0F4
-:100830002BF9A94A1378A3B9A8480121C360117004
-:10084000202383F31188C3680BB103F067FCA44A2B
-:10085000A24800234FF47A7103F024FC002383F3B1
-:100860001188009B9F4A03B113609F49009C00239D
-:100870000B70536098469B461E469A46012001F035
-:10088000DFF824B1974B1B68002B00F01C8200207E
-:1008900001F012F80390039B002B01DA00F08EFEAA
-:1008A000039B002BEDDB012001F0C2F8039B213BF1
-:1008B000162BE3D801A252F823F000BF1909000853
-:1008C00041090008D50900087D0800087D080008D6
-:1008D0007D080008690A00083B0C0008550B000859
-:1008E000B70B0008DF0B0008050C00087D080008A6
-:1008F000170C00087D080008890C0008B9090008D9
-:100900007D080008CD0C000825090008B909000879
-:100910007D080008B70B00080220FFF7E5FE00285D
-:1009200040F0FB81009B0221B8F1000F08BF1C467C
-:1009300005A841F21233ADF8143000F0DBFF9DE75B
-:100940004FF47A7000F0B8FF071EEBDB0220FFF7D0
-:10095000CBFE0028E6D0013F052F00F2E081DFE862
-:1009600007F0030A0D10133605230593042105A88B
-:1009700000F0C0FF17E057480421F9E75B48042165
-:10098000F6E75B480421F3E74FF01C09484600F006
-:10099000DDFF09F104090590042105A800F0AAFF74
-:1009A000B9F12C0FF2D1012000FA07F747EA0B0B3F
-:1009B0005FFA8BFB4FF0000A01F0B2F826B10BF0A2
-:1009C0000B030B2B08BF0024FFF796FE56E74948A0
-:1009D0000421CDE7002EA5D00BF00B030B2BA1D1EA
-:1009E0000220FFF781FE074600289BD001203E4EE3
-:1009F00000F0AAFF0220307001F022F84FF000084A
-:100A00005FFA88F9484600F0B1FF044690B14846C5
-:100A100000F0BCFF08F101080028F1D1B8460446F7
-:100A200041F21213022105A8ADF814303E4600F041
-:100A300061FF23E701230220337000F0F9FF254610
-:100A4000244B9B68AB4207D9284600F07FFF01305A
-:100A500040F068810435F3E7234B00251D70214BDE
-:100A6000B8465D603E46A7E7002E3FF45BAF0BF053
-:100A70000B030B2B7FF456AF1B4B0220187000F0BA
-:100A8000DFFF322000F018FFB0F10009FFF64AAF97
-:100A900019F003077FF446AF0E4A926809EB05038D
-:100AA00093423FF63FAFB9F5807F3FF73BAF124B24
-:100AB0000193B94522DD4FF47A7000F0FDFE0390FA
-:100AC000039A002AFFF62EAF019B039A03F8012B2D
-:100AD0000137EDE700110020A8120020901100203E
-:100AE00011070008AC120020A411002004110020FE
-:100AF000081100200C110020A8110020C820FFF7C9
-:100B0000F3FD074600283FF40DAF1F2D11D8C5F1A6
-:100B100020024A450AAB25F0030028BF4A46834914
-:100B20000192184400F09EFF019A8048FF2100F0D6
-:100B3000ABFF4FEAA9037D490193C9F38702284619
-:100B400000F0AAFF064600283FF46AAF019B05EBC0
-:100B5000830531E70220FFF7C7FD00283FF4E2AE2E
-:100B600000F030FF00283FF4DDAE0027B946704B9F
-:100B70009B68BB4218D91F2F11D80A9B01330ED096
-:100B800027F0030312AA134453F8203C0593484668
-:100B9000042205A901F002FF04378146E7E7384641
-:100BA00000F0D4FE0590F2E7CDF81490042105A8DA
-:100BB00000F0A0FE00E70023642104A8049300F0E5
-:100BC0008FFE00287FF4AEAE0220FFF78DFD0028D7
-:100BD0003FF4A8AE049800F0EBFE0590E6E7002392
-:100BE000642104A8049300F07BFE00287FF49AAEF1
-:100BF0000220FFF779FD00283FF494AE049800F03E
-:100C0000D9FEEAE70220FFF76FFD00283FF48AAE25
-:100C100000F0E8FEE1E70220FFF766FD00283FF460
-:100C200081AE05A9142000F0E3FE042107460490DC
-:100C300004A800F05FFE3946B9E7322000F03CFE20
-:100C4000071EFFF66FAEBB077FF46CAE384A9268A2
-:100C500007EB0A0393423FF665AE0220FFF744FD1F
-:100C600000283FF45FAE27F003075744BA453FF42E
-:100C7000A3AE504600F06AFE0421059005A800F0DE
-:100C800039FE0AF1040AF1E74FF47A70FFF72CFD00
-:100C900000283FF447AE00F095FE002844D00A9BA0
-:100CA00001330BD008220AA9002000F0F5FE00282D
-:100CB0003AD02022FF210AA800F0E6FEFFF71CFD33
-:100CC0001C4803F0B9F913B0BDE8F08F002E3FF4D3
-:100CD00029AE0BF00B030B2B7FF424AE0023642111
-:100CE00005A8059300F0FCFD074600287FF41AAE26
-:100CF0000220FFF7F9FC814600283FF413AEFFF70E
-:100D0000FBFC41F2883003F097F9059800F01EFFD4
-:100D10004E4600F005FF3C46B0E506464CE64FF077
-:100D2000000AFFE5B8467BE6374679E6A8110020C1
-:100D300000110020A0860100094A136849F26900E9
-:100D400099B21B0C00FB01331360064B186844F288
-:100D5000506182B2000C01FB0200186080B2704743
-:100D6000141100201011002010B50021102204469B
-:100D700000F08AFE034B03CB206061601868A0601E
-:100D800010BD00BF9075FF1F2DE9F043204DBBB093
-:100D900001F000FEAB68C31AF92B32D906AFA86088
-:100DA0002B4628220021384602F08CFA05F10E006D
-:100DB00000F062FE002604465FFA80F905F10E0895
-:100DC000F3B2F100994501F1280107D908EB0603B8
-:100DD0000822384602F076FA0136F1E708230122AC
-:100DE000CDE9023205340B4B0193A4B230230093BA
-:100DF000CDE9047404A3D3E90023297B064802F05B
-:100E000079F83BB0BDE8F08378F6339F93CACD8D77
-:100E1000703700207D370020CC22002070B50D46B1
-:100E200014461E4601F0FCFF50B9022E10D1012CD1
-:100E30000ED112A3D3E90023C5E90023012007E066
-:100E4000282C10D005D8012C09D0052C0FD000205B
-:100E500070BD302CFBD10BA3D3E90023ECE70BA32F
-:100E6000D3E90023E8E70BA3D3E90023E4E70BA3CE
-:100E7000D3E90023E0E700BFAFF30080401DA120CD
-:100E800026812A0B78F6339F93CACD8D9E6AC421A2
-:100E9000818A46EE26417272DF25D7B7F017304AB5
-:100EA00039059E5613B504462346084620220021E4
-:100EB000019002F007FA22790198032A234628BFFD
-:100EC000032203F8042F2021022202F0FBF96279A9
-:100ED0000198072A234628BF072203F8052F22215D
-:100EE000032202F0EFF9A2790198072A234628BFCE
-:100EF000072203F8062F2521032202F0E3F90198C7
-:100F000004F108031022282102F0DCF9382002B095
-:100F100010BD00002DE9F04FADF5017D21AD0EAE05
-:100F200040F2751280460F4622A80021296000F089
-:100F3000ABFD48220021304600F0A6FD01F02AFD5D
-:100F4000564B4FF47A72B0FBF2F0186093E807004A
-:100F5000012386E807000DF15A003382FFF704FFF2
-:100F600041F20463338406AB18464D4903F0A2FEF8
-:100F70001C2230642946304686F83C20FFF792FF59
-:100F800012AB044601460822284602F09BF90822CB
-:100F9000A1180DF14903284602F094F90DF14A0316
-:100FA000082204F11001284602F08CF913AB20222C
-:100FB00004F11801284602F085F914AB402204F12F
-:100FC0003801284602F07EF916AB082204F17801B8
-:100FD000284602F077F90DF15903082204F1800147
-:100FE000284602F06FF904F1880A0DF15A0904F558
-:100FF000847B4B465146082228460AF1080A02F033
-:1010000061F9D34509F10109F3D11BAB0822594617
-:10101000284602F057F904F588744FF0000996F855
-:1010200034304B450AD9B36B21464B44082228463D
-:1010300002F048F9083409F10109F0E74FF000091E
-:1010400096F83C304B4504EBC90108D9336C0822B3
-:101050004B44284602F036F909F10109F0E7002374
-:101060000393BB7E0293073107F119030193C1F388
-:10107000CF010123CDE904510093F97E05A3D3E903
-:101080000023404601F036FF0DF5017DBDE8F08FED
-:10109000AFF300809E6AC421818A46EEB41200201C
-:1010A000E44C000810B50A4B0A4A1A6003F5805355
-:1010B00093F840203AB9DC6B2CB1204601F0E8FAF5
-:1010C000204603F061FDBDE81040034801F0E0BA9E
-:1010D000F0220020C84D000818330020014B187082
-:1010E000704700BFC0120020F0B5334B1C7B85B0A9
-:1010F00034B1324B0E221A810024204605B0F0BDD7
-:101100002F4A1068516802AB03C308232D492E48AB
-:101110000DEB030203F060FD054630B9274B2B4869
-:101120000A221A8101F0B0FAE6E70169B1F5CC3F75
-:1011300006D9224B26480B221A8101F0A5FADCE7DA
-:10114000438B40F21642934207D01C490C20088181
-:101150001946204801F098FACFE71F4A024402F1ED
-:101160001003994204D2154B1C4810221A81E4E75F
-:1011700010398E1A2046144901F010FC32460746F9
-:1011800005F11801204601F009FCAB689F4202D12D
-:10119000EB6898420AD0094B0D221A810090D5E9DC
-:1011A00002123B460E4801F06FFAA5E70D4801F028
-:1011B0006BFA0124A1E700BF70370020B4120020B1
-:1011C000954D0008DC97010000680008044D0008F8
-:1011D000104D0008224D00080898FFF7404D000808
-:1011E0005D4D0008864D00082DE9F04FADB006AF0B
-:1011F00080460C4601F014FE054600285AD1237E95
-:10120000022B1BD1E38A012B18D101F0C3FB064648
-:10121000FFF792FD03464FF4C870DFF8D092B3FB9E
-:10122000F0F206F5167602FB103316FA83F3C9F8CE
-:101230000030E37E33B9A84B00221A709C37BD46BC
-:10124000BDE8F08FA38AEEB2013BB34205F1010580
-:101250000BD93B1D1E44E90000960023082201F033
-:10126000F801204601F0F2FEECE707F11400FFF769
-:101270007BFD324607F11401381D03F09DFC002868
-:10128000D9D10F2E08D8944B1E70D9F80030A3F591
-:101290001673C9F80030D1E7FB1CF87001460093C3
-:1012A00007220346204601F0D1FEF978404601F0BE
-:1012B000AFFDC3E7E38A282B26D010D8012B1ED020
-:1012C000052BBBD1BFF34F8F8449854BCA6802F40D
-:1012D000E0621343CB60BFF34F8F00BFFDE7302BBD
-:1012E000ACD1637E7F4D01336A7BDBB29342E9462A
-:1012F00003D1E27E2B7B9A4265D0CD469EE7214604
-:101300004046FFF707FE99E7A38A013B9BB2C92B32
-:1013100094D8744D2E7B26BB05F10C030093082254
-:1013200033463146204601F091FE731CF2B2D900DB
-:101330001E46A38A013B9A4205DA0E322A440092E5
-:1013400000230822EEE700230022C5E90023002342
-:10135000AB6085F8D730C5F8D8302B7B0BB9E37E6E
-:101360002B73002507F114093B1D08222946484626
-:10137000C7E90155FD6001F0A5FF3B7A05F1010ABF
-:10138000AB424FEACA0608D9FB6808222B44314613
-:10139000484601F097FF5546EFE7C6F3CF06E17EDA
-:1013A000CDE9049600230393A37E029319342823E6
-:1013B0000093019446A3D3E90023404601F09AFD2F
-:1013C000FFF7E2FC3AE74FF0000807F11403A7F833
-:1013D00014801022009341460123204601F036FE7E
-:1013E000A68A023EB6B2F31C9B109B000733DB08B3
-:1013F000A9EBC3039D460DF1180A1FFA88F34FEAC3
-:10140000C801B34201F110010AD20AEB08030093AC
-:1014100008220023204601F019FE08F10108ECE73C
-:1014200095F8D70000F0A2FAD5F8D83004461BB9D9
-:1014300095F8D70000F0AAFAD5F8D83033449C428A
-:1014400004D295F8D700013000F0A0FA4FEA960BCD
-:101450004FF000081FFA88F18B45D5E9003209D911
-:101460000AEB880103EB8800012200F015FB08F16C
-:101470000108EFE7F31842F10002C5E90032D5F8A0
-:10148000D83095F8D70006EB0308C5F8D88000F0EF
-:101490006DFA804509D395F8D730D5F8D8000133D7
-:1014A000001B85F8D730C5F8D800FF2E08D80023D8
-:1014B0002B7300F087FAFFF717FE08B1FFF75AF910
-:1014C0002B68094A9B0A013313810023AB6014E7A0
-:1014D00026417272DF25D7B7C522002000ED00E05B
-:1014E0000400FA0570370020B4120020C822002042
-:1014F00008B54FF000530B4A196891420AD10A4AC5
-:10150000597D117009481B7D03730949C9220E30AA
-:1015100000F0A8FABDE80840E02200214FF000509A
-:1015200000F0B2BA9AAD44C5C01200207037002056
-:101530001600002037B5184D18491948022301221A
-:101540006B7100F023FD00230193164B16490093A5
-:101550001648174B4FF4805201F034FC154B1978A4
-:1015600011B1124801F054FC01F014FA0446FFF7DF
-:10157000E3FB4FF4C873B0FBF3F202FB130304F573
-:10158000167010FA83F00C4B186003F03DF808B1A8
-:101590000F232B8103B030BDB412002040420F0056
-:1015A000F02200201D0E0008C4120020CC220020D2
-:1015B000E9110008C0120020C82200202DE9F04FD8
-:1015C0002DED028B97A7D7E900670FF26029D9E9C3
-:1015D00000898E4C95B0DFF85CA2DFF85CB2204643
-:1015E00001F0ECFC034650B30025CDE911551095F0
-:1015F0008DF84C50027B8DF84C209968406811AAF8
-:1016000003C21B6843F00043109301F0C5F910EBCF
-:101610000A0241F10003009510A9584600F000FBB2
-:10162000A8427B4A05DD204601F0CCFC784A1570C3
-:10163000D5E71378072B00F2BA80013313700DAD94
-:101640009FED708B0023DFF8F0B10C938DF83C30E8
-:101650000D936B6000230DF125028DED008B4FF093
-:10166000010A09A958468DF825308DF824A000F00C
-:10167000A1FF9DF824200023002A40F09C802046F2
-:1016800001F0CEFB0546002847D1DFF8B0B101F0EC
-:1016900081F9DBF8003098423FD301F07BF90790E5
-:1016A000FFF74AFB079A4FF4C87302F51672B0FBB6
-:1016B000F3F101FB130312FA83F3CBF80030DFF8E8
-:1016C00080B19BF800100791002914BF2B465346A8
-:1016D00010A88DF83030FFF747FB0799C1F11002D1
-:1016E000D2B2062A10AB28BF062219440DF13100F0
-:1016F000079200F0B7F9079A0CAB039318230293F3
-:101700000132444BD2B2CDE900A304923B463246AB
-:10171000204601F087FB8BF8005001F03BF93E4A70
-:101720003E4D1368C31AB3F57A7F33D3106001F0CE
-:1017300033F902460B46204601F04EFC204601F0EC
-:101740006FFB38B32B7BDFF8FCA0002B14BF032307
-:1017500002238AF8053001F01DF90DF1400B4FF41A
-:101760007A735946B0FBF3F0CAF800005046FFF711
-:1017700099FB182307300293294B0193C0F3CF0044
-:1017800040F25513CDE903B0009342464B46204644
-:1017900001F048FB2B7B2BB1FFF7F6FA2B7B002BDC
-:1017A0007FF419AF15B0BDEC028BBDE8F08F204679
-:1017B00001F008FC43E74FF0904110A84A6982F01D
-:1017C00040024A611946102200F05EF90DF126032D
-:1017D0000AAA0CA9584600F0CFFA95E8030011AB0D
-:1017E00083E803009DF83C308DF84C300C9B10933F
-:1017F00010A9DDE90A23204601F0ACFD2AE700BF6D
-:10180000AFF300800000000000000000CC220020A8
-:1018100055380020C42200205038002070370020A6
-:1018200054380020401DA12026812A0BF1C6A7C1F3
-:10183000D068080F40420F00F0220020C82200208C
-:10184000C5220020B412002008B5054800F01CFB9A
-:10185000BDE80840034A0449002003F08FB900BFE7
-:10186000F0220020A8380020A510000870B50F4B0A
-:101870001B780133DBB2012B0C4611D80C4D2968C3
-:101880004FF47A730E6AA2FB0332014622462846C1
-:10189000B047844204D1074B00221A70012070BD6A
-:1018A0004FF4FA7002F0C8FB0020F8E7181100208E
-:1018B000AC3800209C38002007B5002302460121E7
-:1018C0000DF107008DF80730FFF7D0FF20B19DF82C
-:1018D000070003B05DF804FB4FF0FF30F9E70000AC
-:1018E0000A4608B50421FFF7C1FF80F00100C0B22D
-:1018F000404208BD30B4054C2368DD69044B0A46FC
-:10190000AC460146204630BC604700BFAC380020E2
-:10191000A086010070B502F0C7FC094E094D308069
-:10192000002428683388834208D902F0B9FC2B6868
-:1019300004440133B4F5D04F2B60F2D370BD00BF27
-:101940009E3800205838002002F05CBD00F1006095
-:1019500000F5C040D0F800087047000000F10060BA
-:10196000920000F5D04002F0DBBC0000054B1A6885
-:10197000054B1B889B1A834202D9104402F090BC8D
-:1019800000207047583800209E38002038B5074D99
-:1019900004462868204402F089FC28B928682044BD
-:1019A000BDE8384002F094BC38BD00BF5838002074
-:1019B0000020704700F10050A0F51040D0F89005CD
-:1019C00070470000064991F8243033B10023086ABB
-:1019D00081F824300822FFF7C1BF0120704700BF03
-:1019E0005C380020014B1868704700BF002004E0FD
-:1019F00070B50E4B5C6893F90860421E0A44013CC6
-:101A00000B46934207D214F9015F581C2DB100F820
-:101A1000015C0346F5E7184605E02C2482421C7061
-:101A200001D9981C5E70401A70BD00BF1C110020C7
-:101A3000022802BF4FF0904340229A617047000095
-:101A4000022802BF4FF090434FF480029A61704722
-:101A5000022801BF4FF09042536983F04003536165
-:101A60007047000010B50023934203D0CC5CC454EF
-:101A70000133F9E710BD000003460246D01A12F9FF
-:101A8000011B0029FAD1704702440346934202D059
-:101A900003F8011BFAE770472DE9F8431F4D144680
-:101AA00095F824200746884652BBDFF870909CB317
-:101AB00095F824302BB92022FF2148462F62FFF7EA
-:101AC000E3FF95F82400C0F10802A24228BF224695
-:101AD000D6B24146920005EB8000FFF7C3FF95F8B0
-:101AE0002430A41B1E44F6B2082E17449044E4B2DE
-:101AF00085F82460DBD1FFF765FF0028D7D108E027
-:101B00002B6A03EB82038342CFD0FFF75BFF0028F1
-:101B1000CBD10020BDE8F8830120FBE75C38002032
-:101B2000024B1A78024B1A70704700BF9C38002095
-:101B300018110020034904484FF461430B6002F080
-:101B400015B900BF84380020AC380020074B10B511
-:101B50000021044618221846FFF796FF046001464C
-:101B6000BDE81040024802F001B900BF84380020EF
-:101B7000AC380020202383F3118862B67047000040
-:101B8000002383F3118862B670470000012070477C
-:101B9000704700007047000000F5805090F8510435
-:101BA0007047000000F5805090F84A04704700002C
-:101BB0005020704700F5805208B5FFF7DBFFD2F8E0
-:101BC0007434D2F870041844D2F86C341844D2F843
-:101BD00058341844D2F864341844D2F860341844A5
-:101BE000FFF7CEFF08BD000038B5426A936923F0C5
-:101BF00001039361044600F0CDFE0546636A9B69CC
-:101C0000DB0706D500F0C6FE431BFA2BF6D90020F1
-:101C100004E004F58054012084F84A0438BD000033
-:101C2000F8B500F580551F46D5F854340133C5F892
-:101C300054340C6814F0005461D10B7B082B5ED82F
-:101C400095F84A34002B5AD0FFF794FF436AD3F833
-:101C5000C460B60208D5D5F858340133C5F85834F5
-:101C60002046FFF78DFFF8BDD3F8C4400D68C36967
-:101C7000C4F30144482616FB0436002DB4BF45F0DA
-:101C80008045AD0435600B685B0044BF45F00055EE
-:101C900035600D7B230643EA054373604B68B360F0
-:101CA0008B68F360456A0123A340C5F8CC3000EB94
-:101CB000441303F58253C3E9022700EB441303F5F1
-:101CC0008253103301F10C0251F8045B43F8045BBA
-:101CD0009142F9D10A781A7004F18302530100EBA2
-:101CE0004212C450BDF81830117903F0030343F0D9
-:101CF000100321F01F010B4313710120B1E7D5F848
-:101D000058340133C5F858344FF0FF30ABE70000CA
-:101D100013B50446019100F0F1FC1F280AD901997E
-:101D20002022204600F060FDA0F1200358425841D7
-:101D300002B010BD0020FBE708B500F58050FFF7AA
-:101D400019FFC06B00F0AEFCBDE80840FFF718BFFC
-:101D500000220260027342608260704710B5002268
-:101D60000023C0E900230023044603810C30FFF761
-:101D7000EFFF204610BD00002DE9F041054688B078
-:101D800005F5805568461F460C46FFF7F3FE904662
-:101D9000FFF7E4FFE86B00F097FC1F2805D8002050
-:101DA000FFF7EEFE08B0BDE8F081E86B202269463F
-:101DB00000F09CFD2028F2D195F84A34002BEED09B
-:101DC00003AD05AB2E4603CE9E42206061603546D2
-:101DD00004F10804F6D13068206033792371DDE91D
-:101DE0000023C8E90023BDF808303B800120D7E775
-:101DF0002DE9F84F8046214B48F8283B00F58155E6
-:101E000004460F464646083530462036FFF7A6FF03
-:101E1000AE42F9D104F580554FF480534FF00009DC
-:101E2000C5E90B39C5F828800123EE6304F5A358F2
-:101E300004F58356C5F8349085F8383085F840307D
-:101E4000083608F108084FF0000A4FF0000B46E989
-:101E500008ABA6F11800FFF77BFF203646F8289C58
-:101E60004645F4D185F8507417B1054800F08CFD53
-:101E7000044B63622046BDE8F88F00BFC84D0008E0
-:101E8000AC4D00080064004010B5044B19780446BE
-:101E90004A1C1A70FFF7ACFF204610BDA538002081
-:101EA0002DE9F04300294FD0284B2948B0FBF1F031
-:101EB00099428CBF0A2311235D1EB0FBF3F703FB8D
-:101EC0001703ECB22BB1022D2B46F5D80020BDE84C
-:101ED000F0837E1EB6F5806FF8D2C4EBC40C0CF113
-:101EE00003034FEAE308C3F3C703A4EB030E08F1AF
-:101EF00001094FF47A755FFA8EF008FB055559FA1F
-:101F00008EFEB5FBFEF5B5F5617FC1BF0CF1FF3369
-:101F1000C3F3C703E01AC0B25C1C50FA84F40C4D42
-:101F20007C43B5FBF4F4A142D0D1013BDBB20F2BD3
-:101F3000CCD80138C0B20728C8D80021107116804B
-:101F40009170D3700120C2E70846C0E73F420F00FE
-:101F500000366E010B4B10B54FF45472044600214D
-:101F60001846FFF791FD084B236140336361D83376
-:101F7000A361F033E361636AE0600022C3F8C0202C
-:101F800010BD00BF00A4004070A400402DE9F04740
-:101F900000F5805588B095F85034012B04468846EA
-:101FA000164647D87E4A52F8231009B942F8230052
-:101FB0007C49C4F804800B78267293B9FFF7DAFDE8
-:101FC000794B9A6D42F000729A659A6B42F00072FA
-:101FD0009A639A6B22F000729A6301230B70FFF7E9
-:101FE000CFFD95F8493473B902211520FFF7C2FDE2
-:101FF00001F00AFD0221162001F006FD012385F8FB
-:102000004934FFF7BDFDFFF7B5FD626A936923F020
-:102010001003936100F0BEFC8146636A9F6917F06C
-:1020200008070AD000F0B6FCA0EB0903FA2BF4D99C
-:10203000FFF7A6FD4FF00008AEE09A6942F00102FA
-:102040009A6100F0A7FC8146636A9A69D10706D4B9
-:1020500000F0A0FCA0EB0903FA2BF5D9E8E79A6998
-:1020600042F002029A61636A4FF00009C3F854908B
-:10207000FFF786FDE86B00F015FB04F5825A0AF1C4
-:10208000080A202200216846FFF7FEFC02A8FFF79D
-:102090005FFECDF818906A460AEB07030DF1180EA3
-:1020A0009446BCE80300F44518605960624603F1A9
-:1020B0000803F5D1DCF80000186020379CF80420F4
-:1020C0001A71B7F5806FDCD100276A46414685F862
-:1020D000487485F84B742046ADF80070ADF8027076
-:1020E0008DF80470FFF7DCFE626A804680B9936960
-:1020F00023F00103936100F04DFC0546636A9B6980
-:10210000DA0797D500F046FC431BFA2BF6D991E786
-:102110009DF802309DF803E09DF80400BDF800C072
-:102120005B0643EA0E23034343EA0C43D3614FEAC1
-:102130000E21626A41EA0C4343EA0013D360204651
-:10214000FFF708FF85F85174636A6FF040421A6523
-:10215000636A164A5A65636A44229A65636A07226B
-:10216000C3F8DC20636A03229642DA6514D0626AFF
-:10217000936923F00103936100F00CFC0646636A47
-:102180009B69DB0705D500F005FC831BFA2BF6D90C
-:1021900050E7012385F84A34404608B0BDE8F0878F
-:1021A000A0380020A4380020001002409B00080046
-:1021B0002DE9F043074689B090469946002600F580
-:1021C00080557B6AD3F8D430F340D9073ED506F169
-:1021D000830307EB43131A79120737D4D5F85C242D
-:1021E0000132C5F85C241A7942F008021A71D3074B
-:1021F00024D595F84B340BB307F582541034684658
-:1022000004EB4614FFF7AAFD0DF10C0C04F10802D3
-:1022100020686168634603C3083494429C46F7D142
-:102220002068186023798CF80430E86B0123694634
-:10223000CDE90089ADF80830FFF76AFDD5F84C34D8
-:1022400023B1D5F878340133C5F878340136202E1F
-:10225000B7D109B0BDE8F0832DE9F0478CB0044652
-:102260008A4600F099FB81468846BAF1000F5BD19F
-:10227000636AD3F89020970141BF04F58051D1F8EB
-:1022800070240132C1F87024D3F89020160703D1CE
-:1022900000200CB0BDE8F087D3F890606569C6F304
-:1022A0000126482303FB06556F463846FFF750FDCD
-:1022B0002A6851004ABF22F06043C2F38A4343F0C8
-:1022C0000043920048BF43F080430093EB8803F043
-:1022D0000F038DF80C3001AAEB1D0F3513F8011F09
-:1022E00002F8011BAB42F9D1BAF1000F35D1636A94
-:1022F000C3F8946004A8FFF731FD97E80F0007AD1D
-:1023000007C504F580542B70E06B002304A9CDE9C8
-:102310000498ADF81830FFF7FBFC28B3D4F8683404
-:102320000133C4F86834B4E7BAF1010FB0D1636A7D
-:10233000D3F89820950141BF04F58051D1F870245D
-:102340000132C1F87024D3F898201007A0D0D3F838
-:102350009860A569C6F30126A3E7BAF1010F04BF8F
-:10236000636AC3F89C60C5E7D4F86C340133C4F8E1
-:102370006C3401208DE70000F8B505460F4600F5E6
-:102380008054012639462846FFF766FF10B184F8CD
-:102390004B64F7E7D4F84C3423B1D4F878340133E4
-:1023A000C4F87834F8BD0000F0B5436A1A6C12F432
-:1023B0007F0F29D000F580541B6CC4F87C3400F5E5
-:1023C00083560023012703F1830200EB42121179A7
-:1023D0008D0716D5490714D45901456A7158D5F8A7
-:1023E000C8C007FA01F111EA0C0F0AD0C5F8D010E5
-:1023F000117941F004011171D4F864240132C4F858
-:1024000064240133202BDED1F0BD000010B5254C33
-:10241000254B226802B338B31A6D12060ED58022FE
-:102420001A6500F0B9FA50EA01020B4602D00138F1
-:1024300061F1000302462068FFF7BAFE1A4A136DE5
-:102440001B032AD523684FF4002103F5805311653F
-:10245000012283F8512420E001221A6508221A651E
-:102460004FF480621A6510BD196DC80702D4196D4A
-:10247000890705D50321196510460021FFF77CFF68
-:10248000094B1A6D100702D41A6DD10605D5182212
-:102490001A6520680121FFF76FFF2068BDE8104032
-:1024A000FFF782BFA03800200064004008B5FFF7A6
-:1024B00061FBFFF779FFBDE80840FFF761BB000053
-:1024C000436AD3F8C40080F40010C0F34050704752
-:1024D00000F5805008B5FFF74DFBC06B00F0F4F835
-:1024E000FFF74EFB43090CBF0120002008BD000090
-:1024F00000F5805393F8512462B1416A8A6922F051
-:1025000001028A61D3F874240132C3F874240022D2
-:1025100083F85124704700002DE9F34100F5825102
-:1025200098460831FFF726FB00254FF0010E00F515
-:10253000805C05F1830400EB441423795E071CD40E
-:10254000DB061AD5436A8E69D3F8C8700EFA06F610
-:102550003E4212D04F6801970F689742019F77EB78
-:1025600008070AD2C3F8D060237943F0040323712B
-:10257000DCF860340133CCF860340135202D01F1F2
-:102580002001D6D102B0BDE8F041FFF7F9BA000052
-:10259000F8B51E46002313700F4605461446FFF794
-:1025A00097FF80F0010038701EB12846FFF788FFC2
-:1025B0002070F8BD2DE9F04F85B099460B78019356
-:1025C0000E4613780293DDE90EBA8046174600F0F6
-:1025D000E3F9337804460D4613B93B78002B41D01C
-:1025E00022462B464046FFF797FFFFF75FFFFFF7B6
-:1025F0007FFF4B463A463146FFF7CAFF33782BB18F
-:10260000019B1BB1012005B0BDE8F08F3B7813B1F1
-:10261000029B002BF6D108F5805303935C4575EBC4
-:102620000A031FD2039BD3F84C04D8B10368BBEB59
-:102630000402D9686AEB050388474B463A4631469F
-:102640004046FFF7A5FF337813B1019B002BD9D18A
-:102650003B7813B1029B002BD4D100F09DF90446C6
-:102660000D46DBE70020CEE708B50020FFF7CEFEE1
-:10267000BDE8084001F092B808B50120FFF7C6FE9A
-:10268000BDE8084001F08AB80FB4002004B07047DC
-:1026900010B5037C044613B9006802F085FA2046A1
-:1026A00010BD00000023BFF35B8FC360BFF35B8FDF
-:1026B000BFF35B8F8360BFF35B8F7047BFF35B8FAC
-:1026C0000068BFF35B8F704770B505460C30FFF7AD
-:1026D000F5FF05F1080604463046FFF7EFFFA0427C
-:1026E00006D930466D68FFF7E9FF2544281A70BD0A
-:1026F0003046FFF7E3FF201AF9E7000070B5054602
-:10270000406898B105F10800FFF7D8FF05F10C0605
-:1027100004463046FFF7D2FF8442304694BF6D68CE
-:102720000025FFF7CBFF013C2C44201A70BD0000B0
-:1027300038B50C460546FFF7C7FFA04210D305F198
-:102740000800FFF7BBFF04446868B4FBF0F100FB2E
-:102750001144BFF35B8F0120AC60BFF35B8F38BDCA
-:102760000020FCE72DE9F041144607460D46FFF72F
-:10277000C5FF844228BF0446D4B1B84658F80C6B54
-:102780004046FFF79BFF3044286040467E68FFF7D5
-:1027900095FF331A9C4203D86C600120BDE8F0819C
-:1027A0006B60A41B3B68AB602044E8600220F5E747
-:1027B0002046F3E738B50C460546FFF79FFFA042D9
-:1027C00010D305F10C00FFF779FF04446868B4FBEF
-:1027D000F0F100FB1144BFF35B8F0120EC60BFF30D
-:1027E0005B8F38BD0020FCE72DE9FF418846694634
-:1027F0000746FFF7B7FF6C4606B204EBC606002596
-:10280000B44209D06268206808EB0501FFF72AF995
-:10281000636808341D44F3E729463846FFF7CAFFCA
-:10282000284604B0BDE8F081F8B505460C300F46E7
-:10283000FFF744FF05F1080604463046FFF73EFF68
-:10284000A042304688BF6C68FFF738FF201A386016
-:1028500020B130462C68FFF731FF2044F8BD00005E
-:1028600073B5144606460D46FFF72EFF844228BF77
-:1028700004460190DCB101A93046FFF7D5FF019B6A
-:1028800033B93268C5E90233C5E9002401200CE000
-:102890009C4238BF01942860019868608442F5D951
-:1028A0003368AB60241AEC60022002B070BD204691
-:1028B000FBE700002DE9FF410F466946FFF7D0FF17
-:1028C0006C4600B204EBC0050026AC4209D0D4F837
-:1028D000048054F8081BB8194246FFF7C3F8464471
-:1028E000F3E7304604B0BDE8F081000038B5054696
-:1028F000FFF7E0FF044601462846FFF719FF204690
-:1029000038BD0000FEE7000000B59BB0EFF3098181
-:1029100068226846FFF7A6F8EFF30583044B9A6B2D
-:10292000DA6A9A6A9A6A9A6A9A6A9A6A9B6AFEE765
-:1029300000ED00E000B59BB0EFF309816822684626
-:10294000FFF790F8EFF30583044B9A6B9A6A9A6A43
-:102950009A6A9A6A9A6A9B6AFEE700BF00ED00E0F5
-:1029600000B59BB0EFF3098168226846FFF77AF85B
-:10297000EFF30583034B5A6B9A6A9A6A9A6A9A6ACA
-:102980009B6AFEE700ED00E00FB408B5029801F085
-:10299000EDFAFEE701F080BD01F058BD30B5094DFC
-:1029A0000A4491420DD011F8013B5840082340F3EE
-:1029B0000004013B2C4013F0FF0384EA5000F6D1E1
-:1029C000EFE730BD2083B8ED2DE9F041C56915B9B9
-:1029D000C161BDE8F0814B6823F06047C3F38A46CC
-:1029E0004FEAD37EC3F3807816EA230638BF3E460B
-:1029F000AC462B465A68BEEBD27F22F060440AD028
-:102A0000002A18DAA40CB44217D19D420FD10D60F0
-:102A1000DEE71346EEE7A74207D102F08044C2F397
-:102A2000807242450BD054B1EFE708D2EDE7CCF805
-:102A300000100B60CDE7B44201D0B442E5D81A686B
-:102A40009C46002AE5D11960C3E700002DE9F04754
-:102A5000089D01F007044FEAD508224405F0070558
-:102A600000EBD1004FF47F49944201D1BDE8F087DB
-:102A700004F0070705F0070A57453E4638BF56469B
-:102A8000C6F10806111B8E4228BF0E46E10808EB6E
-:102A9000D50E415C13F80EC0B94029FA06F721FAA9
-:102AA0000AF1FFB28CEA010147FA0AF739408CEAD1
-:102AB000010C03F80EC034443544D5E780EA012008
-:102AC000082341F2210201B24000002980B203F143
-:102AD000FF33B8BF504013F0FF03F4D1704700003C
-:102AE00038B50C468D18A54200D138BD14F8011B2D
-:102AF000FFF7E4FFF7E7000002684AB113680360DC
-:102B0000C388018901339BB29942C38038BF0381D6
-:102B10001046704770B588B0202204460D466846BE
-:102B20000021FEF7B1FF20460495FFF7E5FF0246BE
-:102B300058B16B46054608AE1C4603CCB44228602B
-:102B40006960234605F10805F6D1104608B070BD4E
-:102B500010B54B6823B9CA8A63F30902CA8210BD53
-:102B6000C4681A681C60C360438A013B43824A60A0
-:102B7000EFE700002DE9F84F1D46CB8A0F46C3F35F
-:102B800009010629814692460B4630D00020AAB2A0
-:102B900007F119049EB2052E1FFA80F80FD8904550
-:102BA00003F1010306D3FB8A0A4462F30903FB82A3
-:102BB00001201AE01AF80060E6540130EAE7904577
-:102BC000F1D2A1F1060B1C237C68BBFBF3F203FBE3
-:102BD00012BB1FFA8BF6002C45D14846FFF78CFF3D
-:102BE000044638B978606FF00200BDE8F88F4FF006
-:102BF0000008E6E7002606607860ADB24FF0000BF3
-:102C0000454510D90AEB0803221D13F8011B915505
-:102C1000B1B208F101081B291FFA88F82BD04545ED
-:102C200006F10106F1D8FB8AC3F30902154465F3E6
-:102C30000903BCE7013292B21C462368002BF9D18C
-:102C4000AB1F0B441C21B3FBF1F301339BB29A423F
-:102C5000D3D2BBF1000FD0D14846FFF74DFF20B9CA
-:102C6000C4F800B0BFE70122E7E7C0F800B05E4655
-:102C700020600446C1E74545D5D94846FFF73CFFEB
-:102C800008B92060AFE7C0F800B000262060044615
-:102C9000B6E700002DE9F04F2DED028B83B0CDE9B2
-:102CA0000013BDF83C4080469246002A00F0878021
-:102CB0002CB10E9B002B00F08280072C2BD808F142
-:102CC0000C00FFF719FF054638B96FF002052846DA
-:102CD00003B0BDEC028BBDE8F08F14220021FEF79B
-:102CE000D3FE22460E9905F10800FEF7BBFE631CD9
-:102CF0002B749AF800302C4403F01F0363F03F0359
-:102D00002372009B43F00041696040462946FFF76B
-:102D10005BFE0125DBE700F10C034FF0000908EE34
-:102D2000103A4FF0800B4E464D4618EE100AFFF752
-:102D3000E3FE07460028C8D014220021FEF7A4FEB7
-:102D4000002E3AD1019B3B8102220E9B02F1080129
-:102D500003EB060C57FA81F11046B44202F101026E
-:102D6000D2B201D8024607E01CF8010B01F8010BB2
-:102D70000136062AB6B2EFD99AF8001001F01F0109
-:102D8000B44208BF4FF0400BB81841EA49114BEA72
-:102D900001030372009B013243F000437B603A74ED
-:102DA00039464046FFF710FE0135B4422DB289F096
-:102DB00001094FF0000BB8D189E70022C5E76FF099
-:102DC000010584E7F8B515460E4624220021044685
-:102DD0001F46FEF759FE069B6360B5F5001F079B73
-:102DE000A76034BF6A094FF6FF72236204F10C003A
-:102DF00097B200239A4205D800230360278263829A
-:102E0000A382F8BD0660013330462036F2E70000A9
-:102E100003781BB94BB2002BC8BF0170704700008C
-:102E2000007870472DE9F74FDDF83C90BDF8305041
-:102E30000D9E9DF83840BDF84070804692469B46F6
-:102E4000B9F1000F01D1002F51D11F2C4FD898F8A4
-:102E50000000B0B9072F47D835F0030347D13A46F1
-:102E600049464FF6FF70FFF73BFE20F001002D02B0
-:102E7000400445EA0464400C44EA40244FF6FF73E2
-:102E800021E040EA0520072F40EA0464F6D9002536
-:102E90004FF6FF73C5F12000A5F120022AFA05F1D3
-:102EA0000BFA00F001432BFA02F211431846C9B2A3
-:102EB000FFF704FE0835402D0346EBD13A4649465C
-:102EC000FFF70EFE0346CDE9009732462146404605
-:102ED000FFF7E0FE33780133DBB21F2B88BF0023FE
-:102EE000337003B0BDE8F08F6FF00300F9E76FF0C7
-:102EF0000100F6E72DE9F04F85B09246DDF84880F5
-:102F00000F9D9DF840209DF84490BDF84C700646FA
-:102F10009B46B8F1000F01D1002F48D11F2A46D897
-:102F20003378002B46D00C0244EA02649DF8381036
-:102F300044EAC93444EA01441C43072F44F08004A6
-:102F400032D900234FF6FF72C3F1200CA3F1200009
-:102F50002AFA03F10BFA0CFC41EA0C012BFA00F0FF
-:102F60000143C9B210460393FFF7A8FD039B083342
-:102F7000402B0246E8D13A464146FFF7B1FD0346F1
-:102F8000CDE900872A4621463046FFF783FEB9F196
-:102F9000010F06D12B780133DBB21F2B88BF002332
-:102FA0002B7005B0BDE8F08F4FF6FF73E8E76FF0C8
-:102FB0000100F6E76FF00300F3E70000C06900B11D
-:102FC00004307047C3691A68C261C2681A60C3607E
-:102FD000438A013B438270472DE9F041D0F81880C5
-:102FE000194E14461D464146002709B9BDE8F08137
-:102FF000D1E90223A21A65EB0303964277EB0303A0
-:103000001ED283698B420DD1FFF7A2FD83691B6835
-:103010008361C3680B60438AC1608169013B43825D
-:103020008846E2E7FFF794FD0B68C8F80030C368F4
-:103030000B60438AC160013B4382D8F80010D4E79B
-:1030400088460968D1E700BF80841E002DE9F04F53
-:103050008BB00D46DDF8509014469B468046002804
-:1030600000F01981B9F1000F00F01581531E3F2BBC
-:1030700000F21181012A03D1BBF1000F40F00B8156
-:103080000023CDE90833B8F81430B5EBC30F4FEA8D
-:10309000C30703D300200BB0BDE8F08F2B199F426C
-:1030A000D8F80C303ABF7F1BFFB227461BB9D8F8BF
-:1030B0001030002B7AD02F2D4ED8C5F13006B742F4
-:1030C0004FF000032CBFF6B23E4600932946D8F8D5
-:1030D000080008AB3246FFF7B9FCA7EB060A3544F7
-:1030E0005FFA8AFAB8F8143003F10053063BDB00AC
-:1030F0000493D8F80C3003933021039B13B1BAF139
-:10310000000F2CD1D8F8100040B1BAF1000F05D053
-:10311000009608AB5246691AFFF798FC38B2002FA8
-:10312000B8D066070AD00AAB03EBD401624211F8AB
-:10313000083C02F00702134101F8083C082C3CD976
-:10314000102C40F2B580202C40F2B780BBF1000F6C
-:1031500000F09C80082334E0BA460026C2E7049BB6
-:10316000E02B28BFE02306930B44AB42059314D910
-:103170005A1B03980096924534BF5246D2B2691A40
-:1031800008AB04300792FFF761FC079A1644AAEBDC
-:10319000020A1544F6B25FFA8AFA049B069A059968
-:1031A0009B1A0493039B1B680393A6E70093D8F82C
-:1031B000080008AB3A462946AEE7BBF1000F13D032
-:1031C0000123B4EBC30F6CD0082C12D89DF820302B
-:1031D000621E23FA02F2D50706D54FF0FF3202FA3B
-:1031E00004F423438DF820309DF8203089F8003016
-:1031F00051E7102C12D8BDF82030621E23FA02F2DB
-:10320000D10706D54FF0FF3202FA04F42343ADF89C
-:103210002030BDF82030A9F800303CE7202C0FD832
-:103220000899631E21FA03F3DA0705D54FF0FF3240
-:1032300002FA04F40C430894089BC9F800302AE70A
-:10324000402C2BD0DDE90865611EC4F12102A4F1F8
-:10325000210326FA01F105FA02F225FA03F31143DC
-:103260001943CB0712D50122A4F12003C4F1200198
-:1032700002FA03F322FA01F1A240524243EA0103A7
-:1032800063EB430332432B43CDE90823DDE90823F5
-:10329000C9E90023FFE66FF00100FCE66FF00800CB
-:1032A000F9E6082CA0D9102CB3D9202CEED8C3E70E
-:1032B000BBF1000FADD0022383E7BBF1000FBBD001
-:1032C00004237EE730B5012A144638BF0124402C80
-:1032D00085B028BF40240025012ACDE9025518D821
-:1032E0001B788DF8083063070AD004AB03EBD405D4
-:1032F000624215F8083C02F00702934005F8083CCA
-:10330000009103462246002102A8FFF79FFB05B06B
-:1033100030BD082AE4D9102A03D81B88ADF808303C
-:10332000E1E7202A8DBFD3E900231B680293CDE992
-:103330000223D8E710B5CB681BB98B600B618B8279
-:1033400010BDC4681A681C60C360438A013B438295
-:10335000CA60F0E72DE9F04FD1F8008093B018F083
-:10336000800FCDE90323C8F3C01219BFC8F3C03BD7
-:10337000C8F306264FF0020B1646B8F1000F0446BC
-:103380000D4680F2C58118F0C043059340F0C0811E
-:103390000B7B002B00F0BC81BBF1020F03D0017846
-:1033A000B14240F0B88108F07F0106916AB3C8F3DA
-:1033B000074A2B44069A93F80390760646EA0B4692
-:1033C00046EA82465FEAD91346EA0A06079300F006
-:1033D000908000220023CDE90A23069B00936768B2
-:1033E0005B4652460AA92046B84700287ED0A76906
-:1033F0009FB9314604F10C00FFF78CFB0746E0B99A
-:103400006FF0020013B0BDE8F08FC8F30F2A18F078
-:103410007F0F08BF0AF0030ACBE73B699E420DD03D
-:103420003F68002FF9D1314604F10C00FFF772FB21
-:1034300007460028E4D0A3693B60A761DDE90A23C1
-:1034400000264FF6FF70C6F1200E22FA06F103FAAD
-:103450000EFEA6F1200C23FA0CFC41EA0E0141EA13
-:103460000C01C9B2083609920893FFF727FB402EDA
-:10347000DDE90832E7D1B882FB7D09F01F06C3F30E
-:1034800084039B1BD7E9022198B2002BBCBF00F13B
-:1034900020031BB252EA0100C8F304680FD003985E
-:1034A000821A049860EB0101A14890424FF000029B
-:1034B0008A4104D3079A002A55D0012B23DDFA7DD7
-:1034C0004FEA890302F0030203F07C031343FB7508
-:1034D00039462046FFF73CFB079BA3B9FB7DC3F3AE
-:1034E0008402013262F38603FB7504E06FF00B0087
-:1034F00088E7A76917B96FF00C0083E73B699E4224
-:10350000BAD03F68F6E719F0400F2CD0039BBB60A0
-:10351000049BFB60142200210DA8FEF7B5FA039B63
-:103520000A93049B0B932B1D0C932B7BADF83EA0B1
-:10353000013BDBB2ADF83C30069B8DF843308DF893
-:1035400040B0A3688DF841608DF842800AA92046FA
-:103550009847FB7DC3F38403013303F01F039B02F1
-:10356000FB8200204EE7FB7DC9F34012B2EBD31F74
-:1035700040F0D480C3F38403B34240F0D280079973
-:103580002B7B4FEA9912002934D0D20741D4032B68
-:1035900040F2CA80039BBB60049BFB602B7BAE1D8B
-:1035A000033BDBB23246394604F10C00FFF7E2FA86
-:1035B00000280DDA20463946FFF7CAFAFB7DC3F32F
-:1035C0008403013303F01F039B02FB82032019E7EE
-:1035D000AB883B832A7B033AB88AD2B23146FFF7E5
-:1035E0007FFAFB7DB882DA43C2F3C01262F3C713DD
-:1035F000FB75B6E76AB92E1D013BDBB23246394690
-:1036000004F10C00FFF7B6FA0028D3DB2A7B013A5D
-:10361000E2E7F98AC1F30901013B0529DAB253D87F
-:10362000281D002307F11A0C9A4208D910F801EB63
-:103630000CF801E0013101330629DBB2F4D1039922
-:103640000A9104990B91934207F11A010C9138BF2A
-:10365000043379680D9134BF55FA83F300230E9338
-:10366000FB8AADF83EA0C3F309031A44069B8DF80C
-:1036700043300023ADF83C208DF840B08DF8416018
-:103680008DF842807B602A7BB88A013A291DFFF7BA
-:1036900027FA3B8BB882834203D1A3680AA920464C
-:1036A000984720460AA9FFF745FEFB7DB88AC3F379
-:1036B0008403013303F01F039B02FB823B8B984280
-:1036C00014BF112000209DE67B68002BB7D0062098
-:1036D00001E01C306346D3F800C0BCF1000FF8D104
-:1036E000091A081D05F1040C00EB030905989DF863
-:1036F000143001EB000EBEF11B0FA0D89A429ED9E8
-:103700001CF8013B09F8013B059B01330593EDE7EC
-:103710006FF0090076E66FF00A0073E66FF00D00B7
-:1037200070E66FF00E006DE66FF00F006AE600BF06
-:1037300080841E00EFF3098305494A6B22F00102E1
-:103740004A63683383F30988002383F31188704741
-:1037500000EF00E0202080F3118862B60C4B0D4A88
-:10376000D96821F4E0610904090C0A43DA60D3F84E
-:10377000FC20094942F08072C3F8FC200A6842F03C
-:1037800001020A601022DA7783F82200704700BF36
-:1037900000ED00E00003FA05001000E010B5202362
-:1037A00083F311880E4B5B6813F4006314D0F1EEC1
-:1037B000103AEFF30984683C4FF08073E361094BE2
-:1037C000DB6B236684F3098800F082FB10B1064BA3
-:1037D000A36110BD054BFBE783F31188F9E700BF38
-:1037E00000ED00E000EF00E04B0600084E06000888
-:1037F000026843681143016003B118477047000035
-:10380000024A136843F0C003136070470038014058
-:1038100013B50D4C204600F09DFA04F114000B493D
-:1038200000940023202200F05FF9094B094900941D
-:10383000202204F1380000F0D9F9074A074BC4E907
-:10384000172302B010BD00BFAC380020183900208B
-:10385000013800083839002000380140007A030A96
-:1038600030B5037C234C002918BF0C46012B0FD127
-:10387000214B98420CD1214B1A6E42F480421A66B9
-:10388000D3F8802042F48042C3F88020D3F88030FF
-:103890002268036EC16D846603EB5203B3FBF2F33F
-:1038A0006268150442BF23F0070503F0070343EAEB
-:1038B0004503CB60A36843F040034B60E36843F0EB
-:1038C00001038B6042F4967343F001030B604FF0E9
-:1038D000FF330B62510505D512F0102205D0B2F16D
-:1038E000805F04D080F8643030BD7F23FAE73F2347
-:1038F000F8E700BFFC4D0008AC3800200010024083
-:103900002DE9F047C66D3768F46934622107054632
-:1039100018D014F0080118BF8021E20748BF41F019
-:103920002001A30748BF41F04001600748BF41F4B0
-:103930008071202383F31188281DFFF759FF00238E
-:1039400083F31188E2050AD5202383F311884FF40D
-:103950000071281DFFF74CFF002383F311884FF0FF
-:1039600020094FF0000A14F0200838D13B0616D584
-:103970004FF0200905F1380A200610D589F3118887
-:10398000504600F067F9002836DA0821281DFFF7B5
-:103990002FFF27F080033360002383F3118879061B
-:1039A00014D5620612D5202383F31188D5E9132399
-:1039B0009A4208D12B6C33B11021281D27F0400703
-:1039C000FFF716FF3760002383F31188E30618D54D
-:1039D000AA6E1369ABB1BDE8F0475069184789F387
-:1039E0001188736A95F864102846194000F0CCF9E4
-:1039F0008AF31188F469B6E7B06288F31188F46934
-:103A0000BAE7BDE8F087000000F1604303F56143C9
-:103A10000901C9B283F80013012200F01F039A4084
-:103A200043099B0003F1604303F56143C3F8802120
-:103A30001A607047F8B5154682680669AA420B46B7
-:103A4000816938BF8568761AB54204460BD218469C
-:103A50002A46FEF707F8A3692B44A361A3685B1B02
-:103A6000A3602846F8BD0CD918463246FDF7FAFF88
-:103A7000AF1BE1683A463044FDF7F4FFE3683B448E
-:103A8000EBE718462A46FDF7EDFFE368E5E700009F
-:103A900083689342F7B51546044638BF8568D0E978
-:103AA0000460361AB5420BD22A46FDF7DBFF636984
-:103AB0002B446361A36828465B1BA36003B0F0BD81
-:103AC0000DD932460191FDF7CDFF0199E068AF1B9A
-:103AD0003A463144FDF7C6FFE3683B44E9E72A462E
-:103AE000FDF7C0FFE368E4E710B50A440024C361B2
-:103AF000029B8460C0E90000C0E90511C160026159
-:103B0000036210BD08B5D0E90532934201D1826845
-:103B100082B98268013282605A1C42611970D0E910
-:103B200004329A4224BFC3684361002100F0A0FA26
-:103B3000002008BD4FF0FF30FBE7000070B52023E8
-:103B400004460E4683F31188A568A5B1A368A2694F
-:103B5000013BA360531CA36115782269934224BFE3
-:103B6000E368A361E3690BB120469847002383F320
-:103B70001188284607E03146204600F069FA0028FF
-:103B8000E2DA85F3118870BD2DE9F74F04460E4641
-:103B900017469846D0F81C904FF0200A8AF31188F7
-:103BA0004FF0000B154665B12A4631462046FFF717
-:103BB00041FF034660B94146204600F049FA00281B
-:103BC000F1D0002383F31188781B03B0BDE8F08F98
-:103BD000B9F1000F03D001902046C847019B8BF339
-:103BE0001188ED1A1E448AF31188DCE7C0E905113B
-:103BF000C160C3611144009B8260C0E900000161A3
-:103C000003627047F8B504460D461646202383F339
-:103C10001188A768A7B1A368013BA36063695A1C18
-:103C200062611D70D4E904329A4224BFE368636183
-:103C3000E3690BB120469847002080F3118807E024
-:103C40003146204600F004FA0028E2DA87F31188B2
-:103C5000F8BD0000D0E905239A4210B501D1826871
-:103C60007AB98268013282605A1C82611C780369C9
-:103C70009A4224BFC3688361002100F0F9F920460D
-:103C800010BD4FF0FF30FBE72DE9F74F04460E461D
-:103C900017469846D0F81C904FF0200A8AF31188F6
-:103CA0004FF0000B154665B12A4631462046FFF716
-:103CB000EFFE034660B94146204600F0C9F90028EE
-:103CC000F1D0002383F31188781B03B0BDE8F08F97
-:103CD000B9F1000F03D001902046C847019B8BF338
-:103CE0001188ED1A1E448AF31188DCE702684368E4
-:103CF0001143016003B11847704700001430FFF70B
-:103D000043BF00004FF0FF331430FFF73DBF00000A
-:103D10003830FFF7B9BF00004FF0FF333830FFF7FE
-:103D2000B3BF00001430FFF709BF00004FF0FF31B0
-:103D30001430FFF703BF00003830FFF763BF000007
-:103D40004FF0FF323830FFF75DBF000000207047B2
-:103D5000FFF75EBD044B03600023C0E902334360FC
-:103D600001230374704700BF144E000810B52023D0
-:103D7000044683F31188FFF773FD022323740023A5
-:103D800083F3118810BD000038B5C36904460D46A1
-:103D90001BB904210844FFF7A9FF294604F11400C8
-:103DA000FFF7B0FE002806DA201D4FF48061BDE861
-:103DB0003840FFF79BBF38BD024B0022C3E90033F8
-:103DC0009A60704758390020002303748268054BBD
-:103DD0001B6899689142FBD25A6803604260106088
-:103DE000586070475839002008B5202383F31188A4
-:103DF000037C032B05D0042B0DD02BB983F3118842
-:103E000008BD436900221A604FF0FF334361FFF79A
-:103E1000DBFF0023F2E7D0E9003213605A60F3E7DA
-:103E2000002303748268054B1B6899689142FBD894
-:103E30005A6803604260106058607047583900202B
-:103E4000054B19690874186802681A605360186194
-:103E500001230374FCF7E4BB5839002030B54B1C38
-:103E60000B4D87B0044610D02B690A4A01A800F018
-:103E700019F92046FFF7E4FF049B13B101A800F0F5
-:103E80004DF92B69586907B030BDFFF7D9FFF8E746
-:103E900058390020E93D000838B50C4D41612B69C7
-:103EA00081689A689142044603D8BDE83840FFF71C
-:103EB0008BBF1846FFF7B4FF01232C610146237422
-:103EC0002046BDE83840FCF7ABBB00BF58390020A6
-:103ED000044B1A681B6990689B68984294BF002045
-:103EE000012070475839002010B5084C236820691C
-:103EF0001A6822605460012223611A74FFF790FF50
-:103F000001462069BDE81040FCF78ABB5839002003
-:103F100008B5FFF7DDFF18B1BDE80840FFF7E4BFC3
-:103F200008BD0000FFF7E0BFFEE7000010B50C4C35
-:103F3000FFF742FF00F0A8F80A498022204600F06F
-:103F40003DF8012344F8180C0374FFF703FC002329
-:103F500083F3118862B60448BDE8104000F04EB803
-:103F6000803900203C4E00084C4E000808B572B65F
-:103F7000034B586200F05AFA00F00EFBFEE700BF58
-:103F80005839002000F004B9EFF3118020B9EFF3A5
-:103F90000583202282F311887047000010B530B9E4
-:103FA000EFF30584C4F3080414B180F3118810BD45
-:103FB000FFF7AEFF84F31188F9E700008260022268
-:103FC000028270478368A3F17C0243F80C2C0269DB
-:103FD00043F83C2C426943F8382C074A43F81C2C20
-:103FE000C26843F8102C022203F8082C002203F8C0
-:103FF000072CA3F1180070473906000810B52023DC
-:1040000083F31188FFF7DEFF00210446FFF744FF2A
-:10401000002383F31188204610BD0000024B1B696A
-:1040200058610F20FFF70CBF58390020202383F37D
-:104030001188FFF7F3BF000008B50146202383F382
-:1040400011880820FFF70AFF002383F3118808BDB9
-:1040500049B1064B42681B6918605A60136043609F
-:104060000420FFF7FBBE4FF0FF30704758390020A7
-:104070000368984206D01A68026050605961184679
-:10408000FFF7A2BE70470000054B03F11402C3E91D
-:1040900005224FF0FF310022C3E90712704700BF2D
-:1040A0005839002070B51C4EC0E9032305460C4664
-:1040B00000F0E8FA334653F8142F9A420DD13062DB
-:1040C000C5E901242A600A2C2CBF00190A30C6E970
-:1040D0000555BDE8704000F0C3BA316A431AE318D1
-:1040E00038BF1C469368A34202D9081900F0C6FAEB
-:1040F00073699A6894420CD85A68AC602B606A6005
-:1041000015609A685D60121B9A604FF0FF33F3618F
-:1041100070BD1B68A41AECE75839002038B51B4C59
-:10412000636998420DD0D0E9003213605A600022D2
-:104130008168C2609A680A449A604FF0FF33E36175
-:1041400038BD2246036842F8143F002193425A606A
-:10415000C16003D1BDE8384000F08ABA9A6881682E
-:10416000256A0A449A6000F08DFA63699A68411BD7
-:104170008A42E5D9AB181D1A092D206A98BF01F1B2
-:104180000A02BDE83840104400F078BA58390020DF
-:104190002DE9F041184C002704F11406656900F080
-:1041A00071FA236AAA68C11A8A4215D81344236295
-:1041B000D5E9003213605A606369D5F80C80EF606E
-:1041C000B34201D100F054FA87F311882869C0473F
-:1041D000202383F31188E1E76169B14209D01344D8
-:1041E0001B1ABDE8F0410A2B2CBFC0180A3000F0A2
-:1041F00045BABDE8F08100BF583900200020704763
-:10420000FEE70000704700004FF0FF3070470000ED
-:10421000BFF34F8F024A1369DB03FCD4704700BF22
-:104220000020024008B5094B1B7873B9FFF7F0FF77
-:10423000074B5A69002ABFBF064A9A6002F18832CA
-:104240009A601A6822F480621A6008BDE03A002081
-:10425000002002402301674508B50B4B1B7893B93A
-:10426000FFF7D6FF094B5A6942F000425A611A68BB
-:1042700042F480521A601A6822F480521A601A6856
-:1042800042F480621A6008BDE03A0020002002403B
-:104290003F289ABF00F58030C00200207047000020
-:1042A0004FF4006070470000402070473F2808B579
-:1042B0000BD8FFF7EDFF00F500630268013204D16F
-:1042C00004308342F9D1012008BD0020FCE7000042
-:1042D0003F2810B504461FD8FFF79AFFFFF7A2FF4B
-:1042E0000E4BF3221A6102225A615A6942EAC00255
-:1042F0005A615A6942F480325A61FFF789FF4FF4DC
-:104300000061FFF7C5FF00F043F9FFF7A5FF204666
-:10431000BDE81040FFF7CABF002010BD00200240DA
-:104320002DE9F84340EA020313F00703144606D0D0
-:104330002E4B40F2BF221A600020BDE8F88385189A
-:104340002B4A95420CD9294A4FF431711160F3E799
-:10435000031D1B684A68934208D1083C08300831A5
-:10436000072C14D902680B689A42F1D0FFF75AFF64
-:10437000FFF74EFF1F4E08314FF001084FF00009C4
-:10438000012CA1F1080706D8FFF766FF01E0002C19
-:10439000ECD10120D1E7C6F81480054651F8083C5D
-:1043A00045F8043B51F8043C4360FFF731FFC6F881
-:1043B0001490026851F8083C9A420CD00B4B40F222
-:1043C000EA221A600C4B18600C4B1C600C4B1F60EF
-:1043D000FFF742FFB0E72D6851F8043C9D4201F120
-:1043E0000801EBD1083C0830CAE700BFDC3A0020E6
-:1043F000FFFF010800200240D03A0020D83A0020F8
-:10440000D43A0020084908B50B7828B11BB9FFF74A
-:1044100009FF01230B7008BD002BFCD0BDE808404C
-:104420000870FFF719BF00BFE03A002008B54FF44D
-:10443000B0414FF0005000F0ADF8BDE808404FF437
-:1044400020514FF0805000F0A5B8000070B582B048
-:10445000FFF79AFD0E4E054600F014F932689042BF
-:1044600037BF0C4A0B49516814682EBFD1E900418F
-:10447000013151600419034641F1000128460191C0
-:104480003360FFF78BFD0199204602B070BD00BF7D
-:10449000E43A0020E83A002070B582B0FFF774FDDE
-:1044A000104E054600F0EEF83268904237BF0E4AD3
-:1044B0000D49516814682EBFD1E9004101315160A6
-:1044C000041941F100010346284601913360FFF7CA
-:1044D00065FD01994FF47A7200232046FBF788FEB0
-:1044E00002B070BDE43A0020E83A00200244D2B2A3
-:1044F000904200D17047431C800000F1804000F5DD
-:104500001450006841F8040BD8B2F1E7124B10B513
-:10451000D3F89040240409D4D3F89040C3F89040D5
-:10452000D3F8904044F40044C3F890400B4C236807
-:10453000024443F480732360D2B2904200D110BD94
-:10454000431C800000F1804000F5145051F8044BEA
-:104550000460D8B2F1E700BF0010024000700040D4
-:1045600007B5012201A90020FFF7C0FF019803B0A1
-:104570005DF804FB13B50446FFF7F2FFA04205D037
-:10458000012201A900200194FFF7C0FF02B010BD75
-:10459000704700007047000070470000074B45F26D
-:1045A00055521A6002225A6040F6FF729A604CF629
-:1045B000CC421A60024B01221A7070470030004052
-:1045C000F13A0020034B1B781BB1034B4AF6AA2299
-:1045D0001A607047F13A002000300040044BD3F8D5
-:1045E00094309B0042BF034B01221A70704700BFFA
-:1045F00000100240F03A0020024B4FF40002C3F8D2
-:104600009420704700100240014B1878704700BF9B
-:10461000F03A002070470000FEE700000A4B0B480C
-:104620000B4A90420BD30B4BDA1C121AC11E22F01C
-:1046300003028B4238BF00220021FDF725BA53F850
-:10464000041B40F8041BECE7BC4F00087C3B002037
-:104650007C3B00207C3B00207047000000F078B8D5
-:104660004FF08043002258631A610222DA607047DB
-:104670004FF080430022DA60704700004FF0804323
-:10468000586370474FF08043586A70474B684360E7
-:104690008B688360CB68C3600B6943614B690362BD
-:1046A0008B6943620B6803607047000008B5204BBC
-:1046B000DA6A42F07F02DA62DA6A22F07F02DA62B4
-:1046C000DA6ADA6C42F07F02DA64DA6E42F07F0274
-:1046D000DA66184ADB6E11464FF09040FFF7D6FFBE
-:1046E00002F11C0100F58060FFF7D0FF02F13801F4
-:1046F00000F58060FFF7CAFF02F1540100F5806009
-:10470000FFF7C4FF02F1700100F58060FFF7BEFF04
-:1047100002F18C0100F58060FFF7B8FF02F1A801FB
-:1047200000F58060FFF7B2FFBDE8084000F064B814
-:1047300000100240644E000808B500F003FAFFF7CD
-:10474000F5FBBDE80840FFF749BF000070470000D7
-:104750000F4B9A6D42F001029A659A6F42F0010286
-:104760009A670C4A9B6F936843F0010393604FF084
-:104770008043A7229A624FF0FF32DA6200229A61E8
-:104780005A63DA605A6001225A611A60704700BFAA
-:1047900000100240002004E04FF0804208B511698B
-:1047A000D3680B40D9B2C9439B07116107D52023B9
-:1047B00083F31188FFF7E6FB002383F3118808BD1C
-:1047C00008B50B4BD3F8902012F4407F1FBF4FF475
-:1047D0008032C3F890200022C3F89020D3F89020B4
-:1047E000C3F8902000F086F9024B00225A6008BD01
-:1047F0000010024000700040484B4FF0FF319A6AB1
-:1048000099629A6A00229A62986AD86A60F07F0078
-:10481000D862D86A00F07F00D862D86A186B196332
-:10482000186B1A63186B986B9963986B9A63986B03
-:10483000D86BD963D86BDA63D86B186C1964196CB0
-:104840001A641A6C9A6D42F080529A659A6F22F03F
-:1048500080529A679A6F324A4FF400711160516921
-:1048600011F48061FBD14FF40040516090604FF42F
-:104870008070D160C2F88000116251629162D16291
-:10488000116351639163D163116451649164D16484
-:1048900011655165D3F8982042F00102C3F89820C1
-:1048A000D3F898209007FBD51A6842F480321A603A
-:1048B0001A689103FCD51A490A6842F480720A60AA
-:1048C000184ADA601A6842F080721A601A68920117
-:1048D000FCD5002214499A60C3F888101349C3F824
-:1048E0009C20134A0A600A6802F00F02042AFAD1D7
-:1048F0009A6842F003029A609A6802F00C020C2A4D
-:10490000FAD11A6E42F001021A66D3F8802042F002
-:104910000102C3F88020D3F88030704700100240B5
-:1049200000700040232A6101550100500020024020
-:1049300004070400074A08B5536903F001035361F3
-:1049400023B1054A13680BB150689847BDE8084089
-:10495000FEF724BF00040140F43A0020074A08B5DE
-:10496000536903F00203536123B1054A93680BB105
-:10497000D0689847BDE80840FEF710BF000401402A
-:10498000F43A0020074A08B5536903F00403536161
-:1049900023B1054A13690BB150699847BDE8084037
-:1049A000FEF7FCBE00040140F43A0020074A08B5B7
-:1049B000536903F00803536123B1054A93690BB1AE
-:1049C000D0699847BDE80840FEF7E8BE0004014002
-:1049D000F43A0020074A08B5536903F01003536105
-:1049E00023B1054A136A0BB1506A9847BDE80840E5
-:1049F000FEF7D4BE00040140F43A0020164B10B577
-:104A00005C6904F478725A61A30604D5134A936A68
-:104A10000BB1D06A9847600604D5104A136B0BB1EE
-:104A2000506B9847210604D50C4A936B0BB1D06BA1
-:104A30009847E20504D5094A136C0BB1506C9847AE
-:104A4000A30504D5054A936C0BB1D06C9847BDE81B
-:104A50001040FEF7A3BE00BF00040140F43A00205E
-:104A6000194B10B55C6904F47C425A61620504D5A7
-:104A7000164A136D0BB1506D9847230504D5134AA0
-:104A8000936D0BB1D06D9847E00404D50F4A136EB7
-:104A90000BB1506E9847A10404D50C4A936E0BB12C
-:104AA000D06E9847620404D5084A136F0BB1506F5B
-:104AB0009847230404D5054A936F0BB1D06F9847EC
-:104AC000BDE81040FEF76ABE00040140F43A002041
-:104AD00008B50348FEF714FFBDE80840FEF75EBEC8
-:104AE000AC38002008B5FFF757FEBDE80840FEF7D8
-:104AF00055BE0000062108B50846FEF785FF0621D1
-:104B00000720FEF781FF06210820FEF77DFF062122
-:104B10000920FEF779FF06210A20FEF775FF06211E
-:104B20001720FEF771FF06212820FEF76DFF0721F1
-:104B30001C20FEF769FFBDE808400C212520FEF788
-:104B400063BF000008B5FFF73BFE00F009F8FFF770
-:104B5000FFF8FFF7FBFDBDE80840FFF77FBD000051
-:104B60000023054A19460133102BC2E9001102F156
-:104B70000802F8D1704700BFF43A00200B46014606
-:104B8000184600F003B8000000F00EB810B5054C50
-:104B900013462CB10A4601460220AFF3008010BD37
-:104BA0002046FCE700000000024B0146186800F0B8
-:104BB00035B800BF2811002010B5013902449042D9
-:104BC00001D1002005E0037811F8014FA34201D084
-:104BD000181B10BD0130F2E72DE9F041A3B1C91A4D
-:104BE00017780144044603F1FF3C8C42204601D96A
-:104BF000002009E00578BD4204F10104F5D10CEB79
-:104C00000405D618A54201D1BDE8F08115F8018D43
-:104C100016F801EDF045F5D0E7E7000037B50029BB
-:104C200044D051F8043C0190002BA1F10404B8BF1A
-:104C3000E41800F047F81E4A0198136833B963601E
-:104C4000146003B0BDE8304000F042B8A34208D978
-:104C5000256861198B4201BF19685B684919216099
-:104C6000EDE71A465B680BB1A342FAD911685518F3
-:104C7000A5420BD1246821445418A3421160E0D10D
-:104C80001C685B68536021441160DAE702D90C2389
-:104C90000360D6E7256861198B4204BF19685B6819
-:104CA000636004BF491921605460CAE703B030BD96
-:104CB000743B0020034611F8012B03F8012B002A56
-:104CC000F9D17047014800F009B800BF783B0020D7
-:104CD000014800F005B800BF783B00207047000095
-:104CE000704700006F72672E6172647570696C6F37
-:104CF000742E48697465632D4169727370656564CB
-:104D0000000000004E6F20617070207369670A0018
-:104D1000426164206677206C656E67746820257533
-:104D20000A0042616420626F6172645F69642025D9
-:104D3000752073686F756C642062652025750A00A4
-:104D40004261642066772064657363726970746F72
-:104D500072206C656E6774682025750A0042616474
-:104D60002061707020435243203078253038783AE3
-:104D7000307825303878203078253038783A3078D7
-:104D8000253038780A00476F6F64206669726D7746
-:104D90006172650A0040A2E4F164689106000000B7
-:104DA00053544D333247343F3F000000426164208A
-:104DB00043414E496661636520696E6465782E00E3
-:104DC00000000000000000008D1F0008B52500084D
-:104DD0008D1B0008211C0008791D0008E91B000834
-:104DE000B11B0008B51B0008911B0008991B0008A7
-:104DF000951B0008391D0008A51B0008009600003F
-:104E000000000000000000000000000000000000A2
-:104E10000000000000000000193D0008053D0008EA
-:104E2000413D00082D3D0008393D0008253D0008A2
-:104E3000113D0008FD3C00084D3D00086D61696EA4
-:104E40000000000069646C6500000000444E00082A
-:104E500098390020D03A002001000000293F0008C6
-:104E6000000000000010802A00000000AAAAAAAAE0
-:104E700000000000BFFF00000000000000900900DB
-:104E800000A0000100000000AAFAAAAA0050000138
-:104E9000FFFF00000000007700000000000000009D
-:104EA00000000000AAAAAAAA00000000FFFF00005C
-:104EB00000000000000000000000000000000000F2
-:104EC000AAAAAAAA00000000FFFF0000000000003C
-:104ED000000000000000000000000000AAAAAAAA2A
-:104EE00000000000FFFF00000000000000000000C4
-:104EF0000000000000000000AAAAAAAA000000000A
-:104F0000FFFF0000000000000000000000000000A3
-:104F100000000000AAAAAAAA00000000FFFF0000EB
-:104F20000000000000000000F8B2FF7F0100000058
-:104F300016040000000000000098010000000000BE
-:104F4000FE2A0100D2040000FF0000000000000063
-:104F5000A04D00083F0000002C11002000000000C0
-:104F60000000000000000000000000000000000041
-:104F70000000000000000000000000000000000031
-:104F80000000000000000000000000000000000021
-:104F90000000000000000000000000000000000011
-:104FA0000000000000000000000000000000000001
-:0C4FB000000000000000000000000000F5
+:1004F000704700BF02E000F000F8FEE772B6374830
+:1005000080F30888364880F3098836483649086001
+:1005100040F20000CCF200004EF63471CEF2000141
+:100520000860BFF34F8FBFF36F8F40F20000C0F23F
+:10053000F0004EF68851CEF200010860BFF34F8FF5
+:10054000BFF36F8F4FF00000E1EE100A4EF63C71E2
+:10055000CEF200010860062080F31488BFF36F8F8D
+:1005600004F044FB04F0D6FB4FF055301F491B4A02
+:1005700091423CBF41F8040BFAE71D49184A9142E9
+:100580003CBF41F8040BFAE71A491B4A1B4B9A423D
+:100590003EBF51F8040B42F8040BF8E7002018495D
+:1005A000184A91423CBF41F8040BFAE704F022FBE1
+:1005B00004F0F6FB144C154DAC4203DA54F8041B5E
+:1005C0008847F9E700F042F8114C124DAC4203DACB
+:1005D00054F8041B8847F9E704F00ABB000900201F
+:1005E000001100200000000808ED00E000010020DC
+:1005F0000009002048540008001100208C11002040
+:1006000090110020703C0020E0010008E401000887
+:10061000E4010008E40100082DE9F04F2DED108AF7
+:10062000C1F80CD0C3689D46BDEC108ABDE8F08FC0
+:10063000002383F311882846A047002003F054FFCD
+:10064000FEE703F0B7FE00DFFEE70000F8B504F0B8
+:100650006FFA074604F0C0FA0546B8BB204B9F422C
+:1006600034D001339F4234D01E4B27F0FF029A4210
+:1006700032D1F8B200F04EFE2E4642F2107400F075
+:100680004FFE08B10024264601F0A6FA20B103204F
+:1006900000F07CF80024264635B1134B9F4203D06E
+:1006A00004F092FA00242646002004F04BFA0EB122
+:1006B00000F082F801F05AF900F056FE01F04CF813
+:1006C000204600F0D7F800F077F8F9E72E4600242E
+:1006D000D5E704460126D2E706464FF47A74CEE702
+:1006E000010007B0000008B0263A09B008B500F0D4
+:1006F000FFFFA0F120035842584108BD07B541F261
+:100700001203022101A8ADF8043001F00FF803B084
+:100710005DF804FB38B5302383F31188174803686C
+:100720000BB103F09FFF164A144800234FF47A716F
+:1007300003F08EFF002383F31188124C236813B15A
+:100740002368013B2360636813B16368013B636006
+:100750000D4D2B7833B963687BB9022001F094F812
+:10076000322363602B78032B07D163682BB90220F7
+:1007700001F08AF84FF47A73636038BD901100205D
+:1007800015070008B0120020A8110020084B1870AF
+:1007900003280CD8DFE800F008050208022001F069
+:1007A0006BB8022001F060B8024B00225A6070471B
+:1007B000A8110020B012002038B501F00DFA30B1B8
+:1007C000254B03221A70254B00225A6038BD244B5A
+:1007D000244A19680131F9D004339342F9D1224CEB
+:1007E0001F4DD4F80428AA42F0D3204B9B6803F194
+:1007F000006303F5D0439A42E8D204F0B7F904F05D
+:10080000C9F9002000F0C2FF0220FFF7BFFF184B1C
+:100810009A6D00229A65996F9A67996FD96DDA651A
+:10082000D96FDA67D96F196E1A66D3F88010C3F8DA
+:100830008020D3F8803072B64FF0E0233021C3F827
+:10084000085DD4F80038D4F8042881F311889D4657
+:1008500083F308881047B9E7A8110020B0120020E0
+:1008600000680008206800080060000800110020EF
+:10087000001002402DE9F04F93B0AC4B00902022C5
+:10088000FF210AA89D6801F01BF8A94A1378A3B9B3
+:10089000A848012103601170302383F31188036895
+:1008A0000BB103F0DFFEA44AA24800234FF47A7193
+:1008B00003F0CEFE002383F31188009B13B19F4BFE
+:1008C000009A1A609E4A009C1378032B1EBF0023D7
+:1008D00013709A4A4FF0000A18BF5360D346564629
+:1008E000D146012000F0C8FF24B1944B1B68002BB7
+:1008F00000F01582002000F0FBFE0390039B002B0C
+:1009000001DA00F079FD039B002BEDDB012000F004
+:10091000ABFF039B213B162BE3D801A252F823F037
+:100920007D090008A5090008390A0008E308000845
+:10093000E3080008E3080008C30A0008930C000855
+:10094000AD0B00080F0C0008370C00085D0C000808
+:10095000E30800086F0C0008E3080008E10C000839
+:100960001D0A0008E3080008250D00088909000891
+:100970001D0A0008E30800080F0C00080220FFF71A
+:10098000B5FE002840F0F581009B0221BAF1000F6E
+:1009900008BF1C4605A841F21233ADF8143000F030
+:1009A000C5FE9EE74FF47A7000F0A2FE071EEBDB57
+:1009B0000220FFF79BFE0028E6D0013F052F00F242
+:1009C000DA81DFE807F0030A0D10133605230593DB
+:1009D000042105A800F0AAFE17E054480421F9E715
+:1009E00058480421F6E758480421F3E74FF01C0863
+:1009F000404600F0CDFE08F104080590042105A84A
+:100A000000F094FEB8F12C0FF2D1012000FA07F7A4
+:100A100047EA0B0B5FFA8BFB4FF0000900F09CFFDD
+:100A200026B10BF00B030B2B08BF0024FFF766FE6B
+:100A300057E746480421CDE7002EA5D00BF00B0365
+:100A40000B2BA1D10220FFF751FE074600289BD0B7
+:100A5000012000F09BFE0220FFF798FE00265FFABF
+:100A600086F8404600F0A4FE044690B100214046BE
+:100A700000F0AEFE01360028F1D1BA46044641F23C
+:100A80001213022105A8ADF814303E4600F04EFEC8
+:100A900027E70120FFF77AFE2546244B9B68AB42EF
+:100AA00007D9284600F074FE013040F06781043514
+:100AB000F3E7234B00251D70204BBA465D603E4690
+:100AC000ACE7002E3FF460AF0BF00B030B2B7FF471
+:100AD0005BAF0220FFF75AFE322000F009FEB0F1B2
+:100AE0000008FFF651AF18F003077FF44DAF0F4A2F
+:100AF000926808EB050393423FF646AFB8F5807F56
+:100B00003FF742AF124B0193B84523DD4FF47A70A3
+:100B100000F0EEFD0390039A002AFFF635AF019B2B
+:100B2000039A03F8012B0137EDE700BF0011002005
+:100B3000AC1200209011002015070008B012002010
+:100B4000A811002004110020081100200C11002021
+:100B5000AC110020C820FFF7C9FD074600283FF46C
+:100B600013AF1F2D11D8C5F1200242450AAB25F065
+:100B7000030028BF424683490192184400F08EFECC
+:100B8000019A8048FF2100F09BFE4FEAA8037D49AF
+:100B90000193C8F38702284600F09AFE0646002813
+:100BA0003FF46DAF019B05EB830537E70220FFF7AC
+:100BB0009DFD00283FF4E8AE00F01CFE00283FF445
+:100BC000E3AE0027B846704B9B68BB4218D91F2F75
+:100BD00011D80A9B01330ED027F0030312AA134445
+:100BE00053F8203C05934046042205A900F0DEFF9F
+:100BF00004378046E7E7384600F0CAFD0590F2E783
+:100C0000CDF81480042105A800F090FD06E700232C
+:100C1000642104A8049300F07FFD00287FF4B4AEA3
+:100C20000220FFF763FD00283FF4AEAE049800F009
+:100C3000D7FD0590E6E70023642104A8049300F0A3
+:100C40006BFD00287FF4A0AE0220FFF74FFD0028C7
+:100C50003FF49AAE049800F0C5FDEAE70220FFF7E2
+:100C600045FD00283FF490AE00F0D4FDE1E70220FE
+:100C7000FFF73CFD00283FF487AE05A9142000F0E3
+:100C8000CFFD04210746049004A800F04FFD39462B
+:100C9000B9E7322000F02CFD071EFFF675AEBB074A
+:100CA0007FF472AE384A926807EB090393423FF62D
+:100CB0006BAE0220FFF71AFD00283FF465AE27F067
+:100CC00003074F44B9453FF4A9AE484600F060FD24
+:100CD0000421059005A800F029FD09F10409F1E7B8
+:100CE0004FF47A70FFF702FD00283FF44DAE00F09C
+:100CF00081FD002844D00A9B01330BD008220AA9A9
+:100D0000002000F0E5FD00283AD02022FF210AA8AB
+:100D100000F0D6FDFFF7F2FC1C4803F0EBFB13B02C
+:100D2000BDE8F08F002E3FF42FAE0BF00B030B2B22
+:100D30007FF42AAE0023642105A8059300F0ECFCA3
+:100D4000074600287FF420AE0220FFF7CFFC804644
+:100D500000283FF419AEFFF7D1FC41F2883003F0D0
+:100D6000C9FB059800F00EFE464600F0F5FD3C4636
+:100D7000B7E5064652E64FF0000905E6BA467EE6BC
+:100D800037467CE6AC11002000110020A08601004F
+:100D9000094A136849F2690099B21B0C00FB013340
+:100DA0001360064B186844F2506182B2000C01FBDC
+:100DB0000200186080B2704714110020101100204A
+:100DC00010B500211022044600F07AFD034B03CB3E
+:100DD000206061601868A06010BD00BF9075FF1FA3
+:100DE0002DE9F041ADF5507D0DF13C086EAC40F2BF
+:100DF000751207460D4610A80021C8F8001000F033
+:100E00005FFD4FF4C4720021204600F059FD01F04F
+:100E100023FF254B4FF47A72B0FBF2F0186093E891
+:100E20000700012384E807000DF5ED702382FFF72A
+:100E3000C7FF41F204631D49238407A804F01AFA8E
+:100E40001C2384F832310DF2EB226B440DF1340C8B
+:100E50001E4603CE664510605160334602F108021B
+:100E6000F6D13068106041460122204600F0A4FD12
+:100E700000230393AB7E029305F11903019380B223
+:100E80000123CDE904800093E97E05A3D3E9002383
+:100E9000384602F0A1FA0DF5507DBDE8F08100BFA3
+:100EA0009E6AC421818A46EEB8120020845200084E
+:100EB0002DE9F043224DBBB001F0CEFEAB6840F20D
+:100EC000ED22C31A934232D906AFA8602B462822DE
+:100ED0000021384602F030FC05F10E0000F0E8FC7D
+:100EE000002604465FFA80F905F10E08F3B2F1001E
+:100EF000994501F1280107D908EB06030822384675
+:100F000002F01AFC0136F1E708230122CDE9023292
+:100F100005340C4B0193A4B230230093CDE9047443
+:100F200005A3D3E90023297B074802F055FA3BB01B
+:100F3000BDE8F083AFF3008078F6339F93CACD8D80
+:100F4000B0370020BD370020D0220020F0B58B8ABA
+:100F5000013B9BB2C92BC9B006460C4647D8274D6A
+:100F60002F7B27BB05F10C03009308223B46394633
+:100F7000204602F0A5FA7B1CFAB2D9001F46A38ACC
+:100F8000013B9A4205DA0E322A44009200230822DD
+:100F9000EEE700230022C5E900230023AB6085F8BB
+:100FA000D730C5F8D8302B7B0BB9E37E2B73812269
+:100FB000002106AD27A800F083FC0122294627A8BE
+:100FC00000F0C8FD00230393A37E029304F11903EC
+:100FD00080B201932823CDE90450E17E009330468E
+:100FE00004A3D3E9002302F0F7F9FFF761FF49B04A
+:100FF000F0BD00BF26417272DF25D7B7B0370020A1
+:1010000070B50D4614461E4602F042F950B9022E44
+:1010100010D1012C0ED112A3D3E90023C5E900237E
+:10102000012007E0282C10D005D8012C09D0052C70
+:101030000FD0002070BD302CFBD10BA3D3E90023CF
+:10104000ECE70BA3D3E90023E8E70BA3D3E90023E4
+:10105000E4E70BA3D3E90023E0E700BFAFF3008090
+:10106000401DA12026812A0B78F6339F93CACD8D8F
+:101070009E6AC421818A46EE26417272DF25D7B767
+:10108000F017304A39059E562DE9F04F8DB002AF6A
+:1010900080460D4602F0FCF8044600285CD12B7E09
+:1010A000022B1BD1EB8A012B18D101F0D5FD06468E
+:1010B000FFF76EFE03464FF4C870DFF81C92B3FBD7
+:1010C000F0F206F5167602FB103316FA83F3C9F830
+:1010D0000030EB7E33B97B4B00221A702C37BD46B3
+:1010E000BDE8F08FAB8AE6B2013BB34204F10104E4
+:1010F0000CD907F108031E44E100009600230822E2
+:1011000001F0F801284602F0DBF9EBE707F11800DF
+:10111000FFF756FE324607F1180107F1080004F008
+:1011200077F80028D7D10F2E08D8664B1E70D9F853
+:101130000030A3F51673C9F80030CFE7FB1DF87136
+:101140000146009307220346284602F0B9F9F979CF
+:10115000404602F095F8C1E7EB8A282B26D010D83C
+:10116000012B1ED0052BB9D1BFF34F8F5649574BDA
+:10117000CA6802F4E0621343CB60BFF34F8F00BF35
+:10118000FDE7302BAAD16B7E514C0133627BDBB281
+:101190009342E94603D1EA7E237B9A420BD0CD46A7
+:1011A0009CE729464046FFF71BFE97E72946404645
+:1011B000FFF7CCFE92E74FF0000807F11803A7F8FD
+:1011C00018801022009341460123284602F078F946
+:1011D000AE8A023EB6B2F31C9B109B000733DB08BD
+:1011E000A9EBC3039D460DF1080A1FFA88F34FEAE5
+:1011F000C8019E4201F110010AD90AEB08030093CD
+:1012000008220023284602F05BF908F10108ECE708
+:1012100094F8D70000F0CCFAD4F8D810054619B9E4
+:1012200094F8D70000F0D4FAD4F8D83033449D4273
+:1012300005D294F8D7000021013000F0C9FA4FEA36
+:10124000960B4FF000081FFA88F18B45D4E9003265
+:1012500009D90AEB880103EB8800012200F038FB72
+:1012600008F10108EFE7F31842F10002C4E9003287
+:10127000D4F8D83094F8D70006EB0308C4F8D88027
+:1012800000F096FA804509D394F8D730D4F8D80006
+:101290000133401B84F8D730C4F8D800FF2E0D4D21
+:1012A00009D80023237300F0A5FA00F095FC2881EB
+:1012B00008B9FFF781FA23689B0A01332B810023C9
+:1012C000A3606CE7C922002000ED00E00400FA05ED
+:1012D000B0370020B8120020CC22002010B50A4BF5
+:1012E0000A4A1A6003F5805393F848203AB95C6CB7
+:1012F0002CB1204600F0EEFC204603F071FFBDE863
+:101300001040034800F0E6BC00230020E052000833
+:1013100030330020014B1870704700BFC41200200A
+:1013200010B54FF000540C4B22689A4211D10B4B70
+:10133000627D1A700A48237D03730A49C9220E3060
+:1013400000F0ACFAE0220021204600F0B9FA0120BA
+:1013500010BD0020FCE700BF9AAD44C5C4120020B8
+:10136000B03700201600002037B500F035FC194DCD
+:101370001949288102236B7100220123174801F0CB
+:101380006FF800230193164B164900931648174B2C
+:101390004FF4805201F04CFF154B197811B11248EF
+:1013A00001F06EFF01F058FC0446FFF7F1FC4FF42A
+:1013B000C873B0FBF3F202FB130304F5167010FAC6
+:1013C00083F00C4B186003F007FC08B10F232B814E
+:1013D00003B030BDB812002040420F0000230020AF
+:1013E00001100008C8120020D02200208910000837
+:1013F000C4120020CC2200202DE9F04F2DED028BED
+:1014000095A7D7E900670FF25829D9E900898C4CD4
+:1014100095B0DFF854A2DFF854B2204602F008F885
+:10142000034650B30025CDE911551095ADF84C5049
+:10143000027B8DF84C209968406811AA03C21B6892
+:1014400043F00043109301F009FC10EB0A0241F154
+:101450000003009510A9584600F0DAFDA842794A29
+:1014600005DD204601F0E8FF764A1570D5E71378D0
+:10147000072B00F2B980013313700DAD9FED6E8B19
+:101480000023DFF8E8B10C93ADF83C300D936B60AE
+:1014900000230DF125028DED008B4FF0010A09A903
+:1014A00058468DF825308DF824A001F03DFB9DF8BD
+:1014B00024200023002A40F09B80204601F0E8FE13
+:1014C0000546002847D1DFF8A8B101F0C5FBDBF8DD
+:1014D000003098423FD301F0BFFB0790FFF758FC64
+:1014E000079A4FF4C87302F51672B0FBF3F101FBD3
+:1014F000130312FA83F3CBF80030DFF878B19BF8CE
+:1015000000100791002914BF2B46534610A88DF8F0
+:101510003030FFF755FC0799C1F11002D2B2062A0C
+:1015200010AB28BF062219440DF13100079200F0DC
+:10153000B5F9079A0CAB0393182302930132424B7F
+:10154000D2B2CDE900A304923B463246204601F0D8
+:10155000E5FE8BF8005001F07FFB3C4A3C4D1368E0
+:10156000C31AB3F57A7F32D3106001F077FB0246DD
+:101570000B46204601F06AFF204601F089FE30B399
+:101580002B7BDFF8F4A0002B14BF032302238AF87F
+:10159000053001F061FB0DF1400B4FF47A7301222D
+:1015A000B0FBF3F05946CAF80000504600F0AAFA22
+:1015B00018230293274B019380B240F25513CDE9D3
+:1015C00003B0009342464B46204601F0A7FE2B7B1A
+:1015D0002BB1FFF76DFC2B7B002B7FF41AAF15B0FE
+:1015E000BDEC028BBDE8F08F204601F025FF44E7FB
+:1015F0004FF0904110A84A6982F040024A611946B2
+:10160000102200F05DF90DF126030AAA0CA9584634
+:1016100000F0F0FD95E8030011AB83E803009DF8AE
+:101620003C308DF84C300C9B109310A9DDE90A2357
+:10163000204602F0C9F82BE700000000000000007F
+:10164000D022002095380020C822002090380020A9
+:10165000B037002094380020401DA12026812A0B9D
+:10166000F1C6A7C1D068080F40420F000023002038
+:10167000CC220020C9220020B812002008B505485D
+:1016800000F05CFEBDE80840034A0449002003F076
+:10169000A1BD00BF00230020E8380020DD120008B3
+:1016A00070B5104B1B780133DBB2012B0C4612D8FE
+:1016B0000D4B1D6829684FF47A730E6AA2FB033242
+:1016C000014622462846B047844204D1074B0022F7
+:1016D0001A70012070BD4FF4FA7002F00BFF002069
+:1016E000F8E700BF181100201C110020DC38002092
+:1016F00007B50023024601210DF107008DF80730E0
+:10170000FFF7CEFF20B19DF8070003B05DF804FBA2
+:101710004FF0FF30F9E700000A4608B50421FFF753
+:10172000BFFF80F00100C0B2404208BD30B4074B9B
+:101730000A461978064B53F821402368DD69054BAA
+:101740000146AC46204630BC604700BFDC38002074
+:101750001C110020A086010070B503F073F8094E3B
+:10176000094D3080002428683388834208D903F06B
+:1017700065F82B6804440133B4F5D04F2B60F2D3E5
+:1017800070BD00BFDE3800209838002003F01EB97D
+:1017900000F1006000F5C040D0F80008704700007C
+:1017A00000F10060920000F5D04003F08FB8000017
+:1017B000054B1A68054B1B889B1A834202D91044BB
+:1017C00003F03CB80020704798380020DE38002035
+:1017D000024B1B68184403F049B800BF983800203A
+:1017E0000020704700F10050A0F51040D0F890059F
+:1017F00070470000064991F8243033B10023086A8D
+:1018000081F824300822FFF7CBBF0120704700BFCA
+:101810009C380020014B1868704700BF002004E08E
+:1018200030B50F4B0F4C1B682288C3F30B030138F4
+:10183000934208440BD164680A46013C8242134635
+:101840000BD214F9015F2DB102F8015BF6E781427A
+:101850000B4602D22C2203F8012B581A30BD00BFD0
+:10186000002004E020110020022802BF4FF0904326
+:1018700040229A6170470000022802BF4FF0904357
+:101880004FF480029A617047022801BF4FF09042E6
+:10189000536983F0400353617047000010B5002383
+:1018A000934203D0CC5CC4540133F9E710BD00006F
+:1018B00003460246D01A12F9011B0029FAD17047DB
+:1018C00002440346934202D003F8011BFAE7704733
+:1018D0002DE9F8431F4D144695F824200746884605
+:1018E00052BBDFF870909CB395F824302BB92022BE
+:1018F000FF2148462F62FFF7E3FF95F82400C0F16F
+:101900000802A24228BF2246D6B24146920005EB09
+:101910008000FFF7C3FF95F82430A41B1E44F6B2E5
+:10192000082E17449044E4B285F82460DBD1FFF719
+:1019300061FF0028D7D108E02B6A03EB82038342C2
+:10194000CFD0FFF757FF0028CBD10020BDE8F883A8
+:101950000120FBE79C380020024B1A78024B1A70DA
+:10196000704700BFDC3800201811002003494FF4F5
+:1019700061430B60024B186802F082BCC43800203F
+:101980001C110020094B10B51822044600211846EE
+:10199000FFF796FF064A074B127804600146BDE840
+:1019A000104053F8220002F06BBC00BFC438002086
+:1019B000DC3800201C1100202DE9F0470D460446BC
+:1019C00000219046284640F27912FFF779FF23461E
+:1019D00020220021284601F0AFFE231D02222021F3
+:1019E000284601F0A9FE631D03222221284601F0AA
+:1019F000A3FEA31D03222521284601F09DFE04F12C
+:101A0000080310222821284601F096FE04F1100355
+:101A100008223821284601F08FFE04F11103082224
+:101A20004021284601F088FE04F1120308224821D3
+:101A3000284601F081FE04F114032022502128469B
+:101A400001F07AFE04F1180340227021284601F0CB
+:101A500073FE04F120030822B021284601F06CFE39
+:101A600004F121030822B821284601F065FE04F1A3
+:101A70002207C0263B46314608222846083601F098
+:101A80005BFEB6F5A07F07F10107F3D104F1320345
+:101A900008223146284601F04FFE002704F1330AA0
+:101AA00094F832304FEAC7099F4209F5A47615D35E
+:101AB000B8F1000F08D1314604F599730722284682
+:101AC00001F03AFE09F24F16274694F832213B1BEB
+:101AD00093420CD3F01DC008BDE8F0870AEB070362
+:101AE00008223146284601F027FE0137D8E707F2E1
+:101AF000331331460822284601F01EFE083601370E
+:101B0000E3E7000013B504460846002101602346C0
+:101B1000C0F803102022019001F00EFE0198231D51
+:101B20000222202101F008FE0198631D03222221D8
+:101B300001F002FE0198A31D0322252101F0FCFD06
+:101B4000019804F108031022282101F0F5FD072077
+:101B500002B010BDF8B50E4605461446002181229C
+:101B60003046FFF7ADFE2B4608220021304601F03B
+:101B7000E3FD7CB96B1C07220821304601F0DCFD37
+:101B80000F2401236A785F1C013B934204D3E01DBC
+:101B9000C008F8BD0824F4E7EB19214608223046B6
+:101BA00001F0CAFD08343B46ECE7000030B5094DB2
+:101BB0000A4491420DD011F8013B5840082340F3EC
+:101BC0000004013B2C4013F0FF0384EA5000F6D1DF
+:101BD000EFE730BD2083B8ED73B5384A106851681F
+:101BE0006B4603C36A4636493648082303F020FB98
+:101BF000044670B9344A106851686B4603C36A469C
+:101C000032493048082303F013FB044630BB0A2056
+:101C100022E00369B3F5CC3FECD8418B40F2164289
+:101C20009142E7D12A4A024402F110018B42E1D3EA
+:101C3000103B244900209D1AFFF7B8FF2A460646AC
+:101C400004F118010020FFF7B1FFA3689E42D1D133
+:101C5000E3689842CED1002002B070BD0369B3F5AD
+:101C6000CC3F22D8B0F8661040F2164291421ED105
+:101C7000174A024402F15C018B421AD35C3B1149C2
+:101C800000209D1AFFF792FF2A46064604F16401E0
+:101C90000020FFF78BFFA268964203460BD1E06855
+:101CA000834214BF0D200020D6E70B20D4E70C2080
+:101CB000D2E71020D0E70D20CEE700BFB0520008D9
+:101CC000DC97010000680008B952000890970100F5
+:101CD0000898FFF710B5037C044613B9006803F0B9
+:101CE0008FFA204610BD00000023BFF35B8FC36056
+:101CF000BFF35B8FBFF35B8F8360BFF35B8F704776
+:101D0000BFF35B8F0068BFF35B8F704770B505460C
+:101D10000C30FFF7F5FF05F1080604463046FFF7E3
+:101D2000EFFFA04206D930466D68FFF7E9FF254472
+:101D3000281A70BD3046FFF7E3FF201AF9E70000CC
+:101D400070B50546406898B105F10800FFF7D8FF67
+:101D500005F10C0604463046FFF7D2FF84423046B8
+:101D600094BF6D680025FFF7CBFF013C2C44201A7F
+:101D700070BD000038B50C460546FFF7C7FFA0420E
+:101D800010D305F10800FFF7BBFF04446868B4FBFB
+:101D9000F0F100FB1144BFF35B8F0120AC60BFF397
+:101DA0005B8F38BD0020FCE72DE9F0411446074663
+:101DB0000D46FFF7C5FF844228BF0446D4B1B8469C
+:101DC00058F80C6B4046FFF79BFF304428604046B4
+:101DD0007E68FFF795FF331A9C4203D86C600120A0
+:101DE000BDE8F0816B60A41B3B68AB602044E860F9
+:101DF0000220F5E72046F3E738B50C460546FFF725
+:101E00009FFFA04210D305F10C00FFF779FF0444B7
+:101E10006868B4FBF0F100FB1144BFF35B8F012055
+:101E2000EC60BFF35B8F38BD0020FCE72DE9FF417C
+:101E3000884669460746FFF7B7FF6C4606B204EBD3
+:101E4000C6060025B44209D06268206808EB050187
+:101E5000FFF724FD636808341D44F3E7294638463C
+:101E6000FFF7CAFF284604B0BDE8F081F8B5054683
+:101E70000C300F46FFF744FF05F1080604463046D4
+:101E8000FFF73EFFA042304688BF6C68FFF738FF7F
+:101E9000201A386020B130462C68FFF731FF20440B
+:101EA000F8BD000073B5144606460D46FFF72EFF39
+:101EB000844228BF04460190DCB101A93046FFF7F7
+:101EC000D5FF019B33B93268C5E90233C5E9002467
+:101ED00001200CE09C4238BF0194286001986860A2
+:101EE0008442F5D93368AB60241AEC60022002B05A
+:101EF00070BD2046FBE700002DE9FF410F46694613
+:101F0000FFF7D0FF6C4600B204EBC0050026AC42E0
+:101F100009D0D4F8048054F8081BB8194246FFF7DA
+:101F2000BDFC4644F3E7304604B0BDE8F081000054
+:101F300038B50546FFF7E0FF044601462846FFF79F
+:101F400019FF204638BD0000302383F3118862B6A4
+:101F500070470000002383F3118862B670470000C9
+:101F6000012070477047000010B4134602681468DF
+:101F70000022A4465DF8044B6047000000F5805045
+:101F800090F859047047000000F5805090F8520412
+:101F90007047000000F5805090F958047047000029
+:101FA0005020704700F5805208B5FFF7CDFFD2F8FA
+:101FB0009834D2F894041844D2F890341844D2F8E3
+:101FC00078341844D2F888341844D2F88434184449
+:101FD000FFF7C0FF08BD000038B5C26A936923F05F
+:101FE00001039361044600F037FE0546E36A9B69EE
+:101FF000DB0706D500F030FE431BFA2BF6D9002094
+:1020000004E004F58054012084F8520438BD000037
+:102010002DE9F04F0C4600F5805185B01F4691F830
+:102020005234BDF83890054690469BB1D1F87434CF
+:102030000133C1F8743423689A0006D4237B082B3B
+:102040000BD9627B0AB10F2B07D9D1F87834013351
+:10205000C1F878344FF0FF300FE0FFF775FFEB6AFF
+:10206000D3F8C42012F4001A0AD0D1F87C3401331A
+:10207000C1F87C34FFF76EFF002005B0BDE8F08F9B
+:10208000D3F8C46022686B6AC6F301464FF0480B70
+:10209000002A1BFB063BB4BF42F080429204CBF8FF
+:1020A000002023685B0044BF42F00052CBF80020C0
+:1020B000227B330643EA0243CBF80430607B720193
+:1020C00018B343F44013CBF80430D1F8A4340133EF
+:1020D000C1F8A434AB1803F58353197B41F02001F8
+:1020E0001973207B039200F015FE039A03308010D1
+:1020F0005FFA8AF383420AF1010A0DDA04EB8301E5
+:102100000BEB830349689960F2E7AB1803F583533F
+:10211000197B60F34511E3E7EB6A0121B140C3F895
+:10212000CC10AB1803F58253C3E9048705EB4613C3
+:1021300003F582532146183304F10C0051F804CB07
+:1021400043F804CB8142F9D1098819802A4441F22D
+:1021500068032846D65002F5805209F0030392F82E
+:102160006C1043F0100321F01F010B4382F86C3018
+:10217000FFF7F0FE4246CDF800903B46214600F0C6
+:102180008FFD012079E7000013B500F5805401911F
+:10219000606CFFF7D5FD1F280AD90199606C2022D9
+:1021A000FFF744FEA0F120035842584102B010BD91
+:1021B0000020FBE708B500F58050FFF7C5FE406C36
+:1021C000FFF792FDBDE80840FFF7C4BE00220260A1
+:1021D000828142608260704710B500220023C0E90E
+:1021E00000230023044603810C30FFF7EFFF204655
+:1021F00010BD00002DE9F047074688B007F5805470
+:1022000068469A468846FFF79FFE9146FFF7E4FF2F
+:10221000606CFFF77BFD1F282CD9606C202269467B
+:10222000FFF786FE202825D194F8523413B303AD6E
+:10223000444605AB2E4603CE9E4220606160354683
+:1022400004F10804F6D130682060B388A380DDE98A
+:102250000023C9E90023BDF80830AAF80030FFF7D1
+:1022600079FE4A4653464146384608B0BDE8F04735
+:1022700000F004BDFFF76EFE002008B0BDE8F08757
+:102280002DE9F84F00230646C0E90133284B46F8F4
+:10229000303B00F5815405468846374610343846B1
+:1022A0002037FFF799FFA742F9D105F580544FF485
+:1022B000805326630026C4E90D366764012305F5C3
+:1022C000835705F5A359E66384F8403084F8483015
+:1022D000103709F110094FF0000A4FF0000B47E9E1
+:1022E00008ABA7F11800FFF771FF203747F8286CFB
+:1022F0004F45F4D184F85884A4F85A64A4F85C6477
+:10230000A4F85E6484F86064A4F86264A4F8646469
+:10231000A4F8666484F86864B8F1000F02D0054838
+:1023200000F094FC044BEB622846BDE8F88F00BF38
+:10233000E0520008C45200080064004010B5044B8D
+:10234000197804464A1C1A70FFF79AFF204610BD00
+:10235000E53800202DE9F04300295FD03048314BAB
+:10236000B3FBF1F381428CBF0A201120451EB3FB61
+:10237000F0F700FB1730ECB220B1022D2846F5D85B
+:10238000002037E07D1EB5F5806F33D2C4EBC40862
+:1023900008F103034FEAE30EC3F3C703A4EB030CF6
+:1023A0000EF101094FF47A705FFA8CF60EFB000E05
+:1023B00059FA8CFCBEFBFCFCBCF5617F1CDC1FFAEF
+:1023C0008CF4581C56FA80F047431648B0FBF7F7D8
+:1023D000B942D5D1013BDBB20F2BD1D8711EC9B2A6
+:1023E00007294FF0000005D81071148055805371F3
+:1023F00091710120BDE8F08308F1FF334FEAE30C4F
+:10240000C3F3C703E41A0CF1010EE6B20CFB0000A3
+:102410005EFA84F4B0FBF4F4A4B2D2E70846E9E72C
+:102420003F420F0000366E010B4B10B54FF4547253
+:10243000044600211846FFF743FA084BA3614033D6
+:10244000E361D8332362F0336362E36A60610022A0
+:10245000C3F8C02010BD00BF00A4004070A400401D
+:102460002DE9F04F00F58055994695F85834012B29
+:1024700089B004468A46904604D90027384609B0F8
+:10248000BDE8F08F904A52F8231009B942F82300B2
+:102490008E49C4F80CA00B7884F8109093B9FFF71C
+:1024A00053FD8B4B9A6D42F000729A659A6B42F025
+:1024B00000729A639A6B22F000729A6301230B7088
+:1024C000FFF748FD95F8513473B903211520FFF744
+:1024D0003BFD01F01FFD0321162001F01BFD012330
+:1024E00085F85134FFF736FDFFF72EFDE26A936958
+:1024F00023F01003936100F0AFFB0746E36A9E6987
+:1025000016F0080607D000F0A7FBC31BFA2BF5D97D
+:10251000FFF720FDB1E79A6942F001029A6100F0ED
+:102520009BFB0746E36A9A69D00705D400F094FB49
+:10253000C31BFA2BF6D9EBE79A6942F002029A61C3
+:10254000E36A00275F65FFF705FD686CFFF7CCFBCA
+:1025500004F5825B0BF1100B202200216846FFF787
+:10256000AFF902A8FFF732FE06976A460BEB0603A7
+:102570000DF1180E9446BCE80300F445186059604C
+:10258000624603F10803F5D1DCF80000186020363C
+:102590009CF804201A71B6F5806FDDD1002304F594
+:1025A000A25285F8503485F853341A3251462046E9
+:1025B000FFF7D0FE074690B9E26A936923F0010362
+:1025C000936100F049FB0546E36A9B69D9077FF5F3
+:1025D00054AF00F041FB431BFA2BF5D94DE795F8BA
+:1025E0005F6495F85E24C5F86CA4360246EA42663C
+:1025F00095F86024E36A1643B5F85C2446EA02467F
+:10260000DE61B8F1000F29D004F5A3520232414631
+:102610002046FFF79FFE90B9E26A936923F0010319
+:10262000936100F019FB0546E36A9B69DA077FF5C1
+:1026300024AF00F011FB431BFA2BF5D91DE795F8E9
+:10264000683495F86714C5F870841B0143EA0123C8
+:10265000B5F86414E26A43EA0143D3602046FFF709
+:10266000E3FE002385F85934E36A6FF040421A65AF
+:10267000E36A184A5A65E36A44229A65E36A0722C4
+:10268000C3F8DC20E36A0322DA65E26A9369B9F1F0
+:10269000030F43F4407393613FF4F0AEE26A936931
+:1026A00023F00103936100F0D7FA0646E36A9B69C1
+:1026B000DB0705D500F0D0FA831BFA2BF6D9DCE650
+:1026C000012385F85234D9E6E0380020E4380020B0
+:1026D000001002409B0008002DE9F04F054689B02C
+:1026E00090469946002741F2680A00F58056EB6A49
+:1026F000D3F8D430FB40D8074AD505EB47125244F3
+:102700004FEA471B1379190742D4D6F880340133B6
+:10271000C6F8803413799A0648BFD6F8A83405EB7A
+:102720000B0248BF0133524448BFC6F8A83413799E
+:1027300043F008031371DB0722D596F85334FBB13D
+:1027400005F58254183468465C44FFF745FD03AB39
+:1027500004F1080C206861681A4603C20834644515
+:102760001346F7D120681060A2889A800123ADF843
+:1027700008302B68CDE90089DB6B6946284698470D
+:10278000D6F8543423B1D6F89C340133C6F89C34BF
+:102790000137202FABD109B0BDE8F08F2DE9F04F04
+:1027A0008DB004460F4600F059FA82468946002F44
+:1027B00056D1E36AD3F89020920141BF04F58051CD
+:1027C000D1F894240132C1F89424D3F8902016074C
+:1027D00003D100200DB0BDE8F08FD3F89050E6692A
+:1027E000C5F30125482303FB0566E8464046FFF78D
+:1027F000EDFC326851004ABF22F06043C2F38A43C5
+:1028000043F00043920048BF43F080430093736855
+:1028100013F400131FBF04F5805201238DF80D300F
+:10282000D2F8AC340EBF8DF80D300133C2F8AC34A1
+:10283000F38803F00F038DF80C304FF0000B9DF878
+:102840000C0000F067FA5FFA8BF3984220D9F21877
+:102850000CA90B44127A03F82C2C0BF1010BEEE7B8
+:10286000012FB6D1E36AD3F89820950141BF04F552
+:102870008051D1F894240132C1F89424D3F89820DF
+:102880001007A6D0D3F89850266AC5F30125A9E70A
+:10289000EFB9E36AC3F8945004A8FFF79DFC98E8E9
+:1028A0000F0007AD07C52B800023ADF81830236853
+:1028B0002046CDE904A9DB6B04A9984704F58054B0
+:1028C00058B1D4F88C340133C4F88C3482E7012F2A
+:1028D00004BFE36AC3F89C50DEE7D4F890340133B8
+:1028E000C4F89034012075E7F8B505460F4600F5A9
+:1028F0008054012639462846FFF750FF10B184F86E
+:102900005364F7E7D4F8543423B1D4F89C3401333A
+:10291000C4F89C34F8BD0000F0B5C36A1A6C12F418
+:102920007F0F2BD000F580541B6CC4F8A03441F20B
+:102930006805002347194FF0010C00EB43122A44AD
+:102940005E01117911F0020F15D0490713D4B9595E
+:10295000C66AD6F8C8E00CFA01F111EA0E0F0AD0E7
+:10296000C6F8D010117941F004011171D4F888240F
+:102970000132C4F888240133202BDED1F0BD0000E1
+:1029800010B5254C254B226802B338B31A6D1206D8
+:102990000ED580221A6500F061F950EA01020B465B
+:1029A00002D0013861F1000302462068FFF794FE6F
+:1029B0001A4A136D1B032AD523684FF4002103F52F
+:1029C00080531165012283F8592420E001221A6501
+:1029D00008221A654FF480621A6510BD196DC80788
+:1029E00002D4196D890705D5032119651046002108
+:1029F000FFF77AFF094B1A6D100702D41A6DD10642
+:102A000005D518221A6520680121FFF76DFF20689F
+:102A1000BDE81040FFF780BFE038002000640040B0
+:102A200008B5FFF791FAFFF777FFBDE80840FFF719
+:102A300091BA0000C36AD3F8C40080F40010C0F358
+:102A40004050704700F5805008B5FFF77DFA406CA4
+:102A5000FFF75CF9FFF77EFA43090CBF0120002065
+:102A600008BD000000F5805393F8592462B1C16A93
+:102A70008A6922F001028A61D3F898240132C3F8EE
+:102A80009824002283F85924704700002DE9F74369
+:102A900000F5825198461031FFF756FA002541F2B1
+:102AA000680E4FF0010900F5805C00EB451474449A
+:102AB00023795E071CD4DB061AD5C36A8E69D3F866
+:102AC000C87009FA06F63E4212D04F6801970F68A7
+:102AD0009742019F77EB08070AD2C3F8D0602379A9
+:102AE00043F004032371DCF884340133CCF88434DC
+:102AF0000135202D01F12001D7D103B0BDE8F0430D
+:102B0000FFF728BAF8B51E46002313700F46054696
+:102B10001446FFF797FF80F0010038701EB1284679
+:102B2000FFF788FF2070F8BD2DE9F04F85B099467A
+:102B3000DDE90EA30D4602931378019391F800B0DE
+:102B40008046164600F08AF82B7804460F4613B9E3
+:102B50003378002B42D022463B464046FFF796FF93
+:102B6000FFF75EFFFFF77EFF4B4632462946FFF731
+:102B7000C9FF2B7833B1BBF1000F03D0012005B0A2
+:102B8000BDE8F08F337813B1019B002BF6D108F527
+:102B900080530393029B544577EB03031ED2039BA0
+:102BA000D3F85404D0B10368AAEB0401DB6889B2FE
+:102BB00098474B46324629464046FFF7A3FF2B78FD
+:102BC00013B1BBF1000FD9D1337813B1019B002BA6
+:102BD000D4D100F043F804460F46DBE70020CEE7EF
+:102BE00008B50020FFF7CCFEBDE8084001F048B86A
+:102BF00008B50120FFF7C4FEBDE8084001F040B869
+:102C000000B59BB0EFF3098168226846FEF746FEE7
+:102C1000EFF30583014B9B6BFEE700BF00ED00E087
+:102C200008B5FFF7EDFF000000B59BB0EFF3098199
+:102C300068226846FEF732FEEFF30583014B5B6BBB
+:102C4000FEE700BF00ED00E0FEE700000FB408B5AE
+:102C5000029801F0E5FBFEE701F006BF01F0DEBEE1
+:102C600001F0DCBE13B56C4684E80600031D94E851
+:102C7000030083E80500012002B010BD73B585682C
+:102C8000019155B11B885B0707D4D0E900369B6BD7
+:102C90009847019AC1B23046A847012002B070BDE2
+:102CA000F0B5866889B005460C465EB1BDF838308F
+:102CB0005B070AD4D0E900379B6B98472246C1B224
+:102CC0003846B047012009B0F0BD00220023CDE90D
+:102CD00000230023ADF808300A4603AB01F10806D3
+:102CE000106851681C4603C40832B2422346F7D12B
+:102CF000106820609288A280FFF7B2FF0423ADF82D
+:102D000008302B68CDE90001DB6B694628469847FF
+:102D1000D8E70000082817D909280CD00A280CD0B9
+:102D20000B280CD00C280CD00D280CD00E2814BF6A
+:102D30004020302070470C2070471020704714202E
+:102D40007047182070472020704700002DE9F0419F
+:102D5000456A15B94162BDE8F0814B6823F06047D0
+:102D6000C3F38A464FEAD37EC3F3807816EA23067C
+:102D700038BF3E46AC462B465A68BEEBD27F22F0A7
+:102D800060440AD0002A18DAA40CB44217D19D423C
+:102D90000FD10D60DEE71346EEE7A74207D102F040
+:102DA0008044C2F3807242450BD054B1EFE708D2A1
+:102DB000EDE7CCF800100B60CDE7B44201D0B4428F
+:102DC000E5D81A689C46002AE5D11960C3E70000DF
+:102DD0002DE9F047089D01F007044FEAD508224489
+:102DE00005F0070500EBD1004FF47F49944201D173
+:102DF000BDE8F08704F0070705F0070A57453E468F
+:102E000038BF5646C6F10806111B8E4228BF0E4633
+:102E1000E10808EBD50E415C13F80EC0B94029FA61
+:102E200006F721FA0AF1FFB28CEA010147FA0AF724
+:102E300039408CEA010C03F80EC034443544D5E720
+:102E400080EA0120082341F2210201B2400000295A
+:102E500080B203F1FF33B8BF504013F0FF03F4D149
+:102E60007047000038B50C468D18A54200D138BD1A
+:102E700014F8011BFFF7E4FFF7E7000042684AB1CE
+:102E8000136843604389818901339BB2994243812E
+:102E900038BF83811046704770B588B02022044641
+:102EA0000D4668460021FEF70BFD20460495FFF70E
+:102EB000E5FF024658B16B46054608AE1C4603CCFA
+:102EC000B44228606960234605F10805F6D1104632
+:102ED00008B070BD082817D909280CD00A280CD0D2
+:102EE0000B280CD00C280CD00D280CD00E2814BFA9
+:102EF0004020302070470C2070471020704714206D
+:102F0000704718207047202070470000082817D904
+:102F10000C280CD910280CD914280CD918280CD935
+:102F200020280CD930288CBF0F200E207047092094
+:102F300070470A2070470B2070470C2070470D2007
+:102F4000704700002DE9F843078C072F04461ED96F
+:102F5000D0E9029800254FF6FF73C5F12006A5F1D0
+:102F6000200029FA05F108FA06F628FA00F03143A4
+:102F70000143C9B21846FFF763FF0835402D0346E9
+:102F8000EBD1E1693A46BDE8F843FFF76BBF4FF676
+:102F9000FF70BDE8F883000010B54B6823B9CA8AFA
+:102FA00063F30902CA8210BD04691A681C600361D8
+:102FB000C38A013BC3824A60EFE700002DE9F84F66
+:102FC0001D46CB8A0F46C3F3090105298146924667
+:102FD0000B4630D00020AAB207F11A049EB2042E8C
+:102FE0001FFA80F80FD8904503F1010306D3FB8A3E
+:102FF0000A4462F30903FB8201201AE01AF8006018
+:10300000E6540130EAE79045F1D2A1F1050B1C230B
+:103010007C68BBFBF3F203FB12BB1FFA8BF6002CA0
+:1030200045D14846FFF72AFF044638B978606FF06B
+:103030000200BDE8F88F4FF00008E6E700260660C2
+:103040007860ADB24FF0000B454510D90AEB08038C
+:10305000221D13F8011B9155B1B208F101081B297B
+:103060001FFA88F82BD0454506F10106F1D8FB8AF6
+:10307000C3F30902154465F30903BCE7013292B2B8
+:103080001C462368002BF9D16B1F0B441C21B3FB9A
+:10309000F1F301339BB29A42D3D2BBF1000FD0D1EE
+:1030A0004846FFF7EBFE20B9C4F800B0BFE70122A5
+:1030B000E7E7C0F800B05E4620600446C1E745453A
+:1030C000D5D94846FFF7DAFE08B92060AFE7C0F867
+:1030D00000B0002620600446B6E700002DE9F04F5E
+:1030E0002DED028B1C4683B05B6901920746884632
+:1030F000002B00F09A80238C2BB1E269002A00F0AB
+:103100009480072B35D807F10C00FFF7B7FE054672
+:1031100038B96FF00205284603B0BDEC028BBDE85C
+:10312000F08F14220021FEF7CBFB228CE16905F120
+:103130000800FEF7B3FB208C013080B2FFF7E6FEFB
+:10314000FFF7C8FE013880B220840130287463691B
+:10315000228C1B782A4403F01F0363F03F0348F0DE
+:1031600000411372384669602946FFF7EFFD0125DB
+:10317000D1E700F10C034FF0000908EE103A4FF0D0
+:10318000800A4E464D4618EE100AFFF777FE83463A
+:103190000028BED014220021FEF792FB002E3AD167
+:1031A000019BABF8083002220BF1080E1FFA82FCDB
+:1031B0000CF10100BCF1060F218C80B201D88E42C7
+:1031C0002BD3FFF7A3FEFFF785FE62691278013863
+:1031D00002F01F028E4208BF4FF0400A42EA491235
+:1031E0001BFA80F14AEA020A013048F0004281F8F5
+:1031F00008A08BF81000CBF8042059463846FFF79A
+:10320000A5FD238C0135B3422DB289F001094FF0A1
+:10321000000AB8D17FE70022C6E7E169895D0EF8B0
+:1032200002100136B6B20132C0E76FF0010572E755
+:10323000F8B515460E463022002104461F46FEF71B
+:103240003FFB069B6360B5F5001F079BA76034BF7B
+:103250006A094FF6FF72A36297B2E66104F11000AB
+:1032600000239A4206D800230360A782E3822383C7
+:10327000E360F8BD0660013330462036F1E7000018
+:1032800003781BB94BB2002BC8BF01707047000018
+:1032900000787047F8B50C46C969074611B9238C08
+:1032A000002B37D1257E1F2D34D8387828BB228CAF
+:1032B000072A2CD8268A36F003032BD14FF6FF704D
+:1032C000FFF7D0FD20F001003102400441EA056122
+:1032D000400C41EA40254FF6FF7223462946384606
+:1032E000FFF7FCFE002807DD626913780133DBB2CB
+:1032F0001F2B88BF00231370F8BD218A2D0645EAD5
+:10330000012505432046FFF71DFE0246E5E76FF065
+:103310000300F1E76FF00100EEE7000070B58AB03E
+:10332000044616460021282268461D46FEF7C8FAC4
+:10333000BDF83830ADF810300F9B05939DF8403044
+:103340008DF81830119B07936946BDF84830ADF8E9
+:1033500020302046CDE90265FFF79CFF0AB070BD22
+:103360002DE9F041D36905460C4616460BB9138C7E
+:103370005BBB377E1F2F28D895F80080B8F1000F6F
+:1033800026D03046FFF7DEFD3378210241EAC33113
+:1033900041EA0801338A41EA076141EA03410246F2
+:1033A000334641F080012846FFF798FE00280ADDE9
+:1033B0003378012B07D1726913780133DBB21F2BED
+:1033C00088BF00231370BDE8F0816FF00100FAE7B9
+:1033D0006FF00300F7E70000F0B58BB004460D4630
+:1033E00017460021282268461E46FEF769FA9DF816
+:1033F0004C305A1E534253418DF800309DF84030F6
+:10340000ADF81030119B05939DF848308DF81830B9
+:10341000149B07936A46BDF85430ADF82030294616
+:103420002046CDE90276FFF79BFF0BB0F0BD000010
+:10343000406A00B104307047436A1A684262026908
+:103440001A600361C38A013BC38270472DE9F041D2
+:10345000D0F82080194E14461D464146002709B970
+:10346000BDE8F081D1E90223A21A65EB030396427D
+:1034700077EB03031ED2036A8B420DD1FFF78CFD5D
+:10348000036A1B68036203690B60C38A0161016AF6
+:10349000013BC3828846E2E7FFF77EFD0B68C8F870
+:1034A000003003690B60C38A0161013BC382D8F815
+:1034B0000010D4E788460968D1E700BF80841E0069
+:1034C0002DE9F04F8BB00D46DDF8509014469B4629
+:1034D0008046002800F01981B9F1000F00F0158135
+:1034E000531E3F2B00F21181012A03D1BBF1000FC3
+:1034F00040F00B810023CDE90833B8F81430B5EB68
+:10350000C30F4FEAC30703D300200BB0BDE8F08F11
+:103510002B199F42D8F80C303ABF7F1BFFB22746C9
+:103520001BB9D8F81030002B7AD0272D4ED8C5F112
+:103530002806B7424FF000032CBFF6B23E46009378
+:103540002946D8F8080008AB3246FFF741FCA7EB44
+:10355000060A35445FFA8AFAB8F8143003F10053CA
+:10356000053BDB000493D8F80C3003932821039B20
+:1035700013B1BAF1000F2CD1D8F8100040B1BAF154
+:10358000000F05D0009608AB5246691AFFF720FCE1
+:1035900038B2002FB8D066070AD00AAB03EBD401CB
+:1035A000624211F8083C02F00702134101F8083C9E
+:1035B000082C3CD9102C40F2B580202C40F2B7806A
+:1035C000BBF1000F00F09C80082334E0BA460026CF
+:1035D000C2E7049BE02B28BFE02306930B44AB42D9
+:1035E000059314D95A1B03980096924534BF52464E
+:1035F000D2B2691A08AB04300792FFF7E9FB079AC9
+:103600001644AAEB020A1544F6B25FFA8AFA049B42
+:10361000069A05999B1A0493039B1B680393A6E7DC
+:103620000093D8F8080008AB3A462946AEE7BBF14C
+:10363000000F13D00123B4EBC30F6CD0082C12D8A9
+:103640009DF82030621E23FA02F2D50706D54FF00E
+:10365000FF3202FA04F423438DF820309DF8203025
+:1036600089F8003051E7102C12D8BDF82030621EC6
+:1036700023FA02F2D10706D54FF0FF3202FA04F422
+:103680002343ADF82030BDF82030A9F800303CE7E6
+:10369000202C0FD80899631E21FA03F3DA0705D509
+:1036A0004FF0FF3202FA04F40C430894089BC9F867
+:1036B00000302AE7402C2BD0DDE90865611EC4F1FB
+:1036C0002102A4F1210326FA01F105FA02F225FAFA
+:1036D00003F311431943CB0712D50122A4F12003B0
+:1036E000C4F1200102FA03F322FA01F1A24052428E
+:1036F00043EA010363EB430332432B43CDE9082341
+:10370000DDE90823C9E90023FFE66FF00100FCE6CC
+:103710006FF00800F9E6082CA0D9102CB3D9202CA2
+:10372000EED8C3E7BBF1000FADD0022383E7BBF1B6
+:10373000000FBBD004237EE730B5012A144638BF02
+:103740000124402C85B028BF40240025012ACDE962
+:10375000025518D81B788DF8083063070AD004ABDF
+:1037600003EBD405624215F8083C02F007029340CF
+:1037700005F8083C009103462246002102A8FFF705
+:1037800027FB05B030BD082AE4D9102A03D81B88CE
+:10379000ADF80830E1E7202A8DBFD3E900231B688C
+:1037A0000293CDE90223D8E710B5CB681BB98B6033
+:1037B0000B618B8210BD04691A681C600361C38AA7
+:1037C000013BC382CA60F0E72DE9F04F93B0CDE929
+:1037D00003230B6804460D461806C3F3C01147BF08
+:1037E000C3F3C03BC3F306264FF0020B0E46002B7B
+:1037F00080F2FF8113F0C04940F0FB812A7B002A50
+:1038000000F0F781BBF1020F03D02078B04240F006
+:10381000F381C3F30460079003F07F00059059B370
+:10382000C3F3074A2A44059B92F80380760646EACA
+:103830000B4646EA834600220023CDE908235FEACF
+:10384000D81346EA0A0602936AD0059B009367687C
+:103850005B46524608A92046B847002800F0CF81B1
+:10386000276A87B9314604F10C00FFF715FB0746BC
+:10387000C8B96FF0020057E0C3F30F2A590608BF1A
+:103880000AF0030ACEE73B699E420DD03F68002F45
+:10389000F9D1314604F10C00FFF7FEFA0746002883
+:1038A000E7D0236A3B602762FE7D08F01F03C6F362
+:1038B0008406F01A1FFA80FC0028B8BF0CF1200023
+:1038C000D7E902210693A3EB06031FFA83FCB8BFD6
+:1038D00000B2002BBCBF0CF120031BB252EA010660
+:1038E00036D0039EDFF8D4C2B21A049E66EB010103
+:1038F0000026944576EB010C2AD395F80DE097F855
+:103900001AC0E64518D1029E002E79D001281FDC8E
+:103910007868E8B9A84E964270EB010216D337E0FA
+:10392000276A27B96FF00C0013B0BDE8F08F3B6930
+:103930009E42B9D03F68F4E79F48904276EB01027F
+:1039400001D30020F0E7029A002AFAD00F2B18DCEE
+:10395000FA7D4FEA880302F0030203F07C0313436D
+:10396000FB7539462046FFF717FB6B7BBB76029B46
+:103970003BB9FB7DC3F38402013262F38603FB751E
+:10398000D0E76A7BBB7E9A42DBD1029B002B37D00B
+:103990004FEA9813022B33D0039BBB60049BFB6060
+:1039A000142200210DA8FDF78BFF039B0A93049BB3
+:1039B0000B932B1D0C932B7BADF83EA0013BDBB290
+:1039C000ADF83C30069B8DF84130079B8DF84230B6
+:1039D000059B8DF8433094F82C308DF840B083F07F
+:1039E00001038DF844300AA9A36820469847FB7D5F
+:1039F000C3F38403013303F01F039B02FB82A0E7A0
+:103A0000FB7DC8F34012B2EBD31F40F0FB80069A57
+:103A1000C3F38403934240F0F88002992B7B4FEA72
+:103A2000981200294DD0D2075DD4032B40F2F080CC
+:103A3000039BBB60049BFB602B7BAE1D033BDBB297
+:103A40003246394604F10C00FFF7B8FA00280CDAC8
+:103A500039462046FFF7A0FAFB7DC3F38403013308
+:103A600003F01F039B02FB8203E7DDE90884AB88B8
+:103A70003B834FF6FF73C9F12000A9F1200228FA19
+:103A800009F104FA00F0014324FA02F21143184646
+:103A9000C9B2FFF7D5F909F10809B9F1400F03469A
+:103AA000E9D1B8822A7B033AD2B23146FFF7DAF97C
+:103AB000FB7DB882DA43C2F3C01262F3C713FB7511
+:103AC0003FE782B92E1D013BDBB23246394604F195
+:103AD0000C00FFF773FA0028BADB2A7BB88A013A98
+:103AE000D2B23146E2E7F98AC1F30901013B042968
+:103AF000DAB25CD8281D002307F11B069A4208D9C8
+:103B000010F801CB06F801C0013101330529DBB201
+:103B1000F4D103990A9104990B91934207F11B0187
+:103B20000C9138BF043379680D9134BF55FA83F393
+:103B300000230E93FB8AADF83EA0C3F309031A4499
+:103B4000069B8DF84130079B8DF84230059B8DF820
+:103B5000433094F82C30ADF83C2083F001038DF80D
+:103B6000443000238DF840B07B602A7BB88A013A4C
+:103B7000291DFFF777F93B8BB882834203D1A368F5
+:103B80000AA92046984720460AA9FFF70DFEFB7DAB
+:103B9000BA8AC3F38403013303F01F039B02FB8241
+:103BA0003B8B9A420CBF00206FF01000BCE67B6894
+:103BB000002BAED0052005E040420F0080841E009F
+:103BC0001C3033461E68002EFAD1091A081D2E1D1E
+:103BD000184401EB090CBCF11B0F5FFA89F398D86C
+:103BE0009A4296D916F8013B00F8013B09F1010908
+:103BF000EFE76FF0090097E66FF00A0094E66FF0C8
+:103C00000B0091E66FF00D008EE66FF00E008BE674
+:103C10006FF00F0088E600BFEFF3098305494A6B98
+:103C200022F001024A63683383F30988002383F397
+:103C30001188704700EF00E0302080F3118862B6F1
+:103C40000C4B0D4AD96821F4E0610904090C0A43C0
+:103C5000DA60D3F8FC20094942F08072C3F8FC20F6
+:103C60000A6842F001020A602022DA7783F8220013
+:103C7000704700BF00ED00E00003FA05001000E00F
+:103C800010B5302383F311880E4B5B6813F4006387
+:103C900014D0F1EE103AEFF30984683C4FF08073D2
+:103CA000E361094BDB6B236684F3098800F076FB44
+:103CB00010B1064BA36110BD054BFBE783F31188E0
+:103CC000F9E700BF00ED00E000EF00E04306000868
+:103CD00046060008026843681143016003B11847B3
+:103CE00070470000024A136843F0C0031360704736
+:103CF0000038014013B50D4C204600F0B5FA04F130
+:103D000014000B4900940023202200F073F9094BA2
+:103D100009490094202204F1380000F0EDF9074A27
+:103D2000074BC4E9172302B010BD00BFEC380020D8
+:103D300058390020E53C000878390020003801405F
+:103D4000007A030A30B5037C234C002918BF0C46C7
+:103D5000012B0FD1214B98420CD1214B1A6E42F40A
+:103D600080421A66D3F8802042F48042C3F8802053
+:103D7000D3F880302268036EC16D846603EB520372
+:103D8000B3FBF2F36268150442BF23F0070503F0AA
+:103D9000070343EA4503CB60A36843F040034B604D
+:103DA000E36843F001038B6042F4967343F0010330
+:103DB0000B604FF0FF330B62510505D512F0102256
+:103DC00005D0B2F1805F04D080F8643030BD7F232D
+:103DD000FAE73F23F8E700BF20530008EC38002043
+:103DE000001002402DE9F047C66D3768F46934626F
+:103DF0002107054619D014F0080118BF4FF480714F
+:103E0000E20748BF41F02001A30748BF41F040014D
+:103E1000600748BF41F08001302383F31188281DDB
+:103E2000FFF758FF002383F31188E2050AD53023FA
+:103E300083F311884FF48061281DFFF74BFF0023A7
+:103E400083F311884FF030094FF0000A14F0200876
+:103E500038D13B0616D54FF0300905F1380A200657
+:103E600010D589F31188504600F07AF9002836DA27
+:103E70000821281DFFF72EFF27F080033360002361
+:103E800083F31188790614D5620612D5302383F3A3
+:103E90001188D5E913239A4208D12B6C33B1102134
+:103EA000281D27F04007FFF715FF3760002383F335
+:103EB0001188E30618D5AA6E1369ABB1BDE8F047C7
+:103EC0005069184789F31188736A95F86410284679
+:103ED000194000F0E3F98AF31188F469B6E7B0629B
+:103EE00088F31188F469BAE7BDE8F0874FF0E02362
+:103EF000002258684FF0FF31930003F1604303F54F
+:103F0000614301329042C3F88010C3F88011F3D2AC
+:103F10007047000000F1604303F561430901C9B235
+:103F200083F80013012200F01F039A4043099B000D
+:103F300003F1604303F56143C3F880211A607047C1
+:103F4000F8B5154682680669AA420B46816938BFF2
+:103F50008568761AB54204460BD218462A46FDF704
+:103F60009DFCA3692B44A361A3685B1BA360284647
+:103F7000F8BD0CD918463246FDF790FCAF1BE1683E
+:103F80003A463044FDF78AFCE3683B44EBE71846C9
+:103F90002A46FDF783FCE368E5E700008368934267
+:103FA000F7B51546044638BF8568D0E90460361A6F
+:103FB000B5420BD22A46FDF771FC63692B4463615D
+:103FC000A36828465B1BA36003B0F0BD0DD9324641
+:103FD0000191FDF763FC0199E068AF1B3A4631445B
+:103FE000FDF75CFCE3683B44E9E72A46FDF756FC35
+:103FF000E368E4E710B50A440024C361029B8460CF
+:10400000C0E90000C0E90511C1600261036210BD92
+:1040100008B5D0E90532934201D1826882B982683D
+:10402000013282605A1C42611970D0E904329A420E
+:1040300024BFC3684361002100F078FA002008BD66
+:104040004FF0FF30FBE7000070B5302304460E460A
+:1040500083F31188A568A5B1A368A269013BA36099
+:10406000531CA36115782269934224BFE368A361BE
+:10407000E3690BB120469847002383F31188284653
+:1040800007E03146204600F041FA0028E2DA85F3E5
+:10409000118870BD2DE9F74F04460E461746984625
+:1040A000D0F81C904FF0300A8AF311884FF0000BC3
+:1040B000154665B12A4631462046FFF741FF0346C3
+:1040C00060B94146204600F021FA0028F1D00023D3
+:1040D00083F31188781B03B0BDE8F08FB9F1000FAE
+:1040E00003D001902046C847019B8BF31188ED1A3D
+:1040F0001E448AF31188DCE7C0E90511C160C36181
+:104100001144009B8260C0E90000016103627047B6
+:10411000F8B504460D461646302383F31188A76888
+:10412000A7B1A368013BA36063695A1C62611D705B
+:10413000D4E904329A4224BFE3686361E3690BB1B6
+:1041400020469847002080F3118807E0314620463A
+:1041500000F0DCF90028E2DA87F31188F8BD0000EE
+:10416000D0E905239A4210B501D182687AB98268F4
+:10417000013282605A1C82611C7803699A4224BF12
+:10418000C3688361002100F0D1F9204610BD4FF0D3
+:10419000FF30FBE72DE9F74F04460E4617469846D9
+:1041A000D0F81C904FF0300A8AF311884FF0000BC2
+:1041B000154665B12A4631462046FFF7EFFE034615
+:1041C00060B94146204600F0A1F90028F1D0002353
+:1041D00083F31188781B03B0BDE8F08FB9F1000FAD
+:1041E00003D001902046C847019B8BF31188ED1A3C
+:1041F0001E448AF31188DCE70268436811430160BA
+:1042000003B11847704700001430FFF743BF0000A8
+:104210004FF0FF331430FFF73DBF00003830FFF799
+:10422000B9BF00004FF0FF333830FFF7B3BF0000D5
+:104230001430FFF709BF00004FF0FF311430FFF7D3
+:1042400003BF00003830FFF763BF00004FF0FF32BC
+:104250003830FFF75DBF0000012914BF6FF0130075
+:1042600000207047FFF746BD044B03600023C0E900
+:104270000233436001230374704700BF38530008C2
+:1042800010B53023044683F31188FFF75BFD02234A
+:104290002374002080F3118810BD000038B5C36975
+:1042A00004460D461BB904210844FFF7A5FF294623
+:1042B00004F11400FFF7ACFE002806DA201D4FF4CD
+:1042C0000061BDE83840FFF797BF38BD0023037594
+:1042D000826803691B6899689142FBD25A6803603F
+:1042E000426010605860704700230375826803695C
+:1042F0001B6899689142FBD85A680360426010605D
+:104300005860704708B50846302383F311880B7D49
+:10431000032B05D0042B0DD02BB983F3118808BDD6
+:104320008B6900221A604FF0FF338361FFF7CEFFE5
+:104330000023F2E7D1E9003213605A60F3E700008E
+:10434000FFF7C4BF054BD9680875186802681A6082
+:10435000536001220275D860FCF75EB998390020DD
+:1043600030B50C4BDD684B1C87B004460FD02B4694
+:10437000094A684600F06CF92046FFF7E3FF009B0E
+:1043800013B1684600F06EF9A86907B030BDFFF7B9
+:10439000D9FFF9E79839002005430008044B1A6853
+:1043A000DB6890689B68984294BF002001207047AA
+:1043B00098390020084B10B51C68D86822681A602C
+:1043C000536001222275DC60FFF78EFF0146204614
+:1043D000BDE81040FCF720B998390020044B1A685A
+:1043E000DB6892689B689A4201D9FFF7E3BF704788
+:1043F0009839002038B5074C0749084801230025A3
+:104400002370656000F02EFC0223237085F3118871
+:1044100038BD00BFC03B002064530008983900201D
+:1044200008B572B6044B186500F0E4FA00F09CFB86
+:10443000024B03221A70FEE798390020C03B00208F
+:1044400000F046B9EFF3118020B9EFF30583302275
+:1044500082F311887047000010B530B9EFF305847E
+:10446000C4F3080414B180F3118810BDFFF7B6FF40
+:1044700084F31188F9E700008B60022308618B82C6
+:10448000084670478368A3F1840243F8142C02693C
+:1044900043F8442C426943F8402C094A43F8242C41
+:1044A000C26843F8182C022203F80C2C002203F8EF
+:1044B0000B2C044A43F8102CA3F12000704700BFD6
+:1044C000310600089839002008B5FFF7DBFFBDE88A
+:1044D0000840FFF735BF0000024BDB6898610F20F2
+:1044E000FFF730BF98390020302383F31188FFF79E
+:1044F000F3BF000008B50146302383F3118808207C
+:10450000FFF72EFF002383F3118808BD064BDB68FD
+:1045100039B1426818605A60136043600420FFF7A5
+:104520001FBF4FF0FF307047983900200368984252
+:1045300006D01A680260506099611846FFF700BF04
+:104540007047000010B503689C68A2420CD85C68F4
+:104550008A600B604C602160596099688A1A9A6081
+:104560004FF0FF33836010BD1B68121BECE70000A7
+:104570000A2938BF0A2170B504460D460A2660197B
+:1045800000F06AFB00F056FB041BA54203D8751C23
+:104590002E460446F3E70A2E04D9BDE870400120F8
+:1045A00000F0A0BB70BD0000F8B5144B0D46D961FA
+:1045B00003F1100141600A2A1969826038BF0A229A
+:1045C000016048601861A818144600F037FB0A27FC
+:1045D00000F030FB431BA342064606D37C1C28197F
+:1045E00000F03AFB27463546F2E70A2F04D9BDE82A
+:1045F000F840012000F076BBF8BD00BF98390020DC
+:10460000F8B506460D4600F015FB0F4A134653F861
+:10461000107F9F4206D12A4601463046BDE8F84049
+:10462000FFF7C2BFD169BB68441A2C1928BF2C46BA
+:10463000A34202D92946FFF79BFF22463146034891
+:10464000BDE8F840FFF77EBF98390020A839002068
+:1046500010B4C0E9032300235DF8044B4361FFF766
+:10466000CFBF000010B5194C236998420DD0D0E996
+:104670000032816813605A609A680A449A60002385
+:1046800003604FF0FF33A36110BD2346026843F877
+:10469000102F53600022026022699A4203D1BDE8C4
+:1046A000104000F0D3BA936881680B44936000F027
+:1046B000C1FA2269E1699268441AA242E4D911441C
+:1046C000BDE81040091AFFF753BF00BF983900201A
+:1046D0002DE9F047DFF8BC8008F110072C4ED8F820
+:1046E000105000F0A7FAD8F81C40AA68031B9A42A1
+:1046F0003ED81444D5E900324FF00009C8F81C40F8
+:1047000013605A60C5F80090D8F81030B34201D158
+:1047100000F09CFA89F31188D5E9033128469847BF
+:10472000302383F311886B69002BD8D000F082FA14
+:104730006A69A0EB04094A4582460DD2022000F0C6
+:10474000D1FA0022D8F81030B34208D15146284699
+:10475000BDE8F047FFF728BF121A2244F2E712EB38
+:10476000090938BF4A4629463846FFF7EBFEB5E748
+:10477000D8F81030B34208D01444211AC8F81C00ED
+:10478000A960BDE8F047FFF7F3BEBDE8F08700BFC2
+:10479000A83900209839002000207047FEE700006B
+:1047A000704700004FF0FF3070470000BFF34F8F9D
+:1047B000024A1369DB03FCD4704700BF00200240AB
+:1047C00008B5094B1B7873B9FFF7F0FF074B5A691F
+:1047D000002ABFBF064A9A6002F188329A601A68BE
+:1047E00022F480621A6008BDD83B002000200240FD
+:1047F0002301674508B50B4B1B7893B9FFF7D6FF2C
+:10480000094B5A6942F000425A611A6842F48052D8
+:104810001A601A6822F480521A601A6842F48062A0
+:104820001A6008BDD83B0020002002403F289ABFF4
+:1048300000F58030C0020020704700004FF4006097
+:1048400070470000402070473F2808B50BD8FFF79D
+:10485000EDFF00F500630268013204D104308342A9
+:10486000F9D1012008BD0020FCE700003F2838B541
+:10487000044626D8FFF7E6FDFFF798FFFFF7A0FFF5
+:10488000114BF3221A6102225A615A6942EAC402A8
+:104890005A615A6942F480325A6105462046FFF750
+:1048A00085FF4FF40061FFF7C1FF00F059F928467A
+:1048B000FFF7A0FFFFF7D0FD2046BDE83840FFF727
+:1048C000C3BF002038BD00BF0020024040EA020301
+:1048D00013F007032DE9F04705460C46164606D0AF
+:1048E000344B40F231321A600020BDE8F087811865
+:1048F000314A91420CD92F4A40F236311160F3E728
+:104900002B1D1B686268934208D1083E08350834A5
+:10491000072E19D92A6823689A42F1D0FFF792FD31
+:10492000FFF74EFFFFF742FF04F10801234C4FF061
+:1049300001084FF00009012EA1F1080708D8FFF780
+:1049400059FFFFF789FD01E0002EE7D10120CCE7F8
+:10495000C4F81480AA4651F8083C4AF8043B51F8C0
+:10496000043C6B60FFF722FF236943F001032361DE
+:10497000C4F814902A6851F8083C9A420ED00D4BA6
+:1049800040F25E321A600E4B1D600E4B1E600E4BE5
+:104990001F60FFF72FFFFFF75FFDA5E7DAF800A024
+:1049A00051F8043C9A4501F10801E8D1083E083568
+:1049B000C1E700BFD43B00200000020800200240F5
+:1049C000C83B0020D03B0020CC3B0020084908B564
+:1049D0000B7828B11BB9FFF7F3FE01230B7008BD5C
+:1049E000002BFCD0BDE808400870FFF703BF00BFF4
+:1049F000D83B002008B54FF4B0414FF0005000F014
+:104A0000B1F8BDE808404FF420514FF0805000F05D
+:104A1000A9B80000084600F0F3BB000070B582B0F2
+:104A2000FFF710FD0E4E054600F004F93268904283
+:104A300037BF0C4A0B49516814682EBFD1E90041B9
+:104A4000013151600419034641F1000128460191EA
+:104A50003360FFF701FD0199204602B070BD00BF31
+:104A6000DC3B0020E03B002070B582B0FFF7EAFCA1
+:104A7000104E054600F0DEF83268904237BF0E4A0D
+:104A80000D49516814682EBFD1E9004101315160D0
+:104A9000041941F100010346284601913360FFF7F4
+:104AA000DBFC01994FF47A7200232046FBF7A0FB50
+:104AB00002B070BDDC3B0020E03B00200244D2B2DB
+:104AC000904200D17047431C800000F1804000F507
+:104AD0001450006841F8040BD8B2F1E7124B10B53E
+:104AE000D3F89040240409D4D3F89040C3F8904000
+:104AF000D3F8904044F40044C3F890400B4C236832
+:104B0000024443F480732360D2B2904200D110BDBE
+:104B1000431C800000F1804000F5145051F8044B14
+:104B20000460D8B2F1E700BF0010024000700040FE
+:104B300007B5012201A90020FFF7C0FF019803B0CB
+:104B40005DF804FB13B50446FFF7F2FFA04205D061
+:104B5000012201A900200194FFF7C0FF02B010BD9F
+:104B6000704700007047000070470000074B45F297
+:104B700055521A6002225A6040F6FF729A604CF653
+:104B8000CC421A60024B01221A707047003000407C
+:104B9000EC3B0020034B1B781BB1034B4AF6AA22C7
+:104BA0001A607047EC3B002000300040054B1A684B
+:104BB00032B902F1804202F50432D2F894201A6030
+:104BC000704700BFE83B0020024B4FF40002C3F8DF
+:104BD000942070470010024008B5FFF7E7FF024B32
+:104BE0001868C0F3407008BDE83B00207047000023
+:104BF000FEE700000A4B0B480B4A90420BD30B4BCD
+:104C0000DA1C121AC11E22F003028B4238BF0022A6
+:104C10000021FCF755BE53F8041B40F8041BECE7D9
+:104C2000D4540008703C0020703C0020703C0020F0
+:104C300000F0C2B84FF08043586A70474FF080438D
+:104C4000002258631A610222DA6070474FF08043F5
+:104C50000022DA60704700004FF0804358637047CD
+:104C6000FEE7000070B51B4B01630025044686B0CB
+:104C7000586085620E46FEF7DFFF04F11003C4E9B9
+:104C800004334FF0FF33C4E90635C4E90044A5609E
+:104C9000E562FFF7CFFF2B460246C4E9082304F183
+:104CA00034010D4A256580232046FFF7E5FB0123EB
+:104CB000E0600A4A0375009272680192B268CDE919
+:104CC0000223074B6846CDE90435FFF7FDFB06B02C
+:104CD00070BD00BFC03B0020705300087553000832
+:104CE000614C0008024AD36A1843D062704700BF83
+:104CF000983900204B6843608B688360CB68C36041
+:104D00000B6943614B6903628B6943620B68036003
+:104D10007047000008B5204BDA6A42F07F02DA6281
+:104D2000DA6A22F07F02DA62DA6ADA6C42F07F0233
+:104D3000DA64DA6E42F07F02DA66184ADB6E1146F8
+:104D40004FF09040FFF7D6FF02F11C0100F58060A4
+:104D5000FFF7D0FF02F1380100F58060FFF7CAFFCE
+:104D600002F1540100F58060FFF7C4FF02F1700109
+:104D700000F58060FFF7BEFF02F18C0100F5806056
+:104D8000FFF7B8FF02F1A80100F58060FFF7B2FF5E
+:104D9000BDE8084000F050B8001002407C53000805
+:104DA00008B500F0FBF9FFF725FBBDE80840FFF769
+:104DB000FDBE0000704700000F4B9A6D42F00102EB
+:104DC0009A659A6F42F001029A670C4A9B6F93684A
+:104DD00043F0010393604FF08043A7229A624FF0A3
+:104DE000FF32DA6200229A615A63DA605A60012265
+:104DF0005A611A60704700BF00100240002004E0B2
+:104E00004FF0804208B51169D3680B40D9B2C9434D
+:104E10009B07116107D5302383F31188FFF710FB3F
+:104E2000002383F3118808BD08B5FFF75FF8BDE8DC
+:104E3000084000F08BB900004E4B4FF0FF319A6AEA
+:104E400099629A6A00229A62986AD86A60F07F0032
+:104E5000D862D86A00F07F00D862D86A186B1963EC
+:104E6000186B1A63186B986B9963986B9A63986BBD
+:104E7000D86BD963D86BDA63D86B186C1964196C6A
+:104E80001A64196C196E41F001011966D3F880108B
+:104E900021F00101C3F88010D3F88010996D41F022
+:104EA00080519965996F21F080519967996F3249C6
+:104EB0004FF400408860CA600A624A628A62CA622D
+:104EC0000A634A638A63CA630A644A648A64CA6476
+:104ED0000A654A654A604FF48072C1F880204FF439
+:104EE00040720A604A6912F48062FBD1D3F89010D4
+:104EF00011F4407F1EBF4FF48031C3F89010C3F807
+:104F00009020D3F8982042F00102C3F89820D3F8FB
+:104F100098209207FBD51A6842F480321A601A680A
+:104F20009003FCD5D3F8902022F00322C3F8902000
+:104F3000124ADA601A6842F080721A601A689101A7
+:104F4000FCD50F490F4800229A60C3F888100E491B
+:104F5000C3F89C20016002684A401207FBD19A689E
+:104F600042F003029A609A6802F00C020C2AFAD10D
+:104F7000704700BF0010024000700040232A61010A
+:104F8000550100500020024004070400074A08B5FC
+:104F9000536903F00103536123B1054A13680BB150
+:104FA00050689847BDE80840FEF76ABE000401401B
+:104FB000F03B0020074A08B5536903F00203536130
+:104FC00023B1054A93680BB1D0689847BDE8084003
+:104FD000FEF756BE00040140F03B0020074A08B52A
+:104FE000536903F00403536123B1054A13690BB1FC
+:104FF00050699847BDE80840FEF742BE00040140F2
+:10500000F03B0020074A08B5536903F008035361D9
+:1050100023B1054A93690BB1D0699847BDE80840B0
+:10502000FEF72EBE00040140F03B0020074A08B501
+:10503000536903F01003536123B1054A136A0BB19E
+:10504000506A9847BDE80840FEF71ABE00040140C8
+:10505000F03B0020164B10B55C6904F478725A617D
+:10506000A30604D5134A936A0BB1D06A9847600629
+:1050700004D5104A136B0BB1506B9847210604D529
+:105080000C4A936B0BB1D06B9847E20504D5094AE3
+:10509000136C0BB1506C9847A30504D5054A936C6B
+:1050A0000BB1D06C9847BDE81040FEF7E9BD00BFDA
+:1050B00000040140F03B0020194B10B55C6904F47A
+:1050C0007C425A61620504D5164A136D0BB1506DCE
+:1050D0009847230504D5134A936D0BB1D06D9847BB
+:1050E000E00404D50F4A136E0BB1506E9847A1042B
+:1050F00004D50C4A936E0BB1D06E9847620404D568
+:10510000084A136F0BB1506F9847230404D5054A22
+:10511000936F0BB1D06F9847BDE81040FEF7B0BD5C
+:1051200000040140F03B002008B50348FEF75AFE9A
+:10513000BDE80840FEF7A4BDEC38002008B5FFF735
+:105140005FFEBDE80840FEF79BBD0000062108B5E4
+:105150000846FEF7DFFE06210720FEF7DBFE0621EC
+:105160000820FEF7D7FE06210920FEF7D3FE062110
+:105170000A20FEF7CFFE06211720FEF7CBFE062100
+:105180002820FEF7C7FE07211C20FEF7C3FEBDE85E
+:1051900008400C212520FEF7BDBE000008B5FFF732
+:1051A00043FE00F009F8FFF75DF8FFF703FEBDE8E6
+:1051B0000840FFF73DBD00000023054A19460133B2
+:1051C000102BC2E9001102F10802F8D1704700BFAC
+:1051D000F03B00200B460146184600F003B80000E3
+:1051E00000F00EB810B5054C13462CB10A46014626
+:1051F0000220AFF3008010BD2046FCE70000000055
+:10520000024B01461868FFF705BC00BF28110020BB
+:1052100010B501390244904201D1002005E0037825
+:1052200011F8014FA34201D0181B10BD0130F2E765
+:105230002DE9F041A3B1C91A17780144044603F1DE
+:10524000FF3C8C42204601D9002009E00578BD4290
+:1052500004F10104F5D10CEB0405D618A54201D1E7
+:10526000BDE8F08115F8018D16F801EDF045F5D097
+:10527000E7E70000034611F8012B03F8012B002A91
+:10528000F9D170476F72672E6172647570696C6FC7
+:10529000742E48697465632D416972737065656425
+:1052A0000000000053544D333247343F3F000000AC
+:1052B00040A2E4F1646891060041A3E5F2656992B9
+:1052C000070000004261642043414E496661636506
+:1052D00020696E6465782E00000000000000000068
+:1052E00061240008691F0008292B0008611F0008BD
+:1052F00011200008F5210008D91F0008A11F00088F
+:10530000A51F00087D1F0008651F0008B5210008C3
+:10531000891F0008652C0008951F000889210008D6
+:1053200000960000000000000000000000000000E7
+:1053300000000000000000000000000025420008FE
+:10534000114200084D420008394200084542000859
+:10535000314200081D420008094200085942000875
+:105360006330000060530008F0390020C03B00208B
+:105370006D61696E0069646C650000000010802A30
+:1053800000000000AAAAAAAA00000024BFFF000093
+:10539000000000000090090000A0000100000000D3
+:1053A000AAFAAAAA00500001FFFF0000000000773F
+:1053B000000000000000000000000000AAAAAAAA45
+:1053C00000000000FFFF00000000000000000000DF
+:1053D0000000000000000000AAAAAAAA0000000025
+:1053E000FFFF0000000000000000000000000000BF
+:1053F00000000000AAAAAAAA00000000FFFF000007
+:10540000000000000000000000000000000000009C
+:10541000AAAAAAAA00000000FFFF000000000000E6
+:10542000000000000000000000000000AAAAAAAAD4
+:1054300000000000FFFF000000000000000000006E
+:10544000E0ADFF7F01000000160400000000000036
+:105450000098010000000000FE2A0100D2040000B4
+:10546000FF000000EC38002000000000A4520008FB
+:105470002C110020000000000000000000000000CF
+:10548000000000000000000000000000000000001C
+:10549000000000000000000000000000000000000C
+:1054A00000000000000000000000000000000000FC
+:1054B00000000000000000000000000000000000EC
+:1054C00000000000000000000000000000000000DC
+:0454D00000000000D8
:00000001FF
diff --git a/Tools/bootloaders/HolybroG4_Compass_bl.bin b/Tools/bootloaders/HolybroG4_Compass_bl.bin
index c2b40508745aba..c6cee547010430 100755
Binary files a/Tools/bootloaders/HolybroG4_Compass_bl.bin and b/Tools/bootloaders/HolybroG4_Compass_bl.bin differ
diff --git a/Tools/bootloaders/HolybroG4_GPS_bl.bin b/Tools/bootloaders/HolybroG4_GPS_bl.bin
index 27909f4a5948a6..59d33b5fbf38c3 100755
Binary files a/Tools/bootloaders/HolybroG4_GPS_bl.bin and b/Tools/bootloaders/HolybroG4_GPS_bl.bin differ
diff --git a/Tools/bootloaders/HolybroG4_GPS_bl.elf b/Tools/bootloaders/HolybroG4_GPS_bl.elf
index c8e5d7c421d873..a0432c3ec6b22a 100755
Binary files a/Tools/bootloaders/HolybroG4_GPS_bl.elf and b/Tools/bootloaders/HolybroG4_GPS_bl.elf differ
diff --git a/Tools/bootloaders/HolybroG4_GPS_bl.hex b/Tools/bootloaders/HolybroG4_GPS_bl.hex
index 18c169dad9ed58..07b2562c97e6ae 100644
--- a/Tools/bootloaders/HolybroG4_GPS_bl.hex
+++ b/Tools/bootloaders/HolybroG4_GPS_bl.hex
@@ -1,19 +1,19 @@
:020000040800F2
-:1000000000070020F5040008212D0008A12C00089D
-:10001000F92C0008A12C0008CD2C0008F7040008DA
-:10002000F7040008F7040008F7040008753B00080F
+:1000000000070020F5040008552D00080D2D0008FC
+:10001000352D00080D2D00082D2D0008F7040008CF
+:10002000F7040008F7040008F7040008253D00085D
:10003000F7040008F7040008F7040008F7040008B4
:10004000F7040008F7040008F7040008F7040008A4
-:10005000F7040008F7040008A14D0008C94D000886
-:10006000F14D0008194E0008414E0008F704000841
+:10005000F7040008F704000899500008C150000890
+:10006000E95000081151000839510008F704000850
:10007000F7040008F7040008F7040008F704000874
:10008000F7040008F7040008F7040008F704000864
-:10009000F7040008ED28000801290008694E00084F
+:10009000F7040008BD2C0008D12C000861510008AD
:1000A000F7040008F7040008F7040008F704000844
-:1000B000514F0008F7040008F7040008F70400088F
+:1000B00049520008F7040008F7040008F704000894
:1000C000F7040008F7040008F7040008F704000824
-:1000D000F7040008F70400083D4F0008F704000883
-:1000E000CD4E0008F7040008F7040008F7040008E4
+:1000D000F7040008F704000835520008F704000888
+:1000E000C5510008F7040008F7040008F7040008E9
:1000F000F7040008F7040008F7040008F7040008F4
:10010000F7040008F7040008F7040008F7040008E3
:10011000F7040008F7040008F7040008F7040008D3
@@ -24,12 +24,12 @@
:10016000F7040008F7040008F7040008F704000883
:10017000F7040008F7040008F7040008F704000873
:10018000F7040008F7040008F7040008F704000863
-:10019000F7040008F70400081529000829290008B9
+:10019000F7040008F7040008E52C0008F92C000813
:1001A000F7040008F7040008F7040008F704000843
:1001B000F7040008F7040008F7040008F704000833
:1001C000F7040008F7040008F7040008F704000823
:1001D000F7040008F7040008F7040008F704000813
-:1001E000A11800080000000000000000000000004E
+:1001E000D116000800000000000000000000000020
:1001F00053B94AB9002908BF00281CBF4FF0FF318E
:100200004FF0FF3000F074B9ADF1080C6DE904CE89
:1002100000F006F8DDF804E0DDE9022304B07047E1
@@ -78,1274 +78,1300 @@
:1004C0004B45A9D2B9EB020864EB0C0E0138A3E747
:1004D0004646EAE7204694E74046D1E7D0467BE728
:1004E000023B614432E7304609E76444023842E7A0
-:1004F000704700BF02E000F000F8FEE772B63A482D
-:1005000080F30888394880F3098839484EF6085145
-:10051000CEF20001086040F20000CCF200004EF67E
-:100520003471CEF200010860BFF34F8FBFF36F8FBD
-:1005300040F20000C0F2F0004EF68851CEF2000109
-:100540000860BFF34F8FBFF36F8F4FF00000E1EEF5
-:10055000100A4EF63C71CEF200010860062080F3CE
-:100560001488BFF36F8F04F0ADFA04F089FA04F039
-:10057000D3FA4FF055301F491B4A91423CBF41F816
-:10058000040BFAE71C49194A91423CBF41F8040B9D
-:10059000FAE71A491A4A1B4B9A423EBF51F8040B1C
-:1005A00042F8040BF8E700201749184A91423CBF73
-:1005B00041F8040BFAE704F067FA04F0F3FA144C7C
-:1005C000144DAC4203DA54F8041B8847F9E700F0F5
-:1005D00041F8114C114DAC4203DA54F8041B884722
-:1005E000F9E704F04FBA00000007002000230020C4
-:1005F000000000080001002000070020B853000898
-:10060000002300208C230020902300207064002011
-:10061000E0010008E4010008E4010008E40100082A
-:100620002DE9F04F2DED108AC1F80CD0C3689D461E
-:10063000BDEC108ABDE8F08F002383F311882846B3
-:10064000A047002003F010FFFEE703F089FE00DF63
-:10065000FEE70000F8B504F0B5F9074604F006FA25
-:100660000546A0BB1F4B9F4231D001339F4231D082
-:100670001D4B27F0FF029A422FD1F8B200F036FD51
-:100680002E4642F2107400F03BFF08B100242646CB
-:1006900000F032FD08B90646044635B1134B9F42BF
-:1006A00003D004F0DBF900242646002004F094F97E
-:1006B0000EB100F063F801F06FFA00F045FF01F0B1
-:1006C00059F9204600F0A8F800F058F8F9E72E464E
-:1006D0000024D8E704460126D5E7064640F6C414B0
-:1006E000D1E700BF010007B0000008B0263A09B00A
-:1006F00008B501F011F9A0F120035842584108BD96
-:1007000007B541F21203022101A8ADF8043001F04F
-:1007100021F903B05DF804FB10B5202383F31188A1
-:100720001248C3680BB103F017FF114A0F480023AA
-:100730004FF47A7103F0D4FE002383F311880D4C3B
-:10074000236813B12368013B2360636813B16368B6
-:10075000013B6360084B1B7833B9636823B90220FF
-:1007600001F0A8F93223636010BD00BF9023002080
-:1007700019070008AC240020A4230020214B224AA2
-:1007800010B51C46196801313BD004339342F9D1AE
-:100790006268A24235D31D4B9B6803F1006303F5E9
-:1007A00010439A422DD204F02BF904F03DF90020B9
-:1007B00001F0FAF8164B0220187001F071F9154B90
-:1007C0009A6D00229A65996F9A67996FD96DDA656B
-:1007D000D96FDA67D96F196E1A66D3F88010C3F82B
-:1007E0008020D3F8803072B64FF0E0232021C3F888
-:1007F000084DD4E9003281F311889D4683F30888BF
-:10080000104710BD00900008209000080023002031
-:10081000A4230020001002402DE9F04F93B0AC4B10
-:1008200000902022FF210AA89D6801F05FF9A94AE3
-:100830001378A3B9A8480121C3601170202383F362
-:100840001188C3680BB103F087FEA44AA2480023B5
-:100850004FF47A7103F044FE002383F31188009B68
-:100860009F4A03B113609F49009C00230B705360A3
-:1008700098469B461E469A46012001F011F924B184
-:10088000974B1B68002B00F01C82002001F044F8FD
-:100890000390039B002B01DA00F0A6FE039B002BC4
-:1008A000EDDB012001F0F2F8039B213B162BE3D88E
-:1008B00001A252F823F000BF150900083D09000805
-:1008C000D1090008790800087908000879080008AB
-:1008D000650A0008370C0008510B0008B30B00082C
-:1008E000DB0B0008010C000879080008130C000855
-:1008F00079080008850C0008B50900087908000887
-:10090000C90C000821090008B50900087908000889
-:10091000B30B00080220FFF7EBFE002840F0FB813C
-:10092000009B0221B8F1000F08BF1C4605A841F248
-:100930001233ADF8143001F00DF89DE74FF47A70E2
-:1009400000F0EAFF071EEBDB0220FFF7D1FE0028D4
-:10095000E6D0013F052F00F2E081DFE807F0030A4F
-:100960000D10133605230593042105A800F0F2FFAE
-:1009700017E057480421F9E75B480421F6E75B4894
-:100980000421F3E74FF01C09484601F00FF809F184
-:1009900004090590042105A800F0DCFFB9F12C0F33
-:1009A000F2D1012000FA07F747EA0B0B5FFA8BFB45
-:1009B0004FF0000A01F0E6F826B10BF00B030B2B09
-:1009C00008BF0024FFF79CFE56E749480421CDE705
-:1009D000002EA5D00BF00B030B2BA1D10220FFF7AB
-:1009E00087FE074600289BD001203E4E00F0DCFF2A
-:1009F0000220307001F054F84FF000085FFA88F9D7
-:100A0000484600F0E1FF044690B1484600F0ECFF94
-:100A100008F101080028F1D1B846044641F212134A
-:100A2000022105A8ADF814303E4600F093FF23E7FD
-:100A300001230220337001F029F82546244B9B68DE
-:100A4000AB4207D9284600F0B1FF013040F0688181
-:100A50000435F3E7234B00251D70214BB8465D603C
-:100A60003E46A7E7002E3FF45BAF0BF00B030B2BCA
-:100A70007FF456AF1B4B0220187001F011F83220A2
-:100A800000F04AFFB0F10009FFF64AAF19F0030782
-:100A90007FF446AF0E4A926809EB050393423FF696
-:100AA0003FAFB9F5807F3FF73BAF124B0193B9459C
-:100AB00022DD4FF47A7000F02FFF0390039A002A92
-:100AC000FFF62EAF019B039A03F8012B0137EDE7E8
-:100AD00000230020A82400209023002019070008EC
-:100AE000AC240020A423002004230020082300209D
-:100AF0000C230020A8230020C820FFF7F9FD07469B
-:100B000000283FF40DAF1F2D11D8C5F120024A4532
-:100B10000AAB25F0030028BF4A46834901921844D6
-:100B200000F0D2FF019A8048FF2100F0DFFF4FEA7A
-:100B3000A9037D490193C9F38702284600F0DEFF2F
-:100B4000064600283FF46AAF019B05EB830531E7B9
-:100B50000220FFF7CDFD00283FF4E2AE00F060FF79
-:100B600000283FF4DDAE0027B946704B9B68BB42BE
-:100B700018D91F2F11D80A9B01330ED027F0030379
-:100B800012AA134453F8203C05934846042205A9B1
-:100B900002F0D4F804378146E7E7384600F006FF54
-:100BA0000590F2E7CDF81490042105A800F0D2FEDC
-:100BB00000E70023642104A8049300F0C1FE00288C
-:100BC0007FF4AEAE0220FFF793FD00283FF4A8AEFD
-:100BD000049800F01BFF0590E6E70023642104A8B9
-:100BE000049300F0ADFE00287FF49AAE0220FFF7D8
-:100BF0007FFD00283FF494AE049800F009FFEAE777
-:100C00000220FFF775FD00283FF48AAE00F018FFC0
-:100C1000E1E70220FFF76CFD00283FF481AE05A953
-:100C2000142000F013FF04210746049004A800F0EC
-:100C300091FE3946B9E7322000F06EFE071EFFF63E
-:100C40006FAEBB077FF46CAE384A926807EB0A03BD
-:100C500093423FF665AE0220FFF74AFD00283FF4BD
-:100C60005FAE27F003075744BA453FF4A3AE5046A2
-:100C700000F09CFE0421059005A800F06BFE0AF12F
-:100C8000040AF1E74FF47A70FFF732FD00283FF4D1
-:100C900047AE00F0C5FE002844D00A9B01330BD0BC
-:100CA00008220AA9002000F029FF00283AD02022BB
-:100CB000FF210AA800F01AFFFFF722FD1C4803F0ED
-:100CC000D9FB13B0BDE8F08F002E3FF429AE0BF036
-:100CD0000B030B2B7FF424AE0023642105A805939E
-:100CE00000F02EFE074600287FF41AAE0220FFF720
-:100CF000FFFC814600283FF413AEFFF701FD41F2EF
-:100D0000883003F0B7FB059800F052FF4E4600F024
-:100D100039FF3C46B0E506464CE64FF0000AFFE5D9
-:100D2000B8467BE6374679E6A8230020002300205A
-:100D3000A0860100094A136849F2690099B21B0CA8
-:100D400000FB01331360064B186844F2506182B215
-:100D5000000C01FB0200186080B2704714230020D1
-:100D60001023002010B500211022044600F0BEFE22
-:100D7000034B03CB206061601868A06010BD00BF0A
-:100D80009075FF1F2DE9F043224DBBB001F0D0FF5D
-:100D9000AB6840F2ED22C31A934232D906AFA86085
-:100DA0002B4628220021384602F0A0FC05F10E0057
-:100DB00000F094FE002604465FFA80F905F10E0863
-:100DC000F3B2F100994501F1280107D908EB0603B8
-:100DD0000822384602F08AFC0136F1E70823012296
-:100DE000CDE9023205340C4B0193A4B230230093B9
-:100DF000CDE9047405A3D3E90023297B074802F059
-:100E00008DFA3BB0BDE8F083AFF3008078F6339FF6
-:100E100093CACD8D585E0020655E0020CC34002042
-:100E200070B50D4614461E4602F00EFA50B9022E59
-:100E300010D1012C0ED112A3D3E90023C5E9002360
-:100E4000012007E0282C10D005D8012C09D0052C52
-:100E50000FD0002070BD302CFBD10BA3D3E90023B1
-:100E6000ECE70BA3D3E90023E8E70BA3D3E90023C6
-:100E7000E4E70BA3D3E90023E0E700BFAFF3008072
-:100E8000401DA12026812A0B78F6339F93CACD8D71
-:100E90009E6AC421818A46EE26417272DF25D7B749
-:100EA000F017304A39059E5613B5044623460846C6
-:100EB00020220021019002F019FC22790198032AD6
-:100EC000234628BF032203F8042F2021022202F028
-:100ED0000DFC62790198072A234628BF072203F8F0
-:100EE000052F2221032202F001FCA2790198072A92
-:100EF000234628BF072203F8062F2521032202F0EC
-:100F0000F5FB019804F108031022282102F0EEFB02
-:100F1000382002B010BD00002DE9F04FADF5017D85
-:100F200021AD0EAE40F2751280460F4622A8002178
-:100F3000296000F0DBFD48220021304600F0D6FD9C
-:100F400001F0F6FE564B4FF47A72B0FBF2F01860E7
-:100F500093E80700012386E807000DF15A00338269
-:100F6000FFF700FF41F60453338407AB18464D49A1
-:100F700004F0D6F81B2230642946304686F83C201F
-:100F8000FFF792FF12AB044601460822284602F002
-:100F9000ADFB0822A1180DF14903284602F0A6FB7B
-:100FA0000DF14A03082204F11001284602F09EFBCD
-:100FB00013AB202204F11801284602F097FB14AB72
-:100FC000402204F13801284602F090FB16AB0822BB
-:100FD00004F17801284602F089FB0DF1590308223B
-:100FE00004F18001284602F081FB04F1880A0DF12A
-:100FF0005A0904F5847B4B465146082228460AF1DB
-:10100000080A02F073FBD34509F10109F3D11BABC8
-:1010100008225946284602F069FB04F588744FF00F
-:10102000000996F834304B450AD9B36B21464B443E
-:101030000822284602F05AFB083409F10109F0E7BA
-:101040004FF0000996F83C304B4504EBC90108D934
-:10105000336C08224B44284602F048FB09F1010991
-:10106000F0E700230393BB7E0293073107F11903D6
-:101070000193C1F3CF010123CDE904510093F97E1F
-:1010800005A3D3E90023404602F048F90DF5017DA0
-:10109000BDE8F08FAFF300809E6AC421818A46EEDE
-:1010A000B424002050510008F8B50E4C0E4F022613
-:1010B000A4F5805343F8307C237E3BB965692DB19C
-:1010C000284601F0B3FC284603F094FF204601F0C7
-:1010D000ADFCA4F5A554012EA4F1100400D1F8BD77
-:1010E0000126E5E7D859002040520008014B18704E
-:1010F000704700BFC0240020F0B5334B1C7B85B087
-:1011000034B1324B0E221A810024204605B0F0BDC6
-:101110002F4A1068516802AB03C308232D492E489B
-:101120000DEB030203F08EFF054630B9274B2B4829
-:101130000A221A8101F002FCE6E70169B1F5EE2FFF
-:1011400006D9224B26480B221A8101F0F7FBDCE777
-:10115000438B40F21D42934207D01C490C2008816A
-:101160001946204801F0EAFBCFE71F4A024402F18A
-:101170001003994204D2154B1C4810221A81E4E74F
-:1011800010398E1A2046144901F0D8FD3246074620
-:1011900005F11801204601F0D1FDAB689F4202D154
-:1011A000EB6898420AD0094B0D221A810090D5E9CC
-:1011B00002123B460E4801F0C1FBA5E70D4801F0C5
-:1011C000BDFB0124A1E700BF585E0020B42400202D
-:1011D000FD510008DC6F0700009000086C5100080A
-:1011E000785100088A5100080870FFF7A8510008DC
-:1011F000C5510008EE5100082DE9F04FADB006AF23
-:1012000080460C4602F020F8054600285AD1237E7D
-:10121000022B1BD1E38A012B18D101F089FD064670
-:10122000FFF788FD03464FF4C870DFF8D092B3FB98
-:10123000F0F206F5167602FB103316FA83F3C9F8BE
-:101240000030E37E33B9A84B00221A709C37BD46AC
-:10125000BDE8F08FA38AEEB2013BB34205F1010570
-:101260000BD93B1D1E44E90000960023082201F023
-:10127000F801204602F0FEF8ECE707F11400FFF752
-:1012800071FD324607F11401381D03F0CBFE002832
-:10129000D9D10F2E08D8944B1E70D9F80030A3F581
-:1012A0001673C9F80030D1E7FB1CF87001460093B3
-:1012B00007220346204602F0DDF8F978404601F0A7
-:1012C000BBFFC3E7E38A282B26D010D8012B1ED002
-:1012D000052BBBD1BFF34F8F8449854BCA6802F4FD
-:1012E000E0621343CB60BFF34F8F00BFFDE7302BAD
-:1012F000ACD1637E7F4D01336A7BDBB29342E9461A
-:1013000003D1E27E2B7B9A4265D0CD469EE72146F3
-:101310004046FFF701FE99E7A38A013B9BB2C92B28
-:1013200094D8744D2E7B26BB05F10C030093082244
-:1013300033463146204602F09DF8731CF2B2D900C4
-:101340001E46A38A013B9A4205DA0E322A440092D5
-:1013500000230822EEE700230022C5E90023002332
-:10136000AB6085F8D730C5F8D8302B7B0BB9E37E5E
-:101370002B73002507F114093B1D08222946484616
-:10138000C7E90155FD6002F0B1F93B7A05F1010AA8
-:10139000AB424FEACA0608D9FB6808222B44314603
-:1013A000484602F0A3F95546EFE7C6F3CF06E17EC3
-:1013B000CDE9049600230393A37E029319342823D6
-:1013C0000093019446A3D3E90023404601F0A6FF11
-:1013D000FFF7D8FC3AE74FF0000807F11403A7F82D
-:1013E00014801022009341460123204602F042F867
-:1013F000A68A023EB6B2F31C9B109B000733DB08A3
-:10140000A9EBC3039D460DF1180A1FFA88F34FEAB2
-:10141000C801B34201F110010AD20AEB080300939C
-:1014200008220023204602F025F808F10108ECE725
-:1014300095F8D70000F0C8FAD5F8D83004461BB9A3
-:1014400095F8D70000F0D0FAD5F8D83033449C4254
-:1014500004D295F8D700013000F0C6FA4FEA960B97
-:101460004FF000081FFA88F18B45D5E9003209D901
-:101470000AEB880103EB8800012200F03FFB08F132
-:101480000108EFE7F31842F10002C5E90032D5F890
-:10149000D83095F8D70006EB0308C5F8D88000F0DF
-:1014A00093FA804509D395F8D730D5F8D8000133A1
-:1014B000001B85F8D730C5F8D800FF2E08D80023C8
-:1014C0002B7300F0ADFAFFF717FE08B1FFF756F9DE
-:1014D0002B68094A9B0A013313810023AB6014E790
-:1014E00026417272DF25D7B7C534002000ED00E039
-:1014F0000400FA05585E0020B4240020C8340020FF
-:1015000010B54FF000540C4B22689A4211D10B4B8E
-:10151000627D1A700A48237D03730A49C9220E307E
-:1015200000F0D2FAE0220021204600F0DFFA01208C
-:1015300010BD0020FCE700BF9AAD44C5C0240020C8
-:10154000585E00201600002037B51E4C1E4D1F4966
-:1015500002236B712368204604F580545B680122E6
-:101560009847D4F8B03419495B68012204F59660B5
-:10157000984700230193164B164900931648174BC2
-:101580004FF4805201F032FE154B197811B1124818
-:1015900001F052FE01F0CCFB0446FFF7CBFB4FF409
-:1015A000C873B0FBF3F202FB130304F5167010FAD4
-:1015B00083F00C4B186003F059FA08B10F232B810C
-:1015C00003B030BDF8340020B424002040420F00A6
-:1015D000210E0008C4240020CC340020F91100089A
-:1015E000C0240020C83400202DE9F04F2DED028BDF
-:1015F0009F4D93B0DFF8A0A29E4F284601F0F2FE67
-:10160000034600283ED00024CDE90F440E94ADF8E7
-:101610004440027B8DF8442099684068964E0FAA9A
-:1016200003C21B6843F000430E93A046A1463368F3
-:10163000D3F810B001F07EFB10EB0A0241F1000379
-:101640003046CDF800900EA9D84704F22C5440F64D
-:1016500058230028C8BF48F0010806F5A5569C424B
-:1016600006F11006E3D1B8F1000F05D0284601F0CD
-:10167000BDFE87F80090C0E73B78072B00F2E780BB
-:1016800001333B700DF12C089FED738B0023DFF8C5
-:101690000C920A93ADF834300B93C8F8043000264E
-:1016A000754C374601238DF81C3023688DED008B77
-:1016B0004FF0000BD3F808A08DF81DB05B460DF17C
-:1016C0001D0207A92046D0479DF81CA0BAF1000FC3
-:1016D00024D0D9F8143083F48063C9F81430102270
-:1016E00059460EA800F002FA236808AA5F690AA901
-:1016F0000DF11E032046B84798E803000FAB83E8BE
-:1017000003009DF834308DF844300A9B0E930EA9E7
-:10171000DDE90823284602F031F8574606F22C5638
-:1017200040F6582304F5A5549E4204F11004B9D1A3
-:10173000002FB4D1284601F087FD002840D14F4E3C
-:1017400001F0F6FA336898423AD301F0F1FA044610
-:10175000FFF7F0FA4FF4C87304F51674B0FBF3F218
-:1017600002FB130314FA83F33360454E8DF828709F
-:10177000377817B901238DF82830C7F11004E4B287
-:101780000EA8FFF7EFFA062C28BF06240EAB224660
-:10179000D9190DF1290000F097F90AAB039318232A
-:1017A00002930134374B0193E4B201230093049474
-:1017B0002BA3D3E90023284601F048FD0023337012
-:1017C00001F0B6FA304A314C1368C31AB3F57A7F88
-:1017D00030D3106001F0AEFA02460B46284601F005
-:1017E0000FFE284601F030FD20B3237B284E002B4E
-:1017F00014BF03230223737101F09AFA0EAF4FF462
-:101800007A733946B0FBF3F030603046FFF74CFB9B
-:101810001823073002931F4B0193C0F3CF0040F20F
-:101820005513CDE90370009328460FA3D3E9002395
-:1018300001F00CFD237B2BB1FFF7A4FA237B002BD7
-:101840007FF4D8AE13B0BDEC028BBDE8F08F284614
-:1018500001F0CCFD16E700BF000000000000000012
-:10186000401DA12026812A0BF1C6A7C1D068080F10
-:10187000CC3400203D5F0020F8340020C834002024
-:10188000C5340020C4340020385F0020585E00209A
-:10189000B42400203C5F002040420F0000080048B4
-:1018A00008B5064800F096FB054800F093FBBDE83C
-:1018B0000840044A0449002003F096BBF834002095
-:1018C000A8490020945F0020A910000870B50F4BB4
-:1018D0001B780133DBB2012B0C4611D80C4D296863
-:1018E0004FF47A730E6AA2FB033201462246284661
-:1018F000B047844204D1074B00221A70012070BD0A
-:101900004FF4FA7002F0B6FD0020F8E7182300202B
-:10191000985F0020845F002007B500230246012164
-:101920000DF107008DF80730FFF7D0FF20B19DF8CB
-:10193000070003B05DF804FB4FF0FF30F9E700004B
-:101940000A4608B50421FFF7C1FF80F00100C0B2CC
-:10195000404208BD30B4054C2368DD69044B0A469B
-:10196000AC460146204630BC604700BF985F00206F
-:10197000A086010070B502F0B5FE094E094D308019
-:10198000002428683388834208D902F0A7FE2B6818
-:1019900004440133B4F5104F2B60F2D370BD00BF87
-:1019A000865F0020405F002002F05EBF00F1006013
-:1019B00000F510400068704700F10060920000F5EB
-:1019C000104002F0D5BE0000054B1A68054B1B887D
-:1019D0009B1A834202D9104402F080BE0020704757
-:1019E000405F0020865F002038B5074D0446286818
-:1019F000204402F07BFE28B928682044BDE8384026
-:101A000002F086BE38BD00BF405F00200020704756
-:101A100000F10050A0F51040D0F89005704700008C
-:101A2000064991F8243033B10023086A81F8243044
-:101A30000822FFF7C1BF0120704700BF445F0020AC
-:101A4000014B1868704700BF002004E070B50E4BD2
-:101A50005C6893F90860421E0A44013C0B469342BD
-:101A600007D214F9015F581C2DB100F8015C034640
-:101A7000F5E7184605E02C2482421C7001D9981C19
-:101A80005E70401A70BD00BF1C230020022802BFF8
-:101A9000024B4FF080629A61704700BF0008004817
-:101AA000022802BF024B4FF480629A61704700BF68
-:101AB00000080048022801BF024A536983F480638A
-:101AC000536170470008004810B50023934203D0CB
-:101AD000CC5CC4540133F9E710BD00000346024654
-:101AE000D01A12F9011B0029FAD1704702440346AB
-:101AF000934202D003F8011BFAE770472DE9F8433F
-:101B00001F4D144695F824200746884652BBDFF83F
-:101B100070909CB395F824302BB92022FF214846C1
-:101B20002F62FFF7E3FF95F82400C0F10802A242FC
-:101B300028BF2246D6B24146920005EB8000FFF74F
-:101B4000C3FF95F82430A41B1E44F6B2082E174498
-:101B50009044E4B285F82460DBD1FFF761FF0028F0
-:101B6000D7D108E02B6A03EB82038342CFD0FFF783
-:101B700057FF0028CBD10020BDE8F8830120FBE708
-:101B8000445F0020024B1A78024B1A70704700BF66
-:101B9000845F002018230020034904484FF4614368
-:101BA0000B6002F001BB00BF6C5F0020985F00205B
-:101BB000074B10B50021044618221846FFF796FF80
-:101BC00004600146BDE81040024802F0EDBA00BFD3
-:101BD0006C5F0020985F0020202383F3118862B699
-:101BE00070470000002383F3118862B6704700003D
-:101BF00001207047704700007047000010B4134682
-:101C0000026814680022A4465DF8044B6047000097
-:101C100000F5805090F859047047000000F580509E
-:101C200090F852047047000000F5805090F9580475
-:101C3000704700005020704700F5805208B5FFF74C
-:101C4000CBFFD2F89834D2F894041844D2F89034E8
-:101C50001844D2F878341844D2F888341844D2F8AA
-:101C600084341844FFF7BEFF08BD00002DE9F74F8C
-:101C70000C4600F580511F4691F85234BDF8309063
-:101C8000054690469BB1D1F874340133C1F87434E1
-:101C900023689A0006D4237B082B0BD9627B0AB1F8
-:101CA0000F2B07D9D1F878340133C1F878344FF0CD
-:101CB000FF300FE0FFF790FFEB6AD3F8C42012F477
-:101CC000001A0AD0D1F87C340133C1F87C34FFF714
-:101CD00089FF002003B0BDE8F08FD3F8C46022680C
-:101CE0006B6AC6F301464FF0480B002A1BFB063B0C
-:101CF000B4BF42F080429204CBF8002023685B001E
-:101D000044BF42F00052CBF80020227B330643EA66
-:101D10000243CBF80430607B720118B343F44013E4
-:101D2000CBF80430D1F8A4340133C1F8A434AB1893
-:101D300003F58353197B41F020011973207B019235
-:101D400000F058FE019A033080105FFA8AF3834254
-:101D50000AF1010A0DDA04EB83010BEB83034968F6
-:101D60009960F2E7AB1803F58353197B60F34511D3
-:101D7000E3E7EB6A0121B140C3F8CC10AB1803F5DF
-:101D80008253C3E9048705EB461303F582532146CA
-:101D9000183304F10C0051F804CB43F804CB814212
-:101DA000F9D1098819802A4441F268032846D6509F
-:101DB00002F5805209F0030392F86C1043F010030F
-:101DC00021F01F010B4382F86C30FFF70BFF4246F6
-:101DD0003B462146CDF8309003B0BDE8F04F00F00F
-:101DE000CFBD000038B5C26A936923F00103936147
-:101DF000044600F09DFF0546E36A9B69DB0706D5B4
-:101E000000F096FF431BFA2BF6D9002004E004F5FE
-:101E10008054012084F8520438BD000013B500F549
-:101E200080540191606C00F037FE1F280AD9019997
-:101E3000606C202200F0A6FEA0F120035842584119
-:101E400002B010BD0020FBE708B500F58050FFF799
-:101E5000C3FE406C00F0F4FDBDE80840FFF7C2BED1
-:101E600000220260828142608260704710B50022C9
-:101E70000023C0E900230023044603810C30FFF750
-:101E8000EFFF204610BD00002DE9F047074688B05F
-:101E900007F5805468469A468846FFF79DFE9146AE
-:101EA000FFF7E4FF606C00F0DDFD1F282CD9606CAB
-:101EB0002022694600F0E8FE202825D194F852340B
-:101EC00013B303AD444605AB2E4603CE9E422060BD
-:101ED0006160354604F10804F6D130682060B388AB
-:101EE000A380DDE90023C9E90023BDF80830AAF882
-:101EF0000030FFF777FE4A4653464146384608B061
-:101F0000BDE8F04700F02ABDFFF76CFE002008B0E6
-:101F1000BDE8F0872DE9F84F00230646C0E90133FC
-:101F2000294B46F8303B00F5815405468846374634
-:101F3000103438462037FFF799FFA742F9D105F54D
-:101F400080544FF4805326630026C4E90D3667643D
-:101F5000012305F5835705F5A359E66384F840305E
-:101F600084F84830103709F110094FF0000A4FF09B
-:101F7000000B47E908ABA7F11800FFF771FF203706
-:101F800047F8286C4F45F4D1B8F1010F84F8588414
-:101F9000A4F85A64A4F85C64A4F85E6484F86064ED
-:101FA000A4F86264A4F86464A4F8666484F86864BD
-:101FB00002D9064800F0B6FE054B53F82830EB6214
-:101FC0002846BDE8F88F00BF4052000814520008B0
-:101FD0003052000810B5044B197804464A1C1A7098
-:101FE000FFF798FF204610BD915F00202DE9F043D8
-:101FF00000295FD03048314BB3FBF1F381428CBFF5
-:102000000A201120451EB3FBF0F700FB1730ECB29D
-:1020100020B1022D2846F5D8002037E07D1EB5F509
-:10202000806F33D2C4EBC40808F103034FEAE30E18
-:10203000C3F3C703A4EB030C0EF101094FF47A704C
-:102040005FFA8CF60EFB000E59FA8CFCBEFBFCFC12
-:10205000BCF5617F1CDC1FFA8CF4581C56FA80F02A
-:1020600047431648B0FBF7F7B942D5D1013BDBB285
-:102070000F2BD1D8711EC9B207294FF0000005D827
-:10208000107114805580537191710120BDE8F08367
-:1020900008F1FF334FEAE30CC3F3C703E41A0CF172
-:1020A000010EE6B20CFB00005EFA84F4B0FBF4F41F
-:1020B000A4B2D2E70846E9E73F420F000024F4004B
-:1020C00038B500F58053114A93F85834D55C4FF475
-:1020D0005472554305F1804303F52443044600211F
-:1020E0001846FFF703FD0A4B60612B44A361094BBF
-:1020F0002B44E361084B2B442362084B2B4463625F
-:10210000E36A0022C3F8C02038BD00BF285200088F
-:1021100070A40040B0A4004088A5004078A600400C
-:102120002DE9F04F00F58055994695F85834022B6B
-:1021300089B004468A46904604D90027384609B03B
-:10214000BDE8F08F9C4A52F8231009B942F82300E9
-:102150009A49C4F80CA00B7884F8109093B9FFF753
-:102160003BFD974B9A6D42F000729A659A6B42F074
-:1021700000729A639A6B22F000729A6301230B70CB
-:10218000FFF730FD95F85134BBB9FFF725FD8D4AB7
-:1021900095F85834D65C012E26D0022E2BD03EB9AD
-:1021A0000221152001F04EFE0221162001F04AFE08
-:1021B000012385F85134FFF715FDFFF70DFDE26AA5
-:1021C000936923F01003936100F0B2FD0746E36AC0
-:1021D0009E6916F0080615D000F0AAFDC31BFA2B65
-:1021E000F5D9FFF7FFFCA8E70221562001F02AFEEF
-:1021F00002215720DAE73146582001F023FE31460C
-:102200005920D3E79A6942F001029A6100F090FDEB
-:102210000746E36A9A69D00705D400F089FDC31B1D
-:10222000FA2BF6D9DDE79A6942F002029A61E36A75
-:1022300000275F65FFF7D6FC686C00F001FC04F531
-:10224000825B0BF1100B202200216846FFF74EFC49
-:1022500002A8FFF705FE06976A460BEB06030DF191
-:10226000180E9446BCE80300F445186059606246B5
-:1022700003F10803F5D1DCF80000186020369CF863
-:1022800004201A71B6F5806FDDD1002304F5A25247
-:1022900085F8503485F853341A3251462046FFF7FA
-:1022A000A5FE074690B9E26A936923F001039361A2
-:1022B00000F03EFD0546E36A9B69D9077FF53DAF17
-:1022C00000F036FD431BFA2BF5D936E795F85F642D
-:1022D00095F85E24C5F86CA4360246EA426695F885
-:1022E0006024E36A1643B5F85C2446EA0246DE61E0
-:1022F000B8F1000F29D004F5A3520232414620461E
-:10230000FFF774FE90B9E26A936923F001039361C9
-:1023100000F00EFD0546E36A9B69DA077FF50DAF15
-:1023200000F006FD431BFA2BF5D906E795F8683453
-:1023300095F86714C5F870841B0143EA0123B5F8CA
-:102340006414E26A43EA0143D3602046FFF7B8FE13
-:10235000002385F85934E36A6FF040421A65E36A56
-:10236000194A5A65E36A44229A65E36A0722C3F868
-:10237000DC20E36A0322DA65E26A9369B9F1030FAC
-:1023800043F4407393613FF4D9AEE26A936923F05A
-:102390000103936100F0CCFC0646E36A9B69DB070E
-:1023A00005D500F0C5FC831BFA2BF6D9C5E6012341
-:1023B00085F85234C2E600BF885F0020905F00209D
-:1023C00000100240285200089B0008002DE9F04F41
-:1023D000054689B090469946002741F2680A00F503
-:1023E0008056EB6AD3F8D430FB40D8074AD505EBCA
-:1023F000471252444FEA471B1379190742D4D6F8C3
-:1024000080340133C6F8803413799A0648BFD6F871
-:10241000A83405EB0B0248BF0133524448BFC6F84D
-:10242000A834137943F008031371DB0722D596F81B
-:102430005334FBB105F58254183468465C44FFF709
-:1024400015FD03AB04F1080C206861681A4603C24D
-:10245000083464451346F7D120681060A2889A803A
-:102460000123ADF808302B68CDE900891B6C694663
-:1024700028469847D6F8543423B1D6F89C34013313
-:10248000C6F89C340137202FABD109B0BDE8F08FDE
-:102490002DE9F04F8DB004460F4600F04BFC82460C
-:1024A0008946002F56D1E36AD3F89020920141BFAC
-:1024B00004F58051D1F894240132C1F89424D3F862
-:1024C0009020160703D100200DB0BDE8F08FD3F89F
-:1024D0009050E669C5F30125482303FB0566E846ED
-:1024E0004046FFF7BDFC326851004ABF22F060430E
-:1024F000C2F38A4343F00043920048BF43F0804355
-:102500000093736813F400131FBF04F58052012376
-:102510008DF80D30D2F8AC340EBF8DF80D3001338C
-:10252000C2F8AC34F38803F00F038DF80C304FF091
-:10253000000B9DF80C0000F05DFA5FFA8BF39842F7
-:1025400020D9F2180CA90B44127A03F82C2C0BF1A9
-:10255000010BEEE7012FB6D1E36AD3F8982095017D
-:1025600041BF04F58051D1F894240132C1F894247C
-:10257000D3F898201007A6D0D3F89850266AC5F350
-:102580000125A9E7EFB9E36AC3F8945004A8FFF75F
-:102590006DFC98E80F0007AD07C52B800023ADF850
-:1025A000183023682046CDE904A91B6C04A998477C
-:1025B00004F5805458B1D4F88C340133C4F88C3409
-:1025C00082E7012F04BFE36AC3F89C50DEE7D4F82A
-:1025D00090340133C4F89034012075E7F8B505460E
-:1025E0000F4600F58054012639462846FFF750FF74
-:1025F00010B184F85364F7E7D4F8543423B1D4F815
-:102600009C340133C4F89C34F8BD0000F0B5C36AB3
-:102610001A6C12F47F0F2BD000F580541B6CC4F899
-:10262000A03441F26805002347194FF0010C00EB7C
-:1026300043122A445E01117911F0020F15D04907A7
-:1026400013D4B959C66AD6F8C8E00CFA01F111EAF8
-:102650000E0F0AD0C6F8D010117941F004011171A3
-:10266000D4F888240132C4F888240133202BDED129
-:10267000F0BD00002B4B70B51E561B5C012B2FD8F4
-:10268000294D2A4A55F8233052F826400BB341B35E
-:10269000236D1A060FD58023236500F04BFB50EA0B
-:1026A00001020B4602D0013861F10003024655F8E1
-:1026B0002600FFF78BFE236D1B032CD555F8263023
-:1026C0004FF4002203F580532265012283F8592438
-:1026D00021E001232365082323654FF480632365EC
-:1026E00070BD236DDA0702D4236D9B0706D5032343
-:1026F00055F8260023650021FFF770FF236D1807AA
-:1027000002D4236DD90606D5182355F82600236573
-:102710000121FFF763FF55F82600BDE87040FFF781
-:1027200075BF00BF2C520008885F0020305200089F
-:1027300008B5FFF751FAFFF769FFBDE80840FFF75A
-:1027400051BA0000C36AD3F8C40080F40010C0F38B
-:102750004050704700F5805008B5FFF73DFA406CD7
-:1027600000F080F9FFF73EFA43090CBF012000207A
-:1027700008BD000000F5805393F8592462B1C16A86
-:102780008A6922F001028A61D3F898240132C3F8E1
-:102790009824002283F85924704700002DE9F7435C
-:1027A00000F5825198461031FFF716FA002541F2E4
-:1027B000680E4FF0010900F5805C00EB451474448D
-:1027C00023795E071CD4DB061AD5C36A8E69D3F859
-:1027D000C87009FA06F63E4212D04F6801970F689A
-:1027E0009742019F77EB08070AD2C3F8D06023799C
-:1027F00043F004032371DCF884340133CCF88434CF
-:102800000135202D01F12001D7D103B0BDE8F043FF
-:10281000FFF7E8B9F8B51E46002313700F460546CA
-:102820001446FFF797FF80F0010038701EB128466C
-:10283000FFF788FF2070F8BD2DE9F04F85B099466D
-:102840000B7801930E4613780293DDE90EBA8046A9
-:10285000174600F06FFA337804460D4613B93B78FB
-:10286000002B41D022462B464046FFF797FFFFF74B
-:102870005FFFFFF77FFF4B463A463146FFF7CAFF3F
-:1028800033782BB1019B1BB1012005B0BDE8F08F5F
-:102890003B7813B1029B002BF6D108F580530393CC
-:1028A0005C4575EB0A031FD2039BD3F85404D8B1DF
-:1028B0000368BBEB0402D9686AEB050388474B4603
-:1028C0003A4631464046FFF7A5FF337813B1019BE6
-:1028D000002BD9D13B7813B1029B002BD4D100F04F
-:1028E00029FA04460D46DBE70020CEE708B50021B3
-:1028F0000846FFF7BFFEBDE8084001F06FB90000D1
-:1029000008B501210020FFF7B5FEBDE8084001F041
-:1029100065B9000008B500210120FFF7ABFEBDE856
-:10292000084001F05BB9000008B501210846FFF737
-:10293000A1FEBDE8084001F051B900000FB400202D
-:1029400004B0704713B56C4684E80600031D94E894
-:10295000030083E80500012002B010BD73B585684F
-:10296000019155B11B885B0707D4D0E90036DB6BBA
-:102970009847019AC1B23046A847012002B070BD05
-:10298000F0B5866889B005460C465EB1BDF83830B2
-:102990005B070AD4D0E90037DB6B98472246C1B207
-:1029A0003846B047012009B0F0BD00220023CDE930
-:1029B00000230023ADF808300A4603AB01F10806F6
-:1029C000106851681C4603C40832B2422346F7D14E
-:1029D000106820609288A28000F0AEF90423ADF860
-:1029E00008302B68CDE900011B6C694628469847E2
-:1029F000D8E70000082817D909280CD00A280CD0DD
-:102A00000B280CD00C280CD00D280CD00E2814BF8D
-:102A10004020302070470C20704710207047142051
-:102A200070471820704720207047000010B5037CC5
-:102A3000044613B9006802F0EDFA204610BD00000C
-:102A40000023BFF35B8FC360BFF35B8FBFF35B8F6C
-:102A50008360BFF35B8F7047BFF35B8F0068BFF38A
-:102A60005B8F704770B505460C30FFF7F5FF05F139
-:102A7000080604463046FFF7EFFFA04206D930466D
-:102A80006D68FFF7E9FF2544281A70BD3046FFF74F
-:102A9000E3FF201AF9E7000070B50546406898B1D9
-:102AA00005F10800FFF7D8FF05F10C060446304693
-:102AB000FFF7D2FF8442304694BF6D680025FFF7D0
-:102AC000CBFF013C2C44201A70BD000038B50C46E9
-:102AD0000546FFF7C7FFA04210D305F10800FFF736
-:102AE000BBFF04446868B4FBF0F100FB1144BFF382
-:102AF0005B8F0120AC60BFF35B8F38BD0020FCE72B
-:102B00002DE9F041144607460D46FFF7C5FF844204
-:102B100028BF0446D4B1B84658F80C6B4046FFF7BE
-:102B20009BFF3044286040467E68FFF795FF331ACC
-:102B30009C4203D86C600120BDE8F0816B60A41B4F
-:102B40003B68AB602044E8600220F5E72046F3E7ED
-:102B500038B50C460546FFF79FFFA04210D305F19C
-:102B60000C00FFF779FF04446868B4FBF0F100FB48
-:102B70001144BFF35B8F0120EC60BFF35B8F38BD66
-:102B80000020FCE72DE9FF41884669460746FFF72C
-:102B9000B7FF6C4606B204EBC6060025B44209D066
-:102BA0006268206808EB0501FEF78EFF6368083451
-:102BB0001D44F3E729463846FFF7CAFF284604B00C
-:102BC000BDE8F081F8B505460C300F46FFF744FF2D
-:102BD00005F1080604463046FFF73EFFA0423046A6
-:102BE00088BF6C68FFF738FF201A386020B1304684
-:102BF0002C68FFF731FF2044F8BD000073B5144680
-:102C000006460D46FFF72EFF844228BF044601907A
-:102C1000DCB101A93046FFF7D5FF019B33B932681B
-:102C2000C5E90233C5E9002401200CE09C4238BF0D
-:102C300001942860019868608442F5D93368AB60DC
-:102C4000241AEC60022002B070BD2046FBE70000B1
-:102C50002DE9FF410F466946FFF7D0FF6C4600B2F1
-:102C600004EBC0050026AC4209D0D4F8048054F827
-:102C7000081BB8194246FEF727FF4644F3E73046E3
-:102C800004B0BDE8F081000038B50546FFF7E0FF6D
-:102C9000044601462846FFF719FF204638BD0000CC
-:102CA00000B59BB0EFF3098168226846FEF70CFF80
-:102CB000EFF30583044B9A6BDA6A9A6A9A6A9A6A06
-:102CC0009A6A9A6A9B6AFEE700ED00E000B59BB045
-:102CD000EFF3098168226846FEF7F6FEEFF30583FD
-:102CE000044B9A6B9A6A9A6A9A6A9A6A9A6A9B6A77
-:102CF000FEE700BF00ED00E000B59BB0EFF30981F7
-:102D000068226846FEF7E0FEEFF30583034B5A6B3B
-:102D10009A6A9A6A9A6A9A6A9B6AFEE700ED00E0EC
-:102D2000FEE700000FB408B5029801F03DFBFEE796
-:102D300001F0E4BD01F0BCBD01F0BABD30B5094DF4
-:102D40000A4491420DD011F8013B5840082340F34A
-:102D50000004013B2C4013F0FF0384EA5000F6D13D
-:102D6000EFE730BD2083B8ED2DE9F041C56915B915
-:102D7000C161BDE8F0814B6823F06047C3F38A4628
-:102D80004FEAD37EC3F3807816EA230638BF3E4667
-:102D9000AC462B465A68BEEBD27F22F060440AD084
-:102DA000002A18DAA40CB44217D19D420FD10D604D
-:102DB000DEE71346EEE7A74207D102F08044C2F3F4
-:102DC000807242450BD054B1EFE708D2EDE7CCF862
-:102DD00000100B60CDE7B44201D0B442E5D81A68C8
-:102DE0009C46002AE5D11960C3E700002DE9F047B1
-:102DF000089D01F007044FEAD508224405F00705B5
-:102E000000EBD1004FF47F49944201D1BDE8F08737
-:102E100004F0070705F0070A57453E4638BF5646F7
-:102E2000C6F10806111B8E4228BF0E46E10808EBCA
-:102E3000D50E415C13F80EC0B94029FA06F721FA05
-:102E40000AF1FFB28CEA010147FA0AF739408CEA2D
-:102E5000010C03F80EC034443544D5E780EA012064
-:102E6000082341F2210201B24000002980B203F19F
-:102E7000FF33B8BF504013F0FF03F4D17047000098
-:102E800038B50C468D18A54200D138BD14F8011B89
-:102E9000FFF7E4FFF7E7000002684AB11368036038
-:102EA000C388018901339BB29942C38038BF038133
-:102EB0001046704770B588B0202204460D4668461B
-:102EC0000021FEF713FE20460495FFF7E5FF0246BA
-:102ED00058B16B46054608AE1C4603CCB442286088
-:102EE0006960234605F10805F6D1104608B070BDAB
-:102EF000082817D909280CD00A280CD00B280CD088
-:102F00000C280CD00D280CD00E2814BF40203020E7
-:102F100070470C207047102070471420704718200D
-:102F20007047202070470000082817D90C280CD9BA
-:102F300010280CD914280CD918280CD920280CD901
-:102F400030288CBF0F200E207047092070470A20C0
-:102F500070470B2070470C2070470D207047000011
-:102F600010B54B6823B9CA8A63F30902CA8210BD3F
-:102F7000C4681A681C60C360438A013B43824A608C
-:102F8000EFE700002DE9F84F1D46CB8A0F46C3F34B
-:102F900009010629814692460B4630D00020AAB28C
-:102FA00007F119049EB2052E1FFA80F80FD890453C
-:102FB00003F1010306D3FB8A0A4462F30903FB828F
-:102FC00001201AE01AF80060E6540130EAE7904563
-:102FD000F1D2A1F1060B1C237C68BBFBF3F203FBCF
-:102FE00012BB1FFA8BF6002C45D14846FFF754FF61
-:102FF000044638B978606FF00200BDE8F88F4FF0F2
-:103000000008E6E7002606607860ADB24FF0000BDE
-:10301000454510D90AEB0803221D13F8011B9155F1
-:10302000B1B208F101081B291FFA88F82BD04545D9
-:1030300006F10106F1D8FB8AC3F30902154465F3D2
-:103040000903BCE7013292B21C462368002BF9D178
-:10305000AB1F0B441C21B3FBF1F301339BB29A422B
-:10306000D3D2BBF1000FD0D14846FFF715FF20B9EE
-:10307000C4F800B0BFE70122E7E7C0F800B05E4641
-:1030800020600446C1E74545D5D94846FFF704FF0F
-:1030900008B92060AFE7C0F800B000262060044601
-:1030A000B6E700002DE9F04F2DED028B83B0CDE99E
-:1030B0000013BDF83C5007469146002A00F092806C
-:1030C0002DB10E9B002B00F08D80072D32D807F11B
-:1030D0000C00FFF7E1FE044638B96FF00204204609
-:1030E00003B0BDEC028BBDE8F08F14220021FEF787
-:1030F000FDFC0E992A4604F10800FEF7E5FC681C69
-:10310000C0B2FFF711FFFFF7F3FE207499F800300B
-:10311000013814FA80F003F01F0363F03F030372D9
-:10312000009B43F00041616038462146FFF71CFEDA
-:103130000124D4E700F10C034FF0000808EE103A28
-:103140004FF0800A4646444618EE100AFFF7A4FEE8
-:1031500083460028C1D014220021FEF7C7FCC6BB5D
-:10316000019BABF8083002200E9B00F10802991970
-:103170005BFA82F20130C0B2082801D0AE422AD3F5
-:10318000FFF7D2FEFFF7B4FE99F80020009B411E26
-:1031900002F01F0242EA4812AE4208BF4FF0400A56
-:1031A0005BFA81F14AEA020A43F0004281F808A082
-:1031B0008BF81000CBF8042059463846FFF7D4FDB1
-:1031C0000134AE4224B288F001084FF0000ABBD1AE
-:1031D00085E70020C8E711F801CB02F801CB0136E2
-:1031E000B6B2C7E76FF0010479E70000F8B51546FD
-:1031F0000E462822002104461F46FEF777FC069B58
-:103200006360B5F5001F079BA76034BF6A094FF6DE
-:10321000FF72236204F10C0097B200239A4205D892
-:103220000023036027826382A382F8BD0660013316
-:1032300030462036F2E7000003781BB94BB2002B72
-:10324000C8BF017070470000007870472DE9F74F44
-:10325000DDF83C90BDF830500D9E9DF83840BDF82B
-:103260004070804692469B46B9F1000F01D1002F75
-:1032700051D11F2C4FD898F80000B0B9072F47D86C
-:1032800035F0030347D13A4649464FF6FF70FFF742
-:10329000F7FD20F001002D02400445EA0464400CD3
-:1032A00044EA40244FF6FF7321E040EA0520072F4F
-:1032B00040EA0464F6D900254FF6FF73C5F12000FB
-:1032C000A5F120022AFA05F10BFA00F001432BFACE
-:1032D00002F211431846C9B2FFF7C0FD0835402D70
-:1032E0000346EBD13A464946FFF7CAFD0346CDE90E
-:1032F0000097324621464046FFF7D4FE337801332B
-:10330000DBB21F2B88BF0023337003B0BDE8F08F02
-:103310006FF00300F9E76FF00100F6E72DE9F04FD9
-:1033200085B09246DDF848800F9D9DF840209DF8BD
-:103330004490BDF84C7006469B46B8F1000F01D191
-:10334000002F48D11F2A46D83378002B46D00C02D4
-:1033500044EA02649DF8381044EAC93444EA01445E
-:103360001C43072F44F0800432D900234FF6FF722C
-:10337000C3F1200CA3F120002AFA03F10BFA0CFC94
-:1033800041EA0C012BFA00F00143C9B21046039345
-:10339000FFF764FD039B0833402B0246E8D13A4611
-:1033A0004146FFF76DFD0346CDE900872A462146D9
-:1033B0003046FFF777FEB9F1010F06D12B780133C4
-:1033C000DBB21F2B88BF00232B7005B0BDE8F08F48
-:1033D0004FF6FF73E8E76FF00100F6E76FF00300C8
-:1033E000F3E70000C06900B104307047C3691A6890
-:1033F000C261C2681A60C360438A013B438270475E
-:103400002DE9F041D0F81880194E14461D4641466A
-:10341000002709B9BDE8F081D1E90223A21A65EBC2
-:103420000303964277EB03031ED283698B420DD1CF
-:10343000FFF796FD83691B688361C3680B60438A4D
-:10344000C1608169013B43828846E2E7FFF788FD5E
-:103450000B68C8F80030C3680B60438AC160013B49
-:103460004382D8F80010D4E788460968D1E700BF46
-:1034700080841E002DE9F04F8BB00D46DDF8509092
-:1034800014469B468046002800F01981B9F1000FD0
-:1034900000F01581531E3F2B00F21181012A03D148
-:1034A000BBF1000F40F00B810023CDE90833B8F8E1
-:1034B0001430B5EBC30F4FEAC30703D300200BB0A2
-:1034C000BDE8F08F2B199F42D8F80C303ABF7F1B14
-:1034D000FFB227461BB9D8F81030002B7AD02F2D19
-:1034E0004ED8C5F13006B7424FF000032CBFF6B2FC
-:1034F0003E4600932946D8F8080008AB3246FFF74D
-:1035000075FCA7EB060A35445FFA8AFAB8F814305E
-:1035100003F10053063BDB000493D8F80C3003930F
-:103520003021039B13B1BAF1000F2CD1D8F8100051
-:1035300040B1BAF1000F05D0009608AB5246691AA7
-:10354000FFF754FC38B2002FB8D066070AD00AAB98
-:1035500003EBD401624211F8083C02F00702134168
-:1035600001F8083C082C3CD9102C40F2B580202CE6
-:1035700040F2B780BBF1000F00F09C80082334E0DC
-:10358000BA460026C2E7049BE02B28BFE02306933F
-:103590000B44AB42059314D95A1B039800969245ED
-:1035A00034BF5246D2B2691A08AB04300792FFF713
-:1035B0001DFC079A1644AAEB020A1544F6B25FFAFC
-:1035C0008AFA049B069A05999B1A0493039B1B682D
-:1035D0000393A6E70093D8F8080008AB3A462946BB
-:1035E000AEE7BBF1000F13D00123B4EBC30F6CD0D7
-:1035F000082C12D89DF82030621E23FA02F2D5075B
-:1036000006D54FF0FF3202FA04F423438DF8203040
-:103610009DF8203089F8003051E7102C12D8BDF801
-:103620002030621E23FA02F2D10706D54FF0FF3296
-:1036300002FA04F42343ADF82030BDF82030A9F895
-:1036400000303CE7202C0FD80899631E21FA03F3C1
-:10365000DA0705D54FF0FF3202FA04F40C43089460
-:10366000089BC9F800302AE7402C2BD0DDE908651B
-:10367000611EC4F12102A4F1210326FA01F105FA29
-:1036800002F225FA03F311431943CB0712D50122A5
-:10369000A4F12003C4F1200102FA03F322FA01F19C
-:1036A000A240524243EA010363EB430332432B43FC
-:1036B000CDE90823DDE90823C9E90023FFE66FF01F
-:1036C0000100FCE66FF00800F9E6082CA0D9102CE8
-:1036D000B3D9202CEED8C3E7BBF1000FADD0022345
-:1036E00083E7BBF1000FBBD004237EE730B5012A8E
-:1036F000144638BF0124402C85B028BF4024002543
-:10370000012ACDE9025518D81B788DF808306307D7
-:103710000AD004AB03EBD405624215F8083C02F072
-:103720000702934005F8083C009103462246002119
-:1037300002A8FFF75BFB05B030BD082AE4D9102AC8
-:1037400003D81B88ADF80830E1E7202A8DBFD3E904
-:1037500000231B680293CDE90223D8E710B5CB689C
-:103760001BB98B600B618B8210BDC4681A681C602A
-:10377000C360438A013B4382CA60F0E72DE9F04F02
-:10378000D1F8008093B018F0800FCDE90323C8F37F
-:10379000C01219BFC8F3C03BC8F306264FF0020B96
-:1037A0001646B8F1000F04460D4680F2D18118F09C
-:1037B000C043059340F0CC810B7B002B00F0C88107
-:1037C000BBF1020F03D00178B14240F0C48108F090
-:1037D0007F0106916AB3C8F3074A2B44069A93F80F
-:1037E0000390760646EA0B4646EA82465FEAD9131C
-:1037F00046EA0A06079300F0908000220023CDE9F4
-:103800000A23069B009367685B4652460AA9204636
-:10381000B84700287ED0A7699FB9314604F10C0053
-:10382000FFF748FB0746E0B96FF0020013B0BDE8B0
-:10383000F08FC8F30F2A18F07F0F08BF0AF0030AB1
-:10384000CBE73B699E420DD03F68002FF9D131464E
-:1038500004F10C00FFF72EFB07460028E4D0A36913
-:103860003B60A761DDE90A2300264FF6FF70C6F131
-:10387000200E22FA06F103FA0EFEA6F1200C23FA1E
-:103880000CFC41EA0E0141EA0C01C9B2083609926A
-:103890000893FFF7E3FA402EDDE90832E7D1B8825A
-:1038A000FB7D09F01F06C3F384039B1BD7E90221AC
-:1038B00098B2002BBCBF00F120031BB252EA0100FA
-:1038C000C8F304680FD00398821A049860EB0101D2
-:1038D000A74890424FF000028A4104D3079A002A79
-:1038E0005BD0012B23DDFA7D4FEA890302F003024E
-:1038F00003F07C031343FB7539462046FFF730FB8A
-:10390000079BA3B9FB7DC3F38402013262F38603F4
-:10391000FB7504E06FF00B0088E7A76917B96FF03B
-:103920000C0083E73B699E42BAD03F68F6E719F086
-:10393000400F32D0039BBB60049BFB60142200212C
-:103940000DA8FEF7D3F8039B0A93049B0B932B1D42
-:103950000C932B7BADF83EA0013BDBB2ADF83C30C5
-:10396000069B8DF8433094F824308DF840B083F0F6
-:1039700001038DF844308DF84160A3688DF84280D2
-:103980000AA920469847FB7DC3F38403013303F063
-:103990001F039B02FB82002048E7FB7DC9F3401216
-:1039A000B2EBD31F40F0DA80C3F38403B34240F09C
-:1039B000D88007992B7B4FEA9912002934D0D2077F
-:1039C00041D4032B40F2D080039BBB60049BFB607F
-:1039D0002B7BAE1D033BDBB23246394604F10C00B3
-:1039E000FFF7D0FA00280DDA20463946FFF7B8FA7B
-:1039F000FB7DC3F38403013303F01F039B02FB82AF
-:103A0000032013E7AB883B832A7B033AB88AD2B200
-:103A10003146FFF735FAFB7DB882DA43C2F3C012B4
-:103A200062F3C713FB75B6E76AB92E1D013BDBB223
-:103A30003246394604F10C00FFF7A4FA0028D3DB24
-:103A40002A7B013AE2E7F98AC1F30901013B052922
-:103A5000DAB259D8281D002307F11A0C9A4208D966
-:103A600010F801EB0CF801E0013101330629DBB25B
-:103A7000F4D103990A9104990B91934207F11A0129
-:103A80000C9138BF043379680D9134BF55FA83F334
-:103A900000230E93FB8AADF83EA0C3F309031A443A
-:103AA000069B8DF8433094F82430ADF83C2083F029
-:103AB00001038DF8443000238DF840B08DF841604B
-:103AC0008DF842807B602A7BB88A013A291DFFF776
-:103AD000D7F93B8BB882834203D1A3680AA9204659
-:103AE000984720460AA9FFF739FEFB7DB88AC3F341
-:103AF0008403013303F01F039B02FB823B8B98423C
-:103B000014BF1120002091E67B68002BB1D0062065
-:103B100001E01C306346D3F800C0BCF1000FF8D1BF
-:103B2000091A081D05F1040C00EB030905989DF81E
-:103B3000143001EB000EBEF11B0F9AD89A4298D9AF
-:103B40001CF8013B09F8013B059B01330593EDE7A8
-:103B50006FF009006AE66FF00A0067E66FF00D008B
-:103B600064E66FF00E0061E66FF00F005EE600BFE6
-:103B700080841E00EFF3098305494A6B22F001029D
-:103B80004A63683383F30988002383F311887047FD
-:103B900000EF00E0202080F3118862B60C4B0D4A44
-:103BA000D96821F4E0610904090C0A43DA60D3F80A
-:103BB000FC20094942F08072C3F8FC200A6842F0F8
-:103BC00001020A601022DA7783F82200704700BFF2
-:103BD00000ED00E00003FA05001000E010B520231E
-:103BE00083F311880E4B5B6813F4006314D0F1EE7D
-:103BF000103AEFF30984683C4FF08073E361094B9E
-:103C0000DB6B236684F3098800F080FB10B1064B60
-:103C1000A36110BD054BFBE783F31188F9E700BFF3
-:103C200000ED00E000EF00E04B0600084E06000843
-:103C3000026843681143016003B1184770470000F0
-:103C4000024A136843F0C003136070470044004009
-:103C500013B50E4C204600F09BFA04F114000C49F9
-:103C6000009400234FF4807200F05CF9094B0A497C
-:103C700000944FF4807204F1380000F0D5F9074A3F
-:103C8000074BC4E9172302B010BD00BF985F0020A6
-:103C900004600020413C0008046100200044004012
-:103CA000007A030A30B5037C214C002918BF0C466A
-:103CB000012B0CD11F4B984209D11F4B9A6D42F436
-:103CC00000329A659A6F42F400329A679B6F2268BD
-:103CD000036EC16D846603EB5203B3FBF2F36268BB
-:103CE000150442BF23F0070503F0070343EA450329
-:103CF000CB60A36843F040034B60E36843F00103EB
-:103D00008B6042F4967343F001030B604FF0FF3376
-:103D10000B62510505D512F0102205D0B2F1805F7B
-:103D200004D080F8643030BD7F23FAE73F23F8E702
-:103D300084520008985F0020001002402DE9F047EF
-:103D4000C66D3768F46934622107054618D014F04F
-:103D5000080118BF8021E20748BF41F02001A307F6
-:103D600048BF41F04001600748BF41F48071202303
-:103D700083F31188281DFFF75BFF002383F311886D
-:103D8000E2050AD5202383F311884FF40071281D22
-:103D9000FFF74EFF002383F311884FF020094FF007
-:103DA000000A14F0200838D13B0616D54FF0200940
-:103DB00005F1380A200610D589F31188504600F025
-:103DC00067F9002836DA0821281DFFF731FF27F0B0
-:103DD00080033360002383F31188790614D56206CB
-:103DE00012D5202383F31188D5E913239A4208D1F1
-:103DF0002B6C33B11021281D27F04007FFF718FF67
-:103E00003760002383F31188E30618D5AA6E13697F
-:103E1000ABB1BDE8F0475069184789F31188736A60
-:103E200095F864102846194000F0CCF98AF31188FF
-:103E3000F469B6E7B06288F31188F469BAE7BDE8BF
-:103E4000F087000000F1604303F561430901C9B246
-:103E500083F80013012200F01F039A4043099B00DE
-:103E600003F1604303F56143C3F880211A60704792
-:103E7000F8B5154682680669AA420B46816938BFC3
-:103E80008568761AB54204460BD218462A46FDF7D5
-:103E90001BFEA3692B44A361A3685B1BA360284698
-:103EA000F8BD0CD918463246FDF70EFEAF1BE1688F
-:103EB0003A463044FDF708FEE3683B44EBE718461A
-:103EC0002A46FDF701FEE368E5E7000083689342B8
-:103ED000F7B51546044638BF8568D0E90460361A40
-:103EE000B5420BD22A46FDF7EFFD63692B446361AF
-:103EF000A36828465B1BA36003B0F0BD0DD9324612
-:103F00000191FDF7E1FD0199E068AF1B3A463144AC
-:103F1000FDF7DAFDE3683B44E9E72A46FDF7D4FD07
-:103F2000E368E4E710B50A440024C361029B84609F
-:103F3000C0E90000C0E90511C1600261036210BD63
-:103F400008B5D0E90532934201D1826882B982680E
-:103F5000013282605A1C42611970D0E904329A42DF
-:103F600024BFC3684361002100F0A0FA002008BD0F
-:103F70004FF0FF30FBE7000070B5202304460E46EB
-:103F800083F31188A568A5B1A368A269013BA3606A
-:103F9000531CA36115782269934224BFE368A3618F
-:103FA000E3690BB120469847002383F31188284624
-:103FB00007E03146204600F069FA0028E2DA85F38E
-:103FC000118870BD2DE9F74F04460E4617469846F6
-:103FD000D0F81C904FF0200A8AF311884FF0000BA4
-:103FE000154665B12A4631462046FFF741FF034694
-:103FF00060B94146204600F049FA0028F1D000237C
-:1040000083F31188781B03B0BDE8F08FB9F1000F7E
-:1040100003D001902046C847019B8BF31188ED1A0D
-:104020001E448AF31188DCE7C0E90511C160C36151
-:104030001144009B8260C0E9000001610362704787
-:10404000F8B504460D461646202383F31188A76869
-:10405000A7B1A368013BA36063695A1C62611D702C
-:10406000D4E904329A4224BFE3686361E3690BB187
-:1040700020469847002080F3118807E0314620460B
-:1040800000F004FA0028E2DA87F31188F8BD000096
-:10409000D0E905239A4210B501D182687AB98268C5
-:1040A000013282605A1C82611C7803699A4224BFE3
-:1040B000C3688361002100F0F9F9204610BD4FF07C
-:1040C000FF30FBE72DE9F74F04460E4617469846AA
-:1040D000D0F81C904FF0200A8AF311884FF0000BA3
-:1040E000154665B12A4631462046FFF7EFFE0346E6
-:1040F00060B94146204600F0C9F90028F1D00023FC
-:1041000083F31188781B03B0BDE8F08FB9F1000F7D
-:1041100003D001902046C847019B8BF31188ED1A0C
-:104120001E448AF31188DCE702684368114301608A
-:1041300003B11847704700001430FFF743BF000079
-:104140004FF0FF331430FFF73DBF00003830FFF76A
-:10415000B9BF00004FF0FF333830FFF7B3BF0000A6
-:104160001430FFF709BF00004FF0FF311430FFF7A4
-:1041700003BF00003830FFF763BF00004FF0FF328D
-:104180003830FFF75DBF000000207047FFF760BDCB
-:10419000044B03600023C0E902334360012303742E
-:1041A000704700BF9C52000810B52023044683F3DB
-:1041B0001188FFF777FD02232374002383F311880E
-:1041C00010BD000038B5C36904460D461BB9042173
-:1041D0000844FFF7A9FF294604F11400FFF7B0FED9
-:1041E000002806DA201D4FF48061BDE83840FFF753
-:1041F0009BBF38BD024B0022C3E900339A60704771
-:1042000004620020002303748268054B1B689968D0
-:104210009142FBD25A680360426010605860704758
-:104220000462002008B5202383F31188037C032B4C
-:1042300005D0042B0DD02BB983F3118808BD436939
-:1042400000221A604FF0FF334361FFF7DBFF0023CA
-:10425000F2E7D0E9003213605A60F3E700230374F9
-:104260008268054B1B6899689142FBD85A680360C5
-:10427000426010605860704704620020054B196965
-:104280000874186802681A60536018610123037487
-:10429000FCF7C6B90462002030B54B1C0B4D87B04B
-:1042A000044610D02B690A4A01A800F019F92046EB
-:1042B000FFF7E4FF049B13B101A800F04DF92B694F
-:1042C000586907B030BDFFF7D9FFF8E70462002056
-:1042D0002542000838B50C4D41612B6981689A6808
-:1042E0009142044603D8BDE83840FFF78BBF18461B
-:1042F000FFF7B4FF01232C61014623742046BDE87B
-:104300003840FCF78DB900BF04620020044B1A68E6
-:104310001B6990689B68984294BF002001207047F9
-:104320000462002010B5084C236820691A682260D6
-:104330005460012223611A74FFF790FF014620693F
-:10434000BDE81040FCF76CB90462002008B5FFF727
-:10435000DDFF18B1BDE80840FFF7E4BF08BD00006D
-:10436000FFF7E0BFFEE7000010B50C4CFFF742FF7F
-:1043700000F0A8F80A498022204600F03DF8012309
-:1043800044F8180C0374FFF705FC002383F311882D
-:1043900062B60448BDE8104000F04EB82C62002020
-:1043A000C4520008D452000808B572B6034B5862D4
-:1043B00000F06EFA00F022FBFEE700BF046200206E
-:1043C00000F004B9EFF3118020B9EFF30583202248
-:1043D00082F311887047000010B530B9EFF30584FF
-:1043E000C4F3080414B180F3118810BDFFF7AEFFC9
-:1043F00084F31188F9E7000082600222028270478C
-:104400008368A3F17C0243F80C2C026943F83C2C2E
-:10441000426943F8382C074A43F81C2CC26843F819
-:10442000102C022203F8082C002203F8072CA3F119
-:10443000180070473906000810B5202383F311884F
-:10444000FFF7DEFF00210446FFF744FF002383F35C
-:104450001188204610BD0000024B1B6958610F20D7
-:10446000FFF70CBF04620020202383F31188FFF7BD
-:10447000F3BF000008B50146202383F3118808200C
-:10448000FFF70AFF002383F3118808BD49B1064BEB
-:1044900042681B6918605A60136043600420FFF78C
-:1044A000FBBE4FF0FF307047046200200368984263
-:1044B00006D01A680260506059611846FFF7A2BE24
-:1044C00070470000054B03F11402C3E905224FF0C9
-:1044D000FF310022C3E90712704700BF04620020C9
-:1044E00070B51C4EC0E9032305460C4600F000FBE6
-:1044F000334653F8142F9A420DD13062C5E9012496
-:104500002A600A2C2CBF00190A30C6E90555BDE8FF
-:10451000704000F0DBBA316A431AE31838BF1C461A
-:104520009368A34202D9081900F0DEFA73699A6809
-:1045300094420CD85A68AC602B606A6015609A6827
-:104540005D60121B9A604FF0FF33F36170BD1B6812
-:10455000A41AECE70462002038B51B4C636998424A
-:104560000DD0D0E9003213605A6000228168C26029
-:104570009A680A449A604FF0FF33E36138BD2246DF
-:10458000036842F8143F002193425A60C16003D18E
-:10459000BDE8384000F0A2BA9A688168256A0A44EA
-:1045A0009A6000F0A5FA63699A68411B8A42E5D9CE
-:1045B000AB181D1A092D206A98BF01F10A02BDE847
-:1045C0003840104400F090BA046200202DE9F04118
-:1045D000184C002704F11406656900F089FA236A73
-:1045E000AA68C11A8A4215D813442362D5E9003259
-:1045F00013605A606369D5F80C80EF60B34201D153
-:1046000000F06CFA87F311882869C047202383F3F0
-:104610001188E1E76169B14209D013441B1ABDE872
-:10462000F0410A2B2CBFC0180A3000F05DBABDE87B
-:10463000F08100BF0462002000207047FEE7000008
-:10464000704700004FF0FF3070470000BFF34F8FFE
-:10465000024A1369DB03FCD4704700BF002002400C
-:1046600008B5094B1B7873B9FFF7F0FF074B5A6980
-:10467000002ABFBF064A9A6002F188329A601A681F
-:1046800022F480621A6008BDD0630020002002403E
-:104690002301674508B50B4B1B7893B9FFF7D6FF8D
-:1046A000094B5A6942F000425A611A6842F480523A
-:1046B0001A601A6822F480521A601A6842F4806202
-:1046C0001A6008BDD063002000200240FF289ABF76
-:1046D00000F58030C0020020704700004FF40060F9
-:1046E000704700004FF4807070470000FF2808B545
-:1046F0000BD8FFF7EBFF00F500630268013204D12D
-:1047000004308342F9D1012008BD0020FCE70000FD
-:10471000FF2838B5044626D8FFF754FEFFF796FF6A
-:10472000FFF79EFF114BF3221A6102225A615A6968
-:1047300042EAC4025A615A6942F480325A6105461B
-:104740002046FFF783FF4FF40061FFF7BFFF00F043
-:1047500051F92846FFF79EFFFFF73EFE2046BDE8D1
-:104760003840FFF7C3BF002038BD00BF0020024023
-:1047700040EA020313F007032DE9F04705460C4613
-:10478000164606D0324B40F2FB221A600020BDE8EC
-:10479000F08781182F4A91420CD92D4A4FF440716D
-:1047A0001160F3E72B1D1B686268934208D1083E35
-:1047B00008350834072E19D92A6823689A42F1D09F
-:1047C000FFF700FEFFF74CFFFFF740FF04F1080181
-:1047D000214C4FF001084FF00009012EA1F108070C
-:1047E00008D8FFF757FFFFF7F7FD01E0002EE7D1EC
-:1047F0000120CCE7C4F81480AA4651F8083C4AF8D6
-:10480000043B51F8043C6B60FFF720FFC4F81490A0
-:104810002A6851F8083C9A420ED00D4B40F22632DD
-:104820001A600E4B1D600E4B1E600E4B1F60FFF793
-:1048300031FFFFF7D1FDA9E7DAF800A051F8043CF9
-:104840009A4501F10801E8D1083E0835C5E700BFE7
-:10485000CC6300200000080800200240C063002054
-:10486000C8630020C4630020084908B50B7828B14C
-:104870001BB9FFF7F5FE01230B7008BD002BFCD020
-:10488000BDE808400870FFF705BF00BFD0630020F7
-:1048900008B54FF4C0314FF0005000F0ADF8BDE85E
-:1048A00008404FF400414FF0805000F0A5B80000E0
-:1048B00070B582B0FFF786FD0E4E054600F018F980
-:1048C0003268904237BF0C4A0B49516814682EBFBA
-:1048D000D1E90041013151600419034641F1000161
-:1048E000284601913360FFF777FD0199204602B019
-:1048F00070BD00BFD4630020D863002070B582B0C3
-:10490000FFF760FD104E054600F0F2F83268904265
-:1049100037BF0E4A0D49516814682EBFD1E90041D6
-:1049200001315160041941F100010346284601910B
-:104930003360FFF751FD01994FF47A72002320464E
-:10494000FBF756FC02B070BDD4630020D863002092
-:104950000244D2B2904200D17047431C800000F163
-:10496000804000F51450006841F8040BD8B2F1E71C
-:10497000124B10B5D3F89040240409D4D3F89040DA
-:10498000C3F89040D3F8904044F40044C3F89040FA
-:104990000B4C2368024443F480732360D2B29042EC
-:1049A00000D110BD431C800000F1804000F5145080
-:1049B00051F8044B0460D8B2F1E700BF0010024088
-:1049C0000070004007B5012201A90020FFF7C0FFD9
-:1049D000019803B05DF804FB13B50446FFF7F2FF3E
-:1049E000A04205D0012201A900200194FFF7C0FFD9
-:1049F00002B010BD70470000704700007047000013
-:104A0000074B45F255521A6002225A6040F6FF7277
-:104A10009A604CF6CC421A60024B01221A70704721
-:104A200000300040E4630020034B1B781BB1034BB4
-:104A30004AF6AA221A607047E46300200030004062
-:104A4000054B1A6832B902F1804202F50432D2F8FD
-:104A500094201A60704700BFE0630020024B4FF4BF
-:104A60000002C3F8942070470010024008B5FFF719
-:104A7000E7FF024B1868C0F3407008BDE0630020F8
-:104A800070470000FEE700000A4B0B480B4A9042BB
-:104A90000BD30B4BDA1C121AC11E22F003028B42FD
-:104AA00038BF00220021FDF721B853F8041B40F85D
-:104AB000041BECE74454000870640020706400207C
-:104AC000706400207047000000F078B84FF0804319
-:104AD000002258631A610222DA6070474FF0804367
-:104AE0000022DA60704700004FF08043586370473F
-:104AF0004FF08043586A70474B6843608B6883600F
-:104B0000CB68C3600B6943614B6903628B69436285
-:104B10000B6803607047000008B5204BDA6A42F06A
-:104B20007F02DA62DA6A22F07F02DA62DA6ADA6C2B
-:104B300042F07F02DA64DA6E42F07F02DA66184AE7
-:104B4000DB6E11464FF09040FFF7D6FF02F11C01DB
-:104B500000F58060FFF7D0FF02F1380100F58060BA
-:104B6000FFF7CAFF02F1540100F58060FFF7C4FFB0
-:104B700002F1700100F58060FFF7BEFF02F18C01C9
-:104B800000F58060FFF7B8FF02F1A80100F5806032
-:104B9000FFF7B2FFBDE8084000F064B80010024023
-:104BA000EC52000808B500F003FAFFF7DDFBBDE8A2
-:104BB0000840FFF745BF0000704700000F4B9A6D9B
-:104BC00042F001029A659A6F42F001029A670C4A1C
-:104BD0009B6F936843F0010393604FF08043A722DB
-:104BE0009A624FF0FF32DA6200229A615A63DA6009
-:104BF0005A6001225A611A60704700BF00100240DB
-:104C0000002004E04FF0804208B51169D3680B40E2
-:104C1000D9B2C9439B07116107D5202383F31188BB
-:104C2000FFF7CEFB002383F3118808BD08B50B4BBB
-:104C3000D3F8902012F4407F1FBF4FF48032C3F8A6
-:104C400090200022C3F89020D3F89020C3F8902041
-:104C500000F086F9024B00225A6008BD00100240A5
-:104C600000700040484B4FF0FF319A6A99629A6A8F
-:104C700000229A62986AD86A60F07F00D862D86A87
-:104C800000F07F00D862D86A186B1963186B1A633A
-:104C9000186B986B9963986B9A63986BD86BD96310
-:104CA000D86BDA63D86B186C1964196C1A641A6CB7
-:104CB0009A6D42F080529A659A6F22F080529A67FC
-:104CC0009A6F324A4FF400711160516911F480619A
-:104CD000FBD14FF40040516090604FF48070D16080
-:104CE000C2F88000116251629162D1621163516316
-:104CF0009163D163116451649164D164116551650C
-:104D0000D3F8982042F00102C3F89820D3F89820F5
-:104D10009007FBD51A6842F480321A601A68910332
-:104D2000FCD51A490A6842F480720A60184ADA60AF
-:104D30001A6842F080721A601A689201FCD500224B
-:104D400014499A60C3F888101349C3F89C20134A89
-:104D50000A600A6802F00F02042AFAD19A6842F047
-:104D600003029A609A6802F00C020C2AFAD11A6EB9
-:104D700042F001021A66D3F8802042F00102C3F823
-:104D80008020D3F88030704700100240007000404F
-:104D9000132A61015501005000200240040704005D
-:104DA000074A08B5536903F00103536123B1054A6B
-:104DB00013680BB150689847BDE80840FEF70EBF76
-:104DC00000040140E8630020074A08B5536903F076
-:104DD0000203536123B1054A93680BB1D068984729
-:104DE000BDE80840FEF7FABE00040140E863002079
-:104DF000074A08B5536903F00403536123B1054A18
-:104E000013690BB150699847BDE80840FEF7E6BE4C
-:104E100000040140E8630020074A08B5536903F025
-:104E20000803536123B1054A93690BB1D0699847D0
-:104E3000BDE80840FEF7D2BE00040140E863002050
-:104E4000074A08B5536903F01003536123B1054ABB
-:104E5000136A0BB1506A9847BDE80840FEF7BEBE22
-:104E600000040140E8630020164B10B55C6904F4AF
-:104E700078725A61A30604D5134A936A0BB1D06ABB
-:104E80009847600604D5104A136B0BB1506B9847D6
-:104E9000210604D50C4A936B0BB1D06B9847E20501
-:104EA00004D5094A136C0BB1506C9847A30504D57F
-:104EB000054A936C0BB1D06C9847BDE81040FEF7E3
-:104EC0008DBE00BF00040140E8630020194B10B5FF
-:104ED0005C6904F47C425A61620504D5164A136D7C
-:104EE0000BB1506D9847230504D5134A936D0BB150
-:104EF000D06D9847E00404D50F4A136E0BB1506E85
-:104F00009847A10404D50C4A936E0BB1D06E984714
-:104F1000620404D5084A136F0BB1506F98472304FD
-:104F200004D5054A936F0BB1D06F9847BDE8104088
-:104F3000FEF754BE00040140E863002008B50348B2
-:104F4000FEF7FCFEBDE80840FEF748BE985F002073
-:104F500008B5FFF757FEBDE80840FEF73FBE00006A
-:104F6000062108B50846FEF76DFF06210720FEF76B
-:104F700069FF06210820FEF765FF06210920FEF7DC
-:104F800061FF06210A20FEF75DFF06211720FEF7CC
-:104F900059FF06212820FEF755FF07211C20FEF7A8
-:104FA00051FFBDE808400C212620FEF74BBF000052
-:104FB00008B5FFF73BFE00F009F8FFF7E7F8FFF749
-:104FC000FBFDBDE80840FFF77FBD00000023054A58
-:104FD00019460133102BC2E9001102F10802F8D181
-:104FE000704700BFE86300200B460146184600F0FA
-:104FF00003B8000000F00EB810B5054C13462CB1F4
-:105000000A4601460220AFF3008010BD2046FCE7AF
-:1050100000000000024B0146186800F035B800BFE0
-:105020002823002010B501390244904201D100200C
-:1050300005E0037811F8014FA34201D0181B10BD01
-:105040000130F2E72DE9F041A3B1C91A1778014404
-:10505000044603F1FF3C8C42204601D9002009E0C0
-:105060000578BD4204F10104F5D10CEB0405D61816
-:10507000A54201D1BDE8F08115F8018D16F801EDCA
-:10508000F045F5D0E7E7000037B5002944D051F8E6
-:10509000043C0190002BA1F10404B8BFE41800F017
-:1050A00047F81E4A0198136833B96360146003B06F
-:1050B000BDE8304000F042B8A34208D92568611924
-:1050C0008B4201BF19685B6849192160EDE71A46F8
-:1050D0005B680BB1A342FAD911685518A5420BD1F0
-:1050E000246821445418A3421160E0D11C685B6815
-:1050F000536021441160DAE702D90C230360D6E73C
-:10510000256861198B4204BF19685B68636004BF3E
-:10511000491921605460CAE703B030BD68640020BB
-:10512000034611F8012B03F8012B002AF9D170472F
-:10513000014800F009B800BF6C640020014800F08D
-:1051400005B800BF6C640020704700007047000085
-:105150006F72672E6172647570696C6F742E486F20
-:105160006C7962726F47345F475053004E6F206115
-:105170007070207369670A00426164206677206C52
-:10518000656E6774682025750A0042616420626F4D
-:105190006172645F69642025752073686F756C6443
-:1051A0002062652025750A004261642066772064CC
-:1051B000657363726970746F72206C656E67746872
-:1051C0002025750A004261642061707020435243BB
-:1051D000203078253038783A3078253038782030CB
-:1051E00078253038783A3078253038780A00476F9B
-:1051F0006F64206669726D776172650A0040A2E48F
-:10520000F16468910600000053544D333247343F37
-:105210003F0000004261642043414E49666163657E
-:1052200020696E6465782E00000100000001FF0017
-:105230000064004000680040000000000000000022
-:1052400021210008FD1B000839280008F11B000877
-:105250006D1C0008891E0008E51D0008351C0008AB
-:10526000391C0008F51B0008111C0008F91B000878
-:10527000491E00081D1C000845290008291C0008BB
-:105280001D1E000800960000000000000000000045
-:10529000000000000000000000000000000000000E
-:1052A00055410008414100087D410008694100085E
-:1052B00075410008614100084D410008394100086E
-:1052C000894100086D61696E0000000069646C65C9
-:1052D00000000000CC52000848620020C06300209B
-:1052E000010000006543000800000000A000802AC3
-:1052F00000000000AAAAAAAA50000024FFFF000094
-:1053000000770000009009000400005A000000002F
-:10531000AAAAAA9A04000000FFBF00000000000033
-:10532000000099000011101400000000AAAAAAA60B
-:1053300000010010FFDF000000000000000000007E
-:105340000000000000000000AAAAAAAA00000000B5
-:10535000FFFF00000000000000000000000000004F
-:1053600000000000AAAAAAAA00000000FFFF000097
-:10537000000000000000000000000000000000002D
-:10538000AAAAAAAA00000000FFFF00000000000077
-:10539000000000000000000000000000AAAAAAAA65
-:1053A00000000000FFFF00000000000000000000FF
-:1053B00070AEFF7F010000001D040000000000002F
-:1053C0000070070000000000FE2A0100D204000067
-:1053D000FF00000000000000085200083F0000002D
-:1053E0002C2300200000000000000000000000004E
-:1053F00000000000000000000000000000000000AD
-:10540000000000000000000000000000000000009C
-:10541000000000000000000000000000000000008C
-:10542000000000000000000000000000000000007C
-:10543000000000000000000000000000000000006C
-:045440000000000068
+:1004F000704700BF02E000F000F8FEE772B6374830
+:1005000080F30888364880F3098836483649086001
+:1005100040F20000CCF200004EF63471CEF2000141
+:100520000860BFF34F8FBFF36F8F40F20000C0F23F
+:10053000F0004EF68851CEF200010860BFF34F8FF5
+:10054000BFF36F8F4FF00000E1EE100A4EF63C71E2
+:10055000CEF200010860062080F31488BFF36F8F8D
+:1005600004F0CAFB04F05CFC4FF055301F491B4AF5
+:1005700091423CBF41F8040BFAE71D49184A9142E9
+:100580003CBF41F8040BFAE71A491B4A1B4B9A423D
+:100590003EBF51F8040B42F8040BF8E7002018495D
+:1005A000184A91423CBF41F8040BFAE704F0A8FB5B
+:1005B00004F07CFC144C154DAC4203DA54F8041BD7
+:1005C0008847F9E700F042F8114C124DAC4203DACB
+:1005D00054F8041B8847F9E704F090BB000700209B
+:1005E000002300200000000808ED00E000010020CA
+:1005F0000007002060550008002300208C23002005
+:100600009023002028650020E0010008E401000894
+:10061000E4010008E40100082DE9F04F2DED108AF7
+:10062000C1F80CD0C3689D46BDEC108ABDE8F08FC0
+:10063000002383F311882846A047002003F0D8FF49
+:10064000FEE703F03BFF00DFFEE70000F8B504F033
+:10065000F5FA074604F046FB0546B8BB204B9F421F
+:1006600034D001339F4234D01E4B27F0FF029A4210
+:1006700032D1F8B200F052FE2E4642F2107400F071
+:1006800053FE08B10024264601F0D6FA20B103201B
+:1006900000F07CF80024264635B1134B9F4203D06E
+:1006A00004F018FB00242646002004F0D1FA0EB115
+:1006B00000F082F801F08AF900F05AFE01F07AF8B1
+:1006C000204600F0D1F800F077F8F9E72E46002434
+:1006D000D5E704460126D2E7064640F6C414CEE725
+:1006E000010007B0000008B0263A09B008B501F0D3
+:1006F0002DF8A0F120035842584108BD07B541F23A
+:100700001203022101A8ADF8043001F03DF803B056
+:100710005DF804FB38B5302383F31188174803686C
+:100720000BB104F023F8164A144800234FF47A71F1
+:1007300004F012F8002383F31188124C236813B1DC
+:100740002368013B2360636813B16368013B636006
+:100750000D4D2B7833B963687BB9022001F0C4F8E2
+:10076000322363602B78032B07D163682BB90220F7
+:1007700001F0BAF84FF47A73636038BD902300201B
+:1007800015070008B0240020A8230020084B18708B
+:1007900003280CD8DFE800F008050208022001F069
+:1007A00099B8022001F08CB8024B00225A607047C1
+:1007B000A8230020B024002010B501F03DFA30B18C
+:1007C000234B03221A70234B00225A6010BD224B88
+:1007D000224A1C4619680131F8D004339342F9D1FA
+:1007E0006268A242F2D31E4B9B6803F1006303F5DB
+:1007F00010439A42EAD204F03FFA04F051FA002082
+:1008000000F0F2FF0220FFF7C1FF164B9A6D0022A5
+:100810009A65996F9A67996FD96DDA65D96FDA67BA
+:10082000D96F196E1A66D3F88010C3F88020D3F8F8
+:10083000803072B64FF0E0233021C3F8084DD4E980
+:10084000003281F311889D4683F308881047BDE785
+:10085000A8230020B0240020009000082090000869
+:1008600000230020001002402DE9F04F93B0AC4B64
+:1008700000902022FF210AA89D6801F051F8A94AA2
+:100880001378A3B9A848012103601170302383F3C2
+:10089000118803680BB103F069FFA44AA248002342
+:1008A0004FF47A7103F058FF002383F31188009B03
+:1008B00013B19F4B009A1A609E4A009C1378032B39
+:1008C0001EBF002313709A4A4FF0000A18BF5360EE
+:1008D000D3465646D146012000F0FCFF24B1944B8C
+:1008E0001B68002B00F01582002000F02FFF039002
+:1008F000039B002B01DA00F08FFD039B002BEDDB47
+:10090000012000F0DDFF039B213B162BE3D801A261
+:1009100052F823F071090008990900082D0A00080F
+:10092000D7080008D7080008D7080008B70A000849
+:10093000870C0008A10B0008030C00082B0C000812
+:10094000510C0008D7080008630C0008D7080008FD
+:10095000D50C0008110A0008D7080008190D000876
+:100960007D090008110A0008D7080008030C0008D8
+:100970000220FFF7BBFE002840F0F581009B02211A
+:10098000BAF1000F08BF1C4605A841F21233ADF8BA
+:10099000143000F0F9FE9EE74FF47A7000F0D6FEB6
+:1009A000071EEBDB0220FFF7A1FE0028E6D0013F87
+:1009B000052F00F2DA81DFE807F0030A0D10133685
+:1009C00005230593042105A800F0DEFE17E0544836
+:1009D0000421F9E758480421F6E758480421F3E7D1
+:1009E0004FF01C08404600F001FF08F10408059094
+:1009F000042105A800F0C8FEB8F12C0FF2D10120A7
+:100A000000FA07F747EA0B0B5FFA8BFB4FF0000980
+:100A100000F0D2FF26B10BF00B030B2B08BF002414
+:100A2000FFF76CFE57E746480421CDE7002EA5D01E
+:100A30000BF00B030B2BA1D10220FFF757FE07464B
+:100A400000289BD0012000F0CFFE0220FFF79EFE81
+:100A500000265FFA86F8404600F0D6FE044690B1C4
+:100A60000021404600F0E0FE01360028F1D1BA46F0
+:100A7000044641F21213022105A8ADF814303E4697
+:100A800000F082FE27E70120FFF780FE2546244B79
+:100A90009B68AB4207D9284600F0A8FE013040F021
+:100AA00067810435F3E7234B00251D70204BBA46C0
+:100AB0005D603E46ACE7002E3FF460AF0BF00B03E9
+:100AC0000B2B7FF45BAF0220FFF760FE322000F0BB
+:100AD0003DFEB0F10008FFF651AF18F003077FF4B8
+:100AE0004DAF0F4A926808EB050393423FF646AFBD
+:100AF000B8F5807F3FF742AF124B0193B84523DD35
+:100B00004FF47A7000F022FE0390039A002AFFF659
+:100B100035AF019B039A03F8012B0137EDE700BFC6
+:100B200000230020AC24002090230020150700089B
+:100B3000B0240020A8230020042300200823002044
+:100B40000C230020AC230020C820FFF7CFFD074670
+:100B500000283FF413AF1F2D11D8C5F120024245E4
+:100B60000AAB25F0030028BF42468349019218448E
+:100B700000F0C4FE019A8048FF2100F0D1FE4FEA48
+:100B8000A8037D490193C8F38702284600F0D0FEF0
+:100B9000064600283FF46DAF019B05EB830537E760
+:100BA0000220FFF7A3FD00283FF4E8AE00F04EFE60
+:100BB00000283FF4E3AE0027B846704B9B68BB4269
+:100BC00018D91F2F11D80A9B01330ED027F0030329
+:100BD00012AA134453F8203C05934046042205A969
+:100BE00001F014F804378046E7E7384600F0FEFDD0
+:100BF0000590F2E7CDF81480042105A800F0C4FDAB
+:100C000006E70023642104A8049300F0B3FD002844
+:100C10007FF4B4AE0220FFF769FD00283FF4AEAECA
+:100C2000049800F009FE0590E6E70023642104A87B
+:100C3000049300F09FFD00287FF4A0AE0220FFF790
+:100C400055FD00283FF49AAE049800F0F7FDEAE75E
+:100C50000220FFF74BFD00283FF490AE00F006FEA7
+:100C6000E1E70220FFF742FD00283FF487AE05A927
+:100C7000142000F001FE04210746049004A800F0AF
+:100C800083FD3946B9E7322000F060FD071EFFF60C
+:100C900075AEBB077FF472AE384A926807EB090362
+:100CA00093423FF66BAE0220FFF720FD00283FF491
+:100CB00065AE27F003074F44B9453FF4A9AE484657
+:100CC00000F094FD0421059005A800F05DFD09F1F8
+:100CD0000409F1E74FF47A70FFF708FD00283FF4AC
+:100CE0004DAE00F0B3FD002844D00A9B01330BD079
+:100CF00008220AA9002000F01BFE00283AD020227A
+:100D0000FF210AA800F00CFEFFF7F8FC1C4803F0D6
+:100D100075FC13B0BDE8F08F002E3FF42FAE0BF042
+:100D20000B030B2B7FF42AAE0023642105A8059347
+:100D300000F020FD074600287FF420AE0220FFF7D8
+:100D4000D5FC804600283FF419AEFFF7D7FC41F2EE
+:100D5000883003F053FC059800F044FE464600F04E
+:100D60002BFE3C46B7E5064652E64FF0000905E685
+:100D7000BA467EE637467CE6AC23002000230020FE
+:100D8000A0860100094A136849F2690099B21B0C58
+:100D900000FB01331360064B186844F2506182B2C5
+:100DA000000C01FB0200186080B270471423002081
+:100DB0001023002010B500211022044600F0B0FDE1
+:100DC000034B03CB206061601868A06010BD00BFBA
+:100DD0009075FF1F2DE9F041ADF54E7D0DF1340802
+:100DE0006CAC40F2751207460D460EA80021C8F8FB
+:100DF000001000F095FD4FF4C4720021204600F071
+:100E00008FFD01F0AFFF274B4FF47A72B0FBF2F089
+:100E1000186093E80700012384E807000DF5E970E6
+:100E20002382FFF7C7FF41F604531F49238406A816
+:100E300004F0A6FA1B2384F832310DF2E32206AB4C
+:100E40000DF1300C1E4603CE6645106051603346EE
+:100E500002F10802F6D13188B378937011802046F0
+:100E60004146012200F0D8FD00230393AB7E02939C
+:100E700005F11903019380B20123CDE904800093A9
+:100E8000E97E06A3D3E90023384602F02BFB0DF5DB
+:100E90004E7DBDE8F08100BFAFF300809E6AC421A3
+:100EA000818A46EEB8240020905300082DE9F043D3
+:100EB000224DBBB001F056FFAB6840F2ED22C31AE1
+:100EC000934232D906AFA8602B462822002138462B
+:100ED00002F0B8FC05F10E0000F01AFD00260446F1
+:100EE0005FFA80F905F10E08F3B2F100994501F1BE
+:100EF000280107D908EB06030822384602F0A2FCB5
+:100F00000136F1E708230122CDE9023205340C4B0A
+:100F10000193A4B230230093CDE9047405A3D3E96F
+:100F20000023297B074802F0DDFA3BB0BDE8F083DF
+:100F3000AFF3008078F6339F93CACD8D605E0020BA
+:100F40006D5E0020D0340020F0B58B8A013B9BB24F
+:100F5000C92BC9B006460C4647D8274D2F7B27BB67
+:100F600005F10C03009308223B463946204602F067
+:100F70002DFB7B1CFAB2D9001F46A38A013B9A4283
+:100F800005DA0E322A44009200230822EEE70023FD
+:100F90000022C5E900230023AB6085F8D730C5F8EF
+:100FA000D8302B7B0BB9E37E2B738122002106AD59
+:100FB00027A800F0B5FC0122294627A800F0FAFD79
+:100FC00000230393A37E029304F1190380B20193DB
+:100FD0002823CDE90450E17E0093304604A3D3E9F1
+:100FE000002302F07FFAFFF761FF49B0F0BD00BFB8
+:100FF00026417272DF25D7B7605E002070B50D46BE
+:1010000014461E4602F0CAF950B9022E10D1012C26
+:101010000ED112A3D3E90023C5E90023012007E084
+:10102000282C10D005D8012C09D0052C0FD0002079
+:1010300070BD302CFBD10BA3D3E90023ECE70BA34D
+:10104000D3E90023E8E70BA3D3E90023E4E70BA3EC
+:10105000D3E90023E0E700BFAFF30080401DA120EB
+:1010600026812A0B78F6339F93CACD8D9E6AC421C0
+:10107000818A46EE26417272DF25D7B7F017304AD3
+:1010800039059E562DE9F04F8DB002AF80460D46D2
+:1010900002F084F9044600285CD12B7E022B1BD180
+:1010A000EB8A012B18D101F05DFE0646FFF76AFEC0
+:1010B00003464FF4C870DFF81C92B3FBF0F206F55C
+:1010C000167602FB103316FA83F3C9F80030EB7E74
+:1010D00033B97B4B00221A702C37BD46BDE8F08F28
+:1010E000AB8AE6B2013BB34204F101040CD907F12B
+:1010F00008031E44E10000960023082201F0F801D5
+:10110000284602F063FAEBE707F11800FFF752FEFA
+:10111000324607F1180107F1080004F0FFF8002833
+:10112000D7D10F2E08D8664B1E70D9F80030A3F522
+:101130001673C9F80030CFE7FB1DF8710146009324
+:1011400007220346284602F041FAF979404602F0A8
+:101150001DF9C1E7EB8A282B26D010D8012B1ED011
+:10116000052BB9D1BFF34F8F5649574BCA6802F4CC
+:10117000E0621343CB60BFF34F8F00BFFDE7302B1E
+:10118000AAD16B7E514C0133627BDBB29342E946BC
+:1011900003D1EA7E237B9A420BD0CD469CE72946B9
+:1011A0004046FFF717FE97E729464046FFF7CCFE7B
+:1011B00092E74FF0000807F11803A7F818801022F3
+:1011C000009341460123284602F000FAAE8A023E0F
+:1011D000B6B2F31C9B109B000733DB08A9EBC303DB
+:1011E0009D460DF1080A1FFA88F34FEAC8019E4296
+:1011F00001F110010AD90AEB080300930822002329
+:10120000284602F0E3F908F10108ECE794F8D7006A
+:1012100000F0FAFAD4F8D810054619B994F8D700B6
+:1012200000F002FBD4F8D83033449D4205D294F844
+:10123000D7000021013000F0F7FA4FEA960B4FF08B
+:1012400000081FFA88F18B45D4E9003209D90AEB6E
+:10125000880103EB8800012200F06AFB08F1010815
+:10126000EFE7F31842F10002C4E90032D4F8D830B5
+:1012700094F8D70006EB0308C4F8D88000F0C4FA4D
+:10128000804509D394F8D730D4F8D8000133401BF7
+:1012900084F8D730C4F8D800FF2E0D4D09D80023AC
+:1012A000237300F0D3FA00F0C7FC288108B9FFF7D8
+:1012B00083FA23689B0A01332B810023A3606CE728
+:1012C000C934002000ED00E00400FA05605E002053
+:1012D000B8240020CC340020F8B50E4C0E4F022666
+:1012E000A4F5805343F8307C237E3BB965692DB16A
+:1012F000284600F01FFD284603F0F8FF204600F0C6
+:1013000019FDA4F5A554012EA4F1100400D1F8BDD7
+:101310000126E5E7E0590020F8530008014B18705A
+:10132000704700BFC424002010B54FF000540C4B90
+:1013300022689A4211D10B4B627D1A700A48237DB4
+:1013400003730A49C9220E3000F0D8FAE0220021C6
+:10135000204600F0E5FA012010BD0020FCE700BFA8
+:101360009AAD44C5C4240020605E00201600002011
+:1013700037B500F061FC1F4C1F4D20492881022326
+:101380006B712368204604F580545B6801229847FE
+:10139000D4F8B03419495B68012204F59660984787
+:1013A00000230193164B174900931748174B4FF42E
+:1013B000805201F0C3FF164B197811B1124801F0A9
+:1013C000E5FF01F0CFFC0446FFF7DCFC4FF4C873E7
+:1013D000B0FBF3F202FB130304F5167010FA83F06E
+:1013E0000C4B186003F07EFC08B10F232B8103B077
+:1013F00030BD00BF00350020B824002040420F005F
+:10140000FD0F0008C8240020D034002085100008FB
+:10141000C4240020CC3400202DE9F04F2DED028BA8
+:101420009F4D93B0DFF8A0A29E4F284602F086F8A9
+:10143000034600283ED00024CDE90F440E94ADF8B9
+:101440004440027B8DF8442099684068964E0FAA6C
+:1014500003C21B6843F000430E93A046A1463368C5
+:10146000D3F810B001F080FC10EB0A0241F1000348
+:101470003046CDF800900EA9D84704F22C5440F61F
+:1014800058230028C8BF48F0010806F5A5569C421D
+:1014900006F11006E3D1B8F1000F05D0284602F09E
+:1014A00051F887F80090C0E73B78072B00F2E68000
+:1014B00001333B700DF12C089FED738B0023DFF897
+:1014C0000C920A93ADF834300B93C8F80430002620
+:1014D000754C374601238DF81C3023688DED008B49
+:1014E0004FF0000BD3F808A08DF81DB05B460DF14E
+:1014F0001D0207A92046D0479DF81CA0BAF1000F95
+:1015000024D0D9F8143083F48063C9F81430102241
+:1015100059460EA800F004FA236808AA5F690AA9D0
+:101520000DF11E032046B84798E803000FAB83E88F
+:1015300003009DF834308DF844300A9B0E930EA9B9
+:10154000DDE90823284602F0C5F9574606F22C5675
+:1015500040F6582304F5A5549E4204F11004B9D175
+:10156000002FB4D1284601F019FF002840D14F4E7A
+:1015700001F0F8FB336898423AD301F0F3FB0446DC
+:10158000FFF700FC4FF4C87304F51674B0FBF3F2D8
+:1015900002FB130314FA83F33360454E8DF8287071
+:1015A000377817B901238DF82830C7F11004E4B259
+:1015B0000EA8FFF7FFFB062C28BF06240EAB224621
+:1015C000D9190DF1290000F099F90AAB03931823FA
+:1015D00002930134374B0193E4B201230093049446
+:1015E0002BA3D3E90023284601F01EFF002333700C
+:1015F00001F0B8FB304A314C1368C31AB3F57A7F57
+:101600002FD3106001F0B0FB02460B46284601F0D4
+:10161000A3FF284601F0C2FE18B3237B284E002BFF
+:1016200014BF03230223737101F09CFB0EAF4FF430
+:101630007A730122B0FBF3F039463060304600F097
+:1016400091FA182302931F4B019380B240F2551375
+:10165000CDE90370009328460FA3D3E9002301F0DE
+:10166000E3FE237B2BB1FFF721FC237B002B7FF4D0
+:10167000D9AE13B0BDEC028BBDE8F08F284601F067
+:1016800061FF17E7AFF300800000000000000000DA
+:10169000401DA12026812A0BF1C6A7C1D068080FE2
+:1016A000D0340020455F002000350020CC340020DD
+:1016B000C9340020C8340020405F0020605E002054
+:1016C000B8240020445F002040420F00000800487A
+:1016D00008B5064800F064FE054800F061FEBDE86C
+:1016E0000840044A0449002003F0FABD00350020F8
+:1016F000B04900209C5F0020D912000870B5104B43
+:101700001B780133DBB2012B0C4612D80D4B1D6840
+:1017100029684FF47A730E6AA2FB0332014622460F
+:101720002846B047844204D1074B00221A7001209A
+:1017300070BD4FF4FA7002F061FF0020F8E700BFBF
+:10174000182300201C2300208C5F002007B50023F5
+:10175000024601210DF107008DF80730FFF7CEFF9B
+:1017600020B19DF8070003B05DF804FB4FF0FF3097
+:10177000F9E700000A4608B50421FFF7BFFF80F033
+:101780000100C0B2404208BD30B4074B0A46197888
+:10179000064B53F821402368DD69054B0146AC46F2
+:1017A000204630BC604700BF8C5F00201C23002017
+:1017B000A086010070B503F0C9F8094E094D3080CC
+:1017C000002428683388834208D903F0BBF82B68CB
+:1017D00004440133B4F5104F2B60F2D370BD00BF49
+:1017E0008E5F0020485F002003F076B900F10060B2
+:1017F00000F510400068704700F10060920000F5AD
+:10180000104003F0E9B80000054B1A68054B1B882F
+:101810009B1A834202D9104403F094B80020704709
+:10182000485F00208E5F0020024B1B68184403F0C5
+:10183000A3B800BF485F00200020704700F10050AF
+:10184000A0F51040D0F8900570470000064991F8C7
+:10185000243033B10023086A81F824300822FFF7CE
+:10186000CBBF0120704700BF4C5F0020014B1868C0
+:10187000704700BF002004E030B50F4B0F4C1B68D1
+:101880002288C3F30B030138934208440BD16468E8
+:101890000A46013C824213460BD214F9015F2DB176
+:1018A00002F8015BF6E781420B4602D22C2203F8D4
+:1018B000012B581A30BD00BF002004E02023002077
+:1018C000022802BF024B4FF080629A61704700BF4E
+:1018D00000080048022802BF024B4FF480629A6160
+:1018E000704700BF00080048022801BF024A536940
+:1018F00083F48063536170470008004810B50023EB
+:10190000934203D0CC5CC4540133F9E710BD00000E
+:1019100003460246D01A12F9011B0029FAD170477A
+:1019200002440346934202D003F8011BFAE77047D2
+:101930002DE9F8431F4D144695F8242007468846A4
+:1019400052BBDFF870909CB395F824302BB920225D
+:10195000FF2148462F62FFF7E3FF95F82400C0F10E
+:101960000802A24228BF2246D6B24146920005EBA9
+:101970008000FFF7C3FF95F82430A41B1E44F6B285
+:10198000082E17449044E4B285F82460DBD1FFF7B9
+:101990005DFF0028D7D108E02B6A03EB8203834266
+:1019A000CFD0FFF753FF0028CBD10020BDE8F8834C
+:1019B0000120FBE74C5F0020024B1A78024B1A70A3
+:1019C000704700BF8C5F00201823002003494FF4AC
+:1019D00061430B60024B186802F0D6BC745F0020B4
+:1019E0001C230020094B10B518220446002118467C
+:1019F000FFF796FF064A074B127804600146BDE8E0
+:101A0000104053F8220002F0BFBC00BF745F0020FA
+:101A10008C5F00201C2300202DE9F0470D46044672
+:101A200000219046284640F27912FFF779FF2346BD
+:101A300020220021284601F005FF231D022220213B
+:101A4000284601F0FFFE631D03222221284601F0F3
+:101A5000F9FEA31D03222521284601F0F3FE04F11F
+:101A6000080310222821284601F0ECFE04F110039F
+:101A700008223821284601F0E5FE04F1110308226E
+:101A80004021284601F0DEFE04F11203082248211D
+:101A9000284601F0D7FE04F11403202250212846E5
+:101AA00001F0D0FE04F1180340227021284601F015
+:101AB000C9FE04F120030822B021284601F0C2FE2D
+:101AC00004F121030822B821284601F0BBFE04F1ED
+:101AD0002207C0263B46314608222846083601F038
+:101AE000B1FEB6F5A07F07F10107F3D104F132038F
+:101AF00008223146284601F0A5FE002704F1330AEA
+:101B000094F832304FEAC7099F4209F5A47615D3FD
+:101B1000B8F1000F08D1314604F599730722284621
+:101B200001F090FE09F24F16274694F832213B1B34
+:101B300093420CD3F01DC008BDE8F0870AEB070301
+:101B400008223146284601F07DFE0137D8E707F22A
+:101B5000331331460822284601F074FE0836013757
+:101B6000E3E7000013B50446084600210160234660
+:101B7000C0F803102022019001F064FE0198231D9B
+:101B80000222202101F05EFE0198631D0322222122
+:101B900001F058FE0198A31D0322252101F052FEF9
+:101BA000019804F108031022282101F04BFE0720C0
+:101BB00002B010BDF8B50E4605461446002181223C
+:101BC0003046FFF7ADFE2B4608220021304601F0DB
+:101BD00039FE7CB96B1C07220821304601F032FE29
+:101BE0000F2401236A785F1C013B934204D3E01D5C
+:101BF000C008F8BD0824F4E7EB1921460822304656
+:101C000001F020FE08343B46ECE7000030B5094DFA
+:101C10000A4491420DD011F8013B5840082340F38B
+:101C20000004013B2C4013F0FF0384EA5000F6D17E
+:101C3000EFE730BD2083B8ED73B5384A10685168BE
+:101C40006B4603C36A4636493648082303F076FBE1
+:101C5000044670B9344A106851686B4603C36A463B
+:101C600032493048082303F069FB044630BB0A20A0
+:101C700022E00369B3F5EE2FECD8418B40F21D4210
+:101C80009142E7D12A4A024402F110018B42E1D38A
+:101C9000103B244900209D1AFFF7B8FF2A4606464C
+:101CA00004F118010020FFF7B1FFA3689E42D1D1D3
+:101CB000E3689842CED1002002B070BD0369B3F54D
+:101CC000EE2F22D8B0F8661040F21D4291421ED18C
+:101CD000174A024402F15C018B421AD35C3B114962
+:101CE00000209D1AFFF792FF2A46064604F1640180
+:101CF0000020FFF78BFFA268964203460BD1E068F5
+:101D0000834214BF0D200020D6E70B20D4E70C201F
+:101D1000D2E71020D0E70D20CEE700BFB85300086F
+:101D2000DC6F070000900008C1530008906F0700A7
+:101D30000870FFF710B5037C044613B9006803F080
+:101D4000E5FA204610BD00000023BFF35B8FC3609F
+:101D5000BFF35B8FBFF35B8F8360BFF35B8F704715
+:101D6000BFF35B8F0068BFF35B8F704770B50546AC
+:101D70000C30FFF7F5FF05F1080604463046FFF783
+:101D8000EFFFA04206D930466D68FFF7E9FF254412
+:101D9000281A70BD3046FFF7E3FF201AF9E700006C
+:101DA00070B50546406898B105F10800FFF7D8FF07
+:101DB00005F10C0604463046FFF7D2FF8442304658
+:101DC00094BF6D680025FFF7CBFF013C2C44201A1F
+:101DD00070BD000038B50C460546FFF7C7FFA042AE
+:101DE00010D305F10800FFF7BBFF04446868B4FB9B
+:101DF000F0F100FB1144BFF35B8F0120AC60BFF337
+:101E00005B8F38BD0020FCE72DE9F0411446074602
+:101E10000D46FFF7C5FF844228BF0446D4B1B8463B
+:101E200058F80C6B4046FFF79BFF30442860404653
+:101E30007E68FFF795FF331A9C4203D86C6001203F
+:101E4000BDE8F0816B60A41B3B68AB602044E86098
+:101E50000220F5E72046F3E738B50C460546FFF7C4
+:101E60009FFFA04210D305F10C00FFF779FF044457
+:101E70006868B4FBF0F100FB1144BFF35B8F0120F5
+:101E8000EC60BFF35B8F38BD0020FCE72DE9FF411C
+:101E9000884669460746FFF7B7FF6C4606B204EB73
+:101EA000C6060025B44209D06268206808EB050127
+:101EB000FFF724FD636808341D44F3E729463846DC
+:101EC000FFF7CAFF284604B0BDE8F081F8B5054623
+:101ED0000C300F46FFF744FF05F108060446304674
+:101EE000FFF73EFFA042304688BF6C68FFF738FF1F
+:101EF000201A386020B130462C68FFF731FF2044AB
+:101F0000F8BD000073B5144606460D46FFF72EFFD8
+:101F1000844228BF04460190DCB101A93046FFF796
+:101F2000D5FF019B33B93268C5E90233C5E9002406
+:101F300001200CE09C4238BF019428600198686041
+:101F40008442F5D93368AB60241AEC60022002B0F9
+:101F500070BD2046FBE700002DE9FF410F466946B2
+:101F6000FFF7D0FF6C4600B204EBC0050026AC4280
+:101F700009D0D4F8048054F8081BB8194246FFF77A
+:101F8000BDFC4644F3E7304604B0BDE8F0810000F4
+:101F900038B50546FFF7E0FF044601462846FFF73F
+:101FA00019FF204638BD0000302383F3118862B644
+:101FB00070470000002383F3118862B67047000069
+:101FC000012070477047000010B41346026814687F
+:101FD0000022A4465DF8044B6047000000F58050E5
+:101FE00090F859047047000000F5805090F85204B2
+:101FF0007047000000F5805090F9580470470000C9
+:102000005020704700F5805208B5FFF7CDFFD2F899
+:102010009834D2F894041844D2F890341844D2F882
+:1020200078341844D2F888341844D2F884341844E8
+:10203000FFF7C0FF08BD000038B5C26A936923F0FE
+:1020400001039361044600F08DFE0546E36A9B6937
+:10205000DB0706D500F086FE431BFA2BF6D90020DD
+:1020600004E004F58054012084F8520438BD0000D7
+:102070002DE9F04F0C4600F5805185B01F4691F8D0
+:102080005234BDF83890054690469BB1D1F874346F
+:102090000133C1F8743423689A0006D4237B082BDB
+:1020A0000BD9627B0AB10F2B07D9D1F878340133F1
+:1020B000C1F878344FF0FF300FE0FFF775FFEB6A9F
+:1020C000D3F8C42012F4001A0AD0D1F87C340133BA
+:1020D000C1F87C34FFF76EFF002005B0BDE8F08F3B
+:1020E000D3F8C46022686B6AC6F301464FF0480B10
+:1020F000002A1BFB063BB4BF42F080429204CBF89F
+:10210000002023685B0044BF42F00052CBF800205F
+:10211000227B330643EA0243CBF80430607B720132
+:1021200018B343F44013CBF80430D1F8A43401338E
+:10213000C1F8A434AB1803F58353197B41F0200197
+:102140001973207B039200F06BFE039A033080101A
+:102150005FFA8AF383420AF1010A0DDA04EB830184
+:102160000BEB830349689960F2E7AB1803F58353DF
+:10217000197B60F34511E3E7EB6A0121B140C3F835
+:10218000CC10AB1803F58253C3E9048705EB461363
+:1021900003F582532146183304F10C0051F804CBA7
+:1021A00043F804CB8142F9D1098819802A4441F2CD
+:1021B00068032846D65002F5805209F0030392F8CE
+:1021C0006C1043F0100321F01F010B4382F86C30B8
+:1021D000FFF7F0FE4246CDF800903B46214600F066
+:1021E000E5FD012079E7000013B500F58054019169
+:1021F000606CFFF7D5FD1F280AD90199606C202279
+:10220000FFF744FEA0F120035842584102B010BD30
+:102210000020FBE708B500F58050FFF7C5FE406CD5
+:10222000FFF792FDBDE80840FFF7C4BE0022026040
+:10223000828142608260704710B500220023C0E9AD
+:1022400000230023044603810C30FFF7EFFF2046F4
+:1022500010BD00002DE9F047074688B007F580540F
+:1022600068469A468846FFF79FFE9146FFF7E4FFCF
+:10227000606CFFF77BFD1F282CD9606C202269461B
+:10228000FFF786FE202825D194F8523413B303AD0E
+:10229000444605AB2E4603CE9E4220606160354623
+:1022A00004F10804F6D130682060B388A380DDE92A
+:1022B0000023C9E90023BDF80830AAF80030FFF771
+:1022C00079FE4A4653464146384608B0BDE8F047D5
+:1022D00000F05ABDFFF76EFE002008B0BDE8F087A1
+:1022E0002DE9F84F00230646C0E90133294B46F893
+:1022F000303B00F581540546884637461034384651
+:102300002037FFF799FFA742F9D105F580544FF424
+:10231000805326630026C4E90D366764012305F562
+:10232000835705F5A359E66384F8403084F84830B4
+:10233000103709F110094FF0000A4FF0000B47E980
+:1023400008ABA7F11800FFF771FF203747F8286C9A
+:102350004F45F4D1B8F1010F84F85884A4F85A64B9
+:10236000A4F85C64A4F85E6484F86064A4F8626411
+:10237000A4F86464A4F8666484F8686402D9064822
+:1023800000F0EAFC054B53F82830EB622846BDE824
+:10239000F88F00BFF8530008CC530008E85300083A
+:1023A00010B5044B197804464A1C1A70FFF798FFC1
+:1023B000204610BD995F00202DE9F04300295FD031
+:1023C0003048314BB3FBF1F381428CBF0A2011201E
+:1023D000451EB3FBF0F700FB1730ECB220B1022D25
+:1023E0002846F5D8002037E07D1EB5F5806F33D242
+:1023F000C4EBC40808F103034FEAE30EC3F3C703B9
+:10240000A4EB030C0EF101094FF47A705FFA8CF61D
+:102410000EFB000E59FA8CFCBEFBFCFCBCF5617F88
+:102420001CDC1FFA8CF4581C56FA80F047431648FF
+:10243000B0FBF7F7B942D5D1013BDBB20F2BD1D8B6
+:10244000711EC9B207294FF0000005D81071148021
+:102450005580537191710120BDE8F08308F1FF337D
+:102460004FEAE30CC3F3C703E41A0CF1010EE6B222
+:102470000CFB00005EFA84F4B0FBF4F4A4B2D2E7E3
+:102480000846E9E73F420F000024F40038B500F5A4
+:102490008053114A93F85834D55C4FF45472554325
+:1024A00005F1804303F52443044600211846FFF755
+:1024B00037FA0A4B60612B44A361094B2B44E3615B
+:1024C000084B2B442362084B2B446362E36A0022CF
+:1024D000C3F8C02038BD00BFE053000870A400401E
+:1024E000B0A4004088A5004078A600402DE9F04F38
+:1024F00000F58055994695F85834022B89B004466A
+:102500008A46904604D90027384609B0BDE8F08FC6
+:102510009C4A52F8231009B942F823009A49C4F89A
+:102520000CA00B7884F8109093B9FFF73DFD974B02
+:102530009A6D42F000729A659A6B42F000729A634B
+:102540009A6B22F000729A6301230B70FFF732FD41
+:1025500095F85134BBB9FFF727FD8D4A95F85834EB
+:10256000D35C012B26D0022B2BD03BB903211520A5
+:1025700001F054FD0321162001F050FD012385F8E0
+:102580005134FFF717FDFFF70FFDE26A936923F05F
+:102590001003936100F0E6FB0746E36A9E6916F0BC
+:1025A000080615D000F0DEFBC31BFA2BF5D9FFF7A8
+:1025B00001FDA8E70321562001F030FD032157203B
+:1025C000DAE70321582001F029FD03215920D3E740
+:1025D0009A6942F001029A6100F0C4FB0746E36A7F
+:1025E0009A69D00705D400F0BDFBC31BFA2BF6D9BE
+:1025F000DDE79A6942F002029A61E36A00275F65AB
+:10260000FFF7D8FC686CFFF79FFB04F5825B0BF1CA
+:10261000100B202200216846FFF782F902A8FFF77D
+:1026200005FE06976A460BEB06030DF1180E94465D
+:10263000BCE80300F44518605960624603F10803E2
+:10264000F5D1DCF80000186020369CF804201A71DF
+:10265000B6F5806FDDD1002304F5A25285F8503421
+:1026600085F853341A3251462046FFF7A5FE074637
+:1026700090B9E26A936923F00103936100F072FB61
+:102680000546E36A9B69D9077FF53DAF00F06AFB19
+:10269000431BFA2BF5D936E795F85F6495F85E246D
+:1026A000C5F86CA4360246EA426695F86024E36AEF
+:1026B0001643B5F85C2446EA0246DE61B8F1000F25
+:1026C00029D004F5A352023241462046FFF774FE9A
+:1026D00090B9E26A936923F00103936100F042FB31
+:1026E0000546E36A9B69DA077FF50DAF00F03AFB18
+:1026F000431BFA2BF5D906E795F8683495F867146B
+:10270000C5F870841B0143EA0123B5F86414E26A3A
+:1027100043EA0143D3602046FFF7B8FE002385F863
+:102720005934E36A6FF040421A65E36A194A5A6500
+:10273000E36A44229A65E36A0722C3F8DC20E36A6D
+:102740000322DA65E26A9369B9F1030F43F4407337
+:1027500093613FF4D9AEE26A936923F00103936178
+:1027600000F000FB0646E36A9B69DB0705D500F035
+:10277000F9FA831BFA2BF6D9C5E6012385F8523402
+:10278000C2E600BF905F0020985F0020001002406A
+:10279000E05300089B0008002DE9F04F054689B082
+:1027A00090469946002741F2680A00F58056EB6A88
+:1027B000D3F8D430FB40D8074AD505EB4712524432
+:1027C0004FEA471B1379190742D4D6F880340133F6
+:1027D000C6F8803413799A0648BFD6F8A83405EBBA
+:1027E0000B0248BF0133524448BFC6F8A8341379DE
+:1027F00043F008031371DB0722D596F85334FBB17D
+:1028000005F58254183468465C44FFF715FD03ABA8
+:1028100004F1080C206861681A4603C20834644554
+:102820001346F7D120681060A2889A800123ADF882
+:1028300008302B68CDE90089DB6B6946284698474C
+:10284000D6F8543423B1D6F89C340133C6F89C34FE
+:102850000137202FABD109B0BDE8F08F2DE9F04F43
+:102860008DB004460F4600F07FFA82468946002F5D
+:1028700056D1E36AD3F89020920141BF04F580510C
+:10288000D1F894240132C1F89424D3F8902016078B
+:1028900003D100200DB0BDE8F08FD3F89050E66969
+:1028A000C5F30125482303FB0566E8464046FFF7CC
+:1028B000BDFC326851004ABF22F06043C2F38A4334
+:1028C00043F00043920048BF43F080430093736895
+:1028D00013F400131FBF04F5805201238DF80D304F
+:1028E000D2F8AC340EBF8DF80D300133C2F8AC34E1
+:1028F000F38803F00F038DF80C304FF0000B9DF8B8
+:102900000C0000F08DFA5FFA8BF3984220D9F21890
+:102910000CA90B44127A03F82C2C0BF1010BEEE7F7
+:10292000012FB6D1E36AD3F89820950141BF04F591
+:102930008051D1F894240132C1F89424D3F898201E
+:102940001007A6D0D3F89850266AC5F30125A9E749
+:10295000EFB9E36AC3F8945004A8FFF76DFC98E858
+:102960000F0007AD07C52B800023ADF81830236892
+:102970002046CDE904A9DB6B04A9984704F58054EF
+:1029800058B1D4F88C340133C4F88C3482E7012F69
+:1029900004BFE36AC3F89C50DEE7D4F890340133F7
+:1029A000C4F89034012075E7F8B505460F4600F5E8
+:1029B0008054012639462846FFF750FF10B184F8AD
+:1029C0005364F7E7D4F8543423B1D4F89C3401337A
+:1029D000C4F89C34F8BD0000F0B5C36A1A6C12F458
+:1029E0007F0F2BD000F580541B6CC4F8A03441F24B
+:1029F0006805002347194FF0010C00EB43122A44ED
+:102A00005E01117911F0020F15D0490713D4B9599D
+:102A1000C66AD6F8C8E00CFA01F111EA0E0F0AD026
+:102A2000C6F8D010117941F004011171D4F888244E
+:102A30000132C4F888240133202BDED1F0BD000020
+:102A40002B4B70B51E561B5C012B2FD8294D2A4AE3
+:102A500055F8233052F826400BB341B3236D1A06C4
+:102A60000FD58023236500F07FF950EA01020B4661
+:102A700002D0013861F10003024655F82600FFF745
+:102A80008BFE236D1B032CD555F826304FF4002206
+:102A900003F580532265012283F8592421E00123A4
+:102AA0002365082323654FF48063236570BD236D80
+:102AB000DA0702D4236D9B0706D5032355F82600B9
+:102AC00023650021FFF770FF236D180702D4236DE3
+:102AD000D90606D5182355F8260023650121FFF7EE
+:102AE00063FF55F82600BDE87040FFF775BF00BFD3
+:102AF000E4530008905F0020E853000808B5FFF792
+:102B000053FAFFF769FFBDE80840FFF753BA00002A
+:102B1000C36AD3F8C40080F40010C0F3405070477B
+:102B200000F5805008B5FFF73FFA406CFFF71EF93B
+:102B3000FFF740FA43090CBF0120002008BD000048
+:102B400000F5805393F8592462B1C16A8A6922F072
+:102B500001028A61D3F898240132C3F89824002234
+:102B600083F85924704700002DE9F74300F582519E
+:102B700098461031FFF718FA002541F2680E4FF021
+:102B8000010900F5805C00EB4514744423795E076D
+:102B90001CD4DB061AD5C36A8E69D3F8C87009FA4B
+:102BA00006F63E4212D04F6801970F689742019F88
+:102BB00077EB08070AD2C3F8D060237943F0040307
+:102BC0002371DCF884340133CCF884340135202DB2
+:102BD00001F12001D7D103B0BDE8F043FFF7EAB916
+:102BE000F8B51E46002313700F4605461446FFF73E
+:102BF00097FF80F0010038701EB12846FFF788FF6C
+:102C00002070F8BD2DE9F04F85B09946DDE90EA39F
+:102C10000D4602931378019391F800B08046164652
+:102C200000F0A2F82B7804460F4613B93378002B36
+:102C300042D022463B464046FFF796FFFFF75EFF35
+:102C4000FFF77EFF4B4632462946FFF7C9FF2B7838
+:102C500033B1BBF1000F03D0012005B0BDE8F08F08
+:102C6000337813B1019B002BF6D108F58053039301
+:102C7000029B544577EB03031ED2039BD3F8540405
+:102C8000D0B10368AAEB0401DB6889B298474B46D0
+:102C9000324629464046FFF7A3FF2B7813B1BBF11C
+:102CA000000FD9D1337813B1019B002BD4D100F0A0
+:102CB0005BF804460F46DBE70020CEE708B50021AD
+:102CC0000846FFF7BDFEBDE8084001F05FB8000010
+:102CD00008B501210020FFF7B3FEBDE8084001F070
+:102CE00055B8000008B500210120FFF7A9FEBDE896
+:102CF000084001F04BB8000008B501210846FFF775
+:102D00009FFEBDE8084001F041B8000000B59BB04F
+:102D1000EFF3098168226846FEF7F0FDEFF30583C3
+:102D2000014B9B6BFEE700BF00ED00E008B5FFF72D
+:102D3000EDFF000000B59BB0EFF309816822684603
+:102D4000FEF7DCFDEFF30583014B5B6BFEE700BF95
+:102D500000ED00E0FEE700000FB408B5029801F0B6
+:102D6000E3FBFEE701F006BF01F0DEBE01F0DCBED2
+:102D700013B56C4684E80600031D94E8030083E85D
+:102D80000500012002B010BD73B58568019155B1F1
+:102D90001B885B0707D4D0E900369B6B9847019AE4
+:102DA000C1B23046A847012002B070BDF0B58668B8
+:102DB00089B005460C465EB1BDF838305B070AD4D1
+:102DC000D0E900379B6B98472246C1B23846B047DE
+:102DD000012009B0F0BD00220023CDE9002300232B
+:102DE000ADF808300A4603AB01F1080610685168D7
+:102DF0001C4603C40832B2422346F7D11068206053
+:102E00009288A280FFF7B2FF0423ADF808302B6848
+:102E1000CDE90001DB6B694628469847D8E70000FA
+:102E2000082817D909280CD00A280CD00B280CD058
+:102E30000C280CD00D280CD00E2814BF40203020B8
+:102E400070470C20704710207047142070471820DE
+:102E500070472020704700002DE9F041456A15B900
+:102E60004162BDE8F0814B6823F06047C3F38A46B6
+:102E70004FEAD37EC3F3807816EA230638BF3E4676
+:102E8000AC462B465A68BEEBD27F22F060440AD093
+:102E9000002A18DAA40CB44217D19D420FD10D605C
+:102EA000DEE71346EEE7A74207D102F08044C2F303
+:102EB000807242450BD054B1EFE708D2EDE7CCF871
+:102EC00000100B60CDE7B44201D0B442E5D81A68D7
+:102ED0009C46002AE5D11960C3E700002DE9F047C0
+:102EE000089D01F007044FEAD508224405F00705C4
+:102EF00000EBD1004FF47F49944201D1BDE8F08747
+:102F000004F0070705F0070A57453E4638BF564606
+:102F1000C6F10806111B8E4228BF0E46E10808EBD9
+:102F2000D50E415C13F80EC0B94029FA06F721FA14
+:102F30000AF1FFB28CEA010147FA0AF739408CEA3C
+:102F4000010C03F80EC034443544D5E780EA012073
+:102F5000082341F2210201B24000002980B203F1AE
+:102F6000FF33B8BF504013F0FF03F4D170470000A7
+:102F700038B50C468D18A54200D138BD14F8011B98
+:102F8000FFF7E4FFF7E7000042684AB113684360C7
+:102F90004389818901339BB29942438138BF838140
+:102FA0001046704770B588B0202204460D4668462A
+:102FB0000021FEF7B5FC20460495FFF7E5FF024629
+:102FC00058B16B46054608AE1C4603CCB442286097
+:102FD0006960234605F10805F6D1104608B070BDBA
+:102FE000082817D909280CD00A280CD00B280CD097
+:102FF0000C280CD00D280CD00E2814BF40203020F7
+:1030000070470C207047102070471420704718201C
+:103010007047202070470000082817D90C280CD9C9
+:1030200010280CD914280CD918280CD920280CD910
+:1030300030288CBF0F200E207047092070470A20CF
+:1030400070470B2070470C2070470D207047000020
+:103050002DE9F843078C072F04461ED9D0E90298C2
+:1030600000254FF6FF73C5F12006A5F1200029FACF
+:1030700005F108FA06F628FA00F031430143C9B217
+:103080001846FFF763FF0835402D0346EBD1E16991
+:103090003A46BDE8F843FFF76BBF4FF6FF70BDE857
+:1030A000F883000010B54B6823B9CA8A63F309029C
+:1030B000CA8210BD04691A681C600361C38A013B9F
+:1030C000C3824A60EFE700002DE9F84F1D46CB8A26
+:1030D0000F46C3F309010529814692460B4630D0BD
+:1030E0000020AAB207F11A049EB2042E1FFA80F83B
+:1030F0000FD8904503F1010306D3FB8A0A4462F31B
+:103100000903FB8201201AE01AF80060E65401303E
+:10311000EAE79045F1D2A1F1050B1C237C68BBFBCB
+:10312000F3F203FB12BB1FFA8BF6002C45D1484685
+:10313000FFF72AFF044638B978606FF00200BDE857
+:10314000F88F4FF00008E6E7002606607860ADB221
+:103150004FF0000B454510D90AEB0803221D13F868
+:10316000011B9155B1B208F101081B291FFA88F81B
+:103170002BD0454506F10106F1D8FB8AC3F30902BD
+:10318000154465F30903BCE7013292B21C4623687B
+:10319000002BF9D16B1F0B441C21B3FBF1F301335E
+:1031A0009BB29A42D3D2BBF1000FD0D14846FFF771
+:1031B000EBFE20B9C4F800B0BFE70122E7E7C0F892
+:1031C00000B05E4620600446C1E74545D5D9484673
+:1031D000FFF7DAFE08B92060AFE7C0F800B00026BC
+:1031E00020600446B6E700002DE9F04F2DED028B7C
+:1031F0001C4683B05B69019207468846002B00F0AD
+:103200009A80238C2BB1E269002A00F09480072B6E
+:1032100035D807F10C00FFF7B7FE054638B96FF057
+:103220000205284603B0BDEC028BBDE8F08F1422E6
+:103230000021FEF775FB228CE16905F10800FEF71D
+:103240005DFB208C013080B2FFF7E6FEFFF7C8FE81
+:10325000013880B22084013028746369228C1B7885
+:103260002A4403F01F0363F03F0348F00041137248
+:10327000384669602946FFF7EFFD0125D1E700F1E7
+:103280000C034FF0000908EE103A4FF0800A4E464A
+:103290004D4618EE100AFFF777FE83460028BED091
+:1032A00014220021FEF73CFB002E3AD1019BABF823
+:1032B000083002220BF1080E1FFA82FC0CF101000B
+:1032C000BCF1060F218C80B201D88E422BD3FFF7C0
+:1032D000A3FEFFF785FE62691278013802F01F0233
+:1032E0008E4208BF4FF0400A42EA49121BFA80F1B1
+:1032F0004AEA020A013048F0004281F808A08BF83F
+:103300001000CBF8042059463846FFF7A5FD238C62
+:103310000135B3422DB289F001094FF0000AB8D14E
+:103320007FE70022C6E7E169895D0EF802100136E9
+:10333000B6B20132C0E76FF0010572E7F8B5154685
+:103340000E463022002104461F46FEF7E9FA069B8E
+:103350006360B5F5001F079BA76034BF6A094FF68D
+:10336000FF72A36297B2E66104F1100000239A4253
+:1033700006D800230360A782E3822383E360F8BDBD
+:103380000660013330462036F1E7000003781BB9B0
+:103390004BB2002BC8BF0170704700000078704727
+:1033A000F8B50C46C969074611B9238C002B37D1F3
+:1033B000257E1F2D34D8387828BB228C072A2CD89C
+:1033C000268A36F003032BD14FF6FF70FFF7D0FDAE
+:1033D00020F001003102400441EA0561400C41EA5D
+:1033E00040254FF6FF72234629463846FFF7FCFE7C
+:1033F000002807DD626913780133DBB21F2B88BF19
+:1034000000231370F8BD218A2D0645EA01250543E6
+:103410002046FFF71DFE0246E5E76FF00300F1E7E7
+:103420006FF00100EEE7000070B58AB00446164662
+:103430000021282268461D46FEF772FABDF8383092
+:10344000ADF810300F9B05939DF840308DF8183083
+:10345000119B07936946BDF84830ADF820302046EF
+:10346000CDE90265FFF79CFF0AB070BD2DE9F04180
+:10347000D36905460C4616460BB9138C5BBB377EE9
+:103480001F2F28D895F80080B8F1000F26D03046BD
+:10349000FFF7DEFD3378210241EAC33141EA08013A
+:1034A000338A41EA076141EA03410246334641F06B
+:1034B00080012846FFF798FE00280ADD3378012BAB
+:1034C00007D1726913780133DBB21F2B88BF002349
+:1034D0001370BDE8F0816FF00100FAE76FF00300B0
+:1034E000F7E70000F0B58BB004460D461746002103
+:1034F000282268461E46FEF713FA9DF84C305A1EE5
+:10350000534253418DF800309DF84030ADF81030F3
+:10351000119B05939DF848308DF81830149B079344
+:103520006A46BDF85430ADF8203029462046CDE932
+:103530000276FFF79BFF0BB0F0BD0000406A00B1C0
+:1035400004307047436A1A68426202691A60036174
+:10355000C38A013BC38270472DE9F041D0F8208037
+:10356000194E14461D464146002709B9BDE8F081B1
+:10357000D1E90223A21A65EB0303964277EB03031A
+:103580001ED2036A8B420DD1FFF78CFD036A1B68C4
+:10359000036203690B60C38A0161016A013BC38254
+:1035A0008846E2E7FFF77EFD0B68C8F80030036944
+:1035B0000B60C38A0161013BC382D8F80010D4E7D5
+:1035C00088460968D1E700BF80841E002DE9F04FCE
+:1035D0008BB00D46DDF8509014469B46804600287F
+:1035E00000F01981B9F1000F00F01581531E3F2B37
+:1035F00000F21181012A03D1BBF1000F40F00B81D1
+:103600000023CDE90833B8F81430B5EBC30F4FEA07
+:10361000C30703D300200BB0BDE8F08F2B199F42E6
+:10362000D8F80C303ABF7F1BFFB227461BB9D8F839
+:103630001030002B7AD0272D4ED8C5F12806B7427E
+:103640004FF000032CBFF6B23E4600932946D8F84F
+:10365000080008AB3246FFF741FCA7EB060A3544E9
+:103660005FFA8AFAB8F8143003F10053053BDB0027
+:103670000493D8F80C3003932821039B13B1BAF1BB
+:10368000000F2CD1D8F8100040B1BAF1000F05D0CE
+:10369000009608AB5246691AFFF720FC38B2002F9B
+:1036A000B8D066070AD00AAB03EBD401624211F826
+:1036B000083C02F00702134101F8083C082C3CD9F1
+:1036C000102C40F2B580202C40F2B780BBF1000FE7
+:1036D00000F09C80082334E0BA460026C2E7049B31
+:1036E000E02B28BFE02306930B44AB42059314D98B
+:1036F0005A1B03980096924534BF5246D2B2691ABB
+:1037000008AB04300792FFF7E9FB079A1644AAEBCF
+:10371000020A1544F6B25FFA8AFA049B069A0599E2
+:103720009B1A0493039B1B680393A6E70093D8F8A6
+:10373000080008AB3A462946AEE7BBF1000F13D0AC
+:103740000123B4EBC30F6CD0082C12D89DF82030A5
+:10375000621E23FA02F2D50706D54FF0FF3202FAB5
+:1037600004F423438DF820309DF8203089F8003090
+:1037700051E7102C12D8BDF82030621E23FA02F255
+:10378000D10706D54FF0FF3202FA04F42343ADF817
+:103790002030BDF82030A9F800303CE7202C0FD8AD
+:1037A0000899631E21FA03F3DA0705D54FF0FF32BB
+:1037B00002FA04F40C430894089BC9F800302AE785
+:1037C000402C2BD0DDE90865611EC4F12102A4F173
+:1037D000210326FA01F105FA02F225FA03F3114357
+:1037E0001943CB0712D50122A4F12003C4F1200113
+:1037F00002FA03F322FA01F1A240524243EA010322
+:1038000063EB430332432B43CDE90823DDE908236F
+:10381000C9E90023FFE66FF00100FCE66FF0080045
+:10382000F9E6082CA0D9102CB3D9202CEED8C3E788
+:10383000BBF1000FADD0022383E7BBF1000FBBD07B
+:1038400004237EE730B5012A144638BF0124402CFA
+:1038500085B028BF40240025012ACDE9025518D89B
+:103860001B788DF8083063070AD004AB03EBD4054E
+:10387000624215F8083C02F00702934005F8083C44
+:10388000009103462246002102A8FFF727FB05B05E
+:1038900030BD082AE4D9102A03D81B88ADF80830B7
+:1038A000E1E7202A8DBFD3E900231B680293CDE90D
+:1038B0000223D8E710B5CB681BB98B600B618B82F4
+:1038C00010BD04691A681C600361C38A013BC3828E
+:1038D000CA60F0E72DE9F04F93B0CDE903230B6800
+:1038E00004460D461806C3F3C01147BFC3F3C03BDF
+:1038F000C3F306264FF0020B0E46002B80F2FF8129
+:1039000013F0C04940F0FB812A7B002A00F0F781C8
+:10391000BBF1020F03D02078B04240F0F381C3F333
+:103920000460079003F07F00059059B3C3F3074A82
+:103930002A44059B92F80380760646EA0B4646EA3F
+:10394000834600220023CDE908235FEAD81346EA24
+:103950000A0602936AD0059B009367685B4652464D
+:1039600008A92046B847002800F0CF81276A87B908
+:10397000314604F10C00FFF715FB0746C8B96FF09C
+:10398000020057E0C3F30F2A590608BF0AF0030AE2
+:10399000CEE73B699E420DD03F68002FF9D13146FA
+:1039A00004F10C00FFF7FEFA07460028E7D0236A6F
+:1039B0003B602762FE7D08F01F03C6F38406F01A01
+:1039C0001FFA80FC0028B8BF0CF12000D7E90221C3
+:1039D0000693A3EB06031FFA83FCB8BF00B2002BCB
+:1039E000BCBF0CF120031BB252EA010636D0039E85
+:1039F000DFF8D4C2B21A049E66EB0101002694459A
+:103A000076EB010C2AD395F80DE097F81AC0E6453D
+:103A100018D1029E002E79D001281FDC7868E8B901
+:103A2000A84E964270EB010216D337E0276A27B9F9
+:103A30006FF00C0013B0BDE8F08F3B699E42B9D027
+:103A40003F68F4E79F48904276EB010201D30020E3
+:103A5000F0E7029A002AFAD00F2B18DCFA7D4FEA21
+:103A6000880302F0030203F07C031343FB7539461D
+:103A70002046FFF717FB6B7BBB76029B3BB9FB7DB8
+:103A8000C3F38402013262F38603FB75D0E76A7BDD
+:103A9000BB7E9A42DBD1029B002B37D04FEA9813B2
+:103AA000022B33D0039BBB60049BFB6014220021DC
+:103AB0000DA8FDF735FF039B0A93049B0B932B1D69
+:103AC0000C932B7BADF83EA0013BDBB2ADF83C3054
+:103AD000069B8DF84130079B8DF84230059B8DF891
+:103AE000433094F82C308DF840B083F001038DF80A
+:103AF00044300AA9A36820469847FB7DC3F384039A
+:103B0000013303F01F039B02FB82A0E7FB7DC8F398
+:103B10004012B2EBD31F40F0FB80069AC3F384033C
+:103B2000934240F0F88002992B7B4FEA98120029CB
+:103B30004DD0D2075DD4032B40F2F080039BBB60D5
+:103B4000049BFB602B7BAE1D033BDBB23246394648
+:103B500004F10C00FFF7B8FA00280CDA39462046C9
+:103B6000FFF7A0FAFB7DC3F38403013303F01F03C7
+:103B70009B02FB8203E7DDE90884AB883B834FF6B9
+:103B8000FF73C9F12000A9F1200228FA09F104FA13
+:103B900000F0014324FA02F211431846C9B2FFF7BC
+:103BA000D5F909F10809B9F1400F0346E9D1B88206
+:103BB0002A7B033AD2B23146FFF7DAF9FB7DB882AD
+:103BC000DA43C2F3C01262F3C713FB753FE782B951
+:103BD0002E1D013BDBB23246394604F10C00FFF7E3
+:103BE00073FA0028BADB2A7BB88A013AD2B231468E
+:103BF000E2E7F98AC1F30901013B0429DAB25CD892
+:103C0000281D002307F11B069A4208D910F801CBA2
+:103C100006F801C0013101330529DBB2F4D1039963
+:103C20000A9104990B91934207F11B010C9138BF43
+:103C3000043379680D9134BF55FA83F300230E9352
+:103C4000FB8AADF83EA0C3F309031A44069B8DF826
+:103C50004130079B8DF84230059B8DF8433094F836
+:103C60002C30ADF83C2083F001038DF84430002364
+:103C70008DF840B07B602A7BB88A013A291DFFF796
+:103C800077F93B8BB882834203D1A3680AA9204607
+:103C9000984720460AA9FFF70DFEFB7DBA8AC3F3B9
+:103CA0008403013303F01F039B02FB823B8B9A4288
+:103CB0000CBF00206FF01000BCE67B68002BAED07C
+:103CC000052005E040420F0080841E001C30334672
+:103CD0001E68002EFAD1091A081D2E1D184401EB8A
+:103CE000090CBCF11B0F5FFA89F398D89A4296D958
+:103CF00016F8013B00F8013B09F10109EFE76FF00D
+:103D0000090097E66FF00A0094E66FF00B0091E669
+:103D10006FF00D008EE66FF00E008BE66FF00F0077
+:103D200088E600BFEFF3098305494A6B22F00102E0
+:103D30004A63683383F30988002383F3118870474B
+:103D400000EF00E0302080F3118862B60C4B0D4A82
+:103D5000D96821F4E0610904090C0A43DA60D3F858
+:103D6000FC20094942F08072C3F8FC200A6842F046
+:103D700001020A602022DA7783F82200704700BF30
+:103D800000ED00E00003FA05001000E010B530235C
+:103D900083F311880E4B5B6813F4006314D0F1EECB
+:103DA000103AEFF30984683C4FF08073E361094BEC
+:103DB000DB6B236684F3098800F074FB10B1064BBB
+:103DC000A36110BD054BFBE783F31188F9E700BF42
+:103DD00000ED00E000EF00E04306000846060008A2
+:103DE000026843681143016003B11847704700003F
+:103DF000024A136843F0C003136070470044004058
+:103E000013B50E4C204600F0B3FA04F114000C492F
+:103E1000009400234FF4807200F070F9094B0A49B6
+:103E200000944FF4807204F1380000F0E9F9074A79
+:103E3000074BC4E9172302B010BD00BFA05F0020EC
+:103E40000C600020F13D00080C610020004400409F
+:103E5000007A030A30B5037C214C002918BF0C46B8
+:103E6000012B0CD11F4B984209D11F4B9A6D42F484
+:103E700000329A659A6F42F400329A679B6F22680B
+:103E8000036EC16D846603EB5203B3FBF2F3626809
+:103E9000150442BF23F0070503F0070343EA450377
+:103EA000CB60A36843F040034B60E36843F0010339
+:103EB0008B6042F4967343F001030B604FF0FF33C5
+:103EC0000B62510505D512F0102205D0B2F1805FCA
+:103ED00004D080F8643030BD7F23FAE73F23F8E751
+:103EE00038540008A05F0020001002402DE9F04780
+:103EF000C66D3768F46934622107054619D014F09D
+:103F0000080118BF4FF48071E20748BF41F020015B
+:103F1000A30748BF41F04001600748BF41F080015E
+:103F2000302383F31188281DFFF75AFF002383F302
+:103F30001188E2050AD5302383F311884FF480619C
+:103F4000281DFFF74DFF002383F311884FF0300940
+:103F50004FF0000A14F0200838D13B0616D54FF078
+:103F6000300905F1380A200610D589F3118850462A
+:103F700000F07AF9002836DA0821281DFFF730FF13
+:103F800027F080033360002383F31188790614D56A
+:103F9000620612D5302383F31188D5E913239A42A0
+:103FA00008D12B6C33B11021281D27F04007FFF7F3
+:103FB00017FF3760002383F31188E30618D5AA6E34
+:103FC0001369ABB1BDE8F0475069184789F3118810
+:103FD000736A95F864102846194000F0E3F98AF3F3
+:103FE0001188F469B6E7B06288F31188F469BAE71A
+:103FF000BDE8F0874FF0E023002258684FF0FF3112
+:10400000930003F1604303F5614301329042C3F82A
+:104010008010C3F88011F3D27047000000F16043B4
+:1040200003F561430901C9B283F80013012200F0CE
+:104030001F039A4043099B0003F1604303F561436A
+:10404000C3F880211A607047F8B515468268066982
+:10405000AA420B46816938BF8568761AB542044684
+:104060000BD218462A46FDF749FCA3692B44A361ED
+:10407000A3685B1BA3602846F8BD0CD918463246DE
+:10408000FDF73CFCAF1BE1683A463044FDF736FCD7
+:10409000E3683B44EBE718462A46FDF72FFCE3684C
+:1040A000E5E7000083689342F7B51546044638BF3C
+:1040B0008568D0E90460361AB5420BD22A46FDF76E
+:1040C0001DFC63692B446361A36828465B1BA360E6
+:1040D00003B0F0BD0DD932460191FDF70FFC0199F7
+:1040E000E068AF1B3A463144FDF708FCE3683B4407
+:1040F000E9E72A46FDF702FCE368E4E710B50A4465
+:104100000024C361029B8460C0E90000C0E905117E
+:10411000C1600261036210BD08B5D0E90532934267
+:1041200001D1826882B98268013282605A1C426180
+:104130001970D0E904329A4224BFC3684361002158
+:1041400000F078FA002008BD4FF0FF30FBE70000D8
+:1041500070B5302304460E4683F31188A568A5B1D7
+:10416000A368A269013BA360531CA361157822696F
+:10417000934224BFE368A361E3690BB120469847EB
+:10418000002383F31188284607E03146204600F0DB
+:1041900041FA0028E2DA85F3118870BD2DE9F74F66
+:1041A00004460E4617469846D0F81C904FF0300A49
+:1041B0008AF311884FF0000B154665B12A46314647
+:1041C0002046FFF741FF034660B94146204600F014
+:1041D00021FA0028F1D0002383F31188781B03B063
+:1041E000BDE8F08FB9F1000F03D001902046C84719
+:1041F000019B8BF31188ED1A1E448AF31188DCE7CA
+:10420000C0E90511C160C3611144009B8260C0E92F
+:104210000000016103627047F8B504460D4616467A
+:10422000302383F31188A768A7B1A368013BA3607B
+:1042300063695A1C62611D70D4E904329A4224BF3A
+:10424000E3686361E3690BB120469847002080F37F
+:10425000118807E03146204600F0DCF90028E2DA58
+:1042600087F31188F8BD0000D0E905239A4210B504
+:1042700001D182687AB98268013282605A1C8261F7
+:104280001C7803699A4224BFC3688361002100F04F
+:10429000D1F9204610BD4FF0FF30FBE72DE9F74F75
+:1042A00004460E4617469846D0F81C904FF0300A48
+:1042B0008AF311884FF0000B154665B12A46314646
+:1042C0002046FFF7EFFE034660B94146204600F066
+:1042D000A1F90028F1D0002383F31188781B03B0E3
+:1042E000BDE8F08FB9F1000F03D001902046C84718
+:1042F000019B8BF31188ED1A1E448AF31188DCE7C9
+:10430000026843681143016003B118477047000019
+:104310001430FFF743BF00004FF0FF331430FFF7B6
+:104320003DBF00003830FFF7B9BF00004FF0FF334A
+:104330003830FFF7B3BF00001430FFF709BF0000AB
+:104340004FF0FF311430FFF703BF00003830FFF7A4
+:1043500063BF00004FF0FF323830FFF75DBF000051
+:10436000012914BF6FF0130000207047FFF748BD0C
+:10437000044B03600023C0E902334360012303744C
+:10438000704700BF5054000810B53023044683F333
+:104390001188FFF75FFD02232374002080F311884A
+:1043A00010BD000038B5C36904460D461BB9042191
+:1043B0000844FFF7A5FF294604F11400FFF7ACFEFF
+:1043C000002806DA201D4FF40061BDE83840FFF7F1
+:1043D00097BF38BD00230375826803691B6899681D
+:1043E0009142FBD25A680360426010605860704787
+:1043F00000230375826803691B6899689142FBD8A2
+:104400005A680360426010605860704708B50846FB
+:10441000302383F311880B7D032B05D0042B0DD0A3
+:104420002BB983F3118808BD8B6900221A604FF005
+:10443000FF338361FFF7CEFF0023F2E7D1E90032BB
+:1044400013605A60F3E70000FFF7C4BF054BD9685B
+:104450000875186802681A60536001220275D860F6
+:10446000FCF7DAB81062002030B50C4BDD684B1C4D
+:1044700087B004460FD02B46094A684600F06CF915
+:104480002046FFF7E3FF009B13B1684600F06EF98A
+:10449000A86907B030BDFFF7D9FFF9E71062002027
+:1044A0000D440008044B1A68DB6890689B689842CA
+:1044B00094BF00200120704710620020084B10B507
+:1044C0001C68D86822681A60536001222275DC607B
+:1044D000FFF78EFF01462046BDE81040FCF79CB870
+:1044E00010620020044B1A68DB6892689B689A424D
+:1044F00001D9FFF7E3BF70471062002038B5074CC1
+:1045000007490848012300252370656000F030FC4E
+:104510000223237085F3118838BD00BF7864002022
+:104520007C5400081062002008B572B6044B186570
+:1045300000F0E6FA00F09EFB024B03221A70FEE741
+:10454000106200207864002000F046B9EFF311807B
+:1045500020B9EFF30583302282F311887047000001
+:1045600010B530B9EFF30584C4F3080414B180F337
+:10457000118810BDFFF7B6FF84F31188F9E700003A
+:104580008B60022308618B82084670478368A3F121
+:10459000840243F8142C026943F8442C426943F81E
+:1045A000402C094A43F8242CC26843F8182C0222F4
+:1045B00003F80C2C002203F80B2C044A43F8102CAF
+:1045C000A3F12000704700BF3106000810620020F0
+:1045D00008B5FFF7DBFFBDE80840FFF735BF000077
+:1045E000024BDB6898610F20FFF730BF106200209C
+:1045F000302383F31188FFF7F3BF000008B50146AD
+:10460000302383F311880820FFF72EFF002383F364
+:10461000118808BD064BDB6839B1426818605A60E2
+:10462000136043600420FFF71FBF4FF0FF30704757
+:10463000106200200368984206D01A680260506039
+:1046400099611846FFF700BF7047000010B5036876
+:104650009C68A2420CD85C688A600B604C60216048
+:10466000596099688A1A9A604FF0FF33836010BDD1
+:104670001B68121BECE700000A2938BF0A2170B53D
+:1046800004460D460A26601900F06CFB00F058FB4A
+:10469000041BA54203D8751C2E460446F3E70A2ED8
+:1046A00004D9BDE87040012000F0A2BB70BD00003D
+:1046B000F8B5144B0D46D96103F1100141600A2A87
+:1046C0001969826038BF0A22016048601861A81821
+:1046D000144600F039FB0A2700F032FB431BA342CB
+:1046E000064606D37C1C281900F03CFB27463546BD
+:1046F000F2E70A2F04D9BDE8F840012000F078BBAA
+:10470000F8BD00BF10620020F8B506460D4600F067
+:1047100017FB0F4A134653F8107F9F4206D12A46D3
+:1047200001463046BDE8F840FFF7C2BFD169BB681B
+:10473000441A2C1928BF2C46A34202D92946FFF758
+:104740009BFF224631460348BDE8F840FFF77EBF95
+:10475000106200202062002010B4C0E9032300236F
+:104760005DF8044B4361FFF7CFBF000010B5194C53
+:10477000236998420DD0D0E90032816813605A60F5
+:104780009A680A449A60002303604FF0FF33A361E4
+:1047900010BD2346026843F8102F536000220260C8
+:1047A00022699A4203D1BDE8104000F0D5BA93685F
+:1047B00081680B44936000F0C3FA2269E169926852
+:1047C000441AA242E4D91144BDE81040091AFFF787
+:1047D00053BF00BF106200202DE9F047DFF8BC8016
+:1047E00008F110072C4ED8F8105000F0A9FAD8F8AC
+:1047F0001C40AA68031B9A423ED81444D5E90032F3
+:104800004FF00009C8F81C4013605A60C5F80090CA
+:10481000D8F81030B34201D100F09EFA89F3118824
+:10482000D5E9033128469847302383F311886B6913
+:10483000002BD8D000F084FA6A69A0EB04094A453D
+:1048400082460DD2022000F0D3FA0022D8F81030B0
+:10485000B34208D151462846BDE8F047FFF728BFCC
+:10486000121A2244F2E712EB090938BF4A462946D8
+:104870003846FFF7EBFEB5E7D8F81030B34208D062
+:104880001444211AC8F81C00A960BDE8F047FFF7DE
+:10489000F3BEBDE8F08700BF206200201062002058
+:1048A00000207047FEE70000704700004FF0FF3027
+:1048B00070470000BFF34F8F024A1369DB03FCD43B
+:1048C000704700BF0020024008B5094B1B7873B940
+:1048D000FFF7F0FF074B5A69002ABFBF064A9A60EC
+:1048E00002F188329A601A6822F480621A6008BD68
+:1048F00090640020002002402301674508B50B4B5F
+:104900001B7893B9FFF7D6FF094B5A6942F0004272
+:104910005A611A6842F480521A601A6822F480526E
+:104920001A601A6842F480621A6008BD9064002020
+:1049300000200240FF289ABF00F58030C00200200E
+:10494000704700004FF40060704700004FF4807023
+:1049500070470000FF2808B50BD8FFF7EBFF00F504
+:1049600000630268013204D104308342F9D101208E
+:1049700008BD0020FCE70000FF2838B5044626D813
+:10498000FFF7E4FDFFF796FFFFF79EFF114BF322C1
+:104990001A6102225A615A6942EAC4025A615A698A
+:1049A00042F480325A6105462046FFF783FF4FF4F8
+:1049B0000061FFF7BFFF00F059F92846FFF79EFF9F
+:1049C000FFF7CEFD2046BDE83840FFF7C3BF00200B
+:1049D00038BD00BF0020024040EA020313F0070385
+:1049E0002DE9F04705460C46164606D0344B40F2FA
+:1049F00031321A600020BDE8F0878118314A9142B7
+:104A00000CD92F4A40F236311160F3E72B1D1B6899
+:104A10006268934208D1083E08350834072E19D938
+:104A20002A6823689A42F1D0FFF790FDFFF74CFF08
+:104A3000FFF740FF04F10801234C4FF001084FF04D
+:104A40000009012EA1F1080708D8FFF757FFFFF76B
+:104A500087FD01E0002EE7D10120CCE7C4F81480E7
+:104A6000AA4651F8083C4AF8043B51F8043C6B60F4
+:104A7000FFF720FF236943F001032361C4F814907A
+:104A80002A6851F8083C9A420ED00D4B40F25E3233
+:104A90001A600E4B1D600E4B1E600E4B1F60FFF721
+:104AA0002DFFFFF75DFDA5E7DAF800A051F8043C03
+:104AB0009A4501F10801E8D1083E0835C1E700BF79
+:104AC0008C64002000000808002002408064002060
+:104AD0008864002084640020084908B50B7828B158
+:104AE0001BB9FFF7F1FE01230B7008BD002BFCD0B2
+:104AF000BDE808400870FFF701BF00BF90640020C8
+:104B000008B54FF4C0314FF0005000F0B1F8BDE8E7
+:104B100008404FF400414FF0805000F0A9B8000069
+:104B2000084600F0F3BB000070B582B0FFF70EFD41
+:104B30000E4E054600F004F93268904237BF0C4A29
+:104B40000B49516814682EBFD1E900410131516011
+:104B50000419034641F10001284601913360FFF733
+:104B6000FFFC0199204602B070BD00BF9464002094
+:104B70009864002070B582B0FFF7E8FC104E05463F
+:104B800000F0DEF83268904237BF0E4A0D49516896
+:104B900014682EBFD1E9004101315160041941F17F
+:104BA00000010346284601913360FFF7D9FC0199C3
+:104BB0004FF47A7200232046FBF71AFB02B070BD57
+:104BC00094640020986400200244D2B2904200D144
+:104BD0007047431C800000F1804000F514500068CD
+:104BE00041F8040BD8B2F1E7124B10B5D3F890405E
+:104BF000240409D4D3F89040C3F89040D3F89040EF
+:104C000044F40044C3F890400B4C2368024443F43E
+:104C100080732360D2B2904200D110BD431C80004B
+:104C200000F1804000F5145051F8044B0460D8B2F4
+:104C3000F1E700BF001002400070004007B50122FC
+:104C400001A90020FFF7C0FF019803B05DF804FB45
+:104C500013B50446FFF7F2FFA04205D0012201A9D7
+:104C600000200194FFF7C0FF02B010BD70470000A4
+:104C70007047000070470000074B45F255521A601C
+:104C800002225A6040F6FF729A604CF6CC421A60DB
+:104C9000024B01221A70704700300040A4640020CB
+:104CA000034B1B781BB1034B4AF6AA221A607047CC
+:104CB000A464002000300040054B1A6832B902F1AC
+:104CC000804202F50432D2F894201A60704700BF87
+:104CD000A0640020024B4FF40002C3F894207047F8
+:104CE0000010024008B5FFF7E7FF024B1868C0F359
+:104CF000407008BDA064002070470000FEE700007F
+:104D00000A4B0B480B4A90420BD30B4BDA1C121A7E
+:104D1000C11E22F003028B4238BF00220021FCF7A3
+:104D2000FFBD53F8041B40F8041BECE7EC550008EA
+:104D300028650020286500202865002000F0C2B802
+:104D40004FF08043586A70474FF080430022586309
+:104D50001A610222DA6070474FF080430022DA6065
+:104D6000704700004FF0804358637047FEE7000033
+:104D700070B51B4B01630025044686B05860856200
+:104D80000E46FEF7DFFF04F11003C4E904334FF0D1
+:104D9000FF33C4E90635C4E90044A560E562FFF7C6
+:104DA000CFFF2B460246C4E9082304F134010D4A23
+:104DB000256580232046FFF7E3FB0123E0600A4AD4
+:104DC0000375009272680192B268CDE90223074B25
+:104DD0006846CDE90435FFF7FBFB06B070BD00BFA8
+:104DE00078640020885400088D5400086D4D000838
+:104DF000024AD36A1843D062704700BF1062002095
+:104E00004B6843608B688360CB68C3600B69436108
+:104E10004B6903628B6943620B6803607047000053
+:104E200008B5204BDA6A42F07F02DA62DA6A22F0D1
+:104E30007F02DA62DA6ADA6C42F07F02DA64DA6EF2
+:104E400042F07F02DA66184ADB6E11464FF090405E
+:104E5000FFF7D6FF02F11C0100F58060FFF7D0FFDD
+:104E600002F1380100F58060FFF7CAFF02F154013A
+:104E700000F58060FFF7C4FF02F1700100F580606B
+:104E8000FFF7BEFF02F18C0100F58060FFF7B8FF6D
+:104E900002F1A80100F58060FFF7B2FFBDE808400D
+:104EA00000F050B8001002409454000808B500F01B
+:104EB000FBF9FFF723FBBDE80840FFF7FDBE00004C
+:104EC000704700000F4B9A6D42F001029A659A6F8D
+:104ED00042F001029A670C4A9B6F936843F001030A
+:104EE00093604FF08043A7229A624FF0FF32DA625C
+:104EF00000229A615A63DA605A6001225A611A608C
+:104F0000704700BF00100240002004E04FF08042D4
+:104F100008B51169D3680B40D9B2C9439B07116129
+:104F200007D5302383F31188FFF70EFB002383F3AB
+:104F3000118808BD08B5FFF75DF8BDE8084000F02E
+:104F40008BB900004E4B4FF0FF319A6A99629A6A12
+:104F500000229A62986AD86A60F07F00D862D86AA4
+:104F600000F07F00D862D86A186B1963186B1A6357
+:104F7000186B986B9963986B9A63986BD86BD9632D
+:104F8000D86BDA63D86B186C1964196C1A64196CD5
+:104F9000196E41F001011966D3F8801021F001016A
+:104FA000C3F88010D3F88010996D41F08051996555
+:104FB000996F21F080519967996F32494FF4004001
+:104FC0008860CA600A624A628A62CA620A634A6385
+:104FD0008A63CA630A644A648A64CA640A654A6561
+:104FE0004A604FF48072C1F880204FF440720A602A
+:104FF0004A6912F48062FBD1D3F8901011F4407F1B
+:105000001EBF4FF48031C3F89010C3F89020D3F83E
+:10501000982042F00102C3F89820D3F89820920714
+:10502000FBD51A6842F480321A601A689003FCD5E6
+:10503000D3F8902022F00322C3F89020124ADA60BD
+:105040001A6842F080721A601A689101FCD50F4903
+:105050000F4800229A60C3F888100E49C3F89C20BC
+:10506000016002684A401207FBD19A6842F00302CD
+:105070009A609A6802F00C020C2AFAD1704700BFBD
+:105080000010024000700040132A610155010050D9
+:105090000020024004070400074A08B5536903F0E2
+:1050A0000103536123B1054A13680BB15068984757
+:1050B000BDE80840FEF76ABE00040140A864002075
+:1050C000074A08B5536903F00203536123B1054A47
+:1050D00093680BB1D0689847BDE80840FEF756BE0C
+:1050E00000040140A8640020074A08B5536903F092
+:1050F0000403536123B1054A13690BB15069984702
+:10510000BDE80840FEF742BE00040140A86400204C
+:10511000074A08B5536903F00803536123B1054AF0
+:1051200093690BB1D0699847BDE80840FEF72EBEE1
+:1051300000040140A8640020074A08B5536903F041
+:105140001003536123B1054A136A0BB1506A9847A3
+:10515000BDE80840FEF71ABE00040140A864002024
+:10516000164B10B55C6904F478725A61A30604D535
+:10517000134A936A0BB1D06A9847600604D5104A67
+:10518000136B0BB1506B9847210604D50C4A936BF7
+:105190000BB1D06B9847E20504D5094A136C0BB1EB
+:1051A000506C9847A30504D5054A936C0BB1D06C9D
+:1051B0009847BDE81040FEF7E9BD00BF000401407C
+:1051C000A8640020194B10B55C6904F47C425A6154
+:1051D000620504D5164A136D0BB1506D984723052F
+:1051E00004D5134A936D0BB1D06D9847E00404D5F4
+:1051F0000F4A136E0BB1506E9847A10404D50C4AA8
+:10520000936E0BB1D06E9847620404D5084A136FB1
+:105210000BB1506F9847230404D5054A936F0BB127
+:10522000D06F9847BDE81040FEF7B0BD00040140C4
+:10523000A864002008B50348FEF758FEBDE8084002
+:10524000FEF7A4BDA05F002008B5FFF75FFEBDE834
+:105250000840FEF79BBD0000062108B50846FEF792
+:10526000DDFE06210720FEF7D9FE06210820FEF705
+:10527000D5FE06210920FEF7D1FE06210A20FEF701
+:10528000CDFE06211720FEF7C9FE06212820FEF7D5
+:10529000C5FE07211C20FEF7C1FEBDE808400C2119
+:1052A0002620FEF7BBBE000008B5FFF743FE00F066
+:1052B00009F8FFF75BF8FFF703FEBDE80840FFF7CA
+:1052C0003DBD00000023054A19460133102BC2E9F9
+:1052D000001102F10802F8D1704700BFA864002055
+:1052E0000B460146184600F003B8000000F00EB867
+:1052F00010B5054C13462CB10A4601460220AFF307
+:10530000008010BD2046FCE700000000024B014673
+:105310001868FFF705BC00BF2823002010B501392D
+:105320000244904201D1002005E0037811F8014FBA
+:10533000A34201D0181B10BD0130F2E72DE9F04166
+:10534000A3B1C91A17780144044603F1FF3C8C420B
+:10535000204601D9002009E00578BD4204F101048E
+:10536000F5D10CEB0405D618A54201D1BDE8F081BA
+:1053700015F8018D16F801EDF045F5D0E7E70000CE
+:10538000034611F8012B03F8012B002AF9D17047CD
+:105390006F72672E6172647570696C6F742E486FDE
+:1053A0006C7962726F47345F4750530053544D33EA
+:1053B0003247343F3F00000040A2E4F164689106A8
+:1053C0000041A3E5F2656992070000004261642094
+:1053D00043414E496661636520696E6465782E00BD
+:1053E000000100000001FF00006400400068004070
+:1053F0000000000000000000ED240008C91F0008A4
+:10540000052C0008C11F0008712000085522000863
+:10541000392000080120000805200008DD1F0008D1
+:10542000C51F000815220008E91F0008712D00089B
+:10543000F51F0008E92100080096000000000000A8
+:10544000000000000000000000000000000000005C
+:10545000000000002D4300081943000855430008D0
+:10546000414300084D430008394300082543000824
+:1054700011430008614300086330000078540008BD
+:1054800068620020786400206D61696E0069646C58
+:1054900065000000A000802A00000000AAAAAAAAB5
+:1054A00050000024FFFF000000770000009009007A
+:1054B0000400005A00000000AAAAAA9A04000000F2
+:1054C000FFBF000000000000000099000011101450
+:1054D00000000000AAAAAAA600010010FFDF000039
+:1054E00000000000000000000000000000000000BC
+:1054F000AAAAAAAA00000000FFFF00000000000006
+:10550000000000000000000000000000AAAAAAAAF3
+:1055100000000000FFFF000000000000000000008D
+:105520000000000000000000AAAAAAAA00000000D3
+:10553000FFFF00000000000000000000000000006D
+:1055400000000000AAAAAAAA00000000FFFF0000B5
+:105550000000000000000000C8ACFF7F0100000058
+:105560001D040000000000000070070000000000A3
+:10557000FE2A0100D2040000FF000000A05F00200E
+:1055800000000000AC5300082C23002000000000A5
+:10559000000000000000000000000000000000000B
+:1055A00000000000000000000000000000000000FB
+:1055B00000000000000000000000000000000000EB
+:1055C00000000000000000000000000000000000DB
+:1055D00000000000000000000000000000000000CB
+:0C55E000000000000000000000000000BF
:00000001FF
diff --git a/Tools/bootloaders/JFB100_bl.bin b/Tools/bootloaders/JFB100_bl.bin
new file mode 100644
index 00000000000000..91535184bc58f8
Binary files /dev/null and b/Tools/bootloaders/JFB100_bl.bin differ
diff --git a/Tools/bootloaders/JFB100_bl.hex b/Tools/bootloaders/JFB100_bl.hex
new file mode 100644
index 00000000000000..fa59ae0b72b054
--- /dev/null
+++ b/Tools/bootloaders/JFB100_bl.hex
@@ -0,0 +1,1047 @@
+:020000040800F2
+:1000000000060220010200080302000803020008A3
+:1000100003020008030200080302000803020008AC
+:100020000302000803020008030200086538000804
+:10003000030200080302000803020008030200088C
+:10004000030200080302000803020008030200087C
+:100050000302000803020008093B0008313B0008C6
+:10006000593B0008813B0008A93B00080302000837
+:10007000030200080302000803020008030200084C
+:10008000030200080302000803020008030200083C
+:10009000030200080302000803020008D13B000825
+:1000A000030200080302000803020008030200081C
+:1000B000CD3C000803020008030200080302000808
+:1000C00003020008030200080302000803020008FC
+:1000D0000302000803020008A53C00080302000810
+:1000E000353C000803020008030200080302000870
+:1000F00003020008030200080302000803020008CC
+:1001000003020008030200080302000803020008BB
+:1001100003020008030200080302000803020008AB
+:10012000030200080302000803020008030200089B
+:10013000030200080302000803020008030200088B
+:10014000030200080302000803020008DD2F000874
+:10015000030200080302000803020008030200086B
+:10016000030200080302000803020008030200085B
+:10017000030200080302000803020008030200084B
+:100180000302000803020008B93C0008030200084B
+:10019000030200080302000803020008030200082B
+:1001A000030200080302000803020008030200081B
+:1001B000030200080302000803020008030200080B
+:1001C00003020008030200080302000803020008FB
+:1001D00003020008030200080302000803020008EB
+:1001E00003020008030200080302000803020008DB
+:1001F00003020008030200080302000803020008CB
+:1002000002E000F000F8FEE772B6374880F3088895
+:10021000364880F3098836483649086040F20000C5
+:10022000CCF200004EF63471CEF200010860BFF34C
+:100230004F8FBFF36F8F40F20000C0F2F0004EF618
+:100240008851CEF200010860BFF34F8FBFF36F8F6C
+:100250004FF00000E1EE100A4EF63C71CEF20001C4
+:100260000860062080F31488BFF36F8F02F014FB40
+:1002700003F08AFA4FF055301F491B4A91423CBFA8
+:1002800041F8040BFAE71D49184A91423CBF41F876
+:10029000040BFAE71A491B4A1B4B9A423EBF51F81E
+:1002A000040B42F8040BF8E700201849184A914261
+:1002B0003CBF41F8040BFAE702F02CFB03F0C4FA50
+:1002C000144C154DAC4203DA54F8041B8847F9E787
+:1002D00000F042F8114C124DAC4203DA54F8041B02
+:1002E0008847F9E702F014BB000602200022022032
+:1002F0000000000808ED00E00000022000060220D7
+:10030000E040000800220220682202206822022029
+:10031000A0370220000200080002000800020008C6
+:10032000000200082DE9F04F2DED108AC1F80CD025
+:10033000D0F80CD0BDEC108ABDE8F08F002383F319
+:1003400011882846A047002001F044FEFEE701F096
+:10035000ADFD00DFFEE7000038B502F05DFA0546AE
+:1003600002F090FA0446D0B90F4B9D4219D00133E8
+:100370009D4241F2883512BF044600250124002029
+:1003800002F054FA0CB100F077F800F069FD00F0CB
+:10039000FDFB284600F0F2F800F06EF8F9E70025C2
+:1003A000EDE70546EBE700BF010007B008B500F038
+:1003B000B9FBA0F120035842584108BD07B541F2EE
+:1003C0001203022101A8ADF8043000F0C9FB03B00C
+:1003D0005DF804FB38B5302383F3118817480368B0
+:1003E0000BB101F0C3FE0023154A4FF47A71134894
+:1003F00001F0B2FE002383F31188124C236813B17D
+:100400002368013B2360636813B16368013B636049
+:100410000D4D2B7833B963687BB9022000F092FC54
+:10042000322363602B78032B07D163682BB902203A
+:1004300000F088FC4FF47A73636038BD68220220B4
+:10044000D50300088823022080220220084B187060
+:1004500003280CD8DFE800F008050208022000F0AD
+:1004600063BC022000F050BC024B00225A6070476F
+:100470008022022088230220F8B53B4B3B4A1C46D1
+:10048000196801316ED004339342F9D16268A242F7
+:1004900068D3374B9B6803F1006303F500439A422E
+:1004A00060D2002000F08CFB0220FFF7CFFF314B21
+:1004B00000211A6C19641A6E19661A6E5A6C596406
+:1004C0005A6E59665A6E1A6942F000521A611A69D8
+:1004D00022F000521A611B6972B64FF0E023C3F894
+:1004E000084DD4E90004BFF34F8FBFF36F8F224A4A
+:1004F000C2F88410BFF34F8F536923F480335361E4
+:10050000BFF34F8FD2F8803043F6E076C3F3C905CE
+:10051000C3F34E335B0103EA060C29464CEA8177AC
+:100520000139C2F87472F9D2203B13F1200FF2D1D5
+:10053000BFF34F8FBFF36F8FBFF34F8FBFF36F8F3B
+:10054000536923F4003353610023C2F85032BFF3E0
+:100550004F8FBFF36F8F302383F31188854680F36D
+:1005600008882047F8BD00BF0080000820800008F0
+:10057000002202200038024000ED00E02DE9F04F9B
+:1005800093B0B44B2022FF2100900AA89D6800F090
+:1005900011FCB14A1378A3B90121B048117003606E
+:1005A000302383F3118803680BB101F0DFFD0023D2
+:1005B000AB4A4FF47A71A94801F0CEFD002383F3D2
+:1005C0001188009B13B1A74B009A1A60A64A1378B2
+:1005D000032B03D000231370A24A53604FF0000A8C
+:1005E000009CD3465646D146012000F09DFB24B125
+:1005F0009C4B1B68002B00F02682002000F092FA32
+:100600000390039B002BF2DB012000F07DFB039B9A
+:10061000213B1F2BE8D801A252F823F09D060008C9
+:10062000C506000859070008E9050008E9050008A3
+:10063000E9050008EB070008BB090008D508000819
+:10064000370900085F09000885090008E905000866
+:1006500097090008E9050008090A00083D07000895
+:10066000E90500084D0A0008A90600083D07000832
+:10067000E905000837090008E9050008E905000850
+:10068000E9050008E9050008E9050008E905000892
+:10069000E9050008E9050008590700080220FFF7EE
+:1006A00085FE002840F0F981009B022105A8BAF1DF
+:1006B000000F08BF1C4641F21233ADF8143000F0B1
+:1006C0004FFA91E74FF47A7000F02CFA071EEBDB3B
+:1006D0000220FFF76BFE0028E6D0013F052F00F255
+:1006E000DE81DFE807F0030A0D101336052304212D
+:1006F00005A8059300F034FA17E004215548F9E7FE
+:1007000004215A48F6E704215948F3E74FF01C0842
+:10071000404608F1040800F055FA0421059005A8A8
+:1007200000F01EFAB8F12C0FF2D101204FF00009B1
+:1007300000FA07F747EA0B0B5FFA8BFB00F086FB2A
+:1007400026B10BF00B030B2B08BF0024FFF736FE7E
+:100750004AE704214748CDE7002EA5D00BF00B0354
+:100760000B2BA1D10220FFF721FE074600289BD0CA
+:100770000120002600F024FA0220FFF767FE5FFA4E
+:1007800086F8404600F02CFA0446B0B10399404682
+:100790000136A1F140025142514100F031FA0028E6
+:1007A000EDD1BA46044641F21213022105A83E4695
+:1007B000ADF8143000F0D4F916E725460120FFF714
+:1007C00045FE244B9B68AB4207D9284600F0FAF956
+:1007D000013040F067810435F3E70025224BBA462B
+:1007E0003E461D701F4B5D60A8E7002E3FF45CAFD6
+:1007F0000BF00B030B2B7FF457AF0220FFF726FE05
+:10080000322000F08FF9B0F10008FFF64DAF18F07C
+:1008100003077FF449AF0F4A08EB05039268934240
+:100820003FF642AFB8F5807F3FF73EAF124BB84579
+:10083000019323DD4FF47A7000F074F90390039A6A
+:10084000002AFFF631AF039A0137019B03F8012B11
+:10085000EDE700BF0022022084230220682202204C
+:10086000D5030008882302208022022004220220CF
+:10087000082202200C22022084220220C820FFF736
+:1008800095FD074600283FF40FAF1F2D11D8C5F185
+:1008900020020AAB25F0030084494245184428BFD2
+:1008A0004246019200F060FA019AFF217F4800F071
+:1008B00081FA4FEAA803C8F387027C4928460193CE
+:1008C00000F080FA064600283FF46DAF019B05EB6F
+:1008D000830533E70220FFF769FD00283FF4E4AE0B
+:1008E00000F0BAF900283FF4DFAE0027B846704B9D
+:1008F0009B68BB4218D91F2F11D80A9B01330ED019
+:1009000027F0030312AA134453F8203C05934046F2
+:10091000042205A9043700F001FB8046E7E73846CA
+:1009200000F050F90590F2E7CDF81480042105A8F5
+:1009300000F016F902E70023642104A8049300F0F4
+:1009400005F900287FF4B0AE0220FFF72FFD002844
+:100950003FF4AAAE049800F067F90590E6E700239B
+:10096000642104A8049300F0F1F800287FF49CAE01
+:100970000220FFF71BFD00283FF496AE049800F01C
+:1009800063F9EAE70220FFF711FD00283FF48CAE7F
+:1009900000F072F9E1E70220FFF708FD00283FF4BC
+:1009A00083AE05A9142000F06DF9074604210490D8
+:1009B00004A800F0D5F83946B9E7322000F0B2F8C3
+:1009C000071EFFF671AEBB077FF46EAE384A07EB29
+:1009D0000903926893423FF667AE0220FFF7E6FCF8
+:1009E00000283FF461AE27F003074F44B9453FF4B8
+:1009F000A5AE484609F1040900F0E4F80421059089
+:100A000005A800F0ADF8F1E74FF47A70FFF7CEFCDF
+:100A100000283FF449AE00F01FF9002844D00A9B9B
+:100A200001330BD008220AA9002000F0CBF90028DE
+:100A30003AD02022FF210AA800F0BCF9FFF7BEFC43
+:100A40001C4801F0CDFA13B0BDE8F08F002E3FF442
+:100A50002BAE0BF00B030B2B7FF426AE002364218F
+:100A600005A8059300F072F8074600287FF41CAE35
+:100A70000220FFF79BFC804600283FF415AEFFF7ED
+:100A80009DFC41F2883001F0ABFA059800F024FAA1
+:100A900046463C4600F0DAF9A6E506464EE64FF03B
+:100AA000000901E6BA467EE637467CE6842202204B
+:100AB00000220220A08601002DE9F84F4FF47A733E
+:100AC00006460D46002402FB03F7DFF85080DFF8EE
+:100AD000509098F900305FFA84FA5A1C01D0A34272
+:100AE00010D159F824002A4631460368D3F820B0C3
+:100AF0003B46D847854205D1074B012083F800A02B
+:100B0000BDE8F88F0134032CE3D14FF4FA7001F003
+:100B100067FA0020F4E700BFD4230220102202204D
+:100B200014220220002307B5024601210DF107001F
+:100B30008DF80730FFF7C0FF20B19DF8070003B024
+:100B40005DF804FB4FF0FF30F9E700000A4604218E
+:100B500008B5FFF7B1FF80F00100C0B2404208BD08
+:100B6000074B0A4630B41978064B53F8214001462A
+:100B700023682046DD69044BAC4630BC604700BFAB
+:100B8000D423022014220220A086010070B50A4E50
+:100B900000240A4D01F032FD3080286833888342FA
+:100BA00008D901F025FD2B6804440133B4F5004F4A
+:100BB0002B60F2D370BD00BFD62302209023022009
+:100BC00001F0DEBD00F1006000F5004000687047F4
+:100BD00000F10060920000F5004001F05DBD0000F2
+:100BE000054B1A68054B1B889B1A834202D9104497
+:100BF00001F0FEBC0020704790230220D623022083
+:100C000038B50446074D29B128682044BDE838406E
+:100C100001F00EBD2868204401F0F2FC0028F3D05A
+:100C200038BD00BF9023022010F0030309D1B0F5B6
+:100C3000846F04D200F10050A0F5712003681846BB
+:100C400070470023FBE7000000F10050A0F5712081
+:100C5000D0F8200470470000064991F8243033B1E1
+:100C600000230822086A81F82430FFF7B1BF012071
+:100C7000704700BF94230220014B1868704700BFE3
+:100C8000002004E01E4B0138F0B51D680A1803234C
+:100C90001C482E0CC5F30B0435460788A7420BD120
+:100CA00044680B46013C934218461BD214F9010FCD
+:100CB00048B103F8010BF6E7013B00F10800ECD165
+:100CC00091420ED20B4618462C24B6F5805F00F8F0
+:100CD000014B0AD1824202D94122981C5A70401A13
+:100CE000F0BD0846B6F5805FF9D041F201039D42A0
+:100CF000F5D18242F3D95A2300F8013BEFE700BF58
+:100D0000002004E020220220022804D1054B4FF4E9
+:100D100080029A6170470128FCD1024B4FF4000217
+:100D2000F7E700BF00080240022803D1044B40222D
+:100D30009A6170470128FCD1014B8022F8E700BF7F
+:100D400000080240022805D1064A536983F0400397
+:100D5000536170470128FCD1024A536983F0800334
+:100D6000F6E700BF00080240002310B5934203D00D
+:100D7000CC5CC4540133F9E710BD0000013810B554
+:100D800010F9013F3BB191F900409C4203D11AB1E7
+:100D90000131013AF4E71AB191F90020981A10BD17
+:100DA0001046FCE703460246D01A12F9011B00293F
+:100DB000FAD1704702440346934202D003F8011B64
+:100DC000FAE770472DE9F8431F4D14460746884659
+:100DD00095F8242052BBDFF870909CB395F824302E
+:100DE0002BB92022FF2148462F62FFF7E3FF95F839
+:100DF00024004146C0F1080205EB8000A24228BF52
+:100E00002246D6B29200FFF7AFFF95F82430A41B1C
+:100E100017441E449044E4B2F6B2082E85F82460CC
+:100E2000DBD1FFF719FF0028D7D108E02B6A03EBCD
+:100E300082038342CFD0FFF70FFF0028CBD10020E1
+:100E4000BDE8F8830120FBE794230220024B1A78C7
+:100E5000024B1A70704700BFD423022010220220D8
+:100E6000F8B5174C174800F0F3FB2146154800F081
+:100E70001BFC24681448E26E144ED2F80438144D5A
+:100E800043F002030F4FC2F8043801F0A9F82046DE
+:100E9000104900F011FDE26E0324D2F8043823F06B
+:100EA0000203C2F804384FF4E133336055F8040B01
+:100EB000B84202D0314600F02BFB013CF6D1F8BD20
+:100EC0009C3E0008202B022040420F00BC23022041
+:100ED00014220220A43E00080C4B70B50C4D0446B1
+:100EE0001E780C4B55F826209A420DD00A4B002153
+:100EF00018221846FFF75EFF0460014655F82600E9
+:100F0000BDE8704000F004BB70BD00BFD4230220D8
+:100F100014220220202B0220BC23022030B50A44D8
+:100F2000084D91420DD011F8013B5840082340F381
+:100F30000004013B2C4013F0FF0384EA5000F6D17B
+:100F4000EFE730BD2083B8ED0268436811430160CC
+:100F500003B1184770470000024A136843F0C0030A
+:100F60001360704700440040024A136843F0C00316
+:100F7000136070470078004037B51A4C1A4D204670
+:100F800000F0BAFA04F11400009400234FF48072C8
+:100F9000164900F077F94FF48072154904F13800D2
+:100FA0000094144B00F0F0F9134BC4E91735134CBF
+:100FB000204600F0A1FA04F1140000234FF48072DF
+:100FC0000F49009400F05EF90E4B4FF480720E4909
+:100FD00004F13800009400F0D7F90C4BC4E9173540
+:100FE00003B030BDD823022080F93703B02402209B
+:100FF000B0260220590F000800440040442402207B
+:10100000B0250220690F0008B027022000780040B8
+:10101000037C30B5274C002918BF0C46012B0CD19E
+:10102000254B984236D1254B1A6C42F400321A6493
+:101030001A6E42F400321A661B6E2268036EC16D8E
+:1010400003EB52038466B3FBF2F36268150442BFFC
+:1010500023F0070503F0070343EA4503CB60A368C9
+:1010600043F040034B60E36843F001038B6042F4BC
+:10107000967343F001030B604FF0FF330B62510591
+:1010800005D512F0102211D0B2F1805F10D080F897
+:10109000643030BD0A4B9842CFD1084B1A6C42F0F5
+:1010A00080421A641A6E42F08042C4E77F23EEE762
+:1010B0003F23ECE7B03D0008D8230220003802406F
+:1010C000442402202DE9F047C66D05463768F469CF
+:1010D000210734621AD014F0080118BF4FF4807150
+:1010E000E20748BF41F02001A3074FF0300348BF9B
+:1010F00041F04001600748BF41F0800183F311884F
+:10110000281DFFF721FF002383F31188E2050AD58C
+:10111000302383F311884FF48061281DFFF714FFFB
+:10112000002383F311884FF030094FF0000A14F0C8
+:10113000200838D13B0616D54FF0300905F1380AA2
+:10114000200610D589F31188504600F051F9002887
+:1011500036DA0821281DFFF7F7FE27F080033360F9
+:10116000002383F31188790614D5620612D5302343
+:1011700083F31188D5E913239A4208D12B6C33B13C
+:1011800027F040071021281DFFF7DEFE37600023FF
+:1011900083F31188E30618D5AA6E1369ABB15069C1
+:1011A000BDE8F047184789F31188736A284695F817
+:1011B0006410194000F0BAF98AF31188F469B6E7AF
+:1011C000B06288F31188F469BAE7BDE8F0870000DF
+:1011D000F8B51546826804460B46AA4200D28568D7
+:1011E000A1692669761AB5420BD218462A46FFF73E
+:1011F000BBFDA3692B44A3612846A3685B1BA360C6
+:10120000F8BD0CD9AF1B18463246FFF7ADFD3A4684
+:10121000E1683044FFF7A8FDE3683B44EBE718467C
+:101220002A46FFF7A1FDE368E5E7000083689342E3
+:10123000F7B50446154600D28568D4E90460361A2D
+:10124000B5420BD22A46FFF78FFD63692B446361D9
+:101250002846A3685B1BA36003B0F0BD0DD93246DE
+:10126000AF1B0191FFF780FD01993A46E0683144D8
+:10127000FFF77AFDE3683B44E9E72A46FFF774FD90
+:10128000E368E4E710B50A440024C361029B84606C
+:10129000C16002610362C0E90000C0E9051110BD30
+:1012A00008B5D0E90532934201D1826882B98268DB
+:1012B000013282605A1C426119700021D0E9043267
+:1012C0009A4224BFC368436100F0A6FE002008BD17
+:1012D0004FF0FF30FBE7000070B5302304460E46A8
+:1012E00083F31188A568A5B1A368A269013BA36037
+:1012F000531CA36115782269934224BFE368A3615C
+:10130000E3690BB120469847002383F311882846F0
+:1013100007E03146204600F06FFE0028E2DA85F350
+:10132000118870BD2DE9F74F04460E4617469846C2
+:10133000D0F81C904FF0300A8AF311884FF0000B60
+:10134000154665B12A4631462046FFF741FF034660
+:1013500060B94146204600F04FFE0028F1D000233E
+:1013600083F31188781B03B0BDE8F08FB9F1000F4B
+:1013700003D001902046C847019B8BF31188ED1ADA
+:101380001E448AF31188DCE7C160C361009B826060
+:101390000362C0E905111144C0E900000161704712
+:1013A000F8B504460D461646302383F31188A76826
+:1013B000A7B1A368013BA36063695A1C62611D70F9
+:1013C000D4E904329A4224BFE3686361E3690BB154
+:1013D00020469847002080F3118807E031462046D8
+:1013E00000F00AFE0028E2DA87F31188F8BD000059
+:1013F000D0E9052310B59A4201D182687AB9826892
+:101400000021013282605A1C82611C7803699A4271
+:1014100024BFC368836100F0FFFD204610BD4FF07C
+:10142000FF30FBE72DE9F74F04460E461746984676
+:10143000D0F81C904FF0300A8AF311884FF0000B5F
+:10144000154665B12A4631462046FFF7EFFE0346B2
+:1014500060B94146204600F0CFFD0028F1D00023BE
+:1014600083F31188781B03B0BDE8F08FB9F1000F4A
+:1014700003D001902046C847019B8BF31188ED1AD9
+:101480001E448AF31188DCE7026843681143016057
+:1014900003B11847704700001430FFF743BF000046
+:1014A0004FF0FF331430FFF73DBF00003830FFF737
+:1014B000B9BF00004FF0FF333830FFF7B3BF000073
+:1014C0001430FFF709BF00004FF0FF311430FFF771
+:1014D00003BF00003830FFF763BF00004FF0FF325A
+:1014E0003830FFF75DBF0000012914BF6FF0130013
+:1014F00000207047FFF740BD044B036000234360AA
+:10150000C0E9023301230374704700BFC83D0008DF
+:1015100010B53023044683F31188FFF779FD0223C9
+:101520000020237480F3118810BD000038B5C36912
+:1015300004460D461BB904210844FFF7A5FF2946C0
+:1015400004F11400FFF7ACFE002806DA201D4FF46A
+:101550000061BDE83840FFF797BF38BD02684368B7
+:101560001143016003B118477047000013B5446B85
+:10157000D4F8A4381A681178042915D1217C0229DD
+:1015800012D11979012312898B4013420CD101A980
+:1015900004F14C0001F0B4FFD4F8A4480246019BCA
+:1015A0002179206800F0D6F902B010BD143001F0A6
+:1015B00037BF00004FF0FF33143001F031BF00009F
+:1015C0004C3002F009B800004FF0FF334C3002F00D
+:1015D00003B80000143001F005BF00004FF0FF31E8
+:1015E000143001F0FFBE00004C3001F0D5BF000008
+:1015F0004FF0FF324C3001F0CFBF000000207047A9
+:10160000D0F8A4381A6810B511780446042917D107
+:10161000017C022914D15979012352898B4013424C
+:101620000ED1143001F098FE024648B1D4F8A44817
+:101630004FF4807361792068BDE8104000F078B9FC
+:1016400010BD0000406BFFF7DBBF000070470000DB
+:101650007FB5124B01250426044603600023057460
+:1016600000F1840243602946C0E902330C4B02902A
+:10167000143001934FF48073009601F049FE094B3A
+:1016800004F29442294604F14C000294CDE900632F
+:101690004FF4807301F010FF04B070BDF03D0008FE
+:1016A000451600086D1500080B68302282F311887A
+:1016B0000A7903EB820210624A790D3243F8220064
+:1016C0008A7912B103EB820318620223C0F8A418CE
+:1016D0000374002080F311887047000038B5037F41
+:1016E000044613B190F85430ABB90125201D0221F6
+:1016F000FFF734FF04F114006FF00101257700F0CB
+:1017000097FC04F14C0084F854506FF00101BDE8DF
+:10171000384000F08DBC38BD10B5012104460430BE
+:10172000FFF71CFF0023237784F8543010BD00001E
+:1017300038B504460025143001F002FE04F14C00D7
+:10174000257701F0D1FE201D84F854500121FFF7C8
+:1017500005FF2046BDE83840FFF752BF90F85C30E7
+:1017600003F06003202B06D190F85D200023212A8E
+:1017700003D81F2A06D800207047222AFBD1C0E9CF
+:10178000143303E0034A02650722426583650120A2
+:10179000704700BF38220220D0F8A43837B51A6845
+:1017A0000446117804291AD1017C022917D119792C
+:1017B000012312898B40134211D100F14C052846B8
+:1017C00001F052FF58B101A9284601F099FED4F862
+:1017D000A4480246019B2179206800F0BBF803B0C1
+:1017E00030BD000000EB8103F0B51E6A85B00446F1
+:1017F0000D46FEB1302383F3118804EB8507301DBD
+:101800000821FFF7ABFEFB6806F14C005B691B6823
+:101810001BB1019001F082FE019803A901F070FE56
+:10182000024648B1039B2946204600F093F8002366
+:1018300083F3118805B0F0BDFB685A691268002A6D
+:10184000F5D01B8A013B1340F1D104F15C02EAE7B9
+:101850000D3138B550F82140DCB1302383F31188C5
+:10186000D4F8A4281368527903EB8203DB689B69E0
+:101870005D6845B104216018FFF770FE294604F148
+:10188000140001F073FD2046FFF7BAFE002383F336
+:10189000118838BD7047000001F0C0B8012328222C
+:1018A000002110B5044600F8243BFFF783FA00231B
+:1018B000C4E9013310BD000038B50446302383F37A
+:1018C000118800254160C0E90355C0E90555C0E90C
+:1018D000075501F0B3F80223237085F311882846D9
+:1018E00038BD000070B500EB8103054650690E4617
+:1018F0001446DA6018B110220021FFF75BFAA069E4
+:1019000018B110220021FFF755FA31462846BDE8EC
+:10191000704001F05DB90000826802F0011282603F
+:101920000022C0E90422C0E90622026201F0DCB90B
+:10193000F0B4012500EB810447898D40E4683D4304
+:10194000A469458123600023A2606360F0BC01F0BC
+:10195000F7B90000F0B4012500EB810407898D4040
+:10196000E4683D436469058123600023A2606360ED
+:10197000F0BC01F071BA000070B5022300250446E6
+:1019800003704566056280F84C50C0E90255C0E915
+:101990000455C0E9065501F0B7F863681B6823B128
+:1019A00029462046BDE87040184770BD0378052BD6
+:1019B00010B504460AD080F86830052303704368E8
+:1019C0001B680BB1042198470023A36010BD0000E1
+:1019D0000178052906D190F86820436802701B68D9
+:1019E00003B118477047000070B590F84C300446BA
+:1019F00013B1002380F84C3004F15C02204601F062
+:101A000095F963689B68B3B994F85C3013F060058E
+:101A100035D00021204601F047FC0021204601F08E
+:101A200039FC63681B6813B10621204698470623DA
+:101A300084F84C3070BD204698470028E4D0B4F8B4
+:101A40006230626D9A4288BF636594F95C30656D5F
+:101A5000002B4FF0300380F20381002D00F0F28064
+:101A6000092284F84C2083F3118800212046D4E910
+:101A70001423FFF76FFF002383F31188DAE794F84C
+:101A80005D2003F07F0343EA022340F202329342D7
+:101A900000F0C58021D8B3F5807F48D00DD8012B48
+:101AA0003FD0022B00F09380002BB2D104F16402EE
+:101AB000226502226265A365C1E7B3F5817F00F06C
+:101AC0009B80B3F5407FA4D194F85E30012BA0D168
+:101AD000B4F8643043F0020332E0B3F5006F4DD048
+:101AE00017D8B3F5A06F31D0A3F5C063012B90D800
+:101AF0006368204694F85E205E6894F85F10B4F83E
+:101B00006030B047002884D043682365036863656C
+:101B10001AE0B3F5106F36D040F6024293427FF4DC
+:101B200078AF5C4B2365022363650023C3E794F819
+:101B30005E30012B7FF46DAFB4F8643023F0020304
+:101B4000A4F86430C4E91455A56578E7B4F85C30AE
+:101B5000B3F5A06F0ED194F85E30204684F866305D
+:101B600001F02AF863681B6813B1012120469847E9
+:101B7000032323700023C4E914339CE704F16703B3
+:101B800023650123C3E72378042B10D1302383F38B
+:101B900011882046FFF7C0FE85F311880321636892
+:101BA00084F8675021701B680BB12046984794F861
+:101BB0005E30002BDED084F8673004232370636826
+:101BC0001B68002BD6D0022120469847D2E794F814
+:101BD000603020461D0603F00F010AD501F098F889
+:101BE000012804D002287FF414AF2B4B9AE72B4B2B
+:101BF00098E701F07FF8F3E794F85E30002B7FF46C
+:101C000008AF94F8603013F00F01B3D01A062046E5
+:101C100002D501F05DFBADE701F050FBAAE794F8B7
+:101C20005E30002B7FF4F5AE94F8603013F00F01B6
+:101C3000A0D01B06204602D501F036FB9AE701F042
+:101C400029FB97E7142284F84C2083F311882B4654
+:101C50002A4629462046FFF76BFE85F31188E9E600
+:101C60005DB1152284F84C2083F3118800212046B1
+:101C7000D4E91423FFF75CFEFDE60B2284F84C2028
+:101C800083F311882B462A4629462046FFF762FE39
+:101C9000E3E700BF203E0008183E00081C3E000895
+:101CA00038B590F84C300446002B3ED0063BDAB2F3
+:101CB0000F2A34D80F2B32D8DFE803F03731310840
+:101CC000223231313131313131313737456DB0F870
+:101CD00062309D4214D2C3681B8AB5FBF3F203FB4A
+:101CE00012556DB9302383F311882B462A462946B5
+:101CF000FFF730FE85F311880A2384F84C300EE09C
+:101D0000142384F84C30302383F3118800232046B9
+:101D10001A461946FFF70CFE002383F3118838BDDD
+:101D2000836D03B198470023E7E70021204601F0C7
+:101D3000BBFA0021204601F0ADFA63681B6813B1BD
+:101D40000621204698470623D7E7000010B590F8F3
+:101D50004C300446142B29D017D8062B05D001D8B7
+:101D60001BB110BD093B022BFBD80021204601F01E
+:101D70009BFA0021204601F08DFA63681B6813B1BD
+:101D8000062120469847062319E0152BE9D10B239D
+:101D900080F84C30302383F3118800231A4619460B
+:101DA000FFF7D8FD002383F31188DAE7C3689B6946
+:101DB0005B68002BD5D1836D03B19847002384F86D
+:101DC0004C30CEE700238268037503691B6899686D
+:101DD0009142FBD25A6803604260106058607047BD
+:101DE00000238268037503691B6899689142FBD8D8
+:101DF0005A680360426010605860704708B5084632
+:101E0000302383F311880B7D032B05D0042B0DD0D9
+:101E10002BB983F3118808BD8B6900221A604FF03B
+:101E2000FF338361FFF7CEFF0023F2E7D1E90032F1
+:101E300013605A60F3E70000FFF7C4BF054BD96891
+:101E400008751868026853601A600122D86002752C
+:101E5000FEF768BAB02802200C4B30B5DD684B1C89
+:101E600087B004460FD02B46094A684600F074F943
+:101E70002046FFF7E3FF009B13B1684600F076F9B8
+:101E8000A86907B030BDFFF7D9FFF9E7B0280220F5
+:101E9000FD1D0008044B1A68DB6890689B68984237
+:101EA00094BF002001207047B0280220084B10B5D5
+:101EB0001C68D868226853601A600122DC602275B1
+:101EC000FFF78EFF01462046BDE81040FEF72ABA14
+:101ED000B0280220044B1A68DB6892689B689A421B
+:101EE00001D9FFF7E3BF7047B028022038B5074C8F
+:101EF00001230025064907482370656001F0ECFBCB
+:101F00000223237085F3118838BD00BF182B0220EF
+:101F1000283E0008B028022000F05EB9EFF31180DF
+:101F200020B9EFF30583302282F311887047000057
+:101F300010B530B9EFF30584C4F3080414B180F38D
+:101F4000118810BDFFF7C6FF84F31188F9E7000080
+:101F5000034A516853685B1A9842FBD8704700BF28
+:101F6000001000E08B600223086108468B827047F6
+:101F70008368A3F1840243F8142C026943F8442CCB
+:101F8000426943F8402C094A43F8242CC268A3F163
+:101F9000200043F8182C022203F80C2C002203F82E
+:101FA0000B2C034A43F8102C704700BF3D03000878
+:101FB000B028022008B5FFF7DBFFBDE80840FFF7B7
+:101FC0003BBF0000024BDB6898610F20FFF736BF74
+:101FD000B0280220302383F31188FFF7F3BF0000FD
+:101FE00008B50146302383F311880820FFF734FF3A
+:101FF000002383F3118808BD064BDB6839B14268C2
+:1020000018605A60136043600420FFF725BF4FF04B
+:10201000FF307047B02802200368984206D01A6843
+:102020000260506018469961FFF706BF70470000D4
+:1020300038B504460D462068844200D138BD036897
+:1020400023605C608561FFF7F7FEF4E7036810B575
+:102050009C68A2420CD85C688A600B604C6021606E
+:10206000596099688A1A9A604FF0FF33836010BDF7
+:10207000121B1B68ECE700000A2938BF0A2170B563
+:1020800004460D460A26601901F020FB01F00CFB06
+:10209000041BA54203D8751C04462E46F3E70A2EFE
+:1020A00004D90120BDE8704001F056BB70BD0000AE
+:1020B000F8B5144B0D460A2A4FF00A07D96103F10F
+:1020C0001001826038BF0A2241601969144601601C
+:1020D00048601861A81801F0EBFA01F0E5FA431B1B
+:1020E0000646A34206D37C1C28192746354601F034
+:1020F000EDFAF2E70A2F04D90120BDE8F84001F01B
+:102100002BBBF8BDB0280220F8B506460D4601F0FD
+:10211000CBFA0F4A134653F8107F9F4206D12A4646
+:1021200001463046BDE8F840FFF7C2BFD169BB6841
+:10213000441A2C1928BF2C46A34202D92946FFF77E
+:102140009BFF224631460348BDE8F840FFF77EBFBB
+:10215000B0280220C0280220C0E90323002310B4C5
+:102160005DF8044B4361FFF7CFBF000010B5194C79
+:10217000236998420DD08168D0E9003213605A601B
+:102180009A680A449A60002303604FF0FF33A3610A
+:1021900010BD0268234643F8102F536000220260EE
+:1021A00022699A4203D1BDE8104001F089BA9368D0
+:1021B00081680B44936001F077FA2269E1699268C3
+:1021C000441AA242E4D91144BDE81040091AFFF7AD
+:1021D00053BF00BFB02802202DE9F047DFF8BC80D4
+:1021E00008F110072C4ED8F8105001F05DFAD8F81D
+:1021F0001C40AA68031B9A423ED814444FF00009C1
+:10220000D5E90032C8F81C4013605A60C5F8009048
+:10221000D8F81030B34201D101F052FA89F3118895
+:10222000D5E9033128469847302383F311886B6939
+:10223000002BD8D001F038FA6A69A0EB0409824675
+:102240004A450DD2022001F087FA0022D8F810305A
+:10225000B34208D151462846BDE8F047FFF728BFF2
+:10226000121A2244F2E712EB09092946384638BF10
+:102270004A46FFF7EBFEB5E7D8F81030B34208D076
+:102280001444C8F81C00211AA960BDE8F047FFF704
+:10229000F3BEBDE8F08700BFC0280220B0280220AE
+:1022A00000207047FEE70000704700004FF0FF304D
+:1022B0007047000002290CD0032904D001290748E7
+:1022C00018BF00207047032A05D8054800EBC2005C
+:1022D0007047044870470020704700BF003F000867
+:1022E00048220220B43E000870B59AB00546084660
+:1022F000144601A900F0C2F801A8FEF753FD431CE3
+:102300000022C6B25B001046C5E9003423700323E7
+:10231000023404F8013C01ABD1B202348E4201D840
+:102320001AB070BD13F8011B013204F8010C04F857
+:10233000021CF1E708B5302383F311880348FFF747
+:102340002BFA002383F3118808BD00BF202B022045
+:1023500090F85C3003F01F02012A07D190F85D204D
+:102360000B2A03D10023C0E9143315E003F0600306
+:10237000202B08D1B0F860302BB990F85D20212ACD
+:1023800003D81F2A04D8FFF7E9B9222AEBD0FAE7CD
+:10239000034A02650722426583650120704700BF3A
+:1023A0003F22022007B5052917D8DFE801F01916EA
+:1023B00003191920302383F31188104A0121019059
+:1023C000FFF790FA019802210D4AFFF78BFA0D48AA
+:1023D000FFF7AEF9002383F3118803B05DF804FB27
+:1023E000302383F311880748FFF778F9F2E73023A9
+:1023F00083F311880348FFF78FF9EBE7543E000899
+:10240000783E0008202B022038B50C4D0C4C2A4693
+:102410000C4904F10800FFF767FF05F1CA0204F157
+:1024200010000949FFF760FF05F5CA7204F11800B2
+:102430000649BDE83840FFF757BF00BFF833022018
+:1024400048220220343E00083E3E0008493E000873
+:1024500070B5044608460D46FEF7A4FCC6B22046F9
+:10246000013403780BB9184670BD32462946FEF791
+:1024700085FC0028F3D10120F6E700002DE9F84F94
+:1024800005460C46FEF78EFC2A49C6B22846FFF7E1
+:10249000DFFF08B1013EF6B227492846FFF7D8FF13
+:1024A00008B11036F6B2632E0DD8DFF88890DFF849
+:1024B00088A0224FDFF88CB0DFF88C802E7846B9E8
+:1024C0002670BDE8F88F29462046BDE8F84F01F098
+:1024D00051BC252E2AD1072249462846FEF74EFC3C
+:1024E00050B9D8F800300735063444F8063CB8F83F
+:1024F000043024F8023CE1E7082251462846FEF762
+:102500003DFC98B9A21C0E4B197802320909C95D2D
+:1025100002F8041C13F8011B01F00F015B45C95DB3
+:1025200002F8031CF0D118340835C7E7013504F868
+:10253000016BC3E7203F0008493E00082F3F000819
+:1025400020F4F01F2CF4F01F283F0008BFF34F8F3A
+:10255000024AD368DB03FCD4704700BF003C024052
+:1025600008B5074B1B7853B9FFF7F0FF054B1A6905
+:10257000002A04DA044A5A6002F188325A6008BD1F
+:1025800056360220003C02402301674508B5054B42
+:102590001B7833B9FFF7DAFF034A136943F00043AE
+:1025A000136108BD56360220003C02400B28F0B5EE
+:1025B00016D80C4C0C4923787BB90E460B4D0C23D6
+:1025C0004FF00062013B55F8047B46F8042B13F0F2
+:1025D000FF033A44F6D10123237051F82000F0BDE7
+:1025E0000020FCE78836022058360220403F0008D1
+:1025F000014B53F820007047403F00080C20704703
+:102600000B2810B5044601D9002010BDFFF7CEFFFE
+:10261000064B53F824301844C21A0BB90120F4E7D2
+:1026200012680132F0D1043BF6E700BF403F0008DA
+:102630000B2838B5044628D8FFF770FC0546FFF78D
+:1026400085FF2046FFF78CFF114AF323D360E30098
+:10265000DBB243F4007343F002031361136943F4E4
+:1026600080331361FFF772FFFFF7A0FF094B53F8A8
+:10267000241000F0E9F82846FFF788FFFFF758FC20
+:102680002046BDE83840FFF7BBBF002038BD00BF83
+:10269000003C0240403F000812F001032DE9F041E8
+:1026A00005460E4614464BD18218B2F1026F61D82E
+:1026B000314B1B6813F001035CD0FFF72FFC2F4F49
+:1026C000FFF74EFFF323314640F20128FB60FFF78E
+:1026D0003DFF032C18D824F001046D1A274E40F258
+:1026E00001180C44A14205EB010733692AD123F0FC
+:1026F00001033361FFF74AFFFFF71AFC0120BDE831
+:10270000F081043C0435E4E7AB07E4D13B6923F4F2
+:1027100040733B613B6943EA08033B6151F8046B3A
+:102720002E60BFF34F8FFFF711FF2B689E42E8D05A
+:102730003B6923F001033B61FFF728FFFFF7F8FB3C
+:102740000020DCE723F440733361336943EA080374
+:1027500033610B883B80BFF34F8FFFF7F7FE3F8855
+:10276000BFB231F8023BBB42BCD0336923F0010356
+:102770003361E1E71846C2E700380240003C0240FE
+:10278000084908B50B7828B11BB9FFF7E9FE01230A
+:102790000B7008BD002BFCD00870BDE80840FFF7A7
+:1027A000F5BE00BF563602200244074BD2B210B528
+:1027B000904200D110BD441C00B253F8200041F8F3
+:1027C000040BE0B2F4E700BF502800400F4B30B5D7
+:1027D0001C6F240407D41C6F44F400741C671C6F26
+:1027E00044F400441C670A4C02442368D2B243F408
+:1027F00080732360074B904200D130BD441C51F8D8
+:10280000045B00B243F82050E0B2F4E70038024025
+:10281000007000405028004007B5012201A90020A7
+:10282000FFF7C2FF019803B05DF804FB13B504463F
+:10283000FFF7F2FFA04205D0012201A90020019478
+:10284000FFF7C4FF02B010BD0144BFF34F8F064B2A
+:10285000884204D3BFF34F8FBFF36F8F7047C3F825
+:102860005C022030F4E700BF00ED00E0034B1A6883
+:102870001AB9034AD2F874281A6070478C360220BD
+:102880000030024008B5FFF7F1FF024B1868C0F3B3
+:10289000407008BD8C36022070B5BFF34F8FBFF378
+:1028A0006F8F1A4A0021C2F85012BFF34F8FBFF347
+:1028B0006F8F536943F400335361BFF34F8FBFF3FE
+:1028C0006F8FC2F88410BFF34F8FD2F8803043F679
+:1028D000E074C3F3C900C3F34E335B0103EA04069B
+:1028E000014646EA81750139C2F86052F9D2203BAF
+:1028F00013F1200FF2D1BFF34F8F536943F48033AC
+:102900005361BFF34F8FBFF36F8F70BD00ED00E0D9
+:10291000FEE70000214B2248224A70B5904237D38F
+:10292000214BC11EDA1C121A22F003028B4238BF5F
+:1029300000220021FEF73EFA1C4A0023C2F8843030
+:10294000BFF34F8FD2F8803043F6E074C3F3C90071
+:10295000C3F34E335B0103EA0406014646EA817580
+:102960000139C2F86C52F9D2203B13F1200FF2D199
+:10297000BFF34F8FBFF36F8FBFF34F8FBFF36F8FD7
+:102980000023C2F85032BFF34F8FBFF36F8F70BD7B
+:1029900053F8041B40F8041BC0E700BF484100087F
+:1029A000A0370220A0370220A037022000ED00E06F
+:1029B00070B5D0E91B4300224FF0FF359E6804EB51
+:1029C00042135101D3F80009002805DAD3F80009B1
+:1029D00040F08040C3F80009D3F8000B002805DA66
+:1029E000D3F8000B40F08040C3F8000B01326318AD
+:1029F0009642C3F80859C3F8085BE0D24FF00113C0
+:102A0000C4F81C3870BD0000890141F0200101614B
+:102A100003699B06FCD41220FFF79ABA10B5054C47
+:102A20002046FEF73BFF4FF0A043E366024B2367CF
+:102A300010BD00BF90360220943F000870B50378A7
+:102A40000546012B50D12A4BC46E98421BD1294B0D
+:102A50000E2143205A6B42F080025A635A6D42F0B5
+:102A600080025A655A6D5A6942F080025A615A6969
+:102A700022F080025A615B6900F034FC1E4BE36077
+:102A80001E4BC4F800380023EE6EC4F8003EC0238D
+:102A900023604FF40413A3633369002BFCDA012392
+:102AA0000C203361FFF754FA3369DB07FCD41220A2
+:102AB000FFF74EFA3369002BFCDA00262846A660A1
+:102AC000FFF776FF6B68C4F81068DB68C4F8146819
+:102AD000C4F81C684BB90A4BA3614FF0FF33636124
+:102AE000A36843F00103A36070BD064BF4E700BF89
+:102AF00090360220003802404014004003002002BB
+:102B0000003C30C0083C30C0F8B5C46E054600211A
+:102B10004FF000662046FFF777FF296F00234FF044
+:102B200001128F684FF0FF30C4F83438C4F81C2805
+:102B300004EB431201339F42C2F80069C2F8006BF4
+:102B4000C2F80809C2F8080BF2D20B68EA6E6B678C
+:102B5000636210231361166916F01006FBD1122070
+:102B6000FFF7F6F9D4F8003823F4FE63C4F8003810
+:102B7000A36943F4402343F01003A3610923C4F87D
+:102B80001038C4F814380A4BEB604FF0C043C4F857
+:102B9000103B084BC4F8003BC4F81069C4F8003976
+:102BA0006B6F03F1100243F480136A67A362F8BDF0
+:102BB000703F000840800010C26E90F86610D2F896
+:102BC000003823F4FE6343EA0113C2F8003870476B
+:102BD0002DE9F84300EB8103C56E0C468046DA68A8
+:102BE0000FFA81F94801166806F00306731E022BDE
+:102BF00005EB41134FF0000194BFB604384EC3F803
+:102C0000101B4FF0010104F1100398BF06F180562C
+:102C100001FA03F3916998BF06F5004600293AD0FE
+:102C2000578A04F15801374349016F50D5F81C18F1
+:102C30000B430021C5F81C382B180127C3F81019C5
+:102C4000A7405369611E9BB3138A928B9B08012A8C
+:102C500088BF5343D8F87420981842EA034301F11F
+:102C600040022146C8F87400284605EB82025360F2
+:102C7000FFF7CAFE08EB8900C3681B8A43EA845346
+:102C800048341E4364012E51D5F81C381F43C5F843
+:102C90001C78BDE8F88305EB4917D7F8001B21F431
+:102CA0000041C7F8001BD5F81C1821EA0303C0E750
+:102CB00004F13F030B4A2846214605EB83035A6083
+:102CC000FFF7A2FE05EB4910D0F8003923F40043CA
+:102CD000C0F80039D5F81C3823EA0707D7E700BF4A
+:102CE0000080001000040002026F12684267FFF7C4
+:102CF0005FBE00005831C36E49015B5813F40040B9
+:102D000004D013F4001F0CBF022001207047000004
+:102D10004831C36E49015B5813F4004004D013F4EA
+:102D2000001F0CBF022001207047000000EB810152
+:102D3000CB68196A0B6813604B68536070470000DA
+:102D400000EB810330B5DD68AA691368D36019B957
+:102D5000402B84BF402313606B8A1468C26E1C44EE
+:102D600002EB4110013C09B2B4FBF3F463430333BB
+:102D700023F0030343EAC44343F0C043C0F8103BCD
+:102D80002B6803F00303012B0ED1D2F8083802EBB5
+:102D9000411013F4807FD0F8003B14BF43F0805300
+:102DA00043F00053C0F8003B02EB4112D2F8003B65
+:102DB00043F00443C2F8003B30BD00002DE9F04170
+:102DC000244D0446EE6E06EB4013D3F8087B38071B
+:102DD000C3F8087B0AD5D6F81438190706D505EBD1
+:102DE000840321462846DB685B689847FA071FD5AD
+:102DF000D6F81438DB071BD505EB8403D968CCB9AA
+:102E00008B69488A5A68B2FBF0F600FB16228AB931
+:102E10001868DA6890420DD2121AC3E900243023F0
+:102E200083F311880B482146FFF78AFF84F311884A
+:102E3000BDE8F081012303FA04F26B8923EA02035F
+:102E40006B81CB68002BF3D021460248BDE8F041EE
+:102E5000184700BF9036022000EB81034A0170B58D
+:102E6000DD68C36E6C692668E66056BB1A444FF491
+:102E70000020C2F810092A6802F00302012A0AB2EF
+:102E80000ED1D3F8080803EB421410F4807FD4F875
+:102E9000000914BF40F0805040F00050C4F8000911
+:102EA00003EB4212D2F8000940F00440C2F80009D6
+:102EB0000122D3F8340802FA01F10143C3F83418AF
+:102EC00070BD19B9402E84BF4020206020681A448C
+:102ED0002E8A8419013CB4FBF6F440EAC44040F069
+:102EE0000050C6E72DE9F8433B4D04464701EE6E1E
+:102EF00006EB4013D3F8088918F0010FC3F80889CE
+:102F00001AD0D6F81038DB0716D505EB8003D96840
+:102F10004B691868DA68904230D2121A4FF00009F3
+:102F20001A60C3F80490302383F3118821462846A1
+:102F3000FFF792FF89F3118818F0800F1CD0D6F8A4
+:102F400034380126A640334216D005EB8403013401
+:102F5000ED6ED3F80CC0E4B22F44DCF8142005EB7E
+:102F60000434D2F800E05168714515D3D5F83438EF
+:102F700023EA0606C5F83468BDE8F883012303FA9E
+:102F800004F22B8923EA02032B818B68002BD3D018
+:102F9000214628469847CFE7AEEB0103BCF8100066
+:102FA000834228BF0346D7F8180980B2B3EB800FDD
+:102FB000E2D89068A0F1040959F8048FC4F80080A1
+:102FC000A0EB09089844B8F1040FF5D818440B4455
+:102FD00090605360C7E700BF903602202DE9F74F9D
+:102FE000A44CE56E6E69AB691E4016F480586E61A4
+:102FF00007D02046FEF7C0FC03B0BDE8F04F00F05C
+:1030000069BC002E12DAD5F8003E9B0705D0D5F832
+:10301000003E23F00303C5F8003ED5F80438954878
+:1030200023F00103C5F80438FEF7D2FC370505D5B7
+:103030009048FFF7BDFC8F48FEF7B8FCB0040CD5F4
+:10304000D5F8083813F0060FEB6823F470530CBF63
+:1030500043F4105343F4A053EB6031071BD563686E
+:10306000DB681BB9AB6923F00803AB612378052B40
+:103070000CD1D5F8003E9A0705D0D5F8003E23F0D4
+:103080000303C5F8003E7B48FEF7A2FC6368DB68DB
+:103090000BB178489847F30200F18980B70227D531
+:1030A000D4F86C9000274FF0010ADFF8C8B109EBA3
+:1030B0004712D2F8003B03F44023B3F5802F11D11F
+:1030C000D2F8003B002B0DDA62890AFA07F322EAF4
+:1030D0000303638104EB8703DB68DB6813B13946C4
+:1030E000584698470137236FFFB29B689F42DED94D
+:1030F000F00617D5E76E3A6AC2F30A1002F00F0322
+:1031000002F4F012B2F5802F00F09880B2F5402F53
+:1031100008D104EB8303002207F58057DB681B6AA4
+:1031200090427ED13303D5F818481DD5E70302D568
+:103130000020FFF743FEA50302D50120FFF73EFE66
+:10314000600302D50220FFF739FE210302D50320D8
+:10315000FFF734FEE20202D50420FFF72FFEA302A0
+:1031600002D50520FFF72AFE77037FF545AFE60776
+:1031700002D50020FFF7B6FEA50702D50120FFF714
+:10318000B1FE600702D50220FFF7ACFE210702D591
+:103190000320FFF7A7FEE20602D50420FFF7A2FEF8
+:1031A000A3067FF529AF0520FFF79CFE24E7E36E19
+:1031B00000274FF00109DFF8BCA00193236F5FFAED
+:1031C00087FB9B689B453FF669AF019B03EB4B1365
+:1031D000D3F8001901F44021B1F5802F1FD1D3F8A5
+:1031E000001900291BDAD3F8001941F09041C3F807
+:1031F0000019D3F800190029FBDB5946E06EFFF7F0
+:1032000003FC218909FA0BF321EA0303238104EB70
+:103210008B03DB689B6813B15946504698470137CA
+:10322000CCE7910701D1D7F80080072A02F101020B
+:103230009CBF03F8018B4FEA182871E7023307F5AA
+:10324000805704EB83025268D2F818C0DCF80820DB
+:10325000DCE9001CA1EB0C0C002188420CD104EB32
+:10326000830463689B699A6802449A605A680244BE
+:103270005A6057E79036022011F0030F01D1D7F8BA
+:1032800000808C4501F1010184BF02F8018B4FEAF7
+:103290001828E2E7C36E03EB4111D1F8003B43F479
+:1032A0000013C1F8003B7047C36E03EB4111D1F826
+:1032B000003943F40013C1F800397047C36E03EBC3
+:1032C0004111D1F8003B23F40013C1F8003B7047D3
+:1032D000C36E03EB4111D1F8003923F40013C1F898
+:1032E00000397047090100F16043012203F5614391
+:1032F000C9B283F8001300F01F039A4043099B00F2
+:1033000003F1604303F56143C3F880211A607047FD
+:1033100030B50433039C0172002104FB0325C16016
+:10332000C0E90653049B0363059BC0E90000C0E9A4
+:103330000422C0E90842C0E90A11436330BD00001D
+:103340000022416AC260C0E90411C0E90A226FF09C
+:103350000101FEF76DBE0000D0E90432934201D1B5
+:10336000C2680AB9181D70470020704703691960C8
+:103370000021C2680132C260C2691344826993426B
+:10338000036124BF436A0361FEF746BE38B50446B5
+:103390000D46E3683BB162690020131D1268A36209
+:1033A0001344E36207E0237A33B929462046FEF747
+:1033B00023FE0028EDDA38BD6FF00100FBE70000C6
+:1033C000C368C269013BC360436913448269934285
+:1033D000436124BF436A436100238362036B03B1EB
+:1033E0001847704770B53023044683F31188866A06
+:1033F0003EB9FFF7CBFF054618B186F31188284682
+:1034000070BDA36AE26A13F8015B9342A36202D320
+:103410002046FFF7D5FF002383F31188EFE7000074
+:103420002DE9F84F04460E46174698464FF03009EE
+:1034300089F311880025AA46D4F828B0BBF1000F03
+:1034400009D141462046FFF7A1FF20B18BF3118837
+:103450002846BDE8F88FD4E90A12A7EB050B521AEB
+:10346000934528BF9346BBF1400F1BD9334601F16A
+:10347000400251F8040B914243F8040BF9D1A36ABE
+:10348000403640354033A362D4E90A239A4202D33E
+:103490002046FFF795FF8AF31188BD42D8D289F301
+:1034A0001188C9E730465A46FDF75EFCA36A5E44C0
+:1034B0005D445B44A362E7E710B5029C04330172EC
+:1034C00003FB0421C460C0E906130023C0E90A33EA
+:1034D000039B0363049BC0E90000C0E90422C0E928
+:1034E0000842436310BD0000026A6FF00101C26030
+:1034F000426AC0E904220022C0E90A22FEF798BD10
+:10350000D0E904239A4201D1C26822B9184650F882
+:10351000043B0B60704700231846FAE7C36800219C
+:10352000C2690133C36043691344826993424361B2
+:1035300024BF436A4361FEF76FBD000038B50446FF
+:103540000D46E3683BB1236900201A1DA262E269BF
+:103550001344E36207E0237A33B929462046FEF795
+:103560004BFD0028EDDA38BD6FF00100FBE70000ED
+:1035700003691960C268013AC260C2691344826972
+:103580009342036124BF436A036100238362036B98
+:1035900003B118477047000070B530230D4604464C
+:1035A000114683F31188866A2EB9FFF7C7FF10B161
+:1035B00086F3118870BDA36A1D70A36AE26A0133A5
+:1035C0009342A36204D3E16920460439FFF7D0FF98
+:1035D000002080F31188EDE72DE9F84F04460D46F1
+:1035E000904699464FF0300A8AF311880026B34678
+:1035F000A76A4FB949462046FFF7A0FF20B187F3DD
+:1036000011883046BDE8F88FD4E90A073A1AA8EBCA
+:103610000607974228BF1746402F1BD905F14003E4
+:1036200055F8042B9D4240F8042BF9D1A36A40368B
+:103630004033A362D4E90A239A4204D3E1692046C5
+:103640000439FFF795FF8BF311884645D9D28AF3E9
+:103650001188CDE729463A46FDF786FBA36A3D442B
+:103660003E443B44A362E5E7D0E904239A4217D1E4
+:10367000C3689BB1836A8BB1043B9B1A0ED0136065
+:10368000C368013BC360C3691A4483699A420261FB
+:1036900024BF436A036100238362012318467047F5
+:1036A0000023FBE700F040B94FF08043586A7047B1
+:1036B0004FF08043002258631A610222DA6070479B
+:1036C0004FF080430022DA60704700004FF08043E3
+:1036D00058637047FEE7000070B51B4B0025044699
+:1036E00086B058600E468562016300F0CBF804F1A5
+:1036F0001003A560E562C4E904334FF0FF33C4E969
+:103700000044C4E90635FFF7CFFF2B46024604F11B
+:1037100034012046C4E9082380230C4A2565FEF7BE
+:1037200021FC01230A4AE060009203756846726832
+:103730000192B268CDE90223064BCDE90435FEF7CC
+:1037400039FC06B070BD00BF182B0220A03F000856
+:10375000A53F0008D5360008024AD36A1843D06254
+:10376000704700BFB02802204B6843608B688360BD
+:10377000CB68C3600B6943614B6903628B69436229
+:103780000B6803607047000008B52C4B40F2FF71D6
+:103790002B481A690A431A611A6922F4FF6222F05F
+:1037A00007021A611A691A6B0A431A631A6D0A43EF
+:1037B0001A65244A1B6D1146FFF7D6FF00F580609D
+:1037C00002F11C01FFF7D0FF00F5806002F1380123
+:1037D000FFF7CAFF00F5806002F15401FFF7C4FF54
+:1037E00000F5806002F17001FFF7BEFF00F5806018
+:1037F00002F18C01FFF7B8FF00F5806002F1A8012B
+:10380000FFF7B2FF00F5806002F1C401FFF7ACFFE3
+:1038100000F5806002F1E001FFF7A6FF00F580608F
+:1038200002F1FC01FFF7A0FF02F58C7100F580604A
+:10383000FFF79AFFBDE8084000F0ECB800380240FE
+:1038400000000240AC3F000808B500F073FAFEF734
+:103850004DFBFFF70BF8BDE80840FEF7D5BD0000B3
+:1038600070470000EFF30983054968334A6B22F083
+:1038700001024A6383F30988002383F311887047A8
+:1038800000EF00E0302080F3118862B60D4B0E4A45
+:10389000D96821F4E0610904090C0A430B49DA6094
+:1038A000D3F8FC2042F08072C3F8FC20084AC2F82A
+:1038B000B01F116841F0010111602022DA7783F80E
+:1038C0002200704700ED00E00003FA0555CEACC5BC
+:1038D000001000E0302310B583F311880E4B5B68B5
+:1038E00013F4006314D0F1EE103AEFF309844FF0B3
+:1038F0008073683CE361094BDB6B236684F30988C2
+:10390000FEF7C8FA10B1064BA36110BD054BFBE7EB
+:1039100083F31188F9E700BF00ED00E000EF00E05D
+:103920004F030008520300080F4B1A6C42F00102CB
+:103930001A641A6E42F001021A660C4A1B6E9368F2
+:1039400043F0010393604FF080436B229A624FF083
+:10395000FF32DA6200229A615A63DA605A60012209
+:103960005A611A60704700BF00380240002004E02E
+:103970004FF0804208B51169D3680B40D9B29B075C
+:103980006FEA0101116107D5302383F31188FEF737
+:10399000C3FA002383F3118808BD00001B4B4FF0CE
+:1039A000FF3000211A696FEA42526FEA52521A61DF
+:1039B0001A69C2F30A021A611A695A6958615A6986
+:1039C00059615A691A6A62F080521A621A6A02F0E0
+:1039D00080521A621A6A5A6A58625A6A59625A6A54
+:1039E0000B4A106840F480701060186F00F440704B
+:1039F000B0F5007F03D04FF4803018671967536823
+:103A000023F40073536000F069B900BF003802402E
+:103A100000700040364B4FF44041364A1A64364A33
+:103A200011601A6842F001021A601A689207FCD508
+:103A30009A6822F003029A602D4B9A6812F00C02E9
+:103A4000FBD1196801F0F90119609A601A6842F413
+:103A500080321A601A689003FCD55A6F42F0010256
+:103A60005A67234B5A6F9107FCD5244A5A601A684B
+:103A700042F080721A60204B5A685204FCD51A68D2
+:103A800042F480321A605A68D003FCD51A6842F4B6
+:103A900000321A60184A53689903FCD5144B1A680F
+:103AA0009201FCD5164A9A6040F20112C3F88C20AC
+:103AB0000022C3F8902040F20733124A13601368C3
+:103AC00003F00F03072BFAD1094B9A6842F0020268
+:103AD0009A609A6802F00C02082AFAD15A6C42F4F1
+:103AE00080425A645A6E42F480425A665B6E704756
+:103AF000003802400004001000700040106C4009C3
+:103B000000948838003C0240074A08B5536903F026
+:103B10000103536123B1054A13680BB150689847FC
+:103B2000BDE80840FFF7D6BE003C01402037022028
+:103B3000074A08B5536903F00203536123B1054AEC
+:103B400093680BB1D0689847BDE80840FFF7C2BE44
+:103B5000003C014020370220074A08B5536903F0B2
+:103B60000403536123B1054A13690BB150699847A7
+:103B7000BDE80840FFF7AEBE003C01402037022000
+:103B8000074A08B5536903F00803536123B1054A96
+:103B900093690BB1D0699847BDE80840FFF79ABE1A
+:103BA000003C014020370220074A08B5536903F062
+:103BB0001003536123B1054A136A0BB1506A984749
+:103BC000BDE80840FFF786BE003C014020370220D8
+:103BD000164B10B55C6904F478725A61A30604D5DB
+:103BE000134A936A0BB1D06A9847600604D5104A0D
+:103BF000136B0BB1506B9847210604D50C4A936B9D
+:103C00000BB1D06B9847E20504D5094A136C0BB190
+:103C1000506C9847A30504D5054A936C0BB1D06C42
+:103C20009847BDE81040FFF755BE00BF003C01407B
+:103C300020370220194B10B55C6904F47C425A61AC
+:103C4000620504D5164A136D0BB1506D98472305D4
+:103C500004D5134A936D0BB1D06D9847E00404D599
+:103C60000F4A136E0BB1506E9847A10404D50C4A4D
+:103C7000936E0BB1D06E9847620404D5084A136F57
+:103C80000BB1506F9847230404D5054A936F0BB1CD
+:103C9000D06F9847BDE81040FFF71CBE003C0140C4
+:103CA0002037022008B50348FDF70CFABDE80840AC
+:103CB000FFF710BED823022008B50348FDF702FA2B
+:103CC000BDE80840FFF706BE4424022008B5FFF710
+:103CD0004FFEBDE80840FFF7FDBD0000062108B516
+:103CE0000846FFF7FFFA06210720FFF7FBFA062137
+:103CF0000820FFF7F7FA06210920FFF7F3FA06215B
+:103D00000A20FFF7EFFA06211720FFF7EBFA06214A
+:103D10002820FFF7E7FA07211C20FFF7E3FA0C2120
+:103D20002620FFF7DFFA0C215220BDE80840FFF7FC
+:103D3000D9BA000008B5FFF731FE00F00DF8FDF725
+:103D4000D9FBFDF7A9FDFDF781FCFFF789FDBDE873
+:103D50000840FFF7A7BC00000023054A19460133BD
+:103D6000102BC2E9001102F10802F8D1704700BF20
+:103D700020370220034611F8012B03F8012B002AFB
+:103D8000F9D1704753544D3332463F3F3F3F3F3F99
+:103D90000053544D333246375B347C355D780053E5
+:103DA000544D333246375B367C375D780000000077
+:103DB000009600000000000000000000000000006D
+:103DC000000000000000000000000000B514000822
+:103DD000A1140008DD140008C9140008D514000857
+:103DE000C1140008AD14000899140008E914000873
+:103DF00000000000C9150008B5150008F1150008FD
+:103E0000DD150008E9150008D5150008C1150008E2
+:103E1000AD150008FD1500080000000001000000BD
+:103E20000000000063300000243E00080829022042
+:103E3000182B02204172647550696C6F7400254222
+:103E40004F415244252D424C002553455249414C87
+:103E5000250000000200000000000000E517000837
+:103E60005118000840004000C8330220D833022017
+:103E7000020000000000000003000000000000003D
+:103E8000951800080000000010000000E833022030
+:103E90000000000001000000000000009036022039
+:103EA00001010200A5230008B522000851230008E3
+:103EB0003523000843000000BC3E0008090243000F
+:103EC000020100C0320904000001020201000524C1
+:103ED000001001052401000104240202052406004B
+:103EE00001070582030800FF09040100020A00001F
+:103EF00000070501024000000705810240000000A4
+:103F000012000000083F00081201100102000040EA
+:103F100009124157000201020301000004030904D1
+:103F200025424F41524425004A464231303000304C
+:103F3000313233343536373839414243444546000F
+:103F40000080000000800000008000000080000071
+:103F50000000020000000400000004000000040053
+:103F60000000040000000400000004000000040041
+:103F700000000000E9190008A11C00084D1D000800
+:103F800040004000083702200837022001000000EE
+:103F900018370220800000004001000005000000EA
+:103FA0006D61696E0069646C650000000000802A24
+:103FB00000000000AAAAAAAA00000024FFFF000037
+:103FC0000000000000A00A00000000000000000047
+:103FD000AAAAAAAA00000000FFFF0000000000003B
+:103FE000000000000050000000000000AAAAAAAAD9
+:103FF00000000000FFFF00000000000000000000C3
+:104000008029000000000000AAAAAAAA401500000A
+:10401000FFFF0000007070070000000000000200B9
+:1040200000000000AAAAAAAA00000100FFFF0000E9
+:1040300000000000080000005025100000000000F3
+:104040002AA2AAAA50151000FFFF000000000008D5
+:10405000000000000000000000000000AAAAAAAAB8
+:1040600000000000FFFF0000000000000000000052
+:104070000004000000000000AAAAAAAA0004000090
+:10408000FFFF000000000000000000000051510090
+:1040900000000000AAAAAAAA00515100FFFF0000D8
+:1040A0000000000000000000000000000000000010
+:1040B0000000000000000000000000000000000000
+:1040C00000000000000000000000000000000000F0
+:1040D00000000000000000000000000000000000E0
+:1040E0003C0400000000000000801F0000000000F1
+:1040F000FF000000202B0220D823022044240220AD
+:1041000000000000843D000849040000913D0008C3
+:10411000510400009F3D00080096000000000800C8
+:104120009600000000080000040000001C3F00088A
+:10413000000000000000000000000000000000007F
+:08414000000000000000000077
+:00000001FF
diff --git a/Tools/bootloaders/KakuteH7-Wing_bl.bin b/Tools/bootloaders/KakuteH7-Wing_bl.bin
new file mode 100755
index 00000000000000..c1bb483f772482
Binary files /dev/null and b/Tools/bootloaders/KakuteH7-Wing_bl.bin differ
diff --git a/Tools/bootloaders/KakuteH7-Wing_bl.hex b/Tools/bootloaders/KakuteH7-Wing_bl.hex
new file mode 100644
index 00000000000000..04efd53d7b6d03
--- /dev/null
+++ b/Tools/bootloaders/KakuteH7-Wing_bl.hex
@@ -0,0 +1,1109 @@
+:020000040800F2
+:1000000000060020E1020008E3020008E302000805
+:10001000E3020008E3020008E3020008E30200082C
+:10002000E3020008E3020008E3020008013B0008C5
+:10003000E3020008E3020008E3020008E30200080C
+:10004000E3020008E3020008E3020008E3020008FC
+:10005000E3020008E3020008E93E0008153F00083B
+:10006000413F00086D3F0008993F0008E302000887
+:10007000E3020008E3020008E3020008E3020008CC
+:10008000E3020008E3020008E3020008E3020008BC
+:10009000E3020008E3020008E3020008C53F00088D
+:1000A000E3020008E3020008E3020008E30200089C
+:1000B000E3020008E3020008E3020008E30200088C
+:1000C000E3020008E3020008E3020008E30200087C
+:1000D000E3020008E3020008E3020008E30200086C
+:1000E00029400008E3020008E3020008E3020008D8
+:1000F000E3020008E3020008E3020008E30200084C
+:10010000E3020008E3020008B1400008E30200082F
+:10011000E3020008E3020008E3020008E30200082B
+:10012000E3020008E3020008E3020008E30200081B
+:10013000E3020008E3020008E3020008E30200080B
+:10014000E3020008E3020008E3020008E3020008FB
+:10015000E3020008E3020008E3020008E3020008EB
+:10016000E3020008E3020008E3020008E3020008DB
+:10017000E302000881340008E3020008E3020008FB
+:10018000E3020008E30200089D400008E3020008C3
+:10019000E3020008E3020008E3020008E3020008AB
+:1001A000E3020008E3020008E3020008E30200089B
+:1001B000E3020008E3020008E3020008E30200088B
+:1001C000E3020008E3020008E3020008E30200087B
+:1001D000E30200086D340008E3020008E3020008AF
+:1001E000E3020008E3020008E3020008E30200085B
+:1001F000E3020008E3020008E3020008E30200084B
+:10020000E3020008E3020008E3020008E30200083A
+:10021000E3020008E3020008E3020008E30200082A
+:10022000E3020008E3020008E3020008E30200081A
+:10023000E3020008E3020008E3020008E30200080A
+:10024000E3020008E3020008E3020008E3020008FA
+:10025000E3020008E3020008E3020008E3020008EA
+:10026000E3020008E3020008E3020008E3020008DA
+:10027000E3020008E3020008E3020008E3020008CA
+:10028000E3020008E3020008E3020008E3020008BA
+:10029000E3020008E3020008E3020008E3020008AA
+:1002A000E3020008E3020008E3020008E30200089A
+:1002B000E3020008E3020008E3020008E30200088A
+:1002C000E3020008E3020008E3020008E30200087A
+:1002D000E3020008E3020008E3020008E30200086A
+:1002E00002E000F000F8FEE772B6384880F30888B4
+:1002F000374880F3098837483749086040F20000E2
+:10030000CCF200004EF63471CEF200010860BFF36B
+:100310004F8FBFF36F8F40F20000C0F2F0004EF637
+:100320008851CEF200010860BFF34F8FBFF36F8F8B
+:100330004FF00000E1EE100A4EF63C71CEF20001E3
+:100340000860062080F31488BFF36F8F02F08EFBE5
+:1003500002F030FB03F026FB4FF055301F491B4ADB
+:1003600091423CBF41F8040BFAE71D49184A9142FB
+:100370003CBF41F8040BFAE71A491B4A1B4B9A424F
+:100380003EBF51F8040B42F8040BF8E7002018496F
+:10039000184A91423CBF41F8040BFAE702F048FBCF
+:1003A00003F084FB144C154DAC4203DA54F8041BE3
+:1003B0008847F9E700F042F8114C124DAC4203DADD
+:1003C00054F8041B8847F9E702F030BB0006002010
+:1003D000002200200000000808ED00E000000020DE
+:1003E00000060020C84400080022002064220020EB
+:1003F00068220020C4470020E0020008E002000854
+:10040000E0020008E00200082DE9F04F2DED108A0F
+:10041000C1F80CD0D0F80CD0BDEC108ABDE8F08F3C
+:10042000002383F311882846A047002001F038FEFE
+:10043000FEE701F0A1FD00DFFEE7000038B502F0A5
+:1004400079FA054602F0ACFA0446D0B90F4B9D424A
+:1004500019D001339D4241F2883512BF0446002570
+:100460000124002002F070FA0CB100F077F800F0DF
+:100470007DFD00F029FC284600F01EF900F06EF822
+:10048000F9E70025EDE70546EBE700BF010007B0FF
+:1004900008B500F0E5FBA0F120035842584108BD23
+:1004A00007B541F21203022101A8ADF8043000F0B3
+:1004B000F5FB03B05DF804FB38B5302383F31188F6
+:1004C000174803680BB101F0B7FE0023154A4FF43B
+:1004D0007A71134801F0A6FE002383F31188124CB1
+:1004E000236813B12368013B2360636813B1636819
+:1004F000013B63600D4D2B7833B963687BB90220F3
+:1005000000F0AEFC322363602B78032B07D16368C5
+:100510002BB9022000F0A4FC4FF47A73636038BD5D
+:1005200068220020B90400088823002080220020CF
+:10053000084B187003280CD8DFE800F00805020803
+:10054000022000F083BC022000F076BC024B0022A7
+:100550005A6070478022002088230020F8B5504B55
+:10056000504A1C461968013100F0998004339342C7
+:10057000F8D162684C4B9A4240F291804B4B9B6899
+:1005800003F1006303F500339A4280F08880002075
+:1005900000F0C0FB0220FFF7CBFF454B0021D3F852
+:1005A000E820C3F8E810D3F81021C3F81011D3F8ED
+:1005B0001021D3F8EC20C3F8EC10D3F81421C3F8C1
+:1005C0001411D3F81421D3F8F020C3F8F010D3F8A5
+:1005D0001821C3F81811D3F81821D3F8802042F05D
+:1005E0000062C3F88020D3F8802022F00062C3F8B4
+:1005F0008020D3F88020D3F8802042F00072C3F826
+:100600008020D3F8802022F00072C3F88020D3F835
+:10061000803072B64FF0E023C3F8084DD4E90004EF
+:10062000BFF34F8FBFF36F8F224AC2F88410BFF31E
+:100630004F8F536923F480335361BFF34F8FD2F848
+:10064000803043F6E076C3F3C905C3F34E335B0154
+:1006500003EA060C29464CEA81770139C2F8747224
+:10066000F9D2203B13F1200FF2D1BFF34F8FBFF32C
+:100670006F8FBFF34F8FBFF36F8F536923F4003336
+:1006800053610023C2F85032BFF34F8FBFF36F8F17
+:10069000302383F31188854680F308882047F8BD0E
+:1006A0000000020820000208FFFF010800220020CD
+:1006B0000044025800ED00E02DE9F04F93B0B44B38
+:1006C0002022FF2100900AA89D6800F0F9FBB14AA2
+:1006D0001378A3B90121B04811700360302383F36C
+:1006E000118803680BB101F0A7FD0023AB4A4FF45A
+:1006F0007A71A94801F096FD002383F31188009BCD
+:1007000013B1A74B009A1A60A64A1378032B03D0A3
+:1007100000231370A24A53604FF0000A009CD34696
+:100720005646D146012000F091FB24B19C4B1B683A
+:10073000002B00F02682002000F092FA0390039B29
+:10074000002BF2DB012000F077FB039B213B1F2BEA
+:10075000E8D801A252F823F0D907000801080008E0
+:100760009508000825070008250700082507000848
+:1007700027090008F70A0008110A0008730A000890
+:100780009B0A0008C10A000825070008D30A0008D0
+:1007900025070008450B0008790800082507000810
+:1007A000890B0008E50700087908000825070008FC
+:1007B000730A000825070008250700082507000818
+:1007C0002507000825070008250700082507000859
+:1007D00025070008950800080220FFF759FE0028A9
+:1007E00040F0F981009B022105A8BAF1000F08BF73
+:1007F0001C4641F21233ADF8143000F04FFA91E785
+:100800004FF47A7000F02CFA071EEBDB0220FFF7A2
+:100810003FFE0028E6D0013F052F00F2DE81DFE831
+:1008200007F0030A0D1013360523042105A80593CC
+:1008300000F034FA17E004215548F9E704215A483A
+:10084000F6E704215948F3E74FF01C08404608F149
+:10085000040800F061FA0421059005A800F01EFAD2
+:10086000B8F12C0FF2D101204FF0000900FA07F780
+:1008700047EA0B0B5FFA8BFB00F06EFB26B10BF027
+:100880000B030B2B08BF0024FFF70AFE4AE70421E5
+:100890004748CDE7002EA5D00BF00B030B2BA1D1C1
+:1008A0000220FFF7F5FD074600289BD00120002617
+:1008B00000F030FA0220FFF73BFE5FFA86F8404670
+:1008C00000F038FA0446B0B1039940460136A1F170
+:1008D00040025142514100F03DFA0028EDD1BA46A4
+:1008E000044641F21213022105A83E46ADF8143029
+:1008F00000F0D4F916E725460120FFF719FE244B36
+:100900009B68AB4207D9284600F006FA013040F058
+:1009100067810435F3E70025224BBA463E461D7039
+:100920001F4B5D60A8E7002E3FF45CAF0BF00B039C
+:100930000B2B7FF457AF0220FFF7FAFD322000F0B7
+:100940008FF9B0F10008FFF64DAF18F003077FF400
+:1009500049AF0F4A08EB0503926893423FF642AF56
+:10096000B8F5807F3FF73EAF124BB845019323DDCA
+:100970004FF47A7000F074F90390039A002AFFF69E
+:1009800031AF039A0137019B03F8012BEDE700BF5C
+:10099000002200208423002068220020B9040008DF
+:1009A000882300208022002004220020082200202A
+:1009B0000C22002084220020C820FFF769FD074692
+:1009C00000283FF40FAF1F2D11D8C5F120020AAB4C
+:1009D00025F0030084494245184428BF424601924D
+:1009E00000F048FA019AFF217F4800F069FA4FEAC7
+:1009F000A803C8F387027C492846019300F068FAEF
+:100A0000064600283FF46DAF019B05EB830533E7F5
+:100A10000220FFF73DFD00283FF4E4AE00F0B8F9F6
+:100A200000283FF4DFAE0027B846704B9B68BB42FE
+:100A300018D91F2F11D80A9B01330ED027F00303BA
+:100A400012AA134453F8203C05934046042205A9FA
+:100A5000043700F0EFFA8046E7E7384600F05CF92B
+:100A60000590F2E7CDF81480042105A800F016F9EE
+:100A700002E70023642104A8049300F005F900288C
+:100A80007FF4B0AE0220FFF703FD00283FF4AAAECA
+:100A9000049800F073F90590E6E70023642104A8A8
+:100AA000049300F0F1F800287FF49CAE0220FFF7D9
+:100AB000EFFC00283FF496AE049800F061F9EAE7F5
+:100AC0000220FFF7E5FC00283FF48CAE00F070F93F
+:100AD000E1E70220FFF7DCFC00283FF483AE05A924
+:100AE000142000F06BF907460421049004A800F0DC
+:100AF000D5F83946B9E7322000F0B2F8071EFFF604
+:100B000071AEBB077FF46EAE384A07EB09039268FB
+:100B100093423FF667AE0220FFF7BAFC00283FF48D
+:100B200061AE27F003074F44B9453FF4A5AE4846F0
+:100B300009F1040900F0F0F80421059005A800F07F
+:100B4000ADF8F1E74FF47A70FFF7A2FC00283FF40C
+:100B500049AE00F01DF9002844D00A9B01330BD0A8
+:100B600008220AA9002000F0B3F900283AD0202278
+:100B7000FF210AA800F0A4F9FFF792FC1C4801F03D
+:100B800095FA13B0BDE8F08F002E3FF42BAE0BF0BA
+:100B90000B030B2B7FF426AE0023642105A80593DD
+:100BA00000F072F8074600287FF41CAE0220FFF721
+:100BB0006FFC804600283FF415AEFFF771FC41F250
+:100BC000883001F073FA059800F012FA46463C4668
+:100BD00000F0C2F9A6E506464EE64FF0000901E630
+:100BE000BA467EE637467CE68422002000220020BA
+:100BF000A08601002DE9F84F4FF47A7306460D46A2
+:100C0000002402FB03F7DFF85080DFF8509098F9DA
+:100C100000305FFA84FA5A1C01D0A34212D159F86D
+:100C200024002A4631460368D3F820B03B46D84713
+:100C3000854207D1074B012083F800A0BDE8F88F5B
+:100C40000124E4E7002CFBD04FF4FA7001F02EFAF7
+:100C50000020F3E7D42300201022002014220020DB
+:100C6000002307B5024601210DF107008DF807307A
+:100C7000FFF7C0FF20B19DF8070003B05DF804FB4B
+:100C80004FF0FF30F9E700000A46042108B5FFF7EE
+:100C9000B1FF80F00100C0B2404208BD074B0A46D8
+:100CA00030B41978064B53F821400146236820469A
+:100CB000DD69044BAC4630BC604700BFD423002044
+:100CC00014220020A086010070B5104C0025104EA3
+:100CD00001F008FD20803068238883420CD800256D
+:100CE0002088013801F0FAFC23880544013BB5F562
+:100CF000802F2380F4D370BD01F0F0FC33680544ED
+:100D00000133B5F5003F3360E5D3E8E7D623002093
+:100D10009023002001F0C4BD00F1006000F5003018
+:100D20000068704700F10060920000F5003001F0AB
+:100D30003BBD0000054B1A68054B1B889B1A83427C
+:100D400002D9104401F0CABC002070479023002053
+:100D5000D623002038B50446074D29B12868204421
+:100D6000BDE8384001F0D2BC2868204401F0BCFC4A
+:100D70000028F3D038BD00BF90230020002070472A
+:100D800000F1FF5000F58F10D0F800087047000008
+:100D9000064991F8243033B100230822086A81F80B
+:100DA0002430FFF7BFBF0120704700BF942300200D
+:100DB000014B1868704700BF0010005C1B4B0246D7
+:100DC000F0B518681A4BC0F30B06000C1F885C685E
+:100DD000BE4293F9085003D09F89BE4203D10C3321
+:100DE0005C6893F908500426124B1F88043387422D
+:100DF00008BF13F9025C013EF7D1013A013C0B46F2
+:100E00000A44934207D214F9016F581C2EB10346CD
+:100E100000F8016CF5E7184605E02C2482421C70AE
+:100E200001D9981C5D70401AF0BD00BF0010005C35
+:100E30001C220020A4410008022803D1024B4FF0DD
+:100E400000429A61704700BF00080258022803D18F
+:100E5000024B4FF400429A61704700BF00080258ED
+:100E6000022804D1024A536983F400435361704756
+:100E700000080258002310B5934203D0CC5CC45440
+:100E80000133F9E710BD0000013810B510F9013F3A
+:100E90003BB191F900409C4203D11AB10131013AB2
+:100EA000F4E71AB191F90020981A10BD1046FCE73A
+:100EB00003460246D01A12F9011B0029FAD17047E5
+:100EC00002440346934202D003F8011BFAE770473D
+:100ED0002DE9F8431F4D14460746884695F824200F
+:100EE00052BBDFF870909CB395F824302BB92022C8
+:100EF000FF2148462F62FFF7E3FF95F824004146A3
+:100F0000C0F1080205EB8000A24228BF2246D6B2FB
+:100F10009200FFF7AFFF95F82430A41B17441E443E
+:100F20009044E4B2F6B2082E85F82460DBD1FFF7D6
+:100F30002FFF0028D7D108E02B6A03EB82038342FE
+:100F4000CFD0FFF725FF0028CBD10020BDE8F883E4
+:100F50000120FBE794230020024B1A78024B1A7001
+:100F6000704700BFD42300201022002038B51A4C4F
+:100F70001A4D204600F0C8FB2946204600F0F0FB41
+:100F80002D681748D5F89020D2F8043843F00203B2
+:100F9000C2F8043801F08AF81249284600F0EEFC45
+:100FA000D5F89020104DD2F80438286823F00203B9
+:100FB0000E49A042C2F804384FF4E1330B6001D06F
+:100FC00000F000FB6868A04204D00849BDE8384042
+:100FD00000F0F8BA38BD00BFB82A0020A0420008CF
+:100FE00040420F00A842000814220020BC23002029
+:100FF0000C4B70B50C4D04461E780C4B55F8262052
+:101000009A420DD00A4B002118221846FFF758FFCC
+:101010000460014655F82600BDE8704000F0D2BAE1
+:1010200070BD00BFD423002014220020B82A002065
+:10103000BC23002030B50A44084D91420DD011F870
+:10104000013B5840082340F30004013B2C4013F0BF
+:10105000FF0384EA5000F6D1EFE730BD2083B8EDFE
+:10106000026843681143016003B1184770470000EC
+:10107000024A136843F0C0031360704700780040D1
+:1010800013B50E4C204600F091FA04F11400002331
+:101090004FF400720A49009400F04EF9094B4FF4E6
+:1010A0000072094904F13800009400F0C7F9074ABA
+:1010B000074BC4E9172302B010BD00BFD82300209E
+:1010C00044240020711000084426002000780040CD
+:1010D00000E1F505037C30B5244C002918BF0C460F
+:1010E000012B11D1224B98420ED1224BD3F8E8208C
+:1010F00042F08042C3F8E820D3F8102142F0804249
+:10110000C3F81021D3F810312268036EC16D03EBD0
+:1011100052038466B3FBF2F36268150442BF23F006
+:10112000070503F0070343EA4503CB60A36843F0D8
+:1011300040034B60E36843F001038B6042F4967315
+:1011400043F001030B604FF0FF330B62510505D5EF
+:1011500012F0102205D0B2F1805F04D080F8643024
+:1011600030BD7F23FAE73F23F8E700BFB441000812
+:10117000D8230020004402582DE9F047C66D0546EB
+:101180003768F469210734621AD014F0080118BFD7
+:101190004FF48071E20748BF41F02001A3074FF0F0
+:1011A000300348BF41F04001600748BF41F0800173
+:1011B00083F31188281DFFF753FF002383F3118861
+:1011C000E2050AD5302383F311884FF48061281D8E
+:1011D000FFF746FF002383F311884FF030094FF0EB
+:1011E000000A14F0200838D13B0616D54FF030091C
+:1011F00005F1380A200610D589F31188504600F011
+:1012000051F9002836DA0821281DFFF729FF27F0B9
+:1012100080033360002383F31188790614D56206B6
+:1012200012D5302383F31188D5E913239A4208D1CC
+:101230002B6C33B127F040071021281DFFF710FF5A
+:101240003760002383F31188E30618D5AA6E13696B
+:10125000ABB15069BDE8F047184789F31188736A4C
+:10126000284695F86410194000F0BAF98AF31188FD
+:10127000F469B6E7B06288F31188F469BAE7BDE8AB
+:10128000F0870000F8B51546826804460B46AA426E
+:1012900000D28568A1692669761AB5420BD2184634
+:1012A0002A46FFF7E7FDA3692B44A3612846A368FC
+:1012B0005B1BA360F8BD0CD9AF1B18463246FFF785
+:1012C000D9FD3A46E1683044FFF7D4FDE3683B447A
+:1012D000EBE718462A46FFF7CDFDE368E5E7000097
+:1012E00083689342F7B50446154600D28568D4E971
+:1012F0000460361AB5420BD22A46FFF7BBFD63697C
+:101300002B4463612846A3685B1BA36003B0F0BD58
+:101310000DD93246AF1B0191FFF7ACFD01993A465A
+:10132000E0683144FFF7A6FDE3683B44E9E72A465D
+:10133000FFF7A0FDE368E4E710B50A440024C361A9
+:10134000029B8460C16002610362C0E90000C0E9E1
+:10135000051110BD08B5D0E90532934201D182686C
+:1013600082B98268013282605A1C42611970002180
+:10137000D0E904329A4224BFC368436100F0B2FE50
+:10138000002008BD4FF0FF30FBE7000070B53023B0
+:1013900004460E4683F31188A568A5B1A368A26927
+:1013A000013BA360531CA36115782269934224BFBB
+:1013B000E368A361E3690BB120469847002383F3F8
+:1013C0001188284607E03146204600F07BFE0028C1
+:1013D000E2DA85F3118870BD2DE9F74F04460E4619
+:1013E00017469846D0F81C904FF0300A8AF31188BF
+:1013F0004FF0000B154665B12A4631462046FFF7EF
+:1014000041FF034660B94146204600F05BFE0028DC
+:10141000F1D0002383F31188781B03B0BDE8F08F6F
+:10142000B9F1000F03D001902046C847019B8BF310
+:101430001188ED1A1E448AF31188DCE7C160C3618C
+:10144000009B82600362C0E905111144C0E90000FD
+:1014500001617047F8B504460D461646302383F304
+:101460001188A768A7B1A368013BA36063695A1CF0
+:1014700062611D70D4E904329A4224BFE36863615B
+:10148000E3690BB120469847002080F3118807E0FC
+:101490003146204600F016FE0028E2DA87F3118874
+:1014A000F8BD0000D0E9052310B59A4201D1826849
+:1014B0007AB982680021013282605A1C82611C78EC
+:1014C00003699A4224BFC368836100F00BFE204683
+:1014D00010BD4FF0FF30FBE72DE9F74F04460E46F5
+:1014E00017469846D0F81C904FF0300A8AF31188BE
+:1014F0004FF0000B154665B12A4631462046FFF7EE
+:10150000EFFE034660B94146204600F0DBFD0028AF
+:10151000F1D0002383F31188781B03B0BDE8F08F6E
+:10152000B9F1000F03D001902046C847019B8BF30F
+:101530001188ED1A1E448AF31188DCE702684368BB
+:101540001143016003B11847704700001430FFF7E2
+:1015500043BF00004FF0FF331430FFF73DBF0000E2
+:101560003830FFF7B9BF00004FF0FF333830FFF7D6
+:10157000B3BF00001430FFF709BF00004FF0FF3188
+:101580001430FFF703BF00003830FFF763BF0000DF
+:101590004FF0FF323830FFF75DBF0000012914BF64
+:1015A0006FF0130000207047FFF76ABD044B036023
+:1015B00000234360C0E9023301230374704700BF76
+:1015C000CC41000810B53023044683F31188FFF79F
+:1015D00081FD02230020237480F3118810BD0000D8
+:1015E00038B5C36904460D461BB904210844FFF70A
+:1015F000A5FF294604F11400FFF7ACFE002806DA27
+:10160000201D4FF40061BDE83840FFF797BF38BD9B
+:10161000026843681143016003B118477047000036
+:1016200013B5406B00F58054D4F8A4381A681178CB
+:10163000042914D1017C022911D1197901231289BD
+:101640008B4013420BD101A94C3002F061F8D4F861
+:10165000A4480246019B2179206800F0DFF902B01E
+:1016600010BD0000143001F0E3BF00004FF0FF3365
+:10167000143001F0DDBF00004C3002F0B5B80000BE
+:101680004FF0FF334C3002F0AFB80000143001F0DF
+:10169000B1BF00004FF0FF31143001F0ABBF0000CC
+:1016A0004C3002F081B800004FF0FF324C3002F0B5
+:1016B0007BB800000020704710B500F58054D4F8C6
+:1016C000A4381A681178042917D1017C022914D191
+:1016D0005979012352898B4013420ED1143001F005
+:1016E00043FF024648B1D4F8A4484FF440736179EF
+:1016F0002068BDE8104000F07FB910BD406BFFF7D7
+:10170000DBBF0000704700007FB5124B01250426A7
+:10171000044603600023057400F1840243602946F7
+:10172000C0E902330C4B0290143001934FF4407324
+:10173000009601F0F5FE094B04F69442294604F1A7
+:101740004C000294CDE900634FF4407301F0BCFFFC
+:1017500004B070BDF4410008FD1600082116000811
+:101760000A68302383F311880B790B3342F8230086
+:101770004B79133342F823008B7913B10B3342F8C2
+:10178000230000F58053C3F8A4180223037400203B
+:1017900080F311887047000038B5037F044613B109
+:1017A00090F85430ABB90125201D0221FFF730FF1E
+:1017B00004F114006FF00101257700F09FFC04F1A3
+:1017C0004C0084F854506FF00101BDE8384000F03F
+:1017D00095BC38BD10B5012104460430FFF718FF51
+:1017E0000023237784F8543010BD000038B5044638
+:1017F0000025143001F0ACFE04F14C00257701F017
+:101800007BFF201D84F854500121FFF701FF204683
+:10181000BDE83840FFF750BF90F8803003F0600318
+:10182000202B06D190F881200023212A03D81F2ADB
+:1018300006D800207047222AFBD1C0E91D3303E0FF
+:10184000034A426707228267C3670120704700BFCF
+:101850003422002037B500F58055D5F8A4381A6831
+:10186000117804291AD1017C022917D11979012391
+:1018700012898B40134211D100F14C04204601F033
+:10188000FBFF58B101A9204601F042FFD5F8A4485A
+:101890000246019B2179206800F0C0F803B030BDFA
+:1018A00001F10B03F0B550F8236085B004460D46F6
+:1018B000FEB1302383F3118804EB8507301D082126
+:1018C000FFF7A6FEFB6806F14C005B691B681BB1C5
+:1018D000019001F02BFF019803A901F019FF0246C6
+:1018E00048B1039B2946204600F098F8002383F373
+:1018F000118805B0F0BDFB685A691268002AF5D05E
+:101900001B8A013B1340F1D104F18002EAE7000099
+:10191000133138B550F82140ECB1302383F31188EE
+:1019200004F58053D3F8A4281368527903EB82039B
+:10193000DB689B695D6845B104216018FFF768FEAC
+:10194000294604F1140001F019FE2046FFF7B4FE09
+:10195000002383F3118838BD7047000001F0D0B830
+:1019600001234022002110B5044600F8303BFFF768
+:10197000A7FA0023C4E9013310BD000010B53023DD
+:10198000044683F311882422416000210C30FFF7C4
+:1019900097FA204601F0D6F802230020237080F346
+:1019A000118810BD70B500EB8103054650690E46E5
+:1019B0001446DA6018B110220021FFF781FAA069FD
+:1019C00018B110220021FFF77BFA31462846BDE806
+:1019D000704001F0BDB9000083682022002103F0AF
+:1019E000011310B5044683601030FFF769FA2046F2
+:1019F000BDE8104001F038BAF0B4012500EB8104D5
+:101A000047898D40E4683D43A469458123600023F4
+:101A1000A2606360F0BC01F055BA0000F0B401258B
+:101A200000EB810407898D40E4683D4364690581CA
+:101A300023600023A2606360F0BC01F0CBBA000019
+:101A400070B5022300250446242203702946C0F8FD
+:101A500088500C3040F8045CFFF732FA204684F8D6
+:101A6000705001F009F963681B6823B129462046CC
+:101A7000BDE87040184770BD0378052B10B50446CB
+:101A80000AD080F88C300523037043681B680BB1C3
+:101A9000042198470023A36010BD000001780529A8
+:101AA00006D190F88C20436802701B6803B1184778
+:101AB0007047000070B590F87030044613B10023F1
+:101AC00080F8703004F18002204601F0F1F963687B
+:101AD0009B68B3B994F8803013F0600535D00021CD
+:101AE000204601F0E3FC0021204601F0D3FC6368AE
+:101AF0001B6813B1062120469847062384F87030EE
+:101B000070BD204698470028E4D0B4F88630A26F14
+:101B10009A4288BFA36794F98030A56F002B4FF0DD
+:101B2000300380F20381002D00F0F280092284F856
+:101B3000702083F3118800212046D4E91D23FFF78C
+:101B40006DFF002383F31188DAE794F8812003F016
+:101B50007F0343EA022340F20232934200F0C58041
+:101B600021D8B3F5807F48D00DD8012B3FD0022B70
+:101B700000F09380002BB2D104F188026267022248
+:101B8000A267E367C1E7B3F5817F00F09B80B3F5FF
+:101B9000407FA4D194F88230012BA0D1B4F88830D2
+:101BA00043F0020332E0B3F5006F4DD017D8B3F520
+:101BB000A06F31D0A3F5C063012B90D86368204695
+:101BC00094F882205E6894F88310B4F88430B047AB
+:101BD000002884D0436863670368A3671AE0B3F5FD
+:101BE000106F36D040F6024293427FF478AF5C4BE0
+:101BF00063670223A3670023C3E794F88230012BB5
+:101C00007FF46DAFB4F8883023F00203A4F8883075
+:101C1000C4E91D55E56778E7B4F88030B3F5A06FE7
+:101C20000ED194F88230204684F88A3001F082F890
+:101C300063681B6813B10121204698470323237072
+:101C40000023C4E91D339CE704F18B036367012380
+:101C5000C3E72378042B10D1302383F31188204667
+:101C6000FFF7BAFE85F311880321636884F88B506F
+:101C700021701B680BB12046984794F88230002BE6
+:101C8000DED084F88B300423237063681B68002B3C
+:101C9000D6D0022120469847D2E794F884302046D7
+:101CA0001D0603F00F010AD501F0F4F8012804D055
+:101CB00002287FF414AF2B4B9AE72B4B98E701F0E7
+:101CC000DBF8F3E794F88230002B7FF408AF94F848
+:101CD000843013F00F01B3D01A06204602D501F06C
+:101CE000FDFBADE701F0EEFBAAE794F88230002B94
+:101CF0007FF4F5AE94F8843013F00F01A0D01B06EA
+:101D0000204602D501F0D2FB9AE701F0C3FB97E72A
+:101D1000142284F8702083F311882B462A46294622
+:101D20002046FFF769FE85F31188E9E65DB11522CB
+:101D300084F8702083F3118800212046D4E91D2304
+:101D4000FFF75AFEFDE60B2284F8702083F311881A
+:101D50002B462A4629462046FFF760FEE3E700BFF0
+:101D6000244200081C4200082042000838B590F8C0
+:101D700070300446002B3ED0063BDAB20F2A34D82E
+:101D80000F2B32D8DFE803F03731310822323131FE
+:101D90003131313131313737856FB0F886309D427E
+:101DA00014D2C3681B8AB5FBF3F203FB12556DB95D
+:101DB000302383F311882B462A462946FFF72EFE4F
+:101DC00085F311880A2384F870300EE0142384F818
+:101DD0007030302383F31188002320461A461946B9
+:101DE000FFF70AFE002383F3118838BDC36F03B1E8
+:101DF00098470023E7E70021204601F057FB002128
+:101E0000204601F047FB63681B6813B1062120469A
+:101E100098470623D7E7000010B590F870300446C5
+:101E2000142B29D017D8062B05D001D81BB110BD13
+:101E3000093B022BFBD80021204601F037FB002193
+:101E4000204601F027FB63681B6813B1062120467A
+:101E50009847062319E0152BE9D10B2380F8703041
+:101E6000302383F3118800231A461946FFF7D6FD65
+:101E7000002383F31188DAE7C3689B695B68002B52
+:101E8000D5D1C36F03B19847002384F87030CEE7F3
+:101E900000238268037503691B6899689142FBD22D
+:101EA0005A6803604260106058607047002382687F
+:101EB000037503691B6899689142FBD85A680360EF
+:101EC000426010605860704708B50846302383F3BD
+:101ED00011880B7D032B05D0042B0DD02BB983F378
+:101EE000118808BD8B6900221A604FF0FF338361AF
+:101EF000FFF7CEFF0023F2E7D1E9003213605A600A
+:101F0000F3E70000FFF7C4BF054BD96808751868F0
+:101F1000026853601A600122D8600275FEF774BA35
+:101F2000482800200C4B30B5DD684B1C87B00446B8
+:101F30000FD02B46094A684600F074F92046FFF797
+:101F4000E3FF009B13B1684600F076F9A86907B07B
+:101F500030BDFFF7D9FFF9E748280020C91E000867
+:101F6000044B1A68DB6890689B68984294BF002015
+:101F70000120704748280020084B10B51C68D8681D
+:101F8000226853601A600122DC602275FFF78EFF21
+:101F900001462046BDE81040FEF736BA482800202A
+:101FA000044B1A68DB6892689B689A4201D9FFF774
+:101FB000E3BF70474828002038B5074C01230025AF
+:101FC000064907482370656001F094FC02232370E2
+:101FD00085F3118838BD00BFB02A00202C420008CC
+:101FE0004828002000F05EB9EFF3118020B9EFF32C
+:101FF0000583302282F311887047000010B530B994
+:10200000EFF30584C4F3080414B180F3118810BD04
+:10201000FFF7C6FF84F31188F9E70000034A51680F
+:1020200053685B1A9842FBD8704700BF001000E06D
+:102030008B600223086108468B8270478368A3F196
+:10204000840243F8142C026943F8442C426943F893
+:10205000402C094A43F8242CC268A3F1200043F81D
+:10206000182C022203F80C2C002203F80B2C034A34
+:1020700043F8102C704700BF2104000848280020B6
+:1020800008B5FFF7DBFFBDE80840FFF73BBF0000E6
+:10209000024BDB6898610F20FFF736BF482800200D
+:1020A000302383F31188FFF7F3BF000008B5014622
+:1020B000302383F311880820FFF734FF002383F3D4
+:1020C000118808BD064BDB6839B1426818605A6058
+:1020D000136043600420FFF725BF4FF0FF307047C7
+:1020E000482800200368984206D01A6802605060B1
+:1020F00018469961FFF706BF7047000038B50446DF
+:102100000D462068844200D138BD036823605C60BE
+:102110008561FFF7F7FEF4E7036810B59C68A242FB
+:102120000CD85C688A600B604C60216059609968CB
+:102130008A1A9A604FF0FF33836010BD121B1B6830
+:10214000ECE700000A2938BF0A2170B504460D46A5
+:102150000A26601901F0C6FB01F0AEFB041BA54284
+:1021600003D8751C04462E46F3E70A2E04D9012035
+:10217000BDE8704001F0FEBB70BD0000F8B5144B27
+:102180000D460A2A4FF00A07D96103F11001826057
+:1021900038BF0A224160196914460160486018611D
+:1021A000A81801F08FFB01F087FB431B0646A342F2
+:1021B00006D37C1C28192746354601F093FBF2E72D
+:1021C0000A2F04D90120BDE8F84001F0D3BBF8BDC7
+:1021D00048280020F8B506460D4601F06DFB0F4A71
+:1021E000134653F8107F9F4206D12A4601463046D7
+:1021F000BDE8F840FFF7C2BFD169BB68441A2C198B
+:1022000028BF2C46A34202D92946FFF79BFF22464E
+:1022100031460348BDE8F840FFF77EBF482800205C
+:1022200058280020C0E90323002310B45DF8044BB4
+:102230004361FFF7CFBF000010B5194C23699842E6
+:102240000DD08168D0E9003213605A609A680A4460
+:102250009A60002303604FF0FF33A36110BD026852
+:10226000234643F8102F53600022026022699A42ED
+:1022700003D1BDE8104001F02FBB936881680B4487
+:10228000936001F019FB2269E1699268441AA24245
+:10229000E4D91144BDE81040091AFFF753BF00BF4D
+:1022A000482800202DE9F047DFF8BC8008F110072E
+:1022B0002C4ED8F8105001F0FFFAD8F81C40AA684C
+:1022C000031B9A423ED814444FF00009D5E900326E
+:1022D000C8F81C4013605A60C5F80090D8F8103058
+:1022E000B34201D101F0F8FA89F31188D5E903313D
+:1022F00028469847302383F311886B69002BD8D088
+:1023000001F0DAFA6A69A0EB040982464A450DD267
+:10231000022001F02FFB0022D8F81030B34208D180
+:1023200051462846BDE8F047FFF728BF121A22445D
+:10233000F2E712EB09092946384638BF4A46FFF74B
+:10234000EBFEB5E7D8F81030B34208D01444C8F813
+:102350001C00211AA960BDE8F047FFF7F3BEBDE8F5
+:10236000F08700BF58280020482800200020704730
+:10237000FEE70000704700004FF0FF30704700009C
+:1023800002290CD0032904D00129074818BF0020D6
+:102390007047032A05D8054800EBC200704704487F
+:1023A00070470020704700BF04430008442200200B
+:1023B000B842000870B59AB005460846144601A90F
+:1023C00000F0C2F801A8FEF773FD431C0022C6B25C
+:1023D0005B001046C5E9003423700323023404F87F
+:1023E000013C01ABD1B202348E4201D81AB070BDAB
+:1023F00013F8011B013204F8010C04F8021CF1E788
+:1024000008B5302383F311880348FFF723FA00232C
+:1024100083F3118808BD00BFB82A002090F88030EF
+:1024200003F01F02012A07D190F881200B2A03D163
+:102430000023C0E91D3315E003F06003202B08D111
+:10244000B0F884302BB990F88120212A03D81F2AB4
+:1024500004D8FFF7E1B9222AEBD0FAE7034A426732
+:1024600007228267C3670120704700BF3B2200201C
+:1024700007B5052917D8DFE801F019160319192047
+:10248000302383F31188104A01210190FFF78AFA63
+:10249000019802210D4AFFF785FA0D48FFF7A6F9CA
+:1024A000002383F3118803B05DF804FB302383F32A
+:1024B00011880748FFF770F9F2E7302383F311889A
+:1024C0000348FFF787F9EBE7584200087C42000811
+:1024D000B82A002038B50C4D0C4C2A460C4904F1A2
+:1024E0000800FFF767FF05F1CA0204F1100009496F
+:1024F000FFF760FF05F5CA7204F118000649BDE850
+:102500003840FFF757BF00BF90430020442200200F
+:1025100038420008424200084D42000870B50446A7
+:1025200008460D46FEF7C4FCC6B2204601340378C7
+:102530000BB9184670BD32462946FEF7A5FC0028A7
+:10254000F3D10120F6E700002DE9F04705460C46DF
+:10255000FEF7AEFC2B49C6B22846FFF7DFFF08B1F5
+:102560000636F6B228492846FFF7D8FF08B11036DC
+:10257000F6B2632E0BD8DFF88C80DFF88C90234FF7
+:10258000DFF894A02E7846B92670BDE8F08729467A
+:102590002046BDE8F04701F0EFBD252E2ED10722E1
+:1025A00041462846FEF770FC70B9194B224603F1EC
+:1025B0000C0153F8040B8B4242F8040BF9D11B7841
+:1025C00007350D341370DDE7082249462846FEF72B
+:1025D0005BFC98B9A21C0F4B197802320909C95D3E
+:1025E00002F8041C13F8011B01F00F015345C95DEB
+:1025F00002F8031CF0D118340835C3E7013504F89C
+:10260000016BBFE7244300084D4200083A4300082D
+:102610002C43000800E8F11F0CE8F11FBFF34F8FB7
+:10262000044B1A695107FCD1D3F810215207F8D195
+:10263000704700BF0020005208B50D4B1B78ABB9A6
+:10264000FFF7ECFF0B4BDA68D10704D50A4A5A6052
+:1026500002F188325A60D3F80C21D20706D5064A17
+:10266000C3F8042102F18832C3F8042108BD00BF79
+:10267000EE450020002000522301674508B5114BAC
+:102680001B78F3B9104B1A69510703D5DA6842F089
+:102690004002DA60D3F81021520705D5D3F80C2197
+:1026A00042F04002C3F80C21FFF7B8FF064BDA688E
+:1026B00042F00102DA60D3F80C2142F00102C3F8C3
+:1026C0000C2108BDEE450020002000520F289ABFC3
+:1026D00000F5806040040020704700004FF4003097
+:1026E00070470000102070470F2808B50BD8FFF77F
+:1026F000EDFF00F500330268013204D1043083425B
+:10270000F9D1012008BD0020FCE700000F2870B5BA
+:10271000054645D8FFF768FC224CFFF77FFF0646C9
+:10272000FFF78AFF4FF0FF33072D6361C4F81431C0
+:1027300020D82361FFF772FF2B0243F02403E360EC
+:10274000E36843F08003E36023695A07FCD428461A
+:10275000FFF764FF4FF40031FFF7B8FF00F002F914
+:102760003046FFF78BFFFFF749FC2846BDE8704075
+:10277000FFF7BABFC4F81031FFF750FFA5F1080307
+:102780001B0243F02403C4F80C31D4F80C3143F09D
+:102790008003C4F80C31D4F810315B07FBD4D6E7C2
+:1027A000002070BD002000522DE9F84F40EA0203DE
+:1027B00005460C461746D80602D00020BDE8F88F23
+:1027C00027F01F07DFF8D4B0FFF736FF2744BC42DD
+:1027D00003D10120FFF752FFF0E7202229462046CF
+:1027E00001F0BAFC10B920352034F0E72B4605F192
+:1027F00020021E68711CE0D104339A42F9D1FFF720
+:10280000F3FB05F17843234AB3F5801F224B28BF21
+:102810009A4603F1040338BF9046A2F1080228BF8C
+:102820009846A3F108033ABF9146DA469946FFF766
+:10283000F5FEC8F80060A5EB040CD9F8002004F1FF
+:102840001C0142F00202C9F80020221FDAF80060E1
+:1028500016F00506FAD152F8043F8A424CF80230CD
+:10286000F4D1BFF34F8FFFF7D9FE4FF0FF32C8F816
+:102870000020D9F8002022F00202C9F80020FFF75A
+:10288000BDFB20222146284601F066FC0028AAD084
+:1028900030469FE7142000521021005210200052B1
+:1028A00010B5084C237828B11BB9FFF7C5FE0123EA
+:1028B000237010BD002BFCD02070BDE81040FFF746
+:1028C000DDBE00BFEE4500200244074BD2B210B57A
+:1028D000904200D110BD441C00B253F8200041F8D2
+:1028E000040BE0B2F4E700BF504000580E4B30B587
+:1028F0001C6F240405D41C6F1C671C6F44F4004437
+:102900001C670A4C02442368D2B243F480732360EC
+:10291000074B904200D130BD441C51F8045B00B21B
+:1029200043F82050E0B2F4E700440258004802584F
+:102930005040005807B5012201A90020FFF7C4FF4D
+:10294000019803B05DF804FB13B50446FFF7F2FFEE
+:10295000A04205D0012201A900200194FFF7C6FF83
+:1029600002B010BD0144BFF34F8F064B884204D321
+:10297000BFF34F8FBFF36F8F7047C3F85C022030F7
+:10298000F4E700BF00ED00E0034B1A681AB9034AF0
+:10299000D2F8D0241A607047F04500200040025859
+:1029A00008B5FFF7F1FF024B1868C0F3806008BD5F
+:1029B000F045002070B5BFF34F8FBFF36F8F1A4AF9
+:1029C0000021C2F85012BFF34F8FBFF36F8F5369CE
+:1029D00043F400335361BFF34F8FBFF36F8FC2F8DF
+:1029E0008410BFF34F8FD2F8803043F6E074C3F306
+:1029F000C900C3F34E335B0103EA0406014646EA0D
+:102A000081750139C2F86052F9D2203B13F1200FD1
+:102A1000F2D1BFF34F8F536943F480335361BFF357
+:102A20004F8FBFF36F8F70BD00ED00E0FEE7000039
+:102A30000A4B0B480B4A90420BD30B4BC11EDA1CBE
+:102A4000121A22F003028B4238BF00220021FEF747
+:102A500037BA53F8041B40F8041BECE72C45000878
+:102A6000C4470020C4470020C4470020704700002E
+:102A7000074BD3F8D81021EA0001C3F8D810D3F8D7
+:102A8000002122EA0002C3F80021D3F80031704788
+:102A90000044025870B5D0E9244300224FF0FF35BE
+:102AA0009E6804EB42135101D3F80009002805DAAF
+:102AB000D3F8000940F08040C3F80009D3F8000BB8
+:102AC000002805DAD3F8000B40F08040C3F8000B73
+:102AD000013263189642C3F80859C3F8085BE0D284
+:102AE0004FF00113C4F81C3870BD0000890141F09B
+:102AF0002001016103699B06FCD41220FFF78EBA06
+:102B000010B50A4C2046FEF72BFF094BC4F8903055
+:102B1000084BC4F89430084C2046FEF721FF074BC1
+:102B2000C4F89030064BC4F8943010BDF445002032
+:102B30000000084070430008904600200000044058
+:102B40007C43000870B503780546012B5CD1434BEC
+:102B5000D0F89040984258D1414B0E216520D3F8CF
+:102B6000D82042F00062C3F8D820D3F8002142F008
+:102B70000062C3F80021D3F80021D3F8802042F08E
+:102B80000062C3F88020D3F8802022F00062C3F8EE
+:102B90008020D3F8803000F0ADFC324BE360324B44
+:102BA000C4F800380023D5F89060C4F8003EC02374
+:102BB00023604FF40413A3633369002BFCDA012371
+:102BC0000C203361FFF72AFA3369DB07FCD41220AB
+:102BD000FFF724FA3369002BFCDA00262846A660AA
+:102BE000FFF758FF6B68C4F81068DB68C4F8146816
+:102BF000C4F81C6883BB1D4BA3614FF0FF336361B6
+:102C0000A36843F00103A36070BD194B9842C9D17A
+:102C1000134B4FF08060D3F8D82042F00072C3F815
+:102C2000D820D3F8002142F00072C3F80021D3F875
+:102C30000021D3F8802042F00072C3F88020D3F83E
+:102C4000802022F00072C3F88020D3F88030FFF794
+:102C50000FFF0E214D209EE7064BCDE7F4450020E7
+:102C6000004402584014004003002002003C30C0E1
+:102C700090460020083C30C0F8B5D0F8904005469A
+:102C800000214FF000662046FFF730FFD5F8941082
+:102C900000234FF001128F684FF0FF30C4F8343832
+:102CA000C4F81C2804EB431201339F42C2F80069A8
+:102CB000C2F8006BC2F80809C2F8080BF2D20B6820
+:102CC000D5F89020C5F89830636210231361166917
+:102CD00016F01006FBD11220FFF7A0F9D4F8003847
+:102CE00023F4FE63C4F80038A36943F4402343F09F
+:102CF0001003A3610923C4F81038C4F814380B4B2F
+:102D0000EB604FF0C043C4F8103B094BC4F8003BE4
+:102D1000C4F81069C4F80039D5F8983003F11002EE
+:102D200043F48013C5F89820A362F8BD4C43000813
+:102D300040800010D0F8902090F88A10D2F8003827
+:102D400023F4FE6343EA0113C2F800387047000021
+:102D50002DE9F84300EB8103D0F890500C468046F3
+:102D6000DA680FFA81F94801166806F00306731E47
+:102D7000022B05EB41134FF0000194BFB604384E0F
+:102D8000C3F8101B4FF0010104F1100398BF06F1C6
+:102D9000805601FA03F3916998BF06F500460029B1
+:102DA0003AD0578A04F15801374349016F50D5F89A
+:102DB0001C180B430021C5F81C382B180127C3F839
+:102DC0001019A7405369611E9BB3138A928B9B080D
+:102DD000012A88BF5343D8F89820981842EA034341
+:102DE00001F140022146C8F89800284605EB82020E
+:102DF0005360FFF77BFE08EB8900C3681B8A43EA38
+:102E0000845348341E4364012E51D5F81C381F43A7
+:102E1000C5F81C78BDE8F88305EB4917D7F8001B07
+:102E200021F40041C7F8001BD5F81C1821EA030360
+:102E3000C0E704F13F030B4A2846214605EB830314
+:102E40005A60FFF753FE05EB4910D0F8003923F420
+:102E50000043C0F80039D5F81C3823EA0707D7E744
+:102E60000080001000040002D0F894201268C0F81E
+:102E70009820FFF70FBE00005831D0F8903049017C
+:102E80005B5813F4004004D013F4001F0CBF022061
+:102E9000012070474831D0F8903049015B5813F455
+:102EA000004004D013F4001F0CBF02200120704723
+:102EB00000EB8101CB68196A0B6813604B685360A3
+:102EC0007047000000EB810330B5DD68AA69136824
+:102ED000D36019B9402B84BF402313606B8A1468F8
+:102EE000D0F890201C4402EB4110013C09B2B4FB25
+:102EF000F3F46343033323F0030343EAC44343F08F
+:102F0000C043C0F8103B2B6803F00303012B0ED124
+:102F1000D2F8083802EB411013F4807FD0F8003B60
+:102F200014BF43F0805343F00053C0F8003B02EB62
+:102F30004112D2F8003B43F00443C2F8003B30BDDD
+:102F40002DE9F041D0F8906005460C4606EB4113A0
+:102F5000D3F8087B3A07C3F8087B08D5D6F81438AD
+:102F60001B0704D500EB8103DB685B689847FA0711
+:102F70001FD5D6F81438DB071BD505EB8403D968B9
+:102F8000CCB98B69488A5A68B2FBF0F600FB16226E
+:102F90008AB91868DA6890420DD2121AC3E900247F
+:102FA000302383F3118821462846FFF78BFF84F3F3
+:102FB0001188BDE8F081012303FA04F26B8923EA4A
+:102FC00002036B81CB68002BF3D021462846BDE875
+:102FD000F041184700EB81034A0170B5DD68D0F875
+:102FE00090306C692668E66056BB1A444FF40020A6
+:102FF000C2F810092A6802F00302012A0AB20ED1AF
+:10300000D3F8080803EB421410F4807FD4F80009C9
+:1030100014BF40F0805040F00050C4F8000903EBAA
+:103020004212D2F8000940F00440C2F8000901221F
+:10303000D3F8340802FA01F10143C3F8341870BD23
+:1030400019B9402E84BF4020206020681A442E8A7F
+:103050008419013CB4FBF6F440EAC44040F000504F
+:10306000C6E700002DE9F843D0F8906005460C460D
+:103070004F0106EB4113D3F8088918F0010FC3F88C
+:1030800008891CD0D6F81038DB0718D500EB81036F
+:10309000D3F80CC0DCF81430D3F800E0DA689645B9
+:1030A00030D2A2EB0E024FF000091A60C3F8049070
+:1030B000302383F31188FFF78DFF89F3118818F00F
+:1030C000800F1DD0D6F834380126A640334217D0E1
+:1030D00005EB84030134D5F89050D3F80CC0E4B26A
+:1030E0002F44DCF8142005EB0434D2F800E05168DA
+:1030F000714514D3D5F8343823EA0606C5F8346888
+:10310000BDE8F883012303FA01F2038923EA0203ED
+:103110000381DCF80830002BD1D09847CFE7AEEB25
+:103120000103BCF81000834228BF0346D7F81809F2
+:1031300080B2B3EB800FE3D89068A0F1040959F88E
+:10314000048FC4F80080A0EB09089844B8F1040F7C
+:10315000F5D818440B4490605360C8E72DE9F84F48
+:10316000D0F8905004466E69AB691E4016F4805842
+:103170006E6103D0BDE8F84FFEF762BC002E12DA94
+:10318000D5F8003E9B0705D0D5F8003E23F0030399
+:10319000C5F8003ED5F80438204623F00103C5F8F1
+:1031A0000438FEF77BFC370505D52046FFF772FC97
+:1031B0002046FEF761FCB0040CD5D5F8083813F0B2
+:1031C000060FEB6823F470530CBF43F4105343F421
+:1031D000A053EB6031071BD56368DB681BB9AB6993
+:1031E00023F00803AB612378052B0CD1D5F8003E02
+:1031F0009A0705D0D5F8003E23F00303C5F8003E3A
+:103200002046FEF74BFC6368DB680BB1204698470D
+:10321000F30200F1BA80B70226D5D4F890900027C7
+:103220004FF0010A09EB4712D2F8003B03F44023A8
+:10323000B3F5802F11D1D2F8003B002B0DDA628953
+:103240000AFA07F322EA0303638104EB8703DB68CE
+:10325000DB6813B13946204698470137D4F89430DB
+:10326000FFB29B689F42DDD9F00619D5D4F89000D3
+:10327000026AC2F30A1702F00F0302F4F012B2F569
+:10328000802F00F0CA80B2F5402F09D104EB8303F0
+:10329000002200F58050DB681B6A974240F0B08046
+:1032A0003003D5F8185835D5E90303D50021204659
+:1032B000FFF746FEAA0303D501212046FFF740FE93
+:1032C0006B0303D502212046FFF73AFE2F0303D5F7
+:1032D00003212046FFF734FEE80203D504212046EF
+:1032E000FFF72EFEA90203D505212046FFF728FE91
+:1032F0006A0203D506212046FFF722FE2B0203D5E2
+:1033000007212046FFF71CFEEF0103D508212046C8
+:10331000FFF716FE700340F1A780E90703D50021EF
+:103320002046FFF79FFEAA0703D501212046FFF79D
+:1033300099FE6B0703D502212046FFF793FE2F0766
+:1033400003D503212046FFF78DFEEE0603D50421A9
+:103350002046FFF787FEA80603D505212046FFF784
+:1033600081FE690603D506212046FFF77BFE2A066B
+:1033700003D507212046FFF775FEEB0574D52046DF
+:103380000821BDE8F84FFFF76DBED4F890904FF0DC
+:10339000000B4FF0010AD4F894305FFA8BF79B686A
+:1033A0009F423FF638AF09EB4713D3F8002902F4E8
+:1033B0004022B2F5802F20D1D3F80029002A1CDA50
+:1033C000D3F8002942F09042C3F80029D3F800292D
+:1033D000002AFBDB3946D4F89000FFF787FB2289EF
+:1033E0000AFA07F322EA0303238104EB8703DB686D
+:1033F0009B6813B13946204698470BF1010BCAE789
+:10340000910701D1D0F80080072A02F101029CBF88
+:1034100003F8018B4FEA18283FE704EB830300F51C
+:103420008050DA68D2F818C0DCF80820DCE9001C0B
+:10343000A1EB0C0C00218F4208D1DB689B699A68D4
+:103440003A449A605A683A445A6029E711F0030FE7
+:1034500001D1D0F800808C4501F1010184BF02F850
+:10346000018B4FEA1828E6E7BDE8F88F08B5034856
+:10347000FFF774FEBDE8084000F07ABBF445002079
+:1034800008B50348FFF76AFEBDE8084000F070BBCE
+:1034900090460020D0F8903003EB4111D1F8003B6A
+:1034A00043F40013C1F8003B70470000D0F890309F
+:1034B00003EB4111D1F8003943F40013C1F800398E
+:1034C00070470000D0F8903003EB4111D1F8003B79
+:1034D00023F40013C1F8003B70470000D0F890308F
+:1034E00003EB4111D1F8003923F40013C1F800397E
+:1034F00070470000090100F16043012203F56143B8
+:10350000C9B283F8001300F01F039A4043099B00DF
+:1035100003F1604303F56143C3F880211A607047EB
+:1035200030B50433039C0172002104FB0325C16004
+:10353000C0E90653049B0363059BC0E90000C0E992
+:103540000422C0E90842C0E90A11436330BD00000B
+:103550000022416AC260C0E90411C0E90A226FF08A
+:103560000101FEF7CBBD0000D0E90432934201D146
+:10357000C2680AB9181D70470020704703691960B6
+:103580000021C2680132C260C26913448269934259
+:10359000036124BF436A0361FEF7A4BD38B5044646
+:1035A0000D46E3683BB162690020131D1268A362F7
+:1035B0001344E36207E0237A33B929462046FEF735
+:1035C00081FD0028EDDA38BD6FF00100FBE7000057
+:1035D000C368C269013BC360436913448269934273
+:1035E000436124BF436A436100238362036B03B1D9
+:1035F0001847704770B53023044683F31188866AF4
+:103600003EB9FFF7CBFF054618B186F3118828466F
+:1036100070BDA36AE26A13F8015B9342A36202D30E
+:103620002046FFF7D5FF002383F31188EFE7000062
+:103630002DE9F84F04460E46174698464FF03009DC
+:1036400089F311880025AA46D4F828B0BBF1000FF1
+:1036500009D141462046FFF7A1FF20B18BF3118825
+:103660002846BDE8F88FD4E90A12A7EB050B521AD9
+:10367000934528BF9346BBF1400F1BD9334601F158
+:10368000400251F8040B914243F8040BF9D1A36AAC
+:10369000403640354033A362D4E90A239A4202D32C
+:1036A0002046FFF795FF8AF31188BD42D8D289F3EF
+:1036B0001188C9E730465A46FDF7DCFBA36A5E4431
+:1036C0005D445B44A362E7E710B5029C04330172DA
+:1036D00003FB0421C460C0E906130023C0E90A33D8
+:1036E000039B0363049BC0E90000C0E90422C0E916
+:1036F0000842436310BD0000026A6FF00101C2601E
+:10370000426AC0E904220022C0E90A22FEF7F6BCA0
+:10371000D0E904239A4201D1C26822B9184650F870
+:10372000043B0B60704700231846FAE7C36800218A
+:10373000C2690133C36043691344826993424361A0
+:1037400024BF436A4361FEF7CDBC000038B5044690
+:103750000D46E3683BB1236900201A1DA262E269AD
+:103760001344E36207E0237A33B929462046FEF783
+:10377000A9FC0028EDDA38BD6FF00100FBE700007E
+:1037800003691960C268013AC260C2691344826960
+:103790009342036124BF436A036100238362036B86
+:1037A00003B118477047000070B530230D4604463A
+:1037B000114683F31188866A2EB9FFF7C7FF10B14F
+:1037C00086F3118870BDA36A1D70A36AE26A013393
+:1037D0009342A36204D3E16920460439FFF7D0FF86
+:1037E000002080F31188EDE72DE9F84F04460D46DF
+:1037F000904699464FF0300A8AF311880026B34666
+:10380000A76A4FB949462046FFF7A0FF20B187F3CA
+:1038100011883046BDE8F88FD4E90A073A1AA8EBB8
+:103820000607974228BF1746402F1BD905F14003D2
+:1038300055F8042B9D4240F8042BF9D1A36A403679
+:103840004033A362D4E90A239A4204D3E1692046B3
+:103850000439FFF795FF8BF311884645D9D28AF3D7
+:103860001188CDE729463A46FDF704FBA36A3D449B
+:103870003E443B44A362E5E7D0E904239A4217D1D2
+:10388000C3689BB1836A8BB1043B9B1A0ED0136053
+:10389000C368013BC360C3691A4483699A420261E9
+:1038A00024BF436A036100238362012318467047E3
+:1038B0000023FBE700F086B9014B586A704700BF50
+:1038C000000C0040034B002258631A610222DA60A8
+:1038D000704700BF000C0040014B0022DA607047C7
+:1038E000000C0040014B5863704700BF000C0040C3
+:1038F000FEE7000070B51B4B0025044686B05860FB
+:103900000E468562016300F00BF904F11003A56017
+:10391000E562C4E904334FF0FF33C4E90044C4E96D
+:103920000635FFF7C9FF2B46024604F13401204655
+:10393000C4E9082380230C4A2565FEF779FB01239F
+:103940000A4AE06000920375684672680192B268A4
+:10395000CDE90223064BCDE90435FEF791FB06B015
+:1039600070BD00BFB02A0020884300088D430008C6
+:10397000F1380008024AD36A1843D062704700BF8A
+:10398000482800204B6843608B688360CB68C36025
+:103990000B6943614B6903628B6943620B68036087
+:1039A0007047000008B53C4B40F2FF713B48D3F82C
+:1039B00088200A43C3F88820D3F8882022F4FF62C5
+:1039C00022F00702C3F88820D3F88820D3F8E0203B
+:1039D0000A43C3F8E020D3F808210A43C3F80821BA
+:1039E0002F4AD3F808311146FFF7CCFF00F580606D
+:1039F00002F11C01FFF7C6FF00F5806002F13801FB
+:103A0000FFF7C0FF00F5806002F15401FFF7BAFF35
+:103A100000F5806002F17001FFF7B4FF00F58060EF
+:103A200002F18C01FFF7AEFF00F5806002F1A80102
+:103A3000FFF7A8FF00F5806002F1C401FFF7A2FFC5
+:103A400000F5806002F1E001FFF79CFF00F5806067
+:103A500002F1FC01FFF796FF02F58C7100F5806022
+:103A6000FFF790FF00F076F90E4BD3F8902242F06A
+:103A70000102C3F89022D3F8942242F00102C3F865
+:103A800094220522C3F898204FF06052C3F89C207E
+:103A9000054AC3F8A02008BD00440258000002589F
+:103AA0009443000800ED00E01F00080308B500F093
+:103AB00033FBFEF781FA0F4BD3F8DC2042F04002D3
+:103AC000C3F8DC20D3F8042122F04002C3F804211B
+:103AD000D3F80431084B1A6842F008021A601A68D9
+:103AE00042F004021A60FEF74FFFBDE80840FEF7FF
+:103AF000F1BC00BF004402580018024870470000A3
+:103B0000EFF30983054968334A6B22F001024A63E7
+:103B100083F30988002383F31188704700EF00E0E6
+:103B2000302080F3118862B60D4B0E4AD96821F41B
+:103B3000E0610904090C0A430B49DA60D3F8FC2060
+:103B400042F08072C3F8FC20084AC2F8B01F116826
+:103B500041F0010111602022DA7783F822007047DA
+:103B600000ED00E00003FA0555CEACC5001000E002
+:103B7000302310B583F311880E4B5B6813F4006398
+:103B800014D0F1EE103AEFF309844FF08073683CE3
+:103B9000E361094BDB6B236684F30988FEF7E0F9E8
+:103BA00010B1064BA36110BD054BFBE783F31188F1
+:103BB000F9E700BF00ED00E000EF00E0330400088B
+:103BC00036040008114BD3F8E82042F00802C3F88D
+:103BD000E820D3F8102142F00802C3F810210C4A63
+:103BE000D3F81031D36B43F00803D363C722094BDA
+:103BF0009A624FF0FF32DA6200229A615A63DA6009
+:103C00005A6001225A611A60704700BF004402588E
+:103C10000010005C000C0040094A08B51169D36827
+:103C20000B40D9B29B076FEA0101116107D5302320
+:103C300083F31188FEF7D6F9002383F3118808BDBA
+:103C4000000C0040064BD3F8DC200243C3F8DC2014
+:103C5000D3F804211043C3F80401D3F804317047AA
+:103C6000004402583A4B4FF0FF31D3F8802062F005
+:103C70000042C3F88020D3F8802002F00042C3F84D
+:103C80008020D3F88020D3F88420C3F88410D3F8A0
+:103C900084200022C3F88420D3F88400D86F40F039
+:103CA000FF4040F4FF0040F4DF4040F07F00D86761
+:103CB000D86F20F0FF4020F4FF0020F4DF4020F018
+:103CC0007F00D867D86FD3F888006FEA40506FEA5A
+:103CD0005050C3F88800D3F88800C0F30A00C3F836
+:103CE0008800D3F88800D3F89000C3F89010D3F878
+:103CF0009000C3F89020D3F89000D3F89400C3F854
+:103D00009410D3F89400C3F89420D3F89400D3F817
+:103D10009800C3F89810D3F89800C3F89820D3F807
+:103D20009800D3F88C00C3F88C10D3F88C00C3F83B
+:103D30008C20D3F88C00D3F89C00C3F89C10D3F8E7
+:103D40009C10C3F89C20D3F89C3000F0B9B900BF98
+:103D50000044025808B50122534BC3F80821534BC5
+:103D6000D3F8F42042F00202C3F8F420D3F81C2167
+:103D700042F00202C3F81C210222D3F81C314C4B42
+:103D8000DA605A689104FCD54A4A1A6001229A60A6
+:103D9000494ADA6000221A614FF440429A61444B6A
+:103DA0009A699204FCD51A6842F480721A603F4BFB
+:103DB0001A6F12F4407F04D04FF480321A67002249
+:103DC0001A671A6842F001021A60384B1A685007E5
+:103DD000FCD500221A611A6912F03802FBD10121C8
+:103DE00019604FF0804159605A67344ADA62344AA8
+:103DF0001A611A6842F480321A602C4B1A689103D7
+:103E0000FCD51A6842F480521A601A689204FCD5F4
+:103E10002C4A2D499A6200225A63196301F57C01EC
+:103E2000DA6301F2E71199635A64284A1A64284A4E
+:103E3000DA621A6842F0A8521A601C4B1A6802F043
+:103E40002852B2F1285FF9D148229A614FF4886272
+:103E5000DA6140221A621F4ADA641F4A1A651F4A51
+:103E60005A651F4A9A6532231E4A1360136803F08D
+:103E70000F03022BFAD10D4A136943F003031361B8
+:103E8000136903F03803182BFAD14FF00050FFF7F5
+:103E9000D9FE4FF08040FFF7D5FE4FF00040BDE85F
+:103EA0000840FFF7CFBE00BF008000510044025819
+:103EB0000048025800C000F0020000010000FF01AD
+:103EC000008890082220400063020901470E05087F
+:103ED000DD0BBF0120000020000001100910E000F0
+:103EE00000010110002000524FF0B04208B5D2F896
+:103EF000883003F00103C2F8883023B1044A136804
+:103F00000BB150689847BDE80840FFF731BE00BFCD
+:103F1000444700204FF0B04208B5D2F8883003F093
+:103F20000203C2F8883023B1044A93680BB1D06809
+:103F30009847BDE80840FFF71BBE00BF444700207C
+:103F40004FF0B04208B5D2F8883003F00403C2F84D
+:103F5000883023B1044A13690BB150699847BDE812
+:103F60000840FFF705BE00BF444700204FF0B042B5
+:103F700008B5D2F8883003F00803C2F8883023B1BE
+:103F8000044A93690BB1D0699847BDE80840FFF730
+:103F9000EFBD00BF444700204FF0B04208B5D2F853
+:103FA000883003F01003C2F8883023B1044A136A42
+:103FB0000BB1506A9847BDE80840FFF7D9BD00BF74
+:103FC000444700204FF0B04310B5D3F8884004F4C4
+:103FD0007872C3F88820A30604D5124A936A0BB1FD
+:103FE000D06A9847600604D50E4A136B0BB1506B2C
+:103FF0009847210604D50B4A936B0BB1D06B9847B9
+:10400000E20504D5074A136C0BB1506C9847A30521
+:1040100004D5044A936C0BB1D06C9847BDE81040AE
+:10402000FFF7A6BD444700204FF0B04310B5D3F8CA
+:10403000884004F47C42C3F88820620504D5164AFF
+:10404000136D0BB1506D9847230504D5124A936D3B
+:104050000BB1D06D9847E00404D50F4A136E0BB135
+:10406000506E9847A10404D50B4A936E0BB1D06EE5
+:104070009847620404D5084A136F0BB1506F9847F4
+:10408000230404D5044A936F0BB1D06F9847BDE861
+:104090001040FFF76DBD00BF4447002008B503483E
+:1040A000FDF76AF8BDE80840FFF762BDD82300209D
+:1040B00008B5FFF7B1FDBDE80840FFF759BD0000A6
+:1040C000062108B50846FFF715FA06210720FFF775
+:1040D00011FA06210820FFF70DFA06210920FFF743
+:1040E00009FA06210A20FFF705FA06211720FFF733
+:1040F00001FA06212820FFF7FDF909217A20FFF7B0
+:10410000F9F907213220FFF7F5F90C215220BDE81B
+:104110000840FFF7EFB9000008B5FFF7A3FD00F076
+:104120000DF8FDF741FAFDF719FCFDF7EBFAFFF783
+:10413000E5FCBDE80840FFF7BDBB00000023054AD1
+:1041400019460133102BC2E9001102F10802F8D11F
+:10415000704700BF4447002010B501390244904227
+:1041600001D1002005E0037811F8014FA34201D0EE
+:10417000181B10BD0130F2E7034611F8012B03F8BC
+:10418000012B002AF9D1704753544D333248373F41
+:104190003F3F0053544D3332483734332F37353394
+:1041A0000000000001105A000310590001205800BF
+:1041B00003205600009600000000000000000000F0
+:1041C00000000000000000000000000000000000EF
+:1041D0006915000855150008911500087D1500089F
+:1041E0008915000875150008611500084D150008AF
+:1041F0009D15000800000000811600086D160008DB
+:10420000A916000895160008A11600088D160008CA
+:104210007916000865160008B516000800000000B1
+:104220000100000000000000633000002842000888
+:10423000A0280020B02A00204172647550696C6F7C
+:10424000740025424F415244252D424C00255345D0
+:104250005249414C2500000002000000000000000F
+:10426000A118000811190008400040006043002018
+:104270007043002002000000000000000300000066
+:1042800000000000591900080000000010000000A4
+:10429000804300200000000001000000000000003A
+:1042A000F445002001010200712400088123000868
+:1042B0001D2400080124000843000000C04200083B
+:1042C00009024300020100C0320904000001020299
+:1042D000010005240010010524010001042402024C
+:1042E0000524060001070582030800FF09040100F8
+:1042F000020A0000000705010240000007058102D4
+:1043000040000000120000000C43000812011001E0
+:10431000020000400912415700020102030100009F
+:104320000403090425424F41524425004B616B753B
+:10433000746548372D57696E670030313233343534
+:1043400036373839414243444546000000000000FA
+:10435000B51A00086D1D0008191E00084000400035
+:104360002C4700202C470020010000003C47002083
+:104370008000000040010000080000000001000073
+:1043800000100000080000006D61696E0069646C37
+:10439000650000000000802A00000000AAAAAAAA66
+:1043A00000000024FFFF00000000000000A00A0041
+:1043B0000000040100000000AAAAAAAA000000014F
+:1043C000FFFD0000000000000000000000000540AC
+:1043D00000000000AAAAAAAA00000500FF7F0000B2
+:1043E00000000000000000000000000000000000CD
+:1043F000AAAAAAAA00000000FFFF00000000000017
+:10440000000000004080020100000000AAAAAAAA41
+:1044100000400101F7FF00000000007007000000ED
+:104420000000000000000000AAAAAAAA00000000E4
+:10443000FFFF00000000000000000000000000007E
+:1044400000000000AAAAAAAA00000000FFFF0000C6
+:10445000000000000000000000000000000000005C
+:10446000AAAAAAAA00000000FFFF000000000000A6
+:10447000000000000000000000000000AAAAAAAA94
+:1044800000000000FFFF000000000000000000002E
+:104490000000000000000000AAAAAAAA0000000074
+:1044A000FFFF00000000000000000000000000000E
+:1044B00000000000AAAAAAAA00000000FFFF000056
+:1044C0000000000000000000510400000000000097
+:1044D00000001A0000000000FF000000B82A0020C1
+:1044E000D823002000000000884100083F000000A1
+:1044F00050040000934100083F00000000960000B7
+:104500000000080096000000000800000400000001
+:104510002043000800000000000000000000000030
+:0C4520000000000000000000000000008F
+:00000001FF
diff --git a/Tools/bootloaders/MatekL431-Proximity_bl.bin b/Tools/bootloaders/MatekL431-Proximity_bl.bin
new file mode 100755
index 00000000000000..f581b6d040c06e
Binary files /dev/null and b/Tools/bootloaders/MatekL431-Proximity_bl.bin differ
diff --git a/Tools/bootloaders/MatekL431-RC_bl.bin b/Tools/bootloaders/MatekL431-RC_bl.bin
new file mode 100755
index 00000000000000..ae02106c253586
Binary files /dev/null and b/Tools/bootloaders/MatekL431-RC_bl.bin differ
diff --git a/Tools/bootloaders/MatekL431-bdshot_bl.bin b/Tools/bootloaders/MatekL431-bdshot_bl.bin
new file mode 100755
index 00000000000000..27884c06d95501
Binary files /dev/null and b/Tools/bootloaders/MatekL431-bdshot_bl.bin differ
diff --git a/Tools/bootloaders/MazzyStarDrone_bl.bin b/Tools/bootloaders/MazzyStarDrone_bl.bin
new file mode 100755
index 00000000000000..921855185a4096
Binary files /dev/null and b/Tools/bootloaders/MazzyStarDrone_bl.bin differ
diff --git a/Tools/bootloaders/PH4-mini-bdshot_bl.bin b/Tools/bootloaders/PH4-mini-bdshot_bl.bin
new file mode 100755
index 00000000000000..021118dba0738e
Binary files /dev/null and b/Tools/bootloaders/PH4-mini-bdshot_bl.bin differ
diff --git a/Tools/bootloaders/PixFlamingo_bl.bin b/Tools/bootloaders/PixFlamingo_bl.bin
new file mode 100755
index 00000000000000..a367bc20a2e8f8
Binary files /dev/null and b/Tools/bootloaders/PixFlamingo_bl.bin differ
diff --git a/Tools/bootloaders/PixSurveyA1_bl.bin b/Tools/bootloaders/PixSurveyA1_bl.bin
new file mode 100755
index 00000000000000..b788a106056f7e
Binary files /dev/null and b/Tools/bootloaders/PixSurveyA1_bl.bin differ
diff --git a/Tools/bootloaders/Pixhawk1-bdshot_bl.bin b/Tools/bootloaders/Pixhawk1-bdshot_bl.bin
new file mode 100755
index 00000000000000..8486aa6b1b89a3
Binary files /dev/null and b/Tools/bootloaders/Pixhawk1-bdshot_bl.bin differ
diff --git a/Tools/bootloaders/Pixhawk6X-bdshot_bl.bin b/Tools/bootloaders/Pixhawk6X-bdshot_bl.bin
new file mode 100755
index 00000000000000..aec73925bb513c
Binary files /dev/null and b/Tools/bootloaders/Pixhawk6X-bdshot_bl.bin differ
diff --git a/Tools/bootloaders/SDMODELH7V1_bl.bin b/Tools/bootloaders/SDMODELH7V1_bl.bin
new file mode 100755
index 00000000000000..06c1a5c7af7c65
Binary files /dev/null and b/Tools/bootloaders/SDMODELH7V1_bl.bin differ
diff --git a/Tools/bootloaders/SDMODELH7V1_bl.elf b/Tools/bootloaders/SDMODELH7V1_bl.elf
new file mode 100755
index 00000000000000..4de918a932ca0c
Binary files /dev/null and b/Tools/bootloaders/SDMODELH7V1_bl.elf differ
diff --git a/Tools/bootloaders/SDMODELH7V1_bl.hex b/Tools/bootloaders/SDMODELH7V1_bl.hex
new file mode 100644
index 00000000000000..bb0fa43dc2b3eb
--- /dev/null
+++ b/Tools/bootloaders/SDMODELH7V1_bl.hex
@@ -0,0 +1,1007 @@
+:020000040800F2
+:1000000000060020E1020008E3020008E302000805
+:10001000E3020008E3020008E3020008E30200082C
+:10002000E3020008E3020008E3020008ED340008E0
+:10003000E3020008E3020008E3020008E30200080C
+:10004000E3020008E3020008E3020008E3020008FC
+:10005000E3020008E3020008D5380008013900086F
+:100060002D3900085939000885390008E3020008D5
+:10007000E3020008E3020008E3020008E3020008CC
+:10008000E3020008E3020008E3020008E3020008BC
+:10009000E3020008E3020008E3020008B1390008A7
+:1000A000E3020008E3020008E3020008E30200089C
+:1000B000E3020008E3020008E3020008E30200088C
+:1000C000E3020008E3020008E3020008E30200087C
+:1000D000E3020008E3020008E3020008E30200086C
+:1000E000153A0008E3020008E3020008E3020008F2
+:1000F000E3020008E3020008E3020008E30200084C
+:10010000E3020008E3020008893A0008E30200085D
+:10011000E3020008E3020008E3020008E30200082B
+:10012000E3020008E3020008E3020008E30200081B
+:10013000E3020008E3020008E3020008E30200080B
+:10014000E3020008E3020008E3020008E3020008FB
+:10015000E3020008E3020008E3020008E3020008EB
+:10016000E3020008E3020008E3020008E3020008DB
+:10017000E30200086D2E0008E3020008E302000815
+:10018000E3020008E3020008E3020008E3020008BB
+:10019000E3020008E3020008E3020008E3020008AB
+:1001A000E3020008E3020008E3020008E30200089B
+:1001B000E3020008E3020008E3020008E30200088B
+:1001C000E3020008E3020008E3020008E30200087B
+:1001D000E3020008592E0008E3020008E3020008C9
+:1001E000E3020008E3020008E3020008E30200085B
+:1001F000E3020008E3020008E3020008E30200084B
+:10020000E3020008E3020008E3020008E30200083A
+:10021000E3020008E3020008E3020008E30200082A
+:10022000E3020008E3020008E3020008E30200081A
+:10023000E3020008E3020008E3020008E30200080A
+:10024000E3020008E3020008E3020008E3020008FA
+:10025000E3020008E3020008E3020008E3020008EA
+:10026000E3020008E3020008E3020008E3020008DA
+:10027000E3020008E3020008E3020008E3020008CA
+:10028000E3020008E3020008E3020008E3020008BA
+:10029000E3020008E3020008E3020008E3020008AA
+:1002A000E3020008E3020008E3020008E30200089A
+:1002B000E3020008E3020008E3020008E30200088A
+:1002C000E3020008E3020008E3020008E30200087A
+:1002D000E3020008E3020008E3020008E30200086A
+:1002E00002E000F000F8FEE772B6374880F30888B5
+:1002F000364880F3098836483649086040F20000E5
+:10030000CCF200004EF63471CEF200010860BFF36B
+:100310004F8FBFF36F8F40F20000C0F2F0004EF637
+:100320008851CEF200010860BFF34F8FBFF36F8F8B
+:100330004FF00000E1EE100A4EF63C71CEF20001E3
+:100340000860062080F31488BFF36F8F01F0FAFF76
+:1003500003F01EF84FF055301F491B4A91423CBF35
+:1003600041F8040BFAE71D49184A91423CBF41F895
+:10037000040BFAE71A491B4A1B4B9A423EBF51F83D
+:10038000040B42F8040BF8E700201849184A914280
+:100390003CBF41F8040BFAE702F012F803F07CF8D6
+:1003A000144C154DAC4203DA54F8041B8847F9E7A6
+:1003B00000F042F8114C124DAC4203DA54F8041B21
+:1003C0008847F9E701F0FABF00060020002200206C
+:1003D0000000000808ED00E00000002000060020FA
+:1003E000683E0008002200205C22002060220020DD
+:1003F00034430020E0020008E0020008E0020008A8
+:10040000E00200082DE9F04F2DED108AC1F80CD064
+:10041000D0F80CD0BDEC108ABDE8F08F002383F338
+:1004200011882846A047002001F0FEFAFEE701F0FF
+:1004300067FA00DFFEE7000038B501F043FF05462C
+:1004400001F076FF0446D0B90F4B9D4219D001331D
+:100450009D4241F2883512BF044600250124002048
+:1004600001F03AFF0CB100F077F800F053FD00F016
+:1004700005FC284600F010F900F06EF8F9E70025B9
+:10048000EDE70546EBE700BF010007B008B500F057
+:10049000C7FBA0F120035842584108BD07B541F2FF
+:1004A0001203022101A8ADF8043000F0D7FB03B01D
+:1004B0005DF804FB38B5302383F3118817480368CF
+:1004C0000BB101F07DFB0023154A4FF47A711348FC
+:1004D00001F06CFB002383F31188124C236813B1E5
+:1004E0002368013B2360636813B16368013B636069
+:1004F0000D4D2B7833B963687BB9022000F084FC82
+:10050000322363602B78032B07D163682BB9022059
+:1005100000F07AFC4FF47A73636038BD60220020EB
+:10052000B50400088023002078220020084B1870B2
+:1005300003280CD8DFE800F008050208022000F0CC
+:1005400059BC022000F04EBC024B00225A6070479A
+:100550007822002080230020F8B5494B494A1C46E8
+:100560001968013100F08A8004339342F8D162683F
+:10057000454B9A4240F28280444B9B6803F10063F2
+:1005800003F500339A4279D2002000F09DFB02204F
+:10059000FFF7CCFF3E4B0021D3F8E820C3F8E8106A
+:1005A000D3F81021C3F81011D3F81021D3F8EC20A0
+:1005B000C3F8EC10D3F81421C3F81411D3F81421A4
+:1005C000D3F8F020C3F8F010D3F81821C3F81811AD
+:1005D000D3F81821D3F8802042F00072C3F88020AD
+:1005E000D3F8802022F00072C3F88020D3F8803046
+:1005F00072B64FF0E023C3F8084DD4E90004BFF30E
+:100600004F8FBFF36F8F234AC2F88410BFF34F8F11
+:10061000536923F480335361BFF34F8FD2F8803096
+:1006200043F6E076C3F3C905C3F34E335B0103EA37
+:10063000060C29464CEA81770139C2F87472F9D266
+:10064000203B13F1200FF2D1BFF34F8FBFF36F8F19
+:10065000BFF34F8FBFF36F8F536923F400335361A0
+:100660000023C2F85032BFF34F8FBFF36F8F302398
+:1006700083F31188854680F308882047F8BD00BFC2
+:100680000000020820000208FFFF010800220020ED
+:100690000044025800ED00E02DE9F04F93B0B44B58
+:1006A0002022FF2100900AA89D6800F0DDFBB14ADE
+:1006B0001378A3B90121B04811700360302383F38C
+:1006C000118803680BB101F07BFA0023AB4A4FF4A9
+:1006D0007A71A94801F06AFA002383F31188009B1C
+:1006E00013B1A74B009A1A60A64A1378032B03D0C4
+:1006F00000231370A24A53604FF0000A009CD346B7
+:100700005646D146012000F075FB24B19C4B1B6876
+:10071000002B00F02682002000F082FA0390039B59
+:10072000002BF2DB012000F05DFB039B213B1F2B24
+:10073000E8D801A252F823F0B9070008E107000841
+:1007400075080008050700080507000805070008E8
+:1007500007090008D70A0008F1090008530A000831
+:100760007B0A0008A10A000805070008B30A000870
+:1007700005070008250B00085908000805070008B0
+:10078000690B0008C507000859080008050700089C
+:10079000530A0008050700080507000805070008B8
+:1007A00005070008050700080507000805070008F9
+:1007B00005070008750800080220FFF767FE0028FB
+:1007C00040F0F981009B022105A8BAF1000F08BF93
+:1007D0001C4641F21233ADF8143000F03FFA91E7B5
+:1007E0004FF47A7000F01CFA071EEBDB0220FFF7D3
+:1007F0004DFE0028E6D0013F052F00F2DE81DFE844
+:1008000007F0030A0D1013360523042105A80593EC
+:1008100000F024FA17E004215548F9E704215A486A
+:10082000F6E704215948F3E74FF01C08404608F169
+:10083000040800F04BFA0421059005A800F00EFA18
+:10084000B8F12C0FF2D101204FF0000900FA07F7A0
+:1008500047EA0B0B5FFA8BFB00F052FB26B10BF063
+:100860000B030B2B08BF0024FFF718FE4AE70421F7
+:100870004748CDE7002EA5D00BF00B030B2BA1D1E1
+:100880000220FFF703FE074600289BD00120002628
+:1008900000F01AFA0220FFF749FE5FFA86F8404698
+:1008A00000F022FA0446B0B1039940460136A1F1A6
+:1008B00040025142514100F027FA0028EDD1BA46DA
+:1008C000044641F21213022105A83E46ADF8143049
+:1008D00000F0C4F916E725460120FFF727FE244B58
+:1008E0009B68AB4207D9284600F0F0F9013040F090
+:1008F00067810435F3E70025224BBA463E461D705A
+:100900001F4B5D60A8E7002E3FF45CAF0BF00B03BC
+:100910000B2B7FF457AF0220FFF708FE322000F0C8
+:100920007FF9B0F10008FFF64DAF18F003077FF430
+:1009300049AF0F4A08EB0503926893423FF642AF76
+:10094000B8F5807F3FF73EAF124BB845019323DDEA
+:100950004FF47A7000F064F90390039A002AFFF6CE
+:1009600031AF039A0137019B03F8012BEDE700BF7C
+:10097000002200207C23002060220020B504000813
+:10098000802300207822002004220020082200205A
+:100990000C2200207C220020C820FFF777FD0746AC
+:1009A00000283FF40FAF1F2D11D8C5F120020AAB6C
+:1009B00025F0030084494245184428BF424601926D
+:1009C00000F02CFA019AFF217F4800F04DFA4FEA1F
+:1009D000A803C8F387027C492846019300F04CFA2B
+:1009E000064600283FF46DAF019B05EB830533E716
+:1009F0000220FFF74BFD00283FF4E4AE00F0A2F91F
+:100A000000283FF4DFAE0027B846704B9B68BB421E
+:100A100018D91F2F11D80A9B01330ED027F00303DA
+:100A200012AA134453F8203C05934046042205A91A
+:100A3000043700F09BFA8046E7E7384600F046F9B5
+:100A40000590F2E7CDF81480042105A800F006F91E
+:100A500002E70023642104A8049300F0F5F80028BD
+:100A60007FF4B0AE0220FFF711FD00283FF4AAAEDC
+:100A7000049800F05DF90590E6E70023642104A8DE
+:100A8000049300F0E1F800287FF49CAE0220FFF709
+:100A9000FDFC00283FF496AE049800F04BF9EAE71D
+:100AA0000220FFF7F3FC00283FF48CAE00F05AF967
+:100AB000E1E70220FFF7EAFC00283FF483AE05A936
+:100AC000142000F055F907460421049004A800F012
+:100AD000C5F83946B9E7322000F0A2F8071EFFF644
+:100AE00071AEBB077FF46EAE384A07EB090392681C
+:100AF00093423FF667AE0220FFF7C8FC00283FF4A0
+:100B000061AE27F003074F44B9453FF4A5AE484610
+:100B100009F1040900F0DAF80421059005A800F0B5
+:100B20009DF8F1E74FF47A70FFF7B0FC00283FF42E
+:100B300049AE00F007F9002844D00A9B01330BD0DE
+:100B400008220AA9002000F097F900283AD02022B4
+:100B5000FF210AA800F088F9FFF7A0FC1C4800F06C
+:100B600069FF13B0BDE8F08F002E3FF42BAE0BF001
+:100B70000B030B2B7FF426AE0023642105A80593FD
+:100B800000F062F8074600287FF41CAE0220FFF751
+:100B90007DFC804600283FF415AEFFF77FFC41F254
+:100BA000883000F047FF059800F0DEF946463C46E5
+:100BB00000F0A6F9A6E506464EE64FF0000901E66C
+:100BC000BA467EE637467CE67C22002000220020E2
+:100BD000A08601000F4B70B51B780C460133DBB2C9
+:100BE000012B11D80C4D4FF47A732968A2FB033204
+:100BF00022460E6A01462846B047844204D1074B7C
+:100C0000002201201A7070BD4FF4FA7000F012FF3C
+:100C10000020F8E71022002028260020B42300201E
+:100C2000002307B5024601210DF107008DF80730BA
+:100C3000FFF7D0FF20B19DF8070003B05DF804FB7B
+:100C40004FF0FF30F9E700000A46042108B5FFF72E
+:100C5000C1FF80F00100C0B2404208BD30B4054C75
+:100C60000A46014623682046DD69034BAC4630BC8A
+:100C7000604700BF28260020A086010070B5104CF8
+:100C80000025104E01F0F6F9208030682388834259
+:100C90000CD800252088013801F0E8F923880544A4
+:100CA000013BB5F5802F2380F4D370BD01F0DEF950
+:100CB000336805440133B5F5003F3360E5D3E8E719
+:100CC000B62300208823002001F0B2BA00F10060B2
+:100CD00000F500300068704700F10060920000F5F8
+:100CE000003001F029BA0000054B1A68054B1B883B
+:100CF0009B1A834202D9104401F0B8B90020704712
+:100D000088230020B623002038B50446074D29B1BA
+:100D100028682044BDE8384001F0C0B92868204464
+:100D200001F0AAF90028F3D038BD00BF88230020C5
+:100D30000020704700F1FF5000F58F10D0F8000838
+:100D400070470000064991F8243033B1002308228F
+:100D5000086A81F82430FFF7BFBF0120704700BF49
+:100D60008C230020014B1868704700BF0010005C06
+:100D7000194B01380322084470B51D68174BC5F3A1
+:100D80000B042D0C1E88A6420BD15C680A46013C60
+:100D9000824213460FD214F9016F4EB102F8016B73
+:100DA000F6E7013A03F10803ECD181420B4602D287
+:100DB0002C2203F8012B0424094A1688AE4204D1E0
+:100DC000984284BF967803F8016B013C02F104025B
+:100DD000F3D1581A70BD00BF0010005C142200202F
+:100DE000803B0008022802D1014B04229A6170471F
+:100DF00000080258022803D1024B4FF480229A6166
+:100E0000704700BF00080258022804D1024A536903
+:100E100083F004035361704700080258002310B5A3
+:100E2000934203D0CC5CC4540133F9E710BD0000F9
+:100E3000013810B510F9013F3BB191F900409C42D7
+:100E400003D11AB10131013AF4E71AB191F9002046
+:100E5000981A10BD1046FCE703460246D01A12F954
+:100E6000011B0029FAD1704702440346934202D085
+:100E700003F8011BFAE770472DE9F8431F4D1446AC
+:100E80000746884695F8242052BBDFF870909CB343
+:100E900095F824302BB92022FF2148462F62FFF716
+:100EA000E3FF95F824004146C0F1080205EB8000FD
+:100EB000A24228BF2246D6B29200FFF7AFFF95F8B4
+:100EC0002430A41B17441E449044E4B2F6B2082E0A
+:100ED00085F82460DBD1FFF735FF0028D7D108E083
+:100EE0002B6A03EB82038342CFD0FFF72BFF00284E
+:100EF000CBD10020BDE8F8830120FBE78C23002044
+:100F0000024B1A78024B1A70704700BFB4230020BE
+:100F10001022002010B5104C104800F0B9F82146FE
+:100F20000E4800F0E1F824680D48D4F89020D2F87B
+:100F3000043843F00203C2F8043800F07BFD09498D
+:100F4000204600F0DFF9D4F89020D2F8043823F0DE
+:100F50000203C2F8043810BD3C3C000828260020DB
+:100F600040420F00443C00087047000030B50A447E
+:100F7000084D91420DD011F8013B5840082340F331
+:100F80000004013B2C4013F0FF0384EA5000F6D12B
+:100F9000EFE730BD2083B8ED02684368114301607C
+:100FA00003B118477047000013B5406B00F580543B
+:100FB000D4F8A4381A681178042914D1017C0229C4
+:100FC00011D11979012312898B4013420BD101A948
+:100FD0004C3002F093F8D4F8A4480246019B2179E2
+:100FE000206800F0DFF902B010BD0000143002F0FC
+:100FF00015B800004FF0FF33143002F00FB80000B6
+:101000004C3002F0E7B800004FF0FF334C3002F0F4
+:10101000E1B80000143001F0E3BF00004FF0FF31F1
+:10102000143001F0DDBF00004C3002F0B3B8000016
+:101030004FF0FF324C3002F0ADB800000020704796
+:1010400010B500F58054D4F8A4381A681178042932
+:1010500017D1017C022914D15979012352898B407F
+:1010600013420ED1143001F075FF024648B1D4F896
+:10107000A4484FF4407361792068BDE8104000F047
+:101080007FB910BD406BFFF7DBBF00007047000069
+:101090007FB5124B01250426044603600023057426
+:1010A00000F1840243602946C0E902330C4B0290F0
+:1010B000143001934FF44073009601F027FF094B61
+:1010C00004F69442294604F14C000294CDE90063F1
+:1010D0004FF4407301F0EEFF04B070BD903B000888
+:1010E00085100008A90F00080A68302383F31188CF
+:1010F0000B790B3342F823004B79133342F823006A
+:101100008B7913B10B3342F8230000F58053C3F8F9
+:10111000A41802230374002080F311887047000094
+:1011200038B5037F044613B190F85430ABB90125AC
+:10113000201D0221FFF730FF04F114006FF00101C0
+:10114000257700F09FFC04F14C0084F854506FF0B8
+:101150000101BDE8384000F095BC38BD10B5012153
+:1011600004460430FFF718FF0023237784F8543037
+:1011700010BD000038B504460025143001F0DEFE35
+:1011800004F14C00257701F0ADFF201D84F8545088
+:101190000121FFF701FF2046BDE83840FFF750BFAF
+:1011A00090F8803003F06003202B06D190F8812066
+:1011B0000023212A03D81F2A06D800207047222A9C
+:1011C000FBD1C0E91D3303E0034A4267072282676F
+:1011D000C3670120704700BF2C22002037B500F5FF
+:1011E0008055D5F8A4381A68117804291AD1017CE1
+:1011F000022917D11979012312898B40134211D189
+:1012000000F14C04204602F02DF858B101A9204607
+:1012100001F074FFD5F8A4480246019B21792068AB
+:1012200000F0C0F803B030BD01F10B03F0B550F889
+:10123000236085B004460D46FEB1302383F3118848
+:1012400004EB8507301D0821FFF7A6FEFB6806F1B9
+:101250004C005B691B681BB1019001F05DFF0198B8
+:1012600003A901F04BFF024648B1039B29462046E3
+:1012700000F098F8002383F3118805B0F0BDFB68F7
+:101280005A691268002AF5D01B8A013B1340F1D13C
+:1012900004F18002EAE70000133138B550F821402C
+:1012A000ECB1302383F3118804F58053D3F8A428DC
+:1012B0001368527903EB8203DB689B695D6845B173
+:1012C00004216018FFF768FE294604F1140001F0BC
+:1012D0004BFE2046FFF7B4FE002383F3118838BD90
+:1012E0007047000001F002B901234022002110B52F
+:1012F000044600F8303BFFF7B7FD0023C4E9013393
+:1013000010BD000010B53023044683F31188242259
+:10131000416000210C30FFF7A7FD204601F008F9DD
+:1013200002230020237080F3118810BD70B500EBFC
+:101330008103054650690E461446DA6018B1102242
+:101340000021FFF791FDA06918B110220021FFF7DD
+:101350008BFD31462846BDE8704001F0EFB9000032
+:1013600083682022002103F0011310B50446836036
+:101370001030FFF779FD2046BDE8104001F06ABA51
+:10138000F0B4012500EB810447898D40E4683D43BA
+:10139000A469458123600023A2606360F0BC01F072
+:1013A00087BA0000F0B4012500EB810407898D4065
+:1013B000E4683D436469058123600023A2606360A3
+:1013C000F0BC01F0FDBA000070B502230025044610
+:1013D000242203702946C0F888500C3040F8045C81
+:1013E000FFF742FD204684F8705001F03BF9636836
+:1013F0001B6823B129462046BDE87040184770BDE0
+:101400000378052B10B504460AD080F88C300523EC
+:10141000037043681B680BB1042198470023A36045
+:1014200010BD00000178052906D190F88C20436892
+:1014300002701B6803B118477047000070B590F840
+:101440007030044613B1002380F8703004F180023C
+:10145000204601F023FA63689B68B3B994F88030A2
+:1014600013F0600535D00021204601F015FD002164
+:10147000204601F005FD63681B6813B10621204674
+:101480009847062384F8703070BD2046984700289E
+:10149000E4D0B4F88630A26F9A4288BFA36794F96B
+:1014A0008030A56F002B4FF0300380F20381002DB8
+:1014B00000F0F280092284F8702083F31188002163
+:1014C0002046D4E91D23FFF76DFF002383F3118825
+:1014D000DAE794F8812003F07F0343EA022340F225
+:1014E0000232934200F0C58021D8B3F5807F48D006
+:1014F0000DD8012B3FD0022B00F09380002BB2D1EE
+:1015000004F1880262670222A267E367C1E7B3F5CC
+:10151000817F00F09B80B3F5407FA4D194F88230A6
+:10152000012BA0D1B4F8883043F0020332E0B3F5C8
+:10153000006F4DD017D8B3F5A06F31D0A3F5C063BD
+:10154000012B90D86368204694F882205E6894F856
+:101550008310B4F88430B047002884D043686367B0
+:101560000368A3671AE0B3F5106F36D040F6024265
+:1015700093427FF478AF5C4B63670223A367002339
+:10158000C3E794F88230012B7FF46DAFB4F8883054
+:1015900023F00203A4F88830C4E91D55E56778E715
+:1015A000B4F88030B3F5A06F0ED194F882302046A5
+:1015B00084F88A3001F0B4F863681B6813B1012124
+:1015C00020469847032323700023C4E91D339CE77A
+:1015D00004F18B0363670123C3E72378042B10D145
+:1015E000302383F311882046FFF7BAFE85F3118874
+:1015F0000321636884F88B5021701B680BB120466F
+:10160000984794F88230002BDED084F88B30042386
+:10161000237063681B68002BD6D0022120469847B0
+:10162000D2E794F8843020461D0603F00F010AD556
+:1016300001F026F9012804D002287FF414AF2B4BC7
+:101640009AE72B4B98E701F00DF9F3E794F8823015
+:10165000002B7FF408AF94F8843013F00F01B3D05F
+:101660001A06204602D501F02FFCADE701F020FC60
+:10167000AAE794F88230002B7FF4F5AE94F884301A
+:1016800013F00F01A0D01B06204602D501F004FC88
+:101690009AE701F0F5FB97E7142284F8702083F3B2
+:1016A00011882B462A4629462046FFF769FE85F316
+:1016B0001188E9E65DB1152284F8702083F3118862
+:1016C00000212046D4E91D23FFF75AFEFDE60B2238
+:1016D00084F8702083F311882B462A462946204639
+:1016E000FFF760FEE3E700BFC03B0008B83B00081F
+:1016F000BC3B000838B590F870300446002B3ED053
+:10170000063BDAB20F2A34D80F2B32D8DFE803F0C9
+:1017100037313108223231313131313131313737DE
+:10172000856FB0F886309D4214D2C3681B8AB5FB22
+:10173000F3F203FB12556DB9302383F311882B4666
+:101740002A462946FFF72EFE85F311880A2384F8DE
+:1017500070300EE0142384F87030302383F3118846
+:10176000002320461A461946FFF70AFE002383F39A
+:10177000118838BDC36F03B198470023E7E7002104
+:10178000204601F089FB0021204601F079FB6368C7
+:101790001B6813B10621204698470623D7E70000AF
+:1017A00010B590F870300446142B29D017D8062BAA
+:1017B00005D001D81BB110BD093B022BFBD800217D
+:1017C000204601F069FB0021204601F059FB6368C7
+:1017D0001B6813B1062120469847062319E0152BF4
+:1017E000E9D10B2380F87030302383F31188002374
+:1017F0001A461946FFF7D6FD002383F31188DAE76E
+:10180000C3689B695B68002BD5D1C36F03B1984750
+:10181000002384F87030CEE70023826803750369E3
+:101820001B6899689142FBD25A680360426010605D
+:101830005860704700238268037503691B689968C4
+:101840009142FBD85A68036042601060586070474C
+:1018500008B50846302383F311880B7D032B05D090
+:10186000042B0DD02BB983F3118808BD8B6900229E
+:101870001A604FF0FF338361FFF7CEFF0023F2E7DA
+:10188000D1E9003213605A60F3E70000FFF7C4BFEC
+:10189000054BD96808751868026853601A60012200
+:1018A000D8600275FEF7AEBDB82300200C4B30B5F2
+:1018B000DD684B1C87B004460FD02B46094A6846AA
+:1018C00000F074F92046FFF7E3FF009B13B1684670
+:1018D00000F076F9A86907B030BDFFF7D9FFF9E746
+:1018E000B823002051180008044B1A68DB68906880
+:1018F0009B68984294BF002001207047B8230020C5
+:10190000084B10B51C68D868226853601A60012221
+:10191000DC602275FFF78EFF01462046BDE81040CF
+:10192000FEF770BDB8230020044B1A68DB6892688C
+:101930009B689A4201D9FFF7E3BF7047B8230020A4
+:1019400038B5074C01230025064907482370656018
+:1019500001F0C6FC0223237085F3118838BD00BF57
+:1019600020260020C83B0008B823002000F05EB904
+:10197000EFF3118020B9EFF30583302282F3118851
+:101980007047000010B530B9EFF30584C4F30804C4
+:1019900014B180F3118810BDFFF7C6FF84F31188DE
+:1019A000F9E70000034A516853685B1A9842FBD874
+:1019B000704700BF001000E08B60022308610846FA
+:1019C0008B8270478368A3F1840243F8142C026968
+:1019D00043F8442C426943F8402C094A43F8242C2C
+:1019E000C268A3F1200043F8182C022203F80C2C43
+:1019F000002203F80B2C034A43F8102C704700BF59
+:101A00001D040008B823002008B5FFF7DBFFBDE880
+:101A10000840FFF73BBF0000024BDB6898610F20D6
+:101A2000FFF736BFB8230020302383F31188FFF778
+:101A3000F3BF000008B50146302383F31188082066
+:101A4000FFF734FF002383F3118808BD064BDB68E2
+:101A500039B1426818605A60136043600420FFF790
+:101A600025BF4FF0FF307047B8230020036898422D
+:101A700006D01A680260506018469961FFF706BFE9
+:101A80007047000038B504460D462068844200D1F6
+:101A900038BD036823605C608561FFF7F7FEF4E7FB
+:101AA000036810B59C68A2420CD85C688A600B6021
+:101AB0004C602160596099688A1A9A604FF0FF3330
+:101AC000836010BD121B1B68ECE700000A2938BFB9
+:101AD0000A2170B504460D460A26601901F0F8FB8C
+:101AE00001F0E0FB041BA54203D8751C04462E46FA
+:101AF000F3E70A2E04D90120BDE8704001F030BCA4
+:101B000070BD0000F8B5144B0D460A2A4FF00A07C5
+:101B1000D96103F11001826038BF0A22416019695E
+:101B20001446016048601861A81801F0C1FB01F07B
+:101B3000B9FB431B0646A34206D37C1C2819274643
+:101B4000354601F0C5FBF2E70A2F04D90120BDE8B4
+:101B5000F84001F005BCF8BDB8230020F8B50646F2
+:101B60000D4601F09FFB0F4A134653F8107F9F422A
+:101B700006D12A4601463046BDE8F840FFF7C2BF0D
+:101B8000D169BB68441A2C1928BF2C46A34202D93C
+:101B90002946FFF79BFF224631460348BDE8F8403F
+:101BA000FFF77EBFB8230020C8230020C0E903232D
+:101BB000002310B45DF8044B4361FFF7CFBF000072
+:101BC00010B5194C236998420DD08168D0E90032D4
+:101BD00013605A609A680A449A60002303604FF0C9
+:101BE000FF33A36110BD0268234643F8102F5360F2
+:101BF0000022026022699A4203D1BDE8104001F040
+:101C000061BB936881680B44936001F04BFB2269D0
+:101C1000E1699268441AA242E4D91144BDE8104037
+:101C2000091AFFF753BF00BFB82300202DE9F04782
+:101C3000DFF8BC8008F110072C4ED8F8105001F0E6
+:101C400031FBD8F81C40AA68031B9A423ED81444C2
+:101C50004FF00009D5E90032C8F81C4013605A6003
+:101C6000C5F80090D8F81030B34201D101F02AFB3A
+:101C700089F31188D5E9033128469847302383F347
+:101C800011886B69002BD8D001F00CFB6A69A0EBBE
+:101C9000040982464A450DD2022001F061FB002270
+:101CA000D8F81030B34208D151462846BDE8F04775
+:101CB000FFF728BF121A2244F2E712EB090929465E
+:101CC000384638BF4A46FFF7EBFEB5E7D8F8103084
+:101CD000B34208D01444C8F81C00211AA960BDE81A
+:101CE000F047FFF7F3BEBDE8F08700BFC823002030
+:101CF000B823002000207047FEE700007047000076
+:101D00004FF0FF307047000002290CD0032904D0A7
+:101D10000129074818BF00207047032A05D8054845
+:101D200000EBC2007047044870470020704700BFB6
+:101D3000A03C00083C220020543C000870B59AB03A
+:101D400005460846144601A900F0C2F801A8FFF7AD
+:101D500083F8431C0022C6B25B001046C5E900347C
+:101D600023700323023404F8013C01ABD1B20234E6
+:101D70008E4201D81AB070BD13F8011B013204F86D
+:101D8000010C04F8021CF1E708B5302383F3118835
+:101D90000348FFF723FA002383F3118808BD00BF2F
+:101DA0002826002090F8803003F01F02012A07D176
+:101DB00090F881200B2A03D10023C0E91D3315E0E0
+:101DC00003F06003202B08D1B0F884302BB990F8D1
+:101DD0008120212A03D81F2A04D8FFF7E1B9222A3B
+:101DE000EBD0FAE7034A426707228267C367012004
+:101DF000704700BF3322002007B5052917D8DFE858
+:101E000001F0191603191920302383F31188104AA1
+:101E100001210190FFF78AFA019802210D4AFFF78C
+:101E200085FA0D48FFF7A6F9002383F3118803B064
+:101E30005DF804FB302383F311880748FFF770F93E
+:101E4000F2E7302383F311880348FFF787F9EBE7C4
+:101E5000F43B0008183C00082826002038B50C4D3B
+:101E60000C4C2A460C4904F10800FFF767FF05F106
+:101E7000CA0204F110000949FFF760FF05F5CA72B4
+:101E800004F118000649BDE83840FFF757BF00BF0E
+:101E9000003F00203C220020D43B0008DE3B00082D
+:101EA000E93B000870B5044608460D46FEF7D4FF2E
+:101EB000C6B22046013403780BB9184670BD3246CD
+:101EC0002946FEF7B5FF0028F3D10120F6E7000010
+:101ED0002DE9F84F05460C46FEF7BEFF2D49C6B268
+:101EE0002846FFF7DFFF08B10436F6B22A49284634
+:101EF000FFF7D8FF08B11036F6B2632E0DD8DFF821
+:101F00009490DFF894A0DFF89C80DFF89CB0234F1A
+:101F10002E7846B92670BDE8F88F29462046BDE8E0
+:101F2000F84F01F00FBE252E30D107224946284632
+:101F3000FEF77EFF70B93B6807350B3444F80B3C65
+:101F40007B6844F8073C3B8924F8033CBB7A04F8DF
+:101F5000013CDDE7082251462846FEF769FFA8B993
+:101F6000A21C0F4B19780232090911F8081002F867
+:101F7000041C13F8011B01F00F015B4511F8081058
+:101F800002F8031CEED118340835C1E7013504F816
+:101F9000016BBDE7C03C0008E93B0008C83C0008F5
+:101FA00000E8F11FD43C00080CE8F11FBFF34F8F8D
+:101FB000044B1A695107FCD1D3F810215207F8D10C
+:101FC000704700BF0020005208B50D4B1B78ABB91D
+:101FD000FFF7ECFF0B4BDA68D10704D50A4A5A60C9
+:101FE00002F188325A60D3F80C21D20706D5064A8E
+:101FF000C3F8042102F18832C3F8042108BD00BFF0
+:102000005E410020002000522301674508B5114BB6
+:102010001B78F3B9104B1A69510703D5DA6842F0FF
+:102020004002DA60D3F81021520705D5D3F80C210D
+:1020300042F04002C3F80C21FFF7B8FF064BDA6804
+:1020400042F00102DA60D3F80C2142F00102C3F839
+:102050000C2108BD5E410020002000520F289ABFCD
+:1020600000F5806040040020704700004FF400300D
+:1020700070470000102070470F2808B50BD8FFF7F5
+:10208000EDFF00F500330268013204D104308342D1
+:10209000F9D1012008BD0020FCE700000F2870B531
+:1020A000054645D8FFF764FC224CFFF77FFF064644
+:1020B000FFF78AFF4FF0FF33072D6361C4F8143137
+:1020C00020D82361FFF772FF2B0243F02403E36063
+:1020D000E36843F08003E36023695A07FCD4284691
+:1020E000FFF764FF4FF40031FFF7B8FF00F002F98B
+:1020F0003046FFF78BFFFFF745FC2846BDE87040F0
+:10210000FFF7BABFC4F81031FFF750FFA5F108037D
+:102110001B0243F02403C4F80C31D4F80C3143F013
+:102120008003C4F80C31D4F810315B07FBD4D6E738
+:10213000002070BD002000522DE9F84F40EA020354
+:1021400005460C461746D80602D00020BDE8F88F99
+:1021500027F01F07DFF8D4B0FFF736FF2744BC4253
+:1021600003D10120FFF752FFF0E720222946204645
+:1021700001F0D8FC10B920352034F0E72B4605F1EA
+:1021800020021E68711CE0D104339A42F9D1FFF796
+:10219000EFFB05F17843234AB3F5801F224B28BF9C
+:1021A0009A4603F1040338BF9046A2F1080228BF03
+:1021B0009846A3F108033ABF9146DA469946FFF7DD
+:1021C000F5FEC8F80060A5EB040CD9F8002004F176
+:1021D0001C0142F00202C9F80020221FDAF8006058
+:1021E00016F00506FAD152F8043F8A424CF8023044
+:1021F000F4D1BFF34F8FFFF7D9FE4FF0FF32C8F88D
+:102200000020D9F8002022F00202C9F80020FFF7D0
+:10221000B9FB20222146284601F084FC0028AAD0E0
+:1022200030469FE714200052102100521020005227
+:1022300010B5084C237828B11BB9FFF7C5FE012360
+:10224000237010BD002BFCD02070BDE81040FFF7BC
+:10225000DDBE00BF5E4100200244074BD2B210B584
+:10226000904200D110BD441C00B253F8200041F848
+:10227000040BE0B2F4E700BF504000580E4B30B5FD
+:102280001C6F240405D41C6F1C671C6F44F40044AD
+:102290001C670A4C02442368D2B243F48073236063
+:1022A000074B904200D130BD441C51F8045B00B292
+:1022B00043F82050E0B2F4E70044025800480258C6
+:1022C0005040005807B5012201A90020FFF7C4FFC4
+:1022D000019803B05DF804FB13B50446FFF7F2FF65
+:1022E000A04205D0012201A900200194FFF7C6FFFA
+:1022F00002B010BD0144BFF34F8F064B884204D398
+:10230000BFF34F8FBFF36F8F7047C3F85C0220306D
+:10231000F4E700BF00ED00E0034B1A681AB9034A66
+:10232000D2F8D0241A607047604100200040025863
+:1023300008B5FFF7F1FF024B1868C0F3806008BDD5
+:102340006041002070B5BFF34F8FBFF36F8F1A4A03
+:102350000021C2F85012BFF34F8FBFF36F8F536944
+:1023600043F400335361BFF34F8FBFF36F8FC2F855
+:102370008410BFF34F8FD2F8803043F6E074C3F37C
+:10238000C900C3F34E335B0103EA0406014646EA83
+:1023900081750139C2F86052F9D2203B13F1200F48
+:1023A000F2D1BFF34F8F536943F480335361BFF3CE
+:1023B0004F8FBFF36F8F70BD00ED00E0FEE70000B0
+:1023C000214B2248224A70B5904237D3214BC11E7F
+:1023D000DA1C121A22F003028B4238BF00220021BD
+:1023E000FEF742FD1C4A0023C2F88430BFF34F8F32
+:1023F000D2F8803043F6E074C3F3C900C3F34E3320
+:102400005B0103EA0406014646EA81750139C2F818
+:102410006C52F9D2203B13F1200FF2D1BFF34F8F52
+:10242000BFF36F8FBFF34F8FBFF36F8F0023C2F8DF
+:102430005032BFF34F8FBFF36F8F70BD53F8041B43
+:1024400040F8041BC0E700BFC43E0008344300202E
+:10245000344300203443002000ED00E0074BD3F864
+:10246000D81021EA0001C3F8D810D3F8002122EADD
+:102470000002C3F80021D3F800317047004402582D
+:1024800070B5D0E9244300224FF0FF359E6804EB7D
+:1024900042135101D3F80009002805DAD3F80009E6
+:1024A00040F08040C3F80009D3F8000B002805DA9B
+:1024B000D3F8000B40F08040C3F8000B01326318E2
+:1024C0009642C3F80859C3F8085BE0D24FF00113F5
+:1024D000C4F81C3870BD0000890141F02001016181
+:1024E00003699B06FCD41220FFF75CBA10B50A4CB6
+:1024F0002046FEF7F9FE094BC4F89030084BC4F8AB
+:102500009430084C2046FEF7EFFE074BC4F890309D
+:10251000064BC4F8943010BD644100200000084010
+:102520000C3D00080042002000000440183D000857
+:1025300070B503780546012B5CD1434BD0F8904031
+:10254000984258D1414B0E216520D3F8D82042F053
+:102550000062C3F8D820D3F8002142F00062C3F82B
+:102560000021D3F80021D3F8802042F00062C3F8A4
+:102570008020D3F8802022F00062C3F88020D3F8B6
+:10258000803000F0ADFC324BE360324BC4F80038D1
+:102590000023D5F89060C4F8003EC02323604FF4B8
+:1025A0000413A3633369002BFCDA01230C2033618D
+:1025B000FFF7F8F93369DB07FCD41220FFF7F2F9D3
+:1025C0003369002BFCDA00262846A660FFF758FF87
+:1025D0006B68C4F81068DB68C4F81468C4F81C6839
+:1025E00083BB1D4BA3614FF0FF336361A36843F0CE
+:1025F0000103A36070BD194B9842C9D1134B4FF032
+:102600008060D3F8D82042F00072C3F8D820D3F805
+:10261000002142F00072C3F80021D3F80021D3F862
+:10262000802042F00072C3F88020D3F8802022F08E
+:102630000072C3F88020D3F88030FFF70FFF0E211F
+:102640004D209EE7064BCDE7644100200044025830
+:102650004014004003002002003C30C00042002033
+:10266000083C30C0F8B5D0F89040054600214FF046
+:1026700000662046FFF730FFD5F8941000234FF096
+:1026800001128F684FF0FF30C4F83438C4F81C28AA
+:1026900004EB431201339F42C2F80069C2F8006B99
+:1026A000C2F80809C2F8080BF2D20B68D5F89020DE
+:1026B000C5F89830636210231361166916F010068E
+:1026C000FBD11220FFF76EF9D4F8003823F4FE6333
+:1026D000C4F80038A36943F4402343F01003A36116
+:1026E0000923C4F81038C4F814380B4BEB604FF0D2
+:1026F000C043C4F8103B094BC4F8003BC4F8106950
+:10270000C4F80039D5F8983003F1100243F480136F
+:10271000C5F89820A362F8BDE83C0008408000108E
+:10272000D0F8902090F88A10D2F8003823F4FE6395
+:1027300043EA0113C2F80038704700002DE9F8435E
+:1027400000EB8103D0F890500C468046DA680FFA0F
+:1027500081F94801166806F00306731E022B05EB8B
+:1027600041134FF0000194BFB604384EC3F8101B5C
+:102770004FF0010104F1100398BF06F1805601FAF1
+:1027800003F3916998BF06F5004600293AD0578AAD
+:1027900004F15801374349016F50D5F81C180B4319
+:1027A0000021C5F81C382B180127C3F81019A740C1
+:1027B0005369611E9BB3138A928B9B08012A88BFC1
+:1027C0005343D8F89820981842EA034301F1400295
+:1027D0002146C8F89800284605EB82025360FFF7AF
+:1027E0007BFE08EB8900C3681B8A43EA84534834A4
+:1027F0001E4364012E51D5F81C381F43C5F81C78C0
+:10280000BDE8F88305EB4917D7F8001B21F4004118
+:10281000C7F8001BD5F81C1821EA0303C0E704F130
+:102820003F030B4A2846214605EB83035A60FFF716
+:1028300053FE05EB4910D0F8003923F40043C0F8EB
+:102840000039D5F81C3823EA0707D7E700800010C5
+:1028500000040002D0F894201268C0F89820FFF716
+:102860000FBE00005831D0F8903049015B5813F486
+:10287000004004D013F4001F0CBF02200120704759
+:102880004831D0F8903049015B5813F4004004D02F
+:1028900013F4001F0CBF02200120704700EB8101E0
+:1028A000CB68196A0B6813604B685360704700006F
+:1028B00000EB810330B5DD68AA691368D36019B9EC
+:1028C000402B84BF402313606B8A1468D0F890209B
+:1028D0001C4402EB4110013C09B2B4FBF3F4634326
+:1028E000033323F0030343EAC44343F0C043C0F877
+:1028F000103B2B6803F00303012B0ED1D2F80838EC
+:1029000002EB411013F4807FD0F8003B14BF43F07A
+:10291000805343F00053C0F8003B02EB4112D2F861
+:10292000003B43F00443C2F8003B30BD2DE9F041C9
+:10293000D0F8906005460C4606EB4113D3F8087BAF
+:102940003A07C3F8087B08D5D6F814381B0704D516
+:1029500000EB8103DB685B689847FA071FD5D6F860
+:102960001438DB071BD505EB8403D968CCB98B6918
+:10297000488A5A68B2FBF0F600FB16228AB918683A
+:10298000DA6890420DD2121AC3E90024302383F38F
+:10299000118821462846FFF78BFF84F31188BDE894
+:1029A000F081012303FA04F26B8923EA02036B81AD
+:1029B000CB68002BF3D021462846BDE8F0411847EC
+:1029C00000EB81034A0170B5DD68D0F890306C6986
+:1029D0002668E66056BB1A444FF40020C2F810097E
+:1029E0002A6802F00302012A0AB20ED1D3F80808BD
+:1029F00003EB421410F4807FD4F8000914BF40F0B8
+:102A0000805040F00050C4F8000903EB4212D2F8A5
+:102A1000000940F00440C2F800090122D3F834084C
+:102A200002FA01F10143C3F8341870BD19B9402E00
+:102A300084BF4020206020681A442E8A8419013CFB
+:102A4000B4FBF6F440EAC44040F00050C6E7000092
+:102A50002DE9F843D0F8906005460C464F0106EB8F
+:102A60004113D3F8088918F0010FC3F808891CD066
+:102A7000D6F81038DB0718D500EB8103D3F80CC06B
+:102A8000DCF81430D3F800E0DA68964530D2A2EBD7
+:102A90000E024FF000091A60C3F80490302383F34C
+:102AA0001188FFF78DFF89F3118818F0800F1DD072
+:102AB000D6F834380126A640334217D005EB8403FC
+:102AC0000134D5F89050D3F80CC0E4B22F44DCF8B0
+:102AD000142005EB0434D2F800E05168714514D39A
+:102AE000D5F8343823EA0606C5F83468BDE8F8831B
+:102AF000012303FA01F2038923EA02030381DCF8CC
+:102B00000830002BD1D09847CFE7AEEB0103BCF8DB
+:102B10001000834228BF0346D7F8180980B2B3EBF0
+:102B2000800FE3D89068A0F1040959F8048FC4F825
+:102B30000080A0EB09089844B8F1040FF5D81844B8
+:102B40000B4490605360C8E72DE9F84FD0F89050DF
+:102B500004466E69AB691E4016F480586E6103D05E
+:102B6000BDE8F84FFEF730BC002E12DAD5F8003E73
+:102B70009B0705D0D5F8003E23F00303C5F8003EBF
+:102B8000D5F80438204623F00103C5F80438FEF7D1
+:102B900049FC370505D52046FFF772FC2046FEF7B5
+:102BA0002FFCB0040CD5D5F8083813F0060FEB68ED
+:102BB00023F470530CBF43F4105343F4A053EB6061
+:102BC00031071BD56368DB681BB9AB6923F00803C9
+:102BD000AB612378052B0CD1D5F8003E9A0705D0C0
+:102BE000D5F8003E23F00303C5F8003E2046FEF76B
+:102BF00019FC6368DB680BB120469847F30200F1CB
+:102C0000BA80B70226D5D4F8909000274FF0010A79
+:102C100009EB4712D2F8003B03F44023B3F5802FB1
+:102C200011D1D2F8003B002B0DDA62890AFA07F3C2
+:102C300022EA0303638104EB8703DB68DB6813B1DB
+:102C40003946204698470137D4F89430FFB29B6844
+:102C50009F42DDD9F00619D5D4F89000026AC2F37C
+:102C60000A1702F00F0302F4F012B2F5802F00F001
+:102C7000CA80B2F5402F09D104EB8303002200F58E
+:102C80008050DB681B6A974240F0B0803003D5F873
+:102C9000185835D5E90303D500212046FFF746FE35
+:102CA000AA0303D501212046FFF740FE6B0303D59D
+:102CB00002212046FFF73AFE2F0303D503212046C9
+:102CC000FFF734FEE80203D504212046FFF72EFE6D
+:102CD000A90203D505212046FFF728FE6A0203D585
+:102CE00006212046FFF722FE2B0203D507212046AE
+:102CF000FFF71CFEEF0103D508212046FFF716FE63
+:102D0000700340F1A780E90703D500212046FFF7B3
+:102D10009FFEAA0703D501212046FFF799FE6B0706
+:102D200003D502212046FFF793FE2F0703D5032189
+:102D30002046FFF78DFEEE0603D504212046FFF75F
+:102D400087FEA80603D505212046FFF781FE690608
+:102D500003D506212046FFF77BFE2A0603D507216F
+:102D60002046FFF775FEEB0574D520460821BDE827
+:102D7000F84FFFF76DBED4F890904FF0000B4FF076
+:102D8000010AD4F894305FFA8BF79B689F423FF6B4
+:102D900038AF09EB4713D3F8002902F44022B2F50B
+:102DA000802F20D1D3F80029002A1CDAD3F800297B
+:102DB00042F09042C3F80029D3F80029002AFBDB37
+:102DC0003946D4F89000FFF787FB22890AFA07F307
+:102DD00022EA0303238104EB8703DB689B6813B1BA
+:102DE0003946204698470BF1010BCAE7910701D1FC
+:102DF000D0F80080072A02F101029CBF03F8018B82
+:102E00004FEA18283FE704EB830300F58050DA68A7
+:102E1000D2F818C0DCF80820DCE9001CA1EB0C0C8F
+:102E200000218F4208D1DB689B699A683A449A6016
+:102E30005A683A445A6029E711F0030F01D1D0F8DB
+:102E400000808C4501F1010184BF02F8018B4FEA3B
+:102E50001828E6E7BDE8F88F08B50348FFF774FEC9
+:102E6000BDE8084000F07ABB6441002008B5034883
+:102E7000FFF76AFEBDE8084000F070BB004200208A
+:102E8000D0F8903003EB4111D1F8003B43F400132C
+:102E9000C1F8003B70470000D0F8903003EB4111BF
+:102EA000D1F8003943F40013C1F80039704700002D
+:102EB000D0F8903003EB4111D1F8003B23F400131C
+:102EC000C1F8003B70470000D0F8903003EB41118F
+:102ED000D1F8003923F40013C1F80039704700001D
+:102EE000090100F16043012203F56143C9B283F88F
+:102EF000001300F01F039A4043099B0003F1604355
+:102F000003F56143C3F880211A60704730B504337C
+:102F1000039C0172002104FB0325C160C0E9065334
+:102F2000049B0363059BC0E90000C0E90422C0E9DB
+:102F30000842C0E90A11436330BD00000022416A23
+:102F4000C260C0E90411C0E90A226FF00101FEF776
+:102F500099BD0000D0E90432934201D1C2680AB998
+:102F6000181D704700207047036919600021C2686E
+:102F70000132C260C269134482699342036124BF73
+:102F8000436A0361FEF772BD38B504460D46E36837
+:102F90003BB162690020131D1268A3621344E3620F
+:102FA00007E0237A33B929462046FEF74FFD002873
+:102FB000EDDA38BD6FF00100FBE70000C368C269BD
+:102FC000013BC3604369134482699342436124BF58
+:102FD000436A436100238362036B03B11847704760
+:102FE00070B53023044683F31188866A3EB9FFF733
+:102FF000CBFF054618B186F31188284670BDA36A39
+:10300000E26A13F8015B9342A36202D32046FFF702
+:10301000D5FF002383F31188EFE700002DE9F84F77
+:1030200004460E46174698464FF0300989F311883A
+:103030000025AA46D4F828B0BBF1000F09D14146BB
+:103040002046FFF7A1FF20B18BF311882846BDE889
+:10305000F88FD4E90A12A7EB050B521A934528BF43
+:103060009346BBF1400F1BD9334601F1400251F8A2
+:10307000040B914243F8040BF9D1A36A4036403562
+:103080004033A362D4E90A239A4202D32046FFF7D1
+:1030900095FF8AF31188BD42D8D289F31188C9E718
+:1030A00030465A46FDF7BAFEA36A5E445D445B446F
+:1030B000A362E7E710B5029C0433017203FB04210D
+:1030C000C460C0E906130023C0E90A33039B03630D
+:1030D000049BC0E90000C0E90422C0E90842436340
+:1030E00010BD0000026A6FF00101C260426AC0E9CF
+:1030F00004220022C0E90A22FEF7C4BCD0E904235E
+:103100009A4201D1C26822B9184650F8043B0B60BC
+:10311000704700231846FAE7C3680021C2690133EB
+:10312000C3604369134482699342436124BF436A85
+:103130004361FEF79BBC000038B504460D46E368CA
+:103140003BB1236900201A1DA262E2691344E362C5
+:1031500007E0237A33B929462046FEF777FC00289A
+:10316000EDDA38BD6FF00100FBE70000036919607C
+:10317000C268013AC260C269134482699342036122
+:1031800024BF436A036100238362036B03B11847C2
+:103190007047000070B530230D460446114683F396
+:1031A0001188866A2EB9FFF7C7FF10B186F3118820
+:1031B00070BDA36A1D70A36AE26A01339342A362E1
+:1031C00004D3E16920460439FFF7D0FF002080F3E3
+:1031D0001188EDE72DE9F84F04460D4690469946D3
+:1031E0004FF0300A8AF311880026B346A76A4FB918
+:1031F00049462046FFF7A0FF20B187F311883046EB
+:10320000BDE8F88FD4E90A073A1AA8EB06079742F7
+:1032100028BF1746402F1BD905F1400355F8042B52
+:103220009D4240F8042BF9D1A36A40364033A36293
+:10323000D4E90A239A4204D3E16920460439FFF70E
+:1032400095FF8BF311884645D9D28AF31188CDE7D3
+:1032500029463A46FDF7E2FDA36A3D443E443B441D
+:10326000A362E5E7D0E904239A4217D1C3689BB172
+:10327000836A8BB1043B9B1A0ED01360C368013B79
+:10328000C360C3691A4483699A42026124BF436AD6
+:103290000361002383620123184670470023FBE784
+:1032A00000F086B9014B586A704700BF000C00401F
+:1032B000034B002258631A610222DA60704700BF94
+:1032C000000C0040014B0022DA607047000C004007
+:1032D000014B5863704700BF000C0040FEE7000040
+:1032E00070B51B4B0025044686B058600E468562BB
+:1032F000016300F00BF904F11003A560E562C4E975
+:1033000004334FF0FF33C4E90044C4E90635FFF746
+:10331000C9FF2B46024604F134012046C4E90823C4
+:1033200080230C4A2565FEF747FB01230A4AE0602B
+:1033300000920375684672680192B268CDE9022373
+:10334000064BCDE90435FEF75FFB06B070BD00BF4C
+:1033500020260020243D0008293D0008DD32000819
+:10336000024AD36A1843D062704700BFB8230020D6
+:103370004B6843608B688360CB68C3600B694361B3
+:103380004B6903628B6943620B68036070470000FE
+:1033900008B53C4B40F2FF713B48D3F888200A4304
+:1033A000C3F88820D3F8882022F4FF6222F00702B5
+:1033B000C3F88820D3F88820D3F8E0200A43C3F864
+:1033C000E020D3F808210A43C3F808212F4AD3F894
+:1033D00008311146FFF7CCFF00F5806002F11C01B7
+:1033E000FFF7C6FF00F5806002F13801FFF7C0FF6C
+:1033F00000F5806002F15401FFF7BAFF00F580602C
+:1034000002F17001FFF7B4FF00F5806002F18C015A
+:10341000FFF7AEFF00F5806002F1A801FFF7A8FFFB
+:1034200000F5806002F1C401FFF7A2FF00F58060A3
+:1034300002F1E001FFF79CFF00F5806002F1FC0162
+:10344000FFF796FF02F58C7100F58060FFF790FFA3
+:1034500000F076F90E4BD3F8902242F00102C3F847
+:103460009022D3F8942242F00102C3F8942205225C
+:10347000C3F898204FF06052C3F89C20054AC3F867
+:10348000A02008BD0044025800000258303D00084A
+:1034900000ED00E01F00080308B500F025FBFEF773
+:1034A0004FFA0F4BD3F8DC2042F04002C3F8DC2087
+:1034B000D3F8042122F04002C3F80421D3F80431E8
+:1034C000084B1A6842F008021A601A6842F00402B7
+:1034D0001A60FEF721FFBDE80840FEF7BFBC00BF41
+:1034E000004402580018024870470000EFF30983B7
+:1034F000054968334A6B22F001024A6383F3098865
+:10350000002383F31188704700EF00E0302080F340
+:10351000118862B60D4B0E4AD96821F4E0610904A6
+:10352000090C0A430B49DA60D3F8FC2042F08072A0
+:10353000C3F8FC20084AC2F8B01F116841F001012D
+:1035400011602022DA7783F82200704700ED00E056
+:103550000003FA0555CEACC5001000E0302310B5CD
+:1035600083F311880E4B5B6813F4006314D0F1EE03
+:10357000103AEFF309844FF08073683CE361094B24
+:10358000DB6B236684F30988FEF7AEF910B1064BB6
+:10359000A36110BD054BFBE783F31188F9E700BF7A
+:1035A00000ED00E000EF00E02F0400083204000806
+:1035B000114BD3F8E82042F00802C3F8E820D3F812
+:1035C000102142F00802C3F810210C4AD3F8103140
+:1035D000D36B43F00803D363C722094B9A624FF0C1
+:1035E000FF32DA6200229A615A63DA605A6001227D
+:1035F0005A611A60704700BF004402580010005C16
+:10360000000C0040094A08B51169D3680B40D9B2D3
+:103610009B076FEA0101116107D5302383F31188FD
+:10362000FEF7A4F9002383F3118808BD000C0040C5
+:10363000064BD3F8DC200243C3F8DC20D3F8042186
+:103640001043C3F80401D3F8043170470044025812
+:103650003A4B4FF0FF31D3F8802062F00042C3F8BC
+:103660008020D3F8802002F00042C3F88020D3F8F5
+:103670008020D3F88420C3F88410D3F8842000225B
+:10368000C3F88420D3F88400D86F40F0FF4040F4A2
+:10369000FF0040F4DF4040F07F00D867D86F20F093
+:1036A000FF4020F4FF0020F4DF4020F07F00D867C7
+:1036B000D86FD3F888006FEA40506FEA5050C3F8D3
+:1036C0008800D3F88800C0F30A00C3F88800D3F854
+:1036D0008800D3F89000C3F89010D3F89000C3F896
+:1036E0009020D3F89000D3F89400C3F89410D3F846
+:1036F0009400C3F89420D3F89400D3F89800C3F84A
+:103700009810D3F89800C3F89820D3F89800D3F80D
+:103710008C00C3F88C10D3F88C00C3F88C20D3F83D
+:103720008C00D3F89C00C3F89C10D3F89C10C3F80D
+:103730009C20D3F89C3000F0AFB900BF0044025881
+:1037400008B50122534BC3F80821534BD3F8F4209A
+:1037500042F00202C3F8F420D3F81C2142F0020226
+:10376000C3F81C210222D3F81C314C4BDA605A6892
+:103770009104FCD54A4A1A6001229A60494ADA60EB
+:1037800000221A614FF440429A61444B9A699204B4
+:10379000FCD51A6842F480721A603F4B1A6F12F41B
+:1037A000407F04D04FF480321A6700221A671A68EB
+:1037B00042F001021A60384B1A685007FCD500220B
+:1037C0001A611A6912F03802FBD1012119604FF019
+:1037D000804159605A67344ADA62344A1A611A6879
+:1037E00042F480321A602C4B1A689103FCD51A6897
+:1037F00042F480521A601A689204FCD52C4A2D4972
+:103800009A6200225A63196301F57C01DA6301F2BE
+:10381000E71199635A64284A1A64284ADA621A68D6
+:1038200042F0A8521A601C4B1A6802F02852B2F1FA
+:10383000285FF9D148229A614FF48862DA61402208
+:103840001A621F4ADA641F4A1A651F4A5A651F4ADC
+:103850009A6532231E4A1360136803F00F03022B8C
+:10386000FAD10D4A136943F003031361136903F09E
+:103870003803182BFAD14FF00050FFF7D9FE4FF064
+:103880008040FFF7D5FE4FF00040BDE80840FFF74D
+:10389000CFBE00BF008000510044025800480258CB
+:1038A00000C000F0020000010000FF010088900845
+:1038B0001210200063020901470E0508DD0BBF014D
+:1038C00020000020000001100910E000000101109C
+:1038D000002000524FF0B04208B5D2F8883003F013
+:1038E0000103C2F8883023B1044A13680BB1506851
+:1038F0009847BDE80840FFF731BE00BFB442002042
+:103900004FF0B04208B5D2F8883003F00203C2F895
+:10391000883023B1044A93680BB1D0689847BDE85A
+:103920000840FFF71BBE00BFB44200204FF0B0427A
+:1039300008B5D2F8883003F00403C2F8883023B108
+:10394000044A13690BB150699847BDE80840FFF776
+:1039500005BE00BFB44200204FF0B04208B5D2F817
+:10396000883003F00803C2F8883023B1044A936911
+:103970000BB1D0699847BDE80840FFF7EFBD00BF25
+:10398000B44200204FF0B04208B5D2F8883003F0BE
+:103990001003C2F8883023B1044A136A0BB1506A8D
+:1039A0009847BDE80840FFF7D9BD00BFB4420020EA
+:1039B0004FF0B04310B5D3F8884004F47872C3F8E0
+:1039C0008820A30604D5124A936A0BB1D06A98479F
+:1039D000600604D50E4A136B0BB1506B9847210655
+:1039E00004D50B4A936B0BB1D06B9847E20504D515
+:1039F000074A136C0BB1506C9847A30504D5044AD1
+:103A0000936C0BB1D06C9847BDE81040FFF7A6BD92
+:103A1000B44200204FF0B04310B5D3F8884004F40E
+:103A20007C42C3F88820620504D5164A136D0BB199
+:103A3000506D9847230504D5124A936D0BB1D06D94
+:103A40009847E00404D50F4A136E0BB1506E9847A7
+:103A5000A10404D50B4A936E0BB1D06E9847620453
+:103A600004D5084A136F0BB1506F9847230404D54F
+:103A7000044A936F0BB1D06F9847BDE81040FFF731
+:103A80006DBD00BFB442002008B5FFF7BBFDBDE827
+:103A90000840FFF763BD0000062108B50846FFF7A0
+:103AA0001FFA06210720FFF71BFA06210820FFF75F
+:103AB00017FA06210920FFF713FA06210A20FFF75B
+:103AC0000FFA06211720FFF70BFA06212820FFF72F
+:103AD00007FA09217A20FFF703FA07213220BDE80F
+:103AE0000840FFF7FDB9000008B5FFF7B1FD00F091
+:103AF0000BF8FDF7F7FBFDF7C9FAFFF7F5FCBDE89A
+:103B00000840FFF7CDBB00000023054A19460133EA
+:103B1000102BC2E9001102F10802F8D1704700BF72
+:103B2000B442002010B501390244904201D1002076
+:103B300005E0037811F8014FA34201D0181B10BD16
+:103B40000130F2E7034611F8012B03F8012B002A9C
+:103B5000F9D1704753544D333248373F3F3F0053FC
+:103B6000544D3332483733782F3732780053544D21
+:103B70003332483734332F3735332F373530000061
+:103B800001105A000310590001205800032056006C
+:103B90000000000009100008F50F000831100008AF
+:103BA0001D10000829100008151000080110000859
+:103BB000ED0F00083D1000080000000001000000AB
+:103BC0000000000063300000C43B00081024002007
+:103BD000202600204172647550696C6F7400254284
+:103BE0004F415244252D424C002553455249414CEA
+:103BF000250000000200000000000000291200085B
+:103C00009912000840004000D03E0020E03E002015
+:103C1000020000000000000003000000000000009F
+:103C2000E11200080000000010000000F03E00203B
+:103C300000000000010000000000000064410020BE
+:103C400001010200F91D0008091D0008A51D00085A
+:103C5000891D0008430000005C3C00080902430085
+:103C6000020100C032090400000102020100052423
+:103C700000100105240100010424020205240600AD
+:103C800001070582030800FF09040100020A000081
+:103C90000007050102400000070581024000000006
+:103CA00012000000A83C00081201100102000040B0
+:103CB0000912415700020102030100000403090434
+:103CC00025424F415244250053444D4F44454C48F2
+:103CD0003756310030313233343536373839414296
+:103CE0004344454600000000000000003D14000869
+:103CF000F5160008A1170008400040009C42002073
+:103D00009C42002001000000AC4200208000000026
+:103D10004001000008000000000100000010000049
+:103D2000080000006D61696E0069646C6500000048
+:103D30000001802A00000000AAAAAAAA000100240B
+:103D4000FFFF00000000000000A00A00000040018A
+:103D500000000000AAAAAAAA00000001FFFF0000BC
+:103D6000000000000000000010000004000000003F
+:103D7000AAAAAAAA00000008FBDF000000000000B9
+:103D8000000000000000000000000000AAAAAAAA8B
+:103D900000000000FFFF0000000000000000000025
+:103DA0000001000000000000AAAAAAAA0001000069
+:103DB000FFFF000000000000000000000000000005
+:103DC00000000000AAAAAAAA00000000FFFF00004D
+:103DD00000000000000000000000000000000000E3
+:103DE000AAAAAAAA00000000FFFF0000000000002D
+:103DF000000000000000000000000000AAAAAAAA1B
+:103E000000000000FFFF00000000000000000000B4
+:103E10000000000000000000AAAAAAAA00000000FA
+:103E2000FFFF000000000000000000000000000094
+:103E300000000000AAAAAAAA00000000FFFF0000DC
+:103E40000000000000000000000000000000000072
+:103E5000AAAAAAAA00000000FFFF000000000000BC
+:103E600000000000000000005704000000000000F7
+:103E700000001A0000000000FF0000000000000029
+:103E8000543B0008830400005F3B0008500400001E
+:103E90006D3B00080096000000000800960000003E
+:103EA0000008000004000000BC3C00080000000006
+:103EB0000000000000000000000000000000000002
+:043EC00000000000FE
+:00000001FF
diff --git a/Tools/bootloaders/SIYI_N7_bl.bin b/Tools/bootloaders/SIYI_N7_bl.bin
new file mode 100755
index 00000000000000..c6b617881bf249
Binary files /dev/null and b/Tools/bootloaders/SIYI_N7_bl.bin differ
diff --git a/Tools/bootloaders/SPRacingH7RF_bl.bin b/Tools/bootloaders/SPRacingH7RF_bl.bin
new file mode 100755
index 00000000000000..6a8d9c489c2bd1
Binary files /dev/null and b/Tools/bootloaders/SPRacingH7RF_bl.bin differ
diff --git a/Tools/bootloaders/SPRacingH7RF_bl.hex b/Tools/bootloaders/SPRacingH7RF_bl.hex
new file mode 100644
index 00000000000000..78129ee9c15bdf
--- /dev/null
+++ b/Tools/bootloaders/SPRacingH7RF_bl.hex
@@ -0,0 +1,1697 @@
+:020000040800F2
+:1000000000060020F5050008912500084525000898
+:100010006D2500084525000865250008F70500083E
+:10002000F7050008F7050008F70500083D5B000824
+:10003000F7050008F7050008F7050008F7050008B0
+:10004000F7050008F7050008F7050008F7050008A0
+:10005000F7050008F7050008215F00084D5F00085C
+:10006000795F0008A55F0008D15F0008F705000868
+:10007000F7050008F7050008F7050008F705000870
+:10008000F7050008F7050008F7050008F705000860
+:10009000F7050008F7050008F7050008FD5F0008F0
+:1000A000F7050008F7050008F7050008F705000840
+:1000B000F7050008F7050008F7050008F705000830
+:1000C000F7050008F7050008F7050008F705000820
+:1000D000F7050008E9600008F7050008F7050008C3
+:1000E00061600008F7050008F7050008F70500083B
+:1000F000F7050008F7050008F7050008F7050008F0
+:10010000F7050008F7050008FD600008F70500087E
+:10011000F7050008F7050008F7050008F7050008CF
+:10012000F7050008F7050008F7050008F7050008BF
+:10013000F7050008F7050008F7050008F7050008AF
+:10014000F7050008F7050008F7050008F70500089F
+:10015000F7050008F7050008F7050008F70500088F
+:10016000F7050008F7050008F7050008F70500087F
+:10017000F7050008E14F0008F7050008F70500083B
+:10018000F7050008F7050008F7050008F70500085F
+:10019000F7050008F7050008F7050008F70500084F
+:1001A000F7050008F7050008F7050008F70500083F
+:1001B000D5600008F7050008F7050008F7050008F6
+:1001C000F7050008F7050008F7050008F70500081F
+:1001D000F7050008F7050008F7050008F70500080F
+:1001E000F7050008F7050008F7050008F7050008FF
+:1001F000F7050008F7050008F7050008F7050008EF
+:10020000F7050008F7050008F7050008F7050008DE
+:10021000F7050008F7050008F7050008F7050008CE
+:10022000F7050008F7050008D9470008F70500089A
+:10023000F7050008F7050008F7050008F7050008AE
+:10024000F7050008F7050008F7050008F70500089E
+:10025000F7050008F7050008F7050008F70500088E
+:10026000F7050008F7050008F7050008F70500087E
+:10027000F7050008F7050008F7050008F70500086E
+:10028000F7050008F7050008F7050008F70500085E
+:10029000F7050008F7050008F7050008F70500084E
+:1002A000F7050008F7050008F7050008F70500083E
+:1002B000F7050008F7050008F7050008F70500082E
+:1002C000F7050008F7050008F7050008F70500081E
+:1002D000F7050008F7050008F7050008F70500080E
+:1002E000D50700080D2200081D25000800000000A9
+:1002F00053B94AB9002908BF00281CBF4FF0FF318D
+:100300004FF0FF3000F074B9ADF1080C6DE904CE88
+:1003100000F006F8DDF804E0DDE9022304B07047E0
+:100320002DE9F047089D04468E46002B4DD18A42A8
+:10033000944669D9B2FA82F252B101FA02F3C2F1DB
+:10034000200120FA01F10CFA02FC41EA030E94406C
+:100350004FEA1C48210CBEFBF8F61FFA8CF708FB8D
+:1003600016E341EA034306FB07F199420AD91CEB65
+:10037000030306F1FF3080F01F81994240F21C8197
+:10038000023E63445B1AA4B2B3FBF8F008FB1033DF
+:1003900044EA034400FB07F7A7420AD91CEB040414
+:1003A00000F1FF3380F00A81A74240F207816444E4
+:1003B000023840EA0640E41B00261DB1D440002369
+:1003C000C5E900433146BDE8F0878B4209D9002DCD
+:1003D00000F0EF800026C5E9000130463146BDE857
+:1003E000F087B3FA83F6002E4AD18B4202D38242C1
+:1003F00000F2F980841A61EB030301209E46002D70
+:10040000E0D0C5E9004EDDE702B9FFDEB2FA82F2C4
+:10041000002A40F09280A1EB0C014FEA1C471FFA22
+:100420008CFE0126200CB1FBF7F307FB131140EA09
+:1004300001410EFB03F0884208D91CEB010103F1D6
+:10044000FF3802D2884200F2CB804346091AA4B298
+:10045000B1FBF7F007FB101144EA01440EFB00FE6C
+:10046000A64508D91CEB040400F1FF3102D2A645D1
+:1004700000F2BB800846A4EB0E0440EA03409CE770
+:10048000C6F12007B34022FA07FC4CEA030C20FA1D
+:1004900007F401FA06F31C43F9404FEA1C4900FA3D
+:1004A00006F3B1FBF9F8200C1FFA8CFE09FB1811BA
+:1004B00040EA014108FB0EF0884202FA06F20BD92D
+:1004C0001CEB010108F1FF3A80F08880884240F27D
+:1004D0008580A8F102086144091AA4B2B1FBF9F0C1
+:1004E00009FB101144EA014100FB0EFE8E4508D9BC
+:1004F0001CEB010100F1FF346CD28E456AD9023841
+:10050000614440EA0840A0FB0294A1EB0E01A14225
+:10051000C846A64656D353D05DB1B3EB080261EB93
+:100520000E0101FA07F722FA06F3F1401F43C5E96D
+:10053000007100263146BDE8F087C2F12003D840A3
+:100540000CFA02FC21FA03F3914001434FEA1C47E5
+:100550001FFA8CFEB3FBF7F007FB10360B0C43EAD7
+:10056000064300FB0EF69E4204FA02F408D91CEB87
+:10057000030300F1FF382FD29E422DD90238634485
+:100580009B1B89B2B3FBF7F607FB163341EA034125
+:1005900006FB0EF38B4208D91CEB010106F1FF3874
+:1005A00016D28B4214D9023E6144C91A46EA00466B
+:1005B00038E72E46284605E70646E3E61846F8E6FD
+:1005C0004B45A9D2B9EB020864EB0C0E0138A3E746
+:1005D0004646EAE7204694E74046D1E7D0467BE727
+:1005E000023B614432E7304609E76444023842E79F
+:1005F000704700BF02E000F000F8FEE772B637482F
+:1006000080F30888364880F3098836483649086000
+:1006100040F20000CCF200004EF63471CEF2000140
+:100620000860BFF34F8FBFF36F8F40F20000C0F23E
+:10063000F0004EF68851CEF200010860BFF34F8FF4
+:10064000BFF36F8F4FF00000E1EE100A4EF63C71E1
+:10065000CEF200010860062080F31488BFF36F8F8C
+:1006600004F04AF805F0C4F94FF055301F491B4A11
+:1006700091423CBF41F8040BFAE71D49184A9142E8
+:100680003CBF41F8040BFAE71A491B4A1B4B9A423C
+:100690003EBF51F8040B42F8040BF8E7002018495C
+:1006A000184A91423CBF41F8040BFAE704F062F8A3
+:1006B00005F018FA144C154DAC4203DA54F8041B3B
+:1006C0008847F9E700F050F8114C124DAC4203DABC
+:1006D00054F8041B8847F9E704F04AB800060020E4
+:1006E000002200200000000808ED00E000000020CB
+:1006F000000600201869000800220020D4220020F3
+:10070000D82200200C4A0020E0020008EC02000879
+:10071000EC020008EC0200082DE9F04F2DED108AE4
+:10072000C1F80CD0D0F80CD0BDEC108ABDE8F08F29
+:10073000002383F311882846A047002003F0DEF948
+:10074000FEE703F0F7F800DFFEE70000054B10B509
+:1007500004460360806810B103685B6898472046D0
+:1007600010BD00BF6464000838B503F0EBFE054619
+:1007700003F0B8FF0446F0B9144B9D421DD001337D
+:100780009D4241F2883512BF044600250124002015
+:1007900003F0E2FE0CB100F09FF80D4C00F0FAFE01
+:1007A00000F0A2FD204601F03FFB40B944F6206076
+:1007B00003F0AAF9F6E70025E9E70546E7E728464A
+:1007C00000F030F900F088F8F9E700BF010007B049
+:1007D000D82200200448054B054A03600023054940
+:1007E000836005F0E5BC00BFD822002064640008E7
+:1007F000F42400204D07000808B500F041FDA0F1E9
+:1008000020035842584108BD07B5042101900DEB63
+:10081000010000F053FD03B05DF804FB07B541F2A1
+:100820001203022101A8ADF8043000F047FD03B027
+:100830005DF804FB38B5302383F31188174803684B
+:100840000BB103F03FFA0023154A4FF47A711348B5
+:1008500003F02EFA002383F31188124C236813B19E
+:100860002368013B2360636813B16368013B6360E5
+:100870000D4D2B7833B963687BB9022000F0F4FD8D
+:10088000322363602B78032B07D163682BB90220D6
+:1008900000F0EAFD4FF47A73636038BD68230020EE
+:1008A000350800088824002080230020084B187099
+:1008B00003280CD8DFE800F008050208022000F049
+:1008C000CBBD022000F0BEBD024B00225A60704733
+:1008D0008023002088240020F7B54D4801A901F0AD
+:1008E0002BFC002800F091804FF01043494A196812
+:1008F000013100F0878004339342F8D14FF0104467
+:100900006268A2427ED3444BDB6823449A4279D288
+:10091000002000F003FD0220FFF7C8FF3F4B00213D
+:10092000D3F8E820C3F8E810D3F81021C3F8101169
+:10093000D3F81021D3F8EC20C3F8EC10D3F814212D
+:10094000C3F81411D3F81421D3F8F020C3F8F01031
+:10095000D3F81821C3F81811D3F81821D3F8802040
+:1009600042F00072C3F88020D3F8802022F0007299
+:10097000C3F88020D3F8803072B64FF0E023C3F87C
+:10098000084DD4E90004BFF34F8FBFF36F8F244AA3
+:10099000C2F88410BFF34F8F536923F4803353613F
+:1009A000BFF34F8FD2F8803043F6E076C3F3C9052A
+:1009B000C3F34E335B0103EA060C29464CEA817708
+:1009C0000139C2F87472F9D2203B13F1200FF2D131
+:1009D000BFF34F8FBFF36F8FBFF34F8FBFF36F8F97
+:1009E000536923F4003353610023C2F85032BFF33C
+:1009F0004F8FBFF36F8F302383F31188854680F3C9
+:100A000008882047024800F063FE03B0F0BD00BF35
+:100A1000D82200202000009000220020004402582C
+:100A200000ED00E02DE9F04FB34B9DB02022FF21F7
+:100A3000079014A89E68DB68069300F055FDAF4A46
+:100A40001378A3B90121AE4811700360302383F3FA
+:100A5000118803680BB103F035F90023A94A4FF45C
+:100A60007A71A74803F024F9002383F31188079BC8
+:100A700013B1A54B079A1A60A44A1378032B03D02D
+:100A800000231370A04A53600023079DA04F98468F
+:100A90009B46CDE90433012000F0DEFC25B19A4BE2
+:100AA0001B68002B00F07C83002000F0E9FB0C9019
+:100AB0000C9B002BF2DB012000F0C4FC0C9B213BC3
+:100AC0001F2BE8D801A252F823F000BF4D0B0008FD
+:100AD000750B00080F0C0008970A0008970A000819
+:100AE000970A0008ED0E0008E5100008830F0008C3
+:100AF0006310000889100008AF100008970A00086A
+:100B0000C1100008970A00082D110008ED0B00081D
+:100B1000970A0008A7110008AD0C0008DF0D0008B7
+:100B2000970A0008CD0F0008970A0008970A0008E6
+:100B3000970A0008970A0008970A0008970A000811
+:100B4000970A0008970A00080F0C00080220FFF718
+:100B500053FE002840F05083079B0221059A0FA8FE
+:100B6000002A08BF1D4641F21233ADF83C3000F0B8
+:100B7000A5FB90E74FF47A7000F082FB041EEBDBDC
+:100B80000220FFF739FE0028E6D0013C052C00F2D8
+:100B90003583DFE804F0030A0D101339052304211F
+:100BA0000FA80F9300F08AFB17E004215248F9E7E1
+:100BB00004215848F6E704215748F3E74FF01C0991
+:100BC000484609F1040900F0ABFB04210F900FA87F
+:100BD00000F074FBB9F12C0FF2D10120049B4FF00F
+:100BE000000B00FA04F41C43E3B2049300F0C8FCC9
+:100BF000B8F1000F05D0049B03F00B030B2B08BFCB
+:100C00000025FFF70BFE46E704214448CAE7B8F188
+:100C1000000FA1D0049B03F00B030B2B9CD10220EF
+:100C2000FFF7EAFD0446002896D001204FF00008A7
+:100C300000F074FB0220FFF739FE5FFA88F948469E
+:100C400000F07CFB0546B8B10C99484608F1010854
+:100C5000A1F140025142514100F080FB0028ECD14B
+:100C60000546059441F2121302210FA8A046ADF8E3
+:100C70003C3000F023FB0EE72E46DFF87C8001209D
+:100C8000FFF714FED8F80830B34207D9304600F019
+:100C900047FB013040F0B5820436F3E700261B4BDA
+:100CA000A04605941E70184B5E609FE7B8F1000FD8
+:100CB0003FF452AF049B03F00B030B2B7FF44CAFBC
+:100CC00064210DA800F0F0FA814600287FF444AFBB
+:100CD0000220FFF791FD044600283FF43DAF7A6AF9
+:100CE0003B6A8DF82F9053430D9A93421AD20C48C9
+:100CF00000F0C4FB30E700BF002200208424002065
+:100D00006823002035080008882400208023002064
+:100D1000D822002004220020082200200C220020DB
+:100D200008630008BF48C846CA4600F0A7FBFFF7A3
+:100D300075FD01210DF12F0000F0C0FA0D9B534508
+:100D400041D900230EAA41463846CDE90E330FABF8
+:100D500000F0C2FC002885D001F022FC0E9B00EBC5
+:100D6000030901210DF12F0000F0A8FA01F018FC91
+:100D7000484520D9384600F019FF80B964210D9B01
+:100D8000A94808F1010801FB0AF1B1FBF3F18DF864
+:100D90002F10C9B200F072FB3B6A9A44CEE701F013
+:100DA000FFFB0F9B184448453FF65CAF01F0F8FB92
+:100DB0000E9B00EB03090E9B4FF47A70A3FB00031C
+:100DC00002F0A2FECDE7642301210DF12F00A04621
+:100DD0008DF82F3000F072FA0023069306E7B8F181
+:100DE000000F3FF4B9AE049B03F00B030B2B7FF411
+:100DF000B3AE0220FFF75AFD322000F041FAB0F105
+:100E0000000AFFF6A9AE069BD14653440893874BD0
+:100E1000089ADB689A423FF69FAEBAF5807F3FF7AB
+:100E20009BAE834A0024A24509920EDD4FF47A70EE
+:100E300000F026FA0C900C9B002BFFF68DAE0C9B5D
+:100E40000134099A02F8013BEDE7C820FFF7D4FC12
+:100E5000044600283FF480AE069B1F2B11D8C3F137
+:100E6000200223F0030014AB71495245184428BFF7
+:100E70005246099200F006FB099AFF216C4800F0E7
+:100E800033FB00239846CDE90E33B9F1000F02D1B0
+:100E9000A046089BA1E70FAB654A06993846029326
+:100EA0000EAB4244414401930DAB00934B4601F01D
+:100EB000A3F800283FF4D6AE01F074FB0D9B8246E8
+:100EC00009919844A9EB030901F06CFB0E9B099A68
+:100ED00013EB0A0342F10002834272EB0103F3D2E7
+:100EE000384600F063FE0028EED1CEE7B8F1000FDF
+:100EF0003FF432AE049B03F00B030B2B7FF42CAEBC
+:100F00000220FFF7D3FC322000F0BAF9B0F1000A5A
+:100F1000FFF622AE1AF003047FF41EAE434A0AEB3A
+:100F20000603926893423FF617AEBAF5807F3FF70B
+:100F300013AEDFF8FC90A2450DDD4FF47A7000F09F
+:100F40009FF90C900C9B002BFFF606AE0C9B013416
+:100F500009F8013BEFE7C820FFF74EFC04460028E4
+:100F60003FF4FAADCAF38702314930464FEAAA0985
+:100F700000F0C2FA804600283FF474AE06EB890602
+:100F800034E60220FFF738FC00283FF4E5AD00F01E
+:100F900003FA00283FF4E0AD4FF00009DFF88CA021
+:100FA0004C46DAF808304B450CD9484609F104099B
+:100FB00000F0B6F904220F900FA9204601F02EF997
+:100FC0000446EEE72046FFF71FFC0FE664210EA85B
+:100FD00000F06AF9044600287FF4BEAD0220FFF756
+:100FE0000BFC00283FF4B8AD0E9BA14603F0030AAA
+:100FF0000E99A1EB0A01A14223D91F2C1AD8149BE8
+:10100000013317D024F003031CAA134453F8203CE7
+:101010000F93484604220FA9043401F0FFF88146DB
+:10102000E6E700BF2D6300084563000800220020AA
+:101030008423002004230FAA2146384601F028F813
+:10104000E7E7BAF1000F0AD053460FAA384601F07D
+:101050001FF8484652460FA901F0E0F8814648467D
+:10106000B1E7002364210FA80F9300F01DF90028B9
+:101070007FF472AD0220FFF7BFFB00283FF46CAD98
+:101080000F9800F07FF99EE7002364210FA80F93CB
+:1010900000F00AF900287FF45FAD0220FFF7ACFBF7
+:1010A00000283FF459AD0F9800F06EF98BE702204D
+:1010B000FFF7A2FB00283FF44FAD00F07DF982E777
+:1010C0000220FFF799FB00283FF446AD0FA914203A
+:1010D00000F078F90890FFF797FB08990FA800F047
+:1010E000EDF883E5322000F0CBF8041EFFF634ADB6
+:1010F000A3077FF431AD444A04EB0B03926893429B
+:101100003FF62AAD0220FFF777FB00283FF424AD1D
+:1011100024F003045C44A3453FF468AD58460BF14A
+:10112000040B00F0FDF8FFF76FFBF4E74FF47A7063
+:10113000FFF762FB00283FF40FAD00F02DF978B106
+:10114000149B013327D00FAB14AA00213846029319
+:101150000EAB01930DAB0093202300F04DFF08B9B7
+:1011600044467FE501F01EFA284E04460D4601F084
+:1011700019FA0E9B1B1945F10002834272EB010321
+:10118000F5D2304600F012FD0028F0D12022FF21D8
+:1011900014A800F0A9F9FFF741FB1D4802F0B4FCC8
+:1011A0001DB0BDE8F08FB8F1000F3FF4D5AC049B43
+:1011B00003F00B030B2B7FF4CFAC002364210FA8AB
+:1011C0000F9300F071F8044600287FF4C5AC0220AC
+:1011D000FFF712FB814600283FF4BEACFFF71EFB71
+:1011E00041F2883002F090FC0F9800F015FAC846E2
+:1011F000254600F0C5F94EE48046F7E44FF0000BB9
+:10120000AAE405942EE500BF00220020D822002089
+:10121000A08601002DE9F84F4FF47A7306460D467B
+:10122000002402FB03F7DFF85080DFF8509098F9B4
+:1012300000305FFA84FA5A1C01D0A34212D159F847
+:1012400024002A4631460368D3F820B03B46D847ED
+:10125000854207D1074B012083F800A0BDE8F88F35
+:101260000124E4E7002CFBD04FF4FA7002F04CFCB0
+:101270000020F3E7D42400201022002014220020B4
+:10128000002307B5024601210DF107008DF8073054
+:10129000FFF7C0FF20B19DF8070003B05DF804FB25
+:1012A0004FF0FF30F9E700000A46042108B5FFF7C8
+:1012B000B1FF80F00100C0B2404208BD074B0A46B2
+:1012C00030B41978064B53F8214001462368204674
+:1012D000DD69044BAC4630BC604700BFD42400201D
+:1012E00014220020A086010070B50A4E00240A4D89
+:1012F00002F028FF308028683388834208D902F042
+:101300001DFF2B6804440133B4F5003F2B60F2D37A
+:1013100070BD00BFD62400209024002002F0AABF98
+:1013200000F1006000F500300068704700F10060D7
+:10133000920000F5003002F03BBF0000054B1A6838
+:10134000054B1B889B1A834202D9104402F0F6BE5B
+:101350000020704790240020D624002038B5044691
+:10136000074D29B128682044BDE8384002F0F2BE9C
+:101370002868204402F0E8FE0028F3D038BD00BF02
+:10138000902400200020704700F1FF5000F58F10DE
+:10139000D0F8000870470000064991F8243033B1B6
+:1013A00000230822086A81F82430FFF7BFBF01201C
+:1013B000704700BF94240020014B1868704700BF9D
+:1013C0000010005C1C4B0246F0B5186803261B4B4E
+:1013D000C0F30B07000C5C6893F90850B3F800C029
+:1013E000BC451AD15C6893F908500426144B1F8839
+:1013F0000433874208BF13F9025C013EF7D1013A7A
+:10140000013C0B460A4493420CD214F9016F581C5C
+:1014100056B1034600F8016CF5E7013E03F10C03F9
+:10142000DCD1E2E7184605E02C2482421C7001D989
+:10143000981C5D70401AF0BD0010005C1C2200205A
+:1014400080630008022803D1024B4FF400229A6106
+:10145000704700BF00100258022802D1014B082239
+:101460009A61704700100258022804D1024A536959
+:1014700083F0080353617047001002580FB404B0A2
+:1014800070470000002310B5934203D0CC5CC454D5
+:101490000133F9E710BD0000013810B510F9013F24
+:1014A0003BB191F900409C4203D11AB10131013A9C
+:1014B000F4E71AB191F90020981A10BD1046FCE724
+:1014C0000138013910F9013F11F9012F0BB1934295
+:1014D000F8D0981A7047000003460246D01A12F955
+:1014E000011B0029FAD1704702440346934202D0FF
+:1014F00003F8011BFAE770472DE9F8431F4D144626
+:101500000746884695F8242052BBDFF870909CB3BC
+:1015100095F824302BB92022FF2148462F62FFF78F
+:10152000E3FF95F824004146C0F1080205EB800076
+:10153000A24228BF2246D6B29200FFF7A3FF95F839
+:101540002430A41B17441E449044E4B2F6B2082E83
+:1015500085F82460DBD1FFF71FFF0028D7D108E012
+:101560002B6A03EB82038342CFD0FFF715FF0028DD
+:10157000CBD10020BDE8F8830120FBE794240020B4
+:10158000024B1A78024B1A70704700BFD424002017
+:101590001022002038B51A4C1A4D204601F0F4FCF8
+:1015A0002946204601F01CFD2D681748D5F89020EB
+:1015B000D2F8043843F00203C2F8043802F0A4FA67
+:1015C0001249284601F01AFED5F89020104DD2F8A5
+:1015D0000438286823F002030E49A042C2F80438F8
+:1015E0004FF4E1330B6001D001F02CFC6868A0429D
+:1015F00004D00849BDE8384001F024BC38BD00BF24
+:10160000F82B00208866000840420F009066000812
+:1016100014220020BC2400200C4B70B50C4D044655
+:101620001E780C4B55F826209A420DD00A4B00210B
+:1016300018221846FFF758FF0460014655F82600A7
+:10164000BDE8704001F0FEBB70BD00BFD424002097
+:1016500014220020F82B0020BC2400208069704751
+:10166000C0697047006A7047406A7047806A704777
+:10167000F0B5ADF2044D0E46054600214FF47F72E1
+:1016800001A80091FFF730FF2C6A744301362B6AE2
+:101690007343A34216D92B686A46214628465F68E1
+:1016A0004FF48063B84770B16A464FF4806312F814
+:1016B000011BFF290AD1013B9BB2002BF7D104F596
+:1016C0008064E4E701200DF2044DF0BD0020FAE74C
+:1016D00080680368DB69184730B5456A85B0044601
+:1016E0008D420FD30568CDE90023026A03ABAD6AD2
+:1016F0005143A84720B1206A039BC31A584258415E
+:1017000005B030BD0020FBE7F0B5C56987B00446E1
+:101710008D4212D30C9F866905687143CDE901376C
+:1017200005AB00936D69036AA84720B1A069059BCA
+:10173000C31A5842584107B0F0BD0020FBE7000033
+:10174000F0B5662389B00024054601268068079419
+:1017500003A9CDE90336CDE9054403685B699847E1
+:10176000A86822462146036800941F692346B847AB
+:10177000A8689923079403A9CDE90336CDE9054468
+:1017800003685B699847A86822462146036800946D
+:101790001D692346A84709B0F0BD0000254B2DE97F
+:1017A000F04F1B789FB0002504468DF828304FF08D
+:1017B0009F0E806805A9204BADF829500995CDE909
+:1017C00005E3CDE9075503685B699847A0680322E4
+:1017D0002946036800922A461E690AABB04738B30F
+:1017E0000C2294F88C30DFF858B09DF8281002FBDA
+:1017F00003B31A7991421BD19DF829205B799A4253
+:1018000016D1A0684FF05A0C0C4B082605A9099672
+:10181000CDE905C3CDE9075503685B699847A06822
+:101820002A462946036800961F690AABB84748B99B
+:1018300000205EE1DC6200080100000101210001DE
+:10184000386400080422B7490AA804F0EBFC0546F6
+:101850000028EDD1BDF82C306FF48277A3813B4492
+:10186000012BE5D8079605A9CDE90A00A068036811
+:101870005B699847A0682A462946036800961E6956
+:101880000AABB0470028D3D0DDE90A361A0202F4C9
+:10189000706242EA1662FF2ACAD11B0E26F07F460A
+:1018A00050222946142B26610AA828BF1423A373AB
+:1018B000FFF71AFEA068079605A903685B699847B9
+:1018C000A068A37B294602689B0000930AAB1669B7
+:1018D0002A46B0470028ABD00B990029A8DBC908DD
+:1018E0006FF07E43149D4FF0010E994228BF1946B8
+:1018F000C5F303130EFA03F221FA03F302916161B7
+:10190000A261E361002B93D02646A44600274FF046
+:1019100002081EAAC7F3460302EB830353F834AC54
+:1019200007F001031B01DA1D0EFA03F908FA02F2AF
+:10193000A2EB090202EA0A02DA401BD0216A03F193
+:1019400008090F330EFA02F203910EFA09F108FAB0
+:1019500003F3CCF830205B1A03EA0A0323FA09F9EF
+:10196000039B8CF82C909A42A36A88BF2262934210
+:1019700088BFA26201370CF1100C042FC9D1236A71
+:101980004FF0020C029A4FF0010E139F9A4224BFAF
+:10199000B2FBF3F1616207F00F0138BF01234FF092
+:1019A000090201F1010138BF63624900336B4BB397
+:1019B000531C0EFA02F8A2F105090CFA03F30EFA11
+:1019C00009FAA3EB080302F1FF380CFA08F83B40D0
+:1019D000A8EB0A08D34008EA070828FA09F800F03B
+:1019E0008B80012B00F08A80022B00F08980032B72
+:1019F00008BF4FF47A735FFA88F808FB0333736308
+:101A00004B43B36307321036252ACFD115F0C04FB0
+:101A1000C5F3417376D0012B76D0022B0CBF4FF467
+:101A20007A634FF47A43C5F3046202FB0333E3663F
+:101A30004B432367199B9E0769D0062384F87430B3
+:101A400015F4005F05F00F03C5F3042514BF402211
+:101A50000822013305FB02250C225B00A5675D43CC
+:101A600094F88C3002FB03B3E5679B68012B03D12C
+:101A70009DF86930002B52D10A9B9B027FF5D8AEAE
+:101A8000022300221EA901EB830353F8503CC3F349
+:101A90000721C3F3421503F01F0384F8801084F874
+:101AA000885084F8813000293FF4C2AE002A3FD12B
+:101AB000189BC3F3025213F4401F84F883207FF471
+:101AC000B7AEDF0630D4189B03F40072002A14BFAF
+:101AD0000122002284F8872039D1179B1A0740D5AC
+:101AE000002384F88630702384F88530012384F83D
+:101AF0008D301FB0BDE8F08F01237CE710237AE71B
+:101B0000802378E710238EE74FF480738BE7590723
+:101B100001D5502392E713F0780F91D088E6024662
+:101B20001023AFE790630008042A7FF481AECAE770
+:101B30001C9BC3F30751C3F3025211F0060F84F844
+:101B400083207FF475AE9E06BDD5012AEDE7DD0347
+:101B500003D5002384F88930BFE79903BDD501235D
+:101B6000F8E75B07C2D5012384F886300523BBE77D
+:101B700030B58BB000240546806803920A4A05916F
+:101B800005A9CDE90624CDE90844026852699047C9
+:101B9000A8680121039B026800912146156922462D
+:101BA000A8470BB030BD00BF0100000113B50446CB
+:101BB000A0680368DB6C98470028F9D10DF1070293
+:101BC00094F885102046FFF7D3FF94F886309DF8EF
+:101BD00007001BB100F0010002B010BDC043C0F30C
+:101BE000C010F9E730B50D4B8BB000240546806876
+:101BF0008DF80F20059105A9CDE90634CDE90844FB
+:101C000003685B699847A86801220DF10F0103681A
+:101C100000941D692346A8470BB030BD01000001A8
+:101C2000F7B517460DF1070206461D46FFF7A0FF60
+:101C300068B19DF8074039469DF82020304624EAD7
+:101C400005042A4022438DF80720FFF7CBFF03B09D
+:101C5000F0BD000030B5012389B00024054680683E
+:101C6000039103A9CDE90434CDE9064403685B6917
+:101C70009847A86822462146036800941D692346B8
+:101C8000A84709B030BD000010B5044623682046BF
+:101C9000DB6A98470028F9D110BD000010B590F814
+:101CA000743004465BB1FFF7EFFF012394F8741022
+:101CB000204684F88E30BDE81040FFF7CBBF0120EE
+:101CC00010BD000010B590F87430044653B1FFF712
+:101CD000DBFF01232046042184F88E30BDE810404C
+:101CE000FFF7B8BF012010BDF0B590F883708BB03E
+:101CF0000446042F50D100270DF10E0205218DF866
+:101D00000E708DF80F70FFF733FF00282FD00DF104
+:101D10000F0235212046FFF72BFF40B32046404EEF
+:101D2000FFF7BCFF2046FFF7AFFF05AD0FCE0FC595
+:101D3000336805A99DF80E202B609DF80F30A06830
+:101D400043F002038DF810208DF811308DF80F301C
+:101D500003685B699847A068022204A9036800979A
+:101D60001D693B46A84720B92046FFF7ABFF00207E
+:101D700010E02046FFF7A6FF0DF10F0235212046A7
+:101D8000FFF7F6FE0028F2D09DF80F309A07EED547
+:101D9000012363600BB0F0BD012F3ED1214E05AD94
+:101DA0000FCE0FC5336805A9A0682B6003685B6977
+:101DB0009847A06800220368114600971D6904AB8C
+:101DC000A8470028D3D02046FFF768FF2046FFF73A
+:101DD0005BFF9DF810203121204642F004028DF86F
+:101DE0001020FFF7FFFE0028BED02046FFF76AFF55
+:101DF000A06805A903685B699847A068002203688A
+:101E0000114600971D6904ABA8470028AFD09DF884
+:101E100010305B07ABD50223BBE70120BAE700BF58
+:101E2000E0620008F46200082DE9F3410023044653
+:101E30008068A36010B103685B6898470025264E50
+:101E4000264F0C2301A839465FFA85F86B439A594F
+:101E500000F086FA019BA0680022A360019210B1F5
+:101E600003685B689847019810B103685B689847FE
+:101E7000A368E3B141F2883084F88C8001F044FE1D
+:101E80002046FFF75DFC1E2001F03EFE2046FFF7D6
+:101E900085FC054688B994F88C300C2210485343D1
+:101EA000F158FFF7EBFA284602B0BDE8F0810135A2
+:101EB000032DC6D10B4800F06DFB2046FFF714FF41
+:101EC0000C2294F88C3005465343F15808B9064863
+:101ED000E7E70648E5E700BF38640008D82400209B
+:101EE000986300080E640008C2630008EC630008F1
+:101EF0002DE9F041044688B00F461646FFF7CEFEA6
+:101F00002046FFF7C1FE0025C722A06801230795E0
+:101F100003A9CDE90323CDE9055503685B6998471B
+:101F2000A0682A46294603680095D3F810802B46FE
+:101F3000C047054630B92046FFF7C4FE284608B022
+:101F4000BDE8F081E36E3B60236F3360F3E7000090
+:101F50002DE9F041002588B01F4604460E460E9B31
+:101F600000F1400CA8463D60016B81B1A9420ED33F
+:101F700091420CD8B6FBF1FE01FB1E6139B9416BF1
+:101F800090F82C800F9D1960816B296015461030E8
+:101F90006045E9D16DB3AB196269934229D82046F7
+:101FA000FFF77CFE2046FFF76FFE42F20113A068A8
+:101FB00003A9CDF80C80CDE904360026CDE90666EC
+:101FC00003685B699847A06832463146036800960B
+:101FD000D3F810803346C047064620462EB9FFF797
+:101FE00071FE304608B0BDE8F081FFF76BFE3D6042
+:101FF000F7E70026F5E700002DE9F0418669054680
+:1020000088B00F46B3429046B1FBF6FC06FB1C1CA1
+:1020100028BF3346A6EB0C0C00269C45644628BF1F
+:102020001C46FFF73BFE2846FFF72EFE0222A8685B
+:1020300003A9164B0597CDE90323CDE9066603688E
+:102040005B699847A86822464146036800961F6965
+:102050003346B847064628462EB9FFF733FE3046CA
+:1020600008B0BDE8F081FFF72DFE0E9B1C60AB6F42
+:10207000AA696343B3FBF2F30F9A1360EA6F109BF4
+:102080005443AA69B4FBF2F41C60E8E701210001A3
+:102090002DE9F04FCE18436989B004469E420F46A1
+:1020A00091463FD83D464FF00008DFF888A0FFF783
+:1020B000EBFDAE423AD994F88030A6EB050B0393C2
+:1020C00042F20103BBF5806F0493636828BF4FF4AD
+:1020D000806B012BCDE905581FD1CDF810A094F8E5
+:1020E000882003A994F88130012AA06808BF03F171
+:1020F000FF33079303685B699847A068A9EB070360
+:102100000268CDF800B02B44D2F810B0002211467E
+:10211000D84740B105F58065CBE7022B04BF044BDF
+:102120000493DCE7002009B0BDE8F08F0120FAE756
+:102130000124040401230303F0B5044689B00E46CC
+:10214000FFF7A2FD94F887502DB194F889302BB198
+:10215000012B28D00025284609B0F0BD94F8803026
+:102160000393F023069342F2010304936368012B67
+:1021700015D1214B04930023059394F88130A06876
+:1021800003A9079303685B699847A0683146036811
+:102190009B6998470546642001F0B6FCDBE7022BFB
+:1021A000E9D1164BE6E720460027FFF777FD2046EA
+:1021B000FFF76AFD08238122852120460097FFF75B
+:1021C0002FFD054618B92046FFF77CFDC3E794F8BC
+:1021D0008030069703930A4B04936368012B07D161
+:1021E000084B04930023059394F88130013BC6E724
+:1021F000022BF7D1044BF4E7012303030124040469
+:10220000012000800123038301240484014B024A3E
+:102210001A607047D82400206065000830B50A4471
+:10222000084D91420DD011F8013B5840082340F36E
+:102230000004013B2C4013F0FF0384EA5000F6D168
+:10224000EFE730BD2083B8ED704700007047000015
+:10225000002070470020704713B56C4600F114034E
+:1022600084E8060094E8030083E8050002B010BD8E
+:102270000020704713B56C4600F10C0384E806009B
+:1022800094E8030083E8050002B010BD0023C0E914
+:102290000333704782B002AB03E9060002B0704717
+:1022A0007047000000207047704700000020704712
+:1022B000002070470120704782B0002002A901E988
+:1022C0000C0002B0704700000020704700207047EB
+:1022D000036B1A79034B53F83230DB69186AC0F389
+:1022E00040107047F86400080B6883634B684363D1
+:1022F0008B68C363CB6803640B6943647047000059
+:1023000038B5036B0446154D1B7955F8330001F0C1
+:1023100075FAD4E90B231B7955F8331002F1300319
+:102320004968994218D000231363E26A5363D4E9E1
+:102330000B12537C581E137C92681B0443EA002343
+:1023400013438B63D4E90B131B79303155F83300F9
+:10235000BDE8384001F0E6B938BD00BFF8640008B8
+:10236000F8B51D4F05460E4611463868FFF7A8F828
+:1023700078BB74683B7924B394F82C209A420BD034
+:102380002468F8E70122B52100F00EF97368236094
+:102390003B79746084F82C30482003F013FF68B157
+:1023A00000220271C0E90322C0E90522027A42F04C
+:1023B00007020272094AC0E90B47026028602846FA
+:1023C000F8BD4C2003F0FEFE04460028DAD12C6054
+:1023D000F5E700232B60F2E7E02400200865000801
+:1023E000044B10B504460360406A08B103F0E8FEF0
+:1023F000204610BDAC64000810B50446FFF7F0FF9E
+:10240000204603F0DBFE204610BD000008B519B1E0
+:10241000FFF776FF012008BD036B1A79024B53F8D2
+:10242000320001F0EFF9F5E7F86400082DE9FF410B
+:10243000DDF828800546174603911FFA88F60293B7
+:10244000FFF75EFF02ABBAB203A9E86A009600F09C
+:10245000BFF8044638B900212846FFF7D7FF2046C9
+:1024600004B0BDE8F081AFB92B6B05F134011A79E6
+:10247000134B53F83200B8F1000F19D101F060F995
+:1024800080F00104E4B23346E86ADDE9022100F09D
+:10249000C5F8E0E7029B83B92B6B3A46084805F183
+:1024A00034011C79039B50F8340001F05FF9E7E731
+:1024B000029B424601F070F9E2E70024E3E700BF27
+:1024C000F864000813B504460191FFF719FF019A5B
+:1024D000236B04F134011879054B53F8300001F0F7
+:1024E00071F900212046FFF791FF012002B010BDD5
+:1024F000F864000810B50446FFF702FF236B1A7951
+:10250000054B53F8320001F06BF900212046FFF72C
+:102510007DFF012010BD00BFF8640008064B0121BB
+:10252000064A1A6000221A71054AC3E9021240F2F3
+:1025300015121A82704700BFE02400202A640008A8
+:1025400080A4BF0700B59BB0EFF3098168226846FD
+:10255000FEF798FFEFF30583014B9B6BFEE700BF8F
+:1025600000ED00E008B5FFF7EDFF000000B59BB0FF
+:10257000EFF3098168226846FEF784FFEFF30583D5
+:10258000014B5B6BFEE700BF00ED00E0FEE70000E3
+:10259000FEE700000FB408B5029801F041FAFEE72B
+:1025A00001F06EBF01F046BF38B5084B0446154632
+:1025B000017543600A21243002F002F804F128007A
+:1025C0002A460A2101F0FCFF204638BD7465000848
+:1025D000F8B51E461B6805460C4617461BB923680E
+:1025E00063B9012408E0BDF818203146806A01F083
+:1025F000FFFF0028F3D100242046F8BD21463A46CB
+:10260000686A02F02BF804460028EAD13368002BF0
+:10261000F1D0A86A02F056F8EEE7000038B50D4692
+:10262000114604461A4611B1806A02F009F82DB12C
+:102630002946606ABDE8384002F03CB838BD000069
+:10264000036800211B68184703790BB1002202714F
+:102650001846704703685B681847000003791BB988
+:10266000012303711846704700207047704700002F
+:1026700010B5044603F0A2FD204610BDCB0702D5DD
+:10268000014801F0CDB970478C65000810B50D4CBC
+:10269000204601F03FF84FF0A0420B4BC4E906235F
+:1026A00000232362094BD3F8D42042F40012C3F86C
+:1026B000D420D3F8FC2022F40012C3F8FC20D3F875
+:1026C000FC3010BDF8240020005000520044025895
+:1026D00010B503780446012B1AD1164B984217D136
+:1026E00002461549102002F007F9144B2062D3F876
+:1026F000D42042F48042C3F8D420D3F8FC2042F422
+:102700008042C3F8FC201622D3F8FC3003689A629A
+:102710006268E36991689960D16841F00101D9600C
+:102720001169526919615A61054A1A601B225A627D
+:1027300010BD00BFF82400207D2600080044025888
+:1027400005000200C36980691A6822F040521A60CD
+:1027500000221A640A690243C868C3F808210A689B
+:10276000C3F8002112F4E06FC3F820014868C3F8F1
+:10277000100101D08A689A647047000030B5046A7D
+:102780002468A361C369806903F15005E5610225EE
+:102790006261013A25614225E5601D6825F04055DA
+:1027A0001D601A640A690243C868C3F808210A68F0
+:1027B000C3F8002112F4E06FC3F820014868C3F8A1
+:1027C000100101D08A689A64E36843F00103E36072
+:1027D00030BD000070B5D0E907452D6804F1500602
+:1027E000AE61EB6108236A61013A2B614223EB6021
+:1027F000236823F0405343F0805323600B69226425
+:1028000082691343CA68C4F808310B68C4F8003100
+:1028100013F4E06FC4F820214A68C4F8102101D0F5
+:102820008B68A364EB6843F00103EB6070BD0000AC
+:1028300030B5C369104C85691C600C692C43C3F822
+:1028400008410C684968C3F80041C3F81011002121
+:10285000C3F820119964C3F88811C3F88011C3F834
+:102860009011C3F8A011054B984203D112B14FF05B
+:102870001043136030BD00BF01000030F824002079
+:10288000C3691A6842F002021A601A689207FCD4FF
+:10289000014A1A60704700BF05000200C3691B228D
+:1028A00010B55A62044643681B682BB105220270BA
+:1028B00098472378052B01D102232370302383F31B
+:1028C0001188002104F1080001F038F9002383F396
+:1028D0001188236A1A68D368DB07FCD410BD000096
+:1028E000026843681143016003B118477047000054
+:1028F000024A136843F0C0031360704700100140A0
+:1029000013B50E4C204600F091FA04F11400002398
+:102910004FF400720A49009400F04EF9094B4FF44D
+:102920000072094904F13800009400F0C7F9074A21
+:10293000074BC4E9172302B010BD00BF1C250020BF
+:1029400088250020F1280008882700200010014079
+:1029500080A4BF07037C30B5244C002918BF0C4667
+:10296000012B11D1224B98420ED1224BD3F8F020EB
+:1029700042F01002C3F8F020D3F8182142F0100200
+:10298000C3F81821D3F818312268036EC16D03EB28
+:1029900052038466B3FBF2F36268150442BF23F06E
+:1029A000070503F0070343EA4503CB60A36843F040
+:1029B00040034B60E36843F001038B6042F496737D
+:1029C00043F001030B604FF0FF330B62510505D557
+:1029D00012F0102205D0B2F1805F04D080F864308C
+:1029E00030BD7F23FAE73F23F8E700BF9C6500086E
+:1029F0001C250020004402582DE9F047C66D05460D
+:102A00003768F469210734621AD014F0080118BF3E
+:102A10004FF48071E20748BF41F02001A3074FF057
+:102A2000300348BF41F04001600748BF41F08001DA
+:102A300083F31188281DFFF753FF002383F31188C8
+:102A4000E2050AD5302383F311884FF48061281DF5
+:102A5000FFF746FF002383F311884FF030094FF052
+:102A6000000A14F0200838D13B0616D54FF0300983
+:102A700005F1380A200610D589F31188504600F078
+:102A800051F9002836DA0821281DFFF729FF27F021
+:102A900080033360002383F31188790614D562061E
+:102AA00012D5302383F31188D5E913239A4208D134
+:102AB0002B6C33B127F040071021281DFFF710FFC2
+:102AC0003760002383F31188E30618D5AA6E1369D3
+:102AD000ABB15069BDE8F047184789F31188736AB4
+:102AE000284695F86410194000F0BAF98AF3118865
+:102AF000F469B6E7B06288F31188F469BAE7BDE813
+:102B0000F0870000F8B51546826804460B46AA42D5
+:102B100000D28568A1692669761AB5420BD218469B
+:102B20002A46FEF7AFFCA3692B44A3612846A3689D
+:102B30005B1BA360F8BD0CD9AF1B18463246FEF7ED
+:102B4000A1FC3A46E1683044FEF79CFCE3683B4454
+:102B5000EBE718462A46FEF795FCE368E5E7000038
+:102B600083689342F7B50446154600D28568D4E9D8
+:102B70000460361AB5420BD22A46FEF783FC63691D
+:102B80002B4463612846A3685B1BA36003B0F0BDC0
+:102B90000DD93246AF1B0191FEF774FC01993A46FC
+:102BA000E0683144FEF76EFCE3683B44E9E72A46FF
+:102BB000FEF768FCE368E4E710B50A440024C3614B
+:102BC000029B8460C16002610362C0E90000C0E949
+:102BD000051110BD08B5D0E90532934201D18268D4
+:102BE00082B98268013282605A1C426119700021E8
+:102BF000D0E904329A4224BFC368436100F0B8FFB1
+:102C0000002008BD4FF0FF30FBE7000070B5302317
+:102C100004460E4683F31188A568A5B1A368A2698E
+:102C2000013BA360531CA36115782269934224BF22
+:102C3000E368A361E3690BB120469847002383F35F
+:102C40001188284607E03146204600F081FF002821
+:102C5000E2DA85F3118870BD2DE9F74F04460E4680
+:102C600017469846D0F81C904FF0300A8AF3118826
+:102C70004FF0000B154665B12A4631462046FFF756
+:102C800041FF034660B94146204600F061FF00283D
+:102C9000F1D0002383F31188781B03B0BDE8F08FD7
+:102CA000B9F1000F03D001902046C847019B8BF378
+:102CB0001188ED1A1E448AF31188DCE7C160C361F4
+:102CC000009B82600362C0E905111144C0E9000065
+:102CD00001617047F8B504460D461646302383F36C
+:102CE0001188A768A7B1A368013BA36063695A1C58
+:102CF00062611D70D4E904329A4224BFE3686361C3
+:102D0000E3690BB120469847002080F3118807E063
+:102D10003146204600F01CFF0028E2DA87F31188D4
+:102D2000F8BD0000D0E9052310B59A4201D18268B0
+:102D30007AB982680021013282605A1C82611C7853
+:102D400003699A4224BFC368836100F011FF2046E3
+:102D500010BD4FF0FF30FBE72DE9F74F04460E465C
+:102D600017469846D0F81C904FF0300A8AF3118825
+:102D70004FF0000B154665B12A4631462046FFF755
+:102D8000EFFE034660B94146204600F0E1FE002810
+:102D9000F1D0002383F31188781B03B0BDE8F08FD6
+:102DA000B9F1000F03D001902046C847019B8BF377
+:102DB0001188ED1A1E448AF31188DCE70268436823
+:102DC0001143016003B11847704700001430FFF74A
+:102DD00043BF00004FF0FF331430FFF73DBF00004A
+:102DE0003830FFF7B9BF00004FF0FF333830FFF73E
+:102DF000B3BF00001430FFF709BF00004FF0FF31F0
+:102E00001430FFF703BF00003830FFF763BF000046
+:102E10004FF0FF323830FFF75DBF0000012914BFCB
+:102E20006FF0130000207047FFF76ABD044B03608A
+:102E300000234360C0E9023301230374704700BFDD
+:102E4000B465000810B53023044683F31188FFF7FA
+:102E500081FD02230020237480F3118810BD00003F
+:102E600038B5C36904460D461BB904210844FFF771
+:102E7000A5FF294604F11400FFF7ACFE002806DA8E
+:102E8000201D4FF40061BDE83840FFF797BF38BD03
+:102E9000026843681143016003B11847704700009E
+:102EA00013B5406B00F58054D4F8A4381A68117833
+:102EB000042914D1017C022911D119790123128925
+:102EC0008B4013420BD101A94C3002F049FBD4F8DE
+:102ED000A4480246019B2179206800F0DFF902B086
+:102EE00010BD0000143002F0CBBA00004FF0FF33E9
+:102EF000143002F0C5BA00004C3002F09DBB000057
+:102F00004FF0FF334C3002F097BB0000143002F05A
+:102F100099BA00004FF0FF31143002F093BA00006C
+:102F20004C3002F069BB00004FF0FF324C3002F031
+:102F300063BB00000020704710B500F58054D4F842
+:102F4000A4381A681178042917D1017C022914D1F8
+:102F50005979012352898B4013420ED1143002F06B
+:102F60002BFA024648B1D4F8A4484FF44073617973
+:102F70002068BDE8104000F07FB910BD406BFFF73E
+:102F8000DBBF0000704700007FB5124B012504260F
+:102F9000044603600023057400F18402436029465F
+:102FA000C0E902330C4B0290143001934FF440738C
+:102FB000009602F0DDF9094B04F69442294604F12B
+:102FC0004C000294CDE900634FF4407302F0A4FA80
+:102FD00004B070BDDC6500087D2F0008A12E00083C
+:102FE0000A68302383F311880B790B3342F82300EE
+:102FF0004B79133342F823008B7913B10B3342F82A
+:10300000230000F58053C3F8A418022303740020A2
+:1030100080F311887047000038B5037F044613B170
+:1030200090F85430ABB90125201D0221FFF730FF85
+:1030300004F114006FF00101257700F0A5FD04F103
+:103040004C0084F854506FF00101BDE8384000F0A6
+:103050009BBD38BD10B5012104460430FFF718FFB1
+:103060000023237784F8543010BD000038B504469F
+:103070000025143002F094F904F14C00257702F099
+:1030800063FA201D84F854500121FFF701FF204608
+:10309000BDE83840FFF750BF90F8803003F0600380
+:1030A000202B06D190F881200023212A03D81F2A43
+:1030B00006D800207047222AFBD1C0E91D3303E067
+:1030C000034A426707228267C3670120704700BF37
+:1030D0004022002037B500F58055D5F8A4381A688D
+:1030E000117804291AD1017C022917D119790123F9
+:1030F00012898B40134211D100F14C04204602F09A
+:10310000E3FA58B101A9204602F02AFAD5F8A448FA
+:103110000246019B2179206800F0C0F803B030BD61
+:1031200001F10B03F0B550F8236085B004460D465D
+:10313000FEB1302383F3118804EB8507301D08218D
+:10314000FFF7A6FEFB6806F14C005B691B681BB12C
+:10315000019002F013FA019803A902F001FA024665
+:1031600048B1039B2946204600F098F8002383F3DA
+:10317000118805B0F0BDFB685A691268002AF5D0C5
+:103180001B8A013B1340F1D104F18002EAE7000001
+:10319000133138B550F82140ECB1302383F3118856
+:1031A00004F58053D3F8A4281368527903EB820303
+:1031B000DB689B695D6845B104216018FFF768FE14
+:1031C000294604F1140002F001F92046FFF7B4FE8D
+:1031D000002383F3118838BD7047000001F0F6BB6F
+:1031E00001234022002110B5044600F8303BFEF7D1
+:1031F0007BF90023C4E9013310BD000010B5302372
+:10320000044683F311882422416000210C30FEF72C
+:103210006BF9204601F0ECFB02230020237080F3C1
+:10322000118810BD70B500EB8103054650690E464C
+:103230001446DA6018B110220021FEF755F9A06992
+:1032400018B110220021FEF74FF931462846BDE89B
+:10325000704001F0B9BC000083682022002103F017
+:10326000011310B5044683601030FEF73DF9204687
+:10327000BDE8104001F034BDF0B4012500EB81043D
+:1032800047898D40E4683D43A4694581236000235C
+:10329000A2606360F0BC01F051BD0000F0B40125F4
+:1032A00000EB810407898D40E4683D436469058132
+:1032B00023600023A2606360F0BC01F0CBBD00007E
+:1032C00070B5022300250446242203702946C0F865
+:1032D00088500C3040F8045CFEF706F9204684F86C
+:1032E000705001F005FC63681B6823B12946204635
+:1032F000BDE87040184770BD0378052B10B5044633
+:103300000AD080F88C300523037043681B680BB12A
+:10331000042198470023A36010BD0000017805290F
+:1033200006D190F88C20436802701B6803B11847DF
+:103330007047000070B590F87030044613B1002358
+:1033400080F8703004F18002204601F0EDFC6368E3
+:103350009B68B3B994F8803013F0600535D0002134
+:10336000204601F0CBFF0021204601F0BBFF63683F
+:103370001B6813B1062120469847062384F8703055
+:1033800070BD204698470028E4D0B4F88630A26F7C
+:103390009A4288BFA36794F98030A56F002B4FF045
+:1033A000300380F20381002D00F0F280092284F8BE
+:1033B000702083F3118800212046D4E91D23FFF7F4
+:1033C0006DFF002383F31188DAE794F8812003F07E
+:1033D0007F0343EA022340F20232934200F0C580A9
+:1033E00021D8B3F5807F48D00DD8012B3FD0022BD8
+:1033F00000F09380002BB2D104F1880262670222B0
+:10340000A267E367C1E7B3F5817F00F09B80B3F566
+:10341000407FA4D194F88230012BA0D1B4F8883039
+:1034200043F0020332E0B3F5006F4DD017D8B3F587
+:10343000A06F31D0A3F5C063012B90D863682046FC
+:1034400094F882205E6894F88310B4F88430B04712
+:10345000002884D0436863670368A3671AE0B3F564
+:10346000106F36D040F6024293427FF478AF5C4B47
+:1034700063670223A3670023C3E794F88230012B1C
+:103480007FF46DAFB4F8883023F00203A4F88830DD
+:10349000C4E91D55E56778E7B4F88030B3F5A06F4F
+:1034A0000ED194F88230204684F88A3001F07EFBF9
+:1034B00063681B6813B101212046984703232370DA
+:1034C0000023C4E91D339CE704F18B0363670123E8
+:1034D000C3E72378042B10D1302383F311882046CF
+:1034E000FFF7BAFE85F311880321636884F88B50D7
+:1034F00021701B680BB12046984794F88230002B4E
+:10350000DED084F88B300423237063681B68002BA3
+:10351000D6D0022120469847D2E794F8843020463E
+:103520001D0603F00F010AD501F0F0FB012804D0BD
+:1035300002287FF414AF2B4B9AE72B4B98E701F04E
+:10354000D7FBF3E794F88230002B7FF408AF94F8B0
+:10355000843013F00F01B3D01A06204602D501F0D3
+:10356000E5FEADE701F0D6FEAAE794F88230002B25
+:103570007FF4F5AE94F8843013F00F01A0D01B0651
+:10358000204602D501F0BAFE9AE701F0ABFE97E7BC
+:10359000142284F8702083F311882B462A4629468A
+:1035A0002046FFF769FE85F31188E9E65DB1152233
+:1035B00084F8702083F3118800212046D4E91D236C
+:1035C000FFF75AFEFDE60B2284F8702083F3118882
+:1035D0002B462A4629462046FFF760FEE3E700BF58
+:1035E0000C660008046600080866000838B590F804
+:1035F00070300446002B3ED0063BDAB20F2A34D896
+:103600000F2B32D8DFE803F0373131082232313165
+:103610003131313131313737856FB0F886309D42E5
+:1036200014D2C3681B8AB5FBF3F203FB12556DB9C4
+:10363000302383F311882B462A462946FFF72EFEB6
+:1036400085F311880A2384F870300EE0142384F87F
+:103650007030302383F31188002320461A46194620
+:10366000FFF70AFE002383F3118838BDC36F03B14F
+:1036700098470023E7E70021204601F03FFE0021A4
+:10368000204601F02FFE63681B6813B10621204617
+:1036900098470623D7E7000010B590F8703004462D
+:1036A000142B29D017D8062B05D001D81BB110BD7B
+:1036B000093B022BFBD80021204601F01FFE002110
+:1036C000204601F00FFE63681B6813B106212046F7
+:1036D0009847062319E0152BE9D10B2380F87030A9
+:1036E000302383F3118800231A461946FFF7D6FDCD
+:1036F000002383F31188DAE7C3689B695B68002BBA
+:10370000D5D1C36F03B19847002384F87030CEE75A
+:10371000FEF7BCBF012100230170C0E901330C306A
+:1037200000F028B910B53023044683F311884160B6
+:10373000FEF7CEFF02230020237080F3118810BD16
+:1037400010B53023044683F31188032304F8083BA3
+:10375000FEF7F8FF4FF0FF31204600F0E1F90023BB
+:1037600083F31188C01A18BF012010BD38B5044674
+:10377000302585F31188032504F8085BFEF7FEFF6A
+:103780004FF0FF31204600F0CBF9002383F311887E
+:10379000C01A18BF012038BD38B50446302585F35E
+:1037A0001188042504F8085BFFF714F84FF0FF3187
+:1037B000204600F0B5F9002383F31188C01A18BF22
+:1037C000012038BD10B53023044683F31188FFF77C
+:1037D0002FF806232370002383F3118810BD000007
+:1037E00010B53023044683F31188FFF749F802230C
+:1037F0002370002383F3118810BD00000C3000F00B
+:10380000D5B800000C3000F0DBB80000002382685F
+:10381000037503691B6899689142FBD25A6803607B
+:103820004260106058607047002382680375036926
+:103830001B6899689142FBD85A6803604260106027
+:103840005860704708B50846302383F311880A7D15
+:103850000023052A06D8DFE802F00B050503120E47
+:10386000826913604FF0FF338361FFF7CFFF0023BE
+:1038700083F3118808BD8269936801339360D0E9AE
+:10388000003213605A60EDE7FFF7C0BF054BD968FF
+:1038900008751868026853601A600122D8600275C2
+:1038A000FCF73ABF882900200C4B30B5DD684B1C73
+:1038B00087B004460FD02B46094A684600F0F8F955
+:1038C0002046FFF7E3FF009B13B1684600F0FAF9CA
+:1038D000A86907B030BDFFF7D9FFF9E788290020B4
+:1038E0004538000838B50C4D04468161EB688168A5
+:1038F0009A68914203D8BDE83840FFF787BF184661
+:10390000FFF792FF01230146EC6020462375BDE8D6
+:103910003840FCF701BF00BF88290020044B1A681B
+:10392000DB6890689B68984294BF00200120704734
+:1039300088290020084B10B51C68D868226853609D
+:103940001A600122DC602275FFF76EFF01462046F7
+:10395000BDE81040FCF7E0BE88290020044B1A683F
+:10396000DB6892689B689A4201D9FFF7E3BF704712
+:1039700088290020C0E90000816070478368013B0E
+:10398000002B10B583600CDA074BDC684368A0613C
+:10399000206063601C6044600520FFF777FFA0692A
+:1039A00010BD0020FCE700BF8829002008B53023A7
+:1039B00083F31188FFF7E2FF002383F3118808BD2A
+:1039C00008B5302383F3118883680133002B8360AB
+:1039D00007DC036800211A68026050601846FFF790
+:1039E00081FF002383F3118808BD000038B501234F
+:1039F000084C00252370656001F0A2FE01F0C8FEAE
+:103A00000549064801F09CFF0223237085F31188C5
+:103A100038BD00BFF02B0020146600088829002064
+:103A200008B572B6044B186500F0F6FC00F0C6FD50
+:103A3000024B03221A70FEE788290020F02B002099
+:103A400000F076B9EFF3118020B9EFF3058330224F
+:103A500082F311887047000010B530B9EFF3058488
+:103A6000C4F3080414B180F3118810BDFFF776FF8A
+:103A700084F31188F9E70000034A516853685B1A20
+:103A80009842FBD8704700BF001000E08B60022313
+:103A9000086108468B8270478368A3F1840243F86B
+:103AA000142C026943F8442C426943F8402C094A1B
+:103AB00043F8242CC268A3F1200043F8182C0222FA
+:103AC00003F80C2C002203F80B2C034A43F8102CAB
+:103AD000704700BF310700088829002008B5FFF7AC
+:103AE000DBFFBDE80840FFF7CFBE0000024BDB68FC
+:103AF00098610F20FFF7CABE88290020302383F386
+:103B00001188FFF7F3BF000008B50146302383F3A7
+:103B100011880820FFF7C8FE002383F3118808BD31
+:103B2000054BDB6821B1036098610320FFF7BCBE41
+:103B30004FF0FF30704700BF8829002003682BB189
+:103B40000022026018469961FFF79EBE7047000090
+:103B5000064BDB6839B1426818605A6013604360F5
+:103B60000420FFF7A1BE4FF0FF30704788290020E6
+:103B70000368984206D01A6802605060184699613E
+:103B8000FFF782BE7047000038B504460D46206836
+:103B9000844200D138BD036823605C608561FFF713
+:103BA00073FEF4E7036810B59C68A2420CD85C6809
+:103BB0008A600B604C602160596099688A1A9A602B
+:103BC0004FF0FF33836010BD121B1B68ECE7000051
+:103BD0000A2938BF0A2170B504460D460A26601925
+:103BE00001F0A8FD01F090FD041BA54203D8751C4F
+:103BF00004462E46F3E70A2E04D90120BDE87040A2
+:103C000001F0DEBE70BD0000F8B5144B0D460A2A67
+:103C10004FF00A07D96103F11001826038BF0A2210
+:103C2000416019691446016048601861A81801F0E4
+:103C300071FD01F069FD431B0646A34206D37C1CBF
+:103C400028192746354601F075FDF2E70A2F04D9F9
+:103C50000120BDE8F84001F0B3BEF8BD882900207E
+:103C6000F8B506460D4601F04FFD0F4A134653F8CE
+:103C7000107F9F4206D12A4601463046BDE8F840F3
+:103C8000FFF7C2BFD169BB68441A2C1928BF2C4664
+:103C9000A34202D92946FFF79BFF2246314603483B
+:103CA000BDE8F840FFF77EBF882900209829002052
+:103CB000C0E90323002310B45DF8044B4361FFF710
+:103CC000CFBF000010B5194C236998420DD0816810
+:103CD000D0E9003213605A609A680A449A6000235F
+:103CE00003604FF0FF33A36110BD0268234643F821
+:103CF000102F53600022026022699A4203D1BDE86E
+:103D0000104001F011BD936881680B44936001F08D
+:103D1000FBFC2269E1699268441AA242E4D9114489
+:103D2000BDE81040091AFFF753BF00BF88290020E3
+:103D30002DE9F047DFF8BC8008F110072C4ED8F8C9
+:103D4000105001F0E1FCD8F81C40AA68031B9A420D
+:103D50003ED814444FF00009D5E90032C8F81C40A1
+:103D600013605A60C5F80090D8F81030B34201D102
+:103D700001F0DAFC89F31188D5E903312846984728
+:103D8000302383F311886B69002BD8D001F0BCFC81
+:103D90006A69A0EB040982464A450DD2022001F06F
+:103DA0000FFE0022D8F81030B34208D15146284601
+:103DB000BDE8F047FFF728BF121A2244F2E712EBE2
+:103DC00009092946384638BF4A46FFF7EBFEB5E7F2
+:103DD000D8F81030B34208D01444C8F81C00211A97
+:103DE000A960BDE8F047FFF7F3BEBDE8F08700BF6C
+:103DF000982900208829002000207047FEE7000055
+:103E0000704700004FF0FF307047000002290CD0CF
+:103E1000032904D00129074818BF00207047032A4E
+:103E200005D8054800EBC2007047044870470020E1
+:103E3000704700BFEC66000850220020A066000812
+:103E400070B59AB005460846144601A900F0C2F8BC
+:103E500001A8FDF741FB431C0022C6B25B001046DF
+:103E6000C5E9003423700323023404F8013C01AB9C
+:103E7000D1B202348E4201D81AB070BD13F8011BC2
+:103E8000013204F8010C04F8021CF1E708B53023F4
+:103E900083F311880348FFF71DF9002383F311888A
+:103EA00008BD00BFF82B002090F8803003F01F02FF
+:103EB000012A07D190F881200B2A03D10023C0E901
+:103EC0001D3315E003F06003202B08D1B0F88430D7
+:103ED0002BB990F88120212A03D81F2A04D8FFF794
+:103EE000DBB8222AEBD0FAE7034A4267072282674F
+:103EF000C3670120704700BF4722002007B505298E
+:103F000017D8DFE801F0191603191920302383F3BD
+:103F10001188104A01210190FFF784F901980221CC
+:103F20000D4AFFF77FF90D48FFF7A0F8002383F350
+:103F3000118803B05DF804FB302383F31188074830
+:103F4000FFF76AF8F2E7302383F311880348FFF79D
+:103F500081F8EBE74066000864660008F82B002053
+:103F600038B50C4D0C4C2A460C4904F10800FFF7FB
+:103F700067FF05F1CA0204F110000949FFF760FF6D
+:103F800005F5CA7204F118000649BDE83840FFF78C
+:103F900057BF00BFD04400205022002020660008F8
+:103FA0002A6600083566000870B5044608460D46C6
+:103FB000FDF792FAC6B22046013403780BB91846D1
+:103FC00070BD32462946FDF767FA0028F3D101207B
+:103FD000F6E700002DE9F84F05460C46FDF77CFAA0
+:103FE0002C49C6B22846FFF7DFFF08B10536F6B206
+:103FF00029492846FFF7D8FF08B11036F6B2632EDC
+:104000000DD8DFF89080DFF89090244FDFF894A06F
+:10401000DFF894B02E7846B92670BDE8F88F2946AF
+:104020002046BDE8F84F02F051B9252E2ED10722C7
+:1040300041462846FDF730FA70B9DBF80030073505
+:104040000C3444F80C3CDBF8043044F8083CDBF852
+:10405000083044F8043CDDE7082249462846FDF7CD
+:104060001BFA98B9A21C0E4B197802320909C95DD6
+:1040700002F8041C13F8011B01F00F015345C95D40
+:1040800002F8031CF0D118340835C3E7013504F8F1
+:10409000016BBFE70C670008356600082167000860
+:1040A00000E8F11F0CE8F11F14670008BFF34F8F01
+:1040B000024A13695B07FCD1704700BF0020005221
+:1040C00008B5074B1B7853B9FFF7F0FF054BDA68CB
+:1040D000D20704D5044A5A6002F188325A6008BDFA
+:1040E0002E47002000200052230167454FF0006357
+:1040F000054A1968013104D104339342F9D10120F2
+:1041000070470020704700BF0000020808B5094B47
+:104110001B786BB908490B695B0703D5CB6843F083
+:104120004003CB60FFF7C2FFCB6843F00103CB60D5
+:1041300008BD00BF2E470020002000524FF4003081
+:10414000704700000120704708B9FFF7CFBF00207B
+:104150007047000010B538BBFFF774FC1349FFF738
+:10416000A5FF0446FFF7ACFF4FF0FF334B610B6137
+:10417000FFF79CFF2423CB60CB6843F08003CB6028
+:104180000B695B07FCD44FF400314FF00060FFF780
+:104190008DFF00F0EFF92046FFF7B8FFFFF75CFC5A
+:1041A000BDE81040FFF7A2BF002010BD0020005264
+:1041B0002DE9F84340EA020305460C461146D806AD
+:1041C00002D00020BDE8F88321F01F01DFF8A080B5
+:1041D0004FF0FF39FFF774FF6718BC4203D101208D
+:1041E000FFF794FFEEE720222946204602F01AF856
+:1041F00010B920352034F0E72B4605F120021E6867
+:10420000711CDED104339342F9D1FFF71BFC291B4B
+:10421000FFF74CFFC8F81460D8F80C3004F11C020A
+:1042200043F00203C8F80C30231FD8F8106016F0D2
+:104230000506FAD153F804CF9A4241F803C0F4D1ED
+:10424000BFF34F8FFFF732FFC8F81490D8F80C3047
+:1042500023F00203C8F80C30FFF7FEFB20222146B2
+:10426000284601F0DFFF0028C3D03046B8E700BF82
+:1042700000200052084908B50B7828B11BB9FFF798
+:104280001FFF01230B7008BD002BFCD00870BDE898
+:104290000840FFF73BBF00BF2E4700202DE9F74F36
+:1042A0000E460546002864D011F0050763D139B9E0
+:1042B00008222946304601F08DFA0446002848D1EC
+:1042C00008224FF00109DFF8C08006F00403DFF890
+:1042D000BCA006EA090BBBF1000F27D0D8F81410D8
+:1042E000C80723D409F1010908F10C08B9F1060F38
+:1042F000F1D18FB9224E2946F019009201F06AFAE5
+:10430000044630BB1837009A782FF4D1294601F0C3
+:1043100061FA0446E8B9009A29461A4801F05AFAA7
+:10432000044608BB204603B0BDE8F08FABB1D8F817
+:10433000141011F0040FD5D01820294600FB09A055
+:10434000CDE9002301F046FA0446DDE90023002808
+:10435000C8D02A460021204608E0B107ECD5D8F89D
+:10436000141011F0020FE6E72A460021FDF7BCF811
+:10437000D8E70446D6E71F35202225F01F05A0E721
+:10438000604700203047002034670008484700207D
+:104390000021FFF783BF00000121FFF77FBF00006E
+:1043A000F8B5144D01241827134E40F2FF320021B6
+:1043B0000120FDF799F807FB046001342A6955F8DC
+:1043C0000C1F01F0F3F9062CF5D137254FF4C0543A
+:1043D0002046FFF7E1FF014628B122460748BDE825
+:1043E000F84001F0E3B9C4EBC404013D4FEAD40442
+:1043F000EED1F8BD34670008484700203047002060
+:104400000421FFF74BBF00004843FFF7C1BF000086
+:1044100008B101F051BA704738B5054D0024033496
+:10442000696855F80C0B00F0B7F8122CF7D138BDBD
+:104430003467000870B5104E82B0FFF703FB0546E5
+:1044400001F062F9326803469042336037BF0B4A8D
+:104450000A495168146836BF0131D1E90041516001
+:104460000419284641F100010191FFF7F5FA2046B1
+:10447000019902B070BD00BFD8470020E04700207E
+:1044800070B5124E82B0FFF7DDFA054601F03CF937
+:10449000326803469042336037BF0D4A0C49516879
+:1044A000146836BF0131D1E9004151600419284632
+:1044B00041F100010191FFF7CFFA4FF47A72002326
+:1044C00020460199FBF714FF02B070BDD8470020C9
+:1044D000E04700200244074BD2B210B5904200D111
+:1044E00010BD441C00B253F8200041F8040BE0B2A8
+:1044F000F4E700BF504000580F4B30B51C6F240448
+:1045000007D41C6F44F400741C671C6F44F400440F
+:104510001C670A4C02442368D2B243F480732360C0
+:10452000074B904200D130BD441C51F8045B00B2EF
+:1045300043F82050E0B2F4E7004402580048025823
+:104540005040005807B5012201A90020FFF7C2FF23
+:10455000019803B05DF804FB13B50446FFF7F2FFC2
+:10456000A04205D0012201A900200194FFF7C4FF59
+:1045700002B010BD0144BFF34F8F064B884204D3F5
+:10458000BFF34F8FBFF36F8F7047C3F85C022030CB
+:10459000F4E700BF00ED00E00144BFF34F8F064B8E
+:1045A000884204D3BFF34F8FBFF36F8F7047C3F8B8
+:1045B00070022030F4E700BF00ED00E0704700001B
+:1045C00070B5054616460C4601201021FFF71CFF6A
+:1045D000286046733CB1204636B1FFF711FF2B68C7
+:1045E000186000B19C6070BDFFF7D6FEF7E70000D1
+:1045F00070B50E461546044600B30B6843608368E9
+:10460000934210D213B10068FFF702FF637B284684
+:104610002BB1FFF7F5FE206020B9A06070BDFFF759
+:10462000BBFEF8E7A560206805F11F01306021F0AE
+:104630001F01FFF79FFF01202073EFE70120EDE747
+:1046400010B5044640B10068884205D1606808B1E1
+:10465000FCF718FF0023237310BD000070B50E4651
+:104660001546044620B383689A4210D913B10068F6
+:10467000FFF7CEFE637B28462BB1FFF7C1FE20601B
+:1046800020B9A06070BDFFF787FEF8E7A56031682C
+:1046900019B12A462068FCF7F5FE206805F11F01D4
+:1046A000306021F01F01FFF777FF01202073E9E759
+:1046B0000120E7E720B103688B4204BF00230373A6
+:1046C0007047000008B1002303737047034B1A685A
+:1046D0001AB9034AD2F8D0241A607047E84700207C
+:1046E0000040025808B5FFF7F1FF024B1868C0F30D
+:1046F000806008BDE847002070B5BFF34F8FBFF35F
+:104700006F8F1A4A0021C2F85012BFF34F8FBFF3C8
+:104710006F8F536943F400335361BFF34F8FBFF37F
+:104720006F8FC2F88410BFF34F8FD2F8803043F6FA
+:10473000E074C3F3C900C3F34E335B0103EA04061C
+:10474000014646EA81750139C2F86052F9D2203B30
+:1047500013F1200FF2D1BFF34F8F536943F480332D
+:104760005361BFF34F8FBFF36F8F70BD00ED00E05B
+:10477000FEE7000008B50E480E4B0F4A904212D3D8
+:104780000E4BC11EDA1C121A22F003028B4238BFF4
+:1047900000220021FCF7A8FEBFF34F8FBFF34F8F1D
+:1047A000BFF36F8F08BD53F8041B40F8041BE5E707
+:1047B0000C4A0020EC6900080C4A00200C4A00203A
+:1047C00003681A6899685A6043681BB142EA01415C
+:1047D00080681847704700004FF0A44310B51C686C
+:1047E000E00702D52848FFF7EBFFA10702D52748CD
+:1047F000FFF7E6FF620702D52548FFF7E1FF230731
+:1048000002D52448FFF7DCFFE00602D52248FFF777
+:10481000D7FFA10602D52148FFF7D2FF620602D5D5
+:104820001F48FFF7CDFF230602D51E48FFF7C8FF3C
+:10483000E00502D51C48FFF7C3FFA10502D51B48C0
+:10484000FFF7BEFF620502D51948FFF7B9FF230540
+:1048500002D51848FFF7B4FFE00402D51648FFF769
+:10486000AFFFA10402D51548FFF7AAFF620402D5E5
+:104870001348FFF7A5FF230402D51248FFF7A0FF56
+:10488000BDE8104001F092B9F0470020FC4700203D
+:104890000848002014480020204800202C48002010
+:1048A0003848002044480020504800205C48002040
+:1048B0006848002074480020804800208C48002070
+:1048C00098480020A448002030B5094B0021094C2D
+:1048D00010200725196054F8042B0138C3E9012181
+:1048E000D16003F10C0311615560F4D130BD00BFFC
+:1048F000EC4700207C6700080F28F0B50AD9102883
+:1049000006D10F230020144C01272568984203D9B3
+:1049100000201DE00346F6E707FA00F6354218D1FD
+:104920000C23354343432560181D2344C3E9021279
+:104930000A4B2044D3F8D42042F00102C3F8D4201B
+:10494000D3F8FC2042F00102C3F8FC20D3F8FC307D
+:10495000F0BD0130DAE700BFEC4700200044025808
+:1049600070B5D0E9244300224FF0FF359E6804EB78
+:1049700042135101D3F80009002805DAD3F80009E1
+:1049800040F08040C3F80009D3F8000B002805DA96
+:10499000D3F8000B40F08040C3F8000B01326318DD
+:1049A0009642C3F80859C3F8085BE0D24FF00113F0
+:1049B000C4F81C3870BD0000890141F0200101617C
+:1049C00003699B06FCD41220FFF756B810B5054CBE
+:1049D0002046FEF705FC044BC4F89030034BC4F8A6
+:1049E000943010BDB048002000000440E06700088B
+:1049F00070B503780546012B6AD1374BD0F890404B
+:104A0000984233D1354B0E214D20D3F8D82042F0B7
+:104A10000072C3F8D820D3F8002142F00072C3F826
+:104A20000021D3F80021D3F8802042F00072C3F8AF
+:104A30008020D3F8802022F00072C3F88020D3F8C1
+:104A40008020D3F8D82022F08062C3F8D820D3F891
+:104A5000002122F08062C3F80021D3F8003100F079
+:104A600071FC1F4BE3601F4BC4F800380023D5F8DE
+:104A70009060C4F8003EC02323604FF40413A36386
+:104A80003369002BFCDA01230C203361FEF7F4FFBD
+:104A90003369DB07FCD41220FEF7EEFF3369002BED
+:104AA000FCDA00262846A660FFF75AFF6B68C4F8B8
+:104AB0001068DB68C4F81468C4F81C684BB90A4B6A
+:104AC000A3614FF0FF336361A36843F00103A36068
+:104AD00070BD064BF4E700BFB04800200044025808
+:104AE0004014004003002002003C30C0083C30C0AD
+:104AF000F8B5D0F89040054600214FF000662046FA
+:104B0000FFF75AFFD5F8941000234FF001128F6879
+:104B10004FF0FF30C4F83438C4F81C2804EB4312BB
+:104B200001339F42C2F80069C2F8006BC2F808095D
+:104B3000C2F8080BF2D20B68D5F89020C5F898306F
+:104B4000636210231361166916F01006FBD1122060
+:104B5000FEF792FFD4F8003823F4FE63C4F800385F
+:104B6000A36943F4402343F01003A3610923C4F86D
+:104B70001038C4F814380B4BEB604FF0C043C4F846
+:104B8000103B094BC4F8003BC4F81069C4F8003965
+:104B9000D5F8983003F1100243F48013C5F898203B
+:104BA000A362F8BDBC67000840800010D0F89020D8
+:104BB00090F88A10D2F8003823F4FE6343EA011318
+:104BC000C2F80038704700002DE9F84300EB81037C
+:104BD000D0F890500C468046DA680FFA81F9480107
+:104BE000166806F00306731E022B05EB41134FF007
+:104BF000000194BFB604384EC3F8101B4FF00101FA
+:104C000004F1100398BF06F1805601FA03F391698D
+:104C100098BF06F5004600293AD0578A04F158019A
+:104C2000374349016F50D5F81C180B430021C5F8D4
+:104C30001C382B180127C3F81019A7405369611EAF
+:104C40009BB3138A928B9B08012A88BF5343D8F8E1
+:104C50009820981842EA034301F140022146C8F81F
+:104C60009800284605EB82025360FFF7A5FE08EB8B
+:104C70008900C3681B8A43EA845348341E43640195
+:104C80002E51D5F81C381F43C5F81C78BDE8F883B1
+:104C900005EB4917D7F8001B21F40041C7F8001BAA
+:104CA000D5F81C1821EA0303C0E704F13F030B4ABF
+:104CB0002846214605EB83035A60FFF77DFE05EB8E
+:104CC0004910D0F8003923F40043C0F80039D5F872
+:104CD0001C3823EA0707D7E7008000100004000211
+:104CE000D0F894201268C0F89820FFF739BE000071
+:104CF0005831D0F8903049015B5813F4004004D08B
+:104D000013F4001F0CBF0220012070474831D0F877
+:104D1000903049015B5813F4004004D013F4001F95
+:104D20000CBF02200120704700EB8101CB68196A9B
+:104D30000B6813604B6853607047000000EB810301
+:104D400030B5DD68AA691368D36019B9402B84BFF8
+:104D5000402313606B8A1468D0F890201C4402EB47
+:104D60004110013C09B2B4FBF3F46343033323F075
+:104D7000030343EAC44343F0C043C0F8103B2B682D
+:104D800003F00303012B0ED1D2F8083802EB4110D7
+:104D900013F4807FD0F8003B14BF43F0805343F0FE
+:104DA0000053C0F8003B02EB4112D2F8003B43F045
+:104DB0000443C2F8003B30BD2DE9F041244D0446C8
+:104DC000D5F8906006EB4013D3F8087B3807C3F89A
+:104DD000087B0AD5D6F81438190706D505EB8403E5
+:104DE00021462846DB685B689847FA071FD5D6F846
+:104DF0001438DB071BD505EB8403D968CCB98B6964
+:104E0000488A5A68B2FBF0F600FB16228AB9186885
+:104E1000DA6890420DD2121AC3E90024302383F3DA
+:104E200011880B482146FFF789FF84F31188BDE8FC
+:104E3000F081012303FA04F26B8923EA02036B81F8
+:104E4000CB68002BF3D021460148BDE8F04118475C
+:104E5000B048002000EB81034A0170B5DD68D0F84E
+:104E600090306C692668E66056BB1A444FF4002007
+:104E7000C2F810092A6802F00302012A0AB20ED110
+:104E8000D3F8080803EB421410F4807FD4F800092B
+:104E900014BF40F0805040F00050C4F8000903EB0C
+:104EA0004212D2F8000940F00440C2F80009012281
+:104EB000D3F8340802FA01F10143C3F8341870BD85
+:104EC00019B9402E84BF4020206020681A442E8AE1
+:104ED0008419013CB4FBF6F440EAC44040F00050B1
+:104EE000C6E700002DE9F8433C4D04464701D5F8DC
+:104EF000906006EB4013D3F8088918F0010FC3F84F
+:104F000008891AD0D6F81038DB0716D505EB8003D0
+:104F1000D9684B691868DA68904231D2121A4FF09A
+:104F200000091A60C3F80490302383F311882146E6
+:104F30002846FFF78FFF89F3118818F0800F1DD0E6
+:104F4000D6F834380126A640334217D005EB840347
+:104F50000134D5F89050D3F80CC0E4B22F44DCF8FB
+:104F6000142005EB0434D2F800E05168714515D3E4
+:104F7000D5F8343823EA0606C5F83468BDE8F88366
+:104F8000012303FA04F22B8923EA02032B818B68A5
+:104F9000002BD2D0214628469847CEE7AEEB01033E
+:104FA000BCF81000834228BF0346D7F8180980B226
+:104FB000B3EB800FE2D89068A0F1040959F8048F90
+:104FC000C4F80080A0EB09089844B8F1040FF5D8A4
+:104FD00018440B4490605360C7E700BFB0480020FE
+:104FE0002DE9F74FA94CD4F890506E69AB691E407B
+:104FF00016F480586E6107D02046FEF761F903B0C1
+:10500000BDE8F04F00F0D2BD002E12DAD5F8003E18
+:105010009B0705D0D5F8003E23F00303C5F8003EFA
+:10502000D5F80438994823F00103C5F80438FEF791
+:1050300075F9370505D59548FFF792FC9348FEF7BB
+:105040005BF9B0040CD5D5F8083813F0060FEB68FF
+:1050500023F470530CBF43F4105343F4A053EB609C
+:1050600031071BD56368DB681BB9AB6923F0080304
+:10507000AB612378052B0CD1D5F8003E9A0705D0FB
+:10508000D5F8003E23F00303C5F8003E7F48FEF745
+:1050900045F96368DB680BB17C489847F30200F17F
+:1050A000AA80B70228D5D4F8909000274FF0010AC3
+:1050B000DFF8D8B109EB4712D2F8003B03F44023E4
+:1050C000B3F5802F11D1D2F8003B002B0DDA6289A5
+:1050D0000AFA07F322EA0303638104EB8703DB6820
+:1050E000DB6813B13946584698470137D4F89430F5
+:1050F000FFB29B689F42DDD9F00619D5D4F89070B5
+:105100003A6AC2F30A1002F00F0302F4F012B2F589
+:10511000802F00F0BD80B2F5402F09D104EB83034E
+:10512000002207F58057DB681B6A904240F0A080A0
+:105130003303D5F818482CD5E70302D50020FFF734
+:105140003BFEA50302D50120FFF736FE600302D522
+:105150000220FFF731FE210302D50320FFF72CFECA
+:10516000E20202D50420FFF727FEA30202D50520A4
+:10517000FFF722FE670202D50620FFF71DFE25027B
+:1051800002D50720FFF718FEE00102D50820FFF73F
+:1051900013FE71037FF533AFE20702D50020FFF75E
+:1051A000A1FEA30702D50120FFF79CFE670702D5E9
+:1051B0000220FFF797FE260702D50320FFF792FE95
+:1051C000E50602D50420FFF78DFEA00602D50520D6
+:1051D000FFF788FE610602D50620FFF783FE220650
+:1051E00002D50720FFF77EFEE3057FF508AF082014
+:1051F000FFF778FE03E7D4F8903000274FF001095D
+:10520000DFF888A00193D4F894305FFA87FB9B689D
+:105210009B453FF646AF019B03EB4B13D3F80019B8
+:1052200001F44021B1F5802F20D1D3F800190029D5
+:105230001CDAD3F8001941F09041C3F80019D3F8F3
+:1052400000190029FBDB5946D4F89000FFF7B4FBA6
+:10525000218909FA0BF321EA0303238104EB8B0371
+:10526000DB689B6813B15946504698470137CAE737
+:10527000910701D1D7F80080072A02F101029CBFF3
+:1052800003F8018B4FEA18284FE700BFB048002011
+:10529000023307F5805704EB83025268D2F818C036
+:1052A000DCF80820DCE9001CA1EB0C0C0021884292
+:1052B0000AD104EB830463689B699A6802449A608C
+:1052C0005A6802445A6033E711F0030F01D1D7F84E
+:1052D00000808C4501F1010184BF02F8018B4FEA87
+:1052E0001828E4E7D0F8903003EB4111D1F8003BE7
+:1052F00043F40013C1F8003B70470000D0F8903031
+:1053000003EB4111D1F8003943F40013C1F800391F
+:1053100070470000D0F8903003EB4111D1F8003B0A
+:1053200023F40013C1F8003B70470000D0F8903020
+:1053300003EB4111D1F8003923F40013C1F800390F
+:1053400070470000090100F16043012203F5614349
+:10535000C9B283F8001300F01F039A4043099B0071
+:1053600003F1604303F56143C3F880211A6070477D
+:1053700030B50433039C0172002104FB0325C16096
+:10538000C0E90653049B0363059BC0E90000C0E924
+:105390000422C0E90842C0E90A11436330BD00009D
+:1053A0000022416AC260C0E90411C0E90A226FF01C
+:1053B0000101FEF7E9BB0000D0E90432934201D1BC
+:1053C000C2680AB9181D7047002070470369196048
+:1053D0000021C2680132C260C269134482699342EB
+:1053E000036124BF436A0361FEF7C2BB38B50446BC
+:1053F0000D46E3683BB162690020131D1268A36289
+:105400001344E36207E0237A33B929462046FEF7C6
+:105410009FFB0028EDDA38BD6FF00100FBE70000CC
+:10542000C368C269013BC360436913448269934204
+:10543000436124BF436A436100238362036B03B16A
+:105440001847704770B53023044683F31188866A85
+:105450003EB9FFF7CBFF054618B186F31188284601
+:1054600070BDA36AE26A13F8015B9342A36202D3A0
+:105470002046FFF7D5FF002383F31188EFE70000F4
+:105480002DE9F84F04460E46174698464FF030096E
+:1054900089F311880025AA46D4F828B0BBF1000F83
+:1054A00009D141462046FFF7A1FF20B18BF31188B7
+:1054B0002846BDE8F88FD4E90A12A7EB050B521A6B
+:1054C000934528BF9346BBF1400F1BD9334601F1EA
+:1054D000400251F8040B914243F8040BF9D1A36A3E
+:1054E000403640354033A362D4E90A239A4202D3BE
+:1054F0002046FFF795FF8AF31188BD42D8D289F381
+:105500001188C9E730465A46FBF7BCFFA36A5E44E0
+:105510005D445B44A362E7E710B5029C043301726B
+:1055200003FB0421C460C0E906130023C0E90A3369
+:10553000039B0363049BC0E90000C0E90422C0E9A7
+:105540000842436310BD0000026A6FF00101C260AF
+:10555000426AC0E904220022C0E90A22FEF714BB15
+:10556000D0E904239A4201D1C26822B9184650F802
+:10557000043B0B60704700231846FAE7C36800211C
+:10558000C2690133C3604369134482699342436132
+:1055900024BF436A4361FEF7EBBA000038B5044606
+:1055A0000D46E3683BB1236900201A1DA262E2693F
+:1055B0001344E36207E0237A33B929462046FEF715
+:1055C000C7FA0028EDDA38BD6FF00100FBE70000F4
+:1055D00003691960C268013AC260C26913448269F2
+:1055E0009342036124BF436A036100238362036B18
+:1055F00003B118477047000070B530230D460446CC
+:10560000114683F31188866A2EB9FFF7C7FF10B1E0
+:1056100086F3118870BDA36A1D70A36AE26A013324
+:105620009342A36204D3E16920460439FFF7D0FF17
+:10563000002080F31188EDE72DE9F84F04460D4670
+:10564000904699464FF0300A8AF311880026B346F7
+:10565000A76A4FB949462046FFF7A0FF20B187F35C
+:1056600011883046BDE8F88FD4E90A073A1AA8EB4A
+:105670000607974228BF1746402F1BD905F1400364
+:1056800055F8042B9D4240F8042BF9D1A36A40360B
+:105690004033A362D4E90A239A4204D3E169204645
+:1056A0000439FFF795FF8BF311884645D9D28AF369
+:1056B0001188CDE729463A46FBF7E4FEA36A3D444C
+:1056C0003E443B44A362E5E7D0E904239A4217D164
+:1056D000C3689BB1836A8BB1043B9B1A0ED01360E5
+:1056E000C368013BC360C3691A4483699A4202617B
+:1056F00024BF436A03610023836201231846704775
+:105700000023FBE700F07CBA014B586A704700BFEA
+:10571000000C0040034B002258631A610222DA6039
+:10572000704700BF000C0040014B0022DA60704758
+:10573000000C0040014B5863704700BF000C004054
+:10574000024B034A1A60034A5A60704764490020BA
+:10575000104A002000000220074B494210B55C6847
+:10576000201A08401968821A8A4203D3A24201D83B
+:105770005A6010BD0020FCE76449002008B53023C2
+:1057800083F31188FFF7E8FF002383F3118808BD36
+:1057900004480121044B03600023C0E901330C30AD
+:1057A000FEF7E8B86C4900207D570008CB1D083A89
+:1057B00023F00703591A521A012110B4D208002409
+:1057C000C0E9004384600C301C605A605DF8044BF3
+:1057D000FEF7D0B82DE9F84F364ECD1D0F46002804
+:1057E00018BF0646082A4FEAD50538BF082206F139
+:1057F0000C08341D91464046FEF7D8F809F1070120
+:10580000C9F1000E224624686CB94046FEF7D8F86C
+:105810003368CBB308224946E8009847044698B35A
+:1058200040E9026730E004EB010CD4F804A00CEA74
+:105830000E0C0AF10100ACF1080304EBC000984221
+:10584000E0D9A0EB0C0CB5EBEC0F4FEAEC0BD9D880
+:105850009C421CD204F10802AB45A3EB02024FEAC2
+:10586000E202626009D9691CED43206803EBC102C2
+:105870005D44556043F8310022601C465F6040463D
+:1058800044F8086BFEF79CF82046BDE8F88FAA455F
+:10589000216802D111602346EFE7013504EBC5030F
+:1058A00044F8351003F10801401AC0105860136025
+:1058B000F1E700BF6C490020F8B550F8043C0446FD
+:1058C00050F8085CA0F1080607332F1D0C35DB08E3
+:1058D00040F8043C2846FEF769F83B469F421A68A8
+:1058E00001D0B34228D20AB1964225D244F8082CFE
+:1058F00054F8042C1E60013254F8081C06EBC20058
+:10590000814206D14868024444F8042C0A6844F8ED
+:10591000082C5868411C03EBC1018E4207D154F892
+:10592000042C013202445A6054F8082C1A602846AC
+:10593000BDE8F840FEF744B81346CFE7FEE70000A5
+:1059400070B51B4B0025044686B058600E46856234
+:10595000016300F003F904F11003A560E562C4E9F6
+:1059600004334FF0FF33C4E90044C4E90635FFF7C0
+:10597000CBFE2B46024604F134012046C4E908233D
+:1059800080230C4A2565FEF781F801230A4AE0606E
+:1059900000920375684672680192B268CDE90223ED
+:1059A000064BCDE90435FEF799F806B070BD00BF8F
+:1059B000F02B0020EC670008F16700083D59000853
+:1059C000024AD36A1843D062704700BF882900207A
+:1059D0004B6843608B688360CB68C3600B6943612D
+:1059E0004B6903628B6943620B6803607047000078
+:1059F00008B5364B40F2FF60D3F8E0100143C3F81E
+:105A0000E010D3F8082102433148C3F80821314A95
+:105A1000D3F808311146FFF7DBFF00F5806002F193
+:105A20001C01FFF7D5FF00F5806002F13801FFF798
+:105A3000CFFF00F5806002F15401FFF7C9FF00F5C8
+:105A4000806002F17001FFF7C3FF00F5806002F192
+:105A50008C01FFF7BDFF00F5806002F1A801FFF7A0
+:105A6000B7FF00F5806002F1C401FFF7B1FF00F558
+:105A7000006002F1E001FFF7ABFF02F1FC0100F56D
+:105A80008060FFF7A5FF00F079F9134B0421D3F8EC
+:105A9000902242F00102C3F89022D3F8942242F0FF
+:105AA0000102C3F894220522C3F898204FF06052F7
+:105AB000C3F89C20094AC3F8A020C3F898100849ED
+:105AC000C3F89C10C3F8A02008BD00BF00440258D2
+:105AD00000000258F867000800ED00E01B00080312
+:105AE0000040042408B500F041FBFDF77FFF104B98
+:105AF000D3F8DC2042F04002C3F8DC20D3F80421C4
+:105B000022F04002C3F80421D3F80431094B1A688B
+:105B100042F008021A601A6842F004021A60FEF7A6
+:105B2000D5FDFEF73DFCBDE80840FEF719BA00BF01
+:105B3000004402580018024870470000EFF3098340
+:105B4000054968334A6B22F001024A6383F30988EE
+:105B5000002383F31188704700EF00E0302080F3CA
+:105B6000118862B60D4B0E4AD96821F4E061090430
+:105B7000090C0A430B49DA60D3F8FC2042F080722A
+:105B8000C3F8FC20084AC2F8B01F116841F00101B7
+:105B900011602022DA7783F82200704700ED00E0E0
+:105BA0000003FA0555CEACC5001000E0302310B557
+:105BB00083F311880E4B5B6813F4006314D0F1EE8D
+:105BC000103AEFF309844FF08073683CE361094BAE
+:105BD000DB6B236684F30988FDF7A0FE10B1064B4A
+:105BE000A36110BD054BFBE783F31188F9E700BF04
+:105BF00000ED00E000EF00E0430700084607000862
+:105C0000114BD3F8E82042F00802C3F8E820D3F89B
+:105C1000102142F00802C3F810210C4AD3F81031C9
+:105C2000D36B43F00803D36340F20312084B9A622C
+:105C30004FF0FF32DA6200229A615A63DA605A60EA
+:105C400001225A611A607047004402580010005C3B
+:105C5000000C0040094A08B51169D3680B40D9B25D
+:105C60009B076FEA0101116107D5302383F3118887
+:105C7000FDF7E6FE002383F3118808BD000C004009
+:105C80003C4B4FF0FF31D3F8802062F0004210B55A
+:105C9000C3F88020D3F8802002F00042C3F88020AF
+:105CA000D3F88020D3F88420C3F88410D3F884205C
+:105CB0000022C3F88420D3F88400D86F40F0FF405E
+:105CC00040F4FF0040F4DF4040F07F00D867D86F19
+:105CD00020F0FF4020F4FF0020F4DF4020F07F00A0
+:105CE000D867D86FD3F8884023482043C3F888008A
+:105CF000D3F8880020F480704005400DC3F8880078
+:105D0000D3F88800D3F89000C3F89010D3F890002F
+:105D1000C3F89020D3F89000D3F89400C3F89410FF
+:105D2000D3F89400C3F89420D3F89400D3F89800E3
+:105D3000C3F89810D3F89800C3F89820D3F89800C7
+:105D4000D3F88C00C3F88C10D3F88C00C3F88C20E7
+:105D5000D3F88C00D3F89C00C3F89C10D3F89C10A7
+:105D6000C3F89C20D3F89C30FEF7AEFDBDE8104090
+:105D700000F0CCB90044025800F9FFFF5A4BD3F8A9
+:105D8000F42042F00202C3F8F420D3F81C2142F0C0
+:105D90000202C3F81C210222D3F81C31534BDA60F3
+:105DA0005A689104FCD5524A1A6001229A60514AFD
+:105DB000DA6000221A619A614C4B9A699204FCD510
+:105DC0001A6842F480721A60474B1A6F02F44072EC
+:105DD000B2F5007F04D04FF480321A6700221A67B0
+:105DE0001A6842F001021A603F4B1A685007FCD54E
+:105DF00000221A611A6912F03802FBD101211960E0
+:105E00004FF0804159604FF00051D9605A673A4ACB
+:105E1000DA623A4A1A611A6842F480321A60324BE6
+:105E20001A689103FCD51A6842F480521A601A6805
+:105E30009204FCD5324A33499A6200225A631963AC
+:105E40003149DA6399635A64304A1A64304ADA6233
+:105E50001A6842F0A8521A60234B1A6802F02852BE
+:105E6000B2F1285FF9D148229A614FF48862DA6171
+:105E700040221A624FF00052DA64264A1A654FF443
+:105E800070025A65244A9A653323244A13601368C2
+:105E900003F00F03032BFAD1134B1A6942F00302EC
+:105EA0001A611A6902F03802182AFAD1D3F8DC20F4
+:105EB00042F00052C3F8DC20D3F8042142F0005233
+:105EC000C3F80421D3F80421D3F8DC2042F0804247
+:105ED000C3F8DC20D3F8042142F08042C3F8042147
+:105EE000D3F80431704700BF0044025800480258FC
+:105EF00000C000F0020000010000FF0100828402E7
+:105F000042808000030105038F050201BF000103E9
+:105F10003503FF0100200010000101200020005285
+:105F20004FF0B04208B5D2F8883003F00103C2F850
+:105F3000883023B1044A13680BB150689847BDE814
+:105F40000840FFF733BE00BF844900204FF0B04245
+:105F500008B5D2F8883003F00203C2F8883023B1C4
+:105F6000044A93680BB1D0689847BDE80840FFF732
+:105F70001DBE00BF844900204FF0B04208B5D2F8E2
+:105F8000883003F00403C2F8883023B1044A13694F
+:105F90000BB150699847BDE80840FFF707BE00BF46
+:105FA000844900204FF0B04208B5D2F8883003F0A1
+:105FB0000803C2F8883023B1044A93690BB1D06951
+:105FC0009847BDE80840FFF7F1BD00BF84490020B5
+:105FD0004FF0B04208B5D2F8883003F01003C2F891
+:105FE000883023B1044A136A0BB1506A9847BDE860
+:105FF0000840FFF7DBBD00BF844900204FF0B043ED
+:1060000010B5D3F8884004F47872C3F88820A3064A
+:1060100004D5124A936A0BB1D06A9847600604D53A
+:106020000E4A136B0BB1506B9847210604D50B4AEF
+:10603000936B0BB1D06B9847E20504D5074A136CFC
+:106040000BB1506C9847A30504D5044A936C0BB16F
+:10605000D06C9847BDE81040FFF7A8BD84490020E8
+:106060004FF0B04310B5D3F8884004F47C42C3F835
+:106070008820620504D5164A136D0BB1506D984700
+:10608000230504D5124A936D0BB1D06D9847E004F7
+:1060900004D50F4A136E0BB1506E9847A10404D576
+:1060A0000B4A936E0BB1D06E9847620404D5084A30
+:1060B000136F0BB1506F9847230404D5044A936FB4
+:1060C0000BB1D06F9847BDE81040FFF76FBD00BF20
+:1060D0008449002008B50348FCF7E0FBBDE8084010
+:1060E000FFF764BDF824002008B50348FCF784FCE2
+:1060F000BDE80840FFF75ABD1C25002008B5FFF792
+:10610000A9FDBDE80840FFF751BD0000062108B514
+:106110000846FFF717F906210720FFF713F90621B4
+:106120000820FFF70FF906210920FFF70BF90621D8
+:106130000A20FFF707F906211720FFF703F90621C8
+:106140002820FFF7FFF809217A20FFF7FBF80A2142
+:106150005C20FFF7F7F807213220FFF7F3F80C2156
+:106160002520BDE80840FFF7EDB8000008B5FFF7AF
+:1061700087FD00F00FF8FCF757FEFDF72FF8FCF74E
+:1061800001FFFDF7C5FAFFF7D7FCBDE80840FFF7B0
+:10619000B9BA00000023054A19460133102BC2E9A1
+:1061A000001102F10802F8D1704700BF84490020B5
+:1061B0000B460146184600F027B80000FEF728B944
+:1061C000FFF7FCBF012838BF012010B50446204668
+:1061D000FEF7DEF830B900F007F808B900F00CF867
+:1061E0008047F4E710BD0000024B1868BFF35B8FD7
+:1061F000704700BF044A002008B5062000F04AF8A6
+:106200000120FDF7FBFD000010B5054C13462CB135
+:106210000A4601460220AFF3008010BD2046FCE78D
+:106220000000000010B501390244904201D1002065
+:1062300005E0037811F8014FA34201D0181B10BDEF
+:106240000130F2E71F2938B504460D4604D916235C
+:1062500003604FF0FF3038BD426C12B152F821306C
+:106260004BB9204600F030F82A4601462046BDE8EA
+:10627000384000F017B8012B0AD0591C03D116235F
+:1062800003600120E7E7002442F8254028469847AC
+:106290000020E0E7024B01461868FFF7D3BF00BFBC
+:1062A0007022002038B5074D0023044608461146E9
+:1062B0002B60FDF7A7FD431C02D12B6803B12360BF
+:1062C00038BD00BF084A0020FDF796BD034611F80F
+:1062D000012B03F8012B002AF9D1704700000000C0
+:1062E00001000000010000010000000000000000AB
+:1062F0000000000065000000010100010200000034
+:106300000000000008000000526571756573746537
+:106310006420746F206572617365206D6F726520F3
+:106320007468616E2077652063616E0A0045726152
+:10633000736520436F6D6D616E642052656365699E
+:106340007665640A0050435420444F4E453A202558
+:10635000640A000053544D333248373F3F3F0053E7
+:10636000544D3332483733782F3732780053544DF9
+:106370003332483734332F3735332F373530000039
+:1063800001105A0003105900012058000320560044
+:1063900053464450000000004A454445433A2046D5
+:1063A00061696C656420746F206465746563742032
+:1063B000666C617368206465766963653A2025734D
+:1063C0000A004A454445433A204661696C656420A9
+:1063D000746F20636F6E66696720666C61736820F6
+:1063E0006465766963653A2025730A004A45444529
+:1063F000433A20446574656374656420466C617338
+:1064000068204465766963653A2025730A004578FB
+:106410007420466C617368204E6F7420466F756EF1
+:10642000642100006D743235710077323571007768
+:106430003235712D647472002464000820BA0000A3
+:10644000000000002A640008EF4000000000000087
+:106450002F640008EF700000000000000000000042
+:1064600000000000291E0008912000085D160008A9
+:106470006116000809170008F91F000865160008D2
+:1064800069160008F11E0008D9160008511F0008FF
+:10649000AD1B0008711600086D16000839210008B0
+:1064A000D1160008000000000000000000000000FD
+:1064B00000000000492200088D2500088D250008F5
+:1064C0004D220008512200085522000859220008D8
+:1064D0008D2500088D2500088D25000871220008F3
+:1064E000752200088D22000895220008A1220008CC
+:1064F000A5220008A9220008F824002001000000BD
+:106500000000000000000000E1230008F92300085B
+:1065100049220008B52200082D240008E9220008BD
+:10652000C5240008F524000859220008CD220008DF
+:10653000B9220008C922000871220008752200084B
+:106540008D22000895220008A1220008A52200083B
+:10655000A9220008D122000800000000000000006D
+:1065600061230008AD220008B122000800000000ED
+:1065700000000000552600085D260008412600089E
+:10658000492600086D260008712600084D444D413B
+:10659000206661696C75726500000000009600005D
+:1065A00000000000000000000000000000000000EB
+:1065B0000000000000000000E92D0008D52D0008B3
+:1065C000112E0008FD2D0008092E0008F52D0008E9
+:1065D000E12D0008CD2D00081D2E00080000000050
+:1065E000012F0008ED2E0008292F0008152F0008A4
+:1065F000212F00080D2F0008F92E0008E52E0008B5
+:10660000352F00080000000001000000000000001D
+:106610006330000010660008E0290020F02B002005
+:106620004172647550696C6F740025424F41524449
+:10663000252D424C002553455249414C2500000070
+:106640000200000000000000213100089131000824
+:1066500040004000A0440020B044002002000000A0
+:10666000000000000300000000000000D931000815
+:106670000000000010000000C044002000000000E6
+:106680000100000000000000B048002001010200ED
+:10669000FD3E00080D3E0008A93E00088D3E0008A2
+:1066A00043000000A866000809024300020100C080
+:1066B0003209040000010202010005240010010556
+:1066C00024010001042402020524060001070582BA
+:1066D000030800FF09040100020A00000007050189
+:1066E0000240000007058102400000001200000087
+:1066F000F46600081201100102000040091241571F
+:1067000000020102030100000403090425424F4175
+:10671000524425005350526163696E6748375246B0
+:10672000003031323334353637383941424344450D
+:1067300046000000000000200000020002000000EF
+:106740000000003000800000000000000000002475
+:10675000004004000000000000400424004000004D
+:10676000040000000004000000FC00000200000023
+:10677000000000380040000001000000400000520E
+:1067800080000052C000005200010052400100523F
+:1067900080010052C001005200020052400200522B
+:1067A00080020052C0020052000300524003005217
+:1067B00080030052C0030052000400520000000099
+:1067C00035330008ED3500089936000840004000D8
+:1067D0004C4900204C490020010000005C49002089
+:1067E0000001000000100000080000006D61696EEB
+:1067F0000069646C650000000000806A0000000011
+:10680000AAAAAAAA00000064FFFF0000000000007E
+:1068100000000000202000A000000000AAAAAAAAF0
+:1068200000000050FFFF00000009000A00000044C3
+:106830000000004000000000AAAAAAAA0000000070
+:10684000FFFF000000000000000000000000800AC0
+:1068500000000000AAAAAAAA00000000FFFF000092
+:10686000000000000090990060806A0000000000B5
+:10687000AAAAAAAA00004000F7FF0000000900A091
+:10688000AA0A00000000000000000000AAAAAAAAAC
+:1068900000000000FFFF00000000000000000000FA
+:1068A0000000000000000000AAAAAAAA0000000040
+:1068B000FFFF0000000000000000000000000000DA
+:1068C00000000000AAAAAAAA00000000FFFF000022
+:1068D00000000000000000000000000000000000B8
+:1068E000AAAAAAAA00000000FFFF00000000000002
+:1068F000000000000000000000000000AAAAAAAAF0
+:1069000000000000FFFF0000000000000000000089
+:10691000109AFF7F010000005404000000000000F6
+:106920000000000000002000FF000000F82B002005
+:106930001C25002000000000546300083F000000F8
+:10694000830400005F6300083F0000005004000063
+:106950006D6300083F000000009600000000080082
+:10696000960000000008000004000000086700080E
+:106970000000000000000000000000000000000017
+:106980000000000000000000742200200000000051
+:1069900000000000000000000000000000000000F7
+:1069A00000000000000000000000000000000000E7
+:1069B00000000000000000000000000000000000D7
+:1069C00000000000000000000000000000000000C7
+:1069D00000000000000000000000000000000000B7
+:0C69E000000000000000000000000000AB
+:00000001FF
diff --git a/Tools/bootloaders/Sierra-PrecisionPoint_bl.bin b/Tools/bootloaders/Sierra-PrecisionPoint_bl.bin
new file mode 100644
index 00000000000000..afa4889c8721cf
Binary files /dev/null and b/Tools/bootloaders/Sierra-PrecisionPoint_bl.bin differ
diff --git a/Tools/bootloaders/Sierra-PrecisionPoint_bl.hex b/Tools/bootloaders/Sierra-PrecisionPoint_bl.hex
new file mode 100644
index 00000000000000..9fcb07bb0c4b84
--- /dev/null
+++ b/Tools/bootloaders/Sierra-PrecisionPoint_bl.hex
@@ -0,0 +1,1799 @@
+:020000040800F2
+:1000000000070020F5040008D52B00088D2B000800
+:10001000B52B00088D2B0008AD2B0008F704000855
+:10002000F7040008F7040008F7040008CD3B0008B7
+:10003000F7040008F7040008F7040008F7040008B4
+:10004000F7040008F7040008F7040008F7040008A4
+:10005000F7040008F7040008A5670008CD6700084A
+:10006000F56700081D68000845680008F7040008E7
+:10007000F7040008F7040008F7040008F704000874
+:10008000F7040008F7040008F7040008412B0008F3
+:100090006D2B00087D2B0008F70400086D68000830
+:1000A000F7040008F7040008F7040008F704000844
+:1000B00055690008F7040008F7040008F704000871
+:1000C000F7040008F7040008F7040008F704000824
+:1000D000F704000841690008F7040008F704000865
+:1000E000D1680008F7040008F7040008F7040008C6
+:1000F000F7040008F7040008F7040008F7040008F4
+:10010000F7040008F7040008F7040008F7040008E3
+:10011000F7040008F7040008F7040008F7040008D3
+:10012000F7040008F7040008F7040008F7040008C3
+:10013000F7040008F7040008F7040008F7040008B3
+:10014000F7040008F7040008F7040008595D0008E8
+:10015000F7040008F7040008F7040008F704000893
+:10016000F7040008F7040008F7040008F704000883
+:10017000F7040008F7040008F7040008F704000873
+:10018000F7040008F7040008F7040008F704000863
+:10019000F7040008F7040008F7040008F704000853
+:1001A000F7040008F7040008F7040008F704000843
+:1001B000F7040008F7040008F7040008F704000833
+:1001C000F7040008F7040008F7040008F704000823
+:1001D000F7040008F7040008F7040008F704000813
+:1001E000E51600080000000000000000000000000C
+:1001F00053B94AB9002908BF00281CBF4FF0FF318E
+:100200004FF0FF3000F074B9ADF1080C6DE904CE89
+:1002100000F006F8DDF804E0DDE9022304B07047E1
+:100220002DE9F047089D04468E46002B4DD18A42A9
+:10023000944669D9B2FA82F252B101FA02F3C2F1DC
+:10024000200120FA01F10CFA02FC41EA030E94406D
+:100250004FEA1C48210CBEFBF8F61FFA8CF708FB8E
+:1002600016E341EA034306FB07F199420AD91CEB66
+:10027000030306F1FF3080F01F81994240F21C8198
+:10028000023E63445B1AA4B2B3FBF8F008FB1033E0
+:1002900044EA034400FB07F7A7420AD91CEB040415
+:1002A00000F1FF3380F00A81A74240F207816444E5
+:1002B000023840EA0640E41B00261DB1D44000236A
+:1002C000C5E900433146BDE8F0878B4209D9002DCE
+:1002D00000F0EF800026C5E9000130463146BDE858
+:1002E000F087B3FA83F6002E4AD18B4202D38242C2
+:1002F00000F2F980841A61EB030301209E46002D71
+:10030000E0D0C5E9004EDDE702B9FFDEB2FA82F2C5
+:10031000002A40F09280A1EB0C014FEA1C471FFA23
+:100320008CFE0126200CB1FBF7F307FB131140EA0A
+:1003300001410EFB03F0884208D91CEB010103F1D7
+:10034000FF3802D2884200F2CB804346091AA4B299
+:10035000B1FBF7F007FB101144EA01440EFB00FE6D
+:10036000A64508D91CEB040400F1FF3102D2A645D2
+:1003700000F2BB800846A4EB0E0440EA03409CE771
+:10038000C6F12007B34022FA07FC4CEA030C20FA1E
+:1003900007F401FA06F31C43F9404FEA1C4900FA3E
+:1003A00006F3B1FBF9F8200C1FFA8CFE09FB1811BB
+:1003B00040EA014108FB0EF0884202FA06F20BD92E
+:1003C0001CEB010108F1FF3A80F08880884240F27E
+:1003D0008580A8F102086144091AA4B2B1FBF9F0C2
+:1003E00009FB101144EA014100FB0EFE8E4508D9BD
+:1003F0001CEB010100F1FF346CD28E456AD9023842
+:10040000614440EA0840A0FB0294A1EB0E01A14226
+:10041000C846A64656D353D05DB1B3EB080261EB94
+:100420000E0101FA07F722FA06F3F1401F43C5E96E
+:10043000007100263146BDE8F087C2F12003D840A4
+:100440000CFA02FC21FA03F3914001434FEA1C47E6
+:100450001FFA8CFEB3FBF7F007FB10360B0C43EAD8
+:10046000064300FB0EF69E4204FA02F408D91CEB88
+:10047000030300F1FF382FD29E422DD90238634486
+:100480009B1B89B2B3FBF7F607FB163341EA034126
+:1004900006FB0EF38B4208D91CEB010106F1FF3875
+:1004A00016D28B4214D9023E6144C91A46EA00466C
+:1004B00038E72E46284605E70646E3E61846F8E6FE
+:1004C0004B45A9D2B9EB020864EB0C0E0138A3E747
+:1004D0004646EAE7204694E74046D1E7D0467BE728
+:1004E000023B614432E7304609E76444023842E7A0
+:1004F000704700BF02E000F000F8FEE772B6374830
+:1005000080F30888364880F3098836483649086001
+:1005100040F20000CCF200004EF63471CEF2000141
+:100520000860BFF34F8FBFF36F8F40F20000C0F23F
+:10053000F0004EF68851CEF200010860BFF34F8FF5
+:10054000BFF36F8F4FF00000E1EE100A4EF63C71E2
+:10055000CEF200010860062080F31488BFF36F8F8D
+:1005600005F0C2F805F0BAFF4FF055301F491B4A9D
+:1005700091423CBF41F8040BFAE71D49184A9142E9
+:100580003CBF41F8040BFAE71A491B4A1B4B9A423D
+:100590003EBF51F8040B42F8040BF8E7002018495D
+:1005A000184A91423CBF41F8040BFAE705F0A0F865
+:1005B00005F0E2FF144C154DAC4203DA54F8041B6D
+:1005C0008847F9E700F042F8114C124DAC4203DACB
+:1005D00054F8041B8847F9E705F088B800070020A5
+:1005E000002300200000000808ED00E000010020CA
+:1005F00000070020886F000800230020BC23002093
+:10060000C023002090540020E0010008E40100080D
+:10061000E4010008E40100082DE9F04F2DED108AF7
+:10062000C1F80CD0C3689D46BDEC108ABDE8F08FC0
+:10063000002383F311882846A047002004F056FBCE
+:10064000FEE704F0AFFA00DFFEE70000F8B501F0C6
+:100650005BF804F0E3FF074605F032F80546B8BB47
+:10066000204B9F4234D001339F4234D01E4B27F0A1
+:10067000FF029A4232D1F8B200F04CFE2E4642F20E
+:10068000107400F04DFE08B10024264601F090FBE6
+:1006900020B1032000F07CF80024264635B1134B2E
+:1006A0009F4203D005F004F800242646002004F001
+:1006B000BFFF0EB100F082F801F0D6F900F08EFE17
+:1006C00001F08EF8204600F0D5F800F077F8F9E751
+:1006D0002E460024D5E704460126D2E706464FF40D
+:1006E0007A74CEE7010007B0000008B0263A09B0DE
+:1006F00008B501F041F8A0F120035842584108BD67
+:1007000007B541F21203022101A8ADF8043001F04F
+:1007100051F803B05DF804FB38B5302383F311883A
+:10072000174803680BB104F0ADFB164A14480023C8
+:100730004FF47A7104F09CFB002383F31188124C70
+:10074000236813B12368013B2360636813B16368B6
+:10075000013B63600D4D2B7833B963687BB9022090
+:1007600001F0FCF8322363602B78032B07D1636818
+:100770002BB9022001F0F2F84FF47A73636038BDB0
+:10078000C023002019070008E0240020D8230020FF
+:10079000084B187003280CD8DFE800F008050208A1
+:1007A000022001F0D1B8022001F0C4B8024B0022AF
+:1007B0005A607047D8230020E024002010B501F0D3
+:1007C000F7FA30B1244B03221A70244B00225A60EE
+:1007D00010BD234B234A1C4619680131F8D004335D
+:1007E0009342F9D16268204B9A42F1D91F4B9B6822
+:1007F00003F1006303F580339A42E9D204F02CFF41
+:1008000004F03EFF002001F005F80220FFF7C0FFD2
+:10081000174B1A6C00221A64196E1A66196E596CFD
+:100820005A64596E5A665A6E1A6942F000521A6139
+:100830001A6922F000521A611B6972B64FF0E02368
+:100840003021C3F8084DD4E9003281F311889D4668
+:1008500083F308881047BBE7D8230020E02400205A
+:100860000000010820000108FFFF0008002300200D
+:10087000003802402DE9F04F93B0AC4B009020229D
+:10088000FF210AA89D6801F099F8A94A1378A3B935
+:10089000A848012103601170302383F31188036895
+:1008A0000BB104F0EFFAA44AA24800234FF47A7186
+:1008B00004F0DEFA002383F31188009B13B19F4BF1
+:1008C000009A1A609E4A009C1378032B1EBF0023D7
+:1008D00013709A4A4FF0000A18BF5360D346564629
+:1008E000D146012001F030F824B1944B1B68002B55
+:1008F00000F01582002000F03FFF0390039B002BC7
+:1009000001DA00F0B3FD039B002BEDDB012001F0C9
+:1009100011F8039B213B162BE3D801A252F823F0D8
+:100920007D090008A5090008390A0008E308000845
+:10093000E3080008E3080008C30A0008930C000855
+:10094000AD0B00080F0C0008370C00085D0C000808
+:10095000E30800086F0C0008E3080008E10C000839
+:100960001D0A0008E3080008250D00088909000891
+:100970001D0A0008E30800080F0C00080220FFF71A
+:10098000B7FE002840F0F581009B0221BAF1000F6C
+:1009900008BF1C4605A841F21233ADF8143000F030
+:1009A00009FF9EE74FF47A7000F0E6FE071EEBDBCE
+:1009B0000220FFF79DFE0028E6D0013F052F00F240
+:1009C000DA81DFE807F0030A0D10133605230593DB
+:1009D000042105A800F0EEFE17E054480421F9E7D1
+:1009E00058480421F6E758480421F3E74FF01C0863
+:1009F000404600F011FF08F104080590042105A805
+:100A000000F0D8FEB8F12C0FF2D1012000FA07F760
+:100A100047EA0B0B5FFA8BFB4FF0000901F01AF865
+:100A200026B10BF00B030B2B08BF0024FFF768FE69
+:100A300057E746480421CDE7002EA5D00BF00B0365
+:100A40000B2BA1D10220FFF753FE074600289BD0B5
+:100A5000012000F0DFFE0220FFF79AFE00265FFA79
+:100A600086F8404600F0E6FE044690B1002140467C
+:100A700000F0F0FE01360028F1D1BA46044641F2FA
+:100A80001213022105A8ADF814303E4600F092FE84
+:100A900027E70120FFF77CFE2546244B9B68AB42ED
+:100AA00007D9284600F0B8FE013040F067810435D0
+:100AB000F3E7234B00251D70204BBA465D603E4690
+:100AC000ACE7002E3FF460AF0BF00B030B2B7FF471
+:100AD0005BAF0220FFF75CFE322000F04DFEB0F16C
+:100AE0000008FFF651AF18F003077FF44DAF0F4A2F
+:100AF000926808EB050393423FF646AFB8F5807F56
+:100B00003FF742AF124B0193B84523DD4FF47A70A3
+:100B100000F032FE0390039A002AFFF635AF019BE6
+:100B2000039A03F8012B0137EDE700BF00230020F3
+:100B3000DC240020C023002019070008E024002046
+:100B4000D823002004230020082300200C230020A9
+:100B5000DC230020C820FFF7CBFD074600283FF428
+:100B600013AF1F2D11D8C5F1200242450AAB25F065
+:100B7000030028BF424683490192184400F0F8FE62
+:100B8000019A8048FF2100F019FF4FEAA8037D4930
+:100B90000193C8F38702284600F018FF0646002894
+:100BA0003FF46DAF019B05EB830537E70220FFF7AC
+:100BB0009FFD00283FF4E8AE00F06CFE00283FF4F3
+:100BC000E3AE0027B846704B9B68BB4218D91F2F75
+:100BD00011D80A9B01330ED027F0030312AA134445
+:100BE00053F8203C05934046042205A901F098F8EB
+:100BF00004378046E7E7384600F00EFE0590F2E73E
+:100C0000CDF81480042105A800F0D4FD06E70023E8
+:100C1000642104A8049300F0C3FD00287FF4B4AE5F
+:100C20000220FFF765FD00283FF4AEAE049800F007
+:100C300019FE0590E6E70023642104A8049300F060
+:100C4000AFFD00287FF4A0AE0220FFF751FD002881
+:100C50003FF49AAE049800F015FEEAE70220FFF791
+:100C600047FD00283FF490AE00F024FEE1E70220AB
+:100C7000FFF73EFD00283FF487AE05A9142000F0E1
+:100C80001FFE04210746049004A800F093FD394696
+:100C9000B9E7322000F070FD071EFFF675AEBB0706
+:100CA0007FF472AE384A926807EB090393423FF62D
+:100CB0006BAE0220FFF71CFD00283FF465AE27F065
+:100CC00003074F44B9453FF4A9AE484600F0A4FDE0
+:100CD0000421059005A800F06DFD09F10409F1E774
+:100CE0004FF47A70FFF704FD00283FF44DAE00F09A
+:100CF000D1FD002844D00A9B01330BD008220AA959
+:100D0000002000F063FE00283AD02022FF210AA82C
+:100D100000F054FEFFF7F4FC1C4803F0EDFF13B0A5
+:100D2000BDE8F08F002E3FF42FAE0BF00B030B2B22
+:100D30007FF42AAE0023642105A8059300F030FD5E
+:100D4000074600287FF420AE0220FFF7D1FC804642
+:100D500000283FF419AEFFF7D3FC41F2883003F0CE
+:100D6000CBFF059800F0C0FE464600F073FE3C46FF
+:100D7000B7E5064652E64FF0000905E6BA467EE6BC
+:100D800037467CE6DC23002000230020A0860100FB
+:100D9000094A136849F2690099B21B0C00FB013340
+:100DA0001360064B186844F2506182B2000C01FBDC
+:100DB0000200186080B2704718230020142300201E
+:100DC00010B500211022044600F0F8FD034B03CBC0
+:100DD000206061601868A06010BD00BF107AFF1F1E
+:100DE0002DE9F041ADF5507D0DF13C086EAC40F2BF
+:100DF000751207460D4610A80021C8F8001000F033
+:100E0000DDFD4FF4C4720021204600F0D7FD01F053
+:100E1000E9FE254B4FF47A72B0FBF2F0186093E8CC
+:100E20000700012384E807000DF5ED702382FFF72A
+:100E3000C7FF44F204731D49238406A805F0A0FEF1
+:100E4000212384F832310DF2EB2206AB0DF1380C80
+:100E50001E4603CE664510605160334602F108021B
+:100E6000F6D13378137041460122204600F05EFE31
+:100E700000230393AB7E029305F11903019380B223
+:100E80000123CDE904800093E97E05A3D3E9002383
+:100E9000384602F071FA0DF5507DBDE8F08100BFD3
+:100EA0009E6AC421818A46EEE8240020906B0008E7
+:100EB0002DE9F043224DBBB001F094FEAB6840F247
+:100EC000ED22C31A934232D906AFA8602B462822DE
+:100ED0000021384602F000FC05F10E0000F066FD2E
+:100EE000002604465FFA80F905F10E08F3B2F1001E
+:100EF000994501F1280107D908EB06030822384675
+:100F000002F0EAFB0136F1E708230122CDE90232C3
+:100F100005340C4B0193A4B230230093CDE9047443
+:100F200005A3D3E90023297B074802F025FA3BB04B
+:100F3000BDE8F083AFF3008078F6339F93CACD8D80
+:100F4000004600200D46002000350020F0B58B8AB9
+:100F5000013B9BB2C92BC9B006460C4647D8274D6A
+:100F60002F7B27BB05F10C03009308223B46394633
+:100F7000204602F075FA7B1CFAB2D9001F46A38AFC
+:100F8000013B9A4205DA0E322A44009200230822DD
+:100F9000EEE700230022C5E900230023AB6085F8BB
+:100FA000D730C5F8D8302B7B0BB9E37E2B73812269
+:100FB000002106AD27A800F001FD0122294627A83F
+:100FC00000F082FE00230393A37E029304F1190331
+:100FD00080B201932823CDE90450E17E009330468E
+:100FE00004A3D3E9002302F0C7F9FFF761FF49B07A
+:100FF000F0BD00BF26417272DF25D7B70046002042
+:1010000070B50D4614461E4602F012F950B9022E74
+:1010100010D1012C0ED112A3D3E90023C5E900237E
+:10102000012007E0282C10D005D8012C09D0052C70
+:101030000FD0002070BD302CFBD10BA3D3E90023CF
+:10104000ECE70BA3D3E90023E8E70BA3D3E90023E4
+:10105000E4E70BA3D3E90023E0E700BFAFF3008090
+:10106000401DA12026812A0B78F6339F93CACD8D8F
+:101070009E6AC421818A46EE26417272DF25D7B767
+:10108000F017304A39059E562DE9F04F8DB002AF6A
+:1010900080460D4602F0CCF8044600285CD12B7E39
+:1010A000022B1BD1EB8A012B18D101F09BFD0646C8
+:1010B000FFF76EFE03464FF4C870DFF81C92B3FBD7
+:1010C000F0F206F5167602FB103316FA83F3C9F830
+:1010D0000030EB7E33B97B4B00221A702C37BD46B3
+:1010E000BDE8F08FAB8AE6B2013BB34204F10104E4
+:1010F0000CD907F108031E44E100009600230822E2
+:1011000001F0F801284602F0ABF9EBE707F118000F
+:10111000FFF756FE324607F1180107F1080005F007
+:10112000B9FC0028D7D10F2E08D8664B1E70D9F80D
+:101130000030A3F51673C9F80030CFE7FB1DF87136
+:101140000146009307220346284602F089F9F979FF
+:10115000404602F065F8C1E7EB8A282B26D010D86C
+:10116000012B1ED0052BB9D1BFF34F8F5649574BDA
+:10117000CA6802F4E0621343CB60BFF34F8F00BF35
+:10118000FDE7302BAAD16B7E514C0133627BDBB281
+:101190009342E94603D1EA7E237B9A420BD0CD46A7
+:1011A0009CE729464046FFF71BFE97E72946404645
+:1011B000FFF7CCFE92E74FF0000807F11803A7F8FD
+:1011C00018801022009341460123284602F048F976
+:1011D000AE8A023EB6B2F31C9B109B000733DB08BD
+:1011E000A9EBC3039D460DF1080A1FFA88F34FEAE5
+:1011F000C8019E4201F110010AD90AEB08030093CD
+:1012000008220023284602F02BF908F10108ECE738
+:1012100094F8D70000F00EFBD4F8D810054619B9A1
+:1012200094F8D70000F016FBD4F8D83033449D4230
+:1012300005D294F8D7000021013000F00BFB4FEAF3
+:10124000960B4FF000081FFA88F18B45D4E9003265
+:1012500009D90AEB880103EB8800012200F0B6FBF4
+:1012600008F10108EFE7F31842F10002C4E9003287
+:10127000D4F8D83094F8D70006EB0308C4F8D88027
+:1012800000F0D8FA804509D394F8D730D4F8D800C4
+:101290000133401B84F8D730C4F8D800FF2E0D4D21
+:1012A00009D80023237300F0F5FA00F081FD2881AE
+:1012B00008B9FFF783FA23689B0A01332B810023C7
+:1012C000A3606CE7F934002000ED00E00400FA05AB
+:1012D00000460020E8240020FC34002010B50A4B12
+:1012E0000A4A1A6003F5805393F860203AB9DC6D1E
+:1012F0002CB1204600F0DAFD204605F081FBBDE868
+:101300001040034800F0D2BD30350020506C00087A
+:1013100078450020014B1870704700BFF42400206E
+:1013200030B54FF00054244B22689A4285B007D064
+:1013300004F0D0F90446A8B90024204605B030BD19
+:101340001E4B627D1A701E48237D03731D49C922FE
+:101350000E3000F00DFB2046E022002100F02EFBB5
+:101360000124EAE7184A194D136C43F00073136423
+:10137000AA6D174B9A42DFD12B6E013B7E2BDBD837
+:10138000144A07CA01AB83E807001846032100F09E
+:10139000DDFC6B6D83424FF00003CDD12A6D8A4294
+:1013A00001BFAB65054B2A6E1A7003BF0A4BEA6D8D
+:1013B0001A601C46C1E700BF9AAD44C5F424002062
+:1013C0000046002016000020003802400066004061
+:1013D0005041A0B0586600401023002037B51A4D88
+:1013E00000F0E6FC02236B71184B2881196818483D
+:1013F000012201F095FA00230193164B1649009340
+:101400001648174B4FF4805201F0E2FE154B197845
+:1014100011B1124801F004FF01F0E4FB0446FFF7AC
+:10142000B7FC4FF4C873B0FBF3F202FB130304F5EF
+:10143000167010FA83F00C4B186004F041F908B1F3
+:101440000F232B8103B030BDE8240020102300209F
+:101450003035002001100008F8240020003500205D
+:1014600089100008F4240020FC3400202DE9F04FFE
+:101470002DED028B0FF25C29D9E900898B4C93B0DA
+:101480008B4E8C4F204601F0A3FF034660B300252E
+:10149000CDE90F550E95ADF84450027B8DF84420F0
+:1014A00099684068DFF834A20FAA03C21B6843F0B2
+:1014B00000430E9301F098FB821941F1000300955F
+:1014C0000EA9384600F05AFEA84205DD204601F07C
+:1014D00083FF8AF80050D5E79AF80030072B00F216
+:1014E000B58001338AF800300BAE9FED6C8B002382
+:1014F000704FDFF8ECA10A93ADF834300B937360B2
+:101500004FF0000B5B468DED008B01250DF11D02A8
+:1015100007A938468DF81C508DF81DB001F0B0F9C0
+:101520009DF81C30002B40F09580204601F080FE95
+:101530000646002845D1604F01F054FB3B689842B5
+:101540003FD301F04FFB8246FFF722FC4FF4C873F4
+:101550000AF5167AB0FBF3F202FB13031AFA83F3CF
+:101560003B60564F97F800B0CBF1100ABBF1000F6B
+:1015700014BF33462B465FFA8AFA0EA88DF828303E
+:10158000FFF71EFCBAF1060F28BF4FF0060A0EAB9C
+:1015900003EB0B0152460DF1290000F0E9F90AAB0B
+:1015A0000393182302930AF10102454BD2B2CDE90D
+:1015B0000053049220463BA3D3E9002301F07EFEB2
+:1015C0003E7001F00FFB3F4A3F4D1368C31AB3F55D
+:1015D0007A7F2ED3106001F007FB02460B462046AF
+:1015E00001F004FF204601F023FE10B32B7B374EA1
+:1015F000002B14BF03230223737101F0F3FA0EAF23
+:101600004FF47A730122B0FBF3F039463060304674
+:1016100000F032FB182302932D4B019380B240F26D
+:101620005513CDE90370009342464B46204601F026
+:1016300045FE2B7B2BB1FFF73BFC2B7B002B7FF474
+:101640001FAF13B0BDEC028BBDE8F08F204601F058
+:10165000C3FE49E7DAF8143083F48053CAF8143033
+:10166000594610220EA800F0A9F90DF11E0308AA90
+:101670000AA9384600F080FE96E803000FAB83E825
+:1016800003009DF834308DF844300A9B0E930EA968
+:10169000DDE90823204602F07DF831E70000000074
+:1016A00000000000401DA12026812A0B00350020EB
+:1016B00040420F0030350020FC340020F934002077
+:1016C000F8340020E046002000460020E8240020F6
+:1016D000E4460020F1C6A7C1D068080FE546002007
+:1016E0000004024008B5054800F0E0FEBDE80840EF
+:1016F000034A0449002005F07DB900BF30350020C1
+:1017000034470020DD120008704700002DE9F84F33
+:101710004FF47A73DFF85880DFF8589006460D468C
+:1017200002FB03F7002498F900305A1C5FFA84FA90
+:1017300001D0A34212D159F8240003682A46D3F8F5
+:1017400020B031463B46D847854207D1074B0120A0
+:1017500083F800A0BDE8F88F0124E4E7002CFBD05B
+:101760004FF4FA7003F0C8FA0020F3E7284700208E
+:101770001C2300202023002007B50023024601215E
+:101780000DF107008DF80730FFF7C0FF20B19DF87D
+:10179000070003B05DF804FB4FF0FF30F9E70000ED
+:1017A0000A4608B50421FFF7B1FF80F00100C0B27E
+:1017B000404208BD30B4074B0A461978064B53F82F
+:1017C00021402368DD69054B0146AC46204630BC0C
+:1017D000604700BF2847002020230020A08601008A
+:1017E00070B503F0A9FD094E094D3080002428682A
+:1017F0003388834208D903F099FD2B6804440133F0
+:10180000B4F5803F2B60F2D370BD00BF2A470020A3
+:10181000E846002003F054BE00F1006000F580307F
+:101820000068704700F10060920000F5803003F01E
+:10183000D1BD0000054B1A68054B1B889B1A8342DB
+:1018400002D9104403F072BD00207047E846002022
+:101850002A470020024B1B68184403F087BD00BFD5
+:10186000E846002010F003030AD1B0F5047F05D24A
+:1018700000F10050A0F51040D0F80038184670472D
+:101880000023FBE700F10050A0F51040D0F8100A4B
+:1018900070470000064991F8243033B10023086AEC
+:1018A00081F824300822FFF7BDBF0120704700BF38
+:1018B000EC460020014B1868704700BF002004E090
+:1018C00070B5194B1D68194B0138C5F30B0408445A
+:1018D0002D0C04221E88A6420BD15C680A46013CEE
+:1018E000824213460FD214F9016F4EB102F8016B18
+:1018F000F6E7013A03F10803ECD181420B4602D22C
+:101900002C2203F8012B0A4A05241688AE4204D182
+:10191000984284BF967803F8016B013C02F10402FF
+:10192000F3D1581A70BD00BF002004E0F46B00082A
+:10193000E06B0008022802BF024B4FF080529A6110
+:10194000704700BF00040240022802BF024B4FF460
+:1019500080529A61704700BF00040240022801BF14
+:10196000024A536983F48053536170470004024074
+:1019700010B50023934203D0CC5CC4540133F9E783
+:1019800010BD000010B5013810F9013F3BB191F9CD
+:1019900000409C4203D11AB10131013AF4E71AB177
+:1019A00091F90020981A10BD1046FCE70346024644
+:1019B000D01A12F9011B0029FAD1704702440346DC
+:1019C000934202D003F8011BFAE770472DE9F84370
+:1019D0001F4D144695F824200746884652BBDFF871
+:1019E00070909CB395F824302BB92022FF214846F3
+:1019F0002F62FFF7E3FF95F82400C0F10802A2422E
+:101A000028BF2246D6B24146920005EB8000FFF780
+:101A1000AFFF95F82430A41B1E44F6B2082E1744DD
+:101A20009044E4B285F82460DBD1FFF733FF00284F
+:101A3000D7D108E02B6A03EB82038342CFD0FFF7B4
+:101A400029FF0028CBD10020BDE8F8830120FBE767
+:101A5000EC460020024B1A78024B1A70704700BF08
+:101A6000284700201C23002038B5194C194D20466A
+:101A700002F06AFC2946204602F092FC2D681648C6
+:101A8000EA6ED2F8043843F00203C2F8043803F0D7
+:101A900033F91249284602F08BFDEA6E104DD2F858
+:101AA000043828680F4923F00203C2F80438A04222
+:101AB0004FF461430B6001D002F0A6FB6868A042BE
+:101AC00004D0BDE83840074902F09EBB38BD00BFD6
+:101AD000184C00208C6D000840420F00946D0008E7
+:101AE000202300201447002070B50C4B0C4D1E78AD
+:101AF0000C4B55F826209A4204460DD00A4B002183
+:101B000014221846FFF75AFF0460014655F82600D4
+:101B1000BDE8704002F078BB70BD00BF28470020D0
+:101B200020230020184C0020144700202DE9F04706
+:101B30000D46044600219046284640F27912FFF7F0
+:101B40003DFF234620220021284601F0C5FD231D2C
+:101B500002222021284601F0BFFD631D032222211D
+:101B6000284601F0B9FDA31D03222521284601F0D6
+:101B7000B3FD04F1080310222821284601F0ACFD32
+:101B800004F1100308223821284601F0A5FD04F1D4
+:101B9000110308224021284601F09EFD04F11203A2
+:101BA00008224821284601F097FD04F11403202261
+:101BB0005021284601F090FD04F1180340227021C5
+:101BC000284601F089FD04F120030822B0212846AF
+:101BD00001F082FD04F121030822B821284601F01A
+:101BE0007BFD04F12207C0263B46314608222846E9
+:101BF000083601F071FDB6F5A07F07F10107F3D1BA
+:101C000004F1320308223146284601F065FD002721
+:101C100004F1330A94F832304FEAC7099F4209F5BC
+:101C2000A47615D3B8F1000F08D1314604F59973A5
+:101C30000722284601F050FD09F24F16274694F876
+:101C400032213B1B93420CD3F01DC008BDE8F08746
+:101C50000AEB070308223146284601F03DFD013713
+:101C6000D8E707F2331331460822284601F034FD45
+:101C700008360137E3E7000013B5044608460021A3
+:101C800001602346C0F803102022019001F024FDDA
+:101C90000198231D0222202101F01EFD0198631DE1
+:101CA0000322222101F018FD0198A31D0322252102
+:101CB00001F012FD019804F108031022282101F01F
+:101CC0000BFD072002B010BDF8B50E4605461446C0
+:101CD000002181223046FFF771FE2B4608220021A9
+:101CE000304601F0F9FC7CB96B1C07220821304614
+:101CF00001F0F2FC0F2401236A785F1C013B934240
+:101D000004D3E01DC008F8BD0824F4E7EB19214610
+:101D10000822304601F0E0FC08343B46ECE70000C6
+:101D200030B5094D0A4491420DD011F8013B58409D
+:101D3000082340F30004013B2C4013F0FF0384EA26
+:101D40005000F6D1EFE730BD2083B8EDF7B54FF086
+:101D5000FF33DFF854C0DFF854E000EB81011A468E
+:101D600088421CD050F8044B019401AF042417F8AA
+:101D7000015B82EA05620825DB18164605F1FF358E
+:101D80005241002EBCBF83EA0C0382EA0E0215F01A
+:101D9000FF05F1D1013C14F0FF04E8D1E0E7D8439E
+:101DA000D14303B0F0BD00BF9336EAA9EBE1F042A6
+:101DB000F7B5384A106851686B4603C36A4636491E
+:101DC0003648082304F076FE0446002833D10A255D
+:101DD000334A106851686B4603C36A4631492F483D
+:101DE000082304F067FE0446002849D00369B3F5D0
+:101DF000E02F45D8B0F8661040F2474291423FD1FB
+:101E0000294A024402F15C018B4239D35C3B2349ED
+:101E100000209E1AFFF784FF3246074604F1640152
+:101E20000020FFF77DFFA3689F4229D1E368984215
+:101E300008BF002524E00369B3F5E02F27D8418BC4
+:101E400040F24742914220D1174A024402F1100168
+:101E50008B4218D3103B114900209D1AFFF760FFF9
+:101E60002A46064604F118010020FFF759FFA3682F
+:101E70009E4202D1E368984201D00D25A8E70025D3
+:101E8000284603B0F0BD1025A2E70C25A0E70B25DE
+:101E90009EE700BF146C0008DCFF0600000001088C
+:101EA0001D6C000890FF06000800FFF710B5037CCA
+:101EB000044613B9006804F0E5FD204610BD00009B
+:101EC0000023BFF35B8FC360BFF35B8FBFF35B8FF8
+:101ED0008360BFF35B8F7047BFF35B8F0068BFF316
+:101EE0005B8F704770B505460C30FFF7F5FF05F1C5
+:101EF000080604463046FFF7EFFFA04206D93046F9
+:101F00006D68FFF7E9FF2544281A70BD3046FFF7DA
+:101F1000E3FF201AF9E7000070B50546406898B164
+:101F200005F10800FFF7D8FF05F10C06044630461E
+:101F3000FFF7D2FF8442304694BF6D680025FFF75B
+:101F4000CBFF013C2C44201A70BD000038B50C4674
+:101F50000546FFF7C7FFA04210D305F10800FFF7C1
+:101F6000BBFF04446868B4FBF0F100FB1144BFF30D
+:101F70005B8F0120AC60BFF35B8F38BD0020FCE7B6
+:101F80002DE9F041144607460D46FFF7C5FF844290
+:101F900028BF0446D4B1B84658F80C6B4046FFF74A
+:101FA0009BFF3044286040467E68FFF795FF331A58
+:101FB0009C4203D86C600120BDE8F0816B60A41BDB
+:101FC0003B68AB602044E8600220F5E72046F3E779
+:101FD00038B50C460546FFF79FFFA04210D305F128
+:101FE0000C00FFF779FF04446868B4FBF0F100FBD4
+:101FF0001144BFF35B8F0120EC60BFF35B8F38BDF2
+:102000000020FCE72DE9FF41884669460746FFF7B7
+:10201000B7FF6C4606B204EBC6060025B44209D0F1
+:102020006268206808EB0501FFF7A2FC63680834CA
+:102030001D44F3E729463846FFF7CAFF284604B097
+:10204000BDE8F081F8B505460C300F46FFF744FFB8
+:1020500005F1080604463046FFF73EFFA042304631
+:1020600088BF6C68FFF738FF201A386020B130460F
+:102070002C68FFF731FF2044F8BD000073B514460B
+:1020800006460D46FFF72EFF844228BF0446019006
+:10209000DCB101A93046FFF7D5FF019B33B93268A7
+:1020A000C5E90233C5E9002401200CE09C4238BF99
+:1020B00001942860019868608442F5D93368AB6068
+:1020C000241AEC60022002B070BD2046FBE700003D
+:1020D0002DE9FF410F466946FFF7D0FF6C4600B27D
+:1020E00004EBC0050026AC4209D0D4F8048054F8B3
+:1020F000081BB8194246FFF73BFC4644F3E730465D
+:1021000004B0BDE8F081000038B50546FFF7E0FFF8
+:10211000044601462846FFF719FF204638BD000057
+:10212000302383F3118862B670470000002383F3E5
+:10213000118862B67047000010B4026854681A46ED
+:1021400023465DF8044B1847012070470020704774
+:102150000020704770470000002070470E20704735
+:1021600000F5805090F8C800C0F3400070470000B0
+:1021700000F5805090F9C90070470000F7B50C6871
+:10218000BDF8207014F000541E466FD10B7B082B55
+:102190006CD8FFF7C5FF4569AB685B010CD4AB6831
+:1021A0001B0108D4AC6814F080545DD1FFF7BEFF6A
+:1021B000204603B0F0BD01240B6804F1180C002B7D
+:1021C000B8BFDB004FEA0C1CB4BF43F004035B054F
+:1021D00045F80C300B680FFA84FC13F0804F18BFE1
+:1021E00005EB0C1E05EB0C1C1EBFDEF8803143F026
+:1021F0000203CEF880310B7BCCF8843105EB04155B
+:102200008B68C5F88C314B68C5F88831DCF88031B3
+:1022100043F00103CCF8803100EB441541F2680330
+:102220001D4403EB44130344C5E9002608330D465F
+:1022300001F10C0C55F804EB43F804EB6545F9D1BA
+:1022400084342D881D8000EB441407F003032579A6
+:1022500025F00B052B432371FFF768FF00973346EA
+:1022600000F0E4FC0120A4E70224A5E74FF0FF30D2
+:102270009FE7000013B500F580540191E06DFFF772
+:102280004BFE1F280AD90199E06D2022FFF7BAFE04
+:10229000A0F120035842584102B010BD0020FBE7D6
+:1022A00008B500F58050FFF73BFFC06DFFF708FE53
+:1022B000BDE80840FFF73ABF002202608281426019
+:1022C0008260704710B500220023C0E9002300237C
+:1022D000044603810C30FFF7EFFF204610BD0000DD
+:1022E000F0B5054600F580500C4690F8C83013F064
+:1022F000040FC3F3800108BF114661F3820304F1A8
+:10230000840680F8C83005EB461389B01B79D807DE
+:102310002ED57AB319072DD46846FFF7D3FF05EB06
+:10232000441303F5835303F1180703AA1033186805
+:102330005968144603C40833BB422246F7D11868D3
+:1023400020609B88A380DDE90E23CDE900230123D3
+:10235000ADF808302B686946DB6B2846984705EBDB
+:1023600046152B791A075CBF43F008032B7101E077
+:10237000002AF4D109B0F0BD2DE9F047074688B036
+:1023800007F5805468469A468846FFF7C9FE91468D
+:10239000FFF798FFE06DFFF7A5FD1F2829D9E06D35
+:1023A00020226946FFF7B0FE202822D103AD444623
+:1023B00005AB2E4603CE9E4220606160354604F197
+:1023C0000804F6D130682060B388A380DDE90023DB
+:1023D000C9E90023BDF80830AAF80030FFF7A6FECF
+:1023E0004A4653464146384608B0BDE8F04700F03B
+:1023F0000BBCFFF79BFE002008B0BDE8F087000093
+:102400002DE9F84F0023C0E90133254B044640F87D
+:10241000183B0F46FFF750FF04F12800FFF752FF6B
+:1024200004F1480804F58255464608353046203602
+:10243000FFF748FFAE42F9D104F580554FF48053C1
+:102440004FF00009C5E91339C5F848800123EE654E
+:1024500004F5875804F58456C5F8549085F858302B
+:1024600085F86030083608F108084FF0000A4FF090
+:10247000000B46E908ABA6F11800FFF71DFF203658
+:1024800046F8289C4645F4D185F8C97017B105482F
+:1024900000F0A2FB044B63612046BDE8F88F00BF4B
+:1024A000506C0008286C00080064004010B5044B14
+:1024B000197804464A1C1A70FFF7A2FF204610BD87
+:1024C000304700202DE9F047002950D0294B2A4FF2
+:1024D000B7FBF1F599428CBF0A231123581EB5FBB7
+:1024E000F3FC03FB1C53C4B22BB102280346F5D8FE
+:1024F0000020BDE8F0870CF1FF36B6F5806FF7D20B
+:10250000C4EBC40E0EF103034FEAE309C3F3C703A0
+:10251000A4EB030809F1010A4FF47A755FFA88F019
+:1025200009FB05555AFA88F8B5FBF8F5B5F5617F52
+:10253000C1BF0EF1FF33C3F3C703E01AC0B25C1C86
+:1025400050FA84F40CFB04F4B7FBF4F4A142CFD1AD
+:10255000013BDBB20F2BCBD80138C0B20728C7D85C
+:102560000021107116809170D3700120C1E70846D8
+:10257000BFE700BF3F420F0040787D0170B50546C0
+:102580000E464FF47A746B695B6803F00103B34243
+:1025900007D04FF47A7002F0AFFB013CF3D1204634
+:1025A00070BD0120FCE7000030B54269936913F06B
+:1025B000700F16D000230B4C936103F1840200EBE3
+:1025C000421211794D0709D5890707D5416954F899
+:1025D00023508D60117941F0040111710133032BF7
+:1025E000EBD130BD3C6C000873B51D4643691646FF
+:1025F0009A68D207044609D59A6801219960C2F306
+:102600004002CDE900650021FFF76AFE63699A6820
+:10261000D1050BD59A684FF480719960C2F34022BE
+:10262000CDE9006501212046FFF75AFE63699A68EB
+:10263000D2030BD59A684FF480319960C2F34042BF
+:10264000CDE9006502212046FFF74AFE204602B090
+:10265000BDE87040FFF7A8BFF8B5044646690029F9
+:102660006CD106F10C07386880076AD006EB0115BB
+:102670003868D5F8B00110F0040FD5F8B0011ABFD2
+:10268000C00840F00040400DA061D5F8B0C11CF07A
+:10269000020F1CBF40F08040A061D5F8B40106EBEA
+:1026A000011100F00F0084F82400D1F8B801207760
+:1026B000D1F8B801000A6077D1F8B801000CA07712
+:1026C000D1F8B801000EE077D1F8BC0184F8200001
+:1026D000D1F8BC01000A84F82100D1F8BC01000C3B
+:1026E00084F82200D1F8BC11090E84F82310382197
+:1026F000396004F1340004F1180104F1240551F8A3
+:10270000046B40F8046BA942F9D109880180C4E93F
+:102710000A2321460023238651F8283B2046DB6B01
+:10272000984704F58052204692F8C83043F00403DD
+:1027300082F8C830BDE8F840FFF736BF06F1100751
+:1027400091E7F8BD10B5044600F04EFA02460B467C
+:1027500052EA030102D0013A63F100030449086818
+:1027600020B12146BDE81040FFF776BF10BD00BF85
+:102770002C470020F8B500F583511E46FFF7D0FC2A
+:10278000DFF844C00831002404F1840500EB45154E
+:102790002B795F070ED4DB060CD5D1E90073974285
+:1027A000B34107D243695CF824709F602B7943F0F2
+:1027B00004032B710134032C01F12001E4D1BDE8A5
+:1027C000F840FFF7B3BC00BF3C6C000808B5FFF74A
+:1027D000A7FCFFF7E9FEBDE80840FFF7A7BC000033
+:1027E000F8B543690546986800F0E050B0F1E05F45
+:1027F0000F461FD0E8B1FFF793FC05F58354103462
+:10280000002606F1840305EB43131B791A0706D54E
+:102810000136032E04F12004F3D1012007E05B0709
+:10282000F6D42146384600F03BFA0028F0D1FFF7F5
+:102830007DFCF8BD0120FCE700F5805008B5FFF7EE
+:102840006FFCC06DFFF74EFBFFF770FC43090CBF38
+:102850000120002008BD0000F8B51D4600231370BC
+:102860000F4606461446FFF7E7FF80F00100387078
+:1028700025B129463046FFF7B3FF2070F8BD0000B0
+:102880002DE9B8410C4615461F46804600F0ACF9CC
+:102890000B462178024609B9287850B14046FFF727
+:1028A00069FFFFF793FF3B462A462146FFF7D4FF17
+:1028B0000120BDE8B881000010B5FFF731FC174BCF
+:1028C0001A6C42F000721A641A6A42F000721A62BC
+:1028D0001A6A00F5805422F000721A62FFF726FC93
+:1028E00094F8C830DB0718D4B9B103211320FFF7DF
+:1028F00017FC01F0BDFA0321142001F0B9FA0321FD
+:10290000152001F0B5FA94F8C83043F0010384F8BB
+:10291000C830BDE81040FFF709BC10BD00380240C8
+:102920002DE9F04700F5805588B095F8C930012BA6
+:102930000446884616467FD8804F57F823200AB9A8
+:1029400047F82300D7F800A0C4F80C802674BAF129
+:10295000000F63D095F8C930012B6FD001212046BC
+:10296000FFF7AAFFFFF7DCFB6269136823F002039D
+:1029700013606269136843F0010313606369002701
+:102980005F6101212046FFF7D1FBFFF7F7FD00282B
+:1029900000F09580E86DFFF793FA04F58359BA4685
+:1029A00009F10809202200216846FFF707F802A86C
+:1029B000FFF782FCCDF818A06A4609EB07030DF17A
+:1029C000180E9446BCE80300F4451860596062464E
+:1029D00003F10803F5D1DCF80000186020379CF8FB
+:1029E00004201A71602FDDD195F8C8306FF382038F
+:1029F000002785F8C8306A4641462046ADF8007089
+:102A0000ADF802708DF80470FFF75CFD636948BB98
+:102A10004FF400421A6008B0BDE8F08741F2D000E0
+:102A200003F0F0FF814610B15146FFF7E9FCC7F80B
+:102A30000090B9F1000F8DD10020ECE738680368F1
+:102A40001B6B98470146002888D13868FFF734FF90
+:102A50003868036832465B684146984700287FF42F
+:102A60007DAFE9E761221A609DF802309DF80320EE
+:102A70001B06120402F4702203F040731343BDF8E6
+:102A80000020C2F3090213439DF804201205022E10
+:102A900002F4E0020CBF4FF00041002113436269D1
+:102AA0000B43D361636913225A616269136823F08F
+:102AB0000103136039462046FFF760FD08B96369DA
+:102AC000A6E795F8C93093BB6169D1F8002242F0BE
+:102AD0000102C1F800226169D1F8002222F47C527F
+:102AE00022F00E02C1F800226169D1F8002242F4FE
+:102AF0006062C1F800226269C2F814326269C2F8E9
+:102B00000432626941F6FF71C2F80C126269C2F8C0
+:102B100040326269C2F8443263690122C3F81C2260
+:102B20006269D2F8003223F00103C2F8003295F84E
+:102B3000C83043F0020385F8C8306CE72C4700200A
+:102B400008B500F051F850EA0103024602D0421ED7
+:102B500061F10001044B186810B10B46FFF744FD0A
+:102B6000BDE8084001F066B82C47002008B50020F9
+:102B7000FFF7E8FDBDE8084001F05CB808B50120AA
+:102B8000FFF7E0FDBDE8084001F054B800B59BB088
+:102B9000EFF3098168226846FEF7EAFEEFF305834A
+:102BA000014B9B6BFEE700BF00ED00E008B5FFF7AF
+:102BB000EDFF000000B59BB0EFF309816822684685
+:102BC000FEF7D6FEEFF30583014B5B6BFEE700BF1C
+:102BD00000ED00E0FEE700000FB408B5029802F037
+:102BE00017F8FEE702F0B8BC02F090BC02F08EBC11
+:102BF00013B56C4684E80600031D94E8030083E8DF
+:102C00000500012002B010BD73B58568019155B172
+:102C10001B885B0707D4D0E900369B6B9847019A65
+:102C2000C1B23046A847012002B070BDF0B5866839
+:102C300089B005460C465EB1BDF838305B070AD452
+:102C4000D0E900379B6B98472246C1B23846B0475F
+:102C5000012009B0F0BD00220023CDE900230023AC
+:102C6000ADF808300A4603AB01F108061068516858
+:102C70001C4603C40832B2422346F7D110682060D4
+:102C80009288A280FFF7B2FF0423ADF808302B68CA
+:102C9000CDE90001DB6B694628469847D8E700007C
+:102CA00030B503680968DD0FB5EBD17F23F06044D0
+:102CB00021F060424FEAD1700BD0002BB8BFA40CBA
+:102CC0000029B8BF920C944202D034BF01200020EA
+:102CD00030BD944205D1C1F38070C3F38073834249
+:102CE000F6D194422CBF00200120F1E72DE9F041FC
+:102CF000456A15B94162BDE8F0814B6823F0604731
+:102D0000C3F38A464FEAD37EC3F3807816EA2306DC
+:102D100038BF3E46AC462B465A68BEEBD27F22F007
+:102D200060440AD0002A18DAA40CB44217D19D429C
+:102D30000FD10D60DEE71346EEE7A74207D102F0A0
+:102D40008044C2F3807242450BD054B1EFE708D201
+:102D5000EDE7CCF800100B60CDE7B44201D0B442EF
+:102D6000E5D81A689C46002AE5D11960C3E700003F
+:102D70002DE9F047089D01F007044FEAD5082244E9
+:102D800005F0070500EBD1004FF47F49944201D1D3
+:102D9000BDE8F08704F0070705F0070A57453E46EF
+:102DA00038BF5646C6F10806111B8E4228BF0E4694
+:102DB000E10808EBD50E415C13F80EC0B94029FAC2
+:102DC00006F721FA0AF1FFB28CEA010147FA0AF785
+:102DD00039408CEA010C03F80EC034443544D5E781
+:102DE00080EA0120082341F2210201B240000029BB
+:102DF00080B203F1FF33B8BF504013F0FF03F4D1AA
+:102E00007047000038B50C468D18A54200D138BD7A
+:102E100014F8011BFFF7E4FFF7E7000042684AB12E
+:102E2000136843604389818901339BB2994243818E
+:102E300038BF83811046704770B588B020220446A1
+:102E40000D4668460021FEF7B9FD20460495FFF7C0
+:102E5000E5FF024658B16B46054608AE1C4603CC5A
+:102E6000B44228606960234605F10805F6D1104692
+:102E700008B070BD082817D909280CD00A280CD032
+:102E80000B280CD00C280CD00D280CD00E2814BF09
+:102E90004020302070470C207047102070471420CD
+:102EA000704718207047202070470000082817D965
+:102EB0000C280CD910280CD914280CD918280CD996
+:102EC00020280CD930288CBF0F200E2070470920F5
+:102ED00070470A2070470B2070470C2070470D2068
+:102EE000704700002DE9F843078C072F04461ED9D0
+:102EF000D0E9029800254FF6FF73C5F12006A5F131
+:102F0000200029FA05F108FA06F628FA00F0314304
+:102F10000143C9B21846FFF763FF0835402D034649
+:102F2000EBD1E1693A46BDE8F843FFF76BBF4FF6D6
+:102F3000FF70BDE8F883000010B54B6823B9CA8A5A
+:102F400063F30902CA8210BD04691A681C60036138
+:102F5000C38A013BC3824A60EFE700002DE9F84FC6
+:102F60001D46CB8A0F46C3F30901052981469246C7
+:102F70000B4630D00020AAB207F11A049EB2042EEC
+:102F80001FFA80F80FD8904503F1010306D3FB8A9E
+:102F90000A4462F30903FB8201201AE01AF8006078
+:102FA000E6540130EAE79045F1D2A1F1050B1C236C
+:102FB0007C68BBFBF3F203FB12BB1FFA8BF6002C01
+:102FC00045D14846FFF72AFF044638B978606FF0CC
+:102FD0000200BDE8F88F4FF00008E6E70026066023
+:102FE0007860ADB24FF0000B454510D90AEB0803ED
+:102FF000221D13F8011B9155B1B208F101081B29DC
+:103000001FFA88F82BD0454506F10106F1D8FB8A56
+:10301000C3F30902154465F30903BCE7013292B218
+:103020001C462368002BF9D16B1F0B441C21B3FBFA
+:10303000F1F301339BB29A42D3D2BBF1000FD0D14E
+:103040004846FFF7EBFE20B9C4F800B0BFE7012205
+:10305000E7E7C0F800B05E4620600446C1E745459A
+:10306000D5D94846FFF7DAFE08B92060AFE7C0F8C7
+:1030700000B0002620600446B6E700002DE9F04FBE
+:103080002DED028B1C4683B05B6901920746884692
+:10309000002B00F09A80238C2BB1E269002A00F00B
+:1030A0009480072B35D807F10C00FFF7B7FE0546D3
+:1030B00038B96FF00205284603B0BDEC028BBDE8BD
+:1030C000F08F14220021FEF779FC228CE16905F1D2
+:1030D0000800FEF74DFC208C013080B2FFF7E6FEC1
+:1030E000FFF7C8FE013880B220840130287463697C
+:1030F000228C1B782A4403F01F0363F03F0348F03F
+:1031000000411372384669602946FFF7EFFD01253B
+:10311000D1E700F10C034FF0000908EE103A4FF030
+:10312000800A4E464D4618EE100AFFF777FE83469A
+:103130000028BED014220021FEF740FC002E3AD118
+:10314000019BABF8083002220BF1080E1FFA82FC3B
+:103150000CF10100BCF1060F218C80B201D88E4227
+:103160002BD3FFF7A3FEFFF785FE626912780138C3
+:1031700002F01F028E4208BF4FF0400A42EA491295
+:103180001BFA80F14AEA020A013048F0004281F855
+:1031900008A08BF81000CBF8042059463846FFF7FA
+:1031A000A5FD238C0135B3422DB289F001094FF002
+:1031B000000AB8D17FE70022C6E7E169895D0EF811
+:1031C00002100136B6B20132C0E76FF0010572E7B6
+:1031D000F8B515460E463022002104461F46FEF77C
+:1031E000EDFB069B6360B5F5001F079BA76034BF2E
+:1031F0006A094FF6FF72A36297B2E66104F110000C
+:1032000000239A4206D800230360A782E382238327
+:10321000E360F8BD0660013330462036F1E7000078
+:1032200003781BB94BB2002BC8BF01707047000078
+:1032300000787047F8B50C46C969074611B9238C68
+:10324000002B37D1257E1F2D34D8387828BB228C0F
+:10325000072A2CD8268A36F003032BD14FF6FF70AD
+:10326000FFF7D0FD20F001003102400441EA056182
+:10327000400C41EA40254FF6FF7223462946384666
+:10328000FFF7FCFE002807DD626913780133DBB22B
+:103290001F2B88BF00231370F8BD218A2D0645EA35
+:1032A000012505432046FFF71DFE0246E5E76FF0C6
+:1032B0000300F1E76FF00100EEE7000070B58AB09F
+:1032C000044616460021282268461D46FEF776FB76
+:1032D000BDF83830ADF810300F9B05939DF84030A5
+:1032E0008DF81830119B07936946BDF84830ADF84A
+:1032F00020302046CDE90265FFF79CFF0AB070BD83
+:103300002DE9F041D36905460C4616460BB9138CDE
+:103310005BBB377E1F2F28D895F80080B8F1000FCF
+:1033200026D03046FFF7DEFD3378210241EAC33173
+:1033300041EA0801338A41EA076141EA0341024652
+:10334000334641F080012846FFF798FE00280ADD49
+:103350003378012B07D1726913780133DBB21F2B4D
+:1033600088BF00231370BDE8F0816FF00100FAE719
+:103370006FF00300F7E70000F0B58BB004460D4690
+:1033800017460021282268461E46FEF717FB9DF8C7
+:103390004C305A1E534253418DF800309DF8403056
+:1033A000ADF81030119B05939DF848308DF818301A
+:1033B000149B07936A46BDF85430ADF82030294677
+:1033C0002046CDE90276FFF79BFF0BB0F0BD000071
+:1033D000406A00B104307047436A1A684262026969
+:1033E0001A600361C38A013BC38270472DE9F04133
+:1033F000D0F82080194E14461D464146002709B9D1
+:10340000BDE8F081D1E90223A21A65EB03039642DD
+:1034100077EB03031ED2036A8B420DD1FFF78CFDBD
+:10342000036A1B68036203690B60C38A0161016A56
+:10343000013BC3828846E2E7FFF77EFD0B68C8F8D0
+:10344000003003690B60C38A0161013BC382D8F875
+:103450000010D4E788460968D1E700BF80841E00C9
+:103460002DE9F04F8BB00D46DDF8509014469B4689
+:103470008046002800F01981B9F1000F00F0158195
+:10348000531E3F2B00F21181012A03D1BBF1000F23
+:1034900040F00B810023CDE90833B8F81430B5EBC8
+:1034A000C30F4FEAC30703D300200BB0BDE8F08F72
+:1034B0002B199F42D8F80C303ABF7F1BFFB227462A
+:1034C0001BB9D8F81030002B7AD0272D4ED8C5F173
+:1034D0002806B7424FF000032CBFF6B23E460093D9
+:1034E0002946D8F8080008AB3246FFF741FCA7EBA5
+:1034F000060A35445FFA8AFAB8F8143003F100532B
+:10350000053BDB000493D8F80C3003932821039B80
+:1035100013B1BAF1000F2CD1D8F8100040B1BAF1B4
+:10352000000F05D0009608AB5246691AFFF720FC41
+:1035300038B2002FB8D066070AD00AAB03EBD4012B
+:10354000624211F8083C02F00702134101F8083CFE
+:10355000082C3CD9102C40F2B580202C40F2B780CA
+:10356000BBF1000F00F09C80082334E0BA4600262F
+:10357000C2E7049BE02B28BFE02306930B44AB4239
+:10358000059314D95A1B03980096924534BF5246AE
+:10359000D2B2691A08AB04300792FFF7E9FB079A29
+:1035A0001644AAEB020A1544F6B25FFA8AFA049BA3
+:1035B000069A05999B1A0493039B1B680393A6E73D
+:1035C0000093D8F8080008AB3A462946AEE7BBF1AD
+:1035D000000F13D00123B4EBC30F6CD0082C12D80A
+:1035E0009DF82030621E23FA02F2D50706D54FF06F
+:1035F000FF3202FA04F423438DF820309DF8203086
+:1036000089F8003051E7102C12D8BDF82030621E26
+:1036100023FA02F2D10706D54FF0FF3202FA04F482
+:103620002343ADF82030BDF82030A9F800303CE746
+:10363000202C0FD80899631E21FA03F3DA0705D569
+:103640004FF0FF3202FA04F40C430894089BC9F8C7
+:1036500000302AE7402C2BD0DDE90865611EC4F15B
+:103660002102A4F1210326FA01F105FA02F225FA5A
+:1036700003F311431943CB0712D50122A4F1200310
+:10368000C4F1200102FA03F322FA01F1A2405242EE
+:1036900043EA010363EB430332432B43CDE90823A1
+:1036A000DDE90823C9E90023FFE66FF00100FCE62D
+:1036B0006FF00800F9E6082CA0D9102CB3D9202C03
+:1036C000EED8C3E7BBF1000FADD0022383E7BBF117
+:1036D000000FBBD004237EE730B5012A144638BF63
+:1036E0000124402C85B028BF40240025012ACDE9C3
+:1036F000025518D81B788DF8083063070AD004AB40
+:1037000003EBD405624215F8083C02F0070293402F
+:1037100005F8083C009103462246002102A8FFF765
+:1037200027FB05B030BD082AE4D9102A03D81B882E
+:10373000ADF80830E1E7202A8DBFD3E900231B68EC
+:103740000293CDE90223D8E710B5CB681BB98B6093
+:103750000B618B8210BD04691A681C600361C38A07
+:10376000013BC382CA60F0E703064CBFC0F3C03020
+:103770000220704708B50246FFF7F6FF022806D17F
+:103780005306C2F30F2001D100F0030008BDC2F3BD
+:103790000740FBE72DE9F04F93B0CDE903230A681A
+:1037A00004461046FFF7E0FF022814BFC2F30626C6
+:1037B0000026002A0D46824680F2F28112F0C049AE
+:1037C00040F0EE81097B002900F0EA81022803D055
+:1037D0002378B34240F0E781C2F3046306931046B6
+:1037E00002F07F030593FFF7C5FF059B29444FEACD
+:1037F000834848EA0A4848EA4668CE78002300220F
+:10380000CDE90823F309834648EA0008029367D00C
+:10381000059B009302466768534608A92046B847AF
+:10382000002800F0C381276A4FB9414604F10C001B
+:10383000FFF702FB074690B96FF0020054E03B69C6
+:1038400098450DD03F68002FF9D1414604F10C0096
+:10385000FFF7F2FA07460028EED0236A3B602762A2
+:1038600097F817C006F01F08CCF3840CACEB0800E7
+:103870001FFA80FE0028B8BF0EF12000A8EB0C0351
+:103880001FFA83FED7E90221B8BF00B2002B0793CD
+:10389000BEBF0EF120031BB2079352EA010338D0DA
+:1038A000039BDFF824E39A1A049B4FF0000C63EBB0
+:1038B000010196457CEB01032BD36B7B97F81AE053
+:1038C000734519D1029B002B78D0012821DC786840
+:1038D000F8B9DFF8F0C2944570EB010316D337E076
+:1038E000276A27B96FF00C0013B0BDE8F08F3B6971
+:1038F0009845B5D03F68F4E7B24890427CEB0103AD
+:1039000001D30020F0E7029B002BFAD0079B0F2B7E
+:1039100017DCFA7DB30002F0030203F07C031343CB
+:10392000FB7539462046FFF707FB6B7BBB76029B96
+:103930003BB9FB7DC3F38402013262F38603FB755E
+:10394000D0E76A7BBB7E9A42DBD1029B002B35D04D
+:10395000B309022B32D0039BBB60049BFB60142293
+:1039600000210DA8FEF72AF8039B0A93049B0B93F2
+:103970002B1D0C932B7BADF83EB0013BDBB2ADF8B9
+:103980003C30069B8DF84230059B8DF8433094F80F
+:103990002C308DF840A083F001038DF844308DF871
+:1039A0004180A3680AA920469847FB7DC3F384039E
+:1039B000013303F01F039B02FB82A2E7FB7DC6F3EA
+:1039C0004012B2EBD31F40F0F480C3F384034345AD
+:1039D00040F0F280029A2B7BB609002A4DD0F20704
+:1039E0005DD4032B40F2EB80039BBB60049BFB6028
+:1039F0002B7BAE1D033BDBB23246394604F10C0093
+:103A0000FFF7ACFA00280CDA39462046FFF794FAA3
+:103A1000FB7DC3F38403013303F01F039B02FB828E
+:103A20000AE7DDE90884AB883B834FF6FF73C9F1F1
+:103A30002000A9F1200228FA09F104FA00F001435C
+:103A400024FA02F211431846C9B2FFF7C9F909F185
+:103A50000809B9F1400F0346E9D1B8822A7B033A3D
+:103A6000D2B23146FFF7CEF9FB7DB882DA43C2F31A
+:103A7000C01262F3C713FB7543E786B92E1D013BE5
+:103A8000DBB23246394604F10C00FFF767FA002832
+:103A9000BADB2A7BB88A013AD2B23146E2E7F98A28
+:103AA000C1F30901013B0429DAB25BD8281D0023C8
+:103AB00007F11B069A4208D910F801CB06F801C09D
+:103AC000013101330529DBB2F4D103990A9104993C
+:103AD0000B91934207F11B010C9138BF04337968B5
+:103AE0000D9134BF55FA83F300230E93FB8AADF892
+:103AF0003EB0C3F309031A44069B8DF84230059B80
+:103B00008DF8433094F82C30ADF83C2083F001035D
+:103B10008DF8443000238DF840A08DF841807B6003
+:103B20002A7BB88A013A291DFFF76CF93B8BB882D2
+:103B3000834203D1A3680AA92046984720460AA9D0
+:103B4000FFF702FEFB7DBA8AC3F38403013303F05F
+:103B50001F039B02FB823B8B9A420CBF00206FF03D
+:103B60001000C1E67B68002BAFD0052001E01C30BF
+:103B700033461E68002EFAD1091A081D2E1D18445E
+:103B800001EB090CBCF11B0F5FFA89F39DD89A4237
+:103B90009BD916F8013B00F8013B09F10109EFE759
+:103BA0006FF00900A0E66FF00A009DE66FF00B00D1
+:103BB0009AE66FF00D0097E66FF00E0094E66FF056
+:103BC0000F0091E640420F0080841E00EFF309834E
+:103BD00005494A6B22F001024A63683383F309887E
+:103BE000002383F31188704700EF00E0302080F35A
+:103BF000118862B60C4B0D4AD96821F4E0610904C2
+:103C0000090C0A43DA60D3F8FC20094942F08072BB
+:103C1000C3F8FC200A6842F001020A602022DA7729
+:103C200083F82200704700BF00ED00E00003FA05B2
+:103C3000001000E010B5302383F311880E4B5B6851
+:103C400013F4006314D0F1EE103AEFF30984683CEA
+:103C50004FF08073E361094BDB6B236684F30988C3
+:103C600000F094FF10B1064BA36110BD054BFBE7BC
+:103C700083F31188F9E700BF00ED00E000EF00E0FA
+:103C800043060008460600080268436811430160C5
+:103C900003B1184770470000024AD36843F0C003DD
+:103CA000D36070470010014010B5054C054A002153
+:103CB000204600F087FA044A044BC4E9972310BD5C
+:103CC00038470020993C00080010014080F0FA02BB
+:103CD000234A037C002918BF0A46012B30B5C0F8DF
+:103CE00068220CD11F4B984209D11F4B596C41F0EF
+:103CF00010015964596E41F0100159665B6EB2F9BA
+:103D000004501468D0F86032D0F85C12002D03EB38
+:103D10005403B3FBF4F3BEBF23F0070503F007031E
+:103D200043EA450394888B60D38843F040030B61DA
+:103D3000138943F001034B6144F4045343F02C0313
+:103D4000CB6004F4A05400230B60B4F5806F0B68C3
+:103D50004B680CBF7F23FF2380F8643230BD00BF67
+:103D6000906C000838470020003802402DE9F041EF
+:103D7000D0F85C62F7683368DA0504469DB20DD569
+:103D8000302383F311884FF480610430FFF77CFF08
+:103D90006FF480733360002383F31188302383F33F
+:103DA000118804F1040815F02F033AD183F3118828
+:103DB000380615D5290613D5302383F3118804F16D
+:103DC000380000F07BF900284EDA0821201DFFF7AB
+:103DD0005BFF4FF67F733B40F360002383F3118852
+:103DE0007A0616D56B0614D5302383F31188D4E9EF
+:103DF00013239A420AD1236C43B127F040073F04B2
+:103E00001021201D3F0CFFF73FFFF760002383F3D5
+:103E10001188D4F86822D36843B3BDE8F041106933
+:103E200018472B0714D015F0080F0CBF00214FF4D2
+:103E30008071E80748BF41F02001AA0748BF41F060
+:103E400040016B0748BF41F080014046FFF71CFF6F
+:103E5000AD06736805D594F864122046194000F049
+:103E6000E1F93568ADB29EE77060B6E7BDE8F08174
+:103E700000F1604303F561430901C9B283F80013FF
+:103E8000012200F01F039A4043099B0003F16043A5
+:103E900003F56143C3F880211A607047F8B51546F1
+:103EA00082680669AA420B46816938BF8568761A1E
+:103EB000B54204460BD218462A46FDF759FDA369C0
+:103EC0002B44A361A3685B1BA3602846F8BD0CD9F3
+:103ED00018463246FDF74CFDAF1BE1683A463044C8
+:103EE000FDF746FDE3683B44EBE718462A46FDF73D
+:103EF0003FFDE368E5E7000083689342F7B51546A8
+:103F0000044638BF8568D0E90460361AB5420BD242
+:103F10002A46FDF72DFD63692B446361A36828469B
+:103F20005B1BA36003B0F0BD0DD932460191FDF7D4
+:103F30001FFD0199E068AF1B3A463144FDF718FDBB
+:103F4000E3683B44E9E72A46FDF712FDE368E4E74E
+:103F500010B50A440024C361029B8460C0E90000DC
+:103F6000C0E90511C1600261036210BD08B5D0E966
+:103F70000532934201D1826882B98268013282603F
+:103F80005A1C42611970D0E904329A4224BFC368B6
+:103F90004361002100F0CCFE002008BD4FF0FF304F
+:103FA000FBE7000070B5302304460E4683F311880A
+:103FB000A568A5B1A368A269013BA360531CA361D6
+:103FC00015782269934224BFE368A361E3690BB1CA
+:103FD00020469847002383F31188284607E031469E
+:103FE000204600F095FE0028E2DA85F3118870BDC6
+:103FF0002DE9F74F04460E4617469846D0F81C9018
+:104000004FF0300A8AF311884FF0000B154665B166
+:104010002A4631462046FFF741FF034660B9414634
+:10402000204600F075FE0028F1D0002383F31188AC
+:10403000781B03B0BDE8F08FB9F1000F03D00190F9
+:104040002046C847019B8BF31188ED1A1E448AF362
+:104050001188DCE7C0E90511C160C3611144009B10
+:104060008260C0E90000016103627047F8B5044650
+:104070000D461646302383F31188A768A7B1A368BD
+:10408000013BA36063695A1C62611D70D4E904326C
+:104090009A4224BFE3686361E3690BB12046984705
+:1040A000002080F3118807E03146204600F030FE02
+:1040B0000028E2DA87F31188F8BD0000D0E9052373
+:1040C0009A4210B501D182687AB982680132826061
+:1040D0005A1C82611C7803699A4224BFC3688361B9
+:1040E000002100F025FE204610BD4FF0FF30FBE719
+:1040F0002DE9F74F04460E4617469846D0F81C9017
+:104100004FF0300A8AF311884FF0000B154665B165
+:104110002A4631462046FFF7EFFE034660B9414686
+:10412000204600F0F5FD0028F1D0002383F311882C
+:10413000781B03B0BDE8F08FB9F1000F03D00190F8
+:104140002046C847019B8BF31188ED1A1E448AF361
+:104150001188DCE7026843681143016003B1184726
+:10416000704700001430FFF743BF00004FF0FF33EB
+:104170001430FFF73DBF00003830FFF7B9BF000033
+:104180004FF0FF333830FFF7B3BF00001430FFF7B4
+:1041900009BF00004FF0FF311430FFF703BF0000EC
+:1041A0003830FFF763BF00004FF0FF323830FFF7C1
+:1041B0005DBF0000012914BF6FF01300002070479D
+:1041C000FFF772BD37B515460E4A02600022426005
+:1041D000C0E902220122044602740B46009000F15D
+:1041E0005C014FF480721430FFF7B2FE00942B464E
+:1041F0004FF4807204F5AE7104F13800FFF72AFF26
+:1042000003B030BDA46C000810B53023044683F31E
+:104210001188FFF75DFD02232374002080F31188CD
+:1042200010BD000038B5C36904460D461BB9042112
+:104230000844FFF78FFF294604F11400FFF796FEAC
+:10424000002806DA201D4FF40061BDE83840FFF772
+:1042500081BF38BD026843681143016003B118474C
+:104260007047000013B5446BD4F894341A68117881
+:10427000042915D1217C022912D11979128901232F
+:104280008B4013420CD101A904F14C0001F0E2FF74
+:10429000D4F89444019B21790246206800F0D6F9B5
+:1042A00002B010BD143001F065BF00004FF0FF33C5
+:1042B000143001F05FBF00004C3002F037B800004E
+:1042C0004FF0FF334C3002F031B80000143001F0F1
+:1042D00033BF00004FF0FF31143001F02DBF00005C
+:1042E0004C3002F003B800004FF0FF324C3001F0C8
+:1042F000FDBF00000020704710B5D0F894341A6854
+:1043000011780429044617D1017C022914D1597966
+:10431000528901238B4013420ED1143001F0C6FEA6
+:10432000024648B1D4F894444FF480736179206810
+:10433000BDE8104000F078B910BD0000406BFFF7F9
+:10434000DBBF0000704700007FB5124B0360002305
+:104350004360C0E90233012502260F4B0574044671
+:104360000290019300F18402294600964FF4807375
+:10437000143001F077FE094B0294CDE9006304F597
+:1043800023724FF48073294604F14C0001F03EFF84
+:1043900004B070BDCC6C00083D43000865420008C5
+:1043A0000B68302282F311880A7903EB82021062D3
+:1043B0004A790D3243F822008A7912B103EB820365
+:1043C00018620223C0F894140374002080F311884B
+:1043D0007047000038B5037F044613B190F854309D
+:1043E000ABB9201D01250221FFF734FF04F11400B1
+:1043F00025776FF0010100F0A7FC84F8545004F118
+:104400004C006FF00101BDE8384000F09DBC38BDA4
+:1044100010B5012104460430FFF71CFF0023237769
+:1044200084F8543010BD000038B50446002514301F
+:1044300001F030FE04F14C00257701F0FFFE201D55
+:1044400084F854500121FFF705FF2046BDE83840AD
+:10445000FFF752BF90F85C3003F06003202B07D1C8
+:1044600090F85D20212A4FF0000303D81F2A06D8B8
+:1044700000207047222AFBD1C0E9143303E0034A2D
+:1044800002650722426583650120704728230020CA
+:1044900037B5D0F894341A681178042904461AD133
+:1044A000017C022917D11979128901238B4013420B
+:1044B00011D100F14C05284601F080FF58B101A947
+:1044C000284601F0C7FED4F89444019B21790246A6
+:1044D000206800F0BBF803B030BD0000F0B500EB81
+:1044E000810385B01E6A04460D46FEB1302383F376
+:1044F000118804EB8507301D0821FFF7ABFEFB6830
+:104500005B691B6806F14C001BB1019001F0B0FE25
+:10451000019803A901F09EFE024648B1039B29467B
+:10452000204600F093F8002383F3118805B0F0BD16
+:10453000FB685A691268002AF5D01B8A013B1340B8
+:10454000F1D104F15C02EAE70D3138B550F82140B1
+:10455000DCB1302383F31188D4F8942413685279A2
+:1045600003EB8203DB689B695D6845B10421601839
+:10457000FFF770FE294604F1140001F0A1FD20466A
+:10458000FFF7BAFE002383F3118838BD704700009F
+:1045900001F002B910B501230446282200F8243B9B
+:1045A0000021FDF70BFA0023C4E9013310BD000020
+:1045B00038B50446302383F311880025C0E903553C
+:1045C000C0E90555C0E90755416001F0F5F802233F
+:1045D000237085F31188284638BD000070B500EBC4
+:1045E000810305465069DA600E46144618B1102260
+:1045F0000021FDF7E3F9A06918B110220021FDF7B1
+:10460000DDF931462846BDE8704001F09FB9000051
+:10461000826802F0011282600022C0E90422C0E92F
+:104620000622026201F01EBAF0B400EB8104478951
+:10463000E4680125A4698D403D4345812360002342
+:10464000A2606360F0BC01F039BA0000F0B400EB86
+:1046500081040789E468012564698D403D43058133
+:1046600023600023A2606360F0BC01F0B3BA0000D5
+:1046700070B50223002504460370C0E90255C0E965
+:104680000455C0E906554566056280F84C5001F0B6
+:10469000F9F863681B6823B129462046BDE87040DD
+:1046A000184770BD0378052B10B504460AD080F872
+:1046B00068300523037043681B680BB104219847D9
+:1046C0000023A36010BD00000178052906D190F8F1
+:1046D0006820436802701B6803B1184770470000E8
+:1046E00070B590F84C30044613B1002380F84C307C
+:1046F00004F15C02204601F0D7F963689B68B3B906
+:1047000094F85C3013F0600535D00021204601F0AC
+:104710008BFC0021204601F07DFC63681B6813B10F
+:10472000062120469847062384F84C3070BD204669
+:1047300098470028E4D0B4F86230626D9A4288BF8E
+:10474000636594F95C30656D002B4FF0300380F2A7
+:104750000381002D00F0F280092284F84C2083F3BD
+:1047600011880021D4E914232046FFF76FFF0023AE
+:1047700083F31188DAE794F85D2003F07F0343EABE
+:10478000022340F20232934200F0C58021D8B3F5F3
+:10479000807F48D00DD8012B3FD0022B00F09380B2
+:1047A000002BB2D104F16402226502226265A36586
+:1047B000C1E7B3F5817F00F09B80B3F5407FA4D1C2
+:1047C00094F85E30012BA0D1B4F8643043F00203BA
+:1047D00032E0B3F5006F4DD017D8B3F5A06F31D0EC
+:1047E000A3F5C063012B90D8636894F85E205E68DF
+:1047F00094F85F10B4F860302046B047002884D0A9
+:1048000043682365036863651AE0B3F5106F36D01B
+:1048100040F6024293427FF478AF5C4B236502235B
+:1048200063650023C3E794F85E30012B7FF46DAF1E
+:10483000B4F8643023F00203C4E91455A4F86430DA
+:10484000A56578E7B4F85C30B3F5A06F0ED194F8A5
+:104850005E3084F86630204601F06CF863681B68AF
+:1048600013B1012120469847032323700023C4E994
+:1048700014339CE704F1670323650123C3E723781E
+:10488000042B10D1302383F311882046FFF7C0FE9C
+:1048900085F311880321636884F8675021701B68D1
+:1048A0000BB12046984794F85E30002BDED084F898
+:1048B00067300423237063681B68002BD6D0022165
+:1048C00020469847D2E794F860301D0603F00F01A8
+:1048D00020460AD501F0DAF8012804D002287FF436
+:1048E00014AF2B4B9AE72B4B98E701F0C1F8F3E795
+:1048F00094F85E30002B7FF408AF94F8603013F02A
+:104900000F01B3D01A06204602D501F0A1FBADE796
+:1049100001F094FBAAE794F85E30002B7FF4F5AE2B
+:1049200094F8603013F00F01A0D01B06204602D58A
+:1049300001F07AFB9AE701F06DFB97E7142284F807
+:104940004C2083F311882B462A4629462046FFF740
+:104950006BFE85F31188E9E65DB1152284F84C20E1
+:1049600083F311880021D4E914232046FFF75CFE6D
+:10497000FDE60B2284F84C2083F311882B462A464F
+:1049800029462046FFF762FEE3E700BFFC6C000803
+:10499000F46C0008F86C000838B590F84C30044608
+:1049A000002B3ED0063BDAB20F2A34D80F2B32D878
+:1049B000DFE803F037313108223231313131313122
+:1049C00031313737456DB0F862309D4214D2C3683B
+:1049D0001B8AB5FBF3F203FB12556DB9302383F349
+:1049E00011882B462A462946FFF730FE85F31188A9
+:1049F0000A2384F84C300EE0142384F84C30302322
+:104A000083F3118800231A4619462046FFF70CFE4F
+:104A1000002383F3118838BD836D03B198470023C9
+:104A2000E7E70021204601F0FFFA0021204601F0CF
+:104A3000F1FA63681B6813B10621204698470623E4
+:104A4000D7E7000010B590F84C30142B044629D05D
+:104A500017D8062B05D001D81BB110BD093B022B7E
+:104A6000FBD80021204601F0DFFA0021204601F0AA
+:104A7000D1FA63681B6813B10621204698470623C4
+:104A800019E0152BE9D10B2380F84C30302383F348
+:104A9000118800231A461946FFF7D8FD002383F337
+:104AA0001188DAE7C3689B695B68002BD5D1836DF9
+:104AB00003B19847002384F84C30CEE700230375F8
+:104AC000826803691B6899689142FBD25A68036047
+:104AD0004260106058607047002303758268036964
+:104AE0001B6899689142FBD85A6803604260106065
+:104AF0005860704708B50846302383F311880B7D52
+:104B0000032B05D0042B0DD02BB983F3118808BDDE
+:104B10008B6900221A604FF0FF338361FFF7CEFFED
+:104B20000023F2E7D1E9003213605A60F3E7000096
+:104B3000FFF7C4BF054BD9680875186802681A608A
+:104B4000536001220275D860FBF766BDA8490020BA
+:104B500030B50C4BDD684B1C87B004460FD02B469C
+:104B6000094A684600F084F92046FFF7E3FF009BFE
+:104B700013B1684600F086F9A86907B030BDFFF7A9
+:104B8000D9FFF9E7A8490020F54A0008044B1A6844
+:104B9000DB6890689B68984294BF002001207047B2
+:104BA000A8490020084B10B51C68D86822681A6014
+:104BB000536001222275DC60FFF78EFF014620461C
+:104BC000BDE81040FBF728BDA8490020044B1A6837
+:104BD000DB6892689B689A4201D9FFF7E3BF704790
+:104BE000A849002038B5074C07490848012300258B
+:104BF0002370656001F01AFC0223237085F311888D
+:104C000038BD00BF104C0020046D0008A8490020EA
+:104C100008B572B6044B186500F066FC00F01AFD8A
+:104C2000024B03221A70FEE7A8490020104C002016
+:104C300000F05EB9EFF3118020B9EFF30583302265
+:104C400082F311887047000010B530B9EFF3058486
+:104C5000C4F3080414B180F3118810BDFFF7B6FF48
+:104C600084F31188F9E70000034A516853685B1A1E
+:104C70009842FBD8704700BF001000E08B60022311
+:104C800008618B82084670478368A3F1840243F869
+:104C9000142C026943F8442C426943F8402C094A19
+:104CA00043F8242CC26843F8182C022203F80C2C79
+:104CB000002203F80B2C044A43F8102CA3F1200027
+:104CC000704700BF31060008A849002008B5FFF76B
+:104CD000DBFFBDE80840FFF72BBF0000024BDB689D
+:104CE00098610F20FFF726BFA8490020302383F3E7
+:104CF0001188FFF7F3BF000008B50146302383F3A6
+:104D000011880820FFF724FF002383F3118808BDD2
+:104D1000064BDB6839B1426818605A601360436023
+:104D20000420FFF715BF4FF0FF307047A84900205F
+:104D30000368984206D01A6802605060996118466C
+:104D4000FFF7F6BE7047000038B504460D462068F0
+:104D5000844200D138BD036823605C608561FFF741
+:104D6000E7FEF4E710B503689C68A2420CD85C68C3
+:104D70008A600B604C602160596099688A1A9A6059
+:104D80004FF0FF33836010BD1B68121BECE700007F
+:104D90000A2938BF0A2170B504460D460A26601953
+:104DA00001F03EFB01F02AFB041BA54203D8751C51
+:104DB0002E460446F3E70A2E04D9BDE870400120D0
+:104DC00001F074BB70BD0000F8B5144B0D46D961FD
+:104DD00003F1100141600A2A1969826038BF0A2272
+:104DE000016048601861A818144601F00BFB0A27FF
+:104DF00001F004FB431BA342064606D37C1C281982
+:104E000001F00EFB27463546F2E70A2F04D9BDE82C
+:104E1000F840012001F04ABBF8BD00BFA8490020BE
+:104E2000F8B506460D4601F0E9FA0F4A134653F865
+:104E3000107F9F4206D12A4601463046BDE8F84021
+:104E4000FFF7C2BFD169BB68441A2C1928BF2C4692
+:104E5000A34202D92946FFF79BFF22463146034869
+:104E6000BDE8F840FFF77EBFA8490020B849002000
+:104E700010B4C0E9032300235DF8044B4361FFF73E
+:104E8000CFBF000010B5194C236998420DD0D0E96E
+:104E90000032816813605A609A680A449A6000235D
+:104EA00003604FF0FF33A36110BD2346026843F84F
+:104EB000102F53600022026022699A4203D1BDE89C
+:104EC000104001F0A7BA936881680B44936001F029
+:104ED00095FA2269E1699268441AA242E4D9114420
+:104EE000BDE81040091AFFF753BF00BFA8490020D2
+:104EF0002DE9F047DFF8BC8008F110072C4ED8F8F8
+:104F0000105001F07BFAD8F81C40AA68031B9A42A3
+:104F10003ED81444D5E900324FF00009C8F81C40CF
+:104F200013605A60C5F80090D8F81030B34201D130
+:104F300001F070FA89F31188D5E9033128469847C2
+:104F4000302383F311886B69002BD8D001F056FA17
+:104F50006A69A0EB04094A4582460DD2022001F09D
+:104F6000A5FA0022D8F81030B34208D1514628469D
+:104F7000BDE8F047FFF728BF121A2244F2E712EB10
+:104F8000090938BF4A4629463846FFF7EBFEB5E720
+:104F9000D8F81030B34208D01444211AC8F81C00C5
+:104FA000A960BDE8F047FFF7F3BEBDE8F08700BF9A
+:104FB000B8490020A849002000207047FEE7000003
+:104FC000704700004FF0FF307047000002290CD0FE
+:104FD000032904D00129074818BF00207047032A7D
+:104FE00005D8054800EBC200704704487047002010
+:104FF000704700BFF06D000838230020A46D000842
+:1050000070B59AB00546084601A9144600F0C2F8EA
+:1050100001A8FCF7CBFC431C5B00C5E9003400226F
+:10502000237003236370C6B201AB02341046D1B2C1
+:105030008E4204F1020401D81AB070BD13F8011BAE
+:1050400004F8021C04F8010C0132F0E708B5302323
+:1050500083F311880348FFF71BFA002383F31188B9
+:1050600008BD00BF184C002090F85C3003F01F0210
+:10507000012A07D190F85D200B2A03D10023C0E953
+:10508000143315E003F06003202B08D1B0F8603032
+:105090002BB990F85D20212A03D81F2A04D8FFF7E6
+:1050A000D9B9222AEBD0FAE7034A02650722426502
+:1050B00083650120704700BF2F23002007B5052915
+:1050C00017D8DFE801F0191603191920302383F3EC
+:1050D0001188104A01900121FFF780FA01980E4AC9
+:1050E0000221FFF77BFA0D48FFF79EF9002383F3B7
+:1050F000118803B05DF804FB302383F3118807485F
+:10510000FFF768F9F2E7302383F311880348FFF7CC
+:105110007FF9EBE7446D0008686D0008184C00202B
+:1051200038B50C4D0C4C0D492A4604F10800FFF728
+:1051300067FF05F1CA0204F110000949FFF760FF9B
+:1051400005F5CA7204F118000649BDE83840FFF7BA
+:1051500057BF00BFE050002038230020106D00082A
+:10516000216D00083A6D000870B5044608460D46EA
+:10517000FCF71CFCC6B22046013403780BB9184674
+:1051800070BD32462946FCF7FDFB0028F3D1012013
+:10519000F6E700002DE9F04705460C46FCF706FC53
+:1051A0002B49C6B22846FFF7DFFF08B10E36F6B22C
+:1051B00028492846FFF7D8FF08B11036F6B2632E0B
+:1051C0000BD8DFF88C80DFF88C90234FDFF894A0A9
+:1051D0002E7846B92670BDE8F08729462046BDE8FE
+:1051E000F04701F0CDBC252E2ED10722414628469E
+:1051F000FCF7C8FB70B9194B224603F1140153F8B0
+:10520000040B42F8040B8B42F9D11B78137007355D
+:105210001534DDE7082249462846FCF7B3FB98B968
+:105220000F4BA21C197809090232C95D02F8041C4F
+:1052300013F8011B01F00F015345C95D02F8031C6F
+:10524000F0D118340835C3E704F8016B0135BFE726
+:10525000106E00083A6D00082E6E0008186E0008E7
+:10526000107AFF1F1C7AFF1FBFF34F8F024AD368CB
+:10527000DB03FCD4704700BF003C024008B5094B7B
+:105280001B7873B9FFF7F0FF074B1A69002ABFBFFD
+:10529000064A5A6002F188325A601A6822F4806223
+:1052A0001A6008BD3E530020003C024023016745C0
+:1052B00008B50B4B1B7893B9FFF7D6FF094B1A695A
+:1052C00042F000421A611A6842F480521A601A6869
+:1052D00022F480521A601A6842F480621A6008BD93
+:1052E0003E530020003C02400728F0B516D80C4C75
+:1052F0000C4923787BB90C4D0E4608234FF0006211
+:1053000055F8047B46F8042B013B13F0FF033A44A5
+:10531000F6D10123237051F82000F0BD0020FCE7F6
+:105320006053002040530020406E0008014B53F8AA
+:1053300020007047406E000808207047072810B50D
+:10534000044601D9002010BDFFF7CEFF064B53F8ED
+:1053500024301844C21A0BB90120F4E71268013254
+:10536000F0D1043BF6E700BF406E0008072838B5CF
+:10537000044628D8FFF75EFCFFF776FFFFF77EFFB5
+:10538000124AF323D360E300DBB243F4007343F02B
+:1053900002031361136943F4803313610546204609
+:1053A000FFF762FFFFF7A0FF094B53F8241000F04E
+:1053B0004DF92846FFF77CFFFFF746FC2046BDE885
+:1053C0003840FFF7BBBF002038BD00BF003C0240A3
+:1053D000406E000812F001032DE9F04105460E462B
+:1053E00014464BD18118334A914261D8324B1B6825
+:1053F00013F001035CD0314FFFF71CFCFFF73EFFB9
+:10540000F323FB60FFF730FF314640F20128032C05
+:1054100018D824F00104294E0C446D1A40F20118EA
+:10542000A142336905EB01072AD123F0010333615F
+:10543000FFF73EFFFFF708FC0120BDE8F081043CC8
+:105440000435E4E7AB07E4D13B6923F440733B61E7
+:105450003B6943EA08033B6151F8046B2E60BFF3DC
+:105460004F8FFFF701FF2B689E42E8D03B6923F086
+:1054700001033B61FFF71CFFFFF7E6FB0020DCE7C1
+:1054800023F440733361336943EA080333610B88C3
+:105490003B80BFF34F8FFFF7E7FE3F8831F8023BB9
+:1054A000BFB2BB42BCD0336923F001033361E1E7F3
+:1054B0001846C2E70000080800380240003C0240DD
+:1054C000084908B50B7828B11BB9FFF7D7FE0123AF
+:1054D0000B7008BD002BFCD0BDE808400870FFF73A
+:1054E000E7BE00BF3E5300204FF480214FF0005034
+:1054F00000F0AEB80846114601F0A6BA012001F04E
+:10550000A3BA0000084601F0BDBA000070B582B031
+:10551000FFF790FB0E4E054600F070FF3268904298
+:1055200037BF0C4A0B49516814682EBFD1E90041BE
+:10553000013151600419034641F1000128460191EF
+:105540003360FFF781FB0199204602B070BD00BFB8
+:10555000645300206853002070B582B0FFF76AFBE7
+:10556000104E054600F04AFF3268904237BF0E4A9F
+:105570000D49516814682EBFD1E9004101315160D5
+:10558000041941F100010346284601913360FFF7F9
+:105590005BFB01994FF47A7200232046FAF728FE4C
+:1055A00002B070BD645300206853002010B502445F
+:1055B000064BD2B2904200D110BD441C00B253F849
+:1055C000200041F8040BE0B2F4E700BF502800408F
+:1055D0000F4B30B51C6F240407D41C6F44F40074C7
+:1055E0001C671C6F44F400441C670A4C236843F496
+:1055F000807323600244084BD2B2904200D130BD88
+:10560000441C00B251F8045B43F82050E0B2F4E7C8
+:1056100000380240007000405028004007B50122C9
+:1056200001A90020FFF7C2FF019803B05DF804FB59
+:1056300013B50446FFF7F2FFA04205D0012201A9ED
+:1056400000200194FFF7C4FF02B010BD70470000B6
+:105650007047000070470000074B45F255521A6032
+:1056600002225A6040F6FF729A604CF6CC421A60F1
+:10567000024B01221A707047003000407453002022
+:10568000034B1B781BB1034B4AF6AA221A607047E2
+:105690007453002000300040034B1A681AB9034AC3
+:1056A000D2F874281A60704770530020003002400E
+:1056B000024B4FF08072C3F87428704700300240EC
+:1056C00008B5FFF7E9FF024B1868C0F3407008BD4A
+:1056D0007053002008B5FFF7DFFF024B1868C0F3D6
+:1056E000007008BD7053002070470000FEE7000006
+:1056F0000A4B0B480B4A90420BD30B4BDA1C121A85
+:10570000C11E22F003028B4238BF00220021FCF7A9
+:1057100055B953F8041B40F8041BECE7447000082B
+:1057200090540020905400209054002070B5D0E98F
+:105730001B439E6800224FF0FF3504EB42135101DA
+:10574000D3F800090028BEBFD3F8000940F080401C
+:10575000C3F80009D3F8000B0028BEBFD3F8000B34
+:1057600040F08040C3F8000B013263189642C3F842
+:105770000859C3F8085BE0D24FF00113C4F81C3895
+:1057800070BD0000890141F02001016103699B06A1
+:10579000FCD41220FFF768BA10B5054C2046FEF77E
+:1057A000F9FE4FF0A043E366024B236710BD00BF34
+:1057B00078530020846E000870B50378012B0546ED
+:1057C00050D12A4BC46E98421BD1294B5A6B42F0E0
+:1057D00080025A635A6D42F080025A655A6D5A69C6
+:1057E00042F080025A615A6922F080025A610E2109
+:1057F00043205B69FEF73CFB1E4BE3601E4BC4F885
+:1058000000380023C4F8003EC0232360EE6E4FF43E
+:105810000413A3633369002BFCDA012333610C20EA
+:10582000FFF722FA3369DB07FCD41220FFF71CFADA
+:105830003369002BFCDA0026A6602846FFF776FFC6
+:105840006B68C4F81068DB68C4F81468C4F81C6896
+:105850004BB90A4BA3614FF0FF336361A36843F078
+:105860000103A36070BD064BF4E700BF785300202E
+:10587000003802404014004003002002003C30C0C9
+:10588000083C30C0F8B5C46E054600212046FFF73D
+:1058900079FF296F00234FF001128F68C4F8343864
+:1058A0004FF00066C4F81C284FF0FF3004EB4312A1
+:1058B00001339F42C2F80069C2F8006BC2F80809C0
+:1058C000C2F8080BF2D20B68EA6E6B6763621023B2
+:1058D0001361166916F01006FBD11220FFF7C4F908
+:1058E000D4F8003823F4FE63C4F80038A36943F405
+:1058F000402343F01003A3610923C4F81038C4F80F
+:1059000014380A4BEB604FF0C043C4F8103B084B0F
+:10591000C4F8003BC4F81069C4F800396B6F03F198
+:10592000100243F480136A67A362F8BD606E00083A
+:1059300040800010C26E90F86610D2F8003823F450
+:10594000FE6343EA0113C2F8003870472DE9F843BB
+:1059500000EB8103C56EDA68166806F00306731E55
+:10596000022B05EB41130C4680460FFA81F94FEAF2
+:1059700041104FF00001C3F8101B4FF0010104F17A
+:10598000100398BFB60401FA03F391698EBF334E3A
+:1059900006F1805606F5004600293AD0578A04F1F0
+:1059A0005801490137436F50D5F81C180B43C5F80F
+:1059B0001C382B180021C3F8101953690127611EE8
+:1059C000A7409BB3138A928B9B08012A88BF53433D
+:1059D000D8F87420981842EA034301F1400205EB1D
+:1059E0008202C8F87400214653602846FFF7CAFEB9
+:1059F00008EB8900C3681B8A43EA84534834640176
+:105A00001E432E51D5F81C381F43C5F81C78BDE83D
+:105A1000F88305EB4917D7F8001B21F40041C7F8BC
+:105A2000001BD5F81C1821EA0303C0E704F13F036B
+:105A300005EB83030A4A5A6028462146FFF7A2FE77
+:105A400005EB4910D0F8003923F40043C0F80039C1
+:105A5000D5F81C3823EA0707D7E700BF00800010FD
+:105A600000040002026F12684267FFF75FBE000089
+:105A70005831C36E49015B5813F4004004D013F44D
+:105A8000001F0CBF02200120704700004831C36E88
+:105A900049015B5813F4004004D013F4001F0CBFFD
+:105AA000022001207047000000EB8101CB68196AD9
+:105AB0000B6813604B6853607047000000EB810374
+:105AC00030B5DD68AA691368D36019B9402B84BF6B
+:105AD000402313606B8A1468C26E1C44013CB4FB03
+:105AE000F3F46343033323F0030302EB411043EA6F
+:105AF000C44343F0C043C0F8103B2B6803F00303DA
+:105B0000012B09B20ED1D2F8083802EB411013F480
+:105B1000807FD0F8003B14BF43F0805343F0005324
+:105B2000C0F8003B02EB4112D2F8003B43F00443C3
+:105B3000C2F8003B30BD00002DE9F041244DEE6E6F
+:105B400006EB40130446D3F8087BC3F8087B3807FC
+:105B50000AD5D6F81438190706D505EB8403214673
+:105B6000DB6828465B689847FA071FD5D6F81438D3
+:105B7000DB071BD505EB8403D968CCB98B69488A50
+:105B80005A68B2FBF0F600FB16228AB91868DA6888
+:105B900090420DD2121AC3E90024302383F31188F6
+:105BA0000B482146FFF78AFF84F31188BDE8F08196
+:105BB000012303FA04F26B8923EA02036B81CB68A9
+:105BC000002BF3D021460248BDE8F041184700BF42
+:105BD0007853002000EB810370B5DD68C36E6C69FB
+:105BE0002668E6604A0156BB1A444FF40020C2F80A
+:105BF00010092A6802F00302012A0AB20ED1D3F872
+:105C0000080803EB421410F4807FD4F8000914BF95
+:105C100040F0805040F00050C4F8000903EB4212FD
+:105C2000D2F8000940F00440C2F80009D3F8340863
+:105C3000012202FA01F10143C3F8341870BD19B909
+:105C4000402E84BF4020206020682E8A8419013CA9
+:105C5000B4FBF6F440EAC44040F000501A44C6E7F2
+:105C60002DE9F8433B4DEE6E06EB40130446D3F8A6
+:105C70000889C3F8088918F0010F4FEA40171AD0B5
+:105C8000D6F81038DB0716D505EB8003D9684B69C9
+:105C90001868DA68904230D2121A4FF000091A6080
+:105CA000C3F80490302383F3118821462846FFF778
+:105CB00091FF89F3118818F0800F1CD0D6F8343882
+:105CC0000126A640334216D005EB8403ED6ED3F8CF
+:105CD0000CC0DCF814200134E4B2D2F800E005EB8B
+:105CE00004342F445168714515D3D5F8343823EA6C
+:105CF0000606C5F83468BDE8F883012303FA04F208
+:105D00002B8923EA02032B818B68002BD3D02146F9
+:105D100028469847CFE7BCF81000AEEB010383425A
+:105D200028BF0346D7F8180980B2B3EB800FE2D83A
+:105D30009068A0F1040959F8048FC4F80080A0EB22
+:105D400009089844B8F1040FF5D818440B44906042
+:105D50005360C7E7785300202DE9F74FAC4CE56E50
+:105D60006E69AB691E4016F480586E6107D02046FC
+:105D7000FEF77EFC03B0BDE8F04FFDF75BBF002EE1
+:105D800012DAD5F8003EA2489B071EBFD5F8003EA8
+:105D900023F00303C5F8003ED5F8043823F00103CF
+:105DA000C5F80438FEF790FC370505D59848FFF78D
+:105DB000BDFC9748FEF776FCB0040CD5D5F8083842
+:105DC00013F0060FEB6823F470530CBF43F4105329
+:105DD00043F4A053EB6031071BD56368DB681BB944
+:105DE000AB6923F00803AB612378052B0CD1D5F800
+:105DF000003E87489A071EBFD5F8003E23F00303F4
+:105E0000C5F8003EFEF760FC6368DB680BB18048B4
+:105E10009847F30200F18980B70227D5D4F86C9037
+:105E2000DFF8ECB100274FF0010A09EB4712D2F876
+:105E3000003B03F44023B3F5802F11D1D2F8003B8F
+:105E4000002B0DDA62890AFA07F322EA0303638161
+:105E500004EB8703DB68DB6813B139465846984783
+:105E6000236F01379B68FFB29F42DED9F00617D53A
+:105E7000E76E3A6AC2F30A1002F00F0302F4F0125E
+:105E8000B2F5802F00F09980B2F5402F08D104EBD5
+:105E900083030022DB681B6A07F5805790427ED19E
+:105EA0003303D5F818481DD5E70302D50020FFF7C6
+:105EB00043FEA50302D50120FFF73EFE600302D595
+:105EC0000220FFF739FE210302D50320FFF734FE3D
+:105ED000E20202D50420FFF72FFEA30202D505201F
+:105EE000FFF72AFE77037FF545AFE60702D50020CE
+:105EF000FFF7B6FEA50702D50120FFF7B1FE600748
+:105F000002D50220FFF7ACFE210702D50320FFF7E0
+:105F1000A7FEE20602D50420FFF7A2FEA3067FF546
+:105F200029AF0520FFF79CFE24E7E36EDFF8E0A031
+:105F3000019300274FF00109236F9B685FFA87FBED
+:105F40009B453FF669AF019B03EB4B13D3F8001958
+:105F500001F44021B1F5802F1FD1D3F80019002999
+:105F60001BDAD3F8001941F09041C3F80019D3F8B7
+:105F700000190029FBDB5946E06EFFF703FC21897D
+:105F800009FA0BF321EA0303238104EB8B03DB689B
+:105F90009B6813B15946504698470137CCE79107A3
+:105FA00008BFD7F80080072A98BF03F8018B02F1D9
+:105FB000010298BF4FEA182870E7023304EB83020E
+:105FC00007F580575268D2F818C0DCF80820DCE9E1
+:105FD000001CA1EB0C0C002188420AD104EB8304C5
+:105FE00063689B699A6802449A605A6802445A60DE
+:105FF00056E711F0030F08BFD7F800808C4588BF23
+:1060000002F8018B01F1010188BF4FEA1828E3E78C
+:1060100078530020C36E03EB4111D1F8003B43F4E9
+:106020000013C1F8003B7047C36E03EB4111D1F878
+:10603000003943F40013C1F800397047C36E03EB15
+:106040004111D1F8003B23F40013C1F8003B704725
+:10605000C36E03EB4111D1F8003923F40013C1F8EA
+:106060000039704730B5039C0172043304FB0325EB
+:10607000C0E90653049B03630021059BC160C0E98E
+:106080000000C0E90422C0E90842C0E90A114363E4
+:1060900030BD0000416A0022C0E90411C0E90A22B3
+:1060A000C2606FF00101FEF74FBE0000D0E904327C
+:1060B000934201D1C2680AB9181D70470020704789
+:1060C00003691960C2680132C260C26913448269FF
+:1060D0000361934224BF436A03610021FEF728BE97
+:1060E00038B504460D46E3683BB16269131D12687A
+:1060F000A3621344E362002007E0237A33B9294600
+:106100002046FEF705FE0028EDDA38BD6FF00100ED
+:10611000FBE70000C368C269013BC36043691344E5
+:1061200082694361934224BF436A436100238362CF
+:10613000036B03B11847704770B53023044683F3EF
+:106140001188866A3EB9FFF7CBFF054618B186F382
+:106150001188284670BDA36AE26A13F8015BA36246
+:10616000934202D32046FFF7D5FF002383F3118823
+:10617000EFE700002DE9F84F04460E461746984613
+:106180004FF0300989F311880025AA46D4F828B0C9
+:10619000BBF1000F09D141462046FFF7A1FF20B116
+:1061A0008BF311882846BDE8F88FD4E90A12A7EBD3
+:1061B000050B521A934528BF9346BBF1400F1BD9DC
+:1061C000334601F1400251F8040B43F8040B9142AD
+:1061D000F9D1A36A40334036A3624035D4E90A239B
+:1061E0009A4202D32046FFF795FF8AF31188BD42F9
+:1061F000D8D289F31188C9E730465A46FBF7B8FB75
+:10620000A36A5B445E44A3625D44E7E710B5029C69
+:106210000172043303FB0421C0E906130023C0E923
+:106220000A33039B0363049BC460C0E90000C0E918
+:106230000422C0E90842436310BD0000026AC26044
+:10624000426AC0E904220022C0E90A226FF001017B
+:10625000FEF77ABDD0E904239A4201D1C26822B97F
+:10626000184650F8043B0B60704700231846FAE7C5
+:10627000C368C2690133C3604369134482694361DF
+:10628000934224BF436A43610021FEF751BD0000E1
+:1062900038B504460D46E3683BB123691A1DA26276
+:1062A000E2691344E362002007E0237A33B9294608
+:1062B0002046FEF72DFD0028EDDA38BD6FF0010015
+:1062C000FBE7000003691960C268013AC260C26955
+:1062D000134482690361934224BF436A036100232C
+:1062E0008362036B03B118477047000070B5302319
+:1062F0000D460446114683F31188866A2EB9FFF7CE
+:10630000C7FF10B186F3118870BDA36A1D70A36A20
+:10631000E26A01339342A36204D3E169204604395F
+:10632000FFF7D0FF002080F31188EDE72DE9F84F4B
+:1063300004460D46904699464FF0300A8AF311887C
+:106340000026B346A76A4FB949462046FFF7A0FF8B
+:1063500020B187F311883046BDE8F88FD4E90A07E9
+:106360003A1AA8EB0607974228BF1746402F1BD9B9
+:1063700005F1400355F8042B40F8042B9D42F9D158
+:10638000A36A4033A3624036D4E90A239A4204D375
+:10639000E16920460439FFF795FF8BF311884645E4
+:1063A000D9D28AF31188CDE729463A46FBF7E0FABD
+:1063B000A36A3B443D44A3623E44E5E7D0E904239D
+:1063C0009A4217D1C3689BB1836A8BB1043B9B1A75
+:1063D0000ED01360C368013BC360C3691A4483696C
+:1063E00002619A4224BF436A03610023836201234E
+:1063F000184670470023FBE700F0CCB84FF080430D
+:10640000586A70474FF08043002258631A61022295
+:10641000DA6070474FF080430022DA607047000076
+:106420004FF0804358637047FEE7000070B51B4B88
+:1064300001630025044686B0586085620E46FDF76C
+:10644000D5FB04F11003C4E904334FF0FF33C4E972
+:106450000635C4E90044A560E562FFF7CFFF2B468F
+:106460000246C4E9082304F134010D4A256580235E
+:106470002046FEF703FC0123E0600A4A0375009200
+:1064800072680192B268CDE90223074B6846CDE9F4
+:106490000435FEF71BFC06B070BD00BF104C002099
+:1064A000906E0008956E000829640008024AD36ABD
+:1064B0001843D062704700BFA84900204B68436072
+:1064C0008B688360CB68C3600B6943614B6903626F
+:1064D0008B6943620B6803607047000008B5234B6B
+:1064E00023481A6942F0FF021A611A6922F0FF027A
+:1064F0001A611A691A6B42F0FF021A631A6D42F0B0
+:10650000FF021A651B4A1B6D1146FFF7D7FF02F108
+:106510001C0100F58060FFF7D1FF02F1380100F5A2
+:106520008060FFF7CBFF02F1540100F58060FFF7B8
+:10653000C5FF02F1700100F58060FFF7BFFF02F1B7
+:106540008C0100F58060FFF7B9FF02F1A80100F5AA
+:106550008060FFF7B3FF02F1C40100F58060FFF730
+:10656000ADFFBDE8084000F08FB800BF0038024022
+:10657000000002409C6E000808B500F01BFAFEF710
+:1065800031FBFFF789F8BDE80840FEF7C9BD000000
+:10659000704700000F4B1A6C42F001021A641A6E29
+:1065A00042F001021A660C4A1B6E936843F0010325
+:1065B00093604FF0804331229A624FF0FF32DA62EB
+:1065C00000229A615A63DA605A6001225A611A60A5
+:1065D000704700BF00380240002004E04FF08042C6
+:1065E00008B51169D3680B40D9B2C9439B07116143
+:1065F00007D5302383F31188FEF71AFB002383F3BA
+:10660000118808BD1E4B1A6962F0FF021A611A69EF
+:10661000D2B21A614FF0FF301A695A6958610021ED
+:106620005A6959615A691A6A62F080521A621A6A82
+:1066300002F080521A621A6A5A6A58625A6A596299
+:106640005A6A1A6C42F080521A641A6E42F08052F2
+:106650001A661A6E0B4A106840F480701060186F4A
+:1066600000F44070B0F5007F1EBF4FF48030186713
+:106670001967536823F40073536000F073B900BFC7
+:1066800000380240007000403B4B3C4A1A643C4AD0
+:106690004FF4404111601A6842F001021A601A6812
+:1066A0009007FCD59A6822F003029A60324B9A68F0
+:1066B00012F00C02FBD1196801F0F90119609A601F
+:1066C0001A6842F480321A601A689103FCD55A6F36
+:1066D00042F001025A67284B5A6F9207FCD5294AAB
+:1066E0005A601A6842F080721A60254A536858044A
+:1066F000FCD5214B1A689101FCD5234AC3F88420AC
+:106700001A6842F080621A601A681201FCD51F4AAA
+:106710009A600322C3F88C204FF00062C3F89420E3
+:106720001B4B1A681B4B9A421B4B21D11B4A116809
+:106730001B4A91421CD140F203121A60164A136898
+:1067400003F00F03032BFAD10B4B9A6842F00202BD
+:106750009A609A6802F00C02082AFAD15A6C42F444
+:1067600080425A645A6E42F480425A665B6E7047A9
+:1067700040F20372E1E700BF00380240000400105D
+:10678000007000400819400210300024009488383E
+:10679000002004E011640020003C024000ED00E015
+:1067A00041C20F41074A08B5536903F00103536121
+:1067B00023B1054A13680BB150689847BDE80840FB
+:1067C000FDF738BA003C014008540020074A08B5DC
+:1067D000536903F00203536123B1054A93680BB177
+:1067E000D0689847BDE80840FDF724BA003C014056
+:1067F00008540020074A08B5536903F004035361A5
+:1068000023B1054A13690BB150699847BDE80840A8
+:10681000FDF710BA003C014008540020074A08B5B3
+:10682000536903F00803536123B1054A93690BB11F
+:10683000D0699847BDE80840FDF7FCB9003C01402D
+:1068400008540020074A08B5536903F01003536148
+:1068500023B1054A136A0BB1506A9847BDE8084056
+:10686000FDF7E8B9003C014008540020164B10B574
+:106870005C6904F478725A61A30604D5134A936ADA
+:106880000BB1D06A9847600604D5104A136B0BB160
+:10689000506B9847210604D50C4A936B0BB1D06B13
+:1068A0009847E20504D5094A136C0BB1506C984720
+:1068B000A30504D5054A936C0BB1D06C9847BDE88D
+:1068C0001040FDF7B7B900BF003C0140085400205C
+:1068D000194B10B55C6904F47C425A61620504D519
+:1068E000164A136D0BB1506D9847230504D5134A12
+:1068F000936D0BB1D06D9847E00404D50F4A136E29
+:106900000BB1506E9847A10404D50C4A936E0BB19D
+:10691000D06E9847620404D5084A136F0BB1506FCC
+:106920009847230404D5054A936F0BB1D06F98475D
+:10693000BDE81040FDF77EB9003C0140085400203E
+:1069400008B50348FDF712FABDE80840FDF772B933
+:106950003847002008B5FFF741FEBDE80840FDF7C5
+:1069600069B90000062108B50846FDF781FA06213D
+:106970000720FDF77DFA06210820FDF779FA0621A8
+:106980000920FDF775FA06210A20FDF771FA0621A4
+:106990001720FDF76DFA06212820FDF769FA072177
+:1069A0001C20FDF765FABDE808400C212520FDF705
+:1069B0005FBA000008B5FFF725FE00F00DF8FDF7FF
+:1069C000FFFBFDF7E5FDFDF7BDFCFFF7E1FDBDE8D1
+:1069D0000840FFF711BD00000023054A19460133A6
+:1069E000102BC2E9001102F10802F8D1704700BF74
+:1069F000085400200B460146184600F02DB8000050
+:106A000000F040B8012838BF012010B504462046E8
+:106A100000F030F830B900F007F808B900F00CF8D1
+:106A20008047F4E710BD0000024B1868BFF35B8F8E
+:106A3000704700BF8854002008B5062000F084F895
+:106A40000120FEF7BBFA0000024B0A460146186817
+:106A5000FEF750BD5823002010B5054C13462CB14D
+:106A60000A4601460220AFF3008010BD2046FCE735
+:106A700000000000024B01461868FEF73FBD00BF52
+:106A800058230020024B01461868FEF73BBD00BFAB
+:106A90005823002010B501390244904201D1002052
+:106AA00005E0037811F8014FA34201D0181B10BD77
+:106AB0000130F2E72DE9F041A3B1C91A177801447A
+:106AC000044603F1FF3C8C42204601D9002009E036
+:106AD0000578BD4204F10104F5D10CEB0405D6188C
+:106AE000A54201D1BDE8F08115F8018D16F801ED40
+:106AF000F045F5D0E7E700001F2938B504460D46FC
+:106B000004D9162303604FF0FF3038BD426C12B138
+:106B100052F821304BB9204600F030F82A460146A1
+:106B20002046BDE8384000F017B8012B0AD0591CA8
+:106B300003D1162303600120E7E7002442F8254033
+:106B4000284698470020E0E7024B01461868FFF707
+:106B5000D3BF00BF5823002038B5074D002304469B
+:106B6000084611462B60FEF72DFA431C02D12B6814
+:106B700003B1236038BD00BF8C540020FEF71CBA5F
+:106B8000034611F8012B03F8012B002AF9D17047B5
+:106B9000696E2E7369657272616165726F7370617F
+:106BA00063652E507265636973696F6E506F696EAD
+:106BB0007400000053544D3332463F3F3F0053545E
+:106BC0004D3332463430780053544D3332463432EC
+:106BD000780053544D333246343436585800000050
+:106BE000012033000010410001105A000310590029
+:106BF0000710310000000000B46B0008130400000F
+:106C0000BE6B000819040000C86B000821040000D6
+:106C1000D26B000840A2E4F1646891060041A3E54C
+:106C2000F2656992070000004261642043414E49C9
+:106C30006661636520696E6465782E0080000000DF
+:106C40000080000000008000000000000000000044
+:106C5000392100082129000881280008492100085D
+:106C60007D210008792300084D2100085D210008DE
+:106C7000512100085921000855210008A1220008CF
+:106C800061210008F12B000871210008752200081D
+:106C9000009600000000000000000000000000005E
+:106CA0000000000000000000814100086D41000864
+:106CB000A941000895410008A14100088D41000844
+:106CC0007941000865410008B54100080000000056
+:106CD000C1420008AD420008E9420008D542000860
+:106CE000E1420008CD420008B9420008A542000870
+:106CF000F542000800000000010000000000000054
+:106D000063300000006D0008004A0020104C002095
+:106D1000536965727261204165726F73706163655A
+:106D2000005369657272612D507265636973696F92
+:106D30006E506F696E742D424C0025534552494187
+:106D40004C2500000200000000000000DD440008A7
+:106D50004945000840004000B0500020C0500020CD
+:106D6000020000000000000003000000000000001E
+:106D70008D4500080000000010000000D0500020E9
+:106D80000000000001000000000000007853002017
+:106D900001010200BD500008CD4F000869500008F5
+:106DA0004D50000843000000AC6D0008090243008C
+:106DB000020100C0320904000001020201000524A2
+:106DC000001001052401000104240202052406002C
+:106DD00001070582030800FF09040100020A000000
+:106DE0000007050102400000070581024000000085
+:106DF00012000000F86D00081201100102000040AE
+:106E000009124157000201020301000004030904B2
+:106E100025424F41524425005369657272612D50DD
+:106E20007265636973696F6E506F696E740030319B
+:106E30003233343536373839414243444546000011
+:106E40000040000000400000004000000040000042
+:106E5000000001000000020000000200000002002B
+:106E600000000000E146000899490008454A000872
+:106E700040004000F0530020F053002001000000CB
+:106E800000540020800000004001000005000000C8
+:106E90006D61696E0069646C650000000000002887
+:106EA00000020000AAAAAAAA00000024FFFF000016
+:106EB000000000000000000000A00A150000000013
+:106EC000AAAAAA9600500000FF8F000000000077D9
+:106ED000880000000510000000000000AA9AAAAA7D
+:106EE00005000000FFFF000000000000000000009F
+:106EF0000000000000000000AAAAAAAA00000000EA
+:106F0000FFFF000000000000000000000000000083
+:106F100000000000AAAAAAAA00000000FFFF0000CB
+:106F20000000000000000000000000000000000061
+:106F3000AAAAAAAA00000000FFFF000000000000AB
+:106F4000000000000000000000000000AAAAAAAA99
+:106F500000000000FFFF0000000000000000000033
+:106F600000000000000000000A0000000000000017
+:106F7000030000000000000000000000A492FF7F5A
+:106F800001000000000000004704000000000000B5
+:106F9000000007000000000040420F00FE2A010030
+:106FA000D2040000FF000000184C002038470020E9
+:106FB0000096000000000800960000000008000095
+:106FC000040000000C6E000800000000000000003B
+:106FD00000000000000000000000000000000000B1
+:106FE0005C23002000000000000000000000000002
+:106FF0000000000000000000000000000000000091
+:107000000000000000000000000000000000000080
+:107010000000000000000000000000000000000070
+:107020000000000000000000000000000000000060
+:107030000000000000000000000000000000000050
+:04704000000000004C
+:00000001FF
diff --git a/Tools/bootloaders/Sierra-TrueNavPro_bl.bin b/Tools/bootloaders/Sierra-TrueNavPro_bl.bin
new file mode 100644
index 00000000000000..0c55fc24a43730
Binary files /dev/null and b/Tools/bootloaders/Sierra-TrueNavPro_bl.bin differ
diff --git a/Tools/bootloaders/Sierra-TrueNorth_bl.bin b/Tools/bootloaders/Sierra-TrueNorth_bl.bin
new file mode 100644
index 00000000000000..a022a912745748
Binary files /dev/null and b/Tools/bootloaders/Sierra-TrueNorth_bl.bin differ
diff --git a/Tools/bootloaders/Sierra-TrueSpeed_bl.bin b/Tools/bootloaders/Sierra-TrueSpeed_bl.bin
new file mode 100644
index 00000000000000..cd43a0d228929b
Binary files /dev/null and b/Tools/bootloaders/Sierra-TrueSpeed_bl.bin differ
diff --git a/Tools/bootloaders/YJUAV_A6SE_bl.bin b/Tools/bootloaders/YJUAV_A6SE_bl.bin
new file mode 100644
index 00000000000000..2d733311ae2fe7
Binary files /dev/null and b/Tools/bootloaders/YJUAV_A6SE_bl.bin differ
diff --git a/Tools/bootloaders/YJUAV_A6_bl.bin b/Tools/bootloaders/YJUAV_A6_bl.bin
new file mode 100755
index 00000000000000..dac704dd9eb8ad
Binary files /dev/null and b/Tools/bootloaders/YJUAV_A6_bl.bin differ
diff --git a/Tools/bootloaders/f303-PWM_bl.bin b/Tools/bootloaders/f303-PWM_bl.bin
new file mode 100755
index 00000000000000..37d35bce0eaacb
Binary files /dev/null and b/Tools/bootloaders/f303-PWM_bl.bin differ
diff --git a/Tools/bootloaders/f303-TempSensor_bl.bin b/Tools/bootloaders/f303-TempSensor_bl.bin
new file mode 100755
index 00000000000000..f4aaed67f6026b
Binary files /dev/null and b/Tools/bootloaders/f303-TempSensor_bl.bin differ
diff --git a/Tools/bootloaders/fmuv3-bdshot_bl.bin b/Tools/bootloaders/fmuv3-bdshot_bl.bin
new file mode 100755
index 00000000000000..87f62577ec0bad
Binary files /dev/null and b/Tools/bootloaders/fmuv3-bdshot_bl.bin differ
diff --git a/Tools/bootloaders/luminousbee5_bl.bin b/Tools/bootloaders/luminousbee5_bl.bin
index 59bcdc042f5ee8..7d2fac365c8457 100755
Binary files a/Tools/bootloaders/luminousbee5_bl.bin and b/Tools/bootloaders/luminousbee5_bl.bin differ
diff --git a/Tools/bootloaders/luminousbee5_bl.elf b/Tools/bootloaders/luminousbee5_bl.elf
deleted file mode 100755
index ff00fb5b4ba35d..00000000000000
Binary files a/Tools/bootloaders/luminousbee5_bl.elf and /dev/null differ
diff --git a/Tools/bootloaders/luminousbee5_bl.hex b/Tools/bootloaders/luminousbee5_bl.hex
index e6f79a6010cf57..fdef941ae2efc0 100644
--- a/Tools/bootloaders/luminousbee5_bl.hex
+++ b/Tools/bootloaders/luminousbee5_bl.hex
@@ -1,34 +1,34 @@
:020000040800F2
-:1000000000060020A10200082D100008AD0F000816
-:1000100005100008AD0F0008D90F0008A302000862
-:10002000A3020008A3020008A30200082129000877
+:1000000000060020A102000891100008111000084D
+:1000100069100008111000083D100008A302000834
+:10002000A3020008A3020008A3020008FD2900089B
:10003000A3020008A3020008A3020008A30200080C
:10004000A3020008A3020008A3020008A3020008FC
-:10005000A3020008A3020008A93D0008D53D00083E
-:10006000013E00082D3E0008593E0008A30200088A
+:10005000A3020008A3020008853E0008B13E000884
+:10006000DD3E0008093F0008353F0008A3020008F4
:10007000A3020008A3020008A3020008A3020008CC
:10008000A3020008A3020008A3020008A3020008BC
-:10009000A3020008A3020008A3020008853E00088E
+:10009000A3020008A3020008A3020008613F0008B1
:1000A000A3020008A3020008A3020008A30200089C
:1000B000A3020008A3020008A3020008A30200088C
:1000C000A3020008A3020008A3020008A30200087C
-:1000D000A3020008A3020008A3020008A30200086C
-:1000E000E93E0008A3020008A3020008A3020008DA
+:1000D000A3020008A302000839400008A302000898
+:1000E000C53F0008A3020008A3020008A3020008FD
:1000F000A3020008A3020008A3020008A30200084C
-:10010000A3020008A3020008713F0008A302000830
+:10010000A3020008A302000861400008A30200083F
:10011000A3020008A3020008A3020008A30200082B
:10012000A3020008A3020008A3020008A30200081B
:10013000A3020008A3020008A3020008A30200080B
:10014000A3020008A3020008A3020008A3020008FB
:10015000A3020008A3020008A3020008A3020008EB
:10016000A3020008A3020008A3020008A3020008DB
-:10017000A30200088D340008A3020008A3020008AF
-:10018000A3020008A30200085D3F0008A3020008C4
+:10017000A302000869350008A3020008A3020008D2
+:10018000A3020008A30200084D400008A3020008D3
:10019000A3020008A3020008A3020008A3020008AB
:1001A000A3020008A3020008A3020008A30200089B
:1001B000A3020008A3020008A3020008A30200088B
:1001C000A3020008A3020008A3020008A30200087B
-:1001D000A302000879340008A3020008A302000863
+:1001D000A302000855350008A3020008A302000886
:1001E000A3020008A3020008A3020008A30200085B
:1001F000A3020008A3020008A3020008A30200084B
:10020000A3020008A3020008A3020008A30200083A
@@ -48,1042 +48,1058 @@
:1002E000C0F2F0004EF68851CEF200010860BFF374
:1002F0004F8FBFF36F8F4FF00000E1EE100A4EF604
:100300003C71CEF200010860062080F31488BFF330
-:100310006F8F02F0C3FB02F065FB03F0FFFA4FF0B2
+:100310006F8F02F031FC02F0D3FB03F06DFB4FF066
:1003200055301F491B4A91423CBF41F8040BFAE784
:100330001C49194A91423CBF41F8040BFAE71A499B
:100340001A4A1B4B9A423EBF51F8040B42F8040B69
:10035000F8E700201749184A91423CBF41F8040BC6
-:10036000FAE702F07DFB03F05DFB144C144DAC4248
+:10036000FAE702F0EBFB03F0CBFB144C144DAC426C
:1003700003DA54F8041B8847F9E700F041F8114C00
:10038000114DAC4203DA54F8041B8847F9E702F038
-:1003900065BB0000000600200022002000000008CD
-:1003A00000000020000600209043000800220020EA
-:1003B0005C22002060220020FC460020A0020008F1
+:10039000D3BB00000006002000220020000000085F
+:1003A00000000020000600208844000800220020F1
+:1003B0005C220020602200206C4B0020A00200087C
:1003C000A0020008A0020008A00200082DE9F04FDA
:1003D0002DED108AC1F80CD0D0F80CD0BDEC108AED
:1003E000BDE8F08F002383F311882846A047002042
-:1003F00001F07AFEFEE701F0F5FD00DFFEE7000008
-:1004000038B500F0DDFC30B1164B00220E211A7217
-:100410005A729972DA7202F043FA054602F076FADD
+:1003F00001F0E6FEFEE701F061FE00DFFEE700002F
+:1004000038B502F0E3FA30B1164B00220E211A7211
+:100410005A729972DA7202F0AFFA054602F0E4FA03
:100420000446D0B9104B9D4219D001339D4241F290
-:10043000883512BF044600250124002002F03AFA54
-:100440000CB100F059F800F057FD00F0FFFB284612
-:1004500000F004F900F050F8F9E70025EDE7054653
+:10043000883512BF044600250124002002F0A6FAE8
+:100440000CB100F079F800F089FD00F031FC28468D
+:1004500000F020F900F070F8F9E70025EDE7054617
:10046000EBE700BF00220020010007B008B500F054
-:10047000B9FBA0F120035842584108BD07B541F22D
-:100480001203022101A8ADF8043000F0C9FB03B04B
-:100490005DF804FB202310B583F311881248C3686C
-:1004A0000BB101F0A7FE0023104A4FF47A710E48F9
-:1004B00001F064FE002383F311880D4C236813B10F
+:10047000EBFBA0F120035842584108BD07B541F2FB
+:100480001203022101A8ADF8043000F0FBFB03B019
+:100490005DF804FB38B5202383F311881748C3683F
+:1004A0000BB101F013FF0023154A4FF47A71134882
+:1004B00001F0D0FE002383F31188124C236813B19E
:1004C0002368013B2360636813B16368013B636089
-:1004D000084B1B7833B9636823B9022000F086FC0F
-:1004E0003223636010BD00BF602200209504000825
-:1004F0007C23002074220020F8B5514B514A1C4641
-:100500001968013100F09B8004339342F8D162688E
-:100510004D4B9A4240F293804C4B9B6803F1006331
-:1005200003F500339A4280F08A80002000F0A8FB97
-:100530000220474B187000F04FFC464B0021D3F8C7
-:10054000E820C3F8E810D3F81021C3F81011D3F84D
-:100550001021D3F8EC20C3F8EC10D3F81421C3F821
-:100560001411D3F81421D3F8F020C3F8F010D3F805
-:100570001821C3F81811D3F81821D3F8802042F0BD
-:100580000062C3F88020D3F8802022F00062C3F814
-:100590008020D3F88020D3F8802042F00072C3F886
-:1005A0008020D3F8802022F00072C3F88020D3F896
-:1005B000803072B64FF0E023C3F8084DD4E9000450
-:1005C000BFF34F8FBFF36F8F234AC2F88410BFF37E
-:1005D0004F8F536923F480335361BFF34F8FD2F8A9
-:1005E000803043F6E076C3F3C905C3F34E335B01B5
-:1005F00003EA060C29464CEA81770139C2F8747285
-:10060000F9D2203B13F1200FF2D1BFF34F8FBFF38C
-:100610006F8FBFF34F8FBFF36F8F536923F4003396
-:1006200053610023C2F85032BFF34F8FBFF36F8F77
-:10063000202383F31188854680F308882047F8BD7E
-:100640000000020820000208FFFF0108002200202D
-:10065000742200200044025800ED00E02DE9F04F24
-:1006600093B0A94B2022FF2100900AA89D6800F0BA
-:10067000EDFBA64A1378A3B90121A5481170C36008
-:10068000202383F31188C3680BB101F0B3FD00236D
-:10069000A04A4FF47A719E4801F070FD002383F365
-:1006A0001188009B9C4A03B1136000239B49009C66
-:1006B00098469B461E469A460B705360012000F0F8
-:1006C0008BFB24B1944B1B68002B00F0168200209A
-:1006D00000F088FA0390039B002BF2DB012000F06E
-:1006E00071FB039B213B162BE8D801A252F823F0A3
-:1006F0004D0700087507000809080008BD06000836
-:10070000BD060008BD0600089D0800086F0A000825
-:1007100089090008EB090008130A0008390A0008D3
-:10072000BD0600084B0A0008BD060008BD0A000807
-:10073000ED070008BD060008010B00085907000876
-:10074000ED070008BD060008EB0900080220FFF7CE
-:100750008DFE002840F0FB81009B022105A8B8F126
-:10076000000F08BF1C4641F21233ADF8143000F000
-:1007700057FAA3E74FF47A7000F034FA071EEBDB68
-:100780000220FFF773FE0028E6D0013F052F00F29C
-:10079000E081DFE807F0030A0D101336052304217A
-:1007A00005A8059300F03CFA17E004215648F9E744
-:1007B00004215B48F6E704215A48F3E74FF01C098F
-:1007C000484609F1040900F05DFA0421059005A8E6
-:1007D00000F026FAB9F12C0FF2D101204FF0000AF7
-:1007E00000FA07F747EA0B0B5FFA8BFB00F07AFB86
-:1007F00026B10BF00B030B2B08BF0024FFF73EFEC6
-:100800005CE704214848CDE7002EA5D00BF00B0390
-:100810000B2BA1D10220FFF729FE074600289BD011
-:1008200001203E4E00F02CFA4FF0000802203070FC
-:1008300000F0D2FA5FFA88F9484600F031FA04462F
-:1008400090B1484608F1010800F03AFA0028F1D1C9
-:10085000B846044641F21213022105A83E46ADF8FF
-:10086000143000F0DDF929E701232546022033701A
-:1008700000F0A8FA244B9B68AB4207D9284600F049
-:1008800001FA013040F068810435F3E70025234B7D
-:10089000B8463E461D70204B5D60A7E7002E3FF432
-:1008A0005BAF0BF00B030B2B7FF456AF02201B4BFF
-:1008B000187000F091FA322000F094F9B0F10009BC
-:1008C000FFF64AAF19F003077FF446AF0E4A09EB73
-:1008D0000503926893423FF63FAFB9F5807F3FF73B
-:1008E0003BAF124BB945019322DD4FF47A7000F013
-:1008F00079F90390039A002AFFF62EAF039A013785
-:10090000019B03F8012BEDE7002200207823002053
-:1009100060220020950400087C230020742200201F
-:1009200004220020082200200C220020782200202F
-:10093000C820FFF79BFD074600283FF40DAF1F2D91
-:1009400011D8C5F120020AAB25F0030084494A45BD
-:10095000184428BF4A46019200F052FA019AFF213A
-:100960007F4800F073FA4FEAA903C9F387027C4974
-:100970002846019300F072FA064600283FF46AAF59
-:10098000019B05EB830531E70220FFF76FFD00288F
-:100990003FF4E2AE00F0B0F900283FF4DDAE0027EE
-:1009A000B946704B9B68BB4218D91F2F11D80A9BC0
-:1009B00001330ED027F0030312AA134453F8203C4E
-:1009C00005934846042205A9043700F031FB81460F
-:1009D000E7E7384600F056F90590F2E7CDF81490B5
-:1009E000042105A800F01CF900E70023642104A8F5
-:1009F000049300F00BF900287FF4AEAE0220FFF75D
-:100A000035FD00283FF4A8AE049800F06BF905907E
-:100A1000E6E70023642104A8049300F0F7F8002817
-:100A20007FF49AAE0220FFF721FD00283FF494AE38
-:100A3000049800F059F9EAE70220FFF717FD0028B3
-:100A40003FF48AAE00F068F9E1E70220FFF70EFDFF
-:100A500000283FF481AE05A9142000F063F9074691
-:100A60000421049004A800F0DBF83946B9E73220ED
-:100A700000F0B8F8071EFFF66FAEBB077FF46CAE50
-:100A8000384A07EB0A03926893423FF665AE0220AC
-:100A9000FFF7ECFC00283FF45FAE27F00307574454
-:100AA000BA453FF4A3AE50460AF1040A00F0EAF852
-:100AB0000421059005A800F0B3F8F1E74FF47A702F
-:100AC000FFF7D4FC00283FF447AE00F015F90028EA
-:100AD00044D00A9B01330BD008220AA9002000F061
-:100AE000BDF900283AD02022FF210AA800F0AEF973
-:100AF000FFF7C4FC1C4801F0FDFA13B0BDE8F08F0D
-:100B0000002E3FF429AE0BF00B030B2B7FF424AE29
-:100B10000023642105A8059300F078F80746002813
-:100B20007FF41AAE0220FFF7A1FC814600283FF4B3
-:100B300013AEFFF7A3FC41F2883001F0DBFA059811
-:100B400000F014FA4E463C4600F0CCF9B6E50646F5
-:100B50004CE64FF0000AFFE5B8467BE6374679E6FB
-:100B60007822002000220020A0860100F7B50C4664
-:100B7000184E4FF47A71054602FB01F396F90020F6
-:100B8000501C0BD11448294601930268176A22466B
-:100B9000B8478442019B03D1002310E0002AF1D022
-:100BA00096F90020511C01D0012A0DD10B4829468D
-:100BB0000268166A2246B047844205D10123084ADA
-:100BC0000120137003B0F0BD4FF4FA7001F092FAF7
-:100BD0000020F7E710220020F0290020CC2300207D
-:100BE000C8230020002307B5024601210DF10700AC
-:100BF0008DF80730FFF7BAFF20B19DF8070003B06A
-:100C00005DF804FB4FF0FF30F9E700000A460421CD
-:100C100008B5FFF7ABFF80F00100C0B2404208BD4D
-:100C2000074B0A4630B41978064B53F82140014669
-:100C300023682046DD69044BAC4630BC604700BFEA
-:100C4000C823002064400008A086010070B50A4E49
-:100C500000240A4D01F0FCFC308028683388834270
-:100C600008D901F0F1FC2B6804440133B4F5003FCE
-:100C70002B60F2D370BD00BFCA2300208423002064
-:100C800001F0C4BD00F1006000F50030006870475D
-:100C900000F10060920000F5003001F03BBD000063
-:100CA000054B1A68054B1B889B1A834202D91044D6
-:100CB00001F0CABC0020704784230020CA23002012
-:100CC00038B5074D04462868204401F0C3FC28B914
-:100CD00028682044BDE8384001F0CEBC38BD00BFD4
-:100CE000842300200020704700F1FF5000F58F1092
-:100CF000D0F8000870470000064991F8243033B15D
-:100D000000230822086A81F82430FFF7C1BF0120C0
-:100D1000704700BF88230020014B1868704700BF50
-:100D20000010005C244BF0B51A680446234BC2F354
-:100D30000B06120C1F885868BE4293F9085028D041
-:100D40009F89BE4206D101200C2505FB003358685F
-:100D500093F9085041F201039A421CD041F2030377
-:100D60009A421AD042F201039A4218D042F2030387
-:100D70009A4208BF5625621E0B46441E0A449342FF
-:100D80000FD214F9016F581C6EB1034600F8016CC4
-:100D9000F5E70020D8E75A25EDE75925EBE7582578
-:100DA000E9E7184605E02C2482421C7001D9981C02
-:100DB0005D70401AF0BD00BF0010005C14220020DE
-:100DC00000207047022803D1024B4FF000629A6165
-:100DD000704700BF00040258022803D1024B4FF4B1
-:100DE00000629A61704700BF00040258022804D1D3
-:100DF000024A536983F40063536170470004025848
-:100E0000002310B5934203D0CC5CC4540133F9E7FE
-:100E100010BD0000013810B510F9013F3BB191F948
-:100E200000409C4203D11AB10131013AF4E71AB1F2
-:100E300091F90020981A10BD1046FCE703460246BF
-:100E4000D01A12F9011B0029FAD170470244034657
-:100E5000934202D003F8011BFAE770472DE9F843EB
-:100E60001F4D14460746884695F8242052BBDFF8EC
-:100E700070909CB395F824302BB92022FF2148466E
-:100E80002F62FFF7E3FF95F824004146C0F1080206
-:100E900005EB8000A24228BF2246D6B29200FFF79F
-:100EA000AFFF95F82430A41B17441E449044E4B2CD
-:100EB000F6B2082E85F82460DBD1FFF71DFF00286D
-:100EC000D7D108E02B6A03EB82038342CFD0FFF730
-:100ED00013FF0028CBD10020BDE8F8830120FBE7F9
-:100EE00088230020024B1A78024B1A70704700BF0B
-:100EF000C82300201022002038B5164C164D20467D
-:100F000000F0FAFB2946204600F022FC2D68134829
-:100F1000D5F89020D2F8043843F00203C2F8043820
-:100F200001F0E8F80E49284600F020FDD5F89020A1
-:100F30000C48D2F804380C49A04223F00203C2F84E
-:100F400004384FF4E1330B6003D0BDE8384000F0C3
-:100F500031BB38BDF02900207041000840420F002D
-:100F600078410008CC230020B023002038B50B4B7B
-:100F700004461A780A4B53F822500A4B9D420CD073
-:100F8000094B002118221846FFF760FF0460014654
-:100F90002846BDE8384000F00DBB38BDC82300200E
-:100FA00064400008F0290020B023002000B59BB069
-:100FB000EFF3098168226846FFF722FFEFF305830C
-:100FC000044B9A6BDA6A9A6A9A6A9A6A9A6A9A6A75
-:100FD0009B6AFEE700ED00E000B59BB0EFF30981EE
-:100FE00068226846FFF70CFFEFF30583044B9A6B0A
-:100FF0009A6A9A6A9A6A9A6A9A6A9B6AFEE700BF34
-:1010000000ED00E000B59BB0EFF30981682268466F
-:10101000FFF7F6FEEFF30583034B5A6B9A6A9A6A61
-:101020009A6A9A6A9B6AFEE700ED00E0FEE700001C
-:1010300030B50A44084D91420DD011F8013B58409B
-:10104000082340F30004013B2C4013F0FF0384EA23
-:101050005000F6D1EFE730BD2083B8ED0268436859
-:101060001143016003B1184770470000024A13683A
-:1010700043F0C003136070470078004013B50E4C76
-:10108000204600F08BFA04F1140000234FF40072A4
-:101090000A49009400F04CF9094B4FF400720949D9
-:1010A00004F13800009400F0C5F9074A074BC4E981
-:1010B000172302B010BD00BFCC230020382400202D
-:1010C0006D100008382600200078004000E1F5058A
-:1010D000037C30B5244C002918BF0C46012B11D1DC
-:1010E000224B98420ED1224BD3F8E82042F08042A6
-:1010F000C3F8E820D3F8102142F08042C3F8102151
-:10110000D3F810312268036EC16D03EB520384667D
-:10111000B3FBF2F36268150442BF23F0070503F046
-:10112000070343EA4503CB60A36843F040034B60E9
-:10113000E36843F001038B6042F4967343F00103CC
-:101140000B604FF0FF330B62510505D512F01022F2
-:1011500005D0B2F1805F04D080F8643030BD7F23C9
-:10116000FAE73F23F8E700BF6C400008CC230020DB
-:10117000004402582DE9F047C66D05463768F4690A
-:101180002107346219D014F0080118BF8021E2074A
-:1011900048BF41F02001A3074FF0200348BF41F0B2
-:1011A0004001600748BF41F4807183F31188281D16
-:1011B000FFF754FF002383F31188E2050AD52023AB
-:1011C00083F311884FF40071281DFFF747FF0023B8
-:1011D00083F311884FF020094FF0000A14F0200823
-:1011E00038D13B0616D54FF0200905F1380A200604
-:1011F00010D589F31188504600F050F9002836DAEE
-:101200000821281DFFF72AFF27F080033360002301
-:1012100083F31188790614D5620612D5202383F34F
-:101220001188D5E913239A4208D12B6C33B127F0EA
-:1012300040071021281DFFF711FF3760002383F3BB
-:101240001188E30618D5AA6E1369ABB15069BDE8E1
-:10125000F047184789F31188736A284695F8641097
-:10126000194000F0B5F98AF31188F469B6E7B06265
-:1012700088F31188F469BAE7BDE8F087F8B5154638
-:10128000826804460B46AA4200D28568A169266995
-:10129000761AB5420BD218462A46FFF7B1FDA3696C
-:1012A0002B44A3612846A3685B1BA360F8BD0CD93F
-:1012B000AF1B18463246FFF7A3FD3A46E1683044BB
-:1012C000FFF79EFDE3683B44EBE718462A46FFF72D
-:1012D00097FDE368E5E7000083689342F7B50446AD
-:1012E000154600D28568D4E90460361AB5420BD29F
-:1012F0002A46FFF785FD63692B4463612846A3688E
-:101300005B1BA36003B0F0BD0DD93246AF1B01914A
-:10131000FFF776FD01993A46E0683144FFF770FD2A
-:10132000E3683B44E9E72A46FFF76AFDE368E4E740
-:1013300010B50A440024C361029B8460C16002614D
-:101340000362C0E90000C0E9051110BD08B5D0E98D
-:101350000532934201D1826882B98268013282608B
-:101360005A1C426119700021D0E904329A4224BF0C
-:10137000C368436100F0DAFE002008BD4FF0FF3083
-:10138000FBE7000070B5202304460E4683F3118866
-:10139000A568A5B1A368A269013BA360531CA36122
-:1013A00015782269934224BFE368A361E3690BB116
-:1013B00020469847002383F31188284607E03146EA
-:1013C000204600F0A3FE0028E2DA85F3118870BD04
-:1013D0002DE9F74F04460E4617469846D0F81C9064
-:1013E0004FF0200A8AF311884FF0000B154665B1C3
-:1013F0002A4631462046FFF741FF034660B9414681
-:10140000204600F083FE0028F1D0002383F31188EA
-:10141000781B03B0BDE8F08FB9F1000F03D0019045
-:101420002046C847019B8BF31188ED1A1E448AF3AE
-:101430001188DCE7C160C361009B82600362C0E980
-:1014400005111144C0E9000001617047F8B5044678
-:101450000D461646202383F31188A768A7B1A36819
-:10146000013BA36063695A1C62611D70D4E90432B8
-:101470009A4224BFE3686361E3690BB12046984751
-:10148000002080F3118807E03146204600F03EFE40
-:101490000028E2DA87F31188F8BD0000D0E90523BF
-:1014A00010B59A4201D182687AB98268002101326E
-:1014B00082605A1C82611C7803699A4224BFC36807
-:1014C000836100F033FE204610BD4FF0FF30FBE794
-:1014D0002DE9F74F04460E4617469846D0F81C9063
-:1014E0004FF0200A8AF311884FF0000B154665B1C2
-:1014F0002A4631462046FFF7EFFE034660B94146D3
-:10150000204600F003FE0028F1D0002383F3118869
-:10151000781B03B0BDE8F08FB9F1000F03D0019044
-:101520002046C847019B8BF31188ED1A1E448AF3AD
-:101530001188DCE7026843681143016003B1184772
-:10154000704700001430FFF743BF00004FF0FF3337
-:101550001430FFF73DBF00003830FFF7B9BF00007F
-:101560004FF0FF333830FFF7B3BF00001430FFF700
-:1015700009BF00004FF0FF311430FFF703BF000038
-:101580003830FFF763BF00004FF0FF323830FFF70D
-:101590005DBF000000207047FFF770BD044B036083
-:1015A00000234360C0E9023301230374704700BF86
-:1015B0008440000810B52023044683F31188FFF708
-:1015C00087FD02232374002383F3118810BD0000DC
-:1015D00038B5C36904460D461BB904210844FFF71A
-:1015E000A9FF294604F11400FFF7B0FE002806DA2F
-:1015F000201D4FF48061BDE83840FFF79BBF38BD28
-:10160000026843681143016003B118477047000046
-:1016100013B5406B00F58054D4F8A4381A681178DB
-:10162000042914D1017C022911D1197901231289CD
-:101630008B4013420BD101A94C3002F06FF8D4F863
-:10164000A4480246019B2179206800F0DFF902B02E
-:1016500010BD0000143001F0F1BF00004FF0FF3367
-:10166000143001F0EBBF00004C3002F0C3B80000B2
-:101670004FF0FF334C3002F0BDB80000143001F0E1
-:10168000BFBF00004FF0FF31143001F0B9BF0000C0
-:101690004C3002F08FB800004FF0FF324C3002F0B7
-:1016A00089B800000020704710B500F58054D4F8C8
-:1016B000A4381A681178042917D1017C022914D1A1
-:1016C0005979012352898B4013420ED1143001F015
-:1016D00051FF024648B1D4F8A4484FF440736179F1
-:1016E0002068BDE8104000F07FB910BD406BFFF7E7
-:1016F000DBBF0000704700007FB5124B01250426B8
-:10170000044603600023057400F184024360294607
-:10171000C0E902330C4B0290143001934FF4407334
-:10172000009601F003FF094B04F69442294604F1A8
-:101730004C000294CDE900634FF4407301F0CAFFFE
-:1017400004B070BDAC400008ED160008111600088A
-:101750000A68202383F311880B790B3342F82300A6
-:101760004B79133342F823008B7913B10B3342F8D2
-:10177000230000F58053C3F8A41802230374002348
-:1017800083F311887047000038B5037F044613B116
-:1017900090F85430ABB90125201D0221FFF730FF2E
-:1017A00004F114006FF00101257700F0CBFC04F187
-:1017B0004C0084F854506FF00101BDE8384000F04F
-:1017C000C1BC38BD10B5012104460430FFF718FF35
-:1017D0000023237784F8543010BD000038B5044648
-:1017E0000025143001F0BAFE04F14C00257701F019
-:1017F00089FF201D84F854500121FFF701FF204686
-:10180000BDE83840FFF750BF90F8803003F0600328
-:10181000202B06D190F881200023212A03D81F2AEB
-:1018200006D800207047222AFBD1C0E91D3303E00F
-:10183000034A426707228267C3670120704700BFDF
-:101840002C22002037B500F58055D5F8A4381A6849
-:10185000117804291AD1017C022917D119790123A1
-:1018600012898B40134211D100F14C04204602F042
-:1018700009F858B101A9204601F050FFD5F8A44855
-:101880000246019B2179206800F0C0F803B030BD0A
-:1018900001F10B03F0B550F8236085B004460D4606
-:1018A000FEB1202383F3118804EB8507301D082146
-:1018B000FFF7A6FEFB6806F14C005B691B681BB1D5
-:1018C000019001F039FF019803A901F027FF0246BA
-:1018D00048B1039B2946204600F098F8002383F383
-:1018E000118805B0F0BDFB685A691268002AF5D06E
-:1018F0001B8A013B1340F1D104F18002EAE70000AA
-:10190000133138B550F82140ECB1202383F311880E
-:1019100004F58053D3F8A4281368527903EB8203AB
-:10192000DB689B695D6845B104216018FFF768FEBC
-:10193000294604F1140001F027FE2046FFF7B4FE0B
-:10194000002383F3118838BD7047000001F01AB9F5
-:1019500001234022002110B5044600F8303BFFF778
-:1019600075FA0023C4E9013310BD000010B520232F
-:10197000044683F311882422416000210C30FFF7D4
-:1019800065FA204601F020F902232370002383F337
-:10199000118810BD70B500EB8103054650690E46F5
-:1019A0001446DA6018B110220021FFF74FFAA0693F
-:1019B00018B110220021FFF749FA31462846BDE848
-:1019C000704001F013BA000083682022002103F068
-:1019D000011310B5044683601030FFF737FA204634
-:1019E000BDE8104001F08EBAF0B4012500EB81048F
-:1019F00047898D40E4683D43A46945812360002305
-:101A0000A2606360F0BC01F0ABBA0000F0B4012545
-:101A100000EB810407898D40E4683D4364690581DA
-:101A200023600023A2606360F0BC01F021BB0000D2
-:101A300070B5022300250446242203702946C0F80D
-:101A400088500C3040F8045CFFF700FA204684F818
-:101A5000705001F05FF963681B6823B12946204686
-:101A6000BDE87040184770BD037880F88C300523BE
-:101A7000037043681B6810B504460BB104219847F6
-:101A80000023A36010BD000090F88C204368027012
-:101A90001B680BB1052118477047000070B590F81E
-:101AA0007030044613B1002380F8703004F18002D6
-:101AB000204601F04BFA63689B68B3B994F8803014
-:101AC00013F0600535D00021204601F0F5FC00211F
-:101AD000204601F0E5FC63681B6813B1062120462F
-:101AE0009847062384F8703070BD20469847002838
-:101AF000E4D0B4F88630A26F9A4288BFA36794F905
-:101B00008030A56F002B4FF0200380F20381002D61
-:101B100000F0F280092284F8702083F311880021FC
-:101B20002046D4E91D23FFF771FF002383F31188BA
-:101B3000DAE794F8812003F07F0343EA022340F2BE
-:101B40000232934200F0C58021D8B3F5807F48D09F
-:101B50000DD8012B3FD0022B00F09380002BB2D187
-:101B600004F1880262670222A267E367C1E7B3F566
-:101B7000817F00F09B80B3F5407FA4D194F8823040
-:101B8000012BA0D1B4F8883043F0020332E0B3F562
-:101B9000006F4DD017D8B3F5A06F31D0A3F5C06357
-:101BA000012B90D86368204694F882205E6894F8F0
-:101BB0008310B4F88430B047002884D0436863674A
-:101BC0000368A3671AE0B3F5106F36D040F60242FF
-:101BD00093427FF478AF5C4B63670223A3670023D3
-:101BE000C3E794F88230012B7FF46DAFB4F88830EE
-:101BF00023F00203A4F88830C4E91D55E56778E7AF
-:101C0000B4F88030B3F5A06F0ED194F8823020463E
-:101C100084F88A3001F0DCF863681B6813B1012195
-:101C200020469847032323700023C4E91D339CE713
-:101C300004F18B0363670123C3E72378042B10D1DE
-:101C4000202383F311882046FFF7BEFE85F3118819
-:101C50000321636884F88B5021701B680BB1204608
-:101C6000984794F88230002BDED084F88B30042320
-:101C7000237063681B68002BD6D00221204698474A
-:101C8000D2E794F8843020461D0603F00F010AD5F0
-:101C900001F04EF9012804D002287FF414AF2B4B39
-:101CA0009AE72B4B98E701F035F9F3E794F8823087
-:101CB000002B7FF408AF94F8843013F00F01B3D0F9
-:101CC0001A06204602D501F00FFCADE701F000FC3A
-:101CD000AAE794F88230002B7FF4F5AE94F88430B4
-:101CE00013F00F01A0D01B06204602D501F0E4FB43
-:101CF0009AE701F0D5FB97E7142284F8702083F36C
-:101D000011882B462A4629462046FFF76DFE85F3AB
-:101D10001188E9E65DB1152284F8702083F31188FB
-:101D200000212046D4E91D23FFF75EFEFDE60B22CD
-:101D300084F8702083F311882B462A4629462046D2
-:101D4000FFF764FEE3E700BFDC400008D440000872
-:101D5000D840000838B590F870300446002B3ED0CB
-:101D6000063BDAB20F2A34D80F2B32D8DFE803F063
-:101D70003731310822323131313131313131373778
-:101D8000856FB0F886309D4214D2C3681B8AB5FBBC
-:101D9000F3F203FB12556DB9202383F311882B4610
-:101DA0002A462946FFF732FE85F311880A2384F874
-:101DB00070300EE0142384F87030202383F31188F0
-:101DC000002320461A461946FFF70EFE002383F330
-:101DD000118838BDC36F03B198470023E7E700219E
-:101DE000204601F069FB0021204601F059FB6368A1
-:101DF0001B6813B10621204698470623D7E7000049
-:101E000010B590F870300446142B29D017D8062B43
-:101E100005D001D81BB110BD093B022BFBD8002116
-:101E2000204601F049FB0021204601F039FB6368A0
-:101E30001B6813B1062120469847062319E0152B8D
-:101E4000E9D10B2380F87030202383F3118800231D
-:101E50001A461946FFF7DAFD002383F31188DAE703
-:101E6000C3689B695B68002BD5D1C36F03B19847EA
-:101E7000002384F87030CEE7024B0022C3E9003320
-:101E80009A60704738280020002382680374054B4D
-:101E90001B6899689142FBD25A68036042601060E7
-:101EA000586070473828002008B5202383F3118834
-:101EB000037C032B05D0042B0DD02BB983F31188A1
-:101EC00008BD436900221A604FF0FF334361FFF7FA
-:101ED000DBFF0023F2E7D0E9003213605A60F3E73A
-:101EE000002382680374054B1B6899689142FBD8F4
-:101EF0005A680360426010605860704738280020BC
-:101F0000054B196908741868026853601A601861F3
-:101F100001230374FEF75ABA382800204B1C30B551
-:101F2000044687B00A4D10D02B6901A8094A00F079
-:101F300025F92046FFF7E4FF049B13B101A800F048
-:101F400059F92B69586907B030BDFFF7D9FFF8E799
-:101F500038280020A91E000838B50C4D0446416100
-:101F60002B6981689A68914203D8BDE83840FFF731
-:101F70008BBF1846FFF7B4FF01232C610146237481
-:101F80002046BDE83840FEF721BA00BF38280020BF
-:101F9000044B1A681B6990689B68984294BF0020A4
-:101FA000012070473828002010B5084C23682069AC
-:101FB0001A6854602260012223611A74FFF790FFAF
-:101FC00001462069BDE81040FEF700BA382800201D
-:101FD00008B5FFF7DDFF18B1BDE80840FFF7E4BF23
-:101FE00008BD0000FFF7E0BFFEE7000010B50C4C95
-:101FF000FFF742FF00F0B4F880220A49204600F0C3
-:102000003BF8012344F8180C037400F099FC0023FA
-:1020100083F3118862B60448BDE8104000F04CB864
-:1020200060280020E0400008F040000800F01CB9E3
-:10203000EFF3118020B9EFF30583202282F311889A
-:102040007047000010B530B9EFF30584C4F30804FD
-:1020500014B180F3118810BDFFF7BAFF84F3118823
-:10206000F9E70000034A516853685B1A9842FBD8AD
-:10207000704700BF001000E08260022202827047B9
-:102080008368A3F17C0243F80C2C026943F83C2CD2
-:10209000426943F8382C074A43F81C2CC268A3F164
-:1020A000180043F8102C022203F8082C002203F831
-:1020B000072C7047E503000810B5202383F311882F
-:1020C000FFF7DEFF00210446FFF746FF002383F3FE
-:1020D0001188204610BD0000024B1B6958610F207B
-:1020E000FFF70EBF38280020202383F31188FFF765
-:1020F000F3BF000008B50146202383F311880820B0
-:10210000FFF70CFF002383F3118808BD49B1064B8C
-:1021100042681B6918605A60136043600420FFF72F
-:10212000FDBE4FF0FF30704738280020036898420A
-:1021300006D01A680260506018465961FFF7A4BEC5
-:102140007047000038B504460D462068844200D12F
-:1021500038BD036823605C604561FFF795FEF4E7D6
-:10216000054B4FF0FF3103F11402C3E905220022B1
-:10217000C3E90712704700BF3828002070B51C4E15
-:1021800005460C46C0E9032301F0B2FB334653F881
-:10219000142F9A420DD130620A2C2CBF00190A303C
-:1021A0002A60C5E90124C6E90555BDE8704001F083
-:1021B00089BB316A431AE31838BF1C469368A342AF
-:1021C00002D9081901F08EFB73699A6894420CD801
-:1021D0005A68AC602B606A6015609A685D60121B7B
-:1021E0009A604FF0FF33F36170BDA41A1B68ECE7EF
-:1021F0003828002038B51B4C636998420DD081689F
-:10220000D0E9003213605A600022C2609A680A4422
-:102210009A604FF0FF33E36138BD03682246002126
-:1022200042F8143F93425A60C16003D1BDE8384080
-:1022300001F052BB9A688168256A0A449A6001F0ED
-:1022400057FB6369411B9A688A42E5D9AB181D1A8E
-:10225000206A092D98BF01F10A02BDE838401044F8
-:1022600001F040BB382800202DE9F041184C002730
-:1022700004F11406656901F03BFB236AAA68C11AE0
-:102280008A4215D81344D5F80C802362D5E9003270
-:1022900013605A606369EF60B34201D101F01CFB27
-:1022A00087F311882869C047202383F31188E1E769
-:1022B0006169B14209D013441B1ABDE8F0410A2BF1
-:1022C0002CBFC0180A3001F00DBBBDE8F08100BF83
-:1022D0003828002000207047FEE70000704700000B
-:1022E0004FF0FF307047000002290CD0032904D0C2
-:1022F0000129074818BF00207047032A05D8054860
-:1023000000EBC2007047044870470020704700BFD0
-:10231000D44100083C2200208841000870B59AB0E2
-:1023200005460846144601A900F0C2F801A8FEF7C8
-:1023300085FD431C0022C6B25B001046C5E900348F
-:1023400023700323023404F8013C01ABD1B2023400
-:102350008E4201D81AB070BD13F8011B013204F887
-:10236000010C04F8021CF1E708B5202383F311885F
-:102370000348FFF767FA002383F3118808BD00BF05
-:10238000F029002090F8803003F01F02012A07D1C5
-:1023900090F881200B2A03D10023C0E91D3315E0FA
-:1023A00003F06003202B08D1B0F884302BB990F8EB
-:1023B0008120212A03D81F2A04D8FFF725BA222A10
-:1023C000EBD0FAE7034A426707228267C36701201E
-:1023D000704700BF3322002007B5052917D8DFE872
-:1023E00001F0191603191920202383F31188104ACC
-:1023F00001210190FFF7CEFA019802210D4AFFF763
-:10240000C9FA0D48FFF7EAF9002383F3118803B0F6
-:102410005DF804FB202383F311880748FFF7B4F924
-:10242000F2E7202383F311880348FFF7CBF9EBE7AA
-:10243000284100084C410008F029002038B50C4D17
-:102440000C4C2A460C4904F10800FFF767FF05F120
-:10245000CA0204F110000949FFF760FF05F5CA72CE
-:1024600004F118000649BDE83840FFF757BF00BF28
-:10247000C84200203C220020084100081241000808
-:102480001D41000870B5044608460D46FEF7D6FC0F
-:10249000C6B22046013403780BB9184670BD3246E7
-:1024A0002946FEF7B7FC0028F3D10120F6E700002B
-:1024B0002DE9F84F05460C46FEF7C0FC2C49C6B284
-:1024C0002846FFF7DFFF08B10536F6B2294928464E
-:1024D000FFF7D8FF08B11036F6B2632E0DD8DFF83B
-:1024E0009080DFF89090244FDFF894A0DFF894B04C
-:1024F0002E7846B92670BDE8F88F29462046BDE8FB
-:10250000F84F01F099BD252E2ED1072241462846CD
-:10251000FEF780FC70B9DBF8003007350C3444F866
-:102520000C3CDBF8043044F8083CDBF8083044F895
-:10253000043CDDE7082249462846FEF76BFC98B9C3
-:10254000A21C0E4B197802320909C95D02F8041C5D
-:1025500013F8011B01F00F015345C95D02F8031C7C
-:10256000F0D118340835C3E7013504F8016BBFE733
-:10257000F44100081D4100080942000800E8F11F6D
-:102580000CE8F11FFC410008BFF34F8F044B1A69A0
-:102590005107FCD1D3F810215207F8D1704700BF82
-:1025A0000020005208B50D4B1B78ABB9FFF7ECFFCC
-:1025B0000B4BDA68D10704D50A4A5A6002F1883217
-:1025C0005A60D3F80C21D20706D5064AC3F8042175
-:1025D00002F18832C3F8042108BD00BF264500205F
-:1025E000002000522301674508B5114B1B78F3B951
-:1025F000104B1A69510703D5DA6842F04002DA60DD
-:10260000D3F81021520705D5D3F80C2142F040022F
-:10261000C3F80C21FFF7B8FF064BDA6842F001025D
-:10262000DA60D3F80C2142F00102C3F80C2108BD96
-:1026300026450020002000520F289ABF00F5806038
-:1026400040040020704700004FF400307047000045
-:10265000102070470F2808B50BD8FFF7EDFF00F5E5
-:1026600000330268013204D104308342F9D10120E1
-:1026700008BD0020FCE700000F2870B5054645D8CE
-:10268000FFF7D6FC224CFFF77FFF0646FFF78AFFD5
-:102690004FF0FF33072D6361C4F8143120D8236154
-:1026A000FFF772FF2B0243F02403E360E36843F07B
-:1026B0008003E36023695A07FCD42846FFF764FFD0
-:1026C0004FF40031FFF7B8FF00F002F93046FFF792
-:1026D0008BFFFFF7B7FC2846BDE87040FFF7BABF95
-:1026E000C4F81031FFF750FFA5F108031B0243F0B7
-:1026F0002403C4F80C31D4F80C3143F08003C4F83F
-:102700000C31D4F810315B07FBD4D6E7002070BD44
-:10271000002000522DE9F84F40EA020305460C461E
-:102720001746D80602D00020BDE8F88F27F01F0713
-:10273000DFF8D4B0FFF736FF2744BC4203D10120B5
-:10274000FFF752FFF0E720222946204601F064FC03
-:1027500010B920352034F0E72B4605F120021E6821
-:10276000711CE0D104339A42F9D1FFF761FC05F105
-:102770007843234AB3F5801F224B28BF9A4603F1C2
-:10278000040338BF9046A2F1080228BF9846A3F17F
-:1027900008033ABF9146DA469946FFF7F5FEC8F8B6
-:1027A0000060A5EB040CD9F8002004F11C0142F0F4
-:1027B0000202C9F80020221FDAF8006016F00506B0
-:1027C000FAD152F8043F8A424CF80230F4D1BFF3F8
-:1027D0004F8FFFF7D9FE4FF0FF32C8F80020D9F82D
-:1027E000002022F00202C9F80020FFF72BFC202273
-:1027F0002146284601F010FC0028AAD030469FE769
-:1028000014200052102100521020005210B5084C24
-:10281000237828B11BB9FFF7C5FE0123237010BD33
-:10282000002BFCD02070BDE81040FFF7DDBE00BFDC
-:10283000264500200244074BD2B210B5904200D189
-:1028400010BD441C00B253F8200041F8040BE0B264
-:10285000F4E700BF504000580E4B30B51C6F240405
-:1028600005D41C6F1C671C6F44F400441C670A4CA1
-:1028700002442368D2B243F480732360074B904232
-:1028800000D130BD441C51F8045B00B243F8205025
-:10289000E0B2F4E7004402580048025850400058A3
-:1028A00007B5012201A90020FFF7C4FF019803B07A
-:1028B0005DF804FB13B50446FFF7F2FFA04205D014
-:1028C000012201A900200194FFF7C6FF02B010BD4C
-:1028D0000144BFF34F8F064B884204D3BFF34F8FA1
-:1028E000BFF36F8F7047C3F85C022030F4E700BF7E
-:1028F00000ED00E0034B1A681AB9034AD2F8D0245D
-:102900001A607047284500200040025808B5FFF7BC
-:10291000F1FF024B1868C0F3806008BD2845002015
-:10292000EFF30983054968334A6B22F001024A63D9
-:1029300083F30988002383F31188704700EF00E0D8
-:10294000202080F3118862B60D4B0E4AD96821F41D
-:10295000E0610904090C0A430B49DA60D3F8FC2052
-:1029600042F08072C3F8FC20084AC2F8B01F116818
-:1029700041F0010111601022DA7783F822007047DC
-:1029800000ED00E00003FA0555CEACC5001000E0F4
-:10299000202310B583F311880E4B5B6813F400639A
-:1029A00014D0F1EE103AEFF309844FF08073683CD5
-:1029B000E361094BDB6B236684F30988FFF7E8FAD0
-:1029C00010B1064BA36110BD054BFBE783F31188E3
-:1029D000F9E700BF00ED00E000EF00E0F7030008BA
-:1029E000FA03000870B5BFF34F8FBFF36F8F1A4A19
-:1029F0000021C2F85012BFF34F8FBFF36F8F53699E
-:102A000043F400335361BFF34F8FBFF36F8FC2F8AE
-:102A10008410BFF34F8FD2F8803043F6E074C3F3D5
-:102A2000C900C3F34E335B0103EA0406014646EADC
-:102A300081750139C2F86052F9D2203B13F1200FA1
-:102A4000F2D1BFF34F8F536943F480335361BFF327
-:102A50004F8FBFF36F8F70BD00ED00E0FEE7000009
-:102A60000A4B0B480B4A90420BD30B4BC11EDA1C8E
-:102A7000121A22F003028B4238BF00220021FEF717
-:102A8000E5B953F8041B40F8041BECE7EC430008DD
-:102A9000FC460020FC460020FC4600207047000059
-:102AA00070B5D0E9244300224FF0FF359E6804EB57
-:102AB00042135101D3F80009002805DAD3F80009C0
-:102AC00040F08040C3F80009D3F8000B002805DA75
-:102AD000D3F8000B40F08040C3F8000B01326318BC
-:102AE0009642C3F80859C3F8085BE0D24FF00113CF
-:102AF000C4F81C3870BD000000EB8103D3F80CC093
-:102B00002DE9F043DCF814204E1CD0F89050D2F898
-:102B100000E005EB063605EB4118506870450AD316
-:102B20000122D5F8343802FA01F123EA0101C5F88F
-:102B30003418BDE8F083AEEB0003BCF81040A342AC
-:102B400028BF2346D8F81849A4B2B3EB840FF0D8B5
-:102B50009468A4F1040959F8047F3760A4EB0907CD
-:102B60001F44042FF7D81C44034494605360D4E7F7
-:102B7000890141F02001016103699B06FCD4122008
-:102B8000FFF770BA10B50A4C2046FEF7E1FE094B7C
-:102B9000C4F89030084BC4F89430084C2046FEF737
-:102BA000D7FE074BC4F89030064BC4F8943010BDE4
-:102BB0002C4500200000084040420008C845002085
-:102BC000000004404C42000870B503780546012B14
-:102BD0005DD1494BD0F89040984259D1474B0E21D6
-:102BE0006520D3F8D82042F00062C3F8D820D3F88B
-:102BF000002142F00062C3F80021D3F80021D3F88D
-:102C0000802042F00062C3F88020D3F8802022F0B8
-:102C10000062C3F88020D3F8803000F071FC384B9C
-:102C2000E360384BC4F800380023D5F89060C4F84E
-:102C3000003EC02323604FF40413A3633369002BC9
-:102C4000FCDA01230C203361FFF70CFA3369DB0750
-:102C5000FCD41220FFF706FA3369002BFCDA0026B9
-:102C60002846A660FFF71CFF6B68C4F81068DB6895
-:102C7000C4F81468C4F81C68002B3AD1224BA36135
-:102C80004FF0FF336361A36843F00103A36070BD9D
-:102C90001E4B9842C8D1194B0E214D20D3F8D82095
-:102CA00042F00072C3F8D820D3F8002142F000723D
-:102CB000C3F80021D3F80021D3F8802042F000723D
-:102CC000C3F88020D3F8802022F00072C3F880205F
-:102CD000D3F88020D3F8D82022F08062C3F8D8201F
-:102CE000D3F8002122F08062C3F80021D3F800312C
-:102CF00093E7074BC3E700BF2C4500200044025870
-:102D00004014004003002002003C30C0C8450020B1
-:102D1000083C30C0F8B5D0F89040054600214FF08F
-:102D200000662046FFF724FFD5F8941000234FF0EB
-:102D300001128F684FF0FF30C4F83438C4F81C28F3
-:102D400004EB431201339F42C2F80069C2F8006BE2
-:102D5000C2F80809C2F8080BF2D20B68D5F8902027
-:102D6000C5F89830636210231361166916F01006D7
-:102D7000FBD11220FFF776F9D4F8003823F4FE6374
-:102D8000C4F80038A36943F4402343F01003A3615F
-:102D90000923C4F81038C4F814380B4BEB604FF01B
-:102DA000C043C4F8103B094BC4F8003BC4F8106999
-:102DB000C4F80039D5F8983003F1100243F48013B9
-:102DC000C5F89820A362F8BD1C420008408000109E
-:102DD000D0F8902090F88A10D2F8003823F4FE63DF
-:102DE00043EA0113C2F80038704700002DE9F843A8
-:102DF00000EB8103D0F890500C468046DA680FFA59
-:102E000081F94801166806F00306731E022B05EBD4
-:102E100041134FF0000194BFB604384EC3F8101BA5
-:102E20004FF0010104F1100398BF06F1805601FA3A
-:102E300003F3916998BF06F5004600293AD0578AF6
-:102E400004F15801374349016F50D5F81C180B4362
-:102E50000021C5F81C382B180127C3F81019A7400A
-:102E60005369611E9BB3138A928B9B08012A88BF0A
-:102E70005343D8F89820981842EA034301F14002DE
-:102E80002146C8F89800284605EB82025360FFF7F8
-:102E90006FFE08EB8900C3681B8A43EA84534834F9
-:102EA0001E4364012E51D5F81C381F43C5F81C7809
-:102EB000BDE8F88305EB4917D7F8001B21F4004162
-:102EC000C7F8001BD5F81C1821EA0303C0E704F17A
-:102ED0003F030B4A2846214605EB83035A60FFF760
-:102EE00047FE05EB4910D0F8003923F40043C0F841
-:102EF0000039D5F81C3823EA0707D7E7008000100F
-:102F000000040002D0F894201268C0F89820FFF75F
-:102F1000C7BD00005831D0F8903049015B5813F418
-:102F2000004004D013F4001F0CBF022001207047A2
-:102F30004831D0F8903049015B5813F4004004D078
-:102F400013F4001F0CBF02200120704700EB810129
-:102F5000CB68196A0B6813604B68536070470000B8
-:102F600000EB810330B5DD68AA691368D36019B935
-:102F7000402B84BF402313606B8A1468D0F89020E4
-:102F80001C4402EB4110013C09B2B4FBF3F463436F
-:102F9000033323F0030343EAC44343F0C043C0F8C0
-:102FA000103B2B6803F00303012B0ED1D2F8083835
-:102FB00002EB411013F4807FD0F8003B14BF43F0C4
-:102FC000805343F00053C0F8003B02EB4112D2F8AB
-:102FD000003B43F00443C2F8003B30BD2DE9F04113
-:102FE000D0F8906005460C4606EB4113D3F8087BF9
-:102FF0003A07C3F8087B08D5D6F814381B0704D560
-:1030000000EB8103DB685B689847FA071FD5D6F8A9
-:103010001438DB071BD505EB8403D968CCB98B6961
-:10302000488A5A68B2FBF0F600FB16228AB9186883
-:10303000DA6890420DD2121AC3E90024202383F3E8
-:10304000118821462846FFF78BFF84F31188BDE8DD
-:10305000F081012303FA04F26B8923EA02036B81F6
-:10306000CB68002BF3D021462846BDE8F041184735
-:1030700000EB81034A0170B5DD68D0F890306C69CF
-:103080002668E66056BB1A444FF40020C2F81009C7
-:103090002A6802F00302012A0AB20ED1D3F8080806
-:1030A00003EB421410F4807FD4F8000914BF40F001
-:1030B000805040F00050C4F8000903EB4212D2F8EF
-:1030C000000940F00440C2F800090122D3F8340896
-:1030D00002FA01F10143C3F8341870BD19B9402E4A
-:1030E00084BF4020206020681A442E8A8419013C45
-:1030F000B4FBF6F440EAC44040F00050C6E70000DC
-:103100002DE9F041D0F8906004460D4606EB4113DE
-:10311000D3F80879C3F80879FB071CD5D6F810381E
-:10312000DA0718D500EB8103D3F80CC0DCF81430B3
-:10313000D3F800E0DA6896451BD2A2EB0E024FF0FE
-:1031400000081A60C3F80480202383F31188FFF776
-:103150008FFF88F311883B0618D50123D6F8342851
-:10316000AB40134212D029462046BDE8F041FFF79C
-:10317000C3BC012303FA01F2038923EA020303819A
-:10318000DCF80830002BE6D09847E4E7BDE8F08192
-:103190002DE9F84FD0F8905004466E69AB691E4097
-:1031A00016F480586E6103D0BDE8F84FFEF740BCBE
-:1031B000002E12DAD5F8003E9F0705D0D5F8003E64
-:1031C00023F00303C5F8003ED5F80438204623F069
-:1031D0000103C5F80438FEF757FC300505D5204635
-:1031E000FFF75EFC2046FEF73FFCB1040CD5D5F896
-:1031F000083813F0060FEB6823F470530CBF43F448
-:10320000105343F4A053EB60320704D56368DB68C6
-:103210000BB120469847F30200F1BA80B70226D5D9
-:10322000D4F8909000274FF0010A09EB4712D2F82A
-:10323000003B03F44023B3F5802F11D1D2F8003BBB
-:10324000002B0DDA62890AFA07F322EA030363818D
-:1032500004EB8703DB68DB6813B1394620469847E7
-:103260000137D4F89430FFB29B689F42DDD9F00655
-:1032700019D5D4F89000026AC2F30A1702F00F03BE
-:1032800002F4F012B2F5802F00F0CC80B2F5402F9E
-:1032900009D104EB8303002200F58050DB681B6A30
-:1032A000974240F0B2803003D5F8185835D5E9037D
-:1032B00003D500212046FFF791FEAA0303D5012183
-:1032C0002046FFF78BFE6B0303D502212046FFF754
-:1032D00085FE2F0303D503212046FFF77FFEE8027A
-:1032E00003D504212046FFF779FEA90203D5052165
-:1032F0002046FFF773FE6A0203D506212046FFF73A
-:103300006DFE2B0203D507212046FFF767FEEF0174
-:1033100003D508212046FFF761FE700340F1A98024
-:10332000E90703D500212046FFF7EAFEAA0703D5E7
-:1033300001212046FFF7E4FE6B0703D5022120465A
-:10334000FFF7DEFE2F0703D503212046FFF7D8FE47
-:10335000EE0603D504212046FFF7D2FEA80603D5CA
-:1033600005212046FFF7CCFE690603D5062120463D
-:10337000FFF7C6FE2A0603D507212046FFF7C0FE49
-:10338000EB0576D520460821BDE8F84FFFF7B8BE1B
-:10339000D4F8909000274FF0010AD4F894305FFAE7
-:1033A00087FB9B689B453FF639AF09EB4B13D3F87E
-:1033B000002902F44022B2F5802F24D1D3F800294D
-:1033C000002A20DAD3F8002942F09042C3F80029FD
-:1033D000D3F80029002AFBDB5946D4F89000FFF708
-:1033E000C7FB22890AFA0BF322EA0303238104EBC9
-:1033F0008B03DB689B6813B15946204698475946B2
-:103400002046FFF779FB0137C7E7910701D1D0F8D4
-:103410000080072A02F101029CBF03F8018B4FEAEA
-:1034200018283DE704EB830300F58050DA68D2F8F2
-:1034300018C0DCF80820DCE9001CA1EB0C0C002112
-:103440008F4208D1DB689B699A683A449A605A684F
-:103450003A445A6027E711F0030F01D1D0F80080F9
-:103460008C4501F1010184BF02F8018B4FEA182855
-:10347000E6E7BDE8F88F000008B50348FFF788FECF
-:10348000BDE80840FFF784BA2C45002008B5034882
-:10349000FFF77EFEBDE80840FFF77ABAC845002076
-:1034A000D0F8903003EB4111D1F8003B43F4001306
-:1034B000C1F8003B70470000D0F8903003EB411199
-:1034C000D1F8003943F40013C1F800397047000007
-:1034D000D0F8903003EB4111D1F8003B23F40013F6
-:1034E000C1F8003B70470000D0F8903003EB411169
-:1034F000D1F8003923F40013C1F8003970470000F7
-:10350000090100F16043012203F56143C9B283F868
-:10351000001300F01F039A4043099B0003F160432E
-:1035200003F56143C3F880211A60704730B5043356
-:10353000039C0172002104FB0325C160C0E906530E
-:10354000049B0363059BC0E90000C0E90422C0E9B5
-:103550000842C0E90A11436330BD00000022416AFD
-:10356000C260C0E90411C0E90A226FF00101FEF750
-:10357000E9BD0000D0E90432934201D1C2680AB922
-:10358000181D704700207047036919600021C26848
-:103590000132C260C269134482699342036124BF4D
-:1035A000436A0361FEF7C2BD38B504460D46E368C1
-:1035B0003BB162690020131D1268A3621344E362E9
-:1035C00007E0237A33B929462046FEF79FFD0028FD
-:1035D000EDDA38BD6FF00100FBE70000C368C26997
-:1035E000013BC3604369134482699342436124BF32
-:1035F000436A436100238362036B03B1184770473A
-:1036000070B52023044683F31188866A3EB9FFF71C
-:10361000CBFF054618B186F31188284670BDA36A12
-:10362000E26A13F8015B9342A36202D32046FFF7DC
-:10363000D5FF002383F31188EFE700002DE9F84F51
-:1036400004460E46174698464FF0200989F3118824
-:103650000025AA46D4F828B0BBF1000F09D1414695
-:103660002046FFF7A1FF20B18BF311882846BDE863
-:10367000F88FD4E90A12A7EB050B521A934528BF1D
-:103680009346BBF1400F1BD9334601F1400251F87C
-:10369000040B914243F8040BF9D1A36A403640353C
-:1036A0004033A362D4E90A239A4202D32046FFF7AB
-:1036B00095FF8AF31188BD42D8D289F31188C9E7F2
-:1036C00030465A46FDF79CFBA36A5E445D445B446A
-:1036D000A362E7E710B5029C0433017204FB0321E7
-:1036E000C460C0E906130023C0E90A33039B0363E7
-:1036F000049BC0E90000C0E90422C0E9084243631A
-:1037000010BD0000026A6FF00101C260426AC0E9A8
-:1037100004220022C0E90A22FEF714BDD0E90423E6
-:103720009A4201D1C26822B9184650F8043B0B6096
-:103730007047002070470000C3680021C269013350
-:10374000C3604369134482699342436124BF436A5F
-:103750004361FEF7EBBC000038B504460D46E36854
-:103760003BB1236900201A1DA262E2691344E3629F
-:1037700007E0237A33B929462046FEF7C7FC002824
-:10378000EDDA38BD6FF00100FBE700000369196056
-:10379000C268013AC260C2691344826993420361FC
-:1037A00024BF436A036100238362036B03B118479C
-:1037B0007047000070B520230D460446114683F380
-:1037C0001188866A2EB9FFF7C7FF10B186F31188FA
-:1037D00070BDA36A1D70A36AE26A01339342A362BB
-:1037E00004D3E16920460439FFF7D0FF002080F3BD
-:1037F0001188EDE72DE9F84F04460D4690469946AD
-:103800004FF0200A8AF311880026B346A76A4FB901
-:1038100049462046FFF7A0FF20B187F311883046C4
-:10382000BDE8F88FD4E90A073A1AA8EB06079742D1
-:1038300028BF1746402F1BD905F1400355F8042B2C
-:103840009D4240F8042BF9D1A36A40364033A3626D
-:10385000D4E90A239A4204D3E16920460439FFF7E8
-:1038600095FF8BF311884645D9D28AF31188CDE7AD
-:1038700029463A46FDF7C4FAA36A3D443E443B4418
-:10388000A362E5E7D0E904239A4217D1C3689BB14C
-:10389000836A8BB1043B9B1A0ED01360C368013B53
-:1038A000C360C3691A4483699A42026124BF436AB0
-:1038B0000361002383620123184670470023FBE75E
-:1038C00000F0DAB8034B002258631A610222DA6072
-:1038D000704700BF000C0040014B0022DA607047C7
-:1038E000000C0040014B5863704700BF000C0040C3
-:1038F000014B586A704700BF000C00404B684360A2
-:103900008B688360CB68C3600B6943614B6903625A
-:103910008B6943620B6803607047000008B53C4B3D
-:1039200040F2FF713B48D3F888200A43C3F888204F
-:10393000D3F8882022F4FF6222F00702C3F888201F
-:10394000D3F88820D3F8E0200A43C3F8E020D3F866
-:1039500008210A43C3F808212F4AD3F80831114639
-:10396000FFF7CCFF00F5806002F11C01FFF7C6FFF6
-:1039700000F5806002F13801FFF7C0FF00F58060BC
-:1039800002F15401FFF7BAFF00F5806002F1700107
-:10399000FFF7B4FF00F5806002F18C01FFF7AEFF86
-:1039A00000F5806002F1A801FFF7A8FF00F5806034
-:1039B00002F1C401FFF7A2FF00F5806002F1E0010F
-:1039C000FFF79CFF00F5806002F1FC01FFF796FF16
-:1039D00002F58C7100F58060FFF790FF00F000F9B0
-:1039E0000E4BD3F8902242F00102C3F89022D3F894
-:1039F000942242F00102C3F894220522C3F89820D1
-:103A00004FF06052C3F89C20054AC3F8A02008BDBF
-:103A100000440258000002585842000800ED00E03F
-:103A20001F00080308B500F0D7FAFEF7DFFA0F4BC6
-:103A3000D3F8DC2042F04002C3F8DC20D3F80421A4
-:103A400022F04002C3F80421D3F80431084B1A686D
-:103A500042F008021A601A6842F004021A60FEF787
-:103A600049FFBDE80840FEF7E9BC00BF004402582A
-:103A70000018024870470000114BD3F8E82042F0CC
-:103A80000802C3F8E820D3F8102142F00802C3F876
-:103A900010210C4AD3F81031D36B43F00803D363E1
-:103AA000C722094B9A624FF0FF32DA6200229A6114
-:103AB0005A63DA605A6001225A611A60704700BF87
-:103AC000004402580010005C000C0040094A08B590
-:103AD0001169D3680B40D9B29B076FEA01011161EC
-:103AE00007D5202383F31188FEF7A0FA002383F380
-:103AF000118808BD000C0040384B4FF0FF31D3F85F
-:103B00008020C3F88010D3F880200022C3F88020E2
-:103B1000D3F88000D3F88400C3F88410D3F884006D
-:103B2000C3F88420D3F88400D86F40F0FF4040F4FD
-:103B3000FF0040F43F5040F03F00D867D86F20F0BE
-:103B4000FF4020F4FF0020F43F5020F03F00D867F2
-:103B5000D86FD3F888006FEA40506FEA5050C3F82E
-:103B60008800D3F88800C0F30A00C3F88800D3F8AF
-:103B70008800D3F89000C3F89010D3F89000C3F8F1
-:103B80009020D3F89000D3F89400C3F89410D3F8A1
-:103B90009400C3F89420D3F89400D3F89800C3F8A5
-:103BA0009810D3F89800C3F89820D3F89800D3F869
-:103BB0008C00C3F88C10D3F88C00C3F88C20D3F899
-:103BC0008C00D3F89C00C3F89C10D3F89C10C3F869
-:103BD0009C20D3F89C3000F0D3B900BF00440258B9
-:103BE000614B0122C3F80821604BD3F8F42042F066
-:103BF0000202C3F8F420D3F81C2142F00202C3F8F9
-:103C00001C210222D3F81C31594BDA605A68910406
-:103C1000FCD5584A1A6001229A60574ADA6000229D
-:103C20001A614FF440429A61514B9A699204FCD553
-:103C30001A6842F480721A604C4B1A6F12F4407F7B
-:103C400004D04FF480321A6700221A671A6842F0D3
-:103C500001021A60454B1A685007FCD500221A6110
-:103C60001A6912F03802FBD1012119604FF080412E
-:103C700059605A67414ADA62414A1A611A6842F445
-:103C800080321A60394B1A689103FCD51A6842F4E5
-:103C900080521A601A689204FCD53A4A3A499A62EC
-:103CA00000225A6319633949DA6399635A64384ABE
-:103CB0001A64384ADA621A6842F0A8521A602B4B2A
-:103CC0001A6802F02852B2F1285FF9D148229A61AD
-:103CD0004FF48862DA6140221A622F4ADA644FF0A8
-:103CE00080521A652D4A5A652D4A9A6532232D4A0B
-:103CF0001360136803F00F03022BFAD11B4B1A69F0
-:103D000042F003021A611A6902F03802182AFAD145
-:103D1000D3F8DC2042F00052C3F8DC20D3F80421B1
-:103D200042F00052C3F80421D3F80421D3F8DC2078
-:103D300042F08042C3F8DC20D3F8042142F08042F4
-:103D4000C3F80421D3F80421D3F8DC2042F0004268
-:103D5000C3F8DC20D3F8042142F00042C3F8042168
-:103D6000D3F80431704700BF00800051004402586E
-:103D70000048025800C000F0020000010000FF01EE
-:103D80000088900832206000630209011D020400CF
-:103D900047040508FD0BFF01200000200010E00093
-:103DA00000010100002000524FF0B04208B5D2F8E7
-:103DB000883003F00103C2F8883023B1044A136845
-:103DC0000BB150689847BDE80840FEF7E1BD00BF61
-:103DD0007C4600204FF0B04208B5D2F8883003F09E
-:103DE0000203C2F8883023B1044A93680BB1D0684B
-:103DF0009847BDE80840FEF7CBBD00BF7C460020D9
-:103E00004FF0B04208B5D2F8883003F00403C2F88E
-:103E1000883023B1044A13690BB150699847BDE853
-:103E20000840FEF7B5BD00BF7C4600204FF0B04211
-:103E300008B5D2F8883003F00803C2F8883023B1FF
-:103E4000044A93690BB1D0699847BDE80840FEF772
-:103E50009FBD00BF7C4600204FF0B04208B5D2F8AD
-:103E6000883003F01003C2F8883023B1044A136A83
-:103E70000BB1506A9847BDE80840FEF789BD00BF06
-:103E80007C4600204FF0B04310B5D3F8884004F4CE
-:103E90007872C3F88820A30604D5124A936A0BB13E
-:103EA000D06A9847600604D50E4A136B0BB1506B6D
-:103EB0009847210604D50B4A936B0BB1D06B9847FA
-:103EC000E20504D5074A136C0BB1506C9847A30563
-:103ED00004D5044A936C0BB1D06C9847BDE81040F0
-:103EE000FEF756BD7C4600204FF0B04310B5D3F826
-:103EF000884004F47C42C3F88820620504D5164A41
-:103F0000136D0BB1506D9847230504D5124A936D7C
-:103F10000BB1D06D9847E00404D50F4A136E0BB176
-:103F2000506E9847A10404D50B4A936E0BB1D06E26
-:103F30009847620404D5084A136F0BB1506F984735
-:103F4000230404D5044A936F0BB1D06F9847BDE8A2
-:103F50001040FEF71DBD00BF7C46002008B5034899
-:103F6000FDF708F9BDE80840FEF712BDCC2300209C
-:103F700008B5FFF7ABFDBDE80840FEF709BD00003E
-:103F8000062108B50846FFF7BBFA06210720FFF710
-:103F9000B7FA06210820FFF7B3FA06210920FFF738
-:103FA000AFFA06210A20FFF7ABFA06211720FFF728
-:103FB000A7FA06212820FFF7A3FA09217A20FFF7A4
-:103FC0009FFA07213220FFF79BFA0C215220BDE80F
-:103FD0000840FFF795BA000008B5FFF78DFD00F027
-:103FE0000DF8FDF7D9FAFDF7B1FCFDF783FBFFF7FC
-:103FF00041FDBDE80840FFF763BC00000023054A0F
-:1040000019460133102BC2E9001102F10802F8D160
-:10401000704700BF7C46002010B501390244904231
-:1040200001D1002005E0037811F8014FA34201D02F
-:10403000181B10BD0130F2E7034611F8012B03F8FD
-:10404000012B002AF9D1704753544D333248373F82
-:104050003F3F0053544D3332483734332F373533D5
-:1040600000000000F0290020CC2300200096000072
-:104070000000000000000000000000000000000040
-:104080000000000000000000611500084D15000848
-:104090008915000875150008811500086D150008C0
-:1040A0005915000845150008951500080000000086
-:1040B000711600085D16000899160008851600089C
-:1040C000911600087D1600086916000855160008AC
-:1040D000A51600080000000001000000000000001C
-:1040E0006D61696E0000000069646C65000000008D
-:1040F000E840000878280020F02900200100000096
-:10410000E91F0008000000004172647550696C6F7F
-:10411000740025424F415244252D424C0025534501
-:104120005249414C25000000020000000000000040
-:104130009118000801190008400040009842002032
-:10414000A842002002000000000000000300000060
-:1041500000000000491900080000000010000000E5
-:10416000B842002000000000010000000000000034
-:104170002C45002001010200D9230008E922000893
-:1041800085230008692300084300000090410008CF
-:1041900009024300020100C03209040000010202CA
-:1041A000010005240010010524010001042402027D
-:1041B0000524060001070582030800FF0904010029
-:1041C000020A000000070501024000000705810205
-:1041D0004000000012000000DC4100081201100144
-:1041E00002000040091241570002010203010000D1
-:1041F0000403090425424F41524425006C756D6942
-:104200006E6F757362656535003031323334353623
-:104210003738394142434445460000000000000061
-:104220009D1A0008551D0008011E000840004000AE
-:10423000644600206446002001000000744600200F
-:1042400080000000400100000800000000010000A4
-:1042500000040000080000000000802A00000000A8
-:10426000AAAAAAAA00000024FFFF00000000000084
-:1042700000A00A000001400000000000AAAAAAAAAB
-:1042800000010000FFFF000000000000000000002F
-:104290001000004000000000AAAAAAAA10000040D6
-:1042A000FFFF0000000000000000000000400000D0
-:1042B00000000000AAAAAAAA00400000FFFF000018
-:1042C000000000000000000000800240000000002C
-:1042D000AAAAAAAA00400140FFFF00000000007047
-:1042E000070000000000000000000000AAAAAAAA1F
-:1042F00000000000FFFF00000000000000000000C0
-:104300000000000000000000AAAAAAAA0000000005
-:10431000FFFF00000000000000000000000000009F
-:1043200000000000AAAAAAAA00000000FFFF0000E7
-:10433000000000000000000000000000000000007D
-:10434000AAAAAAAA00000000FFFF000000000000C7
-:10435000000000000000000000000000AAAAAAAAB5
-:1043600000000000FFFF000000000000000000004F
-:104370000000000000000000AAAAAAAA0000000095
-:10438000FFFF00000000000000000000000000002F
-:10439000050400000000000000001E0000000000F6
-:1043A000FF00000000000000484000083F0000003F
-:1043B00050040000534000083F0000000096000039
-:1043C0000000080096000000000800000400000043
-:1043D000F0410008000000000000000000000000A4
-:0C43E000000000000000000000000000D1
+:1004D0000D4D2B7833B963687BB9022000F0B8FC6E
+:1004E000322363602B78032B07D163682BB902207A
+:1004F00000F0AEFC4FF47A73636038BD60220020D8
+:10050000950400087C23002074220020084B1870FA
+:1005100003280CD8DFE800F008050208022000F0EC
+:100520008DBC022000F080BC024B00225A60704754
+:10053000742200207C230020F8B5504B504A1C4602
+:100540001968013100F0998004339342F8D1626850
+:100550004C4B9A4240F291804B4B9B6803F10063F5
+:1005600003F500339A4280F08880002000F0BAFB47
+:100570000220FFF7CBFF454B0021D3F8E820C3F85A
+:10058000E810D3F81021C3F81011D3F81021D3F8D4
+:10059000EC20C3F8EC10D3F81421C3F81411D3F8ED
+:1005A0001421D3F8F020C3F8F010D3F81821C3F8C1
+:1005B0001811D3F81821D3F8802042F00062C3F854
+:1005C0008020D3F8802022F00062C3F88020D3F886
+:1005D0008020D3F8802042F00072C3F88020D3F846
+:1005E000802022F00072C3F88020D3F8803072B6E9
+:1005F0004FF0E023C3F8084DD4E90004BFF34F8F58
+:10060000BFF36F8F224AC2F88410BFF34F8F536934
+:1006100023F480335361BFF34F8FD2F8803043F619
+:10062000E076C3F3C905C3F34E335B0103EA060C5E
+:1006300029464CEA81770139C2F87472F9D2203B1D
+:1006400013F1200FF2D1BFF34F8FBFF36F8FBFF3C2
+:100650004F8FBFF36F8F536923F40033536100232F
+:10066000C2F85032BFF34F8FBFF36F8F202383F355
+:100670001188854680F308882047F8BD00000208ED
+:1006800020000208FFFF0108002200200044025859
+:1006900000ED00E02DE9F04F93B0B44B2022FF2194
+:1006A00000900AA89D6800F003FCB14A1378A3B932
+:1006B0000121B0481170C360202383F31188C368FF
+:1006C0000BB101F003FE0023AB4A4FF47A71A94845
+:1006D00001F0C0FD002383F31188009B13B1A74BE9
+:1006E000009A1A60A64A1378032B03D000231370D4
+:1006F000A24A53604FF0000A009CD3465646D146AA
+:10070000012000F09BFB24B19C4B1B68002B00F0E8
+:100710002682002000F098FA0390039B002BF2DB66
+:10072000012000F081FB039B213B1F2BE8D801A295
+:1007300052F823F0B5070008DD070008710800082B
+:100740000107000801070008010700080309000865
+:10075000D30A0008ED0900084F0A0008770A0008CC
+:100760009D0A000801070008AF0A000801070008F9
+:10077000210B00085508000801070008650B000858
+:10078000C107000855080008010700084F0A0008C3
+:100790000107000801070008010700080107000819
+:1007A0000107000801070008010700080107000809
+:1007B000710800080220FFF759FE002840F0F98177
+:1007C000009B022105A8BAF1000F08BF1C4641F2A8
+:1007D0001233ADF8143000F055FA91E74FF47A7007
+:1007E00000F032FA071EEBDB0220FFF73FFE002885
+:1007F000E6D0013F052F00F2DE81DFE807F0030AB3
+:100800000D1013360523042105A8059300F03AFACC
+:1008100017E004215548F9E704215A48F6E7042176
+:100820005948F3E74FF01C08404608F1040800F06F
+:100830005BFA0421059005A800F024FAB8F12C0F0A
+:10084000F2D101204FF0000900FA07F747EA0B0B3D
+:100850005FFA8BFB00F078FB26B10BF00B030B2B40
+:1008600008BF0024FFF70AFE4AE704214748CDE706
+:10087000002EA5D00BF00B030B2BA1D10220FFF70C
+:10088000F5FD074600289BD00120002600F02AFA3B
+:100890000220FFF73BFE5FFA86F8404600F032FA8E
+:1008A0000446B0B1039940460136A1F140025142DD
+:1008B000514100F037FA0028EDD1BA46044641F222
+:1008C0001213022105A83E46ADF8143000F0DAF903
+:1008D00016E725460120FFF719FE244B9B68AB4223
+:1008E00007D9284600F000FA013040F0678104354E
+:1008F000F3E70025224BBA463E461D701F4B5D6054
+:10090000A8E7002E3FF45CAF0BF00B030B2B7FF43A
+:1009100057AF0220FFF7FAFD322000F095F9B0F151
+:100920000008FFF64DAF18F003077FF449AF0F4AF8
+:1009300008EB0503926893423FF642AFB8F5807F1B
+:100940003FF73EAF124BB845019323DD4FF47A7069
+:1009500000F07AF90390039A002AFFF631AF039A68
+:100960000137019B03F8012BEDE700BF00220020B7
+:100970007823002060220020950400087C230020BA
+:100980007422002004220020082200200C220020D3
+:1009900078220020C820FFF769FD074600283FF4B1
+:1009A0000FAF1F2D11D8C5F120020AAB25F00300AF
+:1009B00084494245184428BF4246019200F052FA49
+:1009C000019AFF217F4800F073FA4FEAA803C8F3A9
+:1009D00087027C492846019300F072FA06460028F7
+:1009E0003FF46DAF019B05EB830533E70220FFF772
+:1009F0003DFD00283FF4E4AE00F0B2F900283FF4DA
+:100A0000DFAE0027B846704B9B68BB4218D91F2F3A
+:100A100011D80A9B01330ED027F0030312AA134406
+:100A200053F8203C05934046042205A9043700F002
+:100A300031FB8046E7E7384600F056F90590F2E7CB
+:100A4000CDF81480042105A800F01CF902E700236A
+:100A5000642104A8049300F00BF900287FF4B0AEE1
+:100A60000220FFF703FD00283FF4AAAE049800F02F
+:100A70006DF90590E6E70023642104A8049300F0D3
+:100A8000F7F800287FF49CAE0220FFF7EFFC002867
+:100A90003FF496AE049800F05BF9EAE70220FFF716
+:100AA000E5FC00283FF48CAE00F06AF9E1E7022093
+:100AB000FFF7DCFC00283FF483AE05A9142000F00A
+:100AC00065F907460421049004A800F0DBF83946D4
+:100AD000B9E7322000F0B8F8071EFFF671AEBB0789
+:100AE0007FF46EAE384A07EB0903926893423FF6F3
+:100AF00067AE0220FFF7BAFC00283FF461AE27F092
+:100B000003074F44B9453FF4A5AE484609F104092F
+:100B100000F0EAF80421059005A800F0B3F8F1E729
+:100B20004FF47A70FFF7A2FC00283FF449AE00F0C2
+:100B300017F9002844D00A9B01330BD008220AA9D8
+:100B4000002000F0BDF900283AD02022FF210AA899
+:100B500000F0AEF9FFF792FC1C4801F037FB13B030
+:100B6000BDE8F08F002E3FF42BAE0BF00B030B2BE8
+:100B70007FF426AE0023642105A8059300F078F8E1
+:100B8000074600287FF41CAE0220FFF76FFC80466A
+:100B900000283FF415AEFFF771FC41F2883001F0F8
+:100BA00015FB059800F014FA46463C4600F0CCF9D7
+:100BB000A6E506464EE64FF0000901E6BA467EE697
+:100BC00037467CE67822002000220020A086010023
+:100BD000F7B50C46184E4FF47A71054602FB01F347
+:100BE00096F90020501C0BD1144829460193026845
+:100BF000176A2246B8478442019B03D1002310E0C4
+:100C0000002AF1D096F90020511C01D0012A0DD103
+:100C10000B4829460268166A2246B047844205D12D
+:100C20000123084A0120137003B0F0BD4FF4FA709D
+:100C300001F0CCFA0020F7E710220020CC2300209E
+:100C4000602E0020C8230020002307B502460121A2
+:100C50000DF107008DF80730FFF7BAFF20B19DF8BE
+:100C6000070003B05DF804FB4FF0FF30F9E7000028
+:100C70000A46042108B5FFF7ABFF80F00100C0B2BF
+:100C8000404208BD074B0A4630B41978064B53F86A
+:100C90002140014623682046DD69044BAC4630BC48
+:100CA000604700BFC82300205C410008A086010007
+:100CB00070B50A4E00240A4D01F036FD30802868D8
+:100CC0003388834208D901F02BFD2B68044401339B
+:100CD000B4F5003F2B60F2D370BD00BFCA230020E3
+:100CE0008423002001F0FEBD00F1006000F500301B
+:100CF0000068704700F10060920000F5003001F0DC
+:100D000075BD0000054B1A68054B1B889B1A834272
+:100D100002D9104401F004BD002070478423002054
+:100D2000CA23002038B50446074D29B1286820445D
+:100D3000BDE8384001F00CBD2868204401F0F6FC05
+:100D40000028F3D038BD00BF842300200020704766
+:100D500000F1FF5000F58F10D0F800087047000038
+:100D6000064991F8243033B100230822086A81F83B
+:100D70002430FFF7BFBF0120704700BF8823002049
+:100D8000014B1868704700BF0010005C244BF0B5A1
+:100D90001A680446234BC2F30B06120C1F885868CE
+:100DA000BE4293F9085028D09F89BE4206D1012047
+:100DB0000C2505FB0033586893F9085041F20103F4
+:100DC0009A421CD041F203039A421AD042F2010324
+:100DD0009A4218D042F203039A4208BF5625621E77
+:100DE0000B46441E0A4493420FD214F9016F581C5B
+:100DF0006EB1034600F8016CF5E70020D8E75A25EC
+:100E0000EDE75925EBE75825E9E7184605E02C24DE
+:100E100082421C7001D9981C5D70401AF0BD00BF61
+:100E20000010005C14220020022803D1024B4FF076
+:100E300000629A61704700BF00040258022803D183
+:100E4000024B4FF400629A61704700BF00040258E1
+:100E5000022804D1024A536983F400635361704746
+:100E600000040258002310B5934203D0CC5CC45454
+:100E70000133F9E710BD0000013810B510F9013F4A
+:100E80003BB191F900409C4203D11AB10131013AC2
+:100E9000F4E71AB191F90020981A10BD1046FCE74A
+:100EA00003460246D01A12F9011B0029FAD17047F5
+:100EB00002440346934202D003F8011BFAE770474D
+:100EC0002DE9F8431F4D14460746884695F824201F
+:100ED00052BBDFF870909CB395F824302BB92022D8
+:100EE000FF2148462F62FFF7E3FF95F824004146B3
+:100EF000C0F1080205EB8000A24228BF2246D6B20C
+:100F00009200FFF7AFFF95F82430A41B17441E444E
+:100F10009044E4B2F6B2082E85F82460DBD1FFF7E6
+:100F20001FFF0028D7D108E02B6A03EB820383421E
+:100F3000CFD0FFF715FF0028CBD10020BDE8F88304
+:100F40000120FBE788230020024B1A78024B1A701D
+:100F5000704700BFC82300201022002038B5164C6F
+:100F6000164D204600F034FC2946204600F05CFC7B
+:100F70002D681348D5F89020D2F8043843F00203C6
+:100F8000C2F8043801F022F90E49284600F05AFD53
+:100F9000D5F890200C48D2F804380C49A04223F030
+:100FA0000203C2F804384FF461230B6003D0BDE89C
+:100FB000384000F06BBB38BD602E0020684200084E
+:100FC00040420F0070420008CC230020B0230020D4
+:100FD00038B50B4B04461A780A4B53F822500A4B8B
+:100FE0009D420CD0094B002118221846FFF760FFE4
+:100FF000046001462846BDE8384000F047BB38BDD4
+:10100000C82300205C410008602E0020B02300208F
+:1010100000B59BB0EFF3098168226846FFF722FF15
+:10102000EFF30583044B9A6BDA6A9A6A9A6A9A6AB2
+:101030009A6A9A6A9B6AFEE700ED00E000B59BB0F1
+:10104000EFF3098168226846FFF70CFFEFF3058391
+:10105000044B9A6B9A6A9A6A9A6A9A6A9A6A9B6A23
+:10106000FEE700BF00ED00E000B59BB0EFF30981A3
+:1010700068226846FFF7F6FEEFF30583034B5A6BD1
+:101080009A6A9A6A9A6A9A6A9B6AFEE700ED00E099
+:10109000FEE7000030B50A44084D91420DD011F82A
+:1010A000013B5840082340F30004013B2C4013F05F
+:1010B000FF0384EA5000F6D1EFE730BD2083B8ED9E
+:1010C000026843681143016003B11847704700008C
+:1010D000024A136843F0C0031360704700440040A5
+:1010E000024A136843F0C003136070470078004061
+:1010F00037B51A4C1A4D204600F0BCFA04F1140022
+:10110000009400234FF40072164900F07DF94FF46B
+:101110000072154904F138000094144B00F0F6F900
+:10112000134BC4E91735134C204600F0A3FA04F121
+:10113000140000234FF400720F49009400F064F98A
+:101140000E4B4FF400720E4904F13800009400F089
+:10115000DDF90C4BC4E9173503B030BDCC230020BA
+:1011600000E1F505A4240020A4280020D1100008E7
+:101170000044004038240020A4260020E11000088C
+:10118000A42A002000780040037C30B52B4C0029B5
+:1011900018BF0C46012B11D1294B98423BD1294B4A
+:1011A000D3F8E82042F40032C3F8E820D3F8102145
+:1011B00042F40032C3F81021D3F810312268036ED4
+:1011C000C16D03EB52038466B3FBF2F3626815044E
+:1011D00042BF23F0070503F0070343EA4503CB6052
+:1011E000A36843F040034B60E36843F001038B6066
+:1011F00042F4967343F001030B604FF0FF330B6230
+:10120000510505D512F0102214D0B2F1805F13D031
+:1012100080F8643030BD0C4B9842CFD1094BD3F8E5
+:10122000E82042F08042C3F8E820D3F8102142F0D1
+:101230008042BFE77F23EBE73F23E9E764410008F3
+:10124000CC23002000440258382400202DE9F04728
+:10125000C66D05463768F4692107346219D014F069
+:10126000080118BF8021E20748BF41F02001A30711
+:101270004FF0200348BF41F04001600748BF41F4F0
+:10128000807183F31188281DFFF71AFF002383F371
+:101290001188E2050AD5202383F311884FF40071E9
+:1012A000281DFFF70DFF002383F311884FF020095D
+:1012B0004FF0000A14F0200838D13B0616D54FF045
+:1012C000200905F1380A200610D589F31188504607
+:1012D00000F050F9002836DA0821281DFFF7F0FE4B
+:1012E00027F080033360002383F31188790614D537
+:1012F000620612D5202383F31188D5E913239A427D
+:1013000008D12B6C33B127F040071021281DFFF7BF
+:10131000D7FE3760002383F31188E30618D5AA6E41
+:101320001369ABB15069BDE8F047184789F31188DC
+:10133000736A284695F86410194000F0B5F98AF3ED
+:101340001188F469B6E7B06288F31188F469BAE7E6
+:10135000BDE8F087F8B51546826804460B46AA42F8
+:1013600000D28568A1692669761AB5420BD2184663
+:101370002A46FFF777FDA3692B44A3612846A3689B
+:101380005B1BA360F8BD0CD9AF1B18463246FFF7B4
+:1013900069FD3A46E1683044FFF764FDE3683B4489
+:1013A000EBE718462A46FFF75DFDE368E5E7000036
+:1013B00083689342F7B50446154600D28568D4E9A0
+:1013C0000460361AB5420BD22A46FFF74BFD63691B
+:1013D0002B4463612846A3685B1BA36003B0F0BD88
+:1013E0000DD93246AF1B0191FFF73CFD01993A46FA
+:1013F000E0683144FFF736FDE3683B44E9E72A46FD
+:10140000FFF730FDE368E4E710B50A440024C36148
+:10141000029B8460C16002610362C0E90000C0E910
+:10142000051110BD08B5D0E90532934201D182689B
+:1014300082B98268013282605A1C426119700021AF
+:10144000D0E904329A4224BFC368436100F0DAFE57
+:10145000002008BD4FF0FF30FBE7000070B52023EF
+:1014600004460E4683F31188A568A5B1A368A26956
+:10147000013BA360531CA36115782269934224BFEA
+:10148000E368A361E3690BB120469847002383F327
+:101490001188284607E03146204600F0A3FE0028C8
+:1014A000E2DA85F3118870BD2DE9F74F04460E4648
+:1014B00017469846D0F81C904FF0200A8AF31188FE
+:1014C0004FF0000B154665B12A4631462046FFF71E
+:1014D00041FF034660B94146204600F083FE0028E4
+:1014E000F1D0002383F31188781B03B0BDE8F08F9F
+:1014F000B9F1000F03D001902046C847019B8BF340
+:101500001188ED1A1E448AF31188DCE7C160C361BB
+:10151000009B82600362C0E905111144C0E900002C
+:1015200001617047F8B504460D461646202383F343
+:101530001188A768A7B1A368013BA36063695A1C1F
+:1015400062611D70D4E904329A4224BFE36863618A
+:10155000E3690BB120469847002080F3118807E02B
+:101560003146204600F03EFE0028E2DA87F311887B
+:10157000F8BD0000D0E9052310B59A4201D1826878
+:101580007AB982680021013282605A1C82611C781B
+:1015900003699A4224BFC368836100F033FE20468A
+:1015A00010BD4FF0FF30FBE72DE9F74F04460E4624
+:1015B00017469846D0F81C904FF0200A8AF31188FD
+:1015C0004FF0000B154665B12A4631462046FFF71D
+:1015D000EFFE034660B94146204600F003FE0028B6
+:1015E000F1D0002383F31188781B03B0BDE8F08F9E
+:1015F000B9F1000F03D001902046C847019B8BF33F
+:101600001188ED1A1E448AF31188DCE702684368EA
+:101610001143016003B11847704700001430FFF711
+:1016200043BF00004FF0FF331430FFF73DBF000011
+:101630003830FFF7B9BF00004FF0FF333830FFF705
+:10164000B3BF00001430FFF709BF00004FF0FF31B7
+:101650001430FFF703BF00003830FFF763BF00000E
+:101660004FF0FF323830FFF75DBF000000207047B9
+:10167000FFF73EBD044B036000234360C0E9023323
+:1016800001230374704700BF7C41000810B520237C
+:10169000044683F31188FFF777FD022323740023A8
+:1016A00083F3118810BD000038B5C36904460D46A8
+:1016B0001BB904210844FFF7A9FF294604F11400CF
+:1016C000FFF7B0FE002806DA201D4FF48061BDE868
+:1016D0003840FFF79BBF38BD026843681143016083
+:1016E00003B118477047000013B5406B00F58054F4
+:1016F000D4F8A4381A681178042914D1017C02297D
+:1017000011D11979012312898B4013420BD101A900
+:101710004C3002F071F8D4F8A4480246019B2179BC
+:10172000206800F0DFF902B010BD0000143001F0B5
+:10173000F3BF00004FF0FF33143001F0EDBF0000A5
+:101740004C3002F0C5B800004FF0FF334C3002F0CF
+:10175000BFB80000143001F0C1BF00004FF0FF31EE
+:10176000143001F0BBBF00004C3002F091B8000013
+:101770004FF0FF324C3002F08BB800000020704771
+:1017800010B500F58054D4F8A4381A6811780429EB
+:1017900017D1017C022914D15979012352898B4038
+:1017A00013420ED1143001F053FF024648B1D4F871
+:1017B000A4484FF4407361792068BDE8104000F000
+:1017C0007FB910BD406BFFF7DBBF00007047000022
+:1017D0007FB5124B012504260446036000230574DF
+:1017E00000F1840243602946C0E902330C4B0290A9
+:1017F000143001934FF44073009601F005FF094B3C
+:1018000004F69442294604F14C000294CDE90063A9
+:101810004FF4407301F0CCFF04B070BDA441000848
+:10182000C5170008E91600080A68202383F3118809
+:101830000B790B3342F823004B79133342F8230022
+:101840008B7913B10B3342F8230000F58053C3F8B2
+:10185000A41802230374002383F311887047000047
+:1018600038B5037F044613B190F85430ABB9012565
+:10187000201D0221FFF730FF04F114006FF0010179
+:10188000257700F0CBFC04F14C0084F854506FF045
+:101890000101BDE8384000F0C1BC38BD10B50121E0
+:1018A00004460430FFF718FF0023237784F85430F0
+:1018B00010BD000038B504460025143001F0BCFE10
+:1018C00004F14C00257701F08BFF201D84F8545063
+:1018D0000121FFF701FF2046BDE83840FFF750BF68
+:1018E00090F8803003F06003202B06D190F881201F
+:1018F0000023212A03D81F2A06D800207047222A55
+:10190000FBD1C0E91D3303E0034A42670722826727
+:10191000C3670120704700BF2C22002037B500F5B7
+:101920008055D5F8A4381A68117804291AD1017C99
+:10193000022917D11979012312898B40134211D141
+:1019400000F14C04204602F00BF858B101A92046E2
+:1019500001F052FFD5F8A4480246019B2179206886
+:1019600000F0C0F803B030BD01F10B03F0B550F842
+:10197000236085B004460D46FEB1202383F3118811
+:1019800004EB8507301D0821FFF7A6FEFB6806F172
+:101990004C005B691B681BB1019001F03BFF019893
+:1019A00003A901F029FF024648B1039B29462046BE
+:1019B00000F098F8002383F3118805B0F0BDFB68B0
+:1019C0005A691268002AF5D01B8A013B1340F1D1F5
+:1019D00004F18002EAE70000133138B550F82140E5
+:1019E000ECB1202383F3118804F58053D3F8A428A5
+:1019F0001368527903EB8203DB689B695D6845B12C
+:101A000004216018FFF768FE294604F1140001F074
+:101A100029FE2046FFF7B4FE002383F3118838BD6A
+:101A20007047000001F01CB901234022002110B5CD
+:101A3000044600F8303BFFF73BFA0023C4E90133CA
+:101A400010BD000010B52023044683F31188242222
+:101A5000416000210C30FFF72BFA204601F022F9FB
+:101A600002232370002383F3118810BD70B500EBAF
+:101A70008103054650690E461446DA6018B11022FB
+:101A80000021FFF715FAA06918B110220021FFF715
+:101A90000FFA31462846BDE8704001F015BA000043
+:101AA00083682022002103F0011310B504468360EF
+:101AB0001030FFF7FDF92046BDE8104001F090BA64
+:101AC000F0B4012500EB810447898D40E4683D4373
+:101AD000A469458123600023A2606360F0BC01F02B
+:101AE000ADBA0000F0B4012500EB810407898D40F8
+:101AF000E4683D436469058123600023A26063605C
+:101B0000F0BC01F023BB000070B5022300250446A1
+:101B1000242203702946C0F888500C3040F8045C39
+:101B2000FFF7C6F9204684F8705001F061F9636848
+:101B30001B6823B129462046BDE87040184770BD98
+:101B4000037880F88C300523037043681B6810B558
+:101B500004460BB1042198470023A36010BD000088
+:101B600090F88C20436802701B680BB10521184760
+:101B70007047000070B590F87030044613B1002330
+:101B800080F8703004F18002204601F04DFA63685D
+:101B90009B68B3B994F8803013F0600535D000210C
+:101BA000204601F0F7FC0021204601F0E7FC6368C5
+:101BB0001B6813B1062120469847062384F870302D
+:101BC00070BD204698470028E4D0B4F88630A26F54
+:101BD0009A4288BFA36794F98030A56F002B4FF01D
+:101BE000200380F20381002D00F0F280092284F8A6
+:101BF000702083F3118800212046D4E91D23FFF7CC
+:101C000071FF002383F31188DAE794F8812003F051
+:101C10007F0343EA022340F20232934200F0C58080
+:101C200021D8B3F5807F48D00DD8012B3FD0022BAF
+:101C300000F09380002BB2D104F188026267022287
+:101C4000A267E367C1E7B3F5817F00F09B80B3F53E
+:101C5000407FA4D194F88230012BA0D1B4F8883011
+:101C600043F0020332E0B3F5006F4DD017D8B3F55F
+:101C7000A06F31D0A3F5C063012B90D863682046D4
+:101C800094F882205E6894F88310B4F88430B047EA
+:101C9000002884D0436863670368A3671AE0B3F53C
+:101CA000106F36D040F6024293427FF478AF5C4B1F
+:101CB00063670223A3670023C3E794F88230012BF4
+:101CC0007FF46DAFB4F8883023F00203A4F88830B5
+:101CD000C4E91D55E56778E7B4F88030B3F5A06F27
+:101CE0000ED194F88230204684F88A3001F0DEF874
+:101CF00063681B6813B101212046984703232370B2
+:101D00000023C4E91D339CE704F18B0363670123BF
+:101D1000C3E72378042B10D1202383F311882046B6
+:101D2000FFF7BEFE85F311880321636884F88B50AA
+:101D300021701B680BB12046984794F88230002B25
+:101D4000DED084F88B300423237063681B68002B7B
+:101D5000D6D0022120469847D2E794F88430204616
+:101D60001D0603F00F010AD501F050F9012804D037
+:101D700002287FF414AF2B4B9AE72B4B98E701F026
+:101D800037F9F3E794F88230002B7FF408AF94F82A
+:101D9000843013F00F01B3D01A06204602D501F0AB
+:101DA00011FCADE701F002FCAAE794F88230002BA9
+:101DB0007FF4F5AE94F8843013F00F01A0D01B0629
+:101DC000204602D501F0E6FB9AE701F0D7FB97E742
+:101DD000142284F8702083F311882B462A46294662
+:101DE0002046FFF76DFE85F31188E9E65DB1152207
+:101DF00084F8702083F3118800212046D4E91D2344
+:101E0000FFF75EFEFDE60B2284F8702083F3118855
+:101E10002B462A4629462046FFF764FEE3E700BF2B
+:101E2000D4410008CC410008D041000838B590F8F2
+:101E300070300446002B3ED0063BDAB20F2A34D86D
+:101E40000F2B32D8DFE803F037313108223231313D
+:101E50003131313131313737856FB0F886309D42BD
+:101E600014D2C3681B8AB5FBF3F203FB12556DB99C
+:101E7000202383F311882B462A462946FFF732FE9A
+:101E800085F311880A2384F870300EE0142384F857
+:101E90007030202383F31188002320461A46194608
+:101EA000FFF70EFE002383F3118838BDC36F03B123
+:101EB00098470023E7E70021204601F06BFB002153
+:101EC000204601F05BFB63681B6813B106212046C6
+:101ED00098470623D7E7000010B590F87030044605
+:101EE000142B29D017D8062B05D001D81BB110BD53
+:101EF000093B022BFBD80021204601F04BFB0021BF
+:101F0000204601F03BFB63681B6813B106212046A5
+:101F10009847062319E0152BE9D10B2380F8703080
+:101F2000202383F3118800231A461946FFF7DAFDB0
+:101F3000002383F31188DAE7C3689B695B68002B91
+:101F4000D5D1C36F03B19847002384F87030CEE732
+:101F5000024B0022C3E900339A607047A42C002092
+:101F6000002382680374054B1B6899689142FBD279
+:101F70005A6803604260106058607047A42C0020CB
+:101F800008B5202383F31188037C032B05D0042B91
+:101F90000DD02BB983F3118808BD436900221A6064
+:101FA0004FF0FF334361FFF7DBFF0023F2E7D0E997
+:101FB000003213605A60F3E7002382680374054B14
+:101FC0001B6899689142FBD85A68036042601060B0
+:101FD00058607047A42C0020054B196908741868D4
+:101FE000026853601A60186101230374FEF7EEB9AA
+:101FF000A42C00204B1C30B5044687B00A4D10D0ED
+:102000002B6901A8094A00F025F92046FFF7E4FFF3
+:10201000049B13B101A800F059F92B69586907B066
+:1020200030BDFFF7D9FFF8E7A42C0020811F00087E
+:1020300038B50C4D044641612B6981689A6891421C
+:1020400003D8BDE83840FFF78BBF1846FFF7B4FF51
+:1020500001232C61014623742046BDE83840FEF779
+:10206000B5B900BFA42C0020044B1A681B69906806
+:102070009B68984294BF002001207047A42C002048
+:1020800010B5084C236820691A6854602260012248
+:1020900023611A74FFF790FF01462069BDE81040E4
+:1020A000FEF794B9A42C002008B5FFF7DDFF18B1A6
+:1020B000BDE80840FFF7E4BF08BD0000FFF7E0BF40
+:1020C000FEE7000010B50C4CFFF742FF00F0B4F83B
+:1020D00080220A49204600F03BF8012344F8180CFE
+:1020E000037400F09BFC002383F3118862B604485C
+:1020F000BDE8104000F04CB8CC2C0020D8410008BE
+:10210000E841000800F01CB9EFF3118020B9EFF3AB
+:102110000583202282F311887047000010B530B982
+:10212000EFF30584C4F3080414B180F3118810BDE3
+:10213000FFF7BAFF84F31188F9E70000034A5168FA
+:1021400053685B1A9842FBD8704700BF001000E04C
+:1021500082600222028270478368A3F17C0243F806
+:102160000C2C026943F83C2C426943F8382C074A8E
+:1021700043F81C2CC268A3F1180043F8102C02226B
+:1021800003F8082C002203F8072C7047E503000829
+:1021900010B5202383F31188FFF7DEFF00210446EA
+:1021A000FFF746FF002383F31188204610BD00008F
+:1021B000024B1B6958610F20FFF70EBFA42C0020B3
+:1021C000202383F31188FFF7F3BF000008B5014611
+:1021D000202383F311880820FFF70CFF002383F3EB
+:1021E000118808BD49B1064B42681B6918605A60E6
+:1021F000136043600420FFF7FDBE4FF0FF307047CF
+:10220000A42C00200368984206D01A68026050602F
+:1022100018465961FFF7A4BE7047000038B5044660
+:102220000D462068844200D138BD036823605C609D
+:102230004561FFF795FEF4E7054B4FF0FF3103F1E1
+:102240001402C3E905220022C3E90712704700BF48
+:10225000A42C002070B51C4E05460C46C0E9032393
+:1022600001F0B4FB334653F8142F9A420DD130627B
+:102270000A2C2CBF00190A302A60C5E90124C6E9DE
+:102280000555BDE8704001F08BBB316A431AE31875
+:1022900038BF1C469368A34202D9081901F090FB8D
+:1022A00073699A6894420CD85A68AC602B606A6073
+:1022B00015609A685D60121B9A604FF0FF33F361FE
+:1022C00070BDA41A1B68ECE7A42C002038B51B4C89
+:1022D000636998420DD08168D0E9003213605A607A
+:1022E0000022C2609A680A449A604FF0FF33E361AB
+:1022F00038BD03682246002142F8143F93425A60D9
+:10230000C16003D1BDE8384001F054BB9A688168D0
+:10231000256A0A449A6001F059FB6369411B9A6877
+:102320008A42E5D9AB181D1A206A092D98BF01F120
+:102330000A02BDE83840104401F042BBA42C002042
+:102340002DE9F041184C002704F11406656901F0ED
+:102350003DFB236AAA68C11A8A4215D81344D5F8EE
+:102360000C802362D5E9003213605A606369EF6024
+:10237000B34201D101F01EFB87F311882869C047E1
+:10238000202383F31188E1E76169B14209D0134446
+:102390001B1ABDE8F0410A2B2CBFC0180A3001F00F
+:1023A0000FBBBDE8F08100BFA42C002000207047C7
+:1023B000FEE70000704700004FF0FF30704700005C
+:1023C00002290CD0032904D00129074818BF002096
+:1023D0007047032A05D8054800EBC200704704483F
+:1023E00070470020704700BFCC4200083C2200200C
+:1023F0008042000870B59AB005460846144601A907
+:1024000000F0C2F801A8FEF74BFD431C0022C6B243
+:102410005B001046C5E9003423700323023404F83E
+:10242000013C01ABD1B202348E4201D81AB070BD6A
+:1024300013F8011B013204F8010C04F8021CF1E747
+:1024400008B5202383F311880348FFF767FA0023B8
+:1024500083F3118808BD00BF602E002090F8803003
+:1024600003F01F02012A07D190F881200B2A03D123
+:102470000023C0E91D3315E003F06003202B08D1D1
+:10248000B0F884302BB990F88120212A03D81F2A74
+:1024900004D8FFF725BA222AEBD0FAE7034A4267AD
+:1024A00007228267C3670120704700BF33220020E4
+:1024B00007B5052917D8DFE801F019160319192007
+:1024C000202383F31188104A01210190FFF7CEFAEF
+:1024D000019802210D4AFFF7C9FA0D48FFF7EAF902
+:1024E000002383F3118803B05DF804FB202383F3FA
+:1024F00011880748FFF7B4F9F2E7202383F3118826
+:102500000348FFF7CBF9EBE72042000844420008FC
+:10251000602E002038B50C4D0C4C2A460C4904F1B5
+:102520000800FFF767FF05F1CA0204F1100009492E
+:10253000FFF760FF05F5CA7204F118000649BDE80F
+:102540003840FFF757BF00BF384700203C2200202B
+:10255000004200080A4200081542000870B504460F
+:1025600008460D46FEF79CFCC6B2204601340378AF
+:102570000BB9184670BD32462946FEF77DFC00288F
+:10258000F3D10120F6E700002DE9F84F05460C468F
+:10259000FEF786FC2C49C6B22846FFF7DFFF08B1DC
+:1025A0000536F6B229492846FFF7D8FF08B110369C
+:1025B000F6B2632E0DD8DFF89080DFF89090244FAC
+:1025C000DFF894A0DFF894B02E7846B92670BDE805
+:1025D000F88F29462046BDE8F84F01F0A9BD252E09
+:1025E0002ED1072241462846FEF746FC70B9DBF89B
+:1025F000003007350C3444F80C3CDBF8043044F868
+:10260000083CDBF8083044F8043CDDE70822494682
+:102610002846FEF731FC98B9A21C0E4B19780232FD
+:102620000909C95D02F8041C13F8011B01F00F0130
+:102630005345C95D02F8031CF0D118340835C3E7CF
+:10264000013504F8016BBFE7EC42000815420008B1
+:102650000143000800E8F11F0CE8F11FF4420008F4
+:10266000BFF34F8F044B1A695107FCD1D3F81021E7
+:102670005207F8D1704700BF0020005208B50D4B3B
+:102680001B78ABB9FFF7ECFF0B4BDA68D10704D529
+:102690000A4A5A6002F188325A60D3F80C21D207F4
+:1026A00006D5064AC3F8042102F18832C3F8042192
+:1026B00008BD00BF96490020002000522301674555
+:1026C00008B5114B1B78F3B9104B1A69510703D5A4
+:1026D000DA6842F04002DA60D3F81021520705D5DB
+:1026E000D3F80C2142F04002C3F80C21FFF7B8FFE9
+:1026F000064BDA6842F00102DA60D3F80C2142F0AE
+:102700000102C3F80C2108BD9649002000200052A8
+:102710000F289ABF00F58060400400207047000039
+:102720004FF4003070470000102070470F2808B5A4
+:102730000BD8FFF7EDFF00F500330268013204D13A
+:1027400004308342F9D1012008BD0020FCE70000DD
+:102750000F2870B5054645D8FFF7D6FC224CFFF789
+:102760007FFF0646FFF78AFF4FF0FF33072D6361B7
+:10277000C4F8143120D82361FFF772FF2B0243F015
+:102780002403E360E36843F08003E36023695A07AE
+:10279000FCD42846FFF764FF4FF40031FFF7B8FF81
+:1027A00000F002F93046FFF78BFFFFF7B7FC284631
+:1027B000BDE87040FFF7BABFC4F81031FFF750FF13
+:1027C000A5F108031B0243F02403C4F80C31D4F82C
+:1027D0000C3143F08003C4F80C31D4F810315B079E
+:1027E000FBD4D6E7002070BD002000522DE9F84F41
+:1027F00040EA020305460C461746D80602D00020E0
+:10280000BDE8F88F27F01F07DFF8D4B0FFF736FFD9
+:102810002744BC4203D10120FFF752FFF0E72022FA
+:102820002946204601F074FC10B920352034F0E729
+:102830002B4605F120021E68711CE0D104339A4238
+:10284000F9D1FFF761FC05F17843234AB3F5801F06
+:10285000224B28BF9A4603F1040338BF9046A2F1E9
+:10286000080228BF9846A3F108033ABF9146DA460A
+:102870009946FFF7F5FEC8F80060A5EB040CD9F8FF
+:10288000002004F11C0142F00202C9F80020221FBE
+:10289000DAF8006016F00506FAD152F8043F8A42D1
+:1028A0004CF80230F4D1BFF34F8FFFF7D9FE4FF051
+:1028B000FF32C8F80020D9F8002022F00202C9F83F
+:1028C0000020FFF72BFC20222146284601F020FCA7
+:1028D0000028AAD030469FE7142000521021005251
+:1028E0001020005210B5084C237828B11BB9FFF70F
+:1028F000C5FE0123237010BD002BFCD02070BDE865
+:102900001040FFF7DDBE00BF964900200244074B90
+:10291000D2B210B5904200D110BD441C00B253F8A1
+:10292000200041F8040BE0B2F4E700BF504000582B
+:102930000E4B30B51C6F240405D41C6F1C671C6F34
+:1029400044F400441C670A4C02442368D2B243F4A6
+:1029500080732360074B904200D130BD441C51F876
+:10296000045B00B243F82050E0B2F4E700440258A0
+:10297000004802585040005807B5012201A9002024
+:10298000FFF7C4FF019803B05DF804FB13B50446DC
+:10299000FFF7F2FFA04205D0012201A90020019417
+:1029A000FFF7C6FF02B010BD0144BFF34F8F064BC7
+:1029B000884204D3BFF34F8FBFF36F8F7047C3F8C4
+:1029C0005C022030F4E700BF00ED00E0002070471B
+:1029D000034B1A681AB9034AD2F8D0241A60704718
+:1029E000984900200040025808B5FFF7F1FF024B5C
+:1029F0001868C0F3806008BD98490020EFF3098390
+:102A0000054968334A6B22F001024A6383F309885F
+:102A1000002383F31188704700EF00E0202080F34B
+:102A2000118862B60D4B0E4AD96821F4E0610904A1
+:102A3000090C0A430B49DA60D3F8FC2042F080729B
+:102A4000C3F8FC20084AC2F8B01F116841F0010128
+:102A500011601022DA7783F82200704700ED00E061
+:102A60000003FA0555CEACC5001000E0202310B5D8
+:102A700083F311880E4B5B6813F4006314D0F1EEFE
+:102A8000103AEFF309844FF08073683CE361094B1F
+:102A9000DB6B236684F30988FFF7E6FA10B1064B77
+:102AA000A36110BD054BFBE783F31188F9E700BF75
+:102AB00000ED00E000EF00E0F7030008FA03000873
+:102AC00070B5BFF34F8FBFF36F8F1A4A0021C2F862
+:102AD0005012BFF34F8FBFF36F8F536943F400332E
+:102AE0005361BFF34F8FBFF36F8FC2F88410BFF3F2
+:102AF0004F8FD2F8803043F6E074C3F3C900C3F3BC
+:102B00004E335B0103EA0406014646EA817501394A
+:102B1000C2F86052F9D2203B13F1200FF2D1BFF37B
+:102B20004F8F536943F480335361BFF34F8FBFF32B
+:102B30006F8F70BD00ED00E0FEE700000A4B0B4810
+:102B40000B4A90420BD30B4BC11EDA1C121A22F017
+:102B500003028B4238BF00220021FEF7A9B953F8C7
+:102B6000041B40F8041BECE7E44400086C4B002015
+:102B70006C4B00206C4B00207047000070B5D0E912
+:102B8000244300224FF0FF359E6804EB42135101AD
+:102B9000D3F80009002805DAD3F8000940F0804096
+:102BA000C3F80009D3F8000B002805DAD3F8000BAE
+:102BB00040F08040C3F8000B013263189642C3F81E
+:102BC0000859C3F8085BE0D24FF00113C4F81C3871
+:102BD00070BD000000EB8103D3F80CC02DE9F04379
+:102BE000DCF814204E1CD0F89050D2F800E005EB31
+:102BF000063605EB4118506870450AD30122D5F816
+:102C0000343802FA01F123EA0101C5F83418BDE8AD
+:102C1000F083AEEB0003BCF81040A34228BF23466C
+:102C2000D8F81849A4B2B3EB840FF0D89468A4F193
+:102C3000040959F8047F3760A4EB09071F44042FE7
+:102C4000F7D81C44034494605360D4E7890141F0F1
+:102C50002001016103699B06FCD41220FFF76EBAC4
+:102C600010B50A4C2046FEF7DFFE094BC4F8903041
+:102C7000084BC4F89430084C2046FEF7D5FE074BAD
+:102C8000C4F89030064BC4F8943010BD9C49002025
+:102C90000000084038430008384A00200000044083
+:102CA0004443000870B503780546012B5DD1494BBC
+:102CB000D0F89040984259D1474B0E216520D3F867
+:102CC000D82042F00062C3F8D820D3F8002142F0A7
+:102CD0000062C3F80021D3F80021D3F8802042F02D
+:102CE0000062C3F88020D3F8802022F00062C3F88D
+:102CF0008020D3F8803000F071FC384BE360384B13
+:102D0000C4F800380023D5F89060C4F8003EC02312
+:102D100023604FF40413A3633369002BFCDA01230F
+:102D20000C203361FFF70AFA3369DB07FCD4122069
+:102D3000FFF704FA3369002BFCDA00262846A66068
+:102D4000FFF71CFF6B68C4F81068DB68C4F81468F0
+:102D5000C4F81C68002B3AD1224BA3614FF0FF331B
+:102D60006361A36843F00103A36070BD1E4B9842EA
+:102D7000C8D1194B0E214D20D3F8D82042F0007253
+:102D8000C3F8D820D3F8002142F00072C3F8002124
+:102D9000D3F80021D3F8802042F00072C3F88020DD
+:102DA000D3F8802022F00072C3F88020D3F880206E
+:102DB000D3F8D82022F08062C3F8D820D3F80021BD
+:102DC00022F08062C3F80021D3F8003193E7074B6B
+:102DD000C3E700BF9C490020004402584014004053
+:102DE00003002002003C30C0384A0020083C30C0BC
+:102DF000F8B5D0F89040054600214FF00066204617
+:102E0000FFF724FFD5F8941000234FF001128F68CC
+:102E10004FF0FF30C4F83438C4F81C2804EB4312D8
+:102E200001339F42C2F80069C2F8006BC2F808097A
+:102E3000C2F8080BF2D20B68D5F89020C5F898308C
+:102E4000636210231361166916F01006FBD112207D
+:102E5000FFF774F9D4F8003823F4FE63C4F800389F
+:102E6000A36943F4402343F01003A3610923C4F88A
+:102E70001038C4F814380B4BEB604FF0C043C4F863
+:102E8000103B094BC4F8003BC4F81069C4F8003982
+:102E9000D5F8983003F1100243F48013C5F8982058
+:102EA000A362F8BD1443000840800010D0F89020C1
+:102EB00090F88A10D2F8003823F4FE6343EA011335
+:102EC000C2F80038704700002DE9F84300EB810399
+:102ED000D0F890500C468046DA680FFA81F9480124
+:102EE000166806F00306731E022B05EB41134FF024
+:102EF000000194BFB604384EC3F8101B4FF0010117
+:102F000004F1100398BF06F1805601FA03F39169AA
+:102F100098BF06F5004600293AD0578A04F15801B7
+:102F2000374349016F50D5F81C180B430021C5F8F1
+:102F30001C382B180127C3F81019A7405369611ECC
+:102F40009BB3138A928B9B08012A88BF5343D8F8FE
+:102F50009820981842EA034301F140022146C8F83C
+:102F60009800284605EB82025360FFF76FFE08EBDE
+:102F70008900C3681B8A43EA845348341E436401B2
+:102F80002E51D5F81C381F43C5F81C78BDE8F883CE
+:102F900005EB4917D7F8001B21F40041C7F8001BC7
+:102FA000D5F81C1821EA0303C0E704F13F030B4ADC
+:102FB0002846214605EB83035A60FFF747FE05EBE1
+:102FC0004910D0F8003923F40043C0F80039D5F88F
+:102FD0001C3823EA0707D7E700800010000400022E
+:102FE000D0F894201268C0F89820FFF7C7BD000001
+:102FF0005831D0F8903049015B5813F4004004D0A8
+:1030000013F4001F0CBF0220012070474831D0F894
+:10301000903049015B5813F4004004D013F4001FB2
+:103020000CBF02200120704700EB8101CB68196AB8
+:103030000B6813604B6853607047000000EB81031E
+:1030400030B5DD68AA691368D36019B9402B84BF15
+:10305000402313606B8A1468D0F890201C4402EB64
+:103060004110013C09B2B4FBF3F46343033323F092
+:10307000030343EAC44343F0C043C0F8103B2B684A
+:1030800003F00303012B0ED1D2F8083802EB4110F4
+:1030900013F4807FD0F8003B14BF43F0805343F01B
+:1030A0000053C0F8003B02EB4112D2F8003B43F062
+:1030B0000443C2F8003B30BD2DE9F041D0F89060E8
+:1030C00005460C4606EB4113D3F8087B3A07C3F8D4
+:1030D000087B08D5D6F814381B0704D500EB81030C
+:1030E000DB685B689847FA071FD5D6F81438DB070A
+:1030F0001BD505EB8403D968CCB98B69488A5A681B
+:10310000B2FBF0F600FB16228AB91868DA68904222
+:103110000DD2121AC3E90024202383F3118821461B
+:103120002846FFF78BFF84F31188BDE8F081012367
+:1031300003FA04F26B8923EA02036B81CB68002B4C
+:10314000F3D021462846BDE8F041184700EB810343
+:103150004A0170B5DD68D0F890306C692668E66089
+:1031600056BB1A444FF40020C2F810092A6802F036
+:103170000302012A0AB20ED1D3F8080803EB421465
+:1031800010F4807FD4F8000914BF40F0805040F064
+:103190000050C4F8000903EB4212D2F8000940F0D5
+:1031A0000440C2F800090122D3F8340802FA01F100
+:1031B0000143C3F8341870BD19B9402E84BF4020B4
+:1031C000206020681A442E8A8419013CB4FBF6F46E
+:1031D00040EAC44040F00050C6E700002DE9F0414D
+:1031E000D0F8906004460D4606EB4113D3F80879F9
+:1031F000C3F80879FB071CD5D6F81038DA0718D5BC
+:1032000000EB8103D3F80CC0DCF81430D3F800E0F5
+:10321000DA6896451BD2A2EB0E024FF000081A6046
+:10322000C3F80480202383F31188FFF78FFF88F30E
+:1032300011883B0618D50123D6F83428AB40134239
+:1032400012D029462046BDE8F041FFF7C3BC012358
+:1032500003FA01F2038923EA02030381DCF8083050
+:10326000002BE6D09847E4E7BDE8F0812DE9F84F60
+:10327000D0F8905004466E69AB691E4016F4805831
+:103280006E6103D0BDE8F84FFEF73EBC002E12DAA7
+:10329000D5F8003E9F0705D0D5F8003E23F0030384
+:1032A000C5F8003ED5F80438204623F00103C5F8E0
+:1032B0000438FEF755FC300505D52046FFF75EFCC7
+:1032C0002046FEF73DFCB1040CD5D5F8083813F0C4
+:1032D000060FEB6823F470530CBF43F4105343F410
+:1032E000A053EB60320704D56368DB680BB120465E
+:1032F0009847F30200F1BA80B70226D5D4F890902F
+:1033000000274FF0010A09EB4712D2F8003B03F403
+:103310004023B3F5802F11D1D2F8003B002B0DDAFA
+:1033200062890AFA07F322EA0303638104EB870345
+:10333000DB68DB6813B13946204698470137D4F87B
+:103340009430FFB29B689F42DDD9F00619D5D4F8BE
+:103350009000026AC2F30A1702F00F0302F4F0129F
+:10336000B2F5802F00F0CC80B2F5402F09D104EBEC
+:103370008303002200F58050DB681B6A974240F00F
+:10338000B2803003D5F8185835D5E90303D50021AC
+:103390002046FFF791FEAA0303D501212046FFF73F
+:1033A0008BFE6B0303D502212046FFF785FE2F031A
+:1033B00003D503212046FFF77FFEE80203D5042151
+:1033C0002046FFF779FEA90203D505212046FFF725
+:1033D00073FE6A0203D506212046FFF76DFE2B021D
+:1033E00003D507212046FFF767FEEF0103D508212B
+:1033F0002046FFF761FE700340F1A980E90703D57D
+:1034000000212046FFF7EAFEAA0703D50121204646
+:10341000FFF7E4FE6B0703D502212046FFF7DEFE2F
+:103420002F0703D503212046FFF7D8FEEE0603D56C
+:1034300004212046FFF7D2FEA80603D50521204629
+:10344000FFF7CCFE690603D506212046FFF7C6FE2E
+:103450002A0603D507212046FFF7C0FEEB0576D5E7
+:1034600020460821BDE8F84FFFF7B8BED4F8909089
+:1034700000274FF0010AD4F894305FFA87FB9B686D
+:103480009B453FF639AF09EB4B13D3F8002902F403
+:103490004022B2F5802F24D1D3F80029002A20DA67
+:1034A000D3F8002942F09042C3F80029D3F800294C
+:1034B000002AFBDB5946D4F89000FFF7C7FB2289AE
+:1034C0000AFA0BF322EA0303238104EB8B03DB6884
+:1034D0009B6813B159462046984759462046FFF746
+:1034E00079FB0137C7E7910701D1D0F80080072A9F
+:1034F00002F101029CBF03F8018B4FEA18283DE757
+:1035000004EB830300F58050DA68D2F818C0DCF8C9
+:103510000820DCE9001CA1EB0C0C00218F4208D133
+:10352000DB689B699A683A449A605A683A445A60E0
+:1035300027E711F0030F01D1D0F800808C4501F18D
+:10354000010184BF02F8018B4FEA1828E6E7BDE8C5
+:10355000F88F000008B50348FFF788FEBDE8084073
+:10356000FFF784BA9C49002008B50348FFF77EFEA8
+:10357000BDE80840FFF77ABA384A0020D0F890300A
+:1035800003EB4111D1F8003B43F40013C1F8003BB9
+:1035900070470000D0F8903003EB4111D1F80039AA
+:1035A00043F40013C1F8003970470000D0F89030A0
+:1035B00003EB4111D1F8003B23F40013C1F8003BA9
+:1035C00070470000D0F8903003EB4111D1F800397A
+:1035D00023F40013C1F8003970470000090100F11D
+:1035E0006043012203F56143C9B283F8001300F080
+:1035F0001F039A4043099B0003F1604303F56143B5
+:10360000C3F880211A60704730B50433039C0172FF
+:10361000002104FB0325C160C0E90653049B03633A
+:10362000059BC0E90000C0E90422C0E90842C0E9E6
+:103630000A11436330BD00000022416AC260C0E944
+:103640000411C0E90A226FF00101FEF7E7BD000096
+:10365000D0E90432934201D1C2680AB9181D7047FB
+:1036600000207047036919600021C2680132C260FE
+:10367000C269134482699342036124BF436A0361B0
+:10368000FEF7C0BD38B504460D46E3683BB162693C
+:103690000020131D1268A3621344E36207E0237A3B
+:1036A00033B929462046FEF79DFD0028EDDA38BDE6
+:1036B0006FF00100FBE70000C368C269013BC36013
+:1036C0004369134482699342436124BF436A43615F
+:1036D00000238362036B03B11847704770B5202342
+:1036E000044683F31188866A3EB9FFF7CBFF05468F
+:1036F00018B186F31188284670BDA36AE26A13F8F0
+:10370000015B9342A36202D32046FFF7D5FF00235B
+:1037100083F31188EFE700002DE9F84F04460E46C9
+:10372000174698464FF0200989F311880025AA46CC
+:10373000D4F828B0BBF1000F09D141462046FFF76D
+:10374000A1FF20B18BF311882846BDE8F88FD4E99A
+:103750000A12A7EB050B521A934528BF9346BBF1FB
+:10376000400F1BD9334601F1400251F8040B91423E
+:1037700043F8040BF9D1A36A403640354033A362C5
+:10378000D4E90A239A4202D32046FFF795FF8AF331
+:103790001188BD42D8D289F31188C9E730465A460C
+:1037A000FDF760FBA36A5E445D445B44A362E7E708
+:1037B00010B5029C0433017204FB0321C460C0E90C
+:1037C00006130023C0E90A33039B0363049BC0E98B
+:1037D0000000C0E90422C0E90842436310BD0000B4
+:1037E000026A6FF00101C260426AC0E9042200224D
+:1037F000C0E90A22FEF712BDD0E904239A4201D1A2
+:10380000C26822B9184650F8043B0B60704700208C
+:1038100070470000C3680021C2690133C360436977
+:10382000134482699342436124BF436A4361FEF7B4
+:10383000E9BC000038B504460D46E3683BB1236996
+:1038400000201A1DA262E2691344E36207E0237AB2
+:1038500033B929462046FEF7C5FC0028EDDA38BD0D
+:103860006FF00100FBE7000003691960C268013ACC
+:10387000C260C269134482699342036124BF436AF0
+:10388000036100238362036B03B118477047000094
+:1038900070B520230D460446114683F31188866ACD
+:1038A0002EB9FFF7C7FF10B186F3118870BDA36A68
+:1038B0001D70A36AE26A01339342A36204D3E169F3
+:1038C00020460439FFF7D0FF002080F31188EDE790
+:1038D0002DE9F84F04460D46904699464FF0200AD0
+:1038E0008AF311880026B346A76A4FB94946204695
+:1038F000FFF7A0FF20B187F311883046BDE8F88FAD
+:10390000D4E90A073A1AA8EB0607974228BF1746D8
+:10391000402F1BD905F1400355F8042B9D4240F878
+:10392000042BF9D1A36A40364033A362D4E90A23B9
+:103930009A4204D3E16920460439FFF795FF8BF3DF
+:1039400011884645D9D28AF31188CDE729463A46EF
+:10395000FDF788FAA36A3D443E443B44A362E5E791
+:10396000D0E904239A4217D1C3689BB1836A8BB113
+:10397000043B9B1A0ED01360C368013BC360C3694C
+:103980001A4483699A42026124BF436A0361002397
+:1039900083620123184670470023FBE700F0DAB882
+:1039A000034B002258631A610222DA60704700BF9D
+:1039B000000C0040014B0022DA607047000C004010
+:1039C000014B5863704700BF000C0040014B586A20
+:1039D000704700BF000C00404B6843608B688360F9
+:1039E000CB68C3600B6943614B6903628B694362B7
+:1039F0000B6803607047000008B53C4B40F2FF7154
+:103A00003B48D3F888200A43C3F88820D3F888209D
+:103A100022F4FF6222F00702C3F88820D3F888203E
+:103A2000D3F8E0200A43C3F8E020D3F808210A4382
+:103A3000C3F808212F4AD3F808311146FFF7CCFF0D
+:103A400000F5806002F11C01FFF7C6FF00F5806001
+:103A500002F13801FFF7C0FF00F5806002F1540168
+:103A6000FFF7BAFF00F5806002F17001FFF7B4FFC5
+:103A700000F5806002F18C01FFF7AEFF00F5806079
+:103A800002F1A801FFF7A8FF00F5806002F1C40170
+:103A9000FFF7A2FF00F5806002F1E001FFF79CFF55
+:103AA00000F5806002F1FC01FFF796FF02F58C71D2
+:103AB00000F58060FFF790FF00F000F90E4BD3F89F
+:103AC000902242F00102C3F89022D3F8942242F0EF
+:103AD0000102C3F894220522C3F898204FF06052E7
+:103AE000C3F89C20054AC3F8A02008BD0044025832
+:103AF000000002585043000800ED00E01F000803DA
+:103B000008B500F0E5FAFEF7DDFA0F4BD3F8DC203C
+:103B100042F04002C3F8DC20D3F8042122F0400236
+:103B2000C3F80421D3F80431084B1A6842F00802A4
+:103B30001A601A6842F004021A60FEF749FFBDE8F5
+:103B40000840FEF7E7BC00BF0044025800180248D6
+:103B500070470000114BD3F8E82042F00802C3F888
+:103B6000E820D3F8102142F00802C3F810210C4AD3
+:103B7000D3F81031D36B43F00803D363C722094B4A
+:103B80009A624FF0FF32DA6200229A615A63DA6079
+:103B90005A6001225A611A60704700BF00440258FF
+:103BA0000010005C000C0040094A08B51169D36898
+:103BB0000B40D9B29B076FEA0101116107D52023A1
+:103BC00083F31188FEF79EFA002383F3118808BD62
+:103BD000000C0040384B4FF0FF31D3F88020C3F881
+:103BE0008010D3F880200022C3F88020D3F8800012
+:103BF000D3F88400C3F88410D3F88400C3F8842079
+:103C0000D3F88400D86F40F0FF4040F4FF0040F448
+:103C10003F5040F03F00D867D86F20F0FF4020F4BD
+:103C2000FF0020F43F5020F03F00D867D86FD3F852
+:103C300088006FEA40506FEA5050C3F88800D3F80C
+:103C40008800C0F30A00C3F88800D3F88800D3F8CE
+:103C50009000C3F89010D3F89000C3F89020D3F8E8
+:103C60009000D3F89400C3F89410D3F89400C3F8EC
+:103C70009420D3F89400D3F89800C3F89810D3F8A0
+:103C80009800C3F89820D3F89800D3F88C00C3F8B4
+:103C90008C10D3F88C00C3F88C20D3F88C00D3F8A8
+:103CA0009C00C3F89C10D3F89C10C3F89C20D3F858
+:103CB0009C3000F0DDB900BF00440258614B012286
+:103CC000C3F80821604BD3F8F42042F00202C3F895
+:103CD000F420D3F81C2142F00202C3F81C21022276
+:103CE000D3F81C31594BDA605A689104FCD5584A14
+:103CF0001A6001229A60574ADA6000221A614FF472
+:103D000040429A61514B9A699204FCD51A6842F478
+:103D100080721A604C4B1A6F12F4407F04D04FF43B
+:103D200080321A6700221A671A6842F001021A608C
+:103D3000454B1A685007FCD500221A611A6912F027
+:103D40003802FBD1012119604FF0804159605A6758
+:103D5000414ADA62414A1A611A6842F480321A60B2
+:103D6000394B1A689103FCD51A6842F480521A60E4
+:103D70001A689204FCD53A4A3A499A6200225A6378
+:103D800019633949DA6399635A64384A1A64384ABC
+:103D9000DA621A6842F0A8521A602B4B1A6802F0D5
+:103DA0002852B2F1285FF9D148229A614FF4886213
+:103DB000DA6140221A622F4ADA644FF080521A65A3
+:103DC0002D4A5A652D4A9A6532232D4A136013688D
+:103DD00003F00F03022BFAD11B4B1A6942F00302C6
+:103DE0001A611A6902F03802182AFAD1D3F8DC20D5
+:103DF00042F00052C3F8DC20D3F8042142F0005214
+:103E0000C3F80421D3F80421D3F8DC2042F0804227
+:103E1000C3F8DC20D3F8042142F08042C3F8042127
+:103E2000D3F80421D3F8DC2042F00042C3F8DC20B0
+:103E3000D3F8042142F00042C3F80421D3F804313E
+:103E4000704700BF008000510044025800480258EB
+:103E500000C000F0020000010000FF01008890088F
+:103E600032206000630209011D02040047040508B6
+:103E7000FD0BFF01200000200010E0000001010008
+:103E8000002000524FF0B04208B5D2F8883003F05D
+:103E90000103C2F8883023B1044A13680BB150689B
+:103EA0009847BDE80840FEF7E1BD00BFEC4A00209E
+:103EB0004FF0B04208B5D2F8883003F00203C2F8E0
+:103EC000883023B1044A93680BB1D0689847BDE8A5
+:103ED0000840FEF7CBBD00BFEC4A00204FF0B042D7
+:103EE00008B5D2F8883003F00403C2F8883023B153
+:103EF000044A13690BB150699847BDE80840FEF7C2
+:103F0000B5BD00BFEC4A00204FF0B04208B5D2F872
+:103F1000883003F00803C2F8883023B1044A93695B
+:103F20000BB1D0699847BDE80840FEF79FBD00BFC0
+:103F3000EC4A00204FF0B04208B5D2F8883003F0C8
+:103F40001003C2F8883023B1044A136A0BB1506AD7
+:103F50009847BDE80840FEF789BD00BFEC4A002045
+:103F60004FF0B04310B5D3F8884004F47872C3F82A
+:103F70008820A30604D5124A936A0BB1D06A9847E9
+:103F8000600604D50E4A136B0BB1506B984721069F
+:103F900004D50B4A936B0BB1D06B9847E20504D55F
+:103FA000074A136C0BB1506C9847A30504D5044A1B
+:103FB000936C0BB1D06C9847BDE81040FEF756BD2E
+:103FC000EC4A00204FF0B04310B5D3F8884004F419
+:103FD0007C42C3F88820620504D5164A136D0BB1E4
+:103FE000506D9847230504D5124A936D0BB1D06DDF
+:103FF0009847E00404D50F4A136E0BB1506E9847F2
+:10400000A10404D50B4A936E0BB1D06E984762049D
+:1040100004D5084A136F0BB1506F9847230404D599
+:10402000044A936F0BB1D06F9847BDE81040FEF77C
+:104030001DBD00BFEC4A002008B50348FDF706F996
+:10404000BDE80840FEF712BDCC23002008B50348A8
+:10405000FDF7FCF8BDE80840FEF708BD3824002055
+:1040600008B5FFF7A1FDBDE80840FEF7FFBC000062
+:10407000062108B50846FFF7B1FA06210720FFF729
+:10408000ADFA06210820FFF7A9FA06210920FFF75B
+:10409000A5FA06210A20FFF7A1FA06211720FFF74B
+:1040A0009DFA06212820FFF799FA09217A20FFF7C7
+:1040B00095FA07213220FFF791FA0C212620FFF70D
+:1040C0008DFA0C215220BDE80840FFF787BA0000A6
+:1040D00008B5FFF77FFD00F00DF8FDF7C9FAFDF711
+:1040E000A1FCFDF773FBFFF733FDBDE80840FFF7C8
+:1040F00055BC00000023054A19460133102BC2E9C4
+:10410000001102F10802F8D1704700BFEC4A00200C
+:1041100010B501390244904201D1002005E0037836
+:1041200011F8014FA34201D0181B10BD0130F2E776
+:10413000034611F8012B03F8012B002AF9D170472F
+:1041400053544D333248373F3F3F0053544D333281
+:10415000483734332F37353300000000CC2300209C
+:10416000602E00200096000000000000000000000B
+:10417000000000000000000000000000000000003F
+:104180003916000825160008611600084D160008AB
+:104190005916000845160008311600081D160008BB
+:1041A0006D160008000000004917000835170008C8
+:1041B000711700085D1700086917000855170008F7
+:1041C000411700082D1700087D17000800000000A7
+:1041D00001000000000000006D61696E0000000039
+:1041E00069646C6500000000E0410008E82C0020D4
+:1041F000602E002001000000C12000080000000027
+:104200004172647550696C6F740025424F4152448D
+:10421000252D424C002553455249414C25000000B4
+:10422000020000000000000069190008D919000808
+:10423000400040000847002018470020020000000E
+:10424000000000000300000000000000211A000828
+:1042500000000000100000002847002000000000BF
+:1042600001000000000000009C4900200101020044
+:10427000B1240008C12300085D240008412400087F
+:10428000430000008842000809024300020100C008
+:10429000320904000001020201000524001001059A
+:1042A00024010001042402020524060001070582FE
+:1042B000030800FF09040100020A000000070501CD
+:1042C00002400000070581024000000012000000CB
+:1042D000D4420008120110010200004009124157A7
+:1042E00000020102030100000403090425424F41BA
+:1042F000524425006C756D696E6F75736265653526
+:104300000030313233343536373839414243444551
+:104310004600000000000000751B00082D1E00086C
+:10432000D91E000840004000D44A0020D44A002092
+:1043300001000000E44A002080000000400100006D
+:104340000800000000010000000400000800000058
+:104350000000802A00000000AAAAAAAA00000024E7
+:10436000FFFF00000000000000A00A000001400064
+:1043700000000000AAAAAAAA00010000FFFF000096
+:1043800000000000000000001000004000000000DD
+:10439000AAAAAAAA10000040FFFF00000000000027
+:1043A000000000000068000000000000AAAAAAAAFD
+:1043B00000540000FFFF0000000070070000000034
+:1043C0000080024000000000AAAAAAAA0040014002
+:1043D000FFFF000000000070070000000000000068
+:1043E00000000000AAAAAAAA00000000FFFF000027
+:1043F00000000000000000000000000000000000BD
+:10440000AAAAAAAA00000000FFFF00000000000006
+:10441000000000000000000000000000AAAAAAAAF4
+:1044200000000000FFFF000000000000000000008E
+:104430000000000000000000AAAAAAAA00000000D4
+:10444000FFFF00000000000000000000000000006E
+:1044500000000000AAAAAAAA00000000FFFF0000B6
+:10446000000000000000000000000000000000004C
+:10447000AAAAAAAA00000000FFFF00000000000096
+:104480000000000000000000050400000000000023
+:1044900000001E0000000000FF00000000000000FF
+:1044A000404100083F000000500400004B4100085C
+:1044B0003F00000000960000000008009600000089
+:1044C0000008000004000000E842000800000000AE
+:1044D00000000000000000000000000000000000DC
+:0444E00000000000D8
:00000001FF
diff --git a/Tools/bootloaders/mRo-M10095_bl.bin b/Tools/bootloaders/mRo-M10095_bl.bin
index 6a6d9fca48cd96..377091dfc2df16 100755
Binary files a/Tools/bootloaders/mRo-M10095_bl.bin and b/Tools/bootloaders/mRo-M10095_bl.bin differ
diff --git a/Tools/bootloaders/mRo-M10095_bl.elf b/Tools/bootloaders/mRo-M10095_bl.elf
index 2a0813d9b78435..67ac806284a39b 100755
Binary files a/Tools/bootloaders/mRo-M10095_bl.elf and b/Tools/bootloaders/mRo-M10095_bl.elf differ
diff --git a/Tools/bootloaders/mRo-M10095_bl.hex b/Tools/bootloaders/mRo-M10095_bl.hex
index d7264495c62e03..30030e9f4f2bba 100644
--- a/Tools/bootloaders/mRo-M10095_bl.hex
+++ b/Tools/bootloaders/mRo-M10095_bl.hex
@@ -1,19 +1,19 @@
:020000040800F2
-:1000000000070020F5040008292C0008A92B00088F
-:10001000012C0008A92B0008D52B0008F7040008C4
-:10002000F7040008F7040008F70400087D3A000808
+:1000000000070020F5040008492C0008012C000816
+:10001000292C0008012C0008212C0008F7040008F6
+:10002000F7040008F7040008F7040008193C00086A
:10003000F7040008F7040008F7040008F7040008B4
:10004000F7040008F7040008F7040008F7040008A4
-:10005000F7040008F7040008AD4C0008D54C000870
-:10006000FD4C0008254D00084D4D0008F704000820
+:10005000F7040008F7040008914F0008B94F0008A2
+:10006000E14F00080950000831500008F70400086B
:10007000F7040008F7040008F7040008F704000874
:10008000F7040008F7040008F7040008F704000864
-:10009000F70400082528000835280008754D0008D9
+:10009000F7040008E12B0008F12B00085950000874
:1000A000F7040008F7040008F7040008F704000844
-:1000B0005D4E0008F7040008F7040008F704000884
+:1000B00041510008F7040008F7040008F70400089D
:1000C000F7040008F7040008F7040008F704000824
-:1000D000F7040008494E0008F7040008F704000878
-:1000E000D94D0008F7040008F7040008F7040008D9
+:1000D000F70400082D510008F7040008F704000891
+:1000E000BD500008F7040008F7040008F7040008F2
:1000F000F7040008F7040008F7040008F7040008F4
:10010000F7040008F7040008F7040008F7040008E3
:10011000F7040008F7040008F7040008F7040008D3
@@ -29,7 +29,7 @@
:1001B000F7040008F7040008F7040008F704000833
:1001C000F7040008F7040008F7040008F704000823
:1001D000F7040008F7040008F7040008F704000813
-:1001E000611800080000000000000000000000008E
+:1001E0007D16000800000000000000000000000074
:1001F00053B94AB9002908BF00281CBF4FF0FF318E
:100200004FF0FF3000F074B9ADF1080C6DE904CE89
:1002100000F006F8DDF804E0DDE9022304B07047E1
@@ -78,1258 +78,1283 @@
:1004C0004B45A9D2B9EB020864EB0C0E0138A3E747
:1004D0004646EAE7204694E74046D1E7D0467BE728
:1004E000023B614432E7304609E76444023842E7A0
-:1004F000704700BF02E000F000F8FEE772B63A482D
-:1005000080F30888394880F3098839484EF6085145
-:10051000CEF20001086040F20000CCF200004EF67E
-:100520003471CEF200010860BFF34F8FBFF36F8FBD
-:1005300040F20000C0F2F0004EF68851CEF2000109
-:100540000860BFF34F8FBFF36F8F4FF00000E1EEF5
-:10055000100A4EF63C71CEF200010860062080F3CE
-:100560001488BFF36F8F04F033FA04F00FFA04F02D
-:1005700059FA4FF055301F491B4A91423CBF41F890
-:10058000040BFAE71C49194A91423CBF41F8040B9D
-:10059000FAE71A491A4A1B4B9A423EBF51F8040B1C
-:1005A00042F8040BF8E700201749184A91423CBF73
-:1005B00041F8040BFAE704F0EDF904F079FA144C71
-:1005C000144DAC4203DA54F8041B8847F9E700F0F5
-:1005D00041F8114C114DAC4203DA54F8041B884722
-:1005E000F9E704F0D5B9000000070020002300203F
-:1005F000000000080001002000070020B852000899
-:10060000002300208C23002090230020B84F0020DE
-:10061000E0010008E4010008E4010008E40100082A
-:100620002DE9F04F2DED108AC1F80CD0C3689D461E
-:10063000BDEC108ABDE8F08F002383F311882846B3
-:10064000A047002003F098FEFEE703F011FE00DF54
-:10065000FEE70000F8B504F03BF9074604F08CF91A
-:100660000546A0BB1F4B9F4231D001339F4231D082
-:100670001D4B27F0FF029A422FD1F8B200F036FD51
-:100680002E4642F2107400F03BFF08B100242646CB
-:1006900000F032FD08B90646044635B1134B9F42BF
-:1006A00003D004F061F900242646002004F01AF972
-:1006B0000EB100F063F801F049FA00F045FF01F0D7
-:1006C00035F9204600F0AEF800F058F8F9E72E466C
-:1006D0000024D8E704460126D5E706464FF47A748D
-:1006E000D1E700BF010007B0000008B0263A09B00A
-:1006F00008B501F0EDF8A0F120035842584108BDBB
-:1007000007B541F21203022101A8ADF8043001F04F
-:10071000FDF803B05DF804FB10B5202383F31188C6
-:100720001248C3680BB103F09FFE114A0F48002323
-:100730004FF47A7103F05CFE002383F311880D4CB3
-:10074000236813B12368013B2360636813B16368B6
-:10075000013B6360084B1B7833B9636823B90220FF
-:1007600001F082F93223636010BD00BF90230020A6
-:1007700019070008AC240020A423002038B5234A20
-:10078000234B1968013140D004339342F9D1214CF5
-:100790001F4DD4F80428AA4237D31F4B9B6803F19E
-:1007A000006303F5F0439A422FD204F0AFF804F04F
-:1007B000C1F8002001F0D4F8184B0220187001F0A5
-:1007C0004BF9174B9A6D00229A65996F9A67996F4A
-:1007D000D96DDA65D96FDA67D96F196E1A66D3F8F1
-:1007E0008010C3F88020D3F8803072B64FF0E02339
-:1007F0002021C3F8085DD4F80038D4F8042881F328
-:1008000011889D4683F30888104738BD207800087A
-:10081000007800080070000800230020A4230020B6
-:10082000001002402DE9F04F93B0AC4B0090202215
-:10083000FF210AA89D6801F033F9A94A1378A3B9EA
-:10084000A8480121C3601170202383F31188C36875
-:100850000BB103F009FEA44AA24800234FF47A71B9
-:1008600003F0C6FD002383F31188009B9F4A03B168
-:1008700013609F49009C00230B70536098469B4671
-:100880001E469A46012001F0E7F824B1974B1B68F9
-:10089000002B00F01C82002001F01AF80390039B4B
-:1008A000002B01DA00F096FE039B002BEDDB01200C
-:1008B00001F0CAF8039B213B162BE3D801A252F8A2
-:1008C00023F000BF2109000849090008DD090008DC
-:1008D000850800088508000885080008710A0008D6
-:1008E000430C00085D0B0008BF0B0008E70B000875
-:1008F0000D0C0008850800081F0C0008850800087A
-:10090000910C0008C109000885080008D50C0008F2
-:100910002D090008C109000885080008BF0B000860
-:100920000220FFF7E5FE002840F0FB81009B02213A
-:10093000B8F1000F08BF1C4605A841F21233ADF80C
-:10094000143000F0E3FF9DE74FF47A7000F0C0FF31
-:10095000071EEBDB0220FFF7CBFE0028E6D0013FAD
-:10096000052F00F2E081DFE807F0030A0D101336CF
-:1009700005230593042105A800F0C8FF17E0574898
-:100980000421F9E75B480421F6E75B480421F3E71B
-:100990004FF01C09484600F0E5FF09F104090590F5
-:1009A000042105A800F0B2FFB9F12C0FF2D101200B
-:1009B00000FA07F747EA0B0B5FFA8BFB4FF0000AD0
-:1009C00001F0BAF826B10BF00B030B2B08BF002483
-:1009D000FFF796FE56E749480421CDE7002EA5D043
-:1009E0000BF00B030B2BA1D10220FFF781FE074672
-:1009F00000289BD001203E4E00F0B2FF0220307054
-:100A000001F02AF84FF000085FFA88F9484600F034
-:100A1000B9FF044690B1484600F0C4FF08F1010850
-:100A20000028F1D1B846044641F21213022105A86C
-:100A3000ADF814303E4600F069FF23E701230220A1
-:100A4000337001F001F82546244B9B68AB4207D96F
-:100A5000284600F087FF013040F068810435F3E755
-:100A6000234B00251D70214BB8465D603E46A7E72D
-:100A7000002E3FF45BAF0BF00B030B2B7FF456AF54
-:100A80001B4B0220187000F0E7FF322000F020FF1F
-:100A9000B0F10009FFF64AAF19F003077FF446AF43
-:100AA0000E4A926809EB050393423FF63FAFB9F552
-:100AB000807F3FF73BAF124B0193B94522DD4FF4E6
-:100AC0007A7000F005FF0390039A002AFFF62EAF1C
-:100AD000019B039A03F8012B0137EDE70023002067
-:100AE000A82400209023002019070008AC2400202F
-:100AF000A423002004230020082300200C2300202E
-:100B0000A8230020C820FFF7F3FD074600283FF484
-:100B10000DAF1F2D11D8C5F120024A450AAB25F0B3
-:100B2000030028BF4A4683490192184400F0A6FFFB
-:100B3000019A8048FF2100F0B3FF4FEAA9037D49E5
-:100B40000193C9F38702284600F0B2FF0646002849
-:100B50003FF46AAF019B05EB830531E70220FFF705
-:100B6000C7FD00283FF4E2AE00F038FF00283FF454
-:100B7000DDAE0027B946704B9B68BB4218D91F2FCA
-:100B800011D80A9B01330ED027F0030312AA134495
-:100B900053F8203C05934846042205A902F052F878
-:100BA00004378146E7E7384600F0DCFE0590F2E7BF
-:100BB000CDF81490042105A800F0A8FE00E700235A
-:100BC000642104A8049300F097FE00287FF4AEAEE1
-:100BD0000220FFF78DFD00283FF4A8AE049800F036
-:100BE000F3FE0590E6E70023642104A8049300F0D7
-:100BF00083FE00287FF49AAE0220FFF779FD0028DB
-:100C00003FF494AE049800F0E1FEEAE70220FFF71B
-:100C10006FFD00283FF48AAE00F0F0FEE1E702200D
-:100C2000FFF766FD00283FF481AE05A9142000F00F
-:100C3000EBFE04210746049004A800F067FE394645
-:100C4000B9E7322000F044FE071EFFF66FAEBB0787
-:100C50007FF46CAE384A926807EB0A0393423FF682
-:100C600065AE0220FFF744FD00283FF45FAE27F099
-:100C700003075744BA453FF4A3AE504600F072FE56
-:100C80000421059005A800F041FE0AF1040AF1E7ED
-:100C90004FF47A70FFF72CFD00283FF447AE00F0C8
-:100CA0009DFE002844D00A9B01330BD008220AA9DC
-:100CB000002000F0FDFE00283AD02022FF210AA8E3
-:100CC00000F0EEFEFFF71CFD1C4803F05BFB13B0C9
-:100CD000BDE8F08F002E3FF429AE0BF00B030B2B79
-:100CE0007FF424AE0023642105A8059300F004FEE0
-:100CF000074600287FF41AAE0220FFF7F9FC814670
-:100D000000283FF413AEFFF7FBFC41F2883003F0FC
-:100D100039FB059800F026FF4E4600F00DFF3C46DB
-:100D2000B0E506464CE64FF0000AFFE5B8467BE624
-:100D3000374679E6A823002000230020A086010082
-:100D4000094A136849F2690099B21B0C00FB013390
-:100D50001360064B186844F2506182B2000C01FB2C
-:100D60000200186080B27047142300201023002076
-:100D700010B500211022044600F092FE034B03CB75
-:100D8000206061601868A06010BD00BF9075FF1FF3
-:100D90002DE9F043224DBBB001F04EFFAB6840F2AD
-:100DA000ED22C31A934232D906AFA8602B462822FF
-:100DB0000021384602F01EFC05F10E0000F068FE2E
-:100DC000002604465FFA80F905F10E08F3B2F1003F
-:100DD000994501F1280107D908EB06030822384696
-:100DE00002F008FC0136F1E708230122CDE90232C6
-:100DF00005340C4B0193A4B230230093CDE9047465
-:100E000005A3D3E90023297B074802F00BFA3BB086
-:100E1000BDE8F083AFF3008078F6339F93CACD8DA1
-:100E2000A8490020B5490020CC34002070B50D46FB
-:100E300014461E4602F08CF950B9022E10D1012C36
-:100E40000ED112A3D3E90023C5E90023012007E056
-:100E5000282C10D005D8012C09D0052C0FD000204B
-:100E600070BD302CFBD10BA3D3E90023ECE70BA31F
-:100E7000D3E90023E8E70BA3D3E90023E4E70BA3BE
-:100E8000D3E90023E0E700BFAFF30080401DA120BD
-:100E900026812A0B78F6339F93CACD8D9E6AC42192
-:100EA000818A46EE26417272DF25D7B7F017304AA5
-:100EB00039059E5613B504462346084620220021D4
-:100EC000019002F097FB22790198032A234628BF5C
-:100ED000032203F8042F2021022202F08BFB627907
-:100EE0000198072A234628BF072203F8052F22214D
-:100EF000032202F07FFBA2790198072A234628BF2C
-:100F0000072203F8062F2521032202F073FB019824
-:100F100004F108031022282102F06CFB382002B0F3
-:100F200010BD00002DE9F04FADF5017D21AD0EAEF5
-:100F300040F2751280460F4622A80021296000F079
-:100F4000AFFD48220021304600F0AAFD01F074FEFA
-:100F5000564B4FF47A72B0FBF2F0186093E807003A
-:100F6000012386E807000DF15A003382FFF700FFE6
-:100F700041F20413338407AB18464D4904F056F888
-:100F8000182230642946304686F83C20FFF792FF4D
-:100F900012AB044601460822284602F02BFB082229
-:100FA000A1180DF14903284602F024FB0DF14A0374
-:100FB000082204F11001284602F01CFB13AB20228A
-:100FC00004F11801284602F015FB14AB402204F18D
-:100FD0003801284602F00EFB16AB082204F1780116
-:100FE000284602F007FB0DF15903082204F18001A5
-:100FF000284602F0FFFA04F1880A0DF15A0904F5B7
-:10100000847B4B465146082228460AF1080A02F022
-:10101000F1FAD34509F10109F3D11BAB0822594676
-:10102000284602F0E7FA04F588744FF0000996F8B4
-:1010300034304B450AD9B36B21464B44082228462D
-:1010400002F0D8FA083409F10109F0E74FF000097D
-:1010500096F83C304B4504EBC90108D9336C0822A3
-:101060004B44284602F0C6FA09F10109F0E70023D3
-:101070000393BB7E0293073107F119030193C1F378
-:10108000CF010123CDE904510093F97E05A3D3E9F3
-:101090000023404602F0C6F80DF5017DBDE8F08F53
-:1010A000AFF300809E6AC421818A46EEB4240020FA
-:1010B0005C50000810B50A4B0A4A1A6003F58053C9
-:1010C00093F848203AB95C6C2CB1204601F032FC10
-:1010D000204603F015FFBDE81040034801F02ABC8C
-:1010E000F83400203C51000828450020014B1870BE
-:1010F000704700BFC0240020F0B5334B1C7B85B087
-:1011000034B1324B0E221A810024204605B0F0BDC6
-:101110002F4A1068516802AB03C308232D492E489B
-:101120000DEB030203F014FF054630B9274B2B48A3
-:101130000A221A8101F086FBE6E70169B1F5623FF8
-:1011400006D9224B26480B221A8101F07BFBDCE7F3
-:10115000438B40F21142934207D01C490C20088176
-:101160001946204801F06EFBCFE71F4A024402F106
-:101170001003994204D2154B1C4810221A81E4E74F
-:1011800010398E1A2046144901F05CFD324607469C
-:1011900005F11801204601F055FDAB689F4202D1D0
-:1011A000EB6898420AD0094B0D221A810090D5E9CC
-:1011B00002123B460E4801F045FBA5E70D4801F041
-:1011C00041FB0124A1E700BFA8490020B42400206E
-:1011D00009510008DC8703000078000878500008F7
-:1011E00084500008965000080888FFF7B4500008A3
-:1011F000D1500008FA5000082DE9F04FADB006AF0D
-:1012000080460C4601F0A4FF054600285AD1237EF3
-:10121000022B1BD1E38A012B18D101F00DFD0646EC
-:10122000FFF78EFD03464FF4C870DFF8D092B3FB92
-:10123000F0F206F5167602FB103316FA83F3C9F8BE
-:101240000030E37E33B9A84B00221A709C37BD46AC
-:10125000BDE8F08FA38AEEB2013BB34205F1010570
-:101260000BD93B1D1E44E90000960023082201F023
-:10127000F801204602F082F8ECE707F11400FFF7CE
-:1012800077FD324607F11401381D03F051FE0028A6
-:10129000D9D10F2E08D8944B1E70D9F80030A3F581
-:1012A0001673C9F80030D1E7FB1CF87001460093B3
-:1012B00007220346204602F061F8F978404601F023
-:1012C0003FFFC3E7E38A282B26D010D8012B1ED07E
-:1012D000052BBBD1BFF34F8F8449854BCA6802F4FD
-:1012E000E0621343CB60BFF34F8F00BFFDE7302BAD
-:1012F000ACD1637E7F4D01336A7BDBB29342E9461A
-:1013000003D1E27E2B7B9A4265D0CD469EE72146F3
-:101310004046FFF707FE99E7A38A013B9BB2C92B22
-:1013200094D8744D2E7B26BB05F10C030093082244
-:1013300033463146204602F021F8731CF2B2D90040
-:101340001E46A38A013B9A4205DA0E322A440092D5
-:1013500000230822EEE700230022C5E90023002332
-:10136000AB6085F8D730C5F8D8302B7B0BB9E37E5E
-:101370002B73002507F114093B1D08222946484616
-:10138000C7E90155FD6002F035F93B7A05F1010A24
-:10139000AB424FEACA0608D9FB6808222B44314603
-:1013A000484602F027F95546EFE7C6F3CF06E17E3F
-:1013B000CDE9049600230393A37E029319342823D6
-:1013C0000093019446A3D3E90023404601F02AFF8D
-:1013D000FFF7DEFC3AE74FF0000807F11403A7F827
-:1013E00014801022009341460123204601F0C6FFDD
-:1013F000A68A023EB6B2F31C9B109B000733DB08A3
-:10140000A9EBC3039D460DF1180A1FFA88F34FEAB2
-:10141000C801B34201F110010AD20AEB080300939C
-:1014200008220023204601F0A9FF08F10108ECE79B
-:1014300095F8D70000F0A6FAD5F8D83004461BB9C5
-:1014400095F8D70000F0AEFAD5F8D83033449C4276
-:1014500004D295F8D700013000F0A4FA4FEA960BB9
-:101460004FF000081FFA88F18B45D5E9003209D901
-:101470000AEB880103EB8800012200F019FB08F158
-:101480000108EFE7F31842F10002C5E90032D5F890
-:10149000D83095F8D70006EB0308C5F8D88000F0DF
-:1014A00071FA804509D395F8D730D5F8D8000133C3
-:1014B000001B85F8D730C5F8D800FF2E08D80023C8
-:1014C0002B7300F08BFAFFF717FE08B1FFF756F900
-:1014D0002B68094A9B0A013313810023AB6014E790
-:1014E00026417272DF25D7B7C534002000ED00E039
-:1014F0000400FA05A8490020B4240020C8340020C4
-:1015000010B54FF000540C4B22689A4211D10B4B8E
-:10151000627D1A700A48237D03730A49C9220E307E
-:1015200000F0ACFAE0220021204600F0B9FA0120D8
-:1015300010BD0020FCE700BF9AAD44C5C0240020C8
-:10154000A84900201600002037B5194D19491A483E
-:1015500002236B710022012300F0A6FD00230193FA
-:10156000164B174900931748174B4FF4805201F060
-:10157000C1FD164B197811B1124801F0E1FD01F0DF
-:101580005BFB0446FFF7DCFB4FF4C873B0FBF3F2E0
-:1015900002FB130304F5167010FA83F00C4B18606D
-:1015A00003F0EAF908B10F232B8103B030BD00BF6F
-:1015B000B424002040420F00F83400202D0E000813
-:1015C000C4240020CC340020F9110008C0240020DD
-:1015D000C83400202DE9F04F2DED028B97A7D7E9F5
-:1015E00000670FF26029D9E900898E4C95B0DFF8C9
-:1015F0005CA2DFF85CB2204601F078FE034650B3EF
-:101600000025CDE911551095ADF84C50027B8DF8B1
-:101610004C209968406811AA03C21B6843F000433C
-:10162000109301F00BFB10EB0A0241F1000300954F
-:1016300010A9584600F0F4FAA8427B4A05DD20467E
-:1016400001F058FE784A1570D5E71378072B00F2A1
-:10165000BA80013313700DAD9FED708B0023DFF85E
-:10166000F0B10C93ADF83C300D936B6000230DF19D
-:1016700025028DED008B4FF0010A09A958468DF81F
-:1016800025308DF824A001F073F89DF82420002364
-:10169000002A40F09C80204601F05AFD05460028B3
-:1016A00047D1DFF8B0B101F0C7FADBF8003098425B
-:1016B0003FD301F0C1FA0790FFF742FB079A4FF4BE
-:1016C000C87302F51672B0FBF3F101FB130312FAB3
-:1016D00083F3CBF80030DFF880B19BF8001007915E
-:1016E000002914BF2B46534610A88DF83030FFF761
-:1016F0003FFB0799C1F11002D2B2062A10AB28BFF6
-:10170000062219440DF13100079200F0B7F9079A4B
-:101710000CAB0393182302930132444BD2B2CDE9B0
-:1017200000A304923B463246204601F013FD8BF89D
-:10173000005001F081FA3E4A3E4D1368C31AB3F5DA
-:101740007A7F33D3106001F079FA02460B462046C7
-:1017500001F0DAFD204601F0FBFC38B32B7BDFF80B
-:10176000FCA0002B14BF032302238AF8053001F0EC
-:1017700063FA0DF1400B4FF47A735946B0FBF3F066
-:10178000CAF800005046FFF795FB18230730029374
-:10179000294B0193C0F3CF0040F25513CDE903B0BC
-:1017A000009342464B46204601F0D4FC2B7B2BB1E4
-:1017B000FFF7EEFA2B7B002B7FF419AF15B0BDECD1
-:1017C000028BBDE8F08F204601F094FD43E74FF017
-:1017D000904110A84A6982F010024A61194610220D
-:1017E00000F05EF90DF126030AAA0CA9584600F094
-:1017F00025FB95E8030011AB83E803009DF83C301E
-:101800008DF84C300C9B109310A9DDE90A2320467B
-:1018100001F038FF2AE700BFAFF3008000000000AE
-:1018200000000000CC3400208D4A0020C434002089
-:10183000884A0020A84900208C4A0020401DA12091
-:1018400026812A0BF1C6A7C1D068080F40420F00BD
-:10185000F8340020C8340020C5340020B42400200F
-:1018600008B5054800F08EFBBDE80840034A04496E
-:10187000002003F03FBB00BFF8340020E04A002006
-:10188000B510000870B50F4B1B780133DBB2012B8C
-:101890000C4611D80C4D29684FF47A730E6AA2FBDE
-:1018A0000332014622462846B047844204D1074B02
-:1018B00000221A70012070BD4FF4FA7002F062FD30
-:1018C0000020F8E718230020E44A0020D44A002032
-:1018D00007B50023024601210DF107008DF80730FE
-:1018E000FFF7D0FF20B19DF8070003B05DF804FBBF
-:1018F0004FF0FF30F9E700000A4608B50421FFF772
-:10190000C1FF80F00100C0B2404208BD30B4054CB8
-:101910002368DD69044B0A46AC460146204630BCCC
-:10192000604700BFE44A0020A086010070B502F0C5
-:1019300061FE094E094D30800024286833888342B7
-:1019400008D902F053FE2B6804440133B4F5F04F7C
-:101950002B60F2D370BD00BFD64A0020904A002011
-:1019600002F008BF00F1006000F5E040D0F8000888
-:101970007047000000F10060920000F5F04002F0B6
-:101980007DBE0000054B1A68054B1B889B1A8342DD
-:1019900002D9104402F02ABE00207047904A00206D
-:1019A000D64A002038B5074D04462868204402F086
-:1019B00023FE28B928682044BDE8384002F02EBE36
-:1019C00038BD00BF904A00200020704700F1005051
-:1019D000A0F51040D0F8900570470000064991F836
-:1019E000243033B10023086A81F824300822FFF73D
-:1019F000C1BF0120704700BF944A0020014B186806
-:101A0000704700BF002004E070B50E4B5C6893F98E
-:101A10000860421E0A44013C0B46934207D214F967
-:101A2000015F581C2DB100F8015C0346F5E718462C
-:101A300005E02C2482421C7001D9981C5E70401A6B
-:101A400070BD00BF1C230020022802BF4FF090434E
-:101A500010229A6170470000022802BF4FF09043A5
-:101A60004FF480129A617047022801BF4FF09042F4
-:101A7000536983F0100353617047000010B50023D1
-:101A8000934203D0CC5CC4540133F9E710BD00008D
-:101A900003460246D01A12F9011B0029FAD17047F9
-:101AA00002440346934202D003F8011BFAE7704751
-:101AB0002DE9F8431F4D144695F824200746884623
-:101AC00052BBDFF870909CB395F824302BB92022DC
-:101AD000FF2148462F62FFF7E3FF95F82400C0F18D
-:101AE0000802A24228BF2246D6B24146920005EB28
-:101AF0008000FFF7C3FF95F82430A41B1E44F6B204
-:101B0000082E17449044E4B285F82460DBD1FFF737
-:101B100065FF0028D7D108E02B6A03EB82038342DC
-:101B2000CFD0FFF75BFF0028CBD10020BDE8F883C2
-:101B30000120FBE7944A0020024B1A78024B1A70EE
-:101B4000704700BFD44A00201823002003490448EE
-:101B50004FF4E1330B6002F0AFBA00BFBC4A002083
-:101B6000E44A0020074B10B500210446182218460D
-:101B7000FFF796FF04600146BDE81040024802F0FE
-:101B80009BBA00BFBC4A0020E44A0020202383F314
-:101B9000118862B670470000002383F3118862B693
-:101BA0007047000001207047704700007047000038
-:101BB00010B41346026814680022A4465DF8044B72
-:101BC0006047000000F5805090F85904704700000D
-:101BD00000F5805090F852047047000000F58050E6
-:101BE00090F95804704700005020704700F580526B
-:101BF00008B5FFF7CBFFD2F89834D2F89404184414
-:101C0000D2F890341844D2F878341844D2F8883492
-:101C10001844D2F884341844FFF7BEFF08BD000012
-:101C20002DE9F74F0C4600F580511F4691F85234CC
-:101C3000BDF83090054690469BB1D1F8743401331D
-:101C4000C1F8743423689A0006D4237B082B0BD97F
-:101C5000627B0AB10F2B07D9D1F878340133C1F870
-:101C600078344FF0FF300FE0FFF790FFEB6AD3F8C6
-:101C7000C42012F4001A0AD0D1F87C340133C1F820
-:101C80007C34FFF789FF002003B0BDE8F08FD3F864
-:101C9000C46022686B6AC6F301464FF0480B002A05
-:101CA0001BFB063BB4BF42F080429204CBF80020FD
-:101CB00023685B0044BF42F00052CBF80020227B37
-:101CC000330643EA0243CBF80430607B720118B359
-:101CD00043F44013CBF80430D1F8A4340133C1F8F5
-:101CE000A434AB1803F58353197B41F02001197319
-:101CF000207B019200F002FE019A033080105FFA0F
-:101D00008AF383420AF1010A0DDA04EB83010BEB3B
-:101D1000830349689960F2E7AB1803F58353197B95
-:101D200060F34511E3E7EB6A0121B140C3F8CC1041
-:101D3000AB1803F58253C3E9048705EB461303F59B
-:101D400082532146183304F10C0051F804CB43F8B8
-:101D500004CB8142F9D1098819802A4441F26803F1
-:101D60002846D65002F5805209F0030392F86C1011
-:101D700043F0100321F01F010B4382F86C30FFF792
-:101D80000BFF42463B462146CDF8309003B0BDE8FC
-:101D9000F04F00F079BD000038B5C26A936923F0B6
-:101DA00001039361044600F047FF0546E36A9B691F
-:101DB000DB0706D500F040FF431BFA2BF6D90020C5
-:101DC00004E004F58054012084F8520438BD00007A
-:101DD00013B500F580540191606C00F0E1FD1F28FF
-:101DE0000AD90199606C202200F050FEA0F1200376
-:101DF0005842584102B010BD0020FBE708B500F57D
-:101E00008050FFF7C3FE406C00F09EFDBDE8084027
-:101E1000FFF7C2BE0022026082814260826070478A
-:101E200010B500220023C0E90023002304460381EB
-:101E30000C30FFF7EFFF204610BD00002DE9F04702
-:101E4000074688B007F5805468469A468846FFF7EB
-:101E50009DFE9146FFF7E4FF606C00F087FD1F28B0
-:101E60002CD9606C2022694600F092FE202825D1F2
-:101E700094F8523413B303AD444605AB2E4603CE5B
-:101E80009E4220606160354604F10804F6D1306856
-:101E90002060B388A380DDE90023C9E90023BDF8F1
-:101EA0000830AAF80030FFF777FE4A46534641460D
-:101EB000384608B0BDE8F04700F0D4BCFFF76CFE30
-:101EC000002008B0BDE8F0872DE9F84F0023064652
-:101ED000C0E90133284B46F8303B00F581540546F4
-:101EE00088463746103438462037FFF799FFA74217
-:101EF000F9D105F580544FF4805326630026C4E9D8
-:101F00000D366764012305F5835705F5A359E6638C
-:101F100084F8403084F84830103709F110094FF048
-:101F2000000A4FF0000B47E908ABA7F11800FFF7D4
-:101F300071FF203747F8286C4F45F4D184F8588456
-:101F4000A4F85A64A4F85C64A4F85E6484F860643D
-:101F5000A4F86264A4F86464A4F8666484F868640D
-:101F6000B8F1000F02D0054800F060FE044BEB62B0
-:101F70002846BDE8F88F00BF3C51000820510008FA
-:101F80000064004010B5044B197804464A1C1A70CE
-:101F9000FFF79AFF204610BDDD4A00202DE9F043EF
-:101FA00000295FD03048314BB3FBF1F381428CBF45
-:101FB0000A201120451EB3FBF0F700FB1730ECB2EE
-:101FC00020B1022D2846F5D8002037E07D1EB5F55A
-:101FD000806F33D2C4EBC40808F103034FEAE30E69
-:101FE000C3F3C703A4EB030C0EF101094FF47A709D
-:101FF0005FFA8CF60EFB000E59FA8CFCBEFBFCFC63
-:10200000BCF5617F1CDC1FFA8CF4581C56FA80F07A
-:1020100047431648B0FBF7F7B942D5D1013BDBB2D5
-:102020000F2BD1D8711EC9B207294FF0000005D877
-:10203000107114805580537191710120BDE8F083B7
-:1020400008F1FF334FEAE30CC3F3C703E41A0CF1C2
-:10205000010EE6B20CFB00005EFA84F4B0FBF4F46F
-:10206000A4B2D2E70846E9E73F420F0000127A0027
-:102070000B4B10B54FF45472044600211846FFF77D
-:102080000FFD084BA3614033E361D8332362F03383
-:102090006362E36A60610022C3F8C02010BD00BF24
-:1020A00000A4004070A400402DE9F04F00F58055D9
-:1020B000994695F85834012B89B004468A469046D3
-:1020C00004D90027384609B0BDE8F08F904A52F88D
-:1020D000231009B942F823008E49C4F80CA00B78EC
-:1020E00084F8109093B9FFF751FD8B4B9A6D42F035
-:1020F00000729A659A6B42F000729A639A6B22F0B2
-:1021000000729A6301230B70FFF746FD95F8513476
-:1021100073B902211520FFF739FD01F01BFE0221E2
-:10212000162001F017FE012385F85134FFF734FD26
-:10213000FFF72CFDE26A936923F01003936100F02E
-:102140007BFD0746E36A9E6916F0080607D000F09B
-:1021500073FDC31BFA2BF5D9FFF71EFDB1E79A6992
-:1021600042F001029A6100F067FD0746E36A9A694E
-:10217000D00705D400F060FDC31BFA2BF6D9EBE7BE
-:102180009A6942F002029A61E36A00275F65FFF7ED
-:1021900003FD686C00F0D8FB04F5825B0BF1100BBB
-:1021A000202200216846FFF77BFC02A8FFF732FEE1
-:1021B00006976A460BEB06030DF1180E9446BCE831
-:1021C0000300F44518605960624603F10803F5D135
-:1021D000DCF80000186020369CF804201A71B6F56F
-:1021E000806FDDD1002304F5A25285F8503485F8C4
-:1021F00053341A3251462046FFF7D0FE074690B9B5
-:10220000E26A936923F00103936100F015FD05462E
-:10221000E36A9B69D9077FF554AF00F00DFD431BBE
-:10222000FA2BF5D94DE795F85F6495F85E24C5F86B
-:102230006CA4360246EA426695F86024E36A1643C7
-:10224000B5F85C2446EA0246DE61B8F1000F29D0F9
-:1022500004F5A352023241462046FFF79FFE90B993
-:10226000E26A936923F00103936100F0E5FC0546FF
-:10227000E36A9B69DA077FF524AF00F0DDFC431BBE
-:10228000FA2BF5D91DE795F8683495F86714C5F869
-:1022900070841B0143EA0123B5F86414E26A43EA3F
-:1022A0000143D3602046FFF7E3FE002385F859344D
-:1022B000E36A6FF040421A65E36A184A5A65E36AB6
-:1022C00044229A65E36A0722C3F8DC20E36A03220A
-:1022D000DA65E26A9369B9F1030F43F440739361DD
-:1022E0003FF4F0AEE26A936923F00103936100F0DA
-:1022F000A3FC0646E36A9B69DB0705D500F09CFC5E
-:10230000831BFA2BF6D9DCE6012385F85234D9E693
-:10231000D84A0020DC4A0020001002409B00080040
-:102320002DE9F04F054689B090469946002741F2C5
-:10233000680A00F58056EB6AD3F8D430FB40D80722
-:102340004AD505EB471252444FEA471B1379190748
-:1023500042D4D6F880340133C6F8803413799A0613
-:1023600048BFD6F8A83405EB0B0248BF01335244EE
-:1023700048BFC6F8A834137943F008031371DB078C
-:1023800022D596F85334FBB105F5825418346846CB
-:102390005C44FFF745FD03AB04F1080C206861685D
-:1023A0001A4603C2083464451346F7D1206810600A
-:1023B000A2889A800123ADF808302B68CDE9008906
-:1023C0001B6C694628469847D6F8543423B1D6F892
-:1023D0009C340133C6F89C340137202FABD109B0AF
-:1023E000BDE8F08F2DE9F04F8DB004460F4600F0A8
-:1023F00025FC82468946002F56D1E36AD3F8902007
-:10240000920141BF04F58051D1F894240132C1F802
-:102410009424D3F89020160703D100200DB0BDE816
-:10242000F08FD3F89050E669C5F30125482303FBEC
-:102430000566E8464046FFF7EDFC326851004ABFAA
-:1024400022F06043C2F38A4343F00043920048BF46
-:1024500043F080430093736813F400131FBF04F527
-:10246000805201238DF80D30D2F8AC340EBF8DF8B8
-:102470000D300133C2F8AC34F38803F00F038DF84C
-:102480000C304FF0000B9DF80C0000F037FA5FFAAB
-:102490008BF3984220D9F2180CA90B44127A03F856
-:1024A0002C2C0BF1010BEEE7012FB6D1E36AD3F828
-:1024B0009820950141BF04F58051D1F89424013250
-:1024C000C1F89424D3F898201007A6D0D3F89850D8
-:1024D000266AC5F30125A9E7EFB9E36AC3F894506A
-:1024E00004A8FFF79DFC98E80F0007AD07C52B80F7
-:1024F0000023ADF8183023682046CDE904A91B6CF1
-:1025000004A9984704F5805458B1D4F88C340133A9
-:10251000C4F88C3482E7012F04BFE36AC3F89C50EF
-:10252000DEE7D4F890340133C4F89034012075E725
-:10253000F8B505460F4600F5805401263946284671
-:10254000FFF750FF10B184F85364F7E7D4F8543420
-:1025500023B1D4F89C340133C4F89C34F8BD000096
-:10256000F0B5C36A1A6C12F47F0F2BD000F58054BB
-:102570001B6CC4F8A03441F26805002347194FF0E2
-:10258000010C00EB43122A445E01117911F0020F95
-:1025900015D0490713D4B959C66AD6F8C8E00CFA61
-:1025A00001F111EA0E0F0AD0C6F8D010117941F0EE
-:1025B00004011171D4F888240132C4F8882401334D
-:1025C000202BDED1F0BD000010B5254C254B226834
-:1025D00002B338B31A6D12060ED580221A6500F0C8
-:1025E0002DFB50EA01020B4602D0013861F10003D5
-:1025F00002462068FFF794FE1A4A136D1B032AD582
-:1026000023684FF4002103F580531165012283F8FC
-:10261000592420E001221A6508221A654FF48062CD
-:102620001A6510BD196DC80702D4196D890705D543
-:102630000321196510460021FFF77AFF094B1A6D37
-:10264000100702D41A6DD10605D518221A65206824
-:102650000121FFF76DFF2068BDE81040FFF780BF44
-:10266000D84A00200064004008B5FFF78FFAFFF752
-:1026700077FFBDE80840FFF78FBA0000C36AD3F8C0
-:10268000C40080F40010C0F34050704700F5805043
-:1026900008B5FFF77BFA406C00F068F9FFF77CFAA9
-:1026A00043090CBF0120002008BD000000F5805345
-:1026B00093F8592462B1C16A8A6922F001028A61E1
-:1026C000D3F898240132C3F89824002283F85924BF
-:1026D000704700002DE9F74300F58251984610310C
-:1026E000FFF754FA002541F2680E4FF0010900F59A
-:1026F000805C00EB4514744423795E071CD4DB0630
-:102700001AD5C36A8E69D3F8C87009FA06F63E4234
-:1027100012D04F6801970F689742019F77EB080727
-:102720000AD2C3F8D060237943F004032371DCF8A4
-:1027300084340133CCF884340135202D01F120019B
-:10274000D7D103B0BDE8F043FFF726BAF8B51E466F
-:10275000002313700F4605461446FFF797FF80F0DD
-:10276000010038701EB12846FFF788FF2070F8BDC1
-:102770002DE9F04F85B099460B7801930E461378FA
-:102780000293DDE90EBA8046174600F057FA337817
-:1027900004460D4613B93B78002B41D022462B4608
-:1027A0004046FFF797FFFFF75FFFFFF77FFF4B46BE
-:1027B0003A463146FFF7CAFF33782BB1019B1BB174
-:1027C000012005B0BDE8F08F3B7813B1029B002BD0
-:1027D000F6D108F5805303935C4575EB0A031FD2CD
-:1027E000039BD3F85404D8B10368BBEB0402D96847
-:1027F0006AEB050388474B463A4631464046FFF7A9
-:10280000A5FF337813B1019B002BD9D13B7813B1CD
-:10281000029B002BD4D100F011FA04460D46DBE7F1
-:102820000020CEE708B50020FFF7CEFEBDE8084047
-:1028300001F058B908B50120FFF7C6FEBDE8084011
-:1028400001F050B90FB4002004B0704713B56C46C6
-:1028500084E80600031D94E8030083E805000120D6
-:1028600002B010BD73B58568019155B11B885B0737
-:1028700007D4D0E90036DB6B9847019AC1B23046E5
-:10288000A847012002B070BDF0B5866889B0054642
-:102890000C465EB1BDF838305B070AD4D0E900378A
-:1028A000DB6B98472246C1B23846B047012009B0D9
-:1028B000F0BD00220023CDE900230023ADF808304D
-:1028C0000A4603AB01F10806106851681C4603C4B0
-:1028D0000832B2422346F7D1106820609288A28065
-:1028E00000F0AEF90423ADF808302B68CDE9000103
-:1028F0001B6C694628469847D8E70000082817D976
-:1029000009280CD00A280CD00B280CD00C280CD08D
-:102910000D280CD00E2814BF4020302070470C200A
-:1029200070471020704714207047182070472020EF
-:102930007047000010B5037C044613B9006802F02C
-:10294000EFFA204610BD00000023BFF35B8FC36089
-:10295000BFF35B8FBFF35B8F8360BFF35B8F704709
-:10296000BFF35B8F0068BFF35B8F704770B50546A0
-:102970000C30FFF7F5FF05F1080604463046FFF777
-:10298000EFFFA04206D930466D68FFF7E9FF254406
-:10299000281A70BD3046FFF7E3FF201AF9E7000060
-:1029A00070B50546406898B105F10800FFF7D8FFFB
-:1029B00005F10C0604463046FFF7D2FF844230464C
-:1029C00094BF6D680025FFF7CBFF013C2C44201A13
-:1029D00070BD000038B50C460546FFF7C7FFA042A2
-:1029E00010D305F10800FFF7BBFF04446868B4FB8F
-:1029F000F0F100FB1144BFF35B8F0120AC60BFF32B
-:102A00005B8F38BD0020FCE72DE9F04114460746F6
-:102A10000D46FFF7C5FF844228BF0446D4B1B8462F
-:102A200058F80C6B4046FFF79BFF30442860404647
-:102A30007E68FFF795FF331A9C4203D86C60012033
-:102A4000BDE8F0816B60A41B3B68AB602044E8608C
-:102A50000220F5E72046F3E738B50C460546FFF7B8
-:102A60009FFFA04210D305F10C00FFF779FF04444B
-:102A70006868B4FBF0F100FB1144BFF35B8F0120E9
-:102A8000EC60BFF35B8F38BD0020FCE72DE9FF4110
-:102A9000884669460746FFF7B7FF6C4606B204EB67
-:102AA000C6060025B44209D06268206808EB05011B
-:102AB000FEF7E4FF636808341D44F3E7294638460F
-:102AC000FFF7CAFF284604B0BDE8F081F8B5054617
-:102AD0000C300F46FFF744FF05F108060446304668
-:102AE000FFF73EFFA042304688BF6C68FFF738FF13
-:102AF000201A386020B130462C68FFF731FF20449F
-:102B0000F8BD000073B5144606460D46FFF72EFFCC
-:102B1000844228BF04460190DCB101A93046FFF78A
-:102B2000D5FF019B33B93268C5E90233C5E90024FA
-:102B300001200CE09C4238BF019428600198686035
-:102B40008442F5D93368AB60241AEC60022002B0ED
-:102B500070BD2046FBE700002DE9FF410F466946A6
-:102B6000FFF7D0FF6C4600B204EBC0050026AC4274
-:102B700009D0D4F8048054F8081BB8194246FEF76F
-:102B80007DFF4644F3E7304604B0BDE8F081000025
-:102B900038B50546FFF7E0FF044601462846FFF733
-:102BA00019FF204638BD000000B59BB0EFF3098146
-:102BB00068226846FEF762FFEFF30583044B9A6BC9
-:102BC000DA6A9A6A9A6A9A6A9A6A9A6A9B6AFEE7C3
-:102BD00000ED00E000B59BB0EFF309816822684684
-:102BE000FEF74CFFEFF30583044B9A6B9A6A9A6ADF
-:102BF0009A6A9A6A9A6A9B6AFEE700BF00ED00E053
-:102C000000B59BB0EFF3098168226846FEF736FFF6
-:102C1000EFF30583034B5A6B9A6A9A6A9A6A9A6A27
-:102C20009B6AFEE700ED00E0FEE700000FB408B588
-:102C3000029801F041FBFEE701F0E6BD01F0BEBDE8
-:102C400001F0BCBD30B5094D0A4491420DD011F8D8
-:102C5000013B5840082340F30004013B2C4013F093
-:102C6000FF0384EA5000F6D1EFE730BD2083B8EDD2
-:102C70002DE9F041C56915B9C161BDE8F0814B6826
-:102C800023F06047C3F38A464FEAD37EC3F38078CC
-:102C900016EA230638BF3E46AC462B465A68BEEBC2
-:102CA000D27F22F060440AD0002A18DAA40CB44281
-:102CB00017D19D420FD10D60DEE71346EEE7A74224
-:102CC00007D102F08044C2F3807242450BD054B168
-:102CD000EFE708D2EDE7CCF800100B60CDE7B44287
-:102CE00001D0B442E5D81A689C46002AE5D11960A3
-:102CF000C3E700002DE9F047089D01F007044FEA03
-:102D0000D508224405F0070500EBD1004FF47F49B8
-:102D1000944201D1BDE8F08704F0070705F0070AE7
-:102D200057453E4638BF5646C6F10806111B8E422F
-:102D300028BF0E46E10808EBD50E415C13F80EC023
-:102D4000B94029FA06F721FA0AF1FFB28CEA01012B
-:102D500047FA0AF739408CEA010C03F80EC03444F4
-:102D60003544D5E780EA0120082341F2210201B26F
-:102D70004000002980B203F1FF33B8BF504013F088
-:102D8000FF03F4D17047000038B50C468D18A542FA
-:102D900000D138BD14F8011BFFF7E4FFF7E700008E
-:102DA00002684AB113680360C388018901339BB28A
-:102DB0009942C38038BF03811046704770B588B010
-:102DC000202204460D4668460021FEF769FE204693
-:102DD0000495FFF7E5FF024658B16B46054608AE7D
-:102DE0001C4603CCB44228606960234605F10805FF
-:102DF000F6D1104608B070BD082817D909280CD0A4
-:102E00000A280CD00B280CD00C280CD00D280CD084
-:102E10000E2814BF4020302070470C20704710202F
-:102E2000704714207047182070472020704700001A
-:102E3000082817D90C280CD910280CD914280CD91B
-:102E400018280CD920280CD930288CBF0F200E2030
-:102E50007047092070470A2070470B2070470C20EC
-:102E600070470D207047000010B54B6823B9CA8A1F
-:102E700063F30902CA8210BDC4681A681C60C3608B
-:102E8000438A013B43824A60EFE700002DE9F84F97
-:102E90001D46CB8A0F46C3F3090106298146924697
-:102EA0000B4630D00020AAB207F119049EB2052EBD
-:102EB0001FFA80F80FD8904503F1010306D3FB8A6F
-:102EC0000A4462F30903FB8201201AE01AF8006049
-:102ED000E6540130EAE79045F1D2A1F1060B1C233C
-:102EE0007C68BBFBF3F203FB12BB1FFA8BF6002CD2
-:102EF00045D14846FFF754FF044638B978606FF073
-:102F00000200BDE8F88F4FF00008E6E700260660F3
-:102F10007860ADB24FF0000B454510D90AEB0803BD
-:102F2000221D13F8011B9155B1B208F101081B29AC
-:102F30001FFA88F82BD0454506F10106F1D8FB8A27
-:102F4000C3F30902154465F30903BCE7013292B2E9
-:102F50001C462368002BF9D1AB1F0B441C21B3FB8B
-:102F6000F1F301339BB29A42D3D2BBF1000FD0D11F
-:102F70004846FFF715FF20B9C4F800B0BFE70122AB
-:102F8000E7E7C0F800B05E4620600446C1E745456B
-:102F9000D5D94846FFF704FF08B92060AFE7C0F86D
-:102FA00000B0002620600446B6E700002DE9F04F8F
-:102FB0002DED028B83B0CDE90013BDF83C500746E0
-:102FC0009146002A00F092802DB10E9B002B00F05C
-:102FD0008D80072D32D807F10C00FFF7E1FE044683
-:102FE00038B96FF00204204603B0BDEC028BBDE897
-:102FF000F08F14220021FEF753FD0E992A4604F1AA
-:103000000800FEF73BFD681CC0B2FFF711FFFFF799
-:10301000F3FE207499F80030013814FA80F003F0C0
-:103020001F0363F03F030372009B43F000416160A4
-:1030300038462146FFF71CFE0124D4E700F10C03BB
-:103040004FF0000808EE103A4FF0800A464644461A
-:1030500018EE100AFFF7A4FE83460028C1D0142200
-:103060000021FEF71DFDC6BB019BABF80830022016
-:103070000E9B00F1080299195BFA82F20130C0B28E
-:10308000082801D0AE422AD3FFF7D2FEFFF7B4FEE4
-:1030900099F80020009B411E02F01F0242EA4812EC
-:1030A000AE4208BF4FF0400A5BFA81F14AEA020AD9
-:1030B00043F0004281F808A08BF81000CBF8042000
-:1030C00059463846FFF7D4FD0134AE4224B288F0A9
-:1030D00001084FF0000ABBD185E70020C8E711F8CE
-:1030E00001CB02F801CB0136B6B2C7E76FF001049D
-:1030F00079E70000F8B515460E462822002104465F
-:103100001F46FEF7CDFC069B6360B5F5001F079BCD
-:10311000A76034BF6A094FF6FF72236204F10C0006
-:1031200097B200239A4205D8002303602782638266
-:10313000A382F8BD0660013330462036F2E7000076
-:1031400003781BB94BB2002BC8BF01707047000059
-:10315000007870472DE9F74FDDF83C90BDF830500E
-:103160000D9E9DF83840BDF84070804692469B46C3
-:10317000B9F1000F01D1002F51D11F2C4FD898F871
-:103180000000B0B9072F47D835F0030347D13A46BE
-:1031900049464FF6FF70FFF7F7FD20F001002D02C2
-:1031A000400445EA0464400C44EA40244FF6FF73AF
-:1031B00021E040EA0520072F40EA0464F6D9002503
-:1031C0004FF6FF73C5F12000A5F120022AFA05F1A0
-:1031D0000BFA00F001432BFA02F211431846C9B270
-:1031E000FFF7C0FD0835402D0346EBD13A4649466E
-:1031F000FFF7CAFD0346CDE9009732462146404617
-:10320000FFF7D4FE33780133DBB21F2B88BF0023D6
-:10321000337003B0BDE8F08F6FF00300F9E76FF093
-:103220000100F6E72DE9F04F85B09246DDF84880C1
-:103230000F9D9DF840209DF84490BDF84C700646C7
-:103240009B46B8F1000F01D1002F48D11F2A46D864
-:103250003378002B46D00C0244EA02649DF8381003
-:1032600044EAC93444EA01441C43072F44F0800473
-:1032700032D900234FF6FF72C3F1200CA3F12000D6
-:103280002AFA03F10BFA0CFC41EA0C012BFA00F0CC
-:103290000143C9B210460393FFF764FD039B083353
-:1032A000402B0246E8D13A464146FFF76DFD034602
-:1032B000CDE900872A4621463046FFF777FEB9F16F
-:1032C000010F06D12B780133DBB21F2B88BF0023FF
-:1032D0002B7005B0BDE8F08F4FF6FF73E8E76FF095
-:1032E0000100F6E76FF00300F3E70000C06900B1EA
-:1032F00004307047C3691A68C261C2681A60C3604B
-:10330000438A013B438270472DE9F041D0F8188091
-:10331000194E14461D464146002709B9BDE8F08103
-:10332000D1E90223A21A65EB0303964277EB03036C
-:103330001ED283698B420DD1FFF796FD83691B680E
-:103340008361C3680B60438AC1608169013B43822A
-:103350008846E2E7FFF788FD0B68C8F80030C368CD
-:103360000B60438AC160013B4382D8F80010D4E768
-:1033700088460968D1E700BF80841E002DE9F04F20
-:103380008BB00D46DDF8509014469B4680460028D1
-:1033900000F01981B9F1000F00F01581531E3F2B89
-:1033A00000F21181012A03D1BBF1000F40F00B8123
-:1033B0000023CDE90833B8F81430B5EBC30F4FEA5A
-:1033C000C30703D300200BB0BDE8F08F2B199F4239
-:1033D000D8F80C303ABF7F1BFFB227461BB9D8F88C
-:1033E0001030002B7AD02F2D4ED8C5F13006B742C1
-:1033F0004FF000032CBFF6B23E4600932946D8F8A2
-:10340000080008AB3246FFF775FCA7EB060A354407
-:103410005FFA8AFAB8F8143003F10053063BDB0078
-:103420000493D8F80C3003933021039B13B1BAF105
-:10343000000F2CD1D8F8100040B1BAF1000F05D020
-:10344000009608AB5246691AFFF754FC38B2002FB9
-:10345000B8D066070AD00AAB03EBD401624211F878
-:10346000083C02F00702134101F8083C082C3CD943
-:10347000102C40F2B580202C40F2B780BBF1000F39
-:1034800000F09C80082334E0BA460026C2E7049B83
-:10349000E02B28BFE02306930B44AB42059314D9DD
-:1034A0005A1B03980096924534BF5246D2B2691A0D
-:1034B00008AB04300792FFF71DFC079A1644AAEBED
-:1034C000020A1544F6B25FFA8AFA049B069A059935
-:1034D0009B1A0493039B1B680393A6E70093D8F8F9
-:1034E000080008AB3A462946AEE7BBF1000F13D0FF
-:1034F0000123B4EBC30F6CD0082C12D89DF82030F8
-:10350000621E23FA02F2D50706D54FF0FF3202FA07
-:1035100004F423438DF820309DF8203089F80030E2
-:1035200051E7102C12D8BDF82030621E23FA02F2A7
-:10353000D10706D54FF0FF3202FA04F42343ADF869
-:103540002030BDF82030A9F800303CE7202C0FD8FF
-:103550000899631E21FA03F3DA0705D54FF0FF320D
-:1035600002FA04F40C430894089BC9F800302AE7D7
-:10357000402C2BD0DDE90865611EC4F12102A4F1C5
-:10358000210326FA01F105FA02F225FA03F31143A9
-:103590001943CB0712D50122A4F12003C4F1200165
-:1035A00002FA03F322FA01F1A240524243EA010374
-:1035B00063EB430332432B43CDE90823DDE90823C2
-:1035C000C9E90023FFE66FF00100FCE66FF0080098
-:1035D000F9E6082CA0D9102CB3D9202CEED8C3E7DB
-:1035E000BBF1000FADD0022383E7BBF1000FBBD0CE
-:1035F00004237EE730B5012A144638BF0124402C4D
-:1036000085B028BF40240025012ACDE9025518D8ED
-:103610001B788DF8083063070AD004AB03EBD405A0
-:10362000624215F8083C02F00702934005F8083C96
-:10363000009103462246002102A8FFF75BFB05B07C
-:1036400030BD082AE4D9102A03D81B88ADF8083009
-:10365000E1E7202A8DBFD3E900231B680293CDE95F
-:103660000223D8E710B5CB681BB98B600B618B8246
-:1036700010BDC4681A681C60C360438A013B438262
-:10368000CA60F0E72DE9F04FD1F8008093B018F050
-:10369000800FCDE90323C8F3C01219BFC8F3C03BA4
-:1036A000C8F306264FF0020B1646B8F1000F044689
-:1036B0000D4680F2D18118F0C043059340F0CC81D3
-:1036C0000B7B002B00F0C881BBF1020F03D0017807
-:1036D000B14240F0C48108F07F0106916AB3C8F39B
-:1036E000074A2B44069A93F80390760646EA0B465F
-:1036F00046EA82465FEAD91346EA0A06079300F0D3
-:10370000908000220023CDE90A23069B009367687E
-:103710005B4652460AA92046B84700287ED0A769D2
-:103720009FB9314604F10C00FFF748FB0746E0B9AA
-:103730006FF0020013B0BDE8F08FC8F30F2A18F045
-:103740007F0F08BF0AF0030ACBE73B699E420DD00A
-:103750003F68002FF9D1314604F10C00FFF72EFB32
-:1037600007460028E4D0A3693B60A761DDE90A238E
-:1037700000264FF6FF70C6F1200E22FA06F103FA7A
-:103780000EFEA6F1200C23FA0CFC41EA0E0141EAE0
-:103790000C01C9B2083609920893FFF7E3FA402EEC
-:1037A000DDE90832E7D1B882FB7D09F01F06C3F3DB
-:1037B00084039B1BD7E9022198B2002BBCBF00F108
-:1037C00020031BB252EA0100C8F304680FD003982B
-:1037D000821A049860EB0101A74890424FF0000262
-:1037E0008A4104D3079A002A5BD0012B23DDFA7D9E
-:1037F0004FEA890302F0030203F07C031343FB75D5
-:1038000039462046FFF730FB079BA3B9FB7DC3F386
-:103810008402013262F38603FB7504E06FF00B0053
-:1038200088E7A76917B96FF00C0083E73B699E42F0
-:10383000BAD03F68F6E719F0400F32D0039BBB6067
-:10384000049BFB60142200210DA8FEF729F9039BBD
-:103850000A93049B0B932B1D0C932B7BADF83EA07E
-:10386000013BDBB2ADF83C30069B8DF8433094F859
-:1038700024308DF840B083F001038DF844308DF88A
-:103880004160A3688DF842800AA920469847FB7DD5
-:10389000C3F38403013303F01F039B02FB82002068
-:1038A00048E7FB7DC9F34012B2EBD31F40F0DA804A
-:1038B000C3F38403B34240F0D88007992B7B4FEACF
-:1038C0009912002934D0D20741D4032B40F2D08082
-:1038D000039BBB60049BFB602B7BAE1D033BDBB2F9
-:1038E0003246394604F10C00FFF7D0FA00280DDA11
-:1038F00020463946FFF7B8FAFB7DC3F38403013352
-:1039000003F01F039B02FB82032013E7AB883B837A
-:103910002A7B033AB88AD2B23146FFF735FAFB7DEB
-:10392000B882DA43C2F3C01262F3C713FB75B6E77D
-:103930006AB92E1D013BDBB23246394604F10C0058
-:10394000FFF7A4FA0028D3DB2A7B013AE2E7F98AE1
-:10395000C1F30901013B0529DAB259D8281D00231A
-:1039600007F11A0C9A4208D910F801EB0CF801E0A3
-:10397000013101330629DBB2F4D103990A9104998C
-:103980000B91934207F11A010C9138BF0433796807
-:103990000D9134BF55FA83F300230E93FB8AADF8E3
-:1039A0003EA0C3F309031A44069B8DF8433094F8F4
-:1039B0002430ADF83C2083F001038DF8443000231F
-:1039C0008DF840B08DF841608DF842807B602A7B95
-:1039D000B88A013A291DFFF7D7F93B8BB882834299
-:1039E00003D1A3680AA92046984720460AA9FFF7F1
-:1039F00039FEFB7DB88AC3F38403013303F01F0350
-:103A00009B02FB823B8B984214BF1120002091E661
-:103A10007B68002BB1D0062001E01C306346D3F850
-:103A200000C0BCF1000FF8D1091A081D05F1040C03
-:103A300000EB030905989DF8143001EB000EBEF170
-:103A40001B0F9AD89A4298D91CF8013B09F8013B00
-:103A5000059B01330593EDE76FF009006AE66FF00F
-:103A60000A0067E66FF00D0064E66FF00E0061E695
-:103A70006FF00F005EE600BF80841E00EFF3098345
-:103A800005494A6B22F001024A63683383F30988CF
-:103A9000002383F31188704700EF00E0202080F3BB
-:103AA000118862B60C4B0D4AD96821F4E061090413
-:103AB000090C0A43DA60D3F8FC20094942F080720D
-:103AC000C3F8FC200A6842F001020A601022DA778B
-:103AD00083F82200704700BF00ED00E00003FA0504
-:103AE000001000E010B5202383F311880E4B5B68B3
-:103AF00013F4006314D0F1EE103AEFF30984683C3C
-:103B00004FF08073E361094BDB6B236684F3098814
-:103B100000F084FB10B1064BA36110BD054BFBE721
-:103B200083F31188F9E700BF00ED00E000EF00E04B
-:103B30004B0600084E060008026843681143016006
-:103B400003B1184770470000024A136843F0C003EE
-:103B5000136070470038014013B50E4C204600F04A
-:103B60009FFA04F114000C49009400234FF4807272
-:103B700000F060F9094B0A4900944FF4807204F197
-:103B8000380000F0D9F9074A074BC4E9172302B0FF
-:103B900010BD00BFE44A0020504B0020493B000804
-:103BA000504C002000380140007A030A30B5037CF5
-:103BB000234C002918BF0C46012B0FD1214B9842F2
-:103BC0000CD1214B1A6E42F480421A66D3F8802041
-:103BD00042F48042C3F88020D3F880302268036E1C
-:103BE000C16D846603EB5203B3FBF2F36268150404
-:103BF00042BF23F0070503F0070343EA4503CB6008
-:103C0000A36843F040034B60E36843F001038B601B
-:103C100042F4967343F001030B604FF0FF330B62E5
-:103C2000510505D512F0102205D0B2F1805F04D005
-:103C300080F8643030BD7F23FAE73F23F8E700BF08
-:103C400080510008E44A0020001002402DE9F047AE
-:103C5000C66D3768F46934622107054618D014F040
-:103C6000080118BF8021E20748BF41F02001A307E7
-:103C700048BF41F04001600748BF41F480712023F4
-:103C800083F31188281DFFF757FF002383F3118862
-:103C9000E2050AD5202383F311884FF40071281D13
-:103CA000FFF74AFF002383F311884FF020094FF0FC
-:103CB000000A14F0200838D13B0616D54FF0200931
-:103CC00005F1380A200610D589F31188504600F016
-:103CD00067F9002836DA0821281DFFF72DFF27F0A5
-:103CE00080033360002383F31188790614D56206BC
-:103CF00012D5202383F31188D5E913239A4208D1E2
-:103D00002B6C33B11021281D27F04007FFF714FF5B
-:103D10003760002383F31188E30618D5AA6E136970
-:103D2000ABB1BDE8F0475069184789F31188736A51
-:103D300095F864102846194000F0CCF98AF31188F0
-:103D4000F469B6E7B06288F31188F469BAE7BDE8B0
-:103D5000F087000000F1604303F561430901C9B237
-:103D600083F80013012200F01F039A4043099B00CF
-:103D700003F1604303F56143C3F880211A60704783
-:103D8000F8B5154682680669AA420B46816938BFB4
-:103D90008568761AB54204460BD218462A46FDF7C6
-:103DA0006DFEA3692B44A361A3685B1BA360284637
-:103DB000F8BD0CD918463246FDF760FEAF1BE1682E
-:103DC0003A463044FDF75AFEE3683B44EBE71846B9
-:103DD0002A46FDF753FEE368E5E700008368934257
-:103DE000F7B51546044638BF8568D0E90460361A31
-:103DF000B5420BD22A46FDF741FE63692B4463614D
-:103E0000A36828465B1BA36003B0F0BD0DD9324602
-:103E10000191FDF733FE0199E068AF1B3A4631444A
-:103E2000FDF72CFEE3683B44E9E72A46FDF726FE52
-:103E3000E368E4E710B50A440024C361029B846090
-:103E4000C0E90000C0E90511C1600261036210BD54
-:103E500008B5D0E90532934201D1826882B98268FF
-:103E6000013282605A1C42611970D0E904329A42D0
-:103E700024BFC3684361002100F0A0FA002008BD00
-:103E80004FF0FF30FBE7000070B5202304460E46DC
-:103E900083F31188A568A5B1A368A269013BA3605B
-:103EA000531CA36115782269934224BFE368A36180
-:103EB000E3690BB120469847002383F31188284615
-:103EC00007E03146204600F069FA0028E2DA85F37F
-:103ED000118870BD2DE9F74F04460E4617469846E7
-:103EE000D0F81C904FF0200A8AF311884FF0000B95
-:103EF000154665B12A4631462046FFF741FF034685
-:103F000060B94146204600F049FA0028F1D000236C
-:103F100083F31188781B03B0BDE8F08FB9F1000F6F
-:103F200003D001902046C847019B8BF31188ED1AFE
-:103F30001E448AF31188DCE7C0E90511C160C36142
-:103F40001144009B8260C0E9000001610362704778
-:103F5000F8B504460D461646202383F31188A7685A
-:103F6000A7B1A368013BA36063695A1C62611D701D
-:103F7000D4E904329A4224BFE3686361E3690BB178
-:103F800020469847002080F3118807E031462046FC
-:103F900000F004FA0028E2DA87F31188F8BD000087
-:103FA000D0E905239A4210B501D182687AB98268B6
-:103FB000013282605A1C82611C7803699A4224BFD4
-:103FC000C3688361002100F0F9F9204610BD4FF06D
-:103FD000FF30FBE72DE9F74F04460E46174698469B
-:103FE000D0F81C904FF0200A8AF311884FF0000B94
-:103FF000154665B12A4631462046FFF7EFFE0346D7
-:1040000060B94146204600F0C9F90028F1D00023EC
-:1040100083F31188781B03B0BDE8F08FB9F1000F6E
-:1040200003D001902046C847019B8BF31188ED1AFD
-:104030001E448AF31188DCE702684368114301607B
-:1040400003B11847704700001430FFF743BF00006A
-:104050004FF0FF331430FFF73DBF00003830FFF75B
-:10406000B9BF00004FF0FF333830FFF7B3BF000097
-:104070001430FFF709BF00004FF0FF311430FFF795
-:1040800003BF00003830FFF763BF00004FF0FF327E
-:104090003830FFF75DBF000000207047FFF75CBDC0
-:1040A000044B03600023C0E902334360012303741F
-:1040B000704700BF9851000810B52023044683F3D1
-:1040C0001188FFF773FD02232374002383F3118803
-:1040D00010BD000038B5C36904460D461BB9042164
-:1040E0000844FFF7A9FF294604F11400FFF7B0FECA
-:1040F000002806DA201D4FF48061BDE83840FFF744
-:104100009BBF38BD024B0022C3E900339A60704761
-:10411000504D0020002303748268054B1B6899688A
-:104120009142FBD25A680360426010605860704749
-:10413000504D002008B5202383F31188037C032B06
-:1041400005D0042B0DD02BB983F3118808BD43692A
-:1041500000221A604FF0FF334361FFF7DBFF0023BB
-:10416000F2E7D0E9003213605A60F3E700230374EA
-:104170008268054B1B6899689142FBD85A680360B6
-:104180004260106058607047504D0020054B19691F
-:104190000874186802681A60536018610123037478
-:1041A000FCF73EBA504D002030B54B1C0B4D87B08C
-:1041B000044610D02B690A4A01A800F019F92046DC
-:1041C000FFF7E4FF049B13B101A800F04DF92B6940
-:1041D000586907B030BDFFF7D9FFF8E7504D002010
-:1041E0003541000838B50C4D41612B6981689A68EA
-:1041F0009142044603D8BDE83840FFF78BBF18460C
-:10420000FFF7B4FF01232C61014623742046BDE86B
-:104210003840FCF705BA00BF504D0020044B1A6827
-:104220001B6990689B68984294BF002001207047EA
-:10423000504D002010B5084C236820691A68226090
-:104240005460012223611A74FFF790FF0146206930
-:10425000BDE81040FCF7E4B9504D002008B5FFF769
-:10426000DDFF18B1BDE80840FFF7E4BF08BD00005E
-:10427000FFF7E0BFFEE7000010B50C4CFFF742FF70
-:1042800000F0A8F80A498022204600F03DF80123FA
-:1042900044F8180C0374FFF701FC002383F3118822
-:1042A00062B60448BDE8104000F04EB8784D0020DA
-:1042B000C0510008D051000808B572B6034B5862CF
-:1042C00000F06CFA00F020FBFEE700BF504D00202C
-:1042D00000F004B9EFF3118020B9EFF30583202239
-:1042E00082F311887047000010B530B9EFF30584F0
-:1042F000C4F3080414B180F3118810BDFFF7AEFFBA
-:1043000084F31188F9E7000082600222028270477C
-:104310008368A3F17C0243F80C2C026943F83C2C1F
-:10432000426943F8382C074A43F81C2CC26843F80A
-:10433000102C022203F8082C002203F8072CA3F10A
-:10434000180070473906000810B5202383F3118840
-:10435000FFF7DEFF00210446FFF744FF002383F34D
-:104360001188204610BD0000024B1B6958610F20C8
-:10437000FFF70CBF504D0020202383F31188FFF777
-:10438000F3BF000008B50146202383F311880820FD
-:10439000FFF70AFF002383F3118808BD49B1064BDC
-:1043A00042681B6918605A60136043600420FFF77D
-:1043B000FBBE4FF0FF307047504D0020036898421D
-:1043C00006D01A680260506059611846FFF7A2BE15
-:1043D00070470000054B03F11402C3E905224FF0BA
-:1043E000FF310022C3E90712704700BF504D002083
-:1043F00070B51C4EC0E9032305460C4600F0FEFADA
-:10440000334653F8142F9A420DD13062C5E9012486
-:104410002A600A2C2CBF00190A30C6E90555BDE8F0
-:10442000704000F0D9BA316A431AE31838BF1C460D
-:104430009368A34202D9081900F0DCFA73699A68FC
-:1044400094420CD85A68AC602B606A6015609A6818
-:104450005D60121B9A604FF0FF33F36170BD1B6803
-:10446000A41AECE7504D002038B51B4C6369984204
-:104470000DD0D0E9003213605A6000228168C2601A
-:104480009A680A449A604FF0FF33E36138BD2246D0
-:10449000036842F8143F002193425A60C16003D17F
-:1044A000BDE8384000F0A0BA9A688168256A0A44DD
-:1044B0009A6000F0A3FA63699A68411B8A42E5D9C1
-:1044C000AB181D1A092D206A98BF01F10A02BDE838
-:1044D0003840104400F08EBA504D00202DE9F041D4
-:1044E000184C002704F11406656900F087FA236A66
-:1044F000AA68C11A8A4215D813442362D5E900324A
-:1045000013605A606369D5F80C80EF60B34201D143
-:1045100000F06AFA87F311882869C047202383F3E3
-:104520001188E1E76169B14209D013441B1ABDE863
-:10453000F0410A2B2CBFC0180A3000F05BBABDE86E
-:10454000F08100BF504D002000207047FEE70000C2
-:10455000704700004FF0FF3070470000BFF34F8FEF
-:10456000024A1369DB03FCD4704700BF00200240FD
-:1045700008B5094B1B7873B9FFF7F0FF074B5A6971
-:10458000002ABFBF064A9A6002F188329A601A6810
-:1045900022F480621A6008BD184F002000200240FB
-:1045A0002301674508B50B4B1B7893B9FFF7D6FF7E
-:1045B000094B5A6942F000425A611A6842F480522B
-:1045C0001A601A6822F480521A601A6842F48062F3
-:1045D0001A6008BD184F0020002002407F289ABFB3
-:1045E00000F58030C0020020704700004FF40060EA
-:1045F00070470000802070477F2808B50BD8FFF770
-:10460000EDFF00F500630268013204D104308342FB
-:10461000F9D1012008BD0020FCE700007F2838B553
-:10462000044626D8FFF756FEFFF798FFFFF7A0FFD6
-:10463000114BF3221A6102225A615A6942EAC402FA
-:104640005A615A6942F480325A6105462046FFF7A2
-:1046500085FF4FF40061FFF7C1FF00F051F92846D4
-:10466000FFF7A0FFFFF740FE2046BDE83840FFF708
-:10467000C3BF002038BD00BF0020024040EA020353
-:1046800013F007032DE9F04705460C46164606D001
-:10469000324B40F2FB221A600020BDE8F0878118FF
-:1046A0002F4A91420CD92D4A4FF440711160F3E723
-:1046B0002B1D1B686268934208D1083E08350834F8
-:1046C000072E19D92A6823689A42F1D0FFF702FE13
-:1046D000FFF74EFFFFF742FF04F10801214C4FF0B6
-:1046E00001084FF00009012EA1F1080708D8FFF7D3
-:1046F00059FFFFF7F9FD01E0002EE7D10120CCE7DB
-:10470000C4F81480AA4651F8083C4AF8043B51F812
-:10471000043C6B60FFF722FFC4F814902A6851F83C
-:10472000083C9A420ED00D4B40F226321A600E4BD6
-:104730001D600E4B1E600E4B1F60FFF733FFFFF72F
-:10474000D3FDA9E7DAF800A051F8043C9A4501F13D
-:104750000801E8D1083E0835C5E700BF144F002026
-:104760000000040800200240084F0020104F0020E5
-:104770000C4F0020084908B50B7828B11BB9FFF78A
-:10478000F7FE01230B7008BD002BFCD0BDE80840EC
-:104790000870FFF707BF00BF184F002008B54FF49F
-:1047A000C0314FF0005000F0ADF8BDE808404FF4C4
-:1047B00080414FF0805000F0A5B8000070B582B085
-:1047C000FFF788FD0E4E054600F018F9326890425A
-:1047D00037BF0C4A0B49516814682EBFD1E900411C
-:1047E000013151600419034641F10001284601914D
-:1047F0003360FFF779FD0199204602B070BD00BF1C
-:104800001C4F0020204F002070B582B0FFF762FDE2
-:10481000104E054600F0F2F83268904237BF0E4A5B
-:104820000D49516814682EBFD1E900410131516032
-:10483000041941F100010346284601913360FFF756
-:1048400053FD01994FF47A7200232046FBF7D0FC08
-:1048500002B070BD1C4F0020204F00200244D2B295
-:10486000904200D17047431C800000F1804000F569
-:104870001450006841F8040BD8B2F1E7124B10B5A0
-:10488000D3F89040240409D4D3F89040C3F8904062
-:10489000D3F8904044F40044C3F890400B4C236894
-:1048A000024443F480732360D2B2904200D110BD21
-:1048B000431C800000F1804000F5145051F8044B77
-:1048C0000460D8B2F1E700BF001002400070004061
-:1048D00007B5012201A90020FFF7C0FF019803B02E
-:1048E0005DF804FB13B50446FFF7F2FFA04205D0C4
-:1048F000012201A900200194FFF7C0FF02B010BD02
-:10490000704700007047000070470000074B45F2F9
-:1049100055521A6002225A6040F6FF729A604CF6B5
-:10492000CC421A60024B01221A70704700300040DE
-:104930002C4F0020034B1B781BB1034B4AF6AA22D5
-:104940001A6070472C4F002000300040054B1A6859
-:1049500032B902F1804202F50432D2F894201A6092
-:10496000704700BF284F0020024B4FF40002C3F8ED
-:10497000942070470010024008B5FFF7E7FF024B94
-:104980001868C0F3407008BD284F00207047000031
-:10499000FEE700000A4B0B480B4A90420BD30B4B2F
-:1049A000DA1C121AC11E22F003028B4238BF002209
-:1049B0000021FDF775B853F8041B40F8041BECE721
-:1049C00044530008B84F0020B84F0020B84F0020D3
-:1049D0007047000000F078B84FF080430022586321
-:1049E0001A610222DA6070474FF080430022DA60D9
-:1049F000704700004FF08043586370474FF080438A
-:104A0000586A70474B6843608B688360CB68C360AB
-:104A10000B6943614B6903628B6943620B680360F6
-:104A20007047000008B5204BDA6A42F07F02DA6274
-:104A3000DA6A22F07F02DA62DA6ADA6C42F07F0226
-:104A4000DA64DA6E42F07F02DA66184ADB6E1146EB
-:104A50004FF09040FFF7D6FF02F11C0100F5806097
-:104A6000FFF7D0FF02F1380100F58060FFF7CAFFC1
-:104A700002F1540100F58060FFF7C4FF02F17001FC
-:104A800000F58060FFF7BEFF02F18C0100F5806049
-:104A9000FFF7B8FF02F1A80100F58060FFF7B2FF51
-:104AA000BDE8084000F064B800100240E85100087A
-:104AB00008B500F003FAFFF7DFFBBDE80840FFF799
-:104AC00045BF0000704700000F4B9A6D42F0010295
-:104AD0009A659A6F42F001029A670C4A9B6F93683D
-:104AE00043F0010393604FF08043A7229A624FF096
-:104AF000FF32DA6200229A615A63DA605A60012258
-:104B00005A611A60704700BF00100240002004E0A4
-:104B10004FF0804208B51169D3680B40D9B2C94340
-:104B20009B07116107D5202383F31188FFF7D0FB82
-:104B3000002383F3118808BD08B50B4BD3F89020F0
-:104B400012F4407F1FBF4FF48032C3F89020002240
-:104B5000C3F89020D3F89020C3F8902000F086F995
-:104B6000024B00225A6008BD001002400070004055
-:104B7000484B4FF0FF319A6A99629A6A00229A6212
-:104B8000986AD86A60F07F00D862D86A00F07F0027
-:104B9000D862D86A186B1963186B1A63186B986B14
-:104BA0009963986B9A63986BD86BD963D86BDA6307
-:104BB000D86B186C1964196C1A641A6C9A6D42F0EF
-:104BC00080529A659A6F22F080529A679A6F324AA1
-:104BD0004FF400711160516911F48061FBD14FF401
-:104BE0000040516090604FF48070D160C2F8800046
-:104BF000116251629162D162116351639163D16319
-:104C0000116451649164D16411655165D3F89820A1
-:104C100042F00102C3F89820D3F898209007FBD502
-:104C20001A6842F480321A601A689103FCD51A4956
-:104C30000A6842F480720A60184ADA601A6842F020
-:104C400080721A601A689201FCD5002214499A6099
-:104C5000C3F888101349C3F89C20134A0A600A68F5
-:104C600002F00F02042AFAD19A6842F003029A6015
-:104C70009A6802F00C020C2AFAD11A6E42F0010274
-:104C80001A66D3F8802042F00102C3F88020D3F8DE
-:104C9000803070470010024000700040032A61011C
-:104CA000550100500020024004070400074A08B5DF
-:104CB000536903F00103536123B1054A13680BB133
-:104CC00050689847BDE80840FEF70CBF000401405B
-:104CD000304F0020074A08B5536903F002035361BF
-:104CE00023B1054A93680BB1D0689847BDE80840E6
-:104CF000FEF7F8BE00040140304F0020074A08B517
-:104D0000536903F00403536123B1054A13690BB1DE
-:104D100050699847BDE80840FEF7E4BE0004014032
-:104D2000304F0020074A08B5536903F00803536168
-:104D300023B1054A93690BB1D0699847BDE8084093
-:104D4000FEF7D0BE00040140304F0020074A08B5EE
-:104D5000536903F01003536123B1054A136A0BB181
-:104D6000506A9847BDE80840FEF7BCBE0004014009
-:104D7000304F0020164B10B55C6904F478725A610C
-:104D8000A30604D5134A936A0BB1D06A984760060C
-:104D900004D5104A136B0BB1506B9847210604D50C
-:104DA0000C4A936B0BB1D06B9847E20504D5094AC6
-:104DB000136C0BB1506C9847A30504D5054A936C4E
-:104DC0000BB1D06C9847BDE81040FEF78BBE00BF1A
-:104DD00000040140304F0020194B10B55C6904F409
-:104DE0007C425A61620504D5164A136D0BB1506DB1
-:104DF0009847230504D5134A936D0BB1D06D98479E
-:104E0000E00404D50F4A136E0BB1506E9847A1040D
-:104E100004D50C4A936E0BB1D06E9847620404D54A
-:104E2000084A136F0BB1506F9847230404D5054A05
-:104E3000936F0BB1D06F9847BDE81040FEF752BE9C
-:104E400000040140304F002008B50348FEF7FEFE85
-:104E5000BDE80840FEF746BEE44A002008B5FFF76B
-:104E600057FEBDE80840FEF73DBE0000062108B52C
-:104E70000846FEF76FFF06210720FEF76BFF0621AD
-:104E80000820FEF767FF06210920FEF763FF0621D1
-:104E90000A20FEF75FFF06211720FEF75BFF0621C1
-:104EA0002820FEF757FF07211C20FEF753FFBDE81F
-:104EB00008400C212520FEF74DBF000008B5FFF784
-:104EC0003BFE00F009F8FFF7E9F8FFF7FBFDBDE84E
-:104ED0000840FFF77FBD00000023054A1946013353
-:104EE000102BC2E9001102F10802F8D1704700BF8F
-:104EF000304F00200B460146184600F003B8000072
-:104F000000F00EB810B5054C13462CB10A46014608
-:104F10000220AFF3008010BD2046FCE70000000037
-:104F2000024B0146186800F035B800BF2823002066
-:104F300010B501390244904201D1002005E0037808
-:104F400011F8014FA34201D0181B10BD0130F2E748
-:104F50002DE9F041A3B1C91A17780144044603F1C1
-:104F6000FF3C8C42204601D9002009E00578BD4273
-:104F700004F10104F5D10CEB0405D618A54201D1CA
-:104F8000BDE8F08115F8018D16F801EDF045F5D07A
-:104F9000E7E7000037B5002944D051F8043C019000
-:104FA000002BA1F10404B8BFE41800F047F81E4A32
-:104FB0000198136833B96360146003B0BDE83040F2
-:104FC00000F042B8A34208D9256861198B4201BF9D
-:104FD00019685B6849192160EDE71A465B680BB1F7
-:104FE000A342FAD911685518A5420BD1246821446F
-:104FF0005418A3421160E0D11C685B6853602144DF
-:105000001160DAE702D90C230360D6E7256861193D
-:105010008B4204BF19685B68636004BF4919216053
-:105020005460CAE703B030BDB04F0020034611F80A
-:10503000012B03F8012B002AF9D17047014800F039
-:1050400009B800BFB44F0020014800F005B800BF08
-:10505000B44F002070470000704700006F72672E49
-:105060006172647570696C6F742E6D526F2D4D3165
-:1050700030303935000000004E6F206170702073B1
-:1050800069670A00426164206677206C656E677408
-:10509000682025750A0042616420626F6172645F56
-:1050A00069642025752073686F756C6420626520C3
-:1050B00025750A0042616420667720646573637217
-:1050C0006970746F72206C656E6774682025750A4C
-:1050D0000042616420617070204352432030782583
-:1050E0003038783A307825303878203078253038A4
-:1050F000783A3078253038780A00476F6F64206638
-:1051000069726D776172650A0040A2E4F16468918A
-:105110000600000053544D333247343F3F00000037
-:105120004261642043414E496661636520696E6453
-:1051300065782E000000000000000000A920000893
-:10514000B11B000871270008A51B0008211C0008DE
-:105150003D1E0008991D0008E91B0008ED1B000812
-:10516000A91B0008C51B0008AD1B0008FD1D000899
-:10517000D11B00084D280008DD1B0008D11D0008C8
-:105180000096000000000000000000000000000089
-:105190000000000000000000000000006540000862
-:1051A000514000088D400008794000088540000803
-:1051B000714000085D40000849400008994000081F
-:1051C0006D61696E0000000069646C65000000009C
-:1051D000C8510008904D0020084F00200100000039
-:1051E00075420008000000000001A82A000000002D
-:1051F000AAAABEAA00001424EFFF000000000000CD
-:10520000709709000000000000000000AAAAAAAAE6
-:1052100000000000FFFF0000000000000000000090
-:105220000000000000000000AAAAAAAA00000000D6
-:10523000FFFF000000000000000000000000000070
-:1052400000000000AAAAAAAA00000000FFFF0000B8
-:10525000000000000000000000000000000000004E
-:10526000AAAAAAAA00000000FFFF00000000000098
-:10527000000000000000000000000000AAAAAAAA86
-:1052800000000000FFFF0000000000000000000020
-:105290000000000000000000AAAAAAAA0000000066
-:1052A000FFFF0000000000000000000074AFFF7F5F
-:1052B00001000000000000001104000000000000D8
-:1052C0000088030000000000FE2A0100D204000054
-:1052D000FF00000000000000145100083F00000023
-:1052E0002C2300200000000000000000000000004F
-:1052F00000000000000000000000000000000000AE
-:10530000000000000000000000000000000000009D
-:10531000000000000000000000000000000000008D
-:10532000000000000000000000000000000000007D
-:10533000000000000000000000000000000000006D
-:045340000000000069
+:1004F000704700BF02E000F000F8FEE772B6374830
+:1005000080F30888364880F3098836483649086001
+:1005100040F20000CCF200004EF63471CEF2000141
+:100520000860BFF34F8FBFF36F8F40F20000C0F23F
+:10053000F0004EF68851CEF200010860BFF34F8FF5
+:10054000BFF36F8F4FF00000E1EE100A4EF63C71E2
+:10055000CEF200010860062080F31488BFF36F8F8D
+:1005600004F046FB04F0D8FB4FF055301F491B4AFE
+:1005700091423CBF41F8040BFAE71D49184A9142E9
+:100580003CBF41F8040BFAE71A491B4A1B4B9A423D
+:100590003EBF51F8040B42F8040BF8E7002018495D
+:1005A000184A91423CBF41F8040BFAE704F024FBDF
+:1005B00004F0F8FB144C154DAC4203DA54F8041B5C
+:1005C0008847F9E700F042F8114C124DAC4203DACB
+:1005D00054F8041B8847F9E704F00CBB000700201F
+:1005E000002300200000000808ED00E000010020CA
+:1005F0000007002048540008002300208C2300201E
+:100600009023002070500020E0010008E401000861
+:10061000E4010008E40100082DE9F04F2DED108AF7
+:10062000C1F80CD0C3689D46BDEC108ABDE8F08FC0
+:10063000002383F311882846A047002003F056FFCB
+:10064000FEE703F0B9FE00DFFEE70000F8B504F0B6
+:1006500071FA074604F0C2FA0546B8BB204B9F4228
+:1006600034D001339F4234D01E4B27F0FF029A4210
+:1006700032D1F8B200F04EFE2E4642F2107400F075
+:100680004FFE08B10024264601F0A6FA20B103204F
+:1006900000F07CF80024264635B1134B9F4203D06E
+:1006A00004F094FA00242646002004F04DFA0EB11E
+:1006B00000F082F801F05AF900F056FE01F04CF813
+:1006C000204600F0D7F800F077F8F9E72E4600242E
+:1006D000D5E704460126D2E706464FF47A74CEE702
+:1006E000010007B0000008B0263A09B008B500F0D4
+:1006F000FFFFA0F120035842584108BD07B541F261
+:100700001203022101A8ADF8043001F00FF803B084
+:100710005DF804FB38B5302383F31188174803686C
+:100720000BB103F0A1FF164A144800234FF47A716D
+:1007300003F090FF002383F31188124C236813B158
+:100740002368013B2360636813B16368013B636006
+:100750000D4D2B7833B963687BB9022001F094F812
+:10076000322363602B78032B07D163682BB90220F7
+:1007700001F08AF84FF47A73636038BD902300204B
+:1007800015070008B0240020A8230020084B18708B
+:1007900003280CD8DFE800F008050208022001F069
+:1007A0006BB8022001F060B8024B00225A6070471B
+:1007B000A8230020B024002038B501F00DFA30B194
+:1007C000254B03221A70254B00225A6038BD244B5A
+:1007D000244A19680131F9D004339342F9D1224CEB
+:1007E0001F4DD4F80428AA42F0D3204B9B6803F194
+:1007F000006303F5F0439A42E8D204F0B9F904F03B
+:10080000CBF9002000F0C2FF0220FFF7BFFF184B1A
+:100810009A6D00229A65996F9A67996FD96DDA651A
+:10082000D96FDA67D96F196E1A66D3F88010C3F8DA
+:100830008020D3F8803072B64FF0E0233021C3F827
+:10084000085DD4F80038D4F8042881F311889D4657
+:1008500083F308881047B9E7A8230020B0240020BC
+:1008600000780008207800080070000800230020AD
+:10087000001002402DE9F04F93B0AC4B00902022C5
+:10088000FF210AA89D6801F01BF8A94A1378A3B9B3
+:10089000A848012103601170302383F31188036895
+:1008A0000BB103F0E1FEA44AA24800234FF47A7191
+:1008B00003F0D0FE002383F31188009B13B19F4BFC
+:1008C000009A1A609E4A009C1378032B1EBF0023D7
+:1008D00013709A4A4FF0000A18BF5360D346564629
+:1008E000D146012000F0C8FF24B1944B1B68002BB7
+:1008F00000F01582002000F0FBFE0390039B002B0C
+:1009000001DA00F079FD039B002BEDDB012000F004
+:10091000ABFF039B213B162BE3D801A252F823F037
+:100920007D090008A5090008390A0008E308000845
+:10093000E3080008E3080008C30A0008930C000855
+:10094000AD0B00080F0C0008370C00085D0C000808
+:10095000E30800086F0C0008E3080008E10C000839
+:100960001D0A0008E3080008250D00088909000891
+:100970001D0A0008E30800080F0C00080220FFF71A
+:10098000B5FE002840F0F581009B0221BAF1000F6E
+:1009900008BF1C4605A841F21233ADF8143000F030
+:1009A000C5FE9EE74FF47A7000F0A2FE071EEBDB57
+:1009B0000220FFF79BFE0028E6D0013F052F00F242
+:1009C000DA81DFE807F0030A0D10133605230593DB
+:1009D000042105A800F0AAFE17E054480421F9E715
+:1009E00058480421F6E758480421F3E74FF01C0863
+:1009F000404600F0CDFE08F104080590042105A84A
+:100A000000F094FEB8F12C0FF2D1012000FA07F7A4
+:100A100047EA0B0B5FFA8BFB4FF0000900F09CFFDD
+:100A200026B10BF00B030B2B08BF0024FFF766FE6B
+:100A300057E746480421CDE7002EA5D00BF00B0365
+:100A40000B2BA1D10220FFF751FE074600289BD0B7
+:100A5000012000F09BFE0220FFF798FE00265FFABF
+:100A600086F8404600F0A4FE044690B100214046BE
+:100A700000F0AEFE01360028F1D1BA46044641F23C
+:100A80001213022105A8ADF814303E4600F04EFEC8
+:100A900027E70120FFF77AFE2546244B9B68AB42EF
+:100AA00007D9284600F074FE013040F06781043514
+:100AB000F3E7234B00251D70204BBA465D603E4690
+:100AC000ACE7002E3FF460AF0BF00B030B2B7FF471
+:100AD0005BAF0220FFF75AFE322000F009FEB0F1B2
+:100AE0000008FFF651AF18F003077FF44DAF0F4A2F
+:100AF000926808EB050393423FF646AFB8F5807F56
+:100B00003FF742AF124B0193B84523DD4FF47A70A3
+:100B100000F0EEFD0390039A002AFFF635AF019B2B
+:100B2000039A03F8012B0137EDE700BF00230020F3
+:100B3000AC2400209023002015070008B0240020DA
+:100B4000A823002004230020082300200C230020D9
+:100B5000AC230020C820FFF7C9FD074600283FF45A
+:100B600013AF1F2D11D8C5F1200242450AAB25F065
+:100B7000030028BF424683490192184400F08EFECC
+:100B8000019A8048FF2100F09BFE4FEAA8037D49AF
+:100B90000193C8F38702284600F09AFE0646002813
+:100BA0003FF46DAF019B05EB830537E70220FFF7AC
+:100BB0009DFD00283FF4E8AE00F01CFE00283FF445
+:100BC000E3AE0027B846704B9B68BB4218D91F2F75
+:100BD00011D80A9B01330ED027F0030312AA134445
+:100BE00053F8203C05934046042205A900F0DEFF9F
+:100BF00004378046E7E7384600F0CAFD0590F2E783
+:100C0000CDF81480042105A800F090FD06E700232C
+:100C1000642104A8049300F07FFD00287FF4B4AEA3
+:100C20000220FFF763FD00283FF4AEAE049800F009
+:100C3000D7FD0590E6E70023642104A8049300F0A3
+:100C40006BFD00287FF4A0AE0220FFF74FFD0028C7
+:100C50003FF49AAE049800F0C5FDEAE70220FFF7E2
+:100C600045FD00283FF490AE00F0D4FDE1E70220FE
+:100C7000FFF73CFD00283FF487AE05A9142000F0E3
+:100C8000CFFD04210746049004A800F04FFD39462B
+:100C9000B9E7322000F02CFD071EFFF675AEBB074A
+:100CA0007FF472AE384A926807EB090393423FF62D
+:100CB0006BAE0220FFF71AFD00283FF465AE27F067
+:100CC00003074F44B9453FF4A9AE484600F060FD24
+:100CD0000421059005A800F029FD09F10409F1E7B8
+:100CE0004FF47A70FFF702FD00283FF44DAE00F09C
+:100CF00081FD002844D00A9B01330BD008220AA9A9
+:100D0000002000F0E5FD00283AD02022FF210AA8AB
+:100D100000F0D6FDFFF7F2FC1C4803F0EDFB13B02A
+:100D2000BDE8F08F002E3FF42FAE0BF00B030B2B22
+:100D30007FF42AAE0023642105A8059300F0ECFCA3
+:100D4000074600287FF420AE0220FFF7CFFC804644
+:100D500000283FF419AEFFF7D1FC41F2883003F0D0
+:100D6000CBFB059800F00EFE464600F0F5FD3C4634
+:100D7000B7E5064652E64FF0000905E6BA467EE6BC
+:100D800037467CE6AC23002000230020A08601002B
+:100D9000094A136849F2690099B21B0C00FB013340
+:100DA0001360064B186844F2506182B2000C01FBDC
+:100DB0000200186080B27047142300201023002026
+:100DC00010B500211022044600F07AFD034B03CB3E
+:100DD000206061601868A06010BD00BF9075FF1FA3
+:100DE0002DE9F041ADF54E7D0DF134086CAC40F2CB
+:100DF000751207460D460EA80021C8F8001000F035
+:100E00005FFD4FF4C4720021204600F059FD01F04F
+:100E100023FF254B4FF47A72B0FBF2F0186093E891
+:100E20000700012384E807000DF5E9702382FFF72E
+:100E3000C7FF41F204131D49238406A804F01CFADD
+:100E4000182384F832310DF2E3266B440DF1300C97
+:100E50001A4603CA624530607160134606F10806FF
+:100E6000F6D141460122204600F0A6FD002303935F
+:100E7000AB7E029305F11903019380B20123CDE902
+:100E800004800093E97E06A3D3E90023384602F0EC
+:100E9000A3FA0DF54E7DBDE8F08100BFAFF30080F1
+:100EA0009E6AC421818A46EEB82400208852000838
+:100EB0002DE9F043224DBBB001F0CEFEAB6840F20D
+:100EC000ED22C31A934232D906AFA8602B462822DE
+:100ED0000021384602F030FC05F10E0000F0E8FC7D
+:100EE000002604465FFA80F905F10E08F3B2F1001E
+:100EF000994501F1280107D908EB06030822384675
+:100F000002F01AFC0136F1E708230122CDE9023292
+:100F100005340C4B0193A4B230230093CDE9047443
+:100F200005A3D3E90023297B074802F055FA3BB01B
+:100F3000BDE8F083AFF3008078F6339F93CACD8D80
+:100F4000B0490020BD490020D0340020F0B58B8A84
+:100F5000013B9BB2C92BC9B006460C4647D8274D6A
+:100F60002F7B27BB05F10C03009308223B46394633
+:100F7000204602F0A5FA7B1CFAB2D9001F46A38ACC
+:100F8000013B9A4205DA0E322A44009200230822DD
+:100F9000EEE700230022C5E900230023AB6085F8BB
+:100FA000D730C5F8D8302B7B0BB9E37E2B73812269
+:100FB000002106AD27A800F083FC0122294627A8BE
+:100FC00000F0C8FD00230393A37E029304F11903EC
+:100FD00080B201932823CDE90450E17E009330468E
+:100FE00004A3D3E9002302F0F7F9FFF761FF49B04A
+:100FF000F0BD00BF26417272DF25D7B7B04900208F
+:1010000070B50D4614461E4602F042F950B9022E44
+:1010100010D1012C0ED112A3D3E90023C5E900237E
+:10102000012007E0282C10D005D8012C09D0052C70
+:101030000FD0002070BD302CFBD10BA3D3E90023CF
+:10104000ECE70BA3D3E90023E8E70BA3D3E90023E4
+:10105000E4E70BA3D3E90023E0E700BFAFF3008090
+:10106000401DA12026812A0B78F6339F93CACD8D8F
+:101070009E6AC421818A46EE26417272DF25D7B767
+:10108000F017304A39059E562DE9F04F8DB002AF6A
+:1010900080460D4602F0FCF8044600285CD12B7E09
+:1010A000022B1BD1EB8A012B18D101F0D5FD06468E
+:1010B000FFF76EFE03464FF4C870DFF81C92B3FBD7
+:1010C000F0F206F5167602FB103316FA83F3C9F830
+:1010D0000030EB7E33B97B4B00221A702C37BD46B3
+:1010E000BDE8F08FAB8AE6B2013BB34204F10104E4
+:1010F0000CD907F108031E44E100009600230822E2
+:1011000001F0F801284602F0DBF9EBE707F11800DF
+:10111000FFF756FE324607F1180107F1080004F008
+:1011200079F80028D7D10F2E08D8664B1E70D9F851
+:101130000030A3F51673C9F80030CFE7FB1DF87136
+:101140000146009307220346284602F0B9F9F979CF
+:10115000404602F095F8C1E7EB8A282B26D010D83C
+:10116000012B1ED0052BB9D1BFF34F8F5649574BDA
+:10117000CA6802F4E0621343CB60BFF34F8F00BF35
+:10118000FDE7302BAAD16B7E514C0133627BDBB281
+:101190009342E94603D1EA7E237B9A420BD0CD46A7
+:1011A0009CE729464046FFF71BFE97E72946404645
+:1011B000FFF7CCFE92E74FF0000807F11803A7F8FD
+:1011C00018801022009341460123284602F078F946
+:1011D000AE8A023EB6B2F31C9B109B000733DB08BD
+:1011E000A9EBC3039D460DF1080A1FFA88F34FEAE5
+:1011F000C8019E4201F110010AD90AEB08030093CD
+:1012000008220023284602F05BF908F10108ECE708
+:1012100094F8D70000F0CCFAD4F8D810054619B9E4
+:1012200094F8D70000F0D4FAD4F8D83033449D4273
+:1012300005D294F8D7000021013000F0C9FA4FEA36
+:10124000960B4FF000081FFA88F18B45D4E9003265
+:1012500009D90AEB880103EB8800012200F038FB72
+:1012600008F10108EFE7F31842F10002C4E9003287
+:10127000D4F8D83094F8D70006EB0308C4F8D88027
+:1012800000F096FA804509D394F8D730D4F8D80006
+:101290000133401B84F8D730C4F8D800FF2E0D4D21
+:1012A00009D80023237300F0A5FA00F095FC2881EB
+:1012B00008B9FFF781FA23689B0A01332B810023C9
+:1012C000A3606CE7C934002000ED00E00400FA05DB
+:1012D000B0490020B8240020CC34002010B50A4BBF
+:1012E0000A4A1A6003F5805393F848203AB95C6CB7
+:1012F0002CB1204600F0EEFC204603F073FFBDE861
+:101300001040034800F0E6BC00350020E052000821
+:1013100030450020014B1870704700BFC4240020E6
+:1013200010B54FF000540C4B22689A4211D10B4B70
+:10133000627D1A700A48237D03730A49C9220E3060
+:1013400000F0ACFAE0220021204600F0B9FA0120BA
+:1013500010BD0020FCE700BF9AAD44C5C4240020A6
+:10136000B04900201600002037B500F035FC194DBB
+:101370001949288102236B7100220123174801F0CB
+:101380006FF800230193164B164900931648174B2C
+:101390004FF4805201F04CFF154B197811B11248EF
+:1013A00001F06EFF01F058FC0446FFF7F1FC4FF42A
+:1013B000C873B0FBF3F202FB130304F5167010FAC6
+:1013C00083F00C4B186003F009FC08B10F232B814C
+:1013D00003B030BDB824002040420F00003500208B
+:1013E00001100008C8240020D03400208910000813
+:1013F000C4240020CC3400202DE9F04F2DED028BC9
+:1014000095A7D7E900670FF25829D9E900898C4CD4
+:1014100095B0DFF854A2DFF854B2204602F008F885
+:10142000034650B30025CDE911551095ADF84C5049
+:10143000027B8DF84C209968406811AA03C21B6892
+:1014400043F00043109301F009FC10EB0A0241F154
+:101450000003009510A9584600F0DAFDA842794A29
+:1014600005DD204601F0E8FF764A1570D5E71378D0
+:10147000072B00F2B980013313700DAD9FED6E8B19
+:101480000023DFF8E8B10C93ADF83C300D936B60AE
+:1014900000230DF125028DED008B4FF0010A09A903
+:1014A00058468DF825308DF824A001F03DFB9DF8BD
+:1014B00024200023002A40F09B80204601F0E8FE13
+:1014C0000546002847D1DFF8A8B101F0C5FBDBF8DD
+:1014D000003098423FD301F0BFFB0790FFF758FC64
+:1014E000079A4FF4C87302F51672B0FBF3F101FBD3
+:1014F000130312FA83F3CBF80030DFF878B19BF8CE
+:1015000000100791002914BF2B46534610A88DF8F0
+:101510003030FFF755FC0799C1F11002D2B2062A0C
+:1015200010AB28BF062219440DF13100079200F0DC
+:10153000B5F9079A0CAB0393182302930132424B7F
+:10154000D2B2CDE900A304923B463246204601F0D8
+:10155000E5FE8BF8005001F07FFB3C4A3C4D1368E0
+:10156000C31AB3F57A7F32D3106001F077FB0246DD
+:101570000B46204601F06AFF204601F089FE30B399
+:101580002B7BDFF8F4A0002B14BF032302238AF87F
+:10159000053001F061FB0DF1400B4FF47A7301222D
+:1015A000B0FBF3F05946CAF80000504600F0AAFA22
+:1015B00018230293274B019380B240F25513CDE9D3
+:1015C00003B0009342464B46204601F0A7FE2B7B1A
+:1015D0002BB1FFF76DFC2B7B002B7FF41AAF15B0FE
+:1015E000BDEC028BBDE8F08F204601F025FF44E7FB
+:1015F0004FF0904110A84A6982F010024A611946E2
+:10160000102200F05DF90DF126030AAA0CA9584634
+:1016100000F0F0FD95E8030011AB83E803009DF8AE
+:101620003C308DF84C300C9B109310A9DDE90A2357
+:10163000204602F0C9F82BE700000000000000007F
+:10164000D0340020954A0020C8340020904A002061
+:10165000B0490020944A0020401DA12026812A0B79
+:10166000F1C6A7C1D068080F40420F000035002026
+:10167000CC340020C9340020B824002008B5054827
+:1016800000F05CFEBDE80840034A0449002003F076
+:10169000A3BD00BF00350020E84A0020DD1200088D
+:1016A00070B5104B1B780133DBB2012B0C4612D8FE
+:1016B0000D4B1D6829684FF47A730E6AA2FB033242
+:1016C000014622462846B047844204D1074B0022F7
+:1016D0001A70012070BD4FF4FA7002F00DFF002067
+:1016E000F8E700BF182300201C230020DC4A00205C
+:1016F00007B50023024601210DF107008DF80730E0
+:10170000FFF7CEFF20B19DF8070003B05DF804FBA2
+:101710004FF0FF30F9E700000A4608B50421FFF753
+:10172000BFFF80F00100C0B2404208BD30B4074B9B
+:101730000A461978064B53F821402368DD69054BAA
+:101740000146AC46204630BC604700BFDC4A002062
+:101750001C230020A086010070B503F075F8094E27
+:10176000094D3080002428683388834208D903F06B
+:1017700067F82B6804440133B4F5F04F2B60F2D3C3
+:1017800070BD00BFDE4A0020984A002003F020B957
+:1017900000F1006000F5E040D0F80008704700005C
+:1017A00000F10060920000F5F04003F091B80000F5
+:1017B000054B1A68054B1B889B1A834202D91044BB
+:1017C00003F03EB800207047984A0020DE4A00200F
+:1017D000024B1B68184403F04BB800BF984A002026
+:1017E0000020704700F10050A0F51040D0F890059F
+:1017F00070470000064991F8243033B10023086A8D
+:1018000081F824300822FFF7CBBF0120704700BFCA
+:101810009C4A0020014B1868704700BF002004E07C
+:1018200030B50F4B0F4C1B682288C3F30B030138F4
+:10183000934208440BD164680A46013C8242134635
+:101840000BD214F9015F2DB102F8015BF6E781427A
+:101850000B4602D22C2203F8012B581A30BD00BFD0
+:10186000002004E020230020022802BF4FF0904314
+:1018700010229A6170470000022802BF4FF0904387
+:101880004FF480129A617047022801BF4FF09042D6
+:10189000536983F0100353617047000010B50023B3
+:1018A000934203D0CC5CC4540133F9E710BD00006F
+:1018B00003460246D01A12F9011B0029FAD17047DB
+:1018C00002440346934202D003F8011BFAE7704733
+:1018D0002DE9F8431F4D144695F824200746884605
+:1018E00052BBDFF870909CB395F824302BB92022BE
+:1018F000FF2148462F62FFF7E3FF95F82400C0F16F
+:101900000802A24228BF2246D6B24146920005EB09
+:101910008000FFF7C3FF95F82430A41B1E44F6B2E5
+:10192000082E17449044E4B285F82460DBD1FFF719
+:1019300061FF0028D7D108E02B6A03EB82038342C2
+:10194000CFD0FFF757FF0028CBD10020BDE8F883A8
+:101950000120FBE79C4A0020024B1A78024B1A70C8
+:10196000704700BFDC4A00201823002003494FF4D1
+:10197000E1330B60024B186802F084BCC44A0020BB
+:101980001C230020094B10B51822044600211846DC
+:10199000FFF796FF064A074B127804600146BDE840
+:1019A000104053F8220002F06DBC00BFC44A002072
+:1019B000DC4A00201C2300202DE9F0470D46044698
+:1019C00000219046284640F27912FFF779FF23461E
+:1019D00020220021284601F0AFFE231D02222021F3
+:1019E000284601F0A9FE631D03222221284601F0AA
+:1019F000A3FEA31D03222521284601F09DFE04F12C
+:101A0000080310222821284601F096FE04F1100355
+:101A100008223821284601F08FFE04F11103082224
+:101A20004021284601F088FE04F1120308224821D3
+:101A3000284601F081FE04F114032022502128469B
+:101A400001F07AFE04F1180340227021284601F0CB
+:101A500073FE04F120030822B021284601F06CFE39
+:101A600004F121030822B821284601F065FE04F1A3
+:101A70002207C0263B46314608222846083601F098
+:101A80005BFEB6F5A07F07F10107F3D104F1320345
+:101A900008223146284601F04FFE002704F1330AA0
+:101AA00094F832304FEAC7099F4209F5A47615D35E
+:101AB000B8F1000F08D1314604F599730722284682
+:101AC00001F03AFE09F24F16274694F832213B1BEB
+:101AD00093420CD3F01DC008BDE8F0870AEB070362
+:101AE00008223146284601F027FE0137D8E707F2E1
+:101AF000331331460822284601F01EFE083601370E
+:101B0000E3E7000013B504460846002101602346C0
+:101B1000C0F803102022019001F00EFE0198231D51
+:101B20000222202101F008FE0198631D03222221D8
+:101B300001F002FE0198A31D0322252101F0FCFD06
+:101B4000019804F108031022282101F0F5FD072077
+:101B500002B010BDF8B50E4605461446002181229C
+:101B60003046FFF7ADFE2B4608220021304601F03B
+:101B7000E3FD7CB96B1C07220821304601F0DCFD37
+:101B80000F2401236A785F1C013B934204D3E01DBC
+:101B9000C008F8BD0824F4E7EB19214608223046B6
+:101BA00001F0CAFD08343B46ECE7000030B5094DB2
+:101BB0000A4491420DD011F8013B5840082340F3EC
+:101BC0000004013B2C4013F0FF0384EA5000F6D1DF
+:101BD000EFE730BD2083B8ED73B5384A106851681F
+:101BE0006B4603C36A4636493648082303F022FB96
+:101BF000044670B9344A106851686B4603C36A469C
+:101C000032493048082303F015FB044630BB0A2054
+:101C100022E00369B3F5623FECD8418B40F21142F8
+:101C20009142E7D12A4A024402F110018B42E1D3EA
+:101C3000103B244900209D1AFFF7B8FF2A460646AC
+:101C400004F118010020FFF7B1FFA3689E42D1D133
+:101C5000E3689842CED1002002B070BD0369B3F5AD
+:101C6000623F22D8B0F8661040F2114291421ED174
+:101C7000174A024402F15C018B421AD35C3B1149C2
+:101C800000209D1AFFF792FF2A46064604F16401E0
+:101C90000020FFF78BFFA268964203460BD1E06855
+:101CA000834214BF0D200020D6E70B20D4E70C2080
+:101CB000D2E71020D0E70D20CEE700BFB0520008D9
+:101CC000DC87030000780008B95200089087030001
+:101CD0000888FFF710B5037C044613B9006803F0C9
+:101CE00091FA204610BD00000023BFF35B8FC36054
+:101CF000BFF35B8FBFF35B8F8360BFF35B8F704776
+:101D0000BFF35B8F0068BFF35B8F704770B505460C
+:101D10000C30FFF7F5FF05F1080604463046FFF7E3
+:101D2000EFFFA04206D930466D68FFF7E9FF254472
+:101D3000281A70BD3046FFF7E3FF201AF9E70000CC
+:101D400070B50546406898B105F10800FFF7D8FF67
+:101D500005F10C0604463046FFF7D2FF84423046B8
+:101D600094BF6D680025FFF7CBFF013C2C44201A7F
+:101D700070BD000038B50C460546FFF7C7FFA0420E
+:101D800010D305F10800FFF7BBFF04446868B4FBFB
+:101D9000F0F100FB1144BFF35B8F0120AC60BFF397
+:101DA0005B8F38BD0020FCE72DE9F0411446074663
+:101DB0000D46FFF7C5FF844228BF0446D4B1B8469C
+:101DC00058F80C6B4046FFF79BFF304428604046B4
+:101DD0007E68FFF795FF331A9C4203D86C600120A0
+:101DE000BDE8F0816B60A41B3B68AB602044E860F9
+:101DF0000220F5E72046F3E738B50C460546FFF725
+:101E00009FFFA04210D305F10C00FFF779FF0444B7
+:101E10006868B4FBF0F100FB1144BFF35B8F012055
+:101E2000EC60BFF35B8F38BD0020FCE72DE9FF417C
+:101E3000884669460746FFF7B7FF6C4606B204EBD3
+:101E4000C6060025B44209D06268206808EB050187
+:101E5000FFF724FD636808341D44F3E7294638463C
+:101E6000FFF7CAFF284604B0BDE8F081F8B5054683
+:101E70000C300F46FFF744FF05F1080604463046D4
+:101E8000FFF73EFFA042304688BF6C68FFF738FF7F
+:101E9000201A386020B130462C68FFF731FF20440B
+:101EA000F8BD000073B5144606460D46FFF72EFF39
+:101EB000844228BF04460190DCB101A93046FFF7F7
+:101EC000D5FF019B33B93268C5E90233C5E9002467
+:101ED00001200CE09C4238BF0194286001986860A2
+:101EE0008442F5D93368AB60241AEC60022002B05A
+:101EF00070BD2046FBE700002DE9FF410F46694613
+:101F0000FFF7D0FF6C4600B204EBC0050026AC42E0
+:101F100009D0D4F8048054F8081BB8194246FFF7DA
+:101F2000BDFC4644F3E7304604B0BDE8F081000054
+:101F300038B50546FFF7E0FF044601462846FFF79F
+:101F400019FF204638BD0000302383F3118862B6A4
+:101F500070470000002383F3118862B670470000C9
+:101F6000012070477047000010B4134602681468DF
+:101F70000022A4465DF8044B6047000000F5805045
+:101F800090F859047047000000F5805090F8520412
+:101F90007047000000F5805090F958047047000029
+:101FA0005020704700F5805208B5FFF7CDFFD2F8FA
+:101FB0009834D2F894041844D2F890341844D2F8E3
+:101FC00078341844D2F888341844D2F88434184449
+:101FD000FFF7C0FF08BD000038B5C26A936923F05F
+:101FE00001039361044600F037FE0546E36A9B69EE
+:101FF000DB0706D500F030FE431BFA2BF6D9002094
+:1020000004E004F58054012084F8520438BD000037
+:102010002DE9F04F0C4600F5805185B01F4691F830
+:102020005234BDF83890054690469BB1D1F87434CF
+:102030000133C1F8743423689A0006D4237B082B3B
+:102040000BD9627B0AB10F2B07D9D1F87834013351
+:10205000C1F878344FF0FF300FE0FFF775FFEB6AFF
+:10206000D3F8C42012F4001A0AD0D1F87C3401331A
+:10207000C1F87C34FFF76EFF002005B0BDE8F08F9B
+:10208000D3F8C46022686B6AC6F301464FF0480B70
+:10209000002A1BFB063BB4BF42F080429204CBF8FF
+:1020A000002023685B0044BF42F00052CBF80020C0
+:1020B000227B330643EA0243CBF80430607B720193
+:1020C00018B343F44013CBF80430D1F8A4340133EF
+:1020D000C1F8A434AB1803F58353197B41F02001F8
+:1020E0001973207B039200F015FE039A03308010D1
+:1020F0005FFA8AF383420AF1010A0DDA04EB8301E5
+:102100000BEB830349689960F2E7AB1803F583533F
+:10211000197B60F34511E3E7EB6A0121B140C3F895
+:10212000CC10AB1803F58253C3E9048705EB4613C3
+:1021300003F582532146183304F10C0051F804CB07
+:1021400043F804CB8142F9D1098819802A4441F22D
+:1021500068032846D65002F5805209F0030392F82E
+:102160006C1043F0100321F01F010B4382F86C3018
+:10217000FFF7F0FE4246CDF800903B46214600F0C6
+:102180008FFD012079E7000013B500F5805401911F
+:10219000606CFFF7D5FD1F280AD90199606C2022D9
+:1021A000FFF744FEA0F120035842584102B010BD91
+:1021B0000020FBE708B500F58050FFF7C5FE406C36
+:1021C000FFF792FDBDE80840FFF7C4BE00220260A1
+:1021D000828142608260704710B500220023C0E90E
+:1021E00000230023044603810C30FFF7EFFF204655
+:1021F00010BD00002DE9F047074688B007F5805470
+:1022000068469A468846FFF79FFE9146FFF7E4FF2F
+:10221000606CFFF77BFD1F282CD9606C202269467B
+:10222000FFF786FE202825D194F8523413B303AD6E
+:10223000444605AB2E4603CE9E4220606160354683
+:1022400004F10804F6D130682060B388A380DDE98A
+:102250000023C9E90023BDF80830AAF80030FFF7D1
+:1022600079FE4A4653464146384608B0BDE8F04735
+:1022700000F004BDFFF76EFE002008B0BDE8F08757
+:102280002DE9F84F00230646C0E90133284B46F8F4
+:10229000303B00F5815405468846374610343846B1
+:1022A0002037FFF799FFA742F9D105F580544FF485
+:1022B000805326630026C4E90D366764012305F5C3
+:1022C000835705F5A359E66384F8403084F8483015
+:1022D000103709F110094FF0000A4FF0000B47E9E1
+:1022E00008ABA7F11800FFF771FF203747F8286CFB
+:1022F0004F45F4D184F85884A4F85A64A4F85C6477
+:10230000A4F85E6484F86064A4F86264A4F8646469
+:10231000A4F8666484F86864B8F1000F02D0054838
+:1023200000F094FC044BEB622846BDE8F88F00BF38
+:10233000E0520008C45200080064004010B5044B8D
+:10234000197804464A1C1A70FFF79AFF204610BD00
+:10235000E54A00202DE9F04300295FD03048314B99
+:10236000B3FBF1F381428CBF0A201120451EB3FB61
+:10237000F0F700FB1730ECB220B1022D2846F5D85B
+:10238000002037E07D1EB5F5806F33D2C4EBC40862
+:1023900008F103034FEAE30EC3F3C703A4EB030CF6
+:1023A0000EF101094FF47A705FFA8CF60EFB000E05
+:1023B00059FA8CFCBEFBFCFCBCF5617F1CDC1FFAEF
+:1023C0008CF4581C56FA80F047431648B0FBF7F7D8
+:1023D000B942D5D1013BDBB20F2BD1D8711EC9B2A6
+:1023E00007294FF0000005D81071148055805371F3
+:1023F00091710120BDE8F08308F1FF334FEAE30C4F
+:10240000C3F3C703E41A0CF1010EE6B20CFB0000A3
+:102410005EFA84F4B0FBF4F4A4B2D2E70846E9E72C
+:102420003F420F0000127A000B4B10B54FF454726C
+:10243000044600211846FFF743FA084BA3614033D6
+:10244000E361D8332362F0336362E36A60610022A0
+:10245000C3F8C02010BD00BF00A4004070A400401D
+:102460002DE9F04F00F58055994695F85834012B29
+:1024700089B004468A46904604D90027384609B0F8
+:10248000BDE8F08F904A52F8231009B942F82300B2
+:102490008E49C4F80CA00B7884F8109093B9FFF71C
+:1024A00053FD8B4B9A6D42F000729A659A6B42F025
+:1024B00000729A639A6B22F000729A6301230B7088
+:1024C000FFF748FD95F8513473B903211520FFF744
+:1024D0003BFD01F021FD0321162001F01DFD01232C
+:1024E00085F85134FFF736FDFFF72EFDE26A936958
+:1024F00023F01003936100F0AFFB0746E36A9E6987
+:1025000016F0080607D000F0A7FBC31BFA2BF5D97D
+:10251000FFF720FDB1E79A6942F001029A6100F0ED
+:102520009BFB0746E36A9A69D00705D400F094FB49
+:10253000C31BFA2BF6D9EBE79A6942F002029A61C3
+:10254000E36A00275F65FFF705FD686CFFF7CCFBCA
+:1025500004F5825B0BF1100B202200216846FFF787
+:10256000AFF902A8FFF732FE06976A460BEB0603A7
+:102570000DF1180E9446BCE80300F445186059604C
+:10258000624603F10803F5D1DCF80000186020363C
+:102590009CF804201A71B6F5806FDDD1002304F594
+:1025A000A25285F8503485F853341A3251462046E9
+:1025B000FFF7D0FE074690B9E26A936923F0010362
+:1025C000936100F049FB0546E36A9B69D9077FF5F3
+:1025D00054AF00F041FB431BFA2BF5D94DE795F8BA
+:1025E0005F6495F85E24C5F86CA4360246EA42663C
+:1025F00095F86024E36A1643B5F85C2446EA02467F
+:10260000DE61B8F1000F29D004F5A3520232414631
+:102610002046FFF79FFE90B9E26A936923F0010319
+:10262000936100F019FB0546E36A9B69DA077FF5C1
+:1026300024AF00F011FB431BFA2BF5D91DE795F8E9
+:10264000683495F86714C5F870841B0143EA0123C8
+:10265000B5F86414E26A43EA0143D3602046FFF709
+:10266000E3FE002385F85934E36A6FF040421A65AF
+:10267000E36A184A5A65E36A44229A65E36A0722C4
+:10268000C3F8DC20E36A0322DA65E26A9369B9F1F0
+:10269000030F43F4407393613FF4F0AEE26A936931
+:1026A00023F00103936100F0D7FA0646E36A9B69C1
+:1026B000DB0705D500F0D0FA831BFA2BF6D9DCE650
+:1026C000012385F85234D9E6E04A0020E44A00208C
+:1026D000001002409B0008002DE9F04F054689B02C
+:1026E00090469946002741F2680A00F58056EB6A49
+:1026F000D3F8D430FB40D8074AD505EB47125244F3
+:102700004FEA471B1379190742D4D6F880340133B6
+:10271000C6F8803413799A0648BFD6F8A83405EB7A
+:102720000B0248BF0133524448BFC6F8A83413799E
+:1027300043F008031371DB0722D596F85334FBB13D
+:1027400005F58254183468465C44FFF745FD03AB39
+:1027500004F1080C206861681A4603C20834644515
+:102760001346F7D120681060A2889A800123ADF843
+:1027700008302B68CDE90089DB6B6946284698470D
+:10278000D6F8543423B1D6F89C340133C6F89C34BF
+:102790000137202FABD109B0BDE8F08F2DE9F04F04
+:1027A0008DB004460F4600F059FA82468946002F44
+:1027B00056D1E36AD3F89020920141BF04F58051CD
+:1027C000D1F894240132C1F89424D3F8902016074C
+:1027D00003D100200DB0BDE8F08FD3F89050E6692A
+:1027E000C5F30125482303FB0566E8464046FFF78D
+:1027F000EDFC326851004ABF22F06043C2F38A43C5
+:1028000043F00043920048BF43F080430093736855
+:1028100013F400131FBF04F5805201238DF80D300F
+:10282000D2F8AC340EBF8DF80D300133C2F8AC34A1
+:10283000F38803F00F038DF80C304FF0000B9DF878
+:102840000C0000F067FA5FFA8BF3984220D9F21877
+:102850000CA90B44127A03F82C2C0BF1010BEEE7B8
+:10286000012FB6D1E36AD3F89820950141BF04F552
+:102870008051D1F894240132C1F89424D3F89820DF
+:102880001007A6D0D3F89850266AC5F30125A9E70A
+:10289000EFB9E36AC3F8945004A8FFF79DFC98E8E9
+:1028A0000F0007AD07C52B800023ADF81830236853
+:1028B0002046CDE904A9DB6B04A9984704F58054B0
+:1028C00058B1D4F88C340133C4F88C3482E7012F2A
+:1028D00004BFE36AC3F89C50DEE7D4F890340133B8
+:1028E000C4F89034012075E7F8B505460F4600F5A9
+:1028F0008054012639462846FFF750FF10B184F86E
+:102900005364F7E7D4F8543423B1D4F89C3401333A
+:10291000C4F89C34F8BD0000F0B5C36A1A6C12F418
+:102920007F0F2BD000F580541B6CC4F8A03441F20B
+:102930006805002347194FF0010C00EB43122A44AD
+:102940005E01117911F0020F15D0490713D4B9595E
+:10295000C66AD6F8C8E00CFA01F111EA0E0F0AD0E7
+:10296000C6F8D010117941F004011171D4F888240F
+:102970000132C4F888240133202BDED1F0BD0000E1
+:1029800010B5254C254B226802B338B31A6D1206D8
+:102990000ED580221A6500F061F950EA01020B465B
+:1029A00002D0013861F1000302462068FFF794FE6F
+:1029B0001A4A136D1B032AD523684FF4002103F52F
+:1029C00080531165012283F8592420E001221A6501
+:1029D00008221A654FF480621A6510BD196DC80788
+:1029E00002D4196D890705D5032119651046002108
+:1029F000FFF77AFF094B1A6D100702D41A6DD10642
+:102A000005D518221A6520680121FFF76DFF20689F
+:102A1000BDE81040FFF780BFE04A0020006400409E
+:102A200008B5FFF791FAFFF777FFBDE80840FFF719
+:102A300091BA0000C36AD3F8C40080F40010C0F358
+:102A40004050704700F5805008B5FFF77DFA406CA4
+:102A5000FFF75CF9FFF77EFA43090CBF0120002065
+:102A600008BD000000F5805393F8592462B1C16A93
+:102A70008A6922F001028A61D3F898240132C3F8EE
+:102A80009824002283F85924704700002DE9F74369
+:102A900000F5825198461031FFF756FA002541F2B1
+:102AA000680E4FF0010900F5805C00EB451474449A
+:102AB00023795E071CD4DB061AD5C36A8E69D3F866
+:102AC000C87009FA06F63E4212D04F6801970F68A7
+:102AD0009742019F77EB08070AD2C3F8D0602379A9
+:102AE00043F004032371DCF884340133CCF88434DC
+:102AF0000135202D01F12001D7D103B0BDE8F0430D
+:102B0000FFF728BAF8B51E46002313700F46054696
+:102B10001446FFF797FF80F0010038701EB1284679
+:102B2000FFF788FF2070F8BD2DE9F04F85B099467A
+:102B3000DDE90EA30D4602931378019391F800B0DE
+:102B40008046164600F08AF82B7804460F4613B9E3
+:102B50003378002B42D022463B464046FFF796FF93
+:102B6000FFF75EFFFFF77EFF4B4632462946FFF731
+:102B7000C9FF2B7833B1BBF1000F03D0012005B0A2
+:102B8000BDE8F08F337813B1019B002BF6D108F527
+:102B900080530393029B544577EB03031ED2039BA0
+:102BA000D3F85404D0B10368AAEB0401DB6889B2FE
+:102BB00098474B46324629464046FFF7A3FF2B78FD
+:102BC00013B1BBF1000FD9D1337813B1019B002BA6
+:102BD000D4D100F043F804460F46DBE70020CEE7EF
+:102BE00008B50020FFF7CCFEBDE8084001F048B86A
+:102BF00008B50120FFF7C4FEBDE8084001F040B869
+:102C000000B59BB0EFF3098168226846FEF746FEE7
+:102C1000EFF30583014B9B6BFEE700BF00ED00E087
+:102C200008B5FFF7EDFF000000B59BB0EFF3098199
+:102C300068226846FEF732FEEFF30583014B5B6BBB
+:102C4000FEE700BF00ED00E0FEE700000FB408B5AE
+:102C5000029801F0E7FBFEE701F008BF01F0E0BEDB
+:102C600001F0DEBE13B56C4684E80600031D94E84F
+:102C7000030083E80500012002B010BD73B585682C
+:102C8000019155B11B885B0707D4D0E900369B6BD7
+:102C90009847019AC1B23046A847012002B070BDE2
+:102CA000F0B5866889B005460C465EB1BDF838308F
+:102CB0005B070AD4D0E900379B6B98472246C1B224
+:102CC0003846B047012009B0F0BD00220023CDE90D
+:102CD00000230023ADF808300A4603AB01F10806D3
+:102CE000106851681C4603C40832B2422346F7D12B
+:102CF000106820609288A280FFF7B2FF0423ADF82D
+:102D000008302B68CDE90001DB6B694628469847FF
+:102D1000D8E70000082817D909280CD00A280CD0B9
+:102D20000B280CD00C280CD00D280CD00E2814BF6A
+:102D30004020302070470C2070471020704714202E
+:102D40007047182070472020704700002DE9F0419F
+:102D5000456A15B94162BDE8F0814B6823F06047D0
+:102D6000C3F38A464FEAD37EC3F3807816EA23067C
+:102D700038BF3E46AC462B465A68BEEBD27F22F0A7
+:102D800060440AD0002A18DAA40CB44217D19D423C
+:102D90000FD10D60DEE71346EEE7A74207D102F040
+:102DA0008044C2F3807242450BD054B1EFE708D2A1
+:102DB000EDE7CCF800100B60CDE7B44201D0B4428F
+:102DC000E5D81A689C46002AE5D11960C3E70000DF
+:102DD0002DE9F047089D01F007044FEAD508224489
+:102DE00005F0070500EBD1004FF47F49944201D173
+:102DF000BDE8F08704F0070705F0070A57453E468F
+:102E000038BF5646C6F10806111B8E4228BF0E4633
+:102E1000E10808EBD50E415C13F80EC0B94029FA61
+:102E200006F721FA0AF1FFB28CEA010147FA0AF724
+:102E300039408CEA010C03F80EC034443544D5E720
+:102E400080EA0120082341F2210201B2400000295A
+:102E500080B203F1FF33B8BF504013F0FF03F4D149
+:102E60007047000038B50C468D18A54200D138BD1A
+:102E700014F8011BFFF7E4FFF7E7000042684AB1CE
+:102E8000136843604389818901339BB2994243812E
+:102E900038BF83811046704770B588B02022044641
+:102EA0000D4668460021FEF70BFD20460495FFF70E
+:102EB000E5FF024658B16B46054608AE1C4603CCFA
+:102EC000B44228606960234605F10805F6D1104632
+:102ED00008B070BD082817D909280CD00A280CD0D2
+:102EE0000B280CD00C280CD00D280CD00E2814BFA9
+:102EF0004020302070470C2070471020704714206D
+:102F0000704718207047202070470000082817D904
+:102F10000C280CD910280CD914280CD918280CD935
+:102F200020280CD930288CBF0F200E207047092094
+:102F300070470A2070470B2070470C2070470D2007
+:102F4000704700002DE9F843078C072F04461ED96F
+:102F5000D0E9029800254FF6FF73C5F12006A5F1D0
+:102F6000200029FA05F108FA06F628FA00F03143A4
+:102F70000143C9B21846FFF763FF0835402D0346E9
+:102F8000EBD1E1693A46BDE8F843FFF76BBF4FF676
+:102F9000FF70BDE8F883000010B54B6823B9CA8AFA
+:102FA00063F30902CA8210BD04691A681C600361D8
+:102FB000C38A013BC3824A60EFE700002DE9F84F66
+:102FC0001D46CB8A0F46C3F3090105298146924667
+:102FD0000B4630D00020AAB207F11A049EB2042E8C
+:102FE0001FFA80F80FD8904503F1010306D3FB8A3E
+:102FF0000A4462F30903FB8201201AE01AF8006018
+:10300000E6540130EAE79045F1D2A1F1050B1C230B
+:103010007C68BBFBF3F203FB12BB1FFA8BF6002CA0
+:1030200045D14846FFF72AFF044638B978606FF06B
+:103030000200BDE8F88F4FF00008E6E700260660C2
+:103040007860ADB24FF0000B454510D90AEB08038C
+:10305000221D13F8011B9155B1B208F101081B297B
+:103060001FFA88F82BD0454506F10106F1D8FB8AF6
+:10307000C3F30902154465F30903BCE7013292B2B8
+:103080001C462368002BF9D16B1F0B441C21B3FB9A
+:10309000F1F301339BB29A42D3D2BBF1000FD0D1EE
+:1030A0004846FFF7EBFE20B9C4F800B0BFE70122A5
+:1030B000E7E7C0F800B05E4620600446C1E745453A
+:1030C000D5D94846FFF7DAFE08B92060AFE7C0F867
+:1030D00000B0002620600446B6E700002DE9F04F5E
+:1030E0002DED028B1C4683B05B6901920746884632
+:1030F000002B00F09A80238C2BB1E269002A00F0AB
+:103100009480072B35D807F10C00FFF7B7FE054672
+:1031100038B96FF00205284603B0BDEC028BBDE85C
+:10312000F08F14220021FEF7CBFB228CE16905F120
+:103130000800FEF7B3FB208C013080B2FFF7E6FEFB
+:10314000FFF7C8FE013880B220840130287463691B
+:10315000228C1B782A4403F01F0363F03F0348F0DE
+:1031600000411372384669602946FFF7EFFD0125DB
+:10317000D1E700F10C034FF0000908EE103A4FF0D0
+:10318000800A4E464D4618EE100AFFF777FE83463A
+:103190000028BED014220021FEF792FB002E3AD167
+:1031A000019BABF8083002220BF1080E1FFA82FCDB
+:1031B0000CF10100BCF1060F218C80B201D88E42C7
+:1031C0002BD3FFF7A3FEFFF785FE62691278013863
+:1031D00002F01F028E4208BF4FF0400A42EA491235
+:1031E0001BFA80F14AEA020A013048F0004281F8F5
+:1031F00008A08BF81000CBF8042059463846FFF79A
+:10320000A5FD238C0135B3422DB289F001094FF0A1
+:10321000000AB8D17FE70022C6E7E169895D0EF8B0
+:1032200002100136B6B20132C0E76FF0010572E755
+:10323000F8B515460E463022002104461F46FEF71B
+:103240003FFB069B6360B5F5001F079BA76034BF7B
+:103250006A094FF6FF72A36297B2E66104F11000AB
+:1032600000239A4206D800230360A782E3822383C7
+:10327000E360F8BD0660013330462036F1E7000018
+:1032800003781BB94BB2002BC8BF01707047000018
+:1032900000787047F8B50C46C969074611B9238C08
+:1032A000002B37D1257E1F2D34D8387828BB228CAF
+:1032B000072A2CD8268A36F003032BD14FF6FF704D
+:1032C000FFF7D0FD20F001003102400441EA056122
+:1032D000400C41EA40254FF6FF7223462946384606
+:1032E000FFF7FCFE002807DD626913780133DBB2CB
+:1032F0001F2B88BF00231370F8BD218A2D0645EAD5
+:10330000012505432046FFF71DFE0246E5E76FF065
+:103310000300F1E76FF00100EEE7000070B58AB03E
+:10332000044616460021282268461D46FEF7C8FAC4
+:10333000BDF83830ADF810300F9B05939DF8403044
+:103340008DF81830119B07936946BDF84830ADF8E9
+:1033500020302046CDE90265FFF79CFF0AB070BD22
+:103360002DE9F041D36905460C4616460BB9138C7E
+:103370005BBB377E1F2F28D895F80080B8F1000F6F
+:1033800026D03046FFF7DEFD3378210241EAC33113
+:1033900041EA0801338A41EA076141EA03410246F2
+:1033A000334641F080012846FFF798FE00280ADDE9
+:1033B0003378012B07D1726913780133DBB21F2BED
+:1033C00088BF00231370BDE8F0816FF00100FAE7B9
+:1033D0006FF00300F7E70000F0B58BB004460D4630
+:1033E00017460021282268461E46FEF769FA9DF816
+:1033F0004C305A1E534253418DF800309DF84030F6
+:10340000ADF81030119B05939DF848308DF81830B9
+:10341000149B07936A46BDF85430ADF82030294616
+:103420002046CDE90276FFF79BFF0BB0F0BD000010
+:10343000406A00B104307047436A1A684262026908
+:103440001A600361C38A013BC38270472DE9F041D2
+:10345000D0F82080194E14461D464146002709B970
+:10346000BDE8F081D1E90223A21A65EB030396427D
+:1034700077EB03031ED2036A8B420DD1FFF78CFD5D
+:10348000036A1B68036203690B60C38A0161016AF6
+:10349000013BC3828846E2E7FFF77EFD0B68C8F870
+:1034A000003003690B60C38A0161013BC382D8F815
+:1034B0000010D4E788460968D1E700BF80841E0069
+:1034C0002DE9F04F8BB00D46DDF8509014469B4629
+:1034D0008046002800F01981B9F1000F00F0158135
+:1034E000531E3F2B00F21181012A03D1BBF1000FC3
+:1034F00040F00B810023CDE90833B8F81430B5EB68
+:10350000C30F4FEAC30703D300200BB0BDE8F08F11
+:103510002B199F42D8F80C303ABF7F1BFFB22746C9
+:103520001BB9D8F81030002B7AD0272D4ED8C5F112
+:103530002806B7424FF000032CBFF6B23E46009378
+:103540002946D8F8080008AB3246FFF741FCA7EB44
+:10355000060A35445FFA8AFAB8F8143003F10053CA
+:10356000053BDB000493D8F80C3003932821039B20
+:1035700013B1BAF1000F2CD1D8F8100040B1BAF154
+:10358000000F05D0009608AB5246691AFFF720FCE1
+:1035900038B2002FB8D066070AD00AAB03EBD401CB
+:1035A000624211F8083C02F00702134101F8083C9E
+:1035B000082C3CD9102C40F2B580202C40F2B7806A
+:1035C000BBF1000F00F09C80082334E0BA460026CF
+:1035D000C2E7049BE02B28BFE02306930B44AB42D9
+:1035E000059314D95A1B03980096924534BF52464E
+:1035F000D2B2691A08AB04300792FFF7E9FB079AC9
+:103600001644AAEB020A1544F6B25FFA8AFA049B42
+:10361000069A05999B1A0493039B1B680393A6E7DC
+:103620000093D8F8080008AB3A462946AEE7BBF14C
+:10363000000F13D00123B4EBC30F6CD0082C12D8A9
+:103640009DF82030621E23FA02F2D50706D54FF00E
+:10365000FF3202FA04F423438DF820309DF8203025
+:1036600089F8003051E7102C12D8BDF82030621EC6
+:1036700023FA02F2D10706D54FF0FF3202FA04F422
+:103680002343ADF82030BDF82030A9F800303CE7E6
+:10369000202C0FD80899631E21FA03F3DA0705D509
+:1036A0004FF0FF3202FA04F40C430894089BC9F867
+:1036B00000302AE7402C2BD0DDE90865611EC4F1FB
+:1036C0002102A4F1210326FA01F105FA02F225FAFA
+:1036D00003F311431943CB0712D50122A4F12003B0
+:1036E000C4F1200102FA03F322FA01F1A24052428E
+:1036F00043EA010363EB430332432B43CDE9082341
+:10370000DDE90823C9E90023FFE66FF00100FCE6CC
+:103710006FF00800F9E6082CA0D9102CB3D9202CA2
+:10372000EED8C3E7BBF1000FADD0022383E7BBF1B6
+:10373000000FBBD004237EE730B5012A144638BF02
+:103740000124402C85B028BF40240025012ACDE962
+:10375000025518D81B788DF8083063070AD004ABDF
+:1037600003EBD405624215F8083C02F007029340CF
+:1037700005F8083C009103462246002102A8FFF705
+:1037800027FB05B030BD082AE4D9102A03D81B88CE
+:10379000ADF80830E1E7202A8DBFD3E900231B688C
+:1037A0000293CDE90223D8E710B5CB681BB98B6033
+:1037B0000B618B8210BD04691A681C600361C38AA7
+:1037C000013BC382CA60F0E72DE9F04F93B0CDE929
+:1037D00003230B6804460D461806C3F3C01147BF08
+:1037E000C3F3C03BC3F306264FF0020B0E46002B7B
+:1037F00080F2FF8113F0C04940F0FB812A7B002A50
+:1038000000F0F781BBF1020F03D02078B04240F006
+:10381000F381C3F30460079003F07F00059059B370
+:10382000C3F3074A2A44059B92F80380760646EACA
+:103830000B4646EA834600220023CDE908235FEACF
+:10384000D81346EA0A0602936AD0059B009367687C
+:103850005B46524608A92046B847002800F0CF81B1
+:10386000276A87B9314604F10C00FFF715FB0746BC
+:10387000C8B96FF0020057E0C3F30F2A590608BF1A
+:103880000AF0030ACEE73B699E420DD03F68002F45
+:10389000F9D1314604F10C00FFF7FEFA0746002883
+:1038A000E7D0236A3B602762FE7D08F01F03C6F362
+:1038B0008406F01A1FFA80FC0028B8BF0CF1200023
+:1038C000D7E902210693A3EB06031FFA83FCB8BFD6
+:1038D00000B2002BBCBF0CF120031BB252EA010660
+:1038E00036D0039EDFF8D4C2B21A049E66EB010103
+:1038F0000026944576EB010C2AD395F80DE097F855
+:103900001AC0E64518D1029E002E79D001281FDC8E
+:103910007868E8B9A84E964270EB010216D337E0FA
+:10392000276A27B96FF00C0013B0BDE8F08F3B6930
+:103930009E42B9D03F68F4E79F48904276EB01027F
+:1039400001D30020F0E7029A002AFAD00F2B18DCEE
+:10395000FA7D4FEA880302F0030203F07C0313436D
+:10396000FB7539462046FFF717FB6B7BBB76029B46
+:103970003BB9FB7DC3F38402013262F38603FB751E
+:10398000D0E76A7BBB7E9A42DBD1029B002B37D00B
+:103990004FEA9813022B33D0039BBB60049BFB6060
+:1039A000142200210DA8FDF78BFF039B0A93049BB3
+:1039B0000B932B1D0C932B7BADF83EA0013BDBB290
+:1039C000ADF83C30069B8DF84130079B8DF84230B6
+:1039D000059B8DF8433094F82C308DF840B083F07F
+:1039E00001038DF844300AA9A36820469847FB7D5F
+:1039F000C3F38403013303F01F039B02FB82A0E7A0
+:103A0000FB7DC8F34012B2EBD31F40F0FB80069A57
+:103A1000C3F38403934240F0F88002992B7B4FEA72
+:103A2000981200294DD0D2075DD4032B40F2F080CC
+:103A3000039BBB60049BFB602B7BAE1D033BDBB297
+:103A40003246394604F10C00FFF7B8FA00280CDAC8
+:103A500039462046FFF7A0FAFB7DC3F38403013308
+:103A600003F01F039B02FB8203E7DDE90884AB88B8
+:103A70003B834FF6FF73C9F12000A9F1200228FA19
+:103A800009F104FA00F0014324FA02F21143184646
+:103A9000C9B2FFF7D5F909F10809B9F1400F03469A
+:103AA000E9D1B8822A7B033AD2B23146FFF7DAF97C
+:103AB000FB7DB882DA43C2F3C01262F3C713FB7511
+:103AC0003FE782B92E1D013BDBB23246394604F195
+:103AD0000C00FFF773FA0028BADB2A7BB88A013A98
+:103AE000D2B23146E2E7F98AC1F30901013B042968
+:103AF000DAB25CD8281D002307F11B069A4208D9C8
+:103B000010F801CB06F801C0013101330529DBB201
+:103B1000F4D103990A9104990B91934207F11B0187
+:103B20000C9138BF043379680D9134BF55FA83F393
+:103B300000230E93FB8AADF83EA0C3F309031A4499
+:103B4000069B8DF84130079B8DF84230059B8DF820
+:103B5000433094F82C30ADF83C2083F001038DF80D
+:103B6000443000238DF840B07B602A7BB88A013A4C
+:103B7000291DFFF777F93B8BB882834203D1A368F5
+:103B80000AA92046984720460AA9FFF70DFEFB7DAB
+:103B9000BA8AC3F38403013303F01F039B02FB8241
+:103BA0003B8B9A420CBF00206FF01000BCE67B6894
+:103BB000002BAED0052005E040420F0080841E009F
+:103BC0001C3033461E68002EFAD1091A081D2E1D1E
+:103BD000184401EB090CBCF11B0F5FFA89F398D86C
+:103BE0009A4296D916F8013B00F8013B09F1010908
+:103BF000EFE76FF0090097E66FF00A0094E66FF0C8
+:103C00000B0091E66FF00D008EE66FF00E008BE674
+:103C10006FF00F0088E600BFEFF3098305494A6B98
+:103C200022F001024A63683383F30988002383F397
+:103C30001188704700EF00E0302080F3118862B6F1
+:103C40000C4B0D4AD96821F4E0610904090C0A43C0
+:103C5000DA60D3F8FC20094942F08072C3F8FC20F6
+:103C60000A6842F001020A602022DA7783F8220013
+:103C7000704700BF00ED00E00003FA05001000E00F
+:103C800010B5302383F311880E4B5B6813F4006387
+:103C900014D0F1EE103AEFF30984683C4FF08073D2
+:103CA000E361094BDB6B236684F3098800F078FB42
+:103CB00010B1064BA36110BD054BFBE783F31188E0
+:103CC000F9E700BF00ED00E000EF00E04306000868
+:103CD00046060008026843681143016003B11847B3
+:103CE00070470000024A136843F0C0031360704736
+:103CF0000038014013B50E4C204600F0B7FA04F12D
+:103D000014000C49009400234FF4807200F074F901
+:103D1000094B0A4900944FF4807204F1380000F016
+:103D2000EDF9074A074BC4E9172302B010BD00BFE5
+:103D3000EC4A0020584B0020E53C0008584C00207D
+:103D400000380140007A030A30B5037C234C002977
+:103D500018BF0C46012B0FD1214B98420CD1214B9F
+:103D60001A6E42F480421A66D3F8802042F48042F0
+:103D7000C3F88020D3F880302268036EC16D84665A
+:103D800003EB5203B3FBF2F36268150442BF23F066
+:103D9000070503F0070343EA4503CB60A36843F03C
+:103DA00040034B60E36843F001038B6042F4967379
+:103DB00043F001030B604FF0FF330B62510505D553
+:103DC00012F0102205D0B2F1805F04D080F8643088
+:103DD00030BD7F23FAE73F23F8E700BF20530008F8
+:103DE000EC4A0020001002402DE9F047C66D37680C
+:103DF000F46934622107054619D014F0080118BF90
+:103E00004FF48071E20748BF41F02001A30748BF8B
+:103E100041F04001600748BF41F08001302383F347
+:103E20001188281DFFF756FF002383F31188E20550
+:103E30000AD5302383F311884FF48061281DFFF7E2
+:103E400049FF002383F311884FF030094FF0000A37
+:103E500014F0200838D13B0616D54FF0300905F193
+:103E6000380A200610D589F31188504600F07AF9F7
+:103E7000002836DA0821281DFFF72CFF27F08003E1
+:103E80003360002383F31188790614D5620612D5B6
+:103E9000302383F31188D5E913239A4208D12B6C80
+:103EA00033B11021281D27F04007FFF713FF3760BB
+:103EB000002383F31188E30618D5AA6E1369ABB10A
+:103EC000BDE8F0475069184789F31188736A95F87F
+:103ED00064102846194000F0E3F98AF31188F46968
+:103EE000B6E7B06288F31188F469BAE7BDE8F087F5
+:103EF0004FF0E023002258684FF0FF31930003F1A8
+:103F0000604303F5614301329042C3F88010C3F867
+:103F10008011F3D27047000000F1604303F5614364
+:103F20000901C9B283F80013012200F01F039A406F
+:103F300043099B0003F1604303F56143C3F880210B
+:103F40001A607047F8B5154682680669AA420B46A2
+:103F5000816938BF8568761AB54204460BD2184687
+:103F60002A46FDF79BFCA3692B44A361A3685B1B56
+:103F7000A3602846F8BD0CD918463246FDF78EFCE2
+:103F8000AF1BE1683A463044FDF788FCE3683B44E8
+:103F9000EBE718462A46FDF781FCE368E5E70000F9
+:103FA00083689342F7B51546044638BF8568D0E963
+:103FB0000460361AB5420BD22A46FDF76FFC6369DE
+:103FC0002B446361A36828465B1BA36003B0F0BD6C
+:103FD0000DD932460191FDF761FC0199E068AF1BF4
+:103FE0003A463144FDF75AFCE3683B44E9E72A4688
+:103FF000FDF754FCE368E4E710B50A440024C3610C
+:10400000029B8460C0E90000C0E90511C160026143
+:10401000036210BD08B5D0E90532934201D1826830
+:1040200082B98268013282605A1C42611970D0E9FB
+:1040300004329A4224BFC3684361002100F078FA39
+:10404000002008BD4FF0FF30FBE7000070B53023C3
+:1040500004460E4683F31188A568A5B1A368A2693A
+:10406000013BA360531CA36115782269934224BFCE
+:10407000E368A361E3690BB120469847002383F30B
+:104080001188284607E03146204600F041FA002812
+:10409000E2DA85F3118870BD2DE9F74F04460E462C
+:1040A00017469846D0F81C904FF0300A8AF31188D2
+:1040B0004FF0000B154665B12A4631462046FFF702
+:1040C00041FF034660B94146204600F021FA00282E
+:1040D000F1D0002383F31188781B03B0BDE8F08F83
+:1040E000B9F1000F03D001902046C847019B8BF324
+:1040F0001188ED1A1E448AF31188DCE7C0E9051126
+:10410000C160C3611144009B8260C0E9000001618D
+:1041100003627047F8B504460D461646302383F314
+:104120001188A768A7B1A368013BA36063695A1C03
+:1041300062611D70D4E904329A4224BFE36863616E
+:10414000E3690BB120469847002080F3118807E00F
+:104150003146204600F0DCF90028E2DA87F31188C6
+:10416000F8BD0000D0E905239A4210B501D182685C
+:104170007AB98268013282605A1C82611C780369B4
+:104180009A4224BFC3688361002100F0D1F9204620
+:1041900010BD4FF0FF30FBE72DE9F74F04460E4608
+:1041A00017469846D0F81C904FF0300A8AF31188D1
+:1041B0004FF0000B154665B12A4631462046FFF701
+:1041C000EFFE034660B94146204600F0A1F9002801
+:1041D000F1D0002383F31188781B03B0BDE8F08F82
+:1041E000B9F1000F03D001902046C847019B8BF323
+:1041F0001188ED1A1E448AF31188DCE702684368CF
+:104200001143016003B11847704700001430FFF7F5
+:1042100043BF00004FF0FF331430FFF73DBF0000F5
+:104220003830FFF7B9BF00004FF0FF333830FFF7E9
+:10423000B3BF00001430FFF709BF00004FF0FF319B
+:104240001430FFF703BF00003830FFF763BF0000F2
+:104250004FF0FF323830FFF75DBF0000012914BF77
+:104260006FF0130000207047FFF744BD044B03605C
+:104270000023C0E90233436001230374704700BF89
+:104280003853000810B53023044683F31188FFF734
+:104290005BFD02232374002080F3118810BD000011
+:1042A00038B5C36904460D461BB904210844FFF71D
+:1042B000A5FF294604F11400FFF7ACFE002806DA3A
+:1042C000201D4FF40061BDE83840FFF797BF38BDAF
+:1042D00000230375826803691B6899689142FBD2C9
+:1042E0005A6803604260106058607047002303758D
+:1042F000826803691B6899689142FBD85A68036019
+:10430000426010605860704708B50846302383F358
+:1043100011880B7D032B05D0042B0DD02BB983F313
+:10432000118808BD8B6900221A604FF0FF3383614A
+:10433000FFF7CEFF0023F2E7D1E9003213605A60A5
+:10434000F3E70000FFF7C4BF054BD968087518688C
+:1043500002681A60536001220275D860FCF75CB9EC
+:10436000584D002030B50C4BDD684B1C87B004461F
+:104370000FD02B46094A684600F06CF92046FFF73B
+:10438000E3FF009B13B1684600F06EF9A86907B01F
+:1043900030BDFFF7D9FFF9E7584D00200943000869
+:1043A000044B1A68DB6890689B68984294BF0020B1
+:1043B00001207047584D0020084B10B51C68D86884
+:1043C00022681A60536001222275DC60FFF78EFFBD
+:1043D00001462046BDE81040FCF71EB9584D0020AC
+:1043E000044B1A68DB6892689B689A4201D9FFF710
+:1043F000E3BF7047584D002038B5074C07490848BF
+:10440000012300252370656000F02EFC0223237039
+:1044100085F3118838BD00BFC04F002064530008E9
+:10442000584D002008B572B6044B186500F0E4FA48
+:1044300000F09CFB024B03221A70FEE7584D00204F
+:10444000C04F002000F046B9EFF3118020B9EFF320
+:104450000583302282F311887047000010B530B90F
+:10446000EFF30584C4F3080414B180F3118810BD80
+:10447000FFF7B6FF84F31188F9E700008B60022391
+:1044800008618B82084670478368A3F1840243F871
+:10449000142C026943F8442C426943F8402C094A21
+:1044A00043F8242CC26843F8182C022203F80C2C81
+:1044B000002203F80B2C044A43F8102CA3F120002F
+:1044C000704700BF31060008584D002008B5FFF7BF
+:1044D000DBFFBDE80840FFF735BF0000024BDB689B
+:1044E00098610F20FFF730BF584D0020302383F331
+:1044F0001188FFF7F3BF000008B50146302383F3AE
+:1045000011880820FFF72EFF002383F3118808BDD0
+:10451000064BDB6839B1426818605A60136043602B
+:104520000420FFF71FBF4FF0FF307047584D0020A9
+:104530000368984206D01A68026050609961184674
+:10454000FFF700BF7047000010B503689C68A242E7
+:104550000CD85C688A600B604C6021605960996877
+:104560008A1A9A604FF0FF33836010BD1B68121BDC
+:10457000ECE700000A2938BF0A2170B504460D4651
+:104580000A26601900F06AFB00F056FB041BA542E6
+:1045900003D8751C2E460446F3E70A2E04D9BDE85D
+:1045A0007040012000F0A0BB70BD0000F8B5144BB6
+:1045B0000D46D96103F1100141600A2A1969826030
+:1045C00038BF0A22016048601861A818144600F03C
+:1045D00037FB0A2700F030FB431BA342064606D3F5
+:1045E0007C1C281900F03AFB27463546F2E70A2FD3
+:1045F00004D9BDE8F840012000F076BBF8BD00BF4B
+:10460000584D0020F8B506460D4600F015FB0F4A40
+:10461000134653F8107F9F4206D12A460146304682
+:10462000BDE8F840FFF7C2BFD169BB68441A2C1936
+:1046300028BF2C46A34202D92946FFF79BFF2246FA
+:1046400031460348BDE8F840FFF77EBF584D0020D3
+:10465000684D002010B4C0E9032300235DF8044B2B
+:104660004361FFF7CFBF000010B5194C2369984292
+:104670000DD0D0E90032816813605A609A680A440C
+:104680009A60002303604FF0FF33A36110BD2346FF
+:10469000026843F8102F53600022026022699A4298
+:1046A00003D1BDE8104000F0D3BA936881680B4491
+:1046B000936000F0C1FA2269E1699268441AA2424B
+:1046C000E4D91144BDE81040091AFFF753BF00BFF9
+:1046D000584D00202DE9F047DFF8BC8008F11007A5
+:1046E0002C4ED8F8105000F0A7FAD8F81C40AA6851
+:1046F000031B9A423ED81444D5E900324FF000091A
+:10470000C8F81C4013605A60C5F80090D8F8103003
+:10471000B34201D100F09CFA89F31188D5E9033145
+:1047200028469847302383F311886B69002BD8D033
+:1047300000F082FA6A69A0EB04094A4582460DD26C
+:10474000022000F0D1FA0022D8F81030B34208D18C
+:1047500051462846BDE8F047FFF728BF121A224409
+:10476000F2E712EB090938BF4A4629463846FFF7F7
+:10477000EBFEB5E7D8F81030B34208D01444211A44
+:10478000C8F81C00A960BDE8F047FFF7F3BEBDE81C
+:10479000F08700BF684D0020584D00200020704772
+:1047A000FEE70000704700004FF0FF307047000048
+:1047B000BFF34F8F024A1369DB03FCD4704700BF7D
+:1047C0000020024008B5094B1B7873B9FFF7F0FFD2
+:1047D000074B5A69002ABFBF064A9A6002F1883225
+:1047E0009A601A6822F480621A6008BDD84F0020CF
+:1047F000002002402301674508B50B4B1B7893B995
+:10480000FFF7D6FF094B5A6942F000425A611A6815
+:1048100042F480521A601A6822F480521A601A68B0
+:1048200042F480621A6008BDD84F00200020024088
+:104830007F289ABF00F58030C0020020704700003A
+:104840004FF4006070470000802070477F2808B553
+:104850000BD8FFF7EDFF00F500630268013204D1C9
+:1048600004308342F9D1012008BD0020FCE700009C
+:104870007F2838B5044626D8FFF7E6FDFFF798FFF6
+:10488000FFF7A0FF114BF3221A6102225A615A6905
+:1048900042EAC4025A615A6942F480325A610546BA
+:1048A0002046FFF785FF4FF40061FFF7C1FF00F0DE
+:1048B00059F92846FFF7A0FFFFF7D0FD2046BDE8D5
+:1048C0003840FFF7C3BF002038BD00BF00200240C2
+:1048D00040EA020313F007032DE9F04705460C46B2
+:1048E000164606D0344B40F231321A600020BDE843
+:1048F000F0878118314A91420CD92F4A40F2363163
+:104900001160F3E72B1D1B686268934208D1083ED3
+:1049100008350834072E19D92A6823689A42F1D03D
+:10492000FFF792FDFFF74EFFFFF742FF04F108018A
+:10493000234C4FF001084FF00009012EA1F10807A8
+:1049400008D8FFF759FFFFF789FD01E0002EE7D1F6
+:104950000120CCE7C4F81480AA4651F8083C4AF874
+:10496000043B51F8043C6B60FFF722FF236943F0DE
+:1049700001032361C4F814902A6851F8083C9A4254
+:104980000ED00D4B40F25E321A600E4B1D600E4B86
+:104990001E600E4B1F60FFF72FFFFFF75FFDA5E7BF
+:1049A000DAF800A051F8043C9A4501F10801E8D179
+:1049B000083E0835C1E700BFD44F002000000408BE
+:1049C00000200240C84F0020D04F0020CC4F0020D4
+:1049D000084908B50B7828B11BB9FFF7F3FE01238E
+:1049E0000B7008BD002BFCD0BDE808400870FFF735
+:1049F00003BF00BFD84F002008B54FF4C0314FF0BF
+:104A0000005000F0B1F8BDE808404FF480414FF08D
+:104A1000805000F0A9B80000084600F0F3BB000089
+:104A200070B582B0FFF710FD0E4E054600F004F998
+:104A30003268904237BF0C4A0B49516814682EBF48
+:104A4000D1E90041013151600419034641F10001EF
+:104A5000284601913360FFF701FD0199204602B01D
+:104A600070BD00BFDC4F0020E04F002070B582B069
+:104A7000FFF7EAFC104E054600F0DEF8326890427F
+:104A800037BF0E4A0D49516814682EBFD1E9004165
+:104A900001315160041941F100010346284601919A
+:104AA0003360FFF7DBFC01994FF47A720023204654
+:104AB000FBF79EFB02B070BDDC4F0020E04F0020F2
+:104AC0000244D2B2904200D17047431C800000F1F2
+:104AD000804000F51450006841F8040BD8B2F1E7AB
+:104AE000124B10B5D3F89040240409D4D3F8904069
+:104AF000C3F89040D3F8904044F40044C3F8904089
+:104B00000B4C2368024443F480732360D2B290427A
+:104B100000D110BD431C800000F1804000F514500E
+:104B200051F8044B0460D8B2F1E700BF0010024016
+:104B30000070004007B5012201A90020FFF7C0FF67
+:104B4000019803B05DF804FB13B50446FFF7F2FFCC
+:104B5000A04205D0012201A900200194FFF7C0FF67
+:104B600002B010BD704700007047000070470000A1
+:104B7000074B45F255521A6002225A6040F6FF7206
+:104B80009A604CF6CC421A60024B01221A707047B0
+:104B900000300040EC4F0020034B1B781BB1034B4F
+:104BA0004AF6AA221A607047EC4F002000300040FD
+:104BB000054B1A6832B902F1804202F50432D2F88C
+:104BC00094201A60704700BFE84F0020024B4FF45A
+:104BD0000002C3F8942070470010024008B5FFF7A8
+:104BE000E7FF024B1868C0F3407008BDE84F002093
+:104BF00070470000FEE700000A4B0B480B4A90424A
+:104C00000BD30B4BDA1C121AC11E22F003028B428B
+:104C100038BF00220021FCF753BE53F8041B40F8B4
+:104C2000041BECE7D45400087050002070500020A2
+:104C30007050002000F0C2B84FF08043586A7047AF
+:104C40004FF08043002258631A610222DA607047F5
+:104C50004FF080430022DA60704700004FF080433D
+:104C600058637047FEE7000070B51B4B01630025D9
+:104C7000044686B0586085620E46FEF7DDFF04F1FB
+:104C80001003C4E904334FF0FF33C4E90635C4E927
+:104C90000044A560E562FFF7CFFF2B460246C4E95A
+:104CA000082304F134010D4A256580232046FFF7CF
+:104CB000E5FB0123E0600A4A0375009272680192E5
+:104CC000B268CDE90223074B6846CDE90435FFF70A
+:104CD000FDFB06B070BD00BFC04F00207053000840
+:104CE00075530008654C0008024AD36A1843D06225
+:104CF000704700BF584D00204B6843608B6883604D
+:104D0000CB68C3600B6943614B6903628B69436283
+:104D10000B6803607047000008B5204BDA6A42F068
+:104D20007F02DA62DA6A22F07F02DA62DA6ADA6C29
+:104D300042F07F02DA64DA6E42F07F02DA66184AE5
+:104D4000DB6E11464FF09040FFF7D6FF02F11C01D9
+:104D500000F58060FFF7D0FF02F1380100F58060B8
+:104D6000FFF7CAFF02F1540100F58060FFF7C4FFAE
+:104D700002F1700100F58060FFF7BEFF02F18C01C7
+:104D800000F58060FFF7B8FF02F1A80100F5806030
+:104D9000FFF7B2FFBDE8084000F050B80010024035
+:104DA0007C53000808B500F0FBF9FFF725FBBDE8D0
+:104DB0000840FFF7FDBE0000704700000F4B9A6DE2
+:104DC00042F001029A659A6F42F001029A670C4A1A
+:104DD0009B6F936843F0010393604FF08043A722D9
+:104DE0009A624FF0FF32DA6200229A615A63DA6007
+:104DF0005A6001225A611A60704700BF00100240D9
+:104E0000002004E04FF0804208B51169D3680B40E0
+:104E1000D9B2C9439B07116107D5302383F31188A9
+:104E2000FFF710FB002383F3118808BD08B5FFF7D7
+:104E30005FF8BDE8084000F08BB900004E4B4FF022
+:104E4000FF319A6A99629A6A00229A62986AD86ACD
+:104E500060F07F00D862D86A00F07F00D862D86A1C
+:104E6000186B1963186B1A63186B986B9963986BBE
+:104E70009A63986BD86BD963D86BDA63D86B186C6C
+:104E80001964196C1A64196C196E41F001011966E4
+:104E9000D3F8801021F00101C3F88010D3F88010FE
+:104EA000996D41F080519965996F21F08051996712
+:104EB000996F32494FF400408860CA600A624A62C2
+:104EC0008A62CA620A634A638A63CA630A644A647A
+:104ED0008A64CA640A654A654A604FF48072C1F800
+:104EE00080204FF440720A604A6912F48062FBD15C
+:104EF000D3F8901011F4407F1EBF4FF48031C3F8F7
+:104F00009010C3F89020D3F8982042F00102C3F823
+:104F10009820D3F898209207FBD51A6842F4803283
+:104F20001A601A689003FCD5D3F8902022F003226F
+:104F3000C3F89020124ADA601A6842F080721A6050
+:104F40001A689101FCD50F490F4800229A60C3F8F6
+:104F500088100E49C3F89C20016002684A4012077D
+:104F6000FBD19A6842F003029A609A6802F00C0240
+:104F70000C2AFAD1704700BF0010024000700040B8
+:104F8000032A61015501005000200240040704007B
+:104F9000074A08B5536903F00103536123B1054A79
+:104FA00013680BB150689847BDE80840FEF768BE2B
+:104FB00000040140F04F0020074A08B5536903F090
+:104FC0000203536123B1054A93680BB1D068984737
+:104FD000BDE80840FEF754BE00040140F04F002039
+:104FE000074A08B5536903F00403536123B1054A26
+:104FF00013690BB150699847BDE80840FEF740BE01
+:1050000000040140F04F0020074A08B5536903F03F
+:105010000803536123B1054A93690BB1D0699847DE
+:10502000BDE80840FEF72CBE00040140F04F002010
+:10503000074A08B5536903F01003536123B1054AC9
+:10504000136A0BB1506A9847BDE80840FEF718BED6
+:1050500000040140F04F0020164B10B55C6904F4C9
+:1050600078725A61A30604D5134A936A0BB1D06AC9
+:105070009847600604D5104A136B0BB1506B9847E4
+:10508000210604D50C4A936B0BB1D06B9847E2050F
+:1050900004D5094A136C0BB1506C9847A30504D58D
+:1050A000054A936C0BB1D06C9847BDE81040FEF7F1
+:1050B000E7BD00BF00040140F04F0020194B10B5C0
+:1050C0005C6904F47C425A61620504D5164A136D8A
+:1050D0000BB1506D9847230504D5134A936D0BB15E
+:1050E000D06D9847E00404D50F4A136E0BB1506E93
+:1050F0009847A10404D50C4A936E0BB1D06E984723
+:10510000620404D5084A136F0BB1506F984723040B
+:1051100004D5054A936F0BB1D06F9847BDE8104096
+:10512000FEF7AEBD00040140F04F002008B5034873
+:10513000FEF75AFEBDE80840FEF7A2BDEC4A00208B
+:1051400008B5FFF75FFEBDE80840FEF799BD000017
+:10515000062108B50846FEF7DFFE06210720FEF708
+:10516000DBFE06210820FEF7D7FE06210920FEF708
+:10517000D3FE06210A20FEF7CFFE06211720FEF7F8
+:10518000CBFE06212820FEF7C7FE07211C20FEF7D4
+:10519000C3FEBDE808400C212520FEF7BDBE00007F
+:1051A00008B5FFF743FE00F009F8FFF75DF8FFF7D9
+:1051B00003FEBDE80840FFF73DBD00000023054A9F
+:1051C00019460133102BC2E9001102F10802F8D18F
+:1051D000704700BFF04F00200B460146184600F014
+:1051E00003B8000000F00EB810B5054C13462CB102
+:1051F0000A4601460220AFF3008010BD2046FCE7BE
+:1052000000000000024B01461868FFF705BC00BF14
+:105210002823002010B501390244904201D100201A
+:1052200005E0037811F8014FA34201D0181B10BD0F
+:105230000130F2E72DE9F041A3B1C91A1778014412
+:10524000044603F1FF3C8C42204601D9002009E0CE
+:105250000578BD4204F10104F5D10CEB0405D61824
+:10526000A54201D1BDE8F08115F8018D16F801EDD8
+:10527000F045F5D0E7E70000034611F8012B03F8ED
+:10528000012B002AF9D170476F72672E6172647525
+:1052900070696C6F742E6D526F2D4D313030393511
+:1052A0000000000053544D333247343F3F000000AC
+:1052B00040A2E4F1646891060041A3E5F2656992B9
+:1052C000070000004261642043414E496661636506
+:1052D00020696E6465782E00000000000000000068
+:1052E00061240008691F0008292B0008611F0008BD
+:1052F00011200008F5210008D91F0008A11F00088F
+:10530000A51F00087D1F0008651F0008B5210008C3
+:10531000891F0008652C0008951F000889210008D6
+:1053200000960000000000000000000000000000E7
+:1053300000000000000000000000000029420008FA
+:1053400015420008514200083D4200084942000849
+:1053500035420008214200080D4200085D42000865
+:105360006330000060530008B04D0020C04F0020A3
+:105370006D61696E0069646C650000000001A82A17
+:1053800000000000AAAABEAA00001424EFFF00003B
+:1053900000000000709709000000000000000000FD
+:1053A000AAAAAAAA00000000FFFF00000000000057
+:1053B000000000000000000000000000AAAAAAAA45
+:1053C00000000000FFFF00000000000000000000DF
+:1053D0000000000000000000AAAAAAAA0000000025
+:1053E000FFFF0000000000000000000000000000BF
+:1053F00000000000AAAAAAAA00000000FFFF000007
+:10540000000000000000000000000000000000009C
+:10541000AAAAAAAA00000000FFFF000000000000E6
+:10542000000000000000000000000000AAAAAAAAD4
+:1054300000000000FFFF000000000000000000006E
+:10544000E0ADFF7F0100000011040000000000003B
+:105450000088030000000000FE2A0100D2040000C2
+:10546000FF000000EC4A002000000000A4520008E9
+:105470002C230020000000000000000000000000BD
+:10548000000000000000000000000000000000001C
+:10549000000000000000000000000000000000000C
+:1054A00000000000000000000000000000000000FC
+:1054B00000000000000000000000000000000000EC
+:1054C00000000000000000000000000000000000DC
+:0454D00000000000D8
:00000001FF
diff --git a/Tools/bootloaders/mRoCANPWM-M10126_bl.bin b/Tools/bootloaders/mRoCANPWM-M10126_bl.bin
old mode 100644
new mode 100755
index 9605069230da23..b72acfa80dde18
Binary files a/Tools/bootloaders/mRoCANPWM-M10126_bl.bin and b/Tools/bootloaders/mRoCANPWM-M10126_bl.bin differ
diff --git a/Tools/bootloaders/mRoControlZeroClassic_bl.bin b/Tools/bootloaders/mRoControlZeroClassic_bl.bin
new file mode 100755
index 00000000000000..76a2270389542d
Binary files /dev/null and b/Tools/bootloaders/mRoControlZeroClassic_bl.bin differ
diff --git a/Tools/bootloaders/mRoControlZeroH7_bl.bin b/Tools/bootloaders/mRoControlZeroH7_bl.bin
new file mode 100755
index 00000000000000..813c5a3a031bba
Binary files /dev/null and b/Tools/bootloaders/mRoControlZeroH7_bl.bin differ
diff --git a/Tools/bootloaders/rGNSS_bl.bin b/Tools/bootloaders/rGNSS_bl.bin
index e8e2f53d26e7b0..ac8843e0e3b027 100755
Binary files a/Tools/bootloaders/rGNSS_bl.bin and b/Tools/bootloaders/rGNSS_bl.bin differ
diff --git a/Tools/environment_install/install-prereqs-arch.sh b/Tools/environment_install/install-prereqs-arch.sh
index 2681c38d9f32c5..d135cd6ac32973 100755
--- a/Tools/environment_install/install-prereqs-arch.sh
+++ b/Tools/environment_install/install-prereqs-arch.sh
@@ -50,10 +50,25 @@ function maybe_prompt_user() {
fi
}
-sudo usermod -a -G uucp $USER
+sudo usermod -a -G uucp "$USER"
sudo pacman -Sy --noconfirm --needed $BASE_PKGS $SITL_PKGS $PX4_PKGS
-pip3 -q install --user -U $PYTHON_PKGS
+
+python3 -m venv "$HOME"/venv-ardupilot
+
+# activate it:
+SOURCE_LINE="source $HOME/venv-ardupilot/bin/activate"
+$SOURCE_LINE
+
+if [[ -z "${DO_PYTHON_VENV_ENV}" ]] && maybe_prompt_user "Make ArduPilot venv default for python [N/y]?" ; then
+ DO_PYTHON_VENV_ENV=1
+fi
+
+if [[ $DO_PYTHON_VENV_ENV -eq 1 ]]; then
+ echo "$SOURCE_LINE" >> ~/.bashrc
+fi
+
+pip3 -q install -U $PYTHON_PKGS
(
cd /usr/lib/ccache
@@ -78,7 +93,7 @@ exportline="export PATH=$OPT/$ARM_ROOT/bin:\$PATH";
if ! grep -Fxq "$exportline" ~/.bashrc ; then
if maybe_prompt_user "Add $OPT/$ARM_ROOT/bin to your PATH [N/y]?" ; then
echo "$exportline" >> ~/.bashrc
- . ~/.bashrc
+ . "$HOME/.bashrc"
else
echo "Skipping adding $OPT/$ARM_ROOT/bin to PATH."
fi
@@ -88,7 +103,7 @@ exportline2="export PATH=$CWD/$ARDUPILOT_TOOLS:\$PATH";
if ! grep -Fxq "$exportline2" ~/.bashrc ; then
if maybe_prompt_user "Add $CWD/$ARDUPILOT_TOOLS to your PATH [N/y]?" ; then
echo "$exportline2" >> ~/.bashrc
- . ~/.bashrc
+ . "$HOME/.bashrc"
else
echo "Skipping adding $CWD/$ARDUPILOT_TOOLS to PATH."
fi
@@ -96,7 +111,7 @@ fi
SCRIPT_DIR=$(dirname $(realpath ${BASH_SOURCE[0]}))
(
- cd $SCRIPT_DIR
+ cd "$SCRIPT_DIR"
git submodule update --init --recursive
)
diff --git a/Tools/environment_install/install-prereqs-ubuntu.sh b/Tools/environment_install/install-prereqs-ubuntu.sh
index ffa3b37df38f5e..eea1db11fcb603 100755
--- a/Tools/environment_install/install-prereqs-ubuntu.sh
+++ b/Tools/environment_install/install-prereqs-ubuntu.sh
@@ -82,13 +82,13 @@ PIP=pip3
if [ ${RELEASE_CODENAME} == 'bionic' ] ; then
SITLFML_VERSION="2.4"
SITLCFML_VERSION="2.4"
- PYTHON_V="python"
- PIP=pip2
+ PYTHON_V="python3"
+ PIP=pip3
elif [ ${RELEASE_CODENAME} == 'buster' ]; then
SITLFML_VERSION="2.5"
SITLCFML_VERSION="2.5"
- PYTHON_V="python"
- PIP=pip2
+ PYTHON_V="python3"
+ PIP=pip3
elif [ ${RELEASE_CODENAME} == 'focal' ]; then
SITLFML_VERSION="2.5"
SITLCFML_VERSION="2.5"
@@ -99,6 +99,11 @@ elif [ ${RELEASE_CODENAME} == 'jammy' ]; then
SITLCFML_VERSION="2.5"
PYTHON_V="python3"
PIP=pip3
+elif [ ${RELEASE_CODENAME} == 'lunar' ]; then
+ SITLFML_VERSION="2.5"
+ SITLCFML_VERSION="2.5"
+ PYTHON_V="python3"
+ PIP=pip3
elif [ ${RELEASE_CODENAME} == 'groovy' ] ||
[ ${RELEASE_CODENAME} == 'bullseye' ]; then
SITLFML_VERSION="2.5"
@@ -141,28 +146,33 @@ else
fi
# Lists of packages to install
-BASE_PKGS="build-essential ccache g++ gawk git make wget"
-if [ ${RELEASE_CODENAME} == 'bionic' ]; then
- # use fixed version for package that drop python2 support
- PYTHON_PKGS="future lxml pymavlink MAVProxy pexpect flake8==3.7.9 requests==2.27.1 monotonic==1.6 geocoder empy configparser==4.0.2 click==7.1.2 decorator==4.4.2 dronecan"
-else
- PYTHON_PKGS="future lxml pymavlink MAVProxy pexpect flake8 geocoder empy dronecan"
-fi
+BASE_PKGS="build-essential ccache g++ gawk git make wget valgrind screen"
+PYTHON_PKGS="future lxml pymavlink pyserial MAVProxy pexpect geocoder empy ptyprocess dronecan"
+PYTHON_PKGS="$PYTHON_PKGS flake8"
# add some Python packages required for commonly-used MAVProxy modules and hex file generation:
if [[ $SKIP_AP_EXT_ENV -ne 1 ]]; then
- if [ ${RELEASE_CODENAME} == 'bionic' ]; then
- PYTHON_PKGS="$PYTHON_PKGS pygame==2.0.3 intelhex"
- else
- PYTHON_PKGS="$PYTHON_PKGS pygame intelhex"
- fi
+ PYTHON_PKGS="$PYTHON_PKGS pygame intelhex"
fi
ARM_LINUX_PKGS="g++-arm-linux-gnueabihf $INSTALL_PKG_CONFIG"
# python-wxgtk packages are added to SITL_PKGS below
+
+if [ ${RELEASE_CODENAME} == 'lunar' ]; then
+ # on Lunar (and presumably later releases), we install in venv, below
+ PYTHON_PKGS+=" numpy pyparsing psutil"
+ SITL_PKGS="python3-dev"
+else
SITL_PKGS="libtool libxml2-dev libxslt1-dev ${PYTHON_V}-dev ${PYTHON_V}-pip ${PYTHON_V}-setuptools ${PYTHON_V}-numpy ${PYTHON_V}-pyparsing ${PYTHON_V}-psutil"
+fi
+
# add some packages required for commonly-used MAVProxy modules:
if [[ $SKIP_AP_GRAPHIC_ENV -ne 1 ]]; then
+ if [ ${RELEASE_CODENAME} == 'lunar' ]; then
+ PYTHON_PKGS+=" matplotlib scipy opencv-python pyyaml"
+ SITL_PKGS+=" xterm libcsfml-dev libcsfml-audio${SITLCFML_VERSION} libcsfml-dev libcsfml-graphics${SITLCFML_VERSION} libcsfml-network${SITLCFML_VERSION} libcsfml-system${SITLCFML_VERSION} libcsfml-window${SITLCFML_VERSION} libsfml-audio${SITLFML_VERSION} libsfml-dev libsfml-graphics${SITLFML_VERSION} libsfml-network${SITLFML_VERSION} libsfml-system${SITLFML_VERSION} libsfml-window${SITLFML_VERSION}"
+ else
SITL_PKGS="$SITL_PKGS xterm ${PYTHON_V}-matplotlib ${PYTHON_V}-serial ${PYTHON_V}-scipy ${PYTHON_V}-opencv libcsfml-dev libcsfml-audio${SITLCFML_VERSION} libcsfml-dev libcsfml-graphics${SITLCFML_VERSION} libcsfml-network${SITLCFML_VERSION} libcsfml-system${SITLCFML_VERSION} libcsfml-window${SITLCFML_VERSION} libsfml-audio${SITLFML_VERSION} libsfml-dev libsfml-graphics${SITLFML_VERSION} libsfml-network${SITLFML_VERSION} libsfml-system${SITLFML_VERSION} libsfml-window${SITLFML_VERSION} ${PYTHON_V}-yaml"
+ fi
fi
if [[ $SKIP_AP_COV_ENV -ne 1 ]]; then
# Coverage utilities
@@ -244,17 +254,24 @@ elif [ ${RELEASE_CODENAME} == 'groovy' ] ||
[ ${RELEASE_CODENAME} == 'jammy' ]; then
BASE_PKGS+=" python-is-python3"
SITL_PKGS+=" libpython3-stdlib" # for argparse
+elif [ ${RELEASE_CODENAME} == 'lunar' ]; then
+ SITL_PKGS+=" libpython3-stdlib" # for argparse
+elif [ ${RELEASE_CODENAME} == 'buster' ]; then
+ SITL_PKGS+=" libpython3-stdlib" # for argparse
else
SITL_PKGS+=" python-argparse"
fi
# Check for graphical package for MAVProxy
if [[ $SKIP_AP_GRAPHIC_ENV -ne 1 ]]; then
- if [ ${RELEASE_CODENAME} == 'bullseye' ]; then
+ if [ ${RELEASE_CODENAME} == 'bullseye' ] ||
+ [ ${RELEASE_CODENAME} == 'buster' ]; then
SITL_PKGS+=" libjpeg62-turbo-dev"
elif [ ${RELEASE_CODENAME} == 'groovy' ] ||
[ ${RELEASE_CODENAME} == 'focal' ]; then
SITL_PKGS+=" libjpeg8-dev"
+ elif [ ${RELEASE_CODENAME} == 'lunar' ]; then
+ SITL_PKGS+=" libgtk-3-dev libwxgtk3.2-dev "
elif apt-cache search python-wxgtk3.0 | grep wx; then
SITL_PKGS+=" python-wxgtk3.0"
elif apt-cache search python3-wxgtk4.0 | grep wx; then
@@ -265,8 +282,14 @@ if [[ $SKIP_AP_GRAPHIC_ENV -ne 1 ]]; then
SITL_PKGS+=" python-wxgtk2.8"
SITL_PKGS+=" fonts-freefont-ttf libfreetype6-dev libjpeg8-dev libpng12-0 libportmidi-dev libsdl-image1.2-dev libsdl-mixer1.2-dev libsdl-ttf2.0-dev libsdl1.2-dev" # for pygame
fi
- if [ ${RELEASE_CODENAME} == 'bullseye' ] ||
+
+ if [ ${RELEASE_CODENAME} == 'lunar' ]; then
+ PYTHON_PKGS+=" opencv-python"
+ SITL_PKGS+=" python3-wxgtk4.0"
+ SITL_PKGS+=" fonts-freefont-ttf libfreetype6-dev libpng16-16 libportmidi-dev libsdl-image1.2-dev libsdl-mixer1.2-dev libsdl-ttf2.0-dev libsdl1.2-dev" # for pygame
+ elif [ ${RELEASE_CODENAME} == 'bullseye' ] ||
[ ${RELEASE_CODENAME} == 'groovy' ] ||
+ [ ${RELEASE_CODENAME} == 'buster' ] ||
[ ${RELEASE_CODENAME} == 'focal' ] ||
[ ${RELEASE_CODENAME} == 'jammy' ]; then
SITL_PKGS+=" python3-wxgtk4.0"
@@ -288,12 +311,55 @@ fi
# Install all packages
$APT_GET install $BASE_PKGS $SITL_PKGS $PX4_PKGS $ARM_LINUX_PKGS $COVERAGE_PKGS
-# Update Pip and Setuptools on old distro
-if [ ${RELEASE_CODENAME} == 'bionic' ]; then
- # use fixed version for package that drop python2 support
- $PIP install --user -U pip==20.3 setuptools==44.0.0
+
+heading "Check if we are inside docker environment..."
+IS_DOCKER=false
+if [[ -f /.dockerenv ]] || grep -Eq '(lxc|docker)' /proc/1/cgroup ; then
+ IS_DOCKER=true
fi
-$PIP install --user -U $PYTHON_PKGS
+echo "Done!"
+
+SHELL_LOGIN=".profile"
+if $IS_DOCKER; then
+ echo "Inside docker, we add the tools path into .bashrc directly"
+ SHELL_LOGIN=".ardupilot_env"
+ echo "# ArduPilot env file. Need to be loaded by your Shell." > ~/$SHELL_LOGIN
+fi
+
+PIP_USER_ARGUMENT="--user"
+
+# create a Python venv on more recent releases:
+if [ ${RELEASE_CODENAME} == 'lunar' ]; then
+ $APT_GET install python3.11-venv
+ python3 -m venv $HOME/venv-ardupilot
+
+ # activate it:
+ SOURCE_LINE="source $HOME/venv-ardupilot/bin/activate"
+ $SOURCE_LINE
+ PIP_USER_ARGUMENT=""
+
+ if [[ -z "${DO_PYTHON_VENV_ENV}" ]] && maybe_prompt_user "Make ArduPilot venv default for python [N/y]?" ; then
+ DO_PYTHON_VENV_ENV=1
+ fi
+
+ if [[ $DO_PYTHON_VENV_ENV -eq 1 ]]; then
+ echo $SOURCE_LINE >> ~/$SHELL_LOGIN
+ fi
+fi
+
+# try update setuptools and wheel before installing pip package that may need compilation
+$PIP install $PIP_USER_ARGUMENT -U pip setuptools wheel
+
+if [ "$GITHUB_ACTIONS" == "true" ]; then
+ PIP_USER_ARGUMENT+=" --progress-bar off"
+fi
+
+if [ ${RELEASE_CODENAME} == 'lunar' ]; then
+ # must do this ahead of wxPython pip3 run :-/
+ $PIP install $PIP_USER_ARGUMENT -U attrdict3
+fi
+
+$PIP install $PIP_USER_ARGUMENT -U $PYTHON_PKGS
if [[ -z "${DO_AP_STM_ENV}" ]] && maybe_prompt_user "Install ArduPilot STM32 toolchain [N/y]?" ; then
DO_AP_STM_ENV=1
@@ -313,20 +379,6 @@ if [[ $DO_AP_STM_ENV -eq 1 ]]; then
install_arm_none_eabi_toolchain
fi
-heading "Check if we are inside docker environment..."
-IS_DOCKER=false
-if [[ -f /.dockerenv ]] || grep -Eq '(lxc|docker)' /proc/1/cgroup ; then
- IS_DOCKER=true
-fi
-echo "Done!"
-
-SHELL_LOGIN=".profile"
-if $IS_DOCKER; then
- echo "Inside docker, we add the tools path into .bashrc directly"
- SHELL_LOGIN=".ardupilot_env"
- echo "# ArduPilot env file. Need to be loaded by your Shell." > ~/$SHELL_LOGIN
-fi
-
heading "Adding ArduPilot Tools to environment"
SCRIPT_DIR=$(dirname $(realpath ${BASH_SOURCE[0]}))
diff --git a/Tools/environment_install/ubuntu-18.04-python3.sh b/Tools/environment_install/ubuntu-18.04-python3.sh
new file mode 100755
index 00000000000000..f8e3ca06851594
--- /dev/null
+++ b/Tools/environment_install/ubuntu-18.04-python3.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+set -e
+set -x
+
+# this should be install by default, but may as well:
+sudo apt install python3
+
+# add $HOME/bin into the binary search path so we can force python-is-python3:
+mkdir $HOME/bin
+rm -f $HOME/bin/python
+ln -s /usr/bin/python3 $HOME/bin/python
+
+echo 'export PATH=$HOME/bin:$PATH' >>$HOME/.profile
+
+# apt Python packages (swiped from install-prereqs-ubuntu.sh):
+sudo apt install -y python3-wxgtk4.0 python3-opencv python3-matplotlib python3-pip
+
+# pip-install python packages (also swiped from install-prereqs-ubuntu.sh):
+pip3 install future lxml pymavlink MAVProxy pexpect flake8==3.7.9 requests==2.27.1 monotonic==1.6 geocoder empy configparser==4.0.2 click==7.1.2 decorator==4.4.2 dronecan pygame intelhex empy
diff --git a/Tools/ros2/README.md b/Tools/ros2/README.md
new file mode 100644
index 00000000000000..bdd055e3f13291
--- /dev/null
+++ b/Tools/ros2/README.md
@@ -0,0 +1,246 @@
+# ArduPilot ROS 2 packages
+
+ This directory contains ROS 2 packages and configuration files for running
+ ROS 2 processes and nodes that communicate with the ArduPilot DDS client
+ library using the microROS agent. It contains the following packages:
+
+#### `ardupilot_sitl`
+
+A `colcon` package for building and running ArduPilot SITL using the ROS 2 CLI.
+For example `ardurover` SITL may be launched with:
+
+```bash
+ros2 launch ardupilot_sitl sitl.launch.py command:=ardurover model:=rover
+```
+
+#### `ardupilot_dds_test`
+
+A `colcon` package for testing communication between `micro_ros_agent` and the
+ArduPilot `AP_DDS` client library.
+
+## Prerequisites
+
+The packages depend on:
+
+- [ROS 2 Humble](https://docs.ros.org/en/humble/Installation/Ubuntu-Install-Debians.html)
+
+
+## Install Ubuntu
+
+#### 1. Create a workspace folder
+
+```bash
+mkdir -p ~/ros_ws/src && cd ~/ros_ws/src
+```
+
+The ROS 2 tutorials contain more details regarding [ROS 2 workspaces](https://docs.ros.org/en/humble/Tutorials/Workspace/Creating-A-Workspace.html).
+
+#### 2. Get the `ros2.repos` file
+
+```bash
+cd ~/ros2_ws/src
+wget https://raw.githubusercontent.com/ArduPilot/ardupilot/master/Tools/ros2/ros2.repos
+vcs import --recursive < ros2.repos
+```
+
+#### 3. Update dependencies
+
+```bash
+cd ~/ros_ws
+source /opt/ros/humble/setup.bash
+sudo apt update
+rosdep update
+rosdep install --rosdistro ${ROS_DISTRO} --from-paths src
+```
+
+#### 4. Build
+
+Check that the [ROS environment](https://docs.ros.org/en/humble/Tutorials/Beginner-CLI-Tools/Configuring-ROS2-Environment.html#check-environment-variables) is configured correctly:
+
+```bash
+ROS_VERSION=2
+ROS_PYTHON_VERSION=3
+ROS_DISTRO=humble
+```
+
+```bash
+cd ~/ros_ws
+colcon build --cmake-args -DBUILD_TESTING=ON
+```
+
+#### 5. Test
+
+```bash
+source ./install/setup.bash
+colcon test --packages-select ardupilot_dds_tests
+colcon test-result --all --verbose
+```
+
+## Install macOS
+
+The install procedure on macOS is similar, except that all dependencies
+must be built from source and additional compiler flags are needed.
+
+#### 1. Create a workspace folder
+
+```bash
+mkdir -p ~/ros_ws/src && cd ~/ros_ws/src
+```
+
+#### 2. Get the `ros2_macos.repos` file
+
+The `ros2_macos.repos` includes additional dependencies to build:
+
+```bash
+cd ~/ros2_ws/src
+wget https://raw.githubusercontent.com/ArduPilot/ardupilot/master/Tools/ros2/ros2_macos.repos
+vcs import --recursive < ros2_macos.repos
+```
+
+#### 3. Update dependencies
+
+```bash
+cd ~/ros_ws
+source /{path_to_your_ros_distro_workspace}/install/setup.zsh
+```
+
+#### 4.1. Build microxrcedds_gen:
+
+```bash
+cd ~/ros2_ws/src/microxrcedds_gen
+./gradlew assemble
+export PATH=$PATH:$(pwd)/scripts
+```
+
+#### 4.2. Build colcon projects
+
+```bash
+colcon build --symlink-install --cmake-args \
+-DBUILD_TESTING=ON \
+-DCMAKE_BUILD_TYPE=RelWithDebInfo \
+-DCMAKE_MACOSX_RPATH=FALSE \
+-DUAGENT_SOCKETCAN_PROFILE=OFF \
+-DUAGENT_LOGGER_PROFILE=OFF \
+-DUAGENT_USE_SYSTEM_LOGGER=OFF \
+-DUAGENT_USE_SYSTEM_FASTDDS=ON \
+-DUAGENT_USE_SYSTEM_FASTCDR=ON \
+--event-handlers=desktop_notification-
+```
+
+#### 5. Test
+
+```bash
+colcon test \
+--pytest-args -s -v \
+--event-handlers console_cohesion+ desktop_notification- \
+--packages-select ardupilot_dds_tests
+```
+
+## Install Docker
+
+#### 0. Build the image and run the container
+
+Clone the ArduPilot docker project:
+
+```bash
+git clone https://github.com/ArduPilot/ardupilot_dev_docker.git
+```
+
+Build the container:
+
+```bash
+cd ~/ardupilot_dev_docker/docker
+docker build -t ardupilot/ardupilot-dev-ros -f Dockerfile_dev-ros .
+```
+
+Start the container in interactive mode:
+
+```bash
+docker run -it --name ardupilot-dds ardupilot/ardupilot-dev-ros
+```
+
+Connect another bash process to the running container:
+
+```bash
+docker container exec -it ardupilot-dds /bin/bash
+```
+
+The remaining steps 1 - 5 are the same as for Ubuntu. You may need to
+install MAVProxy if it is not available on the container.
+
+
+```bash
+pip install -U MAVProxy
+```
+
+
+## Test details
+
+The launch file replicates the following commands:
+
+```bash
+socat -d -d pty,raw,echo=0,link=./dev/ttyROS0 pty,raw,echo=0,link=./dev/ttyROS1
+```
+
+```bash
+ros2 run micro_ros_agent micro_ros_agent serial --baudrate 115200 --dev ./dev/ttyROS0 --refs $(ros2 pkg prefix ardupilot_sitl)/share/ardupilot_sitl/config/dds_xrce_profile.xml
+```
+
+```bash
+arducopter --synthetic-clock --wipe --model quad --speedup 1 --slave 0 --instance 0 --uartC uart:./dev/ttyROS1 --defaults $(ros2 pkg prefix ardupilot_sitl)/share/ardupilot_sitl/config/default_params/copter.parm,$(ros2 pkg prefix ardupilot_sitl)/share/ardupilot_sitl/config/default_params/dds_serial.parm --sim-address 127.0.0.1
+```
+
+```bash
+mavproxy.py --out 127.0.0.1:14550 --out 127.0.0.1:14551 --master tcp:127.0.0.1:5760 --sitl 127.0.0.1:5501
+```
+
+Using individual launch files
+
+```bash
+ros2 launch ardupilot_sitl virtual_ports.launch.py tty0:=./dev/ttyROS0 tty1:=./dev/ttyROS1
+```
+
+```bash
+ros2 launch ardupilot_sitl micro_ros_agent.launch.py transport:=serial refs:=$(ros2 pkg prefix ardupilot_sitl)/share/ardupilot_sitl/config/dds_xrce_profile.xml baudrate:=115200 device:=./dev/ttyROS0
+```
+
+```bash
+ros2 launch ardupilot_sitl sitl.launch.py synthetic_clock:=True wipe:=True model:=quad speedup:=1 slave:=0 instance:=0 uartC:=uart:./dev/ttyROS1 defaults:=$(ros2 pkg prefix ardupilot_sitl)/share/ardupilot_sitl/config/default_params/copter.parm,$(ros2 pkg prefix ardupilot_sitl)/share/ardupilot_sitl/config/default_params/dds_serial.parm sim_address:=127.0.0.1
+```
+
+```bash
+ros2 launch ardupilot_sitl mavproxy.launch.py master:=tcp:127.0.0.1:5760 sitl:=127.0.0.1:5501
+```
+
+Using combined launch file
+
+```bash
+ros2 launch ardupilot_sitl sitl_dds_serial.launch.py \
+\
+tty0:=./dev/ttyROS0 \
+tty1:=./dev/ttyROS1 \
+\
+transport:=serial \
+refs:=$(ros2 pkg prefix ardupilot_sitl)/share/ardupilot_sitl/config/dds_xrce_profile.xml \
+baudrate:=115200 \
+device:=./dev/ttyROS0 \
+\
+synthetic_clock:=True \
+wipe:=True \
+model:=quad \
+speedup:=1 \
+slave:=0 \
+instance:=0 \
+uartC:=uart:./dev/ttyROS1 \
+defaults:=$(ros2 pkg prefix ardupilot_sitl)/share/ardupilot_sitl/config/default_params/copter.parm,$(ros2 pkg prefix ardupilot_sitl)/share/ardupilot_sitl/config/default_params/dds_serial.parm \
+sim_address:=127.0.0.1 \
+\
+master:=tcp:127.0.0.1:5760 \
+sitl:=127.0.0.1:5501
+```
+
+UDP version
+
+```
+ros2 launch ardupilot_sitl sitl_dds_udp.launch.py transport:=udp4 refs:=$(ros2 pkg prefix ardupilot_sitl)/share/ardupilot_sitl/config/dds_xrce_profile.xml synthetic_clock:=True wipe:=False model:=quad speedup:=1 slave:=0 instance:=0 defaults:=$(ros2 pkg prefix ardupilot_sitl)/share/ardupilot_sitl/config/default_params/copter.parm,$(ros2 pkg prefix ardupilot_sitl)/share/ardupilot_sitl/config/default_params/dds_udp.parm sim_address:=127.0.0.1 master:=tcp:127.0.0.1:5760 sitl:=127.0.0.1:5501
+```
diff --git a/Tools/ros2/ardupilot_dds_tests/.flake8 b/Tools/ros2/ardupilot_dds_tests/.flake8
new file mode 100644
index 00000000000000..b79f25fa411990
--- /dev/null
+++ b/Tools/ros2/ardupilot_dds_tests/.flake8
@@ -0,0 +1,10 @@
+[flake8]
+# Match black line length (default 88).
+max-line-length = 88
+# Match black configuration where there are conflicts.
+extend-ignore =
+ # Q000: Double quotes found but single quotes preferred
+ Q000,
+ # W503: Line break before binary operator
+ W503
+
diff --git a/Tools/ros2/ardupilot_dds_tests/ardupilot_dds_tests/__init__.py b/Tools/ros2/ardupilot_dds_tests/ardupilot_dds_tests/__init__.py
new file mode 100644
index 00000000000000..c50c1d44fe9832
--- /dev/null
+++ b/Tools/ros2/ardupilot_dds_tests/ardupilot_dds_tests/__init__.py
@@ -0,0 +1,16 @@
+# Copyright 2023 ArduPilot.org.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+"""Main entry point for the `ardupilot_dds_tests` package."""
diff --git a/Tools/ros2/ardupilot_dds_tests/ardupilot_dds_tests/time_listener.py b/Tools/ros2/ardupilot_dds_tests/ardupilot_dds_tests/time_listener.py
new file mode 100755
index 00000000000000..851ebf7027d930
--- /dev/null
+++ b/Tools/ros2/ardupilot_dds_tests/ardupilot_dds_tests/time_listener.py
@@ -0,0 +1,69 @@
+# Copyright 2023 ArduPilot.org.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+"""Subscribe to Time messages on topic /ap/time."""
+import rclpy
+import time
+
+from rclpy.node import Node
+from builtin_interfaces.msg import Time
+
+
+class TimeListener(Node):
+ """Subscribe to Time messages on topic /ap/time."""
+
+ def __init__(self):
+ """Initialise the node."""
+ super().__init__("time_listener")
+
+ # Declare and acquire `topic` parameter.
+ self.declare_parameter("topic", "ap/time")
+ self.topic = self.get_parameter("topic").get_parameter_value().string_value
+
+ # Subscriptions.
+ self.subscription = self.create_subscription(Time, self.topic, self.cb, 1)
+ self.subscription
+
+ def cb(self, msg):
+ """Process a Time message."""
+ if msg.sec:
+ self.get_logger().info(
+ "From AP : True [sec:{}, nsec: {}]".format(msg.sec, msg.nanosec)
+ )
+ else:
+ self.get_logger().info("From AP : False")
+
+
+def main(args=None):
+ """Node entry point."""
+ rclpy.init(args=args)
+ node = TimeListener()
+ try:
+ count = 0
+ while count < 100:
+ rclpy.spin_once(node)
+ count += 1
+ time.sleep(1.0)
+
+ except KeyboardInterrupt:
+ pass
+
+ # Destroy the node explicitly.
+ node.destroy_node()
+ rclpy.shutdown()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/Tools/ros2/ardupilot_dds_tests/config/ardupilot_dds.yaml b/Tools/ros2/ardupilot_dds_tests/config/ardupilot_dds.yaml
new file mode 100644
index 00000000000000..67d472c34fb946
--- /dev/null
+++ b/Tools/ros2/ardupilot_dds_tests/config/ardupilot_dds.yaml
@@ -0,0 +1,13 @@
+/micro_ros_agent:
+ transport: serial
+ middleware: dds
+ serial_baud: 115200
+ serial_device: ./dev/ttyROS0
+ refs_file: ./src/ardupilot/libraries/AP_DDS/dds_xrce_profile.xml
+
+/ardupilot:
+ sim_vehicle_cmd: ./src/ardupilot/Tools/autotest/sim_vehicle.py
+ vehicle: ArduCopter
+ frame: quad
+ serial_baud: 115200
+ serial_device: ./dev/ttyROS1
diff --git a/Tools/ros2/ardupilot_dds_tests/launch/README.md b/Tools/ros2/ardupilot_dds_tests/launch/README.md
new file mode 100644
index 00000000000000..3a868074aa1e77
--- /dev/null
+++ b/Tools/ros2/ardupilot_dds_tests/launch/README.md
@@ -0,0 +1 @@
+## Placeholder for `ardupilot_dds_tests` launch files.
diff --git a/Tools/ros2/ardupilot_dds_tests/package.xml b/Tools/ros2/ardupilot_dds_tests/package.xml
new file mode 100644
index 00000000000000..dacbbe61e1efe0
--- /dev/null
+++ b/Tools/ros2/ardupilot_dds_tests/package.xml
@@ -0,0 +1,33 @@
+
+
+
+ ardupilot_dds_tests
+ 0.0.0
+ Tests for the ArduPilot AP_DDS library
+ rhys
+ GLP-3.0
+
+ ament_index_python
+ ardupilot_sitl
+ launch
+ launch_pytest
+ launch_ros
+ micro_ros_msgs
+ python3-pytest
+ rclpy
+
+ ament_copyright
+ ament_flake8
+ ament_pep257
+ ardupilot_sitl
+ launch
+ launch_pytest
+ launch_ros
+ micro_ros_msgs
+ python3-pytest
+ rclpy
+
+
+ ament_python
+
+
diff --git a/Tools/autotest/jsb_sim/__init__.py b/Tools/ros2/ardupilot_dds_tests/resource/ardupilot_dds_tests
similarity index 100%
rename from Tools/autotest/jsb_sim/__init__.py
rename to Tools/ros2/ardupilot_dds_tests/resource/ardupilot_dds_tests
diff --git a/Tools/ros2/ardupilot_dds_tests/setup.cfg b/Tools/ros2/ardupilot_dds_tests/setup.cfg
new file mode 100644
index 00000000000000..ef1e9abe748417
--- /dev/null
+++ b/Tools/ros2/ardupilot_dds_tests/setup.cfg
@@ -0,0 +1,4 @@
+[develop]
+script_dir=$base/lib/ardupilot_dds_tests
+[install]
+install_scripts=$base/lib/ardupilot_dds_tests
diff --git a/Tools/ros2/ardupilot_dds_tests/setup.py b/Tools/ros2/ardupilot_dds_tests/setup.py
new file mode 100644
index 00000000000000..ce6e894687c5c5
--- /dev/null
+++ b/Tools/ros2/ardupilot_dds_tests/setup.py
@@ -0,0 +1,34 @@
+import os
+from glob import glob
+from setuptools import setup
+
+package_name = 'ardupilot_dds_tests'
+
+setup(
+ name=package_name,
+ version='0.0.0',
+ packages=[package_name],
+ data_files=[
+ ('share/ament_index/resource_index/packages',
+ ['resource/' + package_name]),
+ ('share/' + package_name, ['package.xml']),
+ (os.path.join("share", package_name, "launch"),
+ glob("launch/*.launch.py")),
+ (os.path.join("share", package_name, "config"),
+ glob("config/*.parm")),
+ (os.path.join("share", package_name, "config"),
+ glob("config/*.yaml")),
+ ],
+ install_requires=['setuptools'],
+ zip_safe=True,
+ maintainer='maintainer',
+ maintainer_email='maintainer@ardupilot.org',
+ description='Tests for the ArduPilot AP_DDS library',
+ license='GPL-3.0',
+ tests_require=['pytest'],
+ entry_points={
+ 'console_scripts': [
+ "time_listener = ardupilot_dds_tests.time_listener:main",
+ ],
+ },
+)
diff --git a/Tools/ros2/ardupilot_dds_tests/test/ardupilot_dds_tests/conftest.py b/Tools/ros2/ardupilot_dds_tests/test/ardupilot_dds_tests/conftest.py
new file mode 100644
index 00000000000000..66a71779fa28ff
--- /dev/null
+++ b/Tools/ros2/ardupilot_dds_tests/test/ardupilot_dds_tests/conftest.py
@@ -0,0 +1,234 @@
+# Copyright 2023 ArduPilot.org.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+"""Common fixtures."""
+import os
+import pytest
+
+from ament_index_python.packages import get_package_share_directory
+
+from launch import LaunchDescription
+from launch import LaunchDescriptionSource
+from launch.actions import IncludeLaunchDescription
+from launch.substitutions import PathJoinSubstitution
+
+from launch_ros.substitutions import FindPackageShare
+
+from pathlib import Path
+
+from ardupilot_sitl.launch import VirtualPortsLaunch
+from ardupilot_sitl.launch import MicroRosAgentLaunch
+from ardupilot_sitl.launch import MAVProxyLaunch
+from ardupilot_sitl.launch import SITLLaunch
+
+
+@pytest.fixture(scope="module")
+def device_dir(tmp_path_factory):
+ """Fixture to create a temporary directory for devices."""
+ path = tmp_path_factory.mktemp("devices")
+
+ # Create dev directory for virtual ports.
+ os.mkdir(Path(path, "dev"))
+
+ yield path
+
+
+@pytest.fixture
+def virtual_ports(device_dir):
+ """Fixture to create virtual ports."""
+ tty0 = Path(device_dir, "dev", "tty0").resolve()
+ tty1 = Path(device_dir, "dev", "tty1").resolve()
+
+ vp_ld, vp_actions = VirtualPortsLaunch.generate_launch_description_with_actions()
+
+ ld = IncludeLaunchDescription(
+ LaunchDescriptionSource(vp_ld),
+ launch_arguments={
+ "tty0": str(tty0),
+ "tty1": str(tty1),
+ }.items(),
+ )
+ yield ld, vp_actions
+
+
+@pytest.fixture
+def micro_ros_agent_serial(device_dir):
+ """Fixture to create a micro_ros_agent node."""
+ tty0 = Path(device_dir, "dev", "tty0").resolve()
+
+ mra_ld, mra_actions = MicroRosAgentLaunch.generate_launch_description_with_actions()
+
+ ld = IncludeLaunchDescription(
+ LaunchDescriptionSource(mra_ld),
+ launch_arguments={
+ "transport": "serial",
+ "refs": PathJoinSubstitution(
+ [
+ FindPackageShare("ardupilot_sitl"),
+ "config",
+ "dds_xrce_profile.xml",
+ ]
+ ),
+ "baudrate": "115200",
+ "device": str(tty0),
+ }.items(),
+ )
+ yield ld, mra_actions
+
+
+@pytest.fixture
+def micro_ros_agent_udp():
+ """Fixture to create a micro_ros_agent node."""
+ mra_ld, mra_actions = MicroRosAgentLaunch.generate_launch_description_with_actions()
+
+ ld = IncludeLaunchDescription(
+ LaunchDescriptionSource(mra_ld),
+ launch_arguments={
+ "transport": "udp4",
+ "refs": PathJoinSubstitution(
+ [
+ FindPackageShare("ardupilot_sitl"),
+ "config",
+ "dds_xrce_profile.xml",
+ ]
+ ),
+ }.items(),
+ )
+ yield ld, mra_actions
+
+
+@pytest.fixture
+def mavproxy():
+ """Fixture to bring up MAVProxy."""
+ mp_ld, mp_actions = MAVProxyLaunch.generate_launch_description_with_actions()
+
+ ld = IncludeLaunchDescription(
+ LaunchDescriptionSource(mp_ld),
+ launch_arguments={
+ "master": "tcp:127.0.0.1:5760",
+ "sitl": "127.0.0.1:5501",
+ }.items(),
+ )
+ yield ld, mp_actions
+
+
+@pytest.fixture
+def sitl_copter_dds_serial(device_dir, virtual_ports, micro_ros_agent_serial, mavproxy):
+ """Fixture to bring up ArduPilot SITL DDS."""
+ tty1 = Path(device_dir, "dev", "tty1").resolve()
+
+ vp_ld, vp_actions = virtual_ports
+ mra_ld, mra_actions = micro_ros_agent_serial
+ mp_ld, mp_actions = mavproxy
+ sitl_ld, sitl_actions = SITLLaunch.generate_launch_description_with_actions()
+
+ sitl_ld_args = IncludeLaunchDescription(
+ LaunchDescriptionSource(sitl_ld),
+ launch_arguments={
+ "command": "arducopter",
+ "synthetic_clock": "True",
+ # "wipe": "True",
+ "wipe": "False",
+ "model": "quad",
+ "speedup": "10",
+ "slave": "0",
+ "instance": "0",
+ "uartC": f"uart:{str(tty1)}",
+ "defaults": str(
+ Path(
+ get_package_share_directory("ardupilot_sitl"),
+ "config",
+ "default_params",
+ "copter.parm",
+ )
+ )
+ + ","
+ + str(
+ Path(
+ get_package_share_directory("ardupilot_sitl"),
+ "config",
+ "default_params",
+ "dds_serial.parm",
+ )
+ ),
+ }.items(),
+ )
+
+ ld = LaunchDescription(
+ [
+ vp_ld,
+ mra_ld,
+ mp_ld,
+ sitl_ld_args,
+ ]
+ )
+ actions = {}
+ actions.update(vp_actions)
+ actions.update(mra_actions)
+ actions.update(mp_actions)
+ actions.update(sitl_actions)
+ yield ld, actions
+
+
+@pytest.fixture
+def sitl_copter_dds_udp(micro_ros_agent_udp, mavproxy):
+ """Fixture to bring up ArduPilot SITL DDS."""
+ mra_ld, mra_actions = micro_ros_agent_udp
+ mp_ld, mp_actions = mavproxy
+ sitl_ld, sitl_actions = SITLLaunch.generate_launch_description_with_actions()
+
+ sitl_ld_args = IncludeLaunchDescription(
+ LaunchDescriptionSource(sitl_ld),
+ launch_arguments={
+ "command": "arducopter",
+ "synthetic_clock": "True",
+ # "wipe": "True",
+ "wipe": "False",
+ "model": "quad",
+ "speedup": "10",
+ "slave": "0",
+ "instance": "0",
+ "defaults": str(
+ Path(
+ get_package_share_directory("ardupilot_sitl"),
+ "config",
+ "default_params",
+ "copter.parm",
+ )
+ )
+ + ","
+ + str(
+ Path(
+ get_package_share_directory("ardupilot_sitl"),
+ "config",
+ "default_params",
+ "dds_udp.parm",
+ )
+ ),
+ }.items(),
+ )
+
+ ld = LaunchDescription(
+ [
+ mra_ld,
+ mp_ld,
+ sitl_ld_args,
+ ]
+ )
+ actions = {}
+ actions.update(mra_actions)
+ actions.update(mp_actions)
+ actions.update(sitl_actions)
+ yield ld, actions
diff --git a/Tools/ros2/ardupilot_dds_tests/test/ardupilot_dds_tests/param_loader_wip.py b/Tools/ros2/ardupilot_dds_tests/test/ardupilot_dds_tests/param_loader_wip.py
new file mode 100644
index 00000000000000..f8c8a5efb881dd
--- /dev/null
+++ b/Tools/ros2/ardupilot_dds_tests/test/ardupilot_dds_tests/param_loader_wip.py
@@ -0,0 +1,58 @@
+# Copyright 2023 ArduPilot.org.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+"""Loader parameters for test cases (WIP)."""
+
+# from pathlib import Path
+#
+# class DDSParams(object):
+# def __init__(self):
+# super().__init__()
+#
+# # default params
+# self.mra_serial_device = f"./dev/ttyROS0"
+# self.mra_serial_baud = 115200
+# self.mra_refs_file = "dds_xrce_profile.xml"
+#
+# self.ap_sim_vehicle_cmd = "sim_vehicle.py"
+# self.ap_serial_device = f"./dev/ttyROS1"
+# self.ap_serial_baud = 115200
+# self.ap_vehicle = "ArduCopter"
+# self.ap_frame = "quad"
+#
+# pkg = get_package_share_directory("ardupilot_sitl")
+#
+# # The micro_ros_agent and ardupilot nodes do not expose params
+# # as ROS params, parse the config file and send them in as node args.
+# params = Path(pkg, "config", "ardupilot_dds.yaml")
+#
+# with open(params, "r") as f:
+# params_str = f.read()
+# params = yaml.safe_load(params_str)
+# print(params)
+#
+# mra_params = params["/micro_ros_agent"]
+# if mra_params["transport"] == "serial":
+# self.mra_serial_baud = f"{mra_params['serial_baud']}"
+# self.mra_serial_device = f"{mra_params['serial_device']}"
+# self.mra_refs_file = f"{mra_params['refs_file']}"
+#
+# ap_params = params["/ardupilot"]
+# if ap_params:
+# self.ap_sim_vehicle_cmd = ap_params["sim_vehicle_cmd"]
+# self.ap_vehicle = ap_params["vehicle"]
+# self.ap_frame = ap_params["frame"]
+# self.ap_serial_device = ap_params["serial_device"]
+# self.ap_serial_baud = ap_params["serial_baud"]
diff --git a/Tools/ros2/ardupilot_dds_tests/test/ardupilot_dds_tests/test_navsat_msg_received.py b/Tools/ros2/ardupilot_dds_tests/test/ardupilot_dds_tests/test_navsat_msg_received.py
new file mode 100644
index 00000000000000..d4f78f80ff6f06
--- /dev/null
+++ b/Tools/ros2/ardupilot_dds_tests/test/ardupilot_dds_tests/test_navsat_msg_received.py
@@ -0,0 +1,153 @@
+# Copyright 2023 ArduPilot.org.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+"""Bring up ArduPilot SITL and check the NavSat message is being published."""
+import launch_pytest
+import pytest
+import rclpy
+import rclpy.node
+import threading
+
+from launch import LaunchDescription
+
+from launch_pytest.tools import process as process_tools
+
+from rclpy.qos import QoSProfile
+from rclpy.qos import QoSReliabilityPolicy
+from rclpy.qos import QoSHistoryPolicy
+
+from sensor_msgs.msg import NavSatFix
+
+
+class NavSatFixListener(rclpy.node.Node):
+ """Subscribe to NavSatFix messages on /ap/navsat/navsat0."""
+
+ def __init__(self):
+ """Initialise the node."""
+ super().__init__("navsatfix_listener")
+ self.msg_event_object = threading.Event()
+
+ # Declare and acquire `topic` parameter
+ self.declare_parameter("topic", "ap/navsat/navsat0")
+ self.topic = self.get_parameter("topic").get_parameter_value().string_value
+
+ def start_subscriber(self):
+ """Start the subscriber."""
+ qos_profile = QoSProfile(
+ reliability=QoSReliabilityPolicy.BEST_EFFORT,
+ history=QoSHistoryPolicy.KEEP_LAST,
+ depth=1,
+ )
+
+ self.subscription = self.create_subscription(
+ NavSatFix, self.topic, self.subscriber_callback, qos_profile
+ )
+
+ # Add a spin thread.
+ self.ros_spin_thread = threading.Thread(
+ target=lambda node: rclpy.spin(node), args=(self,)
+ )
+ self.ros_spin_thread.start()
+
+ def subscriber_callback(self, msg):
+ """Process a NavSatFix message."""
+ self.msg_event_object.set()
+
+ if msg.latitude:
+ self.get_logger().info(
+ "From AP : True [lat:{}, lon: {}]".format(msg.latitude, msg.longitude)
+ )
+ else:
+ self.get_logger().info("From AP : False")
+
+
+@launch_pytest.fixture
+def launch_sitl_copter_dds_serial(sitl_copter_dds_serial):
+ """Fixture to create the launch description."""
+ sitl_ld, sitl_actions = sitl_copter_dds_serial
+
+ ld = LaunchDescription(
+ [
+ sitl_ld,
+ launch_pytest.actions.ReadyToTest(),
+ ]
+ )
+ actions = sitl_actions
+ yield ld, actions
+
+
+@launch_pytest.fixture
+def launch_sitl_copter_dds_udp(sitl_copter_dds_udp):
+ """Fixture to create the launch description."""
+ sitl_ld, sitl_actions = sitl_copter_dds_udp
+
+ ld = LaunchDescription(
+ [
+ sitl_ld,
+ launch_pytest.actions.ReadyToTest(),
+ ]
+ )
+ actions = sitl_actions
+ yield ld, actions
+
+
+@pytest.mark.launch(fixture=launch_sitl_copter_dds_serial)
+def test_dds_serial_navsat_msg_recv(launch_context, launch_sitl_copter_dds_serial):
+ """Test NavSatFix messages are published by AP_DDS."""
+ _, actions = launch_sitl_copter_dds_serial
+ virtual_ports = actions["virtual_ports"].action
+ micro_ros_agent = actions["micro_ros_agent"].action
+ mavproxy = actions["mavproxy"].action
+ sitl = actions["sitl"].action
+
+ # Wait for process to start.
+ process_tools.wait_for_start_sync(launch_context, virtual_ports, timeout=2)
+ process_tools.wait_for_start_sync(launch_context, micro_ros_agent, timeout=2)
+ process_tools.wait_for_start_sync(launch_context, mavproxy, timeout=2)
+ process_tools.wait_for_start_sync(launch_context, sitl, timeout=2)
+
+ rclpy.init()
+ try:
+ node = NavSatFixListener()
+ node.start_subscriber()
+ msgs_received_flag = node.msg_event_object.wait(timeout=10.0)
+ assert msgs_received_flag, "Did not receive 'ap/navsat/navsat0' msgs."
+ finally:
+ rclpy.shutdown()
+ yield
+
+
+@pytest.mark.launch(fixture=launch_sitl_copter_dds_udp)
+def test_dds_udp_navsat_msg_recv(launch_context, launch_sitl_copter_dds_udp):
+ """Test NavSatFix messages are published by AP_DDS."""
+ _, actions = launch_sitl_copter_dds_udp
+ micro_ros_agent = actions["micro_ros_agent"].action
+ mavproxy = actions["mavproxy"].action
+ sitl = actions["sitl"].action
+
+ # Wait for process to start.
+ process_tools.wait_for_start_sync(launch_context, micro_ros_agent, timeout=2)
+ process_tools.wait_for_start_sync(launch_context, mavproxy, timeout=2)
+ process_tools.wait_for_start_sync(launch_context, sitl, timeout=2)
+
+ rclpy.init()
+ try:
+ node = NavSatFixListener()
+ node.start_subscriber()
+ msgs_received_flag = node.msg_event_object.wait(timeout=10.0)
+ assert msgs_received_flag, "Did not receive 'ap/navsat/navsat0' msgs."
+ finally:
+ rclpy.shutdown()
+ yield
diff --git a/Tools/ros2/ardupilot_dds_tests/test/ardupilot_dds_tests/test_time_msg_received.py b/Tools/ros2/ardupilot_dds_tests/test/ardupilot_dds_tests/test_time_msg_received.py
new file mode 100644
index 00000000000000..65676dcc771fe5
--- /dev/null
+++ b/Tools/ros2/ardupilot_dds_tests/test/ardupilot_dds_tests/test_time_msg_received.py
@@ -0,0 +1,143 @@
+# Copyright 2023 ArduPilot.org.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+"""Bring up ArduPilot SITL check the Time message is being published."""
+import launch_pytest
+import pytest
+import rclpy
+import rclpy.node
+import threading
+
+from launch import LaunchDescription
+
+from launch_pytest.tools import process as process_tools
+
+from builtin_interfaces.msg import Time
+
+
+class TimeListener(rclpy.node.Node):
+ """Subscribe to Time messages on /ap/time."""
+
+ def __init__(self):
+ """Initialise the node."""
+ super().__init__("time_listener")
+ self.msg_event_object = threading.Event()
+
+ # Declare and acquire `topic` parameter.
+ self.declare_parameter("topic", "ap/time")
+ self.topic = self.get_parameter("topic").get_parameter_value().string_value
+
+ def start_subscriber(self):
+ """Start the subscriber."""
+ self.subscription = self.create_subscription(
+ Time, self.topic, self.subscriber_callback, 1
+ )
+
+ # Add a spin thread.
+ self.ros_spin_thread = threading.Thread(
+ target=lambda node: rclpy.spin(node), args=(self,)
+ )
+ self.ros_spin_thread.start()
+
+ def subscriber_callback(self, msg):
+ """Process a Time message."""
+ self.msg_event_object.set()
+
+ if msg.sec:
+ self.get_logger().info(
+ "From AP : True [sec:{}, nsec: {}]".format(msg.sec, msg.nanosec)
+ )
+ else:
+ self.get_logger().info("From AP : False")
+
+
+@launch_pytest.fixture
+def launch_sitl_copter_dds_serial(sitl_copter_dds_serial):
+ """Fixture to create the launch description."""
+ sitl_ld, sitl_actions = sitl_copter_dds_serial
+
+ ld = LaunchDescription(
+ [
+ sitl_ld,
+ launch_pytest.actions.ReadyToTest(),
+ ]
+ )
+ actions = sitl_actions
+ yield ld, actions
+
+
+@launch_pytest.fixture
+def launch_sitl_copter_dds_udp(sitl_copter_dds_udp):
+ """Fixture to create the launch description."""
+ sitl_ld, sitl_actions = sitl_copter_dds_udp
+
+ ld = LaunchDescription(
+ [
+ sitl_ld,
+ launch_pytest.actions.ReadyToTest(),
+ ]
+ )
+ actions = sitl_actions
+ yield ld, actions
+
+
+@pytest.mark.launch(fixture=launch_sitl_copter_dds_serial)
+def test_dds_serial_time_msg_recv(launch_context, launch_sitl_copter_dds_serial):
+ """Test /ap/time is published by AP_DDS."""
+ _, actions = launch_sitl_copter_dds_serial
+ virtual_ports = actions["virtual_ports"].action
+ micro_ros_agent = actions["micro_ros_agent"].action
+ mavproxy = actions["mavproxy"].action
+ sitl = actions["sitl"].action
+
+ # Wait for process to start.
+ process_tools.wait_for_start_sync(launch_context, virtual_ports, timeout=2)
+ process_tools.wait_for_start_sync(launch_context, micro_ros_agent, timeout=2)
+ process_tools.wait_for_start_sync(launch_context, mavproxy, timeout=2)
+ process_tools.wait_for_start_sync(launch_context, sitl, timeout=2)
+
+ rclpy.init()
+ try:
+ node = TimeListener()
+ node.start_subscriber()
+ msgs_received_flag = node.msg_event_object.wait(timeout=10.0)
+ assert msgs_received_flag, "Did not receive 'ROS_Time' msgs."
+ finally:
+ rclpy.shutdown()
+ yield
+
+
+@pytest.mark.launch(fixture=launch_sitl_copter_dds_udp)
+def test_dds_udp_time_msg_recv(launch_context, launch_sitl_copter_dds_udp):
+ """Test /ap/time is published by AP_DDS."""
+ _, actions = launch_sitl_copter_dds_udp
+ micro_ros_agent = actions["micro_ros_agent"].action
+ mavproxy = actions["mavproxy"].action
+ sitl = actions["sitl"].action
+
+ # Wait for process to start.
+ process_tools.wait_for_start_sync(launch_context, micro_ros_agent, timeout=2)
+ process_tools.wait_for_start_sync(launch_context, mavproxy, timeout=2)
+ process_tools.wait_for_start_sync(launch_context, sitl, timeout=2)
+
+ rclpy.init()
+ try:
+ node = TimeListener()
+ node.start_subscriber()
+ msgs_received_flag = node.msg_event_object.wait(timeout=10.0)
+ assert msgs_received_flag, "Did not receive 'ROS_Time' msgs."
+ finally:
+ rclpy.shutdown()
+ yield
diff --git a/Tools/ros2/ardupilot_dds_tests/test/ardupilot_dds_tests/test_virtual_ports.py b/Tools/ros2/ardupilot_dds_tests/test/ardupilot_dds_tests/test_virtual_ports.py
new file mode 100644
index 00000000000000..25109a21e975a5
--- /dev/null
+++ b/Tools/ros2/ardupilot_dds_tests/test/ardupilot_dds_tests/test_virtual_ports.py
@@ -0,0 +1,56 @@
+# Copyright 2023 ArduPilot.org.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+"""Use `socat` to create virtual ports ttyROS0 and ttyRO1 and check they exist."""
+import launch_pytest
+import pytest
+
+from launch import LaunchDescription
+
+from launch_pytest.tools import process as process_tools
+
+
+@launch_pytest.fixture
+def launch_description(virtual_ports):
+ """Launch description fixture."""
+ vp_ld, vp_actions = virtual_ports
+
+ ld = LaunchDescription(
+ [
+ vp_ld,
+ launch_pytest.actions.ReadyToTest(),
+ ]
+ )
+ actions = vp_actions
+ yield ld, actions
+
+
+@pytest.mark.launch(fixture=launch_description)
+def test_virtual_ports(launch_context, launch_description):
+ """Test the virtual ports are present."""
+ _, actions = launch_description
+ virtual_ports = actions["virtual_ports"].action
+
+ # Wait for process to start.
+ process_tools.wait_for_start_sync(launch_context, virtual_ports, timeout=2)
+
+ # Assert contents of output to stderr.
+ def validate_output(output):
+ assert "N starting data transfer loop" in output, "Test process had no output."
+
+ process_tools.assert_stderr_sync(
+ launch_context, virtual_ports, validate_output, timeout=5
+ )
+ yield
diff --git a/Tools/ros2/ardupilot_dds_tests/test/test_copyright.py b/Tools/ros2/ardupilot_dds_tests/test/test_copyright.py
new file mode 100644
index 00000000000000..0ba906088ba2c2
--- /dev/null
+++ b/Tools/ros2/ardupilot_dds_tests/test/test_copyright.py
@@ -0,0 +1,25 @@
+# Copyright 2015 Open Source Robotics Foundation, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Test files include a copyright notice."""
+from ament_copyright.main import main
+import pytest
+
+
+@pytest.mark.copyright
+@pytest.mark.linter
+def test_copyright():
+ """Copyright test case."""
+ rc = main(argv=[".", "test"])
+ assert rc == 0, "Found errors"
diff --git a/Tools/ros2/ardupilot_dds_tests/test/test_flake8.py b/Tools/ros2/ardupilot_dds_tests/test/test_flake8.py
new file mode 100644
index 00000000000000..17771247a54724
--- /dev/null
+++ b/Tools/ros2/ardupilot_dds_tests/test/test_flake8.py
@@ -0,0 +1,27 @@
+# Copyright 2017 Open Source Robotics Foundation, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Test Python files satisfy the flake8 linter requirements."""
+from ament_flake8.main import main_with_errors
+import pytest
+
+
+@pytest.mark.flake8
+@pytest.mark.linter
+def test_flake8():
+ """flake8 test case."""
+ rc, errors = main_with_errors(argv=[])
+ assert rc == 0, "Found %d code style errors / warnings:\n" % len(
+ errors
+ ) + "\n".join(errors)
diff --git a/Tools/ros2/ardupilot_dds_tests/test/test_pep257.py b/Tools/ros2/ardupilot_dds_tests/test/test_pep257.py
new file mode 100644
index 00000000000000..c46d13e9730fd0
--- /dev/null
+++ b/Tools/ros2/ardupilot_dds_tests/test/test_pep257.py
@@ -0,0 +1,25 @@
+# Copyright 2015 Open Source Robotics Foundation, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Test Python files satisfy PEP257."""
+from ament_pep257.main import main
+import pytest
+
+
+@pytest.mark.linter
+@pytest.mark.pep257
+def test_pep257():
+ """PEP257 test case."""
+ rc = main(argv=[".", "test"])
+ assert rc == 0, "Found code style errors / warnings"
diff --git a/Tools/ros2/ardupilot_msgs/CMakeLists.txt b/Tools/ros2/ardupilot_msgs/CMakeLists.txt
new file mode 100644
index 00000000000000..5887179c4eb711
--- /dev/null
+++ b/Tools/ros2/ardupilot_msgs/CMakeLists.txt
@@ -0,0 +1,23 @@
+cmake_minimum_required(VERSION 3.8)
+project(ardupilot_msgs)
+
+# --------------------------------------------------------------------------- #
+# Find dependencies.
+
+find_package(ament_cmake REQUIRED)
+find_package(rosidl_default_generators REQUIRED)
+
+# --------------------------------------------------------------------------- #
+# Generate and export message interfaces.
+
+rosidl_generate_interfaces(${PROJECT_NAME}
+ "srv/ArmMotors.srv"
+ ADD_LINTER_TESTS
+)
+
+ament_export_dependencies(rosidl_default_runtime)
+
+# --------------------------------------------------------------------------- #
+# Call last.
+
+ament_package()
diff --git a/Tools/ros2/ardupilot_msgs/package.xml b/Tools/ros2/ardupilot_msgs/package.xml
new file mode 100644
index 00000000000000..b2286616eb6987
--- /dev/null
+++ b/Tools/ros2/ardupilot_msgs/package.xml
@@ -0,0 +1,24 @@
+
+
+
+ ardupilot_msgs
+ 0.0.0
+ Custom ROS 2 messages and services for ArduPilot
+ maintainer
+ GPL-3.0
+
+ ament_cmake
+ rosidl_default_generators
+
+ rosidl_default_runtime
+
+ ament_lint_auto
+ ament_lint_common
+
+ rosidl_interface_packages
+
+
+ ament_cmake
+
+
diff --git a/Tools/ros2/ardupilot_msgs/srv/ArmMotors.srv b/Tools/ros2/ardupilot_msgs/srv/ArmMotors.srv
new file mode 100644
index 00000000000000..671bc30795709e
--- /dev/null
+++ b/Tools/ros2/ardupilot_msgs/srv/ArmMotors.srv
@@ -0,0 +1,8 @@
+
+# This service requests the vehicle to arm or disarm its motors.
+
+# Set true to arm motors, false to disarm motors.
+bool arm
+---
+# True if arming/disarming request for motors was successful , false otherwise.
+bool result
diff --git a/Tools/ros2/ardupilot_sitl/.flake8 b/Tools/ros2/ardupilot_sitl/.flake8
new file mode 100644
index 00000000000000..b79f25fa411990
--- /dev/null
+++ b/Tools/ros2/ardupilot_sitl/.flake8
@@ -0,0 +1,10 @@
+[flake8]
+# Match black line length (default 88).
+max-line-length = 88
+# Match black configuration where there are conflicts.
+extend-ignore =
+ # Q000: Double quotes found but single quotes preferred
+ Q000,
+ # W503: Line break before binary operator
+ W503
+
diff --git a/Tools/ros2/ardupilot_sitl/CMakeLists.txt b/Tools/ros2/ardupilot_sitl/CMakeLists.txt
new file mode 100644
index 00000000000000..9d40ea746d43b6
--- /dev/null
+++ b/Tools/ros2/ardupilot_sitl/CMakeLists.txt
@@ -0,0 +1,117 @@
+cmake_minimum_required(VERSION 3.20)
+project(ardupilot_sitl)
+
+# --------------------------------------------------------------------------- #
+# Find dependencies.
+find_package(ament_cmake REQUIRED)
+find_package(ament_cmake_python REQUIRED)
+
+# --------------------------------------------------------------------------- #
+# Add custom targets to configure and build ardupilot.
+
+# TODO(srmainwaring): add cache variables for vehicle type, debug etc.
+# set(ARDUPILOT_VEHICLE "copter" CACHE STRING "Vehicle type")
+
+# NOTE: look for `waf` and set source and build directories to top level.
+# ${PROJECT_SOURCE_DIR} = ./Tools/ros2/ardupilot
+#
+cmake_path(SET ARDUPILOT_ROOT NORMALIZE ${PROJECT_SOURCE_DIR}/../../..)
+
+find_program(WAF_COMMAND waf HINTS ${ARDUPILOT_ROOT})
+message(STATUS "WAF_COMMAND: ${WAF_COMMAND}")
+
+# Set the build config.
+set(WAF_CONFIG $<$,$>:"--debug">)
+
+add_custom_target(ardupilot_configure ALL
+ ${WAF_COMMAND} configure --board sitl --enable-dds ${WAF_CONFIG}
+ WORKING_DIRECTORY ${ARDUPILOT_ROOT}
+)
+
+add_custom_target(ardupilot_build ALL
+ ${WAF_COMMAND} build --enable-dds ${WAF_CONFIG}
+ WORKING_DIRECTORY ${ARDUPILOT_ROOT}
+)
+add_dependencies(ardupilot_build ardupilot_configure)
+
+# --------------------------------------------------------------------------- #
+# Install.
+
+# Install executables.
+install(PROGRAMS
+ ${ARDUPILOT_ROOT}/build/sitl/bin/antennatracker
+ ${ARDUPILOT_ROOT}/build/sitl/bin/arducopter
+ ${ARDUPILOT_ROOT}/build/sitl/bin/arducopter-heli
+ ${ARDUPILOT_ROOT}/build/sitl/bin/arduplane
+ ${ARDUPILOT_ROOT}/build/sitl/bin/ardurover
+ ${ARDUPILOT_ROOT}/build/sitl/bin/ardusub
+ ${ARDUPILOT_ROOT}/build/sitl/bin/blimp
+ DESTINATION bin/
+)
+
+# Install libs.
+install(DIRECTORY
+ ${ARDUPILOT_ROOT}/build/sitl/lib
+ DESTINATION ./
+)
+
+# Install launch files.
+install(DIRECTORY
+ launch
+ DESTINATION share/${PROJECT_NAME}/
+)
+
+# Install DDS profile.
+install(FILES
+ ${ARDUPILOT_ROOT}/libraries/AP_DDS/dds_xrce_profile.xml
+ DESTINATION share/${PROJECT_NAME}/config
+)
+
+# Install additional default params.
+install(DIRECTORY
+ config/default_params
+ DESTINATION share/${PROJECT_NAME}/config
+)
+
+# Install autotest default params.
+install(DIRECTORY
+ ${ARDUPILOT_ROOT}/Tools/autotest/default_params
+ DESTINATION share/${PROJECT_NAME}/config/
+)
+
+# Install Python package.
+ament_python_install_package(${PROJECT_NAME}
+ PACKAGE_DIR src/${PROJECT_NAME}
+)
+
+# --------------------------------------------------------------------------- #
+# build tests
+
+if(BUILD_TESTING)
+ # Override default flake8 configuration.
+ set(ament_cmake_flake8_CONFIG_FILE ${CMAKE_SOURCE_DIR}/.flake8)
+
+ # Add linters.
+ find_package(ament_lint_auto REQUIRED)
+ ament_lint_auto_find_test_dependencies()
+
+ # Add python tests.
+ find_package(ament_cmake_pytest REQUIRED)
+ set(_pytest_tests
+ # Add tests here, for example:
+ # tests/test_a.py
+ )
+ foreach(_test_path ${_pytest_tests})
+ get_filename_component(_test_name ${_test_path} NAME_WE)
+ ament_add_pytest_test(${_test_name} ${_test_path}
+ APPEND_ENV PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR}
+ TIMEOUT 60
+ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
+ )
+ endforeach()
+endif()
+
+# --------------------------------------------------------------------------- #
+# Call last.
+
+ament_package()
diff --git a/Tools/ros2/ardupilot_sitl/config/copter_quad.yaml b/Tools/ros2/ardupilot_sitl/config/copter_quad.yaml
new file mode 100644
index 00000000000000..02ad121f3a9c95
--- /dev/null
+++ b/Tools/ros2/ardupilot_sitl/config/copter_quad.yaml
@@ -0,0 +1,23 @@
+/sitl:
+ wipe: true
+ speedup: 1
+ instance: 0
+ synthetic_clock: true
+ model: quad
+ slave: 0
+ sim_address: 127.0.0.1
+ defaults: copter.parm
+
+ # unused
+ # rate: 400
+ # console: true
+ # home: [lat, lon, alt, yaw]
+ # uartA: /dev/tty0
+ # uartB: /dev/tty1
+ # serial0: /dev/usb0
+ # serial1: /dev/usb1
+ # sim_port_in: 5501
+ # sim_port_out: 5501
+ # irlock_port: 5501
+ # sysid: 255
+
diff --git a/Tools/ros2/ardupilot_sitl/config/default_params/dds_serial.parm b/Tools/ros2/ardupilot_sitl/config/default_params/dds_serial.parm
new file mode 100644
index 00000000000000..89f2b3cf8e3568
--- /dev/null
+++ b/Tools/ros2/ardupilot_sitl/config/default_params/dds_serial.parm
@@ -0,0 +1,3 @@
+DDS_ENABLE 1
+SERIAL1_BAUD 115
+SERIAL1_PROTOCOL 45
diff --git a/Tools/ros2/ardupilot_sitl/config/default_params/dds_udp.parm b/Tools/ros2/ardupilot_sitl/config/default_params/dds_udp.parm
new file mode 100644
index 00000000000000..81c3e69cd9e15b
--- /dev/null
+++ b/Tools/ros2/ardupilot_sitl/config/default_params/dds_udp.parm
@@ -0,0 +1,2 @@
+DDS_ENABLE 1
+DDS_PORT 2019
diff --git a/Tools/ros2/ardupilot_sitl/launch/mavproxy.launch.py b/Tools/ros2/ardupilot_sitl/launch/mavproxy.launch.py
new file mode 100644
index 00000000000000..47c3ee1b0b6f22
--- /dev/null
+++ b/Tools/ros2/ardupilot_sitl/launch/mavproxy.launch.py
@@ -0,0 +1,33 @@
+# Copyright 2023 ArduPilot.org.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+"""
+Launch a non-interactive instance of MAVProxy.
+
+Run with default arguments:
+
+ros2 launch ardupilot_sitl mavproxy.launch.py
+
+Show launch arguments:
+
+ros2 launch ardupilot_sitl mavproxy.launch.py --show-args
+"""
+from launch import LaunchDescription
+from ardupilot_sitl.launch import MAVProxyLaunch
+
+
+def generate_launch_description() -> LaunchDescription:
+ """Generate a launch description for MAVProxy."""
+ return MAVProxyLaunch.generate_launch_description()
diff --git a/Tools/ros2/ardupilot_sitl/launch/micro_ros_agent.launch.py b/Tools/ros2/ardupilot_sitl/launch/micro_ros_agent.launch.py
new file mode 100644
index 00000000000000..c5ab775bda032d
--- /dev/null
+++ b/Tools/ros2/ardupilot_sitl/launch/micro_ros_agent.launch.py
@@ -0,0 +1,29 @@
+# Copyright 2023 ArduPilot.org.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+"""
+Launch the microROS DDS agent.
+
+Run with default arguments:
+
+ros2 launch ardupilot_sitl micro_ros_agent.launch.py
+"""
+from launch import LaunchDescription
+from ardupilot_sitl.launch import MicroRosAgentLaunch
+
+
+def generate_launch_description() -> LaunchDescription:
+ """Generate a launch description for the micro_ros_agent."""
+ return MicroRosAgentLaunch.generate_launch_description()
diff --git a/Tools/ros2/ardupilot_sitl/launch/sitl.launch.py b/Tools/ros2/ardupilot_sitl/launch/sitl.launch.py
new file mode 100644
index 00000000000000..9cbbdc269f17fa
--- /dev/null
+++ b/Tools/ros2/ardupilot_sitl/launch/sitl.launch.py
@@ -0,0 +1,33 @@
+# Copyright 2023 ArduPilot.org.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+"""
+Launch ArduPilot SITL.
+
+Run with default arguments:
+
+ros2 launch ardupilot_sitl sitl.launch.py
+
+Show launch arguments:
+
+ros2 launch ardupilot_sitl sitl.launch.py --show-args
+"""
+from launch import LaunchDescription
+from ardupilot_sitl.launch import SITLLaunch
+
+
+def generate_launch_description() -> LaunchDescription:
+ """Generate a launch description for ArduPilot SITL."""
+ return SITLLaunch.generate_launch_description()
diff --git a/Tools/ros2/ardupilot_sitl/launch/sitl_dds_serial.launch.py b/Tools/ros2/ardupilot_sitl/launch/sitl_dds_serial.launch.py
new file mode 100644
index 00000000000000..2a9507e5eb37cd
--- /dev/null
+++ b/Tools/ros2/ardupilot_sitl/launch/sitl_dds_serial.launch.py
@@ -0,0 +1,94 @@
+# Copyright 2023 ArduPilot.org.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+"""
+Launch ArduPilot SITL, MAVProxy and the microROS DDS agent.
+
+Run with default arguments:
+
+ros2 launch ardupilot_sitl sitl_dds_serial.launch.py
+"""
+from launch import LaunchDescription
+from launch.actions import IncludeLaunchDescription
+from launch.launch_description_sources import PythonLaunchDescriptionSource
+from launch.substitutions import PathJoinSubstitution
+
+from launch_ros.substitutions import FindPackageShare
+
+
+def generate_launch_description() -> LaunchDescription:
+ """Generate a launch description to bring up ArduPilot SITL with DDS."""
+ # Compose launch files.
+ virtual_ports = IncludeLaunchDescription(
+ PythonLaunchDescriptionSource(
+ [
+ PathJoinSubstitution(
+ [
+ FindPackageShare("ardupilot_sitl"),
+ "launch",
+ "virtual_ports.launch.py",
+ ]
+ ),
+ ]
+ )
+ )
+ micro_ros_agent = IncludeLaunchDescription(
+ PythonLaunchDescriptionSource(
+ [
+ PathJoinSubstitution(
+ [
+ FindPackageShare("ardupilot_sitl"),
+ "launch",
+ "micro_ros_agent.launch.py",
+ ]
+ ),
+ ]
+ )
+ )
+ sitl = IncludeLaunchDescription(
+ PythonLaunchDescriptionSource(
+ [
+ PathJoinSubstitution(
+ [
+ FindPackageShare("ardupilot_sitl"),
+ "launch",
+ "sitl.launch.py",
+ ]
+ ),
+ ]
+ )
+ )
+ mavproxy = IncludeLaunchDescription(
+ PythonLaunchDescriptionSource(
+ [
+ PathJoinSubstitution(
+ [
+ FindPackageShare("ardupilot_sitl"),
+ "launch",
+ "mavproxy.launch.py",
+ ]
+ ),
+ ]
+ )
+ )
+
+ return LaunchDescription(
+ [
+ virtual_ports,
+ micro_ros_agent,
+ sitl,
+ mavproxy,
+ ]
+ )
diff --git a/Tools/ros2/ardupilot_sitl/launch/sitl_dds_udp.launch.py b/Tools/ros2/ardupilot_sitl/launch/sitl_dds_udp.launch.py
new file mode 100644
index 00000000000000..79b1492382a5c9
--- /dev/null
+++ b/Tools/ros2/ardupilot_sitl/launch/sitl_dds_udp.launch.py
@@ -0,0 +1,80 @@
+# Copyright 2023 ArduPilot.org.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+"""
+Launch ArduPilot SITL, MAVProxy and the microROS DDS agent.
+
+Run with default arguments:
+
+ros2 launch ardupilot_sitl sitl_dds_udp.launch.py
+"""
+from launch import LaunchDescription
+from launch.actions import IncludeLaunchDescription
+from launch.launch_description_sources import PythonLaunchDescriptionSource
+from launch.substitutions import PathJoinSubstitution
+
+from launch_ros.substitutions import FindPackageShare
+
+
+def generate_launch_description() -> LaunchDescription:
+ """Generate a launch description to bring up ArduPilot SITL with DDS."""
+ # Compose launch files.
+ micro_ros_agent = IncludeLaunchDescription(
+ PythonLaunchDescriptionSource(
+ [
+ PathJoinSubstitution(
+ [
+ FindPackageShare("ardupilot_sitl"),
+ "launch",
+ "micro_ros_agent.launch.py",
+ ]
+ ),
+ ]
+ )
+ )
+ sitl = IncludeLaunchDescription(
+ PythonLaunchDescriptionSource(
+ [
+ PathJoinSubstitution(
+ [
+ FindPackageShare("ardupilot_sitl"),
+ "launch",
+ "sitl.launch.py",
+ ]
+ ),
+ ]
+ )
+ )
+ mavproxy = IncludeLaunchDescription(
+ PythonLaunchDescriptionSource(
+ [
+ PathJoinSubstitution(
+ [
+ FindPackageShare("ardupilot_sitl"),
+ "launch",
+ "mavproxy.launch.py",
+ ]
+ ),
+ ]
+ )
+ )
+
+ return LaunchDescription(
+ [
+ micro_ros_agent,
+ sitl,
+ mavproxy,
+ ]
+ )
diff --git a/Tools/ros2/ardupilot_sitl/launch/sitl_mavproxy.launch.py b/Tools/ros2/ardupilot_sitl/launch/sitl_mavproxy.launch.py
new file mode 100644
index 00000000000000..50c22371409579
--- /dev/null
+++ b/Tools/ros2/ardupilot_sitl/launch/sitl_mavproxy.launch.py
@@ -0,0 +1,61 @@
+# Copyright 2023 ArduPilot.org.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+"""
+Launch ArduPilot SITL and a non-interactive instance of MAVProxy.
+
+Run with default arguments:
+
+ros2 launch ardupilot_sitl sitl_mavproxy.launch.py
+"""
+from launch import LaunchDescription
+from launch.actions import IncludeLaunchDescription
+from launch.launch_description_sources import PythonLaunchDescriptionSource
+from launch.substitutions import PathJoinSubstitution
+
+from launch_ros.substitutions import FindPackageShare
+
+
+def generate_launch_description() -> LaunchDescription:
+ """Generate a launch description for combined SITL and MAVProxy."""
+ # Compose launch files.
+ sitl = IncludeLaunchDescription(
+ PythonLaunchDescriptionSource(
+ [
+ PathJoinSubstitution(
+ [
+ FindPackageShare("ardupilot_sitl"),
+ "launch",
+ "sitl.launch.py",
+ ]
+ ),
+ ]
+ )
+ )
+ mavproxy = IncludeLaunchDescription(
+ PythonLaunchDescriptionSource(
+ [
+ PathJoinSubstitution(
+ [
+ FindPackageShare("ardupilot_sitl"),
+ "launch",
+ "mavproxy.launch.py",
+ ]
+ ),
+ ]
+ )
+ )
+
+ return LaunchDescription([sitl, mavproxy])
diff --git a/Tools/ros2/ardupilot_sitl/launch/virtual_ports.launch.py b/Tools/ros2/ardupilot_sitl/launch/virtual_ports.launch.py
new file mode 100644
index 00000000000000..d1b771f6bb1e96
--- /dev/null
+++ b/Tools/ros2/ardupilot_sitl/launch/virtual_ports.launch.py
@@ -0,0 +1,29 @@
+# Copyright 2023 ArduPilot.org.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+"""
+Launch a process to create virtual ports.
+
+Run with default arguments:
+
+ros2 launch ardupilot_sitl virtual_ports.launch.py
+"""
+from launch import LaunchDescription
+from ardupilot_sitl.launch import VirtualPortsLaunch
+
+
+def generate_launch_description() -> LaunchDescription:
+ """Generate a launch description for creating virtual ports using `socat`."""
+ return VirtualPortsLaunch.generate_launch_description()
diff --git a/Tools/ros2/ardupilot_sitl/package.xml b/Tools/ros2/ardupilot_sitl/package.xml
new file mode 100644
index 00000000000000..21ae2dfa2975ed
--- /dev/null
+++ b/Tools/ros2/ardupilot_sitl/package.xml
@@ -0,0 +1,21 @@
+
+
+
+ ardupilot_sitl
+ 0.0.0
+ ArduPlane, ArduCopter, ArduRover, ArduSub source
+ maintainer
+ GPL-3.0
+
+ ament_cmake
+ ament_cmake_python
+
+ ament_cmake_pytest
+ ament_lint_auto
+ ament_lint_common
+
+
+ ament_cmake
+
+
diff --git a/Tools/ros2/ardupilot_sitl/src/ardupilot_sitl/__init__.py b/Tools/ros2/ardupilot_sitl/src/ardupilot_sitl/__init__.py
new file mode 100644
index 00000000000000..9691b39d98099f
--- /dev/null
+++ b/Tools/ros2/ardupilot_sitl/src/ardupilot_sitl/__init__.py
@@ -0,0 +1,16 @@
+# Copyright 2023 ArduPilot.org.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+"""Main entry point for the `ardupilot_sitl` package."""
diff --git a/Tools/ros2/ardupilot_sitl/src/ardupilot_sitl/actions.py b/Tools/ros2/ardupilot_sitl/src/ardupilot_sitl/actions.py
new file mode 100644
index 00000000000000..928a5117421231
--- /dev/null
+++ b/Tools/ros2/ardupilot_sitl/src/ardupilot_sitl/actions.py
@@ -0,0 +1,107 @@
+# Copyright 2023 ArduPilot.org.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+# Adapted from launch.actions.opaque_function.py
+
+# Copyright 2018 Open Source Robotics Foundation, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Module for the OpaqueFunction action."""
+
+import collections.abc
+from typing import Any
+from typing import Callable
+from typing import Dict
+from typing import Iterable
+from typing import List
+from typing import Optional
+from typing import Text
+
+from launch.action import Action
+from launch.launch_context import LaunchContext
+from launch.launch_description_entity import LaunchDescriptionEntity
+from launch.utilities import ensure_argument_type
+
+
+class ExecuteFunction(Action):
+ """
+ Action that executes a Python function.
+
+ The signature of the function should be:
+
+ .. code-block:: python
+
+ def function(
+ context: LaunchContext,
+ *args,
+ **kwargs
+ ) -> Optional[Action]:
+ ...
+
+ """
+
+ def __init__(
+ self,
+ *,
+ function: Callable,
+ args: Optional[Iterable[Any]] = None,
+ kwargs: Optional[Dict[Text, Any]] = None,
+ **left_over_kwargs
+ ) -> None:
+ """Create an ExecuteFunction action."""
+ super().__init__(**left_over_kwargs)
+ if not callable(function):
+ raise TypeError(
+ "ExecuteFunction expected a callable for 'function', got '{}'".format(
+ type(function)
+ )
+ )
+ ensure_argument_type(
+ args, (collections.abc.Iterable, type(None)), "args", "ExecuteFunction"
+ )
+ ensure_argument_type(kwargs, (dict, type(None)), "kwargs", "ExecuteFunction")
+ self.__function = function
+ self.__args = [] # type: Iterable
+ if args is not None:
+ self.__args = args
+ self.__kwargs = {} # type: Dict[Text, Any]
+ if kwargs is not None:
+ self.__kwargs = kwargs
+
+ self.__action = None
+
+ @property
+ def action(self) -> Action:
+ """Return the Action obtained by executing the function."""
+ return self.__action
+
+ def execute(
+ self, context: LaunchContext
+ ) -> Optional[List[LaunchDescriptionEntity]]:
+ """Execute the function."""
+ action = self.__function(context, *self.__args, **self.__kwargs)
+ self.__action = action
+ return [action]
diff --git a/Tools/ros2/ardupilot_sitl/src/ardupilot_sitl/launch.py b/Tools/ros2/ardupilot_sitl/src/ardupilot_sitl/launch.py
new file mode 100644
index 00000000000000..0d15ab4ac3c5f8
--- /dev/null
+++ b/Tools/ros2/ardupilot_sitl/src/ardupilot_sitl/launch.py
@@ -0,0 +1,657 @@
+# Copyright 2023 ArduPilot.org.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+"""Launch actions for ArduPilot."""
+from typing import List
+from typing import Dict
+from typing import Text
+from typing import Tuple
+
+from launch import LaunchContext
+from launch import LaunchDescription
+from launch.actions import ExecuteProcess
+from launch.actions import DeclareLaunchArgument
+from launch.substitutions import LaunchConfiguration
+from launch.substitutions import PathJoinSubstitution
+
+from launch_ros.actions import Node
+from launch_ros.substitutions import FindPackageShare
+
+from .actions import ExecuteFunction
+
+
+class VirtualPortsLaunch:
+ """Launch functions for creating virtual ports using `socat`."""
+
+ @staticmethod
+ def generate_action(context: LaunchContext, *args, **kwargs) -> ExecuteProcess:
+ """Generate a launch action."""
+ # Declare commands.
+ command = "socat"
+
+ # Retrieve launch arguments.
+ tty0 = LaunchConfiguration("tty0").perform(context)
+ tty1 = LaunchConfiguration("tty1").perform(context)
+
+ # Display launch arguments.
+ print(f"command: {command}")
+ print(f"tty0: {tty0}")
+ print(f"tty1: {tty1}")
+
+ # Create action.
+ action = ExecuteProcess(
+ cmd=[
+ [
+ "socat ",
+ "-d -d ",
+ f"pty,raw,echo=0,link={tty0} ",
+ f"pty,raw,echo=0,link={tty1} ",
+ ]
+ ],
+ shell=True,
+ output="both",
+ respawn=False,
+ cached_output=True,
+ )
+ return action
+
+ @staticmethod
+ def generate_launch_description_with_actions() -> (
+ Tuple[LaunchDescription, Dict[Text, ExecuteFunction]]
+ ):
+ """Generate a launch description with actions."""
+ launch_arguments = VirtualPortsLaunch.generate_launch_arguments()
+
+ action = ExecuteFunction(function=VirtualPortsLaunch.generate_action)
+
+ ld = LaunchDescription(
+ launch_arguments
+ + [
+ action,
+ ]
+ )
+ actions = {
+ "virtual_ports": action,
+ }
+ return ld, actions
+
+ @staticmethod
+ def generate_launch_description() -> LaunchDescription:
+ """Generate a launch description."""
+ ld, _ = VirtualPortsLaunch.generate_launch_description_with_actions()
+ return ld
+
+ @staticmethod
+ def generate_launch_arguments() -> List[DeclareLaunchArgument]:
+ """Generate a list of launch arguments."""
+ return [
+ DeclareLaunchArgument(
+ "tty0",
+ default_value="tty0",
+ description="Symbolic link name for tty0.",
+ ),
+ DeclareLaunchArgument(
+ "tty1",
+ default_value="tty1",
+ description="Symbolic link name for tty1.",
+ ),
+ ]
+
+
+class MicroRosAgentLaunch:
+ """Launch functions for the micro ROS agent node."""
+
+ @staticmethod
+ def generate_action(context: LaunchContext, *args, **kwargs) -> ExecuteProcess:
+ """Launch the micro_ros_agent node."""
+ # ROS arguments.
+ micro_ros_agent_ns = LaunchConfiguration("micro_ros_agent_ns").perform(context)
+
+ # Common arguments.
+ transport = LaunchConfiguration("transport").perform(context)
+ middleware = LaunchConfiguration("middleware").perform(context)
+ verbose = LaunchConfiguration("verbose").perform(context)
+ discovery = LaunchConfiguration("discovery").perform(context)
+
+ # IPvX arguments.
+ port = LaunchConfiguration("port").perform(context)
+
+ # Serial arguments.
+ device = LaunchConfiguration("device").perform(context)
+ baudrate = LaunchConfiguration("baudrate").perform(context)
+
+ # Display launch arguments.
+ print(f"namespace: {micro_ros_agent_ns}")
+ print(f"transport: {transport}")
+ print(f"middleware: {middleware}")
+ print(f"verbose: {verbose}")
+ print(f"discovery: {discovery}")
+
+ # Required arguments
+ args = [
+ transport,
+ "--middleware",
+ middleware,
+ ]
+
+ if transport in ["udp4", "udp6", "tcp4", "tcp6"]:
+ # IPvX arguments
+ port = LaunchConfiguration("port").perform(context)
+ args.append("--port")
+ args.append(port)
+ print(f"port: {port}")
+ elif transport in ["serial", "multiserial", "pseudoterminal"]:
+ # Serial arguments
+ baudrate = LaunchConfiguration("baudrate").perform(context)
+ args.append("--baudrate")
+ args.append(baudrate)
+ print(f"baudrate: {baudrate}")
+
+ device = LaunchConfiguration("device").perform(context)
+ args.append("--dev")
+ args.append(device)
+ print(f"device: {device}")
+ else:
+ # transport must be canfd
+ pass
+
+ # Optional arguments.
+ refs = LaunchConfiguration("refs").perform(context)
+ if refs:
+ args.append("--refs")
+ args.append(refs)
+ print(f"refs: {refs}")
+
+ # Create action.
+ node = Node(
+ package="micro_ros_agent",
+ executable="micro_ros_agent",
+ name="micro_ros_agent",
+ namespace=f"{micro_ros_agent_ns}",
+ output="both",
+ arguments=args,
+ )
+ return node
+
+ @staticmethod
+ def generate_launch_description_with_actions() -> (
+ Tuple[LaunchDescription, Dict[Text, ExecuteFunction]]
+ ):
+ """Generate a launch description with actions."""
+ launch_arguments = MicroRosAgentLaunch.generate_launch_arguments()
+
+ action = ExecuteFunction(function=MicroRosAgentLaunch.generate_action)
+
+ ld = LaunchDescription(
+ launch_arguments
+ + [
+ action,
+ ]
+ )
+ actions = {
+ "micro_ros_agent": action,
+ }
+ return ld, actions
+
+ @staticmethod
+ def generate_launch_description() -> LaunchDescription:
+ """Generate a launch description."""
+ ld, _ = MicroRosAgentLaunch.generate_launch_description_with_actions()
+ return ld
+
+ @staticmethod
+ def generate_launch_arguments() -> List[DeclareLaunchArgument]:
+ """Generate a list of launch arguments."""
+ return [
+ DeclareLaunchArgument(
+ "micro_ros_agent_ns",
+ default_value="",
+ description="Set the micro_ros_agent namespace.",
+ ),
+ DeclareLaunchArgument(
+ "transport",
+ default_value="udp4",
+ description="Set the transport.",
+ choices=[
+ "udp4",
+ "udp6",
+ "tcp4",
+ "tcp6",
+ "canfd",
+ "serial",
+ "multiserial",
+ "pseudoterminal",
+ ],
+ ),
+ DeclareLaunchArgument(
+ "middleware",
+ default_value="dds",
+ description="Set the middleware.",
+ choices=["ced", "dds", "rtps"],
+ ),
+ DeclareLaunchArgument(
+ "refs",
+ default_value="",
+ description="Set the refs file.",
+ ),
+ DeclareLaunchArgument(
+ "verbose",
+ default_value="4",
+ description="Set the verbosity level.",
+ choices=["0", "1", "2", "3", "4", "5", "6"],
+ ),
+ DeclareLaunchArgument(
+ "discovery",
+ default_value="7400",
+ description="Set the dsicovery port.",
+ ),
+ DeclareLaunchArgument(
+ "port",
+ default_value="2019",
+ description="Set the port number.",
+ ),
+ DeclareLaunchArgument(
+ "baudrate",
+ default_value="115200",
+ description="Set the baudrate.",
+ ),
+ DeclareLaunchArgument(
+ "device",
+ default_value="",
+ description="Set the device.",
+ ),
+ ]
+
+
+class MAVProxyLaunch:
+ """Launch functions for MAVProxy."""
+
+ @staticmethod
+ def generate_action(context: LaunchContext, *args, **kwargs) -> ExecuteProcess:
+ """Return a non-interactive MAVProxy process."""
+ # Declare the command.
+ command = "mavproxy.py"
+
+ # Retrieve launch arguments.
+ master = LaunchConfiguration("master").perform(context)
+ # out = LaunchConfiguration("out").perform(context)
+ sitl = LaunchConfiguration("sitl").perform(context)
+
+ # Display launch arguments.
+ print(f"command: {command}")
+ print(f"master: {master}")
+ print(f"sitl: {sitl}")
+
+ # Create action.
+ mavproxy_process = ExecuteProcess(
+ cmd=[
+ [
+ f"{command} ",
+ "--out ",
+ "127.0.0.1:14550 ",
+ "--out ",
+ "127.0.0.1:14551 ",
+ f"--master {master} ",
+ f"--sitl {sitl} ",
+ "--non-interactive ",
+ ]
+ ],
+ shell=True,
+ output="both",
+ respawn=False,
+ )
+ return mavproxy_process
+
+ @staticmethod
+ def generate_launch_description_with_actions() -> (
+ Tuple[LaunchDescription, Dict[Text, ExecuteFunction]]
+ ):
+ """Generate a launch description for MAVProxy."""
+ launch_arguments = MAVProxyLaunch.generate_launch_arguments()
+
+ action = ExecuteFunction(function=MAVProxyLaunch.generate_action)
+
+ ld = LaunchDescription(
+ launch_arguments
+ + [
+ action,
+ ]
+ )
+ actions = {
+ "mavproxy": action,
+ }
+ return ld, actions
+
+ @staticmethod
+ def generate_launch_description() -> LaunchDescription:
+ """Generate a launch description."""
+ ld, _ = MAVProxyLaunch.generate_launch_description_with_actions()
+ return ld
+
+ @staticmethod
+ def generate_launch_arguments() -> List[DeclareLaunchArgument]:
+ """Generate a list of launch arguments."""
+ return [
+ DeclareLaunchArgument(
+ "master",
+ default_value="tcp:127.0.0.1:5760",
+ description="MAVLink master port and optional baud rate.",
+ ),
+ DeclareLaunchArgument(
+ "out",
+ default_value="127.0.0.1:14550",
+ description="MAVLink output port and optional baud rate.",
+ ),
+ DeclareLaunchArgument(
+ "sitl",
+ default_value="127.0.0.1:5501",
+ description="SITL output port.",
+ ),
+ ]
+
+
+class SITLLaunch:
+ """Launch functions for ArduPilot SITL."""
+
+ # Labels for the optional uart launch arguments.
+ UART_LABELS = ["A", "B", "C", "D", "E", "F", "H", "I", "J"]
+ MAX_SERIAL_PORTS = 10
+
+ @staticmethod
+ def generate_action(context: LaunchContext, *args, **kwargs) -> ExecuteProcess:
+ """Return a SITL process."""
+ # Retrieve launch arguments.
+ command = LaunchConfiguration("command").perform(context)
+ model = LaunchConfiguration("model").perform(context)
+ speedup = LaunchConfiguration("speedup").perform(context)
+ slave = LaunchConfiguration("slave").perform(context)
+ sim_address = LaunchConfiguration("sim_address").perform(context)
+ instance = LaunchConfiguration("instance").perform(context)
+ defaults = LaunchConfiguration("defaults").perform(context)
+
+ # Display launch arguments.
+ print(f"command: {command}")
+ print(f"model: {model}")
+ print(f"speedup: {speedup}")
+ print(f"slave: {slave}")
+ print(f"sim_address: {sim_address}")
+ print(f"instance: {instance}")
+ print(f"defaults: {defaults}")
+
+ # Required arguments.
+ cmd_args = [
+ f"{command} ",
+ f"--model {model} ",
+ f"--speedup {speedup} ",
+ f"--slave {slave} ",
+ f"--sim-address={sim_address} ",
+ f"--instance {instance} ",
+ f"--defaults {defaults} ",
+ ]
+
+ # Optional arguments.
+ wipe = LaunchConfiguration("wipe").perform(context)
+ if wipe == "True":
+ cmd_args.append("--wipe ")
+ print(f"wipe: {wipe}")
+
+ synthetic_clock = LaunchConfiguration("synthetic_clock").perform(context)
+ if synthetic_clock == "True":
+ cmd_args.append("--synthetic-clock ")
+ print(f"synthetic_clock: {synthetic_clock}")
+
+ home = LaunchConfiguration("home").perform(context)
+ if home:
+ cmd_args.append(f"--home {home} ")
+ print(f"home: {home}")
+
+ # Optional uart arguments.
+ for label in SITLLaunch.UART_LABELS:
+ arg = LaunchConfiguration(f"uart{label}").perform(context)
+ if arg:
+ cmd_args.append(f"--uart{label} {arg} ")
+ print(f"uart{label}: {arg}")
+
+ # Optional serial arguments.
+ for label in range(10):
+ arg = LaunchConfiguration(f"serial{label}").perform(context)
+ if arg:
+ cmd_args.append(f"--serial{label} {arg} ")
+ print(f"serial{label}: {arg}")
+
+ rate = LaunchConfiguration("rate").perform(context)
+ if rate:
+ cmd_args.append(f"--rate {rate} ")
+ print(f"rate: {rate}")
+
+ gimbal = LaunchConfiguration("gimbal").perform(context)
+ if gimbal:
+ cmd_args.append(f"--gimbal {gimbal} ")
+ print(f"gimbal: {gimbal}")
+
+ base_port = LaunchConfiguration("base_port").perform(context)
+ if base_port:
+ cmd_args.append(f"--base-port {base_port} ")
+ print(f"base_port: {base_port}")
+
+ rc_in_port = LaunchConfiguration("rc_in_port").perform(context)
+ if rc_in_port:
+ cmd_args.append(f"--rc-in-port {rc_in_port} ")
+ print(f"rc_in_port: {rc_in_port}")
+
+ sim_port_in = LaunchConfiguration("sim_port_in").perform(context)
+ if sim_port_in:
+ cmd_args.append(f"--sim-port-in {sim_port_in} ")
+ print(f"sim_port_in: {sim_port_in}")
+
+ sim_port_out = LaunchConfiguration("sim_port_out").perform(context)
+ if sim_port_out:
+ cmd_args.append(f"--sim-port-out {sim_port_out} ")
+ print(f"sim_port_out: {sim_port_out}")
+
+ irlock_port = LaunchConfiguration("irlock_port").perform(context)
+ if irlock_port:
+ cmd_args.append(f"--irlock-port {irlock_port} ")
+ print(f"irlock_port: {irlock_port}")
+
+ start_time = LaunchConfiguration("start_time").perform(context)
+ if start_time:
+ cmd_args.append(f"--start-time {start_time} ")
+ print(f"start_time: {start_time}")
+
+ sysid = LaunchConfiguration("sysid").perform(context)
+ if sysid:
+ cmd_args.append(f"--sysid {sysid} ")
+ print(f"sysid: {sysid}")
+
+ # Create action.
+ sitl_process = ExecuteProcess(
+ cmd=[cmd_args],
+ shell=True,
+ output="both",
+ respawn=False,
+ )
+ return sitl_process
+
+ @staticmethod
+ def generate_launch_description_with_actions() -> (
+ Tuple[LaunchDescription, Dict[Text, ExecuteFunction]]
+ ):
+ """Generate a launch description for SITL."""
+ launch_arguments = SITLLaunch.generate_launch_arguments()
+
+ action = ExecuteFunction(function=SITLLaunch.generate_action)
+
+ ld = LaunchDescription(
+ launch_arguments
+ + [
+ action,
+ ]
+ )
+ actions = {
+ "sitl": action,
+ }
+ return ld, actions
+
+ @staticmethod
+ def generate_launch_description() -> LaunchDescription:
+ """Generate a launch description."""
+ ld, _ = SITLLaunch.generate_launch_description_with_actions()
+ return ld
+
+ @staticmethod
+ def generate_launch_arguments() -> List[DeclareLaunchArgument]:
+ """Generate a list of launch arguments."""
+ launch_args = [
+ # Required launch arguments.
+ DeclareLaunchArgument(
+ "command",
+ default_value="arducopter",
+ description="Run ArduPilot SITL.",
+ choices=[
+ "antennatracker",
+ "arducopter-heli",
+ "ardurover",
+ "blimp",
+ "arducopter",
+ "arduplane",
+ "ardusub",
+ ],
+ ),
+ DeclareLaunchArgument(
+ "model",
+ default_value="quad",
+ description="Set simulation model.",
+ ),
+ DeclareLaunchArgument(
+ "slave",
+ default_value="0",
+ description="Set the number of JSON slaves.",
+ ),
+ DeclareLaunchArgument(
+ "sim_address",
+ default_value="127.0.0.1",
+ description="Set address string for simulator.",
+ ),
+ DeclareLaunchArgument(
+ "speedup",
+ default_value="1",
+ description="Set simulation speedup.",
+ ),
+ DeclareLaunchArgument(
+ "instance",
+ default_value="0",
+ description="Set instance of SITL "
+ "(adds 10*instance to all port numbers).",
+ ),
+ DeclareLaunchArgument(
+ "defaults",
+ default_value=PathJoinSubstitution(
+ [
+ FindPackageShare("ardupilot_sitl"),
+ "config",
+ "default_params",
+ "copter.parm",
+ ]
+ ),
+ description="Set path to defaults file.",
+ ),
+ # Optional launch arguments.
+ DeclareLaunchArgument(
+ "wipe",
+ default_value="False",
+ description="Wipe eeprom.",
+ choices=["True", "False"],
+ ),
+ DeclareLaunchArgument(
+ "synthetic_clock",
+ default_value="False",
+ description="Set synthetic clock mode.",
+ choices=["True", "False"],
+ ),
+ DeclareLaunchArgument(
+ "home",
+ default_value="",
+ description="Set start location (lat,lng,alt,yaw) or location name.",
+ ),
+ DeclareLaunchArgument(
+ "rate",
+ default_value="",
+ description="Set SITL framerate.",
+ ),
+ DeclareLaunchArgument(
+ "gimbal",
+ default_value="",
+ description="Enable simulated MAVLink gimbal.",
+ ),
+ DeclareLaunchArgument(
+ "base_port",
+ default_value="",
+ description="Set port num for base port(default 5670) "
+ "must be before -I option.",
+ ),
+ DeclareLaunchArgument(
+ "rc_in_port",
+ default_value="",
+ description="Set port num for rc in.",
+ ),
+ DeclareLaunchArgument(
+ "sim_port_in",
+ default_value="",
+ description="Set port num for simulator in.",
+ ),
+ DeclareLaunchArgument(
+ "sim_port_out",
+ default_value="",
+ description="Set port num for simulator out.",
+ ),
+ DeclareLaunchArgument(
+ "irlock_port",
+ default_value="",
+ description="Set port num for irlock.",
+ ),
+ DeclareLaunchArgument(
+ "start_time",
+ default_value="",
+ description="Set simulation start time in UNIX timestamp.",
+ ),
+ DeclareLaunchArgument(
+ "sysid",
+ default_value="",
+ description="Set SYSID_THISMAV.",
+ ),
+ ]
+
+ # UART launch arguments.
+ uart_args = []
+ for label in SITLLaunch.UART_LABELS:
+ arg = DeclareLaunchArgument(
+ f"uart{label}",
+ default_value="",
+ description=f"set device string for UART{label}.",
+ )
+ uart_args.append(arg)
+
+ # Serial launch arguments.
+ serial_args = []
+ for label in range(SITLLaunch.MAX_SERIAL_PORTS):
+ arg = DeclareLaunchArgument(
+ f"serial{label}",
+ default_value="",
+ description=f"set device string for SERIAL{label}.",
+ )
+ serial_args.append(arg)
+
+ return launch_args + uart_args + serial_args
diff --git a/Tools/ros2/ardupilot_sitl/src/ardupilot_sitl/utilities.py b/Tools/ros2/ardupilot_sitl/src/ardupilot_sitl/utilities.py
new file mode 100644
index 00000000000000..10a4396e9f6633
--- /dev/null
+++ b/Tools/ros2/ardupilot_sitl/src/ardupilot_sitl/utilities.py
@@ -0,0 +1,37 @@
+# Copyright 2023 ArduPilot.org.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+"""Utilities."""
+from functools import wraps
+from typing import List
+
+from launch import LaunchContext
+from launch import LaunchDescriptionEntity
+
+
+# Adapted from a SO answer by David Wolever.
+# Is there a library function in Python to turn a generator-function
+# into a function returning a list?
+# https://stackoverflow.com/questions/12377013
+def listify(fn) -> List[LaunchDescriptionEntity]:
+ """Wrap a functions's return value in a list."""
+
+ @wraps(fn)
+ def listify_helper(
+ context: LaunchContext, *args, **kwargs
+ ) -> List[LaunchDescriptionEntity]:
+ return [fn(context, args, kwargs)]
+
+ return listify_helper
diff --git a/Tools/ros2/ros2.repos b/Tools/ros2/ros2.repos
new file mode 100644
index 00000000000000..77c0b5c97cceca
--- /dev/null
+++ b/Tools/ros2/ros2.repos
@@ -0,0 +1,9 @@
+repositories:
+ ardupilot:
+ type: git
+ url: https://github.com/ArduPilot/ardupilot.git
+ version: master
+ micro_ros_agent:
+ type: git
+ url: https://github.com/micro-ROS/micro-ROS-Agent.git
+ version: humble
diff --git a/Tools/ros2/ros2_macos.repos b/Tools/ros2/ros2_macos.repos
new file mode 100644
index 00000000000000..84bca3e85089c9
--- /dev/null
+++ b/Tools/ros2/ros2_macos.repos
@@ -0,0 +1,17 @@
+repositories:
+ ardupilot:
+ type: git
+ url: https://github.com/srmainwaring/ardupilot.git
+ version: pr/pr-dds-launch-tests
+ microxrcedds_gen:
+ type: git
+ url: https://github.com/eProsima/Micro-XRCE-DDS-Gen.git
+ version: develop
+ micro_ros_agent:
+ type: git
+ url: https://github.com/srmainwaring/micro-ROS-Agent.git
+ version: cmake-macos
+ micro_ros_msgs:
+ type: git
+ url: https://github.com/micro-ROS/micro_ros_msgs.git
+ version: humble
diff --git a/Tools/scripts/apj_tool.py b/Tools/scripts/apj_tool.py
index 26b5e25a01a979..b4482ae5334556 100755
--- a/Tools/scripts/apj_tool.py
+++ b/Tools/scripts/apj_tool.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
'''
tool to manipulate ArduPilot firmware files, changing default parameters
'''
diff --git a/Tools/scripts/battery_fit.py b/Tools/scripts/battery_fit.py
new file mode 100755
index 00000000000000..9cc17e38783692
--- /dev/null
+++ b/Tools/scripts/battery_fit.py
@@ -0,0 +1,192 @@
+#!/usr/bin/env python
+'''
+fit coefficients for battery percentate from resting voltage
+
+See AP_Scripting/applets/BattEstimate.lua
+'''
+
+from argparse import ArgumentParser
+parser = ArgumentParser(description=__doc__)
+parser.add_argument("--no-graph", action='store_true', default=False, help='disable graph display')
+parser.add_argument("--num-cells", type=int, default=0, help='cell count, zero for auto-detection')
+parser.add_argument("--batidx", type=int, default=1, help='battery index')
+parser.add_argument("--condition", default=None, help='match condition')
+parser.add_argument("--final-pct", type=float, default=100.0, help='set final percentage in log')
+parser.add_argument("--comparison", type=str, default=None, help='comparison coefficients')
+parser.add_argument("log", metavar="LOG")
+
+args = parser.parse_args()
+
+import sys
+import math
+from pymavlink import mavutil
+import numpy as np
+import matplotlib.pyplot as pyplot
+
+def constrain(value, minv, maxv):
+ """Constrain a value to a range."""
+ return max(min(value,maxv),minv)
+
+def SOC_model(cell_volt, c):
+ '''simple model of state of charge versus resting voltage.
+ With thanks to Roho for the form of the equation
+ https://electronics.stackexchange.com/questions/435837/calculate-battery-percentage-on-lipo-battery
+ '''
+ p0 = 80.0
+ p1 = c[2]
+ return constrain(c[0]*(1.0-1.0/math.pow(1+math.pow(cell_volt/c[1],p0),p1)),0,100)
+
+def fit_batt(data):
+ '''fit a set of battery data to the SOC model'''
+ from scipy import optimize
+
+ def fit_error(p):
+ p = list(p)
+ ret = 0
+ for (voltR,pct) in data:
+ error = pct - SOC_model(voltR, p)
+ ret += abs(error)
+
+ ret /= len(data)
+ return ret
+
+ p = [123.0, 3.7, 0.165]
+ bounds = [(100.0, 10000.0), (3.0,3.9), (0.001, 0.4)]
+
+ (p,err,iterations,imode,smode) = optimize.fmin_slsqp(fit_error, p, bounds=bounds, iter=10000, full_output=True)
+ if imode != 0:
+ print("Fit failed: %s" % smode)
+ sys.exit(1)
+ return p
+
+def ExtractDataLog(logfile):
+ '''find battery fit parameters from a log file'''
+ print("Processing log %s" % logfile)
+ mlog = mavutil.mavlink_connection(logfile)
+
+ Wh_total = 0.0
+ last_t = None
+ data = []
+ last_voltR = None
+
+ while True:
+ msg = mlog.recv_match(type=['BAT'], condition=args.condition)
+ if msg is None:
+ break
+
+ if msg.get_type() == 'BAT' and msg.Instance == args.batidx-1 and msg.VoltR > 1:
+ current = msg.Curr
+ voltR = msg.VoltR
+ if last_voltR is not None and voltR > last_voltR:
+ continue
+ last_voltR = voltR
+ power = current*voltR
+ t = msg.TimeUS*1.0e-6
+
+ if last_t is None:
+ last_t = t
+ continue
+
+ dt = t - last_t
+ if dt < 0.5:
+ # 2Hz data is plenty
+ continue
+ last_t = t
+ Wh_total += (power*dt)/3600.0
+
+ data.append((voltR,Wh_total))
+
+ if len(data) == 0:
+ print("No data found")
+ sys.exit(1)
+
+ # calculate total pack capacity based on final percentage
+ Wh_max = data[-1][1]/(args.final_pct*0.01)
+
+ fit_data = []
+
+ for i in range(len(data)):
+ (voltR,Wh) = data[i]
+ SOC = 100-100*Wh/Wh_max
+ fit_data.append((voltR, SOC))
+
+ print("Loaded %u samples" % len(data))
+ return fit_data
+
+def ExtractDataCSV(logfile):
+ '''find battery fit parameters from a CSV file'''
+ print("Processing CSV %s" % logfile)
+ lines = open(logfile,'r').readlines()
+ fit_data = []
+ for line in lines:
+ line = line.strip()
+ if line.startswith("#"):
+ continue
+ v = line.split(',')
+ if len(v) != 2:
+ continue
+ if not v[0][0].isnumeric() or not v[1][0].isnumeric():
+ continue
+ fit_data.append((float(v[1]),float(v[0])))
+ return fit_data
+
+def BattFit(fit_data, num_cells):
+
+ fit_data = [ (v/num_cells,p) for (v,p) in fit_data ]
+
+ c = fit_batt(fit_data)
+ print("Coefficients C1=%.4f C2=%.4f C3=%.4f" % (c[0], c[1], c[2]))
+
+ if args.no_graph:
+ return
+
+ fig, axs = pyplot.subplots()
+
+ np_volt = np.array([v for (v,p) in fit_data])
+ np_pct = np.array([p for (v,p) in fit_data])
+ axs.invert_xaxis()
+ axs.plot(np_volt, np_pct, label='SOC')
+ np_rem = np.zeros(0,dtype=float)
+
+ # pad down to 3.2V to make it easier to visualise for logs that don't go to a low voltage
+ low_volt = np_volt[-1]
+ while low_volt > 3.2:
+ low_volt -= 0.1
+ np_volt = np.append(np_volt, low_volt)
+
+ for i in range(np_volt.size):
+ voltR = np_volt[i]
+ np_rem = np.append(np_rem, SOC_model(voltR, c))
+
+ axs.plot(np_volt, np_rem, label='SOC Fit')
+
+ if args.comparison:
+ c2 = args.comparison.split(',')
+ c2 = [ float(x) for x in c2 ]
+ np_rem2 = np.zeros(0,dtype=float)
+ for i in range(np_volt.size):
+ voltR = np_volt[i]
+ np_rem2 = np.append(np_rem2, SOC_model(voltR, c2))
+ axs.plot(np_volt, np_rem2, label='SOC Fit2')
+
+ axs.legend(loc='upper left')
+ axs.set_title('Battery Fit')
+
+ pyplot.show()
+
+def get_cell_count(data):
+ if args.num_cells != 0:
+ return args.num_cells
+ volts = [ v[0] for v in data ]
+ volts = sorted(volts)
+ num_cells = round(volts[-1]/4.2)
+ print("Max voltags %.1f num_cells %u" % (volts[-1], num_cells))
+ return num_cells
+
+if args.log.upper().endswith(".CSV"):
+ fit_data = ExtractDataCSV(args.log)
+else:
+ fit_data = ExtractDataLog(args.log)
+
+num_cells = get_cell_count(fit_data)
+BattFit(fit_data, num_cells)
diff --git a/Tools/scripts/bin2hex.py b/Tools/scripts/bin2hex.py
index 6a3f3c37558e30..e6de4a8ed25c59 100755
--- a/Tools/scripts/bin2hex.py
+++ b/Tools/scripts/bin2hex.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# Copyright (c) 2008,2010,2011,2012,2013 Alexander Belchenko
# All rights reserved.
diff --git a/Tools/scripts/board_list.py b/Tools/scripts/board_list.py
index b9b6f0f49e0831..52235fdb0e4d54 100755
--- a/Tools/scripts/board_list.py
+++ b/Tools/scripts/board_list.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
import os
import re
diff --git a/Tools/scripts/build_autotest.sh b/Tools/scripts/build_autotest.sh
index 789c89b6d00b0e..53bd889e5a5ff9 100755
--- a/Tools/scripts/build_autotest.sh
+++ b/Tools/scripts/build_autotest.sh
@@ -100,7 +100,7 @@ export BUILD_BINARIES_PATH=$HOME/build/tmp
# exit on panic so we don't waste time waiting around
export SITL_PANIC_EXIT=1
-timelimit 72000 APM/Tools/autotest/autotest.py --autotest-server --timeout=70000 > buildlogs/autotest-output.txt 2>&1
+timelimit 72000 python3 APM/Tools/autotest/autotest.py --autotest-server --timeout=70000 > buildlogs/autotest-output.txt 2>&1
mkdir -p "buildlogs/history/$hdate"
diff --git a/Tools/scripts/build_binaries.py b/Tools/scripts/build_binaries.py
index 6167b09c681b55..4d0c1c02f2bc27 100755
--- a/Tools/scripts/build_binaries.py
+++ b/Tools/scripts/build_binaries.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
"""
script to build the latest binaries for each vehicle type, ready to upload
@@ -35,16 +35,27 @@
running_python3 = True
+def topdir():
+ '''return path to ardupilot checkout directory. This is to cope with
+ running on developer's machines (where autotest is typically
+ invoked from the root directory), and on the autotest server where
+ it is invoked in the checkout's parent directory.
+ '''
+ for path in [
+ os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", ".."),
+ "",
+ ]:
+ if os.path.exists(os.path.join(path, "libraries", "AP_HAL_ChibiOS")):
+ return path
+ raise Exception("Unable to find ardupilot checkout dir")
+
+
def is_chibios_build(board):
'''see if a board is using HAL_ChibiOS'''
# cope with both running from Tools/scripts or running from cwd
- hwdef_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "..", "libraries", "AP_HAL_ChibiOS", "hwdef")
- if os.path.exists(os.path.join(hwdef_dir, board, "hwdef.dat")):
- return True
- hwdef_dir = os.path.join("libraries", "AP_HAL_ChibiOS", "hwdef")
- if os.path.exists(os.path.join(hwdef_dir, board, "hwdef.dat")):
- return True
- return False
+ hwdef_dir = os.path.join(topdir(), "libraries", "AP_HAL_ChibiOS", "hwdef")
+
+ return os.path.exists(os.path.join(hwdef_dir, board, "hwdef.dat"))
def get_required_compiler(vehicle, tag, board):
@@ -93,7 +104,7 @@ def run_waf(self, args, compiler=None):
waf = "./waf"
else:
waf = os.path.join(".", "modules", "waf", "waf-light")
- cmd_list = [waf]
+ cmd_list = ["python3", waf]
cmd_list.extend(args)
env = None
if compiler is not None:
@@ -113,7 +124,7 @@ def run_waf(self, args, compiler=None):
def run_program(self, prefix, cmd_list, show_output=True, env=None, force_success=False):
if show_output:
self.progress("Running (%s)" % " ".join(cmd_list))
- p = subprocess.Popen(cmd_list, bufsize=1, stdin=None,
+ p = subprocess.Popen(cmd_list, stdin=None,
stdout=subprocess.PIPE, close_fds=True,
stderr=subprocess.STDOUT, env=env)
output = ""
@@ -210,7 +221,7 @@ def skip_board_waf(self, board):
try:
out = self.run_program(
'waf',
- ['./waf', 'configure', '--board=BOARDTEST'],
+ ["python3", './waf', 'configure', '--board=BOARDTEST'],
show_output=False,
force_success=True
)
@@ -491,6 +502,20 @@ def build_vehicle(self, tag, vehicle, boards, vehicle_binaries_subdir,
files_to_copy.append((filepath, os.path.basename(filepath)))
if not os.path.exists(bare_path):
raise Exception("No elf file?!")
+
+ # attempt to run an extract_features.py to create features.txt:
+ features_text = None
+ ef_path = os.path.join(topdir(), "Tools", "scripts", "extract_features.py")
+ if os.path.exists(ef_path):
+ try:
+ features_text = self.run_program("EF", [ef_path, bare_path], show_output=False)
+ except Exception as e:
+ self.print_exception_caught(e)
+ self.progress("Failed to extract features")
+ pass
+ else:
+ self.progress("Not extracting features as (%s) does not exist" % (ef_path,))
+
# only rename the elf if we have have other files to
# copy. So linux gets "arducopter" and stm32 gets
# "arducopter.elf"
@@ -512,6 +537,10 @@ def build_vehicle(self, tag, vehicle, boards, vehicle_binaries_subdir,
if not os.path.exists(ddir):
self.mkpath(ddir)
self.addfwversion(ddir, vehicle)
+ features_filepath = os.path.join(ddir, "features.txt",)
+ if features_text is not None:
+ self.progress("Writing (%s)" % features_filepath)
+ self.write_string_to_filepath(features_text, features_filepath)
self.progress("Copying %s to %s" % (path, ddir,))
shutil.copy(path, os.path.join(ddir, target_filename))
# the most recent build of every tag is kept around:
@@ -521,10 +550,14 @@ def build_vehicle(self, tag, vehicle, boards, vehicle_binaries_subdir,
# must addfwversion even if path already
# exists as we re-use the "beta" directories
self.addfwversion(tdir, vehicle)
+ features_filepath = os.path.join(tdir, "features.txt")
+ if features_text is not None:
+ self.progress("Writing (%s)" % features_filepath)
+ self.write_string_to_filepath(features_text, features_filepath)
shutil.copy(path, os.path.join(tdir, target_filename))
except Exception as e:
self.print_exception_caught(e)
- self.progress("Failed to copy %s to %s: %s" % (path, ddir, str(e)))
+ self.progress("Failed to copy %s to %s: %s" % (path, tdir, str(e)))
# why is touching this important? -pb20170816
self.touch_filepath(os.path.join(self.binaries,
vehicle_binaries_subdir, tag))
@@ -534,7 +567,7 @@ def build_vehicle(self, tag, vehicle, boards, vehicle_binaries_subdir,
self.checkout(vehicle, "latest")
- def get_exception_stacktrace(self, e):
+ def _get_exception_stacktrace(self, e):
if sys.version_info[0] >= 3:
ret = "%s\n" % e
ret += ''.join(traceback.format_exception(type(e),
@@ -545,6 +578,12 @@ def get_exception_stacktrace(self, e):
# Python2:
return traceback.format_exc(e)
+ def get_exception_stacktrace(self, e):
+ try:
+ return self._get_exception_stacktrace(e)
+ except Exception:
+ return "FAILED TO GET EXCEPTION STACKTRACE"
+
def print_exception_caught(self, e, send_statustext=True):
self.progress("Exception caught: %s" %
self.get_exception_stacktrace(e))
@@ -625,6 +664,7 @@ def generate_manifest(self):
generator.run()
generator.write_manifest_json(os.path.join(self.binaries, "manifest.json"))
+ generator.write_features_json(os.path.join(self.binaries, "features.json"))
self.progress("Manifest generation successful")
self.progress("Generating stable releases")
@@ -727,7 +767,7 @@ def run(self):
tags = cmd_opts.tags
if len(tags) == 0:
# FIXME: wedge this defaulting into parser somehow
- tags = ["stable", "beta", "latest"]
+ tags = ["stable", "beta-4.3", "beta", "latest"]
bb = build_binaries(tags)
bb.run()
diff --git a/Tools/scripts/build_ci.sh b/Tools/scripts/build_ci.sh
index c4fa17d6c934d4..12e654c5ba550f 100755
--- a/Tools/scripts/build_ci.sh
+++ b/Tools/scripts/build_ci.sh
@@ -130,7 +130,7 @@ for t in $CI_BUILD_TARGET; do
fi
if [ "$t" == "sitltest-can" ]; then
echo "Building SITL Periph GPS"
- $waf configure --board sitl --force-32bit
+ $waf configure --board sitl
$waf copter
run_autotest "Copter" "build.SITLPeriphGPS" "test.CAN"
continue
@@ -252,6 +252,14 @@ for t in $CI_BUILD_TARGET; do
continue
fi
+ if [ "$t" == "CubeRedPrimary-bootloader" ]; then
+ echo "Building CubeRedPrimary bootloader"
+ $waf configure --board CubeRedPrimary --bootloader
+ $waf clean
+ $waf bootloader
+ continue
+ fi
+
if [ "$t" == "fmuv3-bootloader" ]; then
echo "Building fmuv3 bootloader"
$waf configure --board fmuv3 --bootloader
@@ -328,6 +336,7 @@ for t in $CI_BUILD_TARGET; do
$waf clean
$waf copter
$waf plane
+ $waf tests
continue
fi
@@ -358,9 +367,11 @@ for t in $CI_BUILD_TARGET; do
if [ "$t" == "replay" ]; then
echo "Building replay"
$waf configure --board sitl --debug --disable-scripting
+
$waf replay
echo "Building AP_DAL standalone test"
$waf configure --board sitl --debug --disable-scripting --no-gcs
+
$waf --target tool/AP_DAL_Standalone
$waf clean
continue
@@ -405,7 +416,7 @@ for t in $CI_BUILD_TARGET; do
if [ "$t" == "astyle-cleanliness" ]; then
echo "Checking AStyle code cleanliness"
- ./Tools/scripts/run_astyle.py
+ ./Tools/scripts/run_astyle.py --dry-run
continue
fi
diff --git a/Tools/scripts/build_iofirmware.py b/Tools/scripts/build_iofirmware.py
index c5fc2510aa90d2..6d6c927addab35 100755
--- a/Tools/scripts/build_iofirmware.py
+++ b/Tools/scripts/build_iofirmware.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
"""
script to build iofirmware and copy to Tools/IO_Firmware
@@ -29,6 +29,24 @@ def run_program(cmd_list):
shutil.copy('build/iomcu/bin/iofirmware_lowpolh.bin', 'Tools/IO_Firmware/iofirmware_lowpolh.bin')
shutil.copy('build/iomcu/bin/iofirmware_highpolh.bin', 'Tools/IO_Firmware/iofirmware_highpolh.bin')
+run_program(["./waf", "configure", "--board", 'iomcu-dshot'])
+run_program(["./waf", "clean"])
+run_program(["./waf", "iofirmware"])
+shutil.copy('build/iomcu-dshot/bin/iofirmware_lowpolh.bin', 'Tools/IO_Firmware/iofirmware_dshot_lowpolh.bin')
+shutil.copy('build/iomcu-dshot/bin/iofirmware_highpolh.bin', 'Tools/IO_Firmware/iofirmware_dshot_highpolh.bin')
+
+run_program(["./waf", "configure", "--board", 'iomcu-f103'])
+run_program(["./waf", "clean"])
+run_program(["./waf", "iofirmware"])
+shutil.copy('build/iomcu-f103/bin/iofirmware_lowpolh.bin', 'Tools/IO_Firmware/iofirmware_f103_lowpolh.bin')
+shutil.copy('build/iomcu-f103/bin/iofirmware_highpolh.bin', 'Tools/IO_Firmware/iofirmware_f103_highpolh.bin')
+
+run_program(["./waf", "configure", "--board", 'iomcu-f103-dshot'])
+run_program(["./waf", "clean"])
+run_program(["./waf", "iofirmware"])
+shutil.copy('build/iomcu-f103-dshot/bin/iofirmware_lowpolh.bin', 'Tools/IO_Firmware/iofirmware_f103_dshot_lowpolh.bin')
+shutil.copy('build/iomcu-f103-dshot/bin/iofirmware_highpolh.bin', 'Tools/IO_Firmware/iofirmware_f103_dshot_highpolh.bin')
+
run_program(["./waf", "configure", "--board", 'iomcu_f103_8MHz'])
run_program(["./waf", "clean"])
run_program(["./waf", "iofirmware"])
diff --git a/Tools/scripts/build_options.py b/Tools/scripts/build_options.py
index 43282770887707..1ab62da3d8f47b 100644
--- a/Tools/scripts/build_options.py
+++ b/Tools/scripts/build_options.py
@@ -31,6 +31,8 @@ def __init__(self,
Feature('AHRS', 'EKF3', 'HAL_NAVEKF3_AVAILABLE', 'Enable EKF3', 1, None),
Feature('AHRS', 'EKF2', 'HAL_NAVEKF2_AVAILABLE', 'Enable EKF2', 0, None),
Feature('AHRS', 'AHRS_EXT', 'HAL_EXTERNAL_AHRS_ENABLED', 'Enable External AHRS', 0, None),
+ Feature('AHRS', 'AHRS_EXT_MICROSTRAIN', 'AP_EXTERNAL_AHRS_MICROSTRAIN_ENABLED', 'Enable MICROSTRAIN External AHRS', 0, "AHRS_EXT"), # noqa: E501
+ Feature('AHRS', 'AHRS_EXT_VECTORNAV', 'AP_EXTERNAL_AHRS_VECTORNAV_ENABLED', 'Enable VectorNav External AHRS', 0, "AHRS_EXT"), # noqa
Feature('AHRS', 'TEMPCAL', 'HAL_INS_TEMPERATURE_CAL_ENABLE', 'Enable IMU Temperature Calibration', 0, None),
Feature('AHRS', 'VISUALODOM', 'HAL_VISUALODOM_ENABLED', 'Enable Visual Odometry', 0, 'EKF3_EXTNAV'),
Feature('AHRS', 'EKF3_EXTNAV', 'EK3_FEATURE_EXTERNAL_NAV', 'Enable External Navigation for EKF3', 0, 'EKF3'),
@@ -38,6 +40,7 @@ def __init__(self,
Feature('Safety', 'PARACHUTE', 'HAL_PARACHUTE_ENABLED', 'Enable Parachute', 0, None),
Feature('Safety', 'FENCE', 'AP_FENCE_ENABLED', 'Enable Geofence', 2, None),
+ Feature('Safety', 'RALLY', 'HAL_RALLY_ENABLED', 'Enable Rally Points', 0, None), # noqa
Feature('Safety', 'AC_AVOID', 'AC_AVOID_ENABLED', 'Enable Avoidance', 0, 'FENCE'),
Feature('Safety', 'AC_OAPATHPLANNER', 'AC_OAPATHPLANNER_ENABLED', 'Enable Object Avoidance Path Planner', 0, 'FENCE'),
@@ -47,6 +50,7 @@ def __init__(self,
Feature('Battery', 'BATTERY_SMBUS', 'AP_BATTERY_SMBUS_ENABLED', 'Enable SMBUS BatteryMonitor', 0, None),
Feature('Battery', 'BATTERY_INA2XX', 'AP_BATTERY_INA2XX_ENABLED', 'Enable INA2XX BatteryMonitor', 0, None),
Feature('Battery', 'BATTERY_SYNTHETIC_CURRENT', 'AP_BATTERY_SYNTHETIC_CURRENT_ENABLED', 'Enable Synthetic Current Monitor', 0, None), # noqa: E501
+ Feature('Battery', 'BATTERY_ESC_TELEM_OUTBOUND_ENABLED', 'AP_BATTERY_ESC_TELEM_OUTBOUND_ENABLED', 'Enable Synthetic Current Monitor', 0, None), # noqa: E501
Feature('Ident', 'ADSB', 'HAL_ADSB_ENABLED', 'Enable ADSB', 0, None),
Feature('Ident', 'ADSB_SAGETECH', 'HAL_ADSB_SAGETECH_ENABLED', 'Enable SageTech ADSB', 0, 'ADSB'),
@@ -55,9 +59,8 @@ def __init__(self,
Feature('Ident', 'ADSB_UAVIONX_UCP', 'HAL_ADSB_UCP_ENABLED', 'Enable uAvionix UCP ADSB', 0 , 'ADSB'),
Feature('Ident', 'AIS', 'AP_AIS_ENABLED', 'Enable AIS', 0, None),
- Feature('Telemetry', 'CRSF', 'HAL_CRSF_TELEM_ENABLED', 'Enable CRSF Telemetry', 0, 'FrSky SPort PassThrough,FrSky,FrSky SPort'), # noqa
+ Feature('Telemetry', 'CRSF', 'HAL_CRSF_TELEM_ENABLED', 'Enable CRSF Telemetry', 0, 'FrSky SPort PassThrough,FrSky,FrSky SPort,RC_CRSF'), # noqa
Feature('Telemetry', 'CRSFText', 'HAL_CRSF_TELEM_TEXT_SELECTION_ENABLED', 'Enable CRSF Text Param Selection', 0, 'CRSF,OSD_PARAM,FrSky SPort PassThrough,FrSky,FrSky SPort'), # NOQA: E501
- Feature('Telemetry', 'HIGHLAT2', 'HAL_HIGH_LATENCY2_ENABLED', 'Enable HighLatency2 Support', 0, None),
Feature('Telemetry', 'HOTT', 'HAL_HOTT_TELEM_ENABLED', 'Enable HOTT Telemetry', 0, None),
Feature('Telemetry', 'SPEKTRUM', 'HAL_SPEKTRUM_TELEM_ENABLED', 'Enable Spektrum Telemetry', 0, None),
Feature('Telemetry', 'LTM', 'AP_LTM_TELEM_ENABLED', 'Enable LTM Telemetry', 0, None),
@@ -68,6 +71,7 @@ def __init__(self,
Feature('Telemetry', 'FrSky SPort PassThrough', 'AP_FRSKY_SPORT_PASSTHROUGH_ENABLED', 'Enable FrSkySPort PassThrough Telemetry', 0, 'FrSky SPort,FrSky'), # noqa
Feature('Notify', 'PLAY_TUNE', 'AP_NOTIFY_MAVLINK_PLAY_TUNE_SUPPORT_ENABLED', 'Enable MAVLink Play Tune', 0, None), # noqa
+ Feature('Notify', 'TONEALARM', 'AP_NOTIFY_TONEALARM_ENABLED', 'Enable ToneAlarm on PWM', 0, None), # noqa
Feature('Notify', 'LED_CONTROL', 'AP_NOTIFY_MAVLINK_LED_CONTROL_SUPPORT_ENABLED', 'Enable MAVLink LED Control', 0, None), # noqa
Feature('Notify', 'NOTIFY_NCP5623', 'AP_NOTIFY_NCP5623_ENABLED', 'Enable NCP5623 LED', 0, None), # noqa
# Feature('Notify', 'NOTIFY_PCA9685', 'AP_NOTIFY_PCA9685_ENABLED', 'Enable PCA9685 LED', 0, None), # noqa linux-only
@@ -90,11 +94,12 @@ def __init__(self,
Feature('ICE', 'EFI_NMPWU', 'AP_EFI_NWPWU_ENABLED', 'Enable EFI NMPMU', 0, 'EFI'),
Feature('ICE', 'EFI_CURRAWONGECU', 'AP_EFI_CURRAWONG_ECU_ENABLED', 'Enable EFI Currawong ECU', 0, 'EFI'),
Feature('ICE', 'EFI_DRONECAN', 'AP_EFI_DRONECAN_ENABLED', 'Enable EFI DroneCAN', 0, 'EFI'),
+ Feature('ICE', 'EFI_MAV', 'AP_EFI_MAV_ENABLED', 'Enable EFI MAV', 0, 'EFI'),
Feature('Generator', 'GENERATOR', 'HAL_GENERATOR_ENABLED', 'Enable Generator', 0, None),
Feature('Generator', 'GENERATOR_RICHENPOWER', 'AP_GENERATOR_RICHENPOWER_ENABLED', 'Enable Richenpower Generator', 0, "GENERATOR"), # noqa
- Feature('Generator', 'GENERATOR_IE2400', 'AP_GENERATOR_IE2400_ENABLED', 'Enable IntelligentEnergy 2400', 0, "GENERATOR"), # noqa
- Feature('Generator', 'GENERATOR_IE650', 'AP_GENERATOR_IE650_800_ENABLED', 'Enable IntelligentEnergy 650 and 800 support', 0, "GENERATOR"), # noqa
+ Feature('Generator', 'GENERATOR_IE2400', 'AP_GENERATOR_IE_2400_ENABLED', 'Enable IntelligentEnergy 2400', 0, "GENERATOR"), # noqa
+ Feature('Generator', 'GENERATOR_IE650', 'AP_GENERATOR_IE_650_800_ENABLED', 'Enable IntelligentEnergy 650 and 800 support', 0, "GENERATOR"), # noqa
Feature('OSD', 'OSD', 'OSD_ENABLED', 'Enable OSD', 0, None),
Feature('OSD', 'PLUSCODE', 'HAL_PLUSCODE_ENABLE', 'Enable PlusCode', 0, 'OSD'),
@@ -114,7 +119,7 @@ def __init__(self,
Feature('Camera', 'Camera_MAVLink', 'AP_CAMERA_MAVLINK_ENABLED', 'Enable MAVLink Camera support', 0, 'Camera'),
Feature('Camera', 'Camera_MAVLinkCamV2', 'AP_CAMERA_MAVLINKCAMV2_ENABLED', 'Enable MAVLink CameraV2 support', 0, 'Camera'),
Feature('Camera', 'Camera_Mount', 'AP_CAMERA_MOUNT_ENABLED', 'Enable Camera-in-Mount support', 0, 'Camera,MOUNT'),
- Feature('Camera', 'Camera_Relay', 'AP_CAMERA_RELAY_ENABLED', 'Enable Camera Trigger via Relay support', 0, 'Camera'),
+ Feature('Camera', 'Camera_Relay', 'AP_CAMERA_RELAY_ENABLED', 'Enable Camera Trigger via Relay support', 0, 'Camera,RELAY'),
Feature('Camera', 'Camera_Servo', 'AP_CAMERA_SERVO_ENABLED', 'Enable Camera Trigger via Servo support', 0, 'Camera'),
Feature('Camera', 'Camera_Solo', 'AP_CAMERA_SOLOGIMBAL_ENABLED', 'Enable Solo Gimbal support', 0, 'Camera'),
@@ -128,6 +133,7 @@ def __init__(self,
Feature('Copter', 'MODE_GUIDED_NOGPS', 'MODE_GUIDED_NOGPS_ENABLED', 'Enable Mode Guided NoGPS', 0, None),
Feature('Copter', 'MODE_FLOWHOLD', 'MODE_FLOWHOLD_ENABLED', 'Enable Mode Flowhold', 0, "OPTICALFLOW"),
Feature('Copter', 'MODE_FLIP', 'MODE_FLIP_ENABLED', 'Enable Mode Flip', 0, None),
+ Feature('Copter', 'MODE_BRAKE', 'MODE_BRAKE_ENABLED', 'Enable Mode Brake', 0, None),
Feature('Compass', 'AK09916', 'AP_COMPASS_AK09916_ENABLED', 'Enable AK09916 compasses', 1, None),
Feature('Compass', 'AK8963', 'AP_COMPASS_AK8963_ENABLED', 'Enable AK8963 compasses', 1, None),
@@ -154,6 +160,8 @@ def __init__(self,
Feature('Gimbal', 'SOLOGIMBAL', 'HAL_SOLO_GIMBAL_ENABLED', 'Enable Solo Gimbal', 0, "MOUNT"),
Feature('Gimbal', 'STORM32_MAVLINK', 'HAL_MOUNT_STORM32MAVLINK_ENABLED', 'Enable SToRM32 MAVLink Gimbal', 0, "MOUNT"),
Feature('Gimbal', 'STORM32_SERIAL', 'HAL_MOUNT_STORM32SERIAL_ENABLED', 'Enable SToRM32 Serial Gimbal', 0, "MOUNT"),
+ Feature('Gimbal', 'XACTI', 'HAL_MOUNT_XACTI_ENABLED', 'Enable Xacti Gimbal', 0, "MOUNT"),
+ Feature('Gimbal', 'VIEWPRO', 'HAL_MOUNT_VIEWPRO_ENABLED', 'Enable Viewpro Gimbal', 0, "MOUNT"),
Feature('VTOL Frame', 'QUAD', 'AP_MOTORS_FRAME_QUAD_ENABLED', 'QUADS(BI,TRI also)', 1, None),
Feature('VTOL Frame', 'HEXA', 'AP_MOTORS_FRAME_HEXA_ENABLED', 'HEXA', 0, None),
@@ -167,13 +175,24 @@ def __init__(self,
Feature('Payload', 'SPRAYER', 'HAL_SPRAYER_ENABLED', 'Enable Sprayer', 0, None),
Feature('Payload', 'LANDING_GEAR', 'AP_LANDINGGEAR_ENABLED', 'Enable Landing Gear', 0, None),
Feature('Payload', 'WINCH', 'AP_WINCH_ENABLED', 'Enable Winch', 0, None),
+ Feature('Payload', 'RELAY', 'AP_RELAY_ENABLED', 'Enable Relay support', 0, None),
+ Feature('Payload', 'SERVORELAY_EVENTS', 'AP_SERVORELAYEVENTS_ENABLED', 'Enable Servo/Relay Event support', 0, None),
Feature('Plane', 'QUADPLANE', 'HAL_QUADPLANE_ENABLED', 'Enable QuadPlane support', 0, None),
Feature('Plane', 'SOARING', 'HAL_SOARING_ENABLED', 'Enable Soaring', 0, None),
Feature('Plane', 'DEEPSTALL', 'HAL_LANDING_DEEPSTALL_ENABLED', 'Enable Deepstall Landing', 0, None),
Feature('Plane', 'QAUTOTUNE', 'QAUTOTUNE_ENABLED', 'Enable QuadPlane Autotune mode', 0, "QUADPLANE"),
-
- Feature('RC', 'RC_SRXL', 'AP_RCPROTOCOL_SRXL_ENABLED', "Enable SRXL RC Protocol", 0, None), # NOQA: E501
+ Feature('Plane', 'PLANE_BLACKBOX', 'AP_PLANE_BLACKBOX_LOGGING', 'Enable blackbox logging', 0, None),
+
+ Feature('RC', 'RC_Protocol', 'AP_RCPROTOCOL_ENABLED', "Enable Serial RC Protocol support", 0, None), # NOQA: E501
+ Feature('RC', 'RC_CRSF', 'AP_RCPROTOCOL_CRSF_ENABLED', "Enable CRSF RC Protocol", 0, "RC_Protocol"), # NOQA: E501
+ Feature('RC', 'RC_IBUS', 'AP_RCPROTOCOL_IBUS_ENABLED', "Enable IBus RC Protocol", 0, "RC_Protocol"), # NOQA: E501
+ Feature('RC', 'RC_SBUS', 'AP_RCPROTOCOL_SBUS_ENABLED', "Enable SBUS Protocol", 0, "RC_Protocol"), # NOQA: E501
+ Feature('RC', 'RC_PPMSUM', 'AP_RCPROTOCOL_PPMSUM_ENABLED', "Enable PPMSum Protocol", 0, "RC_Protocol"), # NOQA: E501
+ Feature('RC', 'RC_SRXL', 'AP_RCPROTOCOL_SRXL_ENABLED', "Enable SRXL RC Protocol", 0, "RC_Protocol"), # NOQA: E501
+ Feature('RC', 'RC_SRXL2', 'AP_RCPROTOCOL_SRXL2_ENABLED', "Enable SRXL2 RC Protocol", 0, "RC_Protocol"), # NOQA: E501
+ Feature('RC', 'RC_ST24', 'AP_RCPROTOCOL_ST24_ENABLED', "Enable ST24 Protocol", 0, "RC_Protocol"), # NOQA: E501
+ Feature('RC', 'RC_SUMD', 'AP_RCPROTOCOL_SUMD_ENABLED', "Enable SUMD RC Protocol", 0, "RC_Protocol"), # NOQA: E501
Feature('Rangefinder', 'RANGEFINDER', 'AP_RANGEFINDER_ENABLED', "Enable Rangefinders", 0, None), # NOQA: E501
Feature('Rangefinder', 'RANGEFINDER_ANALOG', 'AP_RANGEFINDER_ANALOG_ENABLED', "Enable Rangefinder - Analog", 0, "RANGEFINDER"), # NOQA: E501
@@ -265,6 +284,24 @@ def __init__(self,
Feature('Other', 'NMEA_OUTPUT', 'HAL_NMEA_OUTPUT_ENABLED', 'Enable NMEA Output', 0, None),
Feature('Other', 'BARO_WIND_COMP', 'HAL_BARO_WIND_COMP_ENABLED', 'Enable Baro Wind Compensation', 0, None),
Feature('Other', 'ADVANCED_FAILSAFE', 'AP_ADVANCEDFAILSAFE_ENABLED', 'Enable Advanced Failsafe features', 0, None),
+ Feature('Other', 'SDCARD_FORMATTING', 'AP_FILESYSTEM_FORMAT_ENABLED', 'Enable formatting of microSD cards', 0, None),
+ Feature('Other', 'BOOTLOADER_FLASHING', 'AP_BOOTLOADER_FLASHING_ENABLED', 'Enable Bootloader flashing', 0, "FILESYSTEM_ROMFS"), # noqa
+ Feature('Other', 'SCRIPTING', 'AP_SCRIPTING_ENABLED', 'Enable LUA Scripting', 0, None),
+ Feature('Other', 'SLCAN', 'AP_CAN_SLCAN_ENABLED', 'Enable SLCAN serial protocol', 0, None),
+ Feature('Other', 'SDCARD_MISSION', 'AP_SDCARD_STORAGE_ENABLED', 'Enable storing mission on microSD cards', 0, None),
+
+ # MAVLink section for mavlink features and/or message handling,
+ # rather than for e.g. mavlink-based sensor drivers
+ Feature('MAVLink', 'HIGHLAT2', 'HAL_HIGH_LATENCY2_ENABLED', 'Enable HighLatency2 Support', 0, None),
+ Feature('MAVLink', 'FENCEPOINT_PROTOCOL', 'AC_POLYFENCE_FENCE_POINT_PROTOCOL_SUPPORT', 'Enable old MAVLink FencePoint protocol', 0, "FENCE"), # noqa
+ Feature('MAVLink', 'RALLYPOINT_PROTOCOL', 'AP_MAVLINK_RALLY_POINT_PROTOCOL_ENABLED', 'Enable old MAVLink RallyPoint protocol', 0, "RALLY"), # noqa
+ Feature('MAVLink', 'AP_MAVLINK_AUTOPILOT_VERSION_REQUEST_ENABLED', 'AP_MAVLINK_AUTOPILOT_VERSION_REQUEST_ENABLED', 'Enable old AUTOPILOT_VERSION_REQUEST mesage', 0, None), # noqa
+ Feature('MAVLink', 'AP_MAVLINK_MAV_CMD_REQUEST_AUTOPILOT_CAPABILITIES_ENABLED', 'AP_MAVLINK_MAV_CMD_REQUEST_AUTOPILOT_CAPABILITIES_ENABLED', 'Enable old REQUEST_AUTOPILOT_CAPABILITIES command', 0, None), # noqa
+ Feature('MAVLink', 'AP_MAVLINK_MSG_RELAY_STATUS_ENABLED', 'AP_MAVLINK_MSG_RELAY_STATUS_ENABLED', 'Enable sending of RELAY_STATUS message', 0, 'RELAY'), # noqa
+ Feature('MAVLink', 'AP_MAVLINK_BATTERY2_ENABLED', 'AP_MAVLINK_BATTERY2_ENABLED', 'Enable sending of old BATTERY2 message', 0, None), # noqa
+
+ Feature('Developer', 'KILL_IMU', 'AP_INERTIALSENSOR_KILL_IMU_ENABLED', 'Allow IMUs to be disabled at runtime', 0, None),
+ Feature('Developer', 'CRASHCATCHER', 'AP_CRASHDUMP_ENABLED', 'Enable CrashCatcher', 0, None),
Feature('GPS Drivers', 'UBLOX', 'AP_GPS_UBLOX_ENABLED', 'Enable u-blox GPS', 1, None),
Feature('GPS Drivers', 'SBP2', 'AP_GPS_SBP2_ENABLED', 'Enable SBP2 GPS', 0, 'SBP'),
@@ -293,11 +330,21 @@ def __init__(self,
Feature('Actuators', 'Volz', 'AP_VOLZ_ENABLED', 'Enable Volz Protocol', 0, None),
Feature('Actuators', 'Volz_DroneCAN', 'AP_DRONECAN_VOLZ_FEEDBACK_ENABLED', 'Enable Volz DroneCAN Feedback', 0, None),
Feature('Actuators', 'RobotisServo', 'AP_ROBOTISSERVO_ENABLED', 'Enable RobotisServo Protocol', 0, None),
+ Feature('Actuators', 'SBUS Output', 'AP_SBUSOUTPUT_ENABLED', 'Enable SBUS Output on serial ports', 0, None),
Feature('Actuators', 'FETTecOneWire', 'AP_FETTEC_ONEWIRE_ENABLED', 'Enable FETTec OneWire ESCs', 0, None),
+ Feature('Actuators', 'KDECAN', 'AP_KDECAN_ENABLED', 'KDE Direct KDECAN ESC', 0, None),
Feature('Precision Landing', 'PrecLand', 'AC_PRECLAND_ENABLED', 'Enable Precision Landing support', 0, None),
Feature('Precision Landing', 'PrecLand - Companion', 'AC_PRECLAND_COMPANION_ENABLED', 'Enable Companion-Supported Precision Landing support', 0, "PrecLand"), # noqa
Feature('Precision Landing', 'PrecLand - IRLock', 'AC_PRECLAND_IRLOCK_ENABLED', 'Enable IRLock-Supported Precision Landing support', 0, "PrecLand"), # noqa
+
+ # Feature('Filesystem', 'FILESYSTEM_ESP32_ENABLED', 'AP_FILESYSTEM_ESP32_ENABLED', 'Enable ESP32 Filesystem', 0, None),
+ # Feature('Filesystem', 'FILESYSTEM_FATFS', 'AP_FILESYSTEM_FATFS_ENABLED', 'Enable FATFS Filesystem', 0, None),
+ Feature('Filesystem', 'FILESYSTEM_MISSION', 'AP_FILESYSTEM_MISSION_ENABLED', 'Enable @MISSION/ filesystem', 0, None),
+ Feature('Filesystem', 'FILESYSTEM_PARAM', 'AP_FILESYSTEM_PARAM_ENABLED', 'Enable @PARAM/ filesystem', 0, None),
+ # Feature('Filesystem', 'FILESYSTEM_POSIX', 'AP_FILESYSTEM_POSIX_ENABLED', 'Enable POSIX filesystem', 0, None),
+ Feature('Filesystem', 'FILESYSTEM_ROMFS', 'AP_FILESYSTEM_ROMFS_ENABLED', 'Enable @ROMFS/ filesystem', 0, None),
+ Feature('Filesystem', 'FILESYSTEM_SYS', 'AP_FILESYSTEM_SYS_ENABLED', 'Enable @SYS/ filesystem', 0, None),
]
BUILD_OPTIONS.sort(key=lambda x: (x.category + x.label))
diff --git a/Tools/scripts/build_sizes/build_sizes.py b/Tools/scripts/build_sizes/build_sizes.py
index d5cce220ad3a61..d347278f17f7e8 100755
--- a/Tools/scripts/build_sizes/build_sizes.py
+++ b/Tools/scripts/build_sizes/build_sizes.py
@@ -15,7 +15,7 @@
parser.add_argument('basedir', default=None, help='base directory (binaries directory)')
parser.add_argument('--outfile', default="builds.html", help='output file')
-build_dirs = ['latest', 'beta', 'stable']
+build_dirs = ['latest', 'beta', 'beta-4.3', 'stable']
builds = ['Plane', 'Copter', 'Rover', 'Sub', 'Blimp', 'AntennaTracker', 'AP_Periph']
args = parser.parse_args()
@@ -97,6 +97,7 @@ def write_headers(h):
''' % datetime.now().strftime("%F %k:%M"))
diff --git a/Tools/scripts/configure_all.py b/Tools/scripts/configure_all.py
index 45629955f59829..6a799fbe9831e4 100755
--- a/Tools/scripts/configure_all.py
+++ b/Tools/scripts/configure_all.py
@@ -12,6 +12,10 @@
import argparse
+# modify our search path:
+sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../../libraries/AP_HAL_ChibiOS/hwdef/scripts'))
+import chibios_hwdef
+
parser = argparse.ArgumentParser(description='configure all ChibiOS boards')
parser.add_argument('--build', action='store_true', default=False, help='build as well as configure')
parser.add_argument('--build-target', default='copter', help='build target')
@@ -66,18 +70,26 @@ def run_program(cmd_list, build):
def is_ap_periph(board):
hwdef = os.path.join('libraries/AP_HAL_ChibiOS/hwdef/%s/hwdef.dat' % board)
- try:
- r = open(hwdef, 'r').read()
- if r.find('periph/hwdef.dat') != -1 or r.find('periph/hwdef.inc') != -1 or r.find('AP_PERIPH') != -1:
- print("%s is AP_Periph" % board)
- return True
- except Exception as ex:
- pass
- return False
+ ch = chibios_hwdef.ChibiOSHWDef()
+ ch.process_file(hwdef)
+ return ch.is_periph_fw()
if args.copy_hwdef_incs_to_directory is not None:
os.makedirs(args.copy_hwdef_incs_to_directory)
+def handle_hwdef_copy(directory, board, bootloader=False):
+ source = os.path.join("build", board, "hwdef.h")
+ if bootloader:
+ filename = "hwdef-%s-bl.h" % board
+ elif board == "iomcu":
+ filename = "hwdef-%s-iomcu.h" % board
+ elif is_ap_periph(board):
+ filename = "hwdef-%s-periph.h" % board
+ else:
+ filename = "hwdef-%s.h" % board
+ target = os.path.join(directory, filename)
+ shutil.copy(source, target)
+
for board in board_list:
done.append(board)
print("Configuring for %s [%u/%u failed=%u]" % (board, len(done), len(board_list), len(failures)))
@@ -86,16 +98,8 @@ def is_ap_periph(board):
config_opts += ["--Werror"]
if not args.only_bl:
run_program([args.python, "waf", "configure"] + config_opts, "configure: " + board)
- if args.copy_hwdef_incs_to_directory is not None:
- source = os.path.join("build", board, "hwdef.h")
- if board == "iomcu":
- filename = "hwdef-%s-iomcu.h" % board
- elif is_ap_periph(board):
- filename = "hwdef-%s-periph.h" % board
- else:
- filename = "hwdef-%s.h" % board
- target = os.path.join(args.copy_hwdef_incs_to_directory, filename)
- shutil.copy(source, target)
+ if args.copy_hwdef_incs_to_directory is not None:
+ handle_hwdef_copy(args.copy_hwdef_incs_to_directory, board)
if args.build:
if board == "iomcu":
target = "iofirmware"
@@ -114,6 +118,8 @@ def is_ap_periph(board):
if os.path.exists(hwdef_bl):
print("Configuring bootloader for %s" % board)
run_program([args.python, "waf", "configure", "--board", board, "--bootloader"], "configure: " + board + "-bl")
+ if args.copy_hwdef_incs_to_directory is not None:
+ handle_hwdef_copy(args.copy_hwdef_incs_to_directory, board, bootloader=True)
if args.build:
run_program([args.python, "waf", "bootloader"], "build: " + board + "-bl")
diff --git a/Tools/scripts/esp32_get_idf.sh b/Tools/scripts/esp32_get_idf.sh
index 817276d56e8ea3..39bf8dae7dcc65 100755
--- a/Tools/scripts/esp32_get_idf.sh
+++ b/Tools/scripts/esp32_get_idf.sh
@@ -23,9 +23,9 @@ else
if [ ! `ls esp_idf/install.sh 2>/dev/null` ]; then
echo "found empty IDF, cloning"
# add esp_idf as almost submodule, depths uses less space
- #git clone -b v4.2 --single-branch --depth 10 https://github.com/espressif/esp-idf.git esp_idf
- git clone -b 'release/v4.2' https://github.com/espressif/esp-idf.git esp_idf
- # check if we've got v4.2 checked out, only this version of esp_idf is tested and works?
+ #git clone -b v4.4 --single-branch --depth 10 https://github.com/espressif/esp-idf.git esp_idf
+ git clone -b 'release/v4.4' https://github.com/espressif/esp-idf.git esp_idf
+ # check if we've got v4.4 checked out, only this version of esp_idf is tested and works?
fi
fi
@@ -33,23 +33,25 @@ fi
echo "inspecting possible IDF... "
cd esp_idf
echo `git rev-parse HEAD`
-# these are a selection of possible specific commit/s that represent v4.2 branch of the esp_idf
-if [ `git rev-parse HEAD` == 'f370d5089f61ac39f183109b6b2908700cfe3b0a' ]; then
- echo "IDF version 'release/4.2' found OK, great.";
-elif [ `git rev-parse HEAD` == 'c40f2590bf759ff60ef122afa79b4ec04e7633d2' ]; then
- echo "IDF version 'v4.2' found OK, great.";
+# these are a selection of possible specific commit/s that represent v4.4 branch of the esp_idf
+if [ `git rev-parse HEAD` == 'f98ec313f2a9bc50151349c404a8f2f10ed99649' ]; then
+ echo "IDF version 'release/4.4' found OK, great.";
else
- echo "looks like an idf, but not v4.2 branch, trying to switch branch and reflect upstream";
+ echo "looks like an idf, but not v4.4 branch, trying to switch branch and reflect upstream";
../../Tools/gittools/submodule-sync.sh >/dev/null
- git fetch ; git checkout -f release/v4.2
+ git fetch ; git checkout -f release/v4.4
# retry same as above
echo `git rev-parse HEAD`
- if [ `git rev-parse HEAD` == 'f370d5089f61ac39f183109b6b2908700cfe3b0a' ]; then
- echo "IDF version 'release/4.2' found OK, great.";
- elif [ `git rev-parse HEAD` == 'c40f2590bf759ff60ef122afa79b4ec04e7633d2' ]; then
- echo "IDF version 'v4.2' found OK, great.";
+ if [ `git rev-parse HEAD` == 'f98ec313f2a9bc50151349c404a8f2f10ed99649' ]; then
+ echo "IDF version 'release/4.4' found OK, great.";
fi
fi
-cd ..
+cd ../..
+cd modules/esp_idf
+git submodule update --init --recursive
+cd ../..
+echo "after changing IDF versions [ such as between 4.2 and 4.4 ] you should re-run these in your console:"
+echo "./modules/esp_idf/install.sh"
+echo "source ./modules/esp_idf/export.sh"
\ No newline at end of file
diff --git a/Tools/scripts/extract_features.py b/Tools/scripts/extract_features.py
index 3d39955e334f16..1b770be5ab3415 100755
--- a/Tools/scripts/extract_features.py
+++ b/Tools/scripts/extract_features.py
@@ -36,6 +36,7 @@ def __init__(self, filename, nm="arm-none-eabi-nm"):
# the substitutions will be upper-cased
self.features = [
('AP_ADVANCEDFAILSAFE_ENABLED', 'AP::advancedfailsafe',),
+ ('AP_BOOTLOADER_FLASHING_ENABLED', 'ChibiOS::Util::flash_bootloader',),
('AP_AIRSPEED_ENABLED', 'AP_Airspeed::AP_Airspeed',),
('AP_AIRSPEED_{type}_ENABLED', r'AP_Airspeed_(?P.*)::init',),
@@ -64,6 +65,7 @@ def __init__(self, filename, nm="arm-none-eabi-nm"):
('HAL_NAVEKF3_AVAILABLE', 'NavEKF3::NavEKF3',),
('HAL_NAVEKF2_AVAILABLE', 'NavEKF2::NavEKF2',),
('HAL_EXTERNAL_AHRS_ENABLED', r'AP_ExternalAHRS::init\b',),
+ ('AP_EXTERNAL_AHRS_{type}_ENABLED', r'AP_ExternalAHRS_{type}::healthy\b',),
('HAL_INS_TEMPERATURE_CAL_ENABLE', 'AP_InertialSensor::TCal::Learn::save_calibration',),
('HAL_VISUALODOM_ENABLED', 'AP_VisualOdom::init',),
@@ -92,6 +94,7 @@ def __init__(self, filename, nm="arm-none-eabi-nm"):
('AP_BATTERY_{type}_ENABLED', r'AP_BattMonitor_(?P.*)::init\b',),
+ ('AP_BATTERY_ESC_TELEM_OUTBOUND_ENABLED', r'AP_BattMonitor_Backend::update_esc_telem_outbound\b',),
('HAL_MOUNT_ENABLED', 'AP_Mount::AP_Mount',),
('HAL_MOUNT_{type}_ENABLED', r'AP_Mount_(?P.*)::update\b',),
@@ -123,6 +126,7 @@ def __init__(self, filename, nm="arm-none-eabi-nm"):
('HAL_PARACHUTE_ENABLED', 'AP_Parachute::update',),
('AP_FENCE_ENABLED', r'AC_Fence::check\b',),
+ ('HAL_RALLY_ENABLED', r'AP_Rally::get_rally_max\b',),
('AC_AVOID_ENABLED', 'AC_Avoid::AC_Avoid',),
('AC_OAPATHPLANNER_ENABLED', 'AP_OAPathPlanner::AP_OAPathPlanner',),
@@ -131,7 +135,7 @@ def __init__(self, filename, nm="arm-none-eabi-nm"):
('AP_EFI_NWPWU_ENABLED', r'AP_EFI_NWPMU::update\b',),
('AP_EFI_CURRAWONG_ECU_ENABLED', r'AP_EFI_Currawong_ECU::update\b',),
('HAL_GENERATOR_ENABLED', 'AP_Generator::AP_Generator',),
- ('AP_GENERATOR_{type}_ENABLED', r'AP_Generator_(?P.*)::update',),
+ ('AP_GENERATOR_{type}_ENABLED', r'AP_Generator_(?P.*)::init',),
('OSD_ENABLED', 'AP_OSD::update_osd',),
('HAL_PLUSCODE_ENABLE', 'AP_OSD_Screen::draw_pluscode',),
@@ -151,7 +155,10 @@ def __init__(self, filename, nm="arm-none-eabi-nm"):
('HAL_SPRAYER_ENABLED', 'AC_Sprayer::AC_Sprayer',),
('AP_LANDINGGEAR_ENABLED', r'AP_LandingGear::init\b',),
('AP_WINCH_ENABLED', 'AP_Winch::AP_Winch',),
+ ('AP_RELAY_ENABLED', 'AP_Relay::init',),
+ ('AP_SERVORELAYEVENTS_ENABLED', 'AP_ServoRelayEvents::update_events',),
+ ('AP_RCPROTOCOL_ENABLED', r'AP_RCProtocol::init\b',),
('AP_RCPROTOCOL_{type}_ENABLED', r'AP_RCProtocol_(?P.*)::_process_byte\b',),
('AP_RCPROTOCOL_{type}_ENABLED', r'AP_RCProtocol_(?P.*)::_process_pulse\b',),
@@ -159,6 +166,8 @@ def __init__(self, filename, nm="arm-none-eabi-nm"):
('AP_DRONECAN_VOLZ_FEEDBACK_ENABLED', r'AP_DroneCAN::handle_actuator_status_Volz\b',),
('AP_ROBOTISSERVO_ENABLED', r'AP_RobotisServo::init\b',),
('AP_FETTEC_ONEWIRE_ENABLED', r'AP_FETtecOneWire::init\b',),
+ ('AP_SBUSOUTPUT_ENABLED', 'AP_SBusOut::sbus_format_frame',),
+ ('AP_KDECAN_ENABLED', r'AP_KDECAN::update\b',),
('AP_RPM_ENABLED', 'AP_RPM::AP_RPM',),
('AP_RPM_{type}_ENABLED', r'AP_RPM_(?P.*)::update',),
@@ -177,13 +186,30 @@ def __init__(self, filename, nm="arm-none-eabi-nm"):
('EK3_FEATURE_DRAG_FUSION', r'NavEKF3_core::FuseDragForces'),
('AP_RC_CHANNEL_AUX_FUNCTION_STRINGS_ENABLED', r'RC_Channel::lookuptable',),
+ ('AP_SCRIPTING_ENABLED', r'AP_Scripting::init',),
+ ('AP_NOTIFY_TONEALARM_ENABLED', r'AP_ToneAlarm::init'),
('AP_NOTIFY_MAVLINK_PLAY_TUNE_SUPPORT_ENABLED', r'AP_Notify::handle_play_tune'),
('AP_NOTIFY_MAVLINK_LED_CONTROL_SUPPORT_ENABLED', r'AP_Notify::handle_led_control'),
('AP_NOTIFY_NCP5623_ENABLED', r'NCP5623::write'),
('AP_NOTIFY_PROFILED_ENABLED', r'ProfiLED::init_ports'),
('AP_NOTIFY_PROFILED_SPI_ENABLED', r'ProfiLED_SPI::rgb_set_id'),
('AP_NOTIFY_NEOPIXEL_ENABLED', r'NeoPixel::init_ports'),
+ ('AP_FILESYSTEM_FORMAT_ENABLED', r'AP_Filesystem::format'),
+
+ ('AP_FILESYSTEM_{type}_ENABLED', r'AP_Filesystem_(?P.*)::open'),
+
+ ('AP_INERTIALSENSOR_KILL_IMU_ENABLED', r'AP_InertialSensor::kill_imu'),
+ ('AP_CRASHDUMP_ENABLED', 'CrashCatcher_DumpMemory'),
+ ('AP_CAN_SLCAN_ENABLED', 'SLCAN::CANIface::var_info'),
+ ('AC_POLYFENCE_FENCE_POINT_PROTOCOL_SUPPORT', 'AC_PolyFence_loader::handle_msg_fetch_fence_point'),
+ ('AP_MAVLINK_RALLY_POINT_PROTOCOL_ENABLED', 'GCS_MAVLINK::handle_common_rally_message'),
+
+ ('AP_SDCARD_STORAGE_ENABLED', 'StorageAccess::attach_file'),
+ ('AP_MAVLINK_AUTOPILOT_VERSION_REQUEST_ENABLED', 'GCS_MAVLINK::handle_send_autopilot_version'),
+ ('AP_MAVLINK_MAV_CMD_REQUEST_AUTOPILOT_CAPABILITIES_ENABLED', 'GCS_MAVLINK::handle_command_request_autopilot_capabilities'), # noqa
+ ('AP_MAVLINK_MSG_RELAY_STATUS_ENABLED', 'GCS_MAVLINK::send_relay_status'),
+ ('AP_MAVLINK_BATTERY2_ENABLED', 'GCS_MAVLINK::send_battery2'),
]
def progress(self, msg):
@@ -196,6 +222,7 @@ def validate_features_list(self):
# a list of problematic defines we don't have fixes for ATM:
whitelist = frozenset([
'HAL_PERIPH_SUPPORT_LONG_CAN_PRINTF', # this define changes single method body, hard to detect?
+ 'AP_PLANE_BLACKBOX_LOGGING', # no visible signature
])
for option in build_options.BUILD_OPTIONS:
if option.define in whitelist:
@@ -362,11 +389,20 @@ def create_string(self):
ret = ""
- for compiled_in_feature_define in sorted(compiled_in_feature_defines):
- ret += compiled_in_feature_define + "\n"
- for remaining in sorted(not_compiled_in_feature_defines):
- ret += "!" + remaining + "\n"
+ combined = {}
+ for define in sorted(compiled_in_feature_defines):
+ combined[define] = True
+ for define in sorted(not_compiled_in_feature_defines):
+ combined[define] = False
+
+ def squash_hal_to_ap(a):
+ return re.sub("^HAL_", "AP_", a)
+ for define in sorted(combined.keys(), key=squash_hal_to_ap):
+ bang = ""
+ if not combined[define]:
+ bang = "!"
+ ret += bang + define + "\n"
return ret
def run(self):
diff --git a/Tools/scripts/generate_features_txt_files.py b/Tools/scripts/generate_features_txt_files.py
deleted file mode 100755
index a998814d6077c2..00000000000000
--- a/Tools/scripts/generate_features_txt_files.py
+++ /dev/null
@@ -1,52 +0,0 @@
-#!/usr/bin/env python
-
-'''
-recurse through directory tree rooted at supplied path. For every elf file found, write out next to it a features.txt
-'''
-
-import optparse
-import os
-import sys
-
-import extract_features
-
-class GenerateFeatureTxtFiles(object):
- def __init__(self, path):
- self.path = path
-
- def write_features_txt_for_filepath(self, filepath):
- ef = extract_features.ExtractFeatures(filepath)
- text = ef.create_string()
- features_txt_filepath = os.path.join(os.path.dirname(filepath), "features.txt")
- with open(features_txt_filepath, "w") as fh:
- fh.write(text)
-
- def run(self):
- done_dirpaths = dict()
- for (dirpath, dirnames, filenames) in os.walk(self.path):
- for filename in filenames:
- if os.path.splitext(filename)[1].upper() != ".ELF":
- continue
- if dirpath in done_dirpaths:
- raise ValueError(
- "Already processed elf (%s) in dirpath (%s) but also found elf (%s)" %
- (done_dirpaths[dirpath], dirpath, filename))
- done_dirpaths[dirpath] = filename
- filepath = os.path.join(dirpath, filename)
- self.write_features_txt_for_filepath(filepath)
-
-
-if __name__ == '__main__':
-
- parser = optparse.OptionParser("generate_features_txt_files.py DIRPATH")
-
- cmd_opts, cmd_args = parser.parse_args()
-
- if len(cmd_args) < 1:
- parser.print_help()
- sys.exit(1)
-
- dirpath = cmd_args[0]
-
- gen = GenerateFeatureTxtFiles(dirpath)
- gen.run()
diff --git a/Tools/scripts/generate_manifest.py b/Tools/scripts/generate_manifest.py
index 70c19cd752ee38..a5aae5e1918679 100755
--- a/Tools/scripts/generate_manifest.py
+++ b/Tools/scripts/generate_manifest.py
@@ -24,7 +24,7 @@
running_python310 = True
FIRMWARE_TYPES = ["AntennaTracker", "Copter", "Plane", "Rover", "Sub", "AP_Periph", "Blimp"]
-RELEASE_TYPES = ["beta", "latest", "stable", "stable-*", "dirty"]
+RELEASE_TYPES = ["beta", "beta-4.3", "latest", "stable", "stable-*", "dirty"]
# mapping for board names to brand name and manufacturer
brand_map = {
diff --git a/Tools/scripts/make_apj.py b/Tools/scripts/make_apj.py
index 69165edb8a3903..05085afed8382e 100755
--- a/Tools/scripts/make_apj.py
+++ b/Tools/scripts/make_apj.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
'''
Create an apj file from a *.bin binary firmware
diff --git a/Tools/scripts/make_intel_hex.py b/Tools/scripts/make_intel_hex.py
index 4aeb8b965e6d0c..629ebf34b5e220 100755
--- a/Tools/scripts/make_intel_hex.py
+++ b/Tools/scripts/make_intel_hex.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
import sys, os, shutil, struct
import intelhex
diff --git a/Tools/scripts/mavlink_parse.py b/Tools/scripts/mavlink_parse.py
new file mode 100755
index 00000000000000..165111125fa4ed
--- /dev/null
+++ b/Tools/scripts/mavlink_parse.py
@@ -0,0 +1,502 @@
+#!/usr/bin/env python
+
+import re
+from enum import StrEnum # requires Python >= 3.11
+from pathlib import Path
+from itertools import chain
+from dataclasses import dataclass, astuple
+
+from pymavlink.dialects.v20 import (
+ common, icarous, cubepilot, uAvionix, ardupilotmega
+)
+
+class MAVLinkDialect(StrEnum):
+ # in subset, superset, unknown order, for correct links
+ # supported values must match imported dialect names
+ COMMON = 'common'
+ ICAROUS = 'icarous'
+ CUBEPILOT = 'cubepilot'
+ UAVIONIX = 'uAvionix'
+ ARDUPILOTMEGA = 'ardupilotmega'
+ UNKNOWN = 'UNKNOWN'
+
+
+@dataclass(slots=True, order=True)
+class MAVLinkMessage:
+ name: str
+ source: str
+ dialect: MAVLinkDialect = MAVLinkDialect.UNKNOWN
+
+ PREFIX = 'MAVLINK_MSG_ID_'
+
+ # Get message sets, for quick containment checks.
+ # Function is required because of Python's class scoping rules.
+ # See https://stackoverflow.com/questions/13905741.
+ def _get_known_messages(prefix):
+ ''' Returns a dictionary of {dialect: {messages}} given 'prefix'. '''
+ return {
+ dialect: set(m for m in dir(globals()[dialect])
+ if m.startswith(prefix))
+ for dialect in MAVLinkDialect
+ if dialect != MAVLinkDialect.UNKNOWN
+ }
+ KNOWN_DIALECTS = _get_known_messages(PREFIX)
+
+ # Try to determine dialect if initialised without one specified.
+ def __post_init__(self):
+ if self.dialect == MAVLinkDialect.UNKNOWN:
+ self.determine_dialect()
+
+ @property
+ def id_name(self):
+ return self.PREFIX + self.name
+
+ def determine_dialect(self):
+ for dialect, message_set in self.KNOWN_DIALECTS.items():
+ if self.id_name in message_set:
+ self.dialect = dialect
+ break # dialect found, no need to continue searching
+ else:
+ self.dialect = MAVLinkDialect.UNKNOWN
+
+ def as_tuple(self):
+ return astuple(self)
+
+ def __str__(self):
+ return f'{self.name:<45}{self.source:<55}{self.dialect}'
+
+ @classmethod
+ def get_unsupported(cls, supported: set, remove_prefix=True):
+ ''' Yields known messages that are not included in 'supported'. '''
+ offset = len(cls.PREFIX) if remove_prefix else 0
+ known_missing = set() # don't double-count for supersets
+ for dialect, message_set in cls.KNOWN_DIALECTS.items():
+ missing_names = message_set - supported - known_missing
+ for name in missing_names:
+ yield cls(name[offset:], 'UNSUPPORTED', dialect)
+ known_missing |= missing_names
+
+
+class MAVLinkCommand(MAVLinkMessage):
+ PREFIX = 'MAV_CMD_'
+ KNOWN_DIALECTS = MAVLinkMessage._get_known_messages(PREFIX)
+
+ @property
+ def id_name(self):
+ return self.name # commands are registered with their prefix
+
+ @classmethod
+ def get_unsupported(cls, supported: set, remove_prefix=False):
+ ''' Yields known commands that are not included in 'supported'. '''
+ # avoid accidentally treating enum values as commands
+ enums = [f'{e}_' for e in ardupilotmega.enums
+ if e.startswith(cls.PREFIX)]
+ for command in super().get_unsupported(supported, remove_prefix):
+ if not any(command.name.startswith(e) for e in enums):
+ yield command
+
+
+class MAVLinkDetector:
+ # file paths
+ BASE_DIR = Path(__file__).parent / '../..'
+ COMMON_FILE = BASE_DIR / 'libraries/GCS_MAVLink/GCS_Common.cpp'
+ STREAM_GROUP_FILE = 'GCS_MAVLink.cpp'
+
+ # regex for messages handled by the autopilot
+ INCOMING_MESSAGES = re.compile(r'case MAVLINK_MSG_ID_([A-Z0-9_]*)')
+ # regex for commands handled by the autopilot
+ INCOMING_COMMANDS = re.compile(r'case (MAV_CMD_[A-Z0-9_]*)')
+ # regex for messages that can be requested from the autopilot
+ REQUESTABLE_REGION = re.compile(' map\[\]([^;]*);')
+ REQUESTABLE_MAP = re.compile(r'MAVLINK_MSG_ID_([A-Z0-9_]*),\s*MSG_([A-Z0-9_]*)')
+ # regex for messages the autopilot might send, but cannot be requested
+ OUTGOING_MESSAGES = re.compile(r'mavlink_msg_([a-z0-9_]*)_send\(')
+ # regex for extracting messages in stream groups
+ STREAM_GROUPS = re.compile(r'ap_message STREAM_([A-Z0-9_]*)_msgs\[\] = \{([^\}]*)')
+ AP_MESSAGE = re.compile(r'MSG_([A-Z0-9_]*)')
+ # regex for named values
+ NAMED_FLOAT = re.compile(r'send_named_float\("([\w]*)"')
+ NAMED_INT = re.compile(r'send_named_int\("([\w]*)"')
+
+ TYPE_DESCRIPTIONS = {
+ 'incoming_messages':
+ 'Messages the autopilot handles when received.',
+ 'requestable_messages':
+ 'Messages that can be requested/streamed from the autopilot.',
+ 'outgoing_messages':
+ 'Messages the autopilot will send automatically (unrequested).',
+ 'named_floats':
+ 'Breakout of named floating-point (numerical) values sent by the autopilot.',
+ 'named_ints':
+ 'Breakout of named integer values sent by the autopilot.',
+ }
+ EXTRA_DESCRIPTIONS = {
+ 'stream_groups':
+ 'Message groups with stream rates requestable by `SRn_*` parameters.'
+ ' Messages in a group are only sent if the corresponding feature'
+ ' is active.',
+ 'missing_messages':
+ 'Unsupported / unhandled messages.',
+ 'incoming_commands':
+ TYPE_DESCRIPTIONS['incoming_messages'].replace('Messages','Commands'),
+ }
+ EXTRA_DESCRIPTIONS['missing_commands'] = \
+ EXTRA_DESCRIPTIONS['missing_messages'].replace('messages', 'commands')
+
+ TYPE_OPTIONS = {
+ 'messages': MAVLinkMessage,
+ 'commands': MAVLinkCommand,
+ }
+
+ MAVLINK_URL = 'https://mavlink.io/en/messages/{dialect}.html#{message_name}'
+ ARDUPILOT_URL = 'https://github.com/ArduPilot/ardupilot/tree/{branch}/{source}'
+ EXPORT_FILETYPES = {
+ 'csv': 'csv',
+ 'markdown': 'md'
+ }
+
+ MARKDOWN_INTRO = (
+ 'The [MAVLink](https://mavlink.io/en/) protocol supports a variety'
+ ' of features and functionalities, but not all'
+ ' [messages](https://mavlink.io/en/messages/) or'
+ ' [commands](https://mavlink.io/en/services/command.html)'
+ ' are implemented by the ArduPilot ecosystem, or relevant to a'
+ ' particular autopilot firmware.\n\n'
+ 'This page is auto-generated from analysing the {vehicle} source'
+ ' code, and provides an indication of which messages{commands} are'
+ ' handled by, requestable from, and sent from the firmware. '
+ 'A message being handled does not guarantee full support, but at'
+ ' least shows that the autopilot is aware it exists, and will try'
+ ' to do something meaningful with it.{unsupported}{stream_groups}'
+ )
+
+ VEHICLES = ('AntennaTracker', 'ArduCopter', 'ArduPlane', 'ArduSub', 'Rover')
+
+ def __init__(self, common_files, vehicle='ALL',
+ exclude_libraries=['SITL', 'AP_Scripting']):
+ self.vehicle = vehicle
+ vehicles = [vehicle] if vehicle != 'ALL' else self.VEHICLES
+ files = chain(*((self.BASE_DIR / vehicle).glob('**/*.cpp')
+ for vehicle in vehicles),
+ common_files)
+ self.incoming_messages = {}
+ self.incoming_commands = {}
+ self.outgoing_messages = {}
+ self.requestable_messages = {}
+ self._ap_to_mavlink = {
+ 'NAMED_FLOAT': 'NAMED_VALUE_FLOAT', # manual inclusion
+ }
+ self.named_floats = {}
+ self.named_ints = {}
+
+ for file in files:
+ folder = file.parent.stem
+ if folder in exclude_libraries:
+ continue
+ text = file.read_text()
+ source = f'{folder}/{file.name}'
+ if file == self.COMMON_FILE:
+ for mavlink, ap_message in self.find_requestable_messages(text):
+ self.requestable_messages[mavlink] = \
+ MAVLinkMessage(mavlink, source)
+ if ap_message != mavlink:
+ self._ap_to_mavlink[ap_message] = mavlink
+
+ named_types = ('float', 'int') if folder in vehicles else ()
+ for type_ in named_types:
+ substring = f'named_{type_}s'
+ method = getattr(self, f'find_{substring}')
+ names = getattr(self, substring)
+ new_names = set(method(text)) - names.keys()
+ for name in new_names:
+ names[name] = MAVLinkMessage(f'NAMED_VALUE_{type_.upper()}:{name}',
+ source, MAVLinkDialect.COMMON)
+
+ for method, data, type_ in (
+ (self.find_incoming_messages, self.incoming_messages, 'messages'),
+ (self.find_incoming_commands, self.incoming_commands, 'commands'),
+ (self.find_outgoing_messages, self.outgoing_messages, 'messages'),
+ ):
+ new_data = set(method(text)) - data.keys()
+ cls = self.TYPE_OPTIONS[type_]
+ for datum in new_data:
+ data[datum] = cls(datum, source)
+
+ self._supported_names = {'messages': None, 'commands': None}
+ self._unsupported = self._supported_names.copy()
+
+ self._stream_groups = self.get_stream_groups(vehicle) if len(vehicles) == 1 else []
+
+ @classmethod
+ def get_description(cls, query):
+ return cls.TYPE_DESCRIPTIONS.get(query,
+ cls.EXTRA_DESCRIPTIONS.get(query, '')
+ )
+
+ @classmethod
+ def find_incoming_messages(cls, text: str):
+ return cls.INCOMING_MESSAGES.findall(text)
+
+ @classmethod
+ def find_incoming_commands(cls, text: str):
+ return cls.INCOMING_COMMANDS.findall(text)
+
+ @classmethod
+ def find_outgoing_messages(cls, text: str):
+ return (msg.upper() for msg in
+ cls.OUTGOING_MESSAGES.findall(text))
+
+ @classmethod
+ def find_requestable_messages(cls, text: str):
+ region = cls.REQUESTABLE_REGION.search(text).group()
+ return cls.REQUESTABLE_MAP.findall(region)
+
+ @classmethod
+ def find_named_floats(cls, text: str):
+ return cls.NAMED_FLOAT.findall(text)
+
+ @classmethod
+ def find_named_ints(cls, text: str):
+ return cls.NAMED_INT.findall(text)
+
+ def get_stream_groups(self, vehicle):
+ stream_groups = ['stream_groups']
+
+ text = (self.BASE_DIR / vehicle / self.STREAM_GROUP_FILE).read_text()
+ for group_name, message_data in self.STREAM_GROUPS.findall(text):
+ stream_groups.extend(sorted(
+ MAVLinkMessage(self._ap_to_mavlink.get(ap_message, ap_message),
+ f'SRn_{group_name}')
+ for ap_message in self.AP_MESSAGE.findall(message_data)
+ ))
+
+ return stream_groups
+
+ def get_supported(self, type: str, inject_commands=False):
+ if type == 'messages':
+ for message_type in self.TYPE_DESCRIPTIONS:
+ values = getattr(self, message_type).values()
+ if not values:
+ continue
+ yield message_type
+ yield from sorted(values)
+ # add in incoming_commands right after incoming_messages
+ if inject_commands and message_type == 'incoming_messages':
+ yield from self.get_supported('commands')
+ elif type == 'commands':
+ yield 'incoming_commands'
+ yield from sorted(self.incoming_commands.values())
+
+ def get_supported_names(self, type: str):
+ if self._supported_names[type] is None:
+ self._supported_names[type] = set(
+ m.id_name for m in self.get_supported(type)
+ if isinstance(m, MAVLinkMessage)
+ )
+ return self._supported_names[type]
+
+ def get_unsupported(self, type='messages'):
+ if self._unsupported[type] is None:
+ supported_messages = self.get_supported_names(type)
+ cls = self.TYPE_OPTIONS[type]
+ self._unsupported[type] = sorted(
+ cls.get_unsupported(supported_messages)
+ )
+
+ if self._unsupported[type]:
+ yield f'missing_{type}'
+ yield from self._unsupported[type]
+
+ def get_iterable(self, include_commands=False, include_stream_groups=False,
+ include_unsupported=False):
+ iterables = [self.get_supported('messages', include_commands)]
+ if include_stream_groups:
+ iterables.append(self._stream_groups)
+ if include_unsupported:
+ iterables.append(self.get_unsupported('messages'))
+ if include_commands:
+ iterables.append(self.get_unsupported('commands'))
+ return chain(*iterables)
+
+ def printout(self, **iter_options):
+ for data in self.get_iterable(**iter_options):
+ match data: # requires Python >= 3.10
+ case str() as type_:
+ print(f'\n{type_}:',
+ self.get_description(type_),
+ sep='\n')
+ case MAVLinkMessage() as message:
+ print(message)
+
+ def export(self, filename: Path, type='csv', include_commands=False,
+ include_stream_groups=False, include_unsupported=False,
+ **export_options):
+ export_method = getattr(self, f'export_{type}')
+ # ensure export_method and get_iterable have the same options specified
+ iter_options = dict(
+ include_commands = include_commands,
+ include_stream_groups = include_stream_groups,
+ include_unsupported = include_unsupported,
+ )
+ with open(filename, 'w') as file:
+ export_method(file, self.get_iterable(**iter_options),
+ **export_options, **iter_options)
+
+ def export_csv(self, file, iterable, **ignore):
+ file.write('MAVLinkMessage,CodeSource,MAVLinkDialect,MessageType\n')
+ for data in iterable:
+ match data:
+ case str():
+ current_type = data
+ case MAVLinkMessage() as message:
+ print(*message.as_tuple(), current_type, sep=',', file=file)
+
+ def export_markdown(self, file, iterable, branch='master', header=None,
+ use_intro=True, **extra_kwargs):
+ if header == 'ArduSub':
+ import time
+ now = time.strftime('%Y-%m-%dT%H:%M:%S%z')
+ date = f'{now[:-2]}:{now[-2:]}' # add colon to the timezone
+ header = '\n'.join((
+ '+++',
+ 'title = "MAVLink Support"',
+ 'description = "MAVLink message support details."',
+ f'{date = }', 'template = "docs/page.html"',
+ 'sort_by = "weight"', 'weight = 20', 'draft = false',
+ '[extra]', 'toc = true', 'top = false',
+ '+++'
+ ))
+ if header:
+ print(header, file=file)
+
+ if use_intro:
+ commands = stream_groups = unsupported = ''
+ if extra_kwargs['include_commands']:
+ commands = ' (and commands)'
+ if extra_kwargs['include_unsupported']:
+ unsupported = (
+ '\n\nKnown [unsupported messages](#missing-messages)'
+ f'{commands} are shown at the end.'
+ )
+ if extra_kwargs['include_stream_groups']:
+ stream_groups = (
+ '\n\nThe autopilot includes a set of [stream groups]'
+ '(#stream-groups) for convenience, which allow'
+ ' configuring the stream rates of groups of'
+ ' requestable messages by setting parameter values. '
+ 'It is also possible to manually request messages,'
+ ' and request individual messages be streamed at a'
+ ' specified rate.'
+ )
+ vehicle = self.vehicle.replace('ALL', 'ArduPilot')
+
+ print(self.MARKDOWN_INTRO.format(
+ vehicle=vehicle, commands=commands,
+ stream_groups=stream_groups, unsupported=unsupported
+ ), file=file)
+
+ for data in iterable:
+ match data:
+ case str() as type_:
+ heading = type_.title().replace('_', ' ')
+ source_header = (
+ 'Code Source' if type_ != 'stream_groups' else
+ 'Stream Group Parameter'
+ )
+ print(f'## {heading}',
+ self.get_description(type_),
+ f'\nMAVLink Message | {source_header} | MAVLink Dialect',
+ '--- | --- | ---', sep='\n', file=file)
+ case MAVLinkMessage() as message:
+ name, source, dialect = message.as_tuple()
+ if dialect != MAVLinkDialect.UNKNOWN:
+ msg_url = self.MAVLINK_URL.format(dialect=dialect,
+ message_name=name.split(':')[0])
+ name = f'[{name}]({msg_url})'
+ if source != 'UNSUPPORTED' and not source.startswith('SRn'):
+ folder = source.split('/')[0]
+ base = 'libraries/' if folder not in self.VEHICLES else ''
+ code_url = self.ARDUPILOT_URL.format(branch=branch,
+ source=base+source)
+ source = f'[{source}]({code_url})'
+
+ print(name, source, dialect, sep=' | ', file=file)
+
+
+if __name__ == '__main__':
+ from inspect import signature
+ from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter
+
+ detector_init_params = signature(MAVLinkDetector.__init__).parameters
+ default_vehicle = detector_init_params['vehicle'].default
+ vehicle_options = [default_vehicle, *MAVLinkDetector.VEHICLES]
+ default_exclusions = detector_init_params['exclude_libraries'].default
+
+ parser = ArgumentParser(formatter_class=ArgumentDefaultsHelpFormatter)
+ parse_opts = parser.add_argument_group('parsing options')
+ parse_opts.add_argument('-v', '--vehicle', default=default_vehicle,
+ choices=vehicle_options, help='Vehicle folder, or ALL.')
+ parse_opts.add_argument('-e', '--exclude-library', action='append',
+ default=default_exclusions,
+ help='Libraries to exclude from the search.')
+ parse_opts.add_argument('-c', '--include-commands', action='store_true',
+ help='Include MAVLink commands as well as messages.')
+ parse_opts.add_argument('-g', '--include-stream-groups', action='store_true',
+ help='Include stream group message sets in the output.')
+ parse_opts.add_argument('-u', '--include-unsupported', action='store_true',
+ help='Include unsupported messages in the output.')
+ export_opts = parser.add_argument_group('export options')
+ export_opts.add_argument('-q', '--quiet', action='store_true',
+ help='Disable printout, only export a file.')
+ export_opts.add_argument('-f', '--format', default='markdown',
+ choices=['csv', 'markdown', 'none'],
+ help='Desired format for the exported file.')
+ export_opts.add_argument('-b', '--branch',
+ help=('The branch to link to in markdown mode.'
+ ' Defaults to the branch in the working directory.'))
+ export_opts.add_argument('--filename', help='Override default filename.')
+ export_opts.add_argument('--header', help='Header for the markdown file.')
+ export_opts.add_argument('--no-intro', action='store_true',
+ help="Flag to not use the automatic markdown intro.")
+
+ args = parser.parse_args()
+
+ assert (args.vehicle in MAVLinkDetector.VEHICLES
+ or not args.include_stream_groups), \
+ 'Determining stream groups requires a single vehicle to be specified.'
+
+ common_files = (MAVLinkDetector.BASE_DIR / 'libraries').glob('**/*.cpp')
+ messages = MAVLinkDetector(common_files, args.vehicle, args.exclude_library)
+
+ include_options = dict(
+ include_commands = args.include_commands,
+ include_stream_groups = args.include_stream_groups,
+ include_unsupported = args.include_unsupported,
+ )
+
+ if not args.quiet:
+ messages.printout(**include_options)
+ if args.format != 'none':
+ ext = messages.EXPORT_FILETYPES[args.format]
+ branch = args.branch
+ if not branch:
+ import subprocess
+ pattern = re.compile(r'On branch ([\S]*)')
+ result = subprocess.run(['git', 'status'], capture_output=True).stdout
+ try:
+ branch, = pattern.search(result.decode()).groups()
+ except AttributeError as e:
+ raise Exception(
+ 'No --branch specified, and "git status" failed to find one.'
+ 'Please manually specify an ardupilot firmware branch for '
+ 'code source hyperlinks (e.g. Sub-4.1) or ensure this '
+ 'repository copy is managed by git.'
+ )
+
+ filename = (
+ args.filename or
+ f'{args.vehicle}_{branch}_MAVLink_Messages.{ext}'
+ )
+
+ messages.export(filename, type=args.format, branch=branch, header=args.header,
+ use_intro=not args.no_intro, **include_options)
diff --git a/Tools/scripts/param_unpack.py b/Tools/scripts/param_unpack.py
index 4a0b5e7578d3b0..5d4c1c5e59ddd2 100755
--- a/Tools/scripts/param_unpack.py
+++ b/Tools/scripts/param_unpack.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
'''
unpack a param.pck file from @PARAM/param.pck via mavlink FTP
'''
diff --git a/Tools/scripts/run_astyle.py b/Tools/scripts/run_astyle.py
index 2a9ac336b74c1a..bf6ff415c97c4f 100755
--- a/Tools/scripts/run_astyle.py
+++ b/Tools/scripts/run_astyle.py
@@ -14,15 +14,18 @@
import argparse
os.environ['PYTHONUNBUFFERED'] = '1'
+DRY_RUN_DEFAULT = False
class AStyleChecker(object):
- def __init__(self):
+ def __init__(self, *, dry_run=DRY_RUN_DEFAULT):
self.retcode = 0
self.directories_to_check = [
'libraries/AP_DDS',
+ 'libraries/AP_ExternalControl'
]
self.files_to_check = []
+ self.dry_run = dry_run
def progress(self, string):
print("****** %s" % (string,))
@@ -31,7 +34,11 @@ def check(self):
'''run astyle on all files in self.files_to_check'''
# for path in self.files_to_check:
# self.progress("Checking (%s)" % path)
- astyle_command = ["astyle", "--dry-run"]
+ astyle_command = ["astyle"]
+ if self.dry_run:
+ astyle_command.append("--dry-run")
+
+ astyle_command.append("--options=Tools/CodeStyle/astylerc")
astyle_command.extend(self.files_to_check)
ret = subprocess.run(
astyle_command,
@@ -57,8 +64,11 @@ def run(self):
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Check all Python files for astyle cleanliness')
- # parser.add_argument('--build', action='store_true', default=False, help='build as well as configure')
+ parser.add_argument('--dry-run',
+ action='store_true',
+ default=DRY_RUN_DEFAULT,
+ help='Perform a trial run with no changes made to check for formatting')
args = parser.parse_args()
- checker = AStyleChecker()
+ checker = AStyleChecker(dry_run=args.dry_run)
sys.exit(checker.run())
diff --git a/Tools/scripts/run_coverage.py b/Tools/scripts/run_coverage.py
index 3c254e205eec59..ee6e4c24a34bc6 100755
--- a/Tools/scripts/run_coverage.py
+++ b/Tools/scripts/run_coverage.py
@@ -24,7 +24,7 @@
class CoverageRunner(object):
"""Coverage Runner Class."""
- def __init__(self, verbose=False, check_tests=True):
+ def __init__(self, verbose=False, check_tests=True) -> None:
"""Set the files Path."""
self.REPORT_DIR = os.path.join(root_dir, "reports/lcov-report")
self.INFO_FILE = os.path.join(root_dir, self.REPORT_DIR, "lcov.info")
@@ -37,13 +37,13 @@ def __init__(self, verbose=False, check_tests=True):
self.check_tests = check_tests
self.start_time = time.time()
- def progress(self, text):
+ def progress(self, text) -> None:
"""Pretty printer."""
delta_time = time.time() - self.start_time
formatted_text = "****** AT-%06.1f: %s" % (delta_time, text)
print(formatted_text)
- def init_coverage(self, use_example=False):
+ def init_coverage(self, use_example=False) -> None:
"""Initialize ArduPilot for coverage.
This needs to be run with the binaries built.
@@ -64,6 +64,7 @@ def init_coverage(self, use_example=False):
binaries_dir = os.path.join(root_dir, 'build/sitl/bin')
dirs_to_check = [["binaries", binaries_dir], ["tests", os.path.join(root_dir, 'build/linux/tests')]]
if use_example:
+ self.progress("Adding examples")
dirs_to_check.append(["examples", os.path.join(root_dir, 'build/linux/examples')])
for dirc in dirs_to_check:
if not (self.check_build(dirc[0], dirc[1])):
@@ -98,7 +99,7 @@ def init_coverage(self, use_example=False):
exit(1)
self.progress("Initialization done")
- def check_build(self, name, path):
+ def check_build(self, name, path) -> bool:
"""Check that build directory is not empty and that binaries are built with the coverage flags."""
self.progress("Checking that %s are set up and built" % name)
if os.path.exists(path):
@@ -114,7 +115,7 @@ def check_build(self, name, path):
self.progress("%s was't built with coverage support" % name)
return False
- def run_build(self, use_example=False):
+ def run_build(self, use_example=False) -> None:
"""Clean the build directory and build binaries for coverage."""
os.chdir(root_dir)
@@ -127,6 +128,7 @@ def run_build(self, use_example=False):
try:
if use_example:
+ self.progress("Building examples")
subprocess.run([waf_light, "configure", "--board=linux", "--debug", "--coverage"], check=True)
subprocess.run([waf_light, "examples"], check=True)
subprocess.run(
@@ -144,7 +146,7 @@ def run_build(self, use_example=False):
exit(1)
self.progress("Build examples and vehicle binaries done !")
- def run_full(self, use_example=False):
+ def run_full(self, use_example=False) -> None:
"""Run full coverage on maximum of ArduPilot binaries and test functions."""
self.progress("Running full test suite...")
self.run_build()
@@ -158,6 +160,7 @@ def run_full(self, use_example=False):
subprocess.run([self.autotest,
"--timeout=" + str(TIMEOUT),
"--debug",
+ "--coverage",
"--no-clean",
"--speedup=" + str(SPEEDUP),
"run.examples"], check=self.check_tests)
@@ -174,16 +177,20 @@ def run_full(self, use_example=False):
test_list = ["Plane", "QuadPlane", "Sub", "Copter", "Helicopter", "Rover", "Tracker", "BalanceBot", "Sailboat"]
for test in test_list:
self.progress("Running test.%s" % test)
- subprocess.run([self.autotest,
- "--timeout=" + str(TIMEOUT),
- "--debug",
- "--no-clean",
- "test.%s" % test], check=self.check_tests)
+ try:
+ subprocess.run([self.autotest,
+ "--timeout=" + str(TIMEOUT),
+ "--debug",
+ "--no-clean",
+ "test.%s" % test], check=self.check_tests)
+ except subprocess.CalledProcessError:
+ # pass in case of failing tests
+ pass
# TODO add any other execution path/s we can to maximise the actually
# used code, can we run other tests or things? Replay, perhaps?
self.update_stats()
- def update_stats(self):
+ def update_stats(self) -> None:
"""Update Coverage statistics only.
Assumes that coverage tests have been run.
@@ -228,6 +235,7 @@ def update_stats(self):
root_dir + "/modules/gtest/*",
root_dir + "/modules/DroneCAN/libcanard/*",
root_dir + "/build/linux/libraries/*",
+ root_dir + "/build/linux/modules/*",
root_dir + "/build/sitl/libraries/*",
root_dir + "/build/sitl/modules/*",
root_dir + "/build/sitl_periph_gps/libraries/*",
@@ -276,6 +284,10 @@ def update_stats(self):
parser = argparse.ArgumentParser(description='Runs tests with gcov coverage support.')
parser.add_argument('-v', '--verbose', action='store_true',
help='Output everything on terminal.')
+ parser.add_argument('-c', '--no-check-tests', action='store_true',
+ help='Do not fail if tests do not run.')
+ parser.add_argument('--add-examples', action='store_true',
+ help='Add examples to coverage.')
group = parser.add_mutually_exclusive_group()
group.add_argument('-i', '--init', action='store_true',
help='Initialise ArduPilot for coverage. It should be run after building the binaries.')
@@ -285,20 +297,17 @@ def update_stats(self):
help='Clean the build directory and build binaries for coverage.')
group.add_argument('-u', '--update', action='store_true',
help='Update coverage statistics. To be used after running some tests.')
- group.add_argument('-c', '--no-check-tests', action='store_true',
- help='Do not fail if tests do not run.')
-
args = parser.parse_args()
runner = CoverageRunner(verbose=args.verbose, check_tests=not args.no_check_tests)
if args.init:
- runner.init_coverage()
+ runner.init_coverage(args.add_examples)
sys.exit(0)
if args.full:
- runner.run_full()
+ runner.run_full(args.add_examples)
sys.exit(0)
if args.build:
- runner.run_build()
+ runner.run_build(args.add_examples)
sys.exit(0)
if args.update:
runner.update_stats()
diff --git a/Tools/scripts/run_luacheck.sh b/Tools/scripts/run_luacheck.sh
index bed71fb88e206a..43e0af5d0e9275 100755
--- a/Tools/scripts/run_luacheck.sh
+++ b/Tools/scripts/run_luacheck.sh
@@ -1,7 +1,15 @@
#!/bin/bash
# Run lua check for all lua files passing AP specific config
+# Can also pass any number of arguments that are passed onto luacheck
+# for example the path of a single script could be given
cd "$(dirname "$0")"
cd ../..
-luacheck */ --config libraries/AP_Scripting/tests/luacheck.lua
+CHECK_PATH="$*"
+if test -z "$CHECK_PATH"
+then
+ CHECK_PATH="*/"
+fi
+
+luacheck ${CHECK_PATH} --config libraries/AP_Scripting/tests/luacheck.lua
diff --git a/Tools/scripts/sensor_status_change.py b/Tools/scripts/sensor_status_change.py
new file mode 100755
index 00000000000000..0b5e5ea28ca239
--- /dev/null
+++ b/Tools/scripts/sensor_status_change.py
@@ -0,0 +1,87 @@
+#!/usr/bin/env python
+
+"""
+Parses a log file and shows how the SENSOR_STATUS flags changed over time
+
+AP_FLAKE8_CLEAN
+
+"""
+
+from __future__ import print_function
+
+import optparse
+import sys
+import time
+
+from pymavlink import mavutil
+
+
+class SYS_STATUS_Change(object):
+ def __init__(self, master):
+ self.master = master
+
+ def progress(self, text):
+ '''emit text with possible timestamps etc'''
+ print("%u: %s" % (time.time(), text))
+
+ def bit_description(self, bit_number):
+ if 1 << bit_number not in mavutil.mavlink.enums["MAV_SYS_STATUS_SENSOR"]:
+ return "UNKNOWN_BIT[%u]" % bit_number
+
+ name = mavutil.mavlink.enums["MAV_SYS_STATUS_SENSOR"][1 << bit_number].name
+ # return name with common prefix removed:
+ return name[len("MAV_SYS_STATUS_"):]
+
+ def run(self):
+
+ self.progress("Creating connection")
+ self.conn = mavutil.mavlink_connection(master)
+
+ fields = ['present', 'enabled', 'health']
+
+ current = dict()
+ for f in fields:
+ current[f] = 0
+ while True:
+ m = self.conn.recv_match(type="SYS_STATUS")
+ if m is None:
+ break
+
+ line = ""
+ for f in fields:
+ current_values = current[f]
+ new_values = getattr(m, "onboard_control_sensors_" + f)
+ for bit in range(0, 32):
+ mask = 1 << bit
+ old_bit_set = current_values & mask
+ new_bit_set = new_values & mask
+ if new_bit_set and not old_bit_set:
+ line += " %s+%s" % (f, self.bit_description(bit))
+ elif not new_bit_set and old_bit_set:
+ line += " %s-%s" % (f, self.bit_description(bit))
+ current[f] = new_values
+
+ if len(line) == 0:
+ continue
+
+ timestamp = getattr(m, '_timestamp', 0.0)
+ formatted_timestamp = "%s.%02u" % (
+ time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(timestamp)),
+ int(timestamp * 100.0) % 100)
+
+ print("%s: %s" % (formatted_timestamp, line))
+
+
+if __name__ == '__main__':
+ parser = optparse.OptionParser("sys_status_change.py [options]")
+
+ (opts, args) = parser.parse_args()
+
+ if len(args) < 1:
+ parser.print_help()
+ sys.exit(1)
+
+ master = args[0]
+
+ tester = SYS_STATUS_Change(master)
+ tester.run()
diff --git a/libraries/SITL/examples/on-hardware/README.md b/Tools/scripts/sitl-on-hardware/README.md
similarity index 100%
rename from libraries/SITL/examples/on-hardware/README.md
rename to Tools/scripts/sitl-on-hardware/README.md
diff --git a/Tools/scripts/sitl-on-hardware/default.param b/Tools/scripts/sitl-on-hardware/default.param
new file mode 100644
index 00000000000000..6e8288127c1e31
--- /dev/null
+++ b/Tools/scripts/sitl-on-hardware/default.param
@@ -0,0 +1,28 @@
+AHRS_EKF_TYPE 10
+
+GPS_TYPE 100
+
+INS_ACCOFFS_X 0.001
+INS_ACCOFFS_Y 0.001
+INS_ACCOFFS_Z 0.001
+INS_ACCSCAL_X 1.001
+INS_ACCSCAL_Y 1.001
+INS_ACCSCAL_Z 1.001
+INS_ACC2OFFS_X 0.001
+INS_ACC2OFFS_Y 0.001
+INS_ACC2OFFS_Z 0.001
+INS_ACC2SCAL_X 1.001
+INS_ACC2SCAL_Y 1.001
+INS_ACC2SCAL_Z 1.001
+
+
+
+SIM_MAG1_DEVID 97539
+
+
+SIM_RATE_HZ 400
+SCHED_LOOP_RATE 400
+
+BRD_RTC_TYPES 2
+BRD_HEAT_TARG 25
+BRD_SAFETY_DEFLT 0
diff --git a/libraries/SITL/examples/on-hardware/extra-hwdef-sitl-on-hw.dat b/Tools/scripts/sitl-on-hardware/extra-hwdef-sitl-on-hw.dat
similarity index 68%
rename from libraries/SITL/examples/on-hardware/extra-hwdef-sitl-on-hw.dat
rename to Tools/scripts/sitl-on-hardware/extra-hwdef-sitl-on-hw.dat
index 6cf2b25d454503..3b0a3f192cb870 100644
--- a/libraries/SITL/examples/on-hardware/extra-hwdef-sitl-on-hw.dat
+++ b/Tools/scripts/sitl-on-hardware/extra-hwdef-sitl-on-hw.dat
@@ -3,30 +3,21 @@ env SIM_ENABLED 1
define INS_MAX_INSTANCES 2
define HAL_COMPASS_MAX_SENSORS 2
+define AP_GPS_BACKEND_DEFAULT_ENABLED 0
+define AP_RANGEFINDER_BACKEND_DEFAULT_ENABLED 0
+
define HAL_NAVEKF2_AVAILABLE 0
define EK3_FEATURE_BODY_ODOM 0
define EK3_FEATURE_EXTERNAL_NAV 0
define EK3_FEATURE_DRAG_FUSION 0
define HAL_ADSB_ENABLED 0
-define HAL_MOUNT_ENABLED 0
define HAL_PROXIMITY_ENABLED 0
define HAL_VISUALODOM_ENABLED 0
define HAL_GENERATOR_ENABLED 0
-# define HAL_LOGGING_ENABLED 0
-define HAL_CRSF_TELEM_ENABLED 0
-#define OSD_ENABLED 0
-define FRAME_HEXA 0
-define FRAME_OCTA 0
-define FRAME_DODECAHEXA 0
-define FRAME_Y6 0
-define FRAME_OCTAQUAD 0
-define MODE_SMARTRTL_ENABLED 0
define MODE_SPORT_ENABLED 0
-# define MODE_CIRCLE_ENABLED 0
define MODE_THROW_ENABLED 0
define MODE_TURTLE_ENABLED 0
-define MODE_ZIGZAG_ENABLED 0
define MODE_FLOWHOLD 0
define MODE_POSHOLD_ENABLED 0
define MODE_SYSTEMID_ENABLED 0
@@ -36,13 +27,10 @@ define MODE_FLIP_ENABLED 0
define MODE_DRIFT_ENABLED 0
define MODE_THROW_ENABLED 0
-define AP_LANDINGGEAR_ENABLED 0
+
define HAL_MSP_OPTICALFLOW_ENABLED 0
define HAL_SUPPORT_RCOUT_SERIAL 0
define HAL_HOTT_TELEM_ENABLED 0
-# define HAL_GYROFFT_ENABLED 0
-
-
define HAL_HIGH_LATENCY2 0
define AP_SIM_INS_FILE_ENABLED 0
diff --git a/libraries/SITL/examples/on-hardware/plane-default.param b/Tools/scripts/sitl-on-hardware/plane-default.param
similarity index 54%
rename from libraries/SITL/examples/on-hardware/plane-default.param
rename to Tools/scripts/sitl-on-hardware/plane-default.param
index c45feab9e36894..38693da247d2df 100644
--- a/libraries/SITL/examples/on-hardware/plane-default.param
+++ b/Tools/scripts/sitl-on-hardware/plane-default.param
@@ -1,26 +1,5 @@
AHRS_EKF_TYPE 10
-BATT_MONITOR 0
-
-COMPASS_OFS_X 5
-COMPASS_OFS_Y 13
-COMPASS_OFS_Z -18
-COMPASS_OFS2_X 5
-COMPASS_OFS2_Y 13
-COMPASS_OFS2_Z -18
-
-THR_FAILSAFE 1
-THR_FS_VALUE 950
-
-RC7_OPTION 7
-
-FLTMODE1 7
-FLTMODE2 9
-FLTMODE3 6
-FLTMODE4 3
-FLTMODE5 5
-FLTMODE6 0
-
GPS_TYPE 100
INS_ACCOFFS_X 0.001
@@ -36,16 +15,16 @@ INS_ACC2SCAL_X 1.001
INS_ACC2SCAL_Y 1.001
INS_ACC2SCAL_Z 1.001
-SCHED_DEBUG 0
SIM_MAG1_DEVID 97539
-SIM_BARO_RND 0
+
SIM_RATE_HZ 400
SCHED_LOOP_RATE 400
BRD_RTC_TYPES 2
+BRD_HEAT_TARG 25
+BRD_SAFETY_DEFLT 0
SERVO3_MIN 1000
-SERVO3_TRIM 1000
SERVO3_MAX 2000
diff --git a/libraries/SITL/examples/on-hardware/plane-extra-hwdef-sitl-on-hw.dat b/Tools/scripts/sitl-on-hardware/plane-extra-hwdef-sitl-on-hw.dat
similarity index 63%
rename from libraries/SITL/examples/on-hardware/plane-extra-hwdef-sitl-on-hw.dat
rename to Tools/scripts/sitl-on-hardware/plane-extra-hwdef-sitl-on-hw.dat
index c2a3bb6d6efaa0..27868fd515b3d7 100644
--- a/libraries/SITL/examples/on-hardware/plane-extra-hwdef-sitl-on-hw.dat
+++ b/Tools/scripts/sitl-on-hardware/plane-extra-hwdef-sitl-on-hw.dat
@@ -3,30 +3,21 @@ env SIM_ENABLED 1
define INS_MAX_INSTANCES 2
define HAL_COMPASS_MAX_SENSORS 2
+define AP_GPS_BACKEND_DEFAULT_ENABLED 0
+define AP_RANGEFINDER_BACKEND_DEFAULT_ENABLED 0
+
define HAL_NAVEKF2_AVAILABLE 0
define EK3_FEATURE_BODY_ODOM 0
define EK3_FEATURE_EXTERNAL_NAV 0
define EK3_FEATURE_DRAG_FUSION 0
define HAL_ADSB_ENABLED 0
-define HAL_MOUNT_ENABLED 0
define HAL_PROXIMITY_ENABLED 0
define HAL_VISUALODOM_ENABLED 0
define HAL_GENERATOR_ENABLED 0
-# define HAL_LOGGING_ENABLED 0
-define HAL_CRSF_TELEM_ENABLED 0
-#define OSD_ENABLED 0
-define FRAME_HEXA 0
-define FRAME_OCTA 0
-define FRAME_DODECAHEXA 0
-define FRAME_Y6 0
-define FRAME_OCTAQUAD 0
-define AP_LANDINGGEAR_ENABLED 0
define HAL_MSP_OPTICALFLOW_ENABLED 0
define HAL_SUPPORT_RCOUT_SERIAL 0
define HAL_HOTT_TELEM_ENABLED 0
-# define HAL_GYROFFT_ENABLED 0
-
define HAL_HIGH_LATENCY2 0
define AP_SIM_INS_FILE_ENABLED 0
diff --git a/libraries/SITL/examples/on-hardware/sitl-on-hw.py b/Tools/scripts/sitl-on-hardware/sitl-on-hw.py
similarity index 100%
rename from libraries/SITL/examples/on-hardware/sitl-on-hw.py
rename to Tools/scripts/sitl-on-hardware/sitl-on-hw.py
diff --git a/libraries/SITL/examples/on-hardware/some.script b/Tools/scripts/sitl-on-hardware/some.script
similarity index 100%
rename from libraries/SITL/examples/on-hardware/some.script
rename to Tools/scripts/sitl-on-hardware/some.script
diff --git a/Tools/scripts/size_compare_branches.py b/Tools/scripts/size_compare_branches.py
index 092e718c797dcc..886e3878767557 100755
--- a/Tools/scripts/size_compare_branches.py
+++ b/Tools/scripts/size_compare_branches.py
@@ -17,16 +17,24 @@
'''
import copy
+import fnmatch
import optparse
import os
+import pathlib
import shutil
import string
import subprocess
import sys
import tempfile
+import threading
import time
import board_list
+try:
+ import queue as Queue
+except ImportError:
+ import Queue
+
if sys.version_info[0] < 3:
running_python3 = False
else:
@@ -54,15 +62,20 @@ def __init__(self,
bin_dir=None,
run_elf_diff=True,
all_vehicles=False,
+ exclude_board_glob=[],
all_boards=False,
use_merge_base=True,
waf_consistent_builds=True,
show_empty=True,
+ show_unchanged=True,
extra_hwdef=[],
extra_hwdef_branch=[],
- extra_hwdef_master=[]):
+ extra_hwdef_master=[],
+ parallel_copies=None,
+ jobs=None):
+
if branch is None:
- branch = self.find_current_git_branch()
+ branch = self.find_current_git_branch_or_sha1()
self.master_branch = master_branch
self.branch = branch
@@ -78,6 +91,9 @@ def __init__(self,
self.use_merge_base = use_merge_base
self.waf_consistent_builds = waf_consistent_builds
self.show_empty = show_empty
+ self.show_unchanged = show_unchanged
+ self.parallel_copies = parallel_copies
+ self.jobs = jobs
if self.bin_dir is None:
self.bin_dir = self.find_bin_dir()
@@ -116,6 +132,18 @@ def __init__(self,
if v not in self.vehicle_map.keys():
raise ValueError("Bad vehicle (%s); choose from %s" % (v, ",".join(self.vehicle_map.keys())))
+ # remove boards based on --exclude-board-glob
+ new_self_board = []
+ for board_name in self.board:
+ exclude = False
+ for exclude_glob in exclude_board_glob:
+ if fnmatch.fnmatch(board_name, exclude_glob):
+ exclude = True
+ break
+ if not exclude:
+ new_self_board.append(board_name)
+ self.board = new_self_board
+
# some boards we don't have a -bl.dat for, so skip them.
# TODO: find a way to get this information from board_list:
self.bootloader_blacklist = set([
@@ -131,7 +159,9 @@ def __init__(self,
'skyviper-f412-rev1',
'skyviper-journey',
'Pixhawk1-1M-bdshot',
+ 'Pixhawk1-bdshot',
'SITL_arm_linux_gnueabihf',
+ 'RADIX2HD',
])
# blacklist all linux boards for bootloader build:
@@ -171,6 +201,9 @@ def esp32_board_names(self):
return [
'esp32buzz',
'esp32empty',
+ 'esp32tomte76',
+ 'esp32nick',
+ 'esp32s3devkit',
'esp32icarous',
'esp32diy',
]
@@ -184,15 +217,21 @@ def find_bin_dir(self):
# vast amounts of stuff copied into here from build_binaries.py
- def run_program(self, prefix, cmd_list, show_output=True, env=None):
- if show_output:
- self.progress("Running (%s)" % " ".join(cmd_list))
+ def run_program(self, prefix, cmd_list, show_output=True, env=None, show_output_on_error=True, show_command=None, cwd="."):
+ if show_command is None:
+ show_command = True
+ if show_command:
+ cmd = " ".join(cmd_list)
+ if cwd is None:
+ cwd = "."
+ self.progress(f"Running ({cmd}) in ({cwd})")
p = subprocess.Popen(
cmd_list,
stdin=None,
stdout=subprocess.PIPE,
close_fds=True,
stderr=subprocess.STDOUT,
+ cwd=cwd,
env=env)
output = ""
while True:
@@ -210,18 +249,33 @@ def run_program(self, prefix, cmd_list, show_output=True, env=None):
x = "".join([chr(c) for c in x])
output += x
x = x.rstrip()
+ some_output = "%s: %s" % (prefix, x)
if show_output:
- print("%s: %s" % (prefix, x))
+ print(some_output)
+ else:
+ output += some_output
(_, status) = returncode
if status != 0:
+ if not show_output and show_output_on_error:
+ # we were told not to show output, but we just
+ # failed... so show output...
+ print(output)
self.progress("Process failed (%s)" %
str(returncode))
raise subprocess.CalledProcessError(
returncode, cmd_list)
return output
- def find_current_git_branch(self):
- output = self.run_git(["symbolic-ref", "--short", "HEAD"])
+ def find_current_git_branch_or_sha1(self):
+ try:
+ output = self.run_git(["symbolic-ref", "--short", "HEAD"])
+ output = output.strip()
+ return output
+ except subprocess.CalledProcessError:
+ pass
+
+ # probably in a detached-head state. Get a sha1 instead:
+ output = self.run_git(["rev-parse", "--short", "HEAD"])
output = output.strip()
return output
@@ -230,13 +284,13 @@ def find_git_branch_merge_base(self, branch, master_branch):
output = output.strip()
return output
- def run_git(self, args):
+ def run_git(self, args, show_output=True, source_dir=None):
'''run git with args git_args; returns git's output'''
cmd_list = ["git"]
cmd_list.extend(args)
- return self.run_program("SCB-GIT", cmd_list)
+ return self.run_program("SCB-GIT", cmd_list, show_output=show_output, cwd=source_dir)
- def run_waf(self, args, compiler=None):
+ def run_waf(self, args, compiler=None, show_output=True, source_dir=None):
# try to modify the environment so we can consistent builds:
consistent_build_envs = {
"CHIBIOS_GIT_VERSION": "12345678",
@@ -265,16 +319,19 @@ def run_waf(self, args, compiler=None):
env["CXX"] = "ccache arm-none-eabi-g++"
else:
raise Exception("BB-WAF: Missing compiler %s" % gcc_path)
- self.run_program("SCB-WAF", cmd_list, env=env)
+ self.run_program("SCB-WAF", cmd_list, env=env, show_output=show_output, cwd=source_dir)
def progress(self, string):
'''pretty-print progress'''
print("SCB: %s" % string)
- def build_branch_into_dir(self, board, branch, vehicle, outdir, extra_hwdef=None):
- self.run_git(["checkout", branch])
- self.run_git(["submodule", "update", "--recursive"])
- shutil.rmtree("build", ignore_errors=True)
+ def build_branch_into_dir(self, board, branch, vehicle, outdir, source_dir=None, extra_hwdef=None, jobs=None):
+ self.run_git(["checkout", branch], show_output=False, source_dir=source_dir)
+ self.run_git(["submodule", "update", "--recursive"], show_output=False, source_dir=source_dir)
+ build_dir = "build"
+ if source_dir is not None:
+ build_dir = os.path.join(source_dir, "build")
+ shutil.rmtree(build_dir, ignore_errors=True)
waf_configure_args = ["configure", "--board", board]
if self.waf_consistent_builds:
waf_configure_args.append("--consistent-builds")
@@ -282,14 +339,22 @@ def build_branch_into_dir(self, board, branch, vehicle, outdir, extra_hwdef=None
if extra_hwdef is not None:
waf_configure_args.extend(["--extra-hwdef", extra_hwdef])
- self.run_waf(waf_configure_args)
+ if self.run_elf_diff:
+ waf_configure_args.extend(["--debug-symbols"])
+
+ if jobs is None:
+ jobs = self.jobs
+ if jobs is not None:
+ waf_configure_args.extend(["-j", str(jobs)])
+
+ self.run_waf(waf_configure_args, show_output=False, source_dir=source_dir)
# we can't run `./waf copter blimp plane` without error, so do
# them one-at-a-time:
for v in vehicle:
if v == 'bootloader':
# need special configuration directive
continue
- self.run_waf([v])
+ self.run_waf([v], show_output=False, source_dir=source_dir)
for v in vehicle:
if v != 'bootloader':
continue
@@ -302,20 +367,229 @@ def build_branch_into_dir(self, board, branch, vehicle, outdir, extra_hwdef=None
# after building other vehicles without a clean:
dsdl_generated_path = os.path.join('build', board, "modules", "DroneCAN", "libcanard", "dsdlc_generated")
self.progress("HACK: Removing (%s)" % dsdl_generated_path)
+ if source_dir is not None:
+ dsdl_generated_path = os.path.join(source_dir, dsdl_generated_path)
shutil.rmtree(dsdl_generated_path, ignore_errors=True)
- self.run_waf(bootloader_waf_configure_args)
- self.run_waf([v])
- self.run_program("rsync", ["rsync", "-aP", "build/", outdir])
+ self.run_waf(bootloader_waf_configure_args, show_output=False, source_dir=source_dir)
+ self.run_waf([v], show_output=False, source_dir=source_dir)
+ self.run_program("rsync", ["rsync", "-ap", "build/", outdir], cwd=source_dir)
+ if source_dir is not None:
+ pathlib.Path(outdir, "scb_sourcepath.txt").write_text(source_dir)
+
+ def vehicles_to_build_for_board_info(self, board_info):
+ vehicles_to_build = []
+ for vehicle in self.vehicle:
+ if vehicle == 'AP_Periph':
+ if not board_info.is_ap_periph:
+ continue
+ else:
+ if board_info.is_ap_periph:
+ continue
+ # the bootloader target isn't an autobuild target, so
+ # it gets special treatment here:
+ if vehicle != 'bootloader' and vehicle.lower() not in [x.lower() for x in board_info.autobuild_targets]:
+ continue
+ vehicles_to_build.append(vehicle)
+
+ return vehicles_to_build
+
+ def parallel_thread_main(self, thread_number):
+ # initialisation; make a copy of the source directory
+ my_source_dir = os.path.join(self.tmpdir, f"thread-{thread_number}-source")
+ self.run_program("rsync", [
+ "rsync",
+ "--exclude=build/",
+ "-ap",
+ "./",
+ my_source_dir
+ ])
+
+ while True:
+ try:
+ task = self.parallel_tasks.pop(0)
+ except IndexError:
+ break
+ jobs = None
+ if self.jobs is not None:
+ jobs = int(self.jobs / self.num_threads_remaining)
+ if jobs <= 0:
+ jobs = 1
+ try:
+ self.run_build_task(task, source_dir=my_source_dir, jobs=jobs)
+ except Exception as ex:
+ self.thread_exit_result_queue.put(f"{task}")
+ raise ex
+
+ def check_result_queue(self):
+ while True:
+ try:
+ result = self.thread_exit_result_queue.get_nowait()
+ except Queue.Empty:
+ break
+ if result is None:
+ continue
+ self.failure_exceptions.append(result)
+
+ def run_build_tasks_in_parallel(self, tasks):
+ n_threads = self.parallel_copies
+ if len(tasks) < n_threads:
+ n_threads = len(tasks)
+ self.num_threads_remaining = n_threads
+
+ # shared list for the threads:
+ self.parallel_tasks = copy.copy(tasks) # make this an argument instead?!
+ threads = []
+ self.thread_exit_result_queue = Queue.Queue()
+ for i in range(0, n_threads):
+ t = threading.Thread(
+ target=self.parallel_thread_main,
+ name=f'task-builder-{i}',
+ args=[i],
+ )
+ t.start()
+ threads.append(t)
+ tstart = time.time()
+ self.failure_exceptions = []
+
+ while len(threads):
+
+ self.check_result_queue()
+
+ new_threads = []
+ for thread in threads:
+ thread.join(0)
+ if thread.is_alive():
+ new_threads.append(thread)
+ threads = new_threads
+ self.num_threads_remaining = len(threads)
+ self.progress(
+ f"remaining-tasks={len(self.parallel_tasks)} " +
+ f"remaining-threads={len(threads)} failed-threads={len(self.failure_exceptions)} elapsed={int(time.time() - tstart)}s") # noqa
+
+ # write out a progress CSV:
+ task_results = []
+ for task in tasks:
+ task_results.append(self.gather_results_for_task(task))
+ # progress CSV:
+ with open("/tmp/some.csv", "w") as f:
+ f.write(self.csv_for_results(self.compare_task_results(task_results, no_elf_diff=True)))
+
+ time.sleep(1)
+ self.progress("All threads returned")
+
+ self.check_result_queue()
+
+ if len(self.failure_exceptions):
+ self.progress("Some threads failed:")
+ for ex in self.failure_exceptions:
+ print("Thread failure: %s" % str(ex))
def run_all(self):
'''run tests for boards and vehicles passed in constructor'''
- results = {}
+ tmpdir = tempfile.mkdtemp()
+ self.tmpdir = tmpdir
+
+ self.master_commit = self.master_branch
+ if self.use_merge_base:
+ self.master_commit = self.find_git_branch_merge_base(self.branch, self.master_branch)
+ self.progress("Using merge base (%s)" % self.master_commit)
+
+ # create an array of tasks to run:
+ tasks = []
for board in self.board:
- vehicle_results = self.run_board(board)
- results[board] = vehicle_results
- with open("/tmp/some.csv", "w") as f:
- f.write(self.csv_for_results(results))
+ board_info = self.boards_by_name[board]
+
+ vehicles_to_build = self.vehicles_to_build_for_board_info(board_info)
+
+ outdir_1 = os.path.join(tmpdir, "out-master-%s" % (board,))
+ tasks.append((board, self.master_commit, outdir_1, vehicles_to_build, self.extra_hwdef_master))
+ outdir_2 = os.path.join(tmpdir, "out-branch-%s" % (board,))
+ tasks.append((board, self.branch, outdir_2, vehicles_to_build, self.extra_hwdef_branch))
+ self.tasks = tasks
+
+ if self.parallel_copies is not None:
+ self.run_build_tasks_in_parallel(tasks)
+ task_results = []
+ for task in tasks:
+ task_results.append(self.gather_results_for_task(task))
+ else:
+ # traditional build everything in sequence:
+ task_results = []
+ for task in tasks:
+ self.run_build_task(task)
+ task_results.append(self.gather_results_for_task(task))
+
+ # progress CSV:
+ with open("/tmp/some.csv", "w") as f:
+ f.write(self.csv_for_results(self.compare_task_results(task_results, no_elf_diff=True)))
+
+ return self.compare_task_results(task_results)
+
+ def elf_diff_results(self, result_master, result_branch):
+ master_branch = result_master["branch"]
+ branch = result_branch["branch"]
+ for vehicle in result_master["vehicle"].keys():
+ elf_filename = result_master["vehicle"][vehicle]["elf_filename"]
+ master_elf_dir = result_master["vehicle"][vehicle]["elf_dir"]
+ new_elf_dir = result_branch["vehicle"][vehicle]["elf_dir"]
+ board = result_master["board"]
+ self.progress("Starting compare (~10 minutes!)")
+ elf_diff_commandline = [
+ "time",
+ "python3",
+ "-m", "elf_diff",
+ "--bin_dir", self.bin_dir,
+ '--bin_prefix=arm-none-eabi-',
+ "--old_alias", "%s %s" % (master_branch, elf_filename),
+ "--new_alias", "%s %s" % (branch, elf_filename),
+ "--html_dir", "../ELF_DIFF_%s_%s" % (board, vehicle),
+ ]
+
+ try:
+ master_source_prefix = result_master["vehicle"][vehicle]["source_path"]
+ branch_source_prefix = result_branch["vehicle"][vehicle]["source_path"]
+ elf_diff_commandline.extend([
+ "--old_source_prefix", master_source_prefix,
+ "--new_source_prefix", branch_source_prefix,
+ ])
+ except KeyError:
+ pass
+
+ elf_diff_commandline.extend([
+ os.path.join(master_elf_dir, elf_filename),
+ os.path.join(new_elf_dir, elf_filename)
+ ])
+
+ self.run_program("SCB", elf_diff_commandline)
+
+ def compare_task_results(self, task_results, no_elf_diff=False):
+ # pair off results, master and branch:
+ pairs = {}
+ for res in task_results:
+ board = res["board"]
+ if board not in pairs:
+ pairs[board] = {}
+ if res["branch"] == self.master_commit:
+ pairs[board]["master"] = res
+ elif res["branch"] == self.branch:
+ pairs[board]["branch"] = res
+ else:
+ raise ValueError(res["branch"])
+
+ results = {}
+ for pair in pairs.values():
+ if "master" not in pair or "branch" not in pair:
+ # probably incomplete:
+ continue
+ master = pair["master"]
+ board = master["board"]
+ try:
+ results[board] = self.compare_results(master, pair["branch"])
+ if self.run_elf_diff and not no_elf_diff:
+ self.elf_diff_results(master, pair["branch"])
+ except FileNotFoundError:
+ pass
return results
@@ -348,6 +622,11 @@ def csv_for_results(self, results):
if not self.show_empty:
if len(list(filter(lambda x : x != "", line[1:]))) == 0:
continue
+ # do not add to ret value if all output binaries are identical:
+ if not self.show_unchanged:
+ starcount = len(list(filter(lambda x : x == "*", line[1:])))
+ if len(line[1:]) == starcount:
+ continue
ret += ",".join(line) + "\n"
return ret
@@ -381,96 +660,75 @@ def extra_hwdef_file(self, more):
return f.name
- def run_board(self, board):
- ret = {}
- board_info = self.boards_by_name[board]
-
- vehicles_to_build = []
- for vehicle in self.vehicle:
- if vehicle == 'AP_Periph':
- if not board_info.is_ap_periph:
- continue
- else:
- if board_info.is_ap_periph:
- continue
- # the bootloader target isn't an autobuild target, so
- # it gets special treatment here:
- if vehicle != 'bootloader' and vehicle.lower() not in [x.lower() for x in board_info.autobuild_targets]:
- continue
- vehicles_to_build.append(vehicle)
- if len(vehicles_to_build) == 0:
- return ret
-
- tmpdir = tempfile.mkdtemp()
- outdir_1 = os.path.join(tmpdir, "out-master-%s" % (board,))
- outdir_2 = os.path.join(tmpdir, "out-branch-%s" % (board,))
-
- self.progress("Building branch 1 (%s)" % self.master_branch)
- master_commit = self.master_branch
- if self.use_merge_base:
- master_commit = self.find_git_branch_merge_base(self.branch, self.master_branch)
- self.progress("Using merge base (%s)" % master_commit)
- shutil.rmtree(outdir_1, ignore_errors=True)
+ def run_build_task(self, task, source_dir=None, jobs=None):
+ (board, commitish, outdir, vehicles_to_build, extra_hwdef_file) = task
+ self.progress(f"Building {task}")
+ shutil.rmtree(outdir, ignore_errors=True)
self.build_branch_into_dir(
board,
- master_commit,
+ commitish,
vehicles_to_build,
- outdir_1,
- extra_hwdef=self.extra_hwdef_file(self.extra_hwdef_master)
+ outdir,
+ source_dir=source_dir,
+ extra_hwdef=self.extra_hwdef_file(extra_hwdef_file),
+ jobs=jobs,
)
- self.progress("Building branch 2 (%s)" % self.branch)
- shutil.rmtree(outdir_2, ignore_errors=True)
- self.build_branch_into_dir(
- board,
- self.branch,
- vehicles_to_build,
- outdir_2,
- self.extra_hwdef_file(self.extra_hwdef_branch)
- )
+ def gather_results_for_task(self, task):
+ (board, commitish, outdir, vehicles_to_build, extra_hwdef_file) = task
+
+ result = {
+ "board": board,
+ "branch": commitish,
+ "vehicle": {},
+ }
+
+ have_source_trees = self.parallel_copies is not None and len(self.tasks) <= self.parallel_copies
for vehicle in vehicles_to_build:
if vehicle == 'bootloader' and board in self.bootloader_blacklist:
continue
- elf_filename = self.vehicle_map[vehicle]
- bin_filename = self.vehicle_map[vehicle] + '.bin'
-
- if self.run_elf_diff:
- master_elf_dirname = "bin"
- new_elf_dirname = "bin"
- if vehicle == 'bootloader':
- # elfs for bootloaders are in the bootloader directory...
- master_elf_dirname = "bootloader"
- new_elf_dirname = "bootloader"
- master_elf_dir = os.path.join(outdir_1, board, master_elf_dirname)
- new_elf_dir = os.path.join(outdir_2, board, new_elf_dirname)
- self.progress("Starting compare (~10 minutes!)")
- elf_diff_commandline = [
- "time",
- "python3",
- "-m", "elf_diff",
- "--bin_dir", self.bin_dir,
- '--bin_prefix=arm-none-eabi-',
- "--old_alias", "%s %s" % (self.master_branch, elf_filename),
- "--new_alias", "%s %s" % (self.branch, elf_filename),
- "--html_dir", "../ELF_DIFF_%s_%s" % (board, vehicle),
- os.path.join(master_elf_dir, elf_filename),
- os.path.join(new_elf_dir, elf_filename)
- ]
-
- self.run_program("SCB", elf_diff_commandline)
-
- master_bin_dir = os.path.join(outdir_1, board, "bin")
- new_bin_dir = os.path.join(outdir_2, board, "bin")
+ result["vehicle"][vehicle] = {}
+ v = result["vehicle"][vehicle]
+ v["bin_filename"] = self.vehicle_map[vehicle] + '.bin'
+
+ elf_dirname = "bin"
+ if vehicle == 'bootloader':
+ # elfs for bootloaders are in the bootloader directory...
+ elf_dirname = "bootloader"
+ elf_basedir = outdir
+ if have_source_trees:
+ try:
+ v["source_path"] = pathlib.Path(outdir, "scb_sourcepath.txt").read_text()
+ elf_basedir = os.path.join(v["source_path"], 'build')
+ self.progress("Have source trees")
+ except FileNotFoundError:
+ pass
+ v["bin_dir"] = os.path.join(elf_basedir, board, "bin")
+ elf_dir = os.path.join(elf_basedir, board, elf_dirname)
+ v["elf_dir"] = elf_dir
+ v["elf_filename"] = self.vehicle_map[vehicle]
+
+ return result
+
+ def compare_results(self, result_master, result_branch):
+ ret = {}
+ for vehicle in result_master["vehicle"].keys():
+ # check for the difference in size (and identicality)
+ # of the two binaries:
+ master_bin_dir = result_master["vehicle"][vehicle]["bin_dir"]
+ new_bin_dir = result_branch["vehicle"][vehicle]["bin_dir"]
try:
+ bin_filename = result_master["vehicle"][vehicle]["bin_filename"]
master_path = os.path.join(master_bin_dir, bin_filename)
new_path = os.path.join(new_bin_dir, bin_filename)
master_size = os.path.getsize(master_path)
new_size = os.path.getsize(new_path)
except FileNotFoundError:
+ elf_filename = result_master["vehicle"][vehicle]["elf_filename"]
master_path = os.path.join(master_bin_dir, elf_filename)
new_path = os.path.join(new_bin_dir, elf_filename)
master_size = os.path.getsize(master_path)
@@ -478,6 +736,7 @@ def run_board(self, board):
identical = self.files_are_identical(master_path, new_path)
+ board = result_master["board"]
ret[vehicle] = SizeCompareBranchesResult(board, vehicle, new_size - master_size, identical)
return ret
@@ -520,6 +779,11 @@ def run_board(self, board):
action='store_true',
default=False,
help="Show result lines even if no builds were done for the board")
+ parser.add_option("",
+ "--hide-unchanged",
+ action='store_true',
+ default=False,
+ help="Hide binary-size-change results for any board where output binary is unchanged")
parser.add_option("",
"--board",
action='append',
@@ -545,11 +809,26 @@ def run_board(self, board):
action='store_true',
default=False,
help="Build all boards")
+ parser.add_option("",
+ "--exclude-board-glob",
+ default=[],
+ action="append",
+ help="exclude any board which matches this pattern")
parser.add_option("",
"--all-vehicles",
action='store_true',
default=False,
help="Build all vehicles")
+ parser.add_option("",
+ "--parallel-copies",
+ type=int,
+ default=None,
+ help="Copy source dir this many times, build from those copies in parallel")
+ parser.add_option("-j",
+ "--jobs",
+ type=int,
+ default=None,
+ help="Passed to waf configure -j; number of build jobs. If running with --parallel-copies, this is divided by the number of remaining threads before being passed.") # noqa
cmd_opts, cmd_args = parser.parse_args()
vehicle = []
@@ -575,8 +854,12 @@ def run_board(self, board):
run_elf_diff=(cmd_opts.elf_diff),
all_vehicles=cmd_opts.all_vehicles,
all_boards=cmd_opts.all_boards,
+ exclude_board_glob=cmd_opts.exclude_board_glob,
use_merge_base=not cmd_opts.no_merge_base,
waf_consistent_builds=not cmd_opts.no_waf_consistent_builds,
show_empty=cmd_opts.show_empty,
+ show_unchanged=not cmd_opts.hide_unchanged,
+ parallel_copies=cmd_opts.parallel_copies,
+ jobs=cmd_opts.jobs,
)
x.run()
diff --git a/Tools/scripts/solution_status_change.py b/Tools/scripts/solution_status_change.py
index 8a1f863095217a..4a052aa0e4d4a1 100755
--- a/Tools/scripts/solution_status_change.py
+++ b/Tools/scripts/solution_status_change.py
@@ -53,23 +53,24 @@ def run(self):
old_message_per_core = {}
while True:
m = self.conn.recv_match(type=desired_type)
+ if m.C != 0:
+ continue
if m is None:
break
if m.C not in old_message_per_core:
old_message_per_core[m.C] = m
continue
- ss = m.SS
current = old_message_per_core[m.C]
- if ss == current.SS:
+ if m.SS == current.SS:
continue
line = ""
- for bit in bit_descriptions.keys():
- old_bit_set = current.SS & (1 << bit_descriptions[bit])
- new_bit_set = ss & (1 << bit_descriptions[bit])
+ for (name, bit) in bit_descriptions.items():
+ old_bit_set = current.SS & (1 << bit)
+ new_bit_set = m.SS & (1 << bit)
if new_bit_set and not old_bit_set:
- line += " +%s" % bit
+ line += " +%s" % name
elif not new_bit_set and old_bit_set:
- line += " -%s" % bit
+ line += " -%s" % name
old_message_per_core[m.C] = m
diff --git a/Tools/scripts/uploader.py b/Tools/scripts/uploader.py
index 97d9b0f8dfc2be..acc8aae658ef95 100755
--- a/Tools/scripts/uploader.py
+++ b/Tools/scripts/uploader.py
@@ -175,11 +175,11 @@ def __init__(self, path):
self.extf_image = None
# pad image to 4-byte length
while ((len(self.image) % 4) != 0):
- self.image.append('\xff')
+ self.image += bytes(0xFF)
# pad image to 4-byte length
if self.extf_image is not None:
while ((len(self.extf_image) % 4) != 0):
- self.extf_image.append('\xff')
+ self.extf_image += bytes(0xFF)
def property(self, propname, default=None):
if propname in self.desc:
diff --git a/Tools/simulink/arducopter/functions/dcmFromEuler.m b/Tools/simulink/arducopter/functions/dcmFromEuler.m
new file mode 100644
index 00000000000000..a8f5c41e8b9582
--- /dev/null
+++ b/Tools/simulink/arducopter/functions/dcmFromEuler.m
@@ -0,0 +1,27 @@
+function dcm = dcmFromEuler(roll, pitch, yaw)
+% Function to calculate the DCM from Euler Angles.
+% Euler Angles are given in radian.
+% Taken from Matrix3::from_euler()
+sr = sin(roll);
+cr = cos(roll);
+sp = sin(pitch);
+cp = cos(pitch);
+sy = sin(yaw);
+cy = cos(yaw);
+
+dcm = zeros(3,3);
+% First row
+dcm(1,1) = cp * cy;
+dcm(1,2) = (sr * sp * cy) - (cr * sy);
+dcm(1,3) = (cr * sp * cy) + (sr * sy);
+% Second row
+dcm(2,1) = cp * sy;
+dcm(2,2) = (sr * sp * sy) + (cr * cy);
+dcm(2,3) = (cr * sp * sy) - (sr * cy);
+% Third row
+dcm(3,1) = -sp;
+dcm(3,2) = sr * cp;
+dcm(3,3) = cr * cp;
+
+
+end
\ No newline at end of file
diff --git a/Tools/simulink/arducopter/functions/fromAxisAngle.m b/Tools/simulink/arducopter/functions/fromAxisAngle.m
new file mode 100644
index 00000000000000..dd88133b22c302
--- /dev/null
+++ b/Tools/simulink/arducopter/functions/fromAxisAngle.m
@@ -0,0 +1,29 @@
+function q = fromAxisAngle(vec)
+% Create a quaternion from its axis-angle representation. Just the rotation
+% vector is given as input.
+% Based on QuaternionT::from_axis_angle(Vector3)
+
+q = zeros(4,1);
+angle = single(sqrt(vec(1)^2 + vec(2)^2 + vec(3)^2));
+
+if angle == 0
+ q(1) = single(1);
+ q(2) = single(0);
+ q(3) = single(0);
+ q(4) = single(0);
+else
+ axis = vec ./ angle;
+ % The following lines are based on QuaternionT::from_axis_angle(const Vector3 &axis, T theta)
+ if angle == 0
+ q(1) = single(1);
+ q(2) = single(0);
+ q(3) = single(0);
+ q(4) = single(0);
+ else
+ st2 = single(sin(0.5*angle));
+ q(1) = single(cos(0.5*angle));
+ q(2) = axis(1) * st2;
+ q(3) = axis(2) * st2;
+ q(4) = axis(3) * st2;
+ end
+end
\ No newline at end of file
diff --git a/Tools/simulink/arducopter/functions/quatMult.m b/Tools/simulink/arducopter/functions/quatMult.m
new file mode 100644
index 00000000000000..767e70a0aace6f
--- /dev/null
+++ b/Tools/simulink/arducopter/functions/quatMult.m
@@ -0,0 +1,10 @@
+function qRes = quatMult(q1, q2)
+% Quaternion multiplication. Code based on QuaternionT::operator*() in
+% quaternion.cpp
+
+qRes = single(zeros(4,1));
+qRes(1) = q1(1)*q2(1) - q1(2)*q2(2) - q1(3)*q2(3) - q1(4)*q2(4);
+qRes(2) = q1(1)*q2(2) + q1(2)*q2(1) + q1(3)*q2(4) - q1(4)*q2(3);
+qRes(3) = q1(1)*q2(3) - q1(2)*q2(4) + q1(3)*q2(1) + q1(4)*q2(2);
+qRes(4) = q1(1)*q2(4) + q1(2)*q2(3) - q1(3)*q2(2) + q1(4)*q2(1);
+end
\ No newline at end of file
diff --git a/Tools/simulink/arducopter/sid_controller_validation.m b/Tools/simulink/arducopter/sid_controller_validation.m
index 014ea31c24e7b2..1c22aca734cb69 100644
--- a/Tools/simulink/arducopter/sid_controller_validation.m
+++ b/Tools/simulink/arducopter/sid_controller_validation.m
@@ -14,7 +14,7 @@
%% Define log file index and controller type to be validated
% Log file index used for validation
-log_idx = 2;
+log_idx = 5;
% Check validity of log_idx
if log_idx > numel(sidLogs)
@@ -25,35 +25,35 @@
% validate
figure % Attitude controller signals
subplot(311)
-plot(sidLogs(log_idx).data.RATE.TimeS, sidLogs(log_idx).data.RATE.RDes, 'LineWidth', 1.4);
+plot(sidLogs(log_idx).data.ATT.TimeS, sidLogs(log_idx).data.ATT.DesRoll, 'LineWidth', 1.4);
hold on
-plot(sidLogs(log_idx).data.RATE.TimeS, sidLogs(log_idx).data.RATE.R, 'LineWidth', 1.4);
+plot(sidLogs(log_idx).data.ATT.TimeS, sidLogs(log_idx).data.ATT.Roll, 'LineWidth', 1.4);
hold off
grid on
legend('Desired', 'Actual');
xlabel('Time (s)');
ylabel('Roll angle (deg)');
-xlim([0 max(sidLogs(log_idx).data.RATE.TimeS)]);
+xlim([0 max(sidLogs(log_idx).data.ATT.TimeS)]);
subplot(312)
-plot(sidLogs(log_idx).data.RATE.TimeS, sidLogs(log_idx).data.RATE.PDes, 'LineWidth', 1.4);
+plot(sidLogs(log_idx).data.ATT.TimeS, sidLogs(log_idx).data.ATT.DesPitch, 'LineWidth', 1.4);
hold on
-plot(sidLogs(log_idx).data.RATE.TimeS, sidLogs(log_idx).data.RATE.P, 'LineWidth', 1.4);
+plot(sidLogs(log_idx).data.ATT.TimeS, sidLogs(log_idx).data.ATT.Pitch, 'LineWidth', 1.4);
hold off
grid on
legend('Desired', 'Actual');
xlabel('Time (s)');
ylabel('Pitch angle (deg)');
-xlim([0 max(sidLogs(log_idx).data.RATE.TimeS)]);
+xlim([0 max(sidLogs(log_idx).data.ATT.TimeS)]);
subplot(313)
-plot(sidLogs(log_idx).data.RATE.TimeS, sidLogs(log_idx).data.RATE.YDes, 'LineWidth', 1.4);
+plot(sidLogs(log_idx).data.ATT.TimeS, sidLogs(log_idx).data.ATT.DesYaw, 'LineWidth', 1.4);
hold on
-plot(sidLogs(log_idx).data.RATE.TimeS, sidLogs(log_idx).data.RATE.Y, 'LineWidth', 1.4);
+plot(sidLogs(log_idx).data.ATT.TimeS, sidLogs(log_idx).data.ATT.Yaw, 'LineWidth', 1.4);
hold off
grid on
legend('Desired', 'Actual');
xlabel('Time (s)');
ylabel('Yaw angle (deg)');
-xlim([0 max(sidLogs(log_idx).data.RATE.TimeS)]);
+xlim([0 max(sidLogs(log_idx).data.ATT.TimeS)]);
% Plot z Controller signals if Althold flight mode was active
if sidLogs(log_idx).data.MODE.Mode == 2
@@ -80,6 +80,10 @@
fprintf(' (Stabilize)\n');
case 2
fprintf(' (Althold)\n');
+ otherwise
+ fprintf(['\n No available flight mode for the validation could be found. ' ...
+ 'Please use the Stabilize or Althold flight mode!\n']);
+ return;
end
fprintf('Available controllers that can be validated: \n');
fprintf('1 = Rate controller\n');
diff --git a/Tools/vagrant/initvagrant.sh b/Tools/vagrant/initvagrant.sh
index 4548e6af6003e1..f600e40096e37f 100755
--- a/Tools/vagrant/initvagrant.sh
+++ b/Tools/vagrant/initvagrant.sh
@@ -42,10 +42,12 @@ sudo -u $VAGRANT_USER ln -fs /vagrant/Tools/vagrant/screenrc /home/$VAGRANT_USER
perl -pe 's/kernel.yama.ptrace_scope = ./kernel.yama.ptrace_scope = 0/' -i /etc/sysctl.d/10-ptrace.conf
echo 0 > /proc/sys/kernel/yama/ptrace_scope
-# build JSB sim
-apt-get install -y libtool automake autoconf libexpat1-dev cmake
-# libtool-bin
-sudo --login -u $VAGRANT_USER /vagrant/Tools/scripts/build-jsbsim.sh
+if [ ${RELEASE_CODENAME} != 'bionic' ]; then
+ # build JSB sim
+ apt-get install -y libtool automake autoconf libexpat1-dev cmake
+ # libtool-bin
+ sudo --login -u $VAGRANT_USER /vagrant/Tools/scripts/build-jsbsim.sh
+fi
# adjust environment for every login shell:
DOT_PROFILE=/home/$VAGRANT_USER/.profile
diff --git a/Vagrantfile b/Vagrantfile
index 2f8b097b8e140d..45fb5b03cbf796 100644
--- a/Vagrantfile
+++ b/Vagrantfile
@@ -43,7 +43,6 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
# removing this line causes "A box must be specified." error
# and this is the default box that will be booted if no name is specified
- config.vm.box = "ubuntu/bionic64"
config.vm.boot_timeout = 1500
# LTS, EOL April, 2019:
@@ -114,7 +113,7 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
end
# 18.04 LTS EOL April 2023
- config.vm.define "bionic64", primary: true do |bionic64|
+ config.vm.define "bionic64", autostart: false do |bionic64|
bionic64.vm.box = "ubuntu/bionic64"
bionic64.vm.provision :shell, path: "Tools/vagrant/initvagrant.sh"
bionic64.vm.provider "virtualbox" do |vb|
@@ -228,7 +227,7 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
# end
# 22.04 LTS EOL Apr 2032
- config.vm.define "jammy", autostart: false do |jammy|
+ config.vm.define "jammy", primary: true do |jammy|
jammy.vm.box = "ubuntu/jammy64"
jammy.vm.provision :shell, path: "Tools/vagrant/initvagrant.sh"
jammy.vm.provider "virtualbox" do |vb|
@@ -246,4 +245,22 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
jammy.vm.boot_timeout = 1200
end
+ # 23.04 EOL Jan 2024
+ config.vm.define "lunar", autostart: false do |lunar|
+ lunar.vm.box = "ubuntu/lunar64"
+ lunar.vm.provision :shell, path: "Tools/vagrant/initvagrant.sh"
+ lunar.vm.provider "virtualbox" do |vb|
+ vb.name = "ArduPilot (lunar)"
+ end
+ lunar.vm.boot_timeout = 1200
+ end
+ config.vm.define "lunar-desktop", autostart: false do |lunar|
+ lunar.vm.box = "ubuntu/lunar64"
+ lunar.vm.provision :shell, path: "Tools/vagrant/initvagrant-desktop.sh"
+ lunar.vm.provider "virtualbox" do |vb|
+ vb.name = "ArduPilot (lunar-desktop)"
+ vb.gui = true
+ end
+ lunar.vm.boot_timeout = 1200
+ end
end
diff --git a/appveyor.yml b/appveyor.yml
deleted file mode 100644
index 3684d1afd1c285..00000000000000
--- a/appveyor.yml
+++ /dev/null
@@ -1,35 +0,0 @@
-version: 1.0.{build}
-image: Visual Studio 2017 Preview
-clone_depth: 1
-clone_folder: C:\work\
-init:
-- cmd: git config --global core.autocrlf false
-environment:
- matrix:
- - TARGET: cygwin64-gcc
- BUILD_ENVIRONMENT: cygwin64
- CYG_ROOT: C:\cygwin64
-
-install:
-- cmd: >-
-
- C:\cygwin64\setup-x86_64.exe -qgnNdO -l C:\cygwin64\var\cache\setup -R c:\cygwin64 -s http://cygwin.mirror.constant.com -P gcc-g++,git,procps,libexpat,python2,python-setuptools,python-future,cygwin32-gcc-g++ )
-
- dir %CYG_ROOT%
- dir %CYG_ROOT%\bin
-
-build_script:
-- cmd: >-
- cd C:\work
-
- mkdir c:\work\sitl
-
- %CYG_ROOT%\bin\sh.exe /cygdrive/c/work/Tools/scripts/build_appveyor.sh
-
- cd c:\work\sitl
-
- 7z a C:\work\sitl.zip *
-test: off
-artifacts:
-- path: sitl.zip
- name: sitl
diff --git a/libraries/AC_AttitudeControl/AC_AttitudeControl.cpp b/libraries/AC_AttitudeControl/AC_AttitudeControl.cpp
index e1dfc243125994..a64a277d883cfd 100644
--- a/libraries/AC_AttitudeControl/AC_AttitudeControl.cpp
+++ b/libraries/AC_AttitudeControl/AC_AttitudeControl.cpp
@@ -169,7 +169,7 @@ void AC_AttitudeControl::relax_attitude_controllers()
{
// Initialize the attitude variables to the current attitude
_ahrs.get_quat_body_to_ned(_attitude_target);
- _attitude_target.to_euler(_euler_angle_target.x, _euler_angle_target.y, _euler_angle_target.z);
+ _attitude_target.to_euler(_euler_angle_target);
_attitude_ang_error.initialise();
// Initialize the angular rate variables to the current rate
@@ -250,7 +250,7 @@ void AC_AttitudeControl::input_quaternion(Quaternion& attitude_desired_quat, Vec
}
// calculate the attitude target euler angles
- _attitude_target.to_euler(_euler_angle_target.x, _euler_angle_target.y, _euler_angle_target.z);
+ _attitude_target.to_euler(_euler_angle_target);
// Convert body-frame angular velocity into euler angle derivative of desired attitude
ang_vel_to_euler_rate(_euler_angle_target, _ang_vel_target, _euler_rate_target);
@@ -274,7 +274,7 @@ void AC_AttitudeControl::input_euler_angle_roll_pitch_euler_rate_yaw(float euler
float euler_yaw_rate = radians(euler_yaw_rate_cds * 0.01f);
// calculate the attitude target euler angles
- _attitude_target.to_euler(_euler_angle_target.x, _euler_angle_target.y, _euler_angle_target.z);
+ _attitude_target.to_euler(_euler_angle_target);
// Add roll trim to compensate tail rotor thrust in heli (will return zero on multirotors)
euler_roll_angle += get_roll_trim_rad();
@@ -325,7 +325,7 @@ void AC_AttitudeControl::input_euler_angle_roll_pitch_yaw(float euler_roll_angle
float euler_yaw_angle = radians(euler_yaw_angle_cd * 0.01f);
// calculate the attitude target euler angles
- _attitude_target.to_euler(_euler_angle_target.x, _euler_angle_target.y, _euler_angle_target.z);
+ _attitude_target.to_euler(_euler_angle_target);
// Add roll trim to compensate tail rotor thrust in heli (will return zero on multirotors)
euler_roll_angle += get_roll_trim_rad();
@@ -384,7 +384,7 @@ void AC_AttitudeControl::input_euler_rate_roll_pitch_yaw(float euler_roll_rate_c
float euler_yaw_rate = radians(euler_yaw_rate_cds * 0.01f);
// calculate the attitude target euler angles
- _attitude_target.to_euler(_euler_angle_target.x, _euler_angle_target.y, _euler_angle_target.z);
+ _attitude_target.to_euler(_euler_angle_target);
if (_rate_bf_ff_enabled) {
// translate the roll pitch and yaw acceleration limits to the euler axis
@@ -426,7 +426,7 @@ void AC_AttitudeControl::input_rate_bf_roll_pitch_yaw(float roll_rate_bf_cds, fl
float yaw_rate_rads = radians(yaw_rate_bf_cds * 0.01f);
// calculate the attitude target euler angles
- _attitude_target.to_euler(_euler_angle_target.x, _euler_angle_target.y, _euler_angle_target.z);
+ _attitude_target.to_euler(_euler_angle_target);
if (_rate_bf_ff_enabled) {
// Compute acceleration-limited body frame rates
@@ -471,7 +471,7 @@ void AC_AttitudeControl::input_rate_bf_roll_pitch_yaw_2(float roll_rate_bf_cds,
// Update the unused targets attitude based on current attitude to condition mode change
_ahrs.get_quat_body_to_ned(_attitude_target);
- _attitude_target.to_euler(_euler_angle_target.x, _euler_angle_target.y, _euler_angle_target.z);
+ _attitude_target.to_euler(_euler_angle_target);
// Convert body-frame angular velocity into euler angle derivative of desired attitude
ang_vel_to_euler_rate(_euler_angle_target, _ang_vel_target, _euler_rate_target);
_ang_vel_body = _ang_vel_target;
@@ -516,7 +516,7 @@ void AC_AttitudeControl::input_rate_bf_roll_pitch_yaw_3(float roll_rate_bf_cds,
_attitude_target = attitude_body * _attitude_ang_error;
// calculate the attitude target euler angles
- _attitude_target.to_euler(_euler_angle_target.x, _euler_angle_target.y, _euler_angle_target.z);
+ _attitude_target.to_euler(_euler_angle_target);
// Convert body-frame angular velocity into euler angle derivative of desired attitude
ang_vel_to_euler_rate(_euler_angle_target, _ang_vel_target, _euler_rate_target);
@@ -546,7 +546,7 @@ void AC_AttitudeControl::input_angle_step_bf_roll_pitch_yaw(float roll_angle_ste
_attitude_target.normalize();
// calculate the attitude target euler angles
- _attitude_target.to_euler(_euler_angle_target.x, _euler_angle_target.y, _euler_angle_target.z);
+ _attitude_target.to_euler(_euler_angle_target);
// Set rate feedforward requests to zero
_euler_rate_target.zero();
@@ -568,7 +568,7 @@ void AC_AttitudeControl::input_thrust_vector_rate_heading(const Vector3f& thrust
}
// calculate the attitude target euler angles
- _attitude_target.to_euler(_euler_angle_target.x, _euler_angle_target.y, _euler_angle_target.z);
+ _attitude_target.to_euler(_euler_angle_target);
// convert thrust vector to a quaternion attitude
Quaternion thrust_vec_quat = attitude_from_thrust_vector(thrust_vector, 0.0f);
@@ -620,7 +620,7 @@ void AC_AttitudeControl::input_thrust_vector_heading(const Vector3f& thrust_vect
float heading_angle = radians(heading_angle_cd * 0.01f);
// calculate the attitude target euler angles
- _attitude_target.to_euler(_euler_angle_target.x, _euler_angle_target.y, _euler_angle_target.z);
+ _attitude_target.to_euler(_euler_angle_target);
// convert thrust vector and heading to a quaternion attitude
const Quaternion desired_attitude_quat = attitude_from_thrust_vector(thrust_vector, heading_angle);
@@ -968,7 +968,7 @@ void AC_AttitudeControl::inertial_frame_reset()
_attitude_target = attitude_body * _attitude_ang_error;
// calculate the attitude target euler angles
- _attitude_target.to_euler(_euler_angle_target.x, _euler_angle_target.y, _euler_angle_target.z);
+ _attitude_target.to_euler(_euler_angle_target);
}
// Convert a 321-intrinsic euler angle derivative to an angular velocity vector
diff --git a/libraries/AC_AttitudeControl/AC_AttitudeControl_Heli.cpp b/libraries/AC_AttitudeControl/AC_AttitudeControl_Heli.cpp
index db5df861385491..e05d6e4af73747 100644
--- a/libraries/AC_AttitudeControl/AC_AttitudeControl_Heli.cpp
+++ b/libraries/AC_AttitudeControl/AC_AttitudeControl_Heli.cpp
@@ -403,19 +403,9 @@ void AC_AttitudeControl_Heli::rate_bf_to_motor_roll_pitch(const Vector3f &rate_r
float roll_out = roll_pid + roll_ff;
float pitch_out = pitch_pid + pitch_ff;
- // constrain output and update limit flags
- if (fabsf(roll_out) > AC_ATTITUDE_RATE_RP_CONTROLLER_OUT_MAX) {
- roll_out = constrain_float(roll_out, -AC_ATTITUDE_RATE_RP_CONTROLLER_OUT_MAX, AC_ATTITUDE_RATE_RP_CONTROLLER_OUT_MAX);
- _flags_heli.limit_roll = true;
- } else {
- _flags_heli.limit_roll = false;
- }
- if (fabsf(pitch_out) > AC_ATTITUDE_RATE_RP_CONTROLLER_OUT_MAX) {
- pitch_out = constrain_float(pitch_out, -AC_ATTITUDE_RATE_RP_CONTROLLER_OUT_MAX, AC_ATTITUDE_RATE_RP_CONTROLLER_OUT_MAX);
- _flags_heli.limit_pitch = true;
- } else {
- _flags_heli.limit_pitch = false;
- }
+ // constrain output
+ roll_out = constrain_float(roll_out, -AC_ATTITUDE_RATE_RP_CONTROLLER_OUT_MAX, AC_ATTITUDE_RATE_RP_CONTROLLER_OUT_MAX);
+ pitch_out = constrain_float(pitch_out, -AC_ATTITUDE_RATE_RP_CONTROLLER_OUT_MAX, AC_ATTITUDE_RATE_RP_CONTROLLER_OUT_MAX);
// output to motors
_motors.set_roll(roll_out);
@@ -457,13 +447,8 @@ float AC_AttitudeControl_Heli::rate_target_to_motor_yaw(float rate_yaw_actual_ra
// add feed forward
float yaw_out = pid + vff;
- // constrain output and update limit flag
- if (fabsf(yaw_out) > AC_ATTITUDE_RATE_YAW_CONTROLLER_OUT_MAX) {
- yaw_out = constrain_float(yaw_out, -AC_ATTITUDE_RATE_YAW_CONTROLLER_OUT_MAX, AC_ATTITUDE_RATE_YAW_CONTROLLER_OUT_MAX);
- _flags_heli.limit_yaw = true;
- } else {
- _flags_heli.limit_yaw = false;
- }
+ // constrain output
+ yaw_out = constrain_float(yaw_out, -AC_ATTITUDE_RATE_YAW_CONTROLLER_OUT_MAX, AC_ATTITUDE_RATE_YAW_CONTROLLER_OUT_MAX);
// output to motors
return yaw_out;
diff --git a/libraries/AC_AttitudeControl/AC_AttitudeControl_Heli.h b/libraries/AC_AttitudeControl/AC_AttitudeControl_Heli.h
index 0b3619f7104456..2a1852c1ded116 100644
--- a/libraries/AC_AttitudeControl/AC_AttitudeControl_Heli.h
+++ b/libraries/AC_AttitudeControl/AC_AttitudeControl_Heli.h
@@ -42,13 +42,9 @@ class AC_AttitudeControl_Heli : public AC_AttitudeControl {
AP_Param::setup_object_defaults(this, var_info);
// initialise flags
- _flags_heli.limit_roll = false;
- _flags_heli.limit_pitch = false;
- _flags_heli.limit_yaw = false;
_flags_heli.leaky_i = true;
_flags_heli.flybar_passthrough = false;
_flags_heli.tail_passthrough = false;
- _flags_heli.do_piro_comp = false;
}
// pid accessors
@@ -59,9 +55,6 @@ class AC_AttitudeControl_Heli : public AC_AttitudeControl {
// passthrough_bf_roll_pitch_rate_yaw - roll and pitch are passed through directly, body-frame rate target for yaw
void passthrough_bf_roll_pitch_rate_yaw(float roll_passthrough, float pitch_passthrough, float yaw_rate_bf_cds) override;
- // Integrate vehicle rate into _att_error_rot_vec_rad
- void integrate_bf_rate_error_to_angle_errors();
-
// subclass non-passthrough too, for external gyro, no flybar
void input_rate_bf_roll_pitch_yaw(float roll_rate_bf_cds, float pitch_rate_bf_cds, float yaw_rate_bf_cds) override;
@@ -82,9 +75,6 @@ class AC_AttitudeControl_Heli : public AC_AttitudeControl {
_flags_heli.tail_passthrough = tail_passthrough;
}
- // do_piro_comp - controls whether piro-comp is active or not
- void do_piro_comp(bool piro_comp) { _flags_heli.do_piro_comp = piro_comp; }
-
// set_hover_roll_scalar - scales Hover Roll Trim parameter. To be used by vehicle code according to vehicle condition.
void set_hover_roll_trim_scalar(float scalar) override {_hover_roll_trim_scalar = constrain_float(scalar, 0.0f, 1.0f);}
@@ -112,15 +102,14 @@ class AC_AttitudeControl_Heli : public AC_AttitudeControl {
// To-Do: move these limits flags into the heli motors class
struct AttControlHeliFlags {
- uint8_t limit_roll : 1; // 1 if we have requested larger roll angle than swash can physically move
- uint8_t limit_pitch : 1; // 1 if we have requested larger pitch angle than swash can physically move
- uint8_t limit_yaw : 1; // 1 if we have requested larger yaw angle than tail servo can physically move
uint8_t leaky_i : 1; // 1 if we should use leaky i term for body-frame rate to motor stage
uint8_t flybar_passthrough : 1; // 1 if we should pass through pilots roll & pitch input directly to swash-plate
uint8_t tail_passthrough : 1; // 1 if we should pass through pilots yaw input to tail
- uint8_t do_piro_comp : 1; // 1 if we should do pirouette compensation on roll/pitch
} _flags_heli;
+ // Integrate vehicle rate into _att_error_rot_vec_rad
+ void integrate_bf_rate_error_to_angle_errors();
+
//
// body-frame rate controller
//
diff --git a/libraries/AC_AttitudeControl/AC_AttitudeControl_Multi_6DoF.cpp b/libraries/AC_AttitudeControl/AC_AttitudeControl_Multi_6DoF.cpp
index 6a2c75f2a8c0c6..ade5317e2a9787 100644
--- a/libraries/AC_AttitudeControl/AC_AttitudeControl_Multi_6DoF.cpp
+++ b/libraries/AC_AttitudeControl/AC_AttitudeControl_Multi_6DoF.cpp
@@ -1,3 +1,5 @@
+#include
+
#if AP_SCRIPTING_ENABLED
#include "AC_AttitudeControl_Multi_6DoF.h"
diff --git a/libraries/AC_AttitudeControl/AC_AttitudeControl_Sub.cpp b/libraries/AC_AttitudeControl/AC_AttitudeControl_Sub.cpp
index 08cb1057be3174..3edb1c40acbc42 100644
--- a/libraries/AC_AttitudeControl/AC_AttitudeControl_Sub.cpp
+++ b/libraries/AC_AttitudeControl/AC_AttitudeControl_Sub.cpp
@@ -378,3 +378,33 @@ void AC_AttitudeControl_Sub::parameter_sanity_check()
_thr_mix_max.set_and_save(AC_ATTITUDE_CONTROL_MAX_DEFAULT);
}
}
+
+// This function ensures that the ROV reaches the target orientation with the desired yaw rate
+void AC_AttitudeControl_Sub::input_euler_angle_roll_pitch_slew_yaw(float euler_roll_angle_cd, float euler_pitch_angle_cd, float euler_yaw_angle_cd, float target_yaw_rate)
+{
+ // Convert from centidegrees on public interface to radians
+ const float euler_yaw_angle = wrap_PI(radians(euler_yaw_angle_cd * 0.01f));
+
+ const float current_yaw = AP::ahrs().get_yaw();
+
+ // Compute angle error
+ const float yaw_error = wrap_PI(euler_yaw_angle - current_yaw);
+
+ int direction = 0;
+ if (yaw_error < 0){
+ direction = -1;
+ } else {
+ direction = 1;
+ }
+
+ target_yaw_rate *= direction;
+
+
+ if (fabsf(yaw_error) > MAX_YAW_ERROR) {
+ // rotate the rov with desired yaw rate towards the target yaw
+ input_euler_angle_roll_pitch_euler_rate_yaw(euler_roll_angle_cd, euler_pitch_angle_cd, target_yaw_rate);
+ } else {
+ // holds the rov's angles
+ input_euler_angle_roll_pitch_yaw(euler_roll_angle_cd, euler_pitch_angle_cd, euler_yaw_angle_cd, true);
+ }
+}
diff --git a/libraries/AC_AttitudeControl/AC_AttitudeControl_Sub.h b/libraries/AC_AttitudeControl/AC_AttitudeControl_Sub.h
index ee98bca30635bd..a776526bcb2bb5 100644
--- a/libraries/AC_AttitudeControl/AC_AttitudeControl_Sub.h
+++ b/libraries/AC_AttitudeControl/AC_AttitudeControl_Sub.h
@@ -23,6 +23,8 @@
#define AC_ATC_SUB_RATE_YAW_IMAX 0.222f
#define AC_ATC_SUB_RATE_YAW_FILT_HZ 5.0f
+#define MAX_YAW_ERROR radians(5)
+
class AC_AttitudeControl_Sub : public AC_AttitudeControl {
public:
AC_AttitudeControl_Sub(AP_AHRS_View &ahrs, const AP_MultiCopter &aparm, AP_MotorsMulticopter& motors);
@@ -60,6 +62,9 @@ class AC_AttitudeControl_Sub : public AC_AttitudeControl {
// sanity check parameters. should be called once before take-off
void parameter_sanity_check() override;
+ // This function ensures that the ROV reaches the target orientation with the desired yaw rate
+ void input_euler_angle_roll_pitch_slew_yaw(float euler_roll_angle_cd, float euler_pitch_angle_cd, float euler_yaw_angle_cd, float slew_yaw);
+
// user settable parameters
static const struct AP_Param::GroupInfo var_info[];
diff --git a/libraries/AC_AutoTune/AC_AutoTune_Heli.h b/libraries/AC_AutoTune/AC_AutoTune_Heli.h
index f9ec037b7b3967..cf941737919c97 100644
--- a/libraries/AC_AutoTune/AC_AutoTune_Heli.h
+++ b/libraries/AC_AutoTune/AC_AutoTune_Heli.h
@@ -243,7 +243,6 @@ class AC_AutoTune_Heli : public AC_AutoTune
Vector3f start_angles; // aircraft attitude at the start of test
uint32_t settle_time; // time in ms for allowing aircraft to stabilize before initiating test
uint32_t phase_out_time; // time in ms to phase out response
- float waveform_freq_rads; //current frequency for chirp waveform
float trim_pff_out; // trim output of the PID rate controller for P, I and FF terms
float trim_meas_rate; // trim measured gyro rate
diff --git a/libraries/AC_AutoTune/AC_AutoTune_Multi.cpp b/libraries/AC_AutoTune/AC_AutoTune_Multi.cpp
index 0e409403b2ccda..6e414b76d8b914 100644
--- a/libraries/AC_AutoTune/AC_AutoTune_Multi.cpp
+++ b/libraries/AC_AutoTune/AC_AutoTune_Multi.cpp
@@ -346,7 +346,7 @@ void AC_AutoTune_Multi::load_test_gains()
attitude_control->get_rate_yaw_pid().kI(tune_yaw_rp*0.01f);
attitude_control->get_rate_yaw_pid().ff(0.0f);
if (axis == YAW_D) {
- attitude_control->get_rate_pitch_pid().kD(tune_yaw_rd);
+ attitude_control->get_rate_yaw_pid().kD(tune_yaw_rd);
} else {
attitude_control->get_rate_yaw_pid().filt_E_hz(tune_yaw_rLPF);
}
@@ -1110,7 +1110,7 @@ void AC_AutoTune_Multi::twitch_test_init()
}
case YAW:
case YAW_D: {
- target_max_rate = MAX(AUTOTUNE_TARGET_MIN_RATE_RLLPIT_CDS, step_scaler*AUTOTUNE_TARGET_RATE_YAW_CDS);
+ target_max_rate = MAX(AUTOTUNE_TARGET_MIN_RATE_YAW_CDS, step_scaler*AUTOTUNE_TARGET_RATE_YAW_CDS);
target_rate = constrain_float(ToDeg(attitude_control->max_rate_step_bf_yaw()*0.75f)*100.0f, AUTOTUNE_TARGET_MIN_RATE_YAW_CDS, target_max_rate);
target_angle = constrain_float(ToDeg(attitude_control->max_angle_step_bf_yaw()*0.75f)*100.0f, AUTOTUNE_TARGET_MIN_ANGLE_YAW_CD, AUTOTUNE_TARGET_ANGLE_YAW_CD);
if (axis == YAW_D) {
diff --git a/libraries/AC_Avoidance/AP_OADatabase.cpp b/libraries/AC_Avoidance/AP_OADatabase.cpp
index 37fb5d7b0e8cb9..cb0153fbbea909 100644
--- a/libraries/AC_Avoidance/AP_OADatabase.cpp
+++ b/libraries/AC_Avoidance/AP_OADatabase.cpp
@@ -68,7 +68,7 @@ const AP_Param::GroupInfo AP_OADatabase::var_info[] = {
// @Description: OADatabase output level to configure which database objects are sent to the ground station. All data is always available internally for avoidance algorithms.
// @Values: 0:Disabled,1:Send only HIGH importance items,2:Send HIGH and NORMAL importance items,3:Send all items
// @User: Advanced
- AP_GROUPINFO("OUTPUT", 4, AP_OADatabase, _output_level, (float)OA_DbOutputLevel::OUTPUT_LEVEL_SEND_HIGH),
+ AP_GROUPINFO("OUTPUT", 4, AP_OADatabase, _output_level, (float)OutputLevel::HIGH),
// @Param: BEAM_WIDTH
// @DisplayName: OADatabase beam width
@@ -97,7 +97,7 @@ const AP_Param::GroupInfo AP_OADatabase::var_info[] = {
// @Param{Copter}: ALT_MIN
// @DisplayName: OADatabase minimum altitude above home before storing obstacles
- // @Description: OADatabase will reject obstacle's if vehicle's altitude above home is below this parameter, in a 3 meter radius around home. Set 0 to disable this feature.
+ // @Description: OADatabase will reject obstacles if vehicle's altitude above home is below this parameter, in a 3 meter radius around home. Set 0 to disable this feature.
// @Units: m
// @Range: 0 4
// @User: Advanced
@@ -210,19 +210,19 @@ uint8_t AP_OADatabase::get_send_to_gcs_flags(const OA_DbItemImportance importanc
{
switch (importance) {
case OA_DbItemImportance::Low:
- if (_output_level.get() >= (int8_t)OA_DbOutputLevel::OUTPUT_LEVEL_SEND_ALL) {
+ if (_output_level >= OutputLevel::ALL) {
return 0xFF;
}
break;
case OA_DbItemImportance::Normal:
- if (_output_level.get() >= (int8_t)OA_DbOutputLevel::OUTPUT_LEVEL_SEND_HIGH_AND_NORMAL) {
+ if (_output_level >= OutputLevel::HIGH_AND_NORMAL) {
return 0xFF;
}
break;
case OA_DbItemImportance::High:
- if (_output_level.get() >= (int8_t)OA_DbOutputLevel::OUTPUT_LEVEL_SEND_HIGH) {
+ if (_output_level >= OutputLevel::HIGH) {
return 0xFF;
}
break;
@@ -372,7 +372,7 @@ void AP_OADatabase::send_adsb_vehicle(mavlink_channel_t chan, uint16_t interval_
static_assert(MAVLINK_COMM_NUM_BUFFERS <= sizeof(OA_DbItem::send_to_gcs) * 8,
"AP_OADatabase's OA_DBItem.send_to_gcs bitmask must be large enough to hold MAVLINK_COMM_NUM_BUFFERS");
- if ((_output_level.get() <= (int8_t)OA_DbOutputLevel::OUTPUT_LEVEL_DISABLED) || !healthy()) {
+ if ((_output_level <= OutputLevel::NONE) || !healthy()) {
return;
}
diff --git a/libraries/AC_Avoidance/AP_OADatabase.h b/libraries/AC_Avoidance/AP_OADatabase.h
index 2a0a0ee65d565f..2a77fdc5661c8d 100644
--- a/libraries/AC_Avoidance/AP_OADatabase.h
+++ b/libraries/AC_Avoidance/AP_OADatabase.h
@@ -74,18 +74,18 @@ class AP_OADatabase {
bool is_close_to_item_in_database(const uint16_t index, const OA_DbItem &item) const;
// enum for use with _OUTPUT parameter
- enum class OA_DbOutputLevel {
- OUTPUT_LEVEL_DISABLED = 0,
- OUTPUT_LEVEL_SEND_HIGH = 1,
- OUTPUT_LEVEL_SEND_HIGH_AND_NORMAL = 2,
- OUTPUT_LEVEL_SEND_ALL = 3
+ enum class OutputLevel {
+ NONE = 0,
+ HIGH = 1,
+ HIGH_AND_NORMAL = 2,
+ ALL = 3
};
// parameters
AP_Int16 _queue_size_param; // queue size
AP_Int16 _database_size_param; // db size
AP_Int8 _database_expiry_seconds; // objects expire after this timeout
- AP_Int8 _output_level; // controls which items should be sent to GCS
+ AP_Enum _output_level; // controls which items should be sent to GCS
AP_Float _beam_width; // beam width used when converting lidar readings to object radius
AP_Float _radius_min; // objects minimum radius (in meters)
AP_Float _dist_max; // objects maximum distance (in meters)
diff --git a/libraries/AC_CustomControl/AC_CustomControl_PID.cpp b/libraries/AC_CustomControl/AC_CustomControl_PID.cpp
index 5cbef5447747f1..29e2163cbb6ea3 100644
--- a/libraries/AC_CustomControl/AC_CustomControl_PID.cpp
+++ b/libraries/AC_CustomControl/AC_CustomControl_PID.cpp
@@ -239,10 +239,11 @@ AC_CustomControl_PID::AC_CustomControl_PID(AC_CustomControl& frontend, AP_AHRS_V
_p_angle_roll2(AC_ATTITUDE_CONTROL_ANGLE_P * 0.90f),
_p_angle_pitch2(AC_ATTITUDE_CONTROL_ANGLE_P * 0.90f),
_p_angle_yaw2(AC_ATTITUDE_CONTROL_ANGLE_P * 0.90f),
- _pid_atti_rate_roll(AC_ATC_MULTI_RATE_RP_P * 0.90f, AC_ATC_MULTI_RATE_RP_I * 0.90f, AC_ATC_MULTI_RATE_RP_D * 0.90f, 0.0f, AC_ATC_MULTI_RATE_RP_IMAX * 0.90f, AC_ATC_MULTI_RATE_RP_FILT_HZ * 0.90f, 0.0f, AC_ATC_MULTI_RATE_RP_FILT_HZ * 0.90f, dt),
- _pid_atti_rate_pitch(AC_ATC_MULTI_RATE_RP_P * 0.90f, AC_ATC_MULTI_RATE_RP_I * 0.90f, AC_ATC_MULTI_RATE_RP_D * 0.90f, 0.0f, AC_ATC_MULTI_RATE_RP_IMAX * 0.90f, AC_ATC_MULTI_RATE_RP_FILT_HZ * 0.90f, 0.0f, AC_ATC_MULTI_RATE_RP_FILT_HZ * 0.90f, dt),
- _pid_atti_rate_yaw(AC_ATC_MULTI_RATE_YAW_P * 0.90f, AC_ATC_MULTI_RATE_YAW_I * 0.90f, AC_ATC_MULTI_RATE_YAW_D * 0.90f, 0.0f, AC_ATC_MULTI_RATE_YAW_IMAX * 0.90f, AC_ATC_MULTI_RATE_RP_FILT_HZ * 0.90f, AC_ATC_MULTI_RATE_YAW_FILT_HZ * 0.90f, 0.0f, dt)
+ _pid_atti_rate_roll(AC_ATC_MULTI_RATE_RP_P * 0.90f, AC_ATC_MULTI_RATE_RP_I * 0.90f, AC_ATC_MULTI_RATE_RP_D * 0.90f, 0.0f, AC_ATC_MULTI_RATE_RP_IMAX * 0.90f, AC_ATC_MULTI_RATE_RP_FILT_HZ * 0.90f, 0.0f, AC_ATC_MULTI_RATE_RP_FILT_HZ * 0.90f),
+ _pid_atti_rate_pitch(AC_ATC_MULTI_RATE_RP_P * 0.90f, AC_ATC_MULTI_RATE_RP_I * 0.90f, AC_ATC_MULTI_RATE_RP_D * 0.90f, 0.0f, AC_ATC_MULTI_RATE_RP_IMAX * 0.90f, AC_ATC_MULTI_RATE_RP_FILT_HZ * 0.90f, 0.0f, AC_ATC_MULTI_RATE_RP_FILT_HZ * 0.90f),
+ _pid_atti_rate_yaw(AC_ATC_MULTI_RATE_YAW_P * 0.90f, AC_ATC_MULTI_RATE_YAW_I * 0.90f, AC_ATC_MULTI_RATE_YAW_D * 0.90f, 0.0f, AC_ATC_MULTI_RATE_YAW_IMAX * 0.90f, AC_ATC_MULTI_RATE_RP_FILT_HZ * 0.90f, AC_ATC_MULTI_RATE_YAW_FILT_HZ * 0.90f, 0.0f)
{
+ _dt = dt;
AP_Param::setup_object_defaults(this, var_info);
}
@@ -289,9 +290,9 @@ Vector3f AC_CustomControl_PID::update()
// run rate controller
Vector3f gyro_latest = _ahrs->get_gyro_latest();
Vector3f motor_out;
- motor_out.x = _pid_atti_rate_roll.update_all(target_rate[0], gyro_latest[0], 1);
- motor_out.y = _pid_atti_rate_pitch.update_all(target_rate[1], gyro_latest[1], 1);
- motor_out.z = _pid_atti_rate_yaw.update_all(target_rate[2], gyro_latest[2], 1);
+ motor_out.x = _pid_atti_rate_roll.update_all(target_rate[0], gyro_latest[0], _dt, false);
+ motor_out.y = _pid_atti_rate_pitch.update_all(target_rate[1], gyro_latest[1], _dt, false);
+ motor_out.z = _pid_atti_rate_yaw.update_all(target_rate[2], gyro_latest[2], _dt, false);
return motor_out;
}
diff --git a/libraries/AC_CustomControl/AC_CustomControl_PID.h b/libraries/AC_CustomControl/AC_CustomControl_PID.h
index 9740061aad76f0..a48b5f9759536f 100644
--- a/libraries/AC_CustomControl/AC_CustomControl_PID.h
+++ b/libraries/AC_CustomControl/AC_CustomControl_PID.h
@@ -26,6 +26,7 @@ class AC_CustomControl_PID : public AC_CustomControl_Backend {
protected:
// put controller related variable here
+ float _dt;
// angle P controller objects
AC_P _p_angle_roll2;
diff --git a/libraries/AC_Fence/AC_Fence.cpp b/libraries/AC_Fence/AC_Fence.cpp
index f9bdb7733010f9..eea61ea6ccf273 100644
--- a/libraries/AC_Fence/AC_Fence.cpp
+++ b/libraries/AC_Fence/AC_Fence.cpp
@@ -52,8 +52,8 @@ const AP_Param::GroupInfo AC_Fence::var_info[] = {
// @Param: TYPE
// @DisplayName: Fence Type
// @Description: Enabled fence types held as bitmask
- // @Bitmask{Rover}: 1:Circle,2:Polygon
- // @Bitmask{Copter, Plane, Sub}: 0:Max altitude,1:Circle,2:Polygon,3:Min altitude
+ // @Bitmask{Rover}: 1:Circle Centered on Home,2:Inclusion/Exclusion Circles+Polygons
+ // @Bitmask{Copter, Plane, Sub}: 0:Max altitude,1:Circle Centered on Home,2:Inclusion/Exclusion Circles+Polygons,3:Min altitude
// @User: Standard
AP_GROUPINFO("TYPE", 1, AC_Fence, _enabled_fences, AC_FENCE_TYPE_DEFAULT),
@@ -137,8 +137,8 @@ const AP_Param::GroupInfo AC_Fence::var_info[] = {
// @Param{Plane}: OPTIONS
// @DisplayName: Fence options
- // @Description: 0:Disable mode change following fence action until fence breach is cleared
- // @Bitmask: 0:Disable mode change following fence action until fence breach is cleared
+ // @Description: 0:Disable mode change following fence action until fence breach is cleared. When bit 1 is set the allowable flight areas is the union of all polygon and circle fence areas instead of the intersection, which means a fence breach occurs only if you are outside all of the fence areas.
+ // @Bitmask: 0:Disable mode change following fence action until fence breach is cleared, 1:Allow union of inclusion areas
// @User: Standard
AP_GROUPINFO_FRAME("OPTIONS", 11, AC_Fence, _options, static_cast(OPTIONS::DISABLE_MODE_CHANGE), AP_PARAM_FRAME_PLANE),
diff --git a/libraries/AC_Fence/AC_Fence.h b/libraries/AC_Fence/AC_Fence.h
index d4c042c082834a..1e8bd1d37c5b6f 100644
--- a/libraries/AC_Fence/AC_Fence.h
+++ b/libraries/AC_Fence/AC_Fence.h
@@ -32,6 +32,7 @@
class AC_Fence
{
public:
+ friend class AC_PolyFence_loader;
enum class AutoEnable
{
@@ -146,10 +147,14 @@ class AC_Fence
const AC_PolyFence_loader &polyfence() const;
enum class OPTIONS {
- DISABLE_MODE_CHANGE = 1 << 0,
+ DISABLE_MODE_CHANGE = 1U << 0,
+ INCLUSION_UNION = 1U << 1,
};
+ static bool option_enabled(OPTIONS opt, const AP_Int16 &options) {
+ return (options.get() & int16_t(opt)) != 0;
+ }
bool option_enabled(OPTIONS opt) const {
- return (_options.get() & int16_t(opt)) != 0;
+ return option_enabled(opt, _options);
}
static const struct AP_Param::GroupInfo var_info[];
@@ -219,7 +224,7 @@ class AC_Fence
uint32_t _manual_recovery_start_ms; // system time in milliseconds that pilot re-took manual control
- AC_PolyFence_loader _poly_loader{_total}; // polygon fence
+ AC_PolyFence_loader _poly_loader{_total, _options}; // polygon fence
};
namespace AP {
diff --git a/libraries/AC_Fence/AC_Fence_config.h b/libraries/AC_Fence/AC_Fence_config.h
index 5c8494f7ad1403..dbc607afa755da 100644
--- a/libraries/AC_Fence/AC_Fence_config.h
+++ b/libraries/AC_Fence/AC_Fence_config.h
@@ -9,3 +9,7 @@
#ifndef AP_FENCE_ENABLED
#define AP_FENCE_ENABLED 2
#endif
+
+#ifndef AC_POLYFENCE_FENCE_POINT_PROTOCOL_SUPPORT
+#define AC_POLYFENCE_FENCE_POINT_PROTOCOL_SUPPORT AP_FENCE_ENABLED
+#endif
diff --git a/libraries/AC_Fence/AC_PolyFence_loader.cpp b/libraries/AC_Fence/AC_PolyFence_loader.cpp
index 242ed7c40fbf38..1b42ded2738094 100644
--- a/libraries/AC_Fence/AC_PolyFence_loader.cpp
+++ b/libraries/AC_Fence/AC_PolyFence_loader.cpp
@@ -13,6 +13,7 @@
#include
#include
#include
+#include
#include
@@ -189,21 +190,6 @@ bool AC_PolyFence_loader::read_latlon_from_storage(uint16_t &read_offset, Vector
return true;
}
-// load boundary point from eeprom, returns true on successful load
-// only used for converting from old storage to new storage
-bool AC_PolyFence_loader::load_point_from_eeprom(uint16_t i, Vector2l& point) const
-{
- // sanity check index
- if (i >= max_items()) {
- return false;
- }
-
- // read fence point
- point.x = fence_storage.read_uint32(i * sizeof(Vector2l));
- point.y = fence_storage.read_uint32(i * sizeof(Vector2l) + sizeof(uint32_t));
- return true;
-}
-
bool AC_PolyFence_loader::breached() const
{
Location loc;
@@ -226,11 +212,14 @@ bool AC_PolyFence_loader::breached(const Location& loc) const
pos.x = loc.lat;
pos.y = loc.lng;
+ const uint16_t num_inclusion = _num_loaded_circle_inclusion_boundaries + _num_loaded_inclusion_boundaries;
+ uint16_t num_inclusion_outside = 0;
+
// check we are inside each inclusion zone:
for (uint8_t i=0; i<_num_loaded_inclusion_boundaries; i++) {
const InclusionBoundary &boundary = _loaded_inclusion_boundary[i];
if (Polygon_outside(pos, boundary.points_lla, boundary.count)) {
- return true;
+ num_inclusion_outside++;
}
}
@@ -260,6 +249,21 @@ bool AC_PolyFence_loader::breached(const Location& loc) const
circle_center.lng = circle.point.y;
const float diff_cm = loc.get_distance(circle_center)*100.0f;
if (diff_cm > circle.radius * 100.0f) {
+ num_inclusion_outside++;
+ }
+ }
+
+ if (AC_Fence::option_enabled(AC_Fence::OPTIONS::INCLUSION_UNION, _options)) {
+ // using union of inclusion areas, we are outside the fence if
+ // there is at least one inclusion areas and we are outside
+ // all of them
+ if (num_inclusion > 0 && num_inclusion == num_inclusion_outside) {
+ return true;
+ }
+ } else {
+ // using intersection of inclusion areas. We are outside if we
+ // are outside any of them
+ if (num_inclusion_outside > 0) {
return true;
}
}
@@ -294,70 +298,6 @@ bool AC_PolyFence_loader::format()
return write_eos_to_storage(offset);
}
-bool AC_PolyFence_loader::convert_to_new_storage()
-{
- // sanity check total
- _total.set(constrain_int16(_total, 0, max_items()));
- // FIXME: ensure the fence was closed and don't load it if it was not
- if (_total < 5) {
- // fence was invalid. Just format it and move on
- return format();
- }
-
- if (hal.util->available_memory() < 100U + _total * sizeof(Vector2l)) {
- return false;
- }
-
- Vector2l *_tmp_boundary = new Vector2l[_total];
- if (_tmp_boundary == nullptr) {
- return false;
- }
-
- // load each point from eeprom
- bool ret = false;
- for (uint16_t index=0; index<_total; index++) {
- // load boundary point as lat/lon point
- if (!load_point_from_eeprom(index, _tmp_boundary[index])) {
- goto out;
- }
- }
-
- // now store:
- if (!format()) {
- goto out;
- }
- {
- uint16_t offset = 4; // skip magic
- // write return point
- if (!write_type_to_storage(offset, AC_PolyFenceType::RETURN_POINT)) {
- return false;
- }
- if (!write_latlon_to_storage(offset, _tmp_boundary[0])) {
- return false;
- }
- // write out polygon fence
- fence_storage.write_uint8(offset, (uint8_t)AC_PolyFenceType::POLYGON_INCLUSION);
- offset++;
- fence_storage.write_uint8(offset, (uint8_t)_total-2);
- offset++;
- for (uint8_t i=1; i<_total-1; i++) {
- if (!write_latlon_to_storage(offset, _tmp_boundary[i])) {
- goto out;
- }
- }
- // write eos marker
- if (!write_eos_to_storage(offset)) {
- goto out;
- }
- }
-
- ret = true;
-
-out:
- delete[] _tmp_boundary;
- return ret;
-}
-
bool AC_PolyFence_loader::scale_latlon_from_origin(const Location &origin, const Vector2l &point, Vector2f &pos_cm)
{
Location tmp_loc;
@@ -522,7 +462,7 @@ void AC_PolyFence_loader::scan_eeprom_index_fences(const AC_PolyFenceType type,
bool AC_PolyFence_loader::index_eeprom()
{
if (!formatted()) {
- if (!convert_to_new_storage()) {
+ if (!format()) {
return false;
}
}
@@ -1202,7 +1142,6 @@ bool AC_PolyFence_loader::write_fence(const AC_PolyFenceItem *new_items, uint16_
}
-#if AC_POLYFENCE_FENCE_POINT_PROTOCOL_SUPPORT
bool AC_PolyFence_loader::get_return_point(Vector2l &ret)
{
if (!check_indexed()) {
@@ -1277,7 +1216,6 @@ bool AC_PolyFence_loader::get_return_point(Vector2l &ret)
return true;
}
-#endif
AC_PolyFence_loader::FenceIndex *AC_PolyFence_loader::find_first_fence(const AC_PolyFenceType type) const
{
diff --git a/libraries/AC_Fence/AC_PolyFence_loader.h b/libraries/AC_Fence/AC_PolyFence_loader.h
index 4c74bd7e2c3e9e..92d8bca51278b0 100644
--- a/libraries/AC_Fence/AC_PolyFence_loader.h
+++ b/libraries/AC_Fence/AC_PolyFence_loader.h
@@ -39,15 +39,14 @@ class AC_PolyFenceItem {
#include
#include
-#define AC_POLYFENCE_FENCE_POINT_PROTOCOL_SUPPORT 1
-
class AC_PolyFence_loader
{
public:
- AC_PolyFence_loader(AP_Int8 &total) :
- _total(total) {}
+ AC_PolyFence_loader(AP_Int8 &total, const AP_Int16 &options) :
+ _total(total),
+ _options(options) {}
/* Do not allow copies */
CLASS_NO_COPY(AC_PolyFence_loader);
@@ -173,12 +172,10 @@ class AC_PolyFence_loader
// call @10Hz to check for fence load being valid
void update();
-#if AC_POLYFENCE_FENCE_POINT_PROTOCOL_SUPPORT
// get_return_point - returns latitude/longitude of return point.
// This works with storage - the returned vector is absolute
// lat/lon.
bool get_return_point(Vector2l &ret) WARN_IF_UNUSED;
-#endif
// return total number of fences - polygons and circles
uint16_t total_fence_count() const {
@@ -353,18 +350,6 @@ class AC_PolyFence_loader
Vector2f *&next_storage_point,
Vector2l *&next_storage_point_lla) WARN_IF_UNUSED;
- /*
- * Upgrade functions - attempt to keep user's fences when
- * upgrading to new firmware
- */
- // convert_to_new_storage - will attempt to change a pre-existing
- // stored fence to the new storage format (so people don't lose
- // their fences when upgrading)
- bool convert_to_new_storage() WARN_IF_UNUSED;
- // load boundary point from eeprom, returns true on successful load
- bool load_point_from_eeprom(uint16_t i, Vector2l& point) const WARN_IF_UNUSED;
-
-
#if AC_POLYFENCE_FENCE_POINT_PROTOCOL_SUPPORT
/*
* FENCE_POINT protocol compatability
@@ -397,6 +382,7 @@ class AC_PolyFence_loader
// _total - reference to FENCE_TOTAL parameter. This is used
// solely for compatability with the FENCE_POINT protocol
AP_Int8 &_total;
+ const AP_Int16 &_options;
uint8_t _old_total;
diff --git a/libraries/AC_PID/AC_PID_2D.cpp b/libraries/AC_PID/AC_PID_2D.cpp
index 48f11f60965a4f..a79c20678f53db 100644
--- a/libraries/AC_PID/AC_PID_2D.cpp
+++ b/libraries/AC_PID/AC_PID_2D.cpp
@@ -97,6 +97,10 @@ Vector2f AC_PID_2D::update_all(const Vector2f &target, const Vector2f &measureme
// update I term
update_i(dt, limit);
+ // calculate slew limit
+ _slew_calc.update(Vector2f{_pid_info_x.P + _pid_info_x.D, _pid_info_y.P + _pid_info_y.D}, dt);
+ _pid_info_x.slew_rate = _pid_info_y.slew_rate = _slew_calc.get_slew_rate();
+
_pid_info_x.target = _target.x;
_pid_info_x.actual = measurement.x;
_pid_info_x.error = _error.x;
diff --git a/libraries/AC_PID/AC_PID_2D.h b/libraries/AC_PID/AC_PID_2D.h
index 0fd7e8a6ec63eb..8213997df1f84d 100644
--- a/libraries/AC_PID/AC_PID_2D.h
+++ b/libraries/AC_PID/AC_PID_2D.h
@@ -8,6 +8,7 @@
#include
#include
#include
+#include
/// @class AC_PID_2D
/// @brief Copter PID control class
@@ -72,6 +73,9 @@ class AC_PID_2D {
void set_integrator(const Vector3f& i) { set_integrator(Vector2f{i.x, i.y}); }
void set_integrator(const Vector2f& i);
+ // return current slew rate of slew limiter. Will return 0 if SMAX is zero
+ float get_slew_rate(void) const { return _slew_calc.get_slew_rate(); }
+
const AP_PIDInfo& get_pid_info_x(void) const { return _pid_info_x; }
const AP_PIDInfo& get_pid_info_y(void) const { return _pid_info_y; }
@@ -99,6 +103,8 @@ class AC_PID_2D {
AP_PIDInfo _pid_info_x;
AP_PIDInfo _pid_info_y;
+ SlewCalculator2D _slew_calc; // 2D slew rate calculator
+
private:
const float default_kp;
const float default_ki;
diff --git a/libraries/AC_WPNav/AC_Circle.cpp b/libraries/AC_WPNav/AC_Circle.cpp
index 6d48ed8ffe80ec..752699a5291cc9 100644
--- a/libraries/AC_WPNav/AC_Circle.cpp
+++ b/libraries/AC_WPNav/AC_Circle.cpp
@@ -29,7 +29,7 @@ const AP_Param::GroupInfo AC_Circle::var_info[] = {
// @Param: OPTIONS
// @DisplayName: Circle options
// @Description: 0:Enable or disable using the pitch/roll stick control circle mode's radius and rate
- // @Bitmask: 0:manual control, 1:face direction of travel, 2:Start at center rather than on perimeter
+ // @Bitmask: 0:manual control, 1:face direction of travel, 2:Start at center rather than on perimeter, 3:Make Mount ROI the center of the circle
// @User: Standard
AP_GROUPINFO("OPTIONS", 2, AC_Circle, _options, 1),
diff --git a/libraries/AC_WPNav/AC_Circle.h b/libraries/AC_WPNav/AC_Circle.h
index 88dd03c02cfeb8..498241e0252304 100644
--- a/libraries/AC_WPNav/AC_Circle.h
+++ b/libraries/AC_WPNav/AC_Circle.h
@@ -89,6 +89,9 @@ class AC_Circle
/// true if pilot control of radius and turn rate is enabled
bool pilot_control_enabled() const { return (_options.get() & CircleOptions::MANUAL_CONTROL) != 0; }
+ /// true if mount roi is at circle center
+ bool roi_at_center() const { return (_options.get() & CircleOptions::ROI_AT_CENTER) != 0; }
+
/// provide rangefinder based terrain offset
/// terrain offset is the terrain's height above the EKF origin
void set_rangefinder_terrain_offset(bool use, bool healthy, float terrain_offset_cm) { _rangefinder_available = use; _rangefinder_healthy = healthy; _rangefinder_terrain_offset_cm = terrain_offset_cm;}
@@ -136,6 +139,7 @@ class AC_Circle
MANUAL_CONTROL = 1U << 0,
FACE_DIRECTION_OF_TRAVEL = 1U << 1,
INIT_AT_CENTER = 1U << 2, // true then the circle center will be the current location, false and the center will be 1 radius ahead
+ ROI_AT_CENTER = 1U << 3, // true when the mount roi is at circle center
};
// parameters
diff --git a/libraries/AC_WPNav/AC_WPNav.cpp b/libraries/AC_WPNav/AC_WPNav.cpp
index c18e9392c7c14a..e63b9fc4450c99 100644
--- a/libraries/AC_WPNav/AC_WPNav.cpp
+++ b/libraries/AC_WPNav/AC_WPNav.cpp
@@ -165,7 +165,8 @@ void AC_WPNav::wp_and_spline_init(float speed_cms, Vector3f stopping_point)
_pos_control.init_z_controller_stopping_point();
_pos_control.init_xy_controller_stopping_point();
- // initialize the desired wp speed if not already done
+ // initialize the desired wp speed
+ _check_wp_speed_change = !is_positive(speed_cms);
_wp_desired_speed_xy_cms = is_positive(speed_cms) ? speed_cms : _wp_speed_cms;
_wp_desired_speed_xy_cms = MAX(_wp_desired_speed_xy_cms, WPNAV_WP_SPEED_MIN);
@@ -586,11 +587,12 @@ int32_t AC_WPNav::get_wp_bearing_to_destination() const
/// update_wpnav - run the wp controller - should be called at 100hz or higher
bool AC_WPNav::update_wpnav()
{
- bool ret = true;
-
- if (!is_equal(_wp_speed_cms.get(), _last_wp_speed_cms)) {
- set_speed_xy(_wp_speed_cms);
- _last_wp_speed_cms = _wp_speed_cms;
+ // check for changes in speed parameter values
+ if (_check_wp_speed_change) {
+ if (!is_equal(_wp_speed_cms.get(), _last_wp_speed_cms)) {
+ set_speed_xy(_wp_speed_cms);
+ _last_wp_speed_cms = _wp_speed_cms;
+ }
}
if (!is_equal(_wp_speed_up_cms.get(), _last_wp_speed_up_cms)) {
set_speed_up(_wp_speed_up_cms);
@@ -602,6 +604,7 @@ bool AC_WPNav::update_wpnav()
}
// advance the target if necessary
+ bool ret = true;
if (!advance_wp_target_along_track(_pos_control.get_dt())) {
// To-Do: handle inability to advance along track (probably because of missing terrain data)
ret = false;
diff --git a/libraries/AC_WPNav/AC_WPNav.h b/libraries/AC_WPNav/AC_WPNav.h
index 8b0a02107e3bbd..e4563f7ce6de16 100644
--- a/libraries/AC_WPNav/AC_WPNav.h
+++ b/libraries/AC_WPNav/AC_WPNav.h
@@ -247,6 +247,8 @@ class AC_WPNav
AP_Float _wp_jerk; // maximum jerk used to generate scurve trajectories in m/s/s/s
AP_Float _terrain_margin; // terrain following altitude margin. vehicle will stop if distance from target altitude is larger than this margin
+ // WPNAV_SPEED param change checker
+ bool _check_wp_speed_change; // if true WPNAV_SPEED param should be checked for changes in-flight
float _last_wp_speed_cms; // last recorded WPNAV_SPEED, used for changing speed in-flight
float _last_wp_speed_up_cms; // last recorded WPNAV_SPEED_UP, used for changing speed in-flight
float _last_wp_speed_down_cms; // last recorded WPNAV_SPEED_DN, used for changing speed in-flight
diff --git a/libraries/APM_Control/AP_AutoTune.cpp b/libraries/APM_Control/AP_AutoTune.cpp
index c8008b61d4ee95..0cc30e59cb6269 100644
--- a/libraries/APM_Control/AP_AutoTune.cpp
+++ b/libraries/APM_Control/AP_AutoTune.cpp
@@ -424,9 +424,17 @@ void AP_AutoTune::update(AP_PIDInfo &pinfo, float scaler, float angle_err_deg)
}
// setup filters to be suitable for time constant and gyro filter
- rpid.filt_T_hz().set(10.0/(current.tau * 2 * M_PI));
+ // filtering T can prevent P/D oscillation being seen, so allow the
+ // user to switch it off
+ if (!has_option(DISABLE_FLTT_UPDATE)) {
+ rpid.filt_T_hz().set(10.0/(current.tau * 2 * M_PI));
+ }
rpid.filt_E_hz().set(0);
- rpid.filt_D_hz().set(AP::ins().get_gyro_filter_hz()*0.5);
+ // filtering D at the same level as VTOL can allow unwanted oscillations to be seen,
+ // so allow the user to switch it off and select their own (usually lower) value
+ if (!has_option(DISABLE_FLTD_UPDATE)) {
+ rpid.filt_D_hz().set(AP::ins().get_gyro_filter_hz()*0.5);
+ }
current.FF = FF;
current.P = P;
diff --git a/libraries/APM_Control/AP_AutoTune.h b/libraries/APM_Control/AP_AutoTune.h
index 1859a2489f269e..67b6cf07f9036f 100644
--- a/libraries/APM_Control/AP_AutoTune.h
+++ b/libraries/APM_Control/AP_AutoTune.h
@@ -25,6 +25,11 @@ class AP_AutoTune
AUTOTUNE_YAW = 2,
};
+ enum Options {
+ DISABLE_FLTD_UPDATE = 0,
+ DISABLE_FLTT_UPDATE = 1
+ };
+
struct PACKED log_ATRP {
LOG_PACKET_HEADER;
uint64_t time_us;
@@ -116,6 +121,10 @@ class AP_AutoTune
// update rmax and tau towards target
void update_rmax();
+ bool has_option(Options option) {
+ return (aparm.autotune_options.get() & uint32_t(1< AR_ATTCONTROL_TIMEOUT_MS)) {
@@ -548,6 +557,12 @@ float AR_AttitudeControl::get_steering_out_rate(float desired_rate, bool motor_l
// acceleration limit desired turn rate
if (is_positive(_steer_accel_max)) {
const float change_max = radians(_steer_accel_max) * dt;
+ if (desired_rate <= _desired_turn_rate - change_max) {
+ _steering_limit_left = true;
+ }
+ if (desired_rate >= _desired_turn_rate + change_max) {
+ _steering_limit_right = true;
+ }
desired_rate = constrain_float(desired_rate, _desired_turn_rate - change_max, _desired_turn_rate + change_max);
}
_desired_turn_rate = desired_rate;
@@ -555,6 +570,12 @@ float AR_AttitudeControl::get_steering_out_rate(float desired_rate, bool motor_l
// rate limit desired turn rate
if (is_positive(_steer_rate_max)) {
const float steer_rate_max_rad = radians(_steer_rate_max);
+ if (_desired_turn_rate <= -steer_rate_max_rad) {
+ _steering_limit_left = true;
+ }
+ if (_desired_turn_rate >= steer_rate_max_rad) {
+ _steering_limit_right = true;
+ }
_desired_turn_rate = constrain_float(_desired_turn_rate, -steer_rate_max_rad, steer_rate_max_rad);
}
@@ -563,9 +584,16 @@ float AR_AttitudeControl::get_steering_out_rate(float desired_rate, bool motor_l
if (get_forward_speed(speed)) {
// do not limit to less than 1 deg/s
const float turn_rate_max = MAX(get_turn_rate_from_lat_accel(get_turn_lat_accel_max(), fabsf(speed)), radians(1.0f));
+ if (_desired_turn_rate <= -turn_rate_max) {
+ _steering_limit_left = true;
+ }
+ if (_desired_turn_rate >= turn_rate_max) {
+ _steering_limit_right = true;
+ }
_desired_turn_rate = constrain_float(_desired_turn_rate, -turn_rate_max, turn_rate_max);
}
+ // update pid to calculate output to motors
float output = _steer_rate_pid.update_all(_desired_turn_rate, AP::ahrs().get_yaw_rate_earth(), dt, (motor_limit_left || motor_limit_right));
output += _steer_rate_pid.get_ff();
// constrain and return final output
@@ -837,6 +865,13 @@ float AR_AttitudeControl::get_sail_out_from_heel(float desired_heel, float dt)
return (ff + p + i + d) * -1.0f;
}
+// get the slew rate value for speed and steering for oscillation detection in lua scripts
+void AR_AttitudeControl::get_srate(float &steering_srate, float &speed_srate)
+{
+ steering_srate = get_steering_rate_pid().get_pid_info().slew_rate;
+ speed_srate = _throttle_speed_pid_info.slew_rate;
+}
+
// get forward speed in m/s (earth-frame horizontal velocity but only along vehicle x-axis). returns true on success
bool AR_AttitudeControl::get_forward_speed(float &speed) const
{
diff --git a/libraries/APM_Control/AR_AttitudeControl.h b/libraries/APM_Control/AR_AttitudeControl.h
index 57d15526599e74..2a6bc583afce34 100644
--- a/libraries/APM_Control/AR_AttitudeControl.h
+++ b/libraries/APM_Control/AR_AttitudeControl.h
@@ -10,6 +10,11 @@ class AR_AttitudeControl {
// constructor
AR_AttitudeControl();
+ // do not allow copying
+ CLASS_NO_COPY(AR_AttitudeControl);
+
+ static AR_AttitudeControl *get_singleton() { return _singleton; }
+
//
// steering controller
//
@@ -31,6 +36,7 @@ class AR_AttitudeControl {
// return a steering servo output given a desired yaw rate in radians/sec.
// positive yaw is to the right
// return value is normally in range -1.0 to +1.0 but can be higher or lower
+ // also sets steering_limit_left and steering_limit_right flags
float get_steering_out_rate(float desired_rate, bool motor_limit_left, bool motor_limit_right, float dt);
// get latest desired turn rate in rad/sec recorded during calls to get_steering_out_rate. For reporting purposes only
@@ -48,6 +54,11 @@ class AR_AttitudeControl {
// get the lateral acceleration limit (in m/s/s). Returns at least 0.1G or approximately 1 m/s/s
float get_turn_lat_accel_max() const { return MAX(_turn_lateral_G_max, 0.1f) * GRAVITY_MSS; }
+ // returns true if the steering has been limited which can be caused by the physical steering surface
+ // reaching its physical limits (aka motor limits) or acceleration or turn rate limits being applied
+ bool steering_limit_left() const { return _steering_limit_left; }
+ bool steering_limit_right() const { return _steering_limit_right; }
+
//
// throttle / speed controller
//
@@ -89,6 +100,9 @@ class AR_AttitudeControl {
AC_PID& get_sailboat_heel_pid() { return _sailboat_heel_pid; }
const AP_PIDInfo& get_throttle_speed_pid_info() const { return _throttle_speed_pid_info; }
+ // get the slew rate value for speed and steering for oscillation detection in lua scripts
+ void get_srate(float &steering_srate, float &speed_srate);
+
// get forward speed in m/s (earth-frame horizontal velocity but only along vehicle x-axis). returns true on success
bool get_forward_speed(float &speed) const;
@@ -121,6 +135,8 @@ class AR_AttitudeControl {
private:
+ static AR_AttitudeControl *_singleton;
+
// parameters
AC_P _steer_angle_p; // steering angle controller
AC_PID _steer_rate_pid; // steering rate controller
@@ -143,6 +159,8 @@ class AR_AttitudeControl {
uint32_t _steer_turn_last_ms; // system time of last call to steering rate controller
float _desired_lat_accel; // desired lateral acceleration (in m/s/s) from latest call to get_steering_out_lat_accel (for reporting purposes)
float _desired_turn_rate; // desired turn rate (in radians/sec) either from external caller or from lateral acceleration controller
+ bool _steering_limit_left; // true when the steering control has reached its left limit (e.g. motor has reached limits or accel or turn rate limits applied)
+ bool _steering_limit_right; // true when the steering control has reached its right limit (e.g. motor has reached limits or accel or turn rate limits applied)
// throttle control
uint32_t _speed_last_ms; // system time of last call to get_throttle_out_speed
diff --git a/libraries/APM_Control/AR_PosControl.cpp b/libraries/APM_Control/AR_PosControl.cpp
index 6e1817ded5e9d5..9cf414831acf7e 100644
--- a/libraries/APM_Control/AR_PosControl.cpp
+++ b/libraries/APM_Control/AR_PosControl.cpp
@@ -22,8 +22,6 @@
#include
#include
-extern const AP_HAL::HAL& hal;
-
#define AR_POSCON_TIMEOUT_MS 100 // timeout after 0.1 sec
#define AR_POSCON_POS_P 0.2f // default position P gain
#define AR_POSCON_VEL_P 1.0f // default velocity P gain
@@ -35,6 +33,10 @@ extern const AP_HAL::HAL& hal;
#define AR_POSCON_VEL_FILT_D 5.0f // default velocity D term filter
#define AR_POSCON_DT 0.02f // default dt for PID controllers
+extern const AP_HAL::HAL& hal;
+
+AR_PosControl *AR_PosControl::_singleton;
+
const AP_Param::GroupInfo AR_PosControl::var_info[] = {
// @Param: _POS_P
@@ -103,6 +105,7 @@ AR_PosControl::AR_PosControl(AR_AttitudeControl& atc) :
_p_pos(AR_POSCON_POS_P),
_pid_vel(AR_POSCON_VEL_P, AR_POSCON_VEL_I, AR_POSCON_VEL_D, AR_POSCON_VEL_FF, AR_POSCON_VEL_IMAX, AR_POSCON_VEL_FILT, AR_POSCON_VEL_FILT_D)
{
+ _singleton = this;
AP_Param::setup_object_defaults(this, var_info);
}
@@ -157,12 +160,23 @@ void AR_PosControl::update(float dt)
_vel_target.y = vel_3d_cms.y * 0.01;
}
+ // calculate limit vector based on steering limits
+ Vector2f steering_limit_vec;
+ if (_atc.steering_limit_left()) {
+ steering_limit_vec = AP::ahrs().body_to_earth2D(Vector2f{0, _reversed ? 1.0f : -1.0f});
+ } else if (_atc.steering_limit_right()) {
+ steering_limit_vec = AP::ahrs().body_to_earth2D(Vector2f{0, _reversed ? -1.0f : 1.0f});
+ }
+
// calculate desired acceleration
- // To-Do: fixup _limit_vel used below
- _accel_target = _pid_vel.update_all(_vel_target, curr_vel_NED.xy(), dt, _limit_vel);
+ _accel_target = _pid_vel.update_all(_vel_target, curr_vel_NED.xy(), dt, steering_limit_vec);
if (_accel_desired_valid) {
_accel_target += _accel_desired;
}
+ // velocity controller I-term zeroed in forward-back direction
+ const Vector2f lat_vec_ef = AP::ahrs().body_to_earth2D(Vector2f{0, 1});
+ const Vector2f vel_i = _pid_vel.get_i().projected(lat_vec_ef);
+ _pid_vel.set_integrator(vel_i);
// convert desired acceleration to desired forward-back speed, desired lateral speed and desired turn rate
@@ -252,17 +266,40 @@ bool AR_PosControl::init()
return true;
}
-// methods to adjust position, velocity and acceleration targets smoothly using input shaping
-// pos should be the target position as an offset from the EKF origin (in meters)
+// adjust position, velocity and acceleration targets smoothly using input shaping
+// pos is the target position as an offset from the EKF origin (in meters)
+// vel is the target velocity in m/s. accel is the target acceleration in m/s/s
// dt should be the update rate in seconds
+// init should be called once before starting to use these methods
void AR_PosControl::input_pos_target(const Vector2p &pos, float dt)
+{
+ Vector2f vel;
+ Vector2f accel;
+ input_pos_vel_accel_target(pos, vel, accel, dt);
+}
+
+// adjust position, velocity and acceleration targets smoothly using input shaping
+// pos is the target position as an offset from the EKF origin (in meters)
+// vel is the target velocity in m/s. accel is the target acceleration in m/s/s
+// dt should be the update rate in seconds
+// init should be called once before starting to use these methods
+void AR_PosControl::input_pos_vel_target(const Vector2p &pos, const Vector2f &vel, float dt)
+{
+ Vector2f accel;
+ input_pos_vel_accel_target(pos, vel, accel, dt);
+}
+
+// adjust position, velocity and acceleration targets smoothly using input shaping
+// pos is the target position as an offset from the EKF origin (in meters)
+// vel is the target velocity in m/s. accel is the target acceleration in m/s/s
+// dt should be the update rate in seconds
+// init should be called once before starting to use these methods
+void AR_PosControl::input_pos_vel_accel_target(const Vector2p &pos, const Vector2f &vel, const Vector2f &accel, float dt)
{
// adjust target position, velocity and acceleration forward by dt
update_pos_vel_accel_xy(_pos_target, _vel_desired, _accel_desired, dt, Vector2f(), Vector2f(), Vector2f());
// call shape_pos_vel_accel_xy to pull target towards final destination
- Vector2f vel;
- Vector2f accel;
const float accel_max = MIN(_accel_max, _lat_accel_max);
shape_pos_vel_accel_xy(pos, vel, accel, _pos_target, _vel_desired, _accel_desired,
_speed_max, accel_max, _jerk_max, dt, false);
@@ -315,6 +352,13 @@ Vector2p AR_PosControl::get_pos_error() const
return (_pos_target - curr_pos_NE.topostype());
}
+// get the slew rate value for velocity. used for oscillation detection in lua scripts
+void AR_PosControl::get_srate(float &velocity_srate)
+{
+ // slew rate is the same for x and y axis
+ velocity_srate = _pid_vel.get_pid_info_x().slew_rate;
+}
+
// write PSC logs
void AR_PosControl::write_log()
{
diff --git a/libraries/APM_Control/AR_PosControl.h b/libraries/APM_Control/AR_PosControl.h
index 6e57077f046cb7..40748fce30771f 100644
--- a/libraries/APM_Control/AR_PosControl.h
+++ b/libraries/APM_Control/AR_PosControl.h
@@ -11,6 +11,11 @@ class AR_PosControl {
// constructor
AR_PosControl(AR_AttitudeControl& atc);
+ // do not allow copying
+ CLASS_NO_COPY(AR_PosControl);
+
+ static AR_PosControl *get_singleton() { return _singleton; }
+
// update navigation
void update(float dt);
@@ -41,10 +46,13 @@ class AR_PosControl {
bool init();
// adjust position, velocity and acceleration targets smoothly using input shaping
- // pos should be the target position as an offset from the EKF origin (in meters)
+ // pos is the target position as an offset from the EKF origin (in meters)
+ // vel is the target velocity in m/s. accel is the target acceleration in m/s/s
// dt should be the update rate in seconds
// init should be called once before starting to use these methods
void input_pos_target(const Vector2p &pos, float dt);
+ void input_pos_vel_target(const Vector2p &pos, const Vector2f &vel, float dt);
+ void input_pos_vel_accel_target(const Vector2p &pos, const Vector2f &vel, const Vector2f &accel, float dt);
// set target position, desired velocity and acceleration. These should be from an externally created path and are not "input shaped"
void set_pos_vel_accel_target(const Vector2p &pos, const Vector2f &vel, const Vector2f &accel);
@@ -70,6 +78,9 @@ class AR_PosControl {
AC_P_2D& get_pos_p() { return _p_pos; }
AC_PID_2D& get_vel_pid() { return _pid_vel; }
+ // get the slew rate value for velocity. used for oscillation detection in lua scripts
+ void get_srate(float &velocity_srate);
+
// write PSC logs
void write_log();
@@ -78,6 +89,8 @@ class AR_PosControl {
private:
+ static AR_PosControl *_singleton;
+
// initialise and check for ekf position resets
void init_ekf_xy_reset();
void handle_ekf_xy_reset();
@@ -95,7 +108,6 @@ class AR_PosControl {
float _lat_accel_max; // lateral acceleration maximum in m/s/s
float _jerk_max; // maximum jerk in m/s/s/s (used for both forward and lateral input shaping)
float _turn_radius; // vehicle turn radius in meters
- Vector2f _limit_vel; // To-Do: explain what this is
// position and velocity targets
Vector2p _pos_target; // position target as an offset (in meters) from the EKF origin
diff --git a/libraries/AP_ADSB/AP_ADSB_Sagetech.cpp b/libraries/AP_ADSB/AP_ADSB_Sagetech.cpp
index 6e610f9e90151d..940228fe345f30 100644
--- a/libraries/AP_ADSB/AP_ADSB_Sagetech.cpp
+++ b/libraries/AP_ADSB/AP_ADSB_Sagetech.cpp
@@ -69,11 +69,11 @@ void AP_ADSB_Sagetech::update()
// -----------------------------
uint32_t nbytes = MIN(_port->available(), 10 * PAYLOAD_XP_MAX_SIZE);
while (nbytes-- > 0) {
- const int16_t data = (uint8_t)_port->read();
- if (data < 0) {
+ uint8_t data;
+ if (!_port->read(data)) {
break;
}
- if (parse_byte_XP((uint8_t)data)) {
+ if (parse_byte_XP(data)) {
handle_packet_XP(message_in.packet);
}
} // while nbytes
diff --git a/libraries/AP_ADSB/AP_ADSB_Sagetech_MXS.cpp b/libraries/AP_ADSB/AP_ADSB_Sagetech_MXS.cpp
index 2cc0544b0285fd..3186a09f911bb4 100644
--- a/libraries/AP_ADSB/AP_ADSB_Sagetech_MXS.cpp
+++ b/libraries/AP_ADSB/AP_ADSB_Sagetech_MXS.cpp
@@ -78,11 +78,11 @@ void AP_ADSB_Sagetech_MXS::update()
// -----------------------------
uint32_t nbytes = MIN(_port->available(), 10 * PAYLOAD_MXS_MAX_SIZE);
while (nbytes-- > 0) {
- const int16_t data = _port->read();
- if (data < 0) {
+ uint8_t data;
+ if (!_port->read(data)) {
break;
}
- parse_byte((uint8_t)data);
+ parse_byte(data);
}
const uint32_t now_ms = AP_HAL::millis();
@@ -334,9 +334,10 @@ void AP_ADSB_Sagetech_MXS::auto_config_operating()
mxs_state.op.identOn = false;
- float vertRate;
- if (AP::ahrs().get_vert_pos_rate(vertRate)) {
- mxs_state.op.climbRate = vertRate * SAGETECH_SCALE_M_PER_SEC_TO_FT_PER_MIN;
+ float vertRateD;
+ if (AP::ahrs().get_vert_pos_rate_D(vertRateD)) {
+ // convert from down to up, and scale appropriately:
+ mxs_state.op.climbRate = -1 * vertRateD * SAGETECH_SCALE_M_PER_SEC_TO_FT_PER_MIN;
mxs_state.op.climbValid = true;
} else {
mxs_state.op.climbValid = false;
@@ -591,9 +592,9 @@ void AP_ADSB_Sagetech_MXS::send_operating_msg()
mxs_state.op.altitude = 0;
}
- float vertRate;
- if (AP::ahrs().get_vert_pos_rate(vertRate)) {
- mxs_state.op.climbRate = vertRate * SAGETECH_SCALE_M_PER_SEC_TO_FT_PER_MIN;
+ float vertRateD;
+ if (AP::ahrs().get_vert_pos_rate_D(vertRateD)) {
+ mxs_state.op.climbRate = -1 * vertRateD * SAGETECH_SCALE_M_PER_SEC_TO_FT_PER_MIN;
mxs_state.op.climbValid = true;
} else {
mxs_state.op.climbValid = false;
diff --git a/libraries/AP_ADSB/AP_ADSB_config.h b/libraries/AP_ADSB/AP_ADSB_config.h
index e686984286aee1..0f07f1b42f1b1a 100644
--- a/libraries/AP_ADSB/AP_ADSB_config.h
+++ b/libraries/AP_ADSB/AP_ADSB_config.h
@@ -4,7 +4,7 @@
#ifndef HAL_ADSB_ENABLED
-#define HAL_ADSB_ENABLED !HAL_MINIMIZE_FEATURES && BOARD_FLASH_SIZE > 1024
+#define HAL_ADSB_ENABLED BOARD_FLASH_SIZE > 1024
#endif
#ifndef HAL_ADSB_UAVIONIX_MAVLINK_ENABLED
diff --git a/libraries/AP_ADSB/AP_ADSB_uAvionix_MAVLink.cpp b/libraries/AP_ADSB/AP_ADSB_uAvionix_MAVLink.cpp
index 14a3b048082f4e..eeeec516bc0bf0 100644
--- a/libraries/AP_ADSB/AP_ADSB_uAvionix_MAVLink.cpp
+++ b/libraries/AP_ADSB/AP_ADSB_uAvionix_MAVLink.cpp
@@ -43,8 +43,8 @@ void AP_ADSB_uAvionix_MAVLink::update()
// send static configuration data to transceiver, every 5s
if (_frontend.out_state.chan_last_ms > 0 && now - _frontend.out_state.chan_last_ms > ADSB_CHAN_TIMEOUT_MS) {
// haven't gotten a heartbeat health status packet in a while, assume hardware failure
- // TODO: reset out_state.chan
_frontend.out_state.chan = -1;
+ _frontend.out_state.chan_last_ms = 0; // if the time isn't reset we spam the message
gcs().send_text(MAV_SEVERITY_ERROR, "ADSB: Transceiver heartbeat timed out");
} else if (_frontend.out_state.chan >= 0 && !_frontend._my_loc.is_zero() && _frontend.out_state.chan < MAVLINK_COMM_NUM_BUFFERS) {
const mavlink_channel_t chan = (mavlink_channel_t)(MAVLINK_COMM_0 + _frontend.out_state.chan);
diff --git a/libraries/AP_ADSB/AP_ADSB_uAvionix_UCP.cpp b/libraries/AP_ADSB/AP_ADSB_uAvionix_UCP.cpp
index 0547bb85d11fd7..b4cae2a3d270b8 100644
--- a/libraries/AP_ADSB/AP_ADSB_uAvionix_UCP.cpp
+++ b/libraries/AP_ADSB/AP_ADSB_uAvionix_UCP.cpp
@@ -76,12 +76,11 @@ void AP_ADSB_uAvionix_UCP::update()
// -----------------------------
uint32_t nbytes = MIN(_port->available(), 10UL * GDL90_RX_MAX_PACKET_LENGTH);
while (nbytes-- > 0) {
- const int16_t data = (uint8_t)_port->read();
- if (data < 0) {
+ uint8_t data;
+ if (!_port->read(data)) {
break;
}
-
- if (parseByte((uint8_t)data, rx.msg, rx.status)) {
+ if (parseByte(data, rx.msg, rx.status)) {
rx.last_msg_ms = now_ms;
handle_msg(rx.msg);
}
diff --git a/libraries/AP_AHRS/AP_AHRS.cpp b/libraries/AP_AHRS/AP_AHRS.cpp
index 32623cfe62f1f4..99291d4251b4a5 100644
--- a/libraries/AP_AHRS/AP_AHRS.cpp
+++ b/libraries/AP_AHRS/AP_AHRS.cpp
@@ -235,6 +235,9 @@ void AP_AHRS::init()
// init backends
dcm.init();
+#if HAL_EXTERNAL_AHRS_ENABLED
+ external.init();
+#endif
#if !APM_BUILD_TYPE(APM_BUILD_AP_Periph)
// convert to new custom rotaton
@@ -296,6 +299,9 @@ void AP_AHRS::reset_gyro_drift(void)
// update DCM
dcm.reset_gyro_drift();
+#if HAL_EXTERNAL_AHRS_ENABLED
+ external.reset_gyro_drift();
+#endif
// reset the EKF gyro bias states
#if HAL_NAVEKF2_AVAILABLE
@@ -386,6 +392,7 @@ void AP_AHRS::update(bool skip_ins_update)
// update AOA and SSA
update_AOA_SSA();
+#if HAL_GCS_ENABLED
EKFType active = active_EKF_type();
if (active != last_active_ekf_type) {
last_active_ekf_type = active;
@@ -417,6 +424,7 @@ void AP_AHRS::update(bool skip_ins_update)
}
GCS_SEND_TEXT(MAV_SEVERITY_INFO, "AHRS: %s active", shortname);
}
+#endif // HAL_GCS_ENABLED
#if CONFIG_HAL_BOARD == HAL_BOARD_SITL
/*
@@ -623,26 +631,11 @@ void AP_AHRS::update_EKF3(void)
#if HAL_EXTERNAL_AHRS_ENABLED
void AP_AHRS::update_external(void)
{
- AP::externalAHRS().update();
+ external.update();
+ external.get_results(external_estimates);
if (active_EKF_type() == EKFType::EXTERNAL) {
- Quaternion quat;
- if (!AP::externalAHRS().get_quaternion(quat)) {
- return;
- }
- quat.rotation_matrix(_dcm_matrix);
- _dcm_matrix = _dcm_matrix * get_rotation_vehicle_body_to_autopilot_body();
- _dcm_matrix.to_euler(&roll, &pitch, &yaw);
-
- update_cd_values();
- update_trig();
-
- _gyro_drift.zero();
-
- _gyro_estimate = AP::externalAHRS().get_gyro();
-
- Vector3f accel = AP::externalAHRS().get_accel();
- _accel_ef = _dcm_matrix * get_rotation_autopilot_body_to_vehicle_body() * accel;
+ copy_estimates_from_backend_estimates(external_estimates);
}
}
#endif // HAL_EXTERNAL_AHRS_ENABLED
@@ -657,6 +650,10 @@ void AP_AHRS::reset()
sim.reset();
#endif
+#if HAL_EXTERNAL_AHRS_ENABLED
+ external.reset();
+#endif
+
#if HAL_NAVEKF2_AVAILABLE
if (_ekf2_started) {
_ekf2_started = EKF2.InitialiseFilter();
@@ -699,7 +696,7 @@ bool AP_AHRS::get_location(Location &loc) const
#if HAL_EXTERNAL_AHRS_ENABLED
case EKFType::EXTERNAL: {
- return AP::externalAHRS().get_location(loc);
+ return external.get_location(loc);
}
#endif
}
@@ -747,7 +744,7 @@ bool AP_AHRS::wind_estimate(Vector3f &wind) const
#if HAL_EXTERNAL_AHRS_ENABLED
case EKFType::EXTERNAL:
- return false;
+ return external.wind_estimate(wind);
#endif
}
return false;
@@ -771,11 +768,11 @@ bool AP_AHRS::airspeed_sensor_enabled(void) const
if (fly_forward &&
hal.util->get_soft_armed() &&
get_filter_status(filter_status) &&
- filter_status.flags.rejecting_airspeed) {
+ (filter_status.flags.rejecting_airspeed && !filter_status.flags.dead_reckoning)) {
// special case for when backend is rejecting airspeed data in
- // an armed fly_forward state. Then the airspeed data is
- // highly suspect and will be rejected. We will use the
- // synthentic airspeed instead
+ // an armed fly_forward state and not dead reckoning. Then the
+ // airspeed data is highly suspect and will be rejected. We
+ // will use the synthentic airspeed instead
return false;
}
return true;
@@ -983,7 +980,6 @@ bool AP_AHRS::use_compass(void)
#if HAL_EXTERNAL_AHRS_ENABLED
case EKFType::EXTERNAL:
- // fall through
break;
#endif
}
@@ -1027,7 +1023,7 @@ bool AP_AHRS::get_quaternion(Quaternion &quat) const
#if HAL_EXTERNAL_AHRS_ENABLED
case EKFType::EXTERNAL:
// we assume the external AHRS isn't trimmed with the autopilot!
- return AP::externalAHRS().get_quaternion(quat);
+ return external.get_quaternion(quat);
#endif
}
@@ -1076,11 +1072,9 @@ bool AP_AHRS::get_secondary_attitude(Vector3f &eulers) const
#if HAL_EXTERNAL_AHRS_ENABLED
case EKFType::EXTERNAL: {
// External is secondary
- Quaternion quat;
- if (!AP::externalAHRS().get_quaternion(quat)) {
- return false;
- }
- quat.to_euler(eulers.x, eulers.y, eulers.z);
+ eulers[0] = external_estimates.roll_rad;
+ eulers[1] = external_estimates.pitch_rad;
+ eulers[2] = external_estimates.yaw_rad;
return true;
}
#endif
@@ -1137,7 +1131,7 @@ bool AP_AHRS::get_secondary_quaternion(Quaternion &quat) const
#if HAL_EXTERNAL_AHRS_ENABLED
case EKFType::EXTERNAL:
// External is secondary
- return AP::externalAHRS().get_quaternion(quat);
+ return external.get_quaternion(quat);
#endif
}
@@ -1184,7 +1178,7 @@ bool AP_AHRS::get_secondary_position(Location &loc) const
#if HAL_EXTERNAL_AHRS_ENABLED
case EKFType::EXTERNAL:
// External is secondary
- return AP::externalAHRS().get_location(loc);
+ return external.get_location(loc);
#endif
}
@@ -1219,7 +1213,7 @@ Vector2f AP_AHRS::groundspeed_vector(void)
#endif
#if HAL_EXTERNAL_AHRS_ENABLED
case EKFType::EXTERNAL: {
- return AP::externalAHRS().get_groundspeed_vector();
+ return external.groundspeed_vector();
}
#endif
}
@@ -1295,6 +1289,16 @@ bool AP_AHRS::set_origin(const Location &loc)
return false;
}
+#if AP_AHRS_POSITION_RESET_ENABLED
+bool AP_AHRS::handle_external_position_estimate(const Location &loc, float pos_accuracy, uint32_t timestamp_ms)
+{
+#if HAL_NAVEKF3_AVAILABLE
+ return EKF3.setLatLng(loc, pos_accuracy, timestamp_ms);
+#endif
+ return false;
+}
+#endif
+
// return true if inertial navigation is active
bool AP_AHRS::have_inertial_nav(void) const
{
@@ -1327,7 +1331,7 @@ bool AP_AHRS::get_velocity_NED(Vector3f &vec) const
#endif
#if HAL_EXTERNAL_AHRS_ENABLED
case EKFType::EXTERNAL:
- return AP::externalAHRS().get_velocity_NED(vec);
+ return external.get_velocity_NED(vec);
#endif
}
return dcm.get_velocity_NED(vec);
@@ -1398,11 +1402,11 @@ bool AP_AHRS::get_mag_field_correction(Vector3f &vec) const
// Get a derivative of the vertical position which is kinematically consistent with the vertical position is required by some control loops.
// This is different to the vertical velocity from the EKF which is not always consistent with the verical position due to the various errors that are being corrected for.
-bool AP_AHRS::get_vert_pos_rate(float &velocity) const
+bool AP_AHRS::get_vert_pos_rate_D(float &velocity) const
{
switch (active_EKF_type()) {
case EKFType::NONE:
- return dcm.get_vert_pos_rate(velocity);
+ return dcm.get_vert_pos_rate_D(velocity);
#if HAL_NAVEKF2_AVAILABLE
case EKFType::TWO:
@@ -1418,11 +1422,11 @@ bool AP_AHRS::get_vert_pos_rate(float &velocity) const
#if AP_AHRS_SIM_ENABLED
case EKFType::SIM:
- return sim.get_vert_pos_rate(velocity);
+ return sim.get_vert_pos_rate_D(velocity);
#endif
#if HAL_EXTERNAL_AHRS_ENABLED
case EKFType::EXTERNAL:
- return AP::externalAHRS().get_speed_down(velocity);
+ return external.get_vert_pos_rate_D(velocity);
#endif
}
// since there is no default case above, this is unreachable
@@ -1460,8 +1464,9 @@ bool AP_AHRS::get_hagl(float &height) const
return false;
}
-// return a relative ground position to the origin in meters
-// North/East/Down order.
+/*
+ return a relative NED position from the origin in meters
+*/
bool AP_AHRS::get_relative_position_NED_origin(Vector3f &vec) const
{
switch (active_EKF_type()) {
@@ -1504,16 +1509,7 @@ bool AP_AHRS::get_relative_position_NED_origin(Vector3f &vec) const
#endif
#if HAL_EXTERNAL_AHRS_ENABLED
case EKFType::EXTERNAL: {
- auto &extahrs = AP::externalAHRS();
- Location loc, orgn;
- if (extahrs.get_origin(orgn) &&
- extahrs.get_location(loc)) {
- const Vector2f diff2d = orgn.get_distance_NE(loc);
- vec = Vector3f(diff2d.x, diff2d.y,
- -(loc.alt - orgn.alt)*0.01);
- return true;
- }
- return false;
+ return external.get_relative_position_NED_origin(vec);
}
#endif
}
@@ -1521,27 +1517,23 @@ bool AP_AHRS::get_relative_position_NED_origin(Vector3f &vec) const
return false;
}
-// return a relative ground position to the home in meters
-// North/East/Down order.
+/*
+ return a relative ground position from home in meters
+*/
bool AP_AHRS::get_relative_position_NED_home(Vector3f &vec) const
{
- Location originLLH;
- Vector3f originNED;
- if (!get_relative_position_NED_origin(originNED) ||
- !get_origin(originLLH)) {
+ Location loc;
+ if (!_home_is_set ||
+ !get_location(loc)) {
return false;
}
-
- const Vector3f offset = originLLH.get_distance_NED(_home);
-
- vec.x = originNED.x - offset.x;
- vec.y = originNED.y - offset.y;
- vec.z = originNED.z - offset.z;
+ vec = _home.get_distance_NED(loc);
return true;
}
-// write a relative ground position estimate to the origin in meters, North/East order
-// return true if estimate is valid
+/*
+ return a relative position estimate from the origin in meters
+*/
bool AP_AHRS::get_relative_position_NE_origin(Vector2f &posNE) const
{
switch (active_EKF_type()) {
@@ -1568,44 +1560,35 @@ bool AP_AHRS::get_relative_position_NE_origin(Vector2f &posNE) const
}
#endif
#if HAL_EXTERNAL_AHRS_ENABLED
- case EKFType::EXTERNAL: {
- Location loc, orgn;
- if (!get_location(loc) ||
- !get_origin(orgn)) {
- return false;
- }
- posNE = orgn.get_distance_NE(loc);
- return true;
- }
+ case EKFType::EXTERNAL:
+ return external.get_relative_position_NE_origin(posNE);
#endif
}
// since there is no default case above, this is unreachable
return false;
}
-// return a relative ground position to the home in meters
-// North/East order.
+/*
+ return a relative ground position from home in meters North/East
+*/
bool AP_AHRS::get_relative_position_NE_home(Vector2f &posNE) const
{
- Location originLLH;
- Vector2f originNE;
- if (!get_relative_position_NE_origin(originNE) ||
- !get_origin(originLLH)) {
+ Location loc;
+ if (!_home_is_set ||
+ !get_location(loc)) {
return false;
}
- const Vector2f offset = originLLH.get_distance_NE(_home);
-
- posNE.x = originNE.x - offset.x;
- posNE.y = originNE.y - offset.y;
+ posNE = _home.get_distance_NE(loc);
return true;
}
// write a relative ground position estimate to the origin in meters, North/East order
-// write a relative ground position to the origin in meters, Down
-// return true if the estimate is valid
+/*
+ return a relative ground position from the origin in meters, down
+*/
bool AP_AHRS::get_relative_position_D_origin(float &posD) const
{
switch (active_EKF_type()) {
@@ -1631,23 +1614,17 @@ bool AP_AHRS::get_relative_position_D_origin(float &posD) const
return sim.get_relative_position_D_origin(posD);
#endif
#if HAL_EXTERNAL_AHRS_ENABLED
- case EKFType::EXTERNAL: {
- Location orgn, loc;
- if (!get_origin(orgn) ||
- !get_location(loc)) {
- return false;
- }
- posD = -(loc.alt - orgn.alt)*0.01;
- return true;
- }
+ case EKFType::EXTERNAL:
+ return external.get_relative_position_D_origin(posD);
#endif
}
// since there is no default case above, this is unreachable
return false;
}
-// write a relative ground position to home in meters, Down
-// will use the barometer if the EKF isn't available
+/*
+ return relative position from home in meters
+*/
void AP_AHRS::get_relative_position_D_home(float &posD) const
{
if (!_home_is_set) {
@@ -1959,7 +1936,7 @@ bool AP_AHRS::healthy(void) const
#endif
#if HAL_EXTERNAL_AHRS_ENABLED
case EKFType::EXTERNAL:
- return AP::externalAHRS().healthy();
+ return external.healthy();
#endif
}
@@ -2008,7 +1985,7 @@ bool AP_AHRS::pre_arm_check(bool requires_position, char *failure_msg, uint8_t f
#if HAL_EXTERNAL_AHRS_ENABLED
case EKFType::EXTERNAL:
- return ret;
+ return external.pre_arm_check(requires_position, failure_msg, failure_msg_len);
#endif
#if HAL_NAVEKF2_AVAILABLE
@@ -2060,7 +2037,7 @@ bool AP_AHRS::initialised(void) const
#endif
#if HAL_EXTERNAL_AHRS_ENABLED
case EKFType::EXTERNAL:
- return AP::externalAHRS().initialised();
+ return external.initialised();
#endif
}
return false;
@@ -2091,8 +2068,7 @@ bool AP_AHRS::get_filter_status(nav_filter_status &status) const
#endif
#if HAL_EXTERNAL_AHRS_ENABLED
case EKFType::EXTERNAL:
- AP::externalAHRS().get_filter_status(status);
- return true;
+ return external.get_filter_status(status);
#endif
}
@@ -2279,6 +2255,11 @@ void AP_AHRS::getCorrectedDeltaVelocityNED(Vector3f& ret, float& dt) const
ret.z += GRAVITY_MSS*dt;
}
+void AP_AHRS::set_failure_inconsistent_message(const char *estimator, const char *axis, float diff_rad, char *failure_msg, const uint8_t failure_msg_len) const
+{
+ hal.util->snprintf(failure_msg, failure_msg_len, "%s %s inconsistent %d deg. Wait or reboot", estimator, axis, (int)degrees(diff_rad));
+}
+
// check all cores providing consistent attitudes for prearm checks
bool AP_AHRS::attitudes_consistent(char *failure_msg, const uint8_t failure_msg_len) const
{
@@ -2299,7 +2280,7 @@ bool AP_AHRS::attitudes_consistent(char *failure_msg, const uint8_t failure_msg_
// check roll and pitch difference
const float rp_diff_rad = primary_quat.roll_pitch_difference(ekf2_quat);
if (rp_diff_rad > ATTITUDE_CHECK_THRESH_ROLL_PITCH_RAD) {
- hal.util->snprintf(failure_msg, failure_msg_len, "EKF2 Roll/Pitch inconsistent by %d deg", (int)degrees(rp_diff_rad));
+ set_failure_inconsistent_message("EKF2", "Roll/Pitch", rp_diff_rad, failure_msg, failure_msg_len);
return false;
}
@@ -2308,7 +2289,7 @@ bool AP_AHRS::attitudes_consistent(char *failure_msg, const uint8_t failure_msg_
primary_quat.angular_difference(ekf2_quat).to_axis_angle(angle_diff);
const float yaw_diff = fabsf(angle_diff.z);
if (check_yaw && (yaw_diff > ATTITUDE_CHECK_THRESH_YAW_RAD)) {
- hal.util->snprintf(failure_msg, failure_msg_len, "EKF2 Yaw inconsistent by %d deg", (int)degrees(yaw_diff));
+ set_failure_inconsistent_message("EKF2", "Yaw", yaw_diff, failure_msg, failure_msg_len);
return false;
}
}
@@ -2326,7 +2307,7 @@ bool AP_AHRS::attitudes_consistent(char *failure_msg, const uint8_t failure_msg_
// check roll and pitch difference
const float rp_diff_rad = primary_quat.roll_pitch_difference(ekf3_quat);
if (rp_diff_rad > ATTITUDE_CHECK_THRESH_ROLL_PITCH_RAD) {
- hal.util->snprintf(failure_msg, failure_msg_len, "EKF3 Roll/Pitch inconsistent by %d deg", (int)degrees(rp_diff_rad));
+ set_failure_inconsistent_message("EKF3", "Roll/Pitch", rp_diff_rad, failure_msg, failure_msg_len);
return false;
}
@@ -2335,7 +2316,7 @@ bool AP_AHRS::attitudes_consistent(char *failure_msg, const uint8_t failure_msg_
primary_quat.angular_difference(ekf3_quat).to_axis_angle(angle_diff);
const float yaw_diff = fabsf(angle_diff.z);
if (check_yaw && (yaw_diff > ATTITUDE_CHECK_THRESH_YAW_RAD)) {
- hal.util->snprintf(failure_msg, failure_msg_len, "EKF3 Yaw inconsistent by %d deg", (int)degrees(yaw_diff));
+ set_failure_inconsistent_message("EKF3", "Yaw", yaw_diff, failure_msg, failure_msg_len);
return false;
}
}
@@ -2351,7 +2332,7 @@ bool AP_AHRS::attitudes_consistent(char *failure_msg, const uint8_t failure_msg_
// check roll and pitch difference
const float rp_diff_rad = primary_quat.roll_pitch_difference(dcm_quat);
if (rp_diff_rad > ATTITUDE_CHECK_THRESH_ROLL_PITCH_RAD) {
- hal.util->snprintf(failure_msg, failure_msg_len, "DCM Roll/Pitch inconsistent by %d deg", (int)degrees(rp_diff_rad));
+ set_failure_inconsistent_message("DCM", "Roll/Pitch", rp_diff_rad, failure_msg, failure_msg_len);
return false;
}
@@ -2366,7 +2347,7 @@ bool AP_AHRS::attitudes_consistent(char *failure_msg, const uint8_t failure_msg_
primary_quat.angular_difference(dcm_quat).to_axis_angle(angle_diff);
const float yaw_diff = fabsf(angle_diff.z);
if (check_yaw && (yaw_diff > ATTITUDE_CHECK_THRESH_YAW_RAD)) {
- hal.util->snprintf(failure_msg, failure_msg_len, "DCM Yaw inconsistent by %d deg", (int)degrees(yaw_diff));
+ set_failure_inconsistent_message("DCM", "Yaw", yaw_diff, failure_msg, failure_msg_len);
return false;
}
}
@@ -2400,7 +2381,7 @@ uint32_t AP_AHRS::getLastYawResetAngle(float &yawAng)
#endif
#if HAL_EXTERNAL_AHRS_ENABLED
case EKFType::EXTERNAL:
- return 0;
+ return external.getLastYawResetAngle(yawAng);
#endif
}
return 0;
@@ -2565,7 +2546,7 @@ void AP_AHRS::send_ekf_status_report(GCS_MAVLINK &link) const
#if HAL_EXTERNAL_AHRS_ENABLED
case EKFType::EXTERNAL: {
- AP::externalAHRS().send_status_report(link);
+ external.send_ekf_status_report(link);
break;
}
#endif
@@ -2606,7 +2587,7 @@ bool AP_AHRS::get_origin(EKFType type, Location &ret) const
#endif
#if HAL_EXTERNAL_AHRS_ENABLED
case EKFType::EXTERNAL:
- return AP::externalAHRS().get_origin(ret);
+ return external.get_origin(ret);
#endif
}
return false;
diff --git a/libraries/AP_AHRS/AP_AHRS.h b/libraries/AP_AHRS/AP_AHRS.h
index fc2fca819d8273..9baf68b13d9adf 100644
--- a/libraries/AP_AHRS/AP_AHRS.h
+++ b/libraries/AP_AHRS/AP_AHRS.h
@@ -31,6 +31,7 @@
#include "AP_AHRS_DCM.h"
#include "AP_AHRS_SIM.h"
+#include "AP_AHRS_External.h"
// forward declare view class
class AP_AHRS_View;
@@ -193,31 +194,44 @@ class AP_AHRS {
// from which to decide the origin on its own
bool set_origin(const Location &loc) WARN_IF_UNUSED;
+#if AP_AHRS_POSITION_RESET_ENABLED
+ // Set the EKF's NE horizontal position states and their corresponding variances from the supplied WGS-84 location
+ // and 1-sigma horizontal position uncertainty. This can be used when the EKF is dead reckoning to periodically
+ // correct the position. If the EKF is is still using data from a postion sensor such as GPS, the position set
+ // will not be performed.
+ // pos_accuracy is the standard deviation of the horizontal position uncertainty in metres.
+ // The altitude element of the location is not used.
+ // Returns true if the set was successful.
+ bool handle_external_position_estimate(const Location &loc, float pos_accuracy, uint32_t timestamp_);
+#endif
+
// returns the inertial navigation origin in lat/lon/alt
bool get_origin(Location &ret) const WARN_IF_UNUSED;
bool have_inertial_nav() const;
+ // return a ground velocity in meters/second, North/East/Down
+ // order. Must only be called if have_inertial_nav() is true
bool get_velocity_NED(Vector3f &vec) const WARN_IF_UNUSED;
- // return the relative position NED to either home or origin
+ // return the relative position NED from either home or origin
// return true if the estimate is valid
bool get_relative_position_NED_home(Vector3f &vec) const WARN_IF_UNUSED;
bool get_relative_position_NED_origin(Vector3f &vec) const WARN_IF_UNUSED;
- // return the relative position NE to either home or origin
+ // return the relative position NE from home or origin
// return true if the estimate is valid
bool get_relative_position_NE_home(Vector2f &posNE) const WARN_IF_UNUSED;
bool get_relative_position_NE_origin(Vector2f &posNE) const WARN_IF_UNUSED;
- // return the relative position down to either home or origin
+ // return the relative position down from home or origin
// baro will be used for the _home relative one if the EKF isn't
void get_relative_position_D_home(float &posD) const;
bool get_relative_position_D_origin(float &posD) const WARN_IF_UNUSED;
// Get a derivative of the vertical position in m/s which is kinematically consistent with the vertical position is required by some control loops.
// This is different to the vertical velocity from the EKF which is not always consistent with the vertical position due to the various errors that are being corrected for.
- bool get_vert_pos_rate(float &velocity) const;
+ bool get_vert_pos_rate_D(float &velocity) const;
// write optical flow measurements to EKF
void writeOptFlowMeas(const uint8_t rawFlowQuality, const Vector2f &rawFlowRates, const Vector2f &rawGyroRates, const uint32_t msecFlowMeas, const Vector3f &posOffset, const float heightOverride);
@@ -658,6 +672,8 @@ class AP_AHRS {
// check all cores providing consistent attitudes for prearm checks
bool attitudes_consistent(char *failure_msg, const uint8_t failure_msg_len) const;
+ // convenience method for setting error string:
+ void set_failure_inconsistent_message(const char *estimator, const char *axis, float diff_rad, char *failure_msg, const uint8_t failure_msg_len) const;
/*
* Attitude-related private methods and attributes:
@@ -811,6 +827,11 @@ class AP_AHRS {
struct AP_AHRS_Backend::Estimates sim_estimates;
#endif
+#if HAL_EXTERNAL_AHRS_ENABLED
+ AP_AHRS_External external;
+ struct AP_AHRS_Backend::Estimates external_estimates;
+#endif
+
/*
* copy results from a backend over AP_AHRS canonical results.
* This updates member variables like roll and pitch, as well as
diff --git a/libraries/AP_AHRS/AP_AHRS_Backend.h b/libraries/AP_AHRS/AP_AHRS_Backend.h
index f5fe9c041bd6cc..6675a9c288dd5e 100644
--- a/libraries/AP_AHRS/AP_AHRS_Backend.h
+++ b/libraries/AP_AHRS/AP_AHRS_Backend.h
@@ -111,7 +111,7 @@ class AP_AHRS_Backend
// get our current position estimate. Return true if a position is available,
// otherwise false. This call fills in lat, lng and alt
- virtual bool get_location(Location &loc) const WARN_IF_UNUSED = 0;
+ virtual bool get_location(class Location &loc) const WARN_IF_UNUSED = 0;
// get latest altitude estimate above ground level in meters and validity flag
virtual bool get_hagl(float &height) const WARN_IF_UNUSED { return false; }
@@ -177,7 +177,7 @@ class AP_AHRS_Backend
// Get a derivative of the vertical position in m/s which is kinematically consistent with the vertical position is required by some control loops.
// This is different to the vertical velocity from the EKF which is not always consistent with the vertical position due to the various errors that are being corrected for.
- virtual bool get_vert_pos_rate(float &velocity) const = 0;
+ virtual bool get_vert_pos_rate_D(float &velocity) const = 0;
// returns the estimated magnetic field offsets in body frame
virtual bool get_mag_field_correction(Vector3f &ret) const WARN_IF_UNUSED {
@@ -284,7 +284,7 @@ class AP_AHRS_Backend
return false;
}
- virtual bool get_filter_status(nav_filter_status &status) const {
+ virtual bool get_filter_status(union nav_filter_status &status) const {
return false;
}
diff --git a/libraries/AP_AHRS/AP_AHRS_DCM.cpp b/libraries/AP_AHRS/AP_AHRS_DCM.cpp
index 5e053688ee2ffc..f2d4ce4c72b86e 100644
--- a/libraries/AP_AHRS/AP_AHRS_DCM.cpp
+++ b/libraries/AP_AHRS/AP_AHRS_DCM.cpp
@@ -62,7 +62,7 @@ void AP_AHRS::load_watchdog_home()
_home.set_alt_cm(pd.home_alt_cm, Location::AltFrame::ABSOLUTE);
_home_is_set = true;
_home_locked = true;
- gcs().send_text(MAV_SEVERITY_INFO, "Restored watchdog home");
+ GCS_SEND_TEXT(MAV_SEVERITY_INFO, "Restored watchdog home");
}
}
@@ -185,7 +185,7 @@ AP_AHRS_DCM::reset(bool recover_eulers)
pitch = pd.pitch_rad;
yaw = pd.yaw_rad;
_dcm_matrix.from_euler(roll, pitch, yaw);
- gcs().send_text(MAV_SEVERITY_INFO, "Restored watchdog attitude %.0f %.0f %.0f",
+ GCS_SEND_TEXT(MAV_SEVERITY_INFO, "Restored watchdog attitude %.0f %.0f %.0f",
degrees(roll), degrees(pitch), degrees(yaw));
} else if (recover_eulers && !isnan(roll) && !isnan(pitch) && !isnan(yaw)) {
_dcm_matrix.from_euler(roll, pitch, yaw);
@@ -485,10 +485,12 @@ AP_AHRS_DCM::drift_correction_yaw(void)
Compass &compass = AP::compass();
+#if COMPASS_CAL_ENABLED
if (compass.is_calibrating()) {
// don't do any yaw correction while calibrating
return;
}
+#endif
if (AP_AHRS_DCM::use_compass()) {
/*
@@ -1147,9 +1149,11 @@ bool AP_AHRS::set_home(const Location &loc)
Log_Write_Home_And_Origin();
+#if HAL_GCS_ENABLED
// send new home and ekf origin to GCS
gcs().send_message(MSG_HOME);
gcs().send_message(MSG_ORIGIN);
+#endif
AP_HAL::Util::PersistentData &pd = hal.util->persistent_data;
pd.home_lat = loc.lat;
@@ -1183,7 +1187,7 @@ bool AP_AHRS_DCM::get_velocity_NED(Vector3f &vec) const
// Get a derivative of the vertical position in m/s which is kinematically consistent with the vertical position is required by some control loops.
// This is different to the vertical velocity from the EKF which is not always consistent with the vertical position due to the various errors that are being corrected for.
-bool AP_AHRS_DCM::get_vert_pos_rate(float &velocity) const
+bool AP_AHRS_DCM::get_vert_pos_rate_D(float &velocity) const
{
Vector3f velned;
if (!get_velocity_NED(velned)) {
diff --git a/libraries/AP_AHRS/AP_AHRS_DCM.h b/libraries/AP_AHRS/AP_AHRS_DCM.h
index 800e7b681cb90d..168cbbaa3362fd 100644
--- a/libraries/AP_AHRS/AP_AHRS_DCM.h
+++ b/libraries/AP_AHRS/AP_AHRS_DCM.h
@@ -111,7 +111,7 @@ class AP_AHRS_DCM : public AP_AHRS_Backend {
// Get a derivative of the vertical position in m/s which is kinematically consistent with the vertical position is required by some control loops.
// This is different to the vertical velocity from the EKF which is not always consistent with the vertical position due to the various errors that are being corrected for.
- bool get_vert_pos_rate(float &velocity) const override;
+ bool get_vert_pos_rate_D(float &velocity) const override;
// returns false if we fail arming checks, in which case the buffer will be populated with a failure message
// requires_position should be true if horizontal position configuration should be checked (not used)
diff --git a/libraries/AP_AHRS/AP_AHRS_External.cpp b/libraries/AP_AHRS/AP_AHRS_External.cpp
new file mode 100644
index 00000000000000..0c1a01b2c7bbc9
--- /dev/null
+++ b/libraries/AP_AHRS/AP_AHRS_External.cpp
@@ -0,0 +1,136 @@
+#include "AP_AHRS_External.h"
+
+#if HAL_EXTERNAL_AHRS_ENABLED
+
+#include
+#include
+
+// true if the AHRS has completed initialisation
+bool AP_AHRS_External::initialised(void) const
+{
+ return AP::externalAHRS().initialised();
+}
+
+void AP_AHRS_External::update()
+{
+ AP::externalAHRS().update();
+}
+
+bool AP_AHRS_External::healthy() const {
+ return AP::externalAHRS().healthy();
+}
+
+void AP_AHRS_External::get_results(AP_AHRS_Backend::Estimates &results)
+{
+ Quaternion quat;
+ if (!AP::externalAHRS().get_quaternion(quat)) {
+ return;
+ }
+ quat.rotation_matrix(results.dcm_matrix);
+ results.dcm_matrix = results.dcm_matrix * AP::ahrs().get_rotation_vehicle_body_to_autopilot_body();
+ results.dcm_matrix.to_euler(&results.roll_rad, &results.pitch_rad, &results.yaw_rad);
+
+ results.gyro_drift.zero();
+ results.gyro_estimate = AP::externalAHRS().get_gyro();
+
+ const Vector3f accel = AP::externalAHRS().get_accel();
+ const Vector3f accel_ef = results.dcm_matrix * AP::ahrs().get_rotation_autopilot_body_to_vehicle_body() * accel;
+ results.accel_ef = accel_ef;
+}
+
+
+bool AP_AHRS_External::get_location(struct Location &loc) const
+{
+ return AP::externalAHRS().get_location(loc);
+}
+
+bool AP_AHRS_External::get_quaternion(Quaternion &quat) const
+{
+ return AP::externalAHRS().get_quaternion(quat);
+}
+
+Vector2f AP_AHRS_External::groundspeed_vector()
+{
+ return AP::externalAHRS().get_groundspeed_vector();
+}
+
+
+bool AP_AHRS_External::get_relative_position_NED_origin(Vector3f &vec) const
+{
+ auto &extahrs = AP::externalAHRS();
+ Location loc, orgn;
+ if (extahrs.get_origin(orgn) &&
+ extahrs.get_location(loc)) {
+ const Vector2f diff2d = orgn.get_distance_NE(loc);
+ vec = Vector3f(diff2d.x, diff2d.y,
+ -(loc.alt - orgn.alt)*0.01);
+ return true;
+ }
+ return false;
+}
+
+bool AP_AHRS_External::get_relative_position_NE_origin(Vector2f &posNE) const
+{
+ auto &extahrs = AP::externalAHRS();
+
+ Location loc, orgn;
+ if (!extahrs.get_location(loc) ||
+ !extahrs.get_origin(orgn)) {
+ return false;
+ }
+ posNE = orgn.get_distance_NE(loc);
+ return true;
+}
+
+bool AP_AHRS_External::get_relative_position_D_origin(float &posD) const
+{
+ auto &extahrs = AP::externalAHRS();
+
+ Location orgn, loc;
+ if (!extahrs.get_origin(orgn) ||
+ !extahrs.get_location(loc)) {
+ return false;
+ }
+ posD = -(loc.alt - orgn.alt)*0.01;
+ return true;
+}
+
+bool AP_AHRS_External::get_velocity_NED(Vector3f &vec) const
+{
+ return AP::externalAHRS().get_velocity_NED(vec);
+}
+
+bool AP_AHRS_External::get_vert_pos_rate_D(float &velocity) const
+{
+ return AP::externalAHRS().get_speed_down(velocity);
+}
+
+bool AP_AHRS_External::pre_arm_check(bool requires_position, char *failure_msg, uint8_t failure_msg_len) const
+{
+ return AP::externalAHRS().pre_arm_check(failure_msg, failure_msg_len);
+}
+
+bool AP_AHRS_External::get_filter_status(nav_filter_status &status) const
+{
+ AP::externalAHRS().get_filter_status(status);
+ return true;
+}
+
+void AP_AHRS_External::send_ekf_status_report(GCS_MAVLINK &link) const
+{
+ AP::externalAHRS().send_status_report(link);
+}
+
+bool AP_AHRS_External::get_origin(Location &ret) const
+{
+ return AP::externalAHRS().get_origin(ret);
+}
+
+void AP_AHRS_External::get_control_limits(float &ekfGndSpdLimit, float &ekfNavVelGainScaler) const
+{
+ // lower gains in VTOL controllers when flying on DCM
+ ekfGndSpdLimit = 50.0;
+ ekfNavVelGainScaler = 0.5;
+}
+
+#endif
diff --git a/libraries/AP_AHRS/AP_AHRS_External.h b/libraries/AP_AHRS/AP_AHRS_External.h
new file mode 100644
index 00000000000000..999ed05fed08be
--- /dev/null
+++ b/libraries/AP_AHRS/AP_AHRS_External.h
@@ -0,0 +1,93 @@
+#pragma once
+
+/*
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+ */
+
+/*
+ * External based AHRS (Attitude Heading Reference System) interface for
+ * ArduPilot
+ *
+ */
+
+#include "AP_AHRS_Backend.h"
+
+#if HAL_EXTERNAL_AHRS_ENABLED
+
+class AP_AHRS_External : public AP_AHRS_Backend {
+public:
+
+ using AP_AHRS_Backend::AP_AHRS_Backend;
+
+ /* Do not allow copies */
+ CLASS_NO_COPY(AP_AHRS_External);
+
+ // reset the current gyro drift estimate
+ // should be called if gyro offsets are recalculated
+ void reset_gyro_drift() override {}
+
+ // Methods
+ bool initialised() const override;
+ void update() override;
+ void get_results(Estimates &results) override;
+ void reset() override {}
+
+ // dead-reckoning support
+ virtual bool get_location(struct Location &loc) const override;
+
+ // return a wind estimation vector, in m/s
+ bool wind_estimate(Vector3f &ret) const override {
+ return false;
+ }
+
+ // return a ground vector estimate in meters/second, in North/East order
+ Vector2f groundspeed_vector() override;
+
+ bool use_compass() override {
+ // this is actually never called at the moment; we use dcm's
+ // return value.
+ return true;
+ }
+
+ // return the quaternion defining the rotation from NED to XYZ (body) axes
+ bool get_quaternion(Quaternion &quat) const override WARN_IF_UNUSED;
+
+ void estimate_wind(void);
+
+ // is the AHRS subsystem healthy?
+ bool healthy() const override;
+
+ bool get_velocity_NED(Vector3f &vec) const override;
+
+ // Get a derivative of the vertical position in m/s which is kinematically consistent with the vertical position is required by some control loops.
+ // This is different to the vertical velocity from the EKF which is not always consistent with the vertical position due to the various errors that are being corrected for.
+ bool get_vert_pos_rate_D(float &velocity) const override;
+
+ // returns false if we fail arming checks, in which case the buffer will be populated with a failure message
+ // requires_position should be true if horizontal position configuration should be checked (not used)
+ bool pre_arm_check(bool requires_position, char *failure_msg, uint8_t failure_msg_len) const override;
+
+ // relative-origin functions for fallback in AP_InertialNav
+ bool get_origin(Location &ret) const override;
+ bool get_relative_position_NED_origin(Vector3f &vec) const override;
+ bool get_relative_position_NE_origin(Vector2f &posNE) const override;
+ bool get_relative_position_D_origin(float &posD) const override;
+
+ bool get_filter_status(nav_filter_status &status) const override;
+ void send_ekf_status_report(class GCS_MAVLINK &link) const override;
+
+ void get_control_limits(float &ekfGndSpdLimit, float &controlScaleXY) const override;
+};
+
+#endif
diff --git a/libraries/AP_AHRS/AP_AHRS_SIM.cpp b/libraries/AP_AHRS/AP_AHRS_SIM.cpp
index 0714d15435bf48..3d191da7855cdb 100644
--- a/libraries/AP_AHRS/AP_AHRS_SIM.cpp
+++ b/libraries/AP_AHRS/AP_AHRS_SIM.cpp
@@ -80,7 +80,7 @@ Vector2f AP_AHRS_SIM::groundspeed_vector(void)
return Vector2f(fdm.speedN, fdm.speedE);
}
-bool AP_AHRS_SIM::get_vert_pos_rate(float &velocity) const
+bool AP_AHRS_SIM::get_vert_pos_rate_D(float &velocity) const
{
if (_sitl == nullptr) {
return false;
@@ -181,6 +181,7 @@ bool AP_AHRS_SIM::get_mag_offsets(uint8_t mag_idx, Vector3f &magOffsets) const
void AP_AHRS_SIM::send_ekf_status_report(GCS_MAVLINK &link) const
{
+#if HAL_GCS_ENABLED
// send status report with everything looking good
const uint16_t flags =
EKF_ATTITUDE | /* Set if EKF's attitude estimate is good. | */
@@ -194,6 +195,7 @@ void AP_AHRS_SIM::send_ekf_status_report(GCS_MAVLINK &link) const
EKF_PRED_POS_HORIZ_REL | /* Set if EKF's predicted horizontal position (relative) estimate is good. | */
EKF_PRED_POS_HORIZ_ABS; /* Set if EKF's predicted horizontal position (absolute) estimate is good. | */
mavlink_msg_ekf_status_report_send(link.get_chan(), flags, 0, 0, 0, 0, 0, 0);
+#endif // HAL_GCS_ENABLED
}
bool AP_AHRS_SIM::get_origin(Location &ret) const
diff --git a/libraries/AP_AHRS/AP_AHRS_SIM.h b/libraries/AP_AHRS/AP_AHRS_SIM.h
index 3caf1051b0a816..340a8877b6f336 100644
--- a/libraries/AP_AHRS/AP_AHRS_SIM.h
+++ b/libraries/AP_AHRS/AP_AHRS_SIM.h
@@ -92,7 +92,7 @@ class AP_AHRS_SIM : public AP_AHRS_Backend {
// Get a derivative of the vertical position in m/s which is kinematically consistent with the vertical position is required by some control loops.
// This is different to the vertical velocity from the EKF which is not always consistent with the vertical position due to the various errors that are being corrected for.
- bool get_vert_pos_rate(float &velocity) const override;
+ bool get_vert_pos_rate_D(float &velocity) const override;
// returns false if we fail arming checks, in which case the buffer will be populated with a failure message
// requires_position should be true if horizontal position configuration should be checked (not used)
diff --git a/libraries/AP_AHRS/AP_AHRS_config.h b/libraries/AP_AHRS/AP_AHRS_config.h
index e600487d1d61f5..9d35d8a9ef0f35 100644
--- a/libraries/AP_AHRS/AP_AHRS_config.h
+++ b/libraries/AP_AHRS/AP_AHRS_config.h
@@ -2,6 +2,10 @@
#include
+#ifndef AP_AHRS_ENABLED
+#define AP_AHRS_ENABLED 1
+#endif
+
#ifndef HAL_NAVEKF2_AVAILABLE
// only default to EK2 enabled on boards with over 1M flash
#define HAL_NAVEKF2_AVAILABLE (BOARD_FLASH_SIZE>1024)
@@ -14,3 +18,8 @@
#ifndef AP_AHRS_SIM_ENABLED
#define AP_AHRS_SIM_ENABLED AP_SIM_ENABLED
#endif
+
+#ifndef AP_AHRS_POSITION_RESET_ENABLED
+#define AP_AHRS_POSITION_RESET_ENABLED (BOARD_FLASH_SIZE>1024)
+#endif
+
diff --git a/libraries/AP_AccelCal/AP_AccelCal.h b/libraries/AP_AccelCal/AP_AccelCal.h
index 539a96f0727a6e..de6168ce62e042 100644
--- a/libraries/AP_AccelCal/AP_AccelCal.h
+++ b/libraries/AP_AccelCal/AP_AccelCal.h
@@ -5,7 +5,8 @@
#ifndef HAL_INS_ACCELCAL_ENABLED
#if HAL_GCS_ENABLED
-#define HAL_INS_ACCELCAL_ENABLED 1
+#include
+#define HAL_INS_ACCELCAL_ENABLED AP_INERTIALSENSOR_ENABLED
#else
#define HAL_INS_ACCELCAL_ENABLED 0
#endif
diff --git a/libraries/AP_Airspeed/AP_Airspeed.cpp b/libraries/AP_Airspeed/AP_Airspeed.cpp
index a3d97e30c05385..341aa7aac94407 100644
--- a/libraries/AP_Airspeed/AP_Airspeed.cpp
+++ b/libraries/AP_Airspeed/AP_Airspeed.cpp
@@ -16,6 +16,10 @@
* AP_Airspeed.cpp - airspeed (pitot) driver
*/
+#include "AP_Airspeed_config.h"
+
+#if AP_AIRSPEED_ENABLED
+
#include "AP_Airspeed.h"
#include
@@ -135,8 +139,8 @@ const AP_Param::GroupInfo AP_Airspeed::var_info[] = {
AP_GROUPINFO("_WIND_MAX", 22, AP_Airspeed, _wind_max, 0),
// @Param: _WIND_WARN
- // @DisplayName: Airspeed and ground speed difference that gives a warning
- // @Description: If the difference between airspeed and ground speed is greater than this value the sensor will issue a warning. If 0 ARSPD_WIND_MAX is used.
+ // @DisplayName: Airspeed and GPS speed difference that gives a warning
+ // @Description: If the difference between airspeed and GPS speed is greater than this value the sensor will issue a warning. If 0 ARSPD_WIND_MAX is used.
// @Description{Copter, Blimp, Rover, Sub}: This parameter and function is not used by this vehicle. Always set to 0.
// @Units: m/s
// @User: Advanced
@@ -144,7 +148,7 @@ const AP_Param::GroupInfo AP_Airspeed::var_info[] = {
// @Param: _WIND_GATE
// @DisplayName: Re-enable Consistency Check Gate Size
- // @Description: Number of standard deviations applied to the re-enable EKF consistency check that is used when ARSPD_OPTIONS bit position 3 is set. Larger values will make the re-enabling of the airspeed sensor faster, but increase the likelihood of re-enabling a degraded sensor. The value can be tuned by using the ARSP.TR log message by setting ARSP_WIND_GATE to a value that is higher than the value for ARSP.TR observed with a healthy airspeed sensor. Occasional transients in ARSP.TR above the value set by ARSP_WIND_GATE can be tolerated provided they are less than 5 seconds in duration and less than 10% duty cycle.
+ // @Description: Number of standard deviations applied to the re-enable EKF consistency check that is used when ARSPD_OPTIONS bit position 3 is set. Larger values will make the re-enabling of the airspeed sensor faster, but increase the likelihood of re-enabling a degraded sensor. The value can be tuned by using the ARSP.TR log message by setting ARSPD_WIND_GATE to a value that is higher than the value for ARSP.TR observed with a healthy airspeed sensor. Occasional transients in ARSP.TR above the value set by ARSPD_WIND_GATE can be tolerated provided they are less than 5 seconds in duration and less than 10% duty cycle.
// @Description{Copter, Blimp, Rover, Sub}: This parameter and function is not used by this vehicle.
// @Range: 0.0 10.0
// @User: Advanced
@@ -605,6 +609,14 @@ void AP_Airspeed::read(uint8_t i)
return;
}
+#ifndef HAL_BUILD_AP_PERIPH
+ /*
+ get the healthy state before we call get_pressure() as
+ get_pressure() overwrites the healthy state
+ */
+ bool prev_healthy = state[i].healthy;
+#endif
+
float raw_pressure = get_pressure(i);
float airspeed_pressure = raw_pressure - get_offset(i);
@@ -612,7 +624,6 @@ void AP_Airspeed::read(uint8_t i)
state[i].corrected_pressure = airspeed_pressure;
#ifndef HAL_BUILD_AP_PERIPH
- bool prev_healthy = state[i].healthy;
if (state[i].cal.start_ms != 0) {
update_calibration(i, raw_pressure);
}
@@ -921,3 +932,5 @@ AP_Airspeed *airspeed()
}
};
+
+#endif // AP_AIRSPEED_ENABLED
diff --git a/libraries/AP_Airspeed/AP_Airspeed.h b/libraries/AP_Airspeed/AP_Airspeed.h
index 9e8f938918b9ce..564d59981465e0 100644
--- a/libraries/AP_Airspeed/AP_Airspeed.h
+++ b/libraries/AP_Airspeed/AP_Airspeed.h
@@ -2,9 +2,15 @@
#include "AP_Airspeed_config.h"
+#if AP_AIRSPEED_ENABLED
+
#include
#include
+#if AP_AIRSPEED_MSP_ENABLED
+#include
+#endif
+
class AP_Airspeed_Backend;
class AP_Airspeed_Params {
@@ -328,3 +334,5 @@ class AP_Airspeed
namespace AP {
AP_Airspeed *airspeed();
};
+
+#endif // AP_AIRSPEED_ENABLED
diff --git a/libraries/AP_Airspeed/AP_Airspeed_ASP5033.h b/libraries/AP_Airspeed/AP_Airspeed_ASP5033.h
index 99c340ec5b83c5..91752656d8e814 100644
--- a/libraries/AP_Airspeed/AP_Airspeed_ASP5033.h
+++ b/libraries/AP_Airspeed/AP_Airspeed_ASP5033.h
@@ -14,11 +14,7 @@
*/
#pragma once
-#include
-
-#ifndef AP_AIRSPEED_ASP5033_ENABLED
-#define AP_AIRSPEED_ASP5033_ENABLED AP_AIRSPEED_BACKEND_DEFAULT_ENABLED
-#endif
+#include "AP_Airspeed_config.h"
#if AP_AIRSPEED_ASP5033_ENABLED
diff --git a/libraries/AP_Airspeed/AP_Airspeed_Backend.cpp b/libraries/AP_Airspeed/AP_Airspeed_Backend.cpp
index fbadf86f5f9347..412b337eeb65c6 100644
--- a/libraries/AP_Airspeed/AP_Airspeed_Backend.cpp
+++ b/libraries/AP_Airspeed/AP_Airspeed_Backend.cpp
@@ -17,6 +17,10 @@
backend driver class for airspeed
*/
+#include "AP_Airspeed_config.h"
+
+#if AP_AIRSPEED_ENABLED
+
#include
#include
#include "AP_Airspeed.h"
@@ -63,3 +67,5 @@ void AP_Airspeed_Backend::set_bus_id(uint32_t id)
{
frontend.param[instance].bus_id.set_and_save(int32_t(id));
}
+
+#endif // AP_AIRSPEED_ENABLED
diff --git a/libraries/AP_Airspeed/AP_Airspeed_Backend.h b/libraries/AP_Airspeed/AP_Airspeed_Backend.h
index a439483c4f0266..5836270bf49567 100644
--- a/libraries/AP_Airspeed/AP_Airspeed_Backend.h
+++ b/libraries/AP_Airspeed/AP_Airspeed_Backend.h
@@ -18,10 +18,15 @@
backend driver class for airspeed
*/
+#include "AP_Airspeed_config.h"
+
+#if AP_AIRSPEED_ENABLED
+
#include
#include
#include
#include "AP_Airspeed.h"
+#include
class AP_Airspeed_Backend {
public:
@@ -125,3 +130,5 @@ class AP_Airspeed_Backend {
AP_Airspeed &frontend;
uint8_t instance;
};
+
+#endif // AP_AIRSPEED_ENABLED
diff --git a/libraries/AP_Airspeed/AP_Airspeed_DLVR.h b/libraries/AP_Airspeed/AP_Airspeed_DLVR.h
index 2e8bd1a6b9c10f..695011286518f3 100644
--- a/libraries/AP_Airspeed/AP_Airspeed_DLVR.h
+++ b/libraries/AP_Airspeed/AP_Airspeed_DLVR.h
@@ -17,11 +17,7 @@
// backend driver for AllSensors DLVR differential airspeed sensor
// currently assumes a 5" of water, noise reduced, sensor
-#include
-
-#ifndef AP_AIRSPEED_DLVR_ENABLED
-#define AP_AIRSPEED_DLVR_ENABLED AP_AIRSPEED_BACKEND_DEFAULT_ENABLED
-#endif
+#include "AP_Airspeed_config.h"
#if AP_AIRSPEED_DLVR_ENABLED
diff --git a/libraries/AP_Airspeed/AP_Airspeed_DroneCAN.cpp b/libraries/AP_Airspeed/AP_Airspeed_DroneCAN.cpp
index 4b5db8bd0e1f42..fc143b11c00d70 100644
--- a/libraries/AP_Airspeed/AP_Airspeed_DroneCAN.cpp
+++ b/libraries/AP_Airspeed/AP_Airspeed_DroneCAN.cpp
@@ -148,7 +148,7 @@ bool AP_Airspeed_DroneCAN::get_differential_pressure(float &pressure)
{
WITH_SEMAPHORE(_sem_airspeed);
- if ((AP_HAL::millis() - _last_sample_time_ms) > 100) {
+ if ((AP_HAL::millis() - _last_sample_time_ms) > 250) {
return false;
}
diff --git a/libraries/AP_Airspeed/AP_Airspeed_DroneCAN.h b/libraries/AP_Airspeed/AP_Airspeed_DroneCAN.h
index cc2484d27d8284..2167f9f061521a 100644
--- a/libraries/AP_Airspeed/AP_Airspeed_DroneCAN.h
+++ b/libraries/AP_Airspeed/AP_Airspeed_DroneCAN.h
@@ -1,10 +1,6 @@
#pragma once
-#include
-
-#ifndef AP_AIRSPEED_DRONECAN_ENABLED
-#define AP_AIRSPEED_DRONECAN_ENABLED HAL_ENABLE_DRONECAN_DRIVERS
-#endif
+#include "AP_Airspeed_config.h"
#if AP_AIRSPEED_DRONECAN_ENABLED
@@ -32,7 +28,7 @@ class AP_Airspeed_DroneCAN : public AP_Airspeed_Backend {
static void subscribe_msgs(AP_DroneCAN* ap_dronecan);
- static AP_Airspeed_Backend* probe(AP_Airspeed &_fronted, uint8_t _instance, uint32_t previous_devid);
+ static AP_Airspeed_Backend* probe(AP_Airspeed &_frontend, uint8_t _instance, uint32_t previous_devid);
private:
diff --git a/libraries/AP_Airspeed/AP_Airspeed_Health.cpp b/libraries/AP_Airspeed/AP_Airspeed_Health.cpp
index 075a788dde52d5..feed1a507a7db3 100644
--- a/libraries/AP_Airspeed/AP_Airspeed_Health.cpp
+++ b/libraries/AP_Airspeed/AP_Airspeed_Health.cpp
@@ -1,3 +1,7 @@
+#include "AP_Airspeed_config.h"
+
+#if AP_AIRSPEED_ENABLED
+
#include "AP_Airspeed.h"
#include
@@ -64,8 +68,9 @@ void AP_Airspeed::check_sensor_ahrs_wind_max_failures(uint8_t i)
}
data_is_inconsistent = state[i].failures.test_ratio > gate_size;
}
-
- const float speed_diff = fabsf(state[i].airspeed-gps.ground_speed());
+
+ const auto gps_speed = gps.velocity().length();
+ const float speed_diff = fabsf(state[i].airspeed-gps_speed);
const bool data_is_implausible = is_positive(_wind_max) && speed_diff > _wind_max;
// update health_probability with LowPassFilter
if (data_is_implausible || data_is_inconsistent) {
@@ -119,3 +124,5 @@ void AP_Airspeed::check_sensor_ahrs_wind_max_failures(uint8_t i)
}
#endif // HAL_BUILD_AP_PERIPH
}
+
+#endif // AP_AIRSPEED_ENABLED
diff --git a/libraries/AP_Airspeed/AP_Airspeed_MS4525.h b/libraries/AP_Airspeed/AP_Airspeed_MS4525.h
index 70e30b127e0860..5c39474bca8050 100644
--- a/libraries/AP_Airspeed/AP_Airspeed_MS4525.h
+++ b/libraries/AP_Airspeed/AP_Airspeed_MS4525.h
@@ -14,11 +14,7 @@
*/
#pragma once
-#include
-
-#ifndef AP_AIRSPEED_MS4525_ENABLED
-#define AP_AIRSPEED_MS4525_ENABLED AP_AIRSPEED_BACKEND_DEFAULT_ENABLED
-#endif
+#include "AP_Airspeed_config.h"
#if AP_AIRSPEED_MS4525_ENABLED
diff --git a/libraries/AP_Airspeed/AP_Airspeed_MS5525.h b/libraries/AP_Airspeed/AP_Airspeed_MS5525.h
index 0bcb74a2d85e16..46e45e74c560fe 100644
--- a/libraries/AP_Airspeed/AP_Airspeed_MS5525.h
+++ b/libraries/AP_Airspeed/AP_Airspeed_MS5525.h
@@ -18,11 +18,7 @@
backend driver for airspeed from I2C
*/
-#include
-
-#ifndef AP_AIRSPEED_MS5525_ENABLED
-#define AP_AIRSPEED_MS5525_ENABLED AP_AIRSPEED_BACKEND_DEFAULT_ENABLED
-#endif
+#include "AP_Airspeed_config.h"
#if AP_AIRSPEED_MS5525_ENABLED
diff --git a/libraries/AP_Airspeed/AP_Airspeed_MSP.h b/libraries/AP_Airspeed/AP_Airspeed_MSP.h
index ac26878ee56875..343f3dc88f75ed 100644
--- a/libraries/AP_Airspeed/AP_Airspeed_MSP.h
+++ b/libraries/AP_Airspeed/AP_Airspeed_MSP.h
@@ -3,18 +3,14 @@
*/
#pragma once
-#include
-#include
-#include
-
-#ifndef AP_AIRSPEED_MSP_ENABLED
-#define AP_AIRSPEED_MSP_ENABLED HAL_MSP_SENSORS_ENABLED
-#endif
+#include "AP_Airspeed_config.h"
#if AP_AIRSPEED_MSP_ENABLED
#include "AP_Airspeed_Backend.h"
+#include
+
class AP_Airspeed_MSP : public AP_Airspeed_Backend
{
public:
diff --git a/libraries/AP_Airspeed/AP_Airspeed_NMEA.h b/libraries/AP_Airspeed/AP_Airspeed_NMEA.h
index 264f1c651dca0e..6246c5e03399c9 100644
--- a/libraries/AP_Airspeed/AP_Airspeed_NMEA.h
+++ b/libraries/AP_Airspeed/AP_Airspeed_NMEA.h
@@ -1,11 +1,6 @@
#pragma once
-#include
-
-// note additional vehicle restrictions are made in the .cpp file!
-#ifndef AP_AIRSPEED_NMEA_ENABLED
-#define AP_AIRSPEED_NMEA_ENABLED AP_AIRSPEED_BACKEND_DEFAULT_ENABLED
-#endif
+#include "AP_Airspeed_config.h"
#if AP_AIRSPEED_NMEA_ENABLED
diff --git a/libraries/AP_Airspeed/AP_Airspeed_Params.cpp b/libraries/AP_Airspeed/AP_Airspeed_Params.cpp
index 08f08999367572..37c6b69faa262c 100644
--- a/libraries/AP_Airspeed/AP_Airspeed_Params.cpp
+++ b/libraries/AP_Airspeed/AP_Airspeed_Params.cpp
@@ -14,6 +14,10 @@
along with this program. If not, see .
*/
+#include "AP_Airspeed_config.h"
+
+#if AP_AIRSPEED_ENABLED
+
#include "AP_Airspeed.h"
#include
@@ -138,3 +142,5 @@ AP_Airspeed_Params::AP_Airspeed_Params(void) {};
const AP_Param::GroupInfo AP_Airspeed_Params::var_info[] = { AP_GROUPEND };
#endif
+
+#endif // AP_AIRSPEED_ENABLED
diff --git a/libraries/AP_Airspeed/AP_Airspeed_SDP3X.h b/libraries/AP_Airspeed/AP_Airspeed_SDP3X.h
index 01b652f17fc3e9..57efcd45df7b9f 100644
--- a/libraries/AP_Airspeed/AP_Airspeed_SDP3X.h
+++ b/libraries/AP_Airspeed/AP_Airspeed_SDP3X.h
@@ -14,11 +14,7 @@
*/
#pragma once
-#include
-
-#ifndef AP_AIRSPEED_SDP3X_ENABLED
-#define AP_AIRSPEED_SDP3X_ENABLED AP_AIRSPEED_BACKEND_DEFAULT_ENABLED
-#endif
+#include "AP_Airspeed_config.h"
#if AP_AIRSPEED_SDP3X_ENABLED
diff --git a/libraries/AP_Airspeed/AP_Airspeed_SITL.h b/libraries/AP_Airspeed/AP_Airspeed_SITL.h
index 64f6da29997a16..0aac553cffb5ed 100644
--- a/libraries/AP_Airspeed/AP_Airspeed_SITL.h
+++ b/libraries/AP_Airspeed/AP_Airspeed_SITL.h
@@ -3,12 +3,7 @@
*/
#pragma once
-#include
-#include
-
-#ifndef AP_AIRSPEED_SITL_ENABLED
-#define AP_AIRSPEED_SITL_ENABLED AP_SIM_ENABLED
-#endif
+#include "AP_Airspeed_config.h"
#if AP_AIRSPEED_SITL_ENABLED
diff --git a/libraries/AP_Airspeed/AP_Airspeed_analog.h b/libraries/AP_Airspeed/AP_Airspeed_analog.h
index 94908436925501..11f8cfb7b643dc 100644
--- a/libraries/AP_Airspeed/AP_Airspeed_analog.h
+++ b/libraries/AP_Airspeed/AP_Airspeed_analog.h
@@ -1,10 +1,6 @@
#pragma once
-#include
-
-#ifndef AP_AIRSPEED_ANALOG_ENABLED
-#define AP_AIRSPEED_ANALOG_ENABLED AP_AIRSPEED_BACKEND_DEFAULT_ENABLED
-#endif
+#include "AP_Airspeed_config.h"
#if AP_AIRSPEED_ANALOG_ENABLED
diff --git a/libraries/AP_Airspeed/AP_Airspeed_config.h b/libraries/AP_Airspeed/AP_Airspeed_config.h
index 3df9e793289e8c..4ba2e4179388a2 100644
--- a/libraries/AP_Airspeed/AP_Airspeed_config.h
+++ b/libraries/AP_Airspeed/AP_Airspeed_config.h
@@ -2,16 +2,59 @@
#include
#include
-#include
+#include
#ifndef AP_AIRSPEED_ENABLED
#define AP_AIRSPEED_ENABLED 1
#endif
+#ifndef AP_AIRSPEED_BACKEND_DEFAULT_ENABLED
+#define AP_AIRSPEED_BACKEND_DEFAULT_ENABLED AP_AIRSPEED_ENABLED
+#endif
+
+// backends
+#ifndef AP_AIRSPEED_ANALOG_ENABLED
+#define AP_AIRSPEED_ANALOG_ENABLED AP_AIRSPEED_BACKEND_DEFAULT_ENABLED
+#endif
+
+#ifndef AP_AIRSPEED_ASP5033_ENABLED
+#define AP_AIRSPEED_ASP5033_ENABLED AP_AIRSPEED_BACKEND_DEFAULT_ENABLED
+#endif
+
+#ifndef AP_AIRSPEED_DLVR_ENABLED
+#define AP_AIRSPEED_DLVR_ENABLED AP_AIRSPEED_BACKEND_DEFAULT_ENABLED
+#endif
+
+#ifndef AP_AIRSPEED_DRONECAN_ENABLED
+#define AP_AIRSPEED_DRONECAN_ENABLED AP_AIRSPEED_BACKEND_DEFAULT_ENABLED && HAL_ENABLE_DRONECAN_DRIVERS
+#endif
+
+#ifndef AP_AIRSPEED_MS4525_ENABLED
+#define AP_AIRSPEED_MS4525_ENABLED AP_AIRSPEED_BACKEND_DEFAULT_ENABLED
+#endif
+
+#ifndef AP_AIRSPEED_MS5525_ENABLED
+#define AP_AIRSPEED_MS5525_ENABLED AP_AIRSPEED_BACKEND_DEFAULT_ENABLED
+#endif
+
#ifndef AP_AIRSPEED_MSP_ENABLED
-#define AP_AIRSPEED_MSP_ENABLED (AP_AIRSPEED_ENABLED && HAL_MSP_SENSORS_ENABLED)
+#define AP_AIRSPEED_MSP_ENABLED (AP_AIRSPEED_BACKEND_DEFAULT_ENABLED && HAL_MSP_SENSORS_ENABLED)
+#endif
+
+// note additional vehicle restrictions are made in the .cpp file!
+#ifndef AP_AIRSPEED_NMEA_ENABLED
+#define AP_AIRSPEED_NMEA_ENABLED AP_AIRSPEED_BACKEND_DEFAULT_ENABLED
+#endif
+
+#ifndef AP_AIRSPEED_SDP3X_ENABLED
+#define AP_AIRSPEED_SDP3X_ENABLED AP_AIRSPEED_BACKEND_DEFAULT_ENABLED
+#endif
+
+#ifndef AP_AIRSPEED_SITL_ENABLED
+#define AP_AIRSPEED_SITL_ENABLED AP_AIRSPEED_BACKEND_DEFAULT_ENABLED && AP_SIM_ENABLED
#endif
+// other AP_Airspeed options:
#ifndef AIRSPEED_MAX_SENSORS
#define AIRSPEED_MAX_SENSORS 2
#endif
diff --git a/libraries/AP_Airspeed/Airspeed_Calibration.cpp b/libraries/AP_Airspeed/Airspeed_Calibration.cpp
index 17380c05199315..3c5e1dc5b7a6aa 100644
--- a/libraries/AP_Airspeed/Airspeed_Calibration.cpp
+++ b/libraries/AP_Airspeed/Airspeed_Calibration.cpp
@@ -5,6 +5,10 @@
*
*/
+#include "AP_Airspeed_config.h"
+
+#if AP_AIRSPEED_ENABLED
+
#include
#include
#include
@@ -185,3 +189,5 @@ void AP_Airspeed::send_airspeed_calibration(const Vector3f &vground)
(const char *)&packet);
#endif // AP_AIRSPEED_AUTOCAL_ENABLE
}
+
+#endif // AP_AIRSPEED_ENABLED
diff --git a/libraries/AP_Arming/AP_Arming.cpp b/libraries/AP_Arming/AP_Arming.cpp
index 55079c3ba44e84..2bd9814b32de27 100644
--- a/libraries/AP_Arming/AP_Arming.cpp
+++ b/libraries/AP_Arming/AP_Arming.cpp
@@ -53,6 +53,8 @@
#include
#include
#include
+#include
+#include
#if HAL_MAX_CAN_PROTOCOL_DRIVERS
#include
@@ -60,11 +62,6 @@
#include
#include
-
- // To be replaced with macro saying if KDECAN library is included
- #if APM_BUILD_COPTER_OR_HELI || APM_BUILD_TYPE(APM_BUILD_ArduPlane) || APM_BUILD_TYPE(APM_BUILD_ArduSub)
- #include
- #endif
#include
#endif
@@ -93,7 +90,7 @@ const AP_Param::GroupInfo AP_Arming::var_info[] = {
// @Param{Plane, Rover}: REQUIRE
// @DisplayName: Require Arming Motors
- // @Description: Arming disabled until some requirements are met. If 0, there are no requirements (arm immediately). If 1, require rudder stick or GCS arming before arming motors and sends the minimum throttle PWM value to the throttle channel when disarmed. If 2, require rudder stick or GCS arming and send 0 PWM to throttle channel when disarmed. See the ARMING_CHECK_* parameters to see what checks are done before arming. Note, if setting this parameter to 0 a reboot is required to arm the plane. Also note, even with this parameter at 0, if ARMING_CHECK parameter is not also zero the plane may fail to arm throttle at boot due to a pre-arm check failure. On planes with ICE enabled and the throttle while disarmed option set in ICE_OPTIONS the motor will get THR_MIN when disarmed.
+ // @Description: Arming disabled until some requirements are met. If 0, there are no requirements (arm immediately). If 1, sends the minimum throttle PWM value to the throttle channel when disarmed. If 2, send 0 PWM (no signal) to throttle channel when disarmed. On planes with ICE enabled and the throttle while disarmed option set in ICE_OPTIONS, the motor will always get THR_MIN when disarmed. Arming will occur using either rudder stick arming (if enabled) or GCS command when all mandatory and ARMING_CHECK items are satisfied. Note, when setting this parameter to 0, a reboot is required to immediately arm the plane.
// @Values: 0:Disabled,1:minimum PWM when disarmed,2:0 PWM when disarmed
// @User: Advanced
AP_GROUPINFO_FLAGS_FRAME("REQUIRE", 0, AP_Arming, require, float(Required::YES_MIN_PWM),
@@ -155,6 +152,11 @@ const AP_Param::GroupInfo AP_Arming::var_info[] = {
extern AP_IOMCU iomcu;
#endif
+#pragma GCC diagnostic push
+#if defined (__clang__)
+#pragma GCC diagnostic ignored "-Wbitwise-instead-of-logical"
+#endif
+
AP_Arming::AP_Arming()
{
if (_singleton) {
@@ -329,6 +331,7 @@ bool AP_Arming::logging_checks(bool report)
return true;
}
+#if AP_INERTIALSENSOR_ENABLED
bool AP_Arming::ins_accels_consistent(const AP_InertialSensor &ins)
{
const uint8_t accel_count = ins.get_accel_count();
@@ -491,6 +494,7 @@ bool AP_Arming::ins_checks(bool report)
return true;
}
+#endif // AP_INERTIALSENSOR_ENABLED
bool AP_Arming::compass_checks(bool report)
{
@@ -614,10 +618,12 @@ bool AP_Arming::gps_checks(bool report)
(double)distance_m);
return false;
}
+#if defined(GPS_BLENDED_INSTANCE)
if (!gps.blend_health_check()) {
check_failed(ARMING_CHECK_GPS, report, "GPS blending unhealthy");
return false;
}
+#endif
// check AHRS and GPS are within 10m of each other
if (gps.num_sensors() > 0) {
@@ -638,7 +644,7 @@ bool AP_Arming::gps_checks(bool report)
if (gps.first_unconfigured_gps(first_unconfigured)) {
check_failed(ARMING_CHECK_GPS_CONFIG,
report,
- "GPS %d failing configuration checks",
+ "GPS %d still configuring this GPS",
first_unconfigured + 1);
if (report) {
gps.broadcast_first_configuration_failure_reason();
@@ -703,7 +709,7 @@ bool AP_Arming::rc_arm_checks(AP_Arming::Method method)
}
const RCMapper * rcmap = AP::rcmap();
if (rcmap != nullptr) {
- if (!rc().arming_skip_checks_rpy()) {
+ if (!rc().option_is_enabled(RC_Channels::Option::ARMING_SKIP_CHECK_RPY)) {
const char *names[3] = {"Roll", "Pitch", "Yaw"};
const uint8_t channels[3] = {rcmap->roll(), rcmap->pitch(), rcmap->yaw()};
for (uint8_t i = 0; i < ARRAY_SIZE(channels); i++) {
@@ -853,8 +859,18 @@ bool AP_Arming::mission_checks(bool report)
mission != nullptr &&
(mission->failed_sdcard_storage() || StorageManager::storage_failed())) {
check_failed(ARMING_CHECK_MISSION, report, "Failed to open %s", AP_MISSION_SDCARD_FILENAME);
+ return false;
}
#endif
+
+ // do not allow arming if there are no mission items and we are in
+ // (e.g.) AUTO mode
+ if (AP::vehicle()->current_mode_requires_mission() &&
+ (mission == nullptr || mission->num_commands() <= 1)) {
+ check_failed(ARMING_CHECK_MISSION, report, "Mode requires mission");
+ return false;
+ }
+
return true;
}
@@ -1040,11 +1056,13 @@ bool AP_Arming::system_checks(bool report)
return false;
}
#endif
+#if AP_RELAY_ENABLED
auto *relay = AP::relay();
if (relay && !relay->arming_checks(sizeof(buffer), buffer)) {
check_failed(ARMING_CHECK_PARAMETERS, report, "%s", buffer);
return false;
}
+#endif
#if HAL_PARACHUTE_ENABLED
auto *chute = AP::parachute();
if (chute && !chute->arming_checks(sizeof(buffer), buffer)) {
@@ -1147,18 +1165,7 @@ bool AP_Arming::can_checks(bool report)
for (uint8_t i = 0; i < num_drivers; i++) {
switch (AP::can().get_driver_type(i)) {
- case AP_CANManager::Driver_Type_KDECAN: {
-// To be replaced with macro saying if KDECAN library is included
-#if APM_BUILD_COPTER_OR_HELI || APM_BUILD_TYPE(APM_BUILD_ArduPlane) || APM_BUILD_TYPE(APM_BUILD_ArduSub)
- AP_KDECAN *ap_kdecan = AP_KDECAN::get_kdecan(i);
- if (ap_kdecan != nullptr && !ap_kdecan->pre_arm_check(fail_msg, ARRAY_SIZE(fail_msg))) {
- check_failed(ARMING_CHECK_SYSTEM, report, "KDECAN: %s", fail_msg);
- return false;
- }
-#endif
- break;
- }
- case AP_CANManager::Driver_Type_PiccoloCAN: {
+ case AP_CAN::Protocol::PiccoloCAN: {
#if HAL_PICCOLO_CAN_ENABLE
AP_PiccoloCAN *ap_pcan = AP_PiccoloCAN::get_pcan(i);
@@ -1173,7 +1180,7 @@ bool AP_Arming::can_checks(bool report)
#endif
break;
}
- case AP_CANManager::Driver_Type_DroneCAN:
+ case AP_CAN::Protocol::DroneCAN:
{
#if HAL_ENABLE_DRONECAN_DRIVERS
AP_DroneCAN *ap_dronecan = AP_DroneCAN::get_dronecan(i);
@@ -1184,17 +1191,13 @@ bool AP_Arming::can_checks(bool report)
#endif
break;
}
- case AP_CANManager::Driver_Type_CANTester:
- {
- check_failed(ARMING_CHECK_SYSTEM, report, "TestCAN: No Arming with TestCAN enabled");
- break;
- }
- case AP_CANManager::Driver_Type_EFI_NWPMU:
- case AP_CANManager::Driver_Type_USD1:
- case AP_CANManager::Driver_Type_None:
- case AP_CANManager::Driver_Type_Scripting:
- case AP_CANManager::Driver_Type_Scripting2:
- case AP_CANManager::Driver_Type_Benewake:
+ case AP_CAN::Protocol::EFI_NWPMU:
+ case AP_CAN::Protocol::USD1:
+ case AP_CAN::Protocol::None:
+ case AP_CAN::Protocol::Scripting:
+ case AP_CAN::Protocol::Scripting2:
+ case AP_CAN::Protocol::Benewake:
+ case AP_CAN::Protocol::KDECAN:
break;
}
}
@@ -1252,20 +1255,20 @@ bool AP_Arming::camera_checks(bool display_failure)
bool AP_Arming::osd_checks(bool display_failure) const
{
-#if OSD_PARAM_ENABLED && OSD_ENABLED
- if (check_enabled(ARMING_CHECK_CAMERA)) {
+#if OSD_ENABLED
+ if (check_enabled(ARMING_CHECK_OSD)) {
+ // if no OSD then pass
const AP_OSD *osd = AP::osd();
if (osd == nullptr) {
return true;
}
-
- // check camera is ready
+ // do osd checks for configuration
char fail_msg[MAVLINK_MSG_STATUSTEXT_FIELD_TEXT_LEN+1];
if (!osd->pre_arm_check(fail_msg, ARRAY_SIZE(fail_msg))) {
- check_failed(ARMING_CHECK_CAMERA, display_failure, "%s", fail_msg);
+ check_failed(ARMING_CHECK_OSD, display_failure, "%s", fail_msg);
return false;
}
- }
+ }
#endif
return true;
}
@@ -1501,7 +1504,9 @@ bool AP_Arming::pre_arm_checks(bool report)
& heater_min_temperature_checks(report)
#endif
& barometer_checks(report)
+#if AP_INERTIALSENSOR_ENABLED
& ins_checks(report)
+#endif
& compass_checks(report)
& gps_checks(report)
& battery_checks(report)
@@ -1546,16 +1551,6 @@ bool AP_Arming::arm_checks(AP_Arming::Method method)
}
}
-#if AP_FENCE_ENABLED
- AC_Fence *fence = AP::fence();
- if (fence != nullptr) {
- // If a fence is set to auto-enable, turn on the fence
- if(fence->auto_enabled() == AC_Fence::AutoEnable::ONLY_WHEN_ARMED) {
- fence->enable(true);
- }
- }
-#endif
-
// note that this will prepare AP_Logger to start logging
// so should be the last check to be done before arming
@@ -1633,6 +1628,19 @@ bool AP_Arming::arm(AP_Arming::Method method, const bool do_arming_checks)
}
#endif
+#if AP_FENCE_ENABLED
+ if (armed) {
+ auto *fence = AP::fence();
+ if (fence != nullptr) {
+ // If a fence is set to auto-enable, turn on the fence
+ if (fence->auto_enabled() == AC_Fence::AutoEnable::ONLY_WHEN_ARMED) {
+ fence->enable(true);
+ gcs().send_text(MAV_SEVERITY_INFO, "Fence: auto-enabled");
+ }
+ }
+ }
+#endif
+
return armed;
}
@@ -1804,6 +1812,7 @@ void AP_Arming::check_forced_logging(const AP_Arming::Method method)
case Method::GCS_FAILSAFE_HOLDFAILED:
case Method::PILOT_INPUT_FAILSAFE:
case Method::DEADRECKON_FAILSAFE:
+ case Method::BLACKBOX:
// keep logging for longer if disarmed for a bad reason
AP::logger().set_long_log_persist(true);
return;
@@ -1823,16 +1832,17 @@ void AP_Arming::check_forced_logging(const AP_Arming::Method method)
case Method::TOYMODELANDTHROTTLE:
case Method::TOYMODELANDFORCE:
case Method::LANDING:
+ case Method::DDS:
case Method::UNKNOWN:
AP::logger().set_long_log_persist(false);
return;
- };
+ }
}
AP_Arming *AP_Arming::_singleton = nullptr;
/*
- * Get the AP_InertialSensor singleton
+ * Get the AP_Arming singleton
*/
AP_Arming *AP_Arming::get_singleton()
{
@@ -1847,3 +1857,5 @@ AP_Arming &arming()
}
};
+
+#pragma GCC diagnostic pop
diff --git a/libraries/AP_Arming/AP_Arming.h b/libraries/AP_Arming/AP_Arming.h
index 8cb1c5f060d3ab..a59aad14bda5b0 100644
--- a/libraries/AP_Arming/AP_Arming.h
+++ b/libraries/AP_Arming/AP_Arming.h
@@ -5,6 +5,7 @@
#include
#include "AP_Arming_config.h"
+#include "AP_InertialSensor/AP_InertialSensor_config.h"
class AP_Arming {
public:
@@ -38,6 +39,7 @@ class AP_Arming {
ARMING_CHECK_AUX_AUTH = (1U << 17),
ARMING_CHECK_VISION = (1U << 18),
ARMING_CHECK_FFT = (1U << 19),
+ ARMING_CHECK_OSD = (1U << 20),
};
enum class Method {
@@ -75,6 +77,8 @@ class AP_Arming {
TOYMODELANDFORCE = 31, // only disarm uses this...
LANDING = 32, // only disarm uses this...
DEADRECKON_FAILSAFE = 33, // only disarm uses this...
+ BLACKBOX = 34,
+ DDS = 35,
UNKNOWN = 100,
};
@@ -141,6 +145,9 @@ class AP_Arming {
return (_arming_options & uint32_t(option)) != 0;
}
+ static bool method_is_GCS(Method method) {
+ return (method == Method::MAVLINK || method == Method::DDS);
+ }
protected:
// Parameters
@@ -162,7 +169,9 @@ class AP_Arming {
bool logging_checks(bool report);
+#if AP_INERTIALSENSOR_ENABLED
virtual bool ins_checks(bool report);
+#endif
bool compass_checks(bool report);
@@ -222,6 +231,8 @@ class AP_Arming {
bool fettec_checks(bool display_failure) const;
+ bool kdecan_checks(bool display_failure) const;
+
virtual bool proximity_checks(bool report) const;
bool servo_checks(bool report) const;
@@ -246,8 +257,10 @@ class AP_Arming {
static AP_Arming *_singleton;
+#if AP_INERTIALSENSOR_ENABLED
bool ins_accels_consistent(const class AP_InertialSensor &ins);
bool ins_gyros_consistent(const class AP_InertialSensor &ins);
+#endif
// check if we should keep logging after disarming
void check_forced_logging(const AP_Arming::Method method);
diff --git a/libraries/AP_BLHeli/AP_BLHeli.cpp b/libraries/AP_BLHeli/AP_BLHeli.cpp
index 1c6670c4b21bc3..918bd8256ad135 100644
--- a/libraries/AP_BLHeli/AP_BLHeli.cpp
+++ b/libraries/AP_BLHeli/AP_BLHeli.cpp
@@ -450,6 +450,18 @@ void AP_BLHeli::msp_process_command(void)
break;
}
+ case MSP_BATTERY_STATE: {
+ debug("MSP_BATTERY_STATE");
+ uint8_t buf[8];
+ buf[0] = 4; // cell count
+ putU16(&buf[1], 1500); // mAh
+ buf[3] = 16; // V
+ putU16(&buf[4], 1500); // mAh
+ putU16(&buf[6], 1); // A
+ msp_send_reply(msp.cmdMSP, buf, sizeof(buf));
+ break;
+ }
+
case MSP_MOTOR_CONFIG: {
debug("MSP_MOTOR_CONFIG");
uint8_t buf[10];
@@ -1448,7 +1460,14 @@ void AP_BLHeli::read_telemetry_packet(void)
const uint8_t motor_idx = motor_map[last_telem_esc];
// we have received valid data, mark the ESC as now active
hal.rcout->set_active_escs_mask(1<= BARO_MAX_INSTANCES) {
+ return false;
+ }
+ return sensors[instance].healthy;
+}
+#else
+bool AP_Baro::healthy(uint8_t instance) const {
+ // If the requested instance was outside max instances it is not healthy (it doesn't exist)
+ if (instance >= BARO_MAX_INSTANCES) {
+ return false;
+ }
+ return sensors[instance].healthy && sensors[instance].alt_ok && sensors[instance].calibrated;
+}
+#endif
+
/*
update field elevation value
*/
diff --git a/libraries/AP_Baro/AP_Baro.h b/libraries/AP_Baro/AP_Baro.h
index ba76b23419c949..a1b4b632422951 100644
--- a/libraries/AP_Baro/AP_Baro.h
+++ b/libraries/AP_Baro/AP_Baro.h
@@ -58,9 +58,9 @@ class AP_Baro
bool healthy(void) const { return healthy(_primary); }
#ifdef HAL_BUILD_AP_PERIPH
// calibration and alt check not valid for AP_Periph
- bool healthy(uint8_t instance) const { return sensors[instance].healthy; }
+ bool healthy(uint8_t instance) const;
#else
- bool healthy(uint8_t instance) const { return sensors[instance].healthy && sensors[instance].alt_ok && sensors[instance].calibrated; }
+ bool healthy(uint8_t instance) const;
#endif
// check if all baros are healthy - used for SYS_STATUS report
diff --git a/libraries/AP_Baro/AP_Baro_config.h b/libraries/AP_Baro/AP_Baro_config.h
index 981baf6684816c..0da6757a733846 100644
--- a/libraries/AP_Baro/AP_Baro_config.h
+++ b/libraries/AP_Baro/AP_Baro_config.h
@@ -5,7 +5,11 @@
#include
#ifndef HAL_BARO_WIND_COMP_ENABLED
-#define HAL_BARO_WIND_COMP_ENABLED !HAL_MINIMIZE_FEATURES
+#define HAL_BARO_WIND_COMP_ENABLED 1
+#endif
+
+#ifndef AP_BARO_ENABLED
+#define AP_BARO_ENABLED 1
#endif
// backend support:
@@ -80,3 +84,8 @@
#ifndef AP_BARO_DRONECAN_ENABLED
#define AP_BARO_DRONECAN_ENABLED (AP_BARO_BACKEND_DEFAULT_ENABLED && HAL_ENABLE_DRONECAN_DRIVERS)
#endif
+
+
+#ifndef AP_BARO_PROBE_EXTERNAL_I2C_BUSES
+#define AP_BARO_PROBE_EXTERNAL_I2C_BUSES 1
+#endif
diff --git a/libraries/AP_BattMonitor/AP_BattMonitor.cpp b/libraries/AP_BattMonitor/AP_BattMonitor.cpp
index 6e3dc4fa8b1ed2..43895108932413 100644
--- a/libraries/AP_BattMonitor/AP_BattMonitor.cpp
+++ b/libraries/AP_BattMonitor/AP_BattMonitor.cpp
@@ -57,6 +57,8 @@ const AP_Param::GroupInfo AP_BattMonitor::var_info[] = {
// @Path: AP_BattMonitor_FuelLevel_Analog.cpp
// @Group: _
// @Path: AP_BattMonitor_Synthetic_Current.cpp
+ // @Group: _
+ // @Path: AP_BattMonitor_INA2xx.cpp
AP_SUBGROUPVARPTR(drivers[0], "_", 41, AP_BattMonitor, backend_var_info[0]),
#if AP_BATT_MONITOR_MAX_INSTANCES > 1
@@ -76,6 +78,8 @@ const AP_Param::GroupInfo AP_BattMonitor::var_info[] = {
// @Path: AP_BattMonitor_FuelLevel_Analog.cpp
// @Group: 2_
// @Path: AP_BattMonitor_Synthetic_Current.cpp
+ // @Group: 2_
+ // @Path: AP_BattMonitor_INA2xx.cpp
AP_SUBGROUPVARPTR(drivers[1], "2_", 42, AP_BattMonitor, backend_var_info[1]),
#endif
@@ -96,6 +100,8 @@ const AP_Param::GroupInfo AP_BattMonitor::var_info[] = {
// @Path: AP_BattMonitor_FuelLevel_Analog.cpp
// @Group: 3_
// @Path: AP_BattMonitor_Synthetic_Current.cpp
+ // @Group: 3_
+ // @Path: AP_BattMonitor_INA2xx.cpp
AP_SUBGROUPVARPTR(drivers[2], "3_", 43, AP_BattMonitor, backend_var_info[2]),
#endif
@@ -116,6 +122,8 @@ const AP_Param::GroupInfo AP_BattMonitor::var_info[] = {
// @Path: AP_BattMonitor_FuelLevel_Analog.cpp
// @Group: 4_
// @Path: AP_BattMonitor_Synthetic_Current.cpp
+ // @Group: 4_
+ // @Path: AP_BattMonitor_INA2xx.cpp
AP_SUBGROUPVARPTR(drivers[3], "4_", 44, AP_BattMonitor, backend_var_info[3]),
#endif
@@ -136,6 +144,8 @@ const AP_Param::GroupInfo AP_BattMonitor::var_info[] = {
// @Path: AP_BattMonitor_FuelLevel_Analog.cpp
// @Group: 5_
// @Path: AP_BattMonitor_Synthetic_Current.cpp
+ // @Group: 5_
+ // @Path: AP_BattMonitor_INA2xx.cpp
AP_SUBGROUPVARPTR(drivers[4], "5_", 45, AP_BattMonitor, backend_var_info[4]),
#endif
@@ -156,6 +166,8 @@ const AP_Param::GroupInfo AP_BattMonitor::var_info[] = {
// @Path: AP_BattMonitor_FuelLevel_Analog.cpp
// @Group: 6_
// @Path: AP_BattMonitor_Synthetic_Current.cpp
+ // @Group: 6_
+ // @Path: AP_BattMonitor_INA2xx.cpp
AP_SUBGROUPVARPTR(drivers[5], "6_", 46, AP_BattMonitor, backend_var_info[5]),
#endif
@@ -176,6 +188,8 @@ const AP_Param::GroupInfo AP_BattMonitor::var_info[] = {
// @Path: AP_BattMonitor_FuelLevel_Analog.cpp
// @Group: 7_
// @Path: AP_BattMonitor_Synthetic_Current.cpp
+ // @Group: 7_
+ // @Path: AP_BattMonitor_INA2xx.cpp
AP_SUBGROUPVARPTR(drivers[6], "7_", 47, AP_BattMonitor, backend_var_info[6]),
#endif
@@ -196,6 +210,8 @@ const AP_Param::GroupInfo AP_BattMonitor::var_info[] = {
// @Path: AP_BattMonitor_FuelLevel_Analog.cpp
// @Group: 8_
// @Path: AP_BattMonitor_Synthetic_Current.cpp
+ // @Group: 8_
+ // @Path: AP_BattMonitor_INA2xx.cpp
AP_SUBGROUPVARPTR(drivers[7], "8_", 48, AP_BattMonitor, backend_var_info[7]),
#endif
@@ -216,6 +232,8 @@ const AP_Param::GroupInfo AP_BattMonitor::var_info[] = {
// @Path: AP_BattMonitor_FuelLevel_Analog.cpp
// @Group: 9_
// @Path: AP_BattMonitor_Synthetic_Current.cpp
+ // @Group: 9_
+ // @Path: AP_BattMonitor_INA2xx.cpp
AP_SUBGROUPVARPTR(drivers[8], "9_", 49, AP_BattMonitor, backend_var_info[8]),
#endif
@@ -478,6 +496,10 @@ void AP_BattMonitor::read()
drivers[i]->read();
drivers[i]->update_resistance_estimate();
+#if AP_BATTERY_ESC_TELEM_OUTBOUND_ENABLED
+ drivers[i]->update_esc_telem_outbound();
+#endif
+
#if HAL_LOGGING_ENABLED
if (logger != nullptr && logger->should_log(_log_battery_bit)) {
const uint64_t time_us = AP_HAL::micros64();
diff --git a/libraries/AP_BattMonitor/AP_BattMonitor.h b/libraries/AP_BattMonitor/AP_BattMonitor.h
index 93987634cdc846..bcd802bcce0710 100644
--- a/libraries/AP_BattMonitor/AP_BattMonitor.h
+++ b/libraries/AP_BattMonitor/AP_BattMonitor.h
@@ -23,7 +23,7 @@
#define AP_BATT_MONITOR_RES_EST_TC_1 0.5f
#define AP_BATT_MONITOR_RES_EST_TC_2 0.1f
-#if !HAL_MINIMIZE_FEATURES && BOARD_FLASH_SIZE > 1024
+#if BOARD_FLASH_SIZE > 1024
#define AP_BATT_MONITOR_CELLS_MAX 14
#else
#define AP_BATT_MONITOR_CELLS_MAX 12
@@ -107,6 +107,7 @@ class AP_BattMonitor
Analog_Volt_Synthetic_Current = 25,
INA239_SPI = 26,
EFI = 27,
+ // AD7091R5_I2C_Analog = 28, reserve ID for future use
};
FUNCTOR_TYPEDEF(battery_failsafe_handler_fn_t, void, const char *, const int8_t);
diff --git a/libraries/AP_BattMonitor/AP_BattMonitor_Analog.cpp b/libraries/AP_BattMonitor/AP_BattMonitor_Analog.cpp
index 1b0dbf9c4820c2..7c65c84fa672c3 100644
--- a/libraries/AP_BattMonitor/AP_BattMonitor_Analog.cpp
+++ b/libraries/AP_BattMonitor/AP_BattMonitor_Analog.cpp
@@ -81,7 +81,7 @@ AP_BattMonitor_Analog::AP_BattMonitor_Analog(AP_BattMonitor &mon,
_volt_multiplier.set_default(HAL_BATT2_VOLT_SCALE);
#endif
#ifdef HAL_BATT2_CURR_SCALE
- _curr_amp_per_volt.set_default(HAL_BATT2_VOLT_SCALE);
+ _curr_amp_per_volt.set_default(HAL_BATT2_CURR_SCALE);
#endif
}
#endif
diff --git a/libraries/AP_BattMonitor/AP_BattMonitor_Backend.cpp b/libraries/AP_BattMonitor/AP_BattMonitor_Backend.cpp
index 6eccda0078c6f6..729d5d02477bfe 100644
--- a/libraries/AP_BattMonitor/AP_BattMonitor_Backend.cpp
+++ b/libraries/AP_BattMonitor/AP_BattMonitor_Backend.cpp
@@ -18,6 +18,10 @@
#include "AP_BattMonitor.h"
#include "AP_BattMonitor_Backend.h"
+#if AP_BATTERY_ESC_TELEM_OUTBOUND_ENABLED
+#include "AP_ESC_Telem/AP_ESC_Telem.h"
+#endif
+
/*
base class constructor.
This incorporates initialisation as well.
@@ -233,6 +237,42 @@ void AP_BattMonitor_Backend::check_failsafe_types(bool &low_voltage, bool &low_c
}
}
+#if AP_BATTERY_ESC_TELEM_OUTBOUND_ENABLED
+void AP_BattMonitor_Backend::update_esc_telem_outbound()
+{
+ const uint8_t esc_index = _params._esc_telem_outbound_index;
+ if (esc_index == 0 || !_state.healthy) {
+ // Disabled if there's no ESC identified to route the data to or if the battery is unhealthy
+ return;
+ }
+
+ AP_ESC_Telem_Backend::TelemetryData telem {};
+
+ uint16_t type = AP_ESC_Telem_Backend::TelemetryType::VOLTAGE;
+ telem.voltage = _state.voltage; // all battery backends have voltage
+
+ if (has_current()) {
+ telem.current = _state.current_amps;
+ type |= AP_ESC_Telem_Backend::TelemetryType::CURRENT;
+ }
+
+ if (has_consumed_energy()) {
+ telem.consumption_mah = _state.consumed_mah;
+ type |= AP_ESC_Telem_Backend::TelemetryType::CONSUMPTION;
+ }
+
+ float temperature_c;
+ if (_mon.get_temperature(temperature_c, _state.instance)) {
+ // get the temperature from the frontend so we check for external temperature
+ telem.temperature_cdeg = temperature_c * 100;
+ type |= AP_ESC_Telem_Backend::TelemetryType::TEMPERATURE;
+ }
+
+ AP::esc_telem().update_telem_data(esc_index-1, telem, type);
+}
+#endif
+
+
/*
default implementation for reset_remaining(). This sets consumed_wh
and consumed_mah based on the given percentage. Use percentage=100
diff --git a/libraries/AP_BattMonitor/AP_BattMonitor_Backend.h b/libraries/AP_BattMonitor/AP_BattMonitor_Backend.h
index 1506e4d6a2276c..84ec427fe8deb7 100644
--- a/libraries/AP_BattMonitor/AP_BattMonitor_Backend.h
+++ b/libraries/AP_BattMonitor/AP_BattMonitor_Backend.h
@@ -81,6 +81,9 @@ class AP_BattMonitor_Backend
// set desired MPPT powered state (enabled/disabled)
virtual void mppt_set_powered_state(bool power_on) {};
+ // Update an ESC telemetry channel's power information
+ void update_esc_telem_outbound();
+
// amps: current (A)
// dt_us: time between samples (micro-seconds)
static float calculate_mah(float amps, float dt_us) { return (float) (amps * dt_us * AUS_TO_MAH); }
diff --git a/libraries/AP_BattMonitor/AP_BattMonitor_DroneCAN.cpp b/libraries/AP_BattMonitor/AP_BattMonitor_DroneCAN.cpp
index 6b30aee470d2dc..3130a8bdf32403 100644
--- a/libraries/AP_BattMonitor/AP_BattMonitor_DroneCAN.cpp
+++ b/libraries/AP_BattMonitor/AP_BattMonitor_DroneCAN.cpp
@@ -256,15 +256,22 @@ void AP_BattMonitor_DroneCAN::read()
}
}
+// Return true if the DroneCAN state of charge should be used.
+// Return false if state of charge should be calculated locally by counting mah.
+bool AP_BattMonitor_DroneCAN::use_CAN_SoC() const
+{
+ // a UAVCAN battery monitor may not be able to supply a state of charge. If it can't then
+ // the user can set the option to use current integration in the backend instead.
+ // SOC of 127 is used as an invalid SOC flag ie system configuration errors or SOC estimation unavailable
+ return !(option_is_set(AP_BattMonitor_Params::Options::Ignore_UAVCAN_SoC) ||
+ _mppt.is_detected ||
+ (_soc == 127));
+}
+
/// capacity_remaining_pct - returns true if the percentage is valid and writes to percentage argument
bool AP_BattMonitor_DroneCAN::capacity_remaining_pct(uint8_t &percentage) const
{
- if ((uint32_t(_params._options.get()) & uint32_t(AP_BattMonitor_Params::Options::Ignore_UAVCAN_SoC)) ||
- _mppt.is_detected ||
- _soc == 127) {
- // a UAVCAN battery monitor may not be able to supply a state of charge. If it can't then
- // the user can set the option to use current integration in the backend instead.
- // SOC of 127 is used as an invalid SOC flag ie system configuration errors or SOC estimation unavailable
+ if (!use_CAN_SoC()) {
return AP_BattMonitor_Backend::capacity_remaining_pct(percentage);
}
@@ -277,6 +284,27 @@ bool AP_BattMonitor_DroneCAN::capacity_remaining_pct(uint8_t &percentage) const
return true;
}
+// reset remaining percentage to given value
+bool AP_BattMonitor_DroneCAN::reset_remaining(float percentage)
+{
+ if (use_CAN_SoC()) {
+ // Cannot reset external state of charge
+ return false;
+ }
+
+ WITH_SEMAPHORE(_sem_battmon);
+
+ if (!AP_BattMonitor_Backend::reset_remaining(percentage)) {
+ // Base class reset failed
+ return false;
+ }
+
+ // Reset interim state that is used internally, this is then copied back to the main state in the read() call
+ _interim_state.consumed_mah = _state.consumed_mah;
+ _interim_state.consumed_wh = _state.consumed_wh;
+ return true;
+}
+
/// get_cycle_count - return true if cycle count can be provided and fills in cycles argument
bool AP_BattMonitor_DroneCAN::get_cycle_count(uint16_t &cycles) const
{
diff --git a/libraries/AP_BattMonitor/AP_BattMonitor_DroneCAN.h b/libraries/AP_BattMonitor/AP_BattMonitor_DroneCAN.h
index 9c5c56bb73b527..543aeb3b6daec9 100644
--- a/libraries/AP_BattMonitor/AP_BattMonitor_DroneCAN.h
+++ b/libraries/AP_BattMonitor/AP_BattMonitor_DroneCAN.h
@@ -54,6 +54,9 @@ class AP_BattMonitor_DroneCAN : public AP_BattMonitor_Backend
void mppt_set_powered_state(bool power_on) override;
+ // reset remaining percentage to given value
+ bool reset_remaining(float percentage) override;
+
private:
void handle_battery_info(const uavcan_equipment_power_BatteryInfo &msg);
void handle_battery_info_aux(const ardupilot_equipment_power_BatteryInfoAux &msg);
@@ -79,6 +82,10 @@ class AP_BattMonitor_DroneCAN : public AP_BattMonitor_Backend
static const char* mppt_fault_string(const MPPT_FaultFlags fault);
#endif
+ // Return true if the DroneCAN state of charge should be used.
+ // Return false if state of charge should be calculated locally by counting mah.
+ bool use_CAN_SoC() const;
+
AP_BattMonitor::BattMonitor_State _interim_state;
BattMonitor_DroneCAN_Type _type;
diff --git a/libraries/AP_BattMonitor/AP_BattMonitor_INA239.h b/libraries/AP_BattMonitor/AP_BattMonitor_INA239.h
index c03eea23f88cfb..3f5f87ee2114ea 100644
--- a/libraries/AP_BattMonitor/AP_BattMonitor_INA239.h
+++ b/libraries/AP_BattMonitor/AP_BattMonitor_INA239.h
@@ -18,7 +18,6 @@ class AP_BattMonitor_INA239 : public AP_BattMonitor_Backend
bool has_cell_voltages() const override { return false; }
bool has_temperature() const override { return false; }
bool has_current() const override { return true; }
- bool reset_remaining(float percentage) override { return false; }
bool get_cycle_count(uint16_t &cycles) const override { return false; }
void init(void) override;
diff --git a/libraries/AP_BattMonitor/AP_BattMonitor_INA2xx.cpp b/libraries/AP_BattMonitor/AP_BattMonitor_INA2xx.cpp
index 39bb82974da089..0a504132aa83a8 100644
--- a/libraries/AP_BattMonitor/AP_BattMonitor_INA2xx.cpp
+++ b/libraries/AP_BattMonitor/AP_BattMonitor_INA2xx.cpp
@@ -2,23 +2,49 @@
#if AP_BATTERY_INA2XX_ENABLED
+/*
+ supports INA226, INA228 and INA238 I2C battery monitors
+ */
+
#include
#include "AP_BattMonitor_INA2xx.h"
extern const AP_HAL::HAL& hal;
-#define REG_CONFIG 0x00
-#define REG_SHUNT_VOLTAGE 0x01
-#define REG_BUS_VOLTAGE 0x02
-#define REG_CURRENT 0x04
-#define REG_CALIBRATION 0x05
-#define REG_CONFIG_DEFAULT 0x4127
-#define REG_CONFIG_RESET 0x8000
+// INA226 specific registers
+#define REG_226_CONFIG 0x00
+#define REG_226_CONFIG_DEFAULT 0x4127
+#define REG_226_CONFIG_RESET 0x8000
+#define REG_226_BUS_VOLTAGE 0x02
+#define REG_226_CURRENT 0x04
+#define REG_226_CALIBRATION 0x05
+#define REG_226_MANUFACT_ID 0xfe
+
+// INA228 specific registers
+#define REG_228_CONFIG 0x00
+#define REG_228_CONFIG_RESET 0x8000
+#define REG_228_ADC_CONFIG 0x01
+#define REG_228_SHUNT_CAL 0x02
+#define REG_228_VBUS 0x05
+#define REG_228_CURRENT 0x07
+#define REG_228_MANUFACT_ID 0x3e
+#define REG_228_DEVICE_ID 0x3f
+
+// INA238 specific registers
+#define REG_238_CONFIG 0x00
+#define REG_238_CONFIG_RESET 0x8000
+#define REG_238_ADC_CONFIG 0x01
+#define REG_238_SHUNT_CAL 0x02
+#define REG_238_VBUS 0x05
+#define REG_238_CURRENT 0x07
+#define REG_238_MANUFACT_ID 0x3e
+#define REG_238_DEVICE_ID 0x3f
-// this should become a parameter in future
-#define MAX_AMPS 90.0
+#ifndef DEFAULT_BATTMON_INA2XX_MAX_AMPS
+#define DEFAULT_BATTMON_INA2XX_MAX_AMPS 90.0
+#endif
#ifndef HAL_BATTMON_INA2XX_BUS
#define HAL_BATTMON_INA2XX_BUS 0
@@ -27,6 +53,9 @@ extern const AP_HAL::HAL& hal;
#define HAL_BATTMON_INA2XX_ADDR 0
#endif
+// list of addresses to probe if I2C_ADDR is zero
+const uint8_t AP_BattMonitor_INA2XX::i2c_probe_addresses[] { 0x41, 0x44, 0x45 };
+
const AP_Param::GroupInfo AP_BattMonitor_INA2XX::var_info[] = {
// @Param: I2C_BUS
@@ -39,12 +68,21 @@ const AP_Param::GroupInfo AP_BattMonitor_INA2XX::var_info[] = {
// @Param: I2C_ADDR
// @DisplayName: Battery monitor I2C address
- // @Description: Battery monitor I2C address
+ // @Description: Battery monitor I2C address. If this is zero then probe list of supported addresses
// @Range: 0 127
// @User: Advanced
// @RebootRequired: True
AP_GROUPINFO("I2C_ADDR", 26, AP_BattMonitor_INA2XX, i2c_address, HAL_BATTMON_INA2XX_ADDR),
+ // @Param: MAX_AMPS
+ // @DisplayName: Battery monitor max current
+ // @Description: This controls the maximum current the INS2XX sensor will work with.
+ // @Range: 1 400
+ // @Units: A
+ // @User: Advanced
+ // @RebootRequired: True
+ AP_GROUPINFO("MAX_AMPS", 27, AP_BattMonitor_INA2XX, max_amps, DEFAULT_BATTMON_INA2XX_MAX_AMPS),
+
AP_GROUPEND
};
@@ -67,31 +105,60 @@ void AP_BattMonitor_INA2XX::init(void)
dev->register_periodic_callback(25000, FUNCTOR_BIND_MEMBER(&AP_BattMonitor_INA2XX::timer, void));
}
-void AP_BattMonitor_INA2XX::configure(void)
+bool AP_BattMonitor_INA2XX::configure(DevType dtype)
{
- WITH_SEMAPHORE(dev->get_semaphore());
+ switch (dtype) {
+ case DevType::UNKNOWN:
+ return false;
- int16_t config = 0;
- if (!write_word(REG_CONFIG, REG_CONFIG_RESET) ||
- !write_word(REG_CONFIG, REG_CONFIG_DEFAULT) ||
- !read_word(REG_CONFIG, config) ||
- config != REG_CONFIG_DEFAULT) {
- return;
+ case DevType::INA226: {
+ // configure for MAX_AMPS
+ const uint16_t conf = (0x2<<9) | (0x5<<6) | (0x5<<3) | 0x7; // 2ms conv time, 16x sampling
+ const float rShunt = 0.0005;
+ current_LSB = max_amps / 32768.0;
+ voltage_LSB = 0.00125; // 1.25mV/bit
+ const uint16_t cal = uint16_t(0.00512 / (current_LSB * rShunt));
+ if (write_word(REG_226_CONFIG, REG_226_CONFIG_RESET) && // reset
+ write_word(REG_226_CONFIG, conf) &&
+ write_word(REG_226_CALIBRATION, cal)) {
+ dev_type = dtype;
+ return true;
+ }
+ break;
}
- // configure for MAX_AMPS
- const uint16_t conf = (0x2<<9) | (0x5<<6) | (0x5<<3) | 0x7; // 2ms conv time, 16x sampling
- const float rShunt = 0.0005;
- current_LSB = MAX_AMPS / 32768.0;
- voltage_LSB = 0.00125; // 1.25mV/bit
- const uint16_t cal = uint16_t(0.00512 / (current_LSB * rShunt));
- if (!write_word(REG_CONFIG, REG_CONFIG_RESET) || // reset
- !write_word(REG_CONFIG, conf) ||
- !write_word(REG_CALIBRATION, cal)) {
- return;
+ case DevType::INA228: {
+ // configure for MAX_AMPS
+ voltage_LSB = 195.3125e-6; // 195.3125 uV/LSB
+ const float rShunt = 0.0005;
+ current_LSB = max_amps / (1<<19);
+ const uint16_t shunt_cal = uint16_t(13107.2e6 * current_LSB * rShunt) & 0x7FFF;
+ if (write_word(REG_228_CONFIG, REG_228_CONFIG_RESET) && // reset
+ write_word(REG_228_CONFIG, 0) &&
+ write_word(REG_228_SHUNT_CAL, shunt_cal)) {
+ dev_type = dtype;
+ return true;
+ }
+ break;
}
- configured = true;
+ case DevType::INA238: {
+ // configure for MAX_AMPS
+ voltage_LSB = 3.125e-3; // 3.125mV/LSB
+ const float rShunt = 0.0005;
+ current_LSB = max_amps / (1<<15);
+ const uint16_t shunt_cal = uint16_t(819.2e6 * current_LSB * rShunt) & 0x7FFF;
+ if (write_word(REG_238_CONFIG, REG_238_CONFIG_RESET) && // reset
+ write_word(REG_238_CONFIG, 0) &&
+ write_word(REG_238_SHUNT_CAL, shunt_cal)) {
+ dev_type = dtype;
+ return true;
+ }
+ break;
+ }
+
+ }
+ return false;
}
/// read the battery_voltage and current, should be called at 10hz
@@ -119,10 +186,10 @@ void AP_BattMonitor_INA2XX::read(void)
}
/*
- read word from register
- returns true if read was successful, false if failed
+ read 16 bit word from register
+ returns true if read was successful, false if failed
*/
-bool AP_BattMonitor_INA2XX::read_word(const uint8_t reg, int16_t& data) const
+bool AP_BattMonitor_INA2XX::read_word16(const uint8_t reg, int16_t& data) const
{
// read the appropriate register from the device
if (!dev->read_registers(reg, (uint8_t *)&data, sizeof(data))) {
@@ -135,6 +202,25 @@ bool AP_BattMonitor_INA2XX::read_word(const uint8_t reg, int16_t& data) const
return true;
}
+/*
+ read 24 bit signed value from register
+ returns true if read was successful, false if failed
+*/
+bool AP_BattMonitor_INA2XX::read_word24(const uint8_t reg, int32_t& data) const
+{
+ // read the appropriate register from the device
+ uint8_t d[3];
+ if (!dev->read_registers(reg, d, sizeof(d))) {
+ return false;
+ }
+ // 24 bit 2s complement data. Shift into upper 24 bits of int32_t then divide by 256
+ // to cope with negative numbers properly
+ data = d[0]<<24 | d[1]<<16 | d[2] << 8;
+ data = data / 256;
+
+ return true;
+}
+
/*
write word to a register, byte swapped
returns true if write was successful, false if failed
@@ -145,38 +231,114 @@ bool AP_BattMonitor_INA2XX::write_word(const uint8_t reg, const uint16_t data) c
return dev->transfer(b, sizeof(b), nullptr, 0);
}
+/*
+ detect device type. This may happen well after power on if battery is
+ not plugged in yet
+*/
+bool AP_BattMonitor_INA2XX::detect_device(void)
+{
+ uint32_t now = AP_HAL::millis();
+ if (now - last_detect_ms < 200) {
+ // don't flood the bus
+ return false;
+ }
+ last_detect_ms = now;
+ int16_t id;
+
+ WITH_SEMAPHORE(dev->get_semaphore());
+
+ if (i2c_address.get() == 0) {
+ dev->set_address(i2c_probe_addresses[i2c_probe_next]);
+ i2c_probe_next = (i2c_probe_next+1) % sizeof(i2c_probe_addresses);
+ }
+
+ if (read_word16(REG_228_MANUFACT_ID, id) && id == 0x5449 &&
+ read_word16(REG_228_DEVICE_ID, id) && (id&0xFFF0) == 0x2280) {
+ return configure(DevType::INA228);
+ }
+ if (read_word16(REG_238_MANUFACT_ID, id) && id == 0x5449 &&
+ read_word16(REG_238_DEVICE_ID, id) && (id&0xFFF0) == 0x2380) {
+ return configure(DevType::INA238);
+ }
+ if (read_word16(REG_226_MANUFACT_ID, id) && id == 0x5449 &&
+ write_word(REG_226_CONFIG, REG_226_CONFIG_RESET) &&
+ write_word(REG_226_CONFIG, REG_226_CONFIG_DEFAULT) &&
+ read_word16(REG_226_CONFIG, id) &&
+ id == REG_226_CONFIG_DEFAULT) {
+ return configure(DevType::INA226);
+ }
+ return false;
+}
+
+
void AP_BattMonitor_INA2XX::timer(void)
{
- // allow for power-on after boot
- if (!configured) {
- uint32_t now = AP_HAL::millis();
- if (now - last_configure_ms > 200) {
- // try contacting the device at 5Hz
- last_configure_ms = now;
- configure();
+ if (dev_type == DevType::UNKNOWN) {
+ if (!detect_device()) {
+ return;
}
- if (!configured) {
- // waiting for the device to respond
+ }
+
+ float voltage = 0, current = 0;
+
+ switch (dev_type) {
+ case DevType::UNKNOWN:
+ return;
+
+ case DevType::INA226: {
+ int16_t bus_voltage16, current16;
+ if (!read_word16(REG_226_BUS_VOLTAGE, bus_voltage16) ||
+ !read_word16(REG_226_CURRENT, current16)) {
+ failed_reads++;
+ if (failed_reads > 10) {
+ // device has disconnected, we need to reconfigure it
+ dev_type = DevType::UNKNOWN;
+ }
return;
}
+ voltage = bus_voltage16 * voltage_LSB;
+ current = current16 * current_LSB;
+ break;
}
- int16_t bus_voltage, current;
+ case DevType::INA228: {
+ int32_t bus_voltage24, current24;
+ if (!read_word24(REG_228_VBUS, bus_voltage24) ||
+ !read_word24(REG_228_CURRENT, current24)) {
+ failed_reads++;
+ if (failed_reads > 10) {
+ // device has disconnected, we need to reconfigure it
+ dev_type = DevType::UNKNOWN;
+ }
+ return;
+ }
+ voltage = (bus_voltage24>>4) * voltage_LSB;
+ current = (current24>>4) * current_LSB;
+ break;
+ }
- if (!read_word(REG_BUS_VOLTAGE, bus_voltage) ||
- !read_word(REG_CURRENT, current)) {
- failed_reads++;
- if (failed_reads > 10) {
- // device has disconnected, we need to reconfigure it
- configured = false;
+ case DevType::INA238: {
+ int16_t bus_voltage16, current16;
+ if (!read_word16(REG_238_VBUS, bus_voltage16) ||
+ !read_word16(REG_238_CURRENT, current16)) {
+ failed_reads++;
+ if (failed_reads > 10) {
+ // device has disconnected, we need to reconfigure it
+ dev_type = DevType::UNKNOWN;
+ }
+ return;
}
- return;
+ voltage = bus_voltage16 * voltage_LSB;
+ current = current16 * current_LSB;
+ break;
+ }
}
+
failed_reads = 0;
WITH_SEMAPHORE(accumulate.sem);
- accumulate.volt_sum += bus_voltage * voltage_LSB;
- accumulate.current_sum += current * current_LSB;
+ accumulate.volt_sum += voltage;
+ accumulate.current_sum += current;
accumulate.count++;
}
diff --git a/libraries/AP_BattMonitor/AP_BattMonitor_INA2xx.h b/libraries/AP_BattMonitor/AP_BattMonitor_INA2xx.h
index 3ed4b223fac69a..3175388b40be96 100644
--- a/libraries/AP_BattMonitor/AP_BattMonitor_INA2xx.h
+++ b/libraries/AP_BattMonitor/AP_BattMonitor_INA2xx.h
@@ -19,7 +19,6 @@ class AP_BattMonitor_INA2XX : public AP_BattMonitor_Backend
bool has_cell_voltages() const override { return false; }
bool has_temperature() const override { return false; }
bool has_current() const override { return true; }
- bool reset_remaining(float percentage) override { return false; }
bool get_cycle_count(uint16_t &cycles) const override { return false; }
void init(void) override;
@@ -30,17 +29,30 @@ class AP_BattMonitor_INA2XX : public AP_BattMonitor_Backend
private:
AP_HAL::OwnPtr dev;
- void configure(void);
- bool read_word(const uint8_t reg, int16_t& data) const;
+ enum class DevType : uint8_t {
+ UNKNOWN = 0,
+ INA226,
+ INA228,
+ INA238,
+ };
+
+ static const uint8_t i2c_probe_addresses[];
+ uint8_t i2c_probe_next;
+
+ bool configure(DevType dtype);
+ bool read_word16(const uint8_t reg, int16_t& data) const;
+ bool read_word24(const uint8_t reg, int32_t& data) const;
bool write_word(const uint8_t reg, const uint16_t data) const;
void timer(void);
+ bool detect_device(void);
+
+ DevType dev_type;
+ uint32_t last_detect_ms;
AP_Int8 i2c_bus;
AP_Int8 i2c_address;
- bool configured;
- bool callback_registered;
+ AP_Float max_amps;
uint32_t failed_reads;
- uint32_t last_configure_ms;
struct {
uint16_t count;
diff --git a/libraries/AP_BattMonitor/AP_BattMonitor_LTC2946.h b/libraries/AP_BattMonitor/AP_BattMonitor_LTC2946.h
index 93b378d52d486d..e365c3aa11b6f2 100644
--- a/libraries/AP_BattMonitor/AP_BattMonitor_LTC2946.h
+++ b/libraries/AP_BattMonitor/AP_BattMonitor_LTC2946.h
@@ -16,7 +16,6 @@ class AP_BattMonitor_LTC2946 : public AP_BattMonitor_Backend
bool has_cell_voltages() const override { return false; }
bool has_temperature() const override { return false; }
bool has_current() const override { return true; }
- bool reset_remaining(float percentage) override { return false; }
bool get_cycle_count(uint16_t &cycles) const override { return false; }
virtual void init(void) override;
diff --git a/libraries/AP_BattMonitor/AP_BattMonitor_Logging.cpp b/libraries/AP_BattMonitor/AP_BattMonitor_Logging.cpp
index f6c8633699d5f1..bb32de92f7e93c 100644
--- a/libraries/AP_BattMonitor/AP_BattMonitor_Logging.cpp
+++ b/libraries/AP_BattMonitor/AP_BattMonitor_Logging.cpp
@@ -22,6 +22,7 @@ void AP_BattMonitor_Backend::Log_Write_BAT(const uint8_t instance, const uint64_
temperature : (int16_t) ( has_temperature() ? _state.temperature * 100 : 0),
resistance : _state.resistance,
rem_percent : percent,
+ health : _state.healthy
};
AP::logger().WriteBlock(&pkt, sizeof(pkt));
}
diff --git a/libraries/AP_BattMonitor/AP_BattMonitor_Params.cpp b/libraries/AP_BattMonitor/AP_BattMonitor_Params.cpp
index 60c9a8ac67fe91..00a5de0c807f21 100644
--- a/libraries/AP_BattMonitor/AP_BattMonitor_Params.cpp
+++ b/libraries/AP_BattMonitor/AP_BattMonitor_Params.cpp
@@ -151,6 +151,16 @@ const AP_Param::GroupInfo AP_BattMonitor_Params::var_info[] = {
AP_GROUPINFO("OPTIONS", 21, AP_BattMonitor_Params, _options, 0),
#endif // HAL_BUILD_AP_PERIPH
+#if AP_BATTERY_ESC_TELEM_OUTBOUND_ENABLED
+ // @Param: ESC_INDEX
+ // @DisplayName: ESC Telemetry Index to write to
+ // @Description: ESC Telemetry Index to write voltage, current, consumption and temperature data to. Use 0 to disable.
+ // @Range: 0 10
+ // @Increment: 1
+ // @User: Advanced
+ AP_GROUPINFO("ESC_INDEX", 22, AP_BattMonitor_Params, _esc_telem_outbound_index, 0),
+#endif
+
AP_GROUPEND
};
diff --git a/libraries/AP_BattMonitor/AP_BattMonitor_Params.h b/libraries/AP_BattMonitor/AP_BattMonitor_Params.h
index 7b3223f3eea559..9366965328cd7a 100644
--- a/libraries/AP_BattMonitor/AP_BattMonitor_Params.h
+++ b/libraries/AP_BattMonitor/AP_BattMonitor_Params.h
@@ -1,6 +1,7 @@
#pragma once
#include
+#include "AP_BattMonitor_config.h"
class AP_BattMonitor_Params {
public:
@@ -43,4 +44,7 @@ class AP_BattMonitor_Params {
AP_Int8 _failsafe_voltage_source; /// voltage type used for detection of low voltage event
AP_Int8 _failsafe_low_action; /// action to preform on a low battery failsafe
AP_Int8 _failsafe_critical_action; /// action to preform on a critical battery failsafe
+#if AP_BATTERY_ESC_TELEM_OUTBOUND_ENABLED
+ AP_Int8 _esc_telem_outbound_index; /// bitmask of ESCs to forward voltage, current, consumption and temperature to.
+#endif
};
diff --git a/libraries/AP_BattMonitor/AP_BattMonitor_config.h b/libraries/AP_BattMonitor/AP_BattMonitor_config.h
index 1a020bee26fe2b..7b14fea17fb3bc 100644
--- a/libraries/AP_BattMonitor/AP_BattMonitor_config.h
+++ b/libraries/AP_BattMonitor/AP_BattMonitor_config.h
@@ -6,8 +6,12 @@
#include
#include
+#ifndef AP_BATTERY_ENABLED
+#define AP_BATTERY_ENABLED 1
+#endif
+
#ifndef AP_BATTERY_BACKEND_DEFAULT_ENABLED
-#define AP_BATTERY_BACKEND_DEFAULT_ENABLED 1
+#define AP_BATTERY_BACKEND_DEFAULT_ENABLED AP_BATTERY_ENABLED
#endif
#ifndef AP_BATTERY_ANALOG_ENABLED
@@ -26,6 +30,10 @@
#define AP_BATTERY_ESC_ENABLED AP_BATTERY_BACKEND_DEFAULT_ENABLED && HAL_WITH_ESC_TELEM
#endif
+#ifndef AP_BATTERY_ESC_TELEM_OUTBOUND_ENABLED
+#define AP_BATTERY_ESC_TELEM_OUTBOUND_ENABLED 0
+#endif
+
#ifndef AP_BATTERY_SMBUS_ENABLED
#define AP_BATTERY_SMBUS_ENABLED AP_BATTERY_BACKEND_DEFAULT_ENABLED
#endif
diff --git a/libraries/AP_BattMonitor/LogStructure.h b/libraries/AP_BattMonitor/LogStructure.h
index 1b7afc07e31ad3..fdc97512ef0065 100644
--- a/libraries/AP_BattMonitor/LogStructure.h
+++ b/libraries/AP_BattMonitor/LogStructure.h
@@ -9,7 +9,7 @@
// @LoggerMessage: BAT
// @Description: Gathered battery data
// @Field: TimeUS: Time since system startup
-// @Field: Instance: battery instance number
+// @Field: Inst: battery instance number
// @Field: Volt: measured voltage
// @Field: VoltR: estimated resting voltage
// @Field: Curr: measured current
@@ -18,6 +18,7 @@
// @Field: Temp: measured temperature
// @Field: Res: estimated battery resistance
// @Field: RemPct: remaining percentage
+// @Field: H: health
struct PACKED log_BAT {
LOG_PACKET_HEADER;
uint64_t time_us;
@@ -30,6 +31,7 @@ struct PACKED log_BAT {
int16_t temperature; // degrees C * 100
float resistance;
uint8_t rem_percent;
+ uint8_t health;
};
// @LoggerMessage: BCL
@@ -59,6 +61,6 @@ struct PACKED log_BCL {
#define LOG_STRUCTURE_FROM_BATTMONITOR \
{ LOG_BAT_MSG, sizeof(log_BAT), \
- "BAT", "QBfffffcfB", "TimeUS,Instance,Volt,VoltR,Curr,CurrTot,EnrgTot,Temp,Res,RemPct", "s#vvAaXOw%", "F-000C0?00" , true }, \
+ "BAT", "QBfffffcfBB", "TimeUS,Inst,Volt,VoltR,Curr,CurrTot,EnrgTot,Temp,Res,RemPct,H", "s#vvAaXOw%-", "F-000C0?000" , true }, \
{ LOG_BCL_MSG, sizeof(log_BCL), \
"BCL", "QBfHHHHHHHHHHHH", "TimeUS,Instance,Volt,V1,V2,V3,V4,V5,V6,V7,V8,V9,V10,V11,V12", "s#vvvvvvvvvvvvv", "F-0CCCCCCCCCCCC" , true },
diff --git a/libraries/AP_BattMonitor/tests/test_calculate_mah.cpp b/libraries/AP_BattMonitor/tests/test_calculate_mah.cpp
index f329c75cca926a..5d5f2346700c69 100644
--- a/libraries/AP_BattMonitor/tests/test_calculate_mah.cpp
+++ b/libraries/AP_BattMonitor/tests/test_calculate_mah.cpp
@@ -2,12 +2,12 @@
#include
-float calculate_mah_with_double_cast(float amps, float dt)
+static float calculate_mah_with_double_cast(float amps, float dt)
{
return (float) ((double) amps * (double) dt * (double) 0.0000002778f);
}
-float calculate_mah(float amps, float dt)
+static float calculate_mah(float amps, float dt)
{
return AP_BattMonitor_Backend::calculate_mah(amps, dt);
}
diff --git a/libraries/AP_Beacon/AP_Beacon_Marvelmind.cpp b/libraries/AP_Beacon/AP_Beacon_Marvelmind.cpp
index 423f383135b89b..4154b5edd99944 100644
--- a/libraries/AP_Beacon/AP_Beacon_Marvelmind.cpp
+++ b/libraries/AP_Beacon/AP_Beacon_Marvelmind.cpp
@@ -203,15 +203,13 @@ void AP_Beacon_Marvelmind::update(void)
return;
}
// read any available characters
- int32_t num_bytes_read = uart->available();
- uint8_t received_char = 0;
- if (num_bytes_read < 0) {
- return;
- }
+ uint16_t num_bytes_read = MIN(uart->available(), 16384U);
while (num_bytes_read-- > 0) {
bool good_byte = false;
- received_char = uart->read();
- input_buffer[num_bytes_in_block_received] = received_char;
+ if (!uart->read(input_buffer[num_bytes_in_block_received])) {
+ break;
+ }
+ const uint8_t received_char = input_buffer[num_bytes_in_block_received];
switch (parse_state) {
case RECV_HDR:
switch (num_bytes_in_block_received) {
diff --git a/libraries/AP_BoardConfig/AP_BoardConfig.cpp b/libraries/AP_BoardConfig/AP_BoardConfig.cpp
index bf223c878ea57e..829cbf4123e7bf 100644
--- a/libraries/AP_BoardConfig/AP_BoardConfig.cpp
+++ b/libraries/AP_BoardConfig/AP_BoardConfig.cpp
@@ -76,7 +76,11 @@
#ifndef HAL_BRD_OPTIONS_DEFAULT
#if CONFIG_HAL_BOARD == HAL_BOARD_CHIBIOS && !APM_BUILD_TYPE(APM_BUILD_UNKNOWN) && !APM_BUILD_TYPE(APM_BUILD_Replay)
+#ifdef HAL_DEBUG_BUILD
+#define HAL_BRD_OPTIONS_DEFAULT BOARD_OPTION_WATCHDOG | BOARD_OPTION_DEBUG_ENABLE
+#else
#define HAL_BRD_OPTIONS_DEFAULT BOARD_OPTION_WATCHDOG
+#endif
#else
#define HAL_BRD_OPTIONS_DEFAULT 0
#endif
@@ -134,7 +138,7 @@ const AP_Param::GroupInfo AP_BoardConfig::var_info[] = {
// @Values: 0:Disabled,1:Enabled,2:Auto
// @RebootRequired: True
// @User: Advanced
- AP_GROUPINFO("SER3_RTSCTS", 23, AP_BoardConfig, state.ser_rtscts[3], 2),
+ AP_GROUPINFO("SER3_RTSCTS", 26, AP_BoardConfig, state.ser_rtscts[3], 2),
#endif
#ifdef HAL_HAVE_RTSCTS_SERIAL4
@@ -144,7 +148,7 @@ const AP_Param::GroupInfo AP_BoardConfig::var_info[] = {
// @Values: 0:Disabled,1:Enabled,2:Auto
// @RebootRequired: True
// @User: Advanced
- AP_GROUPINFO("SER4_RTSCTS", 24, AP_BoardConfig, state.ser_rtscts[4], 2),
+ AP_GROUPINFO("SER4_RTSCTS", 27, AP_BoardConfig, state.ser_rtscts[4], 2),
#endif
#ifdef HAL_HAVE_RTSCTS_SERIAL5
@@ -194,7 +198,7 @@ const AP_Param::GroupInfo AP_BoardConfig::var_info[] = {
#if HAL_HAVE_IMU_HEATER
// @Param: HEAT_TARG
// @DisplayName: Board heater temperature target
- // @Description: Board heater target temperature for boards with controllable heating units. DO NOT SET to -1 on the Cube. Set to -1 to disable the heater, please reboot after setting to -1.
+ // @Description: Board heater target temperature for boards with controllable heating units. Set to -1 to disable the heater, please reboot after setting to -1.
// @Range: -1 80
// @Units: degC
// @User: Advanced
@@ -230,7 +234,7 @@ const AP_Param::GroupInfo AP_BoardConfig::var_info[] = {
// @Param: SAFETYOPTION
// @DisplayName: Options for safety button behavior
// @Description: This controls the activation of the safety button. It allows you to control if the safety button can be used for safety enable and/or disable, and whether the button is only active when disarmed
- // @Bitmask: 0:ActiveForSafetyEnable,1:ActiveForSafetyDisable,2:ActiveWhenArmed,3:Force safety on when the aircraft disarms
+ // @Bitmask: 0:ActiveForSafetyDisable,1:ActiveForSafetyEnable,2:ActiveWhenArmed,3:Force safety on when the aircraft disarms
// @User: Standard
AP_GROUPINFO("SAFETYOPTION", 13, AP_BoardConfig, state.safety_option, BOARD_SAFETY_OPTION_DEFAULT),
@@ -283,7 +287,7 @@ const AP_Param::GroupInfo AP_BoardConfig::var_info[] = {
// @Param: OPTIONS
// @DisplayName: Board options
// @Description: Board specific option flags
- // @Bitmask: 0:Enable hardware watchdog, 1:Disable MAVftp, 2:Enable set of internal parameters, 3:Enable Debug Pins, 4:Unlock flash on reboot, 5:Write protect firmware flash on reboot, 6:Write protect bootloader flash on reboot
+ // @Bitmask: 0:Enable hardware watchdog, 1:Disable MAVftp, 2:Enable set of internal parameters, 3:Enable Debug Pins, 4:Unlock flash on reboot, 5:Write protect firmware flash on reboot, 6:Write protect bootloader flash on reboot, 7:Skip board validation
// @User: Advanced
AP_GROUPINFO("OPTIONS", 19, AP_BoardConfig, _options, HAL_BRD_OPTIONS_DEFAULT),
@@ -349,7 +353,21 @@ const AP_Param::GroupInfo AP_BoardConfig::var_info[] = {
// @User: Advanced
AP_GROUPINFO("SD_MISSION", 24, AP_BoardConfig, sdcard_storage.mission_kb, 0),
#endif
+
+ // index 25 used by SER5_RTSCTS
+ // index 26 used by SER3_RTSCTS
+ // index 27 used by SER4_RTSCTS
+
+#if HAL_WITH_IO_MCU_DSHOT
+ // @Param: IO_DSHOT
+ // @DisplayName: Load DShot FW on IO
+ // @Description: This loads the DShot firmware on the IO co-processor
+ // @Values: 0:StandardFW,1:DshotFW
+ // @RebootRequired: True
+ // @User: Advanced
+ AP_GROUPINFO("IO_DSHOT", 28, AP_BoardConfig, state.io_dshot, 0),
+#endif
AP_GROUPEND
};
diff --git a/libraries/AP_BoardConfig/AP_BoardConfig.h b/libraries/AP_BoardConfig/AP_BoardConfig.h
index f190b6cf5d4f46..c6112dfc289868 100644
--- a/libraries/AP_BoardConfig/AP_BoardConfig.h
+++ b/libraries/AP_BoardConfig/AP_BoardConfig.h
@@ -92,6 +92,14 @@ class AP_BoardConfig {
#endif
}
+ static bool io_dshot(void) {
+#if HAL_WITH_IO_MCU_DSHOT
+ return io_enabled() && _singleton?_singleton->state.io_dshot.get():false;
+#else
+ return false;
+#endif
+ }
+
// get alternative config selection
uint8_t get_alt_config(void) {
return uint8_t(_alt_config.get());
@@ -114,6 +122,10 @@ class AP_BoardConfig {
return uint32_t(state.ignore_safety_channels.get());
}
+ uint32_t get_serial_number() const {
+ return (uint32_t)vehicleSerialNumber.get();
+ }
+
#if HAL_HAVE_BOARD_VOLTAGE
// get minimum board voltage
static float get_minimum_board_voltage(void) {
@@ -142,6 +154,7 @@ class AP_BoardConfig {
UNLOCK_FLASH = (1<<4),
WRITE_PROTECT_FLASH = (1<<5),
WRITE_PROTECT_BOOTLOADER = (1<<6),
+ SKIP_BOARD_VALIDATION = (1<<7)
};
// return true if ftp is disabled
@@ -213,6 +226,7 @@ class AP_BoardConfig {
#endif
AP_Int8 board_type;
AP_Int8 io_enable;
+ AP_Int8 io_dshot;
} state;
#if AP_SDCARD_STORAGE_ENABLED
diff --git a/libraries/AP_BoardConfig/AP_BoardConfig_config.h b/libraries/AP_BoardConfig/AP_BoardConfig_config.h
index 95c4092eb97cbb..c85f95439af3f4 100644
--- a/libraries/AP_BoardConfig/AP_BoardConfig_config.h
+++ b/libraries/AP_BoardConfig/AP_BoardConfig_config.h
@@ -33,5 +33,5 @@
#endif
#ifndef AP_SDCARD_STORAGE_ENABLED
-#define AP_SDCARD_STORAGE_ENABLED (HAL_MEM_CLASS >= HAL_MEM_CLASS_1000) && HAVE_FILESYSTEM_SUPPORT && BOARD_FLASH_SIZE > 1024
+#define AP_SDCARD_STORAGE_ENABLED (HAL_MEM_CLASS >= HAL_MEM_CLASS_1000) && (AP_FILESYSTEM_POSIX_ENABLED || AP_FILESYSTEM_FATFS_ENABLED) && BOARD_FLASH_SIZE > 1024
#endif
diff --git a/libraries/AP_BoardConfig/board_drivers.cpp b/libraries/AP_BoardConfig/board_drivers.cpp
index 6d59ea32d61d3b..ed365120a08cf3 100644
--- a/libraries/AP_BoardConfig/board_drivers.cpp
+++ b/libraries/AP_BoardConfig/board_drivers.cpp
@@ -81,18 +81,6 @@ void AP_BoardConfig::board_setup_drivers(void)
// run board auto-detection
board_autodetect();
-#if HAL_HAVE_IMU_HEATER
- if (state.board_type == PX4_BOARD_PH2SLIM ||
- state.board_type == PX4_BOARD_PIXHAWK2) {
- heater.imu_target_temperature.set_default(45);
- if (heater.imu_target_temperature.get() < 0) {
- // don't allow a value of -1 on the cube, or it could cook
- // the IMU
- heater.imu_target_temperature.set(45);
- }
- }
-#endif
-
px4_configured_board = (enum px4_board_type)state.board_type.get();
switch (px4_configured_board) {
@@ -313,12 +301,14 @@ void AP_BoardConfig::validate_board_type(void)
void AP_BoardConfig::board_autodetect(void)
{
#if defined(HAL_VALIDATE_BOARD)
- const char* errored_check = HAL_VALIDATE_BOARD;
- if (errored_check == nullptr) {
- return;
- } else {
- config_error("Board Validation %s Failed", errored_check);
- return;
+ if((_options & SKIP_BOARD_VALIDATION) == 0) {
+ const char* errored_check = HAL_VALIDATE_BOARD;
+ if (errored_check == nullptr) {
+ return;
+ } else {
+ config_error("Board Validation %s Failed", errored_check);
+ return;
+ }
}
#endif
diff --git a/libraries/AP_CANManager/AP_CAN.h b/libraries/AP_CANManager/AP_CAN.h
new file mode 100644
index 00000000000000..c241b777fc65b7
--- /dev/null
+++ b/libraries/AP_CANManager/AP_CAN.h
@@ -0,0 +1,31 @@
+#pragma once
+
+/*
+ * this header contains data common to ArduPilot CAN, rather than to a
+ * specific implementation of the protocols. So we try to share
+ * enumeration values where possible to make parameters similar across
+ * Periph and main firmwares, for example.
+ *
+ * this is *not* to be a one-stop-shop for including all things CAN...
+ */
+
+#include
+
+class AP_CAN {
+public:
+ enum class Protocol : uint8_t {
+ None = 0,
+ DroneCAN = 1,
+ // 2 was KDECAN -- do not re-use
+ // 3 was ToshibaCAN -- do not re-use
+ PiccoloCAN = 4,
+ // 5 was CANTester
+ EFI_NWPMU = 6,
+ USD1 = 7,
+ KDECAN = 8,
+ // 9 was MPPT_PacketDigital
+ Scripting = 10,
+ Benewake = 11,
+ Scripting2 = 12,
+ };
+};
diff --git a/libraries/AP_CANManager/AP_CANDriver.cpp b/libraries/AP_CANManager/AP_CANDriver.cpp
index 150c66f3c718df..a3e74f98cb025a 100644
--- a/libraries/AP_CANManager/AP_CANDriver.cpp
+++ b/libraries/AP_CANManager/AP_CANDriver.cpp
@@ -21,7 +21,6 @@
#include
#include
-#include "AP_CANTester.h"
#include
@@ -31,10 +30,10 @@ const AP_Param::GroupInfo AP_CANManager::CANDriver_Params::var_info[] = {
// @Param: PROTOCOL
// @DisplayName: Enable use of specific protocol over virtual driver
// @Description: Enabling this option starts selected protocol that will use this virtual driver
- // @Values: 0:Disabled,1:DroneCAN,4:PiccoloCAN,5:CANTester,6:EFI_NWPMU,7:USD1,8:KDECAN,10:Scripting,11:Benewake,12:Scripting2
+ // @Values: 0:Disabled,1:DroneCAN,4:PiccoloCAN,6:EFI_NWPMU,7:USD1,8:KDECAN,10:Scripting,11:Benewake,12:Scripting2
// @User: Advanced
// @RebootRequired: True
- AP_GROUPINFO("PROTOCOL", 1, AP_CANManager::CANDriver_Params, _driver_type, AP_CANManager::Driver_Type_DroneCAN),
+ AP_GROUPINFO("PROTOCOL", 1, AP_CANManager::CANDriver_Params, _driver_type, float(AP_CAN::Protocol::DroneCAN)),
#if HAL_ENABLE_DRONECAN_DRIVERS
// @Group: UC_
@@ -42,17 +41,9 @@ const AP_Param::GroupInfo AP_CANManager::CANDriver_Params::var_info[] = {
AP_SUBGROUPPTR(_uavcan, "UC_", 2, AP_CANManager::CANDriver_Params, AP_DroneCAN),
#endif
-#if (APM_BUILD_COPTER_OR_HELI || APM_BUILD_TYPE(APM_BUILD_ArduPlane) || APM_BUILD_TYPE(APM_BUILD_ArduSub))
- // @Group: KDE_
- // @Path: ../AP_KDECAN/AP_KDECAN.cpp
- AP_SUBGROUPPTR(_kdecan, "KDE_", 3, AP_CANManager::CANDriver_Params, AP_KDECAN),
-#endif
+ // index 3 was KDECAN
-#if HAL_NUM_CAN_IFACES > 1 && !HAL_MINIMIZE_FEATURES && HAL_ENABLE_CANTESTER
- // @Group: TST_
- // @Path: ../AP_CANManager/AP_CANTester.cpp
- AP_SUBGROUPPTR(_testcan, "TST_", 4, AP_CANManager::CANDriver_Params, CANTester),
-#endif
+ // index 4 was CANTester
#if HAL_PICCOLO_CAN_ENABLE
// @Group: PC_
diff --git a/libraries/AP_CANManager/AP_CANManager.cpp b/libraries/AP_CANManager/AP_CANManager.cpp
index 00aeaa4da8cffe..136ac78eeea0c8 100644
--- a/libraries/AP_CANManager/AP_CANManager.cpp
+++ b/libraries/AP_CANManager/AP_CANManager.cpp
@@ -29,7 +29,6 @@
#include
#include
#include
-#include "AP_CANTester.h"
#include
#if CONFIG_HAL_BOARD == HAL_BOARD_LINUX
#include
@@ -121,13 +120,7 @@ void AP_CANManager::init()
WITH_SEMAPHORE(_sem);
#if CONFIG_HAL_BOARD == HAL_BOARD_SITL
- if (AP::sitl() != nullptr) {
- if (AP::sitl()->speedup > 1) {
- log_text(AP_CANManager::LOG_ERROR, LOG_TAG, "CAN is not supported under speedup.");
-
- return;
- }
- } else {
+ if (AP::sitl() == nullptr) {
AP_HAL::panic("CANManager: SITL not initialised!");
}
#endif
@@ -142,7 +135,7 @@ void AP_CANManager::init()
_slcan_interface.reset_params();
#endif
- Driver_Type drv_type[HAL_MAX_CAN_PROTOCOL_DRIVERS] = {};
+ AP_CAN::Protocol drv_type[HAL_MAX_CAN_PROTOCOL_DRIVERS] = {};
// loop through interfaces and allocate and initialise Iface,
// Also allocate Driver objects, and add interfaces to them
for (uint8_t i = 0; i < HAL_NUM_CAN_IFACES; i++) {
@@ -166,7 +159,7 @@ void AP_CANManager::init()
AP_HAL::CANIface* iface = hal.can[i];
// Find the driver type that we need to allocate and register this interface with
- drv_type[drv_num] = (Driver_Type) _drv_param[drv_num]._driver_type.get();
+ drv_type[drv_num] = (AP_CAN::Protocol) _drv_param[drv_num]._driver_type.get();
bool can_initialised = false;
// Check if this interface need hooking up to slcan passthrough
// instead of a driver
@@ -204,7 +197,7 @@ void AP_CANManager::init()
// Allocate the set type of Driver
#if HAL_ENABLE_DRONECAN_DRIVERS
- if (drv_type[drv_num] == Driver_Type_DroneCAN) {
+ if (drv_type[drv_num] == AP_CAN::Protocol::DroneCAN) {
_drivers[drv_num] = _drv_param[drv_num]._uavcan = new AP_DroneCAN(drv_num);
if (_drivers[drv_num] == nullptr) {
@@ -215,20 +208,8 @@ void AP_CANManager::init()
AP_Param::load_object_from_eeprom((AP_DroneCAN*)_drivers[drv_num], AP_DroneCAN::var_info);
} else
#endif
- if (drv_type[drv_num] == Driver_Type_KDECAN) {
-#if (APM_BUILD_COPTER_OR_HELI || APM_BUILD_TYPE(APM_BUILD_ArduPlane) || APM_BUILD_TYPE(APM_BUILD_ArduSub))
- // To be replaced with macro saying if KDECAN library is included
- _drivers[drv_num] = _drv_param[drv_num]._kdecan = new AP_KDECAN;
-
- if (_drivers[drv_num] == nullptr) {
- AP_BoardConfig::allocation_error("KDECAN %d", drv_num + 1);
- continue;
- }
-
- AP_Param::load_object_from_eeprom((AP_KDECAN*)_drivers[drv_num], AP_KDECAN::var_info);
-#endif
- } else if (drv_type[drv_num] == Driver_Type_PiccoloCAN) {
#if HAL_PICCOLO_CAN_ENABLE
+ if (drv_type[drv_num] == AP_CAN::Protocol::PiccoloCAN) {
_drivers[drv_num] = _drv_param[drv_num]._piccolocan = new AP_PiccoloCAN;
if (_drivers[drv_num] == nullptr) {
@@ -237,18 +218,9 @@ void AP_CANManager::init()
}
AP_Param::load_object_from_eeprom((AP_PiccoloCAN*)_drivers[drv_num], AP_PiccoloCAN::var_info);
+ } else
#endif
- } else if (drv_type[drv_num] == Driver_Type_CANTester) {
-#if HAL_NUM_CAN_IFACES > 1 && !HAL_MINIMIZE_FEATURES && HAL_ENABLE_CANTESTER
- _drivers[drv_num] = _drv_param[drv_num]._testcan = new CANTester;
-
- if (_drivers[drv_num] == nullptr) {
- AP_BoardConfig::allocation_error("CANTester %d", drv_num + 1);
- continue;
- }
- AP_Param::load_object_from_eeprom((CANTester*)_drivers[drv_num], CANTester::var_info);
-#endif
- } else {
+ {
continue;
}
@@ -262,6 +234,11 @@ void AP_CANManager::init()
for (uint8_t drv_num = 0; drv_num < HAL_MAX_CAN_PROTOCOL_DRIVERS; drv_num++) {
//initialise all the Drivers
+
+ // Cache the driver type, initialized or not, so we can detect that it is in the params at boot via get_driver_type().
+ // This allows drivers that are initialized by CANSensor instead of CANManager to know if they should init or not
+ _driver_type_cache[drv_num] = drv_type[drv_num];
+
if (_drivers[drv_num] == nullptr) {
continue;
}
@@ -278,9 +255,6 @@ void AP_CANManager::init()
}
_drivers[drv_num]->init(drv_num, enable_filter);
- // Finally initialise driver type, this will be used
- // to find and reference protocol drivers
- _driver_type_cache[drv_num] = drv_type[drv_num];
}
}
#else
@@ -288,7 +262,7 @@ void AP_CANManager::init()
{
WITH_SEMAPHORE(_sem);
for (uint8_t i = 0; i < HAL_NUM_CAN_IFACES; i++) {
- if ((Driver_Type) _drv_param[i]._driver_type.get() == Driver_Type_DroneCAN) {
+ if ((AP_CAN::Protocol) _drv_param[i]._driver_type.get() == AP_CAN::Protocol::DroneCAN) {
_drivers[i] = _drv_param[i]._uavcan = new AP_DroneCAN(i);
if (_drivers[i] == nullptr) {
@@ -298,7 +272,7 @@ void AP_CANManager::init()
AP_Param::load_object_from_eeprom((AP_DroneCAN*)_drivers[i], AP_DroneCAN::var_info);
_drivers[i]->init(i, true);
- _driver_type_cache[i] = (Driver_Type) _drv_param[i]._driver_type.get();
+ _driver_type_cache[i] = (AP_CAN::Protocol) _drv_param[i]._driver_type.get();
}
}
}
@@ -306,7 +280,7 @@ void AP_CANManager::init()
/*
register a new CAN driver
*/
-bool AP_CANManager::register_driver(Driver_Type dtype, AP_CANDriver *driver)
+bool AP_CANManager::register_driver(AP_CAN::Protocol dtype, AP_CANDriver *driver)
{
WITH_SEMAPHORE(_sem);
@@ -318,7 +292,7 @@ bool AP_CANManager::register_driver(Driver_Type dtype, AP_CANDriver *driver)
// from 1 based to 0 based
drv_num--;
- if (dtype != (Driver_Type)_drv_param[drv_num]._driver_type.get()) {
+ if (dtype != (AP_CAN::Protocol)_drv_param[drv_num]._driver_type.get()) {
continue;
}
if (_drivers[drv_num] != nullptr) {
@@ -520,7 +494,7 @@ void AP_CANManager::process_frame_buffer(void)
break;
}
const int16_t retcode = hal.can[frame.bus]->send(frame.frame,
- AP_HAL::native_micros64() + timeout_us,
+ AP_HAL::micros64() + timeout_us,
AP_HAL::CANIface::IsMAVCAN);
if (retcode == 0) {
// no space in the CAN output slots, try again later
diff --git a/libraries/AP_CANManager/AP_CANManager.h b/libraries/AP_CANManager/AP_CANManager.h
index 8c350261415ee7..a0086fce2b01c2 100644
--- a/libraries/AP_CANManager/AP_CANManager.h
+++ b/libraries/AP_CANManager/AP_CANManager.h
@@ -19,9 +19,9 @@
#include "AP_CANManager_config.h"
-#include
+#if HAL_CANMANAGER_ENABLED
-#if HAL_MAX_CAN_PROTOCOL_DRIVERS
+#include
#include
#include "AP_SLCANIface.h"
@@ -32,6 +32,8 @@
#include
#endif
+#include "AP_CAN.h"
+
class AP_CANManager
{
public:
@@ -56,26 +58,10 @@ class AP_CANManager
LOG_DEBUG,
};
- enum Driver_Type : uint8_t {
- Driver_Type_None = 0,
- Driver_Type_DroneCAN = 1,
- // 2 was KDECAN -- do not re-use
- // 3 was ToshibaCAN -- do not re-use
- Driver_Type_PiccoloCAN = 4,
- Driver_Type_CANTester = 5,
- Driver_Type_EFI_NWPMU = 6,
- Driver_Type_USD1 = 7,
- Driver_Type_KDECAN = 8,
- // 9 was Driver_Type_MPPT_PacketDigital
- Driver_Type_Scripting = 10,
- Driver_Type_Benewake = 11,
- Driver_Type_Scripting2 = 12,
- };
-
void init(void);
// register a new driver
- bool register_driver(Driver_Type dtype, AP_CANDriver *driver);
+ bool register_driver(AP_CAN::Protocol dtype, AP_CANDriver *driver);
// returns number of active CAN Drivers
uint8_t get_num_drivers(void) const
@@ -104,12 +90,12 @@ class AP_CANManager
void log_retrieve(ExpandingString &str) const;
// return driver type index i
- Driver_Type get_driver_type(uint8_t i) const
+ AP_CAN::Protocol get_driver_type(uint8_t i) const
{
if (i < HAL_NUM_CAN_IFACES) {
return _driver_type_cache[i];
}
- return Driver_Type_None;
+ return AP_CAN::Protocol::None;
}
static const struct AP_Param::GroupInfo var_info[];
@@ -157,14 +143,13 @@ class AP_CANManager
AP_Int8 _driver_type;
AP_CANDriver* _testcan;
AP_CANDriver* _uavcan;
- AP_CANDriver* _kdecan;
AP_CANDriver* _piccolocan;
};
CANIface_Params _interfaces[HAL_NUM_CAN_IFACES];
AP_CANDriver* _drivers[HAL_MAX_CAN_PROTOCOL_DRIVERS];
CANDriver_Params _drv_param[HAL_MAX_CAN_PROTOCOL_DRIVERS];
- Driver_Type _driver_type_cache[HAL_MAX_CAN_PROTOCOL_DRIVERS];
+ AP_CAN::Protocol _driver_type_cache[HAL_MAX_CAN_PROTOCOL_DRIVERS];
AP_Int8 _loglevel;
uint8_t _num_drivers;
@@ -213,4 +198,4 @@ namespace AP
AP_CANManager& can();
}
-#endif
+#endif // HAL_CANMANAGER_ENABLED
diff --git a/libraries/AP_CANManager/AP_CANSensor.cpp b/libraries/AP_CANManager/AP_CANSensor.cpp
index 457707ba46fa2d..91d0fcb724b610 100644
--- a/libraries/AP_CANManager/AP_CANSensor.cpp
+++ b/libraries/AP_CANManager/AP_CANSensor.cpp
@@ -36,7 +36,7 @@ CANSensor::CANSensor(const char *driver_name, uint16_t stack_size) :
{}
-void CANSensor::register_driver(AP_CANManager::Driver_Type dtype)
+void CANSensor::register_driver(AP_CAN::Protocol dtype)
{
#if HAL_CANMANAGER_ENABLED
if (!AP::can().register_driver(dtype, this)) {
@@ -53,7 +53,7 @@ void CANSensor::register_driver(AP_CANManager::Driver_Type dtype)
#ifdef HAL_BUILD_AP_PERIPH
CANSensor::CANSensor_Periph CANSensor::_periph[HAL_NUM_CAN_IFACES];
-void CANSensor::register_driver_periph(const AP_CANManager::Driver_Type dtype)
+void CANSensor::register_driver_periph(const AP_CAN::Protocol dtype)
{
for (uint8_t i = 0; i < HAL_NUM_CAN_IFACES; i++) {
if (_periph[i].protocol != dtype) {
@@ -137,12 +137,12 @@ bool CANSensor::write_frame(AP_HAL::CANFrame &out_frame, const uint64_t timeout_
bool read_select = false;
bool write_select = true;
- bool ret = _can_iface->select(read_select, write_select, &out_frame, AP_HAL::native_micros64() + timeout_us);
+ bool ret = _can_iface->select(read_select, write_select, &out_frame, AP_HAL::micros64() + timeout_us);
if (!ret || !write_select) {
return false;
}
- uint64_t deadline = AP_HAL::native_micros64() + 2000000;
+ uint64_t deadline = AP_HAL::micros64() + 2000000;
return (_can_iface->send(out_frame, deadline, AP_HAL::CANIface::AbortOnError) == 1);
}
diff --git a/libraries/AP_CANManager/AP_CANSensor.h b/libraries/AP_CANManager/AP_CANSensor.h
index 779dcdd582b9bd..a1374821e40e4e 100644
--- a/libraries/AP_CANManager/AP_CANSensor.h
+++ b/libraries/AP_CANManager/AP_CANSensor.h
@@ -18,7 +18,11 @@
#pragma once
+#include "AP_CAN.h"
+#include "AP_CANDriver.h"
+#ifndef HAL_BUILD_AP_PERIPH
#include "AP_CANManager.h"
+#endif
#if HAL_MAX_CAN_PROTOCOL_DRIVERS
@@ -39,16 +43,27 @@ class CANSensor : public AP_CANDriver {
bool write_frame(AP_HAL::CANFrame &out_frame, const uint64_t timeout_us);
#ifdef HAL_BUILD_AP_PERIPH
- static void set_periph(const uint8_t i, const AP_CANManager::Driver_Type protocol, AP_HAL::CANIface* iface) {
- if (i < HAL_NUM_CAN_IFACES) {
+ static void set_periph(const uint8_t i, const AP_CAN::Protocol protocol, AP_HAL::CANIface* iface) {
+ if (i < ARRAY_SIZE(_periph)) {
_periph[i].protocol = protocol;
_periph[i].iface = iface;
}
}
+
+ // return driver type index i
+ static AP_CAN::Protocol get_driver_type(const uint8_t i)
+ {
+ if (i < ARRAY_SIZE(_periph)) {
+ return _periph[i].protocol;
+ }
+ return AP_CAN::Protocol::None;
+ }
+#else
+ static AP_CAN::Protocol get_driver_type(const uint8_t i) { return AP::can().get_driver_type(i); }
#endif
protected:
- void register_driver(AP_CANManager::Driver_Type dtype);
+ void register_driver(AP_CAN::Protocol dtype);
private:
void loop();
@@ -62,11 +77,11 @@ class CANSensor : public AP_CANDriver {
AP_HAL::CANIface* _can_iface;
#ifdef HAL_BUILD_AP_PERIPH
- void register_driver_periph(const AP_CANManager::Driver_Type dtype);
+ void register_driver_periph(const AP_CAN::Protocol dtype);
struct CANSensor_Periph {
AP_HAL::CANIface* iface;
- AP_CANManager::Driver_Type protocol;
+ AP_CAN::Protocol protocol;
} static _periph[HAL_NUM_CAN_IFACES];
#endif
};
diff --git a/libraries/AP_CANManager/AP_CANTester.cpp b/libraries/AP_CANManager/AP_CANTester.cpp
deleted file mode 100644
index 15abf98de86db4..00000000000000
--- a/libraries/AP_CANManager/AP_CANTester.cpp
+++ /dev/null
@@ -1,720 +0,0 @@
-
-/*
- * This file is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This file is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program. If not, see .
- *
- * Code by Siddharth Bharat Purohit
- */
-
-#include
-#include
-
-#include "AP_CANManager.h"
-#include "AP_CANTester.h"
-#if HAL_MAX_CAN_PROTOCOL_DRIVERS > 1 && !HAL_MINIMIZE_FEATURES && HAL_CANMANAGER_ENABLED && HAL_ENABLE_CANTESTER
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include "AP_CANTester_KDECAN.h"
-extern const AP_HAL::HAL& hal;
-
-const AP_Param::GroupInfo CANTester::var_info[] = {
- // @Param: ID
- // @DisplayName: CAN Test Index
- // @Description: Selects the Index of Test that needs to be run recursively, this value gets reset to 0 at boot.
- // @Range: 0 4
- // @Values: 0:TEST_NONE, 1:TEST_LOOPBACK,2:TEST_BUSOFF_RECOVERY,3:TEST_UAVCAN_DNA,5:TEST_KDE_CAN, 6:TEST_UAVCAN_ESC, 7:TEST_UAVCAN_FD_ESC
- // @User: Advanced
- AP_GROUPINFO("ID", 1, CANTester, _test_id, 0),
-
- // @Param: LPR8
- // @DisplayName: CANTester LoopRate
- // @Description: Selects the Looprate of Test methods
- // @Units: us
- // @User: Advanced
- AP_GROUPINFO("LPR8", 2, CANTester, _loop_rate, 10000),
-
- AP_GROUPEND
-
-};
-
-#define debug_can(level_debug, fmt, args...) do { AP::can().log_text(level_debug, "CANTester", fmt, ##args); } while (0)
-
-bool CANTester::add_interface(AP_HAL::CANIface* can_iface)
-{
- if (_num_ifaces >= HAL_NUM_CAN_IFACES) {
- debug_can(AP_CANManager::LOG_ERROR, "Max Number of CanIfaces exceeded");
- return false;
- }
-
- _can_ifaces[_num_ifaces] = can_iface;
-
- if (_can_ifaces[_num_ifaces] == nullptr) {
- debug_can(AP_CANManager::LOG_ERROR, "CAN driver not found");
- return false;
- }
-
- if (!_can_ifaces[_num_ifaces]->is_initialized()) {
- debug_can(AP_CANManager::LOG_ERROR, "Driver not initialized");
- return false;
- }
-
- _num_ifaces++;
- return true;
-}
-
-void CANTester::init(uint8_t driver_index, bool enable_filters)
-{
- _driver_index = driver_index;
-
- // Reset Test mask
- _test_id.set_and_save(0);
-
- debug_can(AP_CANManager::LOG_DEBUG, "starting init");
-
- if (_initialized) {
- debug_can(AP_CANManager::LOG_ERROR, "already initialized");
- return;
- }
-
- if (_can_ifaces[0] == nullptr) {
- debug_can(AP_CANManager::LOG_ERROR, "Interface not found");
- return;
- }
-
- // kick start tester thread
- if (!hal.scheduler->thread_create(FUNCTOR_BIND_MEMBER(&CANTester::main_thread, void), "can_tester", 4096, AP_HAL::Scheduler::PRIORITY_CAN, 1)) {
- debug_can(AP_CANManager::LOG_ERROR, "couldn't create thread");
- return;
- }
-
- _initialized = true;
-
- debug_can(AP_CANManager::LOG_DEBUG, "init done");
-
- return;
-}
-
-// write frame on CAN bus
-bool CANTester::write_frame(uint8_t iface, AP_HAL::CANFrame &out_frame, uint64_t timeout)
-{
- if (!_can_ifaces[iface]->set_event_handle(&_event_handle)) {
- debug_can(AP_CANManager::LOG_ERROR, "Cannot add event handle");
- return false;
- }
- // wait for space in buffer to send command
- bool read_select = false;
- bool write_select = true;
- out_frame.id += iface; // distinguish between multiple ifaces
- bool ret = _can_ifaces[iface]->select(read_select, write_select, &out_frame, AP_HAL::native_micros64() + timeout);
- if (!ret || !write_select) {
- return false;
- }
- uint64_t deadline = AP_HAL::native_micros64() + 2000000;
- // hal.console->printf("%x TDEAD: %lu\n", out_frame.id, deadline);
- // send frame and return success
- return (_can_ifaces[iface]->send(out_frame, deadline, AP_HAL::CANIface::AbortOnError) == 1);
-}
-
-// read frame on CAN bus, returns true on success
-bool CANTester::read_frame(uint8_t iface, AP_HAL::CANFrame &recv_frame, uint64_t timeout, AP_HAL::CANIface::CanIOFlags &flags)
-{
- if (!_can_ifaces[iface]->set_event_handle(&_event_handle)) {
- debug_can(AP_CANManager::LOG_ERROR, "Cannot add event handle");
- return false;
- }
- // wait for space in buffer to read
- bool read_select = true;
- bool write_select = false;
- bool ret = _can_ifaces[iface]->select(read_select, write_select, nullptr, AP_HAL::native_micros64() + timeout);
- if (!ret || !read_select) {
- // return false if no data is available to read
- return false;
- }
- uint64_t time;
-
- // read frame and return success
- return (_can_ifaces[iface]->receive(recv_frame, time, flags) == 1);
-}
-
-void CANTester::main_thread()
-{
- while (true) {
- switch (_test_id) {
- case CANTester::TEST_LOOPBACK:
- if (_can_ifaces[1] != nullptr) {
- gcs().send_text(MAV_SEVERITY_ALERT, "********Running Loopback Test*******");
- if (test_loopback(_loop_rate)) {
- gcs().send_text(MAV_SEVERITY_ALERT, "********Loopback Test Pass*******");
- } else {
- gcs().send_text(MAV_SEVERITY_ALERT, "********Loopback Test Fail*******");
- }
- } else {
- gcs().send_text(MAV_SEVERITY_ALERT, "Can't do Loopback Test with single iface");
- }
- break;
- case CANTester::TEST_BUSOFF_RECOVERY:
- if (_can_ifaces[1] != nullptr) {
- gcs().send_text(MAV_SEVERITY_ALERT, "********Running Busoff Recovery Test********");
- if (test_busoff_recovery()) {
- gcs().send_text(MAV_SEVERITY_ALERT, "********Busoff Recovery Test Pass********");
- } else {
- gcs().send_text(MAV_SEVERITY_ALERT, "********Busoff Recovery Test Fail********");
- }
- } else {
- gcs().send_text(MAV_SEVERITY_ALERT, "Can't do Busoff Recovery Test with single iface");
- }
- break;
- case CANTester::TEST_UAVCAN_DNA:
- if (_can_ifaces[1] == nullptr) {
- gcs().send_text(MAV_SEVERITY_ALERT, "********Running DroneCAN DNA Test********");
- if (test_uavcan_dna()) {
- gcs().send_text(MAV_SEVERITY_ALERT, "********DroneCAN DNA Test Pass********");
- } else {
- gcs().send_text(MAV_SEVERITY_ALERT, "********DroneCAN DNA Test Fail********");
- }
- } else {
- gcs().send_text(MAV_SEVERITY_ALERT, "Only one iface needs to be set for DroneCAN_DNA_TEST");
- }
- break;
- case CANTester::TEST_KDE_CAN:
- if (_can_ifaces[1] == nullptr) {
- gcs().send_text(MAV_SEVERITY_ALERT, "********Running KDE CAN Test********");
- if (test_kdecan()) {
- gcs().send_text(MAV_SEVERITY_ALERT, "********KDE CAN Test Pass********");
- } else {
- gcs().send_text(MAV_SEVERITY_ALERT, "********KDE CAN Test Fail********");
- }
- } else {
- gcs().send_text(MAV_SEVERITY_ALERT, "Only one iface needs to be set for TEST_KDE_CAN");
- }
- break;
- case CANTester::TEST_UAVCAN_ESC:
- if (_can_ifaces[1] == nullptr) {
- gcs().send_text(MAV_SEVERITY_ALERT, "********Running DroneCAN ESC Test********");
- if (test_uavcan_esc(false)) {
- gcs().send_text(MAV_SEVERITY_ALERT, "********DroneCAN ESC Test Pass********");
- } else {
- gcs().send_text(MAV_SEVERITY_ALERT, "********DroneCAN ESC Test Fail********");
- }
- } else {
- gcs().send_text(MAV_SEVERITY_ALERT, "Only one iface needs to be set for DroneCAN_ESC_TEST");
- }
- break;
- case CANTester::TEST_UAVCAN_FD_ESC:
- if (_can_ifaces[1] == nullptr) {
- gcs().send_text(MAV_SEVERITY_ALERT, "********Running DroneCAN FD ESC Test********");
- if (test_uavcan_esc(true)) {
- gcs().send_text(MAV_SEVERITY_ALERT, "********DroneCAN FD ESC Test Pass********");
- } else {
- gcs().send_text(MAV_SEVERITY_ALERT, "********DroneCAN FD ESC Test Fail********");
- }
- } else {
- gcs().send_text(MAV_SEVERITY_ALERT, "Only one iface needs to be set for UAVCAN_FD_ESC_TEST");
- }
- break;
- default:
- break;
- }
-
- for (uint8_t i = 0; i < 2; i++) {
- if (_can_ifaces[i] != nullptr) {
- _can_ifaces[i]->flush_tx();
- }
- }
- hal.scheduler->delay(5000);
- for (uint8_t i = 0; i < 2; i++) {
- if (_can_ifaces[i] != nullptr) {
- _can_ifaces[i]->clear_rx();
- }
- }
- }
-}
-
-/*****************************************
- * Loopback Test *
- * ***************************************/
-
-#define NUM_LOOPBACK_RUNS 1000UL
-#define LOOPBACK_MAGIC 0x34567819UL
-#if CONFIG_HAL_BOARD == HAL_BOARD_LINUX || CONFIG_HAL_BOARD == HAL_BOARD_SITL
-#define NUM_MAX_TX_FRAMES 1
-#else
-#define NUM_MAX_TX_FRAMES 64 // arbitrary value to max out the buffers
-#endif
-bool CANTester::test_loopback(uint32_t loop_rate)
-{
- AP_HAL::CANFrame frame;
- AP_HAL::CANIface::CanIOFlags flags;
- uint32_t num_loops = NUM_LOOPBACK_RUNS;
- memset(&_loopback_stats[0], 0, sizeof(_loopback_stats[0]));
- memset(&_loopback_stats[1], 0, sizeof(_loopback_stats[1]));
-
- while (num_loops--) {
- for (uint8_t i = 0; i < 2; i++) {
- // Write as many frames as we can on an iface
- for (uint32_t tx_frames = 0; tx_frames < NUM_MAX_TX_FRAMES; tx_frames++) {
- create_loopback_frame(_loopback_stats[i], frame);
- if (write_frame(i, frame, 0)) {
- _loopback_stats[i].tx_seq++;
- _loopback_stats[i].num_tx++;
- } else {
- break;
- }
- }
-
- // Also read as much as we can from the second iface
- while (true) {
- reset_frame(frame);
- if (read_frame((i+1)%2, frame, 0, flags)) {
- if (frame.id != ((13 | AP_HAL::CANFrame::FlagEFF) + i)) {
- continue;
- }
- check_loopback_frame(_loopback_stats[i], frame);
- _loopback_stats[i].num_rx++;
- } else {
- break;
- }
- }
- }
- hal.scheduler->delay_microseconds(loop_rate);
- }
- _can_ifaces[0]->flush_tx();
- hal.scheduler->delay_microseconds(1000);
- _can_ifaces[1]->flush_tx();
- hal.scheduler->delay_microseconds(1000);
- // flush the rx data still buffered in the interface
- for (uint8_t i = 0; i < 2; i++) {
- while (true) {
- reset_frame(frame);
- if (read_frame((i+1)%2, frame, 0, flags)) {
- if (frame.id != ((13 | AP_HAL::CANFrame::FlagEFF) + i)) {
- continue;
- }
- check_loopback_frame(_loopback_stats[i], frame);
- _loopback_stats[i].num_flushed_rx++;
- } else {
- break;
- }
- }
- }
-
- for (uint8_t i = 0; i < _num_ifaces; i++) {
- DEV_PRINTF("Loopback Test Results %d->%d:\n", i, (i+1)%2);
- DEV_PRINTF("num_tx: %lu, failed_tx: %lu\n",
- (long unsigned int)_loopback_stats[i].num_tx, (long unsigned int)_loopback_stats[i].failed_tx);
- DEV_PRINTF("num_rx: %lu, flushed_rx: %lu, bad_rx_data: %lu, bad_rx_seq: %lu\n",
- (long unsigned int)_loopback_stats[i].num_rx, (long unsigned int)_loopback_stats[i].num_flushed_rx,
- (long unsigned int)_loopback_stats[i].bad_rx_data, (long unsigned int)_loopback_stats[i].bad_rx_seq);
- if (_loopback_stats[i].num_rx < 0.9f * _loopback_stats[i].num_tx ||
- _loopback_stats[i].failed_tx || _loopback_stats[i].bad_rx_seq ||
- _loopback_stats[i].bad_rx_data) {
- return false;
- }
- }
- return true;
-}
-
-void CANTester::reset_frame(AP_HAL::CANFrame& frame)
-{
- frame.id = 0;
- memset(frame.data, 0, sizeof(frame.data));
- frame.dlc = 0;
-}
-
-void CANTester::create_loopback_frame(CANTester::loopback_stats_s &stats, AP_HAL::CANFrame& frame)
-{
- frame.id = 13 | AP_HAL::CANFrame::FlagEFF;
- frame.dlc = 8;
- frame.setCanFD(stats.tx_seq%2); //every other frame is canfd if supported
- memcpy(frame.data, &stats.tx_seq, sizeof(stats.tx_seq));
- uint32_t loopback_magic = LOOPBACK_MAGIC;
- memcpy(&frame.data[4], &loopback_magic, sizeof(loopback_magic));
-}
-
-
-void CANTester::check_loopback_frame(CANTester::loopback_stats_s &stats, AP_HAL::CANFrame& frame)
-{
- if (frame.dlc != 8) {
- stats.bad_rx_data++;
- }
-
- uint32_t loopback_magic = LOOPBACK_MAGIC;
- if (memcmp(&frame.data[4], &loopback_magic, sizeof(loopback_magic)) != 0) {
- stats.bad_rx_data++;
- return;
- }
-
- uint16_t curr_seq;
-
- memcpy(&curr_seq, frame.data, sizeof(curr_seq));
-
- if (stats.next_valid_seq != curr_seq) {
- stats.bad_rx_seq++;
- }
- stats.next_valid_seq = curr_seq + 1;
-}
-
-/*****************************************
- * Busoff Recovery Test *
- * ***************************************/
-bool CANTester::test_busoff_recovery()
-{
- uint32_t num_busoff_runs = 100000;
- uint64_t timestamp;
- AP_HAL::CANIface::CanIOFlags flags;
- AP_HAL::CANFrame bo_frame;
- bo_frame.id = (10 | AP_HAL::CANFrame::FlagEFF);
- memset(bo_frame.data, 0xA, sizeof(bo_frame.data));
- bo_frame.dlc =8;//AP_HAL::CANFrame::MaxDataLen;
- bool bus_off_detected = false;
- // Bus Fault can be introduced by shorting CANH and CANL
- gcs().send_text(MAV_SEVERITY_ERROR, "Introduce Bus Off Fault on the bus.");
- while (num_busoff_runs--) {
- if (bus_off_detected) {
- break;
- }
- //Spam the bus with same frame
- _can_ifaces[0]->send(bo_frame, AP_HAL::native_micros64()+1000, 0);
- _can_ifaces[1]->receive(bo_frame, timestamp, flags);
- _can_ifaces[1]->send(bo_frame, AP_HAL::native_micros64()+1000, 0);
- _can_ifaces[0]->receive(bo_frame, timestamp, flags);
- bus_off_detected = _can_ifaces[0]->is_busoff() || _can_ifaces[1]->is_busoff();
- hal.scheduler->delay_microseconds(50);
- }
- if (!bus_off_detected) {
- gcs().send_text(MAV_SEVERITY_ERROR, "BusOff not detected on the bus");
- return false;
- }
- gcs().send_text(MAV_SEVERITY_ERROR, "BusOff detected remove Fault.");
- hal.scheduler->delay(4000);
- gcs().send_text(MAV_SEVERITY_ERROR, "Running Loopback test.");
- //Send Dummy Frames to clear the error
- while (!write_frame(0, bo_frame,100)) {}
- bo_frame.id -= 1;
- while (!write_frame(1, bo_frame,100)) {}
- //Clear the CAN bus Rx Buffer
- hal.scheduler->delay(1000);
- _can_ifaces[0]->clear_rx();
- _can_ifaces[1]->clear_rx();
-
- return test_loopback(_loop_rate);
-}
-
-/*****************************************
- * DroneCAN DNA Test *
- * ***************************************/
-
-bool CANTester::test_uavcan_dna()
-{
- uavcan::CanIfaceMgr _uavcan_iface_mgr {};
-
- if (!_uavcan_iface_mgr.add_interface(_can_ifaces[0])) {
- gcs().send_text(MAV_SEVERITY_CRITICAL, "Failed to add iface");
- return false;
- }
-
- auto *node = new uavcan::Node<0>(_uavcan_iface_mgr, uavcan::SystemClock::instance(), _node_allocator);
- if (!node) {
- return false;
- }
- node->setName("org.ardupilot.dnatest");
-
- uavcan::protocol::HardwareVersion hw_version;
- const uint8_t uid_buf_len = hw_version.unique_id.capacity();
- uint8_t uid_len = uid_buf_len;
- uint8_t unique_id[uid_buf_len];
-
- if (hal.util->get_system_id_unformatted(unique_id, uid_len)) {
- unique_id[uid_len - 1] -= 5;
- uavcan::copy(unique_id, unique_id + uid_len, hw_version.unique_id.begin());
- }
-
- node->setHardwareVersion(hw_version); // Copying the value to the node's internals
-
- /*
- * Starting the node normally, in passive mode (i.e. without node ID assigned).
- */
- const int node_start_res = node->start();
- if (node_start_res < 0) {
- gcs().send_text(MAV_SEVERITY_CRITICAL, "Failed to start the node");
- delete node;
- return false;
- }
-
- /*
- * Initializing the dynamic node ID allocation client.
- * By default, the client will use TransferPriority::OneHigherThanLowest for communications with the allocator;
- * this can be overriden through the third argument to the start() method.
- */
- auto *client = new uavcan::DynamicNodeIDClient(*node);
- if (!client) {
- delete node;
- return false;
- }
- int expected_node_id = 100;
- int client_start_res = client->start(node->getHardwareVersion().unique_id, // USING THE SAME UNIQUE ID AS ABOVE
- expected_node_id);
- if (client_start_res < 0) {
- gcs().send_text(MAV_SEVERITY_ALERT,"Failed to start the dynamic node");
- }
-
- /*
- * Waiting for the client to obtain for us a node ID.
- * This may take a few seconds.
- */
- gcs().send_text(MAV_SEVERITY_ALERT, "Allocation is in progress");
- uint32_t num_runs = 100;
- while (!client->isAllocationComplete() && num_runs--) {
- const int res = node->spin(uavcan::MonotonicDuration::fromMSec(200)); // Spin duration doesn't matter
- if (res < 0) {
- gcs().send_text(MAV_SEVERITY_ALERT, "Transient failure");
- }
- }
- gcs().send_text(MAV_SEVERITY_ALERT, "Dynamic NodeID %d allocated node ID %d",
- int(client->getAllocatedNodeID().get()),
- int(client->getAllocatorNodeID().get()));
- if (client->getAllocatedNodeID().get() != expected_node_id) {
- gcs().send_text(MAV_SEVERITY_ALERT, "Unexpected Node Id, expected %d", expected_node_id);
- delete client;
- delete node;
- return false;
- }
- delete client;
- delete node;
- return true;
-}
-
-/*****************************************
- * KDE CAN Test *
- *****************************************/
-bool CANTester::test_kdecan()
-{
- AP_CANTester_KDECAN* kdecan_test = new AP_CANTester_KDECAN;
- if (kdecan_test == nullptr) {
- gcs().send_text(MAV_SEVERITY_ERROR, "Failed to allocate KDECAN Tester");
- return false;
- }
- kdecan_test->init(_can_ifaces[0]);
-
- while (true) {
- kdecan_test->loop();
- static uint32_t last_print_ms;
- static uint32_t last_enumsend_ms;
- static uint8_t enum_count = 0;
- uint32_t now = AP_HAL::millis();
- if (now - last_print_ms >= 1000) {
- last_print_ms = now;
- kdecan_test->print_stats();
- }
- if (!_kdecan_enumeration) {
- enum_count = 0;
- }
- if (now - last_enumsend_ms >= 2000 && enum_count < 4 && _kdecan_enumeration) {
- last_enumsend_ms = now;
- if (kdecan_test->send_enumeration(enum_count)) {
- enum_count++;
- }
- }
- }
- return true;
-}
-
-bool CANTester::run_kdecan_enumeration(bool start_stop)
-{
- _kdecan_enumeration = start_stop;
- return true;
-}
-
-/***********************************************
- * DroneCAN ESC *
- * *********************************************/
-
-#define NUM_ESCS 4
-static uavcan::Publisher* esc_status_publisher;
-static uavcan::Subscriber *esc_command_listener;
-static uint16_t uavcan_esc_command_rate = 0;
-
-void handle_raw_command(const uavcan::ReceivedDataStructure& msg);
-void handle_raw_command(const uavcan::ReceivedDataStructure& msg)
-{
- static uint16_t num_received = 0;
- static uint32_t last_millis;
- if (num_received == 0) {
- last_millis = AP_HAL::millis();
- }
- num_received++;
- // update rate every 50 packets
- if (num_received == 50) {
- uavcan_esc_command_rate = 50000/(AP_HAL::millis() - last_millis);
- num_received = 0;
- }
-}
-
-bool CANTester::test_uavcan_esc(bool enable_canfd)
-{
- bool ret = true;
- uavcan::CanIfaceMgr _uavcan_iface_mgr {};
-
- if (!_uavcan_iface_mgr.add_interface(_can_ifaces[0])) {
- gcs().send_text(MAV_SEVERITY_CRITICAL, "Failed to add iface");
- return false;
- }
-
- uavcan::Node<0> *node = nullptr;
- {
- node = new uavcan::Node<0>(_uavcan_iface_mgr, uavcan::SystemClock::instance(), _node_allocator);
- if (node == nullptr) {
- gcs().send_text(MAV_SEVERITY_CRITICAL, "Failed to allocate ESC Node");
- ret = false;
- goto exit;
- } else {
- node->setName("org.ardupilot.esctest");
- }
- }
-
- {
- uavcan::protocol::HardwareVersion hw_version;
- const uint8_t uid_buf_len = hw_version.unique_id.capacity();
- uint8_t uid_len = uid_buf_len;
- uint8_t unique_id[uid_buf_len];
- if (hal.util->get_system_id_unformatted(unique_id, uid_len)) {
- // Generate random uid
- unique_id[uid_len - 1] += 5;
- uavcan::copy(unique_id, unique_id + uid_len, hw_version.unique_id.begin());
- }
-
- node->setHardwareVersion(hw_version); // Copying the value to the node's internals
- }
- /*
- * Starting the node normally, in passive mode (i.e. without node ID assigned).
- */
- {
- const int node_start_res = node->start();
- if (node_start_res < 0) {
- gcs().send_text(MAV_SEVERITY_CRITICAL, "Failed to start the node");
- ret = false;
- goto exit;
- }
- }
-
- {
- /*
- * Initializing the dynamic node ID allocation client.
- * By default, the client will use TransferPriority::OneHigherThanLowest for communications with the allocator;
- * this can be overriden through the third argument to the start() method.
- */
- uavcan::DynamicNodeIDClient client(*node);
- int client_start_res = client.start(node->getHardwareVersion().unique_id, // USING THE SAME UNIQUE ID AS ABOVE
- uavcan::NodeID(0));
- if (client_start_res < 0) {
- gcs().send_text(MAV_SEVERITY_ALERT,"Failed to start the dynamic node");
- ret = false;
- goto exit;
- }
-
- /*
- * Waiting for the client to obtain for us a node ID.
- * This may take a few seconds.
- */
- gcs().send_text(MAV_SEVERITY_ALERT, "Allocation is in progress");
- while (!client.isAllocationComplete()) {
- const int res = node->spin(uavcan::MonotonicDuration::fromMSec(200)); // Spin duration doesn't matter
- if (res < 0) {
- gcs().send_text(MAV_SEVERITY_ALERT, "Transient failure");
- }
- }
- gcs().send_text(MAV_SEVERITY_ALERT, "Dynamic NodeID %d allocated node ID %d",
- int(client.getAllocatedNodeID().get()),
- int(client.getAllocatorNodeID().get()));
- if (client.getAllocatedNodeID().get() == 255) {
- gcs().send_text(MAV_SEVERITY_ALERT, "Node Allocation Failed");
- ret = false;
- goto exit;
- }
- esc_command_listener = new uavcan::Subscriber(*node);
- if (esc_command_listener) {
- esc_command_listener->start(handle_raw_command);
- } else {
- ret = false;
- goto exit;
- }
-
- esc_status_publisher = new uavcan::Publisher(*node);
- if (esc_status_publisher == nullptr) {
- ret = false;
- goto exit;
- }
- esc_status_publisher->setTxTimeout(uavcan::MonotonicDuration::fromMSec(2));
- esc_status_publisher->setPriority(uavcan::TransferPriority::OneLowerThanHighest);
-
- if (enable_canfd) {
- node->enableCanFd();
- } else {
- node->disableCanFd();
- }
- node->setNodeID(client.getAllocatedNodeID());
- node->setModeOperational();
- }
-
- // Allocations done lets begin
- if (ret) {
- while (true) {
- node->spin(uavcan::MonotonicDuration::fromMSec(1000));
- gcs().send_text(MAV_SEVERITY_ALERT, "UC ESC Command Rate: %d", uavcan_esc_command_rate);
- uavcan_esc_command_rate = 0;
- // send fake ESC stats as well
- for (uint8_t i = 0; i < NUM_ESCS; i++) {
- uavcan::equipment::esc::Status status_msg;
- status_msg.esc_index = i;
- status_msg.error_count = 0;
- status_msg.voltage = 30 + 2*((float)get_random16()/INT16_MAX);
- status_msg.current = 10 + 10*((float)get_random16()/INT16_MAX);
- status_msg.temperature = C_TO_KELVIN(124 + i);
- status_msg.rpm = 1200 + 300*((float)get_random16()/INT16_MAX);
- status_msg.power_rating_pct = 70 + 20*((float)get_random16()/INT16_MAX);
- esc_status_publisher->broadcast(status_msg);
- }
- }
- }
-
-exit:
- // Clean up!
- delete node;
-
- if (esc_command_listener != nullptr) {
- delete esc_command_listener;
- esc_command_listener = nullptr;
- }
- if (esc_status_publisher != nullptr) {
- delete esc_status_publisher;
- esc_status_publisher = nullptr;
- }
- return ret;
-}
-
-
-CANTester *CANTester::get_cantester(uint8_t driver_index)
-{
- if (driver_index >= AP::can().get_num_drivers() ||
- AP::can().get_driver_type(driver_index) != AP_CANManager::Driver_Type_CANTester) {
- return nullptr;
- }
- return static_cast(AP::can().get_driver(driver_index));
-}
-#endif //#if HAL_MAX_CAN_PROTOCOL_DRIVERS > 1 && !HAL_MINIMIZE_FEATURES && HAL_MAX_CAN_PROTOCOL_DRIVERS
diff --git a/libraries/AP_CANManager/AP_CANTester.h b/libraries/AP_CANManager/AP_CANTester.h
deleted file mode 100644
index 6fb07c761847c3..00000000000000
--- a/libraries/AP_CANManager/AP_CANTester.h
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see .
- */
-
-#pragma once
-
-#include "AP_CANDriver.h"
-#include
-#include
-#ifndef HAL_ENABLE_CANTESTER
-#define HAL_ENABLE_CANTESTER 0
-#endif
-
-#if HAL_MAX_CAN_PROTOCOL_DRIVERS > 1 && !HAL_MINIMIZE_FEATURES && HAL_CANMANAGER_ENABLED && HAL_ENABLE_CANTESTER
-
-class CANTester : public AP_CANDriver
-{
-public:
- CANTester()
- {
- // update protected var for parameter interface
- AP_Param::setup_object_defaults(this, var_info);
- }
-
- static const struct AP_Param::GroupInfo var_info[];
-
- /* Do not allow copies */
- CLASS_NO_COPY(CANTester);
-
- void init(uint8_t driver_index, bool enable_filters) override;
- bool add_interface(AP_HAL::CANIface* can_iface) override;
- bool run_kdecan_enumeration(bool start_stop);
-
- static CANTester *get_cantester(uint8_t driver_index);
-
-private:
-
- enum {
- TEST_NONE,
- TEST_LOOPBACK,
- TEST_BUSOFF_RECOVERY,
- TEST_UAVCAN_DNA,
- TEST_KDE_CAN,
- TEST_UAVCAN_ESC,
- TEST_UAVCAN_FD_ESC,
- TEST_END,
- };
-
- struct loopback_stats_s {
- uint32_t num_tx;
- uint32_t failed_tx;
- uint32_t num_rx;
- uint32_t num_flushed_rx;
- uint32_t bad_rx_data;
- uint32_t bad_rx_seq;
- uint16_t tx_seq;
- uint16_t next_valid_seq;
- } _loopback_stats[HAL_NUM_CAN_IFACES];
-
- void main_thread();
- bool test_loopback(uint32_t loop_rate);
- void create_loopback_frame(loopback_stats_s &stats, AP_HAL::CANFrame& frame);
- void check_loopback_frame(loopback_stats_s &stats, AP_HAL::CANFrame& frame);
-
-
- bool test_busoff_recovery();
-
- bool test_uavcan_dna();
-
- bool test_kdecan();
-
- bool test_uavcan_esc(bool enable_canfd);
-
- // write frame on CAN bus, returns true on success
- bool write_frame(uint8_t iface, AP_HAL::CANFrame &out_frame, uint64_t timeout);
-
- // read frame on CAN bus, returns true on success
- bool read_frame(uint8_t iface, AP_HAL::CANFrame &recv_frame, uint64_t timeout, AP_HAL::CANIface::CanIOFlags &flags);
-
- void reset_frame(AP_HAL::CANFrame& frame);
-
- bool _initialized;
- uint8_t _driver_index;
- AP_HAL::CANIface* _can_ifaces[HAL_NUM_CAN_IFACES];
-
- // Classes required for UAVCAN Test
- class RaiiSynchronizer {};
- uavcan::PoolAllocator _node_allocator;
-
- HAL_EventHandle _event_handle;
- AP_Int8 _test_driver_index;
- AP_Int8 _test_port;
- AP_Int32 _test_id;
- AP_Int32 _loop_rate;
- uint8_t _num_ifaces;
- bool _kdecan_enumeration;
-};
-#endif //#if HAL_MAX_CAN_PROTOCOL_DRIVERS > 1 && !HAL_MINIMIZE_FEATURES && HAL_MAX_CAN_PROTOCOL_DRIVERS
-
diff --git a/libraries/AP_CANManager/AP_CANTester_KDECAN.cpp b/libraries/AP_CANManager/AP_CANTester_KDECAN.cpp
deleted file mode 100644
index a3e7ea979aadf8..00000000000000
--- a/libraries/AP_CANManager/AP_CANTester_KDECAN.cpp
+++ /dev/null
@@ -1,236 +0,0 @@
-/*
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see .
- */
-/*
- * Author: Francisco Ferreira
- * Modified for CANManager by Siddharth B Purohit
- */
-#include
-#include
-
-#if HAL_MAX_CAN_PROTOCOL_DRIVERS > 1 && !HAL_MINIMIZE_FEATURES && HAL_CANMANAGER_ENABLED
-#include "AP_CANTester_KDECAN.h"
-#include "AP_CANManager.h"
-#include
-#include
-#include
-#include
-
-#define debug_can(level_debug, fmt, args...) do { AP::can().log_text(level_debug, "TestKDECAN", fmt, ##args); } while (0)
-extern const AP_HAL::HAL& hal;
-
-void AP_CANTester_KDECAN::count_msg(uint32_t frame_id)
-{
- for (uint16_t i=0; iis_initialized()) {
- debug_can(AP_CANManager::LOG_ERROR, "Can not initialised");
- return false;
- }
-
- if (!_can_iface->set_event_handle(&_event_handle)) {
- debug_can(AP_CANManager::LOG_ERROR, "Failed to set Event Handle");
- return false;
- }
- debug_can(AP_CANManager::LOG_ERROR, "init done");
- return true;
-}
-
-void AP_CANTester_KDECAN::loop(void)
-{
- if (_can_iface == nullptr) {
- return;
- }
-
- AP_HAL::CANFrame empty_frame { (0 | AP_HAL::CANFrame::FlagEFF), nullptr, 0 };
- bool read_select = true;
- bool write_select = false;
- bool select_ret = _can_iface->select(read_select, write_select, nullptr, AP_HAL::micros64() + 1000);
-
- if (select_ret && read_select) {
- AP_HAL::CANFrame recv_frame;
- uint64_t rx_time;
- AP_HAL::CANIface::CanIOFlags flags {};
- int16_t res = _can_iface->receive(recv_frame, rx_time, flags);
- if (res == 1) {
- uint32_t id = recv_frame.id & AP_HAL::CANFrame::MaskExtID;
- uint8_t object_address = id & 0xFF;
- uint8_t esc_num = uint8_t((id >> 8) & 0xFF);
-
- count_msg(id);
-
- uint8_t i = 0;
- uint8_t n = NUM_ESCS;
-
- if (esc_num != BROADCAST_NODE_ID) {
- for (; i < NUM_ESCS; i++) {
- if (object_address == UPDATE_NODE_ID_OBJ_ADDR) {
- uint64_t mcu_id;
- memcpy (&mcu_id, recv_frame.data, sizeof(mcu_id));
- mcu_id = be64toh(mcu_id);
- if (_esc_info[i].mcu_id == mcu_id) {
- n = i + 1;
- break;
- }
- } else if (_esc_info[i].node_id == esc_num) {
- n = i + 1;
- break;
- }
- }
- }
-
- while (i < n) {
- AP_HAL::CANFrame res_frame;
-
- switch (object_address) {
- case ESC_INFO_OBJ_ADDR: {
- uint8_t info[5] { 1, 2, 3, 4, 0 };
-
- res_frame.dlc = 5;
- memcpy(res_frame.data, info, 5);
-
- break;
- }
- case SET_PWM_OBJ_ADDR: {
- if ((1 << (esc_num - 2) & _mask_received_pwm) && _mask_received_pwm != ((1 << _max_node_id) - 1)) {
- count_msg(0xFFFFFFF0);
- _mask_received_pwm = 0;
- }
-
- _mask_received_pwm |= 1 << (esc_num - 2);
-
- if (_mask_received_pwm == ((1 << _max_node_id) - 1)) {
- count_msg(0xFFFFFFFF);
- _mask_received_pwm = 0;
- }
-
- res_frame.dlc = 0;
-
- break;
- }
- case UPDATE_NODE_ID_OBJ_ADDR: {
- if (_esc_info[i].enum_timeout_ms != 0
- && _esc_info[i].enum_timeout_ms >= AP_HAL::millis()) {
- _esc_info[i].node_id = esc_num;
- _max_node_id = MAX(_max_node_id, esc_num - 2 + 1);
- gcs().send_text(MAV_SEVERITY_ALERT, "KDECANTester: Set node ID %d for ESC %d\n", esc_num, i);
- }
-
- _esc_info[i].enum_timeout_ms = 0;
-
- res_frame.dlc = 1;
- memcpy(res_frame.data, &(_esc_info[i].node_id), 1);
-
- break;
- }
- case START_ENUM_OBJ_ADDR: {
- _esc_info[i].enum_timeout_ms = AP_HAL::millis() + be16toh_ptr(&recv_frame.data[0]);
- gcs().send_text(MAV_SEVERITY_ALERT, "KDECANTester: Starting enumeration for ESC %d, timeout %u", i, (unsigned)_esc_info[i].enum_timeout_ms);
- i++;
- continue;
- }
- case TELEMETRY_OBJ_ADDR: {
- uint8_t data[8] {};
- put_le16_ptr(&data[0], get_random16());
- put_le16_ptr(&data[2], get_random16());
- put_le16_ptr(&data[4], get_random16());
- data[6] = uint8_t(float(rand()) / RAND_MAX * 40.0f + 15);
-
- res_frame.dlc = 8;
- memcpy(res_frame.data, data, 8);
- break;
- }
- case VOLTAGE_OBJ_ADDR:
- case CURRENT_OBJ_ADDR:
- case RPM_OBJ_ADDR:
- case TEMPERATURE_OBJ_ADDR:
- case GET_PWM_INPUT_OBJ_ADDR:
- case GET_PWM_OUTPUT_OBJ_ADDR:
- case MCU_ID_OBJ_ADDR:
- default:
- // discard frame
- return;
- }
-
- res_frame.id = (_esc_info[i].node_id << 16) | object_address | AP_HAL::CANFrame::FlagEFF;
- read_select = false;
- write_select = true;
- select_ret = _can_iface->select(read_select, write_select, &res_frame, AP_HAL::micros64() + 1000);
- if (!select_ret) {
- break;
- }
- int16_t res2 = _can_iface->send(res_frame, AP_HAL::micros64() + 500000, 0);
- if (res2 == 1) {
- i++;
- } else {
- gcs().send_text(MAV_SEVERITY_ALERT, "KDECANTester: Failed to transmit frame Err: %d 0x%lx", res2, (long unsigned)res_frame.id);
- }
- }
- }
- }
-}
-
-void AP_CANTester_KDECAN::print_stats(void)
-{
- DEV_PRINTF("KDECANTester: TimeStamp: %u\n", (unsigned)AP_HAL::micros());
- for (uint16_t i=0; i<100; i++) {
- if (counters[i].frame_id == 0) {
- break;
- }
- DEV_PRINTF("0x%08x: %u\n", (unsigned)counters[i].frame_id, (unsigned)counters[i].count);
- counters[i].count = 0;
- }
-}
-
-bool AP_CANTester_KDECAN::send_enumeration(uint8_t num)
-{
- if (_esc_info[num].enum_timeout_ms == 0 ||
- AP_HAL::millis() > _esc_info[num].enum_timeout_ms) {
- _esc_info[num].enum_timeout_ms = 0;
- gcs().send_text(MAV_SEVERITY_ALERT, "KDECANTester: Not running enumeration for ESC %d\n", num);
- return false;
- }
-
- while (true) {
- uint64_t mcu = 0;
- mcu = htobe64(_esc_info[num].mcu_id);
- AP_HAL::CANFrame res_frame { (_esc_info[num].node_id << 16) | START_ENUM_OBJ_ADDR | AP_HAL::CANFrame::FlagEFF,
- (uint8_t*)&mcu,
- 8 };
- int16_t res = _can_iface->send(res_frame, AP_HAL::micros64() + 1000, 0);
- if (res == 1) {
- return true;
- }
- }
-}
-#endif
diff --git a/libraries/AP_CANManager/AP_CANTester_KDECAN.h b/libraries/AP_CANManager/AP_CANTester_KDECAN.h
deleted file mode 100644
index 0bc2d0740c7a1f..00000000000000
--- a/libraries/AP_CANManager/AP_CANTester_KDECAN.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see .
- */
-/*
- * Author: Francisco Ferreira
- * Modified for CANManager by Siddharth B Purohit
- */
-
-#include "AP_CANDriver.h"
-#include
-#include
-#if HAL_MAX_CAN_PROTOCOL_DRIVERS > 1 && !HAL_MINIMIZE_FEATURES && HAL_MAX_CAN_PROTOCOL_DRIVERS
-
-#define NUM_ESCS 4
-
-
-class AP_CANTester_KDECAN
-{
-public:
- AP_CANTester_KDECAN()
- {
- for (uint8_t i = 0; i < NUM_ESCS; i++) {
- _esc_info[i].mcu_id = 0xA5961824E7BD3C00 | i;
- }
- }
-
- bool init(AP_HAL::CANIface* can_iface);
- void loop(void);
- void print_stats(void);
- bool send_enumeration(uint8_t num);
-
-private:
- uint8_t _driver_index = 0;
- uint8_t _interface = 0;
- AP_HAL::CANIface* _can_iface;
- uint8_t _mask_received_pwm = 0;
-
- struct esc_info {
- uint8_t node_id;
- uint64_t mcu_id;
- uint32_t enum_timeout_ms;
-
- esc_info() : node_id(1), mcu_id(0), enum_timeout_ms(0) {}
- } _esc_info[NUM_ESCS];
-
- uint8_t _max_node_id = 0;
-
- static const uint8_t BROADCAST_NODE_ID = 1;
-
- static const uint8_t ESC_INFO_OBJ_ADDR = 0;
- static const uint8_t SET_PWM_OBJ_ADDR = 1;
- static const uint8_t VOLTAGE_OBJ_ADDR = 2;
- static const uint8_t CURRENT_OBJ_ADDR = 3;
- static const uint8_t RPM_OBJ_ADDR = 4;
- static const uint8_t TEMPERATURE_OBJ_ADDR = 5;
- static const uint8_t GET_PWM_INPUT_OBJ_ADDR = 6;
- static const uint8_t GET_PWM_OUTPUT_OBJ_ADDR = 7;
- static const uint8_t MCU_ID_OBJ_ADDR = 8;
- static const uint8_t UPDATE_NODE_ID_OBJ_ADDR = 9;
- static const uint8_t START_ENUM_OBJ_ADDR = 10;
- static const uint8_t TELEMETRY_OBJ_ADDR = 11;
-
- struct {
- uint32_t frame_id;
- uint32_t count;
- } counters[100];
-
- void count_msg(uint32_t frame_id);
- HAL_EventHandle _event_handle;
-};
-#endif
diff --git a/libraries/AP_CANManager/AP_SLCANIface.cpp b/libraries/AP_CANManager/AP_SLCANIface.cpp
index 0656cece984b79..f501e46b397de9 100644
--- a/libraries/AP_CANManager/AP_SLCANIface.cpp
+++ b/libraries/AP_CANManager/AP_SLCANIface.cpp
@@ -112,7 +112,7 @@ bool SLCAN::CANIface::push_Frame(AP_HAL::CANFrame &frame)
AP_HAL::CANIface::CanRxItem frm;
frm.frame = frame;
frm.flags = 0;
- frm.timestamp_us = AP_HAL::native_micros64();
+ frm.timestamp_us = AP_HAL::micros64();
return add_to_rx_queue(frm);
}
@@ -532,10 +532,10 @@ void SLCAN::CANIface::update_slcan_port()
}
if (_prev_ser_port != _slcan_ser_port) {
if (!_slcan_start_req) {
- _slcan_start_req_time = AP_HAL::native_millis();
+ _slcan_start_req_time = AP_HAL::millis();
_slcan_start_req = true;
}
- if (((AP_HAL::native_millis() - _slcan_start_req_time) < ((uint32_t)_slcan_start_delay*1000))) {
+ if (((AP_HAL::millis() - _slcan_start_req_time) < ((uint32_t)_slcan_start_delay*1000))) {
return;
}
_port = AP::serialmanager().get_serial_by_id(_slcan_ser_port);
@@ -546,12 +546,12 @@ void SLCAN::CANIface::update_slcan_port()
_port->lock_port(_serial_lock_key, _serial_lock_key);
_prev_ser_port = _slcan_ser_port;
GCS_SEND_TEXT(MAV_SEVERITY_INFO, "CANManager: Starting SLCAN Passthrough on Serial %d with CAN%d", _slcan_ser_port.get(), _iface_num);
- _last_had_activity = AP_HAL::native_millis();
+ _last_had_activity = AP_HAL::millis();
}
if (_port == nullptr) {
return;
}
- if (((AP_HAL::native_millis() - _last_had_activity) > ((uint32_t)_slcan_timeout*1000)) &&
+ if (((AP_HAL::millis() - _last_had_activity) > ((uint32_t)_slcan_timeout*1000)) &&
(uint32_t)_slcan_timeout != 0) {
_port->lock_port(0, 0);
_port = nullptr;
@@ -658,6 +658,9 @@ bool SLCAN::CANIface::select(bool &read, bool &write, const AP_HAL::CANFrame* co
return ret;
}
+ // ensure we own the UART. Locking is handled at the CAN interface level
+ _port->begin_locked(0, 0, 0, _serial_lock_key);
+
// if under passthrough, we only do send when can_iface also allows it
if (_port->available_locked(_serial_lock_key) || rx_queue_.available()) {
// allow for receiving messages over slcan
@@ -690,7 +693,7 @@ int16_t SLCAN::CANIface::send(const AP_HAL::CANFrame& frame, uint64_t tx_deadlin
) {
return ret;
}
- reportFrame(frame, AP_HAL::native_micros64());
+ reportFrame(frame, AP_HAL::micros64());
return ret;
}
@@ -705,7 +708,7 @@ int16_t SLCAN::CANIface::receive(AP_HAL::CANFrame& out_frame, uint64_t& rx_time,
if (ret > 0) {
// we also pass this frame through to slcan iface,
// and immediately return
- reportFrame(out_frame, AP_HAL::native_micros64());
+ reportFrame(out_frame, AP_HAL::micros64());
return ret;
} else if (ret < 0) {
return ret;
@@ -722,7 +725,7 @@ int16_t SLCAN::CANIface::receive(AP_HAL::CANFrame& out_frame, uint64_t& rx_time,
// flush bytes from port
while (num_bytes--) {
uint8_t b;
- if (!_port->read_locked(_serial_lock_key, b)) {
+ if (_port->read_locked(&b, 1, _serial_lock_key) != 1) {
break;
}
addByte(b);
@@ -747,7 +750,7 @@ int16_t SLCAN::CANIface::receive(AP_HAL::CANFrame& out_frame, uint64_t& rx_time,
bool read = false;
bool write = true;
_can_iface->select(read, write, &out_frame, 0); // select without blocking
- if (write && _can_iface->send(out_frame, AP_HAL::native_micros64() + 100000, out_flags) == 1) {
+ if (write && _can_iface->send(out_frame, AP_HAL::micros64() + 100000, out_flags) == 1) {
rx_queue_.pop();
num_tries = 0;
} else if (num_tries > 8) {
diff --git a/libraries/AP_CANManager/README.md b/libraries/AP_CANManager/README.md
index ae170560e885cb..67fd1352f1fc93 100644
--- a/libraries/AP_CANManager/README.md
+++ b/libraries/AP_CANManager/README.md
@@ -1,29 +1,5 @@
## Testing And Debugging
-In case unavailability of all the CAN modules that we support, I have created a CAN Driver called CANTester. Currently there are following modes inside CANTester:
-
-**1: TEST_LOOPBACK**
-
-This test verifies if the low level ifaces are functioning properly. To do that messages are sent so as to ensure TX buffers are filled to the max, and also read the data of the bus. Sequence of incoming data is tested, and also that no transmitted packet was dropped during transmit.
-
-**2: TEST_BUSOFF_RECOVERY**
-
-This test is only applicable to boards with H7 chip, where the bus off needs to be handled manually. This test is implemented to check if Bus off recovery is handled and recovered properly. Busoff error can be generated by simply shorting the CANH and CANL.
-
-**3: TEST_UAVCAN_DNA**
-
-This test simply creates a uavcan node allocation client and tries to get node allocated, the allocated node needs to match the requested node id for success. This tests AP_UAVCAN and underlying DNA library.
-
-**4: TEST_TOSHIBA_CAN**
-
-This test simply emulates a ToshibaCan ESC on a bus and handles the data sent by Toshiba CAN driver, and and also responds with ESC telemetry.
-
-**5: TEST_KDE_CAN**
-
-This test simply emulates a KDECAN ESC on a bus and handles the data sent by KDE CAN driver, and and also responds with ESC telemetry. Need to supply this command `long MAV_CMD_PREFLIGHT_UAVCAN 1` after enabling KDECAN because need to do Enumeration before use.
-
-A lot more tests will be needing to be added overtime to ensure robustness and maintainability of CAN Ecosystem.
-
**Testing under SITL**
https://github.com/linux-can/can-utils contains a nice set of utility to do CAN related testings on Linux system. I used Ubuntu for this development, for Ubuntu systems you can simply download this tool using `sudo apt-get install can-utils`
@@ -60,4 +36,4 @@ sudo cangw -A -s slcan0 -d vcan0 -e
* Dump can messages:
```
sudo candump vcan0
-```
\ No newline at end of file
+```
diff --git a/libraries/AP_Camera/AP_Camera.cpp b/libraries/AP_Camera/AP_Camera.cpp
index 0dfbb10f08f8a9..f3551bc5f19dee 100644
--- a/libraries/AP_Camera/AP_Camera.cpp
+++ b/libraries/AP_Camera/AP_Camera.cpp
@@ -4,12 +4,8 @@
#include
#include
-#include
-#include
#include
-#include
#include
-#include
#include "AP_Camera_Backend.h"
#include "AP_Camera_Servo.h"
#include "AP_Camera_Relay.h"
@@ -91,51 +87,28 @@ void AP_Camera::take_picture()
primary->take_picture();
}
-// start/stop recording video
-// start_recording should be true to start recording, false to stop recording
-bool AP_Camera::record_video(bool start_recording)
-{
- WITH_SEMAPHORE(_rsem);
-
- if (primary == nullptr) {
- return false;
- }
- return primary->record_video(start_recording);
-}
-
-// zoom in, out or hold
-// zoom out = -1, hold = 0, zoom in = 1
-bool AP_Camera::set_zoom_step(int8_t zoom_step)
-{
- WITH_SEMAPHORE(_rsem);
-
- if (primary == nullptr) {
- return false;
- }
- return primary->set_zoom_step(zoom_step);
-}
-
-// focus in, out or hold
-// focus in = -1, focus hold = 0, focus out = 1
-bool AP_Camera::set_manual_focus_step(int8_t focus_step)
+// take multiple pictures, time_interval between two consecutive pictures is in miliseconds
+// total_num is number of pictures to be taken, -1 means capture forever
+void AP_Camera::take_multiple_pictures(uint32_t time_interval_ms, int16_t total_num)
{
WITH_SEMAPHORE(_rsem);
if (primary == nullptr) {
- return false;
+ return;
}
- return primary->set_manual_focus_step(focus_step);
+ primary->take_multiple_pictures(time_interval_ms, total_num);
}
-// auto focus
-bool AP_Camera::set_auto_focus()
+// start/stop recording video
+// start_recording should be true to start recording, false to stop recording
+bool AP_Camera::record_video(bool start_recording)
{
WITH_SEMAPHORE(_rsem);
if (primary == nullptr) {
return false;
}
- return primary->set_auto_focus();
+ return primary->record_video(start_recording);
}
// detect and initialise backends
@@ -248,34 +221,62 @@ MAV_RESULT AP_Camera::handle_command_long(const mavlink_command_long_t &packet)
}
return MAV_RESULT_ACCEPTED;
case MAV_CMD_SET_CAMERA_ZOOM:
- if (is_equal(packet.param1, (float)ZOOM_TYPE_CONTINUOUS)) {
- set_zoom_step((int8_t)packet.param2);
+ if (is_equal(packet.param1, (float)ZOOM_TYPE_CONTINUOUS) &&
+ set_zoom(ZoomType::RATE, packet.param2)) {
+ return MAV_RESULT_ACCEPTED;
+ }
+ if (is_equal(packet.param1, (float)ZOOM_TYPE_RANGE) &&
+ set_zoom(ZoomType::PCT, packet.param2)) {
return MAV_RESULT_ACCEPTED;
}
return MAV_RESULT_UNSUPPORTED;
case MAV_CMD_SET_CAMERA_FOCUS:
// accept any of the auto focus types
- if (is_equal(packet.param1, (float)FOCUS_TYPE_AUTO) ||
- is_equal(packet.param1, (float)FOCUS_TYPE_AUTO_SINGLE) ||
- is_equal(packet.param1, (float)FOCUS_TYPE_AUTO_CONTINUOUS)) {
- set_auto_focus();
- return MAV_RESULT_ACCEPTED;
- }
- // accept step or continuous manual focus
- if (is_equal(packet.param1, (float)FOCUS_TYPE_CONTINUOUS)) {
- set_manual_focus_step((int8_t)packet.param2);
- return MAV_RESULT_ACCEPTED;
+ switch ((SET_FOCUS_TYPE)packet.param1) {
+ case FOCUS_TYPE_AUTO:
+ case FOCUS_TYPE_AUTO_SINGLE:
+ case FOCUS_TYPE_AUTO_CONTINUOUS:
+ return (MAV_RESULT)set_focus(FocusType::AUTO, 0);
+ case FOCUS_TYPE_CONTINUOUS:
+ // accept continuous manual focus
+ return (MAV_RESULT)set_focus(FocusType::RATE, packet.param2);
+ // accept focus as percentage
+ case FOCUS_TYPE_RANGE:
+ return (MAV_RESULT)set_focus(FocusType::PCT, packet.param2);
+ case SET_FOCUS_TYPE_ENUM_END:
+ case FOCUS_TYPE_STEP:
+ case FOCUS_TYPE_METERS:
+ // unsupported focus (bad parameter)
+ break;
}
- return MAV_RESULT_UNSUPPORTED;
+ return MAV_RESULT_DENIED;
case MAV_CMD_IMAGE_START_CAPTURE:
if (!is_zero(packet.param2) || !is_equal(packet.param3, 1.0f) || !is_zero(packet.param4)) {
- // time interval is not supported
- // multiple image capture is not supported
- // capture sequence number is not supported
- return MAV_RESULT_UNSUPPORTED;
+ // Its a multiple picture request
+ if (is_equal(packet.param3, 0.0f)) {
+ take_multiple_pictures(packet.param2*1000, -1);
+ } else {
+ take_multiple_pictures(packet.param2*1000, packet.param3);
+ }
+ return MAV_RESULT_ACCEPTED;
}
take_picture();
return MAV_RESULT_ACCEPTED;
+ case MAV_CMD_CAMERA_TRACK_POINT:
+ if (set_tracking(TrackingType::TRK_POINT, Vector2f{packet.param1, packet.param2}, Vector2f{})) {
+ return MAV_RESULT_ACCEPTED;
+ }
+ return MAV_RESULT_UNSUPPORTED;
+ case MAV_CMD_CAMERA_TRACK_RECTANGLE:
+ if (set_tracking(TrackingType::TRK_RECTANGLE, Vector2f{packet.param1, packet.param2}, Vector2f{packet.param3, packet.param4})) {
+ return MAV_RESULT_ACCEPTED;
+ }
+ return MAV_RESULT_UNSUPPORTED;
+ case MAV_CMD_CAMERA_STOP_TRACKING:
+ if (set_tracking(TrackingType::TRK_NONE, Vector2f{}, Vector2f{})) {
+ return MAV_RESULT_ACCEPTED;
+ }
+ return MAV_RESULT_UNSUPPORTED;
case MAV_CMD_VIDEO_START_CAPTURE:
case MAV_CMD_VIDEO_STOP_CAPTURE:
{
@@ -391,6 +392,32 @@ void AP_Camera::send_feedback(mavlink_channel_t chan)
}
}
+// send camera information message to GCS
+void AP_Camera::send_camera_information(mavlink_channel_t chan)
+{
+ WITH_SEMAPHORE(_rsem);
+
+ // call each instance
+ for (uint8_t instance = 0; instance < AP_CAMERA_MAX_INSTANCES; instance++) {
+ if (_backends[instance] != nullptr) {
+ _backends[instance]->send_camera_information(chan);
+ }
+ }
+}
+
+// send camera settings message to GCS
+void AP_Camera::send_camera_settings(mavlink_channel_t chan)
+{
+ WITH_SEMAPHORE(_rsem);
+
+ // call each instance
+ for (uint8_t instance = 0; instance < AP_CAMERA_MAX_INSTANCES; instance++) {
+ if (_backends[instance] != nullptr) {
+ _backends[instance]->send_camera_settings(chan);
+ }
+ }
+}
+
/*
update; triggers by distance moved and camera trigger
*/
@@ -435,9 +462,19 @@ bool AP_Camera::record_video(uint8_t instance, bool start_recording)
return backend->record_video(start_recording);
}
-// zoom in, out or hold. returns true on success
-// zoom out = -1, hold = 0, zoom in = 1
-bool AP_Camera::set_zoom_step(uint8_t instance, int8_t zoom_step)
+// zoom specified as a rate or percentage
+bool AP_Camera::set_zoom(ZoomType zoom_type, float zoom_value)
+{
+ WITH_SEMAPHORE(_rsem);
+
+ if (primary == nullptr) {
+ return false;
+ }
+ return primary->set_zoom(zoom_type, zoom_value);
+}
+
+// zoom specified as a rate or percentage
+bool AP_Camera::set_zoom(uint8_t instance, ZoomType zoom_type, float zoom_value)
{
WITH_SEMAPHORE(_rsem);
@@ -447,26 +484,78 @@ bool AP_Camera::set_zoom_step(uint8_t instance, int8_t zoom_step)
}
// call each instance
- return backend->set_zoom_step(zoom_step);
+ return backend->set_zoom(zoom_type, zoom_value);
+}
+
+
+// set focus specified as rate, percentage or auto
+// focus in = -1, focus hold = 0, focus out = 1
+SetFocusResult AP_Camera::set_focus(FocusType focus_type, float focus_value)
+{
+ WITH_SEMAPHORE(_rsem);
+
+ if (primary == nullptr) {
+ return SetFocusResult::FAILED;
+ }
+ return primary->set_focus(focus_type, focus_value);
}
-// focus in, out or hold. returns true on success
+// set focus specified as rate, percentage or auto
// focus in = -1, focus hold = 0, focus out = 1
-bool AP_Camera::set_manual_focus_step(uint8_t instance, int8_t focus_step)
+SetFocusResult AP_Camera::set_focus(uint8_t instance, FocusType focus_type, float focus_value)
{
WITH_SEMAPHORE(_rsem);
auto *backend = get_instance(instance);
if (backend == nullptr) {
+ return SetFocusResult::FAILED;
+ }
+
+ // call each instance
+ return backend->set_focus(focus_type, focus_value);
+}
+
+// set tracking to none, point or rectangle (see TrackingType enum)
+// if POINT only p1 is used, if RECTANGLE then p1 is top-left, p2 is bottom-right
+// p1,p2 are in range 0 to 1. 0 is left or top, 1 is right or bottom
+bool AP_Camera::set_tracking(TrackingType tracking_type, const Vector2f& p1, const Vector2f& p2)
+{
+ WITH_SEMAPHORE(_rsem);
+
+ if (primary == nullptr) {
return false;
}
+ return primary->set_tracking(tracking_type, p1, p2);
+}
- // call backend
- return backend->set_manual_focus_step(focus_step);
+// set tracking to none, point or rectangle (see TrackingType enum)
+// if POINT only p1 is used, if RECTANGLE then p1 is top-left, p2 is bottom-right
+// p1,p2 are in range 0 to 1. 0 is left or top, 1 is right or bottom
+bool AP_Camera::set_tracking(uint8_t instance, TrackingType tracking_type, const Vector2f& p1, const Vector2f& p2)
+{
+ WITH_SEMAPHORE(_rsem);
+
+ auto *backend = get_instance(instance);
+ if (backend == nullptr) {
+ return false;
+ }
+
+ // call each instance
+ return backend->set_tracking(tracking_type, p1, p2);
}
-// auto focus. returns true on success
-bool AP_Camera::set_auto_focus(uint8_t instance)
+// set camera lens as a value from 0 to 5
+bool AP_Camera::set_lens(uint8_t lens)
+{
+ WITH_SEMAPHORE(_rsem);
+
+ if (primary == nullptr) {
+ return false;
+ }
+ return primary->set_lens(lens);
+}
+
+bool AP_Camera::set_lens(uint8_t instance, uint8_t lens)
{
WITH_SEMAPHORE(_rsem);
@@ -475,8 +564,8 @@ bool AP_Camera::set_auto_focus(uint8_t instance)
return false;
}
- // call backend
- return backend->set_auto_focus();
+ // call instance
+ return backend->set_lens(lens);
}
#if AP_CAMERA_SCRIPTING_ENABLED
@@ -511,7 +600,7 @@ void AP_Camera::convert_params()
return;
}
- // below conversions added Feb 2023 ahead of 4.4 release
+ // PARAMETER_CONVERSION - Added: Feb-2023 ahead of 4.4 release
// convert CAM_TRIGG_TYPE to CAM1_TYPE
int8_t cam_trigg_type = 0;
diff --git a/libraries/AP_Camera/AP_Camera.h b/libraries/AP_Camera/AP_Camera.h
index 946c82824d4499..631651147f4ffd 100644
--- a/libraries/AP_Camera/AP_Camera.h
+++ b/libraries/AP_Camera/AP_Camera.h
@@ -6,23 +6,10 @@
#if AP_CAMERA_ENABLED
-#include
-#include
#include
#include
#include "AP_Camera_Params.h"
-#include "AP_Mount/AP_Mount_config.h"
-
-#if AP_CAMERA_SCRIPTING_ENABLED
- // structure and accessors for use by scripting backends
- typedef struct {
- uint16_t take_pic_incr; // incremented each time camera is requested to take a picture
- bool recording_video; // true when recording video
- int8_t zoom_step; // zoom out = -1, hold = 0, zoom in = 1
- int8_t focus_step; // focus in = -1, focus hold = 0, focus out = 1
- bool auto_focus; // true when auto focusing
- } camera_state_t;
-#endif
+#include "AP_Camera_shareddefs.h"
#define AP_CAMERA_MAX_INSTANCES 2 // maximum number of camera backends
@@ -93,11 +80,21 @@ class AP_Camera {
// update - to be called periodically at 50Hz
void update();
- // MAVLink methods
+ // handle MAVLink messages from the camera
void handle_message(mavlink_channel_t chan, const mavlink_message_t &msg);
+
+ // handle MAVLink command from GCS to control the camera
MAV_RESULT handle_command_long(const mavlink_command_long_t &packet);
+
+ // send camera feedback message to GCS
void send_feedback(mavlink_channel_t chan);
+ // send camera information message to GCS
+ void send_camera_information(mavlink_channel_t chan);
+
+ // send camera settings message to GCS
+ void send_camera_settings(mavlink_channel_t chan);
+
// configure camera
void configure(float shooting_mode, float shutter_speed, float aperture, float ISO, float exposure_type, float cmd_id, float engine_cutoff_time);
void configure(uint8_t instance, float shooting_mode, float shutter_speed, float aperture, float ISO, float exposure_type, float cmd_id, float engine_cutoff_time);
@@ -118,29 +115,51 @@ class AP_Camera {
void take_picture();
void take_picture(uint8_t instance);
+ // take multiple pictures, time_interval between two consecutive pictures is in miliseconds
+ // total_num is number of pictures to be taken, -1 means capture forever
+ void take_multiple_pictures(uint32_t time_interval_ms, int16_t total_num);
+
// start/stop recording video
// start_recording should be true to start recording, false to stop recording
bool record_video(bool start_recording);
bool record_video(uint8_t instance, bool start_recording);
- // zoom in, out or hold
- // zoom out = -1, hold = 0, zoom in = 1
- bool set_zoom_step(int8_t zoom_step);
- bool set_zoom_step(uint8_t instance, int8_t zoom_step);
+ // set zoom specified as a rate or percentage
+ bool set_zoom(ZoomType zoom_type, float zoom_value);
+ bool set_zoom(uint8_t instance, ZoomType zoom_type, float zoom_value);
- // focus in, out or hold
+ // set focus specified as rate, percentage or auto
// focus in = -1, focus hold = 0, focus out = 1
- bool set_manual_focus_step(int8_t focus_step);
- bool set_manual_focus_step(uint8_t instance, int8_t focus_step);
+ SetFocusResult set_focus(FocusType focus_type, float focus_value);
+ SetFocusResult set_focus(uint8_t instance, FocusType focus_type, float focus_value);
- // auto focus
- bool set_auto_focus();
- bool set_auto_focus(uint8_t instance);
+ // set tracking to none, point or rectangle (see TrackingType enum)
+ // if POINT only p1 is used, if RECTANGLE then p1 is top-left, p2 is bottom-right
+ // p1,p2 are in range 0 to 1. 0 is left or top, 1 is right or bottom
+ bool set_tracking(TrackingType tracking_type, const Vector2f& p1, const Vector2f& p2);
+ bool set_tracking(uint8_t instance, TrackingType tracking_type, const Vector2f& p1, const Vector2f& p2);
+
+ // set camera lens as a value from 0 to 5
+ bool set_lens(uint8_t lens);
+ bool set_lens(uint8_t instance, uint8_t lens);
// set if vehicle is in AUTO mode
void set_is_auto_mode(bool enable) { _is_in_auto_mode = enable; }
#if AP_CAMERA_SCRIPTING_ENABLED
+ // structure and accessors for use by scripting backends
+ typedef struct {
+ uint16_t take_pic_incr; // incremented each time camera is requested to take a picture
+ bool recording_video; // true when recording video
+ uint8_t zoom_type; // see ZoomType enum (1:Rate or 2:Pct)
+ float zoom_value; // percentage or zoom out = -1, hold = 0, zoom in = 1
+ uint8_t focus_type; // see FocusType enum (1:Rate, 2:Pct, 4:Auto)
+ float focus_value; // If Rate, focus in = -1, focus hold = 0, focus out = 1. If PCT 0 to 100
+ uint8_t tracking_type; // see TrackingType enum (0:NONE, 1:POINT, 2:RECTANGLE)
+ Vector2f tracking_p1; // center or top-left tracking point. x left-right, y is top-bottom. range is 0 to 1
+ Vector2f tracking_p2; // bottom-right tracking point. x left-right, y is top-bottom. range is 0 to 1
+ } camera_state_t;
+
// accessor to allow scripting backend to retrieve state
// returns true on success and cam_state is filled in
bool get_state(uint8_t instance, camera_state_t& cam_state);
diff --git a/libraries/AP_Camera/AP_Camera_Backend.cpp b/libraries/AP_Camera/AP_Camera_Backend.cpp
index ffe266e4294de1..7fd7bd261d0f87 100644
--- a/libraries/AP_Camera/AP_Camera_Backend.cpp
+++ b/libraries/AP_Camera/AP_Camera_Backend.cpp
@@ -3,6 +3,7 @@
#if AP_CAMERA_ENABLED
#include
#include
+#include
extern const AP_HAL::HAL& hal;
@@ -16,6 +17,14 @@ AP_Camera_Backend::AP_Camera_Backend(AP_Camera &frontend, AP_Camera_Params ¶
// update - should be called at 50hz
void AP_Camera_Backend::update()
{
+ // Check CAMx_OPTIONS and start/stop recording based on arm/disarm
+ if (_params.options.get() & CAMOPTIONS::REC_ARM_DISARM) {
+ if (hal.util->get_soft_armed() != last_is_armed) {
+ last_is_armed = hal.util->get_soft_armed();
+ record_video(last_is_armed);
+ }
+ }
+
// try to take picture if pending
if (trigger_pending) {
take_picture();
@@ -24,6 +33,21 @@ void AP_Camera_Backend::update()
// check feedback pin
check_feedback();
+ // time based triggering
+ // if time and distance triggering both are enabled then we only do time based triggering
+ if (time_interval_settings.num_remaining != 0) {
+ uint32_t delta_ms = AP_HAL::millis() - last_picture_time_ms;
+ if (delta_ms > time_interval_settings.time_interval_ms) {
+ if (take_picture()) {
+ // decrease num_remaining except when its -1 i.e. capture forever
+ if (time_interval_settings.num_remaining > 0) {
+ time_interval_settings.num_remaining--;
+ }
+ }
+ }
+ return;
+ }
+
// implement trigger distance
if (!is_positive(_params.trigg_dist)) {
last_location.lat = 0;
@@ -70,6 +94,32 @@ void AP_Camera_Backend::update()
take_picture();
}
+// get corresponding mount instance for the camera
+uint8_t AP_Camera_Backend::get_mount_instance() const
+{
+ // instance 0 means default
+ if (_params.mount_instance.get() == 0) {
+ return _instance;
+ }
+ return _params.mount_instance.get() - 1;
+}
+
+// get mavlink gimbal device id which is normally mount_instance+1
+uint8_t AP_Camera_Backend::get_gimbal_device_id() const
+{
+#if HAL_MOUNT_ENABLED
+ const uint8_t mount_instance = get_mount_instance();
+ AP_Mount* mount = AP::mount();
+ if (mount != nullptr) {
+ if (mount->get_mount_type(mount_instance) != AP_Mount::Type::None) {
+ return (mount_instance + 1);
+ }
+ }
+#endif
+ return 0;
+}
+
+
// take a picture. returns true on success
bool AP_Camera_Backend::take_picture()
{
@@ -78,7 +128,7 @@ bool AP_Camera_Backend::take_picture()
// check minimum time interval since last picture taken
uint32_t now_ms = AP_HAL::millis();
- if (now_ms - last_photo_time_ms < (uint32_t)(_params.interval_min * 1000)) {
+ if (now_ms - last_picture_time_ms < (uint32_t)(_params.interval_min * 1000)) {
trigger_pending = true;
return false;
}
@@ -88,7 +138,7 @@ bool AP_Camera_Backend::take_picture()
// trigger actually taking picture and update image count
if (trigger_pic()) {
image_index++;
- last_photo_time_ms = now_ms;
+ last_picture_time_ms = now_ms;
IGNORE_RETURN(AP::ahrs().get_location(last_location));
log_picture();
return true;
@@ -97,6 +147,13 @@ bool AP_Camera_Backend::take_picture()
return false;
}
+// take multiple pictures, time_interval between two consecutive pictures is in miliseconds
+// total_num is number of pictures to be taken, -1 means capture forever
+void AP_Camera_Backend::take_multiple_pictures(uint32_t time_interval_ms, int16_t total_num)
+{
+ time_interval_settings = {time_interval_ms, total_num};
+}
+
// handle camera control
void AP_Camera_Backend::control(float session, float zoom_pos, float zoom_step, float focus_lock, float shooting_cmd, float cmd_id)
{
@@ -141,6 +198,49 @@ void AP_Camera_Backend::send_camera_feedback(mavlink_channel_t chan)
camera_feedback.feedback_trigger_logged_count); // completed image captures
}
+// send camera information message to GCS
+void AP_Camera_Backend::send_camera_information(mavlink_channel_t chan) const
+{
+ // prepare vendor, model and cam definition strings
+ const uint8_t vendor_name[32] {};
+ const uint8_t model_name[32] {};
+ const char cam_definition_uri[140] {};
+ const uint32_t cap_flags = CAMERA_CAP_FLAGS_CAPTURE_IMAGE;
+ const float NaN = nanf("0x4152");
+
+ // send CAMERA_INFORMATION message
+ mavlink_msg_camera_information_send(
+ chan,
+ AP_HAL::millis(), // time_boot_ms
+ vendor_name, // vendor_name uint8_t[32]
+ model_name, // model_name uint8_t[32]
+ 0, // firmware version uint32_t
+ NaN, // focal_length float (mm)
+ NaN, // sensor_size_h float (mm)
+ NaN, // sensor_size_v float (mm)
+ 0, // resolution_h uint16_t (pix)
+ 0, // resolution_v uint16_t (pix)
+ 0, // lens_id, uint8_t
+ cap_flags, // flags uint32_t (CAMERA_CAP_FLAGS)
+ 0, // cam_definition_version uint16_t
+ cam_definition_uri, // cam_definition_uri char[140]
+ get_gimbal_device_id());// gimbal_device_id uint8_t
+}
+
+// send camera settings message to GCS
+void AP_Camera_Backend::send_camera_settings(mavlink_channel_t chan) const
+{
+ const float NaN = nanf("0x4152");
+
+ // send CAMERA_SETTINGS message
+ mavlink_msg_camera_settings_send(
+ chan,
+ AP_HAL::millis(), // time_boot_ms
+ CAMERA_MODE_IMAGE, // camera mode (0:image, 1:video, 2:image survey)
+ NaN, // zoomLevel float, percentage from 0 to 100, NaN if unknown
+ NaN); // focusLevel float, percentage from 0 to 100, NaN if unknown
+}
+
// setup a callback for a feedback pin. When on PX4 with the right FMU
// mode we can use the microsecond timer.
void AP_Camera_Backend::setup_feedback_callback()
diff --git a/libraries/AP_Camera/AP_Camera_Backend.h b/libraries/AP_Camera/AP_Camera_Backend.h
index 4db6dbebfb0743..b22b4b54b8b69e 100644
--- a/libraries/AP_Camera/AP_Camera_Backend.h
+++ b/libraries/AP_Camera/AP_Camera_Backend.h
@@ -23,6 +23,8 @@
#if AP_CAMERA_ENABLED
#include "AP_Camera.h"
+#include
+#include
class AP_Camera_Backend
{
@@ -34,6 +36,11 @@ class AP_Camera_Backend
/* Do not allow copies */
CLASS_NO_COPY(AP_Camera_Backend);
+ enum CAMOPTIONS {
+ NONE = 0,
+ REC_ARM_DISARM = 1, // Recording start/stop on Arm/Disarm
+ };
+
// init - performs any required initialisation
virtual void init() {};
@@ -49,6 +56,10 @@ class AP_Camera_Backend
// take a picture. returns true on success
bool take_picture();
+ // take multiple pictures, time_interval between two consecutive pictures is in miliseconds
+ // total_num is number of pictures to be taken, -1 means capture forever
+ void take_multiple_pictures(uint32_t time_interval_ms, int16_t total_num);
+
// entry point to actually take a picture. returns true on success
virtual bool trigger_pic() = 0;
@@ -56,18 +67,22 @@ class AP_Camera_Backend
// set start_recording = true to start record, false to stop recording
virtual bool record_video(bool start_recording) { return false; }
- // set camera zoom step. returns true on success
- // zoom out = -1, hold = 0, zoom in = 1
- virtual bool set_zoom_step(int8_t zoom_step) { return false; }
+ // set zoom specified as a rate or percentage
+ virtual bool set_zoom(ZoomType zoom_type, float zoom_value) { return false; }
- // set focus in, out or hold. returns true on success
+ // set focus specified as rate, percentage or auto
// focus in = -1, focus hold = 0, focus out = 1
- virtual bool set_manual_focus_step(int8_t focus_step) { return false; }
+ virtual SetFocusResult set_focus(FocusType focus_type, float focus_value) { return SetFocusResult::UNSUPPORTED; }
+
+ // set tracking to none, point or rectangle (see TrackingType enum)
+ // if POINT only p1 is used, if RECTANGLE then p1 is top-left, p2 is bottom-right
+ // p1,p2 are in range 0 to 1. 0 is left or top, 1 is right or bottom
+ virtual bool set_tracking(TrackingType tracking_type, const Vector2f& p1, const Vector2f& p2) { return false; }
- // auto focus. returns true on success
- virtual bool set_auto_focus() { return false; }
+ // set camera lens as a value from 0 to 5
+ virtual bool set_lens(uint8_t lens) { return false; }
- // handle incoming mavlink message
+ // handle MAVLink messages from the camera
virtual void handle_message(mavlink_channel_t chan, const mavlink_message_t &msg) {}
// configure camera
@@ -82,10 +97,16 @@ class AP_Camera_Backend
// send camera feedback message to GCS
void send_camera_feedback(mavlink_channel_t chan);
+ // send camera information message to GCS
+ virtual void send_camera_information(mavlink_channel_t chan) const;
+
+ // send camera settings message to GCS
+ virtual void send_camera_settings(mavlink_channel_t chan) const;
+
#if AP_CAMERA_SCRIPTING_ENABLED
// accessor to allow scripting backend to retrieve state
// returns true on success and cam_state is filled in
- virtual bool get_state(camera_state_t& cam_state) { return false; }
+ virtual bool get_state(AP_Camera::camera_state_t& cam_state) { return false; }
#endif
protected:
@@ -111,12 +132,24 @@ class AP_Camera_Backend
uint32_t feedback_trigger_logged_count; // ID sequence number
} camera_feedback;
+ // Picture settings
+ struct {
+ uint32_t time_interval_ms; // time interval (in miliseconds) between two consecutive pictures
+ int16_t num_remaining; // number of pictures still to be taken, -1 means take unlimited pictures
+ } time_interval_settings;
+
// Logging Function
void log_picture();
void Write_Camera(uint64_t timestamp_us=0);
void Write_Trigger();
void Write_CameraInfo(enum LogMessages msg, uint64_t timestamp_us=0);
+ // get corresponding mount instance for the camera
+ uint8_t get_mount_instance() const;
+
+ // get mavlink gimbal device id which is normally mount_instance+1
+ uint8_t get_gimbal_device_id() const;
+
// internal members
uint8_t _instance; // this instance's number
bool timer_installed; // true if feedback pin change detected using timer
@@ -126,9 +159,10 @@ class AP_Camera_Backend
uint32_t feedback_trigger_timestamp_us; // system time (in microseconds) that timer detected the feedback pin changed
uint32_t feedback_trigger_logged_count; // number of times the feedback has been logged
bool trigger_pending; // true if a call to take_pic() was delayed due to the minimum time interval time
- uint32_t last_photo_time_ms; // system time that photo was last taken
+ uint32_t last_picture_time_ms; // system time that photo was last taken
Location last_location; // Location that last picture was taken at (used for trigg_dist calculation)
uint16_t image_index; // number of pictures taken since boot
+ bool last_is_armed; // stores last arm/disarm state. true if it was armed lastly
};
#endif // AP_CAMERA_ENABLED
diff --git a/libraries/AP_Camera/AP_Camera_Logging.cpp b/libraries/AP_Camera/AP_Camera_Logging.cpp
index f6a5e26541fe4c..903f42a8a8ab58 100644
--- a/libraries/AP_Camera/AP_Camera_Logging.cpp
+++ b/libraries/AP_Camera/AP_Camera_Logging.cpp
@@ -1,11 +1,12 @@
#include "AP_Camera_Backend.h"
+#include
#if AP_CAMERA_ENABLED
#include
#include
-// Write a Camera packet
+// Write a Camera packet. Also writes a Mount packet if available
void AP_Camera_Backend::Write_CameraInfo(enum LogMessages msg, uint64_t timestamp_us)
{
// exit immediately if no logger
@@ -41,9 +42,14 @@ void AP_Camera_Backend::Write_CameraInfo(enum LogMessages msg, uint64_t timestam
altitude_gps = 0;
}
+ // if timestamp is zero set to current system time
+ if (timestamp_us == 0) {
+ timestamp_us = AP_HAL::micros64();
+ }
+
const struct log_Camera pkt{
LOG_PACKET_HEADER_INIT(static_cast(msg)),
- time_us : timestamp_us ? timestamp_us : AP_HAL::micros64(),
+ time_us : timestamp_us,
instance : _instance,
image_number: image_index,
gps_time : gps.time_week_ms(),
@@ -58,6 +64,13 @@ void AP_Camera_Backend::Write_CameraInfo(enum LogMessages msg, uint64_t timestam
yaw : (uint16_t)ahrs.yaw_sensor
};
AP::logger().WriteCriticalBlock(&pkt, sizeof(pkt));
+
+#if HAL_MOUNT_ENABLED
+ auto *mount = AP_Mount::get_singleton();
+ if (mount!= nullptr) {
+ mount->write_log(get_mount_instance(), timestamp_us);
+ }
+#endif
}
// Write a Camera packet
diff --git a/libraries/AP_Camera/AP_Camera_MAVLinkCamV2.cpp b/libraries/AP_Camera/AP_Camera_MAVLinkCamV2.cpp
index 3eb6eb67bef43e..7a1caa214fbb9d 100644
--- a/libraries/AP_Camera/AP_Camera_MAVLinkCamV2.cpp
+++ b/libraries/AP_Camera/AP_Camera_MAVLinkCamV2.cpp
@@ -23,7 +23,7 @@ void AP_Camera_MAVLinkCamV2::update()
bool AP_Camera_MAVLinkCamV2::trigger_pic()
{
// exit immediately if have not found camera or does not support taking pictures
- if (_link == nullptr || !(_cap_flags & CAMERA_CAP_FLAGS_CAPTURE_IMAGE)) {
+ if (_link == nullptr || !(_cam_info.flags & CAMERA_CAP_FLAGS_CAPTURE_IMAGE)) {
return false;
}
@@ -43,7 +43,7 @@ bool AP_Camera_MAVLinkCamV2::trigger_pic()
bool AP_Camera_MAVLinkCamV2::record_video(bool start_recording)
{
// exit immediately if have not found camera or does not support recording video
- if (_link == nullptr || !(_cap_flags & CAMERA_CAP_FLAGS_CAPTURE_VIDEO)) {
+ if (_link == nullptr || !(_cam_info.flags & CAMERA_CAP_FLAGS_CAPTURE_VIDEO)) {
return false;
}
@@ -64,63 +64,63 @@ bool AP_Camera_MAVLinkCamV2::record_video(bool start_recording)
return true;
}
-// set camera zoom step. returns true on success
-// zoom out = -1, hold = 0, zoom in = 1
-bool AP_Camera_MAVLinkCamV2::set_zoom_step(int8_t zoom_step)
+// set zoom specified as a rate or percentage
+bool AP_Camera_MAVLinkCamV2::set_zoom(ZoomType zoom_type, float zoom_value)
{
// exit immediately if have not found camera or does not support zoom
- if (_link == nullptr || !(_cap_flags & CAMERA_CAP_FLAGS_HAS_BASIC_ZOOM)) {
+ if (_link == nullptr || !(_cam_info.flags & CAMERA_CAP_FLAGS_HAS_BASIC_ZOOM)) {
return false;
}
// prepare and send message
mavlink_command_long_t pkt {};
pkt.command = MAV_CMD_SET_CAMERA_ZOOM;
- pkt.param1 = ZOOM_TYPE_CONTINUOUS; // Zoom Type, 0:ZOOM_TYPE_STEP, 1:ZOOM_TYPE_CONTINUOUS, 2:ZOOM_TYPE_RANGE, 3:ZOOM_TYPE_FOCAL_LENGTH
- pkt.param2 = zoom_step; // Zoom Value
+ switch (zoom_type) {
+ case ZoomType::RATE:
+ pkt.param1 = ZOOM_TYPE_CONTINUOUS;
+ break;
+ case ZoomType::PCT:
+ pkt.param1 = ZOOM_TYPE_RANGE;
+ break;
+ }
+ pkt.param2 = zoom_value; // Zoom Value
_link->send_message(MAVLINK_MSG_ID_COMMAND_LONG, (const char*)&pkt);
return true;
}
-// set focus in, out or hold. returns true on success
+// set focus specified as rate, percentage or auto
// focus in = -1, focus hold = 0, focus out = 1
-bool AP_Camera_MAVLinkCamV2::set_manual_focus_step(int8_t focus_step)
+SetFocusResult AP_Camera_MAVLinkCamV2::set_focus(FocusType focus_type, float focus_value)
{
// exit immediately if have not found camera or does not support focus
- if (_link == nullptr || !(_cap_flags & CAMERA_CAP_FLAGS_HAS_BASIC_FOCUS)) {
- return false;
+ if (_link == nullptr || !(_cam_info.flags & CAMERA_CAP_FLAGS_HAS_BASIC_FOCUS)) {
+ return SetFocusResult::FAILED;
}
// prepare and send message
mavlink_command_long_t pkt {};
pkt.command = MAV_CMD_SET_CAMERA_FOCUS;
- pkt.param1 = FOCUS_TYPE_CONTINUOUS; // Focus Type, 0:FOCUS_TYPE_STEP, 1:FOCUS_TYPE_CONTINUOUS, 2:FOCUS_TYPE_RANGE, 3:FOCUS_TYPE_METERS, 4:FOCUS_TYPE_AUTO, 5:FOCUS_TYPE_AUTO_SINGLE, 5:FOCUS_TYPE_AUTO_CONTINUOUS
- pkt.param2 = focus_step; // Focus Value
-
- _link->send_message(MAVLINK_MSG_ID_COMMAND_LONG, (const char*)&pkt);
-
- return true;
-}
-
-// auto focus. returns true on success
-bool AP_Camera_MAVLinkCamV2::set_auto_focus()
-{
- // exit immediately if have not found camera or does not support focus
- if (_link == nullptr || !(_cap_flags & CAMERA_CAP_FLAGS_HAS_BASIC_FOCUS)) {
- return false;
+ switch (focus_type) {
+ case FocusType::RATE:
+ // focus in, out or hold (focus in = -1, hold = 0, focus out = 1). Same as FOCUS_TYPE_CONTINUOUS
+ pkt.param1 = FOCUS_TYPE_CONTINUOUS;
+ break;
+ case FocusType::PCT:
+ // focus to a percentage (from 0 to 100) of the full range. Same as FOCUS_TYPE_RANGE
+ pkt.param1 = FOCUS_TYPE_RANGE;
+ break;
+ case FocusType::AUTO:
+ // focus automatically. Same as FOCUS_TYPE_AUTO
+ pkt.param1 = FOCUS_TYPE_AUTO;
+ break;
}
-
- // prepare and send message
- mavlink_command_long_t pkt {};
- pkt.command = MAV_CMD_SET_CAMERA_FOCUS;
- pkt.param1 = FOCUS_TYPE_AUTO; // Focus Type, 0:FOCUS_TYPE_STEP, 1:FOCUS_TYPE_CONTINUOUS, 2:FOCUS_TYPE_RANGE, 3:FOCUS_TYPE_METERS, 4:FOCUS_TYPE_AUTO, 5:FOCUS_TYPE_AUTO_SINGLE, 5:FOCUS_TYPE_AUTO_CONTINUOUS
- pkt.param2 = 0; // Focus Value
+ pkt.param2 = focus_value;
_link->send_message(MAVLINK_MSG_ID_COMMAND_LONG, (const char*)&pkt);
- return true;
+ return SetFocusResult::ACCEPTED;
}
// handle incoming mavlink message including CAMERA_INFORMATION
@@ -133,30 +133,53 @@ void AP_Camera_MAVLinkCamV2::handle_message(mavlink_channel_t chan, const mavlin
// handle CAMERA_INFORMATION
if (msg.msgid == MAVLINK_MSG_ID_CAMERA_INFORMATION) {
- mavlink_camera_information_t cam_info;
- mavlink_msg_camera_information_decode(&msg, &cam_info);
+ mavlink_msg_camera_information_decode(&msg, &_cam_info);
- const uint8_t fw_ver_major = cam_info.firmware_version & 0x000000FF;
- const uint8_t fw_ver_minor = (cam_info.firmware_version & 0x0000FF00) >> 8;
- const uint8_t fw_ver_revision = (cam_info.firmware_version & 0x00FF0000) >> 16;
- const uint8_t fw_ver_build = (cam_info.firmware_version & 0xFF000000) >> 24;
+ const uint8_t fw_ver_major = _cam_info.firmware_version & 0x000000FF;
+ const uint8_t fw_ver_minor = (_cam_info.firmware_version & 0x0000FF00) >> 8;
+ const uint8_t fw_ver_revision = (_cam_info.firmware_version & 0x00FF0000) >> 16;
+ const uint8_t fw_ver_build = (_cam_info.firmware_version & 0xFF000000) >> 24;
// display camera info to user
gcs().send_text(MAV_SEVERITY_INFO, "Camera: %s.32 %s.32 fw:%u.%u.%u.%u",
- cam_info.vendor_name,
- cam_info.model_name,
+ _cam_info.vendor_name,
+ _cam_info.model_name,
(unsigned)fw_ver_major,
(unsigned)fw_ver_minor,
(unsigned)fw_ver_revision,
(unsigned)fw_ver_build);
- // capability flags
- _cap_flags = cam_info.flags;
-
_got_camera_info = true;
}
}
+// send camera information message to GCS
+void AP_Camera_MAVLinkCamV2::send_camera_information(mavlink_channel_t chan) const
+{
+ // exit immediately if we have not yet received cam info
+ if (!_got_camera_info) {
+ return;
+ }
+
+ // send CAMERA_INFORMATION message
+ mavlink_msg_camera_information_send(
+ chan,
+ AP_HAL::millis(), // time_boot_ms
+ _cam_info.vendor_name, // vendor_name uint8_t[32]
+ _cam_info.model_name, // model_name uint8_t[32]
+ _cam_info.firmware_version, // firmware version uint32_t
+ _cam_info.focal_length, // focal_length float (mm)
+ _cam_info.sensor_size_h, // sensor_size_h float (mm)
+ _cam_info.sensor_size_v, // sensor_size_v float (mm)
+ _cam_info.resolution_h, // resolution_h uint16_t (pix)
+ _cam_info.resolution_v, // resolution_v uint16_t (pix)
+ _cam_info.lens_id, // lens_id, uint8_t
+ _cam_info.flags, // flags uint32_t (CAMERA_CAP_FLAGS)
+ _cam_info.cam_definition_version, // cam_definition_version uint16_t
+ _cam_info.cam_definition_uri, // cam_definition_uri char[140]
+ get_gimbal_device_id()); // gimbal_device_id uint8_t
+}
+
// search for camera in GCS_MAVLink routing table
void AP_Camera_MAVLinkCamV2::find_camera()
{
diff --git a/libraries/AP_Camera/AP_Camera_MAVLinkCamV2.h b/libraries/AP_Camera/AP_Camera_MAVLinkCamV2.h
index 57c991ee8abe2b..44949bc02f1fde 100644
--- a/libraries/AP_Camera/AP_Camera_MAVLinkCamV2.h
+++ b/libraries/AP_Camera/AP_Camera_MAVLinkCamV2.h
@@ -43,20 +43,19 @@ class AP_Camera_MAVLinkCamV2 : public AP_Camera_Backend
// set start_recording = true to start record, false to stop recording
bool record_video(bool start_recording) override;
- // set camera zoom step. returns true on success
- // zoom out = -1, hold = 0, zoom in = 1
- bool set_zoom_step(int8_t zoom_step) override;
+ // set zoom specified as a rate or percentage
+ bool set_zoom(ZoomType zoom_type, float zoom_value) override;
- // set focus in, out or hold. returns true on success
+ // set focus specified as rate, percentage or auto
// focus in = -1, focus hold = 0, focus out = 1
- bool set_manual_focus_step(int8_t focus_step) override;
+ SetFocusResult set_focus(FocusType focus_type, float focus_value) override;
- // auto focus. returns true on success
- bool set_auto_focus() override;
-
- // handle incoming mavlink message
+ // handle MAVLink messages from the camera
void handle_message(mavlink_channel_t chan, const mavlink_message_t &msg) override;
+ // send camera information message to GCS
+ void send_camera_information(mavlink_channel_t chan) const override;
+
private:
// search for camera in GCS_MAVLink routing table
@@ -68,11 +67,11 @@ class AP_Camera_MAVLinkCamV2 : public AP_Camera_Backend
// internal members
bool _initialised; // true once the camera has provided a CAMERA_INFORMATION
bool _got_camera_info; // true once camera has provided CAMERA_INFORMATION
+ mavlink_camera_information_t _cam_info {}; // latest camera information received from camera
uint32_t _last_caminfo_req_ms; // system time that CAMERA_INFORMATION was last requested (used to throttle requests)
class GCS_MAVLINK *_link; // link we have found the camera on. nullptr if not seen yet
uint8_t _sysid; // sysid of camera
uint8_t _compid; // component id of gimbal
- uint32_t _cap_flags; // capability flags from CAMERA_INFORMATION msg, see MAVLink CAMERA_CAP_FLAGS enum
};
#endif // AP_CAMERA_MAVLINKCAMV2_ENABLED
diff --git a/libraries/AP_Camera/AP_Camera_Mount.cpp b/libraries/AP_Camera/AP_Camera_Mount.cpp
index 31fae0378c8dc4..f85e646a9b3531 100644
--- a/libraries/AP_Camera/AP_Camera_Mount.cpp
+++ b/libraries/AP_Camera/AP_Camera_Mount.cpp
@@ -10,7 +10,7 @@ bool AP_Camera_Mount::trigger_pic()
{
AP_Mount* mount = AP::mount();
if (mount != nullptr) {
- mount->take_picture(0);
+ mount->take_picture(get_mount_instance());
return true;
}
return false;
@@ -22,41 +22,71 @@ bool AP_Camera_Mount::record_video(bool start_recording)
{
AP_Mount* mount = AP::mount();
if (mount != nullptr) {
- return mount->record_video(0, start_recording);
+ return mount->record_video(get_mount_instance(), start_recording);
}
return false;
}
-// zoom in, out or hold. returns true on success
-// zoom out = -1, hold = 0, zoom in = 1
-bool AP_Camera_Mount::set_zoom_step(int8_t zoom_step)
+// set zoom specified as a rate or percentage
+bool AP_Camera_Mount::set_zoom(ZoomType zoom_type, float zoom_value)
{
AP_Mount* mount = AP::mount();
if (mount != nullptr) {
- return mount->set_zoom_step(0, zoom_step);
+ return mount->set_zoom(get_mount_instance(), zoom_type, zoom_value);
}
return false;
}
-// focus in, out or hold. returns true on success
+// set focus specified as rate, percentage or auto
// focus in = -1, focus hold = 0, focus out = 1
-bool AP_Camera_Mount::set_manual_focus_step(int8_t focus_step)
+SetFocusResult AP_Camera_Mount::set_focus(FocusType focus_type, float focus_value)
{
AP_Mount* mount = AP::mount();
if (mount != nullptr) {
- return mount->set_manual_focus_step(0, focus_step);
+ return mount->set_focus(get_mount_instance(), focus_type, focus_value);
+ }
+ return SetFocusResult::FAILED;
+}
+
+// set tracking to none, point or rectangle (see TrackingType enum)
+// if POINT only p1 is used, if RECTANGLE then p1 is top-left, p2 is bottom-right
+// p1,p2 are in range 0 to 1. 0 is left or top, 1 is right or bottom
+bool AP_Camera_Mount::set_tracking(TrackingType tracking_type, const Vector2f& p1, const Vector2f& p2)
+{
+ AP_Mount* mount = AP::mount();
+ if (mount != nullptr) {
+ return mount->set_tracking(get_mount_instance(), tracking_type, p1, p2);
}
return false;
}
-// auto focus. returns true on success
-bool AP_Camera_Mount::set_auto_focus()
+
+// set camera lens as a value from 0 to 5
+bool AP_Camera_Mount::set_lens(uint8_t lens)
{
AP_Mount* mount = AP::mount();
if (mount != nullptr) {
- return mount->set_auto_focus(0);
+ return mount->set_lens(get_mount_instance(), lens);
}
return false;
}
+// send camera information message to GCS
+void AP_Camera_Mount::send_camera_information(mavlink_channel_t chan) const
+{
+ AP_Mount* mount = AP::mount();
+ if (mount != nullptr) {
+ return mount->send_camera_information(get_mount_instance(), chan);
+ }
+}
+
+// send camera settings message to GCS
+void AP_Camera_Mount::send_camera_settings(mavlink_channel_t chan) const
+{
+ AP_Mount* mount = AP::mount();
+ if (mount != nullptr) {
+ return mount->send_camera_settings(get_mount_instance(), chan);
+ }
+}
+
#endif // AP_CAMERA_MOUNT_ENABLED
diff --git a/libraries/AP_Camera/AP_Camera_Mount.h b/libraries/AP_Camera/AP_Camera_Mount.h
index c89c81dfc34cdc..fa53057295b8c2 100644
--- a/libraries/AP_Camera/AP_Camera_Mount.h
+++ b/libraries/AP_Camera/AP_Camera_Mount.h
@@ -39,16 +39,26 @@ class AP_Camera_Mount : public AP_Camera_Backend
// set start_recording = true to start record, false to stop recording
bool record_video(bool start_recording) override;
- // set camera zoom step. returns true on success
- // zoom out = -1, hold = 0, zoom in = 1
- bool set_zoom_step(int8_t zoom_step) override;
+ // set zoom specified as a rate or percentage
+ bool set_zoom(ZoomType zoom_type, float zoom_value) override;
- // set focus in, out or hold. returns true on success
+ // set focus specified as rate, percentage or auto
// focus in = -1, focus hold = 0, focus out = 1
- bool set_manual_focus_step(int8_t focus_step) override;
+ SetFocusResult set_focus(FocusType focus_type, float focus_value) override;
- // auto focus. returns true on success
- bool set_auto_focus() override;
+ // set tracking to none, point or rectangle (see TrackingType enum)
+ // if POINT only p1 is used, if RECTANGLE then p1 is top-left, p2 is bottom-right
+ // p1,p2 are in range 0 to 1. 0 is left or top, 1 is right or bottom
+ bool set_tracking(TrackingType tracking_type, const Vector2f& p1, const Vector2f& p2) override;
+
+ // set camera lens as a value from 0 to 5
+ bool set_lens(uint8_t lens) override;
+
+ // send camera information message to GCS
+ void send_camera_information(mavlink_channel_t chan) const override;
+
+ // send camera settings message to GCS
+ void send_camera_settings(mavlink_channel_t chan) const override;
};
#endif // AP_CAMERA_MOUNT_ENABLED
diff --git a/libraries/AP_Camera/AP_Camera_Params.cpp b/libraries/AP_Camera/AP_Camera_Params.cpp
index cd0240a92e0b29..ee3f7796590ab7 100644
--- a/libraries/AP_Camera/AP_Camera_Params.cpp
+++ b/libraries/AP_Camera/AP_Camera_Params.cpp
@@ -8,7 +8,7 @@ const AP_Param::GroupInfo AP_Camera_Params::var_info[] = {
// @Param: _TYPE
// @DisplayName: Camera shutter (trigger) type
// @Description: how to trigger the camera to take a picture
- // @Values: 1:Servo,2:Relay, 3:GoPro in Solo Gimbal, 4:Mount (Siyi), 5:MAVLink, 6:MAVLinkCamV2, 7:Scripting
+ // @Values: 0:None, 1:Servo, 2:Relay, 3:GoPro in Solo Gimbal, 4:Mount (Siyi), 5:MAVLink, 6:MAVLinkCamV2, 7:Scripting
// @User: Standard
AP_GROUPINFO_FLAGS("_TYPE", 1, AP_Camera_Params, type, 0, AP_PARAM_FLAG_ENABLE),
@@ -74,6 +74,19 @@ const AP_Param::GroupInfo AP_Camera_Params::var_info[] = {
// @User: Standard
AP_GROUPINFO("_FEEDBAK_POL", 9, AP_Camera_Params, feedback_polarity, 1),
+ // @Param: _OPTIONS
+ // @DisplayName: Camera options
+ // @Description: Camera options bitmask
+ // @Bitmask: 0:None,1: Recording Starts at arming and stops at disarming
+ // @User: Standard
+ AP_GROUPINFO("_OPTIONS", 10, AP_Camera_Params, options, 0),
+
+ // @Param: _MNT_INST
+ // @DisplayName: Camera Mount instance
+ // @Description: Mount instance camera is associated with. 0 means camera and mount have identical instance numbers e.g. camera1 and mount1
+ // @User: Standard
+ AP_GROUPINFO("_MNT_INST", 11, AP_Camera_Params, mount_instance, 0),
+
AP_GROUPEND
};
diff --git a/libraries/AP_Camera/AP_Camera_Params.h b/libraries/AP_Camera/AP_Camera_Params.h
index 5816bc55cadc93..ca54550fe1ddbe 100644
--- a/libraries/AP_Camera/AP_Camera_Params.h
+++ b/libraries/AP_Camera/AP_Camera_Params.h
@@ -21,6 +21,8 @@ class AP_Camera_Params {
AP_Float trigg_dist; // distance between trigger points (meters)
AP_Int8 relay_on; // relay value to trigger camera
AP_Float interval_min; // minimum time (in seconds) between shots required by camera
+ AP_Int8 options; // whether to start recording when armed and stop when disarmed
+ AP_Int8 mount_instance; // mount instance to which camera is associated with
// pin number for accurate camera feedback messages
AP_Int8 feedback_pin;
diff --git a/libraries/AP_Camera/AP_Camera_Scripting.cpp b/libraries/AP_Camera/AP_Camera_Scripting.cpp
index 5da821735436a9..add22ca4e46bfd 100644
--- a/libraries/AP_Camera/AP_Camera_Scripting.cpp
+++ b/libraries/AP_Camera/AP_Camera_Scripting.cpp
@@ -20,34 +20,37 @@ bool AP_Camera_Scripting::record_video(bool start_recording)
return true;
}
-// set camera zoom step. returns true on success
-// zoom out = -1, hold = 0, zoom in = 1
-bool AP_Camera_Scripting::set_zoom_step(int8_t zoom_step)
+// set zoom specified as a rate or percentage
+bool AP_Camera_Scripting::set_zoom(ZoomType zoom_type, float zoom_value)
{
- _cam_state.zoom_step = zoom_step;
+ _cam_state.zoom_type = (uint8_t)zoom_type;
+ _cam_state.zoom_value = zoom_value;
return true;
}
-// set focus in, out or hold. returns true on success
+// set focus specified as rate, percentage or auto
// focus in = -1, focus hold = 0, focus out = 1
-bool AP_Camera_Scripting::set_manual_focus_step(int8_t focus_step)
+SetFocusResult AP_Camera_Scripting::set_focus(FocusType focus_type, float focus_value)
{
- _cam_state.focus_step = focus_step;
- _cam_state.auto_focus = false;
- return true;
+ _cam_state.focus_type = (uint8_t)focus_type;
+ _cam_state.focus_value = focus_value;
+ return SetFocusResult::ACCEPTED;
}
-// auto focus. returns true on success
-bool AP_Camera_Scripting::set_auto_focus()
+// set tracking to none, point or rectangle (see TrackingType enum)
+// if POINT only p1 is used, if RECTANGLE then p1 is top-left, p2 is bottom-right
+// p1,p2 are in range 0 to 1. 0 is left or top, 1 is right or bottom
+bool AP_Camera_Scripting::set_tracking(TrackingType tracking_type, const Vector2f& p1, const Vector2f& p2)
{
- _cam_state.auto_focus = true;
- _cam_state.focus_step = 0;
+ _cam_state.tracking_type = (uint8_t)tracking_type;
+ _cam_state.tracking_p1 = p1;
+ _cam_state.tracking_p2 = p2;
return true;
}
// access for scripting backend to retrieve state
// returns true on success and cam_state is filled in
-bool AP_Camera_Scripting::get_state(camera_state_t& cam_state)
+bool AP_Camera_Scripting::get_state(AP_Camera::camera_state_t& cam_state)
{
cam_state = _cam_state;
return true;
diff --git a/libraries/AP_Camera/AP_Camera_Scripting.h b/libraries/AP_Camera/AP_Camera_Scripting.h
index 3a6f77de6dd82b..c8e8a035a6456d 100644
--- a/libraries/AP_Camera/AP_Camera_Scripting.h
+++ b/libraries/AP_Camera/AP_Camera_Scripting.h
@@ -39,24 +39,25 @@ class AP_Camera_Scripting : public AP_Camera_Backend
// set start_recording = true to start record, false to stop recording
bool record_video(bool start_recording) override;
- // set camera zoom step. returns true on success
- // zoom out = -1, hold = 0, zoom in = 1
- bool set_zoom_step(int8_t zoom_step) override;
+ // set zoom specified as a rate or percentage
+ bool set_zoom(ZoomType zoom_type, float zoom_value) override;
- // set focus in, out or hold. returns true on success
+ // set focus specified as rate, percentage or auto
// focus in = -1, focus hold = 0, focus out = 1
- bool set_manual_focus_step(int8_t focus_step) override;
+ SetFocusResult set_focus(FocusType focus_type, float focus_value) override;
- // auto focus. returns true on success
- bool set_auto_focus() override;
+ // set tracking to none, point or rectangle (see TrackingType enum)
+ // if POINT only p1 is used, if RECTANGLE then p1 is top-left, p2 is bottom-right
+ // p1,p2 are in range 0 to 1. 0 is left or top, 1 is right or bottom
+ bool set_tracking(TrackingType tracking_type, const Vector2f& p1, const Vector2f& p2) override;
// returns true on success and cam_state is filled in
- bool get_state(camera_state_t& cam_state) override;
+ bool get_state(AP_Camera::camera_state_t& cam_state) override;
private:
// current state
- camera_state_t _cam_state;
+ AP_Camera::camera_state_t _cam_state;
};
#endif // AP_CAMERA_SCRIPTING_ENABLED
diff --git a/libraries/AP_Camera/AP_Camera_SoloGimbal.h b/libraries/AP_Camera/AP_Camera_SoloGimbal.h
index 56cfd8a698aabe..4f50d3df268704 100644
--- a/libraries/AP_Camera/AP_Camera_SoloGimbal.h
+++ b/libraries/AP_Camera/AP_Camera_SoloGimbal.h
@@ -1,10 +1,10 @@
#pragma once
-#include "AP_Camera_Backend.h"
-#include
+#include "AP_Camera_config.h"
#if AP_CAMERA_SOLOGIMBAL_ENABLED
+#include "AP_Camera_Backend.h"
#include
class AP_Camera_SoloGimbal : public AP_Camera_Backend
@@ -23,7 +23,7 @@ class AP_Camera_SoloGimbal : public AP_Camera_Backend
// momentary switch to change camera between picture and video modes
void cam_mode_toggle() override;
- // handle incoming mavlink message
+ // handle MAVLink messages from the camera
void handle_message(mavlink_channel_t chan, const mavlink_message_t &msg) override;
private:
diff --git a/libraries/AP_Camera/AP_Camera_config.h b/libraries/AP_Camera/AP_Camera_config.h
index 2b8fa5afadb304..c07645112ae270 100644
--- a/libraries/AP_Camera/AP_Camera_config.h
+++ b/libraries/AP_Camera/AP_Camera_config.h
@@ -2,6 +2,7 @@
#include
#include
+#include
#ifndef AP_CAMERA_ENABLED
#define AP_CAMERA_ENABLED 1
@@ -24,7 +25,7 @@
#endif
#ifndef AP_CAMERA_RELAY_ENABLED
-#define AP_CAMERA_RELAY_ENABLED AP_CAMERA_BACKEND_DEFAULT_ENABLED
+#define AP_CAMERA_RELAY_ENABLED AP_CAMERA_BACKEND_DEFAULT_ENABLED && AP_RELAY_ENABLED
#endif
#ifndef AP_CAMERA_SERVO_ENABLED
diff --git a/libraries/AP_Camera/AP_Camera_shareddefs.h b/libraries/AP_Camera/AP_Camera_shareddefs.h
new file mode 100644
index 00000000000000..6543eff0bc8605
--- /dev/null
+++ b/libraries/AP_Camera/AP_Camera_shareddefs.h
@@ -0,0 +1,38 @@
+#pragma once
+
+// Camera related definitions required by both AP_Camera and AP_Mount are here
+// this avoids issues that would occur if AP_Mount and AP_Camera included each other
+
+#include
+
+// set zoom specified as a rate or percentage
+// enumerators match MAVLink CAMERA_ZOOM_TYPE
+enum class ZoomType : uint8_t {
+ RATE = 1, // zoom in, out or hold (zoom out = -1, hold = 0, zoom in = 1). Same as ZOOM_TYPE_CONTINUOUS
+ PCT = 2 // zoom to a percentage (from 0 to 100) of the full range. Same as ZOOM_TYPE_RANGE
+};
+
+// set focus specified as a rate or percentage
+// enumerators match MAVLink CAMERA_FOCUS_TYPE
+enum class FocusType : uint8_t {
+ RATE = 1, // focus in, out or hold (focus in = -1, hold = 0, focus out = 1). Same as FOCUS_TYPE_CONTINUOUS
+ PCT = 2, // focus to a percentage (from 0 to 100) of the full range. Same as FOCUS_TYPE_RANGE
+ AUTO = 4 // focus automatically. Same as FOCUS_TYPE_AUTO
+};
+
+// result type of set_focus. Assumptions are made that this
+// enumeration can be cast directly to MAV_RESULT.
+enum class SetFocusResult : uint8_t {
+ ACCEPTED = 0,
+ INVALID_PARAMETERS = 2, // supported but invalid parameters, like MAV_RESULT_DENIED
+ UNSUPPORTED = 3,
+ FAILED = 4,
+};
+
+// tracking types when tracking an object in the video stream
+enum class TrackingType : uint8_t {
+ TRK_NONE = 0, // tracking is inactive
+ TRK_POINT = 1, // tracking a point
+ TRK_RECTANGLE = 2 // tracking a rectangle
+};
+
diff --git a/libraries/AP_Camera/AP_RunCam.cpp b/libraries/AP_Camera/AP_RunCam.cpp
index 01cacd34da0b3a..b278d4cc7cddc7 100644
--- a/libraries/AP_Camera/AP_RunCam.cpp
+++ b/libraries/AP_Camera/AP_RunCam.cpp
@@ -791,7 +791,6 @@ void AP_RunCam::start_uart()
uart->configure_parity(0);
uart->set_stop_bits(1);
uart->set_flow_control(AP_HAL::UARTDriver::FLOW_CONTROL_DISABLE);
- uart->set_blocking_writes(false); // updates run in the main thread
uart->set_options(uart->get_options() | AP_HAL::UARTDriver::OPTION_NODMA_TX | AP_HAL::UARTDriver::OPTION_NODMA_RX);
uart->begin(115200, 10, 10);
uart->discard_input();
diff --git a/libraries/AP_CheckFirmware/AP_CheckFirmware.cpp b/libraries/AP_CheckFirmware/AP_CheckFirmware.cpp
index 940048e8b560f3..0dce6f8103d434 100644
--- a/libraries/AP_CheckFirmware/AP_CheckFirmware.cpp
+++ b/libraries/AP_CheckFirmware/AP_CheckFirmware.cpp
@@ -192,7 +192,10 @@ check_fw_result_t check_good_firmware(void)
// allows for booting of a signed firmware with an unsigned
// bootloader, which allows for bootstrapping a system up from
// unsigned to signed
- return check_good_firmware_signed();
+ const auto ret2 = check_good_firmware_signed();
+ if (ret2 == check_fw_result_t::CHECK_FW_OK) {
+ return check_fw_result_t::CHECK_FW_OK;
+ }
}
return ret;
#endif
diff --git a/libraries/AP_Common/AP_Common.cpp b/libraries/AP_Common/AP_Common.cpp
index 19c403c353bf0d..19f2002ac41214 100644
--- a/libraries/AP_Common/AP_Common.cpp
+++ b/libraries/AP_Common/AP_Common.cpp
@@ -22,6 +22,9 @@
extern const AP_HAL::HAL& hal;
+/* assert that const vals are float, not double. so 100.0 means 100.0f */
+static_assert(sizeof(1e6) == sizeof(float), "Compilation needs to use single-precision constants");
+
/*
Return true if value is between lower and upper bound inclusive.
False otherwise.
diff --git a/libraries/AP_Common/AP_Common.h b/libraries/AP_Common/AP_Common.h
index fb2fdfc9ceb033..5949ca14cf63ab 100644
--- a/libraries/AP_Common/AP_Common.h
+++ b/libraries/AP_Common/AP_Common.h
@@ -178,3 +178,4 @@ template void BIT_CLEAR (T& value, uint8_t bitnumber) noexcept {
static_assert(std::is_integral::value, "Integral required.");
((value) &= ~((T)(1U) << (bitnumber)));
}
+
diff --git a/libraries/AP_Common/tests/test_expandingstring_failure.cpp b/libraries/AP_Common/tests/test_expandingstring_failure.cpp
index 98702789f4cdad..81b54f132cba29 100644
--- a/libraries/AP_Common/tests/test_expandingstring_failure.cpp
+++ b/libraries/AP_Common/tests/test_expandingstring_failure.cpp
@@ -52,6 +52,7 @@ class BufferPrinter : public AP_HAL::BetterStream {
bool discard_input() override { return false; }
};
+void print_vprintf(AP_HAL::BetterStream *s, const char *fmt, va_list ap);
void print_vprintf(AP_HAL::BetterStream *s, const char *fmt, va_list ap) {
BufferPrinter* p = static_cast(s);
if (count < 2) {
diff --git a/libraries/AP_Common/tests/test_location.cpp b/libraries/AP_Common/tests/test_location.cpp
index fa29927a567054..0c484e20d42384 100644
--- a/libraries/AP_Common/tests/test_location.cpp
+++ b/libraries/AP_Common/tests/test_location.cpp
@@ -63,7 +63,7 @@ TEST(Location, LatLngWrapping)
int32_t expected_lat;
int32_t expected_lng;
} tests[] {
- {519634000, 1797560000, Vector2f{0, 100000}, 519634000, -1787860775}
+ {519634000, 1797560000, Vector2f{0, 100000}, 519634000, -1787860777}
};
for (auto &test : tests) {
@@ -98,7 +98,7 @@ TEST(Location, LocOffsetDouble)
-353632620, 1491652373,
Vector2d{4682795.4576701336, 5953662.7673837934},
Vector2d{4682797.1904749088, 5953664.1586009059},
- Vector2d{1.7365739867091179,1.2050807},
+ Vector2d{1.7365739,1.4261966},
};
for (auto &test : tests) {
@@ -282,8 +282,10 @@ TEST(Location, Distance)
EXPECT_VECTOR2F_EQ(Vector3f(0, 0, 0), test_home.get_distance_NED(test_home));
EXPECT_VECTOR2F_EQ(Vector3f(-11.131885, 0, 0), test_home.get_distance_NED(test_home2));
Location test_loc = test_home;
- test_loc.offset(-11.131885, 0);
+ test_loc.offset(-11.131886, 0);
EXPECT_TRUE(test_loc.same_latlon_as(test_home2));
+ test_loc = test_home;
+ test_loc.offset(-11.131885, 0);
test_loc.offset_bearing(0, 11.131885);
EXPECT_TRUE(test_loc.same_latlon_as(test_home));
diff --git a/libraries/AP_Common/tests/test_nmea_print.cpp b/libraries/AP_Common/tests/test_nmea_print.cpp
index 58e232804f6c31..139e55d6e8c28a 100644
--- a/libraries/AP_Common/tests/test_nmea_print.cpp
+++ b/libraries/AP_Common/tests/test_nmea_print.cpp
@@ -6,24 +6,23 @@ const AP_HAL::HAL& hal = AP_HAL::get_HAL();
class DummyUart: public AP_HAL::UARTDriver {
public:
- void begin(uint32_t baud) override { };
- void begin(uint32_t baud, uint16_t rxSpace, uint16_t txSpace) override { };
- void end() override { };
- void flush() override { };
bool is_initialized() override { return true; };
- void set_blocking_writes(bool blocking) override { };
bool tx_pending() override { return false; };
- uint32_t available() override { return 1; };
uint32_t txspace() override { return _txspace; };
- bool read(uint8_t &c) override { return false; };
- bool discard_input() override { return true; };
- size_t write(uint8_t c) override { return 1; };
- size_t write(const uint8_t *buffer, size_t size) override { return 1; };
void set_txspace(uint32_t space) {
_txspace = space;
}
uint32_t _txspace;
+
+protected:
+ uint32_t _available() override { return 1; };
+ void _begin(uint32_t baud, uint16_t rxSpace, uint16_t txSpace) override { };
+ void _end() override { };
+ void _flush() override { };
+ size_t _write(const uint8_t *buffer, size_t size) override { return 1; };
+ ssize_t _read(uint8_t *buf, uint16_t count) override { return 0; };
+ bool _discard_input() override { return false; }
};
static DummyUart test_uart;
diff --git a/libraries/AP_Common/tests/test_nmea_vaprint.cpp b/libraries/AP_Common/tests/test_nmea_vaprint.cpp
index ba719234a56793..cc4a63dbbac0b2 100644
--- a/libraries/AP_Common/tests/test_nmea_vaprint.cpp
+++ b/libraries/AP_Common/tests/test_nmea_vaprint.cpp
@@ -31,6 +31,7 @@ class BufferPrinter : public AP_HAL::BetterStream {
bool discard_input() override { return false; }
};
+void print_vprintf(AP_HAL::BetterStream *s, const char *fmt, va_list ap);
void print_vprintf(AP_HAL::BetterStream *s, const char *fmt, va_list ap) {
BufferPrinter* p = static_cast(s);
count++;
@@ -44,24 +45,22 @@ void print_vprintf(AP_HAL::BetterStream *s, const char *fmt, va_list ap) {
class DummyUart: public AP_HAL::UARTDriver {
public:
- void begin(uint32_t baud) override { };
- void begin(uint32_t baud, uint16_t rxSpace, uint16_t txSpace) override { };
- void end() override { };
- void flush() override { };
bool is_initialized() override { return true; };
- void set_blocking_writes(bool blocking) override { };
bool tx_pending() override { return false; };
- uint32_t available() override { return 1; };
uint32_t txspace() override { return _txspace; };
- bool read(uint8_t &c) override { return false; };
- bool discard_input() override { return true; };
- size_t write(uint8_t c) override { return 1; };
- size_t write(const uint8_t *buffer, size_t size) override { return 1; };
void set_txspace(uint32_t space) {
_txspace = space;
}
uint32_t _txspace;
+protected:
+ void _begin(uint32_t baud, uint16_t rxSpace, uint16_t txSpace) override { };
+ ssize_t _read(uint8_t *buf, uint16_t size) override { return 0; };
+ void _end() override { };
+ void _flush() override { };
+ uint32_t _available() override { return 1; };
+ size_t _write(const uint8_t *buffer, size_t size) override { return 1; };
+ bool _discard_input() override { return false; }
};
static DummyUart test_uart;
diff --git a/libraries/AP_Common/tests/test_sorting.cpp b/libraries/AP_Common/tests/test_sorting.cpp
index d44f3b14dce296..025a61294c88c6 100644
--- a/libraries/AP_Common/tests/test_sorting.cpp
+++ b/libraries/AP_Common/tests/test_sorting.cpp
@@ -10,6 +10,8 @@
#if CONFIG_HAL_BOARD == HAL_BOARD_SITL || CONFIG_HAL_BOARD == HAL_BOARD_LINUX
+typedef int (*compare_fn_t)(const void*, const void*);
+
static int comp16(const uint16_t *v1, const uint16_t *v2) {
return int32_t(*v1) - int32_t(*v2);
}
@@ -32,7 +34,7 @@ TEST(Sorting, sort)
a1[j] = a2[j] = unsigned(random()) % maxval;
}
insertion_sort_uint16(a1, n);
- qsort(a2, n, sizeof(uint16_t), (__compar_fn_t)comp16);
+ qsort(a2, n, sizeof(uint16_t), (compare_fn_t)comp16);
check_equal(a1, a2, n);
}
}
diff --git a/libraries/AP_Common/tests/wscript b/libraries/AP_Common/tests/wscript
index 067612ac36691a..555f58b53a4b0f 100644
--- a/libraries/AP_Common/tests/wscript
+++ b/libraries/AP_Common/tests/wscript
@@ -4,9 +4,5 @@
def build(bld):
bld.ap_find_tests(
use='ap',
+ DOUBLE_PRECISION_SOURCES = ['test_location.cpp']
)
-
-# location test needs double precision
-def configure(cfg):
- cfg.env.DOUBLE_PRECISION_SOURCES['AP_Common'] = ['tests/test_location.cpp']
-
diff --git a/libraries/AP_Common/time.cpp b/libraries/AP_Common/time.cpp
new file mode 100644
index 00000000000000..81f81b0cfdc54a
--- /dev/null
+++ b/libraries/AP_Common/time.cpp
@@ -0,0 +1,44 @@
+#include "time.h"
+
+/*
+ mktime replacement from Samba
+ */
+time_t ap_mktime(const struct tm *t)
+{
+ time_t epoch = 0;
+ int n;
+ int mon [] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, y, m, i;
+ const unsigned MINUTE = 60;
+ const unsigned HOUR = 60*MINUTE;
+ const unsigned DAY = 24*HOUR;
+ const unsigned YEAR = 365*DAY;
+
+ if (t->tm_year < 70) {
+ return (time_t)-1;
+ }
+
+ n = t->tm_year + 1900 - 1;
+ epoch = (t->tm_year - 70) * YEAR +
+ ((n / 4 - n / 100 + n / 400) - (1969 / 4 - 1969 / 100 + 1969 / 400)) * DAY;
+
+ y = t->tm_year + 1900;
+ m = 0;
+
+ for (i = 0; i < t->tm_mon; i++) {
+ epoch += mon [m] * DAY;
+ if (m == 1 && y % 4 == 0 && (y % 100 != 0 || y % 400 == 0)) {
+ epoch += DAY;
+ }
+
+ if (++m > 11) {
+ m = 0;
+ y++;
+ }
+ }
+
+ epoch += (t->tm_mday - 1) * DAY;
+ epoch += t->tm_hour * HOUR + t->tm_min * MINUTE + t->tm_sec;
+
+ return epoch;
+}
+
diff --git a/libraries/AP_Common/time.h b/libraries/AP_Common/time.h
new file mode 100644
index 00000000000000..e25748f5b9f0cc
--- /dev/null
+++ b/libraries/AP_Common/time.h
@@ -0,0 +1,6 @@
+#pragma once
+
+#include
+
+// replacement for mktime()
+time_t ap_mktime(const struct tm *t);
diff --git a/libraries/AP_Compass/AP_Compass.cpp b/libraries/AP_Compass/AP_Compass.cpp
index f2c9e48c5045c7..cab4a834d61a56 100644
--- a/libraries/AP_Compass/AP_Compass.cpp
+++ b/libraries/AP_Compass/AP_Compass.cpp
@@ -588,6 +588,7 @@ const AP_Param::GroupInfo Compass::var_info[] = {
// @DisplayName: Compass options
// @Description: This sets options to change the behaviour of the compass
// @Bitmask: 0:CalRequireGPS
+ // @Bitmask: 1: Allow missing DroneCAN compasses to be automaticaly replaced (calibration still required)
// @User: Advanced
AP_GROUPINFO("OPTIONS", 43, Compass, _options, 0),
@@ -1175,12 +1176,10 @@ void Compass::_probe_external_i2c_compasses(void)
// IST8310 on external and internal bus
if (AP_BoardConfig::get_board_type() != AP_BoardConfig::PX4_BOARD_FMUV5 &&
AP_BoardConfig::get_board_type() != AP_BoardConfig::PX4_BOARD_FMUV6) {
- enum Rotation default_rotation;
+ enum Rotation default_rotation = AP_COMPASS_IST8310_DEFAULT_ROTATION;
if (AP_BoardConfig::get_board_type() == AP_BoardConfig::PX4_BOARD_AEROFC) {
default_rotation = ROTATION_PITCH_180_YAW_90;
- } else {
- default_rotation = ROTATION_PITCH_180;
}
// probe all 4 possible addresses
const uint8_t ist8310_addr[] = { 0x0C, 0x0D, 0x0E, 0x0F };
@@ -1464,56 +1463,58 @@ void Compass::_detect_backends(void)
}
#if COMPASS_MAX_UNREG_DEV > 0
- // check if there's any uavcan compass in prio slot that's not found
- // and replace it if there's a replacement compass
- for (Priority i(0); i AP_COMPASS_MAX_XYZ_ANG_DIFF) {
return false;
}
// check for an unacceptable angle difference on the xy plane
+ const float xy_ang_diff = mag_field_xy.angle(primary_mag_field_xy);
if (xy_ang_diff > AP_COMPASS_MAX_XY_ANG_DIFF) {
return false;
}
// check for an unacceptable length difference on the xy plane
+ const float xy_len_diff = (primary_mag_field_xy-mag_field_xy).length();
if (xy_len_diff > AP_COMPASS_MAX_XY_LENGTH_DIFF) {
return false;
}
@@ -2078,6 +2067,11 @@ bool Compass::consistent() const
return true;
}
+bool Compass::healthy(uint8_t i) const
+{
+ return (i < COMPASS_MAX_INSTANCES) ? _get_state(Priority(i)).healthy : false;
+}
+
/*
return true if we have a valid scale factor
*/
diff --git a/libraries/AP_Compass/AP_Compass.h b/libraries/AP_Compass/AP_Compass.h
index 53d760404d07e9..92e98f5fe1aa77 100644
--- a/libraries/AP_Compass/AP_Compass.h
+++ b/libraries/AP_Compass/AP_Compass.h
@@ -196,7 +196,7 @@ friend class AP_Compass_Backend;
/*
handle an incoming MAG_CAL command
*/
- MAV_RESULT handle_mag_cal_command(const mavlink_command_long_t &packet);
+ MAV_RESULT handle_mag_cal_command(const mavlink_command_int_t &packet);
bool send_mag_cal_progress(const class GCS_MAVLINK& link);
bool send_mag_cal_report(const class GCS_MAVLINK& link);
@@ -205,7 +205,7 @@ friend class AP_Compass_Backend;
bool consistent() const;
/// Return the health of a compass
- bool healthy(uint8_t i) const { return _get_state(Priority(i)).healthy; }
+ bool healthy(uint8_t i) const;
bool healthy(void) const { return healthy(_first_usable); }
uint8_t get_healthy_mask() const;
@@ -607,7 +607,9 @@ friend class AP_Compass_Backend;
// bitmask of options
enum class Option : uint16_t {
CAL_REQUIRE_GPS = (1U<<0),
+ ALLOW_DRONECAN_AUTO_REPLACEMENT = (1U<<1),
};
+ bool option_set(Option opt) const { return (_options.get() & uint16_t(opt)) != 0; }
AP_Int16 _options;
#if COMPASS_CAL_ENABLED
diff --git a/libraries/AP_Compass/AP_Compass_Calibration.cpp b/libraries/AP_Compass/AP_Compass_Calibration.cpp
index 9943fc87402db5..bd6d0299784be7 100644
--- a/libraries/AP_Compass/AP_Compass_Calibration.cpp
+++ b/libraries/AP_Compass/AP_Compass_Calibration.cpp
@@ -70,7 +70,7 @@ bool Compass::_start_calibration(uint8_t i, bool retry, float delay)
}
}
- if (_options.get() & uint16_t(Option::CAL_REQUIRE_GPS)) {
+ if (option_set(Option::CAL_REQUIRE_GPS)) {
if (AP::gps().status() < AP_GPS::GPS_OK_FIX_2D) {
gcs().send_text(MAV_SEVERITY_ERROR, "Compass cal requires GPS lock");
return false;
@@ -371,7 +371,7 @@ uint8_t Compass::_get_cal_mask()
/*
handle an incoming MAG_CAL command
*/
-MAV_RESULT Compass::handle_mag_cal_command(const mavlink_command_long_t &packet)
+MAV_RESULT Compass::handle_mag_cal_command(const mavlink_command_int_t &packet)
{
MAV_RESULT result = MAV_RESULT_FAILED;
@@ -392,7 +392,7 @@ MAV_RESULT Compass::handle_mag_cal_command(const mavlink_command_long_t &packet)
bool retry = !is_zero(packet.param2);
bool autosave = !is_zero(packet.param3);
float delay = packet.param4;
- bool autoreboot = !is_zero(packet.param5);
+ bool autoreboot = packet.x != 0;
if (mag_mask == 0) { // 0 means all
_reset_compass_id();
diff --git a/libraries/AP_Compass/AP_Compass_IST8310.h b/libraries/AP_Compass/AP_Compass_IST8310.h
index abc01e0df8891f..96d061a9c2d334 100644
--- a/libraries/AP_Compass/AP_Compass_IST8310.h
+++ b/libraries/AP_Compass/AP_Compass_IST8310.h
@@ -31,6 +31,10 @@
#define HAL_COMPASS_IST8310_I2C_ADDR 0x0E
#endif
+#ifndef AP_COMPASS_IST8310_DEFAULT_ROTATION
+#define AP_COMPASS_IST8310_DEFAULT_ROTATION ROTATION_PITCH_180
+#endif
+
class AP_Compass_IST8310 : public AP_Compass_Backend
{
public:
diff --git a/libraries/AP_Compass/AP_Compass_config.h b/libraries/AP_Compass/AP_Compass_config.h
index 72ae8a411c9c9e..3fb16fe0d3837d 100644
--- a/libraries/AP_Compass/AP_Compass_config.h
+++ b/libraries/AP_Compass/AP_Compass_config.h
@@ -4,13 +4,17 @@
#include
#include
+#ifndef AP_COMPASS_ENABLED
+#define AP_COMPASS_ENABLED 1
+#endif
+
#ifndef AP_COMPASS_DIAGONALS_ENABLED
#define AP_COMPASS_DIAGONALS_ENABLED 1
#endif
// Backend support
#ifndef AP_COMPASS_BACKEND_DEFAULT_ENABLED
-#define AP_COMPASS_BACKEND_DEFAULT_ENABLED 1
+#define AP_COMPASS_BACKEND_DEFAULT_ENABLED AP_COMPASS_ENABLED
#endif
#ifndef AP_COMPASS_EXTERNALAHRS_ENABLED
diff --git a/libraries/AP_DAL/AP_DAL.cpp b/libraries/AP_DAL/AP_DAL.cpp
index 8e2b6fe87b7dab..8942a6e46d170a 100644
--- a/libraries/AP_DAL/AP_DAL.cpp
+++ b/libraries/AP_DAL/AP_DAL.cpp
@@ -352,6 +352,17 @@ void AP_DAL::writeExtNavData(const Vector3f &pos, const Quaternion &quat, float
WRITE_REPLAY_BLOCK_IFCHANGED(REPH, _REPH, old);
}
+void AP_DAL::log_SetLatLng(const Location &loc, float posAccuracy, uint32_t timestamp_ms)
+{
+ end_frame();
+ const log_RSLL old = _RSLL;
+ _RSLL.lat = loc.lat;
+ _RSLL.lng = loc.lng;
+ _RSLL.posAccSD = posAccuracy;
+ _RSLL.timestamp_ms = timestamp_ms;
+ WRITE_REPLAY_BLOCK_IFCHANGED(RSLL, _RSLL, old);
+}
+
// log external velocity data
void AP_DAL::writeExtNavVelData(const Vector3f &vel, float err, uint32_t timeStamp_ms, uint16_t delay_ms)
{
@@ -485,6 +496,17 @@ void AP_DAL::handle_message(const log_RBOH &msg, NavEKF2 &ekf2, NavEKF3 &ekf3)
// note that EKF2 does not support body frame odomotry
ekf3.writeBodyFrameOdom(msg.quality, msg.delPos, msg.delAng, msg.delTime, msg.timeStamp_ms, msg.delay_ms, msg.posOffset);
}
+
+/*
+ handle position reset
+ */
+void AP_DAL::handle_message(const log_RSLL &msg, NavEKF2 &ekf2, NavEKF3 &ekf3)
+{
+ _RSLL = msg;
+ // note that EKF2 does not support body frame odomotry
+ const Location loc {msg.lat, msg.lng, 0, Location::AltFrame::ABSOLUTE };
+ ekf3.setLatLng(loc, msg.posAccSD, msg.timestamp_ms);
+}
#endif // APM_BUILD_Replay
namespace AP {
diff --git a/libraries/AP_DAL/AP_DAL.h b/libraries/AP_DAL/AP_DAL.h
index 8b86a4122d3604..ddf643bcf6e33b 100644
--- a/libraries/AP_DAL/AP_DAL.h
+++ b/libraries/AP_DAL/AP_DAL.h
@@ -82,6 +82,8 @@ class AP_DAL {
void log_event3(Event event);
void log_SetOriginLLH3(const Location &loc);
+ void log_SetLatLng(const Location &loc, float posAccuracy, uint32_t timestamp_ms);
+
void log_writeDefaultAirSpeed3(const float aspeed, const float uncertainty);
void log_writeEulerYawAngle(float yawAngle, float yawAngleErr, uint32_t timeStamp_ms, uint8_t type);
@@ -317,6 +319,7 @@ class AP_DAL {
void handle_message(const log_REVH &msg, NavEKF2 &ekf2, NavEKF3 &ekf3);
void handle_message(const log_RWOH &msg, NavEKF2 &ekf2, NavEKF3 &ekf3);
void handle_message(const log_RBOH &msg, NavEKF2 &ekf2, NavEKF3 &ekf3);
+ void handle_message(const log_RSLL &msg, NavEKF2 &ekf2, NavEKF3 &ekf3);
// map core number for replay
uint8_t logging_core(uint8_t c) const;
@@ -340,6 +343,7 @@ class AP_DAL {
struct log_REVH _REVH;
struct log_RWOH _RWOH;
struct log_RBOH _RBOH;
+ struct log_RSLL _RSLL;
// cached variables for speed:
uint32_t _micros;
diff --git a/libraries/AP_DAL/LogStructure.h b/libraries/AP_DAL/LogStructure.h
index e391a6dcf44698..14942768f35c1f 100644
--- a/libraries/AP_DAL/LogStructure.h
+++ b/libraries/AP_DAL/LogStructure.h
@@ -35,6 +35,7 @@
LOG_RMGI_MSG, \
LOG_ROFH_MSG, \
LOG_REPH_MSG, \
+ LOG_RSLL_MSG, \
LOG_REVH_MSG, \
LOG_RWOH_MSG, \
LOG_RBOH_MSG
@@ -324,6 +325,16 @@ struct log_REPH {
uint8_t _end;
};
+// @LoggerMessage: RSLL
+// @Description: Replay Set Lat Lng event
+struct log_RSLL {
+ int32_t lat; // WGS-84 latitude in 1E-7 degrees
+ int32_t lng; // WGS-84 longitude in 1E7 degrees
+ float posAccSD; // horizontal position 1 STD uncertainty (m)
+ uint32_t timestamp_ms;
+ uint8_t _end;
+};
+
// @LoggerMessage: REVH
// @Description: Replay external position data
struct log_REVH {
@@ -417,6 +428,8 @@ struct log_RBOH {
"ROFH", "ffffIffffB", "FX,FY,GX,GY,Tms,PX,PY,PZ,HgtOvr,Qual", "----------", "----------" }, \
{ LOG_REPH_MSG, RLOG_SIZE(REPH), \
"REPH", "fffffffffIIH", "PX,PY,PZ,Q1,Q2,Q3,Q4,PEr,AEr,TS,RT,D", "------------", "------------" }, \
+ { LOG_RSLL_MSG, RLOG_SIZE(RSLL), \
+ "RSLL", "IIfI", "Lat,Lng,PosAccSD,TS", "DU--", "GG--" }, \
{ LOG_REVH_MSG, RLOG_SIZE(REVH), \
"REVH", "ffffIH", "VX,VY,VZ,Er,TS,D", "------", "------" }, \
{ LOG_RWOH_MSG, RLOG_SIZE(RWOH), \
diff --git a/libraries/AP_DDS/AP_DDS_Client.cpp b/libraries/AP_DDS/AP_DDS_Client.cpp
index db47b5ed7ecf29..2e9fe202392698 100644
--- a/libraries/AP_DDS/AP_DDS_Client.cpp
+++ b/libraries/AP_DDS/AP_DDS_Client.cpp
@@ -5,30 +5,63 @@
#include
#include
#include
-#include
+#include
#include
+#include
+#include
+#include
+#include
+#if AP_EXTERNAL_CONTROL_ENABLED
+#include "AP_DDS_ExternalControl.h"
+#endif
+#include "AP_DDS_Frames.h"
#include "AP_DDS_Client.h"
-#include "generated/Time.h"
-
+#include "AP_DDS_Topic_Table.h"
+#include "AP_DDS_Service_Table.h"
+#include "AP_DDS_External_Odom.h"
+// Enable DDS at runtime by default
+static constexpr uint8_t ENABLED_BY_DEFAULT = 1;
static constexpr uint16_t DELAY_TIME_TOPIC_MS = 10;
-static constexpr uint16_t DELAY_NAV_SAT_FIX_TOPIC_MS = 1000;
-static char WGS_84_FRAME_ID[] = "WGS-84";
-// https://www.ros.org/reps/rep-0105.html#base-link
-static char BASE_LINK_FRAME_ID[] = "base_link";
-
-AP_HAL::UARTDriver *dds_port;
-
-
-const AP_Param::GroupInfo AP_DDS_Client::var_info[]= {
- //! @todo Params go here
+static constexpr uint16_t DELAY_BATTERY_STATE_TOPIC_MS = 1000;
+static constexpr uint16_t DELAY_LOCAL_POSE_TOPIC_MS = 33;
+static constexpr uint16_t DELAY_LOCAL_VELOCITY_TOPIC_MS = 33;
+static constexpr uint16_t DELAY_GEO_POSE_TOPIC_MS = 33;
+static constexpr uint16_t DELAY_CLOCK_TOPIC_MS = 10;
+
+// Define the subscriber data members, which are static class scope.
+// If these are created on the stack in the subscriber,
+// the AP_DDS_Client::on_topic frame size is exceeded.
+sensor_msgs_msg_Joy AP_DDS_Client::rx_joy_topic {};
+tf2_msgs_msg_TFMessage AP_DDS_Client::rx_dynamic_transforms_topic {};
+geometry_msgs_msg_TwistStamped AP_DDS_Client::rx_velocity_control_topic {};
+
+
+const AP_Param::GroupInfo AP_DDS_Client::var_info[] {
+
+ // @Param: _ENABLE
+ // @DisplayName: DDS enable
+ // @Description: Enable DDS subsystem
+ // @Values: 0:Disabled,1:Enabled
+ // @RebootRequired: True
+ // @User: Advanced
+ AP_GROUPINFO_FLAGS("_ENABLE", 1, AP_DDS_Client, enabled, ENABLED_BY_DEFAULT, AP_PARAM_FLAG_ENABLE),
+
+#if AP_DDS_UDP_ENABLED
+ // @Param: _UDP_PORT
+ // @DisplayName: DDS UDP port
+ // @Description: UDP port number for DDS
+ // @Range: 1 65535
+ // @RebootRequired: True
+ // @User: Standard
+ AP_GROUPINFO("_PORT", 2, AP_DDS_Client, udp.port, 2019),
+
+#endif
AP_GROUPEND
};
-#include "AP_DDS_Topic_Table.h"
-
void AP_DDS_Client::update_topic(builtin_interfaces_msg_Time& msg)
{
uint64_t utc_usec;
@@ -40,7 +73,7 @@ void AP_DDS_Client::update_topic(builtin_interfaces_msg_Time& msg)
}
-void AP_DDS_Client::update_topic(sensor_msgs_msg_NavSatFix& msg, const uint8_t instance)
+bool AP_DDS_Client::update_topic(sensor_msgs_msg_NavSatFix& msg, const uint8_t instance)
{
// Add a lambda that takes in navsatfix msg and populates the cov
// Make it constexpr if possible
@@ -49,14 +82,9 @@ void AP_DDS_Client::update_topic(sensor_msgs_msg_NavSatFix& msg, const uint8_t i
// assert(instance >= GPS_MAX_RECEIVERS);
if (instance >= GPS_MAX_RECEIVERS) {
- return;
+ return false;
}
- update_topic(msg.header.stamp);
- strcpy(msg.header.frame_id, WGS_84_FRAME_ID);
- msg.status.service = 0; // SERVICE_GPS
- msg.status.status = -1; // STATUS_NO_FIX
-
auto &gps = AP::gps();
WITH_SEMAPHORE(gps.get_semaphore());
@@ -64,10 +92,24 @@ void AP_DDS_Client::update_topic(sensor_msgs_msg_NavSatFix& msg, const uint8_t i
msg.status.status = -1; // STATUS_NO_FIX
msg.status.service = 0; // No services supported
msg.position_covariance_type = 0; // COVARIANCE_TYPE_UNKNOWN
- return;
+ return false;
+ }
+
+ // No update is needed
+ const auto last_fix_time_ms = gps.last_fix_time_ms(instance);
+ if (last_nav_sat_fix_time_ms == last_fix_time_ms) {
+ return false;
+ } else {
+ last_nav_sat_fix_time_ms = last_fix_time_ms;
}
+ update_topic(msg.header.stamp);
+ strcpy(msg.header.frame_id, WGS_84_FRAME_ID);
+ msg.status.service = 0; // SERVICE_GPS
+ msg.status.status = -1; // STATUS_NO_FIX
+
+
//! @todo What about glonass, compass, galileo?
//! This will be properly designed and implemented to spec in #23277
msg.status.service = 1; // SERVICE_GPS
@@ -78,21 +120,17 @@ void AP_DDS_Client::update_topic(sensor_msgs_msg_NavSatFix& msg, const uint8_t i
case AP_GPS::NO_FIX:
msg.status.status = -1; // STATUS_NO_FIX
msg.position_covariance_type = 0; // COVARIANCE_TYPE_UNKNOWN
- return;
+ return true;
case AP_GPS::GPS_OK_FIX_2D:
case AP_GPS::GPS_OK_FIX_3D:
msg.status.status = 0; // STATUS_FIX
- msg.position_covariance_type = 1; // COVARIANCE_TYPE_APPROXIMATED
break;
case AP_GPS::GPS_OK_FIX_3D_DGPS:
msg.status.status = 1; // STATUS_SBAS_FIX
- msg.position_covariance_type = 1; // COVARIANCE_TYPE_APPROXIMATED
break;
case AP_GPS::GPS_OK_FIX_3D_RTK_FLOAT:
case AP_GPS::GPS_OK_FIX_3D_RTK_FIXED:
msg.status.status = 2; // STATUS_SBAS_FIX
- msg.position_covariance_type = 1; // COVARIANCE_TYPE_APPROXIMATED
- // RTK provides "rtk_accuracy" member, should it be used for the covariance?
break;
default:
//! @todo Can we not just use an enum class and not worry about this condition?
@@ -107,24 +145,25 @@ void AP_DDS_Client::update_topic(sensor_msgs_msg_NavSatFix& msg, const uint8_t i
// With absolute frame, this condition is unlikely
msg.status.status = -1; // STATUS_NO_FIX
msg.position_covariance_type = 0; // COVARIANCE_TYPE_UNKNOWN
- return;
+ return true;
}
- msg.altitude = alt_cm / 100.0;
-
- // Calculate covariance: https://answers.ros.org/question/10310/calculate-navsatfix-covariance/
- // https://github.com/ros-drivers/nmea_navsat_driver/blob/indigo-devel/src/libnmea_navsat_driver/driver.py#L110-L114
- //! @todo This calculation will be moved to AP::gps and fixed in #23259
- //! It is a placeholder for now matching the ROS1 nmea_navsat_driver behavior
- const auto hdop = gps.get_hdop(instance);
- const auto hdopSq = hdop * hdop;
- const auto vdop = gps.get_vdop(instance);
- const auto vdopSq = vdop * vdop;
- msg.position_covariance[0] = hdopSq;
- msg.position_covariance[4] = hdopSq;
- msg.position_covariance[8] = vdopSq;
-}
+ msg.altitude = alt_cm * 0.01;
+
+ // ROS allows double precision, ArduPilot exposes float precision today
+ Matrix3f cov;
+ msg.position_covariance_type = (uint8_t)gps.position_covariance(instance, cov);
+ msg.position_covariance[0] = cov[0][0];
+ msg.position_covariance[1] = cov[0][1];
+ msg.position_covariance[2] = cov[0][2];
+ msg.position_covariance[3] = cov[1][0];
+ msg.position_covariance[4] = cov[1][1];
+ msg.position_covariance[5] = cov[1][2];
+ msg.position_covariance[6] = cov[2][0];
+ msg.position_covariance[7] = cov[2][1];
+ msg.position_covariance[8] = cov[2][2];
-#include "generated/TransformStamped.h"
+ return true;
+}
void AP_DDS_Client::populate_static_transforms(tf2_msgs_msg_TFMessage& msg)
{
@@ -163,23 +202,347 @@ void AP_DDS_Client::populate_static_transforms(tf2_msgs_msg_TFMessage& msg)
msg.transforms_size++;
}
- // msg.transforms[0] = transform;
+}
+
+void AP_DDS_Client::update_topic(sensor_msgs_msg_BatteryState& msg, const uint8_t instance)
+{
+ if (instance >= AP_BATT_MONITOR_MAX_INSTANCES) {
+ return;
+ }
+
+ update_topic(msg.header.stamp);
+ auto &battery = AP::battery();
+
+ if (!battery.healthy(instance)) {
+ msg.power_supply_status = 3; //POWER_SUPPLY_HEALTH_DEAD
+ msg.present = false;
+ return;
+ }
+ msg.present = true;
+
+ msg.voltage = battery.voltage(instance);
+
+ float temperature;
+ msg.temperature = (battery.get_temperature(temperature, instance)) ? temperature : NAN;
+
+ float current;
+ msg.current = (battery.current_amps(current, instance)) ? -1 * current : NAN;
+
+ const float design_capacity = (float)battery.pack_capacity_mah(instance) * 0.001;
+ msg.design_capacity = design_capacity;
+
+ uint8_t percentage;
+ if (battery.capacity_remaining_pct(percentage, instance)) {
+ msg.percentage = percentage * 0.01;
+ msg.charge = (percentage * design_capacity) * 0.01;
+ } else {
+ msg.percentage = NAN;
+ msg.charge = NAN;
+ }
+
+ msg.capacity = NAN;
+
+ if (battery.current_amps(current, instance)) {
+ if (percentage == 100) {
+ msg.power_supply_status = 4; //POWER_SUPPLY_STATUS_FULL
+ } else if (current < 0.0) {
+ msg.power_supply_status = 1; //POWER_SUPPLY_STATUS_CHARGING
+ } else if (current > 0.0) {
+ msg.power_supply_status = 2; //POWER_SUPPLY_STATUS_DISCHARGING
+ } else {
+ msg.power_supply_status = 3; //POWER_SUPPLY_STATUS_NOT_CHARGING
+ }
+ } else {
+ msg.power_supply_status = 0; //POWER_SUPPLY_STATUS_UNKNOWN
+ }
+
+ msg.power_supply_health = (battery.overpower_detected(instance)) ? 4 : 1; //POWER_SUPPLY_HEALTH_OVERVOLTAGE or POWER_SUPPLY_HEALTH_GOOD
+
+ msg.power_supply_technology = 0; //POWER_SUPPLY_TECHNOLOGY_UNKNOWN
+
+ if (battery.has_cell_voltages(instance)) {
+ const uint16_t* cellVoltages = battery.get_cell_voltages(instance).cells;
+ std::copy(cellVoltages, cellVoltages + AP_BATT_MONITOR_CELLS_MAX, msg.cell_voltage);
+ }
+}
+
+void AP_DDS_Client::update_topic(geometry_msgs_msg_PoseStamped& msg)
+{
+ update_topic(msg.header.stamp);
+ strcpy(msg.header.frame_id, BASE_LINK_FRAME_ID);
+
+ auto &ahrs = AP::ahrs();
+ WITH_SEMAPHORE(ahrs.get_semaphore());
+
+ // ROS REP 103 uses the ENU convention:
+ // X - East
+ // Y - North
+ // Z - Up
+ // https://www.ros.org/reps/rep-0103.html#axis-orientation
+ // AP_AHRS uses the NED convention
+ // X - North
+ // Y - East
+ // Z - Down
+ // As a consequence, to follow ROS REP 103, it is necessary to switch X and Y,
+ // as well as invert Z
+
+ Vector3f position;
+ if (ahrs.get_relative_position_NED_home(position)) {
+ msg.pose.position.x = position[1];
+ msg.pose.position.y = position[0];
+ msg.pose.position.z = -position[2];
+ }
+
+ // In ROS REP 103, axis orientation uses the following convention:
+ // X - Forward
+ // Y - Left
+ // Z - Up
+ // https://www.ros.org/reps/rep-0103.html#axis-orientation
+ // As a consequence, to follow ROS REP 103, it is necessary to switch X and Y,
+ // as well as invert Z (NED to ENU convertion) as well as a 90 degree rotation in the Z axis
+ // for x to point forward
+ Quaternion orientation;
+ if (ahrs.get_quaternion(orientation)) {
+ Quaternion aux(orientation[0], orientation[2], orientation[1], -orientation[3]); //NED to ENU transformation
+ Quaternion transformation (sqrtF(2) * 0.5,0,0,sqrtF(2) * 0.5); // Z axis 90 degree rotation
+ orientation = aux * transformation;
+ msg.pose.orientation.w = orientation[0];
+ msg.pose.orientation.x = orientation[1];
+ msg.pose.orientation.y = orientation[2];
+ msg.pose.orientation.z = orientation[3];
+ }
+}
+void AP_DDS_Client::update_topic(geometry_msgs_msg_TwistStamped& msg)
+{
+ update_topic(msg.header.stamp);
+ strcpy(msg.header.frame_id, BASE_LINK_FRAME_ID);
+
+ auto &ahrs = AP::ahrs();
+ WITH_SEMAPHORE(ahrs.get_semaphore());
+
+ // ROS REP 103 uses the ENU convention:
+ // X - East
+ // Y - North
+ // Z - Up
+ // https://www.ros.org/reps/rep-0103.html#axis-orientation
+ // AP_AHRS uses the NED convention
+ // X - North
+ // Y - East
+ // Z - Down
+ // As a consequence, to follow ROS REP 103, it is necessary to switch X and Y,
+ // as well as invert Z
+ Vector3f velocity;
+ if (ahrs.get_velocity_NED(velocity)) {
+ msg.twist.linear.x = velocity[1];
+ msg.twist.linear.y = velocity[0];
+ msg.twist.linear.z = -velocity[2];
+ }
+ // In ROS REP 103, axis orientation uses the following convention:
+ // X - Forward
+ // Y - Left
+ // Z - Up
+ // https://www.ros.org/reps/rep-0103.html#axis-orientation
+ // The gyro data is received from AP_AHRS in body-frame
+ // X - Forward
+ // Y - Right
+ // Z - Down
+ // As a consequence, to follow ROS REP 103, it is necessary to invert Y and Z
+ Vector3f angular_velocity = ahrs.get_gyro();
+ msg.twist.angular.x = angular_velocity[0];
+ msg.twist.angular.y = -angular_velocity[1];
+ msg.twist.angular.z = -angular_velocity[2];
+}
- // const auto offset = AP::GPS::
+void AP_DDS_Client::update_topic(geographic_msgs_msg_GeoPoseStamped& msg)
+{
+ update_topic(msg.header.stamp);
+ strcpy(msg.header.frame_id, BASE_LINK_FRAME_ID);
+
+ auto &ahrs = AP::ahrs();
+ WITH_SEMAPHORE(ahrs.get_semaphore());
+
+ Location loc;
+ if (ahrs.get_location(loc)) {
+ msg.pose.position.latitude = loc.lat * 1E-7;
+ msg.pose.position.longitude = loc.lng * 1E-7;
+ msg.pose.position.altitude = loc.alt * 0.01; // Transform from cm to m
+ }
+
+ // In ROS REP 103, axis orientation uses the following convention:
+ // X - Forward
+ // Y - Left
+ // Z - Up
+ // https://www.ros.org/reps/rep-0103.html#axis-orientation
+ // As a consequence, to follow ROS REP 103, it is necessary to switch X and Y,
+ // as well as invert Z (NED to ENU convertion) as well as a 90 degree rotation in the Z axis
+ // for x to point forward
+ Quaternion orientation;
+ if (ahrs.get_quaternion(orientation)) {
+ Quaternion aux(orientation[0], orientation[2], orientation[1], -orientation[3]); //NED to ENU transformation
+ Quaternion transformation(sqrtF(2) * 0.5, 0, 0, sqrtF(2) * 0.5); // Z axis 90 degree rotation
+ orientation = aux * transformation;
+ msg.pose.orientation.w = orientation[0];
+ msg.pose.orientation.x = orientation[1];
+ msg.pose.orientation.y = orientation[2];
+ msg.pose.orientation.z = orientation[3];
+ }
}
+void AP_DDS_Client::update_topic(rosgraph_msgs_msg_Clock& msg)
+{
+ update_topic(msg.clock);
+}
/*
- class constructor
+ start the DDS thread
*/
-AP_DDS_Client::AP_DDS_Client(void)
+bool AP_DDS_Client::start(void)
{
+ AP_Param::setup_object_defaults(this, var_info);
+ AP_Param::load_object_from_eeprom(this, var_info);
+
+ if (enabled == 0) {
+ return true;
+ }
+
if (!hal.scheduler->thread_create(FUNCTOR_BIND_MEMBER(&AP_DDS_Client::main_loop, void),
"DDS",
8192, AP_HAL::Scheduler::PRIORITY_IO, 1)) {
GCS_SEND_TEXT(MAV_SEVERITY_ERROR,"DDS Client: thread create failed");
+ return false;
+ }
+ return true;
+}
+
+// read function triggered at every subscription callback
+void AP_DDS_Client::on_topic_trampoline(uxrSession* uxr_session, uxrObjectId object_id, uint16_t request_id, uxrStreamId stream_id, struct ucdrBuffer* ub, uint16_t length,
+ void* args)
+{
+ AP_DDS_Client *dds = (AP_DDS_Client *)args;
+ dds->on_topic(uxr_session, object_id, request_id, stream_id, ub, length);
+}
+
+void AP_DDS_Client::on_topic(uxrSession* uxr_session, uxrObjectId object_id, uint16_t request_id, uxrStreamId stream_id, struct ucdrBuffer* ub, uint16_t length)
+{
+ /*
+ TEMPLATE for reading to the subscribed topics
+ 1) Store the read contents into the ucdr buffer
+ 2) Deserialize the said contents into the topic instance
+ */
+ (void) uxr_session;
+ (void) request_id;
+ (void) stream_id;
+ (void) length;
+ switch (object_id.id) {
+ case topics[to_underlying(TopicIndex::JOY_SUB)].dr_id.id: {
+ const bool success = sensor_msgs_msg_Joy_deserialize_topic(ub, &rx_joy_topic);
+
+ if (success == false) {
+ break;
+ }
+
+ subscribe_sample_count++;
+ if (rx_joy_topic.axes_size >= 4) {
+ GCS_SEND_TEXT(MAV_SEVERITY_INFO,"Received sensor_msgs/Joy: %f, %f, %f, %f",
+ rx_joy_topic.axes[0], rx_joy_topic.axes[1], rx_joy_topic.axes[2], rx_joy_topic.axes[3]);
+ // TODO implement joystick RC control to AP
+ } else {
+ GCS_SEND_TEXT(MAV_SEVERITY_INFO,"Received sensor_msgs/Joy: Insufficient axes size ");
+ }
+ break;
+ }
+ case topics[to_underlying(TopicIndex::DYNAMIC_TRANSFORMS_SUB)].dr_id.id: {
+ const bool success = tf2_msgs_msg_TFMessage_deserialize_topic(ub, &rx_dynamic_transforms_topic);
+ if (success == false) {
+ break;
+ }
+
+ subscribe_sample_count++;
+ if (rx_dynamic_transforms_topic.transforms_size > 0) {
+#if AP_DDS_VISUALODOM_ENABLED
+ AP_DDS_External_Odom::handle_external_odom(rx_dynamic_transforms_topic);
+#endif // AP_DDS_VISUALODOM_ENABLED
+
+ } else {
+ GCS_SEND_TEXT(MAV_SEVERITY_INFO,"Received tf2_msgs/TFMessage: Insufficient size ");
+ }
+ break;
+ }
+ case topics[to_underlying(TopicIndex::VELOCITY_CONTROL_SUB)].dr_id.id: {
+ const bool success = geometry_msgs_msg_TwistStamped_deserialize_topic(ub, &rx_velocity_control_topic);
+ if (success == false) {
+ break;
+ }
+
+ subscribe_sample_count++;
+#if AP_EXTERNAL_CONTROL_ENABLED
+ if (!AP_DDS_External_Control::handle_velocity_control(rx_velocity_control_topic)) {
+ // TODO #23430 handle velocity control failure through rosout, throttled.
+ }
+#endif // AP_EXTERNAL_CONTROL_ENABLED
+ break;
+ }
+ }
+
+}
+
+/*
+ callback on request completion
+ */
+void AP_DDS_Client::on_request_trampoline(uxrSession* uxr_session, uxrObjectId object_id, uint16_t request_id, SampleIdentity* sample_id, ucdrBuffer* ub, uint16_t length, void* args)
+{
+ AP_DDS_Client *dds = (AP_DDS_Client *)args;
+ dds->on_request(uxr_session, object_id, request_id, sample_id, ub, length);
+}
+
+void AP_DDS_Client::on_request(uxrSession* uxr_session, uxrObjectId object_id, uint16_t request_id, SampleIdentity* sample_id, ucdrBuffer* ub, uint16_t length)
+{
+ (void) request_id;
+ (void) length;
+ switch (object_id.id) {
+ case services[to_underlying(ServiceIndex::ARMING_MOTORS)].rep_id: {
+ bool arm;
+ bool result;
+ const bool deserialize_success = ucdr_deserialize_bool(ub,&arm);
+ if (deserialize_success == false) {
+ break;
+ }
+
+ if (arm) {
+ GCS_SEND_TEXT(MAV_SEVERITY_INFO,"Request for arming received");
+ result = AP::arming().arm(AP_Arming::Method::DDS);
+ } else {
+ GCS_SEND_TEXT(MAV_SEVERITY_INFO,"Request for disarming received");
+ result = AP::arming().disarm(AP_Arming::Method::DDS);
+ }
+
+ const uxrObjectId replier_id = {
+ .id = services[to_underlying(ServiceIndex::ARMING_MOTORS)].rep_id,
+ .type = UXR_REPLIER_ID
+ };
+
+ //Todo : Fix the size-handling of services with the help of the functions autogenerated via Micro-XRCE-DDS Gen
+ uint8_t reply_buffer[8] {};
+ ucdrBuffer reply_ub;
+
+ ucdr_init_buffer(&reply_ub, reply_buffer, sizeof(reply_buffer));
+ const bool serialize_success = ucdr_serialize_bool(&reply_ub,result);
+ if (serialize_success == false) {
+ break;
+ }
+
+ request_sample_count++;
+
+ uxr_buffer_reply(uxr_session, reliable_out, replier_id, sample_id, reply_buffer, ucdr_buffer_length(&reply_ub));
+ if (result) {
+ GCS_SEND_TEXT(MAV_SEVERITY_INFO,"DDS Client: Request for Arming/Disarming : SUCCESS");
+ } else {
+ GCS_SEND_TEXT(MAV_SEVERITY_INFO,"DDS Client: Request for Arming/Disarming : FAIL");
+ }
+ break;
+ }
}
}
@@ -194,7 +557,7 @@ void AP_DDS_Client::main_loop(void)
}
GCS_SEND_TEXT(MAV_SEVERITY_INFO,"DDS Client: Initialization passed");
- populate_static_transforms(static_transforms_topic);
+ populate_static_transforms(tx_static_transforms_topic);
write_static_transforms();
while (true) {
@@ -203,35 +566,49 @@ void AP_DDS_Client::main_loop(void)
}
}
-
bool AP_DDS_Client::init()
{
- AP_SerialManager *serial_manager = AP_SerialManager::get_singleton();
- dds_port = serial_manager->find_serial(AP_SerialManager::SerialProtocol_DDS_XRCE, 0);
- if (dds_port == nullptr) {
- return false;
+ // serial init will fail if the SERIALn_PROTOCOL is not setup
+ bool initTransportStatus = ddsSerialInit();
+ is_using_serial = initTransportStatus;
+
+#if AP_DDS_UDP_ENABLED
+ // fallback to UDP if available
+ if (!initTransportStatus) {
+ initTransportStatus = ddsUdpInit();
}
+#endif
- // ensure we own the UART
- dds_port->begin(0);
-
- constexpr uint8_t fd = 0;
- constexpr uint8_t relativeSerialAgentAddr = 0;
- constexpr uint8_t relativeSerialClientAddr = 1;
- if (!uxr_init_serial_transport(&serial_transport,fd,relativeSerialAgentAddr,relativeSerialClientAddr)) {
+ if (!initTransportStatus) {
+ GCS_SEND_TEXT(MAV_SEVERITY_INFO,"DDS Client: Transport Initialization failed");
return false;
}
- constexpr uint32_t uniqueClientKey = 0xAAAABBBB;
- //TODO does this need to be inside the loop to handle reconnect?
- uxr_init_session(&session, &serial_transport.comm, uniqueClientKey);
+ // Register topic callbacks
+ uxr_set_topic_callback(&session, AP_DDS_Client::on_topic_trampoline, this);
+
+ // ROS-2 Service : Register service request callbacks
+ uxr_set_request_callback(&session, AP_DDS_Client::on_request_trampoline, this);
+
while (!uxr_create_session(&session)) {
GCS_SEND_TEXT(MAV_SEVERITY_INFO,"DDS Client: Initialization waiting...");
hal.scheduler->delay(1000);
}
- reliable_in = uxr_create_input_reliable_stream(&session,input_reliable_stream,BUFFER_SIZE_SERIAL,STREAM_HISTORY);
- reliable_out = uxr_create_output_reliable_stream(&session,output_reliable_stream,BUFFER_SIZE_SERIAL,STREAM_HISTORY);
+ // setup reliable stream buffers
+ input_reliable_stream = new uint8_t[DDS_BUFFER_SIZE];
+ if (input_reliable_stream == nullptr) {
+ GCS_SEND_TEXT(MAV_SEVERITY_ERROR,"DDS Client: allocation failed");
+ return false;
+ }
+ output_reliable_stream = new uint8_t[DDS_BUFFER_SIZE];
+ if (output_reliable_stream == nullptr) {
+ GCS_SEND_TEXT(MAV_SEVERITY_ERROR,"DDS Client: allocation failed");
+ return false;
+ }
+
+ reliable_in = uxr_create_input_reliable_stream(&session, input_reliable_stream, DDS_BUFFER_SIZE, DDS_STREAM_HISTORY);
+ reliable_out = uxr_create_output_reliable_stream(&session, output_reliable_stream, DDS_BUFFER_SIZE, DDS_STREAM_HISTORY);
GCS_SEND_TEXT(MAV_SEVERITY_INFO,"DDS Client: Init Complete");
@@ -254,8 +631,8 @@ bool AP_DDS_Client::create()
constexpr uint8_t nRequestsParticipant = 1;
const uint16_t requestsParticipant[nRequestsParticipant] = {participant_req_id};
- constexpr int maxTimeMsPerRequestMs = 250;
- constexpr int requestTimeoutParticipantMs = nRequestsParticipant * maxTimeMsPerRequestMs;
+ constexpr uint8_t maxTimeMsPerRequestMs = 250;
+ constexpr uint16_t requestTimeoutParticipantMs = (uint16_t) nRequestsParticipant * maxTimeMsPerRequestMs;
uint8_t statusParticipant[nRequestsParticipant];
if (!uxr_run_session_until_all_status(&session, requestTimeoutParticipantMs, requestsParticipant, statusParticipant, nRequestsParticipant)) {
GCS_SEND_TEXT(MAV_SEVERITY_ERROR,"XRCE Client: Participant session request failure");
@@ -263,7 +640,7 @@ bool AP_DDS_Client::create()
return false;
}
- for (size_t i = 0 ; i < ARRAY_SIZE(topics); i++) {
+ for (uint16_t i = 0 ; i < ARRAY_SIZE(topics); i++) {
// Topic
const uxrObjectId topic_id = {
.id = topics[i].topic_id,
@@ -272,32 +649,101 @@ bool AP_DDS_Client::create()
const char* topic_ref = topics[i].topic_profile_label;
const auto topic_req_id = uxr_buffer_create_topic_ref(&session,reliable_out,topic_id,participant_id,topic_ref,UXR_REPLACE);
- // Publisher
- const uxrObjectId pub_id = {
- .id = topics[i].pub_id,
- .type = UXR_PUBLISHER_ID
- };
- const char* pub_xml = "";
- const auto pub_req_id = uxr_buffer_create_publisher_xml(&session,reliable_out,pub_id,participant_id,pub_xml,UXR_REPLACE);
-
- // Data Writer
- const char* data_writer_ref = topics[i].dw_profile_label;
- const auto dwriter_req_id = uxr_buffer_create_datawriter_ref(&session,reliable_out,topics[i].dw_id,pub_id,data_writer_ref,UXR_REPLACE);
-
// Status requests
constexpr uint8_t nRequests = 3;
- const uint16_t requests[nRequests] = {topic_req_id, pub_req_id, dwriter_req_id};
- constexpr int requestTimeoutMs = nRequests * maxTimeMsPerRequestMs;
+ uint16_t requests[nRequests];
+ constexpr uint16_t requestTimeoutMs = nRequests * maxTimeMsPerRequestMs;
uint8_t status[nRequests];
- if (!uxr_run_session_until_all_status(&session, requestTimeoutMs, requests, status, nRequests)) {
- GCS_SEND_TEXT(MAV_SEVERITY_ERROR,"XRCE Client: Topic/Pub/Writer session request failure for index 'TODO'");
- for (int s = 0 ; s < nRequests; s++) {
- GCS_SEND_TEXT(MAV_SEVERITY_ERROR,"XRCE Client: Status '%d' result '%u'", s, status[s]);
+
+ if (strlen(topics[i].dw_profile_label) > 0) {
+ // Publisher
+ const uxrObjectId pub_id = {
+ .id = topics[i].pub_id,
+ .type = UXR_PUBLISHER_ID
+ };
+ const char* pub_xml = "";
+ const auto pub_req_id = uxr_buffer_create_publisher_xml(&session,reliable_out,pub_id,participant_id,pub_xml,UXR_REPLACE);
+
+ // Data Writer
+ const char* data_writer_ref = topics[i].dw_profile_label;
+ const auto dwriter_req_id = uxr_buffer_create_datawriter_ref(&session,reliable_out,topics[i].dw_id,pub_id,data_writer_ref,UXR_REPLACE);
+
+ // save the request statuses
+ requests[0] = topic_req_id;
+ requests[1] = pub_req_id;
+ requests[2] = dwriter_req_id;
+
+ if (!uxr_run_session_until_all_status(&session, requestTimeoutMs, requests, status, nRequests)) {
+ GCS_SEND_TEXT(MAV_SEVERITY_ERROR,"XRCE Client: Topic/Pub/Writer session request failure for index '%u'",i);
+ for (uint8_t s = 0 ; s < nRequests; s++) {
+ GCS_SEND_TEXT(MAV_SEVERITY_ERROR,"XRCE Client: Status '%d' result '%u'", s, status[s]);
+ }
+ // TODO add a failure log message sharing the status results
+ return false;
+ } else {
+ GCS_SEND_TEXT(MAV_SEVERITY_INFO,"XRCE Client: Topic/Pub/Writer session pass for index '%u'",i);
}
- // TODO add a failure log message sharing the status results
- return false;
- } else {
- GCS_SEND_TEXT(MAV_SEVERITY_INFO,"XRCE Client: Topic/Pub/Writer session pass for index 'TOOO'");
+ } else if (strlen(topics[i].dr_profile_label) > 0) {
+ // Subscriber
+ const uxrObjectId sub_id = {
+ .id = topics[i].sub_id,
+ .type = UXR_SUBSCRIBER_ID
+ };
+ const char* sub_xml = "";
+ const auto sub_req_id = uxr_buffer_create_subscriber_xml(&session,reliable_out,sub_id,participant_id,sub_xml,UXR_REPLACE);
+
+ // Data Reader
+ const char* data_reader_ref = topics[i].dr_profile_label;
+ const auto dreader_req_id = uxr_buffer_create_datareader_ref(&session,reliable_out,topics[i].dr_id,sub_id,data_reader_ref,UXR_REPLACE);
+
+ // save the request statuses
+ requests[0] = topic_req_id;
+ requests[1] = sub_req_id;
+ requests[2] = dreader_req_id;
+
+ if (!uxr_run_session_until_all_status(&session, requestTimeoutMs, requests, status, nRequests)) {
+ GCS_SEND_TEXT(MAV_SEVERITY_ERROR,"XRCE Client: Topic/Sub/Reader session request failure for index '%u'",i);
+ for (uint8_t s = 0 ; s < nRequests; s++) {
+ GCS_SEND_TEXT(MAV_SEVERITY_ERROR,"XRCE Client: Status '%d' result '%u'", s, status[s]);
+ }
+ // TODO add a failure log message sharing the status results
+ return false;
+ } else {
+ GCS_SEND_TEXT(MAV_SEVERITY_INFO,"XRCE Client: Topic/Sub/Reader session pass for index '%u'",i);
+ uxr_buffer_request_data(&session, reliable_out, topics[i].dr_id, reliable_in, &delivery_control);
+ }
+ }
+ }
+
+ // ROS-2 Service : else case for service requests
+
+ for (uint16_t i = 0; i < ARRAY_SIZE(services); i++) {
+
+ constexpr uint16_t requestTimeoutMs = maxTimeMsPerRequestMs;
+
+ if (strlen(services[i].rep_profile_label) > 0) {
+ const uxrObjectId rep_id = {
+ .id = services[i].rep_id,
+ .type = UXR_REPLIER_ID
+ };
+ const char* replier_ref = services[i].rep_profile_label;
+ const auto replier_req_id = uxr_buffer_create_replier_ref(&session, reliable_out, rep_id, participant_id, replier_ref, UXR_REPLACE);
+
+ uint16_t request = replier_req_id;
+ uint8_t status;
+
+ if (!uxr_run_session_until_all_status(&session, requestTimeoutMs, &request, &status, 1)) {
+ GCS_SEND_TEXT(MAV_SEVERITY_ERROR,"XRCE Client: Service/Replier session request failure for index '%u'",i);
+ GCS_SEND_TEXT(MAV_SEVERITY_ERROR,"XRCE Client: Status result '%u'", status);
+ // TODO add a failure log message sharing the status results
+ return false;
+ } else {
+ GCS_SEND_TEXT(MAV_SEVERITY_INFO,"XRCE Client: Service/Replier session pass for index '%u'",i);
+ uxr_buffer_request_data(&session, reliable_out, rep_id, reliable_in, &delivery_control);
+ }
+
+ } else if (strlen(services[i].req_profile_label) > 0) {
+ // TODO : Add Similar Code for Requester Profile
}
}
@@ -308,7 +754,7 @@ void AP_DDS_Client::write_time_topic()
{
WITH_SEMAPHORE(csem);
if (connected) {
- ucdrBuffer ub;
+ ucdrBuffer ub {};
const uint32_t topic_size = builtin_interfaces_msg_Time_size_of_topic(&time_topic, 0);
uxr_prepare_output_stream(&session,reliable_out,topics[0].dw_id,&ub,topic_size);
const bool success = builtin_interfaces_msg_Time_serialize_topic(&ub, &time_topic);
@@ -323,7 +769,7 @@ void AP_DDS_Client::write_nav_sat_fix_topic()
{
WITH_SEMAPHORE(csem);
if (connected) {
- ucdrBuffer ub;
+ ucdrBuffer ub {};
const uint32_t topic_size = sensor_msgs_msg_NavSatFix_size_of_topic(&nav_sat_fix_topic, 0);
uxr_prepare_output_stream(&session,reliable_out,topics[1].dw_id,&ub,topic_size);
const bool success = sensor_msgs_msg_NavSatFix_serialize_topic(&ub, &nav_sat_fix_topic);
@@ -338,10 +784,10 @@ void AP_DDS_Client::write_static_transforms()
{
WITH_SEMAPHORE(csem);
if (connected) {
- ucdrBuffer ub;
- const uint32_t topic_size = tf2_msgs_msg_TFMessage_size_of_topic(&static_transforms_topic, 0);
+ ucdrBuffer ub {};
+ const uint32_t topic_size = tf2_msgs_msg_TFMessage_size_of_topic(&tx_static_transforms_topic, 0);
uxr_prepare_output_stream(&session,reliable_out,topics[2].dw_id,&ub,topic_size);
- const bool success = tf2_msgs_msg_TFMessage_serialize_topic(&ub, &static_transforms_topic);
+ const bool success = tf2_msgs_msg_TFMessage_serialize_topic(&ub, &tx_static_transforms_topic);
if (!success) {
// TODO sometimes serialization fails on bootup. Determine why.
// AP_HAL::panic("FATAL: DDS_Client failed to serialize\n");
@@ -349,10 +795,83 @@ void AP_DDS_Client::write_static_transforms()
}
}
-void AP_DDS_Client::update()
+void AP_DDS_Client::write_battery_state_topic()
+{
+ WITH_SEMAPHORE(csem);
+ if (connected) {
+ ucdrBuffer ub {};
+ const uint32_t topic_size = sensor_msgs_msg_BatteryState_size_of_topic(&battery_state_topic, 0);
+ uxr_prepare_output_stream(&session,reliable_out,topics[3].dw_id,&ub,topic_size);
+ const bool success = sensor_msgs_msg_BatteryState_serialize_topic(&ub, &battery_state_topic);
+ if (!success) {
+ // TODO sometimes serialization fails on bootup. Determine why.
+ // AP_HAL::panic("FATAL: DDS_Client failed to serialize\n");
+ }
+ }
+}
+void AP_DDS_Client::write_local_pose_topic()
+{
+ WITH_SEMAPHORE(csem);
+ if (connected) {
+ ucdrBuffer ub {};
+ const uint32_t topic_size = geometry_msgs_msg_PoseStamped_size_of_topic(&local_pose_topic, 0);
+ uxr_prepare_output_stream(&session,reliable_out,topics[4].dw_id,&ub,topic_size);
+ const bool success = geometry_msgs_msg_PoseStamped_serialize_topic(&ub, &local_pose_topic);
+ if (!success) {
+ // TODO sometimes serialization fails on bootup. Determine why.
+ // AP_HAL::panic("FATAL: DDS_Client failed to serialize\n");
+ }
+ }
+}
+
+void AP_DDS_Client::write_tx_local_velocity_topic()
{
WITH_SEMAPHORE(csem);
+ if (connected) {
+ ucdrBuffer ub {};
+ const uint32_t topic_size = geometry_msgs_msg_TwistStamped_size_of_topic(&tx_local_velocity_topic, 0);
+ uxr_prepare_output_stream(&session,reliable_out,topics[5].dw_id,&ub,topic_size);
+ const bool success = geometry_msgs_msg_TwistStamped_serialize_topic(&ub, &tx_local_velocity_topic);
+ if (!success) {
+ // TODO sometimes serialization fails on bootup. Determine why.
+ // AP_HAL::panic("FATAL: DDS_Client failed to serialize\n");
+ }
+ }
+}
+void AP_DDS_Client::write_geo_pose_topic()
+{
+ WITH_SEMAPHORE(csem);
+ if (connected) {
+ ucdrBuffer ub {};
+ const uint32_t topic_size = geographic_msgs_msg_GeoPoseStamped_size_of_topic(&geo_pose_topic, 0);
+ uxr_prepare_output_stream(&session,reliable_out,topics[6].dw_id,&ub,topic_size);
+ const bool success = geographic_msgs_msg_GeoPoseStamped_serialize_topic(&ub, &geo_pose_topic);
+ if (!success) {
+ // TODO sometimes serialization fails on bootup. Determine why.
+ // AP_HAL::panic("FATAL: DDS_Client failed to serialize\n");
+ }
+ }
+}
+
+void AP_DDS_Client::write_clock_topic()
+{
+ WITH_SEMAPHORE(csem);
+ if (connected) {
+ ucdrBuffer ub {};
+ const uint32_t topic_size = rosgraph_msgs_msg_Clock_size_of_topic(&clock_topic, 0);
+ uxr_prepare_output_stream(&session,reliable_out,topics[7].dw_id,&ub,topic_size);
+ const bool success = rosgraph_msgs_msg_Clock_serialize_topic(&ub, &clock_topic);
+ if (!success) {
+ // TODO sometimes serialization fails on bootup. Determine why.
+ // AP_HAL::panic("FATAL: DDS_Client failed to serialize\n");
+ }
+ }
+}
+
+void AP_DDS_Client::update()
+{
+ WITH_SEMAPHORE(csem);
const auto cur_time_ms = AP_HAL::millis64();
if (cur_time_ms - last_time_time_ms > DELAY_TIME_TOPIC_MS) {
@@ -361,69 +880,43 @@ void AP_DDS_Client::update()
write_time_topic();
}
- if (cur_time_ms - last_nav_sat_fix_time_ms > DELAY_NAV_SAT_FIX_TOPIC_MS) {
- constexpr uint8_t instance = 0;
- update_topic(nav_sat_fix_topic, instance);
- last_nav_sat_fix_time_ms = cur_time_ms;
+ constexpr uint8_t gps_instance = 0;
+ if (update_topic(nav_sat_fix_topic, gps_instance)) {
write_nav_sat_fix_topic();
}
- connected = uxr_run_session_time(&session, 1);
-}
+ if (cur_time_ms - last_battery_state_time_ms > DELAY_BATTERY_STATE_TOPIC_MS) {
+ constexpr uint8_t battery_instance = 0;
+ update_topic(battery_state_topic, battery_instance);
+ last_battery_state_time_ms = cur_time_ms;
+ write_battery_state_topic();
+ }
-/*
- implement C functions for serial transport
- */
-extern "C" {
-#include
-}
+ if (cur_time_ms - last_local_pose_time_ms > DELAY_LOCAL_POSE_TOPIC_MS) {
+ update_topic(local_pose_topic);
+ last_local_pose_time_ms = cur_time_ms;
+ write_local_pose_topic();
+ }
-bool uxr_init_serial_platform(void* args, int fd, uint8_t remote_addr, uint8_t local_addr)
-{
- //! @todo Add error reporting
- return true;
-}
+ if (cur_time_ms - last_local_velocity_time_ms > DELAY_LOCAL_VELOCITY_TOPIC_MS) {
+ update_topic(tx_local_velocity_topic);
+ last_local_velocity_time_ms = cur_time_ms;
+ write_tx_local_velocity_topic();
+ }
-bool uxr_close_serial_platform(void* args)
-{
- //! @todo Add error reporting
- return true;
-}
+ if (cur_time_ms - last_geo_pose_time_ms > DELAY_GEO_POSE_TOPIC_MS) {
+ update_topic(geo_pose_topic);
+ last_geo_pose_time_ms = cur_time_ms;
+ write_geo_pose_topic();
+ }
-size_t uxr_write_serial_data_platform(void* args, const uint8_t* buf, size_t len, uint8_t* errcode)
-{
- if (dds_port == nullptr) {
- *errcode = 1;
- return 0;
- }
- ssize_t bytes_written = dds_port->write(buf, len);
- if (bytes_written <= 0) {
- *errcode = 1;
- return 0;
- }
- //! @todo Add populate the error code correctly
- *errcode = 0;
- return bytes_written;
-}
+ if (cur_time_ms - last_clock_time_ms > DELAY_CLOCK_TOPIC_MS) {
+ update_topic(clock_topic);
+ last_clock_time_ms = cur_time_ms;
+ write_clock_topic();
+ }
-size_t uxr_read_serial_data_platform(void* args, uint8_t* buf, size_t len, int timeout, uint8_t* errcode)
-{
- if (dds_port == nullptr) {
- *errcode = 1;
- return 0;
- }
- while (timeout > 0 && dds_port->available() < len) {
- hal.scheduler->delay(1); // TODO select or poll this is limiting speed (1mS)
- timeout--;
- }
- ssize_t bytes_read = dds_port->read(buf, len);
- if (bytes_read <= 0) {
- *errcode = 1;
- return 0;
- }
- //! @todo Add error reporting
- *errcode = 0;
- return bytes_read;
+ connected = uxr_run_session_time(&session, 1);
}
#if CONFIG_HAL_BOARD != HAL_BOARD_SITL
@@ -443,7 +936,7 @@ int clock_gettime(clockid_t clockid, struct timespec *ts)
ts->tv_nsec = (utc_usec % 1000000ULL) * 1000UL;
return 0;
}
-#endif // CONFIG_HAL_BOARD
+#endif // CONFIG_HAL_BOARD != HAL_BOARD_SITL
#endif // AP_DDS_ENABLED
diff --git a/libraries/AP_DDS/AP_DDS_Client.h b/libraries/AP_DDS/AP_DDS_Client.h
index c44e0f825f03ab..a9dbd97cce9f42 100644
--- a/libraries/AP_DDS/AP_DDS_Client.h
+++ b/libraries/AP_DDS/AP_DDS_Client.h
@@ -4,11 +4,16 @@
#include "uxr/client/client.h"
#include "ucdr/microcdr.h"
-#include "generated/Time.h"
-#include "AP_DDS_Generic_Fn_T.h"
-#include "generated/NavSatFix.h"
-#include "generated/TFMessage.h"
+#include "builtin_interfaces/msg/Time.h"
+#include "sensor_msgs/msg/NavSatFix.h"
+#include "tf2_msgs/msg/TFMessage.h"
+#include "sensor_msgs/msg/BatteryState.h"
+#include "sensor_msgs/msg/Joy.h"
+#include "geometry_msgs/msg/PoseStamped.h"
+#include "geometry_msgs/msg/TwistStamped.h"
+#include "geographic_msgs/msg/GeoPoseStamped.h"
+#include "rosgraph_msgs/msg/Clock.h"
#include
#include
@@ -18,8 +23,15 @@
#include "fcntl.h"
#include
-#define STREAM_HISTORY 8
-#define BUFFER_SIZE_SERIAL UXR_CONFIG_SERIAL_TRANSPORT_MTU * STREAM_HISTORY
+#include "AP_DDS_config.h"
+
+#define DDS_MTU 512
+#define DDS_STREAM_HISTORY 8
+#define DDS_BUFFER_SIZE DDS_MTU * DDS_STREAM_HISTORY
+
+#if AP_DDS_UDP_ENABLED
+#include
+#endif
extern const AP_HAL::HAL& hal;
@@ -28,22 +40,35 @@ class AP_DDS_Client
private:
+ AP_Int8 enabled;
+
// Serial Allocation
- uxrSerialTransport serial_transport; // client uxr serial transport
uxrSession session; //Session
+ bool is_using_serial; // true when using serial transport
- // Input Stream
- uint8_t input_reliable_stream[BUFFER_SIZE_SERIAL];
+ // input and output stream
+ uint8_t *input_reliable_stream;
+ uint8_t *output_reliable_stream;
uxrStreamId reliable_in;
-
- // Output Stream
- uint8_t output_reliable_stream[BUFFER_SIZE_SERIAL];
uxrStreamId reliable_out;
- // Topic
+ // Outgoing Sensor and AHRS data
builtin_interfaces_msg_Time time_topic;
+ geographic_msgs_msg_GeoPoseStamped geo_pose_topic;
+ geometry_msgs_msg_PoseStamped local_pose_topic;
+ geometry_msgs_msg_TwistStamped tx_local_velocity_topic;
+ sensor_msgs_msg_BatteryState battery_state_topic;
sensor_msgs_msg_NavSatFix nav_sat_fix_topic;
- tf2_msgs_msg_TFMessage static_transforms_topic;
+ rosgraph_msgs_msg_Clock clock_topic;
+ // incoming joystick data
+ static sensor_msgs_msg_Joy rx_joy_topic;
+ // incoming REP147 velocity control
+ static geometry_msgs_msg_TwistStamped rx_velocity_control_topic;
+ // outgoing transforms
+ tf2_msgs_msg_TFMessage tx_static_transforms_topic;
+ tf2_msgs_msg_TFMessage tx_dynamic_transforms_topic;
+ // incoming transforms
+ static tf2_msgs_msg_TFMessage rx_dynamic_transforms_topic;
HAL_Semaphore csem;
@@ -51,19 +76,83 @@ class AP_DDS_Client
bool connected = true;
static void update_topic(builtin_interfaces_msg_Time& msg);
- static void update_topic(sensor_msgs_msg_NavSatFix& msg, const uint8_t instance);
+ bool update_topic(sensor_msgs_msg_NavSatFix& msg, const uint8_t instance) WARN_IF_UNUSED;
static void populate_static_transforms(tf2_msgs_msg_TFMessage& msg);
+ static void update_topic(sensor_msgs_msg_BatteryState& msg, const uint8_t instance);
+ static void update_topic(geometry_msgs_msg_PoseStamped& msg);
+ static void update_topic(geometry_msgs_msg_TwistStamped& msg);
+ static void update_topic(geographic_msgs_msg_GeoPoseStamped& msg);
+ static void update_topic(rosgraph_msgs_msg_Clock& msg);
+
+ // subscription callback function
+ static void on_topic_trampoline(uxrSession* session, uxrObjectId object_id, uint16_t request_id, uxrStreamId stream_id, struct ucdrBuffer* ub, uint16_t length, void* args);
+ void on_topic(uxrSession* session, uxrObjectId object_id, uint16_t request_id, uxrStreamId stream_id, struct ucdrBuffer* ub, uint16_t length);
+ // count of subscribed samples
+ uint32_t subscribe_sample_count;
+
+ // service replier callback function
+ static void on_request_trampoline(uxrSession* session, uxrObjectId object_id, uint16_t request_id, SampleIdentity* sample_id, ucdrBuffer* ub, uint16_t length, void* args);
+ void on_request(uxrSession* session, uxrObjectId object_id, uint16_t request_id, SampleIdentity* sample_id, ucdrBuffer* ub, uint16_t length);
+ // count of request samples
+ uint32_t request_sample_count;
+
+ // delivery control parameters
+ uxrDeliveryControl delivery_control {
+ .max_samples = UXR_MAX_SAMPLES_UNLIMITED,
+ .max_elapsed_time = 0,
+ .max_bytes_per_second = 0,
+ .min_pace_period = 0
+ };
// The last ms timestamp AP_DDS wrote a Time message
uint64_t last_time_time_ms;
// The last ms timestamp AP_DDS wrote a NavSatFix message
uint64_t last_nav_sat_fix_time_ms;
-
+ // The last ms timestamp AP_DDS wrote a BatteryState message
+ uint64_t last_battery_state_time_ms;
+ // The last ms timestamp AP_DDS wrote a Local Pose message
+ uint64_t last_local_pose_time_ms;
+ // The last ms timestamp AP_DDS wrote a Local Velocity message
+ uint64_t last_local_velocity_time_ms;
+ // The last ms timestamp AP_DDS wrote a GeoPose message
+ uint64_t last_geo_pose_time_ms;
+ // The last ms timestamp AP_DDS wrote a Clock message
+ uint64_t last_clock_time_ms;
+
+ // functions for serial transport
+ bool ddsSerialInit();
+ static bool serial_transport_open(uxrCustomTransport* args);
+ static bool serial_transport_close(uxrCustomTransport* transport);
+ static size_t serial_transport_write(uxrCustomTransport* transport, const uint8_t* buf, size_t len, uint8_t* error);
+ static size_t serial_transport_read(uxrCustomTransport* transport, uint8_t* buf, size_t len, int timeout, uint8_t* error);
+ struct {
+ AP_HAL::UARTDriver *port;
+ uxrCustomTransport transport;
+ } serial;
+
+#if AP_DDS_UDP_ENABLED
+ // functions for udp transport
+ bool ddsUdpInit();
+ static bool udp_transport_open(uxrCustomTransport* args);
+ static bool udp_transport_close(uxrCustomTransport* transport);
+ static size_t udp_transport_write(uxrCustomTransport* transport, const uint8_t* buf, size_t len, uint8_t* error);
+ static size_t udp_transport_read(uxrCustomTransport* transport, uint8_t* buf, size_t len, int timeout, uint8_t* error);
+
+ struct {
+ AP_Int32 port;
+ // UDP endpoint
+ const char* ip = "127.0.0.1";
+ // UDP Allocation
+ uxrCustomTransport transport;
+ SocketAPM *socket;
+ } udp;
+#endif
+
+ // client key we present
+ static constexpr uint32_t uniqueClientKey = 0xAAAABBBB;
public:
- // Constructor
- AP_DDS_Client();
-
+ bool start(void);
void main_loop(void);
//! @brief Initialize the client's transport, uxr session, and IO stream(s)
@@ -81,6 +170,16 @@ class AP_DDS_Client
void write_nav_sat_fix_topic();
//! @brief Serialize the static transforms and publish to the IO stream(s)
void write_static_transforms();
+ //! @brief Serialize the current nav_sat_fix state and publish it to the IO stream(s)
+ void write_battery_state_topic();
+ //! @brief Serialize the current local_pose and publish to the IO stream(s)
+ void write_local_pose_topic();
+ //! @brief Serialize the current local velocity and publish to the IO stream(s)
+ void write_tx_local_velocity_topic();
+ //! @brief Serialize the current geo_pose and publish to the IO stream(s)
+ void write_geo_pose_topic();
+ //! @brief Serialize the current clock and publish to the IO stream(s)
+ void write_clock_topic();
//! @brief Update the internally stored DDS messages with latest data
void update();
@@ -91,16 +190,33 @@ class AP_DDS_Client
struct Topic_table {
const uint8_t topic_id;
const uint8_t pub_id;
+ const uint8_t sub_id; // added sub_id fields to avoid confusion
const uxrObjectId dw_id;
+ const uxrObjectId dr_id; // added dr_id fields to avoid confusion
const char* topic_profile_label;
const char* dw_profile_label;
- Generic_serialize_topic_fn_t serialize;
- Generic_deserialize_topic_fn_t deserialize;
- Generic_size_of_topic_fn_t size_of;
+ const char* dr_profile_label;
};
static const struct Topic_table topics[];
+ //! @brief Convenience grouping for a single "channel" of services
+ struct Service_table {
+ //! @brief Request ID for the service
+ const uint8_t req_id;
+
+ //! @brief Reply ID for the service
+ const uint8_t rep_id;
+
+ //! @brief Profile Label for the service
+ const char* srv_profile_label;
+ //! @brief Profile Label for the service requester
+ const char* req_profile_label;
+
+ //! @brief Profile Label for the service replier
+ const char* rep_profile_label;
+ };
+ static const struct Service_table services[];
};
#endif // AP_DDS_ENABLED
diff --git a/libraries/AP_DDS/AP_DDS_ExternalControl.cpp b/libraries/AP_DDS/AP_DDS_ExternalControl.cpp
new file mode 100644
index 00000000000000..8d551cac1375c6
--- /dev/null
+++ b/libraries/AP_DDS/AP_DDS_ExternalControl.cpp
@@ -0,0 +1,32 @@
+#if AP_DDS_ENABLED
+
+#include "AP_DDS_ExternalControl.h"
+#include "AP_DDS_Frames.h"
+
+#include
+
+bool AP_DDS_External_Control::handle_velocity_control(geometry_msgs_msg_TwistStamped& cmd_vel)
+{
+ auto *external_control = AP::externalcontrol();
+ if (external_control == nullptr) {
+ return false;
+ }
+ if (strcmp(cmd_vel.header.frame_id, MAP_FRAME) != 0) {
+ // Although REP-147 says cmd_vel should be in body frame, all the AP math is done in earth frame.
+ // This is because accounting for the gravity vector.
+ // Although the ROS 2 interface could support body-frame velocity control in the future,
+ // it is currently not supported.
+ return false;
+ }
+
+ // Convert commands from ENU to NED frame
+ Vector3f linear_velocity {
+ float(cmd_vel.twist.linear.y),
+ float(cmd_vel.twist.linear.x),
+ float(-cmd_vel.twist.linear.z) };
+ const float yaw_rate = -cmd_vel.twist.angular.z;
+ return external_control->set_linear_velocity_and_yaw_rate(linear_velocity, yaw_rate);
+}
+
+
+#endif // AP_DDS_ENABLED
\ No newline at end of file
diff --git a/libraries/AP_DDS/AP_DDS_ExternalControl.h b/libraries/AP_DDS/AP_DDS_ExternalControl.h
new file mode 100644
index 00000000000000..dbffafdd81ad1c
--- /dev/null
+++ b/libraries/AP_DDS/AP_DDS_ExternalControl.h
@@ -0,0 +1,11 @@
+#pragma once
+
+#if AP_DDS_ENABLED
+#include "geometry_msgs/msg/TwistStamped.h"
+
+class AP_DDS_External_Control
+{
+public:
+ static bool handle_velocity_control(geometry_msgs_msg_TwistStamped& cmd_vel);
+};
+#endif // AP_DDS_ENABLED
diff --git a/libraries/AP_DDS/AP_DDS_External_Odom.cpp b/libraries/AP_DDS/AP_DDS_External_Odom.cpp
new file mode 100644
index 00000000000000..cf121f408521a6
--- /dev/null
+++ b/libraries/AP_DDS/AP_DDS_External_Odom.cpp
@@ -0,0 +1,76 @@
+
+
+#include "AP_DDS_External_Odom.h"
+#include "AP_DDS_Type_Conversions.h"
+
+#if AP_DDS_VISUALODOM_ENABLED
+
+#include
+#include
+
+void AP_DDS_External_Odom::handle_external_odom(const tf2_msgs_msg_TFMessage& msg)
+{
+ auto *visual_odom = AP::visualodom();
+ if (visual_odom == nullptr) {
+ return;
+ }
+
+ for (size_t i = 0; i < msg.transforms_size; i++) {
+ const auto& ros_transform_stamped = msg.transforms[i];
+ if (!is_odometry_frame(ros_transform_stamped)) {
+ continue;
+ }
+ const uint64_t remote_time_us {AP_DDS_Type_Conversions::time_u64_micros(ros_transform_stamped.header.stamp)};
+
+ Vector3f ap_position;
+ Quaternion ap_rotation;
+
+ convert_transform(ros_transform_stamped.transform, ap_position, ap_rotation);
+ // Although ROS convention states quaternions in ROS messages should be normalized, it's not guaranteed.
+ // Before propogating a potentially inaccurate quaternion to the rest of AP, normalize it here.
+ // TODO what if the quaternion is NaN?
+ ap_rotation.normalize();
+
+ // No error is available in TF, trust the data as-is
+ const float posErr {0.0};
+ const float angErr {0.0};
+ // The odom to base_link transform used is locally consistent per ROS REP-105.
+ // https://www.ros.org/reps/rep-0105.html#id16
+ // Thus, there will not be any resets.
+ const uint8_t reset_counter {0};
+ // TODO imlement jitter correction similar to GCS_MAVLINK::correct_offboard_timestamp_usec_to_ms(remote_time_us, sizeof(msg));
+ const uint32_t time_ms {static_cast(remote_time_us * 1E-3)};
+ visual_odom->handle_pose_estimate(remote_time_us, time_ms, ap_position.x, ap_position.y, ap_position.z, ap_rotation, posErr, angErr, reset_counter);
+
+ }
+}
+
+bool AP_DDS_External_Odom::is_odometry_frame(const geometry_msgs_msg_TransformStamped& msg)
+{
+ char odom_parent[] = "odom";
+ char odom_child[] = "base_link";
+ // Assume the frame ID's are null terminated.
+ return (strcmp(msg.header.frame_id, odom_parent) == 0) &&
+ (strcmp(msg.child_frame_id, odom_child) == 0);
+}
+
+void AP_DDS_External_Odom::convert_transform(const geometry_msgs_msg_Transform& ros_transform, Vector3f& translation, Quaternion& rotation)
+{
+ // convert from x-forward, y-left, z-up to NED
+ // https://github.com/mavlink/mavros/issues/49#issuecomment-51614130
+ translation = {
+ static_cast(ros_transform.translation.x),
+ static_cast(-ros_transform.translation.y),
+ static_cast(-ros_transform.translation.z)
+ };
+
+ // In AP, q1 is the quaternion's scalar component.
+ // In ROS, w is the quaternion's scalar component.
+ // https://docs.ros.org/en/humble/Tutorials/Intermediate/Tf2/Quaternion-Fundamentals.html#components-of-a-quaternion
+ rotation.q1 = ros_transform.rotation.w;
+ rotation.q2 = ros_transform.rotation.x;
+ rotation.q3 = -ros_transform.rotation.y;
+ rotation.q4 = -ros_transform.rotation.z;
+}
+
+#endif // AP_DDS_VISUALODOM_ENABLED
diff --git a/libraries/AP_DDS/AP_DDS_External_Odom.h b/libraries/AP_DDS/AP_DDS_External_Odom.h
new file mode 100644
index 00000000000000..2cba26a16d327b
--- /dev/null
+++ b/libraries/AP_DDS/AP_DDS_External_Odom.h
@@ -0,0 +1,33 @@
+// Class for handling external localization data.
+// For historical reasons, it's called odometry to match AP_VisualOdom.
+
+#pragma once
+
+#include "AP_DDS_config.h"
+#if AP_DDS_VISUALODOM_ENABLED
+
+#include "geometry_msgs/msg/TransformStamped.h"
+#include "tf2_msgs/msg/TFMessage.h"
+#include "AP_Math/vector3.h"
+#include "AP_Math/quaternion.h"
+
+class AP_DDS_External_Odom
+{
+public:
+
+ // Handler for external position localization
+ static void handle_external_odom(const tf2_msgs_msg_TFMessage& msg);
+
+ // Checks the child and parent frames match a set needed for external odom.
+ // Since multiple different transforms can be sent, this validates the specific transform is
+ // for odometry.
+ static bool is_odometry_frame(const geometry_msgs_msg_TransformStamped& msg);
+
+ // Helper to convert from ROS transform to AP datatypes
+ // ros_transform is in ENU
+ // translation is in NED
+ static void convert_transform(const geometry_msgs_msg_Transform& ros_transform, Vector3f& translation, Quaternion& rotation);
+
+};
+
+#endif // AP_DDS_VISUALODOM_ENABLED
diff --git a/libraries/AP_DDS/AP_DDS_Frames.h b/libraries/AP_DDS/AP_DDS_Frames.h
new file mode 100644
index 00000000000000..0bdaf354ec116f
--- /dev/null
+++ b/libraries/AP_DDS/AP_DDS_Frames.h
@@ -0,0 +1,7 @@
+#pragma once
+
+static constexpr char WGS_84_FRAME_ID[] = "WGS-84";
+// https://www.ros.org/reps/rep-0105.html#base-link
+static constexpr char BASE_LINK_FRAME_ID[] = "base_link";
+// https://www.ros.org/reps/rep-0105.html#map
+static constexpr char MAP_FRAME[] = "map";
diff --git a/libraries/AP_DDS/AP_DDS_Generic_Fn_T.h b/libraries/AP_DDS/AP_DDS_Generic_Fn_T.h
deleted file mode 100644
index b6a66f6ee46138..00000000000000
--- a/libraries/AP_DDS/AP_DDS_Generic_Fn_T.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#pragma once
-
-// table maps between string names and pointer to element
-// Function pointer that matches signature of generated topics
-typedef bool (*Generic_serialize_topic_fn_t)(struct ucdrBuffer*, const void*);
-typedef bool (*Generic_deserialize_topic_fn_t)(struct ucdrBuffer*, void*);
-typedef uint32_t (*Generic_size_of_topic_fn_t)(struct ucdrBuffer*, uint32_t);
diff --git a/libraries/AP_DDS/AP_DDS_Serial.cpp b/libraries/AP_DDS/AP_DDS_Serial.cpp
new file mode 100644
index 00000000000000..8ce7cc3b0ec937
--- /dev/null
+++ b/libraries/AP_DDS/AP_DDS_Serial.cpp
@@ -0,0 +1,95 @@
+#include "AP_DDS_Client.h"
+
+#include
+
+#include
+
+/*
+ open connection on a serial port
+ */
+bool AP_DDS_Client::serial_transport_open(uxrCustomTransport *t)
+{
+ AP_DDS_Client *dds = (AP_DDS_Client *)t->args;
+ AP_SerialManager *serial_manager = AP_SerialManager::get_singleton();
+ auto *dds_port = serial_manager->find_serial(AP_SerialManager::SerialProtocol_DDS_XRCE, 0);
+ if (dds_port == nullptr) {
+ return false;
+ }
+ // ensure we own the UART
+ dds_port->begin(0);
+ dds->serial.port = dds_port;
+ return true;
+}
+
+/*
+ close serial transport
+ */
+bool AP_DDS_Client::serial_transport_close(uxrCustomTransport *t)
+{
+ // we don't actually close the UART
+ return true;
+}
+
+/*
+ write on serial transport
+ */
+size_t AP_DDS_Client::serial_transport_write(uxrCustomTransport *t, const uint8_t* buf, size_t len, uint8_t* error)
+{
+ AP_DDS_Client *dds = (AP_DDS_Client *)t->args;
+ if (dds->serial.port == nullptr) {
+ *error = EINVAL;
+ return 0;
+ }
+ ssize_t bytes_written = dds->serial.port->write(buf, len);
+ if (bytes_written <= 0) {
+ *error = 1;
+ return 0;
+ }
+ //! @todo populate the error code correctly
+ *error = 0;
+ return bytes_written;
+}
+
+/*
+ read from a serial transport
+ */
+size_t AP_DDS_Client::serial_transport_read(uxrCustomTransport *t, uint8_t* buf, size_t len, int timeout_ms, uint8_t* error)
+{
+ AP_DDS_Client *dds = (AP_DDS_Client *)t->args;
+ if (dds->serial.port == nullptr) {
+ *error = EINVAL;
+ return 0;
+ }
+ const uint32_t tstart = AP_HAL::millis();
+ while (AP_HAL::millis() - tstart < uint32_t(timeout_ms) &&
+ dds->serial.port->available() < len) {
+ hal.scheduler->delay_microseconds(100); // TODO select or poll this is limiting speed (100us)
+ }
+ ssize_t bytes_read = dds->serial.port->read(buf, len);
+ if (bytes_read <= 0) {
+ *error = 1;
+ return 0;
+ }
+ //! @todo Add error reporting
+ *error = 0;
+ return bytes_read;
+}
+
+/*
+ initialise serial connection
+ */
+bool AP_DDS_Client::ddsSerialInit()
+{
+ // setup a framed transport for serial
+ uxr_set_custom_transport_callbacks(&serial.transport, true,
+ serial_transport_open,
+ serial_transport_close,
+ serial_transport_write,
+ serial_transport_read);
+
+ if (!uxr_init_custom_transport(&serial.transport, (void*)this)) {
+ return false;
+ }
+ uxr_init_session(&session, &serial.transport.comm, uniqueClientKey);
+ return true;
+}
diff --git a/libraries/AP_DDS/AP_DDS_Service_Table.h b/libraries/AP_DDS/AP_DDS_Service_Table.h
new file mode 100644
index 00000000000000..962fa9197d96de
--- /dev/null
+++ b/libraries/AP_DDS/AP_DDS_Service_Table.h
@@ -0,0 +1,21 @@
+#include "uxr/client/client.h"
+
+enum class ServiceIndex: uint8_t {
+ ARMING_MOTORS
+};
+
+static inline constexpr uint8_t to_underlying(const ServiceIndex index)
+{
+ static_assert(sizeof(index) == sizeof(uint8_t));
+ return static_cast(index);
+}
+
+constexpr struct AP_DDS_Client::Service_table AP_DDS_Client::services[] = {
+ {
+ .req_id = to_underlying(ServiceIndex::ARMING_MOTORS),
+ .rep_id = to_underlying(ServiceIndex::ARMING_MOTORS),
+ .srv_profile_label = "ArmMotorsService",
+ .req_profile_label = "",
+ .rep_profile_label = "ArmMotors_Replier",
+ }
+};
diff --git a/libraries/AP_DDS/AP_DDS_Topic_Table.h b/libraries/AP_DDS/AP_DDS_Topic_Table.h
index d7d7af3f5c1f9c..8ce9507d08005d 100644
--- a/libraries/AP_DDS/AP_DDS_Topic_Table.h
+++ b/libraries/AP_DDS/AP_DDS_Topic_Table.h
@@ -1,45 +1,145 @@
-#include "generated/Time.h"
-#include "generated/NavSatFix.h"
-#include "generated/TransformStamped.h"
+#include "builtin_interfaces/msg/Time.h"
+#include "sensor_msgs/msg/NavSatFix.h"
+#include "tf2_msgs/msg/TFMessage.h"
+#include "sensor_msgs/msg/BatteryState.h"
+#include "geographic_msgs/msg/GeoPoseStamped.h"
-
-#include "AP_DDS_Generic_Fn_T.h"
#include "uxr/client/client.h"
// Code generated table based on the enabled topics.
// Mavgen is using python, loops are not readable.
// Can use jinja to template (like Flask)
+enum class TopicIndex: uint8_t {
+ TIME_PUB,
+ NAV_SAT_FIX_PUB,
+ STATIC_TRANSFORMS_PUB,
+ BATTERY_STATE_PUB,
+ LOCAL_POSE_PUB,
+ LOCAL_VELOCITY_PUB,
+ GEOPOSE_PUB,
+ CLOCK_PUB,
+ JOY_SUB,
+ DYNAMIC_TRANSFORMS_SUB,
+ VELOCITY_CONTROL_SUB,
+};
+
+static inline constexpr uint8_t to_underlying(const TopicIndex index)
+{
+ static_assert(sizeof(index) == sizeof(uint8_t));
+ return static_cast(index);
+}
-const struct AP_DDS_Client::Topic_table AP_DDS_Client::topics[] = {
+
+constexpr struct AP_DDS_Client::Topic_table AP_DDS_Client::topics[] = {
{
- .topic_id = 0x01,
- .pub_id = 0x01,
- .dw_id = uxrObjectId{.id=0x01, .type=UXR_DATAWRITER_ID},
+ .topic_id = to_underlying(TopicIndex::TIME_PUB),
+ .pub_id = to_underlying(TopicIndex::TIME_PUB),
+ .sub_id = to_underlying(TopicIndex::TIME_PUB),
+ .dw_id = uxrObjectId{.id=to_underlying(TopicIndex::TIME_PUB), .type=UXR_DATAWRITER_ID},
+ .dr_id = uxrObjectId{.id=to_underlying(TopicIndex::TIME_PUB), .type=UXR_DATAREADER_ID},
.topic_profile_label = "time__t",
.dw_profile_label = "time__dw",
- .serialize = Generic_serialize_topic_fn_t(&builtin_interfaces_msg_Time_serialize_topic),
- .deserialize = Generic_deserialize_topic_fn_t(&builtin_interfaces_msg_Time_deserialize_topic),
- .size_of = Generic_size_of_topic_fn_t(&builtin_interfaces_msg_Time_size_of_topic),
+ .dr_profile_label = "",
},
{
- .topic_id = 0x02,
- .pub_id = 0x02,
- .dw_id = uxrObjectId{.id=0x02, .type=UXR_DATAWRITER_ID},
+ .topic_id = to_underlying(TopicIndex::NAV_SAT_FIX_PUB),
+ .pub_id = to_underlying(TopicIndex::NAV_SAT_FIX_PUB),
+ .sub_id = to_underlying(TopicIndex::NAV_SAT_FIX_PUB),
+ .dw_id = uxrObjectId{.id=to_underlying(TopicIndex::NAV_SAT_FIX_PUB), .type=UXR_DATAWRITER_ID},
+ .dr_id = uxrObjectId{.id=to_underlying(TopicIndex::NAV_SAT_FIX_PUB), .type=UXR_DATAREADER_ID},
.topic_profile_label = "navsatfix0__t",
.dw_profile_label = "navsatfix0__dw",
- .serialize = Generic_serialize_topic_fn_t(&sensor_msgs_msg_NavSatFix_serialize_topic),
- .deserialize = Generic_deserialize_topic_fn_t(&sensor_msgs_msg_NavSatFix_deserialize_topic),
- .size_of = Generic_size_of_topic_fn_t(&sensor_msgs_msg_NavSatFix_size_of_topic),
+ .dr_profile_label = "",
},
{
- .topic_id = 0x03,
- .pub_id = 0x03,
- .dw_id = uxrObjectId{.id=0x03, .type=UXR_DATAWRITER_ID},
+ .topic_id = to_underlying(TopicIndex::STATIC_TRANSFORMS_PUB),
+ .pub_id = to_underlying(TopicIndex::STATIC_TRANSFORMS_PUB),
+ .sub_id = to_underlying(TopicIndex::STATIC_TRANSFORMS_PUB),
+ .dw_id = uxrObjectId{.id=to_underlying(TopicIndex::STATIC_TRANSFORMS_PUB), .type=UXR_DATAWRITER_ID},
+ .dr_id = uxrObjectId{.id=to_underlying(TopicIndex::STATIC_TRANSFORMS_PUB), .type=UXR_DATAREADER_ID},
.topic_profile_label = "statictransforms__t",
.dw_profile_label = "statictransforms__dw",
- .serialize = Generic_serialize_topic_fn_t(&tf2_msgs_msg_TFMessage_serialize_topic),
- .deserialize = Generic_deserialize_topic_fn_t(&tf2_msgs_msg_TFMessage_deserialize_topic),
- .size_of = Generic_size_of_topic_fn_t(&tf2_msgs_msg_TFMessage_size_of_topic),
+ .dr_profile_label = "",
+ },
+ {
+ .topic_id = to_underlying(TopicIndex::BATTERY_STATE_PUB),
+ .pub_id = to_underlying(TopicIndex::BATTERY_STATE_PUB),
+ .sub_id = to_underlying(TopicIndex::BATTERY_STATE_PUB),
+ .dw_id = uxrObjectId{.id=to_underlying(TopicIndex::BATTERY_STATE_PUB), .type=UXR_DATAWRITER_ID},
+ .dr_id = uxrObjectId{.id=to_underlying(TopicIndex::BATTERY_STATE_PUB), .type=UXR_DATAREADER_ID},
+ .topic_profile_label = "batterystate0__t",
+ .dw_profile_label = "batterystate0__dw",
+ .dr_profile_label = "",
+ },
+ {
+ .topic_id = to_underlying(TopicIndex::LOCAL_POSE_PUB),
+ .pub_id = to_underlying(TopicIndex::LOCAL_POSE_PUB),
+ .sub_id = to_underlying(TopicIndex::LOCAL_POSE_PUB),
+ .dw_id = uxrObjectId{.id=to_underlying(TopicIndex::LOCAL_POSE_PUB), .type=UXR_DATAWRITER_ID},
+ .dr_id = uxrObjectId{.id=to_underlying(TopicIndex::LOCAL_POSE_PUB), .type=UXR_DATAREADER_ID},
+ .topic_profile_label = "localpose__t",
+ .dw_profile_label = "localpose__dw",
+ .dr_profile_label = "",
+ },
+ {
+ .topic_id = to_underlying(TopicIndex::LOCAL_VELOCITY_PUB),
+ .pub_id = to_underlying(TopicIndex::LOCAL_VELOCITY_PUB),
+ .sub_id = to_underlying(TopicIndex::LOCAL_VELOCITY_PUB),
+ .dw_id = uxrObjectId{.id=to_underlying(TopicIndex::LOCAL_VELOCITY_PUB), .type=UXR_DATAWRITER_ID},
+ .dr_id = uxrObjectId{.id=to_underlying(TopicIndex::LOCAL_VELOCITY_PUB), .type=UXR_DATAREADER_ID},
+ .topic_profile_label = "localvelocity__t",
+ .dw_profile_label = "localvelocity__dw",
+ .dr_profile_label = "",
+ },
+ {
+ .topic_id = to_underlying(TopicIndex::GEOPOSE_PUB),
+ .pub_id = to_underlying(TopicIndex::GEOPOSE_PUB),
+ .sub_id = to_underlying(TopicIndex::GEOPOSE_PUB),
+ .dw_id = uxrObjectId{.id=to_underlying(TopicIndex::GEOPOSE_PUB), .type=UXR_DATAWRITER_ID},
+ .dr_id = uxrObjectId{.id=to_underlying(TopicIndex::GEOPOSE_PUB), .type=UXR_DATAREADER_ID},
+ .topic_profile_label = "geopose__t",
+ .dw_profile_label = "geopose__dw",
+ .dr_profile_label = "",
+ },
+ {
+ .topic_id = to_underlying(TopicIndex::CLOCK_PUB),
+ .pub_id = to_underlying(TopicIndex::CLOCK_PUB),
+ .sub_id = to_underlying(TopicIndex::CLOCK_PUB),
+ .dw_id = uxrObjectId{.id=to_underlying(TopicIndex::CLOCK_PUB), .type=UXR_DATAWRITER_ID},
+ .dr_id = uxrObjectId{.id=to_underlying(TopicIndex::CLOCK_PUB), .type=UXR_DATAREADER_ID},
+ .topic_profile_label = "clock__t",
+ .dw_profile_label = "clock__dw",
+ .dr_profile_label = "",
+ },
+ {
+ .topic_id = to_underlying(TopicIndex::JOY_SUB),
+ .pub_id = to_underlying(TopicIndex::JOY_SUB),
+ .sub_id = to_underlying(TopicIndex::JOY_SUB),
+ .dw_id = uxrObjectId{.id=to_underlying(TopicIndex::JOY_SUB), .type=UXR_DATAWRITER_ID},
+ .dr_id = uxrObjectId{.id=to_underlying(TopicIndex::JOY_SUB), .type=UXR_DATAREADER_ID},
+ .topic_profile_label = "joy__t",
+ .dw_profile_label = "",
+ .dr_profile_label = "joy__dr",
+ },
+ {
+ .topic_id = to_underlying(TopicIndex::DYNAMIC_TRANSFORMS_SUB),
+ .pub_id = to_underlying(TopicIndex::DYNAMIC_TRANSFORMS_SUB),
+ .sub_id = to_underlying(TopicIndex::DYNAMIC_TRANSFORMS_SUB),
+ .dw_id = uxrObjectId{.id=to_underlying(TopicIndex::DYNAMIC_TRANSFORMS_SUB), .type=UXR_DATAWRITER_ID},
+ .dr_id = uxrObjectId{.id=to_underlying(TopicIndex::DYNAMIC_TRANSFORMS_SUB), .type=UXR_DATAREADER_ID},
+ .topic_profile_label = "dynamictf__t",
+ .dw_profile_label = "",
+ .dr_profile_label = "dynamictf__dr",
+ },
+ {
+ .topic_id = to_underlying(TopicIndex::VELOCITY_CONTROL_SUB),
+ .pub_id = to_underlying(TopicIndex::VELOCITY_CONTROL_SUB),
+ .sub_id = to_underlying(TopicIndex::VELOCITY_CONTROL_SUB),
+ .dw_id = uxrObjectId{.id=to_underlying(TopicIndex::VELOCITY_CONTROL_SUB), .type=UXR_DATAWRITER_ID},
+ .dr_id = uxrObjectId{.id=to_underlying(TopicIndex::VELOCITY_CONTROL_SUB), .type=UXR_DATAREADER_ID},
+ .topic_profile_label = "velocitycontrol__t",
+ .dw_profile_label = "",
+ .dr_profile_label = "velocitycontrol__dr",
},
};
diff --git a/libraries/AP_DDS/AP_DDS_Type_Conversions.cpp b/libraries/AP_DDS/AP_DDS_Type_Conversions.cpp
new file mode 100644
index 00000000000000..2aa4caf543f89b
--- /dev/null
+++ b/libraries/AP_DDS/AP_DDS_Type_Conversions.cpp
@@ -0,0 +1,13 @@
+#include "AP_DDS_Type_Conversions.h"
+#if AP_DDS_ENABLED
+
+#include "builtin_interfaces/msg/Time.h"
+
+
+uint64_t AP_DDS_Type_Conversions::time_u64_micros(const builtin_interfaces_msg_Time& ros_time)
+{
+ return (uint64_t(ros_time.sec) * 1000000ULL) + (ros_time.nanosec / 1000ULL);
+}
+
+
+#endif // AP_DDS_ENABLED
diff --git a/libraries/AP_DDS/AP_DDS_Type_Conversions.h b/libraries/AP_DDS/AP_DDS_Type_Conversions.h
new file mode 100644
index 00000000000000..71b2e3182de299
--- /dev/null
+++ b/libraries/AP_DDS/AP_DDS_Type_Conversions.h
@@ -0,0 +1,17 @@
+// Class for handling type conversions for DDS.
+
+#pragma once
+
+#if AP_DDS_ENABLED
+
+#include "builtin_interfaces/msg/Time.h"
+
+class AP_DDS_Type_Conversions
+{
+public:
+
+ // Convert ROS time to a uint64_t [μS]
+ static uint64_t time_u64_micros(const builtin_interfaces_msg_Time& ros_time);
+};
+
+#endif // AP_DDS_ENABLED
diff --git a/libraries/AP_DDS/AP_DDS_UDP.cpp b/libraries/AP_DDS/AP_DDS_UDP.cpp
new file mode 100644
index 00000000000000..0569e0ecdabeb8
--- /dev/null
+++ b/libraries/AP_DDS/AP_DDS_UDP.cpp
@@ -0,0 +1,89 @@
+#include "AP_DDS_Client.h"
+
+#if AP_DDS_UDP_ENABLED
+
+#include
+
+/*
+ open connection on UDP
+ */
+bool AP_DDS_Client::udp_transport_open(uxrCustomTransport *t)
+{
+ AP_DDS_Client *dds = (AP_DDS_Client *)t->args;
+ auto *sock = new SocketAPM(true);
+ if (sock == nullptr) {
+ return false;
+ }
+ if (!sock->connect(dds->udp.ip, dds->udp.port.get())) {
+ return false;
+ }
+ dds->udp.socket = sock;
+ return true;
+}
+
+/*
+ close UDP connection
+ */
+bool AP_DDS_Client::udp_transport_close(uxrCustomTransport *t)
+{
+ AP_DDS_Client *dds = (AP_DDS_Client *)t->args;
+ delete dds->udp.socket;
+ dds->udp.socket = nullptr;
+ return true;
+}
+
+/*
+ write on UDP
+ */
+size_t AP_DDS_Client::udp_transport_write(uxrCustomTransport *t, const uint8_t* buf, size_t len, uint8_t* error)
+{
+ AP_DDS_Client *dds = (AP_DDS_Client *)t->args;
+ if (dds->udp.socket == nullptr) {
+ *error = EINVAL;
+ return 0;
+ }
+ const ssize_t ret = dds->udp.socket->send(buf, len);
+ if (ret <= 0) {
+ *error = errno;
+ return 0;
+ }
+ return ret;
+}
+
+/*
+ read from UDP
+ */
+size_t AP_DDS_Client::udp_transport_read(uxrCustomTransport *t, uint8_t* buf, size_t len, int timeout_ms, uint8_t* error)
+{
+ AP_DDS_Client *dds = (AP_DDS_Client *)t->args;
+ if (dds->udp.socket == nullptr) {
+ *error = EINVAL;
+ return 0;
+ }
+ const ssize_t ret = dds->udp.socket->recv(buf, len, timeout_ms);
+ if (ret <= 0) {
+ *error = errno;
+ return 0;
+ }
+ return ret;
+}
+
+/*
+ initialise UDP connection
+ */
+bool AP_DDS_Client::ddsUdpInit()
+{
+ // setup a non-framed transport for UDP
+ uxr_set_custom_transport_callbacks(&udp.transport, false,
+ udp_transport_open,
+ udp_transport_close,
+ udp_transport_write,
+ udp_transport_read);
+
+ if (!uxr_init_custom_transport(&udp.transport, (void*)this)) {
+ return false;
+ }
+ uxr_init_session(&session, &udp.transport.comm, uniqueClientKey);
+ return true;
+}
+#endif // AP_DDS_UDP_ENABLED
diff --git a/libraries/AP_DDS/AP_DDS_config.h b/libraries/AP_DDS/AP_DDS_config.h
new file mode 100644
index 00000000000000..febd1a75423bec
--- /dev/null
+++ b/libraries/AP_DDS/AP_DDS_config.h
@@ -0,0 +1,17 @@
+#pragma once
+
+#include
+
+#ifndef AP_DDS_ENABLED
+#define AP_DDS_ENABLED 1
+#endif
+
+// UDP only on SITL for now
+#ifndef AP_DDS_UDP_ENABLED
+#define AP_DDS_UDP_ENABLED AP_DDS_ENABLED && (CONFIG_HAL_BOARD == HAL_BOARD_SITL)
+#endif
+
+#include
+#ifndef AP_DDS_VISUALODOM_ENABLED
+#define AP_DDS_VISUALODOM_ENABLED HAL_VISUALODOM_ENABLED && AP_DDS_ENABLED
+#endif
diff --git a/libraries/AP_DDS/Idl/Duration.idl b/libraries/AP_DDS/Idl/builtin_interfaces/msg/Duration.idl
similarity index 99%
rename from libraries/AP_DDS/Idl/Duration.idl
rename to libraries/AP_DDS/Idl/builtin_interfaces/msg/Duration.idl
index 9f125547c61d87..6180b7fa8eb710 100644
--- a/libraries/AP_DDS/Idl/Duration.idl
+++ b/libraries/AP_DDS/Idl/builtin_interfaces/msg/Duration.idl
@@ -20,3 +20,4 @@ module builtin_interfaces {
};
};
};
+
diff --git a/libraries/AP_DDS/Idl/Time.idl b/libraries/AP_DDS/Idl/builtin_interfaces/msg/Time.idl
similarity index 99%
rename from libraries/AP_DDS/Idl/Time.idl
rename to libraries/AP_DDS/Idl/builtin_interfaces/msg/Time.idl
index f3c9c14042eb9b..f80cb5685fdd58 100644
--- a/libraries/AP_DDS/Idl/Time.idl
+++ b/libraries/AP_DDS/Idl/builtin_interfaces/msg/Time.idl
@@ -19,3 +19,4 @@ module builtin_interfaces {
};
};
};
+
diff --git a/libraries/AP_DDS/Idl/geographic_msgs/msg/GeoPoint.idl b/libraries/AP_DDS/Idl/geographic_msgs/msg/GeoPoint.idl
new file mode 100644
index 00000000000000..e5dbbdf65bb801
--- /dev/null
+++ b/libraries/AP_DDS/Idl/geographic_msgs/msg/GeoPoint.idl
@@ -0,0 +1,30 @@
+// generated from rosidl_adapter/resource/msg.idl.em
+// with input from geographic_msgs/msg/GeoPoint.msg
+// generated code does not contain a copyright notice
+
+
+module geographic_msgs {
+ module msg {
+ @verbatim (language="comment", text=
+ "Geographic point, using the WGS 84 reference ellipsoid.")
+ struct GeoPoint {
+ @verbatim (language="comment", text=
+ "Latitude. Positive is north of equator; negative is south" "\n"
+ "(-90 <= latitude <= +90).")
+ @unit (value="degrees")
+ double latitude;
+
+ @verbatim (language="comment", text=
+ "Longitude. Positive is east of prime meridian; negative is" "\n"
+ "west (-180 <= longitude <= +180). At the poles, latitude is -90 or" "\n"
+ "+90, and longitude is irrelevant, but must be in range.")
+ @unit (value="degrees")
+ double longitude;
+
+ @verbatim (language="comment", text=
+ "Altitude. Positive is above the WGS 84 ellipsoid (NaN if unspecified).")
+ @unit (value="m")
+ double altitude;
+ };
+ };
+};
diff --git a/libraries/AP_DDS/Idl/geographic_msgs/msg/GeoPose.idl b/libraries/AP_DDS/Idl/geographic_msgs/msg/GeoPose.idl
new file mode 100644
index 00000000000000..169dd375eb32d0
--- /dev/null
+++ b/libraries/AP_DDS/Idl/geographic_msgs/msg/GeoPose.idl
@@ -0,0 +1,21 @@
+// generated from rosidl_adapter/resource/msg.idl.em
+// with input from geographic_msgs/msg/GeoPose.msg
+// generated code does not contain a copyright notice
+
+#include "geometry_msgs/msg/Quaternion.idl"
+#include "geographic_msgs/msg/GeoPoint.idl"
+
+module geographic_msgs {
+ module msg {
+ @verbatim (language="comment", text=
+ "Geographic pose, using the WGS 84 reference ellipsoid." "\n"
+ "" "\n"
+ "Orientation uses the East-North-Up (ENU) frame of reference." "\n"
+ "(But, what about singularities at the poles?)")
+ struct GeoPose {
+ geographic_msgs::msg::GeoPoint position;
+
+ geometry_msgs::msg::Quaternion orientation;
+ };
+ };
+};
diff --git a/libraries/AP_DDS/Idl/geographic_msgs/msg/GeoPoseStamped.idl b/libraries/AP_DDS/Idl/geographic_msgs/msg/GeoPoseStamped.idl
new file mode 100644
index 00000000000000..526458f0974c8e
--- /dev/null
+++ b/libraries/AP_DDS/Idl/geographic_msgs/msg/GeoPoseStamped.idl
@@ -0,0 +1,16 @@
+// generated from rosidl_adapter/resource/msg.idl.em
+// with input from geographic_msgs/msg/GeoPoseStamped.msg
+// generated code does not contain a copyright notice
+
+#include "geographic_msgs/msg/GeoPose.idl"
+#include "std_msgs/msg/Header.idl"
+
+module geographic_msgs {
+ module msg {
+ struct GeoPoseStamped {
+ std_msgs::msg::Header header;
+
+ geographic_msgs::msg::GeoPose pose;
+ };
+ };
+};
diff --git a/libraries/AP_DDS/Idl/Point.idl b/libraries/AP_DDS/Idl/geometry_msgs/msg/Point.idl
similarity index 99%
rename from libraries/AP_DDS/Idl/Point.idl
rename to libraries/AP_DDS/Idl/geometry_msgs/msg/Point.idl
index 31f3f0e84274f1..967b02b431d1de 100644
--- a/libraries/AP_DDS/Idl/Point.idl
+++ b/libraries/AP_DDS/Idl/geometry_msgs/msg/Point.idl
@@ -16,3 +16,4 @@ module geometry_msgs {
};
};
};
+
diff --git a/libraries/AP_DDS/Idl/Pose.idl b/libraries/AP_DDS/Idl/geometry_msgs/msg/Pose.idl
similarity index 84%
rename from libraries/AP_DDS/Idl/Pose.idl
rename to libraries/AP_DDS/Idl/geometry_msgs/msg/Pose.idl
index 9d7d0000cc30e9..4b166145c0c770 100644
--- a/libraries/AP_DDS/Idl/Pose.idl
+++ b/libraries/AP_DDS/Idl/geometry_msgs/msg/Pose.idl
@@ -2,8 +2,8 @@
// with input from geometry_msgs/msg/Pose.msg
// generated code does not contain a copyright notice
-#include "Point.idl"
-#include "Quaternion.idl"
+#include "geometry_msgs/msg/Point.idl"
+#include "geometry_msgs/msg/Quaternion.idl"
module geometry_msgs {
module msg {
@@ -16,3 +16,4 @@ module geometry_msgs {
};
};
};
+
diff --git a/libraries/AP_DDS/Idl/PoseStamped.idl b/libraries/AP_DDS/Idl/geometry_msgs/msg/PoseStamped.idl
similarity index 84%
rename from libraries/AP_DDS/Idl/PoseStamped.idl
rename to libraries/AP_DDS/Idl/geometry_msgs/msg/PoseStamped.idl
index e69efef37ab4ac..5da5e2225902dc 100644
--- a/libraries/AP_DDS/Idl/PoseStamped.idl
+++ b/libraries/AP_DDS/Idl/geometry_msgs/msg/PoseStamped.idl
@@ -2,8 +2,8 @@
// with input from geometry_msgs/msg/PoseStamped.msg
// generated code does not contain a copyright notice
-#include "Pose.idl"
-#include "Header.idl"
+#include "geometry_msgs/msg/Pose.idl"
+#include "std_msgs/msg/Header.idl"
module geometry_msgs {
module msg {
@@ -16,3 +16,4 @@ module geometry_msgs {
};
};
};
+
diff --git a/libraries/AP_DDS/Idl/Quaternion.idl b/libraries/AP_DDS/Idl/geometry_msgs/msg/Quaternion.idl
similarity index 99%
rename from libraries/AP_DDS/Idl/Quaternion.idl
rename to libraries/AP_DDS/Idl/geometry_msgs/msg/Quaternion.idl
index 3c0eb79c84dd7e..4484c98b914404 100644
--- a/libraries/AP_DDS/Idl/Quaternion.idl
+++ b/libraries/AP_DDS/Idl/geometry_msgs/msg/Quaternion.idl
@@ -22,3 +22,4 @@ module geometry_msgs {
};
};
};
+
diff --git a/libraries/AP_DDS/Idl/Transform.idl b/libraries/AP_DDS/Idl/geometry_msgs/msg/Transform.idl
similarity index 83%
rename from libraries/AP_DDS/Idl/Transform.idl
rename to libraries/AP_DDS/Idl/geometry_msgs/msg/Transform.idl
index abcdbe435e1eba..cb0497af12d2d0 100644
--- a/libraries/AP_DDS/Idl/Transform.idl
+++ b/libraries/AP_DDS/Idl/geometry_msgs/msg/Transform.idl
@@ -2,8 +2,8 @@
// with input from geometry_msgs/msg/Transform.msg
// generated code does not contain a copyright notice
-#include "Quaternion.idl"
-#include "Vector3.idl"
+#include "geometry_msgs/msg/Quaternion.idl"
+#include "geometry_msgs/msg/Vector3.idl"
module geometry_msgs {
module msg {
@@ -15,4 +15,4 @@ module geometry_msgs {
geometry_msgs::msg::Quaternion rotation;
};
};
-};
\ No newline at end of file
+};
diff --git a/libraries/AP_DDS/Idl/TransformStamped.idl b/libraries/AP_DDS/Idl/geometry_msgs/msg/TransformStamped.idl
similarity index 94%
rename from libraries/AP_DDS/Idl/TransformStamped.idl
rename to libraries/AP_DDS/Idl/geometry_msgs/msg/TransformStamped.idl
index 4a655484ee37ce..dddd59c921ab4f 100644
--- a/libraries/AP_DDS/Idl/TransformStamped.idl
+++ b/libraries/AP_DDS/Idl/geometry_msgs/msg/TransformStamped.idl
@@ -2,8 +2,8 @@
// with input from geometry_msgs/msg/TransformStamped.msg
// generated code does not contain a copyright notice
-#include "Transform.idl"
-#include "Header.idl"
+#include "geometry_msgs/msg/Transform.idl"
+#include "std_msgs/msg/Header.idl"
module geometry_msgs {
module msg {
@@ -32,4 +32,4 @@ module geometry_msgs {
geometry_msgs::msg::Transform transform;
};
};
-};
\ No newline at end of file
+};
diff --git a/libraries/AP_DDS/Idl/Twist.idl b/libraries/AP_DDS/Idl/geometry_msgs/msg/Twist.idl
similarity index 91%
rename from libraries/AP_DDS/Idl/Twist.idl
rename to libraries/AP_DDS/Idl/geometry_msgs/msg/Twist.idl
index 1aa8f1fd087f11..e5c5e54e4d5b3b 100644
--- a/libraries/AP_DDS/Idl/Twist.idl
+++ b/libraries/AP_DDS/Idl/geometry_msgs/msg/Twist.idl
@@ -2,7 +2,7 @@
// with input from geometry_msgs/msg/Twist.msg
// generated code does not contain a copyright notice
-#include "Vector3.idl"
+#include "geometry_msgs/msg/Vector3.idl"
module geometry_msgs {
module msg {
@@ -15,3 +15,4 @@ module geometry_msgs {
};
};
};
+
diff --git a/libraries/AP_DDS/Idl/TwistStamped.idl b/libraries/AP_DDS/Idl/geometry_msgs/msg/TwistStamped.idl
similarity index 70%
rename from libraries/AP_DDS/Idl/TwistStamped.idl
rename to libraries/AP_DDS/Idl/geometry_msgs/msg/TwistStamped.idl
index 0ea65a490f93ca..29c1fa6b0d3214 100644
--- a/libraries/AP_DDS/Idl/TwistStamped.idl
+++ b/libraries/AP_DDS/Idl/geometry_msgs/msg/TwistStamped.idl
@@ -2,13 +2,8 @@
// with input from geometry_msgs/msg/TwistStamped.msg
// generated code does not contain a copyright notice
-#include "Vector3.idl"
-#include "Header.idl"
-
-struct Twist {
- geometry_msgs::msg::Vector3 linear;
- geometry_msgs::msg::Vector3 angular;
-};
+#include "geometry_msgs/msg/Twist.idl"
+#include "std_msgs/msg/Header.idl"
module geometry_msgs {
module msg {
@@ -17,7 +12,8 @@ module geometry_msgs {
struct TwistStamped {
std_msgs::msg::Header header;
- Twist twist;
+ geometry_msgs::msg::Twist twist;
};
};
};
+
diff --git a/libraries/AP_DDS/Idl/Vector3.idl b/libraries/AP_DDS/Idl/geometry_msgs/msg/Vector3.idl
similarity index 99%
rename from libraries/AP_DDS/Idl/Vector3.idl
rename to libraries/AP_DDS/Idl/geometry_msgs/msg/Vector3.idl
index b01ff408eb2e80..b2081595532ba9 100644
--- a/libraries/AP_DDS/Idl/Vector3.idl
+++ b/libraries/AP_DDS/Idl/geometry_msgs/msg/Vector3.idl
@@ -20,3 +20,4 @@ module geometry_msgs {
};
};
};
+
diff --git a/libraries/AP_DDS/Idl/rosgraph_msgs/msg/Clock.idl b/libraries/AP_DDS/Idl/rosgraph_msgs/msg/Clock.idl
new file mode 100644
index 00000000000000..bda2e92608e5a2
--- /dev/null
+++ b/libraries/AP_DDS/Idl/rosgraph_msgs/msg/Clock.idl
@@ -0,0 +1,17 @@
+// generated from rosidl_adapter/resource/msg.idl.em
+// with input from rosgraph_msgs/msg/Clock.msg
+// generated code does not contain a copyright notice
+
+#include "builtin_interfaces/msg/Time.idl"
+
+module rosgraph_msgs {
+ module msg {
+ @verbatim (language="comment", text=
+ "This message communicates the current time." "\n"
+ "" "\n"
+ "For more information, see https://design.ros2.org/articles/clock_and_time.html.")
+ struct Clock {
+ builtin_interfaces::msg::Time clock;
+ };
+ };
+};
diff --git a/libraries/AP_DDS/Idl/BatteryState.idl b/libraries/AP_DDS/Idl/sensor_msgs/msg/BatteryState.idl
similarity index 67%
rename from libraries/AP_DDS/Idl/BatteryState.idl
rename to libraries/AP_DDS/Idl/sensor_msgs/msg/BatteryState.idl
index 5970c11dba86f4..0ca3292d96ef1b 100644
--- a/libraries/AP_DDS/Idl/BatteryState.idl
+++ b/libraries/AP_DDS/Idl/sensor_msgs/msg/BatteryState.idl
@@ -2,38 +2,39 @@
// with input from sensor_msgs/msg/BatteryState.msg
// generated code does not contain a copyright notice
-#include "Header.idl"
+#include "std_msgs/msg/Header.idl"
module sensor_msgs {
module msg {
+ typedef float float__14[14];
module BatteryState_Constants {
@verbatim (language="comment", text=
"Constants are chosen to match the enums in the linux kernel" "\n" "defined in include/linux/power_supply.h as of version 3.7" "\n" "The one difference is for style reasons the constants are" "\n" "all uppercase not mixed case." "\n" "Power supply status constants")
- const octet POWER_SUPPLY_STATUS_UNKNOWN = 0;
- const octet POWER_SUPPLY_STATUS_CHARGING = 1;
- const octet POWER_SUPPLY_STATUS_DISCHARGING = 2;
- const octet POWER_SUPPLY_STATUS_NOT_CHARGING = 3;
- const octet POWER_SUPPLY_STATUS_FULL = 4;
+ const uint8 POWER_SUPPLY_STATUS_UNKNOWN = 0;
+ const uint8 POWER_SUPPLY_STATUS_CHARGING = 1;
+ const uint8 POWER_SUPPLY_STATUS_DISCHARGING = 2;
+ const uint8 POWER_SUPPLY_STATUS_NOT_CHARGING = 3;
+ const uint8 POWER_SUPPLY_STATUS_FULL = 4;
@verbatim (language="comment", text=
"Power supply health constants")
- const octet POWER_SUPPLY_HEALTH_UNKNOWN = 0;
- const octet POWER_SUPPLY_HEALTH_GOOD = 1;
- const octet POWER_SUPPLY_HEALTH_OVERHEAT = 2;
- const octet POWER_SUPPLY_HEALTH_DEAD = 3;
- const octet POWER_SUPPLY_HEALTH_OVERVOLTAGE = 4;
- const octet POWER_SUPPLY_HEALTH_UNSPEC_FAILURE = 5;
- const octet POWER_SUPPLY_HEALTH_COLD = 6;
- const octet POWER_SUPPLY_HEALTH_WATCHDOG_TIMER_EXPIRE = 7;
- const octet POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE = 8;
+ const uint8 POWER_SUPPLY_HEALTH_UNKNOWN = 0;
+ const uint8 POWER_SUPPLY_HEALTH_GOOD = 1;
+ const uint8 POWER_SUPPLY_HEALTH_OVERHEAT = 2;
+ const uint8 POWER_SUPPLY_HEALTH_DEAD = 3;
+ const uint8 POWER_SUPPLY_HEALTH_OVERVOLTAGE = 4;
+ const uint8 POWER_SUPPLY_HEALTH_UNSPEC_FAILURE = 5;
+ const uint8 POWER_SUPPLY_HEALTH_COLD = 6;
+ const uint8 POWER_SUPPLY_HEALTH_WATCHDOG_TIMER_EXPIRE = 7;
+ const uint8 POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE = 8;
@verbatim (language="comment", text=
"Power supply technology (chemistry) constants")
- const octet POWER_SUPPLY_TECHNOLOGY_UNKNOWN = 0;
- const octet POWER_SUPPLY_TECHNOLOGY_NIMH = 1;
- const octet POWER_SUPPLY_TECHNOLOGY_LION = 2;
- const octet POWER_SUPPLY_TECHNOLOGY_LIPO = 3;
- const octet POWER_SUPPLY_TECHNOLOGY_LIFE = 4;
- const octet POWER_SUPPLY_TECHNOLOGY_NICD = 5;
- const octet POWER_SUPPLY_TECHNOLOGY_LIMN = 6;
+ const uint8 POWER_SUPPLY_TECHNOLOGY_UNKNOWN = 0;
+ const uint8 POWER_SUPPLY_TECHNOLOGY_NIMH = 1;
+ const uint8 POWER_SUPPLY_TECHNOLOGY_LION = 2;
+ const uint8 POWER_SUPPLY_TECHNOLOGY_LIPO = 3;
+ const uint8 POWER_SUPPLY_TECHNOLOGY_LIFE = 4;
+ const uint8 POWER_SUPPLY_TECHNOLOGY_NICD = 5;
+ const uint8 POWER_SUPPLY_TECHNOLOGY_LIMN = 6;
};
struct BatteryState {
std_msgs::msg::Header header;
@@ -68,15 +69,15 @@ module sensor_msgs {
@verbatim (language="comment", text=
"The charging status as reported. Values defined above")
- octet power_supply_status;
+ uint8 power_supply_status;
@verbatim (language="comment", text=
"The battery health metric. Values defined above")
- octet power_supply_health;
+ uint8 power_supply_health;
@verbatim (language="comment", text=
"The battery chemistry. Values defined above")
- octet power_supply_technology;
+ uint8 power_supply_technology;
@verbatim (language="comment", text=
"True if the battery is present")
@@ -85,12 +86,12 @@ module sensor_msgs {
@verbatim (language="comment", text=
"An array of individual cell voltages for each cell in the pack" "\n"
"If individual voltages unknown but number of cells known set each to NaN")
- sequence cell_voltage;
+ float__14 cell_voltage;
@verbatim (language="comment", text=
"An array of individual cell temperatures for each cell in the pack" "\n"
"If individual temperatures unknown but number of cells known set each to NaN")
- sequence cell_temperature;
+ float__14 cell_temperature;
@verbatim (language="comment", text=
"The location into which the battery is inserted. (slot number or plug)")
@@ -102,3 +103,4 @@ module sensor_msgs {
};
};
};
+
diff --git a/libraries/AP_DDS/Idl/sensor_msgs/msg/Joy.idl b/libraries/AP_DDS/Idl/sensor_msgs/msg/Joy.idl
new file mode 100644
index 00000000000000..27759f48221294
--- /dev/null
+++ b/libraries/AP_DDS/Idl/sensor_msgs/msg/Joy.idl
@@ -0,0 +1,25 @@
+// generated from rosidl_adapter/resource/msg.idl.em
+// with input from sensor_msgs/msg/Joy.msg
+// generated code does not contain a copyright notice
+
+#include "std_msgs/msg/Header.idl"
+
+module sensor_msgs {
+ module msg {
+ @verbatim (language="comment", text=
+ "Reports the state of a joystick's axes and buttons.")
+ struct Joy {
+ @verbatim (language="comment", text=
+ "The timestamp is the time at which data is received from the joystick.")
+ std_msgs::msg::Header header;
+
+ @verbatim (language="comment", text=
+ "The axes measurements from a joystick.")
+ sequence axes;
+
+ @verbatim (language="comment", text=
+ "The buttons measurements from a joystick.")
+ sequence buttons;
+ };
+ };
+};
diff --git a/libraries/AP_DDS/Idl/NavSatFix.idl b/libraries/AP_DDS/Idl/sensor_msgs/msg/NavSatFix.idl
similarity index 95%
rename from libraries/AP_DDS/Idl/NavSatFix.idl
rename to libraries/AP_DDS/Idl/sensor_msgs/msg/NavSatFix.idl
index cfe9024ed18a27..401875605de9ba 100644
--- a/libraries/AP_DDS/Idl/NavSatFix.idl
+++ b/libraries/AP_DDS/Idl/sensor_msgs/msg/NavSatFix.idl
@@ -1,9 +1,9 @@
-/// generated from rosidl_adapter/resource/msg.idl.em
+// generated from rosidl_adapter/resource/msg.idl.em
// with input from sensor_msgs/msg/NavSatFix.msg
// generated code does not contain a copyright notice
-#include "NavSatStatus.idl"
-#include "Header.idl"
+#include "sensor_msgs/msg/NavSatStatus.idl"
+#include "std_msgs/msg/Header.idl"
module sensor_msgs {
module msg {
@@ -65,3 +65,4 @@ module sensor_msgs {
};
};
};
+
diff --git a/libraries/AP_DDS/Idl/NavSatStatus.idl b/libraries/AP_DDS/Idl/sensor_msgs/msg/NavSatStatus.idl
similarity index 99%
rename from libraries/AP_DDS/Idl/NavSatStatus.idl
rename to libraries/AP_DDS/Idl/sensor_msgs/msg/NavSatStatus.idl
index a19fa90235325b..5dacc9dcba9699 100644
--- a/libraries/AP_DDS/Idl/NavSatStatus.idl
+++ b/libraries/AP_DDS/Idl/sensor_msgs/msg/NavSatStatus.idl
@@ -40,3 +40,4 @@ module sensor_msgs {
};
};
};
+
diff --git a/libraries/AP_DDS/Idl/Header.idl b/libraries/AP_DDS/Idl/std_msgs/msg/Header.idl
similarity index 94%
rename from libraries/AP_DDS/Idl/Header.idl
rename to libraries/AP_DDS/Idl/std_msgs/msg/Header.idl
index 6b4885994206a9..47852f815abf75 100644
--- a/libraries/AP_DDS/Idl/Header.idl
+++ b/libraries/AP_DDS/Idl/std_msgs/msg/Header.idl
@@ -2,7 +2,7 @@
// with input from std_msgs/msg/Header.msg
// generated code does not contain a copyright notice
-#include "Time.idl"
+#include "builtin_interfaces/msg/Time.idl"
module std_msgs {
module msg {
@@ -21,3 +21,4 @@ module std_msgs {
};
};
};
+
diff --git a/libraries/AP_DDS/Idl/TFMessage.idl b/libraries/AP_DDS/Idl/tf2_msgs/msg/TFMessage.idl
similarity index 84%
rename from libraries/AP_DDS/Idl/TFMessage.idl
rename to libraries/AP_DDS/Idl/tf2_msgs/msg/TFMessage.idl
index 69fd27bdde02a8..95f8017e4ed16a 100644
--- a/libraries/AP_DDS/Idl/TFMessage.idl
+++ b/libraries/AP_DDS/Idl/tf2_msgs/msg/TFMessage.idl
@@ -2,7 +2,7 @@
// with input from tf2_msgs/msg/TFMessage.msg
// generated code does not contain a copyright notice
-#include "TransformStamped.idl"
+#include "geometry_msgs/msg/TransformStamped.idl"
module tf2_msgs {
module msg {
@@ -10,4 +10,4 @@ module tf2_msgs {
sequence transforms;
};
};
-};
\ No newline at end of file
+};
diff --git a/libraries/AP_DDS/Is-Config/Arm_Motors_DDS_IS_config.yaml b/libraries/AP_DDS/Is-Config/Arm_Motors_DDS_IS_config.yaml
new file mode 100644
index 00000000000000..ef46bf6aa943b5
--- /dev/null
+++ b/libraries/AP_DDS/Is-Config/Arm_Motors_DDS_IS_config.yaml
@@ -0,0 +1,36 @@
+types:
+ idls:
+ - >
+ struct ArmMotors_Request
+ {
+ boolean arm;
+ };
+
+ struct ArmMotors_Response
+ {
+ boolean result;
+ };
+systems:
+ dds: { type: fastdds }
+ ros2: { type: ros2 }
+
+routes:
+ dds_server:
+ server: dds
+ clients: ros2
+
+services:
+ arm_motors: {
+ request_type: ArmMotors_Request,
+ reply_type: ArmMotors_Response,
+ route: dds_server,
+ remap: {
+ dds: {
+ topic: ArmMotorsService,
+ },
+ ros2: {
+ request_type: "ardupilot_msgs/ArmMotors:request",
+ reply_type: "ardupilot_msgs/ArmMotors:response"
+ }
+ }
+ }
diff --git a/libraries/AP_DDS/README.md b/libraries/AP_DDS/README.md
index 9483f3e70117a5..5d2f60d6a2e3ce 100644
--- a/libraries/AP_DDS/README.md
+++ b/libraries/AP_DDS/README.md
@@ -2,7 +2,30 @@
## Architecture
-Ardupilot contains the DDS Client library, which can run as SITL. Then, the DDS application runs a ROS2 node, an EProsima Integration Service, and the MicroXRCE Agent. The two systems communicate over serial, which is the only supported protocol in Ardupilot MicroXCE DDS at this time.
+Ardupilot contains the DDS Client library, which can run as SITL. Then, the DDS application runs a ROS2 node, an EProsima Integration Service, and the MicroXRCE Agent. The two systems communicate can communicate over serial or UDP.
+
+```mermaid
+---
+title: UDP Loopback
+---
+graph LR
+
+ subgraph Linux Computer
+
+ subgraph Ardupilot SITL
+ veh[sim_vehicle.py] <--> xrceClient[EProsima Micro XRCE DDS Client]
+ xrceClient <--> port1[udp:2019]
+ end
+
+ subgraph DDS Application
+ ros[ROS2 Node] <--> agent[Micro ROS Agent]
+ agent <-->port1[udp:2019]
+ end
+
+ loopback
+
+ end
+```
```mermaid
---
@@ -27,7 +50,6 @@ graph LR
end
```
-Currently, serial is the only supported transport, but there are plans to add IP-based transport over ethernet.
## Installing Build Dependencies
@@ -38,14 +60,14 @@ While DDS support in Ardupilot is mostly through git submodules, another tool ne
```console
sudo apt install default-jre
````
-- Follow instructions [here](https://micro-xrce-dds.docs.eprosima.com/en/latest/installation.html#installing-the-micro-xrce-dds-gen-tool) to install the generator, but use `develop` branch instead of `master` (for now).
+- Follow instructions [here](https://micro-xrce-dds.docs.eprosima.com/en/latest/installation.html#installing-the-micro-xrce-dds-gen-tool) to install the latest version of the generator using Ardupilot's mirror
```console
- git clone -b develop --recurse-submodules https://github.com/eProsima/Micro-XRCE-DDS-Gen.git
+ git clone --recurse-submodules https://github.com/ardupilot/Micro-XRCE-DDS-Gen.git
cd Micro-XRCE-DDS-Gen
./gradlew assemble
```
-- Add the generator directory to $PATH.
+- Add the generator directory to $PATH.
```console
# Add this to ~/.bashrc
@@ -68,7 +90,7 @@ For now, avoid having simultaneous local and global installs.
If you followed the [global install](https://fast-dds.docs.eprosima.com/en/latest/installation/sources/sources_linux.html#global-installation)
section, you should remove it and switch to local install.
-## Setup serial for SITL with DDS
+### Serial Only: Set up serial for SITL with DDS
On Linux, creating a virtual serial port will be necessary to use serial in SITL, because of that install socat.
@@ -80,21 +102,30 @@ sudo apt-get install socat
## Setup ardupilot for SITL with DDS
Set up your [SITL](https://ardupilot.org/dev/docs/setting-up-sitl-on-linux.html).
-Run the simulator with the following command. Take note how two parameters need adjusting from default to use DDS.
-| Name | Description |
-| - | - |
-| SERIAL1_BAUD | The serial baud rate for DDS |
-| SERIAL1_PROTOCOL | Set this to 45 to use DDS on the serial port |
+Run the simulator with the following command. If using UDP, the only parameter you need to set it `DDS_ENABLE`.
+
+| Name | Description | Default |
+| - | - | - |
+| DDS_ENABLE | Set to 1 to enable DDS, or 0 to disable | 1 |
+| SERIAL1_BAUD | The serial baud rate for DDS | 57 |
+| SERIAL1_PROTOCOL | Set this to 45 to use DDS on the serial port | 0 |
```bash
# Wipe params till you see "AP: ArduPilot Ready"
# Select your favorite vehicle type
-sim_vehicle.py -w -v ArduPlane
+sim_vehicle.py -w -v ArduPlane --console -DG --enable-dds
-# Set params
+# Only set this for Serial, which means 115200 baud
param set SERIAL1_BAUD 115
# See libraries/AP_SerialManager/AP_SerialManager.h AP_SerialManager SerialProtocol_DDS_XRCE
param set SERIAL1_PROTOCOL 45
```
+
+DDS is currently enabled by default, if it's part of the build. To disable it, run the following and reboot the simulator.
+```
+param set DDS_ENABLE 0
+REBOOT
+```
+
## Setup ROS 2 and micro-ROS
Follow the steps to use the microROS Agent
@@ -103,6 +134,11 @@ Follow the steps to use the microROS Agent
- https://docs.ros.org/en/humble/Installation/Ubuntu-Install-Debians.html
+- Install geographic_msgs
+ ```bash
+ sudo apt install ros-humble-geographic-msgs
+ ```
+
- Install and run the microROS agent (as descibed here). Make sure to use the `humble` branch.
- Follow [the instructions](https://micro.ros.org/docs/tutorials/core/first_application_linux/) for the following:
@@ -118,11 +154,27 @@ Until this [PR](https://github.com/micro-ROS/micro-ROS.github.io/pull/401) is me
## Using the ROS2 CLI to Read Ardupilot Data
After your setups are complete, do the following:
-
- Source the ros2 installation
```bash
source /opt/ros/humble/setup.bash
```
+
+Next, follow the associated section for your chosen transport, and finally you can use the ROS 2 CLI.
+
+### UDP (recommended for SITL)
+
+- Run the microROS agent
+ ```bash
+ cd ardupilot/libraries/AP_DDS
+ ros2 run micro_ros_agent micro_ros_agent udp4 -p 2019 -r dds_xrce_profile.xml
+ ```
+- Run SITL (remember to kill any terminals running ardupilot SITL beforehand)
+ ```bash
+ sim_vehicle.py -v ArduPlane -DG --console --enable-dds
+ ```
+
+### Serial
+
- Start a virtual serial port with socat. Take note of the two `/dev/pts/*` ports. If yours are different, substitute as needed.
```bash
socat -d -d pty,raw,echo=0 pty,raw,echo=0
@@ -133,12 +185,17 @@ After your setups are complete, do the following:
- Run the microROS agent
```bash
cd ardupilot/libraries/AP_DDS
- ros2 run micro_ros_agent micro_ros_agent serial -b 115200 -D /dev/pts/2 -r dds_xrce_profile.xml # (assuming we are using tty/pts/2 for DDS Application)
+ # assuming we are using tty/pts/2 for DDS Application
+ ros2 run micro_ros_agent micro_ros_agent serial -b 115200 -r dds_xrce_profile.xml -D /dev/pts/2
```
- Run SITL (remember to kill any terminals running ardupilot SITL beforehand)
```bash
- sim_vehicle.py -v ArduPlane -D --console --enable-dds -A "--uartC=uart:/dev/pts/1" # (assuming we are using /dev/pts/1 for Ardupilot SITL)
+ # assuming we are using /dev/pts/1 for Ardupilot SITL
+ sim_vehicle.py -v ArduPlane -DG --console --enable-dds -A "--uartC=uart:/dev/pts/1"
```
+
+## Use ROS 2 CLI
+
- You should be able to see the agent here and view the data output.
```bash
$ ros2 node list
@@ -146,40 +203,76 @@ After your setups are complete, do the following:
$ ros2 topic list -v
Published topics:
- * /ROS2_NavSatFix0 [sensor_msgs/msg/NavSatFix] 1 publisher
- * /ROS2_Time [builtin_interfaces/msg/Time] 1 publisher
- * /parameter_events [rcl_interfaces/msg/ParameterEvent] 1 publisher
- * /rosout [rcl_interfaces/msg/Log] 1 publisher
- * /tf [tf2_msgs/msg/TFMessage] 1 publisher
+ * /ap/battery/battery0 [sensor_msgs/msg/BatteryState] 1 publisher
+ * /ap/clock [rosgraph_msgs/msg/Clock] 1 publisher
+ * /ap/geopose/filtered [geographic_msgs/msg/GeoPoseStamped] 1 publisher
+ * /ap/navsat/navsat0 [sensor_msgs/msg/NavSatFix] 1 publisher
+ * /ap/pose/filtered [geometry_msgs/msg/PoseStamped] 1 publisher
+ * /ap/tf_static [tf2_msgs/msg/TFMessage] 1 publisher
+ * /ap/time [builtin_interfaces/msg/Time] 1 publisher
+ * /ap/twist/filtered [geometry_msgs/msg/TwistStamped] 1 publisher
+ * /parameter_events [rcl_interfaces/msg/ParameterEvent] 1 publisher
+ * /rosout [rcl_interfaces/msg/Log] 1 publisher
Subscribed topics:
+ * /ap/joy [sensor_msgs/msg/Joy] 1 subscriber
+ * /ap/tf [tf2_msgs/msg/TFMessage] 1 subscriber
+ * /ap/cmd_vel [geometry_msgs/msg/TwistStamped] 1 subscriber
- $ ros2 topic hz /ROS2_Time
+ $ ros2 topic hz /ap/time
average rate: 50.115
min: 0.012s max: 0.024s std dev: 0.00328s window: 52
- $ ros2 topic echo /ROS2_Time
+ $ ros2 topic echo /ap/time
sec: 1678668735
nanosec: 729410000
+
+ $ ros2 service list
+ /arm_motors
---
```
The static transforms for enabled sensors are also published, and can be recieved like so:
```console
- ros2 topic echo /tf --qos-depth 1 --qos-history keep_last --qos-reliability reliable --qos-durability transient_local --once
+ ros2 topic echo /ap/tf_static --qos-depth 1 --qos-history keep_last --qos-reliability reliable --qos-durability transient_local --once
```
- In order to consume the transforms, it's highly recommended to [create and run a transform broadcaster in ROS 2](https://docs.ros.org/en/humble/Concepts/About-Tf2.html#tutorials).
+ In order to consume the transforms, it's highly recommended to [create and run a transform broadcaster in ROS 2](https://docs.ros.org/en/humble/Concepts/About-Tf2.html#tutorials).
-## Adding DDS messages to Ardupilot
+## Using ROS 2 services (with Integration Services)
-Unlike the use of ROS 2 `.msg` files, since Ardupilot supports native DDS, the message files follow [OMG IDL DDS v4.2](https://www.omg.org/spec/IDL/4.2/PDF).
-This package is intended to work with any `.idl` file complying with those extensions, with some limitations.
+### Prerequisites
+- Install and setup [Micro-XRCE Agent](https://micro-xrce-dds.docs.eprosima.com/en/latest/installation.html#installing-the-agent-standalone)
+- Install and setup [Integration Services](https://integration-service.docs.eprosima.com/en/latest/installation_manual/installation.html) (it would be good to have a separate workspace for this)
+ - Get System Handles for [ROS 2](https://github.com/eProsima/ROS2-SH)
+ - Get System Handles for [Fast-DDS](https://github.com/eProsima/FastDDS-SH)
+- Once the above-mentioned System Handles have been cloned, build the Integration Services with the following command :
+`colcon build --cmake-args -DMIX_ROS_PACKAGES="example_interfaces ardupilot_msgs"`
+
+### Setup
+- The necessary ROS 2 messages and service defintions (especially for the Arming/Disarming Services) are already defined in the `ardupilot_msgs` folder in the `Tools` directory.
-1. IDL files need to be in the same folder, and modified includes.
-1. Topic types can't use alias types.
-1. Arrays need manually edited type names.
+### Terminal 1 (XRCE Agent)
+- Move to the **AP_DDS** folder and run the XRCE Agent as follows `MicroXRCEAgent udp4 -p 2019 -r dds_xrce_profile.xml`
-Over time, these restrictions will ideally go away.
+### Terminal 2 (Integration Service)
+- Source ROS 2 installation
+- Source Integration Service installation
+- Move to the **AP_DDS** folder and run the following command `integration-service Is-Config/Arm_Motors_DDS_IS_config.yaml`
+
+### Terminal 3 (Ardupilot)
+- Make sure you have successfully setup Ardupilot and the `DDS_ENABLE` param is set to 1
+- Run SITL with the following command `sim_vehicle.py -v ArduPlane -DG --console --enable-dds`
+
+### Terminal 4 (ROS 2 Client)
+- Run the following command : `ros2 service call /arm_motors ardupilot_msgs/srv/ArmMotors "{arm: True}"`
+
+## Contributing to AP_DDS library
+### Adding DDS messages to Ardupilot
+
+Unlike the use of ROS 2 `.msg` files, since Ardupilot supports native DDS, the message files follow [OMG IDL DDS v4.2](https://www.omg.org/spec/IDL/4.2/PDF).
+This package is intended to work with any `.idl` file complying with those extensions.
+
+Over time, these restrictions will ideally go away.
To get a new IDL file from ROS2, follow this process:
```console
@@ -187,14 +280,29 @@ cd ardupilot
source /opt/ros/humble/setup.bash
# Find the IDL file
find /opt/ros/$ROS_DISTRO -type f -wholename \*builtin_interfaces/msg/Time.idl
-# Create the directory in the source tree if it doesn't exist
-mkdir -p libraries/AP_DDS_Client/Idl/builtin_interfaces/msg/
+# Create the directory in the source tree if it doesn't exist similar to the one found in the ros directory
+mkdir -p libraries/AP_DDS/Idl/builtin_interfaces/msg/
# Copy the IDL
-cp -r /opt/ros/humble/share/builtin_interfaces/msg/Time.idl libraries/AP_DDS_Client/Idl/builtin_interfaces/msg/
-# Now, apply the mods manually to be compliant with MicroXRCEDDSGen limitations
-# Create an output directory to test it
-mkdir -p /tmp/xrce_out
-# Run the generator
-microxrceddsgen -replace -d /tmp/xrce_out libraries/AP_DDS_Client/Idl/builtin_interfaces/msg/Time.idl
-# cat /tmp/xrce_out/
+cp /opt/ros/humble/share/builtin_interfaces/msg/Time.idl libraries/AP_DDS/Idl/builtin_interfaces/msg/
+# Build the code again with the `--enable-dds` flag as described above
+```
+
+### Development Requirements
+
+Astyle is used to format the C++ code in AP_DDS. This is required for CI to pass the build.
+See [Tools/CodeStyle/ardupilot-astyle.sh](../../Tools/CodeStyle/ardupilot-astyle.sh).
+
+```console
+./Tools/CodeStyle/ardupilot-astyle.sh libraries/AP_DDS/*.h libraries/AP_DDS/*.cpp
```
+
+Pre-commit is used for other things like formatting python and XML code.
+This will run the tools automatically when you commit. If there are changes, just add them back your staging index and commit again.
+
+1. Install [pre-commit](https://pre-commit.com/#installation) python package.
+1. Install ArduPilot's hooks in the root of the repo, then commit like normal
+ ```console
+ cd ardupilot
+ pre-commit install
+ git commit
+ ```
diff --git a/libraries/AP_DDS/dds_xrce_profile.xml b/libraries/AP_DDS/dds_xrce_profile.xml
index aeed08bc8332c6..dd76da5c2ee506 100644
--- a/libraries/AP_DDS/dds_xrce_profile.xml
+++ b/libraries/AP_DDS/dds_xrce_profile.xml
@@ -6,7 +6,7 @@
- rt/ROS2_Time
+ rt/ap/time
builtin_interfaces::msg::dds_::Time_
KEEP_LAST
@@ -22,7 +22,7 @@
NO_KEY
- rt/ROS2_Time
+ rt/ap/time
builtin_interfaces::msg::dds_::Time_
KEEP_LAST
@@ -31,7 +31,7 @@
- rt/ROS2_NavSatFix0
+ rt/ap/navsat/navsat0
sensor_msgs::msg::dds_::NavSatFix_
KEEP_LAST
@@ -50,7 +50,7 @@
NO_KEY
- rt/ROS2_NavSatFix0
+ rt/ap/navsat/navsat0
sensor_msgs::msg::dds_::NavSatFix_
KEEP_LAST
@@ -59,7 +59,7 @@
- rt/tf
+ rt/ap/tf_static
tf2_msgs::msg::dds_::TFMessage_
KEEP_LAST
@@ -78,7 +78,7 @@
NO_KEY
- rt/tf
+ rt/ap/tf_static
tf2_msgs::msg::dds_::TFMessage_
KEEP_LAST
@@ -86,4 +86,188 @@
+
+ rt/ap/battery/battery0
+ sensor_msgs::msg::dds_::BatteryState_
+
+ KEEP_LAST
+ 5
+
+
+
+ PREALLOCATED_WITH_REALLOC
+
+
+ BEST_EFFORT
+
+
+ VOLATILE
+
+
+
+ NO_KEY
+ rt/ap/battery/battery0
+ sensor_msgs::msg::dds_::BatteryState_
+
+ KEEP_LAST
+ 5
+
+
+
+
+ rt/ap/pose/filtered
+ geometry_msgs::msg::dds_::PoseStamped_
+
+ KEEP_LAST
+ 5
+
+
+
+ PREALLOCATED_WITH_REALLOC
+
+
+ BEST_EFFORT
+
+
+ VOLATILE
+
+
+
+ NO_KEY
+ rt/ap/pose/filtered
+ geometry_msgs::msg::dds_::PoseStamped_
+
+ KEEP_LAST
+ 5
+
+
+
+
+ rt/ap/twist/filtered
+ geometry_msgs::msg::dds_::TwistStamped_
+
+ KEEP_LAST
+ 5
+
+
+
+ PREALLOCATED_WITH_REALLOC
+
+
+ BEST_EFFORT
+
+
+ VOLATILE
+
+
+
+ NO_KEY
+ rt/ap/twist/filtered
+ geometry_msgs::msg::dds_::TwistStamped_
+
+ KEEP_LAST
+ 5
+
+
+
+
+ rt/ap/geopose/filtered
+ geographic_msgs::msg::dds_::GeoPoseStamped_
+
+ KEEP_LAST
+ 5
+
+
+
+ PREALLOCATED_WITH_REALLOC
+
+
+ BEST_EFFORT
+
+
+ VOLATILE
+
+
+
+ NO_KEY
+ rt/ap/geopose/filtered
+ geographic_msgs::msg::dds_::GeoPoseStamped_
+
+ KEEP_LAST
+ 5
+
+
+
+
+ rt/ap/clock
+ rosgraph_msgs::msg::dds_::Clock_
+
+ KEEP_LAST
+ 20
+
+
+
+ PREALLOCATED_WITH_REALLOC
+
+
+ RELIABLE
+
+
+
+ NO_KEY
+ rt/ap/clock
+ rosgraph_msgs::msg::dds_::Clock_
+
+ KEEP_LAST
+ 20
+
+
+
+
+ rt/ap/joy
+ sensor_msgs::msg::dds_::Joy_
+
+ KEEP_LAST
+ 5
+
+
+
+
+ NO_KEY
+ rt/ap/joy
+ sensor_msgs::msg::dds_::Joy_
+
+
+
+ rt/ap/tf
+ tf2_msgs::msg::dds_::TFMessage_
+
+ KEEP_LAST
+ 5
+
+
+
+
+ NO_KEY
+ rt/ap/tf
+ tf2_msgs::msg::dds_::TFMessage_
+
+
+
+ rt/ap/cmd_vel
+ geometry_msgs::msg::dds_::TwistStamped_
+
+ KEEP_LAST
+ 5
+
+
+
+
+ NO_KEY
+ rt/ap/cmd_vel
+ geometry_msgs::msg::dds_::TwistStamped_
+
+
+
+
diff --git a/libraries/AP_DDS/gen_config_h.py b/libraries/AP_DDS/gen_config_h.py
index f35af8f7b89d1a..618a9f84f73567 100755
--- a/libraries/AP_DDS/gen_config_h.py
+++ b/libraries/AP_DDS/gen_config_h.py
@@ -23,7 +23,7 @@
'UCLIENT_UDP_TRANSPORT_MTU': 300,
'UCLIENT_TCP_TRANSPORT_MTU': 350,
'UCLIENT_SERIAL_TRANSPORT_MTU': 1024,
- 'UCLIENT_CUSTOM_TRANSPORT_MTU': 400,
+ 'UCLIENT_CUSTOM_TRANSPORT_MTU': 512,
'CONFIG_MACHINE_ENDIANNESS': 1, # little endian
'UCLIENT_SHARED_MEMORY_MAX_ENTITIES': 0,
'UCLIENT_SHARED_MEMORY_STATIC_MEM_SIZE': 0,
@@ -34,10 +34,10 @@
"UCLIENT_PROFILE_UDP": 0,
"UCLIENT_PROFILE_TCP": 0,
"UCLIENT_PROFILE_CAN": 0,
- "UCLIENT_PROFILE_SERIAL": 1,
- "UCLIENT_PROFILE_CUSTOM_TRANSPORT": 0,
+ "UCLIENT_PROFILE_SERIAL": 0,
+ "UCLIENT_PROFILE_CUSTOM_TRANSPORT": 1,
"UCLIENT_PROFILE_DISCOVERY": 0,
- "UCLIENT_PLATFORM_POSIX": 1,
+ "UCLIENT_PLATFORM_POSIX": 0,
"UCLIENT_PLATFORM_POSIX_NOPOLL": 0,
"UCLIENT_PLATFORM_WINDOWS": 0,
"UCLIENT_PLATFORM_FREERTOS_PLUS_TCP": 0,
@@ -47,7 +47,7 @@
"UCLIENT_EXTERNAL_SERIAL": 0,
"UCLIENT_PROFILE_MULTITHREAD": 0,
"UCLIENT_PROFILE_SHARED_MEMORY": 0,
- "UCLIENT_PROFILE_STREAM_FRAMING": 0,
+ "UCLIENT_PROFILE_STREAM_FRAMING": 1,
"UCLIENT_PLATFORM_RTEMS_BSD_NET": 0,
"UCLIENT_TWEAK_XRCE_WRITE_LIMIT": 0,
"UCLIENT_HARD_LIVELINESS_CHECK": 0,
diff --git a/libraries/AP_DDS/tests/test_ap_dds_external_odom.cpp b/libraries/AP_DDS/tests/test_ap_dds_external_odom.cpp
new file mode 100644
index 00000000000000..804d891e161806
--- /dev/null
+++ b/libraries/AP_DDS/tests/test_ap_dds_external_odom.cpp
@@ -0,0 +1,38 @@
+#include
+
+#include
+#include "geometry_msgs/msg/TransformStamped.h"
+#include
+
+const AP_HAL::HAL &hal = AP_HAL::get_HAL();
+
+TEST(AP_DDS_EXTERNAL_ODOM, test_is_odometry_success)
+{
+ geometry_msgs_msg_TransformStamped msg {};
+
+ strncpy(msg.header.frame_id, "odom", strlen("odom") + 1);
+ strncpy(msg.child_frame_id, "base_link", strlen("base_link") + 1);
+ ASSERT_TRUE(AP_DDS_External_Odom::is_odometry_frame(msg));
+
+ strncpy(msg.header.frame_id, "invalid", strlen("invalid") + 1);
+ strncpy(msg.child_frame_id, "base_link", strlen("base_link") + 1);
+ ASSERT_FALSE(AP_DDS_External_Odom::is_odometry_frame(msg));
+
+ strncpy(msg.header.frame_id, "odom", strlen("odom") + 1);
+ strncpy(msg.child_frame_id, "invalid", strlen("invalid") + 1);
+ ASSERT_FALSE(AP_DDS_External_Odom::is_odometry_frame(msg));
+
+ strncpy(msg.header.frame_id, "odom_with_invalid_extra", strlen("odom_with_invalid_extra") + 1);
+ strncpy(msg.child_frame_id, "base_link", strlen("base_link") + 1);
+ ASSERT_FALSE(AP_DDS_External_Odom::is_odometry_frame(msg));
+
+ strncpy(msg.header.frame_id, "odom", strlen("odom") + 1);
+ strncpy(msg.child_frame_id, "base_link_with_invalid_extra", strlen("base_link_with_invalid_extra") + 1);
+ ASSERT_FALSE(AP_DDS_External_Odom::is_odometry_frame(msg));
+
+ strncpy(msg.header.frame_id, "x", strlen("x") + 1);
+ strncpy(msg.child_frame_id, "base_link", strlen("base_link") + 1);
+ ASSERT_FALSE(AP_DDS_External_Odom::is_odometry_frame(msg));
+}
+
+AP_GTEST_MAIN()
diff --git a/libraries/AP_DDS/tests/test_ap_dds_type_conversions.cpp b/libraries/AP_DDS/tests/test_ap_dds_type_conversions.cpp
new file mode 100644
index 00000000000000..f0b89f207d25f3
--- /dev/null
+++ b/libraries/AP_DDS/tests/test_ap_dds_type_conversions.cpp
@@ -0,0 +1,28 @@
+#include
+
+#include
+#include "builtin_interfaces/msg/Time.h"
+#include
+
+
+const AP_HAL::HAL &hal = AP_HAL::get_HAL();
+
+TEST(AP_DDS_TYPE_CONVERSIONS, test_time_u64_micros)
+{
+ builtin_interfaces_msg_Time ros_time {};
+ ASSERT_EQ(AP_DDS_Type_Conversions::time_u64_micros(ros_time), 0UL);
+
+ ros_time.sec = 5;
+ ASSERT_EQ(AP_DDS_Type_Conversions::time_u64_micros(ros_time), uint64_t(5E6));
+
+ ros_time.nanosec = 1000;
+ const uint64_t expected5 = uint64_t(5E6) + 1;
+ ASSERT_EQ(AP_DDS_Type_Conversions::time_u64_micros(ros_time), expected5);
+
+ ros_time.sec = 7 * 24 * 60 * 60; // 1 week of runtime
+ ros_time.nanosec = 1000;
+ const uint64_t expected_long_runtime = uint64_t(ros_time.sec) * 1000000 + 1;
+ ASSERT_EQ(AP_DDS_Type_Conversions::time_u64_micros(ros_time), expected_long_runtime);
+}
+
+AP_GTEST_MAIN()
diff --git a/libraries/AP_DDS/tests/wscript b/libraries/AP_DDS/tests/wscript
new file mode 100644
index 00000000000000..5f82c39f837b47
--- /dev/null
+++ b/libraries/AP_DDS/tests/wscript
@@ -0,0 +1,10 @@
+#!/usr/bin/env python3
+
+def build(bld):
+ if not bld.env.ENABLE_DDS:
+ return
+
+ bld.ap_find_tests(
+ use='ap',
+ DOUBLE_PRECISION_SOURCES = ['test_ap_dds_external_odom.cpp']
+ )
diff --git a/libraries/AP_DDS/wscript b/libraries/AP_DDS/wscript
index a8e1aa4d0c6d5b..b181f9ab21ad7a 100644
--- a/libraries/AP_DDS/wscript
+++ b/libraries/AP_DDS/wscript
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
-import os
+import pathlib
def configure(cfg):
@@ -10,7 +10,7 @@ def configure(cfg):
'modules/Micro-XRCE-DDS-Client/src/c/core/session/*.c',
'modules/Micro-XRCE-DDS-Client/src/c/core/serialization/*.c',
'modules/Micro-XRCE-DDS-Client/src/c/util/*.c',
- 'modules/Micro-XRCE-DDS-Client/src/c/profile/transport/serial/serial_transport.c',
+ 'modules/Micro-XRCE-DDS-Client/src/c/profile/transport/custom/custom_transport.c',
'modules/Micro-XRCE-DDS-Client/src/c/profile/transport/stream_framing/stream_framing_protocol.c',
'modules/Micro-CDR/src/c/types/*.c',
'modules/Micro-CDR/src/c/common.c',
@@ -49,13 +49,13 @@ def build(bld):
extra_bld_inc = [
'modules/Micro-CDR/include',
'modules/Micro-XRCE-DDS-Client/include',
- gen_path,
+ str(pathlib.PurePath(gen_path, "generated")),
]
for inc in extra_bld_inc:
bld.env.INCLUDES += [bld.bldnode.find_or_declare(inc).abspath()]
for i in range(len(config_h_nodes)):
- print("building %s" % config_h_nodes[i].abspath())
+ print(f"building {config_h_nodes[i].abspath()}")
bld(
# build config.h file
source=config_h_in_nodes[i],
@@ -71,42 +71,27 @@ def build(bld):
group='dynamic_sources',
)
- # temporary whitelist while include issue is sorted out
- whitelist = [
- 'BatteryState.idl',
- 'Duration.idl',
- 'Header.idl',
- 'NavSatFix.idl',
- 'NavSatStatus.idl',
- 'Point.idl',
- 'Pose.idl',
- 'PoseStamped.idl',
- 'Quaternion.idl',
- 'Time.idl',
- 'Transform.idl',
- 'TransformStamped.idl',
- "TFMessage.idl",
- 'Twist.idl',
- 'TwistStamped.idl',
- 'Vector3.idl',
- ]
-
+ # TODO instead of keeping standard IDL files in the source tree, copy them with "ros2 pkg prefix --share " tools
idl_files = bld.srcnode.ant_glob('libraries/AP_DDS/Idl/**/*.idl')
+ idl_include_path = bld.srcnode.make_node(str(pathlib.PurePath(gen_path, "Idl"))).abspath()
+
for idl in idl_files:
- b = os.path.basename(idl.abspath())
- if not b in whitelist:
- continue
- gen_h = b.replace('.idl', '.h')
- gen_c = b.replace('.idl', '.c')
- gen = [
- bld.bldnode.find_or_declare(os.path.join(gen_path, "generated", gen_h)),
- bld.bldnode.find_or_declare(os.path.join(gen_path, "generated", gen_c)),
- ]
+ idl_path = pathlib.PurePath(idl.abspath())
+ b = idl_path.name
+
+ gen_h = idl_path.with_suffix('.h').name
+ gen_c = idl_path.with_suffix('.c').name
+
+ idl_folder = idl_path.parts[-3:-1]
+ dst_dir = pathlib.PurePath(gen_path, "generated", *idl_folder)
+ gen = [bld.bldnode.find_or_declare(str(dst_dir / name)) for name in [gen_h, gen_c]]
+ gen_cmd = f"{bld.env.MICROXRCEDDSGEN[0]} -cs -replace -d {dst_dir} -I {idl_include_path} {idl}"
bld(
# build IDL file
source=idl,
target=gen,
- rule=f"{bld.env.MICROXRCEDDSGEN[0]} -cs -replace -d {os.path.join(gen_path, 'generated')} {idl}",
+ rule=gen_cmd,
group='dynamic_sources',
)
- bld.env.AP_LIB_EXTRA_SOURCES['AP_DDS'] += [os.path.join('generated', gen_c)]
+
+ bld.env.AP_LIB_EXTRA_SOURCES['AP_DDS'] += [str(gen[1])]
diff --git a/libraries/AP_DroneCAN/AP_Canard_iface.cpp b/libraries/AP_DroneCAN/AP_Canard_iface.cpp
index 8f302e1c0fb4d9..540120564d8075 100644
--- a/libraries/AP_DroneCAN/AP_Canard_iface.cpp
+++ b/libraries/AP_DroneCAN/AP_Canard_iface.cpp
@@ -4,11 +4,16 @@
#if HAL_ENABLE_DRONECAN_DRIVERS
#include
#include
+#include
+#include
extern const AP_HAL::HAL& hal;
#define LOG_TAG "DroneCANIface"
+#include
#define DEBUG_PKTS 0
+#define CANARD_MSG_TYPE_FROM_ID(x) ((uint16_t)(((x) >> 8U) & 0xFFFFU))
+
DEFINE_HANDLER_LIST_HEADS();
DEFINE_HANDLER_LIST_SEMAPHORES();
@@ -22,6 +27,27 @@ uint8_t test_node_mem_area[1024];
HAL_Semaphore test_iface_sem;
#endif
+void canard_allocate_sem_take(CanardPoolAllocator *allocator) {
+ if (allocator->semaphore == nullptr) {
+ allocator->semaphore = new HAL_Semaphore;
+ if (allocator->semaphore == nullptr) {
+ // out of memory
+ CANARD_ASSERT(0);
+ return;
+ }
+ }
+ ((HAL_Semaphore*)allocator->semaphore)->take_blocking();
+}
+
+void canard_allocate_sem_give(CanardPoolAllocator *allocator) {
+ if (allocator->semaphore == nullptr) {
+ // it should have been allocated by canard_allocate_sem_take
+ CANARD_ASSERT(0);
+ return;
+ }
+ ((HAL_Semaphore*)allocator->semaphore)->give();
+}
+
CanardInterface::CanardInterface(uint8_t iface_index) :
Interface(iface_index) {
#if AP_TEST_DRONECAN_DRIVERS
@@ -31,6 +57,7 @@ Interface(iface_index) {
if (iface_index == 0) {
test_iface.init(test_node_mem_area, sizeof(test_node_mem_area), 125);
}
+ canardInitTxTransfer(&tx_transfer);
#endif
}
@@ -44,85 +71,107 @@ bool CanardInterface::broadcast(const Canard::Transfer &bcast_transfer) {
if (!initialized) {
return false;
}
- WITH_SEMAPHORE(_sem);
+ WITH_SEMAPHORE(_sem_tx);
+
#if AP_TEST_DRONECAN_DRIVERS
if (this == &test_iface) {
test_iface_sem.take_blocking();
}
#endif
- // do canard broadcast
- bool success = canardBroadcast(&canard,
- bcast_transfer.data_type_signature,
- bcast_transfer.data_type_id,
- bcast_transfer.inout_transfer_id,
- bcast_transfer.priority,
- bcast_transfer.payload,
- bcast_transfer.payload_len,
- AP_HAL::native_micros64() + (bcast_transfer.timeout_ms * 1000)
-#if CANARD_MULTI_IFACE
- , ((1< 0;
+ };
+ // do canard broadcast
+ int16_t ret = canardBroadcastObj(&canard, &tx_transfer);
#if AP_TEST_DRONECAN_DRIVERS
if (this == &test_iface) {
test_iface_sem.give();
}
#endif
- return success;
+ if (ret <= 0) {
+ protocol_stats.tx_errors++;
+ } else {
+ protocol_stats.tx_frames += ret;
+ }
+ return ret > 0;
}
bool CanardInterface::request(uint8_t destination_node_id, const Canard::Transfer &req_transfer) {
if (!initialized) {
return false;
}
- WITH_SEMAPHORE(_sem);
- // do canard request
- return canardRequestOrRespond(&canard,
- destination_node_id,
- req_transfer.data_type_signature,
- req_transfer.data_type_id,
- req_transfer.inout_transfer_id,
- req_transfer.priority,
- CanardRequest,
- req_transfer.payload,
- req_transfer.payload_len,
- AP_HAL::native_micros64() + (req_transfer.timeout_ms * 1000)
-#if CANARD_MULTI_IFACE
- , ((1< 0;
+ };
+ // do canard request
+ int16_t ret = canardRequestOrRespondObj(&canard, destination_node_id, &tx_transfer);
+ if (ret <= 0) {
+ protocol_stats.tx_errors++;
+ } else {
+ protocol_stats.tx_frames += ret;
+ }
+ return ret > 0;
}
bool CanardInterface::respond(uint8_t destination_node_id, const Canard::Transfer &res_transfer) {
if (!initialized) {
return false;
}
- WITH_SEMAPHORE(_sem);
- // do canard respond
- return canardRequestOrRespond(&canard,
- destination_node_id,
- res_transfer.data_type_signature,
- res_transfer.data_type_id,
- res_transfer.inout_transfer_id,
- res_transfer.priority,
- CanardResponse,
- res_transfer.payload,
- res_transfer.payload_len,
- AP_HAL::native_micros64() + (res_transfer.timeout_ms * 1000)
-#if CANARD_MULTI_IFACE
- , ((1< 0;
+ };
+ // do canard respond
+ int16_t ret = canardRequestOrRespondObj(&canard, destination_node_id, &tx_transfer);
+ if (ret <= 0) {
+ protocol_stats.tx_errors++;
+ } else {
+ protocol_stats.tx_frames += ret;
+ }
+ return ret > 0;
}
void CanardInterface::onTransferReception(CanardInstance* ins, CanardRxTransfer* transfer) {
@@ -147,15 +196,15 @@ void CanardInterface::processTestRx() {
WITH_SEMAPHORE(test_iface_sem);
for (const CanardCANFrame* txf = canardPeekTxQueue(&test_iface.canard); txf != NULL; txf = canardPeekTxQueue(&test_iface.canard)) {
if (canard_ifaces[0]) {
- canardHandleRxFrame(&canard_ifaces[0]->canard, txf, AP_HAL::native_micros64());
+ canardHandleRxFrame(&canard_ifaces[0]->canard, txf, AP_HAL::micros64());
}
canardPopTxQueue(&test_iface.canard);
}
}
#endif
-void CanardInterface::processTx() {
- WITH_SEMAPHORE(_sem);
+void CanardInterface::processTx(bool raw_commands_only = false) {
+ WITH_SEMAPHORE(_sem_tx);
for (uint8_t iface = 0; iface < num_ifaces; iface++) {
if (ifaces[iface] == NULL) {
@@ -165,10 +214,20 @@ void CanardInterface::processTx() {
if (txq == nullptr) {
return;
}
- AP_HAL::CANFrame txmsg {};
// scan through list of pending transfers
while (true) {
auto txf = &txq->frame;
+ if (raw_commands_only &&
+ CANARD_MSG_TYPE_FROM_ID(txf->id) != UAVCAN_EQUIPMENT_ESC_RAWCOMMAND_ID &&
+ CANARD_MSG_TYPE_FROM_ID(txf->id) != COM_HOBBYWING_ESC_RAWCOMMAND_ID) {
+ // look at next transfer
+ txq = txq->next;
+ if (txq == nullptr) {
+ break;
+ }
+ continue;
+ }
+ AP_HAL::CANFrame txmsg {};
txmsg.dlc = AP_HAL::CANFrame::dataLengthToDlc(txf->data_len);
memcpy(txmsg.data, txf->data, txf->data_len);
txmsg.id = (txf->id | AP_HAL::CANFrame::FlagEFF);
@@ -178,7 +237,12 @@ void CanardInterface::processTx() {
bool write = true;
bool read = false;
ifaces[iface]->select(read, write, &txmsg, 0);
- if ((AP_HAL::native_micros64() < txf->deadline_usec) && (txf->iface_mask & (1U<iface_mask & (1U<deadline_usec)) {
// try sending to interfaces, clearing the mask if we succeed
if (ifaces[iface]->send(txmsg, txf->deadline_usec, 0) > 0) {
txf->iface_mask &= ~(1U<= txf->deadline_usec) || (txf->iface_mask == 0)) {
- canardPopTxQueue(&canard);
- } else {
- break;
- }
+}
+
+void CanardInterface::update_rx_protocol_stats(int16_t res)
+{
+ switch (res) {
+ case CANARD_OK:
+ protocol_stats.rx_frames++;
+ break;
+ case -CANARD_ERROR_OUT_OF_MEMORY:
+ protocol_stats.rx_error_oom++;
+ break;
+ case -CANARD_ERROR_INTERNAL:
+ protocol_stats.rx_error_internal++;
+ break;
+ case -CANARD_ERROR_RX_INCOMPATIBLE_PACKET:
+ protocol_stats.rx_ignored_not_wanted++;
+ break;
+ case -CANARD_ERROR_RX_WRONG_ADDRESS:
+ protocol_stats.rx_ignored_wrong_address++;
+ break;
+ case -CANARD_ERROR_RX_NOT_WANTED:
+ protocol_stats.rx_ignored_not_wanted++;
+ break;
+ case -CANARD_ERROR_RX_MISSED_START:
+ protocol_stats.rx_error_missed_start++;
+ break;
+ case -CANARD_ERROR_RX_WRONG_TOGGLE:
+ protocol_stats.rx_error_wrong_toggle++;
+ break;
+ case -CANARD_ERROR_RX_UNEXPECTED_TID:
+ protocol_stats.rx_ignored_unexpected_tid++;
+ break;
+ case -CANARD_ERROR_RX_SHORT_FRAME:
+ protocol_stats.rx_error_short_frame++;
+ break;
+ case -CANARD_ERROR_RX_BAD_CRC:
+ protocol_stats.rx_error_bad_crc++;
+ break;
+ default:
+ // mark all other errors as internal
+ protocol_stats.rx_error_internal++;
+ break;
}
}
@@ -236,25 +335,24 @@ void CanardInterface::processRx() {
rx_frame.iface_id = i;
#endif
{
- WITH_SEMAPHORE(_sem);
+ WITH_SEMAPHORE(_sem_rx);
-#if DEBUG_PKTS
- const int16_t res =
-#endif
- canardHandleRxFrame(&canard, &rx_frame, timestamp);
-#if DEBUG_PKTS
- // hal.console->printf("DTID: %u\n", extractDataType(rx_frame.id));
- // hal.console->printf("Rx %d, IF%d %lx: ", res, i, rx_frame.id);
- if (res < 0 &&
- res != -CANARD_ERROR_RX_NOT_WANTED &&
- res != -CANARD_ERROR_RX_WRONG_ADDRESS) {
- hal.console->printf("Rx error %d, IF%d %lx: \n", res, i, rx_frame.id);
- // for (uint8_t index = 0; index < rx_frame.data_len; index++) {
- // hal.console->printf("%02x", rx_frame.data[index]);
- // }
- // hal.console->printf("\n");
+ const int16_t res = canardHandleRxFrame(&canard, &rx_frame, timestamp);
+ if (res == -CANARD_ERROR_RX_MISSED_START) {
+ // this might remaining frames from a message that we don't accept, so check
+ uint64_t dummy_signature;
+ if (shouldAcceptTransfer(&canard,
+ &dummy_signature,
+ extractDataType(rx_frame.id),
+ extractTransferType(rx_frame.id),
+ 1)) { // doesn't matter what we pass here
+ update_rx_protocol_stats(res);
+ } else {
+ protocol_stats.rx_ignored_not_wanted++;
+ }
+ } else {
+ update_rx_protocol_stats(res);
}
-#endif
}
}
}
@@ -268,13 +366,19 @@ void CanardInterface::process(uint32_t duration_ms) {
hal.scheduler->delay_microseconds(1000);
}
#else
- const uint64_t deadline = AP_HAL::native_micros64() + duration_ms*1000;
+ const uint64_t deadline = AP_HAL::micros64() + duration_ms*1000;
while (true) {
processRx();
processTx();
- uint64_t now = AP_HAL::native_micros64();
+ {
+ WITH_SEMAPHORE(_sem_rx);
+ WITH_SEMAPHORE(_sem_tx);
+ canardCleanupStaleTransfers(&canard, AP_HAL::micros64());
+ }
+ uint64_t now = AP_HAL::micros64();
if (now < deadline) {
- _event_handle.wait(deadline - now);
+ _event_handle.wait(MIN(UINT16_MAX - 2U, deadline - now));
+ hal.scheduler->delay_microseconds(50);
} else {
break;
}
diff --git a/libraries/AP_DroneCAN/AP_Canard_iface.h b/libraries/AP_DroneCAN/AP_Canard_iface.h
index 21a9b8eea4881c..aa7533e6913b3f 100644
--- a/libraries/AP_DroneCAN/AP_Canard_iface.h
+++ b/libraries/AP_DroneCAN/AP_Canard_iface.h
@@ -2,6 +2,7 @@
#include
#if HAL_ENABLE_DRONECAN_DRIVERS
#include
+#include
class AP_DroneCAN;
class CanardInterface : public Canard::Interface {
@@ -33,7 +34,7 @@ class CanardInterface : public Canard::Interface {
/// @return true if response was added to the queue
bool respond(uint8_t destination_node_id, const Canard::Transfer &res_transfer) override;
- void processTx();
+ void processTx(bool raw_commands_only);
void processRx();
void process(uint32_t duration);
@@ -52,6 +53,8 @@ class CanardInterface : public Canard::Interface {
static void processTestRx();
#endif
+ void update_rx_protocol_stats(int16_t res);
+
uint8_t get_node_id() const override { return canard.node_id; }
private:
CanardInstance canard;
@@ -63,6 +66,9 @@ class CanardInterface : public Canard::Interface {
uint8_t num_ifaces;
HAL_EventHandle _event_handle;
bool initialized;
- HAL_Semaphore _sem;
+ HAL_Semaphore _sem_tx;
+ HAL_Semaphore _sem_rx;
+ CanardTxTransfer tx_transfer;
+ dronecan_protocol_Stats protocol_stats;
};
#endif // HAL_ENABLE_DRONECAN_DRIVERS
\ No newline at end of file
diff --git a/libraries/AP_DroneCAN/AP_DroneCAN.cpp b/libraries/AP_DroneCAN/AP_DroneCAN.cpp
index 74d5e29c1052d3..0cf2eda8ca945d 100644
--- a/libraries/AP_DroneCAN/AP_DroneCAN.cpp
+++ b/libraries/AP_DroneCAN/AP_DroneCAN.cpp
@@ -29,10 +29,12 @@
#include
#include
#include
+#include
#include
#include
#include
#include
+#include
#include
#include
#include
@@ -46,10 +48,9 @@
#include
#include
#include
+#include
#include
-#define LED_DELAY_US 50000
-
extern const AP_HAL::HAL& hal;
// setup default pool size
@@ -71,9 +72,7 @@ extern const AP_HAL::HAL& hal;
#define AP_DRONECAN_VOLZ_FEEDBACK_ENABLED 0
#endif
-#if AP_DRONECAN_VOLZ_FEEDBACK_ENABLED
-#include
-#endif
+#define AP_DRONECAN_GETSET_TIMEOUT_MS 100 // timeout waiting for response from node after 0.1 sec
#define debug_dronecan(level_debug, fmt, args...) do { AP::can().log_text(level_debug, "DroneCAN", fmt, ##args); } while (0)
@@ -117,7 +116,7 @@ const AP_Param::GroupInfo AP_DroneCAN::var_info[] = {
// @Param: OPTION
// @DisplayName: DroneCAN options
// @Description: Option flags
- // @Bitmask: 0:ClearDNADatabase,1:IgnoreDNANodeConflicts,2:EnableCanfd,3:IgnoreDNANodeUnhealthy,4:SendServoAsPWM,5:SendGNSS
+ // @Bitmask: 0:ClearDNADatabase,1:IgnoreDNANodeConflicts,2:EnableCanfd,3:IgnoreDNANodeUnhealthy,4:SendServoAsPWM,5:SendGNSS,6:UseHimarkServo,7:HobbyWingESC,8:EnableStats
// @User: Advanced
AP_GROUPINFO("OPTION", 5, AP_DroneCAN, _options, 0),
@@ -142,6 +141,13 @@ const AP_Param::GroupInfo AP_DroneCAN::var_info[] = {
// @Range: 1024 16384
// @User: Advanced
AP_GROUPINFO("POOL", 8, AP_DroneCAN, _pool_size, DRONECAN_NODE_POOL_SIZE),
+
+ // @Param: ESC_RV
+ // @DisplayName: Bitmask for output channels for reversible ESCs over DroneCAN.
+ // @Description: Bitmask with one set for each output channel that uses a reversible ESC over DroneCAN. Reversible ESCs use both positive and negative values in RawCommands, with positive commanding the forward direction and negative commanding the reverse direction.
+ // @Bitmask: 0: ESC 1, 1: ESC 2, 2: ESC 3, 3: ESC 4, 4: ESC 5, 5: ESC 6, 6: ESC 7, 7: ESC 8, 8: ESC 9, 9: ESC 10, 10: ESC 11, 11: ESC 12, 12: ESC 13, 13: ESC 14, 14: ESC 15, 15: ESC 16, 16: ESC 17, 17: ESC 18, 18: ESC 19, 19: ESC 20, 20: ESC 21, 21: ESC 22, 22: ESC 23, 23: ESC 24, 24: ESC 25, 25: ESC 26, 26: ESC 27, 27: ESC 28, 28: ESC 29, 29: ESC 30, 30: ESC 31, 31: ESC 32
+ // @User: Advanced
+ AP_GROUPINFO("ESC_RV", 9, AP_DroneCAN, _esc_rv, 0),
AP_GROUPEND
};
@@ -153,7 +159,7 @@ const AP_Param::GroupInfo AP_DroneCAN::var_info[] = {
AP_DroneCAN::AP_DroneCAN(const int driver_index) :
_driver_index(driver_index),
canard_iface(driver_index),
-_dna_server(*this)
+_dna_server(*this, canard_iface, driver_index)
{
AP_Param::setup_object_defaults(this, var_info);
@@ -172,7 +178,7 @@ AP_DroneCAN::~AP_DroneCAN()
AP_DroneCAN *AP_DroneCAN::get_dronecan(uint8_t driver_index)
{
if (driver_index >= AP::can().get_num_drivers() ||
- AP::can().get_driver_type(driver_index) != AP_CANManager::Driver_Type_DroneCAN) {
+ AP::can().get_driver_type(driver_index) != AP_CAN::Protocol::DroneCAN) {
return nullptr;
}
return static_cast(AP::can().get_driver(driver_index));
@@ -198,7 +204,7 @@ void AP_DroneCAN::init(uint8_t driver_index, bool enable_filters)
return;
}
- node_info_rsp.name.len = snprintf((char*)node_info_rsp.name.data, sizeof(node_info_rsp.name.data), "org.ardupilot:%u", driver_index);
+ node_info_rsp.name.len = hal.util->snprintf((char*)node_info_rsp.name.data, sizeof(node_info_rsp.name.data), "org.ardupilot:%u", driver_index);
node_info_rsp.software_version.major = AP_DRONECAN_SW_VERS_MAJOR;
node_info_rsp.software_version.minor = AP_DRONECAN_SW_VERS_MINOR;
@@ -251,6 +257,9 @@ void AP_DroneCAN::init(uint8_t driver_index, bool enable_filters)
#if AP_RANGEFINDER_DRONECAN_ENABLED
AP_RangeFinder_DroneCAN::subscribe_msgs(this);
#endif
+#if AP_RCPROTOCOL_DRONECAN_ENABLED
+ AP_RCProtocol_DroneCAN::subscribe_msgs(this);
+#endif
#if AP_EFI_DRONECAN_ENABLED
AP_EFI_DroneCAN::subscribe_msgs(this);
#endif
@@ -258,12 +267,24 @@ void AP_DroneCAN::init(uint8_t driver_index, bool enable_filters)
#if AP_PROXIMITY_DRONECAN_ENABLED
AP_Proximity_DroneCAN::subscribe_msgs(this);
#endif
+#if HAL_MOUNT_XACTI_ENABLED
+ AP_Mount_Xacti::subscribe_msgs(this);
+#endif
- act_out_array.set_timeout_ms(2);
+ act_out_array.set_timeout_ms(5);
act_out_array.set_priority(CANARD_TRANSFER_PRIORITY_HIGH);
esc_raw.set_timeout_ms(2);
- esc_raw.set_priority(CANARD_TRANSFER_PRIORITY_HIGH);
+ // esc_raw is one higher than high priority to ensure that it is given higher priority over act_out_array
+ esc_raw.set_priority(CANARD_TRANSFER_PRIORITY_HIGH - 1);
+
+#if AP_DRONECAN_HOBBYWING_ESC_SUPPORT
+ esc_hobbywing_raw.set_timeout_ms(2);
+ esc_hobbywing_raw.set_priority(CANARD_TRANSFER_PRIORITY_HIGH);
+#endif
+
+ himark_out.set_timeout_ms(2);
+ himark_out.set_priority(CANARD_TRANSFER_PRIORITY_HIGH);
rgb_led.set_timeout_ms(20);
rgb_led.set_priority(CANARD_TRANSFER_PRIORITY_LOW);
@@ -297,6 +318,15 @@ void AP_DroneCAN::init(uint8_t driver_index, bool enable_filters)
notify_state.set_timeout_ms(20);
notify_state.set_priority(CANARD_TRANSFER_PRIORITY_LOW);
+#if HAL_MOUNT_XACTI_ENABLED
+ xacti_copter_att_status.set_timeout_ms(20);
+ xacti_copter_att_status.set_priority(CANARD_TRANSFER_PRIORITY_LOW);
+ xacti_gimbal_control_data.set_timeout_ms(20);
+ xacti_gimbal_control_data.set_priority(CANARD_TRANSFER_PRIORITY_LOW);
+ xacti_gnss_status.set_timeout_ms(20);
+ xacti_gnss_status.set_priority(CANARD_TRANSFER_PRIORITY_LOW);
+#endif
+
param_save_client.set_timeout_ms(20);
param_save_client.set_priority(CANARD_TRANSFER_PRIORITY_LOW);
@@ -306,9 +336,16 @@ void AP_DroneCAN::init(uint8_t driver_index, bool enable_filters)
node_status.set_priority(CANARD_TRANSFER_PRIORITY_LOWEST);
node_status.set_timeout_ms(1000);
- node_info_server.set_timeout_ms(20);
+ protocol_stats.set_priority(CANARD_TRANSFER_PRIORITY_LOWEST);
+ protocol_stats.set_timeout_ms(3000);
- _led_conf.devices_count = 0;
+ can_stats.set_priority(CANARD_TRANSFER_PRIORITY_LOWEST);
+ can_stats.set_timeout_ms(3000);
+
+ rgb_led.set_timeout_ms(20);
+ rgb_led.set_priority(CANARD_TRANSFER_PRIORITY_LOW);
+
+ node_info_server.set_timeout_ms(20);
// setup node status
node_status_msg.health = UAVCAN_PROTOCOL_NODESTATUS_HEALTH_OK;
@@ -321,7 +358,7 @@ void AP_DroneCAN::init(uint8_t driver_index, bool enable_filters)
canard_iface.process(1000);
}
- snprintf(_thread_name, sizeof(_thread_name), "dronecan_%u", driver_index);
+ hal.util->snprintf(_thread_name, sizeof(_thread_name), "dronecan_%u", driver_index);
if (!hal.scheduler->thread_create(FUNCTOR_BIND_MEMBER(&AP_DroneCAN::loop, void), _thread_name, DRONECAN_STACK_SIZE, AP_HAL::Scheduler::PRIORITY_CAN, 0)) {
debug_dronecan(AP_CANManager::LOG_ERROR, "DroneCAN: couldn't create thread\n\r");
@@ -342,45 +379,13 @@ void AP_DroneCAN::loop(void)
canard_iface.process(1);
- if (_SRV_armed) {
- bool sent_servos = false;
-
- if (_servo_bm > 0) {
- // if we have any Servos in bitmask
- uint32_t now = AP_HAL::native_micros();
- const uint32_t servo_period_us = 1000000UL / unsigned(_servo_rate_hz.get());
- if (now - _SRV_last_send_us >= servo_period_us) {
- _SRV_last_send_us = now;
- SRV_send_actuator();
- sent_servos = true;
- for (uint8_t i = 0; i < DRONECAN_SRV_NUMBER; i++) {
- _SRV_conf[i].servo_pending = false;
- }
- }
- }
-
- // if we have any ESC's in bitmask
- if (_esc_bm > 0 && !sent_servos) {
- SRV_send_esc();
- }
-
- for (uint8_t i = 0; i < DRONECAN_SRV_NUMBER; i++) {
- _SRV_conf[i].esc_pending = false;
- }
- }
-
- led_out_send();
- buzzer_send();
- rtcm_stream_send();
safety_state_send();
notify_state_send();
+ check_parameter_callback_timeout();
send_parameter_request();
send_parameter_save_request();
send_node_status();
_dna_server.verify_nodes();
-#if AP_OPENDRONEID_ENABLED
- AP::opendroneid().dronecan_send(this);
-#endif
#if AP_DRONECAN_SEND_GPS
if (option_is_set(AP_DroneCAN::Options::SEND_GNSS) && !AP_GPS_DroneCAN::instance_exists(this)) {
@@ -389,31 +394,173 @@ void AP_DroneCAN::loop(void)
gnss_send_yaw();
}
#endif
-
logging();
+#if AP_DRONECAN_HOBBYWING_ESC_SUPPORT
+ hobbywing_ESC_update();
+#endif
+ if (_SRV_armed_mask != 0) {
+ // we have active servos
+ uint32_t now = AP_HAL::micros();
+ const uint32_t servo_period_us = 1000000UL / unsigned(_servo_rate_hz.get());
+ if (now - _SRV_last_send_us >= servo_period_us) {
+ _SRV_last_send_us = now;
+ if (option_is_set(Options::USE_HIMARK_SERVO)) {
+ SRV_send_himark();
+ } else {
+ SRV_send_actuator();
+ }
+ for (uint8_t i = 0; i < DRONECAN_SRV_NUMBER; i++) {
+ _SRV_conf[i].servo_pending = false;
+ }
+ }
+ }
+ }
+}
+
+#if AP_DRONECAN_HOBBYWING_ESC_SUPPORT
+void AP_DroneCAN::hobbywing_ESC_update(void)
+{
+ uint32_t now = AP_HAL::millis();
+ if (now - hobbywing.last_GetId_send_ms >= 1000U) {
+ hobbywing.last_GetId_send_ms = now;
+ com_hobbywing_esc_GetEscID msg;
+ msg.payload.len = 1;
+ msg.payload.data[0] = 0;
+ esc_hobbywing_GetEscID.broadcast(msg);
+ }
+}
+
+/*
+ handle hobbywing GetEscID reply. This gets us the mapping between CAN NodeID and throttle channel
+ */
+void AP_DroneCAN::handle_hobbywing_GetEscID(const CanardRxTransfer& transfer, const com_hobbywing_esc_GetEscID& msg)
+{
+ if (msg.payload.len == 2 &&
+ msg.payload.data[0] == transfer.source_node_id) {
+ // throttle channel is 2nd payload byte
+ const uint8_t thr_channel = msg.payload.data[1];
+ if (thr_channel > 0 && thr_channel <= HOBBYWING_MAX_ESC) {
+ hobbywing.thr_chan[thr_channel-1] = transfer.source_node_id;
+ }
+ }
+}
+
+/*
+ find the ESC index given a CAN node ID
+ */
+bool AP_DroneCAN::hobbywing_find_esc_index(uint8_t node_id, uint8_t &esc_index) const
+{
+ for (uint8_t i=0; iget_statistics();
+ if (bus_stats == nullptr) {
+ continue;
+ }
+ dronecan_protocol_CanStats can_stats_msg;
+ can_stats_msg.interface = i;
+ can_stats_msg.tx_requests = bus_stats->tx_requests;
+ can_stats_msg.tx_rejected = bus_stats->tx_rejected;
+ can_stats_msg.tx_overflow = bus_stats->tx_overflow;
+ can_stats_msg.tx_success = bus_stats->tx_success;
+ can_stats_msg.tx_timedout = bus_stats->tx_timedout;
+ can_stats_msg.tx_abort = bus_stats->tx_abort;
+ can_stats_msg.rx_received = bus_stats->rx_received;
+ can_stats_msg.rx_overflow = bus_stats->rx_overflow;
+ can_stats_msg.rx_errors = bus_stats->rx_errors;
+ can_stats_msg.busoff_errors = bus_stats->num_busoff_err;
+ can_stats.broadcast(can_stats_msg);
+ }
+ }
}
void AP_DroneCAN::handle_node_info_request(const CanardRxTransfer& transfer, const uavcan_protocol_GetNodeInfoRequest& req)
{
node_info_rsp.status = node_status_msg;
- node_info_rsp.status.uptime_sec = AP_HAL::native_millis() / 1000;
+ node_info_rsp.status.uptime_sec = AP_HAL::millis() / 1000;
node_info_server.respond(transfer, node_info_rsp);
}
+int16_t AP_DroneCAN::scale_esc_output(uint8_t idx){
+ static const int16_t cmd_max = ((1<<13)-1);
+ float scaled = 0;
+
+ //Check if this channel has a reversible ESC. If it does, we can send negative commands.
+ if ((((uint32_t) 1) << idx) & _esc_rv) {
+ scaled = cmd_max * (hal.rcout->scale_esc_to_unity(_SRV_conf[idx].pulse));
+ } else {
+ scaled = cmd_max * (hal.rcout->scale_esc_to_unity(_SRV_conf[idx].pulse) + 1.0) / 2.0;
+ scaled = constrain_float(scaled, 0, cmd_max);
+ }
+
+ return static_cast(scaled);
+}
///// SRV output /////
@@ -442,7 +589,7 @@ void AP_DroneCAN::SRV_send_actuator(void)
* physically possible throws at [-1:1] limits.
*/
- if (_SRV_conf[starting_servo].servo_pending && ((((uint32_t) 1) << starting_servo) & _servo_bm)) {
+ if (_SRV_conf[starting_servo].servo_pending && ((((uint32_t) 1) << starting_servo) & _SRV_armed_mask)) {
cmd.actuator_id = starting_servo + 1;
if (option_is_set(Options::USE_ACTUATOR_PWM)) {
@@ -473,22 +620,51 @@ void AP_DroneCAN::SRV_send_actuator(void)
} while (repeat_send);
}
+/*
+ Himark servo output. This uses com.himark.servo.ServoCmd packets
+ */
+void AP_DroneCAN::SRV_send_himark(void)
+{
+ WITH_SEMAPHORE(SRV_sem);
+
+ // ServoCmd can hold maximum of 17 commands. First find the highest pending servo < 17
+ int8_t highest_to_send = -1;
+ for (int8_t i = 16; i >= 0; i--) {
+ if (_SRV_conf[i].servo_pending && ((1U<scale_esc_to_unity(_SRV_conf[i].pulse) + 1.0) / 2.0;
-
- scaled = constrain_float(scaled, 0, cmd_max);
-
- esc_msg.cmd.data[k] = static_cast(scaled);
+ if ((((uint32_t) 1) << i) & _ESC_armed_mask) {
+ esc_msg.cmd.data[k] = scale_esc_output(i);
} else {
esc_msg.cmd.data[k] = static_cast(0);
}
@@ -521,118 +692,112 @@ void AP_DroneCAN::SRV_send_esc(void)
} else {
_fail_send_count++;
}
+ // immediately push data to CAN bus
+ canard_iface.processTx(true);
}
-}
-
-void AP_DroneCAN::SRV_push_servos()
-{
- WITH_SEMAPHORE(SRV_sem);
for (uint8_t i = 0; i < DRONECAN_SRV_NUMBER; i++) {
- // Check if this channels has any function assigned
- if (SRV_Channels::channel_function(i) >= SRV_Channel::k_none) {
- _SRV_conf[i].pulse = SRV_Channels::srv_channel(i)->get_output_pwm();
- _SRV_conf[i].esc_pending = true;
- _SRV_conf[i].servo_pending = true;
- }
+ _SRV_conf[i].esc_pending = false;
}
-
- _SRV_armed = hal.util->safety_switch_state() != AP_HAL::Util::SAFETY_DISARMED;
}
+#if AP_DRONECAN_HOBBYWING_ESC_SUPPORT
+/*
+ support for Hobbywing DroneCAN ESCs
+ */
+void AP_DroneCAN::SRV_send_esc_hobbywing(void)
+{
+ com_hobbywing_esc_RawCommand esc_msg;
-///// LED /////
+ uint8_t active_esc_num = 0, max_esc_num = 0;
+ uint8_t k = 0;
-void AP_DroneCAN::led_out_send()
-{
- uint64_t now = AP_HAL::native_micros64();
+ // esc offset allows for efficient packing of higher ESC numbers in RawCommand
+ const uint8_t esc_offset = constrain_int16(_esc_offset.get(), 0, DRONECAN_SRV_NUMBER);
- if ((now - _led_conf.last_update) < LED_DELAY_US) {
- return;
+ // find out how many esc we have enabled and if they are active at all
+ for (uint8_t i = esc_offset; i < DRONECAN_SRV_NUMBER; i++) {
+ if ((((uint32_t) 1) << i) & _ESC_armed_mask) {
+ max_esc_num = i + 1;
+ if (_SRV_conf[i].esc_pending) {
+ active_esc_num++;
+ }
+ }
}
- uavcan_equipment_indication_LightsCommand msg;
- {
- WITH_SEMAPHORE(_led_out_sem);
+ // if at least one is active (update) we need to send to all
+ if (active_esc_num > 0) {
+ k = 0;
- if (_led_conf.devices_count == 0) {
- return;
+ for (uint8_t i = esc_offset; i < max_esc_num && k < 20; i++) {
+ if ((((uint32_t) 1) << i) & _ESC_armed_mask) {
+ esc_msg.command.data[k] = scale_esc_output(i);
+ } else {
+ esc_msg.command.data[k] = static_cast(0);
+ }
+
+ k++;
}
+ esc_msg.command.len = k;
- msg.commands.len = _led_conf.devices_count;
- for (uint8_t i = 0; i < _led_conf.devices_count; i++) {
- msg.commands.data[i].light_id =_led_conf.devices[i].led_index;
- msg.commands.data[i].color.red = _led_conf.devices[i].red >> 3;
- msg.commands.data[i].color.green = _led_conf.devices[i].green >> 2;
- msg.commands.data[i].color.blue = _led_conf.devices[i].blue >> 3;
+ if (esc_hobbywing_raw.broadcast(esc_msg)) {
+ _esc_send_count++;
+ } else {
+ _fail_send_count++;
}
+ // immediately push data to CAN bus
+ canard_iface.processTx(true);
}
-
- rgb_led.broadcast(msg);
- _led_conf.last_update = now;
}
+#endif // AP_DRONECAN_HOBBYWING_ESC_SUPPORT
-bool AP_DroneCAN::led_write(uint8_t led_index, uint8_t red, uint8_t green, uint8_t blue)
+void AP_DroneCAN::SRV_push_servos()
{
- if (_led_conf.devices_count >= AP_DRONECAN_MAX_LED_DEVICES) {
- return false;
- }
-
- WITH_SEMAPHORE(_led_out_sem);
+ WITH_SEMAPHORE(SRV_sem);
- // check if a device instance exists. if so, break so the instance index is remembered
- uint8_t instance = 0;
- for (; instance < _led_conf.devices_count; instance++) {
- if (_led_conf.devices[instance].led_index == led_index) {
- break;
+ for (uint8_t i = 0; i < DRONECAN_SRV_NUMBER; i++) {
+ // Check if this channels has any function assigned
+ if (SRV_Channels::channel_function(i) >= SRV_Channel::k_none) {
+ _SRV_conf[i].pulse = SRV_Channels::srv_channel(i)->get_output_pwm();
+ _SRV_conf[i].esc_pending = true;
+ _SRV_conf[i].servo_pending = true;
}
}
- // load into the correct instance.
- // if an existing instance was found in above for loop search,
- // then instance value is < _led_conf.devices_count.
- // otherwise a new one was just found so we increment the count.
- // Either way, the correct instance is the current value of instance
- _led_conf.devices[instance].led_index = led_index;
- _led_conf.devices[instance].red = red;
- _led_conf.devices[instance].green = green;
- _led_conf.devices[instance].blue = blue;
-
- if (instance == _led_conf.devices_count) {
- _led_conf.devices_count++;
+ uint32_t servo_armed_mask = _servo_bm;
+ uint32_t esc_armed_mask = _esc_bm;
+ const bool safety_off = hal.util->safety_switch_state() != AP_HAL::Util::SAFETY_DISARMED;
+ if (!safety_off) {
+ AP_BoardConfig *boardconfig = AP_BoardConfig::get_singleton();
+ if (boardconfig != nullptr) {
+ const uint32_t safety_mask = boardconfig->get_safety_mask();
+ servo_armed_mask &= safety_mask;
+ esc_armed_mask &= safety_mask;
+ } else {
+ servo_armed_mask = 0;
+ esc_armed_mask = 0;
+ }
}
+ _SRV_armed_mask = servo_armed_mask;
+ _ESC_armed_mask = esc_armed_mask;
- return true;
-}
-
-// buzzer send
-void AP_DroneCAN::buzzer_send()
-{
- uavcan_equipment_indication_BeepCommand msg;
- WITH_SEMAPHORE(_buzzer.sem);
- uint8_t mask = (1U << _driver_index);
- if ((_buzzer.pending_mask & mask) == 0) {
- return;
+ if (_ESC_armed_mask != 0) {
+ // push ESCs as fast as we can
+#if AP_DRONECAN_HOBBYWING_ESC_SUPPORT
+ if (option_is_set(Options::USE_HOBBYWING_ESC)) {
+ SRV_send_esc_hobbywing();
+ } else
+#endif
+ {
+ SRV_send_esc();
+ }
}
- _buzzer.pending_mask &= ~mask;
- msg.frequency = _buzzer.frequency;
- msg.duration = _buzzer.duration;
- buzzer.broadcast(msg);
-}
-
-// buzzer support
-void AP_DroneCAN::set_buzzer_tone(float frequency, float duration_s)
-{
- WITH_SEMAPHORE(_buzzer.sem);
- _buzzer.frequency = frequency;
- _buzzer.duration = duration_s;
- _buzzer.pending_mask = 0xFF;
}
// notify state send
void AP_DroneCAN::notify_state_send()
{
- uint32_t now = AP_HAL::native_millis();
+ uint32_t now = AP_HAL::millis();
if (_notify_state_hz == 0 || (now - _last_notify_state_ms) < uint32_t(1000 / _notify_state_hz)) {
return;
@@ -707,6 +872,18 @@ void AP_DroneCAN::notify_state_send()
msg.vehicle_state |= 1 << ARDUPILOT_INDICATION_NOTIFYSTATE_VEHICLE_STATE_THROW_READY;
}
+#ifndef HAL_BUILD_AP_PERIPH
+ const AP_Vehicle* vehicle = AP::vehicle();
+ if (vehicle != nullptr) {
+ if (vehicle->is_landing()) {
+ msg.vehicle_state |= 1 << ARDUPILOT_INDICATION_NOTIFYSTATE_VEHICLE_STATE_IS_LANDING;
+ }
+ if (vehicle->is_taking_off()) {
+ msg.vehicle_state |= 1 << ARDUPILOT_INDICATION_NOTIFYSTATE_VEHICLE_STATE_IS_TAKING_OFF;
+ }
+ }
+#endif // HAL_BUILD_AP_PERIPH
+
msg.aux_data_type = ARDUPILOT_INDICATION_NOTIFYSTATE_VEHICLE_YAW_EARTH_CENTIDEGREES;
uint16_t yaw_cd = (uint16_t)(360.0f - degrees(AP::ahrs().get_yaw()))*100.0f;
const uint8_t *data = (uint8_t *)&yaw_cd;
@@ -715,7 +892,7 @@ void AP_DroneCAN::notify_state_send()
}
msg.aux_data.len = 2;
notify_state.broadcast(msg);
- _last_notify_state_ms = AP_HAL::native_millis();
+ _last_notify_state_ms = AP_HAL::millis();
}
#if AP_DRONECAN_SEND_GPS
@@ -737,7 +914,7 @@ void AP_DroneCAN::gnss_send_fix()
const Location &loc = gps.location();
const Vector3f &vel = gps.velocity();
- pkt.timestamp.usec = AP_HAL::native_micros64();
+ pkt.timestamp.usec = AP_HAL::micros64();
pkt.gnss_timestamp.usec = gps.time_epoch_usec();
if (pkt.gnss_timestamp.usec == 0) {
pkt.gnss_time_standard = UAVCAN_EQUIPMENT_GNSS_FIX2_GNSS_TIME_STANDARD_NONE;
@@ -805,7 +982,7 @@ void AP_DroneCAN::gnss_send_fix()
- const uint32_t now_ms = AP_HAL::native_millis();
+ const uint32_t now_ms = AP_HAL::millis();
if (now_ms - _gnss.last_send_status_ms >= 1000) {
_gnss.last_send_status_ms = now_ms;
@@ -867,42 +1044,10 @@ void AP_DroneCAN::gnss_send_yaw()
}
#endif // AP_DRONECAN_SEND_GPS
-
-void AP_DroneCAN::rtcm_stream_send()
-{
- WITH_SEMAPHORE(_rtcm_stream.sem);
- if (_rtcm_stream.buf == nullptr ||
- _rtcm_stream.buf->available() == 0) {
- // nothing to send
- return;
- }
- uint32_t now = AP_HAL::native_millis();
- if (now - _rtcm_stream.last_send_ms < 20) {
- // don't send more than 50 per second
- return;
- }
- _rtcm_stream.last_send_ms = now;
- uavcan_equipment_gnss_RTCMStream msg;
- uint32_t len = _rtcm_stream.buf->available();
- if (len > 128) {
- len = 128;
- }
- msg.protocol_id = UAVCAN_EQUIPMENT_GNSS_RTCMSTREAM_PROTOCOL_ID_RTCM3;
- for (uint8_t i=0; iread_byte(&b)) {
- return;
- }
- msg.data.data[i] = b;
- }
- msg.data.len = len;
- rtcm_stream.broadcast(msg);
-}
-
// SafetyState send
void AP_DroneCAN::safety_state_send()
{
- uint32_t now = AP_HAL::native_millis();
+ uint32_t now = AP_HAL::millis();
if (now - _last_safety_state_ms < 500) {
// update at 2Hz
return;
@@ -911,7 +1056,15 @@ void AP_DroneCAN::safety_state_send()
{ // handle SafetyState
ardupilot_indication_SafetyState safety_msg;
- switch (hal.util->safety_switch_state()) {
+ auto state = hal.util->safety_switch_state();
+ if (_SRV_armed_mask != 0 || _ESC_armed_mask != 0) {
+ // if we are outputting any servos or ESCs due to
+ // BRD_SAFETY_MASK then we need to advertise safety as
+ // off, this changes LEDs to indicate unsafe and allows
+ // AP_Periph ESCs and servos to run
+ state = AP_HAL::Util::SAFETY_ARMED;
+ }
+ switch (state) {
case AP_HAL::Util::SAFETY_ARMED:
safety_msg.status = ARDUPILOT_INDICATION_SAFETYSTATE_STATUS_SAFETY_OFF;
safety_state.broadcast(safety_msg);
@@ -934,23 +1087,6 @@ void AP_DroneCAN::safety_state_send()
}
}
-/*
- send RTCMStream packet on all active DroneCAN drivers
-*/
-void AP_DroneCAN::send_RTCMStream(const uint8_t *data, uint32_t len)
-{
- WITH_SEMAPHORE(_rtcm_stream.sem);
- if (_rtcm_stream.buf == nullptr) {
- // give enough space for a full round from a NTRIP server with all
- // constellations
- _rtcm_stream.buf = new ByteBuffer(2400);
- }
- if (_rtcm_stream.buf == nullptr) {
- return;
- }
- _rtcm_stream.buf->write(data, len);
-}
-
/*
handle Button message
*/
@@ -1034,7 +1170,7 @@ void AP_DroneCAN::handle_traffic_report(const CanardRxTransfer& transfer, const
pkt.flags |= ADSB_FLAGS_BARO_VALID;
}
- vehicle.last_update_ms = AP_HAL::native_millis() - (vehicle.info.tslc * 1000);
+ vehicle.last_update_ms = AP_HAL::millis() - (vehicle.info.tslc * 1000);
adsb->handle_adsb_vehicle(vehicle);
#endif
}
@@ -1045,16 +1181,37 @@ void AP_DroneCAN::handle_traffic_report(const CanardRxTransfer& transfer, const
void AP_DroneCAN::handle_actuator_status(const CanardRxTransfer& transfer, const uavcan_equipment_actuator_Status& msg)
{
// log as CSRV message
- AP::logger().Write_ServoStatus(AP_HAL::native_micros64(),
+ AP::logger().Write_ServoStatus(AP_HAL::micros64(),
msg.actuator_id,
msg.position,
msg.force,
msg.speed,
- msg.power_rating_pct);
+ msg.power_rating_pct,
+ 0, 0, 0, 0, 0, 0);
+}
+
+/*
+ handle himark ServoInfo message
+ */
+void AP_DroneCAN::handle_himark_servoinfo(const CanardRxTransfer& transfer, const com_himark_servo_ServoInfo &msg)
+{
+ // log as CSRV message
+ AP::logger().Write_ServoStatus(AP_HAL::micros64(),
+ msg.servo_id,
+ msg.pos_sensor*0.01,
+ 0,
+ 0,
+ 0,
+ msg.pos_cmd*0.01,
+ msg.voltage*0.01,
+ msg.current*0.01,
+ msg.motor_temp*0.2-40,
+ msg.pcb_temp*0.2-40,
+ msg.error_status);
}
#if AP_DRONECAN_VOLZ_FEEDBACK_ENABLED
-void AP_DroneCAN::handle_actuator_status_Volz(AP_DroneCAN* ap_dronecan, uint8_t node_id, const ActuatorStatusVolzCb &cb)
+void AP_DroneCAN::handle_actuator_status_Volz(const CanardRxTransfer& transfer, const com_volz_servo_ActuatorStatus& msg)
{
AP::logger().WriteStreaming(
"CVOL",
@@ -1062,13 +1219,13 @@ void AP_DroneCAN::handle_actuator_status_Volz(AP_DroneCAN* ap_dronecan, uint8_t
"s#dAv%O",
"F-00000",
"QBfffBh",
- AP_HAL::native_micros64(),
- cb.msg->actuator_id,
- ToDeg(cb.msg->actual_position),
- cb.msg->current * 0.025f,
- cb.msg->voltage * 0.2f,
- cb.msg->motor_pwm * (100.0/255.0),
- int16_t(cb.msg->motor_temperature) - 50);
+ AP_HAL::micros64(),
+ msg.actuator_id,
+ ToDeg(msg.actual_position),
+ msg.current * 0.025f,
+ msg.voltage * 0.2f,
+ msg.motor_pwm * (100.0/255.0),
+ int16_t(msg.motor_temperature) - 50);
}
#endif
@@ -1123,6 +1280,30 @@ void AP_DroneCAN::handle_debug(const CanardRxTransfer& transfer, const uavcan_pr
#endif
}
+/*
+ check for parameter get/set response timeout
+*/
+void AP_DroneCAN::check_parameter_callback_timeout()
+{
+ WITH_SEMAPHORE(_param_sem);
+
+ // return immediately if not waiting for get/set parameter response
+ if (param_request_sent_ms == 0) {
+ return;
+ }
+
+ const uint32_t now_ms = AP_HAL::millis();
+ if (now_ms - param_request_sent_ms > AP_DRONECAN_GETSET_TIMEOUT_MS) {
+ param_request_sent_ms = 0;
+ param_int_cb = nullptr;
+ param_float_cb = nullptr;
+ }
+}
+
+/*
+ send any queued request to get/set parameter
+ called from loop
+*/
void AP_DroneCAN::send_parameter_request()
{
WITH_SEMAPHORE(_param_sem);
@@ -1133,12 +1314,16 @@ void AP_DroneCAN::send_parameter_request()
param_request_sent = true;
}
+/*
+ set named float parameter on node
+*/
bool AP_DroneCAN::set_parameter_on_node(uint8_t node_id, const char *name, float value, ParamGetSetFloatCb *cb)
{
WITH_SEMAPHORE(_param_sem);
+
+ // fail if waiting for any previous get/set request
if (param_int_cb != nullptr ||
param_float_cb != nullptr) {
- //busy
return false;
}
param_getset_req.index = 0;
@@ -1147,16 +1332,21 @@ bool AP_DroneCAN::set_parameter_on_node(uint8_t node_id, const char *name, float
param_getset_req.value.union_tag = UAVCAN_PROTOCOL_PARAM_VALUE_REAL_VALUE;
param_float_cb = cb;
param_request_sent = false;
+ param_request_sent_ms = AP_HAL::millis();
param_request_node_id = node_id;
return true;
}
+/*
+ set named integer parameter on node
+*/
bool AP_DroneCAN::set_parameter_on_node(uint8_t node_id, const char *name, int32_t value, ParamGetSetIntCb *cb)
{
WITH_SEMAPHORE(_param_sem);
+
+ // fail if waiting for any previous get/set request
if (param_int_cb != nullptr ||
param_float_cb != nullptr) {
- //busy
return false;
}
param_getset_req.index = 0;
@@ -1165,16 +1355,21 @@ bool AP_DroneCAN::set_parameter_on_node(uint8_t node_id, const char *name, int32
param_getset_req.value.union_tag = UAVCAN_PROTOCOL_PARAM_VALUE_INTEGER_VALUE;
param_int_cb = cb;
param_request_sent = false;
+ param_request_sent_ms = AP_HAL::millis();
param_request_node_id = node_id;
return true;
}
+/*
+ get named float parameter on node
+*/
bool AP_DroneCAN::get_parameter_on_node(uint8_t node_id, const char *name, ParamGetSetFloatCb *cb)
{
WITH_SEMAPHORE(_param_sem);
+
+ // fail if waiting for any previous get/set request
if (param_int_cb != nullptr ||
param_float_cb != nullptr) {
- //busy
return false;
}
param_getset_req.index = 0;
@@ -1182,16 +1377,21 @@ bool AP_DroneCAN::get_parameter_on_node(uint8_t node_id, const char *name, Param
param_getset_req.value.union_tag = UAVCAN_PROTOCOL_PARAM_VALUE_EMPTY;
param_float_cb = cb;
param_request_sent = false;
+ param_request_sent_ms = AP_HAL::millis();
param_request_node_id = node_id;
return true;
}
+/*
+ get named integer parameter on node
+*/
bool AP_DroneCAN::get_parameter_on_node(uint8_t node_id, const char *name, ParamGetSetIntCb *cb)
{
WITH_SEMAPHORE(_param_sem);
+
+ // fail if waiting for any previous get/set request
if (param_int_cb != nullptr ||
param_float_cb != nullptr) {
- //busy
return false;
}
param_getset_req.index = 0;
@@ -1199,6 +1399,7 @@ bool AP_DroneCAN::get_parameter_on_node(uint8_t node_id, const char *name, Param
param_getset_req.value.union_tag = UAVCAN_PROTOCOL_PARAM_VALUE_EMPTY;
param_int_cb = cb;
param_request_sent = false;
+ param_request_sent_ms = AP_HAL::millis();
param_request_node_id = node_id;
return true;
}
@@ -1219,6 +1420,7 @@ void AP_DroneCAN::handle_param_get_set_response(const CanardRxTransfer& transfer
param_getset_req.value.integer_value = val;
param_getset_req.value.union_tag = UAVCAN_PROTOCOL_PARAM_VALUE_INTEGER_VALUE;
param_request_sent = false;
+ param_request_sent_ms = AP_HAL::millis();
param_request_node_id = transfer.source_node_id;
return;
}
@@ -1231,10 +1433,12 @@ void AP_DroneCAN::handle_param_get_set_response(const CanardRxTransfer& transfer
param_getset_req.value.real_value = val;
param_getset_req.value.union_tag = UAVCAN_PROTOCOL_PARAM_VALUE_REAL_VALUE;
param_request_sent = false;
+ param_request_sent_ms = AP_HAL::millis();
param_request_node_id = transfer.source_node_id;
return;
}
}
+ param_request_sent_ms = 0;
param_int_cb = nullptr;
param_float_cb = nullptr;
}
diff --git a/libraries/AP_DroneCAN/AP_DroneCAN.h b/libraries/AP_DroneCAN/AP_DroneCAN.h
index a2df3a8263fbd2..eb3b26a82420fc 100644
--- a/libraries/AP_DroneCAN/AP_DroneCAN.h
+++ b/libraries/AP_DroneCAN/AP_DroneCAN.h
@@ -49,7 +49,10 @@
#define AP_DRONECAN_HW_VERS_MAJOR 1
#define AP_DRONECAN_HW_VERS_MINOR 0
-#define AP_DRONECAN_MAX_LED_DEVICES 4
+
+#ifndef AP_DRONECAN_HOBBYWING_ESC_SUPPORT
+#define AP_DRONECAN_HOBBYWING_ESC_SUPPORT (BOARD_FLASH_SIZE>1024)
+#endif
// fwd-declare callback classes
class AP_DroneCAN_DNA_Server;
@@ -86,16 +89,15 @@ class AP_DroneCAN : public AP_CANDriver, public AP_ESC_Telem_Backend {
// buzzer
void set_buzzer_tone(float frequency, float duration_s);
- // send RTCMStream packets
- void send_RTCMStream(const uint8_t *data, uint32_t len);
-
// Send Reboot command
// Note: Do not call this from outside UAVCAN thread context,
// you can call this from dronecan callbacks and handlers.
// THIS IS NOT A THREAD SAFE API!
void send_reboot_request(uint8_t node_id);
- // set param value
+ // get or set param value
+ // returns true on success, false on failure
+ // failures occur when waiting on node to respond to previous get or set request
bool set_parameter_on_node(uint8_t node_id, const char *name, float value, ParamGetSetFloatCb *cb);
bool set_parameter_on_node(uint8_t node_id, const char *name, int32_t value, ParamGetSetIntCb *cb);
bool get_parameter_on_node(uint8_t node_id, const char *name, ParamGetSetFloatCb *cb);
@@ -112,6 +114,9 @@ class AP_DroneCAN : public AP_CANDriver, public AP_ESC_Telem_Backend {
DNA_IGNORE_UNHEALTHY_NODE = (1U<<3),
USE_ACTUATOR_PWM = (1U<<4),
SEND_GNSS = (1U<<5),
+ USE_HIMARK_SERVO = (1U<<6),
+ USE_HOBBYWING_ESC = (1U<<7),
+ ENABLE_STATS = (1U<<8),
};
// check if a option is set
@@ -125,18 +130,25 @@ class AP_DroneCAN : public AP_CANDriver, public AP_ESC_Telem_Backend {
CanardInterface& get_canard_iface() { return canard_iface; }
+ Canard::Publisher