#![no_std] #![no_main] extern crate panic_halt; use core::cell::RefCell; use cortex_m::delay::Delay; use cortex_m::singleton; use adafruit_feather_rp2040 as board; use board::{entry, Pins}; use board::hal::{self, Clock, clocks, Sio, usb, watchdog}; use board::hal::pac::{self, interrupt, Peripherals, CorePeripherals}; use critical_section::Mutex; use ehal::serial::Write; use embedded_hal as ehal; use usb_device::{class_prelude::*, prelude::*}; use usbd_serial::SerialPort; static SERIAL: Mutex>>> = Mutex::new(RefCell::new(None)); static USB_DEV: Mutex>>> = Mutex::new(RefCell::new(None)); struct Serial(()); impl Serial { pub fn new(usb_bus: usb::UsbBus) -> Self { let usb_alloc = singleton!(: UsbBusAllocator = UsbBusAllocator::new(usb_bus)).unwrap(); // Set up the USB Communications Class Device driver let serial = SerialPort::new(usb_alloc); // Create a USB device with a fake VID and PID let usb_dev = UsbDeviceBuilder::new(usb_alloc, UsbVidPid(0x16c0, 0x27dd)) .manufacturer("Fake company") .product("Serial port") .serial_number("TEST") .device_class(2) // from: https://www.usb.org/defined-class-codes .build(); critical_section::with(|cs| { *SERIAL.borrow(cs).borrow_mut() = Some(serial); *USB_DEV.borrow(cs).borrow_mut() = Some(usb_dev); }); Self(()) } } impl ehal::serial::Write for Serial { fn write(&mut self, mut buffer: &[u8]) -> Result<(), Self::Error> { loop { match critical_section::with(|cs| { SERIAL.borrow(cs).borrow_mut().as_mut().unwrap().write(buffer) }) { Err(UsbError::WouldBlock) => {}, Ok(cnt) => { buffer = &buffer[cnt..]; if buffer.is_empty() { return Ok(()) } } Err(_) => { return Err(ehal::serial::ErrorKind::Other); } } } } fn flush(&mut self) -> Result<(), Self::Error> { critical_section::with(|cs| { SERIAL.borrow(cs).borrow_mut().as_mut().unwrap().flush() }).map_err(|_| ehal::serial::ErrorKind::Other) } } impl ehal::serial::ErrorType for Serial { type Error = ehal::serial::ErrorKind; } #[entry] fn main() -> ! { // SAFETY: Single-threaded, except for USB Peripheral, for which // will be annotated w/ reasons why it's safe :). let mut pac = unsafe { Peripherals::steal() }; let core = CorePeripherals::take().unwrap(); let mut watchdog = watchdog::Watchdog::new(pac.WATCHDOG); let clocks = clocks::init_clocks_and_plls( board::XOSC_CRYSTAL_FREQ, pac.XOSC, pac.CLOCKS, pac.PLL_SYS, pac.PLL_USB, &mut pac.RESETS, &mut watchdog, ) .ok() .unwrap(); let mut delay = cortex_m::delay::Delay::new(core.SYST, clocks.system_clock.freq().to_Hz()); let sio = Sio::new(pac.SIO); let pins = Pins::new( pac.IO_BANK0, pac.PADS_BANK0, sio.gpio_bank0, &mut pac.RESETS, ); let usb = usb::UsbBus::new( pac.USBCTRL_REGS, pac.USBCTRL_DPRAM, clocks.usb_clock, true, &mut pac.RESETS, ); let mut ser = Serial::new(usb); // Safety: We are not in a context where interrupts are assumed to be // disabled (although if we got here, the USB interrupt is mostly // likely disabled, barring additional unsafe). unsafe { pac::NVIC::unmask(hal::pac::Interrupt::USBCTRL_IRQ); } delay.delay_ms(2000); let msg = b"qwertyuiop[]\\asdfghjkl;'zxcvbnm,./\nThe quick brown fox jumps over the lazy dog. `1234567890-=. ~!@#$%^&*()_+.\nQWERTYUIOP{}|ASDFGHJKL:\"ZXCVNM<>?\n\n"; // ser.write(msg).unwrap(); loop { ser.write(msg).unwrap(); delay.delay_ms(500); } } #[interrupt] fn USBCTRL_IRQ() { critical_section::with(|cs| { let mut ser_ref = SERIAL.borrow(cs).borrow_mut(); let mut dev_ref = USB_DEV.borrow(cs).borrow_mut(); let serial = ser_ref.as_mut().unwrap(); let usb_dev = dev_ref.as_mut().unwrap(); usb_dev.poll(&mut [serial]); }); }