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

Add a server cluster interface registry for use by codegen. #37850

Merged
merged 29 commits into from
Mar 6, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
f301851
Server cluster interface
andy31415 Mar 3, 2025
bb89093
ServerClusterInterfaceRegistry adding
andy31415 Mar 3, 2025
e238230
Merge branch 'master' into server-cluster-interface
andy31415 Mar 3, 2025
c3cb1aa
Merge branch 'server-cluster-interface' into server_cluster_registry
andy31415 Mar 3, 2025
bbb33e4
Merge branch 'master' into server_cluster_registry
andreilitvin Mar 4, 2025
7fdd6b4
Update src/data-model-providers/codegen/ServerClusterInterfaceRegistry.h
andy31415 Mar 4, 2025
0a6a7f9
Code review: forward declare
andreilitvin Mar 4, 2025
ab8a9b2
Review comment: switch order of members
andreilitvin Mar 4, 2025
d9aa48e
Updated logic: the condition is not relevant anymore
andreilitvin Mar 4, 2025
a062ca2
Code review: added comment
andreilitvin Mar 4, 2025
a92317c
Restyle
andreilitvin Mar 4, 2025
e73955c
Merge branch 'master' into server_cluster_registry
andreilitvin Mar 4, 2025
b60ebad
Comment update
andy31415 Mar 5, 2025
2daa37c
Updates to make callers use memory allocation
andreilitvin Mar 6, 2025
7a2bb76
Self review: fix an include
andreilitvin Mar 6, 2025
4e819fa
Fix constexpr logic
andreilitvin Mar 6, 2025
7da6312
Restyle
andreilitvin Mar 6, 2025
0c1bc26
minor comment update so github is not confused about head SHA
andreilitvin Mar 6, 2025
ea3e4d0
Added useless unit test to get coverage
andreilitvin Mar 6, 2025
86aeb05
Restyle
andreilitvin Mar 6, 2025
4fec4f1
Update src/app/server-cluster/ServerClusterInterface.h
andy31415 Mar 6, 2025
868d8a9
Update src/data-model-providers/codegen/ServerClusterInterfaceRegistr…
andy31415 Mar 6, 2025
30f5679
Update src/data-model-providers/codegen/ServerClusterInterfaceRegistr…
andy31415 Mar 6, 2025
c88e835
Update src/data-model-providers/codegen/ServerClusterInterfaceRegistry.h
andy31415 Mar 6, 2025
4ea82ec
Update src/data-model-providers/codegen/ServerClusterInterfaceRegistry.h
andy31415 Mar 6, 2025
af23a93
Disallow null ptr registrations
andreilitvin Mar 6, 2025
73c46b6
Merge branch 'server_cluster_registry' of github.com:andy31415/connec…
andreilitvin Mar 6, 2025
4463e95
Restyled by clang-format
restyled-commits Mar 6, 2025
2fa2125
Reworded based on code review
andreilitvin Mar 6, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion src/app/server-cluster/ServerClusterInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,12 @@ class ServerClusterInterface
virtual ~ServerClusterInterface() = default;

///////////////////////////////////// Cluster Metadata Support //////////////////////////////////////////////////
[[nodiscard]] virtual ClusterId GetClusterId() const = 0;

/// The path to this cluster instance.
///
/// This path (endpointid,clusterid) is expected to remain constant once the server
/// cluster interface is in use.
[[nodiscard]] virtual ConcreteClusterPath GetPath() const = 0;

/// Gets the data version for this cluster instance.
///
Expand Down
28 changes: 19 additions & 9 deletions src/app/server-cluster/tests/TestDefaultServerCluster.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

