feat: add application controller handling and DALI control device commands
Signed-off-by: Tony <tonylu@tony-cloud.com>
This commit is contained in:
@@ -28,6 +28,12 @@ constexpr uint8_t kBridgeTransportRequestOpcode = 0xB0;
|
||||
constexpr uint8_t kBridgeTransportResponseOpcode = 0xB1;
|
||||
constexpr uint8_t kBridgeTransportVersion = 1;
|
||||
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 kGatewayCacheOpcode = 0x39;
|
||||
constexpr uint8_t kGatewayCacheProtocolVersion = 1;
|
||||
@@ -106,6 +112,9 @@ bool IsDaliHostCommandOpcode(uint8_t opcode) {
|
||||
case 0x32:
|
||||
case 0x37:
|
||||
case 0x38:
|
||||
case kDali103SendOpcode:
|
||||
case kDali103SendTwiceOpcode:
|
||||
case kDali103QueryOpcode:
|
||||
case 0xA0:
|
||||
case 0xA2:
|
||||
case kBridgeTransportRequestOpcode:
|
||||
@@ -933,6 +942,24 @@ void GatewayController::dispatchCommand(const std::vector<uint8_t>& command) {
|
||||
}
|
||||
}
|
||||
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:
|
||||
handleGatewayCacheCommand(gateway_id, command);
|
||||
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,
|
||||
const std::vector<uint8_t>& command) {
|
||||
const uint8_t version = command.size() > 4 ? command[4] : kBridgeTransportVersion;
|
||||
@@ -1119,6 +1300,20 @@ void GatewayController::handleDaliRawFrame(const DaliRawFrame& frame) {
|
||||
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 data = 0;
|
||||
if (frame.data.size() == 2) {
|
||||
|
||||
Reference in New Issue
Block a user