[Fabric-Admin] Implement FabricSyncGetter APIs (#36108)
* [Fabric-Admin] Implement FabricSyncGetter APIs
* Update examples/fabric-admin/device_manager/FabricSyncGetter.h
Co-authored-by: Terence Hampson <thampson@google.com>
---------
Co-authored-by: Terence Hampson <thampson@google.com>
diff --git a/examples/fabric-admin/BUILD.gn b/examples/fabric-admin/BUILD.gn
index 38252cd..58d9cee 100644
--- a/examples/fabric-admin/BUILD.gn
+++ b/examples/fabric-admin/BUILD.gn
@@ -90,6 +90,8 @@
"device_manager/DeviceSubscriptionManager.h",
"device_manager/DeviceSynchronization.cpp",
"device_manager/DeviceSynchronization.h",
+ "device_manager/FabricSyncGetter.cpp",
+ "device_manager/FabricSyncGetter.h",
"device_manager/PairingManager.cpp",
"device_manager/PairingManager.h",
"device_manager/UniqueIdGetter.cpp",
diff --git a/examples/fabric-admin/commands/clusters/ReportCommand.cpp b/examples/fabric-admin/commands/clusters/ReportCommand.cpp
index df6f329..7f3decd 100644
--- a/examples/fabric-admin/commands/clusters/ReportCommand.cpp
+++ b/examples/fabric-admin/commands/clusters/ReportCommand.cpp
@@ -45,8 +45,6 @@
}
LogErrorOnFailure(RemoteDataModelLogger::LogAttributeAsJSON(path, data));
-
- DeviceMgr().HandleAttributeData(path, *data);
}
void ReportCommand::OnEventData(const app::EventHeader & eventHeader, TLV::TLVReader * data, const app::StatusIB * status)
diff --git a/examples/fabric-admin/device_manager/DeviceManager.cpp b/examples/fabric-admin/device_manager/DeviceManager.cpp
index 2968bcf..3bfd677 100644
--- a/examples/fabric-admin/device_manager/DeviceManager.cpp
+++ b/examples/fabric-admin/device_manager/DeviceManager.cpp
@@ -212,13 +212,18 @@
return;
}
- StringBuilder<kMaxCommandSize> commandBuilder;
+ ChipLogProgress(NotSpecified, "Read SupportedDeviceCategories from the remote bridge.");
- commandBuilder.Add("commissionercontrol read supported-device-categories ");
- commandBuilder.AddFormat("%ld ", mRemoteBridgeNodeId);
- commandBuilder.AddFormat("%d", kAggregatorEndpointId);
+ CHIP_ERROR error = mFabricSyncGetter.GetFabricSynchronizationData(
+ [this](TLV::TLVReader & data) { this->HandleReadSupportedDeviceCategories(data); },
+ PairingManager::Instance().CurrentCommissioner(), this->GetRemoteBridgeNodeId(), kAggregatorEndpointId);
- PushCommand(commandBuilder.c_str());
+ if (error != CHIP_NO_ERROR)
+ {
+ ChipLogError(NotSpecified,
+ "Failed to read SupportedDeviceCategories from the remote bridge (NodeId: %lu). Error: %" CHIP_ERROR_FORMAT,
+ mRemoteBridgeNodeId, error.Format());
+ }
}
void DeviceManager::HandleReadSupportedDeviceCategories(TLV::TLVReader & data)
@@ -421,13 +426,6 @@
void DeviceManager::HandleAttributeData(const app::ConcreteDataAttributePath & path, TLV::TLVReader & data)
{
- if (path.mClusterId == CommissionerControl::Id &&
- path.mAttributeId == CommissionerControl::Attributes::SupportedDeviceCategories::Id)
- {
- HandleReadSupportedDeviceCategories(data);
- return;
- }
-
if (path.mClusterId == Descriptor::Id && path.mAttributeId == Descriptor::Attributes::PartsList::Id)
{
HandleAttributePartsListUpdate(data);
diff --git a/examples/fabric-admin/device_manager/DeviceManager.h b/examples/fabric-admin/device_manager/DeviceManager.h
index 62d5ae0..43461f4 100644
--- a/examples/fabric-admin/device_manager/DeviceManager.h
+++ b/examples/fabric-admin/device_manager/DeviceManager.h
@@ -20,6 +20,7 @@
#include <app-common/zap-generated/cluster-objects.h>
#include <device_manager/BridgeSubscription.h>
+#include <device_manager/FabricSyncGetter.h>
#include <device_manager/PairingManager.h>
#include <platform/CHIPDeviceLayer.h>
@@ -212,6 +213,7 @@
uint64_t mRequestId = 0;
BridgeSubscription mBridgeSubscriber;
+ FabricSyncGetter mFabricSyncGetter;
};
/**
diff --git a/examples/fabric-admin/device_manager/FabricSyncGetter.cpp b/examples/fabric-admin/device_manager/FabricSyncGetter.cpp
new file mode 100644
index 0000000..5201048
--- /dev/null
+++ b/examples/fabric-admin/device_manager/FabricSyncGetter.cpp
@@ -0,0 +1,121 @@
+/*
+ * 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 "FabricSyncGetter.h"
+
+using namespace ::chip;
+using namespace ::chip::app;
+using chip::app::ReadClient;
+
+namespace {
+
+void OnDeviceConnectedWrapper(void * context, Messaging::ExchangeManager & exchangeMgr, const SessionHandle & sessionHandle)
+{
+ reinterpret_cast<FabricSyncGetter *>(context)->OnDeviceConnected(exchangeMgr, sessionHandle);
+}
+
+void OnDeviceConnectionFailureWrapper(void * context, const ScopedNodeId & peerId, CHIP_ERROR error)
+{
+ reinterpret_cast<FabricSyncGetter *>(context)->OnDeviceConnectionFailure(peerId, error);
+}
+
+} // namespace
+
+FabricSyncGetter::FabricSyncGetter() :
+ mOnDeviceConnectedCallback(OnDeviceConnectedWrapper, this),
+ mOnDeviceConnectionFailureCallback(OnDeviceConnectionFailureWrapper, this)
+{}
+
+CHIP_ERROR FabricSyncGetter::GetFabricSynchronizationData(OnDoneCallback onDoneCallback, Controller::DeviceController & controller,
+ NodeId nodeId, EndpointId endpointId)
+{
+ assertChipStackLockedByCurrentThread();
+
+ mEndpointId = endpointId;
+ mOnDoneCallback = onDoneCallback;
+
+ CHIP_ERROR err = controller.GetConnectedDevice(nodeId, &mOnDeviceConnectedCallback, &mOnDeviceConnectionFailureCallback);
+ if (err != CHIP_NO_ERROR)
+ {
+ ChipLogError(NotSpecified, "Failed to connect to remote fabric bridge %" CHIP_ERROR_FORMAT, err.Format());
+ }
+ return err;
+}
+
+void FabricSyncGetter::OnAttributeData(const ConcreteDataAttributePath & path, TLV::TLVReader * data, const StatusIB & status)
+{
+ VerifyOrDie(path.mClusterId == Clusters::CommissionerControl::Id);
+
+ if (!status.IsSuccess())
+ {
+ ChipLogError(NotSpecified, "Response Failure: %" CHIP_ERROR_FORMAT, status.ToChipError().Format());
+ return;
+ }
+
+ switch (path.mAttributeId)
+ {
+ case Clusters::CommissionerControl::Attributes::SupportedDeviceCategories::Id: {
+ mOnDoneCallback(*data);
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+void FabricSyncGetter::OnError(CHIP_ERROR error)
+{
+ ChipLogProgress(NotSpecified, "Error Getting SupportedDeviceCategories: %" CHIP_ERROR_FORMAT, error.Format());
+}
+
+void FabricSyncGetter::OnDone(ReadClient * apReadClient)
+{
+ ChipLogProgress(NotSpecified, "Reading SupportedDeviceCategories is done.");
+}
+
+void FabricSyncGetter::OnDeviceConnected(Messaging::ExchangeManager & exchangeMgr, const SessionHandle & sessionHandle)
+{
+ mClient = std::make_unique<ReadClient>(app::InteractionModelEngine::GetInstance(), &exchangeMgr, *this /* callback */,
+ ReadClient::InteractionType::Read);
+ VerifyOrDie(mClient);
+
+ AttributePathParams readPaths[1];
+ readPaths[0] = AttributePathParams(mEndpointId, Clusters::CommissionerControl::Id,
+ Clusters::CommissionerControl::Attributes::SupportedDeviceCategories::Id);
+
+ ReadPrepareParams readParams(sessionHandle);
+
+ readParams.mpAttributePathParamsList = readPaths;
+ readParams.mAttributePathParamsListSize = 1;
+
+ CHIP_ERROR err = mClient->SendRequest(readParams);
+
+ if (err != CHIP_NO_ERROR)
+ {
+ ChipLogError(NotSpecified, "Failed to read SupportedDeviceCategories from the bridged device.");
+ OnDone(nullptr);
+ return;
+ }
+}
+
+void FabricSyncGetter::OnDeviceConnectionFailure(const ScopedNodeId & peerId, CHIP_ERROR error)
+{
+ ChipLogError(NotSpecified, "FabricSyncGetter failed to connect to " ChipLogFormatX64, ChipLogValueX64(peerId.GetNodeId()));
+
+ OnDone(nullptr);
+}
diff --git a/examples/fabric-admin/device_manager/FabricSyncGetter.h b/examples/fabric-admin/device_manager/FabricSyncGetter.h
new file mode 100644
index 0000000..d6d3a5b
--- /dev/null
+++ b/examples/fabric-admin/device_manager/FabricSyncGetter.h
@@ -0,0 +1,75 @@
+/*
+ * 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/ReadClient.h>
+#include <controller/CHIPDeviceController.h>
+
+#include <memory>
+#include <optional>
+
+/**
+ * @brief Class used to get FabricSynchronization from SupportedDeviceCategories attribute of Commissioner Control Cluster.
+ *
+ * Functionality:
+ * - Establishes a CASE session to communicate with the remote bridge.
+ * - Retrieves the attribute data from the endpoint which host Aggregator.
+ * - Provides callbacks for success, error, and completion when retrieving data.
+ */
+class FabricSyncGetter : public chip::app::ReadClient::Callback
+{
+public:
+ using OnDoneCallback = std::function<void(chip::TLV::TLVReader & data)>;
+
+ FabricSyncGetter();
+
+ /**
+ * @brief Initiates the process of retrieving fabric synchronization data from the target device.
+ *
+ * @param onDoneCallback A callback function to be invoked when the data retrieval is complete.
+ * @param controller The device controller used to establish a session with the target device.
+ * @param nodeId The Node ID of the target device.
+ * @param endpointId The Endpoint ID from which to retrieve the fabric synchronization data.
+ * @return CHIP_ERROR Returns an error if the process fails, CHIP_NO_ERROR on success.
+ */
+ CHIP_ERROR GetFabricSynchronizationData(OnDoneCallback onDoneCallback, chip::Controller::DeviceController & controller,
+ chip::NodeId nodeId, chip::EndpointId endpointId);
+
+ ///////////////////////////////////////////////////////////////
+ // ReadClient::Callback implementation
+ ///////////////////////////////////////////////////////////////
+ void OnAttributeData(const chip::app::ConcreteDataAttributePath & path, chip::TLV::TLVReader * data,
+ const chip::app::StatusIB & status) override;
+ void OnError(CHIP_ERROR error) override;
+ void OnDone(chip::app::ReadClient * apReadClient) override;
+
+ ///////////////////////////////////////////////////////////////
+ // callbacks for CASE session establishment
+ ///////////////////////////////////////////////////////////////
+ void OnDeviceConnected(chip::Messaging::ExchangeManager & exchangeMgr, const chip::SessionHandle & sessionHandle);
+ void OnDeviceConnectionFailure(const chip::ScopedNodeId & peerId, CHIP_ERROR error);
+
+private:
+ std::unique_ptr<chip::app::ReadClient> mClient;
+
+ OnDoneCallback mOnDoneCallback;
+ chip::EndpointId mEndpointId;
+ chip::Callback::Callback<chip::OnDeviceConnected> mOnDeviceConnectedCallback;
+ chip::Callback::Callback<chip::OnDeviceConnectionFailure> mOnDeviceConnectionFailureCallback;
+};