embedded_interfaces/commands/
mod.rs

1use crate::{MaybeBitdumpFormattable, TransportError};
2
3pub mod i2c;
4pub mod spi;
5pub mod unsupported_executor;
6
7/// A base trait for all executors
8pub trait Executor {
9    /// The command type used by this executor
10    type Command: Command;
11    /// An error type for executor specific errors
12    type Error: core::fmt::Debug;
13}
14
15/// The basis trait for all commands. A command represents one or more transactions that belong
16/// together and have to occur in a specific order and/or with a specific timing.
17///
18/// Commands can both have input and output data.
19pub trait Command {
20    /// The input data type
21    type In: bytemuck::Pod + MaybeBitdumpFormattable;
22    /// The output data type
23    type Out: bytemuck::Pod + bytemuck::Zeroable + MaybeBitdumpFormattable;
24
25    /// A common error type which can represent all associated executor errors
26    type ExecutorError: core::fmt::Debug;
27    /// The SPI executor that should be used for this register. If the device doesn't support SPI
28    /// communication, this can be ignored.
29    #[cfg(all(feature = "sync", not(feature = "async")))]
30    type SpiExecutor: spi::ExecutorSync<Command = Self, Error = Self::ExecutorError>;
31    #[cfg(all(not(feature = "sync"), feature = "async"))]
32    type SpiExecutor: spi::ExecutorAsync<Command = Self, Error = Self::ExecutorError>;
33    #[cfg(all(feature = "sync", feature = "async"))]
34    type SpiExecutor: spi::ExecutorSync<Command = Self, Error = Self::ExecutorError>
35        + spi::ExecutorAsync<Command = Self, Error = Self::ExecutorError>;
36    /// The I2C executor that should be used for this register. If the device doesn't support I2C
37    /// communication, this can be ignored.
38    #[cfg(all(feature = "sync", not(feature = "async")))]
39    type I2cExecutor: i2c::ExecutorSync<Command = Self, Error = Self::ExecutorError>;
40    #[cfg(all(not(feature = "sync"), feature = "async"))]
41    type I2cExecutor: i2c::ExecutorAsync<Command = Self, Error = Self::ExecutorError>;
42    #[cfg(all(feature = "sync", feature = "async"))]
43    type I2cExecutor: i2c::ExecutorSync<Command = Self, Error = Self::ExecutorError>
44        + i2c::ExecutorAsync<Command = Self, Error = Self::ExecutorError>;
45}
46
47/// A trait that is implemented by any bus interface and allows devices with commands to share
48/// commands executor implementations independent of the actual interface in use.
49#[maybe_async_cfg::maybe(
50    idents(hal(sync = "embedded_hal", async = "embedded_hal_async")),
51    sync(feature = "sync"),
52    async(feature = "async")
53)]
54#[allow(async_fn_in_trait)]
55pub trait CommandInterface {
56    /// A type representing errors on the underlying bus
57    type BusError: core::fmt::Debug;
58
59    /// Executes the given command through this interface
60    async fn execute<C, D>(
61        &mut self,
62        delay: &mut D,
63        input: C::In,
64    ) -> Result<C::Out, TransportError<C::ExecutorError, Self::BusError>>
65    where
66        D: hal::delay::DelayNs,
67        C: Command;
68}
69
70#[macro_export]
71macro_rules! define_executor {
72    ($executor:ident, $command_trait:ident, $error_type:ty) => {
73        #[doc = "The executor for any [`"]
74        #[doc = stringify!($command_trait)]
75        #[doc = "`]"]
76        pub struct $executor<C: $command_trait + ?Sized> {
77            _marker: PhantomData<C>,
78        }
79
80        impl<C: $command_trait> embedded_interfaces::commands::Executor for $executor<C> {
81            type Error = $error_type;
82            type Command = C;
83        }
84    };
85}