Skip to content

Commit

Permalink
fabric-admin add ability to grab uid from remote fabric sync device (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
tehampson authored Sep 3, 2024
1 parent 3de6f04 commit cacf69f
Show file tree
Hide file tree
Showing 7 changed files with 343 additions and 29 deletions.
2 changes: 2 additions & 0 deletions examples/fabric-admin/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ static_library("fabric-admin-utils") {
"device_manager/DeviceSubscriptionManager.h",
"device_manager/DeviceSynchronization.cpp",
"device_manager/DeviceSynchronization.h",
"device_manager/UidGetter.cpp",
"device_manager/UidGetter.h",
]

deps = [ "${chip_root}/src/app:events" ]
Expand Down
6 changes: 3 additions & 3 deletions examples/fabric-admin/device_manager/DeviceManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,9 @@ class DeviceManager : public PairingDelegate

void HandleCommandResponse(const chip::app::ConcreteCommandPath & path, chip::TLV::TLVReader & data);

Device * FindDeviceByEndpoint(chip::EndpointId endpointId);
Device * FindDeviceByNode(chip::NodeId nodeId);

private:
friend DeviceManager & DeviceMgr();

Expand Down Expand Up @@ -206,9 +209,6 @@ class DeviceManager : public PairingDelegate
bool mAutoSyncEnabled = false;
bool mInitialized = false;
uint64_t mRequestId = 0;

Device * FindDeviceByEndpoint(chip::EndpointId endpointId);
Device * FindDeviceByNode(chip::NodeId nodeId);
};

/**
Expand Down
11 changes: 8 additions & 3 deletions examples/fabric-admin/device_manager/DeviceSubscription.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -207,10 +207,15 @@ CHIP_ERROR DeviceSubscription::StartSubscription(OnDoneCallback onDoneCallback,
mCurrentAdministratorCommissioningAttributes.node_id = nodeId;
mCurrentAdministratorCommissioningAttributes.window_status =
static_cast<uint32_t>(Clusters::AdministratorCommissioning::CommissioningWindowStatusEnum::kWindowNotOpen);
mState = State::Connecting;
mOnDoneCallback = onDoneCallback;

return controller.GetConnectedDevice(nodeId, &mOnDeviceConnectedCallback, &mOnDeviceConnectionFailureCallback);
mOnDoneCallback = onDoneCallback;
MoveToState(State::Connecting);
CHIP_ERROR err = controller.GetConnectedDevice(nodeId, &mOnDeviceConnectedCallback, &mOnDeviceConnectionFailureCallback);
if (err != CHIP_NO_ERROR)
{
MoveToState(State::Idle);
}
return err;
}

void DeviceSubscription::StopSubscription()
Expand Down
120 changes: 99 additions & 21 deletions examples/fabric-admin/device_manager/DeviceSynchronization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,35 +128,35 @@ void DeviceSynchronizer::OnAttributeData(const ConcreteDataAttributePath & path,
void DeviceSynchronizer::OnReportEnd()
{
// Report end is at the end of all attributes (success)
MoveToState(State::ReceivedResponse);
}

void DeviceSynchronizer::OnDone(chip::app::ReadClient * apReadClient)
{
#if defined(PW_RPC_ENABLED)
if (!DeviceMgr().IsCurrentBridgeDevice(mCurrentDeviceData.node_id))
if (mState == State::ReceivedResponse && !DeviceMgr().IsCurrentBridgeDevice(mCurrentDeviceData.node_id))
{
AddSynchronizedDevice(mCurrentDeviceData);
// TODO(#35077) Figure out how we should reflect CADMIN values of ICD.
if (!mCurrentDeviceData.is_icd)
auto * device = DeviceMgr().FindDeviceByNode(mCurrentDeviceData.node_id);
if (!mCurrentDeviceData.has_unique_id && device)
{
VerifyOrDie(mController);
// TODO(#35333) Figure out how we should recover in this circumstance.
CHIP_ERROR err = DeviceSubscriptionManager::Instance().StartSubscription(*mController, mCurrentDeviceData.node_id);
if (err != CHIP_NO_ERROR)
GetUid(device->GetEndpointId());
if (mState == State::GettingUid)
{
ChipLogError(NotSpecified, "Failed start subscription to ");
// GetUid was successful and we rely on callback to call SynchronizationCompleteAddDevice.
return;
}
}
SynchronizationCompleteAddDevice();
}
#else
ChipLogError(NotSpecified, "Cannot synchronize device with fabric bridge: RPC not enabled");
#endif
}

void DeviceSynchronizer::OnDone(chip::app::ReadClient * apReadClient)
{
// Nothing to do: error reported on OnError or report ended called.
mDeviceSyncInProcess = false;
MoveToState(State::Idle);
}

void DeviceSynchronizer::OnError(CHIP_ERROR error)
{
MoveToState(State::ReceivedError);
ChipLogProgress(NotSpecified, "Error fetching device data: %" CHIP_ERROR_FORMAT, error.Format());
}

Expand All @@ -180,21 +180,22 @@ void DeviceSynchronizer::OnDeviceConnected(chip::Messaging::ExchangeManager & ex
if (err != CHIP_NO_ERROR)
{
ChipLogError(NotSpecified, "Failed to issue read for BasicInformation data");
mDeviceSyncInProcess = false;
MoveToState(State::Idle);
}
MoveToState(State::AwaitingResponse);
}

void DeviceSynchronizer::OnDeviceConnectionFailure(const chip::ScopedNodeId & peerId, CHIP_ERROR error)
{
ChipLogError(NotSpecified, "Device Sync failed to connect to " ChipLogFormatX64, ChipLogValueX64(peerId.GetNodeId()));
mDeviceSyncInProcess = false;
MoveToState(State::Idle);
}

void DeviceSynchronizer::StartDeviceSynchronization(chip::Controller::DeviceController * controller, chip::NodeId nodeId,
bool deviceIsIcd)
{
VerifyOrDie(controller);
if (mDeviceSyncInProcess)
if (mState != State::Idle)
{
ChipLogError(NotSpecified, "Device Sync NOT POSSIBLE: another sync is in progress");
return;
Expand All @@ -205,8 +206,85 @@ void DeviceSynchronizer::StartDeviceSynchronization(chip::Controller::DeviceCont
mCurrentDeviceData.has_is_icd = true;
mCurrentDeviceData.is_icd = deviceIsIcd;

mDeviceSyncInProcess = true;

ReturnOnFailure(controller->GetConnectedDevice(nodeId, &mOnDeviceConnectedCallback, &mOnDeviceConnectionFailureCallback));
mController = controller;
controller->GetConnectedDevice(nodeId, &mOnDeviceConnectedCallback, &mOnDeviceConnectionFailureCallback);
MoveToState(State::Connecting);
}

void DeviceSynchronizer::GetUid(EndpointId remoteEndpointIdOfInterest)
{
VerifyOrDie(mState == State::ReceivedResponse);
VerifyOrDie(mController);
VerifyOrDie(DeviceMgr().IsFabricSyncReady());
auto remoteBridgeNodeId = DeviceMgr().GetRemoteBridgeNodeId();

CHIP_ERROR err = mUidGetter.GetUid(
[this](std::optional<CharSpan> aUniqueId) {
if (aUniqueId.has_value())
{
this->mCurrentDeviceData.has_unique_id = true;
memcpy(this->mCurrentDeviceData.unique_id, aUniqueId.value().data(), aUniqueId.value().size());
}
else
{
ChipLogError(NotSpecified, "We expected to get UniqueId from remote fabric sync bridge");
}
this->SynchronizationCompleteAddDevice();
},
*mController, remoteBridgeNodeId, remoteEndpointIdOfInterest);

if (err == CHIP_NO_ERROR)
{
MoveToState(State::GettingUid);
}
}

void DeviceSynchronizer::SynchronizationCompleteAddDevice()
{
VerifyOrDie(mState == State::ReceivedResponse || mState == State::GettingUid);
AddSynchronizedDevice(mCurrentDeviceData);
// TODO(#35077) Figure out how we should reflect CADMIN values of ICD.
if (!mCurrentDeviceData.is_icd)
{
VerifyOrDie(mController);
// TODO(#35333) Figure out how we should recover in this circumstance.
CHIP_ERROR err = DeviceSubscriptionManager::Instance().StartSubscription(*mController, mCurrentDeviceData.node_id);
if (err != CHIP_NO_ERROR)
{
ChipLogError(NotSpecified, "Failed start subscription to NodeId:" ChipLogFormatX64,
ChipLogValueX64(mCurrentDeviceData.node_id));
}
}
MoveToState(State::Idle);
}

void DeviceSynchronizer::MoveToState(const State targetState)
{
mState = targetState;
ChipLogDetail(NotSpecified, "DeviceSynchronizer moving to [%10.10s]", GetStateStr());
}

const char * DeviceSynchronizer::GetStateStr() const
{
switch (mState)
{
case State::Idle:
return "Idle";

case State::Connecting:
return "Connecting";

case State::AwaitingResponse:
return "AwaitingResponse";

case State::ReceivedResponse:
return "ReceivedResponse";

case State::ReceivedError:
return "ReceivedError";

case State::GettingUid:
return "GettingUid";
}
return "N/A";
}
23 changes: 21 additions & 2 deletions examples/fabric-admin/device_manager/DeviceSynchronization.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
*/
#pragma once

