diff --git a/examples/embassy-rp-async/.cargo/config.toml b/examples/embassy-rp-async/.cargo/config.toml new file mode 100644 index 0000000..cc2e7ca --- /dev/null +++ b/examples/embassy-rp-async/.cargo/config.toml @@ -0,0 +1,8 @@ +[target.'cfg(all(target_arch = "arm", target_os = "none"))'] +runner = "probe-rs run --chip RP2040 --protocol swd --speed 16000" + +[build] +target = "thumbv6m-none-eabi" # Cortex-M0 and Cortex-M0+ + +[env] +DEFMT_LOG = "debug" diff --git a/examples/embassy-rp-async/.vscode/launch.json b/examples/embassy-rp-async/.vscode/launch.json new file mode 100644 index 0000000..a29cac7 --- /dev/null +++ b/examples/embassy-rp-async/.vscode/launch.json @@ -0,0 +1,78 @@ +// The format of this file is specified in https://probe.rs/docs/tools/vscode/#start-a-debug-session-with-minimum-configuration +{ + "version": "0.2.0", + "configurations": [ + { + "preLaunchTask": "rust: cargo build", + "type": "probe-rs-debug", + "request": "launch", + "name": "embassy_rp_async launch", + "cwd": "${workspaceFolder}", + "chip": "rp2040", + // RP2040 doesn't support connectUnderReset + "connectUnderReset": false, + "speed": 4000, + "runtimeExecutable": "probe-rs", + "runtimeArgs": [ + "dap-server" + ], + "flashingConfig": { + "flashingEnabled": true, + "resetAfterFlashing": true, + "haltAfterReset": true, + }, + "coreConfigs": [ + { + "coreIndex": 0, + "programBinary": "target/thumbv6m-none-eabi/debug/embassy_rp_async", + "chip": "RP2040", + // Uncomment this if you've downloaded the SVD from + // https://github.com/raspberrypi/pico-sdk/raw/1.3.1/src/rp2040/hardware_regs/rp2040.svd + // and placed it in the .vscode directory + // "svdFile": "./.vscode/rp2040.svd", + "rttEnabled": true, + "options": { + "env": { + "DEFMT_LOG": "debug" + } + }, + } + ], + "consoleLogLevel": "Info", //Error, Warn, Info, Debug, Trace + "wireProtocol": "Swd" + }, + { + "type": "probe-rs-debug", + "request": "attach", + "name": "embassy_rp_async attach", + "cwd": "${workspaceFolder}", + "chip": "rp2040", + // RP2040 doesn't support connectUnderReset + "connectUnderReset": false, + "speed": 4000, + "runtimeExecutable": "probe-rs", + "runtimeArgs": [ + "dap-server" + ], + "coreConfigs": [ + { + "coreIndex": 0, + "programBinary": "target/thumbv6m-none-eabi/debug/embassy_rp_async", + "chip": "RP2040", + // Uncomment this if you've downloaded the SVD from + // https://github.com/raspberrypi/pico-sdk/raw/1.5.1/src/rp2040/hardware_regs/rp2040.svd + // and placed it in the .vscode directory + // "svdFile": "./.vscode/rp2040.svd", + "rttEnabled": true, + "options": { + "env": { + "DEFMT_LOG": "debug" + } + }, + } + ], + "consoleLogLevel": "Info", //Error, Warn, Info, Debug, Trace + "wireProtocol": "Swd" + } + ] +} \ No newline at end of file diff --git a/examples/embassy-rp-async/.vscode/settings.json b/examples/embassy-rp-async/.vscode/settings.json new file mode 100644 index 0000000..72cbfe4 --- /dev/null +++ b/examples/embassy-rp-async/.vscode/settings.json @@ -0,0 +1,6 @@ +{ + "rust-analyzer.cargo.target": "thumbv6m-none-eabi", + "rust-analyzer.check.allTargets": false, + "rust-analyzer.checkOnSave": false, + "editor.formatOnSave": true +} \ No newline at end of file diff --git a/examples/embassy-rp-async/Cargo.toml b/examples/embassy-rp-async/Cargo.toml new file mode 100644 index 0000000..9419473 --- /dev/null +++ b/examples/embassy-rp-async/Cargo.toml @@ -0,0 +1,97 @@ +[package] +edition = "2021" +name = "embassy_rp_async" +version = "0.1.0" +license = "MIT OR Apache-2.0" +resolver = "2" + + +[dependencies] +wii-ext = { version = "0.3.0", features = [ + "defmt_print", +], path = "../../wii-ext" } + +cortex-m = { version = "0.7.6", features = ["inline-asm"] } +cortex-m-rt = "0.7.0" + +defmt = "0.3" +defmt-rtt = "0.4" +panic-probe = { version = "0.3", features = ["print-defmt"] } + +embassy-embedded-hal = { version = "0.1.0", features = ["defmt"] } + +embassy-executor = { version = "0.5.0", features = [ + "arch-cortex-m", + "executor-thread", + "executor-interrupt", + "defmt", + "integrated-timers", + "task-arena-size-32768", +] } +embassy-futures = { version = "0.1.0" } +embassy-sync = { version = "0.5.0", features = ["defmt"] } +embassy-time = { version = "0.3.0", features = [ + "defmt", + "defmt-timestamp-uptime", +] } + +embassy-rp = { version = "0.1.0", features = [ + "defmt", + "unstable-pac", + "time-driver", + "critical-section-impl", +] } +portable-atomic = { version = "1.5.1", features = ["critical-section"] } + +# cargo build/run +[profile.dev] +codegen-units = 1 +debug = 2 +debug-assertions = true +incremental = false +opt-level = 1 +overflow-checks = true +lto = "off" + +# cargo build/run --release +[profile.release] +codegen-units = 1 +debug = 2 +debug-assertions = false +incremental = false +lto = true +opt-level = 's' +overflow-checks = false + +# do not optimize proc-macro crates = faster builds from scratch +[profile.dev.build-override] +codegen-units = 8 +debug = false +debug-assertions = false +opt-level = 0 +overflow-checks = false + +[profile.release.build-override] +codegen-units = 8 +debug = false +debug-assertions = false +opt-level = 0 +overflow-checks = false + +# cargo test +[profile.test] +codegen-units = 1 +debug = 2 +debug-assertions = true +incremental = false +opt-level = 's' +overflow-checks = true + +# cargo test --release +[profile.bench] +codegen-units = 1 +debug = 2 +debug-assertions = false +incremental = false +lto = true +opt-level = 's' diff --git a/examples/embassy-rp-async/build.rs b/examples/embassy-rp-async/build.rs new file mode 100644 index 0000000..3f915f9 --- /dev/null +++ b/examples/embassy-rp-async/build.rs @@ -0,0 +1,36 @@ +//! This build script copies the `memory.x` file from the crate root into +//! a directory where the linker can always find it at build time. +//! For many projects this is optional, as the linker always searches the +//! project root directory -- wherever `Cargo.toml` is. However, if you +//! are using a workspace or have a more complicated build setup, this +//! build script becomes required. Additionally, by requesting that +//! Cargo re-run the build script whenever `memory.x` is changed, +//! updating `memory.x` ensures a rebuild of the application with the +//! new memory settings. + +use std::env; +use std::fs::File; +use std::io::Write; +use std::path::PathBuf; + +fn main() { + // Put `memory.x` in our output directory and ensure it's + // on the linker search path. + let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); + File::create(out.join("memory.x")) + .unwrap() + .write_all(include_bytes!("memory.x")) + .unwrap(); + println!("cargo:rustc-link-search={}", out.display()); + + // By default, Cargo will re-run a build script whenever + // any file in the project changes. By specifying `memory.x` + // here, we ensure the build script is only re-run when + // `memory.x` is changed. + println!("cargo:rerun-if-changed=memory.x"); + + println!("cargo:rustc-link-arg-bins=--nmagic"); + println!("cargo:rustc-link-arg-bins=-Tlink.x"); + println!("cargo:rustc-link-arg-bins=-Tlink-rp.x"); + println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); +} diff --git a/examples/embassy-rp-async/memory.x b/examples/embassy-rp-async/memory.x new file mode 100644 index 0000000..aba861a --- /dev/null +++ b/examples/embassy-rp-async/memory.x @@ -0,0 +1,5 @@ +MEMORY { + BOOT2 : ORIGIN = 0x10000000, LENGTH = 0x100 + FLASH : ORIGIN = 0x10000100, LENGTH = 2048K - 0x100 + RAM : ORIGIN = 0x20000000, LENGTH = 256K +} \ No newline at end of file diff --git a/examples/embassy-rp-async/src/main.rs b/examples/embassy-rp-async/src/main.rs new file mode 100644 index 0000000..2fb1ee9 --- /dev/null +++ b/examples/embassy-rp-async/src/main.rs @@ -0,0 +1,84 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_rp::gpio; +use gpio::{Level, Output}; +use wii_ext::classic_async; +use {defmt_rtt as _, panic_probe as _}; + +use embassy_executor::Spawner; +use embassy_rp::bind_interrupts; +use embassy_rp::gpio::AnyPin; +use embassy_rp::i2c::{self, Config, InterruptHandler}; +use embassy_rp::peripherals::I2C0; +use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; +use embassy_sync::mutex::Mutex; +use embassy_time::{Delay, Duration, Ticker}; + +bind_interrupts!(struct Irqs { + I2C0_IRQ => InterruptHandler; +}); + +type LedType = Mutex>>; +static LED: LedType = Mutex::new(None); + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + info!("Program start"); + let p = embassy_rp::init(Default::default()); + + // Configure Pico LED to blink once a second + let led = Output::new(AnyPin::from(p.PIN_25), Level::High); + { + *(LED.lock().await) = Some(led); + } + unwrap!(spawner.spawn(toggle_led(&LED, Duration::from_millis(500)))); + + let sda = p.PIN_8; + let scl = p.PIN_9; + + info!("set up i2c"); + let i2c = i2c::I2c::new_async(p.I2C0, scl, sda, Irqs, Config::default()); + + // Create, initialise and calibrate the controller + info!("initialising controller"); + let mut controller = classic_async::ClassicAsync::new(i2c, Delay); + controller.init().await.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 { + info!("enabling hi-res mode"); + controller.enable_hires().await.unwrap(); + } + + info!("begin polling controller"); + loop { + let input = controller.read().await.unwrap(); + debug!("{:?}", input); + } +} + +#[embassy_executor::task(pool_size = 1)] +async fn toggle_led(led: &'static LedType, delay: Duration) { + let mut ticker = Ticker::every(delay); + loop { + { + let mut led_unlocked = led.lock().await; + if let Some(pin_ref) = led_unlocked.as_mut() { + pin_ref.toggle(); + } + } + ticker.next().await; + } +} + +#[cortex_m_rt::pre_init] +unsafe fn before_main() { + // Soft-reset doesn't clear spinlocks. Clear the one used by critical-section + // before we hit main to avoid deadlocks when using a debugger + embassy_rp::pac::SIO.spinlock(31).write_value(1); +} diff --git a/examples/rp2040-hal-blocking/src/main.rs b/examples/rp2040-hal-blocking/src/main.rs index 7144d7c..2797eaf 100644 --- a/examples/rp2040-hal-blocking/src/main.rs +++ b/examples/rp2040-hal-blocking/src/main.rs @@ -8,17 +8,17 @@ use defmt::*; use defmt_rtt as _; use panic_probe as _; -use rp_pico as bsp; use bsp::hal::{ self, - entry, clocks::{init_clocks_and_plls, Clock}, + entry, gpio::FunctionI2C, pac, sio::Sio, watchdog::Watchdog, }; use fugit::RateExtU32; +use rp_pico as bsp; use wii_ext::{classic_sync::Classic, core::classic::ClassicReadingCalibrated}; use usb_device::class_prelude::*; diff --git a/wii-ext/Cargo.toml b/wii-ext/Cargo.toml index d7d5321..6a248b1 100644 --- a/wii-ext/Cargo.toml +++ b/wii-ext/Cargo.toml @@ -8,17 +8,14 @@ repository = "https://github.com/9names/wii-ext-rs" license = "MIT OR Apache-2.0" [dependencies] -embedded-hal = { version = "0.2.5", features = ["unproven"] } +embedded-hal = "1" +embedded-hal-async = { version = "1"} defmt = { version = "0.3.0", optional = true } -embedded-hal-async = { version ="0.2.0-alpha.2", optional = true } -embassy-futures = { version ="0.1.0", optional = true } -embassy-time = { version ="0.1.1", optional = true } [dev-dependencies] -embedded-hal-mock = "0.8.0" +embedded-hal-mock = "0.10.0" paste = "1.0.6" [features] default = ["defmt_print"] defmt_print = ["defmt"] -async = ["embedded-hal-async", "embassy-futures", "embassy-time"] diff --git a/wii-ext/src/classic_async.rs b/wii-ext/src/classic_async.rs index 2346e4e..60c59bd 100644 --- a/wii-ext/src/classic_async.rs +++ b/wii-ext/src/classic_async.rs @@ -17,8 +17,7 @@ use crate::ExtHdReport; use crate::ExtReport; use crate::EXT_I2C_ADDR; use crate::INTERMESSAGE_DELAY_MICROSEC_U32; -use embassy_time::{Duration, Timer}; -use embedded_hal_async as hal; +use embedded_hal_async; // use core::future::Future; @@ -34,52 +33,54 @@ pub enum ClassicAsyncError { ParseError, } -pub struct ClassicAsync { +pub struct ClassicAsync { i2cdev: I2C, hires: bool, calibration: CalibrationData, + delay: Delay, } // use crate::nunchuk; -impl ClassicAsync +impl ClassicAsync where - I2C: hal::i2c::I2c, + I2C: embedded_hal_async::i2c::I2c, + Delay: embedded_hal_async::delay::DelayNs, { - pub type Error = ClassicAsyncError; /// 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(i2cdev: I2C) -> Self { + pub fn new(i2cdev: I2C, delay: Delay) -> Self { Self { i2cdev, hires: false, calibration: CalibrationData::default(), + delay, } } async fn delay_us(&mut self, micros: u32) { - Timer::after(Duration::from_micros(micros as _)).await + self.delay.delay_us(micros).await } /// Read the button/axis data from the classic controller - async fn read_ext_report(&mut self) -> Result { + async fn read_ext_report(&mut self) -> Result { let mut buffer: ExtReport = ExtReport::default(); self.i2cdev .read(EXT_I2C_ADDR as u8, &mut buffer) .await - .map_err(|_| Self::Error::I2C) + .map_err(|_| ClassicAsyncError::I2C) .and(Ok(buffer)) } /// Read a high-resolution version of the button/axis data from the classic controller - async fn read_hd_report(&mut self) -> Result { + async fn read_hd_report(&mut self) -> Result { let mut buffer: ExtHdReport = ExtHdReport::default(); self.i2cdev .read(EXT_I2C_ADDR as u8, &mut buffer) .await - .map_err(|_| Self::Error::I2C) + .map_err(|_| ClassicAsyncError::I2C) .and(Ok(buffer)) } @@ -87,7 +88,7 @@ where // / // / Since each device will have different tolerances, we take a snapshot of some analog data // / to use as the "baseline" center. - pub async fn update_calibration(&mut self) -> Result<(), Self::Error> { + pub async fn update_calibration(&mut self) -> Result<(), ClassicAsyncError> { let data = self.read_report().await?; self.calibration = CalibrationData { joystick_left_x: data.joystick_left_x, @@ -103,7 +104,7 @@ where /// Send the init sequence to the Wii extension controller /// /// This could be a bit faster with DelayUs, but since you only init once we'll re-use delay_ms - pub async fn init(&mut self) -> Result<(), Self::Error> { + pub async fn init(&mut self) -> Result<(), ClassicAsyncError> { // 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 @@ -124,7 +125,7 @@ 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 async fn enable_hires(&mut self) -> Result<(), Self::Error> { + pub async fn enable_hires(&mut self) -> Result<(), ClassicAsyncError> { self.set_register_with_delay(0xFE, 0x03).await?; self.hires = true; self.delay_us(100_000).await; @@ -138,72 +139,81 @@ where /// increments the register read postion on each read operation, and also on /// every write operation. /// This should be called before a read operation to ensure you get the correct data - async fn set_read_register_address(&mut self, byte0: u8) -> Result<(), Self::Error> { + async fn set_read_register_address(&mut self, byte0: u8) -> Result<(), ClassicAsyncError> { self.i2cdev .write(EXT_I2C_ADDR as u8, &[byte0]) .await - .map_err(|_| Self::Error::I2C) + .map_err(|_| ClassicAsyncError::I2C) .and(Ok(())) } - async fn set_read_register_address_with_delay(&mut self, byte0: u8) -> Result<(), Self::Error> { + async fn set_read_register_address_with_delay( + &mut self, + byte0: u8, + ) -> Result<(), ClassicAsyncError> { self.delay_us(INTERMESSAGE_DELAY_MICROSEC_U32).await; let res = self.set_read_register_address(byte0); res.await } /// Set a single register at target address - async fn set_register(&mut self, addr: u8, byte1: u8) -> Result<(), Self::Error> { + async fn set_register(&mut self, addr: u8, byte1: u8) -> Result<(), ClassicAsyncError> { self.i2cdev .write(EXT_I2C_ADDR as u8, &[addr, byte1]) .await - .map_err(|_| Self::Error::I2C) + .map_err(|_| ClassicAsyncError::I2C) .and(Ok(())) } - async fn set_register_with_delay(&mut self, addr: u8, byte1: u8) -> Result<(), Self::Error> { + async fn set_register_with_delay( + &mut self, + addr: u8, + byte1: u8, + ) -> Result<(), ClassicAsyncError> { self.delay_us(INTERMESSAGE_DELAY_MICROSEC_U32).await; let res = self.set_register(addr, byte1); res.await } - async fn read_id(&mut self) -> Result { + async fn read_id(&mut self) -> Result { self.set_read_register_address(0xfa).await?; let i2c_id = self.read_ext_report().await?; Ok(i2c_id) } - pub async fn identify_controller(&mut self) -> Result, Self::Error> { + pub async fn identify_controller( + &mut self, + ) -> Result, ClassicAsyncError> { let i2c_id = self.read_id().await?; Ok(crate::common::identify_controller(i2c_id)) } /// tell the extension controller to prepare a sample by setting the read cursor to 0 - async fn start_sample(&mut self) -> Result<(), Self::Error> { + async fn start_sample(&mut self) -> Result<(), ClassicAsyncError> { self.set_read_register_address(0x00).await?; Ok(()) } /// poll the controller for the latest data - async fn read_classic_report(&mut self) -> Result { + async fn read_classic_report(&mut self) -> Result { if self.hires { let buf = self.read_hd_report().await?; - ClassicReading::from_data(&buf).ok_or(Self::Error::InvalidInputData) + ClassicReading::from_data(&buf).ok_or(ClassicAsyncError::InvalidInputData) } else { let buf = self.read_ext_report().await?; - ClassicReading::from_data(&buf).ok_or(Self::Error::InvalidInputData) + ClassicReading::from_data(&buf).ok_or(ClassicAsyncError::InvalidInputData) } } /// Simple blocking read helper that will start a sample, wait 10ms, then read the value - async fn read_report(&mut self) -> Result { + async fn read_report(&mut self) -> Result { self.start_sample().await?; self.delay_us(INTERMESSAGE_DELAY_MICROSEC_U32).await; self.read_classic_report().await } /// Do a read, and report axis values relative to calibration - pub async fn read(&mut self) -> Result { + pub async fn read(&mut self) -> Result { Ok(ClassicReadingCalibrated::new( self.read_report().await?, &self.calibration, diff --git a/wii-ext/src/classic_sync.rs b/wii-ext/src/classic_sync.rs index dffeecd..9306875 100644 --- a/wii-ext/src/classic_sync.rs +++ b/wii-ext/src/classic_sync.rs @@ -16,12 +16,13 @@ use crate::ControllerType; use crate::ExtHdReport; use crate::ExtReport; use crate::EXT_I2C_ADDR; -use crate::INTERMESSAGE_DELAY_MICROSEC; -use embedded_hal::blocking::delay::DelayUs; -use embedded_hal::blocking::i2c as i2ctrait; +use crate::INTERMESSAGE_DELAY_MICROSEC_U32 as INTERMESSAGE_DELAY_MICROSEC; +use embedded_hal::delay::DelayNs; +use embedded_hal::i2c::I2c; #[cfg(feature = "defmt_print")] use defmt; +use embedded_hal::i2c::SevenBitAddress; #[cfg_attr(feature = "defmt_print", derive(defmt::Format))] #[derive(Debug)] @@ -49,14 +50,14 @@ pub struct Classic { // use crate::nunchuk; impl Classic where - T: i2ctrait::Write + i2ctrait::Read + i2ctrait::Write, + T: I2c, { /// 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>(i2cdev: T, delay: &mut D) -> Result, Error> { + pub fn new(i2cdev: T, delay: &mut D) -> Result, Error> { let mut classic = Classic { i2cdev, hires: false, @@ -70,7 +71,7 @@ where /// /// 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>(&mut self, delay: &mut D) -> Result<(), Error> { + pub fn update_calibration(&mut self, delay: &mut D) -> Result<(), Error> { let data = self.read_report_blocking(delay)?; self.calibration = CalibrationData { @@ -125,8 +126,8 @@ where /// Send the init sequence to the Wii extension controller /// - /// This could be a bit faster with DelayUs, but since you only init once we'll re-use delay_ms - pub fn init>(&mut self, delay: &mut D) -> Result<(), Error> { + /// This could be a bit faster with DelayNs, but since you only init once we'll re-use delay_ms + pub fn init(&mut self, delay: &mut D) -> Result<(), Error> { // 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 @@ -150,7 +151,7 @@ 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>(&mut self, delay: &mut D) -> Result<(), Error> { + pub fn enable_hires(&mut self, delay: &mut D) -> Result<(), Error> { delay.delay_us(INTERMESSAGE_DELAY_MICROSEC * 2); self.set_register(0xFE, 0x03)?; delay.delay_us(INTERMESSAGE_DELAY_MICROSEC * 2); @@ -168,7 +169,7 @@ where /// This function does not work. /// TODO: work out why, make it public when it works #[allow(dead_code)] - fn disable_hires>(&mut self, delay: &mut D) -> Result<(), Error> { + fn disable_hires(&mut self, delay: &mut D) -> Result<(), Error> { delay.delay_us(INTERMESSAGE_DELAY_MICROSEC * 2); self.set_register(0xFE, 0x01)?; delay.delay_us(INTERMESSAGE_DELAY_MICROSEC * 2); @@ -212,7 +213,7 @@ where } /// Simple blocking read helper that will start a sample, wait 10ms, then read the value - pub fn read_report_blocking>( + pub fn read_report_blocking( &mut self, delay: &mut D, ) -> Result> { @@ -222,7 +223,7 @@ where } /// Do a read, and report axis values relative to calibration - pub fn read_blocking>( + pub fn read_blocking( &mut self, delay: &mut D, ) -> Result> { diff --git a/wii-ext/src/common.rs b/wii-ext/src/common.rs index 7b1b835..ecf033a 100644 --- a/wii-ext/src/common.rs +++ b/wii-ext/src/common.rs @@ -19,7 +19,6 @@ pub const EXT_I2C_ADDR: u16 = 0x52; /// There needs to be some time between i2c messages or the /// wii ext device will abort the i2c transaction /// 200 microseconds works in my tests - need to test with more devices -pub const INTERMESSAGE_DELAY_MICROSEC: u16 = 200; pub const INTERMESSAGE_DELAY_MICROSEC_U32: u32 = 200; pub fn identify_controller(id: ControllerIdReport) -> Option { diff --git a/wii-ext/src/lib.rs b/wii-ext/src/lib.rs index 1a25f0f..567074e 100644 --- a/wii-ext/src/lib.rs +++ b/wii-ext/src/lib.rs @@ -1,13 +1,11 @@ #![cfg_attr(not(test), no_std)] -#![cfg_attr( - feature = "async", - feature(type_alias_impl_trait, inherent_associated_types) -)] -#[cfg(feature = "async")] -pub mod classic_async; + /// Blocking I2C impl pub mod classic_sync; +// Async I2C impl +pub mod classic_async; + /// Types + data decoding pub mod core; diff --git a/wii-ext/src/nunchuk.rs b/wii-ext/src/nunchuk.rs index 01365a5..f28705c 100644 --- a/wii-ext/src/nunchuk.rs +++ b/wii-ext/src/nunchuk.rs @@ -11,11 +11,12 @@ use crate::ControllerIdReport; use crate::ControllerType; use crate::ExtReport; use crate::EXT_I2C_ADDR; -use crate::INTERMESSAGE_DELAY_MICROSEC; -use embedded_hal::blocking::delay::DelayUs; +use crate::INTERMESSAGE_DELAY_MICROSEC_U32 as INTERMESSAGE_DELAY_MICROSEC; +use embedded_hal::delay::DelayNs; #[cfg(feature = "defmt_print")] use defmt; +use embedded_hal::i2c::{I2c, SevenBitAddress}; #[derive(Debug)] pub enum NunchukError { @@ -116,17 +117,16 @@ pub struct Nunchuk { calibration: CalibrationData, } -use embedded_hal::blocking::i2c as i2ctrait; impl Nunchuk where - T: i2ctrait::Write + i2ctrait::Read + i2ctrait::WriteRead, + T: I2c, { /// Create a new Wii Nunchuk /// /// 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>(i2cdev: T, delay: &mut D) -> Result, Error> { + pub fn new(i2cdev: T, delay: &mut D) -> Result, Error> { let mut nunchuk = Nunchuk { i2cdev, calibration: CalibrationData::default(), @@ -139,7 +139,7 @@ where /// /// 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>(&mut self, delay: &mut D) -> Result<(), Error> { + pub fn update_calibration(&mut self, delay: &mut D) -> Result<(), Error> { let data = self.read_report_blocking(delay)?; self.calibration = CalibrationData { @@ -170,7 +170,7 @@ where } /// Send the init sequence to the Wii extension controller - pub fn init>(&mut self, delay: &mut D) -> Result<(), Error> { + pub fn init(&mut self, delay: &mut D) -> Result<(), Error> { // These registers must be written to disable encryption.; the documentation is a bit // lacking but it appears this is some kind of handshake to // perform unencrypted data tranfers @@ -224,7 +224,7 @@ where } /// Simple blocking read helper that will start a sample, wait `INTERMESSAGE_DELAY_MICROSEC`, then read the value - pub fn read_report_blocking>( + pub fn read_report_blocking( &mut self, delay: &mut D, ) -> Result> { @@ -235,7 +235,7 @@ where } /// Do a read, and report axis values relative to calibration - pub fn read_blocking>( + pub fn read_blocking( &mut self, delay: &mut D, ) -> Result> { @@ -250,7 +250,7 @@ where mod tests { use super::*; use crate::test_data; - use embedded_hal_mock::i2c::{self, Transaction}; + use embedded_hal_mock::eh1::i2c::{self, Transaction}; /// There's a certain amount of slop around the center position. /// Allow up to this range without it being an error const ZERO_SLOP: i8 = 5; @@ -265,14 +265,15 @@ mod tests { Transaction::write(EXT_I2C_ADDR as u8, vec![0]), Transaction::read(EXT_I2C_ADDR as u8, test_data::NUNCHUCK_IDLE.to_vec()), ]; - let mock = i2c::Mock::new(&expectations); + let mut mock = i2c::Mock::new(&expectations); let mut nc = Nunchuk { - i2cdev: mock, + i2cdev: mock.clone(), calibration: CalibrationData::default(), }; let report = nc.read_no_wait().unwrap(); assert!(!report.button_c); assert!(!report.button_z); + mock.done(); } #[test] @@ -281,10 +282,10 @@ mod tests { Transaction::write(EXT_I2C_ADDR as u8, vec![0]), Transaction::read(EXT_I2C_ADDR as u8, test_data::NUNCHUCK_IDLE.to_vec()), ]; - let mock = i2c::Mock::new(&expectations); + let mut mock = i2c::Mock::new(&expectations); let idle = NunchukReading::from_data(&test_data::NUNCHUCK_IDLE).unwrap(); let mut nc = Nunchuk { - i2cdev: mock, + i2cdev: mock.clone(), calibration: CalibrationData { joystick_x: idle.joystick_x, joystick_y: idle.joystick_y, @@ -295,6 +296,7 @@ mod tests { assert!(!report.button_z); assert_eq!(report.joystick_x, 0); assert_eq!(report.joystick_y, 0); + mock.done(); } #[test] @@ -303,10 +305,10 @@ mod tests { Transaction::write(EXT_I2C_ADDR as u8, vec![0]), Transaction::read(EXT_I2C_ADDR as u8, test_data::NUNCHUCK_JOY_L.to_vec()), ]; - let mock = i2c::Mock::new(&expectations); + let mut mock = i2c::Mock::new(&expectations); let idle = NunchukReading::from_data(&test_data::NUNCHUCK_IDLE).unwrap(); let mut nc = Nunchuk { - i2cdev: mock, + i2cdev: mock.clone(), calibration: CalibrationData { joystick_x: idle.joystick_x, joystick_y: idle.joystick_y, @@ -318,6 +320,7 @@ mod tests { assert!(report.joystick_x < -AXIS_MAX, "x = {}", report.joystick_x); assert!(report.joystick_y > -ZERO_SLOP, "y = {}", report.joystick_y); assert!(report.joystick_y < ZERO_SLOP, "y = {}", report.joystick_y); + mock.done(); } #[test] @@ -326,10 +329,10 @@ mod tests { Transaction::write(EXT_I2C_ADDR as u8, vec![0]), Transaction::read(EXT_I2C_ADDR as u8, test_data::NUNCHUCK_JOY_R.to_vec()), ]; - let mock = i2c::Mock::new(&expectations); + let mut mock = i2c::Mock::new(&expectations); let idle = NunchukReading::from_data(&test_data::NUNCHUCK_IDLE).unwrap(); let mut nc = Nunchuk { - i2cdev: mock, + i2cdev: mock.clone(), calibration: CalibrationData { joystick_x: idle.joystick_x, joystick_y: idle.joystick_y, @@ -341,6 +344,7 @@ mod tests { assert!(report.joystick_x > AXIS_MAX, "x = {}", report.joystick_x); assert!(report.joystick_y > -ZERO_SLOP, "y = {}", report.joystick_y); assert!(report.joystick_y < ZERO_SLOP, "y = {}", report.joystick_y); + mock.done(); } #[test] @@ -349,10 +353,10 @@ mod tests { Transaction::write(EXT_I2C_ADDR as u8, vec![0]), Transaction::read(EXT_I2C_ADDR as u8, test_data::NUNCHUCK_JOY_U.to_vec()), ]; - let mock = i2c::Mock::new(&expectations); + let mut mock = i2c::Mock::new(&expectations); let idle = NunchukReading::from_data(&test_data::NUNCHUCK_IDLE).unwrap(); let mut nc = Nunchuk { - i2cdev: mock, + i2cdev: mock.clone(), calibration: CalibrationData { joystick_x: idle.joystick_x, joystick_y: idle.joystick_y, @@ -364,6 +368,7 @@ mod tests { assert!(report.joystick_y > AXIS_MAX, "y = {}", report.joystick_y); assert!(report.joystick_x > -ZERO_SLOP, "x = {}", report.joystick_x); assert!(report.joystick_x < ZERO_SLOP, "x = {}", report.joystick_x); + mock.done(); } #[test] @@ -372,10 +377,10 @@ mod tests { Transaction::write(EXT_I2C_ADDR as u8, vec![0]), Transaction::read(EXT_I2C_ADDR as u8, test_data::NUNCHUCK_JOY_D.to_vec()), ]; - let mock = i2c::Mock::new(&expectations); + let mut mock = i2c::Mock::new(&expectations); let idle = NunchukReading::from_data(&test_data::NUNCHUCK_IDLE).unwrap(); let mut nc = Nunchuk { - i2cdev: mock, + i2cdev: mock.clone(), calibration: CalibrationData { joystick_x: idle.joystick_x, joystick_y: idle.joystick_y, @@ -387,6 +392,7 @@ mod tests { assert!(report.joystick_y < -AXIS_MAX, "y = {}", report.joystick_y); assert!(report.joystick_x > -ZERO_SLOP, "x = {}", report.joystick_x); assert!(report.joystick_x < ZERO_SLOP, "x = {}", report.joystick_x); + mock.done(); } #[test] @@ -397,9 +403,9 @@ mod tests { Transaction::write(EXT_I2C_ADDR as u8, vec![0]), Transaction::read(EXT_I2C_ADDR as u8, test_data::NUNCHUCK_IDLE.to_vec()), ]; - let mock = i2c::Mock::new(&expectations); + let mut mock = i2c::Mock::new(&expectations); let mut nc = Nunchuk { - i2cdev: mock, + i2cdev: mock.clone(), calibration: CalibrationData::default(), }; let report = nc.read_no_wait().unwrap(); @@ -408,6 +414,7 @@ mod tests { let report = nc.read_no_wait().unwrap(); assert!(!report.button_c); assert!(!report.button_z); + mock.done(); } #[test] @@ -416,14 +423,15 @@ mod tests { Transaction::write(EXT_I2C_ADDR as u8, vec![0]), Transaction::read(EXT_I2C_ADDR as u8, test_data::NUNCHUCK_BTN_C.to_vec()), ]; - let mock = i2c::Mock::new(&expectations); + let mut mock = i2c::Mock::new(&expectations); let mut nc = Nunchuk { - i2cdev: mock, + i2cdev: mock.clone(), calibration: CalibrationData::default(), }; let report = nc.read_no_wait().unwrap(); assert!(report.button_c); assert!(!report.button_z); + mock.done(); } #[test] @@ -432,13 +440,14 @@ mod tests { Transaction::write(EXT_I2C_ADDR as u8, vec![0]), Transaction::read(EXT_I2C_ADDR as u8, test_data::NUNCHUCK_BTN_Z.to_vec()), ]; - let mock = i2c::Mock::new(&expectations); + let mut mock = i2c::Mock::new(&expectations); let mut nc = Nunchuk { - i2cdev: mock, + i2cdev: mock.clone(), calibration: CalibrationData::default(), }; let report = nc.read_no_wait().unwrap(); assert!(!report.button_c); assert!(report.button_z); + mock.done(); } } diff --git a/wii-ext/tests/classic_hd.rs b/wii-ext/tests/classic_hd.rs index 4b2b193..92912be 100644 --- a/wii-ext/tests/classic_hd.rs +++ b/wii-ext/tests/classic_hd.rs @@ -1,5 +1,5 @@ -use embedded_hal_mock::delay::MockNoop; -use embedded_hal_mock::i2c::{self, Transaction}; +use embedded_hal_mock::eh1::delay::NoopDelay; +use embedded_hal_mock::eh1::i2c::{self, Transaction}; use paste::paste; use wii_ext::classic_sync::*; use wii_ext::*; @@ -45,9 +45,9 @@ macro_rules! assert_joystick_hd { Transaction::write(EXT_I2C_ADDR as u8, vec![0]), Transaction::read(EXT_I2C_ADDR as u8, test_data::$y.to_vec()), ]; - let i2c = i2c::Mock::new(&expectations); - let mut delay = MockNoop::new(); - let mut classic = Classic::new(i2c, &mut delay).unwrap(); + 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(); @@ -93,6 +93,7 @@ macro_rules! assert_joystick_hd { $rtl, $rth ); + i2c.done(); } } }; diff --git a/wii-ext/tests/classic_pdp_clone.rs b/wii-ext/tests/classic_pdp_clone.rs index 630f52b..4d375c7 100644 --- a/wii-ext/tests/classic_pdp_clone.rs +++ b/wii-ext/tests/classic_pdp_clone.rs @@ -1,5 +1,5 @@ -use embedded_hal_mock::delay::MockNoop; -use embedded_hal_mock::i2c::{self, Transaction}; +use embedded_hal_mock::eh1::delay::NoopDelay; +use embedded_hal_mock::eh1::i2c::{self, Transaction}; use paste::paste; use wii_ext::classic_sync::*; use wii_ext::common::*; @@ -50,11 +50,12 @@ fn classic_idle() { Transaction::read(EXT_I2C_ADDR as u8, test_data::PDP_LINK_IDLE.to_vec()), ]; - let i2c = i2c::Mock::new(&expectations); - let mut delay = MockNoop::new(); - let mut classic = Classic::new(i2c, &mut delay).unwrap(); + 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(); assert_digital_eq(report, ClassicReading::default()); + i2c.done(); } // We don't want to write all that out for every digital button, so let's write a macro instead. @@ -97,14 +98,15 @@ macro_rules! assert_button_fn { Transaction::write(EXT_I2C_ADDR as u8, vec![0]), Transaction::read(EXT_I2C_ADDR as u8, $y.to_vec()), ]; - let i2c = i2c::Mock::new(&expectations); - let mut delay = MockNoop::new(); - let mut classic = Classic::new(i2c, &mut delay).unwrap(); + 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(); assert_digital_eq(input, ClassicReading { $x: true, ..Default::default() }); + i2c.done(); } } }; @@ -143,14 +145,15 @@ fn classic_calibrated_idle() { Transaction::write(EXT_I2C_ADDR as u8, vec![0]), Transaction::read(EXT_I2C_ADDR as u8, test_data::PDP_LINK_IDLE.to_vec()), ]; - let i2c = i2c::Mock::new(&expectations); - let mut delay = MockNoop::new(); - let mut classic = Classic::new(i2c, &mut delay).unwrap(); + 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(); assert_eq!(input.joystick_left_x, 0); assert_eq!(input.joystick_left_y, 0); assert_eq!(input.joystick_right_x, 0); assert_eq!(input.joystick_right_y, 0); + i2c.done(); } /// Test that no buttons are pressed when the controller is idle @@ -169,9 +172,9 @@ fn classic_calibrated_joy_left() { Transaction::write(EXT_I2C_ADDR as u8, vec![0]), Transaction::read(EXT_I2C_ADDR as u8, test_data::PDP_LINK_LJOY_L.to_vec()), ]; - let i2c = i2c::Mock::new(&expectations); - let mut delay = MockNoop::new(); - let mut classic = Classic::new(i2c, &mut delay).unwrap(); + 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(); assert!( @@ -204,6 +207,7 @@ fn classic_calibrated_joy_left() { "trigger_right = {}", input.trigger_right ); + i2c.done(); } macro_rules! assert_joysticks { @@ -231,9 +235,9 @@ macro_rules! assert_joysticks { Transaction::write(EXT_I2C_ADDR as u8, vec![0]), Transaction::read(EXT_I2C_ADDR as u8, test_data::$y.to_vec()), ]; - let i2c = i2c::Mock::new(&expectations); - let mut delay = MockNoop::new(); - let mut classic = Classic::new(i2c, &mut delay).unwrap(); + 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(); assert!( @@ -278,6 +282,7 @@ macro_rules! assert_joysticks { $rtl, $rth ); + i2c.done(); } } }; diff --git a/wii-ext/tests/classic_pdp_clone_hd.rs b/wii-ext/tests/classic_pdp_clone_hd.rs index cc49a63..dc8fbf4 100644 --- a/wii-ext/tests/classic_pdp_clone_hd.rs +++ b/wii-ext/tests/classic_pdp_clone_hd.rs @@ -1,5 +1,5 @@ -use embedded_hal_mock::delay::MockNoop; -use embedded_hal_mock::i2c::{self, Transaction}; +use embedded_hal_mock::eh1::delay::NoopDelay; +use embedded_hal_mock::eh1::i2c::{self, Transaction}; use paste::paste; use wii_ext::classic_sync::*; use wii_ext::*; @@ -45,9 +45,9 @@ macro_rules! assert_joystick_hd { Transaction::write(EXT_I2C_ADDR as u8, vec![0]), Transaction::read(EXT_I2C_ADDR as u8, test_data::$y.to_vec()), ]; - let i2c = i2c::Mock::new(&expectations); - let mut delay = MockNoop::new(); - let mut classic = Classic::new(i2c, &mut delay).unwrap(); + 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(); @@ -93,6 +93,7 @@ macro_rules! assert_joystick_hd { $rtl, $rth ); + i2c.done(); } } }; diff --git a/wii-ext/tests/classic_pro.rs b/wii-ext/tests/classic_pro.rs index f605a87..c1bb047 100644 --- a/wii-ext/tests/classic_pro.rs +++ b/wii-ext/tests/classic_pro.rs @@ -1,5 +1,5 @@ -use embedded_hal_mock::delay::MockNoop; -use embedded_hal_mock::i2c::{self, Transaction}; +use embedded_hal_mock::eh1::delay::NoopDelay; +use embedded_hal_mock::eh1::i2c::{self, Transaction}; use paste::paste; use wii_ext::classic_sync::*; use wii_ext::common::*; @@ -50,11 +50,12 @@ fn classic_idle() { Transaction::read(EXT_I2C_ADDR as u8, test_data::PRO_IDLE.to_vec()), ]; - let i2c = i2c::Mock::new(&expectations); - let mut delay = MockNoop::new(); - let mut classic = Classic::new(i2c, &mut delay).unwrap(); + 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(); assert_digital_eq(report, ClassicReading::default()); + i2c.done(); } // We don't want to write all that out for every digital button, so let's write a macro instead. @@ -97,14 +98,15 @@ macro_rules! assert_button_fn { Transaction::write(EXT_I2C_ADDR as u8, vec![0]), Transaction::read(EXT_I2C_ADDR as u8, $y.to_vec()), ]; - let i2c = i2c::Mock::new(&expectations); - let mut delay = MockNoop::new(); - let mut classic = Classic::new(i2c, &mut delay).unwrap(); + 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(); assert_digital_eq(input, ClassicReading { $x: true, ..Default::default() }); + i2c.done(); } } }; @@ -143,14 +145,15 @@ fn classic_calibrated_idle() { Transaction::write(EXT_I2C_ADDR as u8, vec![0]), Transaction::read(EXT_I2C_ADDR as u8, test_data::PRO_IDLE.to_vec()), ]; - let i2c = i2c::Mock::new(&expectations); - let mut delay = MockNoop::new(); - let mut classic = Classic::new(i2c, &mut delay).unwrap(); + 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(); assert_eq!(input.joystick_left_x, 0); assert_eq!(input.joystick_left_y, 0); assert_eq!(input.joystick_right_x, 0); assert_eq!(input.joystick_right_y, 0); + i2c.done(); } /// Test that no buttons are pressed when the controller is idle @@ -169,9 +172,9 @@ fn classic_calibrated_joy_left() { Transaction::write(EXT_I2C_ADDR as u8, vec![0]), Transaction::read(EXT_I2C_ADDR as u8, test_data::PRO_LJOY_L.to_vec()), ]; - let i2c = i2c::Mock::new(&expectations); - let mut delay = MockNoop::new(); - let mut classic = Classic::new(i2c, &mut delay).unwrap(); + 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(); assert!( @@ -204,6 +207,8 @@ fn classic_calibrated_joy_left() { "trigger_right = {}", input.trigger_right ); + let _ = classic; + i2c.done(); } macro_rules! assert_joysticks { @@ -231,9 +236,9 @@ macro_rules! assert_joysticks { Transaction::write(EXT_I2C_ADDR as u8, vec![0]), Transaction::read(EXT_I2C_ADDR as u8, test_data::$y.to_vec()), ]; - let i2c = i2c::Mock::new(&expectations); - let mut delay = MockNoop::new(); - let mut classic = Classic::new(i2c, &mut delay).unwrap(); + 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(); assert!( @@ -278,6 +283,7 @@ macro_rules! assert_joysticks { $rtl, $rth ); + i2c.done(); } } }; diff --git a/wii-ext/tests/classic_pro_hd.rs b/wii-ext/tests/classic_pro_hd.rs index 56fea17..0cb2bbf 100644 --- a/wii-ext/tests/classic_pro_hd.rs +++ b/wii-ext/tests/classic_pro_hd.rs @@ -1,5 +1,5 @@ -use embedded_hal_mock::delay::MockNoop; -use embedded_hal_mock::i2c::{self, Transaction}; +use embedded_hal_mock::eh1::delay::NoopDelay; +use embedded_hal_mock::eh1::i2c::{self, Transaction}; use paste::paste; use wii_ext::classic_sync::*; use wii_ext::*; @@ -45,9 +45,9 @@ macro_rules! assert_joystick_hd { Transaction::write(EXT_I2C_ADDR as u8, vec![0]), Transaction::read(EXT_I2C_ADDR as u8, test_data::$y.to_vec()), ]; - let i2c = i2c::Mock::new(&expectations); - let mut delay = MockNoop::new(); - let mut classic = Classic::new(i2c, &mut delay).unwrap(); + 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(); @@ -93,6 +93,7 @@ macro_rules! assert_joystick_hd { $rtl, $rth ); + i2c.done(); } } }; diff --git a/wii-ext/tests/classic_regular.rs b/wii-ext/tests/classic_regular.rs index 799cc9a..ba72ff4 100644 --- a/wii-ext/tests/classic_regular.rs +++ b/wii-ext/tests/classic_regular.rs @@ -1,5 +1,5 @@ -use embedded_hal_mock::delay::MockNoop; -use embedded_hal_mock::i2c::{self, Transaction}; +use embedded_hal_mock::eh1::delay::NoopDelay; +use embedded_hal_mock::eh1::i2c::{self, Transaction}; use paste::paste; use wii_ext::classic_sync::*; use wii_ext::common::*; @@ -48,11 +48,12 @@ fn classic_idle() { Transaction::read(EXT_I2C_ADDR as u8, test_data::CLASSIC_IDLE.to_vec()), ]; - let i2c = i2c::Mock::new(&expectations); - let mut delay = MockNoop::new(); - let mut classic = Classic::new(i2c, &mut delay).unwrap(); + 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(); assert_digital_eq(report, ClassicReading::default()); + i2c.done(); } // We don't want to write all that out for every digital button, so let's write a macro instead. @@ -95,14 +96,15 @@ macro_rules! assert_button_fn { Transaction::write(EXT_I2C_ADDR as u8, vec![0]), Transaction::read(EXT_I2C_ADDR as u8, $y.to_vec()), ]; - let i2c = i2c::Mock::new(&expectations); - let mut delay = MockNoop::new(); - let mut classic = Classic::new(i2c, &mut delay).unwrap(); + 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(); assert_digital_eq(input, ClassicReading { $x: true, ..Default::default() }); + i2c.done(); } } }; @@ -141,14 +143,15 @@ fn classic_calibrated_idle() { Transaction::write(EXT_I2C_ADDR as u8, vec![0]), Transaction::read(EXT_I2C_ADDR as u8, test_data::CLASSIC_IDLE.to_vec()), ]; - let i2c = i2c::Mock::new(&expectations); - let mut delay = MockNoop::new(); - let mut classic = Classic::new(i2c, &mut delay).unwrap(); + 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(); assert_eq!(input.joystick_left_x, 0); assert_eq!(input.joystick_left_y, 0); assert_eq!(input.joystick_right_x, 0); assert_eq!(input.joystick_right_y, 0); + i2c.done(); } /// Test that no buttons are pressed when the controller is idle @@ -170,9 +173,9 @@ fn classic_calibrated_joy_left() { Transaction::write(EXT_I2C_ADDR as u8, vec![0]), Transaction::read(EXT_I2C_ADDR as u8, test_data::CLASSIC_LJOY_L.to_vec()), ]; - let i2c = i2c::Mock::new(&expectations); - let mut delay = MockNoop::new(); - let mut classic = Classic::new(i2c, &mut delay).unwrap(); + 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(); assert!( @@ -205,6 +208,7 @@ fn classic_calibrated_joy_left() { "trigger_right = {}", input.trigger_right ); + i2c.done(); } macro_rules! assert_joysticks { @@ -232,9 +236,9 @@ macro_rules! assert_joysticks { Transaction::write(EXT_I2C_ADDR as u8, vec![0]), Transaction::read(EXT_I2C_ADDR as u8, test_data::$y.to_vec()), ]; - let i2c = i2c::Mock::new(&expectations); - let mut delay = MockNoop::new(); - let mut classic = Classic::new(i2c, &mut delay).unwrap(); + 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(); assert!( @@ -279,6 +283,7 @@ macro_rules! assert_joysticks { $rtl, $rth ); + i2c.done(); } } };