Skip to content

Commit

Permalink
[nrfconnect] Added recovering CASE session for the light switch (#17315)
Browse files Browse the repository at this point in the history
There isn't CASE recovery mechanism, so after resetting lighting
device, the light switch is not able to communicate with it,
as it holds out of date CASE session.

Added releasing CASE session in case invoke command failure due
to timeout reason. After that new session is established and command
retransmitted. CASE session is recovered only once per failure to
prevent multiple tries in case comunnication is seriously broken.
  • Loading branch information
kkasperczyk-no authored Apr 13, 2022
1 parent faabdf9 commit a75cd99
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 17 deletions.
1 change: 0 additions & 1 deletion examples/light-switch-app/nrfconnect/main/AppTask.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@

#include "AppTask.h"
#include "AppConfig.h"
#include "BindingHandler.h"
#include "LEDWidget.h"
#include "LightSwitch.h"
#include "ThreadUtil.h"
Expand Down
56 changes: 49 additions & 7 deletions examples/light-switch-app/nrfconnect/main/BindingHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<void *>(&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<BindingData *>(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)
Expand Down Expand Up @@ -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<BindingData *>(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;
Expand All @@ -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<BindingData *>(aContext);
moveToLevelCommand.level = data->Value;
if (aDevice)
{
Expand Down Expand Up @@ -192,7 +234,7 @@ void BindingHandler::InitInternal(intptr_t aArg)
}

BindingManager::GetInstance().RegisterBoundDeviceChangedHandler(LightSwitchChangedHandler);
PrintBindingTable();
BindingHandler::GetInstance().PrintBindingTable();
}

bool BindingHandler::IsGroupBound()
Expand Down
6 changes: 3 additions & 3 deletions examples/light-switch-app/nrfconnect/main/LightSwitch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ using namespace chip::app;

void LightSwitch::Init(chip::EndpointId aLightSwitchEndpoint)
{
BindingHandler::Init();
BindingHandler::GetInstance().Init();
mLightSwitchEndpoint = aLightSwitchEndpoint;
}

Expand All @@ -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<intptr_t>(data));
Platform::Delete(data);
}
Expand All @@ -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<intptr_t>(data));
Platform::Delete(data);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
20 changes: 15 additions & 5 deletions examples/light-switch-app/nrfconnect/main/include/BindingHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
};

0 comments on commit a75cd99

Please sign in to comment.