Skip to content

Commit d071ad0

Browse files
authored
Add new commissioned device as a synchronized device to Fabric Bridge (#33908)
1 parent 51e4846 commit d071ad0

File tree

6 files changed

+191
-27
lines changed

6 files changed

+191
-27
lines changed

examples/fabric-bridge-app/linux/Device.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,11 @@
2525

2626
using namespace chip::app::Clusters::Actions;
2727

28-
Device::Device(chip::NodeId nodeId, const char * name)
28+
Device::Device(chip::NodeId nodeId)
2929
{
30-
chip::Platform::CopyString(mName, name);
3130
mReachable = false;
32-
mEndpointId = 0;
31+
mNodeId = nodeId;
32+
mEndpointId = chip::kInvalidEndpointId;
3333
}
3434

3535
bool Device::IsReachable()

examples/fabric-bridge-app/linux/DeviceManager.cpp

+115-9
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,77 @@ using namespace chip::app::Clusters;
4646
namespace {
4747

4848
constexpr uint8_t kMaxRetries = 10;
49+
constexpr int kNodeLabelSize = 32;
50+
51+
// Current ZCL implementation of Struct uses a max-size array of 254 bytes
52+
constexpr int kDescriptorAttributeArraySize = 254;
53+
54+
// ENDPOINT DEFINITIONS:
55+
// =================================================================================
56+
//
57+
// Endpoint definitions will be reused across multiple endpoints for every instance of the
58+
// endpoint type.
59+
// There will be no intrinsic storage for the endpoint attributes declared here.
60+
// Instead, all attributes will be treated as EXTERNAL, and therefore all reads
61+
// or writes to the attributes must be handled within the emberAfExternalAttributeWriteCallback
62+
// and emberAfExternalAttributeReadCallback functions declared herein. This fits
63+
// the typical model of a bridge, since a bridge typically maintains its own
64+
// state database representing the devices connected to it.
65+
66+
// (taken from matter-devices.xml)
67+
#define DEVICE_TYPE_BRIDGED_NODE 0x0013
68+
69+
// Device Version for dynamic endpoints:
70+
#define DEVICE_VERSION_DEFAULT 1
71+
72+
// ---------------------------------------------------------------------------
73+
//
74+
// SYNCED DEVICE ENDPOINT: contains the following clusters:
75+
// - Descriptor
76+
// - Bridged Device Basic Information
77+
// - Administrator Commissioning
78+
79+
// Declare Descriptor cluster attributes
80+
DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(descriptorAttrs)
81+
DECLARE_DYNAMIC_ATTRIBUTE(Descriptor::Attributes::DeviceTypeList::Id, ARRAY, kDescriptorAttributeArraySize, 0), /* device list */
82+
DECLARE_DYNAMIC_ATTRIBUTE(Descriptor::Attributes::ServerList::Id, ARRAY, kDescriptorAttributeArraySize, 0), /* server list */
83+
DECLARE_DYNAMIC_ATTRIBUTE(Descriptor::Attributes::ClientList::Id, ARRAY, kDescriptorAttributeArraySize, 0), /* client list */
84+
DECLARE_DYNAMIC_ATTRIBUTE(Descriptor::Attributes::PartsList::Id, ARRAY, kDescriptorAttributeArraySize, 0), /* parts list */
85+
DECLARE_DYNAMIC_ATTRIBUTE_LIST_END();
86+
87+
// Declare Bridged Device Basic Information cluster attributes
88+
DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(bridgedDeviceBasicAttrs)
89+
DECLARE_DYNAMIC_ATTRIBUTE(BridgedDeviceBasicInformation::Attributes::NodeLabel::Id, CHAR_STRING, kNodeLabelSize, 0), /* NodeLabel */
90+
DECLARE_DYNAMIC_ATTRIBUTE(BridgedDeviceBasicInformation::Attributes::Reachable::Id, BOOLEAN, 1, 0), /* Reachable */
91+
DECLARE_DYNAMIC_ATTRIBUTE(BridgedDeviceBasicInformation::Attributes::FeatureMap::Id, BITMAP32, 4, 0), /* feature map */
92+
DECLARE_DYNAMIC_ATTRIBUTE_LIST_END();
93+
94+
// Declare Administrator Commissioning cluster attributes
95+
DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(AdministratorCommissioningAttrs)
96+
DECLARE_DYNAMIC_ATTRIBUTE(AdministratorCommissioning::Attributes::WindowStatus::Id, ENUM8, 1, 0), /* NodeLabel */
97+
DECLARE_DYNAMIC_ATTRIBUTE(AdministratorCommissioning::Attributes::AdminFabricIndex::Id, FABRIC_IDX, 1, 0), /* Reachable */
98+
DECLARE_DYNAMIC_ATTRIBUTE(AdministratorCommissioning::Attributes::AdminVendorId::Id, VENDOR_ID, 2, 0), /* Reachable */
99+
DECLARE_DYNAMIC_ATTRIBUTE_LIST_END();
100+
101+
constexpr CommandId administratorCommissioningCommands[] = {
102+
app::Clusters::AdministratorCommissioning::Commands::OpenCommissioningWindow::Id,
103+
app::Clusters::AdministratorCommissioning::Commands::OpenBasicCommissioningWindow::Id,
104+
app::Clusters::AdministratorCommissioning::Commands::RevokeCommissioning::Id,
105+
kInvalidCommandId,
106+
};
107+
108+
// Declare Cluster List for Bridged Node endpoint
109+
DECLARE_DYNAMIC_CLUSTER_LIST_BEGIN(bridgedNodeClusters)
110+
DECLARE_DYNAMIC_CLUSTER(Descriptor::Id, descriptorAttrs, ZAP_CLUSTER_MASK(SERVER), nullptr, nullptr),
111+
DECLARE_DYNAMIC_CLUSTER(BridgedDeviceBasicInformation::Id, bridgedDeviceBasicAttrs, ZAP_CLUSTER_MASK(SERVER), nullptr, nullptr),
112+
DECLARE_DYNAMIC_CLUSTER(AdministratorCommissioning::Id, AdministratorCommissioningAttrs, ZAP_CLUSTER_MASK(SERVER),
113+
administratorCommissioningCommands, nullptr) DECLARE_DYNAMIC_CLUSTER_LIST_END;
114+
115+
// Declare Bridged Node endpoint
116+
DECLARE_DYNAMIC_ENDPOINT(sBridgedNodeEndpoint, bridgedNodeClusters);
117+
DataVersion sBridgedNodeDataVersions[ArraySize(bridgedNodeClusters)];
118+
119+
const EmberAfDeviceType sBridgedDeviceTypes[] = { { DEVICE_TYPE_BRIDGED_NODE, DEVICE_VERSION_DEFAULT } };
49120

50121
} // namespace
51122

@@ -60,11 +131,13 @@ void DeviceManager::Init()
60131
mCurrentEndpointId = mFirstDynamicEndpointId;
61132
}
62133

