use embedded_hal::blocking::spi::{Transfer, Write};
use embedded_hal::digital::v2::{OutputPin, InputPin};
use embedded_hal::blocking::delay::DelayMs;
use crate::{Transaction, Transactional, Busy, Ready, Reset, PinState, Error};
#[derive(Debug, Clone, PartialEq)]
pub struct Wrapper<Spi, SpiError, OutputPin, InputPin, PinError, Delay> {
spi: Spi,
cs: OutputPin,
delay: Delay,
busy: Option<InputPin>,
ready: Option<InputPin>,
reset: Option<OutputPin>,
pub(crate) err: Option<Error<SpiError, PinError>>,
}
impl <Spi, SpiError, Output, Input, PinError, Delay> Wrapper<Spi, SpiError, Output, Input, PinError, Delay>
where
Spi: Transfer<u8, Error = SpiError> + Write<u8, Error = SpiError>,
Output: OutputPin<Error = PinError>,
Input: InputPin<Error = PinError>,
Delay: DelayMs<u32>,
{
pub fn new(spi: Spi, cs: Output, delay: Delay) -> Self {
Self{spi, cs, delay, err: None, busy: None, ready: None, reset: None}
}
pub fn with_busy(&mut self, busy: Input) {
self.busy = Some(busy);
}
pub fn with_ready(&mut self, ready: Input) {
self.ready = Some(ready);
}
pub fn with_reset(&mut self, reset: Output) {
self.reset = Some(reset);
}
pub fn pin_write<P>(&mut self, pin: &mut P, value: bool) -> i32
where P: OutputPin<Error = PinError>
{
let r = match value {
true => pin.set_high(),
false => pin.set_low(),
};
match r {
Ok(_) => 0,
Err(e) => {
self.err = Some(Error::Pin(e));
-1
}
}
}
pub fn pin_read<P>(&mut self, pin: &mut P) -> i32
where P: InputPin<Error = PinError>
{
let r = pin.is_high();
match r {
Ok(true) => 1,
Ok(false) => 0,
Err(e) => {
self.err = Some(Error::Pin(e));
-1
}
}
}
pub fn check_error(&mut self) -> Result<(), Error<SpiError, PinError>> {
match self.err.take() {
Some(e) => Err(e),
None => Ok(())
}
}
}
impl <Spi, SpiError, Output, Input, PinError, Delay> Transactional for Wrapper<Spi, SpiError, Output, Input, PinError, Delay>
where
Spi: Transfer<u8, Error = SpiError> + Write<u8, Error = SpiError>,
Output: OutputPin<Error = PinError>,
Input: InputPin<Error = PinError>,
Delay: DelayMs<u32>,
{
type Error = Error<SpiError, PinError>;
fn spi_read<'a>(&mut self, prefix: &[u8], mut data: &'a mut [u8]) -> Result<(), Self::Error> {
self.cs.set_low().map_err(|e| { Error::Pin(e) })?;
let mut res = self.spi.write(&prefix);
if res.is_ok() {
res = self.spi.transfer(&mut data).map(|_r| () );
}
self.cs.set_high().map_err(|e| { Error::Pin(e) })?;
trace!("[spi_read] prefix: {:x?} received: {:x?}", prefix, data);
match res {
Err(e) => Err( Error::Spi(e) ),
Ok(_) => Ok(()),
}
}
fn spi_write(&mut self, prefix: &[u8], data: &[u8]) -> Result<(), Self::Error> {
self.cs.set_low().map_err(|e| { Error::Pin(e) })?;
trace!("[spi_write] prefix: {:x?} writing: {:x?}", prefix, data);
let mut res = self.spi.write(&prefix);
if res.is_ok() {
res = self.spi.write(&data);
}
self.cs.set_high().map_err(|e| { Error::Pin(e) })?;
match res {
Err(e) => Err( Error::Spi(e) ),
Ok(_) => Ok(()),
}
}
fn spi_exec(&mut self, transactions: &mut [Transaction]) -> Result<(), Self::Error> {
let mut res = Ok(());
self.cs.set_low().map_err(|e| { Error::Pin(e) })?;
for i in 0..transactions.len() {
let mut t = &mut transactions[i];
res = match &mut t {
Transaction::Write(d) => self.spi.write(d),
Transaction::Read(d) => self.spi.transfer(d).map(|_r| () ),
}.map_err(|e| Error::Spi(e) );
if res.is_err() {
break;
}
}
self.cs.set_low().map_err(|e| { Error::Pin(e) })?;
res
}
}
impl <Spi, SpiError, Output, Input, PinError, Delay> Busy for Wrapper<Spi, SpiError, Output, Input, PinError, Delay>
where
Spi: Transfer<u8, Error = SpiError> + Write<u8, Error = SpiError>,
Output: OutputPin<Error = PinError>,
Input: InputPin<Error = PinError>,
Delay: DelayMs<u32>,
{
type Error = Error<SpiError, PinError>;
fn get_busy(&mut self) -> Result<PinState, Self::Error> {
match &self.busy {
None => Ok(PinState::Low),
Some(b) => {
let v = b.is_high().map_err(|e| Error::Pin(e) )?;
match v {
true => Ok(PinState::High),
false => Ok(PinState::Low),
}
}
}
}
}
impl <Spi, SpiError, Output, Input, PinError, Delay> Ready for Wrapper<Spi, SpiError, Output, Input, PinError, Delay>
where
Spi: Transfer<u8, Error = SpiError> + Write<u8, Error = SpiError>,
Output: OutputPin<Error = PinError>,
Input: InputPin<Error = PinError>,
Delay: DelayMs<u32>,
{
type Error = Error<SpiError, PinError>;
fn get_ready(&mut self) -> Result<PinState, Self::Error> {
match &self.ready {
None => Ok(PinState::Low),
Some(b) => {
let v = b.is_high().map_err(|e| Error::Pin(e) )?;
match v {
true => Ok(PinState::High),
false => Ok(PinState::Low),
}
}
}
}
}
impl <Spi, SpiError, Output, Input, PinError, Delay> Reset for Wrapper<Spi, SpiError, Output, Input, PinError, Delay>
where
Spi: Transfer<u8, Error = SpiError> + Write<u8, Error = SpiError>,
Output: OutputPin<Error = PinError>,
Input: InputPin<Error = PinError>,
Delay: DelayMs<u32>,
{
type Error = Error<SpiError, PinError>;
fn set_reset(&mut self, state: PinState) -> Result<(), Self::Error> {
if let Some(p) = &mut self.reset {
match state {
PinState::High => p.set_high().map_err(|e| Error::Pin(e) ),
PinState::Low => p.set_low().map_err(|e| Error::Pin(e) ),
}
} else {
Ok(())
}
}
}
impl <Spi, SpiError, Output, Input, PinError, Delay> DelayMs<u32> for Wrapper<Spi, SpiError, Output, Input, PinError, Delay>
where
Spi: Transfer<u8, Error = SpiError> + Write<u8, Error = SpiError>,
Output: OutputPin<Error = PinError>,
Input: InputPin<Error = PinError>,
Delay: DelayMs<u32>,
{
fn delay_ms(&mut self, ms: u32) {
self.delay.delay_ms(ms);
}
}
impl <Spi, SpiError, Output, Input, PinError, Delay> Transfer<u8> for Wrapper<Spi, SpiError, Output, Input, PinError, Delay>
where
Spi: Transfer<u8, Error = SpiError> + Write<u8, Error = SpiError>,
Output: OutputPin<Error = PinError>,
Input: InputPin<Error = PinError>,
Delay: DelayMs<u32>,
{
type Error = SpiError;
fn transfer<'w>(&mut self, data: &'w mut [u8]) -> Result<&'w [u8], Self::Error> {
trace!("[spi::Transfer] writing: {:x?}", &data);
Transfer::transfer(&mut self.spi, data)
.map(|r| {
trace!("[spi::Transfer] read: {:x?}", &r);
r
})
}
}
impl <Spi, SpiError, Output, Input, PinError, Delay> Write<u8> for Wrapper<Spi, SpiError, Output, Input, PinError, Delay>
where
Spi: Transfer<u8, Error = SpiError> + Write<u8, Error = SpiError>,
Output: OutputPin<Error = PinError>,
Input: InputPin<Error = PinError>,
Delay: DelayMs<u32>,
{
type Error = SpiError;
fn write<'w>(&mut self, data: &[u8]) -> Result<(), Self::Error> {
trace!("[spi::Write] writing: {:x?}", &data);
Write::write(&mut self.spi, data)
}
}