embedded_registers/spi/
mod.rs

1pub mod codecs;
2
3use core::{any::TypeId, marker::PhantomData};
4
5use codecs::NoCodec;
6
7use crate::{ReadableRegister, WritableRegister};
8
9/// Represents a trait for SPI codecs. These are responsible to perform
10/// writes and reads to registers, given the register address and
11/// the raw data. Different devices can have different ways to encode
12/// the desired address, R/W bit location, continuous-read mode and more.
13#[maybe_async_cfg::maybe(
14    idents(hal(sync = "embedded_hal", async = "embedded_hal_async")),
15    sync(feature = "sync"),
16    async(feature = "async")
17)]
18#[allow(async_fn_in_trait)]
19pub trait Codec: 'static {
20    /// Read this register from the given SPI interface/device.
21    async fn read_register<R, I>(interface: &mut I) -> Result<R, I::Error>
22    where
23        R: ReadableRegister,
24        I: hal::spi::r#SpiDevice;
25
26    /// Write this register to the given SPI interface/device.
27    async fn write_register<R, I>(interface: &mut I, register: impl AsRef<R>) -> Result<(), I::Error>
28    where
29        R: WritableRegister,
30        I: hal::spi::r#SpiDevice;
31}
32
33#[maybe_async_cfg::maybe(
34    idents(hal(sync = "embedded_hal", async = "embedded_hal_async"), Codec),
35    sync(feature = "sync"),
36    async(feature = "async")
37)]
38/// This represents an SPI device on an SPI bus.
39pub struct SpiDevice<I, C>
40where
41    I: hal::spi::r#SpiDevice,
42    C: Codec,
43{
44    /// Spi interface
45    pub interface: I,
46    /// The default codec used to interface with registers that don't explicitly specify a codec
47    /// themselves. Usually this is a simple codec designating a bit for R/W and a bit-range
48    /// for the register address. See implementors of the Codec trait for more information on
49    /// available codecs.
50    default_codec: PhantomData<C>,
51}
52
53#[maybe_async_cfg::maybe(
54    idents(hal(sync = "embedded_hal", async = "embedded_hal_async"), Codec),
55    sync(feature = "sync"),
56    async(feature = "async")
57)]
58impl<I, C> SpiDevice<I, C>
59where
60    I: hal::spi::r#SpiDevice,
61    C: Codec,
62{
63    /// Create a new I2cDevice from an interface while specifying the default codec.
64    pub fn new(interface: I) -> Self {
65        Self {
66            interface,
67            default_codec: Default::default(),
68        }
69    }
70}
71
72#[maybe_async_cfg::maybe(
73    idents(hal(sync = "embedded_hal", async = "embedded_hal_async"), Codec, RegisterInterface),
74    sync(feature = "sync"),
75    async(feature = "async")
76)]
77impl<I, C> crate::RegisterInterface for SpiDevice<I, C>
78where
79    I: hal::spi::r#SpiDevice,
80    C: Codec,
81{
82    type Error = I::Error;
83
84    /// Read this register from this spi device using the codec
85    /// specified by the register (if any) or otherwise the
86    /// default codec of the device.
87    #[inline]
88    async fn read_register<R>(&mut self) -> Result<R, I::Error>
89    where
90        R: ReadableRegister,
91    {
92        if TypeId::of::<R::SpiCodec>() == TypeId::of::<NoCodec>() {
93            C::read_register::<R, _>(&mut self.interface).await
94        } else {
95            <R::SpiCodec as Codec>::read_register::<R, _>(&mut self.interface).await
96        }
97    }
98
99    /// Write this register to this spi device using the codec
100    /// specified by the register (if any) or otherwise the
101    /// default codec of the device.
102    #[inline]
103    async fn write_register<R>(&mut self, register: impl AsRef<R>) -> Result<(), I::Error>
104    where
105        R: WritableRegister,
106    {
107        if TypeId::of::<R::SpiCodec>() == TypeId::of::<NoCodec>() {
108            C::write_register(&mut self.interface, register).await
109        } else {
110            <R::SpiCodec as Codec>::write_register(&mut self.interface, register).await
111        }
112    }
113}