Matter SDK Coverage Report
Current view: top level - data-model-providers/codegen - CodegenDataModelProvider.h (source / functions) Coverage Total Hit
Test: SHA:b879ecb8e99e175eea0a293a888bda853da2b19c Lines: 100.0 % 17 17
Test Date: 2025-01-17 19:00:11 Functions: 100.0 % 7 7

            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              : #pragma once
      18              : 
      19              : #include <app/data-model-provider/Provider.h>
      20              : 
      21              : #include <app/CommandHandlerInterface.h>
      22              : #include <app/ConcreteCommandPath.h>
      23              : #include <app/data-model-provider/ActionReturnStatus.h>
      24              : #include <app/util/af-types.h>
      25              : #include <lib/core/CHIPPersistentStorageDelegate.h>
      26              : 
      27              : namespace chip {
      28              : namespace app {
      29              : 
      30              : namespace detail {
      31              : 
      32              : /// Handles going through callback-based enumeration of generated/accepted commands
      33              : /// for CommandHandlerInterface based items.
      34              : ///
      35              : /// Offers the ability to focus on some operation for finding a given
      36              : /// command id:
      37              : ///   - FindFirst will return the first found element
      38              : ///   - FindExact finds the element with the given id
      39              : ///   - FindNext finds the element following the given id
      40              : class EnumeratorCommandFinder
      41              : {
      42              : public:
      43              :     using HandlerCallbackFunction = CHIP_ERROR (CommandHandlerInterface::*)(const ConcreteClusterPath &,
      44              :                                                                             CommandHandlerInterface::CommandIdCallback, void *);
      45              : 
      46              :     enum class Operation
      47              :     {
      48              :         kFindFirst, // Find the first value in the list
      49              :         kFindExact, // Find the given value
      50              :         kFindNext   // Find the value AFTER this value
      51              :     };
      52              : 
      53          178 :     EnumeratorCommandFinder(HandlerCallbackFunction callback) :
      54          178 :         mCallback(callback), mOperation(Operation::kFindFirst), mTarget(kInvalidCommandId)
      55          178 :     {}
      56              : 
      57              :     /// Find the given command ID that matches the given operation/path.
      58              :     ///
      59              :     /// If operation is kFindFirst, then path commandID is ignored. Otherwise it is used as a key to
      60              :     /// kFindExact or kFindNext.
      61              :     ///
      62              :     /// Returns:
      63              :     ///    - std::nullopt if no command found using the command handler interface
      64              :     ///    - kInvalidCommandId if the find failed (but command handler interface does provide a list)
      65              :     ///    - valid id if command handler interface usage succeeds
      66              :     std::optional<CommandId> FindCommandId(Operation operation, const ConcreteCommandPath & path);
      67              : 
      68              : private:
      69              :     HandlerCallbackFunction mCallback;
      70              :     Operation mOperation;
      71              :     CommandId mTarget;
      72              :     std::optional<CommandId> mFound = std::nullopt;
      73              : 
      74              :     Loop HandlerCallback(CommandId id);
      75              : 
      76           18 :     static Loop HandlerCallbackFn(CommandId id, void * context)
      77              :     {
      78           18 :         auto self = static_cast<EnumeratorCommandFinder *>(context);
      79           18 :         return self->HandlerCallback(id);
      80              :     }
      81              : };
      82              : 
      83              : } // namespace detail
      84              : 
      85              : /// An implementation of `InteractionModel::Model` that relies on code-generation
      86              : /// via zap/ember.
      87              : ///
      88              : /// The Ember framework uses generated files (like endpoint-config.h and various
      89              : /// other generated metadata) to provide a cluster model.
      90              : ///
      91              : /// This class will use global functions generally residing in `app/util`
      92              : /// as well as application-specific overrides to provide data model functionality.
      93              : ///
      94              : /// Given that this relies on global data at link time, there generally can be
      95              : /// only one CodegenDataModelProvider per application (you can create more instances,
      96              : /// however they would share the exact same underlying data and storage).
      97              : class CodegenDataModelProvider : public DataModel::Provider
      98              : {
      99              : private:
     100              :     /// Ember commands are stored as a `CommandId *` pointer that is either null (i.e. no commands)
     101              :     /// or is terminated with 0xFFFF_FFFF aka kInvalidCommandId
     102              :     ///
     103              :     /// Since iterator implementations in the data model use Next(before_path) calls, iterating
     104              :     /// such lists from the beginning would be very inefficient as O(n^2).
     105              :     ///
     106              :     /// This class maintains a cached position inside such iteration, such that `Next` calls
     107              :     /// can be faster.
     108              :     class EmberCommandListIterator
     109              :     {
     110              :     private:
     111              :         const CommandId * mCurrentList = nullptr;
     112              :         const CommandId * mCurrentHint = nullptr; // Invariant: mCurrentHint is INSIDE mCurrentList
     113              :     public:
     114              :         EmberCommandListIterator() = default;
     115              : 
     116              :         /// Returns the first command in the given list (or nullopt if list is null or starts with 0xFFFFFFF)
     117              :         std::optional<CommandId> First(const CommandId * list);
     118              : 
     119              :         /// Returns the command after `previousId` in the given list
     120              :         std::optional<CommandId> Next(const CommandId * list, CommandId previousId);
     121              : 
     122              :         /// Checks if the given command id exists in the given list
     123              :         bool Exists(const CommandId * list, CommandId toCheck);
     124              : 
     125          318 :         void Reset() { mCurrentList = mCurrentHint = nullptr; }
     126              :     };
     127              : 
     128              : public:
     129              :     /// clears out internal caching. Especially useful in unit tests,
     130              :     /// where path caching does not really apply (the same path may result in different outcomes)
     131          159 :     void Reset()
     132              :     {
     133          159 :         mAcceptedCommandsIterator.Reset();
     134          159 :         mGeneratedCommandsIterator.Reset();
     135          159 :         mPreviouslyFoundCluster = std::nullopt;
     136          159 :     }
     137              : 
     138            1 :     void SetPersistentStorageDelegate(PersistentStorageDelegate * delegate) { mPersistentStorageDelegate = delegate; }
     139              :     PersistentStorageDelegate * GetPersistentStorageDelegate() { return mPersistentStorageDelegate; }
     140              : 
     141              :     /// Generic model implementations
     142          159 :     CHIP_ERROR Shutdown() override
     143              :     {
     144          159 :         Reset();
     145          159 :         return CHIP_NO_ERROR;
     146              :     }
     147              : 
     148              :     CHIP_ERROR Startup(DataModel::InteractionModelContext context) override;
     149              : 
     150              :     DataModel::ActionReturnStatus ReadAttribute(const DataModel::ReadAttributeRequest & request,
     151              :                                                 AttributeValueEncoder & encoder) override;
     152              :     DataModel::ActionReturnStatus WriteAttribute(const DataModel::WriteAttributeRequest & request,
     153              :                                                  AttributeValueDecoder & decoder) override;
     154              :     std::optional<DataModel::ActionReturnStatus> Invoke(const DataModel::InvokeRequest & request, TLV::TLVReader & input_arguments,
     155              :                                                         CommandHandler * handler) override;
     156              : 
     157              :     /// attribute tree iteration
     158              :     DataModel::EndpointEntry FirstEndpoint() override;
     159              :     DataModel::EndpointEntry NextEndpoint(EndpointId before) override;
     160              :     std::optional<DataModel::EndpointInfo> GetEndpointInfo(EndpointId endpoint) override;
     161              :     bool EndpointExists(EndpointId endpoint) override;
     162              : 
     163              :     std::optional<DataModel::DeviceTypeEntry> FirstDeviceType(EndpointId endpoint) override;
     164              :     std::optional<DataModel::DeviceTypeEntry> NextDeviceType(EndpointId endpoint,
     165              :                                                              const DataModel::DeviceTypeEntry & previous) override;
     166              : 
     167              :     std::optional<SemanticTag> GetFirstSemanticTag(EndpointId endpoint) override;
     168              :     std::optional<SemanticTag> GetNextSemanticTag(EndpointId endpoint, const SemanticTag & previous) override;
     169              : 
     170              :     DataModel::ClusterEntry FirstServerCluster(EndpointId endpoint) override;
     171              :     DataModel::ClusterEntry NextServerCluster(const ConcreteClusterPath & before) override;
     172              :     std::optional<DataModel::ClusterInfo> GetServerClusterInfo(const ConcreteClusterPath & path) override;
     173              : 
     174              :     ConcreteClusterPath FirstClientCluster(EndpointId endpoint) override;
     175              :     ConcreteClusterPath NextClientCluster(const ConcreteClusterPath & before) override;
     176              : 
     177              :     DataModel::AttributeEntry FirstAttribute(const ConcreteClusterPath & cluster) override;
     178              :     DataModel::AttributeEntry NextAttribute(const ConcreteAttributePath & before) override;
     179              :     std::optional<DataModel::AttributeInfo> GetAttributeInfo(const ConcreteAttributePath & path) override;
     180              : 
     181              :     DataModel::CommandEntry FirstAcceptedCommand(const ConcreteClusterPath & cluster) override;
     182              :     DataModel::CommandEntry NextAcceptedCommand(const ConcreteCommandPath & before) override;
     183              :     std::optional<DataModel::CommandInfo> GetAcceptedCommandInfo(const ConcreteCommandPath & path) override;
     184              : 
     185              :     ConcreteCommandPath FirstGeneratedCommand(const ConcreteClusterPath & cluster) override;
     186              :     ConcreteCommandPath NextGeneratedCommand(const ConcreteCommandPath & before) override;
     187              : 
     188              :     void Temporary_ReportAttributeChanged(const AttributePathParams & path) override;
     189              : 
     190              : private:
     191              :     // Iteration is often done in a tight loop going through all values.
     192              :     // To avoid N^2 iterations, cache a hint of where something is positioned
     193              :     uint16_t mEndpointIterationHint      = 0;
     194              :     unsigned mServerClusterIterationHint = 0;
     195              :     unsigned mClientClusterIterationHint = 0;
     196              :     unsigned mAttributeIterationHint     = 0;
     197              :     unsigned mDeviceTypeIterationHint    = 0;
     198              :     unsigned mSemanticTagIterationHint   = 0;
     199              :     EmberCommandListIterator mAcceptedCommandsIterator;
     200              :     EmberCommandListIterator mGeneratedCommandsIterator;
     201              : 
     202              :     // represents a remembered cluster reference that has been found as
     203              :     // looking for clusters is very common (for every attribute iteration)
     204              :     struct ClusterReference
     205              :     {
     206              :         ConcreteClusterPath path;
     207              :         const EmberAfCluster * cluster;
     208              : 
     209          416 :         ClusterReference(const ConcreteClusterPath p, const EmberAfCluster * c) : path(p), cluster(c) {}
     210              :     };
     211              : 
     212              :     enum class ClusterSide : uint8_t
     213              :     {
     214              :         kServer,
     215              :         kClient,
     216              :     };
     217              : 
     218              :     std::optional<ClusterReference> mPreviouslyFoundCluster;
     219              :     unsigned mEmberMetadataStructureGeneration = 0;
     220              : 
     221              :     // Ember requires a persistence provider, so we make sure we can always have something
     222              :     PersistentStorageDelegate * mPersistentStorageDelegate = nullptr;
     223              : 
     224              :     /// Finds the specified ember cluster
     225              :     ///
     226              :     /// Effectively the same as `emberAfFindServerCluster` except with some caching capabilities
     227              :     const EmberAfCluster * FindServerCluster(const ConcreteClusterPath & path);
     228              : 
     229              :     /// Find the index of the given attribute id
     230              :     std::optional<unsigned> TryFindAttributeIndex(const EmberAfCluster * cluster, AttributeId id) const;
     231              : 
     232              :     /// Find the index of the given cluster id
     233              :     std::optional<unsigned> TryFindClusterIndex(const EmberAfEndpointType * endpoint, ClusterId id, ClusterSide clusterSide) const;
     234              : 
     235              :     /// Find the index of the given endpoint id
     236              :     std::optional<unsigned> TryFindEndpointIndex(EndpointId id) const;
     237              : 
     238              :     using CommandListGetter = const CommandId *(const EmberAfCluster &);
     239              : 
     240              :     CommandId FindCommand(const ConcreteCommandPath & path, detail::EnumeratorCommandFinder & handlerFinder,
     241              :                           detail::EnumeratorCommandFinder::Operation operation,
     242              :                           CodegenDataModelProvider::EmberCommandListIterator & emberIterator, CommandListGetter commandListGetter);
     243              : };
     244              : 
     245              : } // namespace app
     246              : } // namespace chip
        

Generated by: LCOV version 2.0-1