1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
use core::{
    cell::UnsafeCell,
    ffi::{c_void, CStr},
    marker::PhantomPinned,
    mem::{size_of, transmute},
    panic::{RefUnwindSafe, UnwindSafe},
    ptr::null_mut,
    str,
};

use crate::{
    bindings::{
        rt_context_init, rt_syscall, rt_syscall_args, rt_syscall_pend, rt_syscall_push,
        rt_syscall_record, rt_task, rt_task_drop_privilege, rt_task_enable_fp, rt_task_exit,
        rt_task_name, rt_task_sleep, rt_task_sleep_periodic, rt_task_state, rt_task_yield,
        RT_STACK_MIN,
    },
    list::list_init,
    tick::Utick,
};

pub const STACK_MIN: usize = RT_STACK_MIN as usize;

pub struct Task {
    t: UnsafeCell<rt_task>,
    _pin_marker: PhantomPinned,
}

unsafe impl Send for Task {}
unsafe impl Sync for Task {}
impl UnwindSafe for Task {}
impl RefUnwindSafe for Task {}

pub fn yield_() {
    unsafe { rt_task_yield() }
}

pub fn sleep(ticks: Utick) {
    unsafe { rt_task_sleep(ticks) }
}

pub fn sleep_periodic(last_wake_tick: &mut Utick, period: Utick) {
    unsafe { rt_task_sleep_periodic(last_wake_tick, period) }
}

pub fn exit() -> ! {
    unsafe { rt_task_exit() }
}

pub fn name() -> &'static str {
    unsafe { str::from_utf8_unchecked(CStr::from_ptr(rt_task_name()).to_bytes()) }
}

pub fn enable_fp() {
    unsafe { rt_task_enable_fp() }
}

pub fn drop_privilege() {
    unsafe { rt_task_drop_privilege() }
}

impl Task {
    pub const fn init(task: &'static Task, name: &'static CStr, priority: u32) -> Task {
        let t = unsafe { &*(task.t.get() as *const rt_task) };
        Task {
            t: UnsafeCell::new(rt_task {
                list: list_init(&t.list),
                sleep_list: list_init(&t.sleep_list),
                ctx: null_mut(),
                list_head: null_mut(),
                record: rt_syscall_record {
                    next: null_mut(),
                    args: unsafe { transmute([0u8; size_of::<rt_syscall_args>()]) },
                    syscall: rt_syscall::RT_SYSCALL_TASK_READY,
                },
                priority,
                base_priority: priority,
                state: rt_task_state::RT_TASK_STATE_EXITED,
                wake_tick: 0,
                mutex_list: list_init(&t.mutex_list),
                name: name.as_ptr(),
            }),
            _pin_marker: PhantomPinned,
        }
    }

    pub fn start(&mut self, f: extern "C" fn(), stack: &mut [u8]) {
        let t = self.t.get_mut();
        unsafe {
            t.ctx = rt_context_init(Some(f), stack.as_mut_ptr() as *mut c_void, stack.len());
            rt_syscall_push(&mut t.record);
            rt_syscall_pend();
        }
    }
}

#[macro_export]
macro_rules! task {
    ($fn: ident $params: tt, $stack_size: expr, $priority: expr) => {
        $crate::paste::paste! {
            {
                static mut [< $fn:upper _TASK >]: rt::task::Task = rt::task::Task::init(
                    unsafe { &[< $fn:upper _TASK >] },
                    unsafe { core::ffi::CStr::from_bytes_with_nul_unchecked(core::concat!(core::stringify!($fn), "\0").as_bytes()) },
                    $priority,
                );
                static mut [< $fn:upper _TASK_STACK >]: [u8; $stack_size] = [0u8; $stack_size];
                extern "C" fn [< $fn _c >]() {
                    $fn $params
                }
                unsafe {
                    [< $fn:upper _TASK >].start([< $fn _c >], [< $fn:upper _TASK_STACK >].as_mut_slice());
                }
            }
        }
    };

    ($fn: ident, $stack_size: expr, $priority: expr) => {
        rt::task!($fn(), $stack_size, $priority);
    };
}