mirror of
https://github.com/rust-embedded/embedded-hal.git
synced 2026-03-13 17:37:41 +00:00
Drafting alt ManagedCS traits
This commit is contained in:
parent
556c1bea37
commit
55bc270841
@ -15,6 +15,7 @@ pub trait Transfer<Word = u8>: ErrorType {
|
||||
fn transfer(&mut self, read: &mut [Word], write: &[Word]) -> Result<(), Self::Error>;
|
||||
}
|
||||
|
||||
#[cfg(conflicting)]
|
||||
impl<T: Transfer<Word>, Word: Copy> Transfer<Word> for &mut T {
|
||||
fn transfer(&mut self, read: &mut [Word], write: &[Word]) -> Result<(), Self::Error> {
|
||||
T::transfer(self, read, write)
|
||||
@ -29,6 +30,7 @@ pub trait TransferInplace<Word: Copy = u8>: ErrorType {
|
||||
fn transfer_inplace(&mut self, words: &mut [Word]) -> Result<(), Self::Error>;
|
||||
}
|
||||
|
||||
#[cfg(conflicting)]
|
||||
impl<T: TransferInplace<Word>, Word: Copy> TransferInplace<Word> for &mut T {
|
||||
fn transfer_inplace(&mut self, words: &mut [Word]) -> Result<(), Self::Error> {
|
||||
T::transfer_inplace(self, words)
|
||||
@ -44,6 +46,7 @@ pub trait Read<Word: Copy = u8>: ErrorType {
|
||||
fn read(&mut self, words: &mut [Word]) -> Result<(), Self::Error>;
|
||||
}
|
||||
|
||||
#[cfg(conflicting)]
|
||||
impl<T: Read<Word>, Word: Copy> Read<Word> for &mut T {
|
||||
fn read(&mut self, words: &mut [Word]) -> Result<(), Self::Error> {
|
||||
T::read(self, words)
|
||||
@ -56,6 +59,7 @@ pub trait Write<Word: Copy = u8>: ErrorType {
|
||||
fn write(&mut self, words: &[Word]) -> Result<(), Self::Error>;
|
||||
}
|
||||
|
||||
#[cfg(conflicting)]
|
||||
impl<T: Write<Word>, Word: Copy> Write<Word> for &mut T {
|
||||
fn write(&mut self, words: &[Word]) -> Result<(), Self::Error> {
|
||||
T::write(self, words)
|
||||
@ -101,8 +105,221 @@ pub trait Transactional<Word: 'static + Copy = u8>: ErrorType {
|
||||
fn exec<'a>(&mut self, operations: &mut [Operation<'a, Word>]) -> Result<(), Self::Error>;
|
||||
}
|
||||
|
||||
#[cfg(conflicting)]
|
||||
impl<T: Transactional<Word>, Word: 'static + Copy> Transactional<Word> for &mut T {
|
||||
fn exec<'a>(&mut self, operations: &mut [Operation<'a, Word>]) -> Result<(), Self::Error> {
|
||||
T::exec(self, operations)
|
||||
}
|
||||
}
|
||||
|
||||
/// SPI Managed CS trait
|
||||
///
|
||||
/// This uses a bunch of magic to manage CS for all SPI methods, and conflicts with the `&mut T` impls for each trait.
|
||||
///
|
||||
/// ```
|
||||
/// use embedded_hal::spi::blocking::{ManagedCs, Write};
|
||||
///
|
||||
/// // Automatic CS assertion
|
||||
/// fn spi_write_auto_cs<SPI: ManagedCs + Write>(spi: &mut SPI) {
|
||||
/// let _ = spi.write(&[0xaa, 0xbb, 0xcc]);
|
||||
/// }
|
||||
/// // Manual CS assertion
|
||||
/// fn spi_write_manual_cs<SPI: ManagedCs<Inner=P>, P: Write>(spi: &mut SPI) {
|
||||
/// let _ = spi.with_cs(|d|{
|
||||
/// let _ = d.write(&[0xaa, 0xbb, 0xcc]);
|
||||
/// Ok(())
|
||||
/// });
|
||||
/// }
|
||||
/// ```
|
||||
pub trait ManagedCs: ErrorType {
|
||||
/// Inner SPI type
|
||||
type Inner: ErrorType;
|
||||
|
||||
/// Execute the provided closure within a CS assertion
|
||||
fn with_cs<F: FnMut(&mut Self::Inner) -> Result<(), Self::Error>>(
|
||||
&mut self,
|
||||
f: F,
|
||||
) -> Result<(), Self::Error>;
|
||||
|
||||
/// Reference the inner SPI object without manipulating CS
|
||||
fn inner(&mut self) -> &mut Self::Inner;
|
||||
}
|
||||
|
||||
/// Alternate managed CS trait
|
||||
///
|
||||
/// This one doesn't require any defaults / provide any magic, if you want
|
||||
/// to do things within a CS assertion you call `with_cs`.
|
||||
///
|
||||
/// ```
|
||||
/// use embedded_hal::spi::blocking::{ManagedCsAlt, Write};
|
||||
///
|
||||
/// // Manual CS assertion
|
||||
/// fn spi_write_manual_cs<SPI: ManagedCsAlt + Write>(spi: &mut SPI) {
|
||||
/// let _ = spi.with_cs(|d|{
|
||||
/// let _ = d.write(&[0xaa, 0xbb, 0xcc]);
|
||||
/// Ok(())
|
||||
/// });
|
||||
/// }
|
||||
/// ```
|
||||
pub trait ManagedCsAlt: ErrorType {
|
||||
/// Execute the provided closure within a CS assertion
|
||||
fn with_cs<F: FnMut(&mut Self) -> Result<(), Self::Error>>(
|
||||
&mut self,
|
||||
f: F,
|
||||
) -> Result<(), Self::Error>;
|
||||
}
|
||||
|
||||
/// These default conflict with the &mut impls, we could just not have them / require folks to always call [`ManagedCs::with_cs`]?
|
||||
mod defaults {
|
||||
use super::*;
|
||||
|
||||
/// Default blocking [`Transfer`] with CS management
|
||||
impl<T, I, E, Word> Transfer<Word> for T
|
||||
where
|
||||
T: ManagedCs<Inner = I> + ErrorType<Error = E>,
|
||||
I: Transfer<Word> + ErrorType<Error = E>,
|
||||
Word: Copy + 'static,
|
||||
{
|
||||
fn transfer<'a>(&mut self, read: &mut [Word], write: &[Word]) -> Result<(), Self::Error> {
|
||||
self.with_cs(|i: &mut I| i.transfer(read, write))
|
||||
}
|
||||
}
|
||||
|
||||
/// Default blocking [`TransferInplace`] with CS management
|
||||
impl<T, I, E, Word> TransferInplace<Word> for T
|
||||
where
|
||||
T: ManagedCs<Inner = I> + ErrorType<Error = E>,
|
||||
I: TransferInplace<Word> + ErrorType<Error = E>,
|
||||
Word: Copy + 'static,
|
||||
{
|
||||
fn transfer_inplace<'a>(&mut self, words: &mut [Word]) -> Result<(), Self::Error> {
|
||||
self.with_cs(|i: &mut I| i.transfer_inplace(words))
|
||||
}
|
||||
}
|
||||
|
||||
/// Default blocking [`Read`] with CS management
|
||||
impl<T, I, E, Word> Read<Word> for T
|
||||
where
|
||||
T: ManagedCs<Inner = I> + ErrorType<Error = E>,
|
||||
I: Read<Word> + ErrorType<Error = E>,
|
||||
Word: Copy + 'static,
|
||||
{
|
||||
fn read<'a>(&mut self, words: &mut [Word]) -> Result<(), Self::Error> {
|
||||
self.with_cs(|i: &mut I| i.read(words))
|
||||
}
|
||||
}
|
||||
|
||||
/// Default blocking [`Write`] with CS management
|
||||
impl<T, I, E, Word> Write<Word> for T
|
||||
where
|
||||
T: ManagedCs<Inner = I> + ErrorType<Error = E>,
|
||||
I: Write<Word> + ErrorType<Error = E>,
|
||||
Word: Copy + 'static,
|
||||
{
|
||||
fn write<'a>(&mut self, words: &[Word]) -> Result<(), Self::Error> {
|
||||
self.with_cs(|i: &mut I| i.write(words))
|
||||
}
|
||||
}
|
||||
|
||||
/// Default blocking [`Transactional`] with CS management
|
||||
impl<T, I, E, Word> Transactional<Word> for T
|
||||
where
|
||||
T: ManagedCs<Inner = I> + ErrorType<Error = E>,
|
||||
I: Transactional<Word> + ErrorType<Error = E>,
|
||||
Word: Copy + 'static,
|
||||
{
|
||||
fn exec<'a>(&mut self, operations: &mut [Operation<'a, Word>]) -> Result<(), Self::Error> {
|
||||
self.with_cs(|i: &mut I| i.exec(operations))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// [`SpiWithCs`] wraps an SPI implementation with Chip Select (CS)
|
||||
/// pin management for exclusive (non-shared) use.
|
||||
/// For sharing SPI between peripherals, see [shared-bus](https://crates.io/crates/shared-bus)
|
||||
pub struct SpiWithCs<Spi, Pin> {
|
||||
spi: Spi,
|
||||
cs: Pin,
|
||||
}
|
||||
|
||||
/// Wrapper for errors returned by [`SpiWithCs`]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum SpiWithCsError<SpiError, PinError> {
|
||||
/// Underlying SPI communication error
|
||||
Spi(SpiError),
|
||||
/// Underlying chip-select pin state setting error
|
||||
Pin(PinError),
|
||||
}
|
||||
|
||||
/// [`ErrorType`] implementation for [`SpiWithCs`] wrapper
|
||||
impl<Spi, Pin> ErrorType for SpiWithCs<Spi, Pin>
|
||||
where
|
||||
Spi: ErrorType,
|
||||
Pin: crate::digital::blocking::OutputPin + crate::digital::ErrorType,
|
||||
{
|
||||
type Error =
|
||||
SpiWithCsError<<Spi as ErrorType>::Error, <Pin as crate::digital::ErrorType>::Error>;
|
||||
}
|
||||
|
||||
/// [`ManagedCs`] implementation for [`SpiWithCs`] wrapper.
|
||||
/// Provides `with_cs` function that asserts and deasserts CS
|
||||
impl<Spi, Pin> ManagedCs for SpiWithCs<Spi, Pin>
|
||||
where
|
||||
Spi: ErrorType,
|
||||
Pin: crate::digital::blocking::OutputPin + crate::digital::ErrorType,
|
||||
{
|
||||
type Inner = Spi;
|
||||
|
||||
/// Executes the provided closure within a CS assertion
|
||||
fn with_cs<F: FnMut(&mut Self::Inner) -> Result<(), Self::Error>>(
|
||||
&mut self,
|
||||
mut f: F,
|
||||
) -> Result<(), Self::Error> {
|
||||
self.cs.set_low().map_err(SpiWithCsError::Pin)?;
|
||||
|
||||
let r = f(&mut self.spi);
|
||||
|
||||
self.cs.set_high().map_err(SpiWithCsError::Pin)?;
|
||||
|
||||
r
|
||||
}
|
||||
|
||||
/// Reference the inner SPI object without manipulating CS
|
||||
fn inner(&mut self) -> &mut Self::Inner {
|
||||
&mut self.spi
|
||||
}
|
||||
}
|
||||
|
||||
/// [`ManagedCs`] implementation for [`SpiWithCs`] wrapper.
|
||||
/// Provides `with_cs` function that asserts and deasserts CS
|
||||
impl<Spi, Pin> ManagedCsAlt for SpiWithCs<Spi, Pin>
|
||||
where
|
||||
Spi: ErrorType,
|
||||
Pin: crate::digital::blocking::OutputPin + crate::digital::ErrorType,
|
||||
{
|
||||
/// Executes the provided closure within a CS assertion
|
||||
fn with_cs<F: FnMut(&mut Self) -> Result<(), Self::Error>>(
|
||||
&mut self,
|
||||
mut f: F,
|
||||
) -> Result<(), Self::Error> {
|
||||
self.cs.set_low().map_err(SpiWithCsError::Pin)?;
|
||||
|
||||
let r = f(self);
|
||||
|
||||
self.cs.set_high().map_err(SpiWithCsError::Pin)?;
|
||||
|
||||
r
|
||||
}
|
||||
}
|
||||
|
||||
/// [`super::Error`] implementation for [`SpiWithCsError`]
|
||||
impl<SpiError: super::Error + core::fmt::Debug, PinError: core::fmt::Debug> super::Error
|
||||
for SpiWithCsError<SpiError, PinError>
|
||||
{
|
||||
fn kind(&self) -> super::ErrorKind {
|
||||
match self {
|
||||
SpiWithCsError::Spi(spi) => spi.kind(),
|
||||
SpiWithCsError::Pin(_pin) => super::ErrorKind::Other,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user