use embassy_time::{Instant, Timer};
use crate::debounce::{DebounceState, DebouncerTrait};
use crate::driver::flex_pin::FlexPin;
use crate::event::{Event, KeyboardEvent};
use crate::input_device::InputDevice;
use crate::matrix::{KeyState, MatrixTrait};
pub enum ScanLocation {
Pins(usize, usize),
Ignore,
}
pub struct BidirectionalMatrix<
Pin: FlexPin,
D: DebouncerTrait<ROW, COL>,
const PIN_NUM: usize,
const ROW: usize,
const COL: usize,
> {
pins: [Pin; PIN_NUM],
debouncer: D,
key_state: [[KeyState; COL]; ROW],
scan_start: Option<Instant>,
scan_pos: (usize, usize),
scan_map: [[ScanLocation; COL]; ROW],
}
impl<Pin: FlexPin, D: DebouncerTrait<ROW, COL>, const PIN_NUM: usize, const ROW: usize, const COL: usize>
BidirectionalMatrix<Pin, D, PIN_NUM, ROW, COL>
{
pub fn new(pins: [Pin; PIN_NUM], debouncer: D, scan_map: [[ScanLocation; COL]; ROW]) -> Self {
BidirectionalMatrix {
pins,
debouncer,
key_state: [[KeyState::new(); COL]; ROW],
scan_start: None,
scan_pos: (0, 0),
scan_map,
}
}
}
impl<Pin: FlexPin, D: DebouncerTrait<ROW, COL>, const PIN_NUM: usize, const ROW: usize, const COL: usize> InputDevice
for BidirectionalMatrix<Pin, D, PIN_NUM, ROW, COL>
{
async fn read_event(&mut self) -> crate::event::Event {
loop {
let (scan_x_start, scan_y_start) = self.scan_pos;
for scan_y_idx in scan_y_start..self.scan_map.len() {
let scan_x_start_current = if scan_y_idx == scan_y_start { scan_x_start } else { 0 };
for scan_x_idx in scan_x_start_current..self.scan_map[scan_y_idx].len() {
if let ScanLocation::Pins(in_idx, out_idx) = self.scan_map[scan_y_idx][scan_x_idx] {
let [in_pin, out_pin] = self.pins.get_disjoint_mut([in_idx, out_idx]).unwrap();
out_pin.set_as_output();
out_pin.set_high().ok();
Timer::after_micros(1).await;
let debounce_state = self.debouncer.detect_change_with_debounce(
scan_y_idx,
scan_x_idx,
in_pin.is_high().ok().unwrap_or_default(),
&self.key_state[scan_y_idx][scan_x_idx],
);
if let DebounceState::Debounced = debounce_state {
self.key_state[scan_y_idx][scan_x_idx].toggle_pressed();
self.scan_pos = (scan_y_idx, scan_x_idx);
return Event::Key(KeyboardEvent::key(
scan_y_idx as u8,
scan_x_idx as u8,
self.key_state[scan_y_idx][scan_x_idx].pressed,
));
}
out_pin.set_low().ok();
out_pin.set_as_input();
Timer::after_micros(1).await;
}
}
}
self.scan_pos = (0, 0);
}
}
}
impl<Pin: FlexPin, D: DebouncerTrait<ROW, COL>, const PIN_NUM: usize, const ROW: usize, const COL: usize>
MatrixTrait<ROW, COL> for BidirectionalMatrix<Pin, D, PIN_NUM, ROW, COL>
{
#[cfg(feature = "async_matrix")]
async fn wait_for_key(&mut self) {}
}