spi: remove write-only and read-only traits.

This commit is contained in:
Dario Nieuwenhuis
2023-05-10 22:22:57 +02:00
parent 804e1de2df
commit 1567f258bf
8 changed files with 128 additions and 675 deletions

View File

@@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
## [Unreleased]
### Removed
- spi: removed read-only and write-only traits.
## [v0.2.0-alpha.1] - 2023-04-04
### Added

View File

@@ -8,96 +8,19 @@ pub use embedded_hal::spi::{
Error, ErrorKind, ErrorType, Mode, Operation, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3,
};
/// SPI read-only device trait
///
/// `SpiDeviceRead` represents ownership over a single SPI device on a (possibly shared) bus, selected
/// with a CS (Chip Select) pin.
///
/// See (the docs on embedded-hal)[embedded_hal::spi] for important information on SPI Bus vs Device traits.
///
/// See the [module-level documentation](self) for important usage information.
pub trait SpiDeviceRead<Word: Copy + 'static = u8>: ErrorType {
/// Perform a read transaction against the device.
///
/// - Locks the bus
/// - Asserts the CS (Chip Select) pin.
/// - Performs all the operations.
/// - [Flushes](SpiBusFlush::flush) the bus.
/// - Deasserts the CS pin.
/// - Unlocks the bus.
///
/// The locking mechanism is implementation-defined. The only requirement is it must prevent two
/// transactions from executing concurrently against the same bus. Examples of implementations are:
/// critical sections, blocking mutexes, returning an error or panicking if the bus is already busy.
///
/// On bus errors the implementation should try to deassert CS.
/// If an error occurs while deasserting CS the bus error should take priority as the return value.
async fn read_transaction(&mut self, operations: &mut [&mut [Word]])
-> Result<(), Self::Error>;
/// Do a read within a transaction.
///
/// This is a convenience method equivalent to `device.read_transaction(&mut [buf])`.
///
/// See also: [`SpiDeviceRead::read_transaction`], [`SpiBusRead::read`]
async fn read(&mut self, buf: &mut [Word]) -> Result<(), Self::Error> {
self.read_transaction(&mut [buf]).await
}
}
/// SPI write-only device trait
///
/// `SpiDeviceWrite` represents ownership over a single SPI device on a (possibly shared) bus, selected
/// with a CS (Chip Select) pin.
///
/// See (the docs on embedded-hal)[embedded_hal::spi] for important information on SPI Bus vs Device traits.
///
/// See the [module-level documentation](self) for important usage information.
pub trait SpiDeviceWrite<Word: Copy + 'static = u8>: ErrorType {
/// Perform a write transaction against the device.
///
/// - Locks the bus
/// - Asserts the CS (Chip Select) pin.
/// - Performs all the operations.
/// - [Flushes](SpiBusFlush::flush) the bus.
/// - Deasserts the CS pin.
/// - Unlocks the bus.
///
/// The locking mechanism is implementation-defined. The only requirement is it must prevent two
/// transactions from executing concurrently against the same bus. Examples of implementations are:
/// critical sections, blocking mutexes, returning an error or panicking if the bus is already busy.
///
/// On bus errors the implementation should try to deassert CS.
/// If an error occurs while deasserting CS the bus error should take priority as the return value.
async fn write_transaction(&mut self, operations: &[&[Word]]) -> Result<(), Self::Error>;
/// Do a write within a transaction.
///
/// This is a convenience method equivalent to `device.write_transaction(&mut [buf])`.
///
/// See also: [`SpiDeviceWrite::write_transaction`], [`SpiBusWrite::write`]
async fn write(&mut self, buf: &[Word]) -> Result<(), Self::Error> {
self.write_transaction(&[buf]).await
}
}
/// SPI device trait
///
/// `SpiDevice` represents ownership over a single SPI device on a (possibly shared) bus, selected
/// with a CS (Chip Select) pin.
///
/// See (the docs on embedded-hal)[embedded_hal::spi] for important information on SPI Bus vs Device traits.
///
/// See the [module-level documentation](self) for important usage information.
pub trait SpiDevice<Word: Copy + 'static = u8>:
SpiDeviceRead<Word> + SpiDeviceWrite<Word> + ErrorType
{
pub trait SpiDevice<Word: Copy + 'static = u8>: ErrorType {
/// Perform a transaction against the device.
///
/// - Locks the bus
/// - Asserts the CS (Chip Select) pin.
/// - Performs all the operations.
/// - [Flushes](SpiBusFlush::flush) the bus.
/// - [Flushes](SpiBus::flush) the bus.
/// - Deasserts the CS pin.
/// - Unlocks the bus.
///
@@ -112,6 +35,24 @@ pub trait SpiDevice<Word: Copy + 'static = u8>:
operations: &mut [Operation<'_, Word>],
) -> Result<(), Self::Error>;
/// Do a read within a transaction.
///
/// This is a convenience method equivalent to `device.read_transaction(&mut [buf])`.
///
/// See also: [`SpiDevice::transaction`], [`SpiDevice::read`]
async fn read(&mut self, buf: &mut [Word]) -> Result<(), Self::Error> {
self.transaction(&mut [Operation::Read(buf)]).await
}
/// Do a write within a transaction.
///
/// This is a convenience method equivalent to `device.write_transaction(&mut [buf])`.
///
/// See also: [`SpiDevice::transaction`], [`SpiDevice::write`]
async fn write(&mut self, buf: &[Word]) -> Result<(), Self::Error> {
self.transaction(&mut [Operation::Write(buf)]).await
}
/// Do a transfer within a transaction.
///
/// This is a convenience method equivalent to `device.transaction(|bus| bus.transfer(read, write))`.
@@ -133,29 +74,6 @@ pub trait SpiDevice<Word: Copy + 'static = u8>:
}
}
impl<Word: Copy + 'static, T: SpiDeviceRead<Word>> SpiDeviceRead<Word> for &mut T {
async fn read_transaction(
&mut self,
operations: &mut [&mut [Word]],
) -> Result<(), Self::Error> {
T::read_transaction(self, operations).await
}
async fn read(&mut self, buf: &mut [Word]) -> Result<(), Self::Error> {
T::read(self, buf).await
}
}
impl<Word: Copy + 'static, T: SpiDeviceWrite<Word>> SpiDeviceWrite<Word> for &mut T {
async fn write_transaction(&mut self, operations: &[&[Word]]) -> Result<(), Self::Error> {
T::write_transaction(self, operations).await
}
async fn write(&mut self, buf: &[Word]) -> Result<(), Self::Error> {
T::write(self, buf).await
}
}
impl<Word: Copy + 'static, T: SpiDevice<Word>> SpiDevice<Word> for &mut T {
async fn transaction(
&mut self,
@@ -164,6 +82,14 @@ impl<Word: Copy + 'static, T: SpiDevice<Word>> SpiDevice<Word> for &mut T {
T::transaction(self, operations).await
}
async fn read(&mut self, buf: &mut [Word]) -> Result<(), Self::Error> {
T::read(self, buf).await
}
async fn write(&mut self, buf: &[Word]) -> Result<(), Self::Error> {
T::write(self, buf).await
}
async fn transfer(&mut self, read: &mut [Word], write: &[Word]) -> Result<(), Self::Error> {
T::transfer(self, read, write).await
}
@@ -173,22 +99,12 @@ impl<Word: Copy + 'static, T: SpiDevice<Word>> SpiDevice<Word> for &mut T {
}
}
/// Flush support for SPI bus
pub trait SpiBusFlush: ErrorType {
/// Wait until all operations have completed and the bus is idle.
///
/// See (the docs on embedded-hal)[embedded_hal::spi] for information on flushing.
async fn flush(&mut self) -> Result<(), Self::Error>;
}
impl<T: SpiBusFlush> SpiBusFlush for &mut T {
async fn flush(&mut self) -> Result<(), Self::Error> {
T::flush(self).await
}
}
/// Read-only SPI bus
pub trait SpiBusRead<Word: 'static + Copy = u8>: SpiBusFlush {
/// SPI bus
///
/// `SpiBus` represents **exclusive ownership** over the whole SPI bus, with SCK, MOSI and MISO pins.
///
/// See (the docs on embedded-hal)[embedded_hal::spi] for important information on SPI Bus vs Device traits.
pub trait SpiBus<Word: 'static + Copy = u8>: ErrorType {
/// Read `words` from the slave.
///
/// The word value sent on MOSI during reading is implementation-defined,
@@ -197,35 +113,13 @@ pub trait SpiBusRead<Word: 'static + Copy = u8>: SpiBusFlush {
/// Implementations are allowed to return before the operation is
/// complete. See (the docs on embedded-hal)[embedded_hal::spi] for details on flushing.
async fn read(&mut self, words: &mut [Word]) -> Result<(), Self::Error>;
}
impl<T: SpiBusRead<Word>, Word: 'static + Copy> SpiBusRead<Word> for &mut T {
async fn read(&mut self, words: &mut [Word]) -> Result<(), Self::Error> {
T::read(self, words).await
}
}
/// Write-only SPI
pub trait SpiBusWrite<Word: 'static + Copy = u8>: SpiBusFlush {
/// Write `words` to the slave, ignoring all the incoming words
///
/// Implementations are allowed to return before the operation is
/// complete. See (the docs on embedded-hal)[embedded_hal::spi] for details on flushing.
async fn write(&mut self, words: &[Word]) -> Result<(), Self::Error>;
}
impl<T: SpiBusWrite<Word>, Word: 'static + Copy> SpiBusWrite<Word> for &mut T {
async fn write(&mut self, words: &[Word]) -> Result<(), Self::Error> {
T::write(self, words).await
}
}
/// Read-write SPI bus
///
/// `SpiBus` represents **exclusive ownership** over the whole SPI bus, with SCK, MOSI and MISO pins.
///
/// See (the docs on embedded-hal)[embedded_hal::spi] for important information on SPI Bus vs Device traits.
pub trait SpiBus<Word: 'static + Copy = u8>: SpiBusRead<Word> + SpiBusWrite<Word> {
/// Write and read simultaneously. `write` is written to the slave on MOSI and
/// words received on MISO are stored in `read`.
///
@@ -237,11 +131,7 @@ pub trait SpiBus<Word: 'static + Copy = u8>: SpiBusRead<Word> + SpiBusWrite<Word
///
/// Implementations are allowed to return before the operation is
/// complete. See (the docs on embedded-hal)[embedded_hal::spi] for details on flushing.
async fn transfer<'a>(
&'a mut self,
read: &'a mut [Word],
write: &'a [Word],
) -> Result<(), Self::Error>;
async fn transfer(&mut self, read: &mut [Word], write: &[Word]) -> Result<(), Self::Error>;
/// Write and read simultaneously. The contents of `words` are
/// written to the slave, and the received words are stored into the same
@@ -249,21 +139,34 @@ pub trait SpiBus<Word: 'static + Copy = u8>: SpiBusRead<Word> + SpiBusWrite<Word
///
/// Implementations are allowed to return before the operation is
/// complete. See (the docs on embedded-hal)[embedded_hal::spi] for details on flushing.
async fn transfer_in_place<'a>(&'a mut self, words: &'a mut [Word]) -> Result<(), Self::Error>;
async fn transfer_in_place(&mut self, words: &mut [Word]) -> Result<(), Self::Error>;
/// Wait until all operations have completed and the bus is idle.
///
/// See (the docs on embedded-hal)[embedded_hal::spi] for information on flushing.
async fn flush(&mut self) -> Result<(), Self::Error>;
}
impl<T: SpiBus<Word>, Word: 'static + Copy> SpiBus<Word> for &mut T {
async fn transfer<'a>(
&'a mut self,
read: &'a mut [Word],
write: &'a [Word],
) -> Result<(), Self::Error> {
async fn read(&mut self, words: &mut [Word]) -> Result<(), Self::Error> {
T::read(self, words).await
}
async fn write(&mut self, words: &[Word]) -> Result<(), Self::Error> {
T::write(self, words).await
}
async fn transfer(&mut self, read: &mut [Word], write: &[Word]) -> Result<(), Self::Error> {
T::transfer(self, read, write).await
}
async fn transfer_in_place<'a>(&'a mut self, words: &'a mut [Word]) -> Result<(), Self::Error> {
async fn transfer_in_place(&mut self, words: &mut [Word]) -> Result<(), Self::Error> {
T::transfer_in_place(self, words).await
}
async fn flush(&mut self) -> Result<(), Self::Error> {
T::flush(self).await
}
}
/// Error type for [`ExclusiveDevice`] operations.
@@ -312,64 +215,6 @@ where
type Error = ExclusiveDeviceError<BUS::Error, CS::Error>;
}
impl<Word: Copy + 'static, BUS, CS> blocking::SpiDeviceRead<Word> for ExclusiveDevice<BUS, CS>
where
BUS: blocking::SpiBusRead<Word>,
CS: OutputPin,
{
fn read_transaction(&mut self, operations: &mut [&mut [Word]]) -> Result<(), Self::Error> {
self.cs.set_low().map_err(ExclusiveDeviceError::Cs)?;
let mut op_res = Ok(());
for buf in operations {
if let Err(e) = self.bus.read(buf) {
op_res = Err(e);
break;
}
}
// On failure, it's important to still flush and deassert CS.
let flush_res = self.bus.flush();
let cs_res = self.cs.set_high();
op_res.map_err(ExclusiveDeviceError::Spi)?;
flush_res.map_err(ExclusiveDeviceError::Spi)?;
cs_res.map_err(ExclusiveDeviceError::Cs)?;
Ok(())
}
}
impl<Word: Copy + 'static, BUS, CS> blocking::SpiDeviceWrite<Word> for ExclusiveDevice<BUS, CS>
where
BUS: blocking::SpiBusWrite<Word>,
CS: OutputPin,
{
fn write_transaction(&mut self, operations: &[&[Word]]) -> Result<(), Self::Error> {
self.cs.set_low().map_err(ExclusiveDeviceError::Cs)?;
let mut op_res = Ok(());
for buf in operations {
if let Err(e) = self.bus.write(buf) {
op_res = Err(e);
break;
}
}
// On failure, it's important to still flush and deassert CS.
let flush_res = self.bus.flush();
let cs_res = self.cs.set_high();
op_res.map_err(ExclusiveDeviceError::Spi)?;
flush_res.map_err(ExclusiveDeviceError::Spi)?;
cs_res.map_err(ExclusiveDeviceError::Cs)?;
Ok(())
}
}
impl<Word: Copy + 'static, BUS, CS> blocking::SpiDevice<Word> for ExclusiveDevice<BUS, CS>
where
BUS: blocking::SpiBus<Word>,
@@ -405,67 +250,6 @@ where
}
}
impl<Word: Copy + 'static, BUS, CS> SpiDeviceRead<Word> for ExclusiveDevice<BUS, CS>
where
BUS: SpiBusRead<Word>,
CS: OutputPin,
{
async fn read_transaction(
&mut self,
operations: &mut [&mut [Word]],
) -> Result<(), Self::Error> {
self.cs.set_low().map_err(ExclusiveDeviceError::Cs)?;
let mut op_res = Ok(());
for buf in operations {
if let Err(e) = self.bus.read(buf).await {
op_res = Err(e);
break;
}
}
// On failure, it's important to still flush and deassert CS.
let flush_res = self.bus.flush().await;
let cs_res = self.cs.set_high();
op_res.map_err(ExclusiveDeviceError::Spi)?;
flush_res.map_err(ExclusiveDeviceError::Spi)?;
cs_res.map_err(ExclusiveDeviceError::Cs)?;
Ok(())
}
}
impl<Word: Copy + 'static, BUS, CS> SpiDeviceWrite<Word> for ExclusiveDevice<BUS, CS>
where
BUS: SpiBusWrite<Word>,
CS: OutputPin,
{
async fn write_transaction(&mut self, operations: &[&[Word]]) -> Result<(), Self::Error> {
self.cs.set_low().map_err(ExclusiveDeviceError::Cs)?;
let mut op_res = Ok(());
for buf in operations {
if let Err(e) = self.bus.write(buf).await {
op_res = Err(e);
break;
}
}
// On failure, it's important to still flush and deassert CS.
let flush_res = self.bus.flush().await;
let cs_res = self.cs.set_high();
op_res.map_err(ExclusiveDeviceError::Spi)?;
flush_res.map_err(ExclusiveDeviceError::Spi)?;
cs_res.map_err(ExclusiveDeviceError::Cs)?;
Ok(())
}
}
impl<Word: Copy + 'static, BUS, CS> SpiDevice<Word> for ExclusiveDevice<BUS, CS>
where
BUS: SpiBus<Word>,