driver_pal/
lib.rs

1//! Embedded SPI helper package
2//! This defines a higher level `Transactional` SPI interface, as well as an SPI `Transaction` enumeration
3//! that more closely map to the common uses of SPI peripherals, as well as some other common driver helpers.
4//!
5//! An `driver_pal::wrapper::Wrapper` type is provided to wrap existing SPI implementations in this
6//! `driver_pal::Transactional` interface, as well as a set of helpers for C compatibility enabled with
7//! the `compat` feature, and a basic mocking adaptor enabled with the `mock` feature.
8
9#![cfg_attr(not(feature = "hal"), no_std)]
10
11#[macro_use]
12extern crate log;
13
14extern crate embedded_hal;
15
16#[cfg(feature = "mock")]
17extern crate std;
18
19#[cfg(feature = "mock")]
20pub mod mock;
21
22#[cfg(feature = "ffi")]
23extern crate libc;
24
25#[cfg(feature = "ffi")]
26pub mod ffi;
27
28#[cfg(feature = "serde")]
29extern crate serde;
30
31#[cfg(feature = "toml")]
32extern crate toml;
33
34#[cfg(feature = "simplelog")]
35extern crate simplelog;
36
37#[cfg(feature = "hal-linux")]
38extern crate linux_embedded_hal;
39
40#[cfg(feature = "hal-cp2130")]
41extern crate driver_cp2130;
42
43#[cfg(feature = "hal")]
44pub mod hal;
45
46pub mod wrapper;
47
48/// ManagedChipSelect marker trait indicates CS is managed by the driver
49pub trait ManagedChipSelect {}
50
51/// HAL trait abstracts commonly required functions for SPI peripherals
52pub trait Hal<E>:
53    PrefixWrite<Error = E>
54    + PrefixRead<Error = E>
55    + embedded_hal::spi::SpiDevice<u8, Error = E>
56    + Busy<Error = E>
57    + Ready<Error = E>
58    + Reset<Error = E>
59    + embedded_hal::delay::DelayNs
60{
61}
62
63/// Default HAL trait impl over component traits
64impl<T, E> Hal<E> for T where
65    T: PrefixWrite<Error = E>
66        + PrefixRead<Error = E>
67        + embedded_hal::spi::SpiDevice<u8, Error = E>
68        + Busy<Error = E>
69        + Ready<Error = E>
70        + Reset<Error = E>
71        + embedded_hal::delay::DelayNs
72{
73}
74
75/// PrefixRead trait provides a higher level, write then read function
76pub trait PrefixRead {
77    type Error;
78
79    /// Read writes the prefix buffer then reads into the input buffer
80    /// Note that the values of the input buffer will also be output, because, SPI...
81    fn prefix_read(&mut self, prefix: &[u8], data: &mut [u8]) -> Result<(), Self::Error>;
82}
83
84/// PrefixWrite trait provides higher level, writye then write function
85pub trait PrefixWrite {
86    type Error;
87
88    /// Write writes the prefix buffer then writes the output buffer
89    fn prefix_write(&mut self, prefix: &[u8], data: &[u8]) -> Result<(), Self::Error>;
90}
91
92/// Transaction enum defines possible SPI transactions
93/// Re-exported from embedded-hal
94pub type Transaction<'a> = embedded_hal::spi::Operation<'a, u8>;
95
96/// Chip Select trait for peripherals supporting manual chip select
97pub trait ChipSelect {
98    type Error;
99
100    /// Set the cs pin state if available
101    fn set_cs(&mut self, state: PinState) -> Result<(), Self::Error>;
102}
103
104/// Busy trait for peripherals that support a busy signal
105pub trait Busy {
106    type Error;
107
108    /// Returns the busy pin state if bound
109    fn get_busy(&mut self) -> Result<PinState, Self::Error>;
110}
111
112/// Reset trait for peripherals that have a reset or shutdown pin
113pub trait Reset {
114    type Error;
115
116    /// Set the reset pin state if available
117    fn set_reset(&mut self, state: PinState) -> Result<(), Self::Error>;
118}
119
120/// Ready trait for peripherals that support a ready signal (or IRQ)
121pub trait Ready {
122    type Error;
123
124    /// Returns the busy pin state if bound
125    fn get_ready(&mut self) -> Result<PinState, Self::Error>;
126}
127
128/// Error type combining SPI and Pin errors for utility
129#[derive(Debug, Clone, PartialEq)]
130pub enum Error<SpiError, PinError> {
131    Spi(SpiError),
132    Pin(PinError),
133    Aborted,
134}
135
136impl<SpiError, PinError> embedded_hal::spi::Error for Error<SpiError, PinError>
137where
138    SpiError: core::fmt::Debug,
139    PinError: core::fmt::Debug,
140{
141    fn kind(&self) -> embedded_hal::spi::ErrorKind {
142        embedded_hal::spi::ErrorKind::Other
143    }
144}
145
146impl<SpiError, PinError> embedded_hal::digital::Error for Error<SpiError, PinError>
147where
148    SpiError: core::fmt::Debug,
149    PinError: core::fmt::Debug,
150{
151    fn kind(&self) -> embedded_hal::digital::ErrorKind {
152        embedded_hal::digital::ErrorKind::Other
153    }
154}
155
156/// PinState enum used for busy indication
157#[derive(Debug, Clone, PartialEq)]
158pub enum PinState {
159    Low,
160    High,
161}
162
163use embedded_hal::spi::{Operation, SpiDevice};
164
165/// Automatic `driver_pal::PrefixWrite` implementation for objects implementing `embedded_hal::spi::SpiDevice`.
166impl<T> PrefixWrite for T
167where
168    T: SpiDevice<u8>,
169    <T as embedded_hal::spi::ErrorType>::Error: core::fmt::Debug,
170{
171    type Error = <T as embedded_hal::spi::ErrorType>::Error;
172
173    /// Write data with the specified prefix
174    fn prefix_write(&mut self, prefix: &[u8], data: &[u8]) -> Result<(), Self::Error> {
175        let mut ops = [Operation::Write(prefix), Operation::Write(data)];
176
177        self.transaction(&mut ops)?;
178
179        Ok(())
180    }
181}
182
183/// Automatic `driver_pal::PrefixRead` implementation for objects implementing `embedded_hal::spi::SpiDevice`.
184impl<T> PrefixRead for T
185where
186    T: SpiDevice<u8>,
187    <T as embedded_hal::spi::ErrorType>::Error: core::fmt::Debug,
188{
189    type Error = <T as embedded_hal::spi::ErrorType>::Error;
190
191    /// Read data with the specified prefix
192    fn prefix_read<'a>(&mut self, prefix: &[u8], data: &'a mut [u8]) -> Result<(), Self::Error> {
193        let mut ops = [Operation::Write(prefix), Operation::TransferInPlace(data)];
194
195        self.transaction(&mut ops)?;
196
197        Ok(())
198    }
199}