library compatibility issues

release 0.8.7
This commit is contained in:
Wastl Kraus 2025-09-30 20:47:37 +02:00 committed by GitHub
commit 946e64168e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 249 additions and 267 deletions

View File

@ -7,6 +7,10 @@
"settings": { "settings": {
"files.associations": { "files.associations": {
"string": "cpp" "string": "cpp"
} },
"arduino.logLevel": "verbose",
"arduino.path": "/usr/bin/arduino-cli",
"arduino.useArduinoCli": true,
"arduino.disableIntelliSenseAutoGen": true
} }
} }

View File

@ -2,7 +2,9 @@
[![Arduino CI](https://github.com/derdoktor667/DShotRMT/actions/workflows/ci.yml/badge.svg)](https://github.com/derdoktor667/DShotRMT/actions/workflows/ci.yml) [![Arduino CI](https://github.com/derdoktor667/DShotRMT/actions/workflows/ci.yml/badge.svg)](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`). This library specifically leverages the official `rmt_bytes_encoder` API for an efficient, hardware-timed, and maintainable implementation. It 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. An Arduino IDElibrary for generating DShot signals on ESP32 microcontrollers using the **modern ESP-IDF 5 RMT encoder API** (`rmt_tx.h` / `rmt_rx.h`). This library specifically leverages the official `rmt_bytes_encoder` API for an efficient, hardware-timed, and maintainable implementation. It 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.
### DShot300 Example Output ### DShot300 Example Output
@ -16,8 +18,8 @@ Here's an example of the output from the `dshot300` example sketch:
- **Bidirectional DShot Support:** Implemented, but note that official support is limited due to potential instability and external hardware requirements. Use with caution. - **Bidirectional DShot Support:** Implemented, but note that official support is limited due to potential instability and external hardware requirements. Use with caution.
- **Hardware-Timed Signals:** Precise signal generation using the ESP32 RMT peripheral, ensuring stable and reliable motor control. - **Hardware-Timed Signals:** Precise signal generation using the ESP32 RMT peripheral, ensuring stable and reliable motor control.
- **Simple API:** Easy-to-use C++ class with intuitive methods like `sendThrottlePercent()`. - **Simple API:** Easy-to-use C++ class with intuitive methods like `sendThrottlePercent()`.
- **Robust Error Handling:** Provides detailed feedback on operation success or failure via `dshot_result_t`. - **Error Handling:** Provides detailed feedback on operation success or failure via `dshot_result_t`.
- **Efficient and Lightweight:** The core library has no external dependencies. - **Lightweight:** The core library has no external dependencies.
- **Arduino and ESP-IDF Compatible:** Can be used in both Arduino and ESP-IDF projects. - **Arduino and ESP-IDF Compatible:** Can be used in both Arduino and ESP-IDF projects.
## ⏱️ DShot Timing Information ## ⏱️ DShot Timing Information
@ -39,18 +41,9 @@ The DShot protocol defines specific timing characteristics for each mode. The fo
2. Search for "DShotRMT" and click "Install". 2. Search for "DShotRMT" and click "Install".
3. Alternatively, you can clone this repository or download it as a ZIP file and place it in your Arduino libraries folder (`~/Arduino/libraries/DShotRMT/`). 3. Alternatively, you can clone this repository or download it as a ZIP file and place it in your Arduino libraries folder (`~/Arduino/libraries/DShotRMT/`).
### PlatformIO
Add the following to your `platformio.ini` file:
```ini
lib_deps =
https://github.com/derdoktor667/DShotRMT.git
```
## ⚡ Quick Start ## ⚡ Quick Start
Here's a basic example of how to use the `DShotRMT` library to control a motor: Here's a basic example of how to use the `DShotRMT` library to control a motor. Please use example sketches for more detailes:
```cpp ```cpp
#include <Arduino.h> #include <Arduino.h>
@ -73,6 +66,9 @@ void setup() {
Serial.println("Motor initialized. Ramping up to 25% throttle..."); Serial.println("Motor initialized. Ramping up to 25% throttle...");
}
void loop() {
// Ramp up to 25% throttle over 2.5 seconds // Ramp up to 25% throttle over 2.5 seconds
for (int i = 0; i <= 25; i++) { for (int i = 0; i <= 25; i++) {
motor.sendThrottlePercent(i); motor.sendThrottlePercent(i);
@ -85,10 +81,6 @@ void setup() {
// Print DShot Info // Print DShot Info
DShotRMT::printDShotInfo(motor, Serial); DShotRMT::printDShotInfo(motor, Serial);
} }
void loop() {
// Your main code here
}
``` ```
## 🎮 Examples ## 🎮 Examples
@ -147,4 +139,4 @@ Contributions are welcome! Please fork the repository, create a feature branch,
## 📄 License ## 📄 License
This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details. This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.

View File

@ -7,7 +7,7 @@
*/ */
#include <Arduino.h> #include <Arduino.h>
#include "DShotRMT.h" #include <DShotRMT.h>
// USB serial port settings // USB serial port settings
static constexpr auto &USB_SERIAL = Serial0; static constexpr auto &USB_SERIAL = Serial0;
@ -29,7 +29,7 @@ static constexpr auto IS_BIDIRECTIONAL = false;
static constexpr auto MOTOR01_MAGNET_COUNT = 14; static constexpr auto MOTOR01_MAGNET_COUNT = 14;
// Creates the motor instance // Creates the motor instance
DShotRMT motor01(MOTOR01_PIN, DSHOT_MODE, IS_BIDIRECTIONAL, MOTOR01_MAGNET_COUNT); DShotRMT motor01(MOTOR01_PIN, DSHOT_MODE, IS_BIDIRECTIONAL);
// //
void setup() void setup()

View File

@ -1,5 +1,5 @@
name=DShotRMT name=DShotRMT
version=0.8.6 version=0.8.7
author=Wastl Kraus <wir-sind-die-matrix.de> author=Wastl Kraus <wir-sind-die-matrix.de>
maintainer=Wastl Kraus <wir-sind-die-matrix.de> maintainer=Wastl Kraus <wir-sind-die-matrix.de>
license=MIT license=MIT

View File

@ -18,13 +18,13 @@ DShotRMT::DShotRMT(gpio_num_t gpio, dshot_mode_t mode, bool is_bidirectional, ui
_dshot_timing(DSHOT_TIMING_US[static_cast<int>(mode)]), _dshot_timing(DSHOT_TIMING_US[static_cast<int>(mode)]),
_frame_timer_us(0), _frame_timer_us(0),
_rmt_ticks{0}, _rmt_ticks{0},
_last_throttle(static_cast<uint16_t>(dshotCommands_e::DSHOT_CMD_MOTOR_STOP)), _last_throttle(dshotCommands_e::DSHOT_CMD_MOTOR_STOP),
_last_transmission_time_us(0), _last_transmission_time_us(0),
_last_command_timestamp(0), _last_command_timestamp(0),
_encoded_frame_value(0), _encoded_frame_value(0),
_packet{0}, _packet{0},
_pulse_level(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
_idle_level(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),
@ -38,9 +38,6 @@ DShotRMT::DShotRMT(gpio_num_t gpio, dshot_mode_t mode, bool is_bidirectional, ui
{ {
// Pre-calculate timing and bit positions for performance // Pre-calculate timing and bit positions for performance
_preCalculateRMTTicks(); _preCalculateRMTTicks();
// Activate internal pullup resistor
// gpio_set_pull_mode(_gpio, GPIO_PULLUP_ONLY);
} }
// Constructor using pin number // Constructor using pin number
@ -87,7 +84,7 @@ dshot_result_t DShotRMT::begin()
{ {
if (!_initTXChannel().success) if (!_initTXChannel().success)
{ {
return {false, dshot_msg_code_t::DSHOT_ERROR_TX_INIT_FAILED}; return {false, dshot_msg_code_t::DSHOT_TX_INIT_FAILED};
} }
if (_is_bidirectional) if (_is_bidirectional)
@ -98,7 +95,7 @@ dshot_result_t DShotRMT::begin()
rmt_disable(_rmt_tx_channel); rmt_disable(_rmt_tx_channel);
rmt_del_channel(_rmt_tx_channel); rmt_del_channel(_rmt_tx_channel);
_rmt_tx_channel = nullptr; _rmt_tx_channel = nullptr;
return {false, dshot_msg_code_t::DSHOT_ERROR_RX_INIT_FAILED}; return {false, dshot_msg_code_t::DSHOT_RX_INIT_FAILED};
} }
} }
@ -116,10 +113,10 @@ dshot_result_t DShotRMT::begin()
_rmt_rx_channel = nullptr; _rmt_rx_channel = nullptr;
} }
return {false, dshot_msg_code_t::DSHOT_ERROR_ENCODER_INIT_FAILED}; return {false, dshot_msg_code_t::DSHOT_ENCODER_INIT_FAILED};
} }
return {true, dshot_msg_code_t::DSHOT_ERROR_INIT_SUCCESS}; return {true, dshot_msg_code_t::DSHOT_INIT_SUCCESS};
} }
// Send throttle value // Send throttle value
@ -128,7 +125,7 @@ dshot_result_t DShotRMT::sendThrottle(uint16_t throttle)
// A throttle value of 0 is a disarm command // A throttle value of 0 is a disarm command
if (throttle == 0) if (throttle == 0)
{ {
return sendCommand(static_cast<uint16_t>(dshotCommands_e::DSHOT_CMD_MOTOR_STOP)); return sendCommand(dshotCommands_e::DSHOT_CMD_MOTOR_STOP);
} }
// Constrain throttle to the valid DShot range // Constrain throttle to the valid DShot range
@ -143,21 +140,20 @@ dshot_result_t DShotRMT::sendThrottlePercent(float percent)
{ {
if (percent < 0.0f || percent > 100.0f) if (percent < 0.0f || percent > 100.0f)
{ {
return {false, dshot_msg_code_t::DSHOT_ERROR_PERCENT_NOT_IN_RANGE}; return {false, dshot_msg_code_t::DSHOT_PERCENT_NOT_IN_RANGE};
} }
// Map percent to DShot throttle range // Map percent to DShot throttle range
uint16_t throttle = static_cast<uint16_t>(DSHOT_THROTTLE_MIN + ((DSHOT_THROTTLE_MAX - DSHOT_THROTTLE_MIN) / 100.0f) * percent); uint16_t throttle = static_cast<uint16_t>(DSHOT_THROTTLE_MIN + ((DSHOT_THROTTLE_MAX - DSHOT_THROTTLE_MIN) / 100.0f) * percent);
return sendThrottle(throttle); return sendThrottle(throttle);
} }
// Send DShot command to ESC // Send DShot command to ESC
dshot_result_t DShotRMT::sendCommand(uint16_t command) dshot_result_t DShotRMT::sendCommand(uint16_t command)
{ {
if (command > static_cast<uint16_t>(dshotCommands_e::DSHOT_CMD_MAX)) if (command > dshotCommands_e::DSHOT_CMD_MAX)
{ {
return {false, dshot_msg_code_t::DSHOT_ERROR_COMMAND_NOT_VALID}; return {false, dshot_msg_code_t::DSHOT_COMMAND_NOT_VALID};
} }
_packet = _buildDShotPacket(command); _packet = _buildDShotPacket(command);
@ -168,11 +164,11 @@ dshot_result_t DShotRMT::sendCommand(uint16_t command)
// This is a blocking function that uses delayMicroseconds for repetitions. // This is a blocking function that uses delayMicroseconds for repetitions.
dshot_result_t DShotRMT::sendCommand(dshotCommands_e dshot_command, uint16_t repeat_count, uint16_t delay_us) dshot_result_t DShotRMT::sendCommand(dshotCommands_e dshot_command, uint16_t repeat_count, uint16_t delay_us)
{ {
dshot_result_t result = {false, dshot_msg_code_t::DSHOT_ERROR_UNKNOWN}; dshot_result_t result = {false, dshot_msg_code_t::DSHOT_UNKNOWN, NO_DSHOT_TELEMETRY, NO_DSHOT_TELEMETRY};
if (!_isValidCommand(dshot_command)) if (!_isValidCommand(dshot_command))
{ {
result.error_code = dshot_msg_code_t::DSHOT_ERROR_INVALID_COMMAND; result.result_code = dshot_msg_code_t::DSHOT_INVALID_COMMAND;
return result; return result;
} }
@ -186,7 +182,7 @@ dshot_result_t DShotRMT::sendCommand(dshotCommands_e dshot_command, uint16_t rep
if (!single_result.success) if (!single_result.success)
{ {
all_successful = false; all_successful = false;
result.error_code = single_result.error_code; result.result_code = single_result.result_code;
break; break;
} }
@ -202,7 +198,7 @@ dshot_result_t DShotRMT::sendCommand(dshotCommands_e dshot_command, uint16_t rep
if (result.success) if (result.success)
{ {
result.error_code = dshot_msg_code_t::DSHOT_ERROR_COMMAND_SUCCESS; result.result_code = dshot_msg_code_t::DSHOT_COMMAND_SUCCESS;
} }
return result; return result;
@ -211,11 +207,11 @@ dshot_result_t DShotRMT::sendCommand(dshotCommands_e dshot_command, uint16_t rep
// Get telemetry data // Get telemetry data
dshot_result_t DShotRMT::getTelemetry(uint16_t magnet_count) dshot_result_t DShotRMT::getTelemetry(uint16_t magnet_count)
{ {
dshot_result_t result = {false, dshot_msg_code_t::DSHOT_ERROR_TELEMETRY_FAILED, NO_DSHOT_TELEMETRY, NO_DSHOT_TELEMETRY}; dshot_result_t result = {false, dshot_msg_code_t::DSHOT_TELEMETRY_FAILED, NO_DSHOT_TELEMETRY, NO_DSHOT_TELEMETRY};
if (!_is_bidirectional) if (!_is_bidirectional)
{ {
result.error_code = dshot_msg_code_t::DSHOT_ERROR_BIDIR_NOT_ENABLED; result.result_code = dshot_msg_code_t::DSHOT_BIDIR_NOT_ENABLED;
return result; return result;
} }
@ -237,7 +233,7 @@ dshot_result_t DShotRMT::getTelemetry(uint16_t magnet_count)
result.success = true; result.success = true;
result.erpm = erpm; result.erpm = erpm;
result.motor_rpm = motor_rpm; result.motor_rpm = motor_rpm;
result.error_code = dshot_msg_code_t::DSHOT_ERROR_TELEMETRY_SUCCESS; result.result_code = dshot_msg_code_t::DSHOT_TELEMETRY_SUCCESS;
} }
} }
@ -255,7 +251,7 @@ dshot_result_t DShotRMT::setMotorSpinDirection(bool reversed)
dshot_result_t DShotRMT::getESCInfo() dshot_result_t DShotRMT::getESCInfo()
{ {
return sendCommand(static_cast<uint16_t>(dshotCommands_e::DSHOT_CMD_ESC_INFO)); return sendCommand(dshotCommands_e::DSHOT_CMD_ESC_INFO);
} }
// Use with caution // Use with caution
@ -267,7 +263,7 @@ dshot_result_t DShotRMT::saveESCSettings()
// Simple check // Simple check
bool DShotRMT::_isValidCommand(dshotCommands_e command) bool DShotRMT::_isValidCommand(dshotCommands_e command)
{ {
return (static_cast<uint16_t>(command) >= static_cast<uint16_t>(dshotCommands_e::DSHOT_CMD_MOTOR_STOP) && static_cast<uint16_t>(command) <= static_cast<uint16_t>(dshotCommands_e::DSHOT_CMD_MAX)); return (command >= dshotCommands_e::DSHOT_CMD_MOTOR_STOP && command <= dshotCommands_e::DSHOT_CMD_MAX);
} }
// //
@ -276,7 +272,7 @@ dshot_result_t DShotRMT::_executeCommand(dshotCommands_e command)
uint64_t start_time = esp_timer_get_time(); uint64_t start_time = esp_timer_get_time();
// Execute the command using the DShotRMT instance // Execute the command using the DShotRMT instance
dshot_result_t result = sendCommand(static_cast<uint16_t>(command)); dshot_result_t result = sendCommand(command);
uint64_t end_time = esp_timer_get_time(); uint64_t end_time = esp_timer_get_time();
_last_command_timestamp = end_time; _last_command_timestamp = end_time;
@ -298,14 +294,15 @@ dshot_result_t DShotRMT::_initTXChannel()
if (rmt_new_tx_channel(&_tx_channel_config, &_rmt_tx_channel) != DSHOT_OK) if (rmt_new_tx_channel(&_tx_channel_config, &_rmt_tx_channel) != DSHOT_OK)
{ {
return {false, dshot_msg_code_t::DSHOT_ERROR_TX_INIT_FAILED}; return {false, dshot_msg_code_t::DSHOT_TX_INIT_FAILED};
}
if (rmt_enable(_rmt_tx_channel) != DSHOT_OK)
{
return {false, dshot_msg_code_t::DSHOT_ERROR_TX_INIT_FAILED};
} }
return {true, dshot_msg_code_t::DSHOT_ERROR_TX_INIT_SUCCESS}; if (rmt_enable(_rmt_tx_channel) != DSHOT_OK)
{
return {false, dshot_msg_code_t::DSHOT_TX_INIT_FAILED};
}
return {true, dshot_msg_code_t::DSHOT_TX_INIT_SUCCESS};
} }
dshot_result_t DShotRMT::_initRXChannel() dshot_result_t DShotRMT::_initRXChannel()
@ -313,7 +310,7 @@ dshot_result_t DShotRMT::_initRXChannel()
// Double check if bidirectional mode is enabled // Double check if bidirectional mode is enabled
if (!_is_bidirectional) if (!_is_bidirectional)
{ {
return {true, dshot_msg_code_t::DSHOT_ERROR_NONE}; return {true, dshot_msg_code_t::DSHOT_NONE};
} }
_rx_channel_config.gpio_num = _gpio; _rx_channel_config.gpio_num = _gpio;
@ -322,24 +319,24 @@ dshot_result_t DShotRMT::_initRXChannel()
_rx_channel_config.mem_block_symbols = RMT_BUFFER_SYMBOLS; _rx_channel_config.mem_block_symbols = RMT_BUFFER_SYMBOLS;
// Filter for pulses that are within a reasonable range for DShot telemetry // Filter for pulses that are within a reasonable range for DShot telemetry
_rmt_rx_config.signal_range_min_ns = DSHOT_PULSE_MIN; _rmt_rx_config.signal_range_min_ns = DSHOT_PULSE_MIN_NS;
_rmt_rx_config.signal_range_max_ns = DSHOT_PULSE_MAX; _rmt_rx_config.signal_range_max_ns = DSHOT_PULSE_MAX_NS;
if (rmt_new_rx_channel(&_rx_channel_config, &_rmt_rx_channel) != DSHOT_OK) if (rmt_new_rx_channel(&_rx_channel_config, &_rmt_rx_channel) != DSHOT_OK)
{ {
return {false, dshot_msg_code_t::DSHOT_ERROR_RX_INIT_FAILED}; return {false, dshot_msg_code_t::DSHOT_RX_INIT_FAILED};
} }
// Register the callback function that will be triggered when a frame is received // Register the callback function that will be triggered when a frame is received
_rx_event_callbacks.on_recv_done = _on_rx_done; _rx_event_callbacks.on_recv_done = _on_rx_done;
if (rmt_rx_register_event_callbacks(_rmt_rx_channel, &_rx_event_callbacks, this) != DSHOT_OK) if (rmt_rx_register_event_callbacks(_rmt_rx_channel, &_rx_event_callbacks, this) != DSHOT_OK)
{ {
return {false, dshot_msg_code_t::DSHOT_ERROR_CALLBACK_REGISTERING_FAILED}; return {false, dshot_msg_code_t::DSHOT_CALLBACK_REGISTERING_FAILED};
} }
if (rmt_enable(_rmt_rx_channel) != DSHOT_OK) if (rmt_enable(_rmt_rx_channel) != DSHOT_OK)
{ {
return {false, dshot_msg_code_t::DSHOT_ERROR_RX_INIT_FAILED}; return {false, dshot_msg_code_t::DSHOT_RX_INIT_FAILED};
} }
// Start the receiver to wait for incoming telemetry data // Start the receiver to wait for incoming telemetry data
@ -347,10 +344,10 @@ dshot_result_t DShotRMT::_initRXChannel()
size_t rx_size_bytes = GCR_BITS_PER_FRAME * sizeof(rmt_symbol_word_t); size_t rx_size_bytes = GCR_BITS_PER_FRAME * sizeof(rmt_symbol_word_t);
if (rmt_receive(_rmt_rx_channel, rx_symbols, rx_size_bytes, &_rmt_rx_config) != DSHOT_OK) if (rmt_receive(_rmt_rx_channel, rx_symbols, rx_size_bytes, &_rmt_rx_config) != DSHOT_OK)
{ {
return {false, dshot_msg_code_t::DSHOT_ERROR_RECEIVER_FAILED}; return {false, dshot_msg_code_t::DSHOT_RECEIVER_FAILED};
} }
return {true, dshot_msg_code_t::DSHOT_ERROR_RX_INIT_SUCCESS}; return {true, dshot_msg_code_t::DSHOT_RX_INIT_SUCCESS};
} }
dshot_result_t DShotRMT::_initDShotEncoder() dshot_result_t DShotRMT::_initDShotEncoder()
@ -375,10 +372,10 @@ dshot_result_t DShotRMT::_initDShotEncoder()
if (rmt_new_bytes_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_ENCODER_INIT_FAILED};
} }
return {true, dshot_msg_code_t::DSHOT_ERROR_ENCODER_INIT_SUCCESS}; return {true, dshot_msg_code_t::DSHOT_ENCODER_INIT_SUCCESS};
} }
// Private Packet Management Functions // Private Packet Management Functions
@ -442,7 +439,7 @@ 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 (!_isFrameIntervalElapsed()) if (!_isFrameIntervalElapsed())
{ {
return {true, dshot_msg_code_t::DSHOT_ERROR_NONE}; return {true, dshot_msg_code_t::DSHOT_NONE};
} }
_encoded_frame_value = _buildDShotFrameValue(packet); _encoded_frame_value = _buildDShotFrameValue(packet);
@ -455,12 +452,12 @@ dshot_result_t DShotRMT::_sendDShotFrame(const dshot_packet_t &packet)
if (rmt_transmit(_rmt_tx_channel, _dshot_encoder, &swapped_value, tx_size_bytes, &_rmt_tx_config) != DSHOT_OK) if (rmt_transmit(_rmt_tx_channel, _dshot_encoder, &swapped_value, 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_TRANSMISSION_FAILED};
} }
_recordFrameTransmissionTime(); // 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_TRANSMISSION_SUCCESS};
} }
// This function needs to be fast, as it generates the RMT symbols just before sending // This function needs to be fast, as it generates the RMT symbols just before sending
@ -545,10 +542,25 @@ bool IRAM_ATTR DShotRMT::_on_rx_done(rmt_channel_handle_t rmt_rx_channel, const
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 uint16_t dshot_mode_val = 0;
: dshot_rmt.getMode() == dshot_mode_t::DSHOT1200 ? 1200 switch (dshot_rmt.getMode())
: 0); {
case dshot_mode_t::DSHOT150:
dshot_mode_val = 150;
break;
case dshot_mode_t::DSHOT300:
dshot_mode_val = 300;
break;
case dshot_mode_t::DSHOT600:
dshot_mode_val = 600;
break;
case dshot_mode_t::DSHOT1200:
dshot_mode_val = 1200;
break;
}
output.printf("Current Mode: DSHOT%d\n", dshot_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: ");
@ -568,4 +580,4 @@ void DShotRMT::printCpuInfo(Stream &output)
output.printf("CPU Freq = %lu MHz\n", ESP.getCpuFreqMHz()); output.printf("CPU Freq = %lu MHz\n", ESP.getCpuFreqMHz());
output.printf("XTAL Freq = %lu MHz\n", getXtalFrequencyMhz()); output.printf("XTAL Freq = %lu MHz\n", getXtalFrequencyMhz());
output.printf("APB Freq = %lu Hz\n", getApbFrequency()); output.printf("APB Freq = %lu Hz\n", getApbFrequency());
} }

