aboutsummaryrefslogtreecommitdiff
path: root/examples/stm32f4
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/stm32f4
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/stm32f4')
-rw-r--r--examples/stm32f4/src/bin/usb_hid_keyboard.rs84
-rw-r--r--examples/stm32f4/src/bin/usb_hid_mouse.rs56
2 files changed, 105 insertions, 35 deletions
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 }