Skip to content

Commit 6251801

Browse files
andy31415Copilotzaid-googleandreilitvin
authored
Decouple Network commissioning and general commissioning via a breadcrumb tracker (#41724)
* Decouple Network commissioning and general commissioning via a breadcrumb tracker. * Comment update. * Cleanup some includes. * Fix includes. * Update src/app/clusters/network-commissioning/tests/TestNetworkCommissioningCluster.cpp Co-authored-by: Copilot <[email protected]> * Make the breadcrumb tracker a reference. * Remove the global instance for general commissioning. * Typo fix. * Update src/app/clusters/network-commissioning/CodegenInstance.h Co-authored-by: Copilot <[email protected]> * Add include dep since that makes things compile clearer. * Look to be able to compile emulator tests as well. * Update src/app/clusters/general-commissioning-server/CodegenIntegration.cpp Co-authored-by: Zaid Omer <[email protected]> * Mark the overrides in general commissioning as final, to slightly reduce flash overhed. * Fix comment. * Add message on failure to set breadcrumb. --------- Co-authored-by: Copilot <[email protected]> Co-authored-by: Zaid Omer <[email protected]> Co-authored-by: Andrei Litvin <[email protected]>
1 parent bd67813 commit 6251801

19 files changed

+327
-77
lines changed

src/app/clusters/general-commissioning-server/BUILD.gn

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,20 @@ import("//build_overrides/chip.gni")
1616

1717
import("${chip_root}/src/app/common_flags.gni")
1818

19+
source_set("bread-crumb-tracker") {
20+
sources = [ "BreadCrumbTracker.h" ]
21+
22+
public_configs = [ "${chip_root}/src:includes" ]
23+
}
24+
1925
source_set("general-commissioning-server") {
2026
sources = [
2127
"general-commissioning-cluster.cpp",
2228
"general-commissioning-cluster.h",
2329
]
2430

2531
public_deps = [
32+
":bread-crumb-tracker",
2633
"${chip_root}/src/app:app_config",
2734
"${chip_root}/src/app/data-model-provider",
2835
"${chip_root}/src/app/server",
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* Copyright (c) 2025 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+
#pragma once
18+
#include <cstdint>
19+
20+
namespace chip::app::Clusters {
21+
22+
/// Defines an interface for tracking a breadcrumb value.
23+
///
24+
/// The Breadcrumb attribute allows commissioners and administrators
25+
/// to save a small payload that can be subsequently read, to keep
26+
/// track of progress (see 11.10.6.1 of the Matter spec related
27+
/// to Breadcrumb Attribute in the General Commissioning Cluster).
28+
class BreadCrumbTracker
29+
{
30+
public:
31+
virtual ~BreadCrumbTracker() = default;
32+
virtual void SetBreadCrumb(uint64_t value) = 0;
33+
};
34+
35+
} // namespace chip::app::Clusters

src/app/clusters/general-commissioning-server/CodegenIntegration.cpp

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,13 @@
1515
* See the License for the specific language governing permissions and
1616
* limitations under the License.
1717
*/
18+
#include <app/clusters/general-commissioning-server/CodegenIntegration.h>
19+
1820
#include <app/clusters/general-commissioning-server/general-commissioning-cluster.h>
21+
#include <app/server-cluster/ServerClusterInterfaceRegistry.h>
1922
#include <app/static-cluster-config/GeneralCommissioning.h>
2023
#include <data-model-providers/codegen/ClusterIntegration.h>
24+
#include <lib/support/CodeUtils.h>
2125

2226
using namespace chip;
2327
using namespace chip::app;
@@ -42,7 +46,7 @@ static_assert((kGeneralCommissioningFixedClusterCount == 0) ||
4246
GeneralCommissioning::StaticApplicationConfig::kFixedClusterConfig[0].endpointNumber == kRootEndpointId),
4347
"General Commissioning cluster MUST be on endpoint 0");
4448

45-
ServerClusterRegistration gRegistration(GeneralCommissioningCluster::Instance());
49+
RegisteredServerCluster<GeneralCommissioningCluster> gRegistration;
4650

4751
class IntegrationDelegate : public CodegenClusterIntegration::Delegate
4852
{
@@ -51,23 +55,30 @@ class IntegrationDelegate : public CodegenClusterIntegration::Delegate
5155
uint32_t optionalAttributeBits, uint32_t featureMap) override
5256
{
5357
// Configure optional attributes based on fetched bits
54-
GeneralCommissioningCluster::Instance().GetOptionalAttributes() =
55-
GeneralCommissioningCluster::OptionalAttributes(optionalAttributeBits);
58+
gRegistration.Cluster().GetOptionalAttributes() = GeneralCommissioningCluster::OptionalAttributes(optionalAttributeBits);
5659

57-
return gRegistration;
60+
return gRegistration.Registration();
5861
}
5962

60-
ServerClusterInterface * FindRegistration(unsigned clusterInstanceIndex) override
61-
{
62-
return &GeneralCommissioningCluster::Instance();
63-
}
63+
ServerClusterInterface * FindRegistration(unsigned clusterInstanceIndex) override { return &gRegistration.Cluster(); }
6464

65-
// Nothing to destroy: separate singleton class without constructor/destructor is used
65+
// Nothing to destroy: gRegistration is a global static that handles destruction
6666
void ReleaseRegistration(unsigned clusterInstanceIndex) override {}
6767
};
6868

6969
} // namespace
7070