#include <access/Privilege.h>
#include <app-common/zap-generated/ids/Attributes.h>
#include <app/ConcreteClusterPath.h>
#include <app/data-model-provider/MetadataList.h>
#include <app/data-model-provider/MetadataTypes.h>
#include <app/data-model-provider/OperationTypes.h>
Expand All @@ -44,9 +45,9 @@ namespace {
class FakeDefaultServerCluster : public DefaultServerCluster
{
public:
FakeDefaultServerCluster(ClusterId id) : mClusterId(id) {}
FakeDefaultServerCluster(ConcreteClusterPath path) : mPath(path) {}

ClusterId GetClusterId() const override { return mClusterId; }
[[nodiscard]] ConcreteClusterPath GetPath() const override { return mPath; }

DataModel::ActionReturnStatus ReadAttribute(const DataModel::ReadAttributeRequest & request,
AttributeValueEncoder & encoder) override
Expand All @@ -64,14 +65,14 @@ class FakeDefaultServerCluster : public DefaultServerCluster
void TestIncreaseDataVersion() { IncreaseDataVersion(); }

private:
ClusterId mClusterId;
ConcreteClusterPath mPath;
};

} // namespace

TEST(TestDefaultServerCluster, TestDataVersion)
{
FakeDefaultServerCluster cluster(1);
FakeDefaultServerCluster cluster({ 1, 2 });

DataVersion v1 = cluster.GetDataVersion();
cluster.TestIncreaseDataVersion();
Expand All @@ -80,13 +81,22 @@ TEST(TestDefaultServerCluster, TestDataVersion)

TEST(TestDefaultServerCluster, TestFlagsDefault)
{
FakeDefaultServerCluster cluster(1);
FakeDefaultServerCluster cluster({ 1, 2 });
ASSERT_EQ(cluster.GetClusterFlags().Raw(), 0u);
}

TEST(TestDefaultServerCluster, ListWriteNotification)
{
FakeDefaultServerCluster cluster({ 1, 2 });

// this does not test anything really, except we get 100% coverage and we see that we do not crash
cluster.ListAttributeWriteNotification({ 1, 2, 3 }, DataModel::ListWriteOperation::kListWriteBegin);
cluster.ListAttributeWriteNotification({ 1, 2, 3 }, DataModel::ListWriteOperation::kListWriteFailure);
}

TEST(TestDefaultServerCluster, AttributesDefault)
{
FakeDefaultServerCluster cluster(1);
FakeDefaultServerCluster cluster({ 1, 2 });

DataModel::ListBuilder<AttributeEntry> attributes;

Expand Down Expand Up @@ -114,7 +124,7 @@ TEST(TestDefaultServerCluster, AttributesDefault)

TEST(TestDefaultServerCluster, CommandsDefault)
{
FakeDefaultServerCluster cluster(1);
FakeDefaultServerCluster cluster({ 1, 2 });

DataModel::ListBuilder<AcceptedCommandEntry> acceptedCommands;
ASSERT_EQ(cluster.AcceptedCommands({ 1, 1 }, acceptedCommands), CHIP_NO_ERROR);
Expand All @@ -127,7 +137,7 @@ TEST(TestDefaultServerCluster, CommandsDefault)

TEST(TestDefaultServerCluster, WriteAttributeDefault)
{
FakeDefaultServerCluster cluster(1);
FakeDefaultServerCluster cluster({ 1, 2 });

WriteOperation test(0 /* endpoint */, 1 /* cluster */, 1234 /* attribute */);
test.SetSubjectDescriptor(kAdminSubjectDescriptor);
Expand All @@ -140,7 +150,7 @@ TEST(TestDefaultServerCluster, WriteAttributeDefault)

TEST(TestDefaultServerCluster, InvokeDefault)
{
FakeDefaultServerCluster cluster(1);
FakeDefaultServerCluster cluster({ 1, 2 });

TLV::TLVReader tlvReader;
InvokeRequest request;
Expand Down
14 changes: 14 additions & 0 deletions src/data-model-providers/codegen/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,17 @@ source_set("instance-header") {
# generally being unit tests or data_model.gni/data_model.cmake files)
sources = [ "Instance.h" ]
}

source_set("registry") {
sources = [
"ServerClusterInterfaceRegistry.cpp",
"ServerClusterInterfaceRegistry.h",
]

public_deps = [
"${chip_root}/src/app:paths",
"${chip_root}/src/app/server-cluster",
"${chip_root}/src/lib/core:types",
"${chip_root}/src/lib/support",
]
}
162 changes: 162 additions & 0 deletions src/data-model-providers/codegen/ServerClusterInterfaceRegistry.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
/*
* Copyright (c) 2025 Project CHIP Authors
* All rights reserved.
*
* 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.
*/
#include <data-model-providers/codegen/ServerClusterInterfaceRegistry.h>

#include <app/ConcreteClusterPath.h>
#include <app/server-cluster/ServerClusterInterface.h>
#include <lib/core/CHIPError.h>
#include <lib/core/DataModelTypes.h>
#include <lib/support/CHIPMem.h>
#include <lib/support/CodeUtils.h>

namespace chip {
namespace app {

ServerClusterInterfaceRegistry::~ServerClusterInterfaceRegistry()
{
while (mRegistrations != nullptr)
{
ServerClusterRegistration * next = mRegistrations->next;
mRegistrations->next = nullptr;
mRegistrations = next;
}
}

CHIP_ERROR ServerClusterInterfaceRegistry::Register(ServerClusterRegistration & entry)
{
// we have no strong way to check if entry is already registered somewhere else, so we use "next" as some
// form of double-check
VerifyOrReturnError(entry.next == nullptr, CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrReturnError(entry.serverClusterInterface != nullptr, CHIP_ERROR_INVALID_ARGUMENT);

ConcreteClusterPath path = entry.serverClusterInterface->GetPath();

VerifyOrReturnError(path.HasValidIds(), CHIP_ERROR_INVALID_ARGUMENT);

// Double-checking for duplicates makes the checks O(n^2) on the total number of registered
// items. We preserve this however we may want to make this optional at some point in time.
VerifyOrReturnError(Get(path) == nullptr, CHIP_ERROR_DUPLICATE_KEY_ID);

entry.next = mRegistrations;
mRegistrations = &entry;

return CHIP_NO_ERROR;
}

ServerClusterInterface * ServerClusterInterfaceRegistry::Unregister(const ConcreteClusterPath & path)
{
ServerClusterRegistration * prev = nullptr;
ServerClusterRegistration * current = mRegistrations;

while (current != nullptr)
{
if (current->serverClusterInterface->GetPath() == path)
{
// take the item out of the current list and return it.
ServerClusterRegistration * next = current->next;

if (prev == nullptr)
{
mRegistrations = next;
}
else
{
prev->next = next;
}

if (mCachedInterface == current->serverClusterInterface)
{
mCachedInterface = nullptr;
}

current->next = nullptr; // Make sure current does not look like part of a list.
return current->serverClusterInterface;
}

prev = current;
current = current->next;
}

// Not found.
return nullptr;
}

ServerClusterInterfaceRegistry::ClustersList ServerClusterInterfaceRegistry::ClustersOnEndpoint(EndpointId endpointId)
{
return { mRegistrations, endpointId };
}

void ServerClusterInterfaceRegistry::UnregisterAllFromEndpoint(EndpointId endpointId)
{
ServerClusterRegistration * prev = nullptr;
ServerClusterRegistration * current = mRegistrations;
while (current != nullptr)
{
if (current->serverClusterInterface->GetPath().mEndpointId == endpointId)
{
if (mCachedInterface == current->serverClusterInterface)
{
mCachedInterface = nullptr;
}
if (prev == nullptr)
{
mRegistrations = current->next;
}
else
{
prev->next = current->next;
}
ServerClusterRegistration * actual_next = current->next;
current->next = nullptr; // Make sure current does not look like part of a list.
current = actual_next;
}
else
{
prev = current;
current = current->next;
}
}
}

ServerClusterInterface * ServerClusterInterfaceRegistry::Get(const ConcreteClusterPath & path)
{
// Check the cache to speed things up
if ((mCachedInterface != nullptr) && (mCachedInterface->GetPath() == path))
{
return mCachedInterface;
}

// The cluster searched for is not cached, do a linear search for it
ServerClusterRegistration * current = mRegistrations;

while (current != nullptr)
{
if (current->serverClusterInterface->GetPath() == path)
{
mCachedInterface = current->serverClusterInterface;
return mCachedInterface;
}

current = current->next;
}

// not found
return nullptr;
}

} // namespace app
} // namespace chip
Loading
Loading