Skip to content

Commit e0a4e79

Browse files
authored
[FS Example] Update the FS Example apps to support fabric sync setup process part II (#34990)
* examples/fabric-bridge-app/linux/CommissionerControl.cpp * Implement reverse commissioning * Update function names to align with spec
1 parent 4e6847d commit e0a4e79

File tree

16 files changed

+235
-73
lines changed

16 files changed

+235
-73
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
chip.rpc.DeviceCommissioningWindowInfo.verifier max_size:97 // kSpake2p_VerifierSerialized_Length
22
chip.rpc.DeviceCommissioningWindowInfo.salt max_size:32 // kSpake2p_Max_PBKDF_Salt_Length
3+
chip.rpc.DeviceCommissioningInfo.salt max_size:32 // kSpake2p_Max_PBKDF_Salt_Length

examples/common/pigweed/protos/fabric_admin_service.proto

+9
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,14 @@ message DeviceCommissioningWindowInfo {
1414
bytes verifier = 6;
1515
}
1616

17+
// Define the message for commissioning a device with necessary fields
18+
message DeviceCommissioningInfo {
19+
uint32 discriminator = 1;
20+
uint32 iterations = 2;
21+
uint32 setup_pin = 3;
22+
bytes salt = 4;
23+
}
24+
1725
message KeepActiveParameters {
1826
uint64 node_id = 1;
1927
uint32 stay_active_duration_ms = 2;
@@ -26,5 +34,6 @@ message OperationStatus {
2634

2735
service FabricAdmin {
2836
rpc OpenCommissioningWindow(DeviceCommissioningWindowInfo) returns (OperationStatus){}
37+
rpc CommissionNode(DeviceCommissioningInfo) returns (pw.protobuf.Empty){}
2938
rpc KeepActive(KeepActiveParameters) returns (pw.protobuf.Empty){}
3039
}

examples/common/pigweed/rpc_services/FabricAdmin.h

+5
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@ class FabricAdmin : public pw_rpc::nanopb::FabricAdmin::Service<FabricAdmin>
4040
return pw::Status::Unimplemented();
4141
}
4242

43+
virtual pw::Status CommissionNode(const chip_rpc_DeviceCommissioningInfo & request, pw_protobuf_Empty & response)
44+
{
45+
return pw::Status::Unimplemented();
46+
}
47+
4348
virtual pw::Status KeepActive(const chip_rpc_KeepActiveParameters & request, pw_protobuf_Empty & response)
4449
{
4550
return pw::Status::Unimplemented();

examples/fabric-admin/commands/clusters/ClusterCommand.h

+1-8
Original file line numberDiff line numberDiff line change
@@ -84,14 +84,7 @@ class ClusterCommand : public InteractionModelCommands, public ModelCommand, pub
8484
if (data != nullptr)
8585
{
8686
LogErrorOnFailure(RemoteDataModelLogger::LogCommandAsJSON(path, data));
87-
88-
error = DataModelLogger::LogCommand(path, data);
89-
if (CHIP_NO_ERROR != error)
90-
{
91-
ChipLogError(NotSpecified, "Response Failure: Can not decode Data");
92-
mError = error;
93-
return;
94-
}
87+
DeviceMgr().HandleCommandResponse(path, data);
9588
}
9689
}
9790

examples/fabric-admin/device_manager/DeviceManager.cpp

+75-32
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,12 @@ void DeviceManager::Init()
5656
NodeId DeviceManager::GetNextAvailableNodeId()
5757
{
5858
mLastUsedNodeId++;
59-
VerifyOrDieWithMsg(mLastUsedNodeId < std::numeric_limits<chip::NodeId>::max(), NotSpecified, "No more available NodeIds.");
59+
VerifyOrDieWithMsg(mLastUsedNodeId < std::numeric_limits<NodeId>::max(), NotSpecified, "No more available NodeIds.");
6060

6161
return mLastUsedNodeId;
6262
}
6363

64-
void DeviceManager::UpdateLastUsedNodeId(chip::NodeId nodeId)
64+
void DeviceManager::UpdateLastUsedNodeId(NodeId nodeId)
6565
{
6666
if (nodeId > mLastUsedNodeId)
6767
{
@@ -159,7 +159,7 @@ void DeviceManager::PairRemoteFabricBridge(NodeId nodeId, const char * deviceRem
159159
PushCommand(commandBuilder.c_str());
160160
}
161161

162-
void DeviceManager::PairRemoteDevice(chip::NodeId nodeId, const char * payload)
162+
void DeviceManager::PairRemoteDevice(NodeId nodeId, const char * payload)
163163
{
164164
StringBuilder<kMaxCommandSize> commandBuilder;
165165

@@ -238,7 +238,7 @@ void DeviceManager::ReadSupportedDeviceCategories()
238238
PushCommand(commandBuilder.c_str());
239239
}
240240

241-
void DeviceManager::StartReverseCommissioning()
241+
void DeviceManager::RequestCommissioningApproval()
242242
{
243243
ChipLogProgress(NotSpecified, "Starting reverse commissioning for bridge device: NodeId: " ChipLogFormatX64,
244244
ChipLogValueX64(mRemoteBridgeNodeId));
@@ -255,7 +255,36 @@ void DeviceManager::StartReverseCommissioning()
255255
PushCommand(commandBuilder.c_str());
256256
}
257257

258-
void DeviceManager::CommissionApprovedRequest(uint64_t requestId, uint16_t responseTimeoutSeconds)
258+
void DeviceManager::HandleCommissioningRequestResult(TLV::TLVReader * data)
259+
{
260+
ChipLogProgress(NotSpecified, "CommissioningRequestResult event received.");
261+
262+
CommissionerControl::Events::CommissioningRequestResult::DecodableType value;
263+
CHIP_ERROR error = app::DataModel::Decode(*data, value);
264+
if (error != CHIP_NO_ERROR)
265+
{
266+
ChipLogError(NotSpecified, "Failed to decode event value. Error: %" CHIP_ERROR_FORMAT, error.Format());
267+
return;
268+
}
269+
270+
if (value.requestId != mRequestId)
271+
{
272+
ChipLogError(NotSpecified, "The RequestId does not match the RequestId provided to RequestCommissioningApproval");
273+
return;
274+
}
275+
276+
if (value.statusCode != static_cast<uint8_t>(Protocols::InteractionModel::Status::Success))
277+
{
278+
ChipLogError(NotSpecified, "The server is not ready to begin commissioning the requested device");
279+
return;
280+
}
281+
282+
// The server is ready to begin commissioning the requested device, request the Commissioner Control Server to begin
283+
// commissioning a previously approved request.
284+
SendCommissionNodeRequest(value.requestId, kResponseTimeoutSeconds);
285+
}
286+
287+
void DeviceManager::SendCommissionNodeRequest(uint64_t requestId, uint16_t responseTimeoutSeconds)
259288
{
260289
ChipLogProgress(NotSpecified, "Request the Commissioner Control Server to begin commissioning a previously approved request.");
261290

@@ -266,6 +295,35 @@ void DeviceManager::CommissionApprovedRequest(uint64_t requestId, uint16_t respo
266295
PushCommand(commandBuilder.c_str());
267296
}
268297

298+
void DeviceManager::HandleReverseOpenCommissioningWindow(TLV::TLVReader * data)
299+
{
300+
CommissionerControl::Commands::ReverseOpenCommissioningWindow::DecodableType value;
301+
CHIP_ERROR error = app::DataModel::Decode(*data, value);
302+
if (error != CHIP_NO_ERROR)
303+
{
304+
ChipLogError(NotSpecified, "Failed to decode command response value. Error: %" CHIP_ERROR_FORMAT, error.Format());
305+
return;
306+
}
307+
308+
// Log all fields
309+
ChipLogProgress(NotSpecified, "DecodableType fields:");
310+
ChipLogProgress(NotSpecified, " commissioningTimeout: %u", value.commissioningTimeout);
311+
ChipLogProgress(NotSpecified, " discriminator: %u", value.discriminator);
312+
ChipLogProgress(NotSpecified, " iterations: %u", value.iterations);
313+
314+
char verifierHex[Crypto::kSpake2p_VerifierSerialized_Length * 2 + 1];
315+
Encoding::BytesToHex(value.PAKEPasscodeVerifier.data(), value.PAKEPasscodeVerifier.size(), verifierHex, sizeof(verifierHex),
316+
Encoding::HexFlags::kNullTerminate);
317+
ChipLogProgress(NotSpecified, " PAKEPasscodeVerifier: %s", verifierHex);
318+
319+
char saltHex[Crypto::kSpake2p_Max_PBKDF_Salt_Length * 2 + 1];
320+
Encoding::BytesToHex(value.salt.data(), value.salt.size(), saltHex, sizeof(saltHex), Encoding::HexFlags::kNullTerminate);
321+
ChipLogProgress(NotSpecified, " salt: %s", saltHex);
322+
323+
OpenDeviceCommissioningWindow(mLocalBridgeNodeId, value.commissioningTimeout, value.iterations, value.discriminator, saltHex,
324+
verifierHex);
325+
}
326+
269327
void DeviceManager::HandleAttributeData(const app::ConcreteDataAttributePath & path, TLV::TLVReader * data)
270328
{
271329
if (path.mClusterId == CommissionerControl::Id &&
@@ -284,7 +342,7 @@ void DeviceManager::HandleAttributeData(const app::ConcreteDataAttributePath & p
284342
if (value.Has(CommissionerControl::SupportedDeviceCategoryBitmap::kFabricSynchronization))
285343
{
286344
ChipLogProgress(NotSpecified, "Remote Fabric-Bridge supports Fabric Synchronization, start reverse commissioning.");
287-
StartReverseCommissioning();
345+
RequestCommissioningApproval();
288346
}
289347

290348
return;
@@ -399,39 +457,24 @@ void DeviceManager::HandleAttributeData(const app::ConcreteDataAttributePath & p
399457
}
400458
}
401459

402-
void DeviceManager::HandleEventData(const chip::app::EventHeader & header, chip::TLV::TLVReader * data)
460+
void DeviceManager::HandleEventData(const app::EventHeader & header, TLV::TLVReader * data)
403461
{
404-
if (header.mPath.mClusterId != CommissionerControl::Id ||
405-
header.mPath.mEventId != CommissionerControl::Events::CommissioningRequestResult::Id)
406-
{
407-
return;
408-
}
409-
410-
ChipLogProgress(NotSpecified, "CommissioningRequestResult event received.");
411-
412-
CommissionerControl::Events::CommissioningRequestResult::DecodableType value;
413-
CHIP_ERROR error = app::DataModel::Decode(*data, value);
414-
if (error != CHIP_NO_ERROR)
462+
if (header.mPath.mClusterId == CommissionerControl::Id &&
463+
header.mPath.mEventId == CommissionerControl::Events::CommissioningRequestResult::Id)
415464
{
416-
ChipLogError(NotSpecified, "Failed to decode event value. Error: %" CHIP_ERROR_FORMAT, error.Format());
417-
return;
465+
HandleCommissioningRequestResult(data);
418466
}
467+
}
419468

420-
if (value.requestId != mRequestId)
421-
{
422-
ChipLogError(NotSpecified, "The RequestId does not match the RequestId provided to RequestCommissioningApproval");
423-
return;
424-
}
469+
void DeviceManager::HandleCommandResponse(const app::ConcreteCommandPath & path, TLV::TLVReader * data)
470+
{
471+
ChipLogProgress(NotSpecified, "Command Response received.");
425472

426-
if (value.statusCode != static_cast<uint8_t>(Protocols::InteractionModel::Status::Success))
473+
if (path.mClusterId == CommissionerControl::Id &&
474+
path.mCommandId == CommissionerControl::Commands::ReverseOpenCommissioningWindow::Id)
427475
{
428-
ChipLogError(NotSpecified, "The server is not ready to begin commissioning the requested device");
429-
return;
476+
HandleReverseOpenCommissioningWindow(data);
430477
}
431-
432-
// The server is ready to begin commissioning the requested device, request the Commissioner Control Server to begin
433-
// commissioning a previously approved request.
434-
CommissionApprovedRequest(value.requestId, kResponseTimeoutSeconds);
435478
}
436479

437480
void DeviceManager::OnDeviceRemoved(NodeId deviceId, CHIP_ERROR err)

examples/fabric-admin/device_manager/DeviceManager.h

+10-4
Original file line numberDiff line numberDiff line change
@@ -148,21 +148,27 @@ class DeviceManager : public PairingDelegate
148148

149149
void SubscribeRemoteFabricBridge();
150150

151-
void StartReverseCommissioning();
152-
153151
void ReadSupportedDeviceCategories();
154152

155-
void CommissionApprovedRequest(uint64_t requestId, uint16_t responseTimeoutSeconds);
156-
157153
void HandleAttributeData(const chip::app::ConcreteDataAttributePath & path, chip::TLV::TLVReader * data);
158154

159155
void HandleEventData(const chip::app::EventHeader & header, chip::TLV::TLVReader * data);
160156

157+
void HandleCommandResponse(const chip::app::ConcreteCommandPath & path, chip::TLV::TLVReader * data);
158+
161159
void OnDeviceRemoved(chip::NodeId deviceId, CHIP_ERROR err) override;
162160

163161
private:
164162
friend DeviceManager & DeviceMgr();
165163

164+
void RequestCommissioningApproval();
165+
166+
void HandleCommissioningRequestResult(chip::TLV::TLVReader * data);
167+
168+
void SendCommissionNodeRequest(uint64_t requestId, uint16_t responseTimeoutSeconds);
169+
170+
void HandleReverseOpenCommissioningWindow(chip::TLV::TLVReader * data);
171+
166172
static DeviceManager sInstance;
167173

168174
chip::NodeId mLastUsedNodeId = 0;

examples/fabric-admin/rpc/RpcServer.cpp

+40
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include <commands/fabric-sync/FabricSyncCommand.h>
3030
#include <commands/interactive/InteractiveCommands.h>
3131
#include <device_manager/DeviceManager.h>
32+
#include <setup_payload/ManualSetupPayloadGenerator.h>
3233
#include <system/SystemClock.h>
3334

3435
#if defined(PW_RPC_FABRIC_ADMIN_SERVICE) && PW_RPC_FABRIC_ADMIN_SERVICE
@@ -91,6 +92,45 @@ class FabricAdmin final : public rpc::FabricAdmin, public IcdManager::Delegate
9192
return pw::OkStatus();
9293
}
9394

95+
pw::Status CommissionNode(const chip_rpc_DeviceCommissioningInfo & request, pw_protobuf_Empty & response) override
96+
{
97+
char saltHex[Crypto::kSpake2p_Max_PBKDF_Salt_Length * 2 + 1];
98+
Encoding::BytesToHex(request.salt.bytes, request.salt.size, saltHex, sizeof(saltHex), Encoding::HexFlags::kNullTerminate);
99+
100+
ChipLogProgress(NotSpecified, "Received CommissionNode request");
101+
102+
SetupPayload setupPayload = SetupPayload();
103+
104+
setupPayload.setUpPINCode = request.setup_pin;
105+
setupPayload.version = 0;
106+
setupPayload.rendezvousInformation.SetValue(RendezvousInformationFlag::kOnNetwork);
107+
108+
SetupDiscriminator discriminator{};
109+
discriminator.SetLongValue(request.discriminator);
110+
setupPayload.discriminator = discriminator;
111+
112+
char payloadBuffer[kMaxManualCodeLength + 1];
113+
MutableCharSpan manualCode(payloadBuffer);
114+
115+
CHIP_ERROR error = ManualSetupPayloadGenerator(setupPayload).payloadDecimalStringRepresentation(manualCode);
116+
if (error == CHIP_NO_ERROR)
117+
{
118+
NodeId nodeId = DeviceMgr().GetNextAvailableNodeId();
119+
120+
// After responding with RequestCommissioningApproval to the node where the client initiated the
121+
// RequestCommissioningApproval, you need to wait for it to open a commissioning window on its bridge.
122+
usleep(kCommissionPrepareTimeMs * 1000);
123+
124+
DeviceMgr().PairRemoteDevice(nodeId, payloadBuffer);
125+
}
126+
else
127+
{
128+
ChipLogError(NotSpecified, "Unable to generate manual code for setup payload: %" CHIP_ERROR_FORMAT, error.Format());
129+
}
130+
131+
return pw::OkStatus();
132+
}
133+
94134
pw::Status KeepActive(const chip_rpc_KeepActiveParameters & request, pw_protobuf_Empty & response) override
95135
{
96136
ChipLogProgress(NotSpecified, "Received KeepActive request: 0x%lx, %u", request.node_id, request.stay_active_duration_ms);

examples/fabric-bridge-app/fabric-bridge-common/BUILD.gn

-2
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,9 @@ source_set("fabric-bridge-lib") {
4545
"include/BridgedDeviceBasicInformationImpl.h",
4646
"include/BridgedDeviceManager.h",
4747
"include/CHIPProjectAppConfig.h",
48-
"include/CommissionerControl.h",
4948
"src/BridgedDevice.cpp",
5049
"src/BridgedDeviceBasicInformationImpl.cpp",
5150
"src/BridgedDeviceManager.cpp",
52-
"src/CommissionerControl.cpp",
5351
"src/ZCLCallbacks.cpp",
5452
]
5553

examples/fabric-bridge-app/linux/BUILD.gn

+1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ if (bridge_enable_pw_rpc) {
3333
executable("fabric-bridge-app") {
3434
sources = [
3535
"${chip_root}/examples/fabric-bridge-app/fabric-bridge-common/include/CHIPProjectAppConfig.h",
36+
"CommissionerControl.cpp",
3637
"main.cpp",
3738
]
3839

0 commit comments

Comments
 (0)