Line data Source code
1 : /**
2 : *
3 : * Copyright (c) 2020-2023 Project CHIP Authors
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 "lib/support/Span.h"
18 : #include <app/util/attribute-storage.h>
19 :
20 : #include <app/AttributeAccessInterfaceRegistry.h>
21 : #include <app/CommandHandlerInterfaceRegistry.h>
22 : #include <app/InteractionModelEngine.h>
23 : #include <app/persistence/AttributePersistenceProvider.h>
24 : #include <app/persistence/AttributePersistenceProviderInstance.h>
25 : #include <app/persistence/PascalString.h>
26 : #include <app/reporting/reporting.h>
27 : #include <app/util/attribute-metadata.h>
28 : #include <app/util/attribute-storage-detail.h>
29 : #include <app/util/config.h>
30 : #include <app/util/ember-io-storage.h>
31 : #include <app/util/ember-strings.h>
32 : #include <app/util/endpoint-config-api.h>
33 : #include <app/util/generic-callbacks.h>
34 : #include <lib/core/CHIPConfig.h>
35 : #include <lib/core/CHIPError.h>
36 : #include <lib/support/CodeUtils.h>
37 : #include <lib/support/logging/CHIPLogging.h>
38 : #include <platform/LockTracker.h>
39 : #include <protocols/interaction_model/StatusCode.h>
40 :
41 : using chip::Protocols::InteractionModel::Status;
42 :
43 : // Attribute storage depends on knowing the current layout/setup of attributes
44 : // and corresponding callbacks. Specifically:
45 : // - zap-generated/callback.h is needed because endpoint_config will call the
46 : // corresponding callbacks (via GENERATED_FUNCTION_ARRAYS) and the include
47 : // for it is:
48 : // util/config.h -> zap-generated/endpoint_config.h
49 : #include <app-common/zap-generated/callback.h>
50 :
51 : using namespace chip;
52 : using namespace chip::app;
53 :
54 : //------------------------------------------------------------------------------
55 : // Globals
56 : // This is not declared CONST in order to handle dynamic endpoint information
57 : // retrieved from tokens.
58 : EmberAfDefinedEndpoint emAfEndpoints[MAX_ENDPOINT_COUNT];
59 :
60 : #if (ATTRIBUTE_MAX_SIZE == 0)
61 : #define ACTUAL_ATTRIBUTE_SIZE 1
62 : #else
63 : #define ACTUAL_ATTRIBUTE_SIZE ATTRIBUTE_MAX_SIZE
64 : #endif
65 :
66 : uint8_t attributeData[ACTUAL_ATTRIBUTE_SIZE];
67 :
68 : // ----- internal-only methods, not part of the external API -----
69 :
70 : // Loads the attributes from built-in default and storage.
71 : static void emAfLoadAttributeDefaults(EndpointId endpoint, Optional<ClusterId> = NullOptional);
72 :
73 : static bool emAfMatchCluster(const EmberAfCluster * cluster, const EmberAfAttributeSearchRecord * attRecord);
74 : static bool emAfMatchAttribute(const EmberAfCluster * cluster, const EmberAfAttributeMetadata * am,
75 : const EmberAfAttributeSearchRecord * attRecord);
76 :
77 : // If server == true, returns the number of server clusters,
78 : // otherwise number of client clusters on the endpoint at the given index.
79 : static uint8_t emberAfClusterCountByIndex(uint16_t endpointIndex, bool server);
80 :
81 : // Check whether there is an endpoint defined with the given endpoint id that is
82 : // enabled.
83 : static bool emberAfEndpointIsEnabled(EndpointId endpoint);
84 :
85 : namespace {
86 :
87 : #if (!defined(ATTRIBUTE_SINGLETONS_SIZE)) || (ATTRIBUTE_SINGLETONS_SIZE == 0)
88 : #define ACTUAL_SINGLETONS_SIZE 1
89 : #else
90 : #define ACTUAL_SINGLETONS_SIZE ATTRIBUTE_SINGLETONS_SIZE
91 : #endif
92 : uint8_t singletonAttributeData[ACTUAL_SINGLETONS_SIZE];
93 :
94 : uint16_t emberEndpointCount = 0;
95 :
96 : /// Determines a incremental unique index for ember
97 : /// metadata that is increased whenever a structural change is made to the
98 : /// ember metadata (e.g. changing dynamic endpoints or enabling/disabling endpoints)
99 : unsigned emberMetadataStructureGeneration = 0;
100 :
101 : // If we have attributes that are more than 4 bytes, then
102 : // we need this data block for the defaults
103 : #if (defined(GENERATED_DEFAULTS) && GENERATED_DEFAULTS_COUNT)
104 : constexpr const uint8_t generatedDefaults[] = GENERATED_DEFAULTS;
105 : #define ZAP_LONG_DEFAULTS_INDEX(index) \
106 : { \
107 : &generatedDefaults[index] \
108 : }
109 : #endif // GENERATED_DEFAULTS
110 :
111 : #if (defined(GENERATED_MIN_MAX_DEFAULTS) && GENERATED_MIN_MAX_DEFAULT_COUNT)
112 : constexpr const EmberAfAttributeMinMaxValue minMaxDefaults[] = GENERATED_MIN_MAX_DEFAULTS;
113 : #define ZAP_MIN_MAX_DEFAULTS_INDEX(index) \
114 : { \
115 : &minMaxDefaults[index] \
116 : }
117 : #endif // GENERATED_MIN_MAX_DEFAULTS
118 :
119 : #ifdef GENERATED_FUNCTION_ARRAYS
120 : GENERATED_FUNCTION_ARRAYS
121 : #endif
122 :
123 : #ifdef GENERATED_COMMANDS
124 : constexpr const CommandId generatedCommands[] = GENERATED_COMMANDS;
125 : #define ZAP_GENERATED_COMMANDS_INDEX(index) (&generatedCommands[index])
126 : #endif // GENERATED_COMMANDS
127 :
128 : #if (defined(GENERATED_EVENTS) && (GENERATED_EVENT_COUNT > 0))
129 : constexpr const EventId generatedEvents[] = GENERATED_EVENTS;
130 : #define ZAP_GENERATED_EVENTS_INDEX(index) (&generatedEvents[index])
131 : #endif // GENERATED_EVENTS
132 :
133 : constexpr const EmberAfAttributeMetadata generatedAttributes[] = GENERATED_ATTRIBUTES;
134 : #define ZAP_ATTRIBUTE_INDEX(index) (&generatedAttributes[index])
135 :
136 : #ifdef GENERATED_CLUSTERS
137 : constexpr const EmberAfCluster generatedClusters[] = GENERATED_CLUSTERS;
138 : #define ZAP_CLUSTER_INDEX(index) (&generatedClusters[index])
139 : #endif
140 :
141 : #if FIXED_ENDPOINT_COUNT > 0
142 : constexpr const EmberAfEndpointType generatedEmberAfEndpointTypes[] = GENERATED_ENDPOINT_TYPES;
143 : constexpr const EmberAfDeviceType fixedDeviceTypeList[] = FIXED_DEVICE_TYPES;
144 :
145 : // Not const, because these need to mutate.
146 : DataVersion fixedEndpointDataVersions[ZAP_FIXED_ENDPOINT_DATA_VERSION_COUNT];
147 : #endif // FIXED_ENDPOINT_COUNT > 0
148 :
149 0 : bool emberAfIsThisDataTypeAListType(EmberAfAttributeType dataType)
150 : {
151 0 : return dataType == ZCL_ARRAY_ATTRIBUTE_TYPE;
152 : }
153 :
154 13919 : uint16_t findIndexFromEndpoint(EndpointId endpoint, bool ignoreDisabledEndpoints)
155 : {
156 13919 : if (endpoint == kInvalidEndpointId)
157 : {
158 0 : return kEmberInvalidEndpointIndex;
159 : }
160 :
161 : uint16_t epi;
162 28184 : for (epi = 0; epi < emberAfEndpointCount(); epi++)
163 : {
164 42009 : if (emAfEndpoints[epi].endpoint == endpoint &&
165 13878 : (!ignoreDisabledEndpoints || emAfEndpoints[epi].bitmask.Has(EmberAfEndpointOptions::isEnabled)))
166 : {
167 13866 : return epi;
168 : }
169 : }
170 53 : return kEmberInvalidEndpointIndex;
171 : }
172 :
173 : // Returns the index of a given endpoint. Considers disabled endpoints.
174 0 : uint16_t emberAfIndexFromEndpointIncludingDisabledEndpoints(EndpointId endpoint)
175 : {
176 0 : return findIndexFromEndpoint(endpoint, false /* ignoreDisabledEndpoints */);
177 : }
178 :
179 0 : CHIP_ERROR ValidateDataContent(ByteSpan span, const EmberAfAttributeMetadata * am)
180 : {
181 0 : if (emberAfIsStringAttributeType(am->attributeType))
182 : {
183 0 : VerifyOrReturnValue(Storage::ShortPascalBytes::IsValid(span), CHIP_ERROR_INCORRECT_STATE);
184 0 : return CHIP_NO_ERROR;
185 : }
186 :
187 0 : if (emberAfIsLongStringAttributeType(am->attributeType))
188 : {
189 0 : VerifyOrReturnValue(Storage::LongPascalBytes::IsValid(span), CHIP_ERROR_INCORRECT_STATE);
190 0 : return CHIP_NO_ERROR;
191 : }
192 :
193 0 : VerifyOrReturnValue(span.size() == am->size, CHIP_ERROR_INCORRECT_STATE);
194 0 : return CHIP_NO_ERROR;
195 : }
196 :
197 : } // anonymous namespace
198 :
199 : // Initial configuration
200 25 : void emberAfEndpointConfigure()
201 : {
202 : uint16_t ep;
203 :
204 : static_assert(FIXED_ENDPOINT_COUNT <= std::numeric_limits<decltype(ep)>::max(),
205 : "FIXED_ENDPOINT_COUNT must not exceed the size of the endpoint data type");
206 :
207 25 : emberEndpointCount = FIXED_ENDPOINT_COUNT;
208 :
209 : #if FIXED_ENDPOINT_COUNT > 0
210 :
211 25 : constexpr uint16_t fixedEndpoints[] = FIXED_ENDPOINT_ARRAY;
212 25 : constexpr uint16_t fixedDeviceTypeListLengths[] = FIXED_DEVICE_TYPE_LENGTHS;
213 25 : constexpr uint16_t fixedDeviceTypeListOffsets[] = FIXED_DEVICE_TYPE_OFFSETS;
214 25 : constexpr uint8_t fixedEmberAfEndpointTypes[] = FIXED_ENDPOINT_TYPES;
215 25 : constexpr EndpointId fixedParentEndpoints[] = FIXED_PARENT_ENDPOINTS;
216 :
217 : #if ZAP_FIXED_ENDPOINT_DATA_VERSION_COUNT > 0
218 : // Initialize our data version storage. If
219 : // ZAP_FIXED_ENDPOINT_DATA_VERSION_COUNT == 0, gcc complains about a memset
220 : // with size equal to number of elements without multiplication by element
221 : // size, because the sizeof() is also 0 in that case...
222 : if (Crypto::DRBG_get_bytes(reinterpret_cast<uint8_t *>(fixedEndpointDataVersions), sizeof(fixedEndpointDataVersions)) !=
223 : CHIP_NO_ERROR)
224 : {
225 : // Now what? At least 0-init it.
226 : memset(fixedEndpointDataVersions, 0, sizeof(fixedEndpointDataVersions));
227 : }
228 : #endif // ZAP_FIXED_ENDPOINT_DATA_VERSION_COUNT > 0
229 :
230 25 : DataVersion * currentDataVersions = fixedEndpointDataVersions;
231 50 : for (ep = 0; ep < FIXED_ENDPOINT_COUNT; ep++)
232 : {
233 25 : emAfEndpoints[ep].endpoint = fixedEndpoints[ep];
234 25 : emAfEndpoints[ep].deviceTypeList =
235 25 : Span<const EmberAfDeviceType>(&fixedDeviceTypeList[fixedDeviceTypeListOffsets[ep]], fixedDeviceTypeListLengths[ep]);
236 25 : emAfEndpoints[ep].endpointType = &generatedEmberAfEndpointTypes[fixedEmberAfEndpointTypes[ep]];
237 25 : emAfEndpoints[ep].dataVersions = currentDataVersions;
238 25 : emAfEndpoints[ep].parentEndpointId = fixedParentEndpoints[ep];
239 :
240 25 : constexpr const DeviceTypeId kRootnodeId = 0x0016;
241 25 : constexpr const DeviceTypeId kAggregatorId = 0x000E;
242 25 : constexpr const DeviceTypeId kBridgedNode = 0x0013;
243 25 : emAfEndpoints[ep].bitmask.Set(EmberAfEndpointOptions::isEnabled);
244 25 : for (const auto & deviceType : emAfEndpoints[ep].deviceTypeList)
245 : {
246 : // Default composition for all device types is set to tree. Except rootnode, aggregator and
247 : // bridgednode, which are full-family. Clients can manually override these defaults using
248 : // SetFlatCompositionForEndpoint / SetTreeCompositionForEndpoint at application init.
249 : // TODO: This information should come from the schema XML, not be hardcoded.
250 25 : if ((deviceType.deviceTypeId == kRootnodeId) || (deviceType.deviceTypeId == kAggregatorId) ||
251 0 : (deviceType.deviceTypeId == kBridgedNode))
252 : {
253 25 : emAfEndpoints[ep].bitmask.Set(EmberAfEndpointOptions::isFlatComposition);
254 25 : break;
255 : }
256 : }
257 :
258 : // Increment currentDataVersions by 1 (slot) for every server cluster
259 : // this endpoint has.
260 25 : currentDataVersions += emberAfClusterCountByIndex(ep, /* server = */ true);
261 : }
262 :
263 : #endif // FIXED_ENDPOINT_COUNT > 0
264 :
265 : #if CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT
266 : if (MAX_ENDPOINT_COUNT > FIXED_ENDPOINT_COUNT)
267 : {
268 : //
269 : // Reset instances tracking dynamic endpoints to safe defaults.
270 : //
271 125 : for (ep = FIXED_ENDPOINT_COUNT; ep < MAX_ENDPOINT_COUNT; ep++)
272 : {
273 100 : emAfEndpoints[ep] = EmberAfDefinedEndpoint();
274 : }
275 : }
276 : #endif
277 25 : }
278 :
279 28 : void emberAfSetDynamicEndpointCount(uint16_t dynamicEndpointCount)
280 : {
281 28 : emberEndpointCount = static_cast<uint16_t>(FIXED_ENDPOINT_COUNT + dynamicEndpointCount);
282 28 : }
283 :
284 0 : uint16_t emberAfGetDynamicIndexFromEndpoint(EndpointId id)
285 : {
286 0 : if (id == kInvalidEndpointId)
287 : {
288 0 : return kEmberInvalidEndpointIndex;
289 : }
290 :
291 : uint16_t index;
292 0 : for (index = FIXED_ENDPOINT_COUNT; index < MAX_ENDPOINT_COUNT; index++)
293 : {
294 0 : if (emAfEndpoints[index].endpoint == id)
295 : {
296 0 : return static_cast<uint16_t>(index - FIXED_ENDPOINT_COUNT);
297 : }
298 : }
299 0 : return kEmberInvalidEndpointIndex;
300 : }
301 :
302 28 : CHIP_ERROR emberAfSetDynamicEndpoint(uint16_t index, EndpointId id, const EmberAfEndpointType * ep,
303 : const Span<DataVersion> & dataVersionStorage, Span<const EmberAfDeviceType> deviceTypeList,
304 : EndpointId parentEndpointId)
305 : {
306 28 : return emberAfSetDynamicEndpointWithEpUniqueId(index, id, ep, dataVersionStorage, deviceTypeList, {}, parentEndpointId);
307 : }
308 :
309 28 : CHIP_ERROR emberAfSetDynamicEndpointWithEpUniqueId(uint16_t index, EndpointId id, const EmberAfEndpointType * ep,
310 : const Span<DataVersion> & dataVersionStorage,
311 : Span<const EmberAfDeviceType> deviceTypeList, CharSpan endpointUniqueId,
312 : EndpointId parentEndpointId)
313 : {
314 28 : auto realIndex = index + FIXED_ENDPOINT_COUNT;
315 :
316 28 : if (realIndex >= MAX_ENDPOINT_COUNT)
317 : {
318 0 : return CHIP_ERROR_NO_MEMORY;
319 : }
320 28 : if (id == kInvalidEndpointId)
321 : {
322 0 : return CHIP_ERROR_INVALID_ARGUMENT;
323 : }
324 :
325 28 : auto serverClusterCount = emberAfClusterCountForEndpointType(ep, /* server = */ true);
326 28 : if (dataVersionStorage.size() < serverClusterCount)
327 : {
328 0 : return CHIP_ERROR_NO_MEMORY;
329 : }
330 :
331 28 : index = static_cast<uint16_t>(realIndex);
332 140 : for (uint16_t i = FIXED_ENDPOINT_COUNT; i < MAX_ENDPOINT_COUNT; i++)
333 : {
334 112 : if (emAfEndpoints[i].endpoint == id)
335 : {
336 0 : return CHIP_ERROR_ENDPOINT_EXISTS;
337 : }
338 : }
339 :
340 28 : const size_t bufferSize = Compatibility::Internal::gEmberAttributeIOBufferSpan.size();
341 62 : for (uint8_t i = 0; i < ep->clusterCount; i++)
342 : {
343 34 : const EmberAfCluster * cluster = &(ep->cluster[i]);
344 34 : if (!cluster->attributes)
345 : {
346 0 : continue;
347 : }
348 :
349 146 : for (uint16_t j = 0; j < cluster->attributeCount; j++)
350 : {
351 112 : const EmberAfAttributeMetadata * attr = &(cluster->attributes[j]);
352 112 : uint16_t attrSize = emberAfAttributeSize(attr);
353 112 : if (attrSize > bufferSize)
354 : {
355 0 : ChipLogError(DataManagement,
356 : "Attribute size %u exceeds max size %lu, (attrId=" ChipLogFormatMEI ", clusterId=" ChipLogFormatMEI
357 : ")",
358 : attrSize, static_cast<unsigned long>(bufferSize), ChipLogValueMEI(attr->attributeId),
359 : ChipLogValueMEI(cluster->clusterId));
360 0 : return CHIP_ERROR_NO_MEMORY;
361 : }
362 : }
363 : }
364 28 : emAfEndpoints[index].endpoint = id;
365 28 : emAfEndpoints[index].deviceTypeList = deviceTypeList;
366 28 : emAfEndpoints[index].endpointType = ep;
367 28 : emAfEndpoints[index].dataVersions = dataVersionStorage.data();
368 : #if CHIP_CONFIG_USE_ENDPOINT_UNIQUE_ID
369 : MutableCharSpan targetSpan(emAfEndpoints[index].endpointUniqueId);
370 : if (CopyCharSpanToMutableCharSpan(endpointUniqueId, targetSpan) != CHIP_NO_ERROR)
371 : {
372 : return CHIP_ERROR_BUFFER_TOO_SMALL;
373 : }
374 :
375 : // Ensure that the size of emAfEndpoints[index].endpointUniqueId fits within uint8_t
376 : static_assert(sizeof(emAfEndpoints[0].endpointUniqueId) <= UINT8_MAX,
377 : "The size of emAfEndpoints[index].endpointUniqueId must fit within uint8_t");
378 :
379 : emAfEndpoints[index].endpointUniqueIdSize = static_cast<uint8_t>(targetSpan.size());
380 : #endif
381 : // Start the endpoint off as disabled.
382 28 : emAfEndpoints[index].bitmask.Clear(EmberAfEndpointOptions::isEnabled);
383 28 : emAfEndpoints[index].parentEndpointId = parentEndpointId;
384 :
385 28 : emberAfSetDynamicEndpointCount(MAX_ENDPOINT_COUNT - FIXED_ENDPOINT_COUNT);
386 :
387 : // Initialize the data versions.
388 28 : size_t dataSize = sizeof(DataVersion) * serverClusterCount;
389 28 : if (dataSize != 0)
390 : {
391 28 : if (Crypto::DRBG_get_bytes(reinterpret_cast<uint8_t *>(dataVersionStorage.data()), dataSize) != CHIP_NO_ERROR)
392 : {
393 : // Now what? At least 0-init it.
394 0 : memset(dataVersionStorage.data(), 0, dataSize);
395 : }
396 : }
397 :
398 : // Now enable the endpoint.
399 28 : emberAfEndpointEnableDisable(id, true);
400 :
401 28 : emberMetadataStructureGeneration++;
402 28 : return CHIP_NO_ERROR;
403 : }
404 :
405 27 : EndpointId emberAfClearDynamicEndpoint(uint16_t index)
406 : {
407 27 : EndpointId ep = 0;
408 :
409 27 : index = static_cast<uint16_t>(index + FIXED_ENDPOINT_COUNT);
410 :
411 54 : if ((index < MAX_ENDPOINT_COUNT) && (emAfEndpoints[index].endpoint != kInvalidEndpointId) &&
412 27 : (emberAfEndpointIndexIsEnabled(index)))
413 : {
414 27 : ep = emAfEndpoints[index].endpoint;
415 27 : emberAfEndpointEnableDisable(ep, false);
416 27 : emAfEndpoints[index].endpoint = kInvalidEndpointId;
417 : }
418 :
419 27 : emberMetadataStructureGeneration++;
420 27 : return ep;
421 : }
422 :
423 13853 : uint16_t emberAfFixedEndpointCount()
424 : {
425 13853 : return FIXED_ENDPOINT_COUNT;
426 : }
427 :
428 62616 : uint16_t emberAfEndpointCount()
429 : {
430 62616 : return emberEndpointCount;
431 : }
432 :
433 14216 : bool emberAfEndpointIndexIsEnabled(uint16_t index)
434 : {
435 14216 : return (emAfEndpoints[index].bitmask.Has(EmberAfEndpointOptions::isEnabled));
436 : }
437 :
438 : // This function is used to call the per-cluster attribute changed callback
439 0 : void emAfClusterAttributeChangedCallback(const ConcreteAttributePath & attributePath)
440 : {
441 0 : const EmberAfCluster * cluster = emberAfFindServerCluster(attributePath.mEndpointId, attributePath.mClusterId);
442 0 : if (cluster != nullptr)
443 : {
444 0 : EmberAfGenericClusterFunction f = emberAfFindClusterFunction(cluster, MATTER_CLUSTER_FLAG_ATTRIBUTE_CHANGED_FUNCTION);
445 0 : if (f != nullptr)
446 : {
447 0 : ((EmberAfClusterAttributeChangedCallback) f)(attributePath);
448 : }
449 : }
450 0 : }
451 :
452 : // This function is used to call the per-cluster pre-attribute changed callback
453 0 : Status emAfClusterPreAttributeChangedCallback(const ConcreteAttributePath & attributePath, EmberAfAttributeType attributeType,
454 : uint16_t size, uint8_t * value)
455 : {
456 0 : const EmberAfCluster * cluster = emberAfFindServerCluster(attributePath.mEndpointId, attributePath.mClusterId);
457 0 : if (cluster == nullptr)
458 : {
459 0 : if (!emberAfEndpointIsEnabled(attributePath.mEndpointId))
460 : {
461 0 : return Status::UnsupportedEndpoint;
462 : }
463 0 : return Status::UnsupportedCluster;
464 : }
465 :
466 0 : Status status = Status::Success;
467 : // Casting and calling a function pointer on the same line results in ignoring the return
468 : // of the call on gcc-arm-none-eabi-9-2019-q4-major
469 0 : EmberAfClusterPreAttributeChangedCallback f = (EmberAfClusterPreAttributeChangedCallback) (emberAfFindClusterFunction(
470 : cluster, MATTER_CLUSTER_FLAG_PRE_ATTRIBUTE_CHANGED_FUNCTION));
471 0 : if (f != nullptr)
472 : {
473 0 : status = f(attributePath, attributeType, size, value);
474 : }
475 0 : return status;
476 : }
477 :
478 54 : static void initializeEndpoint(EmberAfDefinedEndpoint * definedEndpoint)
479 : {
480 : uint8_t clusterIndex;
481 54 : const EmberAfEndpointType * epType = definedEndpoint->endpointType;
482 2964 : for (clusterIndex = 0; clusterIndex < epType->clusterCount; clusterIndex++)
483 : {
484 2910 : const EmberAfCluster * cluster = &(epType->cluster[clusterIndex]);
485 : EmberAfGenericClusterFunction f;
486 2910 : emberAfClusterInitCallback(definedEndpoint->endpoint, cluster->clusterId);
487 2910 : f = emberAfFindClusterFunction(cluster, MATTER_CLUSTER_FLAG_INIT_FUNCTION);
488 2910 : if (f != nullptr)
489 : {
490 0 : ((EmberAfInitFunction) f)(definedEndpoint->endpoint);
491 : }
492 : }
493 54 : }
494 :
495 28 : static void shutdownEndpoint(EmberAfDefinedEndpoint * definedEndpoint)
496 : {
497 : // Call shutdown callbacks from clusters, mainly for canceling pending timers
498 : uint8_t clusterIndex;
499 28 : const EmberAfEndpointType * epType = definedEndpoint->endpointType;
500 62 : for (clusterIndex = 0; clusterIndex < epType->clusterCount; clusterIndex++)
501 : {
502 34 : const EmberAfCluster * cluster = &(epType->cluster[clusterIndex]);
503 34 : EmberAfGenericClusterFunction f = emberAfFindClusterFunction(cluster, MATTER_CLUSTER_FLAG_SHUTDOWN_FUNCTION);
504 34 : if (f != nullptr)
505 : {
506 0 : ((EmberAfShutdownFunction) f)(definedEndpoint->endpoint);
507 : }
508 : }
509 :
510 28 : CommandHandlerInterfaceRegistry::Instance().UnregisterAllCommandHandlersForEndpoint(definedEndpoint->endpoint);
511 28 : AttributeAccessInterfaceRegistry::Instance().UnregisterAllForEndpoint(definedEndpoint->endpoint);
512 28 : }
513 :
514 : // Calls the init functions.
515 25 : void emAfCallInits()
516 : {
517 : uint16_t index;
518 50 : for (index = 0; index < emberAfEndpointCount(); index++)
519 : {
520 25 : if (emberAfEndpointIndexIsEnabled(index))
521 : {
522 25 : initializeEndpoint(&(emAfEndpoints[index]));
523 : }
524 : }
525 25 : }
526 :
527 : // Returns the pointer to metadata, or null if it is not found
528 6914 : const EmberAfAttributeMetadata * emberAfLocateAttributeMetadata(EndpointId endpoint, ClusterId clusterId, AttributeId attributeId)
529 : {
530 6914 : const EmberAfAttributeMetadata * metadata = nullptr;
531 : EmberAfAttributeSearchRecord record;
532 6914 : record.endpoint = endpoint;
533 6914 : record.clusterId = clusterId;
534 6914 : record.attributeId = attributeId;
535 6914 : emAfReadOrWriteAttribute(&record, &metadata,
536 : nullptr, // buffer
537 : 0, // buffer size
538 : false); // write?
539 6914 : return metadata;
540 : }
541 :
542 0 : static uint8_t * singletonAttributeLocation(const EmberAfAttributeMetadata * am)
543 : {
544 :
545 0 : uint16_t index = 0;
546 : // NOLINTNEXTLINE(bugprone-sizeof-expression)
547 : if constexpr (sizeof(generatedAttributes) > 0)
548 : {
549 : const EmberAfAttributeMetadata * m = &(generatedAttributes[0]);
550 : while (m < am)
551 : {
552 : if (m->IsSingleton() && !m->IsExternal())
553 : {
554 : index = static_cast<uint16_t>(index + m->size);
555 : }
556 : m++;
557 : }
558 : }
559 0 : return (uint8_t *) (singletonAttributeData + index);
560 : }
561 :
562 : // This function does mem copy, but smartly, which means that if the type is a
563 : // string, it will copy as much as it can.
564 : // If src == NULL, then this method will set memory to zeroes
565 : // See documentation for emAfReadOrWriteAttribute for the semantics of
566 : // readLength when reading and writing.
567 0 : static Status typeSensitiveMemCopy(ClusterId clusterId, uint8_t * dest, uint8_t * src, const EmberAfAttributeMetadata * am,
568 : bool write, uint16_t readLength)
569 : {
570 0 : EmberAfAttributeType attributeType = am->attributeType;
571 : // readLength == 0 for a read indicates that we should just trust that the
572 : // caller has enough space for an attribute...
573 0 : bool ignoreReadLength = write || (readLength == 0);
574 0 : uint16_t bufferSize = ignoreReadLength ? am->size : readLength;
575 :
576 0 : if (emberAfIsStringAttributeType(attributeType))
577 : {
578 0 : if (bufferSize < 1)
579 : {
580 0 : return Status::ResourceExhausted;
581 : }
582 0 : emberAfCopyString(dest, src, bufferSize - 1);
583 : }
584 0 : else if (emberAfIsLongStringAttributeType(attributeType))
585 : {
586 0 : if (bufferSize < 2)
587 : {
588 0 : return Status::ResourceExhausted;
589 : }
590 0 : emberAfCopyLongString(dest, src, bufferSize - 2);
591 : }
592 0 : else if (emberAfIsThisDataTypeAListType(attributeType))
593 : {
594 0 : if (bufferSize < 2)
595 : {
596 0 : return Status::ResourceExhausted;
597 : }
598 :
599 : // Just copy the length.
600 0 : memmove(dest, src, 2);
601 : }
602 : else
603 : {
604 0 : if (!ignoreReadLength && readLength < am->size)
605 : {
606 0 : return Status::ResourceExhausted;
607 : }
608 0 : if (src == nullptr)
609 : {
610 0 : memset(dest, 0, am->size);
611 : }
612 : else
613 : {
614 0 : memmove(dest, src, am->size);
615 : }
616 : }
617 0 : return Status::Success;
618 : }
619 :
620 : /**
621 : * @brief Matches a cluster based on cluster id and direction.
622 : *
623 : * This function assumes that the passed cluster's endpoint already
624 : * matches the endpoint of the EmberAfAttributeSearchRecord.
625 : *
626 : * Clusters match if:
627 : * 1. Cluster ids match AND
628 : * 2. Cluster is a server cluster (because there are no client attributes).
629 : */
630 6914 : bool emAfMatchCluster(const EmberAfCluster * cluster, const EmberAfAttributeSearchRecord * attRecord)
631 : {
632 6914 : return (cluster->clusterId == attRecord->clusterId && (cluster->mask & MATTER_CLUSTER_FLAG_SERVER));
633 : }
634 :
635 : /**
636 : * @brief Matches an attribute based on attribute id.
637 : * This function assumes that the passed cluster already matches the
638 : * clusterId and direction of the passed EmberAfAttributeSearchRecord.
639 : *
640 : * Attributes match if attr ids match.
641 : */
642 10021 : bool emAfMatchAttribute(const EmberAfCluster * cluster, const EmberAfAttributeMetadata * am,
643 : const EmberAfAttributeSearchRecord * attRecord)
644 : {
645 10021 : return (am->attributeId == attRecord->attributeId);
646 : }
647 :
648 : // When reading non-string attributes, this function returns an error when destination
649 : // buffer isn't large enough to accommodate the attribute type. For strings, the
650 : // function will copy at most readLength bytes. This means the resulting string
651 : // may be truncated. The length byte(s) in the resulting string will reflect
652 : // any truncation. If readLength is zero, we are working with backwards-
653 : // compatibility wrapper functions and we just cross our fingers and hope for
654 : // the best.
655 : //
656 : // When writing attributes, readLength is ignored. For non-string attributes,
657 : // this function assumes the source buffer is the same size as the attribute
658 : // type. For strings, the function will copy as many bytes as will fit in the
659 : // attribute. This means the resulting string may be truncated. The length
660 : // byte(s) in the resulting string will reflect any truncated.
661 6914 : Status emAfReadOrWriteAttribute(const EmberAfAttributeSearchRecord * attRecord, const EmberAfAttributeMetadata ** metadata,
662 : uint8_t * buffer, uint16_t readLength, bool write)
663 : {
664 6914 : assertChipStackLockedByCurrentThread();
665 :
666 6914 : uint16_t attributeOffsetIndex = 0;
667 :
668 13853 : for (uint16_t ep = 0; ep < emberAfEndpointCount(); ep++)
669 : {
670 : // Is this a dynamic endpoint?
671 13853 : bool isDynamicEndpoint = (ep >= emberAfFixedEndpointCount());
672 :
673 13853 : if (emAfEndpoints[ep].endpoint == attRecord->endpoint)
674 : {
675 6914 : const EmberAfEndpointType * endpointType = emAfEndpoints[ep].endpointType;
676 : uint8_t clusterIndex;
677 6914 : if (!emberAfEndpointIndexIsEnabled(ep))
678 : {
679 0 : continue;
680 : }
681 6914 : for (clusterIndex = 0; clusterIndex < endpointType->clusterCount; clusterIndex++)
682 : {
683 6914 : const EmberAfCluster * cluster = &(endpointType->cluster[clusterIndex]);
684 6914 : if (emAfMatchCluster(cluster, attRecord))
685 : { // Got the cluster
686 : uint16_t attrIndex;
687 10021 : for (attrIndex = 0; attrIndex < cluster->attributeCount; attrIndex++)
688 : {
689 10021 : const EmberAfAttributeMetadata * am = &(cluster->attributes[attrIndex]);
690 10021 : if (emAfMatchAttribute(cluster, am, attRecord))
691 : { // Got the attribute
692 : // If passed metadata location is not null, populate
693 6914 : if (metadata != nullptr)
694 : {
695 6914 : *metadata = am;
696 : }
697 :
698 : {
699 : uint8_t * attributeLocation =
700 6914 : (am->mask & MATTER_ATTRIBUTE_FLAG_SINGLETON ? singletonAttributeLocation(am)
701 6914 : : attributeData + attributeOffsetIndex);
702 : uint8_t *src, *dst;
703 6914 : if (write)
704 : {
705 0 : src = buffer;
706 0 : dst = attributeLocation;
707 0 : if (!emberAfAttributeWriteAccessCallback(attRecord->endpoint, attRecord->clusterId,
708 0 : am->attributeId))
709 : {
710 0 : return Status::UnsupportedAccess;
711 : }
712 : }
713 : else
714 : {
715 6914 : if (buffer == nullptr)
716 : {
717 6914 : return Status::Success;
718 : }
719 :
720 0 : src = attributeLocation;
721 0 : dst = buffer;
722 0 : if (!emberAfAttributeReadAccessCallback(attRecord->endpoint, attRecord->clusterId,
723 0 : am->attributeId))
724 : {
725 0 : return Status::UnsupportedAccess;
726 : }
727 : }
728 :
729 : // Is the attribute externally stored?
730 0 : if (am->mask & MATTER_ATTRIBUTE_FLAG_EXTERNAL_STORAGE)
731 : {
732 0 : if (write)
733 : {
734 0 : return emberAfExternalAttributeWriteCallback(attRecord->endpoint, attRecord->clusterId, am,
735 0 : buffer);
736 : }
737 :
738 0 : if (readLength < emberAfAttributeSize(am))
739 : {
740 : // Prevent a potential buffer overflow
741 0 : return Status::ResourceExhausted;
742 : }
743 :
744 0 : return emberAfExternalAttributeReadCallback(attRecord->endpoint, attRecord->clusterId, am,
745 0 : buffer, emberAfAttributeSize(am));
746 : }
747 :
748 : // Internal storage is only supported for fixed endpoints
749 0 : if (!isDynamicEndpoint)
750 : {
751 0 : return typeSensitiveMemCopy(attRecord->clusterId, dst, src, am, write, readLength);
752 : }
753 :
754 0 : return Status::Failure;
755 : }
756 : }
757 : else
758 : { // Not the attribute we are looking for
759 : // Increase the index if attribute is not externally stored
760 3107 : if (!(am->mask & MATTER_ATTRIBUTE_FLAG_EXTERNAL_STORAGE) &&
761 0 : !(am->mask & MATTER_ATTRIBUTE_FLAG_SINGLETON))
762 : {
763 0 : attributeOffsetIndex = static_cast<uint16_t>(attributeOffsetIndex + emberAfAttributeSize(am));
764 : }
765 : }
766 : }
767 :
768 : // Attribute is not in the cluster.
769 0 : return Status::UnsupportedAttribute;
770 : }
771 :
772 : // Not the cluster we are looking for
773 0 : attributeOffsetIndex = static_cast<uint16_t>(attributeOffsetIndex + cluster->clusterSize);
774 : }
775 :
776 : // Cluster is not in the endpoint.
777 0 : return Status::UnsupportedCluster;
778 : }
779 :
780 : // Not the endpoint we are looking for
781 : // Dynamic endpoints are external and don't factor into storage size
782 6939 : if (!isDynamicEndpoint)
783 : {
784 6914 : attributeOffsetIndex = static_cast<uint16_t>(attributeOffsetIndex + emAfEndpoints[ep].endpointType->endpointSize);
785 : }
786 : }
787 0 : return Status::UnsupportedEndpoint; // Sorry, endpoint was not found.
788 : }
789 :
790 4310 : const EmberAfEndpointType * emberAfFindEndpointType(EndpointId endpointId)
791 : {
792 4310 : uint16_t ep = emberAfIndexFromEndpoint(endpointId);
793 4310 : if (ep == kEmberInvalidEndpointIndex)
794 : {
795 5 : return nullptr;
796 : }
797 4305 : return emAfEndpoints[ep].endpointType;
798 : }
799 :
800 9504 : const EmberAfCluster * emberAfFindClusterInType(const EmberAfEndpointType * endpointType, ClusterId clusterId,
801 : EmberAfClusterMask mask, uint8_t * index)
802 : {
803 : uint8_t i;
804 9504 : uint8_t scopedIndex = 0;
805 :
806 9535 : for (i = 0; i < endpointType->clusterCount; i++)
807 : {
808 9525 : const EmberAfCluster * cluster = &(endpointType->cluster[i]);
809 :
810 9525 : if (mask == 0 || ((cluster->mask & mask) != 0))
811 : {
812 9525 : if (cluster->clusterId == clusterId)
813 : {
814 9494 : if (index)
815 : {
816 9459 : *index = scopedIndex;
817 : }
818 :
819 9494 : return cluster;
820 : }
821 :
822 31 : scopedIndex++;
823 : }
824 : }
825 :
826 10 : return nullptr;
827 : }
828 :
829 9469 : uint8_t emberAfClusterIndex(EndpointId endpoint, ClusterId clusterId, EmberAfClusterMask mask)
830 : {
831 19053 : for (uint16_t ep = 0; ep < emberAfEndpointCount(); ep++)
832 : {
833 : // Check the endpoint id first, because that way we avoid examining the
834 : // endpoint type for endpoints that are not actually defined.
835 19043 : if (emAfEndpoints[ep].endpoint == endpoint)
836 : {
837 9469 : const EmberAfEndpointType * endpointType = emAfEndpoints[ep].endpointType;
838 9469 : uint8_t index = 0xFF;
839 9469 : if (emberAfFindClusterInType(endpointType, clusterId, mask, &index) != nullptr)
840 : {
841 9459 : return index;
842 : }
843 : }
844 : }
845 10 : return 0xFF;
846 : }
847 :
848 : // Returns whether the given endpoint has the server of the given cluster on it.
849 0 : bool emberAfContainsServer(EndpointId endpoint, ClusterId clusterId)
850 : {
851 0 : return (emberAfFindServerCluster(endpoint, clusterId) != nullptr);
852 : }
853 :
854 : // Returns whether the given endpoint has the client of the given cluster on it.
855 0 : bool emberAfContainsClient(EndpointId endpoint, ClusterId clusterId)
856 : {
857 0 : uint16_t ep = emberAfIndexFromEndpoint(endpoint);
858 0 : if (ep == kEmberInvalidEndpointIndex)
859 : {
860 0 : return false;
861 : }
862 :
863 0 : return (emberAfFindClusterInType(emAfEndpoints[ep].endpointType, clusterId, MATTER_CLUSTER_FLAG_CLIENT) != nullptr);
864 : }
865 :
866 : // This will find the first server that has the clusterId given from the index of endpoint.
867 0 : bool emberAfContainsServerFromIndex(uint16_t index, ClusterId clusterId)
868 : {
869 0 : if (index == kEmberInvalidEndpointIndex)
870 : {
871 0 : return false;
872 : }
873 :
874 0 : return emberAfFindClusterInType(emAfEndpoints[index].endpointType, clusterId, MATTER_CLUSTER_FLAG_SERVER);
875 : }
876 :
877 : namespace chip {
878 : namespace app {
879 :
880 0 : EnabledEndpointsWithServerCluster::EnabledEndpointsWithServerCluster(ClusterId clusterId) :
881 0 : mEndpointCount(emberAfEndpointCount()), mClusterId(clusterId)
882 : {
883 0 : EnsureMatchingEndpoint();
884 0 : }
885 :
886 0 : EndpointId EnabledEndpointsWithServerCluster::operator*() const
887 : {
888 0 : return emberAfEndpointFromIndex(mEndpointIndex);
889 : }
890 :
891 0 : EnabledEndpointsWithServerCluster & EnabledEndpointsWithServerCluster::operator++()
892 : {
893 0 : ++mEndpointIndex;
894 0 : EnsureMatchingEndpoint();
895 0 : return *this;
896 : }
897 :
898 0 : void EnabledEndpointsWithServerCluster::EnsureMatchingEndpoint()
899 : {
900 0 : for (; mEndpointIndex < mEndpointCount; ++mEndpointIndex)
901 : {
902 0 : if (!emberAfEndpointIndexIsEnabled(mEndpointIndex))
903 : {
904 0 : continue;
905 : }
906 :
907 0 : if (emberAfContainsServerFromIndex(mEndpointIndex, mClusterId))
908 : {
909 0 : break;
910 : }
911 : }
912 0 : }
913 :
914 : } // namespace app
915 : } // namespace chip
916 :
917 : // Finds the cluster that matches endpoint, clusterId, direction.
918 36 : const EmberAfCluster * emberAfFindServerCluster(EndpointId endpoint, ClusterId clusterId)
919 : {
920 36 : uint16_t ep = emberAfIndexFromEndpoint(endpoint);
921 36 : if (ep == kEmberInvalidEndpointIndex)
922 : {
923 1 : return nullptr;
924 : }
925 :
926 35 : return emberAfFindClusterInType(emAfEndpoints[ep].endpointType, clusterId, MATTER_CLUSTER_FLAG_SERVER);
927 : }
928 :
929 : // Returns cluster within the endpoint; Does not ignore disabled endpoints
930 0 : const EmberAfCluster * emberAfFindClusterIncludingDisabledEndpoints(EndpointId endpoint, ClusterId clusterId,
931 : EmberAfClusterMask mask)
932 : {
933 0 : uint16_t ep = emberAfIndexFromEndpointIncludingDisabledEndpoints(endpoint);
934 0 : if (ep < MAX_ENDPOINT_COUNT)
935 : {
936 0 : return emberAfFindClusterInType(emAfEndpoints[ep].endpointType, clusterId, mask);
937 : }
938 0 : return nullptr;
939 : }
940 :
941 0 : uint16_t emberAfGetClusterServerEndpointIndex(EndpointId endpoint, ClusterId cluster, uint16_t fixedClusterServerEndpointCount)
942 : {
943 0 : VerifyOrDie(fixedClusterServerEndpointCount <= FIXED_ENDPOINT_COUNT);
944 0 : uint16_t epIndex = findIndexFromEndpoint(endpoint, true /*ignoreDisabledEndpoints*/);
945 :
946 : // Endpoint must be configured and enabled
947 0 : if (epIndex == kEmberInvalidEndpointIndex)
948 : {
949 0 : return kEmberInvalidEndpointIndex;
950 : }
951 :
952 0 : if (emberAfFindClusterInType(emAfEndpoints[epIndex].endpointType, cluster, MATTER_CLUSTER_FLAG_SERVER) == nullptr)
953 : {
954 : // The provided endpoint does not contain the given cluster server.
955 0 : return kEmberInvalidEndpointIndex;
956 : }
957 :
958 0 : if (epIndex < FIXED_ENDPOINT_COUNT)
959 : {
960 : // This endpoint is a fixed one.
961 : // Return the index of this endpoint in the list of fixed endpoints that support the given cluster.
962 0 : uint16_t adjustedEndpointIndex = 0;
963 0 : for (uint16_t i = 0; i < epIndex; i++)
964 : {
965 : // Increase adjustedEndpointIndex for every endpoint containing the cluster server
966 : // before our endpoint of interest
967 0 : if (emAfEndpoints[i].endpoint != kInvalidEndpointId &&
968 0 : (emberAfFindClusterInType(emAfEndpoints[i].endpointType, cluster, MATTER_CLUSTER_FLAG_SERVER) != nullptr))
969 : {
970 0 : adjustedEndpointIndex++;
971 : }
972 : }
973 :
974 : // If this asserts, the provided fixedClusterServerEndpointCount doesn't match the app data model.
975 0 : VerifyOrDie(adjustedEndpointIndex < fixedClusterServerEndpointCount);
976 0 : epIndex = adjustedEndpointIndex;
977 : }
978 : else
979 : {
980 : // This is a dynamic endpoint.
981 : // Its index is just its index in the dynamic endpoint list, offset by fixedClusterServerEndpointCount.
982 0 : epIndex = static_cast<uint16_t>(fixedClusterServerEndpointCount + (epIndex - FIXED_ENDPOINT_COUNT));
983 : }
984 :
985 0 : return epIndex;
986 : }
987 :
988 0 : bool emberAfEndpointIsEnabled(EndpointId endpoint)
989 : {
990 0 : uint16_t index = findIndexFromEndpoint(endpoint, false /* ignoreDisabledEndpoints */);
991 :
992 0 : if (kEmberInvalidEndpointIndex == index)
993 : {
994 0 : return false;
995 : }
996 :
997 0 : return emberAfEndpointIndexIsEnabled(index);
998 : }
999 :
1000 57 : bool emberAfEndpointEnableDisable(EndpointId endpoint, bool enable)
1001 : {
1002 57 : uint16_t index = findIndexFromEndpoint(endpoint, false /* ignoreDisabledEndpoints */);
1003 : bool currentlyEnabled;
1004 :
1005 57 : if (kEmberInvalidEndpointIndex == index)
1006 : {
1007 0 : return false;
1008 : }
1009 :
1010 57 : currentlyEnabled = emAfEndpoints[index].bitmask.Has(EmberAfEndpointOptions::isEnabled);
1011 :
1012 57 : if (enable)
1013 : {
1014 29 : emAfEndpoints[index].bitmask.Set(EmberAfEndpointOptions::isEnabled);
1015 : }
1016 :
1017 57 : if (currentlyEnabled != enable)
1018 : {
1019 57 : if (enable)
1020 : {
1021 29 : initializeEndpoint(&(emAfEndpoints[index]));
1022 29 : emberAfEndpointChanged(endpoint, emberAfGlobalInteractionModelAttributesChangedListener());
1023 : }
1024 : else
1025 : {
1026 28 : shutdownEndpoint(&(emAfEndpoints[index]));
1027 28 : emAfEndpoints[index].bitmask.Clear(EmberAfEndpointOptions::isEnabled);
1028 : }
1029 :
1030 57 : EndpointId parentEndpointId = emberAfParentEndpointFromIndex(index);
1031 57 : while (parentEndpointId != kInvalidEndpointId)
1032 : {
1033 0 : emberAfAttributeChanged(parentEndpointId, Clusters::Descriptor::Id, Clusters::Descriptor::Attributes::PartsList::Id,
1034 : emberAfGlobalInteractionModelAttributesChangedListener());
1035 0 : uint16_t parentIndex = emberAfIndexFromEndpoint(parentEndpointId);
1036 0 : if (parentIndex == kEmberInvalidEndpointIndex)
1037 : {
1038 : // Something has gone wrong.
1039 0 : break;
1040 : }
1041 0 : parentEndpointId = emberAfParentEndpointFromIndex(parentIndex);
1042 : }
1043 :
1044 57 : emberAfAttributeChanged(/* endpoint = */ 0, Clusters::Descriptor::Id, Clusters::Descriptor::Attributes::PartsList::Id,
1045 : emberAfGlobalInteractionModelAttributesChangedListener());
1046 : }
1047 :
1048 57 : emberMetadataStructureGeneration++;
1049 57 : return true;
1050 : }
1051 :
1052 12136 : unsigned emberAfMetadataStructureGeneration()
1053 : {
1054 12136 : return emberMetadataStructureGeneration;
1055 : }
1056 :
1057 : // Returns the index of a given endpoint. Does not consider disabled endpoints.
1058 13862 : uint16_t emberAfIndexFromEndpoint(EndpointId endpoint)
1059 : {
1060 13862 : return findIndexFromEndpoint(endpoint, true /* ignoreDisabledEndpoints */);
1061 : }
1062 :
1063 2917 : EndpointId emberAfEndpointFromIndex(uint16_t index)
1064 : {
1065 2917 : return emAfEndpoints[index].endpoint;
1066 : }
1067 :
1068 2974 : EndpointId emberAfParentEndpointFromIndex(uint16_t index)
1069 : {
1070 2974 : return emAfEndpoints[index].parentEndpointId;
1071 : }
1072 :
1073 : // If server == true, returns the number of server clusters,
1074 : // otherwise number of client clusters on this endpoint
1075 0 : uint8_t emberAfClusterCount(EndpointId endpoint, bool server)
1076 : {
1077 0 : uint16_t index = emberAfIndexFromEndpoint(endpoint);
1078 0 : if (index == kEmberInvalidEndpointIndex)
1079 : {
1080 0 : return 0;
1081 : }
1082 :
1083 0 : return emberAfClusterCountByIndex(index, server);
1084 : }
1085 :
1086 25 : uint8_t emberAfClusterCountByIndex(uint16_t endpointIndex, bool server)
1087 : {
1088 25 : const EmberAfDefinedEndpoint * de = &(emAfEndpoints[endpointIndex]);
1089 25 : if (de->endpointType == nullptr)
1090 : {
1091 0 : return 0;
1092 : }
1093 :
1094 25 : return emberAfClusterCountForEndpointType(de->endpointType, server);
1095 : }
1096 :
1097 4358 : uint8_t emberAfClusterCountForEndpointType(const EmberAfEndpointType * type, bool server)
1098 : {
1099 4358 : const EmberAfClusterMask cluster_mask = server ? MATTER_CLUSTER_FLAG_SERVER : MATTER_CLUSTER_FLAG_CLIENT;
1100 :
1101 4358 : return static_cast<uint8_t>(std::count_if(type->cluster, type->cluster + type->clusterCount,
1102 13075 : [=](const EmberAfCluster & cluster) { return (cluster.mask & cluster_mask) != 0; }));
1103 : }
1104 :
1105 0 : uint8_t emberAfGetClusterCountForEndpoint(EndpointId endpoint)
1106 : {
1107 0 : uint16_t index = emberAfIndexFromEndpoint(endpoint);
1108 0 : if (index == kEmberInvalidEndpointIndex)
1109 : {
1110 0 : return 0;
1111 : }
1112 0 : return emAfEndpoints[index].endpointType->clusterCount;
1113 : }
1114 :
1115 0 : Span<const EmberAfDeviceType> emberAfDeviceTypeListFromEndpoint(EndpointId endpoint, CHIP_ERROR & err)
1116 : {
1117 0 : return emberAfDeviceTypeListFromEndpointIndex(emberAfIndexFromEndpoint(endpoint), err);
1118 : }
1119 :
1120 0 : chip::Span<const EmberAfDeviceType> emberAfDeviceTypeListFromEndpointIndex(unsigned endpointIndex, CHIP_ERROR & err)
1121 : {
1122 0 : if (endpointIndex == 0xFFFF)
1123 : {
1124 0 : err = CHIP_ERROR_INVALID_ARGUMENT;
1125 0 : return Span<const EmberAfDeviceType>();
1126 : }
1127 :
1128 0 : err = CHIP_NO_ERROR;
1129 0 : return emAfEndpoints[endpointIndex].deviceTypeList;
1130 : }
1131 :
1132 0 : CHIP_ERROR GetSemanticTagForEndpointAtIndex(EndpointId endpoint, size_t index,
1133 : Clusters::Descriptor::Structs::SemanticTagStruct::Type & tag)
1134 : {
1135 0 : uint16_t endpointIndex = emberAfIndexFromEndpoint(endpoint);
1136 :
1137 0 : if (endpointIndex == 0xFFFF || index >= emAfEndpoints[endpointIndex].tagList.size())
1138 : {
1139 0 : return CHIP_ERROR_NOT_FOUND;
1140 : }
1141 0 : tag = emAfEndpoints[endpointIndex].tagList[index];
1142 0 : return CHIP_NO_ERROR;
1143 : }
1144 : #if CHIP_CONFIG_USE_ENDPOINT_UNIQUE_ID
1145 : CHIP_ERROR emberAfGetEndpointUniqueIdForEndPoint(EndpointId endpoint, MutableCharSpan & epUniqueIdMutSpan)
1146 : {
1147 : uint16_t endpointIndex = emberAfIndexFromEndpoint(endpoint);
1148 :
1149 : if (endpointIndex == 0xFFFF)
1150 : {
1151 : return CHIP_ERROR_NOT_FOUND;
1152 : }
1153 :
1154 : CharSpan epUniqueIdSpan(emAfEndpoints[endpointIndex].endpointUniqueId, emAfEndpoints[endpointIndex].endpointUniqueIdSize);
1155 : return CopyCharSpanToMutableCharSpan(epUniqueIdSpan, epUniqueIdMutSpan);
1156 : }
1157 : #endif
1158 0 : CHIP_ERROR emberAfSetDeviceTypeList(EndpointId endpoint, Span<const EmberAfDeviceType> deviceTypeList)
1159 : {
1160 0 : uint16_t endpointIndex = emberAfIndexFromEndpoint(endpoint);
1161 0 : if (endpointIndex == 0xFFFF)
1162 : {
1163 0 : return CHIP_ERROR_INVALID_ARGUMENT;
1164 : }
1165 :
1166 0 : emAfEndpoints[endpointIndex].deviceTypeList = deviceTypeList;
1167 0 : return CHIP_NO_ERROR;
1168 : }
1169 :
1170 0 : CHIP_ERROR SetTagList(EndpointId endpoint, Span<const Clusters::Descriptor::Structs::SemanticTagStruct::Type> tagList)
1171 : {
1172 0 : uint16_t endpointIndex = emberAfIndexFromEndpoint(endpoint);
1173 0 : if (endpointIndex == 0xFFFF)
1174 : {
1175 0 : return CHIP_ERROR_INVALID_ARGUMENT;
1176 : }
1177 :
1178 0 : emAfEndpoints[endpointIndex].tagList = tagList;
1179 0 : return CHIP_NO_ERROR;
1180 : }
1181 :
1182 : // Returns the cluster of Nth server or client cluster,
1183 : // depending on server toggle.
1184 0 : const EmberAfCluster * emberAfGetNthCluster(EndpointId endpoint, uint8_t n, bool server)
1185 : {
1186 0 : uint16_t index = emberAfIndexFromEndpoint(endpoint);
1187 0 : if (index == kEmberInvalidEndpointIndex)
1188 : {
1189 0 : return nullptr;
1190 : }
1191 :
1192 0 : const EmberAfEndpointType * endpointType = emAfEndpoints[index].endpointType;
1193 0 : const EmberAfClusterMask cluster_mask = server ? MATTER_CLUSTER_FLAG_SERVER : MATTER_CLUSTER_FLAG_CLIENT;
1194 0 : const uint8_t clusterCount = endpointType->clusterCount;
1195 :
1196 0 : uint8_t c = 0;
1197 0 : for (uint8_t i = 0; i < clusterCount; i++)
1198 : {
1199 0 : const EmberAfCluster * cluster = &(endpointType->cluster[i]);
1200 :
1201 0 : if ((cluster->mask & cluster_mask) == 0)
1202 : {
1203 0 : continue;
1204 : }
1205 :
1206 0 : if (c == n)
1207 : {
1208 0 : return cluster;
1209 : }
1210 :
1211 0 : c++;
1212 : }
1213 0 : return nullptr;
1214 : }
1215 :
1216 : // Returns the cluster id of Nth server or client cluster,
1217 : // depending on server toggle.
1218 : // Returns Optional<ClusterId>::Missing() if cluster does not exist.
1219 0 : Optional<ClusterId> emberAfGetNthClusterId(EndpointId endpoint, uint8_t n, bool server)
1220 : {
1221 0 : const EmberAfCluster * cluster = emberAfGetNthCluster(endpoint, n, server);
1222 0 : if (cluster == nullptr)
1223 : {
1224 0 : return Optional<ClusterId>::Missing();
1225 : }
1226 0 : return Optional<ClusterId>(cluster->clusterId);
1227 : }
1228 :
1229 : // Returns number of clusters put into the passed cluster list
1230 : // for the given endpoint and client/server polarity
1231 0 : uint8_t emberAfGetClustersFromEndpoint(EndpointId endpoint, ClusterId * clusterList, uint8_t listLen, bool server)
1232 : {
1233 0 : uint8_t clusterCount = emberAfClusterCount(endpoint, server);
1234 : uint8_t i;
1235 : const EmberAfCluster * cluster;
1236 0 : if (clusterCount > listLen)
1237 : {
1238 0 : clusterCount = listLen;
1239 : }
1240 0 : for (i = 0; i < clusterCount; i++)
1241 : {
1242 0 : cluster = emberAfGetNthCluster(endpoint, i, server);
1243 0 : clusterList[i] = (cluster == nullptr ? kEmberInvalidEndpointIndex : cluster->clusterId);
1244 : }
1245 0 : return clusterCount;
1246 : }
1247 :
1248 25 : void emberAfInitializeAttributes(EndpointId endpoint)
1249 : {
1250 25 : emAfLoadAttributeDefaults(endpoint);
1251 25 : }
1252 :
1253 25 : void emAfLoadAttributeDefaults(EndpointId endpoint, Optional<ClusterId> clusterId)
1254 : {
1255 : uint16_t ep;
1256 : uint8_t clusterI;
1257 : uint16_t attr;
1258 : uint8_t * ptr;
1259 25 : uint16_t epCount = emberAfEndpointCount();
1260 : uint8_t attrData[ATTRIBUTE_LARGEST];
1261 25 : auto * attrStorage = GetAttributePersistenceProvider();
1262 : // Don't check whether we actually have an attrStorage here, because it's OK
1263 : // to have one if none of our attributes have NVM storage.
1264 :
1265 50 : for (ep = 0; ep < epCount; ep++)
1266 : {
1267 : EmberAfDefinedEndpoint * de;
1268 25 : if (endpoint != kInvalidEndpointId)
1269 : {
1270 0 : ep = emberAfIndexFromEndpoint(endpoint);
1271 0 : if (ep == kEmberInvalidEndpointIndex)
1272 : {
1273 0 : return;
1274 : }
1275 : }
1276 25 : de = &(emAfEndpoints[ep]);
1277 :
1278 2900 : for (clusterI = 0; clusterI < de->endpointType->clusterCount; clusterI++)
1279 : {
1280 2875 : const EmberAfCluster * cluster = &(de->endpointType->cluster[clusterI]);
1281 2875 : if (clusterId.HasValue())
1282 : {
1283 0 : if (clusterId.Value() != cluster->clusterId)
1284 : {
1285 0 : continue;
1286 : }
1287 : }
1288 :
1289 : // when the attributeCount is high, the loop takes too long to run and a
1290 : // watchdog kicks in causing a reset. As a workaround, we'll
1291 : // conditionally manually reset the watchdog. 300 sounds like a good
1292 : // magic number for now.
1293 2875 : if (cluster->attributeCount > 300)
1294 : {
1295 : // halResetWatchdog();
1296 : }
1297 2875 : for (attr = 0; attr < cluster->attributeCount; attr++)
1298 : {
1299 0 : const EmberAfAttributeMetadata * am = &(cluster->attributes[attr]);
1300 0 : ptr = nullptr; // Will get set to the value to write, as needed.
1301 :
1302 : // First check for a persisted value.
1303 0 : if (am->IsAutomaticallyPersisted())
1304 : {
1305 0 : VerifyOrDieWithMsg(attrStorage != nullptr, Zcl, "Attribute persistence needs a persistence provider");
1306 0 : MutableByteSpan bytes(attrData);
1307 : CHIP_ERROR err =
1308 0 : attrStorage->ReadValue(ConcreteAttributePath(de->endpoint, cluster->clusterId, am->attributeId), bytes);
1309 0 : if (err == CHIP_NO_ERROR)
1310 : {
1311 0 : err = ValidateDataContent(bytes, am);
1312 : }
1313 :
1314 0 : if (err == CHIP_NO_ERROR)
1315 : {
1316 0 : ptr = attrData;
1317 : }
1318 : else
1319 : {
1320 0 : ChipLogDetail(
1321 : DataManagement,
1322 : "Failed to read stored attribute (%u, " ChipLogFormatMEI ", " ChipLogFormatMEI ": %" CHIP_ERROR_FORMAT,
1323 : de->endpoint, ChipLogValueMEI(cluster->clusterId), ChipLogValueMEI(am->attributeId), err.Format());
1324 : // Just fall back to default value.
1325 : }
1326 : }
1327 :
1328 0 : if (!am->IsExternal())
1329 : {
1330 : EmberAfAttributeSearchRecord record;
1331 0 : record.endpoint = de->endpoint;
1332 0 : record.clusterId = cluster->clusterId;
1333 0 : record.attributeId = am->attributeId;
1334 :
1335 0 : if (ptr == nullptr)
1336 : {
1337 0 : size_t defaultValueSizeForBigEndianNudger = 0;
1338 : // Bypasses compiler warning about unused variable for little endian platforms.
1339 : (void) defaultValueSizeForBigEndianNudger;
1340 0 : if ((am->mask & MATTER_ATTRIBUTE_FLAG_MIN_MAX) != 0U)
1341 : {
1342 : // This is intentionally 2 and not 4 bytes since defaultValue in min/max
1343 : // attributes is still uint16_t.
1344 0 : if (emberAfAttributeSize(am) <= 2)
1345 : {
1346 : static_assert(sizeof(am->defaultValue.ptrToMinMaxValue->defaultValue.defaultValue) == 2,
1347 : "if statement relies on size of max/min defaultValue being 2");
1348 0 : ptr = (uint8_t *) &(am->defaultValue.ptrToMinMaxValue->defaultValue.defaultValue);
1349 0 : defaultValueSizeForBigEndianNudger =
1350 : sizeof(am->defaultValue.ptrToMinMaxValue->defaultValue.defaultValue);
1351 : }
1352 : else
1353 : {
1354 0 : ptr = (uint8_t *) am->defaultValue.ptrToMinMaxValue->defaultValue.ptrToDefaultValue;
1355 : }
1356 : }
1357 : else
1358 : {
1359 0 : if ((emberAfAttributeSize(am) <= 4) && !emberAfIsStringAttributeType(am->attributeType))
1360 : {
1361 0 : ptr = (uint8_t *) &(am->defaultValue.defaultValue);
1362 0 : defaultValueSizeForBigEndianNudger = sizeof(am->defaultValue.defaultValue);
1363 : }
1364 : else
1365 : {
1366 0 : ptr = (uint8_t *) am->defaultValue.ptrToDefaultValue;
1367 : }
1368 : }
1369 : // At this point, ptr either points to a default value, or is NULL, in which case
1370 : // it should be treated as if it is pointing to an array of all zeroes.
1371 :
1372 : #if (CHIP_CONFIG_BIG_ENDIAN_TARGET)
1373 : // The default values for attributes that are less than or equal to
1374 : // defaultValueSizeForBigEndianNudger in bytes are stored in an
1375 : // uint32_t. On big-endian platforms, a pointer to the default value
1376 : // of size less than defaultValueSizeForBigEndianNudger will point to the wrong
1377 : // byte. So, for those cases, nudge the pointer forward so it points
1378 : // to the correct byte.
1379 : if (emberAfAttributeSize(am) < defaultValueSizeForBigEndianNudger && ptr != NULL)
1380 : {
1381 : ptr += (defaultValueSizeForBigEndianNudger - emberAfAttributeSize(am));
1382 : }
1383 : #endif // BIGENDIAN
1384 : }
1385 :
1386 0 : emAfReadOrWriteAttribute(&record,
1387 : nullptr, // metadata - unused
1388 : ptr,
1389 : 0, // buffer size - unused
1390 : true); // write?
1391 : }
1392 : }
1393 : }
1394 25 : if (endpoint != kInvalidEndpointId)
1395 : {
1396 0 : break;
1397 : }
1398 : }
1399 : }
1400 :
1401 : // 'data' argument may be null, since we changed the ptrToDefaultValue
1402 : // to be null instead of pointing to all zeroes.
1403 : // This function has to be able to deal with that.
1404 0 : void emAfSaveAttributeToStorageIfNeeded(uint8_t * data, EndpointId endpoint, ClusterId clusterId,
1405 : const EmberAfAttributeMetadata * metadata)
1406 : {
1407 : // Get out of here if this attribute isn't marked non-volatile.
1408 0 : if (!metadata->IsAutomaticallyPersisted())
1409 : {
1410 0 : return;
1411 : }
1412 :
1413 : // TODO: Maybe we should have a separate constant for the size of the
1414 : // largest non-volatile attribute?
1415 0 : uint8_t allZeroData[ATTRIBUTE_LARGEST] = { 0 };
1416 0 : if (data == nullptr)
1417 : {
1418 0 : data = allZeroData;
1419 : }
1420 :
1421 : size_t dataSize;
1422 0 : EmberAfAttributeType type = metadata->attributeType;
1423 0 : if (emberAfIsStringAttributeType(type))
1424 : {
1425 0 : dataSize = emberAfStringLength(data) + 1;
1426 : }
1427 0 : else if (emberAfIsLongStringAttributeType(type))
1428 : {
1429 0 : dataSize = emberAfLongStringLength(data) + 2;
1430 : }
1431 : else
1432 : {
1433 0 : dataSize = metadata->size;
1434 : }
1435 :
1436 0 : auto * attrStorage = GetAttributePersistenceProvider();
1437 0 : if (attrStorage)
1438 : {
1439 0 : attrStorage->WriteValue(ConcreteAttributePath(endpoint, clusterId, metadata->attributeId), ByteSpan(data, dataSize));
1440 : }
1441 : else
1442 : {
1443 0 : ChipLogProgress(DataManagement, "Can't store attribute value: no persistence provider");
1444 : }
1445 : }
1446 :
1447 : // This function returns the actual function point from the array,
1448 : // iterating over the function bits.
1449 2944 : EmberAfGenericClusterFunction emberAfFindClusterFunction(const EmberAfCluster * cluster, EmberAfClusterMask functionMask)
1450 : {
1451 2944 : EmberAfClusterMask mask = 0x01;
1452 2944 : uint8_t functionIndex = 0;
1453 :
1454 2944 : if ((cluster->mask & functionMask) == 0)
1455 : {
1456 2944 : return nullptr;
1457 : }
1458 :
1459 0 : while (mask < functionMask)
1460 : {
1461 0 : if ((cluster->mask & mask) != 0)
1462 : {
1463 0 : functionIndex++;
1464 : }
1465 0 : mask = static_cast<EmberAfClusterMask>(mask << 1);
1466 : }
1467 0 : return cluster->functions[functionIndex];
1468 : }
1469 :
1470 : namespace chip {
1471 : namespace app {
1472 :
1473 0 : CHIP_ERROR SetParentEndpointForEndpoint(EndpointId childEndpoint, EndpointId parentEndpoint)
1474 : {
1475 0 : uint16_t childIndex = emberAfIndexFromEndpoint(childEndpoint);
1476 0 : uint16_t parentIndex = emberAfIndexFromEndpoint(parentEndpoint);
1477 :
1478 0 : if (childIndex == kEmberInvalidEndpointIndex || parentIndex == kEmberInvalidEndpointIndex)
1479 : {
1480 0 : return CHIP_ERROR_INVALID_ARGUMENT;
1481 : }
1482 0 : emAfEndpoints[childIndex].parentEndpointId = parentEndpoint;
1483 0 : return CHIP_NO_ERROR;
1484 : }
1485 :
1486 0 : CHIP_ERROR SetFlatCompositionForEndpoint(EndpointId endpoint)
1487 : {
1488 0 : uint16_t index = emberAfIndexFromEndpoint(endpoint);
1489 0 : if (index == kEmberInvalidEndpointIndex)
1490 : {
1491 0 : return CHIP_ERROR_INVALID_ARGUMENT;
1492 : }
1493 0 : emAfEndpoints[index].bitmask.Set(EmberAfEndpointOptions::isFlatComposition);
1494 0 : return CHIP_NO_ERROR;
1495 : }
1496 :
1497 0 : CHIP_ERROR SetTreeCompositionForEndpoint(EndpointId endpoint)
1498 : {
1499 0 : uint16_t index = emberAfIndexFromEndpoint(endpoint);
1500 0 : if (index == kEmberInvalidEndpointIndex)
1501 : {
1502 0 : return CHIP_ERROR_INVALID_ARGUMENT;
1503 : }
1504 0 : emAfEndpoints[index].bitmask.Clear(EmberAfEndpointOptions::isFlatComposition);
1505 0 : return CHIP_NO_ERROR;
1506 : }
1507 :
1508 0 : bool IsFlatCompositionForEndpoint(EndpointId endpoint)
1509 : {
1510 0 : uint16_t index = emberAfIndexFromEndpoint(endpoint);
1511 0 : if (index == kEmberInvalidEndpointIndex)
1512 : {
1513 0 : return false;
1514 : }
1515 0 : return emAfEndpoints[index].bitmask.Has(EmberAfEndpointOptions::isFlatComposition);
1516 : }
1517 :
1518 0 : bool IsTreeCompositionForEndpoint(EndpointId endpoint)
1519 : {
1520 0 : uint16_t index = emberAfIndexFromEndpoint(endpoint);
1521 0 : if (index == kEmberInvalidEndpointIndex)
1522 : {
1523 0 : return false;
1524 : }
1525 0 : return !emAfEndpoints[index].bitmask.Has(EmberAfEndpointOptions::isFlatComposition);
1526 : }
1527 :
1528 2917 : EndpointComposition GetCompositionForEndpointIndex(uint16_t endpointIndex)
1529 : {
1530 2917 : VerifyOrReturnValue(endpointIndex < MATTER_ARRAY_SIZE(emAfEndpoints), EndpointComposition::kInvalid);
1531 2917 : if (emAfEndpoints[endpointIndex].bitmask.Has(EmberAfEndpointOptions::isFlatComposition))
1532 : {
1533 1438 : return EndpointComposition::kFullFamily;
1534 : }
1535 1479 : return EndpointComposition::kTree;
1536 : }
1537 :
1538 : } // namespace app
1539 : } // namespace chip
1540 :
1541 0 : uint16_t emberAfGetServerAttributeCount(EndpointId endpoint, ClusterId cluster)
1542 : {
1543 0 : const EmberAfCluster * clusterObj = emberAfFindServerCluster(endpoint, cluster);
1544 0 : VerifyOrReturnError(clusterObj != nullptr, 0);
1545 0 : return clusterObj->attributeCount;
1546 : }
1547 :
1548 0 : uint16_t emberAfGetServerAttributeIndexByAttributeId(EndpointId endpoint, ClusterId cluster, AttributeId attributeId)
1549 : {
1550 0 : const EmberAfCluster * clusterObj = emberAfFindServerCluster(endpoint, cluster);
1551 0 : VerifyOrReturnError(clusterObj != nullptr, UINT16_MAX);
1552 :
1553 0 : for (uint16_t i = 0; i < clusterObj->attributeCount; i++)
1554 : {
1555 0 : if (clusterObj->attributes[i].attributeId == attributeId)
1556 : {
1557 0 : return i;
1558 : }
1559 : }
1560 0 : return UINT16_MAX;
1561 : }
1562 :
1563 0 : Optional<AttributeId> emberAfGetServerAttributeIdByIndex(EndpointId endpoint, ClusterId cluster, uint16_t attributeIndex)
1564 : {
1565 0 : const EmberAfCluster * clusterObj = emberAfFindServerCluster(endpoint, cluster);
1566 0 : if (clusterObj == nullptr || clusterObj->attributeCount <= attributeIndex)
1567 : {
1568 0 : return Optional<AttributeId>::Missing();
1569 : }
1570 0 : return Optional<AttributeId>(clusterObj->attributes[attributeIndex].attributeId);
1571 : }
1572 :
1573 9516 : DataVersion * emberAfDataVersionStorage(const ConcreteClusterPath & aConcreteClusterPath)
1574 : {
1575 9516 : uint16_t index = emberAfIndexFromEndpoint(aConcreteClusterPath.mEndpointId);
1576 9516 : if (index == kEmberInvalidEndpointIndex)
1577 : {
1578 : // Unknown endpoint.
1579 47 : return nullptr;
1580 : }
1581 9469 : const EmberAfDefinedEndpoint & ep = emAfEndpoints[index];
1582 9469 : if (!ep.dataVersions)
1583 : {
1584 : // No storage provided.
1585 0 : return nullptr;
1586 : }
1587 :
1588 : // This does a second walk over endpoints to find the right one, but
1589 : // probably worth it to avoid duplicating code.
1590 : auto clusterIndex =
1591 9469 : emberAfClusterIndex(aConcreteClusterPath.mEndpointId, aConcreteClusterPath.mClusterId, MATTER_CLUSTER_FLAG_SERVER);
1592 9469 : if (clusterIndex == 0xFF)
1593 : {
1594 : // No such cluster on this endpoint.
1595 10 : return nullptr;
1596 : }
1597 :
1598 9459 : return ep.dataVersions + clusterIndex;
1599 : }
1600 :
1601 : namespace {
1602 : class GlobalInteractionModelEngineChangedpathListener : public AttributesChangedListener
1603 : {
1604 : public:
1605 6 : ~GlobalInteractionModelEngineChangedpathListener() = default;
1606 :
1607 86 : void MarkDirty(const AttributePathParams & path) override
1608 : {
1609 86 : InteractionModelEngine::GetInstance()->GetReportingEngine().SetDirty(path);
1610 86 : }
1611 : };
1612 :
1613 : } // namespace
1614 :
1615 86 : AttributesChangedListener * emberAfGlobalInteractionModelAttributesChangedListener()
1616 : {
1617 86 : static GlobalInteractionModelEngineChangedpathListener listener;
1618 86 : return &listener;
1619 : }
1620 :
1621 5203 : void emberAfAttributeChanged(EndpointId endpoint, ClusterId clusterId, AttributeId attributeId,
1622 : AttributesChangedListener * listener)
1623 : {
1624 : // Increase cluster data path
1625 5203 : DataVersion * version = emberAfDataVersionStorage(ConcreteClusterPath(endpoint, clusterId));
1626 5203 : if (version == nullptr)
1627 : {
1628 57 : ChipLogError(DataManagement, "Endpoint %x, Cluster " ChipLogFormatMEI " not found in IncreaseClusterDataVersion!", endpoint,
1629 : ChipLogValueMEI(clusterId));
1630 : }
1631 : else
1632 : {
1633 5146 : (*(version))++;
1634 5146 : ChipLogDetail(DataManagement, "Endpoint %x, Cluster " ChipLogFormatMEI " update version to %" PRIx32, endpoint,
1635 : ChipLogValueMEI(clusterId), *(version));
1636 : }
1637 :
1638 5203 : listener->MarkDirty(AttributePathParams(endpoint, clusterId, attributeId));
1639 5203 : }
1640 :
1641 29 : void emberAfEndpointChanged(EndpointId endpoint, AttributesChangedListener * listener)
1642 : {
1643 29 : listener->MarkDirty(AttributePathParams(endpoint));
1644 29 : }
|