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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
//! Real Time For the Masses (RTFM) framework for ARM Cortex-M microcontrollers
//!
//! This crate is based on [the RTFM framework] created by the Embedded Systems
//! group at [Luleå University of Technology][ltu], led by Prof. Per Lindgren,
//! and uses a simplified version of the Stack Resource Policy as scheduling
//! policy (check the [references] for details).
//!
//! [the RTFM framework]: http://www.rtfm-lang.org/
//! [ltu]: https://www.ltu.se/?l=en
//! [per]: https://www.ltu.se/staff/p/pln-1.11258?l=en
//! [references]: ./index.html#references
//!
//! # Features
//!
//! - **Event triggered tasks** as the unit of concurrency.
//! - Support for prioritization of tasks and, thus, **preemptive
//!   multitasking**.
//! - **Efficient and data race free memory sharing** through fine grained *non
//!   global* critical sections.
//! - **Deadlock free execution** guaranteed at compile time.
//! - **Minimal scheduling overhead** as the scheduler has no "software
//!   component": the hardware does all the scheduling.
//! - **Highly efficient memory usage**: All the tasks share a single call stack
//!   and there's no hard dependency on a dynamic memory allocator.
//! - **All Cortex M devices are fully supported**.
//! - This task model is amenable to known WCET (Worst Case Execution Time)
//!   analysis and scheduling analysis techniques. (Though we haven't yet
//!   developed Rust friendly tooling for that.)
//!
//! # Constraints
//!
//! - Tasks must run to completion. That's it, tasks can't contain endless
//!   loops. However, you can run an endless event loop in the `idle` *loop*.
//!
//! - Task priorities must remain constant at runtime.
//!
//! # Dependencies
//!
//! The application crate must depend on a device crate generated using
//! [`svd2rust`] v0.11.x and the "rt" feature of that crate must be enabled. The
//! SVD file used to generate the device crate *must* contain [`<cpu>`]
//! information.
//!
//! [`svd2rust`]: https://docs.rs/svd2rust/0..0/svd2rust/
//! [`<cpu>`]: https://www.keil.com/pack/doc/CMSIS/SVD/html/elem_cpu.html
//!
//! # `app!`
//!
//! The `app!` macro is documented [here].
//!
//! [here]: https://docs.rs/cortex-m-rtfm-macros/0.2.0/cortex_m_rtfm_macros/fn.app.html
//!
//! # Examples
//!
//! In increasing grade of complexity. See the [examples](./examples/index.html)
//! module.
//!
//! # References
//!
//! - Baker, T. P. (1991). Stack-based scheduling of realtime processes.
//!   *Real-Time Systems*, 3(1), 67-99.
//!
//! > The original Stack Resource Policy paper. [PDF][srp].
//!
//! [srp]: http://www.cs.fsu.edu/~baker/papers/mstacks3.pdf
//!
//! - Eriksson, J., Häggström, F., Aittamaa, S., Kruglyak, A., & Lindgren, P.
//!   (2013, June). Real-time for the masses, step 1: Programming API and static
//!   priority SRP kernel primitives. In Industrial Embedded Systems (SIES),
//!   2013 8th IEEE International Symposium on (pp. 110-113). IEEE.
//!
//! > A description of the RTFM task and resource model. [PDF][rtfm]
//!
//! [rtfm]: http://www.diva-portal.org/smash/get/diva2:1005680/FULLTEXT01.pdf
#![deny(missing_docs)]
#![deny(warnings)]
#![feature(proc_macro)]
#![no_std]

extern crate cortex_m;
extern crate cortex_m_rtfm_macros;
extern crate rtfm_core;
extern crate static_ref;

use core::u8;

pub use rtfm_core::{Resource, Static, Threshold};
pub use cortex_m::asm::{bkpt, wfi};
pub use cortex_m_rtfm_macros::app;
use cortex_m::interrupt::{self, Nr};
#[cfg(not(armv6m))]
use cortex_m::register::basepri;

pub mod examples;

/// Executes the closure `f` in a preemption free context
///
/// During the execution of the closure no task can preempt the current task.
pub fn atomic<R, F>(t: &mut Threshold, f: F) -> R
where
    F: FnOnce(&mut Threshold) -> R,
{
    if t.value() == u8::MAX {
        f(t)
    } else {
        interrupt::disable();
        let r = f(&mut unsafe { Threshold::max() });
        unsafe { interrupt::enable() };
        r
    }
}

#[inline]
#[doc(hidden)]
pub unsafe fn claim<T, R, F>(
    data: T,
    ceiling: u8,
    _nvic_prio_bits: u8,
    t: &mut Threshold,
    f: F,
) -> R
where
    F: FnOnce(T, &mut Threshold) -> R,
{
    if ceiling > t.value() {
        match () {
            #[cfg(armv6m)]
            () => atomic(t, |t| f(data, t)),

            #[cfg(not(armv6m))]
            () => {
                let max_priority = 1 << _nvic_prio_bits;

                if ceiling == max_priority {
                    atomic(t, |t| f(data, t))
                } else {
                    let old = basepri::read();
                    let hw = (max_priority - ceiling) << (8 - _nvic_prio_bits);
                    basepri::write(hw);
                    let ret = f(data, &mut Threshold::new(ceiling));
                    basepri::write(old);
                    ret
                }
            }
        }
    } else {
        f(data, t)
    }
}

/// Sets an interrupt, that is a task, as pending
///
/// If the task priority is high enough the task will be serviced immediately,
/// otherwise it will be serviced at some point after the current task ends.
pub fn set_pending<I>(interrupt: I)
where
    I: Nr,
{
    // NOTE(safe) atomic write
    let nvic = unsafe { &*cortex_m::peripheral::NVIC.get() };
    nvic.set_pending(interrupt);
}