diff --git a/examples/platform/silabs/MatterConfig.cpp b/examples/platform/silabs/MatterConfig.cpp index 23ae8a1b39..e405cb71b8 100644 --- a/examples/platform/silabs/MatterConfig.cpp +++ b/examples/platform/silabs/MatterConfig.cpp @@ -338,6 +338,9 @@ CHIP_ERROR SilabsMatterConfig::InitMatter(const char * appName) // Register ReadHandler::ApplicationCallback app::InteractionModelEngine::GetInstance()->RegisterReadHandlerAppCallback( &app::Silabs::ApplicationSleepManager::GetInstance()); + + // Register ICDStateObserver + chip::Server::GetInstance().GetICDManager().RegisterObserver(&app::Silabs::ApplicationSleepManager::GetInstance()); #endif // SL_MATTER_ENABLE_APP_SLEEP_MANAGER // Init Matter Server and Start Event Loop diff --git a/examples/platform/silabs/wifi/icd/ApplicationSleepManager.cpp b/examples/platform/silabs/wifi/icd/ApplicationSleepManager.cpp index d53dafb25f..585a109889 100644 --- a/examples/platform/silabs/wifi/icd/ApplicationSleepManager.cpp +++ b/examples/platform/silabs/wifi/icd/ApplicationSleepManager.cpp @@ -16,12 +16,22 @@ ******************************************************************************/ #include "ApplicationSleepManager.h" +#include #include namespace chip { namespace app { namespace Silabs { +namespace { + +enum class SpecialCaseVendorID : uint16_t +{ + kAppleKeychain = 4996, +}; + +} // namespace + ApplicationSleepManager ApplicationSleepManager::mInstance; CHIP_ERROR ApplicationSleepManager::Init() @@ -92,24 +102,93 @@ bool ApplicationSleepManager::CanGoToLIBasedSleep() ChipLogProgress(AppServer, "Commissioning Window is Open - Cannot go to LI based sleep"); canGoToLIBasedSleep = false; } + else if (mIsInActiveMode) + { + ChipLogProgress(AppServer, "Device is in active mode - Cannot go to LI based sleep"); + canGoToLIBasedSleep = false; + } else { for (auto it = mFabricTable->begin(); it != mFabricTable->end(); ++it) { if (!mSubscriptionsInfoProvider->FabricHasAtLeastOneActiveSubscription(it->GetFabricIndex())) { - ChipLogProgress(AppServer, "Fabric index %u has no active subscriptions - Cannot go to LI based sleep", - it->GetFabricIndex()); - canGoToLIBasedSleep = false; - break; + ChipLogProgress(AppServer, "Fabric index %u has no active subscriptions", it->GetFabricIndex()); + canGoToLIBasedSleep = ProcessSpecialVendorIDCase(it->GetVendorId()); + + if (canGoToLIBasedSleep) + { + ChipLogProgress(AppServer, + "Fabric index %u with vendor ID : %d has an edge case that allows for LI based sleep", + it->GetFabricIndex(), it->GetVendorId()); + } + else + { + // Fabric doesn't meet the requirements to allow us to go to LI based sleep + break; + } } - ChipLogProgress(AppServer, "Fabric index %u has an active subscriptions!", it->GetFabricIndex()); } } return canGoToLIBasedSleep; } +bool ApplicationSleepManager::ProcessSpecialVendorIDCase(chip::VendorId vendorId) +{ + bool hasValidException = false; + switch (to_underlying(vendorId)) + { + case to_underlying(SpecialCaseVendorID::kAppleKeychain): + hasValidException = ProcessKeychainEdgeCase(); + break; + + default: + break; + } + + return hasValidException; +} + +bool ApplicationSleepManager::ProcessKeychainEdgeCase() +{ + bool hasValidException = false; + + for (auto it = mFabricTable->begin(); it != mFabricTable->end(); ++it) + { + if ((it->GetVendorId() == chip::VendorId::Apple) && + mSubscriptionsInfoProvider->FabricHasAtLeastOneActiveSubscription(it->GetFabricIndex())) + { + hasValidException = true; + break; + } + } + + return hasValidException; +} + +void ApplicationSleepManager::OnEnterActiveMode() +{ + mIsInActiveMode = true; + mWifiSleepManager->VerifyAndTransitionToLowPowerMode(); +} + +void ApplicationSleepManager::OnEnterIdleMode() +{ + mIsInActiveMode = false; + mWifiSleepManager->VerifyAndTransitionToLowPowerMode(); +} + +void ApplicationSleepManager::OnTransitionToIdle() +{ + // Nothing to do +} + +void ApplicationSleepManager::OnICDModeChange() +{ + // Nothing to do +} + } // namespace Silabs } // namespace app } // namespace chip diff --git a/examples/platform/silabs/wifi/icd/ApplicationSleepManager.h b/examples/platform/silabs/wifi/icd/ApplicationSleepManager.h index 800c1f980c..374fc3c9c9 100644 --- a/examples/platform/silabs/wifi/icd/ApplicationSleepManager.h +++ b/examples/platform/silabs/wifi/icd/ApplicationSleepManager.h @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -29,7 +30,8 @@ namespace Silabs { class ApplicationSleepManager : public chip::app::ReadHandler::ApplicationCallback, public chip::DeviceLayer::Silabs::WifiSleepManager::ApplicationCallback, - public chip::FabricTable::Delegate + public chip::FabricTable::Delegate, + public chip::app::ICDStateObserver { public: static ApplicationSleepManager & GetInstance() { return mInstance; } @@ -131,6 +133,12 @@ class ApplicationSleepManager : public chip::app::ReadHandler::ApplicationCallba void OnFabricUpdated(const chip::FabricTable & fabricTable, chip::FabricIndex fabricIndex) override {} + // ICDStateObserver implementation + void OnEnterActiveMode() override; + void OnEnterIdleMode() override; + void OnTransitionToIdle() override; + void OnICDModeChange() override; + private: ApplicationSleepManager() = default; ~ApplicationSleepManager() = default; @@ -138,6 +146,33 @@ class ApplicationSleepManager : public chip::app::ReadHandler::ApplicationCallba ApplicationSleepManager(const ApplicationSleepManager &) = delete; ApplicationSleepManager & operator=(const ApplicationSleepManager &) = delete; + /** + * @brief Processes special cases based on the vendor ID. + * + * This method checks if the given vendor ID has any special cases that allow + * the device to go to LI based sleep when the fabric associated to the vendor ID does not have an active subscription. + * + * @param vendorId The vendor ID to check for special cases. + * @return true if the vendor ID has a special case that allows LI based sleep, false otherwise. + */ + bool ProcessSpecialVendorIDCase(chip::VendorId vendorId); + + /** + * @brief Processes the Apple Keychain edge case. + * + * Apple, when commissioning, adds two fabric to the device. One for Apple Home and one for the Appley Keychain. + * Apple Home is the active fabric which is used to communication with the device. The associated fabric also has the active + * subcription. Applye Keychain fabric acts as a safety and doesn't have an active fabric with the device. As such, we need an + * alternate method to check if the device can go to LI based sleep. + * + * This method checks if there is any fabric with the Apple Home vendor ID that + * has at least one active subscription. If such a fabric is found, it allows + * the device to go to LI based sleep. + * + * @return true if the Apple Keychain edge case allows low-power mode, false otherwise. + */ + bool ProcessKeychainEdgeCase(); + static ApplicationSleepManager mInstance; chip::FabricTable * mFabricTable = nullptr; chip::app::SubscriptionsInfoProvider * mSubscriptionsInfoProvider = nullptr; @@ -145,6 +180,7 @@ class ApplicationSleepManager : public chip::app::ReadHandler::ApplicationCallba chip::DeviceLayer::Silabs::WifiSleepManager * mWifiSleepManager = nullptr; bool mIsCommissionningWindowOpen = false; + bool mIsInActiveMode = false; }; } // namespace Silabs diff --git a/src/platform/silabs/CHIPPlatformConfig.h b/src/platform/silabs/CHIPPlatformConfig.h index c6c855ee9c..efd573af8d 100644 --- a/src/platform/silabs/CHIPPlatformConfig.h +++ b/src/platform/silabs/CHIPPlatformConfig.h @@ -118,6 +118,13 @@ #define CHIP_CONFIG_ICD_CLIENTS_SUPPORTED_PER_FABRIC SL_ICD_SUPPORTED_CLIENTS_PER_FABRIC #endif // CHIP_CONFIG_ICD_CLIENTS_SUPPORTED_PER_FABRIC +#ifdef SL_WIFI +#ifndef CHIP_CONFIG_ICD_OBSERVERS_POOL_SIZE +#define CHIP_CONFIG_ICD_OBSERVERS_POOL_SIZE 3 +#endif // CHIP_CONFIG_ICD_OBSERVERS_POOL_SIZE +static_assert(CHIP_CONFIG_ICD_OBSERVERS_POOL_SIZE >= 3, "ICD Observers pool size must be at least 3"); +#endif // SL_WIFI + #endif // defined(CHIP_CONFIG_ENABLE_ICD_SERVER) && CHIP_CONFIG_ENABLE_ICD_SERVER /**