aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2022-04-14 15:16:55 +0000
committerGitHub <[email protected]>2022-04-14 15:16:55 +0000
commit3a90a8eb4a5ef61aef034025ac882255c94260dc (patch)
treea40a8f9bb7b847d168a5b4c725d678d59d4d7823
parent391fdc097ec1691cfab6a3db5c3992f6f2e6da8e (diff)
parentb0725c14d36cb9c508cb9fcec5b92ca9e0148583 (diff)
Merge #711
711: Add DeviceStateHandler, DeviceCommand channel, and remote wakeup support r=Dirbaio a=alexmoon Apologies for the size of this PR. Once I started getting into the Vbus power management side of my device I found a couple of areas of functionality missing from embassy-usb. Specifically, I need the application to be able to respond to changes in the USB device state in order to properly control the amount of power I'm drawing from Vbus. I also wanted to enable remote wakeup support for my device. In order to enable device state monitoring, I've created a `DeviceStateHandler` trait and made it possible to pass in an optional reference a handler implementing that trait when creating the `UsbDeviceBuilder`. Remote wakeup required a way to send commands to the bus which is exclusively owned by the `UsbDevice::run` method. This is the same problem we were discussing for enabling/disabling the device on Vbus power events. My solution is to allow an optional `Channel` to be provided to the `UsbDeviceBuilder` (via `UsbDeviceBuilder::new_with_channel`), allowing the application to send commands into the `run` method. Right now it supports enable, disable and remote wakeup commands. Since there's now a way to dynamically enable and disable the device, I also added `Config::start_enabled` to control whether or not the `UsbDevice` should start in the enabled state. That also allowed me to make `UsbDeviceBuilder::build` sync again and move enabling the bus into `UsbDevice::run`. This led to a few driver changes: 1. `Driver::enable` became `Driver::into_bus` 2. `Bus::enable`, `Bus::disable`, and `Bus::remote_wakeup` were added 3. I removed `Bus::reset`, `Bus::suspend`, and `Bus::resume` because they were only ever called based on the result of `Bus::poll`. It made more sense to me to have `Bus::poll` handle the driver-specific state management itself. I've updated the `usb_hid_keyboard` example to take advantage of all these additional features. Let me know what you think. Thanks! Co-authored-by: alexmoon <[email protected]>
-rw-r--r--embassy-nrf/src/usb.rs109
-rw-r--r--embassy-usb/src/builder.rs8
-rw-r--r--embassy-usb/src/driver.rs45
-rw-r--r--embassy-usb/src/lib.rs210
-rw-r--r--embassy-usb/src/util.rs45
-rw-r--r--examples/nrf/src/bin/usb_hid_keyboard.rs173
-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
9 files changed, 446 insertions, 153 deletions
diff --git a/embassy-nrf/src/usb.rs b/embassy-nrf/src/usb.rs
index 5e2f585f2..b67201e67 100644
--- a/embassy-nrf/src/usb.rs
+++ b/embassy-nrf/src/usb.rs
@@ -10,7 +10,7 @@ use embassy::util::Unborrow;
10use embassy::waitqueue::AtomicWaker; 10use embassy::waitqueue::AtomicWaker;
11use embassy_hal_common::unborrow; 11use embassy_hal_common::unborrow;
12use embassy_usb::control::Request; 12use embassy_usb::control::Request;
13use embassy_usb::driver::{self, EndpointError, Event}; 13use embassy_usb::driver::{self, EndpointError, Event, Unsupported};
14use embassy_usb::types::{EndpointAddress, EndpointInfo, EndpointType, UsbDirection}; 14use embassy_usb::types::{EndpointAddress, EndpointInfo, EndpointType, UsbDirection};
15use futures::future::poll_fn; 15use futures::future::poll_fn;
16use futures::Future; 16use futures::Future;
@@ -140,7 +140,6 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> {
140 type EndpointIn = Endpoint<'d, T, In>; 140 type EndpointIn = Endpoint<'d, T, In>;
141 type ControlPipe = ControlPipe<'d, T>; 141 type ControlPipe = ControlPipe<'d, T>;
142 type Bus = Bus<'d, T>; 142 type Bus = Bus<'d, T>;
143 type EnableFuture = impl Future<Output = Self::Bus> + 'd;
144 143
145 fn alloc_endpoint_in( 144 fn alloc_endpoint_in(
146 &mut self, 145 &mut self,
@@ -192,7 +191,28 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> {
192 }) 191 })
193 } 192 }
194 193
195 fn enable(self) -> Self::EnableFuture { 194 fn into_bus(self) -> Self::Bus {
195 Bus {
196 phantom: PhantomData,
197 alloc_in: self.alloc_in,
198 alloc_out: self.alloc_out,
199 }
200 }
201}
202
203pub struct Bus<'d, T: Instance> {
204 phantom: PhantomData<&'d mut T>,
205 alloc_in: Allocator,
206 alloc_out: Allocator,
207}
208
209impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
210 type EnableFuture<'a> = impl Future<Output = ()> + 'a where Self: 'a;
211 type DisableFuture<'a> = impl Future<Output = ()> + 'a where Self: 'a;
212 type PollFuture<'a> = impl Future<Output = Event> + 'a where Self: 'a;
213 type RemoteWakeupFuture<'a> = impl Future<Output = Result<(), Unsupported>> + 'a where Self: 'a;
214
215 fn enable(&mut self) -> Self::EnableFuture<'_> {
196 async move { 216 async move {
197 let regs = T::regs(); 217 let regs = T::regs();
198 218
@@ -226,33 +246,25 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> {
226 // Enable the USB pullup, allowing enumeration. 246 // Enable the USB pullup, allowing enumeration.
227 regs.usbpullup.write(|w| w.connect().enabled()); 247 regs.usbpullup.write(|w| w.connect().enabled());
228 trace!("enabled"); 248 trace!("enabled");
229
230 Bus {
231 phantom: PhantomData,
232 alloc_in: self.alloc_in,
233 alloc_out: self.alloc_out,
234 }
235 } 249 }
236 } 250 }
237}
238
239pub struct Bus<'d, T: Instance> {
240 phantom: PhantomData<&'d mut T>,
241 alloc_in: Allocator,
242 alloc_out: Allocator,
243}
244 251
245impl<'d, T: Instance> driver::Bus for Bus<'d, T> { 252 fn disable(&mut self) -> Self::DisableFuture<'_> {
246 type PollFuture<'a> = impl Future<Output = Event> + 'a where Self: 'a; 253 async move {
254 let regs = T::regs();
255 regs.enable.write(|x| x.enable().disabled());
256 }
257 }
247 258
248 fn poll<'a>(&'a mut self) -> Self::PollFuture<'a> { 259 fn poll<'a>(&'a mut self) -> Self::PollFuture<'a> {
249 poll_fn(|cx| { 260 poll_fn(move |cx| {
250 BUS_WAKER.register(cx.waker()); 261 BUS_WAKER.register(cx.waker());
251 let regs = T::regs(); 262 let regs = T::regs();
252 263
253 if regs.events_usbreset.read().bits() != 0 { 264 if regs.events_usbreset.read().bits() != 0 {
254 regs.events_usbreset.reset(); 265 regs.events_usbreset.reset();
255 regs.intenset.write(|w| w.usbreset().set()); 266 regs.intenset.write(|w| w.usbreset().set());
267 self.set_configured(false);
256 return Poll::Ready(Event::Reset); 268 return Poll::Ready(Event::Reset);
257 } 269 }
258 270
@@ -268,11 +280,12 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
268 } 280 }
269 if r.suspend().bit() { 281 if r.suspend().bit() {
270 regs.eventcause.write(|w| w.suspend().set_bit()); 282 regs.eventcause.write(|w| w.suspend().set_bit());
271 trace!("USB event: suspend"); 283 regs.lowpower.write(|w| w.lowpower().low_power());
284 return Poll::Ready(Event::Suspend);
272 } 285 }
273 if r.resume().bit() { 286 if r.resume().bit() {
274 regs.eventcause.write(|w| w.resume().set_bit()); 287 regs.eventcause.write(|w| w.resume().set_bit());
275 trace!("USB event: resume"); 288 return Poll::Ready(Event::Resume);
276 } 289 }
277 if r.ready().bit() { 290 if r.ready().bit() {
278 regs.eventcause.write(|w| w.ready().set_bit()); 291 regs.eventcause.write(|w| w.ready().set_bit());
@@ -284,11 +297,6 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
284 } 297 }
285 298
286 #[inline] 299 #[inline]
287 fn reset(&mut self) {
288 self.set_configured(false);
289 }
290
291 #[inline]
292 fn set_configured(&mut self, configured: bool) { 300 fn set_configured(&mut self, configured: bool) {
293 let regs = T::regs(); 301 let regs = T::regs();
294 302
@@ -343,18 +351,43 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
343 } 351 }
344 352
345 #[inline] 353 #[inline]
346 fn suspend(&mut self) { 354 fn remote_wakeup(&mut self) -> Self::RemoteWakeupFuture<'_> {
347 let regs = T::regs(); 355 async move {
348 regs.lowpower.write(|w| w.lowpower().low_power()); 356 let regs = T::regs();
349 }
350 357
351 #[inline] 358 if regs.lowpower.read().lowpower().is_low_power() {
352 fn resume(&mut self) { 359 errata::pre_wakeup();
353 let regs = T::regs(); 360
361 regs.lowpower.write(|w| w.lowpower().force_normal());
362
363 poll_fn(|cx| {
364 BUS_WAKER.register(cx.waker());
365 let regs = T::regs();
366 let r = regs.eventcause.read();
367
368 if regs.events_usbreset.read().bits() != 0 {
369 Poll::Ready(())
370 } else if r.resume().bit() {
371 Poll::Ready(())
372 } else if r.usbwuallowed().bit() {
373 regs.eventcause.write(|w| w.usbwuallowed().set_bit());
354 374
355 errata::pre_wakeup(); 375 regs.dpdmvalue.write(|w| w.state().resume());
376 regs.tasks_dpdmdrive
377 .write(|w| w.tasks_dpdmdrive().set_bit());
356 378
357 regs.lowpower.write(|w| w.lowpower().force_normal()); 379 Poll::Ready(())
380 } else {
381 Poll::Pending
382 }
383 })
384 .await;
385
386 errata::post_wakeup();
387 }
388
389 Ok(())
390 }
358 } 391 }
359} 392}
360 393
@@ -834,17 +867,20 @@ macro_rules! impl_usb {
834mod errata { 867mod errata {
835 868
836 /// Writes `val` to `addr`. Used to apply Errata workarounds. 869 /// Writes `val` to `addr`. Used to apply Errata workarounds.
870 #[cfg(any(feature = "nrf52840", feature = "nrf52833", feature = "nrf52820"))]
837 unsafe fn poke(addr: u32, val: u32) { 871 unsafe fn poke(addr: u32, val: u32) {
838 (addr as *mut u32).write_volatile(val); 872 (addr as *mut u32).write_volatile(val);
839 } 873 }
840 874
841 /// Reads 32 bits from `addr`. 875 /// Reads 32 bits from `addr`.
876 #[cfg(feature = "nrf52840")]
842 unsafe fn peek(addr: u32) -> u32 { 877 unsafe fn peek(addr: u32) -> u32 {
843 (addr as *mut u32).read_volatile() 878 (addr as *mut u32).read_volatile()
844 } 879 }
845 880
846 pub fn pre_enable() { 881 pub fn pre_enable() {
847 // Works around Erratum 187 on chip revisions 1 and 2. 882 // Works around Erratum 187 on chip revisions 1 and 2.
883 #[cfg(any(feature = "nrf52840", feature = "nrf52833", feature = "nrf52820"))]
848 unsafe { 884 unsafe {
849 poke(0x4006EC00, 0x00009375); 885 poke(0x4006EC00, 0x00009375);
850 poke(0x4006ED14, 0x00000003); 886 poke(0x4006ED14, 0x00000003);
@@ -858,6 +894,7 @@ mod errata {
858 post_wakeup(); 894 post_wakeup();
859 895
860 // Works around Erratum 187 on chip revisions 1 and 2. 896 // Works around Erratum 187 on chip revisions 1 and 2.
897 #[cfg(any(feature = "nrf52840", feature = "nrf52833", feature = "nrf52820"))]
861 unsafe { 898 unsafe {
862 poke(0x4006EC00, 0x00009375); 899 poke(0x4006EC00, 0x00009375);
863 poke(0x4006ED14, 0x00000000); 900 poke(0x4006ED14, 0x00000000);
@@ -868,6 +905,7 @@ mod errata {
868 pub fn pre_wakeup() { 905 pub fn pre_wakeup() {
869 // Works around Erratum 171 on chip revisions 1 and 2. 906 // Works around Erratum 171 on chip revisions 1 and 2.
870 907
908 #[cfg(feature = "nrf52840")]
871 unsafe { 909 unsafe {
872 if peek(0x4006EC00) == 0x00000000 { 910 if peek(0x4006EC00) == 0x00000000 {
873 poke(0x4006EC00, 0x00009375); 911 poke(0x4006EC00, 0x00009375);
@@ -881,6 +919,7 @@ mod errata {
881 pub fn post_wakeup() { 919 pub fn post_wakeup() {
882 // Works around Erratum 171 on chip revisions 1 and 2. 920 // Works around Erratum 171 on chip revisions 1 and 2.
883 921
922 #[cfg(feature = "nrf52840")]
884 unsafe { 923 unsafe {
885 if peek(0x4006EC00) == 0x00000000 { 924 if peek(0x4006EC00) == 0x00000000 {
886 poke(0x4006EC00, 0x00009375); 925 poke(0x4006EC00, 0x00009375);
diff --git a/embassy-usb/src/builder.rs b/embassy-usb/src/builder.rs
index 4bbcd3e56..486672055 100644
--- a/embassy-usb/src/builder.rs
+++ b/embassy-usb/src/builder.rs
@@ -4,6 +4,7 @@ use super::control::ControlHandler;
4use super::descriptor::{BosWriter, DescriptorWriter}; 4use super::descriptor::{BosWriter, DescriptorWriter};
5use super::driver::{Driver, EndpointAllocError}; 5use super::driver::{Driver, EndpointAllocError};
6use super::types::*; 6use super::types::*;
7use super::DeviceStateHandler;
7use super::UsbDevice; 8use super::UsbDevice;
8use super::MAX_INTERFACE_COUNT; 9use super::MAX_INTERFACE_COUNT;
9 10
@@ -119,6 +120,7 @@ impl<'a> Config<'a> {
119/// Used to build new [`UsbDevice`]s. 120/// Used to build new [`UsbDevice`]s.
120pub struct UsbDeviceBuilder<'d, D: Driver<'d>> { 121pub struct UsbDeviceBuilder<'d, D: Driver<'d>> {
121 config: Config<'d>, 122 config: Config<'d>,
123 handler: Option<&'d dyn DeviceStateHandler>,
122 interfaces: Vec<(u8, &'d mut dyn ControlHandler), MAX_INTERFACE_COUNT>, 124 interfaces: Vec<(u8, &'d mut dyn ControlHandler), MAX_INTERFACE_COUNT>,
123 control_buf: &'d mut [u8], 125 control_buf: &'d mut [u8],
124 126
@@ -145,6 +147,7 @@ impl<'d, D: Driver<'d>> UsbDeviceBuilder<'d, D> {
145 config_descriptor_buf: &'d mut [u8], 147 config_descriptor_buf: &'d mut [u8],
146 bos_descriptor_buf: &'d mut [u8], 148 bos_descriptor_buf: &'d mut [u8],
147 control_buf: &'d mut [u8], 149 control_buf: &'d mut [u8],
150 handler: Option<&'d dyn DeviceStateHandler>,
148 ) -> Self { 151 ) -> Self {
149 // Magic values specified in USB-IF ECN on IADs. 152 // Magic values specified in USB-IF ECN on IADs.
150 if config.composite_with_iads 153 if config.composite_with_iads
@@ -174,6 +177,7 @@ impl<'d, D: Driver<'d>> UsbDeviceBuilder<'d, D> {
174 177
175 UsbDeviceBuilder { 178 UsbDeviceBuilder {
176 driver, 179 driver,
180 handler,
177 config, 181 config,
178 interfaces: Vec::new(), 182 interfaces: Vec::new(),
179 control_buf, 183 control_buf,
@@ -187,20 +191,20 @@ impl<'d, D: Driver<'d>> UsbDeviceBuilder<'d, D> {
187 } 191 }
188 192
189 /// Creates the [`UsbDevice`] instance with the configuration in this builder. 193 /// Creates the [`UsbDevice`] instance with the configuration in this builder.
190 pub async fn build(mut self) -> UsbDevice<'d, D> { 194 pub fn build(mut self) -> UsbDevice<'d, D> {
191 self.config_descriptor.end_configuration(); 195 self.config_descriptor.end_configuration();
192 self.bos_descriptor.end_bos(); 196 self.bos_descriptor.end_bos();
193 197
194 UsbDevice::build( 198 UsbDevice::build(
195 self.driver, 199 self.driver,
196 self.config, 200 self.config,
201 self.handler,
197 self.device_descriptor.into_buf(), 202 self.device_descriptor.into_buf(),
198 self.config_descriptor.into_buf(), 203 self.config_descriptor.into_buf(),
199 self.bos_descriptor.writer.into_buf(), 204 self.bos_descriptor.writer.into_buf(),
200 self.interfaces, 205 self.interfaces,
201 self.control_buf, 206 self.control_buf,
202 ) 207 )
203 .await
204 } 208 }
205 209
206 /// Allocates a new interface number. 210 /// Allocates a new interface number.
diff --git a/embassy-usb/src/driver.rs b/embassy-usb/src/driver.rs
index 875ceafcb..cedd349fb 100644
--- a/embassy-usb/src/driver.rs
+++ b/embassy-usb/src/driver.rs
@@ -11,7 +11,6 @@ pub trait Driver<'a> {
11 type EndpointIn: EndpointIn + 'a; 11 type EndpointIn: EndpointIn + 'a;
12 type ControlPipe: ControlPipe + 'a; 12 type ControlPipe: ControlPipe + 'a;
13 type Bus: Bus + 'a; 13 type Bus: Bus + 'a;
14 type EnableFuture: Future<Output = Self::Bus> + 'a;
15 14
16 /// Allocates an endpoint and specified endpoint parameters. This method is called by the device 15 /// Allocates an endpoint and specified endpoint parameters. This method is called by the device
17 /// and class implementations to allocate endpoints, and can only be called before 16 /// and class implementations to allocate endpoints, and can only be called before
@@ -47,7 +46,7 @@ pub trait Driver<'a> {
47 46
48 /// Enables and initializes the USB peripheral. Soon after enabling the device will be reset, so 47 /// Enables and initializes the USB peripheral. Soon after enabling the device will be reset, so
49 /// there is no need to perform a USB reset in this method. 48 /// there is no need to perform a USB reset in this method.
50 fn enable(self) -> Self::EnableFuture; 49 fn into_bus(self) -> Self::Bus;
51 50
52 /// Indicates that `set_device_address` must be called before accepting the corresponding 51 /// Indicates that `set_device_address` must be called before accepting the corresponding
53 /// control transfer, not after. 52 /// control transfer, not after.
@@ -57,18 +56,27 @@ pub trait Driver<'a> {
57} 56}
58 57
59pub trait Bus { 58pub trait Bus {
59 type EnableFuture<'a>: Future<Output = ()> + 'a
60 where
61 Self: 'a;
62 type DisableFuture<'a>: Future<Output = ()> + 'a
63 where
64 Self: 'a;
60 type PollFuture<'a>: Future<Output = Event> + 'a 65 type PollFuture<'a>: Future<Output = Event> + 'a
61 where 66 where
62 Self: 'a; 67 Self: 'a;
68 type RemoteWakeupFuture<'a>: Future<Output = Result<(), Unsupported>> + 'a
69 where
70 Self: 'a;
63 71
64 fn poll<'a>(&'a mut self) -> Self::PollFuture<'a>; 72 /// Enables the USB peripheral. Soon after enabling the device will be reset, so
73 /// there is no need to perform a USB reset in this method.
74 fn enable(&mut self) -> Self::EnableFuture<'_>;
65 75
66 /// Called when the host resets the device. This will be soon called after 76 /// Disables and powers down the USB peripheral.
67 /// [`poll`](crate::device::UsbDevice::poll) returns [`PollResult::Reset`]. This method should 77 fn disable(&mut self) -> Self::DisableFuture<'_>;
68 /// reset the state of all endpoints and peripheral flags back to a state suitable for 78
69 /// enumeration, as well as ensure that all endpoints previously allocated with alloc_ep are 79 fn poll<'a>(&'a mut self) -> Self::PollFuture<'a>;
70 /// initialized as specified.
71 fn reset(&mut self);
72 80
73 /// Sets the device USB address to `addr`. 81 /// Sets the device USB address to `addr`.
74 fn set_device_address(&mut self, addr: u8); 82 fn set_device_address(&mut self, addr: u8);
@@ -83,17 +91,6 @@ pub trait Bus {
83 /// Gets whether the STALL condition is set for an endpoint. Only used during control transfers. 91 /// Gets whether the STALL condition is set for an endpoint. Only used during control transfers.
84 fn is_stalled(&mut self, ep_addr: EndpointAddress) -> bool; 92 fn is_stalled(&mut self, ep_addr: EndpointAddress) -> bool;
85 93
86 /// Causes the USB peripheral to enter USB suspend mode, lowering power consumption and
87 /// preparing to detect a USB wakeup event. This will be called after
88 /// [`poll`](crate::device::UsbDevice::poll) returns [`PollResult::Suspend`]. The device will
89 /// continue be polled, and it shall return a value other than `Suspend` from `poll` when it no
90 /// longer detects the suspend condition.
91 fn suspend(&mut self);
92
93 /// Resumes from suspend mode. This may only be called after the peripheral has been previously
94 /// suspended.
95 fn resume(&mut self);
96
97 /// Simulates a disconnect from the USB bus, causing the host to reset and re-enumerate the 94 /// Simulates a disconnect from the USB bus, causing the host to reset and re-enumerate the
98 /// device. 95 /// device.
99 /// 96 ///
@@ -106,6 +103,14 @@ pub trait Bus {
106 fn force_reset(&mut self) -> Result<(), Unsupported> { 103 fn force_reset(&mut self) -> Result<(), Unsupported> {
107 Err(Unsupported) 104 Err(Unsupported)
108 } 105 }
106
107 /// Initiates a remote wakeup of the host by the device.
108 ///
109 /// # Errors
110 ///
111 /// * [`Unsupported`](crate::UsbError::Unsupported) - This UsbBus implementation doesn't support
112 /// remote wakeup or it has not been enabled at creation time.
113 fn remote_wakeup(&mut self) -> Self::RemoteWakeupFuture<'_>;
109} 114}
110 115
111pub trait Endpoint { 116pub trait Endpoint {
diff --git a/embassy-usb/src/lib.rs b/embassy-usb/src/lib.rs
index e98cbdee3..baeca099f 100644
--- a/embassy-usb/src/lib.rs
+++ b/embassy-usb/src/lib.rs
@@ -10,15 +10,14 @@ pub mod control;
10pub mod descriptor; 10pub mod descriptor;
11pub mod driver; 11pub mod driver;
12pub mod types; 12pub mod types;
13mod util;
14 13
14use embassy::util::{select, Either};
15use heapless::Vec; 15use heapless::Vec;
16 16
17use self::control::*; 17use self::control::*;
18use self::descriptor::*; 18use self::descriptor::*;
19use self::driver::{Bus, Driver, Event}; 19use self::driver::{Bus, Driver, Event};
20use self::types::*; 20use self::types::*;
21use self::util::*;
22 21
23pub use self::builder::Config; 22pub use self::builder::Config;
24pub use self::builder::UsbDeviceBuilder; 23pub use self::builder::UsbDeviceBuilder;
@@ -28,8 +27,12 @@ pub use self::builder::UsbDeviceBuilder;
28/// In general class traffic is only possible in the `Configured` state. 27/// In general class traffic is only possible in the `Configured` state.
29#[repr(u8)] 28#[repr(u8)]
30#[derive(PartialEq, Eq, Copy, Clone, Debug)] 29#[derive(PartialEq, Eq, Copy, Clone, Debug)]
30#[cfg_attr(feature = "defmt", derive(defmt::Format))]
31pub enum UsbDeviceState { 31pub enum UsbDeviceState {
32 /// The USB device has just been created or reset. 32 /// The USB device is disabled.
33 Disabled,
34
35 /// The USB device has just been enabled or reset.
33 Default, 36 Default,
34 37
35 /// The USB device has received an address from the host. 38 /// The USB device has received an address from the host.
@@ -37,9 +40,19 @@ pub enum UsbDeviceState {
37 40
38 /// The USB device has been configured and is fully functional. 41 /// The USB device has been configured and is fully functional.
39 Configured, 42 Configured,
43}
40 44
41 /// The USB device has been suspended by the host or it has been unplugged from the USB bus. 45#[derive(PartialEq, Eq, Copy, Clone, Debug)]
42 Suspend, 46#[cfg_attr(feature = "defmt", derive(defmt::Format))]
47pub enum RemoteWakeupError {
48 InvalidState,
49 Unsupported,
50}
51
52impl From<driver::Unsupported> for RemoteWakeupError {
53 fn from(_: driver::Unsupported) -> Self {
54 RemoteWakeupError::Unsupported
55 }
43} 56}
44 57
45/// The bConfiguration value for the not configured state. 58/// The bConfiguration value for the not configured state.
@@ -53,8 +66,30 @@ pub const DEFAULT_ALTERNATE_SETTING: u8 = 0;
53 66
54pub const MAX_INTERFACE_COUNT: usize = 4; 67pub const MAX_INTERFACE_COUNT: usize = 4;
55 68
69/// A handler trait for changes in the device state of the [UsbDevice].
70pub trait DeviceStateHandler {
71 /// Called when the USB device has been enabled or disabled.
72 fn enabled(&self, _enabled: bool) {}
73
74 /// Called when the host resets the device.
75 fn reset(&self) {}
76
77 /// Called when the host has set the address of the device to `addr`.
78 fn addressed(&self, _addr: u8) {}
79
80 /// Called when the host has enabled or disabled the configuration of the device.
81 fn configured(&self, _configured: bool) {}
82
83 /// Called when the bus has entered or exited the suspend state.
84 fn suspended(&self, _suspended: bool) {}
85
86 /// Called when remote wakeup feature is enabled or disabled.
87 fn remote_wakeup_enabled(&self, _enabled: bool) {}
88}
89
56pub struct UsbDevice<'d, D: Driver<'d>> { 90pub struct UsbDevice<'d, D: Driver<'d>> {
57 bus: D::Bus, 91 bus: D::Bus,
92 handler: Option<&'d dyn DeviceStateHandler>,
58 control: ControlPipe<D::ControlPipe>, 93 control: ControlPipe<D::ControlPipe>,
59 94
60 config: Config<'d>, 95 config: Config<'d>,
@@ -64,6 +99,7 @@ pub struct UsbDevice<'d, D: Driver<'d>> {
64 control_buf: &'d mut [u8], 99 control_buf: &'d mut [u8],
65 100
66 device_state: UsbDeviceState, 101 device_state: UsbDeviceState,
102 suspended: bool,
67 remote_wakeup_enabled: bool, 103 remote_wakeup_enabled: bool,
68 self_powered: bool, 104 self_powered: bool,
69 pending_address: u8, 105 pending_address: u8,
@@ -72,9 +108,10 @@ pub struct UsbDevice<'d, D: Driver<'d>> {
72} 108}
73 109
74impl<'d, D: Driver<'d>> UsbDevice<'d, D> { 110impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
75 pub(crate) async fn build( 111 pub(crate) fn build(
76 mut driver: D, 112 mut driver: D,
77 config: Config<'d>, 113 config: Config<'d>,
114 handler: Option<&'d dyn DeviceStateHandler>,
78 device_descriptor: &'d [u8], 115 device_descriptor: &'d [u8],
79 config_descriptor: &'d [u8], 116 config_descriptor: &'d [u8],
80 bos_descriptor: &'d [u8], 117 bos_descriptor: &'d [u8],
@@ -87,17 +124,19 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
87 124
88 // Enable the USB bus. 125 // Enable the USB bus.
89 // This prevent further allocation by consuming the driver. 126 // This prevent further allocation by consuming the driver.
90 let bus = driver.enable().await; 127 let bus = driver.into_bus();
91 128
92 Self { 129 Self {
93 bus, 130 bus,
94 config, 131 config,
132 handler,
95 control: ControlPipe::new(control), 133 control: ControlPipe::new(control),
96 device_descriptor, 134 device_descriptor,
97 config_descriptor, 135 config_descriptor,
98 bos_descriptor, 136 bos_descriptor,
99 control_buf, 137 control_buf,
100 device_state: UsbDeviceState::Default, 138 device_state: UsbDeviceState::Disabled,
139 suspended: false,
101 remote_wakeup_enabled: false, 140 remote_wakeup_enabled: false,
102 self_powered: false, 141 self_powered: false,
103 pending_address: 0, 142 pending_address: 0,
@@ -105,34 +144,46 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
105 } 144 }
106 } 145 }
107 146
108 pub async fn run(&mut self) { 147 /// Runs the `UsbDevice` forever.
148 ///
149 /// This future may leave the bus in an invalid state if it is dropped.
150 /// After dropping the future, [`UsbDevice::disable()`] should be called
151 /// before calling any other `UsbDevice` methods to fully reset the
152 /// peripheral.
153 pub async fn run(&mut self) -> ! {
154 loop {
155 self.run_until_suspend().await;
156 self.wait_resume().await;
157 }
158 }
159
160 /// Runs the `UsbDevice` until the bus is suspended.
161 ///
162 /// This future may leave the bus in an invalid state if it is dropped.
163 /// After dropping the future, [`UsbDevice::disable()`] should be called
164 /// before calling any other `UsbDevice` methods to fully reset the
165 /// peripheral.
166 pub async fn run_until_suspend(&mut self) -> () {
167 if self.device_state == UsbDeviceState::Disabled {
168 self.bus.enable().await;
169 self.device_state = UsbDeviceState::Default;
170
171 if let Some(h) = &self.handler {
172 h.enabled(true);
173 }
174 }
175
109 loop { 176 loop {
110 let control_fut = self.control.setup(); 177 let control_fut = self.control.setup();
111 let bus_fut = self.bus.poll(); 178 let bus_fut = self.bus.poll();
112 match select(bus_fut, control_fut).await { 179 match select(bus_fut, control_fut).await {
113 Either::Left(evt) => match evt { 180 Either::First(evt) => {
114 Event::Reset => { 181 self.handle_bus_event(evt);
115 trace!("usb: reset"); 182 if self.suspended {
116 self.bus.reset(); 183 return;
117
118 self.device_state = UsbDeviceState::Default;
119 self.remote_wakeup_enabled = false;
120 self.pending_address = 0;
121
122 for (_, h) in self.interfaces.iter_mut() {
123 h.reset();
124 }
125 }
126 Event::Resume => {
127 trace!("usb: resume");
128 }
129 Event::Suspend => {
130 trace!("usb: suspend");
131 self.bus.suspend();
132 self.device_state = UsbDeviceState::Suspend;
133 } 184 }
134 }, 185 }
135 Either::Right(req) => match req { 186 Either::Second(req) => match req {
136 Setup::DataIn(req, stage) => self.handle_control_in(req, stage).await, 187 Setup::DataIn(req, stage) => self.handle_control_in(req, stage).await,
137 Setup::DataOut(req, stage) => self.handle_control_out(req, stage).await, 188 Setup::DataOut(req, stage) => self.handle_control_out(req, stage).await,
138 }, 189 },
@@ -140,6 +191,87 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
140 } 191 }
141 } 192 }
142 193
194 /// Disables the USB peripheral.
195 pub async fn disable(&mut self) {
196 if self.device_state != UsbDeviceState::Disabled {
197 self.bus.disable().await;
198 self.device_state = UsbDeviceState::Disabled;
199 self.suspended = false;
200 self.remote_wakeup_enabled = false;
201
202 if let Some(h) = &self.handler {
203 h.enabled(false);
204 }
205 }
206 }
207
208 /// Waits for a resume condition on the USB bus.
209 ///
210 /// This future is cancel-safe.
211 pub async fn wait_resume(&mut self) {
212 while self.suspended {
213 let evt = self.bus.poll().await;
214 self.handle_bus_event(evt);
215 }
216 }
217
218 /// Initiates a device remote wakeup on the USB bus.
219 ///
220 /// If the bus is not suspended or remote wakeup is not enabled, an error
221 /// will be returned.
222 ///
223 /// This future may leave the bus in an inconsistent state if dropped.
224 /// After dropping the future, [`UsbDevice::disable()`] should be called
225 /// before calling any other `UsbDevice` methods to fully reset the peripheral.
226 pub async fn remote_wakeup(&mut self) -> Result<(), RemoteWakeupError> {
227 if self.suspended && self.remote_wakeup_enabled {
228 self.bus.remote_wakeup().await?;
229 self.suspended = false;
230
231 if let Some(h) = &self.handler {
232 h.suspended(false);
233 }
234
235 Ok(())
236 } else {
237 Err(RemoteWakeupError::InvalidState)
238 }
239 }
240
241 fn handle_bus_event(&mut self, evt: Event) {
242 match evt {
243 Event::Reset => {
244 trace!("usb: reset");
245 self.device_state = UsbDeviceState::Default;
246 self.suspended = false;
247 self.remote_wakeup_enabled = false;
248 self.pending_address = 0;
249
250 for (_, h) in self.interfaces.iter_mut() {
251 h.reset();
252 }
253
254 if let Some(h) = &self.handler {
255 h.reset();
256 }
257 }
258 Event::Resume => {
259 trace!("usb: resume");
260 self.suspended = false;
261 if let Some(h) = &self.handler {
262 h.suspended(false);
263 }
264 }
265 Event::Suspend => {
266 trace!("usb: suspend");
267 self.suspended = true;
268 if let Some(h) = &self.handler {
269 h.suspended(true);
270 }
271 }
272 }
273 }
274
143 async fn handle_control_out(&mut self, req: Request, stage: DataOutStage) { 275 async fn handle_control_out(&mut self, req: Request, stage: DataOutStage) {
144 const CONFIGURATION_NONE_U16: u16 = CONFIGURATION_NONE as u16; 276 const CONFIGURATION_NONE_U16: u16 = CONFIGURATION_NONE as u16;
145 const CONFIGURATION_VALUE_U16: u16 = CONFIGURATION_VALUE as u16; 277 const CONFIGURATION_VALUE_U16: u16 = CONFIGURATION_VALUE as u16;
@@ -156,20 +288,33 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
156 (RequestType::Standard, Recipient::Device) => match (req.request, req.value) { 288 (RequestType::Standard, Recipient::Device) => match (req.request, req.value) {
157 (Request::CLEAR_FEATURE, Request::FEATURE_DEVICE_REMOTE_WAKEUP) => { 289 (Request::CLEAR_FEATURE, Request::FEATURE_DEVICE_REMOTE_WAKEUP) => {
158 self.remote_wakeup_enabled = false; 290 self.remote_wakeup_enabled = false;
291 if let Some(h) = &self.handler {
292 h.remote_wakeup_enabled(false);
293 }
159 self.control.accept(stage) 294 self.control.accept(stage)
160 } 295 }
161 (Request::SET_FEATURE, Request::FEATURE_DEVICE_REMOTE_WAKEUP) => { 296 (Request::SET_FEATURE, Request::FEATURE_DEVICE_REMOTE_WAKEUP) => {
162 self.remote_wakeup_enabled = true; 297 self.remote_wakeup_enabled = true;
298 if let Some(h) = &self.handler {
299 h.remote_wakeup_enabled(true);
300 }
163 self.control.accept(stage) 301 self.control.accept(stage)
164 } 302 }
165 (Request::SET_ADDRESS, addr @ 1..=127) => { 303 (Request::SET_ADDRESS, addr @ 1..=127) => {
166 self.pending_address = addr as u8; 304 self.pending_address = addr as u8;
167 self.bus.set_device_address(self.pending_address); 305 self.bus.set_device_address(self.pending_address);
306 self.device_state = UsbDeviceState::Addressed;
307 if let Some(h) = &self.handler {
308 h.addressed(self.pending_address);
309 }
168 self.control.accept(stage) 310 self.control.accept(stage)
169 } 311 }
170 (Request::SET_CONFIGURATION, CONFIGURATION_VALUE_U16) => { 312 (Request::SET_CONFIGURATION, CONFIGURATION_VALUE_U16) => {
171 self.device_state = UsbDeviceState::Configured; 313 self.device_state = UsbDeviceState::Configured;
172 self.bus.set_configured(true); 314 self.bus.set_configured(true);
315 if let Some(h) = &self.handler {
316 h.configured(true);
317 }
173 self.control.accept(stage) 318 self.control.accept(stage)
174 } 319 }
175 (Request::SET_CONFIGURATION, CONFIGURATION_NONE_U16) => match self.device_state { 320 (Request::SET_CONFIGURATION, CONFIGURATION_NONE_U16) => match self.device_state {
@@ -177,6 +322,9 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
177 _ => { 322 _ => {
178 self.device_state = UsbDeviceState::Addressed; 323 self.device_state = UsbDeviceState::Addressed;
179 self.bus.set_configured(false); 324 self.bus.set_configured(false);
325 if let Some(h) = &self.handler {
326 h.configured(false);
327 }
180 self.control.accept(stage) 328 self.control.accept(stage)
181 } 329 }
182 }, 330 },
diff --git a/embassy-usb/src/util.rs b/embassy-usb/src/util.rs
deleted file mode 100644
index 18cc875c6..000000000
--- a/embassy-usb/src/util.rs
+++ /dev/null
@@ -1,45 +0,0 @@
1use core::future::Future;
2use core::pin::Pin;
3use core::task::{Context, Poll};
4
5#[derive(Debug, Clone)]
6pub enum Either<A, B> {
7 Left(A),
8 Right(B),
9}
10
11pub fn select<A, B>(a: A, b: B) -> Select<A, B>
12where
13 A: Future,
14 B: Future,
15{
16 Select { a, b }
17}
18
19pub struct Select<A, B> {
20 a: A,
21 b: B,
22}
23
24impl<A: Unpin, B: Unpin> Unpin for Select<A, B> {}
25
26impl<A, B> Future for Select<A, B>
27where
28 A: Future,
29 B: Future,
30{
31 type Output = Either<A::Output, B::Output>;
32
33 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
34 let this = unsafe { self.get_unchecked_mut() };
35 let a = unsafe { Pin::new_unchecked(&mut this.a) };
36 let b = unsafe { Pin::new_unchecked(&mut this.b) };
37 match a.poll(cx) {
38 Poll::Ready(x) => Poll::Ready(Either::Left(x)),
39 Poll::Pending => match b.poll(cx) {
40 Poll::Ready(x) => Poll::Ready(Either::Right(x)),
41 Poll::Pending => Poll::Pending,
42 },
43 }
44 }
45}
diff --git a/examples/nrf/src/bin/usb_hid_keyboard.rs b/examples/nrf/src/bin/usb_hid_keyboard.rs
index 0812697e4..5f03f5126 100644
--- a/examples/nrf/src/bin/usb_hid_keyboard.rs
+++ b/examples/nrf/src/bin/usb_hid_keyboard.rs
@@ -4,16 +4,20 @@
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::channel::Signal;
8use embassy::executor::Spawner; 10use embassy::executor::Spawner;
11use embassy::interrupt::InterruptExt;
9use embassy::time::Duration; 12use embassy::time::Duration;
13use embassy::util::{select, select3, Either, Either3};
10use embassy_nrf::gpio::{Input, Pin, Pull}; 14use embassy_nrf::gpio::{Input, Pin, Pull};
11use embassy_nrf::interrupt; 15use embassy_nrf::interrupt;
12use embassy_nrf::pac; 16use 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, 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,25 @@ 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 ENABLE_USB: Signal<bool> = Signal::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 ENABLE_USB.signal(true);
38 }
39
40 if regs.events_usbremoved.read().bits() != 0 {
41 regs.events_usbremoved.reset();
42 info!("Vbus removed, disabling USB...");
43 ENABLE_USB.signal(false);
44 }
45}
46
24#[embassy::main] 47#[embassy::main]
25async fn main(_spawner: Spawner, p: Peripherals) { 48async fn main(_spawner: Spawner, p: Peripherals) {
26 let clock: pac::CLOCK = unsafe { mem::transmute(()) }; 49 let clock: pac::CLOCK = unsafe { mem::transmute(()) };
@@ -30,10 +53,6 @@ async fn main(_spawner: Spawner, p: Peripherals) {
30 clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) }); 53 clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) });
31 while clock.events_hfclkstarted.read().bits() != 1 {} 54 while clock.events_hfclkstarted.read().bits() != 1 {}
32 55
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. 56 // Create the driver, from the HAL.
38 let irq = interrupt::take!(USBD); 57 let irq = interrupt::take!(USBD);
39 let driver = Driver::new(p.USBD, irq); 58 let driver = Driver::new(p.USBD, irq);
@@ -45,6 +64,7 @@ async fn main(_spawner: Spawner, p: Peripherals) {
45 config.serial_number = Some("12345678"); 64 config.serial_number = Some("12345678");
46 config.max_power = 100; 65 config.max_power = 100;
47 config.max_packet_size_0 = 64; 66 config.max_packet_size_0 = 64;
67 config.supports_remote_wakeup = true;
48 68
49 // Create embassy-usb DeviceBuilder using the driver and config. 69 // Create embassy-usb DeviceBuilder using the driver and config.
50 // It needs some buffers for building the descriptors. 70 // It needs some buffers for building the descriptors.
@@ -53,6 +73,7 @@ async fn main(_spawner: Spawner, p: Peripherals) {
53 let mut bos_descriptor = [0; 256]; 73 let mut bos_descriptor = [0; 256];
54 let mut control_buf = [0; 16]; 74 let mut control_buf = [0; 16];
55 let request_handler = MyRequestHandler {}; 75 let request_handler = MyRequestHandler {};
76 let device_state_handler = MyDeviceStateHandler::new();
56 77
57 let mut state = State::<8, 1>::new(); 78 let mut state = State::<8, 1>::new();
58 79
@@ -63,6 +84,7 @@ async fn main(_spawner: Spawner, p: Peripherals) {
63 &mut config_descriptor, 84 &mut config_descriptor,
64 &mut bos_descriptor, 85 &mut bos_descriptor,
65 &mut control_buf, 86 &mut control_buf,
87 Some(&device_state_handler),
66 ); 88 );
67 89
68 // Create classes on the builder. 90 // Create classes on the builder.
@@ -76,10 +98,40 @@ async fn main(_spawner: Spawner, p: Peripherals) {
76 ); 98 );
77 99
78 // Build the builder. 100 // Build the builder.
79 let mut usb = builder.build().await; 101 let mut usb = builder.build();
102
103 let remote_wakeup = Signal::new();
80 104
81 // Run the USB device. 105 // Run the USB device.
82 let usb_fut = usb.run(); 106 let usb_fut = async {
107 enable_command().await;
108 loop {
109 match select(usb.run_until_suspend(), ENABLE_USB.wait()).await {
110 Either::First(_) => {}
111 Either::Second(enable) => {
112 if enable {
113 warn!("Enable when already enabled!");
114 } else {
115 usb.disable().await;
116 enable_command().await;
117 }
118 }
119 }
120
121 match select3(usb.wait_resume(), ENABLE_USB.wait(), remote_wakeup.wait()).await {
122 Either3::First(_) => (),
123 Either3::Second(enable) => {
124 if enable {
125 warn!("Enable when already enabled!");
126 } else {
127 usb.disable().await;
128 enable_command().await;
129 }
130 }
131 Either3::Third(_) => unwrap!(usb.remote_wakeup().await),
132 }
133 }
134 };
83 135
84 let mut button = Input::new(p.P0_11.degrade(), Pull::Up); 136 let mut button = Input::new(p.P0_11.degrade(), Pull::Up);
85 137
@@ -90,16 +142,22 @@ async fn main(_spawner: Spawner, p: Peripherals) {
90 loop { 142 loop {
91 button.wait_for_low().await; 143 button.wait_for_low().await;
92 info!("PRESSED"); 144 info!("PRESSED");
93 let report = KeyboardReport { 145
94 keycodes: [4, 0, 0, 0, 0, 0], 146 if SUSPENDED.load(Ordering::Acquire) {
95 leds: 0, 147 info!("Triggering remote wakeup");
96 modifier: 0, 148 remote_wakeup.signal(());
97 reserved: 0, 149 } else {
98 }; 150 let report = KeyboardReport {
99 match hid_in.serialize(&report).await { 151 keycodes: [4, 0, 0, 0, 0, 0],
100 Ok(()) => {} 152 leds: 0,
101 Err(e) => warn!("Failed to send report: {:?}", e), 153 modifier: 0,
102 }; 154 reserved: 0,
155 };
156 match hid_in.serialize(&report).await {
157 Ok(()) => {}
158 Err(e) => warn!("Failed to send report: {:?}", e),
159 };
160 }
103 161
104 button.wait_for_high().await; 162 button.wait_for_high().await;
105 info!("RELEASED"); 163 info!("RELEASED");
@@ -119,11 +177,31 @@ async fn main(_spawner: Spawner, p: Peripherals) {
119 let out_fut = async { 177 let out_fut = async {
120 hid_out.run(false, &request_handler).await; 178 hid_out.run(false, &request_handler).await;
121 }; 179 };
180
181 let power_irq = interrupt::take!(POWER_CLOCK);
182 power_irq.set_handler(on_power_interrupt);
183 power_irq.unpend();
184 power_irq.enable();
185
186 power
187 .intenset
188 .write(|w| w.usbdetected().set().usbremoved().set());
189
122 // Run everything concurrently. 190 // Run everything concurrently.
123 // If we had made everything `'static` above instead, we could do this using separate tasks instead. 191 // 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; 192 join(usb_fut, join(in_fut, out_fut)).await;
125} 193}
126 194
195async fn enable_command() {
196 loop {
197 if ENABLE_USB.wait().await {
198 break;
199 } else {
200 warn!("Received disable signal when already disabled!");
201 }
202 }
203}
204
127struct MyRequestHandler {} 205struct MyRequestHandler {}
128 206
129impl RequestHandler for MyRequestHandler { 207impl RequestHandler for MyRequestHandler {
@@ -146,3 +224,64 @@ impl RequestHandler for MyRequestHandler {
146 None 224 None
147 } 225 }
148} 226}
227
228struct MyDeviceStateHandler {
229 configured: AtomicBool,
230}
231
232impl MyDeviceStateHandler {
233 fn new() -> Self {
234 MyDeviceStateHandler {
235 configured: AtomicBool::new(false),
236 }
237 }
238}
239
240impl DeviceStateHandler for MyDeviceStateHandler {
241 fn enabled(&self, enabled: bool) {
242 self.configured.store(false, Ordering::Relaxed);
243 SUSPENDED.store(false, Ordering::Release);
244 if enabled {
245 info!("Device enabled");
246 } else {
247 info!("Device disabled");
248 }
249 }
250
251 fn reset(&self) {
252 self.configured.store(false, Ordering::Relaxed);
253 info!("Bus reset, the Vbus current limit is 100mA");
254 }
255
256 fn addressed(&self, addr: u8) {
257 self.configured.store(false, Ordering::Relaxed);
258 info!("USB address set to: {}", addr);
259 }
260
261 fn configured(&self, configured: bool) {
262 self.configured.store(configured, Ordering::Relaxed);
263 if configured {
264 info!(
265 "Device configured, it may now draw up to the configured current limit from Vbus."
266 )
267 } else {
268 info!("Device is no longer configured, the Vbus current limit is 100mA.");
269 }
270 }
271
272 fn suspended(&self, suspended: bool) {
273 if suspended {
274 info!("Device suspended, the Vbus current limit is 500µA (or 2.5mA for high-power devices with remote wakeup enabled).");
275 SUSPENDED.store(true, Ordering::Release);
276 } else {
277 SUSPENDED.store(false, Ordering::Release);
278 if self.configured.load(Ordering::Relaxed) {
279 info!(
280 "Device resumed, it may now draw up to the configured current limit from Vbus"
281 );
282 } else {
283 info!("Device resumed, the Vbus current limit is 100mA");
284 }
285 }
286 }
287}
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)));