keyberon_smart_keyboard/
matrix.rs

1//! Hardware pin switch matrix handling.
2
3use core::fmt::Debug;
4
5use embedded_hal::delay::DelayNs;
6use embedded_hal::digital::{InputPin, OutputPin};
7
8/// Newtype wrapper around [keyberon::matrix::DirectPinMatrix]
9///  to implement [crate::input::MatrixScanner] for it.
10pub struct DirectPinMatrix<P: InputPin, const CS: usize, const RS: usize>(
11    pub keyberon::matrix::DirectPinMatrix<P, CS, RS>,
12);
13
14impl<P, const CS: usize, const RS: usize, E: Debug> DirectPinMatrix<P, CS, RS>
15where
16    P: InputPin<Error = E>,
17{
18    pub fn new(pins: [[Option<P>; CS]; RS]) -> Self
19    where
20        P: InputPin<Error = E>,
21    {
22        Self(keyberon::matrix::DirectPinMatrix::new(pins).unwrap())
23    }
24}
25
26impl<P, const CS: usize, const RS: usize> crate::input::MatrixScanner<CS, RS>
27    for DirectPinMatrix<P, CS, RS>
28where
29    P: InputPin<Error = core::convert::Infallible>,
30{
31    fn is_boot_key_pressed(&mut self) -> bool {
32        self.0.get().unwrap()[0][0]
33    }
34
35    fn get(&mut self) -> Result<[[bool; CS]; RS], core::convert::Infallible> {
36        self.0.get()
37    }
38}
39
40/// Describes the hardware-level matrix of switches.
41///
42/// Generic parameters are in order: The type of column pins,
43/// the type of row pins, the number of columns and rows.
44/// **NOTE:** In order to be able to put different pin structs
45/// in an array they have to be downgraded (stripped of their
46/// numbers etc.). Most HAL-s have a method of downgrading pins
47/// to a common (erased) struct. (for example see
48/// [stm32f0xx_hal::gpio::PA0::downgrade](https://docs.rs/stm32f0xx-hal/0.17.1/stm32f0xx_hal/gpio/gpioa/struct.PA0.html#method.downgrade))
49///
50/// TIM5 is used to provide a delay during the matrix scanning.
51pub struct Matrix<C, R, const CS: usize, const RS: usize, D>
52where
53    C: InputPin,
54    R: OutputPin,
55    D: DelayNs,
56{
57    cols: [C; CS],
58    rows: [R; RS],
59    delay: D,
60    select_delay_us: u32,
61    unselect_delay_us: u32,
62}
63
64impl<C, R, const CS: usize, const RS: usize, D> Matrix<C, R, CS, RS, D>
65where
66    C: InputPin,
67    R: OutputPin,
68    D: DelayNs,
69{
70    /// Creates a new Matrix.
71    ///
72    /// Assumes columns are pull-up inputs,
73    /// and rows are output pins which are set high when not being scanned.
74    pub fn new<E>(
75        cols: [C; CS],
76        rows: [R; RS],
77        delay: D,
78        select_delay_us: u32,
79        unselect_delay_us: u32,
80    ) -> Result<Self, E>
81    where
82        C: InputPin<Error = E>,
83        R: OutputPin<Error = E>,
84    {
85        let mut res = Self {
86            cols,
87            rows,
88            delay,
89            select_delay_us,
90            unselect_delay_us,
91        };
92        res.clear()?;
93        Ok(res)
94    }
95    fn clear<E>(&mut self) -> Result<(), E>
96    where
97        C: InputPin<Error = E>,
98        R: OutputPin<Error = E>,
99    {
100        for r in self.rows.iter_mut() {
101            r.set_high()?;
102        }
103        Ok(())
104    }
105}
106
107impl<C, R, const CS: usize, const RS: usize, D, E: Debug> crate::input::MatrixScanner<CS, RS, E>
108    for Matrix<C, R, CS, RS, D>
109where
110    C: InputPin<Error = E>,
111    R: OutputPin<Error = E>,
112    D: DelayNs,
113{
114    fn is_boot_key_pressed(&mut self) -> bool {
115        self.rows[0].set_low().unwrap();
116        self.delay.delay_us(self.select_delay_us);
117
118        let is_pressed = self.cols[0].is_low().unwrap();
119
120        self.rows[0].set_high().unwrap();
121        self.delay.delay_us(self.unselect_delay_us);
122
123        is_pressed
124    }
125
126    /// Scans the matrix and checks which keys are pressed.
127    ///
128    /// Every row pin in order is pulled low, and then each column
129    /// pin is tested; if it's low, the key is marked as pressed.
130    ///
131    /// Delays for a bit after setting each pin, and after clearing
132    /// each pin.
133    fn get(&mut self) -> Result<[[bool; CS]; RS], E> {
134        let mut keys = [[false; CS]; RS];
135
136        for (ri, row) in self.rows.iter_mut().enumerate() {
137            row.set_low()?;
138            // Delay after setting the pin low.
139            // Using a timer for this is probably overkill.
140            self.delay.delay_us(self.select_delay_us);
141            for (ci, col) in self.cols.iter_mut().enumerate() {
142                if col.is_low()? {
143                    keys[ri][ci] = true;
144                }
145            }
146            row.set_high()?;
147            // Delay after setting the pin high.
148            // Using a timer for this is probably overkill.
149            self.delay.delay_us(self.unselect_delay_us);
150        }
151        Ok(keys)
152    }
153}