From e55af0616d30384f216131aef3ec2e3a0bed8aea Mon Sep 17 00:00:00 2001 From: hodasemi Date: Tue, 31 Jan 2023 10:46:10 +0100 Subject: [PATCH] Implement twitching mouse --- Cargo.toml | 5 ++- src/main.rs | 114 +++++++++++++++++++++++++++++++++++++++------------- 2 files changed, 91 insertions(+), 28 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b25cbd0..8d2fb62 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,4 +10,7 @@ cortex-m = "0.7.2" cortex-m-rt = "0.7.2" rp-pico = "0.6.0" panic-halt = "0.2.0" -defmt = "0.3.0" \ No newline at end of file +defmt = "0.3.0" +usb-device = "0.2.9" +usbd-hid = "0.6.1" +critical-section = "1.1.1" \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 54383b0..3943b80 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,19 +5,35 @@ // be linked) use panic_halt as _; -// Pull in any important traits -use rp_pico::{ +use rp_pico as bsp; + +use bsp::{ entry, - hal::{self, pac, prelude::*}, + hal::{ + self, pac, + pac::{interrupt, Interrupt}, + prelude::*, + usb::UsbBus, + }, }; -/// Entry point to our bare-metal application. -/// -/// The `#[entry]` macro ensures the Cortex-M start-up code calls this function -/// as soon as all global variables are initialised. -/// -/// The function configures the RP2040 peripherals, then blinks the LED in an -/// infinite loop. +use cortex_m::delay::Delay; + +use usb_device::{class_prelude::*, prelude::*}; +use usbd_hid::{ + descriptor::{MouseReport, SerializedDescriptor}, + hid_class::HIDClass, +}; + +/// The USB Device Driver (shared with the interrupt). +static mut USB_DEVICE: Option> = None; + +/// The USB Bus Driver (shared with the interrupt). +static mut USB_BUS: Option> = None; + +/// The USB Human Interface Device Driver (shared with the interrupt). +static mut USB_HID: Option> = None; + #[entry] fn main() -> ! { // Grab our singleton objects @@ -42,26 +58,70 @@ fn main() -> ! { .ok() .unwrap(); - // The delay object lets us wait for specified amounts of time (in - // milliseconds) - let mut delay = cortex_m::delay::Delay::new(core.SYST, clocks.system_clock.freq().to_Hz()); + unsafe { + USB_BUS = Some(UsbBusAllocator::new(UsbBus::new( + pac.USBCTRL_REGS, + pac.USBCTRL_DPRAM, + clocks.usb_clock, + true, + &mut pac.RESETS, + ))) + }; - // The single-cycle I/O block controls our GPIO pins - let sio = hal::Sio::new(pac.SIO); + unsafe { + USB_HID = Some(HIDClass::new( + USB_BUS.as_ref().unwrap(), + MouseReport::desc(), + 60, + )); + } - // Set the pins up according to their function on this particular board - let pins = rp_pico::Pins::new( - pac.IO_BANK0, - pac.PADS_BANK0, - sio.gpio_bank0, - &mut pac.RESETS, - ); + unsafe { + USB_DEVICE = Some( + UsbDeviceBuilder::new(USB_BUS.as_ref().unwrap(), UsbVidPid(0x046d, 0x101b)) + .manufacturer("Logitech") + .product("Marathon Mouse/Performance Plus M705") + .serial_number("B14D65DA") + .build(), + ); + } - // Set the LED to be an output - let mut led_pin = pins.led.into_push_pull_output(); + unsafe { + pac::NVIC::unmask(Interrupt::USBCTRL_IRQ); + } - // Blink the LED at 1 Hz - loop {} + let mut delay = Delay::new(core.SYST, clocks.system_clock.freq().to_Hz()); + + loop { + mouse_move(&mut delay, 4); + mouse_move(&mut delay, -4); + } } -// End of file +fn mouse_move(delay: &mut Delay, v: i8) { + delay.delay_ms(100); + + let rep = MouseReport { + x: 0, + y: v, + buttons: 0, + wheel: 0, + pan: 0, + }; + push_mouse_movement(rep).unwrap_or(0); +} + +/// with interrupts disabled, to avoid a race hazard with the USB IRQ. +fn push_mouse_movement(report: MouseReport) -> Result { + critical_section::with(|_| unsafe { USB_HID.as_mut().map(|hid| hid.push_input(&report)) }) + .unwrap() +} + +#[allow(non_snake_case)] +#[interrupt] +unsafe fn USBCTRL_IRQ() { + // Handle USB request + let usb_dev = USB_DEVICE.as_mut().unwrap(); + let usb_hid = USB_HID.as_mut().unwrap(); + usb_dev.poll(&mut [usb_hid]); +}