aboutsummaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authoralexmoon <[email protected]>2022-04-10 15:41:51 -0400
committeralexmoon <[email protected]>2022-04-13 14:55:02 -0400
commitf5656e354485888cc7c2697052ae2c79b94a59ad (patch)
tree8580410dbaca2c3f0db6e431f77f248dd6bd5dc9 /examples
parent2217de24c02e9f7e0aafeb8315ab6be8b644c52f (diff)
Add DeviceStateHandler, DeviceCommand channel, and remote wakeup support
Diffstat (limited to 'examples')
-rw-r--r--examples/nrf/src/bin/usb_hid_keyboard.rs114
-rw-r--r--examples/nrf/src/bin/usb_hid_mouse.rs3
-rw-r--r--examples/nrf/src/bin/usb_serial.rs3
-rw-r--r--examples/nrf/src/bin/usb_serial_multitask.rs3
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
6use core::mem; 6use core::mem;
7use core::sync::atomic::{AtomicBool, Ordering};
7use defmt::*; 8use defmt::*;
9use embassy::blocking_mutex::raw::CriticalSectionRawMutex;
10use embassy::channel::Channel;
8use embassy::executor::Spawner; 11use embassy::executor::Spawner;
12use embassy::interrupt::InterruptExt;
9use embassy::time::Duration; 13use embassy::time::Duration;
10use embassy_nrf::gpio::{Input, Pin, Pull}; 14use embassy_nrf::gpio::{Input, Pin, Pull};
11use embassy_nrf::interrupt; 15use embassy_nrf::interrupt;
@@ -13,7 +17,7 @@ use embassy_nrf::pac;
13use embassy_nrf::usb::Driver; 17use embassy_nrf::usb::Driver;
14use embassy_nrf::Peripherals; 18use embassy_nrf::Peripherals;
15use embassy_usb::control::OutResponse; 19use embassy_usb::control::OutResponse;
16use embassy_usb::{Config, UsbDeviceBuilder}; 20use embassy_usb::{Config, DeviceCommand, DeviceStateHandler, UsbDeviceBuilder};
17use embassy_usb_hid::{HidClass, ReportId, RequestHandler, State}; 21use embassy_usb_hid::{HidClass, ReportId, RequestHandler, State};
18use futures::future::join; 22use futures::future::join;
19use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; 23use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor};
@@ -21,6 +25,29 @@ use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor};
21use defmt_rtt as _; // global logger 25use defmt_rtt as _; // global logger
22use panic_probe as _; 26use panic_probe as _;
23 27
28static USB_COMMANDS: Channel<CriticalSectionRawMutex, DeviceCommand, 1> = Channel::new();
29static SUSPENDED: AtomicBool = AtomicBool::new(false);
30
31fn 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]
25async fn main(_spawner: Spawner, p: Peripherals) { 52async 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
194struct MyDeviceStateHandler {
195 configured: AtomicBool,
196}
197
198impl MyDeviceStateHandler {
199 fn new() -> Self {
200 MyDeviceStateHandler {
201 configured: AtomicBool::new(false),
202 }
203 }
204}
205
206impl 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)));