Coverage Report

Created: 2025-06-24 06:17

/src/connectedhomeip/src/controller/InvokeInteraction.h
Line
Count
Source (jump to first uncovered line)
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 <controller/TypedCommandCallback.h>
22
#include <lib/core/Optional.h>
23
24
#include <functional>
25
26
namespace chip {
27
namespace Controller {
28
29
namespace Internal {
30
// Cancellation functions on InvokeCommandRequest() are for internal use only.
31
typedef std::function<void()> InvokeCancelFn;
32
} // namespace Internal
33
34
/*
35
 * A typed command invocation function that takes as input a cluster-object representation of a command request and
36
 * callbacks for success and failure and either returns a decoded cluster-object representation of the response through
37
 * the provided success callback or calls the provided failure callback.
38
 *
39
 * The RequestObjectT is generally expected to be a ClusterName::Commands::CommandName::Type struct, but any object
40
 * that can be encoded using the DataModel::Encode machinery and exposes the
41
 * GetClusterId() and GetCommandId() functions and a ResponseType type
42
 * is expected to work.
43
 *
44
 * The ResponseType is expected to be one of two things:
45
 *
46
 *    - If a data response is expected on success, a struct type decodable via DataModel::Decode which has GetClusterId() and
47
 * GetCommandId() methods.  A ClusterName::Commands::ResponseCommandName::DecodableType is typically used.
48
 *    - If a status response is expected on success, DataModel::NullObjectType.
49
 *
50
 */
51
template <typename RequestObjectT>
52
CHIP_ERROR
53
InvokeCommandRequest(Messaging::ExchangeManager * aExchangeMgr, const SessionHandle & sessionHandle, chip::EndpointId endpointId,
54
                     const RequestObjectT & requestCommandData,
55
                     typename TypedCommandCallback<typename RequestObjectT::ResponseType>::OnSuccessCallbackType onSuccessCb,
56
                     typename TypedCommandCallback<typename RequestObjectT::ResponseType>::OnErrorCallbackType onErrorCb,
57
                     const Optional<uint16_t> & timedInvokeTimeoutMs,
58
                     const Optional<System::Clock::Timeout> & responseTimeout = NullOptional,
59
                     Internal::InvokeCancelFn * outCancelFn                   = nullptr)
60
0
{
61
    // InvokeCommandRequest expects responses, so cannot happen over a group session.
62
0
    VerifyOrReturnError(!sessionHandle->IsGroupSession(), CHIP_ERROR_INVALID_ARGUMENT);
63
64
0
    app::CommandPathParams commandPath = { endpointId, 0, RequestObjectT::GetClusterId(), RequestObjectT::GetCommandId(),
65
0
                                           (app::CommandPathFlags::kEndpointIdValid) };
66
67
    //
68
    // Let's create a handle version of the decoder to ensure we do correct clean-up of it if things go south at any point below
69
    //
70
0
    auto decoder = chip::Platform::MakeUnique<TypedCommandCallback<typename RequestObjectT::ResponseType>>(onSuccessCb, onErrorCb);
71
0
    VerifyOrReturnError(decoder != nullptr, CHIP_ERROR_NO_MEMORY);
72
73
    //
74
    // Upon successful completion of SendCommandRequest below, we're expected to free up the respective allocated objects
75
    // in the OnDone callback.
76
    //
77
0
    auto onDone = [rawDecoderPtr = decoder.get()](app::CommandSender * commandSender) {
78
0
        chip::Platform::Delete(commandSender);
79
0
        chip::Platform::Delete(rawDecoderPtr);
80
0
    };
Unexecuted instantiation: chip::Controller::InvokeCommandRequest<chip::app::Clusters::OnOff::Commands::On::Type>(chip::Messaging::ExchangeManager*, chip::SessionHandle const&, unsigned short, chip::app::Clusters::OnOff::Commands::On::Type const&, chip::Controller::TypedCommandCallback<chip::app::Clusters::OnOff::Commands::On::Type::ResponseType>::OnSuccessCallbackType, chip::Controller::TypedCommandCallback<chip::app::Clusters::OnOff::Commands::On::Type::ResponseType>::OnErrorCallbackType, chip::Optional<unsigned short> const&, chip::Optional<std::__1::chrono::duration<unsigned int, std::__1::ratio<1l, 1000l> > > const&, std::__1::function<void ()>*)::{lambda(chip::app::CommandSender*)#1}::operator()(chip::app::CommandSender*) const
Unexecuted instantiation: chip::Controller::InvokeCommandRequest<chip::app::Clusters::OnOff::Commands::Off::Type>(chip::Messaging::ExchangeManager*, chip::SessionHandle const&, unsigned short, chip::app::Clusters::OnOff::Commands::Off::Type const&, chip::Controller::TypedCommandCallback<chip::app::Clusters::OnOff::Commands::Off::Type::ResponseType>::OnSuccessCallbackType, chip::Controller::TypedCommandCallback<chip::app::Clusters::OnOff::Commands::Off::Type::ResponseType>::OnErrorCallbackType, chip::Optional<unsigned short> const&, chip::Optional<std::__1::chrono::duration<unsigned int, std::__1::ratio<1l, 1000l> > > const&, std::__1::function<void ()>*)::{lambda(chip::app::CommandSender*)#1}::operator()(chip::app::CommandSender*) const
Unexecuted instantiation: chip::Controller::InvokeCommandRequest<chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::QueryImage::Type>(chip::Messaging::ExchangeManager*, chip::SessionHandle const&, unsigned short, chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::QueryImage::Type const&, chip::Controller::TypedCommandCallback<chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::QueryImage::Type::ResponseType>::OnSuccessCallbackType, chip::Controller::TypedCommandCallback<chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::QueryImage::Type::ResponseType>::OnErrorCallbackType, chip::Optional<unsigned short> const&, chip::Optional<std::__1::chrono::duration<unsigned int, std::__1::ratio<1l, 1000l> > > const&, std::__1::function<void ()>*)::{lambda(chip::app::CommandSender*)#1}::operator()(chip::app::CommandSender*) const
Unexecuted instantiation: chip::Controller::InvokeCommandRequest<chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::ApplyUpdateRequest::Type>(chip::Messaging::ExchangeManager*, chip::SessionHandle const&, unsigned short, chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::ApplyUpdateRequest::Type const&, chip::Controller::TypedCommandCallback<chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::ApplyUpdateRequest::Type::ResponseType>::OnSuccessCallbackType, chip::Controller::TypedCommandCallback<chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::ApplyUpdateRequest::Type::ResponseType>::OnErrorCallbackType, chip::Optional<unsigned short> const&, chip::Optional<std::__1::chrono::duration<unsigned int, std::__1::ratio<1l, 1000l> > > const&, std::__1::function<void ()>*)::{lambda(chip::app::CommandSender*)#1}::operator()(chip::app::CommandSender*) const
Unexecuted instantiation: chip::Controller::InvokeCommandRequest<chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::NotifyUpdateApplied::Type>(chip::Messaging::ExchangeManager*, chip::SessionHandle const&, unsigned short, chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::NotifyUpdateApplied::Type const&, chip::Controller::TypedCommandCallback<chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::NotifyUpdateApplied::Type::ResponseType>::OnSuccessCallbackType, chip::Controller::TypedCommandCallback<chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::NotifyUpdateApplied::Type::ResponseType>::OnErrorCallbackType, chip::Optional<unsigned short> const&, chip::Optional<std::__1::chrono::duration<unsigned int, std::__1::ratio<1l, 1000l> > > const&, std::__1::function<void ()>*)::{lambda(chip::app::CommandSender*)#1}::operator()(chip::app::CommandSender*) const
81
82
0
    decoder->SetOnDoneCallback(onDone);
83
84
0
    auto commandSender =
85
0
        chip::Platform::MakeUnique<app::CommandSender>(decoder.get(), aExchangeMgr, timedInvokeTimeoutMs.HasValue());
86
0
    VerifyOrReturnError(commandSender != nullptr, CHIP_ERROR_NO_MEMORY);
87
88
0
    ReturnErrorOnFailure(commandSender->AddRequestData(commandPath, requestCommandData, timedInvokeTimeoutMs));
89
0
    ReturnErrorOnFailure(commandSender->SendCommandRequest(sessionHandle, responseTimeout));
90
91
    // If requested by the caller, provide a way to cancel the invoke interaction.
92
0
    if (outCancelFn != nullptr)
93
0
    {
94
0
        *outCancelFn = [rawDecoderPtr = decoder.get(), rawCommandSender = commandSender.get()]() {
95
0
            chip::Platform::Delete(rawCommandSender);
96
0
            chip::Platform::Delete(rawDecoderPtr);
97
0
        };
Unexecuted instantiation: chip::Controller::InvokeCommandRequest<chip::app::Clusters::OnOff::Commands::On::Type>(chip::Messaging::ExchangeManager*, chip::SessionHandle const&, unsigned short, chip::app::Clusters::OnOff::Commands::On::Type const&, chip::Controller::TypedCommandCallback<chip::app::Clusters::OnOff::Commands::On::Type::ResponseType>::OnSuccessCallbackType, chip::Controller::TypedCommandCallback<chip::app::Clusters::OnOff::Commands::On::Type::ResponseType>::OnErrorCallbackType, chip::Optional<unsigned short> const&, chip::Optional<std::__1::chrono::duration<unsigned int, std::__1::ratio<1l, 1000l> > > const&, std::__1::function<void ()>*)::{lambda()#1}::operator()() const
Unexecuted instantiation: chip::Controller::InvokeCommandRequest<chip::app::Clusters::OnOff::Commands::Off::Type>(chip::Messaging::ExchangeManager*, chip::SessionHandle const&, unsigned short, chip::app::Clusters::OnOff::Commands::Off::Type const&, chip::Controller::TypedCommandCallback<chip::app::Clusters::OnOff::Commands::Off::Type::ResponseType>::OnSuccessCallbackType, chip::Controller::TypedCommandCallback<chip::app::Clusters::OnOff::Commands::Off::Type::ResponseType>::OnErrorCallbackType, chip::Optional<unsigned short> const&, chip::Optional<std::__1::chrono::duration<unsigned int, std::__1::ratio<1l, 1000l> > > const&, std::__1::function<void ()>*)::{lambda()#1}::operator()() const
Unexecuted instantiation: chip::Controller::InvokeCommandRequest<chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::QueryImage::Type>(chip::Messaging::ExchangeManager*, chip::SessionHandle const&, unsigned short, chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::QueryImage::Type const&, chip::Controller::TypedCommandCallback<chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::QueryImage::Type::ResponseType>::OnSuccessCallbackType, chip::Controller::TypedCommandCallback<chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::QueryImage::Type::ResponseType>::OnErrorCallbackType, chip::Optional<unsigned short> const&, chip::Optional<std::__1::chrono::duration<unsigned int, std::__1::ratio<1l, 1000l> > > const&, std::__1::function<void ()>*)::{lambda()#1}::operator()() const
Unexecuted instantiation: chip::Controller::InvokeCommandRequest<chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::ApplyUpdateRequest::Type>(chip::Messaging::ExchangeManager*, chip::SessionHandle const&, unsigned short, chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::ApplyUpdateRequest::Type const&, chip::Controller::TypedCommandCallback<chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::ApplyUpdateRequest::Type::ResponseType>::OnSuccessCallbackType, chip::Controller::TypedCommandCallback<chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::ApplyUpdateRequest::Type::ResponseType>::OnErrorCallbackType, chip::Optional<unsigned short> const&, chip::Optional<std::__1::chrono::duration<unsigned int, std::__1::ratio<1l, 1000l> > > const&, std::__1::function<void ()>*)::{lambda()#1}::operator()() const
Unexecuted instantiation: chip::Controller::InvokeCommandRequest<chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::NotifyUpdateApplied::Type>(chip::Messaging::ExchangeManager*, chip::SessionHandle const&, unsigned short, chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::NotifyUpdateApplied::Type const&, chip::Controller::TypedCommandCallback<chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::NotifyUpdateApplied::Type::ResponseType>::OnSuccessCallbackType, chip::Controller::TypedCommandCallback<chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::NotifyUpdateApplied::Type::ResponseType>::OnErrorCallbackType, chip::Optional<unsigned short> const&, chip::Optional<std::__1::chrono::duration<unsigned int, std::__1::ratio<1l, 1000l> > > const&, std::__1::function<void ()>*)::{lambda()#1}::operator()() const
98
0
    }
99
100
    //
101
    // We've effectively transferred ownership of the above allocated objects to CommandSender, and we need to wait for it to call
102
    // us back when processing is completed (through OnDone) to eventually free up resources.
103
    //
104
    // So signal that by releasing the smart pointer.
105
    //
106
0
    decoder.release();
107
0
    commandSender.release();
108
109
0
    return CHIP_NO_ERROR;
110
0
}
Unexecuted instantiation: chip::ChipError chip::Controller::InvokeCommandRequest<chip::app::Clusters::OnOff::Commands::On::Type>(chip::Messaging::ExchangeManager*, chip::SessionHandle const&, unsigned short, chip::app::Clusters::OnOff::Commands::On::Type const&, chip::Controller::TypedCommandCallback<chip::app::Clusters::OnOff::Commands::On::Type::ResponseType>::OnSuccessCallbackType, chip::Controller::TypedCommandCallback<chip::app::Clusters::OnOff::Commands::On::Type::ResponseType>::OnErrorCallbackType, chip::Optional<unsigned short> const&, chip::Optional<std::__1::chrono::duration<unsigned int, std::__1::ratio<1l, 1000l> > > const&, std::__1::function<void ()>*)
Unexecuted instantiation: chip::ChipError chip::Controller::InvokeCommandRequest<chip::app::Clusters::OnOff::Commands::Off::Type>(chip::Messaging::ExchangeManager*, chip::SessionHandle const&, unsigned short, chip::app::Clusters::OnOff::Commands::Off::Type const&, chip::Controller::TypedCommandCallback<chip::app::Clusters::OnOff::Commands::Off::Type::ResponseType>::OnSuccessCallbackType, chip::Controller::TypedCommandCallback<chip::app::Clusters::OnOff::Commands::Off::Type::ResponseType>::OnErrorCallbackType, chip::Optional<unsigned short> const&, chip::Optional<std::__1::chrono::duration<unsigned int, std::__1::ratio<1l, 1000l> > > const&, std::__1::function<void ()>*)
Unexecuted instantiation: chip::ChipError chip::Controller::InvokeCommandRequest<chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::QueryImage::Type>(chip::Messaging::ExchangeManager*, chip::SessionHandle const&, unsigned short, chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::QueryImage::Type const&, chip::Controller::TypedCommandCallback<chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::QueryImage::Type::ResponseType>::OnSuccessCallbackType, chip::Controller::TypedCommandCallback<chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::QueryImage::Type::ResponseType>::OnErrorCallbackType, chip::Optional<unsigned short> const&, chip::Optional<std::__1::chrono::duration<unsigned int, std::__1::ratio<1l, 1000l> > > const&, std::__1::function<void ()>*)
Unexecuted instantiation: chip::ChipError chip::Controller::InvokeCommandRequest<chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::ApplyUpdateRequest::Type>(chip::Messaging::ExchangeManager*, chip::SessionHandle const&, unsigned short, chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::ApplyUpdateRequest::Type const&, chip::Controller::TypedCommandCallback<chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::ApplyUpdateRequest::Type::ResponseType>::OnSuccessCallbackType, chip::Controller::TypedCommandCallback<chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::ApplyUpdateRequest::Type::ResponseType>::OnErrorCallbackType, chip::Optional<unsigned short> const&, chip::Optional<std::__1::chrono::duration<unsigned int, std::__1::ratio<1l, 1000l> > > const&, std::__1::function<void ()>*)
Unexecuted instantiation: chip::ChipError chip::Controller::InvokeCommandRequest<chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::NotifyUpdateApplied::Type>(chip::Messaging::ExchangeManager*, chip::SessionHandle const&, unsigned short, chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::NotifyUpdateApplied::Type const&, chip::Controller::TypedCommandCallback<chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::NotifyUpdateApplied::Type::ResponseType>::OnSuccessCallbackType, chip::Controller::TypedCommandCallback<chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::NotifyUpdateApplied::Type::ResponseType>::OnErrorCallbackType, chip::Optional<unsigned short> const&, chip::Optional<std::__1::chrono::duration<unsigned int, std::__1::ratio<1l, 1000l> > > const&, std::__1::function<void ()>*)
111
112
/*
113
 * A typed group command invocation function that takes as input a cluster-object representation of a command request.
114
 *
115
 * The RequestObjectT is generally expected to be a ClusterName::Commands::CommandName::Type struct, but any object
116
 * that can be encoded using the DataModel::Encode machinery and exposes the GetClusterId() and GetCommandId() functions
117
 * and a ResponseType type is expected to work.
118
 *
119
 * Since this sends a group command, no response will be received and all allocated resources will be cleared before exiting this
120
 * function
121
 */
122
template <typename RequestObjectT>
123
CHIP_ERROR InvokeGroupCommandRequest(Messaging::ExchangeManager * exchangeMgr, chip::FabricIndex fabric, chip::GroupId groupId,
124
                                     const RequestObjectT & requestCommandData)
125
{
126
    app::CommandPathParams commandPath = { groupId, RequestObjectT::GetClusterId(), RequestObjectT::GetCommandId(),
127
                                           app::CommandPathFlags::kGroupIdValid };
128
    Transport::OutgoingGroupSession session(groupId, fabric);
129
130
    auto commandSender = chip::Platform::MakeUnique<app::CommandSender>(nullptr, exchangeMgr);
131
    VerifyOrReturnError(commandSender != nullptr, CHIP_ERROR_NO_MEMORY);
132
133
    ReturnErrorOnFailure(commandSender->AddRequestData(commandPath, requestCommandData));
134
    return commandSender->SendGroupCommandRequest(SessionHandle(session));
135
}
136
137
template <typename RequestObjectT>
138
CHIP_ERROR
139
InvokeCommandRequest(Messaging::ExchangeManager * exchangeMgr, const SessionHandle & sessionHandle, chip::EndpointId endpointId,
140
                     const RequestObjectT & requestCommandData,
141
                     typename TypedCommandCallback<typename RequestObjectT::ResponseType>::OnSuccessCallbackType onSuccessCb,
142
                     typename TypedCommandCallback<typename RequestObjectT::ResponseType>::OnErrorCallbackType onErrorCb,
143
                     uint16_t timedInvokeTimeoutMs, const Optional<System::Clock::Timeout> & responseTimeout = NullOptional)
144
{
145
    return InvokeCommandRequest(exchangeMgr, sessionHandle, endpointId, requestCommandData, onSuccessCb, onErrorCb,
146
                                MakeOptional(timedInvokeTimeoutMs), responseTimeout);
147
}
148
149
template <typename RequestObjectT, typename std::enable_if_t<!RequestObjectT::MustUseTimedInvoke(), int> = 0>
150
CHIP_ERROR
151
InvokeCommandRequest(Messaging::ExchangeManager * exchangeMgr, const SessionHandle & sessionHandle, chip::EndpointId endpointId,
152
                     const RequestObjectT & requestCommandData,
153
                     typename TypedCommandCallback<typename RequestObjectT::ResponseType>::OnSuccessCallbackType onSuccessCb,
154
                     typename TypedCommandCallback<typename RequestObjectT::ResponseType>::OnErrorCallbackType onErrorCb,
155
                     const Optional<System::Clock::Timeout> & responseTimeout = NullOptional)
156
0
{
157
0
    return InvokeCommandRequest(exchangeMgr, sessionHandle, endpointId, requestCommandData, onSuccessCb, onErrorCb, NullOptional,
158
0
                                responseTimeout);
159
0
}
Unexecuted instantiation: _ZN4chip10Controller20InvokeCommandRequestINS_3app8Clusters5OnOff8Commands2On4TypeETnNSt3__19enable_ifIXntclsrT_18MustUseTimedInvokeEEiE4typeELi0EEENS_9ChipErrorEPNS_9Messaging15ExchangeManagerERKNS_13SessionHandleEtRKSA_NS0_20TypedCommandCallbackINSA_12ResponseTypeEE21OnSuccessCallbackTypeENSO_19OnErrorCallbackTypeERKNS_8OptionalINS8_6chrono8durationIjNS8_5ratioILl1ELl1000EEEEEEE
Unexecuted instantiation: _ZN4chip10Controller20InvokeCommandRequestINS_3app8Clusters5OnOff8Commands3Off4TypeETnNSt3__19enable_ifIXntclsrT_18MustUseTimedInvokeEEiE4typeELi0EEENS_9ChipErrorEPNS_9Messaging15ExchangeManagerERKNS_13SessionHandleEtRKSA_NS0_20TypedCommandCallbackINSA_12ResponseTypeEE21OnSuccessCallbackTypeENSO_19OnErrorCallbackTypeERKNS_8OptionalINS8_6chrono8durationIjNS8_5ratioILl1ELl1000EEEEEEE
160
161
} // namespace Controller
162
} // namespace chip