Enhance DaliGatewayCache: add capabilities management for DALI devices

Signed-off-by: Tony <tonylu@tony-cloud.com>
This commit is contained in:
Tony
2026-08-08 08:41:27 +08:00
parent 491b2ede4f
commit d8d0c39630
3 changed files with 56 additions and 3 deletions
+8
View File
@@ -83,6 +83,11 @@ struct DaliGatewayRuntimeStatus {
struct DaliGatewayAddressState {
bool groupMaskKnown{false};
uint16_t groupMask{0};
// Capability data is populated by discovery adapters and persisted with the
// rest of the address cache so bridge planners do not need a live bus scan
// on every boot.
std::optional<uint16_t> daliDeviceTypeMask;
std::optional<uint8_t> dt8ColorTypeFeatures;
std::array<std::optional<uint8_t>, 16> sceneLevels{};
DaliGatewaySettingsSnapshot settings;
DaliGatewayRuntimeStatus status;
@@ -143,6 +148,9 @@ class DaliGatewayCache {
void markAddressPresence(uint8_t channel, uint8_t shortAddress, DaliGatewayPresence presence);
bool setGroupMask(uint8_t channel, uint8_t shortAddress, std::optional<uint16_t> groupMask);
bool setCapabilities(uint8_t channel, uint8_t shortAddress,
std::optional<uint16_t> daliDeviceTypeMask,
std::optional<uint8_t> dt8ColorTypeFeatures);
bool setSceneLevel(uint8_t channel, uint8_t shortAddress, uint8_t scene,
std::optional<uint8_t> level);
bool setSettings(uint8_t channel, uint8_t shortAddress,
+36 -3
View File
@@ -5,7 +5,7 @@
namespace {
constexpr int kAddressStatePayloadVersion = 1;
constexpr int kAddressStatePayloadVersion = 2;
constexpr uint32_t kGroupMaskKnown = 1U << 0;
constexpr uint32_t kActualLevelKnown = 1U << 1;
constexpr uint32_t kSceneKnown = 1U << 2;
@@ -17,6 +17,8 @@ constexpr uint32_t kMinKnown = 1U << 7;
constexpr uint32_t kMaxKnown = 1U << 8;
constexpr uint32_t kFadeTimeKnown = 1U << 9;
constexpr uint32_t kFadeRateKnown = 1U << 10;
constexpr uint32_t kDeviceTypeMaskKnown = 1U << 11;
constexpr uint32_t kDt8ColorTypeFeaturesKnown = 1U << 12;
std::vector<int> ParseCsv(std::string_view raw) {
std::vector<int> values;
@@ -65,12 +67,15 @@ uint32_t StateFlags(const DaliGatewayAddressState& state) {
if (state.settings.maxLevel.has_value()) flags |= kMaxKnown;
if (state.settings.fadeTime.has_value()) flags |= kFadeTimeKnown;
if (state.settings.fadeRate.has_value()) flags |= kFadeRateKnown;
if (state.daliDeviceTypeMask.has_value()) flags |= kDeviceTypeMaskKnown;
if (state.dt8ColorTypeFeatures.has_value()) flags |= kDt8ColorTypeFeaturesKnown;
return flags;
}
bool IsDefaultState(const DaliGatewayAddressState& state) {
return !state.groupMaskKnown && state.groupMask == 0 && SceneKnownMask(state) == 0 &&
!state.settings.anyKnown() && !state.status.anyKnown();
!state.settings.anyKnown() && !state.status.anyKnown() &&
!state.daliDeviceTypeMask.has_value() && !state.dt8ColorTypeFeatures.has_value();
}
} // namespace
@@ -217,6 +222,22 @@ void DaliGatewayCache::markAddressPresence(uint8_t channel, uint8_t shortAddress
ensurePresence(channel)[shortAddress] = presence;
}
bool DaliGatewayCache::setCapabilities(
uint8_t channel, uint8_t shortAddress, std::optional<uint16_t> daliDeviceTypeMask,
std::optional<uint8_t> dt8ColorTypeFeatures) {
std::lock_guard<std::recursive_mutex> guard(mutex_);
if (shortAddress >= 64) return false;
auto& state = ensureStates(channel)[shortAddress];
if (state.daliDeviceTypeMask == daliDeviceTypeMask &&
state.dt8ColorTypeFeatures == dt8ColorTypeFeatures) {
return false;
}
state.daliDeviceTypeMask = daliDeviceTypeMask;
state.dt8ColorTypeFeatures = dt8ColorTypeFeatures;
markDirty(channel);
return true;
}
std::array<DaliGatewayAddressState, 64> DaliGatewayCache::addressStates(uint8_t channel) const {
std::lock_guard<std::recursive_mutex> guard(mutex_);
const auto it = states_.find(channel);
@@ -286,13 +307,17 @@ std::optional<std::string> DaliGatewayCache::encodeAddressState(
for (const auto& level : state.sceneLevels) {
payload += "," + std::to_string(level.value_or(255));
}
payload += "," + std::to_string(state.daliDeviceTypeMask.value_or(0));
payload += "," + std::to_string(state.dt8ColorTypeFeatures.value_or(0));
return payload;
}
std::optional<DaliGatewayAddressState> DaliGatewayCache::decodeAddressState(
std::string_view payload) {
const auto values = ParseCsv(payload);
if (values.size() < 13 || values[0] != kAddressStatePayloadVersion) return std::nullopt;
if (values.size() < 13 || (values[0] != 1 && values[0] != kAddressStatePayloadVersion)) {
return std::nullopt;
}
DaliGatewayAddressState state;
const uint32_t flags = static_cast<uint32_t>(std::max(values[1], 0));
@@ -321,6 +346,14 @@ std::optional<DaliGatewayAddressState> DaliGatewayCache::decodeAddressState(
state.sceneLevels[scene] = ByteValue(values[valueIndex]);
}
}
if (values[0] >= 2) {
if ((flags & kDeviceTypeMaskKnown) != 0 && values.size() > 29) {
state.daliDeviceTypeMask = WordValue(values[29]);
}
if ((flags & kDt8ColorTypeFeaturesKnown) != 0 && values.size() > 30) {
state.dt8ColorTypeFeatures = ByteValue(values[30]);
}
}
return state;
}
+12
View File
@@ -40,6 +40,7 @@ int main() {
[&](const DaliGatewayStatusUpdate&) { ++observer_updates; });
assert(cache.setGroupMask(7, 4, 0x0001));
assert(cache.setCapabilities(7, 4, 0x0180, 0x07));
assert(cache.mirrorForwardFrame(7, 0x80, 42));
assert(status_updates == 1);
assert(observer_updates == status_updates);
@@ -87,6 +88,17 @@ int main() {
assert(restored_state.groupMask == 0x0001);
assert(restored_state.settings.minLevel == 12);
assert(restored_state.status.stale);
assert(restored_state.daliDeviceTypeMask == 0x0180);
assert(restored_state.dt8ColorTypeFeatures == 0x07);
// Version-one records remain readable and retain their original fields.
persisted[{8, 2}] = "1,129,9,2,111,0,0,0,4,254,0,0,0";
assert(restored.preloadChannel(8));
const auto migrated_state = restored.addressState(8, 2);
assert(migrated_state.groupMaskKnown);
assert(migrated_state.groupMask == 2);
assert(migrated_state.settings.minLevel == 4);
assert(!migrated_state.daliDeviceTypeMask.has_value());
DaliApplicationControllerConfig config;
config.shortAddress = 3;