#[repr(C)]
#[derive(Clone,Copy)]
pub struct ThreadContext {
entry_point: fn()->u8,
}
pub type ThreadId = u8;
pub(crate) mod internal {
use avr_oxide::deviceconsts::oxide::MAX_THREADS;
use avr_oxide::hal::concurrency::{ThreadContext, interrupt};
pub(super) struct SchedulerState<const MT: usize> {
pub(super) threads: [Option<ThreadContext>; MT],
pub(super) current_thread: Option<u8>,
pub(super) run_q: Option<u8>
}
pub(super) static mut SCHEDULER: Option<SchedulerState<MAX_THREADS>> = None;
pub(crate) fn initialise() {
unsafe {
core::ptr::replace(&mut SCHEDULER,
Some(SchedulerState {
threads: [None; MAX_THREADS],
current_thread: None,
run_q: None
}));
}
}
pub(crate) unsafe fn run_scheduler() -> ! {
loop {
interrupt::disable_interrupts();
if let Some(scheduler) = &mut SCHEDULER {
if let Some(thread_id) = scheduler.run_q {
scheduler.run_q = None;
scheduler.current_thread = Some(thread_id);
if let Some(thread_context) = &mut scheduler.threads[thread_id as usize] {
interrupt::enable_interrupts();
(thread_context.entry_point)();
} else {
panic!();
}
} else {
interrupt::enable_interrupts();
interrupt::wait();
}
} else {
panic!()
}
}
}
}
pub mod thread {
use avr_oxide::hal::concurrency::{ThreadContext, interrupt, ThreadId};
use avr_oxide::deviceconsts::oxide::MAX_THREADS;
use avr_oxide::hal::concurrency::internal::SCHEDULER;
pub struct JoinHandle {
thread: Thread
}
#[repr(C)]
#[derive(Clone,Copy)]
pub struct Thread {
thread_id: u8
}
pub fn spawn(f: fn() -> u8) -> JoinHandle {
interrupt::isolated(||{unsafe{spawn_threadunsafe(f)}})
}
pub(crate) unsafe fn spawn_threadunsafe(f: fn() -> u8) -> JoinHandle
{
if let Some(scheduler) = &mut SCHEDULER {
for i in 0..MAX_THREADS {
match scheduler.threads[i] {
None => {
let thread = ThreadContext {
entry_point: f
};
scheduler.threads[i] = Some(thread);
scheduler.run_q = Some(i as ThreadId);
return JoinHandle {
thread: Thread {
thread_id: i as u8
}
};
},
Some(_) => {}
}
}
panic!()
} else {
panic!()
}
}
impl JoinHandle {
pub fn join(self) -> u8 {
unimplemented!()
}
pub fn thread(&self) -> &Thread {
&self.thread
}
}
impl Thread {
pub fn id(&self) -> ThreadId {
self.thread_id
}
}
}
pub mod interrupt {
use avr_oxide::hal::generic::cpu::Cpu;
use avr_oxide::cpu;
pub fn isolated<F,R>(f: F) -> R
where
F: FnOnce() -> R
{
unsafe {
#[cfg(target_arch="avr")]
let sreg = cpu!().read_sreg();
disable_interrupts();
let result = f();
#[cfg(target_arch="avr")]
cpu!().write_sreg(sreg);
result
}
}
#[inline(always)]
pub(crate) fn isr<F>(f: F) -> ()
where
F: FnOnce() -> (),
{
#[allow(deprecated)]
unsafe {
llvm_asm!("push r24" :::: "volatile");
#[cfg(feature="atmega4809")]
llvm_asm!("in r24,0x0F" :::: "volatile");
#[cfg(feature="atmega328p")]
llvm_asm!("in r24,0x3F" :::: "volatile");
llvm_asm!("push r24" :::: "volatile");
llvm_asm!("push r31" :::: "volatile");
llvm_asm!("push r30" :::: "volatile");
llvm_asm!("push r29" :::: "volatile");
llvm_asm!("push r28" :::: "volatile");
llvm_asm!("push r27" :::: "volatile");
llvm_asm!("push r26" :::: "volatile");
llvm_asm!("push r25" :::: "volatile");
llvm_asm!("push r23" :::: "volatile");
llvm_asm!("push r22" :::: "volatile");
llvm_asm!("push r21" :::: "volatile");
llvm_asm!("push r20" :::: "volatile");
llvm_asm!("push r19" :::: "volatile");
llvm_asm!("push r18" :::: "volatile");
llvm_asm!("push r17" :::: "volatile");
llvm_asm!("push r16" :::: "volatile");
llvm_asm!("push r15" :::: "volatile");
llvm_asm!("push r14" :::: "volatile");
llvm_asm!("push r13" :::: "volatile");
llvm_asm!("push r12" :::: "volatile");
llvm_asm!("push r11" :::: "volatile");
llvm_asm!("push r10" :::: "volatile");
llvm_asm!("push r9" :::: "volatile");
llvm_asm!("push r8" :::: "volatile");
llvm_asm!("push r7" :::: "volatile");
llvm_asm!("push r6" :::: "volatile");
llvm_asm!("push r5" :::: "volatile");
llvm_asm!("push r4" :::: "volatile");
llvm_asm!("push r3" :::: "volatile");
llvm_asm!("push r2" :::: "volatile");
llvm_asm!("push r1" :::: "volatile");
llvm_asm!("push r0" :::: "volatile");
f();
llvm_asm!("pop r0" :::: "volatile");
llvm_asm!("pop r1" :::: "volatile");
llvm_asm!("pop r2" :::: "volatile");
llvm_asm!("pop r3" :::: "volatile");
llvm_asm!("pop r4" :::: "volatile");
llvm_asm!("pop r5" :::: "volatile");
llvm_asm!("pop r6" :::: "volatile");
llvm_asm!("pop r7" :::: "volatile");
llvm_asm!("pop r8" :::: "volatile");
llvm_asm!("pop r9" :::: "volatile");
llvm_asm!("pop r10" :::: "volatile");
llvm_asm!("pop r11" :::: "volatile");
llvm_asm!("pop r12" :::: "volatile");
llvm_asm!("pop r13" :::: "volatile");
llvm_asm!("pop r14" :::: "volatile");
llvm_asm!("pop r15" :::: "volatile");
llvm_asm!("pop r16" :::: "volatile");
llvm_asm!("pop r17" :::: "volatile");
llvm_asm!("pop r18" :::: "volatile");
llvm_asm!("pop r19" :::: "volatile");
llvm_asm!("pop r20" :::: "volatile");
llvm_asm!("pop r21" :::: "volatile");
llvm_asm!("pop r22" :::: "volatile");
llvm_asm!("pop r23" :::: "volatile");
llvm_asm!("pop r25" :::: "volatile");
llvm_asm!("pop r26" :::: "volatile");
llvm_asm!("pop r27" :::: "volatile");
llvm_asm!("pop r28" :::: "volatile");
llvm_asm!("pop r29" :::: "volatile");
llvm_asm!("pop r30" :::: "volatile");
llvm_asm!("pop r31" :::: "volatile");
llvm_asm!("pop r24" :::: "volatile");
#[cfg(feature="atmega4809")]
llvm_asm!("out 0x0F,r24" :::: "volatile");
#[cfg(feature="atmega328p")]
llvm_asm!("out 0x3F,r24" :::: "volatile");
llvm_asm!("pop r24" :::: "volatile");
}
}
#[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(){
#![allow(deprecated)] llvm_asm!("sei" :::: "volatile")
}
#[cfg(target_arch="avr")]
#[inline(always)]
pub(crate) unsafe fn disable_interrupts() {
#![allow(deprecated)] llvm_asm!("cli" :::: "volatile")
}
#[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 {
#![allow(deprecated)] llvm_asm!("sleep");
}
}
}