aboutsummaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorUlf Lilleengen <[email protected]>2025-11-12 08:24:18 +0000
committerGitHub <[email protected]>2025-11-12 08:24:18 +0000
commit7201c6deb9d8c2b1fb380a58b9e879e394ed5f24 (patch)
treed33ddfb6b8038a25e319495649844c798689fdef /examples
parent0d1fc76a10863b85961a63db4a9e1e2807f35957 (diff)
parenta60b268186ff3accf68a3a6009d96ffca12221bd (diff)
Merge pull request #4691 from matteo-meluzzi/17-add-support-for-boot-protocol
Add support for changing hid protocol mode in embassy-usb
Diffstat (limited to 'examples')
-rw-r--r--examples/nrf52840/src/bin/usb_hid_keyboard.rs58
-rw-r--r--examples/nrf52840/src/bin/usb_hid_mouse.rs56
-rw-r--r--examples/rp/src/bin/usb_hid_keyboard.rs86
-rwxr-xr-xexamples/rp/src/bin/usb_hid_mouse.rs60
-rw-r--r--examples/rp235x/src/bin/usb_hid_keyboard.rs85
-rw-r--r--examples/stm32f4/src/bin/usb_hid_keyboard.rs84
-rw-r--r--examples/stm32f4/src/bin/usb_hid_mouse.rs56
-rw-r--r--examples/stm32l5/src/bin/usb_hid_mouse.rs56
8 files changed, 411 insertions, 130 deletions
diff --git a/examples/nrf52840/src/bin/usb_hid_keyboard.rs b/examples/nrf52840/src/bin/usb_hid_keyboard.rs
index 1cd730503..7b7303526 100644
--- a/examples/nrf52840/src/bin/usb_hid_keyboard.rs
+++ b/examples/nrf52840/src/bin/usb_hid_keyboard.rs
@@ -1,7 +1,7 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4use core::sync::atomic::{AtomicBool, Ordering}; 4use core::sync::atomic::{AtomicBool, AtomicU8, Ordering};
5 5
6use defmt::*; 6use defmt::*;
7use embassy_executor::Spawner; 7use embassy_executor::Spawner;
@@ -13,7 +13,9 @@ use embassy_nrf::usb::vbus_detect::HardwareVbusDetect;
13use embassy_nrf::{bind_interrupts, pac, peripherals, usb}; 13use embassy_nrf::{bind_interrupts, pac, peripherals, usb};
14use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; 14use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
15use embassy_sync::signal::Signal; 15use embassy_sync::signal::Signal;
16use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State}; 16use embassy_usb::class::hid::{
17 HidBootProtocol, HidProtocolMode, HidReaderWriter, HidSubclass, ReportId, RequestHandler, State,
18};
17use embassy_usb::control::OutResponse; 19use embassy_usb::control::OutResponse;
18use embassy_usb::{Builder, Config, Handler}; 20use embassy_usb::{Builder, Config, Handler};
19use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; 21use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor};
@@ -26,6 +28,8 @@ bind_interrupts!(struct Irqs {
26 28
27static SUSPENDED: AtomicBool = AtomicBool::new(false); 29static SUSPENDED: AtomicBool = AtomicBool::new(false);
28 30
31static HID_PROTOCOL_MODE: AtomicU8 = AtomicU8::new(HidProtocolMode::Boot as u8);
32
29#[embassy_executor::main] 33#[embassy_executor::main]
30async fn main(_spawner: Spawner) { 34async fn main(_spawner: Spawner) {
31 let p = embassy_nrf::init(Default::default()); 35 let p = embassy_nrf::init(Default::default());
@@ -45,6 +49,10 @@ async fn main(_spawner: Spawner) {
45 config.max_power = 100; 49 config.max_power = 100;
46 config.max_packet_size_0 = 64; 50 config.max_packet_size_0 = 64;
47 config.supports_remote_wakeup = true; 51 config.supports_remote_wakeup = true;
52 config.composite_with_iads = false;
53 config.device_class = 0;
54 config.device_sub_class = 0;
55 config.device_protocol = 0;
48 56
49 // Create embassy-usb DeviceBuilder using the driver and config. 57 // Create embassy-usb DeviceBuilder using the driver and config.
50 // It needs some buffers for building the descriptors. 58 // It needs some buffers for building the descriptors.
@@ -74,6 +82,8 @@ async fn main(_spawner: Spawner) {
74 request_handler: None, 82 request_handler: None,
75 poll_ms: 60, 83 poll_ms: 60,
76 max_packet_size: 64, 84 max_packet_size: 64,
85 hid_subclass: HidSubclass::Boot,
86 hid_boot_protocol: HidBootProtocol::Keyboard,
77 }; 87 };
78 let hid = HidReaderWriter::<_, 1, 8>::new(&mut builder, &mut state, config); 88 let hid = HidReaderWriter::<_, 1, 8>::new(&mut builder, &mut state, config);
79 89
@@ -106,6 +116,11 @@ async fn main(_spawner: Spawner) {
106 if SUSPENDED.load(Ordering::Acquire) { 116 if SUSPENDED.load(Ordering::Acquire) {
107 info!("Triggering remote wakeup"); 117 info!("Triggering remote wakeup");
108 remote_wakeup.signal(()); 118 remote_wakeup.signal(());
119 } else if HID_PROTOCOL_MODE.load(Ordering::Relaxed) == HidProtocolMode::Boot as u8 {
120 match writer.write(&[0, 0, 4, 0, 0, 0, 0, 0]).await {
121 Ok(()) => {}
122 Err(e) => warn!("Failed to send boot report: {:?}", e),
123 };
109 } else { 124 } else {
110 let report = KeyboardReport { 125 let report = KeyboardReport {
111 keycodes: [4, 0, 0, 0, 0, 0], 126 keycodes: [4, 0, 0, 0, 0, 0],
@@ -121,16 +136,23 @@ async fn main(_spawner: Spawner) {
121 136
122 button.wait_for_high().await; 137 button.wait_for_high().await;
123 info!("RELEASED"); 138 info!("RELEASED");
124 let report = KeyboardReport { 139 if HID_PROTOCOL_MODE.load(Ordering::Relaxed) == HidProtocolMode::Boot as u8 {
125 keycodes: [0, 0, 0, 0, 0, 0], 140 match writer.write(&[0, 0, 0, 0, 0, 0, 0, 0]).await {
126 leds: 0, 141 Ok(()) => {}
127 modifier: 0, 142 Err(e) => warn!("Failed to send boot report: {:?}", e),
128 reserved: 0, 143 };
129 }; 144 } else {
130 match writer.write_serialize(&report).await { 145 let report = KeyboardReport {
131 Ok(()) => {} 146 keycodes: [0, 0, 0, 0, 0, 0],
132 Err(e) => warn!("Failed to send report: {:?}", e), 147 leds: 0,
133 }; 148 modifier: 0,
149 reserved: 0,
150 };
151 match writer.write_serialize(&report).await {
152 Ok(()) => {}
153 Err(e) => warn!("Failed to send report: {:?}", e),
154 };
155 }
134 } 156 }
135 }; 157 };
136 158
@@ -156,6 +178,18 @@ impl RequestHandler for MyRequestHandler {
156 OutResponse::Accepted 178 OutResponse::Accepted
157 } 179 }
158 180
181 fn get_protocol(&self) -> HidProtocolMode {
182 let protocol = HidProtocolMode::from(HID_PROTOCOL_MODE.load(Ordering::Relaxed));
183 info!("The current HID protocol mode is: {}", protocol);
184 protocol
185 }
186
187 fn set_protocol(&mut self, protocol: HidProtocolMode) -> OutResponse {
188 info!("Switching to HID protocol mode: {}", protocol);
189 HID_PROTOCOL_MODE.store(protocol as u8, Ordering::Relaxed);
190 OutResponse::Accepted
191 }
192
159 fn set_idle_ms(&mut self, id: Option<ReportId>, dur: u32) { 193 fn set_idle_ms(&mut self, id: Option<ReportId>, dur: u32) {
160 info!("Set idle rate for {:?} to {:?}", id, dur); 194 info!("Set idle rate for {:?} to {:?}", id, dur);
161 } 195 }
diff --git a/examples/nrf52840/src/bin/usb_hid_mouse.rs b/examples/nrf52840/src/bin/usb_hid_mouse.rs
index 3c0fc04e8..6bee4546b 100644
--- a/examples/nrf52840/src/bin/usb_hid_mouse.rs
+++ b/examples/nrf52840/src/bin/usb_hid_mouse.rs
@@ -1,6 +1,8 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4use core::sync::atomic::{AtomicU8, Ordering};
5
4use defmt::*; 6use defmt::*;
5use embassy_executor::Spawner; 7use embassy_executor::Spawner;
6use embassy_futures::join::join; 8use embassy_futures::join::join;
@@ -8,7 +10,9 @@ use embassy_nrf::usb::Driver;
8use embassy_nrf::usb::vbus_detect::HardwareVbusDetect; 10use embassy_nrf::usb::vbus_detect::HardwareVbusDetect;
9use embassy_nrf::{bind_interrupts, pac, peripherals, usb}; 11use embassy_nrf::{bind_interrupts, pac, peripherals, usb};
10use embassy_time::Timer; 12use embassy_time::Timer;
11use embassy_usb::class::hid::{HidWriter, ReportId, RequestHandler, State}; 13use embassy_usb::class::hid::{
14 HidBootProtocol, HidProtocolMode, HidSubclass, HidWriter, ReportId, RequestHandler, State,
15};
12use embassy_usb::control::OutResponse; 16use embassy_usb::control::OutResponse;
13use embassy_usb::{Builder, Config}; 17use embassy_usb::{Builder, Config};
14use usbd_hid::descriptor::{MouseReport, SerializedDescriptor}; 18use usbd_hid::descriptor::{MouseReport, SerializedDescriptor};
@@ -19,6 +23,8 @@ bind_interrupts!(struct Irqs {
19 CLOCK_POWER => usb::vbus_detect::InterruptHandler; 23 CLOCK_POWER => usb::vbus_detect::InterruptHandler;
20}); 24});
21 25
26static HID_PROTOCOL_MODE: AtomicU8 = AtomicU8::new(HidProtocolMode::Boot as u8);
27
22#[embassy_executor::main] 28#[embassy_executor::main]
23async fn main(_spawner: Spawner) { 29async fn main(_spawner: Spawner) {
24 let p = embassy_nrf::init(Default::default()); 30 let p = embassy_nrf::init(Default::default());
@@ -37,6 +43,10 @@ async fn main(_spawner: Spawner) {
37 config.serial_number = Some("12345678"); 43 config.serial_number = Some("12345678");
38 config.max_power = 100; 44 config.max_power = 100;
39 config.max_packet_size_0 = 64; 45 config.max_packet_size_0 = 64;
46 config.composite_with_iads = false;
47 config.device_class = 0;
48 config.device_sub_class = 0;
49 config.device_protocol = 0;
40 50
41 // Create embassy-usb DeviceBuilder using the driver and config. 51 // Create embassy-usb DeviceBuilder using the driver and config.
42 // It needs some buffers for building the descriptors. 52 // It needs some buffers for building the descriptors.
@@ -63,6 +73,8 @@ async fn main(_spawner: Spawner) {
63 request_handler: Some(&mut request_handler), 73 request_handler: Some(&mut request_handler),
64 poll_ms: 60, 74 poll_ms: 60,
65 max_packet_size: 8, 75 max_packet_size: 8,
76 hid_subclass: HidSubclass::Boot,
77 hid_boot_protocol: HidBootProtocol::Mouse,
66 }; 78 };
67 79
68 let mut writer = HidWriter::<_, 5>::new(&mut builder, &mut state, config); 80 let mut writer = HidWriter::<_, 5>::new(&mut builder, &mut state, config);
@@ -80,16 +92,26 @@ async fn main(_spawner: Spawner) {
80 Timer::after_millis(500).await; 92 Timer::after_millis(500).await;
81 93
82 y = -y; 94 y = -y;
83 let report = MouseReport { 95
84 buttons: 0, 96 if HID_PROTOCOL_MODE.load(Ordering::Relaxed) == HidProtocolMode::Boot as u8 {
85 x: 0, 97 let buttons = 0u8;
86 y, 98 let x = 0i8;
87 wheel: 0, 99 match writer.write(&[buttons, x as u8, y as u8]).await {
88 pan: 0, 100 Ok(()) => {}
89 }; 101 Err(e) => warn!("Failed to send boot report: {:?}", e),
90 match writer.write_serialize(&report).await { 102 }
91 Ok(()) => {} 103 } else {
92 Err(e) => warn!("Failed to send report: {:?}", e), 104 let report = MouseReport {
105 buttons: 0,
106 x: 0,
107 y,
108 wheel: 0,
109 pan: 0,
110 };
111 match writer.write_serialize(&report).await {
112 Ok(()) => {}
113 Err(e) => warn!("Failed to send report: {:?}", e),
114 }
93 } 115 }
94 } 116 }
95 }; 117 };
@@ -112,6 +134,18 @@ impl RequestHandler for MyRequestHandler {
112 OutResponse::Accepted 134 OutResponse::Accepted
113 } 135 }
114 136
137 fn get_protocol(&self) -> HidProtocolMode {
138 let protocol = HidProtocolMode::from(HID_PROTOCOL_MODE.load(Ordering::Relaxed));
139 info!("The current HID protocol mode is: {}", protocol);
140 protocol
141 }
142
143 fn set_protocol(&mut self, protocol: HidProtocolMode) -> OutResponse {
144 info!("Switching to HID protocol mode: {}", protocol);
145 HID_PROTOCOL_MODE.store(protocol as u8, Ordering::Relaxed);
146 OutResponse::Accepted
147 }
148
115 fn set_idle_ms(&mut self, id: Option<ReportId>, dur: u32) { 149 fn set_idle_ms(&mut self, id: Option<ReportId>, dur: u32) {
116 info!("Set idle rate for {:?} to {:?}", id, dur); 150 info!("Set idle rate for {:?} to {:?}", id, dur);
117 } 151 }
diff --git a/examples/rp/src/bin/usb_hid_keyboard.rs b/examples/rp/src/bin/usb_hid_keyboard.rs
index a7cb322d8..2f6d169bf 100644
--- a/examples/rp/src/bin/usb_hid_keyboard.rs
+++ b/examples/rp/src/bin/usb_hid_keyboard.rs
@@ -1,7 +1,7 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4use core::sync::atomic::{AtomicBool, Ordering}; 4use core::sync::atomic::{AtomicBool, AtomicU8, Ordering};
5 5
6use defmt::*; 6use defmt::*;
7use embassy_executor::Spawner; 7use embassy_executor::Spawner;
@@ -10,7 +10,9 @@ use embassy_rp::bind_interrupts;
10use embassy_rp::gpio::{Input, Pull}; 10use embassy_rp::gpio::{Input, Pull};
11use embassy_rp::peripherals::USB; 11use embassy_rp::peripherals::USB;
12use embassy_rp::usb::{Driver, InterruptHandler}; 12use embassy_rp::usb::{Driver, InterruptHandler};
13use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State}; 13use embassy_usb::class::hid::{
14 HidBootProtocol, HidProtocolMode, HidReaderWriter, HidSubclass, ReportId, RequestHandler, State,
15};
14use embassy_usb::control::OutResponse; 16use embassy_usb::control::OutResponse;
15use embassy_usb::{Builder, Config, Handler}; 17use embassy_usb::{Builder, Config, Handler};
16use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; 18use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor};
@@ -20,6 +22,8 @@ bind_interrupts!(struct Irqs {
20 USBCTRL_IRQ => InterruptHandler<USB>; 22 USBCTRL_IRQ => InterruptHandler<USB>;
21}); 23});
22 24
25static HID_PROTOCOL_MODE: AtomicU8 = AtomicU8::new(HidProtocolMode::Boot as u8);
26
23#[embassy_executor::main] 27#[embassy_executor::main]
24async fn main(_spawner: Spawner) { 28async fn main(_spawner: Spawner) {
25 let p = embassy_rp::init(Default::default()); 29 let p = embassy_rp::init(Default::default());
@@ -33,6 +37,10 @@ async fn main(_spawner: Spawner) {
33 config.serial_number = Some("12345678"); 37 config.serial_number = Some("12345678");
34 config.max_power = 100; 38 config.max_power = 100;
35 config.max_packet_size_0 = 64; 39 config.max_packet_size_0 = 64;
40 config.composite_with_iads = false;
41 config.device_class = 0;
42 config.device_sub_class = 0;
43 config.device_protocol = 0;
36 44
37 // Create embassy-usb DeviceBuilder using the driver and config. 45 // Create embassy-usb DeviceBuilder using the driver and config.
38 // It needs some buffers for building the descriptors. 46 // It needs some buffers for building the descriptors.
@@ -63,6 +71,8 @@ async fn main(_spawner: Spawner) {
63 request_handler: None, 71 request_handler: None,
64 poll_ms: 60, 72 poll_ms: 60,
65 max_packet_size: 64, 73 max_packet_size: 64,
74 hid_subclass: HidSubclass::Boot,
75 hid_boot_protocol: HidBootProtocol::Keyboard,
66 }; 76 };
67 let hid = HidReaderWriter::<_, 1, 8>::new(&mut builder, &mut state, config); 77 let hid = HidReaderWriter::<_, 1, 8>::new(&mut builder, &mut state, config);
68 78
@@ -86,30 +96,46 @@ async fn main(_spawner: Spawner) {
86 info!("Waiting for HIGH on pin 16"); 96 info!("Waiting for HIGH on pin 16");
87 signal_pin.wait_for_high().await; 97 signal_pin.wait_for_high().await;
88 info!("HIGH DETECTED"); 98 info!("HIGH DETECTED");
89 // Create a report with the A key pressed. (no shift modifier) 99
90 let report = KeyboardReport { 100 if HID_PROTOCOL_MODE.load(Ordering::Relaxed) == HidProtocolMode::Boot as u8 {
91 keycodes: [4, 0, 0, 0, 0, 0], 101 match writer.write(&[0, 0, 4, 0, 0, 0, 0, 0]).await {
92 leds: 0, 102 Ok(()) => {}
93 modifier: 0, 103 Err(e) => warn!("Failed to send boot report: {:?}", e),
94 reserved: 0, 104 };
95 }; 105 } else {
96 // Send the report. 106 // Create a report with the A key pressed. (no shift modifier)
97 match writer.write_serialize(&report).await { 107 let report = KeyboardReport {
98 Ok(()) => {} 108 keycodes: [4, 0, 0, 0, 0, 0],
99 Err(e) => warn!("Failed to send report: {:?}", e), 109 leds: 0,
100 }; 110 modifier: 0,
111 reserved: 0,
112 };
113 // Send the report.
114 match writer.write_serialize(&report).await {
115 Ok(()) => {}
116 Err(e) => warn!("Failed to send report: {:?}", e),
117 };
118 }
119
101 signal_pin.wait_for_low().await; 120 signal_pin.wait_for_low().await;
102 info!("LOW DETECTED"); 121 info!("LOW DETECTED");
103 let report = KeyboardReport { 122 if HID_PROTOCOL_MODE.load(Ordering::Relaxed) == HidProtocolMode::Boot as u8 {
104 keycodes: [0, 0, 0, 0, 0, 0], 123 match writer.write(&[0, 0, 0, 0, 0, 0, 0, 0]).await {
105 leds: 0, 124 Ok(()) => {}
106 modifier: 0, 125 Err(e) => warn!("Failed to send boot report: {:?}", e),
107 reserved: 0, 126 };
108 }; 127 } else {
109 match writer.write_serialize(&report).await { 128 let report = KeyboardReport {
110 Ok(()) => {} 129 keycodes: [0, 0, 0, 0, 0, 0],
111 Err(e) => warn!("Failed to send report: {:?}", e), 130 leds: 0,
112 }; 131 modifier: 0,
132 reserved: 0,
133 };
134 match writer.write_serialize(&report).await {
135 Ok(()) => {}
136 Err(e) => warn!("Failed to send report: {:?}", e),
137 };
138 }
113 } 139 }
114 }; 140 };
115 141
@@ -135,6 +161,18 @@ impl RequestHandler for MyRequestHandler {
135 OutResponse::Accepted 161 OutResponse::Accepted
136 } 162 }
137 163
164 fn get_protocol(&self) -> HidProtocolMode {
165 let protocol = HidProtocolMode::from(HID_PROTOCOL_MODE.load(Ordering::Relaxed));
166 info!("The current HID protocol mode is: {}", protocol);
167 protocol
168 }
169
170 fn set_protocol(&mut self, protocol: HidProtocolMode) -> OutResponse {
171 info!("Switching to HID protocol mode: {}", protocol);
172 HID_PROTOCOL_MODE.store(protocol as u8, Ordering::Relaxed);
173 OutResponse::Accepted
174 }
175
138 fn set_idle_ms(&mut self, id: Option<ReportId>, dur: u32) { 176 fn set_idle_ms(&mut self, id: Option<ReportId>, dur: u32) {
139 info!("Set idle rate for {:?} to {:?}", id, dur); 177 info!("Set idle rate for {:?} to {:?}", id, dur);
140 } 178 }
diff --git a/examples/rp/src/bin/usb_hid_mouse.rs b/examples/rp/src/bin/usb_hid_mouse.rs
index 4454c593c..dc331cbdd 100755
--- a/examples/rp/src/bin/usb_hid_mouse.rs
+++ b/examples/rp/src/bin/usb_hid_mouse.rs
@@ -1,7 +1,7 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4use core::sync::atomic::{AtomicBool, Ordering}; 4use core::sync::atomic::{AtomicBool, AtomicU8, Ordering};
5 5
6use defmt::*; 6use defmt::*;
7use embassy_executor::Spawner; 7use embassy_executor::Spawner;
@@ -11,7 +11,9 @@ use embassy_rp::clocks::RoscRng;
11use embassy_rp::peripherals::USB; 11use embassy_rp::peripherals::USB;
12use embassy_rp::usb::{Driver, InterruptHandler}; 12use embassy_rp::usb::{Driver, InterruptHandler};
13use embassy_time::Timer; 13use embassy_time::Timer;
14use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State}; 14use embassy_usb::class::hid::{
15 HidBootProtocol, HidProtocolMode, HidReaderWriter, HidSubclass, ReportId, RequestHandler, State,
16};
15use embassy_usb::control::OutResponse; 17use embassy_usb::control::OutResponse;
16use embassy_usb::{Builder, Config, Handler}; 18use embassy_usb::{Builder, Config, Handler};
17use rand::Rng; 19use rand::Rng;
@@ -22,6 +24,8 @@ bind_interrupts!(struct Irqs {
22 USBCTRL_IRQ => InterruptHandler<USB>; 24 USBCTRL_IRQ => InterruptHandler<USB>;
23}); 25});
24 26
27static HID_PROTOCOL_MODE: AtomicU8 = AtomicU8::new(HidProtocolMode::Boot as u8);
28
25#[embassy_executor::main] 29#[embassy_executor::main]
26async fn main(_spawner: Spawner) { 30async fn main(_spawner: Spawner) {
27 let p = embassy_rp::init(Default::default()); 31 let p = embassy_rp::init(Default::default());
@@ -35,6 +39,10 @@ async fn main(_spawner: Spawner) {
35 config.serial_number = Some("12345678"); 39 config.serial_number = Some("12345678");
36 config.max_power = 100; 40 config.max_power = 100;
37 config.max_packet_size_0 = 64; 41 config.max_packet_size_0 = 64;
42 config.composite_with_iads = false;
43 config.device_class = 0;
44 config.device_sub_class = 0;
45 config.device_protocol = 0;
38 46
39 // Create embassy-usb DeviceBuilder using the driver and config. 47 // Create embassy-usb DeviceBuilder using the driver and config.
40 // It needs some buffers for building the descriptors. 48 // It needs some buffers for building the descriptors.
@@ -65,6 +73,8 @@ async fn main(_spawner: Spawner) {
65 request_handler: None, 73 request_handler: None,
66 poll_ms: 60, 74 poll_ms: 60,
67 max_packet_size: 64, 75 max_packet_size: 64,
76 hid_subclass: HidSubclass::Boot,
77 hid_boot_protocol: HidBootProtocol::Mouse,
68 }; 78 };
69 let hid = HidReaderWriter::<_, 1, 8>::new(&mut builder, &mut state, config); 79 let hid = HidReaderWriter::<_, 1, 8>::new(&mut builder, &mut state, config);
70 80
@@ -83,17 +93,29 @@ async fn main(_spawner: Spawner) {
83 loop { 93 loop {
84 // every 1 second 94 // every 1 second
85 _ = Timer::after_secs(1).await; 95 _ = Timer::after_secs(1).await;
86 let report = MouseReport { 96
87 buttons: 0, 97 let x = rng.random_range(-100..100); // random small x movement
88 x: rng.random_range(-100..100), // random small x movement 98 let y = rng.random_range(-100..100); // random small y movement
89 y: rng.random_range(-100..100), // random small y movement 99
90 wheel: 0, 100 if HID_PROTOCOL_MODE.load(Ordering::Relaxed) == HidProtocolMode::Boot as u8 {
91 pan: 0, 101 let buttons = 0u8;
92 }; 102 match writer.write(&[buttons, x as u8, y as u8]).await {
93 // Send the report. 103 Ok(()) => {}
94 match writer.write_serialize(&report).await { 104 Err(e) => warn!("Failed to send boot report: {:?}", e),
95 Ok(()) => {} 105 }
96 Err(e) => warn!("Failed to send report: {:?}", e), 106 } else {
107 let report = MouseReport {
108 buttons: 0,
109 x,
110 y,
111 wheel: 0,
112 pan: 0,
113 };
114 // Send the report.
115 match writer.write_serialize(&report).await {
116 Ok(()) => {}
117 Err(e) => warn!("Failed to send report: {:?}", e),
118 }
97 } 119 }
98 } 120 }
99 }; 121 };
@@ -120,6 +142,18 @@ impl RequestHandler for MyRequestHandler {
120 OutResponse::Accepted 142 OutResponse::Accepted
121 } 143 }
122 144
145 fn get_protocol(&self) -> HidProtocolMode {
146 let protocol = HidProtocolMode::from(HID_PROTOCOL_MODE.load(Ordering::Relaxed));
147 info!("The current HID protocol mode is: {}", protocol);
148 protocol
149 }
150
151 fn set_protocol(&mut self, protocol: HidProtocolMode) -> OutResponse {
152 info!("Switching to HID protocol mode: {}", protocol);
153 HID_PROTOCOL_MODE.store(protocol as u8, Ordering::Relaxed);
154 OutResponse::Accepted
155 }
156
123 fn set_idle_ms(&mut self, id: Option<ReportId>, dur: u32) { 157 fn set_idle_ms(&mut self, id: Option<ReportId>, dur: u32) {
124 info!("Set idle rate for {:?} to {:?}", id, dur); 158 info!("Set idle rate for {:?} to {:?}", id, dur);
125 } 159 }
diff --git a/examples/rp235x/src/bin/usb_hid_keyboard.rs b/examples/rp235x/src/bin/usb_hid_keyboard.rs
index 6f496e23a..d8f64c470 100644
--- a/examples/rp235x/src/bin/usb_hid_keyboard.rs
+++ b/examples/rp235x/src/bin/usb_hid_keyboard.rs
@@ -1,7 +1,7 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4use core::sync::atomic::{AtomicBool, Ordering}; 4use core::sync::atomic::{AtomicBool, AtomicU8, Ordering};
5 5
6use defmt::*; 6use defmt::*;
7use embassy_executor::Spawner; 7use embassy_executor::Spawner;
@@ -10,7 +10,9 @@ use embassy_rp::bind_interrupts;
10use embassy_rp::gpio::{Input, Pull}; 10use embassy_rp::gpio::{Input, Pull};
11use embassy_rp::peripherals::USB; 11use embassy_rp::peripherals::USB;
12use embassy_rp::usb::{Driver as UsbDriver, InterruptHandler}; 12use embassy_rp::usb::{Driver as UsbDriver, InterruptHandler};
13use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State as HidState}; 13use embassy_usb::class::hid::{
14 HidBootProtocol, HidProtocolMode, HidReaderWriter, HidSubclass, ReportId, RequestHandler, State as HidState,
15};
14use embassy_usb::control::OutResponse; 16use embassy_usb::control::OutResponse;
15use embassy_usb::{Builder, Config, Handler}; 17use embassy_usb::{Builder, Config, Handler};
16use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; 18use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor};
@@ -20,6 +22,8 @@ bind_interrupts!(struct Irqs {
20 USBCTRL_IRQ => InterruptHandler<USB>; 22 USBCTRL_IRQ => InterruptHandler<USB>;
21}); 23});
22 24
25static HID_PROTOCOL_MODE: AtomicU8 = AtomicU8::new(HidProtocolMode::Boot as u8);
26
23#[embassy_executor::main] 27#[embassy_executor::main]
24async fn main(_spawner: Spawner) { 28async fn main(_spawner: Spawner) {
25 let p = embassy_rp::init(Default::default()); 29 let p = embassy_rp::init(Default::default());
@@ -33,6 +37,10 @@ async fn main(_spawner: Spawner) {
33 config.serial_number = Some("12345678"); 37 config.serial_number = Some("12345678");
34 config.max_power = 100; 38 config.max_power = 100;
35 config.max_packet_size_0 = 64; 39 config.max_packet_size_0 = 64;
40 config.composite_with_iads = false;
41 config.device_class = 0;
42 config.device_sub_class = 0;
43 config.device_protocol = 0;
36 44
37 // Create embassy-usb DeviceBuilder using the driver and config. 45 // Create embassy-usb DeviceBuilder using the driver and config.
38 // It needs some buffers for building the descriptors. 46 // It needs some buffers for building the descriptors.
@@ -63,6 +71,8 @@ async fn main(_spawner: Spawner) {
63 request_handler: None, 71 request_handler: None,
64 poll_ms: 60, 72 poll_ms: 60,
65 max_packet_size: 64, 73 max_packet_size: 64,
74 hid_subclass: HidSubclass::Boot,
75 hid_boot_protocol: HidBootProtocol::Keyboard,
66 }; 76 };
67 let hid = HidReaderWriter::<_, 1, 8>::new(&mut builder, &mut state, config); 77 let hid = HidReaderWriter::<_, 1, 8>::new(&mut builder, &mut state, config);
68 78
@@ -86,30 +96,45 @@ async fn main(_spawner: Spawner) {
86 info!("Waiting for HIGH on pin 16"); 96 info!("Waiting for HIGH on pin 16");
87 signal_pin.wait_for_high().await; 97 signal_pin.wait_for_high().await;
88 info!("HIGH DETECTED"); 98 info!("HIGH DETECTED");
89 // Create a report with the A key pressed. (no shift modifier) 99
90 let report = KeyboardReport { 100 if HID_PROTOCOL_MODE.load(Ordering::Relaxed) == HidProtocolMode::Boot as u8 {
91 keycodes: [4, 0, 0, 0, 0, 0], 101 match writer.write(&[0, 0, 4, 0, 0, 0, 0, 0]).await {
92 leds: 0, 102 Ok(()) => {}
93 modifier: 0, 103 Err(e) => warn!("Failed to send boot report: {:?}", e),
94 reserved: 0, 104 };
95 }; 105 } else {
96 // Send the report. 106 // Create a report with the A key pressed. (no shift modifier)
97 match writer.write_serialize(&report).await { 107 let report = KeyboardReport {
98 Ok(()) => {} 108 keycodes: [4, 0, 0, 0, 0, 0],
99 Err(e) => warn!("Failed to send report: {:?}", e), 109 leds: 0,
100 }; 110 modifier: 0,
111 reserved: 0,
112 };
113 // Send the report.
114 match writer.write_serialize(&report).await {
115 Ok(()) => {}
116 Err(e) => warn!("Failed to send report: {:?}", e),
117 };
118 }
101 signal_pin.wait_for_low().await; 119 signal_pin.wait_for_low().await;
102 info!("LOW DETECTED"); 120 info!("LOW DETECTED");
103 let report = KeyboardReport { 121 if HID_PROTOCOL_MODE.load(Ordering::Relaxed) == HidProtocolMode::Boot as u8 {
104 keycodes: [0, 0, 0, 0, 0, 0], 122 match writer.write(&[0, 0, 0, 0, 0, 0, 0, 0]).await {
105 leds: 0, 123 Ok(()) => {}
106 modifier: 0, 124 Err(e) => warn!("Failed to send boot report: {:?}", e),
107 reserved: 0, 125 };
108 }; 126 } else {
109 match writer.write_serialize(&report).await { 127 let report = KeyboardReport {
110 Ok(()) => {} 128 keycodes: [0, 0, 0, 0, 0, 0],
111 Err(e) => warn!("Failed to send report: {:?}", e), 129 leds: 0,
112 }; 130 modifier: 0,
131 reserved: 0,
132 };
133 match writer.write_serialize(&report).await {
134 Ok(()) => {}
135 Err(e) => warn!("Failed to send report: {:?}", e),
136 };
137 }
113 } 138 }
114 }; 139 };
115 140
@@ -135,6 +160,18 @@ impl RequestHandler for MyRequestHandler {
135 OutResponse::Accepted 160 OutResponse::Accepted
136 } 161 }
137 162
163 fn get_protocol(&self) -> HidProtocolMode {
164 let protocol = HidProtocolMode::from(HID_PROTOCOL_MODE.load(Ordering::Relaxed));
165 info!("The current HID protocol mode is: {}", protocol);
166 protocol
167 }
168
169 fn set_protocol(&mut self, protocol: HidProtocolMode) -> OutResponse {
170 info!("Switching to HID protocol mode: {}", protocol);
171 HID_PROTOCOL_MODE.store(protocol as u8, Ordering::Relaxed);
172 OutResponse::Accepted
173 }
174
138 fn set_idle_ms(&mut self, id: Option<ReportId>, dur: u32) { 175 fn set_idle_ms(&mut self, id: Option<ReportId>, dur: u32) {
139 info!("Set idle rate for {:?} to {:?}", id, dur); 176 info!("Set idle rate for {:?} to {:?}", id, dur);
140 } 177 }
diff --git a/examples/stm32f4/src/bin/usb_hid_keyboard.rs b/examples/stm32f4/src/bin/usb_hid_keyboard.rs
index a3afb887c..9971e43f5 100644
--- a/examples/stm32f4/src/bin/usb_hid_keyboard.rs
+++ b/examples/stm32f4/src/bin/usb_hid_keyboard.rs
@@ -1,7 +1,7 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4use core::sync::atomic::{AtomicBool, Ordering}; 4use core::sync::atomic::{AtomicBool, AtomicU8, Ordering};
5 5
6use defmt::*; 6use defmt::*;
7use embassy_executor::Spawner; 7use embassy_executor::Spawner;
@@ -11,7 +11,9 @@ use embassy_stm32::gpio::Pull;
11use embassy_stm32::time::Hertz; 11use embassy_stm32::time::Hertz;
12use embassy_stm32::usb::Driver; 12use embassy_stm32::usb::Driver;
13use embassy_stm32::{Config, bind_interrupts, peripherals, usb}; 13use embassy_stm32::{Config, bind_interrupts, peripherals, usb};
14use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State}; 14use embassy_usb::class::hid::{
15 HidBootProtocol, HidProtocolMode, HidReaderWriter, HidSubclass, ReportId, RequestHandler, State,
16};
15use embassy_usb::control::OutResponse; 17use embassy_usb::control::OutResponse;
16use embassy_usb::{Builder, Handler}; 18use embassy_usb::{Builder, Handler};
17use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; 19use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor};
@@ -21,6 +23,8 @@ bind_interrupts!(struct Irqs {
21 OTG_FS => usb::InterruptHandler<peripherals::USB_OTG_FS>; 23 OTG_FS => usb::InterruptHandler<peripherals::USB_OTG_FS>;
22}); 24});
23 25
26static HID_PROTOCOL_MODE: AtomicU8 = AtomicU8::new(HidProtocolMode::Boot as u8);
27
24// If you are trying this and your USB device doesn't connect, the most 28// If you are trying this and your USB device doesn't connect, the most
25// common issues are the RCC config and vbus_detection 29// common issues are the RCC config and vbus_detection
26// 30//
@@ -70,6 +74,10 @@ async fn main(_spawner: Spawner) {
70 config.serial_number = Some("12345678"); 74 config.serial_number = Some("12345678");
71 config.max_power = 100; 75 config.max_power = 100;
72 config.max_packet_size_0 = 64; 76 config.max_packet_size_0 = 64;
77 config.composite_with_iads = false;
78 config.device_class = 0;
79 config.device_sub_class = 0;
80 config.device_protocol = 0;
73 81
74 // Create embassy-usb DeviceBuilder using the driver and config. 82 // Create embassy-usb DeviceBuilder using the driver and config.
75 // It needs some buffers for building the descriptors. 83 // It needs some buffers for building the descriptors.
@@ -101,6 +109,8 @@ async fn main(_spawner: Spawner) {
101 request_handler: None, 109 request_handler: None,
102 poll_ms: 60, 110 poll_ms: 60,
103 max_packet_size: 8, 111 max_packet_size: 8,
112 hid_subclass: HidSubclass::Boot,
113 hid_boot_protocol: HidBootProtocol::Keyboard,
104 }; 114 };
105 115
106 let hid = HidReaderWriter::<_, 1, 8>::new(&mut builder, &mut state, config); 116 let hid = HidReaderWriter::<_, 1, 8>::new(&mut builder, &mut state, config);
@@ -121,32 +131,46 @@ async fn main(_spawner: Spawner) {
121 button.wait_for_rising_edge().await; 131 button.wait_for_rising_edge().await;
122 // signal_pin.wait_for_high().await; 132 // signal_pin.wait_for_high().await;
123 info!("Button pressed!"); 133 info!("Button pressed!");
124 // Create a report with the A key pressed. (no shift modifier) 134 if HID_PROTOCOL_MODE.load(Ordering::Relaxed) == HidProtocolMode::Boot as u8 {
125 let report = KeyboardReport { 135 match writer.write(&[0, 0, 4, 0, 0, 0, 0, 0]).await {
126 keycodes: [4, 0, 0, 0, 0, 0], 136 Ok(()) => {}
127 leds: 0, 137 Err(e) => warn!("Failed to send boot report: {:?}", e),
128 modifier: 0, 138 };
129 reserved: 0, 139 } else {
130 }; 140 // Create a report with the A key pressed. (no shift modifier)
131 // Send the report. 141 let report = KeyboardReport {
132 match writer.write_serialize(&report).await { 142 keycodes: [4, 0, 0, 0, 0, 0],
133 Ok(()) => {} 143 leds: 0,
134 Err(e) => warn!("Failed to send report: {:?}", e), 144 modifier: 0,
135 }; 145 reserved: 0,
146 };
147 // Send the report.
148 match writer.write_serialize(&report).await {
149 Ok(()) => {}
150 Err(e) => warn!("Failed to send report: {:?}", e),
151 };
152 }
136 153
137 button.wait_for_falling_edge().await; 154 button.wait_for_falling_edge().await;
138 // signal_pin.wait_for_low().await; 155 // signal_pin.wait_for_low().await;
139 info!("Button released!"); 156 info!("Button released!");
140 let report = KeyboardReport { 157 if HID_PROTOCOL_MODE.load(Ordering::Relaxed) == HidProtocolMode::Boot as u8 {
141 keycodes: [0, 0, 0, 0, 0, 0], 158 match writer.write(&[0, 0, 0, 0, 0, 0, 0, 0]).await {
142 leds: 0, 159 Ok(()) => {}
143 modifier: 0, 160 Err(e) => warn!("Failed to send boot report: {:?}", e),
144 reserved: 0, 161 };
145 }; 162 } else {
146 match writer.write_serialize(&report).await { 163 let report = KeyboardReport {
147 Ok(()) => {} 164 keycodes: [0, 0, 0, 0, 0, 0],
148 Err(e) => warn!("Failed to send report: {:?}", e), 165 leds: 0,
149 }; 166 modifier: 0,
167 reserved: 0,
168 };
169 match writer.write_serialize(&report).await {
170 Ok(()) => {}
171 Err(e) => warn!("Failed to send report: {:?}", e),
172 };
173 }
150 } 174 }
151 }; 175 };
152 176
@@ -172,6 +196,18 @@ impl RequestHandler for MyRequestHandler {
172 OutResponse::Accepted 196 OutResponse::Accepted
173 } 197 }
174 198
199 fn get_protocol(&self) -> HidProtocolMode {
200 let protocol = HidProtocolMode::from(HID_PROTOCOL_MODE.load(Ordering::Relaxed));
201 info!("The current HID protocol mode is: {}", protocol);
202 protocol
203 }
204
205 fn set_protocol(&mut self, protocol: HidProtocolMode) -> OutResponse {
206 info!("Switching to HID protocol mode: {}", protocol);
207 HID_PROTOCOL_MODE.store(protocol as u8, Ordering::Relaxed);
208 OutResponse::Accepted
209 }
210
175 fn set_idle_ms(&mut self, id: Option<ReportId>, dur: u32) { 211 fn set_idle_ms(&mut self, id: Option<ReportId>, dur: u32) {
176 info!("Set idle rate for {:?} to {:?}", id, dur); 212 info!("Set idle rate for {:?} to {:?}", id, dur);
177 } 213 }
diff --git a/examples/stm32f4/src/bin/usb_hid_mouse.rs b/examples/stm32f4/src/bin/usb_hid_mouse.rs
index 162a035f2..e83d01f88 100644
--- a/examples/stm32f4/src/bin/usb_hid_mouse.rs
+++ b/examples/stm32f4/src/bin/usb_hid_mouse.rs
@@ -1,6 +1,8 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4use core::sync::atomic::{AtomicU8, Ordering};
5
4use defmt::*; 6use defmt::*;
5use embassy_executor::Spawner; 7use embassy_executor::Spawner;
6use embassy_futures::join::join; 8use embassy_futures::join::join;
@@ -9,7 +11,9 @@ use embassy_stm32::usb::Driver;
9use embassy_stm32::{Config, bind_interrupts, peripherals, usb}; 11use embassy_stm32::{Config, bind_interrupts, peripherals, usb};
10use embassy_time::Timer; 12use embassy_time::Timer;
11use embassy_usb::Builder; 13use embassy_usb::Builder;
12use embassy_usb::class::hid::{HidWriter, ReportId, RequestHandler, State}; 14use embassy_usb::class::hid::{
15 HidBootProtocol, HidProtocolMode, HidSubclass, HidWriter, ReportId, RequestHandler, State,
16};
13use embassy_usb::control::OutResponse; 17use embassy_usb::control::OutResponse;
14use usbd_hid::descriptor::{MouseReport, SerializedDescriptor}; 18use usbd_hid::descriptor::{MouseReport, SerializedDescriptor};
15use {defmt_rtt as _, panic_probe as _}; 19use {defmt_rtt as _, panic_probe as _};
@@ -18,6 +22,8 @@ bind_interrupts!(struct Irqs {
18 OTG_FS => usb::InterruptHandler<peripherals::USB_OTG_FS>; 22 OTG_FS => usb::InterruptHandler<peripherals::USB_OTG_FS>;
19}); 23});
20 24
25static HID_PROTOCOL_MODE: AtomicU8 = AtomicU8::new(HidProtocolMode::Boot as u8);
26
21// If you are trying this and your USB device doesn't connect, the most 27// If you are trying this and your USB device doesn't connect, the most
22// common issues are the RCC config and vbus_detection 28// common issues are the RCC config and vbus_detection
23// 29//
@@ -65,6 +71,10 @@ async fn main(_spawner: Spawner) {
65 config.manufacturer = Some("Embassy"); 71 config.manufacturer = Some("Embassy");
66 config.product = Some("HID mouse example"); 72 config.product = Some("HID mouse example");
67 config.serial_number = Some("12345678"); 73 config.serial_number = Some("12345678");
74 config.composite_with_iads = false;
75 config.device_class = 0;
76 config.device_sub_class = 0;
77 config.device_protocol = 0;
68 78
69 // Create embassy-usb DeviceBuilder using the driver and config. 79 // Create embassy-usb DeviceBuilder using the driver and config.
70 // It needs some buffers for building the descriptors. 80 // It needs some buffers for building the descriptors.
@@ -91,6 +101,8 @@ async fn main(_spawner: Spawner) {
91 request_handler: Some(&mut request_handler), 101 request_handler: Some(&mut request_handler),
92 poll_ms: 60, 102 poll_ms: 60,
93 max_packet_size: 8, 103 max_packet_size: 8,
104 hid_subclass: HidSubclass::Boot,
105 hid_boot_protocol: HidBootProtocol::Mouse,
94 }; 106 };
95 107
96 let mut writer = HidWriter::<_, 5>::new(&mut builder, &mut state, config); 108 let mut writer = HidWriter::<_, 5>::new(&mut builder, &mut state, config);
@@ -108,16 +120,26 @@ async fn main(_spawner: Spawner) {
108 Timer::after_millis(500).await; 120 Timer::after_millis(500).await;
109 121
110 y = -y; 122 y = -y;
111 let report = MouseReport { 123
112 buttons: 0, 124 if HID_PROTOCOL_MODE.load(Ordering::Relaxed) == HidProtocolMode::Boot as u8 {
113 x: 0, 125 let buttons = 0u8;
114 y, 126 let x = 0i8;
115 wheel: 0, 127 match writer.write(&[buttons, x as u8, y as u8]).await {
116 pan: 0, 128 Ok(()) => {}
117 }; 129 Err(e) => warn!("Failed to send boot report: {:?}", e),
118 match writer.write_serialize(&report).await { 130 }
119 Ok(()) => {} 131 } else {
120 Err(e) => warn!("Failed to send report: {:?}", e), 132 let report = MouseReport {
133 buttons: 0,
134 x: 0,
135 y,
136 wheel: 0,
137 pan: 0,
138 };
139 match writer.write_serialize(&report).await {
140 Ok(()) => {}
141 Err(e) => warn!("Failed to send report: {:?}", e),
142 }
121 } 143 }
122 } 144 }
123 }; 145 };
@@ -140,6 +162,18 @@ impl RequestHandler for MyRequestHandler {
140 OutResponse::Accepted 162 OutResponse::Accepted
141 } 163 }
142 164
165 fn get_protocol(&self) -> HidProtocolMode {
166 let protocol = HidProtocolMode::from(HID_PROTOCOL_MODE.load(Ordering::Relaxed));
167 info!("The current HID protocol mode is: {}", protocol);
168 protocol
169 }
170
171 fn set_protocol(&mut self, protocol: HidProtocolMode) -> OutResponse {
172 info!("Switching to HID protocol mode: {}", protocol);
173 HID_PROTOCOL_MODE.store(protocol as u8, Ordering::Relaxed);
174 OutResponse::Accepted
175 }
176
143 fn set_idle_ms(&mut self, id: Option<ReportId>, dur: u32) { 177 fn set_idle_ms(&mut self, id: Option<ReportId>, dur: u32) {
144 info!("Set idle rate for {:?} to {:?}", id, dur); 178 info!("Set idle rate for {:?} to {:?}", id, dur);
145 } 179 }
diff --git a/examples/stm32l5/src/bin/usb_hid_mouse.rs b/examples/stm32l5/src/bin/usb_hid_mouse.rs
index b721f5b2e..d8f2de941 100644
--- a/examples/stm32l5/src/bin/usb_hid_mouse.rs
+++ b/examples/stm32l5/src/bin/usb_hid_mouse.rs
@@ -1,6 +1,8 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4use core::sync::atomic::{AtomicU8, Ordering};
5
4use defmt::*; 6use defmt::*;
5use embassy_executor::Spawner; 7use embassy_executor::Spawner;
6use embassy_futures::join::join; 8use embassy_futures::join::join;
@@ -8,7 +10,9 @@ use embassy_stm32::usb::Driver;
8use embassy_stm32::{Config, bind_interrupts, peripherals, usb}; 10use embassy_stm32::{Config, bind_interrupts, peripherals, usb};
9use embassy_time::Timer; 11use embassy_time::Timer;
10use embassy_usb::Builder; 12use embassy_usb::Builder;
11use embassy_usb::class::hid::{HidWriter, ReportId, RequestHandler, State}; 13use embassy_usb::class::hid::{
14 HidBootProtocol, HidProtocolMode, HidSubclass, HidWriter, ReportId, RequestHandler, State,
15};
12use embassy_usb::control::OutResponse; 16use embassy_usb::control::OutResponse;
13use usbd_hid::descriptor::{MouseReport, SerializedDescriptor}; 17use usbd_hid::descriptor::{MouseReport, SerializedDescriptor};
14use {defmt_rtt as _, panic_probe as _}; 18use {defmt_rtt as _, panic_probe as _};
@@ -17,6 +21,8 @@ bind_interrupts!(struct Irqs {
17 USB_FS => usb::InterruptHandler<peripherals::USB>; 21 USB_FS => usb::InterruptHandler<peripherals::USB>;
18}); 22});
19 23
24static HID_PROTOCOL_MODE: AtomicU8 = AtomicU8::new(HidProtocolMode::Boot as u8);
25
20#[embassy_executor::main] 26#[embassy_executor::main]
21async fn main(_spawner: Spawner) { 27async fn main(_spawner: Spawner) {
22 let mut config = Config::default(); 28 let mut config = Config::default();
@@ -48,6 +54,10 @@ async fn main(_spawner: Spawner) {
48 config.serial_number = Some("12345678"); 54 config.serial_number = Some("12345678");
49 config.max_power = 100; 55 config.max_power = 100;
50 config.max_packet_size_0 = 64; 56 config.max_packet_size_0 = 64;
57 config.composite_with_iads = false;
58 config.device_class = 0;
59 config.device_sub_class = 0;
60 config.device_protocol = 0;
51 61
52 // Create embassy-usb DeviceBuilder using the driver and config. 62 // Create embassy-usb DeviceBuilder using the driver and config.
53 // It needs some buffers for building the descriptors. 63 // It needs some buffers for building the descriptors.
@@ -73,6 +83,8 @@ async fn main(_spawner: Spawner) {
73 request_handler: Some(&mut request_handler), 83 request_handler: Some(&mut request_handler),
74 poll_ms: 60, 84 poll_ms: 60,
75 max_packet_size: 8, 85 max_packet_size: 8,
86 hid_subclass: HidSubclass::Boot,
87 hid_boot_protocol: HidBootProtocol::Mouse,
76 }; 88 };
77 89
78 let mut writer = HidWriter::<_, 5>::new(&mut builder, &mut state, config); 90 let mut writer = HidWriter::<_, 5>::new(&mut builder, &mut state, config);
@@ -90,16 +102,26 @@ async fn main(_spawner: Spawner) {
90 Timer::after_millis(500).await; 102 Timer::after_millis(500).await;
91 103
92 y = -y; 104 y = -y;
93 let report = MouseReport { 105
94 buttons: 0, 106 if HID_PROTOCOL_MODE.load(Ordering::Relaxed) == HidProtocolMode::Boot as u8 {
95 x: 0, 107 let buttons = 0u8;
96 y, 108 let x = 0i8;
97 wheel: 0, 109 match writer.write(&[buttons, x as u8, y as u8]).await {
98 pan: 0, 110 Ok(()) => {}
99 }; 111 Err(e) => warn!("Failed to send boot report: {:?}", e),
100 match writer.write_serialize(&report).await { 112 }
101 Ok(()) => {} 113 } else {
102 Err(e) => warn!("Failed to send report: {:?}", e), 114 let report = MouseReport {
115 buttons: 0,
116 x: 0,
117 y,
118 wheel: 0,
119 pan: 0,
120 };
121 match writer.write_serialize(&report).await {
122 Ok(()) => {}
123 Err(e) => warn!("Failed to send report: {:?}", e),
124 }
103 } 125 }
104 } 126 }
105 }; 127 };
@@ -122,6 +144,18 @@ impl RequestHandler for MyRequestHandler {
122 OutResponse::Accepted 144 OutResponse::Accepted
123 } 145 }
124 146
147 fn get_protocol(&self) -> HidProtocolMode {
148 let protocol = HidProtocolMode::from(HID_PROTOCOL_MODE.load(Ordering::Relaxed));
149 info!("The current HID protocol mode is: {}", protocol);
150 protocol
151 }
152
153 fn set_protocol(&mut self, protocol: HidProtocolMode) -> OutResponse {
154 info!("Switching to HID protocol mode: {}", protocol);
155 HID_PROTOCOL_MODE.store(protocol as u8, Ordering::Relaxed);
156 OutResponse::Accepted
157 }
158
125 fn set_idle_ms(&mut self, id: Option<ReportId>, dur: u32) { 159 fn set_idle_ms(&mut self, id: Option<ReportId>, dur: u32) {
126 info!("Set idle rate for {:?} to {:?}", id, dur); 160 info!("Set idle rate for {:?} to {:?}", id, dur);
127 } 161 }