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 : #include <data-model-providers/codegen/ClusterIntegration.h>
18 :
19 : #include <app/util/attribute-storage.h>
20 : #include <app/util/attribute-table.h>
21 : #include <app/util/endpoint-config-api.h>
22 : #include <data-model-providers/codegen/CodegenDataModelProvider.h>
23 : #include <data-model-providers/codegen/CodegenProcessingConfig.h>
24 :
25 : #include <limits>
26 :
27 : namespace chip::app {
28 :
29 : namespace {
30 :
31 0 : bool FindEndpointWithLog(EndpointId endpointId, ClusterId clusterId, uint16_t fixedClusterInstanceCount,
32 : uint16_t maxClusterInstanceCount, uint16_t & clusterInstanceIndex)
33 : {
34 0 : clusterInstanceIndex = emberAfGetClusterServerEndpointIndex(endpointId, clusterId, fixedClusterInstanceCount);
35 :
36 0 : if (clusterInstanceIndex >= maxClusterInstanceCount)
37 : {
38 : #if CHIP_CODEGEN_CONFIG_ENABLE_CODEGEN_INTEGRATION_LOOKUP_ERRORS
39 0 : ChipLogError(AppServer,
40 : "Could not find a valid endpoint index for endpoint %u/" ChipLogFormatMEI " (Index %u was not valid)",
41 : endpointId, ChipLogValueMEI(clusterId), clusterInstanceIndex);
42 : #endif // CHIP_CODEGEN_CONFIG_ENABLE_CODEGEN_INTEGRATION_LOOKUP_ERRORS
43 0 : return false;
44 : }
45 0 : return true;
46 : }
47 :
48 : /// Fetch the featuremap from ember for the given endpoint/cluster
49 : ///
50 : /// on error 0 is returned
51 0 : uint32_t LoadFeatureMap(EndpointId endpointId, ClusterId clusterId)
52 : {
53 : using Traits = NumericAttributeTraits<uint32_t>;
54 : Traits::StorageType temp;
55 0 : uint8_t * readable = Traits::ToAttributeStoreRepresentation(temp);
56 : Protocols::InteractionModel::Status status =
57 0 : emberAfReadAttribute(endpointId, clusterId, Clusters::Globals::Attributes::FeatureMap::Id, readable, sizeof(temp));
58 0 : if (status != Protocols::InteractionModel::Status::Success)
59 : {
60 : #if CHIP_CODEGEN_CONFIG_ENABLE_CODEGEN_INTEGRATION_LOOKUP_ERRORS
61 0 : ChipLogError(AppServer, "Failed to load feature map for %u/" ChipLogFormatMEI " (Status %d)", endpointId,
62 : ChipLogValueMEI(clusterId), static_cast<int>(status));
63 : #endif // CHIP_CODEGEN_CONFIG_ENABLE_CODEGEN_INTEGRATION_LOOKUP_ERRORS
64 0 : return 0;
65 : }
66 : // note: we do not try to check if value is representable: all the uint32_t values are representable
67 0 : return Traits::StorageToWorking(temp);
68 : }
69 :
70 0 : ClusterShutdownType ToServerClusterInterfaceShutdown(MatterClusterShutdownType t)
71 : {
72 0 : switch (t)
73 : {
74 0 : case MatterClusterShutdownType::kPermanentRemove:
75 0 : return ClusterShutdownType::kPermanentRemove;
76 0 : case MatterClusterShutdownType::kClusterShutdown:
77 0 : return ClusterShutdownType::kClusterShutdown;
78 : }
79 : // we are handling all cases above, but compiler does not seem to detect this...
80 0 : return ClusterShutdownType::kClusterShutdown;
81 : }
82 :
83 : } // namespace
84 :
85 0 : void CodegenClusterIntegration::RegisterServer(const RegisterServerOptions & options, Delegate & delegate)
86 : {
87 : uint16_t clusterInstanceIndex;
88 0 : if (!FindEndpointWithLog(options.endpointId, options.clusterId, options.fixedClusterInstanceCount,
89 0 : options.maxClusterInstanceCount, clusterInstanceIndex))
90 : {
91 0 : return;
92 : }
93 :
94 0 : uint32_t featureMap = 0;
95 0 : if (options.fetchFeatureMap)
96 : {
97 0 : featureMap = LoadFeatureMap(options.endpointId, options.clusterId);
98 : }
99 :
100 : // NOTE: we fetch low ID attributes only here as a convenience/speedup for the very frequent cluster case
101 : // where attributes are few and with low IDS.
102 : //
103 : // This is NOT a general rule. Specific examples are:
104 : // - LevelControl::StartupCurrentLevel has ID 0x4000
105 : // - OnOff has several: GlobalSceneControl, OnTime, OffWaitTime, StartupOnOff with id >= 0x4000
106 : // - Thermostat and DoorLock have more than 32 attributes in general
107 : // - ColorControl has a lot of high-ID attributes
108 : //
109 : // The above examples however are few compared to the large number of clusters that Matter supports,
110 : // so this optimization is considered worth it at this time.
111 0 : uint32_t optionalAttributes = 0;
112 0 : if (options.fetchOptionalAttributes)
113 : {
114 0 : for (AttributeId attributeId = 0; attributeId < std::numeric_limits<uint32_t>::digits; attributeId++)
115 : {
116 0 : if (emberAfContainsAttribute(options.endpointId, options.clusterId, attributeId))
117 : {
118 0 : optionalAttributes |= 1u << attributeId;
119 : }
120 : }
121 : }
122 :
123 0 : CHIP_ERROR err = CodegenDataModelProvider::Instance().Registry().Register(
124 0 : delegate.CreateRegistration(options.endpointId, clusterInstanceIndex, optionalAttributes, featureMap));
125 :
126 0 : if (err != CHIP_NO_ERROR)
127 : {
128 : #if CHIP_CODEGEN_CONFIG_ENABLE_CODEGEN_INTEGRATION_LOOKUP_ERRORS
129 0 : ChipLogError(AppServer, "Failed to register cluster %u/" ChipLogFormatMEI ": %" CHIP_ERROR_FORMAT, options.endpointId,
130 : ChipLogValueMEI(options.clusterId), err.Format());
131 : #endif // CHIP_CODEGEN_CONFIG_ENABLE_CODEGEN_INTEGRATION_LOOKUP_ERRORS
132 : }
133 : }
134 :
135 0 : void CodegenClusterIntegration::UnregisterServer(const UnregisterServerOptions & options, Delegate & delegate,
136 : MatterClusterShutdownType shutdownType)
137 : {
138 : uint16_t clusterInstanceIndex;
139 0 : if (!FindEndpointWithLog(options.endpointId, options.clusterId, options.fixedClusterInstanceCount,
140 0 : options.maxClusterInstanceCount, clusterInstanceIndex))
141 : {
142 0 : return;
143 : }
144 :
145 0 : CHIP_ERROR err = CodegenDataModelProvider::Instance().Registry().Unregister(delegate.FindRegistration(clusterInstanceIndex),
146 : ToServerClusterInterfaceShutdown(shutdownType));
147 0 : if (err != CHIP_NO_ERROR)
148 : {
149 : #if CHIP_CODEGEN_CONFIG_ENABLE_CODEGEN_INTEGRATION_LOOKUP_ERRORS
150 0 : ChipLogError(AppServer, "Failed to unregister cluster %u/" ChipLogFormatMEI ": %" CHIP_ERROR_FORMAT, options.endpointId,
151 : ChipLogValueMEI(options.clusterId), err.Format());
152 : #endif // CHIP_CODEGEN_CONFIG_ENABLE_CODEGEN_INTEGRATION_LOOKUP_ERRORS
153 : // NOTE: There is no sane way to handle this failure:
154 : // - Returning here means we never free resources and a future registration will fail.
155 : // - Not returning (as we do now) will free resources, but it is unclear why unregistration failed (is it still in use?).
156 : //
157 : // For now, assume that unregistration failed due to "already missing", so it is safe to delete.
158 : // However, this should never happen in practice.
159 : }
160 :
161 0 : delegate.ReleaseRegistration(clusterInstanceIndex);
162 : }
163 :
164 0 : ServerClusterInterface * CodegenClusterIntegration::FindClusterOnEndpoint(const FindClusterOnEndpointOptions & options,
165 : Delegate & delegate)
166 : {
167 : uint16_t clusterInstanceIndex;
168 0 : if (!FindEndpointWithLog(options.endpointId, options.clusterId, options.fixedClusterInstanceCount,
169 0 : options.maxClusterInstanceCount, clusterInstanceIndex))
170 : {
171 0 : return nullptr;
172 : }
173 :
174 0 : ServerClusterInterface * interface = delegate.FindRegistration(clusterInstanceIndex);
175 : #if CHIP_CODEGEN_CONFIG_ENABLE_CODEGEN_INTEGRATION_LOOKUP_ERRORS
176 0 : if (interface == nullptr)
177 : {
178 0 : ChipLogError(AppServer,
179 : "No endpoint interface available on %u/" ChipLogFormatMEI ". Code may try to use an uninitialized cluster",
180 : options.endpointId, ChipLogValueMEI(options.clusterId));
181 : }
182 : #endif
183 :
184 0 : return interface;
185 : }
186 :
187 : } // namespace chip::app
|