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

Generated by: LCOV version 1.14