ESPHome  2024.9.0
esp32_can.cpp
Go to the documentation of this file.
1 #ifdef USE_ESP32
2 #include "esp32_can.h"
3 #include "esphome/core/log.h"
4 
5 #include <driver/twai.h>
6 
7 // WORKAROUND, because CAN_IO_UNUSED is just defined as (-1) in this version
8 // of the framework which does not work with -fpermissive
9 #undef CAN_IO_UNUSED
10 #define CAN_IO_UNUSED ((gpio_num_t) -1)
11 
12 namespace esphome {
13 namespace esp32_can {
14 
15 static const char *const TAG = "esp32_can";
16 
17 static bool get_bitrate(canbus::CanSpeed bitrate, twai_timing_config_t *t_config) {
18  switch (bitrate) {
19 #if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) || defined(USE_ESP32_VARIANT_ESP32C3) || \
20  defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32H6)
21  case canbus::CAN_1KBPS:
22  *t_config = (twai_timing_config_t) TWAI_TIMING_CONFIG_1KBITS();
23  return true;
24  case canbus::CAN_5KBPS:
25  *t_config = (twai_timing_config_t) TWAI_TIMING_CONFIG_5KBITS();
26  return true;
27  case canbus::CAN_10KBPS:
28  *t_config = (twai_timing_config_t) TWAI_TIMING_CONFIG_10KBITS();
29  return true;
31  *t_config = (twai_timing_config_t) TWAI_TIMING_CONFIG_12_5KBITS();
32  return true;
33  case canbus::CAN_16KBPS:
34  *t_config = (twai_timing_config_t) TWAI_TIMING_CONFIG_16KBITS();
35  return true;
36  case canbus::CAN_20KBPS:
37  *t_config = (twai_timing_config_t) TWAI_TIMING_CONFIG_20KBITS();
38  return true;
39 #endif
40  case canbus::CAN_25KBPS:
41  *t_config = (twai_timing_config_t) TWAI_TIMING_CONFIG_25KBITS();
42  return true;
43  case canbus::CAN_50KBPS:
44  *t_config = (twai_timing_config_t) TWAI_TIMING_CONFIG_50KBITS();
45  return true;
47  *t_config = (twai_timing_config_t) TWAI_TIMING_CONFIG_100KBITS();
48  return true;
50  *t_config = (twai_timing_config_t) TWAI_TIMING_CONFIG_125KBITS();
51  return true;
53  *t_config = (twai_timing_config_t) TWAI_TIMING_CONFIG_250KBITS();
54  return true;
56  *t_config = (twai_timing_config_t) TWAI_TIMING_CONFIG_500KBITS();
57  return true;
59  *t_config = (twai_timing_config_t) TWAI_TIMING_CONFIG_800KBITS();
60  return true;
62  *t_config = (twai_timing_config_t) TWAI_TIMING_CONFIG_1MBITS();
63  return true;
64  default:
65  return false;
66  }
67 }
68 
70  twai_general_config_t g_config =
71  TWAI_GENERAL_CONFIG_DEFAULT((gpio_num_t) this->tx_, (gpio_num_t) this->rx_, TWAI_MODE_NORMAL);
72  if (this->tx_queue_len_.has_value()) {
73  g_config.tx_queue_len = this->tx_queue_len_.value();
74  }
75  if (this->rx_queue_len_.has_value()) {
76  g_config.rx_queue_len = this->rx_queue_len_.value();
77  }
78 
79  twai_filter_config_t f_config = TWAI_FILTER_CONFIG_ACCEPT_ALL();
80  twai_timing_config_t t_config;
81 
82  if (!get_bitrate(this->bit_rate_, &t_config)) {
83  // invalid bit rate
84  this->mark_failed();
85  return false;
86  }
87 
88  // Install TWAI driver
89  if (twai_driver_install(&g_config, &t_config, &f_config) != ESP_OK) {
90  // Failed to install driver
91  this->mark_failed();
92  return false;
93  }
94 
95  // Start TWAI driver
96  if (twai_start() != ESP_OK) {
97  // Failed to start driver
98  this->mark_failed();
99  return false;
100  }
101  return true;
102 }
103 
105  if (frame->can_data_length_code > canbus::CAN_MAX_DATA_LENGTH) {
106  return canbus::ERROR_FAILTX;
107  }
108 
109  uint32_t flags = TWAI_MSG_FLAG_NONE;
110  if (frame->use_extended_id) {
111  flags |= TWAI_MSG_FLAG_EXTD;
112  }
113  if (frame->remote_transmission_request) {
114  flags |= TWAI_MSG_FLAG_RTR;
115  }
116 
117  twai_message_t message = {
118  .flags = flags,
119  .identifier = frame->can_id,
120  .data_length_code = frame->can_data_length_code,
121  .data = {}, // to suppress warning, data is initialized properly below
122  };
123  if (!frame->remote_transmission_request) {
124  memcpy(message.data, frame->data, frame->can_data_length_code);
125  }
126 
127  if (twai_transmit(&message, pdMS_TO_TICKS(1000)) == ESP_OK) {
128  return canbus::ERROR_OK;
129  } else {
131  }
132 }
133 
135  twai_message_t message;
136 
137  if (twai_receive(&message, 0) != ESP_OK) {
138  return canbus::ERROR_NOMSG;
139  }
140 
141  frame->can_id = message.identifier;
142  frame->use_extended_id = message.flags & TWAI_MSG_FLAG_EXTD;
143  frame->remote_transmission_request = message.flags & TWAI_MSG_FLAG_RTR;
144  frame->can_data_length_code = message.data_length_code;
145 
146  if (!frame->remote_transmission_request) {
147  size_t dlc =
148  message.data_length_code < canbus::CAN_MAX_DATA_LENGTH ? message.data_length_code : canbus::CAN_MAX_DATA_LENGTH;
149  memcpy(frame->data, message.data, dlc);
150  }
151 
152  return canbus::ERROR_OK;
153 }
154 
155 } // namespace esp32_can
156 } // namespace esphome
157 
158 #endif
value_type const & value() const
Definition: optional.h:89
optional< uint32_t > tx_queue_len_
Definition: esp32_can.h:26
bool setup_internal() override
Definition: esp32_can.cpp:69
optional< uint32_t > rx_queue_len_
Definition: esp32_can.h:27
uint8_t can_data_length_code
Definition: canbus.h:61
bool has_value() const
Definition: optional.h:87
CanSpeed bit_rate_
Definition: canbus.h:90
bool remote_transmission_request
Definition: canbus.h:59
const uint32_t flags
Definition: stm32flash.h:85
canbus::Error read_message(struct canbus::CanFrame *frame) override
Definition: esp32_can.cpp:134
virtual void mark_failed()
Mark this component as failed.
Definition: component.cpp:118
Implementation of SPI Controller mode.
Definition: a01nyub.cpp:7
canbus::Error send_message(struct canbus::CanFrame *frame) override
Definition: esp32_can.cpp:104