refractor dshot_result_t

This commit is contained in:
Wastl Kraus 2025-09-29 16:51:12 +02:00
parent 3b84df295f
commit 3537f4f2d8
4 changed files with 97 additions and 36 deletions

View File

@ -10,6 +10,7 @@
}, },
"arduino.logLevel": "verbose", "arduino.logLevel": "verbose",
"arduino.path": "/usr/bin/arduino-cli", "arduino.path": "/usr/bin/arduino-cli",
"arduino.useArduinoCli": true "arduino.useArduinoCli": true,
"arduino.disableIntelliSenseAutoGen": true
} }
} }

View File

@ -147,4 +147,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

@ -18,7 +18,7 @@ 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),
@ -84,7 +84,7 @@ dshot_result_t DShotRMT::begin()
{ {
if (!_initTXChannel().success) if (!_initTXChannel().success)
{ {
return {false, TX_INIT_FAILED}; return {false, dshot_msg_code_t::DSHOT_TX_INIT_FAILED};
} }
if (_is_bidirectional) if (_is_bidirectional)
@ -95,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, RX_INIT_FAILED}; return {false, dshot_msg_code_t::DSHOT_RX_INIT_FAILED};
} }
} }
@ -113,10 +113,10 @@ dshot_result_t DShotRMT::begin()
_rmt_rx_channel = nullptr; _rmt_rx_channel = nullptr;
} }
return {false, ENCODER_INIT_FAILED}; return {false, dshot_msg_code_t::DSHOT_ENCODER_INIT_FAILED};
} }
return {true, INIT_SUCCESS}; return {true, dshot_msg_code_t::DSHOT_INIT_SUCCESS};
} }
// Send throttle value // Send throttle value
@ -125,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
@ -140,7 +140,7 @@ dshot_result_t DShotRMT::sendThrottlePercent(float percent)
{ {
if (percent < 0.0f || percent > 100.0f) if (percent < 0.0f || percent > 100.0f)
{ {
return {false, 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
@ -151,9 +151,9 @@ dshot_result_t DShotRMT::sendThrottlePercent(float percent)
// 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, COMMAND_NOT_VALID}; return {false, dshot_msg_code_t::DSHOT_COMMAND_NOT_VALID};
} }
_packet = _buildDShotPacket(command); _packet = _buildDShotPacket(command);
@ -164,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, UNKNOWN_ERROR}; 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.result_code = INVALID_COMMAND; result.result_code = dshot_msg_code_t::DSHOT_INVALID_COMMAND;
return result; return result;
} }
@ -198,7 +198,7 @@ dshot_result_t DShotRMT::sendCommand(dshotCommands_e dshot_command, uint16_t rep
if (result.success) if (result.success)
{ {
result.result_code = COMMAND_SUCCESS; result.result_code = dshot_msg_code_t::DSHOT_COMMAND_SUCCESS;
} }
return result; return result;
@ -207,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, 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.result_code = BIDIR_NOT_ENABLED; result.result_code = dshot_msg_code_t::DSHOT_BIDIR_NOT_ENABLED;
return result; return result;
} }
@ -233,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.result_code = TELEMETRY_SUCCESS; result.result_code = dshot_msg_code_t::DSHOT_TELEMETRY_SUCCESS;
} }
} }
@ -251,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
@ -263,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);
} }
// //
@ -272,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;
@ -294,15 +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, TX_INIT_FAILED}; return {false, dshot_msg_code_t::DSHOT_TX_INIT_FAILED};
} }
if (rmt_enable(_rmt_tx_channel) != DSHOT_OK) if (rmt_enable(_rmt_tx_channel) != DSHOT_OK)
{ {
return {false, TX_INIT_FAILED}; return {false, dshot_msg_code_t::DSHOT_TX_INIT_FAILED};
} }
return {true, TX_INIT_SUCCESS}; return {true, dshot_msg_code_t::DSHOT_TX_INIT_SUCCESS};
} }
dshot_result_t DShotRMT::_initRXChannel() dshot_result_t DShotRMT::_initRXChannel()
@ -310,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, NONE}; return {true, dshot_msg_code_t::DSHOT_NONE};
} }
_rx_channel_config.gpio_num = _gpio; _rx_channel_config.gpio_num = _gpio;
@ -324,19 +324,19 @@ dshot_result_t DShotRMT::_initRXChannel()
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, 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, 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, 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
@ -344,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, RECEIVER_FAILED}; return {false, dshot_msg_code_t::DSHOT_RECEIVER_FAILED};
} }
return {true, RX_INIT_SUCCESS}; return {true, dshot_msg_code_t::DSHOT_RX_INIT_SUCCESS};
} }
dshot_result_t DShotRMT::_initDShotEncoder() dshot_result_t DShotRMT::_initDShotEncoder()
@ -372,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, ENCODER_INIT_FAILED}; return {false, dshot_msg_code_t::DSHOT_ENCODER_INIT_FAILED};
} }
return {true, ENCODER_INIT_SUCCESS}; return {true, dshot_msg_code_t::DSHOT_ENCODER_INIT_SUCCESS};
} }
// Private Packet Management Functions // Private Packet Management Functions
@ -439,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, NONE}; return {true, dshot_msg_code_t::DSHOT_NONE};
} }
_encoded_frame_value = _buildDShotFrameValue(packet); _encoded_frame_value = _buildDShotFrameValue(packet);
@ -452,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, 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, 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

View File

@ -75,7 +75,7 @@ enum class dshot_msg_code_t
typedef struct dshot_result typedef struct dshot_result
{ {
bool success; bool success;
char *result_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;
@ -194,10 +194,70 @@ static constexpr char *CALLBACK_REGISTERING_FAILED = "RMT RX Callback registerin
static constexpr char *INVALID_COMMAND = "Invalid command!"; static constexpr char *INVALID_COMMAND = "Invalid command!";
static constexpr char *COMMAND_SUCCESS = "DShot command sent successfully"; static constexpr char *COMMAND_SUCCESS = "DShot command sent successfully";
// 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;
}
}
// Helpers // Helpers
inline void printDShotResult(dshot_result_t &result, Stream &output = Serial) inline void printDShotResult(dshot_result_t &result, Stream &output = Serial)
{ {
output.printf("Status: %s - %s", result.success ? "SUCCESS" : "FAILED", result.result_code); output.printf("Status: %s - %s", result.success ? "SUCCESS" : "FAILED", _get_result_code_str(result.result_code));
// 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))