Skip to main content

derico/
pin.rs

1#![deny(unsafe_code)]
2
3use super::debouncer::{Debouncer, Edge};
4
5#[derive(Debug, PartialEq, Clone, Copy)]
6pub enum PinState {
7    Low,
8    High,
9}
10
11#[derive(Debug)]
12pub struct SmallPinDebouncer {
13    inner: Debouncer<PinState, u8>,
14}
15
16impl SmallPinDebouncer {
17    pub fn new(threshold: u8, inital_state: PinState) -> Self {
18        SmallPinDebouncer {
19            inner: Debouncer::new(threshold, inital_state),
20        }
21    }
22
23    pub fn update(&mut self, state: PinState) -> Option<Edge<PinState>> {
24        self.inner.update(state)
25    }
26
27    pub fn is_high(&self) -> bool {
28        self.inner.is_state(PinState::High)
29    }
30
31    pub fn is_low(&self) -> bool {
32        self.inner.is_state(PinState::Low)
33    }
34}
35
36#[cfg(test)]
37mod tests {
38    use super::*;
39
40    #[test]
41    fn test_rising_edge() {
42        // Initially low state
43        let mut debouncer: SmallPinDebouncer = SmallPinDebouncer::new(3, PinState::Low);
44        assert!(debouncer.is_low());
45
46        // Three high updates required
47        assert_eq!(debouncer.update(PinState::High), None);
48        assert_eq!(debouncer.update(PinState::High), None);
49        assert_eq!(
50            debouncer.update(PinState::High),
51            Some(Edge::new(PinState::Low, PinState::High))
52        );
53
54        // Further highs do not indicate a rising edge anymore
55        assert_eq!(debouncer.update(PinState::High), None);
56
57        // A low state does not reset counting
58        assert_eq!(debouncer.update(PinState::Low), None);
59        assert_eq!(debouncer.update(PinState::High), None);
60        assert_eq!(debouncer.update(PinState::High), None);
61        assert_ne!(
62            debouncer.update(PinState::High),
63            Some(Edge::new(PinState::Low, PinState::High))
64        );
65    }
66
67    #[test]
68    fn test_falling_edge() {
69        // Initially high state
70        let mut debouncer: SmallPinDebouncer = SmallPinDebouncer::new(3, PinState::High);
71        assert!(debouncer.is_high());
72
73        // Three low updates required
74        assert_eq!(debouncer.update(PinState::Low), None);
75        assert_eq!(debouncer.update(PinState::Low), None);
76        assert_eq!(
77            debouncer.update(PinState::Low),
78            Some(Edge::new(PinState::High, PinState::Low))
79        );
80
81        // Further lowss do not indicate a rising edge anymore
82        assert_eq!(debouncer.update(PinState::Low), None);
83
84        // A high state does not reset counting
85        assert_eq!(debouncer.update(PinState::High), None);
86        assert_eq!(debouncer.update(PinState::Low), None);
87        assert_eq!(debouncer.update(PinState::Low), None);
88        assert_ne!(
89            debouncer.update(PinState::Low),
90            Some(Edge::new(PinState::High, PinState::Low))
91        );
92    }
93
94    #[test]
95    fn test_debounce_16() {
96        // Sixteen pressed updates required
97        let mut debouncer: SmallPinDebouncer = SmallPinDebouncer::new(16, PinState::Low);
98        assert!(debouncer.is_low());
99        for _ in 0..15 {
100            assert_eq!(debouncer.update(PinState::High), None);
101            assert!(!debouncer.is_high());
102        }
103        assert_eq!(
104            debouncer.update(PinState::High),
105            Some(Edge::new(PinState::Low, PinState::High))
106        );
107        assert!(debouncer.is_high());
108        assert_eq!(debouncer.update(PinState::High), None);
109        assert!(debouncer.is_high());
110    }
111
112    #[test]
113    fn test_is_low_high() {
114        // Initially low
115        let mut debouncer: SmallPinDebouncer = SmallPinDebouncer::new(8, PinState::Low);
116        assert!(debouncer.is_low());
117        assert!(!debouncer.is_high());
118
119        // Depressed updates don't change the situation
120        debouncer.update(PinState::Low);
121        assert!(debouncer.is_low());
122        assert!(!debouncer.is_high());
123
124        // A pressed update causes neither low nor high state
125        for _ in 0..7 {
126            assert!(debouncer.update(PinState::High).is_none());
127            assert!(!debouncer.is_low());
128            assert!(!debouncer.is_high());
129        }
130
131        // Once complete, the state is high
132        assert_eq!(
133            debouncer.update(PinState::High),
134            Some(Edge::new(PinState::Low, PinState::High))
135        );
136        assert!(!debouncer.is_low());
137        assert!(debouncer.is_high());
138
139        // Consecutive pressed updates don't trigger an edge but are still high
140        assert!(debouncer.update(PinState::High).is_none());
141        assert!(!debouncer.is_low());
142        assert!(debouncer.is_high());
143    }
144
145    /// Ensure the promised low RAM consumption.
146    #[test]
147    fn test_ram_consumption() {
148        // Regular debouncers
149        assert_eq!(
150            std::mem::size_of_val(&SmallPinDebouncer::new(2, PinState::Low)),
151            4
152        );
153        assert_eq!(
154            std::mem::size_of_val(&SmallPinDebouncer::new(8, PinState::Low)),
155            4
156        );
157        assert_eq!(
158            std::mem::size_of_val(&SmallPinDebouncer::new(9, PinState::Low)),
159            4
160        );
161        assert_eq!(
162            std::mem::size_of_val(&SmallPinDebouncer::new(16, PinState::Low)),
163            4
164        );
165    }
166
167    /// Ensure that the initial state can be specified.
168    #[test]
169    fn test_initial_state() {
170        let mut debouncer_01 = SmallPinDebouncer::new(2, PinState::Low);
171        assert_eq!(debouncer_01.update(PinState::Low), None);
172        assert_eq!(debouncer_01.update(PinState::Low), None);
173        assert_eq!(debouncer_01.update(PinState::High), None);
174        assert_eq!(
175            debouncer_01.update(PinState::High),
176            Some(Edge::new(PinState::Low, PinState::High))
177        );
178
179        let mut debouncer_02 = SmallPinDebouncer::new(2, PinState::Low);
180        assert_eq!(debouncer_02.update(PinState::High), None);
181        assert_eq!(
182            debouncer_02.update(PinState::High),
183            Some(Edge::new(PinState::Low, PinState::High))
184        );
185        assert_eq!(debouncer_02.update(PinState::Low), None);
186        assert_eq!(
187            debouncer_02.update(PinState::Low),
188            Some(Edge::new(PinState::High, PinState::Low))
189        );
190
191        let mut debouncer_03 = SmallPinDebouncer::new(2, PinState::High);
192        assert_eq!(debouncer_03.update(PinState::Low), None);
193        assert_eq!(
194            debouncer_03.update(PinState::Low),
195            Some(Edge::new(PinState::High, PinState::Low))
196        );
197        assert_eq!(debouncer_03.update(PinState::High), None);
198        assert_eq!(
199            debouncer_03.update(PinState::High),
200            Some(Edge::new(PinState::Low, PinState::High))
201        );
202
203        let mut debouncer_04 = SmallPinDebouncer::new(2, PinState::High);
204        assert_eq!(debouncer_04.update(PinState::High), None);
205        assert_eq!(debouncer_04.update(PinState::High), None);
206        assert_eq!(debouncer_04.update(PinState::Low), None);
207        assert_eq!(
208            debouncer_04.update(PinState::Low),
209            Some(Edge::new(PinState::High, PinState::Low))
210        );
211    }
212
213    #[test]
214    fn test_long_running_02() {
215        let mut debouncer: SmallPinDebouncer = SmallPinDebouncer::new(2, PinState::Low);
216        assert_eq!(debouncer.update(PinState::High), None);
217        assert_eq!(
218            debouncer.update(PinState::High),
219            Some(Edge::new(PinState::Low, PinState::High))
220        );
221        assert_eq!(debouncer.update(PinState::High), None);
222        assert_eq!(debouncer.update(PinState::High), None);
223        assert_eq!(debouncer.update(PinState::Low), None);
224        assert_eq!(
225            debouncer.update(PinState::Low),
226            Some(Edge::new(PinState::High, PinState::Low))
227        );
228        assert_eq!(debouncer.update(PinState::High), None);
229        assert_eq!(debouncer.update(PinState::Low), None);
230        assert_eq!(debouncer.update(PinState::Low), None);
231        assert_eq!(debouncer.update(PinState::Low), None);
232        assert_eq!(debouncer.update(PinState::High), None);
233        assert_eq!(
234            debouncer.update(PinState::High),
235            Some(Edge::new(PinState::Low, PinState::High))
236        );
237        assert_eq!(debouncer.update(PinState::High), None);
238        assert_eq!(debouncer.update(PinState::High), None);
239        assert_eq!(debouncer.update(PinState::Low), None);
240        assert_eq!(
241            debouncer.update(PinState::Low),
242            Some(Edge::new(PinState::High, PinState::Low))
243        );
244        assert_eq!(debouncer.update(PinState::High), None);
245        assert_eq!(
246            debouncer.update(PinState::High),
247            Some(Edge::new(PinState::Low, PinState::High))
248        );
249        assert_eq!(debouncer.update(PinState::High), None);
250        assert_eq!(debouncer.update(PinState::Low), None);
251        assert_eq!(
252            debouncer.update(PinState::Low),
253            Some(Edge::new(PinState::High, PinState::Low))
254        );
255        assert_eq!(debouncer.update(PinState::Low), None);
256        assert_eq!(debouncer.update(PinState::High), None);
257        assert_eq!(debouncer.update(PinState::Low), None);
258        assert_eq!(debouncer.update(PinState::High), None);
259        assert_eq!(debouncer.update(PinState::Low), None);
260        assert_eq!(debouncer.update(PinState::High), None);
261        assert_eq!(debouncer.update(PinState::Low), None);
262        assert_eq!(debouncer.update(PinState::High), None);
263        assert_eq!(debouncer.update(PinState::Low), None);
264        assert_eq!(debouncer.update(PinState::High), None);
265        assert_eq!(
266            debouncer.update(PinState::High),
267            Some(Edge::new(PinState::Low, PinState::High))
268        );
269        assert_eq!(debouncer.update(PinState::High), None);
270        assert_eq!(debouncer.update(PinState::High), None);
271        assert_eq!(debouncer.update(PinState::Low), None);
272        assert_eq!(
273            debouncer.update(PinState::Low),
274            Some(Edge::new(PinState::High, PinState::Low))
275        );
276        assert_eq!(debouncer.update(PinState::High), None);
277        assert_eq!(
278            debouncer.update(PinState::High),
279            Some(Edge::new(PinState::Low, PinState::High))
280        );
281        assert_eq!(debouncer.update(PinState::Low), None);
282        assert_eq!(
283            debouncer.update(PinState::Low),
284            Some(Edge::new(PinState::High, PinState::Low))
285        );
286        assert_eq!(debouncer.update(PinState::High), None);
287        assert_eq!(debouncer.update(PinState::Low), None);
288        assert_eq!(debouncer.update(PinState::High), None);
289        assert_eq!(debouncer.update(PinState::Low), None);
290        assert_eq!(debouncer.update(PinState::High), None);
291        assert_eq!(debouncer.update(PinState::Low), None);
292        assert_eq!(debouncer.update(PinState::High), None);
293        assert_eq!(
294            debouncer.update(PinState::High),
295            Some(Edge::new(PinState::Low, PinState::High))
296        );
297        assert_eq!(debouncer.update(PinState::High), None);
298        assert_eq!(debouncer.update(PinState::Low), None);
299        assert_eq!(
300            debouncer.update(PinState::Low),
301            Some(Edge::new(PinState::High, PinState::Low))
302        );
303        assert_eq!(debouncer.update(PinState::Low), None);
304        assert_eq!(debouncer.update(PinState::Low), None);
305        assert_eq!(debouncer.update(PinState::Low), None);
306        assert_eq!(debouncer.update(PinState::Low), None);
307        assert_eq!(debouncer.update(PinState::High), None);
308        assert_eq!(
309            debouncer.update(PinState::High),
310            Some(Edge::new(PinState::Low, PinState::High))
311        );
312        assert_eq!(debouncer.update(PinState::High), None);
313        assert_eq!(debouncer.update(PinState::High), None);
314        assert_eq!(debouncer.update(PinState::Low), None);
315        assert_eq!(
316            debouncer.update(PinState::Low),
317            Some(Edge::new(PinState::High, PinState::Low))
318        );
319        assert_eq!(debouncer.update(PinState::Low), None);
320        assert_eq!(debouncer.update(PinState::High), None);
321        assert_eq!(
322            debouncer.update(PinState::High),
323            Some(Edge::new(PinState::Low, PinState::High))
324        );
325        assert_eq!(debouncer.update(PinState::Low), None);
326        assert_eq!(
327            debouncer.update(PinState::Low),
328            Some(Edge::new(PinState::High, PinState::Low))
329        );
330        assert_eq!(debouncer.update(PinState::Low), None);
331        assert_eq!(debouncer.update(PinState::Low), None);
332        assert_eq!(debouncer.update(PinState::High), None);
333        assert_eq!(debouncer.update(PinState::Low), None);
334        assert_eq!(debouncer.update(PinState::High), None);
335        assert_eq!(debouncer.update(PinState::Low), None);
336        assert_eq!(debouncer.update(PinState::Low), None);
337        assert_eq!(debouncer.update(PinState::Low), None);
338        assert_eq!(debouncer.update(PinState::High), None);
339        assert_eq!(
340            debouncer.update(PinState::High),
341            Some(Edge::new(PinState::Low, PinState::High))
342        );
343        assert_eq!(debouncer.update(PinState::Low), None);
344        assert_eq!(debouncer.update(PinState::High), None);
345        assert_eq!(debouncer.update(PinState::High), None);
346        assert_eq!(debouncer.update(PinState::Low), None);
347        assert_eq!(debouncer.update(PinState::High), None);
348        assert_eq!(debouncer.update(PinState::High), None);
349        assert_eq!(debouncer.update(PinState::Low), None);
350        assert_eq!(
351            debouncer.update(PinState::Low),
352            Some(Edge::new(PinState::High, PinState::Low))
353        );
354        assert_eq!(debouncer.update(PinState::High), None);
355        assert_eq!(
356            debouncer.update(PinState::High),
357            Some(Edge::new(PinState::Low, PinState::High))
358        );
359        assert_eq!(debouncer.update(PinState::High), None);
360        assert_eq!(debouncer.update(PinState::Low), None);
361        assert_eq!(
362            debouncer.update(PinState::Low),
363            Some(Edge::new(PinState::High, PinState::Low))
364        );
365        assert_eq!(debouncer.update(PinState::Low), None);
366        assert_eq!(debouncer.update(PinState::High), None);
367        assert_eq!(debouncer.update(PinState::Low), None);
368        assert_eq!(debouncer.update(PinState::Low), None);
369        assert_eq!(debouncer.update(PinState::Low), None);
370        assert_eq!(debouncer.update(PinState::Low), None);
371        assert_eq!(debouncer.update(PinState::Low), None);
372        assert_eq!(debouncer.update(PinState::High), None);
373        assert_eq!(debouncer.update(PinState::Low), None);
374        assert_eq!(debouncer.update(PinState::High), None);
375    }
376
377    #[test]
378    fn test_long_running_04() {
379        let mut debouncer: SmallPinDebouncer = SmallPinDebouncer::new(4, PinState::Low);
380        assert_eq!(debouncer.update(PinState::High), None);
381        assert_eq!(debouncer.update(PinState::High), None);
382        assert_eq!(debouncer.update(PinState::High), None);
383        assert_eq!(
384            debouncer.update(PinState::High),
385            Some(Edge::new(PinState::Low, PinState::High))
386        );
387        assert_eq!(debouncer.update(PinState::Low), None);
388        assert_eq!(debouncer.update(PinState::Low), None);
389        assert_eq!(debouncer.update(PinState::High), None);
390        assert_eq!(debouncer.update(PinState::Low), None);
391        assert_eq!(debouncer.update(PinState::Low), None);
392        assert_eq!(debouncer.update(PinState::Low), None);
393        assert_eq!(debouncer.update(PinState::High), None);
394        assert_eq!(debouncer.update(PinState::High), None);
395        assert_eq!(debouncer.update(PinState::High), None);
396        assert_eq!(debouncer.update(PinState::High), None);
397        assert_eq!(debouncer.update(PinState::Low), None);
398        assert_eq!(debouncer.update(PinState::Low), None);
399        assert_eq!(debouncer.update(PinState::High), None);
400        assert_eq!(debouncer.update(PinState::High), None);
401        assert_eq!(debouncer.update(PinState::High), None);
402        assert_eq!(debouncer.update(PinState::Low), None);
403        assert_eq!(debouncer.update(PinState::Low), None);
404        assert_eq!(debouncer.update(PinState::Low), None);
405        assert_eq!(debouncer.update(PinState::High), None);
406        assert_eq!(debouncer.update(PinState::Low), None);
407        assert_eq!(debouncer.update(PinState::High), None);
408        assert_eq!(debouncer.update(PinState::Low), None);
409        assert_eq!(debouncer.update(PinState::High), None);
410        assert_eq!(debouncer.update(PinState::Low), None);
411        assert_eq!(debouncer.update(PinState::High), None);
412        assert_eq!(debouncer.update(PinState::Low), None);
413        assert_eq!(debouncer.update(PinState::High), None);
414        assert_eq!(debouncer.update(PinState::High), None);
415        assert_eq!(debouncer.update(PinState::High), None);
416        assert_eq!(debouncer.update(PinState::High), None);
417        assert_eq!(debouncer.update(PinState::Low), None);
418        assert_eq!(debouncer.update(PinState::Low), None);
419        assert_eq!(debouncer.update(PinState::High), None);
420        assert_eq!(debouncer.update(PinState::High), None);
421        assert_eq!(debouncer.update(PinState::Low), None);
422        assert_eq!(debouncer.update(PinState::Low), None);
423        assert_eq!(debouncer.update(PinState::High), None);
424        assert_eq!(debouncer.update(PinState::Low), None);
425        assert_eq!(debouncer.update(PinState::High), None);
426        assert_eq!(debouncer.update(PinState::Low), None);
427        assert_eq!(debouncer.update(PinState::High), None);
428        assert_eq!(debouncer.update(PinState::Low), None);
429        assert_eq!(debouncer.update(PinState::High), None);
430        assert_eq!(debouncer.update(PinState::High), None);
431        assert_eq!(debouncer.update(PinState::High), None);
432        assert_eq!(debouncer.update(PinState::Low), None);
433        assert_eq!(debouncer.update(PinState::Low), None);
434        assert_eq!(debouncer.update(PinState::Low), None);
435        assert_eq!(
436            debouncer.update(PinState::Low),
437            Some(Edge::new(PinState::High, PinState::Low))
438        );
439        assert_eq!(debouncer.update(PinState::Low), None);
440        assert_eq!(debouncer.update(PinState::Low), None);
441        assert_eq!(debouncer.update(PinState::High), None);
442        assert_eq!(debouncer.update(PinState::High), None);
443        assert_eq!(debouncer.update(PinState::High), None);
444        assert_eq!(
445            debouncer.update(PinState::High),
446            Some(Edge::new(PinState::Low, PinState::High))
447        );
448        assert_eq!(debouncer.update(PinState::Low), None);
449        assert_eq!(debouncer.update(PinState::Low), None);
450        assert_eq!(debouncer.update(PinState::Low), None);
451        assert_eq!(debouncer.update(PinState::High), None);
452        assert_eq!(debouncer.update(PinState::High), None);
453        assert_eq!(debouncer.update(PinState::Low), None);
454        assert_eq!(debouncer.update(PinState::Low), None);
455        assert_eq!(debouncer.update(PinState::Low), None);
456        assert_eq!(
457            debouncer.update(PinState::Low),
458            Some(Edge::new(PinState::High, PinState::Low))
459        );
460        assert_eq!(debouncer.update(PinState::High), None);
461        assert_eq!(debouncer.update(PinState::Low), None);
462        assert_eq!(debouncer.update(PinState::High), None);
463        assert_eq!(debouncer.update(PinState::Low), None);
464        assert_eq!(debouncer.update(PinState::Low), None);
465        assert_eq!(debouncer.update(PinState::Low), None);
466        assert_eq!(debouncer.update(PinState::High), None);
467        assert_eq!(debouncer.update(PinState::High), None);
468        assert_eq!(debouncer.update(PinState::Low), None);
469        assert_eq!(debouncer.update(PinState::High), None);
470        assert_eq!(debouncer.update(PinState::High), None);
471        assert_eq!(debouncer.update(PinState::Low), None);
472        assert_eq!(debouncer.update(PinState::High), None);
473        assert_eq!(debouncer.update(PinState::High), None);
474        assert_eq!(debouncer.update(PinState::Low), None);
475        assert_eq!(debouncer.update(PinState::Low), None);
476        assert_eq!(debouncer.update(PinState::High), None);
477        assert_eq!(debouncer.update(PinState::High), None);
478        assert_eq!(debouncer.update(PinState::High), None);
479        assert_eq!(debouncer.update(PinState::Low), None);
480        assert_eq!(debouncer.update(PinState::Low), None);
481        assert_eq!(debouncer.update(PinState::Low), None);
482        assert_eq!(debouncer.update(PinState::High), None);
483        assert_eq!(debouncer.update(PinState::Low), None);
484        assert_eq!(debouncer.update(PinState::Low), None);
485        assert_eq!(debouncer.update(PinState::Low), None);
486        assert_eq!(debouncer.update(PinState::Low), None);
487        assert_eq!(debouncer.update(PinState::Low), None);
488        assert_eq!(debouncer.update(PinState::High), None);
489        assert_eq!(debouncer.update(PinState::Low), None);
490        assert_eq!(debouncer.update(PinState::High), None);
491    }
492}