[ICD] StayActiveRequest (#32247)
* Implementation of StayActive request with test
* Regenerated zap files
* Added StayActiveRequest scenarios to the yaml test
* Co-authored-by: Boris Zbarsky <bzbarsky@apple.com>
Applied comments about #if and clarifying maximum guaranteed stay active
* Added the #if back for platforms that build the icd-management-server cluster without being ICD devices
* Applied suggestions
diff --git a/examples/contact-sensor-app/nxp/zap-lit/contact-sensor-app.matter b/examples/contact-sensor-app/nxp/zap-lit/contact-sensor-app.matter
index 9a6eeb7..fa6101b 100644
--- a/examples/contact-sensor-app/nxp/zap-lit/contact-sensor-app.matter
+++ b/examples/contact-sensor-app/nxp/zap-lit/contact-sensor-app.matter
@@ -1337,6 +1337,10 @@
optional octet_string<16> verificationKey = 1;
}
+ request struct StayActiveRequestRequest {
+ int32u stayActiveDuration = 0;
+ }
+
response struct StayActiveResponse = 4 {
int32u promisedActiveDuration = 0;
}
@@ -1346,7 +1350,7 @@
/** Unregister a client from an end device */
fabric command access(invoke: manage) UnregisterClient(UnregisterClientRequest): DefaultSuccess = 2;
/** Request the end device to stay in Active Mode for an additional ActiveModeThreshold */
- command access(invoke: manage) StayActiveRequest(): StayActiveResponse = 3;
+ command access(invoke: manage) StayActiveRequest(StayActiveRequestRequest): StayActiveResponse = 3;
}
endpoint 0 {
diff --git a/examples/contact-sensor-app/nxp/zap-sit/contact-sensor-app.matter b/examples/contact-sensor-app/nxp/zap-sit/contact-sensor-app.matter
index 479f8ba..f82f6a9 100644
--- a/examples/contact-sensor-app/nxp/zap-sit/contact-sensor-app.matter
+++ b/examples/contact-sensor-app/nxp/zap-sit/contact-sensor-app.matter
@@ -1337,6 +1337,10 @@
optional octet_string<16> verificationKey = 1;
}
+ request struct StayActiveRequestRequest {
+ int32u stayActiveDuration = 0;
+ }
+
response struct StayActiveResponse = 4 {
int32u promisedActiveDuration = 0;
}
@@ -1346,7 +1350,7 @@
/** Unregister a client from an end device */
fabric command access(invoke: manage) UnregisterClient(UnregisterClientRequest): DefaultSuccess = 2;
/** Request the end device to stay in Active Mode for an additional ActiveModeThreshold */
- command access(invoke: manage) StayActiveRequest(): StayActiveResponse = 3;
+ command access(invoke: manage) StayActiveRequest(StayActiveRequestRequest): StayActiveResponse = 3;
}
endpoint 0 {
diff --git a/examples/light-switch-app/light-switch-common/light-switch-app.matter b/examples/light-switch-app/light-switch-common/light-switch-app.matter
index 90e6058..b96bf90 100644
--- a/examples/light-switch-app/light-switch-common/light-switch-app.matter
+++ b/examples/light-switch-app/light-switch-common/light-switch-app.matter
@@ -2007,6 +2007,10 @@
optional octet_string<16> verificationKey = 1;
}
+ request struct StayActiveRequestRequest {
+ int32u stayActiveDuration = 0;
+ }
+
response struct StayActiveResponse = 4 {
int32u promisedActiveDuration = 0;
}
@@ -2016,7 +2020,7 @@
/** Unregister a client from an end device */
fabric command access(invoke: manage) UnregisterClient(UnregisterClientRequest): DefaultSuccess = 2;
/** Request the end device to stay in Active Mode for an additional ActiveModeThreshold */
- command access(invoke: manage) StayActiveRequest(): StayActiveResponse = 3;
+ command access(invoke: manage) StayActiveRequest(StayActiveRequestRequest): StayActiveResponse = 3;
}
/** Attributes and commands for scene configuration and manipulation. */
diff --git a/examples/light-switch-app/qpg/zap/switch.matter b/examples/light-switch-app/qpg/zap/switch.matter
index b7f217d..0475721 100644
--- a/examples/light-switch-app/qpg/zap/switch.matter
+++ b/examples/light-switch-app/qpg/zap/switch.matter
@@ -1804,6 +1804,10 @@
optional octet_string<16> verificationKey = 1;
}
+ request struct StayActiveRequestRequest {
+ int32u stayActiveDuration = 0;
+ }
+
response struct StayActiveResponse = 4 {
int32u promisedActiveDuration = 0;
}
@@ -1813,7 +1817,7 @@
/** Unregister a client from an end device */
fabric command access(invoke: manage) UnregisterClient(UnregisterClientRequest): DefaultSuccess = 2;
/** Request the end device to stay in Active Mode for an additional ActiveModeThreshold */
- command access(invoke: manage) StayActiveRequest(): StayActiveResponse = 3;
+ command access(invoke: manage) StayActiveRequest(StayActiveRequestRequest): StayActiveResponse = 3;
}
/** Attributes and commands for scene configuration and manipulation. */
diff --git a/examples/lit-icd-app/lit-icd-common/lit-icd-server-app.matter b/examples/lit-icd-app/lit-icd-common/lit-icd-server-app.matter
index db80008..d4b7f3f 100644
--- a/examples/lit-icd-app/lit-icd-common/lit-icd-server-app.matter
+++ b/examples/lit-icd-app/lit-icd-common/lit-icd-server-app.matter
@@ -1465,6 +1465,10 @@
optional octet_string<16> verificationKey = 1;
}
+ request struct StayActiveRequestRequest {
+ int32u stayActiveDuration = 0;
+ }
+
response struct StayActiveResponse = 4 {
int32u promisedActiveDuration = 0;
}
@@ -1474,7 +1478,7 @@
/** Unregister a client from an end device */
fabric command access(invoke: manage) UnregisterClient(UnregisterClientRequest): DefaultSuccess = 2;
/** Request the end device to stay in Active Mode for an additional ActiveModeThreshold */
- command access(invoke: manage) StayActiveRequest(): StayActiveResponse = 3;
+ command access(invoke: manage) StayActiveRequest(StayActiveRequestRequest): StayActiveResponse = 3;
}
endpoint 0 {
diff --git a/examples/lock-app/lock-common/lock-app.matter b/examples/lock-app/lock-common/lock-app.matter
index f07b85c..1b34782 100644
--- a/examples/lock-app/lock-common/lock-app.matter
+++ b/examples/lock-app/lock-common/lock-app.matter
@@ -1825,6 +1825,10 @@
optional octet_string<16> verificationKey = 1;
}
+ request struct StayActiveRequestRequest {
+ int32u stayActiveDuration = 0;
+ }
+
response struct StayActiveResponse = 4 {
int32u promisedActiveDuration = 0;
}
@@ -1834,7 +1838,7 @@
/** Unregister a client from an end device */
fabric command access(invoke: manage) UnregisterClient(UnregisterClientRequest): DefaultSuccess = 2;
/** Request the end device to stay in Active Mode for an additional ActiveModeThreshold */
- command access(invoke: manage) StayActiveRequest(): StayActiveResponse = 3;
+ command access(invoke: manage) StayActiveRequest(StayActiveRequestRequest): StayActiveResponse = 3;
}
/** An interface to a generic way to secure a door */
diff --git a/examples/lock-app/lock-common/lock-app.zap b/examples/lock-app/lock-common/lock-app.zap
index c5201e7..8ec233c 100644
--- a/examples/lock-app/lock-common/lock-app.zap
+++ b/examples/lock-app/lock-common/lock-app.zap
@@ -2412,10 +2412,10 @@
"side": "server",
"type": "bitmap32",
"included": 1,
- "storageOption": "RAM",
+ "storageOption": "External",
"singleton": 0,
"bounded": 0,
- "defaultValue": "0",
+ "defaultValue": null,
"reportable": 1,
"minInterval": 1,
"maxInterval": 65534,
@@ -2428,10 +2428,10 @@
"side": "server",
"type": "int16u",
"included": 1,
- "storageOption": "RAM",
+ "storageOption": "External",
"singleton": 0,
"bounded": 0,
- "defaultValue": "0x0002",
+ "defaultValue": null,
"reportable": 1,
"minInterval": 0,
"maxInterval": 65344,
@@ -4939,6 +4939,7 @@
"define": "ICD_MANAGEMENT_CLUSTER",
"side": "server",
"enabled": 1,
+ "commands": [],
"attributes": [
{
"name": "IdleModeDuration",
diff --git a/examples/lock-app/qpg/zap/lock.matter b/examples/lock-app/qpg/zap/lock.matter
index 91ff769..9815def 100644
--- a/examples/lock-app/qpg/zap/lock.matter
+++ b/examples/lock-app/qpg/zap/lock.matter
@@ -1481,6 +1481,10 @@
optional octet_string<16> verificationKey = 1;
}
+ request struct StayActiveRequestRequest {
+ int32u stayActiveDuration = 0;
+ }
+
response struct StayActiveResponse = 4 {
int32u promisedActiveDuration = 0;
}
@@ -1490,7 +1494,7 @@
/** Unregister a client from an end device */
fabric command access(invoke: manage) UnregisterClient(UnregisterClientRequest): DefaultSuccess = 2;
/** Request the end device to stay in Active Mode for an additional ActiveModeThreshold */
- command access(invoke: manage) StayActiveRequest(): StayActiveResponse = 3;
+ command access(invoke: manage) StayActiveRequest(StayActiveRequestRequest): StayActiveResponse = 3;
}
/** An interface to a generic way to secure a door */
diff --git a/examples/smoke-co-alarm-app/smoke-co-alarm-common/smoke-co-alarm-app.matter b/examples/smoke-co-alarm-app/smoke-co-alarm-common/smoke-co-alarm-app.matter
index 6c1938c..f318835 100644
--- a/examples/smoke-co-alarm-app/smoke-co-alarm-common/smoke-co-alarm-app.matter
+++ b/examples/smoke-co-alarm-app/smoke-co-alarm-common/smoke-co-alarm-app.matter
@@ -1801,6 +1801,10 @@
optional octet_string<16> verificationKey = 1;
}
+ request struct StayActiveRequestRequest {
+ int32u stayActiveDuration = 0;
+ }
+
response struct StayActiveResponse = 4 {
int32u promisedActiveDuration = 0;
}
@@ -1810,7 +1814,7 @@
/** Unregister a client from an end device */
fabric command access(invoke: manage) UnregisterClient(UnregisterClientRequest): DefaultSuccess = 2;
/** Request the end device to stay in Active Mode for an additional ActiveModeThreshold */
- command access(invoke: manage) StayActiveRequest(): StayActiveResponse = 3;
+ command access(invoke: manage) StayActiveRequest(StayActiveRequestRequest): StayActiveResponse = 3;
}
/** This cluster provides an interface for observing and managing the state of smoke and CO alarms. */
diff --git a/examples/window-app/common/window-app.matter b/examples/window-app/common/window-app.matter
index 7e0053f..7f1b3d3 100644
--- a/examples/window-app/common/window-app.matter
+++ b/examples/window-app/common/window-app.matter
@@ -1899,6 +1899,10 @@
optional octet_string<16> verificationKey = 1;
}
+ request struct StayActiveRequestRequest {
+ int32u stayActiveDuration = 0;
+ }
+
response struct StayActiveResponse = 4 {
int32u promisedActiveDuration = 0;
}
@@ -1908,7 +1912,7 @@
/** Unregister a client from an end device */
fabric command access(invoke: manage) UnregisterClient(UnregisterClientRequest): DefaultSuccess = 2;
/** Request the end device to stay in Active Mode for an additional ActiveModeThreshold */
- command access(invoke: manage) StayActiveRequest(): StayActiveResponse = 3;
+ command access(invoke: manage) StayActiveRequest(StayActiveRequestRequest): StayActiveResponse = 3;
}
/** Provides an interface for controlling and adjusting automatic window coverings. */
diff --git a/src/app/clusters/icd-management-server/icd-management-server.cpp b/src/app/clusters/icd-management-server/icd-management-server.cpp
index 27ecfe7..0f71345 100644
--- a/src/app/clusters/icd-management-server/icd-management-server.cpp
+++ b/src/app/clusters/icd-management-server/icd-management-server.cpp
@@ -364,14 +364,6 @@
#endif // CHIP_CONFIG_ENABLE_ICD_CIP
-Status ICDManagementServer::StayActiveRequest(FabricIndex fabricIndex)
-{
- // TODO: Implementent stay awake logic for end device
- // https://github.com/project-chip/connectedhomeip/issues/24259
- ICDNotifier::GetInstance().NotifyICDManagementEvent(ICDListener::ICDManagementEvents::kStayActiveRequestReceived);
- return InteractionModel::Status::UnsupportedCommand;
-}
-
void ICDManagementServer::Init(PersistentStorageDelegate & storage, Crypto::SymmetricKeystore * symmetricKeystore,
ICDConfigurationData & icdConfigurationData)
{
@@ -433,10 +425,14 @@
bool emberAfIcdManagementClusterStayActiveRequestCallback(CommandHandler * commandObj, const ConcreteCommandPath & commandPath,
const Commands::StayActiveRequest::DecodableType & commandData)
{
- ICDManagementServer server;
- InteractionModel::Status status = server.StayActiveRequest(commandObj->GetAccessingFabricIndex());
-
- commandObj->AddStatus(commandPath, status);
+// Note: We only need this #if statement for platform examples that enable the ICD management server without building the sample
+// as an ICD. Since this is not spec compliant, we should remove this #if statement once we stop compiling the ICD management
+// server in those examples.
+#if CHIP_CONFIG_ENABLE_ICD_SERVER
+ IcdManagement::Commands::StayActiveResponse::Type response;
+ response.promisedActiveDuration = Server::GetInstance().GetICDManager().StayActiveRequest(commandData.stayActiveDuration);
+ commandObj->AddResponse(commandPath, response);
+#endif // CHIP_CONFIG_ENABLE_ICD_SERVER
return true;
}
diff --git a/src/app/clusters/icd-management-server/icd-management-server.h b/src/app/clusters/icd-management-server/icd-management-server.h
index 4462cb9..5c6b838 100644
--- a/src/app/clusters/icd-management-server/icd-management-server.h
+++ b/src/app/clusters/icd-management-server/icd-management-server.h
@@ -68,8 +68,6 @@
const chip::app::Clusters::IcdManagement::Commands::UnregisterClient::DecodableType & commandData);
#endif // CHIP_CONFIG_ENABLE_ICD_CIP
- chip::Protocols::InteractionModel::Status StayActiveRequest(chip::FabricIndex fabricIndex);
-
private:
#if CHIP_CONFIG_ENABLE_ICD_CIP
/**
diff --git a/src/app/icd/server/ICDConfigurationData.h b/src/app/icd/server/ICDConfigurationData.h
index 3fb3e9a..8b87d09 100644
--- a/src/app/icd/server/ICDConfigurationData.h
+++ b/src/app/icd/server/ICDConfigurationData.h
@@ -61,6 +61,8 @@
System::Clock::Milliseconds16 GetActiveModeThreshold() { return mActiveThreshold; }
+ System::Clock::Milliseconds32 GetGuaranteedStayActiveDuration() { return kGuaranteedStayActiveDuration; }
+
Protocols::SecureChannel::CheckInCounter & GetICDCounter() { return mICDCounter; }
uint16_t GetClientsSupportedPerFabric() { return mFabricClientsSupported; }
@@ -123,6 +125,9 @@
static constexpr System::Clock::Seconds32 kMaxIdleModeDuration = System::Clock::Seconds32(18 * kSecondsPerHour);
static constexpr System::Clock::Seconds32 kMinIdleModeDuration = System::Clock::Seconds32(1);
+ // As defined in the spec, the maximum guaranteed duration for the StayActiveDuration is 30s "Matter Application
+ // Clusters: 9.17.7.5.1. PromisedActiveDuration Field"
+ static constexpr System::Clock::Milliseconds32 kGuaranteedStayActiveDuration = System::Clock::Milliseconds32(30000);
static_assert((CHIP_CONFIG_ICD_IDLE_MODE_DURATION_SEC) <= kMaxIdleModeDuration.count(),
"Spec requires the IdleModeDuration to be equal or inferior to 64800s.");
diff --git a/src/app/icd/server/ICDManager.cpp b/src/app/icd/server/ICDManager.cpp
index 057cc08..9317377 100644
--- a/src/app/icd/server/ICDManager.cpp
+++ b/src/app/icd/server/ICDManager.cpp
@@ -120,6 +120,22 @@
#endif // !CONFIG_BUILD_FOR_HOST_UNIT_TEST
}
+uint32_t ICDManager::StayActiveRequest(uint32_t stayActiveDuration)
+{
+ // This should only be called when the device is in ActiveMode
+ VerifyOrReturnValue(mOperationalState == OperationalState::ActiveMode, 0);
+
+ uint32_t promisedActiveDuration =
+ std::min(ICDConfigurationData::GetInstance().GetGuaranteedStayActiveDuration().count(), stayActiveDuration);
+
+ // If the device is already in ActiveMode, we need to extend the active mode duration
+ // for whichever is smallest between 30000 milliseconds and stayActiveDuration, taking in account the remaining active time.
+ ExtendActiveMode(System::Clock::Milliseconds16(promisedActiveDuration));
+ promisedActiveDuration = DeviceLayer::SystemLayer().GetRemainingTime(OnActiveModeDone, this).count();
+
+ return promisedActiveDuration;
+}
+
#if CHIP_CONFIG_ENABLE_ICD_CIP
void ICDManager::SendCheckInMsgs()
{
@@ -366,17 +382,7 @@
}
else
{
- Milliseconds16 activeModeThreshold = ICDConfigurationData::GetInstance().GetActiveModeThreshold();
- DeviceLayer::SystemLayer().ExtendTimerTo(activeModeThreshold, OnActiveModeDone, this);
-
- Milliseconds32 activeModeJitterThreshold = Milliseconds32(ICD_ACTIVE_TIME_JITTER_MS);
- activeModeJitterThreshold =
- (activeModeThreshold >= activeModeJitterThreshold) ? activeModeThreshold - activeModeJitterThreshold : kZero;
-
- if (!mTransitionToIdleCalled)
- {
- DeviceLayer::SystemLayer().ExtendTimerTo(activeModeJitterThreshold, OnTransitionToIdle, this);
- }
+ ExtendActiveMode(ICDConfigurationData::GetInstance().GetActiveModeThreshold());
}
}
}
@@ -521,11 +527,6 @@
case ICDManagementEvents::kTableUpdated:
this->UpdateICDMode();
break;
-
- case ICDManagementEvents::kStayActiveRequestReceived:
- // TODO : Implement the StayActiveRequest
- // https://github.com/project-chip/connectedhomeip/issues/24259
- break;
default:
break;
}
@@ -540,6 +541,19 @@
this->UpdateOperationState(OperationalState::ActiveMode);
}
+void ICDManager::ExtendActiveMode(Milliseconds16 extendDuration)
+{
+ DeviceLayer::SystemLayer().ExtendTimerTo(extendDuration, OnActiveModeDone, this);
+
+ Milliseconds32 activeModeJitterThreshold = Milliseconds32(ICD_ACTIVE_TIME_JITTER_MS);
+ activeModeJitterThreshold = (extendDuration >= activeModeJitterThreshold) ? extendDuration - activeModeJitterThreshold : kZero;
+
+ if (!mTransitionToIdleCalled)
+ {
+ DeviceLayer::SystemLayer().ExtendTimerTo(activeModeJitterThreshold, OnTransitionToIdle, this);
+ }
+}
+
ICDManager::ObserverPointer * ICDManager::RegisterObserver(ICDStateObserver * observer)
{
return mStateObserverPool.CreateObject(observer);
diff --git a/src/app/icd/server/ICDManager.h b/src/app/icd/server/ICDManager.h
index 396e6be..5e391c1 100644
--- a/src/app/icd/server/ICDManager.h
+++ b/src/app/icd/server/ICDManager.h
@@ -109,6 +109,14 @@
void postObserverEvent(ObserverEventType event);
OperationalState GetOperationalState() { return mOperationalState; }
+ /**
+ * @brief Ensures that the remaining Active Mode duration is at least the smaller of 30000 milliseconds and stayActiveDuration.
+ *
+ * @param stayActiveDuration The duration (in milliseconds) requested by the client to stay in Active Mode
+ * @return The duration (in milliseconds) the device will stay in Active Mode
+ */
+ uint32_t StayActiveRequest(uint32_t stayActiveDuration);
+
#if CHIP_CONFIG_ENABLE_ICD_CIP
void SendCheckInMsgs();
@@ -131,6 +139,12 @@
void OnSubscriptionReport() override;
protected:
+ /**
+ * @brief Hepler function that extends the Active Mode duration as well as the Active Mode Jitter timer for the transition to
+ * iddle mode.
+ */
+ void ExtendActiveMode(System::Clock::Milliseconds16 extendDuration);
+
friend class TestICDManager;
static void OnIdleModeDone(System::Layer * aLayer, void * appState);
diff --git a/src/app/icd/server/ICDNotifier.h b/src/app/icd/server/ICDNotifier.h
index 1223732..5db1450 100644
--- a/src/app/icd/server/ICDNotifier.h
+++ b/src/app/icd/server/ICDNotifier.h
@@ -48,8 +48,7 @@
enum class ICDManagementEvents : uint8_t
{
- kTableUpdated = 0x01,
- kStayActiveRequestReceived = 0x02,
+ kTableUpdated = 0x01,
};
using KeepActiveFlags = BitFlags<KeepActiveFlagsValues>;
diff --git a/src/app/tests/TestICDManager.cpp b/src/app/tests/TestICDManager.cpp
index da549ff..ba311f8 100644
--- a/src/app/tests/TestICDManager.cpp
+++ b/src/app/tests/TestICDManager.cpp
@@ -540,6 +540,83 @@
// After the init we should be in Idle mode
NL_TEST_ASSERT(aSuite, ctx->mICDManager.mOperationalState == ICDManager::OperationalState::IdleMode);
}
+
+ /* Test that verifies the logic of the ICDManager when it receives a StayActiveRequest*/
+ static void TestICDMStayActive(nlTestSuite * aSuite, void * aContext)
+ {
+ TestContext * ctx = static_cast<TestContext *>(aContext);
+ ICDNotifier notifier = ICDNotifier::GetInstance();
+ ICDConfigurationData & icdConfigData = ICDConfigurationData::GetInstance();
+
+ // Verify That ICDManager starts in Idle
+ NL_TEST_ASSERT(aSuite, ctx->mICDManager.mOperationalState == ICDManager::OperationalState::IdleMode);
+
+ // Trigger a subscription report. Put the ICD manager into active mode.
+ notifier.NotifySubscriptionReport();
+ NL_TEST_ASSERT(aSuite, ctx->mICDManager.mOperationalState == ICDManager::OperationalState::ActiveMode);
+
+ // Advance time by the ActiveModeDuration - 1
+ AdvanceClockAndRunEventLoop(ctx, icdConfigData.GetActiveModeDuration() - 1_ms32);
+ // Confirm ICD manager is in active mode
+ NL_TEST_ASSERT(aSuite, ctx->mICDManager.mOperationalState == ICDManager::OperationalState::ActiveMode);
+
+ uint32_t stayActiveRequestedMs = 20000;
+ // Send a stay active request for 20 seconds
+ uint32_t stayActivePromisedMs = ctx->mICDManager.StayActiveRequest(stayActiveRequestedMs);
+ // confirm the promised time is the same as the requested time
+ NL_TEST_ASSERT(aSuite, stayActivePromisedMs == stayActiveRequestedMs);
+
+ // Advance time by the duration of the stay stayActiveRequestedMs - 1 ms
+ AdvanceClockAndRunEventLoop(ctx, System::Clock::Milliseconds32(stayActiveRequestedMs) - 1_ms32);
+ // Confirm ICD manager is in active mode
+ NL_TEST_ASSERT(aSuite, ctx->mICDManager.mOperationalState == ICDManager::OperationalState::ActiveMode);
+
+ // Advance time by 1ms and Confirm ICD manager is in idle mode
+ AdvanceClockAndRunEventLoop(ctx, 1_ms32);
+ NL_TEST_ASSERT(aSuite, ctx->mICDManager.mOperationalState == ICDManager::OperationalState::IdleMode);
+
+ // Trigger a subscription report Put the ICD manager into active mode
+ notifier.NotifySubscriptionReport();
+ NL_TEST_ASSERT(aSuite, ctx->mICDManager.mOperationalState == ICDManager::OperationalState::ActiveMode);
+
+ // Advance time by the duration of the stay active request - 1 ms
+ AdvanceClockAndRunEventLoop(ctx, icdConfigData.GetActiveModeDuration() - 1_ms32);
+ stayActiveRequestedMs = 35000;
+ // Send a stay active request for 35 seconds, which is higher than the maximum stay active duration (30 seconds)
+ stayActivePromisedMs = ctx->mICDManager.StayActiveRequest(stayActiveRequestedMs);
+ // confirm the promised time is the maximum stay active duration (30 seconds)
+ NL_TEST_ASSERT(aSuite, stayActivePromisedMs == 30000);
+
+ // Advance time by the duration of the max stay active duration - 1 ms
+ AdvanceClockAndRunEventLoop(ctx, System::Clock::Milliseconds32(30000) - 1_ms32);
+ NL_TEST_ASSERT(aSuite, ctx->mICDManager.mOperationalState == ICDManager::OperationalState::ActiveMode);
+
+ // Advance time by 1ms and Confirm ICD manager is in idle mode
+ AdvanceClockAndRunEventLoop(ctx, 1_ms32);
+ NL_TEST_ASSERT(aSuite, ctx->mICDManager.mOperationalState == ICDManager::OperationalState::IdleMode);
+
+ // Trigger a subscription report Put the ICD manager into active mode
+ notifier.NotifySubscriptionReport();
+ NL_TEST_ASSERT(aSuite, ctx->mICDManager.mOperationalState == ICDManager::OperationalState::ActiveMode);
+
+ // Advance time by the duration of the stay active request - 1 ms
+ AdvanceClockAndRunEventLoop(ctx, icdConfigData.GetActiveModeDuration() - 1_ms32);
+ stayActiveRequestedMs = 30000;
+ // Send a stay active request for 30 seconds
+ stayActivePromisedMs = ctx->mICDManager.StayActiveRequest(stayActiveRequestedMs);
+ // confirm the promised time is the same as the requested time
+ NL_TEST_ASSERT(aSuite, stayActivePromisedMs == 30000);
+
+ // Advance time by the duration of the stay active request - 20000 ms
+ AdvanceClockAndRunEventLoop(ctx, System::Clock::Milliseconds32(stayActiveRequestedMs) - 20000_ms32);
+ // Confirm ICD manager is in active mode, we should have 20000 seconds left at that point
+ NL_TEST_ASSERT(aSuite, ctx->mICDManager.mOperationalState == ICDManager::OperationalState::ActiveMode);
+
+ stayActiveRequestedMs = 10000;
+ stayActivePromisedMs = ctx->mICDManager.StayActiveRequest(stayActiveRequestedMs);
+ // confirm the promised time is 20000 since the device is already planing to stay active longer than the requested time
+ NL_TEST_ASSERT(aSuite, stayActivePromisedMs == 20000);
+ }
};
} // namespace app
@@ -556,6 +633,7 @@
NL_TEST_DEF("TestKeepActivemodeRequests", TestICDManager::TestKeepActivemodeRequests),
NL_TEST_DEF("TestICDMRegisterUnregisterEvents", TestICDManager::TestICDMRegisterUnregisterEvents),
NL_TEST_DEF("TestICDCounter", TestICDManager::TestICDCounter),
+ NL_TEST_DEF("TestICDStayActive", TestICDManager::TestICDMStayActive),
NL_TEST_SENTINEL(),
};
diff --git a/src/app/tests/suites/TestIcdManagementCluster.yaml b/src/app/tests/suites/TestIcdManagementCluster.yaml
index d9d275b..3d00815 100644
--- a/src/app/tests/suites/TestIcdManagementCluster.yaml
+++ b/src/app/tests/suites/TestIcdManagementCluster.yaml
@@ -372,3 +372,82 @@
value: 102
response:
error: NOT_FOUND
+
+ - label:
+ "Wait for a little bit less than the active mode duration (10000ms)"
+ cluster: "DelayCommands"
+ command: "WaitForMs"
+ arguments:
+ values:
+ - name: "ms"
+ value: 9000
+
+ - label:
+ "StayActive Scenario 1: Confirm the promised active duration is
+ increased to a specific if a value less than 30000ms is requested and
+ the device does not intend to stay active longer"
+ command: "StayActiveRequest"
+ arguments:
+ values:
+ - name: "StayActiveDuration"
+ value: 20000
+ response:
+ values:
+ - name: "PromisedActiveDuration"
+ constraints:
+ type: int32u
+ minValue: 19500
+ maxValue: 20500
+
+ - label:
+ "Wait for a little bit less than the new promied active mode duration
+ (20000ms)"
+ cluster: "DelayCommands"
+ command: "WaitForMs"
+ arguments:
+ values:
+ - name: "ms"
+ value: 19000
+
+ - label:
+ "StayActive Scenario 2: Confirm the promised active duration is
+ reduced to 30000ms if a value greater than 30000ms is requested"
+ command: "StayActiveRequest"
+ arguments:
+ values:
+ - name: "StayActiveDuration"
+ value: 35000
+ response:
+ values:
+ - name: "PromisedActiveDuration"
+ constraints:
+ type: int32u
+ minValue: 29500
+ maxValue: 30500
+
+ - label:
+ "Wait for a 20000 less than the new promied active mode duration
+ (30000ms)"
+ cluster: "DelayCommands"
+ command: "WaitForMs"
+ arguments:
+ values:
+ - name: "ms"
+ value: 10000
+
+ - label:
+ "StayActive Scenario 3: confirm that the device ignores the request if
+ the device intends to stay active longer than the requested duration
+ we should have about 20000ms left here"
+ command: "StayActiveRequest"
+ arguments:
+ values:
+ - name: "StayActiveDuration"
+ value: 10000
+ response:
+ values:
+ - name: "PromisedActiveDuration"
+ constraints:
+ type: int32u
+ minValue: 19500
+ maxValue: 20500
diff --git a/src/app/zap-templates/zcl/data-model/chip/icd-management-cluster.xml b/src/app/zap-templates/zcl/data-model/chip/icd-management-cluster.xml
index a266591..d68cc30 100644
--- a/src/app/zap-templates/zcl/data-model/chip/icd-management-cluster.xml
+++ b/src/app/zap-templates/zcl/data-model/chip/icd-management-cluster.xml
@@ -111,6 +111,7 @@
<command source="client" code="0x03" name="StayActiveRequest" response="StayActiveResponse" optional="true">
<description>Request the end device to stay in Active Mode for an additional ActiveModeThreshold</description>
<access op="invoke" privilege="manage"/>
+ <arg name="StayActiveDuration" type="int32u" isNullable="false"/>
</command>
<command source="server" code="0x04" name="StayActiveResponse" optional="true" disableDefaultResponse="true">
diff --git a/src/controller/data_model/controller-clusters.matter b/src/controller/data_model/controller-clusters.matter
index 8611f4b..5dece39 100644
--- a/src/controller/data_model/controller-clusters.matter
+++ b/src/controller/data_model/controller-clusters.matter
@@ -2740,6 +2740,10 @@
optional octet_string<16> verificationKey = 1;
}
+ request struct StayActiveRequestRequest {
+ int32u stayActiveDuration = 0;
+ }
+
response struct StayActiveResponse = 4 {
int32u promisedActiveDuration = 0;
}
@@ -2749,7 +2753,7 @@
/** Unregister a client from an end device */
fabric command access(invoke: manage) UnregisterClient(UnregisterClientRequest): DefaultSuccess = 2;
/** Request the end device to stay in Active Mode for an additional ActiveModeThreshold */
- command access(invoke: manage) StayActiveRequest(): StayActiveResponse = 3;
+ command access(invoke: manage) StayActiveRequest(StayActiveRequestRequest): StayActiveResponse = 3;
}
/** This cluster supports creating a simple timer functionality. */
diff --git a/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java b/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java
index 7025f3c..c55a45b 100644
--- a/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java
+++ b/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java
@@ -18170,14 +18170,18 @@
}}, commandId, commandArgs, timedInvokeTimeoutMs);
}
- public void stayActiveRequest(StayActiveResponseCallback callback) {
- stayActiveRequest(callback, 0);
+ public void stayActiveRequest(StayActiveResponseCallback callback, Long stayActiveDuration) {
+ stayActiveRequest(callback, stayActiveDuration, 0);
}
- public void stayActiveRequest(StayActiveResponseCallback callback, int timedInvokeTimeoutMs) {
+ public void stayActiveRequest(StayActiveResponseCallback callback, Long stayActiveDuration, int timedInvokeTimeoutMs) {
final long commandId = 3L;
ArrayList<StructElement> elements = new ArrayList<>();
+ final long stayActiveDurationFieldID = 0L;
+ BaseTLVType stayActiveDurationtlvValue = new UIntType(stayActiveDuration);
+ elements.add(new StructElement(stayActiveDurationFieldID, stayActiveDurationtlvValue));
+
StructType commandArgs = new StructType(elements);
invoke(new InvokeCallbackImpl(callback) {
@Override
diff --git a/src/controller/java/generated/java/chip/devicecontroller/ClusterIDMapping.java b/src/controller/java/generated/java/chip/devicecontroller/ClusterIDMapping.java
index a1d43e3..3437b8a 100644
--- a/src/controller/java/generated/java/chip/devicecontroller/ClusterIDMapping.java
+++ b/src/controller/java/generated/java/chip/devicecontroller/ClusterIDMapping.java
@@ -5881,6 +5881,23 @@
}
throw new NoSuchFieldError();
}
+ }public enum StayActiveRequestCommandField {StayActiveDuration(0),;
+ private final int id;
+ StayActiveRequestCommandField(int id) {
+ this.id = id;
+ }
+
+ public int getID() {
+ return id;
+ }
+ public static StayActiveRequestCommandField value(int id) throws NoSuchFieldError {
+ for (StayActiveRequestCommandField field : StayActiveRequestCommandField.values()) {
+ if (field.getID() == id) {
+ return field;
+ }
+ }
+ throw new NoSuchFieldError();
+ }
}@Override
public String getAttributeName(long id) throws NoSuchFieldError {
return Attribute.value(id).toString();
diff --git a/src/controller/java/generated/java/chip/devicecontroller/ClusterInfoMapping.java b/src/controller/java/generated/java/chip/devicecontroller/ClusterInfoMapping.java
index 5162f97..4ded328 100644
--- a/src/controller/java/generated/java/chip/devicecontroller/ClusterInfoMapping.java
+++ b/src/controller/java/generated/java/chip/devicecontroller/ClusterInfoMapping.java
@@ -23352,10 +23352,16 @@
icdManagementClusterInteractionInfoMap.put("unregisterClient", icdManagementunregisterClientInteractionInfo);
Map<String, CommandParameterInfo> icdManagementstayActiveRequestCommandParams = new LinkedHashMap<String, CommandParameterInfo>();
+
+ CommandParameterInfo icdManagementstayActiveRequeststayActiveDurationCommandParameterInfo = new CommandParameterInfo("stayActiveDuration", Long.class, Long.class);
+ icdManagementstayActiveRequestCommandParams.put("stayActiveDuration",icdManagementstayActiveRequeststayActiveDurationCommandParameterInfo);
InteractionInfo icdManagementstayActiveRequestInteractionInfo = new InteractionInfo(
(cluster, callback, commandArguments) -> {
((ChipClusters.IcdManagementCluster) cluster)
.stayActiveRequest((ChipClusters.IcdManagementCluster.StayActiveResponseCallback) callback
+ , (Long)
+ commandArguments.get("stayActiveDuration")
+
);
},
() -> new DelegatedIcdManagementClusterStayActiveResponseCallback(),
diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/IcdManagementCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/IcdManagementCluster.kt
index 9421d92..008aa63 100644
--- a/src/controller/java/generated/java/matter/controller/cluster/clusters/IcdManagementCluster.kt
+++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/IcdManagementCluster.kt
@@ -193,11 +193,17 @@
logger.log(Level.FINE, "Invoke command succeeded: ${response}")
}
- suspend fun stayActiveRequest(timedInvokeTimeout: Duration? = null): StayActiveResponse {
+ suspend fun stayActiveRequest(
+ stayActiveDuration: UInt,
+ timedInvokeTimeout: Duration? = null
+ ): StayActiveResponse {
val commandId: UInt = 3u
val tlvWriter = TlvWriter()
tlvWriter.startStructure(AnonymousTag)
+
+ val TAG_STAY_ACTIVE_DURATION_REQ: Int = 0
+ tlvWriter.put(ContextSpecificTag(TAG_STAY_ACTIVE_DURATION_REQ), stayActiveDuration)
tlvWriter.endStructure()
val request: InvokeRequest =
diff --git a/src/controller/python/chip/clusters/CHIPClusters.py b/src/controller/python/chip/clusters/CHIPClusters.py
index 853fd1f..3bc7158 100644
--- a/src/controller/python/chip/clusters/CHIPClusters.py
+++ b/src/controller/python/chip/clusters/CHIPClusters.py
@@ -4078,6 +4078,7 @@
"commandId": 0x00000003,
"commandName": "StayActiveRequest",
"args": {
+ "stayActiveDuration": "int",
},
},
},
diff --git a/src/controller/python/chip/clusters/Objects.py b/src/controller/python/chip/clusters/Objects.py
index 3f5c116..cd411b9 100644
--- a/src/controller/python/chip/clusters/Objects.py
+++ b/src/controller/python/chip/clusters/Objects.py
@@ -14304,8 +14304,11 @@
def descriptor(cls) -> ClusterObjectDescriptor:
return ClusterObjectDescriptor(
Fields=[
+ ClusterObjectFieldDescriptor(Label="stayActiveDuration", Tag=0, Type=uint),
])
+ stayActiveDuration: 'uint' = 0
+
@dataclass
class StayActiveResponse(ClusterCommand):
cluster_id: typing.ClassVar[int] = 0x00000046
diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h b/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h
index 9f7d6f8..6232b64 100644
--- a/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h
+++ b/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h
@@ -4491,9 +4491,7 @@
*
* Request the end device to stay in Active Mode for an additional ActiveModeThreshold
*/
-- (void)stayActiveRequestWithParams:(MTRICDManagementClusterStayActiveRequestParams * _Nullable)params completion:(void (^)(MTRICDManagementClusterStayActiveResponseParams * _Nullable data, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE;
-- (void)stayActiveRequestWithCompletion:(void (^)(MTRICDManagementClusterStayActiveResponseParams * _Nullable data, NSError * _Nullable error))completion
- MTR_PROVISIONALLY_AVAILABLE;
+- (void)stayActiveRequestWithParams:(MTRICDManagementClusterStayActiveRequestParams *)params completion:(void (^)(MTRICDManagementClusterStayActiveResponseParams * _Nullable data, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE;
- (void)readAttributeIdleModeDurationWithCompletion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE;
- (void)subscribeAttributeIdleModeDurationWithParams:(MTRSubscribeParams *)params
diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.mm b/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.mm
index 8cca4c8..b375488 100644
--- a/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.mm
+++ b/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.mm
@@ -37049,11 +37049,7 @@
queue:self.callbackQueue
completion:responseHandler];
}
-- (void)stayActiveRequestWithCompletion:(void (^)(MTRICDManagementClusterStayActiveResponseParams * _Nullable data, NSError * _Nullable error))completion
-{
- [self stayActiveRequestWithParams:nil completion:completion];
-}
-- (void)stayActiveRequestWithParams:(MTRICDManagementClusterStayActiveRequestParams * _Nullable)params completion:(void (^)(MTRICDManagementClusterStayActiveResponseParams * _Nullable data, NSError * _Nullable error))completion
+- (void)stayActiveRequestWithParams:(MTRICDManagementClusterStayActiveRequestParams *)params completion:(void (^)(MTRICDManagementClusterStayActiveResponseParams * _Nullable data, NSError * _Nullable error))completion
{
if (params == nil) {
params = [[MTRICDManagementClusterStayActiveRequestParams
diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRClusters.h b/src/darwin/Framework/CHIP/zap-generated/MTRClusters.h
index d8bc645..7ce97cf 100644
--- a/src/darwin/Framework/CHIP/zap-generated/MTRClusters.h
+++ b/src/darwin/Framework/CHIP/zap-generated/MTRClusters.h
@@ -2090,9 +2090,7 @@
- (void)registerClientWithParams:(MTRICDManagementClusterRegisterClientParams *)params expectedValues:(NSArray<NSDictionary<NSString *, id> *> * _Nullable)expectedDataValueDictionaries expectedValueInterval:(NSNumber * _Nullable)expectedValueIntervalMs completion:(void (^)(MTRICDManagementClusterRegisterClientResponseParams * _Nullable data, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE;
- (void)unregisterClientWithParams:(MTRICDManagementClusterUnregisterClientParams *)params expectedValues:(NSArray<NSDictionary<NSString *, id> *> * _Nullable)expectedDataValueDictionaries expectedValueInterval:(NSNumber * _Nullable)expectedValueIntervalMs completion:(MTRStatusCompletion)completion MTR_PROVISIONALLY_AVAILABLE;
-- (void)stayActiveRequestWithParams:(MTRICDManagementClusterStayActiveRequestParams * _Nullable)params expectedValues:(NSArray<NSDictionary<NSString *, id> *> * _Nullable)expectedDataValueDictionaries expectedValueInterval:(NSNumber * _Nullable)expectedValueIntervalMs completion:(void (^)(MTRICDManagementClusterStayActiveResponseParams * _Nullable data, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE;
-- (void)stayActiveRequestWithExpectedValues:(NSArray<NSDictionary<NSString *, id> *> * _Nullable)expectedValues expectedValueInterval:(NSNumber * _Nullable)expectedValueIntervalMs completion:(void (^)(MTRICDManagementClusterStayActiveResponseParams * _Nullable data, NSError * _Nullable error))completion
- MTR_PROVISIONALLY_AVAILABLE;
+- (void)stayActiveRequestWithParams:(MTRICDManagementClusterStayActiveRequestParams *)params expectedValues:(NSArray<NSDictionary<NSString *, id> *> * _Nullable)expectedDataValueDictionaries expectedValueInterval:(NSNumber * _Nullable)expectedValueIntervalMs completion:(void (^)(MTRICDManagementClusterStayActiveResponseParams * _Nullable data, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE;
- (NSDictionary<NSString *, id> * _Nullable)readAttributeIdleModeDurationWithParams:(MTRReadParams * _Nullable)params MTR_PROVISIONALLY_AVAILABLE;
diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRClusters.mm b/src/darwin/Framework/CHIP/zap-generated/MTRClusters.mm
index 2374d7f..db27925 100644
--- a/src/darwin/Framework/CHIP/zap-generated/MTRClusters.mm
+++ b/src/darwin/Framework/CHIP/zap-generated/MTRClusters.mm
@@ -6080,11 +6080,7 @@
completion:responseHandler];
}
-- (void)stayActiveRequestWithExpectedValues:(NSArray<NSDictionary<NSString *, id> *> *)expectedValues expectedValueInterval:(NSNumber *)expectedValueIntervalMs completion:(void (^)(MTRICDManagementClusterStayActiveResponseParams * _Nullable data, NSError * _Nullable error))completion
-{
- [self stayActiveRequestWithParams:nil expectedValues:expectedValues expectedValueInterval:expectedValueIntervalMs completion:completion];
-}
-- (void)stayActiveRequestWithParams:(MTRICDManagementClusterStayActiveRequestParams * _Nullable)params expectedValues:(NSArray<NSDictionary<NSString *, id> *> * _Nullable)expectedValues expectedValueInterval:(NSNumber * _Nullable)expectedValueIntervalMs completion:(void (^)(MTRICDManagementClusterStayActiveResponseParams * _Nullable data, NSError * _Nullable error))completion
+- (void)stayActiveRequestWithParams:(MTRICDManagementClusterStayActiveRequestParams *)params expectedValues:(NSArray<NSDictionary<NSString *, id> *> * _Nullable)expectedValues expectedValueInterval:(NSNumber * _Nullable)expectedValueIntervalMs completion:(void (^)(MTRICDManagementClusterStayActiveResponseParams * _Nullable data, NSError * _Nullable error))completion
{
if (params == nil) {
params = [[MTRICDManagementClusterStayActiveRequestParams
diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.h b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.h
index 8f2b070..ccd23b3 100644
--- a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.h
+++ b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.h
@@ -3697,6 +3697,8 @@
MTR_PROVISIONALLY_AVAILABLE
@interface MTRICDManagementClusterStayActiveRequestParams : NSObject <NSCopying>
+
+@property (nonatomic, copy) NSNumber * _Nonnull stayActiveDuration MTR_PROVISIONALLY_AVAILABLE;
/**
* Controls whether the command is a timed command (using Timed Invoke).
*
diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.mm b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.mm
index 60757c9..3105c9a 100644
--- a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.mm
+++ b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.mm
@@ -9783,6 +9783,8 @@
- (instancetype)init
{
if (self = [super init]) {
+
+ _stayActiveDuration = @(0);
_timedInvokeTimeoutMs = nil;
_serverSideProcessingTimeout = nil;
}
@@ -9793,6 +9795,7 @@
{
auto other = [[MTRICDManagementClusterStayActiveRequestParams alloc] init];
+ other.stayActiveDuration = self.stayActiveDuration;
other.timedInvokeTimeoutMs = self.timedInvokeTimeoutMs;
other.serverSideProcessingTimeout = self.serverSideProcessingTimeout;
@@ -9801,7 +9804,7 @@
- (NSString *)description
{
- NSString * descriptionString = [NSString stringWithFormat:@"<%@: >", NSStringFromClass([self class])];
+ NSString * descriptionString = [NSString stringWithFormat:@"<%@: stayActiveDuration:%@; >", NSStringFromClass([self class]), _stayActiveDuration];
return descriptionString;
}
@@ -9813,6 +9816,9 @@
{
chip::app::Clusters::IcdManagement::Commands::StayActiveRequest::Type encodableStruct;
ListFreer listFreer;
+ {
+ encodableStruct.stayActiveDuration = self.stayActiveDuration.unsignedIntValue;
+ }
auto buffer = chip::System::PacketBufferHandle::New(chip::System::PacketBuffer::kMaxSizeWithoutReserve, 0);
if (buffer.IsNull()) {
diff --git a/src/system/SystemLayer.h b/src/system/SystemLayer.h
index 427bf00..d91a80d 100644
--- a/src/system/SystemLayer.h
+++ b/src/system/SystemLayer.h
@@ -142,6 +142,9 @@
* This method searches for the timer matching the provided parameters.
* and returns whether it is still "running" and waiting to trigger or not.
*
+ * @note This is used to verify by how long the ExtendTimer method extends the timer, as it may ignore an extension request
+ * if it is shorter than the current timer's remaining time.
+ *
* @param[in] onComplete A pointer to the function called when timer expires.
* @param[in] appState A pointer to the application state object used when timer expires.
*
@@ -151,6 +154,17 @@
virtual bool IsTimerActive(TimerCompleteCallback onComplete, void * appState) = 0;
/**
+ * @brief
+ * This method searches for the timer matching the provided parameters
+ * and returns the remaining time left before it expires.
+ * @param[in] onComplete A pointer to the function called when timer expires.
+ * @param[in] appState A pointer to the application state object used when timer expires.
+ *
+ * @return The remaining time left before the timer expires.
+ */
+ virtual Clock::Timeout GetRemainingTime(TimerCompleteCallback onComplete, void * appState) = 0;
+
+ /**
* @brief This method cancels a one-shot timer, started earlier through @p StartTimer(). This method must
* be called while in the Matter context (from the Matter event loop, or while holding the Matter
* stack lock).
diff --git a/src/system/SystemLayerImplFreeRTOS.cpp b/src/system/SystemLayerImplFreeRTOS.cpp
index cfc8e09..59265f6 100644
--- a/src/system/SystemLayerImplFreeRTOS.cpp
+++ b/src/system/SystemLayerImplFreeRTOS.cpp
@@ -96,6 +96,11 @@
return (mTimerList.GetRemainingTime(onComplete, appState) > Clock::kZero);
}
+Clock::Timeout LayerImplFreeRTOS::GetRemainingTime(TimerCompleteCallback onComplete, void * appState)
+{
+ return mTimerList.GetRemainingTime(onComplete, appState);
+}
+
void LayerImplFreeRTOS::CancelTimer(TimerCompleteCallback onComplete, void * appState)
{
assertChipStackLockedByCurrentThread();
diff --git a/src/system/SystemLayerImplFreeRTOS.h b/src/system/SystemLayerImplFreeRTOS.h
index 2e7401d..fe0e9be 100644
--- a/src/system/SystemLayerImplFreeRTOS.h
+++ b/src/system/SystemLayerImplFreeRTOS.h
@@ -42,6 +42,7 @@
CHIP_ERROR StartTimer(Clock::Timeout delay, TimerCompleteCallback onComplete, void * appState) override;
CHIP_ERROR ExtendTimerTo(Clock::Timeout delay, TimerCompleteCallback onComplete, void * appState) override;
bool IsTimerActive(TimerCompleteCallback onComplete, void * appState) override;
+ Clock::Timeout GetRemainingTime(TimerCompleteCallback onComplete, void * appState) override;
void CancelTimer(TimerCompleteCallback onComplete, void * appState) override;
CHIP_ERROR ScheduleWork(TimerCompleteCallback onComplete, void * appState) override;
diff --git a/src/system/SystemLayerImplSelect.cpp b/src/system/SystemLayerImplSelect.cpp
index 7ae25a0..86ff1cb 100644
--- a/src/system/SystemLayerImplSelect.cpp
+++ b/src/system/SystemLayerImplSelect.cpp
@@ -255,6 +255,11 @@
return timerIsActive;
}
+Clock::Timeout LayerImplSelect::GetRemainingTime(TimerCompleteCallback onComplete, void * appState)
+{
+ return mTimerList.GetRemainingTime(onComplete, appState);
+}
+
void LayerImplSelect::CancelTimer(TimerCompleteCallback onComplete, void * appState)
{
assertChipStackLockedByCurrentThread();
diff --git a/src/system/SystemLayerImplSelect.h b/src/system/SystemLayerImplSelect.h
index 060657e..1bab3db 100644
--- a/src/system/SystemLayerImplSelect.h
+++ b/src/system/SystemLayerImplSelect.h
@@ -65,6 +65,7 @@
CHIP_ERROR StartTimer(Clock::Timeout delay, TimerCompleteCallback onComplete, void * appState) override;
CHIP_ERROR ExtendTimerTo(Clock::Timeout delay, TimerCompleteCallback onComplete, void * appState) override;
bool IsTimerActive(TimerCompleteCallback onComplete, void * appState) override;
+ Clock::Timeout GetRemainingTime(TimerCompleteCallback onComplete, void * appState) override;
void CancelTimer(TimerCompleteCallback onComplete, void * appState) override;
CHIP_ERROR ScheduleWork(TimerCompleteCallback onComplete, void * appState) override;
diff --git a/zzz_generated/app-common/app-common/zap-generated/cluster-objects.cpp b/zzz_generated/app-common/app-common/zap-generated/cluster-objects.cpp
index fc5a2bd..32b6263 100644
--- a/zzz_generated/app-common/app-common/zap-generated/cluster-objects.cpp
+++ b/zzz_generated/app-common/app-common/zap-generated/cluster-objects.cpp
@@ -9794,6 +9794,7 @@
CHIP_ERROR Type::Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const
{
DataModel::WrappedStructEncoder encoder{ aWriter, aTag };
+ encoder.Encode(to_underlying(Fields::kStayActiveDuration), stayActiveDuration);
return encoder.Finalize();
}
@@ -9807,6 +9808,19 @@
{
return std::get<CHIP_ERROR>(__element);
}
+
+ CHIP_ERROR err = CHIP_NO_ERROR;
+ const uint8_t __context_tag = std::get<uint8_t>(__element);
+
+ if (__context_tag == to_underlying(Fields::kStayActiveDuration))
+ {
+ err = DataModel::Decode(reader, stayActiveDuration);
+ }
+ else
+ {
+ }
+
+ ReturnErrorOnFailure(err);
}
}
} // namespace StayActiveRequest.
diff --git a/zzz_generated/app-common/app-common/zap-generated/cluster-objects.h b/zzz_generated/app-common/app-common/zap-generated/cluster-objects.h
index dfdf2e6..89c36f3 100644
--- a/zzz_generated/app-common/app-common/zap-generated/cluster-objects.h
+++ b/zzz_generated/app-common/app-common/zap-generated/cluster-objects.h
@@ -13302,6 +13302,7 @@
namespace StayActiveRequest {
enum class Fields : uint8_t
{
+ kStayActiveDuration = 0,
};
struct Type
@@ -13311,6 +13312,8 @@
static constexpr CommandId GetCommandId() { return Commands::StayActiveRequest::Id; }
static constexpr ClusterId GetClusterId() { return Clusters::IcdManagement::Id; }
+ uint32_t stayActiveDuration = static_cast<uint32_t>(0);
+
CHIP_ERROR Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const;
using ResponseType = Clusters::IcdManagement::Commands::StayActiveResponse::DecodableType;
@@ -13324,6 +13327,7 @@
static constexpr CommandId GetCommandId() { return Commands::StayActiveRequest::Id; }
static constexpr ClusterId GetClusterId() { return Clusters::IcdManagement::Id; }
+ uint32_t stayActiveDuration = static_cast<uint32_t>(0);
CHIP_ERROR Decode(TLV::TLVReader & reader);
};
}; // namespace StayActiveRequest
diff --git a/zzz_generated/chip-tool/zap-generated/cluster/Commands.h b/zzz_generated/chip-tool/zap-generated/cluster/Commands.h
index 6191eb2..8a3081e 100644
--- a/zzz_generated/chip-tool/zap-generated/cluster/Commands.h
+++ b/zzz_generated/chip-tool/zap-generated/cluster/Commands.h
@@ -4314,6 +4314,7 @@
IcdManagementStayActiveRequest(CredentialIssuerCommands * credsIssuerConfig) :
ClusterCommand("stay-active-request", credsIssuerConfig)
{
+ AddArgument("StayActiveDuration", 0, UINT32_MAX, &mRequest.stayActiveDuration);
ClusterCommand::AddArguments();
}
diff --git a/zzz_generated/darwin-framework-tool/zap-generated/cluster/Commands.h b/zzz_generated/darwin-framework-tool/zap-generated/cluster/Commands.h
index 60843e7..be046cb 100644
--- a/zzz_generated/darwin-framework-tool/zap-generated/cluster/Commands.h
+++ b/zzz_generated/darwin-framework-tool/zap-generated/cluster/Commands.h
@@ -47653,6 +47653,9 @@
IcdManagementStayActiveRequest()
: ClusterCommand("stay-active-request")
{
+#if MTR_ENABLE_PROVISIONAL
+ AddArgument("StayActiveDuration", 0, UINT32_MAX, &mRequest.stayActiveDuration);
+#endif // MTR_ENABLE_PROVISIONAL
ClusterCommand::AddArguments();
}
@@ -47667,6 +47670,9 @@
__auto_type * cluster = [[MTRBaseClusterICDManagement alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue];
__auto_type * params = [[MTRICDManagementClusterStayActiveRequestParams alloc] init];
params.timedInvokeTimeoutMs = mTimedInteractionTimeoutMs.HasValue() ? [NSNumber numberWithUnsignedShort:mTimedInteractionTimeoutMs.Value()] : nil;
+#if MTR_ENABLE_PROVISIONAL
+ params.stayActiveDuration = [NSNumber numberWithUnsignedInt:mRequest.stayActiveDuration];
+#endif // MTR_ENABLE_PROVISIONAL
uint16_t repeatCount = mRepeatCount.ValueOr(1);
uint16_t __block responsesNeeded = repeatCount;
while (repeatCount--) {
@@ -47693,6 +47699,7 @@
}
private:
+ chip::app::Clusters::IcdManagement::Commands::StayActiveRequest::Type mRequest;
};
#endif // MTR_ENABLE_PROVISIONAL