1- // -----
2- // OneButton.cpp - Library for detecting button clicks, doubleclicks and long press pattern on a single button.
3- // This class is implemented for use with the Arduino environment.
4- // Copyright (c) by Matthias Hertel, http://www.mathertel.de
5- // This work is licensed under a BSD style license. See http://www.mathertel.de/License.aspx
6- // More information on: http://www.mathertel.de/Arduino
7- // -----
8- // Changelog: see OneButton.h
9- // -----
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+ */
1017
1118#include " OneButton.h"
1219
1320// ----- Initialization and Default Values -----
1421
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+
1531OneButton::OneButton (int pin, int activeLow, bool pullupActive)
1632{
33+ // OneButton();
1734 _pin = pin;
1835
19- _debounceTicks = 50 ; // number of millisec that have to pass by before a click is assumed as safe.
20- _clickTicks = 600 ; // number of millisec that have to pass by before a click is detected.
21- _pressTicks = 1000 ; // number of millisec that have to pass by before a long button press is detected.
22-
23- _state = 0 ; // starting with state 0: waiting for button to be pressed
24- _isLongPressed = false ; // Keep track of long press state
25-
2636 if (activeLow) {
2737 // the button connects the input pin to GND when pressed.
28- _buttonReleased = HIGH; // notPressed
2938 _buttonPressed = LOW;
3039
31- // use the given pin as input and activate internal PULLUP resistor.
32- if (pullupActive)
33- pinMode ( pin, INPUT_PULLUP );
34- else
35- pinMode ( pin, INPUT );
36-
3740 } else {
3841 // the button connects the input pin to VCC when pressed.
39- _buttonReleased = LOW;
4042 _buttonPressed = HIGH;
43+ } // if
4144
45+ if (pullupActive) {
46+ // use the given pin as input and activate internal PULLUP resistor.
47+ pinMode (pin, INPUT_PULLUP);
48+ } else {
4249 // use the given pin as input
4350 pinMode (pin, INPUT);
4451 } // if
45-
46- // no functions attached yet: clear all function pointers.
47- _clickFunc = NULL ;
48- _doubleClickFunc = NULL ;
49- _pressFunc = NULL ;
50- _longPressStartFunc = NULL ;
51- _longPressStopFunc = NULL ;
52- _duringLongPressFunc = NULL ;
5352} // OneButton
5453
5554
56- // explicitly set the number of millisec that have to pass by before a click is assumed as safe.
57- void OneButton::setDebounceTicks (int ticks) {
55+ // explicitly set the number of millisec that have to pass by before a click is
56+ // assumed as safe.
57+ void OneButton::setDebounceTicks (int ticks)
58+ {
5859 _debounceTicks = ticks;
5960} // setDebounceTicks
6061
61- // explicitly set the number of millisec that have to pass by before a click is detected.
62- void OneButton::setClickTicks (int ticks) {
62+ // explicitly set the number of millisec that have to pass by before a click is
63+ // detected.
64+ void OneButton::setClickTicks (int ticks)
65+ {
6366 _clickTicks = ticks;
6467} // setClickTicks
6568
6669
67- // explicitly set the number of millisec that have to pass by before a long button press is detected.
68- void OneButton::setPressTicks (int ticks) {
70+ // explicitly set the number of millisec that have to pass by before a long
71+ // button press is detected.
72+ void OneButton::setPressTicks (int ticks)
73+ {
6974 _pressTicks = ticks;
7075} // setPressTicks
7176
@@ -85,7 +90,8 @@ void OneButton::attachDoubleClick(callbackFunction newFunction)
8590
8691
8792// save function for press event
88- // DEPRECATED, is replaced by attachLongPressStart, attachLongPressStop, attachDuringLongPress,
93+ // DEPRECATED, is replaced by attachLongPressStart, attachLongPressStop,
94+ // attachDuringLongPress,
8995void OneButton::attachPress (callbackFunction newFunction)
9096{
9197 _pressFunc = newFunction;
@@ -125,73 +131,101 @@ void OneButton::reset(void){
125131 _isLongPressed = false ;
126132}
127133
134+
135+ /* *
136+ * @brief Check input of the configured pin and then advance the finite state
137+ * machine (FSM).
138+ */
128139void OneButton::tick (void )
129140{
130- // Detect the input information
131- int buttonLevel = digitalRead (_pin); // current button signal.
141+ if (_pin >= 0 ) {
142+ tick (digitalRead (_pin) == _buttonPressed);
143+ }
144+ }
145+
146+
147+ /* *
148+ * @brief Advance the finite state machine (FSM) using the given level.
149+ */
150+ void OneButton::tick (bool activeLevel)
151+ {
132152 unsigned long now = millis (); // current (relative) time in msecs.
133153
134154 // Implementation of the state machine
155+
135156 if (_state == 0 ) { // waiting for menu pin being pressed.
136- if (buttonLevel == _buttonPressed ) {
157+ if (activeLevel ) {
137158 _state = 1 ; // step to state 1
138159 _startTime = now; // remember starting time
139160 } // if
140161
141162 } else if (_state == 1 ) { // waiting for menu pin being released.
142163
143- if ((buttonLevel == _buttonReleased) && ((unsigned long )(now - _startTime) < _debounceTicks)) {
164+ if ((!activeLevel) &&
165+ ((unsigned long )(now - _startTime) < _debounceTicks)) {
144166 // button was released to quickly so I assume some debouncing.
145- // go back to state 0 without calling a function.
167+ // go back to state 0 without calling a function.
146168 _state = 0 ;
147169
148- } else if (buttonLevel == _buttonReleased ) {
170+ } else if (!activeLevel ) {
149171 _state = 2 ; // step to state 2
150172 _stopTime = now; // remember stopping time
151173
152- } else if ((buttonLevel == _buttonPressed) && ((unsigned long )(now - _startTime) > _pressTicks)) {
153- _isLongPressed = true ; // Keep track of long press state
154- if (_pressFunc) _pressFunc ();
155- if (_longPressStartFunc) _longPressStartFunc ();
156- if (_duringLongPressFunc) _duringLongPressFunc ();
174+ } else if ((activeLevel) &&
175+ ((unsigned long )(now - _startTime) > _pressTicks)) {
176+ _isLongPressed = true ; // Keep track of long press state
177+ if (_pressFunc)
178+ _pressFunc ();
179+ if (_longPressStartFunc)
180+ _longPressStartFunc ();
181+ if (_duringLongPressFunc)
182+ _duringLongPressFunc ();
157183 _state = 6 ; // step to state 6
158184 _stopTime = now; // remember stopping time
159185 } else {
160186 // wait. Stay in this state.
161187 } // if
162188
163- } else if (_state == 2 ) { // waiting for menu pin being pressed the second time or timeout.
164- if (_doubleClickFunc == NULL || (unsigned long )(now - _startTime) > _clickTicks) {
189+ } else if (_state == 2 ) {
190+ // waiting for menu pin being pressed the second time or timeout.
191+ if (_doubleClickFunc == NULL ||
192+ (unsigned long )(now - _startTime) > _clickTicks) {
165193 // this was only a single short click
166- if (_clickFunc) _clickFunc ();
194+ if (_clickFunc)
195+ _clickFunc ();
167196 _state = 0 ; // restart.
168197
169- } else if ((buttonLevel == _buttonPressed) && ((unsigned long )(now - _stopTime) > _debounceTicks)) {
198+ } else if ((activeLevel) &&
199+ ((unsigned long )(now - _stopTime) > _debounceTicks)) {
170200 _state = 3 ; // step to state 3
171201 _startTime = now; // remember starting time
172202 } // if
173203
174204 } else if (_state == 3 ) { // waiting for menu pin being released finally.
175- // Stay here for at least _debounceTicks because else we might end up in state 1 if the
176- // button bounces for too long.
177- if (buttonLevel == _buttonReleased && ((unsigned long )(now - _startTime) > _debounceTicks)) {
205+ // Stay here for at least _debounceTicks because else we might end up in
206+ // state 1 if the button bounces for too long.
207+ if ((!activeLevel) &&
208+ ((unsigned long )(now - _startTime) > _debounceTicks)) {
178209 // this was a 2 click sequence.
179- if (_doubleClickFunc) _doubleClickFunc ();
210+ if (_doubleClickFunc)
211+ _doubleClickFunc ();
180212 _state = 0 ; // restart.
181213 _stopTime = now; // remember stopping time
182-
183214 } // if
184215
185- } else if (_state == 6 ) { // waiting for menu pin being release after long press.
186- if (buttonLevel == _buttonReleased) {
187- _isLongPressed = false ; // Keep track of long press state
188- if (_longPressStopFunc) _longPressStopFunc ();
216+ } else if (_state == 6 ) {
217+ // waiting for menu pin being release after long press.
218+ if (!activeLevel) {
219+ _isLongPressed = false ; // Keep track of long press state
220+ if (_longPressStopFunc)
221+ _longPressStopFunc ();
189222 _state = 0 ; // restart.
190223 _stopTime = now; // remember stopping time
191224 } else {
192- // button is being long pressed
193- _isLongPressed = true ; // Keep track of long press state
194- if (_duringLongPressFunc) _duringLongPressFunc ();
225+ // button is being long pressed
226+ _isLongPressed = true ; // Keep track of long press state
227+ if (_duringLongPressFunc)
228+ _duringLongPressFunc ();
195229 } // if
196230
197231 } // if
0 commit comments