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