feat: add application controller handling and DALI control device commands
Signed-off-by: Tony <tonylu@tony-cloud.com>
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user