Skip to content

Commit 93eb20f

Browse files
committed
async/spi: Add a transaction helper macro
1 parent 597493d commit 93eb20f

File tree

2 files changed

+54
-20
lines changed

2 files changed

+54
-20
lines changed

embedded-hal-async/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
99

1010
## [v0.1.0-alpha.1] - 2022-05-24
1111

12+
### Added
13+
14+
- spi: added a transaction helper macro as a workaround for the raw pointer workaround.
15+
1216
### Changed
1317

1418
- spi: device helper methods (`read`, `write`, `transfer`...) are now default methods in `SpiDevice` instead of an `SpiDeviceExt` extension trait.

embedded-hal-async/src/spi.rs

Lines changed: 50 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,46 @@ where
3535
Word: Copy + 'static,
3636
= impl Future<Output = Result<(), T::Error>>;
3737

38+
#[macro_export]
39+
/// This macro is a workaround for the workaround in [`SpiDevice::transaction`]
40+
///
41+
/// # Examples
42+
///
43+
/// ```
44+
/// use embedded_hal_async::spi::{transaction_helper, SpiBus, SpiBusRead, SpiBusWrite, SpiDevice};
45+
///
46+
/// pub async fn transaction_example<SPI>(mut device: SPI) -> Result<u32, SPI::Error>
47+
/// where
48+
/// SPI: SpiDevice,
49+
/// SPI::Bus: SpiBus,
50+
/// {
51+
/// transaction_helper!(&mut device, move |bus| async move {
52+
/// // Unlike `SpiDevice::transaction`, we don't need to
53+
/// // manually dereference a pointer in order to use the bus.
54+
/// bus.write(&[42]).await?;
55+
/// let mut data = [0; 4];
56+
/// bus.read(&mut data).await?;
57+
/// Ok(u32::from_be_bytes(data))
58+
/// })
59+
/// .await
60+
/// }
61+
/// ```
62+
macro_rules! spi_transaction_helper {
63+
($device:expr, move |$bus:ident| async move $closure_body:expr) => {
64+
$crate::spi::SpiDevice::transaction($device, move |$bus| async move {
65+
// Safety: Implementers of the `SpiDevice` trait guarantee that the pointer is
66+
// valid and dereferencable for the entire duration of the closure.
67+
let $bus = unsafe { &mut *$bus };
68+
let result = $closure_body;
69+
::core::mem::drop($bus); // Ensure that the bus reference was not moved out of the closure
70+
result
71+
})
72+
};
73+
}
74+
75+
#[doc(inline)]
76+
pub use spi_transaction_helper as transaction_helper;
77+
3878
/// SPI device trait
3979
///
4080
/// `SpiDevice` represents ownership over a single SPI device on a (possibly shared) bus, selected
@@ -95,11 +135,7 @@ pub unsafe trait SpiDevice: ErrorType {
95135
Self::Bus: SpiBusRead<Word>,
96136
Word: Copy + 'static,
97137
{
98-
self.transaction(move |bus| async move {
99-
// safety: `bus` is a valid pointer we're allowed to use for the duration of the closure.
100-
let bus = unsafe { &mut *bus };
101-
bus.read(buf).await
102-
})
138+
transaction_helper!(self, move |bus| async move { bus.read(buf).await })
103139
}
104140

105141
/// Do a write within a transaction.
@@ -112,11 +148,7 @@ pub unsafe trait SpiDevice: ErrorType {
112148
Self::Bus: SpiBusWrite<Word>,
113149
Word: Copy + 'static,
114150
{
115-
self.transaction(move |bus| async move {
116-
// safety: `bus` is a valid pointer we're allowed to use for the duration of the closure.
117-
let bus = unsafe { &mut *bus };
118-
bus.write(buf).await
119-
})
151+
transaction_helper!(self, move |bus| async move { bus.write(buf).await })
120152
}
121153

122154
/// Do a transfer within a transaction.
@@ -133,11 +165,10 @@ pub unsafe trait SpiDevice: ErrorType {
133165
Self::Bus: SpiBus<Word>,
134166
Word: Copy + 'static,
135167
{
136-
self.transaction(move |bus| async move {
137-
// safety: `bus` is a valid pointer we're allowed to use for the duration of the closure.
138-
let bus = unsafe { &mut *bus };
139-
bus.transfer(read, write).await
140-
})
168+
transaction_helper!(
169+
self,
170+
move |bus| async move { bus.transfer(read, write).await }
171+
)
141172
}
142173

143174
/// Do an in-place transfer within a transaction.
@@ -153,11 +184,10 @@ pub unsafe trait SpiDevice: ErrorType {
153184
Self::Bus: SpiBus<Word>,
154185
Word: Copy + 'static,
155186
{
156-
self.transaction(move |bus| async move {
157-
// safety: `bus` is a valid pointer we're allowed to use for the duration of the closure.
158-
let bus = unsafe { &mut *bus };
159-
bus.transfer_in_place(buf).await
160-
})
187+
transaction_helper!(
188+
self,
189+
move |bus| async move { bus.transfer_in_place(buf).await }
190+
)
161191
}
162192
}
163193

0 commit comments

Comments
 (0)