2021-09-20 11:47:51 +02:00
|
|
|
#ifdef USE_ESP_IDF
|
|
|
|
|
|
|
|
#include "uart_component_esp_idf.h"
|
|
|
|
#include "esphome/core/application.h"
|
|
|
|
#include "esphome/core/defines.h"
|
|
|
|
#include "esphome/core/helpers.h"
|
|
|
|
#include "esphome/core/log.h"
|
2023-07-27 07:18:02 +02:00
|
|
|
#include <cinttypes>
|
2021-09-20 11:47:51 +02:00
|
|
|
|
|
|
|
#ifdef USE_LOGGER
|
|
|
|
#include "esphome/components/logger/logger.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
namespace esphome {
|
|
|
|
namespace uart {
|
|
|
|
static const char *const TAG = "uart.idf";
|
|
|
|
|
2021-09-24 18:02:28 +02:00
|
|
|
uart_config_t IDFUARTComponent::get_config_() {
|
2021-09-20 11:47:51 +02:00
|
|
|
uart_parity_t parity = UART_PARITY_DISABLE;
|
2022-01-24 20:56:36 +01:00
|
|
|
if (this->parity_ == UART_CONFIG_PARITY_EVEN) {
|
2021-09-20 11:47:51 +02:00
|
|
|
parity = UART_PARITY_EVEN;
|
2022-01-24 20:56:36 +01:00
|
|
|
} else if (this->parity_ == UART_CONFIG_PARITY_ODD) {
|
2021-09-20 11:47:51 +02:00
|
|
|
parity = UART_PARITY_ODD;
|
2022-01-24 20:56:36 +01:00
|
|
|
}
|
2021-09-20 11:47:51 +02:00
|
|
|
|
|
|
|
uart_word_length_t data_bits;
|
|
|
|
switch (this->data_bits_) {
|
|
|
|
case 5:
|
|
|
|
data_bits = UART_DATA_5_BITS;
|
|
|
|
break;
|
|
|
|
case 6:
|
|
|
|
data_bits = UART_DATA_6_BITS;
|
|
|
|
break;
|
|
|
|
case 7:
|
|
|
|
data_bits = UART_DATA_7_BITS;
|
|
|
|
break;
|
|
|
|
case 8:
|
|
|
|
data_bits = UART_DATA_8_BITS;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
data_bits = UART_DATA_BITS_MAX;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
uart_config_t uart_config;
|
|
|
|
uart_config.baud_rate = this->baud_rate_;
|
|
|
|
uart_config.data_bits = data_bits;
|
|
|
|
uart_config.parity = parity;
|
|
|
|
uart_config.stop_bits = this->stop_bits_ == 1 ? UART_STOP_BITS_1 : UART_STOP_BITS_2;
|
|
|
|
uart_config.flow_ctrl = UART_HW_FLOWCTRL_DISABLE;
|
|
|
|
uart_config.source_clk = UART_SCLK_APB;
|
|
|
|
uart_config.rx_flow_ctrl_thresh = 122;
|
|
|
|
|
|
|
|
return uart_config;
|
|
|
|
}
|
|
|
|
|
|
|
|
void IDFUARTComponent::setup() {
|
|
|
|
static uint8_t next_uart_num = 0;
|
|
|
|
#ifdef USE_LOGGER
|
|
|
|
if (logger::global_logger->get_uart_num() == next_uart_num)
|
|
|
|
next_uart_num++;
|
|
|
|
#endif
|
|
|
|
if (next_uart_num >= UART_NUM_MAX) {
|
|
|
|
ESP_LOGW(TAG, "Maximum number of UART components created already.");
|
|
|
|
this->mark_failed();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this->uart_num_ = next_uart_num++;
|
|
|
|
ESP_LOGCONFIG(TAG, "Setting up UART %u...", this->uart_num_);
|
|
|
|
|
|
|
|
this->lock_ = xSemaphoreCreateMutex();
|
|
|
|
|
|
|
|
xSemaphoreTake(this->lock_, portMAX_DELAY);
|
|
|
|
|
2021-09-24 18:02:28 +02:00
|
|
|
uart_config_t uart_config = this->get_config_();
|
2021-09-20 11:47:51 +02:00
|
|
|
esp_err_t err = uart_param_config(this->uart_num_, &uart_config);
|
|
|
|
if (err != ESP_OK) {
|
|
|
|
ESP_LOGW(TAG, "uart_param_config failed: %s", esp_err_to_name(err));
|
|
|
|
this->mark_failed();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-03-31 06:30:24 +02:00
|
|
|
err = uart_driver_install(this->uart_num_, /* UART RX ring buffer size. */ this->rx_buffer_size_,
|
|
|
|
/* UART TX ring buffer size. If set to zero, driver will not use TX buffer, TX function will
|
|
|
|
block task until all data have been sent out.*/
|
|
|
|
0,
|
|
|
|
/* UART event queue size/depth. */ 20, &(this->uart_event_queue_),
|
|
|
|
/* Flags used to allocate the interrupt. */ 0);
|
2021-09-20 11:47:51 +02:00
|
|
|
if (err != ESP_OK) {
|
|
|
|
ESP_LOGW(TAG, "uart_driver_install failed: %s", esp_err_to_name(err));
|
|
|
|
this->mark_failed();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int8_t tx = this->tx_pin_ != nullptr ? this->tx_pin_->get_pin() : -1;
|
|
|
|
int8_t rx = this->rx_pin_ != nullptr ? this->rx_pin_->get_pin() : -1;
|
|
|
|
|
|
|
|
err = uart_set_pin(this->uart_num_, tx, rx, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
|
|
|
|
if (err != ESP_OK) {
|
|
|
|
ESP_LOGW(TAG, "uart_set_pin failed: %s", esp_err_to_name(err));
|
|
|
|
this->mark_failed();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t invert = 0;
|
|
|
|
if (this->tx_pin_ != nullptr && this->tx_pin_->is_inverted())
|
|
|
|
invert |= UART_SIGNAL_TXD_INV;
|
|
|
|
if (this->rx_pin_ != nullptr && this->rx_pin_->is_inverted())
|
|
|
|
invert |= UART_SIGNAL_RXD_INV;
|
|
|
|
|
|
|
|
err = uart_set_line_inverse(this->uart_num_, invert);
|
|
|
|
if (err != ESP_OK) {
|
|
|
|
ESP_LOGW(TAG, "uart_set_line_inverse failed: %s", esp_err_to_name(err));
|
|
|
|
this->mark_failed();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
xSemaphoreGive(this->lock_);
|
|
|
|
}
|
|
|
|
|
|
|
|
void IDFUARTComponent::dump_config() {
|
|
|
|
ESP_LOGCONFIG(TAG, "UART Bus:");
|
|
|
|
ESP_LOGCONFIG(TAG, " Number: %u", this->uart_num_);
|
|
|
|
LOG_PIN(" TX Pin: ", tx_pin_);
|
|
|
|
LOG_PIN(" RX Pin: ", rx_pin_);
|
|
|
|
if (this->rx_pin_ != nullptr) {
|
|
|
|
ESP_LOGCONFIG(TAG, " RX Buffer Size: %u", this->rx_buffer_size_);
|
|
|
|
}
|
2023-07-27 07:18:02 +02:00
|
|
|
ESP_LOGCONFIG(TAG, " Baud Rate: %" PRIu32 " baud", this->baud_rate_);
|
2021-09-20 11:47:51 +02:00
|
|
|
ESP_LOGCONFIG(TAG, " Data Bits: %u", this->data_bits_);
|
|
|
|
ESP_LOGCONFIG(TAG, " Parity: %s", LOG_STR_ARG(parity_to_str(this->parity_)));
|
|
|
|
ESP_LOGCONFIG(TAG, " Stop bits: %u", this->stop_bits_);
|
|
|
|
this->check_logger_conflict();
|
|
|
|
}
|
|
|
|
|
|
|
|
void IDFUARTComponent::write_array(const uint8_t *data, size_t len) {
|
|
|
|
xSemaphoreTake(this->lock_, portMAX_DELAY);
|
|
|
|
uart_write_bytes(this->uart_num_, data, len);
|
|
|
|
xSemaphoreGive(this->lock_);
|
2021-11-10 23:34:17 +01:00
|
|
|
#ifdef USE_UART_DEBUGGER
|
2021-09-20 11:47:51 +02:00
|
|
|
for (size_t i = 0; i < len; i++) {
|
2021-11-10 23:34:17 +01:00
|
|
|
this->debug_callback_.call(UART_DIRECTION_TX, data[i]);
|
2021-09-20 11:47:51 +02:00
|
|
|
}
|
2021-11-10 23:34:17 +01:00
|
|
|
#endif
|
2021-09-20 11:47:51 +02:00
|
|
|
}
|
2021-11-10 23:34:17 +01:00
|
|
|
|
2021-09-20 11:47:51 +02:00
|
|
|
bool IDFUARTComponent::peek_byte(uint8_t *data) {
|
|
|
|
if (!this->check_read_timeout_())
|
|
|
|
return false;
|
|
|
|
xSemaphoreTake(this->lock_, portMAX_DELAY);
|
2022-01-24 20:56:36 +01:00
|
|
|
if (this->has_peek_) {
|
2021-09-20 11:47:51 +02:00
|
|
|
*data = this->peek_byte_;
|
2022-01-24 20:56:36 +01:00
|
|
|
} else {
|
2023-07-27 07:18:02 +02:00
|
|
|
int len = uart_read_bytes(this->uart_num_, data, 1, 20 / portTICK_PERIOD_MS);
|
2021-09-20 11:47:51 +02:00
|
|
|
if (len == 0) {
|
|
|
|
*data = 0;
|
|
|
|
} else {
|
|
|
|
this->has_peek_ = true;
|
|
|
|
this->peek_byte_ = *data;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
xSemaphoreGive(this->lock_);
|
|
|
|
return true;
|
|
|
|
}
|
2021-11-10 23:34:17 +01:00
|
|
|
|
2021-09-20 11:47:51 +02:00
|
|
|
bool IDFUARTComponent::read_array(uint8_t *data, size_t len) {
|
|
|
|
size_t length_to_read = len;
|
|
|
|
if (!this->check_read_timeout_(len))
|
|
|
|
return false;
|
|
|
|
xSemaphoreTake(this->lock_, portMAX_DELAY);
|
|
|
|
if (this->has_peek_) {
|
|
|
|
length_to_read--;
|
|
|
|
*data = this->peek_byte_;
|
|
|
|
data++;
|
|
|
|
this->has_peek_ = false;
|
|
|
|
}
|
|
|
|
if (length_to_read > 0)
|
2023-07-27 07:18:02 +02:00
|
|
|
uart_read_bytes(this->uart_num_, data, length_to_read, 20 / portTICK_PERIOD_MS);
|
2021-09-20 11:47:51 +02:00
|
|
|
xSemaphoreGive(this->lock_);
|
2021-11-10 23:34:17 +01:00
|
|
|
#ifdef USE_UART_DEBUGGER
|
2021-09-20 11:47:51 +02:00
|
|
|
for (size_t i = 0; i < len; i++) {
|
2021-11-10 23:34:17 +01:00
|
|
|
this->debug_callback_.call(UART_DIRECTION_RX, data[i]);
|
2021-09-20 11:47:51 +02:00
|
|
|
}
|
2021-11-10 23:34:17 +01:00
|
|
|
#endif
|
2021-09-20 11:47:51 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
int IDFUARTComponent::available() {
|
|
|
|
size_t available;
|
|
|
|
|
|
|
|
xSemaphoreTake(this->lock_, portMAX_DELAY);
|
|
|
|
uart_get_buffered_data_len(this->uart_num_, &available);
|
|
|
|
if (this->has_peek_)
|
|
|
|
available++;
|
|
|
|
xSemaphoreGive(this->lock_);
|
|
|
|
|
|
|
|
return available;
|
|
|
|
}
|
|
|
|
|
|
|
|
void IDFUARTComponent::flush() {
|
|
|
|
ESP_LOGVV(TAG, " Flushing...");
|
|
|
|
xSemaphoreTake(this->lock_, portMAX_DELAY);
|
|
|
|
uart_wait_tx_done(this->uart_num_, portMAX_DELAY);
|
|
|
|
xSemaphoreGive(this->lock_);
|
|
|
|
}
|
|
|
|
|
|
|
|
void IDFUARTComponent::check_logger_conflict() {}
|
|
|
|
|
|
|
|
} // namespace uart
|
|
|
|
} // namespace esphome
|
|
|
|
|
|
|
|
#endif // USE_ESP32
|