rmk_q1_pro_iso/matrix/
shiftreg_matrix.rs1use crate::matrix::hc595_cols::Hc595Cols;
4use core::{array::from_fn, hint::cold_path};
5use embassy_stm32::{exti::ExtiInput, mode::Async};
6use embassy_time::{Duration, Timer};
7use rmk::{
8 debounce::{DebounceState, DebouncerTrait as _, default_debouncer::DefaultDebouncer},
9 event::KeyboardEvent,
10 macros::input_device,
11 matrix::KeyState,
12};
13
14pub struct ShiftRegMatrixConfig {
16 col_settle_time: Duration,
18}
19
20impl Default for ShiftRegMatrixConfig {
21 fn default() -> Self { Self { col_settle_time: Duration::from_micros(2) } }
22}
23
24#[derive(Copy, Clone)]
26struct ScanPos {
27 col: usize,
29 row: usize,
31}
32
33impl ScanPos {
34 const fn new(row: usize, col: usize) -> Self { Self { col, row } }
36}
37
38struct KeyGrid<const ROW: usize, const COL: usize> {
40 cells: [[KeyState; COL]; ROW],
42}
43
44impl<const ROW: usize, const COL: usize> KeyGrid<ROW, COL> {
45 #[inline]
48 const fn get_mut(&mut self, row: usize, col: usize) -> Option<&mut KeyState> {
49 match self.cells.get_mut(row) {
50 None => None,
51 Some(row_arr) => row_arr.get_mut(col),
52 }
53 }
54
55 fn new() -> Self { Self { cells: from_fn(|_| from_fn(|_| KeyState { pressed: false })) } }
58}
59
60#[input_device(publish = KeyboardEvent)]
63pub struct ShiftRegMatrix<'peripherals, const ROW: usize, const COL: usize> {
64 cols: Hc595Cols<'peripherals>,
66 debouncer: DefaultDebouncer<ROW, COL>,
68 key_state: KeyGrid<ROW, COL>,
70 rows: [ExtiInput<'peripherals, Async>; ROW],
72 scan_pos: ScanPos,
74 col_settle_delay: Duration,
76}
77
78impl<'peripherals, const ROW: usize, const COL: usize> ShiftRegMatrix<'peripherals, ROW, COL> {
79 pub fn new(
83 rows: [ExtiInput<'peripherals, Async>; ROW],
84 mut cols: Hc595Cols<'peripherals>,
85 config: ShiftRegMatrixConfig,
86 ) -> Self {
87 cols.unselect_all();
88
89 Self {
90 rows,
91 cols,
92 debouncer: DefaultDebouncer::new(),
93 key_state: KeyGrid::new(),
94 scan_pos: ScanPos::new(0, 0),
95 col_settle_delay: config.col_settle_time,
96 }
97 }
98
99 #[optimize(speed)]
104 async fn read_keyboard_event(&mut self) -> KeyboardEvent {
105 loop {
106 if let Some(ev) = self.scan_until_event().await {
107 return ev;
108 }
109 }
110 }
111
112 #[optimize(speed)]
119 async fn scan_until_event(&mut self) -> Option<KeyboardEvent> {
120 let start = self.scan_pos;
121
122 for col in (start.col..COL).chain(0..start.col) {
123 self.cols.select_col(col);
124 Timer::after(self.col_settle_delay).await;
125
126 let r_start = if col == start.col { start.row } else { 0 };
127
128 for (row, row_pin) in self.rows.iter().enumerate().skip(r_start) {
129 let pressed = row_pin.is_low();
130
131 let Some(ks) = self.key_state.get_mut(row, col) else {
132 continue;
133 };
134
135 let st = self.debouncer.detect_change_with_debounce(row, col, pressed, ks);
136 if matches!(st, DebounceState::Debounced) {
137 cold_path();
138 ks.pressed = pressed;
139 self.cols.unselect_all();
140 self.scan_pos = ScanPos::new(row, col);
141 return Some(KeyboardEvent::key(
142 u8::try_from(row).unwrap_or_default(),
143 u8::try_from(col).unwrap_or_default(),
144 pressed,
145 ));
146 }
147 }
148 }
149
150 self.scan_pos = ScanPos::new(0, 0);
151 self.cols.unselect_all();
152 None
153 }
154}