Skip to content

Commit 576c54a

Browse files
kkasperczyk-nonordicjm
authored andcommitted
doc: Improved the documentation related to Matter code-gen.
The way of handling data model related code changed in Matter a lot. Added advanced migration guide and updated the instruction for creating cluster extension. Signed-off-by: Kamil Kasperczyk <[email protected]>
1 parent d1409ee commit 576c54a

File tree

4 files changed

+215
-12
lines changed

4 files changed

+215
-12
lines changed

doc/nrf/links.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@
194194
.. _`Generate partition script`: https://github.com/nrfconnect/sdk-connectedhomeip/blob/bf45da8a28/scripts/tools/nrfconnect/nrfconnect_generate_partition.py
195195
.. _`Matter nRF Connect scripts`: https://github.com/nrfconnect/sdk-connectedhomeip/tree/bf45da8a28/scripts/tools/nrfconnect
196196
.. _`Matter nRF Connect Kconfig`: https://github.com/nrfconnect/sdk-connectedhomeip/blob/bf45da8a28/config/nrfconnect/chip-module/Kconfig
197+
.. _`Matter Clusters Code-Driven support`: https://github.com/nrfconnect/sdk-connectedhomeip/blob/bf45da8a28/src/app/common/templates/config-data.yaml
197198

198199
.. _`bt_nus_service.cpp`: https://github.com/nrfconnect/sdk-nrf/blob/main/samples/matter/common/src/bt_nus/bt_nus_service.cpp
199200
.. _`bt_nus_service.h`: https://github.com/nrfconnect/sdk-nrf/blob/main/samples/matter/common/src/bt_nus/bt_nus_service.h

doc/nrf/protocols/matter/getting_started/custom_clusters.rst

Lines changed: 146 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -798,19 +798,159 @@ Then, you need to implement the following command in the application code:
798798
// TODO: Implement the plugin server init callback.
799799
}
800800
801-
The same applies to the extended commands.
801+
Implement the extension handling in the application code
802+
********************************************************
802803

