Skip to content

Commit 45e9715

Browse files
Power source: Implementation of dynamic endpoint list setter (#28110)
* Implementation of dynamic endpoint list setter Test: tested by adding a call to set endpoint list in all clusters with chip-tool. Also see TestPowerSourceCluster.cpp * Restyled by whitespace * Restyled by gn * Remove the define Some platforms run these tests, but don't have that define defined. Instead, just change the function name to test only. * Address review comments * free is being called, man, where's the leak? * Restyled by clang-format * Address some review comments. * Fix leak. * Deal with zero-length arrays. * shutdown -> clear * Use EncodeList for list * test fix. * types need to match --------- Co-authored-by: Restyled.io <commits@restyled.io>
1 parent 27c3ff4 commit 45e9715

File tree

4 files changed

+583
-17
lines changed

4 files changed

+583
-17
lines changed

src/app/clusters/power-source-server/power-source-server.cpp

+164-17
Original file line numberDiff line numberDiff line change
@@ -19,32 +19,82 @@
1919
* @brief Implementation for the Power Source Server Cluster
2020
***************************************************************************/
2121

22+
#include "power-source-server.h"
23+
2224
#include <app-common/zap-generated/cluster-objects.h>
2325
#include <app-common/zap-generated/ids/Attributes.h>
24-
#include <app-common/zap-generated/ids/Clusters.h>
25-
#include <app/AttributeAccessInterface.h>
2626
#include <app/util/attribute-storage.h>
2727
#include <lib/support/CodeUtils.h>
2828
#include <lib/support/logging/CHIPLogging.h>
29+
#include <zap-generated/gen_config.h>
2930

3031
using namespace chip;
31-
using namespace chip::app;
32-
using namespace chip::app::Clusters;
33-
using namespace chip::app::Clusters::PowerSource::Attributes;
32+
using namespace app;
33+
using namespace app::Clusters;
34+
using namespace app::Clusters::PowerSource::Attributes;
3435

3536
namespace {
3637

37-
class PowerSourceAttrAccess : public AttributeAccessInterface
38+
struct PowerSourceClusterInfo
3839
{
39-
public:
40-
// Register on all endpoints.
41-
PowerSourceAttrAccess() : AttributeAccessInterface(Optional<EndpointId>::Missing(), PowerSource::Id) {}
42-
43-
CHIP_ERROR Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) override;
40+
PowerSourceClusterInfo() : mClusterEndpoint(kInvalidEndpointId) {}
41+
explicit PowerSourceClusterInfo(EndpointId powerClusterEndpointId) : mClusterEndpoint(powerClusterEndpointId) {}
42+
void Clear()
43+
{
44+
mBuf.Free();
45+
mEndpointList = Span<EndpointId>();
46+
}
47+
CHIP_ERROR SetEndpointList(Span<EndpointId> endpointList)
48+
{
49+
Clear();
50+
if (endpointList.size() == 0)
51+
{
52+
mEndpointList = Span<EndpointId>();
53+
return CHIP_NO_ERROR;
54+
}
55+
mBuf.Calloc(endpointList.size());
56+
if (mBuf.Get() == nullptr)
57+
{
58+
return CHIP_ERROR_NO_MEMORY;
59+
}
60+
memcpy(mBuf.Get(), endpointList.data(), endpointList.size() * sizeof(EndpointId));
61+
mEndpointList = Span<EndpointId>(mBuf.Get(), endpointList.size());
62+
return CHIP_NO_ERROR;
63+
}
64+
EndpointId mClusterEndpoint = kInvalidEndpointId;
65+
Platform::ScopedMemoryBuffer<EndpointId> mBuf;
66+
Span<EndpointId> mEndpointList;
4467
};
4568

69+
PowerSourceServer gPowerSourceServer;
70+
4671
PowerSourceAttrAccess gAttrAccess;
4772

73+
#ifdef ZCL_USING_POWER_SOURCE_CLUSTER_SERVER
74+
#define POWER_SERVER_NUM_SUPPORTED_ENDPOINTS \
75+
(EMBER_AF_POWER_SOURCE_CLUSTER_SERVER_ENDPOINT_COUNT + CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT)
76+
#else
77+
#define POWER_SERVER_NUM_SUPPORTED_ENDPOINTS CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT
78+
#endif
79+
static constexpr size_t kNumSupportedEndpoints = POWER_SERVER_NUM_SUPPORTED_ENDPOINTS;
80+
81+
#if POWER_SERVER_NUM_SUPPORTED_ENDPOINTS > 0
82+
PowerSourceClusterInfo sPowerSourceClusterInfo[kNumSupportedEndpoints] = {};
83+
#else
84+
PowerSourceClusterInfo * sPowerSourceClusterInfo = nullptr;
85+
#endif
86+
87+
} // anonymous namespace
88+
89+
void MatterPowerSourcePluginServerInitCallback()
90+
{
91+
registerAttributeAccessOverride(&gAttrAccess);
92+
}
93+
94+
namespace chip {
95+
namespace app {
96+
namespace Clusters {
97+
4898
CHIP_ERROR PowerSourceAttrAccess::Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder)
4999
{
50100
CHIP_ERROR err = CHIP_NO_ERROR;
@@ -55,20 +105,117 @@ CHIP_ERROR PowerSourceAttrAccess::Read(const ConcreteReadAttributePath & aPath,
55105
// TODO: Needs implementation.
56106
err = aEncoder.EncodeEmptyList();
57107
break;
58-
case EndpointList::Id:
59-
// TODO: Needs implementation and a way to allow dynamic endpoints to register endpoints
60-
err = aEncoder.EncodeEmptyList();
108+
case EndpointList::Id: {
109+
PowerSourceServer & server = PowerSourceServer::Instance();
110+
const Span<EndpointId> * span = server.GetEndpointList(aPath.mEndpointId);
111+
if (span == nullptr)
112+
{
113+
err = aEncoder.EncodeEmptyList();
114+
}
115+
else
116+
{
117+
err = aEncoder.EncodeList([span](const auto & encoder) -> CHIP_ERROR {
118+
for (auto id : *span)
119+
{
120+
ReturnErrorOnFailure(encoder.Encode(id));
121+
}
122+
return CHIP_NO_ERROR;
123+
});
124+
}
61125
break;
126+
}
62127
default:
63128
break;
64129
}
65130

66131
return err;
67132
}
68133

69-
} // anonymous namespace
134+
PowerSourceAttrAccess & TestOnlyGetPowerSourceAttrAccess()
135+
{
136+
return gAttrAccess;
137+
}
70138

71-
void MatterPowerSourcePluginServerInitCallback()
139+
PowerSourceServer & PowerSourceServer::Instance()
72140
{
73-
registerAttributeAccessOverride(&gAttrAccess);
141+
return gPowerSourceServer;
142+
}
143+
144+
// Caller does not need to retain the span past the call point as these are copied into an internal storage
145+
CHIP_ERROR PowerSourceServer::SetEndpointList(EndpointId powerSourceClusterEndpoint, Span<EndpointId> endpointList)
146+
{
147+
// TODO: should check here that the power source cluster exists on the endpoint, but for now let's take the caller's word
148+
// for it
149+
150+
size_t idx = PowerSourceClusterEndpointIndex(powerSourceClusterEndpoint);
151+
if (idx >= kNumSupportedEndpoints)
152+
{
153+
idx = NextEmptyIndex();
154+
}
155+
if (idx >= kNumSupportedEndpoints)
156+
{
157+
return CHIP_ERROR_NO_MEMORY;
158+
}
159+
160+
sPowerSourceClusterInfo[idx].Clear();
161+
if (endpointList.size() == 0)
162+
{
163+
sPowerSourceClusterInfo[idx] = PowerSourceClusterInfo();
164+
}
165+
else
166+
{
167+
sPowerSourceClusterInfo[idx] = PowerSourceClusterInfo(powerSourceClusterEndpoint);
168+
sPowerSourceClusterInfo[idx].SetEndpointList(endpointList);
169+
}
170+
return CHIP_NO_ERROR;
171+
}
172+
const Span<EndpointId> * PowerSourceServer::GetEndpointList(EndpointId powerSourceClusterEndpoint) const
173+
{
174+
size_t idx = PowerSourceClusterEndpointIndex(powerSourceClusterEndpoint);
175+
if (idx != std::numeric_limits<size_t>::max())
176+
{
177+
return &sPowerSourceClusterInfo[idx].mEndpointList;
178+
}
179+
return nullptr;
180+
}
181+
182+
void PowerSourceServer::Shutdown()
183+
{
184+
for (size_t i = 0; i < kNumSupportedEndpoints; ++i)
185+
{
186+
sPowerSourceClusterInfo[i].Clear();
187+
}
188+
}
189+
190+
size_t PowerSourceServer::GetNumSupportedEndpointLists() const
191+
{
192+
return kNumSupportedEndpoints;
74193
}
194+
195+
size_t PowerSourceServer::PowerSourceClusterEndpointIndex(EndpointId endpointId) const
196+
{
197+
for (size_t i = 0; i < kNumSupportedEndpoints; ++i)
198+
{
199+
if (sPowerSourceClusterInfo[i].mClusterEndpoint == endpointId)
200+
{
201+
return i;
202+
}
203+
}
204+
return std::numeric_limits<size_t>::max();
205+
}
206+
207+
size_t PowerSourceServer::NextEmptyIndex() const
208+
{
209+
for (size_t i = 0; i < kNumSupportedEndpoints; ++i)
210+
{
211+
if (sPowerSourceClusterInfo[i].mClusterEndpoint == kInvalidEndpointId)
212+
{
213+
return i;
214+
}
215+
}
216+
return std::numeric_limits<size_t>::max();
217+
}
218+
219+
} // namespace Clusters
220+
} // namespace app
221+
} // namespace chip
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/*
2+
*
3+
* Copyright (c) 2023 Project CHIP Authors
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+
#pragma once
19+
20+
#include <app-common/zap-generated/ids/Clusters.h>
21+
#include <app/AttributeAccessInterface.h>
22+
#include <app/util/af-types.h>
23+
#include <app/util/basic-types.h>
24+
#include <lib/support/Span.h>
25+
#include <platform/CHIPDeviceConfig.h>
26+
27+
namespace chip {
28+
namespace app {
29+
namespace Clusters {
30+
31+
class PowerSourceServer
32+
{
33+
public:
34+
static PowerSourceServer & Instance();
35+
36+
// Caller does not need to retain the span past the call point as these are copied into an internal storage
37+
CHIP_ERROR SetEndpointList(EndpointId powerSourceClusterEndpoint, Span<EndpointId> endpointList);
38+
CHIP_ERROR ClearEndpointList(EndpointId powerSourceClusterEndpoint)
39+
{
40+
return SetEndpointList(powerSourceClusterEndpoint, Span<EndpointId>());
41+
}
42+
// returns nullptr if there's not endpoint list set for this power source cluster endpoint id.
43+
const Span<EndpointId> * GetEndpointList(EndpointId powerSourceClusterEndpoint) const;
44+
void Shutdown();
45+
size_t GetNumSupportedEndpointLists() const;
46+
47+
private:
48+
// Both return std::numeric_limits<size_t>::max() for not found
49+
size_t PowerSourceClusterEndpointIndex(EndpointId endpointId) const;
50+
size_t NextEmptyIndex() const;
51+
};
52+
53+
class PowerSourceAttrAccess : public AttributeAccessInterface
54+
{
55+
public:
56+
// Register on all endpoints.
57+
PowerSourceAttrAccess() : AttributeAccessInterface(Optional<EndpointId>::Missing(), PowerSource::Id) {}
58+
59+
CHIP_ERROR Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) override;
60+
};
61+
62+
PowerSourceAttrAccess & TestOnlyGetPowerSourceAttrAccess();
63+
64+
} // namespace Clusters
65+
} // namespace app
66+
} // namespace chip

src/app/tests/BUILD.gn

+14
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,18 @@ source_set("time-sync-data-provider-test-srcs") {
7878
]
7979
}
8080

81+
source_set("power-cluster-test-srcs") {
82+
sources = [
83+
"${chip_root}/src/app/clusters/power-source-server/power-source-server.cpp",
84+
]
85+
86+
public_deps = [
87+
"${chip_root}/src/app/common:cluster-objects",
88+
"${chip_root}/src/app/util/mock:mock_ember",
89+
"${chip_root}/src/lib/core",
90+
]
91+
}
92+
8193
source_set("scenes-table-test-srcs") {
8294
sources = [
8395
"${chip_root}/src/app/clusters/scenes-server/ExtensionFieldSets.h",
@@ -133,6 +145,7 @@ chip_test_suite("tests") {
133145
"TestNumericAttributeTraits.cpp",
134146
"TestOperationalStateDelegate.cpp",
135147
"TestPendingNotificationMap.cpp",
148+
"TestPowerSourceCluster.cpp",
136149
"TestReadInteraction.cpp",
137150
"TestReportingEngine.cpp",
138151
"TestSceneTable.cpp",
@@ -183,6 +196,7 @@ chip_test_suite("tests") {
183196
":binding-test-srcs",
184197
":operational-state-test-srcs",
185198
":ota-requestor-test-srcs",
199+
":power-cluster-test-srcs",
186200
":scenes-table-test-srcs",
187201
":time-sync-data-provider-test-srcs",
188202
"${chip_root}/src/app",

0 commit comments

Comments
 (0)