前提
現在、Rust + ESP32でI2Cに接続したPWMボードと9軸センサーを制御するプログラムを作成している。
同じI2Cバスに2つの制御対象を接続するため、I2Cインスタンスは共有したいと考えたため、
I2Cはesp_idf_halクレートを使用してインスタンスを生成し、
そのインスタンスを保持する自作のI2CDriverクラスを作成し、
PWMコントローラークラスと9軸コントローラークラスでそのI2CDriverクラスのインスタンスを共有して保持するように作成していた。
今回の問題が発生した経緯
次にPCA9685チップが搭載されているPWMボードの制御をおこないたいと思い、
PWM-Pca9685クレートを使用し、
PWMコントローラークラス内で保持しているI2Cインスタンスを使用してPca9685構造体をnew関数でインスタンス化しようとした。
しかし、new関数の引数にI2Cインスタンスを渡そうとすると、
cannot move out of dereference of `RefMut<'_, &mut I2CDriver<I2C, SDA, SCL>>` move occurs because value has type `esp_idf_hal::i2c::Master<I2C, SDA, SCL>`, which does not implement the `Copy` trait
とエラーが表示されてしまう。
I2CインスタンスはI2CDriver<~~~>構造体が保持しており、
I2CDriver<~~~>構造体はRc<RefCell<I2CDriver<~~~>>>の形でPWMコントローラーが保持している。
Rc<RefCell<I2CDriver<~~~>>>の形でI2Cインスタンスを保持することで、PWMコントローラーでも9軸コントローラーでもI2Cインスタンスを保持することができることは確認している。
このRc<RefCell<I2CDriver<~~~>>>は、Rc::clone()してさらにborrow_mut()すれば、I2CDriverをCopyしなくても参照として保持することができ、インスタンスを実体として関数に渡せるようになるとの認識だったため、エラーがどうしても解決できずにいる。
質問内容
Q1. クレートの関数の引数にインスタンスを渡す時、コピーしなくてもよい方法があるかどうか。
Q2. もしなければ、複数箇所で使用したいインスタンスの所有権を奪われるクレートに対して、どのような回避策があるのか
をご教授お願い致します。
ソースコード
pwm_controller.rs
Rust
1use esp_idf_hal::{ 2 gpio::{InputPin, OutputPin}, 3 i2c::{self as esp_i2c_mod}, 4}; 5use std::{cell::RefCell, rc::Rc}; 6 7use i2c_driver::i2c::I2CDriver; 8use i2c_driver::i2c::I2CMasterTrait; 9 10use anyhow; 11 12use pwm_pca9685::{Address, Channel, Pca9685}; 13 14pub struct PwmController<'i2c_driver, I2C, SDA, SCL> 15where 16 I2C: esp_i2c_mod::I2c, 17 SDA: OutputPin + InputPin, 18 SCL: OutputPin + InputPin, 19{ 20 pub i2c_driver: Rc<RefCell<&'i2c_driver mut I2CDriver<I2C, SDA, SCL>>>, 21 pub slave_id: u8, 22} 23 24impl<I2C, SDA, SCL> PwmController<'_, I2C, SDA, SCL> 25where 26 I2C: esp_i2c_mod::I2c, 27 SDA: OutputPin + InputPin, 28 SCL: OutputPin + InputPin, 29{ 30 pub fn new( 31 i2c_driver: Rc<RefCell<&mut I2CDriver<I2C, SDA, SCL>>>, 32 slave_id: u8, 33 ) -> anyhow::Result<PwmController<I2C, SDA, SCL>> { 34 return Ok(PwmController { 35 i2c_driver, 36 slave_id, 37 }); 38 } 39 // PWMボードのアドレスを取得する 40 pub fn fetch_board_addr(&self) -> String { 41 return "not implement".to_string(); 42 } 43 44 fn test_pwm(&mut self) { 45 let i2c_driver = Rc::clone(&self.i2c_driver); 46 let i2c = i2c_driver.borrow_mut(); 47 let address = Address::default(); 48 49 let mut pwm = Pca9685::new(i2c.i2c_instance, address).unwrap(); 50 // This corresponds to a frequency of 60 Hz. 51 pwm.set_prescale(100).unwrap(); 52 53 // It is necessary to enable the device. 54 pwm.enable().unwrap(); 55 56 // Turn on channel 0 at 0. 57 pwm.set_channel_on(Channel::C0, 0).unwrap(); 58 59 // Turn off channel 0 at 2047, which is 50% in 60 // the range `[0..4095]`. 61 pwm.set_channel_off(Channel::C0, 2047).unwrap(); 62 63 let _ = pwm.destroy(); // Get the I2C device back 64 } 65} 66 67impl<I2C, SDA, SCL> I2CMasterTrait for PwmController<'_, I2C, SDA, SCL> 68where 69 I2C: esp_i2c_mod::I2c, 70 SDA: OutputPin + InputPin, 71 SCL: OutputPin + InputPin, 72{ 73 fn get_id(&self) -> u8 { 74 self.slave_id 75 } 76 77 fn exist_slave(&mut self) -> bool { 78 let mut buffer = [0, 2]; 79 RefCell::borrow_mut(&self.i2c_driver) 80 .read(self.get_id(), &mut buffer) 81 .unwrap(); 82 83 println!("exist {}, buffer = {:?}", self.get_id(), buffer); 84 85 return true; 86 } 87}
i2c.rs
Rust
1//! i2cのインスタンスを管理するクラス 2//! 3 4use std::{thread::sleep, time::Duration}; 5 6use anyhow::Result; 7use embedded_hal::prelude::_embedded_hal_blocking_i2c_Read; 8use esp_idf_hal::{ 9 gpio::{InputPin, OutputPin}, 10 i2c::{self, I2cError}, 11}; 12 13pub trait I2CMasterTrait { 14 fn get_id(&self) -> u8; 15 /// センサーが生きているかどうか 16 fn exist_slave(&mut self) -> bool; 17} 18 19pub struct I2CDriver<I2C, SDA, SCL> 20where 21 I2C: i2c::I2c, 22 SDA: OutputPin + InputPin, 23 SCL: OutputPin + InputPin, 24{ 25 pub i2c_instance: i2c::Master<I2C, SDA, SCL>, 26} 27 28impl<I2C, SDA, SCL> I2CDriver<I2C, SDA, SCL> 29where 30 I2C: i2c::I2c, 31 SDA: OutputPin + InputPin, 32 SCL: OutputPin + InputPin, 33{ 34 pub fn new(i2c: I2C, pins: i2c::MasterPins<SDA, SCL>) -> Result<Self> { 35 let i2c_instance = i2c::Master::new( 36 i2c, 37 pins, 38 i2c::config::MasterConfig::new().timeout(Some(Duration::from_millis(100))), 39 ) 40 .unwrap(); 41 42 return Ok(I2CDriver { i2c_instance }); 43 } 44 45 pub fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), I2cError> { 46 if let Err(e) = self.i2c_instance.read(address, buffer) { 47 println!("read error: {}", e); 48 return Ok(()); 49 } 50 return Ok(()); 51 } 52 53 pub fn scan_address(&mut self) -> String { 54 println!("created i2c pwm boad instance."); 55 56 for address in 60..127 { 57 println!("try address= {}", address); 58 59 let mut ret = [0; 32]; 60 if let Err(e) = self.i2c_instance.read(address, &mut ret) { 61 println!("cant read e:{}", e); 62 continue; 63 } 64 65 println!("Read Complete."); 66 println!("hit i2c. addr: {:?}", address); 67 println!("receive data = {:?}", ret); 68 sleep(Duration::from_millis(100)); 69 } 70 71 return "finish".to_string(); 72 } 73}
エラー発生箇所とエラー文
エラー文は今回の問題が発生した経緯と同じ

あなたの回答
tips
プレビュー