blob: 0122eba4336340c5d665970350000362237d00e4 [file] [log] [blame]
Tennessee Carmel-Veilleuxc91a7792024-07-25 10:32:04 -04001/*
2 *
3 * Copyright (c) 2024 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#include "ButtonEventsSimulator.h"
20
21#include <functional>
22#include <inttypes.h>
23#include <stdint.h>
24#include <utility>
25
26#include <app-common/zap-generated/attributes/Accessors.h>
27#include <app-common/zap-generated/cluster-objects.h>
28#include <app/EventLogging.h>
29#include <lib/core/CHIPError.h>
30#include <lib/core/DataModelTypes.h>
31#include <lib/support/CodeUtils.h>
32#include <lib/support/logging/CHIPLogging.h>
33#include <platform/CHIPDeviceLayer.h>
34#include <system/SystemClock.h>
35#include <system/SystemLayer.h>
36
37namespace chip {
38namespace app {
39
40namespace {
41
42void SetButtonPosition(EndpointId endpointId, uint8_t position)
43{
44 Clusters::Switch::Attributes::CurrentPosition::Set(endpointId, position);
45}
46
47void EmitInitialPress(EndpointId endpointId, uint8_t newPosition)
48{
49 Clusters::Switch::Events::InitialPress::Type event{ newPosition };
50 EventNumber eventNumber = 0;
51
52 CHIP_ERROR err = LogEvent(event, endpointId, eventNumber);
53 if (err != CHIP_NO_ERROR)
54 {
55 ChipLogError(NotSpecified, "Failed to log InitialPress event: %" CHIP_ERROR_FORMAT, err.Format());
56 }
57 else
58 {
59 ChipLogProgress(NotSpecified, "Logged InitialPress(%u) on Endpoint %u", static_cast<unsigned>(newPosition),
60 static_cast<unsigned>(endpointId));
61 }
62}
63
64void EmitLongPress(EndpointId endpointId, uint8_t newPosition)
65{
66 Clusters::Switch::Events::LongPress::Type event{ newPosition };
67 EventNumber eventNumber = 0;
68
69 CHIP_ERROR err = LogEvent(event, endpointId, eventNumber);
70 if (err != CHIP_NO_ERROR)
71 {
72 ChipLogError(NotSpecified, "Failed to log LongPress event: %" CHIP_ERROR_FORMAT, err.Format());
73 }
74 else
75 {
76 ChipLogProgress(NotSpecified, "Logged LongPress(%u) on Endpoint %u", static_cast<unsigned>(newPosition),
77 static_cast<unsigned>(endpointId));
78 }
79}
80
81void EmitLongRelease(EndpointId endpointId, uint8_t previousPosition)
82{
83 Clusters::Switch::Events::LongRelease::Type event{};
84 event.previousPosition = previousPosition;
85 EventNumber eventNumber = 0;
86
87 CHIP_ERROR err = LogEvent(event, endpointId, eventNumber);
88 if (err != CHIP_NO_ERROR)
89 {
90 ChipLogError(NotSpecified, "Failed to log LongRelease event: %" CHIP_ERROR_FORMAT, err.Format());
91 }
92 else
93 {
94 ChipLogProgress(NotSpecified, "Logged LongRelease on Endpoint %u", static_cast<unsigned>(endpointId));
95 }
96}
97
98void EmitMultiPressComplete(EndpointId endpointId, uint8_t previousPosition, uint8_t count)
99{
100 Clusters::Switch::Events::MultiPressComplete::Type event{};
101 event.previousPosition = previousPosition;
102 event.totalNumberOfPressesCounted = count;
103 EventNumber eventNumber = 0;
104
105 CHIP_ERROR err = LogEvent(event, endpointId, eventNumber);
106 if (err != CHIP_NO_ERROR)
107 {
108 ChipLogError(NotSpecified, "Failed to log MultiPressComplete event: %" CHIP_ERROR_FORMAT, err.Format());
109 }
110 else
111 {
112 ChipLogProgress(NotSpecified, "Logged MultiPressComplete(count=%u) on Endpoint %u", static_cast<unsigned>(count),
113 static_cast<unsigned>(endpointId));
114 }
115}
116
C Freeman295ad532024-07-29 14:07:08 -0400117void EmitShortRelease(EndpointId endpointId, uint8_t previousPosition)
118{
119 Clusters::Switch::Events::ShortRelease::Type event{};
120 event.previousPosition = previousPosition;
121 EventNumber eventNumber = 0;
122
123 CHIP_ERROR err = LogEvent(event, endpointId, eventNumber);
124 if (err != CHIP_NO_ERROR)
125 {
126 ChipLogError(NotSpecified, "Failed to log ShortRelease event: %" CHIP_ERROR_FORMAT, err.Format());
127 }
128 else
129 {
130 ChipLogProgress(NotSpecified, "Logged ShortRelease on Endpoint %u", static_cast<unsigned>(endpointId));
131 }
132}
133
134void EmitMultiPressOngoing(EndpointId endpointId, uint8_t newPosition, uint8_t count)
135{
136 Clusters::Switch::Events::MultiPressOngoing::Type event{};
137 event.newPosition = newPosition;
138 event.currentNumberOfPressesCounted = count;
139 EventNumber eventNumber = 0;
140
141 CHIP_ERROR err = LogEvent(event, endpointId, eventNumber);
142 if (err != CHIP_NO_ERROR)
143 {
144 ChipLogError(NotSpecified, "Failed to log MultiPressOngoing event: %" CHIP_ERROR_FORMAT, err.Format());
145 }
146 else
147 {
148 ChipLogProgress(NotSpecified, "Logged MultiPressOngoing on Endpoint %u position %u, count %u",
149 static_cast<unsigned>(endpointId), newPosition, count);
150 }
151}
152
Tennessee Carmel-Veilleuxc91a7792024-07-25 10:32:04 -0400153} // namespace
154
155void ButtonEventsSimulator::OnTimerDone(System::Layer * layer, void * appState)
156{
157 ButtonEventsSimulator * that = reinterpret_cast<ButtonEventsSimulator *>(appState);
158 that->Next();
159}
160
161bool ButtonEventsSimulator::Execute(DoneCallback && doneCallback)
162{
163 VerifyOrReturnValue(mIdleButtonId != mPressedButtonId, false);
164
165 switch (mMode)
166 {
167 case Mode::kModeLongPress:
168 VerifyOrReturnValue(mLongPressDurationMillis > mLongPressDelayMillis, false);
169 SetState(State::kEmitStartOfLongPress);
170 break;
171 case Mode::kModeMultiPress:
172 VerifyOrReturnValue(mMultiPressPressedTimeMillis.count() > 0, false);
173 VerifyOrReturnValue(mMultiPressReleasedTimeMillis.count() > 0, false);
174 VerifyOrReturnValue(mMultiPressNumPresses > 0, false);
175 SetState(State::kEmitStartOfMultiPress);
176 break;
177 default:
178 return false;
179 }
180 mDoneCallback = std::move(doneCallback);
181 Next();
182 return true;
183}
184
185void ButtonEventsSimulator::SetState(ButtonEventsSimulator::State newState)
186{
187 ButtonEventsSimulator::State oldState = mState;
188 if (oldState != newState)
189 {
190 ChipLogProgress(NotSpecified, "ButtonEventsSimulator state change %u -> %u", static_cast<unsigned>(oldState),
191 static_cast<unsigned>(newState));
192 }
193
194 mState = newState;
195}
196
197void ButtonEventsSimulator::StartTimer(System::Clock::Timeout duration)
198{
199 chip::DeviceLayer::SystemLayer().StartTimer(duration, &ButtonEventsSimulator::OnTimerDone, this);
200}
201
202void ButtonEventsSimulator::Next()
203{
204 switch (mState)
205 {
206 case ButtonEventsSimulator::State::kIdle: {
207 ChipLogError(NotSpecified, "Found idle state where not expected!");
208 break;
209 }
210 case ButtonEventsSimulator::State::kEmitStartOfLongPress: {
211 SetButtonPosition(mEndpointId, mPressedButtonId);
212 EmitInitialPress(mEndpointId, mPressedButtonId);
213 SetState(ButtonEventsSimulator::State::kEmitLongPress);
214 StartTimer(mLongPressDelayMillis);
215 break;
216 }
217 case ButtonEventsSimulator::State::kEmitLongPress: {
218 EmitLongPress(mEndpointId, mPressedButtonId);
219 SetState(ButtonEventsSimulator::State::kEmitLongRelease);
220 StartTimer(mLongPressDurationMillis - mLongPressDelayMillis);
221 break;
222 }
223 case ButtonEventsSimulator::State::kEmitLongRelease: {
224 SetButtonPosition(mEndpointId, mIdleButtonId);
C Freeman295ad532024-07-29 14:07:08 -0400225 if (mFeatureMap & static_cast<uint32_t>(Clusters::Switch::Feature::kMomentarySwitchLongPress))
226 {
227 EmitLongRelease(mEndpointId, mPressedButtonId);
228 }
229 else if (mFeatureMap & static_cast<uint32_t>(Clusters::Switch::Feature::kMomentarySwitchRelease))
230 {
231 EmitShortRelease(mEndpointId, mPressedButtonId);
232 }
Tennessee Carmel-Veilleuxc91a7792024-07-25 10:32:04 -0400233 SetState(ButtonEventsSimulator::State::kIdle);
234 mDoneCallback();
235 break;
236 }
237 case ButtonEventsSimulator::State::kEmitStartOfMultiPress: {
Tennessee Carmel-Veilleux506d9732024-08-28 17:27:48 -0400238 SetButtonPosition(mEndpointId, mPressedButtonId);
Tennessee Carmel-Veilleuxc91a7792024-07-25 10:32:04 -0400239 EmitInitialPress(mEndpointId, mPressedButtonId);
C Freeman295ad532024-07-29 14:07:08 -0400240 if (mFeatureMap & static_cast<uint32_t>(Clusters::Switch::Feature::kActionSwitch))
241 {
242 StartTimer(mMultiPressNumPresses * (mMultiPressPressedTimeMillis + mMultiPressReleasedTimeMillis));
243 SetState(ButtonEventsSimulator::State::kEmitEndOfMultiPress);
244 }
245 else
246 {
247 SetState(ButtonEventsSimulator::State::kMultiPressButtonRelease);
248 StartTimer(mMultiPressPressedTimeMillis);
249 }
Tennessee Carmel-Veilleuxc91a7792024-07-25 10:32:04 -0400250 break;
251 }
C Freeman295ad532024-07-29 14:07:08 -0400252 case ButtonEventsSimulator::State::kMultiPressButtonRelease: {
253 ++mMultiPressPressesDone;
254 if (mMultiPressPressesDone > 1)
255 {
256 EmitMultiPressOngoing(mEndpointId, mPressedButtonId, mMultiPressPressesDone);
257 }
258
259 if (mMultiPressPressesDone == mMultiPressNumPresses)
260 {
261 SetState(ButtonEventsSimulator::State::kEmitEndOfMultiPress);
262 }
263 else
264 {
265 SetState(ButtonEventsSimulator::State::kEmitStartOfMultiPress);
266 }
267
268 if (mFeatureMap & static_cast<uint32_t>(Clusters::Switch::Feature::kMomentarySwitchRelease))
269 {
270 EmitShortRelease(mEndpointId, mPressedButtonId);
271 }
Tennessee Carmel-Veilleux506d9732024-08-28 17:27:48 -0400272 SetButtonPosition(mEndpointId, mIdleButtonId);
C Freeman295ad532024-07-29 14:07:08 -0400273 StartTimer(mMultiPressReleasedTimeMillis);
274 break;
275 }
276
Tennessee Carmel-Veilleuxc91a7792024-07-25 10:32:04 -0400277 case ButtonEventsSimulator::State::kEmitEndOfMultiPress: {
C Freeman295ad532024-07-29 14:07:08 -0400278 if (mFeatureMap & static_cast<uint32_t>(Clusters::Switch::Feature::kActionSwitch) && mMultiPressNumPresses > mMultiPressMax)
279 {
280 EmitMultiPressComplete(mEndpointId, mPressedButtonId, 0);
281 }
282 else
283 {
284 EmitMultiPressComplete(mEndpointId, mPressedButtonId, mMultiPressNumPresses);
285 }
Tennessee Carmel-Veilleuxc91a7792024-07-25 10:32:04 -0400286 SetState(ButtonEventsSimulator::State::kIdle);
287 mDoneCallback();
288 break;
289 }
290 }
291}
292
293} // namespace app
294} // namespace chip