mirror of
https://github.com/esphome/esphome.git
synced 2026-10-09 21:13:12 +00:00
77 lines
2.7 KiB
C++
77 lines
2.7 KiB
C++
#pragma once
|
|
#include <initializer_list>
|
|
#include <utility>
|
|
#include <gtest/gtest.h>
|
|
#include "esphome/components/hoermann_hcp/hoermann_hcp.h"
|
|
|
|
namespace esphome::hoermann_hcp::testing {
|
|
|
|
using modbus::RegisterValues;
|
|
|
|
// Register block addresses the Hoermann bus controller polls (see hoermann_hcp.cpp).
|
|
constexpr uint16_t COMMAND_REG = 0x9C41;
|
|
constexpr uint16_t STATE_REG = 0x9CB9;
|
|
constexpr uint16_t BROADCAST_REG = 0x9D31;
|
|
// The lamp commands a status answer carries in its two command registers.
|
|
constexpr uint16_t LIGHT_ON = 0x0880;
|
|
constexpr uint16_t LIGHT_ON_2 = 0x0000;
|
|
constexpr uint16_t LIGHT_OFF = 0x0800;
|
|
constexpr uint16_t LIGHT_OFF_2 = 0x0100;
|
|
|
|
inline RegisterValues make_registers(std::initializer_list<uint16_t> values) {
|
|
RegisterValues registers;
|
|
for (uint16_t value : values)
|
|
registers.push_back(value);
|
|
return registers;
|
|
}
|
|
|
|
// A status broadcast carrying the lamp register, which the door reports at index 6.
|
|
inline RegisterValues lamp_broadcast(uint16_t lamp_reg) {
|
|
return make_registers({0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, lamp_reg});
|
|
}
|
|
|
|
// The door only accepts commands once the bus controller has actually talked to it.
|
|
inline void connect_controller(HoermannHcp &door) {
|
|
door.on_write_registers(COMMAND_REG, make_registers({0x0000, 0x0000}));
|
|
}
|
|
|
|
// Runs one status poll (write 2 / read 8) and returns the whole answer.
|
|
inline RegisterValues status_answer(HoermannHcp &door, uint16_t command_reg = 0x0003) {
|
|
door.on_write_registers(COMMAND_REG, make_registers({command_reg, 0x0000}));
|
|
RegisterValues response;
|
|
door.on_read_holding_registers(STATE_REG, 8, response);
|
|
return response;
|
|
}
|
|
|
|
// Runs one status poll and returns both command registers.
|
|
inline std::pair<uint16_t, uint16_t> poll_command(HoermannHcp &door) {
|
|
const RegisterValues response = status_answer(door);
|
|
EXPECT_EQ(response.size(), 8u);
|
|
if (response.size() != 8u)
|
|
return {0xFFFF, 0xFFFF};
|
|
return {response[2], response[3]};
|
|
}
|
|
|
|
// Lets the controller fetch the queued command, leaving the slot free.
|
|
inline void consume_command(HoermannHcp &door) { poll_command(door); }
|
|
|
|
// Exposes the internal timings and the connection bookkeeping, so no test has to wait out a real delay.
|
|
class TestableHoermannHcp : public HoermannHcp {
|
|
public:
|
|
using HoermannHcp::connection_timeout_ms_;
|
|
using HoermannHcp::start_window_ms_;
|
|
#ifdef USE_HOERMANN_HCP_IDENTITY
|
|
using HoermannHcp::identity_asked_at_;
|
|
using HoermannHcp::identity_request_;
|
|
using HoermannHcp::firmware_unreadable_;
|
|
using HoermannHcp::serial_unreadable_;
|
|
#endif
|
|
using HoermannHcp::last_stop_at_;
|
|
using HoermannHcp::light_requested_;
|
|
using HoermannHcp::light_since_;
|
|
using HoermannHcp::light_command_sent_;
|
|
using HoermannHcp::set_valid_;
|
|
};
|
|
|
|
} // namespace esphome::hoermann_hcp::testing
|