embedded_hal_bus/spi/rc.rs
1extern crate alloc;
2use alloc::rc::Rc;
3
4use core::cell::RefCell;
5use embedded_hal::delay::DelayNs;
6use embedded_hal::digital::OutputPin;
7use embedded_hal::spi::{ErrorType, Operation, SpiBus, SpiDevice};
8
9use super::DeviceError;
10use crate::spi::shared::transaction;
11
12/// Implementation of [`SpiDevice`] around a bus shared with `Rc<RefCell<T>>`.
13/// This is the reference-counting equivalent of [`RefCellDevice`](super::RefCellDevice), requiring allocation.
14///
15/// A single [`SpiBus`] is shared via [`RefCell`], and its ownership is handled by [`Rc`].
16/// Both of these mechanisms only allow sharing within a single thread (or interrupt priority level).
17/// For this reason, this does not implement [`Send`].
18///
19/// When this structure is dropped, the reference count of the `Bus` instance will be decremented,
20/// and it will be cleaned up once the reference count reaches zero.
21#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
22pub struct RcDevice<Bus, Cs, Delay> {
23 bus: Rc<RefCell<Bus>>,
24 cs: Cs,
25 delay: Delay,
26}
27
28impl<Bus, Cs, Delay> RcDevice<Bus, Cs, Delay> {
29 /// Creates a new [`RcDevice`].
30 ///
31 /// This sets the `cs` pin high, and returns an error if that fails.
32 /// It is recommended to have already set that pin high the moment it has been configured as an output, to avoid glitches.
33 ///
34 /// This function does not increment the reference count:
35 /// you will need to call `Rc::clone(&bus)` if you only have a `&Rc<RefCell<Bus>>`.
36 #[inline]
37 pub fn new(bus: Rc<RefCell<Bus>>, mut cs: Cs, delay: Delay) -> Result<Self, Cs::Error>
38 where
39 Cs: OutputPin,
40 {
41 cs.set_high()?;
42
43 Ok(Self { bus, cs, delay })
44 }
45}
46
47impl<Bus, Cs> RcDevice<Bus, Cs, super::NoDelay> {
48 /// Creates a new [`RcDevice`] without support for in-transaction delays.
49 ///
50 /// **Warning**: It's advised to prefer [`RcDevice::new`],
51 /// as the contract of [`SpiDevice`] requests support for in-transaction delays.
52 ///
53 /// Refer to [`RefCellDevice::new_no_delay`](super::RefCellDevice::new_no_delay) for more information.
54 #[inline]
55 pub fn new_no_delay(bus: Rc<RefCell<Bus>>, mut cs: Cs) -> Result<Self, Cs::Error>
56 where
57 Cs: OutputPin,
58 {
59 cs.set_high()?;
60
61 Ok(Self {
62 bus,
63 cs,
64 delay: super::NoDelay,
65 })
66 }
67}
68
69impl<Bus, Cs, Delay> ErrorType for RcDevice<Bus, Cs, Delay>
70where
71 Bus: ErrorType,
72 Cs: OutputPin,
73{
74 type Error = DeviceError<Bus::Error, Cs::Error>;
75}
76
77impl<Word, Bus, Cs, Delay> SpiDevice<Word> for RcDevice<Bus, Cs, Delay>
78where
79 Word: Copy + 'static,
80 Bus: SpiBus<Word>,
81 Cs: OutputPin,
82 Delay: DelayNs,
83{
84 #[inline]
85 fn transaction(&mut self, operations: &mut [Operation<'_, Word>]) -> Result<(), Self::Error> {
86 let bus = &mut *self.bus.borrow_mut();
87
88 transaction(operations, bus, &mut self.delay, &mut self.cs)
89 }
90}