use crate::debounce::Debouncer;
use core::convert::Infallible;
use embassy_time::{Duration, Instant, Timer};
use embedded_hal::digital::{InputPin, OutputPin};
#[derive(Copy, Clone, Debug)]
pub(crate) struct KeyState {
pub(crate) pressed: bool,
pub(crate) changed: bool,
hold_start: Option<Instant>,
}
impl Default for KeyState {
fn default() -> Self {
Self::new()
}
}
impl KeyState {
fn new() -> Self {
KeyState {
pressed: false,
changed: false,
hold_start: None,
}
}
fn start_timer(&mut self) {
self.hold_start = Some(Instant::now());
}
fn elapsed(&self) -> Option<Duration> {
match self.hold_start {
Some(t) => Instant::now().checked_duration_since(t),
None => None,
}
}
fn clear_timer(&mut self) {
self.hold_start = None;
}
}
pub struct Matrix<
In: InputPin,
Out: OutputPin,
const INPUT_PIN_NUM: usize,
const OUTPUT_PIN_NUM: usize,
> {
input_pins: [In; INPUT_PIN_NUM],
output_pins: [Out; OUTPUT_PIN_NUM],
debouncer: Debouncer<INPUT_PIN_NUM, OUTPUT_PIN_NUM>,
key_states: [[KeyState; INPUT_PIN_NUM]; OUTPUT_PIN_NUM],
}
impl<
In: InputPin<Error = Infallible>,
Out: OutputPin<Error = Infallible>,
const INPUT_PIN_NUM: usize,
const OUTPUT_PIN_NUM: usize,
> Matrix<In, Out, INPUT_PIN_NUM, OUTPUT_PIN_NUM>
{
pub(crate) fn new(input_pins: [In; INPUT_PIN_NUM], output_pins: [Out; OUTPUT_PIN_NUM]) -> Self {
Matrix {
input_pins,
output_pins,
debouncer: Debouncer::new(),
key_states: [[KeyState::new(); INPUT_PIN_NUM]; OUTPUT_PIN_NUM],
}
}
pub(crate) async fn scan(&mut self) -> Result<(), Infallible> {
for (out_idx, out_pin) in self.output_pins.iter_mut().enumerate() {
out_pin.set_high()?;
Timer::after_micros(1).await;
for (in_idx, in_pin) in self.input_pins.iter_mut().enumerate() {
self.debouncer.debounce(
in_idx,
out_idx,
in_pin.is_high()?,
&mut self.key_states[out_idx][in_idx],
);
}
out_pin.set_low()?;
}
Ok(())
}
pub(crate) fn key_pressed(&mut self, row: usize, col: usize) {
#[cfg(feature = "col2row")]
self.key_states[col][row].start_timer();
#[cfg(not(feature = "col2row"))]
self.key_states[row][col].start_timer();
}
pub(crate) fn get_key_state(&mut self, row: usize, col: usize) -> KeyState {
#[cfg(feature = "col2row")]
return self.key_states[col][row];
#[cfg(not(feature = "col2row"))]
return self.key_states[row][col];
}
}