Skip to content

Commit 59df5a8

Browse files
committed
Add TogglerCounter class
1 parent 86d01cb commit 59df5a8

2 files changed

Lines changed: 209 additions & 0 deletions

File tree

tests/debouncer_tests.cc

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
#include "doctest.h"
2+
#include "util/debouncer.hh"
3+
4+
TEST_CASE("TogglerCounter starts low with zero count and no events") {
5+
TogglerCounter t;
6+
7+
CHECK(t.is_high() == false);
8+
CHECK(t.is_pressed() == false);
9+
CHECK(bool(t) == false);
10+
CHECK(t.steady_state_count() == 0);
11+
CHECK(t.is_just_pressed() == false);
12+
CHECK(t.is_just_released() == false);
13+
}
14+
15+
TEST_CASE("TogglerCounter rising edge sets state and event, resets count") {
16+
TogglerCounter t;
17+
18+
t.process(1);
19+
CHECK(t.is_high() == true);
20+
CHECK(t.steady_state_count() == 0);
21+
CHECK(t.is_just_pressed() == true);
22+
CHECK(t.is_just_pressed() == false); // event clears after read
23+
CHECK(t.is_just_released() == false);
24+
}
25+
26+
TEST_CASE("TogglerCounter steady state increments count without events") {
27+
TogglerCounter t;
28+
29+
// staying low: count increments each call
30+
t.process(0);
31+
CHECK(t.steady_state_count() == 1);
32+
CHECK(t.is_just_pressed() == false);
33+
CHECK(t.is_just_released() == false);
34+
35+
t.process(0);
36+
CHECK(t.steady_state_count() == 2);
37+
38+
t.process(0);
39+
CHECK(t.steady_state_count() == 3);
40+
CHECK(t.is_high() == false);
41+
}
42+
43+
TEST_CASE("TogglerCounter falling edge resets count and fires event") {
44+
TogglerCounter t;
45+
46+
t.process(1);
47+
CHECK(t.steady_state_count() == 0);
48+
49+
t.process(1);
50+
t.process(1);
51+
CHECK(t.steady_state_count() == 2);
52+
53+
t.process(0);
54+
// Count reset:
55+
CHECK(t.steady_state_count() == 0);
56+
// Event fired:
57+
CHECK(t.is_just_released() == true);
58+
CHECK(t.is_just_released() == false);
59+
}
60+
61+
TEST_CASE("TogglerCounter count accumulates while steady high") {
62+
TogglerCounter t;
63+
64+
// Start with button pressed
65+
t.process(1);
66+
67+
for (unsigned i = 1; i <= 10; i++) {
68+
t.process(1);
69+
CHECK(t.steady_state_count() == i);
70+
}
71+
}
72+
73+
TEST_CASE("TogglerCounter count accumulates while steady low") {
74+
TogglerCounter t;
75+
76+
for (unsigned i = 1; i <= 10; i++) {
77+
t.process(0);
78+
CHECK(t.steady_state_count() == i);
79+
}
80+
}
81+
82+
TEST_CASE("TogglerCounter register_state mirrors process") {
83+
TogglerCounter t;
84+
85+
t.register_state(1);
86+
CHECK(t.is_high() == true);
87+
CHECK(t.steady_state_count() == 0);
88+
89+
t.register_state(1);
90+
CHECK(t.steady_state_count() == 1);
91+
92+
t.register_state(0);
93+
CHECK(t.is_high() == false);
94+
CHECK(t.steady_state_count() == 0);
95+
}
96+
97+
TEST_CASE("TogglerCounter reset_count clears count without affecting state") {
98+
TogglerCounter t;
99+
100+
t.process(1);
101+
t.process(1);
102+
t.process(1);
103+
t.process(1);
104+
CHECK(t.steady_state_count() == 3);
105+
CHECK(t.is_high() == true);
106+
107+
t.reset_count();
108+
CHECK(t.steady_state_count() == 0);
109+
CHECK(t.is_high() == true);
110+
111+
t.process(1);
112+
CHECK(t.steady_state_count() == 1);
113+
}
114+
115+
TEST_CASE("TogglerCounter reset clears state and events but not count") {
116+
TogglerCounter t;
117+
118+
t.process(1);
119+
t.process(1);
120+
CHECK(t.steady_state_count() == 1);
121+
122+
t.reset();
123+
CHECK(t.is_high() == false);
124+
CHECK(t.is_just_pressed() == false);
125+
CHECK(t.is_just_released() == false);
126+
127+
// after reset (state low) processing 0 increments steady count
128+
t.process(0);
129+
CHECK(t.steady_state_count() == 2);
130+
}
131+
132+
TEST_CASE("TogglerCounter clear_events does not change state or count") {
133+
TogglerCounter t;
134+
135+
t.process(1);
136+
CHECK(t.is_high() == true);
137+
138+
t.clear_events();
139+
CHECK(t.is_just_pressed() == false);
140+
CHECK(t.is_just_released() == false);
141+
CHECK(t.is_high() == true);
142+
143+
t.process(1);
144+
CHECK(t.steady_state_count() == 1);
145+
}
146+
147+
TEST_CASE("TogglerCounter alternating transitions reset count each edge") {
148+
TogglerCounter t;
149+
150+
t.process(1);
151+
CHECK(t.steady_state_count() == 0);
152+
CHECK(t.is_just_pressed() == true);
153+
154+
t.process(0);
155+
CHECK(t.steady_state_count() == 0);
156+
CHECK(t.is_just_released() == true);
157+
158+
t.process(1);
159+
CHECK(t.steady_state_count() == 0);
160+
CHECK(t.is_just_pressed() == true);
161+
162+
t.process(0);
163+
CHECK(t.steady_state_count() == 0);
164+
CHECK(t.is_just_released() == true);
165+
}
166+
167+
TEST_CASE("TogglerCounter is_just_pressed cleared after read across steady samples") {
168+
TogglerCounter t;
169+
170+
t.process(1);
171+
t.process(1);
172+
t.process(1);
173+
CHECK(t.is_just_pressed() == true);
174+
CHECK(t.is_just_pressed() == false);
175+
CHECK(t.steady_state_count() == 2);
176+
CHECK(t.is_high() == true);
177+
}

util/debouncer.hh

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,38 @@ public:
126126
}
127127
};
128128

129+
struct TogglerCounter : Toggler {
130+
void register_state(unsigned newstate) {
131+
if (newstate == is_high_) {
132+
steady_state_ctr++;
133+
return;
134+
}
135+
136+
is_high_ = newstate;
137+
steady_state_ctr = 0;
138+
139+
if (newstate)
140+
got_rising_edge_ = true;
141+
else
142+
got_falling_edge_ = true;
143+
}
144+
145+
unsigned steady_state_count() const {
146+
return steady_state_ctr;
147+
}
148+
149+
void reset_count() {
150+
steady_state_ctr = 0;
151+
}
152+
153+
void process(unsigned new_state) {
154+
register_state(new_state);
155+
}
156+
157+
private:
158+
unsigned steady_state_ctr = 0;
159+
};
160+
129161
template<unsigned RisingEdgePattern = 0x00000001,
130162
unsigned FallingEdgePattern = 0xFFFFFFFE,
131163
unsigned StateMask = 0x00000FFF>

0 commit comments

Comments
 (0)