ESPHome 2025.10.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
10#ifdef USE_LOGGER
12#endif
13
14namespace esphome {
15namespace uart {
16static 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 uart_config.source_clk = UART_SCLK_DEFAULT;
52 uart_config.rx_flow_ctrl_thresh = 122;
53
54 return uart_config;
55}
56
58 static uint8_t next_uart_num = 0;
59
60#ifdef USE_LOGGER
61 bool logger_uses_hardware_uart = true;
62
63#ifdef USE_LOGGER_USB_CDC
65 // this is not a hardware UART, ignore it
66 logger_uses_hardware_uart = false;
67 }
68#endif // USE_LOGGER_USB_CDC
69
70#ifdef USE_LOGGER_USB_SERIAL_JTAG
72 // this is not a hardware UART, ignore it
73 logger_uses_hardware_uart = false;
74 }
75#endif // USE_LOGGER_USB_SERIAL_JTAG
76
77 if (logger_uses_hardware_uart && logger::global_logger->get_baud_rate() > 0 &&
78 logger::global_logger->get_uart_num() == next_uart_num) {
79 next_uart_num++;
80 }
81#endif // USE_LOGGER
82
83 if (next_uart_num >= SOC_UART_NUM) {
84 ESP_LOGW(TAG, "Maximum number of UART components created already");
85 this->mark_failed();
86 return;
87 }
88 this->uart_num_ = static_cast<uart_port_t>(next_uart_num++);
89 this->lock_ = xSemaphoreCreateMutex();
90
91 xSemaphoreTake(this->lock_, portMAX_DELAY);
92
93 this->load_settings(false);
94
95 xSemaphoreGive(this->lock_);
96}
97
98void IDFUARTComponent::load_settings(bool dump_config) {
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 int8_t flow_control = this->flow_control_pin_ != nullptr ? this->flow_control_pin_->get_pin() : -1;
110
111 uint32_t invert = 0;
112 if (this->tx_pin_ != nullptr && this->tx_pin_->is_inverted())
113 invert |= UART_SIGNAL_TXD_INV;
114 if (this->rx_pin_ != nullptr && this->rx_pin_->is_inverted())
115 invert |= UART_SIGNAL_RXD_INV;
116
117 err = uart_set_line_inverse(this->uart_num_, invert);
118 if (err != ESP_OK) {
119 ESP_LOGW(TAG, "uart_set_line_inverse failed: %s", esp_err_to_name(err));
120 this->mark_failed();
121 return;
122 }
123
124 err = uart_set_pin(this->uart_num_, tx, rx, flow_control, UART_PIN_NO_CHANGE);
125 if (err != ESP_OK) {
126 ESP_LOGW(TAG, "uart_set_pin failed: %s", esp_err_to_name(err));
127 this->mark_failed();
128 return;
129 }
130
131 if (uart_is_driver_installed(this->uart_num_)) {
132 uart_driver_delete(this->uart_num_);
133 if (err != ESP_OK) {
134 ESP_LOGW(TAG, "uart_driver_delete failed: %s", esp_err_to_name(err));
135 this->mark_failed();
136 return;
137 }
138 }
139 err = uart_driver_install(this->uart_num_, /* UART RX ring buffer size. */ this->rx_buffer_size_,
140 /* UART TX ring buffer size. If set to zero, driver will not use TX buffer, TX function will
141 block task until all data have been sent out.*/
142 0,
143 /* UART event queue size/depth. */ 20, &(this->uart_event_queue_),
144 /* Flags used to allocate the interrupt. */ 0);
145 if (err != ESP_OK) {
146 ESP_LOGW(TAG, "uart_driver_install failed: %s", esp_err_to_name(err));
147 this->mark_failed();
148 return;
149 }
150
151 err = uart_set_rx_full_threshold(this->uart_num_, this->rx_full_threshold_);
152 if (err != ESP_OK) {
153 ESP_LOGW(TAG, "uart_set_rx_full_threshold failed: %s", esp_err_to_name(err));
154 this->mark_failed();
155 return;
156 }
157
158 err = uart_set_rx_timeout(this->uart_num_, this->rx_timeout_);
159 if (err != ESP_OK) {
160 ESP_LOGW(TAG, "uart_set_rx_timeout failed: %s", esp_err_to_name(err));
161 this->mark_failed();
162 return;
163 }
164
165 auto mode = this->flow_control_pin_ != nullptr ? UART_MODE_RS485_HALF_DUPLEX : UART_MODE_UART;
166 err = uart_set_mode(this->uart_num_, mode);
167 if (err != ESP_OK) {
168 ESP_LOGW(TAG, "uart_set_mode failed: %s", esp_err_to_name(err));
169 this->mark_failed();
170 return;
171 }
172
173 if (dump_config) {
174 ESP_LOGCONFIG(TAG, "UART %u was reloaded.", this->uart_num_);
175 this->dump_config();
176 }
177}
178
180 ESP_LOGCONFIG(TAG, "UART Bus %u:", this->uart_num_);
181 LOG_PIN(" TX Pin: ", tx_pin_);
182 LOG_PIN(" RX Pin: ", rx_pin_);
183 LOG_PIN(" Flow Control Pin: ", flow_control_pin_);
184 if (this->rx_pin_ != nullptr) {
185 ESP_LOGCONFIG(TAG,
186 " RX Buffer Size: %u\n"
187 " RX Full Threshold: %u\n"
188 " RX Timeout: %u",
190 }
191 ESP_LOGCONFIG(TAG,
192 " Baud Rate: %" PRIu32 " baud\n"
193 " Data Bits: %u\n"
194 " Parity: %s\n"
195 " Stop bits: %u",
196 this->baud_rate_, this->data_bits_, LOG_STR_ARG(parity_to_str(this->parity_)), this->stop_bits_);
197 this->check_logger_conflict();
198}
199
200void IDFUARTComponent::set_rx_full_threshold(size_t rx_full_threshold) {
201 if (this->is_ready()) {
202 esp_err_t err = uart_set_rx_full_threshold(this->uart_num_, rx_full_threshold);
203 if (err != ESP_OK) {
204 ESP_LOGW(TAG, "uart_set_rx_full_threshold failed: %s", esp_err_to_name(err));
205 return;
206 }
207 }
208 this->rx_full_threshold_ = rx_full_threshold;
209}
210
211void IDFUARTComponent::set_rx_timeout(size_t rx_timeout) {
212 if (this->is_ready()) {
213 esp_err_t err = uart_set_rx_timeout(this->uart_num_, rx_timeout);
214 if (err != ESP_OK) {
215 ESP_LOGW(TAG, "uart_set_rx_timeout failed: %s", esp_err_to_name(err));
216 return;
217 }
218 }
219 this->rx_timeout_ = rx_timeout;
220}
221
222void IDFUARTComponent::write_array(const uint8_t *data, size_t len) {
223 xSemaphoreTake(this->lock_, portMAX_DELAY);
224 uart_write_bytes(this->uart_num_, data, len);
225 xSemaphoreGive(this->lock_);
226#ifdef USE_UART_DEBUGGER
227 for (size_t i = 0; i < len; i++) {
228 this->debug_callback_.call(UART_DIRECTION_TX, data[i]);
229 }
230#endif
231}
232
233bool IDFUARTComponent::peek_byte(uint8_t *data) {
234 if (!this->check_read_timeout_())
235 return false;
236 xSemaphoreTake(this->lock_, portMAX_DELAY);
237 if (this->has_peek_) {
238 *data = this->peek_byte_;
239 } else {
240 int len = uart_read_bytes(this->uart_num_, data, 1, 20 / portTICK_PERIOD_MS);
241 if (len == 0) {
242 *data = 0;
243 } else {
244 this->has_peek_ = true;
245 this->peek_byte_ = *data;
246 }
247 }
248 xSemaphoreGive(this->lock_);
249 return true;
250}
251
252bool IDFUARTComponent::read_array(uint8_t *data, size_t len) {
253 size_t length_to_read = len;
254 if (!this->check_read_timeout_(len))
255 return false;
256 xSemaphoreTake(this->lock_, portMAX_DELAY);
257 if (this->has_peek_) {
258 length_to_read--;
259 *data = this->peek_byte_;
260 data++;
261 this->has_peek_ = false;
262 }
263 if (length_to_read > 0)
264 uart_read_bytes(this->uart_num_, data, length_to_read, 20 / portTICK_PERIOD_MS);
265 xSemaphoreGive(this->lock_);
266#ifdef USE_UART_DEBUGGER
267 for (size_t i = 0; i < len; i++) {
268 this->debug_callback_.call(UART_DIRECTION_RX, data[i]);
269 }
270#endif
271 return true;
272}
273
275 size_t available;
276
277 xSemaphoreTake(this->lock_, portMAX_DELAY);
278 uart_get_buffered_data_len(this->uart_num_, &available);
279 if (this->has_peek_)
280 available++;
281 xSemaphoreGive(this->lock_);
282
283 return available;
284}
285
287 ESP_LOGVV(TAG, " Flushing");
288 xSemaphoreTake(this->lock_, portMAX_DELAY);
289 uart_wait_tx_done(this->uart_num_, portMAX_DELAY);
290 xSemaphoreGive(this->lock_);
291}
292
294
295} // namespace uart
296} // namespace esphome
297
298#endif // USE_ESP32
BedjetMode mode
BedJet operating mode.
virtual void mark_failed()
Mark this component as failed.
bool is_ready() const
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:82
@ UART_SELECTION_USB_CDC
Definition logger.h:79
Logger * global_logger
Definition logger.cpp:288
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:291