aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2023-11-07 10:30:52 +0000
committerGitHub <[email protected]>2023-11-07 10:30:52 +0000
commit78a7ee7ec48a6ed26d770165e777beb06e92777c (patch)
tree89cb9344fe554ca6c68795c3553f056699a978d2
parent8369f7614ab7c7d035c99cd17b3e7bb5b2abfa70 (diff)
parente3fe13e9052e6502b9618b94a64ed69688bbf5b6 (diff)
Merge pull request #2157 from kalkyl/usb-raw
rp: Add USB raw example + msos-descriptor to examples and usb-logger
-rw-r--r--embassy-usb-logger/Cargo.toml3
-rw-r--r--embassy-usb-logger/src/lib.rs6
-rw-r--r--examples/rp/Cargo.toml4
-rw-r--r--examples/rp/src/bin/pio_uart.rs1
-rw-r--r--examples/rp/src/bin/usb_ethernet.rs1
-rw-r--r--examples/rp/src/bin/usb_hid_keyboard.rs4
-rw-r--r--examples/rp/src/bin/usb_midi.rs1
-rw-r--r--examples/rp/src/bin/usb_raw.rs199
-rw-r--r--examples/rp/src/bin/usb_serial.rs1
9 files changed, 216 insertions, 4 deletions
diff --git a/embassy-usb-logger/Cargo.toml b/embassy-usb-logger/Cargo.toml
index 48b8bbcc6..02d0ed8e5 100644
--- a/embassy-usb-logger/Cargo.toml
+++ b/embassy-usb-logger/Cargo.toml
@@ -8,6 +8,9 @@ src_base = "https://github.com/embassy-rs/embassy/blob/embassy-usb-logger-v$VERS
8src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-usb-logger/src/" 8src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-usb-logger/src/"
9target = "thumbv7em-none-eabi" 9target = "thumbv7em-none-eabi"
10 10
11[features]
12msos-descriptor = ["embassy-usb/msos-descriptor"]
13
11[dependencies] 14[dependencies]
12embassy-usb = { version = "0.1.0", path = "../embassy-usb" } 15embassy-usb = { version = "0.1.0", path = "../embassy-usb" }
13embassy-sync = { version = "0.4.0", path = "../embassy-sync" } 16embassy-sync = { version = "0.4.0", path = "../embassy-sync" }
diff --git a/embassy-usb-logger/src/lib.rs b/embassy-usb-logger/src/lib.rs
index 9178dd6dd..95fc0a7ed 100644
--- a/embassy-usb-logger/src/lib.rs
+++ b/embassy-usb-logger/src/lib.rs
@@ -19,6 +19,8 @@ pub struct LoggerState<'d> {
19 device_descriptor: [u8; 32], 19 device_descriptor: [u8; 32],
20 config_descriptor: [u8; 128], 20 config_descriptor: [u8; 128],
21 bos_descriptor: [u8; 16], 21 bos_descriptor: [u8; 16],
22 #[cfg(feature = "msos-descriptor")]
23 msos_descriptor: [u8; 256],
22 control_buf: [u8; 64], 24 control_buf: [u8; 64],
23} 25}
24 26
@@ -30,6 +32,8 @@ impl<'d> LoggerState<'d> {
30 device_descriptor: [0; 32], 32 device_descriptor: [0; 32],
31 config_descriptor: [0; 128], 33 config_descriptor: [0; 128],
32 bos_descriptor: [0; 16], 34 bos_descriptor: [0; 16],
35 #[cfg(feature = "msos-descriptor")]
36 msos_descriptor: [0; 256],
33 control_buf: [0; 64], 37 control_buf: [0; 64],
34 } 38 }
35 } 39 }
@@ -73,6 +77,8 @@ impl<const N: usize> UsbLogger<N> {
73 &mut state.device_descriptor, 77 &mut state.device_descriptor,
74 &mut state.config_descriptor, 78 &mut state.config_descriptor,
75 &mut state.bos_descriptor, 79 &mut state.bos_descriptor,
80 #[cfg(feature = "msos-descriptor")]
81 &mut state.msos_descriptor,
76 &mut state.control_buf, 82 &mut state.control_buf,
77 ); 83 );
78 84
diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml
index fbe7acae1..5ff505e86 100644
--- a/examples/rp/Cargo.toml
+++ b/examples/rp/Cargo.toml
@@ -11,11 +11,11 @@ embassy-sync = { version = "0.4.0", path = "../../embassy-sync", features = ["de
11embassy-executor = { version = "0.3.1", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.3.1", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
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"] } 14embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt", "msos-descriptor"] }
15embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "udp", "dhcpv4", "medium-ethernet"] } 15embassy-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"] } 16embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] }
17embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 17embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
18embassy-usb-logger = { version = "0.1.0", path = "../../embassy-usb-logger" } 18embassy-usb-logger = { version = "0.1.0", path = "../../embassy-usb-logger", features = ["msos-descriptor"]}
19embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["time", "defmt"] } 19embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["time", "defmt"] }
20lora-phy = { version = "2" } 20lora-phy = { version = "2" }
21lorawan-device = { version = "0.11.0", default-features = false, features = ["async", "external-lora-phy"] } 21lorawan-device = { version = "0.11.0", default-features = false, features = ["async", "external-lora-phy"] }
diff --git a/examples/rp/src/bin/pio_uart.rs b/examples/rp/src/bin/pio_uart.rs
index 45416c56b..dca28d779 100644
--- a/examples/rp/src/bin/pio_uart.rs
+++ b/examples/rp/src/bin/pio_uart.rs
@@ -75,6 +75,7 @@ async fn main(_spawner: Spawner) {
75 &mut device_descriptor, 75 &mut device_descriptor,
76 &mut config_descriptor, 76 &mut config_descriptor,
77 &mut bos_descriptor, 77 &mut bos_descriptor,
78 &mut [],
78 &mut control_buf, 79 &mut control_buf,
79 ); 80 );
80 81
diff --git a/examples/rp/src/bin/usb_ethernet.rs b/examples/rp/src/bin/usb_ethernet.rs
index 6c2f27acf..aea9e6481 100644
--- a/examples/rp/src/bin/usb_ethernet.rs
+++ b/examples/rp/src/bin/usb_ethernet.rs
@@ -71,6 +71,7 @@ async fn main(spawner: Spawner) {
71 &mut make_static!([0; 256])[..], 71 &mut make_static!([0; 256])[..],
72 &mut make_static!([0; 256])[..], 72 &mut make_static!([0; 256])[..],
73 &mut make_static!([0; 256])[..], 73 &mut make_static!([0; 256])[..],
74 &mut make_static!([0; 0])[..],
74 &mut make_static!([0; 128])[..], 75 &mut make_static!([0; 128])[..],
75 ); 76 );
76 77
diff --git a/examples/rp/src/bin/usb_hid_keyboard.rs b/examples/rp/src/bin/usb_hid_keyboard.rs
index cc2090d22..569c9b12b 100644
--- a/examples/rp/src/bin/usb_hid_keyboard.rs
+++ b/examples/rp/src/bin/usb_hid_keyboard.rs
@@ -41,7 +41,7 @@ async fn main(_spawner: Spawner) {
41 let mut config_descriptor = [0; 256]; 41 let mut config_descriptor = [0; 256];
42 let mut bos_descriptor = [0; 256]; 42 let mut bos_descriptor = [0; 256];
43 // You can also add a Microsoft OS descriptor. 43 // You can also add a Microsoft OS descriptor.
44 // let mut msos_descriptor = [0; 256]; 44 let mut msos_descriptor = [0; 256];
45 let mut control_buf = [0; 64]; 45 let mut control_buf = [0; 64];
46 let request_handler = MyRequestHandler {}; 46 let request_handler = MyRequestHandler {};
47 let mut device_handler = MyDeviceHandler::new(); 47 let mut device_handler = MyDeviceHandler::new();
@@ -54,7 +54,7 @@ async fn main(_spawner: Spawner) {
54 &mut device_descriptor, 54 &mut device_descriptor,
55 &mut config_descriptor, 55 &mut config_descriptor,
56 &mut bos_descriptor, 56 &mut bos_descriptor,
57 // &mut msos_descriptor, 57 &mut msos_descriptor,
58 &mut control_buf, 58 &mut control_buf,
59 ); 59 );
60 60
diff --git a/examples/rp/src/bin/usb_midi.rs b/examples/rp/src/bin/usb_midi.rs
index f0b03c81b..3ba34c806 100644
--- a/examples/rp/src/bin/usb_midi.rs
+++ b/examples/rp/src/bin/usb_midi.rs
@@ -58,6 +58,7 @@ async fn main(_spawner: Spawner) {
58 &mut device_descriptor, 58 &mut device_descriptor,
59 &mut config_descriptor, 59 &mut config_descriptor,
60 &mut bos_descriptor, 60 &mut bos_descriptor,
61 &mut [],
61 &mut control_buf, 62 &mut control_buf,
62 ); 63 );
63 64
diff --git a/examples/rp/src/bin/usb_raw.rs b/examples/rp/src/bin/usb_raw.rs
new file mode 100644
index 000000000..f59262e5c
--- /dev/null
+++ b/examples/rp/src/bin/usb_raw.rs
@@ -0,0 +1,199 @@
1//! Example of using USB without a pre-defined class, but instead responding to
2//! raw USB control requests.
3//!
4//! The host computer can either:
5//! * send a command, with a 16-bit request ID, a 16-bit value, and an optional data buffer
6//! * request some data, with a 16-bit request ID, a 16-bit value, and a length of data to receive
7//!
8//! For higher throughput data, you can add some bulk endpoints after creating the alternate,
9//! but for low rate command/response, plain control transfers can be very simple and effective.
10//!
11//! Example code to send/receive data using `nusb`:
12//!
13//! ```ignore
14//! use futures_lite::future::block_on;
15//! use nusb::transfer::{ControlIn, ControlOut, ControlType, Recipient};
16//!
17//! fn main() {
18//! let di = nusb::list_devices()
19//! .unwrap()
20//! .find(|d| d.vendor_id() == 0xc0de && d.product_id() == 0xcafe)
21//! .expect("no device found");
22//! let device = di.open().expect("error opening device");
23//! let interface = device.claim_interface(0).expect("error claiming interface");
24//!
25//! // Send "hello world" to device
26//! let result = block_on(interface.control_out(ControlOut {
27//! control_type: ControlType::Vendor,
28//! recipient: Recipient::Interface,
29//! request: 100,
30//! value: 200,
31//! index: 0,
32//! data: b"hello world",
33//! }));
34//! println!("{result:?}");
35//!
36//! // Receive "hello" from device
37//! let result = block_on(interface.control_in(ControlIn {
38//! control_type: ControlType::Vendor,
39//! recipient: Recipient::Interface,
40//! request: 101,
41//! value: 201,
42//! index: 0,
43//! length: 5,
44//! }));
45//! println!("{result:?}");
46//! }
47//! ```
48
49#![no_std]
50#![no_main]
51#![feature(type_alias_impl_trait)]
52
53use defmt::info;
54use embassy_executor::Spawner;
55use embassy_rp::bind_interrupts;
56use embassy_rp::peripherals::USB;
57use embassy_rp::usb::{Driver, InterruptHandler};
58use embassy_usb::control::{InResponse, OutResponse, Recipient, Request, RequestType};
59use embassy_usb::msos::{self, windows_version};
60use embassy_usb::types::InterfaceNumber;
61use embassy_usb::{Builder, Config, Handler};
62use {defmt_rtt as _, panic_probe as _};
63
64// This is a randomly generated GUID to allow clients on Windows to find our device
65const DEVICE_INTERFACE_GUIDS: &[&str] = &["{AFB9A6FB-30BA-44BC-9232-806CFC875321}"];
66
67bind_interrupts!(struct Irqs {
68 USBCTRL_IRQ => InterruptHandler<USB>;
69});
70
71#[embassy_executor::main]
72async fn main(_spawner: Spawner) {
73 info!("Hello there!");
74
75 let p = embassy_rp::init(Default::default());
76
77 // Create the driver, from the HAL.
78 let driver = Driver::new(p.USB, Irqs);
79
80 // Create embassy-usb Config
81 let mut config = Config::new(0xc0de, 0xcafe);
82 config.manufacturer = Some("Embassy");
83 config.product = Some("USB raw example");
84 config.serial_number = Some("12345678");
85 config.max_power = 100;
86 config.max_packet_size_0 = 64;
87
88 // // Required for windows compatibility.
89 // // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help
90 config.device_class = 0xEF;
91 config.device_sub_class = 0x02;
92 config.device_protocol = 0x01;
93 config.composite_with_iads = true;
94
95 // Create embassy-usb DeviceBuilder using the driver and config.
96 // It needs some buffers for building the descriptors.
97 let mut device_descriptor = [0; 256];
98 let mut config_descriptor = [0; 256];
99 let mut bos_descriptor = [0; 256];
100 let mut msos_descriptor = [0; 256];
101 let mut control_buf = [0; 64];
102
103 let mut handler = ControlHandler {
104 if_num: InterfaceNumber(0),
105 };
106
107 let mut builder = Builder::new(
108 driver,
109 config,
110 &mut device_descriptor,
111 &mut config_descriptor,
112 &mut bos_descriptor,
113 &mut msos_descriptor,
114 &mut control_buf,
115 );
116
117 // Add the Microsoft OS Descriptor (MSOS/MOD) descriptor.
118 // We tell Windows that this entire device is compatible with the "WINUSB" feature,
119 // which causes it to use the built-in WinUSB driver automatically, which in turn
120 // can be used by libusb/rusb software without needing a custom driver or INF file.
121 // In principle you might want to call msos_feature() just on a specific function,
122 // if your device also has other functions that still use standard class drivers.
123 builder.msos_descriptor(windows_version::WIN8_1, 0);
124 builder.msos_feature(msos::CompatibleIdFeatureDescriptor::new("WINUSB", ""));
125 builder.msos_feature(msos::RegistryPropertyFeatureDescriptor::new(
126 "DeviceInterfaceGUIDs",
127 msos::PropertyData::RegMultiSz(DEVICE_INTERFACE_GUIDS),
128 ));
129
130 // Add a vendor-specific function (class 0xFF), and corresponding interface,
131 // that uses our custom handler.
132 let mut function = builder.function(0xFF, 0, 0);
133 let mut interface = function.interface();
134 let _alt = interface.alt_setting(0xFF, 0, 0, None);
135 handler.if_num = interface.interface_number();
136 drop(function);
137 builder.handler(&mut handler);
138
139 // Build the builder.
140 let mut usb = builder.build();
141
142 // Run the USB device.
143 usb.run().await;
144}
145
146/// Handle CONTROL endpoint requests and responses. For many simple requests and responses
147/// you can get away with only using the control endpoint.
148struct ControlHandler {
149 if_num: InterfaceNumber,
150}
151
152impl Handler for ControlHandler {
153 /// Respond to HostToDevice control messages, where the host sends us a command and
154 /// optionally some data, and we can only acknowledge or reject it.
155 fn control_out<'a>(&'a mut self, req: Request, buf: &'a [u8]) -> Option<OutResponse> {
156 // Log the request before filtering to help with debugging.
157 info!("Got control_out, request={}, buf={:a}", req, buf);
158
159 // Only handle Vendor request types to an Interface.
160 if req.request_type != RequestType::Vendor || req.recipient != Recipient::Interface {
161 return None;
162 }
163
164 // Ignore requests to other interfaces.
165 if req.index != self.if_num.0 as u16 {
166 return None;
167 }
168
169 // Accept request 100, value 200, reject others.
170 if req.request == 100 && req.value == 200 {
171 Some(OutResponse::Accepted)
172 } else {
173 Some(OutResponse::Rejected)
174 }
175 }
176
177 /// Respond to DeviceToHost control messages, where the host requests some data from us.
178 fn control_in<'a>(&'a mut self, req: Request, buf: &'a mut [u8]) -> Option<InResponse<'a>> {
179 info!("Got control_in, request={}", req);
180
181 // Only handle Vendor request types to an Interface.
182 if req.request_type != RequestType::Vendor || req.recipient != Recipient::Interface {
183 return None;
184 }
185
186 // Ignore requests to other interfaces.
187 if req.index != self.if_num.0 as u16 {
188 return None;
189 }
190
191 // Respond "hello" to request 101, value 201, when asked for 5 bytes, otherwise reject.
192 if req.request == 101 && req.value == 201 && req.length == 5 {
193 buf[..5].copy_from_slice(b"hello");
194 Some(InResponse::Accepted(&buf[..5]))
195 } else {
196 Some(InResponse::Rejected)
197 }
198 }
199}
diff --git a/examples/rp/src/bin/usb_serial.rs b/examples/rp/src/bin/usb_serial.rs
index 164e2052d..0d0317cda 100644
--- a/examples/rp/src/bin/usb_serial.rs
+++ b/examples/rp/src/bin/usb_serial.rs
@@ -60,6 +60,7 @@ async fn main(_spawner: Spawner) {
60 &mut device_descriptor, 60 &mut device_descriptor,
61 &mut config_descriptor, 61 &mut config_descriptor,
62 &mut bos_descriptor, 62 &mut bos_descriptor,
63 &mut [],
63 &mut control_buf, 64 &mut control_buf,
64 ); 65 );
65 66