use avr_oxide::hal::generic::port::{InterruptMode, Pin, PinMode};
use avr_oxide::util::debug;
use core::ops::{ControlFlow, Try};
static mut DEBUGPIN : Option<&'static dyn Pin> = None;
#[cfg_attr(not(target_arch="avr"), derive(Debug))]
#[cfg_attr(target_arch="avr", derive(ufmt::derive::uDebug))]
pub enum OxideResult<T,E> {
Ok(T),
Err(E)
}
#[cfg_attr(not(target_arch="avr"), derive(Debug))]
#[cfg_attr(target_arch="avr", derive(ufmt::derive::uDebug))]
#[derive(Copy,Clone,PartialEq)]
pub enum OsError {
NotEnoughRam,
OutOfMemory,
StackOverflow,
KernelStackOverflow,
KernelGuardCrashed,
NoSchedulableThreads,
InternalError,
BadThreadState,
OutOfThreads,
DoubleFree,
BadParams,
NestedInhibitTooDeep,
Arithmetic,
Panic,
CannotYield,
OxideEventOverflow,
StaticDropped,
StaticBorrow,
UnwrapError,
UnwrapNone
}
pub trait OxideTryFrom<T>
where
T: Sized
{
type Error;
fn oxide_try_from(_: T) -> OxideResult<Self, Self::Error> where Self: Sized;
}
impl<T,E> OxideResult<T,E> {
pub const fn is_ok(&self) -> bool {
match self {
OxideResult::Ok(_) => true,
OxideResult::Err(_) => false
}
}
pub const fn is_err(&self) -> bool {
match self {
OxideResult::Ok(_) => false,
OxideResult::Err(_) => true
}
}
pub fn unwrap(self) -> T {
match self {
OxideResult::Ok(t) => t,
OxideResult::Err(_) => {
halt(OsError::UnwrapError);
}
}
}
pub fn expect_err(self) -> E {
match self {
OxideResult::Ok(_) => {
halt(OsError::UnwrapError)
}
OxideResult::Err(e) => e
}
}
pub fn unwrap_or(self, default: T) -> T {
match self {
OxideResult::Ok(t) => t,
OxideResult::Err(_) => default
}
}
pub fn unwrap_or_else<F: FnOnce(E)->T>(self, op: F) -> T {
match self {
OxideResult::Ok(t) => t,
OxideResult::Err(e) => { (op)(e) }
}
}
}
impl<T,E> Try for OxideResult<T,E> {
type Output = T;
type Residual = OxideResult<core::convert::Infallible, E>;
#[inline]
fn from_output(output: Self::Output) -> Self {
OxideResult::Ok(output)
}
#[inline]
fn branch(self) -> ControlFlow<Self::Residual, Self::Output> {
match self {
OxideResult::Ok(t) => ControlFlow::Continue(t),
OxideResult::Err(e) => ControlFlow::Break(OxideResult::Err(e))
}
}
}
impl<T, E, F: ~const From<E>> const core::ops::FromResidual<OxideResult<core::convert::Infallible, E>>
for OxideResult<T, F>
{
#[inline]
fn from_residual(residual: OxideResult<core::convert::Infallible, E>) -> Self {
match residual {
OxideResult::Err(e) => return OxideResult::Err(From::from(e)),
OxideResult::Ok(_) => { panic!() }
}
}
}
impl<T, E> core::ops::Residual<T> for OxideResult<core::convert::Infallible, E> {
type TryType = OxideResult<T, E>;
}
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,
Self::StaticDropped => 0b_0000_0000_0000_0000_0000_0000_0111_0101,
Self::StaticBorrow => 0b_0000_0000_0000_0000_0000_0001_0111_0101,
Self::UnwrapError => 0b_0000_0000_0000_0000_0101_1101_1101_1101,
Self::UnwrapNone => 0b_0000_0000_0000_0001_0101_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 fn halt(error: OsError) -> ! {
panic!("OS Error: {:?}", error);
}
#[macro_export]
macro_rules! panic_if_none {
($result:expr) => {
match $result {
Some(value) => value,
None => { avr_oxide::oserror::halt(avr_oxide::oserror::OsError::UnwrapNone); }
}
};
($result:expr,$paniccode:expr) => {
match $result {
Some(value) => value,
None => { avr_oxide::oserror::halt($paniccode); }
}
};
}