Matter SDK Coverage Report
Current view: top level - app/util - attribute-storage.cpp (source / functions) Coverage Total Hit
Test: SHA:f1767a8b0a3778fdf31b1d979afbdf544892fd94 Lines: 43.8 % 591 259
Test Date: 2026-06-03 07:35:21 Functions: 49.3 % 73 36

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

Generated by: LCOV version 2.0-1