803-
.. note::
804+
The way you handle cluster extensions depends on whether the cluster that you want to extend is implemented using the code-driven approach or with ZAP-generated code.
805+
806+
If the cluster is implemented using the code-driven approach, you must inherit from this cluster delegate class and implement the methods to handle the customized part.
807+
Then, you must unregister the original cluster delegate and register the customized one.
808+
For example, if you want to extend the ``BasicInformation`` cluster, you need to implement it in the application code as follows:
809+
810+
* Inherit from the ``BasicInformationCluster`` class and override the methods to handle the customized part.
811+
812+
.. code-block:: C++
813+
814+
#include <app/clusters/basic-information/BasicInformationCluster.h>
815+
#include <app/server-cluster/ServerClusterContext.h>
816+
#include <app/server-cluster/ServerClusterInterface.h>
817+
818+
class BasicInformationExtension : public chip::app::Clusters::BasicInformationCluster {
819+
public:
820+
BasicInformationExtension() {}
821+
822+
/* Overrides the default BasicInformationCluster implementation. */
823+
chip::app::DataModel::ActionReturnStatus
824+
ReadAttribute(const chip::app::DataModel::ReadAttributeRequest &request,
825+
chip::app::AttributeValueEncoder &encoder) override;
826+
827+
CHIP_ERROR Attributes(const chip::app::ConcreteClusterPath &path,
828+
chip::ReadOnlyBufferBuilder<chip::app::DataModel::AttributeEntry> &builder) override;
829+
830+
CHIP_ERROR AcceptedCommands(const chip::app::ConcreteClusterPath &path,
831+
chip::ReadOnlyBufferBuilder<chip::app::DataModel::AcceptedCommandEntry> &builder) override;
832+
833+
CHIP_ERROR GeneratedCommands(const chip::app::ConcreteClusterPath &path,
834+
chip::ReadOnlyBufferBuilder<chip::app::DataModel::GeneratedCommandEntry> &builder) override;
835+
836+
CHIP_ERROR Attributes(const chip::app::ConcreteClusterPath &path,
837+
chip::ReadOnlyBufferBuilder<chip::app::DataModel::AttributeEntry> &builder) override;
838+
839+
chip::app::DataModel::ActionReturnStatus SetExtendedAttribute(bool newExtendedAttribute);
840+
841+
private:
842+
bool mExtendedAttribute;
843+
};
844+
845+
* Implement the body of overridden methods to handle the custom attributes, commands and events.
846+
847+
.. code-block:: C++
848+
849+
#include <app/util/attribute-storage.h>
850+
#include <clusters/BasicInformation/Events.h>
851+
#include <clusters/BasicInformation/Metadata.h>
852+
853+
using namespace chip;
854+
using namespace chip::app;
855+
856+
constexpr AttributeId kExtendedAttributeId = 0x17;
857+
858+
constexpr DataModel::AttributeEntry kExtraAttributeMetadata[] = {
859+
{ kExtendedAttributeId,
860+
{} /* qualities */,
861+
Access::Privilege::kView /* readPriv */,
862+
std::nullopt /* writePriv */ },
863+
};
864+
865+
DataModel::ActionReturnStatus BasicInformationExtension::SetExtendedAttribute(bool newExtendedAttribute)
866+
{
867+
mExtendedAttribute = newExtendedAttribute;
868+
return CHIP_NO_ERROR;
869+
}
870+
871+
DataModel::ActionReturnStatus BasicInformationExtension::ReadAttribute(const DataModel::ReadAttributeRequest &request,
872+
AttributeValueEncoder &encoder)
873+
{
874+
switch (request.path.mAttributeId) {
875+
case kExtendedAttributeId:
876+
return encoder.Encode(mExtendedAttribute);
877+
default:
878+
return chip::app::Clusters::BasicInformationCluster::ReadAttribute(request, encoder);
879+
}
880+
}
881+
882+
DataModel::ActionReturnStatus BasicInformationExtension::WriteAttribute(const DataModel::WriteAttributeRequest &request,
883+
AttributeValueDecoder &decoder)
884+
{
885+
switch (request.path.mAttributeId) {
886+
case kExtendedAttributeId:
887+
bool newExtendedAttribute;
888+
ReturnErrorOnFailure(decoder.Decode(newExtendedAttribute));
889+
return NotifyAttributeChangedIfSuccess(request.path.mAttributeId, SetExtendedAttribute(newExtendedAttribute));
890+
default:
891+
return chip::app::Clusters::BasicInformationCluster::WriteAttribute(request, decoder);
892+
}
893+
}
894+
895+
CHIP_ERROR BasicInformationExtension::Attributes(const ConcreteClusterPath &path,
896+
ReadOnlyBufferBuilder<DataModel::AttributeEntry> &builder)
897+
{
898+
ReturnErrorOnFailure(builder.ReferenceExisting(kExtraAttributeMetadata));
899+
900+
return chip::app::Clusters::BasicInformationCluster::Attributes(path, builder);
901+
}
804902

805-
Before the |NCS| v3.2.0, the extended commands callback were handled by the ``emberAf...`` functions.
806-
807-
For example, if you want to extend the ``BasicInformation`` cluster with the ``ExtendedCommand`` command, you need to implement it in the application code as follows:
903+
CHIP_ERROR BasicInformationExtension::AcceptedCommands(const ConcreteClusterPath &path,
904+
ReadOnlyBufferBuilder<DataModel::AcceptedCommandEntry> &builder)
905+
{
906+
/* The BasicInformationCluster does not have any commands, so it is not necessary to call the implementation of the base class. */
907+
static constexpr DataModel::AcceptedCommandEntry kAcceptedCommands[] = {
908+
Clusters::BasicInformation::Commands::ExtendedCommand::kMetadataEntry
909+
};
910+
return builder.ReferenceExisting(kAcceptedCommands);
911+
}
912+
913+
std::optional<DataModel::ActionReturnStatus>
914+
BasicInformationExtension::InvokeCommand(const DataModel::InvokeRequest &request, chip::TLV::TLVReader &input_arguments,
915+
CommandHandler *handler)
916+
{
917+
switch (request.path.mCommandId) {
918+
case Clusters::BasicInformation::Commands::ExtendedCommand::Id: {
919+
/* Implement the command handling logic here */
920+
}
921+
default:
922+
/* The BasicInformationCluster does not have any commands, so it is not necessary to call the implementation of the base class. */
923+
return Protocols::InteractionModel::Status::UnsupportedCommand;
924+
}
925+
}
926+
927+
* Unregister the original cluster delegate and register the customized one.
928+
929+
.. code-block:: C++
930+
931+
#include <data-model-providers/codegen/CodegenDataModelProvider.h>
932+
933+
/* Replaces the registered BasicInformation cluster with a customized one that adds random number handling. */
934+
auto &registry = chip::app::CodegenDataModelProvider::Instance().Registry();
935+
936+
ServerClusterInterface *interface =
937+
registry.Get({ kRootEndpointId, chip::app::Clusters::BasicInformation::Id });
938+
939+
VerifyOrDie(interface != nullptr);
940+
941+
registry.Unregister(interface);
942+
static RegisteredServerCluster<BasicInformationExtension> sBasicInformationExtension;
943+
944+
VerifyOrDie(registry.Register(sBasicInformationExtension.Registration()) == CHIP_NO_ERROR);
945+
946+
If the cluster is implemented with ZAP-generated code, you must implement the required extension callbacks by defining the appropriate ``emberAf...Callback`` functions, as described in the code examples and in the cluster XML.
947+
For example, if you want to extend the ``LevelControl`` cluster with the ``ExtendedCommand`` command, you need to implement it in the application code as follows:
808948

