use core::{ fmt::{self, Write}, mem::MaybeUninit, }; use cortex_m::interrupt::free; use log::{Log, Metadata, Record}; use stm32f4xx_hal::{ otg_fs::{UsbBus as Bus, USB}, pac::{interrupt, Interrupt, NVIC}, }; use usb_device::{ descriptor::lang_id, device::StringDescriptors, class_prelude::UsbBusAllocator, prelude::{UsbDevice, UsbDeviceBuilder, UsbVidPid}, }; use usbd_serial::SerialPort; static mut EP_MEMORY: [u32; 1024] = [0; 1024]; static mut BUS: MaybeUninit>> = MaybeUninit::uninit(); // static mut SERIAL_DEV: Option<(SerialPort<'static, Bus>, UsbDevice<'static, Bus>)> = None; static mut STATE: Option = None; pub struct State { serial: SerialPort<'static, Bus>, dev: UsbDevice<'static, Bus>, } impl State { pub fn setup(usb: USB) { unsafe { BUS.write(Bus::new(usb, EP_MEMORY.as_mut())) }; let str_descriptor = StringDescriptors::new(lang_id::LangID::EN) .manufacturer("M-Labs") .product("Kirdy"); let bus = unsafe { BUS.assume_init_ref() }; let serial = SerialPort::new(bus); let dev = UsbDeviceBuilder::new(bus, UsbVidPid(0x16c0, 0x27dd)) .device_release(0x20) .self_powered(true) .device_class(usbd_serial::USB_CLASS_CDC) .strings(&[str_descriptor]).unwrap() .build(); free(|_| unsafe { STATE = Some(State { serial, dev }); }); unsafe { NVIC::unmask(Interrupt::OTG_FS); } } pub fn get() -> Option<&'static mut Self> { unsafe { STATE.as_mut() } } pub fn poll() { if let Some(ref mut s) = Self::get() { if s.dev.poll(&mut [&mut s.serial]) { // discard any input let mut buf = [0u8; 64]; let _ = s.serial.read(&mut buf); } } } } #[interrupt] fn OTG_FS() { free(|_| { State::poll(); }); } pub struct Logger; impl Log for Logger { fn enabled(&self, _: &Metadata) -> bool { true } fn log(&self, record: &Record) { if self.enabled(record.metadata()) { let mut output = SerialOutput; let _ = writeln!(&mut output, "{} - {}", record.level(), record.args()); } } fn flush(&self) { if let Some(ref mut state) = State::get() { let _ = free(|_| state.serial.flush()); } } } pub struct SerialOutput; impl Write for SerialOutput { fn write_str(&mut self, s: &str) -> core::result::Result<(), core::fmt::Error> { if let Some(ref mut state) = State::get() { for chunk in s.as_bytes().chunks(16) { free(|_| state.serial.write(chunk)).map_err(|_| fmt::Error)?; } } Ok(()) } }