wii_ext/blocking_impl/
interface.rs

1use crate::core::{
2    ControllerIdReport, ControllerType, ExtHdReport, ExtReport, EXT_I2C_ADDR,
3    INTERMESSAGE_DELAY_MICROSEC_U32 as INTERMESSAGE_DELAY_MICROSEC,
4};
5use embedded_hal::i2c::{I2c, SevenBitAddress};
6
7#[cfg_attr(feature = "defmt_print", derive(defmt::Format))]
8#[derive(Debug, Default)]
9pub struct Interface<I2C, Delay> {
10    i2cdev: I2C,
11    delay: Delay,
12}
13
14#[cfg_attr(feature = "defmt_print", derive(defmt::Format))]
15#[derive(Debug)]
16/// Errors in this crate
17pub enum BlockingImplError<E> {
18    /// I²C bus communication error
19    I2C(E),
20    /// Invalid input data provided
21    InvalidInputData,
22}
23
24impl<I2C, E, Delay> Interface<I2C, Delay>
25where
26    I2C: I2c<SevenBitAddress, Error = E>,
27    Delay: embedded_hal::delay::DelayNs,
28{
29    pub fn new(i2cdev: I2C, delay: Delay) -> Interface<I2C, Delay> {
30        Interface { i2cdev, delay }
31    }
32
33    /// Recover data members
34    pub fn destroy(self) -> (I2C, Delay) {
35        (self.i2cdev, self.delay)
36    }
37
38    /// Send the init sequence to the Wii extension controller
39    pub(super) fn init(&mut self) -> Result<(), BlockingImplError<E>> {
40        // Extension controllers by default will use encrypted communication, as that is what the Wii does.
41        // We can disable this encryption by writing some magic values
42        // This is described at https://wiibrew.org/wiki/Wiimote/Extension_Controllers#The_New_Way
43
44        // Reset to base register first - this should recover a controller in a weird state.
45        // Use longer delays here than normal reads - the system seems more unreliable performing these commands
46        self.delay.delay_us(INTERMESSAGE_DELAY_MICROSEC * 2);
47        self.set_read_register_address(0)?;
48        self.delay.delay_us(INTERMESSAGE_DELAY_MICROSEC * 2);
49        self.set_register(0xF0, 0x55)?;
50        self.delay.delay_us(INTERMESSAGE_DELAY_MICROSEC * 2);
51        self.set_register(0xFB, 0x00)?;
52        self.delay.delay_us(INTERMESSAGE_DELAY_MICROSEC * 2);
53        Ok(())
54    }
55
56    pub(super) fn read_id(&mut self) -> Result<ControllerIdReport, BlockingImplError<E>> {
57        self.set_read_register_address(0xfa)?;
58        let i2c_id = self.read_report()?;
59        Ok(i2c_id)
60    }
61
62    /// Determine the controller type based on the type ID of the extension controller
63    pub(super) fn identify_controller(
64        &mut self,
65    ) -> Result<Option<ControllerType>, BlockingImplError<E>> {
66        let i2c_id = self.read_id()?;
67        Ok(crate::core::identify_controller(i2c_id))
68    }
69
70    /// tell the extension controller to prepare a sample by setting the read cursor to 0
71    pub(super) fn start_sample(&mut self) -> Result<(), BlockingImplError<E>> {
72        self.set_read_register_address(0x00)?;
73        Ok(())
74    }
75
76    /// tell the extension controller to prepare a sample by setting the read cursor to 0
77    pub(super) fn start_sample_and_wait(&mut self) -> Result<(), BlockingImplError<E>> {
78        self.set_read_register_address(0x00)?;
79        self.delay.delay_us(INTERMESSAGE_DELAY_MICROSEC);
80        Ok(())
81    }
82
83    /// Set the cursor position for the next i2c read
84    ///
85    /// This hardware has a range of 100 registers and automatically
86    /// increments the register read postion on each read operation, and also on
87    /// every write operation.
88    /// This should be called before a read operation to ensure you get the correct data
89    pub(super) fn set_read_register_address(
90        &mut self,
91        byte0: u8,
92    ) -> Result<(), BlockingImplError<E>> {
93        self.i2cdev
94            .write(EXT_I2C_ADDR as u8, &[byte0])
95            .map_err(BlockingImplError::I2C)
96            .and(Ok(()))
97    }
98
99    /// Set a single register at target address
100    pub(super) fn set_register(&mut self, addr: u8, byte1: u8) -> Result<(), BlockingImplError<E>> {
101        self.i2cdev
102            .write(EXT_I2C_ADDR as u8, &[addr, byte1])
103            .map_err(BlockingImplError::I2C)
104            .and(Ok(()))
105    }
106
107    /// Read the button/axis data from the classic controller
108    pub(super) fn read_report(&mut self) -> Result<ExtReport, BlockingImplError<E>> {
109        let mut buffer: ExtReport = ExtReport::default();
110        self.i2cdev
111            .read(EXT_I2C_ADDR as u8, &mut buffer)
112            .map_err(BlockingImplError::I2C)
113            .and(Ok(buffer))
114    }
115
116    pub(super) fn enable_hires(&mut self) -> Result<(), BlockingImplError<E>> {
117        self.delay.delay_us(INTERMESSAGE_DELAY_MICROSEC * 2);
118        self.set_register(0xFE, 0x03)?;
119        self.delay.delay_us(INTERMESSAGE_DELAY_MICROSEC * 2);
120        Ok(())
121    }
122
123    pub(super) fn disable_hires(&mut self) -> Result<(), BlockingImplError<E>> {
124        self.delay.delay_us(INTERMESSAGE_DELAY_MICROSEC * 2);
125        self.set_register(0xFE, 0x01)?;
126        self.delay.delay_us(INTERMESSAGE_DELAY_MICROSEC * 2);
127        Ok(())
128    }
129
130    /// Read a high-resolution version of the button/axis data from the classic controller
131    pub(super) fn read_hd_report(&mut self) -> Result<ExtHdReport, BlockingImplError<E>> {
132        let mut buffer: ExtHdReport = ExtHdReport::default();
133        self.i2cdev
134            .read(EXT_I2C_ADDR as u8, &mut buffer)
135            .map_err(BlockingImplError::I2C)
136            .and(Ok(buffer))
137    }
138}