diff options
| author | Ulf Lilleengen <[email protected]> | 2025-11-12 08:24:18 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-11-12 08:24:18 +0000 |
| commit | 7201c6deb9d8c2b1fb380a58b9e879e394ed5f24 (patch) | |
| tree | d33ddfb6b8038a25e319495649844c798689fdef /examples | |
| parent | 0d1fc76a10863b85961a63db4a9e1e2807f35957 (diff) | |
| parent | a60b268186ff3accf68a3a6009d96ffca12221bd (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.rs | 58 | ||||
| -rw-r--r-- | examples/nrf52840/src/bin/usb_hid_mouse.rs | 56 | ||||
| -rw-r--r-- | examples/rp/src/bin/usb_hid_keyboard.rs | 86 | ||||
| -rwxr-xr-x | examples/rp/src/bin/usb_hid_mouse.rs | 60 | ||||
| -rw-r--r-- | examples/rp235x/src/bin/usb_hid_keyboard.rs | 85 | ||||
| -rw-r--r-- | examples/stm32f4/src/bin/usb_hid_keyboard.rs | 84 | ||||
| -rw-r--r-- | examples/stm32f4/src/bin/usb_hid_mouse.rs | 56 | ||||
| -rw-r--r-- | examples/stm32l5/src/bin/usb_hid_mouse.rs | 56 |
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 | ||
| 4 | use core::sync::atomic::{AtomicBool, Ordering}; | 4 | use core::sync::atomic::{AtomicBool, AtomicU8, Ordering}; |
| 5 | 5 | ||
| 6 | use defmt::*; | 6 | use defmt::*; |
| 7 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
| @@ -13,7 +13,9 @@ use embassy_nrf::usb::vbus_detect::HardwareVbusDetect; | |||
| 13 | use embassy_nrf::{bind_interrupts, pac, peripherals, usb}; | 13 | use embassy_nrf::{bind_interrupts, pac, peripherals, usb}; |
| 14 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | 14 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; |
| 15 | use embassy_sync::signal::Signal; | 15 | use embassy_sync::signal::Signal; |
| 16 | use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State}; | 16 | use embassy_usb::class::hid::{ |
| 17 | HidBootProtocol, HidProtocolMode, HidReaderWriter, HidSubclass, ReportId, RequestHandler, State, | ||
| 18 | }; | ||
| 17 | use embassy_usb::control::OutResponse; | 19 | use embassy_usb::control::OutResponse; |
| 18 | use embassy_usb::{Builder, Config, Handler}; | 20 | use embassy_usb::{Builder, Config, Handler}; |
| 19 | use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; | 21 | use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; |
| @@ -26,6 +28,8 @@ bind_interrupts!(struct Irqs { | |||
| 26 | 28 | ||
| 27 | static SUSPENDED: AtomicBool = AtomicBool::new(false); | 29 | static SUSPENDED: AtomicBool = AtomicBool::new(false); |
| 28 | 30 | ||
| 31 | static HID_PROTOCOL_MODE: AtomicU8 = AtomicU8::new(HidProtocolMode::Boot as u8); | ||
| 32 | |||
| 29 | #[embassy_executor::main] | 33 | #[embassy_executor::main] |
| 30 | async fn main(_spawner: Spawner) { | 34 | async 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 | ||
| 4 | use core::sync::atomic::{AtomicU8, Ordering}; | ||
| 5 | |||
| 4 | use defmt::*; | 6 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
| 6 | use embassy_futures::join::join; | 8 | use embassy_futures::join::join; |
| @@ -8,7 +10,9 @@ use embassy_nrf::usb::Driver; | |||
| 8 | use embassy_nrf::usb::vbus_detect::HardwareVbusDetect; | 10 | use embassy_nrf::usb::vbus_detect::HardwareVbusDetect; |
| 9 | use embassy_nrf::{bind_interrupts, pac, peripherals, usb}; | 11 | use embassy_nrf::{bind_interrupts, pac, peripherals, usb}; |
| 10 | use embassy_time::Timer; | 12 | use embassy_time::Timer; |
| 11 | use embassy_usb::class::hid::{HidWriter, ReportId, RequestHandler, State}; | 13 | use embassy_usb::class::hid::{ |
| 14 | HidBootProtocol, HidProtocolMode, HidSubclass, HidWriter, ReportId, RequestHandler, State, | ||
| 15 | }; | ||
| 12 | use embassy_usb::control::OutResponse; | 16 | use embassy_usb::control::OutResponse; |
| 13 | use embassy_usb::{Builder, Config}; | 17 | use embassy_usb::{Builder, Config}; |
| 14 | use usbd_hid::descriptor::{MouseReport, SerializedDescriptor}; | 18 | use 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 | ||
| 26 | static HID_PROTOCOL_MODE: AtomicU8 = AtomicU8::new(HidProtocolMode::Boot as u8); | ||
| 27 | |||
| 22 | #[embassy_executor::main] | 28 | #[embassy_executor::main] |
| 23 | async fn main(_spawner: Spawner) { | 29 | async 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 | ||
| 4 | use core::sync::atomic::{AtomicBool, Ordering}; | 4 | use core::sync::atomic::{AtomicBool, AtomicU8, Ordering}; |
| 5 | 5 | ||
| 6 | use defmt::*; | 6 | use defmt::*; |
| 7 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
| @@ -10,7 +10,9 @@ use embassy_rp::bind_interrupts; | |||
| 10 | use embassy_rp::gpio::{Input, Pull}; | 10 | use embassy_rp::gpio::{Input, Pull}; |
| 11 | use embassy_rp::peripherals::USB; | 11 | use embassy_rp::peripherals::USB; |
| 12 | use embassy_rp::usb::{Driver, InterruptHandler}; | 12 | use embassy_rp::usb::{Driver, InterruptHandler}; |
| 13 | use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State}; | 13 | use embassy_usb::class::hid::{ |
| 14 | HidBootProtocol, HidProtocolMode, HidReaderWriter, HidSubclass, ReportId, RequestHandler, State, | ||
| 15 | }; | ||
| 14 | use embassy_usb::control::OutResponse; | 16 | use embassy_usb::control::OutResponse; |
| 15 | use embassy_usb::{Builder, Config, Handler}; | 17 | use embassy_usb::{Builder, Config, Handler}; |
| 16 | use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; | 18 | use 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 | ||
| 25 | static HID_PROTOCOL_MODE: AtomicU8 = AtomicU8::new(HidProtocolMode::Boot as u8); | ||
| 26 | |||
| 23 | #[embassy_executor::main] | 27 | #[embassy_executor::main] |
| 24 | async fn main(_spawner: Spawner) { | 28 | async 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 | ||
| 4 | use core::sync::atomic::{AtomicBool, Ordering}; | 4 | use core::sync::atomic::{AtomicBool, AtomicU8, Ordering}; |
| 5 | 5 | ||
| 6 | use defmt::*; | 6 | use defmt::*; |
| 7 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
| @@ -11,7 +11,9 @@ use embassy_rp::clocks::RoscRng; | |||
| 11 | use embassy_rp::peripherals::USB; | 11 | use embassy_rp::peripherals::USB; |
| 12 | use embassy_rp::usb::{Driver, InterruptHandler}; | 12 | use embassy_rp::usb::{Driver, InterruptHandler}; |
| 13 | use embassy_time::Timer; | 13 | use embassy_time::Timer; |
| 14 | use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State}; | 14 | use embassy_usb::class::hid::{ |
| 15 | HidBootProtocol, HidProtocolMode, HidReaderWriter, HidSubclass, ReportId, RequestHandler, State, | ||
| 16 | }; | ||
| 15 | use embassy_usb::control::OutResponse; | 17 | use embassy_usb::control::OutResponse; |
| 16 | use embassy_usb::{Builder, Config, Handler}; | 18 | use embassy_usb::{Builder, Config, Handler}; |
| 17 | use rand::Rng; | 19 | use rand::Rng; |
| @@ -22,6 +24,8 @@ bind_interrupts!(struct Irqs { | |||
| 22 | USBCTRL_IRQ => InterruptHandler<USB>; | 24 | USBCTRL_IRQ => InterruptHandler<USB>; |
| 23 | }); | 25 | }); |
| 24 | 26 | ||
| 27 | static HID_PROTOCOL_MODE: AtomicU8 = AtomicU8::new(HidProtocolMode::Boot as u8); | ||
| 28 | |||
| 25 | #[embassy_executor::main] | 29 | #[embassy_executor::main] |
| 26 | async fn main(_spawner: Spawner) { | 30 | async 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 | ||
| 4 | use core::sync::atomic::{AtomicBool, Ordering}; | 4 | use core::sync::atomic::{AtomicBool, AtomicU8, Ordering}; |
| 5 | 5 | ||
| 6 | use defmt::*; | 6 | use defmt::*; |
| 7 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
| @@ -10,7 +10,9 @@ use embassy_rp::bind_interrupts; | |||
| 10 | use embassy_rp::gpio::{Input, Pull}; | 10 | use embassy_rp::gpio::{Input, Pull}; |
| 11 | use embassy_rp::peripherals::USB; | 11 | use embassy_rp::peripherals::USB; |
| 12 | use embassy_rp::usb::{Driver as UsbDriver, InterruptHandler}; | 12 | use embassy_rp::usb::{Driver as UsbDriver, InterruptHandler}; |
| 13 | use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State as HidState}; | 13 | use embassy_usb::class::hid::{ |
| 14 | HidBootProtocol, HidProtocolMode, HidReaderWriter, HidSubclass, ReportId, RequestHandler, State as HidState, | ||
| 15 | }; | ||
| 14 | use embassy_usb::control::OutResponse; | 16 | use embassy_usb::control::OutResponse; |
| 15 | use embassy_usb::{Builder, Config, Handler}; | 17 | use embassy_usb::{Builder, Config, Handler}; |
| 16 | use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; | 18 | use 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 | ||
| 25 | static HID_PROTOCOL_MODE: AtomicU8 = AtomicU8::new(HidProtocolMode::Boot as u8); | ||
| 26 | |||
| 23 | #[embassy_executor::main] | 27 | #[embassy_executor::main] |
| 24 | async fn main(_spawner: Spawner) { | 28 | async 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 | ||
| 4 | use core::sync::atomic::{AtomicBool, Ordering}; | 4 | use core::sync::atomic::{AtomicBool, AtomicU8, Ordering}; |
| 5 | 5 | ||
| 6 | use defmt::*; | 6 | use defmt::*; |
| 7 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
| @@ -11,7 +11,9 @@ use embassy_stm32::gpio::Pull; | |||
| 11 | use embassy_stm32::time::Hertz; | 11 | use embassy_stm32::time::Hertz; |
| 12 | use embassy_stm32::usb::Driver; | 12 | use embassy_stm32::usb::Driver; |
| 13 | use embassy_stm32::{Config, bind_interrupts, peripherals, usb}; | 13 | use embassy_stm32::{Config, bind_interrupts, peripherals, usb}; |
| 14 | use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State}; | 14 | use embassy_usb::class::hid::{ |
| 15 | HidBootProtocol, HidProtocolMode, HidReaderWriter, HidSubclass, ReportId, RequestHandler, State, | ||
| 16 | }; | ||
| 15 | use embassy_usb::control::OutResponse; | 17 | use embassy_usb::control::OutResponse; |
| 16 | use embassy_usb::{Builder, Handler}; | 18 | use embassy_usb::{Builder, Handler}; |
| 17 | use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; | 19 | use 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 | ||
| 26 | static 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 | ||
| 4 | use core::sync::atomic::{AtomicU8, Ordering}; | ||
| 5 | |||
| 4 | use defmt::*; | 6 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
| 6 | use embassy_futures::join::join; | 8 | use embassy_futures::join::join; |
| @@ -9,7 +11,9 @@ use embassy_stm32::usb::Driver; | |||
| 9 | use embassy_stm32::{Config, bind_interrupts, peripherals, usb}; | 11 | use embassy_stm32::{Config, bind_interrupts, peripherals, usb}; |
| 10 | use embassy_time::Timer; | 12 | use embassy_time::Timer; |
| 11 | use embassy_usb::Builder; | 13 | use embassy_usb::Builder; |
| 12 | use embassy_usb::class::hid::{HidWriter, ReportId, RequestHandler, State}; | 14 | use embassy_usb::class::hid::{ |
| 15 | HidBootProtocol, HidProtocolMode, HidSubclass, HidWriter, ReportId, RequestHandler, State, | ||
| 16 | }; | ||
| 13 | use embassy_usb::control::OutResponse; | 17 | use embassy_usb::control::OutResponse; |
| 14 | use usbd_hid::descriptor::{MouseReport, SerializedDescriptor}; | 18 | use usbd_hid::descriptor::{MouseReport, SerializedDescriptor}; |
| 15 | use {defmt_rtt as _, panic_probe as _}; | 19 | use {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 | ||
| 25 | static 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 | ||
| 4 | use core::sync::atomic::{AtomicU8, Ordering}; | ||
| 5 | |||
| 4 | use defmt::*; | 6 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
| 6 | use embassy_futures::join::join; | 8 | use embassy_futures::join::join; |
| @@ -8,7 +10,9 @@ use embassy_stm32::usb::Driver; | |||
| 8 | use embassy_stm32::{Config, bind_interrupts, peripherals, usb}; | 10 | use embassy_stm32::{Config, bind_interrupts, peripherals, usb}; |
| 9 | use embassy_time::Timer; | 11 | use embassy_time::Timer; |
| 10 | use embassy_usb::Builder; | 12 | use embassy_usb::Builder; |
| 11 | use embassy_usb::class::hid::{HidWriter, ReportId, RequestHandler, State}; | 13 | use embassy_usb::class::hid::{ |
| 14 | HidBootProtocol, HidProtocolMode, HidSubclass, HidWriter, ReportId, RequestHandler, State, | ||
| 15 | }; | ||
| 12 | use embassy_usb::control::OutResponse; | 16 | use embassy_usb::control::OutResponse; |
| 13 | use usbd_hid::descriptor::{MouseReport, SerializedDescriptor}; | 17 | use usbd_hid::descriptor::{MouseReport, SerializedDescriptor}; |
| 14 | use {defmt_rtt as _, panic_probe as _}; | 18 | use {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 | ||
| 24 | static HID_PROTOCOL_MODE: AtomicU8 = AtomicU8::new(HidProtocolMode::Boot as u8); | ||
| 25 | |||
| 20 | #[embassy_executor::main] | 26 | #[embassy_executor::main] |
| 21 | async fn main(_spawner: Spawner) { | 27 | async 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 | } |
