mod serial_config; use numtoa::NumToA; use core::future::Future; use embassy_rp::usb::Driver; use embassy_rp::{interrupt, peripherals::USB}; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::{Builder, Config, UsbDevice}; pub use serial_config::SerialConfig; static mut DEVICE_DESCRIPTOR_BUFFER: [u8; 256] = [0; 256]; static mut CONFIG_DESCRIPTOR_BUFFER: [u8; 256] = [0; 256]; static mut BOS_DESCRIPTOR_BUFFER: [u8; 256] = [0; 256]; static mut MSOS_DESCRIPTOR_BUFFER: [u8; 256] = [0; 256]; static mut CONTROL_BUFFER: [u8; 64] = [0; 64]; static mut STATE: Option> = None; static mut USB: Option>> = None; pub trait Sender { async fn send_msg(&mut self, msg: &str); async fn send_number(&mut self, i: T, base: I) where T: NumToA; } pub struct Serial<'a> { class: CdcAcmClass<'a, Driver<'a, USB>>, } impl Serial<'static> { pub async fn new( usb: USB, serial_config: SerialConfig<'static>, ) -> (Serial<'static>, impl Future) { // Create the driver, from the HAL. let irq = interrupt::take!(USBCTRL_IRQ); let driver = Driver::new(usb, irq); // Create embassy-usb Config let mut config = Config::new( serial_config.vendor_id as u16, serial_config.product_id as u16, ); config.manufacturer = Some(serial_config.manufacturer); config.product = Some(serial_config.product); config.serial_number = Some(serial_config.serial_number); config.max_power = 100; config.max_packet_size_0 = 64; // Required for windows compatiblity. // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help config.device_class = 0xEF; config.device_sub_class = 0x02; config.device_protocol = 0x01; config.composite_with_iads = true; unsafe { STATE = Some(State::new()); } let mut builder = Builder::new( driver, config, unsafe { &mut DEVICE_DESCRIPTOR_BUFFER }, unsafe { &mut CONFIG_DESCRIPTOR_BUFFER }, unsafe { &mut BOS_DESCRIPTOR_BUFFER }, unsafe { &mut MSOS_DESCRIPTOR_BUFFER }, unsafe { &mut CONTROL_BUFFER }, ); // Create classes on the builder. let class = CdcAcmClass::new(&mut builder, unsafe { STATE.as_mut().unwrap() }, 64); // Build the builder. unsafe { USB = Some(builder.build()); }; (Self { class }, Self::run_usb().await) } async fn run_usb() -> impl Future { unsafe { USB.as_mut().unwrap().run() } } pub async fn send_msg(&mut self, s: &str) { self.class.write_packet(s.as_bytes()).await.unwrap_or(()); } pub async fn send_number(&mut self, i: T, base: I) where T: NumToA, { let mut buf = [0; 256]; let s = i.numtoa_str(base, &mut buf); self.send_msg(s).await; } } impl Sender for Serial<'static> { async fn send_msg(&mut self, msg: &str) { self.send_msg(msg).await; } async fn send_number(&mut self, i: T, base: I) where T: NumToA, { self.send_number(i, base).await; } }