diff options
| author | alexmoon <[email protected]> | 2022-04-10 15:41:51 -0400 |
|---|---|---|
| committer | alexmoon <[email protected]> | 2022-04-13 14:55:02 -0400 |
| commit | f5656e354485888cc7c2697052ae2c79b94a59ad (patch) | |
| tree | 8580410dbaca2c3f0db6e431f77f248dd6bd5dc9 /examples/nrf/src | |
| parent | 2217de24c02e9f7e0aafeb8315ab6be8b644c52f (diff) | |
Add DeviceStateHandler, DeviceCommand channel, and remote wakeup support
Diffstat (limited to 'examples/nrf/src')
| -rw-r--r-- | examples/nrf/src/bin/usb_hid_keyboard.rs | 114 | ||||
| -rw-r--r-- | examples/nrf/src/bin/usb_hid_mouse.rs | 3 | ||||
| -rw-r--r-- | examples/nrf/src/bin/usb_serial.rs | 3 | ||||
| -rw-r--r-- | examples/nrf/src/bin/usb_serial_multitask.rs | 3 |
4 files changed, 113 insertions, 10 deletions
diff --git a/examples/nrf/src/bin/usb_hid_keyboard.rs b/examples/nrf/src/bin/usb_hid_keyboard.rs index 0812697e4..483d86b81 100644 --- a/examples/nrf/src/bin/usb_hid_keyboard.rs +++ b/examples/nrf/src/bin/usb_hid_keyboard.rs | |||
| @@ -4,8 +4,12 @@ | |||
| 4 | #![feature(type_alias_impl_trait)] | 4 | #![feature(type_alias_impl_trait)] |
| 5 | 5 | ||
| 6 | use core::mem; | 6 | use core::mem; |
| 7 | use core::sync::atomic::{AtomicBool, Ordering}; | ||
| 7 | use defmt::*; | 8 | use defmt::*; |
| 9 | use embassy::blocking_mutex::raw::CriticalSectionRawMutex; | ||
| 10 | use embassy::channel::Channel; | ||
| 8 | use embassy::executor::Spawner; | 11 | use embassy::executor::Spawner; |
| 12 | use embassy::interrupt::InterruptExt; | ||
| 9 | use embassy::time::Duration; | 13 | use embassy::time::Duration; |
| 10 | use embassy_nrf::gpio::{Input, Pin, Pull}; | 14 | use embassy_nrf::gpio::{Input, Pin, Pull}; |
| 11 | use embassy_nrf::interrupt; | 15 | use embassy_nrf::interrupt; |
| @@ -13,7 +17,7 @@ use embassy_nrf::pac; | |||
| 13 | use embassy_nrf::usb::Driver; | 17 | use embassy_nrf::usb::Driver; |
| 14 | use embassy_nrf::Peripherals; | 18 | use embassy_nrf::Peripherals; |
| 15 | use embassy_usb::control::OutResponse; | 19 | use embassy_usb::control::OutResponse; |
| 16 | use embassy_usb::{Config, UsbDeviceBuilder}; | 20 | use embassy_usb::{Config, DeviceCommand, DeviceStateHandler, UsbDeviceBuilder}; |
| 17 | use embassy_usb_hid::{HidClass, ReportId, RequestHandler, State}; | 21 | use embassy_usb_hid::{HidClass, ReportId, RequestHandler, State}; |
| 18 | use futures::future::join; | 22 | use futures::future::join; |
| 19 | use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; | 23 | use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; |
| @@ -21,6 +25,29 @@ use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; | |||
| 21 | use defmt_rtt as _; // global logger | 25 | use defmt_rtt as _; // global logger |
| 22 | use panic_probe as _; | 26 | use panic_probe as _; |
| 23 | 27 | ||
| 28 | static USB_COMMANDS: Channel<CriticalSectionRawMutex, DeviceCommand, 1> = Channel::new(); | ||
| 29 | static SUSPENDED: AtomicBool = AtomicBool::new(false); | ||
| 30 | |||
| 31 | fn on_power_interrupt(_: *mut ()) { | ||
| 32 | let regs = unsafe { &*pac::POWER::ptr() }; | ||
| 33 | |||
| 34 | if regs.events_usbdetected.read().bits() != 0 { | ||
| 35 | regs.events_usbdetected.reset(); | ||
| 36 | info!("Vbus detected, enabling USB..."); | ||
| 37 | if USB_COMMANDS.try_send(DeviceCommand::Enable).is_err() { | ||
| 38 | warn!("Failed to send enable command to USB channel"); | ||
| 39 | } | ||
| 40 | } | ||
| 41 | |||
| 42 | if regs.events_usbremoved.read().bits() != 0 { | ||
| 43 | regs.events_usbremoved.reset(); | ||
| 44 | info!("Vbus removed, disabling USB..."); | ||
| 45 | if USB_COMMANDS.try_send(DeviceCommand::Disable).is_err() { | ||
| 46 | warn!("Failed to send disable command to USB channel"); | ||
| 47 | }; | ||
| 48 | } | ||
| 49 | } | ||
| 50 | |||
| 24 | #[embassy::main] | 51 | #[embassy::main] |
| 25 | async fn main(_spawner: Spawner, p: Peripherals) { | 52 | async fn main(_spawner: Spawner, p: Peripherals) { |
| 26 | let clock: pac::CLOCK = unsafe { mem::transmute(()) }; | 53 | let clock: pac::CLOCK = unsafe { mem::transmute(()) }; |
| @@ -30,10 +57,6 @@ async fn main(_spawner: Spawner, p: Peripherals) { | |||
| 30 | clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) }); | 57 | clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) }); |
| 31 | while clock.events_hfclkstarted.read().bits() != 1 {} | 58 | while clock.events_hfclkstarted.read().bits() != 1 {} |
| 32 | 59 | ||
| 33 | info!("Waiting for vbus..."); | ||
| 34 | while !power.usbregstatus.read().vbusdetect().is_vbus_present() {} | ||
| 35 | info!("vbus OK"); | ||
| 36 | |||
| 37 | // Create the driver, from the HAL. | 60 | // Create the driver, from the HAL. |
| 38 | let irq = interrupt::take!(USBD); | 61 | let irq = interrupt::take!(USBD); |
| 39 | let driver = Driver::new(p.USBD, irq); | 62 | let driver = Driver::new(p.USBD, irq); |
| @@ -45,6 +68,8 @@ async fn main(_spawner: Spawner, p: Peripherals) { | |||
| 45 | config.serial_number = Some("12345678"); | 68 | config.serial_number = Some("12345678"); |
| 46 | config.max_power = 100; | 69 | config.max_power = 100; |
| 47 | config.max_packet_size_0 = 64; | 70 | config.max_packet_size_0 = 64; |
| 71 | config.supports_remote_wakeup = true; | ||
| 72 | config.start_enabled = false; | ||
| 48 | 73 | ||
| 49 | // Create embassy-usb DeviceBuilder using the driver and config. | 74 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 50 | // It needs some buffers for building the descriptors. | 75 | // It needs some buffers for building the descriptors. |
| @@ -53,16 +78,19 @@ async fn main(_spawner: Spawner, p: Peripherals) { | |||
| 53 | let mut bos_descriptor = [0; 256]; | 78 | let mut bos_descriptor = [0; 256]; |
| 54 | let mut control_buf = [0; 16]; | 79 | let mut control_buf = [0; 16]; |
| 55 | let request_handler = MyRequestHandler {}; | 80 | let request_handler = MyRequestHandler {}; |
| 81 | let device_state_handler = MyDeviceStateHandler::new(); | ||
| 56 | 82 | ||
| 57 | let mut state = State::<8, 1>::new(); | 83 | let mut state = State::<8, 1>::new(); |
| 58 | 84 | ||
| 59 | let mut builder = UsbDeviceBuilder::new( | 85 | let mut builder = UsbDeviceBuilder::new_with_channel( |
| 60 | driver, | 86 | driver, |
| 61 | config, | 87 | config, |
| 62 | &mut device_descriptor, | 88 | &mut device_descriptor, |
| 63 | &mut config_descriptor, | 89 | &mut config_descriptor, |
| 64 | &mut bos_descriptor, | 90 | &mut bos_descriptor, |
| 65 | &mut control_buf, | 91 | &mut control_buf, |
| 92 | Some(&device_state_handler), | ||
| 93 | &USB_COMMANDS, | ||
| 66 | ); | 94 | ); |
| 67 | 95 | ||
| 68 | // Create classes on the builder. | 96 | // Create classes on the builder. |
| @@ -76,7 +104,7 @@ async fn main(_spawner: Spawner, p: Peripherals) { | |||
| 76 | ); | 104 | ); |
| 77 | 105 | ||
| 78 | // Build the builder. | 106 | // Build the builder. |
| 79 | let mut usb = builder.build().await; | 107 | let mut usb = builder.build(); |
| 80 | 108 | ||
| 81 | // Run the USB device. | 109 | // Run the USB device. |
| 82 | let usb_fut = usb.run(); | 110 | let usb_fut = usb.run(); |
| @@ -90,6 +118,12 @@ async fn main(_spawner: Spawner, p: Peripherals) { | |||
| 90 | loop { | 118 | loop { |
| 91 | button.wait_for_low().await; | 119 | button.wait_for_low().await; |
| 92 | info!("PRESSED"); | 120 | info!("PRESSED"); |
| 121 | |||
| 122 | if SUSPENDED.load(Ordering::Acquire) { | ||
| 123 | info!("Triggering remote wakeup"); | ||
| 124 | USB_COMMANDS.send(DeviceCommand::RemoteWakeup); | ||
| 125 | } | ||
| 126 | |||
| 93 | let report = KeyboardReport { | 127 | let report = KeyboardReport { |
| 94 | keycodes: [4, 0, 0, 0, 0, 0], | 128 | keycodes: [4, 0, 0, 0, 0, 0], |
| 95 | leds: 0, | 129 | leds: 0, |
| @@ -119,6 +153,16 @@ async fn main(_spawner: Spawner, p: Peripherals) { | |||
| 119 | let out_fut = async { | 153 | let out_fut = async { |
| 120 | hid_out.run(false, &request_handler).await; | 154 | hid_out.run(false, &request_handler).await; |
| 121 | }; | 155 | }; |
| 156 | |||
| 157 | let power_irq = interrupt::take!(POWER_CLOCK); | ||
| 158 | power_irq.set_handler(on_power_interrupt); | ||
| 159 | power_irq.unpend(); | ||
| 160 | power_irq.enable(); | ||
| 161 | |||
| 162 | power | ||
| 163 | .intenset | ||
| 164 | .write(|w| w.usbdetected().set().usbremoved().set()); | ||
| 165 | |||
| 122 | // Run everything concurrently. | 166 | // Run everything concurrently. |
| 123 | // If we had made everything `'static` above instead, we could do this using separate tasks instead. | 167 | // If we had made everything `'static` above instead, we could do this using separate tasks instead. |
| 124 | join(usb_fut, join(in_fut, out_fut)).await; | 168 | join(usb_fut, join(in_fut, out_fut)).await; |
| @@ -146,3 +190,59 @@ impl RequestHandler for MyRequestHandler { | |||
| 146 | None | 190 | None |
| 147 | } | 191 | } |
| 148 | } | 192 | } |
| 193 | |||
| 194 | struct MyDeviceStateHandler { | ||
| 195 | configured: AtomicBool, | ||
| 196 | } | ||
| 197 | |||
| 198 | impl MyDeviceStateHandler { | ||
| 199 | fn new() -> Self { | ||
| 200 | MyDeviceStateHandler { | ||
| 201 | configured: AtomicBool::new(false), | ||
| 202 | } | ||
| 203 | } | ||
| 204 | } | ||
| 205 | |||
| 206 | impl DeviceStateHandler for MyDeviceStateHandler { | ||
| 207 | fn reset(&self) { | ||
| 208 | self.configured.store(false, Ordering::Relaxed); | ||
| 209 | info!("Bus reset, the Vbus current limit is 100mA"); | ||
| 210 | } | ||
| 211 | |||
| 212 | fn addressed(&self, addr: u8) { | ||
| 213 | self.configured.store(false, Ordering::Relaxed); | ||
| 214 | info!("USB address set to: {}", addr); | ||
| 215 | } | ||
| 216 | |||
| 217 | fn configured(&self, configured: bool) { | ||
| 218 | self.configured.store(configured, Ordering::Relaxed); | ||
| 219 | if configured { | ||
| 220 | info!( | ||
| 221 | "Device configured, it may now draw up to the configured current limit from Vbus." | ||
| 222 | ) | ||
| 223 | } else { | ||
| 224 | info!("Device is no longer configured, the Vbus current limit is 100mA."); | ||
| 225 | } | ||
| 226 | } | ||
| 227 | |||
| 228 | fn suspended(&self, suspended: bool) { | ||
| 229 | if suspended { | ||
| 230 | info!("Device suspended, the Vbus current limit is 500µA (or 2.5mA for high-power devices with remote wakeup enabled)."); | ||
| 231 | SUSPENDED.store(true, Ordering::Release); | ||
| 232 | } else { | ||
| 233 | SUSPENDED.store(false, Ordering::Release); | ||
| 234 | if self.configured.load(Ordering::Relaxed) { | ||
| 235 | info!( | ||
| 236 | "Device resumed, it may now draw up to the configured current limit from Vbus" | ||
| 237 | ); | ||
| 238 | } else { | ||
| 239 | info!("Device resumed, the Vbus current limit is 100mA"); | ||
| 240 | } | ||
| 241 | } | ||
| 242 | } | ||
| 243 | |||
| 244 | fn disabled(&self) { | ||
| 245 | self.configured.store(false, Ordering::Relaxed); | ||
| 246 | info!("Device disabled"); | ||
| 247 | } | ||
| 248 | } | ||
diff --git a/examples/nrf/src/bin/usb_hid_mouse.rs b/examples/nrf/src/bin/usb_hid_mouse.rs index ca9383827..fe27e76fb 100644 --- a/examples/nrf/src/bin/usb_hid_mouse.rs +++ b/examples/nrf/src/bin/usb_hid_mouse.rs | |||
| @@ -61,6 +61,7 @@ async fn main(_spawner: Spawner, p: Peripherals) { | |||
| 61 | &mut config_descriptor, | 61 | &mut config_descriptor, |
| 62 | &mut bos_descriptor, | 62 | &mut bos_descriptor, |
| 63 | &mut control_buf, | 63 | &mut control_buf, |
| 64 | None, | ||
| 64 | ); | 65 | ); |
| 65 | 66 | ||
| 66 | // Create classes on the builder. | 67 | // Create classes on the builder. |
| @@ -74,7 +75,7 @@ async fn main(_spawner: Spawner, p: Peripherals) { | |||
| 74 | ); | 75 | ); |
| 75 | 76 | ||
| 76 | // Build the builder. | 77 | // Build the builder. |
| 77 | let mut usb = builder.build().await; | 78 | let mut usb = builder.build(); |
| 78 | 79 | ||
| 79 | // Run the USB device. | 80 | // Run the USB device. |
| 80 | let usb_fut = usb.run(); | 81 | let usb_fut = usb.run(); |
diff --git a/examples/nrf/src/bin/usb_serial.rs b/examples/nrf/src/bin/usb_serial.rs index 684322837..987cc4139 100644 --- a/examples/nrf/src/bin/usb_serial.rs +++ b/examples/nrf/src/bin/usb_serial.rs | |||
| @@ -54,13 +54,14 @@ async fn main(_spawner: Spawner, p: Peripherals) { | |||
| 54 | &mut config_descriptor, | 54 | &mut config_descriptor, |
| 55 | &mut bos_descriptor, | 55 | &mut bos_descriptor, |
| 56 | &mut control_buf, | 56 | &mut control_buf, |
| 57 | None, | ||
| 57 | ); | 58 | ); |
| 58 | 59 | ||
| 59 | // Create classes on the builder. | 60 | // Create classes on the builder. |
| 60 | let mut class = CdcAcmClass::new(&mut builder, &mut state, 64); | 61 | let mut class = CdcAcmClass::new(&mut builder, &mut state, 64); |
| 61 | 62 | ||
| 62 | // Build the builder. | 63 | // Build the builder. |
| 63 | let mut usb = builder.build().await; | 64 | let mut usb = builder.build(); |
| 64 | 65 | ||
| 65 | // Run the USB device. | 66 | // Run the USB device. |
| 66 | let usb_fut = usb.run(); | 67 | let usb_fut = usb.run(); |
diff --git a/examples/nrf/src/bin/usb_serial_multitask.rs b/examples/nrf/src/bin/usb_serial_multitask.rs index bfb09014c..5fcb0e052 100644 --- a/examples/nrf/src/bin/usb_serial_multitask.rs +++ b/examples/nrf/src/bin/usb_serial_multitask.rs | |||
| @@ -79,13 +79,14 @@ async fn main(spawner: Spawner, p: Peripherals) { | |||
| 79 | &mut res.config_descriptor, | 79 | &mut res.config_descriptor, |
| 80 | &mut res.bos_descriptor, | 80 | &mut res.bos_descriptor, |
| 81 | &mut res.control_buf, | 81 | &mut res.control_buf, |
| 82 | None, | ||
| 82 | ); | 83 | ); |
| 83 | 84 | ||
| 84 | // Create classes on the builder. | 85 | // Create classes on the builder. |
| 85 | let class = CdcAcmClass::new(&mut builder, &mut res.serial_state, 64); | 86 | let class = CdcAcmClass::new(&mut builder, &mut res.serial_state, 64); |
| 86 | 87 | ||
| 87 | // Build the builder. | 88 | // Build the builder. |
| 88 | let usb = builder.build().await; | 89 | let usb = builder.build(); |
| 89 | 90 | ||
| 90 | unwrap!(spawner.spawn(usb_task(usb))); | 91 | unwrap!(spawner.spawn(usb_task(usb))); |
| 91 | unwrap!(spawner.spawn(echo_task(class))); | 92 | unwrap!(spawner.spawn(echo_task(class))); |
