Enhance DaliGatewayCache: add capabilities management for DALI devices
Signed-off-by: Tony <tonylu@tony-cloud.com>
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user