diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d22d3d92..856e11c55 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] ### Added +- Default SPI word types - Added `Can` Controller Area Network traits. - `Error` traits for SPI, I2C and Serial traits. The error types used in those must implement these `Error` traits, which implies providing a conversion to a common diff --git a/src/spi/blocking.rs b/src/spi/blocking.rs index b98207277..00f779f38 100644 --- a/src/spi/blocking.rs +++ b/src/spi/blocking.rs @@ -4,59 +4,70 @@ //! traits. To save boilerplate when that's the case a `Default` marker trait may be provided. //! Implementing that marker trait will opt in your type into a blanket implementation. +use super::{SpiWord, U8}; + /// Blocking transfer -pub trait Transfer { +pub trait Transfer { /// Error type type Error: crate::spi::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(&mut self, words: &mut [W::Data]) -> Result<(), Self::Error>; } -impl, W> Transfer for &mut T { +impl, W> Transfer for &mut T +where + W: SpiWord, +{ type Error = T::Error; - fn transfer(&mut self, words: &mut [W]) -> Result<(), Self::Error> { + fn transfer(&mut self, words: &mut [W::Data]) -> Result<(), Self::Error> { T::transfer(self, words) } } /// Blocking write -pub trait Write { +pub trait Write { /// Error type type Error: crate::spi::Error; /// Writes `words` to the slave, ignoring all the incoming words - fn write(&mut self, words: &[W]) -> Result<(), Self::Error>; + fn write(&mut self, words: &[W::Data]) -> Result<(), Self::Error>; } -impl, W> Write for &mut T { +impl, W> Write for &mut T +where + W: SpiWord, +{ type Error = T::Error; - fn write(&mut self, words: &[W]) -> Result<(), Self::Error> { + fn write(&mut self, words: &[W::Data]) -> Result<(), Self::Error> { T::write(self, words) } } /// Blocking write (iterator version) -pub trait WriteIter { +pub trait WriteIter { /// Error type type Error: crate::spi::Error; /// Writes `words` to the slave, ignoring all the incoming words fn write_iter(&mut self, words: WI) -> Result<(), Self::Error> where - WI: IntoIterator; + WI: IntoIterator; } -impl, W> WriteIter for &mut T { +impl, W> WriteIter for &mut T +where + W: SpiWord, +{ type Error = T::Error; fn write_iter(&mut self, words: WI) -> Result<(), Self::Error> where - WI: IntoIterator, + WI: IntoIterator, { T::write_iter(self, words) } @@ -66,16 +77,24 @@ impl, W> WriteIter for &mut T { /// /// This allows composition of SPI operations into a single bus transaction #[derive(Debug, PartialEq)] -pub enum Operation<'a, W: 'static> { +pub enum Operation<'a, W = U8> +where + W: SpiWord, + W::Data: 'static, +{ /// Write data from the provided buffer, discarding read data - Write(&'a [W]), + Write(&'a [W::Data]), /// Write data out while reading data into the provided buffer - Transfer(&'a mut [W]), + Transfer(&'a mut [W::Data]), } /// Transactional trait allows multiple actions to be executed /// as part of a single SPI transaction -pub trait Transactional { +pub trait Transactional +where + W: SpiWord, + W::Data: 'static, +{ /// Associated error type type Error: crate::spi::Error; @@ -83,7 +102,11 @@ pub trait Transactional { fn exec<'a>(&mut self, operations: &mut [Operation<'a, W>]) -> Result<(), Self::Error>; } -impl, W: 'static> Transactional for &mut T { +impl, W> Transactional for &mut T +where + W: SpiWord, + W::Data: 'static, +{ type Error = T::Error; fn exec<'a>(&mut self, operations: &mut [Operation<'a, W>]) -> Result<(), Self::Error> { diff --git a/src/spi/mod.rs b/src/spi/mod.rs index c367e70d8..7bb9da473 100644 --- a/src/spi/mod.rs +++ b/src/spi/mod.rs @@ -1,8 +1,42 @@ //! SPI traits +use crate::private::Sealed; + pub mod blocking; pub mod nb; +/// Marker trait for SPI Word +pub trait SpiWord: Sealed { + /// Specified data size type + type Data: Sized; +} + +/// 8-bit SPI Word (default) +pub type U8 = u8; +/// 9-bit SPI Word +pub struct U9; +/// 16-bit SPI Word +pub struct U16; +/// 18-bit SPI Word +pub struct U18; + +impl Sealed for U9 {} +impl Sealed for U16 {} +impl Sealed for U18 {} + +impl SpiWord for U8 { + type Data = u8; +} +impl SpiWord for U9 { + type Data = u16; +} +impl SpiWord for U16 { + type Data = u16; +} +impl SpiWord for U18 { + type Data = u32; +} + /// Clock polarity #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Polarity { diff --git a/src/spi/nb.rs b/src/spi/nb.rs index c7d377ef9..342bac0ee 100644 --- a/src/spi/nb.rs +++ b/src/spi/nb.rs @@ -1,5 +1,7 @@ //! Serial Peripheral Interface +use super::{SpiWord, U8}; + /// Full duplex (master mode) /// /// # Notes @@ -15,8 +17,8 @@ /// The slave select line shouldn't be released before that. /// /// - Some SPIs can work with 8-bit *and* 16-bit words. You can overload this trait with different -/// `Word` types to allow operation in both modes. -pub trait FullDuplex { +/// `W` types to allow operation in both modes. +pub trait FullDuplex { /// An enumeration of SPI errors type Error: crate::spi::Error; @@ -24,20 +26,23 @@ pub trait FullDuplex { /// /// **NOTE** A word must be sent to the slave before attempting to call this /// method. - fn read(&mut self) -> nb::Result; + fn read(&mut self) -> nb::Result; /// Writes a word to the slave - fn write(&mut self, word: Word) -> nb::Result<(), Self::Error>; + fn write(&mut self, word: W::Data) -> nb::Result<(), Self::Error>; } -impl, Word> FullDuplex for &mut T { +impl, W> FullDuplex for &mut T +where + W: SpiWord, +{ type Error = T::Error; - fn read(&mut self) -> nb::Result { + fn read(&mut self) -> nb::Result { T::read(self) } - fn write(&mut self, word: Word) -> nb::Result<(), Self::Error> { + fn write(&mut self, word: W::Data) -> nb::Result<(), Self::Error> { T::write(self, word) } }