Matter SDK Coverage Report
Current view: top level - app/util - attribute-storage.cpp (source / functions) Coverage Total Hit
Test: SHA:1560a87972ec2c7a76cec101927a563a6862bc2a Lines: 42.9 % 576 247
Test Date: 2025-03-30 07:08:27 Functions: 50.0 % 74 37

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

Generated by: LCOV version 2.0-1