diff --git a/examples/platform/silabs/SiWx917/SiWx917/sl_wifi_if.c b/examples/platform/silabs/SiWx917/SiWx917/sl_wifi_if.c index 8f738e36159dc6..5a4e1a533c65c1 100644 --- a/examples/platform/silabs/SiWx917/SiWx917/sl_wifi_if.c +++ b/examples/platform/silabs/SiWx917/SiWx917/sl_wifi_if.c @@ -192,7 +192,7 @@ sl_status_t join_callback_handler(sl_wifi_event_t event, char * result, uint32_t return SL_STATUS_OK; } -#if SL_ICD_ENABLED +#if CHIP_DEVICE_CONFIG_ENABLE_SED /****************************************************************** * @fn wfx_rsi_power_save() * @brief @@ -222,7 +222,7 @@ int32_t wfx_rsi_power_save() SILABS_LOG("Powersave Config Success"); return status; } -#endif /* SL_ICD_ENABLED */ +#endif /* CHIP_DEVICE_CONFIG_ENABLE_SED */ /************************************************************************************* * @fn static int32_t wfx_wifi_rsi_init(void) diff --git a/examples/pump-app/silabs/src/AppTask.cpp b/examples/pump-app/silabs/src/AppTask.cpp index b37d10852d0bd9..d870092d6527a4 100644 --- a/examples/pump-app/silabs/src/AppTask.cpp +++ b/examples/pump-app/silabs/src/AppTask.cpp @@ -135,7 +135,7 @@ void AppTask::AppTaskMain(void * pvParameter) appError(err); } -#if !(defined(CHIP_CONFIG_ENABLE_ICD_SERVER) && CHIP_CONFIG_ENABLE_ICD_SERVER) +#if !(defined(CHIP_DEVICE_CONFIG_ENABLE_SED) && CHIP_DEVICE_CONFIG_ENABLE_SED) sAppTask.StartStatusLEDTimer(); #endif diff --git a/examples/window-app/silabs/src/AppTask.cpp b/examples/window-app/silabs/src/AppTask.cpp index 4765c48fa4d987..9adf137a5ccc04 100644 --- a/examples/window-app/silabs/src/AppTask.cpp +++ b/examples/window-app/silabs/src/AppTask.cpp @@ -120,7 +120,7 @@ void AppTask::AppTaskMain(void * pvParameter) appError(err); } -#if !(defined(CHIP_CONFIG_ENABLE_ICD_SERVER) && CHIP_CONFIG_ENABLE_ICD_SERVER) +#if !(defined(CHIP_DEVICE_CONFIG_ENABLE_SED) && CHIP_DEVICE_CONFIG_ENABLE_SED) sAppTask.StartStatusLEDTimer(); #endif diff --git a/src/app/FailSafeContext.cpp b/src/app/FailSafeContext.cpp index b11ad8775c84df..d79a36f14f045b 100644 --- a/src/app/FailSafeContext.cpp +++ b/src/app/FailSafeContext.cpp @@ -52,6 +52,14 @@ void FailSafeContext::HandleDisarmFailSafe(intptr_t arg) void FailSafeContext::SetFailSafeArmed(bool armed) { +#if CHIP_DEVICE_CONFIG_ENABLE_SED + if (IsFailSafeArmed() != armed) + { + // Per spec, we should be staying in active mode while a fail-safe is + // armed. + DeviceLayer::ConnectivityMgr().RequestSEDActiveMode(armed); + } +#endif // CHIP_DEVICE_CONFIG_ENABLE_SED #if CHIP_CONFIG_ENABLE_ICD_SERVER if (IsFailSafeArmed() != armed) { diff --git a/src/app/server/CommissioningWindowManager.cpp b/src/app/server/CommissioningWindowManager.cpp index 270f4dad57cb39..cbc7c44e7fb6f8 100644 --- a/src/app/server/CommissioningWindowManager.cpp +++ b/src/app/server/CommissioningWindowManager.cpp @@ -98,6 +98,14 @@ void CommissioningWindowManager::ResetState() mECMIterations = 0; mECMSaltLength = 0; +#if CHIP_DEVICE_CONFIG_ENABLE_SED + if (mSEDActiveModeEnabled) + { + DeviceLayer::ConnectivityMgr().RequestSEDActiveMode(false); + mSEDActiveModeEnabled = false; + } +#endif + UpdateWindowStatus(CommissioningWindowStatusEnum::kWindowNotOpen); UpdateOpenerFabricIndex(NullNullable); @@ -237,6 +245,14 @@ CHIP_ERROR CommissioningWindowManager::AdvertiseAndListenForPASE() mPairingSession.Clear(); +#if CHIP_DEVICE_CONFIG_ENABLE_SED + if (!mSEDActiveModeEnabled) + { + mSEDActiveModeEnabled = true; + DeviceLayer::ConnectivityMgr().RequestSEDActiveMode(true); + } +#endif + ReturnErrorOnFailure(mServer->GetExchangeManager().RegisterUnsolicitedMessageHandlerForType( Protocols::SecureChannel::MsgType::PBKDFParamRequest, this)); mListeningForPASE = true; diff --git a/src/app/server/CommissioningWindowManager.h b/src/app/server/CommissioningWindowManager.h index df9b1dcd5e36c6..fae3c075f5b518 100644 --- a/src/app/server/CommissioningWindowManager.h +++ b/src/app/server/CommissioningWindowManager.h @@ -211,6 +211,10 @@ class CommissioningWindowManager : public Messaging::UnsolicitedMessageHandler, uint32_t mECMSaltLength = 0; uint8_t mECMSalt[kSpake2p_Max_PBKDF_Salt_Length]; +#if CHIP_DEVICE_CONFIG_ENABLE_SED + bool mSEDActiveModeEnabled = false; +#endif + // For tests only, so that we can test the commissioning window timeout // without having to wait 3 minutes. Optional mMinCommissioningTimeoutOverride; diff --git a/src/include/platform/ConnectivityManager.h b/src/include/platform/ConnectivityManager.h index cdacf50b663979..79eaa37423542a 100755 --- a/src/include/platform/ConnectivityManager.h +++ b/src/include/platform/ConnectivityManager.h @@ -204,6 +204,28 @@ class ConnectivityManager void ResetThreadNetworkDiagnosticsCounts(); CHIP_ERROR WriteThreadNetworkDiagnosticAttributeToTlv(AttributeId attributeId, app::AttributeValueEncoder & encoder); +// Sleepy end device methods +#if CHIP_DEVICE_CONFIG_ENABLE_SED + CHIP_ERROR GetSEDIntervalsConfig(SEDIntervalsConfig & intervalsConfig); + + /** + * Sets Sleepy End Device intervals configuration and posts kSEDIntervalChange event to inform other software + * modules about the change. + * + * @param[in] intervalsConfig intervals configuration to be set + */ + CHIP_ERROR SetSEDIntervalsConfig(const SEDIntervalsConfig & intervalsConfig); + + /** + * Requests setting Sleepy End Device active interval on or off. + * Every method call with onOff parameter set to true or false results in incrementing or decrementing the active mode + * consumers counter. Active mode is set if the consumers counter is bigger than 0. + * + * @param[in] onOff true if active mode should be enabled and false otherwise. + */ + CHIP_ERROR RequestSEDActiveMode(bool onOff, bool delayIdle = false); +#endif + CHIP_ERROR SetPollingInterval(System::Clock::Milliseconds32 pollingInterval); // CHIPoBLE service methods @@ -448,6 +470,23 @@ inline CHIP_ERROR ConnectivityManager::SetThreadDeviceType(ThreadDeviceType devi return static_cast(this)->_SetThreadDeviceType(deviceType); } +#if CHIP_DEVICE_CONFIG_ENABLE_SED +inline CHIP_ERROR ConnectivityManager::GetSEDIntervalsConfig(SEDIntervalsConfig & intervalsConfig) +{ + return static_cast(this)->_GetSEDIntervalsConfig(intervalsConfig); +} + +inline CHIP_ERROR ConnectivityManager::SetSEDIntervalsConfig(const SEDIntervalsConfig & intervalsConfig) +{ + return static_cast(this)->_SetSEDIntervalsConfig(intervalsConfig); +} + +inline CHIP_ERROR ConnectivityManager::RequestSEDActiveMode(bool onOff, bool delayIdle) +{ + return static_cast(this)->_RequestSEDActiveMode(onOff, delayIdle); +} +#endif + inline CHIP_ERROR ConnectivityManager::SetPollingInterval(System::Clock::Milliseconds32 pollingInterval) { #if CHIP_CONFIG_ENABLE_ICD_SERVER diff --git a/src/include/platform/ThreadStackManager.h b/src/include/platform/ThreadStackManager.h index bfd8875551a84b..589d138ba77773 100755 --- a/src/include/platform/ThreadStackManager.h +++ b/src/include/platform/ThreadStackManager.h @@ -163,6 +163,26 @@ class ThreadStackManager ConnectivityManager::ThreadDeviceType GetThreadDeviceType(); CHIP_ERROR SetThreadDeviceType(ConnectivityManager::ThreadDeviceType threadRole); +#if CHIP_DEVICE_CONFIG_ENABLE_SED + CHIP_ERROR GetSEDIntervalsConfig(ConnectivityManager::SEDIntervalsConfig & intervalsConfig); + + /** + * Sets Sleepy End Device intervals configuration and posts kICDPollingIntervalChange event to inform other software + * modules about the change. + * + * @param[in] intervalsConfig intervals configuration to be set + */ + CHIP_ERROR SetSEDIntervalsConfig(const ConnectivityManager::SEDIntervalsConfig & intervalsConfig); + + /** + * Requests setting Sleepy End Device active interval on or off. + * Every method call with onOff parameter set to true or false results in incrementing or decrementing the active mode + * consumers counter. Active mode is set if the consumers counter is bigger than 0. + * + * @param[in] onOff true if active mode should be enabled and false otherwise. + */ + CHIP_ERROR RequestSEDActiveMode(bool onOff, bool delayIdle = false); +#endif #if CHIP_CONFIG_ENABLE_ICD_SERVER CHIP_ERROR SetPollingInterval(System::Clock::Milliseconds32 pollingInterval); #endif @@ -373,6 +393,23 @@ inline CHIP_ERROR ThreadStackManager::SetThreadDeviceType(ConnectivityManager::T return static_cast(this)->_SetThreadDeviceType(deviceType); } +#if CHIP_DEVICE_CONFIG_ENABLE_SED +inline CHIP_ERROR ThreadStackManager::GetSEDIntervalsConfig(ConnectivityManager::SEDIntervalsConfig & intervalsConfig) +{ + return static_cast(this)->_GetSEDIntervalsConfig(intervalsConfig); +} + +inline CHIP_ERROR ThreadStackManager::SetSEDIntervalsConfig(const ConnectivityManager::SEDIntervalsConfig & intervalsConfig) +{ + return static_cast(this)->_SetSEDIntervalsConfig(intervalsConfig); +} + +inline CHIP_ERROR ThreadStackManager::RequestSEDActiveMode(bool onOff, bool delayIdle) +{ + return static_cast(this)->_RequestSEDActiveMode(onOff, delayIdle); +} +#endif + #if CHIP_CONFIG_ENABLE_ICD_SERVER inline CHIP_ERROR ThreadStackManager::SetPollingInterval(System::Clock::Milliseconds32 pollingInterval) { diff --git a/src/include/platform/internal/GenericConnectivityManagerImpl_Thread.h b/src/include/platform/internal/GenericConnectivityManagerImpl_Thread.h index a1d24c2e1c80d4..0f8b568d0393dd 100755 --- a/src/include/platform/internal/GenericConnectivityManagerImpl_Thread.h +++ b/src/include/platform/internal/GenericConnectivityManagerImpl_Thread.h @@ -63,6 +63,11 @@ class GenericConnectivityManagerImpl_Thread bool _IsThreadApplicationControlled(); ConnectivityManager::ThreadDeviceType _GetThreadDeviceType(); CHIP_ERROR _SetThreadDeviceType(ConnectivityManager::ThreadDeviceType deviceType); +#if CHIP_DEVICE_CONFIG_ENABLE_SED + CHIP_ERROR _GetSEDIntervalsConfig(ConnectivityManager::SEDIntervalsConfig & intervalsConfig); + CHIP_ERROR _SetSEDIntervalsConfig(const ConnectivityManager::SEDIntervalsConfig & intervalsConfig); + CHIP_ERROR _RequestSEDActiveMode(bool onOff, bool delayIdle = false); +#endif #if CHIP_CONFIG_ENABLE_ICD_SERVER CHIP_ERROR _SetPollingInterval(System::Clock::Milliseconds32 pollingInterval); #endif /* CHIP_CONFIG_ENABLE_ICD_SERVER */ @@ -139,6 +144,28 @@ GenericConnectivityManagerImpl_Thread::_SetThreadDeviceType(Connectiv return ThreadStackMgrImpl().SetThreadDeviceType(deviceType); } +#if CHIP_DEVICE_CONFIG_ENABLE_SED +template +inline CHIP_ERROR +GenericConnectivityManagerImpl_Thread::_GetSEDIntervalsConfig(ConnectivityManager::SEDIntervalsConfig & intervalsConfig) +{ + return ThreadStackMgrImpl().GetSEDIntervalsConfig(intervalsConfig); +} + +template +inline CHIP_ERROR GenericConnectivityManagerImpl_Thread::_SetSEDIntervalsConfig( + const ConnectivityManager::SEDIntervalsConfig & intervalsConfig) +{ + return ThreadStackMgrImpl().SetSEDIntervalsConfig(intervalsConfig); +} + +template +inline CHIP_ERROR GenericConnectivityManagerImpl_Thread::_RequestSEDActiveMode(bool onOff, bool delayIdle) +{ + return ThreadStackMgrImpl().RequestSEDActiveMode(onOff, delayIdle); +} +#endif + #if CHIP_CONFIG_ENABLE_ICD_SERVER template inline CHIP_ERROR diff --git a/src/messaging/ExchangeContext.cpp b/src/messaging/ExchangeContext.cpp index 8c085025456ba8..2b794e4f3465c6 100644 --- a/src/messaging/ExchangeContext.cpp +++ b/src/messaging/ExchangeContext.cpp @@ -91,6 +91,45 @@ void ExchangeContext::SetResponseTimeout(Timeout timeout) mResponseTimeout = timeout; } +#if CONFIG_DEVICE_LAYER && CHIP_DEVICE_CONFIG_ENABLE_SED +void ExchangeContext::UpdateSEDIntervalMode() +{ + if (!HasSessionHandle()) + { + // After the session has been deleted, no further communication can occur on the exchange, + // so withdraw a SED active mode request. + UpdateSEDIntervalMode(false); + return; + } + + Transport::PeerAddress address; + + switch (GetSessionHandle()->GetSessionType()) + { + case Transport::Session::SessionType::kSecure: + address = GetSessionHandle()->AsSecureSession()->GetPeerAddress(); + break; + case Transport::Session::SessionType::kUnauthenticated: + address = GetSessionHandle()->AsUnauthenticatedSession()->GetPeerAddress(); + break; + default: + return; + } + + VerifyOrReturn(address.GetTransportType() != Transport::Type::kBle); + UpdateSEDIntervalMode(IsResponseExpected() || IsSendExpected() || IsMessageNotAcked()); +} + +void ExchangeContext::UpdateSEDIntervalMode(bool activeMode) +{ + if (activeMode != IsRequestingActiveMode()) + { + SetRequestingActiveMode(activeMode); + DeviceLayer::ConnectivityMgr().RequestSEDActiveMode(activeMode, true); + } +} +#endif + CHIP_ERROR ExchangeContext::SendMessage(Protocols::Id protocolId, uint8_t msgType, PacketBufferHandle && msgBuf, const SendFlags & sendFlags) { @@ -361,6 +400,11 @@ ExchangeContext::~ExchangeContext() // VerifyOrDie(mFlags.Has(Flags::kFlagClosed)); +#if CONFIG_DEVICE_LAYER && CHIP_DEVICE_CONFIG_ENABLE_SED + // Make sure that the exchange withdraws the request for Sleepy End Device active mode. + UpdateSEDIntervalMode(false); +#endif + // Ideally, in this scenario, the retransmit table should // be clear of any outstanding messages for this context and // the boolean parameter passed to DoClose() should not matter. @@ -644,6 +688,10 @@ CHIP_ERROR ExchangeContext::HandleMessage(uint32_t messageCounter, const Payload void ExchangeContext::MessageHandled() { +#if CONFIG_DEVICE_LAYER && CHIP_DEVICE_CONFIG_ENABLE_SED + UpdateSEDIntervalMode(); +#endif + if (mFlags.Has(Flags::kFlagClosed) || IsResponseExpected() || IsSendExpected()) { return; diff --git a/src/messaging/ReliableMessageMgr.cpp b/src/messaging/ReliableMessageMgr.cpp index 68818585df3075..ca3687a09432d5 100644 --- a/src/messaging/ReliableMessageMgr.cpp +++ b/src/messaging/ReliableMessageMgr.cpp @@ -268,6 +268,13 @@ System::Clock::Timestamp ReliableMessageMgr::GetBackoff(System::Clock::Timestamp // "An ICD sender SHOULD increase t to also account for its own sleepy interval // required to receive the acknowledgment" mrpBackoffTime += app::ICDManager::GetFastPollingInterval(); +#elif CHIP_DEVICE_CONFIG_ENABLE_SED + DeviceLayer::ConnectivityManager::SEDIntervalsConfig sedIntervals; + + if (DeviceLayer::ConnectivityMgr().GetSEDIntervalsConfig(sedIntervals) == CHIP_NO_ERROR) + { + mrpBackoffTime += System::Clock::Timestamp(sedIntervals.ActiveIntervalMS); + } #endif mrpBackoffTime += CHIP_CONFIG_MRP_RETRY_INTERVAL_SENDER_BOOST; diff --git a/src/messaging/ReliableMessageProtocolConfig.cpp b/src/messaging/ReliableMessageProtocolConfig.cpp index 9dfd0719293774..795e02c3ce3679 100644 --- a/src/messaging/ReliableMessageProtocolConfig.cpp +++ b/src/messaging/ReliableMessageProtocolConfig.cpp @@ -76,6 +76,16 @@ Optional GetLocalMRPConfig() config.mIdleRetransTimeout += app::ICDManager::GetSlowPollingInterval(); config.mActiveRetransTimeout += app::ICDManager::GetFastPollingInterval(); config.mActiveThresholdTime = System::Clock::Milliseconds16(IcdManagementServer::GetInstance().GetActiveModeThreshold()); +#elif CHIP_DEVICE_CONFIG_ENABLE_SED + DeviceLayer::ConnectivityManager::SEDIntervalsConfig sedIntervalsConfig; + + if (DeviceLayer::ConnectivityMgr().GetSEDIntervalsConfig(sedIntervalsConfig) == CHIP_NO_ERROR) + { + // Increase local MRP retry intervals by SED intervals. That is, intervals for + // which the device can be at sleep and not be able to receive any messages). + config.mIdleRetransTimeout += sedIntervalsConfig.IdleIntervalMS; + config.mActiveRetransTimeout += sedIntervalsConfig.ActiveIntervalMS; + } #endif #if CONFIG_BUILD_FOR_HOST_UNIT_TEST diff --git a/src/platform/Linux/ThreadStackManagerImpl.cpp b/src/platform/Linux/ThreadStackManagerImpl.cpp index a880490d85fb00..f8cdcb2f453e44 100644 --- a/src/platform/Linux/ThreadStackManagerImpl.cpp +++ b/src/platform/Linux/ThreadStackManagerImpl.cpp @@ -518,6 +518,32 @@ CHIP_ERROR ThreadStackManagerImpl::_SetThreadDeviceType(ConnectivityManager::Thr return CHIP_NO_ERROR; } +#if CHIP_DEVICE_CONFIG_ENABLE_SED +CHIP_ERROR ThreadStackManagerImpl::_GetSEDIntervalsConfig(ConnectivityManager::SEDIntervalsConfig & intervalsConfig) +{ + (void) intervalsConfig; + + ChipLogError(DeviceLayer, "SED intervals config is not supported on linux"); + return CHIP_ERROR_NOT_IMPLEMENTED; +} + +CHIP_ERROR ThreadStackManagerImpl::_SetSEDIntervalsConfig(const ConnectivityManager::SEDIntervalsConfig & intervalsConfig) +{ + (void) intervalsConfig; + + ChipLogError(DeviceLayer, "SED intervals config is not supported on linux"); + return CHIP_ERROR_NOT_IMPLEMENTED; +} + +CHIP_ERROR ThreadStackManagerImpl::_RequestSEDActiveMode(bool onOff, bool delayIdle) +{ + (void) onOff; + (void) delayIdle; + + ChipLogError(DeviceLayer, "SED intervals config is not supported on linux"); + return CHIP_ERROR_NOT_IMPLEMENTED; +} +#endif #if CHIP_CONFIG_ENABLE_ICD_SERVER CHIP_ERROR ThreadStackManagerImpl::_SetPollingInterval(System::Clock::Milliseconds32 pollingInterval) { diff --git a/src/platform/Linux/ThreadStackManagerImpl.h b/src/platform/Linux/ThreadStackManagerImpl.h index 5e077cba3bd1fe..b91d210f7c5028 100755 --- a/src/platform/Linux/ThreadStackManagerImpl.h +++ b/src/platform/Linux/ThreadStackManagerImpl.h @@ -93,6 +93,11 @@ class ThreadStackManagerImpl : public ThreadStackManager CHIP_ERROR _SetThreadDeviceType(ConnectivityManager::ThreadDeviceType deviceType); +#if CHIP_DEVICE_CONFIG_ENABLE_SED + CHIP_ERROR _GetSEDIntervalsConfig(ConnectivityManager::SEDIntervalsConfig & intervalsConfig); + CHIP_ERROR _SetSEDIntervalsConfig(const ConnectivityManager::SEDIntervalsConfig & intervalsConfig); + CHIP_ERROR _RequestSEDActiveMode(bool onOff, bool delayIdle = false); +#endif #if CHIP_CONFIG_ENABLE_ICD_SERVER CHIP_ERROR _SetPollingInterval(System::Clock::Milliseconds32 pollingInterval); #endif /* CHIP_CONFIG_ENABLE_ICD_SERVER */ diff --git a/src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.h b/src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.h index d8bf1b2b76a4a0..b28058b5946d72 100755 --- a/src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.h +++ b/src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.h @@ -100,6 +100,13 @@ class GenericThreadStackManagerImpl_OpenThread void _OnNetworkScanFinished(otActiveScanResult * aResult); void _UpdateNetworkStatus(); +#if CHIP_DEVICE_CONFIG_ENABLE_SED + CHIP_ERROR _GetSEDIntervalsConfig(ConnectivityManager::SEDIntervalsConfig & intervalsConfig); + CHIP_ERROR _SetSEDIntervalsConfig(const ConnectivityManager::SEDIntervalsConfig & intervalsConfig); + CHIP_ERROR _RequestSEDActiveMode(bool onOff, bool delayIdle); + CHIP_ERROR SEDUpdateMode(); + static void RequestSEDModeUpdate(chip::System::Layer * apSystemLayer, void * apAppState); +#endif #if CHIP_CONFIG_ENABLE_ICD_SERVER CHIP_ERROR _SetPollingInterval(System::Clock::Milliseconds32 pollingInterval); #endif // CHIP_CONFIG_ENABLE_ICD_SERVER @@ -159,6 +166,13 @@ class GenericThreadStackManagerImpl_OpenThread NetworkCommissioning::Internal::WirelessDriver::ConnectCallback * mpConnectCallback; NetworkCommissioning::Internal::BaseDriver::NetworkStatusChangeCallback * mpStatusChangeCallback = nullptr; +#if CHIP_DEVICE_CONFIG_ENABLE_SED + ConnectivityManager::SEDIntervalsConfig mIntervalsConfig; + ConnectivityManager::SEDIntervalMode mIntervalsMode = ConnectivityManager::SEDIntervalMode::Idle; + uint32_t mActiveModeConsumers = 0; + bool mDelayIdleTimerRunning = false; +#endif + #if CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT struct SrpClient @@ -265,6 +279,10 @@ class GenericThreadStackManagerImpl_OpenThread static void OnJoinerComplete(otError aError, void * aContext); void OnJoinerComplete(otError aError); +#if CHIP_DEVICE_CONFIG_ENABLE_SED + CHIP_ERROR SetSEDIntervalMode(ConnectivityManager::SEDIntervalMode intervalType); +#endif + inline ImplClass * Impl() { return static_cast(this); } }; diff --git a/src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.hpp b/src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.hpp index 4e89e6938520b4..4d2f461e61dd7f 100644 --- a/src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.hpp +++ b/src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.hpp @@ -376,7 +376,7 @@ CHIP_ERROR GenericThreadStackManagerImpl_OpenThread::_StartThreadScan(NetworkCommissioning::ThreadDriver::ScanCallback * callback) { CHIP_ERROR error = CHIP_NO_ERROR; -#if CHIP_CONFIG_ENABLE_ICD_SERVER +#if CHIP_DEVICE_CONFIG_ENABLE_SED || CHIP_CONFIG_ENABLE_ICD_SERVER otLinkModeConfig linkMode; #endif // If there is another ongoing scan request, reject the new one. @@ -392,7 +392,7 @@ GenericThreadStackManagerImpl_OpenThread::_StartThreadScan(NetworkCom SuccessOrExit(error = MapOpenThreadError(otIp6SetEnabled(mOTInst, true))); } -#if CHIP_CONFIG_ENABLE_ICD_SERVER +#if CHIP_DEVICE_CONFIG_ENABLE_SED || CHIP_CONFIG_ENABLE_ICD_SERVER // Thread network discovery makes Sleepy End Devices detach from a network, so temporarily disable the SED mode. linkMode = otThreadGetLinkMode(mOTInst); @@ -430,7 +430,7 @@ void GenericThreadStackManagerImpl_OpenThread::_OnNetworkScanFinished { if (aResult == nullptr) // scan completed { -#if CHIP_CONFIG_ENABLE_ICD_SERVER +#if CHIP_DEVICE_CONFIG_ENABLE_SED || CHIP_CONFIG_ENABLE_ICD_SERVER if (mTemporaryRxOnWhenIdle) { otLinkModeConfig linkMode = otThreadGetLinkMode(mOTInst); @@ -1702,6 +1702,19 @@ CHIP_ERROR GenericThreadStackManagerImpl_OpenThread::DoInit(otInstanc mOTInst = otInst; +#if CHIP_DEVICE_CONFIG_ENABLE_SED + ConnectivityManager::SEDIntervalsConfig sedIntervalsConfig; + using namespace System::Clock::Literals; + sedIntervalsConfig.ActiveIntervalMS = CHIP_DEVICE_CONFIG_ICD_FAST_POLL_INTERVAL; + sedIntervalsConfig.IdleIntervalMS = CHIP_DEVICE_CONFIG_ICD_SLOW_POLL_INTERVAL; + err = _SetSEDIntervalsConfig(sedIntervalsConfig); + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "Failed to set sleepy end device intervals: %s", ErrorStr(err)); + } + SuccessOrExit(err); +#endif + // Arrange for OpenThread to call the OnOpenThreadStateChange method whenever a // state change occurs. Note that we reference the OnOpenThreadStateChange method // on the concrete implementation class so that that class can override the default @@ -1754,6 +1767,172 @@ bool GenericThreadStackManagerImpl_OpenThread::IsThreadInterfaceUpNoL return otIp6IsEnabled(mOTInst); } +#if CHIP_DEVICE_CONFIG_ENABLE_SED +template +CHIP_ERROR GenericThreadStackManagerImpl_OpenThread::_GetSEDIntervalsConfig( + ConnectivityManager::SEDIntervalsConfig & intervalsConfig) +{ + intervalsConfig = mIntervalsConfig; + return CHIP_NO_ERROR; +} + +template +CHIP_ERROR GenericThreadStackManagerImpl_OpenThread::_SetSEDIntervalsConfig( + const ConnectivityManager::SEDIntervalsConfig & intervalsConfig) +{ + using namespace System::Clock::Literals; + if ((intervalsConfig.IdleIntervalMS < intervalsConfig.ActiveIntervalMS) || (intervalsConfig.IdleIntervalMS == 0_ms32) || + (intervalsConfig.ActiveIntervalMS == 0_ms32)) + { + return CHIP_ERROR_INVALID_ARGUMENT; + } + mIntervalsConfig = intervalsConfig; + + CHIP_ERROR err = SetSEDIntervalMode(mIntervalsMode); + + if (err == CHIP_NO_ERROR) + { + ChipDeviceEvent event; + event.Type = DeviceEventType::kICDPollingIntervalChange; + err = chip::DeviceLayer::PlatformMgr().PostEvent(&event); + } + + return err; +} + +template +CHIP_ERROR +GenericThreadStackManagerImpl_OpenThread::SetSEDIntervalMode(ConnectivityManager::SEDIntervalMode intervalType) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + System::Clock::Milliseconds32 interval; + + if (intervalType == ConnectivityManager::SEDIntervalMode::Idle) + { + interval = mIntervalsConfig.IdleIntervalMS; + } + else if (intervalType == ConnectivityManager::SEDIntervalMode::Active) + { + interval = mIntervalsConfig.ActiveIntervalMS; + } + else + { + return CHIP_ERROR_INVALID_ARGUMENT; + } + + Impl()->LockThreadStack(); + + mIntervalsMode = intervalType; + +// For Thread devices, the intervals are defined as: +// * poll period for SED devices that poll the parent for data +// * CSL period for SSED devices that listen for messages in scheduled time slots. +#if CHIP_DEVICE_CONFIG_THREAD_SSED + // Get CSL period in units of 10 symbols, convert it to microseconds and divide by 1000 to get milliseconds. + uint32_t curIntervalMS = otLinkCslGetPeriod(mOTInst) * OT_US_PER_TEN_SYMBOLS / 1000; +#else + uint32_t curIntervalMS = otLinkGetPollPeriod(mOTInst); +#endif + otError otErr = OT_ERROR_NONE; + if (interval.count() != curIntervalMS) + { +#if CHIP_DEVICE_CONFIG_THREAD_SSED + // Set CSL period in units of 10 symbols, convert it to microseconds and divide by 1000 to get milliseconds. + otErr = otLinkCslSetPeriod(mOTInst, interval.count() * 1000 / OT_US_PER_TEN_SYMBOLS); + curIntervalMS = otLinkCslGetPeriod(mOTInst) * OT_US_PER_TEN_SYMBOLS / 1000; +#else + otErr = otLinkSetPollPeriod(mOTInst, interval.count()); + curIntervalMS = otLinkGetPollPeriod(mOTInst); +#endif + err = MapOpenThreadError(otErr); + } + + Impl()->UnlockThreadStack(); + + if (otErr != OT_ERROR_NONE) + { + ChipLogError(DeviceLayer, "Failed to set SED interval to %" PRId32 "ms. Defaulting to %" PRId32 "ms", interval.count(), + curIntervalMS); + } + else + { + ChipLogProgress(DeviceLayer, "OpenThread SED interval is %" PRId32 "ms", curIntervalMS); + } + + return err; +} + +template +CHIP_ERROR GenericThreadStackManagerImpl_OpenThread::_RequestSEDActiveMode(bool onOff, bool delayIdle) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + + if (onOff) + { + mActiveModeConsumers++; + } + else + { + if (mActiveModeConsumers > 0) + mActiveModeConsumers--; + } + + if (!onOff && delayIdle && CHIP_DEVICE_CONFIG_SED_ACTIVE_THRESHOLD.count() != 0) + { + // StartTimer will cancel a timer if the same callback & context is used. + // This will have the effect of canceling the previous one (if any) and starting + // a new timer of the same duration. This effectively prolongs the active threshold + // without consuming additional resources. + err = DeviceLayer::SystemLayer().StartTimer(CHIP_DEVICE_CONFIG_SED_ACTIVE_THRESHOLD, RequestSEDModeUpdate, this); + if (CHIP_NO_ERROR == err) + { + if (!mDelayIdleTimerRunning) + { + mDelayIdleTimerRunning = true; + mActiveModeConsumers++; + } + return err; + } + + ChipLogError(DeviceLayer, "Failed to postpone Idle Mode with error %" CHIP_ERROR_FORMAT, err.Format()); + } + + return SEDUpdateMode(); +} + +template +CHIP_ERROR GenericThreadStackManagerImpl_OpenThread::SEDUpdateMode() +{ + CHIP_ERROR err = CHIP_NO_ERROR; + ConnectivityManager::SEDIntervalMode mode; + + mode = mActiveModeConsumers > 0 ? ConnectivityManager::SEDIntervalMode::Active : ConnectivityManager::SEDIntervalMode::Idle; + + if (mIntervalsMode != mode) + err = SetSEDIntervalMode(mode); + + return err; +} + +template +void GenericThreadStackManagerImpl_OpenThread::RequestSEDModeUpdate(chip::System::Layer * apSystemLayer, + void * apAppState) +{ + if (apAppState != nullptr) + { + GenericThreadStackManagerImpl_OpenThread * obj = static_cast(apAppState); + if (obj->mActiveModeConsumers > 0) + { + obj->mActiveModeConsumers--; + } + + obj->mDelayIdleTimerRunning = false; + + obj->SEDUpdateMode(); + } +} +#endif + #if CHIP_CONFIG_ENABLE_ICD_SERVER template CHIP_ERROR GenericThreadStackManagerImpl_OpenThread::_SetPollingInterval(System::Clock::Milliseconds32 pollingInterval) diff --git a/src/platform/nrfconnect/wifi/ConnectivityManagerImplWiFi.cpp b/src/platform/nrfconnect/wifi/ConnectivityManagerImplWiFi.cpp index b3bdede0f2f852..93559822ef6d82 100644 --- a/src/platform/nrfconnect/wifi/ConnectivityManagerImplWiFi.cpp +++ b/src/platform/nrfconnect/wifi/ConnectivityManagerImplWiFi.cpp @@ -123,6 +123,26 @@ CHIP_ERROR ConnectivityManagerImplWiFi::_GetAndLogWiFiStatsCounters(void) return CHIP_NO_ERROR; } +#if CHIP_DEVICE_CONFIG_ENABLE_SED +CHIP_ERROR ConnectivityManagerImplWiFi::_GetSEDIntervalsConfig(ConnectivityManager::SEDIntervalsConfig & SEDIntervalsConfig) +{ + // For now Wi-Fi uses legacy power save mode that has fixed inactivity interval + SEDIntervalsConfig.ActiveIntervalMS = + chip::System::Clock::Milliseconds32(WiFiManager::kDefaultDTIMInterval * WiFiManager::kBeaconIntervalMs); + SEDIntervalsConfig.IdleIntervalMS = + chip::System::Clock::Milliseconds32(WiFiManager::kDefaultDTIMInterval * WiFiManager::kBeaconIntervalMs); + return CHIP_NO_ERROR; +} +CHIP_ERROR ConnectivityManagerImplWiFi::_SetSEDIntervalsConfig(const ConnectivityManager::SEDIntervalsConfig & intervalsConfig) +{ + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +} +CHIP_ERROR ConnectivityManagerImplWiFi::_RequestSEDActiveMode(bool onOff, bool delayIdle) +{ + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +} +#endif + ConnectivityManager::WiFiAPMode ConnectivityManagerImplWiFi::_GetWiFiAPMode(void) { /* AP mode is unsupported */ diff --git a/src/platform/nrfconnect/wifi/ConnectivityManagerImplWiFi.h b/src/platform/nrfconnect/wifi/ConnectivityManagerImplWiFi.h index dfa6a05f0b7ae4..407bb2044ed77c 100644 --- a/src/platform/nrfconnect/wifi/ConnectivityManagerImplWiFi.h +++ b/src/platform/nrfconnect/wifi/ConnectivityManagerImplWiFi.h @@ -55,6 +55,12 @@ class ConnectivityManagerImplWiFi void _OnWiFiScanDone(); void _OnWiFiStationProvisionChange(); +#if CHIP_DEVICE_CONFIG_ENABLE_SED + CHIP_ERROR _GetSEDIntervalsConfig(ConnectivityManager::SEDIntervalsConfig & intervalsConfig); + CHIP_ERROR _SetSEDIntervalsConfig(const ConnectivityManager::SEDIntervalsConfig & intervalsConfig); + CHIP_ERROR _RequestSEDActiveMode(bool onOff, bool delayIdle = false); +#endif + // Wi-Fi access point - not supported ConnectivityManager::WiFiAPMode _GetWiFiAPMode(void); CHIP_ERROR _SetWiFiAPMode(ConnectivityManager::WiFiAPMode val); diff --git a/src/platform/qpg/ThreadStackManagerImpl.cpp b/src/platform/qpg/ThreadStackManagerImpl.cpp index 01abdc679f970c..cb6fd0e2ec1289 100644 --- a/src/platform/qpg/ThreadStackManagerImpl.cpp +++ b/src/platform/qpg/ThreadStackManagerImpl.cpp @@ -113,3 +113,13 @@ extern "C" void otPlatFree(void * aPtr) { CHIPPlatformMemoryFree(aPtr); } + +#if CHIP_DEVICE_CONFIG_ENABLE_SED +CHIP_ERROR ThreadStackManagerImpl::_RequestSEDFastPollingMode(bool onOff) +{ + (void) onOff; + + ChipLogError(DeviceLayer, "Polling config is not supported on this platform"); + return CHIP_ERROR_NOT_IMPLEMENTED; +} +#endif diff --git a/src/platform/qpg/ThreadStackManagerImpl.h b/src/platform/qpg/ThreadStackManagerImpl.h index 9896ea6e57128e..fe39291e77edb3 100644 --- a/src/platform/qpg/ThreadStackManagerImpl.h +++ b/src/platform/qpg/ThreadStackManagerImpl.h @@ -74,6 +74,10 @@ class ThreadStackManagerImpl final : public ThreadStackManager, using ThreadStackManager::InitThreadStack; CHIP_ERROR InitThreadStack(otInstance * otInst); +#if CHIP_DEVICE_CONFIG_ENABLE_SED + CHIP_ERROR _RequestSEDFastPollingMode(bool onOff); +#endif + private: // ===== Methods that implement the ThreadStackManager abstract interface. diff --git a/src/platform/webos/ThreadStackManagerImpl.cpp b/src/platform/webos/ThreadStackManagerImpl.cpp index 6acb542d78a3c1..b6e4bd9e9a853e 100644 --- a/src/platform/webos/ThreadStackManagerImpl.cpp +++ b/src/platform/webos/ThreadStackManagerImpl.cpp @@ -481,6 +481,32 @@ CHIP_ERROR ThreadStackManagerImpl::_SetThreadDeviceType(ConnectivityManager::Thr return CHIP_NO_ERROR; } +#if CHIP_DEVICE_CONFIG_ENABLE_SED +CHIP_ERROR ThreadStackManagerImpl::_GetSEDPollingConfig(ConnectivityManager::SEDPollingConfig & pollingConfig) +{ + (void) pollingConfig; + + ChipLogError(DeviceLayer, "Polling config is not supported on linux"); + return CHIP_ERROR_NOT_IMPLEMENTED; +} + +CHIP_ERROR ThreadStackManagerImpl::_SetSEDPollingConfig(const ConnectivityManager::SEDPollingConfig & pollingConfig) +{ + (void) pollingConfig; + + ChipLogError(DeviceLayer, "Polling config is not supported on linux"); + return CHIP_ERROR_NOT_IMPLEMENTED; +} + +CHIP_ERROR ThreadStackManagerImpl::_RequestSEDFastPollingMode(bool onOff) +{ + (void) onOff; + + ChipLogError(DeviceLayer, "Polling config is not supported on linux"); + return CHIP_ERROR_NOT_IMPLEMENTED; +} +#endif + bool ThreadStackManagerImpl::_HaveMeshConnectivity() { // TODO: Remove Weave legacy APIs diff --git a/src/platform/webos/ThreadStackManagerImpl.h b/src/platform/webos/ThreadStackManagerImpl.h index 330e601f75a7fd..b70910878c08d0 100644 --- a/src/platform/webos/ThreadStackManagerImpl.h +++ b/src/platform/webos/ThreadStackManagerImpl.h @@ -86,6 +86,12 @@ class ThreadStackManagerImpl : public ThreadStackManager CHIP_ERROR _SetThreadDeviceType(ConnectivityManager::ThreadDeviceType deviceType); +#if CHIP_DEVICE_CONFIG_ENABLE_SED + CHIP_ERROR _GetSEDPollingConfig(ConnectivityManager::SEDPollingConfig & pollingConfig); + CHIP_ERROR _SetSEDPollingConfig(const ConnectivityManager::SEDPollingConfig & pollingConfig); + CHIP_ERROR _RequestSEDFastPollingMode(bool onOff); +#endif + bool _HaveMeshConnectivity(); CHIP_ERROR _GetAndLogThreadStatsCounters();