ESPHome 2025.12.0-dev
Loading...
Searching...
No Matches
uart_component_esp_idf.cpp
Go to the documentation of this file.
1#ifdef USE_ESP32
2
4#include <cinttypes>
8#include "esphome/core/log.h"
9#include "esphome/core/gpio.h"
10#include "driver/gpio.h"
11#include "soc/gpio_num.h"
12
13#ifdef USE_LOGGER
15#endif
16
17namespace esphome {
18namespace uart {
19static const char *const TAG = "uart.idf";
20
22 uart_parity_t parity = UART_PARITY_DISABLE;
23 if (this->parity_ == UART_CONFIG_PARITY_EVEN) {
24 parity = UART_PARITY_EVEN;
25 } else if (this->parity_ == UART_CONFIG_PARITY_ODD) {
26 parity = UART_PARITY_ODD;
27 }
28
29 uart_word_length_t data_bits;
30 switch (this->data_bits_) {
31 case 5:
32 data_bits = UART_DATA_5_BITS;
33 break;
34 case 6:
35 data_bits = UART_DATA_6_BITS;
36 break;
37 case 7:
38 data_bits = UART_DATA_7_BITS;
39 break;
40 case 8:
41 data_bits = UART_DATA_8_BITS;
42 break;
43 default:
44 data_bits = UART_DATA_BITS_MAX;
45 break;
46 }
47
48 uart_config_t uart_config{};
49 uart_config.baud_rate = this->baud_rate_;
50 uart_config.data_bits = data_bits;
51 uart_config.parity = parity;
52 uart_config.stop_bits = this->stop_bits_ == 1 ? UART_STOP_BITS_1 : UART_STOP_BITS_2;
53 uart_config.flow_ctrl = UART_HW_FLOWCTRL_DISABLE;
54 uart_config.source_clk = UART_SCLK_DEFAULT;
55 uart_config.rx_flow_ctrl_thresh = 122;
56
57 return uart_config;
58}
59
61 static uint8_t next_uart_num = 0;
62
63#ifdef USE_LOGGER
64 bool logger_uses_hardware_uart = true;
65
66#ifdef USE_LOGGER_USB_CDC
68 // this is not a hardware UART, ignore it
69 logger_uses_hardware_uart = false;
70 }
71#endif // USE_LOGGER_USB_CDC
72
73#ifdef USE_LOGGER_USB_SERIAL_JTAG
75 // this is not a hardware UART, ignore it
76 logger_uses_hardware_uart = false;
77 }
78#endif // USE_LOGGER_USB_SERIAL_JTAG
79
80 if (logger_uses_hardware_uart && logger::global_logger->get_baud_rate() > 0 &&
81 logger::global_logger->get_uart_num() == next_uart_num) {
82 next_uart_num++;
83 }
84#endif // USE_LOGGER
85
86 if (next_uart_num >= SOC_UART_NUM) {
87 ESP_LOGW(TAG, "Maximum number of UART components created already");
88 this->mark_failed();
89 return;
90 }
91 this->uart_num_ = static_cast<uart_port_t>(next_uart_num++);
92 this->lock_ = xSemaphoreCreateMutex();
93
94#if (SOC_UART_LP_NUM >= 1)
95 size_t fifo_len = ((this->uart_num_ < SOC_UART_HP_NUM) ? SOC_UART_FIFO_LEN : SOC_LP_UART_FIFO_LEN);
96#else
97 size_t fifo_len = SOC_UART_FIFO_LEN;
98#endif
99 if (this->rx_buffer_size_ <= fifo_len) {
100 ESP_LOGW(TAG, "rx_buffer_size is too small, must be greater than %zu", fifo_len);
101 this->rx_buffer_size_ = fifo_len * 2;
102 }
103
104 xSemaphoreTake(this->lock_, portMAX_DELAY);
105
106 this->load_settings(false);
107
108 xSemaphoreGive(this->lock_);
109}
110
111void IDFUARTComponent::load_settings(bool dump_config) {
112 esp_err_t err;
113
114 if (uart_is_driver_installed(this->uart_num_)) {
115 err = uart_driver_delete(this->uart_num_);
116 if (err != ESP_OK) {
117 ESP_LOGW(TAG, "uart_driver_delete failed: %s", esp_err_to_name(err));
118 this->mark_failed();
119 return;
120 }
121 }
122 err = uart_driver_install(this->uart_num_, // UART number
123 this->rx_buffer_size_, // RX ring buffer size
124 0, // TX ring buffer size. If zero, driver will not use a TX buffer and TX function will
125 // block task until all data has been sent out
126 20, // event queue size/depth
127 &this->uart_event_queue_, // event queue
128 0 // Flags used to allocate the interrupt
129 );
130 if (err != ESP_OK) {
131 ESP_LOGW(TAG, "uart_driver_install failed: %s", esp_err_to_name(err));
132 this->mark_failed();
133 return;
134 }
135
136 if (this->rx_pin_) {
137 this->rx_pin_->setup();
138 }
139 if (this->tx_pin_ && this->rx_pin_ != this->tx_pin_) {
140 this->tx_pin_->setup();
141 }
142
143 int8_t tx = this->tx_pin_ != nullptr ? this->tx_pin_->get_pin() : -1;
144 int8_t rx = this->rx_pin_ != nullptr ? this->rx_pin_->get_pin() : -1;
145 int8_t flow_control = this->flow_control_pin_ != nullptr ? this->flow_control_pin_->get_pin() : -1;
146
147 uint32_t invert = 0;
148 if (this->tx_pin_ != nullptr && this->tx_pin_->is_inverted()) {
149 invert |= UART_SIGNAL_TXD_INV;
150 }
151 if (this->rx_pin_ != nullptr && this->rx_pin_->is_inverted()) {
152 invert |= UART_SIGNAL_RXD_INV;
153 }
154
155 err = uart_set_line_inverse(this->uart_num_, invert);
156 if (err != ESP_OK) {
157 ESP_LOGW(TAG, "uart_set_line_inverse failed: %s", esp_err_to_name(err));
158 this->mark_failed();
159 return;
160 }
161
162 err = uart_set_pin(this->uart_num_, tx, rx, flow_control, UART_PIN_NO_CHANGE);
163 if (err != ESP_OK) {
164 ESP_LOGW(TAG, "uart_set_pin failed: %s", esp_err_to_name(err));
165 this->mark_failed();
166 return;
167 }
168
169 err = uart_set_rx_full_threshold(this->uart_num_, this->rx_full_threshold_);
170 if (err != ESP_OK) {
171 ESP_LOGW(TAG, "uart_set_rx_full_threshold failed: %s", esp_err_to_name(err));
172 this->mark_failed();
173 return;
174 }
175
176 err = uart_set_rx_timeout(this->uart_num_, this->rx_timeout_);
177 if (err != ESP_OK) {
178 ESP_LOGW(TAG, "uart_set_rx_timeout failed: %s", esp_err_to_name(err));
179 this->mark_failed();
180 return;
181 }
182
183 auto mode = this->flow_control_pin_ != nullptr ? UART_MODE_RS485_HALF_DUPLEX : UART_MODE_UART;
184 err = uart_set_mode(this->uart_num_, mode); // per docs, must be called only after uart_driver_install()
185 if (err != ESP_OK) {
186 ESP_LOGW(TAG, "uart_set_mode failed: %s", esp_err_to_name(err));
187 this->mark_failed();
188 return;
189 }
190
191 uart_config_t uart_config = this->get_config_();
192 err = uart_param_config(this->uart_num_, &uart_config);
193 if (err != ESP_OK) {
194 ESP_LOGW(TAG, "uart_param_config failed: %s", esp_err_to_name(err));
195 this->mark_failed();
196 return;
197 }
198
199 if (dump_config) {
200 ESP_LOGCONFIG(TAG, "Reloaded UART %u", this->uart_num_);
201 this->dump_config();
202 }
203}
204
206 ESP_LOGCONFIG(TAG, "UART Bus %u:", this->uart_num_);
207 LOG_PIN(" TX Pin: ", this->tx_pin_);
208 LOG_PIN(" RX Pin: ", this->rx_pin_);
209 LOG_PIN(" Flow Control Pin: ", this->flow_control_pin_);
210 if (this->rx_pin_ != nullptr) {
211 ESP_LOGCONFIG(TAG,
212 " RX Buffer Size: %u\n"
213 " RX Full Threshold: %u\n"
214 " RX Timeout: %u",
216 }
217 ESP_LOGCONFIG(TAG,
218 " Baud Rate: %" PRIu32 " baud\n"
219 " Data Bits: %u\n"
220 " Parity: %s\n"
221 " Stop bits: %u",
222 this->baud_rate_, this->data_bits_, LOG_STR_ARG(parity_to_str(this->parity_)), this->stop_bits_);
223 this->check_logger_conflict();
224}
225
226void IDFUARTComponent::set_rx_full_threshold(size_t rx_full_threshold) {
227 if (this->is_ready()) {
228 esp_err_t err = uart_set_rx_full_threshold(this->uart_num_, rx_full_threshold);
229 if (err != ESP_OK) {
230 ESP_LOGW(TAG, "uart_set_rx_full_threshold failed: %s", esp_err_to_name(err));
231 return;
232 }
233 }
234 this->rx_full_threshold_ = rx_full_threshold;
235}
236
237void IDFUARTComponent::set_rx_timeout(size_t rx_timeout) {
238 if (this->is_ready()) {
239 esp_err_t err = uart_set_rx_timeout(this->uart_num_, rx_timeout);
240 if (err != ESP_OK) {
241 ESP_LOGW(TAG, "uart_set_rx_timeout failed: %s", esp_err_to_name(err));
242 return;
243 }
244 }
245 this->rx_timeout_ = rx_timeout;
246}
247
248void IDFUARTComponent::write_array(const uint8_t *data, size_t len) {
249 xSemaphoreTake(this->lock_, portMAX_DELAY);
250 int32_t write_len = uart_write_bytes(this->uart_num_, data, len);
251 xSemaphoreGive(this->lock_);
252 if (write_len != (int32_t) len) {
253 ESP_LOGW(TAG, "uart_write_bytes failed: %d != %zu", write_len, len);
254 this->mark_failed();
255 }
256#ifdef USE_UART_DEBUGGER
257 for (size_t i = 0; i < len; i++) {
258 this->debug_callback_.call(UART_DIRECTION_TX, data[i]);
259 }
260#endif
261}
262
263bool IDFUARTComponent::peek_byte(uint8_t *data) {
264 if (!this->check_read_timeout_())
265 return false;
266 xSemaphoreTake(this->lock_, portMAX_DELAY);
267 if (this->has_peek_) {
268 *data = this->peek_byte_;
269 } else {
270 int len = uart_read_bytes(this->uart_num_, data, 1, 20 / portTICK_PERIOD_MS);
271 if (len == 0) {
272 *data = 0;
273 } else {
274 this->has_peek_ = true;
275 this->peek_byte_ = *data;
276 }
277 }
278 xSemaphoreGive(this->lock_);
279 return true;
280}
281
282bool IDFUARTComponent::read_array(uint8_t *data, size_t len) {
283 size_t length_to_read = len;
284 int32_t read_len = 0;
285 if (!this->check_read_timeout_(len))
286 return false;
287 xSemaphoreTake(this->lock_, portMAX_DELAY);
288 if (this->has_peek_) {
289 length_to_read--;
290 *data = this->peek_byte_;
291 data++;
292 this->has_peek_ = false;
293 }
294 if (length_to_read > 0)
295 read_len = uart_read_bytes(this->uart_num_, data, length_to_read, 20 / portTICK_PERIOD_MS);
296 xSemaphoreGive(this->lock_);
297#ifdef USE_UART_DEBUGGER
298 for (size_t i = 0; i < len; i++) {
299 this->debug_callback_.call(UART_DIRECTION_RX, data[i]);
300 }
301#endif
302 return read_len == (int32_t) length_to_read;
303}
304
306 size_t available = 0;
307 esp_err_t err;
308
309 xSemaphoreTake(this->lock_, portMAX_DELAY);
310 err = uart_get_buffered_data_len(this->uart_num_, &available);
311 xSemaphoreGive(this->lock_);
312
313 if (err != ESP_OK) {
314 ESP_LOGW(TAG, "uart_get_buffered_data_len failed: %s", esp_err_to_name(err));
315 this->mark_failed();
316 }
317 if (this->has_peek_) {
318 available++;
319 }
320 return available;
321}
322
324 ESP_LOGVV(TAG, " Flushing");
325 xSemaphoreTake(this->lock_, portMAX_DELAY);
326 uart_wait_tx_done(this->uart_num_, portMAX_DELAY);
327 xSemaphoreGive(this->lock_);
328}
329
331
332} // namespace uart
333} // namespace esphome
334
335#endif // USE_ESP32
BedjetMode mode
BedJet operating mode.
virtual void mark_failed()
Mark this component as failed.
bool is_ready() const
virtual void setup()=0
virtual uint8_t get_pin() const =0
virtual bool is_inverted() const =0
void set_rx_timeout(size_t rx_timeout) override
bool peek_byte(uint8_t *data) override
void write_array(const uint8_t *data, size_t len) override
void set_rx_full_threshold(size_t rx_full_threshold) override
bool read_array(uint8_t *data, size_t len) override
bool check_read_timeout_(size_t len=1)
InternalGPIOPin * flow_control_pin_
CallbackManager< void(UARTDirection, uint8_t)> debug_callback_
@ UART_SELECTION_USB_SERIAL_JTAG
Definition logger.h:94
@ UART_SELECTION_USB_CDC
Definition logger.h:91
Logger * global_logger
Definition logger.cpp:294
const char *const TAG
Definition spi.cpp:8
const LogString * parity_to_str(UARTParityOptions parity)
Definition uart.cpp:33
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
std::string size_t len
Definition helpers.h:500