Matter SDK Coverage Report
Current view: top level - controller - CHIPCluster.h (source / functions) Coverage Total Hit
Test: SHA:b879ecb8e99e175eea0a293a888bda853da2b19c Lines: 0.0 % 24 0
Test Date: 2025-01-17 19:00:11 Functions: 0.0 % 25 0

            Line data    Source code
       1              : /*
       2              :  *
       3              :  *    Copyright (c) 2020 Project CHIP Authors
       4              :  *    All rights reserved.
       5              :  *
       6              :  *    Licensed under the Apache License, Version 2.0 (the "License");
       7              :  *    you may not use this file except in compliance with the License.
       8              :  *    You may obtain a copy of the License at
       9              :  *
      10              :  *        http://www.apache.org/licenses/LICENSE-2.0
      11              :  *
      12              :  *    Unless required by applicable law or agreed to in writing, software
      13              :  *    distributed under the License is distributed on an "AS IS" BASIS,
      14              :  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      15              :  *    See the License for the specific language governing permissions and
      16              :  *    limitations under the License.
      17              :  */
      18              : 
      19              : /**
      20              :  *  @file
      21              :  *    This file contains definitions for a base Cluster class. This class will
      22              :  *    be derived by various ZCL clusters supported by CHIP. The objects of the
      23              :  *    ZCL cluster class will be used by Controller applications to interact with
      24              :  *    the CHIP device.
      25              :  */
      26              : 
      27              : #pragma once
      28              : 
      29              : #include <app/AppConfig.h>
      30              : #include <app/ConcreteCommandPath.h>
      31              : #include <controller/InvokeInteraction.h>
      32              : #include <controller/ReadInteraction.h>
      33              : #include <controller/WriteInteraction.h>
      34              : #include <lib/core/Optional.h>
      35              : #include <messaging/ExchangeMgr.h>
      36              : #include <system/SystemClock.h>
      37              : 
      38              : namespace chip {
      39              : namespace Controller {
      40              : 
      41              : template <typename T>
      42              : using CommandResponseSuccessCallback = void(void * context, const T & responseObject);
      43              : using CommandResponseFailureCallback = void(void * context, CHIP_ERROR err);
      44              : using CommandResponseDoneCallback    = void();
      45              : using WriteResponseSuccessCallback   = void (*)(void * context);
      46              : using WriteResponseFailureCallback   = void (*)(void * context, CHIP_ERROR err);
      47              : using WriteResponseDoneCallback      = void (*)(void * context);
      48              : template <typename T>
      49              : using ReadResponseSuccessCallback     = void (*)(void * context, T responseData);
      50              : using ReadResponseFailureCallback     = void (*)(void * context, CHIP_ERROR err);
      51              : using ReadDoneCallback                = void (*)(void * context);
      52              : using SubscriptionEstablishedCallback = void (*)(void * context, SubscriptionId subscriptionId);
      53              : using ResubscriptionAttemptCallback   = void (*)(void * context, CHIP_ERROR aError, uint32_t aNextResubscribeIntervalMsec);
      54              : using SubscriptionOnDoneCallback      = std::function<void(void)>;
      55              : 
      56              : class DLL_EXPORT ClusterBase
      57              : {
      58              : public:
      59            0 :     ClusterBase(Messaging::ExchangeManager & exchangeManager, const SessionHandle & session, EndpointId endpoint) :
      60            0 :         mExchangeManager(exchangeManager), mSession(session), mEndpoint(endpoint)
      61            0 :     {}
      62              : 
      63            0 :     virtual ~ClusterBase() {}
      64              : 
      65              :     // Temporary function to set command timeout before we move over to InvokeCommand
      66              :     // TODO: remove when we start using InvokeCommand everywhere
      67              :     void SetCommandTimeout(Optional<System::Clock::Timeout> timeout) { mTimeout = timeout; }
      68              : 
      69              :     /**
      70              :      * Returns the current command timeout set via SetCommandTimeout, or an
      71              :      * empty optional if no timeout has been set.
      72              :      */
      73              :     Optional<System::Clock::Timeout> GetCommandTimeout() { return mTimeout; }
      74              : 
      75              :     /*
      76              :      * This function permits sending an invoke request using cluster objects that represent the request and response data payloads.
      77              :      *
      78              :      * Success and Failure callbacks must be passed in through which the decoded response is provided as well as notification of any
      79              :      * failure.
      80              :      */
      81              :     template <typename RequestDataT>
      82            0 :     CHIP_ERROR InvokeCommand(const RequestDataT & requestData, void * context,
      83              :                              CommandResponseSuccessCallback<typename RequestDataT::ResponseType> successCb,
      84              :                              CommandResponseFailureCallback failureCb, const Optional<uint16_t> & timedInvokeTimeoutMs)
      85              :     {
      86            0 :         auto onSuccessCb = [context, successCb](const app::ConcreteCommandPath & aPath, const app::StatusIB & aStatus,
      87              :                                                 const typename RequestDataT::ResponseType & responseData) {
      88            0 :             successCb(context, responseData);
      89              :         };
      90              : 
      91            0 :         auto onFailureCb = [context, failureCb](CHIP_ERROR aError) { failureCb(context, aError); };
      92              : 
      93            0 :         return InvokeCommandRequest(&mExchangeManager, mSession.Get().Value(), mEndpoint, requestData, onSuccessCb, onFailureCb,
      94            0 :                                     timedInvokeTimeoutMs, mTimeout);
      95              :     }
      96              : 
      97              :     template <typename RequestDataT>
      98              :     CHIP_ERROR InvokeCommand(const RequestDataT & requestData, void * context,
      99              :                              CommandResponseSuccessCallback<typename RequestDataT::ResponseType> successCb,
     100              :                              CommandResponseFailureCallback failureCb, uint16_t timedInvokeTimeoutMs)
     101              :     {
     102              :         return InvokeCommand(requestData, context, successCb, failureCb, MakeOptional(timedInvokeTimeoutMs));
     103              :     }
     104              : 
     105              :     template <typename RequestDataT, typename std::enable_if_t<!RequestDataT::MustUseTimedInvoke(), int> = 0>
     106            0 :     CHIP_ERROR InvokeCommand(const RequestDataT & requestData, void * context,
     107              :                              CommandResponseSuccessCallback<typename RequestDataT::ResponseType> successCb,
     108              :                              CommandResponseFailureCallback failureCb)
     109              :     {
     110            0 :         return InvokeCommand(requestData, context, successCb, failureCb, NullOptional);
     111              :     }
     112              : 
     113              :     /**
     114              :      * Functions for writing attributes.  We have lots of different
     115              :      * AttributeInfo but a fairly small set of types that get written.  So we
     116              :      * want to keep the template on AttributeInfo very small, and put all the
     117              :      * work in the template with a small number of instantiations (one per
     118              :      * type).
     119              :      */
     120              :     template <typename AttrType>
     121              :     CHIP_ERROR WriteAttribute(const AttrType & requestData, void * context, ClusterId clusterId, AttributeId attributeId,
     122              :                               WriteResponseSuccessCallback successCb, WriteResponseFailureCallback failureCb,
     123              :                               const Optional<uint16_t> & aTimedWriteTimeoutMs, WriteResponseDoneCallback doneCb = nullptr,
     124              :                               const Optional<DataVersion> & aDataVersion = NullOptional)
     125              :     {
     126              :         auto onSuccessCb = [context, successCb](const app::ConcreteAttributePath & aPath) {
     127              :             if (successCb != nullptr)
     128              :             {
     129              :                 successCb(context);
     130              :             }
     131              :         };
     132              : 
     133              :         auto onFailureCb = [context, failureCb](const app::ConcreteAttributePath * aPath, CHIP_ERROR aError) {
     134              :             if (failureCb != nullptr)
     135              :             {
     136              :                 failureCb(context, aError);
     137              :             }
     138              :         };
     139              : 
     140              :         auto onDoneCb = [context, doneCb](app::WriteClient * pWriteClient) {
     141              :             if (doneCb != nullptr)
     142              :             {
     143              :                 doneCb(context);
     144              :             }
     145              :         };
     146              : 
     147              :         return chip::Controller::WriteAttribute<AttrType>(mSession.Get().Value(), mEndpoint, clusterId, attributeId, requestData,
     148              :                                                           onSuccessCb, onFailureCb, aTimedWriteTimeoutMs, onDoneCb, aDataVersion);
     149              :     }
     150              : 
     151              :     template <typename AttrType>
     152              :     CHIP_ERROR WriteAttribute(GroupId groupId, FabricIndex fabricIndex, const AttrType & requestData, void * context,
     153              :                               ClusterId clusterId, AttributeId attributeId, WriteResponseSuccessCallback successCb,
     154              :                               WriteResponseFailureCallback failureCb, const Optional<uint16_t> & aTimedWriteTimeoutMs,
     155              :                               WriteResponseDoneCallback doneCb = nullptr, const Optional<DataVersion> & aDataVersion = NullOptional)
     156              :     {
     157              : 
     158              :         auto onSuccessCb = [context, successCb](const app::ConcreteAttributePath & aPath) {
     159              :             if (successCb != nullptr)
     160              :             {
     161              :                 successCb(context);
     162              :             }
     163              :         };
     164              : 
     165              :         auto onFailureCb = [context, failureCb](const app::ConcreteAttributePath * aPath, CHIP_ERROR aError) {
     166              :             if (failureCb != nullptr)
     167              :             {
     168              :                 failureCb(context, aError);
     169              :             }
     170              :         };
     171              : 
     172              :         auto onDoneCb = [context, doneCb](app::WriteClient * pWriteClient) {
     173              :             if (doneCb != nullptr)
     174              :             {
     175              :                 doneCb(context);
     176              :             }
     177              :         };
     178              : 
     179              :         Transport::OutgoingGroupSession groupSession(groupId, fabricIndex);
     180              :         return chip::Controller::WriteAttribute<AttrType>(SessionHandle(groupSession), 0 /*Unused for Group*/, clusterId,
     181              :                                                           attributeId, requestData, onSuccessCb, onFailureCb, aTimedWriteTimeoutMs,
     182              :                                                           onDoneCb, aDataVersion);
     183              :     }
     184              : 
     185              :     template <typename AttributeInfo>
     186              :     CHIP_ERROR WriteAttribute(GroupId groupId, FabricIndex fabricIndex, const typename AttributeInfo::Type & requestData,
     187              :                               void * context, WriteResponseSuccessCallback successCb, WriteResponseFailureCallback failureCb,
     188              :                               WriteResponseDoneCallback doneCb = nullptr, const Optional<DataVersion> & aDataVersion = NullOptional,
     189              :                               const Optional<uint16_t> & aTimedWriteTimeoutMs = NullOptional)
     190              :     {
     191              :         return WriteAttribute(groupId, fabricIndex, requestData, context, AttributeInfo::GetClusterId(),
     192              :                               AttributeInfo::GetAttributeId(), successCb, failureCb, aTimedWriteTimeoutMs, doneCb, aDataVersion);
     193              :     }
     194              : 
     195              :     template <typename AttributeInfo>
     196              :     CHIP_ERROR WriteAttribute(const typename AttributeInfo::Type & requestData, void * context,
     197              :                               WriteResponseSuccessCallback successCb, WriteResponseFailureCallback failureCb,
     198              :                               const Optional<uint16_t> & aTimedWriteTimeoutMs, WriteResponseDoneCallback doneCb = nullptr,
     199              :                               const Optional<DataVersion> & aDataVersion = NullOptional)
     200              :     {
     201              :         return WriteAttribute(requestData, context, AttributeInfo::GetClusterId(), AttributeInfo::GetAttributeId(), successCb,
     202              :                               failureCb, aTimedWriteTimeoutMs, doneCb, aDataVersion);
     203              :     }
     204              : 
     205              :     template <typename AttributeInfo>
     206              :     CHIP_ERROR WriteAttribute(const typename AttributeInfo::Type & requestData, void * context,
     207              :                               WriteResponseSuccessCallback successCb, WriteResponseFailureCallback failureCb,
     208              :                               uint16_t aTimedWriteTimeoutMs, WriteResponseDoneCallback doneCb = nullptr,
     209              :                               const Optional<DataVersion> & aDataVersion = NullOptional)
     210              :     {
     211              :         return WriteAttribute<AttributeInfo>(requestData, context, successCb, failureCb, MakeOptional(aTimedWriteTimeoutMs), doneCb,
     212              :                                              aDataVersion);
     213              :     }
     214              : 
     215              :     template <typename AttributeInfo, typename std::enable_if_t<!AttributeInfo::MustUseTimedWrite(), int> = 0>
     216              :     CHIP_ERROR WriteAttribute(const typename AttributeInfo::Type & requestData, void * context,
     217              :                               WriteResponseSuccessCallback successCb, WriteResponseFailureCallback failureCb,
     218              :                               WriteResponseDoneCallback doneCb = nullptr, const Optional<DataVersion> & aDataVersion = NullOptional)
     219              :     {
     220              :         return WriteAttribute<AttributeInfo>(requestData, context, successCb, failureCb, NullOptional, doneCb, aDataVersion);
     221              :     }
     222              : 
     223              : #if CHIP_CONFIG_ENABLE_READ_CLIENT
     224              :     /**
     225              :      * Read an attribute and get a type-safe callback with the attribute value.
     226              :      */
     227              :     template <typename AttributeInfo>
     228            0 :     CHIP_ERROR ReadAttribute(void * context, ReadResponseSuccessCallback<typename AttributeInfo::DecodableArgType> successCb,
     229              :                              ReadResponseFailureCallback failureCb, bool aIsFabricFiltered = true)
     230              :     {
     231            0 :         return ReadAttribute<typename AttributeInfo::DecodableType, typename AttributeInfo::DecodableArgType>(
     232            0 :             context, AttributeInfo::GetClusterId(), AttributeInfo::GetAttributeId(), successCb, failureCb, aIsFabricFiltered);
     233              :     }
     234              : 
     235              :     template <typename DecodableType, typename DecodableArgType>
     236            0 :     CHIP_ERROR ReadAttribute(void * context, ClusterId clusterId, AttributeId attributeId,
     237              :                              ReadResponseSuccessCallback<DecodableArgType> successCb, ReadResponseFailureCallback failureCb,
     238              :                              bool aIsFabricFiltered = true)
     239              :     {
     240            0 :         auto onSuccessCb = [context, successCb](const app::ConcreteAttributePath & aPath, const DecodableType & aData) {
     241            0 :             if (successCb != nullptr)
     242              :             {
     243            0 :                 successCb(context, aData);
     244              :             }
     245              :         };
     246              : 
     247            0 :         auto onFailureCb = [context, failureCb](const app::ConcreteAttributePath * aPath, CHIP_ERROR aError) {
     248            0 :             if (failureCb != nullptr)
     249              :             {
     250            0 :                 failureCb(context, aError);
     251              :             }
     252              :         };
     253              : 
     254            0 :         return Controller::ReadAttribute<DecodableType>(&mExchangeManager, mSession.Get().Value(), mEndpoint, clusterId,
     255            0 :                                                         attributeId, onSuccessCb, onFailureCb, aIsFabricFiltered);
     256              :     }
     257              : 
     258              :     /**
     259              :      * Subscribe to attribute and get a type-safe callback with the attribute
     260              :      * value when it changes.
     261              :      */
     262              :     template <typename AttributeInfo>
     263              :     CHIP_ERROR
     264              :     SubscribeAttribute(void * context, ReadResponseSuccessCallback<typename AttributeInfo::DecodableArgType> reportCb,
     265              :                        ReadResponseFailureCallback failureCb, uint16_t minIntervalFloorSeconds, uint16_t maxIntervalCeilingSeconds,
     266              :                        SubscriptionEstablishedCallback subscriptionEstablishedCb = nullptr,
     267              :                        ResubscriptionAttemptCallback resubscriptionAttemptCb = nullptr, bool aIsFabricFiltered = true,
     268              :                        bool aKeepPreviousSubscriptions = false, const Optional<DataVersion> & aDataVersion = NullOptional,
     269              :                        SubscriptionOnDoneCallback subscriptionDoneCb = nullptr)
     270              :     {
     271              :         return SubscribeAttribute<typename AttributeInfo::DecodableType, typename AttributeInfo::DecodableArgType>(
     272              :             context, AttributeInfo::GetClusterId(), AttributeInfo::GetAttributeId(), reportCb, failureCb, minIntervalFloorSeconds,
     273              :             maxIntervalCeilingSeconds, subscriptionEstablishedCb, resubscriptionAttemptCb, aIsFabricFiltered,
     274              :             aKeepPreviousSubscriptions, aDataVersion, subscriptionDoneCb);
     275              :     }
     276              : 
     277              :     template <typename DecodableType, typename DecodableArgType>
     278              :     CHIP_ERROR SubscribeAttribute(void * context, ClusterId clusterId, AttributeId attributeId,
     279              :                                   ReadResponseSuccessCallback<DecodableArgType> reportCb, ReadResponseFailureCallback failureCb,
     280              :                                   uint16_t minIntervalFloorSeconds, uint16_t maxIntervalCeilingSeconds,
     281              :                                   SubscriptionEstablishedCallback subscriptionEstablishedCb = nullptr,
     282              :                                   ResubscriptionAttemptCallback resubscriptionAttemptCb = nullptr, bool aIsFabricFiltered = true,
     283              :                                   bool aKeepPreviousSubscriptions               = false,
     284              :                                   const Optional<DataVersion> & aDataVersion    = NullOptional,
     285              :                                   SubscriptionOnDoneCallback subscriptionDoneCb = nullptr)
     286              :     {
     287              :         auto onReportCb = [context, reportCb](const app::ConcreteAttributePath & aPath, const DecodableType & aData) {
     288              :             if (reportCb != nullptr)
     289              :             {
     290              :                 reportCb(context, aData);
     291              :             }
     292              :         };
     293              : 
     294              :         auto onFailureCb = [context, failureCb](const app::ConcreteAttributePath * aPath, CHIP_ERROR aError) {
     295              :             if (failureCb != nullptr)
     296              :             {
     297              :                 failureCb(context, aError);
     298              :             }
     299              :         };
     300              : 
     301              :         auto onSubscriptionEstablishedCb = [context, subscriptionEstablishedCb](const app::ReadClient & readClient,
     302              :                                                                                 SubscriptionId subscriptionId) {
     303              :             if (subscriptionEstablishedCb != nullptr)
     304              :             {
     305              :                 subscriptionEstablishedCb(context, subscriptionId);
     306              :             }
     307              :         };
     308              : 
     309              :         auto onResubscriptionAttemptCb = [context, resubscriptionAttemptCb](const app::ReadClient & readClient, CHIP_ERROR aError,
     310              :                                                                             uint32_t aNextResubscribeIntervalMsec) {
     311              :             if (resubscriptionAttemptCb != nullptr)
     312              :             {
     313              :                 resubscriptionAttemptCb(context, aError, aNextResubscribeIntervalMsec);
     314              :             }
     315              :         };
     316              : 
     317              :         return Controller::SubscribeAttribute<DecodableType>(
     318              :             &mExchangeManager, mSession.Get().Value(), mEndpoint, clusterId, attributeId, onReportCb, onFailureCb,
     319              :             minIntervalFloorSeconds, maxIntervalCeilingSeconds, onSubscriptionEstablishedCb, onResubscriptionAttemptCb,
     320              :             aIsFabricFiltered, aKeepPreviousSubscriptions, aDataVersion, subscriptionDoneCb);
     321              :     }
     322              : 
     323              :     /**
     324              :      * Read an event and get a type-safe callback with the event data.
     325              :      *
     326              :      * @param[in] successCb Used to deliver event data received through the Read interactions
     327              :      * @param[in] failureCb failureCb will be called when an error occurs *after* a successful call to ReadEvent.
     328              :      * @param[in] doneCb    OnDone will be called when ReadClient has finished all work for event retrieval, it is possible that
     329              :      * there is no event.
     330              :      */
     331              :     template <typename DecodableType>
     332              :     CHIP_ERROR ReadEvent(void * context, ReadResponseSuccessCallback<DecodableType> successCb,
     333              :                          ReadResponseFailureCallback failureCb, ReadDoneCallback doneCb)
     334              :     {
     335              :         auto onSuccessCb = [context, successCb](const app::EventHeader & aEventHeader, const DecodableType & aData) {
     336              :             if (successCb != nullptr)
     337              :             {
     338              :                 successCb(context, aData);
     339              :             }
     340              :         };
     341              : 
     342              :         auto onFailureCb = [context, failureCb](const app::EventHeader * aEventHeader, CHIP_ERROR aError) {
     343              :             if (failureCb != nullptr)
     344              :             {
     345              :                 failureCb(context, aError);
     346              :             }
     347              :         };
     348              : 
     349              :         auto onDoneCb = [context, doneCb](app::ReadClient * apReadClient) {
     350              :             if (doneCb != nullptr)
     351              :             {
     352              :                 doneCb(context);
     353              :             }
     354              :         };
     355              :         return Controller::ReadEvent<DecodableType>(&mExchangeManager, mSession.Get().Value(), mEndpoint, onSuccessCb, onFailureCb,
     356              :                                                     onDoneCb);
     357              :     }
     358              : 
     359              :     template <typename DecodableType>
     360              :     CHIP_ERROR SubscribeEvent(void * context, ReadResponseSuccessCallback<DecodableType> reportCb,
     361              :                               ReadResponseFailureCallback failureCb, uint16_t minIntervalFloorSeconds,
     362              :                               uint16_t maxIntervalCeilingSeconds,
     363              :                               SubscriptionEstablishedCallback subscriptionEstablishedCb = nullptr,
     364              :                               ResubscriptionAttemptCallback resubscriptionAttemptCb     = nullptr,
     365              :                               bool aKeepPreviousSubscriptions = false, bool aIsUrgentEvent = false)
     366              :     {
     367              :         auto onReportCb = [context, reportCb](const app::EventHeader & aEventHeader, const DecodableType & aData) {
     368              :             if (reportCb != nullptr)
     369              :             {
     370              :                 reportCb(context, aData);
     371              :             }
     372              :         };
     373              : 
     374              :         auto onFailureCb = [context, failureCb](const app::EventHeader * aEventHeader, CHIP_ERROR aError) {
     375              :             if (failureCb != nullptr)
     376              :             {
     377              :                 failureCb(context, aError);
     378              :             }
     379              :         };
     380              : 
     381              :         auto onSubscriptionEstablishedCb = [context, subscriptionEstablishedCb](const app::ReadClient & readClient,
     382              :                                                                                 SubscriptionId subscriptionId) {
     383              :             if (subscriptionEstablishedCb != nullptr)
     384              :             {
     385              :                 subscriptionEstablishedCb(context, subscriptionId);
     386              :             }
     387              :         };
     388              : 
     389              :         auto onResubscriptionAttemptCb = [context, resubscriptionAttemptCb](const app::ReadClient & readClient, CHIP_ERROR aError,
     390              :                                                                             uint32_t aNextResubscribeIntervalMsec) {
     391              :             if (resubscriptionAttemptCb != nullptr)
     392              :             {
     393              :                 resubscriptionAttemptCb(context, aError, aNextResubscribeIntervalMsec);
     394              :             }
     395              :         };
     396              : 
     397              :         return Controller::SubscribeEvent<DecodableType>(&mExchangeManager, mSession.Get().Value(), mEndpoint, onReportCb,
     398              :                                                          onFailureCb, minIntervalFloorSeconds, maxIntervalCeilingSeconds,
     399              :                                                          onSubscriptionEstablishedCb, onResubscriptionAttemptCb,
     400              :                                                          aKeepPreviousSubscriptions, aIsUrgentEvent);
     401              :     }
     402              : #endif // CHIP_CONFIG_ENABLE_READ_CLIENT
     403              : 
     404              : protected:
     405              :     Messaging::ExchangeManager & mExchangeManager;
     406              : 
     407              :     // Since cluster object is ephemeral, the session shall be valid during the entire lifespan, so we do not need to check the
     408              :     // session existence when using it. For java and objective-c binding, the cluster object is allocated in the heap, such that we
     409              :     // can't use SessionHandle here, in such case, the cluster object must be freed when the session is released.
     410              :     SessionHolder mSession;
     411              : 
     412              :     EndpointId mEndpoint;
     413              :     Optional<System::Clock::Timeout> mTimeout;
     414              : };
     415              : 
     416              : } // namespace Controller
     417              : } // namespace chip
        

Generated by: LCOV version 2.0-1