use core::sync::atomic::{Ordering, compiler_fence};
use crate::pac::NVIC;
use atsamd_hal_macros::{hal_cfg, hal_macro_helper};
pub use crate::pac::NVIC_PRIO_BITS;
#[hal_cfg(any("nvic-d11", "nvic-d21"))]
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[repr(u8)]
#[allow(missing_docs)]
pub enum Priority {
P1 = 1,
P2 = 2,
P3 = 3,
P4 = 4,
}
#[hal_cfg("nvic-d5x")]
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[repr(u8)]
#[allow(missing_docs)]
pub enum Priority {
P1 = 1,
P2 = 2,
P3 = 3,
P4 = 4,
P5 = 5,
P6 = 6,
P7 = 7,
P8 = 8,
}
impl Priority {
pub const fn from_numeric(prio: u8) -> Option<Self> {
if prio >= 1 && prio <= 8 {
Some(unsafe { core::mem::transmute::<u8, Self>(prio) })
} else {
None
}
}
#[inline]
#[must_use]
pub const fn logical2hw(self) -> u8 {
((1 << NVIC_PRIO_BITS) - self as u8) << (8 - NVIC_PRIO_BITS)
}
#[inline]
#[must_use]
pub const fn hw2logical(prio: u8) -> Self {
assert!(prio % 0x20 == 0);
unsafe { core::mem::transmute((1 << NVIC_PRIO_BITS) - (prio >> (8 - NVIC_PRIO_BITS))) }
}
}
pub trait InterruptExt: cortex_m::interrupt::InterruptNumber + Copy {
#[inline]
unsafe fn enable(self) {
compiler_fence(Ordering::SeqCst);
unsafe { NVIC::unmask(self) }
}
#[inline]
fn disable(self) {
NVIC::mask(self);
compiler_fence(Ordering::SeqCst);
}
#[inline]
fn is_enabled(self) -> bool {
NVIC::is_enabled(self)
}
#[inline]
fn is_pending(self) -> bool {
NVIC::is_pending(self)
}
#[inline]
fn pend(self) {
NVIC::pend(self)
}
#[inline]
fn unpend(self) {
NVIC::unpend(self)
}
#[inline]
fn get_priority(self) -> Priority {
Priority::hw2logical(NVIC::get_priority(self))
}
#[inline]
#[hal_macro_helper]
fn set_priority(self, prio: Priority) {
unsafe {
let mut nvic = steal_nvic();
#[hal_cfg(any("nvic-d11", "nvic-d21"))]
critical_section::with(|_| nvic.set_priority(self, prio.logical2hw()));
#[hal_cfg("nvic-d5x")]
nvic.set_priority(self, prio.logical2hw());
}
}
#[inline]
fn set_priority_with_cs(self, _cs: critical_section::CriticalSection, prio: Priority) {
unsafe {
let mut nvic = steal_nvic();
nvic.set_priority(self, prio.logical2hw());
}
}
}
impl<T: cortex_m::interrupt::InterruptNumber + Copy> InterruptExt for T {}
unsafe fn steal_nvic() -> NVIC {
unsafe { cortex_m::peripheral::Peripherals::steal().NVIC }
}