feat: enhance gateway channel management with serial command handling and gateway ID updates
Signed-off-by: Tony <tonylu@tony-cloud.com>
This commit is contained in:
@@ -139,6 +139,7 @@ class GatewayController {
|
||||
|
||||
bool hasGateway(uint8_t gateway_id) const;
|
||||
std::vector<uint8_t> gatewayIds() const;
|
||||
std::optional<uint8_t> gatewayIdForChannelNumber(uint8_t channel_number) const;
|
||||
std::string gatewayName(uint8_t gateway_id) const;
|
||||
void refreshRuntimeGatewayNames();
|
||||
void publishPayload(uint8_t gateway_id, const std::vector<uint8_t>& payload);
|
||||
@@ -181,6 +182,11 @@ class GatewayController {
|
||||
bool executeGroup(uint8_t gateway_id, uint8_t group_id);
|
||||
|
||||
void handleGatewayNameCommand(uint8_t gateway_id, const std::vector<uint8_t>& command);
|
||||
void handleGatewaySerialCommand(uint8_t channel_number, const std::vector<uint8_t>& command);
|
||||
void publishGatewaySerialReport();
|
||||
void publishGatewaySerialResponse(uint8_t status, uint8_t op,
|
||||
const std::vector<uint8_t>& data);
|
||||
bool gatewaySerialMatches(const std::vector<uint8_t>& command) const;
|
||||
void handleGatewayIdentityCommand(uint8_t gateway_id, uint8_t op);
|
||||
void handleAllocationCommand(uint8_t gateway_id, const std::vector<uint8_t>& command);
|
||||
void handleInternalSceneCommand(uint8_t gateway_id, const std::vector<uint8_t>& command);
|
||||
|
||||
@@ -28,13 +28,23 @@ constexpr uint8_t kBridgeTransportRequestOpcode = 0xB0;
|
||||
constexpr uint8_t kBridgeTransportResponseOpcode = 0xB1;
|
||||
constexpr uint8_t kBridgeTransportVersion = 1;
|
||||
constexpr size_t kBridgeTransportMaxChunkBytes = 120;
|
||||
constexpr uint8_t kGatewaySerialOpcode = 0x0B;
|
||||
constexpr uint8_t kGatewaySerialOpReport = 0x00;
|
||||
constexpr uint8_t kGatewaySerialOpGetChannelId = 0x01;
|
||||
constexpr uint8_t kGatewaySerialOpSetChannelId = 0x02;
|
||||
constexpr uint8_t kGatewaySerialOpDispatchByChannelNumber = 0x03;
|
||||
constexpr uint8_t kGatewaySerialStatusOk = 0x00;
|
||||
constexpr uint8_t kGatewaySerialStatusInvalidArgument = 0x02;
|
||||
constexpr uint8_t kGatewaySerialStatusDuplicateChannelId = 0x03;
|
||||
constexpr uint8_t kGatewaySerialStatusStorageError = 0x04;
|
||||
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 uint16_t kGatewayFeatureCache = 0x0040;
|
||||
constexpr uint16_t kGatewayFeatureNativeCpp = 0x0100;
|
||||
constexpr uint8_t kGatewayCacheOpcode = 0x39;
|
||||
constexpr uint8_t kGatewayCacheProtocolVersion = 1;
|
||||
constexpr uint8_t kGatewayCacheOpSummary = 0x00;
|
||||
@@ -165,6 +175,13 @@ void AppendLe32(std::vector<uint8_t>& out, uint32_t value) {
|
||||
out.push_back(static_cast<uint8_t>((value >> 24) & 0xFF));
|
||||
}
|
||||
|
||||
void AppendFeatureBits(std::vector<uint8_t>& out, uint16_t feature) {
|
||||
if (feature > 0xFF) {
|
||||
out.push_back(static_cast<uint8_t>((feature >> 8) & 0xFF));
|
||||
}
|
||||
out.push_back(static_cast<uint8_t>(feature & 0xFF));
|
||||
}
|
||||
|
||||
uint8_t CacheByte(std::optional<uint8_t> value) {
|
||||
return value.value_or(0xFF);
|
||||
}
|
||||
@@ -759,6 +776,10 @@ void GatewayController::dispatchCommand(const std::vector<uint8_t>& command) {
|
||||
publishPayload(gateway_id, payload);
|
||||
return;
|
||||
}
|
||||
if (opcode == kGatewaySerialOpcode) {
|
||||
handleGatewaySerialCommand(gateway_id, command);
|
||||
return;
|
||||
}
|
||||
if (!hasGateway(gateway_id)) {
|
||||
ESP_LOGW(kTag, "command for unknown gateway=%u opcode=0x%02x", gateway_id, opcode);
|
||||
return;
|
||||
@@ -825,7 +846,7 @@ void GatewayController::dispatchCommand(const std::vector<uint8_t>& command) {
|
||||
handleGatewayNameCommand(gateway_id, command);
|
||||
break;
|
||||
case 0x06: {
|
||||
uint8_t feature = 0;
|
||||
uint16_t feature = kGatewayFeatureNativeCpp;
|
||||
if (setup_mode_ && config_.setup_supported) {
|
||||
feature |= 0x01;
|
||||
}
|
||||
@@ -844,7 +865,9 @@ void GatewayController::dispatchCommand(const std::vector<uint8_t>& command) {
|
||||
if (config_.cache_supported) {
|
||||
feature |= kGatewayFeatureCache;
|
||||
}
|
||||
publishPayload(gateway_id, {0x03, gateway_id, feature});
|
||||
std::vector<uint8_t> payload{0x03, gateway_id};
|
||||
AppendFeatureBits(payload, feature);
|
||||
publishPayload(gateway_id, payload);
|
||||
break;
|
||||
}
|
||||
case 0x07:
|
||||
@@ -995,6 +1018,23 @@ std::vector<uint8_t> GatewayController::gatewayIds() const {
|
||||
return ids;
|
||||
}
|
||||
|
||||
std::optional<uint8_t> GatewayController::gatewayIdForChannelNumber(
|
||||
uint8_t channel_number) const {
|
||||
if (channel_number == 0) {
|
||||
return std::nullopt;
|
||||
}
|
||||
const uint8_t channel_index = static_cast<uint8_t>(channel_number - 1);
|
||||
const auto channels = dali_domain_.channelInfo();
|
||||
const auto it =
|
||||
std::find_if(channels.begin(), channels.end(), [channel_index](const auto& channel) {
|
||||
return channel.channel_index == channel_index;
|
||||
});
|
||||
if (it == channels.end()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return it->gateway_id;
|
||||
}
|
||||
|
||||
std::string GatewayController::gatewayName(uint8_t gateway_id) const {
|
||||
const auto channels = dali_domain_.channelInfo();
|
||||
const auto it = std::find_if(channels.begin(), channels.end(), [gateway_id](const auto& channel) {
|
||||
@@ -1618,6 +1658,117 @@ void GatewayController::handleGatewayNameCommand(uint8_t gateway_id,
|
||||
}
|
||||
}
|
||||
|
||||
void GatewayController::publishGatewaySerialResponse(uint8_t status, uint8_t op,
|
||||
const std::vector<uint8_t>& data) {
|
||||
std::vector<uint8_t> payload{kGatewaySerialOpcode, status};
|
||||
const auto serial = runtime_.serialNumberBytes();
|
||||
payload.insert(payload.end(), serial.begin(), serial.end());
|
||||
payload.push_back(op);
|
||||
payload.insert(payload.end(), data.begin(), data.end());
|
||||
publishPayload(0, payload);
|
||||
}
|
||||
|
||||
bool GatewayController::gatewaySerialMatches(const std::vector<uint8_t>& command) const {
|
||||
if (command.size() < 9) {
|
||||
return false;
|
||||
}
|
||||
const auto serial = runtime_.serialNumberBytes();
|
||||
return command[5] == serial[0] && command[6] == serial[1] && command[7] == serial[2];
|
||||
}
|
||||
|
||||
void GatewayController::publishGatewaySerialReport() {
|
||||
const auto serial = runtime_.serialNumberBytes();
|
||||
std::vector<uint8_t> payload{kGatewaySerialOpcode,
|
||||
kGatewaySerialStatusOk,
|
||||
serial[0],
|
||||
serial[1],
|
||||
serial[2],
|
||||
kGatewaySerialOpReport};
|
||||
const auto channels = dali_domain_.channelInfo();
|
||||
const auto count = std::min<size_t>(channels.size(), 16);
|
||||
payload.push_back(static_cast<uint8_t>(count));
|
||||
for (size_t index = 0; index < count; ++index) {
|
||||
payload.push_back(static_cast<uint8_t>(channels[index].channel_index + 1));
|
||||
payload.push_back(channels[index].gateway_id);
|
||||
}
|
||||
publishPayload(0, payload);
|
||||
}
|
||||
|
||||
void GatewayController::handleGatewaySerialCommand(uint8_t channel_number,
|
||||
const std::vector<uint8_t>& command) {
|
||||
const uint8_t op = command.size() > 4 ? command[4] : kGatewaySerialOpReport;
|
||||
if (op == kGatewaySerialOpReport) {
|
||||
if (command.size() >= 9 && !gatewaySerialMatches(command)) {
|
||||
return;
|
||||
}
|
||||
publishGatewaySerialReport();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!gatewaySerialMatches(command)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto gateway_id = gatewayIdForChannelNumber(channel_number);
|
||||
if (!gateway_id.has_value()) {
|
||||
publishGatewaySerialResponse(kGatewaySerialStatusInvalidArgument, op, {channel_number});
|
||||
return;
|
||||
}
|
||||
|
||||
switch (op) {
|
||||
case kGatewaySerialOpGetChannelId:
|
||||
publishGatewaySerialResponse(kGatewaySerialStatusOk, op,
|
||||
{channel_number, gateway_id.value()});
|
||||
return;
|
||||
case kGatewaySerialOpSetChannelId: {
|
||||
if (command.size() < 10) {
|
||||
publishGatewaySerialResponse(kGatewaySerialStatusInvalidArgument, op, {channel_number});
|
||||
return;
|
||||
}
|
||||
const uint8_t new_gateway_id = command[8];
|
||||
const uint8_t channel_index = static_cast<uint8_t>(channel_number - 1);
|
||||
const uint8_t old_gateway_id = gateway_id.value();
|
||||
if (!dali_domain_.updateChannelGatewayId(channel_index, new_gateway_id)) {
|
||||
publishGatewaySerialResponse(kGatewaySerialStatusDuplicateChannelId, op,
|
||||
{channel_number, new_gateway_id});
|
||||
return;
|
||||
}
|
||||
if (!runtime_.setGatewayIdForChannel(channel_index, new_gateway_id)) {
|
||||
dali_domain_.updateChannelGatewayId(channel_index, old_gateway_id);
|
||||
publishGatewaySerialResponse(kGatewaySerialStatusStorageError, op,
|
||||
{channel_number, new_gateway_id});
|
||||
return;
|
||||
}
|
||||
cache_.preloadChannel(new_gateway_id);
|
||||
reconciliation_jobs_.erase(old_gateway_id);
|
||||
cache_refresh_jobs_.erase(old_gateway_id);
|
||||
refreshRuntimeGatewayNames();
|
||||
publishGatewaySerialResponse(kGatewaySerialStatusOk, op,
|
||||
{channel_number, new_gateway_id});
|
||||
return;
|
||||
}
|
||||
case kGatewaySerialOpDispatchByChannelNumber: {
|
||||
if (command.size() < 12) {
|
||||
publishGatewaySerialResponse(kGatewaySerialStatusInvalidArgument, op, {channel_number});
|
||||
return;
|
||||
}
|
||||
const uint8_t inner_opcode = command[8];
|
||||
if (inner_opcode == kGatewaySerialOpcode) {
|
||||
publishGatewaySerialResponse(kGatewaySerialStatusInvalidArgument, op,
|
||||
{channel_number, inner_opcode});
|
||||
return;
|
||||
}
|
||||
std::vector<uint8_t> inner{0x28, 0x01, gateway_id.value(), inner_opcode};
|
||||
inner.insert(inner.end(), command.begin() + 9, command.end() - 1);
|
||||
dispatchCommand(GatewayRuntime::checksum(std::move(inner)));
|
||||
return;
|
||||
}
|
||||
default:
|
||||
publishGatewaySerialResponse(kGatewaySerialStatusInvalidArgument, op, {channel_number});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void GatewayController::handleGatewayIdentityCommand(uint8_t gateway_id, uint8_t op) {
|
||||
std::string value;
|
||||
if (op == 0x00) {
|
||||
|
||||
Reference in New Issue
Block a user