use core::arch::asm;
use avr_oxide::hal::generic::cpu::Cpu;
use avr_oxide::cpu;
use avr_oxide::concurrency::Isolated;
pub mod token {
#[derive(Clone, Copy)]
pub struct Isolated {
pub(super) _private: ()
}
}
pub fn isolated<F,R>(f: F) -> R
where
F: FnOnce(Isolated) -> R
{
if cpu!().interrupts_enabled() && !cpu!().in_isr() {
unsafe {
disable_interrupts();
let result = f(Isolated{_private:()});
enable_interrupts();
result
}
} else {
f(Isolated{_private:()})
}
}
#[cfg(target_arch="avr")]
pub(crate) fn isr<F>(reschedule: bool, f: F) -> ()
where
F: FnOnce(Isolated) -> ()
{
let isotoken = Isolated{_private:()};
unsafe {
core::arch::asm!(
"sbi {context_flags_reg},{flag_inisr}",
context_flags_reg = const(avr_oxide::hardware::cpu::cpuregs::IOADR_CONTEXT_FLAGS),
flag_inisr = const(avr_oxide::hal::generic::cpu::CONTEXT_FLAG_INISR)
);
f(isotoken);
#[cfg(feature="runtime_checks")]
avr_oxide::concurrency::stack::kernel::halt_if_stack_invalid();
if reschedule {
preemptive_reschedule(isotoken);
}
core::arch::asm!(
"cbi {context_flags_reg},{flag_inisr}",
context_flags_reg = const(avr_oxide::hardware::cpu::cpuregs::IOADR_CONTEXT_FLAGS),
flag_inisr = const(avr_oxide::hal::generic::cpu::CONTEXT_FLAG_INISR)
);
}
}
#[cfg(target_arch="avr")]
pub(crate) unsafe fn preemptive_reschedule(isotoken: Isolated) {
avr_oxide::concurrency::scheduler::schedule_next_thread(isotoken);
core::arch::asm!(
"sbi {context_flags_reg},{flag_preemption}",
context_flags_reg = const(avr_oxide::hardware::cpu::cpuregs::IOADR_CONTEXT_FLAGS),
flag_preemption = const(avr_oxide::hal::generic::cpu::CONTEXT_FLAG_PREEMPTION)
);
}
#[cfg(not(target_arch="avr"))]
pub(crate) unsafe fn preemptive_reschedule(isotoken: Isolated) {
unimplemented!()
}
#[cfg(not(target_arch="avr"))]
pub fn isr<F>(_reschedule: bool, f: F) -> ()
where
F: FnOnce(Isolated) -> (),
{
f(Isolated{_private:()});
}
#[cfg(not(target_arch="avr"))]
pub(crate) unsafe fn enable_interrupts() {
}
#[cfg(not(target_arch="avr"))]
pub(crate) unsafe fn disable_interrupts() {
}
#[cfg(target_arch="avr")]
#[inline(always)]
pub(crate) unsafe fn enable_interrupts(){
asm!("sei")
}
#[cfg(target_arch="avr")]
#[inline(always)]
pub(crate) unsafe fn disable_interrupts() {
asm!("cli")
}
#[cfg(not(target_arch="avr"))]
pub fn wait() {
std::thread::sleep(std::time::Duration::from_millis(100));
}
#[cfg(target_arch="avr")]
#[inline(always)]
pub fn wait() {
unsafe {
asm!("sleep")
}
}