Create keypad handler
This commit is contained in:
parent
91e75d37a0
commit
2fb089fd03
351
src/keypad.rs
Normal file
351
src/keypad.rs
Normal file
@ -0,0 +1,351 @@
|
|||||||
|
#[doc(hidden)]
|
||||||
|
pub extern crate core as _core;
|
||||||
|
|
||||||
|
use core::cell::RefCell;
|
||||||
|
|
||||||
|
use esp_hal::gpio::{Input, InputPin, OutputOpenDrain, OutputPin};
|
||||||
|
|
||||||
|
/// A virtual `embedded-hal` input pin representing one key of the keypad.
|
||||||
|
///
|
||||||
|
/// A `KeypadInput` stores references to one row and one column pin. When you
|
||||||
|
/// read from it with `.is_low()` or `.is_high()`, it secretly sets the column
|
||||||
|
/// pin low, reads from the row pin, and then sets the column pin high again.
|
||||||
|
/// The column pin is actually stored inside a `RefCell` in the keypad struct,
|
||||||
|
/// so that multiple `KeypadInput`s can mutate the column pin's state as needed,
|
||||||
|
/// even though they only have a shared/immutable reference to it.
|
||||||
|
///
|
||||||
|
/// This has several implications.
|
||||||
|
///
|
||||||
|
/// 1) Reading from `KeypadInput`s is not reentrant. If we were in the middle
|
||||||
|
/// of reading a `KeypadInput` and entered an interrupt service routine that
|
||||||
|
/// read any `KeypadInput` of the same keypad, we might read an incorrect value
|
||||||
|
/// or cause a `panic`.
|
||||||
|
///
|
||||||
|
/// 2) Reading from a `KeypadInput` is slower than reading from a real input
|
||||||
|
/// pin, because it needs to change the output pin state twice for every read.
|
||||||
|
pub struct KeypadInput<'a> {
|
||||||
|
row: &'a RefCell<Input<'a, InputPin>>,
|
||||||
|
col: &'a RefCell<OutputOpenDrain<'a, dyn InputPin + OutputPin>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, E> KeypadInput<'a, E> {
|
||||||
|
/// Create a new `KeypadInput`. For use in macros.
|
||||||
|
pub fn new(row: &'a dyn InputPin, col: &'a RefCell<dyn OutputPin>) -> Self {
|
||||||
|
Self { row, col }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, E> InputPin for KeypadInput<'a, E> {
|
||||||
|
type Error = E;
|
||||||
|
/// Read the state of the key at this row and column. Not reentrant.
|
||||||
|
fn is_high(&self) -> Result<bool, E> {
|
||||||
|
Ok(!self.is_low()?)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read the state of the key at this row and column. Not reentrant.
|
||||||
|
fn is_low(&self) -> Result<bool, E> {
|
||||||
|
self.col.borrow_mut().set_low()?;
|
||||||
|
let out = self.row.is_low()?;
|
||||||
|
self.col.borrow_mut().set_high()?;
|
||||||
|
Ok(out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Define a new struct representing your keypad matrix circuit.
|
||||||
|
///
|
||||||
|
/// Every pin has a unique type, depending on its pin number and its current
|
||||||
|
/// mode. This struct is where you specify which pin types will be used in the
|
||||||
|
/// rows and columns of the keypad matrix. All the row pins must implement the
|
||||||
|
/// `InputPin` trait, and the column pins must implement the `OutputPin` trait.
|
||||||
|
/// The associated `Error` type of the `InputPin` and `OutputPin` traits must be
|
||||||
|
/// the same for every row and column pin, and you must specify it after your
|
||||||
|
/// struct name with `<Error = ...>`
|
||||||
|
///
|
||||||
|
/// You can specify the visibility of the struct (eg. `pub`) as usual, and add
|
||||||
|
/// doc comments using the `#[doc="..."]` attribute.
|
||||||
|
///
|
||||||
|
/// Don't access or modify the struct's fields directly. Instead, use
|
||||||
|
/// the methods implemented by this macro, documented here:
|
||||||
|
/// [`example_generated::ExampleKeypad`](./example_generated/struct.ExampleKeypad.html)
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # #![cfg_attr(docs_rs_workaround, feature(macro_vis_matcher))]
|
||||||
|
/// #[macro_use]
|
||||||
|
/// extern crate keypad;
|
||||||
|
///
|
||||||
|
/// use keypad::mock_hal::{self, Input, OpenDrain, Output, PullUp};
|
||||||
|
/// use core::convert::Infallible;
|
||||||
|
///
|
||||||
|
/// keypad_struct! {
|
||||||
|
/// #[doc="My super-special keypad."]
|
||||||
|
/// pub struct ExampleKeypad<Error = Infallible> {
|
||||||
|
/// rows: (
|
||||||
|
/// mock_hal::gpioa::PA0<Input<PullUp>>,
|
||||||
|
/// mock_hal::gpioa::PA1<Input<PullUp>>,
|
||||||
|
/// mock_hal::gpioa::PA2<Input<PullUp>>,
|
||||||
|
/// mock_hal::gpioa::PA3<Input<PullUp>>,
|
||||||
|
/// ),
|
||||||
|
/// columns: (
|
||||||
|
/// mock_hal::gpioa::PA4<Output<OpenDrain>>,
|
||||||
|
/// mock_hal::gpioa::PA5<Output<OpenDrain>>,
|
||||||
|
/// mock_hal::gpioa::PA6<Output<OpenDrain>>,
|
||||||
|
/// mock_hal::gpioa::PA7<Output<OpenDrain>>,
|
||||||
|
/// mock_hal::gpioa::PA8<Output<OpenDrain>>,
|
||||||
|
/// ),
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// # fn main() {
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// This macro uses `unsafe` to create an array with uninitialized memory, which
|
||||||
|
/// is then immediately initialized in a loop. This is fine as long as there is
|
||||||
|
/// not a bug in how the macro calculates the dimensions of the array.
|
||||||
|
|
||||||
|
// There are two reasons why this big, scary macro is necessary:
|
||||||
|
//
|
||||||
|
// 1) Every single pin has a unique type, and we don't know which pins will be used. We know that
|
||||||
|
// they all implement a certain trait, but that doesn't help much because it doesn't tell us the
|
||||||
|
// size of the type, so we can't directly stick it into the struct. If we could use dynamic
|
||||||
|
// allocation, we could just store pins on the heap as boxed trait objects. But this crate needs
|
||||||
|
// to work on embedded platforms without an allocator! So, we use this macro to generate a
|
||||||
|
// struct containing the exact, concrete pin types the user provides.
|
||||||
|
//
|
||||||
|
// 2) We don't know how many pins there will be, because the keypad could have any number of rows
|
||||||
|
// and columns. That makes it hard to implement `decompose()`, which needs to iterate over the
|
||||||
|
// row and column pins. We can't store pins in arrays because they all have unique types, but we
|
||||||
|
// can store them in tuples instead. The problem is that you can't actually iterate over a tuple,
|
||||||
|
// and even indexing into arbitrary fields of a tuple using a macro is stupidly hard. The best
|
||||||
|
// approach I could come up with was to repeatedly destructure the tuple with different patterns,
|
||||||
|
// like this:
|
||||||
|
//
|
||||||
|
// let tuple = (0, 1, 2);
|
||||||
|
// let array = [
|
||||||
|
// {
|
||||||
|
// let (ref x, ..) = tuple;
|
||||||
|
// x
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// let (_, ref x, ..) = tuple;
|
||||||
|
// x
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// let (_, _, ref x, ..) = tuple;
|
||||||
|
// x
|
||||||
|
// },
|
||||||
|
// ];
|
||||||
|
// for reference in array.into_iter() {
|
||||||
|
// // ...
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// So that's how the `keypad_struct!()` macro iterates over tuples of pins. It counts the length of
|
||||||
|
// the tuple (also tricky!), creates patterns with increasing numbers of underscores, and uses them
|
||||||
|
// to build up a temporary array of references that it can iterate over. Luckily this code only
|
||||||
|
// needs to be run once, in `decompose()`, and not every time we read from a pin.
|
||||||
|
//
|
||||||
|
// I can't think of any simpler design that still has a convenient API and allows the keypad struct
|
||||||
|
// to own the row and column pins. If they weren't owned, the crate would be less convenient to use
|
||||||
|
// but could provide a generic Keypad struct like this:
|
||||||
|
//
|
||||||
|
// pub struct Keypad<'a, E, const R: usize, const C: usize> {
|
||||||
|
// rows: [&'a dyn InputPin<Error = E>; R],
|
||||||
|
// columns: [&'a RefCell<dyn OutputPin<Error = E>>; C],
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! keypad_struct {
|
||||||
|
(
|
||||||
|
$(#[$attributes:meta])* $visibility:vis struct $struct_name:ident {
|
||||||
|
rows: ( $($row_type:ty),* $(,)* ),
|
||||||
|
columns: ( $($col_type:ty),* $(,)* ),
|
||||||
|
}
|
||||||
|
) => {
|
||||||
|
compile_error!("You must specify the associated `Error` type of the row and column pins'\
|
||||||
|
`InputPin` and `OutputPin` traits.\n\
|
||||||
|
Example: `struct MyStruct <Error = Infallible> { ... }`");
|
||||||
|
};
|
||||||
|
(
|
||||||
|
$(#[$attributes:meta])* $visibility:vis struct $struct_name:ident <Error = $error_type:ty> {
|
||||||
|
rows: ( $($row_type:ty),* $(,)* ),
|
||||||
|
columns: ( $($col_type:ty),* $(,)* ),
|
||||||
|
}
|
||||||
|
) => {
|
||||||
|
$(#[$attributes])* $visibility struct $struct_name {
|
||||||
|
/// The input pins used for reading each row.
|
||||||
|
rows: ($($row_type),* ,),
|
||||||
|
/// The output pins used for scanning through each column. They're
|
||||||
|
/// wrapped in RefCells so that we can change their state even if we
|
||||||
|
/// only have shared/immutable reference to them. This lets us
|
||||||
|
/// actively scan the matrix when reading the state of a virtual
|
||||||
|
/// `KeypadInput` pin.
|
||||||
|
columns: ($($crate::_core::cell::RefCell<$col_type>),* ,),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl $struct_name {
|
||||||
|
/// Get a 2d array of embedded-hal input pins, each representing one
|
||||||
|
/// key in the keypad matrix.
|
||||||
|
#[allow(dead_code)]
|
||||||
|
$visibility fn decompose<'a>(&'a self) ->
|
||||||
|
keypad_struct!(
|
||||||
|
@array2d_type
|
||||||
|
$crate::KeypadInput<'a, $error_type>,
|
||||||
|
($($row_type),*)
|
||||||
|
($($crate::_core::cell::RefCell<$col_type>),*)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
|
||||||
|
let rows: [
|
||||||
|
&dyn $crate::embedded_hal::digital::v2::InputPin<Error = $error_type>;
|
||||||
|
keypad_struct!(@count $($row_type)*)
|
||||||
|
]
|
||||||
|
= keypad_struct!(@tuple self.rows, ($($row_type),*));
|
||||||
|
|
||||||
|
let columns: [
|
||||||
|
&$crate::_core::cell::RefCell<dyn $crate::embedded_hal::digital::v2::OutputPin<Error = $error_type>>;
|
||||||
|
keypad_struct!(@count $($col_type)*)
|
||||||
|
]
|
||||||
|
= keypad_struct!(@tuple self.columns, ($($col_type),*));
|
||||||
|
|
||||||
|
// Create an uninitialized 2d array of MaybeUninit.
|
||||||
|
let mut out: keypad_struct!(
|
||||||
|
@array2d_type
|
||||||
|
$crate::_core::mem::MaybeUninit<$crate::KeypadInput<'a, $error_type>>,
|
||||||
|
($($row_type),*)
|
||||||
|
($($crate::_core::cell::RefCell<$col_type>),*)
|
||||||
|
) = unsafe {
|
||||||
|
$crate::_core::mem::MaybeUninit::uninit().assume_init()
|
||||||
|
};
|
||||||
|
|
||||||
|
// Initialize each element with a KeypadInput struct
|
||||||
|
for r in 0..rows.len() {
|
||||||
|
for c in 0..columns.len() {
|
||||||
|
out[r][c].write($crate::KeypadInput::new(rows[r], columns[c]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// All elements are initialized. Transmute the array to the initialized type.
|
||||||
|
unsafe { $crate::_core::mem::transmute::<_, _>(out) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Give back ownership of the row and column pins.
|
||||||
|
///
|
||||||
|
/// This consumes the keypad struct. All references to its virtual
|
||||||
|
/// `KeypadInput` pins must have gone out of scope before you try to
|
||||||
|
/// call `.release()`, or it will fail to compile.
|
||||||
|
///
|
||||||
|
/// The column pins will be returned inside of `RefCell`s (because
|
||||||
|
/// macros are hard). You can use `.into_inner()` to extract
|
||||||
|
/// each column pin from its `RefCell`.
|
||||||
|
#[allow(dead_code)]
|
||||||
|
$visibility fn release(self) ->(($($row_type),* ,), ($($crate::_core::cell::RefCell<$col_type>),* ,)) {
|
||||||
|
(self.rows, self.columns)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
(@array2d_type $element_type:ty, ($($row:ty),*) ($($col:ty),*) ) => {
|
||||||
|
[keypad_struct!(@array1d_type $element_type, ($($col),*)) ; keypad_struct!(@count $($row)*)]
|
||||||
|
};
|
||||||
|
(@array1d_type $element_type:ty, ($($col:ty),*)) => {
|
||||||
|
[$element_type ; keypad_struct!(@count $($col)*)]
|
||||||
|
};
|
||||||
|
(@count $($token_trees:tt)*) => {
|
||||||
|
0usize $(+ keypad_struct!(@replace $token_trees 1usize))*
|
||||||
|
};
|
||||||
|
(@replace $_t:tt $sub:expr) => {
|
||||||
|
$sub
|
||||||
|
};
|
||||||
|
(@underscore $unused:tt) => {
|
||||||
|
_
|
||||||
|
};
|
||||||
|
(@destructure_ref $tuple:expr, ($($repeat_n:ty),*)) => {
|
||||||
|
{
|
||||||
|
let (
|
||||||
|
$(keypad_struct!(@underscore $repeat_n),)*
|
||||||
|
ref nth, ..) = $tuple;
|
||||||
|
nth
|
||||||
|
}
|
||||||
|
};
|
||||||
|
(@tuple_helper $tuple:expr, ($head:ty), ($($result:expr),* $(,)*)) => {
|
||||||
|
[
|
||||||
|
keypad_struct!(@destructure_ref $tuple, ()),
|
||||||
|
$($result),*
|
||||||
|
]
|
||||||
|
};
|
||||||
|
(@tuple_helper $tuple:expr, ($head:ty $(,$repeats:ty)* $(,)*), ($($result:expr),* $(,)*)) => {
|
||||||
|
keypad_struct!(
|
||||||
|
@tuple_helper $tuple, ($($repeats),*),
|
||||||
|
(
|
||||||
|
keypad_struct!(@destructure_ref $tuple, ($($repeats),*)),
|
||||||
|
$($result),*
|
||||||
|
)
|
||||||
|
)
|
||||||
|
};
|
||||||
|
(@tuple $tuple:expr, ($($repeats:ty),*)) => {
|
||||||
|
keypad_struct!(@tuple_helper $tuple, ($($repeats),*) , ())
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create an instance of the struct you defined with the `keypad_struct!()` macro..
|
||||||
|
///
|
||||||
|
/// The pin numbers and modes will need to match the ones you specified with `keypad_struct!()`.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # #![cfg_attr(docs_rs_workaround, feature(macro_vis_matcher))]
|
||||||
|
/// # #[macro_use]
|
||||||
|
/// # extern crate keypad;
|
||||||
|
/// # use core::convert::Infallible;
|
||||||
|
/// # use keypad::mock_hal::{self, Input, OpenDrain, Output, PullUp};
|
||||||
|
/// # use keypad::mock_hal::{GpioExt, GPIOA};
|
||||||
|
/// # keypad_struct!{
|
||||||
|
/// # pub struct ExampleKeypad<Error = Infallible>{
|
||||||
|
/// # rows: (
|
||||||
|
/// # mock_hal::gpioa::PA0<Input<PullUp>>,
|
||||||
|
/// # mock_hal::gpioa::PA1<Input<PullUp>>,
|
||||||
|
/// # mock_hal::gpioa::PA2<Input<PullUp>>,
|
||||||
|
/// # mock_hal::gpioa::PA3<Input<PullUp>>,
|
||||||
|
/// # ),
|
||||||
|
/// # columns: (
|
||||||
|
/// # mock_hal::gpioa::PA4<Output<OpenDrain>>,
|
||||||
|
/// # mock_hal::gpioa::PA5<Output<OpenDrain>>,
|
||||||
|
/// # mock_hal::gpioa::PA6<Output<OpenDrain>>,
|
||||||
|
/// # mock_hal::gpioa::PA7<Output<OpenDrain>>,
|
||||||
|
/// # mock_hal::gpioa::PA8<Output<OpenDrain>>,
|
||||||
|
/// # ),
|
||||||
|
/// # }
|
||||||
|
/// # }
|
||||||
|
/// # fn main() {
|
||||||
|
/// let pins = GPIOA::split();
|
||||||
|
///
|
||||||
|
/// let keypad = keypad_new!(ExampleKeypad {
|
||||||
|
/// rows: (
|
||||||
|
/// pins.pa0.into_pull_up_input(),
|
||||||
|
/// pins.pa1.into_pull_up_input(),
|
||||||
|
/// pins.pa2.into_pull_up_input(),
|
||||||
|
/// pins.pa3.into_pull_up_input(),
|
||||||
|
/// ),
|
||||||
|
/// columns: (
|
||||||
|
/// pins.pa4.into_open_drain_output(),
|
||||||
|
/// pins.pa5.into_open_drain_output(),
|
||||||
|
/// pins.pa6.into_open_drain_output(),
|
||||||
|
/// pins.pa7.into_open_drain_output(),
|
||||||
|
/// pins.pa8.into_open_drain_output(),
|
||||||
|
/// ),
|
||||||
|
/// });
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! keypad_new {
|
||||||
|
( $struct_name:ident {
|
||||||
|
rows: ( $($row_val:expr),* $(,)* ),
|
||||||
|
columns: ( $($col_val:expr),* $(,)* ),
|
||||||
|
}) => {
|
||||||
|
$struct_name {
|
||||||
|
rows: ($($row_val),* ,),
|
||||||
|
columns: ($($crate::_core::cell::RefCell::new($col_val)),* ,),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
160
src/main.rs
160
src/main.rs
@ -115,20 +115,37 @@ fn main() -> ! {
|
|||||||
// .unwrap();
|
// .unwrap();
|
||||||
driver.clear_frame(&mut spi, &mut delay).unwrap();
|
driver.clear_frame(&mut spi, &mut delay).unwrap();
|
||||||
|
|
||||||
let mut kbd = Keyboard {
|
let mut gpio2 = Input::new(io.pins.gpio2, Pull::Up);
|
||||||
rows: Rows {
|
let mut gpio3 = Input::new(io.pins.gpio3, Pull::Up);
|
||||||
gpio2: Input::new(io.pins.gpio2, Pull::Up),
|
let mut gpio4 = Input::new(io.pins.gpio4, Pull::Up);
|
||||||
gpio3: Input::new(io.pins.gpio3, Pull::Up),
|
let mut gpio5 = Input::new(io.pins.gpio5, Pull::Up);
|
||||||
gpio4: Input::new(io.pins.gpio4, Pull::Up),
|
|
||||||
gpio5: Input::new(io.pins.gpio5, Pull::Up),
|
let mut gpio6 = OutputOpenDrain::new(io.pins.gpio6, Level::Low, Pull::Up);
|
||||||
},
|
let mut gpio7 = OutputOpenDrain::new(io.pins.gpio7, Level::Low, Pull::Up);
|
||||||
cols: Cols {
|
let mut gpio8 = OutputOpenDrain::new(io.pins.gpio8, Level::Low, Pull::Up);
|
||||||
gpio6: Output::new(io.pins.gpio6, Level::Low),
|
let mut gpio10 = OutputOpenDrain::new(io.pins.gpio10, Level::Low, Pull::Up);
|
||||||
gpio7: Output::new(io.pins.gpio7, Level::Low),
|
|
||||||
gpio8: Output::new(io.pins.gpio8, Level::Low),
|
let mut kbd = Keypad((
|
||||||
gpio10: Output::new(io.pins.gpio10, Level::Low),
|
(&mut gpio2, &mut gpio6),
|
||||||
},
|
(&mut gpio3, &mut gpio6),
|
||||||
};
|
(&mut gpio4, &mut gpio6),
|
||||||
|
(&mut gpio5, &mut gpio6),
|
||||||
|
// --------------------------------------
|
||||||
|
(&mut gpio2, &mut gpio7),
|
||||||
|
(&mut gpio3, &mut gpio7),
|
||||||
|
(&mut gpio4, &mut gpio7),
|
||||||
|
(&mut gpio5, &mut gpio7),
|
||||||
|
// --------------------------------------
|
||||||
|
(&mut gpio2, &mut gpio8),
|
||||||
|
(&mut gpio3, &mut gpio8),
|
||||||
|
(&mut gpio4, &mut gpio8),
|
||||||
|
(&mut gpio5, &mut gpio8),
|
||||||
|
// --------------------------------------
|
||||||
|
(&mut gpio2, &mut gpio10),
|
||||||
|
(&mut gpio3, &mut gpio10),
|
||||||
|
(&mut gpio4, &mut gpio10),
|
||||||
|
(&mut gpio5, &mut gpio10),
|
||||||
|
));
|
||||||
|
|
||||||
let mut ctx = Context {
|
let mut ctx = Context {
|
||||||
button_pressed: None,
|
button_pressed: None,
|
||||||
@ -218,79 +235,78 @@ struct Rows<'d> {
|
|||||||
gpio5: Input<'d, Gpio5>, //
|
gpio5: Input<'d, Gpio5>, //
|
||||||
}
|
}
|
||||||
struct Cols<'d> {
|
struct Cols<'d> {
|
||||||
gpio6: Output<'d, Gpio6>, //
|
gpio6: OutputOpenDrain<'d, Gpio6>, //
|
||||||
gpio7: Output<'d, Gpio7>, //
|
gpio7: OutputOpenDrain<'d, Gpio7>, //
|
||||||
gpio8: Output<'d, Gpio8>, //
|
gpio8: OutputOpenDrain<'d, Gpio8>, //
|
||||||
gpio10: Output<'d, Gpio10>, //
|
gpio10: OutputOpenDrain<'d, Gpio10>, //
|
||||||
}
|
}
|
||||||
struct Keyboard<'d> {
|
pub type OOD<'d, T> = OutputOpenDrain<'d, T>;
|
||||||
rows: Rows<'d>,
|
|
||||||
cols: Cols<'d>,
|
struct Keypad<'d>(
|
||||||
}
|
pub (
|
||||||
impl<'d> Keyboard<'d> {
|
// --------------------------------------
|
||||||
|
(&'d mut Input<'d, Gpio2>, &'d mut OOD<'d, Gpio6>),
|
||||||
|
(&'d mut Input<'d, Gpio3>, &'d mut OOD<'d, Gpio6>),
|
||||||
|
(&'d mut Input<'d, Gpio4>, &'d mut OOD<'d, Gpio6>),
|
||||||
|
(&'d mut Input<'d, Gpio5>, &'d mut OOD<'d, Gpio6>),
|
||||||
|
// --------------------------------------
|
||||||
|
(&'d mut Input<'d, Gpio2>, &'d mut OOD<'d, Gpio7>),
|
||||||
|
(&'d mut Input<'d, Gpio3>, &'d mut OOD<'d, Gpio7>),
|
||||||
|
(&'d mut Input<'d, Gpio4>, &'d mut OOD<'d, Gpio7>),
|
||||||
|
(&'d mut Input<'d, Gpio5>, &'d mut OOD<'d, Gpio7>),
|
||||||
|
// --------------------------------------
|
||||||
|
(&'d mut Input<'d, Gpio2>, &'d mut OOD<'d, Gpio8>),
|
||||||
|
(&'d mut Input<'d, Gpio3>, &'d mut OOD<'d, Gpio8>),
|
||||||
|
(&'d mut Input<'d, Gpio4>, &'d mut OOD<'d, Gpio8>),
|
||||||
|
(&'d mut Input<'d, Gpio5>, &'d mut OOD<'d, Gpio8>),
|
||||||
|
// --------------------------------------
|
||||||
|
(&'d mut Input<'d, Gpio2>, &'d mut OOD<'d, Gpio10>),
|
||||||
|
(&'d mut Input<'d, Gpio3>, &'d mut OOD<'d, Gpio10>),
|
||||||
|
(&'d mut Input<'d, Gpio4>, &'d mut OOD<'d, Gpio10>),
|
||||||
|
(&'d mut Input<'d, Gpio5>, &'d mut OOD<'d, Gpio10>),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
impl<'d> Keypad<'d> {
|
||||||
pub fn pressed(&mut self) -> Option<Button> {
|
pub fn pressed(&mut self) -> Option<Button> {
|
||||||
self.cols.gpio6.set_high();
|
|
||||||
let col1 = [
|
let col1 = [
|
||||||
self.rows.gpio2.is_high(),
|
self.0 .0.is_low(),
|
||||||
self.rows.gpio3.is_high(),
|
self.0 .1.is_low(),
|
||||||
self.rows.gpio4.is_high(),
|
self.0 .2.is_low(),
|
||||||
self.rows.gpio5.is_high(),
|
self.0 .3.is_low(),
|
||||||
];
|
];
|
||||||
self.cols.gpio6.set_high();
|
|
||||||
|
|
||||||
self.cols.gpio7.set_high();
|
|
||||||
let col2 = [
|
let col2 = [
|
||||||
self.rows.gpio2.is_high(),
|
self.0 .4.is_low(),
|
||||||
self.rows.gpio3.is_high(),
|
self.0 .5.is_low(),
|
||||||
self.rows.gpio4.is_high(),
|
self.0 .6.is_low(),
|
||||||
self.rows.gpio5.is_high(),
|
self.0 .7.is_low(),
|
||||||
];
|
];
|
||||||
self.cols.gpio7.set_low();
|
|
||||||
|
|
||||||
self.cols.gpio8.set_high();
|
|
||||||
let col3 = [
|
let col3 = [
|
||||||
self.rows.gpio2.is_high(),
|
self.0 .8.is_low(),
|
||||||
self.rows.gpio3.is_high(),
|
self.0 .9.is_low(),
|
||||||
self.rows.gpio4.is_high(),
|
self.0 .10.is_low(),
|
||||||
self.rows.gpio5.is_high(),
|
self.0 .11.is_low(),
|
||||||
];
|
];
|
||||||
self.cols.gpio8.set_low();
|
|
||||||
|
|
||||||
self.cols.gpio10.set_high();
|
|
||||||
let col4 = [
|
let col4 = [
|
||||||
self.rows.gpio2.is_high(),
|
self.0 .12.is_low(),
|
||||||
self.rows.gpio3.is_high(),
|
self.0 .13.is_low(),
|
||||||
self.rows.gpio4.is_high(),
|
self.0 .14.is_low(),
|
||||||
self.rows.gpio5.is_high(),
|
self.0 .15.is_low(),
|
||||||
];
|
];
|
||||||
self.cols.gpio10.set_low();
|
|
||||||
|
if col1.iter().any(|b| !b)
|
||||||
|
|| col2.iter().any(|b| !b)
|
||||||
|
|| col3.iter().any(|b| !b)
|
||||||
|
|| col4.iter().any(|b| !b)
|
||||||
|
{
|
||||||
println!("***************************************");
|
println!("***************************************");
|
||||||
println!("col1 {col1:?}");
|
println!("col1 {col1:?}");
|
||||||
println!("col2 {col2:?}");
|
println!("col2 {col2:?}");
|
||||||
println!("col3 {col3:?}");
|
println!("col3 {col3:?}");
|
||||||
println!("col4 {col4:?}");
|
println!("col4 {col4:?}");
|
||||||
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
struct Keyboard<'d>(
|
|
||||||
[(
|
|
||||||
core::cell::RefCell<dyn InputPin + 'd>,
|
|
||||||
core::cell::RefCell<dyn OutputPin + 'd>,
|
|
||||||
); 16],
|
|
||||||
);
|
|
||||||
|
|
||||||
impl<'d> Keyboard<'d> {
|
|
||||||
pub fn new(cols: [impl InputPin; 4], rows: [impl OutputPin; 4]) {
|
|
||||||
core::array::from_fn(|x| )
|
|
||||||
for (x, c) in cols.into_iter().enumerate() {
|
|
||||||
for (y, r) in rows.into_iter().enumerate() {
|
|
||||||
;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
trait KeyboardInput<'d> {
|
trait KeyboardInput<'d> {
|
||||||
fn is_low(&mut self) -> bool;
|
fn is_low(&mut self) -> bool;
|
||||||
@ -299,11 +315,13 @@ trait KeyboardInput<'d> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, C: InputPin, R: OutputPin> KeyboardInput<'d> for (Input<'d, C>, Output<'d, R>) {
|
impl<'d, C: InputPin, R: OutputPin + InputPin> KeyboardInput<'d>
|
||||||
|
for (&'d mut Input<'d, C>, &'d mut OutputOpenDrain<'d, R>)
|
||||||
|
{
|
||||||
fn is_low(&mut self) -> bool {
|
fn is_low(&mut self) -> bool {
|
||||||
self.1.set_low();
|
self.1.set_low();
|
||||||
let s = self.0.is_low();
|
let s = self.0.is_low();
|
||||||
self.1.set_high();
|
self.1.set_high();
|
||||||
s
|
s
|
||||||
}
|
}
|
||||||
}*/
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user