Skip to content

Commit

Permalink
Move Delay into struct instead of taking by ref (#8)
Browse files Browse the repository at this point in the history
* Store delay in classic-sync struct
* Fix tests
  • Loading branch information
9names authored Apr 14, 2024
1 parent 8c87207 commit 976316a
Show file tree
Hide file tree
Showing 8 changed files with 91 additions and 95 deletions.
12 changes: 6 additions & 6 deletions examples/rp2040-hal-blocking/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ use panic_probe as _;
use bsp::hal::{
self, clocks::init_clocks_and_plls, entry, gpio, pac, sio::Sio, watchdog::Watchdog, Timer,
};
use embedded_hal::delay::DelayNs;
use fugit::RateExtU32;
use rp_pico as bsp;
use wii_ext::classic_sync::Classic;
use embedded_hal::delay::DelayNs;

#[entry]
fn main() -> ! {
Expand Down Expand Up @@ -59,14 +59,14 @@ fn main() -> ! {
);

// Create, initialise and calibrate the controller
let mut controller = Classic::new(i2c, &mut delay).unwrap();
let mut controller = Classic::new(i2c, delay).unwrap();

let hi_res = false;

// Enable hi-resolution mode. This also updates calibration
// Don't really need it for this single stick mode. Plus it might make recovery easier...
if hi_res {
controller.enable_hires(&mut delay).unwrap();
controller.enable_hires().unwrap();
}

// If you have a Nunchuk controller, use this instead.
Expand All @@ -76,15 +76,15 @@ fn main() -> ! {
delay.delay_ms(10);

// Capture the current button and axis values
let input = controller.read_blocking(&mut delay);
let input = controller.read_blocking();
if let Ok(input) = input {
// Print inputs from the controller
debug!("{:?}", input);
} else {
// re-init controller on failure
let _ = controller.init(&mut delay);
let _ = controller.init();
if hi_res {
let _ = controller.enable_hires(&mut delay);
let _ = controller.enable_hires();
}
}
}
Expand Down
60 changes: 28 additions & 32 deletions wii-ext/src/classic_sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ use crate::ExtHdReport;
use crate::ExtReport;
use crate::EXT_I2C_ADDR;
use crate::INTERMESSAGE_DELAY_MICROSEC_U32 as INTERMESSAGE_DELAY_MICROSEC;
use embedded_hal::delay::DelayNs;
use embedded_hal::i2c::I2c;

#[cfg(feature = "defmt_print")]
Expand All @@ -41,38 +40,41 @@ pub enum Error<E> {
InvalidInputData,
}

pub struct Classic<I2C> {
pub struct Classic<I2C, DELAY> {
i2cdev: I2C,
hires: bool,
calibration: CalibrationData,
delay: DELAY,
}

// use crate::nunchuk;
impl<T, E> Classic<T>
impl<T, E, DELAY> Classic<T, DELAY>
where
T: I2c<SevenBitAddress, Error = E>,
DELAY: embedded_hal::delay::DelayNs,
{
/// Create a new Wii Nunchuck
///
/// This method will open the provide i2c device file and will
/// send the required init sequence in order to read data in
/// the future.
pub fn new<D: DelayNs>(i2cdev: T, delay: &mut D) -> Result<Classic<T>, Error<E>> {
pub fn new(i2cdev: T, delay: DELAY) -> Result<Classic<T, DELAY>, Error<E>> {
let mut classic = Classic {
i2cdev,
hires: false,
calibration: CalibrationData::default(),
delay,
};
classic.init(delay)?;
classic.init()?;
Ok(classic)
}

/// Update the stored calibration for this controller
///
/// Since each device will have different tolerances, we take a snapshot of some analog data
/// to use as the "baseline" center.
pub fn update_calibration<D: DelayNs>(&mut self, delay: &mut D) -> Result<(), Error<E>> {
let data = self.read_report_blocking(delay)?;
pub fn update_calibration(&mut self) -> Result<(), Error<E>> {
let data = self.read_report_blocking()?;

self.calibration = CalibrationData {
joystick_left_x: data.joystick_left_x,
Expand Down Expand Up @@ -127,22 +129,22 @@ where
/// Send the init sequence to the Wii extension controller
///
/// This could be a bit faster with DelayNs, but since you only init once we'll re-use delay_ms
pub fn init<D: DelayNs>(&mut self, delay: &mut D) -> Result<(), Error<E>> {
pub fn init(&mut self) -> Result<(), Error<E>> {
// Extension controllers by default will use encrypted communication, as that is what the Wii does.
// We can disable this encryption by writing some magic values
// This is described at https://wiibrew.org/wiki/Wiimote/Extension_Controllers#The_New_Way

// 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
delay.delay_us(INTERMESSAGE_DELAY_MICROSEC * 2);
self.delay.delay_us(INTERMESSAGE_DELAY_MICROSEC * 2);
self.set_read_register_address(0)?;
delay.delay_us(INTERMESSAGE_DELAY_MICROSEC * 2);
self.delay.delay_us(INTERMESSAGE_DELAY_MICROSEC * 2);
self.set_register(0xF0, 0x55)?;
delay.delay_us(INTERMESSAGE_DELAY_MICROSEC * 2);
self.delay.delay_us(INTERMESSAGE_DELAY_MICROSEC * 2);
self.set_register(0xFB, 0x00)?;
delay.delay_us(INTERMESSAGE_DELAY_MICROSEC * 2);
self.update_calibration(delay)?;
delay.delay_us(INTERMESSAGE_DELAY_MICROSEC * 2);
self.delay.delay_us(INTERMESSAGE_DELAY_MICROSEC * 2);
self.update_calibration()?;
self.delay.delay_us(INTERMESSAGE_DELAY_MICROSEC * 2);
Ok(())
}

Expand All @@ -151,12 +153,12 @@ where
/// 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 fn enable_hires<D: DelayNs>(&mut self, delay: &mut D) -> Result<(), Error<E>> {
delay.delay_us(INTERMESSAGE_DELAY_MICROSEC * 2);
pub fn enable_hires(&mut self) -> Result<(), Error<E>> {
self.delay.delay_us(INTERMESSAGE_DELAY_MICROSEC * 2);
self.set_register(0xFE, 0x03)?;
delay.delay_us(INTERMESSAGE_DELAY_MICROSEC * 2);
self.delay.delay_us(INTERMESSAGE_DELAY_MICROSEC * 2);
self.hires = true;
self.update_calibration(delay)?;
self.update_calibration()?;
Ok(())
}

Expand All @@ -169,12 +171,12 @@ where
/// This function does not work.
/// TODO: work out why, make it public when it works
#[allow(dead_code)]
fn disable_hires<D: DelayNs>(&mut self, delay: &mut D) -> Result<(), Error<E>> {
delay.delay_us(INTERMESSAGE_DELAY_MICROSEC * 2);
fn disable_hires(&mut self) -> Result<(), Error<E>> {
self.delay.delay_us(INTERMESSAGE_DELAY_MICROSEC * 2);
self.set_register(0xFE, 0x01)?;
delay.delay_us(INTERMESSAGE_DELAY_MICROSEC * 2);
self.delay.delay_us(INTERMESSAGE_DELAY_MICROSEC * 2);
self.hires = false;
self.update_calibration(delay)?;
self.update_calibration()?;
Ok(())
}

Expand Down Expand Up @@ -213,22 +215,16 @@ where
}

/// Simple blocking read helper that will start a sample, wait 10ms, then read the value
pub fn read_report_blocking<D: DelayNs>(
&mut self,
delay: &mut D,
) -> Result<ClassicReading, Error<E>> {
pub fn read_report_blocking(&mut self) -> Result<ClassicReading, Error<E>> {
self.start_sample()?;
delay.delay_us(INTERMESSAGE_DELAY_MICROSEC);
self.delay.delay_us(INTERMESSAGE_DELAY_MICROSEC);
self.read_classic_report()
}

/// Do a read, and report axis values relative to calibration
pub fn read_blocking<D: DelayNs>(
&mut self,
delay: &mut D,
) -> Result<ClassicReadingCalibrated, Error<E>> {
pub fn read_blocking(&mut self) -> Result<ClassicReadingCalibrated, Error<E>> {
Ok(ClassicReadingCalibrated::new(
self.read_report_blocking(delay)?,
self.read_report_blocking()?,
&self.calibration,
))
}
Expand Down
8 changes: 4 additions & 4 deletions wii-ext/tests/classic_hd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,10 @@ macro_rules! assert_joystick_hd {
Transaction::read(EXT_I2C_ADDR as u8, test_data::$y.to_vec()),
];
let mut i2c = i2c::Mock::new(&expectations);
let mut delay = NoopDelay::new();
let mut classic = Classic::new(i2c.clone(), &mut delay).unwrap();
classic.enable_hires(&mut delay).unwrap();
let input = classic.read_blocking(&mut delay).unwrap();
let delay = NoopDelay::new();
let mut classic = Classic::new(i2c.clone(), delay).unwrap();
classic.enable_hires().unwrap();
let input = classic.read_blocking().unwrap();

assert!(
($lxl..=$lxh).contains(&input.joystick_left_x),
Expand Down
30 changes: 15 additions & 15 deletions wii-ext/tests/classic_pdp_clone.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@ fn classic_idle() {
];

let mut i2c = i2c::Mock::new(&expectations);
let mut delay = NoopDelay::new();
let mut classic = Classic::new(i2c.clone(), &mut delay).unwrap();
let report = classic.read_report_blocking(&mut delay).unwrap();
let delay = NoopDelay::new();
let mut classic = Classic::new(i2c.clone(), delay).unwrap();
let report = classic.read_report_blocking().unwrap();
assert_digital_eq(report, ClassicReading::default());
i2c.done();
}
Expand Down Expand Up @@ -99,9 +99,9 @@ macro_rules! assert_button_fn {
Transaction::read(EXT_I2C_ADDR as u8, $y.to_vec()),
];
let mut i2c = i2c::Mock::new(&expectations);
let mut delay = NoopDelay::new();
let mut classic = Classic::new(i2c.clone(), &mut delay).unwrap();
let input = classic.read_report_blocking(&mut delay).unwrap();
let delay = NoopDelay::new();
let mut classic = Classic::new(i2c.clone(), delay).unwrap();
let input = classic.read_report_blocking().unwrap();
assert_digital_eq(input, ClassicReading {
$x: true,
..Default::default()
Expand Down Expand Up @@ -146,9 +146,9 @@ fn classic_calibrated_idle() {
Transaction::read(EXT_I2C_ADDR as u8, test_data::PDP_LINK_IDLE.to_vec()),
];
let mut i2c = i2c::Mock::new(&expectations);
let mut delay = NoopDelay::new();
let mut classic = Classic::new(i2c.clone(), &mut delay).unwrap();
let input = classic.read_blocking(&mut delay).unwrap();
let delay = NoopDelay::new();
let mut classic = Classic::new(i2c.clone(), delay).unwrap();
let input = classic.read_blocking().unwrap();
assert_eq!(input.joystick_left_x, 0);
assert_eq!(input.joystick_left_y, 0);
assert_eq!(input.joystick_right_x, 0);
Expand All @@ -173,9 +173,9 @@ fn classic_calibrated_joy_left() {
Transaction::read(EXT_I2C_ADDR as u8, test_data::PDP_LINK_LJOY_L.to_vec()),
];
let mut i2c = i2c::Mock::new(&expectations);
let mut delay = NoopDelay::new();
let mut classic = Classic::new(i2c.clone(), &mut delay).unwrap();
let input = classic.read_blocking(&mut delay).unwrap();
let delay = NoopDelay::new();
let mut classic = Classic::new(i2c.clone(), delay).unwrap();
let input = classic.read_blocking().unwrap();

assert!(
(i8::MIN..-AXIS_MAX).contains(&input.joystick_left_x),
Expand Down Expand Up @@ -236,9 +236,9 @@ macro_rules! assert_joysticks {
Transaction::read(EXT_I2C_ADDR as u8, test_data::$y.to_vec()),
];
let mut i2c = i2c::Mock::new(&expectations);
let mut delay = NoopDelay::new();
let mut classic = Classic::new(i2c.clone(), &mut delay).unwrap();
let input = classic.read_blocking(&mut delay).unwrap();
let delay = NoopDelay::new();
let mut classic = Classic::new(i2c.clone(), delay).unwrap();
let input = classic.read_blocking().unwrap();

assert!(
($lxl..=$lxh).contains(&input.joystick_left_x),
Expand Down
8 changes: 4 additions & 4 deletions wii-ext/tests/classic_pdp_clone_hd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,10 @@ macro_rules! assert_joystick_hd {
Transaction::read(EXT_I2C_ADDR as u8, test_data::$y.to_vec()),
];
let mut i2c = i2c::Mock::new(&expectations);
let mut delay = NoopDelay::new();
let mut classic = Classic::new(i2c.clone(), &mut delay).unwrap();
classic.enable_hires(&mut delay).unwrap();
let input = classic.read_blocking(&mut delay).unwrap();
let delay = NoopDelay::new();
let mut classic = Classic::new(i2c.clone(), delay).unwrap();
classic.enable_hires().unwrap();
let input = classic.read_blocking().unwrap();

assert!(
($lxl..=$lxh).contains(&input.joystick_left_x),
Expand Down
30 changes: 15 additions & 15 deletions wii-ext/tests/classic_pro.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@ fn classic_idle() {
];

let mut i2c = i2c::Mock::new(&expectations);
let mut delay = NoopDelay::new();
let mut classic = Classic::new(i2c.clone(), &mut delay).unwrap();
let report = classic.read_report_blocking(&mut delay).unwrap();
let delay = NoopDelay::new();
let mut classic = Classic::new(i2c.clone(), delay).unwrap();
let report = classic.read_report_blocking().unwrap();
assert_digital_eq(report, ClassicReading::default());
i2c.done();
}
Expand Down Expand Up @@ -99,9 +99,9 @@ macro_rules! assert_button_fn {
Transaction::read(EXT_I2C_ADDR as u8, $y.to_vec()),
];
let mut i2c = i2c::Mock::new(&expectations);
let mut delay = NoopDelay::new();
let mut classic = Classic::new(i2c.clone(), &mut delay).unwrap();
let input = classic.read_report_blocking(&mut delay).unwrap();
let delay = NoopDelay::new();
let mut classic = Classic::new(i2c.clone(), delay).unwrap();
let input = classic.read_report_blocking().unwrap();
assert_digital_eq(input, ClassicReading {
$x: true,
..Default::default()
Expand Down Expand Up @@ -146,9 +146,9 @@ fn classic_calibrated_idle() {
Transaction::read(EXT_I2C_ADDR as u8, test_data::PRO_IDLE.to_vec()),
];
let mut i2c = i2c::Mock::new(&expectations);
let mut delay = NoopDelay::new();
let mut classic = Classic::new(i2c.clone(), &mut delay).unwrap();
let input = classic.read_blocking(&mut delay).unwrap();
let delay = NoopDelay::new();
let mut classic = Classic::new(i2c.clone(), delay).unwrap();
let input = classic.read_blocking().unwrap();
assert_eq!(input.joystick_left_x, 0);
assert_eq!(input.joystick_left_y, 0);
assert_eq!(input.joystick_right_x, 0);
Expand All @@ -173,9 +173,9 @@ fn classic_calibrated_joy_left() {
Transaction::read(EXT_I2C_ADDR as u8, test_data::PRO_LJOY_L.to_vec()),
];
let mut i2c = i2c::Mock::new(&expectations);
let mut delay = NoopDelay::new();
let mut classic = Classic::new(i2c.clone(), &mut delay).unwrap();
let input = classic.read_blocking(&mut delay).unwrap();
let delay = NoopDelay::new();
let mut classic = Classic::new(i2c.clone(), delay).unwrap();
let input = classic.read_blocking().unwrap();

assert!(
(i8::MIN..-AXIS_MAX).contains(&input.joystick_left_x),
Expand Down Expand Up @@ -237,9 +237,9 @@ macro_rules! assert_joysticks {
Transaction::read(EXT_I2C_ADDR as u8, test_data::$y.to_vec()),
];
let mut i2c = i2c::Mock::new(&expectations);
let mut delay = NoopDelay::new();
let mut classic = Classic::new(i2c.clone(), &mut delay).unwrap();
let input = classic.read_blocking(&mut delay).unwrap();
let delay = NoopDelay::new();
let mut classic = Classic::new(i2c.clone(), delay).unwrap();
let input = classic.read_blocking().unwrap();

assert!(
($lxl..=$lxh).contains(&input.joystick_left_x),
Expand Down
8 changes: 4 additions & 4 deletions wii-ext/tests/classic_pro_hd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,10 @@ macro_rules! assert_joystick_hd {
Transaction::read(EXT_I2C_ADDR as u8, test_data::$y.to_vec()),
];
let mut i2c = i2c::Mock::new(&expectations);
let mut delay = NoopDelay::new();
let mut classic = Classic::new(i2c.clone(), &mut delay).unwrap();
classic.enable_hires(&mut delay).unwrap();
let input = classic.read_blocking(&mut delay).unwrap();
let delay = NoopDelay::new();
let mut classic = Classic::new(i2c.clone(), delay).unwrap();
classic.enable_hires().unwrap();
let input = classic.read_blocking().unwrap();

assert!(
($lxl..=$lxh).contains(&input.joystick_left_x),
Expand Down
Loading

0 comments on commit 976316a

Please sign in to comment.