#include "UidGetter.h"

#include <app/ReadClient.h>
#include <controller/CHIPDeviceController.h>
#include <lib/core/DataModelTypes.h>
Expand Down Expand Up @@ -65,14 +67,31 @@ class DeviceSynchronizer : public chip::app::ReadClient::Callback
static DeviceSynchronizer & Instance();

private:
enum class State : uint8_t
{
Idle, ///< Default state that the object starts out in, where no work has commenced
Connecting, ///< We are waiting for OnDeviceConnected or OnDeviceConnectionFailure callbacks to be called
AwaitingResponse, ///< We have started reading BasicInformation cluster attributes
ReceivedResponse, ///< We have received a ReportEnd from reading BasicInformation cluster attributes
ReceivedError, ///< We recieved an error while reading of BasicInformation cluster attributes
GettingUid, ///< We are getting UniqueId from the remote fabric sync bridge.
};

void GetUid(chip::EndpointId endpointId);
void SynchronizationCompleteAddDevice();

void MoveToState(const State targetState);
const char * GetStateStr() const;

std::unique_ptr<chip::app::ReadClient> mClient;

chip::Callback::Callback<chip::OnDeviceConnected> mOnDeviceConnectedCallback;
chip::Callback::Callback<chip::OnDeviceConnectionFailure> mOnDeviceConnectionFailureCallback;

State mState = State::Idle;
// mController is expected to remain valid throughout the entire device synchronization process (i.e. when
// mDeviceSyncInProcess is true).
// mState != Idle).
chip::Controller::DeviceController * mController = nullptr;
bool mDeviceSyncInProcess = false;
chip_rpc_SynchronizedDevice mCurrentDeviceData = chip_rpc_SynchronizedDevice_init_default;
UidGetter mUidGetter;
};
Loading

0 comments on commit cacf69f

Please sign in to comment.