From 29c851d4e213a4ba9ffee5756bf2658af299c62c Mon Sep 17 00:00:00 2001 From: Wastl Kraus Date: Fri, 5 Sep 2025 12:16:19 +0200 Subject: [PATCH 1/2] ...update result codes --- DShotCommandManager.cpp | 112 +++----- DShotCommandManager.h | 64 ++--- DShotRMT.cpp | 125 ++++++--- DShotRMT.h | 74 ++++- examples/command_manager/command_manager.ino | 279 +++++++++++-------- examples/dshot300/dshot300.ino | 153 ++++++++-- 6 files changed, 505 insertions(+), 302 deletions(-) diff --git a/DShotCommandManager.cpp b/DShotCommandManager.cpp index 7ec6f0c..9391640 100644 --- a/DShotCommandManager.cpp +++ b/DShotCommandManager.cpp @@ -13,43 +13,42 @@ DShotCommandManager::DShotCommandManager(DShotRMT &dshot_instance) : _dshot(dshot_instance), _total_commands_sent(0), _failed_commands(0), - _last_execution_time_us(0), _last_command_timestamp(0) { } // Init command manager -bool DShotCommandManager::begin() +dshot_result_t DShotCommandManager::begin() { - resetStatistics(); - return true; + dshot_result_t result; + result.success = true; + result.error_message = "Success"; + return result; } // --- BASIC COMMAND METHODS --- -dshot_command_result_t DShotCommandManager::sendCommand(dshot_commands_t command, uint16_t repeat_count) +dshot_result_t DShotCommandManager::sendCommand(dshot_commands_t command, uint16_t repeat_count) { return sendCommandWithDelay(command, repeat_count, DEFAULT_COMMAND_DELAY_MS); } // -dshot_command_result_t DShotCommandManager::sendCommandWithDelay(dshot_commands_t command, uint16_t repeat_count, uint32_t delay_ms) +dshot_result_t DShotCommandManager::sendCommandWithDelay(dshot_commands_t command, uint16_t repeat_count, uint32_t delay_ms) { - dshot_command_result_t result = {false, 0, "Unknown error"}; - + dshot_result_t result = {false, "Unknown error"}; + if (!isValidCommand(command)) { result.error_message = "Invalid command"; - _updateStatistics(false, 0); return result; } - uint64_t start_time = esp_timer_get_time(); bool all_successful = true; // Send command multiple times with delay for (uint16_t i = 0; i < repeat_count; i++) { - dshot_command_result_t single_result = _executeCommand(command); + dshot_result_t single_result = _executeCommand(command); if (!single_result.success) { @@ -61,12 +60,11 @@ dshot_command_result_t DShotCommandManager::sendCommandWithDelay(dshot_commands_ // Add delay between repetitions (except for last repetition) if (i < repeat_count - 1) { - _delay(delay_ms); + _delay_ms(delay_ms); } } - uint64_t end_time = esp_timer_get_time(); - result.execution_time_us = (uint32_t)(end_time - start_time); + // result.success = all_successful; if (result.success) @@ -74,57 +72,54 @@ dshot_command_result_t DShotCommandManager::sendCommandWithDelay(dshot_commands_ result.error_message = "Success"; } - _updateStatistics(result.success, result.execution_time_us); - return result; } // --- MOTOR CONTROL COMMANDS --- -dshot_command_result_t DShotCommandManager::stopMotor() +dshot_result_t DShotCommandManager::stopMotor() { return sendCommand(DSHOT_CMD_MOTOR_STOP); } // -dshot_command_result_t DShotCommandManager::set3DMode(bool enable) +dshot_result_t DShotCommandManager::set3DMode(bool enable) { dshot_commands_t command = enable ? DSHOT_CMD_3D_MODE_ON : DSHOT_CMD_3D_MODE_OFF; return sendCommandWithDelay(command, SETTINGS_COMMAND_REPEATS, SETTINGS_COMMAND_DELAY_MS); } // -dshot_command_result_t DShotCommandManager::setSpinDirection(bool reversed) +dshot_result_t DShotCommandManager::setSpinDirection(bool reversed) { dshot_commands_t command = reversed ? DSHOT_CMD_SPIN_DIRECTION_REVERSED : DSHOT_CMD_SPIN_DIRECTION_NORMAL; return sendCommandWithDelay(command, SETTINGS_COMMAND_REPEATS, SETTINGS_COMMAND_DELAY_MS); } // -dshot_command_result_t DShotCommandManager::saveSettings() +dshot_result_t DShotCommandManager::saveSettings() { return sendCommandWithDelay(DSHOT_CMD_SAVE_SETTINGS, SETTINGS_COMMAND_REPEATS, SETTINGS_COMMAND_DELAY_MS); } // --- TELEMETRY COMMANDS --- -dshot_command_result_t DShotCommandManager::setExtendedTelemetry(bool enable) +dshot_result_t DShotCommandManager::setExtendedTelemetry(bool enable) { dshot_commands_t command = enable ? DSHOT_CMD_EXTENDED_TELEMETRY_ENABLE : DSHOT_CMD_EXTENDED_TELEMETRY_DISABLE; return sendCommand(command); } // -dshot_command_result_t DShotCommandManager::requestESCInfo() +dshot_result_t DShotCommandManager::requestESCInfo() { return sendCommand(DSHOT_CMD_ESC_INFO); } // --- LED CONTROL COMMANDS --- -dshot_command_result_t DShotCommandManager::setLED(uint8_t led_number, bool state) +dshot_result_t DShotCommandManager::setLED(uint8_t led_number, bool state) { if (led_number > 3) { - dshot_command_result_t result = {false, 0, "Invalid LED number (0-3)"}; - _updateStatistics(false, 0); + dshot_result_t result = {false, "Invalid LED number (0-3)"}; return result; } @@ -172,12 +167,11 @@ dshot_command_result_t DShotCommandManager::setLED(uint8_t led_number, bool stat } // --- BEACON COMMANDS --- -dshot_command_result_t DShotCommandManager::activateBeacon(uint8_t beacon_number) +dshot_result_t DShotCommandManager::activateBeacon(uint8_t beacon_number) { if (beacon_number < 1 || beacon_number > 5) { - dshot_command_result_t result = {false, 0, "Invalid beacon number (1-5)"}; - _updateStatistics(false, 0); + dshot_result_t result = {false, "Invalid beacon number (1-5)"}; return result; } @@ -186,28 +180,28 @@ dshot_command_result_t DShotCommandManager::activateBeacon(uint8_t beacon_number } // --- KISS ESC SPECIFIC COMMANDS --- -dshot_command_result_t DShotCommandManager::setAudioStreamMode(bool enable) +dshot_result_t DShotCommandManager::setAudioStreamMode(bool enable) { // KISS audio stream mode is a toggle command return sendCommand(DSHOT_CMD_AUDIO_STREAM_MODE_ON_OFF); } // -dshot_command_result_t DShotCommandManager::setSilentMode(bool enable) +dshot_result_t DShotCommandManager::setSilentMode(bool enable) { // KISS silent mode is a toggle command return sendCommand(DSHOT_CMD_SILENT_MODE_ON_OFF); } // --- SEQUENCE COMMANDS --- -dshot_command_result_t DShotCommandManager::executeSequence(const dshot_command_sequence_item_t *sequence, size_t sequence_length) +dshot_result_t DShotCommandManager::executeSequence(const dshot_command_sequence_item_t *sequence, size_t sequence_length) { - dshot_command_result_t result = {true, 0, "Success"}; + dshot_result_t result = {true, "Success"}; uint64_t total_start_time = esp_timer_get_time(); for (size_t i = 0; i < sequence_length; i++) { - dshot_command_result_t item_result = sendCommandWithDelay( + dshot_result_t item_result = sendCommandWithDelay( sequence[i].command, sequence[i].repeat_count, DEFAULT_COMMAND_DELAY_MS); @@ -222,18 +216,17 @@ dshot_command_result_t DShotCommandManager::executeSequence(const dshot_command_ // Add delay after command if specified if (sequence[i].delay_ms > 0) { - _delay(sequence[i].delay_ms); + _delay_ms(sequence[i].delay_ms); } } uint64_t total_end_time = esp_timer_get_time(); - result.execution_time_us = (uint32_t)(total_end_time - total_start_time); return result; } // -dshot_command_result_t DShotCommandManager::executeInitSequence() +dshot_result_t DShotCommandManager::executeInitSequence() { // Basic ESC initialization sequence dshot_command_sequence_item_t init_sequence[] = { @@ -246,7 +239,7 @@ dshot_command_result_t DShotCommandManager::executeInitSequence() } // -dshot_command_result_t DShotCommandManager::executeCalibrationSequence() +dshot_result_t DShotCommandManager::executeCalibrationSequence() { // Basic ESC calibration sequence dshot_command_sequence_item_t calibration_sequence[] = { @@ -330,64 +323,25 @@ bool DShotCommandManager::isValidCommand(dshot_commands_t command) return (command >= DSHOT_CMD_MOTOR_STOP && command <= DSHOT_CMD_MAX); } -// -void DShotCommandManager::printStatistics(Stream &output) const -{ - output.println("\n--- DShot Command Manager Statistics ---"); - output.printf("Total commands sent: %u\n", _total_commands_sent); - output.printf("Failed commands: %u\n", _failed_commands); - output.printf("Success rate: %.2f%%\n", - _total_commands_sent > 0 ? (float)(_total_commands_sent - _failed_commands) / _total_commands_sent * 100.0f : 0.0f); - output.printf("Last execution time: %u us\n", _last_execution_time_us); - output.printf("Last command timestamp: %llu us\n", _last_command_timestamp); -} - -// -void DShotCommandManager::resetStatistics() -{ - _total_commands_sent = 0; - _failed_commands = 0; - _last_execution_time_us = 0; - _last_command_timestamp = 0; -} - // --- PRIVATE METHODS --- -dshot_command_result_t DShotCommandManager::_executeCommand(dshot_commands_t command) +dshot_result_t DShotCommandManager::_executeCommand(dshot_commands_t command) { - dshot_command_result_t result = {false, 0, "Execution failed"}; - uint64_t start_time = esp_timer_get_time(); // Execute the command using the DShotRMT instance - bool success = _dshot.sendCommand(static_cast(command)); + dshot_result_t result = _dshot.sendCommand(static_cast(command)); uint64_t end_time = esp_timer_get_time(); - - result.success = success; - result.execution_time_us = (uint32_t)(end_time - start_time); - result.error_message = success ? "Success" : "Command transmission failed"; - _last_command_timestamp = end_time; return result; } // -void DShotCommandManager::_delay(uint32_t delay_ms) +void DShotCommandManager::_delay_ms(uint32_t delay_ms) { if (delay_ms > 0) { delay(delay_ms); } } - -// -void DShotCommandManager::_updateStatistics(bool success, uint32_t execution_time_us) -{ - _total_commands_sent++; - if (!success) - { - _failed_commands++; - } - _last_execution_time_us = execution_time_us; -} diff --git a/DShotCommandManager.h b/DShotCommandManager.h index ccb2f05..aa47ff1 100644 --- a/DShotCommandManager.h +++ b/DShotCommandManager.h @@ -12,17 +12,6 @@ #include #include -// Naming convention -typedef dshotCommands_e dshot_commands_t; - -// Command execution result structure -typedef struct -{ - bool success; - uint32_t execution_time_us; - const char *error_message; -} dshot_command_result_t; - // Command sequence item typedef struct { @@ -39,63 +28,61 @@ public: explicit DShotCommandManager(DShotRMT &dshot_instance); // Initialize command manager - bool begin(); - - bool printMenu(Stream &output); + dshot_result_t begin(); void handleMenuInput(const String &input, Stream &output = Serial); // Send a single DShot command - dshot_command_result_t sendCommand(dshot_commands_t command, uint16_t repeat_count = 1); + dshot_result_t sendCommand(dshot_commands_t command, uint16_t repeat_count = 1); // Send command with specified delay between repetitions - dshot_command_result_t sendCommandWithDelay(dshot_commands_t command, uint16_t repeat_count, uint32_t delay_ms); + dshot_result_t sendCommandWithDelay(dshot_commands_t command, uint16_t repeat_count, uint32_t delay_ms); // --- MOTOR CONTROL COMMANDS --- // Stop motor (send MOTOR_STOP command) - dshot_command_result_t stopMotor(); + dshot_result_t stopMotor(); // Enable/disable 3D mode - dshot_command_result_t set3DMode(bool enable); + dshot_result_t set3DMode(bool enable); // Set motor spin direction - dshot_command_result_t setSpinDirection(bool reversed); + dshot_result_t setSpinDirection(bool reversed); // Save current settings to ESC - dshot_command_result_t saveSettings(); + dshot_result_t saveSettings(); // --- TELEMETRY COMMANDS --- // Enable/disable extended telemetry - dshot_command_result_t setExtendedTelemetry(bool enable); + dshot_result_t setExtendedTelemetry(bool enable); // Request ESC information - dshot_command_result_t requestESCInfo(); + dshot_result_t requestESCInfo(); // --- LED CONTROL COMMANDS (BLHeli32 only) --- // Control ESC LEDs (BLHeli32 only) - dshot_command_result_t setLED(uint8_t led_number, bool state); + dshot_result_t setLED(uint8_t led_number, bool state); // --- BEACON COMMANDS --- // Activate beacon (motor beeping) - dshot_command_result_t activateBeacon(uint8_t beacon_number); + dshot_result_t activateBeacon(uint8_t beacon_number); // --- KISS ESC SPECIFIC COMMANDS --- // Enable/disable audio stream mode (KISS ESCs) - dshot_command_result_t setAudioStreamMode(bool enable); + dshot_result_t setAudioStreamMode(bool enable); // Enable/disable silent mode (KISS ESCs) - dshot_command_result_t setSilentMode(bool enable); + dshot_result_t setSilentMode(bool enable); // --- SEQUENCE COMMANDS --- // Execute a sequence of DShot commands - dshot_command_result_t executeSequence(const dshot_command_sequence_item_t *sequence, size_t sequence_length); + dshot_result_t executeSequence(const dshot_command_sequence_item_t *sequence, size_t sequence_length); // Execute ESC initialization sequence - dshot_command_result_t executeInitSequence(); + dshot_result_t executeInitSequence(); // Execute ESC calibration sequence - dshot_command_result_t executeCalibrationSequence(); + dshot_result_t executeCalibrationSequence(); // --- UTILITY METHODS --- // Get command name as string @@ -104,12 +91,6 @@ public: // Check if command is valid static bool isValidCommand(dshot_commands_t command); - // Print command execution statistics - void printStatistics(Stream &output = Serial) const; - - // Reset execution statistics - void resetStatistics(); - // --- GETTERS --- // Get total number of commands sent uint32_t getTotalCommandCount() const { return _total_commands_sent; } @@ -117,26 +98,23 @@ public: // Get number of failed commands uint32_t getFailedCommandCount() const { return _failed_commands; } - // Get last command execution time - uint32_t getLastExecutionTime() const { return _last_execution_time_us; } + // Get reference to underlying DShotRMT instance + DShotRMT &getDShotRMT() { return _dshot; } + const DShotRMT &getDShotRMT() const { return _dshot; } private: // --- PRIVATE MEMBERS --- DShotRMT &_dshot; // Reference to DShotRMT instance uint32_t _total_commands_sent; // Total commands sent counter uint32_t _failed_commands; // Failed commands counter - uint32_t _last_execution_time_us; // Last command execution time uint64_t _last_command_timestamp; // Timestamp of last command // --- PRIVATE METHODS --- // Execute single command with timing - dshot_command_result_t _executeCommand(dshot_commands_t command); + dshot_result_t _executeCommand(dshot_commands_t command); // Wait for specified delay - void _delay(uint32_t delay_ms); - - // Update execution statistics - void _updateStatistics(bool success, uint32_t execution_time_us); + void _delay_ms(uint32_t delay_ms); // --- CONSTANTS --- static constexpr uint32_t DEFAULT_COMMAND_DELAY_MS = 10; diff --git a/DShotRMT.cpp b/DShotRMT.cpp index 597130f..823e67e 100644 --- a/DShotRMT.cpp +++ b/DShotRMT.cpp @@ -29,6 +29,8 @@ DShotRMT::DShotRMT(gpio_num_t gpio, dshot_mode_t mode, bool is_bidirectional) _last_erpm(0), _parsed_packet(0), _packet{0}, + _total_transmissions(0), + _failed_transmissions(0), _rmt_tx_channel(nullptr), _rmt_rx_channel(nullptr), _dshot_encoder(nullptr), @@ -90,33 +92,43 @@ DShotRMT::~DShotRMT() } // Initialize DShotRMT -uint16_t DShotRMT::begin() +dshot_result_t DShotRMT::begin() { + dshot_result_t result = {false, UNKNOWN_ERROR}; + uint64_t start_time = esp_timer_get_time(); + // Init RX channel first if (_is_bidirectional) { if (!_initRXChannel()) { + result.error_message = RX_INIT_FAILED; _dshot_log(RX_INIT_FAILED); - return DSHOT_ERROR; + return result; } } // Init TX channel if (!_initTXChannel()) { + result.error_message = TX_INIT_FAILED; _dshot_log(TX_INIT_FAILED); - return DSHOT_ERROR; + return result; } // Init DShot encoder if (_initDShotEncoder() != DSHOT_OK) { + result.error_message = ENCODER_INIT_FAILED; _dshot_log(ENCODER_INIT_FAILED); - return DSHOT_ERROR; + return result; } - return DSHOT_OK; + uint64_t end_time = esp_timer_get_time(); + result.success = true; + result.error_message = INIT_SUCCESS; + + return result; } // Init RMT TX channel @@ -153,7 +165,7 @@ bool DShotRMT::_initRXChannel() return DSHOT_ERROR; } - // Config RMT RX + // Config RMT RX _rx_channel_config.gpio_num = _gpio; _rx_channel_config.clk_src = DSHOT_CLOCK_SRC_DEFAULT; _rx_channel_config.resolution_hz = DSHOT_RMT_RESOLUTION; @@ -212,9 +224,10 @@ bool DShotRMT::_initDShotEncoder() } // Send throttle value -bool DShotRMT::sendThrottle(uint16_t throttle) +dshot_result_t DShotRMT::sendThrottle(uint16_t throttle) { static uint16_t last_throttle = DSHOT_CMD_MOTOR_STOP; + dshot_result_t result = {false, UNKNOWN_ERROR}; // Special case: if throttle is 0, use sendCommand() instead if (throttle == 0) @@ -226,6 +239,7 @@ bool DShotRMT::sendThrottle(uint16_t throttle) if ((throttle < DSHOT_THROTTLE_MIN || throttle > DSHOT_THROTTLE_MAX) && throttle != last_throttle) { _dshot_log(THROTTLE_NOT_IN_RANGE); + result.error_message = THROTTLE_NOT_IN_RANGE; } // Always store the original throttle value @@ -234,17 +248,21 @@ bool DShotRMT::sendThrottle(uint16_t throttle) // Constrain throttle for transmission and send uint16_t new_throttle = constrain(throttle, DSHOT_THROTTLE_MIN, DSHOT_THROTTLE_MAX); _packet = _buildDShotPacket(new_throttle); + return _sendDShotFrame(_packet); } // Send DShot command to ESC -bool DShotRMT::sendCommand(uint16_t command) +dshot_result_t DShotRMT::sendCommand(uint16_t command) { + dshot_result_t result = {false, UNKNOWN_ERROR}; + // Validate command is within DShot specification range if (command < DSHOT_CMD_MOTOR_STOP || command > DSHOT_CMD_MAX) { _dshot_log(COMMAND_NOT_VALID); - return DSHOT_ERROR; + result.error_message = COMMAND_NOT_VALID; + return result; } // Build packet and transmit @@ -252,7 +270,41 @@ bool DShotRMT::sendCommand(uint16_t command) return _sendDShotFrame(_packet); } -// Get RPM from ESC (bidirectional mode only) +// Get telemetry data with timing and error handling +dshot_telemetry_result_t DShotRMT::getTelemetry(uint8_t magnet_count) +{ + dshot_telemetry_result_t result = {false, 0, 0, UNKNOWN_ERROR}; + + // Check if bidirectional mode is enabled + if (!_is_bidirectional) + { + result.error_message = BIDIR_NOT_ENABLED; + _dshot_log(BIDIR_NOT_ENABLED); + return result; + } + + // Get eRPM + uint16_t erpm = getERPM(); + + if (erpm == DSHOT_NULL_PACKET) + { + result.error_message = TELEMETRY_TIMEOUT; + return result; + } + + // Calculate motor RPM + uint8_t pole_pairs = max(1, magnet_count / 2); + uint32_t motor_rpm = erpm / pole_pairs; + + result.success = true; + result.erpm = erpm; + result.motor_rpm = motor_rpm; + result.error_message = TELEMETRY_SUCCESS; + + return result; +} + +// Get RPM from ESC (bidirectional mode only) - backward compatibility uint16_t DShotRMT::getERPM() { // Check if bidirectional mode is enabled @@ -278,13 +330,6 @@ uint16_t DShotRMT::getERPM() return _last_erpm; } -// Convert eRPM to actual motor RPM -uint32_t DShotRMT::getMotorRPM(uint8_t magnet_count) -{ - uint8_t pole_pairs = max(1, magnet_count / 2); - return getERPM() / pole_pairs; -} - // Build a complete DShot packet dshot_packet_t DShotRMT::_buildDShotPacket(const uint16_t value) { @@ -295,7 +340,7 @@ dshot_packet_t DShotRMT::_buildDShotPacket(const uint16_t value) if (value > DSHOT_THROTTLE_MAX) { _dshot_log(PACKET_BUILD_ERROR); - + // Something is really wrong return packet; } @@ -303,10 +348,10 @@ dshot_packet_t DShotRMT::_buildDShotPacket(const uint16_t value) // Build packet packet.throttle_value = value & 0b0000011111111111; packet.telemetric_request = _is_bidirectional ? 1 : 0; - + // CRC is calculated over 11bit uint16_t data = (packet.throttle_value << 1) | packet.telemetric_request; - + packet.checksum = _calculateCRC(data); return packet; @@ -338,21 +383,28 @@ uint16_t DShotRMT::_calculateCRC(const uint16_t data) } // Transmit DShot packet via RMT -bool DShotRMT::_sendDShotFrame(const dshot_packet_t &packet) +dshot_result_t DShotRMT::_sendDShotFrame(const dshot_packet_t &packet) { + dshot_result_t result = {false, UNKNOWN_ERROR}; + uint64_t start_time = esp_timer_get_time(); + // Check timing requirements if (!_timer_signal()) { - return DSHOT_ERROR; + return result; } - // Enable RMT RX before RMT TX + // Enable RMT RX before RMT TX if (_is_bidirectional) { // Performance reasons rmt_symbol_word_t rx_symbols[DSHOT_BITS_PER_FRAME]; - rmt_receive(_rmt_rx_channel, rx_symbols, sizeof(rx_symbols), &_receive_config); + if (rmt_receive(_rmt_rx_channel, rx_symbols, sizeof(rx_symbols), &_receive_config) != DSHOT_OK) + { + result.error_message = RX_RMT_RECEIVER_ERROR; + return result; + } } // Local for performance @@ -370,16 +422,18 @@ bool DShotRMT::_sendDShotFrame(const dshot_packet_t &packet) // Disable RMT RX for sending if (rmt_disable(_rmt_rx_channel) != DSHOT_OK) { + result.error_message = RX_RMT_RECEIVER_ERROR; _dshot_log(RX_RMT_RECEIVER_ERROR); - return DSHOT_ERROR; + return result; } } - + // Perform RMT transmission if (rmt_transmit(_rmt_tx_channel, _dshot_encoder, tx_symbols, tx_size_bytes, &_transmit_config) != DSHOT_OK) { + result.error_message = TRANSMITTER_ERROR; _dshot_log(TRANSMITTER_ERROR); - return DSHOT_ERROR; + return result; } // Re-enable RMT RX @@ -387,15 +441,20 @@ bool DShotRMT::_sendDShotFrame(const dshot_packet_t &packet) { if (rmt_enable(_rmt_rx_channel) != DSHOT_OK) { + result.error_message = RX_RMT_RECEIVER_ERROR; _dshot_log(RX_RMT_RECEIVER_ERROR); - return DSHOT_ERROR; + return result; } } - // Update timestamp and return success + // Update timestamp and calculate execution time _timer_reset(); + uint64_t end_time = esp_timer_get_time(); - return DSHOT_OK; + result.success = true; + result.error_message = TRANSMISSION_SUCCESS; + + return result; } // Encode DShot packet into RMT symbol format (placed in IRAM for performance) @@ -492,9 +551,9 @@ void DShotRMT::printDShotInfo(Stream &output) const // Current DShot mode output.printf("Current Mode: DSHOT%d\n", - _mode == DSHOT150 ? 150 : - _mode == DSHOT300 ? 300 : - _mode == DSHOT600 ? 600 : + _mode == DSHOT150 ? 150 : + _mode == DSHOT300 ? 300 : + _mode == DSHOT600 ? 600 : _mode == DSHOT1200 ? 1200 : 0); output.printf("Bidirectional: %s\n", _is_bidirectional ? "YES" : "NO"); diff --git a/DShotRMT.h b/DShotRMT.h index 21cc76d..bdf40ee 100644 --- a/DShotRMT.h +++ b/DShotRMT.h @@ -65,14 +65,31 @@ typedef struct uint16_t ticks_zero_low; } dshot_timing_t; +// Command execution result structure +typedef struct +{ + bool success; + const char *error_message; +} dshot_result_t; + +// DShot telemetry result structure +typedef struct +{ + bool success; + uint16_t erpm; + uint32_t motor_rpm; + const char *error_message; +} dshot_telemetry_result_t; + +// Naming convention +typedef dshotCommands_e dshot_commands_t; + // class DShotRMT { public: // Constructor with GPIO enum - explicit DShotRMT(gpio_num_t gpio = GPIO_NUM_16, - dshot_mode_t mode = DSHOT300, - bool is_bidirectional = false); + explicit DShotRMT(gpio_num_t gpio = GPIO_NUM_16, dshot_mode_t mode = DSHOT300, bool is_bidirectional = false); // Constructor with pin number DShotRMT(uint16_t pin_nr, dshot_mode_t mode, bool is_bidirectional); @@ -81,24 +98,29 @@ public: ~DShotRMT(); // Initialize the RMT module and DShot config - uint16_t begin(); + dshot_result_t begin(); // Send throttle value (48-2047) - bool sendThrottle(uint16_t throttle); + dshot_result_t sendThrottle(uint16_t throttle); // Send DShot command (0-47) - bool sendCommand(uint16_t command); + dshot_result_t sendCommand(uint16_t command); // Get telemetry data (bidirectional mode only) + dshot_telemetry_result_t getTelemetry(uint8_t magnet_count = 14); + + // Get eRPM only (bidirectional mode only) uint16_t getERPM(); - // Convert eRPM to motor RPM - uint32_t getMotorRPM(uint8_t magnet_count); - - // + // --- GETTERS --- gpio_num_t getGPIO() const { return _gpio; } uint16_t getDShotPacket() const { return _parsed_packet; } bool is_bidirectional() const { return _is_bidirectional; } + dshot_mode_t getMode() const { return _mode; } + + // Get execution statistics + uint32_t getTotalTransmissions() const { return _total_transmissions; } + uint32_t getFailedTransmissions() const { return _failed_transmissions; } // --- INFO --- void printDShotInfo(Stream &output = Serial) const; @@ -106,10 +128,25 @@ public: // --- DEPRECATED METHODS --- [[deprecated("Use sendThrottle() instead")]] - bool setThrottle(uint16_t throttle) { return sendThrottle(throttle); } + bool setThrottle(uint16_t throttle) + { + auto result = sendThrottle(throttle); + return result.success; + } [[deprecated("Use sendCommand() instead")]] - bool sendDShotCommand(uint16_t command) { return sendCommand(command); } + bool sendDShotCommand(uint16_t command) + { + auto result = sendCommand(command); + return result.success; + } + + [[deprecated("Use getTelemetry() instead")]] + uint32_t getMotorRPM(uint8_t magnet_count) + { + auto result = getTelemetry(magnet_count); + return result.success; + } private: // --- CONFIG --- @@ -125,6 +162,10 @@ private: uint16_t _parsed_packet; dshot_packet_t _packet; + // --- STATISTICS --- + uint32_t _total_transmissions; + uint32_t _failed_transmissions; + // --- RMT HARDWARE HANDLES --- rmt_channel_handle_t _rmt_tx_channel; rmt_channel_handle_t _rmt_rx_channel; @@ -147,7 +188,7 @@ private: uint16_t _calculateCRC(const uint16_t data); // --- FRAME PROCESSING --- - bool _sendDShotFrame(const dshot_packet_t &packet); + dshot_result_t _sendDShotFrame(const dshot_packet_t &packet); bool IRAM_ATTR _encodeDShotFrame(const dshot_packet_t &packet, rmt_symbol_word_t *symbols); uint16_t _decodeDShotFrame(const rmt_symbol_word_t *symbols); @@ -164,13 +205,14 @@ private: static constexpr auto DSHOT_TELEMETRY_INVALID = (0xffff); // --- ERROR HANDLING & LOGGING --- - void _dshot_log(const char *msg, Stream &output = Serial) { output.println(msg); } + void _dshot_log(const char *msg, Stream &output = Serial) const { output.println(msg); } // --- CONSTANTS & ERROR MESSAGES --- static constexpr bool DSHOT_OK = 0; static constexpr bool DSHOT_ERROR = 1; static constexpr char *NEW_LINE = " "; + static constexpr char *UNKNOWN_ERROR = "Unknown Error!"; static constexpr char *TX_INIT_FAILED = "Failed to initialize TX channel!"; static constexpr char *RX_INIT_FAILED = "Failed to initialize RX channel!"; static constexpr char *ENCODER_INIT_FAILED = "Failed to initialize DShot encoder!"; @@ -181,4 +223,8 @@ private: static constexpr char *RX_RMT_RECEIVER_ERROR = "RX RMT receiver error!"; static constexpr char *PACKET_BUILD_ERROR = "Value too big for DShot Packet!"; static constexpr char *TRANSMITTER_ERROR = "RMT TX Transmitter Error!"; + static constexpr char *INIT_SUCCESS = "DShotRMT initialized successfully"; + static constexpr char *TELEMETRY_SUCCESS = "Telemetry read successfully"; + static constexpr char *TELEMETRY_TIMEOUT = "Telemetry read timeout"; + static constexpr char *TRANSMISSION_SUCCESS = "Transmission successful"; }; diff --git a/examples/command_manager/command_manager.ino b/examples/command_manager/command_manager.ino index 6d0d508..a07cbe2 100644 --- a/examples/command_manager/command_manager.ino +++ b/examples/command_manager/command_manager.ino @@ -1,11 +1,9 @@ /* - * command_manager_example.ino - * Example sketch demonstrating DShotCommandManager usage + * command_manager.ino + * Example sketch for DShotCommandManager * Author: Wastl Kraus * Date: 2025-09-04 * License: MIT - * - * Modified by Especiallist to support continuous throttle sending. */ #include @@ -28,7 +26,20 @@ DShotRMT motor01(MOTOR01_PIN, DSHOT300, IS_BIDIRECTIONAL); DShotCommandManager commandManager(motor01); // Global variable to store the desired continuous throttle value -static volatile uint16_t throttle_now = NULL; +static volatile uint16_t throttle_now = 0; + +// Helper function to print telemetry results +void printTelemetryResult(const dshot_telemetry_result_t &result) +{ + if (result.success) + { + USB_SERIAL.printf("Telemetry: eRPM=%u, Motor RPM=%u\n", result.erpm, result.motor_rpm); + } + else + { + USB_SERIAL.printf("Telemetry: FAILED - %s\n", result.error_message); + } +} // void setup() @@ -36,25 +47,11 @@ void setup() // Start USB Serial Port USB_SERIAL.begin(USB_SERIAL_BAUD); - USB_SERIAL.println("=== DShotRMT Command Manager Example ==="); - // Initialize DShot - if (motor01.begin() != 0) - { - USB_SERIAL.println("ERROR: Failed to initialize DShotRMT!"); - while (1) - delay(1000); - } + motor01.begin(); // Init Command Manager - if (!commandManager.begin()) - { - USB_SERIAL.println("ERROR: Failed to initialize DShotCommandManager!"); - while (1) - delay(1000); - } - - USB_SERIAL.println("Initialization successful!"); + commandManager.begin(); // Print Menu printMenu(); @@ -75,9 +72,15 @@ void loop() } // Continuously send the stored throttle value - if (throttle_now != NULL) + if (throttle_now != 0) { - motor01.sendThrottle(throttle_now); + dshot_result_t result = motor01.sendThrottle(throttle_now); + + // Only print errors to avoid spam + if (!result.success) + { + printResult(result); + } // Print motor stats every 2 seconds if (esp_timer_get_time() - last_stats_print >= 2000000) @@ -87,8 +90,8 @@ void loop() // Get Motor RPM if (IS_BIDIRECTIONAL) { - uint32_t rpm = motor01.getMotorRPM(MOTOR01_MAGNET_COUNT); - USB_SERIAL.printf("Motor RPM: %u\n", rpm); + dshot_telemetry_result_t telem_result = motor01.getTelemetry(MOTOR01_MAGNET_COUNT); + printTelemetryResult(telem_result); } // Time Stamp @@ -100,92 +103,64 @@ void loop() // void handleUserInput(const String &input) { - dshot_command_result_t result; + dshot_result_t cmd_result; if (input == "1") { // Stop motor command should also reset the continuous throttle value throttle_now = 0; USB_SERIAL.print("Stopping motor... "); - result = commandManager.stopMotor(); - printResult(result); + cmd_result = commandManager.stopMotor(); + printResult(cmd_result); } else if (input == "2") { USB_SERIAL.print("Activating beacon 1... "); - result = commandManager.activateBeacon(1); - printResult(result); + cmd_result = commandManager.activateBeacon(1); + printResult(cmd_result); } else if (input == "3") { USB_SERIAL.print("Setting normal spin direction... "); - result = commandManager.setSpinDirection(false); - printResult(result); + cmd_result = commandManager.setSpinDirection(false); + printResult(cmd_result); } else if (input == "4") { USB_SERIAL.print("Setting reversed spin direction... "); - result = commandManager.setSpinDirection(true); - printResult(result); + cmd_result = commandManager.setSpinDirection(true); + printResult(cmd_result); } else if (input == "5") { - USB_SERIAL.print("Enabling 3D mode... "); - result = commandManager.set3DMode(true); - printResult(result); + USB_SERIAL.print("Getting ESC Info... "); + cmd_result = commandManager.requestESCInfo(); + printResult(cmd_result); } else if (input == "6") { - USB_SERIAL.print("Disabling 3D mode... "); - result = commandManager.set3DMode(false); - printResult(result); + USB_SERIAL.print("Turning LED 0 ON... "); + cmd_result = commandManager.setLED(0, true); + printResult(cmd_result); } else if (input == "7") - { - USB_SERIAL.print("Saving settings... "); - result = commandManager.saveSettings(); - printResult(result); - } - else if (input == "8") - { - USB_SERIAL.print("Turning LED 0 ON... "); - result = commandManager.setLED(0, true); - printResult(result); - } - else if (input == "9") { USB_SERIAL.print("Turning LED 0 OFF... "); - result = commandManager.setLED(0, false); - printResult(result); + cmd_result = commandManager.setLED(0, false); + printResult(cmd_result); } - else if (input == "i") - { - USB_SERIAL.print("Executing initialization sequence... "); - result = commandManager.executeInitSequence(); - printResult(result); - } - else if (input == "c") - { - USB_SERIAL.print("Executing calibration sequence... "); - result = commandManager.executeCalibrationSequence(); - printResult(result); - } - else if (input == "s") - { - commandManager.printStatistics(); - } - else if (input == "r") - { - commandManager.resetStatistics(); - USB_SERIAL.println("Statistics reset."); - } - else if (input == "h") + else if (input == "h" || input == "help") { printMenu(); } - else if (input == "help") + else if (input == "info") { - printMenu(); + motor01.printDShotInfo(); + } + else if (input == "rpm" && IS_BIDIRECTIONAL) + { + dshot_telemetry_result_t result = motor01.getTelemetry(MOTOR01_MAGNET_COUNT); + printTelemetryResult(result); } else if (input.startsWith("cmd ")) { @@ -195,12 +170,12 @@ void handleUserInput(const String &input) { USB_SERIAL.printf("Sending command %d (%s)... ", cmd_num, DShotCommandManager::getCommandName(static_cast(cmd_num))); - result = commandManager.sendCommand(static_cast(cmd_num)); - printResult(result); + cmd_result = commandManager.sendCommand(static_cast(cmd_num)); + printResult(cmd_result); } else { - USB_SERIAL.printf("Invalid command number: %d (valid range: 0-%d)\n", cmd_num, DSHOT_CMD_MAX); + USB_SERIAL.printf("Invalid command number: %d (valid range: 0 - %d)\n", cmd_num, DSHOT_CMD_MAX); } } else if (input.startsWith("throttle ")) @@ -211,65 +186,139 @@ void handleUserInput(const String &input) { throttle_now = throttle_value; USB_SERIAL.printf("Setting continuous throttle to %d\n", throttle_now); + + // Send first throttle command and show result + dshot_result_t result = motor01.sendThrottle(throttle_now); + printResult(result); + + if (result.success) + { + USB_SERIAL.println("Continuous throttle mode enabled. Send '0' or 'throttle 0' to stop."); + } } else if (throttle_value == 0) { throttle_now = 0; USB_SERIAL.println("Continuous throttle stopped."); + + // Send stop command + dshot_result_t result = motor01.sendCommand(DSHOT_CMD_MOTOR_STOP); + printResult(result); } else { - USB_SERIAL.printf("Invalid throttle value: %d (valid range: 48-2047, use 0 to stop)\n", throttle_value); + USB_SERIAL.printf("Invalid throttle value: %d (valid range: %d-%d, use 0 to stop)\n", + throttle_value, DSHOT_THROTTLE_MIN, DSHOT_THROTTLE_MAX); + } + } + else if (input == "0") + { + // Quick stop + throttle_now = 0; + USB_SERIAL.print("Emergency stop... "); + dshot_result_t result = motor01.sendCommand(DSHOT_CMD_MOTOR_STOP); + printResult(result); + } + else if (input.startsWith("repeat ")) + { + // Repeat command: "repeat cmd 5 count 10" - sends command 5 ten times + String params = input.substring(7); + if (params.startsWith("cmd ")) + { + int space_pos = params.indexOf(' ', 4); + if (space_pos > 0 && params.substring(space_pos + 1).startsWith("count ")) + { + int cmd_num = params.substring(4, space_pos).toInt(); + int repeat_count = params.substring(space_pos + 7).toInt(); + + if (DShotCommandManager::isValidCommand(static_cast(cmd_num)) && + repeat_count > 0 && repeat_count <= 100) + { + USB_SERIAL.printf("Sending command %d (%s) %d times... ", cmd_num, + DShotCommandManager::getCommandName(static_cast(cmd_num)), + repeat_count); + cmd_result = commandManager.sendCommand(static_cast(cmd_num), repeat_count); + printResult(cmd_result); + } + else + { + USB_SERIAL.println("Invalid command or repeat count (1-100)"); + } + } + else + { + USB_SERIAL.println("Usage: repeat cmd count "); + } + } + else + { + USB_SERIAL.println("Usage: repeat cmd count "); } } else { - USB_SERIAL.println("Unknown command. Type 'h' for help."); + USB_SERIAL.printf("Unknown command: '%s'. Type 'h' or 'help' for help.\n", input.c_str()); } } // -void printResult(const dshot_command_result_t &result) +void printResult(const dshot_result_t &result) { - if (!result.success) + if (result.success) { - USB_SERIAL.printf("SUCCESS (%u us)\n", result.execution_time_us); + USB_SERIAL.printf("SUCCESS\n"); } else { - USB_SERIAL.printf("FAILED - %s (%u us)\n", result.error_message, result.execution_time_us); + USB_SERIAL.printf("FAILED - %s \n", result.error_message); } } +// +void printSystemStatus() +{ + USB_SERIAL.println("\n=== System Status ==="); + USB_SERIAL.printf("Current throttle: %u\n", throttle_now); + USB_SERIAL.printf("Continuous mode: %s\n", throttle_now > 0 ? "ACTIVE" : "INACTIVE"); + USB_SERIAL.printf("GPIO Pin: %d\n", motor01.getGPIO()); + USB_SERIAL.printf("DShot Mode: DSHOT%d\n", + motor01.getMode() == DSHOT150 ? 150 : motor01.getMode() == DSHOT300 ? 300 + : motor01.getMode() == DSHOT600 ? 600 + : motor01.getMode() == DSHOT1200 ? 1200 + : 0); + USB_SERIAL.printf("Bidirectional: %s\n", motor01.is_bidirectional() ? "YES" : "NO"); + USB_SERIAL.printf("Free heap: %u bytes\n", ESP.getFreeHeap()); + USB_SERIAL.printf("Uptime: %lu seconds\n", millis() / 1000); +} + // void printMenu() { - USB_SERIAL.println("================================================"); - USB_SERIAL.println("\n=== DShot Command Manager Menu ==="); - USB_SERIAL.println("Basic Commands:"); - USB_SERIAL.println(" 1 - Stop Motor"); - USB_SERIAL.println(" 2 - Activate Beacon 1"); - USB_SERIAL.println(" 3 - Set Normal Spin Direction"); - USB_SERIAL.println(" 4 - Set Reversed Spin Direction"); - USB_SERIAL.println(" 5 - Enable 3D Mode"); - USB_SERIAL.println(" 6 - Disable 3D Mode"); - USB_SERIAL.println(" 7 - Save Settings"); - USB_SERIAL.println(" 8 - Turn LED 0 ON"); - USB_SERIAL.println(" 9 - Turn LED 0 OFF"); - USB_SERIAL.println(""); - USB_SERIAL.println("Sequences:"); - USB_SERIAL.println(" i - Execute Initialization Sequence"); - USB_SERIAL.println(" c - Execute Calibration Sequence"); - USB_SERIAL.println(""); - USB_SERIAL.println("Advanced:"); - USB_SERIAL.println(" cmd - Send DShot command (0 - 47)"); - USB_SERIAL.println(" throttle - Set throttle (48 - 2047)"); - USB_SERIAL.println(" throttle 0 - Stop sending throttle"); - USB_SERIAL.println(""); - USB_SERIAL.println(" h - Show this Menu"); - USB_SERIAL.println(""); - USB_SERIAL.println("Examples:"); - USB_SERIAL.println(" cmd 1 - Stop Motor"); - USB_SERIAL.println(" throttle 1000 - Set throttle to 1000"); - USB_SERIAL.println("================================================"); + USB_SERIAL.println("**********************************************"); + USB_SERIAL.println(" DShot Command Manager Menu "); + USB_SERIAL.println("**********************************************"); + USB_SERIAL.println(" 1 - Stop Motor"); + USB_SERIAL.println(" 2 - Activate Beacon 1"); + USB_SERIAL.println(" 3 - Set Normal Spin"); + USB_SERIAL.println(" 4 - Set Reversed Spin"); + USB_SERIAL.println(" 5 - Get ESC Info"); + USB_SERIAL.println(" 6 - Turn LED 0 ON"); + USB_SERIAL.println(" 7 - Turn LED 0 OFF"); + USB_SERIAL.println(" 0 - Emergency Stop"); + USB_SERIAL.println("**********************************************"); + USB_SERIAL.println(" cmd - Send Command (0 - 47)"); + USB_SERIAL.println(" throttle - Set throttle (48 - 2047)"); + USB_SERIAL.println("**********************************************"); + USB_SERIAL.println(" info - Show DShot signal info"); + USB_SERIAL.println(" status - Show system status"); + if (IS_BIDIRECTIONAL) + { + USB_SERIAL.println(" rpm - Get telemetry data"); + } + USB_SERIAL.println(" h / help - Show this Menu"); + USB_SERIAL.println("**********************************************"); + USB_SERIAL.println("EXAMPLE INPUT:"); + USB_SERIAL.println(" cmd 5 - Get ESC Info"); + USB_SERIAL.println(" throttle 1000 - Set throttle to 1000"); + USB_SERIAL.println("**********************************************"); } diff --git a/examples/dshot300/dshot300.ino b/examples/dshot300/dshot300.ino index 4343b93..0660332 100644 --- a/examples/dshot300/dshot300.ino +++ b/examples/dshot300/dshot300.ino @@ -9,9 +9,6 @@ #include #include -// Debug output -static constexpr auto DEBUG = false; - // USB serial port settings static constexpr auto &USB_SERIAL = Serial0; static constexpr auto USB_SERIAL_BAUD = 115200; @@ -38,49 +35,169 @@ void setup() // Starts the USB Serial Port USB_SERIAL.begin(USB_SERIAL_BAUD); - // Initializes DShot Signal + // Initialize DShot Signal motor01.begin(); // Print CPU Info motor01.printCpuInfo(); - USB_SERIAL.println(" "); - USB_SERIAL.println("***********************************"); - USB_SERIAL.println(" === DShotRMT Demo started. === "); - USB_SERIAL.println("Enter a throttle value (48 – 2047):"); + // + printMenu(); } // void loop() { - /// ...safety first + // Safety first static uint16_t throttle = DSHOT_CMD_MOTOR_STOP; + static bool continuous_throttle = true; // Time Measurement static uint32_t last_stats_print = 0; - // Read throttle value + // Handle serial input if (USB_SERIAL.available() > 0) { - throttle = USB_SERIAL.readStringUntil('\n').toInt(); + String input = USB_SERIAL.readStringUntil('\n'); + input.trim(); + + if (input.length() > 0) + { + handleSerialInput(input, throttle, continuous_throttle); + } } - // Send the current throttle value - motor01.sendThrottle(throttle); + // Send throttle value in continuous mode + if (continuous_throttle) + { + motor01.sendThrottle(throttle); + } - // Print motor stats every 2 seconds - if (millis() - last_stats_print >= 2000) + // Print motor stats every 5 seconds in continuous mode + if (continuous_throttle && (millis() - last_stats_print >= 5000)) { motor01.printDShotInfo(); - // Get Motor RPM + // Get Motor RPM if bidirectional if (IS_BIDIRECTIONAL) { - uint32_t rpm = motor01.getMotorRPM(MOTOR01_MAGNET_COUNT); - USB_SERIAL.printf("Motor RPM: %u\n", rpm); + dshot_telemetry_result_t telem_result = motor01.getTelemetry(MOTOR01_MAGNET_COUNT); + printTelemetryResult(telem_result); } // Time Stamp last_stats_print = millis(); } } + +// +void printMenu() +{ + USB_SERIAL.println(" "); + USB_SERIAL.println("******************************************"); + USB_SERIAL.println(" DShotRMT Demo "); + USB_SERIAL.println("******************************************"); + USB_SERIAL.println(" - Set throttle (48 – 2047)"); + USB_SERIAL.println(" 0 - Stop motor"); + USB_SERIAL.println("******************************************"); + USB_SERIAL.println(" cmd - Send DShot command (0-47)"); + USB_SERIAL.println(" info - Show motor info"); + if (IS_BIDIRECTIONAL) + { + USB_SERIAL.println(" rpm - Get telemetry data"); + } + USB_SERIAL.println("******************************************"); + USB_SERIAL.println(" h / help - Show this Menu"); + USB_SERIAL.println("******************************************"); +} + +// Helper function to print command results +void printCommandResult(const dshot_result_t &result, const String &operation) +{ + if (result.success) + { + USB_SERIAL.printf("%s: SUCCESS\n", operation.c_str()); + } + else + { + USB_SERIAL.printf("%s: FAILED - %s\n", operation.c_str(), result.error_message); + } +} + +// Helper function to print telemetry results +void printTelemetryResult(const dshot_telemetry_result_t &result) +{ + if (result.success) + { + USB_SERIAL.printf("Telemetry: eRPM=%u, Motor RPM=%u (%s)\n", result.erpm, result.motor_rpm, result.error_message); + } + else + { + USB_SERIAL.printf("Telemetry: FAILED - %s\n", result.error_message); + } +} + +// +void handleSerialInput(const String &input, uint16_t &throttle, bool &continuous_throttle) +{ + if (input == "0") + { + // Stop motor + throttle = 0; + continuous_throttle = true; // kill motor for sure + dshot_result_t result = motor01.sendCommand(DSHOT_CMD_MOTOR_STOP); + printCommandResult(result, "Stop Motor"); + } + else if (input == "info") + { + continuous_throttle = false; + motor01.printDShotInfo(); + } + else if (input == "rpm" && IS_BIDIRECTIONAL) + { + dshot_telemetry_result_t result = motor01.getTelemetry(MOTOR01_MAGNET_COUNT); + printTelemetryResult(result); + } + else if (input.startsWith("cmd ")) + { + continuous_throttle = false; + + // Send DShot command + int cmd_num = input.substring(4).toInt(); + + if (cmd_num >= DSHOT_CMD_MOTOR_STOP && cmd_num <= DSHOT_CMD_MAX) + { + dshot_result_t result = motor01.sendCommand(cmd_num); + printCommandResult(result, "DShot Command " + String(cmd_num)); + } + else + { + USB_SERIAL.printf("Invalid command: %d (valid range: 0 - %d)\n", cmd_num, DSHOT_CMD_MAX); + } + } + else if (input == "h" || input == "help") + { + printMenu(); + } + else + { + // Parse input throttle value + int throttle_value = input.toInt(); + + if (throttle_value >= DSHOT_THROTTLE_MIN && throttle_value <= DSHOT_THROTTLE_MAX) + { + throttle = throttle_value; + continuous_throttle = true; + + dshot_result_t result = motor01.sendThrottle(throttle); + printCommandResult(result, "Set Throttle " + String(throttle)); + + USB_SERIAL.println("Continuous throttle mode enabled. Send '0' to stop."); + } + else + { + USB_SERIAL.printf("Invalid input: '%s'\n", input.c_str()); + USB_SERIAL.printf("Valid throttle range: %d - %d\n", DSHOT_THROTTLE_MIN, DSHOT_THROTTLE_MAX); + } + } +} From 52d11d8d8684bcc8cc0812c519d0ccc9fe05579e Mon Sep 17 00:00:00 2001 From: Wastl Kraus Date: Fri, 5 Sep 2025 12:20:01 +0200 Subject: [PATCH 2/2] ...preparing release --- examples/dshot300/dshot300.ino | 4 ++-- library.properties | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/dshot300/dshot300.ino b/examples/dshot300/dshot300.ino index 0660332..21f68a8 100644 --- a/examples/dshot300/dshot300.ino +++ b/examples/dshot300/dshot300.ino @@ -111,7 +111,7 @@ void printMenu() USB_SERIAL.println("******************************************"); } -// Helper function to print command results +// Helper to print command results void printCommandResult(const dshot_result_t &result, const String &operation) { if (result.success) @@ -124,7 +124,7 @@ void printCommandResult(const dshot_result_t &result, const String &operation) } } -// Helper function to print telemetry results +// Helper to print telemetry results void printTelemetryResult(const dshot_telemetry_result_t &result) { if (result.success) diff --git a/library.properties b/library.properties index 5e9ba5a..0f27f35 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=DShotRMT -version=0.7.0 +version=0.7.1 author=derdoktor667 maintainer=derdoktor667 sentence=DShotRMT Library supporting all DShot Types and speeds. Tested with BlHeli_S.