feat: add readMemoryLocation method and update GatewayController for memory identity reads
Signed-off-by: Tony <tonylu@tony-cloud.com>
This commit is contained in:
@@ -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: {
|
||||||
|
|||||||
Reference in New Issue
Block a user