-
Notifications
You must be signed in to change notification settings - Fork 79
/
matrix.rs
137 lines (128 loc) · 4.1 KB
/
matrix.rs
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
//! Hardware pin switch matrix handling.
use embedded_hal::digital::{InputPin, OutputPin};
/// Describes the hardware-level matrix of switches.
///
/// Generic parameters are in order: The type of column pins,
/// the type of row pins, the number of columns and rows.
/// **NOTE:** In order to be able to put different pin structs
/// in an array they have to be downgraded (stripped of their
/// numbers etc.). Most HAL-s have a method of downgrading pins
/// to a common (erased) struct. (for example see
/// [stm32f0xx_hal::gpio::PA0::downgrade](https://docs.rs/stm32f0xx-hal/0.17.1/stm32f0xx_hal/gpio/gpioa/struct.PA0.html#method.downgrade))
pub struct Matrix<C, R, const CS: usize, const RS: usize>
where
C: InputPin,
R: OutputPin,
{
cols: [C; CS],
rows: [R; RS],
}
impl<C, R, const CS: usize, const RS: usize> Matrix<C, R, CS, RS>
where
C: InputPin,
R: OutputPin,
{
/// Creates a new Matrix.
///
/// Assumes columns are pull-up inputs,
/// and rows are output pins which are set high when not being scanned.
pub fn new<E>(cols: [C; CS], rows: [R; RS]) -> Result<Self, E>
where
C: InputPin<Error = E>,
R: OutputPin<Error = E>,
{
let mut res = Self { cols, rows };
res.clear()?;
Ok(res)
}
fn clear<E>(&mut self) -> Result<(), E>
where
C: InputPin<Error = E>,
R: OutputPin<Error = E>,
{
for r in self.rows.iter_mut() {
r.set_high()?;
}
Ok(())
}
/// Scans the matrix and checks which keys are pressed.
///
/// Every row pin in order is pulled low, and then each column
/// pin is tested; if it's low, the key is marked as pressed.
/// Scans the pins and checks which keys are pressed (state is "low").
///
/// Delay function allows pause to let input pins settle
pub fn get_with_delay<F: FnMut(), E>(&mut self, mut delay: F) -> Result<[[bool; CS]; RS], E>
where
C: InputPin<Error = E>,
R: OutputPin<Error = E>,
{
let mut keys = [[false; CS]; RS];
for (ri, row) in self.rows.iter_mut().enumerate() {
row.set_low()?;
delay();
for (ci, col) in self.cols.iter_mut().enumerate() {
if col.is_low()? {
keys[ri][ci] = true;
}
}
row.set_high()?;
}
Ok(keys)
}
/// Scans the matrix and checks which keys are pressed.
///
/// Every row pin in order is pulled low, and then each column
/// pin is tested; if it's low, the key is marked as pressed.
/// Scans the pins and checks which keys are pressed (state is "low").
pub fn get<E>(&mut self) -> Result<[[bool; CS]; RS], E>
where
C: InputPin<Error = E>,
R: OutputPin<Error = E>,
{
self.get_with_delay(|| ())
}
}
/// Matrix-representation of switches directly attached to the pins ("diodeless").
///
/// Generic parameters are in order: The type of column pins,
/// the number of columns and rows.
pub struct DirectPinMatrix<P, const CS: usize, const RS: usize>
where
P: InputPin,
{
pins: [[Option<P>; CS]; RS],
}
impl<P, const CS: usize, const RS: usize> DirectPinMatrix<P, CS, RS>
where
P: InputPin,
{
/// Creates a new DirectPinMatrix.
///
/// Assumes pins are pull-up inputs. Spots in the matrix that are
/// not corresponding to any pins use ´None´.
pub fn new<E>(pins: [[Option<P>; CS]; RS]) -> Result<Self, E>
where
P: InputPin<Error = E>,
{
let res = Self { pins };
Ok(res)
}
/// Scans the pins and checks which keys are pressed (state is "low").
pub fn get<E>(&mut self) -> Result<[[bool; CS]; RS], E>
where
P: InputPin<Error = E>,
{
let mut keys = [[false; CS]; RS];
for (ri, row) in self.pins.iter_mut().enumerate() {
for (ci, col_option) in row.iter_mut().enumerate() {
if let Some(col) = col_option {
if col.is_low()? {
keys[ri][ci] = true;
}
}
}
}
Ok(keys)
}
}