~ruther/simple-clock

ref: 789aeecec296d7d3301509d32153022927ff33e4 simple-clock/src/button.rs -rw-r--r-- 2.2 KiB
789aeece — František Boháček feat(src): add basic button representation 1 year, 8 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
use core::convert::Infallible;

use alloc::boxed::Box;
use core::marker::PhantomData;
use embedded_hal::digital::v2::InputPin;

pub struct ActiveHigh;
pub struct ActiveLow;

const DEBOUNCE: u8 = 2;
const LONG_PRESS: u8 = 5;

#[derive(PartialEq, Eq)]
pub enum ButtonState {
    Off,
    JustPressed,
    LongPress,
    Click,
    DoubleClick,
    Released,
}

pub struct Button<ActiveLevel> {
    pin: Box<dyn InputPin<Error = Infallible>>,
    debounce: u8,
    prev_state: bool,
    level: PhantomData<ActiveLevel>,
}

pub trait ActiveLevel {
    fn raw_is_pressed(pin_state: bool) -> bool;
}

impl ActiveLevel for ActiveHigh {
    fn raw_is_pressed(pin_state: bool) -> bool {
        pin_state
    }
}

impl ActiveLevel for ActiveLow {
    fn raw_is_pressed(pin_state: bool) -> bool {
        !pin_state
    }
}

impl<ACTIVELEVEL: ActiveLevel> Button<ACTIVELEVEL> {
    pub fn new(pin: Box<dyn InputPin<Error = Infallible>>) -> Self {
        Self {
            pin,
            debounce: 0,
            prev_state: false,
            level: PhantomData::<ACTIVELEVEL>,
        }
    }

    pub fn raw_is_pressed(&self) -> bool {
        ACTIVELEVEL::raw_is_pressed(self.pin.is_high().unwrap())
    }

    pub fn is_just_pressed(&self) -> bool {
        self.raw_is_pressed() && self.debounce == DEBOUNCE
    }

    pub fn is_pressed(&self) -> bool {
        self.raw_is_pressed() && self.debounce >= DEBOUNCE
    }

    pub fn is_long_pressed(&self) -> bool {
        self.raw_is_pressed() && self.debounce >= LONG_PRESS
    }

    pub fn state(&self) -> ButtonState {
        if !self.raw_is_pressed() {
            ButtonState::Off
        } else if self.is_just_pressed() {
            ButtonState::JustPressed
        } else if self.is_long_pressed() {
            ButtonState::LongPress
        } else {
            ButtonState::Off
        }
    }

    pub fn update(&mut self) {
        let raw_pressed = self.raw_is_pressed();

        if raw_pressed != self.prev_state {
            self.debounce = 0;
        } else if self.debounce < u8::MAX {
            self.debounce += 1;
        }

        self.prev_state = raw_pressed;
    }

    pub fn reset() {
        // resets is_clicked etc.
    }
}
Do not follow this link