|
1 | 1 | //! Blocking SPI API
|
| 2 | +use crate::spi::ErrorType; |
2 | 3 |
|
3 |
| -use super::ErrorType; |
| 4 | +/// SPI device base trait |
| 5 | +/// |
| 6 | +/// If you're writing a driver, require [`SpiDevice`] (read-write), [`SpiDeviceRead`], [`SpiDeviceWrite`] |
| 7 | +/// to specify the kind of access to the device. |
| 8 | +pub trait SpiDeviceBase: ErrorType { |
| 9 | + /// SPI Bus type for this device. |
| 10 | + type Bus: ErrorType; |
4 | 11 |
|
5 |
| -/// Blocking transfer with separate buffers |
6 |
| -pub trait Transfer<Word = u8>: ErrorType { |
7 |
| - /// Writes and reads simultaneously. `write` is written to the slave on MOSI and |
8 |
| - /// words received on MISO are stored in `read`. |
| 12 | + /// Start a transaction against the device. |
9 | 13 | ///
|
10 |
| - /// It is allowed for `read` and `write` to have different lengths, even zero length. |
11 |
| - /// The transfer runs for `max(read.len(), write.len())` words. If `read` is shorter, |
12 |
| - /// incoming words after `read` has been filled will be discarded. If `write` is shorter, |
13 |
| - /// the value of words sent in MOSI after all `write` has been sent is implementation-defined, |
14 |
| - /// typically `0x00`, `0xFF`, or configurable. |
15 |
| - fn transfer(&mut self, read: &mut [Word], write: &[Word]) -> Result<(), Self::Error>; |
| 14 | + /// - Locks the bus, asserting the Chip Select pin (if any). |
| 15 | + /// - Calls `f` with an exclusive reference to the bus, which can then be used to do transfers against the device. |
| 16 | + /// - Unlocks the bus, deasserting the Chip Select pin (if any). |
| 17 | + /// |
| 18 | + /// The lock mechanism is implementation-defined. The only requirement is it must prevent two |
| 19 | + /// transactions from executing concurrently against the same bus. Examples of implementations are: |
| 20 | + /// critical sections, blocking mutexes, or returning an error or panicking if the bus is already busy. |
| 21 | + fn transaction<R>(&mut self, f: impl FnOnce(&mut Self::Bus) -> R) -> Result<R, Self::Error>; |
16 | 22 | }
|
17 | 23 |
|
18 |
| -impl<T: Transfer<Word>, Word: Copy> Transfer<Word> for &mut T { |
19 |
| - fn transfer(&mut self, read: &mut [Word], write: &[Word]) -> Result<(), Self::Error> { |
20 |
| - T::transfer(self, read, write) |
| 24 | +impl<T: SpiDeviceBase> SpiDeviceBase for &mut T { |
| 25 | + type Bus = T::Bus; |
| 26 | + fn transaction<R>(&mut self, f: impl FnOnce(&mut Self::Bus) -> R) -> Result<R, Self::Error> { |
| 27 | + T::transaction(self, f) |
21 | 28 | }
|
22 | 29 | }
|
23 | 30 |
|
24 |
| -/// Blocking transfer with single buffer (in-place) |
25 |
| -pub trait TransferInplace<Word: Copy = u8>: ErrorType { |
26 |
| - /// Writes and reads simultaneously. The contents of `words` are |
27 |
| - /// written to the slave, and the received words are stored into the same |
28 |
| - /// `words` buffer, overwriting it. |
29 |
| - fn transfer_inplace(&mut self, words: &mut [Word]) -> Result<(), Self::Error>; |
30 |
| -} |
| 31 | +/// SPI device |
| 32 | +pub trait SpiDevice<Word: Copy = u8> = |
| 33 | + SpiDeviceBase where <Self as SpiDeviceBase>::Bus: SpiBus<Word>; |
31 | 34 |
|
32 |
| -impl<T: TransferInplace<Word>, Word: Copy> TransferInplace<Word> for &mut T { |
33 |
| - fn transfer_inplace(&mut self, words: &mut [Word]) -> Result<(), Self::Error> { |
34 |
| - T::transfer_inplace(self, words) |
35 |
| - } |
36 |
| -} |
| 35 | +/// SPI device with read-only access |
| 36 | +pub trait SpiDeviceRead<Word: Copy = u8> = |
| 37 | + SpiDeviceBase where <Self as SpiDeviceBase>::Bus: SpiBusRead<Word>; |
| 38 | + |
| 39 | +/// SPI device with write-only access |
| 40 | +pub trait SpiDeviceWrite<Word: Copy = u8> = |
| 41 | + SpiDeviceBase where <Self as SpiDeviceBase>::Bus: SpiBusWrite<Word>; |
37 | 42 |
|
38 |
| -/// Blocking read |
39 |
| -pub trait Read<Word: Copy = u8>: ErrorType { |
| 43 | +/// Read-only SPI bus |
| 44 | +pub trait SpiBusRead<Word: Copy = u8>: ErrorType { |
40 | 45 | /// Reads `words` from the slave.
|
41 | 46 | ///
|
42 | 47 | /// The word value sent on MOSI during reading is implementation-defined,
|
43 | 48 | /// typically `0x00`, `0xFF`, or configurable.
|
44 | 49 | fn read(&mut self, words: &mut [Word]) -> Result<(), Self::Error>;
|
45 | 50 | }
|
46 | 51 |
|
47 |
| -impl<T: Read<Word>, Word: Copy> Read<Word> for &mut T { |
| 52 | +impl<T: SpiBusRead<Word>, Word: Copy> SpiBusRead<Word> for &mut T { |
48 | 53 | fn read(&mut self, words: &mut [Word]) -> Result<(), Self::Error> {
|
49 | 54 | T::read(self, words)
|
50 | 55 | }
|
51 | 56 | }
|
52 | 57 |
|
53 |
| -/// Blocking write |
54 |
| -pub trait Write<Word: Copy = u8>: ErrorType { |
| 58 | +/// Write-only SPI bus |
| 59 | +pub trait SpiBusWrite<Word: Copy = u8>: ErrorType { |
55 | 60 | /// Writes `words` to the slave, ignoring all the incoming words
|
56 | 61 | fn write(&mut self, words: &[Word]) -> Result<(), Self::Error>;
|
57 | 62 | }
|
58 | 63 |
|
59 |
| -impl<T: Write<Word>, Word: Copy> Write<Word> for &mut T { |
| 64 | +impl<T: SpiBusWrite<Word>, Word: Copy> SpiBusWrite<Word> for &mut T { |
60 | 65 | fn write(&mut self, words: &[Word]) -> Result<(), Self::Error> {
|
61 | 66 | T::write(self, words)
|
62 | 67 | }
|
63 | 68 | }
|
64 | 69 |
|
65 |
| -/// Blocking write (iterator version) |
66 |
| -pub trait WriteIter<Word: Copy = u8>: ErrorType { |
67 |
| - /// Writes `words` to the slave, ignoring all the incoming words |
68 |
| - fn write_iter<WI>(&mut self, words: WI) -> Result<(), Self::Error> |
69 |
| - where |
70 |
| - WI: IntoIterator<Item = Word>; |
71 |
| -} |
72 |
| - |
73 |
| -impl<T: WriteIter<Word>, Word: Copy> WriteIter<Word> for &mut T { |
74 |
| - fn write_iter<WI>(&mut self, words: WI) -> Result<(), Self::Error> |
75 |
| - where |
76 |
| - WI: IntoIterator<Item = Word>, |
77 |
| - { |
78 |
| - T::write_iter(self, words) |
79 |
| - } |
80 |
| -} |
| 70 | +/// Read-write SPI bus |
| 71 | +pub trait SpiBus<Word: Copy = u8>: SpiBusRead<Word> + SpiBusWrite<Word> { |
| 72 | + /// Writes and reads simultaneously. `write` is written to the slave on MOSI and |
| 73 | + /// words received on MISO are stored in `read`. |
| 74 | + /// |
| 75 | + /// It is allowed for `read` and `write` to have different lengths, even zero length. |
| 76 | + /// The transfer runs for `max(read.len(), write.len())` words. If `read` is shorter, |
| 77 | + /// incoming words after `read` has been filled will be discarded. If `write` is shorter, |
| 78 | + /// the value of words sent in MOSI after all `write` has been sent is implementation-defined, |
| 79 | + /// typically `0x00`, `0xFF`, or configurable. |
| 80 | + fn transfer(&mut self, read: &mut [Word], write: &[Word]) -> Result<(), Self::Error>; |
81 | 81 |
|
82 |
| -/// Operation for transactional SPI trait |
83 |
| -/// |
84 |
| -/// This allows composition of SPI operations into a single bus transaction |
85 |
| -#[derive(Debug, PartialEq)] |
86 |
| -pub enum Operation<'a, Word: 'static + Copy = u8> { |
87 |
| - /// Read data into the provided buffer. |
88 |
| - Read(&'a mut [Word]), |
89 |
| - /// Write data from the provided buffer, discarding read data |
90 |
| - Write(&'a [Word]), |
91 |
| - /// Write data out while reading data into the provided buffer |
92 |
| - Transfer(&'a mut [Word], &'a [Word]), |
93 |
| - /// Write data out while reading data into the provided buffer |
94 |
| - TransferInplace(&'a mut [Word]), |
| 82 | + /// Writes and reads simultaneously. The contents of `words` are |
| 83 | + /// written to the slave, and the received words are stored into the same |
| 84 | + /// `words` buffer, overwriting it. |
| 85 | + fn transfer_in_place(&mut self, words: &mut [Word]) -> Result<(), Self::Error>; |
95 | 86 | }
|
96 | 87 |
|
97 |
| -/// Transactional trait allows multiple actions to be executed |
98 |
| -/// as part of a single SPI transaction |
99 |
| -pub trait Transactional<Word: 'static + Copy = u8>: ErrorType { |
100 |
| - /// Execute the provided transactions |
101 |
| - fn exec<'a>(&mut self, operations: &mut [Operation<'a, Word>]) -> Result<(), Self::Error>; |
102 |
| -} |
| 88 | +impl<T: SpiBus<Word>, Word: Copy> SpiBus<Word> for &mut T { |
| 89 | + fn transfer(&mut self, read: &mut [Word], write: &[Word]) -> Result<(), Self::Error> { |
| 90 | + T::transfer(self, read, write) |
| 91 | + } |
103 | 92 |
|
104 |
| -impl<T: Transactional<Word>, Word: 'static + Copy> Transactional<Word> for &mut T { |
105 |
| - fn exec<'a>(&mut self, operations: &mut [Operation<'a, Word>]) -> Result<(), Self::Error> { |
106 |
| - T::exec(self, operations) |
| 93 | + fn transfer_in_place(&mut self, words: &mut [Word]) -> Result<(), Self::Error> { |
| 94 | + T::transfer_in_place(self, words) |
107 | 95 | }
|
108 | 96 | }
|
0 commit comments