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

Generated by: LCOV version 2.0-1