Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ICD] Subscription report emission when becoming active #28266

2 changes: 1 addition & 1 deletion src/app/BUILD.gn
Original file line number Diff line number Diff line change
@@ -212,7 +212,7 @@ static_library("app") {
public_deps = [
":app_config",
"${chip_root}/src/access",
"${chip_root}/src/app/icd:cluster-srcs",
"${chip_root}/src/app/icd:observer-srcs",
"${chip_root}/src/lib/address_resolve",
"${chip_root}/src/lib/support",
"${chip_root}/src/messaging",
4 changes: 2 additions & 2 deletions src/app/ReadHandler.h
Original file line number Diff line number Diff line change
@@ -418,8 +418,8 @@ class ReadHandler : public Messaging::ExchangeDelegate
friend class chip::app::reporting::Engine;
friend class chip::app::InteractionModelEngine;

// The report scheduler needs to be able to access StateFlag private functions IsReportable(), IsGeneratingReports() and
// IsDirty() to know when to schedule a run so it is declared as a friend class.
// The report scheduler needs to be able to access StateFlag private functions IsReportable(), IsGeneratingReports(),
// ForceDirtyState() and IsDirty() to know when to schedule a run so it is declared as a friend class.
friend class chip::app::reporting::ReportScheduler;

enum class HandlerState : uint8_t
9 changes: 8 additions & 1 deletion src/app/icd/BUILD.gn
Original file line number Diff line number Diff line change
@@ -17,6 +17,10 @@ import("icd.gni")

# ICD Server sources and configurations

source_set("observer-srcs") {
sources = [ "ICDStateObserver.h" ]
}

# ICD Manager source-set is broken out of the main source-set to enable unit tests
# All sources and configurations used by the ICDManager need to go in this source-set
source_set("manager-srcs") {
@@ -25,7 +29,10 @@ source_set("manager-srcs") {
"ICDManager.h",
]

deps = [ ":cluster-srcs" ]
deps = [
":cluster-srcs",
":observer-srcs",
]
public_deps = [ "${chip_root}/src/credentials:credentials" ]
}

19 changes: 16 additions & 3 deletions src/app/icd/ICDManager.cpp
Original file line number Diff line number Diff line change
@@ -33,19 +33,28 @@
#define ICD_ENFORCE_SIT_SLOW_POLL_LIMIT 0
#endif

#ifndef ICD_REPORT_ON_ENTER_ACTIVE_MODE
// Enabling this makes the devive emmit subscription reports when transitionning from idle to active mode. It gives the device a
lpbeliveau-silabs marked this conversation as resolved.
Show resolved Hide resolved
// chance to sleep for the extent of its idle mode interval before getting awakened to emit reports again.
lpbeliveau-silabs marked this conversation as resolved.
Show resolved Hide resolved
#define ICD_REPORT_ON_ENTER_ACTIVE_MODE 0
#endif

namespace chip {
namespace app {

using namespace chip::app;
using namespace chip::app::Clusters;
using namespace chip::app::Clusters::IcdManagement;

void ICDManager::Init(PersistentStorageDelegate * storage, FabricTable * fabricTable)
void ICDManager::Init(PersistentStorageDelegate * storage, FabricTable * fabricTable, ICDStateObserver * stateObserver)
{
VerifyOrDie(storage != nullptr);
VerifyOrDie(fabricTable != nullptr);
mStorage = storage;
mFabricTable = fabricTable;
VerifyOrDie(stateObserver != nullptr);

mStorage = storage;
mFabricTable = fabricTable;
mStateObserver = stateObserver;

uint32_t activeModeInterval = IcdManagementServer::GetInstance().GetActiveModeInterval();
VerifyOrDie(kFastPollingInterval.count() < activeModeInterval);
@@ -152,6 +161,10 @@ void ICDManager::UpdateOperationState(OperationalState state)
{
ChipLogError(AppServer, "Failed to set Polling Interval: err %" CHIP_ERROR_FORMAT, err.Format());
}

#if ICD_REPORT_ON_ENTER_ACTIVE_MODE
mStateObserver->OnEnterActiveMode();
#endif
lpbeliveau-silabs marked this conversation as resolved.
Show resolved Hide resolved
}
else
{
4 changes: 3 additions & 1 deletion src/app/icd/ICDManager.h
Original file line number Diff line number Diff line change
@@ -16,6 +16,7 @@
*/
#pragma once

#include <app/icd/ICDStateObserver.h>
#include <credentials/FabricTable.h>
#include <lib/support/BitFlags.h>
#include <platform/CHIPDeviceConfig.h>
@@ -51,7 +52,7 @@ class ICDManager
};

ICDManager() {}
void Init(PersistentStorageDelegate * storage, FabricTable * fabricTable);
void Init(PersistentStorageDelegate * storage, FabricTable * fabricTable, ICDStateObserver * stateObserver);
void Shutdown();
void UpdateIcdMode();
void UpdateOperationState(OperationalState state);
@@ -86,6 +87,7 @@ class ICDManager
ICDMode mICDMode = ICDMode::SIT;
PersistentStorageDelegate * mStorage = nullptr;
FabricTable * mFabricTable = nullptr;
ICDStateObserver * mStateObserver = nullptr;
};

} // namespace app
30 changes: 30 additions & 0 deletions src/app/icd/ICDStateObserver.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
*
* Copyright (c) 2023 Project CHIP Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once

namespace chip {
namespace app {

class ICDStateObserver
{
public:
virtual ~ICDStateObserver() {}
virtual void OnEnterActiveMode() = 0;
};

} // namespace app
} // namespace chip
7 changes: 6 additions & 1 deletion src/app/reporting/ReportScheduler.h
Original file line number Diff line number Diff line change
@@ -19,6 +19,7 @@
#pragma once

#include <app/ReadHandler.h>
#include <app/icd/ICDStateObserver.h>
#include <lib/core/CHIPError.h>
#include <system/SystemClock.h>

@@ -38,7 +39,7 @@ class TimerContext
virtual void TimerFired() = 0;
};

class ReportScheduler : public ReadHandler::Observer
class ReportScheduler : public ReadHandler::Observer, public ICDStateObserver
{
public:
/// @brief This class acts as an interface between the report scheduler and the system timer to reduce dependencies on the
@@ -167,11 +168,15 @@ class ReportScheduler : public ReadHandler::Observer

virtual void ReportTimerCallback() = 0;

void TriggerReportEmission() {}
lpbeliveau-silabs marked this conversation as resolved.
Show resolved Hide resolved

/// @brief Check whether a ReadHandler is reportable right now, taking into account its minimum and maximum intervals.
/// @param aReadHandler read handler to check
bool IsReportableNow(ReadHandler * aReadHandler) { return FindReadHandlerNode(aReadHandler)->IsReportableNow(); }
/// @brief Check if a ReadHandler is reportable without considering the timing
bool IsReadHandlerReportable(ReadHandler * aReadHandler) const { return aReadHandler->IsReportable(); }
/// @brief Sets the ForceDirty flag of a ReadHandler
void HandlerForceDirtyState(ReadHandler * aReadHandler) { aReadHandler->ForceDirtyState(); }

/// @brief Get the number of ReadHandlers registered in the scheduler's node pool
size_t GetNumReadHandlers() const { return mNodesPool.Allocated(); }
15 changes: 15 additions & 0 deletions src/app/reporting/ReportSchedulerImpl.cpp
Original file line number Diff line number Diff line change
@@ -37,6 +37,21 @@ ReportSchedulerImpl::ReportSchedulerImpl(TimerDelegate * aTimerDelegate) : Repor
VerifyOrDie(nullptr != mTimerDelegate);
}

/// @brief Method that triggers a report emission on each ReadHandler that is not blocked on its min interval.
/// Each read handler that is not blocked is immediately marked dirty so that it will report as soon as possible.
void ReportSchedulerImpl::OnEnterActiveMode()
{
Timestamp now = mTimerDelegate->GetCurrentMonotonicTimestamp();
lpbeliveau-silabs marked this conversation as resolved.
Show resolved Hide resolved
mNodesPool.ForEachActiveObject([now, this](ReadHandlerNode * node) {
if (now >= node->GetMinTimestamp())
{
this->HandlerForceDirtyState(node->GetReadHandler());
}

return Loop::Continue;
});
}

/// @brief When a ReadHandler is added, register it, which will schedule an engine run
void ReportSchedulerImpl::OnReadHandlerCreated(ReadHandler * aReadHandler)
{
3 changes: 3 additions & 0 deletions src/app/reporting/ReportSchedulerImpl.h
Original file line number Diff line number Diff line change
@@ -32,6 +32,9 @@ class ReportSchedulerImpl : public ReportScheduler
ReportSchedulerImpl(TimerDelegate * aTimerDelegate);
~ReportSchedulerImpl() override { UnregisterAllHandlers(); }

// ICDStateObserver
void OnEnterActiveMode() override;

// ReadHandlerObserver
void OnReadHandlerCreated(ReadHandler * aReadHandler) final;
void OnBecameReportable(ReadHandler * aReadHandler) final;
2 changes: 1 addition & 1 deletion src/app/server/Server.cpp
Original file line number Diff line number Diff line change
@@ -249,7 +249,7 @@ CHIP_ERROR Server::Init(const ServerInitParams & initParams)
#endif // CHIP_CONFIG_ENABLE_SERVER_IM_EVENT

#if CHIP_CONFIG_ENABLE_ICD_SERVER
mICDManager.Init(mDeviceStorage, &GetFabricTable());
mICDManager.Init(mDeviceStorage, &GetFabricTable(), &mReportScheduler);
mICDEventManager.Init(&mICDManager);
#endif // CHIP_CONFIG_ENABLE_ICD_SERVER