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