Matter SDK Coverage Report
Current view: top level - controller - TypedReadCallback.h (source / functions) Coverage Total Hit
Test: SHA:b879ecb8e99e175eea0a293a888bda853da2b19c Lines: 0.0 % 46 0
Test Date: 2025-01-17 19:00:11 Functions: 0.0 % 33 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, constructing a StatusIB from it will
      47              :  *     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 2.0-1