feat: add readMemoryLocation method and update GatewayController for memory identity reads

Signed-off-by: Tony <tonylu@tony-cloud.com>
This commit is contained in:
Tony
2026-06-15 17:01:27 +08:00
parent 780b4aa8d5
commit 49dcd8785b
5 changed files with 77 additions and 0 deletions
+9
View File
@@ -112,6 +112,15 @@ Unsupported ids return an `unsupported` operation error so old clients can fall
back to their app-side workflow. Legacy opcodes such as `0x12`, `0x13`, `0x14`, back to their app-side workflow. Legacy opcodes such as `0x12`, `0x13`, `0x14`,
`0x30`, `0x32`, `0x60`-`0x65`, and `0x39` remain available for compatibility. `0x30`, `0x32`, `0x60`-`0x65`, and `0x39` remain available for compatibility.
Operation id `84` performs a direct-short-address DALI identity memory batch
read. The start TLV must include target field `0x01` as a u8 short address
`0..63`; group and broadcast reads are rejected. Kind field `0x20` as u8
selects compact (`0`) or extended (`nonzero`) identity coverage. Results are
repeated field `0x30` byte-list entries, each with payload
`[bank, location, value]`. Missing byte replies are omitted; a completed result
with no entries reports `no response` so clients can fall back to single-byte
`READ MEMORY LOCATION` reads.
Opcode `0x66` controls passive raw-report leases. Command Opcode `0x66` controls passive raw-report leases. Command
`28 01 <gw> 66 01 <enabled> <ttlLo> <ttlHi> <checksum>` enables or disables a `28 01 <gw> 66 01 <enabled> <ttlLo> <ttlHi> <checksum>` enables or disables a
volatile per-gateway lease; `ttl=0` disables. The response is volatile per-gateway lease; `ttl=0` disables. The response is
@@ -149,6 +149,8 @@ class DaliDomainService {
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;
std::optional<uint8_t> readMemoryLocation(uint8_t gateway_id, int short_address, uint8_t bank,
uint8_t location) const;
std::optional<DaliDomainSnapshot> baseStatusSnapshot(uint8_t gateway_id, std::optional<DaliDomainSnapshot> baseStatusSnapshot(uint8_t gateway_id,
int short_address) const; int short_address) const;
std::optional<DaliDomainSnapshot> dt1Snapshot(uint8_t gateway_id, int short_address) const; std::optional<DaliDomainSnapshot> dt1Snapshot(uint8_t gateway_id, int short_address) const;
@@ -942,6 +942,25 @@ std::optional<DaliDomainSnapshot> DaliDomainService::discoverDeviceTypes(
return snapshot; return snapshot;
} }
std::optional<uint8_t> DaliDomainService::readMemoryLocation(uint8_t gateway_id,
int short_address,
uint8_t bank,
uint8_t location) const {
const auto* channel = findChannelByGateway(gateway_id);
if (channel == nullptr || channel->dali == nullptr) {
return std::nullopt;
}
if (short_address < 0 || short_address > 63) {
return std::nullopt;
}
markBusActivity(gateway_id);
const auto value = channel->dali->base.readMemoryLocation(short_address, bank, location);
if (!value.has_value()) {
return std::nullopt;
}
return static_cast<uint8_t>(value.value() & 0xFF);
}
std::optional<DaliDomainSnapshot> DaliDomainService::baseStatusSnapshot( std::optional<DaliDomainSnapshot> DaliDomainService::baseStatusSnapshot(
uint8_t gateway_id, int short_address) const { uint8_t gateway_id, int short_address) const {
const auto* channel = findChannelByGateway(gateway_id); const auto* channel = findChannelByGateway(gateway_id);
@@ -633,6 +633,7 @@ bool OperationRequiresDt1(BridgeOperation operation) {
case BridgeOperation::dt1GetRatedDuration: case BridgeOperation::dt1GetRatedDuration:
case BridgeOperation::dt1GetExtendedVersion: case BridgeOperation::dt1GetExtendedVersion:
case BridgeOperation::dt1GetEmergencyDeviceType: case BridgeOperation::dt1GetEmergencyDeviceType:
case BridgeOperation::readMemoryIdentity:
return true; return true;
default: default:
return false; return false;
@@ -167,6 +167,7 @@ constexpr uint16_t kBridgeOperationSetColourRGB = 23;
constexpr uint16_t kBridgeOperationSetColourRGBW = 80; constexpr uint16_t kBridgeOperationSetColourRGBW = 80;
constexpr uint16_t kBridgeOperationSetColourRGBCW = 81; constexpr uint16_t kBridgeOperationSetColourRGBCW = 81;
constexpr uint16_t kBridgeOperationSetColourRGBWAF = 82; constexpr uint16_t kBridgeOperationSetColourRGBWAF = 82;
constexpr uint16_t kBridgeOperationReadMemoryIdentity = 84;
constexpr uint16_t kDaliCmdQueryStatus = 0x90; constexpr uint16_t kDaliCmdQueryStatus = 0x90;
constexpr uint16_t kDaliCmdQueryBallast = 0x91; constexpr uint16_t kDaliCmdQueryBallast = 0x91;
constexpr const char* kBridgeTransportInvalidFrameResponse = constexpr const char* kBridgeTransportInvalidFrameResponse =
@@ -2993,6 +2994,51 @@ void GatewayController::runOperationTask(GatewayOperationTaskContext* context) {
progress = 100; progress = 100;
break; break;
} }
case kBridgeOperationReadMemoryIdentity: {
if (target < 0 || target > 63) {
fail(kOperationStatusInvalid);
break;
}
struct MemoryLocation {
uint8_t bank;
uint8_t location;
};
std::vector<MemoryLocation> locations;
locations.reserve(38);
for (uint8_t location = 0x00; location <= 0x05; ++location) {
locations.push_back(MemoryLocation{0, location});
}
const bool extended = TlvIntOr(fields, kTlvFieldKind, 0) != 0;
const uint8_t bank1_end = extended ? 0x1F : 0x06;
for (uint8_t location = 0x00; location <= bank1_end; ++location) {
locations.push_back(MemoryLocation{1, location});
}
const int total = std::max<int>(1, locations.size());
for (size_t index = 0; index < locations.size(); ++index) {
if (canceled()) {
fail(kOperationStatusAborted);
break;
}
const auto location = locations[index];
const auto value = dali_domain_.readMemoryLocation(gateway_id, target, location.bank,
location.location);
if (value.has_value()) {
const uint8_t entry[] = {location.bank, location.location, value.value()};
AppendTlvBytes(result_tlvs, kTlvFieldEntry, kTlvTypeBytes, entry, sizeof(entry));
++count;
}
update_progress(kOperationEventItemResult,
static_cast<uint8_t>((index + 1) * 100 / total),
location.location, count,
value.has_value() ? kOperationStatusOk : kOperationStatusNoResponse);
}
if (status == kOperationStatusOk && count == 0) {
fail(kOperationStatusNoResponse);
} else {
progress = 100;
}
break;
}
case kBridgeOperationAllocateAllShortAddresses: case kBridgeOperationAllocateAllShortAddresses:
case kBridgeOperationResetAndAllocateShortAddresses: case kBridgeOperationResetAndAllocateShortAddresses:
case kBridgeOperationStopAddressAllocation: { case kBridgeOperationStopAddressAllocation: {