# 卒研経過報告 #12
Rustによる組み込みプログラミング
マイコンWio terminalを用いたRustとC言語の信頼性,安全性の比較検証、考察
[先週のレジュメ](https://hackmd.io/@Fteam/Syll3sEdY)
### 型状態プログラミング
何すればいいかわからなかったので,言語化して課題を明確にする.
#### 実現したいこと
Rustの型状態プログラミングの利点の確認.
#### 主張の流れ
1. 構造体を用いGPIOの状態を管理する -> 無効から出力のような例が作成可能
```graphviz
digraph hierarchy {
GPIO->{無効 有効}
有効->{出力 入力}
出力->{high low}
入力->{高抵抗 プルダウン プルアップ}
}
```
2. 全ての動作でifで状態チェック -> 実行コスト
3. Rustの型システム
#### わかっていること
- 組み込み -> wioを使うといい
- 簡単な例でも可
-> ボタンを押してLEDを点灯する例を流用するのが最適か
#### 実現
3.のRustの型システムについて
先週のコードを構造体を使った例に変更(組込みRustから抜粋)
:::spoiler コード
```rust=
#![no_std]
#![no_main]
#![allow(dead_code)] // 使用しないメソッドでコンパイラが警告を出さないようにする
use panic_halt as _;
use wio_terminal as wio;
use wio::entry;
use wio::hal::gpio::*; // GPIOの構造体やトレイトをインポートする
use wio::pac::Peripherals;
use wio::prelude::*; // 主要な構造体やトレイトをインポートする
#[entry]
fn main() -> ! {
let peripherals = Peripherals::take().unwrap();
let mut pins = wio::Pins::new(peripherals.PORT);
// TODO: ボタン1を押している間、LEDが点灯するコードを書く
let mut led = Led::new(pins.user_led, &mut pins.port);
let button1 = Button1::new(pins.button1, &mut pins.port);
loop {
if button1.is_pressed(){
led.turn_on();
}else{
led.turn_off();
}
}
}
// Wio Terminalのボタン1ドライバ
struct Button1{
pin: Pc26<Input<Floating>>,
}
impl Button1 {
// PC26 ピンを入力モードに設定する
fn new(pin: Pc26<Input<Floating>>, port: &mut Port) -> Button1 {
Button1 {
pin: pin.into_floating_input(port),
}
}
// ボタンが押されていれば trueを返す
fn is_pressed (&self) -> bool {
self.pin.set_low().unwrap() // error
}
// ボタンが押されていなければtrue を返す
fn is_released (&self) -> bool {
self.pin.is_high().unwrap()
}
}
// Wio TerminalのユーザーLEDドライバ
struct Led {
pin: Pa15<Output<PushPull>>,
}
impl Led {
// デフォルトモードの PA15 ピンを、出力モードに移行する
fn new(pin: Pa15<Input<Floating>>, port: &mut Port) -> Led {
Led {
pin: pin.into_push_pull_output(port),
}
}
// LEDを点灯する
fn turn_on(&mut self) {
self.pin.set_high().unwrap();
}
// LEDを消灯する
fn turn_off(&mut self) {
self.pin.set_low().unwrap();
}
// LEDが点灯しているときは消灯し、消灯しているときは点灯する
fn toggle(&mut self) {
self.pin.toggle();
}
}
```
:::
`use wio::hal::gpio::*;`:GPIOの構造体やトレイトのインポート
---
**ifを使って実行時にチェックを行う例**
* set_enable関数は条件なしでenableを1(有効)に
* set_direction関数はenableが1(有効)の時のみ使えてset_bit()で方向を1(出力)に変更する
* set_output_statusはenableが有効かつdirectionが出力の時に使えて、出力モードを1にする
result型よくわからん
```=rust
impl Gpio {
pub fn set_enable(&mut self, is_enabled: bool) {
self.periph.modify(|_r, w| {
w.enable().set_bit(is_enabled)
});
}
pub fn set_direction(&mut self, is_output: bool) -> Result<(), ()> {
if self.periph.read().enable().bit_is_clear() {
// 方向を設定するには、有効化されてなければなりません
return Err(());
}
self.periph.modify(|r, w| {
w.direction().set_bit(is_output)
});
Ok(())
}
pub fn set_output_status(&mut self, is_high: bool) -> Result<(), ()> {
if self.periph.read().enable().bit_is_clear() {
// 出力状態を設定するためには、有効化されてなければなりません
return Err(());
}
if self.periph.read().direction().bit_is_clear() {
// 方向は出力でなければなりません
return Err(());
}
self.periph.modify(|_r, w| {
w.output_mode.set_bit(is_high)
});
Ok(())
}
```
簡単な例➡同じように構造体を作り
bool型で1か0(入力か出力/有効か無効)かをif文でチェックする簡単なコードを作ればいい?(まだできてないしよくわからん)
set_enableは条件なしでenabledをtrueに
set_directionはenabledが(1)でなければ処理を抜ける
(1)ならdirectionをtrueに
```=rust
struct Gpio{
enabled:bool,
direction:bool,
output:bool,
//periph:GPIO_CONFIG,
}
impl Gpio{
pub fn set_enable(&mut self){
self.enabled=true;
}
pub fn set_direction(&mut self){
if self.enabled!=true{
return;
}
self.direction=true;
}
pub fn set_output_status(&mut self){
if self.enabled!=true{
return;
}
if self.direction!=true{
return;
}
self.output=true;
}
}
fn main(){
let mut pin=Gpio{
enabled:false,
direction:false,
output:false,
};
println!("{}",pin.enabled); //false
pin.set_enable();
println!("{}",pin.enabled); //true
}
```
そもそも構造体がまだよくわかってない
## 参考文献
[1] rustプログラミング入門 オーム社
[2] 基礎から学ぶ組込みRust C&R研究所
[公式ドキュメント](https://doc.rust-jp.rs/book-ja/ch08-02-strings.html)
[The Embedded Rust Book](https://tomoyuki-nakabayashi.github.io/book/static-guarantees/index.html)
[seeed:ユーザー定義ボタン](https://wiki.seeedstudio.com/jp/Wio-Terminal-Buttons/)
[](https://tomo-wait-for-it-yuki.hatenablog.com/entry/2019/01/30/163235)