Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Power source: Implementation of dynamic endpoint list setter #28110

Merged
121 changes: 102 additions & 19 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,36 @@
* @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>

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
{
public:
// Register on all endpoints.
PowerSourceAttrAccess() : AttributeAccessInterface(Optional<EndpointId>::Missing(), PowerSource::Id) {}

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

PowerSourceAttrAccess gAttrAccess;

} // 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 +59,99 @@ 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();
// EndpointId id[2] = { 1, 2 };
cecille marked this conversation as resolved.
Show resolved Hide resolved
// server.SetEndpointList(aPath.mEndpointId, Span<EndpointId>(id));
const Span<EndpointId> * span = server.GetEndpointList(aPath.mEndpointId);

if (span == nullptr)
{
err = aEncoder.EncodeEmptyList();
}
else
{
DataModel::List<EndpointId> list(*span);
err = aEncoder.Encode(list);
cecille marked this conversation as resolved.
Show resolved Hide resolved
}
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

int idx = PowerSourceClusterEndpointIndex(powerSourceClusterEndpoint);
if (idx == -1)
{
idx = NextEmptyIndex();
}
if (idx == -1)
{
return CHIP_ERROR_NO_MEMORY;
cecille marked this conversation as resolved.
Show resolved Hide resolved
}
if (endpointList.size() == 0)
{
mPowerSourceClusterInfo[idx] = PowerSourceClusterInfo();
}
else
{
mPowerSourceClusterInfo[idx] = PowerSourceClusterInfo(powerSourceClusterEndpoint);
mPowerSourceClusterInfo[idx].SetEndpointList(endpointList);
}
return CHIP_NO_ERROR;
}
const Span<EndpointId> * PowerSourceServer::GetEndpointList(EndpointId powerSourceClusterEndpoint) const
{
int idx = PowerSourceClusterEndpointIndex(powerSourceClusterEndpoint);
if (idx != -1)
{
return &mPowerSourceClusterInfo[idx].mEndpointList;
}
return nullptr;
}

int PowerSourceServer::PowerSourceClusterEndpointIndex(EndpointId endpointId) const
{
for (int i = 0; i < nSupportedEndpoints; ++i)
{
if (mPowerSourceClusterInfo[i].mClusterEndpoint == endpointId)
{
return i;
}
}
return -1;
}

int PowerSourceServer::NextEmptyIndex() const
{
for (int i = 0; i < nSupportedEndpoints; ++i)
{
if (mPowerSourceClusterInfo[i].mClusterEndpoint == kInvalidEndpointId)
{
return i;
}
}
return -1;
}

} // namespace Clusters
} // namespace app
} // namespace chip
91 changes: 91 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,91 @@
/*
*
* 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 {

struct PowerSourceClusterInfo
{
PowerSourceClusterInfo() : mClusterEndpoint(kInvalidEndpointId) {}
explicit PowerSourceClusterInfo(EndpointId powerClusterEndpointId) : mClusterEndpoint(powerClusterEndpointId) {}
CHIP_ERROR SetEndpointList(Span<EndpointId> endpointList)
{
if (endpointList.size() == 0)
{
mBuf = nullptr;
mEndpointList = Span<EndpointId>();
return CHIP_NO_ERROR;
}

mBuf = std::make_unique<EndpointId[]>(endpointList.size());
if (mBuf == nullptr)
cecille marked this conversation as resolved.
Show resolved Hide resolved
{
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;
std::unique_ptr<EndpointId[]> mBuf = nullptr;
cecille marked this conversation as resolved.
Show resolved Hide resolved
Span<EndpointId> mEndpointList;
};

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);
cecille marked this conversation as resolved.
Show resolved Hide resolved
// returns nullptr if there's not endpoint list set for this power source cluster endpoint id.
const Span<EndpointId> * GetEndpointList(EndpointId powerSourceClusterEndpoint) const;
cecille marked this conversation as resolved.
Show resolved Hide resolved

private:
// There's probably a good way to properly set this from zap or have this grow dynamically as dynamic endpoints are
// finalized, but for now, let's just say 10 power clusters is probably ok.
// TODO: is there a way to get a static count of endpoints? CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT?
cecille marked this conversation as resolved.
Show resolved Hide resolved
cecille marked this conversation as resolved.
Show resolved Hide resolved
static constexpr int nSupportedEndpoints = 10;
cecille marked this conversation as resolved.
Show resolved Hide resolved
cecille marked this conversation as resolved.
Show resolved Hide resolved
PowerSourceClusterInfo mPowerSourceClusterInfo[nSupportedEndpoints] = {};
int PowerSourceClusterEndpointIndex(EndpointId endpointId) const;
int 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 @@ -76,6 +76,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 @@ -131,6 +143,7 @@ chip_test_suite("tests") {
"TestNumericAttributeTraits.cpp",
"TestOperationalStateDelegate.cpp",
"TestPendingNotificationMap.cpp",
"TestPowerSourceCluster.cpp",
"TestReadInteraction.cpp",
"TestReportingEngine.cpp",
"TestSceneTable.cpp",
Expand Down Expand Up @@ -181,6 +194,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
Loading