Skip to content

Commit 49dc39f

Browse files
kkasperczyk-nocarlescufi
authored andcommitted
samples: matter: Fixed extension handling for manufacturer sample
The extension handling did not work for basic information cluster and it had to be aligned with the new code-gen style. Created an extension class that inherits by BasicInformation cluster and implements custom attribute, command and event handling. Signed-off-by: Kamil Kasperczyk <[email protected]>
1 parent 8df0fe6 commit 49dc39f

File tree

5 files changed

+162
-25
lines changed

5 files changed

+162
-25
lines changed

samples/matter/manufacturer_specific/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ target_sources(app PRIVATE
3636
src/app_task.cpp
3737
src/zcl_callbacks.cpp
3838
src/main.cpp
39+
src/basic_information_extension.cpp
3940
)
4041

4142
ncs_configure_data_model(

samples/matter/manufacturer_specific/src/app_task.cpp

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
#include "app_task.h"
88

9+
#include "basic_information_extension.h"
10+
911
#include "app/matter_init.h"
1012
#include "app/task_executor.h"
1113
#include "board/board.h"
@@ -18,6 +20,8 @@
1820
#include <app/util/attribute-storage.h>
1921
#include <setup_payload/OnboardingCodesUtil.h>
2022

23+
#include <data-model-providers/codegen/CodegenDataModelProvider.h>
24+
2125
#include <dk_buttons_and_leds.h>
2226
#include <zephyr/logging/log.h>
2327
#include <zephyr/random/random.h>
@@ -33,6 +37,8 @@ namespace
3337
#define BUTTON2_MASK DK_BTN2_MSK
3438
constexpr EndpointId kBasicInformationEndpointId = 0;
3539
constexpr EndpointId kNordicDevKitEndpointId = 1;
40+
41+
RegisteredServerCluster<BasicInformationExtension> sBasicInformationExtension;
3642
} /* namespace */
3743

