diff options
Diffstat (limited to 'examples')
| -rw-r--r-- | examples/rp/Cargo.toml | 1 | ||||
| -rw-r--r-- | examples/rp/src/bin/usb_raw_bulk.rs | 150 |
2 files changed, 151 insertions, 0 deletions
diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index 5ff505e86..c53510445 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml | |||
| @@ -12,6 +12,7 @@ embassy-executor = { version = "0.3.1", path = "../../embassy-executor", feature | |||
| 12 | embassy-time = { version = "0.1.5", path = "../../embassy-time", features = ["nightly", "unstable-traits", "defmt", "defmt-timestamp-uptime"] } | 12 | embassy-time = { version = "0.1.5", path = "../../embassy-time", features = ["nightly", "unstable-traits", "defmt", "defmt-timestamp-uptime"] } |
| 13 | embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt", "unstable-traits", "nightly", "unstable-pac", "time-driver", "critical-section-impl"] } | 13 | embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt", "unstable-traits", "nightly", "unstable-pac", "time-driver", "critical-section-impl"] } |
| 14 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt", "msos-descriptor"] } | 14 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt", "msos-descriptor"] } |
| 15 | embassy-usb-driver = { version = "0.1.0", path = "../../embassy-usb-driver" } | ||
| 15 | embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "udp", "dhcpv4", "medium-ethernet"] } | 16 | embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "udp", "dhcpv4", "medium-ethernet"] } |
| 16 | embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] } | 17 | embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] } |
| 17 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } | 18 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } |
diff --git a/examples/rp/src/bin/usb_raw_bulk.rs b/examples/rp/src/bin/usb_raw_bulk.rs new file mode 100644 index 000000000..e8618c48d --- /dev/null +++ b/examples/rp/src/bin/usb_raw_bulk.rs | |||
| @@ -0,0 +1,150 @@ | |||
| 1 | //! Example of using USB without a pre-defined class, but instead using raw USB bulk transfers. | ||
| 2 | //! | ||
| 3 | //! Example code to send/receive data using `nusb`: | ||
| 4 | //! | ||
| 5 | //! ```ignore | ||
| 6 | //! use futures_lite::future::block_on; | ||
| 7 | //! use nusb::transfer::RequestBuffer; | ||
| 8 | //! | ||
| 9 | //! const BULK_OUT_EP: u8 = 0x01; | ||
| 10 | //! const BULK_IN_EP: u8 = 0x81; | ||
| 11 | //! | ||
| 12 | //! fn main() { | ||
| 13 | //! let di = nusb::list_devices() | ||
| 14 | //! .unwrap() | ||
| 15 | //! .find(|d| d.vendor_id() == 0xc0de && d.product_id() == 0xcafe) | ||
| 16 | //! .expect("no device found"); | ||
| 17 | //! let device = di.open().expect("error opening device"); | ||
| 18 | //! let interface = device.claim_interface(0).expect("error claiming interface"); | ||
| 19 | //! | ||
| 20 | //! let result = block_on(interface.bulk_out(BULK_OUT_EP, b"hello world".into())); | ||
| 21 | //! println!("{result:?}"); | ||
| 22 | //! let result = block_on(interface.bulk_in(BULK_IN_EP, RequestBuffer::new(64))); | ||
| 23 | //! println!("{result:?}"); | ||
| 24 | //! } | ||
| 25 | //! ``` | ||
| 26 | |||
| 27 | #![no_std] | ||
| 28 | #![no_main] | ||
| 29 | #![feature(type_alias_impl_trait)] | ||
| 30 | |||
| 31 | use defmt::info; | ||
| 32 | use embassy_executor::Spawner; | ||
| 33 | use embassy_futures::join::join; | ||
| 34 | use embassy_rp::bind_interrupts; | ||
| 35 | use embassy_rp::peripherals::USB; | ||
| 36 | use embassy_rp::usb::{Driver, InterruptHandler}; | ||
| 37 | use embassy_usb::msos::{self, windows_version}; | ||
| 38 | use embassy_usb::{Builder, Config, Handler}; | ||
| 39 | use embassy_usb_driver::{Endpoint, EndpointIn, EndpointOut}; | ||
| 40 | use {defmt_rtt as _, panic_probe as _}; | ||
| 41 | |||
| 42 | // This is a randomly generated GUID to allow clients on Windows to find our device | ||
| 43 | const DEVICE_INTERFACE_GUIDS: &[&str] = &["{AFB9A6FB-30BA-44BC-9232-806CFC875321}"]; | ||
| 44 | |||
| 45 | bind_interrupts!(struct Irqs { | ||
| 46 | USBCTRL_IRQ => InterruptHandler<USB>; | ||
| 47 | }); | ||
| 48 | |||
| 49 | #[embassy_executor::main] | ||
| 50 | async fn main(_spawner: Spawner) { | ||
| 51 | info!("Hello there!"); | ||
| 52 | |||
| 53 | let p = embassy_rp::init(Default::default()); | ||
| 54 | |||
| 55 | // Create the driver, from the HAL. | ||
| 56 | let driver = Driver::new(p.USB, Irqs); | ||
| 57 | |||
| 58 | // Create embassy-usb Config | ||
| 59 | let mut config = Config::new(0xc0de, 0xcafe); | ||
| 60 | config.manufacturer = Some("Embassy"); | ||
| 61 | config.product = Some("USB raw example"); | ||
| 62 | config.serial_number = Some("12345678"); | ||
| 63 | config.max_power = 100; | ||
| 64 | config.max_packet_size_0 = 64; | ||
| 65 | |||
| 66 | // // Required for windows compatibility. | ||
| 67 | // // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help | ||
| 68 | config.device_class = 0xEF; | ||
| 69 | config.device_sub_class = 0x02; | ||
| 70 | config.device_protocol = 0x01; | ||
| 71 | config.composite_with_iads = true; | ||
| 72 | |||
| 73 | // Create embassy-usb DeviceBuilder using the driver and config. | ||
| 74 | // It needs some buffers for building the descriptors. | ||
| 75 | let mut device_descriptor = [0; 256]; | ||
| 76 | let mut config_descriptor = [0; 256]; | ||
| 77 | let mut bos_descriptor = [0; 256]; | ||
| 78 | let mut msos_descriptor = [0; 256]; | ||
| 79 | let mut control_buf = [0; 64]; | ||
| 80 | |||
| 81 | let mut handler = ControlHandler; | ||
| 82 | |||
| 83 | let mut builder = Builder::new( | ||
| 84 | driver, | ||
| 85 | config, | ||
| 86 | &mut device_descriptor, | ||
| 87 | &mut config_descriptor, | ||
| 88 | &mut bos_descriptor, | ||
| 89 | &mut msos_descriptor, | ||
| 90 | &mut control_buf, | ||
| 91 | ); | ||
| 92 | |||
| 93 | // Add the Microsoft OS Descriptor (MSOS/MOD) descriptor. | ||
| 94 | // We tell Windows that this entire device is compatible with the "WINUSB" feature, | ||
| 95 | // which causes it to use the built-in WinUSB driver automatically, which in turn | ||
| 96 | // can be used by libusb/rusb software without needing a custom driver or INF file. | ||
| 97 | // In principle you might want to call msos_feature() just on a specific function, | ||
| 98 | // if your device also has other functions that still use standard class drivers. | ||
| 99 | builder.msos_descriptor(windows_version::WIN8_1, 0); | ||
| 100 | builder.msos_feature(msos::CompatibleIdFeatureDescriptor::new("WINUSB", "")); | ||
| 101 | builder.msos_feature(msos::RegistryPropertyFeatureDescriptor::new( | ||
| 102 | "DeviceInterfaceGUIDs", | ||
| 103 | msos::PropertyData::RegMultiSz(DEVICE_INTERFACE_GUIDS), | ||
| 104 | )); | ||
| 105 | |||
| 106 | // Add a vendor-specific function (class 0xFF), and corresponding interface, | ||
| 107 | // that uses our custom handler. | ||
| 108 | let mut function = builder.function(0xFF, 0, 0); | ||
| 109 | let mut interface = function.interface(); | ||
| 110 | let mut alt = interface.alt_setting(0xFF, 0, 0, None); | ||
| 111 | let mut read_ep = alt.endpoint_bulk_out(64); | ||
| 112 | let mut write_ep = alt.endpoint_bulk_in(64); | ||
| 113 | |||
| 114 | drop(function); | ||
| 115 | builder.handler(&mut handler); | ||
| 116 | |||
| 117 | // Build the builder. | ||
| 118 | let mut usb = builder.build(); | ||
| 119 | |||
| 120 | // Run the USB device. | ||
| 121 | let usb_fut = usb.run(); | ||
| 122 | |||
| 123 | // Do stuff with the class! | ||
| 124 | let echo_fut = async { | ||
| 125 | loop { | ||
| 126 | read_ep.wait_enabled().await; | ||
| 127 | info!("Connected"); | ||
| 128 | loop { | ||
| 129 | let mut data = [0; 64]; | ||
| 130 | match read_ep.read(&mut data).await { | ||
| 131 | Ok(n) => { | ||
| 132 | info!("Got bulk: {:a}", data[..n]); | ||
| 133 | // Echo back to the host: | ||
| 134 | write_ep.write(&data[..n]).await.ok(); | ||
| 135 | } | ||
| 136 | Err(_) => break, | ||
| 137 | } | ||
| 138 | } | ||
| 139 | info!("Disconnected"); | ||
| 140 | } | ||
| 141 | }; | ||
| 142 | |||
| 143 | // Run everything concurrently. | ||
| 144 | // If we had made everything `'static` above instead, we could do this using separate tasks instead. | ||
| 145 | join(usb_fut, echo_fut).await; | ||
| 146 | } | ||
| 147 | |||
| 148 | /// Handle CONTROL endpoint requests and responses. | ||
| 149 | struct ControlHandler; | ||
| 150 | impl Handler for ControlHandler {} | ||
