Skip to content

Commit

Permalink
Power source: Implementation of dynamic endpoint list setter (#28110)
Browse files Browse the repository at this point in the history
* 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 <[email protected]>
  • Loading branch information
cecille and restyled-commits authored Aug 4, 2023
1 parent 27c3ff4 commit 45e9715
Show file tree
Hide file tree
Showing 4 changed files with 583 additions and 17 deletions.
181 changes: 164 additions & 17 deletions src/app/clusters/power-source-server/power-source-server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,32 +19,82 @@
* @brief Implementation for the Power Source Server Cluster
***************************************************************************/

#include "power-source-server.h"

#include <app-common/zap-generated/cluster-objects.h>
#include <app-common/zap-generated/ids/Attributes.h>
#include <app-common/zap-generated/ids/Clusters.h>
#include <app/AttributeAccessInterface.h>
#include <app/util/attribute-storage.h>
#include <lib/support/CodeUtils.h>
#include <lib/support/logging/CHIPLogging.h>
#include <zap-generated/gen_config.h>

using namespace chip;
using namespace chip::app;
using namespace chip::app::Clusters;
using namespace chip::app::Clusters::PowerSource::Attributes;
using namespace app;
using namespace app::Clusters;
using namespace app::Clusters::PowerSource::Attributes;

namespace {

class PowerSourceAttrAccess : public AttributeAccessInterface
struct PowerSourceClusterInfo
{
public:
// Register on all endpoints.
PowerSourceAttrAccess() : AttributeAccessInterface(Optional<EndpointId>::Missing(), PowerSource::Id) {}

CHIP_ERROR Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) override;
PowerSourceClusterInfo() : mClusterEndpoint(kInvalidEndpointId) {}
explicit PowerSourceClusterInfo(EndpointId powerClusterEndpointId) : mClusterEndpoint(powerClusterEndpointId) {}
void Clear()
{
mBuf.Free();
mEndpointList = Span<EndpointId>();
}
CHIP_ERROR SetEndpointList(Span<EndpointId> endpointList)
{
Clear();
if (endpointList.size() == 0)
{
mEndpointList = Span<EndpointId>();
return CHIP_NO_ERROR;
}
mBuf.Calloc(endpointList.size());
if (mBuf.Get() == nullptr)
{
return CHIP_ERROR_NO_MEMORY;
}
memcpy(mBuf.Get(), endpointList.data(), endpointList.size() * sizeof(EndpointId));
mEndpointList = Span<EndpointId>(mBuf.Get(), endpointList.size());
return CHIP_NO_ERROR;
}
EndpointId mClusterEndpoint = kInvalidEndpointId;
Platform::ScopedMemoryBuffer<EndpointId> mBuf;
Span<EndpointId> mEndpointList;
};

PowerSourceServer gPowerSourceServer;

PowerSourceAttrAccess gAttrAccess;

#ifdef ZCL_USING_POWER_SOURCE_CLUSTER_SERVER
#define POWER_SERVER_NUM_SUPPORTED_ENDPOINTS \
(EMBER_AF_POWER_SOURCE_CLUSTER_SERVER_ENDPOINT_COUNT + CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT)
#else
#define POWER_SERVER_NUM_SUPPORTED_ENDPOINTS CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT
#endif
static constexpr size_t kNumSupportedEndpoints = POWER_SERVER_NUM_SUPPORTED_ENDPOINTS;

#if POWER_SERVER_NUM_SUPPORTED_ENDPOINTS > 0
PowerSourceClusterInfo sPowerSourceClusterInfo[kNumSupportedEndpoints] = {};
#else
PowerSourceClusterInfo * sPowerSourceClusterInfo = nullptr;
#endif

} // anonymous namespace

void MatterPowerSourcePluginServerInitCallback()
{
registerAttributeAccessOverride(&gAttrAccess);
}