809949
.. code-block:: c
810950
811951
#include <app-common/zap-generated/callback.h>
812952
813-
bool emberAfBasicInformationClusterBasicInformationExtendedCommandCallback(chip::app::CommandHandler *commandObj, const chip::app::ConcreteCommandPath &commandPath,
953+
bool emberAfLevelControlClusterExtendedCommandCallback(chip::app::CommandHandler *commandObj, const chip::app::ConcreteCommandPath &commandPath,
814954
const chip::app::Clusters::BasicInformation::Commands::ExtendedCommand::DecodableType &commandData)
815955
{
816956
// TODO: Implement the command.

doc/nrf/releases_and_maturity/migration/migration_guide_3.2.rst

Lines changed: 66 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -104,11 +104,72 @@ Matter
104104

105105
To build your custom board with Wi-Fi support, set both the :kconfig:option:`CONFIG_CHIP_WIFI` and :kconfig:option:`CONFIG_WIFI_NRF70` Kconfig options to ``y``.
106106

107-
* The :file:`zap-generated` directory now includes the :file:`CodeDrivenCallback.h` and :file:`CodeDrivenInitShutdown.cpp` files.
108-
The Matter build system gradually moves to the new approach of data model handling and does not auto-generate some bits of a code responsible for command handling anymore.
109-
Invoking the ``west zap-generate`` command removes command handler implementations from the existing :file:`IMClusterCommandHandler.cpp` file.
110-
To fix this, you must now manually create the :file:`CodeDrivenCallback.h` and :file:`CodeDrivenInitShutdown.cpp` files, and implement the ``MatterClusterServerInitCallback`` and ``MatterClusterServerShutdownCallback`` callbacks to handle server initialization, shutdown, and Matter cluster commands.
111-
Ensure that these callbacks contain your application's command handling logic as required.
107+
* The Matter build system is transitioning to a code-driven approach for Data Model and Cluster configuration handling.
108+
This approach assumes gradual replacement of the configuration based on the ZAP files and the ZAP-generated code, and handling the configuration in the source code.
109+
This change has the following impacts:
110+
111+
* The :file:`zap-generated` directory now includes the :file:`CodeDrivenCallback.h` and :file:`CodeDrivenInitShutdown.cpp` files.
112+
Invoking the ``west zap-generate`` command removes command handler implementations from the existing :file:`IMClusterCommandHandler.cpp` file.
113+
To fix this, you must now manually create the :file:`CodeDrivenCallback.h` and :file:`CodeDrivenInitShutdown.cpp` files, and implement the ``MatterClusterServerInitCallback`` and ``MatterClusterServerShutdownCallback`` callbacks to handle server initialization, shutdown, and Matter cluster commands.
114+
Ensure that these callbacks contain your application's command handling logic.
115+
* The code-driven approach is not yet fully implemented for all available clusters, but the coverage will be increasing and it is used for the newly created clusters.
116+
The following clusters are already ported using the code-driven approach:
117+
118+
* Access Control
119+
* Administrator Commissioning
120+
* Basic Information
121+
* Binding
122+
* Boolean State
123+
* Descriptor
124+
* Diagnostic Logs
125+
* Ethernet Network Diagnostics
126+
* Fixed Label
127+
* General Commissioning
128+
* General Diagnostics
129+
* Group Key Management
130+
* Groupcast
131+
* Identify
132+
* Localization Configuration
133+
* OTA Software Update Provider
134+
* Operational Credentials
135+
* Push AV Stream Transport
136+
* Software Diagnostics
137+
* Time Format Localization
138+
* User Label
139+
* Wi-Fi Network Diagnostics
140+
141+
For the full list of clusters and their migration status, see the `Matter Clusters Code-Driven support`_ file.
142+
143+
* By default, all the mandatory attributes are enabled for the cluster.
144+
To enable an optional attribute or set an optional feature in the feature map, you must do that in the source code by calling dedicated methods.
145+
For example, to enable the Positioning feature and the ``CountdownTime`` optional attribute for the Closure Control cluster, perform the following operations:
146+
147+
* Implement a delegate class for the Closure Control cluster.
148+
See the :file:`samples/matter/closure/src/closure_control_endpoint.h` file for an example.
149+
* Enable the attribute and set the feature on cluster initialization.
150+
See the ``ClosureControlEndpoint::Init`` function in the :file:`samples/matter/closure/src/closure_control_endpoint.cpp` file for an example.
151+
152+
* To enable an optional cluster, you must register it in the source code by calling a dedicated method.
153+
For example, to enable the Identify cluster, implement the following code:
154+
155+
.. code-block:: C++
156+
157+
#include <data-model-providers/codegen/CodegenDataModelProvider.h>
158+
#include <app/clusters/identify-server/IdentifyCluster.h>
159+
160+
chip::app::RegisteredServerCluster<chip::app::Clusters::IdentifyCluster> mIdentifyCluster;
161+
chip::app::CodegenDataModelProvider::Instance().Registry().Register(mIdentifyCluster.Registration());
162+
163+
* To enable a cluster extension for the cluster that is already implemented using the code-driven approach, you must inherit from this cluster delegate class and implement the methods to handle the customized part.
164+
You also have to unregister the original cluster delegate and register the customized one.
165+
For example, to enable a cluster extension for the Basic Information cluster, perform the following operations:
166+
167+
* Inherit from the ``BasicInformationCluster`` class and override the methods to handle the customized part.
168+
See the :file:`samples/matter/manufacturer_specific/src/basic_information_extension.h` file for an example.
169+
* Implement the body of overridden methods to handle the custom attributes, commands, and events.
170+
See the :file:`samples/matter/manufacturer_specific/src/basic_information_extension.cpp` file for an example.
171+
* Unregister the original cluster delegate and register the customized one.
172+
See the ``AppTask::StartApp`` function in the :file:`samples/matter/manufacturer_specific/src/app_task.cpp` file for an example.
112173

113174
* :ref:`matter_lock_sample` sample:
114175

doc/nrf/releases_and_maturity/releases/release-notes-changelog.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,7 @@ The Matter fork in the |NCS| (``sdk-connectedhomeip``) contains all commits from
259259
* Added:
260260

261261
* Support for the following new device types:
262+
262263
* Irrigation System
263264
* Soil Sensor
264265
* Closure
@@ -284,10 +285,10 @@ The Matter fork in the |NCS| (``sdk-connectedhomeip``) contains all commits from
284285
For example, to enable a specific cluster or its attribute, the new model requires calling a dedicated delegate and registering the cluster in a source code.
285286
The code-driven approach is not yet fully implemented for all the available clusters, but the coverage will be increasing and it is used for the newly created clusters.
286287
The new model is meant to be backward compatible with the previous configuration based on the ZAP files and the ZAP-generated code, until the code-driven approach is fully implemented for all the available clusters.
288+
See the `Migration guide for nRF Connect SDK v3.2.0`_ for more information.
287289
* The :ref:`ug_matter_gs_tools_matter_west_commands_sync` command to synchronize the ZAP and :file:`zcl.json` files after updating the ZAP tool version.
288290
* The check to all :ref:`ug_matter_gs_tools_matter_west_commands_zap_tool` commands that verify whether ZAP tool sandbox permissions are correctly set.
289291
In case of detecting incorrect permissions, the command will prompt the user to accept automatically updating the permissions to required ones.
290-
291292
* Updated:
292293

293294
* The :ref:`ug_matter_gs_tools_matter_west_commands_append` command to accept ``--clusters`` argument instead of ``new_clusters`` argument.

0 commit comments

Comments
 (0)