feat: add application controller handling and DALI control device commands

Signed-off-by: Tony <tonylu@tony-cloud.com>
This commit is contained in:
Tony
2026-06-11 18:46:32 +08:00
parent 1342ab6aaf
commit 6ffca719d9
6 changed files with 379 additions and 11 deletions
@@ -140,6 +140,11 @@ class DaliDomainService {
bool sendRaw(uint8_t gateway_id, uint8_t raw_addr, uint8_t command) const;
bool sendExtRaw(uint8_t gateway_id, uint8_t raw_addr, uint8_t command) const;
std::optional<uint8_t> queryRaw(uint8_t gateway_id, uint8_t raw_addr, uint8_t command) const;
bool sendControlDeviceRaw(uint8_t gateway_id, uint8_t byte0, uint8_t byte1, uint8_t byte2,
bool send_twice = false) const;
std::optional<uint8_t> queryControlDeviceRaw(uint8_t gateway_id, uint8_t byte0,
uint8_t byte1, uint8_t byte2) const;
bool sendBackwardFrame(uint8_t gateway_id, uint8_t value) const;
std::optional<DaliDomainSnapshot> discoverDeviceTypes(
uint8_t gateway_id, int short_address, const std::vector<int>& fallback_types = {},
int max_next_types = 16) const;
@@ -229,4 +234,4 @@ class DaliDomainService {
TaskHandle_t raw_frame_task_handle_{nullptr};
};
} // namespace gateway
} // namespace gateway
+153 -5
View File
@@ -25,6 +25,9 @@ namespace {
constexpr size_t kSerialRxPacketMaxBytes = 8;
constexpr UBaseType_t kSerialRxQueueDepth = 8;
constexpr uint32_t kHardwareQueryRawPostSuppressMs = 10;
constexpr uint8_t kControlDeviceSendOpcode = 0x60;
constexpr uint8_t kControlDeviceSendTwiceOpcode = 0x61;
constexpr uint8_t kControlDeviceQueryOpcode = 0x62;
portMUX_TYPE s_query_raw_suppress_lock = portMUX_INITIALIZER_UNLOCKED;
uint8_t s_query_raw_suppress_inflight[DALI_PHY_COUNT] = {};
@@ -146,6 +149,13 @@ std::vector<uint8_t> LegacyQueryResponse(uint8_t status, uint8_t value = 0x00) {
return {status, value};
}
std::optional<uint8_t> ParseLegacyQueryValue(const std::vector<uint8_t>& packet) {
if (packet.size() >= 2 && packet[0] == 0xFF) {
return packet[1];
}
return std::nullopt;
}
void LogQueryRxPacket(const char* transport, int id, const std::vector<uint8_t>& packet,
const char* note = nullptr) {
const unsigned first = packet.size() > 0 ? packet[0] : 0;
@@ -156,11 +166,80 @@ void LogQueryRxPacket(const char* transport, int id, const std::vector<uint8_t>&
note == nullptr ? "" : " note=", note == nullptr ? "" : note);
}
bool SendHardwareFrame(uint8_t bus_id, const uint8_t* data, size_t len) {
bool SendHardwareControlDeviceFrame(uint8_t bus_id, const uint8_t* data, size_t len,
bool send_twice) {
if (data == nullptr || len != 3) {
return false;
}
Dali_msg_t tx = dali_msg_new_3B(data[0], data[1], data[2]);
tx.id = bus_id;
ESP_LOGD(TAG, "sending hardware control-device frame for bus=%u data=%02x %02x %02x",
bus_id, data[0], data[1], data[2]);
if (send_twice) {
dali_send_double(&tx);
} else {
dali_send(&tx);
}
return tx.status == DALI_FRAME_OK;
}
std::vector<uint8_t> TransactHardwareControlDeviceFrame(uint8_t bus_id, const uint8_t* data,
size_t len) {
if (data == nullptr || len != 3) {
const auto packet = LegacyQueryResponse(0xFD);
LogQueryRxPacket("hardware-cd", bus_id, packet, "invalid-query-len");
return packet;
}
Dali_msg_t tx = dali_msg_new_3B(data[0], data[1], data[2]);
tx.id = bus_id;
Dali_msg_t rx = {};
ESP_LOGD(TAG, "received hardware control-device query for bus=%u data=%02x %02x %02x",
bus_id, data[0], data[1], data[2]);
BeginHardwareQueryRawSuppress(bus_id);
if (dali_query(&tx, &rx) == pdTRUE) {
ClearHardwareQueryRawSuppress(bus_id);
if (rx.status != DALI_FRAME_OK || rx.length != 8) {
ESP_LOGW(TAG, "hardware control-device query response for bus=%u has invalid status or length",
bus_id);
const auto packet = LegacyQueryResponse(0xFD);
LogQueryRxPacket("hardware-cd", bus_id, packet, "invalid-status-or-length");
return packet;
}
const std::vector<uint8_t> packet{0xFF, rx.data[0]};
LogQueryRxPacket("hardware-cd", bus_id, packet, "ok");
return packet;
}
ClearHardwareQueryRawSuppress(bus_id);
const auto packet = LegacyQueryResponse(0xFE);
LogQueryRxPacket("hardware-cd", bus_id, packet, "no-response");
return packet;
}
bool SendHardwareBackwardFrame(uint8_t bus_id, uint8_t value) {
Dali_msg_t tx = dali_msg_new_1B(value);
tx.id = bus_id;
ESP_LOGD(TAG, "sending hardware backward frame for bus=%u data=%02x", bus_id, value);
dali_send(&tx);
return tx.status == DALI_FRAME_OK;
}
bool SendHardwareFrame(uint8_t bus_id, const uint8_t* data, size_t len) {
if (data == nullptr) {
return false;
}
if (len == 4 && (data[0] == kControlDeviceSendOpcode ||
data[0] == kControlDeviceSendTwiceOpcode)) {
return SendHardwareControlDeviceFrame(bus_id, data + 1, 3,
data[0] == kControlDeviceSendTwiceOpcode);
}
if (len != 3) {
return false;
}
if (data[0] == 0x00) {
return true;
}
@@ -186,6 +265,9 @@ std::vector<uint8_t> TransactHardwareFrame(uint8_t bus_id, const uint8_t* data,
if (data == nullptr) {
return {};
}
if (len == 4 && data[0] == kControlDeviceQueryOpcode) {
return TransactHardwareControlDeviceFrame(bus_id, data + 1, 3);
}
if (len != 3) {
if (len > 0 && data[0] == 0x12) {
const auto packet = LegacyQueryResponse(0xFD);
@@ -276,12 +358,14 @@ std::vector<uint8_t> TransactSerialFrame(int uart_port, QueueHandle_t queue,
LogQueryRxPacket("serial", uart_port, packet, "empty-query");
return packet;
}
if (data[0] == 0x12 && len != 3) {
const bool query_frame = data[0] == 0x12 || data[0] == kControlDeviceQueryOpcode;
const size_t expected_query_len = data[0] == kControlDeviceQueryOpcode ? 4 : 3;
if (query_frame && len != expected_query_len) {
const auto packet = LegacyQueryResponse(0xFD);
LogQueryRxPacket("serial", uart_port, packet, "invalid-query-len");
return packet;
}
if (data != nullptr && len > 0 && data[0] == 0x12) {
if (query_frame) {
DrainSerialQueue(queue);
}
if (!WriteSerialFrame(uart_port, data, len)) {
@@ -289,7 +373,7 @@ std::vector<uint8_t> TransactSerialFrame(int uart_port, QueueHandle_t queue,
LogQueryRxPacket("serial", uart_port, packet, "write-failed");
return packet;
}
if (data[0] != 0x12) {
if (!query_frame) {
return {0xFF};
}
@@ -721,6 +805,70 @@ std::optional<uint8_t> DaliDomainService::queryRaw(uint8_t gateway_id, uint8_t r
return channel->comm->queryRawNew(raw_addr, command);
}
bool DaliDomainService::sendControlDeviceRaw(uint8_t gateway_id, uint8_t byte0, uint8_t byte1,
uint8_t byte2, bool send_twice) const {
const auto* channel = findChannelByGateway(gateway_id);
if (channel == nullptr) {
return false;
}
const uint8_t frame[3] = {byte0, byte1, byte2};
markHostActivity(gateway_id);
markBusActivity(gateway_id);
if (channel->hardware_bus.has_value()) {
return SendHardwareControlDeviceFrame(channel->hardware_bus->bus_id, frame, sizeof(frame),
send_twice);
}
if (!channel->hooks.send) {
return false;
}
const uint8_t bridge_frame[4] = {
static_cast<uint8_t>(send_twice ? kControlDeviceSendTwiceOpcode : kControlDeviceSendOpcode),
byte0,
byte1,
byte2,
};
return channel->hooks.send(bridge_frame, sizeof(bridge_frame));
}
std::optional<uint8_t> DaliDomainService::queryControlDeviceRaw(uint8_t gateway_id, uint8_t byte0,
uint8_t byte1,
uint8_t byte2) const {
const auto* channel = findChannelByGateway(gateway_id);
if (channel == nullptr) {
return std::nullopt;
}
const uint8_t frame[3] = {byte0, byte1, byte2};
markHostActivity(gateway_id);
markBusActivity(gateway_id);
if (channel->hardware_bus.has_value()) {
return ParseLegacyQueryValue(
TransactHardwareControlDeviceFrame(channel->hardware_bus->bus_id, frame, sizeof(frame)));
}
if (!channel->hooks.transact) {
return std::nullopt;
}
const uint8_t bridge_frame[4] = {kControlDeviceQueryOpcode, byte0, byte1, byte2};
return ParseLegacyQueryValue(channel->hooks.transact(bridge_frame, sizeof(bridge_frame)));
}
bool DaliDomainService::sendBackwardFrame(uint8_t gateway_id, uint8_t value) const {
const auto* channel = findChannelByGateway(gateway_id);
if (channel == nullptr) {
return false;
}
markBusActivity(gateway_id);
if (channel->hardware_bus.has_value()) {
return SendHardwareBackwardFrame(channel->hardware_bus->bus_id, value);
}
if (!channel->hooks.send) {
return false;
}
return channel->hooks.send(&value, 1);
}
std::optional<DaliDomainSnapshot> DaliDomainService::discoverDeviceTypes(
uint8_t gateway_id, int short_address, const std::vector<int>& fallback_types,
int max_next_types) const {
@@ -1682,4 +1830,4 @@ bool DaliDomainService::hasSerialPort(int uart_port) const {
});
}
} // namespace gateway
} // namespace gateway