#pragma once // ============================================================================ // HOST-ONLY TEST COMPONENT — DO NOT COPY TO PRODUCTION CODE // // This component runs exclusively on the host platform for integration testing. // It intentionally uses std::vector, std::deque, and dynamic allocation which // would be inappropriate for production embedded components. Do not use this // code as a reference for writing ESPHome components targeting real hardware. // ============================================================================ #include "esphome/core/component.h" #include "esphome/components/uart/uart_component.h" #include #include namespace esphome::uart_mock { class MockUartComponent : public uart::UARTComponent, public Component { public: void setup() override; void loop() override; void dump_config() override; float get_setup_priority() const override { return setup_priority::BUS; } // UARTComponent interface 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; uart::UARTFlushResult flush() override; void set_rx_full_threshold(size_t rx_full_threshold) override; void set_rx_timeout(size_t rx_timeout) override; // Scenario configuration - called from generated code void add_injection(const std::vector &rx_data, uint32_t delay_ms); void add_response(const std::vector &expect_tx, const std::vector &inject_rx, uint32_t delay_ms = 0); void add_periodic_rx(const std::vector &data, uint32_t interval_ms); void start_scenario(); void set_auto_start(bool auto_start) { this->auto_start_ = auto_start; } void set_tx_hook(std::function &)> &&cb) { this->tx_hook_ = std::move(cb); } void inject_to_rx_buffer(const std::vector &data); void inject_to_rx_buffer(const uint8_t *data, size_t len); // Stage bytes for delayed delivery - simulates transport-level latency (e.g., USB packets) void inject_to_rx_buffer_delayed(const std::vector &data, uint32_t delay_ms); protected: void check_logger_conflict() override {} void try_match_response_(); // Timed injections struct Injection { std::vector rx_data; uint32_t delay_ms; }; std::vector injections_; uint32_t injection_index_{0}; uint32_t scenario_start_ms_{0}; uint32_t cumulative_delay_ms_{0}; bool loop_started_{false}; bool auto_start_{true}; bool scenario_active_{false}; // TX-triggered responses struct Response { std::vector expect_tx; std::vector inject_rx; uint32_t delay_ms; uint32_t last_match_ms{0}; }; std::vector responses_; std::vector tx_buffer_; // RX buffer std::deque rx_buffer_; // Periodic RX struct PeriodicRx { std::vector data; uint32_t interval_ms; uint32_t last_inject_ms{0}; }; std::vector periodic_rx_; // Staged RX - bytes that are pending delivery after a delay // Simulates transport-level latency (e.g., USB packet delivery) struct StagedRx { std::vector data; uint32_t available_at_ms; // millis() time when bytes become available }; std::deque staged_rx_; // Observability uint32_t tx_count_{0}; uint32_t rx_count_{0}; // Direct TX hook for tests that want to bypass the response-matching logic std::function &)> tx_hook_; }; } // namespace esphome::uart_mock