use core::{fmt, hash, marker::PhantomData};
use super::{
utils, ClearInterruptLineError, EnableInterruptLineError, Kernel, PendInterruptLineError, Port,
QueryInterruptLineError, SetInterruptLinePriorityError,
};
use crate::utils::Init;
pub type InterruptNum = usize;
pub type InterruptPriority = i16;
pub struct InterruptLine<System>(InterruptNum, PhantomData<System>);
impl<System> Clone for InterruptLine<System> {
fn clone(&self) -> Self {
Self(self.0, self.1)
}
}
impl<System> Copy for InterruptLine<System> {}
impl<System> PartialEq for InterruptLine<System> {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
impl<System> Eq for InterruptLine<System> {}
impl<System> hash::Hash for InterruptLine<System> {
fn hash<H>(&self, state: &mut H)
where
H: hash::Hasher,
{
hash::Hash::hash(&self.0, state);
}
}
impl<System> fmt::Debug for InterruptLine<System> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_tuple("InterruptLine").field(&self.0).finish()
}
}
impl<System> InterruptLine<System> {
pub const fn from_num(num: InterruptNum) -> Self {
Self(num, PhantomData)
}
pub const fn num(self) -> InterruptNum {
self.0
}
}
impl<System: Kernel> InterruptLine<System> {
#[cfg_attr(not(feature = "inline_syscall"), inline(never))]
pub fn set_priority(
self,
value: InterruptPriority,
) -> Result<(), SetInterruptLinePriorityError> {
let mut lock = utils::lock_cpu::<System>()?;
if !System::is_task_context() {
return Err(SetInterruptLinePriorityError::BadContext);
}
if !System::MANAGED_INTERRUPT_PRIORITY_RANGE.contains(&value) {
return Err(SetInterruptLinePriorityError::BadParam);
}
unsafe { self.set_priority_unchecked_inner(value, lock.borrow_mut()) }
}
#[cfg_attr(not(feature = "inline_syscall"), inline(never))]
pub unsafe fn set_priority_unchecked(
self,
value: InterruptPriority,
) -> Result<(), SetInterruptLinePriorityError> {
let mut lock = utils::lock_cpu::<System>()?;
if !System::is_task_context() {
return Err(SetInterruptLinePriorityError::BadContext);
}
unsafe { self.set_priority_unchecked_inner(value, lock.borrow_mut()) }
}
#[inline]
unsafe fn set_priority_unchecked_inner(
self,
value: InterruptPriority,
_lock: utils::CpuLockGuardBorrowMut<System>,
) -> Result<(), SetInterruptLinePriorityError> {
unsafe { System::set_interrupt_line_priority(self.0, value) }
}
#[inline]
pub fn enable(self) -> Result<(), EnableInterruptLineError> {
unsafe { System::enable_interrupt_line(self.0) }
}
#[inline]
pub fn disable(self) -> Result<(), EnableInterruptLineError> {
unsafe { System::disable_interrupt_line(self.0) }
}
#[inline]
pub fn pend(self) -> Result<(), PendInterruptLineError> {
unsafe { System::pend_interrupt_line(self.0) }
}
#[inline]
pub fn clear(self) -> Result<(), ClearInterruptLineError> {
unsafe { System::clear_interrupt_line(self.0) }
}
#[inline]
pub fn is_pending(self) -> Result<bool, QueryInterruptLineError> {
unsafe { System::is_interrupt_line_pending(self.0) }
}
}
pub struct InterruptHandler<System>(PhantomData<System>);
impl<System> InterruptHandler<System> {
pub(super) const fn new() -> Self {
Self(PhantomData)
}
}
#[doc(hidden)]
#[derive(Debug, Clone, Copy)]
pub struct InterruptLineInit<System> {
pub(super) line: InterruptLine<System>,
pub(super) priority: InterruptPriority,
pub(super) flags: InterruptLineInitFlags,
}
impl<System> Init for InterruptLineInit<System> {
const INIT: Self = Self {
line: InterruptLine::from_num(0),
priority: Init::INIT,
flags: InterruptLineInitFlags::empty(),
};
}
bitflags::bitflags! {
#[doc(hidden)]
pub struct InterruptLineInitFlags: u32 {
const ENABLE = 1 << 0;
const SET_PRIORITY = 1 << 1;
}
}
#[doc(hidden)]
#[derive(Debug, Clone, Copy)]
pub struct InterruptAttr<System: Port> {
pub line_inits: &'static [InterruptLineInit<System>],
}
impl<System: Kernel> InterruptAttr<System> {
pub(super) unsafe fn init(&self, mut lock: utils::CpuLockGuardBorrowMut<System>) {
for line_init in self.line_inits {
if line_init
.flags
.contains(InterruptLineInitFlags::SET_PRIORITY)
{
unsafe {
line_init
.line
.set_priority_unchecked_inner(line_init.priority, lock.borrow_mut())
.unwrap()
};
}
if line_init.flags.contains(InterruptLineInitFlags::ENABLE) {
line_init.line.enable().unwrap();
}
}
}
}