Embedded Template Library  1.0
debounce.h
Go to the documentation of this file.
1 
3 /******************************************************************************
4 The MIT License(MIT)
5 
6 Embedded Template Library.
7 https://github.com/ETLCPP/etl
8 https://www.etlcpp.com
9 
10 Copyright(c) 2016 jwellbelove
11 
12 Permission is hereby granted, free of charge, to any person obtaining a copy
13 of this software and associated documentation files(the "Software"), to deal
14 in the Software without restriction, including without limitation the rights
15 to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
16 copies of the Software, and to permit persons to whom the Software is
17 furnished to do so, subject to the following conditions :
18 
19 The above copyright notice and this permission notice shall be included in all
20 copies or substantial portions of the Software.
21 
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
25 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 SOFTWARE.
29 ******************************************************************************/
30 
31 #ifndef ETL_DEBOUNCE_INCLUDED
32 #define ETL_DEBOUNCE_INCLUDED
33 
34 #include <stdint.h>
35 
36 #include "platform.h"
37 #include "static_assert.h"
38 
39 namespace etl
40 {
41  namespace private_debounce
42  {
44  {
45  public:
46 
47  typedef uint_least8_t flags_t;
48  typedef uint16_t count_t;
49 
50  //*************************************************************************
54  //*************************************************************************
55  void add_sample(bool sample)
56  {
57  // Changed from last time?
58  if (sample != bool((flags & SAMPLE) != 0))
59  {
60  count = 0;
61  flags = (flags & ~SAMPLE) | (sample ? SAMPLE : 0);
62  }
63 
64  flags &= ~CHANGE;
65  }
66 
67  //*************************************************************************
70  //*************************************************************************
71  bool has_changed() const
72  {
73  return (flags & CHANGE) != 0;
74  }
75 
76  //*************************************************************************
79  //*************************************************************************
80  bool is_set() const
81  {
82  return ((flags & STATE) > OFF);
83  }
84 
85  //*************************************************************************
88  //*************************************************************************
89  bool is_held() const
90  {
91  return (flags & STATE) > ON;
92  }
93 
94  //*************************************************************************
97  //*************************************************************************
98  bool is_repeating() const
99  {
100  return ((flags & STATE) == REPEATING);
101  }
102 
103  enum states
104  {
105  OFF = 0,
106  ON = 1,
107  HELD = 2,
108  REPEATING = 3,
109  STATE = 0x03,
110  SAMPLE = 4,
111  CHANGE = 8
112  };
113 
114  protected:
115 
116  //*************************************************************************
118  //*************************************************************************
119  debounce_base(bool initial_state)
120  : flags(initial_state ? ON : OFF),
121  count(0)
122  {
123  }
124 
125  //*************************************************************************
127  //*************************************************************************
129  {
130  }
131 
132  //*************************************************************************
134  //*************************************************************************
135  void get_next(bool sample, bool condition_set, bool condition_clear, uint_least8_t state_table[][2])
136  {
137  int index1 = ((flags & STATE) * 2) + (sample ? 1 : 0);
138  int index2 = (sample ? (condition_set ? 0 : 1) : (condition_clear ? 0 : 1));
139 
140  flags_t next = flags;
141 
142  next &= ~STATE;
143  next |= state_table[index1][index2];
144 
145  if (next != flags)
146  {
147  next |= CHANGE;
148  }
149  else
150  {
151  next &= ~CHANGE;
152  }
153 
154  flags = next;
155  }
156 
157  flags_t flags;
158  count_t count;
159  };
160 
161  //***************************************************************************
163  //***************************************************************************
164  class debounce2 : public debounce_base
165  {
166  protected:
167 
168  debounce2(bool initial_state)
169  : debounce_base(initial_state)
170  {
171  }
172 
173  //*************************************************************************
175  //*************************************************************************
177  {
178  }
179 
180  //*************************************************************************
182  //*************************************************************************
183  void set_state(bool sample, bool condition_set, bool condition_clear)
184  {
185  static uint_least8_t state_table[4][2] =
186  {
187  /* OFF 0 */{ debounce_base::OFF, debounce_base::OFF },
188  /* OFF 1 */{ debounce_base::ON, debounce_base::OFF },
189  /* ON 0 */{ debounce_base::OFF, debounce_base::ON },
190  /* ON 1 */{ debounce_base::ON, debounce_base::ON },
191  };
192 
193  get_next(sample, condition_set, condition_clear, state_table);
194  }
195 
196  //*************************************************************************
198  //*************************************************************************
199  bool process(bool sample, count_t valid_count)
200  {
201  add_sample(sample);
202 
203  if (count < UINT16_MAX)
204  {
205  ++count;
206 
207  bool valid = (count == valid_count);
208 
209  switch (flags & STATE)
210  {
211  case OFF:
212  {
213  set_state(sample, valid, valid);
214  break;
215  }
216 
217  case ON:
218  {
219  set_state(sample, valid, valid);
220  break;
221  }
222 
223  default:
224  {
225  break;
226  }
227  }
228  }
229 
230  if (flags & CHANGE)
231  {
232  count = 0;
233  }
234 
235  return (flags & CHANGE);
236  }
237  };
238 
239  //***************************************************************************
241  //***************************************************************************
242  class debounce3 : public debounce_base
243  {
244  protected:
245 
246  debounce3(bool initial_state)
247  : debounce_base(initial_state)
248  {
249  }
250 
251  //*************************************************************************
253  //*************************************************************************
255  {
256  }
257 
258  //*************************************************************************
260  //*************************************************************************
261  void set_state(bool sample, bool condition_set, bool condition_clear)
262  {
263  static uint_least8_t state_table[6][2] =
264  {
265  /* OFF 0 */{ debounce_base::OFF, debounce_base::OFF },
266  /* OFF 1 */{ debounce_base::ON, debounce_base::OFF },
267  /* ON 0 */{ debounce_base::OFF, debounce_base::ON },
268  /* ON 1 */{ debounce_base::HELD, debounce_base::ON },
269  /* HELD 0 */{ debounce_base::OFF, debounce_base::HELD },
270  /* HELD 1 */{ debounce_base::HELD, debounce_base::HELD }
271  };
272 
273  get_next(sample, condition_set, condition_clear, state_table);
274  }
275 
276  //*************************************************************************
278  //*************************************************************************
279  bool process(bool sample, count_t valid_count, count_t hold_count)
280  {
281  add_sample(sample);
282 
283  if (count < UINT16_MAX)
284  {
285  ++count;
286 
287  bool valid = (count == valid_count);
288  bool hold = (count == hold_count);
289 
290  switch (flags & STATE)
291  {
292  case OFF:
293  {
294  set_state(sample, valid, valid);
295  break;
296  }
297 
298  case ON:
299  {
300  set_state(sample, hold, valid);
301  break;
302  }
303 
304  case HELD:
305  {
306  set_state(sample, hold, valid);
307  break;
308  }
309 
310  default:
311  {
312  break;
313  }
314  }
315  }
316 
317  if (flags & CHANGE)
318  {
319  count = 0;
320  }
321 
322  return (flags & CHANGE);
323  }
324  };
325 
326  //***************************************************************************
328  //***************************************************************************
329  class debounce4 : public debounce_base
330  {
331  protected:
332 
333  debounce4(bool initial_state)
334  : debounce_base(initial_state)
335  {
336  }
337 
338  //*************************************************************************
340  //*************************************************************************
342  {
343  }
344 
345  //*************************************************************************
347  //*************************************************************************
348  void set_state(bool sample, bool condition_set, bool condition_clear)
349  {
350  static uint_least8_t state_table[8][2] =
351  {
352  /* OFF 0 */{ debounce_base::OFF, debounce_base::OFF },
353  /* OFF 1 */{ debounce_base::ON, debounce_base::OFF },
354  /* ON 0 */{ debounce_base::OFF, debounce_base::ON },
355  /* ON 1 */{ debounce_base::HELD, debounce_base::ON },
356  /* HELD 0 */{ debounce_base::OFF, debounce_base::HELD },
357  /* HELD 1 */{ debounce_base::REPEATING, debounce_base::HELD },
358  /* REPEATING 0 */{ debounce_base::OFF, debounce_base::REPEATING },
359  /* REPEATING 1 */{ debounce_base::REPEATING, debounce_base::REPEATING }
360  };
361 
362  get_next(sample, condition_set, condition_clear, state_table);
363  }
364 
365  //*************************************************************************
367  //*************************************************************************
368  bool process(bool sample, count_t valid_count, count_t hold_count, count_t repeat_count)
369  {
370  add_sample(sample);
371 
372  if (count < UINT16_MAX)
373  {
374  ++count;
375 
376  bool valid = (count == valid_count);
377  bool hold = (count == hold_count);
378  bool repeat = (count == repeat_count);
379 
380  switch (flags & STATE)
381  {
382  case OFF:
383  {
384  set_state(sample, valid, valid);
385  break;
386  }
387 
388  case ON:
389  {
390  set_state(sample, hold, valid);
391  break;
392  }
393 
394  case HELD:
395  {
396  set_state(sample, repeat, valid);
397  break;
398  }
399 
400  case REPEATING:
401  {
402  set_state(sample, repeat, valid);
403 
404  if (sample && repeat)
405  {
406  count = 0;
407  flags |= CHANGE;
408  }
409  break;
410  }
411 
412  default:
413  {
414  break;
415  }
416  }
417  }
418 
419  if (flags & CHANGE)
420  {
421  count = 0;
422  }
423 
424  return (flags & CHANGE);
425  }
426  };
427  }
428 
429  //***************************************************************************
432  //***************************************************************************
433  template <const uint16_t VALID_COUNT = 0, const uint16_t HOLD_COUNT = 0, const uint16_t REPEAT_COUNT = 0>
435  {
436  public:
437 
438  //*************************************************************************
440  //*************************************************************************
441  debounce(bool initial_state = false)
442  : debounce4(initial_state)
443  {
444  }
445 
446  //*************************************************************************
451  //*************************************************************************
452  bool add(bool sample)
453  {
454  return process(sample, VALID_COUNT, HOLD_COUNT, REPEAT_COUNT);
455  }
456  };
457 
458  //***************************************************************************
461  //***************************************************************************
462  template <const uint16_t VALID_COUNT, const uint16_t HOLD_COUNT>
463  class debounce<VALID_COUNT, HOLD_COUNT, 0> : public private_debounce::debounce3
464  {
465  public:
466 
467  //*************************************************************************
469  //*************************************************************************
470  debounce(bool initial_state = false)
471  : debounce3(initial_state)
472  {
473  }
474 
475  //*************************************************************************
483  //*************************************************************************
484  bool add(bool sample)
485  {
486  return process(sample, VALID_COUNT, HOLD_COUNT);
487  }
488  };
489 
490  //***************************************************************************
493  //***************************************************************************
494  template <const uint16_t VALID_COUNT>
495  class debounce<VALID_COUNT, 0, 0> : public private_debounce::debounce2
496  {
497  public:
498 
499  //*************************************************************************
501  //*************************************************************************
502  debounce(bool initial_state = false)
503  : debounce2(initial_state)
504  {
505  }
506 
507  //*************************************************************************
514  //*************************************************************************
515  bool add(bool sample)
516  {
517  return process(sample, VALID_COUNT);
518  }
519  };
520 
521  //***************************************************************************
524  //***************************************************************************
525  template <>
526  class debounce<0, 0, 0> : public private_debounce::debounce4
527  {
528  public:
529 
530  //*************************************************************************
533  //*************************************************************************
534  debounce(bool initial_state = false)
535  : debounce4(initial_state),
536  valid_count(1),
537  hold_count(0),
538  repeat_count(0)
539  {
540  }
541 
542  //*************************************************************************
547  //*************************************************************************
548  debounce(count_t valid, count_t hold = 0, count_t repeat = 0)
549  : debounce4(false)
550  {
551  set(valid, hold, repeat);
552  }
553 
554  //*************************************************************************
556  //*************************************************************************
557  void set(count_t valid, count_t hold = 0, count_t repeat = 0)
558  {
559  valid_count = valid;
560  hold_count = hold;
561  repeat_count = repeat;
562  }
563 
564  //*************************************************************************
573  //*************************************************************************
574  bool add(bool sample)
575  {
576  return process(sample, valid_count, hold_count, repeat_count);
577  }
578 
579  private:
580 
581  count_t valid_count;
582  count_t hold_count;
583  count_t repeat_count;
584  };
585 }
586 
587 #endif
bool add(bool sample)
Definition: debounce.h:574
void set(count_t valid, count_t hold=0, count_t repeat=0)
Constructor.
Definition: debounce.h:557
debounce(count_t valid, count_t hold=0, count_t repeat=0)
Definition: debounce.h:548
debounce(bool initial_state=false)
Definition: debounce.h:534
bool add(bool sample)
Definition: debounce.h:515
debounce(bool initial_state=false)
Constructor.
Definition: debounce.h:502
bool add(bool sample)
Definition: debounce.h:484
debounce(bool initial_state=false)
Constructor.
Definition: debounce.h:470
Definition: debounce.h:435
bool add(bool sample)
Definition: debounce.h:452
debounce(bool initial_state=false)
Constructor.
Definition: debounce.h:441
Definition: flags.h:55
State change logic for 2 state debounce.
Definition: debounce.h:165
~debounce2()
Destructor.
Definition: debounce.h:176
State change logic for 3 state debounce.
Definition: debounce.h:243
~debounce3()
Destructor.
Definition: debounce.h:254
State change logic for 4 state debounce.
Definition: debounce.h:330
~debounce4()
Destructor.
Definition: debounce.h:341
Definition: debounce.h:44
bool has_changed() const
Definition: debounce.h:71
void add_sample(bool sample)
Definition: debounce.h:55
bool is_repeating() const
Definition: debounce.h:98
debounce_base(bool initial_state)
Constructor.
Definition: debounce.h:119
bool is_set() const
Definition: debounce.h:80
void get_next(bool sample, bool condition_set, bool condition_clear, uint_least8_t state_table[][2])
Gets the next state based on the inputs.
Definition: debounce.h:135
bool is_held() const
Definition: debounce.h:89
~debounce_base()
Destructor.
Definition: debounce.h:128
A templated set implementation that uses a fixed size buffer.
Definition: set.h:2104
Definition: absolute.h:37