use embedded_hal::delay::DelayNs;
use embedded_hal::digital::{InputPin, OutputPin};
pub trait DynamicPin {
type Error: core::fmt::Debug;
fn set_as_output(&mut self) -> Result<(), Self::Error>;
fn set_as_input(&mut self) -> Result<(), Self::Error>;
fn set_high(&mut self) -> Result<(), Self::Error>;
fn set_low(&mut self) -> Result<(), Self::Error>;
fn is_high(&mut self) -> Result<bool, Self::Error>;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Spi3BusError<CSE, SCKE, DATAE, DCE, RSTE, BUSYE> {
Cs(CSE),
Sck(SCKE),
Data(DATAE),
Dc(DCE),
Reset(RSTE),
Busy(BUSYE),
}
pub type Spi3BusResult<CSE, SCKE, DATAE, DCE, RSTE, BUSYE, T = ()> =
Result<T, Spi3BusError<CSE, SCKE, DATAE, DCE, RSTE, BUSYE>>;
pub struct Spi3Bus<CS, SCK, DATA, DC, RST, BUSY> {
cs: CS,
sck: SCK,
data: DATA,
dc: DC,
rst: RST,
busy: BUSY,
}
#[allow(clippy::type_complexity)]
impl<CS, SCK, DATA, DC, RST, BUSY> Spi3Bus<CS, SCK, DATA, DC, RST, BUSY>
where
CS: OutputPin,
SCK: OutputPin,
DATA: DynamicPin,
DC: OutputPin,
RST: OutputPin,
BUSY: InputPin,
{
pub fn new(cs: CS, sck: SCK, data: DATA, dc: DC, rst: RST, busy: BUSY) -> Self {
Self {
cs,
sck,
data,
dc,
rst,
busy,
}
}
pub fn release(self) -> (CS, SCK, DATA, DC, RST, BUSY) {
(self.cs, self.sck, self.data, self.dc, self.rst, self.busy)
}
pub fn reset<DELAY: DelayNs>(
&mut self,
delay: &mut DELAY,
) -> Spi3BusResult<CS::Error, SCK::Error, DATA::Error, DC::Error, RST::Error, BUSY::Error> {
delay.delay_ms(20);
self.rst.set_high().map_err(Spi3BusError::Reset)?;
delay.delay_ms(10);
self.rst.set_low().map_err(Spi3BusError::Reset)?;
delay.delay_ms(20);
self.rst.set_high().map_err(Spi3BusError::Reset)?;
delay.delay_ms(10);
self.cs.set_high().map_err(Spi3BusError::Cs)?;
delay.delay_ms(10);
self.wait_busy(delay)
}
pub fn wait_busy<DELAY: DelayNs>(
&mut self,
delay: &mut DELAY,
) -> Spi3BusResult<CS::Error, SCK::Error, DATA::Error, DC::Error, RST::Error, BUSY::Error> {
let mut retries = 0u32;
loop {
let is_busy = !self.busy.is_high().map_err(Spi3BusError::Busy)?;
if is_busy {
delay.delay_ms(1);
retries += 1;
if retries > 1_500 {
break;
}
} else {
break;
}
}
Ok(())
}
fn write_byte<DELAY: DelayNs>(
&mut self,
delay: &mut DELAY,
value: u8,
) -> Spi3BusResult<CS::Error, SCK::Error, DATA::Error, DC::Error, RST::Error, BUSY::Error> {
self.data.set_as_output().map_err(Spi3BusError::Data)?;
for i in 0..8 {
if value & (1 << (7 - i)) != 0 {
self.data.set_high().map_err(Spi3BusError::Data)?;
} else {
self.data.set_low().map_err(Spi3BusError::Data)?;
}
delay.delay_us(1);
self.sck.set_high().map_err(Spi3BusError::Sck)?;
delay.delay_us(1);
self.sck.set_low().map_err(Spi3BusError::Sck)?;
delay.delay_us(1);
}
Ok(())
}
fn read_byte<DELAY: DelayNs>(
&mut self,
delay: &mut DELAY,
) -> Spi3BusResult<CS::Error, SCK::Error, DATA::Error, DC::Error, RST::Error, BUSY::Error, u8>
{
self.data.set_as_input().map_err(Spi3BusError::Data)?;
let mut value = 0u8;
for i in 0..8 {
self.sck.set_high().map_err(Spi3BusError::Sck)?;
delay.delay_us(1);
if self.data.is_high().map_err(Spi3BusError::Data)? {
value |= 1 << (7 - i);
}
self.sck.set_low().map_err(Spi3BusError::Sck)?;
delay.delay_us(1);
}
Ok(value)
}
pub fn write_cmd<DELAY: DelayNs>(
&mut self,
delay: &mut DELAY,
byte: u8,
) -> Spi3BusResult<CS::Error, SCK::Error, DATA::Error, DC::Error, RST::Error, BUSY::Error> {
self.dc.set_low().map_err(Spi3BusError::Dc)?;
self.cs.set_low().map_err(Spi3BusError::Cs)?;
self.write_byte(delay, byte)?;
self.cs.set_high().map_err(Spi3BusError::Cs)
}
pub fn write_data<DELAY: DelayNs>(
&mut self,
delay: &mut DELAY,
byte: u8,
) -> Spi3BusResult<CS::Error, SCK::Error, DATA::Error, DC::Error, RST::Error, BUSY::Error> {
self.dc.set_high().map_err(Spi3BusError::Dc)?;
self.cs.set_low().map_err(Spi3BusError::Cs)?;
self.write_byte(delay, byte)?;
self.cs.set_high().map_err(Spi3BusError::Cs)
}
pub fn read_data_byte<DELAY: DelayNs>(
&mut self,
delay: &mut DELAY,
) -> Spi3BusResult<CS::Error, SCK::Error, DATA::Error, DC::Error, RST::Error, BUSY::Error, u8>
{
self.dc.set_high().map_err(Spi3BusError::Dc)?;
self.cs.set_low().map_err(Spi3BusError::Cs)?;
let value = self.read_byte(delay)?;
self.cs.set_high().map_err(Spi3BusError::Cs)?;
Ok(value)
}
pub fn read_byte_no_dc<DELAY: DelayNs>(
&mut self,
delay: &mut DELAY,
) -> Spi3BusResult<CS::Error, SCK::Error, DATA::Error, DC::Error, RST::Error, BUSY::Error, u8>
{
self.cs.set_low().map_err(Spi3BusError::Cs)?;
let value = self.read_byte(delay)?;
self.cs.set_high().map_err(Spi3BusError::Cs)?;
Ok(value)
}
}