-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement CommissionerControl command APIs
- Loading branch information
1 parent
d2d06b3
commit 515ff47
Showing
6 changed files
with
287 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
142 changes: 142 additions & 0 deletions
142
examples/fabric-admin/device_manager/CommissionerControl.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
#include "CommissionerControl.h" | ||
#include <device_manager/DeviceManager.h> | ||
|
||
using namespace ::chip; | ||
|
||
void CommissionerControl::Init(Controller::DeviceCommissioner & commissioner, NodeId nodeId, EndpointId endpointId) | ||
{ | ||
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; | ||
mRequestCommissioningApproval.label = label; | ||
|
||
CommissioneeDeviceProxy * commissioneeDeviceProxy = nullptr; | ||
if (CHIP_NO_ERROR == mCommissioner->GetDeviceBeingCommissioned(mDestinationId, &commissioneeDeviceProxy)) | ||
{ | ||
return SendCommandForType(CommandType::kRequestCommissioningApproval, commissioneeDeviceProxy); | ||
} | ||
|
||
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; | ||
|
||
CommissioneeDeviceProxy * commissioneeDeviceProxy = nullptr; | ||
if (CHIP_NO_ERROR == mCommissioner->GetDeviceBeingCommissioned(mDestinationId, &commissioneeDeviceProxy)) | ||
{ | ||
return SendCommandForType(CommandType::kCommissionNode, commissioneeDeviceProxy); | ||
} | ||
|
||
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) | ||
{ | ||
DeviceMgr().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)); | ||
mCommandSender.reset(); | ||
} | ||
|
||
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) | ||
{ | ||
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); | ||
; | ||
LogErrorOnFailure(err); | ||
} | ||
|
||
void CommissionerControl::OnDeviceConnectionFailureFn(void * context, const ScopedNodeId & peerId, CHIP_ERROR err) | ||
{ | ||
LogErrorOnFailure(err); | ||
|
||
CommissionerControl * self = reinterpret_cast<CommissionerControl *>(context); | ||
VerifyOrReturn(self != nullptr, ChipLogError(NotSpecified, "OnDeviceConnectionFailureFn: context is null")); | ||
} |
122 changes: 122 additions & 0 deletions
122
examples/fabric-admin/device_manager/CommissionerControl.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
/* | ||
* 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. | ||
* | ||
*/ | ||
|
||
#pragma once | ||
|
||
#include <app/CommandSender.h> | ||
#include <controller/CHIPDeviceController.h> | ||
|
||
/** | ||
* @class CommissionerControl | ||
* @brief This class handles commissioning control operations using CHIP commands, including sending | ||
* commissioning approval requests and commissioning nodes. | ||
* | ||
* The class implements the `chip::app::CommandSender::Callback` interface to handle responses, errors, | ||
* and completion events for the commands it sends. It allows sending commands related to commissioning | ||
* and tracks the status of the operations. | ||
*/ | ||
class CommissionerControl : public chip::app::CommandSender::Callback | ||
{ | ||
public: | ||
CommissionerControl() : | ||
mOnDeviceConnectedCallback(OnDeviceConnectedFn, this), mOnDeviceConnectionFailureCallback(OnDeviceConnectionFailureFn, this) | ||
{} | ||
|
||
/** | ||
* @brief Initializes the CommissionerControl with a DeviceCommissioner, NodeId, and EndpointId. | ||
* | ||
* @param commissioner The DeviceCommissioner to use for the commissioning process. | ||
* @param nodeId The node ID of the remote fabric bridge. | ||
* @param endpointId The endpoint on which to send CommissionerControl commands. | ||
*/ | ||
void Init(chip::Controller::DeviceCommissioner & commissioner, chip::NodeId nodeId, chip::EndpointId endpointId); | ||
|
||
/** | ||
* @brief Sends a RequestCommissioningApproval command to the device. | ||
* | ||
* @param requestId The unique request ID. | ||
* @param vendorId The vendor ID of the device. | ||
* @param productId The product ID of the device. | ||
* @param label Optional label for the device. | ||
* @return CHIP_ERROR CHIP_NO_ERROR on success, or an appropriate error code on failure. | ||
*/ | ||
CHIP_ERROR RequestCommissioningApproval(uint64_t requestId, uint16_t vendorId, uint16_t productId, | ||
chip::Optional<chip::CharSpan> label); | ||
/** | ||
* @brief Sends a CommissionNode command to the device. | ||
* | ||
* @param requestId The unique request ID. | ||
* @param responseTimeoutSeconds Timeout for the response in seconds. | ||
* @return CHIP_ERROR CHIP_NO_ERROR on success, or an appropriate error code on failure. | ||
*/ | ||
CHIP_ERROR CommissionNode(uint64_t requestId, uint16_t responseTimeoutSeconds); | ||
|
||
/////////// CommandSender Callback Interface ///////// | ||
virtual void OnResponse(chip::app::CommandSender * client, const chip::app::ConcreteCommandPath & path, | ||
const chip::app::StatusIB & status, chip::TLV::TLVReader * data) override; | ||
|
||
virtual void OnError(const chip::app::CommandSender * client, CHIP_ERROR error) override; | ||
|
||
virtual void OnDone(chip::app::CommandSender * client) override; | ||
|
||
private: | ||
enum class CommandType : uint8_t | ||
{ | ||
kUndefined = 0, | ||
kRequestCommissioningApproval = 1, | ||
kCommissionNode = 2, | ||
}; | ||
|
||
template <class T> | ||
CHIP_ERROR SendCommand(chip::DeviceProxy * device, chip::EndpointId endpointId, chip::ClusterId clusterId, | ||
chip::CommandId commandId, const T & value) | ||
{ | ||
chip::app::CommandPathParams commandPath = { endpointId, clusterId, commandId, | ||
(chip::app::CommandPathFlags::kEndpointIdValid) }; | ||
mCommandSender = std::make_unique<chip::app::CommandSender>(this, device->GetExchangeManager(), false, false, | ||
device->GetSecureSession().Value()->AllowsLargePayload()); | ||
|
||
VerifyOrReturnError(mCommandSender != nullptr, CHIP_ERROR_NO_MEMORY); | ||
|
||
chip::app::CommandSender::AddRequestDataParameters addRequestDataParams(chip::NullOptional); | ||
// Using TestOnly AddRequestData to allow for an intentionally malformed request for server validation testing. | ||
ReturnErrorOnFailure(mCommandSender->TestOnlyAddRequestDataNoTimedCheck(commandPath, value, addRequestDataParams)); | ||
ReturnErrorOnFailure(mCommandSender->SendCommandRequest(device->GetSecureSession().Value())); | ||
|
||
return CHIP_NO_ERROR; | ||
} | ||
|
||
CHIP_ERROR SendCommandForType(CommandType commandType, chip::DeviceProxy * device); | ||
|
||
static void OnDeviceConnectedFn(void * context, chip::Messaging::ExchangeManager & exchangeMgr, | ||
const chip::SessionHandle & sessionHandle); | ||
static void OnDeviceConnectionFailureFn(void * context, const chip::ScopedNodeId & peerId, CHIP_ERROR error); | ||
|
||
// Private data members | ||
chip::Controller::DeviceCommissioner * mCommissioner = nullptr; | ||
std::unique_ptr<chip::app::CommandSender> mCommandSender; | ||
chip::NodeId mDestinationId = chip::kUndefinedNodeId; | ||
chip::EndpointId mEndpointId = chip::kRootEndpointId; | ||
CommandType mCommandType = CommandType::kUndefined; | ||
|
||
chip::Callback::Callback<chip::OnDeviceConnected> mOnDeviceConnectedCallback; | ||
chip::Callback::Callback<chip::OnDeviceConnectionFailure> mOnDeviceConnectionFailureCallback; | ||
|
||
chip::app::Clusters::CommissionerControl::Commands::RequestCommissioningApproval::Type mRequestCommissioningApproval; | ||
chip::app::Clusters::CommissionerControl::Commands::CommissionNode::Type mCommissionNode; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters