ESPHome  2024.4.1
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 #ifdef USE_LOGGER
64  if (logger::global_logger->get_uart_num() == next_uart_num)
65  next_uart_num++;
66 #endif
67  if (next_uart_num >= UART_NUM_MAX) {
68  ESP_LOGW(TAG, "Maximum number of UART components created already.");
69  this->mark_failed();
70  return;
71  }
72  this->uart_num_ = next_uart_num++;
73  ESP_LOGCONFIG(TAG, "Setting up UART %u...", this->uart_num_);
74 
75  this->lock_ = xSemaphoreCreateMutex();
76 
77  xSemaphoreTake(this->lock_, portMAX_DELAY);
78 
79  uart_config_t uart_config = this->get_config_();
80  esp_err_t err = uart_param_config(this->uart_num_, &uart_config);
81  if (err != ESP_OK) {
82  ESP_LOGW(TAG, "uart_param_config failed: %s", esp_err_to_name(err));
83  this->mark_failed();
84  return;
85  }
86 
87  int8_t tx = this->tx_pin_ != nullptr ? this->tx_pin_->get_pin() : -1;
88  int8_t rx = this->rx_pin_ != nullptr ? this->rx_pin_->get_pin() : -1;
89 
90  uint32_t invert = 0;
91  if (this->tx_pin_ != nullptr && this->tx_pin_->is_inverted())
92  invert |= UART_SIGNAL_TXD_INV;
93  if (this->rx_pin_ != nullptr && this->rx_pin_->is_inverted())
94  invert |= UART_SIGNAL_RXD_INV;
95 
96  err = uart_set_line_inverse(this->uart_num_, invert);
97  if (err != ESP_OK) {
98  ESP_LOGW(TAG, "uart_set_line_inverse failed: %s", esp_err_to_name(err));
99  this->mark_failed();
100  return;
101  }
102 
103  err = uart_set_pin(this->uart_num_, tx, rx, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
104  if (err != ESP_OK) {
105  ESP_LOGW(TAG, "uart_set_pin failed: %s", esp_err_to_name(err));
106  this->mark_failed();
107  return;
108  }
109 
110  err = uart_driver_install(this->uart_num_, /* UART RX ring buffer size. */ this->rx_buffer_size_,
111  /* UART TX ring buffer size. If set to zero, driver will not use TX buffer, TX function will
112  block task until all data have been sent out.*/
113  0,
114  /* UART event queue size/depth. */ 20, &(this->uart_event_queue_),
115  /* Flags used to allocate the interrupt. */ 0);
116  if (err != ESP_OK) {
117  ESP_LOGW(TAG, "uart_driver_install failed: %s", esp_err_to_name(err));
118  this->mark_failed();
119  return;
120  }
121 
122  xSemaphoreGive(this->lock_);
123 }
124 
126  uart_config_t uart_config = this->get_config_();
127  esp_err_t err = uart_param_config(this->uart_num_, &uart_config);
128  if (err != ESP_OK) {
129  ESP_LOGW(TAG, "uart_param_config failed: %s", esp_err_to_name(err));
130  this->mark_failed();
131  return;
132  } else if (dump_config) {
133  ESP_LOGCONFIG(TAG, "UART %u was reloaded.", this->uart_num_);
134  this->dump_config();
135  }
136 }
137 
139  ESP_LOGCONFIG(TAG, "UART Bus %u:", this->uart_num_);
140  LOG_PIN(" TX Pin: ", tx_pin_);
141  LOG_PIN(" RX Pin: ", rx_pin_);
142  if (this->rx_pin_ != nullptr) {
143  ESP_LOGCONFIG(TAG, " RX Buffer Size: %u", this->rx_buffer_size_);
144  }
145  ESP_LOGCONFIG(TAG, " Baud Rate: %" PRIu32 " baud", this->baud_rate_);
146  ESP_LOGCONFIG(TAG, " Data Bits: %u", this->data_bits_);
147  ESP_LOGCONFIG(TAG, " Parity: %s", LOG_STR_ARG(parity_to_str(this->parity_)));
148  ESP_LOGCONFIG(TAG, " Stop bits: %u", this->stop_bits_);
149  this->check_logger_conflict();
150 }
151 
152 void IDFUARTComponent::write_array(const uint8_t *data, size_t len) {
153  xSemaphoreTake(this->lock_, portMAX_DELAY);
154  uart_write_bytes(this->uart_num_, data, len);
155  xSemaphoreGive(this->lock_);
156 #ifdef USE_UART_DEBUGGER
157  for (size_t i = 0; i < len; i++) {
158  this->debug_callback_.call(UART_DIRECTION_TX, data[i]);
159  }
160 #endif
161 }
162 
163 bool IDFUARTComponent::peek_byte(uint8_t *data) {
164  if (!this->check_read_timeout_())
165  return false;
166  xSemaphoreTake(this->lock_, portMAX_DELAY);
167  if (this->has_peek_) {
168  *data = this->peek_byte_;
169  } else {
170  int len = uart_read_bytes(this->uart_num_, data, 1, 20 / portTICK_PERIOD_MS);
171  if (len == 0) {
172  *data = 0;
173  } else {
174  this->has_peek_ = true;
175  this->peek_byte_ = *data;
176  }
177  }
178  xSemaphoreGive(this->lock_);
179  return true;
180 }
181 
182 bool IDFUARTComponent::read_array(uint8_t *data, size_t len) {
183  size_t length_to_read = len;
184  if (!this->check_read_timeout_(len))
185  return false;
186  xSemaphoreTake(this->lock_, portMAX_DELAY);
187  if (this->has_peek_) {
188  length_to_read--;
189  *data = this->peek_byte_;
190  data++;
191  this->has_peek_ = false;
192  }
193  if (length_to_read > 0)
194  uart_read_bytes(this->uart_num_, data, length_to_read, 20 / portTICK_PERIOD_MS);
195  xSemaphoreGive(this->lock_);
196 #ifdef USE_UART_DEBUGGER
197  for (size_t i = 0; i < len; i++) {
198  this->debug_callback_.call(UART_DIRECTION_RX, data[i]);
199  }
200 #endif
201  return true;
202 }
203 
205  size_t available;
206 
207  xSemaphoreTake(this->lock_, portMAX_DELAY);
208  uart_get_buffered_data_len(this->uart_num_, &available);
209  if (this->has_peek_)
210  available++;
211  xSemaphoreGive(this->lock_);
212 
213  return available;
214 }
215 
217  ESP_LOGVV(TAG, " Flushing...");
218  xSemaphoreTake(this->lock_, portMAX_DELAY);
219  uart_wait_tx_done(this->uart_num_, portMAX_DELAY);
220  xSemaphoreGive(this->lock_);
221 }
222 
224 
225 } // namespace uart
226 } // namespace esphome
227 
228 #endif // USE_ESP32
bool read_array(uint8_t *data, size_t len) override
virtual uint8_t get_pin() const =0
Logger * global_logger
Definition: logger.cpp:179
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
This is a workaround until we can figure out a way to get the tflite-micro idf component code availab...
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