blob: 6a7b5be05bb3bd03b4dea2df684a59fce1c8a6de [file] [log] [blame]
/*
* Copyright (c) 2024 Project CHIP Authors
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include "FabricSyncCommand.h"
#include <commands/common/RemoteDataModelLogger.h>
#include <commands/interactive/InteractiveCommands.h>
#include <device_manager/DeviceManager.h>
#include <setup_payload/ManualSetupPayloadGenerator.h>
#include <thread>
#include <unistd.h>
#if defined(PW_RPC_ENABLED)
#include <rpc/RpcClient.h>
#endif
using namespace ::chip;
namespace {
void CheckFabricBridgeSynchronizationSupport(intptr_t ignored)
{
DeviceMgr().ReadSupportedDeviceCategories();
}
} // namespace
void FabricSyncAddBridgeCommand::OnCommissioningComplete(NodeId deviceId, CHIP_ERROR err)
{
if (mBridgeNodeId != deviceId)
{
if (err != CHIP_NO_ERROR)
{
ChipLogError(NotSpecified, "Failed to pair non-bridge device (0x:" ChipLogFormatX64 ") with error: %" CHIP_ERROR_FORMAT,
ChipLogValueX64(deviceId), err.Format());
}
else
{
ChipLogProgress(NotSpecified, "Commissioning complete for non-bridge device: NodeId: " ChipLogFormatX64,
ChipLogValueX64(deviceId));
}
return;
}
if (err == CHIP_NO_ERROR)
{
DeviceMgr().SetRemoteBridgeNodeId(mBridgeNodeId);
ChipLogProgress(NotSpecified, "Successfully paired bridge device: NodeId: " ChipLogFormatX64,
ChipLogValueX64(mBridgeNodeId));
DeviceMgr().SubscribeRemoteFabricBridge();
if (DeviceMgr().IsLocalBridgeReady())
{
// After successful commissioning of the Commissionee, initiate Reverse Commissioning
// via the Commissioner Control Cluster. However, we must first verify that the
// remote Fabric-Bridge supports Fabric Synchronization.
//
// Note: The Fabric-Admin MUST NOT send the RequestCommissioningApproval command
// if the remote Fabric-Bridge lacks Fabric Synchronization support.
DeviceLayer::PlatformMgr().ScheduleWork(CheckFabricBridgeSynchronizationSupport, 0);
}
}
else
{
ChipLogError(NotSpecified, "Failed to pair bridge device (0x:" ChipLogFormatX64 ") with error: %" CHIP_ERROR_FORMAT,
ChipLogValueX64(deviceId), err.Format());
}
mBridgeNodeId = kUndefinedNodeId;
}
CHIP_ERROR FabricSyncAddBridgeCommand::RunCommand(NodeId remoteId)
{
if (DeviceMgr().IsFabricSyncReady())
{
// print to console
fprintf(stderr, "Remote Fabric Bridge has already been configured.");
return CHIP_NO_ERROR;
}
PairingCommand * pairingCommand = static_cast<PairingCommand *>(CommandMgr().GetCommandByName("pairing", "already-discovered"));
if (pairingCommand == nullptr)
{
ChipLogError(NotSpecified, "Pairing already-discovered command is not available");
return CHIP_ERROR_NOT_IMPLEMENTED;
}
pairingCommand->RegisterCommissioningDelegate(this);
mBridgeNodeId = remoteId;
DeviceMgr().PairRemoteFabricBridge(remoteId, reinterpret_cast<const char *>(mRemoteAddr.data()));
return CHIP_NO_ERROR;
}
void FabricSyncRemoveBridgeCommand::OnDeviceRemoved(NodeId deviceId, CHIP_ERROR err)
{
if (mBridgeNodeId != deviceId)
{
ChipLogProgress(NotSpecified, "An non-bridge device: NodeId: " ChipLogFormatX64 " is removed.", ChipLogValueX64(deviceId));
return;
}
if (err == CHIP_NO_ERROR)
{
DeviceMgr().SetRemoteBridgeNodeId(kUndefinedNodeId);
ChipLogProgress(NotSpecified, "Successfully removed bridge device: NodeId: " ChipLogFormatX64,
ChipLogValueX64(mBridgeNodeId));
}
else
{
ChipLogError(NotSpecified, "Failed to remove bridge device (0x:" ChipLogFormatX64 ") with error: %" CHIP_ERROR_FORMAT,
ChipLogValueX64(deviceId), err.Format());
}
mBridgeNodeId = kUndefinedNodeId;
}
CHIP_ERROR FabricSyncRemoveBridgeCommand::RunCommand()
{
NodeId bridgeNodeId = DeviceMgr().GetRemoteBridgeNodeId();
if (bridgeNodeId == kUndefinedNodeId)
{
// print to console
fprintf(stderr, "Remote Fabric Bridge is not configured yet, nothing to remove.");
return CHIP_NO_ERROR;
}
mBridgeNodeId = bridgeNodeId;
PairingCommand * pairingCommand = static_cast<PairingCommand *>(CommandMgr().GetCommandByName("pairing", "unpair"));
if (pairingCommand == nullptr)
{
ChipLogError(NotSpecified, "Pairing unpair command is not available");
return CHIP_ERROR_NOT_IMPLEMENTED;
}
pairingCommand->RegisterPairingDelegate(this);
DeviceMgr().UnpairRemoteFabricBridge();
return CHIP_NO_ERROR;
}
void FabricSyncAddLocalBridgeCommand::OnCommissioningComplete(NodeId deviceId, CHIP_ERROR err)
{
if (mLocalBridgeNodeId != deviceId)
{
if (err != CHIP_NO_ERROR)
{
ChipLogError(NotSpecified, "Failed to pair non-bridge device (0x:" ChipLogFormatX64 ") with error: %" CHIP_ERROR_FORMAT,
ChipLogValueX64(deviceId), err.Format());
}
else
{
ChipLogProgress(NotSpecified, "Commissioning complete for non-bridge device: NodeId: " ChipLogFormatX64,
ChipLogValueX64(deviceId));
}
return;
}
if (err == CHIP_NO_ERROR)
{
DeviceMgr().SetLocalBridgeNodeId(mLocalBridgeNodeId);
ChipLogProgress(NotSpecified, "Successfully paired local bridge device: NodeId: " ChipLogFormatX64,
ChipLogValueX64(mLocalBridgeNodeId));
}
else
{
ChipLogError(NotSpecified, "Failed to pair local bridge device (0x:" ChipLogFormatX64 ") with error: %" CHIP_ERROR_FORMAT,
ChipLogValueX64(deviceId), err.Format());
}
mLocalBridgeNodeId = kUndefinedNodeId;
}
CHIP_ERROR FabricSyncAddLocalBridgeCommand::RunCommand(NodeId deviceId)
{
if (DeviceMgr().IsLocalBridgeReady())
{
// print to console
fprintf(stderr, "Local Fabric Bridge has already been configured.");
return CHIP_NO_ERROR;
}
PairingCommand * pairingCommand = static_cast<PairingCommand *>(CommandMgr().GetCommandByName("pairing", "already-discovered"));
VerifyOrDie(pairingCommand != nullptr);
pairingCommand->RegisterCommissioningDelegate(this);
mLocalBridgeNodeId = deviceId;
DeviceMgr().PairLocalFabricBridge(deviceId);
return CHIP_NO_ERROR;
}
void FabricSyncRemoveLocalBridgeCommand::OnDeviceRemoved(NodeId deviceId, CHIP_ERROR err)
{
if (mLocalBridgeNodeId != deviceId)
{
ChipLogProgress(NotSpecified, "A non-bridge device: NodeId: " ChipLogFormatX64 " is removed.", ChipLogValueX64(deviceId));
return;
}
if (err == CHIP_NO_ERROR)
{
DeviceMgr().SetLocalBridgeNodeId(kUndefinedNodeId);
ChipLogProgress(NotSpecified, "Successfully removed local bridge device: NodeId: " ChipLogFormatX64,
ChipLogValueX64(mLocalBridgeNodeId));
}
else
{
ChipLogError(NotSpecified, "Failed to remove local bridge device (0x:" ChipLogFormatX64 ") with error: %" CHIP_ERROR_FORMAT,
ChipLogValueX64(deviceId), err.Format());
}
mLocalBridgeNodeId = kUndefinedNodeId;
}
CHIP_ERROR FabricSyncRemoveLocalBridgeCommand::RunCommand()
{
NodeId bridgeNodeId = DeviceMgr().GetLocalBridgeNodeId();
if (bridgeNodeId == kUndefinedNodeId)
{
// print to console
fprintf(stderr, "Local Fabric Bridge is not configured yet, nothing to remove.");
return CHIP_NO_ERROR;
}
mLocalBridgeNodeId = bridgeNodeId;
PairingCommand * pairingCommand = static_cast<PairingCommand *>(CommandMgr().GetCommandByName("pairing", "unpair"));
if (pairingCommand == nullptr)
{
ChipLogError(NotSpecified, "Pairing unpair command is not available");
return CHIP_ERROR_NOT_IMPLEMENTED;
}
pairingCommand->RegisterPairingDelegate(this);
DeviceMgr().UnpairLocalFabricBridge();
return CHIP_NO_ERROR;
}
void FabricSyncDeviceCommand::OnCommissioningWindowOpened(NodeId deviceId, CHIP_ERROR err, chip::SetupPayload payload)
{
ChipLogProgress(NotSpecified, "FabricSyncDeviceCommand::OnCommissioningWindowOpened");
if (err == CHIP_NO_ERROR)
{
char payloadBuffer[kMaxManualCodeLength + 1];
MutableCharSpan manualCode(payloadBuffer);
CHIP_ERROR error = ManualSetupPayloadGenerator(payload).payloadDecimalStringRepresentation(manualCode);
if (error == CHIP_NO_ERROR)
{
NodeId nodeId = DeviceMgr().GetNextAvailableNodeId();
PairingCommand * pairingCommand = static_cast<PairingCommand *>(CommandMgr().GetCommandByName("pairing", "code"));
if (pairingCommand == nullptr)
{
ChipLogError(NotSpecified, "Pairing code command is not available");
return;
}
pairingCommand->RegisterCommissioningDelegate(this);
mAssignedNodeId = nodeId;
usleep(kCommissionPrepareTimeMs * 1000);
DeviceMgr().PairRemoteDevice(nodeId, payloadBuffer);
}
else
{
ChipLogError(NotSpecified, "Unable to generate manual code for setup payload: %" CHIP_ERROR_FORMAT, error.Format());
}
}
else
{
ChipLogError(NotSpecified,
"Failed to open synced device (0x:" ChipLogFormatX64 ") commissioning window: %" CHIP_ERROR_FORMAT,
ChipLogValueX64(deviceId), err.Format());
}
}
void FabricSyncDeviceCommand::OnCommissioningComplete(NodeId deviceId, CHIP_ERROR err)
{
if (mAssignedNodeId != deviceId)
{
// Ignore if the deviceId does not match the mAssignedNodeId.
// This scenario should not occur because no other device should be commissioned during the fabric sync process.
return;
}
if (err == CHIP_NO_ERROR)
{
DeviceMgr().AddSyncedDevice(Device(mAssignedNodeId, mRemoteEndpointId));
}
else
{
ChipLogError(NotSpecified, "Failed to pair synced device (0x:" ChipLogFormatX64 ") with error: %" CHIP_ERROR_FORMAT,
ChipLogValueX64(deviceId), err.Format());
}
}
CHIP_ERROR FabricSyncDeviceCommand::RunCommand(EndpointId remoteId)
{
if (!DeviceMgr().IsFabricSyncReady())
{
// print to console
fprintf(stderr, "Remote Fabric Bridge is not configured yet.");
return CHIP_NO_ERROR;
}
OpenCommissioningWindowCommand * openCommand =
static_cast<OpenCommissioningWindowCommand *>(CommandMgr().GetCommandByName("pairing", "open-commissioning-window"));
if (openCommand == nullptr)
{
return CHIP_ERROR_NOT_IMPLEMENTED;
}
openCommand->RegisterDelegate(this);
DeviceMgr().OpenRemoteDeviceCommissioningWindow(remoteId);
return CHIP_NO_ERROR;
}
CHIP_ERROR FabricAutoSyncCommand::RunCommand(bool enableAutoSync)
{
DeviceMgr().EnableAutoSync(enableAutoSync);
// print to console
fprintf(stderr, "Auto Fabric Sync is %s.\n", enableAutoSync ? "enabled" : "disabled");
fprintf(stderr,
"WARNING: The auto-sync command is currently under development and may contain bugs. Use it at your own risk.\n");
return CHIP_NO_ERROR;
}