From dc935d56ee65408b74daca79a9a676687d497218 Mon Sep 17 00:00:00 2001 From: melfey Date: Sat, 15 Aug 2026 19:01:34 -0500 Subject: [PATCH] USB test that works! It parrots. I mostly just wanted to save this state of the project --- Cargo.lock | 19 ++++++++++ Cargo.toml | 2 ++ src/main.rs | 59 ++++++++++++++++++++----------- src/usb.rs | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 159 insertions(+), 20 deletions(-) create mode 100644 src/usb.rs diff --git a/Cargo.lock b/Cargo.lock index 19546fd..d62e808 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -588,6 +588,8 @@ dependencies = [ "embedded-io-async 0.7.0", "heapless 0.9.3", "panic-probe", + "static_cell", + "usb_communication_shared", ] [[package]] @@ -1319,6 +1321,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" dependencies = [ "serde_core", + "serde_derive", ] [[package]] @@ -1418,6 +1421,15 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" +[[package]] +name = "static_cell" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0530892bb4fa575ee0da4b86f86c667132a94b74bb72160f58ee5a4afec74c23" +dependencies = [ + "portable-atomic", +] + [[package]] name = "string_cache" version = "0.8.9" @@ -1600,6 +1612,13 @@ dependencies = [ "portable-atomic", ] +[[package]] +name = "usb_communication_shared" +version = "0.1.0" +dependencies = [ + "serde", +] + [[package]] name = "usbd-hid" version = "0.10.1" diff --git a/Cargo.toml b/Cargo.toml index 2c351e1..7ada217 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,3 +20,5 @@ heapless = "0.9" embedded-hal-async = "1.0" embedded-io-async = { version = "0.7.0", features = ["defmt"] } defmt-rtt = "1.3.0" +static_cell = "2.1.1" +usb_communication_shared = { version = "0.1.0", path = "../usb_communication_shared" } diff --git a/src/main.rs b/src/main.rs index 952f6c4..836488f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,34 +4,53 @@ use defmt::*; use defmt_rtt as _; use embassy_executor::Spawner; +use embassy_rp::{ + bind_interrupts, + peripherals::USB, + usb::{Driver as UsbDriver, InterruptHandler as UsbInterruptHandler}, +}; use embassy_time::Timer; use panic_probe as _; +use crate::usb::handle_usb; + +mod usb; + +bind_interrupts!(struct Irqs{ + USBCTRL_IRQ => UsbInterruptHandler; +}); + +#[embassy_executor::main( + executor = "embassy_rp::executor::Executor", + entry = "cortex_m_rt::entry" +)] +async fn main(spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + + let usb_driver = UsbDriver::new(p.USB, Irqs); + + spawner.spawn(handle_usb(usb_driver).unwrap()); + + let led_future = async { + loop { + info!("led on!"); + Timer::after_millis(500).await; + + info!("led off!"); + Timer::after_millis(500).await; + } + }; + + led_future.await; +} + // Program metadata for `picotool info`. // This isn't needed, but it's recommended to have these minimal entries. #[unsafe(link_section = ".bi_entries")] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info::rp_program_name!(c"Blinky Example"), - embassy_rp::binary_info::rp_program_description!( - c"This example tests the RP Pico on board LED, connected to gpio 25" - ), + embassy_rp::binary_info::rp_program_name!(c"USB-Communication"), + embassy_rp::binary_info::rp_program_description!(c"USB-Communication System"), embassy_rp::binary_info::rp_cargo_version!(), embassy_rp::binary_info::rp_program_build_attribute!(), ]; - -#[embassy_executor::main( - executor = "embassy_rp::executor::Executor", - entry = "cortex_m_rt::entry" -)] -async fn main(_spawner: Spawner) { - let p = embassy_rp::init(Default::default()); - - loop { - info!("led on!"); - Timer::after_millis(500).await; - - info!("led off!"); - Timer::after_millis(500).await; - } -} diff --git a/src/usb.rs b/src/usb.rs new file mode 100644 index 0000000..abc1d70 --- /dev/null +++ b/src/usb.rs @@ -0,0 +1,99 @@ +use defmt::*; +use heapless::Vec; +use static_cell::StaticCell; + +use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, channel::Channel}; + +use embassy_rp::{peripherals::USB, usb::Driver as UsbDriver}; +use embassy_usb::class::cdc_acm::{CdcAcmClass, State as UsbState}; +use usb_communication_shared::request::Packet as RequestPacket; +use usb_communication_shared::response::Packet as ResponsePacket; +static USB_SEND_CHANNEL: Channel = Channel::new(); +static USB_RECIEVE_CHANNEL: Channel = Channel::new(); + +#[embassy_executor::task] +pub async fn handle_usb(usb_driver: UsbDriver<'static, USB>) { + let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); + config.manufacturer = Some("Melfely"); + config.product = Some("USB-Parrot"); + config.serial_number = Some("1234"); + config.max_power = 100; + config.max_packet_size_0 = 64; + + let mut usb_builder = { + static CONFIG_DESCRIPTOR: StaticCell<[u8; 256]> = StaticCell::new(); + static BOS_DESCRIPTOR: StaticCell<[u8; 256]> = StaticCell::new(); + static CONTROL_BUF: StaticCell<[u8; 64]> = StaticCell::new(); + + let embassy = embassy_usb::Builder::new( + usb_driver, + config, + CONFIG_DESCRIPTOR.init([0; 256]), + BOS_DESCRIPTOR.init([0; 256]), + &mut [], + CONTROL_BUF.init([0; 64]), + ); + embassy + }; + + let usb_class = { + static STATE: StaticCell = StaticCell::new(); + let state = STATE.init(UsbState::new()); + CdcAcmClass::new(&mut usb_builder, state, 64) + }; + + let (mut usb_tx, mut usb_rx, _usb_control) = usb_class.split_with_control(); + + let mut usb = usb_builder.build(); + + let usb_fut = usb.run(); + + let channel = Channel::, 4>::new(); + + let mut usb_buf = [0; 64]; + let usb_rx_future = async { + let sender = channel.sender(); + loop { + usb_rx.wait_connection().await; + info!("USB RX Connected"); + loop { + match usb_rx.read_packet(&mut usb_buf).await { + Err(e) => { + error!( + "Usb read error: {:?}. Assume Discconection", + Debug2Format(&e) + ); + break; + } + Ok(_) => { + let vec: Vec = usb_buf.into(); + sender.send(vec).await; + } + } + } + } + }; + + let usb_tx_future = async { + let reciever = channel.receiver(); + loop { + usb_tx.wait_connection().await; + info!("USB TX Connected"); + loop { + let packet = reciever.receive().await; + match usb_tx.write_packet(&packet).await { + Ok(_) => {} + Err(err) => { + error!( + "Usb write error: {:?}, Assume Disconnection", + Debug2Format(&err) + ); + break; + } + } + } + } + }; + + embassy_futures::join::join3(usb_fut, usb_rx_future, usb_tx_future).await; +}