Skip to content

Commit

Permalink
Add ServerCluster base class and Ember adapter
Browse files Browse the repository at this point in the history
  • Loading branch information
ksperling-apple committed Jun 17, 2024
1 parent 4d5e2ee commit 2638722
Show file tree
Hide file tree
Showing 6 changed files with 226 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/app/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,8 @@ static_library("app") {
"OTAUserConsentCommon.h",
"ReadHandler.cpp",
"SafeAttributePersistenceProvider.h",
"ServerCluster.cpp",
"ServerCluster.h",
"TimerDelegates.cpp",
"TimerDelegates.h",
"WriteHandler.cpp",
Expand Down
58 changes: 58 additions & 0 deletions src/app/ServerCluster.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
*
* Copyright (c) 2024 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 <app/ServerCluster.h>

#include <app/AttributeAccessInterfaceRegistry.h>
#include <app/InteractionModelEngine.h>
#include <lib/support/CodeUtils.h>

namespace chip {
namespace app {

ServerCluster::ServerCluster(EndpointId aEndpointId, ClusterId aClusterId) :
AttributeAccessInterface(MakeOptional(aEndpointId), aClusterId), CommandHandlerInterface(MakeOptional(aEndpointId), aClusterId)
{}

CHIP_ERROR ServerCluster::Init()
{
ChipLogError(NotSpecified, "CLUStER INIT");
ReturnErrorOnFailure(InteractionModelEngine::GetInstance()->RegisterCommandHandler(this));
VerifyOrReturnError(registerAttributeAccessOverride(this), CHIP_ERROR_INCORRECT_STATE);
return CHIP_NO_ERROR;
}

void ServerCluster::Shutdown()
{
InteractionModelEngine::GetInstance()->UnregisterCommandHandler(this);
unregisterAttributeAccessOverride(this);
}

void EmberClusterAdapterImpl::Init(ServerCluster & cluster)
{
CHIP_ERROR err = cluster.Init();
VerifyOrDieWithMsg(err == CHIP_NO_ERROR, Zcl, "Cluster initialization failed: %" CHIP_ERROR_FORMAT, err.Format());
}

void EmberClusterAdapterImpl::InitFailureInstancesExceeded()
{
VerifyOrDieWithMsg(false, Zcl, "Cluster initialization failed: no instance allocated");
}

} // namespace app
} // namespace chip
108 changes: 108 additions & 0 deletions src/app/ServerCluster.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/*
*
* Copyright (c) 2024 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.
*/

#pragma once

#include <app/AttributeAccessInterface.h>
#include <app/CommandHandlerInterface.h>
#include <array>
#include <optional>
#include <type_traits>

namespace chip {
namespace app {

/**
* Base class for server-side cluster implementations.
*/
class ServerCluster : protected AttributeAccessInterface, protected CommandHandlerInterface
{
public:
ServerCluster(EndpointId aEndpointId, ClusterId aClusterId);
virtual ~ServerCluster() { Shutdown(); }

EndpointId GetEndpointId() { return mEndpointId; }

virtual CHIP_ERROR Init();
virtual void Shutdown();

protected:
void InvokeCommand(HandlerContext & handlerContext) override {};

private:
EndpointId mEndpointId;
};

/**
* An adapter class that statically allocates memory for a fixed number of cluster instances
* and manages their lifecycle.
*
* @see DECLARE_CLUSTER_SERVER()
*/
template <class S, size_t N>
class EmberClusterAdapter;

class EmberClusterAdapterImpl
{
template <class S, size_t N>
friend class EmberClusterAdapter;

static void Init(ServerCluster & cluster);
static void InitFailureInstancesExceeded();
};

template <class S, size_t N>
class EmberClusterAdapter final
{
static_assert(std::is_base_of_v<ServerCluster, S>);

public:
constexpr EmberClusterAdapter() = default;

void Init(EndpointId endpoint)
{
for (auto & instance : mInstances)
{
if (!instance)
{
EmberClusterAdapterImpl::Init(instance.emplace(endpoint));
return;
}
}
EmberClusterAdapterImpl::InitFailureInstancesExceeded();
}

void Shutdown(EndpointId endpoint)
{
for (auto & instance : mInstances)
{
if (instance && instance->GetEndpointId() == endpoint)
{
instance.reset(); // destructor calls Shutdown
return;
}
}
// ignore silently
}

private:
std::array<std::optional<S>, N> mInstances;
};

} // namespace app
} // namespace chip
1 change: 1 addition & 0 deletions src/app/util/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ source_set("types") {
"attribute-metadata.h",
"attribute-storage-null-handling.h",
"basic-types.h",
"ember-server-cluster.h",
"ember-strings.cpp",
"ember-strings.h",
"endpoint-config-defines.h",
Expand Down
50 changes: 50 additions & 0 deletions src/app/util/ember-server-cluster.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
*
* Copyright (c) 2024 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.
*/

#pragma once

#include <app/ServerCluster.h>

#include <app-common/zap-generated/callback.h>
#include <app/util/config.h>

/**
* Defines static storage for the specified number of instances of the specified class
* (which must be a sub-class of chip::app::ServerCluster) as well as the corresponding Ember
* ServerInitCallback and ShutdownCallback functions.
*
* Note: This macro must be called from the global namespace.
*
* Example:
* DECLARE_SERVER_CLUSTER(DISCO_BALL_CLUSTER, chip::app::Clusters::DiscoBall::Instance);
*/
#define DECLARE_SERVER_CLUSTER(NAME, CLASS) \
chip::app::EmberClusterAdapter<CLASS, _DECLARE_CLUSTER_EXPAND(MATTER_DM_##NAME##_SERVER_ENDPOINT_COUNT)> \
gClusterAdapter_##NAME; \
void _DECLARE_CLUSTER_CONCAT3(emberAf, MATTER_DM_##NAME##_LABEL, ClusterServerInitCallback)(chip::EndpointId endpoint) \
{ \
gClusterAdapter_##NAME.Init(endpoint); \
} \
void _DECLARE_CLUSTER_CONCAT3(Matter, MATTER_DM_##NAME##_LABEL, ClusterServerShutdownCallback)(chip::EndpointId endpoint) \
{ \
gClusterAdapter_##NAME.Shutdown(endpoint); \
}

#define _DECLARE_CLUSTER_EXPAND(a) a
#define _DECLARE_CLUSTER_CONCAT3_(a, b, c) a##b##c
#define _DECLARE_CLUSTER_CONCAT3(a, b, c) _DECLARE_CLUSTER_CONCAT3_(a, b, c)
7 changes: 7 additions & 0 deletions src/app/zap-templates/templates/app/callback.zapt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@
#include <lib/support/Span.h>
#include <protocols/interaction_model/Constants.h>


// Cluster Labels

{{#zcl_clusters}}
#define MATTER_DM_{{as_delimited_macro define}}_LABEL {{asUpperCamelCase label}}
{{/zcl_clusters}}

// Cluster Init Functions

{{#zcl_clusters}}
Expand Down

0 comments on commit 2638722

Please sign in to comment.