Groupcast cluster server skeleton. (#41132)
* Groupcast cluster server skeleton.
* Code review.
* [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
---------
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
diff --git a/src/BUILD.gn b/src/BUILD.gn
index 84eb2a2..3192870 100644
--- a/src/BUILD.gn
+++ b/src/BUILD.gn
@@ -103,6 +103,7 @@
"${chip_root}/src/lib/dnssd/minimal_mdns/responders/tests",
"${chip_root}/src/lib/dnssd/minimal_mdns/tests",
"${chip_root}/src/lib/dnssd/tests",
+ "${chip_root}/src/app/clusters/groupcast/tests",
# TODO(#40932): Fix and re-enable the Commodity Tariff unit tests.
# "${chip_root}/src/app/clusters/commodity-tariff-server/tests",
diff --git a/src/app/clusters/groupcast/BUILD.gn b/src/app/clusters/groupcast/BUILD.gn
new file mode 100644
index 0000000..7f5ce6b
--- /dev/null
+++ b/src/app/clusters/groupcast/BUILD.gn
@@ -0,0 +1,29 @@
+# Copyright (c) 2025 Project CHIP Authors
+#
+# 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.
+import("//build_overrides/build.gni")
+import("//build_overrides/chip.gni")
+
+source_set("groupcast") {
+ sources = [
+ "GroupcastCluster.cpp",
+ "GroupcastCluster.h",
+ "GroupcastLogic.cpp",
+ "GroupcastLogic.h",
+ ]
+ public_deps = [
+ "${chip_root}/src/app/server",
+ "${chip_root}/src/app/server-cluster",
+ "${chip_root}/zzz_generated/app-common/clusters/Groupcast",
+ ]
+}
diff --git a/src/app/clusters/groupcast/CodegenIntegration.cpp b/src/app/clusters/groupcast/CodegenIntegration.cpp
new file mode 100644
index 0000000..75a6c03
--- /dev/null
+++ b/src/app/clusters/groupcast/CodegenIntegration.cpp
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2025 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 <app-common/zap-generated/attributes/Accessors.h>
+#include <app/clusters/groupcast/GroupcastCluster.h>
+#include <app/static-cluster-config/Groupcast.h>
+#include <app/util/attribute-storage.h>
+#include <app/util/endpoint-config-api.h>
+#include <data-model-providers/codegen/ClusterIntegration.h>
+
+using namespace chip::app;
+using namespace chip::app::Clusters;
+using namespace chip::app::Clusters::Groupcast::Attributes;
+using namespace chip::app::Clusters::Groupcast::StaticApplicationConfig;
+using chip::Protocols::InteractionModel::Status;
+
+namespace {
+
+LazyRegisteredServerCluster<GroupcastCluster> gServer;
+
+// Groupcast implementation is specifically implemented
+// only for the root endpoint (endpoint 0)
+
+static constexpr size_t kGroupcastFixedClusterCount = Groupcast::StaticApplicationConfig::kFixedClusterConfig.size();
+
+static_assert((kGroupcastFixedClusterCount == 0) ||
+ ((kGroupcastFixedClusterCount == 1) &&
+ Groupcast::StaticApplicationConfig::kFixedClusterConfig[0].endpointNumber == chip::kRootEndpointId),
+ "Groupcast cluster MUST be on endpoint 0");
+
+class IntegrationDelegate : public CodegenClusterIntegration::Delegate
+{
+public:
+ ServerClusterRegistration & CreateRegistration(chip::EndpointId endpointId, unsigned clusterInstanceIndex,
+ uint32_t optionalAttributeBits, uint32_t featureMap) override
+ {
+ // No optional attributes
+ gServer.Create();
+ return gServer.Registration();
+ }
+
+ ServerClusterInterface * FindRegistration(unsigned clusterInstanceIndex) override
+ {
+ VerifyOrReturnValue(gServer.IsConstructed(), nullptr);
+ return &gServer.Cluster();
+ }
+
+ // Nothing to destroy: separate singleton class without constructor/destructor is used
+ void ReleaseRegistration(unsigned clusterInstanceIndex) override { gServer.Destroy(); }
+};
+
+} // namespace
+
+void MatterGroupcastClusterInitCallback(chip::EndpointId endpointId)
+{
+ VerifyOrDie(endpointId == chip::kRootEndpointId);
+
+ IntegrationDelegate integrationDelegate;
+
+ // register a singleton server (root endpoint only)
+ CodegenClusterIntegration::RegisterServer(
+ {
+ .endpointId = endpointId,
+ .clusterId = Groupcast::Id,
+ .fixedClusterInstanceCount = Groupcast::StaticApplicationConfig::kFixedClusterConfig.size(),
+ .maxClusterInstanceCount = 1, // Cluster is a singleton on the root node and this is the only thing supported
+ .fetchFeatureMap = false,
+ .fetchOptionalAttributes = false,
+ },
+ integrationDelegate);
+}
+
+void MatterGroupcastClusterShutdownCallback(chip::EndpointId endpointId)
+{
+ VerifyOrDie(endpointId == chip::kRootEndpointId);
+
+ IntegrationDelegate integrationDelegate;
+
+ CodegenClusterIntegration::UnregisterServer(
+ {
+ .endpointId = endpointId,
+ .clusterId = Groupcast::Id,
+ .fixedClusterInstanceCount = Groupcast::StaticApplicationConfig::kFixedClusterConfig.size(),
+ .maxClusterInstanceCount = 1, // Cluster is a singleton on the root node and this is the only thing supported
+ },
+ integrationDelegate);
+}
+
+void MatterGroupcastPluginServerInitCallback() {}
+void MatterGroupcastPluginServerShutdownCallback() {}
diff --git a/src/app/clusters/groupcast/GroupcastCluster.cpp b/src/app/clusters/groupcast/GroupcastCluster.cpp
new file mode 100644
index 0000000..7347b7c
--- /dev/null
+++ b/src/app/clusters/groupcast/GroupcastCluster.cpp
@@ -0,0 +1,97 @@
+#include "GroupcastCluster.h"
+#include <app/server-cluster/AttributeListBuilder.h>
+#include <clusters/Groupcast/AttributeIds.h>
+#include <clusters/Groupcast/Attributes.h>
+#include <clusters/Groupcast/Metadata.h>
+
+using chip::Protocols::InteractionModel::Status;
+
+namespace chip {
+namespace app {
+namespace Clusters {
+namespace {
+
+constexpr DataModel::AcceptedCommandEntry kAcceptedCommands[] = {
+ Groupcast::Commands::JoinGroup::kMetadataEntry,
+ Groupcast::Commands::LeaveGroup::kMetadataEntry,
+ Groupcast::Commands::UpdateGroupKey::kMetadataEntry,
+ Groupcast::Commands::ExpireGracePeriod::kMetadataEntry,
+ Groupcast::Commands::ConfigureAuxiliaryACL::kMetadataEntry,
+};
+} // namespace
+
+GroupcastCluster::GroupcastCluster() : DefaultServerCluster({ kRootEndpointId, Groupcast::Id }) {}
+
+DataModel::ActionReturnStatus GroupcastCluster::ReadAttribute(const DataModel::ReadAttributeRequest & request,
+ AttributeValueEncoder & encoder)
+{
+ switch (request.path.mAttributeId)
+ {
+ case Groupcast::Attributes::FeatureMap::Id:
+ return encoder.Encode(mLogic.Features());
+ case Groupcast::Attributes::ClusterRevision::Id:
+ return encoder.Encode(Groupcast::kRevision);
+ case Groupcast::Attributes::Membership::Id:
+ return mLogic.ReadMembership(request.path.mEndpointId, encoder);
+ case Groupcast::Attributes::MaxMembershipCount::Id:
+ return mLogic.ReadMaxMembershipCount(request.path.mEndpointId, encoder);
+ }
+ return Protocols::InteractionModel::Status::UnsupportedAttribute;
+}
+
+CHIP_ERROR GroupcastCluster::Attributes(const ConcreteClusterPath & path,
+ ReadOnlyBufferBuilder<DataModel::AttributeEntry> & builder)
+{
+ AttributeListBuilder listBuilder(builder);
+ return listBuilder.Append(Span(Groupcast::Attributes::kMandatoryMetadata), {});
+}
+
+std::optional<DataModel::ActionReturnStatus> GroupcastCluster::InvokeCommand(const DataModel::InvokeRequest & request,
+ chip::TLV::TLVReader & arguments,
+ CommandHandler * handler)
+{
+ VerifyOrReturnValue(nullptr != handler, Protocols::InteractionModel::Status::InvalidAction);
+ FabricIndex fabric_index = handler->GetAccessingFabricIndex();
+ switch (request.path.mCommandId)
+ {
+ case Groupcast::Commands::JoinGroup::Id: {
+ Groupcast::Commands::JoinGroup::DecodableType data;
+ ReturnErrorOnFailure(data.Decode(arguments, fabric_index));
+ return mLogic.JoinGroup(fabric_index, data);
+ }
+ case Groupcast::Commands::LeaveGroup::Id: {
+ Groupcast::Commands::LeaveGroup::DecodableType data;
+ Groupcast::Commands::LeaveGroupResponse::Type response;
+ ReturnErrorOnFailure(data.Decode(arguments, fabric_index));
+ mLogic.LeaveGroup(fabric_index, data, response);
+ handler->AddResponse(request.path, response);
+ return std::nullopt;
+ }
+ case Groupcast::Commands::UpdateGroupKey::Id: {
+ Groupcast::Commands::UpdateGroupKey::DecodableType data;
+ ReturnErrorOnFailure(data.Decode(arguments, fabric_index));
+ return mLogic.UpdateGroupKey(fabric_index, data);
+ }
+ case Groupcast::Commands::ExpireGracePeriod::Id: {
+ Groupcast::Commands::ExpireGracePeriod::DecodableType data;
+ ReturnErrorOnFailure(data.Decode(arguments, fabric_index));
+ return mLogic.ExpireGracePeriod(fabric_index, data);
+ }
+ case Groupcast::Commands::ConfigureAuxiliaryACL::Id: {
+ Groupcast::Commands::ConfigureAuxiliaryACL::DecodableType data;
+ ReturnErrorOnFailure(data.Decode(arguments, fabric_index));
+ return mLogic.ConfigureAuxiliaryACL(fabric_index, data);
+ }
+ }
+ return Protocols::InteractionModel::Status::UnsupportedCommand;
+}
+
+CHIP_ERROR GroupcastCluster::AcceptedCommands(const ConcreteClusterPath & path,
+ ReadOnlyBufferBuilder<DataModel::AcceptedCommandEntry> & builder)
+{
+ return builder.ReferenceExisting(kAcceptedCommands);
+}
+
+} // namespace Clusters
+} // namespace app
+} // namespace chip
diff --git a/src/app/clusters/groupcast/GroupcastCluster.h b/src/app/clusters/groupcast/GroupcastCluster.h
new file mode 100644
index 0000000..b88bbbc
--- /dev/null
+++ b/src/app/clusters/groupcast/GroupcastCluster.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2025 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 "GroupcastLogic.h"
+#include <app/server-cluster/DefaultServerCluster.h>
+#include <lib/core/DataModelTypes.h>
+#include <protocols/interaction_model/StatusCode.h>
+
+namespace chip {
+namespace app {
+namespace Clusters {
+
+/**
+ * @brief Provides code-driven implementation for the Groupcast cluster server.
+ */
+class GroupcastCluster : public DefaultServerCluster
+{
+public:
+ GroupcastCluster();
+ virtual ~GroupcastCluster() {}
+
+ DataModel::ActionReturnStatus ReadAttribute(const DataModel::ReadAttributeRequest & request,
+ AttributeValueEncoder & encoder) override;
+ CHIP_ERROR Attributes(const ConcreteClusterPath & path, ReadOnlyBufferBuilder<DataModel::AttributeEntry> & builder) override;
+ std::optional<DataModel::ActionReturnStatus> InvokeCommand(const DataModel::InvokeRequest & request,
+ chip::TLV::TLVReader & arguments, CommandHandler * handler) override;
+ CHIP_ERROR AcceptedCommands(const ConcreteClusterPath & path,
+ ReadOnlyBufferBuilder<DataModel::AcceptedCommandEntry> & builder) override;
+
+private:
+ GroupcastLogic mLogic;
+};
+
+} // namespace Clusters
+} // namespace app
+} // namespace chip
diff --git a/src/app/clusters/groupcast/GroupcastLogic.cpp b/src/app/clusters/groupcast/GroupcastLogic.cpp
new file mode 100644
index 0000000..471384a
--- /dev/null
+++ b/src/app/clusters/groupcast/GroupcastLogic.cpp
@@ -0,0 +1,52 @@
+#include "GroupcastLogic.h"
+
+namespace chip {
+namespace app {
+namespace Clusters {
+
+CHIP_ERROR GroupcastLogic::ReadMembership(EndpointId endpoint, AttributeValueEncoder & aEncoder)
+{
+ return CHIP_ERROR_NOT_IMPLEMENTED;
+}
+
+CHIP_ERROR GroupcastLogic::ReadMaxMembershipCount(EndpointId endpoint, AttributeValueEncoder & aEncoder)
+{
+ return CHIP_ERROR_NOT_IMPLEMENTED;
+}
+
+CHIP_ERROR GroupcastLogic::JoinGroup(FabricIndex fabric_index, const Groupcast::Commands::JoinGroup::DecodableType & data)
+{
+ return CHIP_ERROR_NOT_IMPLEMENTED;
+}
+
+CHIP_ERROR GroupcastLogic::LeaveGroup(FabricIndex fabric_index, const Groupcast::Commands::LeaveGroup::DecodableType & data,
+ Groupcast::Commands::LeaveGroupResponse::Type & response)
+{
+ return CHIP_ERROR_NOT_IMPLEMENTED;
+}
+
+CHIP_ERROR GroupcastLogic::UpdateGroupKey(FabricIndex fabric_index, const Groupcast::Commands::UpdateGroupKey::DecodableType & data)
+{
+ return CHIP_ERROR_NOT_IMPLEMENTED;
+}
+
+CHIP_ERROR GroupcastLogic::ExpireGracePeriod(FabricIndex fabric_index,
+ const Groupcast::Commands::ExpireGracePeriod::DecodableType & data)
+{
+ return CHIP_ERROR_NOT_IMPLEMENTED;
+}
+
+CHIP_ERROR GroupcastLogic::ConfigureAuxiliaryACL(FabricIndex fabric_index,
+ const Groupcast::Commands::ConfigureAuxiliaryACL::DecodableType & data)
+{
+ return CHIP_ERROR_NOT_IMPLEMENTED;
+}
+
+CHIP_ERROR GroupcastLogic::RegisterAccessControl(FabricIndex fabric_index, GroupId group_id)
+{
+ return CHIP_ERROR_NOT_IMPLEMENTED;
+}
+
+} // namespace Clusters
+} // namespace app
+} // namespace chip
diff --git a/src/app/clusters/groupcast/GroupcastLogic.h b/src/app/clusters/groupcast/GroupcastLogic.h
new file mode 100644
index 0000000..b4b9af7
--- /dev/null
+++ b/src/app/clusters/groupcast/GroupcastLogic.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2025 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/AttributeValueDecoder.h>
+#include <app/AttributeValueEncoder.h>
+#include <app/data-model-provider/ActionReturnStatus.h>
+#include <clusters/Groupcast/AttributeIds.h>
+#include <clusters/Groupcast/ClusterId.h>
+#include <clusters/Groupcast/CommandIds.h>
+#include <clusters/Groupcast/Commands.h>
+#include <clusters/Groupcast/Enums.h>
+#include <lib/core/CHIPError.h>
+#include <lib/core/DataModelTypes.h>
+
+namespace chip {
+namespace app {
+namespace Clusters {
+
+/**
+ * @brief Implements the Matter specifications for the Groupcast cluster
+ */
+class GroupcastLogic
+{
+public:
+ GroupcastLogic() : mFeatures(0) {}
+ const BitFlags<Groupcast::Feature> & Features() const { return mFeatures; }
+
+ CHIP_ERROR ReadMembership(EndpointId endpoint, AttributeValueEncoder & aEncoder);
+ CHIP_ERROR ReadMaxMembershipCount(EndpointId endpoint, AttributeValueEncoder & aEncoder);
+
+ CHIP_ERROR JoinGroup(FabricIndex fabric_index, const Groupcast::Commands::JoinGroup::DecodableType & data);
+ CHIP_ERROR LeaveGroup(FabricIndex fabric_index, const Groupcast::Commands::LeaveGroup::DecodableType & data,
+ Groupcast::Commands::LeaveGroupResponse::Type & response);
+ CHIP_ERROR UpdateGroupKey(FabricIndex fabric_index, const Groupcast::Commands::UpdateGroupKey::DecodableType & data);
+ CHIP_ERROR ExpireGracePeriod(FabricIndex fabric_index, const Groupcast::Commands::ExpireGracePeriod::DecodableType & data);
+ CHIP_ERROR ConfigureAuxiliaryACL(FabricIndex fabric_index,
+ const Groupcast::Commands::ConfigureAuxiliaryACL::DecodableType & data);
+
+private:
+ CHIP_ERROR RegisterAccessControl(FabricIndex fabric_index, GroupId group_id);
+
+ const BitFlags<Groupcast::Feature> mFeatures;
+};
+
+} // namespace Clusters
+} // namespace app
+} // namespace chip
diff --git a/src/app/clusters/groupcast/app_config_dependent_sources.cmake b/src/app/clusters/groupcast/app_config_dependent_sources.cmake
new file mode 100644
index 0000000..47f3fc8
--- /dev/null
+++ b/src/app/clusters/groupcast/app_config_dependent_sources.cmake
@@ -0,0 +1,30 @@
+# Copyright (c) 2025 Project CHIP Authors
+#
+# 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.
+
+# This is the equivalent to app_config_dependent_sources.gni
+TARGET_SOURCES(
+ ${APP_TARGET}
+ PRIVATE
+ "${CLUSTER_DIR}/CodegenIntegration.cpp"
+)
+
+# These are the things that BUILD.gn dependencies would pull
+TARGET_SOURCES(
+ ${APP_TARGET}
+ PRIVATE
+ "${CLUSTER_DIR}/GroupcastCluster.cpp"
+ "${CLUSTER_DIR}/GroupcastCluster.h"
+ "${CLUSTER_DIR}/GroupcastLogic.cpp"
+ "${CLUSTER_DIR}/GroupcastLogic.h"
+)
diff --git a/src/app/clusters/groupcast/app_config_dependent_sources.gni b/src/app/clusters/groupcast/app_config_dependent_sources.gni
new file mode 100644
index 0000000..2c3232e
--- /dev/null
+++ b/src/app/clusters/groupcast/app_config_dependent_sources.gni
@@ -0,0 +1,14 @@
+# Copyright (c) 2025 Project CHIP Authors
+#
+# 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.
+app_config_dependent_sources = [ "CodegenIntegration.cpp" ]
diff --git a/src/app/clusters/groupcast/tests/BUILD.gn b/src/app/clusters/groupcast/tests/BUILD.gn
new file mode 100644
index 0000000..ecd0771
--- /dev/null
+++ b/src/app/clusters/groupcast/tests/BUILD.gn
@@ -0,0 +1,33 @@
+# Copyright (c) 2025 Project CHIP Authors
+#
+# 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.
+
+import("//build_overrides/build.gni")
+import("//build_overrides/chip.gni")
+
+import("${chip_root}/build/chip/chip_test_suite.gni")
+
+chip_test_suite("tests") {
+ output_name = "libTestGroupcastCluster"
+
+ test_sources = [ "TestGroupcastCluster.cpp" ]
+
+ cflags = [ "-Wconversion" ]
+
+ public_deps = [
+ "${chip_root}/src/app/clusters/groupcast",
+ "${chip_root}/src/app/clusters/testing",
+ "${chip_root}/src/lib/core:string-builder-adapters",
+ "${chip_root}/src/lib/support",
+ ]
+}
diff --git a/src/app/clusters/groupcast/tests/TestGroupcastCluster.cpp b/src/app/clusters/groupcast/tests/TestGroupcastCluster.cpp
new file mode 100644
index 0000000..ea5308d
--- /dev/null
+++ b/src/app/clusters/groupcast/tests/TestGroupcastCluster.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2025 Project CHIP Authors
+ *
+ * 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 <pw_unit_test/framework.h>
+
+#include <app/clusters/groupcast/GroupcastCluster.h>
+#include <app/clusters/testing/AttributeTesting.h>
+#include <app/data-model-provider/MetadataTypes.h>
+#include <app/server-cluster/DefaultServerCluster.h>
+#include <clusters/Groupcast/Enums.h>
+#include <clusters/Groupcast/Metadata.h>
+#include <lib/core/CHIPError.h>
+#include <lib/core/DataModelTypes.h>
+#include <lib/support/BitFlags.h>
+#include <lib/support/ReadOnlyBuffer.h>
+#include <platform/NetworkCommissioning.h>
+
+namespace {
+
+using namespace chip;
+using namespace chip::app::Clusters::Groupcast;
+
+using chip::app::DataModel::AcceptedCommandEntry;
+using chip::app::DataModel::AttributeEntry;
+
+// initialize memory as ReadOnlyBufferBuilder may allocate
+struct TestGroupcastCluster : public ::testing::Test
+{
+ static void SetUpTestSuite() { ASSERT_EQ(Platform::MemoryInit(), CHIP_NO_ERROR); }
+ static void TearDownTestSuite() { Platform::MemoryShutdown(); }
+};
+
+TEST_F(TestGroupcastCluster, TestAttributes)
+{
+ app::Clusters::GroupcastCluster cluster;
+
+ // Attributes
+ {
+ ReadOnlyBufferBuilder<AttributeEntry> builder;
+ ASSERT_EQ(cluster.Attributes({ kRootEndpointId, chip::app::Clusters::Groupcast::Id }, builder), CHIP_NO_ERROR);
+
+ ReadOnlyBufferBuilder<AttributeEntry> expectedBuilder;
+ ASSERT_EQ(expectedBuilder.AppendElements({
+ Attributes::Membership::kMetadataEntry,
+ Attributes::MaxMembershipCount::kMetadataEntry,
+ }),
+ CHIP_NO_ERROR);
+ ASSERT_EQ(expectedBuilder.ReferenceExisting(app::DefaultServerCluster::GlobalAttributes()), CHIP_NO_ERROR);
+ ASSERT_TRUE(Testing::EqualAttributeSets(builder.TakeBuffer(), expectedBuilder.TakeBuffer()));
+ }
+}
+
+} // namespace
diff --git a/src/app/common/templates/config-data.yaml b/src/app/common/templates/config-data.yaml
index bec9bca..c5075a7 100644
--- a/src/app/common/templates/config-data.yaml
+++ b/src/app/common/templates/config-data.yaml
@@ -50,6 +50,7 @@
- General Commissioning
- General Diagnostics
- Group Key Management
+ - Groupcast
- HEPA Filter Monitoring
- Joint Fabric Administrator
- Laundry Washer Mode
@@ -152,6 +153,7 @@
- General Commissioning
- General Diagnostics
- Group Key Management
+ - Groupcast
- Localization Configuration
- OTA Software Update Provider
- Operational Credentials
diff --git a/src/app/zap_cluster_list.json b/src/app/zap_cluster_list.json
index 6dfb44e..f9a5780 100644
--- a/src/app/zap_cluster_list.json
+++ b/src/app/zap_cluster_list.json
@@ -216,7 +216,7 @@
"ELECTRICAL_GRID_CONDITIONS_CLUSTER": [
"electrical-grid-conditions-server"
],
- "GROUPCAST_CLUSTER": [],
+ "GROUPCAST_CLUSTER": ["groupcast-server"],
"METER_IDENTIFICATION_CLUSTER": ["meter-identification-server"],
"MICROWAVE_OVEN_MODE_CLUSTER": ["mode-base-server"],
"DOOR_LOCK_CLUSTER": ["door-lock-server"],
diff --git a/zzz_generated/app-common/app-common/zap-generated/callback.h b/zzz_generated/app-common/app-common/zap-generated/callback.h
index a73f5f0..702eeed 100644
--- a/zzz_generated/app-common/app-common/zap-generated/callback.h
+++ b/zzz_generated/app-common/app-common/zap-generated/callback.h
@@ -7149,36 +7149,6 @@
chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath,
const chip::app::Clusters::DishwasherAlarm::Commands::ModifyEnabledAlarms::DecodableType & commandData);
/**
- * @brief Groupcast Cluster JoinGroup Command callback (from client)
- */
-bool emberAfGroupcastClusterJoinGroupCallback(
- chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath,
- const chip::app::Clusters::Groupcast::Commands::JoinGroup::DecodableType & commandData);
-/**
- * @brief Groupcast Cluster LeaveGroup Command callback (from client)
- */
-bool emberAfGroupcastClusterLeaveGroupCallback(
- chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath,
- const chip::app::Clusters::Groupcast::Commands::LeaveGroup::DecodableType & commandData);
-/**
- * @brief Groupcast Cluster UpdateGroupKey Command callback (from client)
- */
-bool emberAfGroupcastClusterUpdateGroupKeyCallback(
- chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath,
- const chip::app::Clusters::Groupcast::Commands::UpdateGroupKey::DecodableType & commandData);
-/**
- * @brief Groupcast Cluster ExpireGracePeriod Command callback (from client)
- */
-bool emberAfGroupcastClusterExpireGracePeriodCallback(
- chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath,
- const chip::app::Clusters::Groupcast::Commands::ExpireGracePeriod::DecodableType & commandData);
-/**
- * @brief Groupcast Cluster ConfigureAuxiliaryACL Command callback (from client)
- */
-bool emberAfGroupcastClusterConfigureAuxiliaryACLCallback(
- chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath,
- const chip::app::Clusters::Groupcast::Commands::ConfigureAuxiliaryACL::DecodableType & commandData);
-/**
* @brief Boolean State Configuration Cluster SuppressAlarm Command callback (from client)
*/
bool emberAfBooleanStateConfigurationClusterSuppressAlarmCallback(