LCOV - code coverage report
Current view: top level - controller - TypedReadCallback.h (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 0 46 0.0 %
Date: 2024-02-15 08:20:41 Functions: 0 33 0.0 %

          Line data    Source code
       1             : /*
       2             :  *
       3             :  *    Copyright (c) 2021 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             : #pragma once
      20             : 
      21             : #include <app/AppConfig.h>
      22             : #include <app/BufferedReadCallback.h>
      23             : #include <app/ConcreteAttributePath.h>
      24             : #include <app/data-model/Decode.h>
      25             : #include <functional>
      26             : #include <lib/support/CHIPMem.h>
      27             : 
      28             : #if CHIP_CONFIG_ENABLE_READ_CLIENT
      29             : namespace chip {
      30             : namespace Controller {
      31             : 
      32             : /*
      33             :  * This provides an adapter class that implements ReadClient::Callback and provides three additional
      34             :  * features:
      35             :  *  1. The ability to pass in std::function closures to permit more flexible
      36             :  *     programming scenarios than are provided by the strict delegate interface
      37             :  *     stipulated by ReadClient::Callback.
      38             :  *
      39             :  *  2. Automatic decoding of attribute data provided in the TLVReader by
      40             :  *     ReadClient::Callback::OnAttributeData into a decoded cluster object.
      41             :  *
      42             :  *  3. Automatically representing all errors as a CHIP_ERROR (which might
      43             :  *     encapsulate a StatusIB).  This could be a path-specific error or it
      44             :  *     could be a general error for the entire request; the distinction is not
      45             :  *     that important, because we only have one path involved.  If the
      46             :  *     CHIP_ERROR encapsulates a StatusIB, StatusIB::InitFromChipError can be
      47             :  *     used to extract the status.
      48             :  */
      49             : template <typename DecodableAttributeType>
      50             : class TypedReadAttributeCallback final : public app::ReadClient::Callback
      51             : {
      52             : public:
      53             :     using OnSuccessCallbackType =
      54             :         std::function<void(const app::ConcreteDataAttributePath & aPath, const DecodableAttributeType & aData)>;
      55             :     using OnErrorCallbackType = std::function<void(const app::ConcreteDataAttributePath * aPath, CHIP_ERROR aError)>;
      56             :     using OnDoneCallbackType  = std::function<void(TypedReadAttributeCallback * callback)>;
      57             :     using OnSubscriptionEstablishedCallbackType =
      58             :         std::function<void(const app::ReadClient & readClient, SubscriptionId aSubscriptionId)>;
      59             :     using OnResubscriptionAttemptCallbackType =
      60             :         std::function<void(const app::ReadClient & readClient, CHIP_ERROR aError, uint32_t aNextResubscribeIntervalMsec)>;
      61           0 :     TypedReadAttributeCallback(ClusterId aClusterId, AttributeId aAttributeId, OnSuccessCallbackType aOnSuccess,
      62             :                                OnErrorCallbackType aOnError, OnDoneCallbackType aOnDone,
      63             :                                OnSubscriptionEstablishedCallbackType aOnSubscriptionEstablished = nullptr,
      64             :                                OnResubscriptionAttemptCallbackType aOnResubscriptionAttempt     = nullptr) :
      65           0 :         mClusterId(aClusterId),
      66           0 :         mAttributeId(aAttributeId), mOnSuccess(aOnSuccess), mOnError(aOnError), mOnDone(aOnDone),
      67           0 :         mOnSubscriptionEstablished(aOnSubscriptionEstablished), mOnResubscriptionAttempt(aOnResubscriptionAttempt),
      68           0 :         mBufferedReadAdapter(*this)
      69           0 :     {}
      70             : 
      71           0 :     ~TypedReadAttributeCallback()
      72             :     {
      73             :         // Ensure we release the ReadClient before we tear down anything else,
      74             :         // so it can call our OnDeallocatePaths properly.
      75           0 :         mReadClient = nullptr;
      76           0 :     }
      77             : 
      78           0 :     app::BufferedReadCallback & GetBufferedCallback() { return mBufferedReadAdapter; }
      79             : 
      80           0 :     void AdoptReadClient(Platform::UniquePtr<app::ReadClient> aReadClient) { mReadClient = std::move(aReadClient); }
      81             : 
      82             : private:
      83           0 :     void OnAttributeData(const app::ConcreteDataAttributePath & aPath, TLV::TLVReader * apData,
      84             :                          const app::StatusIB & aStatus) override
      85             :     {
      86           0 :         if (mCalledCallback && mReadClient->IsReadType())
      87             :         {
      88           0 :             return;
      89             :         }
      90           0 :         mCalledCallback = true;
      91             : 
      92           0 :         CHIP_ERROR err = CHIP_NO_ERROR;
      93             :         DecodableAttributeType value;
      94             : 
      95             :         //
      96             :         // We shouldn't be getting list item operations in the provided path since that should be handled by the buffered read
      97             :         // callback. If we do, that's a bug.
      98             :         //
      99           0 :         VerifyOrDie(!aPath.IsListItemOperation());
     100             : 
     101           0 :         VerifyOrExit(aStatus.IsSuccess(), err = aStatus.ToChipError());
     102           0 :         VerifyOrExit(aPath.mClusterId == mClusterId && aPath.mAttributeId == mAttributeId, err = CHIP_ERROR_SCHEMA_MISMATCH);
     103           0 :         VerifyOrExit(apData != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT);
     104             : 
     105           0 :         SuccessOrExit(err = app::DataModel::Decode(*apData, value));
     106             : 
     107           0 :         mOnSuccess(aPath, value);
     108             : 
     109           0 :     exit:
     110           0 :         if (err != CHIP_NO_ERROR)
     111             :         {
     112           0 :             mOnError(&aPath, err);
     113             :         }
     114             :     }
     115             : 
     116           0 :     void OnError(CHIP_ERROR aError) override
     117             :     {
     118           0 :         if (mCalledCallback && mReadClient->IsReadType())
     119             :         {
     120           0 :             return;
     121             :         }
     122           0 :         mCalledCallback = true;
     123             : 
     124           0 :         mOnError(nullptr, aError);
     125             :     }
     126             : 
     127           0 :     void OnDone(app::ReadClient *) override { mOnDone(this); }
     128             : 
     129           0 :     void OnSubscriptionEstablished(SubscriptionId aSubscriptionId) override
     130             :     {
     131           0 :         if (mOnSubscriptionEstablished)
     132             :         {
     133           0 :             mOnSubscriptionEstablished(*mReadClient.get(), aSubscriptionId);
     134             :         }
     135           0 :     }
     136             : 
     137           0 :     CHIP_ERROR OnResubscriptionNeeded(chip::app::ReadClient * apReadClient, CHIP_ERROR aTerminationCause) override
     138             :     {
     139           0 :         ReturnErrorOnFailure(app::ReadClient::Callback::OnResubscriptionNeeded(apReadClient, aTerminationCause));
     140             : 
     141           0 :         if (mOnResubscriptionAttempt)
     142             :         {
     143           0 :             mOnResubscriptionAttempt(*mReadClient.get(), aTerminationCause, apReadClient->ComputeTimeTillNextSubscription());
     144             :         }
     145             : 
     146           0 :         return CHIP_NO_ERROR;
     147             :     }
     148             : 
     149           0 :     void OnDeallocatePaths(chip::app::ReadPrepareParams && aReadPrepareParams) override
     150             :     {
     151           0 :         VerifyOrDie(aReadPrepareParams.mAttributePathParamsListSize == 1 &&
     152             :                     aReadPrepareParams.mpAttributePathParamsList != nullptr);
     153           0 :         chip::Platform::Delete<app::AttributePathParams>(aReadPrepareParams.mpAttributePathParamsList);
     154             : 
     155           0 :         if (aReadPrepareParams.mDataVersionFilterListSize == 1 && aReadPrepareParams.mpDataVersionFilterList != nullptr)
     156             :         {
     157           0 :             chip::Platform::Delete<app::DataVersionFilter>(aReadPrepareParams.mpDataVersionFilterList);
     158             :         }
     159           0 :     }
     160             : 
     161             :     ClusterId mClusterId;
     162             :     AttributeId mAttributeId;
     163             :     OnSuccessCallbackType mOnSuccess;
     164             :     OnErrorCallbackType mOnError;
     165             :     OnDoneCallbackType mOnDone;
     166             :     OnSubscriptionEstablishedCallbackType mOnSubscriptionEstablished;
     167             :     OnResubscriptionAttemptCallbackType mOnResubscriptionAttempt;
     168             :     app::BufferedReadCallback mBufferedReadAdapter;
     169             :     Platform::UniquePtr<app::ReadClient> mReadClient;
     170             :     // For reads, we ensure that we make only one data/error callback to our consumer.
     171             :     bool mCalledCallback = false;
     172             : };
     173             : 
     174             : template <typename DecodableEventType>
     175             : class TypedReadEventCallback final : public app::ReadClient::Callback
     176             : {
     177             : public:
     178             :     using OnSuccessCallbackType = std::function<void(const app::EventHeader & aEventHeader, const DecodableEventType & aData)>;
     179             :     using OnErrorCallbackType   = std::function<void(const app::EventHeader * apEventHeader, CHIP_ERROR aError)>;
     180             :     using OnDoneCallbackType    = std::function<void(app::ReadClient * apReadClient)>;
     181             :     using OnSubscriptionEstablishedCallbackType =
     182             :         std::function<void(const app::ReadClient & aReadClient, SubscriptionId aSubscriptionId)>;
     183             :     using OnResubscriptionAttemptCallbackType =
     184             :         std::function<void(const app::ReadClient & aReadClient, CHIP_ERROR aError, uint32_t aNextResubscribeIntervalMsec)>;
     185             : 
     186             :     TypedReadEventCallback(OnSuccessCallbackType aOnSuccess, OnErrorCallbackType aOnError, OnDoneCallbackType aOnDone,
     187             :                            OnSubscriptionEstablishedCallbackType aOnSubscriptionEstablished = nullptr,
     188             :                            OnResubscriptionAttemptCallbackType aOnResubscriptionAttempt     = nullptr) :
     189             :         mOnSuccess(aOnSuccess),
     190             :         mOnError(aOnError), mOnDone(aOnDone), mOnSubscriptionEstablished(aOnSubscriptionEstablished),
     191             :         mOnResubscriptionAttempt(aOnResubscriptionAttempt)
     192             :     {}
     193             : 
     194             :     ~TypedReadEventCallback()
     195             :     {
     196             :         // Ensure we release the ReadClient before we tear down anything else,
     197             :         // so it can call our OnDeallocatePaths properly.
     198             :         mReadClient = nullptr;
     199             :     }
     200             : 
     201             :     void AdoptReadClient(Platform::UniquePtr<app::ReadClient> aReadClient) { mReadClient = std::move(aReadClient); }
     202             : 
     203             : private:
     204             :     void OnEventData(const app::EventHeader & aEventHeader, TLV::TLVReader * apData, const app::StatusIB * apStatus) override
     205             :     {
     206             :         if (mCalledCallback && mReadClient->IsReadType())
     207             :         {
     208             :             return;
     209             :         }
     210             :         mCalledCallback = true;
     211             : 
     212             :         CHIP_ERROR err = CHIP_NO_ERROR;
     213             :         DecodableEventType value;
     214             : 
     215             :         // Only one of the apData and apStatus can be non-null, so apStatus will always indicate a failure status when it is not
     216             :         // nullptr.
     217             :         VerifyOrExit(apStatus == nullptr, err = apStatus->ToChipError());
     218             : 
     219             :         VerifyOrExit(apData != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT);
     220             : 
     221             :         VerifyOrExit((aEventHeader.mPath.mEventId == value.GetEventId()) && (aEventHeader.mPath.mClusterId == value.GetClusterId()),
     222             :                      CHIP_ERROR_SCHEMA_MISMATCH);
     223             :         err = app::DataModel::Decode(*apData, value);
     224             :         SuccessOrExit(err);
     225             : 
     226             :         mOnSuccess(aEventHeader, value);
     227             : 
     228             :     exit:
     229             :         if (err != CHIP_NO_ERROR)
     230             :         {
     231             :             mOnError(&aEventHeader, err);
     232             :         }
     233             :     }
     234             : 
     235             :     void OnError(CHIP_ERROR aError) override
     236             :     {
     237             :         if (mCalledCallback && mReadClient->IsReadType())
     238             :         {
     239             :             return;
     240             :         }
     241             :         mCalledCallback = true;
     242             : 
     243             :         mOnError(nullptr, aError);
     244             :     }
     245             : 
     246             :     void OnDone(app::ReadClient * apReadClient) override
     247             :     {
     248             :         if (mOnDone != nullptr)
     249             :         {
     250             :             mOnDone(apReadClient);
     251             :         }
     252             : 
     253             :         // Always needs to be the last call
     254             :         chip::Platform::Delete(this);
     255             :     }
     256             : 
     257             :     void OnDeallocatePaths(chip::app::ReadPrepareParams && aReadPrepareParams) override
     258             :     {
     259             :         VerifyOrDie(aReadPrepareParams.mEventPathParamsListSize == 1 && aReadPrepareParams.mpEventPathParamsList != nullptr);
     260             :         chip::Platform::Delete<app::EventPathParams>(aReadPrepareParams.mpEventPathParamsList);
     261             :     }
     262             : 
     263             :     void OnSubscriptionEstablished(SubscriptionId aSubscriptionId) override
     264             :     {
     265             :         if (mOnSubscriptionEstablished)
     266             :         {
     267             :             mOnSubscriptionEstablished(*mReadClient.get(), aSubscriptionId);
     268             :         }
     269             :     }
     270             : 
     271             :     CHIP_ERROR OnResubscriptionNeeded(chip::app::ReadClient * apReadClient, CHIP_ERROR aTerminationCause) override
     272             :     {
     273             :         ReturnErrorOnFailure(app::ReadClient::Callback::OnResubscriptionNeeded(apReadClient, aTerminationCause));
     274             : 
     275             :         if (mOnResubscriptionAttempt)
     276             :         {
     277             :             mOnResubscriptionAttempt(*mReadClient.get(), aTerminationCause, apReadClient->ComputeTimeTillNextSubscription());
     278             :         }
     279             : 
     280             :         return CHIP_NO_ERROR;
     281             :     }
     282             : 
     283             :     OnSuccessCallbackType mOnSuccess;
     284             :     OnErrorCallbackType mOnError;
     285             :     OnDoneCallbackType mOnDone;
     286             :     OnSubscriptionEstablishedCallbackType mOnSubscriptionEstablished;
     287             :     OnResubscriptionAttemptCallbackType mOnResubscriptionAttempt;
     288             :     Platform::UniquePtr<app::ReadClient> mReadClient;
     289             :     // For reads, we ensure that we make only one data/error callback to our consumer.
     290             :     bool mCalledCallback = false;
     291             : };
     292             : 
     293             : } // namespace Controller
     294             : } // namespace chip
     295             : #endif // CHIP_CONFIG_ENABLE_READ_CLIENT

Generated by: LCOV version 1.14