driver_pal/
wrapper.rs

1//! Transactional SPI wrapper implementation
2//! This provides a `Wrapper` type that is generic over an `embedded_hal::spi`
3//! and `embedded_hal::digital::v2::OutputPin` to provide a transactional API for SPI transactions.
4
5use embedded_hal::delay::DelayNs;
6use embedded_hal::digital::{InputPin, OutputPin};
7use embedded_hal::spi::{Operation, SpiDevice};
8
9use crate::{Busy, Error, ManagedChipSelect, PinState, Ready, Reset};
10
11/// Wrapper provides a wrapper around an SPI object with Chip Select management
12pub struct Wrapper<Spi, CsPin, BusyPin, ReadyPin, ResetPin, Delay> {
13    spi: Spi,
14
15    cs: CsPin,
16    reset: ResetPin,
17
18    busy: BusyPin,
19    ready: ReadyPin,
20
21    delay: Delay,
22}
23
24/// ManagedChipSelect indicates wrapper controls CS line
25impl<Spi, CsPin, BusyPin, ReadyPin, ResetPin, Delay> ManagedChipSelect
26    for Wrapper<Spi, CsPin, BusyPin, ReadyPin, ResetPin, Delay>
27{
28}
29
30impl<Spi, CsPin, BusyPin, ReadyPin, ResetPin, Delay>
31    Wrapper<Spi, CsPin, BusyPin, ReadyPin, ResetPin, Delay>
32where
33    Spi: SpiDevice<u8>,
34    CsPin: OutputPin,
35{
36    /// Create a new wrapper with the provided chip select pin
37    pub fn new(
38        spi: Spi,
39        cs: CsPin,
40        reset: ResetPin,
41        busy: BusyPin,
42        ready: ReadyPin,
43        delay: Delay,
44    ) -> Self {
45        Self {
46            spi,
47            cs,
48            reset,
49            busy,
50            ready,
51            delay,
52        }
53    }
54
55    /// Explicitly fetch the inner spi (non-CS controlling) object
56    ///
57    /// (note that deref is also implemented for this)
58    pub fn inner_spi(&mut self) -> &mut Spi {
59        &mut self.spi
60    }
61}
62
63impl<Spi, CsPin, BusyPin, ReadyPin, ResetPin, Delay> embedded_hal::spi::ErrorType
64    for Wrapper<Spi, CsPin, BusyPin, ReadyPin, ResetPin, Delay>
65where
66    Spi: embedded_hal::spi::ErrorType,
67    CsPin: embedded_hal::digital::ErrorType,
68    Delay: DelayNs,
69{
70    type Error = Error<
71        <Spi as embedded_hal::spi::ErrorType>::Error,
72        <CsPin as embedded_hal::digital::ErrorType>::Error,
73    >;
74}
75
76impl<Spi, CsPin, BusyPin, ReadyPin, ResetPin, Delay> embedded_hal::digital::ErrorType
77    for Wrapper<Spi, CsPin, BusyPin, ReadyPin, ResetPin, Delay>
78where
79    Spi: embedded_hal::spi::ErrorType,
80    CsPin: embedded_hal::digital::ErrorType,
81    Delay: DelayNs,
82{
83    type Error = Error<
84        <Spi as embedded_hal::spi::ErrorType>::Error,
85        <CsPin as embedded_hal::digital::ErrorType>::Error,
86    >;
87}
88
89impl<Spi, CsPin, BusyPin, ReadyPin, ResetPin, Delay> SpiDevice<u8>
90    for Wrapper<Spi, CsPin, BusyPin, ReadyPin, ResetPin, Delay>
91where
92    Spi: SpiDevice<u8>,
93    CsPin: OutputPin,
94    Delay: DelayNs,
95{
96    fn transaction(&mut self, operations: &mut [Operation<'_, u8>]) -> Result<(), Self::Error> {
97        self.cs.set_low().map_err(Error::Pin)?;
98
99        let r = self.spi.transaction(operations).map_err(Error::Spi);
100
101        self.cs.set_high().map_err(Error::Pin)?;
102
103        r
104    }
105
106    /// spi write implementation managing the CS pin
107    fn write<'w>(&mut self, data: &'w [u8]) -> Result<(), Self::Error> {
108        self.cs.set_low().map_err(Error::Pin)?;
109
110        let r = self.spi.write(data).map_err(Error::Spi);
111
112        self.cs.set_high().map_err(Error::Pin)?;
113
114        r
115    }
116
117    fn transfer_in_place<'w>(&mut self, data: &'w mut [u8]) -> Result<(), Self::Error> {
118        self.cs.set_low().map_err(Error::Pin)?;
119
120        self.spi.transfer_in_place(data).map_err(Error::Spi)?;
121
122        self.cs.set_high().map_err(Error::Pin)?;
123
124        Ok(())
125    }
126}
127
128/// Reset pin implementation for inner objects implementing `Reset`
129impl<Spi, CsPin, BusyPin, ReadyPin, ResetPin, Delay> Reset
130    for Wrapper<Spi, CsPin, BusyPin, ReadyPin, ResetPin, Delay>
131where
132    ResetPin: OutputPin,
133{
134    type Error = <ResetPin as embedded_hal::digital::ErrorType>::Error;
135
136    /// Set the reset pin state
137    fn set_reset(&mut self, state: PinState) -> Result<(), Self::Error> {
138        match state {
139            PinState::High => self.reset.set_high()?,
140            PinState::Low => self.reset.set_low()?,
141        };
142        Ok(())
143    }
144}
145
146/// Busy pin implementation for inner objects implementing `Busy`
147impl<Spi, CsPin, BusyPin, ReadyPin, ResetPin, Delay> Busy
148    for Wrapper<Spi, CsPin, BusyPin, ReadyPin, ResetPin, Delay>
149where
150    BusyPin: InputPin,
151{
152    type Error = <BusyPin as embedded_hal::digital::ErrorType>::Error;
153
154    /// Fetch the busy pin state
155    fn get_busy(&mut self) -> Result<PinState, Self::Error> {
156        match self.busy.is_high()? {
157            true => Ok(PinState::High),
158            false => Ok(PinState::Low),
159        }
160    }
161}
162
163/// Ready pin implementation for inner object implementing `Ready`
164impl<Spi, CsPin, BusyPin, ReadyPin, ResetPin, Delay> Ready
165    for Wrapper<Spi, CsPin, BusyPin, ReadyPin, ResetPin, Delay>
166where
167    ReadyPin: InputPin,
168{
169    type Error = <ReadyPin as embedded_hal::digital::ErrorType>::Error;
170
171    /// Fetch the ready pin state
172    fn get_ready(&mut self) -> Result<PinState, Self::Error> {
173        match self.ready.is_high()? {
174            true => Ok(PinState::High),
175            false => Ok(PinState::Low),
176        }
177    }
178}
179
180impl<Spi, CsPin, BusyPin, ReadyPin, ResetPin, Delay> DelayNs
181    for Wrapper<Spi, CsPin, BusyPin, ReadyPin, ResetPin, Delay>
182where
183    Delay: DelayNs,
184{
185    fn delay_ns(&mut self, ns: u32) {
186        self.delay.delay_ns(ns)
187    }
188}