mirror of
https://github.com/esphome/esphome.git
synced 2026-09-28 15:30:21 +00:00
144 lines
5.3 KiB
C++
144 lines
5.3 KiB
C++
#pragma once
|
|
|
|
// WARNING: This component is EXPERIMENTAL. The API may change at any time
|
|
// without following the normal breaking changes policy. Use at your own risk.
|
|
// Once the API is considered stable, this warning will be removed.
|
|
|
|
#include "esphome/core/defines.h"
|
|
|
|
#ifdef USE_SERIAL_PROXY
|
|
|
|
#include "esphome/core/component.h"
|
|
#include "esphome/core/hal.h"
|
|
#include "esphome/components/uart/uart.h"
|
|
|
|
// Include api_pb2.h only when the API is enabled. The full include is needed
|
|
// to hold SerialProxyDataReceived by value as a pre-allocated member.
|
|
// Guarding prevents pulling conflicting Zephyr logging macro names into
|
|
// translation units that include this header without USE_API defined.
|
|
#ifdef USE_API
|
|
#include "esphome/components/api/api_pb2.h"
|
|
#endif
|
|
|
|
// Forward-declare types needed outside the USE_API guard.
|
|
namespace esphome::api {
|
|
class APIConnection;
|
|
namespace enums {
|
|
enum SerialProxyPortType : uint32_t;
|
|
enum SerialProxyRequestType : uint32_t;
|
|
} // namespace enums
|
|
} // namespace esphome::api
|
|
|
|
namespace esphome::serial_proxy {
|
|
|
|
/// Bit flags for the line_states field exchanged with API clients.
|
|
/// Bit positions are stable API — new signals must use the next available bit.
|
|
enum SerialProxyLineStateFlag : uint32_t {
|
|
SERIAL_PROXY_LINE_STATE_FLAG_RTS = 1 << 0, ///< RTS (Request To Send)
|
|
SERIAL_PROXY_LINE_STATE_FLAG_DTR = 1 << 1, ///< DTR (Data Terminal Ready)
|
|
};
|
|
|
|
/// Maximum bytes to read from UART in a single loop iteration
|
|
inline constexpr size_t SERIAL_PROXY_MAX_READ_SIZE = 256;
|
|
|
|
class SerialProxy final : public uart::UARTDevice, public Component {
|
|
public:
|
|
void setup() override;
|
|
void loop() override;
|
|
void dump_config() override;
|
|
float get_setup_priority() const override { return setup_priority::AFTER_CONNECTION; }
|
|
|
|
/// Get the instance index (position in Application's serial_proxies_ vector)
|
|
uint32_t get_instance_index() const { return this->instance_index_; }
|
|
|
|
/// Set the instance index (called by Application::register_serial_proxy)
|
|
void set_instance_index(uint32_t index) { this->instance_index_ = index; }
|
|
|
|
/// Set the human-readable port name (from YAML configuration)
|
|
void set_name(const char *name) { this->name_ = name; }
|
|
|
|
/// Get the human-readable port name
|
|
const char *get_name() const { return this->name_; }
|
|
|
|
/// Set the port type (from YAML configuration)
|
|
void set_port_type(api::enums::SerialProxyPortType port_type) { this->port_type_ = port_type; }
|
|
|
|
/// Get the port type
|
|
api::enums::SerialProxyPortType get_port_type() const { return this->port_type_; }
|
|
|
|
/// Configure UART parameters and apply them
|
|
/// @param api_connection The API connection requesting the change
|
|
/// @param baudrate Baud rate in bits per second
|
|
/// @param flow_control True to enable hardware flow control
|
|
/// @param parity Parity setting (0=none, 1=even, 2=odd)
|
|
/// @param stop_bits Number of stop bits (1 or 2)
|
|
/// @param data_size Number of data bits (5-8)
|
|
void configure(api::APIConnection *api_connection, uint32_t baudrate, bool flow_control, uint8_t parity,
|
|
uint8_t stop_bits, uint8_t data_size);
|
|
|
|
/// Get the currently subscribed API connection (nullptr if none)
|
|
api::APIConnection *get_api_connection() { return this->api_connection_; }
|
|
|
|
/// Handle a subscribe/unsubscribe request from an API client
|
|
void serial_proxy_request(api::APIConnection *api_connection, api::enums::SerialProxyRequestType type);
|
|
|
|
/// Write data received from an API client to the serial device
|
|
/// @param api_connection The API connection sending the data
|
|
/// @param data Pointer to data buffer
|
|
/// @param len Number of bytes to write
|
|
void write_from_client(api::APIConnection *api_connection, const uint8_t *data, size_t len);
|
|
|
|
/// Set modem pin states from a bitmask of SerialProxyLineStateFlag values
|
|
void set_modem_pins(api::APIConnection *api_connection, uint32_t line_states);
|
|
|
|
/// Get current modem pin states as a bitmask of SerialProxyLineStateFlag values
|
|
uint32_t get_modem_pins() const;
|
|
|
|
/// Flush the serial port (block until all TX data is sent)
|
|
uart::UARTFlushResult flush_port();
|
|
|
|
/// Set the RTS GPIO pin (from YAML configuration)
|
|
void set_rts_pin(GPIOPin *pin) { this->rts_pin_ = pin; }
|
|
|
|
/// Set the DTR GPIO pin (from YAML configuration)
|
|
void set_dtr_pin(GPIOPin *pin) { this->dtr_pin_ = pin; }
|
|
|
|
protected:
|
|
#ifdef USE_API
|
|
/// Read from UART and send to API client (slow path with 256-byte stack buffer)
|
|
void read_and_send_(size_t available);
|
|
|
|
/// True when a live subscriber other than the given connection holds the port
|
|
bool port_claimed_by_other_(api::APIConnection *api_connection) const;
|
|
#endif
|
|
|
|
/// Instance index for identifying this proxy in API messages
|
|
uint32_t instance_index_{0};
|
|
|
|
/// Subscribed API client (only one allowed at a time)
|
|
api::APIConnection *api_connection_{nullptr};
|
|
|
|
#ifdef USE_API
|
|
/// Pre-allocated outgoing message; instance field is set once in setup()
|
|
api::SerialProxyDataReceived outgoing_msg_;
|
|
#endif
|
|
|
|
/// Human-readable port name (points to a string literal in flash)
|
|
const char *name_{nullptr};
|
|
|
|
/// Port type
|
|
api::enums::SerialProxyPortType port_type_{};
|
|
|
|
/// Optional GPIO pins for modem control
|
|
GPIOPin *rts_pin_{nullptr};
|
|
GPIOPin *dtr_pin_{nullptr};
|
|
|
|
/// Current modem pin states
|
|
bool rts_state_{false};
|
|
bool dtr_state_{false};
|
|
};
|
|
|
|
} // namespace esphome::serial_proxy
|
|
|
|
#endif // USE_SERIAL_PROXY
|