diff --git a/src/blocking/spi.rs b/src/blocking/spi.rs index 2d0f732c..cc0a2752 100644 --- a/src/blocking/spi.rs +++ b/src/blocking/spi.rs @@ -1,14 +1,30 @@ //! Blocking SPI API -/// Blocking transfer +/// Blocking transfer with separate buffers pub trait Transfer { /// Error type type Error; + /// Writes and reads simultaneously. `write` is written to the slave on MOSI and + /// words received on MISO are stored in `read`. + /// + /// It is allowed for `read` and `write` to have different lengths, even zero length. + /// The transfer runs for `max(read.len(), write.len())` words. If `read` is shorter, + /// incoming words after `read` has been filled will be discarded. If `write` is shorter, + /// the value of words sent in MOSI after all `write` has been sent is implementation defined, + /// typically `0x00`, `0xFF`, or configurable. + fn transfer(&mut self, read: &mut [W], write: &[W]) -> Result<(), Self::Error>; +} + +/// Blocking transfer with single buffer +pub trait TransferInplace { + /// Error type + type Error; + /// Writes and reads simultaneously. The contents of `words` are /// written to the slave, and the received words are stored into the same /// `words` buffer, overwriting it. - fn transfer(&mut self, words: &mut [W]) -> Result<(), Self::Error>; + fn transfer_inplace(&mut self, words: &mut [W]) -> Result<(), Self::Error>; } /// Blocking write @@ -20,6 +36,16 @@ pub trait Write { fn write(&mut self, words: &[W]) -> Result<(), Self::Error>; } +/// Blocking read +pub trait Read { + /// Error type + type Error; + + /// Reads `words` to the slave. The word value sent on MOSI during + /// reading is implementation defined, typically `0x00`, `0xFF`, or configurable. + fn read(&mut self, words: &mut [W]) -> Result<(), Self::Error>; +} + /// Blocking write (iterator version) pub trait WriteIter { /// Error type @@ -31,20 +57,56 @@ pub trait WriteIter { WI: IntoIterator; } -/// Blocking transfer +/// Blocking transfer with separate buffers pub mod transfer { /// Default implementation of `blocking::spi::Transfer` for implementers of /// `nonblocking::spi::FullDuplex` + /// + /// If `read` is longer than `write`, `W::default()` (which is typically 0) is sent on MOSI + /// to fill the remaining bytes. pub trait Default: crate::nb::spi::FullDuplex {} impl crate::blocking::spi::Transfer for S + where + S: Default, + W: Clone + core::default::Default, + { + type Error = S::Error; + + fn transfer(&mut self, read: &mut [W], write: &[W]) -> Result<(), S::Error> { + for i in 0..core::cmp::max(read.len(), write.len()) { + let word_out = if i < write.len() { + write[i].clone() + } else { + W::default() + }; + nb::block!(self.write(word_out.clone()))?; + + let word_in = nb::block!(self.read())?; + if i < read.len() { + read[i] = word_in; + } + } + + Ok(()) + } + } +} + +/// Blocking simultaneous read+write with separate buffers +pub mod transfer_inplace { + /// Default implementation of `blocking::spi::Transfer` for implementers of + /// `nonblocking::spi::FullDuplex` + pub trait Default: crate::nb::spi::FullDuplex {} + + impl crate::blocking::spi::TransferInplace for S where S: Default, W: Clone, { type Error = S::Error; - fn transfer(&mut self, words: &mut [W]) -> Result<(), S::Error> { + fn transfer_inplace(&mut self, words: &mut [W]) -> Result<(), S::Error> { for word in words.iter_mut() { nb::block!(self.write(word.clone()))?; *word = nb::block!(self.read())?; @@ -79,6 +141,32 @@ pub mod write { } } +/// Blocking read +pub mod read { + /// Default implementation of `blocking::spi::Read` for implementers + /// of `nonblocking::spi::FullDuplex` + /// + /// During the read, `W::default()` (which is typically 0) is sent on MOSI. + pub trait Default: crate::nb::spi::FullDuplex {} + + impl crate::blocking::spi::Read for S + where + S: Default, + W: core::default::Default, + { + type Error = S::Error; + + fn read(&mut self, words: &mut [W]) -> Result<(), S::Error> { + for word in words.iter_mut() { + nb::block!(self.write(W::default()))?; + *word = nb::block!(self.read())?; + } + + Ok(()) + } + } +} + /// Blocking write (iterator version) pub mod write_iter { /// Default implementation of `blocking::spi::WriteIter` for implementers of @@ -129,15 +217,15 @@ pub trait Transactional { /// Blocking transactional impl over spi::Write and spi::Transfer pub mod transactional { - use super::{Operation, Transfer, Write}; + use super::{Operation, TransferInplace, Write}; /// Default implementation of `blocking::spi::Transactional` for implementers of /// `spi::Write` and `spi::Transfer` - pub trait Default: Write + Transfer {} + pub trait Default: Write + TransferInplace {} impl super::Transactional for S where - S: self::Default + Write + Transfer, + S: self::Default + Write + TransferInplace, W: Copy + Clone, { type Error = E; @@ -146,7 +234,7 @@ pub mod transactional { for op in operations { match op { Operation::Write(w) => self.write(w)?, - Operation::Transfer(t) => self.transfer(t).map(|_| ())?, + Operation::Transfer(t) => self.transfer_inplace(t).map(|_| ())?, } }