use core::{convert::Infallible, fmt::Display}; use embedded_hal::{ blocking::delay::{DelayMs, DelayUs}, digital::v2::{InputPin, OutputPin}, }; use rp2040_hal::Timer; const NONE: char = '\0'; const CALL_END: char = '\x01'; const L_SHIFT: char = '\x02'; const R_SHIFT: char = '\x03'; const ALT: char = '\x04'; const SYM: char = '\x05'; const BACK: char = '\x06'; const MENU: char = '\x07'; const BACKSPACE: char = '\x08'; const CALL_START: char = '\x09'; const TOUCHPAD_BUTTON: char = '\x0B'; const ENTER: char = '\n'; const KEYMAP: [[char; 8]; 6] = [ [CALL_END, ENTER, 'b', 'y', 'n', 'j', 'u', 'h'], [NONE, BACKSPACE, '$', 'i', 'm', 'k', 'o', 'l'], [NONE, 'p', 'x', 'd', 'z', L_SHIFT, 'e', 's'], [NONE, R_SHIFT, 'v', 't', 'c', 'f', 'r', 'g'], [NONE, 'a', ALT, SYM, ' ', '0', 'q', 'w'], [ NONE, NONE, BACK, MENU, NONE, CALL_START, NONE, TOUCHPAD_BUTTON, ], ]; #[derive(PartialEq, Eq, Copy, Clone)] pub enum KeyCode { CallStart, Menu, Touchpad, Back, CallEnd, Backspace, Enter, LeftShift, RightShift, Alt, Sym, Char(char), } impl KeyCode { fn from_keyboard(c: char, alt: bool, shift: bool) -> Self { match (alt, shift, c) { (_, _, CALL_END) => KeyCode::CallEnd, (_, _, L_SHIFT) => KeyCode::LeftShift, (_, _, R_SHIFT) => KeyCode::RightShift, (_, _, ALT) => KeyCode::Alt, (_, _, SYM) => KeyCode::Sym, (_, _, BACK) => KeyCode::Back, (_, _, MENU) => KeyCode::Menu, (_, _, BACKSPACE) => KeyCode::Backspace, (_, _, CALL_START) => KeyCode::CallStart, (_, _, TOUCHPAD_BUTTON) => KeyCode::Touchpad, (_, _, ENTER) => KeyCode::Enter, (false, false, _) => KeyCode::Char(c), (true, _, _) => KeyCode::Char(altify(c)), (false, true, _) => KeyCode::Char(c.to_ascii_uppercase()), } } } impl Display for KeyCode { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match self { KeyCode::CallEnd => write!(f, "<CALLEND>"), KeyCode::Backspace => write!(f, "<BACKSPACE>"), KeyCode::Enter => writeln!(f), KeyCode::CallStart => write!(f, "<CALLSTART>"), KeyCode::Menu => write!(f, "<MENU>"), KeyCode::Touchpad => write!(f, "<TOUCHPAD>"), KeyCode::Back => write!(f, "<BACK>"), KeyCode::LeftShift => write!(f, "<LEFTSHIFT>"), KeyCode::RightShift => write!(f, "<RIGHTSHIFT>"), KeyCode::Alt => write!(f, "<ALT>"), KeyCode::Sym => write!(f, "<SYM>"), KeyCode::Char(c) => write!(f, "{c}"), } } } pub struct Keyboard< // col CCLK: OutputPin<Error = Infallible>, CSER: OutputPin<Error = Infallible>, CRCLK: OutputPin<Error = Infallible>, // row RCLK: OutputPin<Error = Infallible>, RSER: InputPin, RLD: OutputPin<Error = Infallible>, > { timer: Timer, col_clk: CCLK, col_ser: CSER, col_rclk: CRCLK, row_clk: RCLK, row_ser: RSER, row_ld: RLD, last_state: u64, cur_key: Option<KeyCode>, } impl< CCLK: OutputPin<Error = Infallible>, CSER: OutputPin<Error = Infallible>, CRCLK: OutputPin<Error = Infallible>, RCLK: OutputPin<Error = Infallible>, RSER: InputPin<Error = Infallible>, RLD: OutputPin<Error = Infallible>, > Keyboard<CCLK, CSER, CRCLK, RCLK, RSER, RLD> { pub fn new( timer: Timer, col_clk: CCLK, col_ser: CSER, col_rclk: CRCLK, row_clk: RCLK, row_ser: RSER, row_ld: RLD, ) -> Self { Self { timer, col_clk, col_ser, col_rclk, row_clk, row_ser, row_ld, last_state: 0, cur_key: None, } } pub fn read_state(&mut self) -> u64 { let mut state = 0; for x in 0..6 { // +2 gets us to QF (col 6) self.write_cols(1 << (x + 2)); self.timer.delay_ms(1); let y = read_rows( &mut self.timer, &mut self.row_clk, &mut self.row_ser, &mut self.row_ld, ); state |= u64::from(y) << (x * 8); } let delta = (!self.last_state) & state; for x in 0..6 { for y in 0..8 { if delta & (1 << (x * 8 + y)) > 0 { let key = KEYMAP[usize::try_from(x).unwrap()][usize::try_from(y).unwrap()]; if key != NONE { let keycode = KeyCode::from_keyboard( key, is_alt_pressed(state), is_shift_pressed(state), ); self.cur_key = Some(keycode); } } } } self.last_state = state; state } pub fn pushed_key(&mut self) -> Option<KeyCode> { self.cur_key.take() } // 1s in val are low // 0s are high // indexes from furthest pin (QH on second shift register) fn write_cols(&mut self, val: u16) { for i in 0..16 { self.col_ser .set_state(((val & (1 << i)) == 0).into()) .unwrap(); self.col_clk.set_low().unwrap(); self.col_clk.set_high().unwrap(); } self.col_rclk.set_low().unwrap(); self.col_rclk.set_high().unwrap(); } } fn read_rows< RCLK: OutputPin<Error = Infallible>, RSER: InputPin<Error = Infallible>, RLD: OutputPin<Error = Infallible>, >( timer: &mut Timer, row_clk: &mut RCLK, row_ser: &mut RSER, row_ld: &mut RLD, ) -> u8 { row_ld.set_low().unwrap(); row_ld.set_high().unwrap(); let mut out = 0; for i in 0..8 { timer.delay_us(10); if row_ser.is_low().unwrap() { out |= 1 << i; } row_clk.set_low().unwrap(); row_clk.set_high().unwrap(); } out } fn is_alt_pressed(state: u64) -> bool { (state & (1 << (4 * 8 + 2))) > 0 } fn is_shift_pressed(state: u64) -> bool { let left = (state & (1 << (2 * 8 + 5))) > 0; let right = (state & (1 << (3 * 8 + 1))) > 0; left || right } fn altify(c: char) -> char { match c { 'q' => '#', 'w' => '1', 'e' => '2', 'r' => '3', 't' => '(', 'y' => ')', 'u' => '_', 'i' => '-', 'o' => '+', 'p' => '@', 'a' => '*', 's' => '4', 'd' => '5', 'f' => '6', 'g' => '/', 'h' => ':', 'j' => ';', 'k' => ',', 'l' => '"', 'z' => '7', 'x' => '8', 'c' => '9', 'v' => '?', 'b' => '!', 'n' => ',', 'm' => '.', _ => c, } }