Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FS Example] Update the FS Example apps to support fabric sync setup process part II #34990

Merged
merged 3 commits into from
Aug 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
chip.rpc.DeviceCommissioningWindowInfo.verifier max_size:97 // kSpake2p_VerifierSerialized_Length
yufengwangca marked this conversation as resolved.
Show resolved Hide resolved
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();
tehampson marked this conversation as resolved.
Show resolved Hide resolved
}

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);
tehampson marked this conversation as resolved.
Show resolved Hide resolved

DeviceMgr().PairRemoteDevice(nodeId, payloadBuffer);
tehampson marked this conversation as resolved.
Show resolved Hide resolved
}
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",
yufengwangca marked this conversation as resolved.
Show resolved Hide resolved
"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
Loading