RSeries astromech firmware
PushButton.h
Go to the documentation of this file.
1 
2 #ifndef PushButton_h
3 #define PushButton_h
4 
5 #include "ReelTwo.h"
6 #include "core/SetupEvent.h"
7 #include "core/AnimatedEvent.h"
8 
10 {
11 public:
12  typedef void (*CallbackFunction)(void);
13  typedef void (*ParameterizedCallbackFunction)(void *);
14 
21  PushButton(const int pin, const bool activeLow = true, const bool pullupActive = true) :
22  fPin(pin),
23  fButtonPressed(activeLow ? LOW : HIGH),
24  fPullup(pullupActive)
25  {
26  }
27 
28  // ----- Set runtime parameters -----
29 
33  void setDebounceTicks(const int ticks)
34  {
35  fDebounceTicks = ticks;
36  }
37 
41  void setClickTicks(const int ticks)
42  {
43  fClickTicks = ticks;
44  }
45 
49  void setPressTicks(const int ticks)
50  {
51  fPressTicks = ticks;
52  }
53 
59  {
60  fClickFunc = callback;
61  }
62 
67  void attachClick(ParameterizedCallbackFunction callback, void *param)
68  {
69  fParamClickFunc = callback;
70  fClickFuncParam = param;
71  }
72 
78  {
79  fDoubleClickFunc = callback;
80  fMaxClicks = max(fMaxClicks, 2);
81  }
82 
88  {
89  fParamDoubleClickFunc = callback;
90  fDoubleClickFuncParam = param;
91  fMaxClicks = max(fMaxClicks, 2);
92  }
93 
99  {
100  fMultiClickFunc = callback;
101  fMaxClicks = max(fMaxClicks, 100);
102  }
103 
109  {
110  fParamMultiClickFunc = callback;
111  fMultiClickFuncParam = param;
112  fMaxClicks = max(fMaxClicks, 100);
113  }
114 
120  {
121  fLongPressStartFunc = callback;
122  }
123 
129  {
130  fParamLongPressStartFunc = callback;
131  fLongPressStartFuncParam = param;
132  }
133 
139  {
140  fLongPressStopFunc = callback;
141  }
142 
148  {
149  fParamLongPressStopFunc = callback;
150  fLongPressStopFuncParam = param;
151  }
152 
158  {
159  fDuringLongPressFunc = callback;
160  }
161 
167  {
168  fParamDuringLongPressFunc = callback;
169  fDuringLongPressFuncParam = param;
170  }
171 
172  virtual void setup() override
173  {
174  if (fPullup)
175  {
176  // use the given pin as input and activate internal PULLUP resistor.
177  pinMode(fPin, INPUT_PULLUP);
178  }
179  else
180  {
181  // use the given pin as input
182  pinMode(fPin, INPUT);
183  }
184  }
185 
189  virtual void animate() override
190  {
191  unsigned long now = millis(); // current (relative) time in msecs.
192  unsigned long waitTime = (now - fStartTime);
193 
194  bool activeLevel = (digitalRead(fPin) == fButtonPressed);
195  switch (fState)
196  {
197  case kPB_INIT:
198  // waiting for level to become active.
199  if (activeLevel)
200  {
201  newState(kPB_DOWN);
202  fStartTime = now; // remember starting time
203  fNClicks = 0;
204  }
205  break;
206 
207  case kPB_DOWN:
208  // waiting for level to become inactive.
209 
210  if ((!activeLevel) && (waitTime < fDebounceTicks))
211  {
212  // button was released to quickly so I assume some bouncing.
213  newState(fLastState);
214  }
215  else if (!activeLevel)
216  {
217  newState(kPB_UP);
218  fStartTime = now; // remember starting time
219  }
220  else if ((activeLevel) && (waitTime > fPressTicks))
221  {
222  if (fLongPressStartFunc)
223  fLongPressStartFunc();
224  if (fParamLongPressStartFunc)
225  fParamLongPressStartFunc(fLongPressStartFuncParam);
226  newState(kPB_PRESS);
227  }
228  break;
229 
230  case kPB_UP:
231  // level is inactive
232  if ((activeLevel) && (waitTime < fDebounceTicks))
233  {
234  // button was pressed to quickly so I assume some bouncing.
235  newState(fLastState); // go back
236  }
237  else if (waitTime >= fDebounceTicks)
238  {
239  // count as a short button down
240  fNClicks++;
241  newState(kPB_COUNT);
242  } // if
243  break;
244 
245  case kPB_COUNT:
246  // dobounce time is over, count clicks
247  if (activeLevel)
248  {
249  // button is down again
250  newState(kPB_DOWN);
251  fStartTime = now; // remember starting time
252  }
253  else if ((waitTime > fClickTicks) || (fNClicks == fMaxClicks))
254  {
255  // now we know how many clicks have been made.
256  if (fNClicks == 1)
257  {
258  // this was 1 click only.
259  if (fClickFunc)
260  fClickFunc();
261  if (fParamClickFunc)
262  fParamClickFunc(fClickFuncParam);
263  }
264  else if (fNClicks == 2)
265  {
266  // this was a 2 click sequence.
267  if (fDoubleClickFunc)
268  fDoubleClickFunc();
269  if (fParamDoubleClickFunc)
270  fParamDoubleClickFunc(fDoubleClickFuncParam);
271  }
272  else
273  {
274  // this was a multi click sequence.
275  if (fMultiClickFunc)
276  fMultiClickFunc();
277  if (fParamMultiClickFunc)
278  fParamMultiClickFunc(fMultiClickFuncParam);
279  }
280  reset();
281  }
282  break;
283 
284  case kPB_PRESS:
285  // waiting for menu pin being release after long press.
286  if (!activeLevel)
287  {
288  newState(kPB_PRESSEND);
289  fStartTime = now;
290  }
291  else
292  {
293  // still the button is pressed
294  if (fDuringLongPressFunc)
295  fDuringLongPressFunc();
296  if (fParamDuringLongPressFunc)
297  fParamDuringLongPressFunc(fDuringLongPressFuncParam);
298  }
299  break;
300 
301  case kPB_PRESSEND:
302  // button was released.
303  if ((activeLevel) && (waitTime < fDebounceTicks))
304  {
305  // button was released to quickly so I assume some bouncing.
306  newState(fLastState); // go back
307  }
308  else if (waitTime >= fDebounceTicks)
309  {
310  if (fLongPressStopFunc)
311  fLongPressStopFunc();
312  if (fParamLongPressStopFunc)
313  fParamLongPressStopFunc(fLongPressStopFuncParam);
314  reset();
315  }
316  break;
317 
318  default:
319  // unknown state detected -> reset state machine
320  newState(kPB_INIT);
321  break;
322  }
323  }
324 
325 
328  void reset(void)
329  {
330  fState = kPB_INIT;
331  fLastState = kPB_INIT;
332  fNClicks = 0;
333  fStartTime = 0;
334  }
335 
340  inline int getNumberClicks(void) const
341  {
342  return fNClicks;
343  }
344 
349  inline bool isIdle() const
350  {
351  return fState == kPB_INIT;
352  }
353 
357  inline bool isLongPressed() const
358  {
359  return fState == kPB_PRESS;
360  }
361 
362 private:
363  int fPin; // hardware pin number.
364  unsigned int fDebounceTicks = 50; // number of ticks for debounce times.
365  unsigned int fClickTicks = 400; // number of msecs before a click is detected.
366  unsigned int fPressTicks = 800; // number of msecs before a long button press is detected
367 
368  int fButtonPressed;
369  bool fPullup;
370 
371  // These variables will hold functions acting as event source.
372  CallbackFunction fClickFunc = NULL;
373  ParameterizedCallbackFunction fParamClickFunc = NULL;
374  void *fClickFuncParam = NULL;
375 
376  CallbackFunction fDoubleClickFunc = NULL;
377  ParameterizedCallbackFunction fParamDoubleClickFunc = NULL;
378  void *fDoubleClickFuncParam = NULL;
379 
380  CallbackFunction fMultiClickFunc = NULL;
381  ParameterizedCallbackFunction fParamMultiClickFunc = NULL;
382  void *fMultiClickFuncParam = NULL;
383 
384  CallbackFunction fLongPressStartFunc = NULL;
385  ParameterizedCallbackFunction fParamLongPressStartFunc = NULL;
386  void *fLongPressStartFuncParam = NULL;
387 
388  CallbackFunction fLongPressStopFunc = NULL;
389  ParameterizedCallbackFunction fParamLongPressStopFunc = NULL;
390  void *fLongPressStopFuncParam;
391 
392  CallbackFunction fDuringLongPressFunc = NULL;
393  ParameterizedCallbackFunction fParamDuringLongPressFunc = NULL;
394  void *fDuringLongPressFuncParam = NULL;
395 
396  enum State : int
397  {
398  kPB_INIT = 0,
399  kPB_DOWN = 1,
400  kPB_UP = 2,
401  kPB_COUNT = 3,
402  kPB_PRESS = 6,
403  kPB_PRESSEND = 7,
404  kUNKNOWN = 99
405  };
406 
407  void newState(State nextState)
408  {
409  fLastState = fState;
410  fState = nextState;
411  }
412 
413  State fState = kPB_INIT;
414  State fLastState = kPB_INIT; // used for debouncing
415 
416  unsigned long fStartTime; // start of current input change to checking debouncing
417  int fNClicks; // count the number of clicks with this variable
418  int fMaxClicks = 1; // max number (1, 2, multi=3) of clicks of interest by registration of event functions.
419 };
420 
421 #endif
PushButton::attachClick
void attachClick(ParameterizedCallbackFunction callback, void *param)
Attach an event to be called when a single click is detected.
Definition: PushButton.h:67
PushButton::attachDuringLongPress
void attachDuringLongPress(ParameterizedCallbackFunction callback, void *param)
Attach an event to fire periodically while the button is held down.
Definition: PushButton.h:166
PushButton::ParameterizedCallbackFunction
void(* ParameterizedCallbackFunction)(void *)
Definition: PushButton.h:13
PushButton::reset
void reset(void)
Reset the button state machine.
Definition: PushButton.h:328
ReelTwo.h
SetupEvent.h
AnimatedEvent
Base class for all animated devices. AnimatedEvent::animate() is called for each device once through ...
Definition: AnimatedEvent.h:18
PushButton::setDebounceTicks
void setDebounceTicks(const int ticks)
set # millisec after safe click is assumed.
Definition: PushButton.h:33
PushButton::isIdle
bool isIdle() const
Definition: PushButton.h:349
SetupEvent
Base class for all devices that require setup that cannot happen in the constructor....
Definition: SetupEvent.h:15
PushButton::getNumberClicks
int getNumberClicks(void) const
Returns number of clicks in any case: single or multiple clicks.
Definition: PushButton.h:340
PushButton::isLongPressed
bool isLongPressed() const
Definition: PushButton.h:357
PushButton
Definition: PushButton.h:9
PushButton::attachDoubleClick
void attachDoubleClick(CallbackFunction callback)
Attach an event to be called after a double click is detected.
Definition: PushButton.h:77
AnimatedEvent.h
PushButton::setup
virtual void setup() override
Subclasses must implement this function to perform any necessary setup that cannot happen in the cons...
Definition: PushButton.h:172
PushButton::animate
virtual void animate() override
Call this function every some milliseconds for checking the input level at the initialized digital pi...
Definition: PushButton.h:189
PushButton::attachLongPressStop
void attachLongPressStop(CallbackFunction callback)
Attach an event to fire as soon as the button is released after a long press.
Definition: PushButton.h:138
PushButton::attachLongPressStop
void attachLongPressStop(ParameterizedCallbackFunction callback, void *param)
Attach an event to fire as soon as the button is released after a long press.
Definition: PushButton.h:147
PushButton::attachMultiClick
void attachMultiClick(ParameterizedCallbackFunction callback, void *param)
Attach an event to be called after a multi click is detected.
Definition: PushButton.h:108
PushButton::attachLongPressStart
void attachLongPressStart(CallbackFunction callback)
Attach an event to fire when the button is pressed and held down.
Definition: PushButton.h:119
PushButton::attachMultiClick
void attachMultiClick(CallbackFunction callback)
Attach an event to be called after a multi click is detected.
Definition: PushButton.h:98
PushButton::attachClick
void attachClick(CallbackFunction callback)
Attach an event to be called when a single click is detected.
Definition: PushButton.h:58
PushButton::attachDuringLongPress
void attachDuringLongPress(CallbackFunction callback)
Attach an event to fire periodically while the button is held down.
Definition: PushButton.h:157
PushButton::attachLongPressStart
void attachLongPressStart(ParameterizedCallbackFunction callback, void *param)
Attach an event to fire when the button is pressed and held down.
Definition: PushButton.h:128
PushButton::PushButton
PushButton(const int pin, const bool activeLow=true, const bool pullupActive=true)
Initialize the PushButton.
Definition: PushButton.h:21
PushButton::CallbackFunction
void(* CallbackFunction)(void)
Definition: PushButton.h:12
PushButton::attachDoubleClick
void attachDoubleClick(ParameterizedCallbackFunction callback, void *param)
Attach an event to be called after a double click is detected.
Definition: PushButton.h:87
PushButton::setPressTicks
void setPressTicks(const int ticks)
set # millisec after press is assumed.
Definition: PushButton.h:49
PushButton::setClickTicks
void setClickTicks(const int ticks)
set # millisec after single click is assumed.
Definition: PushButton.h:41