use embedded_hal::digital::OutputPin;
use super::{Interface, InterfaceKind};
pub trait OutputBus {
type Word: Copy;
const KIND: InterfaceKind;
type Error: core::fmt::Debug;
fn set_value(&mut self, value: Self::Word) -> Result<(), Self::Error>;
}
macro_rules! generic_bus {
($GenericxBitBus:ident { type Word = $Word:ident; const KIND: InterfaceKind = $InterfaceKind:expr; Pins {$($PX:ident => $x:tt,)*}}) => {
pub struct $GenericxBitBus<$($PX, )*> {
pins: ($($PX, )*),
last: Option<$Word>,
}
impl<$($PX, )*> $GenericxBitBus<$($PX, )*>
where
$($PX: OutputPin, )*
{
pub fn new(pins: ($($PX, )*)) -> Self {
Self { pins, last: None }
}
pub fn release(self) -> ($($PX, )*) {
self.pins
}
}
impl<$($PX, )* E> OutputBus
for $GenericxBitBus<$($PX, )*>
where
$($PX: OutputPin<Error = E>, )*
E: core::fmt::Debug,
{
type Word = $Word;
type Error = E;
const KIND: InterfaceKind = $InterfaceKind;
fn set_value(&mut self, value: Self::Word) -> Result<(), Self::Error> {
if self.last == Some(value) {
return Ok(())
}
let last = self.last.take();
let changed = match last {
Some(old_value) => value ^ old_value,
None => !0, };
$(
let mask = 1 << $x;
if changed & mask != 0 {
if value & mask != 0 {
self.pins.$x.set_high()
} else {
self.pins.$x.set_low()
}
?;
}
)*
self.last = Some(value);
Ok(())
}
}
impl<$($PX, )*> From<($($PX, )*)>
for $GenericxBitBus<$($PX, )*>
where
$($PX: OutputPin, )*
{
fn from(pins: ($($PX, )*)) -> Self {
Self::new(pins)
}
}
};
}
generic_bus! {
Generic8BitBus {
type Word = u8;
const KIND: InterfaceKind = InterfaceKind::Parallel8Bit;
Pins {
P0 => 0,
P1 => 1,
P2 => 2,
P3 => 3,
P4 => 4,
P5 => 5,
P6 => 6,
P7 => 7,
}
}
}
generic_bus! {
Generic16BitBus {
type Word = u16;
const KIND: InterfaceKind = InterfaceKind::Parallel16Bit;
Pins {
P0 => 0,
P1 => 1,
P2 => 2,
P3 => 3,
P4 => 4,
P5 => 5,
P6 => 6,
P7 => 7,
P8 => 8,
P9 => 9,
P10 => 10,
P11 => 11,
P12 => 12,
P13 => 13,
P14 => 14,
P15 => 15,
}
}
}
#[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum ParallelError<BUS, DC, WR> {
Bus(BUS),
Dc(DC),
Wr(WR),
}
pub struct ParallelInterface<BUS, DC, WR> {
bus: BUS,
dc: DC,
wr: WR,
}
impl<BUS, DC, WR> ParallelInterface<BUS, DC, WR>
where
BUS: OutputBus,
BUS::Word: From<u8> + Eq + core::ops::BitXor<Output = BUS::Word>,
DC: OutputPin,
WR: OutputPin,
{
pub fn new(bus: BUS, dc: DC, wr: WR) -> Self {
Self { bus, dc, wr }
}
pub fn release(self) -> (BUS, DC, WR) {
(self.bus, self.dc, self.wr)
}
fn send_word(
&mut self,
word: BUS::Word,
) -> Result<(), ParallelError<BUS::Error, DC::Error, WR::Error>> {
self.wr.set_low().map_err(ParallelError::Wr)?;
self.bus.set_value(word).map_err(ParallelError::Bus)?;
self.wr.set_high().map_err(ParallelError::Wr)
}
}
impl<BUS, DC, WR> Interface for ParallelInterface<BUS, DC, WR>
where
BUS: OutputBus,
BUS::Word: From<u8> + Eq + core::ops::BitXor<Output = BUS::Word>,
DC: OutputPin,
WR: OutputPin,
{
type Word = BUS::Word;
type Error = ParallelError<BUS::Error, DC::Error, WR::Error>;
const KIND: InterfaceKind = BUS::KIND;
async fn send_command(&mut self, command: u8, args: &[u8]) -> Result<(), Self::Error> {
self.dc.set_low().map_err(ParallelError::Dc)?;
self.send_word(BUS::Word::from(command))?;
self.dc.set_high().map_err(ParallelError::Dc)?;
for &arg in args {
self.send_word(BUS::Word::from(arg))?;
}
Ok(())
}
async fn send_data_slice(&mut self, data: &[Self::Word]) -> Result<(), Self::Error> {
for &word in data {
self.send_word(word)?;
}
Ok(())
}
}