Skip to content

Commit 7884660

Browse files
bors[bot]ryankurte
andauthored
Merge #191
191: Added transactional SPI interface r=therealprof a=ryankurte This PR adds a transactional interface for SPI devices (#94), compatible with linux spidev. Split from #178 as I believe this is complete and useful, but that there is more experimentation required before (if?) the I2C component is landed, check there for previous reviews / discussion. **Demonstrated in:** - Linux embedded hal: rust-embedded/linux-embedded-hal#35 - STM32F4xx-hal: stm32-rs/stm32f4xx-hal#167 - embedded-spi driver abstraction (previously provided a polyfill for equivalent transactional functionality) https://github.com/ryankurte/rust-embedded-spi/pull/4/files#diff-74eea42f4e5e15399ac9184c8f2727a9R344 - sx128x radio driver: rust-iot/rust-radio-sx128x#5 **Notes:** - `Operation::Transfer` uses one buffer to allow polyfill using the existing `Transfer` trait (with the convenient side effect of reducing memory requirements) - `W` has a static bound as it _should_ only ever be a type with static lifetime (u8, u16 etc., not a reference), and to differentiate this from `'a` which is the lifetime of the data in the object and only bound to the function - `exec(.., &mut [Operation])` is chosen over `exec<O: AsMut<[Operation]>(..)` as the latter imposes limits on generic types using this trait (which i ran into, see [E0038](https://doc.rust-lang.org/error-index.html#E0038)) cc. @rust-embedded/hal folks, @eldruin, @RandomInsano, @Rahix, @austinglaser for opinions / review Co-authored-by: Ryan Kurte <[email protected]> Co-authored-by: ryan <[email protected]>
2 parents 646bfea + c66420b commit 7884660

File tree

1 file changed

+49
-0
lines changed

1 file changed

+49
-0
lines changed

src/blocking/spi.rs

+49
Original file line numberDiff line numberDiff line change
@@ -102,3 +102,52 @@ pub mod write_iter {
102102
}
103103
}
104104
}
105+
106+
/// Operation for transactional SPI trait
107+
///
108+
/// This allows composition of SPI operations into a single bus transaction
109+
#[derive(Debug, PartialEq)]
110+
pub enum Operation<'a, W: 'static> {
111+
/// Write data from the provided buffer, discarding read data
112+
Write(&'a [W]),
113+
/// Write data out while reading data into the provided buffer
114+
Transfer(&'a mut [W]),
115+
}
116+
117+
/// Transactional trait allows multiple actions to be executed
118+
/// as part of a single SPI transaction
119+
pub trait Transactional<W: 'static> {
120+
/// Associated error type
121+
type Error;
122+
123+
/// Execute the provided transactions
124+
fn try_exec<'a>(&mut self, operations: &mut [Operation<'a, W>]) -> Result<(), Self::Error>;
125+
}
126+
127+
/// Blocking transactional impl over spi::Write and spi::Transfer
128+
pub mod transactional {
129+
use super::{Operation, Transfer, Write};
130+
131+
/// Default implementation of `blocking::spi::Transactional<W>` for implementers of
132+
/// `spi::Write<W>` and `spi::Transfer<W>`
133+
pub trait Default<W>: Write<W> + Transfer<W> {}
134+
135+
impl<W: 'static, E, S> super::Transactional<W> for S
136+
where
137+
S: self::Default<W> + Write<W, Error = E> + Transfer<W, Error = E>,
138+
W: Copy + Clone,
139+
{
140+
type Error = E;
141+
142+
fn try_exec<'a>(&mut self, operations: &mut [super::Operation<'a, W>]) -> Result<(), E> {
143+
for op in operations {
144+
match op {
145+
Operation::Write(w) => self.try_write(w)?,
146+
Operation::Transfer(t) => self.try_transfer(t).map(|_| ())?,
147+
}
148+
}
149+
150+
Ok(())
151+
}
152+
}
153+
}

0 commit comments

Comments
 (0)