Skip to content

Commit 46480dc

Browse files
andy31415restyled-commitsandreilitvin
authored andcommitted
Marshal the data from BasicInformationCluster to FabricBridge (project-chip#34854)
* Add extra attributes to the bridged device basic info structures, remove nonsense comments * Make use of AAI for BridgedDeviceBasicInformation cluster * Restyled by gn * Fix sizes for software version * Update the synchronized device proto to have more data in it * Switch to unique ptr in the registry, making sure memory management works (fixed memory leak on remove device) * Use more std::optional * Bump revision to 4 * Forward attributes from the create call into the bridged device * Make attribute mapping actually work * Restyle * Ensure unique IDs are generated * Restyle * Increase size to 33 to allow for a null terminator * make sure that the rpc structures are initialized * Restyle * Add some fake data to test moving the data around * Remove unused members that were likely just copied over * make the attributes optional * Prepare some device sync data - reading the basic info cluster * Prepare some device sync data - reading the basic info cluster * Full implementation of forwarding data * Restyle * Add missing file * Restyle * reset readclient, since this may reset the exchange manager ... seems cleaner * Add the verifyOrDie * Restyled by clang-format * Fix string size for HW and software versions * Remove some of the spammier logs * Enfore RPC enabling for synchronized device addition * Add device sync in progress tracking * Undo submodule update * Fix up device sync progress tracking to better handle errors * Restyled by clang-format --------- Co-authored-by: Restyled.io <commits@restyled.io> Co-authored-by: Andrei Litvin <andreilitvin@google.com>
1 parent 8dc2e89 commit 46480dc

File tree

7 files changed

+270
-47
lines changed

7 files changed

+270
-47
lines changed

examples/common/pigweed/protos/fabric_bridge_service.proto

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ message SynchronizedDevice {
1818
optional string hardware_version_string = 9;
1919
optional uint32 software_version = 10;
2020
optional string software_version_string = 11;
21+
optional bool is_icd = 12;
2122
}
2223

2324
service FabricBridge {

examples/fabric-admin/BUILD.gn

+2
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ static_library("fabric-admin-utils") {
7272
"commands/common/RemoteDataModelLogger.cpp",
7373
"commands/common/RemoteDataModelLogger.h",
7474
"commands/fabric-sync/FabricSyncCommand.cpp",
75+
"commands/pairing/DeviceSynchronization.cpp",
76+
"commands/pairing/DeviceSynchronization.h",
7577
"commands/pairing/OpenCommissioningWindowCommand.cpp",
7678
"commands/pairing/OpenCommissioningWindowCommand.h",
7779
"commands/pairing/PairingCommand.cpp",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
/*
2+
* Copyright (c) 2024 Project CHIP Authors
3+
* All rights reserved.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*
17+
*/
18+
19+
#include "DeviceSynchronization.h"
20+
#include "rpc/RpcClient.h"
21+
22+
#include <app/InteractionModelEngine.h>
23+
#include <app/server/Server.h>
24+
25+
#include <app-common/zap-generated/ids/Attributes.h>
26+
#include <app-common/zap-generated/ids/Clusters.h>
27+
28+
using namespace ::chip;
29+
using namespace ::chip::app;
30+
using chip::app::ReadClient;
31+
32+
namespace {
33+
34+
void OnDeviceConnectedWrapper(void * context, Messaging::ExchangeManager & exchangeMgr, const SessionHandle & sessionHandle)
35+
{
36+
reinterpret_cast<DeviceSynchronizer *>(context)->OnDeviceConnected(exchangeMgr, sessionHandle);
37+
}
38+
39+
void OnDeviceConnectionFailureWrapper(void * context, const ScopedNodeId & peerId, CHIP_ERROR error)
40+
{
41+
reinterpret_cast<DeviceSynchronizer *>(context)->OnDeviceConnectionFailure(peerId, error);
42+
}
43+
44+
bool SuccessOrLog(CHIP_ERROR err, const char * name)
45+
{
46+
if (err == CHIP_NO_ERROR)
47+
{
48+
return true;
49+
}
50+
51+
ChipLogError(NotSpecified, "Failed to read %s: %" CHIP_ERROR_FORMAT, name, err.Format());
52+
53+
return false;
54+
}
55+
56+
} // namespace
57+
58+
DeviceSynchronizer & DeviceSynchronizer::Instance()
59+
{
60+
static DeviceSynchronizer instance;
61+
return instance;
62+
}
63+
64+
DeviceSynchronizer::DeviceSynchronizer() :
65+
mOnDeviceConnectedCallback(OnDeviceConnectedWrapper, this),
66+
mOnDeviceConnectionFailureCallback(OnDeviceConnectionFailureWrapper, this)
67+
{}
68+
69+
void DeviceSynchronizer::OnAttributeData(const ConcreteDataAttributePath & path, TLV::TLVReader * data, const StatusIB & status)
70+
{
71+
VerifyOrDie(path.mEndpointId == kRootEndpointId);
72+
VerifyOrDie(path.mClusterId == Clusters::BasicInformation::Id);
73+
74+
switch (path.mAttributeId)
75+
{
76+
case Clusters::BasicInformation::Attributes::UniqueID::Id:
77+
mCurrentDeviceData.has_unique_id =
78+
SuccessOrLog(data->GetString(mCurrentDeviceData.unique_id, sizeof(mCurrentDeviceData.unique_id)), "UniqueId");
79+
break;
80+
case Clusters::BasicInformation::Attributes::VendorName::Id:
81+
mCurrentDeviceData.has_vendor_name =
82+
SuccessOrLog(data->GetString(mCurrentDeviceData.vendor_name, sizeof(mCurrentDeviceData.vendor_name)), "VendorName");
83+
break;
84+
case Clusters::BasicInformation::Attributes::VendorID::Id:
85+
mCurrentDeviceData.has_vendor_id = SuccessOrLog(data->Get(mCurrentDeviceData.vendor_id), "VendorID");
86+
break;
87+
case Clusters::BasicInformation::Attributes::ProductName::Id:
88+
mCurrentDeviceData.has_product_name =
89+
SuccessOrLog(data->GetString(mCurrentDeviceData.product_name, sizeof(mCurrentDeviceData.product_name)), "ProductName");
90+
break;
91+
case Clusters::BasicInformation::Attributes::ProductID::Id:
92+
mCurrentDeviceData.has_product_id = SuccessOrLog(data->Get(mCurrentDeviceData.product_id), "ProductID");
93+
break;
94+
case Clusters::BasicInformation::Attributes::NodeLabel::Id:
95+
mCurrentDeviceData.has_node_label =
96+
SuccessOrLog(data->GetString(mCurrentDeviceData.node_label, sizeof(mCurrentDeviceData.node_label)), "NodeLabel");
97+
break;
98+
case Clusters::BasicInformation::Attributes::HardwareVersion::Id:
99+
mCurrentDeviceData.has_hardware_version = SuccessOrLog(data->Get(mCurrentDeviceData.hardware_version), "HardwareVersion");
100+
break;
101+
case Clusters::BasicInformation::Attributes::HardwareVersionString::Id:
102+
mCurrentDeviceData.has_hardware_version_string = SuccessOrLog(
103+
data->GetString(mCurrentDeviceData.hardware_version_string, sizeof(mCurrentDeviceData.hardware_version_string)),
104+
"HardwareVersionString");
105+
break;
106+
case Clusters::BasicInformation::Attributes::SoftwareVersion::Id:
107+
mCurrentDeviceData.has_software_version = SuccessOrLog(data->Get(mCurrentDeviceData.software_version), "HardwareVersion");
108+
break;
109+
case Clusters::BasicInformation::Attributes::SoftwareVersionString::Id:
110+
mCurrentDeviceData.has_software_version_string = SuccessOrLog(
111+
data->GetString(mCurrentDeviceData.software_version_string, sizeof(mCurrentDeviceData.software_version_string)),
112+
"SoftwareVersionString");
113+
break;
114+
default:
115+
break;
116+
}
117+
}
118+
119+
void DeviceSynchronizer::OnReportEnd()
120+
{
121+
// Report end is at the end of all attributes (success)
122+
#if defined(PW_RPC_ENABLED)
123+
AddSynchronizedDevice(mCurrentDeviceData);
124+
#else
125+
ChipLogError(NotSpecified, "Cannot synchronize device with fabric bridge: RPC not enabled");
126+
#endif
127+
}
128+
129+
void DeviceSynchronizer::OnDone(chip::app::ReadClient * apReadClient)
130+
{
131+
// Nothing to do: error reported on OnError or report ended called.
132+
mDeviceSyncInProcess = false;
133+
}
134+
135+
void DeviceSynchronizer::OnError(CHIP_ERROR error)
136+
{
137+
ChipLogProgress(NotSpecified, "Error fetching device data: %" CHIP_ERROR_FORMAT, error.Format());
138+
}
139+
140+
void DeviceSynchronizer::OnDeviceConnected(chip::Messaging::ExchangeManager & exchangeMgr,
141+
const chip::SessionHandle & sessionHandle)
142+
{
143+
mClient = std::make_unique<ReadClient>(app::InteractionModelEngine::GetInstance(), &exchangeMgr /* echangeMgr */,
144+
*this /* callback */, ReadClient::InteractionType::Read);
145+
VerifyOrDie(mClient);
146+
147+
AttributePathParams readPaths[1];
148+
readPaths[0] = AttributePathParams(kRootEndpointId, Clusters::BasicInformation::Id);
149+
150+
ReadPrepareParams readParams(sessionHandle);
151+
152+
readParams.mpAttributePathParamsList = readPaths;
153+
readParams.mAttributePathParamsListSize = 1;
154+
155+
CHIP_ERROR err = mClient->SendRequest(readParams);
156+
157+
if (err != CHIP_NO_ERROR)
158+
{
159+
ChipLogError(NotSpecified, "Failed to issue read for BasicInformation data");
160+
mDeviceSyncInProcess = false;
161+
}
162+
}
163+
164+
void DeviceSynchronizer::OnDeviceConnectionFailure(const chip::ScopedNodeId & peerId, CHIP_ERROR error)
165+
{
166+
ChipLogError(NotSpecified, "Device Sync failed to connect to " ChipLogFormatX64, ChipLogValueX64(peerId.GetNodeId()));
167+
mDeviceSyncInProcess = false;
168+
}
169+
170+
void DeviceSynchronizer::StartDeviceSynchronization(chip::Controller::DeviceController & controller, chip::NodeId nodeId,
171+
bool deviceIsIcd)
172+
{
173+
if (mDeviceSyncInProcess)
174+
{
175+
ChipLogError(NotSpecified, "Device Sync NOT POSSIBLE: another sync is in progress");
176+
return;
177+
}
178+
179+
mCurrentDeviceData = chip_rpc_SynchronizedDevice_init_default;
180+
mCurrentDeviceData.node_id = nodeId;
181+
mCurrentDeviceData.has_is_icd = true;
182+
mCurrentDeviceData.is_icd = deviceIsIcd;
183+
184+
mDeviceSyncInProcess = true;
185+
186+
controller.GetConnectedDevice(nodeId, &mOnDeviceConnectedCallback, &mOnDeviceConnectionFailureCallback);
187+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
* Copyright (c) 2024 Project CHIP Authors
3+
* All rights reserved.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*
17+
*/
18+
#pragma once
19+
20+
#include <app/ReadClient.h>
21+
#include <controller/CHIPDeviceController.h>
22+
#include <lib/core/DataModelTypes.h>
23+
24+
#include <memory>
25+
26+
#include "fabric_bridge_service/fabric_bridge_service.pb.h"
27+
#include "fabric_bridge_service/fabric_bridge_service.rpc.pb.h"
28+
29+
/// Ensures that device data is synchronized to the remove fabric bridge.
30+
///
31+
/// Includes a state machine that:
32+
/// - initiates a "read basic information data" command to fetch basic information
33+
/// - upon receiving such information, ensures that synchronized device data is sent
34+
/// to the remote end.
35+
class DeviceSynchronizer : public chip::app::ReadClient::Callback
36+
{
37+
public:
38+
DeviceSynchronizer();
39+
40+
/// Usually called after commissioning is complete, initiates a
41+
/// read of required data from the remote node ID and then will synchronize
42+
/// the device towards the fabric bridge
43+
void StartDeviceSynchronization(chip::Controller::DeviceController & controller, chip::NodeId nodeId, bool deviceIsIcd);
44+
45+
///////////////////////////////////////////////////////////////
46+
// ReadClient::Callback implementation
47+
///////////////////////////////////////////////////////////////
48+
void OnAttributeData(const chip::app::ConcreteDataAttributePath & path, chip::TLV::TLVReader * data,
49+
const chip::app::StatusIB & status) override;
50+
void OnReportEnd() override;
51+
void OnError(CHIP_ERROR error) override;
52+
void OnDone(chip::app::ReadClient * apReadClient) override;
53+
54+
///////////////////////////////////////////////////////////////
55+
// callbacks for CASE session establishment
56+
///////////////////////////////////////////////////////////////
57+
void OnDeviceConnected(chip::Messaging::ExchangeManager & exchangeMgr, const chip::SessionHandle & sessionHandle);
58+
void OnDeviceConnectionFailure(const chip::ScopedNodeId & peerId, CHIP_ERROR error);
59+
60+
static DeviceSynchronizer & Instance();
61+
62+
private:
63+
std::unique_ptr<chip::app::ReadClient> mClient;
64+
65+
chip::Callback::Callback<chip::OnDeviceConnected> mOnDeviceConnectedCallback;
66+
chip::Callback::Callback<chip::OnDeviceConnectionFailure> mOnDeviceConnectionFailureCallback;
67+
68+
bool mDeviceSyncInProcess = false;
69+
chip_rpc_SynchronizedDevice mCurrentDeviceData = chip_rpc_SynchronizedDevice_init_default;
70+
};

examples/fabric-admin/commands/pairing/PairingCommand.cpp

+4-4
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,10 @@
1818

1919
#include "PairingCommand.h"
2020

21+
#include <app-common/zap-generated/ids/Clusters.h>
2122
#include <commands/common/DeviceScanner.h>
23+
#include <commands/interactive/InteractiveCommands.h>
24+
#include <commands/pairing/DeviceSynchronization.h>
2225
#include <controller/ExampleOperationalCredentialsIssuer.h>
2326
#include <crypto/CHIPCryptoPAL.h>
2427
#include <lib/core/CHIPSafeCasts.h>
@@ -400,10 +403,7 @@ void PairingCommand::OnCommissioningComplete(NodeId nodeId, CHIP_ERROR err)
400403
{
401404
// print to console
402405
fprintf(stderr, "New device with Node ID: 0x%lx has been successfully added.\n", nodeId);
403-
404-
#if defined(PW_RPC_ENABLED)
405-
AddSynchronizedDevice(nodeId);
406-
#endif
406+
DeviceSynchronizer::Instance().StartDeviceSynchronization(CurrentCommissioner(), mNodeId, mDeviceIsICD);
407407
}
408408
else
409409
{

examples/fabric-admin/rpc/RpcClient.cpp

+3-41
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,9 @@
2222
#include <chrono>
2323
#include <condition_variable>
2424
#include <mutex>
25-
#include <string>
26-
#include <thread>
2725

26+
#include "fabric_bridge_service/fabric_bridge_service.pb.h"
2827
#include "fabric_bridge_service/fabric_bridge_service.rpc.pb.h"
29-
#include "pw_assert/check.h"
30-
#include "pw_hdlc/decoder.h"
31-
#include "pw_hdlc/default_addresses.h"
32-
#include "pw_hdlc/rpc_channel.h"
33-
#include "pw_rpc/client.h"
34-
#include "pw_stream/socket_stream.h"
3528

3629
using namespace chip;
3730

@@ -113,44 +106,13 @@ CHIP_ERROR InitRpcClient(uint16_t rpcServerPort)
113106
return rpc::client::StartPacketProcessing();
114107
}
115108

116-
CHIP_ERROR AddSynchronizedDevice(chip::NodeId nodeId)
109+
CHIP_ERROR AddSynchronizedDevice(const chip_rpc_SynchronizedDevice & data)
117110
{
118111
ChipLogProgress(NotSpecified, "AddSynchronizedDevice");
119112

120-
chip_rpc_SynchronizedDevice device = chip_rpc_SynchronizedDevice_init_default;
121-
device.node_id = nodeId;
122-
123-
// TODO: fill this with real data. For now we just add things for testing
124-
strcpy(device.vendor_name, "Test Vendor");
125-
device.has_vendor_name = true;
126-
127-
device.vendor_id = 123;
128-
device.has_vendor_id = true;
129-
130-
strcpy(device.product_name, "Test Product");
131-
device.has_product_name = true;
132-
133-
device.product_id = 234;
134-
device.has_product_id = true;
135-
136-
strcpy(device.node_label, "Device Label");
137-
device.has_node_label = true;
138-
139-
device.hardware_version = 11;
140-
device.has_hardware_version = true;
141-
142-
strcpy(device.hardware_version_string, "Hardware");
143-
device.has_hardware_version_string = true;
144-
145-
device.software_version = 22;
146-
device.has_software_version = true;
147-
148-
strcpy(device.software_version_string, "Test 1.4.22");
149-
device.has_software_version_string = true;
150-
151113
// The RPC call is kept alive until it completes. When a response is received, it will be logged by the handler
152114
// function and the call will complete.
153-
auto call = fabricBridgeClient.AddSynchronizedDevice(device, OnAddDeviceResponseCompleted);
115+
auto call = fabricBridgeClient.AddSynchronizedDevice(data, OnAddDeviceResponseCompleted);
154116

155117
if (!call.active())
156118
{

examples/fabric-admin/rpc/RpcClient.h

+3-2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020

2121
#include <platform/CHIPDeviceLayer.h>
2222

23+
#include "fabric_bridge_service/fabric_bridge_service.rpc.pb.h"
24+
2325
constexpr uint16_t kFabricBridgeServerPort = 33002;
2426

2527
/**
@@ -39,13 +41,12 @@ CHIP_ERROR InitRpcClient(uint16_t rpcServerPort);
3941
* It logs the progress and checks if an `AddSynchronizedDevice` operation is already in progress.
4042
* If an operation is in progress, it returns `CHIP_ERROR_BUSY`.
4143
*
42-
* @param nodeId The Node ID of the device to be added.
4344
* @return CHIP_ERROR An error code indicating the success or failure of the operation.
4445
* - CHIP_NO_ERROR: The RPC command was successfully processed.
4546
* - CHIP_ERROR_BUSY: Another operation is currently in progress.
4647
* - CHIP_ERROR_INTERNAL: An internal error occurred while activating the RPC call.
4748
*/
48-
CHIP_ERROR AddSynchronizedDevice(chip::NodeId nodeId);
49+
CHIP_ERROR AddSynchronizedDevice(const chip_rpc_SynchronizedDevice & data);
4950

5051
/**
5152
* @brief Removes a synchronized device from the RPC client.

0 commit comments

Comments
 (0)