Real-Time Interrupt-driven Concurrency — страница 15 из 23

fn foo(c: foo::Context) {

// .. пользовательский код ..

}


#[interrupt(binds = UART1, resources = [X, Y])]

fn bar(c: bar::Context) {

// .. пользовательский код ..

}


// ..

}

}

Фреймворк создает код, подобный этому:

fn init(c: init::Context) {

// .. пользовательский код ..

}


fn foo(c: foo::Context) {

// .. пользовательский код ..

}


fn bar(c: bar::Context) {

// .. пользовательский код ..

}


// Публичное API

pub mod init {

pub struct Context<'a> {

pub resources: Resources<'a>,

// ..

}


pub struct Resources<'a> {

pub Y: &'a mut bool,

}

}


pub mod foo {

pub struct Context<'a> {

pub resources: Resources<'a>,

// ..

}


pub struct Resources<'a> {

pub X: &'a mut u64,

}

}


pub mod bar {

pub struct Context<'a> {

pub resources: Resources<'a>,

// ..

}


pub struct Resources<'a> {

pub X: &'a mut u64,

pub Y: &'a mut bool,

}

}


/// Детали реализации

mod app {

// все, что внутри этого модуля спрятано от пользовательского кода


static mut X: u64 = 0;

static mut Y: bool = 0;


// настоящая точка входа в программу

unsafe fn main() -> ! {

interrupt::disable();


// ..


// вызов пользовательского кода; передача ссылок на статические переменные

init(init::Context {

resources: init::Resources {

X: &mut X,

},

// ..

});


// ..


interrupt::enable();


// ..

}


// обработчик прерывания,с которым связан `foo`

#[no_mangle]

unsafe fn UART0() {

// вызов пользовательского кода; передача ссылок на статические переменные

foo(foo::Context {

resources: foo::Resources {

X: &mut X,

},

// ..

});

}


// обработчик прерывания,с которым связан `bar`

#[no_mangle]

unsafe fn UART1() {

// вызов пользовательского кода; передача ссылок на статические переменные

bar(bar::Context {

resources: bar::Resources {

X: &mut X,

Y: &mut Y,

},

// ..

});

}

}

Поздние ресурсы

Некоторые ресурсы инициализируются во время выполнения после завершения функции init. Важно то, что ресурсы (статические переменные) полностью инициализируются до того, как задачи смогут запуститься, вот почему они должны быть инициализированы пока прерывания отключены.

Ниже показан пример кода, генерируемого фреймворком для инициализации позних ресурсов.


#![allow(unused)]

fn main() {

#[rtic::app(device = ..)]

mod app {

struct Resources {

x: Thing,

}


#[init]

fn init() -> init::LateResources {

// ..


init::LateResources {

x: Thing::new(..),

}

}


#[task(binds = UART0, resources = [x])]

fn foo(c: foo::Context) {

let x: &mut Thing = c.resources.x;


x.frob();


// ..

}


// ..

}

}

Код, генерируемы фреймворком выглядит примерно так:

fn init(c: init::Context) -> init::LateResources {

// .. пользовательский код ..

}


fn foo(c: foo::Context) {

// .. пользовательский код ..

}


// Public API

pub mod init {

pub struct LateResources {

pub x: Thing,

}


// ..

}


pub mod foo {

pub struct Resources<'a> {

pub x: &'a mut Thing,

}


pub struct Context<'a> {

pub resources: Resources<'a>,

// ..

}

}


/// Детали реализации

mod app {

// неинициализированная статическая переменная

static mut x: MaybeUninit = MaybeUninit::uninit();


#[no_mangle]

unsafe fn main() -> ! {

cortex_m::interrupt::disable();


// ..


let late = init(..);


// инициализация поздних ресурсов

x.as_mut_ptr().write(late.x);


cortex_m::interrupt::enable(); //~ compiler fence


// исключения, прерывания и задачи могут вытеснить `main` в этой точке


idle(..)

}


#[no_mangle]

unsafe fn UART0() {

foo(foo::Context {

resources: foo::Resources {

// `x` уже инициализирована к этому моменту

x: &mut *x.as_mut_ptr(),

},

// ..

})

}

}

Важная деталь здесь то, что interrupt::enable ведет себя как like a