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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
159
src/main.rs
159
src/main.rs
@@ -1,22 +1,18 @@
|
|||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
||||||
|
mod keyboard;
|
||||||
|
|
||||||
use calc_math::calc::StackCalc;
|
use calc_math::calc::StackCalc;
|
||||||
use calc_math::Decimal;
|
use calc_math::Decimal;
|
||||||
use core::ops::{Index, IndexMut};
|
use core::ops::{Index, IndexMut};
|
||||||
|
use keyboard::{Debounce, KeyPress, KeyReadout, Keyboard};
|
||||||
|
|
||||||
use arduino_hal::{
|
use arduino_hal::{
|
||||||
adc::{
|
adc::channel::{ADC6, ADC7},
|
||||||
channel::{ADC6, ADC7},
|
hal::port::{
|
||||||
AdcChannel,
|
|
||||||
},
|
|
||||||
hal::{
|
|
||||||
port::{
|
|
||||||
PB0, PB1, PB2, PB3, PB4, PC0, PC1, PC2, PC3, PC4, PC5, PD2, PD3, PD4, PD5, PD6, PD7,
|
PB0, PB1, PB2, PB3, PB4, PC0, PC1, PC2, PC3, PC4, PC5, PD2, PD3, PD4, PD5, PD6, PD7,
|
||||||
},
|
},
|
||||||
Atmega,
|
|
||||||
},
|
|
||||||
pac::ADC,
|
|
||||||
port::{mode::Output, Pin},
|
port::{mode::Output, Pin},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
Adc,
|
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)
|
// 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;
|
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))]
|
#[cfg(not(doc))]
|
||||||
#[panic_handler]
|
#[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)]
|
#[derive(Default)]
|
||||||
struct NumberInput {
|
struct NumberInput {
|
||||||
minus: bool,
|
minus: bool,
|
||||||
@@ -538,14 +452,10 @@ fn main() -> ! {
|
|||||||
let dp = arduino_hal::Peripherals::take().unwrap();
|
let dp = arduino_hal::Peripherals::take().unwrap();
|
||||||
let pins = arduino_hal::pins!(dp);
|
let pins = arduino_hal::pins!(dp);
|
||||||
|
|
||||||
// let mut led = pins.d13.into_output();
|
|
||||||
let mut serial = arduino_hal::default_serial!(dp, pins, SERIAL_BAUD);
|
let mut serial = arduino_hal::default_serial!(dp, pins, SERIAL_BAUD);
|
||||||
|
|
||||||
ufmt::uwriteln!(&mut serial, "Hello from Arduino!").unwrap_infallible();
|
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(
|
let mut io = IOPins::new(
|
||||||
pins.d2.into_output(),
|
pins.d2.into_output(),
|
||||||
pins.d3.into_output(),
|
pins.d3.into_output(),
|
||||||
@@ -570,7 +480,7 @@ fn main() -> ! {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let mut adc = Adc::new(dp.ADC, Default::default());
|
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 debounce = Debounce::default();
|
||||||
let mut number_input = NumberInput::default();
|
let mut number_input = NumberInput::default();
|
||||||
|
|
||||||
@@ -581,7 +491,7 @@ fn main() -> ! {
|
|||||||
let mut state = State::EnterSignificant;
|
let mut state = State::EnterSignificant;
|
||||||
|
|
||||||
loop {
|
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()) {
|
for (mut io_select, ss) in io.iter_mut().zip(display.0.iter()) {
|
||||||
ss.apply(&mut seg);
|
ss.apply(&mut seg);
|
||||||
io_select.set_on();
|
io_select.set_on();
|
||||||
@@ -589,27 +499,26 @@ fn main() -> ! {
|
|||||||
io_select.set_off();
|
io_select.set_off();
|
||||||
seg.set_off();
|
seg.set_off();
|
||||||
io_select.set_on();
|
io_select.set_on();
|
||||||
// arduino_hal::delay_us(100);
|
if let Some(key_readout) = input.read(&mut adc) {
|
||||||
if let Some((kn, ko)) = input.read(&mut adc) {
|
last_key_readout = Some((io_select.display_no(), key_readout));
|
||||||
key = Some((io_select.display_no(), kn, ko))
|
|
||||||
}
|
}
|
||||||
io_select.set_off();
|
io_select.set_off();
|
||||||
}
|
}
|
||||||
|
|
||||||
let key = key.and_then(|(no, kn, ko)| InputKey::map(no, kn, ko));
|
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) {
|
if let Some(key) = debounce.input(key_press) {
|
||||||
ufmt::uwriteln!(&mut serial, "key: {:?} state: {:?}", key, state).unwrap_infallible();
|
ufmt::uwriteln!(&mut serial, "key: {:?} state: {:?}", key, state).unwrap_infallible();
|
||||||
let res = match state {
|
let res = match state {
|
||||||
State::EnterSignificant => match key {
|
State::EnterSignificant => match key {
|
||||||
InputKey::C => {
|
KeyPress::C => {
|
||||||
number_input.reset();
|
number_input.reset();
|
||||||
calc.reset();
|
calc.reset();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
InputKey::Num(val) => number_input.input(val),
|
KeyPress::Num(val) => number_input.input(val),
|
||||||
InputKey::Minus => Ok(number_input.toggle_minus()),
|
KeyPress::Minus => Ok(number_input.toggle_minus()),
|
||||||
InputKey::E => {
|
KeyPress::E => {
|
||||||
number_input.toggle_enter_exponent();
|
number_input.toggle_enter_exponent();
|
||||||
state = State::EnterExponent;
|
state = State::EnterExponent;
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -617,15 +526,15 @@ fn main() -> ! {
|
|||||||
_ => Ok(()),
|
_ => Ok(()),
|
||||||
},
|
},
|
||||||
State::EnterExponent => match key {
|
State::EnterExponent => match key {
|
||||||
InputKey::C => {
|
KeyPress::C => {
|
||||||
number_input.reset();
|
number_input.reset();
|
||||||
calc.reset();
|
calc.reset();
|
||||||
state = State::EnterSignificant;
|
state = State::EnterSignificant;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
InputKey::Num(val) => number_input.input(val),
|
KeyPress::Num(val) => number_input.input(val),
|
||||||
InputKey::Minus => Ok(number_input.toggle_minus()),
|
KeyPress::Minus => Ok(number_input.toggle_minus()),
|
||||||
InputKey::E => {
|
KeyPress::E => {
|
||||||
number_input.toggle_enter_exponent();
|
number_input.toggle_enter_exponent();
|
||||||
match calc.push(number_input.to_decimal()) {
|
match calc.push(number_input.to_decimal()) {
|
||||||
Ok(()) => {
|
Ok(()) => {
|
||||||
@@ -643,15 +552,15 @@ fn main() -> ! {
|
|||||||
_ => Ok(()),
|
_ => Ok(()),
|
||||||
},
|
},
|
||||||
State::EnterOperation => match key {
|
State::EnterOperation => match key {
|
||||||
InputKey::Up => todo!(),
|
KeyPress::Up => todo!(),
|
||||||
InputKey::C => {
|
KeyPress::C => {
|
||||||
number_input.reset();
|
number_input.reset();
|
||||||
calc.reset();
|
calc.reset();
|
||||||
state = State::EnterSignificant;
|
state = State::EnterSignificant;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
InputKey::Num(_) => todo!(),
|
KeyPress::Num(_) => todo!(),
|
||||||
InputKey::Mul => match calc.mul() {
|
KeyPress::Mul => match calc.mul() {
|
||||||
Ok(dec) => {
|
Ok(dec) => {
|
||||||
number_input.set_decimal(dec);
|
number_input.set_decimal(dec);
|
||||||
state = State::EnterSignificant;
|
state = State::EnterSignificant;
|
||||||
@@ -659,7 +568,7 @@ fn main() -> ! {
|
|||||||
}
|
}
|
||||||
Err(_) => Err(()),
|
Err(_) => Err(()),
|
||||||
},
|
},
|
||||||
InputKey::Div => match calc.div() {
|
KeyPress::Div => match calc.div() {
|
||||||
Ok(dec) => {
|
Ok(dec) => {
|
||||||
number_input.set_decimal(dec);
|
number_input.set_decimal(dec);
|
||||||
state = State::EnterSignificant;
|
state = State::EnterSignificant;
|
||||||
@@ -667,7 +576,7 @@ fn main() -> ! {
|
|||||||
}
|
}
|
||||||
Err(_) => Err(()),
|
Err(_) => Err(()),
|
||||||
},
|
},
|
||||||
InputKey::Plus => match calc.add() {
|
KeyPress::Plus => match calc.add() {
|
||||||
Ok(dec) => {
|
Ok(dec) => {
|
||||||
number_input.set_decimal(dec);
|
number_input.set_decimal(dec);
|
||||||
state = State::EnterSignificant;
|
state = State::EnterSignificant;
|
||||||
@@ -675,7 +584,7 @@ fn main() -> ! {
|
|||||||
}
|
}
|
||||||
Err(_) => Err(()),
|
Err(_) => Err(()),
|
||||||
},
|
},
|
||||||
InputKey::Minus => match calc.sub() {
|
KeyPress::Minus => match calc.sub() {
|
||||||
Ok(dec) => {
|
Ok(dec) => {
|
||||||
number_input.set_decimal(dec);
|
number_input.set_decimal(dec);
|
||||||
state = State::EnterSignificant;
|
state = State::EnterSignificant;
|
||||||
@@ -683,11 +592,11 @@ fn main() -> ! {
|
|||||||
}
|
}
|
||||||
Err(_) => Err(()),
|
Err(_) => Err(()),
|
||||||
},
|
},
|
||||||
InputKey::Down => todo!(),
|
KeyPress::Down => todo!(),
|
||||||
InputKey::E => todo!(),
|
KeyPress::E => todo!(),
|
||||||
},
|
},
|
||||||
State::Err => match key {
|
State::Err => match key {
|
||||||
InputKey::C => {
|
KeyPress::C => {
|
||||||
number_input.reset();
|
number_input.reset();
|
||||||
calc.reset();
|
calc.reset();
|
||||||
state = State::EnterSignificant;
|
state = State::EnterSignificant;
|
||||||
|
|||||||
Reference in New Issue
Block a user