aboutsummaryrefslogtreecommitdiff
path: root/examples/rp
diff options
context:
space:
mode:
authorkalkyl <[email protected]>2023-11-07 19:57:05 +0100
committerkalkyl <[email protected]>2023-11-07 19:57:05 +0100
commitd1adc936141b06cb2d8acd2f8a15279307ef06a6 (patch)
treec3035e6ccebae9eecaef95c63caa8ed59a99241d /examples/rp
parente3fe13e9052e6502b9618b94a64ed69688bbf5b6 (diff)
rp: Add USB raw bulk example
Diffstat (limited to 'examples/rp')
-rw-r--r--examples/rp/Cargo.toml1
-rw-r--r--examples/rp/src/bin/usb_raw_bulk.rs150
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
12embassy-time = { version = "0.1.5", path = "../../embassy-time", features = ["nightly", "unstable-traits", "defmt", "defmt-timestamp-uptime"] } 12embassy-time = { version = "0.1.5", path = "../../embassy-time", features = ["nightly", "unstable-traits", "defmt", "defmt-timestamp-uptime"] }
13embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt", "unstable-traits", "nightly", "unstable-pac", "time-driver", "critical-section-impl"] } 13embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt", "unstable-traits", "nightly", "unstable-pac", "time-driver", "critical-section-impl"] }
14embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt", "msos-descriptor"] } 14embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt", "msos-descriptor"] }
15embassy-usb-driver = { version = "0.1.0", path = "../../embassy-usb-driver" }
15embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "udp", "dhcpv4", "medium-ethernet"] } 16embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "udp", "dhcpv4", "medium-ethernet"] }
16embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] } 17embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] }
17embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 18embassy-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
31use defmt::info;
32use embassy_executor::Spawner;
33use embassy_futures::join::join;
34use embassy_rp::bind_interrupts;
35use embassy_rp::peripherals::USB;
36use embassy_rp::usb::{Driver, InterruptHandler};
37use embassy_usb::msos::{self, windows_version};
38use embassy_usb::{Builder, Config, Handler};
39use embassy_usb_driver::{Endpoint, EndpointIn, EndpointOut};
40use {defmt_rtt as _, panic_probe as _};
41
42// This is a randomly generated GUID to allow clients on Windows to find our device
43const DEVICE_INTERFACE_GUIDS: &[&str] = &["{AFB9A6FB-30BA-44BC-9232-806CFC875321}"];
44
45bind_interrupts!(struct Irqs {
46 USBCTRL_IRQ => InterruptHandler<USB>;
47});
48
49#[embassy_executor::main]
50async 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.
149struct ControlHandler;
150impl Handler for ControlHandler {}