blob: 24db51b5d1b4d9c90286f6ad146f3d5ce5270862 [file] [log] [blame]
chrisdecenzo3c5b7ab2022-05-02 12:33:12 -07001/*
2 * Copyright (c) 2022 Project CHIP Authors
3 * All rights reserved.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 */
18
19#pragma once
20
21#include <app/CommandSender.h>
22#include <lib/support/UnitTestUtils.h>
23
24#include "DataModelLogger.h"
25#include "ModelCommand.h"
26
27class ClusterCommand : public ModelCommand, public chip::app::CommandSender::Callback
28{
29public:
30 ClusterCommand(CredentialIssuerCommands * credsIssuerConfig) : ModelCommand("command-by-id", credsIssuerConfig)
31 {
32 AddArgument("cluster-id", 0, UINT32_MAX, &mClusterId);
33 AddArgument("command-id", 0, UINT32_MAX, &mCommandId);
34 AddArgument("payload", &mPayload);
35 AddArgument("timedInteractionTimeoutMs", 0, UINT16_MAX, &mTimedInteractionTimeoutMs);
36 AddArgument("suppressResponse", 0, 1, &mSuppressResponse);
37 AddArgument("repeat-count", 1, UINT16_MAX, &mRepeatCount);
38 AddArgument("repeat-delay-ms", 0, UINT16_MAX, &mRepeatDelayInMs);
39 ModelCommand::AddArguments();
40 }
41
42 ClusterCommand(chip::ClusterId clusterId, CredentialIssuerCommands * credsIssuerConfig) :
43 ModelCommand("command-by-id", credsIssuerConfig), mClusterId(clusterId)
44 {
45 AddArgument("command-id", 0, UINT32_MAX, &mCommandId);
46 AddArgument("payload", &mPayload);
47 AddArgument("timedInteractionTimeoutMs", 0, UINT16_MAX, &mTimedInteractionTimeoutMs);
48 AddArgument("suppressResponse", 0, 1, &mSuppressResponse);
49 AddArgument("repeat-count", 1, UINT16_MAX, &mRepeatCount);
50 AddArgument("repeat-delay-ms", 0, UINT16_MAX, &mRepeatDelayInMs);
51 ModelCommand::AddArguments();
52 }
53
54 ClusterCommand(const char * commandName, CredentialIssuerCommands * credsIssuerConfig) :
55 ModelCommand(commandName, credsIssuerConfig)
56 {
57 AddArgument("timedInteractionTimeoutMs", 0, UINT16_MAX, &mTimedInteractionTimeoutMs);
58 AddArgument("suppressResponse", 0, 1, &mSuppressResponse);
59 AddArgument("repeat-count", 1, UINT16_MAX, &mRepeatCount);
60 AddArgument("repeat-delay-ms", 0, UINT16_MAX, &mRepeatDelayInMs);
61 }
62
63 ~ClusterCommand() {}
64
Vivien Nicolase8d58d12022-05-11 12:36:36 +020065 CHIP_ERROR SendCommand(chip::DeviceProxy * device, std::vector<chip::EndpointId> endpointIds) override
chrisdecenzo3c5b7ab2022-05-02 12:33:12 -070066 {
67 return ClusterCommand::SendCommand(device, endpointIds.at(0), mClusterId, mCommandId, mPayload);
68 }
69
70 CHIP_ERROR SendGroupCommand(chip::GroupId groupId, chip::FabricIndex fabricIndex) override
71 {
72 return ClusterCommand::SendGroupCommand(groupId, fabricIndex, mClusterId, mCommandId, mPayload);
73 }
74
75 /////////// CommandSender Callback Interface /////////
76 virtual void OnResponse(chip::app::CommandSender * client, const chip::app::ConcreteCommandPath & path,
77 const chip::app::StatusIB & status, chip::TLV::TLVReader * data) override
78 {
79 CHIP_ERROR error = status.ToChipError();
80 if (CHIP_NO_ERROR != error)
81 {
82 ChipLogError(chipTool, "Response Failure: %s", chip::ErrorStr(error));
83 mError = error;
84 return;
85 }
86
87 if (data != nullptr)
88 {
89 error = DataModelLogger::LogCommand(path, data);
90 if (CHIP_NO_ERROR != error)
91 {
92 ChipLogError(chipTool, "Response Failure: Can not decode Data");
93 mError = error;
94 return;
95 }
96 }
97 }
98
99 virtual void OnError(const chip::app::CommandSender * client, CHIP_ERROR error) override
100 {
101 ChipLogProgress(chipTool, "Error: %s", chip::ErrorStr(error));
102 mError = error;
103 }
104
105 virtual void OnDone(chip::app::CommandSender * client) override
106 {
107 mCommandSender.front().reset();
108 mCommandSender.erase(mCommandSender.begin());
109
110 // If the command is repeated N times, wait for all the responses to comes in
111 // before exiting.
112 bool shouldStop = true;
113 if (mRepeatCount.HasValue())
114 {
115 mRepeatCount.SetValue(static_cast<uint16_t>(mRepeatCount.Value() - 1));
116 shouldStop = mRepeatCount.Value() == 0;
117 }
118
119 if (shouldStop)
120 {
121 SetCommandExitStatus(mError);
122 }
123 }
124
125 template <class T>
Vivien Nicolase8d58d12022-05-11 12:36:36 +0200126 CHIP_ERROR SendCommand(chip::DeviceProxy * device, chip::EndpointId endpointId, chip::ClusterId clusterId,
127 chip::CommandId commandId, const T & value)
chrisdecenzo3c5b7ab2022-05-02 12:33:12 -0700128 {
129 uint16_t repeatCount = mRepeatCount.ValueOr(1);
130 while (repeatCount--)
131 {
132 chip::app::CommandPathParams commandPath = { endpointId, 0 /* groupId */, clusterId, commandId,
133 (chip::app::CommandPathFlags::kEndpointIdValid) };
134
135 auto commandSender = std::make_unique<chip::app::CommandSender>(this, device->GetExchangeManager(),
136 mTimedInteractionTimeoutMs.HasValue());
137 VerifyOrReturnError(commandSender != nullptr, CHIP_ERROR_NO_MEMORY);
138 ReturnErrorOnFailure(commandSender->AddRequestDataNoTimedCheck(commandPath, value, mTimedInteractionTimeoutMs,
139 mSuppressResponse.ValueOr(false)));
140
141 ReturnErrorOnFailure(commandSender->SendCommandRequest(device->GetSecureSession().Value()));
142 mCommandSender.push_back(std::move(commandSender));
143
144 if (mRepeatDelayInMs.HasValue())
145 {
146 chip::test_utils::SleepMillis(mRepeatDelayInMs.Value());
147 }
148 }
149 return CHIP_NO_ERROR;
150 }
151
152 template <class T>
153 CHIP_ERROR SendGroupCommand(chip::GroupId groupId, chip::FabricIndex fabricIndex, chip::ClusterId clusterId,
154 chip::CommandId commandId, const T & value)
155 {
156 chip::app::CommandPathParams commandPath = { 0 /* endpoint */, groupId, clusterId, commandId,
157 (chip::app::CommandPathFlags::kGroupIdValid) };
158
159 chip::Messaging::ExchangeManager * exchangeManager = chip::app::InteractionModelEngine::GetInstance()->GetExchangeManager();
160
161 auto commandSender =
162 chip::Platform::MakeUnique<chip::app::CommandSender>(this, exchangeManager, mTimedInteractionTimeoutMs.HasValue());
163 VerifyOrReturnError(commandSender != nullptr, CHIP_ERROR_NO_MEMORY);
164 ReturnErrorOnFailure(commandSender->AddRequestDataNoTimedCheck(commandPath, value, mTimedInteractionTimeoutMs));
165
166 chip::Transport::OutgoingGroupSession session(groupId, fabricIndex);
167 ReturnErrorOnFailure(commandSender->SendGroupCommandRequest(chip::SessionHandle(session)));
168 commandSender.release();
169
170 return CHIP_NO_ERROR;
171 }
172
173private:
174 chip::ClusterId mClusterId;
175 chip::CommandId mCommandId;
176 chip::Optional<uint16_t> mTimedInteractionTimeoutMs;
177 chip::Optional<bool> mSuppressResponse;
178 chip::Optional<uint16_t> mRepeatCount;
179 chip::Optional<uint16_t> mRepeatDelayInMs;
180
181 CHIP_ERROR mError = CHIP_NO_ERROR;
182 CustomArgument mPayload;
183 std::vector<std::unique_ptr<chip::app::CommandSender>> mCommandSender;
184};