diff --git a/examples/light-switch-app/nrfconnect/main/AppTask.cpp b/examples/light-switch-app/nrfconnect/main/AppTask.cpp index 9643dce1a8ef4b..f1d7d8b0064f38 100644 --- a/examples/light-switch-app/nrfconnect/main/AppTask.cpp +++ b/examples/light-switch-app/nrfconnect/main/AppTask.cpp @@ -18,7 +18,6 @@ #include "AppTask.h" #include "AppConfig.h" -#include "BindingHandler.h" #include "LEDWidget.h" #include "LightSwitch.h" #include "ThreadUtil.h" diff --git a/examples/light-switch-app/nrfconnect/main/BindingHandler.cpp b/examples/light-switch-app/nrfconnect/main/BindingHandler.cpp index c94801ed1730f7..54cce9924887fd 100644 --- a/examples/light-switch-app/nrfconnect/main/BindingHandler.cpp +++ b/examples/light-switch-app/nrfconnect/main/BindingHandler.cpp @@ -35,17 +35,54 @@ void BindingHandler::Init() DeviceLayer::PlatformMgr().ScheduleWork(InitInternal); } +void BindingHandler::OnInvokeCommandFailure(DeviceProxy * aDevice, BindingData & aBindingData, CHIP_ERROR aError) +{ + CHIP_ERROR error; + + if (aError == CHIP_ERROR_TIMEOUT && !BindingHandler::GetInstance().mCaseSessionRecovered) + { + LOG_INF("Response timeout for invoked command, trying to recover CASE session."); + if (!aDevice) + return; + + // Release current CASE session. + error = aDevice->Disconnect(); + + if (CHIP_NO_ERROR != error) + { + LOG_ERR("Disconnecting from CASE session failed due to: %" CHIP_ERROR_FORMAT, error.Format()); + return; + } + + // Set flag to not try recover session multiple times. + BindingHandler::GetInstance().mCaseSessionRecovered = true; + + // Establish new CASE session and retrasmit command that was not applied. + error = BindingManager::GetInstance().NotifyBoundClusterChanged(aBindingData.EndpointId, aBindingData.ClusterId, + static_cast(&aBindingData)); + } + else + { + LOG_ERR("Binding command was not applied! Reason: %" CHIP_ERROR_FORMAT, aError.Format()); + } +} + void BindingHandler::OnOffProcessCommand(CommandId aCommandId, const EmberBindingTableEntry & aBinding, DeviceProxy * aDevice, void * aContext) { - CHIP_ERROR ret = CHIP_NO_ERROR; + CHIP_ERROR ret = CHIP_NO_ERROR; + BindingData * data = reinterpret_cast(aContext); auto onSuccess = [](const ConcreteCommandPath & commandPath, const StatusIB & status, const auto & dataResponse) { LOG_DBG("Binding command applied successfully!"); + + // If session was recovered and communication works, reset flag to the initial state. + if (BindingHandler::GetInstance().mCaseSessionRecovered) + BindingHandler::GetInstance().mCaseSessionRecovered = false; }; - auto onFailure = [](CHIP_ERROR error) { - LOG_INF("Binding command was not applied! Reason: %" CHIP_ERROR_FORMAT, error.Format()); + auto onFailure = [aDevice, dataRef = *data](CHIP_ERROR aError) mutable { + BindingHandler::OnInvokeCommandFailure(aDevice, dataRef, aError); }; switch (aCommandId) @@ -105,12 +142,18 @@ void BindingHandler::OnOffProcessCommand(CommandId aCommandId, const EmberBindin void BindingHandler::LevelControlProcessCommand(CommandId aCommandId, const EmberBindingTableEntry & aBinding, DeviceProxy * aDevice, void * aContext) { + BindingData * data = reinterpret_cast(aContext); + auto onSuccess = [](const ConcreteCommandPath & commandPath, const StatusIB & status, const auto & dataResponse) { LOG_DBG("Binding command applied successfully!"); + + // If session was recovered and communication works, reset flag to the initial state. + if (BindingHandler::GetInstance().mCaseSessionRecovered) + BindingHandler::GetInstance().mCaseSessionRecovered = false; }; - auto onFailure = [](CHIP_ERROR error) { - LOG_INF("Binding command was not applied! Reason: %" CHIP_ERROR_FORMAT, error.Format()); + auto onFailure = [aDevice, dataRef = *data](CHIP_ERROR aError) mutable { + BindingHandler::OnInvokeCommandFailure(aDevice, dataRef, aError); }; CHIP_ERROR ret = CHIP_NO_ERROR; @@ -119,7 +162,6 @@ void BindingHandler::LevelControlProcessCommand(CommandId aCommandId, const Embe { case Clusters::LevelControl::Commands::MoveToLevel::Id: { Clusters::LevelControl::Commands::MoveToLevel::Type moveToLevelCommand; - BindingData * data = reinterpret_cast(aContext); moveToLevelCommand.level = data->Value; if (aDevice) { @@ -192,7 +234,7 @@ void BindingHandler::InitInternal(intptr_t aArg) } BindingManager::GetInstance().RegisterBoundDeviceChangedHandler(LightSwitchChangedHandler); - PrintBindingTable(); + BindingHandler::GetInstance().PrintBindingTable(); } bool BindingHandler::IsGroupBound() diff --git a/examples/light-switch-app/nrfconnect/main/LightSwitch.cpp b/examples/light-switch-app/nrfconnect/main/LightSwitch.cpp index 275dcdceccf1f4..7420d8f5254feb 100644 --- a/examples/light-switch-app/nrfconnect/main/LightSwitch.cpp +++ b/examples/light-switch-app/nrfconnect/main/LightSwitch.cpp @@ -29,7 +29,7 @@ using namespace chip::app; void LightSwitch::Init(chip::EndpointId aLightSwitchEndpoint) { - BindingHandler::Init(); + BindingHandler::GetInstance().Init(); mLightSwitchEndpoint = aLightSwitchEndpoint; } @@ -55,7 +55,7 @@ void LightSwitch::InitiateActionSwitch(Action mAction) Platform::Delete(data); return; } - data->IsGroup = BindingHandler::IsGroupBound(); + data->IsGroup = BindingHandler::GetInstance().IsGroupBound(); DeviceLayer::PlatformMgr().ScheduleWork(BindingHandler::SwitchWorkerHandler, reinterpret_cast(data)); Platform::Delete(data); } @@ -77,7 +77,7 @@ void LightSwitch::DimmerChangeBrightness() sBrightness = 0; } data->Value = (uint8_t) sBrightness; - data->IsGroup = BindingHandler::IsGroupBound(); + data->IsGroup = BindingHandler::GetInstance().IsGroupBound(); DeviceLayer::PlatformMgr().ScheduleWork(BindingHandler::SwitchWorkerHandler, reinterpret_cast(data)); Platform::Delete(data); } diff --git a/examples/light-switch-app/nrfconnect/main/ShellCommands.cpp b/examples/light-switch-app/nrfconnect/main/ShellCommands.cpp index 4dc0a3db58258c..235b9f9aedb336 100644 --- a/examples/light-switch-app/nrfconnect/main/ShellCommands.cpp +++ b/examples/light-switch-app/nrfconnect/main/ShellCommands.cpp @@ -55,7 +55,7 @@ static CHIP_ERROR SwitchCommandHandler(int argc, char ** argv) static CHIP_ERROR TableCommandHelper(int argc, char ** argv) { - BindingHandler::PrintBindingTable(); + BindingHandler::GetInstance().PrintBindingTable(); return CHIP_NO_ERROR; } diff --git a/examples/light-switch-app/nrfconnect/main/include/BindingHandler.h b/examples/light-switch-app/nrfconnect/main/include/BindingHandler.h index 02aed9d7aedc49..fcd2d4fa8288b3 100644 --- a/examples/light-switch-app/nrfconnect/main/include/BindingHandler.h +++ b/examples/light-switch-app/nrfconnect/main/include/BindingHandler.h @@ -28,11 +28,6 @@ class BindingHandler { public: - static void Init(); - static void SwitchWorkerHandler(intptr_t); - static void PrintBindingTable(); - static bool IsGroupBound(); - struct BindingData { chip::EndpointId EndpointId; @@ -42,9 +37,24 @@ class BindingHandler bool IsGroup{ false }; }; + void Init(); + void PrintBindingTable(); + bool IsGroupBound(); + + static void SwitchWorkerHandler(intptr_t); + static void OnInvokeCommandFailure(chip::DeviceProxy * aDevice, BindingData & aBindingData, CHIP_ERROR aError); + + static BindingHandler & GetInstance() + { + static BindingHandler sBindingHandler; + return sBindingHandler; + } + private: static void OnOffProcessCommand(chip::CommandId, const EmberBindingTableEntry &, chip::DeviceProxy *, void *); static void LevelControlProcessCommand(chip::CommandId, const EmberBindingTableEntry &, chip::DeviceProxy *, void *); static void LightSwitchChangedHandler(const EmberBindingTableEntry &, chip::DeviceProxy *, void *); static void InitInternal(intptr_t); + + bool mCaseSessionRecovered = false; };