use embedded_hal::delay::DelayNs;
use embedded_hal::digital::OutputPin;
use embedded_hal::spi::{Error, ErrorKind, ErrorType, Operation, SpiBus, SpiDevice};
use super::DeviceError;
use crate::spi::shared::transaction;
use crate::util::AtomicCell;
pub struct AtomicDevice<'a, BUS, CS, D> {
bus: &'a AtomicCell<BUS>,
cs: CS,
delay: D,
}
#[derive(Debug, Copy, Clone)]
pub enum AtomicError<T: Error> {
Busy,
Other(T),
}
impl<'a, BUS, CS, D> AtomicDevice<'a, BUS, CS, D> {
#[inline]
pub fn new(bus: &'a AtomicCell<BUS>, mut cs: CS, delay: D) -> Result<Self, CS::Error>
where
CS: OutputPin,
{
cs.set_high()?;
Ok(Self { bus, cs, delay })
}
}
impl<'a, BUS, CS> AtomicDevice<'a, BUS, CS, super::NoDelay>
where
BUS: ErrorType,
CS: OutputPin,
{
#[inline]
pub fn new_no_delay(bus: &'a AtomicCell<BUS>, mut cs: CS) -> Result<Self, CS::Error>
where
CS: OutputPin,
{
cs.set_high()?;
Ok(Self {
bus,
cs,
delay: super::NoDelay,
})
}
}
impl<T: Error> Error for AtomicError<T> {
fn kind(&self) -> ErrorKind {
match self {
AtomicError::Other(e) => e.kind(),
_ => ErrorKind::Other,
}
}
}
impl<BUS, CS, D> ErrorType for AtomicDevice<'_, BUS, CS, D>
where
BUS: ErrorType,
CS: OutputPin,
{
type Error = AtomicError<DeviceError<BUS::Error, CS::Error>>;
}
impl<Word: Copy + 'static, BUS, CS, D> SpiDevice<Word> for AtomicDevice<'_, BUS, CS, D>
where
BUS: SpiBus<Word>,
CS: OutputPin,
D: DelayNs,
{
#[inline]
fn transaction(&mut self, operations: &mut [Operation<'_, Word>]) -> Result<(), Self::Error> {
self.bus
.busy
.compare_exchange(
false,
true,
core::sync::atomic::Ordering::SeqCst,
core::sync::atomic::Ordering::SeqCst,
)
.map_err(|_| AtomicError::Busy)?;
let bus = unsafe { &mut *self.bus.bus.get() };
let result = transaction(operations, bus, &mut self.delay, &mut self.cs);
self.bus
.busy
.store(false, core::sync::atomic::Ordering::SeqCst);
result.map_err(AtomicError::Other)
}
}