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 async fn scan(&mut self, mut cb: impl FnMut(KeyChangeEvent)) {
142 Self::scan_dir(
143 &mut self.rows,
144 &mut self.cols,
145 self.output_wait,
146 |row_pin_idx, col_pin_idx, pressed| {
147 if let Some((row, col)) =
148 (self.map_key_pos)(ScanDir::Row2Col, row_pin_idx, col_pin_idx)
149 {
150 if let Some(change) = self.pressed.set_pressed(pressed, row, col) {
151 cb(KeyChangeEvent {
152 row: row as u8,
153 col: col as u8,
154 pressed: change,
155 });
156 }
157 }
158 },
159 )
160 .await;
161
162 Self::scan_dir(
163 &mut self.cols,
164 &mut self.rows,
165 self.output_wait,
166 |col_pin_idx, row_pin_idx, pressed| {
167 if let Some((row, col)) =
168 (self.map_key_pos)(ScanDir::Col2Row, row_pin_idx, col_pin_idx)
169 {
170 if let Some(change) = self.pressed.set_pressed(pressed, row, col) {
171 cb(KeyChangeEvent {
172 row: row as u8,
173 col: col as u8,
174 pressed: change,
175 });
176 }
177 }
178 },
179 )
180 .await;
181 }
182}
183
184#[derive(Clone, Copy, PartialEq, Eq, Debug)]
185pub enum ScanDir {
186 Col2Row,
187 Row2Col,
188}