# Советы и хитрости ## Обобщенное программирование (Generics) Все объекты, предоставляющие ресурысы реализуют трейт `rtic::Mutex`. Если ресурс не реализует его, можно обернуть его в новый тип [`rtic::Exclusive`], который реализует трейт `Mutex`. С помощью этого нового типа можно написать обобщенную функцию, которая работает с обобщенным ресурсом и вызывать его из различных задач, чтобы производить однотипные операции над похожим множеством ресурсов. Вот один такой пример: [`rtic::Exclusive`]: ../../../api/rtic/struct.Exclusive.html ``` rust {{#include ../../../../examples/generics.rs}} ``` ``` console $ cargo run --example generics {{#include ../../../../ci/expected/generics.run}} ``` ## Условная компиляция Вы можете использовать условную компиляцию (`#[cfg]`) на ресурсах (полях структуры `#[resources] struct Resources`) и задачах (элементах `fn`). Эффект использования атрибутов `#[cfg]` в том, что ресурс/ задача будут *не* доступны в соответствующих структурах `Context` если условие не выполняется. В примере ниже выводится сообщение каждый раз, когда вызывается задача `foo`, но только если программы скомпилирова с профилем `dev`. ``` rust {{#include ../../../../examples/cfg.rs}} ``` ``` console $ cargo run --example cfg --release $ cargo run --example cfg {{#include ../../../../ci/expected/cfg.run}} ``` ## Запуск задач из ОЗУ Главной целью переноса описания программы на RTIC в атрибуты в RTIC v0.4.x была возможность взаимодействия с другими атрибутами. Напримерe, атрибут `link_section` можно применять к задачам, чтобы разместить их в ОЗУ; это может улучшить производительность в некоторых случаях. > **ВАЖНО**: Обычно атрибуты `link_section`, `export_name` и `no_mangle` > очень мощные, но их легко использовать неправильно. Неверное использование > любого из этих атрибутов может вызвать неопределенное поведение; > Вам следует всегда предпочитать использование безопасных, высокоуровневых > атрибутов вместо них, таких как атрибуты `interrupt` и `exception` > из `cortex-m-rt`. > > В особых функций, размещаемых в ОЗУ нет безопасной абстракции в `cortex-m-rt` > v0.6.5 но создано [RFC] для добавления атрибута `ramfunc` в будущем релизе. [RFC]: https://github.com/rust-embedded/cortex-m-rt/pull/100 В примере ниже показано как разместить высокоприоритетную задачу `bar` в ОЗУ. ``` rust {{#include ../../../../examples/ramfunc.rs}} ``` Запуск этой программы создаст ожидаемый вывод. ``` console $ cargo run --example ramfunc {{#include ../../../../ci/expected/ramfunc.run}} ``` Можно посмотреть на вывод `cargo-nm`, чтобы убедиться, что `bar` расположен в ОЗУ (`0x2000_0000`), тогда как `foo` расположен во Flash (`0x0000_0000`). ``` console $ cargo nm --example ramfunc --release | grep ' foo::' {{#include ../../../../ci/expected/ramfunc.grep.foo}} ``` ``` console $ cargo nm --example ramfunc --release | grep ' bar::' {{#include ../../../../ci/expected/ramfunc.grep.bar}} ``` ## Обходной путь для быстрой передачи сообщений Передача сообщений всегда вызывает копирование от отправителя в статическую переменную, а затем из статической переменной получателю. Таким образом, при передаче большого буфера, например `[u8; 128]`, передача сообщения вызывает два дорогих вызова `memcpy`. Чтобы минимизировать накладные расходы на передачу сообщения, можно использовать обходной путь: вместо передачи буфера по значению, можно передавать владеющий указатель на буфер. Можно использовать глобальный аллокатор, чтобы реализовать данный трюк (`alloc::Box`, `alloc::Rc`, и т.п.), либо использовать статически аллоцируемый пул памяти, например [`heapless::Pool`]. [`heapless::Pool`]: https://docs.rs/heapless/0.5.0/heapless/pool/index.html Здесь приведен пример использования `heapless::Pool` для "упаковки" буфера из 128 байт. ``` rust {{#include ../../../../examples/pool.rs}} ``` ``` console $ cargo run --example pool {{#include ../../../../ci/expected/pool.run}} ``` ## Инспектирование раскрываемого кода `#[rtic::app]` - это процедурный макрос, который создает код. Если по какой-то причине вам нужно увидеть код, сгенерированный этим макросом, у вас есть два пути: Вы можете изучить файл `rtic-expansion.rs` внутри папки `target`. Этот файл содержит элемент `#[rtic::app]` в раскрытом виде (не всю вашу программу!) из *последней сборки* (с помощью `cargo build` или `cargo check`) RTIC программы. Раскрытый код не отформатирован по-умолчанию, но вы можете запустить `rustfmt` на нем перед тем, как читать. ``` console $ cargo build --example foo $ rustfmt target/rtic-expansion.rs $ tail target/rtic-expansion.rs ``` ``` rust #[doc = r" Implementation details"] mod app { #[doc = r" Always include the device crate which contains the vector table"] use lm3s6965 as _; #[no_mangle] unsafe extern "C" fn main() -> ! { rtic::export::interrupt::disable(); let mut core: rtic::export::Peripherals = core::mem::transmute(()); core.SCB.scr.modify(|r| r | 1 << 1); rtic::export::interrupt::enable(); loop { rtic::export::wfi() } } } ``` Или, вы можете использовать подкоманду [`cargo-expand`]. Она раскроет *все* макросы, включая атрибут `#[rtic::app]`, и модули в вашем крейте и напечатает вывод в консоль. [`cargo-expand`]: https://crates.io/crates/cargo-expand ``` console $ # создаст такой же вывод, как выше $ cargo expand --example smallest | tail ``` ## Деструктуризация ресурса Если задача требует нескольких ресурсов, разбиение структуры ресурсов может улучшить читабельность. Вот два примера того, как это можно сделать: ``` rust {{#include ../../../../examples/destructure.rs}} ```