diff --git a/main/modules/can.cpp b/main/modules/can.cpp index f0a36aa2..479df603 100644 --- a/main/modules/can.cpp +++ b/main/modules/can.cpp @@ -18,6 +18,15 @@ static uint32_t to_29_bit(const int64_t value, const std::string &what) { return value; } +// Lizard's own modules send in every step, so a stopped bus or a full TX queue would flood the console. +static void log_dropped_frame(const char *reason) { + static unsigned long last_drop_log = 0; + if (millis_since(last_drop_log) > 1000) { + echo("CAN send dropped: %s", reason); + last_drop_log = millis(); + } +} + static Module_ptr create_can(const std::string &name, const std::vector &arguments, MessageHandler) { Module::expect(arguments, 3, integer, integer, integer); const gpio_num_t rx_pin = (gpio_num_t)arguments[0]->evaluate_integer(); @@ -173,19 +182,15 @@ bool Can::receive() { return true; } -void Can::send(const uint32_t id, const uint8_t data[8], const bool rtr, uint8_t dlc) const { +bool Can::send(const uint32_t id, const uint8_t data[8], const bool rtr, const uint8_t dlc) const { if (id > MAX_EXTENDED_ID) { throw std::runtime_error("CAN ID does not fit into 29 bits"); } twai_status_info_t status_info; if (twai_get_status_info(&status_info) != ESP_OK || status_info.state != TWAI_STATE_RUNNING) { - static unsigned long last_drop_log = 0; - if (millis_since(last_drop_log) > 1000) { - echo("CAN send dropped: bus not RUNNING"); - last_drop_log = millis(); - } - return; + log_dropped_frame("bus not RUNNING"); + return false; } twai_message_t message; @@ -197,15 +202,20 @@ void Can::send(const uint32_t id, const uint8_t data[8], const bool rtr, uint8_t message.data[i] = data[i]; } - twai_transmit(&message, pdMS_TO_TICKS(0)); + const esp_err_t result = twai_transmit(&message, pdMS_TO_TICKS(0)); + if (result != ESP_OK) { + log_dropped_frame(result == ESP_ERR_TIMEOUT ? "TX queue full" : esp_err_to_name(result)); + return false; + } + return true; } -void Can::send(uint32_t id, - uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3, - uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7, - bool rtr) const { +bool Can::send(const uint32_t id, + const uint8_t d0, const uint8_t d1, const uint8_t d2, const uint8_t d3, + const uint8_t d4, const uint8_t d5, const uint8_t d6, const uint8_t d7, + const bool rtr) const { uint8_t data[8] = {d0, d1, d2, d3, d4, d5, d6, d7}; - this->send(id, data, rtr); + return this->send(id, data, rtr); } void Can::call(const std::string method_name, const std::vector arguments) { diff --git a/main/modules/can.h b/main/modules/can.h index 825fb9cb..f90c0928 100644 --- a/main/modules/can.h +++ b/main/modules/can.h @@ -29,8 +29,10 @@ class Can : public Module { static const std::map get_defaults(); bool receive(); - void send(const uint32_t id, const uint8_t data[8], const bool rtr = false, const uint8_t dlc = 8) const; - void send(const uint32_t id, + // Both overloads return whether the driver accepted the frame, not whether it was acknowledged on the bus. + // false means the frame was dropped, because the bus is not RUNNING or the TX queue is full. + bool send(const uint32_t id, const uint8_t data[8], const bool rtr = false, const uint8_t dlc = 8) const; + bool send(const uint32_t id, const uint8_t d0, const uint8_t d1, const uint8_t d2, const uint8_t d3, const uint8_t d4, const uint8_t d5, const uint8_t d6, const uint8_t d7, const bool rtr = false) const; diff --git a/main/modules/rmd_motor.cpp b/main/modules/rmd_motor.cpp index 6fe47f79..74c10da7 100644 --- a/main/modules/rmd_motor.cpp +++ b/main/modules/rmd_motor.cpp @@ -44,7 +44,9 @@ bool RmdMotor::send(const uint8_t d0, const uint8_t d1, const uint8_t d2, const this->last_msg_id = 0; const int max_attempts = 3; for (int i = 0; i < max_attempts; ++i) { - this->can->send(this->motor_id + 0x140, d0, d1, d2, d3, d4, d5, d6, d7); + if (!this->can->send(this->motor_id + 0x140, d0, d1, d2, d3, d4, d5, d6, d7)) { + return false; // the bus is not RUNNING or the TX queue is full; the next step() sends again anyway + } unsigned long int start = micros(); while (this->last_msg_id != d0 && micros_since(start) < timeout_ms * 1000) { this->can->receive();