Skip to main content

device_driver/
lib.rs

1#![allow(async_fn_in_trait)]
2#![cfg_attr(not(test), no_std)]
3#![warn(missing_docs)]
4#![doc = include_str!(concat!("../", env!("CARGO_PKG_README")))]
5
6use core::fmt::{Debug, Display};
7use core::marker::PhantomData;
8
9mod buffer;
10mod command;
11mod fieldset;
12mod register;
13
14mod repeats;
15
16pub use buffer::*;
17pub use command::*;
18pub use fieldset::*;
19pub use register::*;
20
21pub use repeats::*;
22
23#[doc(hidden)]
24pub mod ops;
25
26#[cfg(feature = "macros")]
27pub use device_driver_macros::*;
28
29/// Trait implemented on every generated block/device.
30pub trait Block: Sized {
31    /// The interface used by the block
32    type Interface;
33    /// The register address type
34    type RegisterAddressType: Address;
35    /// The command address type
36    type CommandAddressType: Address;
37    /// The buffer address type
38    type BufferAddressType: Address;
39    /// The address mode of the registers in this block
40    type RegisterAddressMode;
41
42    /// Get a reference to the inner interface.
43    /// With it you can do out-of-band operations that aren't defined in the generated code.
44    fn interface(&mut self) -> &mut Self::Interface;
45
46    /// Start a bulk-read transaction
47    ///
48    /// You can chain reads by calling [`register::BulkRegisterOperation::with`].
49    /// Once chained, call [`register::BulkRegisterOperation::execute`] to perform the read.
50    fn bulk_read(
51        &mut self,
52    ) -> register::BulkRegisterOperation<
53        '_,
54        Self,
55        <Self::Interface as RegisterInterfaceBase>::AddressType,
56        (),
57        RO,
58    >
59    where
60        Self::Interface: RegisterInterfaceBase,
61        Self::RegisterAddressMode: AddressMode,
62    {
63        register::BulkRegisterOperation {
64            block: self,
65            start_address: None,
66            next_address: None,
67            field_sets: (),
68            _phantom: PhantomData,
69        }
70    }
71
72    /// Start a bulk-write transaction
73    ///
74    /// You can chain writes by calling [`register::BulkRegisterOperation::with`].
75    /// Once chained, call [`register::BulkRegisterOperation::execute`] to perform the write.
76    fn bulk_write(
77        &mut self,
78    ) -> register::BulkRegisterOperation<
79        '_,
80        Self,
81        <Self::Interface as RegisterInterfaceBase>::AddressType,
82        (),
83        WO,
84    >
85    where
86        Self::Interface: RegisterInterfaceBase,
87        Self::RegisterAddressMode: AddressMode,
88    {
89        register::BulkRegisterOperation {
90            block: self,
91            start_address: None,
92            next_address: None,
93            field_sets: (),
94            _phantom: PhantomData,
95        }
96    }
97
98    /// Start a bulk-modify transaction
99    ///
100    /// You can chain modifies by calling [`register::BulkRegisterOperation::with`].
101    /// Once chained, call [`register::BulkRegisterOperation::execute`] to perform the modify.
102    fn bulk_modify(
103        &mut self,
104    ) -> register::BulkRegisterOperation<
105        '_,
106        Self,
107        <Self::Interface as RegisterInterfaceBase>::AddressType,
108        (),
109        RW,
110    >
111    where
112        Self::Interface: RegisterInterfaceBase,
113        Self::RegisterAddressMode: AddressMode,
114    {
115        register::BulkRegisterOperation {
116            block: self,
117            start_address: None,
118            next_address: None,
119            field_sets: (),
120            _phantom: PhantomData,
121        }
122    }
123}
124
125/// Value representing the byte order
126#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
127#[cfg_attr(feature = "defmt", derive(defmt::Format))]
128pub enum ByteOrder {
129    /// Little endian
130    LE,
131    /// Big endian
132    BE,
133}
134
135/// The error returned by the generated [`TryFrom`]s.
136/// It contains the base type of the enum.
137#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
138#[cfg_attr(feature = "defmt", derive(defmt::Format))]
139pub struct ConversionError<T> {
140    /// The value of the thing that was tried to be converted
141    pub source: T,
142    /// The name of the target type
143    pub target: &'static str,
144}
145
146impl<T: Display> Display for ConversionError<T> {
147    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
148        write!(
149            f,
150            "Could not convert value from `{}` to type `{}`",
151            self.source, self.target
152        )
153    }
154}
155
156impl<T: Display + Debug> core::error::Error for ConversionError<T> {}
157
158#[doc(hidden)]
159pub struct WO;
160#[doc(hidden)]
161pub struct RO;
162#[doc(hidden)]
163pub struct RW;
164
165#[doc(hidden)]
166pub trait ReadCapability {}
167#[doc(hidden)]
168pub trait WriteCapability {}
169
170impl WriteCapability for WO {}
171
172impl ReadCapability for RO {}
173
174impl WriteCapability for RW {}
175impl ReadCapability for RW {}
176
177trait SealedAddress {}
178
179/// A trait implemented for the types that can be used as an address
180#[expect(private_bounds, reason = "sealed on purpose")]
181#[cfg(feature = "defmt")]
182pub trait Address: Copy + Eq + Display + Debug + defmt::Format + SealedAddress {
183    #[doc(hidden)]
184    const ZERO: Self;
185    #[doc(hidden)]
186    fn add(self, val: i32) -> Self;
187}
188/// A trait implemented for the types that can be used as an address
189#[expect(private_bounds, reason = "sealed on purpose")]
190#[cfg(not(feature = "defmt"))]
191pub trait Address: Copy + Eq + Display + Debug + SealedAddress {
192    #[doc(hidden)]
193    const ZERO: Self;
194    #[doc(hidden)]
195    fn add(self, val: i32) -> Self;
196}
197
198impl SealedAddress for u8 {}
199impl Address for u8 {
200    const ZERO: Self = 0;
201    fn add(self, val: i32) -> Self {
202        (self as i32 + val).try_into().unwrap()
203    }
204}
205impl SealedAddress for u16 {}
206impl Address for u16 {
207    const ZERO: Self = 0;
208    fn add(self, val: i32) -> Self {
209        (self as i32 + val).try_into().unwrap()
210    }
211}
212impl SealedAddress for u32 {}
213impl Address for u32 {
214    const ZERO: Self = 0;
215    fn add(self, val: i32) -> Self {
216        self.checked_add_signed(val).unwrap()
217    }
218}
219impl SealedAddress for u64 {}
220impl Address for u64 {
221    const ZERO: Self = 0;
222    fn add(self, val: i32) -> Self {
223        self.checked_add_signed(val as i64).unwrap()
224    }
225}
226impl SealedAddress for i8 {}
227impl Address for i8 {
228    const ZERO: Self = 0;
229    fn add(self, val: i32) -> Self {
230        (self as i32 + val).try_into().unwrap()
231    }
232}
233impl SealedAddress for i16 {}
234impl Address for i16 {
235    const ZERO: Self = 0;
236    fn add(self, val: i32) -> Self {
237        (self as i32 + val).try_into().unwrap()
238    }
239}
240impl SealedAddress for i32 {}
241impl Address for i32 {
242    const ZERO: Self = 0;
243    fn add(self, val: i32) -> Self {
244        self + val
245    }
246}
247impl SealedAddress for i64 {}
248impl Address for i64 {
249    const ZERO: Self = 0;
250    fn add(self, val: i32) -> Self {
251        self + val as i64
252    }
253}
254
255#[diagnostic::on_unimplemented(
256    message = "no `register-address-mode` is specified in the driver, so bulk register operations are not possible",
257    label = "not supported for this driver",
258    note = "if you are the author of the driver, specify `register-address-mode` in the device config to enable this feature if the device supports it",
259    note = "not all devices support this feature"
260)]
261#[doc(hidden)]
262pub trait AddressMode {
263    #[doc(hidden)]
264    fn next_address<A: Address>(current_address: A, current_size: usize) -> A;
265}
266
267#[doc(hidden)]
268pub struct MappedAddressMode;
269impl AddressMode for MappedAddressMode {
270    #[inline]
271    fn next_address<A: Address>(current_address: A, current_size: usize) -> A {
272        // Current size can be cast to i32 fine because this is the size of a fieldset
273        // Fieldsets are limited to 1MB in size
274
275        current_address.add(current_size as i32)
276    }
277}
278
279#[doc(hidden)]
280pub struct IndexedAddressMode;
281impl AddressMode for IndexedAddressMode {
282    #[inline]
283    fn next_address<A: Address>(current_address: A, _current_size: usize) -> A {
284        current_address.add(1)
285    }
286}