wii_ext/async_impl/
interface.rs

1use crate::core::{
2    ControllerIdReport, ControllerType, ExtHdReport, ExtReport, EXT_I2C_ADDR,
3    INTERMESSAGE_DELAY_MICROSEC_U32,
4};
5use embedded_hal_async;
6
7#[cfg(feature = "defmt_print")]
8use defmt;
9
10#[cfg_attr(feature = "defmt_print", derive(defmt::Format))]
11#[derive(Debug)]
12pub enum AsyncImplError {
13    I2C,
14    InvalidInputData,
15    Error,
16    ParseError,
17}
18
19#[cfg_attr(feature = "defmt_print", derive(defmt::Format))]
20#[derive(Debug, Default)]
21pub struct InterfaceAsync<I2C, Delay> {
22    i2cdev: I2C,
23    delay: Delay,
24}
25
26impl<I2C, Delay> InterfaceAsync<I2C, Delay>
27where
28    I2C: embedded_hal_async::i2c::I2c,
29    Delay: embedded_hal_async::delay::DelayNs,
30{
31    /// Create async interface for wii-extension controller
32    pub fn new(i2cdev: I2C, delay: Delay) -> Self {
33        Self { i2cdev, delay }
34    }
35
36    /// Destroy i2c interface, allowing recovery of i2c and delay
37    pub fn destroy(self) -> (I2C, Delay) {
38        (self.i2cdev, self.delay)
39    }
40
41    /// Access delay stored in interface
42    pub(super) async fn delay_us(&mut self, micros: u32) {
43        self.delay.delay_us(micros).await
44    }
45
46    /// Read report data from the wii-extension controller
47    pub(super) async fn read_ext_report(&mut self) -> Result<ExtReport, AsyncImplError> {
48        self.start_sample().await?;
49        self.delay_us(INTERMESSAGE_DELAY_MICROSEC_U32).await;
50        let mut buffer: ExtReport = ExtReport::default();
51        self.i2cdev
52            .read(EXT_I2C_ADDR as u8, &mut buffer)
53            .await
54            .map_err(|_| AsyncImplError::I2C)
55            .and(Ok(buffer))
56    }
57
58    /// Read a high-resolution version of the report data from the wii-extension controller
59    pub(super) async fn read_hd_report(&mut self) -> Result<ExtHdReport, AsyncImplError> {
60        self.start_sample().await?;
61        self.delay_us(INTERMESSAGE_DELAY_MICROSEC_U32).await;
62        let mut buffer: ExtHdReport = ExtHdReport::default();
63        self.i2cdev
64            .read(EXT_I2C_ADDR as u8, &mut buffer)
65            .await
66            .map_err(|_| AsyncImplError::I2C)
67            .and(Ok(buffer))
68    }
69
70    /// Send the init sequence to the Wii extension controller
71    pub(super) async fn init(&mut self) -> Result<(), AsyncImplError> {
72        // Extension controllers by default will use encrypted communication, as that is what the Wii does.
73        // We can disable this encryption by writing some magic values
74        // This is described at https://wiibrew.org/wiki/Wiimote/Extension_Controllers#The_New_Way
75
76        // Reset to base register first - this should recover a controller in a weird state.
77        // Use longer delays here than normal reads - the system seems more unreliable performing these commands
78        self.delay_us(100_000).await;
79        self.set_read_register_address_with_delay(0).await?;
80        self.set_register_with_delay(0xF0, 0x55).await?;
81        self.set_register_with_delay(0xFB, 0x00).await?;
82        self.delay_us(100_000).await;
83        Ok(())
84    }
85
86    /// Switch the driver from standard to hi-resolution reporting
87    ///
88    /// This enables the controller's high-resolution report data mode, which returns each
89    /// analogue axis as a u8, rather than packing smaller integers in a structure.
90    /// If your controllers supports this mode, you should use it. It is much better.
91    pub(super) async fn enable_hires(&mut self) -> Result<(), AsyncImplError> {
92        self.set_register_with_delay(0xFE, 0x03).await?;
93        self.delay_us(100_000).await;
94        Ok(())
95    }
96
97    /// Set the cursor position for the next i2c read
98    ///
99    /// This hardware has a range of 100 registers and automatically
100    /// increments the register read postion on each read operation, and also on
101    /// every write operation.
102    /// This should be called before a read operation to ensure you get the correct data
103    pub(super) async fn set_read_register_address(
104        &mut self,
105        byte0: u8,
106    ) -> Result<(), AsyncImplError> {
107        self.i2cdev
108            .write(EXT_I2C_ADDR as u8, &[byte0])
109            .await
110            .map_err(|_| AsyncImplError::I2C)
111            .and(Ok(()))
112    }
113
114    /// Set the cursor position for the next i2c read after a small delay
115    ///
116    /// This hardware has a range of 100 registers and automatically
117    /// increments the register read postion on each read operation, and also on
118    /// every write operation.
119    /// This should be called before a read operation to ensure you get the correct data
120    /// The delay helps ensure that required timings are met
121    pub(super) async fn set_read_register_address_with_delay(
122        &mut self,
123        byte0: u8,
124    ) -> Result<(), AsyncImplError> {
125        self.delay_us(INTERMESSAGE_DELAY_MICROSEC_U32).await;
126        let res = self.set_read_register_address(byte0);
127        res.await
128    }
129
130    /// Set a single register at target address
131    pub(super) async fn set_register(&mut self, addr: u8, byte1: u8) -> Result<(), AsyncImplError> {
132        self.i2cdev
133            .write(EXT_I2C_ADDR as u8, &[addr, byte1])
134            .await
135            .map_err(|_| AsyncImplError::I2C)
136            .and(Ok(()))
137    }
138
139    /// Set a single register at target address after a small delay
140    pub(super) async fn set_register_with_delay(
141        &mut self,
142        addr: u8,
143        byte1: u8,
144    ) -> Result<(), AsyncImplError> {
145        self.delay_us(INTERMESSAGE_DELAY_MICROSEC_U32).await;
146        let res = self.set_register(addr, byte1);
147        res.await
148    }
149
150    /// Read the controller type ID register from the extension controller
151    pub(super) async fn read_id(&mut self) -> Result<ControllerIdReport, AsyncImplError> {
152        self.set_read_register_address(0xfa).await?;
153        let i2c_id = self.read_ext_report().await?;
154        Ok(i2c_id)
155    }
156
157    /// Determine the controller type based on the type ID of the extension controller
158    pub(super) async fn identify_controller(
159        &mut self,
160    ) -> Result<Option<ControllerType>, AsyncImplError> {
161        let i2c_id = self.read_id().await?;
162        Ok(crate::core::identify_controller(i2c_id))
163    }
164
165    /// Instruct the extension controller to start preparing a sample by setting the read cursor to 0
166    pub(super) async fn start_sample(&mut self) -> Result<(), AsyncImplError> {
167        self.set_read_register_address(0x00).await?;
168        Ok(())
169    }
170}