View File

@ -1,12 +1,12 @@
#pragma once #pragma once
#include <Arduino.h> #include <Arduino.h>
#include <driver/gpio.h> // Added for gpio_num_t #include <driver/gpio.h>
#include <driver/rmt_tx.h> #include <driver/rmt_tx.h>
#include <driver/rmt_rx.h> #include <driver/rmt_rx.h>
#include <atomic> // Added for std::atomic #include <atomic>
// Defines the available DShot communication speeds. // Defines the available DShot communication speeds with type safety.
enum class dshot_mode_t enum class dshot_mode_t
{ {
DSHOT_OFF, DSHOT_OFF,
@ -41,46 +41,46 @@ typedef struct rmt_ticks
uint16_t t0l_ticks; // Low time duration for a '0' bit in RMT ticks. uint16_t t0l_ticks; // Low time duration for a '0' bit in RMT ticks.
} rmt_ticks_t; } rmt_ticks_t;
// Enum class for specific error and success codes returned by DShotRMT functions. // Enum class for specific error and success codes
enum class dshot_msg_code_t enum class dshot_msg_code_t
{ {
DSHOT_ERROR_NONE = 0, DSHOT_NONE = 0,
DSHOT_ERROR_UNKNOWN, DSHOT_UNKNOWN,
DSHOT_ERROR_TX_INIT_FAILED, DSHOT_TX_INIT_FAILED,
DSHOT_ERROR_RX_INIT_FAILED, DSHOT_RX_INIT_FAILED,
DSHOT_ERROR_ENCODER_INIT_FAILED, DSHOT_ENCODER_INIT_FAILED,
DSHOT_ERROR_CALLBACK_REGISTERING_FAILED, DSHOT_CALLBACK_REGISTERING_FAILED,
DSHOT_ERROR_RECEIVER_FAILED, DSHOT_RECEIVER_FAILED,
DSHOT_ERROR_TRANSMISSION_FAILED, DSHOT_TRANSMISSION_FAILED,
DSHOT_ERROR_THROTTLE_NOT_IN_RANGE, DSHOT_THROTTLE_NOT_IN_RANGE,
DSHOT_ERROR_PERCENT_NOT_IN_RANGE, DSHOT_PERCENT_NOT_IN_RANGE,
DSHOT_ERROR_COMMAND_NOT_VALID, DSHOT_COMMAND_NOT_VALID,
DSHOT_ERROR_BIDIR_NOT_ENABLED, DSHOT_BIDIR_NOT_ENABLED,
DSHOT_ERROR_TELEMETRY_FAILED, DSHOT_TELEMETRY_FAILED,
DSHOT_ERROR_INVALID_MAGNET_COUNT, DSHOT_INVALID_MAGNET_COUNT,
DSHOT_ERROR_INVALID_COMMAND, DSHOT_INVALID_COMMAND,
DSHOT_ERROR_TIMING_CORRECTION, DSHOT_TIMING_CORRECTION,
DSHOT_ERROR_INIT_FAILED, DSHOT_INIT_FAILED,
DSHOT_ERROR_INIT_SUCCESS, DSHOT_INIT_SUCCESS,
DSHOT_ERROR_TX_INIT_SUCCESS, DSHOT_TX_INIT_SUCCESS,
DSHOT_ERROR_RX_INIT_SUCCESS, DSHOT_RX_INIT_SUCCESS,
DSHOT_ERROR_ENCODER_INIT_SUCCESS, DSHOT_ENCODER_INIT_SUCCESS,
DSHOT_ERROR_ENCODING_SUCCESS, DSHOT_ENCODING_SUCCESS,
DSHOT_ERROR_TRANSMISSION_SUCCESS, DSHOT_TRANSMISSION_SUCCESS,
DSHOT_ERROR_TELEMETRY_SUCCESS, DSHOT_TELEMETRY_SUCCESS,
DSHOT_ERROR_COMMAND_SUCCESS DSHOT_COMMAND_SUCCESS
}; };
// Contains the success status, an error code, and optional telemetry data. // Contains the success status, an error code, and optional telemetry data.
typedef struct dshot_result typedef struct dshot_result
{ {
bool success; bool success;
dshot_msg_code_t error_code; // Specific error or success code. dshot_msg_code_t result_code; // Specific error or success code.
uint16_t erpm; // Electrical RPM (eRPM) if telemetry is successful. uint16_t erpm; // Electrical RPM (eRPM) if telemetry is successful.
uint16_t motor_rpm; // Motor RPM if telemetry is successful and magnet count is known. uint16_t motor_rpm; // Motor RPM if telemetry is successful and magnet count is known.
} dshot_result_t; } dshot_result_t;
// Enum class for standard DShot commands that can be sent to an ESC. // Standard DShot commands by "betaflight"
enum dshotCommands_e enum dshotCommands_e
{ {
DSHOT_CMD_MOTOR_STOP = 0, DSHOT_CMD_MOTOR_STOP = 0,
@ -89,194 +89,168 @@ enum dshotCommands_e
DSHOT_CMD_BEACON3, DSHOT_CMD_BEACON3,
DSHOT_CMD_BEACON4, DSHOT_CMD_BEACON4,
DSHOT_CMD_BEACON5, DSHOT_CMD_BEACON5,
DSHOT_CMD_ESC_INFO, // V2 includes settings DSHOT_CMD_ESC_INFO,
DSHOT_CMD_SPIN_DIRECTION_1, DSHOT_CMD_SPIN_DIRECTION_1,
DSHOT_CMD_SPIN_DIRECTION_2, DSHOT_CMD_SPIN_DIRECTION_2,
DSHOT_CMD_3D_MODE_OFF, DSHOT_CMD_3D_MODE_OFF,
DSHOT_CMD_3D_MODE_ON, DSHOT_CMD_3D_MODE_ON,
DSHOT_CMD_SETTINGS_REQUEST, // Currently not implemented DSHOT_CMD_SETTINGS_REQUEST,
DSHOT_CMD_SAVE_SETTINGS, DSHOT_CMD_SAVE_SETTINGS,
DSHOT_CMD_EXTENDED_TELEMETRY_ENABLE, DSHOT_CMD_EXTENDED_TELEMETRY_ENABLE,
DSHOT_CMD_EXTENDED_TELEMETRY_DISABLE, DSHOT_CMD_EXTENDED_TELEMETRY_DISABLE,
DSHOT_CMD_SPIN_DIRECTION_NORMAL = 20, DSHOT_CMD_SPIN_DIRECTION_NORMAL = 20,
DSHOT_CMD_SPIN_DIRECTION_REVERSED = 21, DSHOT_CMD_SPIN_DIRECTION_REVERSED = 21,
DSHOT_CMD_LED0_ON, // BLHeli32 only DSHOT_CMD_LED0_ON,
DSHOT_CMD_LED1_ON, // BLHeli32 only DSHOT_CMD_LED1_ON,
DSHOT_CMD_LED2_ON, // BLHeli32 only DSHOT_CMD_LED2_ON,
DSHOT_CMD_LED3_ON, // BLHeli32 only DSHOT_CMD_LED3_ON,
DSHOT_CMD_LED0_OFF, // BLHeli32 only DSHOT_CMD_LED0_OFF,
DSHOT_CMD_LED1_OFF, // BLHeli32 only DSHOT_CMD_LED1_OFF,
DSHOT_CMD_LED2_OFF, // BLHeli32 only DSHOT_CMD_LED2_OFF,
DSHOT_CMD_LED3_OFF, // BLHeli32 only DSHOT_CMD_LED3_OFF,
DSHOT_CMD_AUDIO_STREAM_MODE_ON_OFF = 30, // KISS audio Stream mode on/Off DSHOT_CMD_AUDIO_STREAM_MODE_ON_OFF = 30,
DSHOT_CMD_SILENT_MODE_ON_OFF = 31, // KISS silent Mode on/Off DSHOT_CMD_SILENT_MODE_ON_OFF = 31,
DSHOT_CMD_MAX = 47 DSHOT_CMD_MAX = 47
}; };
// Defines how DShot commands are sent.
enum class dshotCommandType_e
{
DSHOT_CMD_TYPE_INLINE = 0, // Commands sent inline with motor signal (motors must be enabled).
DSHOT_CMD_TYPE_BLOCKING // Commands sent in blocking method (motors must be disabled).
};
// DShot Protocol Constants // DShot Protocol Constants
const uint16_t DSHOT_THROTTLE_FAILSAFE = 0; static constexpr auto DSHOT_THROTTLE_FAILSAFE = 0;
const uint16_t DSHOT_THROTTLE_MIN = 48; static constexpr auto DSHOT_THROTTLE_MIN = 48;
const uint16_t DSHOT_THROTTLE_MAX = 2047; static constexpr auto DSHOT_THROTTLE_MAX = 2047;
const uint16_t DSHOT_BITS_PER_FRAME = 16; static constexpr auto DSHOT_BITS_PER_FRAME = 16;
const uint16_t DEFAULT_MOTOR_MAGNET_COUNT = 14; static constexpr auto DEFAULT_MOTOR_MAGNET_COUNT = 14;
// Custom status codes // Custom status codes
const int DSHOT_OK = 0; static constexpr int DSHOT_OK = 0;
const int DSHOT_ERROR = 1; static constexpr int DSHOT_ERROR = 1;
// Configuration Constants (from DShotRMT.h private section) // Configuration Constants
const uint16_t DSHOT_NULL_PACKET = 0b0000000000000000; static constexpr auto DSHOT_NULL_PACKET = 0b0000000000000000;
const uint16_t DSHOT_FULL_PACKET = 0b1111111111111111; static constexpr auto DSHOT_FULL_PACKET = 0b1111111111111111;
const uint16_t DSHOT_CRC_MASK = 0b0000000000001111; static constexpr auto DSHOT_CRC_MASK = 0b0000000000001111;
const rmt_clock_source_t DSHOT_CLOCK_SRC_DEFAULT = RMT_CLK_SRC_DEFAULT; static constexpr auto DSHOT_CLOCK_SRC_DEFAULT = RMT_CLK_SRC_DEFAULT;
const uint32_t DSHOT_RMT_RESOLUTION = 8 * 1000 * 1000; // 8 MHz resolution static constexpr auto DSHOT_RMT_RESOLUTION = 8000000; // 8 MHz resolution
const uint16_t RMT_TICKS_PER_US = DSHOT_RMT_RESOLUTION / (1 * 1000 * 1000); // RMT Ticks per microsecond static constexpr auto RMT_TICKS_PER_US = DSHOT_RMT_RESOLUTION / 1000000; // RMT Ticks per microsecond
const uint16_t DSHOT_RX_TIMEOUT_MS = 2; static constexpr auto DSHOT_RX_TIMEOUT_MS = 2;
const uint16_t DSHOT_PADDING_US = 20; // Add to pause between frames for compatibility static constexpr auto DSHOT_PADDING_US = 20; // Pause between frames
const uint16_t RMT_BUFFER_SYMBOLS = 64; static constexpr auto RMT_BUFFER_SYMBOLS = 64;
const uint16_t RMT_QUEUE_DEPTH = 1; static constexpr auto RMT_QUEUE_DEPTH = 1;
const uint16_t GCR_BITS_PER_FRAME = 21; // Number of GCR bits in a DShot answer frame static constexpr auto GCR_BITS_PER_FRAME = 21; // GCR bits in a DShot answer frame
const uint16_t POLE_PAIRS_MIN = 1; static constexpr auto POLE_PAIRS_MIN = 1;
const uint16_t MAGNETS_PER_POLE_PAIR = 2; static constexpr auto MAGNETS_PER_POLE_PAIR = 2;
const uint16_t NO_DSHOT_TELEMETRY = 0; static constexpr auto NO_DSHOT_TELEMETRY = 0;
const uint16_t DSHOT_PULSE_MIN = 800; // 0.8us minimum pulse static constexpr auto DSHOT_PULSE_MIN_NS = 800; // 0.8us minimum pulse
const uint16_t DSHOT_PULSE_MAX = 8000; // 8.0us maximum pulse static constexpr auto DSHOT_PULSE_MAX_NS = 8000; // 8.0us maximum pulse
const uint16_t DSHOT_TELEMETRY_INVALID = DSHOT_THROTTLE_MAX; static constexpr auto DSHOT_TELEMETRY_INVALID = DSHOT_THROTTLE_MAX;
const uint16_t DSHOT_TELEMETRY_BIT_POSITION = 11; // Bit position of the telemetry request flag in the DShot frame static constexpr auto DSHOT_TELEMETRY_BIT_POSITION = 11;
const uint16_t DSHOT_CRC_BIT_SHIFT = 4; // Number of bits to shift to extract data from data_and_crc static constexpr auto DSHOT_CRC_BIT_SHIFT = 4;
// Command Constants (from DShotRMT.h private section) // Command Constants
const uint16_t DEFAULT_CMD_DELAY_US = 10; static constexpr auto DEFAULT_CMD_DELAY_US = 10;
const uint16_t DEFAULT_CMD_REPEAT_COUNT = 1; static constexpr auto DEFAULT_CMD_REPEAT_COUNT = 1;
const uint16_t SETTINGS_COMMAND_REPEATS = 10; // Settings commands need 10 repeats static constexpr auto SETTINGS_COMMAND_REPEATS = 10;
const uint16_t SETTINGS_COMMAND_DELAY_US = 5; static constexpr auto SETTINGS_COMMAND_DELAY_US = 5;
// Timing parameters for each DShot mode // Timing parameters for each DShot mode
// Format: {bit_length_us, t1h_length_us}
const dshot_timing_us_t DSHOT_TIMING_US[] = { const dshot_timing_us_t DSHOT_TIMING_US[] = {
{0.00, 0.00}, // DSHOT_OFF {0.00, 0.00}, // DSHOT_OFF
{6.67, 5.00}, // DSHOT150 {6.67, 5.00}, // DSHOT150
{3.33, 2.50}, // DSHOT300 {3.33, 2.50}, // DSHOT300
{1.67, 1.25}, // DSHOT600 {1.67, 1.25}, // DSHOT600
{0.83, 0.67}}; // DSHOT1200 {0.83, 0.67} // DSHOT1200
};
// Error Messages // Error Messages
const char *const NONE = ""; static constexpr char NONE[] = "";
const char *const UNKNOWN_ERROR = "Unknown Error!"; static constexpr char UNKNOWN_ERROR[] = "Unknown Error!";
const char *const INIT_SUCCESS = "SignalGeneratorRMT initialized successfully"; static constexpr char INIT_SUCCESS[] = "SignalGeneratorRMT initialized successfully";
const char *const INIT_FAILED = "SignalGeneratorRMT init failed!"; static constexpr char INIT_FAILED[] = "SignalGeneratorRMT init failed!";
const char *const TX_INIT_SUCCESS = "TX RMT channel initialized successfully"; static constexpr char TX_INIT_SUCCESS[] = "TX RMT channel initialized successfully";
const char *const TX_INIT_FAILED = "TX RMT channel init failed!"; static constexpr char TX_INIT_FAILED[] = "TX RMT channel init failed!";
const char *const RX_INIT_SUCCESS = "RX RMT channel initialized successfully"; static constexpr char RX_INIT_SUCCESS[] = "RX RMT channel initialized successfully";
const char *const RX_INIT_FAILED = "RX RMT channel init failed!"; static constexpr char RX_INIT_FAILED[] = "RX RMT channel init failed!";
const char *const ENCODER_INIT_SUCCESS = "RMT encoder initialized successfully"; static constexpr char ENCODER_INIT_SUCCESS[] = "RMT encoder initialized successfully";
const char *const ENCODER_INIT_FAILED = "RMT encoder init failed!"; static constexpr char ENCODER_INIT_FAILED[] = "RMT encoder init failed!";
const char *const ENCODING_SUCCESS = "Packet encoded successfully"; static constexpr char ENCODING_SUCCESS[] = "Packet encoded successfully";
const char *const TRANSMISSION_SUCCESS = "Transmission successfully"; static constexpr char TRANSMISSION_SUCCESS[] = "Transmission successfully";
const char *const TRANSMISSION_FAILED = "Transmission failed!"; static constexpr char TRANSMISSION_FAILED[] = "Transmission failed!";
const char *const RECEIVER_FAILED = "RMT receiver failed!"; static constexpr char RECEIVER_FAILED[] = "RMT receiver failed!";
const char *const THROTTLE_NOT_IN_RANGE = "Throttle not in range! (48 - 2047)"; static constexpr char THROTTLE_NOT_IN_RANGE[] = "Throttle not in range! (48 - 2047)";
const char *const PERCENT_NOT_IN_RANGE = "Percent not in range! (0.0 - 100.0)"; static constexpr char PERCENT_NOT_IN_RANGE[] = "Percent not in range! (0.0 - 100.0)";
const char *const COMMAND_NOT_VALID = "Command not valid! (0 - 47)"; static constexpr char COMMAND_NOT_VALID[] = "Command not valid! (0 - 47)";
const char *const BIDIR_NOT_ENABLED = "Bidirectional DShot not enabled!"; static constexpr char BIDIR_NOT_ENABLED[] = "Bidirectional DShot not enabled!";
const char *const TELEMETRY_SUCCESS = "Valid Telemetric Frame received!"; static constexpr char TELEMETRY_SUCCESS[] = "Valid Telemetric Frame received!";
const char *const TELEMETRY_FAILED = "No valid Telemetric Frame received!"; static constexpr char TELEMETRY_FAILED[] = "No valid Telemetric Frame received!";
const char *const INVALID_MAGNET_COUNT = "Invalid motor magnet count!"; static constexpr char INVALID_MAGNET_COUNT[] = "Invalid motor magnet count!";
const char *const TIMING_CORRECTION = "Timing correction!"; static constexpr char TIMING_CORRECTION[] = "Timing correction!";
const char *const CALLBACK_REGISTERING_FAILED = "RMT RX Callback registering failed!"; static constexpr char CALLBACK_REGISTERING_FAILED[] = "RMT RX Callback registering failed!";
const char *const INVALID_COMMAND = "Invalid command!"; static constexpr char INVALID_COMMAND[] = "Invalid command!";
const char *const COMMAND_SUCCESS = "DShot command sent successfully"; static constexpr char COMMAND_SUCCESS[] = "DShot command sent successfully";
// Helper Functions // Helper to get result code string
inline const char *_get_result_code_str(dshot_msg_code_t code)
{
switch (code)
{
case dshot_msg_code_t::DSHOT_NONE:
return NONE;
case dshot_msg_code_t::DSHOT_UNKNOWN:
return UNKNOWN_ERROR;
case dshot_msg_code_t::DSHOT_TX_INIT_FAILED:
return TX_INIT_FAILED;
case dshot_msg_code_t::DSHOT_RX_INIT_FAILED:
return RX_INIT_FAILED;
case dshot_msg_code_t::DSHOT_ENCODER_INIT_FAILED:
return ENCODER_INIT_FAILED;
case dshot_msg_code_t::DSHOT_CALLBACK_REGISTERING_FAILED:
return CALLBACK_REGISTERING_FAILED;
case dshot_msg_code_t::DSHOT_RECEIVER_FAILED:
return RECEIVER_FAILED;
case dshot_msg_code_t::DSHOT_TRANSMISSION_FAILED:
return TRANSMISSION_FAILED;
case dshot_msg_code_t::DSHOT_THROTTLE_NOT_IN_RANGE:
return THROTTLE_NOT_IN_RANGE;
case dshot_msg_code_t::DSHOT_PERCENT_NOT_IN_RANGE:
return PERCENT_NOT_IN_RANGE;
case dshot_msg_code_t::DSHOT_COMMAND_NOT_VALID:
return COMMAND_NOT_VALID;
case dshot_msg_code_t::DSHOT_BIDIR_NOT_ENABLED:
return BIDIR_NOT_ENABLED;
case dshot_msg_code_t::DSHOT_TELEMETRY_FAILED:
return TELEMETRY_FAILED;
case dshot_msg_code_t::DSHOT_INVALID_MAGNET_COUNT:
return INVALID_MAGNET_COUNT;
case dshot_msg_code_t::DSHOT_INVALID_COMMAND:
return INVALID_COMMAND;
case dshot_msg_code_t::DSHOT_TIMING_CORRECTION:
return TIMING_CORRECTION;
case dshot_msg_code_t::DSHOT_INIT_FAILED:
return INIT_FAILED;
case dshot_msg_code_t::DSHOT_INIT_SUCCESS:
return INIT_SUCCESS;
case dshot_msg_code_t::DSHOT_TX_INIT_SUCCESS:
return TX_INIT_SUCCESS;
case dshot_msg_code_t::DSHOT_RX_INIT_SUCCESS:
return RX_INIT_SUCCESS;
case dshot_msg_code_t::DSHOT_ENCODER_INIT_SUCCESS:
return ENCODER_INIT_SUCCESS;
case dshot_msg_code_t::DSHOT_ENCODING_SUCCESS:
return ENCODING_SUCCESS;
case dshot_msg_code_t::DSHOT_TRANSMISSION_SUCCESS:
return TRANSMISSION_SUCCESS;
case dshot_msg_code_t::DSHOT_TELEMETRY_SUCCESS:
return TELEMETRY_SUCCESS;
case dshot_msg_code_t::DSHOT_COMMAND_SUCCESS:
return COMMAND_SUCCESS;
default:
return UNKNOWN_ERROR;
}
}
// Helper to quick print DShot result codes
inline void printDShotResult(dshot_result_t &result, Stream &output = Serial) inline void printDShotResult(dshot_result_t &result, Stream &output = Serial)
{ {
const char *msg_str; output.printf("Status: %s - %s", result.success ? "SUCCESS" : "FAILED", _get_result_code_str(result.result_code));
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 // Print telemetry data if available
if (result.success && (result.erpm > 0 || result.motor_rpm > 0)) if (result.success && (result.erpm > 0 || result.motor_rpm > 0))
@ -285,4 +259,4 @@ inline void printDShotResult(dshot_result_t &result, Stream &output = Serial)
} }
output.println(); output.println();
} }