blob: a0c24eb956d5bbea4be24f6c9405007f9841a9a4 [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 "CommissionerControl.h"
#include "DeviceManager.h"
using namespace ::chip;
namespace admin {
void CommissionerControl::Init(Controller::DeviceCommissioner & commissioner, NodeId nodeId, EndpointId endpointId)
{
// Ensure that mCommissioner is not already initialized
VerifyOrDie(mCommissioner == nullptr);
ChipLogProgress(NotSpecified, "Initilize CommissionerControl");
mCommissioner = &commissioner;
mDestinationId = nodeId;
mEndpointId = endpointId;
}
CHIP_ERROR CommissionerControl::RequestCommissioningApproval(uint64_t requestId, uint16_t vendorId, uint16_t productId,
Optional<CharSpan> label)
{
VerifyOrReturnError(mCommissioner != nullptr, CHIP_ERROR_INCORRECT_STATE);
ChipLogProgress(NotSpecified, "Sending RequestCommissioningApproval to node " ChipLogFormatX64,
ChipLogValueX64(mDestinationId));
mRequestCommissioningApproval.requestID = requestId;
mRequestCommissioningApproval.vendorID = static_cast<VendorId>(vendorId);
mRequestCommissioningApproval.productID = productId;
if (label.HasValue())
{
VerifyOrReturnError(label.Value().size() <= kMaxDeviceLabelLength, CHIP_ERROR_BUFFER_TOO_SMALL);
memcpy(mLabelBuffer, label.Value().data(), label.Value().size());
mRequestCommissioningApproval.label = Optional<Span<const char>>(CharSpan(mLabelBuffer, label.Value().size()));
}
mCommandType = CommandType::kRequestCommissioningApproval;
return mCommissioner->GetConnectedDevice(mDestinationId, &mOnDeviceConnectedCallback, &mOnDeviceConnectionFailureCallback);
}
CHIP_ERROR CommissionerControl::CommissionNode(uint64_t requestId, uint16_t responseTimeoutSeconds)
{
VerifyOrReturnError(mCommissioner != nullptr, CHIP_ERROR_INCORRECT_STATE);
ChipLogProgress(NotSpecified, "Sending CommissionNode to node " ChipLogFormatX64, ChipLogValueX64(mDestinationId));
mCommissionNode.requestID = requestId;
mCommissionNode.responseTimeoutSeconds = responseTimeoutSeconds;
mCommandType = CommandType::kCommissionNode;
return mCommissioner->GetConnectedDevice(mDestinationId, &mOnDeviceConnectedCallback, &mOnDeviceConnectionFailureCallback);
}
void CommissionerControl::OnResponse(app::CommandSender * client, const app::ConcreteCommandPath & path,
const app::StatusIB & status, TLV::TLVReader * data)
{
ChipLogProgress(NotSpecified, "CommissionerControl: OnResponse.");
CHIP_ERROR error = status.ToChipError();
if (CHIP_NO_ERROR != error)
{
ChipLogError(NotSpecified, "Response Failure: %s", ErrorStr(error));
return;
}
if (data != nullptr)
{
DeviceManager::Instance().HandleCommandResponse(path, *data);
}
}
void CommissionerControl::OnError(const app::CommandSender * client, CHIP_ERROR error)
{
// Handle the error, then reset mCommandSender
ChipLogProgress(NotSpecified, "CommissionerControl: OnError: Error: %s", ErrorStr(error));
}
void CommissionerControl::OnDone(app::CommandSender * client)
{
ChipLogProgress(NotSpecified, "CommissionerControl: OnDone.");
switch (mCommandType)
{
case CommandType::kRequestCommissioningApproval:
ChipLogProgress(NotSpecified, "CommissionerControl: Command RequestCommissioningApproval has been successfully processed.");
break;
case CommandType::kCommissionNode:
ChipLogProgress(NotSpecified, "CommissionerControl: Command CommissionNode has been successfully processed.");
break;
default:
ChipLogError(NotSpecified, "CommissionerControl: Unknown or unhandled command type in OnDone.");
break;
}
// Reset command type to undefined after processing is done
mCommandType = CommandType::kUndefined;
// Ensure that mCommandSender is cleaned up after it is done
mCommandSender.reset();
}
CHIP_ERROR CommissionerControl::SendCommandForType(CommandType commandType, DeviceProxy * device)
{
ChipLogProgress(AppServer, "Sending command with Endpoint ID: %d, Command Type: %d", mEndpointId,
static_cast<int>(commandType));
switch (commandType)
{
case CommandType::kRequestCommissioningApproval:
return SendCommand(device, mEndpointId, app::Clusters::CommissionerControl::Id,
app::Clusters::CommissionerControl::Commands::RequestCommissioningApproval::Id,
mRequestCommissioningApproval);
case CommandType::kCommissionNode:
return SendCommand(device, mEndpointId, app::Clusters::CommissionerControl::Id,
app::Clusters::CommissionerControl::Commands::CommissionNode::Id, mCommissionNode);
default:
return CHIP_ERROR_INVALID_ARGUMENT;
}
}
void CommissionerControl::OnDeviceConnectedFn(void * context, Messaging::ExchangeManager & exchangeMgr,
const SessionHandle & sessionHandle)
{
CommissionerControl * self = reinterpret_cast<CommissionerControl *>(context);
VerifyOrReturn(self != nullptr, ChipLogError(NotSpecified, "OnDeviceConnectedFn: context is null"));
OperationalDeviceProxy device(&exchangeMgr, sessionHandle);
CHIP_ERROR err = self->SendCommandForType(self->mCommandType, &device);
if (err != CHIP_NO_ERROR)
{
ChipLogError(NotSpecified, "Failed to send CommissionerControl command.");
self->OnDone(nullptr);
}
}
void CommissionerControl::OnDeviceConnectionFailureFn(void * context, const ScopedNodeId & peerId, CHIP_ERROR err)
{
LogErrorOnFailure(err);
CommissionerControl * self = reinterpret_cast<CommissionerControl *>(context);
VerifyOrReturn(self != nullptr, ChipLogError(NotSpecified, "OnDeviceConnectedFn: context is null"));
self->OnDone(nullptr);
}
} // namespace admin