From 7f54fb60da3eaa4146ba5c35eff82906c940bf2f Mon Sep 17 00:00:00 2001 From: mkardous-silabs <84793247+mkardous-silabs@users.noreply.github.com> Date: Fri, 20 Jan 2023 19:11:25 -0500 Subject: [PATCH] [ICD] Add read handler callback to negociate max sub interval (#24414) * add max interval negociation * generic read handler * restyle * Address PR comments * Update naming used * Update gn argument name * Add class / function comments * Add an ICD build to efr32 workflow * Apply suggestions from code review Co-authored-by: Boris Zbarsky * Address PR comments * restyle * Add fail safe checks to always have a valid maxInterval * PR comments Co-authored-by: Boris Zbarsky --- .github/workflows/examples-efr32.yaml | 1 + .../light-switch-app/silabs/efr32/BUILD.gn | 11 ++++ .../silabs/ICDSubscriptionCallback.cpp | 65 +++++++++++++++++++ .../platform/silabs/ICDSubscriptionCallback.h | 35 ++++++++++ examples/platform/silabs/efr32/BUILD.gn | 15 ++++- .../platform/silabs/efr32/matter_config.cpp | 11 ++++ .../platform/silabs/efr32/matter_config.h | 8 +++ 7 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 examples/platform/silabs/ICDSubscriptionCallback.cpp create mode 100644 examples/platform/silabs/ICDSubscriptionCallback.h diff --git a/.github/workflows/examples-efr32.yaml b/.github/workflows/examples-efr32.yaml index 1db615947c3b72..57d20aa35ed79f 100644 --- a/.github/workflows/examples-efr32.yaml +++ b/.github/workflows/examples-efr32.yaml @@ -82,6 +82,7 @@ jobs: --enable-flashbundle \ --target efr32-brd4187c-window-covering \ --target efr32-brd4187c-switch \ + --target efr32-brd4187c-switch-sed \ --target efr32-brd4187c-unit-test \ --target efr32-brd4187c-light \ --target efr32-brd4187c-light-rpc \ diff --git a/examples/light-switch-app/silabs/efr32/BUILD.gn b/examples/light-switch-app/silabs/efr32/BUILD.gn index 823f733273b9eb..85ccf1ac6f833f 100644 --- a/examples/light-switch-app/silabs/efr32/BUILD.gn +++ b/examples/light-switch-app/silabs/efr32/BUILD.gn @@ -74,11 +74,17 @@ declare_args() { declare_args() { # Enables LCD Qr Code on supported devices show_qr_code = !disable_lcd + + # Use default handler to negotiate subscription max interval + chip_config_use_icd_subscription_callbacks = enable_sleepy_device } # qr code cannot be true if lcd is disabled assert(!(disable_lcd && show_qr_code)) +# default read handler cannot be used without being an IC device (SED) +assert(!chip_config_use_icd_subscription_callbacks || enable_sleepy_device) + # Sanity check assert(!(chip_enable_wifi && chip_enable_openthread)) assert(!(use_rs911x && chip_enable_openthread)) @@ -252,6 +258,11 @@ efr32_executable("light_switch_app") { deps += [ "${examples_plat_dir}:efr32-factory-data-provider" ] } + # Default Read handler for SED + if (chip_config_use_icd_subscription_callbacks) { + deps += [ "${examples_plat_dir}:efr32-ICD-subscription-callback" ] + } + if (chip_enable_ota_requestor) { defines += [ "EFR32_OTA_ENABLED" ] sources += [ "${examples_plat_dir}/OTAConfig.cpp" ] diff --git a/examples/platform/silabs/ICDSubscriptionCallback.cpp b/examples/platform/silabs/ICDSubscriptionCallback.cpp new file mode 100644 index 00000000000000..30fbf683e6e8dc --- /dev/null +++ b/examples/platform/silabs/ICDSubscriptionCallback.cpp @@ -0,0 +1,65 @@ +/* + * + * Copyright (c) 2023 Project CHIP Authors + * All rights reserved. + * + * 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 "ICDSubscriptionCallback.h" +#include + +CHIP_ERROR ICDSubscriptionCallback::OnSubscriptionRequested(chip::app::ReadHandler & aReadHandler, + chip::Transport::SecureSession & aSecureSession) +{ + using namespace chip::System::Clock; + + Seconds32 interval_s32 = std::chrono::duration_cast(CHIP_DEVICE_CONFIG_SED_IDLE_INTERVAL); + + if (interval_s32 > Seconds16::max()) + { + interval_s32 = Seconds16::max(); + } + uint32_t decidedMaxInterval = interval_s32.count(); + + uint16_t requestedMinInterval = 0; + uint16_t requestedMaxInterval = 0; + aReadHandler.GetReportingIntervals(requestedMinInterval, requestedMaxInterval); + + // If requestedMinInterval is greater than IdleTimeInterval, select next wake up time as max interval + if (requestedMinInterval > decidedMaxInterval) + { + uint16_t ratio = requestedMinInterval / decidedMaxInterval; + if (requestedMinInterval % decidedMaxInterval) + { + ratio++; + } + + decidedMaxInterval *= ratio; + } + + // Verify that decidedMaxInterval is an acceptable value + if (decidedMaxInterval > Seconds16::max().count()) + { + decidedMaxInterval = Seconds16::max().count(); + } + + // Verify that the decidedMaxInterval respects MAX(SUBSCRIPTION_MAX_INTERVAL_PUBLISHER_LIMIT, MaxIntervalCeiling) + uint16_t maximumMaxInterval = std::max(kSubscriptionMaxIntervalPublisherLimit, requestedMaxInterval); + if (decidedMaxInterval > maximumMaxInterval) + { + decidedMaxInterval = maximumMaxInterval; + } + + return aReadHandler.SetReportingIntervals(decidedMaxInterval); +} diff --git a/examples/platform/silabs/ICDSubscriptionCallback.h b/examples/platform/silabs/ICDSubscriptionCallback.h new file mode 100644 index 00000000000000..c9f77e6df2a3c6 --- /dev/null +++ b/examples/platform/silabs/ICDSubscriptionCallback.h @@ -0,0 +1,35 @@ +/* + * + * Copyright (c) 2023 Project CHIP Authors + * All rights reserved. + * + * 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 + +/** + * @brief The goal of the ICDSubscriptionCallback class is to negotiate the max interval subscription to match the idle interval of + * the IC device. When a subscription is requested, the device will change the requested max interval to match its idle time + * interval through the OnSubscriptionRequested function. + */ +class ICDSubscriptionCallback : public chip::app::ReadHandler::ApplicationCallback +{ + /** + * @brief Function called when a subscription is requested. + * An ICD will use this function to negotiate the subscription max interval to match its idle time interval + */ + CHIP_ERROR OnSubscriptionRequested(chip::app::ReadHandler & aReadHandler, + chip::Transport::SecureSession & aSecureSession) override; +}; diff --git a/examples/platform/silabs/efr32/BUILD.gn b/examples/platform/silabs/efr32/BUILD.gn index f2ffefb77eed62..4c62826c7c4a8a 100644 --- a/examples/platform/silabs/efr32/BUILD.gn +++ b/examples/platform/silabs/efr32/BUILD.gn @@ -110,6 +110,19 @@ source_set("efr32-factory-data-provider") { "${chip_root}/src/platform:platform_base", "${chip_root}/src/setup_payload", ] +} + +config("ICD-subscription-callback-config") { + defines = [ "CHIP_CONFIG_USE_ICD_SUBSCRIPTION_CALLBACKS=1" ] +} + +source_set("efr32-ICD-subscription-callback") { + sources = [ + "../ICDSubscriptionCallback.cpp", + "../ICDSubscriptionCallback.h", + ] + + public_deps = [ "${chip_root}/src/app:app" ] - #public_configs = [ "" ] + public_configs = [ ":ICD-subscription-callback-config" ] } diff --git a/examples/platform/silabs/efr32/matter_config.cpp b/examples/platform/silabs/efr32/matter_config.cpp index 83e909588d9811..942f19c57ad91e 100644 --- a/examples/platform/silabs/efr32/matter_config.cpp +++ b/examples/platform/silabs/efr32/matter_config.cpp @@ -54,6 +54,11 @@ static chip::DeviceLayer::Internal::Efr32PsaOperationalKeystore gOperationalKeys #endif #include "EFR32DeviceDataProvider.h" +#include + +#ifdef CHIP_CONFIG_USE_ICD_SUBSCRIPTION_CALLBACKS +ICDSubscriptionCallback EFR32MatterConfig::mICDSubscriptionHandler; +#endif // CHIP_CONFIG_USE_ICD_SUBSCRIPTION_CALLBACKS #if CHIP_ENABLE_OPENTHREAD #include @@ -189,6 +194,12 @@ CHIP_ERROR EFR32MatterConfig::InitMatter(const char * appName) // Init Matter Server and Start Event Loop err = chip::Server::GetInstance().Init(initParams); + +#ifdef CHIP_CONFIG_USE_ICD_SUBSCRIPTION_CALLBACKS + // Register ICD subscription callback to match subscription max intervals to its idle time interval + chip::app::InteractionModelEngine::GetInstance()->RegisterReadHandlerAppCallback(&mICDSubscriptionHandler); +#endif // CHIP_CONFIG_USE_ICD_SUBSCRIPTION_CALLBACKS + chip::DeviceLayer::PlatformMgr().UnlockChipStack(); ReturnErrorOnFailure(err); diff --git a/examples/platform/silabs/efr32/matter_config.h b/examples/platform/silabs/efr32/matter_config.h index e0af60356becf9..e4acdb107bad1f 100644 --- a/examples/platform/silabs/efr32/matter_config.h +++ b/examples/platform/silabs/efr32/matter_config.h @@ -22,6 +22,10 @@ #include #include +#ifdef CHIP_CONFIG_USE_ICD_SUBSCRIPTION_CALLBACKS +#include "ICDSubscriptionCallback.h" +#endif // CHIP_CONFIG_USE_ICD_SUBSCRIPTION_CALLBACKS + class EFR32MatterConfig { public: @@ -32,4 +36,8 @@ class EFR32MatterConfig static void InitWiFi(void); static void ConnectivityEventCallback(const chip::DeviceLayer::ChipDeviceEvent * event, intptr_t arg); static void InitOTARequestorHandler(chip::System::Layer * systemLayer, void * appState); + +#ifdef CHIP_CONFIG_USE_ICD_SUBSCRIPTION_CALLBACKS + static ICDSubscriptionCallback mICDSubscriptionHandler; +#endif // CHIP_CONFIG_USE_ICD_SUBSCRIPTION_CALLBACKS };