Skip to content

Commit

Permalink
Merge #191
Browse files Browse the repository at this point in the history
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]>
  • Loading branch information
3 people authored Oct 28, 2020
2 parents 646bfea + c66420b commit 7884660
Showing 1 changed file with 49 additions and 0 deletions.
49 changes: 49 additions & 0 deletions src/blocking/spi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,52 @@ pub mod write_iter {
}
}
}

/// Operation for transactional SPI trait
///
/// This allows composition of SPI operations into a single bus transaction
#[derive(Debug, PartialEq)]
pub enum Operation<'a, W: 'static> {
/// Write data from the provided buffer, discarding read data
Write(&'a [W]),
/// Write data out while reading data into the provided buffer
Transfer(&'a mut [W]),
}

/// Transactional trait allows multiple actions to be executed
/// as part of a single SPI transaction
pub trait Transactional<W: 'static> {
/// Associated error type
type Error;

/// Execute the provided transactions
fn try_exec<'a>(&mut self, operations: &mut [Operation<'a, W>]) -> Result<(), Self::Error>;
}

/// Blocking transactional impl over spi::Write and spi::Transfer
pub mod transactional {
use super::{Operation, Transfer, Write};

/// Default implementation of `blocking::spi::Transactional<W>` for implementers of
/// `spi::Write<W>` and `spi::Transfer<W>`
pub trait Default<W>: Write<W> + Transfer<W> {}

impl<W: 'static, E, S> super::Transactional<W> for S
where
S: self::Default<W> + Write<W, Error = E> + Transfer<W, Error = E>,
W: Copy + Clone,
{
type Error = E;

fn try_exec<'a>(&mut self, operations: &mut [super::Operation<'a, W>]) -> Result<(), E> {
for op in operations {
match op {
Operation::Write(w) => self.try_write(w)?,
Operation::Transfer(t) => self.try_transfer(t).map(|_| ())?,
}
}

Ok(())
}
}
}

0 comments on commit 7884660

Please sign in to comment.