• Игнорирование результата. В программах реального времени, как и в обычных, может быть нормальным иногда терять данные, или не получать ответ на некоторые события в пиковых ситуациях. В таких сценариях может быть допустимо игнорирование ошибки вызова spawn.
Следует отметить, что повторная попытка вызова spawn обычно неверный подход, поскольку такая операция на практике вероятно никогда не завершится успешно. Так как у нас есть только переключения контекста на задачи с
#![allow(unused)]
fn main() {
#[rtic::app(..)]
mod app {
#[init(spawn = [foo, bar])]
fn init(cx: init::Context) {
cx.spawn.foo().unwrap();
cx.spawn.bar().unwrap();
}
#[task(priority = 2, spawn = [bar])]
fn foo(cx: foo::Context) {
while cx.spawn.bar(payload).is_err() {
}
}
#[task(priority = 1)]
fn bar(cx: bar::Context, payload: i32) {
}
}
}
В отличие от интерфейса spawn, который немедленно передает программную задачу планировщику для немедленного запуска, интерфейс schedule можно использовать для планирования задачи к запуске через какое-то время в будущем.
Чтобы использовать интерфейс schedule, предварительно должен быть определен монотонный таймер с помощью аргумента monotonic атрибута #[app]. Этот аргумент принимает путь к типу, реализующему трейт Monotonic. Ассоциированный тип, Instant, этого трейта представляет метку времени в соответствущих единицах измерения и широко используется в интерфейсе schedule -- предлагается смоделировать этот тип позднее один из таких есть в стандартной библиотеке.
Хотя это не отражено в определении трейта (из-за ограничений системы типов / трейтов), разница двух Instantов должна возвращать какой-то тип Duration (см. core::time::Duration) и этот Duration должен реализовывать трейт TryInto
Для целевых платформ ARMv7+ крейт rtic предоставляет реализацию Monotonic, основанную на встроенном CYCle CouNTer (CYCCNT). Заметьте, что это 32-битный таймер, работающий на частоте центрального процессора, и поэтому не подходит для отслеживания интервалов времени в секундах.
Когда планируется задача, (определенный пользователем) Instant, в который задача должна быть выполнена, должен передаваться в качестве первого аргумента вызова schedule.
К тому же, выбранный monotonic таймер, необходимо сконфигурировать и инициализировать в фазе работы #[init]. Заметьте, что
Пример ниже планирует к выполнению две задачи из init: foo и bar. foo запланирована к запуску через 8 миллионов циклов в будущем. Далее, bar запланировано запустить через 4 миллиона циклов в будущем. Таким образом, bar запустится до foo, так как и запланировано.
DF:YJ: Примеры, использующие интерфейс schedule или абстракцию Instant не будут правильно работать на эмуляторе QEMU, поскольку счетчик циклов Cortex-M функционально не был реализован в qemu-system-arm.
#![allow(unused)]
fn main() {
#![deny(unsafe_code)]
#![deny(warnings)]
#![no_main]
#![no_std]
use panic_semihosting as _;
#[rtic::app(device = lm3s6965, dispatchers = [SSI0])]
mod app {