use embedded_hal::digital::v2::{
InputPin,
OutputPin,
};
pub trait Pull {
const NPULL: usize;
fn pull(&mut self, x: usize);
fn release(&mut self, x: usize);
}
impl<'a, P> Pull for &'a mut P
where
P: Pull,
{
const NPULL: usize = P::NPULL;
fn pull(&mut self, x: usize) {
<P as Pull>::pull(self, x)
}
fn release(&mut self, x: usize) {
<P as Pull>::release(self, x)
}
}
pub trait Read {
const NREAD: usize;
fn read(&self, y: usize) -> bool;
}
impl<'a, R> Read for &'a mut R
where
R: Read,
{
const NREAD: usize = R::NREAD;
fn read(&self, y: usize) -> bool {
<R as Read>::read(self, y)
}
}
impl<'a, R> Read for &'a R
where
R: Read,
{
const NREAD: usize = R::NREAD;
fn read(&self, y: usize) -> bool {
<R as Read>::read(self, y)
}
}
pub trait Scan: Pull + Read {}
impl<M> Scan for M where M: Pull + Read {}
pub struct Matrix<P, R> {
pub pull: P,
pub read: R,
}
impl<P, R> Read for Matrix<P, R>
where
R: Read,
{
const NREAD: usize = R::NREAD;
#[inline]
fn read(&self, y: usize) -> bool {
self.read.read(y)
}
}
impl<P, R> Pull for Matrix<P, R>
where
P: Pull,
{
const NPULL: usize = P::NPULL;
#[inline]
fn pull(&mut self, x: usize) {
self.pull.pull(x)
}
#[inline]
fn release(&mut self, x: usize) {
self.pull.release(x)
}
}
macro_rules! replace_expr {
($_t:tt $sub:expr) => {
$sub
};
}
macro_rules! count_tts {
($($tts:tt)*) => {0usize $(+ replace_expr!($tts 1usize))*};
}
macro_rules! impl_scan {
(@impl $($pos:tt: $slot:ident),*) => {
impl<$($slot : OutputPin),*> Pull for ($($slot),*)
{
const NPULL: usize = count_tts!($($slot)*);
#[inline]
fn pull(&mut self, x: usize) {
match x {
$(
$pos => if self.$pos.set_low().is_err() {
panic!(concat!("error setting ", $pos, " low"));
},
)*
_ => unreachable!(),
}
}
#[inline]
fn release(&mut self, x: usize) {
match x {
$(
$pos => if self.$pos.set_high().is_err() {
panic!(concat!("error setting ", $pos, " high"));
},
)*
_ => unreachable!(),
}
}
}
impl<$($slot : InputPin),*> Read for ($($slot),*)
{
const NREAD: usize = count_tts!($($slot)*);
#[inline]
fn read(&self, y: usize) -> bool {
match y {
$(
$pos => self.$pos.is_low().unwrap_or(false),
)*
_ => unreachable!(),
}
}
}
};
(@rec ($($cur_pos:tt: $cur_slot:ident),*) $next_pos:tt: $next_slot:ident , $($pos:tt: $slot:ident),*) => {
impl_scan!(@impl $($cur_pos: $cur_slot,)* $next_pos: $next_slot);
impl_scan!(@rec ($($cur_pos: $cur_slot,)* $next_pos: $next_slot) $($pos: $slot),*);
};
(@rec ($($cur_pos:tt: $cur_slot:ident),*) $next_pos:tt: $next_slot:ident) => {};
($zero:tt: $first:ident, $($pos:tt: $slot:ident),* $(,)*) => {
impl_scan!(@rec ($zero: $first) $($pos: $slot),*);
}
}
#[cfg(not(feature = "exhaustive"))]
impl_scan!(
0: A,
1: B,
2: C,
3: D,
4: E,
5: F,
6: G,
7: H,
8: I,
9: J,
10: K,
11: L,
12: M,
13: N,
14: O,
);
#[cfg(feature = "exhaustive")]
impl_scan!(
0: A,
1: B,
2: C,
3: D,
4: E,
5: F,
6: G,
7: H,
8: I,
9: J,
10: K,
11: L,
12: M,
13: N,
14: O,
15: P,
16: Q,
17: R,
18: S,
19: T,
20: U,
21: V,
22: W,
23: X,
24: Y,
25: Z,
);