Matter SDK Coverage Report
Current view: top level - app/util - attribute-storage.cpp (source / functions) Coverage Total Hit
Test: SHA:db08debc068562b264a2df3a7f3a8cc1d0b3aba1 Lines: 44.4 % 586 260
Test Date: 2025-10-02 07:10:30 Functions: 50.7 % 75 38

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

Generated by: LCOV version 2.0-1