Выбрать главу

fn init(_: init::Context) -> (Shared, Local, init::Monotonics) {

foo::spawn().unwrap();

(Shared {}, Local {}, init::Monotonics())

}

#[task]

fn foo(_: foo::Context) {

hprintln!("foo - start").unwrap();

// spawns `bar` onto the task scheduler

// `foo` and `bar` have the same priority so `bar` will not run until

// after `foo` terminates

bar::spawn().unwrap();

hprintln!("foo - middle").unwrap();

// spawns `baz` onto the task scheduler

// `baz` has higher priority than `foo` so it immediately preempts `foo`

baz::spawn().unwrap();

hprintln!("foo - end").unwrap();

}

#[task]

fn bar(_: bar::Context) {

hprintln!("bar").unwrap();

debug::exit(debug::EXIT_SUCCESS);

}

#[task(priority = 2)]

fn baz(_: baz::Context) {

hprintln!("baz").unwrap();

}

}

}

$ cargo run --example task

foo - start

foo - middle

baz

foo - end

bar

Другое преимущество программной задачи в том, что задачам можно передать сообщения в момент их запуска. Тип передаваемого сообщения должен быть определен в сигнатуре задачи-обработчика.

Пример ниже демонстрирует три задачи, две из которых ожидают сообщение.

#![allow(unused)]

fn main() {

//! examples/message.rs

#![deny(unsafe_code)]

#![deny(warnings)]

#![no_main]

#![no_std]

use panic_semihosting as _;

#[rtic::app(device = lm3s6965, dispatchers = [SSI0])]

mod app {

use cortex_m_semihosting::{debug, hprintln};

#[shared]

struct Shared {}

#[local]

struct Local {}

#[init]

fn init(_: init::Context) -> (Shared, Local, init::Monotonics) {

foo::spawn(/* no message */).unwrap();

(Shared {}, Local {}, init::Monotonics())

}

#[task(local = [count: u32 = 0])]

fn foo(cx: foo::Context) {

hprintln!("foo").unwrap();

bar::spawn(*cx.local.count).unwrap();

*cx.local.count += 1;

}

#[task]

fn bar(_: bar::Context, x: u32) {

hprintln!("bar({})", x).unwrap();

baz::spawn(x + 1, x + 2).unwrap();

}

#[task]

fn baz(_: baz::Context, x: u32, y: u32) {

hprintln!("baz({}, {})", x, y).unwrap();

if x + y > 4 {

debug::exit(debug::EXIT_SUCCESS);

}

foo::spawn().unwrap();

}

}

}

$ cargo run --example message

foo

bar(0)

baz(1, 2)

foo

bar(1)

baz(2, 3)

RTIC не производит никакого рода аллокаций памяти в куче. Память, необходимая для размещения сообщения резервируется статически. По-умолчанию фреймворк минимизирует выделение памяти программой таким образом, что каждая задача имеет "вместимость" для сообщения равную 1: это значит, что не более одного сообщения можно передать задаче перед тем, как у нее появится возможность к запуску. Это значение по-умолчанию можно изменить для каждой задачи, используя аргумент capacity. Этот аргумент принимает положительное целое, которое определяет как много сообщений буфер сообщений задачи может хранить.

Пример ниже устанавливает вместимость программной задачи foo равной 4. Если вместимость не установить, второй вызов spawn.foo в UART0 приведет к ошибке (панике).

#![allow(unused)]

fn main() {

//! examples/capacity.rs

#![deny(unsafe_code)]

#![deny(warnings)]

#![no_main]

#![no_std]

use panic_semihosting as _;

#[rtic::app(device = lm3s6965, dispatchers = [SSI0])]

mod app {

use cortex_m_semihosting::{debug, hprintln};

use lm3s6965::Interrupt;

#[shared]

struct Shared {}

#[local]

struct Local {}

#[init]

fn init(_: init::Context) -> (Shared, Local, init::Monotonics) {

rtic::pend(Interrupt::UART0);

(Shared {}, Local {}, init::Monotonics())

}

#[task(binds = UART0)]

fn uart0(_: uart0::Context) {

foo::spawn(0).unwrap();

foo::spawn(1).unwrap();

foo::spawn(2).unwrap();

foo::spawn(3).unwrap();

bar::spawn().unwrap();

}

#[task(capacity = 4)]

fn foo(_: foo::Context, x: u32) {

hprintln!("foo({})", x).unwrap();

}

#[task]

fn bar(_: bar::Context) {

hprintln!("bar").unwrap();

debug::exit(debug::EXIT_SUCCESS);