3#include <esp8266_peri.h>
8#ifdef USE_UART_WAKE_LOOP_ON_RX
20static constexpr uint32_t SW_SERIAL_EDGE_MODE_MAX_BAUD = 19200;
23static constexpr uint32_t RX_TICKS_PER_SECOND = 16000000;
25bool ESP8266UartComponent::serial0_in_use =
false;
31 config |= UART_PARITY_NONE;
33 config |= UART_PARITY_EVEN;
35 config |= UART_PARITY_ODD;
40 config |= UART_NB_BIT_5;
43 config |= UART_NB_BIT_6;
46 config |= UART_NB_BIT_7;
49 config |= UART_NB_BIT_8;
54 config |= UART_NB_STOP_BIT_1;
56 config |= UART_NB_STOP_BIT_2;
78 setup_pin_if_needed(this->
rx_pin_);
80 setup_pin_if_needed(this->
tx_pin_);
86 SerialConfig config =
static_cast<SerialConfig
>(
get_config());
88#ifdef USE_ESP8266_UART_SERIAL
100 ESP8266UartComponent::serial0_in_use =
true;
101 }
else if (!ESP8266UartComponent::serial0_in_use && (
tx_pin_ ==
nullptr ||
tx_pin_->
get_pin() == 15) &&
113 ESP8266UartComponent::serial0_in_use =
true;
116#ifdef USE_ESP8266_UART_SERIAL1
131 ESP_LOGCONFIG(TAG,
"Loading UART bus settings");
133 SerialConfig config =
static_cast<SerialConfig
>(
get_config());
141 ESP_LOGCONFIG(TAG,
"UART bus was reloaded.");
147 ESP_LOGCONFIG(TAG,
"UART Bus:");
148 LOG_PIN(
" TX Pin: ", this->
tx_pin_);
149 LOG_PIN(
" RX Pin: ", this->
rx_pin_);
150 if (this->
rx_pin_ !=
nullptr) {
154 " Baud Rate: %u baud\n"
160 ESP_LOGCONFIG(TAG,
" Using hardware serial interface.");
162 ESP_LOGCONFIG(TAG,
" Using software serial"
163#ifdef USE_UART_WAKE_LOOP_ON_RX
164 "\n Wake on data RX: ENABLED"
167 if (this->
rx_pin_ !=
nullptr) {
168 ESP_LOGCONFIG(TAG,
" RX decoder: %s",
169 this->
baud_rate_ <= SW_SERIAL_EDGE_MODE_MAX_BAUD ? LOG_STR_LITERAL(
"edge")
170 : LOG_STR_LITERAL(
"start bit sampler"));
183 ESP_LOGW(TAG,
" You're using the same serial port for logging and the UART component. Please "
184 "disable logging over the serial port by setting logger->baud_rate to 0.");
193 for (
size_t i = 0; i <
len; i++)
196#ifdef USE_UART_DEBUGGER
197 for (
size_t i = 0; i <
len; i++) {
218 for (
size_t i = 0; i <
len; i++)
221#ifdef USE_UART_DEBUGGER
222 for (
size_t i = 0; i <
len; i++) {
242 ESP_LOGVV(TAG,
" Flushing");
252 size_t rx_buffer_size) {
261 if (tx_pin !=
nullptr) {
268 if (rx_pin !=
nullptr) {
276 buffer =
new uint8_t[rx_buffer_size];
279 stop_bits,
buffer, rx_buffer_size);
281 if (baud_rate <= SW_SERIAL_EDGE_MODE_MAX_BAUD) {
291#if F_CPU != 160000000L
293 return bit_time << (CPU2X & 1);
301 uint32_t wait = bit_time + bit_time / 3 - 500;
306 rec |= arg->
read_bit_(&wait, start, bit_time) << i;
314 arg->
wait_(&wait, start, bit_time);
316 arg->
wait_(&wait, start, bit_time);
321#ifdef USE_UART_WAKE_LOOP_ON_RX
331 [[maybe_unused]]
const bool wake = arg->
rx_.
on_edge(now, level);
332#ifdef USE_UART_WAKE_LOOP_ON_RX
339#ifdef USE_UART_WAKE_LOOP_ON_RX
351 ESP_LOGE(TAG,
"UART doesn't have TX pins set!");
354 bool parity_bit =
false;
355 bool need_parity_bit =
true;
361 need_parity_bit =
false;
371 this->
write_bit_(
false, &wait, start, bit_time);
373 bool bit = data & (1 << i);
374 this->
write_bit_(bit, &wait, start, bit_time);
379 this->
write_bit_(parity_bit, &wait, start, bit_time);
381 this->
write_bit_(
true, &wait, start, bit_time);
383 this->
wait_(&wait, start, bit_time);
392 this->
wait_(wait, start, bit_time);
397 this->
wait_(wait, start, bit_time);
void digital_write(bool value)
virtual uint8_t get_pin() const =0
virtual void detach_interrupt() const =0
void attach_interrupt(void(*func)(T *), T *arg, gpio::InterruptType type) const
virtual bool is_inverted() const =0
virtual ISRInternalGPIOPin to_isr() const =0
Helper class to disable interrupts.
Stream * get_hw_serial() const
UARTSelection get_uart() const
Get the UART used by the logger.
void rx_finalize_pending_()
UARTParityOptions parity_
void write_bit_(bool bit, uint32_t *wait, const uint32_t &start, uint32_t bit_time)
SoftwareSerialRxDecoder rx_
static void gpio_intr_edge(ESP8266SoftwareSerial *arg)
void ESPHOME_ALWAYS_INLINE rx_sync_()
bool read_bit_(uint32_t *wait, const uint32_t &start, uint32_t bit_time)
ISRInternalGPIOPin rx_pin_
void wait_(uint32_t *wait, const uint32_t &start, uint32_t bit_time)
void setup(InternalGPIOPin *tx_pin, InternalGPIOPin *rx_pin, uint32_t baud_rate, uint8_t stop_bits, uint32_t data_bits, UARTParityOptions parity, size_t rx_buffer_size)
InternalGPIOPin * gpio_tx_pin_
InternalGPIOPin * gpio_rx_pin_
static void gpio_intr(ESP8266SoftwareSerial *arg)
Above SW_SERIAL_EDGE_MODE_MAX_BAUD; reads the whole byte in the ISR.
void write_byte(uint8_t data)
ISRInternalGPIOPin tx_pin_
size_t available() override
size_t available_for_write() override
void load_settings()
Load the UART settings.
void check_logger_conflict() override
bool peek_byte(uint8_t *data) override
bool read_array(uint8_t *data, size_t len) override
void dump_config() override
HardwareSerial * hw_serial_
UARTFlushResult flush() override
void write_array(const uint8_t *data, size_t len) override
ESP8266SoftwareSerial * sw_serial_
bool finalize_due(uint32_t now) const
void finalize(uint32_t now)
Call with the ISR masked.
size_t buffer_size() const
void setup(uint32_t bit_ticks, uint8_t data_bits, bool parity, uint8_t stop_bits, uint8_t *buffer, size_t buffer_size)
Configure framing and buffer; drops all state. Follow with reset().
bool ESPHOME_ALWAYS_INLINE on_edge(uint32_t now, bool level)
ISR.
uint8_t peek_byte() const
void reset(uint32_t now, bool level)
Forget any partial frame; level is the current line level.
bool ESPHOME_ALWAYS_INLINE push_byte(uint8_t data)
Drops the byte when full; holds buffer_size - 1 bytes.
UARTParityOptions parity_
bool check_read_timeout_(size_t len=1)
InternalGPIOPin * tx_pin_
uint32_t get_baud_rate() const
CallbackManager< void(UARTDirection, uint8_t)> debug_callback_
InternalGPIOPin * rx_pin_
struct @66::@67 __attribute__
Wake the main loop task from an ISR. ISR-safe.
@ UART_SELECTION_UART0_SWAP
ESPHOME_LOG_TAG(TAG, "uart")
const LogString * parity_to_str(UARTParityOptions parity)
@ UART_CONFIG_PARITY_EVEN
@ UART_CONFIG_PARITY_NONE
UARTFlushResult
Result of a flush() call.
@ UART_FLUSH_RESULT_ASSUMED_SUCCESS
Platform cannot report result; success is assumed.
uint32_t arch_get_cpu_cycle_count()
void wake_loop_threadsafe()
Non-ISR: always inline.
uint32_t IRAM_ATTR HOT micros()
void ESPHOME_ALWAYS_INLINE wake_loop_isrsafe()
ISR-safe: no task_woken arg because ESP8266 has no FreeRTOS. Caller must be IRAM_ATTR.
Platform-specific main loop wake primitives.