-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathPBtnToggleBase.cpp
More file actions
243 lines (220 loc) · 7.1 KB
/
PBtnToggleBase.cpp
File metadata and controls
243 lines (220 loc) · 7.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
#include "PBtnToggleBase.h"
// PBtnToggleBase::state_ bit values:
// 0 - pressed, timer started
// 1 - onPress triggered
// 2 - onLongPress triggered
// 3 - onRelease triggered
// 4 - check running
// 5 - pressed button state
// 6 - last button state
// 7 - last event was long press, ignore next release, then press ad clear on press
/**
* Create button instance
*
* @param btn_pin Pin where button is wired
* @param pressed_state Pin state when button is pressed. Value LOW or HIGH depends on wiring.
*/
PBtnToggleBase::PBtnToggleBase(int btn_pin, int pressed_state) {
PBtnToggleBase::btn_ = btn_pin;
PBtnToggleBase::state_ = B00000000;
state_pressed_on_high_(pressed_state==HIGH);
PBtnToggleBase::on_press_callback_ = NULL;
PBtnToggleBase::on_long_press_callback_ = NULL;
PBtnToggleBase::on_release_callback_ = NULL;
PBtnToggleBase::timer_ = millis();
}
/**
* Set optional callback function to be called on button press event
*
* @param callback Callback function pointer
*/
void PBtnToggleBase::onPress(ToggleFunc callback) {
PBtnToggleBase::on_press_callback_ = callback;
}
/**
* Set optional callback function to be called on button long press event
*
* @param callback Callback function pointer
*/
void PBtnToggleBase::onLongPress(LongPressFunc callback) {
PBtnToggleBase::on_long_press_callback_ = callback;
}
/**
* Set optional callback function to be called on button release event
*
* @param callback Callback function pointer
*/
void PBtnToggleBase::onRelease(ToggleFunc callback) {
PBtnToggleBase::on_release_callback_ = callback;
}
void PBtnToggleBase::trigger_events_(bool btn_pressed) {
if (btn_pressed) {
// button pressed, trigger press event if not triggered already
if (!state_press_triggered_()) {
// if last event was long press, then do not trigger this press event
if (!state_longpress_triggered_() && PBtnToggleBase::on_press_callback_) {
PBtnToggleBase::on_press_callback_(PBtnToggleBase::btn_, state_pressed_on_high_()?HIGH:LOW);
}
// if no long press event callback set, then stop press timer
if (!PBtnToggleBase::on_long_press_callback_) {
state_press_timer_started_(false);
}
state_press_triggered_(true);
state_longpress_triggered_(false);
state_release_triggered_(false);
PBtnToggleBase::timer_ = millis();
}
// longpress event callback set but not triggered, button press period reached long press state
if (PBtnToggleBase::on_long_press_callback_ && !state_longpress_triggered_() && PBtnToggleBase::timer_ + PBTNTOGGLEBASE_LONGCLICK_TIME < millis()) {
bool noSkip = PBtnToggleBase::on_long_press_callback_(PBtnToggleBase::btn_, state_pressed_on_high_()?HIGH:LOW);
// if long press callback returns true, then set longpress event status as triggered, this will make button release not to trigger release event
if (noSkip) {
state_press_triggered_(false);
state_longpress_triggered_(true);
state_release_triggered_(false);
}
state_press_timer_started_(false);
}
} else {
// if no press or longpress triggered before, then stop timer
if (!state_press_triggered_() && !state_longpress_triggered_()) {
state_press_timer_started_(false);
return;
}
// trigger release
if (!state_release_triggered_() && !state_longpress_triggered_() && state_press_triggered_()) {
if (PBtnToggleBase::on_release_callback_) {
PBtnToggleBase::on_release_callback_(PBtnToggleBase::btn_, !state_pressed_on_high_()?HIGH:LOW);
}
state_press_timer_started_(false);
state_press_triggered_(false);
state_longpress_triggered_(false);
state_release_triggered_(true);
}
}
}
/**
* Check button state and trigger event callback functions. This method must be called in loop()
*/
void PBtnToggleBase::check() {
if (state_is_running_()) {
return;
}
state_is_running_(true);
// get current button state
bool btn_pressed = this->is_btn_pressed_();
// has state changed during last check
bool btn_state_changed = btn_pressed != state_was_button_pressed_();
state_was_button_pressed_(btn_pressed);
// trigger event if debounce time is passed
if (!btn_state_changed && PBtnToggleBase::timer_ + PBTNTOGGLEBASE_CLICK_DEBOUNCE_TIME < millis() && state_press_timer_started_()) {
PBtnToggleBase::trigger_events_(btn_pressed);
}
// reset timer if state has changed
if (btn_state_changed) {
PBtnToggleBase::timer_ = millis();
state_press_timer_started_(true);
}
state_is_running_(false);
}
/**
* Get pin number
*/
int PBtnToggleBase::getPin() {
return this->btn_;
}
/**
* Check if initial
*/
bool PBtnToggleBase::state_press_timer_started_() {
return bitRead(PBtnToggleBase::state_, 0) == 1;
}
/**
* Set current running state
*/
void PBtnToggleBase::state_press_timer_started_(bool set) {
state_set_state_(set, 0);
}
/**
* Check if press event triggered
*/
bool PBtnToggleBase::state_press_triggered_() {
return bitRead(PBtnToggleBase::state_, 1) == 1;
}
/**
* Set press event trigger status
*/
void PBtnToggleBase::state_press_triggered_(bool set) {
state_set_state_(set, 1);
}
/**
* Check if long press event triggered
*/
bool PBtnToggleBase::state_longpress_triggered_() {
return bitRead(PBtnToggleBase::state_, 2) == 1;
}
/**
* Set long press event trigger status
*/
void PBtnToggleBase::state_longpress_triggered_(bool set) {
state_set_state_(set, 2);
}
/**
* Check if release event triggered
*/
bool PBtnToggleBase::state_release_triggered_() {
return bitRead(PBtnToggleBase::state_, 3) == 1;
}
/**
* Set release event trigger status
*/
void PBtnToggleBase::state_release_triggered_(bool set) {
state_set_state_(set, 3);
}
/**
* Check if button check() is currently running
*/
bool PBtnToggleBase::state_is_running_() {
return bitRead(PBtnToggleBase::state_, 4) == 1;
}
/**
* Set current running state
*/
void PBtnToggleBase::state_is_running_(bool set) {
state_set_state_(set, 4);
}
/**
* Get pin state on button press
*/
bool PBtnToggleBase::state_pressed_on_high_() {
return bitRead(PBtnToggleBase::state_, 5) == 1;
}
/**
* Set pin state in button press
*/
void PBtnToggleBase::state_pressed_on_high_(bool set) {
state_set_state_(set, 5);
}
/**
* Get button pressed status on last check
*/
bool PBtnToggleBase::state_was_button_pressed_() {
return bitRead(PBtnToggleBase::state_, 6) == 1;
}
/**
* Set button pressed status for next check
* Used to detect if button pressed status is changed
*/
void PBtnToggleBase::state_was_button_pressed_(bool set) {
state_set_state_(set, 6);
}
/**
* Common method for setting state bit value
*/
void PBtnToggleBase::state_set_state_(bool set, int bit) {
if (set) {
bitSet(PBtnToggleBase::state_, bit);
} else {
bitClear(PBtnToggleBase::state_, bit);
}
}