From cb396756b5aa90c90dc95084cbaa25e0b219eb2f Mon Sep 17 00:00:00 2001 From: 9names <60134748+9names@users.noreply.github.com> Date: Sun, 14 Apr 2024 22:22:38 +1000 Subject: [PATCH] Extract async i2c interface --- wii-ext/src/classic_async.rs | 151 ++++++----------------------------- wii-ext/src/lib.rs | 2 + 2 files changed, 25 insertions(+), 128 deletions(-) diff --git a/wii-ext/src/classic_async.rs b/wii-ext/src/classic_async.rs index 60c59bd..e8f272b 100644 --- a/wii-ext/src/classic_async.rs +++ b/wii-ext/src/classic_async.rs @@ -11,33 +11,20 @@ // See `decode_classic_report` and `decode_classic_hd_report` for data format use crate::core::classic::*; -use crate::ControllerIdReport; -use crate::ControllerType; -use crate::ExtHdReport; -use crate::ExtReport; -use crate::EXT_I2C_ADDR; -use crate::INTERMESSAGE_DELAY_MICROSEC_U32; +use crate::interface_async::InterfaceAsync; +use crate::{ControllerIdReport, ControllerType}; use embedded_hal_async; // use core::future::Future; -#[cfg(feature = "defmt_print")] -use defmt; -#[cfg_attr(feature = "defmt_print", derive(defmt::Format))] -#[derive(Debug)] -pub enum ClassicAsyncError { - I2C, - InvalidInputData, - Error, - ParseError, -} + +use crate::interface_async::ClassicAsyncError; pub struct ClassicAsync { - i2cdev: I2C, + interface: InterfaceAsync, hires: bool, calibration: CalibrationData, - delay: Delay, } // use crate::nunchuk; @@ -52,38 +39,14 @@ where /// send the required init sequence in order to read data in /// the future. pub fn new(i2cdev: I2C, delay: Delay) -> Self { + let interface = InterfaceAsync::new(i2cdev, delay); Self { - i2cdev, + interface, hires: false, calibration: CalibrationData::default(), - delay, } } - async fn delay_us(&mut self, micros: u32) { - self.delay.delay_us(micros).await - } - - /// Read the button/axis data from the classic controller - async fn read_ext_report(&mut self) -> Result { - let mut buffer: ExtReport = ExtReport::default(); - self.i2cdev - .read(EXT_I2C_ADDR as u8, &mut buffer) - .await - .map_err(|_| ClassicAsyncError::I2C) - .and(Ok(buffer)) - } - - /// Read a high-resolution version of the button/axis data from the classic controller - async fn read_hd_report(&mut self) -> Result { - let mut buffer: ExtHdReport = ExtHdReport::default(); - self.i2cdev - .read(EXT_I2C_ADDR as u8, &mut buffer) - .await - .map_err(|_| ClassicAsyncError::I2C) - .and(Ok(buffer)) - } - // / Update the stored calibration for this controller // / // / Since each device will have different tolerances, we take a snapshot of some analog data @@ -111,112 +74,44 @@ where // Reset to base register first - this should recover a controller in a weird state. // Use longer delays here than normal reads - the system seems more unreliable performing these commands - self.delay_us(100_000).await; - self.set_read_register_address_with_delay(0).await?; - self.set_register_with_delay(0xF0, 0x55).await?; - self.set_register_with_delay(0xFB, 0x00).await?; - self.delay_us(100_000).await; + self.interface.init().await?; self.update_calibration().await?; Ok(()) } - /// Switch the driver from standard to hi-resolution reporting - /// - /// This enables the controllers high-resolution report data mode, which returns each - /// analogue axis as a u8, rather than packing smaller integers in a structure. - /// If your controllers supports this mode, you should use it. It is much better. - pub async fn enable_hires(&mut self) -> Result<(), ClassicAsyncError> { - self.set_register_with_delay(0xFE, 0x03).await?; - self.hires = true; - self.delay_us(100_000).await; - self.update_calibration().await?; - Ok(()) - } - - /// Set the cursor position for the next i2c read - /// - /// This hardware has a range of 100 registers and automatically - /// increments the register read postion on each read operation, and also on - /// every write operation. - /// This should be called before a read operation to ensure you get the correct data - async fn set_read_register_address(&mut self, byte0: u8) -> Result<(), ClassicAsyncError> { - self.i2cdev - .write(EXT_I2C_ADDR as u8, &[byte0]) - .await - .map_err(|_| ClassicAsyncError::I2C) - .and(Ok(())) - } - - async fn set_read_register_address_with_delay( - &mut self, - byte0: u8, - ) -> Result<(), ClassicAsyncError> { - self.delay_us(INTERMESSAGE_DELAY_MICROSEC_U32).await; - let res = self.set_read_register_address(byte0); - res.await - } - - /// Set a single register at target address - async fn set_register(&mut self, addr: u8, byte1: u8) -> Result<(), ClassicAsyncError> { - self.i2cdev - .write(EXT_I2C_ADDR as u8, &[addr, byte1]) - .await - .map_err(|_| ClassicAsyncError::I2C) - .and(Ok(())) - } - - async fn set_register_with_delay( - &mut self, - addr: u8, - byte1: u8, - ) -> Result<(), ClassicAsyncError> { - self.delay_us(INTERMESSAGE_DELAY_MICROSEC_U32).await; - let res = self.set_register(addr, byte1); - res.await - } - - async fn read_id(&mut self) -> Result { - self.set_read_register_address(0xfa).await?; - let i2c_id = self.read_ext_report().await?; - Ok(i2c_id) - } - - pub async fn identify_controller( - &mut self, - ) -> Result, ClassicAsyncError> { - let i2c_id = self.read_id().await?; - Ok(crate::common::identify_controller(i2c_id)) - } - - /// tell the extension controller to prepare a sample by setting the read cursor to 0 - async fn start_sample(&mut self) -> Result<(), ClassicAsyncError> { - self.set_read_register_address(0x00).await?; - Ok(()) - } - /// poll the controller for the latest data async fn read_classic_report(&mut self) -> Result { if self.hires { - let buf = self.read_hd_report().await?; + let buf = self.interface.read_hd_report().await?; ClassicReading::from_data(&buf).ok_or(ClassicAsyncError::InvalidInputData) } else { - let buf = self.read_ext_report().await?; + let buf = self.interface.read_ext_report().await?; ClassicReading::from_data(&buf).ok_or(ClassicAsyncError::InvalidInputData) } } /// Simple blocking read helper that will start a sample, wait 10ms, then read the value async fn read_report(&mut self) -> Result { - self.start_sample().await?; - self.delay_us(INTERMESSAGE_DELAY_MICROSEC_U32).await; self.read_classic_report().await } /// Do a read, and report axis values relative to calibration pub async fn read(&mut self) -> Result { Ok(ClassicReadingCalibrated::new( - self.read_report().await?, + self.read_classic_report().await?, &self.calibration, )) } + + pub async fn enable_hires(&mut self) -> Result<(), ClassicAsyncError> { + self.interface.enable_hires().await + } + + pub async fn read_id(&mut self) -> Result { + self.interface.read_id().await + } + + pub async fn identify_controller(&mut self)-> Result, ClassicAsyncError> { + self.interface.identify_controller().await + } } diff --git a/wii-ext/src/lib.rs b/wii-ext/src/lib.rs index c418a02..a6c5ae3 100644 --- a/wii-ext/src/lib.rs +++ b/wii-ext/src/lib.rs @@ -14,6 +14,8 @@ pub mod common; /// i2c interface code pub mod interface; +/// async i2c interface code +pub mod interface_async; pub mod nunchuk;