~ruther/avr-guess-the-number

ref: d496c1b47a62846703277a36d073c601511bb501 avr-guess-the-number/src/button.rs -rw-r--r-- 4.0 KiB
d496c1b4 — František Boháček feat: add avr-device lib 2 years 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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
use atmega_hal::port::{Pin, mode};

#[derive(PartialEq, Eq)]
pub enum ButtonState {
    Inactive, // button is not pressed and the state is same from last time
    Active, // button is pressed and the state is same from last time
    Pressed, // The button was just pressed
    Released // The button was just released
}

#[derive(Copy, Clone, PartialEq, Eq)]
pub enum ButtonEvent {
    Click,
    LongClick,
    LongClickContinuous,
    DoubleClick,
    None
}

const DEBOUNCECYCLES: u8 = 50;

const PRESSED_FOR_MAX: u16 = 65000;
const RELEASED_FOR_MAX: u16 = 65000;

const PRESSED_FOR_LONG: u16 = 1000;
const RELEASED_FOR_DOUBLE_CLICK: u16 = 1000;

pub struct Button {
    input: Pin<mode::Input>,
    active_high: bool,
    last_active: bool,
    active: bool,
    integrator: u8,

    pressed_for: u16,
    released_for: u16,

    last_event: ButtonEvent,
}

impl Button {
    pub fn create(input: Pin<mode::Input>, active_high: bool) -> Button {
        Button {
            input,
            active_high,
            last_active: false,
            active: false,
            integrator: 0,
            pressed_for: 0,
            released_for: 0,
            last_event: ButtonEvent::None
        }
    }

    pub fn step(&mut self) {
        let mut btn_active = self.input.is_low();
        if self.active_high {
            btn_active = !btn_active;
        }

        if !btn_active {
            if self.integrator > 0 {
                self.integrator -= 1;
            }
        } else if self.integrator < DEBOUNCECYCLES {
            self.integrator += 1;
        }

        let last_active = self.active;
        self.active = self.pressed();

        if !last_active && self.active {
            self.pressed_for = 0;
        } else if last_active && !self.active {
            self.released_for = 0;
        }

        if self.active {
            if self.pressed_for < PRESSED_FOR_MAX {
                self.pressed_for += 1;
            }
        }
        else {
            if self.released_for < RELEASED_FOR_MAX {
                self.released_for += 1;
            }
        }

        // just pressed and was released just for time it could be double click
        // fire double click right away
        // that is different to normal click. Normal clicks fire after release,
        // double click fires right after the second press
        if self.active && self.pressed_for == 1 && self.released_for < RELEASED_FOR_DOUBLE_CLICK {
            self.last_event = ButtonEvent::DoubleClick;
            self.pressed_for += 1;
        }

        // is a long click, fire event until released
        if self.active && self.pressed_for == PRESSED_FOR_LONG {
            self.last_event = ButtonEvent::LongClick;
        }
        else if self.active && self.pressed_for % PRESSED_FOR_LONG == 0 && self.last_event == ButtonEvent::None {
            self.last_event = ButtonEvent::LongClickContinuous;
        }

        // was not long click and period for double click is over
        if self.pressed_for < PRESSED_FOR_LONG && self.pressed_for > 1 && self.released_for == RELEASED_FOR_DOUBLE_CLICK {
            self.last_event = ButtonEvent::Click;
            self.released_for += 1;
        }
    }

    pub fn event(&mut self) -> ButtonEvent {
        let last_event = self.last_event;
        self.last_event = ButtonEvent::None;

        last_event
    }

    fn pressed(&mut self) -> bool{
        if self.integrator == 0 {
            self.last_active = self.active;
            self.active = false;
        } else if self.integrator >= DEBOUNCECYCLES {
            self.integrator = DEBOUNCECYCLES;
            self.last_active = self.active;
            self.active = true;
        }

        self.active
    }

    pub fn state(&self) -> ButtonState {
        if self.active {
            if self.last_active {
                return ButtonState::Active;
            }

            return ButtonState::Pressed;
        }

        if !self.last_active {
            return ButtonState::Inactive;
        }

        return ButtonState::Released;
    }
}
Do not follow this link