namespace chip {
namespace app {
namespace Clusters {

CHIP_ERROR PowerSourceAttrAccess::Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder)
{
CHIP_ERROR err = CHIP_NO_ERROR;
Expand All @@ -55,20 +105,117 @@ CHIP_ERROR PowerSourceAttrAccess::Read(const ConcreteReadAttributePath & aPath,
// TODO: Needs implementation.
err = aEncoder.EncodeEmptyList();
break;
case EndpointList::Id:
// TODO: Needs implementation and a way to allow dynamic endpoints to register endpoints
err = aEncoder.EncodeEmptyList();
case EndpointList::Id: {
PowerSourceServer & server = PowerSourceServer::Instance();
const Span<EndpointId> * span = server.GetEndpointList(aPath.mEndpointId);
if (span == nullptr)
{
err = aEncoder.EncodeEmptyList();
}
else
{
err = aEncoder.EncodeList([span](const auto & encoder) -> CHIP_ERROR {
for (auto id : *span)
{
ReturnErrorOnFailure(encoder.Encode(id));
}
return CHIP_NO_ERROR;
});
}
break;
}
default:
break;
}

return err;
}

} // anonymous namespace
PowerSourceAttrAccess & TestOnlyGetPowerSourceAttrAccess()
{
return gAttrAccess;
}

void MatterPowerSourcePluginServerInitCallback()
PowerSourceServer & PowerSourceServer::Instance()
{
registerAttributeAccessOverride(&gAttrAccess);
return gPowerSourceServer;
}

// Caller does not need to retain the span past the call point as these are copied into an internal storage
CHIP_ERROR PowerSourceServer::SetEndpointList(EndpointId powerSourceClusterEndpoint, Span<EndpointId> endpointList)
{
// TODO: should check here that the power source cluster exists on the endpoint, but for now let's take the caller's word
// for it

size_t idx = PowerSourceClusterEndpointIndex(powerSourceClusterEndpoint);
if (idx >= kNumSupportedEndpoints)
{
idx = NextEmptyIndex();
}
if (idx >= kNumSupportedEndpoints)
{
return CHIP_ERROR_NO_MEMORY;
}

sPowerSourceClusterInfo[idx].Clear();
if (endpointList.size() == 0)
{
sPowerSourceClusterInfo[idx] = PowerSourceClusterInfo();
}
else
{
sPowerSourceClusterInfo[idx] = PowerSourceClusterInfo(powerSourceClusterEndpoint);
sPowerSourceClusterInfo[idx].SetEndpointList(endpointList);
}
return CHIP_NO_ERROR;
}
const Span<EndpointId> * PowerSourceServer::GetEndpointList(EndpointId powerSourceClusterEndpoint) const
{
size_t idx = PowerSourceClusterEndpointIndex(powerSourceClusterEndpoint);
if (idx != std::numeric_limits<size_t>::max())
{
return &sPowerSourceClusterInfo[idx].mEndpointList;
}
return nullptr;
}

void PowerSourceServer::Shutdown()
{
for (size_t i = 0; i < kNumSupportedEndpoints; ++i)
{
sPowerSourceClusterInfo[i].Clear();
}
}

size_t PowerSourceServer::GetNumSupportedEndpointLists() const
{
return kNumSupportedEndpoints;
}

size_t PowerSourceServer::PowerSourceClusterEndpointIndex(EndpointId endpointId) const
{
for (size_t i = 0; i < kNumSupportedEndpoints; ++i)
{
if (sPowerSourceClusterInfo[i].mClusterEndpoint == endpointId)
{
return i;
}
}
return std::numeric_limits<size_t>::max();
}

size_t PowerSourceServer::NextEmptyIndex() const
{
for (size_t i = 0; i < kNumSupportedEndpoints; ++i)
{
if (sPowerSourceClusterInfo[i].mClusterEndpoint == kInvalidEndpointId)
{
return i;
}
}
return std::numeric_limits<size_t>::max();
}

} // namespace Clusters
} // namespace app
} // namespace chip
66 changes: 66 additions & 0 deletions src/app/clusters/power-source-server/power-source-server.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
*
* Copyright (c) 2023 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.
*/

#pragma once

#include <app-common/zap-generated/ids/Clusters.h>
#include <app/AttributeAccessInterface.h>
#include <app/util/af-types.h>
#include <app/util/basic-types.h>
#include <lib/support/Span.h>
#include <platform/CHIPDeviceConfig.h>

namespace chip {
namespace app {
namespace Clusters {

class PowerSourceServer
{
public:
static PowerSourceServer & Instance();

// Caller does not need to retain the span past the call point as these are copied into an internal storage
CHIP_ERROR SetEndpointList(EndpointId powerSourceClusterEndpoint, Span<EndpointId> endpointList);
CHIP_ERROR ClearEndpointList(EndpointId powerSourceClusterEndpoint)
{
return SetEndpointList(powerSourceClusterEndpoint, Span<EndpointId>());
}
// returns nullptr if there's not endpoint list set for this power source cluster endpoint id.
const Span<EndpointId> * GetEndpointList(EndpointId powerSourceClusterEndpoint) const;
void Shutdown();
size_t GetNumSupportedEndpointLists() const;

private:
// Both return std::numeric_limits<size_t>::max() for not found
size_t PowerSourceClusterEndpointIndex(EndpointId endpointId) const;
size_t NextEmptyIndex() const;
};

class PowerSourceAttrAccess : public AttributeAccessInterface
{
public:
// Register on all endpoints.
PowerSourceAttrAccess() : AttributeAccessInterface(Optional<EndpointId>::Missing(), PowerSource::Id) {}

CHIP_ERROR Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) override;
};

PowerSourceAttrAccess & TestOnlyGetPowerSourceAttrAccess();

} // namespace Clusters
} // namespace app
} // namespace chip
14 changes: 14 additions & 0 deletions src/app/tests/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,18 @@ source_set("time-sync-data-provider-test-srcs") {
]
}

source_set("power-cluster-test-srcs") {
sources = [
"${chip_root}/src/app/clusters/power-source-server/power-source-server.cpp",
]

public_deps = [
"${chip_root}/src/app/common:cluster-objects",
"${chip_root}/src/app/util/mock:mock_ember",
"${chip_root}/src/lib/core",
]
}

source_set("scenes-table-test-srcs") {
sources = [
"${chip_root}/src/app/clusters/scenes-server/ExtensionFieldSets.h",
Expand Down Expand Up @@ -133,6 +145,7 @@ chip_test_suite("tests") {
"TestNumericAttributeTraits.cpp",
"TestOperationalStateDelegate.cpp",
"TestPendingNotificationMap.cpp",
"TestPowerSourceCluster.cpp",
"TestReadInteraction.cpp",
"TestReportingEngine.cpp",
"TestSceneTable.cpp",
Expand Down Expand Up @@ -183,6 +196,7 @@ chip_test_suite("tests") {
":binding-test-srcs",
":operational-state-test-srcs",
":ota-requestor-test-srcs",
":power-cluster-test-srcs",
":scenes-table-test-srcs",
":time-sync-data-provider-test-srcs",
"${chip_root}/src/app",
Expand Down
Loading

0 comments on commit 45e9715

Please sign in to comment.