mcan_core/
lib.rs

1#![no_std]
2#![warn(missing_docs)]
3
4//! `mcan-core` provides a set of essential abstractions that serves as a thin
5//! integration layer between the platform independent [`mcan`] crate and
6//! platform specific HAL crates (in documentation also referred to as _target
7//! HALs_).
8//!
9//! Traits from this crate are not supposed to be implemented by the
10//! application developer; implementations should be provided by target HALs.
11//!
12//! Integrators of this crate into any given target HAL are responsible for
13//! soundness of trait implementations and conforming to their respective safety
14//! prerequisites.
15//!
16//! [`mcan`]: <https://docs.rs/crate/mcan/>
17
18pub use fugit;
19
20/// Trait representing CAN peripheral identity
21///
22/// Types implementing this trait are expected to be used as a marker types that
23/// serve the purpose of identifying specific instances of CAN peripherals
24/// available on the platform (as there might be more than one). It only conveys
25/// *where* the CAN peripheral HW register is located, not necessarily that it
26/// can be accessed. The latter is expressed by the [`Dependencies`] trait.
27///
28/// It is also useful for associating [`Dependencies`] with specific [`CanId`]
29/// and setting up additional type constraints preventing application developers
30/// from constructing CAN abstractions with incompatible sets of dependencies.
31///
32/// More details in [`Dependencies`] documentation.
33///
34/// # Safety
35/// `CanId::ADDRESS` points to the start of a valid HW register of a CAN
36/// peripheral
37///
38/// # Examples
39/// ```no_run
40/// use mcan_core::CanId;
41///
42/// pub enum Can0 {}
43///
44/// unsafe impl CanId for Can0 {
45///     const ADDRESS: *const () = 0xDEAD0000 as *const _;
46/// }
47///
48/// pub enum Can1 {}
49///
50/// unsafe impl CanId for Can1 {
51///     const ADDRESS: *const () = 0xBEEF0000 as *const _;
52/// }
53/// ```
54pub unsafe trait CanId {
55    /// Static address of HW register controlling corresponding CAN peripheral
56    const ADDRESS: *const ();
57}
58
59/// Trait representing CAN peripheral dependencies
60///
61/// Structs implementing [`Dependencies`] should
62/// - enclose all object representable dependencies of [`CanId`] and release
63///   them upon destruction
64/// - be constructible only when it is safe and sound to interact with the CAN
65///   peripheral (respective clocks and pins have been already configured)
66/// - be a singleton (only a single instance of [`Dependencies`] for a specific
67///   [`CanId`] must exist at the same time)
68///
69/// in order to prevent aliasing and guarantee that high level abstractions
70/// provided by [`mcan`] are sole owners of the peripheral.
71///
72/// Depending on target HAL API capabilities this can be assured either at
73/// compile-time by type constraints and/or by fallible [`Dependencies`] struct
74/// construction.
75///
76/// # Safety
77/// While the [`Dependencies`] type instance exists
78/// - Start address of the eligible memory region for `Message RAM` allocation
79///   must not change
80/// - CAN related clocks must not change
81/// - CAN related pins modes must not change
82/// - The HW register must be neither safely accessible by the application
83///   developer nor accessed in other parts of the target HAL
84///
85/// # Example
86/// ```no_run
87/// // This is just an example implementation, it is up to the `mcan`
88/// // integrator how to guarantee the soundness of `mcan` usage
89/// // with the target HAL API.
90/// # mod pac {
91/// #     pub struct CAN0;
92/// #     impl CAN0 {
93/// #         const PTR: *const u8 = 0xDEAD0000 as *const _;
94/// #     }
95/// #     pub struct CAN1;
96/// #     impl CAN1 {
97/// #         const PTR: *const u8 = 0xBEEF0000 as *const _;
98/// #     }
99/// # }
100/// # mod hal {
101/// #     pub mod identities {
102/// #         pub enum Can0 {}
103/// #         pub enum Can1 {}
104/// #     }
105/// # }
106/// # trait PeripheralClockId {}
107/// # struct PeripheralClock<ID: PeripheralClockId> {
108/// #     __: core::marker::PhantomData<ID>
109/// # }
110/// # impl<ID: PeripheralClockId> PeripheralClock<ID> {
111/// #     fn frequency(&self) -> HertzU32 {
112/// #         HertzU32::from_raw(123)
113/// #     }
114/// # }
115/// # struct HostClockToken;
116/// # impl HostClockToken {
117/// #     fn frequency(&self) -> HertzU32 {
118/// #         HertzU32::from_raw(123)
119/// #     }
120/// # }
121/// # struct HostClock;
122/// # impl HostClock {
123/// #     fn register_new_user(&mut self) -> HostClockToken { HostClockToken }
124/// #     fn unregister_user(&mut self, _: HostClockToken) -> Result<(), ()> { Ok(()) }
125/// # }
126/// # struct Pin<ID, MODE> {
127/// #     __: core::marker::PhantomData<(ID, MODE)>
128/// # }
129/// # struct PA22;
130/// # struct PA23;
131/// # struct PB12;
132/// # struct PB13;
133/// # struct AlternateI;
134/// # struct AlternateH;
135/// use fugit::HertzU32;
136/// use mcan_core::CanId;
137///
138/// // In this example, `CanId` types are proper zero-sized marker
139/// // types and one can observe that information about HW register
140/// // addressing is somewhat duplicated between `pac::CAN{0, 1}`
141/// // and `Can{0, 1}`.
142/// //
143/// // The HAL design in this example assumes that a marker/identity type
144/// // is reused in related contexts allowing for elaborate type constraints
145/// // between abstractions from different modules (like peripheral clock
146/// // for CAN and its HW register).
147/// //
148/// // In a simpler setup, `CanId` could be just implemented by the low
149/// // level CAN type from PAC.
150/// unsafe impl CanId for hal::identities::Can0 {
151///     const ADDRESS: *const () = 0xDEAD0000 as *const _;
152/// }
153///
154/// unsafe impl CanId for hal::identities::Can1 {
155///     const ADDRESS: *const () = 0xBEEF0000 as *const _;
156/// }
157///
158/// pub struct Dependencies<ID: PeripheralClockId, RX, TX, CAN> {
159///     // This example design assumes runtime tracking of host clock
160///     // users à la reference counting. `HostClock` should not be
161///     // reconfigurable while having `> 0` users.
162///     host_clock_token: HostClockToken,
163///     // Clock object representing the CAN specific asynchronous clock
164///     can_peripheral_clock: PeripheralClock<ID>,
165///     // Opaque field reserved for RX pin
166///     rx: RX,
167///     // Opaque field reserved for TX pin
168///     tx: TX,
169///     // Opaque field reserved for the CAN HW register type (from PAC)
170///     can: CAN,
171/// }
172///
173/// impl<ID: PeripheralClockId, RX, TX, CAN> Dependencies<ID, RX, TX, CAN> {
174///     // Constructor that additionally registers a new user of the host clock
175///     pub fn new<S>(
176///         host_clock: &mut HostClock,
177///         can_peripheral_clock: PeripheralClock<ID>,
178///         rx: RX,
179///         tx: TX,
180///         can: CAN,
181///     ) -> Self
182///     {
183///         Self {
184///             host_clock_token: host_clock.register_new_user(),
185///             can_peripheral_clock,
186///             rx,
187///             tx,
188///             can,
189///         }
190///     }
191///     // Destructor that additionally unregisters from the host clock
192///     pub fn free(self, host_clock: &mut HostClock) -> (PeripheralClock<ID>, RX, TX, CAN)
193///     {
194///         let Self {
195///             host_clock_token,
196///             can_peripheral_clock,
197///             rx,
198///             tx,
199///             can,
200///             ..
201///         } = self;
202///         host_clock.unregister_user(host_clock_token).expect("Host clock has invalid amount of users!");
203///         (can_peripheral_clock, rx, tx, can)
204///     }
205/// }
206///
207/// // Trait is only implemented for valid combinations of dependencies.
208/// unsafe impl<ID, RX, TX, CAN> mcan_core::Dependencies<ID> for Dependencies<ID, RX, TX, CAN>
209/// where
210///     ID: CanId + PeripheralClockId,
211///     RX: RxPin<ValidFor = ID>,
212///     TX: TxPin<ValidFor = ID>,
213///     CAN: OwnedPeripheral<Represents = ID>,
214/// {
215///     fn eligible_message_ram_start(&self) -> *const () {
216///         0x2000_0000 as _
217///     }
218///
219///     fn host_clock(&self) -> HertzU32 {
220///         self.host_clock_token.frequency()
221///     }
222///
223///     fn can_clock(&self) -> HertzU32 {
224///         self.can_peripheral_clock.frequency()
225///     }
226/// }
227///
228/// // Trait introduced in order to get 1:1 mapping from the identity type to the PAC type.
229/// //
230/// // Again, in a simpler setup, `CanId` could just be implemented by the low
231/// // level CAN type from PAC.
232/// trait OwnedPeripheral {
233///     type Represents: CanId;
234/// }
235///
236/// impl OwnedPeripheral for pac::CAN0 {
237///     type Represents = hal::identities::Can0;
238/// }
239///
240/// impl OwnedPeripheral for pac::CAN1 {
241///     type Represents = hal::identities::Can1;
242/// }
243///
244/// trait RxPin {
245///     type ValidFor: CanId;
246/// }
247///
248/// trait TxPin {
249///     type ValidFor: CanId;
250/// }
251///
252/// impl RxPin for Pin<PA23, AlternateI> {
253///     type ValidFor = hal::identities::Can0;
254/// }
255///
256/// impl TxPin for Pin<PA22, AlternateI> {
257///     type ValidFor = hal::identities::Can0;
258/// }
259///
260/// impl RxPin for Pin<PB13, AlternateH> {
261///     type ValidFor = hal::identities::Can1;
262/// }
263///
264/// impl TxPin for Pin<PB12, AlternateH> {
265///     type ValidFor = hal::identities::Can1;
266/// }
267/// ```
268///
269/// [`mcan`]: <https://docs.rs/crate/mcan/>
270pub unsafe trait Dependencies<Id: CanId> {
271    /// Pointer to the start of memory that can be used for `Message RAM`.
272    ///
273    /// The two least significant bytes must be zero, or in other words, the
274    /// address must be aligned to `u16::MAX + 1`.
275    ///
276    /// MCAN uses 16-bit addressing internally. In order to validate the
277    /// correctness of the `Message RAM` placement, the target HAL has to
278    /// provide information about its absolute position in RAM.
279    fn eligible_message_ram_start(&self) -> *const ();
280    /// Frequency of the host / main / CPU clock.
281    ///
282    /// MCAN uses the host clock for most of its internal operations and its
283    /// speed has to be equal to or faster than the CAN specific asynchronous
284    /// clock.
285    fn host_clock(&self) -> fugit::HertzU32;
286    /// Frequency of the CAN specific asynchronous clock.
287    ///
288    /// MCAN uses a separate asynchronous clock for signaling / sampling and
289    /// as such it should have reasonably high precision. Its speed has to
290    /// be equal to or slower than the host clock.
291    fn can_clock(&self) -> fugit::HertzU32;
292}