Use official RMT Encoder API
This commit is contained in:
parent
3f3f1ff90c
commit
96b5595c72
|
|
@ -1,98 +1,92 @@
|
||||||
|
# This GitHub Actions workflow is designed to ensure code quality and
|
||||||
|
# successful compilation for an ESP32 Arduino library.
|
||||||
|
# It runs on every push to any branch.
|
||||||
|
|
||||||
name: ESP32 Build & Quality Check
|
name: ESP32 Build & Quality Check
|
||||||
|
|
||||||
|
# Set permissions for the GitHub token.
|
||||||
|
# 'contents: read' is required to checkout the repository.
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
|
|
||||||
|
# Define the trigger for the workflow.
|
||||||
|
# It runs on any push to any branch.
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [ '*' ]
|
branches: [ '*' ]
|
||||||
|
|
||||||
|
# Concurrency control ensures that only the latest commit for a branch
|
||||||
|
# runs, canceling any workflows already in progress for the same branch.
|
||||||
concurrency:
|
concurrency:
|
||||||
group: ${{ github.workflow }}-${{ github.ref }}
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
# Code Quality & Linting
|
# Prepare Environment & Cache
|
||||||
|
# This job installs the Arduino core and libraries and saves them to a cache
|
||||||
|
# for later jobs to use.
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
|
prepare-cache:
|
||||||
quality-check-linux:
|
name: Prepare Cache (Linux)
|
||||||
name: Arduino Lint Check (Linux)
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
timeout-minutes: 10
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5
|
- name: Checkout Repository
|
||||||
- uses: arduino/setup-arduino-cli@v2
|
uses: actions/checkout@v4
|
||||||
- name: Restore Arduino Core Cache
|
|
||||||
id: cache-core-linux
|
- name: Setup Arduino CLI
|
||||||
uses: actions/cache/restore@v4
|
uses: arduino/setup-arduino-cli@v2
|
||||||
|
|
||||||
|
- name: Restore Arduino Core & Libraries Cache
|
||||||
|
uses: actions/cache@v4
|
||||||
|
id: cache-arduino
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
~/.arduino15/packages
|
~/.arduino15/packages
|
||||||
~/.arduino15/cache
|
~/.arduino15/cache
|
||||||
key: arduino-core-linux-esp32-v1
|
~/Arduino/libraries
|
||||||
restore-keys: |
|
key: linux-arduino-esp32-v2-${{ hashFiles('**/library.properties') }}
|
||||||
arduino-core-linux-
|
|
||||||
- name: Ensure ESP32 Core is installed (Linux)
|
- name: Install Dependencies
|
||||||
|
if: steps.cache-arduino.outputs.cache-hit != 'true'
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
if [[ "${{ steps.cache-core-linux.outputs.cache-hit }}" != "true" ]]; then
|
|
||||||
arduino-cli core update-index --additional-urls https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
|
arduino-cli core update-index --additional-urls https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
|
||||||
fi
|
|
||||||
if ! arduino-cli core list | grep -q 'esp32'; then
|
|
||||||
arduino-cli core install esp32:esp32
|
arduino-cli core install esp32:esp32
|
||||||
fi
|
arduino-cli lib install "ArduinoJson"
|
||||||
- name: Save Arduino Core Cache
|
mkdir -p "$HOME/Arduino/libraries"
|
||||||
if: always() && steps.cache-core-linux.outputs.cache-hit != 'true'
|
git clone --depth=1 https://github.com/ESP32Async/ESPAsyncWebServer "$HOME/Arduino/libraries/ESPAsyncWebServer"
|
||||||
uses: actions/cache/save@v4
|
git clone --depth=1 https://github.com/ESP32Async/AsyncTCP "$HOME/Arduino/libraries/AsyncTCP"
|
||||||
with:
|
|
||||||
path: |
|
|
||||||
~/.arduino15/packages
|
|
||||||
~/.arduino15/cache
|
|
||||||
key: arduino-core-linux-esp32-v1
|
|
||||||
- uses: arduino/arduino-lint-action@v2
|
|
||||||
with:
|
|
||||||
path: ${{ github.workspace }}
|
|
||||||
compliance: strict
|
|
||||||
library-manager: update
|
|
||||||
verbose: true
|
|
||||||
|
|
||||||
quality-check-windows:
|
# ============================================================================
|
||||||
name: Arduino Lint Check (Windows)
|
# Code Quality & Linting
|
||||||
runs-on: windows-latest
|
# This job runs after the cache is prepared and checks the code quality.
|
||||||
|
# ============================================================================
|
||||||
|
quality-check:
|
||||||
|
name: Arduino Lint Check (Linux)
|
||||||
|
needs: prepare-cache
|
||||||
|
runs-on: ubuntu-latest
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5
|
- name: Checkout Repository
|
||||||
- uses: arduino/setup-arduino-cli@v2
|
uses: actions/checkout@v4
|
||||||
- name: Restore Arduino Core Cache
|
|
||||||
id: cache-core-win
|
- name: Setup Arduino CLI
|
||||||
uses: actions/cache/restore@v4
|
uses: arduino/setup-arduino-cli@v2
|
||||||
|
|
||||||
|
- name: Restore Arduino Core & Libraries Cache
|
||||||
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
~/.arduino15/packages
|
~/.arduino15/packages
|
||||||
~/.arduino15/cache
|
~/.arduino15/cache
|
||||||
key: arduino-core-windows-esp32-v1
|
~/Arduino/libraries
|
||||||
restore-keys: |
|
key: linux-arduino-esp32-v2-${{ hashFiles('**/library.properties') }}
|
||||||
arduino-core-windows-
|
|
||||||
- name: Ensure ESP32 Core is installed (Windows)
|
- name: Run Arduino Lint
|
||||||
if: steps.cache-core-win.outputs.cache-hit != 'true'
|
uses: arduino/arduino-lint-action@v2
|
||||||
shell: pwsh
|
|
||||||
run: |
|
|
||||||
if ($env:cache-core-win.outputs.cache-hit -ne 'true') {
|
|
||||||
arduino-cli core update-index --additional-urls https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
|
|
||||||
}
|
|
||||||
if (-not (arduino-cli core list | Select-String 'esp32')) {
|
|
||||||
arduino-cli core install esp32:esp32
|
|
||||||
}
|
|
||||||
- name: Save Arduino Core Cache
|
|
||||||
if: always() && steps.cache-core-win.outputs.cache-hit != 'true'
|
|
||||||
uses: actions/cache/save@v4
|
|
||||||
with:
|
|
||||||
path: |
|
|
||||||
~/.arduino15/packages
|
|
||||||
~/.arduino15/cache
|
|
||||||
key: arduino-core-windows-esp32-v1
|
|
||||||
- uses: arduino/arduino-lint-action@v2
|
|
||||||
with:
|
with:
|
||||||
path: ${{ github.workspace }}
|
path: ${{ github.workspace }}
|
||||||
compliance: strict
|
compliance: strict
|
||||||
|
|
@ -101,114 +95,66 @@ jobs:
|
||||||
|
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
# Compilation Test
|
# Compilation Test
|
||||||
|
# This job compiles all example sketches.
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
|
compile-sketches:
|
||||||
compile-all-sketches:
|
name: Compile ${{ matrix.sketch }} (Linux)
|
||||||
name: Compile ${{ matrix.sketch }} (${{ matrix.os }})
|
needs: prepare-cache
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ubuntu-latest
|
||||||
timeout-minutes: 15
|
timeout-minutes: 15
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest, windows-latest]
|
|
||||||
sketch:
|
sketch:
|
||||||
- examples/throttle_percent/throttle_percent.ino
|
- examples/throttle_percent/throttle_percent.ino
|
||||||
- examples/dshot300/dshot300.ino
|
- examples/dshot300/dshot300.ino
|
||||||
- examples/web_control/web_control.ino
|
- examples/web_control/web_control.ino
|
||||||
- examples/web_client/web_client.ino
|
- examples/web_client/web_client.ino
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5
|
- name: Checkout Repository
|
||||||
- uses: arduino/setup-arduino-cli@v2
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Arduino CLI
|
||||||
|
uses: arduino/setup-arduino-cli@v2
|
||||||
|
|
||||||
- name: Restore Arduino Core & Libraries Cache
|
- name: Restore Arduino Core & Libraries Cache
|
||||||
id: cache-all
|
uses: actions/cache@v4
|
||||||
uses: actions/cache/restore@v4
|
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
~/.arduino15/packages
|
~/.arduino15/packages
|
||||||
~/.arduino15/cache
|
~/.arduino15/cache
|
||||||
~/Arduino/libraries
|
~/Arduino/libraries
|
||||||
key: ${{ runner.os }}-arduino-full-esp32-v1-${{ hashFiles('**/library.properties', '**/platform.txt') }}
|
key: linux-arduino-esp32-v2-${{ hashFiles('**/library.properties') }}
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-arduino-full-esp32-v1-
|
|
||||||
|
|
||||||
- name: Ensure ESP32 Core and Dependencies (Linux)
|
- name: Compile Sketch
|
||||||
if: runner.os == 'Linux' && steps.cache-all.outputs.cache-hit != 'true'
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
arduino-cli core update-index --additional-urls https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
|
|
||||||
arduino-cli core install esp32:esp32
|
|
||||||
mkdir -p ~/Arduino/libraries
|
|
||||||
git clone --depth=1 https://github.com/bblanchon/ArduinoJson.git ~/Arduino/libraries/ArduinoJson
|
|
||||||
git clone --depth=1 https://github.com/ESP32Async/ESPAsyncWebServer ~/Arduino/libraries/ESPAsyncWebServer
|
|
||||||
git clone --depth=1 https://github.com/ESP32Async/AsyncTCP ~/Arduino/libraries/AsyncTCP
|
|
||||||
|
|
||||||
- name: Ensure ESP32 Core and Dependencies (Windows)
|
|
||||||
if: runner.os == 'Windows' && steps.cache-all.outputs.cache-hit != 'true'
|
|
||||||
shell: pwsh
|
|
||||||
run: |
|
|
||||||
arduino-cli core update-index --additional-urls https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
|
|
||||||
arduino-cli core install esp32:esp32
|
|
||||||
if (-not (Test-Path -Path "$env:USERPROFILE/Arduino/libraries/ArduinoJson")) {
|
|
||||||
git clone --depth=1 https://github.com/bblanchon/ArduinoJson.git "$env:USERPROFILE/Arduino/libraries/ArduinoJson"
|
|
||||||
}
|
|
||||||
if (-not (Test-Path -Path "$env:USERPROFILE/Arduino/libraries/ESPAsyncWebServer")) {
|
|
||||||
git clone --depth=1 https://github.com/ESP32Async/ESPAsyncWebServer "$env:USERPROFILE/Arduino/libraries/ESPAsyncWebServer"
|
|
||||||
}
|
|
||||||
if (-not (Test-Path -Path "$env:USERPROFILE/Arduino/libraries/AsyncTCP")) {
|
|
||||||
git clone --depth=1 https://github.com/ESP32Async/AsyncTCP "$env:USERPROFILE/Arduino/libraries/AsyncTCP"
|
|
||||||
}
|
|
||||||
|
|
||||||
- name: Save Arduino Core & Libraries Cache
|
|
||||||
if: always() && steps.cache-all.outputs.cache-hit != 'true'
|
|
||||||
uses: actions/cache/save@v4
|
|
||||||
with:
|
|
||||||
path: |
|
|
||||||
~/.arduino15/packages
|
|
||||||
~/.arduino15/cache
|
|
||||||
~/Arduino/libraries
|
|
||||||
key: ${{ runner.os }}-arduino-full-esp32-v1-${{ hashFiles('**/library.properties', '**/platform.txt') }}
|
|
||||||
|
|
||||||
- name: Compile Sketch (Linux)
|
|
||||||
shell: bash
|
|
||||||
if: runner.os == 'Linux'
|
|
||||||
run: arduino-cli compile --fqbn esp32:esp32:esp32 --library ${{ github.workspace }} "${{ matrix.sketch }}"
|
run: arduino-cli compile --fqbn esp32:esp32:esp32 --library ${{ github.workspace }} "${{ matrix.sketch }}"
|
||||||
|
|
||||||
- name: Compile Sketch (Windows)
|
|
||||||
shell: pwsh
|
|
||||||
if: runner.os == 'Windows'
|
|
||||||
run: arduino-cli compile --fqbn esp32:esp32:esp32 --library ${{ github.workspace }} "${{ matrix.sketch }}"
|
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
# Build Status Report
|
# Build Status Report
|
||||||
|
# This job runs last and provides a summary of the build status.
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
build-summary:
|
build-summary:
|
||||||
name: Build Summary
|
name: Build Summary
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: always()
|
if: always() # This ensures the job runs even if previous jobs fail
|
||||||
needs:
|
needs:
|
||||||
- quality-check-linux
|
- quality-check
|
||||||
- quality-check-windows
|
- compile-sketches
|
||||||
- compile-all-sketches
|
|
||||||
steps:
|
steps:
|
||||||
- name: Create Build Summary
|
- name: Create Build Summary
|
||||||
run: |
|
run: |
|
||||||
echo "# 🔧 DShotRMT Build Report" >> $GITHUB_STEP_SUMMARY
|
echo "# 🔧 DShotRMT Build Report" >> $GITHUB_STEP_SUMMARY
|
||||||
echo "| Check | Status | Details |" >> $GITHUB_STEP_SUMMARY
|
echo "| Check | Status | Details |" >> $GITHUB_STEP_SUMMARY
|
||||||
echo "|-------|--------|---------|" >> $GITHUB_STEP_SUMMARY
|
echo "|-------|--------|---------|" >> $GITHUB_STEP_SUMMARY
|
||||||
|
if [[ "${{ needs.quality-check.result }}" == "success" ]]; then
|
||||||
[[ "${{ needs.quality-check-linux.result }}" == "success" && "${{ needs.quality-check-windows.result }}" == "success" ]] \
|
echo "| 📋 Quality Check | ✅ Passed | Arduino Lint completed successfully |" >> $GITHUB_STEP_SUMMARY
|
||||||
&& echo "| 📋 Quality Check | ✅ Passed | Arduino Lint completed successfully |" >> $GITHUB_STEP_SUMMARY \
|
else
|
||||||
|| echo "| 📋 Quality Check | ❌ Failed | Check Arduino Lint report |" >> $GITHUB_STEP_SUMMARY
|
echo "| 📋 Quality Check | ❌ Failed | Check Arduino Lint report for errors |" >> $GITHUB_STEP_SUMMARY
|
||||||
|
fi
|
||||||
[[ "${{ needs.compile-all-sketches.result }}" == "success" ]] \
|
if [[ "${{ needs.compile-sketches.result }}" == "success" ]]; then
|
||||||
&& echo "| 🔨 Compilation | ✅ Passed | All examples compiled successfully |" >> $GITHUB_STEP_SUMMARY \
|
echo "| 🔨 Compilation | ✅ Passed | All examples compiled successfully |" >> $GITHUB_STEP_SUMMARY
|
||||||
|| echo "| 🔨 Compilation | ❌ Failed | Compilation errors detected |" >> $GITHUB_STEP_SUMMARY
|
else
|
||||||
|
echo "| 🔨 Compilation | ❌ Failed | One or more examples failed to compile |" >> $GITHUB_STEP_SUMMARY
|
||||||
echo "" >> $GITHUB_STEP_SUMMARY
|
fi
|
||||||
|
|
||||||
[[ "${{ needs.quality-check-linux.result }}" == "success" && "${{ needs.quality-check-windows.result }}" == "success" && "${{ needs.compile-all-sketches.result }}" == "success" ]] \
|
|
||||||
&& echo "## 🎉 All Checks Passed!" >> $GITHUB_STEP_SUMMARY \
|
|
||||||
&& echo "Your DShotRMT library is ready for deployment." >> $GITHUB_STEP_SUMMARY \
|
|
||||||
|| echo "## ⚠️ Action Required" >> $GITHUB_STEP_SUMMARY \
|
|
||||||
&& echo "Please review the failed checks and address any issues." >> $GITHUB_STEP_SUMMARY
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
[](https://github.com/derdoktor667/DShotRMT/actions/workflows/ci.yml)
|
[](https://github.com/derdoktor667/DShotRMT/actions/workflows/ci.yml)
|
||||||
|
|
||||||
A C++ library for generating DShot signals on ESP32 microcontrollers using the **modern ESP-IDF 5 RMT encoder API** (`rmt_tx.h` / `rmt_rx.h`). It provides a simple, efficient, and hardware-timed way to control brushless motors in both Arduino and ESP-IDF projects. The legacy version using the old `rmt.h` API is available in the `oldAPI` branch.
|
A C++ library for generating DShot signals on ESP32 microcontrollers using the **modern ESP-IDF 5 RMT encoder API** (`rmt_tx.h` / `rmt_rx.h`). It leverages the standard `rmt_bytes_encoder` to ensure an efficient, hardware-timed, and maintainable implementation. The library provides a simple way to control brushless motors in both Arduino and ESP-IDF projects. The legacy version using the old `rmt.h` API is available in the `oldAPI` branch.
|
||||||
|
|
||||||
## 🚀 Core Features
|
## 🚀 Core Features
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -88,7 +88,7 @@ void loop()
|
||||||
if (IS_BIDIRECTIONAL)
|
if (IS_BIDIRECTIONAL)
|
||||||
{
|
{
|
||||||
dshot_result_t telem_result = motor01.getTelemetry();
|
dshot_result_t telem_result = motor01.getTelemetry();
|
||||||
printDShotResult(telem_result);
|
DShotRMT::printDShotResult(telem_result);
|
||||||
}
|
}
|
||||||
|
|
||||||
USB_SERIAL.println("Type 'help' to show Menu");
|
USB_SERIAL.println("Type 'help' to show Menu");
|
||||||
|
|
@ -128,7 +128,7 @@ void handleSerialInput(const String &input, uint16_t &throttle, bool &continuous
|
||||||
throttle = 0;
|
throttle = 0;
|
||||||
continuous_throttle = true;
|
continuous_throttle = true;
|
||||||
dshot_result_t result = motor01.sendCommand(DSHOT_CMD_MOTOR_STOP);
|
dshot_result_t result = motor01.sendCommand(DSHOT_CMD_MOTOR_STOP);
|
||||||
printDShotResult(result);
|
DShotRMT::printDShotResult(result);
|
||||||
}
|
}
|
||||||
else if (input == "info")
|
else if (input == "info")
|
||||||
{
|
{
|
||||||
|
|
@ -137,7 +137,7 @@ void handleSerialInput(const String &input, uint16_t &throttle, bool &continuous
|
||||||
else if (input == "rpm" && IS_BIDIRECTIONAL)
|
else if (input == "rpm" && IS_BIDIRECTIONAL)
|
||||||
{
|
{
|
||||||
dshot_result_t result = motor01.getTelemetry();
|
dshot_result_t result = motor01.getTelemetry();
|
||||||
printDShotResult(result);
|
DShotRMT::printDShotResult(result);
|
||||||
}
|
}
|
||||||
else if (input.startsWith("cmd "))
|
else if (input.startsWith("cmd "))
|
||||||
{
|
{
|
||||||
|
|
@ -149,7 +149,7 @@ void handleSerialInput(const String &input, uint16_t &throttle, bool &continuous
|
||||||
if (cmd_num >= DSHOT_CMD_MOTOR_STOP && cmd_num <= DSHOT_CMD_MAX)
|
if (cmd_num >= DSHOT_CMD_MOTOR_STOP && cmd_num <= DSHOT_CMD_MAX)
|
||||||
{
|
{
|
||||||
dshot_result_t result = motor01.sendCommand(cmd_num);
|
dshot_result_t result = motor01.sendCommand(cmd_num);
|
||||||
printDShotResult(result);
|
DShotRMT::printDShotResult(result);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -171,7 +171,7 @@ void handleSerialInput(const String &input, uint16_t &throttle, bool &continuous
|
||||||
continuous_throttle = true;
|
continuous_throttle = true;
|
||||||
|
|
||||||
dshot_result_t result = motor01.sendThrottle(throttle);
|
dshot_result_t result = motor01.sendThrottle(throttle);
|
||||||
printDShotResult(result);
|
DShotRMT::printDShotResult(result);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,7 @@ void handleSerialInput(const String &input)
|
||||||
{
|
{
|
||||||
// Stop motor
|
// Stop motor
|
||||||
dshot_result_t result = motor01.sendThrottlePercent(0.0f);
|
dshot_result_t result = motor01.sendThrottlePercent(0.0f);
|
||||||
printDShotResult(result);
|
DShotRMT::printDShotResult(result);
|
||||||
}
|
}
|
||||||
else if (input == "info")
|
else if (input == "info")
|
||||||
{
|
{
|
||||||
|
|
@ -103,7 +103,7 @@ void handleSerialInput(const String &input)
|
||||||
else if (input == "rpm" && IS_BIDIRECTIONAL)
|
else if (input == "rpm" && IS_BIDIRECTIONAL)
|
||||||
{
|
{
|
||||||
dshot_result_t result = motor01.getTelemetry();
|
dshot_result_t result = motor01.getTelemetry();
|
||||||
printDShotResult(result);
|
DShotRMT::printDShotResult(result);
|
||||||
}
|
}
|
||||||
else if (input.startsWith("cmd "))
|
else if (input.startsWith("cmd "))
|
||||||
{
|
{
|
||||||
|
|
@ -113,7 +113,7 @@ void handleSerialInput(const String &input)
|
||||||
if (cmd_num >= DSHOT_CMD_MOTOR_STOP && cmd_num <= DSHOT_CMD_MAX)
|
if (cmd_num >= DSHOT_CMD_MOTOR_STOP && cmd_num <= DSHOT_CMD_MAX)
|
||||||
{
|
{
|
||||||
dshot_result_t result = motor01.sendCommand(cmd_num);
|
dshot_result_t result = motor01.sendCommand(cmd_num);
|
||||||
printDShotResult(result);
|
DShotRMT::printDShotResult(result);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -132,7 +132,7 @@ void handleSerialInput(const String &input)
|
||||||
if (throttle_percent >= 0.0f && throttle_percent <= 100.0f)
|
if (throttle_percent >= 0.0f && throttle_percent <= 100.0f)
|
||||||
{
|
{
|
||||||
dshot_result_t result = motor01.sendThrottlePercent(throttle_percent);
|
dshot_result_t result = motor01.sendThrottlePercent(throttle_percent);
|
||||||
printDShotResult(result);
|
DShotRMT::printDShotResult(result);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -178,7 +178,7 @@ void loop()
|
||||||
if (IS_BIDIRECTIONAL && isArmed)
|
if (IS_BIDIRECTIONAL && isArmed)
|
||||||
{
|
{
|
||||||
dshot_result_t telem_result = motor01.getTelemetry(MOTOR01_MAGNET_COUNT);
|
dshot_result_t telem_result = motor01.getTelemetry(MOTOR01_MAGNET_COUNT);
|
||||||
printDShotResult(telem_result);
|
DShotRMT::printDShotResult(telem_result);
|
||||||
}
|
}
|
||||||
|
|
||||||
USB_SERIAL.println("Type 'help' to show Menu");
|
USB_SERIAL.println("Type 'help' to show Menu");
|
||||||
|
|
@ -495,7 +495,7 @@ void handleSerialInput(const String &input)
|
||||||
if (isArmed)
|
if (isArmed)
|
||||||
{
|
{
|
||||||
dshot_result_t result = motor01.getTelemetry(MOTOR01_MAGNET_COUNT);
|
dshot_result_t result = motor01.getTelemetry(MOTOR01_MAGNET_COUNT);
|
||||||
printDShotResult(result);
|
DShotRMT::printDShotResult(result);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -520,7 +520,7 @@ void handleSerialInput(const String &input)
|
||||||
if (cmd_num >= DSHOT_CMD_MOTOR_STOP && cmd_num <= DSHOT_CMD_MAX)
|
if (cmd_num >= DSHOT_CMD_MOTOR_STOP && cmd_num <= DSHOT_CMD_MAX)
|
||||||
{
|
{
|
||||||
dshot_result_t result = motor01.sendCommand(cmd_num);
|
dshot_result_t result = motor01.sendCommand(cmd_num);
|
||||||
printDShotResult(result);
|
DShotRMT::printDShotResult(result);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -581,7 +581,7 @@ void handleSerialInput(const String &input)
|
||||||
throttle = 0;
|
throttle = 0;
|
||||||
continuous_throttle = false;
|
continuous_throttle = false;
|
||||||
dshot_result_t result = motor01.sendCommand(DSHOT_CMD_MOTOR_STOP);
|
dshot_result_t result = motor01.sendCommand(DSHOT_CMD_MOTOR_STOP);
|
||||||
printDShotResult(result);
|
DShotRMT::printDShotResult(result);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -146,7 +146,7 @@ void loop()
|
||||||
if (IS_BIDIRECTIONAL && isArmed)
|
if (IS_BIDIRECTIONAL && isArmed)
|
||||||
{
|
{
|
||||||
dshot_result_t telem_result = motor01.getTelemetry(MOTOR01_MAGNET_COUNT);
|
dshot_result_t telem_result = motor01.getTelemetry(MOTOR01_MAGNET_COUNT);
|
||||||
printDShotResult(telem_result);
|
DShotRMT::printDShotResult(telem_result);
|
||||||
}
|
}
|
||||||
|
|
||||||
USB_SERIAL.println("Type 'help' to show Menu");
|
USB_SERIAL.println("Type 'help' to show Menu");
|
||||||
|
|
@ -264,7 +264,7 @@ void handleSerialInput(const String &input)
|
||||||
if (isArmed)
|
if (isArmed)
|
||||||
{
|
{
|
||||||
dshot_result_t result = motor01.getTelemetry(MOTOR01_MAGNET_COUNT);
|
dshot_result_t result = motor01.getTelemetry(MOTOR01_MAGNET_COUNT);
|
||||||
printDShotResult(result);
|
DShotRMT::printDShotResult(result);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -288,7 +288,7 @@ void handleSerialInput(const String &input)
|
||||||
if (cmd_num >= DSHOT_CMD_MOTOR_STOP && cmd_num <= DSHOT_CMD_MAX)
|
if (cmd_num >= DSHOT_CMD_MOTOR_STOP && cmd_num <= DSHOT_CMD_MAX)
|
||||||
{
|
{
|
||||||
dshot_result_t result = motor01.sendCommand(cmd_num);
|
dshot_result_t result = motor01.sendCommand(cmd_num);
|
||||||
printDShotResult(result);
|
DShotRMT::printDShotResult(result);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -341,7 +341,7 @@ void handleSerialInput(const String &input)
|
||||||
throttle = 0;
|
throttle = 0;
|
||||||
continuous_throttle = false;
|
continuous_throttle = false;
|
||||||
dshot_result_t result = motor01.sendCommand(DSHOT_CMD_MOTOR_STOP);
|
dshot_result_t result = motor01.sendCommand(DSHOT_CMD_MOTOR_STOP);
|
||||||
printDShotResult(result);
|
DShotRMT::printDShotResult(result);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
181
src/DShotRMT.cpp
181
src/DShotRMT.cpp
|
|
@ -23,8 +23,8 @@ DShotRMT::DShotRMT(gpio_num_t gpio, dshot_mode_t mode, bool is_bidirectional, ui
|
||||||
_last_command_timestamp(0),
|
_last_command_timestamp(0),
|
||||||
_encoded_frame_value(0),
|
_encoded_frame_value(0),
|
||||||
_packet{0},
|
_packet{0},
|
||||||
_level0(1), // DShot standard: signal is idle-low, so pulses start by going HIGH
|
_pulse_level(1), // DShot standard: signal is idle-low, so pulses start by going HIGH
|
||||||
_level1(0), // DShot standard: signal returns to LOW after the high pulse
|
_idle_level(0), // DShot standard: signal returns to LOW after the high pulse
|
||||||
_rmt_tx_channel(nullptr),
|
_rmt_tx_channel(nullptr),
|
||||||
_rmt_rx_channel(nullptr),
|
_rmt_rx_channel(nullptr),
|
||||||
_dshot_encoder(nullptr),
|
_dshot_encoder(nullptr),
|
||||||
|
|
@ -355,9 +355,25 @@ dshot_result_t DShotRMT::_initRXChannel()
|
||||||
|
|
||||||
dshot_result_t DShotRMT::_initDShotEncoder()
|
dshot_result_t DShotRMT::_initDShotEncoder()
|
||||||
{
|
{
|
||||||
rmt_copy_encoder_config_t encoder_config = {};
|
rmt_bytes_encoder_config_t encoder_config = {
|
||||||
|
.bit0 = {
|
||||||
|
.duration0 = _rmt_ticks.t0h_ticks,
|
||||||
|
.level0 = _pulse_level,
|
||||||
|
.duration1 = _rmt_ticks.t0l_ticks,
|
||||||
|
.level1 = _idle_level,
|
||||||
|
},
|
||||||
|
.bit1 = {
|
||||||
|
.duration0 = _rmt_ticks.t1h_ticks,
|
||||||
|
.level0 = _pulse_level,
|
||||||
|
.duration1 = _rmt_ticks.t1l_ticks,
|
||||||
|
.level1 = _idle_level,
|
||||||
|
},
|
||||||
|
.flags = {
|
||||||
|
.msb_first = 1 // DShot is MSB first
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if (rmt_new_copy_encoder(&encoder_config, &_dshot_encoder) != DSHOT_OK)
|
if (rmt_new_bytes_encoder(&encoder_config, &_dshot_encoder) != DSHOT_OK)
|
||||||
{
|
{
|
||||||
return {false, dshot_msg_code_t::DSHOT_ERROR_ENCODER_INIT_FAILED};
|
return {false, dshot_msg_code_t::DSHOT_ERROR_ENCODER_INIT_FAILED};
|
||||||
}
|
}
|
||||||
|
|
@ -424,50 +440,27 @@ void DShotRMT::_preCalculateRMTTicks()
|
||||||
dshot_result_t DShotRMT::_sendDShotFrame(const dshot_packet_t &packet)
|
dshot_result_t DShotRMT::_sendDShotFrame(const dshot_packet_t &packet)
|
||||||
{
|
{
|
||||||
// Ensure enough time has passed since the last transmission
|
// Ensure enough time has passed since the last transmission
|
||||||
if (!_timer_signal())
|
if (!_isFrameIntervalElapsed())
|
||||||
{
|
{
|
||||||
return {true, dshot_msg_code_t::DSHOT_ERROR_NONE};
|
return {true, dshot_msg_code_t::DSHOT_ERROR_NONE};
|
||||||
}
|
}
|
||||||
|
|
||||||
rmt_symbol_word_t tx_symbols[DSHOT_BITS_PER_FRAME];
|
_encoded_frame_value = _buildDShotFrameValue(packet);
|
||||||
dshot_result_t result = _encodeDShotFrame(packet, tx_symbols);
|
|
||||||
|
|
||||||
if (!result.success)
|
// The DShot frame is 16 bits, which is 2 bytes
|
||||||
{
|
size_t tx_size_bytes = sizeof(_encoded_frame_value);
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t tx_size_bytes = DSHOT_BITS_PER_FRAME * sizeof(rmt_symbol_word_t);
|
if (rmt_transmit(_rmt_tx_channel, _dshot_encoder, &_encoded_frame_value, tx_size_bytes, &_rmt_tx_config) != DSHOT_OK)
|
||||||
|
|
||||||
if (rmt_transmit(_rmt_tx_channel, _dshot_encoder, tx_symbols, tx_size_bytes, &_rmt_tx_config) != DSHOT_OK)
|
|
||||||
{
|
{
|
||||||
return {false, dshot_msg_code_t::DSHOT_ERROR_TRANSMISSION_FAILED};
|
return {false, dshot_msg_code_t::DSHOT_ERROR_TRANSMISSION_FAILED};
|
||||||
}
|
}
|
||||||
|
|
||||||
_timer_reset(); // Reset the timer for the next frame
|
_recordFrameTransmissionTime(); // Reset the timer for the next frame
|
||||||
|
|
||||||
return {true, dshot_msg_code_t::DSHOT_ERROR_TRANSMISSION_SUCCESS};
|
return {true, dshot_msg_code_t::DSHOT_ERROR_TRANSMISSION_SUCCESS};
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function needs to be fast, as it generates the RMT symbols just before sending
|
|
||||||
dshot_result_t IRAM_ATTR DShotRMT::_encodeDShotFrame(const dshot_packet_t &packet, rmt_symbol_word_t *symbols)
|
|
||||||
{
|
|
||||||
_encoded_frame_value = _buildDShotFrameValue(packet);
|
|
||||||
|
|
||||||
for (int i = 0; i < DSHOT_BITS_PER_FRAME; ++i)
|
|
||||||
{
|
|
||||||
int bit_position = DSHOT_BITS_PER_FRAME - 1 - i;
|
|
||||||
bool bit = (_encoded_frame_value >> bit_position) & 1;
|
|
||||||
|
|
||||||
// A '1' bit has a longer high-time, a '0' bit has a shorter high-time
|
|
||||||
symbols[i].level0 = _level0; // Go HIGH
|
|
||||||
symbols[i].duration0 = bit ? _rmt_ticks.t1h_ticks : _rmt_ticks.t0h_ticks;
|
|
||||||
symbols[i].level1 = _level1; // Go LOW
|
|
||||||
symbols[i].duration1 = bit ? _rmt_ticks.t1l_ticks : _rmt_ticks.t0l_ticks;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {true, dshot_msg_code_t::DSHOT_ERROR_ENCODING_SUCCESS};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Placed in IRAM for high performance, as it's called from an ISR context
|
// Placed in IRAM for high performance, as it's called from an ISR context
|
||||||
uint16_t IRAM_ATTR DShotRMT::_decodeDShotFrame(const rmt_symbol_word_t *symbols)
|
uint16_t IRAM_ATTR DShotRMT::_decodeDShotFrame(const rmt_symbol_word_t *symbols)
|
||||||
|
|
@ -510,7 +503,7 @@ uint16_t IRAM_ATTR DShotRMT::_decodeDShotFrame(const rmt_symbol_word_t *symbols)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Timing Control Functions
|
// Timing Control Functions
|
||||||
bool IRAM_ATTR DShotRMT::_timer_signal()
|
bool IRAM_ATTR DShotRMT::_isFrameIntervalElapsed()
|
||||||
{
|
{
|
||||||
// Check if the minimum interval between frames has passed
|
// Check if the minimum interval between frames has passed
|
||||||
uint64_t current_time = esp_timer_get_time();
|
uint64_t current_time = esp_timer_get_time();
|
||||||
|
|
@ -518,11 +511,10 @@ bool IRAM_ATTR DShotRMT::_timer_signal()
|
||||||
return elapsed >= _frame_timer_us;
|
return elapsed >= _frame_timer_us;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DShotRMT::_timer_reset()
|
void DShotRMT::_recordFrameTransmissionTime()
|
||||||
{
|
{
|
||||||
// Record the time of the current transmission
|
// Record the time of the current transmission
|
||||||
_last_transmission_time_us = esp_timer_get_time();
|
_last_transmission_time_us = esp_timer_get_time();
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Static Callback Functions
|
// Static Callback Functions
|
||||||
|
|
@ -546,14 +538,123 @@ bool IRAM_ATTR DShotRMT::_on_rx_done(rmt_channel_handle_t rmt_rx_channel, const
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DShotRMT::printDShotResult(const dshot_result_t &result, Stream &output)
|
||||||
|
{
|
||||||
|
const char *msg_str;
|
||||||
|
switch (result.error_code)
|
||||||
|
{
|
||||||
|
case dshot_msg_code_t::DSHOT_ERROR_NONE:
|
||||||
|
msg_str = "None";
|
||||||
|
break;
|
||||||
|
case dshot_msg_code_t::DSHOT_ERROR_UNKNOWN:
|
||||||
|
msg_str = "Unknown Error!";
|
||||||
|
break;
|
||||||
|
case dshot_msg_code_t::DSHOT_ERROR_TX_INIT_FAILED:
|
||||||
|
msg_str = "TX RMT channel init failed!";
|
||||||
|
break;
|
||||||
|
case dshot_msg_code_t::DSHOT_ERROR_RX_INIT_FAILED:
|
||||||
|
msg_str = "RX RMT channel init failed!";
|
||||||
|
break;
|
||||||
|
case dshot_msg_code_t::DSHOT_ERROR_ENCODER_INIT_FAILED:
|
||||||
|
msg_str = "RMT encoder init failed!";
|
||||||
|
break;
|
||||||
|
case dshot_msg_code_t::DSHOT_ERROR_CALLBACK_REGISTERING_FAILED:
|
||||||
|
msg_str = "RMT RX Callback registering failed!";
|
||||||
|
break;
|
||||||
|
case dshot_msg_code_t::DSHOT_ERROR_RECEIVER_FAILED:
|
||||||
|
msg_str = "RMT receiver failed!";
|
||||||
|
break;
|
||||||
|
case dshot_msg_code_t::DSHOT_ERROR_TRANSMISSION_FAILED:
|
||||||
|
msg_str = "Transmission failed!";
|
||||||
|
break;
|
||||||
|
case dshot_msg_code_t::DSHOT_ERROR_THROTTLE_NOT_IN_RANGE:
|
||||||
|
msg_str = "Throttle not in range! (48 - 2047)";
|
||||||
|
break;
|
||||||
|
case dshot_msg_code_t::DSHOT_ERROR_PERCENT_NOT_IN_RANGE:
|
||||||
|
msg_str = "Percent not in range! (0.0 - 100.0)";
|
||||||
|
break;
|
||||||
|
case dshot_msg_code_t::DSHOT_ERROR_COMMAND_NOT_VALID:
|
||||||
|
msg_str = "Command not valid! (0 - 47)";
|
||||||
|
break;
|
||||||
|
case dshot_msg_code_t::DSHOT_ERROR_BIDIR_NOT_ENABLED:
|
||||||
|
msg_str = "Bidirectional DShot not enabled!";
|
||||||
|
break;
|
||||||
|
case dshot_msg_code_t::DSHOT_ERROR_TELEMETRY_FAILED:
|
||||||
|
msg_str = "No valid Telemetric Frame received!";
|
||||||
|
break;
|
||||||
|
case dshot_msg_code_t::DSHOT_ERROR_INVALID_MAGNET_COUNT:
|
||||||
|
msg_str = "Invalid motor magnet count!";
|
||||||
|
break;
|
||||||
|
case dshot_msg_code_t::DSHOT_ERROR_INVALID_COMMAND:
|
||||||
|
msg_str = "Invalid command!";
|
||||||
|
break;
|
||||||
|
case dshot_msg_code_t::DSHOT_ERROR_TIMING_CORRECTION:
|
||||||
|
msg_str = "Timing correction!";
|
||||||
|
break;
|
||||||
|
case dshot_msg_code_t::DSHOT_ERROR_INIT_FAILED:
|
||||||
|
msg_str = "SignalGeneratorRMT init failed!";
|
||||||
|
break;
|
||||||
|
case dshot_msg_code_t::DSHOT_ERROR_INIT_SUCCESS:
|
||||||
|
msg_str = "SignalGeneratorRMT initialized successfully";
|
||||||
|
break;
|
||||||
|
case dshot_msg_code_t::DSHOT_ERROR_TX_INIT_SUCCESS:
|
||||||
|
msg_str = "TX RMT channel initialized successfully";
|
||||||
|
break;
|
||||||
|
case dshot_msg_code_t::DSHOT_ERROR_RX_INIT_SUCCESS:
|
||||||
|
msg_str = "RX RMT channel initialized successfully";
|
||||||
|
break;
|
||||||
|
case dshot_msg_code_t::DSHOT_ERROR_ENCODING_SUCCESS:
|
||||||
|
msg_str = "Packet encoded successfully";
|
||||||
|
break;
|
||||||
|
case dshot_msg_code_t::DSHOT_ERROR_TRANSMISSION_SUCCESS:
|
||||||
|
msg_str = "Transmission successfully";
|
||||||
|
break;
|
||||||
|
case dshot_msg_code_t::DSHOT_ERROR_TELEMETRY_SUCCESS:
|
||||||
|
msg_str = "Valid Telemetric Frame received!";
|
||||||
|
break;
|
||||||
|
case dshot_msg_code_t::DSHOT_ERROR_COMMAND_SUCCESS:
|
||||||
|
msg_str = "DShot command sent successfully";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
msg_str = "Unhandled Error Code!";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
output.printf("Status: %s - %s", result.success ? "SUCCESS" : "FAILED", msg_str);
|
||||||
|
|
||||||
|
// Print telemetry data if available
|
||||||
|
if (result.success && (result.erpm > 0 || result.motor_rpm > 0))
|
||||||
|
{
|
||||||
|
output.printf(" | eRPM: %u, Motor RPM: %u", result.erpm, result.motor_rpm);
|
||||||
|
}
|
||||||
|
|
||||||
|
output.println();
|
||||||
|
}
|
||||||
|
|
||||||
// Public Static Utility Functions
|
// Public Static Utility Functions
|
||||||
void DShotRMT::printDShotInfo(const DShotRMT &dshot_rmt, Stream &output)
|
void DShotRMT::printDShotInfo(const DShotRMT &dshot_rmt, Stream &output)
|
||||||
{
|
{
|
||||||
output.println("\n === DShot Signal Info === ");
|
output.println("\n === DShot Signal Info === ");
|
||||||
output.printf("Current Mode: DSHOT%d\n", dshot_rmt.getMode() == dshot_mode_t::DSHOT150 ? 150 : dshot_rmt.getMode() == dshot_mode_t::DSHOT300 ? 300
|
|
||||||
: dshot_rmt.getMode() == dshot_mode_t::DSHOT600 ? 600
|
int mode_val = 0;
|
||||||
: dshot_rmt.getMode() == dshot_mode_t::DSHOT1200 ? 1200
|
switch (dshot_rmt.getMode())
|
||||||
: 0);
|
{
|
||||||
|
case dshot_mode_t::DSHOT150:
|
||||||
|
mode_val = 150;
|
||||||
|
break;
|
||||||
|
case dshot_mode_t::DSHOT300:
|
||||||
|
mode_val = 300;
|
||||||
|
break;
|
||||||
|
case dshot_mode_t::DSHOT600:
|
||||||
|
mode_val = 600;
|
||||||
|
break;
|
||||||
|
case dshot_mode_t::DSHOT1200:
|
||||||
|
mode_val = 1200;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
output.printf("Current Mode: DSHOT%d\n", mode_val);
|
||||||
|
|
||||||
output.printf("Bidirectional: %s\n", dshot_rmt.isBidirectional() ? "YES" : "NO");
|
output.printf("Bidirectional: %s\n", dshot_rmt.isBidirectional() ? "YES" : "NO");
|
||||||
output.printf("Current Packet: ");
|
output.printf("Current Packet: ");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -113,6 +113,13 @@ public:
|
||||||
dshot_result_t saveESCSettings();
|
dshot_result_t saveESCSettings();
|
||||||
|
|
||||||
// Public Utility & Info Functions
|
// Public Utility & Info Functions
|
||||||
|
/**
|
||||||
|
* @brief Prints the result of a DShot operation to the specified output stream.
|
||||||
|
* @param result The dshot_result_t structure containing the operation's outcome.
|
||||||
|
* @param output The output stream (e.g., Serial) to print to. Defaults to Serial.
|
||||||
|
*/
|
||||||
|
static void printDShotResult(const dshot_result_t &result, Stream &output = Serial);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Prints detailed DShot signal information for a given DShotRMT instance.
|
* @brief Prints detailed DShot signal information for a given DShotRMT instance.
|
||||||
* @param dshot_rmt The DShotRMT instance to get information from.
|
* @param dshot_rmt The DShotRMT instance to get information from.
|
||||||
|
|
@ -213,8 +220,8 @@ private:
|
||||||
uint64_t _last_command_timestamp;
|
uint64_t _last_command_timestamp;
|
||||||
uint16_t _encoded_frame_value;
|
uint16_t _encoded_frame_value;
|
||||||
dshot_packet_t _packet;
|
dshot_packet_t _packet;
|
||||||
uint16_t _level0; // DShot protocol: Signal is idle-low, so pulses start by going HIGH.
|
uint16_t _pulse_level; // DShot protocol: Signal is idle-low, so pulses start by going HIGH.
|
||||||
uint16_t _level1; // DShot protocol: Signal returns to LOW after the high pulse.
|
uint16_t _idle_level; // DShot protocol: Signal returns to LOW after the high pulse.
|
||||||
|
|
||||||
// RMT Hardware Handles
|
// RMT Hardware Handles
|
||||||
rmt_channel_handle_t _rmt_tx_channel;
|
rmt_channel_handle_t _rmt_tx_channel;
|
||||||
|
|
@ -245,12 +252,12 @@ private:
|
||||||
|
|
||||||
// Private Frame Processing Functions
|
// Private Frame Processing Functions
|
||||||
dshot_result_t _sendDShotFrame(const dshot_packet_t &packet);
|
dshot_result_t _sendDShotFrame(const dshot_packet_t &packet);
|
||||||
dshot_result_t _encodeDShotFrame(const dshot_packet_t &packet, rmt_symbol_word_t *symbols);
|
|
||||||
uint16_t _decodeDShotFrame(const rmt_symbol_word_t *symbols);
|
uint16_t _decodeDShotFrame(const rmt_symbol_word_t *symbols);
|
||||||
|
|
||||||
// Private Timing Control Functions
|
// Private Timing Control Functions
|
||||||
bool _timer_signal();
|
bool _isFrameIntervalElapsed();
|
||||||
bool _timer_reset();
|
void _recordFrameTransmissionTime();
|
||||||
|
|
||||||
// Static Callback Functions
|
// Static Callback Functions
|
||||||
static bool _on_rx_done(rmt_channel_handle_t rmt_rx_channel, const rmt_rx_done_event_data_t *edata, void *user_data);
|
static bool _on_rx_done(rmt_channel_handle_t rmt_rx_channel, const rmt_rx_done_event_data_t *edata, void *user_data);
|
||||||
|
|
|
||||||
|
|
@ -217,101 +217,3 @@ const char *const TIMING_CORRECTION = "Timing correction!";
|
||||||
const char *const CALLBACK_REGISTERING_FAILED = "RMT RX Callback registering failed!";
|
const char *const CALLBACK_REGISTERING_FAILED = "RMT RX Callback registering failed!";
|
||||||
const char *const INVALID_COMMAND = "Invalid command!";
|
const char *const INVALID_COMMAND = "Invalid command!";
|
||||||
const char *const COMMAND_SUCCESS = "DShot command sent successfully";
|
const char *const COMMAND_SUCCESS = "DShot command sent successfully";
|
||||||
|
|
||||||
// Helper Functions
|
|
||||||
/**
|
|
||||||
* @brief Prints the result of a DShot operation to the specified output stream.
|
|
||||||
* @param result The dshot_result_t structure containing the operation's outcome.
|
|
||||||
* @param output The output stream (e.g., Serial) to print to. Defaults to Serial.
|
|
||||||
*/
|
|
||||||
inline void printDShotResult(dshot_result_t &result, Stream &output = Serial)
|
|
||||||
{
|
|
||||||
const char *msg_str;
|
|
||||||
switch (result.error_code)
|
|
||||||
{
|
|
||||||
case dshot_msg_code_t::DSHOT_ERROR_NONE:
|
|
||||||
msg_str = "None";
|
|
||||||
break;
|
|
||||||
case dshot_msg_code_t::DSHOT_ERROR_UNKNOWN:
|
|
||||||
msg_str = "Unknown Error!";
|
|
||||||
break;
|
|
||||||
case dshot_msg_code_t::DSHOT_ERROR_TX_INIT_FAILED:
|
|
||||||
msg_str = "TX RMT channel init failed!";
|
|
||||||
break;
|
|
||||||
case dshot_msg_code_t::DSHOT_ERROR_RX_INIT_FAILED:
|
|
||||||
msg_str = "RX RMT channel init failed!";
|
|
||||||
break;
|
|
||||||
case dshot_msg_code_t::DSHOT_ERROR_ENCODER_INIT_FAILED:
|
|
||||||
msg_str = "RMT encoder init failed!";
|
|
||||||
break;
|
|
||||||
case dshot_msg_code_t::DSHOT_ERROR_CALLBACK_REGISTERING_FAILED:
|
|
||||||
msg_str = "RMT RX Callback registering failed!";
|
|
||||||
break;
|
|
||||||
case dshot_msg_code_t::DSHOT_ERROR_RECEIVER_FAILED:
|
|
||||||
msg_str = "RMT receiver failed!";
|
|
||||||
break;
|
|
||||||
case dshot_msg_code_t::DSHOT_ERROR_TRANSMISSION_FAILED:
|
|
||||||
msg_str = "Transmission failed!";
|
|
||||||
break;
|
|
||||||
case dshot_msg_code_t::DSHOT_ERROR_THROTTLE_NOT_IN_RANGE:
|
|
||||||
msg_str = "Throttle not in range! (48 - 2047)";
|
|
||||||
break;
|
|
||||||
case dshot_msg_code_t::DSHOT_ERROR_PERCENT_NOT_IN_RANGE:
|
|
||||||
msg_str = "Percent not in range! (0.0 - 100.0)";
|
|
||||||
break;
|
|
||||||
case dshot_msg_code_t::DSHOT_ERROR_COMMAND_NOT_VALID:
|
|
||||||
msg_str = "Command not valid! (0 - 47)";
|
|
||||||
break;
|
|
||||||
case dshot_msg_code_t::DSHOT_ERROR_BIDIR_NOT_ENABLED:
|
|
||||||
msg_str = "Bidirectional DShot not enabled!";
|
|
||||||
break;
|
|
||||||
case dshot_msg_code_t::DSHOT_ERROR_TELEMETRY_FAILED:
|
|
||||||
msg_str = "No valid Telemetric Frame received!";
|
|
||||||
break;
|
|
||||||
case dshot_msg_code_t::DSHOT_ERROR_INVALID_MAGNET_COUNT:
|
|
||||||
msg_str = "Invalid motor magnet count!";
|
|
||||||
break;
|
|
||||||
case dshot_msg_code_t::DSHOT_ERROR_INVALID_COMMAND:
|
|
||||||
msg_str = "Invalid command!";
|
|
||||||
break;
|
|
||||||
case dshot_msg_code_t::DSHOT_ERROR_TIMING_CORRECTION:
|
|
||||||
msg_str = "Timing correction!";
|
|
||||||
break;
|
|
||||||
case dshot_msg_code_t::DSHOT_ERROR_INIT_FAILED:
|
|
||||||
msg_str = "SignalGeneratorRMT init failed!";
|
|
||||||
break;
|
|
||||||
case dshot_msg_code_t::DSHOT_ERROR_INIT_SUCCESS:
|
|
||||||
msg_str = "SignalGeneratorRMT initialized successfully";
|
|
||||||
break;
|
|
||||||
case dshot_msg_code_t::DSHOT_ERROR_TX_INIT_SUCCESS:
|
|
||||||
msg_str = "TX RMT channel initialized successfully";
|
|
||||||
break;
|
|
||||||
case dshot_msg_code_t::DSHOT_ERROR_RX_INIT_SUCCESS:
|
|
||||||
msg_str = "RX RMT channel initialized successfully";
|
|
||||||
break;
|
|
||||||
case dshot_msg_code_t::DSHOT_ERROR_ENCODING_SUCCESS:
|
|
||||||
msg_str = "Packet encoded successfully";
|
|
||||||
break;
|
|
||||||
case dshot_msg_code_t::DSHOT_ERROR_TRANSMISSION_SUCCESS:
|
|
||||||
msg_str = "Transmission successfully";
|
|
||||||
break;
|
|
||||||
case dshot_msg_code_t::DSHOT_ERROR_TELEMETRY_SUCCESS:
|
|
||||||
msg_str = "Valid Telemetric Frame received!";
|
|
||||||
break;
|
|
||||||
case dshot_msg_code_t::DSHOT_ERROR_COMMAND_SUCCESS:
|
|
||||||
msg_str = "DShot command sent successfully";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
msg_str = "Unhandled Error Code!";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
output.printf("Status: %s - %s", result.success ? "SUCCESS" : "FAILED", msg_str);
|
|
||||||
|
|
||||||
// Print telemetry data if available
|
|
||||||
if (result.success && (result.erpm > 0 || result.motor_rpm > 0))
|
|
||||||
{
|
|
||||||
output.printf(" | eRPM: %u, Motor RPM: %u", result.erpm, result.motor_rpm);
|
|
||||||
}
|
|
||||||
|
|
||||||
output.println();
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue