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