ESPHome  2024.9.0
uart_component_esp_idf.cpp
Go to the documentation of this file.
1 #ifdef USE_ESP_IDF
2 
5 #include "esphome/core/defines.h"
6 #include "esphome/core/helpers.h"
7 #include "esphome/core/log.h"
8 #include <cinttypes>
9 
10 #ifdef USE_LOGGER
12 #endif
13 
14 namespace esphome {
15 namespace uart {
16 static const char *const TAG = "uart.idf";
17 
19  uart_parity_t parity = UART_PARITY_DISABLE;
20  if (this->parity_ == UART_CONFIG_PARITY_EVEN) {
21  parity = UART_PARITY_EVEN;
22  } else if (this->parity_ == UART_CONFIG_PARITY_ODD) {
23  parity = UART_PARITY_ODD;
24  }
25 
26  uart_word_length_t data_bits;
27  switch (this->data_bits_) {
28  case 5:
29  data_bits = UART_DATA_5_BITS;
30  break;
31  case 6:
32  data_bits = UART_DATA_6_BITS;
33  break;
34  case 7:
35  data_bits = UART_DATA_7_BITS;
36  break;
37  case 8:
38  data_bits = UART_DATA_8_BITS;
39  break;
40  default:
41  data_bits = UART_DATA_BITS_MAX;
42  break;
43  }
44 
45  uart_config_t uart_config;
46  uart_config.baud_rate = this->baud_rate_;
47  uart_config.data_bits = data_bits;
48  uart_config.parity = parity;
49  uart_config.stop_bits = this->stop_bits_ == 1 ? UART_STOP_BITS_1 : UART_STOP_BITS_2;
50  uart_config.flow_ctrl = UART_HW_FLOWCTRL_DISABLE;
51 #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
52  uart_config.source_clk = UART_SCLK_DEFAULT;
53 #else
54  uart_config.source_clk = UART_SCLK_APB;
55 #endif
56  uart_config.rx_flow_ctrl_thresh = 122;
57 
58  return uart_config;
59 }
60 
62  static uint8_t next_uart_num = 0;
63 
64 #ifdef USE_LOGGER
65  bool logger_uses_hardware_uart = true;
66 
67 #ifdef USE_LOGGER_USB_CDC
69  // this is not a hardware UART, ignore it
70  logger_uses_hardware_uart = false;
71  }
72 #endif // USE_LOGGER_USB_CDC
73 
74 #ifdef USE_LOGGER_USB_SERIAL_JTAG
76  // this is not a hardware UART, ignore it
77  logger_uses_hardware_uart = false;
78  }
79 #endif // USE_LOGGER_USB_SERIAL_JTAG
80 
81  if (logger_uses_hardware_uart && logger::global_logger->get_baud_rate() > 0 &&
82  logger::global_logger->get_uart_num() == next_uart_num) {
83  next_uart_num++;
84  }
85 #endif // USE_LOGGER
86 
87  if (next_uart_num >= UART_NUM_MAX) {
88  ESP_LOGW(TAG, "Maximum number of UART components created already.");
89  this->mark_failed();
90  return;
91  }
92  this->uart_num_ = static_cast<uart_port_t>(next_uart_num++);
93  ESP_LOGCONFIG(TAG, "Setting up UART %u...", this->uart_num_);
94 
95  this->lock_ = xSemaphoreCreateMutex();
96 
97  xSemaphoreTake(this->lock_, portMAX_DELAY);
98 
99  uart_config_t uart_config = this->get_config_();
100  esp_err_t err = uart_param_config(this->uart_num_, &uart_config);
101  if (err != ESP_OK) {
102  ESP_LOGW(TAG, "uart_param_config failed: %s", esp_err_to_name(err));
103  this->mark_failed();
104  return;
105  }
106 
107  int8_t tx = this->tx_pin_ != nullptr ? this->tx_pin_->get_pin() : -1;
108  int8_t rx = this->rx_pin_ != nullptr ? this->rx_pin_->get_pin() : -1;
109 
110  uint32_t invert = 0;
111  if (this->tx_pin_ != nullptr && this->tx_pin_->is_inverted())
112  invert |= UART_SIGNAL_TXD_INV;
113  if (this->rx_pin_ != nullptr && this->rx_pin_->is_inverted())
114  invert |= UART_SIGNAL_RXD_INV;
115 
116  err = uart_set_line_inverse(this->uart_num_, invert);
117  if (err != ESP_OK) {
118  ESP_LOGW(TAG, "uart_set_line_inverse failed: %s", esp_err_to_name(err));
119  this->mark_failed();
120  return;
121  }
122 
123  err = uart_set_pin(this->uart_num_, tx, rx, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
124  if (err != ESP_OK) {
125  ESP_LOGW(TAG, "uart_set_pin failed: %s", esp_err_to_name(err));
126  this->mark_failed();
127  return;
128  }
129 
130  err = uart_driver_install(this->uart_num_, /* UART RX ring buffer size. */ this->rx_buffer_size_,
131  /* UART TX ring buffer size. If set to zero, driver will not use TX buffer, TX function will
132  block task until all data have been sent out.*/
133  0,
134  /* UART event queue size/depth. */ 20, &(this->uart_event_queue_),
135  /* Flags used to allocate the interrupt. */ 0);
136  if (err != ESP_OK) {
137  ESP_LOGW(TAG, "uart_driver_install failed: %s", esp_err_to_name(err));
138  this->mark_failed();
139  return;
140  }
141 
142  xSemaphoreGive(this->lock_);
143 }
144 
146  uart_config_t uart_config = this->get_config_();
147  esp_err_t err = uart_param_config(this->uart_num_, &uart_config);
148  if (err != ESP_OK) {
149  ESP_LOGW(TAG, "uart_param_config failed: %s", esp_err_to_name(err));
150  this->mark_failed();
151  return;
152  } else if (dump_config) {
153  ESP_LOGCONFIG(TAG, "UART %u was reloaded.", this->uart_num_);
154  this->dump_config();
155  }
156 }
157 
159  ESP_LOGCONFIG(TAG, "UART Bus %u:", this->uart_num_);
160  LOG_PIN(" TX Pin: ", tx_pin_);
161  LOG_PIN(" RX Pin: ", rx_pin_);
162  if (this->rx_pin_ != nullptr) {
163  ESP_LOGCONFIG(TAG, " RX Buffer Size: %u", this->rx_buffer_size_);
164  }
165  ESP_LOGCONFIG(TAG, " Baud Rate: %" PRIu32 " baud", this->baud_rate_);
166  ESP_LOGCONFIG(TAG, " Data Bits: %u", this->data_bits_);
167  ESP_LOGCONFIG(TAG, " Parity: %s", LOG_STR_ARG(parity_to_str(this->parity_)));
168  ESP_LOGCONFIG(TAG, " Stop bits: %u", this->stop_bits_);
169  this->check_logger_conflict();
170 }
171 
172 void IDFUARTComponent::write_array(const uint8_t *data, size_t len) {
173  xSemaphoreTake(this->lock_, portMAX_DELAY);
174  uart_write_bytes(this->uart_num_, data, len);
175  xSemaphoreGive(this->lock_);
176 #ifdef USE_UART_DEBUGGER
177  for (size_t i = 0; i < len; i++) {
178  this->debug_callback_.call(UART_DIRECTION_TX, data[i]);
179  }
180 #endif
181 }
182 
183 bool IDFUARTComponent::peek_byte(uint8_t *data) {
184  if (!this->check_read_timeout_())
185  return false;
186  xSemaphoreTake(this->lock_, portMAX_DELAY);
187  if (this->has_peek_) {
188  *data = this->peek_byte_;
189  } else {
190  int len = uart_read_bytes(this->uart_num_, data, 1, 20 / portTICK_PERIOD_MS);
191  if (len == 0) {
192  *data = 0;
193  } else {
194  this->has_peek_ = true;
195  this->peek_byte_ = *data;
196  }
197  }
198  xSemaphoreGive(this->lock_);
199  return true;
200 }
201 
202 bool IDFUARTComponent::read_array(uint8_t *data, size_t len) {
203  size_t length_to_read = len;
204  if (!this->check_read_timeout_(len))
205  return false;
206  xSemaphoreTake(this->lock_, portMAX_DELAY);
207  if (this->has_peek_) {
208  length_to_read--;
209  *data = this->peek_byte_;
210  data++;
211  this->has_peek_ = false;
212  }
213  if (length_to_read > 0)
214  uart_read_bytes(this->uart_num_, data, length_to_read, 20 / portTICK_PERIOD_MS);
215  xSemaphoreGive(this->lock_);
216 #ifdef USE_UART_DEBUGGER
217  for (size_t i = 0; i < len; i++) {
218  this->debug_callback_.call(UART_DIRECTION_RX, data[i]);
219  }
220 #endif
221  return true;
222 }
223 
225  size_t available;
226 
227  xSemaphoreTake(this->lock_, portMAX_DELAY);
228  uart_get_buffered_data_len(this->uart_num_, &available);
229  if (this->has_peek_)
230  available++;
231  xSemaphoreGive(this->lock_);
232 
233  return available;
234 }
235 
237  ESP_LOGVV(TAG, " Flushing...");
238  xSemaphoreTake(this->lock_, portMAX_DELAY);
239  uart_wait_tx_done(this->uart_num_, portMAX_DELAY);
240  xSemaphoreGive(this->lock_);
241 }
242 
244 
245 } // namespace uart
246 } // namespace esphome
247 
248 #endif // USE_ESP32
uint32_t get_baud_rate() const
bool read_array(uint8_t *data, size_t len) override
virtual uint8_t get_pin() const =0
Logger * global_logger
Definition: logger.cpp:198
const char *const TAG
Definition: spi.cpp:8
bool peek_byte(uint8_t *data) override
void write_array(const uint8_t *data, size_t len) override
std::string size_t len
Definition: helpers.h:292
virtual void mark_failed()
Mark this component as failed.
Definition: component.cpp:118
Implementation of SPI Controller mode.
Definition: a01nyub.cpp:7
bool check_read_timeout_(size_t len=1)
CallbackManager< void(UARTDirection, uint8_t)> debug_callback_
const LogString * parity_to_str(UARTParityOptions parity)
Definition: uart.cpp:33
virtual bool is_inverted() const =0