rtic/book/ru/src/migration/migration_v5.md

366 lines
8.9 KiB
Markdown
Raw Normal View History

2021-12-25 16:18:28 +01:00
# Миграция с v0.5.x на v1.0.0
2021-04-04 07:15:13 +02:00
2021-12-25 16:18:28 +01:00
Этот раздел описывает как обновиться с версии v0.5.x на v1.0.0 фреймворка RTIC.
2021-04-04 07:15:13 +02:00
## `Cargo.toml` - увеличьте версию
Измените версию `cortex-m-rtic` на `"0.6.0"`.
## `mod` вместо `const`
С поддержкой атрибутов над модулями трюк с `const APP` теперь не нужен.
Измените
``` rust
#[rtic::app(/* .. */)]
const APP: () = {
[код здесь]
};
```
на
``` rust
#[rtic::app(/* .. */)]
mod app {
[код здесь]
}
```
Так как теперь используется обычный модуль Rust, это значит, что можно использовать
обычный пользовательский код в этом модуле.
2021-08-03 21:40:33 +02:00
Также это значит, что `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();
}
}
```
2021-04-04 07:15:13 +02:00
## Перенос диспетчеров из `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
2021-08-03 21:40:33 +02:00
## Структуры ресурсов - `#[shared]`, `#[local]`
2021-04-04 07:15:13 +02:00
2021-08-03 21:40:33 +02:00
Ранее ресурсы RTIC должны были размещаться в структуре с именем "Resources":
2021-04-04 07:15:13 +02:00
2021-08-03 21:40:33 +02:00
``` rust
struct Resources {
// Ресурсы определяются здесь
}
```
2021-12-25 16:18:28 +01:00
Начиная с RTIC v1.0.0 структуры ресурсов аннотируются подобно
2021-08-03 21:40:33 +02:00
`#[task]`, `#[init]`, `#[idle]`: аттрибутами `#[shared]` и `#[local]`
2021-04-04 07:15:13 +02:00
``` rust
2021-08-03 21:40:33 +02:00
#[shared]
struct MySharedResources {
// Разделяемые задачами ресурсы определены здесь
}
2021-04-04 07:15:13 +02:00
2021-08-03 21:40:33 +02:00
#[local]
struct MyLocalResources {
// Ресурсы, определенные здесь нельзя передавать между задачами; каждый из них локальный для единственной задачи
2021-04-04 07:15:13 +02:00
}
```
2021-08-03 21:40:33 +02:00
Эти структуры разработчик может называть по своему желанию.
## `shared` и `local` аргументы в `#[task]`'ах
2021-12-25 16:18:28 +01:00
В v1.0.0 ресурсы разделены на `shared` ресурсы и `local` ресурсы.
2021-08-03 21:40:33 +02:00
`#[task]`, `#[init]` и `#[idle]` больше не имеют аргумента `resources`;
они должны использовать аргументы `shared` и `local`.
В v0.5.x:
2021-04-04 07:15:13 +02:00
``` rust
2021-08-03 21:40:33 +02:00
struct Resources {
local_to_b: i64,
shared_by_a_and_b: i64,
}
2021-04-04 07:15:13 +02:00
2021-08-03 21:40:33 +02:00
#[task(resources = [shared_by_a_and_b])]
fn a(_: a::Context) {}
2021-04-04 07:15:13 +02:00
2021-08-03 21:40:33 +02:00
#[task(resources = [shared_by_a_and_b, local_to_b])]
fn b(_: b::Context) {}
```
2021-12-25 16:18:28 +01:00
В v1.0.0:
2021-08-03 21:40:33 +02:00
``` rust
#[shared]
struct Shared {
shared_by_a_and_b: i64,
2021-04-04 07:15:13 +02:00
}
2021-08-03 21:40:33 +02:00
#[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) {}
2021-04-04 07:15:13 +02:00
```
2021-08-03 21:40:33 +02:00
## Симметричные блокировки
2021-04-04 07:15:13 +02:00
2021-08-03 21:40:33 +02:00
Теперь RTIC использует симметричные блокировки, это значит, что метод `lock` нужно использовать для
всех доступов к `shared` ресурсам. Поскольку высокоприоритетные задачи имеют эксклюзивный доступ к ресурсу,
в старом коде можно было следующее:
2021-04-04 07:15:13 +02:00
``` rust
2021-08-03 21:40:33 +02:00
#[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 = /* ... */);
2021-04-04 07:15:13 +02:00
}
```
2021-08-03 21:40:33 +02:00
С симметричными блокировками нужно вызывать `lock` для обоих задач:
2021-04-04 07:15:13 +02:00
``` rust
2021-08-03 21:40:33 +02:00
#[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 = /* ... */);
2021-04-04 07:15:13 +02:00
}
```
2021-08-03 21:40:33 +02:00
Заметьте, что скорость работы не изменяется благодаря оптимизациям LLVM, которые убирают ненужные блокировки.
## Неблокирующий доступ к ресурсам
В RTIC 0.5 к ресурсам разделяемым задачами, запускаемыми с одинаковым
приоритетом, можно получить доступ *без* `lock` API.
Это все еще возможно в 0.6: ресурс `#[shared]` должен быть аннотирован
аттрибутом поля `#[lock_free]`.
v0.5 код:
2021-04-04 07:15:13 +02:00
``` rust
2021-08-03 21:40:33 +02:00
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;
2021-04-04 07:15:13 +02:00
}
```
2021-12-25 16:18:28 +01:00
v1.0 код:
2021-04-04 07:15:13 +02:00
2021-08-03 21:40:33 +02:00
``` rust
#[shared]
struct Shared {
#[lock_free]
counter: u64,
}
2021-04-04 07:15:13 +02:00
2021-08-03 21:40:33 +02:00
#[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`
2021-04-04 07:15:13 +02:00
2021-08-03 21:40:33 +02:00
`static mut` переменные больше не преобразуются в безопасные `&'static mut` ссылки.
Вместо этого синтаксиса используйте аргумент `local` в `#[init]`.
v0.5.x code:
2021-04-04 07:15:13 +02:00
``` rust
2021-08-03 21:40:33 +02:00
#[init]
fn init(_: init::Context) {
static mut BUFFER: [u8; 1024] = [0; 1024];
let buffer: &'static mut [u8; 1024] = BUFFER;
2021-04-04 07:15:13 +02:00
}
2021-08-03 21:40:33 +02:00
```
2021-04-04 07:15:13 +02:00
2021-12-25 16:18:28 +01:00
v1.0.0 code:
2021-08-03 21:40:33 +02:00
``` 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())
2021-04-04 07:15:13 +02:00
}
```
2021-08-03 21:40:33 +02:00
## Init всегда возвращает поздние ресурсы
С целью сделать API более симметричным задача #[init] всегда возвращает поздние ресурсы.
С этого:
2021-04-04 07:15:13 +02:00
``` rust
2021-08-03 21:40:33 +02:00
#[rtic::app(device = lm3s6965)]
mod app {
#[init]
fn init(_: init::Context) {
rtic::pend(Interrupt::UART0);
}
// [еще код]
2021-04-04 07:15:13 +02:00
}
2021-08-03 21:40:33 +02:00
```
2021-04-04 07:15:13 +02:00
2021-08-03 21:40:33 +02:00
на это:
``` 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]
2021-04-04 07:15:13 +02:00
}
```
2021-08-03 21:40:33 +02:00
## Вызов/планирование откуда угодно
2021-04-04 07:15:13 +02:00
2021-08-03 21:40:33 +02:00
С этой новой возвожностью, старый код, такой как:
2021-04-04 07:15:13 +02:00
``` rust
2021-08-03 21:40:33 +02:00
#[task(spawn = [bar])]
2021-04-04 07:15:13 +02:00
fn foo(cx: foo::Context) {
2021-08-03 21:40:33 +02:00
cx.spawn.bar().unwrap();
2021-04-04 07:15:13 +02:00
}
2021-08-03 21:40:33 +02:00
#[task(schedule = [bar])]
2021-04-04 07:15:13 +02:00
fn bar(cx: bar::Context) {
2021-08-03 21:40:33 +02:00
cx.schedule.foo(/* ... */).unwrap();
2021-04-04 07:15:13 +02:00
}
```
2021-08-03 21:40:33 +02:00
Теперь будет выглядеть так:
2021-04-04 07:15:13 +02:00
``` rust
2021-08-03 21:40:33 +02:00
#[task]
fn foo(_c: foo::Context) {
bar::spawn().unwrap();
2021-04-04 07:15:13 +02:00
}
2021-08-03 21:40:33 +02:00
#[task]
fn bar(_c: bar::Context) {
foo::schedule(/* ... */).unwrap();
2021-04-04 07:15:13 +02:00
}
```
2021-08-03 21:40:33 +02:00
Заметьте, что атрибуты `spawn` и `schedule` больше не нужны.
2021-04-04 07:15:13 +02:00
---
## Дополнительно
### Внешние задачи
Как программные, так и аппаратные задачи теперь можно определять вне модуля `mod app`.
Ранее это было возможно только путем реализации обертки, вызывающей реализацию задачи.
Смотреть примеры `examples/extern_binds.rs` и `examples/extern_spawn.rs`.