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.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
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)]),
_frame_timer_us(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_command_timestamp(0),
_encoded_frame_value(0),
@ -84,7 +84,7 @@ dshot_result_t DShotRMT::begin()
{
if (!_initTXChannel().success)
{
return {false, TX_INIT_FAILED};
return {false, dshot_msg_code_t::DSHOT_TX_INIT_FAILED};
}
if (_is_bidirectional)
@ -95,7 +95,7 @@ dshot_result_t DShotRMT::begin()
rmt_disable(_rmt_tx_channel);
rmt_del_channel(_rmt_tx_channel);
_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;
}
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
@ -125,7 +125,7 @@ dshot_result_t DShotRMT::sendThrottle(uint16_t throttle)
// A throttle value of 0 is a disarm command
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
@ -140,7 +140,7 @@ dshot_result_t DShotRMT::sendThrottlePercent(float percent)
{
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
@ -151,9 +151,9 @@ dshot_result_t DShotRMT::sendThrottlePercent(float percent)
// Send DShot command to ESC
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);
@ -164,11 +164,11 @@ dshot_result_t DShotRMT::sendCommand(uint16_t command)
// 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 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))
{
result.result_code = INVALID_COMMAND;
result.result_code = dshot_msg_code_t::DSHOT_INVALID_COMMAND;
return result;
}
@ -198,7 +198,7 @@ dshot_result_t DShotRMT::sendCommand(dshotCommands_e dshot_command, uint16_t rep
if (result.success)
{
result.result_code = COMMAND_SUCCESS;
result.result_code = dshot_msg_code_t::DSHOT_COMMAND_SUCCESS;
}
return result;
@ -207,11 +207,11 @@ dshot_result_t DShotRMT::sendCommand(dshotCommands_e dshot_command, uint16_t rep
// Get telemetry data
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)
{
result.result_code = BIDIR_NOT_ENABLED;
result.result_code = dshot_msg_code_t::DSHOT_BIDIR_NOT_ENABLED;
return result;
}
@ -233,7 +233,7 @@ dshot_result_t DShotRMT::getTelemetry(uint16_t magnet_count)
result.success = true;
result.erpm = erpm;
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()
{
return sendCommand(static_cast<uint16_t>(dshotCommands_e::DSHOT_CMD_ESC_INFO));
return sendCommand(dshotCommands_e::DSHOT_CMD_ESC_INFO);
}
// Use with caution
@ -263,7 +263,7 @@ dshot_result_t DShotRMT::saveESCSettings()
// Simple check
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();
// 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();
_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)
{
return {false, TX_INIT_FAILED};
return {false, dshot_msg_code_t::DSHOT_TX_INIT_FAILED};
}
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()
@ -310,7 +310,7 @@ dshot_result_t DShotRMT::_initRXChannel()
// Double check if bidirectional mode is enabled
if (!_is_bidirectional)
{
return {true, NONE};
return {true, dshot_msg_code_t::DSHOT_NONE};
}
_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)
{
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
_rx_event_callbacks.on_recv_done = _on_rx_done;
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)
{
return {false, RX_INIT_FAILED};
return {false, dshot_msg_code_t::DSHOT_RX_INIT_FAILED};
}
// 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);
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()
@ -372,10 +372,10 @@ dshot_result_t DShotRMT::_initDShotEncoder()
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
@ -439,7 +439,7 @@ dshot_result_t DShotRMT::_sendDShotFrame(const dshot_packet_t &packet)
// Ensure enough time has passed since the last transmission
if (!_isFrameIntervalElapsed())
{
return {true, NONE};
return {true, dshot_msg_code_t::DSHOT_NONE};
}
_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)
{
return {false, TRANSMISSION_FAILED};
return {false, dshot_msg_code_t::DSHOT_TRANSMISSION_FAILED};
}
_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

View File

@ -75,7 +75,7 @@ enum class dshot_msg_code_t
typedef struct dshot_result
{
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 motor_rpm; // Motor RPM if telemetry is successful and magnet count is known.
} 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 *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
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
if (result.success && (result.erpm > 0 || result.motor_rpm > 0))