Skip to content

Commit

Permalink
[FS Example] Update the FS Example apps to support fabric sync setup …
Browse files Browse the repository at this point in the history
…process part II (#34990)

* examples/fabric-bridge-app/linux/CommissionerControl.cpp

* Implement reverse commissioning

* Update function names to align with spec
  • Loading branch information
yufengwangca authored and pull[bot] committed Oct 24, 2024
1 parent 48a45cc commit 5530557
Show file tree
Hide file tree
Showing 16 changed files with 235 additions and 73 deletions.
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
chip.rpc.DeviceCommissioningWindowInfo.verifier max_size:97 // kSpake2p_VerifierSerialized_Length
chip.rpc.DeviceCommissioningWindowInfo.salt max_size:32 // kSpake2p_Max_PBKDF_Salt_Length
chip.rpc.DeviceCommissioningInfo.salt max_size:32 // kSpake2p_Max_PBKDF_Salt_Length
9 changes: 9 additions & 0 deletions examples/common/pigweed/protos/fabric_admin_service.proto
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@ message DeviceCommissioningWindowInfo {
bytes verifier = 6;
}

// Define the message for commissioning a device with necessary fields
message DeviceCommissioningInfo {
uint32 discriminator = 1;
uint32 iterations = 2;
uint32 setup_pin = 3;
bytes salt = 4;
}

message KeepActiveParameters {
uint64 node_id = 1;
uint32 stay_active_duration_ms = 2;
Expand All @@ -26,5 +34,6 @@ message OperationStatus {

service FabricAdmin {
rpc OpenCommissioningWindow(DeviceCommissioningWindowInfo) returns (OperationStatus){}
rpc CommissionNode(DeviceCommissioningInfo) returns (pw.protobuf.Empty){}
rpc KeepActive(KeepActiveParameters) returns (pw.protobuf.Empty){}
}
5 changes: 5 additions & 0 deletions examples/common/pigweed/rpc_services/FabricAdmin.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ class FabricAdmin : public pw_rpc::nanopb::FabricAdmin::Service<FabricAdmin>
return pw::Status::Unimplemented();
}

virtual pw::Status CommissionNode(const chip_rpc_DeviceCommissioningInfo & request, pw_protobuf_Empty & response)
{
return pw::Status::Unimplemented();
}

virtual pw::Status KeepActive(const chip_rpc_KeepActiveParameters & request, pw_protobuf_Empty & response)
{
return pw::Status::Unimplemented();
Expand Down
9 changes: 1 addition & 8 deletions examples/fabric-admin/commands/clusters/ClusterCommand.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,14 +84,7 @@ class ClusterCommand : public InteractionModelCommands, public ModelCommand, pub
if (data != nullptr)
{
LogErrorOnFailure(RemoteDataModelLogger::LogCommandAsJSON(path, data));

error = DataModelLogger::LogCommand(path, data);
if (CHIP_NO_ERROR != error)
{
ChipLogError(NotSpecified, "Response Failure: Can not decode Data");
mError = error;
return;
}
DeviceMgr().HandleCommandResponse(path, data);
}
}

Expand Down
107 changes: 75 additions & 32 deletions examples/fabric-admin/device_manager/DeviceManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,12 @@ void DeviceManager::Init()
NodeId DeviceManager::GetNextAvailableNodeId()
{
mLastUsedNodeId++;
VerifyOrDieWithMsg(mLastUsedNodeId < std::numeric_limits<chip::NodeId>::max(), NotSpecified, "No more available NodeIds.");
VerifyOrDieWithMsg(mLastUsedNodeId < std::numeric_limits<NodeId>::max(), NotSpecified, "No more available NodeIds.");

return mLastUsedNodeId;
}

void DeviceManager::UpdateLastUsedNodeId(chip::NodeId nodeId)
void DeviceManager::UpdateLastUsedNodeId(NodeId nodeId)
{
if (nodeId > mLastUsedNodeId)
{
Expand Down Expand Up @@ -159,7 +159,7 @@ void DeviceManager::PairRemoteFabricBridge(NodeId nodeId, const char * deviceRem
PushCommand(commandBuilder.c_str());
}

void DeviceManager::PairRemoteDevice(chip::NodeId nodeId, const char * payload)
void DeviceManager::PairRemoteDevice(NodeId nodeId, const char * payload)
{
StringBuilder<kMaxCommandSize> commandBuilder;

Expand Down Expand Up @@ -238,7 +238,7 @@ void DeviceManager::ReadSupportedDeviceCategories()
PushCommand(commandBuilder.c_str());
}

void DeviceManager::StartReverseCommissioning()
void DeviceManager::RequestCommissioningApproval()
{
ChipLogProgress(NotSpecified, "Starting reverse commissioning for bridge device: NodeId: " ChipLogFormatX64,
ChipLogValueX64(mRemoteBridgeNodeId));
Expand All @@ -255,7 +255,36 @@ void DeviceManager::StartReverseCommissioning()
PushCommand(commandBuilder.c_str());
}

void DeviceManager::CommissionApprovedRequest(uint64_t requestId, uint16_t responseTimeoutSeconds)
void DeviceManager::HandleCommissioningRequestResult(TLV::TLVReader * data)
{
ChipLogProgress(NotSpecified, "CommissioningRequestResult event received.");

CommissionerControl::Events::CommissioningRequestResult::DecodableType value;
CHIP_ERROR error = app::DataModel::Decode(*data, value);
if (error != CHIP_NO_ERROR)
{
ChipLogError(NotSpecified, "Failed to decode event value. Error: %" CHIP_ERROR_FORMAT, error.Format());
return;
}

if (value.requestId != mRequestId)
{
ChipLogError(NotSpecified, "The RequestId does not match the RequestId provided to RequestCommissioningApproval");
return;
}

if (value.statusCode != static_cast<uint8_t>(Protocols::InteractionModel::Status::Success))
{
ChipLogError(NotSpecified, "The server is not ready to begin commissioning the requested device");
return;
}

// The server is ready to begin commissioning the requested device, request the Commissioner Control Server to begin
// commissioning a previously approved request.
SendCommissionNodeRequest(value.requestId, kResponseTimeoutSeconds);
}

void DeviceManager::SendCommissionNodeRequest(uint64_t requestId, uint16_t responseTimeoutSeconds)
{
ChipLogProgress(NotSpecified, "Request the Commissioner Control Server to begin commissioning a previously approved request.");

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

void DeviceManager::HandleReverseOpenCommissioningWindow(TLV::TLVReader * data)
{
CommissionerControl::Commands::ReverseOpenCommissioningWindow::DecodableType value;
CHIP_ERROR error = app::DataModel::Decode(*data, value);
if (error != CHIP_NO_ERROR)
{
ChipLogError(NotSpecified, "Failed to decode command response value. Error: %" CHIP_ERROR_FORMAT, error.Format());
return;
}

// Log all fields
ChipLogProgress(NotSpecified, "DecodableType fields:");
ChipLogProgress(NotSpecified, " commissioningTimeout: %u", value.commissioningTimeout);
ChipLogProgress(NotSpecified, " discriminator: %u", value.discriminator);
ChipLogProgress(NotSpecified, " iterations: %u", value.iterations);

char verifierHex[Crypto::kSpake2p_VerifierSerialized_Length * 2 + 1];
Encoding::BytesToHex(value.PAKEPasscodeVerifier.data(), value.PAKEPasscodeVerifier.size(), verifierHex, sizeof(verifierHex),
Encoding::HexFlags::kNullTerminate);
ChipLogProgress(NotSpecified, " PAKEPasscodeVerifier: %s", verifierHex);

char saltHex[Crypto::kSpake2p_Max_PBKDF_Salt_Length * 2 + 1];
Encoding::BytesToHex(value.salt.data(), value.salt.size(), saltHex, sizeof(saltHex), Encoding::HexFlags::kNullTerminate);
ChipLogProgress(NotSpecified, " salt: %s", saltHex);

OpenDeviceCommissioningWindow(mLocalBridgeNodeId, value.commissioningTimeout, value.iterations, value.discriminator, saltHex,
verifierHex);
}

void DeviceManager::HandleAttributeData(const app::ConcreteDataAttributePath & path, TLV::TLVReader * data)
{
if (path.mClusterId == CommissionerControl::Id &&
Expand All @@ -284,7 +342,7 @@ void DeviceManager::HandleAttributeData(const app::ConcreteDataAttributePath & p
if (value.Has(CommissionerControl::SupportedDeviceCategoryBitmap::kFabricSynchronization))
{
ChipLogProgress(NotSpecified, "Remote Fabric-Bridge supports Fabric Synchronization, start reverse commissioning.");
StartReverseCommissioning();
RequestCommissioningApproval();
}

return;
Expand Down Expand Up @@ -399,39 +457,24 @@ void DeviceManager::HandleAttributeData(const app::ConcreteDataAttributePath & p
}
}

void DeviceManager::HandleEventData(const chip::app::EventHeader & header, chip::TLV::TLVReader * data)
void DeviceManager::HandleEventData(const app::EventHeader & header, TLV::TLVReader * data)
{
if (header.mPath.mClusterId != CommissionerControl::Id ||
header.mPath.mEventId != CommissionerControl::Events::CommissioningRequestResult::Id)
{
return;
}

ChipLogProgress(NotSpecified, "CommissioningRequestResult event received.");

CommissionerControl::Events::CommissioningRequestResult::DecodableType value;
CHIP_ERROR error = app::DataModel::Decode(*data, value);
if (error != CHIP_NO_ERROR)
if (header.mPath.mClusterId == CommissionerControl::Id &&
header.mPath.mEventId == CommissionerControl::Events::CommissioningRequestResult::Id)
{
ChipLogError(NotSpecified, "Failed to decode event value. Error: %" CHIP_ERROR_FORMAT, error.Format());
return;
HandleCommissioningRequestResult(data);
}
}

if (value.requestId != mRequestId)
{
ChipLogError(NotSpecified, "The RequestId does not match the RequestId provided to RequestCommissioningApproval");
return;
}
void DeviceManager::HandleCommandResponse(const app::ConcreteCommandPath & path, TLV::TLVReader * data)
{
ChipLogProgress(NotSpecified, "Command Response received.");

if (value.statusCode != static_cast<uint8_t>(Protocols::InteractionModel::Status::Success))
if (path.mClusterId == CommissionerControl::Id &&
path.mCommandId == CommissionerControl::Commands::ReverseOpenCommissioningWindow::Id)
{
ChipLogError(NotSpecified, "The server is not ready to begin commissioning the requested device");
return;
HandleReverseOpenCommissioningWindow(data);
}

// The server is ready to begin commissioning the requested device, request the Commissioner Control Server to begin
// commissioning a previously approved request.
CommissionApprovedRequest(value.requestId, kResponseTimeoutSeconds);
}

void DeviceManager::OnDeviceRemoved(NodeId deviceId, CHIP_ERROR err)
Expand Down
14 changes: 10 additions & 4 deletions examples/fabric-admin/device_manager/DeviceManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -148,21 +148,27 @@ class DeviceManager : public PairingDelegate

void SubscribeRemoteFabricBridge();

void StartReverseCommissioning();

void ReadSupportedDeviceCategories();

void CommissionApprovedRequest(uint64_t requestId, uint16_t responseTimeoutSeconds);

void HandleAttributeData(const chip::app::ConcreteDataAttributePath & path, chip::TLV::TLVReader * data);

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

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

void OnDeviceRemoved(chip::NodeId deviceId, CHIP_ERROR err) override;

private:
friend DeviceManager & DeviceMgr();

void RequestCommissioningApproval();

void HandleCommissioningRequestResult(chip::TLV::TLVReader * data);

void SendCommissionNodeRequest(uint64_t requestId, uint16_t responseTimeoutSeconds);

void HandleReverseOpenCommissioningWindow(chip::TLV::TLVReader * data);

static DeviceManager sInstance;

chip::NodeId mLastUsedNodeId = 0;
Expand Down
40 changes: 40 additions & 0 deletions examples/fabric-admin/rpc/RpcServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include <commands/fabric-sync/FabricSyncCommand.h>
#include <commands/interactive/InteractiveCommands.h>
#include <device_manager/DeviceManager.h>
#include <setup_payload/ManualSetupPayloadGenerator.h>
#include <system/SystemClock.h>

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

pw::Status CommissionNode(const chip_rpc_DeviceCommissioningInfo & request, pw_protobuf_Empty & response) override
{
char saltHex[Crypto::kSpake2p_Max_PBKDF_Salt_Length * 2 + 1];
Encoding::BytesToHex(request.salt.bytes, request.salt.size, saltHex, sizeof(saltHex), Encoding::HexFlags::kNullTerminate);

ChipLogProgress(NotSpecified, "Received CommissionNode request");

SetupPayload setupPayload = SetupPayload();

setupPayload.setUpPINCode = request.setup_pin;
setupPayload.version = 0;
setupPayload.rendezvousInformation.SetValue(RendezvousInformationFlag::kOnNetwork);

SetupDiscriminator discriminator{};
discriminator.SetLongValue(request.discriminator);
setupPayload.discriminator = discriminator;

char payloadBuffer[kMaxManualCodeLength + 1];
MutableCharSpan manualCode(payloadBuffer);

CHIP_ERROR error = ManualSetupPayloadGenerator(setupPayload).payloadDecimalStringRepresentation(manualCode);
if (error == CHIP_NO_ERROR)
{
NodeId nodeId = DeviceMgr().GetNextAvailableNodeId();

// After responding with RequestCommissioningApproval to the node where the client initiated the
// RequestCommissioningApproval, you need to wait for it to open a commissioning window on its bridge.
usleep(kCommissionPrepareTimeMs * 1000);

DeviceMgr().PairRemoteDevice(nodeId, payloadBuffer);
}
else
{
ChipLogError(NotSpecified, "Unable to generate manual code for setup payload: %" CHIP_ERROR_FORMAT, error.Format());
}

return pw::OkStatus();
}

pw::Status KeepActive(const chip_rpc_KeepActiveParameters & request, pw_protobuf_Empty & response) override
{
ChipLogProgress(NotSpecified, "Received KeepActive request: 0x%lx, %u", request.node_id, request.stay_active_duration_ms);
Expand Down
2 changes: 0 additions & 2 deletions examples/fabric-bridge-app/fabric-bridge-common/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,9 @@ source_set("fabric-bridge-lib") {
"include/BridgedDeviceBasicInformationImpl.h",
"include/BridgedDeviceManager.h",
"include/CHIPProjectAppConfig.h",
"include/CommissionerControl.h",
"src/BridgedDevice.cpp",
"src/BridgedDeviceBasicInformationImpl.cpp",
"src/BridgedDeviceManager.cpp",
"src/CommissionerControl.cpp",
"src/ZCLCallbacks.cpp",
]

Expand Down
1 change: 1 addition & 0 deletions examples/fabric-bridge-app/linux/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ if (bridge_enable_pw_rpc) {
executable("fabric-bridge-app") {
sources = [
"${chip_root}/examples/fabric-bridge-app/fabric-bridge-common/include/CHIPProjectAppConfig.h",
"CommissionerControl.cpp",
"main.cpp",
]

Expand Down
Loading

0 comments on commit 5530557

Please sign in to comment.