Files
sinclair-sci-calc/src/keyboard.rs
2025-07-18 20:31:23 +01:00

104 lines
3.0 KiB
Rust

use arduino_hal::{adc::AdcChannel, hal::Atmega, pac::ADC, Adc};
use ufmt::derive::uDebug;
use crate::{DEBOUNCE_DEPTH, KEYBOARD_ADC_THRESHOLD};
#[derive(uDebug, Clone, Copy, PartialEq, Eq)]
pub enum KeyPress {
Up,
C,
Num(u8),
Mul,
Div,
Plus,
Minus,
Down,
E,
}
impl KeyPress {
fn map(display_no: usize, kn: bool, ko: bool) -> Option<KeyPress> {
match (display_no, kn, ko) {
(0, true, false) => Some(KeyPress::Num(1)),
(0, false, true) => Some(KeyPress::C),
(1, true, false) => Some(KeyPress::Num(5)),
(1, false, true) => Some(KeyPress::Div),
(2, true, false) => Some(KeyPress::Num(6)),
(2, false, true) => Some(KeyPress::Mul),
(3, true, false) => Some(KeyPress::Num(7)),
(3, false, true) => Some(KeyPress::Up),
(4, true, false) => Some(KeyPress::Num(8)),
(4, false, true) => Some(KeyPress::E),
(5, true, false) => Some(KeyPress::Num(9)),
(5, false, true) => Some(KeyPress::Num(0)),
(6, true, false) => Some(KeyPress::Num(2)),
(6, false, true) => Some(KeyPress::Down),
(7, true, false) => Some(KeyPress::Num(3)),
(7, false, true) => Some(KeyPress::Plus),
(8, true, false) => Some(KeyPress::Num(4)),
(8, false, true) => Some(KeyPress::Minus),
_ => None,
}
}
}
#[derive(uDebug, Clone, Copy, PartialEq, Eq)]
pub struct KeyReadout {
display_no: usize,
kn: bool,
ko: bool,
}
pub struct Keyboard<KN, KO> {
kn: KN,
ko: KO,
}
impl<KN: AdcChannel<Atmega, ADC>, KO: AdcChannel<Atmega, ADC>> Keyboard<KN, KO> {
pub fn new(kn: KN, ko: KO) -> Keyboard<KN, KO> {
Keyboard { kn, ko }
}
pub fn read(&self, adc: &mut Adc, display_no: usize) -> Option<KeyReadout> {
let kn = adc.read_blocking(&self.kn);
let ko = adc.read_blocking(&self.ko);
if kn > KEYBOARD_ADC_THRESHOLD || ko > KEYBOARD_ADC_THRESHOLD {
Some(KeyReadout {
display_no,
kn: kn > KEYBOARD_ADC_THRESHOLD,
ko: ko > KEYBOARD_ADC_THRESHOLD,
})
} else {
None
}
}
}
#[derive(Default)]
pub struct Debounce {
record: [Option<KeyReadout>; DEBOUNCE_DEPTH],
pos: usize,
last: Option<KeyReadout>,
}
impl Debounce {
pub fn input(&mut self, key: Option<KeyReadout>) -> Option<KeyPress> {
self.record[self.pos] = key;
self.pos += 1;
if self.pos >= self.record.len() {
self.pos = 0;
}
if self.record.iter().all(|hist| hist == &key) && self.last != key {
self.last = key;
key.and_then(|key_readout| {
KeyPress::map(key_readout.display_no, key_readout.kn, key_readout.ko)
})
} else if self.record.iter().all(|hist| hist == &None) {
self.last = None;
None
} else {
None
}
}
}