71+
namespace chip::app::Clusters::GeneralCommissioning {
72+
73+
GeneralCommissioningCluster * Instance()
74+
{
75+
// we ALWAYS return this for now, however in the future this may be instantiated
76+
// at runtime (i.e only after server is initialized.)
77+
return &gRegistration.Cluster();
78+
}
79+
80+
} // namespace chip::app::Clusters::GeneralCommissioning
81+
7182
void MatterGeneralCommissioningClusterInitCallback(EndpointId endpointId)
7283
{
7384
VerifyOrReturn(endpointId == kRootEndpointId);
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Copyright (c) 2025 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+
#pragma once
18+
19+
#include <app/clusters/general-commissioning-server/general-commissioning-cluster.h>
20+
21+
namespace chip {
22+
namespace app {
23+
namespace Clusters {
24+
namespace GeneralCommissioning {
25+
26+
/// Returns the singleton instance of the general commissioning cluster, if enabled.
27+
///
28+
/// This is a temporary integration point for ember-based apps.
29+
GeneralCommissioningCluster * Instance();
30+
31+
} // namespace GeneralCommissioning
32+
} // namespace Clusters
33+
} // namespace app
34+
} // namespace chip

src/app/clusters/general-commissioning-server/app_config_dependent_sources.gni

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,7 @@
1111
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
14-
app_config_dependent_sources = [ "CodegenIntegration.cpp" ]
14+
app_config_dependent_sources = [
15+
"CodegenIntegration.cpp",
16+
"CodegenIntegration.h",
17+
]

src/app/clusters/general-commissioning-server/general-commissioning-cluster.cpp

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -139,12 +139,12 @@ void NotifyTermsAndConditionsAttributeChangeIfRequired(const TermsAndConditionsS
139139
}
140140
#endif // CHIP_CONFIG_TERMS_AND_CONDITIONS_REQUIRED
141141

142-
void OnPlatformEventHandler(const DeviceLayer::ChipDeviceEvent * event, intptr_t /* arg */)
142+
void OnPlatformEventHandler(const DeviceLayer::ChipDeviceEvent * event, intptr_t self)
143143
{
144144
if (event->Type == DeviceLayer::DeviceEventType::kFailSafeTimerExpired)
145145
{
146146
// Spec says to reset Breadcrumb attribute to 0.
147-
GeneralCommissioningCluster::Instance().SetBreadCrumb(0);
147+
reinterpret_cast<GeneralCommissioningCluster *>(self)->SetBreadCrumb(0);
148148

149149
#if CHIP_CONFIG_TERMS_AND_CONDITIONS_REQUIRED
150150
if (event->FailSafeTimerExpired.updateTermsAndConditionsHasBeenInvoked)
@@ -161,16 +161,10 @@ void OnPlatformEventHandler(const DeviceLayer::ChipDeviceEvent * event, intptr_t
161161
}
162162
}
163163

164-
GeneralCommissioningCluster gInstance;
165164
} // anonymous namespace
166165

167166
namespace chip::app::Clusters {
168167

169-
GeneralCommissioningCluster & GeneralCommissioningCluster::Instance()
170-
{
171-
return gInstance;
172-
}
173-
174168
DataModel::ActionReturnStatus GeneralCommissioningCluster::ReadAttribute(const DataModel::ReadAttributeRequest & request,
175169
AttributeValueEncoder & encoder)
176170
{
@@ -403,14 +397,14 @@ void GeneralCommissioningCluster::SetBreadCrumb(uint64_t value)
403397
CHIP_ERROR GeneralCommissioningCluster::Startup(ServerClusterContext & context)
404398
{
405399
ReturnErrorOnFailure(DefaultServerCluster::Startup(context));
406-
PlatformMgrImpl().AddEventHandler(OnPlatformEventHandler, 0);
400+
PlatformMgrImpl().AddEventHandler(OnPlatformEventHandler, reinterpret_cast<intptr_t>(this));
407401
Server::GetInstance().GetFabricTable().AddFabricDelegate(this);
408402
return CHIP_NO_ERROR;
409403
}
410404

411405
void GeneralCommissioningCluster::Shutdown()
412406
{
413-
PlatformMgrImpl().RemoveEventHandler(OnPlatformEventHandler, 0);
407+
PlatformMgrImpl().RemoveEventHandler(OnPlatformEventHandler, reinterpret_cast<intptr_t>(this));
414408
Server::GetInstance().GetFabricTable().RemoveFabricDelegate(this);
415409
DefaultServerCluster::Shutdown();
416410
}

src/app/clusters/general-commissioning-server/general-commissioning-cluster.h

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#pragma once
1818

1919
#include <app/AppConfig.h>
20+
#include <app/clusters/general-commissioning-server/BreadCrumbTracker.h>
2021
#include <app/server-cluster/DefaultServerCluster.h>
2122
#include <app/server-cluster/OptionalAttributeSet.h>
2223
#include <clusters/GeneralCommissioning/AttributeIds.h>
@@ -28,7 +29,7 @@
2829

2930
namespace chip::app::Clusters {
3031

31-
class GeneralCommissioningCluster : public DefaultServerCluster, chip::FabricTable::Delegate
32+
class GeneralCommissioningCluster : public DefaultServerCluster, chip::FabricTable::Delegate, public BreadCrumbTracker
3233
{
3334
public:
3435
using OptionalAttributes = OptionalAttributeSet<GeneralCommissioning::Attributes::IsCommissioningWithoutPower::Id>;
@@ -37,7 +38,7 @@ class GeneralCommissioningCluster : public DefaultServerCluster, chip::FabricTab
3738

3839
OptionalAttributes & GetOptionalAttributes() { return mOptionalAttributes; }
3940

40-
void SetBreadCrumb(uint64_t value);
41+
void SetBreadCrumb(uint64_t value) final;
4142

4243
// Server cluster implementation
4344
CHIP_ERROR Startup(ServerClusterContext & context) override;
@@ -55,10 +56,7 @@ class GeneralCommissioningCluster : public DefaultServerCluster, chip::FabricTab
5556
CHIP_ERROR Attributes(const ConcreteClusterPath & path, ReadOnlyBufferBuilder<DataModel::AttributeEntry> & builder) override;
5657

5758
// Fabric delegate
58-
void OnFabricRemoved(const FabricTable & fabricTable, FabricIndex fabricIndex) override;
59-
60-
// GeneralCommissioning is a singleton cluster that exists only on the root endpoint.
61-
static GeneralCommissioningCluster & Instance();
59+
void OnFabricRemoved(const FabricTable & fabricTable, FabricIndex fabricIndex) final;
6260

6361
// Feature map constant based on compile-time defines. This ensures feature map
6462
// is in sync with the actual supported features determined at build time.

src/app/clusters/general-commissioning-server/tests/TestGeneralCommissioningCluster.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ TEST_F(TestGeneralCommissioningCluster, TestAttributes)
5151
{
5252
// test without optional attributes
5353
{
54-
auto & cluster = GeneralCommissioningCluster::Instance();
54+
GeneralCommissioningCluster cluster;
5555
auto & optionalAttributes = cluster.GetOptionalAttributes();
5656
optionalAttributes = GeneralCommissioningCluster::OptionalAttributes(0);
5757

@@ -87,7 +87,7 @@ TEST_F(TestGeneralCommissioningCluster, TestAttributes)
8787

8888
// test with optional attributes
8989
{
90-
auto & cluster = GeneralCommissioningCluster::Instance();
90+
GeneralCommissioningCluster cluster;
9191
auto & optionalAttributes = cluster.GetOptionalAttributes();
9292
optionalAttributes.Set<IsCommissioningWithoutPower::Id>();
9393

@@ -132,8 +132,8 @@ TEST_F(TestGeneralCommissioningCluster, TestAcceptedCommands)
132132
{
133133
{
134134
ReadOnlyBufferBuilder<AcceptedCommandEntry> builder;
135-
ASSERT_EQ(GeneralCommissioningCluster::Instance().AcceptedCommands({ kRootEndpointId, GeneralCommissioning::Id }, builder),
136-
CHIP_NO_ERROR);
135+
GeneralCommissioningCluster cluster;
136+
ASSERT_EQ(cluster.AcceptedCommands({ kRootEndpointId, GeneralCommissioning::Id }, builder), CHIP_NO_ERROR);
137137

138138
ReadOnlyBufferBuilder<AcceptedCommandEntry> expectedBuilder;
139139
ASSERT_EQ(expectedBuilder.AppendElements({

src/app/clusters/network-commissioning/BUILD.gn

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ source_set("network-commissioning") {
5959
":thread-response-encoding",
6060
":wifi-response-encoding",
6161
"${chip_root}/src/app:interaction-model",
62-
"${chip_root}/src/app/clusters/general-commissioning-server:general-commissioning-server",
62+
"${chip_root}/src/app/clusters/general-commissioning-server:bread-crumb-tracker",
6363
"${chip_root}/src/app/data-model-provider",
6464
"${chip_root}/src/app/server",
6565
"${chip_root}/src/app/server-cluster",

src/app/clusters/network-commissioning/CodegenInstance.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,27 @@
1616
*/
1717
#include "CodegenInstance.h"
1818

19+
#include <app/clusters/general-commissioning-server/CodegenIntegration.h>
20+
#include <app/clusters/general-commissioning-server/general-commissioning-cluster.h>
21+
#include <app/clusters/network-commissioning/NetworkCommissioningCluster.h>
1922
#include <data-model-providers/codegen/CodegenDataModelProvider.h>
2023

2124
namespace chip {
2225
namespace app {
2326
namespace Clusters {
2427
namespace NetworkCommissioning {
2528

29+
void Instance::CodegenGeneralCommissioningBreadcrumbTracker::SetBreadCrumb(uint64_t value)
30+
{
31+
GeneralCommissioningCluster * cluster = GeneralCommissioning::Instance();
32+
if (cluster == nullptr)
33+
{
34+
ChipLogError(Zcl, "General commissioning cluster not available. Failed to set breadcrumb.");
35+
return;
36+
}
37+
cluster->SetBreadCrumb(value);
38+
}
39+
2640
CHIP_ERROR Instance::Init()
2741
{
2842
ReturnErrorOnFailure(mCluster.Cluster().Init());

0 commit comments

Comments
 (0)