aboutsummaryrefslogtreecommitdiff
path: root/book/ru/src/by-example/tips.md
diff options
context:
space:
mode:
Diffstat (limited to 'book/ru/src/by-example/tips.md')
-rw-r--r--book/ru/src/by-example/tips.md142
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}}
+```