use avr_oxide::hal::generic::port::{InterruptMode, Pin, PinMode};
use avr_oxide::util::debug;
static mut DEBUGPIN : Option<&'static dyn Pin> = None;
#[derive(Copy,Clone,PartialEq,Debug)]
pub enum OsError {
NotEnoughRam,
OutOfMemory,
StackOverflow,
KernelStackOverflow,
KernelGuardCrashed,
NoSchedulableThreads,
InternalError,
BadThreadState,
OutOfThreads,
DoubleFree,
BadParams,
NestedInhibitTooDeep,
Arithmetic,
Panic,
CannotYield,
OxideEventOverflow,
}
impl OsError {
fn pulse_train(&self) -> u32 {
match self {
Self::NotEnoughRam => 0b_0000_0000_0000_0000_0000_0000_0000_0001,
Self::OutOfMemory => 0b_0000_0000_0000_0000_0000_0000_0000_0101,
Self::StackOverflow => 0b_0000_0000_0000_0000_0000_0000_0001_0101,
Self::KernelStackOverflow => 0b_0000_0000_0000_0000_0000_0001_0101_0111,
Self::KernelGuardCrashed => 0b_0000_0000_0000_0000_0000_0111_0101_0111,
Self::OxideEventOverflow => 0b_0000_0000_0000_0000_0001_0101_0111_0111,
Self::NoSchedulableThreads => 0b_0000_0000_0000_0000_0000_0000_0101_0101,
Self::CannotYield => 0b_0000_0000_0000_0000_0000_0101_0101_0111,
Self::InternalError => 0b_0000_0000_0000_0000_0000_0001_0101_0101,
Self::BadThreadState => 0b_0000_0000_0000_0000_0000_0101_0111_0101,
Self::OutOfThreads => 0b_0000_0000_0000_0000_0000_0101_0101_0101,
Self::DoubleFree => 0b_0000_0000_0000_0000_0001_0101_0101_0101,
Self::BadParams => 0b_0000_0000_0000_0000_0000_0000_0001_1101,
Self::NestedInhibitTooDeep => 0b_0000_0000_0000_0001_0101_0101_0101_0101,
Self::Arithmetic => 0b_0000_0000_0000_0000_0000_0001_1101_1101,
Self::Panic => 0b_0000_0000_0000_0000_0001_1101_1101_1101,
}
}
}
pub fn set_debug_pin(pin: &'static dyn Pin) {
avr_oxide::concurrency::interrupt::isolated(|_isotoken|{
unsafe {
core::ptr::replace(&mut DEBUGPIN, Some(pin));
}
})
}
#[cfg(target_arch="avr")]
pub fn halt(error: OsError) -> ! {
unsafe {
avr_oxide::concurrency::interrupt::disable_interrupts();
#[cfg(feature="panicout")]
{
debug::print("\r\n\nHALT: ");
debug::print_u32(error.pulse_train());
debug::print("\r\n");
debug::print_thread_state();
}
const DELAYLOOP : u32 = (avr_oxide::deviceconsts::clock::MASTER_CLOCK_HZ / 100) / avr_oxide::deviceconsts::clock::MASTER_CLOCK_PRESCALER as u32;
match DEBUGPIN {
Some(pin) => {
let pulse_code = error.pulse_train();
pin.set_mode(PinMode::Output);
pin.set_interrupt_mode(InterruptMode::Disabled);
pin.set_low();
loop {
let mut mask : u32 = 1u32;
for _i in 0..32 {
if pulse_code & mask > 0 {
pin.set_high();
} else {
pin.set_low();
}
mask <<= 1;
for _d in 0..DELAYLOOP {
core::arch::asm!("nop");
}
}
core::arch::asm!("break");
}
},
None => {
core::arch::asm!(
"break",
"0: ", "sleep",
"jmp 0b",
options(noreturn)
);
}
}
}
}
#[cfg(not(target_arch="avr"))]
pub(crate) fn halt(error: OsError) -> ! {
panic!("OS Error: {:?}", error);
}
#[macro_export]
macro_rules! halt_if_err {
($result:expr, $error:expr) => {
match $result {
Ok(value) => value,
Err(_) => avr_oxide::oserror::halt($error)
}
}
}
#[macro_export]
macro_rules! halt_if_none {
($result:expr, $error:expr) => {
match $result {
Some(value) => value,
None => avr_oxide::oserror::halt($error)
}
}
}