-
Notifications
You must be signed in to change notification settings - Fork 2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Fabric-Sync] Port commissioner control protocol implementation (#36427)
* [Fabric-Sync] Port commissioner control protocol * Add device synchronization * Fix compile error * Update examples/fabric-sync/admin/DeviceSubscription.cpp Co-authored-by: Terence Hampson <[email protected]> * Address review comments * Add debug log * Update examples/fabric-sync/admin/DeviceManager.cpp Co-authored-by: Terence Hampson <[email protected]> * Address review comments * Add endpoint check --------- Co-authored-by: Terence Hampson <[email protected]>
- Loading branch information
1 parent
39e83c9
commit dac4a53
Showing
42 changed files
with
3,624 additions
and
17 deletions.
There are no files selected for viewing
18 changes: 18 additions & 0 deletions
18
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
/* | ||
* 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 "BridgeSubscription.h" | ||
#include "DeviceManager.h" | ||
|
||
using namespace ::chip; | ||
using namespace ::chip::app; | ||
using chip::app::ReadClient; | ||
|
||
namespace admin { | ||
|
||
namespace { | ||
|
||
constexpr uint16_t kSubscribeMinInterval = 0; | ||
constexpr uint16_t kSubscribeMaxInterval = 60; | ||
|
||
void OnDeviceConnectedWrapper(void * context, Messaging::ExchangeManager & exchangeMgr, const SessionHandle & sessionHandle) | ||
{ | ||
reinterpret_cast<BridgeSubscription *>(context)->OnDeviceConnected(exchangeMgr, sessionHandle); | ||
} | ||
|
||
void OnDeviceConnectionFailureWrapper(void * context, const ScopedNodeId & peerId, CHIP_ERROR error) | ||
{ | ||
reinterpret_cast<BridgeSubscription *>(context)->OnDeviceConnectionFailure(peerId, error); | ||
} | ||
|
||
} // namespace | ||
|
||
BridgeSubscription::BridgeSubscription() : | ||
mOnDeviceConnectedCallback(OnDeviceConnectedWrapper, this), | ||
mOnDeviceConnectionFailureCallback(OnDeviceConnectionFailureWrapper, this) | ||
{} | ||
|
||
CHIP_ERROR BridgeSubscription::StartSubscription(Controller::DeviceController & controller, NodeId nodeId, EndpointId endpointId) | ||
{ | ||
assertChipStackLockedByCurrentThread(); | ||
|
||
VerifyOrDie(!subscriptionStarted); // Ensure it's not called multiple times. | ||
|
||
// Mark as started | ||
subscriptionStarted = true; | ||
|
||
mEndpointId = endpointId; | ||
|
||
CHIP_ERROR err = controller.GetConnectedDevice(nodeId, &mOnDeviceConnectedCallback, &mOnDeviceConnectionFailureCallback); | ||
if (err != CHIP_NO_ERROR) | ||
{ | ||
ChipLogError(NotSpecified, "Failed to connect to remote fabric sync bridge %" CHIP_ERROR_FORMAT, err.Format()); | ||
} | ||
return err; | ||
} | ||
|
||
void BridgeSubscription::OnAttributeData(const ConcreteDataAttributePath & path, TLV::TLVReader * data, const StatusIB & status) | ||
{ | ||
if (!status.IsSuccess()) | ||
{ | ||
ChipLogError(NotSpecified, "Response Failure: %" CHIP_ERROR_FORMAT, status.ToChipError().Format()); | ||
return; | ||
} | ||
|
||
if (data == nullptr) | ||
{ | ||
ChipLogError(NotSpecified, "Response Failure: No Data"); | ||
return; | ||
} | ||
|
||
DeviceMgr().HandleAttributeData(path, *data); | ||
} | ||
|
||
void BridgeSubscription::OnEventData(const app::EventHeader & eventHeader, TLV::TLVReader * data, const app::StatusIB * status) | ||
{ | ||
if (status != nullptr) | ||
{ | ||
CHIP_ERROR error = status->ToChipError(); | ||
if (CHIP_NO_ERROR != error) | ||
{ | ||
ChipLogError(NotSpecified, "Response Failure: %" CHIP_ERROR_FORMAT, error.Format()); | ||
return; | ||
} | ||
} | ||
|
||
if (data == nullptr) | ||
{ | ||
ChipLogError(NotSpecified, "Response Failure: No Data"); | ||
return; | ||
} | ||
|
||
DeviceMgr().HandleEventData(eventHeader, *data); | ||
} | ||
|
||
void BridgeSubscription::OnError(CHIP_ERROR error) | ||
{ | ||
ChipLogProgress(NotSpecified, "Error on remote fabric sync bridge subscription: %" CHIP_ERROR_FORMAT, error.Format()); | ||
} | ||
|
||
void BridgeSubscription::OnDone(ReadClient * apReadClient) | ||
{ | ||
mClient.reset(); | ||
ChipLogProgress(NotSpecified, "The remote fabric sync bridge subscription is terminated"); | ||
|
||
// Reset the subscription state to allow retry | ||
subscriptionStarted = false; | ||
|
||
// TODO:(#36092) Fabric-Admin should attempt to re-subscribe when the subscription to the remote bridge is terminated. | ||
} | ||
|
||
void BridgeSubscription::OnDeviceConnected(Messaging::ExchangeManager & exchangeMgr, const SessionHandle & sessionHandle) | ||
{ | ||
mClient = std::make_unique<ReadClient>(app::InteractionModelEngine::GetInstance(), &exchangeMgr /* echangeMgr */, | ||
*this /* callback */, ReadClient::InteractionType::Subscribe); | ||
VerifyOrDie(mClient); | ||
|
||
AttributePathParams readPaths[1]; | ||
readPaths[0] = AttributePathParams(mEndpointId, Clusters::Descriptor::Id, Clusters::Descriptor::Attributes::PartsList::Id); | ||
|
||
EventPathParams eventPaths[1]; | ||
eventPaths[0] = EventPathParams(mEndpointId, Clusters::CommissionerControl::Id, | ||
Clusters::CommissionerControl::Events::CommissioningRequestResult::Id); | ||
eventPaths[0].mIsUrgentEvent = true; | ||
|
||
ReadPrepareParams readParams(sessionHandle); | ||
|
||
readParams.mpAttributePathParamsList = readPaths; | ||
readParams.mAttributePathParamsListSize = 1; | ||
readParams.mpEventPathParamsList = eventPaths; | ||
readParams.mEventPathParamsListSize = 1; | ||
readParams.mMinIntervalFloorSeconds = kSubscribeMinInterval; | ||
readParams.mMaxIntervalCeilingSeconds = kSubscribeMaxInterval; | ||
readParams.mKeepSubscriptions = true; | ||
|
||
CHIP_ERROR err = mClient->SendRequest(readParams); | ||
|
||
if (err != CHIP_NO_ERROR) | ||
{ | ||
ChipLogError(NotSpecified, "Failed to issue subscription to the Descriptor Cluster of the remote bridged device."); | ||
OnDone(nullptr); | ||
return; | ||
} | ||
} | ||
|
||
void BridgeSubscription::OnDeviceConnectionFailure(const ScopedNodeId & peerId, CHIP_ERROR error) | ||
{ | ||
ChipLogError(NotSpecified, "BridgeSubscription failed to connect to " ChipLogFormatX64, ChipLogValueX64(peerId.GetNodeId())); | ||
OnDone(nullptr); | ||
} | ||
|
||
} // namespace admin |
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,81 @@ | ||
/* | ||
* 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/ReadClient.h> | ||
#include <controller/CHIPDeviceController.h> | ||
|
||
#include <memory> | ||
#include <optional> | ||
|
||
namespace admin { | ||
|
||
/** | ||
* @brief Class used to subscribe to attributes and events from the remote bridged device. | ||
* | ||
* The Descriptor Cluster contains attributes such as the Parts List, which provides a list | ||
* of endpoints or devices that are part of a composite device or bridge. The CommissionerControl | ||
* Cluster generates events related to commissioning requests, which can be monitored to track | ||
* device commissioning status. | ||
* | ||
* When subscribing to attributes and events of a bridged device from another fabric, the class: | ||
* - Establishes a secure session with the device (if needed) via CASE (Chip over | ||
* Authenticated Session Establishment) session. | ||
* - Subscribes to the specified attributes in the Descriptor Cluster (e.g., Parts List) and | ||
* events in the CommissionerControl Cluster (e.g., CommissioningRequestResult) of the remote | ||
* device on the specified node and endpoint. | ||
* - Invokes the provided callback upon successful or unsuccessful subscription, allowing | ||
* further handling of data or errors. | ||
* | ||
* This class also implements the necessary callbacks to handle attribute data reports, event data, | ||
* errors, and session establishment procedures. | ||
*/ | ||
class BridgeSubscription : public chip::app::ReadClient::Callback | ||
{ | ||
public: | ||
BridgeSubscription(); | ||
|
||
CHIP_ERROR StartSubscription(chip::Controller::DeviceController & controller, chip::NodeId nodeId, chip::EndpointId endpointId); | ||
|
||
/////////////////////////////////////////////////////////////// | ||
// ReadClient::Callback implementation | ||
/////////////////////////////////////////////////////////////// | ||
void OnAttributeData(const chip::app::ConcreteDataAttributePath & path, chip::TLV::TLVReader * data, | ||
const chip::app::StatusIB & status) override; | ||
void OnEventData(const chip::app::EventHeader & eventHeader, chip::TLV::TLVReader * data, | ||
const chip::app::StatusIB * status) override; | ||
void OnError(CHIP_ERROR error) override; | ||
void OnDone(chip::app::ReadClient * apReadClient) override; | ||
|
||
/////////////////////////////////////////////////////////////// | ||
// callbacks for CASE session establishment | ||
/////////////////////////////////////////////////////////////// | ||
void OnDeviceConnected(chip::Messaging::ExchangeManager & exchangeMgr, const chip::SessionHandle & sessionHandle); | ||
void OnDeviceConnectionFailure(const chip::ScopedNodeId & peerId, CHIP_ERROR error); | ||
|
||
private: | ||
std::unique_ptr<chip::app::ReadClient> mClient; | ||
|
||
chip::Callback::Callback<chip::OnDeviceConnected> mOnDeviceConnectedCallback; | ||
chip::Callback::Callback<chip::OnDeviceConnectionFailure> mOnDeviceConnectionFailureCallback; | ||
chip::EndpointId mEndpointId; | ||
bool subscriptionStarted = false; | ||
}; | ||
|
||
} // namespace admin |
Oops, something went wrong.