Skip to main content

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]) -> Result<Self, E>
19    where
20        P: InputPin<Error = E>,
21    {
22        keyberon::matrix::DirectPinMatrix::new(pins).map(Self)
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().ok().is_some_and(|keys| keys[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:
43///  The type of column pins,
44///  the type of row pins,
45///  the number of columns and rows.
46///
47/// **NOTE:**
48/// In order to be able to put different pin structs in an array
49///  they have to be downgraded (stripped of their numbers etc.).
50/// Most HAL-s have a method of downgrading pins to a common (erased) struct.
51/// (For example see
52/// [stm32f0xx_hal::gpio::PA0::downgrade](https://docs.rs/stm32f0xx-hal/0.17.1/stm32f0xx_hal/gpio/gpioa/struct.PA0.html#method.downgrade))
53///
54/// TIM5 is used to provide a delay during the matrix scanning.
55pub struct Matrix<C, R, const CS: usize, const RS: usize, D>
56where
57    C: InputPin,
58    R: OutputPin,
59    D: DelayNs,
60{
61    cols: [C; CS],
62    rows: [R; RS],
63    delay: D,
64    select_delay_us: u32,
65    unselect_delay_us: u32,
66}
67
68impl<C, R, const CS: usize, const RS: usize, D> Matrix<C, R, CS, RS, D>
69where
70    C: InputPin,
71    R: OutputPin,
72    D: DelayNs,
73{
74    /// Creates a new Matrix.
75    ///
76    /// Assumes columns are pull-up inputs,
77    ///  and rows are output pins
78    ///  which are set high when not being scanned.
79    pub fn new<E>(
80        cols: [C; CS],
81        rows: [R; RS],
82        delay: D,
83        select_delay_us: u32,
84        unselect_delay_us: u32,
85    ) -> Result<Self, E>
86    where
87        C: InputPin<Error = E>,
88        R: OutputPin<Error = E>,
89    {
90        let mut res = Self {
91            cols,
92            rows,
93            delay,
94            select_delay_us,
95            unselect_delay_us,
96        };
97        res.clear()?;
98        Ok(res)
99    }
100    fn clear<E>(&mut self) -> Result<(), E>
101    where
102        C: InputPin<Error = E>,
103        R: OutputPin<Error = E>,
104    {
105        for r in self.rows.iter_mut() {
106            r.set_high()?;
107        }
108        Ok(())
109    }
110}
111
112impl<C, R, const CS: usize, const RS: usize, D, E: Debug> crate::input::MatrixScanner<CS, RS, E>
113    for Matrix<C, R, CS, RS, D>
114where
115    C: InputPin<Error = E>,
116    R: OutputPin<Error = E>,
117    D: DelayNs,
118{
119    fn is_boot_key_pressed(&mut self) -> bool {
120        let Ok(()) = self.rows[0].set_low() else {
121            return false;
122        };
123        self.delay.delay_us(self.select_delay_us);
124
125        let is_pressed = self.cols[0].is_low().unwrap_or(false);
126
127        let _ = self.rows[0].set_high();
128        self.delay.delay_us(self.unselect_delay_us);
129
130        is_pressed
131    }
132
133    /// Scans the matrix and checks which keys are pressed.
134    ///
135    /// Every row pin in order is pulled low,
136    ///  and then each column pin is tested;
137    /// if it's low, the key is marked as pressed.
138    ///
139    /// Delays for a bit after setting each pin,
140    ///  and after clearing each pin.
141    fn get(&mut self) -> Result<[[bool; CS]; RS], E> {
142        let mut keys = [[false; CS]; RS];
143
144        for (ri, row) in self.rows.iter_mut().enumerate() {
145            row.set_low()?;
146            // Delay after setting the pin low.
147            // Using a timer for this is probably overkill.
148            self.delay.delay_us(self.select_delay_us);
149            for (ci, col) in self.cols.iter_mut().enumerate() {
150                if col.is_low()? {
151                    keys[ri][ci] = true;
152                }
153            }
154            row.set_high()?;
155            // Delay after setting the pin high.
156            // Using a timer for this is probably overkill.
157            self.delay.delay_us(self.unselect_delay_us);
158        }
159        Ok(keys)
160    }
161}