feat: add application controller handling and DALI control device commands
Signed-off-by: Tony <tonylu@tony-cloud.com>
This commit is contained in:
@@ -22,6 +22,7 @@ Dali_msg_t dali_msg_new_generic(uint8_t bit_length, uint8_t address, uint8_t cmd
|
|||||||
|
|
||||||
// create standard DALI message: 16,24,32 bits
|
// create standard DALI message: 16,24,32 bits
|
||||||
Dali_msg_t dali_msg_new(uint8_t address, uint8_t cmd1);
|
Dali_msg_t dali_msg_new(uint8_t address, uint8_t cmd1);
|
||||||
|
Dali_msg_t dali_msg_new_1B(uint8_t data);
|
||||||
Dali_msg_t dali_msg_new_3B(uint8_t address, uint8_t cmd1, uint8_t cmd2);
|
Dali_msg_t dali_msg_new_3B(uint8_t address, uint8_t cmd1, uint8_t cmd2);
|
||||||
Dali_msg_t dali_msg_new_4B(uint8_t address, uint8_t cmd1, uint8_t cmd2, uint8_t cmd3);
|
Dali_msg_t dali_msg_new_4B(uint8_t address, uint8_t cmd1, uint8_t cmd2, uint8_t cmd3);
|
||||||
|
|
||||||
@@ -86,4 +87,3 @@ void dali_change_short_address(int addr1, int addr2);
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -140,6 +140,11 @@ class DaliDomainService {
|
|||||||
bool sendRaw(uint8_t gateway_id, uint8_t raw_addr, uint8_t command) const;
|
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;
|
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;
|
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(
|
std::optional<DaliDomainSnapshot> discoverDeviceTypes(
|
||||||
uint8_t gateway_id, int short_address, const std::vector<int>& fallback_types = {},
|
uint8_t gateway_id, int short_address, const std::vector<int>& fallback_types = {},
|
||||||
int max_next_types = 16) const;
|
int max_next_types = 16) const;
|
||||||
@@ -229,4 +234,4 @@ class DaliDomainService {
|
|||||||
TaskHandle_t raw_frame_task_handle_{nullptr};
|
TaskHandle_t raw_frame_task_handle_{nullptr};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace gateway
|
} // namespace gateway
|
||||||
|
|||||||
@@ -25,6 +25,9 @@ namespace {
|
|||||||
constexpr size_t kSerialRxPacketMaxBytes = 8;
|
constexpr size_t kSerialRxPacketMaxBytes = 8;
|
||||||
constexpr UBaseType_t kSerialRxQueueDepth = 8;
|
constexpr UBaseType_t kSerialRxQueueDepth = 8;
|
||||||
constexpr uint32_t kHardwareQueryRawPostSuppressMs = 10;
|
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;
|
portMUX_TYPE s_query_raw_suppress_lock = portMUX_INITIALIZER_UNLOCKED;
|
||||||
uint8_t s_query_raw_suppress_inflight[DALI_PHY_COUNT] = {};
|
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};
|
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,
|
void LogQueryRxPacket(const char* transport, int id, const std::vector<uint8_t>& packet,
|
||||||
const char* note = nullptr) {
|
const char* note = nullptr) {
|
||||||
const unsigned first = packet.size() > 0 ? packet[0] : 0;
|
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);
|
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) {
|
if (data == nullptr || len != 3) {
|
||||||
return false;
|
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) {
|
if (data[0] == 0x00) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -186,6 +265,9 @@ std::vector<uint8_t> TransactHardwareFrame(uint8_t bus_id, const uint8_t* data,
|
|||||||
if (data == nullptr) {
|
if (data == nullptr) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
if (len == 4 && data[0] == kControlDeviceQueryOpcode) {
|
||||||
|
return TransactHardwareControlDeviceFrame(bus_id, data + 1, 3);
|
||||||
|
}
|
||||||
if (len != 3) {
|
if (len != 3) {
|
||||||
if (len > 0 && data[0] == 0x12) {
|
if (len > 0 && data[0] == 0x12) {
|
||||||
const auto packet = LegacyQueryResponse(0xFD);
|
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");
|
LogQueryRxPacket("serial", uart_port, packet, "empty-query");
|
||||||
return packet;
|
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);
|
const auto packet = LegacyQueryResponse(0xFD);
|
||||||
LogQueryRxPacket("serial", uart_port, packet, "invalid-query-len");
|
LogQueryRxPacket("serial", uart_port, packet, "invalid-query-len");
|
||||||
return packet;
|
return packet;
|
||||||
}
|
}
|
||||||
if (data != nullptr && len > 0 && data[0] == 0x12) {
|
if (query_frame) {
|
||||||
DrainSerialQueue(queue);
|
DrainSerialQueue(queue);
|
||||||
}
|
}
|
||||||
if (!WriteSerialFrame(uart_port, data, len)) {
|
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");
|
LogQueryRxPacket("serial", uart_port, packet, "write-failed");
|
||||||
return packet;
|
return packet;
|
||||||
}
|
}
|
||||||
if (data[0] != 0x12) {
|
if (!query_frame) {
|
||||||
return {0xFF};
|
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);
|
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(
|
std::optional<DaliDomainSnapshot> DaliDomainService::discoverDeviceTypes(
|
||||||
uint8_t gateway_id, int short_address, const std::vector<int>& fallback_types,
|
uint8_t gateway_id, int short_address, const std::vector<int>& fallback_types,
|
||||||
int max_next_types) const {
|
int max_next_types) const {
|
||||||
@@ -1682,4 +1830,4 @@ bool DaliDomainService::hasSerialPort(int uart_port) const {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace gateway
|
} // namespace gateway
|
||||||
|
|||||||
@@ -144,6 +144,9 @@ class GatewayController {
|
|||||||
void publishPayload(uint8_t gateway_id, const std::vector<uint8_t>& payload);
|
void publishPayload(uint8_t gateway_id, const std::vector<uint8_t>& payload);
|
||||||
void publishFrame(const std::vector<uint8_t>& frame);
|
void publishFrame(const std::vector<uint8_t>& frame);
|
||||||
void handleDaliRawFrame(const DaliRawFrame& frame);
|
void handleDaliRawFrame(const DaliRawFrame& frame);
|
||||||
|
bool handleApplicationControllerFrame(const DaliRawFrame& frame);
|
||||||
|
std::optional<uint8_t> applicationControllerResponse(uint8_t gateway_id, uint8_t first,
|
||||||
|
uint8_t instance, uint8_t opcode) const;
|
||||||
|
|
||||||
bool sendRawAndMirror(uint8_t gateway_id, uint8_t raw_addr, uint8_t command);
|
bool sendRawAndMirror(uint8_t gateway_id, uint8_t raw_addr, uint8_t command);
|
||||||
bool sendExtRawAndMirror(uint8_t gateway_id, uint8_t raw_addr, uint8_t command);
|
bool sendExtRawAndMirror(uint8_t gateway_id, uint8_t raw_addr, uint8_t command);
|
||||||
@@ -207,6 +210,14 @@ class GatewayController {
|
|||||||
bool ble_enabled_{false};
|
bool ble_enabled_{false};
|
||||||
bool wifi_enabled_{false};
|
bool wifi_enabled_{false};
|
||||||
bool ip_router_enabled_{true};
|
bool ip_router_enabled_{true};
|
||||||
|
bool application_controller_enabled_{true};
|
||||||
|
bool application_controller_power_cycle_notification_{true};
|
||||||
|
bool application_controller_power_cycle_seen_{true};
|
||||||
|
bool application_controller_reset_state_{false};
|
||||||
|
uint8_t application_controller_operating_mode_{0};
|
||||||
|
uint8_t application_controller_dtr0_{0};
|
||||||
|
uint8_t application_controller_dtr1_{0};
|
||||||
|
uint8_t application_controller_dtr2_{0};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace gateway
|
} // namespace gateway
|
||||||
|
|||||||
@@ -28,6 +28,12 @@ constexpr uint8_t kBridgeTransportRequestOpcode = 0xB0;
|
|||||||
constexpr uint8_t kBridgeTransportResponseOpcode = 0xB1;
|
constexpr uint8_t kBridgeTransportResponseOpcode = 0xB1;
|
||||||
constexpr uint8_t kBridgeTransportVersion = 1;
|
constexpr uint8_t kBridgeTransportVersion = 1;
|
||||||
constexpr size_t kBridgeTransportMaxChunkBytes = 120;
|
constexpr size_t kBridgeTransportMaxChunkBytes = 120;
|
||||||
|
constexpr uint8_t kDali103SendOpcode = 0x60;
|
||||||
|
constexpr uint8_t kDali103SendTwiceOpcode = 0x61;
|
||||||
|
constexpr uint8_t kDali103QueryOpcode = 0x62;
|
||||||
|
constexpr uint8_t kDali103QueryResponseOpcode = 0x63;
|
||||||
|
constexpr uint8_t kDali103NoResponseOpcode = 0x64;
|
||||||
|
constexpr uint8_t kDali103RawFrameOpcode = 0x65;
|
||||||
constexpr uint8_t kGatewayFeatureCache = 0x40;
|
constexpr uint8_t kGatewayFeatureCache = 0x40;
|
||||||
constexpr uint8_t kGatewayCacheOpcode = 0x39;
|
constexpr uint8_t kGatewayCacheOpcode = 0x39;
|
||||||
constexpr uint8_t kGatewayCacheProtocolVersion = 1;
|
constexpr uint8_t kGatewayCacheProtocolVersion = 1;
|
||||||
@@ -106,6 +112,9 @@ bool IsDaliHostCommandOpcode(uint8_t opcode) {
|
|||||||
case 0x32:
|
case 0x32:
|
||||||
case 0x37:
|
case 0x37:
|
||||||
case 0x38:
|
case 0x38:
|
||||||
|
case kDali103SendOpcode:
|
||||||
|
case kDali103SendTwiceOpcode:
|
||||||
|
case kDali103QueryOpcode:
|
||||||
case 0xA0:
|
case 0xA0:
|
||||||
case 0xA2:
|
case 0xA2:
|
||||||
case kBridgeTransportRequestOpcode:
|
case kBridgeTransportRequestOpcode:
|
||||||
@@ -933,6 +942,24 @@ void GatewayController::dispatchCommand(const std::vector<uint8_t>& command) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case kDali103SendOpcode:
|
||||||
|
case kDali103SendTwiceOpcode:
|
||||||
|
if (command.size() >= 8) {
|
||||||
|
dali_domain_.sendControlDeviceRaw(gateway_id, command[4], command[5], command[6],
|
||||||
|
opcode == kDali103SendTwiceOpcode);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case kDali103QueryOpcode:
|
||||||
|
if (command.size() >= 8) {
|
||||||
|
const auto result =
|
||||||
|
dali_domain_.queryControlDeviceRaw(gateway_id, command[4], command[5], command[6]);
|
||||||
|
if (result.has_value()) {
|
||||||
|
publishPayload(gateway_id, {kDali103QueryResponseOpcode, gateway_id, result.value()});
|
||||||
|
} else {
|
||||||
|
publishPayload(gateway_id, {kDali103NoResponseOpcode, gateway_id, 0x00});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
case kGatewayCacheOpcode:
|
case kGatewayCacheOpcode:
|
||||||
handleGatewayCacheCommand(gateway_id, command);
|
handleGatewayCacheCommand(gateway_id, command);
|
||||||
break;
|
break;
|
||||||
@@ -1036,6 +1063,160 @@ void GatewayController::publishFrame(const std::vector<uint8_t>& frame) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<uint8_t> GatewayController::applicationControllerResponse(
|
||||||
|
uint8_t gateway_id, uint8_t first, uint8_t instance, uint8_t opcode) const {
|
||||||
|
const uint8_t gateway_short =
|
||||||
|
static_cast<uint8_t>(((gateway_id & 0x3F) << 1) | 0x01);
|
||||||
|
const bool addressed_to_gateway = first == 0xFF || first == gateway_short;
|
||||||
|
if (!addressed_to_gateway || instance != 0xFE) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (opcode) {
|
||||||
|
case 0x30: {
|
||||||
|
uint8_t status = 0;
|
||||||
|
if (application_controller_enabled_) {
|
||||||
|
status |= 0x08;
|
||||||
|
}
|
||||||
|
if (application_controller_power_cycle_seen_) {
|
||||||
|
status |= 0x20;
|
||||||
|
}
|
||||||
|
if (application_controller_reset_state_) {
|
||||||
|
status |= 0x40;
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
case 0x31:
|
||||||
|
case 0x32:
|
||||||
|
case 0x33:
|
||||||
|
return 0x00;
|
||||||
|
case 0x34:
|
||||||
|
return 0x02;
|
||||||
|
case 0x35:
|
||||||
|
return 0x00;
|
||||||
|
case 0x36:
|
||||||
|
return application_controller_dtr0_;
|
||||||
|
case 0x37:
|
||||||
|
return application_controller_dtr1_;
|
||||||
|
case 0x38:
|
||||||
|
return application_controller_dtr2_;
|
||||||
|
case 0x39:
|
||||||
|
case 0x3A:
|
||||||
|
case 0x3B:
|
||||||
|
return 0x00;
|
||||||
|
case 0x3C:
|
||||||
|
return 0xFF;
|
||||||
|
case 0x3D:
|
||||||
|
return static_cast<uint8_t>(application_controller_enabled_ ? 1 : 0);
|
||||||
|
case 0x3E:
|
||||||
|
return application_controller_operating_mode_;
|
||||||
|
case 0x3F:
|
||||||
|
case 0x40:
|
||||||
|
case 0x41:
|
||||||
|
case 0x42:
|
||||||
|
case 0x43:
|
||||||
|
case 0x44:
|
||||||
|
return 0x00;
|
||||||
|
case 0x45:
|
||||||
|
return static_cast<uint8_t>(application_controller_power_cycle_notification_ ? 1 : 0);
|
||||||
|
case 0x46:
|
||||||
|
return 0x01;
|
||||||
|
case 0x47:
|
||||||
|
return 0x01;
|
||||||
|
case 0x48:
|
||||||
|
return static_cast<uint8_t>(application_controller_reset_state_ ? 1 : 0);
|
||||||
|
default:
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GatewayController::handleApplicationControllerFrame(const DaliRawFrame& frame) {
|
||||||
|
if (frame.data.size() != 3) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t first = frame.data[0];
|
||||||
|
const uint8_t instance = frame.data[1];
|
||||||
|
const uint8_t opcode = frame.data[2];
|
||||||
|
|
||||||
|
if (first == 0xC1) {
|
||||||
|
switch (instance) {
|
||||||
|
case 0x30:
|
||||||
|
application_controller_dtr0_ = opcode;
|
||||||
|
break;
|
||||||
|
case 0x31:
|
||||||
|
application_controller_dtr1_ = opcode;
|
||||||
|
break;
|
||||||
|
case 0x32:
|
||||||
|
application_controller_dtr2_ = opcode;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((first & 0x01) == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t gateway_short =
|
||||||
|
static_cast<uint8_t>(((frame.gateway_id & 0x3F) << 1) | 0x01);
|
||||||
|
if (first != 0xFF && first != gateway_short) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (instance != 0xFE) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (opcode) {
|
||||||
|
case 0x01:
|
||||||
|
application_controller_power_cycle_seen_ = false;
|
||||||
|
application_controller_reset_state_ = false;
|
||||||
|
break;
|
||||||
|
case 0x10:
|
||||||
|
application_controller_enabled_ = true;
|
||||||
|
application_controller_power_cycle_notification_ = true;
|
||||||
|
application_controller_reset_state_ = true;
|
||||||
|
application_controller_operating_mode_ = 0;
|
||||||
|
application_controller_dtr0_ = 0;
|
||||||
|
application_controller_dtr1_ = 0;
|
||||||
|
application_controller_dtr2_ = 0;
|
||||||
|
break;
|
||||||
|
case 0x16:
|
||||||
|
application_controller_enabled_ = true;
|
||||||
|
application_controller_reset_state_ = false;
|
||||||
|
break;
|
||||||
|
case 0x17:
|
||||||
|
application_controller_enabled_ = false;
|
||||||
|
application_controller_reset_state_ = false;
|
||||||
|
break;
|
||||||
|
case 0x18:
|
||||||
|
application_controller_operating_mode_ = application_controller_dtr0_;
|
||||||
|
application_controller_reset_state_ = false;
|
||||||
|
break;
|
||||||
|
case 0x1F:
|
||||||
|
application_controller_power_cycle_notification_ = true;
|
||||||
|
application_controller_reset_state_ = false;
|
||||||
|
break;
|
||||||
|
case 0x20:
|
||||||
|
application_controller_power_cycle_notification_ = false;
|
||||||
|
application_controller_reset_state_ = false;
|
||||||
|
break;
|
||||||
|
case 0x21:
|
||||||
|
application_controller_reset_state_ = false;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto response = applicationControllerResponse(frame.gateway_id, first, instance, opcode);
|
||||||
|
if (!response.has_value()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return dali_domain_.sendBackwardFrame(frame.gateway_id, response.value());
|
||||||
|
}
|
||||||
|
|
||||||
void GatewayController::handleBridgeTransportCommand(uint8_t gateway_id,
|
void GatewayController::handleBridgeTransportCommand(uint8_t gateway_id,
|
||||||
const std::vector<uint8_t>& command) {
|
const std::vector<uint8_t>& command) {
|
||||||
const uint8_t version = command.size() > 4 ? command[4] : kBridgeTransportVersion;
|
const uint8_t version = command.size() > 4 ? command[4] : kBridgeTransportVersion;
|
||||||
@@ -1119,6 +1300,20 @@ void GatewayController::handleDaliRawFrame(const DaliRawFrame& frame) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (frame.data.size() == 3 &&
|
||||||
|
(((frame.data[0] & 0x01) != 0) || frame.data[0] == 0xC1)) {
|
||||||
|
handleApplicationControllerFrame(frame);
|
||||||
|
const bool maintenance_activity = maintenance_activity_gateway_.load() == frame.gateway_id;
|
||||||
|
if (setup_mode_ || dali_domain_.isAllocAddr(frame.gateway_id) || maintenance_activity ||
|
||||||
|
runtime_.hasActiveQueryCommand(frame.gateway_id)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
publishPayload(frame.gateway_id,
|
||||||
|
{kDali103RawFrameOpcode, frame.gateway_id, frame.data[0], frame.data[1],
|
||||||
|
frame.data[2]});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t addr = 0;
|
uint8_t addr = 0;
|
||||||
uint8_t data = 0;
|
uint8_t data = 0;
|
||||||
if (frame.data.size() == 2) {
|
if (frame.data.size() == 2) {
|
||||||
|
|||||||
@@ -324,7 +324,7 @@ GatewayRuntime::CommandPriority GatewayRuntime::classifyCommandPriority(
|
|||||||
if (opcode == 0x00 || opcode == 0x01 || opcode == 0x03 || opcode == 0x04 || opcode == 0x07 ||
|
if (opcode == 0x00 || opcode == 0x01 || opcode == 0x03 || opcode == 0x04 || opcode == 0x07 ||
|
||||||
opcode == 0x08 || opcode == 0x10 || opcode == 0x11 || opcode == 0x12 || opcode == 0x13 ||
|
opcode == 0x08 || opcode == 0x10 || opcode == 0x11 || opcode == 0x12 || opcode == 0x13 ||
|
||||||
opcode == 0x17 || opcode == 0x18 || opcode == 0x37 || opcode == 0x38 ||
|
opcode == 0x17 || opcode == 0x18 || opcode == 0x37 || opcode == 0x38 ||
|
||||||
(opcode == 0x30 && addr == 0)) {
|
opcode == 0x60 || opcode == 0x61 || opcode == 0x62 || (opcode == 0x30 && addr == 0)) {
|
||||||
return CommandPriority::kControl;
|
return CommandPriority::kControl;
|
||||||
}
|
}
|
||||||
return CommandPriority::kNormal;
|
return CommandPriority::kNormal;
|
||||||
@@ -597,8 +597,8 @@ std::string GatewayRuntime::defaultBleGatewayName() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool GatewayRuntime::isQueryCommand(const std::vector<uint8_t>& command) const {
|
bool GatewayRuntime::isQueryCommand(const std::vector<uint8_t>& command) const {
|
||||||
return command.size() >= 6 && isGatewayCommandFrame(command) && command[3] >= 0x14 &&
|
return command.size() >= 6 && isGatewayCommandFrame(command) &&
|
||||||
command[3] <= 0x16;
|
((command[3] >= 0x14 && command[3] <= 0x16) || command[3] == 0x62);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t GatewayRuntime::pendingCommandCountLocked() const {
|
size_t GatewayRuntime::pendingCommandCountLocked() const {
|
||||||
@@ -639,6 +639,15 @@ std::optional<std::string> GatewayRuntime::queryCommandKey(
|
|||||||
|
|
||||||
const auto gw = command[2];
|
const auto gw = command[2];
|
||||||
const auto cmd = command[3];
|
const auto cmd = command[3];
|
||||||
|
if (cmd == 0x62) {
|
||||||
|
if (command.size() < 8) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
char key[40] = {0};
|
||||||
|
std::snprintf(key, sizeof(key), "%u:%u:%u:%u:%u", gw, cmd, command[4], command[5],
|
||||||
|
command[6]);
|
||||||
|
return std::string(key);
|
||||||
|
}
|
||||||
if (cmd == 0x16) {
|
if (cmd == 0x16) {
|
||||||
char key[16] = {0};
|
char key[16] = {0};
|
||||||
std::snprintf(key, sizeof(key), "%u:%u", gw, cmd);
|
std::snprintf(key, sizeof(key), "%u:%u", gw, cmd);
|
||||||
@@ -688,4 +697,4 @@ std::string GatewayRuntime::toHex(const std::vector<uint8_t>& bytes) {
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace gateway
|
} // namespace gateway
|
||||||
|
|||||||
Reference in New Issue
Block a user