Skip to content

Commit 57a5666

Browse files
committed
v0.9.180
1 parent b207e7a commit 57a5666

File tree

5 files changed

+550
-2
lines changed

5 files changed

+550
-2
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,9 @@ Work is in progress...
226226

227227
---
228228
## Version history
229+
#### v0.9.180
230+
- OneButton library moved to the project
231+
229232
#### v0.9.177
230233
- fixed bitrate display error when playing SD on VS1053B modules
231234

Lines changed: 333 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,333 @@
1+
/**
2+
* @file OneButton.cpp
3+
*
4+
* @brief Library for detecting button clicks, doubleclicks and long press
5+
* pattern on a single button.
6+
*
7+
* @author Matthias Hertel, https://www.mathertel.de
8+
* @Copyright Copyright (c) by Matthias Hertel, https://www.mathertel.de.
9+
*
10+
* This work is licensed under a BSD style license. See
11+
* http://www.mathertel.de/License.aspx
12+
*
13+
* More information on: https://www.mathertel.de/Arduino/OneButtonLibrary.aspx
14+
*
15+
* Changelog: see OneButton.h
16+
*/
17+
18+
#include "OneButton.h"
19+
20+
// ----- Initialization and Default Values -----
21+
22+
/**
23+
* @brief Construct a new OneButton object but not (yet) initialize the IO pin.
24+
*/
25+
OneButton::OneButton()
26+
{
27+
_pin = -1;
28+
// further initialization has moved to OneButton.h
29+
}
30+
31+
/**
32+
* Initialize the OneButton library.
33+
* @param pin The pin to be used for input from a momentary button.
34+
* @param activeLow Set to true when the input level is LOW when the button is pressed, Default is true.
35+
* @param pullupActive Activate the internal pullup when available. Default is true.
36+
*/
37+
OneButton::OneButton(const int pin, const boolean activeLow, const bool pullupActive)
38+
{
39+
// OneButton();
40+
_pin = pin;
41+
42+
if (activeLow) {
43+
// the button connects the input pin to GND when pressed.
44+
_buttonPressed = LOW;
45+
46+
} else {
47+
// the button connects the input pin to VCC when pressed.
48+
_buttonPressed = HIGH;
49+
} // if
50+
51+
if (pullupActive) {
52+
// use the given pin as input and activate internal PULLUP resistor.
53+
pinMode(pin, INPUT_PULLUP);
54+
} else {
55+
// use the given pin as input
56+
pinMode(pin, INPUT);
57+
} // if
58+
} // OneButton
59+
60+
61+
// explicitly set the number of millisec that have to pass by before a click is assumed stable.
62+
void OneButton::setDebounceTicks(const int ticks)
63+
{
64+
_debounceTicks = ticks;
65+
} // setDebounceTicks
66+
67+
68+
// explicitly set the number of millisec that have to pass by before a click is detected.
69+
void OneButton::setClickTicks(const int ticks)
70+
{
71+
_clickTicks = ticks;
72+
} // setClickTicks
73+
74+
75+
// explicitly set the number of millisec that have to pass by before a long button press is detected.
76+
void OneButton::setPressTicks(const int ticks)
77+
{
78+
_pressTicks = ticks;
79+
} // setPressTicks
80+
81+
82+
// save function for click event
83+
void OneButton::attachClick(callbackFunction newFunction)
84+
{
85+
_clickFunc = newFunction;
86+
} // attachClick
87+
88+
89+
// save function for parameterized click event
90+
void OneButton::attachClick(parameterizedCallbackFunction newFunction, void *parameter)
91+
{
92+
_paramClickFunc = newFunction;
93+
_clickFuncParam = parameter;
94+
} // attachClick
95+
96+
97+
// save function for doubleClick event
98+
void OneButton::attachDoubleClick(callbackFunction newFunction)
99+
{
100+
_doubleClickFunc = newFunction;
101+
_maxClicks = max(_maxClicks, 2);
102+
} // attachDoubleClick
103+
104+
105+
// save function for parameterized doubleClick event
106+
void OneButton::attachDoubleClick(parameterizedCallbackFunction newFunction, void *parameter)
107+
{
108+
_paramDoubleClickFunc = newFunction;
109+
_doubleClickFuncParam = parameter;
110+
_maxClicks = max(_maxClicks, 2);
111+
} // attachDoubleClick
112+
113+
114+
// save function for multiClick event
115+
void OneButton::attachMultiClick(callbackFunction newFunction)
116+
{
117+
_multiClickFunc = newFunction;
118+
_maxClicks = max(_maxClicks, 100);
119+
} // attachMultiClick
120+
121+
122+
// save function for parameterized MultiClick event
123+
void OneButton::attachMultiClick(parameterizedCallbackFunction newFunction, void *parameter)
124+
{
125+
_paramMultiClickFunc = newFunction;
126+
_multiClickFuncParam = parameter;
127+
_maxClicks = max(_maxClicks, 100);
128+
} // attachMultiClick
129+
130+
131+
// save function for longPressStart event
132+
void OneButton::attachLongPressStart(callbackFunction newFunction)
133+
{
134+
_longPressStartFunc = newFunction;
135+
} // attachLongPressStart
136+
137+
138+
// save function for parameterized longPressStart event
139+
void OneButton::attachLongPressStart(parameterizedCallbackFunction newFunction, void *parameter)
140+
{
141+
_paramLongPressStartFunc = newFunction;
142+
_longPressStartFuncParam = parameter;
143+
} // attachLongPressStart
144+
145+
146+
// save function for longPressStop event
147+
void OneButton::attachLongPressStop(callbackFunction newFunction)
148+
{
149+
_longPressStopFunc = newFunction;
150+
} // attachLongPressStop
151+
152+
153+
// save function for parameterized longPressStop event
154+
void OneButton::attachLongPressStop(parameterizedCallbackFunction newFunction, void *parameter)
155+
{
156+
_paramLongPressStopFunc = newFunction;
157+
_longPressStopFuncParam = parameter;
158+
} // attachLongPressStop
159+
160+
161+
// save function for during longPress event
162+
void OneButton::attachDuringLongPress(callbackFunction newFunction)
163+
{
164+
_duringLongPressFunc = newFunction;
165+
} // attachDuringLongPress
166+
167+
168+
// save function for parameterized during longPress event
169+
void OneButton::attachDuringLongPress(parameterizedCallbackFunction newFunction, void *parameter)
170+
{
171+
_paramDuringLongPressFunc = newFunction;
172+
_duringLongPressFuncParam = parameter;
173+
} // attachDuringLongPress
174+
175+
176+
void OneButton::reset(void)
177+
{
178+
_state = OneButton::OCS_INIT;
179+
_lastState = OneButton::OCS_INIT;
180+
_nClicks = 0;
181+
_startTime = 0;
182+
}
183+
184+
185+
// ShaggyDog ---- return number of clicks in any case: single or multiple clicks
186+
int OneButton::getNumberClicks(void)
187+
{
188+
return _nClicks;
189+
}
190+
191+
192+
/**
193+
* @brief Check input of the configured pin and then advance the finite state
194+
* machine (FSM).
195+
*/
196+
void OneButton::tick(void)
197+
{
198+
if (_pin >= 0) {
199+
tick(digitalRead(_pin) == _buttonPressed);
200+
}
201+
}
202+
203+
204+
/**
205+
* @brief Advance to a new state and save the last one to come back in cas of bouncing detection.
206+
*/
207+
void OneButton::_newState(stateMachine_t nextState)
208+
{
209+
_lastState = _state;
210+
_state = nextState;
211+
} // _newState()
212+
213+
214+
/**
215+
* @brief Run the finite state machine (FSM) using the given level.
216+
*/
217+
void OneButton::tick(bool activeLevel)
218+
{
219+
unsigned long now = millis(); // current (relative) time in msecs.
220+
unsigned long waitTime = (now - _startTime);
221+
222+
// Implementation of the state machine
223+
switch (_state) {
224+
case OneButton::OCS_INIT:
225+
// waiting for level to become active.
226+
if (activeLevel) {
227+
_newState(OneButton::OCS_DOWN);
228+
_startTime = now; // remember starting time
229+
_nClicks = 0;
230+
} // if
231+
break;
232+
233+
case OneButton::OCS_DOWN:
234+
// waiting for level to become inactive.
235+
236+
if ((!activeLevel) && (waitTime < _debounceTicks)) {
237+
// button was released to quickly so I assume some bouncing.
238+
_newState(_lastState);
239+
240+
} else if (!activeLevel) {
241+
_newState(OneButton::OCS_UP);
242+
_startTime = now; // remember starting time
243+
244+
} else if ((activeLevel) && (waitTime > _pressTicks)) {
245+
if (_longPressStartFunc) _longPressStartFunc();
246+
if (_paramLongPressStartFunc) _paramLongPressStartFunc(_longPressStartFuncParam);
247+
_newState(OneButton::OCS_PRESS);
248+
} // if
249+
break;
250+
251+
case OneButton::OCS_UP:
252+
// level is inactive
253+
254+
if ((activeLevel) && (waitTime < _debounceTicks)) {
255+
// button was pressed to quickly so I assume some bouncing.
256+
_newState(_lastState); // go back
257+
258+
} else if (waitTime >= _debounceTicks) {
259+
// count as a short button down
260+
_nClicks++;
261+
_newState(OneButton::OCS_COUNT);
262+
} // if
263+
break;
264+
265+
case OneButton::OCS_COUNT:
266+
// dobounce time is over, count clicks
267+
268+
if (activeLevel) {
269+
// button is down again
270+
_newState(OneButton::OCS_DOWN);
271+
_startTime = now; // remember starting time
272+
273+
} else if ((waitTime > _clickTicks) || (_nClicks == _maxClicks)) {
274+
// now we know how many clicks have been made.
275+
276+
if (_nClicks == 1) {
277+
// this was 1 click only.
278+
if (_clickFunc) _clickFunc();
279+
if (_paramClickFunc) _paramClickFunc(_clickFuncParam);
280+
281+
} else if (_nClicks == 2) {
282+
// this was a 2 click sequence.
283+
if (_doubleClickFunc) _doubleClickFunc();
284+
if (_paramDoubleClickFunc) _paramDoubleClickFunc(_doubleClickFuncParam);
285+
286+
} else {
287+
// this was a multi click sequence.
288+
if (_multiClickFunc) _multiClickFunc();
289+
if (_paramMultiClickFunc) _paramMultiClickFunc(_multiClickFuncParam);
290+
} // if
291+
292+
reset();
293+
} // if
294+
break;
295+
296+
case OneButton::OCS_PRESS:
297+
// waiting for menu pin being release after long press.
298+
299+
if (!activeLevel) {
300+
_newState(OneButton::OCS_PRESSEND);
301+
_startTime = now;
302+
303+
} else {
304+
// still the button is pressed
305+
if (_duringLongPressFunc) _duringLongPressFunc();
306+
if (_paramDuringLongPressFunc) _paramDuringLongPressFunc(_duringLongPressFuncParam);
307+
} // if
308+
break;
309+
310+
case OneButton::OCS_PRESSEND:
311+
// button was released.
312+
313+
if ((activeLevel) && (waitTime < _debounceTicks)) {
314+
// button was released to quickly so I assume some bouncing.
315+
_newState(_lastState); // go back
316+
317+
} else if (waitTime >= _debounceTicks) {
318+
if (_longPressStopFunc) _longPressStopFunc();
319+
if (_paramLongPressStopFunc) _paramLongPressStopFunc(_longPressStopFuncParam);
320+
reset();
321+
}
322+
break;
323+
324+
default:
325+
// unknown state detected -> reset state machine
326+
_newState(OneButton::OCS_INIT);
327+
break;
328+
} // if
329+
330+
} // OneButton.tick()
331+
332+
333+
// end.

0 commit comments

Comments
 (0)