11#include " can.h"
22#include " ../utils/string_utils.h"
3+ #include " ../utils/timing.h"
34#include " ../utils/uart.h"
45#include " driver/twai.h"
56#include < stdexcept>
@@ -93,7 +94,26 @@ void Can::step() {
9394
9495bool Can::receive () {
9596 twai_message_t message;
96- if (twai_receive (&message, pdMS_TO_TICKS (0 )) != ESP_OK) {
97+ const esp_err_t result = twai_receive (&message, pdMS_TO_TICKS (0 ));
98+ if (result == ESP_ERR_TIMEOUT) {
99+ // no message available
100+ return false ;
101+ }
102+
103+ if (result != ESP_OK) {
104+ // reset if bus is off
105+ twai_status_info_t status_info;
106+ if (twai_get_status_info (&status_info) == ESP_OK) {
107+ if (status_info.state == TWAI_STATE_BUS_OFF) {
108+ try {
109+ this ->reset_can_bus ();
110+ } catch (const std::exception &e) {
111+ echo (" CAN recovery failed: %s" , e.what ());
112+ }
113+ }
114+ } else {
115+ echo (" CAN receive error: %d (could not get status info)" , result);
116+ }
97117 return false ;
98118 }
99119
@@ -126,27 +146,18 @@ void Can::send(const uint32_t id, const uint8_t data[8], const bool rtr, uint8_t
126146 for (int i = 0 ; i < dlc; ++i) {
127147 message.data [i] = data[i];
128148 }
149+
129150 if (twai_transmit (&message, pdMS_TO_TICKS (0 )) != ESP_OK) {
130- twai_status_info_t status_info;
151+ try {
152+ echo (" CAN send failed, attempting bus reset..." );
153+ const_cast <Can *>(this )->reset_can_bus ();
131154
132- if (twai_get_status_info (&status_info) != ESP_OK) {
133- throw std::runtime_error (" could not get twai status" );
134- }
135- if (status_info.state == TWAI_STATE_BUS_OFF) {
136- if (twai_initiate_recovery () != ESP_OK) {
137- throw std::runtime_error (" could not initiate recovery" );
155+ if (twai_transmit (&message, pdMS_TO_TICKS (0 )) != ESP_OK) {
156+ throw std::runtime_error (" could not send CAN message even after bus reset" );
138157 }
139- vTaskDelay (pdMS_TO_TICKS (100 )); // Wait for recovery to start
158+ } catch (const std::exception &e) {
159+ throw std::runtime_error (std::string (" Failed to send CAN message: " ) + e.what ());
140160 }
141- if (status_info.state != TWAI_STATE_STOPPED) {
142- if (twai_stop () != ESP_OK) {
143- throw std::runtime_error (" could not stop twai driver" );
144- }
145- }
146- if (twai_start () != ESP_OK) {
147- throw std::runtime_error (" could not restart twai driver" );
148- }
149- throw std::runtime_error (" could not send CAN message" );
150161 }
151162}
152163
@@ -185,18 +196,26 @@ void Can::call(const std::string method_name, const std::vector<ConstExpression_
185196 } else if (method_name == " start" ) {
186197 Module::expect (arguments, 0 );
187198 if (twai_start () != ESP_OK) {
188- throw std::runtime_error (" could not start twai driver" );
199+ throw std::runtime_error (" could not start TWAI driver" );
189200 }
190201 } else if (method_name == " stop" ) {
191202 Module::expect (arguments, 0 );
192203 if (twai_stop () != ESP_OK) {
193- throw std::runtime_error (" could not stop twai driver" );
204+ throw std::runtime_error (" could not stop TWAI driver" );
194205 }
195206 } else if (method_name == " recover" ) {
196207 Module::expect (arguments, 0 );
197208 if (twai_initiate_recovery () != ESP_OK) {
198209 throw std::runtime_error (" could not initiate recovery" );
199210 }
211+ } else if (method_name == " reset" ) {
212+ Module::expect (arguments, 0 );
213+ try {
214+ this ->reset_can_bus ();
215+ } catch (const std::exception &e) {
216+ echo (" Error during CAN reset: %s" , e.what ());
217+ throw ;
218+ }
200219 } else {
201220 Module::call (method_name, arguments);
202221 }
@@ -208,3 +227,68 @@ void Can::subscribe(const uint32_t id, const Module_ptr module) {
208227 }
209228 this ->subscribers [id] = module ;
210229}
230+
231+ void Can::reset_can_bus () {
232+ twai_status_info_t status_info;
233+
234+ if (twai_get_status_info (&status_info) != ESP_OK) {
235+ throw std::runtime_error (" could not get TWAI status" );
236+ }
237+
238+ echo (" CAN bus state before reset: %s" ,
239+ status_info.state == TWAI_STATE_STOPPED ? " STOPPED"
240+ : status_info.state == TWAI_STATE_RUNNING ? " RUNNING"
241+ : status_info.state == TWAI_STATE_BUS_OFF ? " BUS_OFF"
242+ : status_info.state == TWAI_STATE_RECOVERING ? " RECOVERING"
243+ : " UNKNOWN" );
244+
245+ if (status_info.state != TWAI_STATE_STOPPED) {
246+ if (twai_stop () != ESP_OK) {
247+ throw std::runtime_error (" could not stop TWAI driver" );
248+ }
249+ if (twai_get_status_info (&status_info) != ESP_OK || status_info.state != TWAI_STATE_STOPPED) {
250+ throw std::runtime_error (" TWAI driver didn't stop properly" );
251+ }
252+ }
253+
254+ if (status_info.state == TWAI_STATE_BUS_OFF) {
255+ if (twai_initiate_recovery () != ESP_OK) {
256+ throw std::runtime_error (" could not initiate recovery" );
257+ }
258+
259+ const unsigned long start_time = millis ();
260+ const unsigned long timeout_ms = 500 ;
261+
262+ while (true ) {
263+ if (twai_get_status_info (&status_info) != ESP_OK) {
264+ throw std::runtime_error (" failed to get status during recovery" );
265+ }
266+
267+ if (status_info.state != TWAI_STATE_RECOVERING) {
268+ echo (" Recovery completed, state: %s" ,
269+ status_info.state == TWAI_STATE_STOPPED ? " STOPPED"
270+ : status_info.state == TWAI_STATE_RUNNING ? " RUNNING"
271+ : status_info.state == TWAI_STATE_BUS_OFF ? " BUS_OFF"
272+ : " UNKNOWN" );
273+ break ;
274+ }
275+
276+ if (millis_since (start_time) > timeout_ms) {
277+ throw std::runtime_error (" recovery timeout" );
278+ }
279+
280+ delay (20 );
281+ }
282+ }
283+
284+ echo (" Starting TWAI driver..." );
285+ if (twai_start () != ESP_OK) {
286+ throw std::runtime_error (" could not start TWAI driver" );
287+ }
288+
289+ if (twai_get_status_info (&status_info) != ESP_OK || status_info.state != TWAI_STATE_RUNNING) {
290+ throw std::runtime_error (" TWAI driver didn't start properly" );
291+ }
292+
293+ echo (" CAN bus reset successful, state: RUNNING" );
294+ }
0 commit comments