Skip to content

Commit

Permalink
[Fabric-Sync] Support icd-registration during device sync (#36569)
Browse files Browse the repository at this point in the history
  • Loading branch information
yufengwangca authored Nov 20, 2024
1 parent c197bc2 commit f4b8064
Show file tree
Hide file tree
Showing 10 changed files with 507 additions and 5 deletions.
6 changes: 6 additions & 0 deletions examples/fabric-sync/admin/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,21 @@ source_set("fabric-admin-lib") {
"FabricAdmin.h",
"FabricSyncGetter.cpp",
"FabricSyncGetter.h",
"IcdManager.cpp",
"IcdManager.h",
"PairingManager.cpp",
"PairingManager.h",
"StayActiveSender.cpp",
"StayActiveSender.h",
"UniqueIdGetter.cpp",
"UniqueIdGetter.h",
]

deps = [
"${chip_root}/examples/fabric-sync/bridge:fabric-bridge-lib",
"${chip_root}/examples/platform/linux:app-main",
"${chip_root}/src/app/icd/client:handler",
"${chip_root}/src/app/icd/client:manager",
"${chip_root}/src/lib",
]
}
64 changes: 63 additions & 1 deletion examples/fabric-sync/admin/FabricAdmin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
*/

#include "FabricAdmin.h"
#include <AppMain.h>
#include <bridge/include/FabricBridge.h>
#include <controller/CHIPDeviceControllerFactory.h>

using namespace ::chip;

Expand All @@ -28,16 +31,35 @@ constexpr uint32_t kCommissionPrepareTimeMs = 500;
} // namespace

FabricAdmin FabricAdmin::sInstance;
app::DefaultICDClientStorage FabricAdmin::sICDClientStorage;
app::CheckInHandler FabricAdmin::sCheckInHandler;

FabricAdmin & FabricAdmin::Instance()
{
if (!sInstance.mInitialized)
{
sInstance.Init();
VerifyOrDie(sInstance.Init() == CHIP_NO_ERROR);
}
return sInstance;
}

CHIP_ERROR FabricAdmin::Init()
{
IcdManager::Instance().SetDelegate(&sInstance);

ReturnLogErrorOnFailure(sICDClientStorage.Init(GetPersistentStorageDelegate(), GetSessionKeystore()));

auto engine = chip::app::InteractionModelEngine::GetInstance();
VerifyOrReturnError(engine != nullptr, CHIP_ERROR_INCORRECT_STATE);
ReturnLogErrorOnFailure(IcdManager::Instance().Init(&sICDClientStorage, engine));
ReturnLogErrorOnFailure(sCheckInHandler.Init(Controller::DeviceControllerFactory::GetInstance().GetSystemState()->ExchangeMgr(),
&sICDClientStorage, &IcdManager::Instance(), engine));

mInitialized = true;

return CHIP_NO_ERROR;
}

CHIP_ERROR FabricAdmin::OpenCommissioningWindow(Controller::CommissioningWindowVerifierParams params, FabricIndex fabricIndex)
{
ScopedNodeId scopedNodeId(params.GetNodeId(), fabricIndex);
Expand Down Expand Up @@ -116,6 +138,46 @@ CHIP_ERROR FabricAdmin::KeepActive(ScopedNodeId scopedNodeId, uint32_t stayActiv
return CHIP_NO_ERROR;
}

void FabricAdmin::OnCheckInCompleted(const app::ICDClientInfo & clientInfo)
{
// Accessing mPendingCheckIn should only be done while holding ChipStackLock
assertChipStackLockedByCurrentThread();
ScopedNodeId scopedNodeId = clientInfo.peer_node;
auto it = mPendingCheckIn.find(scopedNodeId);
VerifyOrReturn(it != mPendingCheckIn.end());

KeepActiveDataForCheckIn checkInData = it->second;
// Removed from pending map as check-in from this node has occured and we will handle the pending KeepActive
// request.
mPendingCheckIn.erase(scopedNodeId);

auto timeNow = System::SystemClock().GetMonotonicTimestamp();
if (timeNow > checkInData.mRequestExpiryTimestamp)
{
ChipLogError(NotSpecified,
"ICD check-in for device we have been waiting, came after KeepActive expiry. Request dropped for ID: "
"[%d:0x " ChipLogFormatX64 "]",
scopedNodeId.GetFabricIndex(), ChipLogValueX64(scopedNodeId.GetNodeId()));
return;
}

// TODO https://github.com/CHIP-Specifications/connectedhomeip-spec/issues/10448. Spec does
// not define what to do if we fail to send the StayActiveRequest. We are assuming that any
// further attempts to send a StayActiveRequest will result in a similar failure. Because
// there is no mechanism for us to communicate with the client that sent out the KeepActive
// command that there was a failure, we simply fail silently. After spec issue is
// addressed, we can implement what spec defines here.
auto onDone = [=](uint32_t promisedActiveDuration) {
bridge::FabricBridge::Instance().ActiveChanged(scopedNodeId, promisedActiveDuration);
};
CHIP_ERROR err = StayActiveSender::SendStayActiveCommand(checkInData.mStayActiveDurationMs, clientInfo.peer_node,
app::InteractionModelEngine::GetInstance(), onDone);
if (err != CHIP_NO_ERROR)
{
ChipLogError(NotSpecified, "Failed to send StayActive command %s", err.AsString());
}
}

void FabricAdmin::OnCommissioningComplete(NodeId deviceId, CHIP_ERROR err)
{
if (mNodeId != deviceId)
Expand Down
14 changes: 12 additions & 2 deletions examples/fabric-sync/admin/FabricAdmin.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,12 @@
#pragma once

#include "DeviceManager.h"
#include "IcdManager.h"
#include "StayActiveSender.h"

#include <app/icd/client/CheckInHandler.h>
#include <app/icd/client/DefaultCheckInDelegate.h>
#include <app/icd/client/DefaultICDClientStorage.h>
#include <bridge/include/FabricAdminDelegate.h>
#include <map>
#include <setup_payload/QRCodeSetupPayloadGenerator.h>
Expand All @@ -37,10 +42,11 @@ struct ScopedNodeIdHasher
}
};

