feat(gateway): enhance DALI command handling with mirroring and new target types
This commit is contained in:
@@ -35,6 +35,17 @@ enum class GatewayCacheRawFrameOrigin : uint8_t {
|
|||||||
kOutsideBus = 1,
|
kOutsideBus = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class GatewayCacheDaliTargetKind : uint8_t {
|
||||||
|
kShortAddress = 0,
|
||||||
|
kGroup = 1,
|
||||||
|
kBroadcast = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct GatewayCacheDaliTarget {
|
||||||
|
GatewayCacheDaliTargetKind kind{GatewayCacheDaliTargetKind::kShortAddress};
|
||||||
|
uint8_t value{0};
|
||||||
|
};
|
||||||
|
|
||||||
struct GatewayCacheChannelFlags {
|
struct GatewayCacheChannelFlags {
|
||||||
bool need_update_group{false};
|
bool need_update_group{false};
|
||||||
bool need_update_scene{false};
|
bool need_update_scene{false};
|
||||||
@@ -56,11 +67,23 @@ struct GatewayCacheDaliSettingsSnapshot {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct GatewayCacheDaliRuntimeStatus {
|
||||||
|
std::optional<uint8_t> actual_level;
|
||||||
|
std::optional<uint8_t> scene_id;
|
||||||
|
bool use_min_level{false};
|
||||||
|
uint32_t revision{0};
|
||||||
|
|
||||||
|
bool anyKnown() const {
|
||||||
|
return actual_level.has_value() || scene_id.has_value() || use_min_level;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct GatewayCacheDaliAddressState {
|
struct GatewayCacheDaliAddressState {
|
||||||
bool group_mask_known{false};
|
bool group_mask_known{false};
|
||||||
uint16_t group_mask{0};
|
uint16_t group_mask{0};
|
||||||
std::array<std::optional<uint8_t>, 16> scene_levels{};
|
std::array<std::optional<uint8_t>, 16> scene_levels{};
|
||||||
GatewayCacheDaliSettingsSnapshot settings;
|
GatewayCacheDaliSettingsSnapshot settings;
|
||||||
|
GatewayCacheDaliRuntimeStatus status;
|
||||||
};
|
};
|
||||||
|
|
||||||
class GatewayCache {
|
class GatewayCache {
|
||||||
@@ -113,6 +136,8 @@ class GatewayCache {
|
|||||||
GatewayCacheChannelFlags channelFlags(uint8_t gateway_id);
|
GatewayCacheChannelFlags channelFlags(uint8_t gateway_id);
|
||||||
GatewayCacheChannelFlags pendingChannelFlags(uint8_t gateway_id);
|
GatewayCacheChannelFlags pendingChannelFlags(uint8_t gateway_id);
|
||||||
GatewayCacheDaliAddressState daliAddressState(uint8_t gateway_id, uint8_t short_address);
|
GatewayCacheDaliAddressState daliAddressState(uint8_t gateway_id, uint8_t short_address);
|
||||||
|
GatewayCacheDaliRuntimeStatus daliGroupStatus(uint8_t gateway_id, uint8_t group_id);
|
||||||
|
GatewayCacheDaliRuntimeStatus daliBroadcastStatus(uint8_t gateway_id);
|
||||||
bool setDaliGroupMask(uint8_t gateway_id, uint8_t short_address,
|
bool setDaliGroupMask(uint8_t gateway_id, uint8_t short_address,
|
||||||
std::optional<uint16_t> group_mask);
|
std::optional<uint16_t> group_mask);
|
||||||
bool setDaliSceneLevel(uint8_t gateway_id, uint8_t short_address, uint8_t scene_id,
|
bool setDaliSceneLevel(uint8_t gateway_id, uint8_t short_address, uint8_t scene_id,
|
||||||
@@ -127,6 +152,7 @@ class GatewayCache {
|
|||||||
bool cacheEnabled() const;
|
bool cacheEnabled() const;
|
||||||
bool reconciliationEnabled() const;
|
bool reconciliationEnabled() const;
|
||||||
bool fullStateMirrorEnabled() const;
|
bool fullStateMirrorEnabled() const;
|
||||||
|
bool mirrorDaliCommand(uint8_t gateway_id, uint8_t raw_addr, uint8_t command);
|
||||||
bool observeDaliCommand(uint8_t gateway_id, uint8_t raw_addr, uint8_t command,
|
bool observeDaliCommand(uint8_t gateway_id, uint8_t raw_addr, uint8_t command,
|
||||||
GatewayCacheRawFrameOrigin origin);
|
GatewayCacheRawFrameOrigin origin);
|
||||||
|
|
||||||
@@ -150,8 +176,31 @@ class GatewayCache {
|
|||||||
bool persistGroupLocked(uint8_t gateway_id, uint8_t group_id, const GroupEntry& group);
|
bool persistGroupLocked(uint8_t gateway_id, uint8_t group_id, const GroupEntry& group);
|
||||||
bool commitStorageLocked();
|
bool commitStorageLocked();
|
||||||
bool shouldTrackUpdateFlagsLocked() const;
|
bool shouldTrackUpdateFlagsLocked() const;
|
||||||
|
uint32_t nextDaliRuntimeRevisionLocked();
|
||||||
|
bool mirrorDaliCommandLocked(uint8_t gateway_id, uint8_t raw_addr, uint8_t command);
|
||||||
|
void clearDaliTargetStateLocked(uint8_t gateway_id, const GatewayCacheDaliTarget& target,
|
||||||
|
uint32_t revision);
|
||||||
|
void applyDaliTargetRuntimeStatusLocked(uint8_t gateway_id,
|
||||||
|
const GatewayCacheDaliTarget& target,
|
||||||
|
const GatewayCacheDaliRuntimeStatus& status);
|
||||||
|
void applyDaliRuntimeStatusToAddressLocked(GatewayCacheDaliAddressState& state,
|
||||||
|
const GatewayCacheDaliRuntimeStatus& status);
|
||||||
|
void applyDaliTargetGroupMutationLocked(uint8_t gateway_id,
|
||||||
|
const GatewayCacheDaliTarget& target, uint8_t group_id,
|
||||||
|
bool add_to_group);
|
||||||
|
void applyDaliTargetSceneLevelLocked(uint8_t gateway_id,
|
||||||
|
const GatewayCacheDaliTarget& target, uint8_t scene_id,
|
||||||
|
std::optional<uint8_t> level);
|
||||||
|
void applyDaliTargetSettingsLocked(uint8_t gateway_id,
|
||||||
|
const GatewayCacheDaliTarget& target, uint8_t command,
|
||||||
|
uint8_t value);
|
||||||
|
void refreshDaliAddressAggregateStatusLocked(uint8_t gateway_id,
|
||||||
|
GatewayCacheDaliAddressState& state);
|
||||||
GatewayCacheDaliAddressState& ensureDaliAddressStateLocked(uint8_t gateway_id,
|
GatewayCacheDaliAddressState& ensureDaliAddressStateLocked(uint8_t gateway_id,
|
||||||
uint8_t short_address);
|
uint8_t short_address);
|
||||||
|
GatewayCacheDaliRuntimeStatus& ensureDaliGroupStatusLocked(uint8_t gateway_id,
|
||||||
|
uint8_t group_id);
|
||||||
|
GatewayCacheDaliRuntimeStatus& ensureDaliBroadcastStatusLocked(uint8_t gateway_id);
|
||||||
SceneStore& ensureSceneStoreLocked(uint8_t gateway_id);
|
SceneStore& ensureSceneStoreLocked(uint8_t gateway_id);
|
||||||
GroupStore& ensureGroupStoreLocked(uint8_t gateway_id);
|
GroupStore& ensureGroupStoreLocked(uint8_t gateway_id);
|
||||||
void loadSceneStoreLocked(uint8_t gateway_id, SceneStore& scenes);
|
void loadSceneStoreLocked(uint8_t gateway_id, SceneStore& scenes);
|
||||||
@@ -168,8 +217,11 @@ class GatewayCache {
|
|||||||
std::map<uint8_t, SceneStore> scenes_;
|
std::map<uint8_t, SceneStore> scenes_;
|
||||||
std::map<uint8_t, GroupStore> groups_;
|
std::map<uint8_t, GroupStore> groups_;
|
||||||
std::map<uint8_t, std::array<GatewayCacheDaliAddressState, 64>> dali_states_;
|
std::map<uint8_t, std::array<GatewayCacheDaliAddressState, 64>> dali_states_;
|
||||||
|
std::map<uint8_t, std::array<GatewayCacheDaliRuntimeStatus, 16>> dali_group_status_;
|
||||||
|
std::map<uint8_t, GatewayCacheDaliRuntimeStatus> dali_broadcast_status_;
|
||||||
std::map<uint8_t, DtrState> dtr_states_;
|
std::map<uint8_t, DtrState> dtr_states_;
|
||||||
std::map<uint8_t, GatewayCacheChannelFlags> channel_flags_;
|
std::map<uint8_t, GatewayCacheChannelFlags> channel_flags_;
|
||||||
|
uint32_t dali_runtime_revision_{0};
|
||||||
bool dirty_{false};
|
bool dirty_{false};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,15 @@ namespace {
|
|||||||
|
|
||||||
constexpr const char* kTag = "gateway_cache";
|
constexpr const char* kTag = "gateway_cache";
|
||||||
constexpr size_t kMaxNameBytes = 32;
|
constexpr size_t kMaxNameBytes = 32;
|
||||||
|
constexpr uint8_t kDaliRawBroadcastArc = 0xFE;
|
||||||
|
constexpr uint8_t kDaliRawBroadcastCommand = 0xFF;
|
||||||
|
constexpr uint8_t kDaliGroupRawMin = 0x80;
|
||||||
|
constexpr uint8_t kDaliGroupRawMax = 0x9F;
|
||||||
|
constexpr uint8_t kDaliCmdOff = 0x00;
|
||||||
|
constexpr uint8_t kDaliCmdRecallMax = 0x05;
|
||||||
|
constexpr uint8_t kDaliCmdRecallMin = 0x06;
|
||||||
|
constexpr uint8_t kDaliCmdGoToSceneMin = 0x10;
|
||||||
|
constexpr uint8_t kDaliCmdGoToSceneMax = 0x1F;
|
||||||
constexpr uint8_t kDaliCmdReset = 0x20;
|
constexpr uint8_t kDaliCmdReset = 0x20;
|
||||||
constexpr uint8_t kDaliCmdStoreDtrAsMaxLevel = 0x2A;
|
constexpr uint8_t kDaliCmdStoreDtrAsMaxLevel = 0x2A;
|
||||||
constexpr uint8_t kDaliCmdStoreDtrAsMinLevel = 0x2B;
|
constexpr uint8_t kDaliCmdStoreDtrAsMinLevel = 0x2B;
|
||||||
@@ -104,9 +113,17 @@ bool AnyFlagSet(const GatewayCacheChannelFlags& flags) {
|
|||||||
return flags.need_update_group || flags.need_update_scene || flags.need_update_settings;
|
return flags.need_update_group || flags.need_update_scene || flags.need_update_settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<uint8_t> DecodeShortAddress(uint8_t raw_addr) {
|
std::optional<GatewayCacheDaliTarget> DecodeDaliTarget(uint8_t raw_addr) {
|
||||||
if (raw_addr <= 0x7F && (raw_addr & 0x01) != 0) {
|
if (raw_addr <= 0x7F) {
|
||||||
return static_cast<uint8_t>(raw_addr >> 1);
|
return GatewayCacheDaliTarget{GatewayCacheDaliTargetKind::kShortAddress,
|
||||||
|
static_cast<uint8_t>(raw_addr >> 1)};
|
||||||
|
}
|
||||||
|
if (raw_addr >= kDaliGroupRawMin && raw_addr <= kDaliGroupRawMax) {
|
||||||
|
return GatewayCacheDaliTarget{GatewayCacheDaliTargetKind::kGroup,
|
||||||
|
static_cast<uint8_t>((raw_addr - kDaliGroupRawMin) >> 1)};
|
||||||
|
}
|
||||||
|
if (raw_addr == kDaliRawBroadcastArc || raw_addr == kDaliRawBroadcastCommand) {
|
||||||
|
return GatewayCacheDaliTarget{GatewayCacheDaliTargetKind::kBroadcast, 0};
|
||||||
}
|
}
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
@@ -122,6 +139,7 @@ void ClearDaliState(GatewayCacheDaliAddressState& state) {
|
|||||||
state.group_mask = 0;
|
state.group_mask = 0;
|
||||||
state.scene_levels.fill(std::nullopt);
|
state.scene_levels.fill(std::nullopt);
|
||||||
state.settings = {};
|
state.settings = {};
|
||||||
|
state.status = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApplyObservedSettingsValue(GatewayCacheDaliSettingsSnapshot& settings, uint8_t command,
|
void ApplyObservedSettingsValue(GatewayCacheDaliSettingsSnapshot& settings, uint8_t command,
|
||||||
@@ -577,6 +595,20 @@ GatewayCacheDaliAddressState GatewayCache::daliAddressState(uint8_t gateway_id,
|
|||||||
return ensureDaliAddressStateLocked(gateway_id, short_address);
|
return ensureDaliAddressStateLocked(gateway_id, short_address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GatewayCacheDaliRuntimeStatus GatewayCache::daliGroupStatus(uint8_t gateway_id,
|
||||||
|
uint8_t group_id) {
|
||||||
|
LockGuard guard(lock_);
|
||||||
|
if (group_id >= 16) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return ensureDaliGroupStatusLocked(gateway_id, group_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
GatewayCacheDaliRuntimeStatus GatewayCache::daliBroadcastStatus(uint8_t gateway_id) {
|
||||||
|
LockGuard guard(lock_);
|
||||||
|
return ensureDaliBroadcastStatusLocked(gateway_id);
|
||||||
|
}
|
||||||
|
|
||||||
bool GatewayCache::setDaliGroupMask(uint8_t gateway_id, uint8_t short_address,
|
bool GatewayCache::setDaliGroupMask(uint8_t gateway_id, uint8_t short_address,
|
||||||
std::optional<uint16_t> group_mask) {
|
std::optional<uint16_t> group_mask) {
|
||||||
LockGuard guard(lock_);
|
LockGuard guard(lock_);
|
||||||
@@ -587,6 +619,7 @@ bool GatewayCache::setDaliGroupMask(uint8_t gateway_id, uint8_t short_address,
|
|||||||
auto& state = ensureDaliAddressStateLocked(gateway_id, short_address);
|
auto& state = ensureDaliAddressStateLocked(gateway_id, short_address);
|
||||||
state.group_mask_known = group_mask.has_value();
|
state.group_mask_known = group_mask.has_value();
|
||||||
state.group_mask = group_mask.value_or(0);
|
state.group_mask = group_mask.value_or(0);
|
||||||
|
refreshDaliAddressAggregateStatusLocked(gateway_id, state);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -664,62 +697,31 @@ bool GatewayCache::fullStateMirrorEnabled() const {
|
|||||||
return reconciliationEnabled() && config_.full_state_mirror_enabled;
|
return reconciliationEnabled() && config_.full_state_mirror_enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GatewayCache::mirrorDaliCommand(uint8_t gateway_id, uint8_t raw_addr, uint8_t command) {
|
||||||
|
LockGuard guard(lock_);
|
||||||
|
if (!config_.cache_enabled) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return mirrorDaliCommandLocked(gateway_id, raw_addr, command);
|
||||||
|
}
|
||||||
|
|
||||||
bool GatewayCache::observeDaliCommand(uint8_t gateway_id, uint8_t raw_addr, uint8_t command,
|
bool GatewayCache::observeDaliCommand(uint8_t gateway_id, uint8_t raw_addr, uint8_t command,
|
||||||
GatewayCacheRawFrameOrigin origin) {
|
GatewayCacheRawFrameOrigin origin) {
|
||||||
LockGuard guard(lock_);
|
LockGuard guard(lock_);
|
||||||
if (!shouldTrackUpdateFlagsLocked()) {
|
if (!config_.cache_enabled) {
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto& dtr_state = dtr_states_[gateway_id];
|
|
||||||
if (raw_addr == kDaliCmdSetDtr0) {
|
|
||||||
dtr_state.dtr0 = command;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (raw_addr == kDaliCmdSetDtr1) {
|
|
||||||
dtr_state.dtr1 = command;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (raw_addr == kDaliCmdSetDtr2) {
|
|
||||||
dtr_state.dtr2 = command;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto detected = ClassifyDaliMutation(raw_addr, command);
|
|
||||||
if (!AnyFlagSet(detected)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ShouldMirrorObservedMutation(origin, priority_mode_)) {
|
if (ShouldMirrorObservedMutation(origin, priority_mode_)) {
|
||||||
if (command == kDaliCmdReset) {
|
mirrorDaliCommandLocked(gateway_id, raw_addr, command);
|
||||||
if (const auto short_address = DecodeShortAddress(raw_addr); short_address.has_value()) {
|
}
|
||||||
ClearDaliState(ensureDaliAddressStateLocked(gateway_id, *short_address));
|
|
||||||
} else if (auto states = dali_states_.find(gateway_id); states != dali_states_.end()) {
|
|
||||||
for (auto& state : states->second) {
|
|
||||||
ClearDaliState(state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (const auto short_address = DecodeShortAddress(raw_addr); short_address.has_value()) {
|
|
||||||
auto& state = ensureDaliAddressStateLocked(gateway_id, *short_address);
|
|
||||||
|
|
||||||
if (command >= kDaliCmdAddToGroupMin && command <= kDaliCmdRemoveFromGroupMax &&
|
if (!shouldTrackUpdateFlagsLocked()) {
|
||||||
state.group_mask_known) {
|
return false;
|
||||||
const uint16_t bit = static_cast<uint16_t>(1U << (command & 0x0F));
|
}
|
||||||
if (command < (kDaliCmdAddToGroupMin + 16)) {
|
const auto detected = ClassifyDaliMutation(raw_addr, command);
|
||||||
state.group_mask |= bit;
|
if (!AnyFlagSet(detected)) {
|
||||||
} else {
|
return false;
|
||||||
state.group_mask &= static_cast<uint16_t>(~bit);
|
|
||||||
}
|
|
||||||
} else if (command >= kDaliCmdSetSceneMin && command < (kDaliCmdSetSceneMin + 16) &&
|
|
||||||
dtr_state.dtr0.has_value()) {
|
|
||||||
state.scene_levels[command - kDaliCmdSetSceneMin] = *dtr_state.dtr0;
|
|
||||||
} else if (command >= (kDaliCmdSetSceneMin + 16) && command <= kDaliCmdRemoveSceneMax) {
|
|
||||||
state.scene_levels[command - (kDaliCmdSetSceneMin + 16)] = 255U;
|
|
||||||
} else if (command >= kDaliCmdStoreDtrAsMaxLevel && command <= kDaliCmdStoreDtrAsFadeRate &&
|
|
||||||
dtr_state.dtr0.has_value()) {
|
|
||||||
ApplyObservedSettingsValue(state.settings, command, *dtr_state.dtr0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (origin != GatewayCacheRawFrameOrigin::kOutsideBus) {
|
if (origin != GatewayCacheRawFrameOrigin::kOutsideBus) {
|
||||||
@@ -752,6 +754,394 @@ void GatewayCache::setPriorityMode(GatewayCachePriorityMode mode) {
|
|||||||
priority_mode_ = mode;
|
priority_mode_ = mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t GatewayCache::nextDaliRuntimeRevisionLocked() {
|
||||||
|
++dali_runtime_revision_;
|
||||||
|
if (dali_runtime_revision_ == 0) {
|
||||||
|
++dali_runtime_revision_;
|
||||||
|
}
|
||||||
|
return dali_runtime_revision_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GatewayCache::mirrorDaliCommandLocked(uint8_t gateway_id, uint8_t raw_addr,
|
||||||
|
uint8_t command) {
|
||||||
|
auto& dtr_state = dtr_states_[gateway_id];
|
||||||
|
if (raw_addr == kDaliCmdSetDtr0) {
|
||||||
|
dtr_state.dtr0 = command;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (raw_addr == kDaliCmdSetDtr1) {
|
||||||
|
dtr_state.dtr1 = command;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (raw_addr == kDaliCmdSetDtr2) {
|
||||||
|
dtr_state.dtr2 = command;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto target = DecodeDaliTarget(raw_addr);
|
||||||
|
if (!target.has_value()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool arc_power_frame = (raw_addr & 0x01) == 0;
|
||||||
|
if (arc_power_frame) {
|
||||||
|
if (command > 254) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
GatewayCacheDaliRuntimeStatus status;
|
||||||
|
status.actual_level = command;
|
||||||
|
status.revision = nextDaliRuntimeRevisionLocked();
|
||||||
|
applyDaliTargetRuntimeStatusLocked(gateway_id, *target, status);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (command == kDaliCmdReset) {
|
||||||
|
clearDaliTargetStateLocked(gateway_id, *target, nextDaliRuntimeRevisionLocked());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (command == kDaliCmdOff || command == kDaliCmdRecallMax) {
|
||||||
|
GatewayCacheDaliRuntimeStatus status;
|
||||||
|
status.actual_level = command == kDaliCmdOff ? 0 : 254;
|
||||||
|
status.revision = nextDaliRuntimeRevisionLocked();
|
||||||
|
applyDaliTargetRuntimeStatusLocked(gateway_id, *target, status);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (command == kDaliCmdRecallMin) {
|
||||||
|
GatewayCacheDaliRuntimeStatus status;
|
||||||
|
status.use_min_level = true;
|
||||||
|
status.revision = nextDaliRuntimeRevisionLocked();
|
||||||
|
applyDaliTargetRuntimeStatusLocked(gateway_id, *target, status);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (command >= kDaliCmdGoToSceneMin && command <= kDaliCmdGoToSceneMax) {
|
||||||
|
GatewayCacheDaliRuntimeStatus status;
|
||||||
|
status.scene_id = static_cast<uint8_t>(command - kDaliCmdGoToSceneMin);
|
||||||
|
status.revision = nextDaliRuntimeRevisionLocked();
|
||||||
|
applyDaliTargetRuntimeStatusLocked(gateway_id, *target, status);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (command >= kDaliCmdAddToGroupMin && command <= kDaliCmdRemoveFromGroupMax) {
|
||||||
|
applyDaliTargetGroupMutationLocked(gateway_id, *target,
|
||||||
|
static_cast<uint8_t>(command & 0x0F),
|
||||||
|
command < (kDaliCmdAddToGroupMin + 16));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (command >= kDaliCmdSetSceneMin && command < (kDaliCmdSetSceneMin + 16) &&
|
||||||
|
dtr_state.dtr0.has_value()) {
|
||||||
|
applyDaliTargetSceneLevelLocked(gateway_id, *target,
|
||||||
|
static_cast<uint8_t>(command - kDaliCmdSetSceneMin),
|
||||||
|
*dtr_state.dtr0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (command >= (kDaliCmdSetSceneMin + 16) && command <= kDaliCmdRemoveSceneMax) {
|
||||||
|
applyDaliTargetSceneLevelLocked(
|
||||||
|
gateway_id, *target, static_cast<uint8_t>(command - (kDaliCmdSetSceneMin + 16)),
|
||||||
|
static_cast<uint8_t>(255U));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (command >= kDaliCmdStoreDtrAsMaxLevel && command <= kDaliCmdStoreDtrAsFadeRate &&
|
||||||
|
dtr_state.dtr0.has_value()) {
|
||||||
|
applyDaliTargetSettingsLocked(gateway_id, *target, command, *dtr_state.dtr0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GatewayCache::clearDaliTargetStateLocked(uint8_t gateway_id,
|
||||||
|
const GatewayCacheDaliTarget& target,
|
||||||
|
uint32_t revision) {
|
||||||
|
auto clear_state = [revision](GatewayCacheDaliAddressState& state) {
|
||||||
|
ClearDaliState(state);
|
||||||
|
state.status.revision = revision;
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (target.kind) {
|
||||||
|
case GatewayCacheDaliTargetKind::kShortAddress:
|
||||||
|
if (target.value < 64) {
|
||||||
|
clear_state(ensureDaliAddressStateLocked(gateway_id, target.value));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case GatewayCacheDaliTargetKind::kGroup: {
|
||||||
|
if (target.value >= 16) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
auto& group_status = ensureDaliGroupStatusLocked(gateway_id, target.value);
|
||||||
|
group_status = {};
|
||||||
|
group_status.revision = revision;
|
||||||
|
const uint16_t bit = static_cast<uint16_t>(1U << target.value);
|
||||||
|
if (auto states = dali_states_.find(gateway_id); states != dali_states_.end()) {
|
||||||
|
for (auto& state : states->second) {
|
||||||
|
if (state.group_mask_known && (state.group_mask & bit) != 0) {
|
||||||
|
clear_state(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case GatewayCacheDaliTargetKind::kBroadcast: {
|
||||||
|
auto& broadcast_status = ensureDaliBroadcastStatusLocked(gateway_id);
|
||||||
|
broadcast_status = {};
|
||||||
|
broadcast_status.revision = revision;
|
||||||
|
auto& group_statuses = dali_group_status_[gateway_id];
|
||||||
|
for (auto& group_status : group_statuses) {
|
||||||
|
group_status = {};
|
||||||
|
group_status.revision = revision;
|
||||||
|
}
|
||||||
|
auto& states = dali_states_[gateway_id];
|
||||||
|
for (auto& state : states) {
|
||||||
|
clear_state(state);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GatewayCache::applyDaliTargetRuntimeStatusLocked(
|
||||||
|
uint8_t gateway_id, const GatewayCacheDaliTarget& target,
|
||||||
|
const GatewayCacheDaliRuntimeStatus& status) {
|
||||||
|
if (!status.anyKnown()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (target.kind) {
|
||||||
|
case GatewayCacheDaliTargetKind::kShortAddress:
|
||||||
|
if (target.value < 64) {
|
||||||
|
applyDaliRuntimeStatusToAddressLocked(ensureDaliAddressStateLocked(gateway_id,
|
||||||
|
target.value),
|
||||||
|
status);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case GatewayCacheDaliTargetKind::kGroup: {
|
||||||
|
if (target.value >= 16) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ensureDaliGroupStatusLocked(gateway_id, target.value) = status;
|
||||||
|
const uint16_t bit = static_cast<uint16_t>(1U << target.value);
|
||||||
|
if (auto states = dali_states_.find(gateway_id); states != dali_states_.end()) {
|
||||||
|
for (auto& state : states->second) {
|
||||||
|
if (state.group_mask_known && (state.group_mask & bit) != 0) {
|
||||||
|
applyDaliRuntimeStatusToAddressLocked(state, status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case GatewayCacheDaliTargetKind::kBroadcast: {
|
||||||
|
ensureDaliBroadcastStatusLocked(gateway_id) = status;
|
||||||
|
auto& states = dali_states_[gateway_id];
|
||||||
|
for (auto& state : states) {
|
||||||
|
applyDaliRuntimeStatusToAddressLocked(state, status);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GatewayCache::applyDaliRuntimeStatusToAddressLocked(
|
||||||
|
GatewayCacheDaliAddressState& state, const GatewayCacheDaliRuntimeStatus& status) {
|
||||||
|
if (!status.anyKnown() || status.revision <= state.status.revision) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status.scene_id.has_value()) {
|
||||||
|
state.status.scene_id = status.scene_id;
|
||||||
|
state.status.use_min_level = false;
|
||||||
|
const uint8_t scene_id = *status.scene_id;
|
||||||
|
if (scene_id < state.scene_levels.size()) {
|
||||||
|
const auto scene_level = state.scene_levels[scene_id];
|
||||||
|
if (scene_level.has_value() && *scene_level != 255U) {
|
||||||
|
state.status.actual_level = *scene_level;
|
||||||
|
} else if (status.actual_level.has_value()) {
|
||||||
|
state.status.actual_level = status.actual_level;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
state.status.scene_id.reset();
|
||||||
|
state.status.use_min_level = status.use_min_level;
|
||||||
|
if (status.use_min_level) {
|
||||||
|
state.status.actual_level = state.settings.min_level;
|
||||||
|
} else {
|
||||||
|
state.status.actual_level = status.actual_level;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
state.status.revision = status.revision;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GatewayCache::applyDaliTargetGroupMutationLocked(uint8_t gateway_id,
|
||||||
|
const GatewayCacheDaliTarget& target,
|
||||||
|
uint8_t group_id, bool add_to_group) {
|
||||||
|
if (group_id >= 16) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const uint16_t bit = static_cast<uint16_t>(1U << group_id);
|
||||||
|
auto apply = [&](GatewayCacheDaliAddressState& state) {
|
||||||
|
if (!state.group_mask_known) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (add_to_group) {
|
||||||
|
state.group_mask |= bit;
|
||||||
|
} else {
|
||||||
|
state.group_mask &= static_cast<uint16_t>(~bit);
|
||||||
|
}
|
||||||
|
refreshDaliAddressAggregateStatusLocked(gateway_id, state);
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (target.kind) {
|
||||||
|
case GatewayCacheDaliTargetKind::kShortAddress:
|
||||||
|
if (target.value < 64) {
|
||||||
|
apply(ensureDaliAddressStateLocked(gateway_id, target.value));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case GatewayCacheDaliTargetKind::kGroup: {
|
||||||
|
if (target.value >= 16) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
const uint16_t target_bit = static_cast<uint16_t>(1U << target.value);
|
||||||
|
if (auto states = dali_states_.find(gateway_id); states != dali_states_.end()) {
|
||||||
|
for (auto& state : states->second) {
|
||||||
|
if (state.group_mask_known && (state.group_mask & target_bit) != 0) {
|
||||||
|
apply(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case GatewayCacheDaliTargetKind::kBroadcast: {
|
||||||
|
auto& states = dali_states_[gateway_id];
|
||||||
|
for (auto& state : states) {
|
||||||
|
apply(state);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GatewayCache::applyDaliTargetSceneLevelLocked(uint8_t gateway_id,
|
||||||
|
const GatewayCacheDaliTarget& target,
|
||||||
|
uint8_t scene_id,
|
||||||
|
std::optional<uint8_t> level) {
|
||||||
|
if (scene_id >= 16) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto apply = [scene_id, level](GatewayCacheDaliAddressState& state) {
|
||||||
|
state.scene_levels[scene_id] = level;
|
||||||
|
if (state.status.scene_id.has_value() && *state.status.scene_id == scene_id &&
|
||||||
|
level.has_value() && *level != 255U) {
|
||||||
|
state.status.actual_level = *level;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (target.kind) {
|
||||||
|
case GatewayCacheDaliTargetKind::kShortAddress:
|
||||||
|
if (target.value < 64) {
|
||||||
|
apply(ensureDaliAddressStateLocked(gateway_id, target.value));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case GatewayCacheDaliTargetKind::kGroup: {
|
||||||
|
if (target.value >= 16) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
const uint16_t bit = static_cast<uint16_t>(1U << target.value);
|
||||||
|
if (auto states = dali_states_.find(gateway_id); states != dali_states_.end()) {
|
||||||
|
for (auto& state : states->second) {
|
||||||
|
if (state.group_mask_known && (state.group_mask & bit) != 0) {
|
||||||
|
apply(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case GatewayCacheDaliTargetKind::kBroadcast: {
|
||||||
|
auto& states = dali_states_[gateway_id];
|
||||||
|
for (auto& state : states) {
|
||||||
|
apply(state);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GatewayCache::applyDaliTargetSettingsLocked(uint8_t gateway_id,
|
||||||
|
const GatewayCacheDaliTarget& target,
|
||||||
|
uint8_t command, uint8_t value) {
|
||||||
|
auto apply = [command, value](GatewayCacheDaliAddressState& state) {
|
||||||
|
ApplyObservedSettingsValue(state.settings, command, value);
|
||||||
|
if (command == kDaliCmdStoreDtrAsMinLevel && state.status.use_min_level) {
|
||||||
|
state.status.actual_level = value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (target.kind) {
|
||||||
|
case GatewayCacheDaliTargetKind::kShortAddress:
|
||||||
|
if (target.value < 64) {
|
||||||
|
apply(ensureDaliAddressStateLocked(gateway_id, target.value));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case GatewayCacheDaliTargetKind::kGroup: {
|
||||||
|
if (target.value >= 16) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
const uint16_t bit = static_cast<uint16_t>(1U << target.value);
|
||||||
|
if (auto states = dali_states_.find(gateway_id); states != dali_states_.end()) {
|
||||||
|
for (auto& state : states->second) {
|
||||||
|
if (state.group_mask_known && (state.group_mask & bit) != 0) {
|
||||||
|
apply(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case GatewayCacheDaliTargetKind::kBroadcast: {
|
||||||
|
auto& states = dali_states_[gateway_id];
|
||||||
|
for (auto& state : states) {
|
||||||
|
apply(state);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GatewayCache::refreshDaliAddressAggregateStatusLocked(uint8_t gateway_id,
|
||||||
|
GatewayCacheDaliAddressState& state) {
|
||||||
|
if (!state.group_mask_known) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (const auto broadcast = dali_broadcast_status_.find(gateway_id);
|
||||||
|
broadcast != dali_broadcast_status_.end()) {
|
||||||
|
applyDaliRuntimeStatusToAddressLocked(state, broadcast->second);
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto groups = dali_group_status_.find(gateway_id);
|
||||||
|
if (groups == dali_group_status_.end()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (uint8_t group_id = 0; group_id < groups->second.size(); ++group_id) {
|
||||||
|
const uint16_t bit = static_cast<uint16_t>(1U << group_id);
|
||||||
|
if ((state.group_mask & bit) != 0) {
|
||||||
|
applyDaliRuntimeStatusToAddressLocked(state, groups->second[group_id]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void GatewayCache::TaskEntry(void* arg) {
|
void GatewayCache::TaskEntry(void* arg) {
|
||||||
static_cast<GatewayCache*>(arg)->taskLoop();
|
static_cast<GatewayCache*>(arg)->taskLoop();
|
||||||
}
|
}
|
||||||
@@ -921,6 +1311,17 @@ GatewayCacheDaliAddressState& GatewayCache::ensureDaliAddressStateLocked(uint8_t
|
|||||||
return it->second[short_address];
|
return it->second[short_address];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GatewayCacheDaliRuntimeStatus& GatewayCache::ensureDaliGroupStatusLocked(uint8_t gateway_id,
|
||||||
|
uint8_t group_id) {
|
||||||
|
auto [it, inserted] = dali_group_status_.try_emplace(gateway_id);
|
||||||
|
(void)inserted;
|
||||||
|
return it->second[group_id];
|
||||||
|
}
|
||||||
|
|
||||||
|
GatewayCacheDaliRuntimeStatus& GatewayCache::ensureDaliBroadcastStatusLocked(uint8_t gateway_id) {
|
||||||
|
return dali_broadcast_status_[gateway_id];
|
||||||
|
}
|
||||||
|
|
||||||
GatewayCache::SceneStore& GatewayCache::ensureSceneStoreLocked(uint8_t gateway_id) {
|
GatewayCache::SceneStore& GatewayCache::ensureSceneStoreLocked(uint8_t gateway_id) {
|
||||||
auto [it, inserted] = scenes_.try_emplace(gateway_id);
|
auto [it, inserted] = scenes_.try_emplace(gateway_id);
|
||||||
if (inserted) {
|
if (inserted) {
|
||||||
|
|||||||
@@ -119,12 +119,19 @@ class GatewayController {
|
|||||||
void publishFrame(const std::vector<uint8_t>& frame);
|
void publishFrame(const std::vector<uint8_t>& frame);
|
||||||
void handleDaliRawFrame(const DaliRawFrame& frame);
|
void handleDaliRawFrame(const DaliRawFrame& frame);
|
||||||
|
|
||||||
|
bool sendRawAndMirror(uint8_t gateway_id, uint8_t raw_addr, uint8_t command);
|
||||||
|
bool sendExtRawAndMirror(uint8_t gateway_id, uint8_t raw_addr, uint8_t command);
|
||||||
|
bool setBrightAndMirror(uint8_t gateway_id, int dec_address, uint8_t level);
|
||||||
|
bool offAndMirror(uint8_t gateway_id, int dec_address);
|
||||||
|
bool onAndMirror(uint8_t gateway_id, int dec_address);
|
||||||
uint8_t resolveInternalGroupRawAddress(uint8_t gateway_id, uint8_t raw_addr);
|
uint8_t resolveInternalGroupRawAddress(uint8_t gateway_id, uint8_t raw_addr);
|
||||||
static uint8_t normalizeGroupTargetType(uint8_t target_type);
|
static uint8_t normalizeGroupTargetType(uint8_t target_type);
|
||||||
static uint8_t normalizeGroupTargetValue(uint8_t target_type, uint8_t target_value);
|
static uint8_t normalizeGroupTargetValue(uint8_t target_type, uint8_t target_value);
|
||||||
static uint8_t internalGroupRawTargetAddress(uint8_t target_type, uint8_t target_value,
|
static uint8_t internalGroupRawTargetAddress(uint8_t target_type, uint8_t target_value,
|
||||||
uint8_t raw_addr);
|
uint8_t raw_addr);
|
||||||
static int internalGroupDecTargetAddress(uint8_t target_type, uint8_t target_value);
|
static int internalGroupDecTargetAddress(uint8_t target_type, uint8_t target_value);
|
||||||
|
static uint8_t rawArcAddressFromDec(int dec_address);
|
||||||
|
static uint8_t rawCommandAddressFromDec(int dec_address);
|
||||||
static int shortAddressFromRaw(uint8_t raw_addr);
|
static int shortAddressFromRaw(uint8_t raw_addr);
|
||||||
static int reverseInRange(int value, int min_value, int max_value);
|
static int reverseInRange(int value, int min_value, int max_value);
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ constexpr const char* kTag = "gateway_controller";
|
|||||||
constexpr size_t kMaxNameBytes = 32;
|
constexpr size_t kMaxNameBytes = 32;
|
||||||
constexpr uint8_t kDaliShortAddressCount = 64;
|
constexpr uint8_t kDaliShortAddressCount = 64;
|
||||||
constexpr uint8_t kDaliSceneCount = 16;
|
constexpr uint8_t kDaliSceneCount = 16;
|
||||||
|
constexpr uint8_t kDaliCmdOff = 0x00;
|
||||||
|
constexpr uint8_t kDaliCmdRecallMax = 0x05;
|
||||||
constexpr TickType_t kMaintenancePollTicks = pdMS_TO_TICKS(20);
|
constexpr TickType_t kMaintenancePollTicks = pdMS_TO_TICKS(20);
|
||||||
|
|
||||||
class LockGuard {
|
class LockGuard {
|
||||||
@@ -558,7 +560,7 @@ void GatewayController::dispatchCommand(const std::vector<uint8_t>& command) {
|
|||||||
}
|
}
|
||||||
case 0x07:
|
case 0x07:
|
||||||
case 0x08:
|
case 0x08:
|
||||||
dali_domain_.sendRaw(gateway_id, addr, data);
|
sendRawAndMirror(gateway_id, addr, data);
|
||||||
break;
|
break;
|
||||||
case 0x09: {
|
case 0x09: {
|
||||||
const auto ids = gatewayIds();
|
const auto ids = gatewayIds();
|
||||||
@@ -575,20 +577,20 @@ void GatewayController::dispatchCommand(const std::vector<uint8_t>& command) {
|
|||||||
break;
|
break;
|
||||||
case 0x10:
|
case 0x10:
|
||||||
case 0x11:
|
case 0x11:
|
||||||
dali_domain_.sendRaw(gateway_id, resolveInternalGroupRawAddress(gateway_id, addr), data);
|
sendRawAndMirror(gateway_id, resolveInternalGroupRawAddress(gateway_id, addr), data);
|
||||||
break;
|
break;
|
||||||
case 0x12:
|
case 0x12:
|
||||||
if (addr == 0xff && data >= 0x10 && data <= 0x1f) {
|
if (addr == 0xff && data >= 0x10 && data <= 0x1f) {
|
||||||
const uint8_t scene_id = static_cast<uint8_t>(data - 0x10);
|
const uint8_t scene_id = static_cast<uint8_t>(data - 0x10);
|
||||||
if (!executeScene(gateway_id, shortAddressFromRaw(addr), scene_id)) {
|
if (!executeScene(gateway_id, shortAddressFromRaw(addr), scene_id)) {
|
||||||
dali_domain_.sendRaw(gateway_id, addr, data);
|
sendRawAndMirror(gateway_id, addr, data);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
dali_domain_.sendRaw(gateway_id, resolveInternalGroupRawAddress(gateway_id, addr), data);
|
sendRawAndMirror(gateway_id, resolveInternalGroupRawAddress(gateway_id, addr), data);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x13:
|
case 0x13:
|
||||||
dali_domain_.sendExtRaw(gateway_id, resolveInternalGroupRawAddress(gateway_id, addr), data);
|
sendExtRawAndMirror(gateway_id, resolveInternalGroupRawAddress(gateway_id, addr), data);
|
||||||
break;
|
break;
|
||||||
case 0x14: {
|
case 0x14: {
|
||||||
const auto result = dali_domain_.queryRaw(gateway_id, resolveInternalGroupRawAddress(gateway_id, addr), data);
|
const auto result = dali_domain_.queryRaw(gateway_id, resolveInternalGroupRawAddress(gateway_id, addr), data);
|
||||||
@@ -645,7 +647,7 @@ void GatewayController::dispatchCommand(const std::vector<uint8_t>& command) {
|
|||||||
const uint8_t b = command[7];
|
const uint8_t b = command[7];
|
||||||
const int target = shortAddressFromRaw(resolveInternalGroupRawAddress(gateway_id, addr));
|
const int target = shortAddressFromRaw(resolveInternalGroupRawAddress(gateway_id, addr));
|
||||||
if (r == 0 && g == 0 && b == 0) {
|
if (r == 0 && g == 0 && b == 0) {
|
||||||
dali_domain_.off(gateway_id, target);
|
offAndMirror(gateway_id, target);
|
||||||
} else {
|
} else {
|
||||||
dali_domain_.setColourRGB(gateway_id, target, r, g, b);
|
dali_domain_.setColourRGB(gateway_id, target, r, g, b);
|
||||||
}
|
}
|
||||||
@@ -755,6 +757,48 @@ void GatewayController::handleDaliRawFrame(const DaliRawFrame& frame) {
|
|||||||
publishPayload(frame.gateway_id, {0x01, frame.gateway_id, addr, data});
|
publishPayload(frame.gateway_id, {0x01, frame.gateway_id, addr, data});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GatewayController::sendRawAndMirror(uint8_t gateway_id, uint8_t raw_addr, uint8_t command) {
|
||||||
|
const bool sent = dali_domain_.sendRaw(gateway_id, raw_addr, command);
|
||||||
|
if (sent) {
|
||||||
|
cache_.mirrorDaliCommand(gateway_id, raw_addr, command);
|
||||||
|
}
|
||||||
|
return sent;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GatewayController::sendExtRawAndMirror(uint8_t gateway_id, uint8_t raw_addr,
|
||||||
|
uint8_t command) {
|
||||||
|
const bool sent = dali_domain_.sendExtRaw(gateway_id, raw_addr, command);
|
||||||
|
if (sent) {
|
||||||
|
cache_.mirrorDaliCommand(gateway_id, raw_addr, command);
|
||||||
|
}
|
||||||
|
return sent;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GatewayController::setBrightAndMirror(uint8_t gateway_id, int dec_address, uint8_t level) {
|
||||||
|
const bool sent = dali_domain_.setBright(gateway_id, dec_address, level);
|
||||||
|
if (sent) {
|
||||||
|
cache_.mirrorDaliCommand(gateway_id, rawArcAddressFromDec(dec_address), level);
|
||||||
|
}
|
||||||
|
return sent;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GatewayController::offAndMirror(uint8_t gateway_id, int dec_address) {
|
||||||
|
const bool sent = dali_domain_.off(gateway_id, dec_address);
|
||||||
|
if (sent) {
|
||||||
|
cache_.mirrorDaliCommand(gateway_id, rawCommandAddressFromDec(dec_address), kDaliCmdOff);
|
||||||
|
}
|
||||||
|
return sent;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GatewayController::onAndMirror(uint8_t gateway_id, int dec_address) {
|
||||||
|
const bool sent = dali_domain_.on(gateway_id, dec_address);
|
||||||
|
if (sent) {
|
||||||
|
cache_.mirrorDaliCommand(gateway_id, rawCommandAddressFromDec(dec_address),
|
||||||
|
kDaliCmdRecallMax);
|
||||||
|
}
|
||||||
|
return sent;
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t GatewayController::resolveInternalGroupRawAddress(uint8_t gateway_id, uint8_t raw_addr) {
|
uint8_t GatewayController::resolveInternalGroupRawAddress(uint8_t gateway_id, uint8_t raw_addr) {
|
||||||
if (raw_addr < 0x80 || raw_addr > 0x9f) {
|
if (raw_addr < 0x80 || raw_addr > 0x9f) {
|
||||||
return raw_addr;
|
return raw_addr;
|
||||||
@@ -808,6 +852,26 @@ int GatewayController::internalGroupDecTargetAddress(uint8_t target_type, uint8_
|
|||||||
return 127;
|
return 127;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t GatewayController::rawArcAddressFromDec(int dec_address) {
|
||||||
|
if (dec_address >= 0 && dec_address < 64) {
|
||||||
|
return static_cast<uint8_t>(dec_address * 2);
|
||||||
|
}
|
||||||
|
if (dec_address >= 64 && dec_address < 80) {
|
||||||
|
return static_cast<uint8_t>(0x80 + (dec_address - 64) * 2);
|
||||||
|
}
|
||||||
|
return 0xfe;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t GatewayController::rawCommandAddressFromDec(int dec_address) {
|
||||||
|
if (dec_address >= 0 && dec_address < 64) {
|
||||||
|
return static_cast<uint8_t>(dec_address * 2 + 1);
|
||||||
|
}
|
||||||
|
if (dec_address >= 64 && dec_address < 80) {
|
||||||
|
return static_cast<uint8_t>(0x80 + (dec_address - 64) * 2 + 1);
|
||||||
|
}
|
||||||
|
return 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
int GatewayController::shortAddressFromRaw(uint8_t raw_addr) {
|
int GatewayController::shortAddressFromRaw(uint8_t raw_addr) {
|
||||||
return raw_addr / 2;
|
return raw_addr / 2;
|
||||||
}
|
}
|
||||||
@@ -859,9 +923,9 @@ bool GatewayController::executeScene(uint8_t gateway_id, int short_address, uint
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (scene_data.brightness <= 0) {
|
if (scene_data.brightness <= 0) {
|
||||||
dali_domain_.off(gateway_id, short_address);
|
offAndMirror(gateway_id, short_address);
|
||||||
} else {
|
} else {
|
||||||
dali_domain_.setBright(gateway_id, short_address, scene_data.brightness);
|
setBrightAndMirror(gateway_id, short_address, scene_data.brightness);
|
||||||
}
|
}
|
||||||
if (scene_data.color_mode == 0) {
|
if (scene_data.color_mode == 0) {
|
||||||
int kelvin = scene_data.data1 * 256 + scene_data.data2;
|
int kelvin = scene_data.data1 * 256 + scene_data.data2;
|
||||||
@@ -877,7 +941,7 @@ bool GatewayController::executeScene(uint8_t gateway_id, int short_address, uint
|
|||||||
dali_domain_.setColourRGB(gateway_id, short_address, scene_data.data1, scene_data.data2,
|
dali_domain_.setColourRGB(gateway_id, short_address, scene_data.data1, scene_data.data2,
|
||||||
scene_data.data3);
|
scene_data.data3);
|
||||||
} else if (scene_data.brightness <= 0) {
|
} else if (scene_data.brightness <= 0) {
|
||||||
dali_domain_.off(gateway_id, short_address);
|
offAndMirror(gateway_id, short_address);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -912,9 +976,9 @@ bool GatewayController::executeGroup(uint8_t gateway_id, uint8_t group_id) {
|
|||||||
if (!group_data.enabled) {
|
if (!group_data.enabled) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return dali_domain_.on(gateway_id,
|
return onAndMirror(gateway_id,
|
||||||
internalGroupDecTargetAddress(group_data.target_type,
|
internalGroupDecTargetAddress(group_data.target_type,
|
||||||
group_data.target_value));
|
group_data.target_value));
|
||||||
}
|
}
|
||||||
|
|
||||||
void GatewayController::handleGatewayNameCommand(uint8_t gateway_id,
|
void GatewayController::handleGatewayNameCommand(uint8_t gateway_id,
|
||||||
|
|||||||
Reference in New Issue
Block a user