ESPHome 2025.10.4
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 xSemaphoreTake(this->lock_, portMAX_DELAY);
95
96 this->load_settings(false);
97
98 xSemaphoreGive(this->lock_);
99}
100
101void IDFUARTComponent::load_settings(bool dump_config) {
102 esp_err_t err;
103
104 if (uart_is_driver_installed(this->uart_num_)) {
105 err = uart_driver_delete(this->uart_num_);
106 if (err != ESP_OK) {
107 ESP_LOGW(TAG, "uart_driver_delete failed: %s", esp_err_to_name(err));
108 this->mark_failed();
109 return;
110 }
111 }
112 err = uart_driver_install(this->uart_num_, // UART number
113 this->rx_buffer_size_, // RX ring buffer size
114 0, // TX ring buffer size. If zero, driver will not use a TX buffer and TX function will
115 // block task until all data has been sent out
116 20, // event queue size/depth
117 &this->uart_event_queue_, // event queue
118 0 // Flags used to allocate the interrupt
119 );
120 if (err != ESP_OK) {
121 ESP_LOGW(TAG, "uart_driver_install failed: %s", esp_err_to_name(err));
122 this->mark_failed();
123 return;
124 }
125
126 if (this->rx_pin_) {
127 this->rx_pin_->setup();
128 }
129 if (this->tx_pin_ && this->rx_pin_ != this->tx_pin_) {
130 this->tx_pin_->setup();
131 }
132
133 int8_t tx = this->tx_pin_ != nullptr ? this->tx_pin_->get_pin() : -1;
134 int8_t rx = this->rx_pin_ != nullptr ? this->rx_pin_->get_pin() : -1;
135 int8_t flow_control = this->flow_control_pin_ != nullptr ? this->flow_control_pin_->get_pin() : -1;
136
137 uint32_t invert = 0;
138 if (this->tx_pin_ != nullptr && this->tx_pin_->is_inverted()) {
139 invert |= UART_SIGNAL_TXD_INV;
140 }
141 if (this->rx_pin_ != nullptr && this->rx_pin_->is_inverted()) {
142 invert |= UART_SIGNAL_RXD_INV;
143 }
144
145 err = uart_set_line_inverse(this->uart_num_, invert);
146 if (err != ESP_OK) {
147 ESP_LOGW(TAG, "uart_set_line_inverse failed: %s", esp_err_to_name(err));
148 this->mark_failed();
149 return;
150 }
151
152 err = uart_set_pin(this->uart_num_, tx, rx, flow_control, UART_PIN_NO_CHANGE);
153 if (err != ESP_OK) {
154 ESP_LOGW(TAG, "uart_set_pin failed: %s", esp_err_to_name(err));
155 this->mark_failed();
156 return;
157 }
158
159 err = uart_set_rx_full_threshold(this->uart_num_, this->rx_full_threshold_);
160 if (err != ESP_OK) {
161 ESP_LOGW(TAG, "uart_set_rx_full_threshold failed: %s", esp_err_to_name(err));
162 this->mark_failed();
163 return;
164 }
165
166 err = uart_set_rx_timeout(this->uart_num_, this->rx_timeout_);
167 if (err != ESP_OK) {
168 ESP_LOGW(TAG, "uart_set_rx_timeout failed: %s", esp_err_to_name(err));
169 this->mark_failed();
170 return;
171 }
172
173 auto mode = this->flow_control_pin_ != nullptr ? UART_MODE_RS485_HALF_DUPLEX : UART_MODE_UART;
174 err = uart_set_mode(this->uart_num_, mode); // per docs, must be called only after uart_driver_install()
175 if (err != ESP_OK) {
176 ESP_LOGW(TAG, "uart_set_mode failed: %s", esp_err_to_name(err));
177 this->mark_failed();
178 return;
179 }
180
181 uart_config_t uart_config = this->get_config_();
182 err = uart_param_config(this->uart_num_, &uart_config);
183 if (err != ESP_OK) {
184 ESP_LOGW(TAG, "uart_param_config failed: %s", esp_err_to_name(err));
185 this->mark_failed();
186 return;
187 }
188
189 if (dump_config) {
190 ESP_LOGCONFIG(TAG, "Reloaded UART %u", this->uart_num_);
191 this->dump_config();
192 }
193}
194
196 ESP_LOGCONFIG(TAG, "UART Bus %u:", this->uart_num_);
197 LOG_PIN(" TX Pin: ", this->tx_pin_);
198 LOG_PIN(" RX Pin: ", this->rx_pin_);
199 LOG_PIN(" Flow Control Pin: ", this->flow_control_pin_);
200 if (this->rx_pin_ != nullptr) {
201 ESP_LOGCONFIG(TAG,
202 " RX Buffer Size: %u\n"
203 " RX Full Threshold: %u\n"
204 " RX Timeout: %u",
206 }
207 ESP_LOGCONFIG(TAG,
208 " Baud Rate: %" PRIu32 " baud\n"
209 " Data Bits: %u\n"
210 " Parity: %s\n"
211 " Stop bits: %u",
212 this->baud_rate_, this->data_bits_, LOG_STR_ARG(parity_to_str(this->parity_)), this->stop_bits_);
213 this->check_logger_conflict();
214}
215
216void IDFUARTComponent::set_rx_full_threshold(size_t rx_full_threshold) {
217 if (this->is_ready()) {
218 esp_err_t err = uart_set_rx_full_threshold(this->uart_num_, rx_full_threshold);
219 if (err != ESP_OK) {
220 ESP_LOGW(TAG, "uart_set_rx_full_threshold failed: %s", esp_err_to_name(err));
221 return;
222 }
223 }
224 this->rx_full_threshold_ = rx_full_threshold;
225}
226
227void IDFUARTComponent::set_rx_timeout(size_t rx_timeout) {
228 if (this->is_ready()) {
229 esp_err_t err = uart_set_rx_timeout(this->uart_num_, rx_timeout);
230 if (err != ESP_OK) {
231 ESP_LOGW(TAG, "uart_set_rx_timeout failed: %s", esp_err_to_name(err));
232 return;
233 }
234 }
235 this->rx_timeout_ = rx_timeout;
236}
237
238void IDFUARTComponent::write_array(const uint8_t *data, size_t len) {
239 xSemaphoreTake(this->lock_, portMAX_DELAY);
240 uart_write_bytes(this->uart_num_, data, len);
241 xSemaphoreGive(this->lock_);
242#ifdef USE_UART_DEBUGGER
243 for (size_t i = 0; i < len; i++) {
244 this->debug_callback_.call(UART_DIRECTION_TX, data[i]);
245 }
246#endif
247}
248
249bool IDFUARTComponent::peek_byte(uint8_t *data) {
250 if (!this->check_read_timeout_())
251 return false;
252 xSemaphoreTake(this->lock_, portMAX_DELAY);
253 if (this->has_peek_) {
254 *data = this->peek_byte_;
255 } else {
256 int len = uart_read_bytes(this->uart_num_, data, 1, 20 / portTICK_PERIOD_MS);
257 if (len == 0) {
258 *data = 0;
259 } else {
260 this->has_peek_ = true;
261 this->peek_byte_ = *data;
262 }
263 }
264 xSemaphoreGive(this->lock_);
265 return true;
266}
267
268bool IDFUARTComponent::read_array(uint8_t *data, size_t len) {
269 size_t length_to_read = len;
270 if (!this->check_read_timeout_(len))
271 return false;
272 xSemaphoreTake(this->lock_, portMAX_DELAY);
273 if (this->has_peek_) {
274 length_to_read--;
275 *data = this->peek_byte_;
276 data++;
277 this->has_peek_ = false;
278 }
279 if (length_to_read > 0)
280 uart_read_bytes(this->uart_num_, data, length_to_read, 20 / portTICK_PERIOD_MS);
281 xSemaphoreGive(this->lock_);
282#ifdef USE_UART_DEBUGGER
283 for (size_t i = 0; i < len; i++) {
284 this->debug_callback_.call(UART_DIRECTION_RX, data[i]);
285 }
286#endif
287 return true;
288}
289
291 size_t available;
292
293 xSemaphoreTake(this->lock_, portMAX_DELAY);
294 uart_get_buffered_data_len(this->uart_num_, &available);
295 if (this->has_peek_)
296 available++;
297 xSemaphoreGive(this->lock_);
298
299 return available;
300}
301
303 ESP_LOGVV(TAG, " Flushing");
304 xSemaphoreTake(this->lock_, portMAX_DELAY);
305 uart_wait_tx_done(this->uart_num_, portMAX_DELAY);
306 xSemaphoreGive(this->lock_);
307}
308
310
311} // namespace uart
312} // namespace esphome
313
314#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:91
@ UART_SELECTION_USB_CDC
Definition logger.h:88
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:304