Files
esphome/tests/integration/fixtures/external_components/uart_mock/uart_mock.h
2026-03-23 01:55:14 -05:00

104 lines
3.6 KiB
C++

#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 <deque>
#include <vector>
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<uint8_t> &rx_data, uint32_t delay_ms);
void add_response(const std::vector<uint8_t> &expect_tx, const std::vector<uint8_t> &inject_rx,
uint32_t delay_ms = 0);
void add_periodic_rx(const std::vector<uint8_t> &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<void(const std::vector<uint8_t> &)> &&cb) { this->tx_hook_ = std::move(cb); }
void inject_to_rx_buffer(const std::vector<uint8_t> &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<uint8_t> &data, uint32_t delay_ms);
protected:
void check_logger_conflict() override {}
void try_match_response_();
// Timed injections
struct Injection {
std::vector<uint8_t> rx_data;
uint32_t delay_ms;
};
std::vector<Injection> 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<uint8_t> expect_tx;
std::vector<uint8_t> inject_rx;
uint32_t delay_ms;
uint32_t last_match_ms{0};
};
std::vector<Response> responses_;
std::vector<uint8_t> tx_buffer_;
// RX buffer
std::deque<uint8_t> rx_buffer_;
// Periodic RX
struct PeriodicRx {
std::vector<uint8_t> data;
uint32_t interval_ms;
uint32_t last_inject_ms{0};
};
std::vector<PeriodicRx> 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<uint8_t> data;
uint32_t available_at_ms; // millis() time when bytes become available
};
std::deque<StagedRx> 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<void(const std::vector<uint8_t> &)> tx_hook_;
};
} // namespace esphome::uart_mock