wii_ext/blocking_impl/
classic.rs

1use crate::blocking_impl::interface::{BlockingImplError, Interface};
2use crate::core::classic::{CalibrationData, ClassicReading, ClassicReadingCalibrated};
3use crate::core::ControllerType;
4use embedded_hal::i2c::I2c;
5
6#[cfg(feature = "defmt_print")]
7use defmt;
8use embedded_hal::i2c::SevenBitAddress;
9
10#[cfg_attr(feature = "defmt_print", derive(defmt::Format))]
11#[derive(Debug)]
12pub enum ClassicError<E> {
13    Error(E),
14    ParseError,
15}
16
17#[cfg_attr(feature = "defmt_print", derive(defmt::Format))]
18#[derive(Debug, Default)]
19pub struct Classic<I2C, DELAY> {
20    interface: Interface<I2C, DELAY>,
21    hires: bool,
22    calibration: CalibrationData,
23}
24
25impl<T, E, DELAY> Classic<T, DELAY>
26where
27    T: I2c<SevenBitAddress, Error = E>,
28    DELAY: embedded_hal::delay::DelayNs,
29{
30    /// Create a new Wii Classic Controller
31    pub fn new(i2cdev: T, delay: DELAY) -> Result<Classic<T, DELAY>, BlockingImplError<E>> {
32        let interface = Interface::new(i2cdev, delay);
33        let mut classic = Classic {
34            interface,
35            hires: false,
36            calibration: CalibrationData::default(),
37        };
38        classic.init()?;
39        Ok(classic)
40    }
41
42    /// Destroy this driver, recovering the i2c bus and delay used to create it
43    pub fn destroy(self) -> (T, DELAY) {
44        self.interface.destroy()
45    }
46
47    /// Update the stored calibration for this controller
48    ///
49    /// Since each device will have different tolerances, we take a snapshot of some analog data
50    /// to use as the "baseline" center.
51    pub fn update_calibration(&mut self) -> Result<(), BlockingImplError<E>> {
52        let data = self.read_uncalibrated()?;
53
54        self.calibration = CalibrationData {
55            joystick_left_x: data.joystick_left_x,
56            joystick_left_y: data.joystick_left_y,
57            joystick_right_x: data.joystick_right_x,
58            joystick_right_y: data.joystick_right_y,
59            trigger_left: data.trigger_left,
60            trigger_right: data.trigger_left,
61        };
62        Ok(())
63    }
64
65    /// Send the init sequence to the controller
66    pub fn init(&mut self) -> Result<(), BlockingImplError<E>> {
67        self.interface.init()?;
68        self.update_calibration()?;
69        Ok(())
70    }
71
72    /// Switch the driver from standard to hi-resolution reporting
73    ///
74    /// This enables the controllers high-resolution report data mode, which returns each
75    /// analogue axis as a u8, rather than packing smaller integers in a structure.
76    /// If your controllers supports this mode, you should use it. It is much better.
77    pub fn enable_hires(&mut self) -> Result<(), BlockingImplError<E>> {
78        self.interface.enable_hires()?;
79        self.hires = true;
80        self.update_calibration()?;
81        Ok(())
82    }
83
84    /// Switch the driver from hi-resolution to standard reporting reporting
85    ///
86    /// This disables the controllers high-resolution report data mode
87    /// It is assumed that all controllers use 0x01 as the 'standard' mode.
88    /// This has only been confirmed for classic and pro-classic controller.
89    ///
90    /// This function does not work.
91    /// TODO: work out why, make it public when it works
92    #[allow(dead_code)]
93    fn disable_hires(&mut self) -> Result<(), BlockingImplError<E>> {
94        self.interface.disable_hires()?;
95        self.hires = false;
96        self.update_calibration()?;
97        Ok(())
98    }
99
100    /// Determine the controller type based on the type ID of the extension controller
101    pub fn identify_controller(&mut self) -> Result<Option<ControllerType>, BlockingImplError<E>> {
102        self.interface.identify_controller()
103    }
104
105    /// Do a read, and return button and axis values without applying calibration
106    pub fn read_uncalibrated(&mut self) -> Result<ClassicReading, BlockingImplError<E>> {
107        self.interface.start_sample_and_wait()?;
108        if self.hires {
109            let buf = self.interface.read_hd_report()?;
110            ClassicReading::from_data(&buf).ok_or(BlockingImplError::InvalidInputData)
111        } else {
112            let buf = self.interface.read_report()?;
113            ClassicReading::from_data(&buf).ok_or(BlockingImplError::InvalidInputData)
114        }
115    }
116
117    /// Do a read, and return button and axis values relative to calibration
118    pub fn read(&mut self) -> Result<ClassicReadingCalibrated, BlockingImplError<E>> {
119        Ok(ClassicReadingCalibrated::new(
120            self.read_uncalibrated()?,
121            &self.calibration,
122        ))
123    }
124}