Rust製組込みOSのTockを触ってみる②

はじめに

諸事情によりまとまった時間を取るのが難しいので、入門系やります。

今回は、Rust製のRTOSであるTockを触ってみます。 githubのTock organizationはこちらです。

前回はC言語で書かれたサンプルアプリケーションを動かしたので、今回はRustで書かれたサンプルアプリケーションを動かしてみます。

libtock-rs

Rustでアプリケーションを書くためのライブラリレポジトリは、libtock-rsです。 examplesは、nRF52-DKでなら動作するようです。 nRF52840-DKとは別物ですが、まぁ動くでしょう。やってみましょう。

rustup target add thumbv7em-none-eabi
git clone https://github.com/tock/libtock-rs.git
cd libtock-rs
./run_example.sh blink

無事書き込めて、動いています。

+ elf_file_name=target/tab/blink/cortex-m4.elf
+ tab_file_name=target/tab/blink.tab
+ tockloader_flags='--jlink --arch cortex-m4 --board nrf52dk --jtag-device nrf52 --app-address 0x20000'
+ hail_defined=
+ '[' -n '' ']'
+ mkdir -p target/tab/blink
+ cp target/thumbv7em-none-eabi/release/examples/blink target/tab/blink/cortex-m4.elf
+ elf2tab -n blink -o target/tab/blink.tab target/tab/blink/cortex-m4.elf --stack 2048 --app-heap 1024 --kernel-heap 1024 --protected-region-size=64
+ '[' 1 -ge 2 ']'
+ tockloader uninstall --jlink --arch cortex-m4 --board nrf52dk --jtag-device nrf52 --app-address 0x20000
Preparing to uninstall apps...
Using known arch and jtag-device for known board nrf52dk
No apps are installed on the board

+ true
+ tockloader install --jlink --arch cortex-m4 --board nrf52dk --jtag-device nrf52 --app-address 0x20000 target/tab/blink.tab
Installing apps on the board...
Using known arch and jtag-device for known board nrf52dk
Finished in 1.961 seconds

なにやら色々やっていますね。 事前にアプリケーションがインストールされていると、アンインストールするみたいです。

examplesチラ見

BLEのサンプルがあって気になります。

|> exmaples/ble_scanning.rs

#![no_std]

use libtock::ble_parser;
use libtock::led;
use libtock::simple_ble;
use libtock::simple_ble::BleCallback;
use libtock::simple_ble::BleDriver;
use libtock::syscalls;
use serde::Deserialize;

#[derive(Deserialize)]
struct LedCommand {
    pub nr: u8,
    pub st: bool,
}

// Prevents the compiler from dropping the subscription too early.
#[allow(unreachable_code)]
fn main() {
    let mut shared_buffer = BleDriver::create_scan_buffer();
    let mut my_buffer = BleDriver::create_scan_buffer();
    let shared_memory = BleDriver::share_memory(&mut shared_buffer).unwrap();

    let mut callback = BleCallback::new(|_: usize, _: usize| {
        shared_memory.read_bytes(&mut my_buffer[..]);
        ble_parser::find(&my_buffer, simple_ble::gap_data::SERVICE_DATA as u8)
            .and_then(|service_data| ble_parser::extract_for_service([91, 79], service_data))
            .and_then(|payload| corepack::from_bytes::<LedCommand>(&payload).ok())
            .and_then(|msg| led::get(msg.nr as isize).map(|led| led.set_state(msg.st)));
    });

    let _subscription = BleDriver::start(&mut callback).unwrap();

    loop {
        syscalls::yieldk();
    }
}

あー、serdeビルドしているの、なぜだろうと思ってましたが、ここで使っていたのですね…。 割とビルド時間長いのは、気になりますね。

BLE Advertising driverもkernel側に実装されています。 libtock-rsにBleAdvertisingDriverの実装がありますが、基本はシステムコールを呼ぶだけで、実態はkernel側のようですね。

おもむろにDRIVER_NUMBERが使用されていますが、これはkernel側のシステムコールで定義されています。

|> libtock-rs/src/simple_ble.rs

const DRIVER_NUMBER: usize = 0x30000;
pub const MAX_PAYLOAD_SIZE: usize = 9;
pub const BUFFER_SIZE_ADVERTISE: usize = 39;
pub const BUFFER_SIZE_SCAN: usize = 39;

mod ble_commands {
    pub const START_ADVERTISING: usize = 0;
    pub const ALLOW_ADVERTISMENT_BUFFER: usize = 0;
    pub const BLE_PASSIVE_SCAN_SUB: usize = 0;
    pub const ALLOW_SCAN_BUFFER: usize = 1;
    pub const PASSIVE_SCAN: usize = 5;
}

|> tock/doc/syscalls/README.md

Radio

1.0 Driver Number Driver Description
0x30000 BLE Bluetooth Low Energy
0x30001 802.15.4 IEEE 802.15.4
0x30002 UDP UDP / 6LoWPAN Interface

なるほどね〜。