class FabricAdmin final : public bridge::FabricAdminDelegate, public PairingDelegate
class FabricAdmin final : public bridge::FabricAdminDelegate, public PairingDelegate, public IcdManager::Delegate
{
public:
static FabricAdmin & Instance();
static chip::app::DefaultICDClientStorage & GetDefaultICDClientStorage() { return sICDClientStorage; }

CHIP_ERROR OpenCommissioningWindow(chip::Controller::CommissioningWindowVerifierParams params,
chip::FabricIndex fabricIndex) override;
Expand All @@ -51,6 +57,8 @@ class FabricAdmin final : public bridge::FabricAdminDelegate, public PairingDele

CHIP_ERROR KeepActive(chip::ScopedNodeId scopedNodeId, uint32_t stayActiveDurationMs, uint32_t timeoutMs) override;

void OnCheckInCompleted(const chip::app::ICDClientInfo & clientInfo) override;

void OnCommissioningComplete(chip::NodeId deviceId, CHIP_ERROR err) override;

void ScheduleSendingKeepActiveOnCheckIn(chip::ScopedNodeId scopedNodeId, uint32_t stayActiveDurationMs, uint32_t timeoutMs);
Expand Down Expand Up @@ -89,11 +97,13 @@ class FabricAdmin final : public bridge::FabricAdminDelegate, public PairingDele
std::unordered_map<chip::ScopedNodeId, KeepActiveDataForCheckIn, ScopedNodeIdHasher> mPendingCheckIn;

static FabricAdmin sInstance;
static chip::app::DefaultICDClientStorage sICDClientStorage;
static chip::app::CheckInHandler sCheckInHandler;

bool mInitialized = false;
chip::NodeId mNodeId = chip::kUndefinedNodeId;

void Init() { mInitialized = true; }
CHIP_ERROR Init();
};

} // namespace admin
51 changes: 51 additions & 0 deletions examples/fabric-sync/admin/IcdManager.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright (c) 2024 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 "IcdManager.h"

namespace admin {

IcdManager IcdManager::sInstance;

IcdManager & IcdManager::Instance()
{
return sInstance;
}

void IcdManager::OnCheckInComplete(const chip::app::ICDClientInfo & clientInfo)
{
DefaultCheckInDelegate::OnCheckInComplete(clientInfo);
if (mDelegate)
{
mDelegate->OnCheckInCompleted(clientInfo);
}
}

void IcdManager::SetDelegate(Delegate * delegate)
{
// To keep IcdManager simple, there is an assumption that there is only ever
// one delegate set and it's lifetime is identical to IcdManager. In the
// future this assumption can change should there be a need, but that will
// require code changes to IcdManager. For now we will crash if someone tries
// to call SetDelegate for a second time or if delegate is non-null.
VerifyOrDie(delegate);
VerifyOrDie(!mDelegate);
mDelegate = delegate;
}

} // namespace admin
55 changes: 55 additions & 0 deletions examples/fabric-sync/admin/IcdManager.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright (c) 2024 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 <app/icd/client/DefaultCheckInDelegate.h>

namespace admin {

/**
* @brief Manages check-ins from ICD devices.
*
* Intended to be used as a thin CheckInDelegate. This allows a delegate register
* themselves so they can be aware when ICD device checks-in allowing the
* delegate to interact with the ICD device during the short window that it is
* awake.
*/
class IcdManager : public chip::app::DefaultCheckInDelegate
{
public:
class Delegate
{
public:
virtual ~Delegate() = default;
virtual void OnCheckInCompleted(const chip::app::ICDClientInfo & clientInfo) = 0;
};

static IcdManager & Instance();
void OnCheckInComplete(const chip::app::ICDClientInfo & clientInfo) override;

// There is an assumption delegate assigned only happens once and that it lives
// for the entirety of the lifetime of fabric admin.
void SetDelegate(Delegate * delegate);

private:
static IcdManager sInstance;
Delegate * mDelegate = nullptr;
};

} // namespace admin
Loading

0 comments on commit f4b8064

Please sign in to comment.