From 2a8e7d99240115f747c65248b16e02970809ac0d Mon Sep 17 00:00:00 2001 From: Mathieu Kardous <84793247+mkardous-silabs@users.noreply.github.com> Date: Tue, 19 Nov 2024 12:32:31 -0500 Subject: [PATCH] [SL-UP] Introduce PlatformSleepManager to manage Wi-Fi sleep states (#113) --- examples/platform/silabs/BaseApplication.cpp | 61 ++++----- examples/platform/silabs/BaseApplication.h | 1 + examples/platform/silabs/MatterConfig.cpp | 14 +- examples/platform/silabs/SiWx917/BUILD.gn | 5 - examples/platform/silabs/wifi/icd/BUILD.gn | 37 ------ .../platform/silabs/wifi/icd/SleepManager.cpp | 40 ------ .../platform/silabs/wifi/icd/SleepManager.h | 61 --------- .../silabs/CHIPDevicePlatformConfig.h | 5 - src/platform/silabs/CHIPDevicePlatformEvent.h | 2 +- .../silabs/SiWx917/OTAImageProcessorImpl.cpp | 38 ++---- src/platform/silabs/wifi/BUILD.gn | 11 ++ .../silabs/wifi/SiWx/WifiInterface.cpp | 69 +++++----- .../silabs/wifi/WifiInterfaceAbstraction.cpp | 17 ++- .../silabs/wifi/WifiInterfaceAbstraction.h | 10 +- .../silabs/wifi/icd/WifiSleepManager.cpp | 123 ++++++++++++++++++ .../silabs/wifi/icd/WifiSleepManager.h | 95 ++++++++++++++ 16 files changed, 333 insertions(+), 256 deletions(-) delete mode 100644 examples/platform/silabs/wifi/icd/BUILD.gn delete mode 100644 examples/platform/silabs/wifi/icd/SleepManager.cpp delete mode 100644 examples/platform/silabs/wifi/icd/SleepManager.h create mode 100644 src/platform/silabs/wifi/icd/WifiSleepManager.cpp create mode 100644 src/platform/silabs/wifi/icd/WifiSleepManager.h diff --git a/examples/platform/silabs/BaseApplication.cpp b/examples/platform/silabs/BaseApplication.cpp index 57e082e5514f31..8ca09aeb6b8651 100644 --- a/examples/platform/silabs/BaseApplication.cpp +++ b/examples/platform/silabs/BaseApplication.cpp @@ -67,6 +67,10 @@ #include #include #include + +#if CHIP_CONFIG_ENABLE_ICD_SERVER +#include +#endif // CHIP_CONFIG_ENABLE_ICD_SERVER #endif // SL_WIFI #ifdef DIC_ENABLE @@ -182,25 +186,23 @@ BaseApplicationDelegate BaseApplication::sAppDelegate = BaseApplicationDelegate( void BaseApplicationDelegate::OnCommissioningSessionStarted() { isComissioningStarted = true; + +#if SL_WIFI && CHIP_CONFIG_ENABLE_ICD_SERVER + WifiSleepManager::GetInstance().HandleCommissioningSessionStarted(); +#endif // SL_WIFI && CHIP_CONFIG_ENABLE_ICD_SERVER } void BaseApplicationDelegate::OnCommissioningSessionStopped() { isComissioningStarted = false; + +#if SL_WIFI && CHIP_CONFIG_ENABLE_ICD_SERVER + WifiSleepManager::GetInstance().HandleCommissioningSessionStopped(); +#endif // SL_WIFI && CHIP_CONFIG_ENABLE_ICD_SERVER } void BaseApplicationDelegate::OnCommissioningWindowClosed() { -#if CHIP_CONFIG_ENABLE_ICD_SERVER && SLI_SI917 - if (!BaseApplication::GetProvisionStatus() && !isComissioningStarted) - { - int32_t status = wfx_power_save(RSI_SLEEP_MODE_8, DEEP_SLEEP_WITH_RAM_RETENTION); - if (status != SL_STATUS_OK) - { - ChipLogError(AppServer, "Failed to enable the TA Deep Sleep"); - } - } -#endif // CHIP_CONFIG_ENABLE_ICD_SERVER && SLI_SI917 if (BaseApplication::GetProvisionStatus()) { // After the device is provisioned and the commissioning passed @@ -215,8 +217,14 @@ void BaseApplicationDelegate::OnCommissioningWindowClosed() #endif // QR_CODE_ENABLED #endif // DISPLAY_ENABLED } + +#if SL_WIFI && CHIP_CONFIG_ENABLE_ICD_SERVER + WifiSleepManager::GetInstance().HandleCommissioningWindowClose(); +#endif // SL_WIFI && CHIP_CONFIG_ENABLE_ICD_SERVER } +void BaseApplicationDelegate::OnCommissioningWindowOpened() {} + void BaseApplicationDelegate::OnFabricCommitted(const FabricTable & fabricTable, FabricIndex fabricIndex) { // If we commissioned our first fabric, Update the commissioned status of the App @@ -896,6 +904,9 @@ void BaseApplication::OnPlatformEvent(const ChipDeviceEvent * event, intptr_t) { #if SL_WIFI chip::app::DnssdServer::Instance().StartServer(); +#if CHIP_CONFIG_ENABLE_ICD_SERVER + WifiSleepManager::GetInstance().HandleInternetConnectivityChange(); +#endif // CHIP_CONFIG_ENABLE_ICD_SERVER #endif // SL_WIFI #if SILABS_OTA_ENABLED @@ -903,37 +914,15 @@ void BaseApplication::OnPlatformEvent(const ChipDeviceEvent * event, intptr_t) chip::DeviceLayer::SystemLayer().StartTimer(chip::System::Clock::Seconds32(OTAConfig::kInitOTARequestorDelaySec), InitOTARequestorHandler, nullptr); #endif // SILABS_OTA_ENABLED -#if (CHIP_CONFIG_ENABLE_ICD_SERVER && RS911X_WIFI) - // on power cycle, let the device go to sleep after connection is established - if (BaseApplication::sAppDelegate.isCommissioningInProgress() == false) - { -#if SLI_SI917 - sl_status_t err = wfx_power_save(RSI_SLEEP_MODE_2, ASSOCIATED_POWER_SAVE); -#else - sl_status_t err = wfx_power_save(); -#endif /* SLI_SI917 */ - if (err != SL_STATUS_OK) - { - ChipLogError(AppServer, "wfx_power_save failed: 0x%lx", err); - } - } -#endif /* CHIP_CONFIG_ENABLE_ICD_SERVER && RS911X_WIFI */ } } break; case DeviceEventType::kCommissioningComplete: { -#if (CHIP_CONFIG_ENABLE_ICD_SERVER && RS911X_WIFI) -#if SLI_SI917 - sl_status_t err = wfx_power_save(RSI_SLEEP_MODE_2, ASSOCIATED_POWER_SAVE); -#else - sl_status_t err = wfx_power_save(); -#endif /* SLI_SI917 */ - if (err != SL_STATUS_OK) - { - ChipLogError(AppServer, "wfx_power_save failed: 0x%lx", err); - } -#endif /* CHIP_CONFIG_ENABLE_ICD_SERVER && RS911X_WIFI */ +#if SL_WIFI && CHIP_CONFIG_ENABLE_ICD_SERVER + WifiSleepManager::GetInstance().HandleCommissioningComplete(); +#endif // SL_WIFI && CHIP_CONFIG_ENABLE_ICD_SERVER + // SL-Only #ifdef SL_CATALOG_ZIGBEE_STACK_COMMON_PRESENT #if defined(SL_MATTER_ZIGBEE_CMP) && defined(_SILICON_LABS_32B_SERIES_3) diff --git a/examples/platform/silabs/BaseApplication.h b/examples/platform/silabs/BaseApplication.h index d355447d1b7981..fd16a426c2d944 100644 --- a/examples/platform/silabs/BaseApplication.h +++ b/examples/platform/silabs/BaseApplication.h @@ -71,6 +71,7 @@ class BaseApplicationDelegate : public AppDelegate, public chip::FabricTable::De private: // AppDelegate bool isComissioningStarted = false; + void OnCommissioningWindowOpened() override; void OnCommissioningSessionStarted() override; void OnCommissioningSessionStopped() override; void OnCommissioningWindowClosed() override; diff --git a/examples/platform/silabs/MatterConfig.cpp b/examples/platform/silabs/MatterConfig.cpp index 2475b6455d5eca..3bdac990342627 100644 --- a/examples/platform/silabs/MatterConfig.cpp +++ b/examples/platform/silabs/MatterConfig.cpp @@ -20,12 +20,16 @@ #include "AppConfig.h" #include "BaseApplication.h" #include +#include #include - #include #ifdef SL_WIFI #include + +#if CHIP_CONFIG_ENABLE_ICD_SERVER +#include +#endif // CHIP_CONFIG_ENABLE_ICD_SERVER #endif /* SL_WIFI */ #if PW_RPC_ENABLED @@ -240,7 +244,12 @@ CHIP_ERROR SilabsMatterConfig::InitMatter(const char * appName) // See comment above about OpenThread memory allocation as to why this is WIFI only here. ReturnErrorOnFailure(chip::Platform::MemoryInit()); ReturnErrorOnFailure(InitWiFi()); -#endif + +#if CHIP_CONFIG_ENABLE_ICD_SERVER + err = DeviceLayer::Silabs::WifiSleepManager::GetInstance().Init(); + VerifyOrReturnError(err == CHIP_NO_ERROR, err); +#endif // CHIP_CONFIG_ENABLE_ICD_SERVER +#endif // SL_WIFI ReturnErrorOnFailure(PlatformMgr().InitChipStack()); @@ -299,6 +308,7 @@ CHIP_ERROR SilabsMatterConfig::InitMatter(const char * appName) #endif initParams.appDelegate = &BaseApplication::sAppDelegate; + // Init Matter Server and Start Event Loop err = chip::Server::GetInstance().Init(initParams); diff --git a/examples/platform/silabs/SiWx917/BUILD.gn b/examples/platform/silabs/SiWx917/BUILD.gn index 4ef00d2ede738b..2d6d3574ea3506 100644 --- a/examples/platform/silabs/SiWx917/BUILD.gn +++ b/examples/platform/silabs/SiWx917/BUILD.gn @@ -174,11 +174,6 @@ source_set("siwx917-common") { } } - # Sl-Only: Support for the Wi-Fi Sleep Manager - if (chip_enable_icd_server) { - public_deps += [ "${silabs_common_plat_dir}/wifi/icd:sleep-manager" ] - } - # DIC if (enable_dic) { public_deps += diff --git a/examples/platform/silabs/wifi/icd/BUILD.gn b/examples/platform/silabs/wifi/icd/BUILD.gn deleted file mode 100644 index 7b0e1b1fef1ebd..00000000000000 --- a/examples/platform/silabs/wifi/icd/BUILD.gn +++ /dev/null @@ -1,37 +0,0 @@ -# Copyright (c) 2024 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. - -import("//build_overrides/chip.gni") - -config("sleep-manager-config") { - include_dirs = [ "." ] - defines = [] -} - -source_set("sleep-manager") { - sources = [ - "SleepManager.cpp", - "SleepManager.h", - ] - - public_deps = [ - "${chip_root}/src/app:app", - "${chip_root}/src/app/icd/server:manager", - "${chip_root}/src/app/icd/server:observer", - "${chip_root}/src/lib/core", - "${chip_root}/src/lib/support", - ] - - public_configs = [ ":sleep-manager-config" ] -} diff --git a/examples/platform/silabs/wifi/icd/SleepManager.cpp b/examples/platform/silabs/wifi/icd/SleepManager.cpp deleted file mode 100644 index 8fc181ce19335e..00000000000000 --- a/examples/platform/silabs/wifi/icd/SleepManager.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include "SleepManager.h" - -using namespace chip::app; - -namespace chip { -namespace DeviceLayer { -namespace Silabs { - -// Initialize the static instance -SleepManager SleepManager::mInstance; - -CHIP_ERROR SleepManager::Init() -{ - // Initialization logic - return CHIP_NO_ERROR; -} - -void SleepManager::OnEnterActiveMode() -{ - // Execution logic for entering active mode -} - -void SleepManager::OnEnterIdleMode() -{ - // Execution logic for entering idle mode -} - -void SleepManager::OnSubscriptionEstablished(ReadHandler & aReadHandler) -{ - // Implement logic for when a subscription is established -} - -void SleepManager::OnSubscriptionTerminated(ReadHandler & aReadHandler) -{ - // Implement logic for when a subscription is terminated -} - -} // namespace Silabs -} // namespace DeviceLayer -} // namespace chip diff --git a/examples/platform/silabs/wifi/icd/SleepManager.h b/examples/platform/silabs/wifi/icd/SleepManager.h deleted file mode 100644 index 80db24807c67d4..00000000000000 --- a/examples/platform/silabs/wifi/icd/SleepManager.h +++ /dev/null @@ -1,61 +0,0 @@ - -#pragma once - -#include -#include -#include -#include - -namespace chip { -namespace DeviceLayer { -namespace Silabs { - -/** - * @brief SleepManager is a singleton class that manages the sleep modes for Wi-Fi devices. - * The class contains the buisness logic associated with optimizing the sleep states based on the Matter SDK internal states - * - * The class implements two disctint optimization states; one of SIT devices and one of LIT devices - * For SIT ICDs, the logic is based on the Subscriptions established with the device. - * For LIT ICDs, the logic is based on the ICDManager operating modes. The LIT mode also utilizes the SIT mode logic. - */ -class SleepManager : public chip::app::ICDStateObserver, public chip::app::ReadHandler::ApplicationCallback -{ -public: - SleepManager(const SleepManager &) = delete; - SleepManager & operator=(const SleepManager &) = delete; - - static SleepManager & GetInstance() { return mInstance; } - - /** - * @brief Init function that configure the SleepManager APIs based on the type of ICD - * SIT ICD: Init function registers the ReadHandler Application callback to be notified when a subscription is - * established or destroyed. - * - * LIT ICD: Init function registers with the ICDManager as an observer to be notified of the ICD mode changes. - * - * @return CHIP_ERROR - */ - CHIP_ERROR Init(); - - // ICDStateObserver implementation overrides - - void OnEnterActiveMode(); - void OnEnterIdleMode(); - void OnTransitionToIdle() { /* No execution logic */ } - void OnICDModeChange() { /* No execution logic */ } - - // ReadHandler::ApplicationCallback implementation overrides - - void OnSubscriptionEstablished(chip::app::ReadHandler & aReadHandler); - void OnSubscriptionTerminated(chip::app::ReadHandler & aReadHandler); - -private: - SleepManager() = default; - ~SleepManager() = default; - - static SleepManager mInstance; -}; - -} // namespace Silabs -} // namespace DeviceLayer -} // namespace chip diff --git a/src/platform/silabs/CHIPDevicePlatformConfig.h b/src/platform/silabs/CHIPDevicePlatformConfig.h index d31ce423996686..1b65cfb56e18a2 100644 --- a/src/platform/silabs/CHIPDevicePlatformConfig.h +++ b/src/platform/silabs/CHIPDevicePlatformConfig.h @@ -115,11 +115,6 @@ #define CHIP_DEVICE_CONFIG_ENABLE_IPV4 0 #endif /* CHIP_DEVICE_CONFIG_ENABLE_IPV4 */ -#if SL_ICD_ENABLED -#define CHIP_DEVICE_CONFIG_ICD_SLOW_POLL_INTERVAL chip::System::Clock::Milliseconds32(300) -#define CHIP_DEVICE_CONFIG_ICD_FAST_POLL_INTERVAL chip::System::Clock::Milliseconds32(10) -#endif /* SL_ICD_ENABLED */ - #endif /* SL_WIFI */ // ========== Platform-specific Configuration ========= diff --git a/src/platform/silabs/CHIPDevicePlatformEvent.h b/src/platform/silabs/CHIPDevicePlatformEvent.h index 090ada64037c6f..bbdf3614f914a4 100644 --- a/src/platform/silabs/CHIPDevicePlatformEvent.h +++ b/src/platform/silabs/CHIPDevicePlatformEvent.h @@ -39,7 +39,7 @@ namespace DeviceEventType { */ enum PublicPlatformSpecificEventTypes { - /* None currently defined */ + // No public platform specific events }; /** diff --git a/src/platform/silabs/SiWx917/OTAImageProcessorImpl.cpp b/src/platform/silabs/SiWx917/OTAImageProcessorImpl.cpp index 074097bac7aadf..f9ff53bb5739f1 100644 --- a/src/platform/silabs/SiWx917/OTAImageProcessorImpl.cpp +++ b/src/platform/silabs/SiWx917/OTAImageProcessorImpl.cpp @@ -19,9 +19,9 @@ #include #include #include - #include -#include +#include + #ifdef __cplusplus extern "C" { #endif @@ -157,13 +157,9 @@ void OTAImageProcessorImpl::HandlePrepareDownload(intptr_t context) imageProcessor->mHeaderParser.Init(); - // Setting the device is in high performace - no-sleepy mode while OTA tranfer -#if (CHIP_CONFIG_ENABLE_ICD_SERVER) - status = wfx_power_save(RSI_ACTIVE, HIGH_PERFORMANCE); - if (status != SL_STATUS_OK) - { - ChipLogError(DeviceLayer, "Failed to enable the TA Deep Sleep"); - } +#if CHIP_CONFIG_ENABLE_ICD_SERVER + // Setting the device is in high performace - no-sleepy mode during OTA tranfer + DeviceLayer::Silabs::WifiSleepManager::GetInstance().RequestHighPerformance(); #endif /* CHIP_CONFIG_ENABLE_ICD_SERVER*/ imageProcessor->mDownloader->OnPreparedForDownload(CHIP_NO_ERROR); @@ -200,13 +196,9 @@ void OTAImageProcessorImpl::HandleFinalize(intptr_t context) } imageProcessor->ReleaseBlock(); - // Setting the device back to power save mode when transfer is completed successfully #if (CHIP_CONFIG_ENABLE_ICD_SERVER) - sl_status_t err = wfx_power_save(RSI_SLEEP_MODE_2, ASSOCIATED_POWER_SAVE); - if (err != SL_STATUS_OK) - { - ChipLogError(DeviceLayer, "Power save config for Wifi failed"); - } + // Setting the device back to power save mode when transfer is completed successfully + DeviceLayer::Silabs::WifiSleepManager::GetInstance().RemoveHighPerformanceRequest(); #endif /* CHIP_CONFIG_ENABLE_ICD_SERVER*/ ChipLogProgress(SoftwareUpdate, "OTA image downloaded successfully"); @@ -223,13 +215,9 @@ void OTAImageProcessorImpl::HandleApply(intptr_t context) ChipLogProgress(SoftwareUpdate, "OTA image downloaded successfully in HandleApply"); +#if CHIP_CONFIG_ENABLE_ICD_SERVER // Setting the device is in high performace - no-sleepy mode before soft reset as soft reset is not happening in sleep mode -#if (CHIP_CONFIG_ENABLE_ICD_SERVER) - status = wfx_power_save(RSI_ACTIVE, HIGH_PERFORMANCE); - if (status != SL_STATUS_OK) - { - ChipLogError(DeviceLayer, "Failed to enable the TA Deep Sleep"); - } + DeviceLayer::Silabs::WifiSleepManager::GetInstance().RequestHighPerformance(); #endif /* CHIP_CONFIG_ENABLE_ICD_SERVER*/ if (mReset) @@ -250,13 +238,9 @@ void OTAImageProcessorImpl::HandleAbort(intptr_t context) return; } +#if CHIP_CONFIG_ENABLE_ICD_SERVER // Setting the device back to power save mode when transfer is aborted in the middle -#if (CHIP_CONFIG_ENABLE_ICD_SERVER) - sl_status_t err = wfx_power_save(RSI_SLEEP_MODE_2, ASSOCIATED_POWER_SAVE); - if (err != SL_STATUS_OK) - { - ChipLogError(DeviceLayer, "Power save config for Wifi failed"); - } + DeviceLayer::Silabs::WifiSleepManager::GetInstance().RemoveHighPerformanceRequest(); #endif /* CHIP_CONFIG_ENABLE_ICD_SERVER*/ // Not clearing the image storage area as it is done during each write diff --git a/src/platform/silabs/wifi/BUILD.gn b/src/platform/silabs/wifi/BUILD.gn index 882a66deb4fa9f..865b5f6ff78cc2 100644 --- a/src/platform/silabs/wifi/BUILD.gn +++ b/src/platform/silabs/wifi/BUILD.gn @@ -14,6 +14,7 @@ import("//build_overrides/chip.gni") import("//build_overrides/lwip.gni") +import("${chip_root}/src/app/icd/icd.gni") import("${chip_root}/src/platform/device.gni") import("${chip_root}/third_party/silabs/efr32_sdk.gni") import("${chip_root}/third_party/silabs/silabs_board.gni") @@ -107,6 +108,7 @@ source_set("wifi-platform") { public_deps = [ "${chip_root}/src/app/icd/server:icd-server-config", "${chip_root}/src/inet", + "${chip_root}/src/lib/core", "${chip_root}/src/lib/support", ] @@ -147,4 +149,13 @@ source_set("wifi-platform") { "${silabs_platform_dir}/wifi/lwip-support/lwip_netif.cpp", ] } + + if (chip_enable_icd_server) { + public_deps += [ "${chip_root}/src/app/icd/server:configuration-data" ] + + sources += [ + "${silabs_platform_dir}/wifi/icd/WifiSleepManager.cpp", + "${silabs_platform_dir}/wifi/icd/WifiSleepManager.h", + ] + } } diff --git a/src/platform/silabs/wifi/SiWx/WifiInterface.cpp b/src/platform/silabs/wifi/SiWx/WifiInterface.cpp index 24b00290e330be..cbd383bd070be5 100644 --- a/src/platform/silabs/wifi/SiWx/WifiInterface.cpp +++ b/src/platform/silabs/wifi/SiWx/WifiInterface.cpp @@ -33,6 +33,7 @@ #include "sl_status.h" #include "sl_wifi_device.h" #include "task.h" +#include #include #include #include @@ -82,10 +83,18 @@ extern osSemaphoreId_t sl_rs_ble_init_sem; namespace { -#if CHIP_CONFIG_ENABLE_ICD_SERVER && SLI_SI91X_MCU_INTERFACE +#if CHIP_CONFIG_ENABLE_ICD_SERVER + +constexpr uint32_t kTimeToFullBeaconReception = 5000; // 5 seconds + +#if SLI_SI91X_MCU_INTERFACE // TODO: should be removed once we are getting the press interrupt for button 0 with sleep bool btn0_pressed = false; -#endif // CHIP_CONFIG_ENABLE_ICD_SERVER && SLI_SI91X_MCU_INTERFACE +#ifdef ENABLE_CHIP_SHELL +bool ps_requirement_added = false; +#endif // ENABLE_CHIP_SHELL +#endif // SLI_SI91X_MCU_INTERFACE +#endif // CHIP_CONFIG_ENABLE_ICD_SERVER bool hasNotifiedWifiConnectivity = false; bool hasNotifiedIPV6 = false; @@ -338,14 +347,21 @@ sl_status_t SetWifiConfigurations() sl_status_t status = SL_STATUS_OK; #if CHIP_CONFIG_ENABLE_ICD_SERVER - // Setting the listen interval to 0 which will set it to DTIM interval - sl_wifi_listen_interval_t sleep_interval = { .listen_interval = 0 }; + // [sl-only] Set the listen interval to the slow polling interval during association + sl_wifi_listen_interval_t sleep_interval = { .listen_interval = + chip::ICDConfigurationData::GetInstance().GetSlowPollingInterval().count() }; status = sl_wifi_set_listen_interval(SL_WIFI_CLIENT_INTERFACE, sleep_interval); VerifyOrReturnError(status == SL_STATUS_OK, status); sl_wifi_advanced_client_configuration_t client_config = { .max_retry_attempts = 5 }; status = sl_wifi_set_advanced_client_configuration(SL_WIFI_CLIENT_INTERFACE, &client_config); VerifyOrReturnError(status == SL_STATUS_OK, status); + + // [sl-only] Required configuration for listen interval changes at runtime + status = sl_si91x_set_join_configuration( + SL_WIFI_CLIENT_INTERFACE, (SL_SI91X_JOIN_FEAT_LISTEN_INTERVAL_VALID | SL_SI91X_JOIN_FEAT_PS_CMD_LISTEN_INTERVAL_VALID)); + VerifyOrReturnError(status == SL_STATUS_OK, status); + #endif // CHIP_CONFIG_ENABLE_ICD_SERVER status = sl_net_set_credential(SL_NET_DEFAULT_WIFI_CLIENT_CREDENTIAL_ID, SL_NET_WIFI_PSK, &wfx_rsi.sec.passkey[0], @@ -402,6 +418,8 @@ sl_status_t JoinWifiNetwork(void) if (status == SL_STATUS_OK || status == SL_STATUS_IN_PROGRESS) { + // TODO: Set listen interval to 0 with DTIM sync + WifiEvent event = WifiEvent::kStationConnect; sl_matter_wifi_post_event(event); return status; @@ -846,34 +864,25 @@ void wfx_dhcp_got_ipv4(uint32_t ip) } #endif /* CHIP_DEVICE_CONFIG_ENABLE_IPV4 */ -#if SL_ICD_ENABLED -/********************************************************************* - * @fn sl_status_t wfx_power_save(rsi_power_save_profile_mode_t sl_si91x_ble_state, sl_si91x_performance_profile_t - sl_si91x_wifi_state) - * @brief - * Implements the power save in sleepy application - * @param[in] sl_si91x_ble_state : State to set for the BLE - sl_si91x_wifi_state : State to set for the WiFi - * @return SL_STATUS_OK if successful, - * SL_STATUS_FAIL otherwise - ***********************************************************************/ -sl_status_t wfx_power_save(rsi_power_save_profile_mode_t sl_si91x_ble_state, sl_si91x_performance_profile_t sl_si91x_wifi_state) +#if CHIP_CONFIG_ENABLE_ICD_SERVER + +sl_status_t wfx_power_save(rsi_power_save_profile_mode_t sl_si91x_ble_state, sl_si91x_performance_profile_t sl_si91x_wifi_state, + uint32_t listenInterval) { int32_t error = rsi_bt_power_save_profile(sl_si91x_ble_state, 0); - if (error != RSI_SUCCESS) - { - ChipLogError(DeviceLayer, "rsi_bt_power_save_profile failed: %ld", error); - return SL_STATUS_FAIL; - } + VerifyOrReturnError(error == RSI_SUCCESS, SL_STATUS_FAIL, + ChipLogError(DeviceLayer, "rsi_bt_power_save_profile failed: %ld", error)); - sl_wifi_performance_profile_t wifi_profile = { .profile = sl_si91x_wifi_state }; - sl_status_t status = sl_wifi_set_performance_profile(&wifi_profile); - if (status != SL_STATUS_OK) - { - ChipLogError(DeviceLayer, "sl_wifi_set_performance_profile failed: 0x%lx", static_cast(status)); - return status; - } + sl_wifi_performance_profile_t wifi_profile = { .profile = sl_si91x_wifi_state, + // TODO: Performance profile fails if not alligned with DTIM + .dtim_aligned_type = SL_SI91X_ALIGN_WITH_DTIM_BEACON, + // TODO: Different types need to be fixe in the Wi-Fi SDK + .listen_interval = static_cast(listenInterval) }; - return SL_STATUS_OK; + sl_status_t status = sl_wifi_set_performance_profile(&wifi_profile); + VerifyOrReturnError(status == SL_STATUS_OK, status, + ChipLogError(DeviceLayer, "sl_wifi_set_performance_profile failed: 0x%lx", status)); + + return status; } -#endif +#endif // CHIP_CONFIG_ENABLE_ICD_SERVER diff --git a/src/platform/silabs/wifi/WifiInterfaceAbstraction.cpp b/src/platform/silabs/wifi/WifiInterfaceAbstraction.cpp index ad36a6c6ecffa7..d195262e1e4770 100644 --- a/src/platform/silabs/wifi/WifiInterfaceAbstraction.cpp +++ b/src/platform/silabs/wifi/WifiInterfaceAbstraction.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -37,6 +38,9 @@ using namespace chip::DeviceLayer; // As such we can't depend on the platform here as well extern void HandleWFXSystemEvent(wfx_event_base_t eventBase, sl_wfx_generic_message_t * eventData); +// TODO: We shouldn't need to have access to a global variable in the interface here +extern WfxRsi_t wfx_rsi; + namespace { constexpr uint8_t kWlanMinRetryIntervalsInSec = 1; @@ -50,9 +54,10 @@ osTimerId_t sRetryTimer; */ void RetryConnectionTimerHandler(void * arg) { -#if CHIP_CONFIG_ENABLE_ICD_SERVER && SLI_SI91X_MCU_INTERFACE - wfx_power_save(RSI_ACTIVE, HIGH_PERFORMANCE); -#endif // CHIP_CONFIG_ENABLE_ICD_SERVER && SLI_SI91X_MCU_INTERFACE +#if CHIP_CONFIG_ENABLE_ICD_SERVER + Silabs::WifiSleepManager::GetInstance().RequestHighPerformance(); +#endif // CHIP_CONFIG_ENABLE_ICD_SERVER + if (wfx_connect_to_ap() != SL_STATUS_OK) { ChipLogError(DeviceLayer, "wfx_connect_to_ap() failed."); @@ -191,9 +196,9 @@ void wfx_retry_connection(uint16_t retryAttempt) } return; } -#if CHIP_CONFIG_ENABLE_ICD_SERVER && SLI_SI91X_MCU_INTERFACE - wfx_power_save(RSI_SLEEP_MODE_8, DEEP_SLEEP_WITH_RAM_RETENTION); -#endif // CHIP_CONFIG_ENABLE_ICD_SERVER && SLI_SI91X_MCU_INTERFACE +#if CHIP_CONFIG_ENABLE_ICD_SERVER + Silabs::WifiSleepManager::GetInstance().RemoveHighPerformanceRequest(); +#endif // CHIP_CONFIG_ENABLE_ICD_SERVER ChipLogProgress(DeviceLayer, "wfx_retry_connection : Next attempt after %d Seconds", retryInterval); retryInterval += retryInterval; } diff --git a/src/platform/silabs/wifi/WifiInterfaceAbstraction.h b/src/platform/silabs/wifi/WifiInterfaceAbstraction.h index 19ac163dc1d2e6..faf192673f2c93 100644 --- a/src/platform/silabs/wifi/WifiInterfaceAbstraction.h +++ b/src/platform/silabs/wifi/WifiInterfaceAbstraction.h @@ -195,9 +195,6 @@ typedef struct wfx_rsi_s uint8_t ip4_addr[4]; /* Not sure if this is enough */ } WfxRsi_t; -// TODO: We shouldn't need to have access to a global variable in the interface here -extern WfxRsi_t wfx_rsi; - sl_status_t wfx_wifi_start(void); void wfx_enable_sta_mode(void); void wfx_get_wifi_mac_addr(sl_wfx_interface_t interface, sl_wfx_mac_address_t * addr); @@ -253,16 +250,17 @@ int32_t wfx_rsi_send_data(void * p, uint16_t len); bool wfx_hw_ready(void); +#if CHIP_CONFIG_ENABLE_ICD_SERVER #ifdef RS911X_WIFI // for RS9116, 917 NCP and 917 SoC /* RSI Power Save */ -#if SL_ICD_ENABLED #if (SLI_SI91X_MCU_INTERFACE | EXP_BOARD) -sl_status_t wfx_power_save(rsi_power_save_profile_mode_t sl_si91x_ble_state, sl_si91x_performance_profile_t sl_si91x_wifi_state); +sl_status_t wfx_power_save(rsi_power_save_profile_mode_t sl_si91x_ble_state, sl_si91x_performance_profile_t sl_si91x_wifi_state, + uint32_t listenInterval); #else sl_status_t wfx_power_save(); #endif /* (SLI_SI91X_MCU_INTERFACE | EXP_BOARD) */ -#endif /* SL_ICD_ENABLED */ #endif /* RS911X_WIFI */ +#endif // CHIP_CONFIG_ENABLE_ICD_SERVER void sl_matter_wifi_task(void * arg); diff --git a/src/platform/silabs/wifi/icd/WifiSleepManager.cpp b/src/platform/silabs/wifi/icd/WifiSleepManager.cpp new file mode 100644 index 00000000000000..21fa5b09b6a209 --- /dev/null +++ b/src/platform/silabs/wifi/icd/WifiSleepManager.cpp @@ -0,0 +1,123 @@ +/* + * + * Copyright (c) 2024 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. + */ + +#include +#include +#include +#include + +using namespace chip::app; + +namespace chip { +namespace DeviceLayer { +namespace Silabs { + +// Initialize the static instance +WifiSleepManager WifiSleepManager::mInstance; + +CHIP_ERROR WifiSleepManager::Init() +{ + return CHIP_NO_ERROR; +} + +void WifiSleepManager::HandleCommissioningComplete() +{ + VerifyAndTransitionToLowPowerMode(); +} + +void WifiSleepManager::HandleInternetConnectivityChange() +{ + // TODO: Centralize the buisness logic in the VerifyAndTransitionToLowPowerMode + if (!isCommissioningInProgress) + { + VerifyAndTransitionToLowPowerMode(); + } +} + +void WifiSleepManager::HandleCommissioningWindowClose() {} + +void WifiSleepManager::HandleCommissioningSessionStarted() +{ + isCommissioningInProgress = true; +} + +void WifiSleepManager::HandleCommissioningSessionStopped() +{ + isCommissioningInProgress = false; +} + +CHIP_ERROR WifiSleepManager::RequestHighPerformance() +{ + VerifyOrReturnError(mHighPerformanceRequestCounter < std::numeric_limits::max(), CHIP_ERROR_INTERNAL, + ChipLogError(DeviceLayer, "High performance request counter overflow")); + + if (mHighPerformanceRequestCounter == 0) + { +#if SLI_SI917 // 917 SoC & NCP + VerifyOrReturnError(wfx_power_save(RSI_ACTIVE, HIGH_PERFORMANCE, 0) == SL_STATUS_OK, CHIP_ERROR_INTERNAL, + ChipLogError(DeviceLayer, "Failed to set Wi-FI configuration to HighPerformance")); +#endif // SLI_SI917 + } + + mHighPerformanceRequestCounter++; + return CHIP_NO_ERROR; +} + +CHIP_ERROR WifiSleepManager::RemoveHighPerformanceRequest() +{ + VerifyOrReturnError(mHighPerformanceRequestCounter > 0, CHIP_NO_ERROR, + ChipLogError(DeviceLayer, "Wi-Fi configuration already in low power mode")); + + mHighPerformanceRequestCounter--; + + // We don't do the mHighPerformanceRequestCounter check here; the check is in TransitionToLowPowerMode function + ReturnErrorOnFailure(VerifyAndTransitionToLowPowerMode()); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR WifiSleepManager::VerifyAndTransitionToLowPowerMode() +{ + VerifyOrReturnValue(mHighPerformanceRequestCounter == 0, CHIP_NO_ERROR, + ChipLogDetail(DeviceLayer, "High Performance Requested - Device cannot go to a lower power mode.")); + +#if SLI_SI917 // 917 SoC & NCP + // TODO: Clean this up when the Wi-Fi interface re-work is finished + wfx_wifi_provision_t wifiConfig; + wfx_get_wifi_provision(&wifiConfig); + + if (!(wifiConfig.ssid[0] != 0) && !isCommissioningInProgress) + { + VerifyOrReturnError(wfx_power_save(RSI_SLEEP_MODE_8, DEEP_SLEEP_WITH_RAM_RETENTION, 0) != SL_STATUS_OK, CHIP_ERROR_INTERNAL, + ChipLogError(DeviceLayer, "Failed to enable Deep Sleep.")); + } + else + { + VerifyOrReturnError(wfx_power_save(RSI_SLEEP_MODE_2, ASSOCIATED_POWER_SAVE, 0) != SL_STATUS_OK, CHIP_ERROR_INTERNAL, + ChipLogError(DeviceLayer, "Failed to enable to go to sleep.")); + } +#elif RS911X_WIFI // rs9116 + VerifyOrReturnError(wfx_power_save() != SL_STATUS_OK, CHIP_ERROR_INTERNAL, + ChipLogError(DeviceLayer, "Failed to enable to go to sleep.")); +#endif + + return CHIP_NO_ERROR; +} + +} // namespace Silabs +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/silabs/wifi/icd/WifiSleepManager.h b/src/platform/silabs/wifi/icd/WifiSleepManager.h new file mode 100644 index 00000000000000..38c3cce4d53497 --- /dev/null +++ b/src/platform/silabs/wifi/icd/WifiSleepManager.h @@ -0,0 +1,95 @@ +/* + * + * Copyright (c) 2024 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 + +#include + +namespace chip { +namespace DeviceLayer { +namespace Silabs { + +/** + * @brief WifiSleepManager is a singleton class that manages the sleep modes for Wi-Fi devices. + * The class contains the buisness logic associated with optimizing the sleep states based on the Matter SDK internal states + */ +class WifiSleepManager +{ +public: + WifiSleepManager(const WifiSleepManager &) = delete; + WifiSleepManager & operator=(const WifiSleepManager &) = delete; + + static WifiSleepManager & GetInstance() { return mInstance; } + + /** + * @brief Init function that configure the SleepManager APIs based on the type of ICD. + * Function validates that the SleepManager configuration were correctly set as well. + * + * @return CHIP_ERROR + */ + CHIP_ERROR Init(); + + /** + * @brief Public API to request the Wi-Fi chip to transition to High Performance. + * Function increases the HighPerformance request counter to prevent the chip from going to sleep + * while the Matter SDK is in a state that requires High Performance + * + * @return CHIP_ERROR CHIP_NO_ERROR if the chip was set to high performance or already in high performance + * CHIP_ERROR_INTERNAL, if the high performance configuration failed + */ + CHIP_ERROR RequestHighPerformance(); + + /** + * @brief Public API to remove request to keep the Wi-Fi chip in High Performance. + * If calling this function removes the last High performance request, + * The chip will transition to sleep based on its lowest sleep level allowed + * + * @return CHIP_ERROR CHIP_NO_ERROR if the req removal and sleep transition succeed + * CHIP_ERROR_INTERNAL, if the req removal or the transition to sleep failed + */ + CHIP_ERROR RemoveHighPerformanceRequest(); + + void HandleCommissioningComplete(); + void HandleInternetConnectivityChange(); + void HandleCommissioningWindowClose(); + void HandleCommissioningSessionStarted(); + void HandleCommissioningSessionStopped(); + +private: + WifiSleepManager() = default; + ~WifiSleepManager() = default; + + /** + * @brief Function validates what is the lowest power mode the device can got to and transitions the device to a low pwoer + * state. + * - Unprovisionned and no commissioning in progress: Deep Sleep + * - Otherwise, DTIM based low power mode + * + * @return CHIP_ERROR CHIP_NO_ERROR if the device was transitionned to low power + * CHIP_ERROR_INTERNAL if an error occured + */ + CHIP_ERROR VerifyAndTransitionToLowPowerMode(); + + static WifiSleepManager mInstance; + bool isCommissioningInProgress = false; + + uint8_t mHighPerformanceRequestCounter = 0; +}; + +} // namespace Silabs +} // namespace DeviceLayer +} // namespace chip