diff --git a/Cargo.toml b/Cargo.toml index 69cbfec..9093d65 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ license = "MIT OR Apache-2.0" all-features = true [dependencies] -embedded-hal = "0.2.3" +embedded-hal = "1.0.0-alpha.4" once_cell = { version = "1.4.0", optional = true } cortex-m = { version = "0.6.3", optional = true } @@ -25,3 +25,8 @@ embedded-hal-mock = "0.7.0" [features] std = ["once_cell"] + + +[patch.crates-io] +embedded-hal = { git = "https://github.com/ryankurte/embedded-hal", branch = "feature/spi-cs" } +embedded-hal-mock = { git = "https://github.com/ryankurte/embedded-hal-mock", branch="support-eh-v1.0.0-alpha" } diff --git a/src/lib.rs b/src/lib.rs index ba4435b..1e09845 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -118,6 +118,10 @@ mod manager; mod mutex; mod proxies; +#[doc(hidden)] +#[cfg(test)] +extern crate std; + #[doc(hidden)] #[cfg(feature = "std")] pub use once_cell; diff --git a/src/manager.rs b/src/manager.rs index 89088dc..f5601e7 100644 --- a/src/manager.rs +++ b/src/manager.rs @@ -146,7 +146,7 @@ impl BusManager> { /// /// ``` /// # use embedded_hal::blocking::spi; - /// # use embedded_hal::digital::v2; + /// # use embedded_hal::blocking::digital::OutputPin; /// # use embedded_hal::blocking::spi::Write as _; /// # struct MyDevice(T); /// # impl> MyDevice { @@ -156,7 +156,7 @@ impl BusManager> { /// # } /// # } /// # - /// # fn _example(mut cs1: impl v2::OutputPin, spi: impl spi::Write) { + /// # fn _example(mut cs1: impl OutputPin, spi: impl spi::Write) { /// let bus = shared_bus::BusManagerSimple::new(spi); /// /// let mut proxy1 = bus.acquire_spi(); diff --git a/src/proxies.rs b/src/proxies.rs index 4904137..f8bca67 100644 --- a/src/proxies.rs +++ b/src/proxies.rs @@ -1,5 +1,7 @@ use embedded_hal::blocking::i2c; use embedded_hal::blocking::spi; +use embedded_hal::blocking::spi::spi_with_cs::SpiWithCsError; +use embedded_hal::blocking::digital; /// Proxy type for I2C bus sharing. /// @@ -111,3 +113,95 @@ where self.mutex.lock(|bus| bus.write(words)) } } + +impl<'a, M: crate::BusMutex> spi::Transactional for SpiProxy<'a, M> +where + M::Bus: spi::Transactional, +{ + type Error = >::Error; + + fn exec(&mut self, ops: &mut [spi::Operation]) -> Result<(), Self::Error> { + self.mutex.lock(|bus| bus.exec(ops)) + } +} + + + +/// Proxy type for SPI bus sharing with Chip Select management. +/// The `SpiProxyCs` implements all (blocking) SPI traits so it can be passed to drivers instead of +/// the bus instance. An `SpiProxyCs` is created by calling [`BusManager::acquire_spi_cs()`][acquire_spi_cs]. +/// +/// This implementation locks the mutex _prior_ to asserting CS, ensuring exclusive access. +/// See [embedded_hal::blocking::spi::ManagedCS] for more details. +#[derive(Debug)] +pub struct SpiProxyCs<'a, M, P> { + pub(crate) mutex: &'a M, + pub(crate) cs: P, + pub(crate) _u: core::marker::PhantomData<*mut ()>, +} + +/// SpiProxyCx implements ManagedCs, include CS assert/de-assert in the mutex. +impl<'a, M: crate::BusMutex, CsPin> spi::ManagedCs for SpiProxyCs<'a, M, CsPin> {} + +impl<'a, M: crate::BusMutex, CsPin, PinError> spi::Transfer for SpiProxyCs<'a, M, CsPin> +where + M::Bus: spi::Transfer, + CsPin: digital::OutputPin +{ + type Error = SpiWithCsError<>::Error, PinError>; + + fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> { + self.mutex.lock(move |bus| { + // Assert CS + self.cs.set_low().map_err(SpiWithCsError::Pin)?; + // Execute bus operation + let r = bus.transfer(words).map_err(SpiWithCsError::Spi)?; + // De-assert CS + self.cs.set_high().map_err(SpiWithCsError::Pin)?; + + Ok(r) + }) + } +} + +impl<'a, M: crate::BusMutex, CsPin, PinError> spi::Write for SpiProxyCs<'a, M, CsPin> +where + M::Bus: spi::Write, + CsPin: digital::OutputPin +{ + type Error = SpiWithCsError<>::Error, PinError>; + + fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> { + self.mutex.lock(|bus| { + // Assert CS + self.cs.set_low().map_err(SpiWithCsError::Pin)?; + // Execute bus operation + bus.write(words).map_err(SpiWithCsError::Spi)?; + // De-assert CS + self.cs.set_high().map_err(SpiWithCsError::Pin)?; + + Ok(()) + }) + } +} + +impl<'a, M: crate::BusMutex, CsPin, PinError> spi::Transactional for SpiProxyCs<'a, M, CsPin> +where + M::Bus: spi::Transactional, + CsPin: digital::OutputPin, +{ + type Error = SpiWithCsError<>::Error, PinError>; + + fn exec(&mut self, ops: &mut [spi::Operation]) -> Result<(), Self::Error> { + self.mutex.lock(|bus| { + // Assert CS + self.cs.set_low().map_err(SpiWithCsError::Pin)?; + // Execute bus operation + bus.exec(ops).map_err(SpiWithCsError::Spi)?; + // De-assert CS + self.cs.set_high().map_err(SpiWithCsError::Pin)?; + + Ok(()) + }) + } +} diff --git a/tests/i2c.rs b/tests/i2c.rs index 013ef56..ee02b2f 100644 --- a/tests/i2c.rs +++ b/tests/i2c.rs @@ -1,4 +1,4 @@ -use embedded_hal::prelude::*; +use embedded_hal::blocking::i2c::*; use embedded_hal_mock::i2c; use std::thread; diff --git a/tests/spi.rs b/tests/spi.rs index 6df30a7..12a58e5 100644 --- a/tests/spi.rs +++ b/tests/spi.rs @@ -1,4 +1,4 @@ -use embedded_hal::prelude::*; +use embedded_hal::blocking::spi::*; use embedded_hal_mock::spi; #[test]