Skip to content

Commit dac4a53

Browse files
[Fabric-Sync] Port commissioner control protocol implementation (project-chip#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 <thampson@google.com> * Address review comments * Add debug log * Update examples/fabric-sync/admin/DeviceManager.cpp Co-authored-by: Terence Hampson <thampson@google.com> * Address review comments * Add endpoint check --------- Co-authored-by: Terence Hampson <thampson@google.com>
1 parent 39e83c9 commit dac4a53

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+3624
-17
lines changed

examples/fabric-admin/device_manager/CommissionerControl.cpp

+18
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,21 @@
1+
/*
2+
* Copyright (c) 2024 Project CHIP Authors
3+
* All rights reserved.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*
17+
*/
18+
119
#include "CommissionerControl.h"
220
#include "DeviceManager.h"
321

examples/fabric-sync/admin/BUILD.gn

+28
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,44 @@
1515
import("//build_overrides/chip.gni")
1616
import("${chip_root}/src/app/chip_data_model.gni")
1717

18+
config("config") {
19+
include_dirs = [
20+
".",
21+
"${chip_root}/examples/fabric-sync",
22+
"${chip_root}/examples/platform/linux",
23+
"${chip_root}/src/lib",
24+
]
25+
}
26+
1827
source_set("fabric-admin-lib") {
28+
public_configs = [ ":config" ]
29+
1930
sources = [
31+
"BridgeSubscription.cpp",
32+
"BridgeSubscription.h",
33+
"CommissionerControl.cpp",
34+
"CommissionerControl.h",
2035
"DeviceManager.cpp",
2136
"DeviceManager.h",
37+
"DeviceSubscription.cpp",
38+
"DeviceSubscription.h",
39+
"DeviceSubscriptionManager.cpp",
40+
"DeviceSubscriptionManager.h",
41+
"DeviceSynchronization.cpp",
42+
"DeviceSynchronization.h",
43+
"FabricAdmin.cpp",
44+
"FabricAdmin.h",
45+
"FabricSyncGetter.cpp",
46+
"FabricSyncGetter.h",
2247
"PairingManager.cpp",
2348
"PairingManager.h",
49+
"UniqueIdGetter.cpp",
50+
"UniqueIdGetter.h",
2451
]
2552

2653
deps = [
2754
"${chip_root}/examples/fabric-sync/bridge:fabric-bridge-lib",
55+
"${chip_root}/examples/platform/linux:app-main",
2856
"${chip_root}/src/lib",
2957
]
3058
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
/*
2+
* Copyright (c) 2024 Project CHIP Authors
3+
* All rights reserved.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*
17+
*/
18+
19+
#include "BridgeSubscription.h"
20+
#include "DeviceManager.h"
21+
22+
using namespace ::chip;
23+
using namespace ::chip::app;
24+
using chip::app::ReadClient;
25+
26+
namespace admin {
27+
28+
namespace {
29+
30+
constexpr uint16_t kSubscribeMinInterval = 0;
31+
constexpr uint16_t kSubscribeMaxInterval = 60;
32+
33+
void OnDeviceConnectedWrapper(void * context, Messaging::ExchangeManager & exchangeMgr, const SessionHandle & sessionHandle)
34+
{
35+
reinterpret_cast<BridgeSubscription *>(context)->OnDeviceConnected(exchangeMgr, sessionHandle);
36+
}
37+
38+
void OnDeviceConnectionFailureWrapper(void * context, const ScopedNodeId & peerId, CHIP_ERROR error)
39+
{
40+
reinterpret_cast<BridgeSubscription *>(context)->OnDeviceConnectionFailure(peerId, error);
41+
}
42+
43+
} // namespace
44+
45+
BridgeSubscription::BridgeSubscription() :
46+
mOnDeviceConnectedCallback(OnDeviceConnectedWrapper, this),
47+
mOnDeviceConnectionFailureCallback(OnDeviceConnectionFailureWrapper, this)
48+
{}
49+
50+
CHIP_ERROR BridgeSubscription::StartSubscription(Controller::DeviceController & controller, NodeId nodeId, EndpointId endpointId)
51+
{
52+
assertChipStackLockedByCurrentThread();
53+
54+
VerifyOrDie(!subscriptionStarted); // Ensure it's not called multiple times.
55+
56+
// Mark as started
57+
subscriptionStarted = true;
58+
59+
mEndpointId = endpointId;
60+
61+
CHIP_ERROR err = controller.GetConnectedDevice(nodeId, &mOnDeviceConnectedCallback, &mOnDeviceConnectionFailureCallback);
62+
if (err != CHIP_NO_ERROR)
63+
{
64+
ChipLogError(NotSpecified, "Failed to connect to remote fabric sync bridge %" CHIP_ERROR_FORMAT, err.Format());
65+
}
66+
return err;
67+
}
68+
69+
void BridgeSubscription::OnAttributeData(const ConcreteDataAttributePath & path, TLV::TLVReader * data, const StatusIB & status)
70+
{
71+
if (!status.IsSuccess())
72+
{
73+
ChipLogError(NotSpecified, "Response Failure: %" CHIP_ERROR_FORMAT, status.ToChipError().Format());
74+
return;
75+
}
76+
77+
if (data == nullptr)
78+
{
79+
ChipLogError(NotSpecified, "Response Failure: No Data");
80+
return;
81+
}
82+
83+
DeviceMgr().HandleAttributeData(path, *data);
84+
}
85+
86+
void BridgeSubscription::OnEventData(const app::EventHeader & eventHeader, TLV::TLVReader * data, const app::StatusIB * status)
87+
{
88+
if (status != nullptr)
89+
{
90+
CHIP_ERROR error = status->ToChipError();
91+
if (CHIP_NO_ERROR != error)
92+
{
93+
ChipLogError(NotSpecified, "Response Failure: %" CHIP_ERROR_FORMAT, error.Format());
94+
return;
95+
}
96+
}
97+
98+
if (data == nullptr)
99+
{
100+
ChipLogError(NotSpecified, "Response Failure: No Data");
101+
return;
102+
}
103+
104+
DeviceMgr().HandleEventData(eventHeader, *data);
105+
}
106+
107+
void BridgeSubscription::OnError(CHIP_ERROR error)
108+
{
109+
ChipLogProgress(NotSpecified, "Error on remote fabric sync bridge subscription: %" CHIP_ERROR_FORMAT, error.Format());
110+
}
111+
112+
void BridgeSubscription::OnDone(ReadClient * apReadClient)
113+
{
114+
mClient.reset();
115+
ChipLogProgress(NotSpecified, "The remote fabric sync bridge subscription is terminated");
116+
117+
// Reset the subscription state to allow retry
118+
subscriptionStarted = false;
119+
120+
// TODO:(#36092) Fabric-Admin should attempt to re-subscribe when the subscription to the remote bridge is terminated.
121+
}
122+
123+
void BridgeSubscription::OnDeviceConnected(Messaging::ExchangeManager & exchangeMgr, const SessionHandle & sessionHandle)
124+
{
125+
mClient = std::make_unique<ReadClient>(app::InteractionModelEngine::GetInstance(), &exchangeMgr /* echangeMgr */,
126+
*this /* callback */, ReadClient::InteractionType::Subscribe);
127+
VerifyOrDie(mClient);
128+
129+
AttributePathParams readPaths[1];
130+
readPaths[0] = AttributePathParams(mEndpointId, Clusters::Descriptor::Id, Clusters::Descriptor::Attributes::PartsList::Id);
131+
132+
EventPathParams eventPaths[1];
133+
eventPaths[0] = EventPathParams(mEndpointId, Clusters::CommissionerControl::Id,
134+
Clusters::CommissionerControl::Events::CommissioningRequestResult::Id);
135+
eventPaths[0].mIsUrgentEvent = true;
136+
137+
ReadPrepareParams readParams(sessionHandle);
138+
139+
readParams.mpAttributePathParamsList = readPaths;
140+
readParams.mAttributePathParamsListSize = 1;
141+
readParams.mpEventPathParamsList = eventPaths;
142+
readParams.mEventPathParamsListSize = 1;
143+
readParams.mMinIntervalFloorSeconds = kSubscribeMinInterval;
144+
readParams.mMaxIntervalCeilingSeconds = kSubscribeMaxInterval;
145+
readParams.mKeepSubscriptions = true;
146+
147+
CHIP_ERROR err = mClient->SendRequest(readParams);
148+
149+
if (err != CHIP_NO_ERROR)
150+
{
151+
ChipLogError(NotSpecified, "Failed to issue subscription to the Descriptor Cluster of the remote bridged device.");
152+
OnDone(nullptr);
153+
return;
154+
}
155+
}
156+
157+
void BridgeSubscription::OnDeviceConnectionFailure(const ScopedNodeId & peerId, CHIP_ERROR error)
158+
{
159+
ChipLogError(NotSpecified, "BridgeSubscription failed to connect to " ChipLogFormatX64, ChipLogValueX64(peerId.GetNodeId()));
160+
OnDone(nullptr);
161+
}
162+
163+
} // namespace admin
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/*
2+
* Copyright (c) 2024 Project CHIP Authors
3+
* All rights reserved.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*
17+
*/
18+
19+
#pragma once
20+
21+
#include <app/ReadClient.h>
22+
#include <controller/CHIPDeviceController.h>
23+
24+
#include <memory>
25+
#include <optional>
26+
27+
namespace admin {
28+
29+
/**
30+
* @brief Class used to subscribe to attributes and events from the remote bridged device.
31+
*
32+
* The Descriptor Cluster contains attributes such as the Parts List, which provides a list
33+
* of endpoints or devices that are part of a composite device or bridge. The CommissionerControl
34+
* Cluster generates events related to commissioning requests, which can be monitored to track
35+
* device commissioning status.
36+
*
37+
* When subscribing to attributes and events of a bridged device from another fabric, the class:
38+
* - Establishes a secure session with the device (if needed) via CASE (Chip over
39+
* Authenticated Session Establishment) session.
40+
* - Subscribes to the specified attributes in the Descriptor Cluster (e.g., Parts List) and
41+
* events in the CommissionerControl Cluster (e.g., CommissioningRequestResult) of the remote
42+
* device on the specified node and endpoint.
43+
* - Invokes the provided callback upon successful or unsuccessful subscription, allowing
44+
* further handling of data or errors.
45+
*
46+
* This class also implements the necessary callbacks to handle attribute data reports, event data,
47+
* errors, and session establishment procedures.
48+
*/
49+
class BridgeSubscription : public chip::app::ReadClient::Callback
50+
{
51+
public:
52+
BridgeSubscription();
53+
54+
CHIP_ERROR StartSubscription(chip::Controller::DeviceController & controller, chip::NodeId nodeId, chip::EndpointId endpointId);
55+
56+
///////////////////////////////////////////////////////////////
57+
// ReadClient::Callback implementation
58+
///////////////////////////////////////////////////////////////
59+
void OnAttributeData(const chip::app::ConcreteDataAttributePath & path, chip::TLV::TLVReader * data,
60+
const chip::app::StatusIB & status) override;
61+
void OnEventData(const chip::app::EventHeader & eventHeader, chip::TLV::TLVReader * data,
62+
const chip::app::StatusIB * status) override;
63+
void OnError(CHIP_ERROR error) override;
64+
void OnDone(chip::app::ReadClient * apReadClient) override;
65+
66+
///////////////////////////////////////////////////////////////
67+
// callbacks for CASE session establishment
68+
///////////////////////////////////////////////////////////////
69+
void OnDeviceConnected(chip::Messaging::ExchangeManager & exchangeMgr, const chip::SessionHandle & sessionHandle);
70+
void OnDeviceConnectionFailure(const chip::ScopedNodeId & peerId, CHIP_ERROR error);
71+
72+
private:
73+
std::unique_ptr<chip::app::ReadClient> mClient;
74+
75+
chip::Callback::Callback<chip::OnDeviceConnected> mOnDeviceConnectedCallback;
76+
chip::Callback::Callback<chip::OnDeviceConnectionFailure> mOnDeviceConnectionFailureCallback;
77+
chip::EndpointId mEndpointId;
78+
bool subscriptionStarted = false;
79+
};
80+
81+
} // namespace admin

0 commit comments

Comments
 (0)