diff --git a/.vscode/settings.json b/.vscode/settings.json index 3accdc5..731e42e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -8,4 +8,5 @@ "rust-analyzer.cargo.features": [ "serial" ], + "rust-analyzer.showUnlinkedFileNotification": false, } \ No newline at end of file diff --git a/src/mouse_sensor/mod.rs b/src/mouse_sensor/mod.rs new file mode 100644 index 0000000..1657c58 --- /dev/null +++ b/src/mouse_sensor/mod.rs @@ -0,0 +1,4 @@ +mod spi_interface; +mod wrapper; + +pub use wrapper::MouseSensor; diff --git a/src/mouse_sensor.rs b/src/mouse_sensor/spi_interface.rs similarity index 58% rename from src/mouse_sensor.rs rename to src/mouse_sensor/spi_interface.rs index 96519db..84ab4ff 100644 --- a/src/mouse_sensor.rs +++ b/src/mouse_sensor/spi_interface.rs @@ -6,34 +6,34 @@ use fugit::{HertzU32, MegahertzU32}; use rp_pico::{ hal::{ gpio::{ - self, - bank0::{Gpio2, Gpio25, Gpio3, Gpio4, Gpio5}, - Function, Output, Pin, PushPull, PushPullOutput, Spi, + bank0::{Gpio2, Gpio3, Gpio4, Gpio5}, + Function, Output, Pin, PushPull, Spi, }, spi::{self, Enabled, Spi as SpiDevice}, }, pac::{RESETS, SPI0}, - Pins, }; -pub struct MouseSensor +pub struct SpiPins { + pub sclk: Pin>, + pub mosi: Pin>, + pub miso: Pin>, + pub cs: Pin>, +} + +pub struct SpiMouseSensor where L: FnMut(&str), { - _sclk: Pin>, - _mosi: Pin>, - _miso: Pin>, - cs: Pin>, - - led: Pin, + pins: SpiPins, spi: SpiDevice, delay: Delay, - log: L, + pub log: L, } -impl MouseSensor +impl SpiMouseSensor where L: FnMut(&str), { @@ -61,19 +61,13 @@ where const REG_SPI_MODE: u8 = 0x26; pub fn new( - pins: Pins, + mut pins: SpiPins, resets: &mut RESETS, spio: SPI0, peripheral_clock: impl Into, mut delay: Delay, mut log: L, ) -> Self { - // These are implicitly used by the spi driver if they are in the correct mode - let _sclk = pins.gpio2.into_mode::(); - let _mosi = pins.gpio3.into_mode::(); - let _miso = pins.gpio4.into_mode::(); - let mut cs = pins.gpio5.into_push_pull_output(); - // Create an SPI driver instance for the SPI0 device let spi = spi::Spi::<_, _, 8>::new(spio); @@ -85,59 +79,31 @@ where &embedded_hal::spi::MODE_2, ); - if let Err(_err) = cs.set_low() { + if let Err(_err) = pins.cs.set_low() { log("cs high failed"); } delay.delay_ms(2); - if let Err(_err) = cs.set_high() { + if let Err(_err) = pins.cs.set_high() { log("cs high failed"); } - let mut me = Self { - _sclk, - _mosi, - _miso, - cs, - - led: pins.led.into_push_pull_output(), + Self { + pins, spi, delay, log, - }; - - if me.led.set_high().is_err() { - (me.log)("led high failed"); } - - // verify initialization - loop { - if me.verify_product_id_1() { - break; - } - } - - loop { - if me.verify_product_id_2() { - break; - } - } - - if me.led.set_low().is_err() { - (me.log)("led low failed"); - } - - me } fn access(&mut self, f: F) -> T where F: Fn(&mut Self) -> T, { - if self.cs.set_low().is_err() { + if self.pins.cs.set_low().is_err() { (self.log)("cs low failed"); } @@ -145,7 +111,7 @@ where let res = f(self); - if self.cs.set_high().is_err() { + if self.pins.cs.set_high().is_err() { (self.log)("cs low failed"); } @@ -154,7 +120,7 @@ where res } - pub fn read(&mut self, address: u8) -> u8 { + fn read(&mut self, address: u8) -> u8 { loop { let res = self.access(|me| { if me.spi.send(address & Self::READ).is_err() { @@ -180,7 +146,7 @@ where } } - pub fn write(&mut self, address: u8, value: u8) { + fn write(&mut self, address: u8, value: u8) { self.access(|me| { if me.spi.send(address | Self::WRITE).is_err() { (me.log)("send address (write) failed"); @@ -191,24 +157,12 @@ where } }); } +} - pub fn read_movement(&mut self) -> Option<(i8, i8)> { - let (motion, x_overflow, y_overflow) = self.motion_detected(); - - if motion { - if x_overflow || y_overflow { - return None; - } - - let x = self.delta_x(); - let y = self.delta_y(); - - Some((x, y)) - } else { - None - } - } - +impl SpiMouseSensor +where + L: FnMut(&str), +{ pub fn delta_x(&mut self) -> i8 { unsafe { mem::transmute(self.read(Self::REG_DELTA_X)) } } @@ -217,16 +171,6 @@ where unsafe { mem::transmute(self.read(Self::REG_DELTA_Y)) } } - pub fn motion_detected(&mut self) -> (bool, bool, bool) { - let reg = self.read(Self::REG_MOTION_STATUS); - - let motion = (reg & 0b10000000) != 0; - let x_overflow = (reg & 0b00010000) != 0; - let y_overflow = (reg & 0b00001000) != 0; - - (motion, x_overflow, y_overflow) - } - pub fn product_id_1(&mut self) -> u8 { self.read(Self::REG_PRODUCT_ID1) } @@ -239,15 +183,7 @@ where self.read(Self::REG_OPERATION_MODE) } - fn verify_product_id_1(&mut self) -> bool { - const DEFAULT_VALUE: u8 = 0x30; - - DEFAULT_VALUE == self.product_id_1() - } - - fn verify_product_id_2(&mut self) -> bool { - const DEFAULT_VALUE: u8 = 0x02; - - DEFAULT_VALUE == self.product_id_2() + pub fn motion_status(&mut self) -> u8 { + self.read(Self::REG_MOTION_STATUS) } } diff --git a/src/mouse_sensor/wrapper.rs b/src/mouse_sensor/wrapper.rs new file mode 100644 index 0000000..39511b3 --- /dev/null +++ b/src/mouse_sensor/wrapper.rs @@ -0,0 +1,109 @@ +use super::spi_interface::{SpiMouseSensor, SpiPins}; + +use cortex_m::delay::Delay; +use embedded_hal::digital::v2::OutputPin; +use fugit::HertzU32; +use rp_pico::{ + hal::gpio::{self, bank0::Gpio25, Pin, PushPullOutput}, + pac::{RESETS, SPI0}, + Pins, +}; + +pub struct MouseSensor +where + L: FnMut(&str), +{ + spi_device: SpiMouseSensor, + + led: Pin, +} + +impl MouseSensor +where + L: FnMut(&str), +{ + pub fn new( + pins: Pins, + resets: &mut RESETS, + spio: SPI0, + peripheral_clock: impl Into, + delay: Delay, + log: L, + ) -> Self { + // These are implicitly used by the spi driver if they are in the correct mode + + let spi_pins = SpiPins { + sclk: pins.gpio2.into_mode::(), + mosi: pins.gpio3.into_mode::(), + miso: pins.gpio4.into_mode::(), + cs: pins.gpio5.into_push_pull_output(), + }; + + let led = pins.led.into_push_pull_output(); + let spi_device = SpiMouseSensor::new(spi_pins, resets, spio, peripheral_clock, delay, log); + + let mut me = Self { spi_device, led }; + + if me.led.set_high().is_err() { + (me.spi_device.log)("led high failed"); + } + + // verify initialization + loop { + if me.verify_product_id_1() { + break; + } + } + + loop { + if me.verify_product_id_2() { + break; + } + } + + if me.led.set_low().is_err() { + (me.spi_device.log)("led low failed"); + } + + me + } + + fn verify_product_id_1(&mut self) -> bool { + const DEFAULT_VALUE: u8 = 0x30; + + DEFAULT_VALUE == self.spi_device.product_id_1() + } + + fn verify_product_id_2(&mut self) -> bool { + const DEFAULT_VALUE: u8 = 0x02; + + DEFAULT_VALUE == self.spi_device.product_id_2() + } + + pub fn motion_detected(&mut self) -> (bool, bool, bool) { + let reg = self.spi_device.motion_status(); + + let motion = (reg & 0b10000000) != 0; + let x_overflow = (reg & 0b00010000) != 0; + let y_overflow = (reg & 0b00001000) != 0; + + (motion, x_overflow, y_overflow) + } + + pub fn read_movement(&mut self) -> Option<(i8, i8)> { + let (motion, x_overflow, y_overflow) = self.motion_detected(); + + if motion { + if x_overflow || y_overflow { + return None; + } + + let x = self.spi_device.delta_x(); + let y = self.spi_device.delta_y(); + + Some((x, y)) + } else { + None + } + } +}