aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Andrey Zgarbul <zgarbul.andrey@gmail.com> 2021-08-03 22:40:33 +0300
committerGravatar Andrey Zgarbul <zgarbul.andrey@gmail.com> 2021-08-03 22:40:33 +0300
commit9134f7d36a46032e7223ebed45b4bc7b2eea5fd3 (patch)
treed5b377b3121b0f3139f2253328b70057fad0a8eb
parent8ddfcf8efc1f9005fad6ea4bbd4956348c606405 (diff)
downloadrtic-9134f7d36a46032e7223ebed45b4bc7b2eea5fd3.tar.gz
rtic-9134f7d36a46032e7223ebed45b4bc7b2eea5fd3.tar.zst
rtic-9134f7d36a46032e7223ebed45b4bc7b2eea5fd3.zip
update russian book
-rw-r--r--README_ru.md6
-rw-r--r--book/ru/src/by-example/app.md8
-rw-r--r--book/ru/src/by-example/resources.md87
-rw-r--r--book/ru/src/by-example/tips.md4
-rw-r--r--book/ru/src/internals/late-resources.md3
-rw-r--r--book/ru/src/internals/tasks.md10
-rw-r--r--book/ru/src/migration/migration_v5.md289
7 files changed, 285 insertions, 122 deletions
diff --git a/README_ru.md b/README_ru.md
index 918d03e3..49e66d1d 100644
--- a/README_ru.md
+++ b/README_ru.md
@@ -50,10 +50,16 @@
- Приложения должны быть написаны в редакции 2018.
+## [Руководство пользователя](https://rtic.rs) - [(Версия в разработке)](https://rtic.rs/dev)
+
## [Документация пользователя](https://rtic.rs)
## [Справочник по API](https://rtic.rs/stable/api/)
+## [Сборник примеров, предоставляемы сообществом][examples]
+
+[examples]: https://github.com/rtic-rs/rtic-examples
+
## Чат
Присоединяйтесь к нам, чтобы говорить о RTIC [в Matrix-комнате][matrix-room].
diff --git a/book/ru/src/by-example/app.md b/book/ru/src/by-example/app.md
index 628819ad..5beca239 100644
--- a/book/ru/src/by-example/app.md
+++ b/book/ru/src/by-example/app.md
@@ -23,7 +23,7 @@
Внутри модуля `app` атрибут ожидает найти функцию инициализации, помеченную
атрибутом `init`. Эта функция должна иметь сигнатуру
-`fn(init::Context) [-> init::LateResources]` (возвращаемый тип нужен не всегда).
+`fn(init::Context) (-> init::LateResources, init::Monotonics)`.
Эта функция инициализации будет первой частью программы, выполняемой при запуске.
Функция `init` будет запущена *с отключенными прерываниями* и будет иметь эксклюзивный доступ
@@ -54,6 +54,12 @@ $ cargo run --example init
{{#include ../../../../ci/expected/init.run}}
```
+> **ПРИМЕЧАНИЕ**: Не забывайте указывать выбранное вами целевое устройство, передавая параметр target
+> в cargo (например `cargo run --example init --target thumbv7m-none-eabi`) или
+> настроив устройство, используемое по умолчанию для сборки примеров в `.cargo/config.toml`.
+> В нашем случае используется Cortex M3, эмулируемый с помощью QEMU, поэтому пишем `thumbv7m-none-eabi`.
+> Смотрите [`Создание нового проекта`](./new.md) для большей информации.
+
## `idle`
Функцию, помеченную атрибутом `idle` может опционально добавить в модуль.
diff --git a/book/ru/src/by-example/resources.md b/book/ru/src/by-example/resources.md
index 70f798d2..ed8904ba 100644
--- a/book/ru/src/by-example/resources.md
+++ b/book/ru/src/by-example/resources.md
@@ -7,21 +7,26 @@
Фреймворк дает пользователю полный контроль за тем, какой контекст может
получить доступ к какому ресурсу.
-Все ресурсы определены в одной структуре внутри модуля `#[app]`.
-Каждое поле структуры соответствует отдельному ресурсу.
-`struct`-ура должна быть аннотирована следующим атрибутом: `#[resources]`.
-
-Ресурсам могут быть опционально даны начальные значения с помощью атрибута `#[init]`.
-Ресурсы, которым не передано начально значение, называются
-*поздними* ресурсами, более детально они описаны в одном из разделов на этой странице.
+Все ресурсы определены в *двух* структурах внутри модуля `#[app]`.
+Каждое поле этих структур соответствует отдельному ресурсу.
+Одна `struct`-ура должна быть аннотирована атрибутом `#[local]`.
+Другая `struct`-ура должна быть аннотирована атрибутом `#[shared]`.
+Разница между этими двумя множествами ресурсов будет описана познее.
Каждый контекс (задача-обработчик, `init` или `idle`) должен указать ресурсы, к которым
он намерен обращаться, в соответсятвующем ему атрибуте с метаданными, используя
-аргумент `resources`. Этот аргумент принимает список имен ресурсов в качестве значения.
-Перечисленные ресурсы становятся доступны в контексте через поле `resources` структуры `Context`.
+либо аргумент `local`, либо `shared`. Этот аргумент принимает список имен ресурсов в качестве значения.
+Перечисленные ресурсы становятся доступны в контексте через поля `local` и `shared` структуры `Context`.
+
+Во время выполнения при выходе из функции `#[init]` все ресурсы инициализированы.
+Функция `#[init]` должна возвращать начальные значения для всех ресурсов;
+отсюда следует, что тип возвращаемого ею значения включает типы
+структур `#[shared]` и `#[local]`.
+Поскольку ресурсы инициализированы в ходе функции `#[init]`, к ним нельзя
+получить доступ внетри функции `#[init]`.
-Пример программы, показанной ниже содержит два обработчика прерывания, которые разделяют
-доступ к ресурсу под названием `shared`.
+Пример программы, показанной ниже содержит два обработчика прерывания.
+Каждый обработчик имеет доступ к его собственному `#[local]` ресурсу.
``` rust
{{#include ../../../../examples/resource.rs}}
@@ -32,15 +37,17 @@ $ cargo run --example resource
{{#include ../../../../ci/expected/resource.run}}
```
-Заметьте, что к ресурсу `shared` нельзя получить доступ из `idle`. Попытка сделать это
-приведет к ошибке компиляции.
+К ресурсу `#[local]` нельзя получить доступ извне задачи к которой он
+привязан атрибутом `#[task]`.
+Попытка обращения к одному и тому же ресурсу `#[local]` из более чем одной
+задачи - ошибка компиляции.
## `lock`
-Критические секции необходимы для разделения изменяемых данных таким образом,
+Критические секции необходимы для доступа к ресурсам `#[shared]` таким образом,
чтобы избежать гонок данных.
-Поле `resources`, передаваемого `Context` реализует трейт [`Mutex`] для каждого разделяемого
+Поле `shared`, передаваемого `Context` реализует трейт [`Mutex`] для каждого разделяемого
ресурса, доступного задаче.
Единственный метод этого трейта, [`lock`], запускает свой аргумент-замыкание в критической секции.
@@ -81,33 +88,7 @@ $ cargo run --example lock
{{#include ../../../../examples/multilock.rs}}
```
-## Поздние ресурсы
-
-Поздние ресурсы - такие ресурсы, которым не передано начальное значение во время компиляции
-с помощью атрибута `#[init]`, но которые вместо этого инициализируются во время выполнения
-с помощью значений из структуры `init::LateResources`, возвращаемой функцией `init`.
-
-Поздние ресурсы полезны, например, для *move* (передача владения) периферии,
-инициализированной в `init`, в задачи.
-
-Пример ниже использует поздние ресурсы, чтобы установить неблокируемый односторонний канал
-между обработчиком прерывания `UART0` и задачей `idle`. Для канала использована очередь типа
-один производитель-один потребитель [`Queue`]. Структура очереди разделяется на потребителя
-и производителя в `init`, а затем каждая из частей располагается в отдельном ресурсу;
-`UART0` владеет ресурсом производителя, а `idle` владеет ресурсом потребителя.
-
-[`Queue`]: ../../../api/heapless/spsc/struct.Queue.html
-
-``` rust
-{{#include ../../../../examples/late.rs}}
-```
-
-``` console
-$ cargo run --example late
-{{#include ../../../../ci/expected/late.run}}
-```
-
-## Только разделяемый доступ
+## Только разделяемый (`&-`) доступ
По-умолчанию фреймворк предполагает, что все задачи требуют эксклюзивный доступ (`&mut-`) к ресурсам,
но возможно указать, что задаче достаточен разделяемый доступ (`&-`) к ресурсы с помощью синтакисиса
@@ -139,11 +120,21 @@ $ cargo run --example only-shared-access
## Неблокируемый доступ к изменяемым ресурсам
-Есть две других возможности доступа к ресурсам
+Критическая секция *не* требуется для доступа к ресурсу `#[shared]`,
+к которому обращаются только из задач с *одинаковым* приоритетом.
+В этом случае вы можете избежать `lock` API, добавив атрибут поля `#[lock_free]` при объявдении ресурса (смотреть пример ниже).
+Заметьте, что это лишь для удобства: даже если вы используете `lock` API,
+во время выполнения фреймворк *не* создаст критическую секцию.
+Еще одно ценное замечание: использование `#[lock_free]` на ресурсах,
+разделяемых задачами, запускаемыми с разными приоритетами
+приведет к ошибке *компиляции* -- не импользование `lock` API может
+привести к гонке данных в этом случае.
-* `#[lock_free]`: могут быть несколько задач с одинаковым приоритетом,
- получающие доступ к ресурсу без критических секций. Так как задачи с
- одинаковым приоритетом никогда не могут вытеснить друг друга, это безопасно.
-* `#[task_local]`: в этом случае должна быть только одна задача, использующая
- этот ресурс, так же как локальный `static mut` ресурс задачи, но (опционально) устанавливаемая с в init.
+``` rust
+{{#include ../../../../examples/lock-free.rs}}
+```
+``` console
+$ cargo run --example lock-free
+{{#include ../../../../ci/expected/lock-free.run}}
+``` \ No newline at end of file
diff --git a/book/ru/src/by-example/tips.md b/book/ru/src/by-example/tips.md
index cf66c4b7..f19cfee9 100644
--- a/book/ru/src/by-example/tips.md
+++ b/book/ru/src/by-example/tips.md
@@ -1,5 +1,9 @@
# Советы и хитрости
+Полные примеры для RTIC смотрите в репозитарии [rtic-examples][rtic-examples].
+
+[rtic-examples]: https://github.com/rtic-rs/rtic-examples
+
## Обобщенное программирование (Generics)
Все объекты, предоставляющие ресурысы реализуют трейт `rtic::Mutex`.
diff --git a/book/ru/src/internals/late-resources.md b/book/ru/src/internals/late-resources.md
index 0fad0aec..146c438d 100644
--- a/book/ru/src/internals/late-resources.md
+++ b/book/ru/src/internals/late-resources.md
@@ -103,8 +103,7 @@ mod app {
}
```
-Важная деталь здесь то, что `interrupt::enable` ведет себя как like a *compiler
-fence*, которое не дает компилятору пореставить запись в `X` *после*
+Важная деталь здесь то, что `interrupt::enable` ведет себя как *барьер компиляции*, который не дает компилятору переставить запись в `X` *после*
`interrupt::enable`. Если бы компилятор мог делать такие перестановки появились
бы гонки данных между этой записью и любой операцией `foo`, взаимодействующей с `X`.
diff --git a/book/ru/src/internals/tasks.md b/book/ru/src/internals/tasks.md
index 66503251..01380ba9 100644
--- a/book/ru/src/internals/tasks.md
+++ b/book/ru/src/internals/tasks.md
@@ -79,8 +79,8 @@ mod app {
}
// очередь готовности диспетчера задач
- // `U4` - целое число, представляющее собой емкость этой очереди
- static mut RQ1: Queue<Ready<T1>, U4> = Queue::new();
+ // `5-1=4` - представляет собой емкость этой очереди
+ static mut RQ1: Queue<Ready<T1>, 5> = Queue::new();
// обработчик прерывания, выбранный для диспетчеризации задач с приоритетом `1`
#[no_mangle]
@@ -151,9 +151,9 @@ mod app {
const RQ1_CEILING: u8 = 2;
// используется, чтобы отследить сколько еще сообщений для `bar` можно поставить в очередь
- // `U2` - емкость задачи `bar`; максимум 2 экземпляра можно добавить в очередь
+ // `3-1=2` - емкость задачи `bar`; максимум 2 экземпляра можно добавить в очередь
// эта очередь заполняется фреймворком до того, как запустится `init`
- static mut bar_FQ: Queue<(), U2> = Queue::new();
+ static mut bar_FQ: Queue<(), 3> = Queue::new();
// Поиск максимального приоритета для конечного потребителя `bar_FQ`
const bar_FQ_CEILING: u8 = 2;
@@ -227,7 +227,7 @@ mod app {
// список свободной памяти: используется для отслеживания свободных ячеек в массиве `baz_INPUTS`
// эта очередь инициализируется значениями `0` и `1` перед запуском `init`
- static mut baz_FQ: Queue<u8, U2> = Queue::new();
+ static mut baz_FQ: Queue<u8, 3> = Queue::new();
// Поиск максимального приоритета для конечного потребителя `baz_FQ`
const baz_FQ_CEILING: u8 = 2;
diff --git a/book/ru/src/migration/migration_v5.md b/book/ru/src/migration/migration_v5.md
index 04aedc5f..870c20fd 100644
--- a/book/ru/src/migration/migration_v5.md
+++ b/book/ru/src/migration/migration_v5.md
@@ -30,7 +30,46 @@ mod app {
Так как теперь используется обычный модуль Rust, это значит, что можно использовать
обычный пользовательский код в этом модуле.
-Также жто значит, что `use`-выражения для ресурсов (и т.п.) могут понадобиться.
+Также это значит, что `use`-выражения для ресурсов, используемые
+в пользовательском коде должны быть перемещены внутрь `mod app`,
+либо на них можно сослаться с помощью `super`. Например, измените:
+
+```rust
+use some_crate::some_func;
+
+#[rtic::app(/* .. */)]
+const APP: () = {
+ fn func() {
+ some_crate::some_func();
+ }
+};
+```
+
+на
+
+```rust
+#[rtic::app(/* .. */)]
+mod app {
+ use some_crate::some_func;
+
+ fn func() {
+ some_crate::some_func();
+ }
+}
+```
+
+или
+
+```rust
+use some_crate::some_func;
+
+#[rtic::app(/* .. */)]
+mod app {
+ fn func() {
+ super::some_crate::some_func();
+ }
+}
+```
## Перенос диспетчеров из `extern "C"` в аргументы app.
@@ -63,137 +102,255 @@ mod app {
Это работает и для ОЗУ-функций, см. examples/ramfunc.rs
-## Init всегда возвращает поздние ресурсы
+## Структуры ресурсов - `#[shared]`, `#[local]`
-С целью сделать API более симметричным задача #[init] всегда возвращает поздние ресурсы.
+Ранее ресурсы RTIC должны были размещаться в структуре с именем "Resources":
-С этого:
+``` rust
+struct Resources {
+ // Ресурсы определяются здесь
+}
+```
+
+Начиная с RTIC v0.6.0 структуры ресурсов аннотируются подобно
+`#[task]`, `#[init]`, `#[idle]`: аттрибутами `#[shared]` и `#[local]`
``` rust
-#[rtic::app(device = lm3s6965)]
-mod app {
- #[init]
- fn init(_: init::Context) {
- rtic::pend(Interrupt::UART0);
- }
+#[shared]
+struct MySharedResources {
+ // Разделяемые задачами ресурсы определены здесь
+}
- // [еще код]
+#[local]
+struct MyLocalResources {
+ // Ресурсы, определенные здесь нельзя передавать между задачами; каждый из них локальный для единственной задачи
}
```
-на это:
+Эти структуры разработчик может называть по своему желанию.
+
+## `shared` и `local` аргументы в `#[task]`'ах
+
+В v0.6.0 ресурсы разделены на `shared` ресурсы и `local` ресурсы.
+`#[task]`, `#[init]` и `#[idle]` больше не имеют аргумента `resources`;
+они должны использовать аргументы `shared` и `local`.
+
+В v0.5.x:
``` rust
-#[rtic::app(device = lm3s6965)]
-mod app {
- #[init]
- fn init(_: init::Context) -> init::LateResources {
- rtic::pend(Interrupt::UART0);
+struct Resources {
+ local_to_b: i64,
+ shared_by_a_and_b: i64,
+}
- init::LateResources {}
- }
+#[task(resources = [shared_by_a_and_b])]
+fn a(_: a::Context) {}
- // [еще код]
+#[task(resources = [shared_by_a_and_b, local_to_b])]
+fn b(_: b::Context) {}
+```
+
+В v0.6.0:
+
+``` rust
+#[shared]
+struct Shared {
+ shared_by_a_and_b: i64,
}
+
+#[local]
+struct Local {
+ local_to_b: i64,
+}
+
+#[task(shared = [shared_by_a_and_b])]
+fn a(_: a::Context) {}
+
+#[task(shared = [shared_by_a_and_b], local = [local_to_b])]
+fn b(_: b::Context) {}
```
-## Структура Resources - `#[resources]`
+## Симметричные блокировки
-Ранее ресурсы RTIC должны были располагаться в структуре с именем "Resources":
+Теперь RTIC использует симметричные блокировки, это значит, что метод `lock` нужно использовать для
+всех доступов к `shared` ресурсам. Поскольку высокоприоритетные задачи имеют эксклюзивный доступ к ресурсу,
+в старом коде можно было следующее:
``` rust
-struct Resources {
- // Ресурсы определены здесь
+#[task(priority = 2, resources = [r])]
+fn foo(cx: foo::Context) {
+ cx.resources.r = /* ... */;
+}
+
+#[task(resources = [r])]
+fn bar(cx: bar::Context) {
+ cx.resources.r.lock(|r| r = /* ... */);
}
```
-В RTIC v0.6.0 структура ресурсов аннотируется также, как и
-`#[task]`, `#[init]`, `#[idle]`: атрибутом `#[resources]`
+С симметричными блокировками нужно вызывать `lock` для обоих задач:
``` rust
-#[resources]
-struct Resources {
- // Ресурсы определены здесь
+#[task(priority = 2, shared = [r])]
+fn foo(cx: foo::Context) {
+ cx.shared.r.lock(|r| r = /* ... */);
+}
+
+#[task(shared = [r])]
+fn bar(cx: bar::Context) {
+ cx.shared.r.lock(|r| r = /* ... */);
}
```
-На самом деле, имя структуры предоставлено на усмотрение разработчика:
+Заметьте, что скорость работы не изменяется благодаря оптимизациям LLVM, которые убирают ненужные блокировки.
+
+## Неблокирующий доступ к ресурсам
+
+В RTIC 0.5 к ресурсам разделяемым задачами, запускаемыми с одинаковым
+приоритетом, можно получить доступ *без* `lock` API.
+Это все еще возможно в 0.6: ресурс `#[shared]` должен быть аннотирован
+аттрибутом поля `#[lock_free]`.
+
+v0.5 код:
``` rust
-#[resources]
-struct Whateveryouwant {
- // Ресурсы определены здесь
+struct Resources {
+ counter: u64,
+}
+
+#[task(resources = [counter])]
+fn a(cx: a::Context) {
+ *cx.resources.counter += 1;
+}
+
+#[task(resources = [counter])]
+fn b(cx: b::Context) {
+ *cx.resources.counter += 1;
}
```
-будет работать так же хороршо.
+v0.6 код:
-## Вызов/планирование откуда угодно
+``` rust
+#[shared]
+struct Shared {
+ #[lock_free]
+ counter: u64,
+}
-С этой новой возвожностью, старый код, такой как:
+#[task(shared = [counter])]
+fn a(cx: a::Context) {
+ *cx.shared.counter += 1;
+}
+
+#[task(shared = [counter])]
+fn b(cx: b::Context) {
+ *cx.shared.counter += 1;
+}
+```
+
+## нет преобразования `static mut`
+`static mut` переменные больше не преобразуются в безопасные `&'static mut` ссылки.
+Вместо этого синтаксиса используйте аргумент `local` в `#[init]`.
+
+v0.5.x code:
``` rust
-#[task(spawn = [bar])]
-fn foo(cx: foo::Context) {
- cx.spawn.bar().unwrap();
+#[init]
+fn init(_: init::Context) {
+ static mut BUFFER: [u8; 1024] = [0; 1024];
+ let buffer: &'static mut [u8; 1024] = BUFFER;
}
+```
-#[task(schedule = [bar])]
-fn bar(cx: bar::Context) {
- cx.schedule.foo(/* ... */).unwrap();
+v0.6.0 code:
+
+``` rust
+#[init(local = [
+ buffer: [u8; 1024] = [0; 1024]
+// type ^^^^^^^^^^^^ ^^^^^^^^^ initial value
+])]
+fn init(cx: init::Context) -> (Shared, Local, init::Monotonics) {
+ let buffer: &'static mut [u8; 1024] = cx.local.buffer;
+
+ (Shared {}, Local {}, init::Monotonics())
}
```
-Теперь будет выглядеть так:
+## Init всегда возвращает поздние ресурсы
+
+С целью сделать API более симметричным задача #[init] всегда возвращает поздние ресурсы.
+
+С этого:
``` rust
-#[task]
-fn foo(_c: foo::Context) {
- bar::spawn().unwrap();
+#[rtic::app(device = lm3s6965)]
+mod app {
+ #[init]
+ fn init(_: init::Context) {
+ rtic::pend(Interrupt::UART0);
+ }
+
+ // [еще код]
}
+```
-#[task]
-fn bar(_c: bar::Context) {
- foo::schedule(/* ... */).unwrap();
+на это:
+
+
+``` rust
+#[rtic::app(device = lm3s6965)]
+mod app {
+ #[shared]
+ struct MySharedResources {}
+
+ #[local]
+ struct MyLocalResources {}
+
+ #[init]
+ fn init(_: init::Context) -> (MySharedResources, MyLocalResources, init::Monotonics) {
+ rtic::pend(Interrupt::UART0);
+
+ (MySharedResources, MyLocalResources, init::Monotonics())
+ }
+
+ // [more code]
}
```
-Заметьте, что атрибуты `spawn` и `schedule` больше не нужны.
+## Вызов/планирование откуда угодно
-## Симметричные блокировки
+С этой новой возвожностью, старый код, такой как:
-Теперь RTIC использует симметричные блокировки, это значит, что метод `lock` нужно использовать для
-всех доступов к ресурсам. Поскольку высокоприоритетные задачи имеют эксклюзивный доступ к ресурсу,
-в старом коде можно было следующее:
``` rust
-#[task(priority = 2, resources = [r])]
+#[task(spawn = [bar])]
fn foo(cx: foo::Context) {
- cx.resources.r = /* ... */;
+ cx.spawn.bar().unwrap();
}
-#[task(resources = [r])]
+#[task(schedule = [bar])]
fn bar(cx: bar::Context) {
- cx.resources.r.lock(|r| r = /* ... */);
+ cx.schedule.foo(/* ... */).unwrap();
}
```
-С симметричными блокировками нужно вызывать `lock` для обоих задач:
+Теперь будет выглядеть так:
``` rust
-#[task(priority = 2, resources = [r])]
-fn foo(cx: foo::Context) {
- cx.resources.r.lock(|r| r = /* ... */);
+#[task]
+fn foo(_c: foo::Context) {
+ bar::spawn().unwrap();
}
-#[task(resources = [r])]
-fn bar(cx: bar::Context) {
- cx.resources.r.lock(|r| r = /* ... */);
+#[task]
+fn bar(_c: bar::Context) {
+ foo::schedule(/* ... */).unwrap();
}
```
-Заметьте, что скорость работы не изменяется благодаря оптимизациям LLVM, которые убирают ненужные блокировки.
+Заметьте, что атрибуты `spawn` и `schedule` больше не нужны.
---