factored out keyboard file
This commit is contained in:
104
src/keyboard.rs
Normal file
104
src/keyboard.rs
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
161
src/main.rs
161
src/main.rs
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user