use crate::{ serial::{Commands, Serial}, MouseInfoSender, }; use rp_pico as bsp; use bsp::{ hal::{ clocks::ClocksManager, pac, pac::{interrupt, Interrupt}, rom_data::reset_to_usb_boot, usb::UsbBus, }, pac::{RESETS, USBCTRL_DPRAM, USBCTRL_REGS}, }; use usb_device::{class_prelude::*, prelude::*}; use usbd_hid::descriptor::MouseReport; static mut USB_BUS: Option> = None; static mut USB_SERIAL: Option = None; static mut USB_DEVICE: Option> = None; pub fn serial() -> &'static mut Serial<'static> { unsafe { USB_SERIAL.as_mut().unwrap() } } pub struct CustomHID { c: u32, } impl CustomHID { pub fn new( usbctrl_reg: USBCTRL_REGS, usbctrl_dpram: USBCTRL_DPRAM, resets: &mut RESETS, clocks: ClocksManager, poll_ms: u8, ) -> Self { // Set up the USB driver unsafe { USB_BUS = Some(UsbBusAllocator::new(UsbBus::new( usbctrl_reg, usbctrl_dpram, clocks.usb_clock, true, resets, ))) }; unsafe { USB_SERIAL = Some(Serial::new(USB_BUS.as_ref().unwrap())); } unsafe { USB_DEVICE = Some( UsbDeviceBuilder::new(USB_BUS.as_ref().unwrap(), UsbVidPid(0x16c0, 0x27dd)) .manufacturer("Fake company") .product("Serial port") .serial_number("TEST") .device_class(2) // from: https://www.usb.org/defined-class-codes .build(), ); } unsafe { pac::NVIC::unmask(Interrupt::USBCTRL_IRQ); pac::NVIC::unmask(Interrupt::SW0_IRQ); }; Self { c: 0 } } pub fn serial(&mut self, mut f: F) where F: FnMut(&mut Serial), { critical_section::with(|_| { f(serial()); }) } } impl MouseInfoSender for CustomHID { fn send(&mut self, x: i8, y: i8, buttons: u8, wheel: i8, pan: i8) { push_mouse_movement(MouseReport { x, y, buttons, wheel, pan, }) } fn heart_beat(&mut self) { self.c += 1; if self.c == 1_000_000 { self.c = 0; if !(pac::NVIC::is_pending(Interrupt::SW0_IRQ)) { pac::NVIC::pend(Interrupt::SW0_IRQ); } } } } /// with interrupts disabled, to avoid a race hazard with the USB IRQ. fn push_mouse_movement(report: MouseReport) { critical_section::with(|_| { let serial = serial(); serial.send_text("x"); serial.send_number(report.x, 10); serial.send_text("y"); serial.send_number(report.y, 10); }); } #[allow(non_snake_case)] #[interrupt] unsafe fn USBCTRL_IRQ() { // Handle USB request let usb_dev = USB_DEVICE.as_mut().unwrap(); let usb_hid = serial(); if usb_dev.poll(&mut [usb_hid]) { if let Some(command) = usb_hid.read() { match command { Commands::Reset => reset_to_usb_boot(0, 0), } } } } #[allow(non_snake_case)] #[interrupt] unsafe fn SW0_IRQ() { serial().send_text("heartbeat (IRQ)"); }