#![no_std] #![no_main] use panic_halt as _; use common::{handle_input, Handshake, UnsafeSync}; use core::cell::RefCell; use cortex_m::{asm::delay as cycle_delay, interrupt::Mutex, peripheral::NVIC}; use once_cell::unsync::OnceCell; use rp2040_hal::{ pac::{interrupt, Interrupt, Peripherals}, usb::UsbBus, Sio, Watchdog, }; use usb_device::{class_prelude::*, prelude::*}; use usbd_serial::{SerialPort, USB_CLASS_CDC}; mod bsp; mod buttons; mod device_signature; use bsp::{entry, Pins}; use buttons::Buttons; static USB_ALLOCATOR: UnsafeSync>> = UnsafeSync::new(OnceCell::new()); // static RTC_COUNT: Mutex>>> = Mutex::new(RefCell::new(None)); static USB_BUS: Mutex>>> = Mutex::new(RefCell::new(None)); static USB_SERIAL: Mutex>>> = Mutex::new(RefCell::new(None)); static HANDSHAKE: Mutex> = Mutex::new(RefCell::new(Handshake::new())); fn get_current_time() -> u32 { unimplemented!() } fn is_handshake_complete() -> bool { cortex_m::interrupt::free(|cs| HANDSHAKE.borrow(cs).borrow().is_complete()) } #[entry] fn main() -> ! { let mut peripherals = Peripherals::take().unwrap(); let mut watchdog = Watchdog::new(peripherals.WATCHDOG); let clocks = rp2040_hal::clocks::init_clocks_and_plls( bsp::XOSC_CRYSTAL_FREQ, peripherals.XOSC, peripherals.CLOCKS, peripherals.PLL_SYS, peripherals.PLL_USB, &mut peripherals.RESETS, &mut watchdog, ) .ok() .unwrap(); let sio = Sio::new(peripherals.SIO); let pins = Pins::new( peripherals.IO_BANK0, peripherals.PADS_BANK0, sio.gpio_bank0, &mut peripherals.RESETS, ); let usb_allocator = UsbBusAllocator::new(UsbBus::new( peripherals.USBCTRL_REGS, peripherals.USBCTRL_DPRAM, clocks.usb_clock, true, &mut peripherals.RESETS, )); // SAFETY: No interrupt will access USB_ALLOCATOR before this point, since it is only // referenced from inside the USB_SERIAL mutex and the USB_BUS mutex, which have not been set // yet. // // SAFETY: This is the only line of the program that modifies USB_ALLOCATOR let allocator = unsafe { USB_ALLOCATOR.get().set(usb_allocator).ok().unwrap(); USB_ALLOCATOR.get().get().unwrap() }; cortex_m::interrupt::free(|cs| { let serial = USB_SERIAL.borrow(cs); let mut serial = serial.borrow_mut(); *serial = Some(SerialPort::new(allocator)); }); cortex_m::interrupt::free(|cs| { let bus = USB_BUS.borrow(cs); let mut bus = bus.borrow_mut(); *bus = Some( UsbDeviceBuilder::new(allocator, UsbVidPid(0x16c0, 0x27dd)) .manufacturer("Aode Lion") .product("Pico Streamdeck") .serial_number("AAAB") .device_class(USB_CLASS_CDC) .build(), ); }); unsafe { NVIC::unmask(Interrupt::USBCTRL_IRQ); } let mut buttons = Buttons { d0: pins.gpio0, d1: pins.gpio1, d2: pins.gpio2, d3: pins.gpio3, d4: pins.gpio4, } .init(); loop { let current_time = get_current_time(); if !is_handshake_complete() { cycle_delay(1024 * 15); continue; } if let Some(byte) = buttons.tick(current_time) { let _ = cortex_m::interrupt::free(|cs| { let mut serial = USB_SERIAL.borrow(cs).borrow_mut(); let serial = serial.as_mut().unwrap(); let _ = serial.write(&[byte])?; serial.flush() }); } } } #[allow(non_snake_case)] #[interrupt] fn USBCTRL_IRQ() { poll_usb(); } fn poll_usb() -> Option<()> { let ready = cortex_m::interrupt::free(|cs1| { cortex_m::interrupt::free(|cs2| { let mut usb_dev = USB_BUS.borrow(cs1).borrow_mut(); let usb_dev = usb_dev.as_mut()?; let mut serial = USB_SERIAL.borrow(cs2).borrow_mut(); let serial = serial.as_mut()?; Some(usb_dev.poll(&mut [&mut *serial])) }) })?; if !ready { return Some(()); } let mut input = [0u8; 32]; let count = cortex_m::interrupt::free(|cs| { USB_SERIAL .borrow(cs) .borrow_mut() .as_mut()? .read(&mut input) .ok() })?; let current_time = get_current_time(); cortex_m::interrupt::free(|cs| { let mut handshake = HANDSHAKE.borrow(cs).borrow_mut(); if count == 32 && handshake.perform(&input, current_time, &mut Device)? { return None; } let is_complete = handshake.is_complete(); if !is_complete { return None; } Some(()) })?; handle_input(&mut Device, &input, count)?; Some(()) } struct Device; impl common::Device<8, 1> for Device { fn serial_number(&mut self) -> [u8; 8] { device_signature::read_uid() } fn write(&mut self, bytes: &[u8]) -> Option<()> { cortex_m::interrupt::free(|cs| { let mut serial = USB_SERIAL.borrow(cs).borrow_mut(); let serial = serial.as_mut()?; serial.write(bytes).ok()?; serial.flush().ok() }) } fn extras() -> [(&'static str, &'static str); 1] { [("version", env!("FIRMWARE_VERSION"))] } fn reset(&mut self) { cortex_m::interrupt::disable(); rp2040_hal::rom_data::reset_to_usb_boot(0, 0); } }