factored out keyboard file

This commit is contained in:
2025-07-18 20:31:23 +01:00
parent f2613dd936
commit 7467f41c30
2 changed files with 139 additions and 126 deletions

104
src/keyboard.rs Normal file
View File

@@ -0,0 +1,104 @@
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,
}
}
}
pub struct KeyReadout {
kn: bool,
ko: bool,
}
impl KeyReadout {
pub fn to_keypress(&self, display_no: usize) -> Option<KeyPress> {
KeyPress::map(display_no, self.kn, self.ko)
}
}
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) -> 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 {
kn: kn > KEYBOARD_ADC_THRESHOLD,
ko: ko > KEYBOARD_ADC_THRESHOLD,
})
} else {
None
}
}
}
#[derive(Default)]
pub struct Debounce {
record: [Option<KeyPress>; DEBOUNCE_DEPTH],
pos: usize,
last: Option<KeyPress>,
}
impl Debounce {
pub fn input(&mut self, key: Option<KeyPress>) -> 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
} else if self.record.iter().all(|hist| hist == &None) {
self.last = None;
None
} else {
None
}
}
}

View File

@@ -1,22 +1,18 @@
#![no_std]
#![no_main]
mod keyboard;
use calc_math::calc::StackCalc;
use calc_math::Decimal;
use core::ops::{Index, IndexMut};
use keyboard::{Debounce, KeyPress, KeyReadout, Keyboard};
use arduino_hal::{
adc::{
channel::{ADC6, ADC7},
AdcChannel,
adc::channel::{ADC6, ADC7},
hal::port::{
PB0, PB1, PB2, PB3, PB4, PC0, PC1, PC2, PC3, PC4, PC5, PD2, PD3, PD4, PD5, PD6, PD7,
},
hal::{
port::{
PB0, PB1, PB2, PB3, PB4, PC0, PC1, PC2, PC3, PC4, PC5, PD2, PD3, PD4, PD5, PD6, PD7,
},
Atmega,
},
pac::ADC,
port::{mode::Output, Pin},
prelude::*,
Adc,
@@ -25,6 +21,10 @@ use ufmt::derive::uDebug;
// NOTE: 115200 @ 16MHz is 3.5% off, try 9600 or 1M if it causes issues (https://wormfood.net/avrbaudcalc.php)
const SERIAL_BAUD: u32 = 115200;
// Analog threshold level of key press on ADC read from KN or KO
pub const KEYBOARD_ADC_THRESHOLD: u16 = 500;
// Number of key presses to record for debounce
pub const DEBOUNCE_DEPTH: usize = 4;
#[cfg(not(doc))]
#[panic_handler]
@@ -332,92 +332,6 @@ impl DispalyState {
}
}
#[derive(uDebug, Clone, Copy, PartialEq, Eq)]
enum InputKey {
Up,
C,
Num(u8),
Mul,
Div,
Plus,
Minus,
Down,
E,
}
impl InputKey {
fn map(display_no: usize, kn: bool, ko: bool) -> Option<InputKey> {
match (display_no, kn, ko) {
(0, true, false) => Some(InputKey::Num(1)),
(0, false, true) => Some(InputKey::C),
(1, true, false) => Some(InputKey::Num(5)),
(1, false, true) => Some(InputKey::Div),
(2, true, false) => Some(InputKey::Num(6)),
(2, false, true) => Some(InputKey::Mul),
(3, true, false) => Some(InputKey::Num(7)),
(3, false, true) => Some(InputKey::Up),
(4, true, false) => Some(InputKey::Num(8)),
(4, false, true) => Some(InputKey::E),
(5, true, false) => Some(InputKey::Num(9)),
(5, false, true) => Some(InputKey::Num(0)),
(6, true, false) => Some(InputKey::Num(2)),
(6, false, true) => Some(InputKey::Down),
(7, true, false) => Some(InputKey::Num(3)),
(7, false, true) => Some(InputKey::Plus),
(8, true, false) => Some(InputKey::Num(4)),
(8, false, true) => Some(InputKey::Minus),
_ => None,
}
}
}
struct Input<KN, KO> {
kn: KN,
ko: KO,
}
impl<KN: AdcChannel<Atmega, ADC>, KO: AdcChannel<Atmega, ADC>> Input<KN, KO> {
fn new(kn: KN, ko: KO) -> Input<KN, KO> {
Input { kn, ko }
}
fn read(&self, adc: &mut Adc) -> Option<(bool, bool)> {
let kn = adc.read_blocking(&self.kn);
let ko = adc.read_blocking(&self.ko);
if kn > 500 || ko > 500 {
Some((kn > 500, ko > 500))
} else {
None
}
}
}
#[derive(Default)]
struct Debounce {
history: [Option<InputKey>; 4],
pos: usize,
last: Option<InputKey>,
}
impl Debounce {
fn input(&mut self, key: Option<InputKey>) -> Option<InputKey> {
self.history[self.pos] = key;
self.pos += 1;
if self.pos >= self.history.len() {
self.pos = 0;
}
if self.history.iter().all(|hist| hist == &key) && self.last != key {
self.last = key;
key
} else if self.history.iter().all(|hist| hist == &None) {
self.last = None;
None
} else {
None
}
}
}
#[derive(Default)]
struct NumberInput {
minus: bool,
@@ -538,14 +452,10 @@ fn main() -> ! {
let dp = arduino_hal::Peripherals::take().unwrap();
let pins = arduino_hal::pins!(dp);
// let mut led = pins.d13.into_output();
let mut serial = arduino_hal::default_serial!(dp, pins, SERIAL_BAUD);
ufmt::uwriteln!(&mut serial, "Hello from Arduino!").unwrap_infallible();
// let mut kd_KN = pins..into_input();
// let mut kd_KO = *pins.a.into_output();
let mut io = IOPins::new(
pins.d2.into_output(),
pins.d3.into_output(),
@@ -570,7 +480,7 @@ fn main() -> ! {
);
let mut adc = Adc::new(dp.ADC, Default::default());
let input = Input::new(ADC7, ADC6);
let input = Keyboard::new(ADC7, ADC6);
let mut debounce = Debounce::default();
let mut number_input = NumberInput::default();
@@ -581,7 +491,7 @@ fn main() -> ! {
let mut state = State::EnterSignificant;
loop {
let mut key: Option<(usize, bool, bool)> = None;
let mut last_key_readout: Option<(usize, KeyReadout)> = None;
for (mut io_select, ss) in io.iter_mut().zip(display.0.iter()) {
ss.apply(&mut seg);
io_select.set_on();
@@ -589,27 +499,26 @@ fn main() -> ! {
io_select.set_off();
seg.set_off();
io_select.set_on();
// arduino_hal::delay_us(100);
if let Some((kn, ko)) = input.read(&mut adc) {
key = Some((io_select.display_no(), kn, ko))
if let Some(key_readout) = input.read(&mut adc) {
last_key_readout = Some((io_select.display_no(), key_readout));
}
io_select.set_off();
}
let key = key.and_then(|(no, kn, ko)| InputKey::map(no, kn, ko));
if let Some(key) = debounce.input(key) {
let key_press = last_key_readout
.and_then(|(display_no, key_readout)| key_readout.to_keypress(display_no));
if let Some(key) = debounce.input(key_press) {
ufmt::uwriteln!(&mut serial, "key: {:?} state: {:?}", key, state).unwrap_infallible();
let res = match state {
State::EnterSignificant => match key {
InputKey::C => {
KeyPress::C => {
number_input.reset();
calc.reset();
Ok(())
}
InputKey::Num(val) => number_input.input(val),
InputKey::Minus => Ok(number_input.toggle_minus()),
InputKey::E => {
KeyPress::Num(val) => number_input.input(val),
KeyPress::Minus => Ok(number_input.toggle_minus()),
KeyPress::E => {
number_input.toggle_enter_exponent();
state = State::EnterExponent;
Ok(())
@@ -617,15 +526,15 @@ fn main() -> ! {
_ => Ok(()),
},
State::EnterExponent => match key {
InputKey::C => {
KeyPress::C => {
number_input.reset();
calc.reset();
state = State::EnterSignificant;
Ok(())
}
InputKey::Num(val) => number_input.input(val),
InputKey::Minus => Ok(number_input.toggle_minus()),
InputKey::E => {
KeyPress::Num(val) => number_input.input(val),
KeyPress::Minus => Ok(number_input.toggle_minus()),
KeyPress::E => {
number_input.toggle_enter_exponent();
match calc.push(number_input.to_decimal()) {
Ok(()) => {
@@ -643,15 +552,15 @@ fn main() -> ! {
_ => Ok(()),
},
State::EnterOperation => match key {
InputKey::Up => todo!(),
InputKey::C => {
KeyPress::Up => todo!(),
KeyPress::C => {
number_input.reset();
calc.reset();
state = State::EnterSignificant;
Ok(())
}
InputKey::Num(_) => todo!(),
InputKey::Mul => match calc.mul() {
KeyPress::Num(_) => todo!(),
KeyPress::Mul => match calc.mul() {
Ok(dec) => {
number_input.set_decimal(dec);
state = State::EnterSignificant;
@@ -659,7 +568,7 @@ fn main() -> ! {
}
Err(_) => Err(()),
},
InputKey::Div => match calc.div() {
KeyPress::Div => match calc.div() {
Ok(dec) => {
number_input.set_decimal(dec);
state = State::EnterSignificant;
@@ -667,7 +576,7 @@ fn main() -> ! {
}
Err(_) => Err(()),
},
InputKey::Plus => match calc.add() {
KeyPress::Plus => match calc.add() {
Ok(dec) => {
number_input.set_decimal(dec);
state = State::EnterSignificant;
@@ -675,7 +584,7 @@ fn main() -> ! {
}
Err(_) => Err(()),
},
InputKey::Minus => match calc.sub() {
KeyPress::Minus => match calc.sub() {
Ok(dec) => {
number_input.set_decimal(dec);
state = State::EnterSignificant;
@@ -683,11 +592,11 @@ fn main() -> ! {
}
Err(_) => Err(()),
},
InputKey::Down => todo!(),
InputKey::E => todo!(),
KeyPress::Down => todo!(),
KeyPress::E => todo!(),
},
State::Err => match key {
InputKey::C => {
KeyPress::C => {
number_input.reset();
calc.reset();
state = State::EnterSignificant;