3844
static void ButtonEventHandler(Nrf::ButtonState /* unused */, Nrf::ButtonMask has_changed)
@@ -81,23 +87,11 @@ void AppTask::UpdateNordicDevkitClusterState()
8187
void AppTask::UpdateBasicInformationClusterState()
8288
{
8389
SystemLayer().ScheduleLambda([] {
84-
Protocols::InteractionModel::Status status;
85-
86-
status = Clusters::BasicInformation::Attributes::RandomNumber::Set(kBasicInformationEndpointId,
87-
sys_rand16_get());
88-
89-
if (status != Protocols::InteractionModel::Status::Success) {
90-
LOG_ERR("Updating Basic information cluster failed: %x", to_underlying(status));
91-
}
90+
DataModel::ActionReturnStatus status =
91+
sBasicInformationExtension.Cluster().SetRandomNumber(sys_rand16_get());
9292

93-
for (auto endpoint : EnabledEndpointsWithServerCluster(Clusters::BasicInformation::Id)) {
94-
/* If Basic cluster is implemented on this endpoint */
95-
Clusters::BasicInformation::Events::RandomNumberChanged::Type event;
96-
EventNumber eventNumber;
97-
98-
if (CHIP_NO_ERROR != LogEvent(event, endpoint, eventNumber)) {
99-
ChipLogError(Zcl, "Failed to emit RandomNumberChanged event");
100-
}
93+
if (status != CHIP_NO_ERROR) {
94+
ChipLogError(Zcl, "Updating Basic information cluster failed");
10195
}
10296
});
10397
}
@@ -123,6 +117,17 @@ CHIP_ERROR AppTask::StartApp()
123117
{
124118
ReturnErrorOnFailure(Init());
125119

120+
/* Replaces the registered BasicInformation cluster with a customized one that adds random number handling. */
121+
auto &registry = chip::app::CodegenDataModelProvider::Instance().Registry();
122+
123+
ServerClusterInterface *interface =
124+
registry.Get({ kRootEndpointId, chip::app::Clusters::BasicInformation::Id });
125+
126+
VerifyOrDie(interface != nullptr);
127+
128+
registry.Unregister(interface);
129+
VerifyOrDie(registry.Register(sBasicInformationExtension.Registration()) == CHIP_NO_ERROR);
130+
126131
while (true) {
127132
Nrf::DispatchNextTask();
128133
}
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
/*
2+
* Copyright (c) 2025 Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
*/
6+
7+
#include "basic_information_extension.h"
8+
9+
#include <app/EventLogging.h>
10+
#include <app/util/attribute-storage.h>
11+
#include <clusters/BasicInformation/Events.h>
12+
#include <clusters/BasicInformation/Metadata.h>
13+
14+
using namespace chip;
15+
using namespace chip::app;
16+
17+
constexpr AttributeId kRandomNumberAttributeId = 0x17;
18+
19+
constexpr DataModel::AttributeEntry kExtraAttributeMetadata[] = {
20+
{ kRandomNumberAttributeId,
21+
{} /* qualities */,
22+
Access::Privilege::kView /* readPriv */,
23+
std::nullopt /* writePriv */ },
24+
};
25+
26+
DataModel::ActionReturnStatus BasicInformationExtension::SetRandomNumber(int16_t newRandomNumber)
27+
{
28+
mRandomNumber = newRandomNumber;
29+
30+
Clusters::BasicInformation::Events::RandomNumberChanged::Type event;
31+
EventNumber eventNumber;
32+
33+
for (auto endpoint : EnabledEndpointsWithServerCluster(Clusters::BasicInformation::Id)) {
34+
/* If Basic cluster is implemented on this endpoint */
35+
if (CHIP_NO_ERROR != LogEvent(event, endpoint, eventNumber)) {
36+
ChipLogError(Zcl, "Failed to emit RandomNumberChanged event");
37+
}
38+
}
39+
40+
return CHIP_NO_ERROR;
41+
}
42+
43+
DataModel::ActionReturnStatus BasicInformationExtension::ReadAttribute(const DataModel::ReadAttributeRequest &request,
44+
AttributeValueEncoder &encoder)
45+
{
46+
switch (request.path.mAttributeId) {
47+
case kRandomNumberAttributeId:
48+
return encoder.Encode(mRandomNumber);
49+
default:
50+
return chip::app::Clusters::BasicInformationCluster::ReadAttribute(request, encoder);
51+
}
52+
}
53+
54+
DataModel::ActionReturnStatus BasicInformationExtension::WriteAttribute(const DataModel::WriteAttributeRequest &request,
55+
AttributeValueDecoder &decoder)
56+
{
57+
switch (request.path.mAttributeId) {
58+
case kRandomNumberAttributeId:
59+
int16_t newRandomNumber;
60+
ReturnErrorOnFailure(decoder.Decode(newRandomNumber));
61+
return NotifyAttributeChangedIfSuccess(request.path.mAttributeId, SetRandomNumber(newRandomNumber));
62+
default:
63+
return chip::app::Clusters::BasicInformationCluster::WriteAttribute(request, decoder);
64+
}
65+
}
66+
67+
CHIP_ERROR BasicInformationExtension::Attributes(const ConcreteClusterPath &path,
68+
ReadOnlyBufferBuilder<DataModel::AttributeEntry> &builder)
69+
{
70+
ReturnErrorOnFailure(builder.ReferenceExisting(kExtraAttributeMetadata));
71+
72+
return chip::app::Clusters::BasicInformationCluster::Attributes(path, builder);
73+
}
74+
75+
CHIP_ERROR BasicInformationExtension::AcceptedCommands(const ConcreteClusterPath &path,
76+
ReadOnlyBufferBuilder<DataModel::AcceptedCommandEntry> &builder)
77+
{
78+
/* The BasicInformationCluster does not have any commands, so it is not necessary to call the implementation of the base class. */
79+
static constexpr DataModel::AcceptedCommandEntry kAcceptedCommands[] = {
80+
Clusters::BasicInformation::Commands::GenerateRandom::kMetadataEntry
81+
};
82+
return builder.ReferenceExisting(kAcceptedCommands);
83+
}
84+
85+
std::optional<DataModel::ActionReturnStatus>
86+
BasicInformationExtension::InvokeCommand(const DataModel::InvokeRequest &request, chip::TLV::TLVReader &input_arguments,
87+
CommandHandler *handler)
88+
{
89+
switch (request.path.mCommandId) {
90+
case Clusters::BasicInformation::Commands::GenerateRandom::Id: {
91+
return SetRandomNumber(sys_rand16_get());
92+
}
93+
default:
94+
/* The BasicInformationCluster does not have any commands, so it is not necessary to call the implementation of the base class. */
95+
return Protocols::InteractionModel::Status::UnsupportedCommand;
96+
}
97+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Copyright (c) 2025 Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
*/
6+
7+
#pragma once
8+
9+
#include <app/clusters/basic-information/BasicInformationCluster.h>
10+
#include <app/server-cluster/ServerClusterContext.h>
11+
#include <app/server-cluster/ServerClusterInterface.h>
12+
13+
#include <zephyr/random/random.h>
14+
15+
class BasicInformationExtension : public chip::app::Clusters::BasicInformationCluster {
16+
public:
17+
BasicInformationExtension() : mRandomNumber(sys_rand16_get()) {}
18+
19+
chip::app::DataModel::ActionReturnStatus SetRandomNumber(int16_t newRandomNumber);
20+
21+
/* Overrides the default BasicInformationCluster implementation. */
22+
chip::app::DataModel::ActionReturnStatus
23+
ReadAttribute(const chip::app::DataModel::ReadAttributeRequest &request,
24+
chip::app::AttributeValueEncoder &encoder) override;
25+
26+
chip::app::DataModel::ActionReturnStatus
27+
WriteAttribute(const chip::app::DataModel::WriteAttributeRequest &request,
28+
chip::app::AttributeValueDecoder &decoder) override;
29+
30+
CHIP_ERROR Attributes(const chip::app::ConcreteClusterPath &path,
31+
chip::ReadOnlyBufferBuilder<chip::app::DataModel::AttributeEntry> &builder) override;
32+
33+
CHIP_ERROR
34+
AcceptedCommands(const chip::app::ConcreteClusterPath &path,
35+
chip::ReadOnlyBufferBuilder<chip::app::DataModel::AcceptedCommandEntry> &builder) override;
36+
37+
std::optional<chip::app::DataModel::ActionReturnStatus>
38+
InvokeCommand(const chip::app::DataModel::InvokeRequest &request, chip::TLV::TLVReader &input_arguments,
39+
chip::app::CommandHandler *handler) override;
40+
41+
private:
42+
int16_t mRandomNumber;
43+
};

samples/matter/manufacturer_specific/src/zcl_callbacks.cpp

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -80,15 +80,6 @@ void emberAfNordicDevKitClusterInitCallback(EndpointId endpoint)
8080
}
8181
}
8282

83-
bool emberAfBasicInformationClusterGenerateRandomCallback(CommandHandler *commandObj,
84-
const ConcreteCommandPath &commandPath,
85-
const GenerateRandom::DecodableType & /* unused */)
86-
{
87-
AppTask::Instance().UpdateBasicInformationClusterState();
88-
commandObj->AddStatus(commandPath, Protocols::InteractionModel::Status::Success);
89-
return true;
90-
}
91-
9283
/** @brief Basic Information Cluster Init
9384
*
9485
* This function is called when a specific cluster is initialized. It gives the

0 commit comments

Comments
 (0)