blob: dbd5fecbeb5ade0bff304b9ca1acd0142b0e76cd [file] [log] [blame]
/*
* 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.
*/
#pragma once
#include <app/server-cluster/ServerClusterInterfaceRegistry.h>
#include <cstdint>
namespace chip::app {
/// Handles reusable code for integrating server cluster interfaces with ember:
/// - loads ember metadata (optional attributes and feature maps)
/// - calls corresponding register/unregister calls on the Codegen Data Model Provider.
///
/// Uses an underlying delegate to handle constructor/destructor calls for actual cluster implementations.
class CodegenClusterIntegration
{
public:
/// Handles the creation/destruction of server clusters when using codegen integration.
///
/// The purpose of this class is to call ServerClusterInterfaces constructors and
/// destructors once generic ember processing has been completed.
///
/// Logic is generally split into:
/// - generic fetching and validating data from the ember framework like
/// 0-based array index from endpoint id, optional attribute fetching, feature map fetching
/// - registering/unregistering ServerClusterInterfaces
/// - determining how to create/destroy classes (the purpose of this delegate)
class Delegate
{
public:
virtual ~Delegate() = default;
/// Create the given registration for an endpoint
///
/// When this is called, the caller has ensured that the endpointId was valid, that optionalAttributeBits are loaded
/// from ember according to supported attributes and that the feature map for the underlying cluster ID has been loaded.
///
/// NOTE: optionalAttributeBits is intended for low id attributes since it supports attribute bits up to 31 only. It is
/// intended for use with `OptionalAttributeSet` and NOT all clusters support this. Specific examples:
/// - LevelControl::StartupCurrentLevel has ID 0x4000
/// - OnOff attributes GlobalSceneControl, OnTime, OffWaitTime, StartupOnOff have ID >= 0x4000
/// - ColorControl, Thermostat and DoorLock have many attributes with high ID as well
///
/// Use optionalAttributes only if its usage makes sense for the cluster. In many instances it does,
/// however it is not a generic rule. Usage of it must be double-checked as sufficient.
///
/// Method is assumed to never fail: this is expected to call a constructor and not fail.
virtual ServerClusterRegistration & CreateRegistration(EndpointId endpointId, unsigned emberEndpointIndex,
uint32_t optionalAttributeBits, uint32_t featureMap) = 0;
/// Find the previously created cluster on the given path
///
/// This is assumed to never fail as `CreateRegistration` is assumed to never fail.
/// This will be called only after `CreateRegistration`.
virtual ServerClusterInterface & FindRegistration(unsigned emberEndpointIndex) = 0;
/// Free up resources for this index, generally expected to call a destructor/free resources
/// as applicable.
///
/// It is assumed that this is called as the couterpart of `CreateRegistration`.
virtual void ReleaseRegistration(unsigned emberEndpointIndex) = 0;
};
// Note on indexing:
// - The methods here use emberAfGetClusterServerEndpointIndex to convert
// an endpointId to a linear index [0; maxEndpointCount) from ember.
// For this ember requires the fixedClusterServerEndpointCount.
struct RegisterServerOptions
{
EndpointId endpointId;
ClusterId clusterId;
uint16_t fixedClusterServerEndpointCount; // Number of fixed endpoints in ember configuration.
uint16_t maxEndpointCount; // This is how many endpoints are supported by the delegate (0-based index).
bool fetchFeatureMap; // Read feature map attribute from ember.
bool fetchOptionalAttributes; // Read the enabling of the first 32 optional attributes from ember.
};
/// Loads required data from ember and calls `CreateRegistration` once all the data
/// has been validated. Validation includes:
/// - cluster exists on the given endpoint and a valid index could be found for it
/// - feature map could be loaded (if applicable, otherwise it will be set to 0)
/// - optional attributes were loaded
///
/// The returned `CreateRegistration` value will be used to register to the codegen
/// data model provider registry
///
/// In case of errors, this method will log the error and return (error state is not
/// returned to the caller as it is generally not actionable/fixable)
///
/// Typical implementation is that this gets called in `emberAf....ClusterServerInitCallback`
static void RegisterServer(const RegisterServerOptions & options, Delegate & delegate);
struct UnregisterServerOptions
{
EndpointId endpointId;
ClusterId clusterId;
uint16_t fixedClusterServerEndpointCount; // Number of fixed endpoints in ember configuration.
uint16_t maxEndpointCount; // This is how many endpoints are supported by the delegate (0-based index).
};
/// A typical implementation is that this gets called in `Matter....ClusterServerShutdownCallback`.
///
/// In case of errors, this method will log the error and return (error state is not
/// returned to the caller as it is generally not actionable/fixable)
static void UnregisterServer(const UnregisterServerOptions & options, Delegate & delegate);
struct GetClusterForEndpointIndexOptions
{
EndpointId endpointId;
ClusterId clusterId;
uint16_t fixedClusterServerEndpointCount; // Number of fixed endpoints in ember configuration.
uint16_t maxEndpointCount; // This is how many endpoints are supported by the delegate (0-based index).
};
/// Calls 'FindRegistration' on the delegate and returns the address of the cluster for an endpoint index or nullptr if not
/// found.
static ServerClusterInterface * GetClusterForEndpointIndex(const GetClusterForEndpointIndexOptions & options,
Delegate & delegate);
};
} // namespace chip::app