aboutsummaryrefslogtreecommitdiff
path: root/book
diff options
context:
space:
mode:
Diffstat (limited to 'book')
-rw-r--r--book/ru/book.toml9
-rw-r--r--book/ru/src/RTIC.svg109
-rw-r--r--book/ru/src/SUMMARY.md25
-rw-r--r--book/ru/src/by-example.md23
-rw-r--r--book/ru/src/by-example/app.md161
-rw-r--r--book/ru/src/by-example/new.md84
-rw-r--r--book/ru/src/by-example/resources.md140
-rw-r--r--book/ru/src/by-example/tasks.md116
-rw-r--r--book/ru/src/by-example/timer-queue.md108
-rw-r--r--book/ru/src/by-example/tips.md175
-rw-r--r--book/ru/src/by-example/types-send-sync.md49
-rw-r--r--book/ru/src/internals.md14
-rw-r--r--book/ru/src/internals/access.md158
-rw-r--r--book/ru/src/internals/ceilings.md92
-rw-r--r--book/ru/src/internals/critical-sections.md521
-rw-r--r--book/ru/src/internals/interrupt-configuration.md72
-rw-r--r--book/ru/src/internals/late-resources.md113
-rw-r--r--book/ru/src/internals/non-reentrancy.md79
-rw-r--r--book/ru/src/internals/tasks.md399
-rw-r--r--book/ru/src/internals/timer-queue.md372
-rw-r--r--book/ru/src/migration.md4
-rw-r--r--book/ru/src/migration/migration_rtic.md48
-rw-r--r--book/ru/src/migration/migration_v4.md230
-rw-r--r--book/ru/src/migration/migration_v5.md365
-rw-r--r--book/ru/src/preface.md26
25 files changed, 0 insertions, 3492 deletions
diff --git a/book/ru/book.toml b/book/ru/book.toml
deleted file mode 100644
index 98c5bf3..0000000
--- a/book/ru/book.toml
+++ /dev/null
@@ -1,9 +0,0 @@
-[book]
-authors = ["Jorge Aparicio, Per Lindgren and The Real-Time Interrupt-driven Concurrency developers"]
-multilingual = false
-src = "src"
-title = "Real-Time Interrupt-driven Concurrency"
-
-[output.html]
-git-repository-url = "https://github.com/rtic-rs/cortex-m-rtic"
-git-repository-icon = "fa-github"
diff --git a/book/ru/src/RTIC.svg b/book/ru/src/RTIC.svg
deleted file mode 100644
index 1c65cba..0000000
--- a/book/ru/src/RTIC.svg
+++ /dev/null
@@ -1,109 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<svg
- xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:cc="http://creativecommons.org/ns#"
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:svg="http://www.w3.org/2000/svg"
- xmlns="http://www.w3.org/2000/svg"
- xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
- xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)"
- inkscape:export-ydpi="145.74001"
- inkscape:export-xdpi="145.74001"
- inkscape:export-filename="/home/emifre/Documents/logo/v2_seller1/vctr/g248_2.png"
- sodipodi:docname="RTIC.svg"
- viewBox="0 0 375.55994 408.84339"
- height="408.84338"
- width="375.55994"
- xml:space="preserve"
- id="svg2"
- version="1.1"><metadata
- id="metadata8"><rdf:RDF><cc:Work
- rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
- rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
- id="defs6"><clipPath
- id="clipPath18"
- clipPathUnits="userSpaceOnUse"><path
- id="path16"
- d="M 0,500 H 500 V 0 H 0 Z" /></clipPath></defs><sodipodi:namedview
- inkscape:current-layer="g10"
- inkscape:window-maximized="1"
- inkscape:window-y="0"
- inkscape:window-x="0"
- inkscape:cy="229.27385"
- inkscape:cx="150.39187"
- inkscape:zoom="1.5119999"
- fit-margin-bottom="0"
- fit-margin-right="0"
- fit-margin-left="0"
- fit-margin-top="0"
- inkscape:pagecheckerboard="false"
- showgrid="false"
- id="namedview4"
- inkscape:window-height="1016"
- inkscape:window-width="1920"
- inkscape:pageshadow="2"
- inkscape:pageopacity="0"
- guidetolerance="10"
- gridtolerance="10"
- objecttolerance="10"
- borderopacity="1"
- bordercolor="#666666"
- pagecolor="#ffffff"
- inkscape:document-rotation="0" /><g
- transform="matrix(1.3333333,0,0,-1.3333333,-148.85309,622.34951)"
- inkscape:label="45453_RTIC logo_JK"
- inkscape:groupmode="layer"
- id="g10"><g
- inkscape:export-filename="/home/emifre/Documents/logo/v2_seller1/vctr/g248.png"
- inkscape:export-ydpi="153.37898"
- inkscape:export-xdpi="153.37898"
- style="opacity:1;fill:#4d4d4d;fill-opacity:1"
- transform="matrix(7.464224,0,0,7.464224,393.30978,300.96457)"
- id="g248"><path
- id="path250"
- style="fill:#4d4d4d;fill-opacity:1;fill-rule:nonzero;stroke:none"
- d="m 0,0 c 0,-10.421 -8.448,-18.868 -18.868,-18.868 -10.421,0 -18.868,8.447 -18.868,18.868 0,10.421 8.447,18.868 18.868,18.868 C -8.448,18.868 0,10.421 0,0" /></g><g
- inkscape:export-filename="/home/emifre/Documents/logo/v2_seller1/vctr/g248.png"
- inkscape:export-ydpi="153.37898"
- inkscape:export-xdpi="153.37898"
- transform="matrix(7.464224,0,0,7.464224,292.89574,388.12804)"
- id="g252"><path
- sodipodi:nodetypes="cccccccccc"
- id="path254"
- style="fill:#cccccc;fill-opacity:1;fill-rule:nonzero;stroke:none"
- d="M 0,0 C -0.604,5.477 -5.967,9.765 -6.856,10.442 -6.487,9.748 -5.71,8.123 -5.267,6.023 -4.92,4.374 -4.845,2.758 -5.043,1.221 -5.291,-0.701 -5.97,-2.505 -7.062,-4.14 c -0.294,-0.441 -0.601,-0.894 -0.926,-1.374 -3.428,-5.065 -8.25205,-11.907209 -7.04305,-17.843209 0.528,-2.592 2.166,-4.805 4.866,-6.583 -7.606,6.593 -2.20795,13.944209 1.62005,17.105209 C -5.253,-10.117 0.659,-5.974 0,0" /></g><g
- inkscape:export-filename="/home/emifre/Documents/logo/v2_seller1/vctr/g248.png"
- inkscape:export-ydpi="153.37898"
- inkscape:export-xdpi="153.37898"
- transform="matrix(7.464224,0,0,7.464224,193.42458,186.62982)"
- id="g256"><path
- sodipodi:nodetypes="ccccccccccc"
- id="path258"
- style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
- d="m 0,0 c -0.777,1.074 -1.303,2.263 -1.562,3.535 -1.212,5.951 3.488,12.895 6.92,17.966 0.325,0.48 0.632,0.933 0.926,1.374 2.464,3.693 2.333,7.549 1.789,10.135 -0.456,2.168 -1.27,3.828 -1.621,4.477 -0.038,0.028 -0.058,0.043 -0.058,0.043 0,0 -6.038,-7.951 -8.738,-12.258 C -5.045,20.964 -8.509,12.81 -5.274,5.863 -2.263,-0.605 2.4913395,-2.6700085 3.1613395,-2.9450085 1.7523395,-2.0240085 0.824,-1.138 0,0" /></g><g
- inkscape:export-filename="/home/emifre/Documents/logo/v2_seller1/vctr/g248.png"
- inkscape:export-ydpi="153.37898"
- inkscape:export-xdpi="153.37898"
- transform="matrix(7.464224,0,0,7.464224,286.22601,210.85049)"
- id="g260"><path
- sodipodi:nodetypes="cccccccssc"
- id="path262"
- style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
- d="m 0,0 c -0.199,-4.847 -3.7433301,-6.7788234 -3.7433301,-6.7788234 0,0 0.2005158,0.00584 0.4557728,0.023109 C -0.01255733,-5.7517164 4.496,-3.342 4.518,2.624 4.53,5.687 2.682,7.663 1.13,8.781 c -1.149,0.828 -2.309,1.321 -2.935,1.551 -0.396,-0.067 -2.392,-0.519 -2.51,-2.836 0,0 -3.5425677,-1.2008654 -3.56,-1.632 C -7.9046856,5.1298176 -6.9355723,4.1874599 -6.187,3.63 -5.1908601,2.8881772 0.199,4.847 0,0" /></g><g
- inkscape:export-filename="/home/emifre/Documents/logo/v2_seller1/vctr/g248.png"
- inkscape:export-ydpi="153.37898"
- inkscape:export-xdpi="153.37898"
- transform="matrix(7.464224,0,0,7.464224,360.6426,228.88853)"
- id="g264"><path
- sodipodi:nodetypes="zcccccccccccczzz"
- id="path266"
- style="fill:#cccccc;fill-opacity:1;fill-rule:nonzero;stroke:none"
- d="M -0.34917151,1.6816738 C -0.7974951,5.9368052 -3.1264734,7.1611735 -5.072,8.56 c 0,0 -0.8516082,3.022335 -1.7015402,3.1237 0,0 0.3570815,0.04169 0,0 -0.6687287,0.05444 -1.1522423,-0.270149 -1.9532423,-1.364149 0,0 -1.1502065,1.167917 -2.4848885,1.093235 C -12.505303,11.107968 -11.817,7.957 -11.818,7.928 c 0.64,-0.24 1.768,-0.729 2.886,-1.535 0.992,-0.715 1.781,-1.534 2.346,-2.437 0.707,-1.128 1.062,-2.389 1.057,-3.748 -0.006,-1.773 -0.433,-3.369 -1.267,-4.743 -0.712,-1.172 -1.724,-2.193 -3.01,-3.036 -1.181,-0.774 -2.329326,-1.2453139 -3.451326,-1.6013139 1.173268,0.050293 3.778241,0.431572 5.8646425,1.3359556 2.0864016,0.9043837 3.5682459,1.7417342 4.4081274,2.592566 0.8398814,0.8508318 3.08370818,2.6703347 2.63538459,6.9254661 z" /></g><path
- inkscape:export-filename="/home/emifre/Documents/logo/v2_seller1/vctr/g248.png"
- sodipodi:nodetypes="ssss"
- inkscape:export-ydpi="153.37898"
- inkscape:export-xdpi="153.37898"
- id="path1340"
- d="m 227.38125,254.73726 c -0.52355,-1.50734 0.39304,-4.38366 2.33326,-6.47436 2.23581,-2.40923 7.33976,11.89073 4.18714,10.96111 -2.21547,-0.65328 -6.03712,-3.09534 -6.5204,-4.48675 z"
- style="fill:#808080;fill-opacity:1;stroke:#cccccc;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /></g></svg>
diff --git a/book/ru/src/SUMMARY.md b/book/ru/src/SUMMARY.md
deleted file mode 100644
index cf03cda..0000000
--- a/book/ru/src/SUMMARY.md
+++ /dev/null
@@ -1,25 +0,0 @@
-# Summary
-
-[Введение](./preface.md)
-
-- [RTIC в примерах](./by-example.md)
- - [Атрибут `app`](./by-example/app.md)
- - [Ресурсы](./by-example/resources.md)
- - [Программные задачи](./by-example/tasks.md)
- - [Очередь таймера](./by-example/timer-queue.md)
- - [Типы, Send и Sync](./by-example/types-send-sync.md)
- - [Создание нового проекта](./by-example/new.md)
- - [Советы и хитрости](./by-example/tips.md)
-- [Инструкции по миграции](./migration.md)
- - [v0.5.x на v1.0.x](./migration/migration_v5.md)
- - [v0.4.x на v0.5.x](./migration/migration_v4.md)
- - [RTFM на RTIC](./migration/migration_rtic.md)
-- [Под капотом](./internals.md)
- - [Настройка прерываний](./internals/interrupt-configuration.md)
- - [Нереентерабельнось](./internals/non-reentrancy.md)
- - [Контроль доступа](./internals/access.md)
- - [Поздние ресурсы](./internals/late-resources.md)
- - [Критические секции](./internals/critical-sections.md)
- - [Анализ приоритетов](./internals/ceilings.md)
- - [Программные задачи](./internals/tasks.md)
- - [Очередь таймера](./internals/timer-queue.md)
diff --git a/book/ru/src/by-example.md b/book/ru/src/by-example.md
deleted file mode 100644
index 027716f..0000000
--- a/book/ru/src/by-example.md
+++ /dev/null
@@ -1,23 +0,0 @@
-# RTIC в примерах
-
-В этой части книги фреймворк Real-Time Interrupt-driven Concurrency (RTIC) представляется
-новым пользователям путем прохода по примерам от простых к более сложным.
-
-Все примеры в этой части книги можно найти в [репозитарии] проекта.
-Большинство из них можно пройти, запустив их на эмуляторе QEMU без специального оборудования.
-
-[репозитарии]: https://github.com/rtic-rs/cortex-m-rtic
-
-Для запуска примеров на вашем ПК, вам понадобится программа `qemu-system-arm`.
-В [the embedded Rust book] есть инструкции по настройке среды для эмбеддед разработке,
-в том числе QEMU.
-
-[the embedded Rust book]: https://rust-embedded.github.io/book/intro/install.html
-
-## Примеры из реальной жизни
-
-Ниже представлены примеры использования RTIC (RTFM) в реальных проектах.
-
-### RTFM V0.4.2
-
-- [etrombly/sandbox](https://github.com/etrombly/sandbox/tree/41d423bcdd0d8e42fd46b79771400a8ca349af55). Аппаратный дзэн-сад, рисующий картинки на песке. Картинки передаются по последовательному порту с помощью G-кода.
diff --git a/book/ru/src/by-example/app.md b/book/ru/src/by-example/app.md
deleted file mode 100644
index 5259bfa..0000000
--- a/book/ru/src/by-example/app.md
+++ /dev/null
@@ -1,161 +0,0 @@
-# Атрибут `app`
-
-Это простейшая из возможных программ на RTIC:
-
-``` rust
-{{#include ../../../../examples/smallest.rs}}
-```
-
-Все программы на RTIC используют атрибут [`app`] (`#[app(..)]`). Этот атрибут
-должен применяться к элементу `mod`. Атрибут `app` имеет обязательный аргумент `device`,
-который принимает *путь* как значение. Это должен быть полный путь, указывающий на
-*крейт доступа к периферии* (PAC), сгенерированный с помощью [`svd2rust`] версии **v0.14.x**
-или новее. Более подробно в разделе [Создание нового проекта](./new.md).
-
-Атрибут `app` будет раскрыт в подходящую точку входа программы, поэтому
-атрибут [`cortex_m_rt::entry`] не нужен.
-
-[`app`]: ../../../api/cortex_m_rtic_macros/attr.app.html
-[`svd2rust`]: https://crates.io/crates/svd2rust
-[`cortex_m_rt::entry`]: ../../../api/cortex_m_rt_macros/attr.entry.html
-
-## `init`
-
-Внутри модуля `app` атрибут ожидает найти функцию инициализации, помеченную
-атрибутом `init`. Эта функция должна иметь сигнатуру
-`fn(init::Context) (-> init::LateResources, init::Monotonics)`.
-
-Эта функция инициализации будет первой частью программы, выполняемой при запуске.
-Функция `init` будет запущена *с отключенными прерываниями* и будет иметь эксклюзивный доступ
-к Cortex-M, в котором токен `bare_metal::CriticalSection` доступен как `cs`.
-Опционально, устройство-специфичные периферия доступна через поля `core` и `device` структуры
-`init::Context`.
-
-`static mut` переменные, определенные в начале `init` будут преобразованы в
-`&'static mut` ссылки, безопасные для доступа. Обратите внимание, данная возможность может
-быть удалена в следующем релизе, см. `task_local` ресурсы.
-
-[`rtic::Peripherals`]: ../../api/rtic/struct.Peripherals.html
-
-Пример ниже показывает типы полей `core`, `device` и `cs`, и демонстрирует
-безопасный доступ к `static mut` переменной. Поле `device` доступно только
-когда аргумент `peripherals` установлен в `true` (по умолчанию).
-В редких случаях, когда вы захотите создать приложение с минимальным потреблением ресурсов,
-можно явно установить `peripherals` в `false`.
-
-``` rust
-{{#include ../../../../examples/init.rs}}
-```
-
-Запуск примера напечатате `init` в консоли, а затем завершит процесс QEMU.
-
-``` console
-$ 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` может опционально добавить в модуль.
-Эта функция используется как специальная *задача ожидания* и должна иметь сигнатуру
-`fn(idle::Context) - > !`.
-
-Если она присутствует, задача `idle` будет запущена после `init`. В отличие от
-`init`, `idle` будет запущена *с включенными прерываниями* и она не может вернуть результат,
-а значит должна работать вечно.
-
-Как и в `init`, `static mut` переменные будут трансформированы в `&'static mut` ссылки,
-безопасные для доступа. Обратите внимание, данная возможность может
-быть удалена в следующем релизе, см. `task_local` ресурсы.
-
-Пример ниже показывает, что `idle` запускается после `init`.
-
-**Примечание:** Цикл `loop {}` в функци ожидания не может быть пустым, так как это сломает
-микроконтроллер, из-за того, что LLVM компилирует пустые циклы в инструкцию `UDF` в release mode.
-Чтобы избежать неопределенного поведения, цикл должен включать "side-effect"
-путем вставки ассемблерной инструкции (например, `WFI`) или ключевого слова `continue`.
-
-``` rust
-{{#include ../../../../examples/idle.rs}}
-```
-
-``` console
-$ cargo run --example idle
-{{#include ../../../../ci/expected/idle.run}}
-```
-
-## Аппаратные задачи
-
-Чтобы объявить обработчик прерывания, фреймворк предоставляет атрибут `#[task]`,
-который можно применять к функциям. Этот атрибут берет аргумент `binds`, чье значение -
-это имя прерывания, которому будет назначен обработчик;
-функция, декорированная этим атрибутом становится обработчиком прерывания.
-В фреймворке такие типы задач именуются *аппаратными*, потому что они начинают
-выполняться в ответ на аппаратное событие.
-
-Пример ниже демонстрирует использование атрибута `#[task]`, чтобы объявить
-обработчик прерывания. Как и в случае с `#[init]` и `#[idle]` локальные `static
-mut` переменные безопасны для использования с аппаратной задачей.
-
-``` rust
-{{#include ../../../../examples/hardware.rs}}
-```
-
-``` console
-$ cargo run --example hardware
-{{#include ../../../../ci/expected/hardware.run}}
-```
-
-До сих пор все программы на RTIC, которые мы видели, не отличались от программ,
-которые можно написать, используя лишь крейт `cortex-m-rt`. С этого момента мы
-начинаем представлять возможности, уникальные для RTIC.
-
-## Приоритеты
-
-Статический приоритет каждого обработчика можно оределить в атрибуте `task`, используя
-аргумент `priority`. Задачи могут иметь приоритет в диапазоне `1..=(1 << NVIC_PRIO_BITS)`,
-где `NVIC_PRIO_BITS` - это константа, определенная в крейте `устройства`.
-Когда аргумент `priority` не указан, предполагается, что приоритет равен `1`.
-Задача `idle` имеет ненастраиваемый приоритет `0`, наименьший из возможных.
-
-> Более высокое значение означает более высокий приоритет в RTIC, что противоположно тому,
-> что указано в периферии NVIC Cortex-M.
-> Точнее, это значит, что число `10` обозначает приоритет **выше**, чем число `9`.
-
-Когда несколько задач готовы к запуску, задача с самым большим статическим
-приоритетом будет запущена первой. Приоритезацию задач можно рассматривать по
-такому сценарию: сигнал прерывания приходит во время выполнения задачи с низким приоритетом;
-сигнал переключает задачу с высоким приоритетом в режим ожидания.
-Разница в приоритетах приводи к тому, что задача с высоким приоритетом вытесняет задачу с низким:
-выполнение задачи с низким приоритетом замораживается и задача с высоким приоритетом выполняется,
-пока не будет завершена. Как только задача с высоким приоритетом будет остановлена,
-продолжится выполнение задачи с низким приоритетом.
-
-Следующий пример демонстрирует диспетчеризацию на основе приоритетов задач.
-
-``` rust
-{{#include ../../../../examples/preempt.rs}}
-```
-
-``` console
-$ cargo run --example preempt
-{{#include ../../../../ci/expected/preempt.run}}
-```
-
-Заметьте, что задача `gpiob` *не* вытесняет задачу `gpioc`, потому что ее приоритет
-*такой же*, как и у `gpioc`. Однако, как только `gpioc` возвращает результат,
-выполненяется задача `gpiob`, как более приоритетная по сравнению с `gpioa`.
-Выполнение `gpioa` возобновляется только после выхода из `gpiob`.
-
-Еще одно замечание по поводу приоритетов: выбор приоритета большего, чем поддерживает устройство
-(а именно `1 << NVIC_PRIO_BITS`) приведет к ошибке компиляции.
-Из-за ограничений языка, сообщение об ошибке далеко от понимания:
-вам скажут что-то похожее на "evaluation of constant value failed", а указатель на ошибку
-*не* покажет на проблемное значение прерывания --
-мы извиняемся за это!
diff --git a/book/ru/src/by-example/new.md b/book/ru/src/by-example/new.md
deleted file mode 100644
index 0ff8d98..0000000
--- a/book/ru/src/by-example/new.md
+++ /dev/null
@@ -1,84 +0,0 @@
-# Создание нового проекта
-
-Теперь, когда Вы изучили основные возможности фреймворка RTIC, Вы можете
-попробовать его использовать на Вашем оборудовании следуя этим инструкциям.
-
-1. Создайте экземпляр из шаблона [`cortex-m-quickstart`].
-
-[`cortex-m-quickstart`]: https://github.com/rust-embedded/cortex-m-quickstart#cortex-m-quickstart
-
-``` console
-$ # например используя `cargo-generate`
-$ cargo generate \
- --git https://github.com/rust-embedded/cortex-m-quickstart \
- --name app
-
-$ # следуйте остальным инструкциям
-```
-
-2. Добавьте крейт доступа к периферии (PAC), сгенерированный с помощью[`svd2rust`]
- **v0.14.x**, или крейт отладочной платы, у которой в зависимостях один из таких PAC'ов.
- Убедитесь, что опция `rt` крейта включена.
-
-[`svd2rust`]: https://crates.io/crates/svd2rust
-
-В этом примере я буду использовать крейт устройства [`lm3s6965`].
-Эта библиотека не имеет Cargo-опции `rt`; эта опция всегда включена.
-
-[`lm3s6965`]: https://crates.io/crates/lm3s6965
-
-Этот крейт устройства предоставляет линковочный скрипт с макетом памяти
-целевого устройства, поэтому `memory.x` и `build.rs` нужно удалить.
-
-``` console
-$ cargo add lm3s6965 --vers 0.1.3
-
-$ rm memory.x build.rs
-```
-
-3. Добавьте крейт `cortex-m-rtic` как зависимость.
-
-``` console
-$ cargo add cortex-m-rtic --allow-prerelease
-```
-
-4. Напишите свою RTIC программу.
-
-Здесь я буду использовать пример `init` из крейта `cortex-m-rtic`.
-
-Примеры находтся в папке `examples`, а содержание `init.rs` показано здесь:
-
-``` console
-{{#include ../../../../examples/init.rs}}
-```
-
-Пример `init` использует устройство `lm3s6965`. Не забудьте настроить аргумент `device`
-в атрибуте макроса app так, чтобы он соответствовал пути к PAC-крейту, если он отличается,
-а также добавить перифериб и другие аргументы если необходимо.
-Несмотря на то, что в программе могут использоваться псевдонимы типов,
-здесь необходимо указать полный путь (из корня крейта). Для многих устройств,
-есть общий подход в крейтах реализации HAL (с псевдонимом `hal`) и крейтах поддержки
-отладочных плат реекспортиорвать PAC как `pac`, что приводит нас к образцу, аналогичному
-приведенному ниже:
-
-```rust
-use abcd123_hal as hal;
-//...
-
-#[rtic::app(device = crate::hal::pac, peripherals = true, monotonic = rtic::cyccnt::CYCCNT)]
-mod app { /*...*/ }
-```
-
-Пример `init` также зависит от крейта `panic-semihosting`:
-
-``` console
-$ cargo add panic-semihosting
-```
-
-5. Соберите его, загрузите в микроконтроллер и запустите.
-
-``` console
-$ # ПРИМЕЧАНИЕ: Я раскомментировал опцию `runner` в `.cargo/config.toml`
-$ cargo run
-{{#include ../../../../ci/expected/init.run}}
-```
diff --git a/book/ru/src/by-example/resources.md b/book/ru/src/by-example/resources.md
deleted file mode 100644
index ed8904b..0000000
--- a/book/ru/src/by-example/resources.md
+++ /dev/null
@@ -1,140 +0,0 @@
-# Ресурсы
-
-Фреймворк предоставляет абстракцию для разделения данных между любыми контекстами,
-с которыми мы встречались в предыдущей главе (задачами-обработчиками, `init` и `idle`): ресурсы.
-
-Ресурсы - это данные, видимые только функциями, определенными внутри модуля `#[app]`.
-Фреймворк дает пользователю полный контроль за тем, какой контекст может
-получить доступ к какому ресурсу.
-
-Все ресурсы определены в *двух* структурах внутри модуля `#[app]`.
-Каждое поле этих структур соответствует отдельному ресурсу.
-Одна `struct`-ура должна быть аннотирована атрибутом `#[local]`.
-Другая `struct`-ура должна быть аннотирована атрибутом `#[shared]`.
-Разница между этими двумя множествами ресурсов будет описана познее.
-
-Каждый контекс (задача-обработчик, `init` или `idle`) должен указать ресурсы, к которым
-он намерен обращаться, в соответсятвующем ему атрибуте с метаданными, используя
-либо аргумент `local`, либо `shared`. Этот аргумент принимает список имен ресурсов в качестве значения.
-Перечисленные ресурсы становятся доступны в контексте через поля `local` и `shared` структуры `Context`.
-
-Во время выполнения при выходе из функции `#[init]` все ресурсы инициализированы.
-Функция `#[init]` должна возвращать начальные значения для всех ресурсов;
-отсюда следует, что тип возвращаемого ею значения включает типы
-структур `#[shared]` и `#[local]`.
-Поскольку ресурсы инициализированы в ходе функции `#[init]`, к ним нельзя
-получить доступ внетри функции `#[init]`.
-
-Пример программы, показанной ниже содержит два обработчика прерывания.
-Каждый обработчик имеет доступ к его собственному `#[local]` ресурсу.
-
-``` rust
-{{#include ../../../../examples/resource.rs}}
-```
-
-``` console
-$ cargo run --example resource
-{{#include ../../../../ci/expected/resource.run}}
-```
-
-К ресурсу `#[local]` нельзя получить доступ извне задачи к которой он
-привязан атрибутом `#[task]`.
-Попытка обращения к одному и тому же ресурсу `#[local]` из более чем одной
-задачи - ошибка компиляции.
-
-## `lock`
-
-Критические секции необходимы для доступа к ресурсам `#[shared]` таким образом,
-чтобы избежать гонок данных.
-
-Поле `shared`, передаваемого `Context` реализует трейт [`Mutex`] для каждого разделяемого
-ресурса, доступного задаче.
-
-Единственный метод этого трейта, [`lock`], запускает свой аргумент-замыкание в критической секции.
-
-[`Mutex`]: ../../../api/rtic/trait.Mutex.html
-[`lock`]: ../../../api/rtic/trait.Mutex.html#method.lock
-
-Критическая секция, создаваемая интерфейсом `lock` основана на динамических приоритетах:
-она временно повышает динамический приоритет контекста до *максимального* приоритета,
-что не дает другим задачам возможности вытеснить критическую секцию.
-Этот протокол синхронизации известен как [Протокол немедленного максимального приоритета
-(ICPP)][icpp], и компилируется диспетчером RTIC с [Политикой ресурсов стека(SRP)][srp].
-
-[icpp]: https://en.wikipedia.org/wiki/Priority_ceiling_protocol
-[srp]: https://en.wikipedia.org/wiki/Stack_Resource_Policy
-
-В примере ниже у нас есть три обработчика прерываний с приоритетами от одного до трех.
-Два из обработчиков с более низким приоритетом соревнуются за ресурс `shared`,
-поэтому должны блокировать доступа к данным ресурса.
-Обработчик с наивысшим приоритетом, который не имеет доступа к ресурсу `shared`,
-может свободно вытеснять критическую секцию, созданную обработчиком с низким приоритетом.
-
-``` rust
-{{#include ../../../../examples/lock.rs}}
-```
-
-``` console
-$ cargo run --example lock
-{{#include ../../../../ci/expected/lock.run}}
-```
-
-## Множественное блокировка
-
-Это расширение к `lock`, чтобы уменьшить количесво отступов, блокируемые ресурсы можно объединять в кортежи.
-Следующий пример это демонстрирует:
-
-``` rust
-{{#include ../../../../examples/multilock.rs}}
-```
-
-## Только разделяемый (`&-`) доступ
-
-По-умолчанию фреймворк предполагает, что все задачи требуют эксклюзивный доступ (`&mut-`) к ресурсам,
-но возможно указать, что задаче достаточен разделяемый доступ (`&-`) к ресурсы с помощью синтакисиса
-`&resource_name` в списке `resources`.
-
-Преимущество указания разделяемого досупа (`&-`) к ресурсу в том, что для доступа к ресурсу
-не нужна блокировка, даже если за ресурс соревнуются несколько задач, запускаемые с
-разными приоритетами. Недостаток в том, что задача получает только разделяемую ссылку (`&-`)
-на ресурс, и ограничена операциями, возможными с ней, но там, где разделяемой ссылки достаточно,
-такой подход уменьшает количесво требуемых блокировок.
-В дополнение к простым неизменяемым данным, такой разделяемый доступ может быть полезен для
-ресурсов, безопасно реализующих внутреннюю мутабельность с самоблокировкой или атомарными операциями.
-
-Заметьте, что в этом релизе RTIC невозможно запросить и эксклюзивный доступ (`&mut-`)
-и разделяемый (`&-`) для *одного и того же* ресурса из различных задач.
-Попытка это сделать приведет к ошибке компиляции.
-
-В примере ниже ключ (например криптографический ключ) загружается (или создается) во время выполнения,
-а затем используется двумя задачами, запускаемымы с различным приоритетом без каких-либо блокировок.
-
-``` rust
-{{#include ../../../../examples/only-shared-access.rs}}
-```
-
-``` console
-$ cargo run --example only-shared-access
-{{#include ../../../../ci/expected/only-shared-access.run}}
-```
-
-## Неблокируемый доступ к изменяемым ресурсам
-
-Критическая секция *не* требуется для доступа к ресурсу `#[shared]`,
-к которому обращаются только из задач с *одинаковым* приоритетом.
-В этом случае вы можете избежать `lock` API, добавив атрибут поля `#[lock_free]` при объявдении ресурса (смотреть пример ниже).
-Заметьте, что это лишь для удобства: даже если вы используете `lock` API,
-во время выполнения фреймворк *не* создаст критическую секцию.
-Еще одно ценное замечание: использование `#[lock_free]` на ресурсах,
-разделяемых задачами, запускаемыми с разными приоритетами
-приведет к ошибке *компиляции* -- не импользование `lock` API может
-привести к гонке данных в этом случае.
-
-``` 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/tasks.md b/book/ru/src/by-example/tasks.md
deleted file mode 100644
index 3c99d00..0000000
--- a/book/ru/src/by-example/tasks.md
+++ /dev/null
@@ -1,116 +0,0 @@
-# Программные задачи
-
-В дополнение к аппаратным задачам, вызываемым в ответ на аппаратные события,
-RTIC также поддерживает *программные* задачи, которые могут порождаться
-приложением из любого контекста выполнения.
-
-Программным задачам можно также назначать приоритет и, под капотом, они
-диспетчеризуются обработчиками прерываний. RTIC требует, чтобы свободные
-прерывания, были указаны в аргументе `dispatchers` модуля `app`, если используются
-программные задачи; часть из этих свободных прерываний будут использованы для
-управления программными задачами. Преимущество программных задач над аппаратными
-в том, что множество задач можно назначить на один обработчик прерывания.
-
-Программные задачи также определяются атрибутом `task`, но аргумент `binds` опускается.
-
-Пример ниже демонстрирует три программные задачи, запускаемых 2-х разных приоритетах.
-Три программные задачи привязаны к 2-м обработчикам прерываний.
-
-``` rust
-{{#include ../../../../examples/task.rs}}
-```
-
-``` console
-$ cargo run --example task
-{{#include ../../../../ci/expected/task.run}}
-```
-
-## Передача сообщений
-
-Другое преимущество программной задачи в том, что задачам можно передать сообщения
-в момент их запуска. Тип передаваемого сообщения должен быть определен в сигнатуре
-задачи-обработчика.
-
-Пример ниже демонстрирует три задачи, две из которых ожидают сообщение.
-
-``` rust
-{{#include ../../../../examples/message.rs}}
-```
-
-``` console
-$ cargo run --example message
-{{#include ../../../../ci/expected/message.run}}
-```
-
-## Вместимость
-
-RTIC *не* производит никакого рода аллокаций памяти в куче.
-Память, необходимая для размещения сообщения резервируется статически.
-По-умолчанию фреймворк минимизирует выделение памяти программой таким образом,
-что каждая задача имеет "вместимость" для сообщения равную 1:
-это значит, что не более одного сообщения можно передать задаче перед тем, как
-у нее появится возможность к запуску. Это значение по-умолчанию можно
-изменить для каждой задачи, используя аргумент `capacity`.
-Этот аргумент принимает положительное целое, которое определяет как много
-сообщений буфер сообщений задачи может хранить.
-
-Пример ниже устанавливает вместимость программной задачи `foo` равной 4.
-Если вместимость не установить, второй вызов `spawn.foo` в `UART0` приведет к ошибке (панике).
-
-``` rust
-{{#include ../../../../examples/capacity.rs}}
-```
-
-``` console
-$ cargo run --example capacity
-{{#include ../../../../ci/expected/capacity.run}}
-```
-
-## Обработка ошибок
-
-Интерфейс `spawn` возвращает вариант `Err`, если для размещения сообщения нет места.
-В большинстве сценариев возникающие ошибки обрабатываются одним из двух способов:
-
-- Паника, с помощью `unwrap`, `expect`, и т.п. Этот метод используется, чтобы обнаружить
- ошибку программиста (например bug) выбора вместительности, которая оказалась недостаточна.
- Когда эта паника встречается во время тестирования, выбирается большая вместительность,
- и перекомпиляция программы может решить проблему, но иногда достаточно окунуться глубже
- и провести анализ времени выполнения программы, чтобы выяснить, может ли платформа
- обрабатывать пиковые нагрузки, или процессор необходимо заменить на более быстрый.
-
-- Игнорирование результата. В программах реального времени, как и в обычных, может быть
- нормальным иногда терять данные, или не получать ответ на некоторые события в пиковых ситуациях.
- В таких сценариях может быть допустимо игнорирование ошибки вызова `spawn`.
-
-Следует отметить, что повторная попытка вызова `spawn` обычно неверный подход, поскольку
-такая операция на практике вероятно никогда не завершится успешно.
-Так как у нас есть только переключения контекста на задачи с *более высоким* приоритетом,
-повторение вызова `spawn` на задаче с низким приоритом никогда не позволит планировщику
-вызвать задачу, что значит, что буфер никогда не будет очищен. Такая ситуация отражена в
-следующем наброске:
-
-``` rust
-#[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() {
- // повтор попытки вызова spawn, если произошла ошибка
- }
- }
-
- #[task(priority = 1)]
- fn bar(cx: bar::Context, payload: i32) {
- // ..
- }
-}
-```
diff --git a/book/ru/src/by-example/timer-queue.md b/book/ru/src/by-example/timer-queue.md
deleted file mode 100644
index c8818d7..0000000
--- a/book/ru/src/by-example/timer-queue.md
+++ /dev/null
@@ -1,108 +0,0 @@
-# Очередь таймера
-
-В отличие от интерфейса `spawn`, который немедленно передает программную задачу
-планировщику для немедленного запуска, интерфейс `schedule` можно использовать
-для планирования задачи к запуске через какое-то время в будущем.
-
-Чтобы использовать интерфейс `schedule`, предварительно должен быть определен
-монотонный таймер с помощью аргумента `monotonic` атрибута `#[app]`.
-Этот аргумент принимает путь к типу, реализующему трейт [`Monotonic`].
-Ассоциированный тип, `Instant`, этого трейта представляет метку времени в соответствущих
-единицах измерения и широко используется в интерфейсе `schedule` -- предлагается смоделировать
-этот тип позднее [один из таких есть в стандартной библиотеке][std-instant].
-
-Хотя это не отражено в определении трейта (из-за ограничений системы типов / трейтов),
-разница двух `Instant`ов должна возвращать какой-то тип `Duration` (см. [`core::time::Duration`])
-и этот `Duration` должен реализовывать трейт `TryInto<u32>`.
-Реализация этого трейта должна конвертировать значение `Duration`, которое
-использует какую-то определенную единицу измерения времени, в единицы измерения "тактов системного таймера
-(SYST)". Результат преобразований должен быть 32-битным целым.
-Если результат не соответствует 32-битному целому, тогда операция должна возвращать ошибку любого типа.
-
-[`Monotonic`]: ../../../api/rtic/trait.Monotonic.html
-[std-instant]: https://doc.rust-lang.org/std/time/struct.Instant.html
-[`core::time::Duration`]: https://doc.rust-lang.org/core/time/struct.Duration.html
-
-Для целевых платформ ARMv7+ крейт `rtic` предоставляет реализацию `Monotonic`, основанную на
-встроенном CYCle CouNTer (CYCCNT). Заметьте, что это 32-битный таймер, работающий на
-частоте центрального процессора, и поэтому не подходит для отслеживания интервалов времени в секундах.
-
-Когда планируется задача, (определенный пользователем) `Instant`, в который задача должна быть
-выполнена, должен передаваться в качестве первого аргумента вызова `schedule`.
-
-К тому же, выбранный `monotonic` таймер, необходимо сконфигурировать и инициализировать в
-фазе работы `#[init]`. Заметьте, что *также* касается случая использования `CYCCNT`,
-предоставляемого крейтом `cortex-m-rtic`.
-
-Пример ниже планирует к выполнению две задачи из `init`: `foo` и `bar`. `foo` запланирована
-к запуску через 8 миллионов циклов в будущем. Далее, `bar` запланировано запустить через
-4 миллиона циклов в будущем. Таким образом, `bar` запустится до `foo`, так как и запланировано.
-
-> **DF:YJ**: Примеры, использующие интерфейс `schedule` или абстракцию `Instant`
-> **не будут** правильно работать на эмуляторе QEMU, поскольку счетчик циклов Cortex-M
-> функционально не был реализован в `qemu-system-arm`.
-
-``` rust
-{{#include ../../../../examples/schedule.rs}}
-```
-
-Запусе программы на реальном оборудовании создает следующий вывод в консоли:
-
-``` text
-{{#include ../../../../ci/expected/schedule.run}}
-```
-
-Когда интерфейс `schedule` используется, среда исполнения использует внутри
-обработчик прерываний `SysTick` и периферию системного таймера (`SYST`), поэтому ни
-тот ни другой нельзя использовать в программе. Это гарантируется изменением типа
-`init::Context.core` с `cortex_m::Peripherals` на `rtic::Peripherals`.
-Последняя структура содержит все поля из предыдущей кроме `SYST`.
-
-## Периодические задачи
-
-Программные задачи имеют доступ к моменту времени `Instant`, в который они были запланированы
-на выполнение переменной `scheduled`. Эта информация и интерфейс `schedule` можно использовать,
-чтобы реализовать периодические задачи, как показано ниже.
-
-``` rust
-{{#include ../../../../examples/periodic.rs}}
-```
-
-Это вывод, создаваемый примером. Заметьте, что здесь пристствует небольшой дрейф / колебания
-даже несмотря на то, что `schedule.foo` была вызвана в *конце* `foo`. Использование
-`Instant::now` вместо `scheduled` вызвало бы дрейф / колебания.
-
-``` text
-{{#include ../../../../ci/expected/periodic.run}}
-```
-
-## Базовое время
-
-Для задач, вызываемых из `init` мы имеем точную информацию о их `scheduled` времени.
-Для аппаратных задач такого времени нет, поскольку они асинхронны по природе.
-Для аппаратных задач среда исполнения предоставляет время запуска (`start`), которое отражает
-время, в которое обработчик прерывания будет запущен.
-
-Заметьте, что `start` **не** равно времени прихода события, которое вызывает задачу.
-В зависимости от приоритета задачи и загрузки системы, время `start` может сильно отдалиться от
-времени прихода события.
-
-Какое по вашему мнению будет значение `scheduled` для программных задач, которые вызываются через
-`spawn` вместо планирования? Ответ в том, что вызываемые задачи наследуют
-*базовое* время того контекста, который их вызывает. Базовое время аппаратных задач -
-это их время `start`, базовое время программных задач - их время `scheduled`, а
-базовое время `init` - время старта системы, или нулевое
-(`Instant::zero()`). `idle` на самом деле не имеет базового времени, но задачи вызываемые из нее,
-используют `Instant::now()` в качестве базового.
-
-Пример ниже демонстрирует разные смыслы *базового времени*.
-
-``` rust
-{{#include ../../../../examples/baseline.rs}}
-```
-
-Запуск программы на реальном оборудовании приведет к следующему выводу в консоли:
-
-``` text
-{{#include ../../../../ci/expected/baseline.run}}
-```
diff --git a/book/ru/src/by-example/tips.md b/book/ru/src/by-example/tips.md
deleted file mode 100644
index 7d4fc2f..0000000
--- a/book/ru/src/by-example/tips.md
+++ /dev/null
@@ -1,175 +0,0 @@
-# Советы и хитрости
-
-Полные примеры для RTIC смотрите в репозитарии [rtic-examples][rtic-examples].
-
-[rtic-examples]: https://github.com/rtic-rs/rtic-examples
-
-## Обобщенное программирование (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.run.grep.foo}}
-```
-
-``` console
-$ cargo nm --example ramfunc --release | grep ' bar::'
-{{#include ../../../../ci/expected/ramfunc.run.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}}
-```
diff --git a/book/ru/src/by-example/types-send-sync.md b/book/ru/src/by-example/types-send-sync.md
deleted file mode 100644
index 755a379..0000000
--- a/book/ru/src/by-example/types-send-sync.md
+++ /dev/null
@@ -1,49 +0,0 @@
-# Типы, Send и Sync
-
-Каждая функция в модуле `app` принимает структуру `Context` в качесте первого параметра.
-Все поля этих структур имеют предсказуемые, неанонимные типы,
-поэтому вы можете написать обычные функции, принимающие их как аргументы.
-
-Справочник по API определяет как эти типы генерируются на основе входных данных.
-Вы можете также сгенерировать документацию к вашему крейту программы (`cargo doc --bin <name>`);
-в документации вы найдете структуры `Context` (например `init::Context` и
-`idle::Context`).
-
-Пример ниже показывает различные типы, сгенерированные атрибутом `app`.
-
-``` rust
-{{#include ../../../../examples/types.rs}}
-```
-
-## `Send`
-
-[`Send`] - это маркерный трейт для "типов, которые можно передавать через границы
-потоков", как это определено в `core`. В контексте RTIC трейт `Send` необходим
-только там, где возможна передача значения между задачами, запускаемыми на
-*разных* приоритетах. Это возникает в нескольких случаях: при передаче сообщений,
-в разделяемых `static mut` ресурсах и при инициализации поздних ресурсов.
-
-[`Send`]: https://doc.rust-lang.org/core/marker/trait.Send.html
-
-Атрибут `app` проверит, что `Send` реализован, где необходимо, поэтому вам не
-стоит волноваться об этом. В настоящий момент все передаваемые типы в RTIC должны быть `Send`, но
-это ограничение возможно будет ослаблено в будущем.
-
-## `Sync`
-
-Аналогично, [`Sync`] - маркерный трейт для "типов, на которые можно безопасно разделять между потоками",
-как это определено в `core`. В контексте RTIC типаж `Sync` необходим только там,
-где возможно для двух или более задач, запускаемых на разных приоритетах получить разделяемую ссылку (`&-`) на
-ресурс. Это возникает только (`&-`) ресурсах с разделяемым доступом.
-
-[`Sync`]: https://doc.rust-lang.org/core/marker/trait.Sync.html
-
-Атрибут `app` проверит, что `Sync` реализован, где необходимо, но важно знать,
-где ограничение `Sync` не требуется: в (`&-`) ресурсах с разделяемым доступом, за которые
-соперничают задачи с *одинаковым* приоритетом.
-
-В примере ниже показано, где можно использовать типы, не реализующие `Sync`.
-
-``` rust
-{{#include ../../../../examples/not-sync.rs}}
-```
diff --git a/book/ru/src/internals.md b/book/ru/src/internals.md
deleted file mode 100644
index 48495b0..0000000
--- a/book/ru/src/internals.md
+++ /dev/null
@@ -1,14 +0,0 @@
-# Под капотом
-
-**Этот раздел в настоящий момент находится в разработке,
-он появится снова, когда будет завершен**
-
-Этот раздел описывает внутренности фреймворка RTIC на *высоком уровне*.
-Низкоуровневые детали, такие как парсинг и генерация кода, выполняемые процедурным макросом
-(`#[app]`) объясняться не будут. Внимание будет сосредоточено на анализе
-спецификации пользователя и структурах данных, используемых на этапе выполнения.
-
-Мы настоятельно рекомендуем вам прочитать раздел о [конкуренции] в embedonomicon
-перед тем, как погружаться в материал.
-
-[конкуренции]: https://github.com/rust-embedded/embedonomicon/pull/48
diff --git a/book/ru/src/internals/access.md b/book/ru/src/internals/access.md
deleted file mode 100644
index ea073a4..0000000
--- a/book/ru/src/internals/access.md
+++ /dev/null
@@ -1,158 +0,0 @@
-# Контроль доступа
-
-Одна из основ RTIC - контроль доступа. Контроль того, какая часть программы
-может получить доступ к какой статической переменной - инструмент обеспечения
-безопасности памяти.
-
-Статические переменные используются для разделения состояний между обработчиками
-прерываний, или между обработчиком прерывания и нижним контекстом выполнения, `main`.
-В обычном Rust коде трудно обеспечить гранулированный контроль за тем, какие функции
-могут получать доступ к статическим переменным, поскольку к статическим переменным
-можно получить доступ из любой функции, находящейся в той же области видимости,
-в которой они определены. Модули дают частичный контроль над доступом
-к статическим переменным, но они недостаточно гибкие.
-
-Чтобы добиться полного контроля за тем, что задачи могут получить доступ
-только к статическим переменным (ресурсам), которые им были указаны в RTIC атрибуте,
-фреймворк RTIC производит трансформацию структуры кода.
-Эта трансформация состоит из размещения ресурсов (статических переменных), определенных
-пользователем *внутри* модуля, а пользовательского кода *вне* модуля.
-Это делает невозможным обращение пользовательского кода к статическим переменным.
-
-Затем доступ к ресурсам предоставляется каждой задаче с помощью структуры `Resources`,
-чьи поля соответствуют ресурсам, к которым получает доступ задача.
-Есть лишь одна такая структура на задачу и структура `Resources` инициализируется
-либо уникальной ссылкой (`&mut-`) на статическую переменную, либо с помощью прокси-ресурса (см.
-раздел [критические секции](critical-sections.html)).
-
-Код ниже - пример разных трансформаций структуры кода, происходящих за сценой:
-
-``` rust
-#[rtic::app(device = ..)]
-mod app {
- static mut X: u64: 0;
- static mut Y: bool: 0;
-
- #[init(resources = [Y])]
- fn init(c: init::Context) {
- // .. пользовательский код ..
- }
-
- #[interrupt(binds = UART0, resources = [X])]
- fn foo(c: foo::Context) {
- // .. пользовательский код ..
- }
-
- #[interrupt(binds = UART1, resources = [X, Y])]
- fn bar(c: bar::Context) {
- // .. пользовательский код ..
- }
-
- // ..
-}
-```
-
-Фреймворк создает код, подобный этому:
-
-``` rust
-fn init(c: init::Context) {
- // .. пользовательский код ..
-}
-
-fn foo(c: foo::Context) {
- // .. пользовательский код ..
-}
-
-fn bar(c: bar::Context) {
- // .. пользовательский код ..
-}
-
-// Публичное API
-pub mod init {
- pub struct Context<'a> {
- pub resources: Resources<'a>,
- // ..
- }
-
- pub struct Resources<'a> {
- pub Y: &'a mut bool,
- }
-}
-
-pub mod foo {
- pub struct Context<'a> {
- pub resources: Resources<'a>,
- // ..
- }
-
- pub struct Resources<'a> {
- pub X: &'a mut u64,
- }
-}
-
-pub mod bar {
- pub struct Context<'a> {
- pub resources: Resources<'a>,
- // ..
- }
-
- pub struct Resources<'a> {
- pub X: &'a mut u64,
- pub Y: &'a mut bool,
- }
-}
-
-/// Детали реализации
-mod app {
- // все, что внутри этого модуля спрятано от пользовательского кода
-
- static mut X: u64 = 0;
- static mut Y: bool = 0;
-
- // настоящая точка входа в программу
- unsafe fn main() -> ! {
- interrupt::disable();
-
- // ..
-
- // вызов пользовательского кода; передача ссылок на статические переменные
- init(init::Context {
- resources: init::Resources {
- X: &mut X,
- },
- // ..
- });
-
- // ..
-
- interrupt::enable();
-
- // ..
- }
-
- // обработчик прерывания,с которым связан `foo`
- #[no_mangle]
- unsafe fn UART0() {
- // вызов пользовательского кода; передача ссылок на статические переменные
- foo(foo::Context {
- resources: foo::Resources {
- X: &mut X,
- },
- // ..
- });
- }
-
- // обработчик прерывания,с которым связан `bar`
- #[no_mangle]
- unsafe fn UART1() {
- // вызов пользовательского кода; передача ссылок на статические переменные
- bar(bar::Context {
- resources: bar::Resources {
- X: &mut X,
- Y: &mut Y,
- },
- // ..
- });
- }
-}
-```
diff --git a/book/ru/src/internals/ceilings.md b/book/ru/src/internals/ceilings.md
deleted file mode 100644
index df9901a..0000000
--- a/book/ru/src/internals/ceilings.md
+++ /dev/null
@@ -1,92 +0,0 @@
-# Анализ приоритетов
-
-*Поиск максимального приоритета* ресурса (*ceiling*) - поиск динамического
-приоритета, который любая задача должна иметь, чтобы безопасно работать с
-памятью ресурсов. Анализ приоритетов - относительно прост,
-но критичен для безопасности памяти RTIC программ.
-
-Для расчета максимального приоритета ресурса мы должны сначала составить
-список задач, имеющих доступ к ресурсу -- так как фреймворк RTIC
-форсирует контроль доступа к ресурсам на этапе компиляции, он
-также имеет доступ к этой информации на этапе компиляции.
-Максимальный приоритет ресурса - просто наивысший логический приоритет
-среди этих задач.
-
-`init` и `idle` не настоящие задачи, но у них есть доступ к ресурсам,
-поэтому они должны учитываться при анализе приоритетов.
-`idle` учитывается как задача, имеющая логический приоритет `0`,
-в то время как `init` полностью исключается из анализа --
-причина этому в том, что `init` никогда не использует (не нуждается) критические
-секции для доступа к статическим переменным.
-
-В предыдущем разделе мы показывали, что разделяемые ресусы
-могут быть представлены уникальными ссылками (`&mut-`) или скрываться за
-прокси в зависимости от того, имеет ли задача к ним доступ.
-Какой из вариантов представляется задаче зависит от приоритета задачи и
-максимального приоритета ресурса.
-Если приоритет задачи такой же, как максимальный приоритет ресурса, тогда
-задача получает уникальную ссылку (`&mut-`) на память ресурса,
-в противном случае задача получает прокси -- это также касается `idle`.
-`init` особеннвй: он всегда получает уникальные ссылки (`&mut-`) на ресурсы.
-
-Пример для иллюстрации анализа приоритетов:
-
-``` rust
-#[rtic::app(device = ..)]
-mod app {
- struct Resources {
- // доступен из `foo` (prio = 1) и `bar` (prio = 2)
- // -> CEILING = 2
- #[init(0)]
- x: u64,
-
- // доступен из `idle` (prio = 0)
- // -> CEILING = 0
- #[init(0)]
- y: u64,
- }
-
- #[init(resources = [x])]
- fn init(c: init::Context) {
- // уникальная ссылка, потому что это `init`
- let x: &mut u64 = c.resources.x;
-
- // уникальная ссылка, потому что это `init`
- let y: &mut u64 = c.resources.y;
-
- // ..
- }
-
- // PRIORITY = 0
- #[idle(resources = [y])]
- fn idle(c: idle::Context) -> ! {
- // уникальная ссылка, потому что
- // приоритет (0) == максимальному приоритету ресурса (0)
- let y: &'static mut u64 = c.resources.y;
-
- loop {
- // ..
- }
- }
-
- #[interrupt(binds = UART0, priority = 1, resources = [x])]
- fn foo(c: foo::Context) {
- // прокси-ресурс, потому что
- // приоритет задач (1) < максимальному приоритету ресурса (2)
- let x: resources::x = c.resources.x;
-
- // ..
- }
-
- #[interrupt(binds = UART1, priority = 2, resources = [x])]
- fn bar(c: foo::Context) {
- // уникальная ссылка, потому что
- // приоритет задачи (2) == максимальному приоритету ресурса (2)
- let x: &mut u64 = c.resources.x;
-
- // ..
- }
-
- // ..
-}
-```
diff --git a/book/ru/src/internals/critical-sections.md b/book/ru/src/internals/critical-sections.md
deleted file mode 100644
index e4c3d0a..0000000
--- a/book/ru/src/internals/critical-sections.md
+++ /dev/null
@@ -1,521 +0,0 @@
-# Критические секции
-
-Когда ресурсы (статические переменные) разделяются между двумя или более задачами,
-которые выполняются с разными приоритетами, некая форма запрета изменений
-необходима, чтобы изменять память без гонки данных. В RTIC мы используем
-основанные на приоритетах критические секции, чтобы гарантировать запрет изменений
-(см. [Протокол немедленного максимального приоритета][icpp]).
-
-[icpp]: https://en.wikipedia.org/wiki/Priority_ceiling_protocol
-
-Критическия секция состоит во временном увеличении *динамического* приоритета задачи.
-Пока задача находится в критической секции, все другие задачи, которые могут
-послать запрос переменной *не могут запуститься*.
-
-Насколько большим должен быть динамический приориткт, чтобы гарантировать запрет изменений
-определенного ресурса? [Анализ приоритетов](ceilings.html) отвечает на этот вопрос
-и будет обсужден в следующем разделе. В этом разделе мы сфокусируемся
-на реализации критической секции.
-
-## Прокси-ресурсы
-
-Для упрощения, давайте взглянем на ресурс, разделяемый двумя задачами,
-запускаемыми с разными приоритетами. Очевидно, что одна задача может вытеснить
-другую; чтобы предотвратить гонку данных задача с *низким приоритетом* должна
-использовать критическую секцию, когда необходимо изменять разделяемую память.
-С другой стороны, высокоприоритетная задача может напрямую изменять
-разделяемую память, поскольку не может быть вытеснена низкоприоритетной задачей.
-Чтобы заставить использовать критическую секцию на задаче с низким приоритетом,
-мы предоставляем *прокси-ресурсы*, в которых мы отдаем уникальную ссылку
-(`&mut-`) высокоприоритетной задаче.
-
-Пример ниже показывает разные типы, передаваемые каждой задаче:
-
-``` rust
-#[rtic::app(device = ..)]
-mut app {
- struct Resources {
- #[init(0)]
- x: u64,
- }
-
- #[interrupt(binds = UART0, priority = 1, resources = [x])]
- fn foo(c: foo::Context) {
- // прокси-ресурс
- let mut x: resources::x = c.resources.x;
-
- x.lock(|x: &mut u64| {
- // критическая секция
- *x += 1
- });
- }
-
- #[interrupt(binds = UART1, priority = 2, resources = [x])]
- fn bar(c: bar::Context) {
- let mut x: &mut u64 = c.resources.x;
-
- *x += 1;
- }
-
- // ..
-}
-```
-
-Теперь давайте посмотрим. как эти типы создаются фреймворком.
-
-``` rust
-fn foo(c: foo::Context) {
- // .. пользовательский код ..
-}
-
-fn bar(c: bar::Context) {
- // .. пользовательский код ..
-}
-
-pub mod resources {
- pub struct x {
- // ..
- }
-}
-
-pub mod foo {
- pub struct Resources {
- pub x: resources::x,
- }
-
- pub struct Context {
- pub resources: Resources,
- // ..
- }
-}
-
-pub mod bar {
- pub struct Resources<'a> {
- pub x: &'a mut u64,
- }
-
- pub struct Context {
- pub resources: Resources,
- // ..
- }
-}
-
-mod app {
- static mut x: u64 = 0;
-
- impl rtic::Mutex for resources::x {
- type T = u64;
-
- fn lock<R>(&mut self, f: impl FnOnce(&mut u64) -> R) -> R {
- // мы рассмотрим это детально позднее
- }
- }
-
- #[no_mangle]
- unsafe fn UART0() {
- foo(foo::Context {
- resources: foo::Resources {
- x: resources::x::new(/* .. */),
- },
- // ..
- })
- }
-
- #[no_mangle]
- unsafe fn UART1() {
- bar(bar::Context {
- resources: bar::Resources {
- x: &mut x,
- },
- // ..
- })
- }
-}
-```
-
-## `lock`
-
-Теперь давайте рассмотрим непосредственно критическую секцию. В этом примере мы должны
-увеличить динамический приоритет минимум до `2`, чтобы избежать гонки данных.
-В архитектуре Cortex-M динамический приоритет можно изменить записью в регистр `BASEPRI`.
-
-Семантика регистра `BASEPRI` такова:
-
-- Запись `0` в `BASEPRI` отключает его функциональность.
-- Запись ненулевого значения в `BASEPRI` изменяет уровень приоритета, требуемого для
- вытеснения прерывания. Однако, это имеет эффект, только когда записываемое значение
- *меньше*, чем уровень приоритета текущего контекста выполнения, но обращаем внимание, что
- более низкий уровень аппаратного приоритета означает более высокий логический приоритет
-
-Таким образом, динамический приоритет в любой момент времени может быть рассчитан как
-
-``` rust
-dynamic_priority = max(hw2logical(BASEPRI), hw2logical(static_priority))
-```
-
-Где `static_priority` - приоритет, запрограммированный в NVIC для текущего прерывания,
-или логический `0`, когда текущий контекств - это `idle`.
-
-В этом конкретном примере мы можем реализовать критическую секцию так:
-
-> **ПРИМЕЧАНИЕ:** это упрощенная реализация
-
-``` rust
-impl rtic::Mutex for resources::x {
- type T = u64;
-
- fn lock<R, F>(&mut self, f: F) -> R
- where
- F: FnOnce(&mut u64) -> R,
- {
- unsafe {
- // начать критическую секцию: увеличить динамический приоритет до `2`
- asm!("msr BASEPRI, 192" : : : "memory" : "volatile");
-
- // запустить пользовательский код в критической секции
- let r = f(&mut x);
-
- // окончить критическую секцию: восстановить динамический приоритет до статического значения (`1`)
- asm!("msr BASEPRI, 0" : : : "memory" : "volatile");
-
- r
- }
- }
-}
-```
-
-В данном случае важно указать `"memory"` в блоке `asm!`.
-Это не даст компилятору менять местами операции вокруг него.
-Это важно, поскольку доступ к переменной `x` вне критической секции привело бы
-к гонке данных.
-
-Важно отметить, что сигнатура метода `lock` препятствет его вложенным вызовам.
-Это необходимо для безопасности памяти, так как вложенные вызовы привели бы
-к созданию множественных уникальных ссылок (`&mut-`) на `x`, ломая правила заимствования Rust.
-Смотреть ниже:
-
-``` rust
-#[interrupt(binds = UART0, priority = 1, resources = [x])]
-fn foo(c: foo::Context) {
- // resource proxy
- let mut res: resources::x = c.resources.x;
-
- res.lock(|x: &mut u64| {
- res.lock(|alias: &mut u64| {
- //~^ ошибка: `res` уже был заимствован уникально (`&mut-`)
- // ..
- });
- });
-}
-```
-
-## Вложенность
-
-Вложенные вызовы `lock` на *том же* ресурсе должны отклоняться компилятором
-для безопасности памяти, однако вложенные вызовы `lock` на *разных* ресурсах -
-нормальная операция. В этом случае мы хотим убедиться, что вложенные критические секции
-никогда не приведут к понижению динамического приоритета, так как это плохо,
-и мы хотим оптимизировать несколько записей в регистр `BASEPRI` и compiler fences.
-Чтобы справиться с этим, мы проследим динамический приоритет задачи, с помощью стековой
-переменной и используем ее, чтобы решить, записывать `BASEPRI` или нет.
-На практике, стековая переменная будет соптимизирована компилятором, но все еще
-будет предоставлять информацию компилятору.
-
-Рассмотрим такую программу:
-
-``` rust
-#[rtic::app(device = ..)]
-mod app {
- struct Resources {
- #[init(0)]
- x: u64,
- #[init(0)]
- y: u64,
- }
-
- #[init]
- fn init() {
- rtic::pend(Interrupt::UART0);
- }
-
- #[interrupt(binds = UART0, priority = 1, resources = [x, y])]
- fn foo(c: foo::Context) {
- let mut x = c.resources.x;
- let mut y = c.resources.y;
-
- y.lock(|y| {
- *y += 1;
-
- *x.lock(|x| {
- x += 1;
- });
-
- *y += 1;
- });
-
- // середина
-
- x.lock(|x| {
- *x += 1;
-
- y.lock(|y| {
- *y += 1;
- });
-
- *x += 1;
- })
- }
-
- #[interrupt(binds = UART1, priority = 2, resources = [x])]
- fn bar(c: foo::Context) {
- // ..
- }
-
- #[interrupt(binds = UART2, priority = 3, resources = [y])]
- fn baz(c: foo::Context) {
- // ..
- }
-
- // ..
-}
-```
-
-Код, сгенерированный фреймворком, выглядит так:
-
-``` rust
-// опущено: пользовательский код
-
-pub mod resources {
- pub struct x<'a> {
- priority: &'a Cell<u8>,
- }
-
- impl<'a> x<'a> {
- pub unsafe fn new(priority: &'a Cell<u8>) -> Self {
- x { priority }
- }
-
- pub unsafe fn priority(&self) -> &Cell<u8> {
- self.priority
- }
- }
-
- // repeat for `y`
-}
-
-pub mod foo {
- pub struct Context {
- pub resources: Resources,
- // ..
- }
-
- pub struct Resources<'a> {
- pub x: resources::x<'a>,
- pub y: resources::y<'a>,
- }
-}
-
-mod app {
- use cortex_m::register::basepri;
-
- #[no_mangle]
- unsafe fn UART1() {
- // статический приоритет прерывания (определено пользователем)
- const PRIORITY: u8 = 2;
-
- // сделать снимок BASEPRI
- let initial = basepri::read();
-
- let priority = Cell::new(PRIORITY);
- bar(bar::Context {
- resources: bar::Resources::new(&priority),
- // ..
- });
-
- // вернуть BASEPRI значение из снимка, сделанного ранее
- basepri::write(initial); // то же, что и `asm!` блок, виденный ранее
- }
-
- // так же для `UART0` / `foo` и `UART2` / `baz`
-
- impl<'a> rtic::Mutex for resources::x<'a> {
- type T = u64;
-
- fn lock<R>(&mut self, f: impl FnOnce(&mut u64) -> R) -> R {
- unsafe {
- // определение максимального приоритет ресурса
- const CEILING: u8 = 2;
-
- let current = self.priority().get();
- if current < CEILING {
- // увеличить динамический приоритет
- self.priority().set(CEILING);
- basepri::write(logical2hw(CEILING));
-
- let r = f(&mut y);
-
- // восстановить динамический приоритет
- basepri::write(logical2hw(current));
- self.priority().set(current);
-
- r
- } else {
- // динамический приоритет достаточно высок
- f(&mut y)
- }
- }
- }
- }
-
- // повторить для ресурса `y`
-}
-```
-
-Наконец, компилятор оптимизирует функцию `foo` во что-то наподобие такого:
-
-``` rust
-fn foo(c: foo::Context) {
- // ПРИМЕЧАНИЕ: BASEPRI содержит значение `0` (значение сброса) в этот момент
-
- // увеличить динамический приоритет до `3`
- unsafe { basepri::write(160) }
-
- // две операции над `y` объединены в одну
- y += 2;
-
- // BASEPRI не изменяется для доступа к `x`, потому что динамический приоритет достаточно высок
- x += 1;
-
- // уменьшить (восстановить) динамический приоритет до `1`
- unsafe { basepri::write(224) }
-
- // средина
-
- // увеличить динамический приоритет до `2`
- unsafe { basepri::write(192) }
-
- x += 1;
-
- // увеличить динамический приоритет до `3`
- unsafe { basepri::write(160) }
-
- y += 1;
-
- // уменьшить (восстановить) динамический приоритет до `2`
- unsafe { basepri::write(192) }
-
- // ПРИМЕЧАНИЕ: было вы правильно объединить эту операцию над `x` с предыдущей, но
- // compiler fences грубые и предотвращают оптимизацию
- x += 1;
-
- // уменьшить (восстановить) динамический приоритет до `1`
- unsafe { basepri::write(224) }
-
- // ПРИМЕЧАНИЕ: BASEPRI содержит значение `224` в этот момент
- // обработчик UART0 восстановит значение `0` перед завершением
-}
-```
-
-## Инвариант BASEPRI
-
-Инвариант, который фреймворк RTIC должен сохранять в том, что значение
-BASEPRI в начале обработчика *прерывания* должно быть таким же, как и при выходе
-из него. BASEPRI может изменяться в процессе выполнения обработчика прерывания,
-но но выполнения обработчика прерывания в начале и конце не должно вызвать
-наблюдаемого изменения BASEPRI.
-
-Этот инвариант нужен, чтобы избежать уеличения динамического приоритета до значений,
-при которых обработчик не сможет быть вытеснен. Лучше всего это видно на следующем примере:
-
-``` rust
-#[rtic::app(device = ..)]
-mod app {
- struct Resources {
- #[init(0)]
- x: u64,
- }
-
- #[init]
- fn init() {
- // `foo` запустится сразу после завершения `init`
- rtic::pend(Interrupt::UART0);
- }
-
- #[task(binds = UART0, priority = 1)]
- fn foo() {
- // BASEPRI равен `0` в этот момент; динамический приоритет равен `1`
-
- // `bar` вытеснит `foo` в этот момент
- rtic::pend(Interrupt::UART1);
-
- // BASEPRI равен `192` в этот момент (из-за бага); динамический приоритет равен `2`
- // эта функция возвращается в `idle`
- }
-
- #[task(binds = UART1, priority = 2, resources = [x])]
- fn bar() {
- // BASEPRI равен `0` (динамический приоритет = 2)
-
- x.lock(|x| {
- // BASEPRI увеличен до `160` (динамический приоритет = 3)
-
- // ..
- });
-
- // BASEPRI восстановлен до `192` (динамический приоритет = 2)
- }
-
- #[idle]
- fn idle() -> ! {
- // BASEPRI равен `192` (из-за бага); динамический приоритет = 2
-
- // это не оказывает эффекта, из-за значени BASEPRI
- // задача `foo` не будет выполнена снова никогда
- rtic::pend(Interrupt::UART0);
-
- loop {
- // ..
- }
- }
-
- #[task(binds = UART2, priority = 3, resources = [x])]
- fn baz() {
- // ..
- }
-
-}
-```
-
-ВАЖНО: давайте например мы *забудем* восстановить `BASEPRI` в `UART1` -- из-за
-какого нибудь бага в генераторе кода RTIC.
-
-``` rust
-// код, сгенерированный RTIC
-
-mod app {
- // ..
-
- #[no_mangle]
- unsafe fn UART1() {
- // статический приоритет этого прерывания (определен пользователем)
- const PRIORITY: u8 = 2;
-
- // сделать снимок BASEPRI
- let initial = basepri::read();
-
- let priority = Cell::new(PRIORITY);
- bar(bar::Context {
- resources: bar::Resources::new(&priority),
- // ..
- });
-
- // БАГ: ЗАБЫЛИ восстановить BASEPRI на значение из снимка
- basepri::write(initial);
- }
-}
-```
-
-В результате, `idle` запустится на динамическом приоритете `2` и на самом деле
-система больше никогда не перейдет на динамический приоритет ниже `2`.
-Это не компромис для безопасности памяти программы, а влияет на диспетчеризацию задач:
-в этом конкретном случае задачи с приоритетом `1` никогда не получат шанс на запуск.
diff --git a/book/ru/src/internals/interrupt-configuration.md b/book/ru/src/internals/interrupt-configuration.md
deleted file mode 100644
index 5631b37..0000000
--- a/book/ru/src/internals/interrupt-configuration.md
+++ /dev/null
@@ -1,72 +0,0 @@
-# Настройка прерываний
-
-Прерывания - это основа работы программ на RTIC. Правильно настроить приоритеты
-прерываний и убедиться, что они не изменяются во время выполнения обязательно
-для безопасной работы программы.
-
-Фреймворк RTIC представляет приоритеты прерываний, как нечто, что должно быть определено
-на этапе компиляции. Однако, статическая настройка должна быть зашита в соответствующие регистры
-в процессе инициализации программы. Настройка прерываний происходит до запуска функции `init`.
-
-Этот пример дает представление о коде, запускаемом фреймворком RTIC:
-
-``` rust
-#[rtic::app(device = lm3s6965)]
-mod app {
- #[init]
- fn init(c: init::Context) {
- // .. пользовательский код ..
- }
-
- #[idle]
- fn idle(c: idle::Context) -> ! {
- // .. пользовательский код ..
- }
-
- #[interrupt(binds = UART0, priority = 2)]
- fn foo(c: foo::Context) {
- // .. пользовательский код ..
- }
-}
-```
-
-Фреймворк генерирует точку входа в программу, которая выглядит примерно так:
-
-``` rust
-// настоящая точку входа в программу
-#[no_mangle]
-unsafe fn main() -> ! {
- // преобразует логические приоритеты в аппаратные / NVIC приоритеты
- fn logical2hw(priority: u8) -> u8 {
- use lm3s6965::NVIC_PRIO_BITS;
-
- // NVIC кодирует приоритеты верхними битами
- // большие значения обозначают меньший приоритет
- ((1 << NVIC_PRIORITY_BITS) - priority) << (8 - NVIC_PRIO_BITS)
- }
-
- cortex_m::interrupt::disable();
-
- let mut core = cortex_m::Peripheral::steal();
-
- core.NVIC.enable(Interrupt::UART0);
-
- // значение, определенное пользователем
- let uart0_prio = 2;
-
- // проверка на этапе компиляции, что определенный приоритет входит в поддерживаемый диапазон
- let _ = [(); (1 << NVIC_PRIORITY_BITS) - (uart0_prio as usize)];
-
- core.NVIC.set_priority(Interrupt::UART0, logical2hw(uart0_prio));
-
- // вызов пользовательского кода
- init(/* .. */);
-
- // ..
-
- cortex_m::interrupt::enable();
-
- // вызов пользовательского кода
- idle(/* .. */)
-}
-```
diff --git a/book/ru/src/internals/late-resources.md b/book/ru/src/internals/late-resources.md
deleted file mode 100644
index 146c438..0000000
--- a/book/ru/src/internals/late-resources.md
+++ /dev/null
@@ -1,113 +0,0 @@
-# Поздние ресурсы
-
-Некоторые ресурсы инициализируются во время выполнения после завершения функции `init`.
-Важно то, что ресурсы (статические переменные) полностью инициализируются
-до того, как задачи смогут запуститься, вот почему они должны быть инициализированы
-пока прерывания отключены.
-
-Ниже показан пример кода, генерируемого фреймворком для инициализации позних ресурсов.
-
-``` rust
-#[rtic::app(device = ..)]
-mod app {
- struct Resources {
- x: Thing,
- }
-
- #[init]
- fn init() -> init::LateResources {
- // ..
-
- init::LateResources {
- x: Thing::new(..),
- }
- }
-
- #[task(binds = UART0, resources = [x])]
- fn foo(c: foo::Context) {
- let x: &mut Thing = c.resources.x;
-
- x.frob();
-
- // ..
- }
-
- // ..
-}
-```
-
-Код, генерируемы фреймворком выглядит примерно так:
-
-``` rust
-fn init(c: init::Context) -> init::LateResources {
- // .. пользовательский код ..
-}
-
-fn foo(c: foo::Context) {
- // .. пользовательский код ..
-}
-
-// Public API
-pub mod init {
- pub struct LateResources {
- pub x: Thing,
- }
-
- // ..
-}
-
-pub mod foo {
- pub struct Resources<'a> {
- pub x: &'a mut Thing,
- }
-
- pub struct Context<'a> {
- pub resources: Resources<'a>,
- // ..
- }
-}
-
-/// Детали реализации
-mod app {
- // неинициализированная статическая переменная
- static mut x: MaybeUninit<Thing> = MaybeUninit::uninit();
-
- #[no_mangle]
- unsafe fn main() -> ! {
- cortex_m::interrupt::disable();
-
- // ..
-
- let late = init(..);
-
- // инициализация поздних ресурсов
- x.as_mut_ptr().write(late.x);
-
- cortex_m::interrupt::enable(); //~ compiler fence
-
- // исключения, прерывания и задачи могут вытеснить `main` в этой точке
-
- idle(..)
- }
-
- #[no_mangle]
- unsafe fn UART0() {
- foo(foo::Context {
- resources: foo::Resources {
- // `x` уже инициализирована к этому моменту
- x: &mut *x.as_mut_ptr(),
- },
- // ..
- })
- }
-}
-```
-
-Важная деталь здесь то, что `interrupt::enable` ведет себя как *барьер компиляции*, который не дает компилятору переставить запись в `X` *после*
-`interrupt::enable`. Если бы компилятор мог делать такие перестановки появились
-бы гонки данных между этой записью и любой операцией `foo`, взаимодействующей с `X`.
-
-Архитектурам с более сложным конвейером инструкций нужен барьер памяти
-(`atomic::fence`) вместо compiler fence для полной очистки операции записи
-перед включением прерываний. Архитектура ARM Cortex-M не нуждается в барьере памяти
-в одноядерном контексте.
diff --git a/book/ru/src/internals/non-reentrancy.md b/book/ru/src/internals/non-reentrancy.md
deleted file mode 100644
index 98eb00f..0000000
--- a/book/ru/src/internals/non-reentrancy.md
+++ /dev/null
@@ -1,79 +0,0 @@
-# Нереентерабельность
-
-В RTIC задачи-обработчики *не* могут использоваться повторно. Переиспользование задачи-обработчика
-может сломать правила заимствования Rust и привести к *неопределенному поведению*.
-Задача-обработчик теоретически может быть переиспользована одним из двух способов: программно или аппаратно.
-
-## Программно
-
-Чтобы переиспользовать задачу-обработчик программно, назначенный ей обработчик прерывания
-должен быть вызван с помощью FFI (смотрите пример ниже). FFI требует `unsafe` код,
-что уменьшает желание конечных пользователей вызывать обработчик прерывания.
-
-``` rust
-#[rtic::app(device = ..)]
-mod app {
- #[init]
- fn init(c: init::Context) { .. }
-
- #[interrupt(binds = UART0)]
- fn foo(c: foo::Context) {
- static mut X: u64 = 0;
-
- let x: &mut u64 = X;
-
- // ..
-
- //~ `bar` может вытеснить `foo` в этом месте
-
- // ..
- }
-
- #[interrupt(binds = UART1, priority = 2)]
- fn bar(c: foo::Context) {
- extern "C" {
- fn UART0();
- }
-
- // этот обработчик прерывания вызовет задачу-обработчик `foo`, что сломает
- // ссылку на статическую переменную `X`
- unsafe { UART0() }
- }
-}
-```
-
-Фреймворк RTIC должен сгенерировать код обработчика прерывания, который вызывает
-определенные пользователем задачи-обработчики. Мы аккуратны в том, чтобы обеспечить
-невозможность вызова этих обработчиков из пользовательского кода.
-
-Пример выше раскрывается в:
-
-``` rust
-fn foo(c: foo::Context) {
- // .. пользовательский код ..
-}
-
-fn bar(c: bar::Context) {
- // .. пользовательский код ..
-}
-
-mod app {
- // все в этом блоке невидимо для пользовательского кода
-
- #[no_mangle]
- unsafe fn USART0() {
- foo(..);
- }
-
- #[no_mangle]
- unsafe fn USART1() {
- bar(..);
- }
-}
-```
-
-## Аппаратно
-
-Обработчик прерывания также может быть вызван без программного вмешательства.
-Это может произойти, если один обработчик будет назначен двум или более прерываниям
-в векторе прерываний, но синтаксиса для такого рода функциональности в RTIC нет.
diff --git a/book/ru/src/internals/tasks.md b/book/ru/src/internals/tasks.md
deleted file mode 100644
index 01380ba..0000000
--- a/book/ru/src/internals/tasks.md
+++ /dev/null
@@ -1,399 +0,0 @@
-# Программные задачи
-
-RTIC поддерживает программные и аппаратные задачи. Каждая аппаратная задача
-назначается на отдельный обработчик прерывания. С другой стороны, несколько
-программных задач могут управляться одним обработчиком прерывания --
-это сделано, чтобы минимизировать количество обработчиков прерывания,
-используемых фреймворком.
-
-Фреймворк группирует задачи, для которых вызывается `spawn` по уровню приоритета,
-и генерирует один *диспетчер задачи* для каждого уровня приоритета.
-Каждый диспетчер запускается на отдельном обработчике прерывания,
-а приоритет этого обработчика прерывания устанавливается так, чтобы соответствовать
-уровню приоритета задач, управляемых диспетчером.
-
-Каждый диспетчер задач хранит *очередь* задач, *готовых* к выполнению;
-эта очередь называется *очередью готовности*. Вызов программной задачи состоит
-из добавления записи в очередь и вызова прерывания, который запускает соответствующий
-диспетчер задач. Каждая запись в эту очередь содержит метку (`enum`),
-которая идентифицирует задачу, которую необходимо выполнить и *указатель*
-на сообщение, передаваемое задаче.
-
-Очередь готовности - неблокируемая очередь типа SPSC (один производитель - один потребитель).
-Диспетчер задач владеет конечным потребителем в очереди; конечным производителем
-считается ресурс, за который соперничают задачи, которые могут вызывать (`spawn`) другие задачи.
-
-## Дисметчер задач
-
-Давайте сначала глянем на код, генерируемый фреймворком для диспетчеризации задач.
-Рассмотрим пример:
-
-``` rust
-#[rtic::app(device = ..)]
-mod app {
- // ..
-
- #[interrupt(binds = UART0, priority = 2, spawn = [bar, baz])]
- fn foo(c: foo::Context) {
- foo.spawn.bar().ok();
-
- foo.spawn.baz(42).ok();
- }
-
- #[task(capacity = 2, priority = 1)]
- fn bar(c: bar::Context) {
- // ..
- }
-
- #[task(capacity = 2, priority = 1, resources = [X])]
- fn baz(c: baz::Context, input: i32) {
- // ..
- }
-
- extern "C" {
- fn UART1();
- }
-}
-```
-
-Фреймворк создает следующий диспетчер задач, состоящий из обработчика прерывания и очереди готовности:
-
-``` rust
-fn bar(c: bar::Context) {
- // .. пользовательский код ..
-}
-
-mod app {
- use heapless::spsc::Queue;
- use cortex_m::register::basepri;
-
- struct Ready<T> {
- task: T,
- // ..
- }
-
- /// вызываемые (`spawn`) задачи, выполняющиеся с уровнем приоритета `1`
- enum T1 {
- bar,
- baz,
- }
-
- // очередь готовности диспетчера задач
- // `5-1=4` - представляет собой емкость этой очереди
- static mut RQ1: Queue<Ready<T1>, 5> = Queue::new();
-
- // обработчик прерывания, выбранный для диспетчеризации задач с приоритетом `1`
- #[no_mangle]
- unsafe UART1() {
- // приоритет данного обработчика прерывания
- const PRIORITY: u8 = 1;
-
- let snapshot = basepri::read();
-
- while let Some(ready) = RQ1.split().1.dequeue() {
- match ready.task {
- T1::bar => {
- // **ПРИМЕЧАНИЕ** упрощенная реализация
-
- // используется для отслеживания динамического приоритета
- let priority = Cell::new(PRIORITY);
-
- // вызов пользовательского кода
- bar(bar::Context::new(&priority));
- }
-
- T1::baz => {
- // рассмотрим `baz` позднее
- }
- }
- }
-
- // инвариант BASEPRI
- basepri::write(snapshot);
- }
-}
-```
-
-## Вызов задачи
-
-Интерфейс `spawn` предоставлен пользователю как методы структурв `Spawn`.
-Для каждой задачи существует своя структура `Spawn`.
-
-Код `Spawn`, генерируемый фреймворком для предыдущего примера выглядит так:
-
-``` rust
-mod foo {
- // ..
-
- pub struct Context<'a> {
- pub spawn: Spawn<'a>,
- // ..
- }
-
- pub struct Spawn<'a> {
- // отслеживает динамический приоритет задачи
- priority: &'a Cell<u8>,
- }
-
- impl<'a> Spawn<'a> {
- // `unsafe` и спрятано, поскольку сы не хотит, чтобы пользователь вмешивался сюда
- #[doc(hidden)]
- pub unsafe fn priority(&self) -> &Cell<u8> {
- self.priority
- }
- }
-}
-
-mod app {
- // ..
-
- // Поиск максимального приоритета для конечного производителя `RQ1`
- const RQ1_CEILING: u8 = 2;
-
- // используется, чтобы отследить сколько еще сообщений для `bar` можно поставить в очередь
- // `3-1=2` - емкость задачи `bar`; максимум 2 экземпляра можно добавить в очередь
- // эта очередь заполняется фреймворком до того, как запустится `init`
- static mut bar_FQ: Queue<(), 3> = Queue::new();
-
- // Поиск максимального приоритета для конечного потребителя `bar_FQ`
- const bar_FQ_CEILING: u8 = 2;
-
- // приоритет-ориентированная критическая секция
- //
- // это запускае переданное замыкание `f` с динамическим приоритетом не ниже
- // `ceiling`
- fn lock(priority: &Cell<u8>, ceiling: u8, f: impl FnOnce()) {
- // ..
- }
-
- impl<'a> foo::Spawn<'a> {
- /// Вызывает задачу `bar`
- pub fn bar(&self) -> Result<(), ()> {
- unsafe {
- match lock(self.priority(), bar_FQ_CEILING, || {
- bar_FQ.split().1.dequeue()
- }) {
- Some(()) => {
- lock(self.priority(), RQ1_CEILING, || {
- // помещаем задачу в очередь готовности
- RQ1.split().1.enqueue_unchecked(Ready {
- task: T1::bar,
- // ..
- })
- });
-
- // вызываем прерывание, которое запускает диспетчер задач
- rtic::pend(Interrupt::UART0);
- }
-
- None => {
- // достигнута максимальная вместительность; неудачный вызов
- Err(())
- }
- }
- }
- }
- }
-}
-```
-
-Использование `bar_FQ` для ограничения числа задач `bar`, которые могут бы вызваны,
-может показаться искусственным, но это будет иметь больше смысла, когда мы поговорим
-о вместительности задач.
-
-## Сообщения
-
-Мы пропустили, как на самом деле работает передача сообщений, поэтому давайте вернемся
-к реализации `spawn`, но в этот раз для задачи `baz`, которая принимает сообщение типа `u64`.
-
-``` rust
-fn baz(c: baz::Context, input: u64) {
- // .. пользовательский код ..
-}
-
-mod app {
- // ..
-
- // Теперь мы покажем все содержимое структуры `Ready`
- struct Ready {
- task: Task,
- // индекс сообщения; используется с буфером `INPUTS`
- index: u8,
- }
-
- // память, зарезервированная для хранения сообщений, переданных `baz`
- static mut baz_INPUTS: [MaybeUninit<u64>; 2] =
- [MaybeUninit::uninit(), MaybeUninit::uninit()];
-
- // список свободной памяти: используется для отслеживания свободных ячеек в массиве `baz_INPUTS`
- // эта очередь инициализируется значениями `0` и `1` перед запуском `init`
- static mut baz_FQ: Queue<u8, 3> = Queue::new();
-
- // Поиск максимального приоритета для конечного потребителя `baz_FQ`
- const baz_FQ_CEILING: u8 = 2;
-
- impl<'a> foo::Spawn<'a> {
- /// Spawns the `baz` task
- pub fn baz(&self, message: u64) -> Result<(), u64> {
- unsafe {
- match lock(self.priority(), baz_FQ_CEILING, || {
- baz_FQ.split().1.dequeue()
- }) {
- Some(index) => {
- // ПРИМЕЧАНИЕ: `index` - владеющий указатель на ячейку буфера
- baz_INPUTS[index as usize].write(message);
-
- lock(self.priority(), RQ1_CEILING, || {
- // помещаем задачу в очередь готовности
- RQ1.split().1.enqueue_unchecked(Ready {
- task: T1::baz,
- index,
- });
- });
-
- // вызываем прерывание, которое запускает диспетчер задач
- rtic::pend(Interrupt::UART0);
- }
-
- None => {
- // достигнута максимальная вместительность; неудачный вызов
- Err(message)
- }
- }
- }
- }
- }
-}
-```
-
-А теперь давайте взглянем на настоящую реализацию диспетчера задач:
-
-``` rust
-mod app {
- // ..
-
- #[no_mangle]
- unsafe UART1() {
- const PRIORITY: u8 = 1;
-
- let snapshot = basepri::read();
-
- while let Some(ready) = RQ1.split().1.dequeue() {
- match ready.task {
- Task::baz => {
- // ПРИМЕЧАНИЕ: `index` - владеющий указатель на ячейку буфера
- let input = baz_INPUTS[ready.index as usize].read();
-
- // сообщение было прочитано, поэтому можно вернуть ячейку обратно
- // чтобы освободить очередь
- // (диспетчер задач имеет эксклюзивный доступ к
- // последнему элементу очереди)
- baz_FQ.split().0.enqueue_unchecked(ready.index);
-
- let priority = Cell::new(PRIORITY);
- baz(baz::Context::new(&priority), input)
- }
-
- Task::bar => {
- // выглядит также как ветка для `baz`
- }
-
- }
- }
-
- // инвариант BASEPRI
- basepri::write(snapshot);
- }
-}
-```
-
-`INPUTS` плюс `FQ`, список свободной памяти равняется эффективному пулу памяти.
-Однако, вместо того *список свободной памяти* (связный список), чтобы отслеживать
-пустые ячейки в буфере `INPUTS`, мы используем SPSC очередь; это позволяет нам
-уменьшить количество критических секций.
-На самом деле благодаря этому выбору код диспетчера задач неблокируемый.
-
-## Вместительность очереди
-
-Фреймворк RTIC использует несколько очередей, такие как очереди готовности и
-списки свободной памяти. Когда список свободной памяти пуст, попытка выызова
-(`spawn`) задачи приводит к ошибке; это условие проверяется во время выполнения.
-Не все операции, произвожимые фреймворком с этими очередями проверяют их
-пустоту / наличие места. Например, возвращение ячейки списка свободной памяти
-(см. диспетчер задач) не проверяется, поскольку есть фиксированное количество
-таких ячеек циркулирующих в системе, равное вместительности списка свободной памяти.
-Аналогично, добавление записи в очередь готовности (см. `Spawn`) не проверяется,
-потому что вместительность очереди выбрана фреймворком.
-
-Пользователи могут задавать вместительность программных задач;
-эта вместительность - максимальное количество сообщений, которые можно
-послать указанной задаче от задачи более высоким приоритетом до того,
-как `spawn` вернет ошибку. Эта определяемая пользователем иместительность -
-размер списка свободной памяти задачи (например `foo_FQ`), а также размер массива,
-содержащего входные данные для задачи (например `foo_INPUTS`).
-
-Вместительность очереди готовности (например `RQ1`) вычисляется как *сумма*
-вместительностей всех задач, управляемх диспетчером; эта сумма является также
-количеством сообщений, которые очередь может хранить в худшем сценарии, когда
-все возможные сообщения были посланы до того, как диспетчер задач получает шанс
-на запуск. По этой причине получение ячейки списка свободной памяти при любой
-операции `spawn` приводит к тому, что очередь готовности еще не заполнена,
-поэтому вставка записи в список готовности может пропустить проверку "полна ли очередь?".
-
-В нашем запущенном примере задача `bar` не принимает входных данных, поэтому
-мы можем пропустить проверку как `bar_INPUTS`, так и `bar_FQ` и позволить
-пользователю посылать неограниченное число сообщений задаче, но если бы мы сделали это,
-было бы невозможно превысить вместительность для `RQ1`, что позволяет нам
-пропустить проверку "полна ли очередь?" при вызове задачи `baz`.
-В разделе о [очереди таймера](timer-queue.html) мы увидим как
-список свободной памяти используется для задач без входных данных.
-
-## Анализ приоритетов
-
-Очереди, использемые внутри интерфейса `spawn`, рассматриваются как обычные ресурсы
-и для них тоже работает анализ приоритетов. Важно заметить, что это SPSC очереди,
-и только один из конечных элементов становится ресурсом; другим конечным элементом
-владеет диспетчер задач.
-
-Рассмотрим следующий пример:
-
-``` rust
-#[rtic::app(device = ..)]
-mod app {
- #[idle(spawn = [foo, bar])]
- fn idle(c: idle::Context) -> ! {
- // ..
- }
-
- #[task]
- fn foo(c: foo::Context) {
- // ..
- }
-
- #[task]
- fn bar(c: bar::Context) {
- // ..
- }
-
- #[task(priority = 2, spawn = [foo])]
- fn baz(c: baz::Context) {
- // ..
- }
-
- #[task(priority = 3, spawn = [bar])]
- fn quux(c: quux::Context) {
- // ..
- }
-}
-```
-
-Вот как будет проходить анализ приоритетов:
-
-- `idle` (prio = 0) и `baz` (prio = 2) соревнуются за конечный потребитель
- `foo_FQ`; это приводит к максимальному приоритету `2`.
-
-- `idle` (prio = 0) и `quux` (prio = 3) соревнуются за конечный потребитель
- `bar_FQ`; это приводит к максимальному приоритету `3`.
-
-- `idle` (prio = 0), `baz` (prio = 2) и `quux` (prio = 3) соревнуются за
- конечный производитель `RQ1`; это приводит к максимальному приоритету `3`
diff --git a/book/ru/src/internals/timer-queue.md b/book/ru/src/internals/timer-queue.md
deleted file mode 100644
index 9f2dc37..0000000
--- a/book/ru/src/internals/timer-queue.md
+++ /dev/null
@@ -1,372 +0,0 @@
-# Очередь таймера
-
-Функциональность очередь таймера позволяет пользователю планировать задачи на запуск
-в опреленное время в будущем. Неудивительно, что эта функция также реализуется с помощью очереди:
-очередь приоритетов, где запланированные задачи сортируются в порядке аозрастания времени.
-Эта функция требует таймер, способный устанавливать прерывания истечения времени.
-Таймер используется для пуска прерывания, когда настает запланированное время задачи;
-в этот момент задача удаляется из очереди таймера и помещается в очередь готовности.
-
-Давайте посмотрим, как это реализовано в коде. Рассмотрим следующую программу:
-
-``` rust
-#[rtic::app(device = ..)]
-mod app {
- // ..
-
- #[task(capacity = 2, schedule = [foo])]
- fn foo(c: foo::Context, x: u32) {
- // запланировать задачу на повторный запуск через 1 млн. тактов
- c.schedule.foo(c.scheduled + Duration::cycles(1_000_000), x + 1).ok();
- }
-
- extern "C" {
- fn UART0();
- }
-}
-```
-
-## `schedule`
-
-Давайте сначала взглянем на интерфейс `schedule`.
-
-``` rust
-mod foo {
- pub struct Schedule<'a> {
- priority: &'a Cell<u8>,
- }
-
- impl<'a> Schedule<'a> {
- // `unsafe` и спрятано, потому что мы не хотим, чтобы пользовать сюда вмешивался
- #[doc(hidden)]
- pub unsafe fn priority(&self) -> &Cell<u8> {
- self.priority
- }
- }
-}
-
-mod app {
- type Instant = <path::to::user::monotonic::timer as rtic::Monotonic>::Instant;
-
- // все задачи, которые могут быть запланированы (`schedule`)
- enum T {
- foo,
- }
-
- struct NotReady {
- index: u8,
- instant: Instant,
- task: T,
- }
-
- // Очередь таймера - двоичная куча (min-heap) задач `NotReady`
- static mut TQ: TimerQueue<U2> = ..;
- const TQ_CEILING: u8 = 1;
-
- static mut foo_FQ: Queue<u8, U2> = Queue::new();
- const foo_FQ_CEILING: u8 = 1;
-
- static mut foo_INPUTS: [MaybeUninit<u32>; 2] =
- [MaybeUninit::uninit(), MaybeUninit::uninit()];
-
- static mut foo_INSTANTS: [MaybeUninit<Instant>; 2] =
- [MaybeUninit::uninit(), MaybeUninit::uninit()];
-
- impl<'a> foo::Schedule<'a> {
- fn foo(&self, instant: Instant, input: u32) -> Result<(), u32> {
- unsafe {
- let priority = self.priority();
- if let Some(index) = lock(priority, foo_FQ_CEILING, || {
- foo_FQ.split().1.dequeue()
- }) {
- // `index` - владеющий укачатель на ячейки в этих буферах
- foo_INSTANTS[index as usize].write(instant);
- foo_INPUTS[index as usize].write(input);
-
- let nr = NotReady {
- index,
- instant,
- task: T::foo,
- };
-
- lock(priority, TQ_CEILING, || {
- TQ.enqueue_unchecked(nr);
- });
- } else {
- // Не осталось места, чтобы разместить входные данные / instant
- Err(input)
- }
- }
- }
- }
-}
-```
-
-Это очень похоже на реализацию `Spawn`. На самом деле одни и те же буфер
-`INPUTS` и список сободной памяти (`FQ`) используются совместно интерфейсами
-`spawn` и `schedule`. Главное отличие между ними в том, что `schedule` также
-размещает `Instant`, момент на который задача запланирована на запуск,
-в отдельном буфере (`foo_INSTANTS` в нашем случае).
-
-`TimerQueue::enqueue_unchecked` делает немного больше работы, чем
-просто добавление записи в min-heap: он также вызывает прерывание
-системного таймера (`SysTick`), если новая запись оказывается первой в очереди.
-
-## Системный таймер
-
-Прерывание системного таймера (`SysTick`) заботится о двух вещах:
-передаче задач, которых становятся готовыми из очереди таймера в очередь готовности
-и установке прерывания истечения времени, когда наступит запланированное
-время следующей задачи.
-
-Давайте посмотрим на соответствующий код.
-
-``` rust
-mod app {
- #[no_mangle]
- fn SysTick() {
- const PRIORITY: u8 = 1;
-
- let priority = &Cell::new(PRIORITY);
- while let Some(ready) = lock(priority, TQ_CEILING, || TQ.dequeue()) {
- match ready.task {
- T::foo => {
- // переместить эту задачу в очередь готовности `RQ1`
- lock(priority, RQ1_CEILING, || {
- RQ1.split().0.enqueue_unchecked(Ready {
- task: T1::foo,
- index: ready.index,
- })
- });
-
- // вызвать диспетчер задач
- rtic::pend(Interrupt::UART0);
- }
- }
- }
- }
-}
-```
-
-Выглядит похоже на диспетчер задач, за исключением того, что
-вместо запуска готовой задачи, она лишь переносится в очередь готовности,
-что ведет к ее запуску с нужным приоритетом.
-
-`TimerQueue::dequeue` установит новое прерывание истечения времени, если вернет
-`None`. Он сязан с `TimerQueue::enqueue_unchecked`, который вызывает это
-прерывание; на самом деле, `enqueue_unchecked` передает задачу установки
-нового прерывание истечения времени обработчику `SysTick`.
-
-## Точность и диапазон `cyccnt::Instant` и `cyccnt::Duration`
-
-RTIC предоставляет реализацию `Monotonic`, основанную на счетчике тактов `DWT` (Data Watchpoint and Trace). `Instant::now` возвращает снимок таймера; эти снимки
-DWT (`Instant`ы) используются для сортировки записей в очереди таймера.
-Счетчик тактов - 32-битный счетчик, работающий на частоте ядра.
-Этот счетчик обнуляется каждые `(1 << 32)` тактов; у нас нет прерывания,
-ассоциированног с этим счетчиком, поэтому ничего ужасного не случится,
-когда он пройдет оборот.
-
-Чтобы упорядочить `Instant`ы в очереди, нам нужно сравнить 32-битные целые.
-Чтобы учесть обороты, мы используем разницу между двумя `Instant`ами, `a - b`,
-и рассматриваем результат как 32-битное знаковое целое.
-Если результат меньше нуля, значит `b` более поздний `Instant`;
-если результат больше нуля, значит `b` более ранний `Instant`.
-Это значит, что планирование задачи на `Instant`, который на `(1 << 31) - 1` тактов
-больше, чем запланированное время (`Instant`) первой (самой ранней) записи
-в очереди приведет к тому, что задача будет помещена в неправильное
-место в очереди. У нас есть несколько debug assertions в коде, чтобы
-предотвратить эту пользовательскую ошибку, но этого нельзя избежать,
-поскольку пользователь может написать
-`(instant + duration_a) + duration_b` и переполнить `Instant`.
-
-Системный таймер, `SysTick` - 24-битный счетчик также работающий
-на частоте процессора. Когда следующая планируемая задача более, чем в
-`1 << 24` тактов в будущем, прерывание устанавливается на время в пределах
-`1 << 24` тактов. Этот процесс может происходить несколько раз, пока
-следующая запланированная задача не будет в диапазоне счетчика `SysTick`.
-
-Подведем итог, оба `Instant` и `Duration` имеют разрешение 1 такт ядра, и `Duration` эффективно имеет (полуоткрытый) диапазон `0..(1 << 31)` (не включая максимум) тактов ядра.
-
-## Вместительность очереди
-
-Вместительность очереди таймера рассчитывается как сумма вместительностей
-всех планируемых (`schedule`) задач. Как и в случае очередей готовности,
-это значит, что как только мы затребовали пустую ячейку в буфере `INPUTS`,
-мы гарантируем, что способны передать задачу в очередь таймера;
-это позволяет нам опустить проверки времени выполнения.
-
-## Приоритет системного таймера
-
-Приориет системного таймера не может быть установлен пользователем;
-он выбирается фреймворком.
-Чтобы убедиться, что низкоприоритетные задачи не препятствуют
-запуску высокоприоритетных, мы выбираем приоритет системного таймера
-максимальным из всех планируемых задач.
-
-Чтобы понять, почему это нужно, рассмотрим вариант, когда две ранее
-запланированные задачи с приоритетами `2` и `3` становятся готовыми в
-примерно одинаковое время, но низкоприоритетная задача перемещается
-в очередь готовности первой.
-Если бы приоритет системного таймера был, например, равен `1`,
-тогда после перемещения низкоприоритетной (`2`) задачи, это бы привело
-к завершению (из-за того, что приоритет выше приоритета системного таймера)
-ожидания выполнения высокоприоритетной задачи (`3`).
-Чтобы избежать такого сценария, системный таймер должен работать на
-приоритете, равном наивысшему из приоритетов планируемых задач;
-в этом примере это `3`.
-
-## Анализ приоритетов
-
-Очередь таймера - это ресурс, разделяемый всеми задачами, которые могут
-планировать (`schedule`) задачи и обработчиком `SysTick`.
-Также интерфейс `schedule` соперничает с интерфейсом `spawn`
-за списки свободной памяти. Все это должно уситываться в анализе приоритетов.
-
-Чтобы проиллюстрировать, рассмотрим следующий пример:
-
-``` rust
-#[rtic::app(device = ..)]
-mod app {
- #[task(priority = 3, spawn = [baz])]
- fn foo(c: foo::Context) {
- // ..
- }
-
- #[task(priority = 2, schedule = [foo, baz])]
- fn bar(c: bar::Context) {
- // ..
- }
-
- #[task(priority = 1)]
- fn baz(c: baz::Context) {
- // ..
- }
-}
-```
-
-Анализ приоритетов происходил бы вот так:
-
-- `foo` (prio = 3) и `baz` (prio = 1) планируемые задачи, поэтому
- `SysTick` должен работать на максимальном из этих двух приоритетов, т.е. `3`.
-
-- `foo::Spawn` (prio = 3) и `bar::Schedule` (prio = 2) соперничают за
- конечный потребитель `baz_FQ`; это приводит к максимальному приоритету `3`.
-
-- `bar::Schedule` (prio = 2) имеет экслюзивный доступ к
- конечному потребителю `foo_FQ`; поэтому максимальный приоритет `foo_FQ` фактически `2`.
-
-- `SysTick` (prio = 3) и `bar::Schedule` (prio = 2) соперничают за
- очередь таймера `TQ`; это приводит к максимальному приоритету `3`.
-
-- `SysTick` (prio = 3) и `foo::Spawn` (prio = 3) оба имеют неблокируемый
- доступ к очереди готовности `RQ3`, что хранит записи `foo`;
- поэтому максимальный приоритет `RQ3` фактически `3`.
-
-- `SysTick` имеет эксклюзивный доступ к очереди готовности `RQ1`,
- которая хранит записи `baz`; поэтому максимальный приоритет `RQ1` фактически `3`.
-
-## Изменения в реализации `spawn`
-
-Когда интерфейс `schedule` используется, реализация `spawn` немного
-изменяется, чтобы отслеживать baseline задач. Как можете видеть в
-реализации `schedule` есть буферы `INSTANTS`, используемые, чтобы
-хранить время, в которое задача была запланирована навыполнение;
-этот `Instant` читается диспетчером задач и передается в пользовательский
-код, как часть контекста задачи.
-
-``` rust
-mod app {
- // ..
-
- #[no_mangle]
- unsafe UART1() {
- const PRIORITY: u8 = 1;
-
- let snapshot = basepri::read();
-
- while let Some(ready) = RQ1.split().1.dequeue() {
- match ready.task {
- Task::baz => {
- let input = baz_INPUTS[ready.index as usize].read();
- // ADDED
- let instant = baz_INSTANTS[ready.index as usize].read();
-
- baz_FQ.split().0.enqueue_unchecked(ready.index);
-
- let priority = Cell::new(PRIORITY);
- // ИЗМЕНЕНО instant передан как часть контекста задачи
- baz(baz::Context::new(&priority, instant), input)
- }
-
- Task::bar => {
- // выглядит также как ветка для `baz`
- }
-
- }
- }
-
- // инвариант BASEPRI
- basepri::write(snapshot);
- }
-}
-```
-
-И наоборот, реализации `spawn` нужно писать значение в буфер `INSTANTS`.
-Записанное значение располагается в структуре `Spawn` и это либо
-время `start` аппаратной задачи, либо время `scheduled` программной задачи.
-
-``` rust
-mod foo {
- // ..
-
- pub struct Spawn<'a> {
- priority: &'a Cell<u8>,
- // ADDED
- instant: Instant,
- }
-
- impl<'a> Spawn<'a> {
- pub unsafe fn priority(&self) -> &Cell<u8> {
- &self.priority
- }
-
- // ADDED
- pub unsafe fn instant(&self) -> Instant {
- self.instant
- }
- }
-}
-
-mod app {
- impl<'a> foo::Spawn<'a> {
- /// Spawns the `baz` task
- pub fn baz(&self, message: u64) -> Result<(), u64> {
- unsafe {
- match lock(self.priority(), baz_FQ_CEILING, || {
- baz_FQ.split().1.dequeue()
- }) {
- Some(index) => {
- baz_INPUTS[index as usize].write(message);
- // ADDED
- baz_INSTANTS[index as usize].write(self.instant());
-
- lock(self.priority(), RQ1_CEILING, || {
- RQ1.split().1.enqueue_unchecked(Ready {
- task: Task::foo,
- index,
- });
- });
-
- rtic::pend(Interrupt::UART0);
- }
-
- None => {
- // достигнута максимальная вместительность; неудачный вызов
- Err(message)
- }
- }
- }
- }
- }
-}
-```
diff --git a/book/ru/src/migration.md b/book/ru/src/migration.md
deleted file mode 100644
index b7f2fa1..0000000
--- a/book/ru/src/migration.md
+++ /dev/null
@@ -1,4 +0,0 @@
-# Инструкции по миграции
-
-В этом разделе описывается как мигрировать между различными версиями RTIC.
-Можно также использовать для сравнения версий.
diff --git a/book/ru/src/migration/migration_rtic.md b/book/ru/src/migration/migration_rtic.md
deleted file mode 100644
index 28813fe..0000000
--- a/book/ru/src/migration/migration_rtic.md
+++ /dev/null
@@ -1,48 +0,0 @@
-# Миграция с RTFM на RTIC
-
-В этом разделе описано, как обновить приложение, написанное на RTFM v0.5.x на RTIC той же версии.
-Это необходимо из-за переименования фреймворка в соответствии с [RFC #33].
-
-**Примечание:** Между RTFM v0.5.3 и RTIC v0.5.3 нет разниц в коде, это исключительно изменение имен.
-
-[RFC #33]: https://github.com/rtic-rs/rfcs/pull/33
-
-## `Cargo.toml`
-
-Во-первых, зависимость `cortex-m-rtfm` должна быть изменена на `cortex-m-rtic`.
-
-``` toml
-[dependencies]
-# измените это
-cortex-m-rtfm = "0.5.3"
-
-# на это
-cortex-m-rtic = "0.5.3"
-```
-
-## Изменения в коде
-
-Единственное изменение в коде, которое нужно сделать - поменять все ссылки на `rtfm`,
-чтобы они указывали на `rtic`:
-
-``` rust
-//
-// Измените это
-//
-
-#[rtfm::app(/* .. */, monotonic = rtfm::cyccnt::CYCCNT)]
-const APP: () = {
- // ...
-
-};
-
-//
-// На это
-//
-
-#[rtic::app(/* .. */, monotonic = rtic::cyccnt::CYCCNT)]
-const APP: () = {
- // ...
-
-};
-```
diff --git a/book/ru/src/migration/migration_v4.md b/book/ru/src/migration/migration_v4.md
deleted file mode 100644
index 0ff8039..0000000
--- a/book/ru/src/migration/migration_v4.md
+++ /dev/null
@@ -1,230 +0,0 @@
-# Миграция с v0.4.x на v0.5.0
-
-Этот раздел описывает как обновить программы, написанные на RTIC v0.4.x
-на версию v0.5.0 фреймворка.
-
-## `Cargo.toml`
-
-Во-первых, нужно обновить версию зависимости `cortex-m-rtic` до
-`"0.5.0"`. Опцию `timer-queue` нужно удалить.
-
-``` toml
-[dependencies.cortex-m-rtic]
-# изменить это
-version = "0.4.3"
-
-# на это
-version = "0.5.0"
-
-# и удалить Cargo feature
-features = ["timer-queue"]
-# ^^^^^^^^^^^^^
-```
-
-## Аргумент `Context`
-
-Все функции внутри элемента `#[rtic::app]` должны принимать первым аргументом
-структуру `Context`. Этот тип `Context` будет содержать переменные, которые были магически
-инъецированы в область видимости функции версией v0.4.x фреймворка:
-`resources`, `spawn`, `schedule` -- эти переменные станут полями структуры `Context`.
-Каждая функция элемента `#[rtic::app]` получит отдельный тип `Context`.
-
-``` rust
-#[rtic::app(/* .. */)]
-const APP: () = {
- // change this
- #[task(resources = [x], spawn = [a], schedule = [b])]
- fn foo() {
- resources.x.lock(|x| /* .. */);
- spawn.a(message);
- schedule.b(baseline);
- }
-
- // into this
- #[task(resources = [x], spawn = [a], schedule = [b])]
- fn foo(mut cx: foo::Context) {
- // ^^^^^^^^^^^^^^^^^^^^
-
- cx.resources.x.lock(|x| /* .. */);
- // ^^^
-
- cx.spawn.a(message);
- // ^^^
-
- cx.schedule.b(message, baseline);
- // ^^^
- }
-
- // change this
- #[init]
- fn init() {
- // ..
- }
-
- // into this
- #[init]
- fn init(cx: init::Context) {
- // ^^^^^^^^^^^^^^^^^
- // ..
- }
-
- // ..
-};
-```
-
-## Ресурсы
-
-Синтаксис, используемый, для определения ресурсов был изменен с переменных `static mut`
-на структуру `Resources`.
-
-``` rust
-#[rtic::app(/* .. */)]
-const APP: () = {
- // измените это
- static mut X: u32 = 0;
- static mut Y: u32 = (); // поздний ресурс
-
- // на это
- struct Resources {
- #[init(0)] // <- начальное значение
- X: u32, // ПРИМЕЧАНИЕ: мы предлагаем изменить стиль именования на `snake_case`
-
- Y: u32, // поздний ресурс
- }
-
- // ..
-};
-```
-
-## Периферия устройства
-
-Если ваша программа получала доступ к периферии в `#[init]` через
-переменну `device`, вам нужно будет добавить `peripherals = true` в атрибут
-`#[rtic::app]`, чтобы и дальше получать доступ к периферии через поле `device` структуры `init::Context`.
-
-Измените это:
-
-``` rust
-#[rtic::app(/* .. */)]
-const APP: () = {
- #[init]
- fn init() {
- device.SOME_PERIPHERAL.write(something);
- }
-
- // ..
-};
-```
-
-На это:
-
-``` rust
-#[rtic::app(/* .. */, peripherals = true)]
-// ^^^^^^^^^^^^^^^^^^
-const APP: () = {
- #[init]
- fn init(cx: init::Context) {
- // ^^^^^^^^^^^^^^^^^
- cx.device.SOME_PERIPHERAL.write(something);
- // ^^^
- }
-
- // ..
-};
-```
-
-## `#[interrupt]` и `#[exception]`
-
-Атрибуты `#[interrupt]` и `#[exception]` были удалены. Чтобы определять аппаратные задачи в v0.5.x
-используте атрибут `#[task]` с аргументом `binds`.
-
-Измените это:
-
-``` rust
-#[rtic::app(/* .. */)]
-const APP: () = {
- // аппаратные задачи
- #[exception]
- fn SVCall() { /* .. */ }
-
- #[interrupt]
- fn UART0() { /* .. */ }
-
- // программные задачи
- #[task]
- fn foo() { /* .. */ }
-
- // ..
-};
-```
-
-На это:
-
-``` rust
-#[rtic::app(/* .. */)]
-const APP: () = {
- #[task(binds = SVCall)]
- // ^^^^^^^^^^^^^^
- fn svcall(cx: svcall::Context) { /* .. */ }
- // ^^^^^^ мы предлагаем использовать `snake_case` имя здесь
-
- #[task(binds = UART0)]
- // ^^^^^^^^^^^^^
- fn uart0(cx: uart0::Context) { /* .. */ }
-
- #[task]
- fn foo(cx: foo::Context) { /* .. */ }
-
- // ..
-};
-```
-
-## `schedule`
-
-Интерфейс `schedule` больше не требует cargo опции `timer-queue`, которая была удалена.
-Чтобы использовать интерфес `schedule`, нужно сначала определить
-монотонный тамер, который будет использоваьт среды выполнения, с помощью аргумента `monotonic`
-атрибута `#[rtic::app]`. Чтобы продолжить использовать счетчик циклов
-(CYCCNT) в качестве монотонного таймера, как было в версии v0.4.x, добавьте
-аргумент `monotonic = rtic::cyccnt::CYCCNT` в атрибут `#[rtic::app]`.
-
-Также были добавлены типы `Duration` и `Instant`, а трейт `U32Ext` был перемещен в модуль `rtic::cyccnt`.
-Этот модуль доступен только на устройствах ARMv7-M+.
-Удаление `timer-queue` также возвращает периферию `DWT` в структуру периферии ядра,
-включить ее в работу можно внутри `init`.
-
-Измените это:
-
-``` rust
-use rtic::{Duration, Instant, U32Ext};
-
-#[rtic::app(/* .. */)]
-const APP: () = {
- #[task(schedule = [b])]
- fn a() {
- // ..
- }
-};
-```
-
-На это:
-
-``` rust
-use rtic::cyccnt::{Duration, Instant, U32Ext};
-// ^^^^^^^^
-
-#[rtic::app(/* .. */, monotonic = rtic::cyccnt::CYCCNT)]
-// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-const APP: () = {
- #[init]
- fn init(cx: init::Context) {
- cx.core.DWT.enable_cycle_counter();
- // опционально, настройка запуска DWT без подключенного отладчика
- cx.core.DCB.enable_trace();
- }
- #[task(schedule = [b])]
- fn a(cx: a::Context) {
- // ..
- }
-};
-```
diff --git a/book/ru/src/migration/migration_v5.md b/book/ru/src/migration/migration_v5.md
deleted file mode 100644
index 84bd9fb..0000000
--- a/book/ru/src/migration/migration_v5.md
+++ /dev/null
@@ -1,365 +0,0 @@
-# Миграция с v0.5.x на v1.0.0
-
-Этот раздел описывает как обновиться с версии v0.5.x на v1.0.0 фреймворка RTIC.
-
-## `Cargo.toml` - увеличьте версию
-
-Измените версию `cortex-m-rtic` на `"0.6.0"`.
-
-## `mod` вместо `const`
-
-С поддержкой атрибутов над модулями трюк с `const APP` теперь не нужен.
-
-Измените
-
-``` rust
-#[rtic::app(/* .. */)]
-const APP: () = {
- [код здесь]
-};
-```
-
-на
-
-``` rust
-#[rtic::app(/* .. */)]
-mod app {
- [код здесь]
-}
-```
-
-Так как теперь используется обычный модуль Rust, это значит, что можно использовать
-обычный пользовательский код в этом модуле.
-Также это значит, что `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.
-
-Измените
-
-``` rust
-#[rtic::app(/* .. */)]
-const APP: () = {
- [код здесь]
-
- // RTIC требует, чтобы неиспользуемые прерывания были задекларированы в блоке extern, когда
- // используются программные задачи; эти свободные прерывания будут использованы для управления
- // программными задачами.
- extern "C" {
- fn SSI0();
- fn QEI0();
- }
-};
-```
-
-на
-
-``` rust
-#[rtic::app(/* .. */, dispatchers = [SSI0, QEI0])]
-mod app {
- [код здесь]
-}
-```
-
-Это работает и для ОЗУ-функций, см. examples/ramfunc.rs
-
-
-## Структуры ресурсов - `#[shared]`, `#[local]`
-
-Ранее ресурсы RTIC должны были размещаться в структуре с именем "Resources":
-
-``` rust
-struct Resources {
- // Ресурсы определяются здесь
-}
-```
-
-Начиная с RTIC v1.0.0 структуры ресурсов аннотируются подобно
-`#[task]`, `#[init]`, `#[idle]`: аттрибутами `#[shared]` и `#[local]`
-
-``` rust
-#[shared]
-struct MySharedResources {
- // Разделяемые задачами ресурсы определены здесь
-}
-
-#[local]
-struct MyLocalResources {
- // Ресурсы, определенные здесь нельзя передавать между задачами; каждый из них локальный для единственной задачи
-}
-```
-
-Эти структуры разработчик может называть по своему желанию.
-
-## `shared` и `local` аргументы в `#[task]`'ах
-
-В v1.0.0 ресурсы разделены на `shared` ресурсы и `local` ресурсы.
-`#[task]`, `#[init]` и `#[idle]` больше не имеют аргумента `resources`;
-они должны использовать аргументы `shared` и `local`.
-
-В v0.5.x:
-
-``` rust
-struct Resources {
- local_to_b: i64,
- shared_by_a_and_b: i64,
-}
-
-#[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) {}
-```
-
-В v1.0.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) {}
-```
-
-## Симметричные блокировки
-
-Теперь RTIC использует симметричные блокировки, это значит, что метод `lock` нужно использовать для
-всех доступов к `shared` ресурсам. Поскольку высокоприоритетные задачи имеют эксклюзивный доступ к ресурсу,
-в старом коде можно было следующее:
-
-``` rust
-#[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 = /* ... */);
-}
-```
-
-С симметричными блокировками нужно вызывать `lock` для обоих задач:
-
-``` rust
-#[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
-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;
-}
-```
-
-v1.0 код:
-
-``` 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
-#[init]
-fn init(_: init::Context) {
- static mut BUFFER: [u8; 1024] = [0; 1024];
- let buffer: &'static mut [u8; 1024] = BUFFER;
-}
-```
-
-v1.0.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
-#[rtic::app(device = lm3s6965)]
-mod app {
- #[init]
- fn init(_: init::Context) {
- rtic::pend(Interrupt::UART0);
- }
-
- // [еще код]
-}
-```
-
-на это:
-
-
-``` 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]
-}
-```
-
-## Вызов/планирование откуда угодно
-
-С этой новой возвожностью, старый код, такой как:
-
-
-``` rust
-#[task(spawn = [bar])]
-fn foo(cx: foo::Context) {
- cx.spawn.bar().unwrap();
-}
-
-#[task(schedule = [bar])]
-fn bar(cx: bar::Context) {
- cx.schedule.foo(/* ... */).unwrap();
-}
-```
-
-Теперь будет выглядеть так:
-
-``` rust
-#[task]
-fn foo(_c: foo::Context) {
- bar::spawn().unwrap();
-}
-
-#[task]
-fn bar(_c: bar::Context) {
- foo::schedule(/* ... */).unwrap();
-}
-```
-
-Заметьте, что атрибуты `spawn` и `schedule` больше не нужны.
-
----
-
-## Дополнительно
-
-### Внешние задачи
-
-Как программные, так и аппаратные задачи теперь можно определять вне модуля `mod app`.
-Ранее это было возможно только путем реализации обертки, вызывающей реализацию задачи.
-
-Смотреть примеры `examples/extern_binds.rs` и `examples/extern_spawn.rs`.
-
diff --git a/book/ru/src/preface.md b/book/ru/src/preface.md
deleted file mode 100644
index 894b6b4..0000000
--- a/book/ru/src/preface.md
+++ /dev/null
@@ -1,26 +0,0 @@
-<div align="center"><img width="300" height="300" src="RTIC.svg"></div>
-<div style="font-size: 6em; font-weight: bolder;" align="center">RTIC</div>
-
-<h1 align="center">Real-Time Interrupt-driven Concurrency</h1>
-
-<p align="center">Конкурентный фреймворк для создания систем реального времени</p>
-
-# Введение
-
-Эта книга содержит документацию пользовательского уровня о фреймворке Real-Time Interrupt-driven Concurrency
-(RTIC). Справочник по API можно найти [здесь](../../api/).
-
-Также известен как Real-Time For the Masses.
-
-<!--Оригинал данного руководства на [английском].-->
-
-<!--[английском]: ../en/index.html-->
-
-Это документация по RTIC версии v1.0.x; за документацией по другим версиям:
-
-* v0.5.x [сюда](/0.5).
-* v0.4.x [сюда](/0.4).
-
-{{#include ../../../README_ru.md:7:45}}
-
-{{#include ../../../README_ru.md:51:}}