17static const char *
const TAG =
"serial_proxy";
48 ESP_LOGW(TAG,
"Subscriber disconnected");
67 size_t to_read = std::min(
available,
sizeof(buffer));
79 "Serial Proxy [%" PRIu32
"]:\n"
87 : LOG_STR_LITERAL(
"TTL"),
88 this->
rts_pin_ !=
nullptr ? LOG_STR_LITERAL(
"configured") : LOG_STR_LITERAL(
"not configured"),
89 this->
dtr_pin_ !=
nullptr ? LOG_STR_LITERAL(
"configured") : LOG_STR_LITERAL(
"not configured"));
93 uint8_t parity, uint8_t stop_bits, uint8_t data_size) {
96 ESP_LOGW(TAG,
"Ignoring configure request from client without port access [%" PRIu32
"]", this->
instance_index_);
101 "Configuring serial proxy [%" PRIu32
"]: baud=%" PRIu32
", flow_ctrl=%s, parity=%" PRIu8
", stop=%" PRIu8
105 auto *uart_comp = this->
parent_;
106 if (uart_comp ==
nullptr) {
107 ESP_LOGE(TAG,
"UART component not available");
113 ESP_LOGW(TAG,
"Invalid baud rate: 0");
117 ESP_LOGW(TAG,
"Invalid stop bits: %u (must be 1 or 2)",
stop_bits);
120 if (data_size < 5 || data_size > 8) {
121 ESP_LOGW(TAG,
"Invalid data bits: %u (must be 5-8)", data_size);
125 ESP_LOGW(TAG,
"Invalid parity: %u (must be 0-2)",
parity);
129 ESP_LOGW(TAG,
"Hardware flow control requested but is not yet supported");
142 if (uart_comp->get_baud_rate() == baudrate && uart_comp->get_stop_bits() ==
stop_bits &&
143 uart_comp->get_data_bits() == data_size && uart_comp->get_parity() == PARITY_MAP[
parity]) {
144 ESP_LOGV(TAG,
"Settings unchanged, skipping reconfigure [%" PRIu32
"]", this->
instance_index_);
151 uart_comp->set_data_bits(data_size);
153 uart_comp->set_parity(PARITY_MAP[
parity]);
156#if defined(USE_ESP8266) || defined(USE_ESP32)
157 uart_comp->load_settings(
true);
167 ESP_LOGW(TAG,
"Ignoring write from client without port access [%" PRIu32
"]", this->
instance_index_);
171 if (data ==
nullptr ||
len == 0)
179 ESP_LOGW(TAG,
"Ignoring modem pin request from client without port access [%" PRIu32
"]", this->
instance_index_);
187 ESP_LOGW(TAG,
"Requested modem pin not configured on serial proxy [%" PRIu32
"]", this->
instance_index_);
192 ESP_LOGV(TAG,
"Setting modem pins [%" PRIu32
"]: RTS=%s, DTR=%s", this->
instance_index_, ONOFF(rts), ONOFF(dtr));
214 ESP_LOGW(TAG,
"Ignoring flush from client without port access [%" PRIu32
"]", this->
instance_index_);
218 ESP_LOGV(TAG,
"Flushing serial proxy [%" PRIu32
"]", this->
instance_index_);
219 switch (this->
flush()) {
243 ESP_LOGV(TAG,
"API connection is already subscribed to serial proxy [%" PRIu32
"]", this->
instance_index_);
251 ESP_LOGE(TAG,
"Only one API subscription is allowed at a time");
254 ESP_LOGW(TAG,
"Previous subscriber disconnected; taking over subscription");
258 ESP_LOGV(TAG,
"API connection subscribed to serial proxy [%" PRIu32
"]", this->
instance_index_);
263 ESP_LOGV(TAG,
"API connection is not subscribed to serial proxy [%" PRIu32
"]", this->
instance_index_);
268 ESP_LOGV(TAG,
"API connection unsubscribed from serial proxy [%" PRIu32
"]", this->
instance_index_);
271 ESP_LOGW(TAG,
"Unknown serial proxy request type: %" PRIu32,
static_cast<uint32_t>(
type));
void enable_loop()
Enable this component's loop.
void disable_loop()
Disable this component's loop.
virtual void digital_write(bool value)=0
void send_serial_proxy_data(const SerialProxyDataReceived &msg)
bool is_connection_setup()
bool is_marked_for_removal() const
void set_data(const uint8_t *data, size_t len)
SerialProxyResult configure(api::APIConnection *api_connection, uint32_t baudrate, bool flow_control, uint8_t parity, uint8_t stop_bits, uint8_t data_size)
Configure UART parameters and apply them.
void read_and_send_(size_t available)
Read from UART and send to API client (slow path with 256-byte stack buffer)
SerialProxyResult serial_proxy_request(api::APIConnection *api_connection, api::enums::SerialProxyRequestType type)
Handle a subscribe/unsubscribe request from an API client.
uint32_t get_modem_pins() const
Get current modem pin states as a bitmask of SerialProxyLineStateFlag values.
uint32_t instance_index_
Instance index for identifying this proxy in API messages.
bool port_claimed_by_other_(api::APIConnection *api_connection) const
True when a live subscriber other than the given connection holds the port.
bool rts_state_
Current modem pin states.
SerialProxyResult flush_port(api::APIConnection *api_connection)
Flush the serial port (block until all TX data is sent)
uint32_t get_configured_modem_pins() const
Get the modem pins this instance can drive as a bitmask of SerialProxyLineStateFlag values.
api::SerialProxyDataReceived outgoing_msg_
Pre-allocated outgoing message; instance field is set once in setup()
const char * name_
Human-readable port name (points to a string literal in flash)
api::enums::SerialProxyPortType port_type_
Port type.
GPIOPin * rts_pin_
Optional GPIO pins for modem control.
SerialProxyResult set_modem_pins(api::APIConnection *api_connection, uint32_t line_states)
Set modem pin states from a bitmask of SerialProxyLineStateFlag values.
void write_from_client(api::APIConnection *api_connection, const uint8_t *data, size_t len)
Write data received from an API client to the serial device.
void dump_config() override
api::APIConnection * api_connection_
Subscribed API client (only one allowed at a time)
void set_baud_rate(uint32_t baud_rate)
optional< std::array< uint8_t, N > > read_array()
void write_array(const uint8_t *data, size_t len)
uint8_t UARTParityOptions parity
struct @66::@67 __attribute__
Wake the main loop task from an ISR. ISR-safe.
@ SERIAL_PROXY_PORT_TYPE_RS232
@ SERIAL_PROXY_PORT_TYPE_RS485
@ SERIAL_PROXY_REQUEST_TYPE_UNSUBSCRIBE
@ SERIAL_PROXY_REQUEST_TYPE_SUBSCRIBE
@ SERIAL_PROXY_LINE_STATE_FLAG_RTS
RTS (Request To Send)
@ SERIAL_PROXY_LINE_STATE_FLAG_DTR
DTR (Data Terminal Ready)
SerialProxyResult
Result of a client-initiated operation; mapped to api::enums::SerialProxyStatus by the API layer.
@ SERIAL_PROXY_RESULT_TIMEOUT
Timed out before TX completed.
@ SERIAL_PROXY_RESULT_ERROR
Driver or hardware error.
@ SERIAL_PROXY_RESULT_NOT_SUPPORTED
Requested feature is not available on this instance.
@ SERIAL_PROXY_RESULT_PORT_IN_USE
Denied: another live client holds the port.
@ SERIAL_PROXY_RESULT_OK
Operation completed or request accepted.
@ SERIAL_PROXY_RESULT_INVALID_ARGUMENT
A parameter value is out of range.
@ SERIAL_PROXY_RESULT_ASSUMED_SUCCESS
Platform cannot confirm TX drain; success assumed.
constexpr size_t SERIAL_PROXY_MAX_READ_SIZE
Maximum bytes to read from UART in a single loop iteration.
@ UART_CONFIG_PARITY_EVEN
@ UART_CONFIG_PARITY_NONE
@ UART_FLUSH_RESULT_ASSUMED_SUCCESS
Platform cannot report result; success is assumed.
@ UART_FLUSH_RESULT_SUCCESS
Confirmed: all bytes left the TX FIFO.
@ UART_FLUSH_RESULT_FAILED
Confirmed: driver or hardware error.
@ UART_FLUSH_RESULT_TIMEOUT
Confirmed: timed out before TX completed.
ESPHOME_ALWAYS_INLINE bool api_is_connected()
Return whether the node has at least one client connected to the native API.