...simplify user api

This commit is contained in:
Wastl Kraus 2025-09-25 16:32:40 +02:00
parent 7447855c32
commit 3f3f1ff90c
9 changed files with 81 additions and 140 deletions

View File

@ -36,7 +36,9 @@ jobs:
- name: Ensure ESP32 Core is installed (Linux)
shell: bash
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
fi
if ! arduino-cli core list | grep -q 'esp32'; then
arduino-cli core install esp32:esp32
fi
@ -73,9 +75,12 @@ jobs:
restore-keys: |
arduino-core-windows-
- name: Ensure ESP32 Core is installed (Windows)
if: steps.cache-core-win.outputs.cache-hit != 'true'
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
}
@ -98,79 +103,52 @@ jobs:
# Compilation Test
# ============================================================================
compile-test-linux:
name: Compile Sketches (Linux)
runs-on: ubuntu-latest
compile-all-sketches:
name: Compile ${{ matrix.sketch }} (${{ matrix.os }})
runs-on: ${{ matrix.os }}
timeout-minutes: 15
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest]
sketch:
- examples/throttle_percent/throttle_percent.ino
- examples/dshot300/dshot300.ino
- examples/web_control/web_control.ino
- examples/web_client/web_client.ino
steps:
- uses: actions/checkout@v5
- uses: arduino/setup-arduino-cli@v2
- name: Restore Arduino Core & Libraries Cache
id: cache-all-linux
id: cache-all
uses: actions/cache/restore@v4
with:
path: |
~/.arduino15/packages
~/.arduino15/cache
~/Arduino/libraries
key: arduino-full-linux-esp32-v1
key: ${{ runner.os }}-arduino-full-esp32-v1-${{ hashFiles('**/library.properties', '**/platform.txt') }}
restore-keys: |
arduino-full-linux-
${{ runner.os }}-arduino-full-esp32-v1-
- name: Ensure ESP32 Core and Dependencies (Linux)
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
if ! arduino-cli core list | grep -q 'esp32'; then
arduino-cli core install esp32:esp32
fi
mkdir -p ~/Arduino/libraries
if [ ! -d ~/Arduino/libraries/ArduinoJson ]; then
git clone --depth=1 https://github.com/bblanchon/ArduinoJson.git ~/Arduino/libraries/ArduinoJson
fi
if [ ! -d ~/Arduino/libraries/ESPAsyncWebServer ]; then
git clone --depth=1 https://github.com/ESP32Async/ESPAsyncWebServer ~/Arduino/libraries/ESPAsyncWebServer
fi
if [ ! -d ~/Arduino/libraries/AsyncTCP ]; then
git clone --depth=1 https://github.com/ESP32Async/AsyncTCP ~/Arduino/libraries/AsyncTCP
fi
- name: Save Arduino Core & Libraries Cache
if: always() && steps.cache-all-linux.outputs.cache-hit != 'true'
uses: actions/cache/save@v4
with:
path: |
~/.arduino15/packages
~/.arduino15/cache
~/Arduino/libraries
key: arduino-full-linux-esp32-v1
- name: Compile Sketch
run: |
arduino-cli compile --fqbn esp32:esp32:esp32 --library ${{ github.workspace }} examples/dshot300/dshot300.ino
compile-test-windows:
name: Compile Sketches (Windows)
runs-on: windows-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v5
- uses: arduino/setup-arduino-cli@v2
- name: Restore Arduino Core & Libraries Cache
id: cache-all-win
uses: actions/cache/restore@v4
with:
path: |
~/.arduino15/packages
~/.arduino15/cache
~/Arduino/libraries
key: arduino-full-windows-esp32-v1
restore-keys: |
arduino-full-windows-
- 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
if (-not (arduino-cli core list | Select-String 'esp32')) {
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"
}
@ -180,19 +158,26 @@ jobs:
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-win.outputs.cache-hit != 'true'
if: always() && steps.cache-all.outputs.cache-hit != 'true'
uses: actions/cache/save@v4
with:
path: |
~/.arduino15/packages
~/.arduino15/cache
~/Arduino/libraries
key: arduino-full-windows-esp32-v1
- name: Compile Sketch
run: |
arduino-cli compile --fqbn esp32:esp32:esp32 --library ${{ github.workspace }} examples/dshot300/dshot300.ino
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 }}"
- 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
# ============================================================================
@ -203,8 +188,7 @@ jobs:
needs:
- quality-check-linux
- quality-check-windows
- compile-test-linux
- compile-test-windows
- compile-all-sketches
steps:
- name: Create Build Summary
run: |
@ -216,13 +200,13 @@ jobs:
&& echo "| 📋 Quality Check | ✅ Passed | Arduino Lint completed successfully |" >> $GITHUB_STEP_SUMMARY \
|| echo "| 📋 Quality Check | ❌ Failed | Check Arduino Lint report |" >> $GITHUB_STEP_SUMMARY
[[ "${{ needs.compile-test-linux.result }}" == "success" && "${{ needs.compile-test-windows.result }}" == "success" ]] \
[[ "${{ needs.compile-all-sketches.result }}" == "success" ]] \
&& echo "| 🔨 Compilation | ✅ Passed | All examples compiled successfully |" >> $GITHUB_STEP_SUMMARY \
|| echo "| 🔨 Compilation | ❌ Failed | Compilation errors detected |" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
[[ "${{ needs.quality-check-linux.result }}" == "success" && "${{ needs.quality-check-windows.result }}" == "success" && "${{ needs.compile-test-linux.result }}" == "success" && "${{ needs.compile-test-windows.result }}" == "success" ]] \
[[ "${{ 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 \

View File

@ -51,6 +51,9 @@ void setup() {
// Initialize the DShot motor
motor.begin();
// Print CPU Info
DShotRMT::printCpuInfo(Serial);
Serial.println("Motor initialized. Ramping up to 25% throttle...");
// Ramp up to 25% throttle over 2.5 seconds
@ -61,6 +64,9 @@ void setup() {
Serial.println("Stopping motor.");
motor.sendThrottlePercent(0);
// Print DShot Info
DShotRMT::printDShotInfo(motor, Serial);
}
void loop() {
@ -106,6 +112,8 @@ The main class is `DShotRMT`. Here are the most important methods:
- `sendCommand(uint16_t command)`: Sends a DShot command (0-47) to the motor.
- `getTelemetry(uint16_t magnet_count)`: Receives and parses telemetry data from the motor (for bidirectional DShot, which is currently not officially supported).
- `printDShotResult(dshot_result_t &result, Stream &output = Serial)`: Helper function to print DShot operation results and telemetry to a specified serial output.
- `DShotRMT::printDShotInfo(const DShotRMT &dshot_rmt, Stream &output = Serial)`: Static helper function to print detailed DShot signal information for a given DShotRMT instance.
- `DShotRMT::printCpuInfo(Stream &output = Serial)`: Static helper function to print detailed CPU information.
## 🤝 Contributing

View File

@ -51,7 +51,7 @@ void setup()
void loop()
{
// Safety first
static uint16_t throttle = static_cast<uint16_t>(dshotCommands_e::DSHOT_CMD_MOTOR_STOP);
static uint16_t throttle = DSHOT_CMD_MOTOR_STOP;
// Initialize the esc with "0"
static bool continuous_throttle = true;
@ -127,7 +127,7 @@ void handleSerialInput(const String &input, uint16_t &throttle, bool &continuous
// Stop motor
throttle = 0;
continuous_throttle = true;
dshot_result_t result = motor01.sendCommand(static_cast<uint16_t>(dshotCommands_e::DSHOT_CMD_MOTOR_STOP));
dshot_result_t result = motor01.sendCommand(DSHOT_CMD_MOTOR_STOP);
printDShotResult(result);
}
else if (input == "info")
@ -146,14 +146,14 @@ void handleSerialInput(const String &input, uint16_t &throttle, bool &continuous
// Send DShot command
int cmd_num = input.substring(4).toInt();
if (cmd_num >= static_cast<uint16_t>(dshotCommands_e::DSHOT_CMD_MOTOR_STOP) && cmd_num <= static_cast<uint16_t>(dshotCommands_e::DSHOT_CMD_MAX))
if (cmd_num >= DSHOT_CMD_MOTOR_STOP && cmd_num <= DSHOT_CMD_MAX)
{
dshot_result_t result = motor01.sendCommand(cmd_num);
printDShotResult(result);
}
else
{
USB_SERIAL.printf("Invalid command: %d (valid range: 0 - %d)\n", cmd_num, static_cast<uint16_t>(dshotCommands_e::DSHOT_CMD_MAX));
USB_SERIAL.printf("Invalid command: %d (valid range: 0 - %d)\n", cmd_num, DSHOT_CMD_MAX);
}
}
else if (input == "h" || input == "help")

View File

@ -110,14 +110,14 @@ void handleSerialInput(const String &input)
// Send DShot command
int cmd_num = input.substring(4).toInt();
if (cmd_num >= static_cast<uint16_t>(dshotCommands_e::DSHOT_CMD_MOTOR_STOP) && cmd_num <= static_cast<uint16_t>(dshotCommands_e::DSHOT_CMD_MAX))
if (cmd_num >= DSHOT_CMD_MOTOR_STOP && cmd_num <= DSHOT_CMD_MAX)
{
dshot_result_t result = motor01.sendCommand(cmd_num);
printDShotResult(result);
}
else
{
USB_SERIAL.printf("Invalid command: %d (valid range: 0 - %d)\n", cmd_num, static_cast<uint16_t>(dshotCommands_e::DSHOT_CMD_MAX));
USB_SERIAL.printf("Invalid command: %d (valid range: 0 - %d)\n", cmd_num, DSHOT_CMD_MAX);
}
}
else if (input == "h" || input == "help")

View File

@ -58,7 +58,7 @@ AsyncWebServer server(80);
AsyncWebSocket ws("/ws");
// Global variables
static uint16_t throttle = static_cast<uint16_t>(dshotCommands_e::DSHOT_CMD_MOTOR_STOP);
static uint16_t throttle = DSHOT_CMD_MOTOR_STOP;
static bool isArmed = false;
static bool last_sent_armed = false;
static bool continuous_throttle = true;
@ -126,7 +126,7 @@ void setup()
void loop()
{
static uint64_t last_serial_update = 0;
static uint16_t last_sent_throttle = static_cast<uint16_t>(dshotCommands_e::DSHOT_CMD_MOTOR_STOP);
static uint16_t last_sent_throttle = DSHOT_CMD_MOTOR_STOP;
static String last_sent_rpm = "N/A";
static uint64_t last_wifi_check = 0;
@ -166,7 +166,7 @@ void loop()
}
else if (!isArmed && continuous_throttle)
{
motor01.sendCommand(static_cast<uint16_t>(dshotCommands_e::DSHOT_CMD_MOTOR_STOP));
motor01.sendCommand(DSHOT_CMD_MOTOR_STOP);
}
// Print motor stats every 3 seconds in continuous mode
@ -267,7 +267,7 @@ void handleOTAUpload(AsyncWebServerRequest *request, String filename, size_t ind
if (!index)
{
// Safety: Ensure motor is stopped during update
motor01.sendCommand(static_cast<uint16_t>(dshotCommands_e::DSHOT_CMD_MOTOR_STOP)); setArmingStatus(false);
motor01.sendCommand(DSHOT_CMD_MOTOR_STOP); setArmingStatus(false);
USB_SERIAL.printf("OTA Update Start: %s\n", filename.c_str());
@ -380,7 +380,7 @@ void setArmingStatus(bool armed)
// Safety: Stop motor and reset throttle when disarming
throttle = 0;
continuous_throttle = false;
motor01.sendCommand(static_cast<uint16_t>(dshotCommands_e::DSHOT_CMD_MOTOR_STOP));
motor01.sendCommand(DSHOT_CMD_MOTOR_STOP);
USB_SERIAL.println(" ");
USB_SERIAL.println("=== MOTOR DISARMED - SAFETY STOP EXECUTED ===");
@ -517,7 +517,7 @@ void handleSerialInput(const String &input)
continuous_throttle = false;
int cmd_num = input.substring(4).toInt();
if (cmd_num >= static_cast<uint16_t>(dshotCommands_e::DSHOT_CMD_MOTOR_STOP) && cmd_num <= static_cast<uint16_t>(dshotCommands_e::DSHOT_CMD_MAX))
if (cmd_num >= DSHOT_CMD_MOTOR_STOP && cmd_num <= DSHOT_CMD_MAX)
{
dshot_result_t result = motor01.sendCommand(cmd_num);
printDShotResult(result);
@ -525,7 +525,7 @@ void handleSerialInput(const String &input)
else
{
USB_SERIAL.println(" ");
USB_SERIAL.printf("Invalid command: %d (valid range: 0 - %d)\n", cmd_num, static_cast<uint16_t>(dshotCommands_e::DSHOT_CMD_MAX));
USB_SERIAL.printf("Invalid command: %d (valid range: 0 - %d)\n", cmd_num, DSHOT_CMD_MAX);
}
return;
}
@ -580,7 +580,7 @@ void handleSerialInput(const String &input)
{
throttle = 0;
continuous_throttle = false;
dshot_result_t result = motor01.sendCommand(static_cast<uint16_t>(dshotCommands_e::DSHOT_CMD_MOTOR_STOP));
dshot_result_t result = motor01.sendCommand(DSHOT_CMD_MOTOR_STOP);
printDShotResult(result);
return;
}
@ -634,7 +634,7 @@ void handleWebSocketMessage(void *arg, uint8_t *data, size_t len)
{
throttle = 0;
continuous_throttle = false;
motor01.sendCommand(static_cast<uint16_t>(dshotCommands_e::DSHOT_CMD_MOTOR_STOP));
motor01.sendCommand(DSHOT_CMD_MOTOR_STOP);
}
else if (web_throttle >= DSHOT_THROTTLE_MIN && web_throttle <= DSHOT_THROTTLE_MAX)
{

View File

@ -57,7 +57,7 @@ AsyncWebServer server(80);
AsyncWebSocket ws("/ws");
// Global variables
static uint16_t throttle = static_cast<uint16_t>(dshotCommands_e::DSHOT_CMD_MOTOR_STOP);
static uint16_t throttle = DSHOT_CMD_MOTOR_STOP;
static bool isArmed = false;
static bool continuous_throttle = true;
@ -109,7 +109,7 @@ void setup()
void loop()
{
static uint64_t last_serial_update = 0;
static uint16_t last_sent_throttle = static_cast<uint16_t>(dshotCommands_e::DSHOT_CMD_MOTOR_STOP);
static uint16_t last_sent_throttle = DSHOT_CMD_MOTOR_STOP;
static bool last_sent_armed = false;
static String last_sent_rpm = "N/A";
@ -131,7 +131,8 @@ void loop()
}
else if (!isArmed && continuous_throttle)
{
motor01.sendCommand(static_cast<uint16_t>(dshotCommands_e::DSHOT_CMD_MOTOR_STOP));
// Ensure motor is stopped when disarmed
motor01.sendCommand(DSHOT_CMD_MOTOR_STOP);
}
// Print motor stats every 3 seconds in continuous mode
@ -206,7 +207,7 @@ void setArmingStatus(bool armed)
// Safety: Stop motor and reset throttle when disarming
throttle = 0;
continuous_throttle = false;
motor01.sendCommand(static_cast<uint16_t>(dshotCommands_e::DSHOT_CMD_MOTOR_STOP));
motor01.sendCommand(DSHOT_CMD_MOTOR_STOP);
USB_SERIAL.println(" ");
USB_SERIAL.println("=== MOTOR DISARMED - SAFETY STOP EXECUTED ===");
}
@ -284,7 +285,7 @@ void handleSerialInput(const String &input)
continuous_throttle = false;
int cmd_num = input.substring(4).toInt();
if (cmd_num >= static_cast<uint16_t>(dshotCommands_e::DSHOT_CMD_MOTOR_STOP) && cmd_num <= static_cast<uint16_t>(dshotCommands_e::DSHOT_CMD_MAX))
if (cmd_num >= DSHOT_CMD_MOTOR_STOP && cmd_num <= DSHOT_CMD_MAX)
{
dshot_result_t result = motor01.sendCommand(cmd_num);
printDShotResult(result);
@ -292,7 +293,7 @@ void handleSerialInput(const String &input)
else
{
USB_SERIAL.println(" ");
USB_SERIAL.printf("Invalid command: %d (valid range: 0 - %d)\n", cmd_num, static_cast<uint16_t>(dshotCommands_e::DSHOT_CMD_MAX));
USB_SERIAL.printf("Invalid command: %d (valid range: 0 - %d)\n", cmd_num, DSHOT_CMD_MAX);
}
return;
}
@ -339,7 +340,7 @@ void handleSerialInput(const String &input)
{
throttle = 0;
continuous_throttle = false;
dshot_result_t result = motor01.sendCommand(static_cast<uint16_t>(dshotCommands_e::DSHOT_CMD_MOTOR_STOP));
dshot_result_t result = motor01.sendCommand(DSHOT_CMD_MOTOR_STOP);
printDShotResult(result);
return;
}
@ -393,7 +394,7 @@ void handleWebSocketMessage(void *arg, uint8_t *data, size_t len)
{
throttle = 0;
continuous_throttle = false;
motor01.sendCommand(static_cast<uint16_t>(dshotCommands_e::DSHOT_CMD_MOTOR_STOP));
motor01.sendCommand(DSHOT_CMD_MOTOR_STOP);
}
else if (web_throttle >= DSHOT_THROTTLE_MIN && web_throttle <= DSHOT_THROTTLE_MAX)
{

View File

@ -7,59 +7,7 @@
#######################################
DShotRMT KEYWORD1
DShotCommandManager KEYWORD1
dshot_mode_t KEYWORD1
dshot_packet_t KEYWORD1
dshot_timing_t KEYWORD1
dshot_commands_t KEYWORD1
dshot_command_result_t KEYWORD1
dshot_command_sequence_item_t KEYWORD1
dshotCommands_e KEYWORD1
dshotCommandType_e KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
# DShotRMT Methods
begin KEYWORD2
setThrottle KEYWORD2
sendThrottle KEYWORD2
sendDShotCommand KEYWORD2
sendCommand KEYWORD2
getERPM KEYWORD2
getMotorRPM KEYWORD2
getGPIO KEYWORD2
getDShotPacket KEYWORD2
is_bidirectional KEYWORD2
printDShotInfo KEYWORD2
printCpuInfo KEYWORD2
# DShotCommandManager Methods
sendCommand KEYWORD2
sendCommandWithDelay KEYWORD2
stopMotor KEYWORD2
set3DMode KEYWORD2
setSpinDirection KEYWORD2
saveSettings KEYWORD2
setExtendedTelemetry KEYWORD2
requestESCInfo KEYWORD2
setLED KEYWORD2
activateBeacon KEYWORD2
setAudioStreamMode KEYWORD2
setSilentMode KEYWORD2
executeSequence KEYWORD2
executeInitSequence KEYWORD2
executeCalibrationSequence KEYWORD2
getCommandName KEYWORD2
isValidCommand KEYWORD2
printStatistics KEYWORD2
resetStatistics KEYWORD2
getTotalCommandCount KEYWORD2
getFailedCommandCount KEYWORD2
getLastExecutionTime KEYWORD2
printMenu KEYWORD2
handleMenuInput KEYWORD2
#######################################
# Constants (LITERAL1)

View File

@ -1,5 +1,5 @@
name=DShotRMT
version=0.8.5
version=0.8.6
author=Wastl Kraus <wir-sind-die-matrix.de>
maintainer=Wastl Kraus <wir-sind-die-matrix.de>
license=MIT
@ -8,4 +8,4 @@ paragraph=This library can control a BlHeli_S by using encoded DShot commands.
category=Signal Input/Output
url=https://github.com/derdoktor667/DShotRMT
architectures=esp32
provides_includes=DShotRMT.h, dshot_commands.h, web_content.h, ota_update.h
provides_includes=DShotRMT.h, dshot_definitions.h, web_content.h, ota_update.h

View File

@ -102,7 +102,7 @@ typedef struct dshot_result
* @brief DShot Commands
* Enum class for standard DShot commands that can be sent to an ESC.
*/
enum class dshotCommands_e
enum dshotCommands_e
{
DSHOT_CMD_MOTOR_STOP = 0,
DSHOT_CMD_BEACON1,