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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
use crate::{MTTaskId, MTTaskPri};
use crate::msgqueue::MTMsgQueue;
use crate::shared::MTShared;
use crate::memory::{MTMemBlk, MTAlloc};
use crate::kernel::{mtkernel_create, mtkernel_get_ref, mtkernel_get_mut, MTEvent, MTEventCond};

/// Multitasking API
pub struct Minimult<'a>
{
    alloc: MTAlloc<'a>
}

impl<'a> Minimult<'a>
{
    // ----- ----- Main context ----- ----- //

    /// Reserves a memory block to be used by `Minimult` instance.
    /// * Any type `B` specifies a size of the memory block. Typically use `[u8; N]` for `N` bytes.
    /// * Returns the reserved memory block.
    pub const fn mem<B>() -> MTMemBlk<B>
    {
        MTMemBlk::new()
    }

    /// Creates `Minimult` instance.
    /// * `mem` - reserved memory block.
    /// * `num_tasks` - number of tasks.
    /// * Returns the created instance.
    /// * (`num_tasks` * (32 + 6)) bytes of the memory block is consumed.
    pub fn new<B>(mem: &mut MTMemBlk<B>, num_tasks: MTTaskId) -> Minimult
    {
        let mut alloc = MTAlloc::new(mem);

        mtkernel_create(alloc.array(num_tasks), alloc.array(num_tasks));

        Minimult {
            alloc
        }
    }

    /// Creates a message queue.
    /// * `M` - type of the message element.
    /// * `len` - length of the message queue array.
    /// * Returns the created message queue.
    /// * (`len` * (size of `M`)) bytes of the memory block is consumed.
    pub fn msgq<M>(&mut self, len: usize) -> MTMsgQueue<'a, M> // NOTE: lifetime safety correctness
    {
        let mem = self.alloc.array(len);

        MTMsgQueue::new(mem)
    }

    /// Creates a shared variable.
    /// * `m: M` - the variable to be shared.
    /// * Returns the created shared variable.
    pub fn share<M>(&mut self, m: M) -> MTShared<'a, M> // NOTE: lifetime safety correctness
    {
        MTShared::new(m)
    }

    /// Registers a closure as a task.
    /// * `tid` - task identifier. `0` to `num_tasks - 1`.
    /// * `pri` - task priority. The lower value is the higher priority.
    /// * `stack_len` - length of a stack used by the task.
    /// * `task: T` - task closure.
    /// * (`stack_len` * size of `usize`) bytes of the memory block is consumed.
    pub fn register<T>(&mut self, tid: MTTaskId, pri: MTTaskPri, stack_len: usize, task: T)
    where T: FnOnce() + Send + 'a // NOTE: lifetime safety correctness
    {
        let tm = mtkernel_get_mut().unwrap();

        let stack = self.alloc.array(stack_len);
        
        tm.register_once(tid, pri, stack, task);
    }

    /// Runs into a loop to dispatch the registered tasks.
    /// * Never returns.
    pub fn run(self) -> !
    {
        let tm = mtkernel_get_mut().unwrap();

        tm.run()
    }

    // ----- ----- Task context ----- ----- //

    /// Brings a current running task into an idle state.
    pub fn idle()
    {
        if let Some(tm) = mtkernel_get_mut() {
            tm.idle();
        }
    }

    pub(crate) fn wait(ev: &MTEvent, evcond: MTEventCond)
    {
        if let Some(tm) = mtkernel_get_mut() {
            tm.wait(ev, evcond);
        }
    }

    pub(crate) fn signal(ev: &MTEvent)
    {
        if let Some(tm) = mtkernel_get_mut() {
            tm.signal(ev);
        }
    }

    // ----- ----- Task and Interrupt context ----- ----- //

    /// Makes a service call to request dispatching.
    pub fn dispatch()
    {
        if let Some(tm) = mtkernel_get_ref() {
            tm.dispatch();
        }
    }

    /// Wakes up a task in an idle state.
    /// * `tid` - task identifier. `0` to `num_tasks - 1`.
    pub fn kick(tid: MTTaskId)
    {
        if let Some(tm) = mtkernel_get_mut() {
            tm.kick(tid);
        }
    }

    /// Gets task identifier of a current running task if any.
    /// * Returns task identifier in `Option`.
    pub fn curr_tid() -> Option<MTTaskId>
    {
        if let Some(tm) = mtkernel_get_ref() {
            tm.curr_tid()
        }
        else {
            None
        }
    }
}

impl Drop for Minimult<'_>
{
    fn drop(&mut self)
    {
        panic!("Minimult dropped without a run");
    }
}