63-
int DeviceManager::AddDeviceEndpoint(Device * dev, EmberAfEndpointType * ep,
64-
const chip::Span<const EmberAfDeviceType> & deviceTypeList,
65-
const chip::Span<chip::DataVersion> & dataVersionStorage, chip::EndpointId parentEndpointId)
134+
int DeviceManager::AddDeviceEndpoint(Device * dev, chip::EndpointId parentEndpointId)
66135
{
67-
uint8_t index = 0;
136+
uint8_t index = 0;
137+
EmberAfEndpointType * ep = &sBridgedNodeEndpoint;
138+
const chip::Span<const EmberAfDeviceType> & deviceTypeList = Span<const EmberAfDeviceType>(sBridgedDeviceTypes);
139+
const chip::Span<chip::DataVersion> & dataVersionStorage = Span<DataVersion>(sBridgedNodeDataVersions);
140+
68141
while (index < CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT)
69142
{
70143
if (nullptr == mDevices[index])
@@ -81,8 +154,9 @@ int DeviceManager::AddDeviceEndpoint(Device * dev, EmberAfEndpointType * ep,
81154
emberAfSetDynamicEndpoint(index, mCurrentEndpointId, ep, dataVersionStorage, deviceTypeList, parentEndpointId);
82155
if (err == CHIP_NO_ERROR)
83156
{
84-
ChipLogProgress(NotSpecified, "Added device %s to dynamic endpoint %d (index=%d)", dev->GetName(),
85-
mCurrentEndpointId, index);
157+
ChipLogProgress(NotSpecified,
158+
"Added device with nodeId=0x" ChipLogFormatX64 " to dynamic endpoint %d (index=%d)",
159+
ChipLogValueX64(dev->GetNodeId()), mCurrentEndpointId, index);
86160
return index;
87161
}
88162
if (err != CHIP_ERROR_ENDPOINT_EXISTS)
@@ -125,11 +199,43 @@ int DeviceManager::RemoveDeviceEndpoint(Device * dev)
125199
return -1;
126200
}
127201

128-
Device * DeviceManager::GetDevice(uint16_t index) const
202+
Device * DeviceManager::GetDevice(chip::EndpointId endpointId) const
203+
{
204+
for (uint8_t index = 0; index < CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT; ++index)
205+
{
206+
if (mDevices[index] && mDevices[index]->GetEndpointId() == endpointId)
207+
{
208+
return mDevices[index];
209+
}
210+
}
211+
return nullptr;
212+
}
213+
214+
Device * DeviceManager::GetDeviceByNodeId(chip::NodeId nodeId) const
129215
{
130-
if (index < CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT)
216+
for (uint8_t index = 0; index < CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT; ++index)
131217
{
132-
return mDevices[index];
218+
if (mDevices[index] && mDevices[index]->GetNodeId() == nodeId)
219+
{
220+
return mDevices[index];
221+
}
133222
}
134223
return nullptr;
135224
}
225+
226+
int DeviceManager::RemoveDeviceByNodeId(chip::NodeId nodeId)
227+
{
228+
for (uint8_t index = 0; index < CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT; ++index)
229+
{
230+
if (mDevices[index] && mDevices[index]->GetNodeId() == nodeId)
231+
{
232+
DeviceLayer::StackLock lock;
233+
EndpointId ep = emberAfClearDynamicEndpoint(index);
234+
mDevices[index] = nullptr;
235+
ChipLogProgress(NotSpecified, "Removed device with NodeId=0x" ChipLogFormatX64 " from dynamic endpoint %d (index=%d)",
236+
ChipLogValueX64(nodeId), ep, index);
237+
return index;
238+
}
239+
}
240+
return -1;
241+
}

examples/fabric-bridge-app/linux/RpcClient.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ CHIP_ERROR InitRpcClient(uint16_t rpcServerPort)
6565

6666
CHIP_ERROR OpenCommissioningWindow(NodeId nodeId)
6767
{
68-
ChipLogProgress(NotSpecified, "OpenCommissioningWindow\n");
68+
ChipLogProgress(NotSpecified, "OpenCommissioningWindow with Node Id 0x:" ChipLogFormatX64, ChipLogValueX64(nodeId));
6969

7070
if (openCommissioningWindowCall.active())
7171
{

examples/fabric-bridge-app/linux/RpcServer.cpp

+29-6
Original file line numberDiff line numberDiff line change
@@ -20,26 +20,49 @@
2020
#include "pw_rpc_system_server/rpc_server.h"
2121
#include "pw_rpc_system_server/socket.h"
2222

23-
#include <system/SystemClock.h>
23+
#include <lib/core/CHIPError.h>
24+
25+
#include <string>
2426
#include <thread>
2527

2628
#if defined(PW_RPC_FABRIC_BRIDGE_SERVICE) && PW_RPC_FABRIC_BRIDGE_SERVICE
2729
#include "pigweed/rpc_services/FabricBridge.h"
2830
#endif
2931

32+
#include "Device.h"
33+
#include "DeviceManager.h"
34+
35+
using namespace chip;
36+
using namespace chip::app;
37+
using namespace chip::app::Clusters;
38+
3039
namespace {
3140

3241
#if defined(PW_RPC_FABRIC_BRIDGE_SERVICE) && PW_RPC_FABRIC_BRIDGE_SERVICE
3342
class FabricBridge final : public chip::rpc::FabricBridge
3443
{
3544
public:
36-
pw::Status AddSynchronizedDevice(const chip_rpc_SynchronizedDevice & request, pw_protobuf_Empty & response) override
45+
pw::Status AddSynchronizedDevice(const chip_rpc_SynchronizedDevice & request, pw_protobuf_Empty & response) override;
46+
};
47+
48+
pw::Status FabricBridge::AddSynchronizedDevice(const chip_rpc_SynchronizedDevice & request, pw_protobuf_Empty & response)
49+
{
50+
NodeId nodeId = request.node_id;
51+
ChipLogProgress(NotSpecified, "Received AddSynchronizedDevice: " ChipLogFormatX64, ChipLogValueX64(nodeId));
52+
53+
Device * device = new Device(nodeId);
54+
device->SetReachable(true);
55+
56+
int result = DeviceMgr().AddDeviceEndpoint(device, 1);
57+
if (result == -1)
3758
{
38-
chip::NodeId nodeId = request.node_id;
39-
ChipLogProgress(NotSpecified, "Received AddSynchronizedDevice: " ChipLogFormatX64, ChipLogValueX64(nodeId));
40-
return pw::OkStatus();
59+
delete device;
60+
ChipLogError(NotSpecified, "Failed to add device with nodeId=0x" ChipLogFormatX64, ChipLogValueX64(nodeId));
61+
return pw::Status::Unknown();
4162
}
42-
};
63+
64+
return pw::OkStatus();
65+
}
4366

4467
FabricBridge fabric_bridge_service;
4568
#endif // defined(PW_RPC_FABRIC_BRIDGE_SERVICE) && PW_RPC_FABRIC_BRIDGE_SERVICE

examples/fabric-bridge-app/linux/include/Device.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ class Device
3232
public:
3333
static const int kDeviceNameSize = 32;
3434

35-
Device(chip::NodeId nodeId, const char * name);
35+
Device(chip::NodeId nodeId);
3636
virtual ~Device() {}
3737

3838
bool IsReachable();
@@ -41,6 +41,7 @@ class Device
4141
void SetLocation(std::string location) { mLocation = location; };
4242
inline void SetEndpointId(chip::EndpointId id) { mEndpointId = id; };
4343
inline chip::EndpointId GetEndpointId() { return mEndpointId; };
44+
inline chip::NodeId GetNodeId() { return mNodeId; };
4445
inline void SetParentEndpointId(chip::EndpointId id) { mParentEndpointId = id; };
4546
inline chip::EndpointId GetParentEndpointId() { return mParentEndpointId; };
4647
inline char * GetName() { return mName; };

examples/fabric-bridge-app/linux/include/DeviceManager.h

+41-7
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,12 @@ class DeviceManager
2727
public:
2828
DeviceManager() = default;
2929

30+
/**
31+
* @brief Initializes the DeviceManager.
32+
*
33+
* This function sets up the initial state of the DeviceManager, clearing
34+
* any existing devices and setting the starting dynamic endpoint ID.
35+
*/
3036
void Init();
3137

3238
/**
@@ -38,15 +44,10 @@ class DeviceManager
3844
* dynamic endpoint; otherwise, it returns -1.
3945
*
4046
* @param dev A pointer to the device to be added.
41-
* @param ep A pointer to the endpoint type.
42-
* @param deviceTypeList A span containing the list of device types.
43-
* @param dataVersionStorage A span containing the data version storage.
4447
* @param parentEndpointId The parent endpoint ID. Defaults to an invalid endpoint ID.
4548
* @return int The index of the dynamic endpoint if successful, -1 otherwise.
4649
*/
47-
int AddDeviceEndpoint(Device * dev, EmberAfEndpointType * ep, const chip::Span<const EmberAfDeviceType> & deviceTypeList,
48-
const chip::Span<chip::DataVersion> & dataVersionStorage,
49-
chip::EndpointId parentEndpointId = chip::kInvalidEndpointId);
50+
int AddDeviceEndpoint(Device * dev, chip::EndpointId parentEndpointId = chip::kInvalidEndpointId);
5051

5152
/**
5253
* @brief Removes a device from a dynamic endpoint.
@@ -61,7 +62,40 @@ class DeviceManager
6162
*/
6263
int RemoveDeviceEndpoint(Device * dev);
6364

64-
Device * GetDevice(uint16_t index) const;
65+
/**
66+
* @brief Gets a device from its endpoint ID.
67+
*
68+
* This function iterates through the available devices and returns the device that matches the
69+
* specified endpoint ID. If no device matches the endpoint ID, it returns nullptr.
70+
*
71+
* @param endpointId The endpoint ID of the device to be retrieved.
72+
* @return Device* A pointer to the device if found, nullptr otherwise.
73+
*/
74+
Device * GetDevice(chip::EndpointId endpointId) const;
75+
76+
/**
77+
* @brief Gets a device from its NodeId.
78+
*
79+
* This function iterates through the available devices and returns the device that matches the
80+
* specified NodeId. If no device matches the NodeId, it returns nullptr.
81+
*
82+
* @param nodeId The NodeId of the device to be retrieved.
83+
* @return Device* A pointer to the device if found, nullptr otherwise.
84+
*/
85+
Device * GetDeviceByNodeId(chip::NodeId nodeId) const;
86+
87+
/**
88+
* @brief Removes a device from a dynamic endpoint by its NodeId.
89+
*
90+
* This function attempts to remove a device from a dynamic endpoint by iterating through the
91+
* available endpoints and checking if the device matches the specified NodeId. If the device is
92+
* found, it clears the dynamic endpoint, logs the removal, and returns the index of the removed
93+
* endpoint. If the device is not found, it returns -1.
94+
*
95+
* @param nodeId The NodeId of the device to be removed.
96+
* @return int The index of the removed dynamic endpoint if successful, -1 otherwise.
97+
*/
98+
int RemoveDeviceByNodeId(chip::NodeId nodeId);
6599

66100
private:
67101
friend DeviceManager & DeviceMgr();

0 commit comments

Comments
 (0)