Line data Source code
1 : /*
2 : * Copyright (c) 2025 Project CHIP Authors
3 : * All rights reserved.
4 : *
5 : * Licensed under the Apache License, Version 2.0 (the "License");
6 : * you may not use this file except in compliance with the License.
7 : * You may obtain a copy of the License at
8 : *
9 : * http://www.apache.org/licenses/LICENSE-2.0
10 : *
11 : * Unless required by applicable law or agreed to in writing, software
12 : * distributed under the License is distributed on an "AS IS" BASIS,
13 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 : * See the License for the specific language governing permissions and
15 : * limitations under the License.
16 : */
17 : #pragma once
18 :
19 : #include <app/server-cluster/ServerClusterInterfaceRegistry.h>
20 :
21 : #include <app/util/generic-callbacks.h>
22 :
23 : #include <cstdint>
24 :
25 : namespace chip::app {
26 :
27 : /// Handles reusable code for integrating server cluster interfaces with ember:
28 : /// - loads ember metadata (optional attributes and feature maps)
29 : /// - calls corresponding register/unregister calls on the Codegen Data Model Provider.
30 : ///
31 : /// Uses an underlying delegate to handle constructor/destructor calls for actual cluster implementations.
32 : class CodegenClusterIntegration
33 : {
34 : public:
35 : /// Handles the creation/destruction of server clusters when using codegen integration.
36 : ///
37 : /// The purpose of this class is to call ServerClusterInterfaces constructors and
38 : /// destructors once generic ember processing has been completed.
39 : ///
40 : /// Logic is generally split into:
41 : /// - generic fetching and validating data from the ember framework like
42 : /// 0-based array index from endpoint id, optional attribute fetching, feature map fetching
43 : /// - registering/unregistering ServerClusterInterfaces
44 : /// - determining how to create/destroy classes (the purpose of this delegate)
45 : class Delegate
46 : {
47 : public:
48 0 : virtual ~Delegate() = default;
49 :
50 : /// Create the given registration for an endpoint
51 : ///
52 : /// When this is called, the caller has ensured that:
53 : /// - the endpointId was valid
54 : /// - IF AND ONLY IF optional attribute load is requested that optionalAttributeBits are
55 : /// loaded from ember according to supported attributes
56 : /// - IF AND ONLY IF feature map loading is requested, that the feature map for the
57 : /// underlying cluster ID and endpoint has been loaded.
58 : ///
59 : /// NOTE: optionalAttributeBits is intended for low id attributes since it supports attribute bits up to 31 only. It is
60 : /// intended for use with `OptionalAttributeSet` and NOT all clusters support this. Specific examples:
61 : /// - LevelControl::StartupCurrentLevel has ID 0x4000
62 : /// - OnOff attributes GlobalSceneControl, OnTime, OffWaitTime, StartupOnOff have ID >= 0x4000
63 : /// - ColorControl, Thermostat and DoorLock have many attributes with high ID as well
64 : ///
65 : /// Use optionalAttributes only if its usage makes sense for the cluster. In many instances it does,
66 : /// however it is not a generic rule. Usage of it must be double-checked as sufficient.
67 : ///
68 : /// Method is assumed to never fail: this is expected to call a constructor and not fail.
69 : virtual ServerClusterRegistration & CreateRegistration(EndpointId endpointId, unsigned clusterInstanceIndex,
70 : uint32_t optionalAttributeBits, uint32_t featureMap) = 0;
71 :
72 : /// Find the previously created cluster at the given index.
73 : ///
74 : /// It should return the given interface IF AND ONLY IF it is valid.
75 : /// This will be called after CreateRegistration or as part of finding an existing
76 : /// registered cluster.
77 : virtual ServerClusterInterface * FindRegistration(unsigned clusterInstanceIndex) = 0;
78 :
79 : /// Free up resources for this index, generally expected to call a destructor/free resources
80 : /// as applicable.
81 : ///
82 : /// It is assumed that this is called once as part of the shutdown sequence to undo
83 : /// work done by `CreateRegistration`.
84 : virtual void ReleaseRegistration(unsigned clusterInstanceIndex) = 0;
85 : };
86 :
87 : // Note on indexing:
88 : // - The methods here use emberAfGetClusterServerEndpointIndex to convert
89 : // an endpointId to a linear index [0; maxClusterInstanceCount) from ember.
90 : // For this ember requires the fixedClusterInstanceCount.
91 : struct RegisterServerOptions
92 : {
93 : EndpointId endpointId;
94 : ClusterId clusterId;
95 : uint16_t
96 : fixedClusterInstanceCount; // Number of fixed endpoints that contain this server cluster in the ember configuration.
97 : uint16_t maxClusterInstanceCount; // This is how many cluster instancers are supported by the delegate (0-based indexing, so
98 : // indices smaller than this are valid).
99 : bool fetchFeatureMap; // Read feature map attribute from ember.
100 : bool fetchOptionalAttributes; // Read the enabling of the first 32 optional attributes from ember.
101 : };
102 :
103 : /// Loads required data from ember and calls `CreateRegistration` once all the data
104 : /// has been validated. Validation includes:
105 : /// - cluster exists on the given endpoint and a valid index could be found for the cluster instance
106 : /// - feature map could be loaded (if requested for load, otherwise it will be set to 0)
107 : /// - optional attributes were loaded (if requested for load, otherwise it will be set to 0)
108 : ///
109 : /// The returned `CreateRegistration` value will be used to register to the codegen
110 : /// data model provider registry.
111 : ///
112 : /// In case of errors, this method will log the error and return (error state is not
113 : /// returned to the caller as it is generally not actionable/fixable).
114 : ///
115 : /// Typical implementation is that this gets called in `emberAf....ClusterServerInitCallback`
116 : static void RegisterServer(const RegisterServerOptions & options, Delegate & delegate);
117 :
118 : struct UnregisterServerOptions
119 : {
120 : EndpointId endpointId;
121 : ClusterId clusterId;
122 : uint16_t
123 : fixedClusterInstanceCount; // Number of fixed endpoints that contain this server cluster in the ember configuration.
124 : uint16_t maxClusterInstanceCount; // This is how many cluster instancers are supported by the delegate (0-based indexing, so
125 : // indices smaller than this are valid).
126 : };
127 :
128 : /// A typical implementation is that this gets called in `Matter....ClusterServerShutdownCallback`.
129 : ///
130 : /// In case of errors, this method will log the error and return (error state is not
131 : /// returned to the caller as it is generally not actionable/fixable)
132 : static void UnregisterServer(const UnregisterServerOptions & options, Delegate & delegate,
133 : MatterClusterShutdownType clusterShutdownType);
134 :
135 : struct FindClusterOnEndpointOptions
136 : {
137 : EndpointId endpointId;
138 : ClusterId clusterId;
139 : uint16_t
140 : fixedClusterInstanceCount; // Number of fixed endpoints that contain this server cluster in the ember configuration.
141 : uint16_t maxClusterInstanceCount; // This is how many cluster instances are supported by the delegate (0-based indexing, so
142 : // indices smaller than this are valid).
143 : };
144 :
145 : /// Calls 'FindRegistration' on the delegate and returns the address of the cluster for the provided endpoint id or nullptr if
146 : /// not found.
147 : static ServerClusterInterface * FindClusterOnEndpoint(const FindClusterOnEndpointOptions & options, Delegate & delegate);
148 : };
149 :
150 : } // namespace chip::app
|