LCOV - code coverage report
Current view: top level - controller - TypedCommandCallback.h (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 0 37 0.0 %
Date: 2024-02-15 08:20:41 Functions: 0 65 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 "protocols/interaction_model/Constants.h"
      22             : #include <app/CommandSender.h>
      23             : #include <app/data-model/Decode.h>
      24             : #include <app/data-model/NullObject.h>
      25             : #include <functional>
      26             : 
      27             : namespace chip {
      28             : namespace Controller {
      29             : 
      30             : /*
      31             :  * This provides an adapter class that implements CommandSender::Callback and provides two additional features:
      32             :  *  1. The ability to pass in std::function closures to permit more flexible programming scenarios than are provided by the strict
      33             :  *     delegate interface stipulated by CommandSender::Callback
      34             :  *
      35             :  *  2. Automatic decoding of command response data provided in the TLVReader by the CommandSender callback into a decoded cluster
      36             :  * object.
      37             :  */
      38             : template <typename CommandResponseObjectT>
      39             : class TypedCommandCallback final : public app::CommandSender::Callback
      40             : {
      41             : public:
      42             :     using OnSuccessCallbackType =
      43             :         std::function<void(const app::ConcreteCommandPath &, const app::StatusIB &, const CommandResponseObjectT &)>;
      44             :     using OnErrorCallbackType = std::function<void(CHIP_ERROR aError)>;
      45             :     using OnDoneCallbackType  = std::function<void(app::CommandSender * commandSender)>;
      46             : 
      47             :     /*
      48             :      * Constructor that takes in success, failure and onDone callbacks.
      49             :      *
      50             :      * The latter can be provided later through the SetOnDoneCallback below in cases where the
      51             :      * TypedCommandCallback object needs to be created first before it can be passed in as a closure
      52             :      * into a hypothetical OnDoneCallback function.
      53             :      */
      54           0 :     TypedCommandCallback(OnSuccessCallbackType aOnSuccess, OnErrorCallbackType aOnError, OnDoneCallbackType aOnDone = {}) :
      55           0 :         mOnSuccess(aOnSuccess), mOnError(aOnError), mOnDone(aOnDone)
      56           0 :     {}
      57             : 
      58           0 :     void SetOnDoneCallback(OnDoneCallbackType callback) { mOnDone = callback; }
      59             : 
      60             : private:
      61             :     void OnResponse(app::CommandSender * apCommandSender, const app::ConcreteCommandPath & aCommandPath,
      62             :                     const app::StatusIB & aStatus, TLV::TLVReader * aReader) override;
      63             : 
      64           0 :     void OnError(const app::CommandSender * apCommandSender, CHIP_ERROR aError) override
      65             :     {
      66           0 :         if (mCalledCallback)
      67             :         {
      68           0 :             return;
      69             :         }
      70           0 :         mCalledCallback = true;
      71             : 
      72           0 :         mOnError(aError);
      73             :     }
      74             : 
      75           0 :     void OnDone(app::CommandSender * apCommandSender) override
      76             :     {
      77           0 :         if (!mCalledCallback)
      78             :         {
      79             :             // This can happen if the server sends a response with an empty
      80             :             // InvokeResponses list.  Since we are not sending wildcard command
      81             :             // paths, that's not a valid response and we should treat it as an
      82             :             // error.  Use the error we would have gotten if we in fact expected
      83             :             // a nonempty list.
      84           0 :             OnError(apCommandSender, CHIP_END_OF_TLV);
      85             :         }
      86             : 
      87           0 :         mOnDone(apCommandSender);
      88           0 :     }
      89             : 
      90             :     OnSuccessCallbackType mOnSuccess;
      91             :     OnErrorCallbackType mOnError;
      92             :     OnDoneCallbackType mOnDone;
      93             : 
      94             :     bool mCalledCallback = false;
      95             : };
      96             : 
      97             : /*
      98             :  * Decodes the data provided by the TLVReader into the templated cluster object that denotes the command response.
      99             :  *
     100             :  * This function specifically decodes command responses that have actual data payloads.
     101             :  */
     102             : template <typename CommandResponseObjectT>
     103           0 : void TypedCommandCallback<CommandResponseObjectT>::OnResponse(app::CommandSender * apCommandSender,
     104             :                                                               const app::ConcreteCommandPath & aCommandPath,
     105             :                                                               const app::StatusIB & aStatus, TLV::TLVReader * aReader)
     106             : {
     107           0 :     if (mCalledCallback)
     108             :     {
     109           0 :         return;
     110             :     }
     111           0 :     mCalledCallback = true;
     112             : 
     113           0 :     CommandResponseObjectT response;
     114           0 :     CHIP_ERROR err = CHIP_NO_ERROR;
     115             : 
     116             :     //
     117             :     // We're expecting response data in this variant of OnResponse. Consequently, aReader should always be
     118             :     // non-null. If it is, it means we received a success status code instead, which is not what was expected.
     119             :     //
     120           0 :     VerifyOrExit(aReader != nullptr, err = CHIP_ERROR_SCHEMA_MISMATCH);
     121             : 
     122             :     //
     123             :     // Validate that the data response we received matches what we expect in terms of its cluster and command IDs.
     124             :     //
     125           0 :     VerifyOrExit(aCommandPath.mClusterId == CommandResponseObjectT::GetClusterId() &&
     126             :                      aCommandPath.mCommandId == CommandResponseObjectT::GetCommandId(),
     127             :                  err = CHIP_ERROR_SCHEMA_MISMATCH);
     128             : 
     129           0 :     err = app::DataModel::Decode(*aReader, response);
     130           0 :     SuccessOrExit(err);
     131             : 
     132           0 :     mOnSuccess(aCommandPath, aStatus, response);
     133             : 
     134           0 : exit:
     135           0 :     if (err != CHIP_NO_ERROR)
     136             :     {
     137           0 :         mOnError(err);
     138             :     }
     139           0 : }
     140             : 
     141             : /*
     142             :  * Decodes the data provided by the TLVReader into the templated cluster object that denotes the command response.
     143             :  *
     144             :  * This function specifically decodes command responses that do not have actual data payloads and where the passed in TLVReader
     145             :  * should be null.
     146             :  */
     147             : template <>
     148           0 : inline void TypedCommandCallback<app::DataModel::NullObjectType>::OnResponse(app::CommandSender * apCommandSender,
     149             :                                                                              const app::ConcreteCommandPath & aCommandPath,
     150             :                                                                              const app::StatusIB & aStatus,
     151             :                                                                              TLV::TLVReader * aReader)
     152             : {
     153           0 :     if (mCalledCallback)
     154             :     {
     155           0 :         return;
     156             :     }
     157           0 :     mCalledCallback = true;
     158             : 
     159             :     //
     160             :     // If we got a valid reader, it means we received response data that we were not expecting to receive.
     161             :     //
     162           0 :     if (aReader != nullptr)
     163             :     {
     164           0 :         mOnError(CHIP_ERROR_SCHEMA_MISMATCH);
     165           0 :         return;
     166             :     }
     167             : 
     168             :     app::DataModel::NullObjectType nullResp;
     169           0 :     mOnSuccess(aCommandPath, aStatus, nullResp);
     170             : }
     171             : 
     172             : } // namespace Controller
     173             : } // namespace chip

Generated by: LCOV version 1.14