feat(gateway): enhance DALI host activity tracking and presence management
Signed-off-by: Tony <tonylu@tony-cloud.com>
This commit is contained in:
@@ -315,7 +315,8 @@ struct DaliDomainService::DaliChannel {
|
||||
|
||||
DaliDomainService::DaliDomainService()
|
||||
: raw_frame_sink_lock_(xSemaphoreCreateMutex()),
|
||||
bus_activity_lock_(xSemaphoreCreateMutex()) {
|
||||
bus_activity_lock_(xSemaphoreCreateMutex()),
|
||||
host_activity_lock_(xSemaphoreCreateMutex()) {
|
||||
esp_log_level_set(TAG, (esp_log_level_t)CONFIG_DALI_LOG_LEVEL);
|
||||
}
|
||||
|
||||
@@ -328,6 +329,10 @@ DaliDomainService::~DaliDomainService() {
|
||||
vSemaphoreDelete(bus_activity_lock_);
|
||||
bus_activity_lock_ = nullptr;
|
||||
}
|
||||
if (host_activity_lock_ != nullptr) {
|
||||
vSemaphoreDelete(host_activity_lock_);
|
||||
host_activity_lock_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool DaliDomainService::bindTransport(const DaliChannelConfig& config, DaliTransportHooks hooks) {
|
||||
@@ -568,11 +573,85 @@ bool DaliDomainService::isBusIdle(uint8_t gateway_id, uint32_t quiet_ms) const {
|
||||
return (xTaskGetTickCount() - last_activity) >= pdMS_TO_TICKS(quiet_ms);
|
||||
}
|
||||
|
||||
void DaliDomainService::markHostActivity(uint8_t gateway_id) const {
|
||||
if (host_activity_lock_ != nullptr) {
|
||||
xSemaphoreTake(host_activity_lock_, portMAX_DELAY);
|
||||
}
|
||||
last_host_activity_ticks_[gateway_id] = xTaskGetTickCount();
|
||||
if (host_activity_lock_ != nullptr) {
|
||||
xSemaphoreGive(host_activity_lock_);
|
||||
}
|
||||
}
|
||||
|
||||
void DaliDomainService::markHostCommandFrame(uint8_t gateway_id, uint8_t raw_addr,
|
||||
uint8_t command) const {
|
||||
const TickType_t now = xTaskGetTickCount();
|
||||
if (host_activity_lock_ != nullptr) {
|
||||
xSemaphoreTake(host_activity_lock_, portMAX_DELAY);
|
||||
}
|
||||
last_host_activity_ticks_[gateway_id] = now;
|
||||
recent_host_command_frames_[gateway_id] = RecentHostCommandFrame{raw_addr, command, now, true};
|
||||
if (host_activity_lock_ != nullptr) {
|
||||
xSemaphoreGive(host_activity_lock_);
|
||||
}
|
||||
}
|
||||
|
||||
bool DaliDomainService::hasRecentHostActivity(uint8_t gateway_id, uint32_t window_ms) const {
|
||||
if (window_ms == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
TickType_t last_activity = 0;
|
||||
if (host_activity_lock_ != nullptr) {
|
||||
xSemaphoreTake(host_activity_lock_, portMAX_DELAY);
|
||||
}
|
||||
if (const auto it = last_host_activity_ticks_.find(gateway_id);
|
||||
it != last_host_activity_ticks_.end()) {
|
||||
last_activity = it->second;
|
||||
}
|
||||
if (host_activity_lock_ != nullptr) {
|
||||
xSemaphoreGive(host_activity_lock_);
|
||||
}
|
||||
if (last_activity == 0) {
|
||||
return false;
|
||||
}
|
||||
return (xTaskGetTickCount() - last_activity) < pdMS_TO_TICKS(window_ms);
|
||||
}
|
||||
|
||||
bool DaliDomainService::matchesRecentHostCommandFrame(uint8_t gateway_id, uint8_t raw_addr,
|
||||
uint8_t command,
|
||||
uint32_t window_ms) const {
|
||||
if (window_ms == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RecentHostCommandFrame frame;
|
||||
if (host_activity_lock_ != nullptr) {
|
||||
xSemaphoreTake(host_activity_lock_, portMAX_DELAY);
|
||||
}
|
||||
if (const auto it = recent_host_command_frames_.find(gateway_id);
|
||||
it != recent_host_command_frames_.end()) {
|
||||
frame = it->second;
|
||||
}
|
||||
if (host_activity_lock_ != nullptr) {
|
||||
xSemaphoreGive(host_activity_lock_);
|
||||
}
|
||||
if (!frame.valid || frame.raw_addr != raw_addr || frame.command != command) {
|
||||
return false;
|
||||
}
|
||||
return (xTaskGetTickCount() - frame.tick) < pdMS_TO_TICKS(window_ms);
|
||||
}
|
||||
|
||||
bool DaliDomainService::writeBridgeFrame(uint8_t gateway_id, const uint8_t* data, size_t len) const {
|
||||
const auto* channel = findChannelByGateway(gateway_id);
|
||||
if (channel == nullptr || !channel->hooks.send) {
|
||||
return false;
|
||||
}
|
||||
if (data != nullptr && len == 3 && (data[0] == 0x10 || data[0] == 0x11)) {
|
||||
markHostCommandFrame(gateway_id, data[1], data[2]);
|
||||
} else {
|
||||
markHostActivity(gateway_id);
|
||||
}
|
||||
markBusActivity(gateway_id);
|
||||
return channel->hooks.send(data, len);
|
||||
}
|
||||
@@ -584,6 +663,11 @@ std::vector<uint8_t> DaliDomainService::transactBridgeFrame(uint8_t gateway_id,
|
||||
if (channel == nullptr || !channel->hooks.transact) {
|
||||
return {};
|
||||
}
|
||||
if (data != nullptr && len == 3 && (data[0] == 0x10 || data[0] == 0x11 || data[0] == 0x12)) {
|
||||
markHostCommandFrame(gateway_id, data[1], data[2]);
|
||||
} else {
|
||||
markHostActivity(gateway_id);
|
||||
}
|
||||
markBusActivity(gateway_id);
|
||||
return channel->hooks.transact(data, len);
|
||||
}
|
||||
@@ -593,6 +677,7 @@ bool DaliDomainService::sendRaw(uint8_t gateway_id, uint8_t raw_addr, uint8_t co
|
||||
if (channel == nullptr || channel->comm == nullptr) {
|
||||
return false;
|
||||
}
|
||||
markHostCommandFrame(gateway_id, raw_addr, command);
|
||||
markBusActivity(gateway_id);
|
||||
return channel->comm->sendRawNew(raw_addr, command);
|
||||
}
|
||||
@@ -602,6 +687,7 @@ bool DaliDomainService::sendExtRaw(uint8_t gateway_id, uint8_t raw_addr, uint8_t
|
||||
if (channel == nullptr || channel->comm == nullptr) {
|
||||
return false;
|
||||
}
|
||||
markHostCommandFrame(gateway_id, raw_addr, command);
|
||||
markBusActivity(gateway_id);
|
||||
return channel->comm->sendExtRawNew(raw_addr, command);
|
||||
}
|
||||
@@ -612,6 +698,7 @@ std::optional<uint8_t> DaliDomainService::queryRaw(uint8_t gateway_id, uint8_t r
|
||||
if (channel == nullptr || channel->comm == nullptr) {
|
||||
return std::nullopt;
|
||||
}
|
||||
markHostCommandFrame(gateway_id, raw_addr, command);
|
||||
markBusActivity(gateway_id);
|
||||
return channel->comm->queryRawNew(raw_addr, command);
|
||||
}
|
||||
@@ -683,6 +770,23 @@ std::optional<DaliDomainSnapshot> DaliDomainService::dt1Snapshot(uint8_t gateway
|
||||
PutOptionalInt(snapshot, "emergencyModeRaw", detailed->emergencyMode);
|
||||
PutOptionalInt(snapshot, "featuresRaw", detailed->feature);
|
||||
PutOptionalInt(snapshot, "deviceStatusRaw", detailed->deviceStatus);
|
||||
PutOptionalInt(snapshot, "batteryChargeLevel", detailed->batteryChargeLevel);
|
||||
PutOptionalInt(snapshot, "functionTestDelayTime", detailed->functionTestDelayTime);
|
||||
PutOptionalInt(snapshot, "durationTestDelayTime", detailed->durationTestDelayTime);
|
||||
PutOptionalInt(snapshot, "functionTestIntervalDays", detailed->functionTestIntervalDays);
|
||||
PutOptionalInt(snapshot, "durationTestIntervalWeeks", detailed->durationTestIntervalWeeks);
|
||||
PutOptionalInt(snapshot, "testExecutionTimeoutDays", detailed->testExecutionTimeoutDays);
|
||||
PutOptionalInt(snapshot, "prolongTimeHalfMinutes", detailed->prolongTimeHalfMinutes);
|
||||
PutOptionalInt(snapshot, "durationTestResultMinutes", detailed->durationTestResultMinutes);
|
||||
PutOptionalInt(snapshot, "lampEmergencyTimeHours", detailed->lampEmergencyTimeHours);
|
||||
PutOptionalInt(snapshot, "lampTotalOperationTimeHours", detailed->lampTotalOperationTimeHours);
|
||||
PutOptionalInt(snapshot, "emergencyLevel", detailed->emergencyLevel);
|
||||
PutOptionalInt(snapshot, "emergencyMinLevel", detailed->emergencyMinLevel);
|
||||
PutOptionalInt(snapshot, "emergencyMaxLevel", detailed->emergencyMaxLevel);
|
||||
PutOptionalInt(snapshot, "ratedDurationMinutes", detailed->ratedDurationMinutes);
|
||||
PutOptionalInt(snapshot, "extendedVersion", detailed->extendedVersion);
|
||||
PutOptionalInt(snapshot, "physicalMinLevel", detailed->physicalMinLevel);
|
||||
PutOptionalInt(snapshot, "emergencyDeviceTypeCode", detailed->emergencyDeviceTypeCode);
|
||||
|
||||
snapshot.bools["testInProgress"] = detailed->testInProgress;
|
||||
snapshot.bools["lampFailure"] = detailed->lampFailure;
|
||||
@@ -736,6 +840,8 @@ std::optional<DaliDomainSnapshot> DaliDomainService::dt1Snapshot(uint8_t gateway
|
||||
snapshot.bools["hardwiredInhibitSupported"] = features.hardwiredInhibitSupported();
|
||||
snapshot.bools["physicalSelectionSupported"] = features.physicalSelectionSupported();
|
||||
snapshot.bools["relightInRestModeSupported"] = features.relightInRestModeSupported();
|
||||
snapshot.ints["derivedEmergencyDeviceTypeCode"] =
|
||||
features.emergencyDeviceTypeCode(detailed->physicalMinLevel);
|
||||
}
|
||||
if (detailed->deviceStatus.has_value()) {
|
||||
const DaliDT1DeviceStatus status(detailed->deviceStatus.value());
|
||||
@@ -1208,9 +1314,11 @@ std::optional<DaliAddressSettingsSnapshot> DaliDomainService::queryAddressSettin
|
||||
|
||||
DaliAddressSettingsSnapshot settings{};
|
||||
|
||||
if (const auto value = channel->dali->base.getPowerOnLevel(short_address); value.has_value()) {
|
||||
settings.power_on_level = static_cast<uint8_t>(*value);
|
||||
const auto power_on_level = channel->dali->base.getPowerOnLevel(short_address);
|
||||
if (!power_on_level.has_value()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
settings.power_on_level = static_cast<uint8_t>(*power_on_level);
|
||||
if (const auto value = channel->dali->base.getSystemFailureLevel(short_address);
|
||||
value.has_value()) {
|
||||
settings.system_failure_level = static_cast<uint8_t>(*value);
|
||||
|
||||
Reference in New Issue
Block a user