Matter SDK Coverage Report
Current view: top level - data-model-providers/codegen - CodegenDataModelProvider.cpp (source / functions) Coverage Total Hit
Test: SHA:2a48c1efeab1c0f76f3adb3a0940b0f7de706453 Lines: 98.0 % 205 201
Test Date: 2026-01-31 08:14:20 Functions: 100.0 % 17 17

            Line data    Source code
       1              : /*
       2              :  *    Copyright (c) 2024 Project CHIP Authors
       3              :  *    All rights reserved.
       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 <data-model-providers/codegen/CodegenDataModelProvider.h>
      18              : 
      19              : #include <access/AccessControl.h>
      20              : #include <access/Privilege.h>
      21              : #include <app-common/zap-generated/attribute-type.h>
      22              : #include <app/CommandHandlerInterface.h>
      23              : #include <app/CommandHandlerInterfaceRegistry.h>
      24              : #include <app/ConcreteAttributePath.h>
      25              : #include <app/ConcreteClusterPath.h>
      26              : #include <app/ConcreteCommandPath.h>
      27              : #include <app/EventPathParams.h>
      28              : #include <app/GlobalAttributes.h>
      29              : #include <app/RequiredPrivilege.h>
      30              : #include <app/data-model-provider/MetadataTypes.h>
      31              : #include <app/data-model-provider/Provider.h>
      32              : #include <app/persistence/AttributePersistenceProvider.h>
      33              : #include <app/persistence/AttributePersistenceProviderInstance.h>
      34              : #include <app/persistence/DefaultAttributePersistenceProvider.h>
      35              : #include <app/server-cluster/ServerClusterContext.h>
      36              : #include <app/server-cluster/ServerClusterInterface.h>
      37              : #include <app/util/DataModelHandler.h>
      38              : #include <app/util/IMClusterCommandHandler.h>
      39              : #include <app/util/af-types.h>
      40              : #include <app/util/attribute-metadata.h>
      41              : #include <app/util/attribute-storage.h>
      42              : #include <app/util/endpoint-config-api.h>
      43              : #include <lib/core/CHIPError.h>
      44              : #include <lib/core/DataModelTypes.h>
      45              : #include <lib/support/CodeUtils.h>
      46              : #include <lib/support/ReadOnlyBuffer.h>
      47              : #include <lib/support/ScopedBuffer.h>
      48              : 
      49              : #include <cstdint>
      50              : #include <optional>
      51              : 
      52              : namespace chip {
      53              : namespace app {
      54              : namespace {
      55              : 
      56          114 : DataModel::AcceptedCommandEntry AcceptedCommandEntryFor(const ConcreteCommandPath & path)
      57              : {
      58          114 :     const CommandId commandId = path.mCommandId;
      59              : 
      60              :     DataModel::AcceptedCommandEntry entry(
      61          114 :         path.mCommandId,
      62          114 :         BitFlags<DataModel::CommandQualityFlags>{}
      63          114 :             .Set(DataModel::CommandQualityFlags::kTimed, CommandNeedsTimedInvoke(path.mClusterId, commandId))
      64          114 :             .Set(DataModel::CommandQualityFlags::kFabricScoped, CommandIsFabricScoped(path.mClusterId, commandId))
      65          114 :             .Set(DataModel::CommandQualityFlags::kLargeMessage, CommandHasLargePayload(path.mClusterId, commandId)),
      66          228 :         RequiredPrivilege::ForInvokeCommand(path));
      67              : 
      68          114 :     return entry;
      69              : }
      70              : 
      71        15151 : DataModel::ServerClusterEntry ServerClusterEntryFrom(EndpointId endpointId, const EmberAfCluster & cluster)
      72              : {
      73        15151 :     DataModel::ServerClusterEntry entry;
      74              : 
      75        15151 :     entry.clusterId = cluster.clusterId;
      76              : 
      77        15151 :     DataVersion * versionPtr = emberAfDataVersionStorage(ConcreteClusterPath(endpointId, cluster.clusterId));
      78        15151 :     if (versionPtr == nullptr)
      79              :     {
      80              : #if CHIP_CONFIG_DATA_MODEL_EXTRA_LOGGING
      81            0 :         ChipLogError(AppServer, "Failed to get data version for %d/" ChipLogFormatMEI, endpointId,
      82              :                      ChipLogValueMEI(cluster.clusterId));
      83              : #endif
      84            0 :         entry.dataVersion = 0;
      85              :     }
      86              :     else
      87              :     {
      88        15151 :         entry.dataVersion = *versionPtr;
      89              :     }
      90              : 
      91              :     // TODO: set entry flags:
      92              :     //   entry.flags.Set(ClusterQualityFlags::kDiagnosticsData)
      93              : 
      94        15151 :     return entry;
      95              : }
      96              : 
      97        80881 : DataModel::AttributeEntry AttributeEntryFrom(const ConcreteClusterPath & clusterPath, const EmberAfAttributeMetadata & attribute)
      98              : {
      99        80881 :     const ConcreteAttributePath attributePath(clusterPath.mEndpointId, clusterPath.mClusterId, attribute.attributeId);
     100              : 
     101              :     using DataModel::AttributeQualityFlags;
     102              : 
     103              :     DataModel::AttributeEntry entry(
     104        80881 :         attribute.attributeId,
     105        80881 :         BitFlags<DataModel::AttributeQualityFlags>{}
     106        80881 :             .Set(AttributeQualityFlags::kListAttribute, (attribute.attributeType == ZCL_ARRAY_ATTRIBUTE_TYPE))
     107        80881 :             .Set(DataModel::AttributeQualityFlags::kTimed, attribute.MustUseTimedWrite()),
     108       161762 :         attribute.IsReadable() ? std::make_optional(RequiredPrivilege::ForReadAttribute(attributePath)) : std::nullopt,
     109       242643 :         attribute.IsWritable() ? std::make_optional(RequiredPrivilege::ForWriteAttribute(attributePath)) : std::nullopt);
     110              : 
     111              :     // NOTE: we do NOT provide additional info for:
     112              :     //    - IsExternal/IsAutomaticallyPersisted is not used by IM handling
     113              :     //    - Several specification flags are not available (reportable, quieter reporting,
     114              :     //      fixed, source attribution)
     115              : 
     116              :     // TODO: Set additional flags:
     117              :     // entry.flags.Set(DataModel::AttributeQualityFlags::kFabricScoped)
     118              :     // entry.flags.Set(DataModel::AttributeQualityFlags::kFabricSensitive)
     119              :     // entry.flags.Set(DataModel::AttributeQualityFlags::kChangesOmitted)
     120        80881 :     return entry;
     121              : }
     122              : 
     123              : DefaultAttributePersistenceProvider gDefaultAttributePersistence;
     124              : 
     125              : } // namespace
     126              : 
     127          180 : CHIP_ERROR CodegenDataModelProvider::Shutdown()
     128              : {
     129          180 :     Reset();
     130          180 :     mContext.reset();
     131          180 :     mRegistry.ClearContext();
     132          180 :     return DataModel::Provider::Shutdown();
     133              : }
     134              : 
     135          438 : CHIP_ERROR CodegenDataModelProvider::Startup(DataModel::InteractionModelContext context)
     136              : {
     137              :     // server clusters require a valid persistent storage delegate
     138          438 :     VerifyOrReturnError(mPersistentStorageDelegate != nullptr, CHIP_ERROR_INCORRECT_STATE);
     139          157 :     ReturnErrorOnFailure(DataModel::Provider::Startup(context));
     140              : 
     141          157 :     mContext.emplace(context);
     142              : 
     143              :     // Ember NVM requires have a data model provider. attempt to create one if one is not available
     144              :     //
     145              :     // It is not a critical failure to not have one, however if one is not set up, ember NVM operations
     146              :     // will error out with a `persistence not available`.
     147          157 :     if (GetAttributePersistenceProvider() == nullptr)
     148              :     {
     149              : #if CHIP_CONFIG_DATA_MODEL_EXTRA_LOGGING
     150            3 :         ChipLogProgress(DataManagement, "Ember attribute persistence requires setting up");
     151              : #endif
     152            3 :         ReturnErrorOnFailure(gDefaultAttributePersistence.Init(mPersistentStorageDelegate));
     153            3 :         SetAttributePersistenceProvider(&gDefaultAttributePersistence);
     154              :     }
     155              : 
     156          157 :     InitDataModelForTesting();
     157              : 
     158          314 :     return mRegistry.SetContext(ServerClusterContext{
     159              :         .provider           = *this,
     160          157 :         .storage            = *mPersistentStorageDelegate,
     161          157 :         .attributeStorage   = *GetAttributePersistenceProvider(), // guaranteed set up by the above logic
     162          157 :         .interactionContext = *mContext,                          // NOLINT(bugprone-unchecked-optional-access): emplaced above
     163          157 :     });
     164              : }
     165              : 
     166            6 : std::optional<DataModel::ActionReturnStatus> CodegenDataModelProvider::InvokeCommand(const DataModel::InvokeRequest & request,
     167              :                                                                                      TLV::TLVReader & input_arguments,
     168              :                                                                                      CommandHandler * handler)
     169              : {
     170            6 :     if (auto * cluster = mRegistry.Get(request.path); cluster != nullptr)
     171              :     {
     172            1 :         return cluster->InvokeCommand(request, input_arguments, handler);
     173              :     }
     174              : 
     175              :     CommandHandlerInterface * handler_interface =
     176            5 :         CommandHandlerInterfaceRegistry::Instance().GetCommandHandler(request.path.mEndpointId, request.path.mClusterId);
     177              : 
     178            5 :     if (handler_interface)
     179              :     {
     180            3 :         CommandHandlerInterface::HandlerContext context(*handler, request.path, input_arguments);
     181            3 :         handler_interface->InvokeCommand(context);
     182              : 
     183              :         // If the command was handled, don't proceed any further and return successfully.
     184            3 :         if (context.mCommandHandled)
     185              :         {
     186            3 :             return std::nullopt;
     187              :         }
     188              :     }
     189              : 
     190              :     // Ember always returns responses via the handler, so std::nullopt must be returned here to follow the InvokeCommand API
     191              :     // contract
     192            2 :     DispatchSingleClusterCommand(request.path, input_arguments, handler);
     193            2 :     return std::nullopt;
     194              : }
     195              : 
     196         2976 : CHIP_ERROR CodegenDataModelProvider::Endpoints(ReadOnlyBufferBuilder<DataModel::EndpointEntry> & builder)
     197              : {
     198         2976 :     const uint16_t endpointCount = emberAfEndpointCount();
     199              : 
     200         2976 :     ReturnErrorOnFailure(builder.EnsureAppendCapacity(endpointCount));
     201              : 
     202        17356 :     for (uint16_t endpointIndex = 0; endpointIndex < endpointCount; endpointIndex++)
     203              :     {
     204        14380 :         if (!emberAfEndpointIndexIsEnabled(endpointIndex))
     205              :         {
     206         4333 :             continue;
     207              :         }
     208              : 
     209              :         DataModel::EndpointEntry entry;
     210        10047 :         entry.id       = emberAfEndpointFromIndex(endpointIndex);
     211        10047 :         entry.parentId = emberAfParentEndpointFromIndex(endpointIndex);
     212              : 
     213        10047 :         switch (GetCompositionForEndpointIndex(endpointIndex))
     214              :         {
     215         8566 :         case EndpointComposition::kFullFamily:
     216         8566 :             entry.compositionPattern = DataModel::EndpointCompositionPattern::kFullFamily;
     217         8566 :             break;
     218         1481 :         case EndpointComposition::kTree:
     219              :         case EndpointComposition::kInvalid: // should NOT happen, but force compiler to check we validate all versions
     220         1481 :             entry.compositionPattern = DataModel::EndpointCompositionPattern::kTree;
     221         1481 :             break;
     222              :         }
     223        10047 :         ReturnErrorOnFailure(builder.Append(entry));
     224              :     }
     225              : 
     226         2976 :     return CHIP_NO_ERROR;
     227              : }
     228              : 
     229            3 : std::optional<unsigned> CodegenDataModelProvider::TryFindEndpointIndex(EndpointId id) const
     230              : {
     231            3 :     const uint16_t lastEndpointIndex = emberAfEndpointCount();
     232              : 
     233            6 :     if ((mEndpointIterationHint < lastEndpointIndex) && emberAfEndpointIndexIsEnabled(mEndpointIterationHint) &&
     234            3 :         (id == emberAfEndpointFromIndex(mEndpointIterationHint)))
     235              :     {
     236            1 :         return std::make_optional(mEndpointIterationHint);
     237              :     }
     238              : 
     239              :     // Linear search, this may be slow
     240            2 :     uint16_t idx = emberAfIndexFromEndpoint(id);
     241            2 :     if (idx == kEmberInvalidEndpointIndex)
     242              :     {
     243            0 :         return std::nullopt;
     244              :     }
     245              : 
     246            2 :     return std::make_optional<unsigned>(idx);
     247              : }
     248              : 
     249         2247 : CHIP_ERROR CodegenDataModelProvider::EventInfo(const ConcreteEventPath & path, DataModel::EventEntry & eventInfo)
     250              : {
     251         2247 :     if (auto * cluster = mRegistry.Get(path); cluster != nullptr)
     252              :     {
     253            3 :         return cluster->EventInfo(path, eventInfo);
     254              :     }
     255              : 
     256         2244 :     eventInfo.readPrivilege = RequiredPrivilege::ForReadEvent(path);
     257         2244 :     return CHIP_NO_ERROR;
     258              : }
     259              : 
     260         8990 : CHIP_ERROR CodegenDataModelProvider::ServerClusters(EndpointId endpointId,
     261              :                                                     ReadOnlyBufferBuilder<DataModel::ServerClusterEntry> & builder)
     262              : {
     263         8990 :     const EmberAfEndpointType * endpoint = emberAfFindEndpointType(endpointId);
     264              : 
     265         8990 :     VerifyOrReturnValue(endpoint != nullptr, CHIP_ERROR_NOT_FOUND);
     266         8978 :     VerifyOrReturnValue(endpoint->clusterCount > 0, CHIP_NO_ERROR);
     267         8978 :     VerifyOrReturnValue(endpoint->cluster != nullptr, CHIP_NO_ERROR);
     268              : 
     269              :     // We build the cluster list by merging two lists:
     270              :     //   - mRegistry items from ServerClusterInterfaces
     271              :     //   - ember metadata clusters
     272              :     //
     273              :     // This is done because `ServerClusterInterface` allows full control for all its metadata,
     274              :     // in particular `data version` and `flags`.
     275              :     //
     276              :     // To allow cluster implementations to be incrementally converted to storing their own data versions,
     277              :     // instead of relying on the out-of-band emberAfDataVersionStorage, first check for clusters that are
     278              :     // using the new data version storage and are registered via SingleEndpointServerClusterRegistry, then fill
     279              :     // in the data versions for the rest via the out-of-band mechanism.
     280              : 
     281              :     // assume the clusters on endpoint does not change in between these two loops
     282         8978 :     auto clusters               = mRegistry.ClustersOnEndpoint(endpointId);
     283         8978 :     size_t registryClusterCount = 0;
     284         8980 :     for ([[maybe_unused]] auto _ : clusters)
     285              :     {
     286            2 :         registryClusterCount++;
     287              :     }
     288              : 
     289         8978 :     ReturnErrorOnFailure(builder.EnsureAppendCapacity(registryClusterCount));
     290              : 
     291         8978 :     ReadOnlyBufferBuilder<ClusterId> knownClustersBuilder;
     292         8978 :     ReturnErrorOnFailure(knownClustersBuilder.EnsureAppendCapacity(registryClusterCount));
     293         8980 :     for (const auto clusterId : mRegistry.ClustersOnEndpoint(endpointId))
     294              :     {
     295            2 :         ConcreteClusterPath path(endpointId, clusterId);
     296            2 :         ServerClusterInterface * cluster = mRegistry.Get(path);
     297              : 
     298              :         // path MUST be valid: we just got it from iterating our registrations...
     299            2 :         VerifyOrReturnError(cluster != nullptr, CHIP_ERROR_INTERNAL);
     300              : 
     301            2 :         ReturnErrorOnFailure(builder.Append({
     302              :             .clusterId   = path.mClusterId,
     303              :             .dataVersion = cluster->GetDataVersion(path),
     304              :             .flags       = cluster->GetClusterFlags(path),
     305              :         }));
     306            2 :         ReturnErrorOnFailure(knownClustersBuilder.Append(path.mClusterId));
     307              :     }
     308              : 
     309         8978 :     ReadOnlyBuffer<ClusterId> knownClusters = knownClustersBuilder.TakeBuffer();
     310              : 
     311         8978 :     ReturnErrorOnFailure(builder.EnsureAppendCapacity(emberAfClusterCountForEndpointType(endpoint, /* server = */ true)));
     312              : 
     313         8978 :     const EmberAfCluster * begin = endpoint->cluster;
     314         8978 :     const EmberAfCluster * end   = endpoint->cluster + endpoint->clusterCount;
     315        25634 :     for (const EmberAfCluster * cluster = begin; cluster != end; cluster++)
     316              :     {
     317        16656 :         if (!cluster->IsServer())
     318              :         {
     319         1503 :             continue;
     320              :         }
     321              : 
     322              :         // linear search as this is a somewhat compact number list, so performance is probably not too bad
     323              :         // This results in smaller code than some memory allocation + std::sort + std::binary_search
     324        15153 :         bool found = false;
     325        15156 :         for (ClusterId clusterId : knownClusters)
     326              :         {
     327            5 :             if (clusterId == cluster->clusterId)
     328              :             {
     329            2 :                 found = true;
     330            2 :                 break;
     331              :             }
     332              :         }
     333        15153 :         if (found)
     334              :         {
     335              :             // value already filled from the ServerClusterRegistry. That one has the correct/overriden
     336              :             // flags and data version
     337            2 :             continue;
     338              :         }
     339              : 
     340        15151 :         ReturnErrorOnFailure(builder.Append(ServerClusterEntryFrom(endpointId, *cluster)));
     341              :     }
     342              : 
     343         8978 :     return CHIP_NO_ERROR;
     344         8978 : }
     345              : 
     346        18992 : CHIP_ERROR CodegenDataModelProvider::Attributes(const ConcreteClusterPath & path,
     347              :                                                 ReadOnlyBufferBuilder<DataModel::AttributeEntry> & builder)
     348              : {
     349        18992 :     if (auto * cluster = mRegistry.Get(path); cluster != nullptr)
     350              :     {
     351            1 :         return cluster->Attributes(path, builder);
     352              :     }
     353              : 
     354        18991 :     const EmberAfCluster * cluster = FindServerCluster(path);
     355              : 
     356        18991 :     VerifyOrReturnValue(cluster != nullptr, CHIP_ERROR_NOT_FOUND);
     357        18950 :     VerifyOrReturnValue(cluster->attributeCount > 0, CHIP_NO_ERROR);
     358        18950 :     VerifyOrReturnValue(cluster->attributes != nullptr, CHIP_NO_ERROR);
     359              : 
     360              :     // TODO: if ember would encode data in AttributeEntry form, we could reference things directly (shorter code,
     361              :     //       although still allocation overhead due to global attributes not in metadata)
     362              :     //
     363              :     // We have Attributes from ember + global attributes that are NOT in ember metadata.
     364              :     // We have to report them all
     365        18950 :     constexpr size_t kGlobalAttributeNotInMetadataCount = MATTER_ARRAY_SIZE(GlobalAttributesNotInMetadata);
     366              : 
     367        18950 :     ReturnErrorOnFailure(builder.EnsureAppendCapacity(cluster->attributeCount + kGlobalAttributeNotInMetadataCount));
     368              : 
     369        18950 :     Span<const EmberAfAttributeMetadata> attributeSpan(cluster->attributes, cluster->attributeCount);
     370              : 
     371        99831 :     for (auto & attribute : attributeSpan)
     372              :     {
     373        80881 :         ReturnErrorOnFailure(builder.Append(AttributeEntryFrom(path, attribute)));
     374              :     }
     375              : 
     376        75800 :     for (auto & attributeId : GlobalAttributesNotInMetadata)
     377              :     {
     378              : 
     379              :         // This "GlobalListEntry" is specific for metadata that ember does not include
     380              :         // in its attribute list metadata.
     381              :         //
     382              :         // By spec these Attribute/AcceptedCommands/GeneratedCommants lists are:
     383              :         //   - lists of elements
     384              :         //   - read-only, with read privilege view
     385              :         //   - fixed value (no such flag exists, so this is not a quality flag we set/track)
     386              :         DataModel::AttributeEntry globalListEntry(attributeId, DataModel::AttributeQualityFlags::kListAttribute,
     387        56850 :                                                   Access::Privilege::kView, std::nullopt);
     388              : 
     389        56850 :         ReturnErrorOnFailure(builder.Append(std::move(globalListEntry)));
     390              :     }
     391              : 
     392        18950 :     return CHIP_NO_ERROR;
     393              : }
     394              : 
     395            4 : CHIP_ERROR CodegenDataModelProvider::ClientClusters(EndpointId endpointId, ReadOnlyBufferBuilder<ClusterId> & builder)
     396              : {
     397            4 :     const EmberAfEndpointType * endpoint = emberAfFindEndpointType(endpointId);
     398              : 
     399            4 :     VerifyOrReturnValue(endpoint != nullptr, CHIP_ERROR_NOT_FOUND);
     400            2 :     VerifyOrReturnValue(endpoint->clusterCount > 0, CHIP_NO_ERROR);
     401            2 :     VerifyOrReturnValue(endpoint->cluster != nullptr, CHIP_NO_ERROR);
     402              : 
     403            2 :     ReturnErrorOnFailure(builder.EnsureAppendCapacity(emberAfClusterCountForEndpointType(endpoint, /* server = */ false)));
     404              : 
     405            2 :     const EmberAfCluster * begin = endpoint->cluster;
     406            2 :     const EmberAfCluster * end   = endpoint->cluster + endpoint->clusterCount;
     407           10 :     for (const EmberAfCluster * cluster = begin; cluster != end; cluster++)
     408              :     {
     409            8 :         if (!cluster->IsClient())
     410              :         {
     411            4 :             continue;
     412              :         }
     413            4 :         ReturnErrorOnFailure(builder.Append(cluster->clusterId));
     414              :     }
     415              : 
     416            2 :     return CHIP_NO_ERROR;
     417              : }
     418              : 
     419        19969 : const EmberAfCluster * CodegenDataModelProvider::FindServerCluster(const ConcreteClusterPath & path)
     420              : {
     421        39313 :     if (mPreviouslyFoundCluster.has_value() && (mPreviouslyFoundCluster->path == path) &&
     422        19344 :         (mEmberMetadataStructureGeneration == emberAfMetadataStructureGeneration()))
     423              : 
     424              :     {
     425        19235 :         return mPreviouslyFoundCluster->cluster;
     426              :     }
     427              : 
     428          734 :     const EmberAfCluster * cluster = emberAfFindServerCluster(path.mEndpointId, path.mClusterId);
     429          734 :     if (cluster != nullptr)
     430              :     {
     431          672 :         mPreviouslyFoundCluster           = std::make_optional<ClusterReference>(path, cluster);
     432          672 :         mEmberMetadataStructureGeneration = emberAfMetadataStructureGeneration();
     433              :     }
     434          734 :     return cluster;
     435              : }
     436              : 
     437          526 : CHIP_ERROR CodegenDataModelProvider::AcceptedCommands(const ConcreteClusterPath & path,
     438              :                                                       ReadOnlyBufferBuilder<DataModel::AcceptedCommandEntry> & builder)
     439              : {
     440          526 :     if (auto * cluster = mRegistry.Get(path); cluster != nullptr)
     441              :     {
     442            1 :         return cluster->AcceptedCommands(path, builder);
     443              :     }
     444              : 
     445              :     // Some CommandHandlerInterface instances are registered of ALL endpoints, so make sure first that
     446              :     // the cluster actually exists on this endpoint before asking the CommandHandlerInterface what commands
     447              :     // it claims to support.
     448          525 :     const EmberAfCluster * serverCluster = FindServerCluster(path);
     449          525 :     VerifyOrReturnError(serverCluster != nullptr, CHIP_ERROR_NOT_FOUND);
     450              : 
     451              :     CommandHandlerInterface * interface =
     452          512 :         CommandHandlerInterfaceRegistry::Instance().GetCommandHandler(path.mEndpointId, path.mClusterId);
     453          512 :     if (interface != nullptr)
     454              :     {
     455           20 :         CHIP_ERROR err = interface->RetrieveAcceptedCommands(path, builder);
     456              :         // If retrieving the accepted commands returns CHIP_ERROR_NOT_IMPLEMENTED then continue with normal processing.
     457              :         // Otherwise we finished.
     458           40 :         VerifyOrReturnError(err == CHIP_ERROR_NOT_IMPLEMENTED, err);
     459              :     }
     460          502 :     VerifyOrReturnError(serverCluster->acceptedCommandList != nullptr, CHIP_NO_ERROR);
     461              : 
     462           42 :     const chip::CommandId * endOfList = serverCluster->acceptedCommandList;
     463          156 :     while (*endOfList != kInvalidCommandId)
     464              :     {
     465          114 :         endOfList++;
     466              :     }
     467           42 :     const auto commandCount = static_cast<size_t>(endOfList - serverCluster->acceptedCommandList);
     468              : 
     469              :     // TODO: if ember would store command entries, we could simplify this code to use static data
     470           42 :     ReturnErrorOnFailure(builder.EnsureAppendCapacity(commandCount));
     471              : 
     472           42 :     ConcreteCommandPath commandPath = ConcreteCommandPath(path.mEndpointId, path.mClusterId, kInvalidCommandId);
     473          156 :     for (const chip::CommandId * p = serverCluster->acceptedCommandList; p != endOfList; p++)
     474              :     {
     475          114 :         commandPath.mCommandId = *p;
     476          114 :         ReturnErrorOnFailure(builder.Append(AcceptedCommandEntryFor(commandPath)));
     477              :     }
     478              : 
     479           42 :     return CHIP_NO_ERROR;
     480              : }
     481              : 
     482          454 : CHIP_ERROR CodegenDataModelProvider::GeneratedCommands(const ConcreteClusterPath & path, ReadOnlyBufferBuilder<CommandId> & builder)
     483              : {
     484          454 :     if (auto * cluster = mRegistry.Get(path); cluster != nullptr)
     485              :     {
     486            1 :         return cluster->GeneratedCommands(path, builder);
     487              :     }
     488              : 
     489              :     // Some CommandHandlerInterface instances are registered of ALL endpoints, so make sure first that
     490              :     // the cluster actually exists on this endpoint before asking the CommandHandlerInterface what commands
     491              :     // it claims to support.
     492          453 :     const EmberAfCluster * serverCluster = FindServerCluster(path);
     493          453 :     VerifyOrReturnError(serverCluster != nullptr, CHIP_ERROR_NOT_FOUND);
     494              : 
     495              :     CommandHandlerInterface * interface =
     496          445 :         CommandHandlerInterfaceRegistry::Instance().GetCommandHandler(path.mEndpointId, path.mClusterId);
     497          445 :     if (interface != nullptr)
     498              :     {
     499            8 :         CHIP_ERROR err = interface->RetrieveGeneratedCommands(path, builder);
     500              :         // If retrieving generated commands returns CHIP_ERROR_NOT_IMPLEMENTED then continue with normal procesing.
     501              :         // Otherwise we finished.
     502           16 :         VerifyOrReturnError(err == CHIP_ERROR_NOT_IMPLEMENTED, err);
     503              :     }
     504              : 
     505          441 :     VerifyOrReturnError(serverCluster->generatedCommandList != nullptr, CHIP_NO_ERROR);
     506              : 
     507            2 :     const chip::CommandId * endOfList = serverCluster->generatedCommandList;
     508            6 :     while (*endOfList != kInvalidCommandId)
     509              :     {
     510            4 :         endOfList++;
     511              :     }
     512            2 :     const auto commandCount = static_cast<size_t>(endOfList - serverCluster->generatedCommandList);
     513            2 :     return builder.ReferenceExisting({ serverCluster->generatedCommandList, commandCount });
     514              : }
     515              : 
     516          157 : void CodegenDataModelProvider::InitDataModelForTesting()
     517              : {
     518              :     // Call the Ember-specific InitDataModelHandler
     519          157 :     InitDataModelHandler();
     520          157 : }
     521              : 
     522            3 : CHIP_ERROR CodegenDataModelProvider::DeviceTypes(EndpointId endpointId, ReadOnlyBufferBuilder<DataModel::DeviceTypeEntry> & builder)
     523              : {
     524            3 :     std::optional<unsigned> endpoint_index = TryFindEndpointIndex(endpointId);
     525            3 :     if (!endpoint_index.has_value())
     526              :     {
     527            0 :         return {};
     528              :     }
     529              : 
     530            3 :     CHIP_ERROR err = CHIP_NO_ERROR;
     531              : 
     532            3 :     return builder.ReferenceExisting(emberAfDeviceTypeListFromEndpointIndex(*endpoint_index, err));
     533              : }
     534              : 
     535              : #if CHIP_CONFIG_USE_ENDPOINT_UNIQUE_ID
     536              : CHIP_ERROR CodegenDataModelProvider::EndpointUniqueID(EndpointId endpointId, MutableCharSpan & epUniqueId)
     537              : {
     538              :     char buffer[Clusters::Descriptor::Attributes::EndpointUniqueID::TypeInfo::MaxLength()] = { 0 };
     539              :     MutableCharSpan epUniqueIdSpan(buffer);
     540              :     ReturnErrorOnFailure(emberAfGetEndpointUniqueIdForEndPoint(endpointId, epUniqueIdSpan));
     541              : 
     542              :     memcpy(epUniqueId.data(), epUniqueIdSpan.data(), epUniqueIdSpan.size());
     543              :     return CHIP_NO_ERROR;
     544              : }
     545              : #endif
     546              : 
     547              : } // namespace app
     548              : } // namespace chip
        

Generated by: LCOV version 2.0-1