mirror of
https://github.com/esphome/esphome.git
synced 2026-06-24 16:20:42 +00:00
104 lines
3.6 KiB
C++
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
|