1#![cfg_attr(not(test), no_std)]
2
3use embedded_hal::digital::v2::InputPin;
4
5#[derive(Copy, Clone)]
6pub enum ButtonState {
7 Down,
9 Press,
11 Pressing,
13 LongPress,
15 Idle,
17}
18
19pub enum ButtonPull {
22 PullUp,
23 PullDown,
24}
25
26pub struct ButtonConfig {
27 pub pressing_threshold: f32,
28 pub long_press_threshold: f32,
29 pub pull: ButtonPull,
30}
31
32impl Default for ButtonConfig {
33 fn default() -> Self {
34 Self {
35 pressing_threshold: 0.2,
38 long_press_threshold: 2.0,
40 pull: ButtonPull::PullUp,
42 }
43 }
44}
45
46pub struct Button<PIN> {
47 counter: u16,
48 debounced: u8,
49 long_press_threshold: u16,
50 pin: PIN,
51 pressing_threshold: u16,
52 pull: ButtonPull,
53 reset: bool,
54 state: ButtonState,
55}
56
57impl<PIN> Button<PIN>
58where
59 PIN: InputPin,
60{
61 pub fn new(pin: PIN, f_refresh: u16, config: ButtonConfig) -> Self {
62 Self {
63 counter: 0,
64 debounced: 0,
65 long_press_threshold: (f_refresh as f32 / (1.0 / config.long_press_threshold)) as u16,
66 pin,
67 pressing_threshold: (f_refresh as f32 / (1.0 / config.pressing_threshold)) as u16,
68 pull: config.pull,
69 reset: false,
70 state: ButtonState::Idle,
71 }
72 }
73
74 fn raw_state(&self) -> u8 {
75 match (&self.pull, self.pin.is_low()) {
76 (ButtonPull::PullUp, Ok(true)) => 1,
77 (ButtonPull::PullDown, Ok(false)) => 1,
78 _ => 0,
79 }
80 }
81
82 pub fn poll(&mut self) {
83 let state = self.raw_state();
84 self.debounced |= state;
85 if self.debounced > 0 {
87 if self.counter == 0 {
88 self.state = ButtonState::Down;
89 }
90 self.counter = self.counter.wrapping_add(1);
91 if self.counter >= self.pressing_threshold {
93 self.state = ButtonState::Pressing;
94 }
95 if self.counter >= self.long_press_threshold {
96 self.state = ButtonState::LongPress;
97 }
98 if state == 0 {
100 if self.reset {
101 self.state = ButtonState::Idle;
102 self.reset = false;
103 } else if self.counter <= self.pressing_threshold {
104 self.state = ButtonState::Press;
105 } else {
106 self.state = ButtonState::Idle;
107 }
108
109 self.counter = 0;
110 self.debounced = 0;
111 }
112 }
113 }
114
115 pub fn read(&mut self) -> ButtonState {
116 match self.state {
117 ButtonState::Pressing | ButtonState::LongPress | ButtonState::Idle => self.state,
118 _ => {
119 let state = self.state;
120 self.state = ButtonState::Idle;
121 state
122 }
123 }
124 }
125
126 pub fn reset(&mut self) {
127 self.reset = true;
128 }
129}