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