diff options
| author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2022-04-14 15:16:55 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2022-04-14 15:16:55 +0000 |
| commit | 3a90a8eb4a5ef61aef034025ac882255c94260dc (patch) | |
| tree | a40a8f9bb7b847d168a5b4c725d678d59d4d7823 | |
| parent | 391fdc097ec1691cfab6a3db5c3992f6f2e6da8e (diff) | |
| parent | b0725c14d36cb9c508cb9fcec5b92ca9e0148583 (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.rs | 109 | ||||
| -rw-r--r-- | embassy-usb/src/builder.rs | 8 | ||||
| -rw-r--r-- | embassy-usb/src/driver.rs | 45 | ||||
| -rw-r--r-- | embassy-usb/src/lib.rs | 210 | ||||
| -rw-r--r-- | embassy-usb/src/util.rs | 45 | ||||
| -rw-r--r-- | examples/nrf/src/bin/usb_hid_keyboard.rs | 173 | ||||
| -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 |
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; | |||
| 10 | use embassy::waitqueue::AtomicWaker; | 10 | use embassy::waitqueue::AtomicWaker; |
| 11 | use embassy_hal_common::unborrow; | 11 | use embassy_hal_common::unborrow; |
| 12 | use embassy_usb::control::Request; | 12 | use embassy_usb::control::Request; |
| 13 | use embassy_usb::driver::{self, EndpointError, Event}; | 13 | use embassy_usb::driver::{self, EndpointError, Event, Unsupported}; |
| 14 | use embassy_usb::types::{EndpointAddress, EndpointInfo, EndpointType, UsbDirection}; | 14 | use embassy_usb::types::{EndpointAddress, EndpointInfo, EndpointType, UsbDirection}; |
| 15 | use futures::future::poll_fn; | 15 | use futures::future::poll_fn; |
| 16 | use futures::Future; | 16 | use 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 | |||
| 203 | pub struct Bus<'d, T: Instance> { | ||
| 204 | phantom: PhantomData<&'d mut T>, | ||
| 205 | alloc_in: Allocator, | ||
| 206 | alloc_out: Allocator, | ||
| 207 | } | ||
| 208 | |||
| 209 | impl<'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 | |||
| 239 | pub struct Bus<'d, T: Instance> { | ||
| 240 | phantom: PhantomData<&'d mut T>, | ||
| 241 | alloc_in: Allocator, | ||
| 242 | alloc_out: Allocator, | ||
| 243 | } | ||
| 244 | 251 | ||
| 245 | impl<'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 { | |||
| 834 | mod errata { | 867 | mod 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; | |||
| 4 | use super::descriptor::{BosWriter, DescriptorWriter}; | 4 | use super::descriptor::{BosWriter, DescriptorWriter}; |
| 5 | use super::driver::{Driver, EndpointAllocError}; | 5 | use super::driver::{Driver, EndpointAllocError}; |
| 6 | use super::types::*; | 6 | use super::types::*; |
| 7 | use super::DeviceStateHandler; | ||
| 7 | use super::UsbDevice; | 8 | use super::UsbDevice; |
| 8 | use super::MAX_INTERFACE_COUNT; | 9 | use 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. |
| 120 | pub struct UsbDeviceBuilder<'d, D: Driver<'d>> { | 121 | pub 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 | ||
| 59 | pub trait Bus { | 58 | pub 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 | ||
| 111 | pub trait Endpoint { | 116 | pub 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; | |||
| 10 | pub mod descriptor; | 10 | pub mod descriptor; |
| 11 | pub mod driver; | 11 | pub mod driver; |
| 12 | pub mod types; | 12 | pub mod types; |
| 13 | mod util; | ||
| 14 | 13 | ||
| 14 | use embassy::util::{select, Either}; | ||
| 15 | use heapless::Vec; | 15 | use heapless::Vec; |
| 16 | 16 | ||
| 17 | use self::control::*; | 17 | use self::control::*; |
| 18 | use self::descriptor::*; | 18 | use self::descriptor::*; |
| 19 | use self::driver::{Bus, Driver, Event}; | 19 | use self::driver::{Bus, Driver, Event}; |
| 20 | use self::types::*; | 20 | use self::types::*; |
| 21 | use self::util::*; | ||
| 22 | 21 | ||
| 23 | pub use self::builder::Config; | 22 | pub use self::builder::Config; |
| 24 | pub use self::builder::UsbDeviceBuilder; | 23 | pub 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))] | ||
| 31 | pub enum UsbDeviceState { | 31 | pub 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))] |
| 47 | pub enum RemoteWakeupError { | ||
| 48 | InvalidState, | ||
| 49 | Unsupported, | ||
| 50 | } | ||
| 51 | |||
| 52 | impl 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 | ||
| 54 | pub const MAX_INTERFACE_COUNT: usize = 4; | 67 | pub const MAX_INTERFACE_COUNT: usize = 4; |
| 55 | 68 | ||
| 69 | /// A handler trait for changes in the device state of the [UsbDevice]. | ||
| 70 | pub 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 | |||
| 56 | pub struct UsbDevice<'d, D: Driver<'d>> { | 90 | pub 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 | ||
| 74 | impl<'d, D: Driver<'d>> UsbDevice<'d, D> { | 110 | impl<'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 @@ | |||
| 1 | use core::future::Future; | ||
| 2 | use core::pin::Pin; | ||
| 3 | use core::task::{Context, Poll}; | ||
| 4 | |||
| 5 | #[derive(Debug, Clone)] | ||
| 6 | pub enum Either<A, B> { | ||
| 7 | Left(A), | ||
| 8 | Right(B), | ||
| 9 | } | ||
| 10 | |||
| 11 | pub fn select<A, B>(a: A, b: B) -> Select<A, B> | ||
| 12 | where | ||
| 13 | A: Future, | ||
| 14 | B: Future, | ||
| 15 | { | ||
| 16 | Select { a, b } | ||
| 17 | } | ||
| 18 | |||
| 19 | pub struct Select<A, B> { | ||
| 20 | a: A, | ||
| 21 | b: B, | ||
| 22 | } | ||
| 23 | |||
| 24 | impl<A: Unpin, B: Unpin> Unpin for Select<A, B> {} | ||
| 25 | |||
| 26 | impl<A, B> Future for Select<A, B> | ||
| 27 | where | ||
| 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 | ||
| 6 | use core::mem; | 6 | use core::mem; |
| 7 | use core::sync::atomic::{AtomicBool, Ordering}; | ||
| 7 | use defmt::*; | 8 | use defmt::*; |
| 9 | use embassy::channel::Signal; | ||
| 8 | use embassy::executor::Spawner; | 10 | use embassy::executor::Spawner; |
| 11 | use embassy::interrupt::InterruptExt; | ||
| 9 | use embassy::time::Duration; | 12 | use embassy::time::Duration; |
| 13 | use embassy::util::{select, select3, Either, Either3}; | ||
| 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; |
| 12 | use embassy_nrf::pac; | 16 | 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, 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,25 @@ 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 ENABLE_USB: Signal<bool> = Signal::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 | 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] |
| 25 | async fn main(_spawner: Spawner, p: Peripherals) { | 48 | async 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 | ||
| 195 | async 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 | |||
| 127 | struct MyRequestHandler {} | 205 | struct MyRequestHandler {} |
| 128 | 206 | ||
| 129 | impl RequestHandler for MyRequestHandler { | 207 | impl RequestHandler for MyRequestHandler { |
| @@ -146,3 +224,64 @@ impl RequestHandler for MyRequestHandler { | |||
| 146 | None | 224 | None |
| 147 | } | 225 | } |
| 148 | } | 226 | } |
| 227 | |||
| 228 | struct MyDeviceStateHandler { | ||
| 229 | configured: AtomicBool, | ||
| 230 | } | ||
| 231 | |||
| 232 | impl MyDeviceStateHandler { | ||
| 233 | fn new() -> Self { | ||
| 234 | MyDeviceStateHandler { | ||
| 235 | configured: AtomicBool::new(false), | ||
| 236 | } | ||
| 237 | } | ||
| 238 | } | ||
| 239 | |||
| 240 | impl 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))); |
