Matter SDK Coverage Report
Current view: top level - controller - WriteInteraction.h (source / functions) Coverage Total Hit
Test: SHA:c5aeaea5470ddad6464d5b62caddeb9f1efd6a41 Lines: 75.0 % 48 36
Test Date: 2025-07-25 07:10:31 Functions: 76.5 % 17 13

            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/ChunkedWriteCallback.h>
      22              : #include <app/InteractionModelEngine.h>
      23              : #include <app/WriteClient.h>
      24              : #include <controller/CommandSenderAllocator.h>
      25              : #include <controller/TypedCommandCallback.h>
      26              : #include <functional>
      27              : #include <lib/core/Optional.h>
      28              : 
      29              : namespace chip {
      30              : namespace Controller {
      31              : 
      32              : namespace Internal {
      33              : // WriteCancelFn functions on WriteAttribute() are for internal use only.
      34              : typedef std::function<void()> WriteCancelFn;
      35              : } // namespace Internal
      36              : 
      37              : /*
      38              :  * An adapter callback that permits applications to provide std::function callbacks for success, error and on done.
      39              :  * This permits a slightly more flexible programming model that allows applications to pass in lambdas and bound member functions
      40              :  * as they see fit instead.
      41              :  *
      42              :  */
      43              : 
      44              : class WriteCallback final : public app::WriteClient::Callback
      45              : {
      46              : public:
      47              :     using OnSuccessCallbackType = std::function<void(const app::ConcreteAttributePath &)>;
      48              : 
      49              :     //
      50              :     // Callback to deliver any error that occurs during the write. This includes
      51              :     // errors global to the write as a whole (e.g timeout) as well as per-attribute
      52              :     // errors.
      53              :     //
      54              :     // In the latter case, path will be non-null. Otherwise, it shall be null.
      55              :     //
      56              :     using OnErrorCallbackType = std::function<void(const app::ConcreteAttributePath * path, CHIP_ERROR err)>;
      57              :     using OnDoneCallbackType  = std::function<void(app::WriteClient *)>;
      58              : 
      59            7 :     WriteCallback(OnSuccessCallbackType aOnSuccess, OnErrorCallbackType aOnError, OnDoneCallbackType aOnDone, bool aIsGroupWrite) :
      60            7 :         mOnSuccess(aOnSuccess), mOnError(aOnError), mOnDone(aOnDone), mIsGroupWrite(aIsGroupWrite), mCallback(this)
      61            7 :     {}
      62              : 
      63            7 :     app::WriteClient::Callback * GetChunkedCallback() { return &mCallback; }
      64              : 
      65            7 :     void OnResponse(const app::WriteClient * apWriteClient, const app::ConcreteDataAttributePath & aPath,
      66              :                     app::StatusIB status) override
      67              :     {
      68            7 :         if (mCalledCallback)
      69              :         {
      70            0 :             return;
      71              :         }
      72            7 :         mCalledCallback = true;
      73              : 
      74            7 :         if (status.IsSuccess())
      75              :         {
      76            3 :             mOnSuccess(aPath);
      77              :         }
      78              :         else
      79              :         {
      80            4 :             mOnError(&aPath, status.ToChipError());
      81              :         }
      82              :     }
      83              : 
      84            0 :     void OnError(const app::WriteClient * apWriteClient, CHIP_ERROR aError) override
      85              :     {
      86            0 :         if (mCalledCallback)
      87              :         {
      88            0 :             return;
      89              :         }
      90            0 :         mCalledCallback = true;
      91              : 
      92            0 :         mOnError(nullptr, aError);
      93              :     }
      94              : 
      95            7 :     void OnDone(app::WriteClient * apWriteClient) override
      96              :     {
      97            7 :         if (!mIsGroupWrite && !mCalledCallback)
      98              :         {
      99              :             // This can happen if the server sends a response with an empty
     100              :             // WriteResponses list.  Since we are not sending wildcard write
     101              :             // paths, that's not a valid response and we should treat it as an
     102              :             // error.  Use the error we would have gotten if we in fact expected
     103              :             // a nonempty list.
     104            0 :             OnError(apWriteClient, CHIP_END_OF_TLV);
     105              :         }
     106              : 
     107            7 :         if (mOnDone != nullptr)
     108              :         {
     109            0 :             mOnDone(apWriteClient);
     110              :         }
     111              : 
     112            7 :         chip::Platform::Delete(apWriteClient);
     113              :         // Always needs to be the last call
     114            7 :         chip::Platform::Delete(this);
     115            7 :     }
     116              : 
     117              : private:
     118              :     OnSuccessCallbackType mOnSuccess = nullptr;
     119              :     OnErrorCallbackType mOnError     = nullptr;
     120              :     OnDoneCallbackType mOnDone       = nullptr;
     121              : 
     122              :     bool mCalledCallback = false;
     123              :     bool mIsGroupWrite   = false;
     124              : 
     125              :     app::ChunkedWriteCallback mCallback;
     126              : };
     127              : 
     128              : /**
     129              :  * Functions for writing attributes.  We have lots of different AttributeInfo
     130              :  * but a fairly small set of types that get written.  So we want to keep the
     131              :  * template on AttributeInfo very small, and put all the work in the template
     132              :  * with a small number of instantiations (one per type).
     133              :  */
     134              : template <typename AttrType>
     135            7 : CHIP_ERROR WriteAttribute(const SessionHandle & sessionHandle, chip::EndpointId endpointId, ClusterId clusterId,
     136              :                           AttributeId attributeId, const AttrType & requestData, WriteCallback::OnSuccessCallbackType onSuccessCb,
     137              :                           WriteCallback::OnErrorCallbackType onErrorCb, const Optional<uint16_t> & aTimedWriteTimeoutMs,
     138              :                           WriteCallback::OnDoneCallbackType onDoneCb = nullptr,
     139              :                           const Optional<DataVersion> & aDataVersion = NullOptional,
     140              :                           Internal::WriteCancelFn * outCancelFn      = nullptr)
     141              : {
     142            7 :     auto callback = Platform::MakeUnique<WriteCallback>(onSuccessCb, onErrorCb, onDoneCb, sessionHandle->IsGroupSession());
     143            7 :     VerifyOrReturnError(callback != nullptr, CHIP_ERROR_NO_MEMORY);
     144              : 
     145            7 :     auto client = Platform::MakeUnique<app::WriteClient>(app::InteractionModelEngine::GetInstance()->GetExchangeManager(),
     146            7 :                                                          callback->GetChunkedCallback(), aTimedWriteTimeoutMs);
     147            7 :     VerifyOrReturnError(client != nullptr, CHIP_ERROR_NO_MEMORY);
     148              : 
     149            7 :     if (sessionHandle->IsGroupSession())
     150              :     {
     151            0 :         ReturnErrorOnFailure(client->EncodeAttribute(chip::app::AttributePathParams(clusterId, attributeId), requestData));
     152              :     }
     153              :     else
     154              :     {
     155            7 :         ReturnErrorOnFailure(
     156              :             client->EncodeAttribute(chip::app::AttributePathParams(endpointId, clusterId, attributeId), requestData, aDataVersion));
     157              :     }
     158              : 
     159            7 :     ReturnErrorOnFailure(client->SendWriteRequest(sessionHandle));
     160              : 
     161              :     // If requested by the caller, provide a way to cancel the write interaction.
     162            7 :     if (outCancelFn != nullptr)
     163              :     {
     164            0 :         *outCancelFn = [rawCallback = callback.get(), rawClient = client.get()]() {
     165            0 :             chip::Platform::Delete(rawClient);
     166            0 :             chip::Platform::Delete(rawCallback);
     167              :         };
     168              :     }
     169              : 
     170              :     // At this point the handle will ensure our callback's OnDone is always
     171              :     // called.
     172            7 :     client.release();
     173            7 :     callback.release();
     174              : 
     175            7 :     return CHIP_NO_ERROR;
     176            7 : }
     177              : 
     178              : template <typename AttributeInfo>
     179            7 : CHIP_ERROR WriteAttribute(const SessionHandle & sessionHandle, chip::EndpointId endpointId,
     180              :                           const typename AttributeInfo::Type & requestData, WriteCallback::OnSuccessCallbackType onSuccessCb,
     181              :                           WriteCallback::OnErrorCallbackType onErrorCb, const Optional<uint16_t> & aTimedWriteTimeoutMs,
     182              :                           WriteCallback::OnDoneCallbackType onDoneCb = nullptr,
     183              :                           const Optional<DataVersion> & aDataVersion = NullOptional)
     184              : {
     185           14 :     return WriteAttribute(sessionHandle, endpointId, AttributeInfo::GetClusterId(), AttributeInfo::GetAttributeId(), requestData,
     186            7 :                           onSuccessCb, onErrorCb, aTimedWriteTimeoutMs, onDoneCb, aDataVersion);
     187              : }
     188              : 
     189              : template <typename AttributeInfo>
     190              : CHIP_ERROR WriteAttribute(const SessionHandle & sessionHandle, chip::EndpointId endpointId,
     191              :                           const typename AttributeInfo::Type & requestData, WriteCallback::OnSuccessCallbackType onSuccessCb,
     192              :                           WriteCallback::OnErrorCallbackType onErrorCb, uint16_t aTimedWriteTimeoutMs,
     193              :                           WriteCallback::OnDoneCallbackType onDoneCb = nullptr,
     194              :                           const Optional<DataVersion> & aDataVersion = NullOptional)
     195              : {
     196              :     return WriteAttribute<AttributeInfo>(sessionHandle, endpointId, requestData, onSuccessCb, onErrorCb, onDoneCb,
     197              :                                          MakeOptional(aTimedWriteTimeoutMs), onDoneCb, aDataVersion);
     198              : }
     199              : 
     200              : template <typename AttributeInfo, typename std::enable_if_t<!AttributeInfo::MustUseTimedWrite(), int> = 0>
     201            7 : CHIP_ERROR WriteAttribute(const SessionHandle & sessionHandle, chip::EndpointId endpointId,
     202              :                           const typename AttributeInfo::Type & requestData, WriteCallback::OnSuccessCallbackType onSuccessCb,
     203              :                           WriteCallback::OnErrorCallbackType onErrorCb, WriteCallback::OnDoneCallbackType onDoneCb = nullptr,
     204              :                           const Optional<DataVersion> & aDataVersion = NullOptional)
     205              : {
     206           14 :     return WriteAttribute<AttributeInfo>(sessionHandle, endpointId, requestData, onSuccessCb, onErrorCb, NullOptional, onDoneCb,
     207            7 :                                          aDataVersion);
     208              : }
     209              : 
     210              : } // namespace Controller
     211              : } // namespace chip
        

Generated by: LCOV version 2.0-1