#![feature(prelude_import)] //! examples/optlock.rs #![deny(unsafe_code)] #![deny(warnings)] #![no_main] #![no_std] #[prelude_import] use core::prelude::v1::*; #[macro_use] extern crate core; #[macro_use] extern crate compiler_builtins; use cortex_m_semihosting::debug; use lm3s6965::Interrupt; use panic_semihosting as _; use rtfm::Exclusive; #[allow(non_snake_case)] fn init(_: init::Context) { rtfm::pend(Interrupt::GPIOA); } #[allow(non_snake_case)] fn gpioa( // when omitted priority is assumed to be `1` mut c: gpioa::Context, ) { use rtfm::Mutex as _; // the lower priority task requires a critical section to access the data c.resources.shared.lock( // data can only be modified within this critical section (closure) // GPIOB will *not* run right now due to the critical section // hprintln!("B - shared = {}", *shared).unwrap(); // GPIOC does not contend for `shared` so it's allowed to run now |shared| { *shared += 1; rtfm::pend(Interrupt::GPIOB); rtfm::pend(Interrupt::GPIOC); }, ); // critical section is over: GPIOB can now start debug::exit(debug::EXIT_SUCCESS); } #[allow(non_snake_case)] fn gpiob(mut c: gpiob::Context) { use rtfm::Mutex as _; // higher priority task, with critical section c.resources.shared.lock(|shared| { *shared += 1; }); } #[allow(non_snake_case)] fn gpioc(c: gpioc::Context) { use rtfm::Mutex as _; // highest priority task with critical section // we wrap resource.shared into an Exclusive let mut exclusive = Exclusive(c.resources.shared); // we can access through both lock ... exclusive.lock(|shared| { *shared += 1; }); // and deref, i.e., non-orthogonal design *exclusive += 1; } #[allow(non_snake_case)] #[doc = "Initialization function"] pub mod init { #[doc = r" Execution context"] pub struct Context { #[doc = r" Core (Cortex-M) peripherals"] pub core: rtfm::export::Peripherals, } impl Context { #[inline(always)] pub unsafe fn new(core: rtfm::export::Peripherals) -> Self { Context { core } } } } mod resources { use rtfm::export::Priority; #[allow(non_camel_case_types)] pub struct shared<'a> { priority: &'a Priority, } impl<'a> shared<'a> { #[inline(always)] pub unsafe fn new(priority: &'a Priority) -> Self { shared { priority } } #[inline(always)] pub unsafe fn priority(&self) -> &Priority { self.priority } } } #[allow(non_snake_case)] #[doc = "Resources `gpioa` has access to"] pub struct gpioaResources<'a> { pub shared: resources::shared<'a>, } #[allow(non_snake_case)] #[doc = "Hardware task"] pub mod gpioa { #[doc(inline)] pub use super::gpioaResources as Resources; #[doc = r" Execution context"] pub struct Context<'a> { #[doc = r" Resources this task has access to"] pub resources: Resources<'a>, } impl<'a> Context<'a> { #[inline(always)] pub unsafe fn new(priority: &'a rtfm::export::Priority) -> Self { Context { resources: Resources::new(priority), } } } } #[allow(non_snake_case)] #[doc = "Resources `gpiob` has access to"] pub struct gpiobResources<'a> { pub shared: resources::shared<'a>, } #[allow(non_snake_case)] #[doc = "Hardware task"] pub mod gpiob { #[doc(inline)] pub use super::gpiobResources as Resources; #[doc = r" Execution context"] pub struct Context<'a> { #[doc = r" Resources this task has access to"] pub resources: Resources<'a>, } impl<'a> Context<'a> { #[inline(always)] pub unsafe fn new(priority: &'a rtfm::export::Priority) -> Self { Context { resources: Resources::new(priority), } } } } #[allow(non_snake_case)] #[doc = "Resources `gpioc` has access to"] pub struct gpiocResources<'a> { pub shared: &'a mut u32, } #[allow(non_snake_case)] #[doc = "Hardware task"] pub mod gpioc { #[doc(inline)] pub use super::gpiocResources as Resources; #[doc = r" Execution context"] pub struct Context<'a> { #[doc = r" Resources this task has access to"] pub resources: Resources<'a>, } impl<'a> Context<'a> { #[inline(always)] pub unsafe fn new(priority: &'a rtfm::export::Priority) -> Self { Context { resources: Resources::new(priority), } } } } #[doc = r" Implementation details"] const APP: () = { #[doc = r" Always include the device crate which contains the vector table"] use lm3s6965 as _; #[allow(non_upper_case_globals)] static mut shared: u32 = 0; impl<'a> rtfm::Mutex for resources::shared<'a> { type T = u32; #[inline(always)] fn lock(&mut self, f: impl FnOnce(&mut u32) -> R) -> R { #[doc = r" Priority ceiling"] const CEILING: u8 = 3u8; unsafe { rtfm::export::lock( &mut shared, self.priority(), CEILING, lm3s6965::NVIC_PRIO_BITS, f, ) } } } #[allow(non_snake_case)] #[no_mangle] unsafe fn GPIOA() { const PRIORITY: u8 = 1u8; crate::gpioa(gpioa::Context::new(&rtfm::export::Priority::new(PRIORITY))); } impl<'a> gpioaResources<'a> { #[inline(always)] unsafe fn new(priority: &'a rtfm::export::Priority) -> Self { gpioaResources { shared: resources::shared::new(priority), } } } #[allow(non_snake_case)] #[no_mangle] unsafe fn GPIOB() { const PRIORITY: u8 = 2u8; crate::gpiob(gpiob::Context::new(&rtfm::export::Priority::new(PRIORITY))); } impl<'a> gpiobResources<'a> { #[inline(always)] unsafe fn new(priority: &'a rtfm::export::Priority) -> Self { gpiobResources { shared: resources::shared::new(priority), } } } #[allow(non_snake_case)] #[no_mangle] unsafe fn GPIOC() { const PRIORITY: u8 = 3u8; crate::gpioc(gpioc::Context::new(&rtfm::export::Priority::new(PRIORITY))); } impl<'a> gpiocResources<'a> { #[inline(always)] unsafe fn new(priority: &'a rtfm::export::Priority) -> Self { gpiocResources { shared: &mut shared, } } } #[no_mangle] unsafe extern "C" fn main() -> ! { rtfm::export::interrupt::disable(); let mut core: rtfm::export::Peripherals = core::mem::transmute(()); let _ = [(); ((1 << lm3s6965::NVIC_PRIO_BITS) - 1u8 as usize)]; core.NVIC.set_priority( lm3s6965::Interrupt::GPIOA, rtfm::export::logical2hw(1u8, lm3s6965::NVIC_PRIO_BITS), ); rtfm::export::NVIC::unmask(lm3s6965::Interrupt::GPIOA); let _ = [(); ((1 << lm3s6965::NVIC_PRIO_BITS) - 2u8 as usize)]; core.NVIC.set_priority( lm3s6965::Interrupt::GPIOB, rtfm::export::logical2hw(2u8, lm3s6965::NVIC_PRIO_BITS), ); rtfm::export::NVIC::unmask(lm3s6965::Interrupt::GPIOB); let _ = [(); ((1 << lm3s6965::NVIC_PRIO_BITS) - 3u8 as usize)]; core.NVIC.set_priority( lm3s6965::Interrupt::GPIOC, rtfm::export::logical2hw(3u8, lm3s6965::NVIC_PRIO_BITS), ); rtfm::export::NVIC::unmask(lm3s6965::Interrupt::GPIOC); core.SCB.scr.modify(|r| r | 1 << 1); let late = init(init::Context::new(core.into())); rtfm::export::interrupt::enable(); loop { rtfm::export::wfi() } } };