Skip to content

Commit be43383

Browse files
adri326Dirbaio
authored andcommitted
Add a Rc<RefCell<Bus>>-based implementation of SpiDevice
1 parent 5055422 commit be43383

File tree

3 files changed

+98
-1
lines changed

3 files changed

+98
-1
lines changed

embedded-hal-bus/Cargo.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,11 @@ repository = "https://github.com/rust-embedded/embedded-hal"
1515
version = "0.2.0"
1616

1717
[features]
18-
std = []
18+
std = ["alloc"]
1919
async = ["dep:embedded-hal-async"]
2020
defmt-03 = ["dep:defmt-03", "embedded-hal/defmt-03", "embedded-hal-async?/defmt-03"]
21+
# Enables additional utilities requiring a global allocator.
22+
alloc = []
2123

2224
[dependencies]
2325
embedded-hal = { version = "1.0.0", path = "../embedded-hal" }

embedded-hal-bus/src/spi/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ mod critical_section;
1616
mod shared;
1717
pub use atomic::*;
1818

19+
#[cfg(feature = "alloc")]
20+
mod rc;
21+
#[cfg(feature = "alloc")]
22+
pub use rc::*;
23+
1924
pub use self::critical_section::*;
2025

2126
#[cfg(feature = "defmt-03")]

embedded-hal-bus/src/spi/rc.rs

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
extern crate alloc;
2+
use alloc::rc::Rc;
3+
4+
use core::cell::RefCell;
5+
use embedded_hal::delay::DelayNs;
6+
use embedded_hal::digital::OutputPin;
7+
use embedded_hal::spi::{ErrorType, Operation, SpiBus, SpiDevice};
8+
9+
use super::DeviceError;
10+
use 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` will be decremented,
20+
/// and the bus driver will be cleaned up when that count reaches zero.
21+
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
22+
pub struct RcDevice<Bus, Cs, Delay> {
23+
bus: Rc<RefCell<Bus>>,
24+
cs: Cs,
25+
delay: Delay,
26+
}
27+
28+
impl<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 `&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+
47+
impl<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+
69+
impl<Bus, Cs, Delay> ErrorType for RcDevice<Bus, Cs, Delay>
70+
where
71+
Bus: ErrorType,
72+
Cs: OutputPin,
73+
{
74+
type Error = DeviceError<Bus::Error, Cs::Error>;
75+
}
76+
77+
impl<Word, Bus, Cs, Delay> SpiDevice<Word> for RcDevice<Bus, Cs, Delay>
78+
where
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+
}

0 commit comments

Comments
 (0)