russian translation

This commit is contained in:
Andrey Zgarbul 2019-02-08 23:18:51 +03:00
parent 45659fdbbc
commit 5ef1f2088a
17 changed files with 753 additions and 2 deletions

104
ru/src/README_RU.md Normal file
View file

@ -0,0 +1,104 @@
# Real Time For the Masses
Конкурентный фреймворк для создания систем реального времени.
**ВАЖНО** Эта библиотека в настоящее время в состоянии пре-релиза (бета).
Мы зарезервировали право делать ломающие синтакс изменения или патчить дыры
в безопасности памяти до релиза v0.4.0, который запланирован на 2018-12-07.
Когда выйдет v0.4.0, *все пре-релизы будут убраны*. Если при запуске Вы
получите сообщение о панике или бесполезное сообщение об ошибке
(вводящее в заблуждение), или что-то будет работать не так, как Вы ожидаете,
пожалуйста, сообщите о [проблеме]!
[проблеме]: https://github.com/japaric/cortex-m-rtfm/issues
## Возможности
- **Задачи** - единица конкуренции [^1]. Задачи могут *запускаться по событию*
(в ответ на асинхронный стимул) или вызываться программно по желанию.
- **Передача сообщений** между задачами. А именно, сообщения можно передавать
программным задачам в момент вызова.
- **Очередь таймера** [^2]. Программные задачи можно планировать на запуск в
определенный момент в будущем. Это свойство можно использовать, чтобы
реализовывать периодические задачи.
- Поддержка приоритетов задач, и таким образом, **вытесняющей многозадачности**.
- **Эффективное, свободное от гонок данных разделение памяти** через хорошо
разграниченные критические секции на *основе приоритетов* [^1].
- **Выполнение без взаимной блокировки задач**, гарантированное на этапе
компиляции. Это более сильная гарантия, чем предоставляемая
[стандартной абстракцией `Mutex`][std-mutex].
[std-mutex]: https://doc.rust-lang.org/std/sync/struct.Mutex.html
- **Минимальные затраты на диспетчеризацию**. Диспетчер задач имеет
минимальный след; основная часть работы по диспетчеризации делается аппаратно.
- **Высокоэффективное использование памяти**: Все задачи используют общий стек
вызовов и нет сильной зависимости от динамического распределителя памяти.
- **Все устройства Cortex-M полностью поддерживаются**.
- Эта модель задач поддается известному анализу методом WCET (наихудшего
времени исполнения) и техникам анализа диспетчеризации. (Хотя мы еще не
разработали для дружественных инструментов для этого).
## Требования
- Rust 1.31.0+
- Программы нужно писать используя 2018 edition.
## [User documentation](https://japaric.github.io/cortex-m-rtfm/book)
## [API reference](https://japaric.github.io/cortex-m-rtfm/api/rtfm/index.html)
## Благодарности
Эта библиотека основана на [языке RTFM][rtfm-lang], созданном Embedded
Systems group в [Техническом Университете Luleå][ltu], под рук.
[Prof. Per Lindgren][per].
[rtfm-lang]: http://www.rtfm-lang.org/
[ltu]: https://www.ltu.se/?l=en
[per]: https://www.ltu.se/staff/p/pln-1.11258?l=en
## Ссылки
[^1]: Eriksson, J., Häggström, F., Aittamaa, S., Kruglyak, A., & Lindgren, P.
(2013, June). Real-time for the masses, step 1: Programming API and static
priority SRP kernel primitives. In Industrial Embedded Systems (SIES), 2013
8th IEEE International Symposium on (pp. 110-113). IEEE.
[^2]: Lindgren, P., Fresk, E., Lindner, M., Lindner, A., Pereira, D., & Pinho,
L. M. (2016). Abstract timers and their implementation onto the arm cortex-m
family of mcus. ACM SIGBED Review, 13(1), 48-53.
## Лицензия
Все исходные тексты (включая примеры кода) лицензированы либо под:
- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) или
[https://www.apache.org/licenses/LICENSE-2.0][L1])
- MIT license ([LICENSE-MIT](LICENSE-MIT) or
[https://opensource.org/licenses/MIT][L2])
[L1]: https://www.apache.org/licenses/LICENSE-2.0
[L2]: https://opensource.org/licenses/MIT
на Ваше усмотрение.
Текст книги лицензирован по условиям лицензий
Creative Commons CC-BY-SA v4.0 ([LICENSE-CC-BY-SA](LICENSE-CC-BY-SA) или
[https://creativecommons.org/licenses/by-sa/4.0/legalcode][L3]).
[L3]: https://creativecommons.org/licenses/by-sa/4.0/legalcode
### Contribution
Если вы явно не заявляете иначе, любой взнос, преднамеренно представленный
для включения в эту работу, как определено в лицензии Apache-2.0, лицензируется, как указано выше, без каких-либо дополнительных условий.

View file

@ -1,3 +1,16 @@
# Summary # Summary
- [Chapter 1](./chapter_1.md) [Введение](./preface.md)
- [RTFM в примерах](./by-example.md)
- [Атрибут `app](./by-example/app.md)
- [Ресурсы](./by-example/resources.md)
- [Задачи](./by-example/tasks.md)
- [Очередь таймера](./by-example/timer-queue.md)
- [Одиночки](./by-example/singletons.md)
- [Типы, Send и Sync](./by-example/types-send-sync.md)
- [Создание нового проекта](./by-example/new.md)
- [Советы и хитрости](./by-example/tips.md)
- [Под капотом](./internals.md)
- [Ceiling analysis](./internals/ceilings.md)
- [Диспетчер задач](./internals/tasks.md)
- [Очередь таймера](./internals/timer-queue.md)

16
ru/src/by-example.md Normal file
View file

@ -0,0 +1,16 @@
# RTFM в примерах
Эта часть книги представляет фреймворк Real Time For the Masses (RTFM)
новым пользователям через примеры с растущей сложностью.
Все примеры в этой книге можно найти в [репозитории] проекта на GitHub,
и большинство примеров можно запустить на эмуляторе QEMU, поэтому никакого
специальног оборудования не требуется to follow along.
[репозитории]: https://github.com/japaric/cortex-m-rtfm
Чтобы запустить примеры на Вашем ноутбуке / PC, Вам нужна программа
`qemu-system-arm`. Посмотрите [the embedded Rust book] на предмет инструкций
как настроить окружение для разработки встраиваемых устройств, в том числе QEMU.
[the embedded Rust book]: https://rust-embedded.github.io/book/intro/install.html

101
ru/src/by-example/app.md Normal file
View file

@ -0,0 +1,101 @@
# The `app` attribute
Это наименьшая возможная программа на RTFM:
``` rust
{{#include ../../../examples/smallest.rs}}
```
Все программы на RTFM используют атрибут [`app`] (`#[app(..)]`). Этот атрибут
нужно применять к `const`-элементам, содержащим элементы. Атрибут `app` имеет
обязательный аргумент `device`, в качестве значения которому передается *путь*.
Этот путь должен указывать на библиотеку *устройства*, сгенерированную с помощью
[`svd2rust`] **v0.14.x**. Атрибут `app` развернется в удобную точку входа,
поэтому нет необходимости использовать атрибут [`cortex_m_rt::entry`].
[`app`]: ../../api/cortex_m_rtfm_macros/attr.app.html
[`svd2rust`]: https://crates.io/crates/svd2rust
[`cortex_m_rt::entry`]: ../../api/cortex_m_rt_macros/attr.entry.html
> **ОТСТУПЛЕНИЕ**: Некоторые из вас удивятся, почему мы используем ключевое слово `const` как
> модуль, а не правильное `mod`. Причина в том, что использование атрибутов на
> модулях требует feature gate, который требует ночную сборку. Чтобы заставить
> RTFM работать на стабильной сборке, мы используем вместо него слово `const`.
> Когда большая часть макросов 1.2 стабилизируются, мы прейдем от `const` к `mod` и в конце концов в атрибуту уровне приложения (`#![app]`).
## `init`
Внутри псевдо-модуля атрибут `app` ожидает найти функцию инициализации, обозначенную
атрибутом `init`. Эта функция должна иметь сигнатуру `[unsafe] fn()`.
Эта функция инициализации будет первой частью запускаемого приложения.
Функция `init` запустится *с отключенными прерываниями* и будет иметь эксклюзивный
доступ к периферии Cortex-M и специфичной для устройства периферии через переменные
`core` and `device`, которые внедряются в область видимости `init` атрибутом `app`.
Не вся периферия Cortex-M доступна в `core`, потому что рантайм RTFM принимает владение
частью из неё -- более подробно см. структуру [`rtfm::Peripherals`].
Переменные `static mut`, определённые в начале `init` будут преобразованы
в ссылки `&'static mut` с безопасным доступом.
[`rtfm::Peripherals`]: ../../api/rtfm/struct.Peripherals.html
Пример ниже показывает типы переменных `core` и `device` и
демонстрирует безопасный доступ к переменной `static mut`.
``` rust
{{#include ../../../examples/init.rs}}
```
Запуск примера напечатает `init` в консоли и завершит процесс QEMU.
``` console
$ cargo run --example init
{{#include ../../../ci/expected/init.run}}```
## `idle`
Функция, помеченная атрибутом `idle` может присутствовать в псевдо-модуле
опционально. Эта функция используется как специальная *задача ожидания* и должна иметь
сигнатуру `[unsafe] fn() - > !`.
Когда она присутствует, рантайм запустит задачу `idle` после `init`. В отличие от
`init`, `idle` запустится *с включенными прерываниями* и не может завершиться,
поэтому будет работать бесконечно.
Когда функция `idle` определена, рантайм устанавливает бит [SLEEPONEXIT], после чего
отправляет микроконтроллер в состояние сна после выполнения `init`.
[SLEEPONEXIT]: https://developer.arm.com/products/architecture/cpu-architecture/m-profile/docs/100737/0100/power-management/sleep-mode/sleep-on-exit-bit
Как и в `init`, переменные `static mut`будут преобразованы в ссылки `&'static mut`
с безопасным доступом.
В примере ниже показан запуск `idle` после `init`.
``` rust
{{#include ../../../examples/idle.rs}}
```
``` console
$ cargo run --example idle
{{#include ../../../ci/expected/idle.run}}```
## `interrupt` / `exception`
Как Вы бы сделали с помощью библиотеки `cortex-m-rt`, Вы можете использовать атрибуты
`interrupt` и `exception` внутри псевдо-модуля `app`, чтобы определить обработчики
прерываний и исключений. В RTFM, мы называем обработчики прерываний и исключений
*аппаратными* задачами.
``` rust
{{#include ../../../examples/interrupt.rs}}
```
``` console
$ cargo run --example interrupt
{{#include ../../../ci/expected/interrupt.run}}```
До сих пор программы RTFM, которые мы видели не отличались от программ, которые
можно написать, используя только библиотеку `cortex-m-rt`. В следующем разделе
мы начнем знакомиться с функционалом, присущим только RTFM.

67
ru/src/by-example/new.md Normal file
View file

@ -0,0 +1,67 @@
# Создание нового проекта
Теперь, когда Вы изучили основные возможности фреймворка RTFM, Вы можете
попробовать его использовать на Вашем оборудовании следуя этим инструкциям.
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. Добавьте крейт устройства, сгенерированный с помощью [`svd2rust`] **v0.14.x**,
или библиотеку отладочной платы, у которой в зависимостях одно из устройств.
Убедитесь, что опция `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-rtfm` как зависимость, и если необходимо,
включите опцию `timer-queue`.
``` console
$ cargo add cortex-m-rtfm --allow-prerelease --upgrade=none
```
4. Напишите программу RTFM.
Здесь я буду использовать пример `init` из библиотеки `cortex-m-rtfm`.
``` console
$ curl \
-L https://github.com/japaric/cortex-m-rtfm/raw/v0.4.0-beta.1/examples/init.rs \
> src/main.rs
```
Этот пример зависит от библиотеки `panic-semihosting`:
``` console
$ cargo add panic-semihosting
```
5. Соберите его, загрузите в микроконтроллер и запустите.
``` console
$ # ПРИМЕЧАНИЕ: Я раскомментировал опцию `runner` в `.cargo/config`
$ cargo run
{{#include ../../../ci/expected/init.run}}```

View file

@ -0,0 +1,122 @@
## Ресурсы
Одно из ограничений атрибутов, предоставляемых библиотекой `cortex-m-rt` является
то, что совместное использование данных (или периферии) между прерываниями,
или прерыванием и функцией `init`, требуют `cortex_m::interrupt::Mutex`, который
*всегда* требует отключения *всех* прерываний для доступа к данным. Отключение всех
прерываний не всегда необходимо для безопасности памяти, но компилятор не имеет
достаточно информации, чтобы оптимизировать доступ к разделяемым данным.
Атрибут `app` имеет полную картину приложения, поэтому может оптимизировать доступ к
`static`-переменным. В RTFM мы обращаемся к `static`-переменным, объявленным внутри
псевдо-модуля `app` как к *ресурсам*. Чтобы получить доступ к ресурсу, контекст
(`init`, `idle`, `interrupt` или `exception`) должен сначала определить
аргумент `resources` в соответствующем атрибуте.
В примере ниже два обработчика прерываний имеют доступ к одному и тому же ресурсу.
Никакого `Mutex` в этом случае не требуется, потому что оба обработчика запускаются
с обним приоритетом и никакого вытеснения быть не может.
К ресурсу `SHARED` можно получить доступ только из этих двух прерываний.
``` rust
{{#include ../../../examples/resource.rs}}
```
``` console
$ cargo run --example resource
{{#include ../../../ci/expected/resource.run}}
```
## Приоритеты
Приоритет каждого прерывания можно определить в атрибутах `interrupt` и `exception`.
Невозможно установить приоритет любым другим способом, потому что рантайм
забирает владение прерыванием `NVIC`; также невозможно изменить приоритет
обработчика / задачи в рантайме. Благодаря этому ограничению у фреймворка
есть знание о *статических* приоритетах всех обработчиков прерываний и исключений.
Прерывания и исключения могут иметь приоритеты в интервале `1..=(1 << NVIC_PRIO_BITS)`,
где `NVIC_PRIO_BITS` - константа, определённая в библиотеке `device`.
Задача `idle` имеет приоритет `0`, наименьший.
Ресурсы, совместно используемые обработчиками, работающими на разных приоритетах,
требуют критических секций для безопасности памяти. Фреймворк проверяет, что
критические секции используются, но *только где необходимы*: например,
критические секции не нужны для обработчика с наивысшим приоритетом, имеющим
доступ к ресурсу.
API критической секции, предоставляемое фреймворком RTFM (см. [`Mutex`]),
основано на динамических приоритетах вместо отключения прерываний. Из этого следует,
что критические секции не будут допускать *запуск некоторых* обработчиков,
включая все соперничающие за ресурс, но будут позволять запуск обработчиков с
большим приоритетом не соперничащих за ресурс.
[`Mutex`]: ../../api/rtfm/trait.Mutex.html
В примере ниже у нас есть 3 обработчика прерываний с приоритетами от одного
до трех. Два обработчика с низким приоритетом соперничают за ресурс `SHARED`.
Обработчик с низшим приоритетом должен заблокировать ([`lock`]) ресурс
`SHARED`, чтобы получить доступ к его данным, в то время как обработчик со
средним приоритетом может напрямую получать доступ к его данным. Обработчик
с наивысшим приоритетом может свободно вытеснять критическую секцию,
созданную обработчиком с низшим приоритетом.
[`lock`]: ../../api/rtfm/trait.Mutex.html#method.lock
``` rust
{{#include ../../../examples/lock.rs}}
```
``` console
$ cargo run --example lock
{{#include ../../../ci/expected/lock.run}}```
## Поздние ресурсы
В отличие от обычных `static`-переменных, к которым должно быть присвоено
начальное значение, ресурсы можно инициализировать в рантайме.
Мы называем ресурсы, инициализируемые в рантайме *поздними*. Поздние ресурсы
полезны для *переноса* (как при передаче владения) периферии из `init` в
обработчики прерываний и исключений.
Поздние ресурсы определяются как обычные ресурсы, но им присваивается начальное
значение `()` (the unit value). Поздние ресурсы необходимо инициализировать в конце
функции `init` используя обычное присвоение (например `FOO = 1`).
В примере ниже использованы поздние ресурсы, чтобы установить неблокированный,
односторонний канал между обработчиком прерывания `UART0` и функцией `idle`.
Очередь типа один производитель-один потребитель [`Queue`] использована как канал.
Очередь разделена на элементы потребителя и поизводителя в `init` и каждый элемент
расположен в отдельном ресурсе; `UART0` владеет ресурсом произодителя, а `idle`
владеет ресурсом потребителя.
[`Queue`]: ../../api/heapless/spsc/struct.Queue.html
``` rust
{{#include ../../../examples/late.rs}}
```
``` console
$ cargo run --example late
{{#include ../../../ci/expected/late.run}}```
## `static`-ресурсы
Переменные типа `static` также можно использовать в качестве ресурсов. Задачи
могут получать только (разделяемые) `&` ссылки на ресурсы, но блокировки не
нужны для доступа к данным. Вы можете думать о `static`-ресурсах как о простых
`static`-переменных, которые можно инициализировать в рантайме и иметь лучшие
правила видимости: Вы можете контролировать, какие задачи получают доступ к
переменной, чтобы переменная не была видна всем фунциям в область видимости,
где она была объявлена.
В примере ниже ключ загружен (или создан) в рантайме, а затем использован в двух
задачах, запущенных на разных приоритетах.
``` rust
{{#include ../../../examples/static.rs}}
```
``` console
$ cargo run --example static
{{#include ../../../ci/expected/static.run}}```

View file

@ -0,0 +1,26 @@
# Одиночки
Атрибут `app` знает о библиотеке [`owned-singleton`] и её атрибуте [`Singleton`].
Когда этот атрибут применяется к одному из ресурсов, рантайм производит для Вас
`unsafe` инициализацию одиночки, проверяя, что только один экземпляр одиночки
когда-либо создан.
[`owned-singleton`]: ../../api/owned_singleton/index.html
[`Singleton`]: ../../api/owned_singleton_macros/attr.Singleton.html
Заметьте, что когда Вы используете атрибут `Singleton`, Вым нужно иметь
`owned_singleton` в зависимостях.
Ниже, в примере, использован атрибут `Singleton` на куске памяти, а затем
использован экземпляр одиночки как фиксированный по размеру пул памяти,
используя одну из абстракций [`alloc-singleton`].
[`alloc-singleton`]: https://crates.io/crates/alloc-singleton
``` rust
{{#include ../../../examples/singleton.rs}}
```
``` console
$ cargo run --example singleton
{{#include ../../../ci/expected/singleton.run}}```

View file

@ -0,0 +1,63 @@
# Программные задачи
RTFM обрабатывает прерывания и исключения как *аппаратные* задачи. Аппаратные
задачи могут вызываться устройством в ответ на события, такие как нажатие кнопки.
RTFM также поддерживает *программные* задачи, порождаемые программой из любого
контекста выполнения.
Программным задачам также можно назначать приоритет и диспетчеризовать из
обработчиков прерываний. RTFM требует определения свободных прерываний в блоке
`extern`, когда используются программные задачи; эти свободные прерывания будут использованы, чтобы диспетчеризовать программные задачи. Преимущество программных
задач перед аппаратными в том, что на один обработчик прерывания можно назначить
множество задач.
Программные задачи определяются заданием функциям атрибута `task`. Чтобы было
возможно вызывать программные задачи, имя задачи нужно передать в аргументе
`spawn` контекста атрибута (`init`, `idle`, `interrupt`, etc.).
В примере ниже продемонстрированы три программных задачи, запускаемые на 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}}```
## Ёмкость
Диспетчеры задач *не* используют динамическое выделение памяти. Память
необходимая для размещения сообщений, резервируется статически. Фреймворк
зарезервирует достаточно памяти для каждого контекста, чтобы можно было вызвать
каждую задачу как минимум единожды. Это разумно по умолчанию, но
"внутреннюю" ёмкость каждой задачи можно контролировать используя аргумент
`capacicy` атрибута `task`.
В примере ниже установлена ёмкость программной задачи `foo` на 4. Если ёмкость
не определена, тогда второй вызов `spawn.foo` в `UART0` вызовет ошибку.
``` rust
{{#include ../../../examples/capacity.rs}}
```
``` console
$ cargo run --example capacity
{{#include ../../../ci/expected/capacity.run}}```

View file

@ -0,0 +1,90 @@
# Очередь таймера
Когда включена опция `timer-queue`, фреймворк RTFM включает
*глобальную очередь таймера*, которую приложения могут использовать, чтобы
*планировать* программные задачи на запуск через некоторое время в будущем.
Чтобы была возможность планировать программную задачу, имя задачи должно
присутствовать в аргументе `schedule` контекста атрибута. Когда задача
планируется, момент ([`Instant`]), в который задачу нужно запустить, нужно передать
как первый аргумент вызова `schedule`.
[`Instant`]: ../../api/rtfm/struct.Instant.html
Рантайм RTFM включает монотонный, растущий только вверх, 32-битный таймер,
значение которого можно запросить конструктором `Instant::now`. Время ([`Duration`])
можно передать в `Instant::now()`, чтобы получить `Instant` в будущем. Монотонный
таймер отключен пока запущен `init`, поэтому `Instant::now()` всегда возвращает
значение `Instant(0 /* циклов тактовой частоты */)`; таймер включается сразу перед
включением прерываний и запуском `idle`.
[`Duration`]: ../../api/rtfm/struct.Duration.html
В примере ниже две задачи планируются из `init`: `foo` и `bar`. `foo` -
запланирована на запуск через 8 миллионов тактов в будущем. Кроме того, `bar`
запланирован на запуск через 4 миллиона тактов в будущем. `bar` запустится раньше
`foo`, т.к. он запланирован на запуск первым.
> **ВАЖНО**: Примеры, использующие API `schedule` или абстракцию `Instant`
> **не** будут правильно работать на QEMU, потому что функциональность счетчика
> тактов Cortex-M не реализована в `qemu-system-arm`.
``` rust
{{#include ../../../examples/schedule.rs}}
```
Запуск программы на реальном оборудовании производит следующий вывод в консоли:
``` text
{{#include ../../../ci/expected/schedule.run}}
```
## Периодические задачи
Программные задачи имеют доступ к `Instant` в момент, когда были запланированы
на запуск через переменную `scheduled`. Эта информация и API `schedule` могут
быть использованы для реализации периодических задач, как показано в примере ниже.
``` rust
{{#include ../../../examples/periodic.rs}}
```
Это вывод, произведенный примером. Заметьте, что есть смещение / колебание нуля
даже если `schedule.foo` была вызвана в *конце* `foo`. Использование
`Instant::now` вместо `scheduled` имело бы влияние на смещение / колебание.
``` text
{{#include ../../../ci/expected/periodic.run}}
```
## Базовое время
Для задач, планируемых из `init` мы имеем точную информацию о их планируемом
(`scheduled`) времени. Для аппаратных задач нет `scheduled` времени, потому
что эти задачи асинхронны по природе. Для аппаратных задач рантайм предоставляет
время старта (`start`), которе отражает время, в которое обработчик прерывания
был запущен.
Заметьте, что `start` **не** равен времени возникновения события, вызвавшего
задачу. В зависимости от приоритета задачи и загрузки системы время
`start` может быть сильно отдалено от времени возникновения события.
Какое по Вашему мнению будет значение `scheduled` для программных задач которые
*вызываются*, вместо того чтобы планироваться? Ответ в том, что вызываемые
задачи наследуют *базовое* время контекста, в котором вызваны. Бызовым для
аппаратных задач является `start`, базовым для программных задач - `scheduled`
и базовым для `init` - `start = Instant(0)`. `idle` на сомом деле не имеет
базового времени но задачи, вызванные из него будут использовать `Instant::now()`
как их базовое время.
Пример ниже демонстрирует разное значение *базового времени*.
``` rust
{{#include ../../../examples/baseline.rs}}
```
Запуск программы на реальном оборудовании произведет следующий вывод в консоли:
``` text
{{#include ../../../ci/expected/baseline.run}}
```

63
ru/src/by-example/tips.md Normal file
View file

@ -0,0 +1,63 @@
# Советы и хитрости
## Generics
Ресурсы, совместно используемые двумя или более задачами реализуют трейт `Mutex`
во *всех* контекстах, даже в тех, где для доступа к данным не требуются
критические секции. Это позволяет легко писать обобщенный код оперирующий
ресурсами, который можно вызывать из различных задач. Вот такой пример:
``` rust
{{#include ../../../examples/generics.rs}}
```
``` console
$ cargo run --example generics
{{#include ../../../ci/expected/generics.run}}```
Это также позволяет Вам изменять статические приоритеты задач без
переписывания кода. Если Вы единообразно используете `lock`-и для доступа
к данным в разделяемых ресурсах, тогда Ваш код продолжит компилироваться,
когда Вы измените приоритет задач.
## Запуск задач из RAM
Главной целью переноса описания программы на RTFM в атрибуты в
RTFM v0.4.x была возможность взаимодействия с другими атрибутами.
Напримерe, атрибут `link_section` можно применять к задачам, чтобы разместить
из в RAM; это может улучшить производительность в некоторых случаях.
> **ВАЖНО**: Обычно атрибуты `link_section`, `export_name` и `no_mangle`
> очень мощные, но их легко использовать неправильно. Неверное использование
> любого из этих атрибутов может вызвать неопределенное поведение;
> Вам следует всегда предпочитать использование безопасных, высокоуровневых
> атрибутов вокруг них, таких как атрибуты `interrupt` и `exception`
> из `cortex-m-rt`.
>
> В особых случаях функций RAM нет безопасной абстракции в `cortex-m-rt`
> v0.6.5 но создано [RFC] для добавления атрибута `ramfunc` в будущем релизе.
[RFC]: https://github.com/rust-embedded/cortex-m-rt/pull/100
В примере ниже показано как разместить высокоприоритетную задачу `bar` в RAM.
``` rust
{{#include ../../../examples/ramfunc.rs}}
```
Запуск этой программы произведет ожидаемый вывод.
``` console
$ cargo run --example ramfunc
{{#include ../../../ci/expected/ramfunc.run}}```
Можно посмотреть на вывод `cargo-nm`, чтобы убедиться, что `bar` расположен в RAM
(`0x2000_0000`), тогда как `foo` расположен во Flash (`0x0000_0000`).
``` console
$ cargo nm --example ramfunc --release | grep ' foo::'
{{#include ../../../ci/expected/ramfunc.grep.foo}}```
``` console
$ cargo nm --example ramfunc --release | grep ' bar::'
{{#include ../../../ci/expected/ramfunc.grep.bar}}```

View file

@ -0,0 +1,59 @@
# Типы, Send и Sync
Атрибут `app` вводит контекст, коллекцию переменных в каждую из функций.
Все эти переменные имеют предсказуемые, неанонимные типы, поэтому Вы можете
писать простые функции, получающие их как аргументы.
Описание API определяет как эти типы эти типы генерируются из входных данных.
Вы можете также сгенерировать документацию для Вашей бинарной библиотеки
(`cargo doc --bin <name>`); в документации Вы найдете структуры `Context`
(например `init::Context` и `idle::Context`), чьи поля представляют переменные
включенные в каждую функцию.
В примере ниже сгенерированы разные типы с помощью атрибута `app`.
``` rust
{{#include ../../../examples/types.rs}}
```
## `Send`
[`Send`] - маркерный трейт для "типов, которые можно передавать через границы
потоков", как это определено в `core`. В контексте RTFM трейт `Send` необходим
только там, где возможна передача значения между задачами, запускаемыми на
*разных* приоритетах. Это возникает в нескольких случаях: при передаче сообщений,
в совместно используемых `static mut` ресурсах и инициализации поздних ресурсов.
[`Send`]: https://doc.rust-lang.org/core/marker/trait.Send.html
Атрибут `app` проверит, что `Send` реализован, где необходимо, поэтому Вам не
стоит волноваться об этом. Более важно знать, где Вам *не* нужен трейт `Send`:
в типах, передаваемых между задачами с *одинаковым* приоритетом. Это возникает
в двух случаях: при передаче сообщений и в совместно используемых `static mut`
ресурсах.
В примере ниже показано, где можно использовать типы, не реализующие `Send`.
``` rust
{{#include ../../../examples/not-send.rs}}
```
## `Sync`
Похожая ситуация, [`Sync`] - маркерный трейт для "типов, на которых можно
ссылаться в разных потоках", как это определено в `core`. В контексте RTFM
трейт `Sync` необходим только там, где возможны две или более задачи,
запускаемые на разных приоритетах, чтобы захватить разделяемую ссылку на
ресурс. Это возникает только совместно используемых `static`-ресурсах.
[`Sync`]: https://doc.rust-lang.org/core/marker/trait.Sync.html
Атрибут `app` проверит, что `Sync` реализован, где необходимо, но важно знать,
где ограничение `Sync` не требуется: в `static`-ресурсах, разделяемых между
задачами с *одинаковым* приоритетом.
В примере ниже показано, где можно использовать типы, не реализующие `Sync`.
``` rust
{{#include ../../../examples/not-sync.rs}}
```

View file

@ -1 +0,0 @@
# Chapter 1

7
ru/src/internals.md Normal file
View file

@ -0,0 +1,7 @@
# Под капотом
В этом разделе описывабтся внутренности фркймворка на *высоком уровне*.
Низкоуровневые тонкости, такие как парсинг и кодогенерация производимые
процедурным макросом (`#[app]`) здесь объясняться не будут. Мы сосредоточимся
на анализе пользовательской спецификации и структурах данных, используемых
рантаймом.

View file

@ -0,0 +1,3 @@
# Ceiling analysis
**TODO**

View file

@ -0,0 +1,3 @@
# Task dispatcher
**TODO**

View file

@ -0,0 +1,3 @@
# Timer queue
**TODO**

12
ru/src/preface.md Normal file
View file

@ -0,0 +1,12 @@
<h1 align="center">Real Time For the Masses</h1>
<p align="center">Конкурентный фреймворк для создания систем реального времени</p>
# Введение
Эта книга содержит документацию уровня пользователя фреймворком Real Time For the Masses
(RTFM). Описание API можно найти [здесь](../api/rtfm/index.html).
{{#include README_RU.md:5:54}}
{{#include README_RU.md:60:}}