wii_ext/blocking_impl/
nunchuk.rs

1use crate::blocking_impl::interface::{BlockingImplError, Interface};
2use crate::core::nunchuk::{CalibrationData, NunchukReading, NunchukReadingCalibrated};
3use crate::core::ControllerType;
4use embedded_hal::i2c::{I2c, SevenBitAddress};
5
6#[derive(Debug)]
7pub enum NunchukError<E> {
8    Error(E),
9    ParseError,
10}
11
12pub struct Nunchuk<I2C, DELAY> {
13    interface: Interface<I2C, DELAY>,
14    calibration: CalibrationData,
15}
16
17impl<I2C, ERR, DELAY> Nunchuk<I2C, DELAY>
18where
19    I2C: I2c<SevenBitAddress, Error = ERR>,
20    DELAY: embedded_hal::delay::DelayNs,
21{
22    /// Create a new Wii Nunchuk
23    pub fn new(i2cdev: I2C, delay: DELAY) -> Result<Nunchuk<I2C, DELAY>, BlockingImplError<ERR>> {
24        let interface = Interface::new(i2cdev, delay);
25        let mut nunchuk = Nunchuk {
26            interface,
27            calibration: CalibrationData::default(),
28        };
29        nunchuk.init()?;
30        Ok(nunchuk)
31    }
32
33    /// Destroy this driver, recovering the i2c bus and delay used to create it
34    pub fn destroy(self) -> (I2C, DELAY) {
35        self.interface.destroy()
36    }
37
38    /// Update the stored calibration for this controller
39    ///
40    /// Since each device will have different tolerances, we take a snapshot of some analog data
41    /// to use as the "baseline" center.
42    pub fn update_calibration(&mut self) -> Result<(), BlockingImplError<ERR>> {
43        let data = self.read_uncalibrated()?;
44
45        self.calibration = CalibrationData {
46            joystick_x: data.joystick_x,
47            joystick_y: data.joystick_y,
48        };
49        Ok(())
50    }
51
52    /// Send the init sequence to the Nunchuk
53    pub fn init(&mut self) -> Result<(), BlockingImplError<ERR>> {
54        self.interface.init()?;
55        self.update_calibration()
56    }
57
58    /// Determine the controller type based on the type ID of the extension controller
59    pub fn identify_controller(
60        &mut self,
61    ) -> Result<Option<ControllerType>, BlockingImplError<ERR>> {
62        self.interface.identify_controller()
63    }
64
65    /// Do a read, and return button and axis values without applying calibration
66    pub fn read_uncalibrated(&mut self) -> Result<NunchukReading, BlockingImplError<ERR>> {
67        self.interface.start_sample()?;
68        let buf = self.interface.read_report()?;
69        NunchukReading::from_data(&buf).ok_or(BlockingImplError::InvalidInputData)
70    }
71
72    /// Do a read, and return button and axis values relative to calibration
73    pub fn read(&mut self) -> Result<NunchukReadingCalibrated, BlockingImplError<ERR>> {
74        Ok(NunchukReadingCalibrated::new(
75            self.read_uncalibrated()?,
76            &self.calibration,
77        ))
78    }
79}