rktk_drivers_common/magnetic/
matrix.rs1use crate::magnetic::profile::{KeyProfileMap, SwitchProfile};
2use crate::magnetic::rapid_trigger::RapidTriggerState;
3use rktk::drivers::interface::keyscan::{KeyChangeEvent, KeyscanDriver};
4use rktk::drivers::interface::magnetic::{Adc, Multiplexer};
5use rktk_log::MaybeFormat;
6
7pub trait MagneticScanner {
8 type Error: core::fmt::Debug + MaybeFormat;
9 fn scan(
10 &mut self,
11 row: usize,
12 col: usize,
13 ) -> impl core::future::Future<Output = Result<u16, Self::Error>>;
14}
15
16pub struct DirectScanner<A: Adc, const ROWS: usize, const COLS: usize> {
17 adcs: [[A; COLS]; ROWS],
18}
19
20impl<A: Adc, const ROWS: usize, const COLS: usize> DirectScanner<A, ROWS, COLS> {
21 pub fn new(adcs: [[A; COLS]; ROWS]) -> Self {
22 Self { adcs }
23 }
24}
25
26impl<A: Adc, const ROWS: usize, const COLS: usize> MagneticScanner
27 for DirectScanner<A, ROWS, COLS>
28{
29 type Error = A::Error;
30 async fn scan(&mut self, row: usize, col: usize) -> Result<u16, Self::Error> {
31 self.adcs[row][col].read().await
32 }
33}
34
35pub struct MuxScanner<A: Adc, M: Multiplexer, F: Fn(usize, usize) -> Option<(u8, u8)>> {
36 adc: A,
37 mux: M,
38 map: F,
39}
40
41impl<A: Adc, M: Multiplexer, F: Fn(usize, usize) -> Option<(u8, u8)>> MuxScanner<A, M, F> {
42 pub fn new(adc: A, mux: M, map: F) -> Self {
43 Self { adc, mux, map }
44 }
45}
46
47#[derive(Debug)]
48#[cfg_attr(feature = "defmt", derive(defmt::Format))]
49pub enum MagneticError<AE, ME> {
50 Adc(AE),
51 Mux(ME),
52}
53
54impl<A: Adc, M: Multiplexer, F: Fn(usize, usize) -> Option<(u8, u8)>> MagneticScanner
55 for MuxScanner<A, M, F>
56{
57 type Error = MagneticError<A::Error, M::Error>;
58 async fn scan(&mut self, row: usize, col: usize) -> Result<u16, Self::Error> {
59 if let Some((mux_ch, _adc_ch)) = (self.map)(row, col) {
60 self.mux.select(mux_ch).await.map_err(MagneticError::Mux)?;
61 embassy_time::Timer::after_micros(10).await;
63 self.adc.read().await.map_err(MagneticError::Adc)
64 } else {
65 Ok(0)
66 }
67 }
68}
69
70#[derive(Clone, Copy, Debug)]
71pub struct CalibrationEntry {
72 pub min: u16,
73 pub max: u16,
74}
75
76impl CalibrationEntry {
77 pub const fn new() -> Self {
78 Self { min: u16::MAX, max: u16::MIN }
79 }
80}
81
82impl Default for CalibrationEntry {
83 fn default() -> Self {
84 Self::new()
85 }
86}
87
88pub struct MagneticMatrix<
89 S: MagneticScanner,
90 M: KeyProfileMap<ROWS, COLS>,
91 const ROWS: usize,
92 const COLS: usize,
93> {
94 scanner: S,
95 profiles: M,
96 states: [[RapidTriggerState; COLS]; ROWS],
97 calibration_mode: bool,
98 calibration_data: [[CalibrationEntry; COLS]; ROWS],
99 press_dist: u16,
100 release_dist: u16,
101 top_deadzone: u16,
102}
103
104impl<S: MagneticScanner, M: KeyProfileMap<ROWS, COLS>, const ROWS: usize, const COLS: usize>
105 MagneticMatrix<S, M, ROWS, COLS>
106{
107 pub fn new(
108 scanner: S,
109 profiles: M,
110 press_dist: u16,
111 release_dist: u16,
112 top_deadzone: u16,
113 ) -> Self {
114 Self {
115 scanner,
116 profiles,
117 states: [[RapidTriggerState::new(); COLS]; ROWS],
118 calibration_mode: false,
119 calibration_data: [[CalibrationEntry::new(); COLS]; ROWS],
120 press_dist,
121 release_dist,
122 top_deadzone,
123 }
124 }
125
126 pub fn set_calibration_mode(&mut self, enabled: bool) {
127 self.calibration_mode = enabled;
128 if enabled {
129 self.calibration_data = [[CalibrationEntry::new(); COLS]; ROWS];
131 }
132 }
133
134 pub fn get_calibration_data(&self) -> [[CalibrationEntry; COLS]; ROWS] {
135 self.calibration_data
136 }
137
138 pub fn set_calibration_data(&mut self, data: [[CalibrationEntry; COLS]; ROWS]) {
139 self.calibration_data = data;
140 }
141}
142
143#[derive(Debug)]
144pub enum CalibrationError {
145 BufferTooSmall,
146}
147
148impl core::fmt::Display for CalibrationError {
149 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
150 match self {
151 CalibrationError::BufferTooSmall => write!(f, "Calibration buffer is too small"),
152 }
153 }
154}
155impl core::error::Error for CalibrationError {}
156
157impl<S: MagneticScanner, M: KeyProfileMap<ROWS, COLS>, const ROWS: usize, const COLS: usize>
158 KeyscanDriver for MagneticMatrix<S, M, ROWS, COLS>
159{
160 const CALIBRATION_SIZE: usize = ROWS * COLS * 4;
161
162 type CalibrationError = CalibrationError;
163
164 fn save_calibration(&self, buf: &mut [u8]) -> Result<(), Self::CalibrationError> {
165 if buf.len() < Self::CALIBRATION_SIZE {
166 return Err(CalibrationError::BufferTooSmall);
167 }
168 let mut idx = 0;
169 for row in 0..ROWS {
170 for col in 0..COLS {
171 let entry = self.calibration_data[row][col];
172 buf[idx..idx + 2].copy_from_slice(&entry.min.to_le_bytes());
173 buf[idx + 2..idx + 4].copy_from_slice(&entry.max.to_le_bytes());
174 idx += 4;
175 }
176 }
177 Ok(())
178 }
179
180 #[allow(clippy::needless_range_loop)]
181 fn load_calibration(&mut self, buf: &[u8]) -> Result<(), Self::CalibrationError> {
182 if buf.len() < Self::CALIBRATION_SIZE {
183 return Err(CalibrationError::BufferTooSmall);
184 }
185 let mut idx = 0;
186 let mut data = [[CalibrationEntry::new(); COLS]; ROWS];
187 for row in 0..ROWS {
188 for col in 0..COLS {
189 let min = u16::from_le_bytes([buf[idx], buf[idx + 1]]);
190 let max = u16::from_le_bytes([buf[idx + 2], buf[idx + 3]]);
191 data[row][col] = CalibrationEntry { min, max };
192 idx += 4;
193 }
194 }
195 self.set_calibration_data(data);
196 Ok(())
197 }
198
199 async fn scan(&mut self, mut cb: impl FnMut(KeyChangeEvent)) {
200 for row in 0..ROWS {
201 for col in 0..COLS {
202 match self.scanner.scan(row, col).await {
203 Ok(val) => {
204 if self.calibration_mode {
205 let entry = &mut self.calibration_data[row][col];
206 if val < entry.min {
207 entry.min = val;
208 }
209 if val > entry.max {
210 entry.max = val;
211 }
212 } else {
213 let entry = &self.calibration_data[row][col];
214 if entry.min < entry.max && (entry.max - entry.min) >= 300 {
215 let normalized = if val <= entry.min {
217 0
218 } else if val >= entry.max {
219 65535
220 } else {
221 ((val - entry.min) as u32 * 65535
222 / (entry.max - entry.min) as u32)
223 as u16
224 };
225
226 let profile = self.profiles.get_profile(row, col);
227 let distance = profile.normalized_to_distance(normalized);
228
229 if let Some(pressed) = self.states[row][col].update(
230 distance,
231 self.press_dist,
232 self.release_dist,
233 self.top_deadzone,
234 ) {
235 rktk_log::debug!(
236 "Magnetic Key Event: ({},{}) pressed={} distance={} normalized={}",
237 row,
238 col,
239 pressed,
240 distance,
241 normalized
242 );
243 cb(KeyChangeEvent { row: row as u8, col: col as u8, pressed });
244 }
245 }
246 }
247 }
248 Err(e) => {
249 rktk_log::error!("Magnetic scan error at {},{}: {:?}", row, col, e);
250 }
251 }
252 }
253 }
254 }
255
256 fn start_calibration(&mut self) {
257 self.set_calibration_mode(true);
258 rktk_log::info!("Calibration started. Press all keys to their physical limits.");
259 }
260
261 fn end_calibration(&mut self) {
262 self.set_calibration_mode(false);
263 rktk_log::info!("Calibration finished. Results:");
264 for row in 0..ROWS {
265 for col in 0..COLS {
266 let entry = self.calibration_data[row][col];
267 if entry.min < entry.max && (entry.max - entry.min) >= 300 {
268 rktk_log::info!(
269 " Key ({},{}): min_adc={}, max_adc={}, range={}",
270 row,
271 col,
272 entry.min,
273 entry.max,
274 entry.max - entry.min
275 );
276 } else {
277 rktk_log::info!(" Key ({},{}): Not calibrated (range too small)", row, col);
278 }
279 }
280 }
281 }
282}