use defmt::{info, error}; use embassy_executor::Spawner; use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; use embassy_stm32::usb::Driver; use embassy_stm32::{peripherals, uid, usb}; use postcard_rpc::{ define_dispatch, header::VarHeader, server::{ impls::embassy_usb_v0_4::{ dispatch_impl::{WireRxBuf, WireRxImpl, WireSpawnImpl, WireStorage, WireTxImpl}, PacketBuffers, }, Dispatch, Server, }, }; use bioz_icd_rs::{PingEndpoint, GetUniqueIdEndpoint, ENDPOINT_LIST, TOPICS_IN_LIST, TOPICS_OUT_LIST}; pub struct Context { pub unique_id: [u8; 12], } type AppDriver = usb::Driver<'static, peripherals::USB>; type AppStorage = WireStorage; type BufStorage = PacketBuffers<1024, 1024>; type AppTx = WireTxImpl; type AppRx = WireRxImpl; type AppServer = Server; use static_cell::ConstStaticCell; static PBUFS: ConstStaticCell = ConstStaticCell::new(BufStorage::new()); static STORAGE: AppStorage = AppStorage::new(); define_dispatch! { app: MyApp; spawn_fn: spawn_fn; tx_impl: AppTx; spawn_impl: WireSpawnImpl; context: Context; endpoints: { list: ENDPOINT_LIST; | EndpointTy | kind | handler | | ---------- | ---- | ------- | | PingEndpoint | blocking | ping_handler | | GetUniqueIdEndpoint | blocking | get_unique_id_handler | }; topics_in: { list: TOPICS_IN_LIST; | TopicTy | kind | handler | | ---------- | ---- | ------- | }; topics_out: { list: TOPICS_OUT_LIST; }; } fn usb_config() -> embassy_usb::Config<'static> { let mut config = embassy_usb::Config::new(0x16c0, 0x27DD); config.manufacturer = Some("Hubald Verzijl"); config.product = Some("Bioz Amplifier"); config.serial_number = Some("12345678"); // Required for windows compatibility. // 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; config } /// This handles the low level USB management #[embassy_executor::task] pub async fn usb_task(mut usb: embassy_usb::UsbDevice<'static, AppDriver>) { usb.run().await; } #[embassy_executor::task] async fn server_run(mut server: AppServer) { loop { // If the host disconnects, we'll return an error here. // If this happens, just wait until the host reconnects let _ = server.run().await; } } // --- pub fn init_communication(usb_driver: Driver<'static, peripherals::USB>, spawner: Spawner) { // Initialize communication peripherals let pbufs = PBUFS.take(); let config = usb_config(); let context = Context { unique_id: *uid::uid(), }; let (device, tx_impl, rx_impl) = STORAGE.init(usb_driver, config, pbufs.tx_buf.as_mut_slice()); let dispatcher = MyApp::new(context, spawner.into()); let vkk = dispatcher.min_key_len(); let server: AppServer = Server::new( tx_impl, rx_impl, pbufs.rx_buf.as_mut_slice(), dispatcher, vkk, ); spawner.must_spawn(usb_task(device)); spawner.must_spawn(server_run(server)); } fn ping_handler(_context: &mut Context, _header: VarHeader, rqst: u32) -> u32 { info!("ping"); rqst } fn get_unique_id_handler(context: &mut Context, _header: VarHeader, _rqst: ()) -> [u8; 12] { info!("get_unique_id"); context.unique_id }