Embedded Template Library 1.0
Loading...
Searching...
No Matches
debounce.h
Go to the documentation of this file.
1
2
3/******************************************************************************
4The MIT License(MIT)
5
6Embedded Template Library.
7https://github.com/ETLCPP/etl
8https://www.etlcpp.com
9
10Copyright(c) 2016 John Wellbelove
11
12Permission is hereby granted, free of charge, to any person obtaining a copy
13of this software and associated documentation files(the "Software"), to deal
14in the Software without restriction, including without limitation the rights
15to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
16copies of the Software, and to permit persons to whom the Software is
17furnished to do so, subject to the following conditions :
18
19The above copyright notice and this permission notice shall be included in all
20copies or substantial portions of the Software.
21
22THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
25AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28SOFTWARE.
29******************************************************************************/
30
31#ifndef ETL_DEBOUNCE_INCLUDED
32#define ETL_DEBOUNCE_INCLUDED
33
34#include "platform.h"
35
36namespace etl
37{
38 namespace private_debounce
39 {
41 {
42 public:
43
44 typedef uint_least8_t flags_t;
45 typedef uint16_t count_t;
46
47 //*************************************************************************
51 //*************************************************************************
52 void add_sample(bool sample)
53 {
54 // Changed from last time?
55 if (sample != ((flags & Sample) != 0))
56 {
57 count = 0;
58 flags = static_cast<flags_t>((flags & static_cast<flags_t>(~Sample)) | (sample ? Sample : 0));
59 }
60
61 flags &= static_cast<flags_t>(~Change);
62 }
63
64 //*************************************************************************
67 //*************************************************************************
68 bool has_changed() const
69 {
70 return (flags & Change) != 0;
71 }
72
73 //*************************************************************************
76 //*************************************************************************
77 bool is_set() const
78 {
79 return ((flags & State) > Off);
80 }
81
82 //*************************************************************************
85 //*************************************************************************
86 bool is_held() const
87 {
88 return (flags & State) > On;
89 }
90
91 //*************************************************************************
94 //*************************************************************************
95 bool is_repeating() const
96 {
97 return ((flags & State) == Repeating);
98 }
99
100 protected:
101
102 enum states
103 {
104 Off = 0,
105 On = 1,
106 Held = 2,
107 Repeating = 3,
108 State = 0x03U,
109 Sample = 4,
110 Change = 8
111 };
112
113 //*************************************************************************
115 //*************************************************************************
116 debounce_base(bool initial_state)
117 : flags(initial_state ? On : Off)
118 , count(0)
119 {
120 }
121
122 //*************************************************************************
124 //*************************************************************************
126
127 //*************************************************************************
129 //*************************************************************************
130 void get_next(bool sample, bool condition_set, bool condition_clear, const uint_least8_t state_table[][2])
131 {
132 int index1 = ((flags & State) * 2) + (sample ? 1 : 0);
133 int index2 = (sample ? (condition_set ? 0 : 1) : (condition_clear ? 0 : 1));
134
135 flags_t next = flags;
136
137 next &= static_cast<flags_t>(~State);
138 next |= state_table[index1][index2];
139
140 if (next != flags)
141 {
142 next |= Change;
143 }
144 else
145 {
146 next &= static_cast<flags_t>(~Change);
147 }
148
149 flags = next;
150 }
151
152 flags_t flags;
153 count_t count;
154 };
155
156 //***************************************************************************
158 //***************************************************************************
159 class debounce2 : public debounce_base
160 {
161 protected:
162
163 debounce2(bool initial_state)
164 : debounce_base(initial_state)
165 {
166 }
167
168 //*************************************************************************
170 //*************************************************************************
172
173 //*************************************************************************
175 //*************************************************************************
176 void set_state(bool sample, bool condition_set, bool condition_clear)
177 {
178 static ETL_CONSTANT uint_least8_t state_table[4][2] = {
179 /* Off 0 */ {debounce_base::Off, debounce_base::Off},
180 /* Off 1 */ {debounce_base::On, debounce_base::Off},
181 /* On 0 */ {debounce_base::Off, debounce_base::On},
182 /* On 1 */ {debounce_base::On, debounce_base::On},
183 };
184
185 get_next(sample, condition_set, condition_clear, state_table);
186 }
187
188 //*************************************************************************
190 //*************************************************************************
191 bool process(bool sample, count_t valid_count)
192 {
193 add_sample(sample);
194
195 if (count < UINT16_MAX)
196 {
197 ++count;
198
199 bool valid = (count == valid_count);
200
201 switch (flags & State)
202 {
203 case Off:
204 {
205 set_state(sample, valid, valid);
206 break;
207 }
208
209 case On:
210 {
211 set_state(sample, valid, valid);
212 break;
213 }
214
215 default:
216 {
217 break;
218 }
219 }
220 }
221
222 if (flags & Change)
223 {
224 count = 0;
225 }
226
227 return (flags & Change);
228 }
229 };
230
231 //***************************************************************************
233 //***************************************************************************
234 class debounce3 : public debounce_base
235 {
236 protected:
237
238 debounce3(bool initial_state)
239 : debounce_base(initial_state)
240 {
241 }
242
243 //*************************************************************************
245 //*************************************************************************
247
248 //*************************************************************************
250 //*************************************************************************
251 void set_state(bool sample, bool condition_set, bool condition_clear)
252 {
253 static ETL_CONSTANT uint_least8_t state_table[6][2] = {/* Off 0 */ {debounce_base::Off, debounce_base::Off},
254 /* Off 1 */ {debounce_base::On, debounce_base::Off},
255 /* On 0 */ {debounce_base::Off, debounce_base::On},
256 /* On 1 */ {debounce_base::Held, debounce_base::On},
257 /* Held 0 */ {debounce_base::Off, debounce_base::Held},
258 /* Held 1 */ {debounce_base::Held, debounce_base::Held}};
259
260 get_next(sample, condition_set, condition_clear, state_table);
261 }
262
263 //*************************************************************************
265 //*************************************************************************
266 bool process(bool sample, count_t valid_count, count_t hold_count)
267 {
268 add_sample(sample);
269
270 if (count < UINT16_MAX)
271 {
272 ++count;
273
274 bool valid = (count == valid_count);
275 bool hold = (count == hold_count);
276
277 switch (flags & State)
278 {
279 case Off:
280 {
281 set_state(sample, valid, valid);
282 break;
283 }
284
285 case On:
286 {
287 set_state(sample, hold, valid);
288 break;
289 }
290
291 case Held:
292 {
293 set_state(sample, hold, valid);
294 break;
295 }
296
297 default:
298 {
299 break;
300 }
301 }
302 }
303
304 if (flags & Change)
305 {
306 count = 0;
307 }
308
309 return (flags & Change);
310 }
311 };
312
313 //***************************************************************************
315 //***************************************************************************
316 class debounce4 : public debounce_base
317 {
318 protected:
319
320 debounce4(bool initial_state)
321 : debounce_base(initial_state)
322 {
323 }
324
325 //*************************************************************************
327 //*************************************************************************
329
330 //*************************************************************************
332 //*************************************************************************
333 void set_state(bool sample, bool condition_set, bool condition_clear)
334 {
335 static ETL_CONSTANT uint_least8_t state_table[8][2] = {/* Off 0 */ {debounce_base::Off, debounce_base::Off},
336 /* Off 1 */ {debounce_base::On, debounce_base::Off},
337 /* On 0 */ {debounce_base::Off, debounce_base::On},
338 /* On 1 */ {debounce_base::Held, debounce_base::On},
339 /* Held 0 */ {debounce_base::Off, debounce_base::Held},
340 /* Held 1 */ {debounce_base::Repeating, debounce_base::Held},
341 /* Repeating 0 */ {debounce_base::Off, debounce_base::Repeating},
342 /* Repeating 1 */
343 {debounce_base::Repeating, debounce_base::Repeating}};
344
345 get_next(sample, condition_set, condition_clear, state_table);
346 }
347
348 //*************************************************************************
350 //*************************************************************************
351 bool process(bool sample, count_t valid_count, count_t hold_count, count_t repeat_count)
352 {
353 add_sample(sample);
354
355 if (count < UINT16_MAX)
356 {
357 ++count;
358
359 bool valid = (count == valid_count);
360 bool hold = (count == hold_count);
361 bool repeat = (count == repeat_count);
362
363 switch (flags & State)
364 {
365 case Off:
366 {
367 set_state(sample, valid, valid);
368 break;
369 }
370
371 case On:
372 {
373 set_state(sample, hold, valid);
374 break;
375 }
376
377 case Held:
378 {
379 set_state(sample, repeat, valid);
380 break;
381 }
382
383 case Repeating:
384 {
385 set_state(sample, repeat, valid);
386
387 if (sample && repeat)
388 {
389 count = 0;
390 flags |= Change;
391 }
392 break;
393 }
394
395 default:
396 {
397 break;
398 }
399 }
400 }
401
402 if (flags & Change)
403 {
404 count = 0;
405 }
406
407 return (flags & Change);
408 }
409 };
410 } // namespace private_debounce
411
412 //***************************************************************************
415 //***************************************************************************
416 template <const uint16_t VALID_COUNT = 0, const uint16_t HOLD_COUNT = 0, const uint16_t REPEAT_COUNT = 0>
418 {
419 public:
420
421 //*************************************************************************
423 //*************************************************************************
424 debounce(bool initial_state = false)
425 : debounce4(initial_state)
426 {
427 }
428
429 //*************************************************************************
434 //*************************************************************************
435 bool add(bool sample)
436 {
437 return process(sample, VALID_COUNT, HOLD_COUNT, REPEAT_COUNT);
438 }
439 };
440
441 //***************************************************************************
444 //***************************************************************************
445 template <const uint16_t VALID_COUNT, const uint16_t HOLD_COUNT>
446 class debounce<VALID_COUNT, HOLD_COUNT, 0> : public private_debounce::debounce3
447 {
448 public:
449
450 //*************************************************************************
452 //*************************************************************************
453 debounce(bool initial_state = false)
454 : debounce3(initial_state)
455 {
456 }
457
458 //*************************************************************************
466 //*************************************************************************
467 bool add(bool sample)
468 {
469 return process(sample, VALID_COUNT, HOLD_COUNT);
470 }
471 };
472
473 //***************************************************************************
476 //***************************************************************************
477 template <const uint16_t VALID_COUNT>
478 class debounce<VALID_COUNT, 0, 0> : public private_debounce::debounce2
479 {
480 public:
481
482 //*************************************************************************
484 //*************************************************************************
485 debounce(bool initial_state = false)
486 : debounce2(initial_state)
487 {
488 }
489
490 //*************************************************************************
497 //*************************************************************************
498 bool add(bool sample)
499 {
500 return process(sample, VALID_COUNT);
501 }
502 };
503
504 //***************************************************************************
507 //***************************************************************************
508 template <>
509 class debounce<0, 0, 0> : public private_debounce::debounce4
510 {
511 public:
512
513 //*************************************************************************
516 //*************************************************************************
517 debounce(bool initial_state = false)
518 : debounce4(initial_state)
519 , valid_count(1)
520 , hold_count(0)
521 , repeat_count(0)
522 {
523 }
524
525 //*************************************************************************
531 //*************************************************************************
532 debounce(count_t valid, count_t hold = 0, count_t repeat = 0)
533 : debounce4(false)
534 {
535 set(valid, hold, repeat);
536 }
537
538 //*************************************************************************
540 //*************************************************************************
541 void set(count_t valid, count_t hold = 0, count_t repeat = 0)
542 {
543 valid_count = valid;
544 hold_count = hold;
545 repeat_count = repeat;
546 }
547
548 //*************************************************************************
557 //*************************************************************************
558 bool add(bool sample)
559 {
560 return process(sample, valid_count, hold_count, repeat_count);
561 }
562
563 private:
564
565 count_t valid_count;
566 count_t hold_count;
567 count_t repeat_count;
568 };
569} // namespace etl
570
571#endif
bool add(bool sample)
Definition debounce.h:558
void set(count_t valid, count_t hold=0, count_t repeat=0)
Constructor.
Definition debounce.h:541
debounce(count_t valid, count_t hold=0, count_t repeat=0)
Definition debounce.h:532
debounce(bool initial_state=false)
Definition debounce.h:517
bool add(bool sample)
Definition debounce.h:498
debounce(bool initial_state=false)
Constructor.
Definition debounce.h:485
bool add(bool sample)
Definition debounce.h:467
debounce(bool initial_state=false)
Constructor.
Definition debounce.h:453
bool add(bool sample)
Definition debounce.h:435
debounce(bool initial_state=false)
Constructor.
Definition debounce.h:424
Definition flags.h:51
State change logic for 2 state debounce.
Definition debounce.h:160
~debounce2()
Destructor.
Definition debounce.h:171
State change logic for 3 state debounce.
Definition debounce.h:235
~debounce3()
Destructor.
Definition debounce.h:246
State change logic for 4 state debounce.
Definition debounce.h:317
~debounce4()
Destructor.
Definition debounce.h:328
bool has_changed() const
Definition debounce.h:68
void add_sample(bool sample)
Definition debounce.h:52
bool is_repeating() const
Definition debounce.h:95
debounce_base(bool initial_state)
Constructor.
Definition debounce.h:116
bool is_set() const
Definition debounce.h:77
bool is_held() const
Definition debounce.h:86
void get_next(bool sample, bool condition_set, bool condition_clear, const uint_least8_t state_table[][2])
Gets the next state based on the inputs.
Definition debounce.h:130
~debounce_base()
Destructor.
Definition debounce.h:125
Definition absolute.h:40