chakokuのブログ(rev4)

テック・コミック・DTM・・・ごくまれにチャリ

Rustでドライバを試作する(その2)

課題:I2Cバスで制御するドライバを書いていたが、どうしてもGPIOの方向を変えるコードをstruct型に閉じ込めた変数で実装することができなかった(借用のselfとデータの移動との矛盾が解消できず)
解決策:メソッド実行時、借用のselfではなく、所有権付きのselfを渡してメソッドでselfに再代入を行うことで、上記エラーが解消できた。このままだとselfの?所有権がメソッドに行きっぱなしになるので、呼び出し元にselfを返却する。メソッドから帰ってきたselfの実体を変数に再代入してもらうことで、所有権が戻るようにした。このコードが以下

use anyhow::Result;
use esp_idf_svc::hal::gpio::{PinDriver, Pin, Output, Input, Level,Gpio2, Gpio3};
//use esp_idf_svc::hal::gpio::Level::{Low, High};
use esp_idf_svc::hal::peripherals::Peripherals;
use esp_idf_svc::sys::link_patches;
//use std::{thread::sleep, time::Duration};

struct I2CBus<'a, >{
    scl: PinDriver<'a, Gpio2, Output> ,
    sda: PinDriver<'a, Gpio3, Output> ,
}
impl I2CBus<'_> {
  fn send(mut self)->Self{
      self.scl.set_low();
      let sda_in = self.sda.into_input().unwrap();
      self.sda = sda_in.into_output().unwrap();
      self
  }  
}


fn main() -> Result<()> {

  link_patches();
  esp_idf_svc::log::EspLogger::initialize_default();

  let peripherals = Peripherals::take()?;

  let mut i2c_bus = I2CBus{
     scl: PinDriver::output(peripherals.pins.gpio2)?,
     sda: PinDriver::output(peripherals.pins.gpio3)?,
  };
  loop{
     i2c_bus = i2c_bus.send();
  } 
}

上記のようにstructにI2Cを制御するscl, sdaを閉じ込め、scl, sdaの操作はメソッドにまとめることで、本来のオブジェクト指向風にドライバが実装できる。これまでのように、GPIOの実体をサブルーチンから戻してもらうようなコードを書かなくてもよくなる。