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