AbleButtons V0.4.0
Lightweight button library for Arduino.
 
Loading...
Searching...
No Matches
Checks.cpp
Go to the documentation of this file.
1/**
2 * @file Checks.cpp Definition of check state of a button functions.
3 *
4 * @copyright Copyright (c) 2022 John Scott
5 */
6#include "Checks.h"
7#include "Utils.h"
8
9struct ButtonState btnState[NUM_BUTTONS]; ///< Previous state for each button.
10
11
12/**
13 * Check the state of an individual button just setup.
14 *
15 * @param btn The button to check.
16 */
18 // Given the button, when first setup, then it...
19 assert(btn->isPressed() == false); // ...is not pressed.
20
21# if TESTABLE_CLASS >= TESTABLE_BUTTON
22 assert(btn->isHeld() == false); // ...is not held.
23 assert(btn->isIdle() == false); // ...is not idle.
24#endif
25
26# if TESTABLE_CLASS >= TESTABLE_CLICKER
27 assert(btn->isClicked() == false); // ...is not clicked.
28# endif
29
30# if TESTABLE_CLASS >= TESTABLE_DOUBLECLICKER
31 assert(btn->isSingleClicked() == false); // ...is not exclusively clicked.
32 assert(btn->isDoubleClicked() == false); // ...is not double-clicked.
33# endif
34}
35
36
37/**
38 * Check state of a pressed button just pressed.
39 *
40 * @param btn The button to check.
41 */
43 // Given a button, when just pressed, then it...
44 assert(btn->isPressed() == true); // ...must be pressed.
45
46# if TESTABLE_CLASS >= TESTABLE_BUTTON
47 assert(btn->isHeld() == false); // ...cannot be held.
48 assert(btn->isIdle() == false); // ...cannot be idle.
49# endif
50
51# if TESTABLE_CLASS >= TESTABLE_CLICKER
52 assert(btn->isClicked() == false); // ...cannot be clicked.
53# endif
54
55# if TESTABLE_CLASS >= TESTABLE_DOUBLECLICKER
56 assert(btn->isSingleClicked() == false); // ...is not exclusively clicked.
57 assert(btn->isDoubleClicked() == false); // ...cannot be double-clicked.
58# endif
59}
60
61
62/**
63 * Check button that has just been released.
64 *
65 * @param btn The button to check.
66 */
68 // Given a button, when just released, then it...
69 assert(btn->isPressed() == false); // ...cannot be pressed.
70
71# if TESTABLE_CLASS >= TESTABLE_BUTTON
72 assert(btn->isHeld() == false); // ...cannot be held.
73 assert(btn->isIdle() == false); // ...cannot be idle.
74# endif
75
76# if TESTABLE_CLASS >= TESTABLE_CLICKER
77 assert(btn->isClicked() == true); // ...must be clicked.
78# endif
79
80# if TESTABLE_CLASS >= TESTABLE_DOUBLECLICKER
81 assert(btn->isSingleClicked() == false); // ...is not exclusively clicked.
82 // assert(btn->isDoubleClicked() == true); // ...*might* be double-clicked.
83# endif
84}
85
86
87/**
88 * Check button that has just been held.
89 *
90 * @param btn The button to check.
91 */
93 // Given a button, when it is held, then it...
94 assert(btn->isPressed() == true); // ...must be pressed.
95
96# if TESTABLE_CLASS >= TESTABLE_BUTTON
97 assert(btn->isHeld() == true); // ...must be held.
98 assert(btn->isIdle() == false); // ...cannot be idle.
99# endif
100
101# if TESTABLE_CLASS >= TESTABLE_CLICKER
102 assert(btn->isClicked() == false); // ...cannot be clicked.
103# endif
104
105# if TESTABLE_CLASS >= TESTABLE_DOUBLECLICKER
106 assert(btn->isSingleClicked() == false); // ...is not exclusively clicked.
107 assert(btn->isDoubleClicked() == false); // ...cannot be double-clicked.
108# endif
109}
110
111
112/**
113 * Check button that has just become or remains idle.
114 *
115 * @param btn The button to check.
116 */
118 // Given a button, when it is idle, then it...
119 assert(btn->isPressed() == false); // ...cannot be pressed.
120
121# if TESTABLE_CLASS >= TESTABLE_BUTTON
122 assert(btn->isHeld() == false); // ...cannot be held.
123 assert(btn->isIdle() == true); // ...will be idle.
124# endif
125
126# if TESTABLE_CLASS >= TESTABLE_CLICKER
127 assert(btn->isClicked() == false); // ...cannot be clicked.
128# endif
129
130# if TESTABLE_CLASS >= TESTABLE_DOUBLECLICKER
131 assert(btn->isSingleClicked() == false); // ...is not exclusively clicked.
132 assert(btn->isDoubleClicked() == false); // ...cannot be double-clicked.
133# endif
134}
135
136
137/**
138 * Check button that has just been clicked.
139 *
140 * @param btn The button to check.
141 */
143 // Given a button, when it just becomes clicked, then it...
144 assert(btn->isPressed() == false); // ...cannot be pressed.
145
146# if TESTABLE_CLASS >= TESTABLE_BUTTON
147 assert(btn->isHeld() == false); // ...cannot be held.
148 assert(btn->isIdle() == false); // ...cannot be idle.
149# endif
150
151# if TESTABLE_CLASS >= TESTABLE_CLICKER
152 assert(btn->isClicked() == true); // ...must be clicked.
153# endif
154
155# if TESTABLE_CLASS >= TESTABLE_DOUBLECLICKER
156 assert(btn->isSingleClicked() == false); // ...is not exclusively clicked.
157 // assert(btn->isDoubleClicked() == false); // ...*might* be double-clicked.
158# endif
159}
160
161
162/**
163 * Check button that has just been single-clicked.
164 *
165 * @param btn The button to check.
166 */
168 // Given a button, when it just becomes single-clicked, then it...
169 assert(btn->isPressed() == false); // ...cannot be pressed.
170}
171
172/**
173 * Check button that has just been double-clicked.
174 *
175 * @param btn The button to check.
176 */
178 // Given a button, when it just becomes double-clicked, then it...
179 assert(btn->isPressed() == false); // ...cannot be pressed.
180
181# if TESTABLE_CLASS >= TESTABLE_BUTTON
182 assert(btn->isHeld() == false); // ...cannot be held.
183 assert(btn->isIdle() == false); // ...cannot be idle.
184#endif
185
186# if TESTABLE_CLASS >= TESTABLE_CLICKER
187 assert(btn->isClicked() == true); // ...must be clicked.
188# endif
189
190# if TESTABLE_CLASS >= TESTABLE_DOUBLECLICKER
191 assert(btn->isSingleClicked() == false); // ...is not exclusively clicked.
192 assert(btn->isDoubleClicked() == true); // ...will be double-clicked.
193# endif
194}
195
196/**
197 * Check integrity of Button invariants (always hold true).
198 *
199 * @param btn The button to check.
200 * @param state The tracked state of the button for comparison.
201 */
202void checkButtonIntegrity(Button *btn, ButtonState &state) {
203 // Basic checks...
204 if(btn->isPressed()) {
205 // Given a pressed button...
206 if(!state.isPressed) {
207 // ...when it is just pressed, then...
209 } else {
210# if TESTABLE_CLASS >= TESTABLE_BUTTON
211 // ...when it is still pressed, then it...
212 // assert(btn->isHeld() == false); // ...*might* be held.
213 assert(btn->isIdle() == false); // ...cannot be idle.
214# endif
215
216# if TESTABLE_CLASS >= TESTABLE_CLICKER
217 assert(btn->isClicked() == false); // ...cannot be clicked.
218# endif
219
220# if TESTABLE_CLASS >= TESTABLE_DOUBLECLICKER
221 assert(btn->isSingleClicked() == false); // ...is not exclusively clicked.
222 assert(btn->isDoubleClicked() == false); // ...cannot double-clicked.
223# endif
224 }
225 } else {
226 // Given an unpressed button...
227 if(state.isPressed) {
228 // ...when it is just released, then...
230 } else {
231# if TESTABLE_CLASS >= TESTABLE_BUTTON
232 // ...when it is still released, then it...
233 assert(btn->isHeld() == false); // ...cannot be held.
234 // assert(btn->isIdle() == false); // ...*might* be idle.
235# endif
236
237# if TESTABLE_CLASS >= TESTABLE_CLICKER
238 // assert(btn->isClicked() == false); // ...*might* be clicked.
239# endif
240
241# if TESTABLE_CLASS >= TESTABLE_DOUBLECLICKER
242 assert(btn->isDoubleClicked() == false); // ...cannot double-clicked.
243# endif
244 }
245 }
246
247
248# if TESTABLE_CLASS >= TESTABLE_BUTTON
249 if(!state.isHeld && btn->isHeld()) {
250 // Given a button that has just become held, then...
252 }
253
254 if(!state.isIdle && btn->isIdle()) {
255 // Given a button that has just become idle, then...
257 }
258# endif
259
260 // Clickable checks...
261# if TESTABLE_CLASS >= TESTABLE_CLICKER
262 if(!state.isClicked && btn->isClicked()) {
263 // Given a button that has just been clicked, then...
265 }
266# endif
267
268 // Double clicker checks...
269# if TESTABLE_CLASS >= TESTABLE_DOUBLECLICKER
270 if(!state.isSingleClicked && btn->isSingleClicked()) {
271 // given a button that has just been double-clicked, then...
273 }
274
275 if(!state.isDoubleClicked && btn->isDoubleClicked()) {
276 // given a button that has just been double-clicked, then...
278 }
279# endif
280}
281
282
283/**
284 * Check integrity of ButtonList invariants (always hold true).
285 */
287 // ButtonList::all*() accessors...
289
290# if TESTABLE_CLASS >= TESTABLE_BUTTON
291 // Because isHeld and isIdle use millis() timings, the state can change
292 // whilst checking ButtonList::allHeld/Idle and each Button:isHeld/Idle. So
293 // checking each twice ensures if the first check is false, it tries once
294 // more. Only if both comparisons are false means we have a problem...
295 assert(
296 (btnList.allHeld() == (btnA.isHeld() && btnB.isHeld())) ||
297 (btnList.allHeld() == (btnA.isHeld() && btnB.isHeld()))
298 );
299 assert(
300 (btnList.allIdle() == (btnA.isIdle() && btnB.isIdle())) ||
301 (btnList.allIdle() == (btnA.isIdle() && btnB.isIdle()))
302 );
303# endif
304
305# if TESTABLE_CLASS >= TESTABLE_CLICKER
307# endif
308
309# if TESTABLE_CLASS >= TESTABLE_DOUBLECLICKER
312# endif
313
314 // ButtonList::any*() accessors...
316
317# if TESTABLE_CLASS >= TESTABLE_BUTTON
318 // Because isHeld and isIdle use millis() timings, the state can change
319 // whilst checking ButtonList::anyHeld/Idle and each Button:isHeld/Idle. So
320 // checking each twice ensures if the first check is false, it tries once
321 // more. Only if both comparisons are false means we have a problem...
322 assert(
323 (btnList.anyHeld() == (btnA.isHeld() || btnB.isHeld())) ||
324 (btnList.anyHeld() == (btnA.isHeld() || btnB.isHeld()))
325 );
326 assert(
327 (btnList.anyIdle() == (btnA.isIdle() || btnB.isIdle())) ||
328 (btnList.anyIdle() == (btnA.isIdle() || btnB.isIdle()))
329 );
330# endif
331
332# if TESTABLE_CLASS >= TESTABLE_CLICKER
334# endif
335
336# if TESTABLE_CLASS >= TESTABLE_DOUBLECLICKER
338# endif
339}
340
341
342/**
343 * Display button changes to Serial.
344 *
345 * @param index Which button in the button list to check.
346 */
347void displayButtonChanges(int index) {
348 Button *btn = btns[index];
349 ButtonState &state(btnState[index]);
350
351 // Basic checks...
352 if(btn->isPressed()) {
353 if(!state.isPressed) {
354 Serial << F("Button btns[") << index << F("] (btn") << (char)('A' + index) << F(") pressed") << endl;
355 }
356 state.isPressed = true;
357 } else {
358 if(state.isPressed) {
359 Serial << F("Button btns[") << index << F("] (btn") << (char)('A' + index) << F(") released") << endl;
360 }
361 state.isPressed = false;
362 }
363
364# if TESTABLE_CLASS >= TESTABLE_BUTTON
365 if(btn->isHeld()) {
366 if(!state.isHeld) {
367 Serial << F("Button btns[") << index << F("] (btn") << (char)('A' + index) << F(") held") << endl;
368 }
369 state.isHeld = true;
370 } else {
371 if(state.isHeld) {
372 Serial << F("Button btns[") << index << F("] (btn") << (char)('A' + index) << F(") un-held") << endl;
373 }
374 state.isHeld = false;
375 }
376
377 if(btn->isIdle()) {
378 if(!state.isIdle) {
379 Serial << F("Button btns[") << index << F("] (btn") << (char)('A' + index) << F(") idle") << endl;
380 }
381 state.isIdle = true;
382 } else {
383 if(state.isIdle) {
384 Serial << F("Button btns[") << index << F("] (btn") << (char)('A' + index) << F(") un-idle") << endl;
385 }
386 state.isIdle = false;
387 }
388# endif
389
390 // Clickable checks...
391# if TESTABLE_CLASS >= TESTABLE_CLICKER
392 if(btn->isClicked()) {
393 if(!state.isClicked) {
394 Serial << F("Button btns[") << index << F("] (btn") << (char)('A' + index) << F(") clicked") << endl;
395 }
396 state.isClicked = true;
397 } else if(state.isClicked) {
398 state.isClicked = false;
399 }
400# endif
401
402 // Double clicker checks...
403# if TESTABLE_CLASS >= TESTABLE_DOUBLECLICKER
404 if(!state.isDoubleClicked && btn->isDoubleClicked()) {
405 Serial << F("Button btns[") << index << F("] (btn") << (char)('A' + index) << F(") double-clicked") << endl;
406 state.isDoubleClicked = true;
407 } else {
408 state.isDoubleClicked = false;
409 }
410# endif
411}
Button btn(BUTTON_PIN)
The button to check.
Button * btns[]
Array of buttons for ButtonList.
ButtonList btnList(btns)
List of button to control together.
Button btnA(BUTTON_A_PIN)
Primary button.
Button btnB(BUTTON_B_PIN)
Secondary button.
void checkButtonJustSingleClicked(Button *btn)
Check button that has just been single-clicked.
Definition: Checks.cpp:167
void checkButtonJustClicked(Button *btn)
Check button that has just been clicked.
Definition: Checks.cpp:142
void checkButtonListIntegrity()
Check integrity of ButtonList invariants (always hold true).
Definition: Checks.cpp:286
void checkButtonJustReleased(Button *btn)
Check button that has just been released.
Definition: Checks.cpp:67
void checkButtonJustHeld(Button *btn)
Check button that has just been held.
Definition: Checks.cpp:92
void checkButtonIntegrity(Button *btn, ButtonState &state)
Check integrity of Button invariants (always hold true).
Definition: Checks.cpp:202
void checkButtonJustIdle(Button *btn)
Check button that has just become or remains idle.
Definition: Checks.cpp:117
void checkButtonSetup(Button *btn)
Check the state of an individual button just setup.
Definition: Checks.cpp:17
void displayButtonChanges(int index)
Display button changes to Serial.
Definition: Checks.cpp:347
struct ButtonState btnState[NUM_BUTTONS]
Previous state for each button.
Definition: Checks.cpp:9
void checkButtonJustDoubleClicked(Button *btn)
Check button that has just been double-clicked.
Definition: Checks.cpp:177
void checkButtonJustPressed(Button *btn)
Check state of a pressed button just pressed.
Definition: Checks.cpp:42
Declarations for the Checks module.
#define NUM_BUTTONS
The number of buttons to connect for testing.
Definition: Config.h:13
Utility function declarations.
#define assert(e)
Macro to assert using FlashStringHelper to reduce memory usage.
Definition: Utils.h:30
endl
Special type to allow Serial << endl to print a line and flush the stream.
Definition: Utils.h:45
Core Button class.
Definition: Button.h:22
bool isClicked() const
Determine if the button is clicked.
Definition: Button.h:156
bool isHeld() const
Determine if the button is currently held down.
Definition: Button.h:136
bool isIdle() const
Determine if the button is currently idle (unpressed for a "long" time).
Definition: Button.h:145
bool isSingleClicked() const
Determine if the button is exclusively single-clicked.
Definition: Button.h:170
bool isDoubleClicked() const
Determine if the button is double-clicked.
Definition: Button.h:182
bool isPressed() const
Determine if the button is currently pressed.
Definition: Button.h:127
bool allSingleClicked() const
Determine if all of the buttons have been single-clicked.
Definition: ButtonList.h:304
bool allDoubleClicked() const
Determine if all of the buttons have been double-clicked.
Definition: ButtonList.h:274
bool allPressed() const
Determine if all of the buttons are currently pressed.
Definition: ButtonList.h:154
bool anyHeld() const
Determine if any of the buttons are currently held.
Definition: ButtonList.h:199
bool allHeld() const
Determine if all of the buttons are currently held.
Definition: ButtonList.h:184
bool anyDoubleClicked() const
Determine if any of the buttons have been double-clicked.
Definition: ButtonList.h:289
bool anyClicked() const
Determine if all of the buttons have been clicked.
Definition: ButtonList.h:259
bool anyPressed() const
Determine if any of the buttons are currently pressed.
Definition: ButtonList.h:169
bool anyIdle() const
Determine if any of the buttons are currently idle.
Definition: ButtonList.h:229
bool allIdle() const
Determine if all of the buttons are currently idle.
Definition: ButtonList.h:214
bool allClicked() const
Determine if all of the buttons have been clicked.
Definition: ButtonList.h:244