diff options
Diffstat (limited to 'book/ru/src/by-example/tips.md')
| -rw-r--r-- | book/ru/src/by-example/tips.md | 142 |
1 files changed, 116 insertions, 26 deletions
diff --git a/book/ru/src/by-example/tips.md b/book/ru/src/by-example/tips.md index 249e8f4..cf66c4b 100644 --- a/book/ru/src/by-example/tips.md +++ b/book/ru/src/by-example/tips.md @@ -2,10 +2,15 @@ ## Обобщенное программирование (Generics) -Ресурсы, совместно используемые двумя или более задачами, реализуют трейт `Mutex` -во *всех* контекстах, даже в тех, где для доступа к данным не требуются -критические секции. Это позволяет легко писать обобщенный код оперирующий -ресурсами, который можно вызывать из различных задач. Вот такой пример: +Все объекты, предоставляющие ресурысы реализуют трейт `rtic::Mutex`. +Если ресурс не реализует его, можно обернуть его в новый тип [`rtic::Exclusive`], +который реализует трейт `Mutex`. С помощью этого нового типа +можно написать обобщенную функцию, которая работает с обобщенным ресурсом и +вызывать его из различных задач, чтобы производить однотипные операции над +похожим множеством ресурсов. +Вот один такой пример: + +[`rtic::Exclusive`]: ../../../api/rtic/struct.Exclusive.html ``` rust {{#include ../../../../examples/generics.rs}} @@ -13,12 +18,29 @@ ``` console $ cargo run --example generics -{{#include ../../../../ci/expected/generics.run}}``` +{{#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 -Это также позволяет Вам изменять статические приоритеты задач без -переписывания кода. Если Вы единообразно используете `lock`-и для доступа -к данным в разделяемых ресурсах, тогда Ваш код продолжит компилироваться, -когда Вы измените приоритет задач. +$ cargo run --example cfg +{{#include ../../../../ci/expected/cfg.run}} +``` ## Запуск задач из ОЗУ @@ -31,10 +53,10 @@ RTIC v0.4.x была возможность взаимодействия с др > очень мощные, но их легко использовать неправильно. Неверное использование > любого из этих атрибутов может вызвать неопределенное поведение; > Вам следует всегда предпочитать использование безопасных, высокоуровневых -> атрибутов вокруг них, таких как атрибуты `interrupt` и `exception` +> атрибутов вместо них, таких как атрибуты `interrupt` и `exception` > из `cortex-m-rt`. > -> В особых случаях функций RAM нет безопасной абстракции в `cortex-m-rt` +> В особых функций, размещаемых в ОЗУ нет безопасной абстракции в `cortex-m-rt` > v0.6.5 но создано [RFC] для добавления атрибута `ramfunc` в будущем релизе. [RFC]: https://github.com/rust-embedded/cortex-m-rt/pull/100 @@ -45,37 +67,105 @@ RTIC v0.4.x была возможность взаимодействия с др {{#include ../../../../examples/ramfunc.rs}} ``` -Запуск этой программы произведет ожидаемый вывод. +Запуск этой программы создаст ожидаемый вывод. ``` console $ cargo run --example ramfunc -{{#include ../../../../ci/expected/ramfunc.run}}``` +{{#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}}``` +{{#include ../../../../ci/expected/ramfunc.grep.foo}} +``` ``` console $ cargo nm --example ramfunc --release | grep ' bar::' -{{#include ../../../../ci/expected/ramfunc.grep.bar}}``` +{{#include ../../../../ci/expected/ramfunc.grep.bar}} +``` + +## Обходной путь для быстрой передачи сообщений -## `binds` +Передача сообщений всегда вызывает копирование от отправителя в +статическую переменную, а затем из статической переменной получателю. +Таким образом, при передаче большого буфера, например `[u8; 128]`, передача сообщения +вызывает два дорогих вызова `memcpy`. Чтобы минимизировать накладные расходы на передачу +сообщения, можно использовать обходной путь: вместо передачи буфера по значению, +можно передавать владеющий указатель на буфер. -**ПРИМЕЧАНИЕ**: Требуется RTIC не ниже 0.4.2 +Можно использовать глобальный аллокатор, чтобы реализовать данный трюк (`alloc::Box`, +`alloc::Rc`, и т.п.), либо использовать статически аллоцируемый пул памяти, например [`heapless::Pool`]. -Вы можете давать аппаратным задачам имена похожие на имена обычных задач. -Для этого нужно использовать аргумент `binds`: Вы называете функцию -по своему желанию и назначаете ей прерывание / исключение -через аргумент `binds`. `Spawn` и другие служебные типы будут размещены в модуле, -названном в соответствии с названием функции, а не прерывания / исключения. -Давайте посмотрим пример: +[`heapless::Pool`]: https://docs.rs/heapless/0.5.0/heapless/pool/index.html + +Здесь приведен пример использования `heapless::Pool` для "упаковки" буфера из 128 байт. ``` rust -{{#include ../../../../examples/binds.rs}} +{{#include ../../../../examples/pool.rs}} ``` + ``` console -$ cargo run --example binds -{{#include ../../../../ci/expected/binds.run}}```
\ No newline at end of file +$ 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}} +``` |
