use std::fmt::Display;
use std::sync::{Arc, Mutex};
use std::mem::MaybeUninit;
use embedded_hal::digital::v2::{OutputPin, InputPin};
use esp_idf_svc::hal::gpio::*;
use esp_idf_svc::sys::EspError;
use keypad::KeypadInput;
#[derive(Debug, Clone, Copy)]
pub enum SpecialCharacter {
ESC,
Backspace,
DEL,
Tab,
Fn,
Shift,
Ctrl,
Option,
Alt,
OK,
Up,
Down,
Left,
Right
}
#[derive(Debug, Clone, Copy)]
pub enum Key {
Alphanumeric(char),
Special(SpecialCharacter)
}
impl Display for Key {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Key::Alphanumeric(c) => write!(f, "{}", c),
Key::Special(c) => write!(f, "{:?}", c)
}
}
}
macro_rules! keymap {
($normal: expr, $shift: expr) => {
(Key::Alphanumeric($normal), Some(Key::Alphanumeric($shift)), None)
};
($normal: expr, $shift: expr, $special: ident) => {
(Key::Alphanumeric($normal), Some(Key::Alphanumeric($shift)), Some(Key::Special(SpecialCharacter::$special)))
};
($special: ident) => {
(Key::Special(SpecialCharacter::$special), None, None)
};
}
const KEYMAP: [[(Key, Option<Key>, Option<Key>); 14]; 4] = [
[keymap!('`','~',ESC), keymap!('1','!'), keymap!('2','@'), keymap!('3','#'), keymap!('4','$'), keymap!('5','%'), keymap!('6','^'), keymap!('7','&'), keymap!('8','*'), keymap!('9','('), keymap!('0',')'), keymap!('_','-'), keymap!('=','+'), (Key::Special(SpecialCharacter::Backspace), None, Some(Key::Special(SpecialCharacter::DEL)))],
[keymap!(Tab), keymap!('q','Q'), keymap!('w','W'), keymap!('e','E'), keymap!('r','R'), keymap!('t','T'), keymap!('y','Y'), keymap!('u','U'), keymap!('i','I'), keymap!('o','O'), keymap!('p','P'), keymap!('[','{'), keymap!(']','}'), keymap!('\\','|')],
[keymap!(Fn), keymap!(Shift), keymap!('a','A'), keymap!('s','S'), keymap!('d','D'), keymap!('f','F'), keymap!('g','G'), keymap!('h','H'), keymap!('j','J'), keymap!('k','K'), keymap!('l','L'), keymap!(';',':',Up), keymap!('\'','"'), keymap!(OK)],
[keymap!(Ctrl), keymap!(Option), keymap!(Alt), keymap!('z','Z'), keymap!('x','X'), keymap!('c','C'), keymap!('v','V'), keymap!('b','B'), keymap!('n','N'), keymap!('m','M'), keymap!(',','<',Left), keymap!('.','>',Down), keymap!('/','?',Right), (Key::Alphanumeric(' '), None, None)]
];
struct MultiplexDecoder<'a> {
address_pins: Arc<Mutex<(PinDriver<'a, Gpio8, Output>, PinDriver<'a, Gpio9, Output>, PinDriver<'a, Gpio11, Output>)>>
}
impl<'a> MultiplexDecoder<'a> {
fn new(address_pins: (PinDriver<'a, Gpio8, Output>, PinDriver<'a, Gpio9, Output>, PinDriver<'a, Gpio11, Output>)) -> MultiplexDecoder<'a> {
Self { address_pins: Arc::new(Mutex::new(address_pins)) }
}
fn reset(&mut self) -> Result<(), EspError> {
let mut pins_write = self.address_pins.lock().unwrap();
pins_write.0.set_low()?;
pins_write.1.set_low()?;
pins_write.2.set_low()?;
Ok(())
}
fn set(&mut self, active: (bool, bool, bool)) -> Result<(), EspError> {
let mut pins_write = self.address_pins.lock().unwrap();
pins_write.0.set_level(active.0.into())?;
pins_write.1.set_level(active.1.into())?;
pins_write.2.set_level(active.2.into())?;
Ok(())
}
}
impl Clone for MultiplexDecoder<'_> {
fn clone(&self) -> Self {
Self { address_pins: self.address_pins.clone() }
}
}
struct AnyMultiplexedOutputPin<'a>(MultiplexDecoder<'a>, (bool, bool, bool));
impl<'a> AnyMultiplexedOutputPin<'a> {
fn get_active_pins(&self) -> (bool, bool, bool) {
self.1
}
fn get_decoder(&mut self) -> &mut MultiplexDecoder<'a> {
&mut self.0
}
}
impl OutputPin for AnyMultiplexedOutputPin<'_> {
type Error = EspError;
fn set_high(&mut self) -> Result<(), Self::Error> {
self.get_decoder().reset()?;
Ok(())
}
fn set_low(&mut self) -> Result<(), Self::Error> {
let active = self.get_active_pins().clone();
let dec = self.get_decoder();
dec.set(active)?;
Ok(())
}
}
macro_rules! multiplex {
($d:ident, $a:expr) => {
AnyMultiplexedOutputPin($d.clone(), $a)
};
}
macro_rules! configure_row_pin {
($i:expr) => {
$i.set_pull(Pull::Up).unwrap();
};
}
keypad_struct! {
pub struct CardputerKeyboard<Error = EspError> {
rows: (
PinDriver<'static, Gpio13, Input>,
PinDriver<'static, Gpio15, Input>,
PinDriver<'static, Gpio3, Input>,
PinDriver<'static, Gpio4, Input>,
PinDriver<'static, Gpio5, Input>,
PinDriver<'static, Gpio6, Input>,
PinDriver<'static, Gpio7, Input>,
),
columns: (
AnyMultiplexedOutputPin<'static>,
AnyMultiplexedOutputPin<'static>,
AnyMultiplexedOutputPin<'static>,
AnyMultiplexedOutputPin<'static>,
AnyMultiplexedOutputPin<'static>,
AnyMultiplexedOutputPin<'static>,
AnyMultiplexedOutputPin<'static>,
AnyMultiplexedOutputPin<'static>,
),
}
}
pub struct Keyboard {
keypad: CardputerKeyboard,
keymap: [[(Key, Option<Key>, Option<Key>); 14]; 4]
}
impl Keyboard {
pub fn new(row_pins: (Gpio13, Gpio15, Gpio3, Gpio4, Gpio5, Gpio6, Gpio7), address_pins: (Gpio8, Gpio9, Gpio11)) -> Result<Self, EspError> {
let address_pin_drivers = (
PinDriver::output(address_pins.0)?,
PinDriver::output(address_pins.1)?,
PinDriver::output(address_pins.2)?,
);
let dec = MultiplexDecoder::new(address_pin_drivers);
let mut keypad = keypad_new!(CardputerKeyboard {
rows: (
PinDriver::input(row_pins.0)?,
PinDriver::input(row_pins.1)?,
PinDriver::input(row_pins.2)?,
PinDriver::input(row_pins.3)?,
PinDriver::input(row_pins.4)?,
PinDriver::input(row_pins.5)?,
PinDriver::input(row_pins.6)?,
),
columns: (
multiplex!(dec, (false, false, false)),
multiplex!(dec, (true, false, false)),
multiplex!(dec, (false, true, false)),
multiplex!(dec, (true, true, false)),
multiplex!(dec, (false, false, true)),
multiplex!(dec, (true, false, true)),
multiplex!(dec, (false, true, true)),
multiplex!(dec, (true, true, true)),
),
});
configure_row_pin!(keypad.rows.0);
configure_row_pin!(keypad.rows.1);
configure_row_pin!(keypad.rows.2);
configure_row_pin!(keypad.rows.3);
configure_row_pin!(keypad.rows.4);
configure_row_pin!(keypad.rows.5);
configure_row_pin!(keypad.rows.6);
Ok(Self {
keypad,
keymap: KEYMAP
})
}
pub fn set_keymap(&mut self, keymap: [[(Key, Option<Key>, Option<Key>); 14]; 4]) {
self.keymap = keymap;
}
pub fn decompose(&self) -> [[KeypadInput<EspError>; 14]; 4] {
let keys = self.keypad.decompose();
unsafe {
const ARRAY_UNINIT: MaybeUninit<KeypadInput<EspError>> = MaybeUninit::<KeypadInput<EspError>>::uninit();
let mut row0: [MaybeUninit<KeypadInput<EspError>>; 14] = [ARRAY_UNINIT; 14];
let mut row1: [MaybeUninit<KeypadInput<EspError>>; 14] = [ARRAY_UNINIT; 14];
let mut row2: [MaybeUninit<KeypadInput<EspError>>; 14] = [ARRAY_UNINIT; 14];
let mut row3: [MaybeUninit<KeypadInput<EspError>>; 14] = [ARRAY_UNINIT; 14];
for (row_ix, row) in keys.into_iter().enumerate() {
for (col_ix, key) in row.into_iter().enumerate() {
match col_ix {
7 => row0[row_ix*2] = MaybeUninit::new(key),
3 => row0[1+row_ix*2] = MaybeUninit::new(key),
6 => row1[row_ix*2] = MaybeUninit::new(key),
2 => row1[1+row_ix*2] = MaybeUninit::new(key),
5 => row2[row_ix*2] = MaybeUninit::new(key),
1 => row2[1+row_ix*2] = MaybeUninit::new(key),
4 => row3[row_ix*2] = MaybeUninit::new(key),
0 => row3[1+row_ix*2] = MaybeUninit::new(key),
_ => panic!("access to invalid column index")
}
}
}
let row0_init: [KeypadInput<EspError>; 14] = std::mem::transmute(row0);
let row1_init: [KeypadInput<EspError>; 14] = std::mem::transmute(row1);
let row2_init: [KeypadInput<EspError>; 14] = std::mem::transmute(row2);
let row3_init: [KeypadInput<EspError>; 14] = std::mem::transmute(row3);
[row0_init, row1_init, row2_init, row3_init]
}
}
pub fn get_keys(&self) -> Result<Vec<Key>, EspError> {
let mut keys = Vec::new();
let dec = self.decompose();
let shift_pressed = dec[2][1].is_low()?;
let fn_pressed = dec[2][0].is_low()?;
for (row_ix, row) in dec.into_iter().enumerate() {
for (col_ix, key) in row.into_iter().enumerate() {
if key.is_low()? {
let map_entry = self.keymap[row_ix][col_ix];
if fn_pressed && map_entry.2.is_some() {
keys.push(map_entry.2.unwrap());
} else if shift_pressed && map_entry.1.is_some() {
keys.push(map_entry.1.unwrap());
} else {
keys.push(map_entry.0);
}
}
}
}
Ok(keys)
}
}