# 卒研経過報告 #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)