Files
esphome-wake-up-light-ii/components/uart/uart_component_esp_idf.h
T

126 lines
4.9 KiB
C++
Raw Normal View History

#pragma once
#ifdef USE_ESP32
#include <driver/uart.h>
#include "esphome/core/component.h"
#include "uart_component.h"
#ifdef USE_UART_WAKE_LOOP_ON_RX
#include <driver/uart_select.h>
#endif
namespace esphome::uart {
/// ESP-IDF UART driver wrapper.
///
/// Thread safety: All public methods must only be called from the main loop.
/// The ESP-IDF UART driver API does not guarantee thread safety, and ESPHome's
/// peek byte state (has_peek_/peek_byte_) is not synchronized.
class IDFUARTComponent final : public UARTComponent, public Component {
public:
// User provided, not "= default": `new(p) IDFUARTComponent()` would zero-fill .bss that is already zero.
IDFUARTComponent() {}
void setup() override;
void dump_config() override;
float get_setup_priority() const override { return setup_priority::BUS; }
void set_rx_full_threshold(size_t rx_full_threshold) override;
void set_rx_timeout(size_t rx_timeout) override;
void write_array(const uint8_t *data, size_t len) override;
bool peek_byte(uint8_t *data) override;
bool read_array(uint8_t *data, size_t len) override;
size_t available() override;
size_t available_for_write() override;
UARTFlushResult flush() override;
void set_flush_timeout(uint32_t flush_timeout_ms) override { this->flush_timeout_ms_ = flush_timeout_ms; }
/// TX ring buffer size for the driver; 0 leaves TX unbuffered so write_array() blocks until
/// the FIFO has taken everything.
void set_tx_buffer_size(size_t tx_buffer_size) { this->tx_buffer_size_ = tx_buffer_size; }
void set_clock_source(uart_sclk_t clock_source) { this->clock_source_ = static_cast<uint8_t>(clock_source); }
uint8_t get_hw_serial_number() { return this->uart_num_; }
/// Discard everything received so far: the peek cache and the driver's RX buffer.
void flush_input() {
this->has_peek_ = false;
uart_flush_input(this->uart_num_);
}
/**
* Load the UART with the current settings.
* @param dump_config (Optional, default `true`): True for displaying new settings or
* false to change it quitely
*
* Example:
* ```cpp
* id(uart1).load_settings();
* ```
*
* This will load the current UART interface with the latest settings (baud_rate, parity, etc).
*/
void load_settings(bool dump_config) override;
using UARTComponent::load_settings; // also bring in the no-arg overload for convenience
/**
* Apply the current framing (baud rate, parity, data/stop bits) to the installed
* driver in place, without the delete/reinstall of load_settings(). Tasks blocked in
* the driver survive and the ring buffers are kept, but both hardware FIFOs are
* flushed: a frame in flight reaches the peer truncated and bytes not yet out of the
* RX FIFO are dropped. No lock is taken: quiesce writers first if that matters.
* rx_full_threshold is not rescaled (call set_rx_full_threshold_ms() first if it
* should follow the baud rate); a rollback restores the value from the last accepted
* configuration, undoing a standalone set_rx_full_threshold() made since. Without an
* installed driver this is a full load_settings(false) instead.
*
* @return ESP_OK once the new framing is live (a line-setting error after that only
* logs). On rejection (unreachable baud rate) the previous framing is restored and
* the driver's error returned; if the restore fails too the component is marked
* failed. ESP_ERR_INVALID_STATE if already failed; ESP_FAIL if the fallback
* load_settings() fails.
*/
esp_err_t apply_settings_live();
void on_shutdown() override;
protected:
void check_logger_conflict() override;
uint32_t line_inversion_mask_();
// Re-applies what uart_param_config() resets: inversion, RX threshold/timeout, mode.
esp_err_t apply_line_settings_();
uart_port_t uart_num_{UART_NUM_MAX};
uart_config_t get_config_();
struct Framing {
uint32_t baud_rate;
uint8_t data_bits;
uint8_t stop_bits;
UARTParityOptions parity;
size_t rx_full_threshold; // sized for the baud rate, so rolled back with it
};
Framing framing_() const {
return {this->baud_rate_, this->data_bits_, this->stop_bits_, this->parity_, this->rx_full_threshold_};
}
void set_framing_(const Framing &framing);
// Last framing the driver accepted; baud_rate 0 means none yet.
Framing last_good_framing_{};
bool has_peek_{false};
uint8_t peek_byte_{0};
uint8_t clock_source_{UART_SCLK_DEFAULT}; ///< uart_sclk_t stored in a byte; the IDF values are all small.
uint32_t flush_timeout_ms_{0}; ///< 0 means wait indefinitely (portMAX_DELAY).
size_t tx_buffer_size_{0};
#ifdef USE_UART_WAKE_LOOP_ON_RX
// ISR callback for UART RX data notification — wakes the main loop directly.
static void uart_rx_isr_callback(uart_port_t uart_num, uart_select_notif_t uart_select_notif, BaseType_t *task_woken);
#endif // USE_UART_WAKE_LOOP_ON_RX
};
} // namespace esphome::uart
#endif // USE_ESP32