rktk_drivers_common/keyscan/
duplex_matrix.rs1use super::{
4 flex_pin::{FlexPin, Pull},
5 pressed::Pressed,
6};
7use embassy_time::Duration;
8use rktk::drivers::interface::keyscan::{KeyChangeEvent, KeyscanDriver};
9
10#[derive(Clone, Copy)]
18pub enum OutputWait {
19 Pin,
20 Time(Duration),
21}
22
23pub struct DuplexMatrixScanner<
25 F: FlexPin,
26 T: Fn(ScanDir, usize, usize) -> Option<(usize, usize)>,
27 const ROW_PIN_COUNT: usize,
28 const COL_PIN_COUNT: usize,
29 const ROWS: usize,
30 const COLS: usize,
31> {
32 rows: [F; ROW_PIN_COUNT],
33 cols: [F; COL_PIN_COUNT],
34 pressed: Pressed<ROWS, COLS>,
35 output_wait: OutputWait,
36 map_key_pos: T,
37}
38
39impl<
40 F: FlexPin,
41 T: Fn(ScanDir, usize, usize) -> Option<(usize, usize)>,
42 const ROW_PIN_COUNT: usize,
43 const COL_PIN_COUNT: usize,
44 const ROWS: usize,
45 const COLS: usize,
46> DuplexMatrixScanner<F, T, ROW_PIN_COUNT, COL_PIN_COUNT, ROWS, COLS>
47{
48 pub fn new(
60 rows: [F; ROW_PIN_COUNT],
61 cols: [F; COL_PIN_COUNT],
62 output_wait: Option<OutputWait>,
63 translate_key_position: T,
64 ) -> Self {
65 Self {
66 rows,
67 cols,
68 pressed: Pressed::new(),
69 output_wait: output_wait.unwrap_or(OutputWait::Time(Duration::from_micros(20))),
70 map_key_pos: translate_key_position,
71 }
72 }
73
74 async fn wait_for_low(output_wait: OutputWait, pin: &mut F) {
75 match output_wait {
76 OutputWait::Pin => {
77 pin.wait_for_low().await;
78 }
79 OutputWait::Time(duration) => {
80 embassy_time::Timer::after(duration).await;
81 }
82 }
83 }
84
85 async fn wait_for_high(output_wait: OutputWait, pin: &mut F) {
86 match output_wait {
87 OutputWait::Pin => {
88 pin.wait_for_high().await;
89 }
90 OutputWait::Time(duration) => {
91 embassy_time::Timer::after(duration).await;
92 }
93 }
94 }
95
96 async fn scan_dir(
101 outputs: &mut [F],
102 inputs: &mut [F],
103 output_wait: OutputWait,
104 mut cb: impl FnMut(usize, usize, bool),
105 ) {
106 for output in outputs.iter_mut() {
107 output.set_low();
108 }
109 for inputs in inputs.iter_mut() {
110 inputs.set_pull(Pull::Down);
111 inputs.set_as_input();
112 }
113
114 embassy_time::Timer::after_micros(20).await;
115
116 for (o_i, output) in outputs.iter_mut().enumerate() {
117 output.set_high();
118 output.set_as_output();
119 Self::wait_for_high(output_wait, output).await;
120
121 for (i_i, input) in inputs.iter_mut().enumerate() {
122 cb(o_i, i_i, input.is_high());
123 }
124
125 output.set_low();
126 Self::wait_for_low(output_wait, output).await;
127 output.set_as_input();
128 }
129 }
130}
131
132impl<
133 F: FlexPin,
134 T: Fn(ScanDir, usize, usize) -> Option<(usize, usize)>,
135 const ROW_PIN_COUNT: usize,
136 const COL_PIN_COUNT: usize,
137 const ROWS: usize,
138 const COLS: usize,
139> KeyscanDriver for DuplexMatrixScanner<F, T, ROW_PIN_COUNT, COL_PIN_COUNT, ROWS, COLS>
140{
141 type CalibrationError = core::convert::Infallible;
142
143 async fn scan(&mut self, mut cb: impl FnMut(KeyChangeEvent)) {
144 Self::scan_dir(
145 &mut self.rows,
146 &mut self.cols,
147 self.output_wait,
148 |row_pin_idx, col_pin_idx, pressed| {
149 if let Some((row, col)) =
150 (self.map_key_pos)(ScanDir::Row2Col, row_pin_idx, col_pin_idx)
151 && let Some(change) = self.pressed.set_pressed(pressed, row, col)
152 {
153 cb(KeyChangeEvent { row: row as u8, col: col as u8, pressed: change });
154 }
155 },
156 )
157 .await;
158
159 Self::scan_dir(
160 &mut self.cols,
161 &mut self.rows,
162 self.output_wait,
163 |col_pin_idx, row_pin_idx, pressed| {
164 if let Some((row, col)) =
165 (self.map_key_pos)(ScanDir::Col2Row, row_pin_idx, col_pin_idx)
166 && let Some(change) = self.pressed.set_pressed(pressed, row, col)
167 {
168 cb(KeyChangeEvent { row: row as u8, col: col as u8, pressed: change });
169 }
170 },
171 )
172 .await;
173 }
174}
175
176#[derive(Clone, Copy, PartialEq, Eq, Debug)]
177pub enum ScanDir {
178 Col2Row,
179 Row2Col,
180}