diff options
| author | alexmoon <[email protected]> | 2022-04-10 15:41:51 -0400 |
|---|---|---|
| committer | alexmoon <[email protected]> | 2022-04-13 14:55:02 -0400 |
| commit | f5656e354485888cc7c2697052ae2c79b94a59ad (patch) | |
| tree | 8580410dbaca2c3f0db6e431f77f248dd6bd5dc9 | |
| parent | 2217de24c02e9f7e0aafeb8315ab6be8b644c52f (diff) | |
Add DeviceStateHandler, DeviceCommand channel, and remote wakeup support
| -rw-r--r-- | embassy-nrf/src/usb.rs | 104 | ||||
| -rw-r--r-- | embassy-usb-hid/src/lib.rs | 13 | ||||
| -rw-r--r-- | embassy-usb-serial/src/lib.rs | 5 | ||||
| -rw-r--r-- | embassy-usb/src/builder.rs | 77 | ||||
| -rw-r--r-- | embassy-usb/src/driver.rs | 44 | ||||
| -rw-r--r-- | embassy-usb/src/lib.rs | 144 | ||||
| -rw-r--r-- | embassy-usb/src/util.rs | 72 | ||||
| -rw-r--r-- | examples/nrf/src/bin/usb_hid_keyboard.rs | 114 | ||||
| -rw-r--r-- | examples/nrf/src/bin/usb_hid_mouse.rs | 3 | ||||
| -rw-r--r-- | examples/nrf/src/bin/usb_serial.rs | 3 | ||||
| -rw-r--r-- | examples/nrf/src/bin/usb_serial_multitask.rs | 3 |
11 files changed, 472 insertions, 110 deletions
diff --git a/embassy-nrf/src/usb.rs b/embassy-nrf/src/usb.rs index 5e2f585f2..3d90f4b9a 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,27 @@ 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 PollFuture<'a> = impl Future<Output = Event> + 'a where Self: 'a; | ||
| 212 | type RemoteWakeupFuture<'a> = impl Future<Output = Result<(), Unsupported>> + 'a where Self: 'a; | ||
| 213 | |||
| 214 | fn enable(&mut self) -> Self::EnableFuture<'_> { | ||
| 196 | async move { | 215 | async move { |
| 197 | let regs = T::regs(); | 216 | let regs = T::regs(); |
| 198 | 217 | ||
| @@ -226,33 +245,23 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> { | |||
| 226 | // Enable the USB pullup, allowing enumeration. | 245 | // Enable the USB pullup, allowing enumeration. |
| 227 | regs.usbpullup.write(|w| w.connect().enabled()); | 246 | regs.usbpullup.write(|w| w.connect().enabled()); |
| 228 | trace!("enabled"); | 247 | trace!("enabled"); |
| 229 | |||
| 230 | Bus { | ||
| 231 | phantom: PhantomData, | ||
| 232 | alloc_in: self.alloc_in, | ||
| 233 | alloc_out: self.alloc_out, | ||
| 234 | } | ||
| 235 | } | 248 | } |
| 236 | } | 249 | } |
| 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 | 250 | ||
| 245 | impl<'d, T: Instance> driver::Bus for Bus<'d, T> { | 251 | fn disable(&mut self) { |
| 246 | type PollFuture<'a> = impl Future<Output = Event> + 'a where Self: 'a; | 252 | let regs = T::regs(); |
| 253 | regs.enable.write(|x| x.enable().disabled()); | ||
| 254 | } | ||
| 247 | 255 | ||
| 248 | fn poll<'a>(&'a mut self) -> Self::PollFuture<'a> { | 256 | fn poll<'a>(&'a mut self) -> Self::PollFuture<'a> { |
| 249 | poll_fn(|cx| { | 257 | poll_fn(move |cx| { |
| 250 | BUS_WAKER.register(cx.waker()); | 258 | BUS_WAKER.register(cx.waker()); |
| 251 | let regs = T::regs(); | 259 | let regs = T::regs(); |
| 252 | 260 | ||
| 253 | if regs.events_usbreset.read().bits() != 0 { | 261 | if regs.events_usbreset.read().bits() != 0 { |
| 254 | regs.events_usbreset.reset(); | 262 | regs.events_usbreset.reset(); |
| 255 | regs.intenset.write(|w| w.usbreset().set()); | 263 | regs.intenset.write(|w| w.usbreset().set()); |
| 264 | self.set_configured(false); | ||
| 256 | return Poll::Ready(Event::Reset); | 265 | return Poll::Ready(Event::Reset); |
| 257 | } | 266 | } |
| 258 | 267 | ||
| @@ -268,11 +277,12 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> { | |||
| 268 | } | 277 | } |
| 269 | if r.suspend().bit() { | 278 | if r.suspend().bit() { |
| 270 | regs.eventcause.write(|w| w.suspend().set_bit()); | 279 | regs.eventcause.write(|w| w.suspend().set_bit()); |
| 271 | trace!("USB event: suspend"); | 280 | regs.lowpower.write(|w| w.lowpower().low_power()); |
| 281 | return Poll::Ready(Event::Suspend); | ||
| 272 | } | 282 | } |
| 273 | if r.resume().bit() { | 283 | if r.resume().bit() { |
| 274 | regs.eventcause.write(|w| w.resume().set_bit()); | 284 | regs.eventcause.write(|w| w.resume().set_bit()); |
| 275 | trace!("USB event: resume"); | 285 | return Poll::Ready(Event::Resume); |
| 276 | } | 286 | } |
| 277 | if r.ready().bit() { | 287 | if r.ready().bit() { |
| 278 | regs.eventcause.write(|w| w.ready().set_bit()); | 288 | regs.eventcause.write(|w| w.ready().set_bit()); |
| @@ -284,11 +294,6 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> { | |||
| 284 | } | 294 | } |
| 285 | 295 | ||
| 286 | #[inline] | 296 | #[inline] |
| 287 | fn reset(&mut self) { | ||
| 288 | self.set_configured(false); | ||
| 289 | } | ||
| 290 | |||
| 291 | #[inline] | ||
| 292 | fn set_configured(&mut self, configured: bool) { | 297 | fn set_configured(&mut self, configured: bool) { |
| 293 | let regs = T::regs(); | 298 | let regs = T::regs(); |
| 294 | 299 | ||
| @@ -343,18 +348,43 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> { | |||
| 343 | } | 348 | } |
| 344 | 349 | ||
| 345 | #[inline] | 350 | #[inline] |
| 346 | fn suspend(&mut self) { | 351 | fn remote_wakeup(&mut self) -> Self::RemoteWakeupFuture<'_> { |
| 347 | let regs = T::regs(); | 352 | async move { |
| 348 | regs.lowpower.write(|w| w.lowpower().low_power()); | 353 | let regs = T::regs(); |
| 349 | } | ||
| 350 | 354 | ||
| 351 | #[inline] | 355 | if regs.lowpower.read().lowpower().is_low_power() { |
| 352 | fn resume(&mut self) { | 356 | errata::pre_wakeup(); |
| 353 | let regs = T::regs(); | 357 | |
| 358 | regs.lowpower.write(|w| w.lowpower().force_normal()); | ||
| 354 | 359 | ||
| 355 | errata::pre_wakeup(); | 360 | poll_fn(|cx| { |
| 361 | BUS_WAKER.register(cx.waker()); | ||
| 362 | let regs = T::regs(); | ||
| 363 | let r = regs.eventcause.read(); | ||
| 356 | 364 | ||
| 357 | regs.lowpower.write(|w| w.lowpower().force_normal()); | 365 | if regs.events_usbreset.read().bits() != 0 { |
| 366 | Poll::Ready(()) | ||
| 367 | } else if r.resume().bit() { | ||
| 368 | Poll::Ready(()) | ||
| 369 | } else if r.usbwuallowed().bit() { | ||
| 370 | regs.eventcause.write(|w| w.usbwuallowed().set_bit()); | ||
| 371 | |||
| 372 | regs.dpdmvalue.write(|w| w.state().resume()); | ||
| 373 | regs.tasks_dpdmdrive | ||
| 374 | .write(|w| w.tasks_dpdmdrive().set_bit()); | ||
| 375 | |||
| 376 | Poll::Ready(()) | ||
| 377 | } else { | ||
| 378 | Poll::Pending | ||
| 379 | } | ||
| 380 | }) | ||
| 381 | .await; | ||
| 382 | |||
| 383 | errata::post_wakeup(); | ||
| 384 | } | ||
| 385 | |||
| 386 | Ok(()) | ||
| 387 | } | ||
| 358 | } | 388 | } |
| 359 | } | 389 | } |
| 360 | 390 | ||
| @@ -845,6 +875,7 @@ mod errata { | |||
| 845 | 875 | ||
| 846 | pub fn pre_enable() { | 876 | pub fn pre_enable() { |
| 847 | // Works around Erratum 187 on chip revisions 1 and 2. | 877 | // Works around Erratum 187 on chip revisions 1 and 2. |
| 878 | #[cfg(any(feature = "nrf52840", feature = "nrf52833", feature = "nrf52820"))] | ||
| 848 | unsafe { | 879 | unsafe { |
| 849 | poke(0x4006EC00, 0x00009375); | 880 | poke(0x4006EC00, 0x00009375); |
| 850 | poke(0x4006ED14, 0x00000003); | 881 | poke(0x4006ED14, 0x00000003); |
| @@ -858,6 +889,7 @@ mod errata { | |||
| 858 | post_wakeup(); | 889 | post_wakeup(); |
| 859 | 890 | ||
| 860 | // Works around Erratum 187 on chip revisions 1 and 2. | 891 | // Works around Erratum 187 on chip revisions 1 and 2. |
| 892 | #[cfg(any(feature = "nrf52840", feature = "nrf52833", feature = "nrf52820"))] | ||
| 861 | unsafe { | 893 | unsafe { |
| 862 | poke(0x4006EC00, 0x00009375); | 894 | poke(0x4006EC00, 0x00009375); |
| 863 | poke(0x4006ED14, 0x00000000); | 895 | poke(0x4006ED14, 0x00000000); |
| @@ -868,6 +900,7 @@ mod errata { | |||
| 868 | pub fn pre_wakeup() { | 900 | pub fn pre_wakeup() { |
| 869 | // Works around Erratum 171 on chip revisions 1 and 2. | 901 | // Works around Erratum 171 on chip revisions 1 and 2. |
| 870 | 902 | ||
| 903 | #[cfg(feature = "nrf52840")] | ||
| 871 | unsafe { | 904 | unsafe { |
| 872 | if peek(0x4006EC00) == 0x00000000 { | 905 | if peek(0x4006EC00) == 0x00000000 { |
| 873 | poke(0x4006EC00, 0x00009375); | 906 | poke(0x4006EC00, 0x00009375); |
| @@ -881,6 +914,7 @@ mod errata { | |||
| 881 | pub fn post_wakeup() { | 914 | pub fn post_wakeup() { |
| 882 | // Works around Erratum 171 on chip revisions 1 and 2. | 915 | // Works around Erratum 171 on chip revisions 1 and 2. |
| 883 | 916 | ||
| 917 | #[cfg(feature = "nrf52840")] | ||
| 884 | unsafe { | 918 | unsafe { |
| 885 | if peek(0x4006EC00) == 0x00000000 { | 919 | if peek(0x4006EC00) == 0x00000000 { |
| 886 | poke(0x4006EC00, 0x00009375); | 920 | poke(0x4006EC00, 0x00009375); |
diff --git a/embassy-usb-hid/src/lib.rs b/embassy-usb-hid/src/lib.rs index e870becf5..4a1df0eab 100644 --- a/embassy-usb-hid/src/lib.rs +++ b/embassy-usb-hid/src/lib.rs | |||
| @@ -11,6 +11,7 @@ use core::mem::MaybeUninit; | |||
| 11 | use core::ops::Range; | 11 | use core::ops::Range; |
| 12 | use core::sync::atomic::{AtomicUsize, Ordering}; | 12 | use core::sync::atomic::{AtomicUsize, Ordering}; |
| 13 | 13 | ||
| 14 | use embassy::blocking_mutex::raw::RawMutex; | ||
| 14 | use embassy::time::Duration; | 15 | use embassy::time::Duration; |
| 15 | use embassy_usb::driver::EndpointOut; | 16 | use embassy_usb::driver::EndpointOut; |
| 16 | use embassy_usb::{ | 17 | use embassy_usb::{ |
| @@ -88,8 +89,8 @@ impl<'d, D: Driver<'d>, const IN_N: usize> HidClass<'d, D, (), IN_N> { | |||
| 88 | /// high performance uses, and a value of 255 is good for best-effort usecases. | 89 | /// high performance uses, and a value of 255 is good for best-effort usecases. |
| 89 | /// | 90 | /// |
| 90 | /// This allocates an IN endpoint only. | 91 | /// This allocates an IN endpoint only. |
| 91 | pub fn new<const OUT_N: usize>( | 92 | pub fn new<M: RawMutex, const OUT_N: usize>( |
| 92 | builder: &mut UsbDeviceBuilder<'d, D>, | 93 | builder: &mut UsbDeviceBuilder<'d, D, M>, |
| 93 | state: &'d mut State<'d, IN_N, OUT_N>, | 94 | state: &'d mut State<'d, IN_N, OUT_N>, |
| 94 | report_descriptor: &'static [u8], | 95 | report_descriptor: &'static [u8], |
| 95 | request_handler: Option<&'d dyn RequestHandler>, | 96 | request_handler: Option<&'d dyn RequestHandler>, |
| @@ -132,8 +133,8 @@ impl<'d, D: Driver<'d>, const IN_N: usize, const OUT_N: usize> | |||
| 132 | /// high performance uses, and a value of 255 is good for best-effort usecases. | 133 | /// high performance uses, and a value of 255 is good for best-effort usecases. |
| 133 | /// | 134 | /// |
| 134 | /// This allocates two endpoints (IN and OUT). | 135 | /// This allocates two endpoints (IN and OUT). |
| 135 | pub fn with_output_ep( | 136 | pub fn with_output_ep<M: RawMutex>( |
| 136 | builder: &mut UsbDeviceBuilder<'d, D>, | 137 | builder: &mut UsbDeviceBuilder<'d, D, M>, |
| 137 | state: &'d mut State<'d, IN_N, OUT_N>, | 138 | state: &'d mut State<'d, IN_N, OUT_N>, |
| 138 | report_descriptor: &'static [u8], | 139 | report_descriptor: &'static [u8], |
| 139 | request_handler: Option<&'d dyn RequestHandler>, | 140 | request_handler: Option<&'d dyn RequestHandler>, |
| @@ -392,9 +393,9 @@ impl<'a> Control<'a> { | |||
| 392 | } | 393 | } |
| 393 | } | 394 | } |
| 394 | 395 | ||
| 395 | fn build<'d, D: Driver<'d>>( | 396 | fn build<'d, D: Driver<'d>, M: RawMutex>( |
| 396 | &'d mut self, | 397 | &'d mut self, |
| 397 | builder: &mut UsbDeviceBuilder<'d, D>, | 398 | builder: &mut UsbDeviceBuilder<'d, D, M>, |
| 398 | ep_out: Option<&D::EndpointOut>, | 399 | ep_out: Option<&D::EndpointOut>, |
| 399 | ep_in: &D::EndpointIn, | 400 | ep_in: &D::EndpointIn, |
| 400 | ) { | 401 | ) { |
diff --git a/embassy-usb-serial/src/lib.rs b/embassy-usb-serial/src/lib.rs index 7b25398d0..7f006c0fd 100644 --- a/embassy-usb-serial/src/lib.rs +++ b/embassy-usb-serial/src/lib.rs | |||
| @@ -8,6 +8,7 @@ pub(crate) mod fmt; | |||
| 8 | use core::cell::Cell; | 8 | use core::cell::Cell; |
| 9 | use core::mem::{self, MaybeUninit}; | 9 | use core::mem::{self, MaybeUninit}; |
| 10 | use core::sync::atomic::{AtomicBool, Ordering}; | 10 | use core::sync::atomic::{AtomicBool, Ordering}; |
| 11 | use embassy::blocking_mutex::raw::RawMutex; | ||
| 11 | use embassy::blocking_mutex::CriticalSectionMutex; | 12 | use embassy::blocking_mutex::CriticalSectionMutex; |
| 12 | use embassy_usb::control::{self, ControlHandler, InResponse, OutResponse, Request}; | 13 | use embassy_usb::control::{self, ControlHandler, InResponse, OutResponse, Request}; |
| 13 | use embassy_usb::driver::{Endpoint, EndpointError, EndpointIn, EndpointOut}; | 14 | use embassy_usb::driver::{Endpoint, EndpointError, EndpointIn, EndpointOut}; |
| @@ -162,8 +163,8 @@ impl<'d> ControlHandler for Control<'d> { | |||
| 162 | impl<'d, D: Driver<'d>> CdcAcmClass<'d, D> { | 163 | impl<'d, D: Driver<'d>> CdcAcmClass<'d, D> { |
| 163 | /// Creates a new CdcAcmClass with the provided UsbBus and max_packet_size in bytes. For | 164 | /// Creates a new CdcAcmClass with the provided UsbBus and max_packet_size in bytes. For |
| 164 | /// full-speed devices, max_packet_size has to be one of 8, 16, 32 or 64. | 165 | /// full-speed devices, max_packet_size has to be one of 8, 16, 32 or 64. |
| 165 | pub fn new( | 166 | pub fn new<M: RawMutex>( |
| 166 | builder: &mut UsbDeviceBuilder<'d, D>, | 167 | builder: &mut UsbDeviceBuilder<'d, D, M>, |
| 167 | state: &'d mut State<'d>, | 168 | state: &'d mut State<'d>, |
| 168 | max_packet_size: u16, | 169 | max_packet_size: u16, |
| 169 | ) -> Self { | 170 | ) -> Self { |
diff --git a/embassy-usb/src/builder.rs b/embassy-usb/src/builder.rs index 4bbcd3e56..30d31ac74 100644 --- a/embassy-usb/src/builder.rs +++ b/embassy-usb/src/builder.rs | |||
| @@ -1,9 +1,14 @@ | |||
| 1 | use embassy::blocking_mutex::raw::{NoopRawMutex, RawMutex}; | ||
| 2 | use embassy::channel::Channel; | ||
| 1 | use heapless::Vec; | 3 | use heapless::Vec; |
| 2 | 4 | ||
| 5 | use crate::DeviceCommand; | ||
| 6 | |||
| 3 | use super::control::ControlHandler; | 7 | use super::control::ControlHandler; |
| 4 | use super::descriptor::{BosWriter, DescriptorWriter}; | 8 | use super::descriptor::{BosWriter, DescriptorWriter}; |
| 5 | use super::driver::{Driver, EndpointAllocError}; | 9 | use super::driver::{Driver, EndpointAllocError}; |
| 6 | use super::types::*; | 10 | use super::types::*; |
| 11 | use super::DeviceStateHandler; | ||
| 7 | use super::UsbDevice; | 12 | use super::UsbDevice; |
| 8 | use super::MAX_INTERFACE_COUNT; | 13 | use super::MAX_INTERFACE_COUNT; |
| 9 | 14 | ||
| @@ -93,6 +98,11 @@ pub struct Config<'a> { | |||
| 93 | /// Default: 100mA | 98 | /// Default: 100mA |
| 94 | /// Max: 500mA | 99 | /// Max: 500mA |
| 95 | pub max_power: u16, | 100 | pub max_power: u16, |
| 101 | |||
| 102 | /// Whether the USB bus should be enabled when built. | ||
| 103 | /// | ||
| 104 | /// Default: true | ||
| 105 | pub start_enabled: bool, | ||
| 96 | } | 106 | } |
| 97 | 107 | ||
| 98 | impl<'a> Config<'a> { | 108 | impl<'a> Config<'a> { |
| @@ -112,15 +122,18 @@ impl<'a> Config<'a> { | |||
| 112 | supports_remote_wakeup: false, | 122 | supports_remote_wakeup: false, |
| 113 | composite_with_iads: false, | 123 | composite_with_iads: false, |
| 114 | max_power: 100, | 124 | max_power: 100, |
| 125 | start_enabled: true, | ||
| 115 | } | 126 | } |
| 116 | } | 127 | } |
| 117 | } | 128 | } |
| 118 | 129 | ||
| 119 | /// Used to build new [`UsbDevice`]s. | 130 | /// Used to build new [`UsbDevice`]s. |
| 120 | pub struct UsbDeviceBuilder<'d, D: Driver<'d>> { | 131 | pub struct UsbDeviceBuilder<'d, D: Driver<'d>, M: RawMutex> { |
| 121 | config: Config<'d>, | 132 | config: Config<'d>, |
| 133 | handler: Option<&'d dyn DeviceStateHandler>, | ||
| 122 | interfaces: Vec<(u8, &'d mut dyn ControlHandler), MAX_INTERFACE_COUNT>, | 134 | interfaces: Vec<(u8, &'d mut dyn ControlHandler), MAX_INTERFACE_COUNT>, |
| 123 | control_buf: &'d mut [u8], | 135 | control_buf: &'d mut [u8], |
| 136 | commands: Option<&'d Channel<M, DeviceCommand, 1>>, | ||
| 124 | 137 | ||
| 125 | driver: D, | 138 | driver: D, |
| 126 | next_interface_number: u8, | 139 | next_interface_number: u8, |
| @@ -132,7 +145,7 @@ pub struct UsbDeviceBuilder<'d, D: Driver<'d>> { | |||
| 132 | pub bos_descriptor: BosWriter<'d>, | 145 | pub bos_descriptor: BosWriter<'d>, |
| 133 | } | 146 | } |
| 134 | 147 | ||
| 135 | impl<'d, D: Driver<'d>> UsbDeviceBuilder<'d, D> { | 148 | impl<'d, D: Driver<'d>> UsbDeviceBuilder<'d, D, NoopRawMutex> { |
| 136 | /// Creates a builder for constructing a new [`UsbDevice`]. | 149 | /// Creates a builder for constructing a new [`UsbDevice`]. |
| 137 | /// | 150 | /// |
| 138 | /// `control_buf` is a buffer used for USB control request data. It should be sized | 151 | /// `control_buf` is a buffer used for USB control request data. It should be sized |
| @@ -145,6 +158,58 @@ impl<'d, D: Driver<'d>> UsbDeviceBuilder<'d, D> { | |||
| 145 | config_descriptor_buf: &'d mut [u8], | 158 | config_descriptor_buf: &'d mut [u8], |
| 146 | bos_descriptor_buf: &'d mut [u8], | 159 | bos_descriptor_buf: &'d mut [u8], |
| 147 | control_buf: &'d mut [u8], | 160 | control_buf: &'d mut [u8], |
| 161 | handler: Option<&'d dyn DeviceStateHandler>, | ||
| 162 | ) -> Self { | ||
| 163 | Self::new_inner( | ||
| 164 | driver, | ||
| 165 | config, | ||
| 166 | device_descriptor_buf, | ||
| 167 | config_descriptor_buf, | ||
| 168 | bos_descriptor_buf, | ||
| 169 | control_buf, | ||
| 170 | handler, | ||
| 171 | None, | ||
| 172 | ) | ||
| 173 | } | ||
| 174 | } | ||
| 175 | |||
| 176 | impl<'d, D: Driver<'d>, M: RawMutex> UsbDeviceBuilder<'d, D, M> { | ||
| 177 | /// Creates a builder for constructing a new [`UsbDevice`]. | ||
| 178 | /// | ||
| 179 | /// `control_buf` is a buffer used for USB control request data. It should be sized | ||
| 180 | /// large enough for the length of the largest control request (in or out) | ||
| 181 | /// anticipated by any class added to the device. | ||
| 182 | pub fn new_with_channel( | ||
| 183 | driver: D, | ||
| 184 | config: Config<'d>, | ||
| 185 | device_descriptor_buf: &'d mut [u8], | ||
| 186 | config_descriptor_buf: &'d mut [u8], | ||
| 187 | bos_descriptor_buf: &'d mut [u8], | ||
| 188 | control_buf: &'d mut [u8], | ||
| 189 | handler: Option<&'d dyn DeviceStateHandler>, | ||
| 190 | channel: &'d Channel<M, DeviceCommand, 1>, | ||
| 191 | ) -> Self { | ||
| 192 | Self::new_inner( | ||
| 193 | driver, | ||
| 194 | config, | ||
| 195 | device_descriptor_buf, | ||
| 196 | config_descriptor_buf, | ||
| 197 | bos_descriptor_buf, | ||
| 198 | control_buf, | ||
| 199 | handler, | ||
| 200 | Some(channel), | ||
| 201 | ) | ||
| 202 | } | ||
| 203 | |||
| 204 | fn new_inner( | ||
| 205 | driver: D, | ||
| 206 | config: Config<'d>, | ||
| 207 | device_descriptor_buf: &'d mut [u8], | ||
| 208 | config_descriptor_buf: &'d mut [u8], | ||
| 209 | bos_descriptor_buf: &'d mut [u8], | ||
| 210 | control_buf: &'d mut [u8], | ||
| 211 | handler: Option<&'d dyn DeviceStateHandler>, | ||
| 212 | channel: Option<&'d Channel<M, DeviceCommand, 1>>, | ||
| 148 | ) -> Self { | 213 | ) -> Self { |
| 149 | // Magic values specified in USB-IF ECN on IADs. | 214 | // Magic values specified in USB-IF ECN on IADs. |
| 150 | if config.composite_with_iads | 215 | if config.composite_with_iads |
| @@ -174,9 +239,12 @@ impl<'d, D: Driver<'d>> UsbDeviceBuilder<'d, D> { | |||
| 174 | 239 | ||
| 175 | UsbDeviceBuilder { | 240 | UsbDeviceBuilder { |
| 176 | driver, | 241 | driver, |
| 242 | handler, | ||
| 177 | config, | 243 | config, |
| 178 | interfaces: Vec::new(), | 244 | interfaces: Vec::new(), |
| 179 | control_buf, | 245 | control_buf, |
| 246 | commands: channel, | ||
| 247 | |||
| 180 | next_interface_number: 0, | 248 | next_interface_number: 0, |
| 181 | next_string_index: 4, | 249 | next_string_index: 4, |
| 182 | 250 | ||
| @@ -187,20 +255,21 @@ impl<'d, D: Driver<'d>> UsbDeviceBuilder<'d, D> { | |||
| 187 | } | 255 | } |
| 188 | 256 | ||
| 189 | /// Creates the [`UsbDevice`] instance with the configuration in this builder. | 257 | /// Creates the [`UsbDevice`] instance with the configuration in this builder. |
| 190 | pub async fn build(mut self) -> UsbDevice<'d, D> { | 258 | pub fn build(mut self) -> UsbDevice<'d, D, M> { |
| 191 | self.config_descriptor.end_configuration(); | 259 | self.config_descriptor.end_configuration(); |
| 192 | self.bos_descriptor.end_bos(); | 260 | self.bos_descriptor.end_bos(); |
| 193 | 261 | ||
| 194 | UsbDevice::build( | 262 | UsbDevice::build( |
| 195 | self.driver, | 263 | self.driver, |
| 196 | self.config, | 264 | self.config, |
| 265 | self.handler, | ||
| 266 | self.commands, | ||
| 197 | self.device_descriptor.into_buf(), | 267 | self.device_descriptor.into_buf(), |
| 198 | self.config_descriptor.into_buf(), | 268 | self.config_descriptor.into_buf(), |
| 199 | self.bos_descriptor.writer.into_buf(), | 269 | self.bos_descriptor.writer.into_buf(), |
| 200 | self.interfaces, | 270 | self.interfaces, |
| 201 | self.control_buf, | 271 | self.control_buf, |
| 202 | ) | 272 | ) |
| 203 | .await | ||
| 204 | } | 273 | } |
| 205 | 274 | ||
| 206 | /// Allocates a new interface number. | 275 | /// Allocates a new interface number. |
diff --git a/embassy-usb/src/driver.rs b/embassy-usb/src/driver.rs index 875ceafcb..99610deef 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,24 @@ 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; | ||
| 60 | type PollFuture<'a>: Future<Output = Event> + 'a | 62 | type PollFuture<'a>: Future<Output = Event> + 'a |
| 61 | where | 63 | where |
| 62 | Self: 'a; | 64 | Self: 'a; |
| 65 | type RemoteWakeupFuture<'a>: Future<Output = Result<(), Unsupported>> + 'a | ||
| 66 | where | ||
| 67 | Self: 'a; | ||
| 63 | 68 | ||
| 64 | fn poll<'a>(&'a mut self) -> Self::PollFuture<'a>; | 69 | /// Enables the USB peripheral. Soon after enabling the device will be reset, so |
| 70 | /// there is no need to perform a USB reset in this method. | ||
| 71 | fn enable(&mut self) -> Self::EnableFuture<'_>; | ||
| 72 | |||
| 73 | /// Disables and powers down the USB peripheral. | ||
| 74 | fn disable(&mut self); | ||
| 65 | 75 | ||
| 66 | /// Called when the host resets the device. This will be soon called after | 76 | fn poll<'a>(&'a mut self) -> Self::PollFuture<'a>; |
| 67 | /// [`poll`](crate::device::UsbDevice::poll) returns [`PollResult::Reset`]. This method should | ||
| 68 | /// reset the state of all endpoints and peripheral flags back to a state suitable for | ||
| 69 | /// enumeration, as well as ensure that all endpoints previously allocated with alloc_ep are | ||
| 70 | /// initialized as specified. | ||
| 71 | fn reset(&mut self); | ||
| 72 | 77 | ||
| 73 | /// Sets the device USB address to `addr`. | 78 | /// Sets the device USB address to `addr`. |
| 74 | fn set_device_address(&mut self, addr: u8); | 79 | fn set_device_address(&mut self, addr: u8); |
| @@ -83,17 +88,6 @@ pub trait Bus { | |||
| 83 | /// Gets whether the STALL condition is set for an endpoint. Only used during control transfers. | 88 | /// 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; | 89 | fn is_stalled(&mut self, ep_addr: EndpointAddress) -> bool; |
| 85 | 90 | ||
| 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 | 91 | /// Simulates a disconnect from the USB bus, causing the host to reset and re-enumerate the |
| 98 | /// device. | 92 | /// device. |
| 99 | /// | 93 | /// |
| @@ -106,6 +100,16 @@ pub trait Bus { | |||
| 106 | fn force_reset(&mut self) -> Result<(), Unsupported> { | 100 | fn force_reset(&mut self) -> Result<(), Unsupported> { |
| 107 | Err(Unsupported) | 101 | Err(Unsupported) |
| 108 | } | 102 | } |
| 103 | |||
| 104 | /// Initiates a remote wakeup of the host by the device. | ||
| 105 | /// | ||
| 106 | /// The default implementation just returns `Unsupported`. | ||
| 107 | /// | ||
| 108 | /// # Errors | ||
| 109 | /// | ||
| 110 | /// * [`Unsupported`](crate::UsbError::Unsupported) - This UsbBus implementation doesn't support | ||
| 111 | /// remote wakeup or it has not been enabled at creation time. | ||
| 112 | fn remote_wakeup(&mut self) -> Self::RemoteWakeupFuture<'_>; | ||
| 109 | } | 113 | } |
| 110 | 114 | ||
| 111 | pub trait Endpoint { | 115 | pub trait Endpoint { |
diff --git a/embassy-usb/src/lib.rs b/embassy-usb/src/lib.rs index e98cbdee3..2c53d9214 100644 --- a/embassy-usb/src/lib.rs +++ b/embassy-usb/src/lib.rs | |||
| @@ -12,6 +12,9 @@ pub mod driver; | |||
| 12 | pub mod types; | 12 | pub mod types; |
| 13 | mod util; | 13 | mod util; |
| 14 | 14 | ||
| 15 | use driver::Unsupported; | ||
| 16 | use embassy::blocking_mutex::raw::{NoopRawMutex, RawMutex}; | ||
| 17 | use embassy::channel::Channel; | ||
| 15 | use heapless::Vec; | 18 | use heapless::Vec; |
| 16 | 19 | ||
| 17 | use self::control::*; | 20 | use self::control::*; |
| @@ -28,8 +31,12 @@ pub use self::builder::UsbDeviceBuilder; | |||
| 28 | /// In general class traffic is only possible in the `Configured` state. | 31 | /// In general class traffic is only possible in the `Configured` state. |
| 29 | #[repr(u8)] | 32 | #[repr(u8)] |
| 30 | #[derive(PartialEq, Eq, Copy, Clone, Debug)] | 33 | #[derive(PartialEq, Eq, Copy, Clone, Debug)] |
| 34 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 31 | pub enum UsbDeviceState { | 35 | pub enum UsbDeviceState { |
| 32 | /// The USB device has just been created or reset. | 36 | /// The USB device is disabled. |
| 37 | Disabled, | ||
| 38 | |||
| 39 | /// The USB device has just been enabled or reset. | ||
| 33 | Default, | 40 | Default, |
| 34 | 41 | ||
| 35 | /// The USB device has received an address from the host. | 42 | /// The USB device has received an address from the host. |
| @@ -37,9 +44,6 @@ pub enum UsbDeviceState { | |||
| 37 | 44 | ||
| 38 | /// The USB device has been configured and is fully functional. | 45 | /// The USB device has been configured and is fully functional. |
| 39 | Configured, | 46 | Configured, |
| 40 | |||
| 41 | /// The USB device has been suspended by the host or it has been unplugged from the USB bus. | ||
| 42 | Suspend, | ||
| 43 | } | 47 | } |
| 44 | 48 | ||
| 45 | /// The bConfiguration value for the not configured state. | 49 | /// The bConfiguration value for the not configured state. |
| @@ -53,8 +57,39 @@ pub const DEFAULT_ALTERNATE_SETTING: u8 = 0; | |||
| 53 | 57 | ||
| 54 | pub const MAX_INTERFACE_COUNT: usize = 4; | 58 | pub const MAX_INTERFACE_COUNT: usize = 4; |
| 55 | 59 | ||
| 56 | pub struct UsbDevice<'d, D: Driver<'d>> { | 60 | #[derive(PartialEq, Eq, Copy, Clone, Debug)] |
| 61 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 62 | pub enum DeviceCommand { | ||
| 63 | Enable, | ||
| 64 | Disable, | ||
| 65 | RemoteWakeup, | ||
| 66 | } | ||
| 67 | |||
| 68 | /// A handler trait for changes in the device state of the [UsbDevice]. | ||
| 69 | pub trait DeviceStateHandler { | ||
| 70 | /// Called when the host resets the device. | ||
| 71 | fn reset(&self) {} | ||
| 72 | |||
| 73 | /// Called when the host has set the address of the device to `addr`. | ||
| 74 | fn addressed(&self, _addr: u8) {} | ||
| 75 | |||
| 76 | /// Called when the host has enabled or disabled the configuration of the device. | ||
| 77 | fn configured(&self, _configured: bool) {} | ||
| 78 | |||
| 79 | /// Called when the bus has entered or exited the suspend state. | ||
| 80 | fn suspended(&self, _suspended: bool) {} | ||
| 81 | |||
| 82 | /// Called when remote wakeup feature is enabled or disabled. | ||
| 83 | fn remote_wakeup_enabled(&self, _enabled: bool) {} | ||
| 84 | |||
| 85 | /// Called when the USB device has been disabled. | ||
| 86 | fn disabled(&self) {} | ||
| 87 | } | ||
| 88 | |||
| 89 | pub struct UsbDevice<'d, D: Driver<'d>, M: RawMutex = NoopRawMutex> { | ||
| 57 | bus: D::Bus, | 90 | bus: D::Bus, |
| 91 | handler: Option<&'d dyn DeviceStateHandler>, | ||
| 92 | commands: Option<&'d Channel<M, DeviceCommand, 1>>, | ||
| 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, |
| @@ -71,33 +107,38 @@ pub struct UsbDevice<'d, D: Driver<'d>> { | |||
| 71 | interfaces: Vec<(u8, &'d mut dyn ControlHandler), MAX_INTERFACE_COUNT>, | 107 | interfaces: Vec<(u8, &'d mut dyn ControlHandler), MAX_INTERFACE_COUNT>, |
| 72 | } | 108 | } |
| 73 | 109 | ||
| 74 | impl<'d, D: Driver<'d>> UsbDevice<'d, D> { | 110 | impl<'d, D: Driver<'d>, M: RawMutex> UsbDevice<'d, D, M> { |
| 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>, | ||
| 115 | commands: Option<&'d Channel<M, DeviceCommand, 1>>, | ||
| 78 | device_descriptor: &'d [u8], | 116 | device_descriptor: &'d [u8], |
| 79 | config_descriptor: &'d [u8], | 117 | config_descriptor: &'d [u8], |
| 80 | bos_descriptor: &'d [u8], | 118 | bos_descriptor: &'d [u8], |
| 81 | interfaces: Vec<(u8, &'d mut dyn ControlHandler), MAX_INTERFACE_COUNT>, | 119 | interfaces: Vec<(u8, &'d mut dyn ControlHandler), MAX_INTERFACE_COUNT>, |
| 82 | control_buf: &'d mut [u8], | 120 | control_buf: &'d mut [u8], |
| 83 | ) -> UsbDevice<'d, D> { | 121 | ) -> UsbDevice<'d, D, M> { |
| 84 | let control = driver | 122 | let control = driver |
| 85 | .alloc_control_pipe(config.max_packet_size_0 as u16) | 123 | .alloc_control_pipe(config.max_packet_size_0 as u16) |
| 86 | .expect("failed to alloc control endpoint"); | 124 | .expect("failed to alloc control endpoint"); |
| 87 | 125 | ||
| 88 | // Enable the USB bus. | 126 | // Enable the USB bus. |
| 89 | // This prevent further allocation by consuming the driver. | 127 | // This prevent further allocation by consuming the driver. |
| 90 | let bus = driver.enable().await; | 128 | let bus = driver.into_bus(); |
| 91 | 129 | ||
| 92 | Self { | 130 | Self { |
| 93 | bus, | 131 | bus, |
| 94 | config, | 132 | config, |
| 133 | handler, | ||
| 134 | commands, | ||
| 95 | control: ControlPipe::new(control), | 135 | control: ControlPipe::new(control), |
| 96 | device_descriptor, | 136 | device_descriptor, |
| 97 | config_descriptor, | 137 | config_descriptor, |
| 98 | bos_descriptor, | 138 | bos_descriptor, |
| 99 | control_buf, | 139 | control_buf, |
| 100 | device_state: UsbDeviceState::Default, | 140 | device_state: UsbDeviceState::Default, |
| 141 | suspended: false, | ||
| 101 | remote_wakeup_enabled: false, | 142 | remote_wakeup_enabled: false, |
| 102 | self_powered: false, | 143 | self_powered: false, |
| 103 | pending_address: 0, | 144 | pending_address: 0, |
| @@ -105,41 +146,94 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> { | |||
| 105 | } | 146 | } |
| 106 | } | 147 | } |
| 107 | 148 | ||
| 108 | pub async fn run(&mut self) { | 149 | pub async fn run(&mut self) -> ! { |
| 150 | if self.config.start_enabled { | ||
| 151 | self.bus.enable().await; | ||
| 152 | } else { | ||
| 153 | self.wait_for_enable().await | ||
| 154 | } | ||
| 155 | |||
| 109 | loop { | 156 | loop { |
| 110 | let control_fut = self.control.setup(); | 157 | let control_fut = self.control.setup(); |
| 111 | let bus_fut = self.bus.poll(); | 158 | let bus_fut = self.bus.poll(); |
| 112 | match select(bus_fut, control_fut).await { | 159 | let commands_fut = recv_or_wait(self.commands); |
| 113 | Either::Left(evt) => match evt { | 160 | |
| 161 | match select3(bus_fut, control_fut, commands_fut).await { | ||
| 162 | Either3::First(evt) => match evt { | ||
| 114 | Event::Reset => { | 163 | Event::Reset => { |
| 115 | trace!("usb: reset"); | 164 | trace!("usb: reset"); |
| 116 | self.bus.reset(); | ||
| 117 | |||
| 118 | self.device_state = UsbDeviceState::Default; | 165 | self.device_state = UsbDeviceState::Default; |
| 166 | self.suspended = false; | ||
| 119 | self.remote_wakeup_enabled = false; | 167 | self.remote_wakeup_enabled = false; |
| 120 | self.pending_address = 0; | 168 | self.pending_address = 0; |
| 121 | 169 | ||
| 122 | for (_, h) in self.interfaces.iter_mut() { | 170 | for (_, h) in self.interfaces.iter_mut() { |
| 123 | h.reset(); | 171 | h.reset(); |
| 124 | } | 172 | } |
| 173 | |||
| 174 | if let Some(h) = &mut self.handler { | ||
| 175 | h.reset(); | ||
| 176 | } | ||
| 125 | } | 177 | } |
| 126 | Event::Resume => { | 178 | Event::Resume => { |
| 127 | trace!("usb: resume"); | 179 | trace!("usb: resume"); |
| 180 | self.suspended = false; | ||
| 181 | if let Some(h) = &mut self.handler { | ||
| 182 | h.suspended(false); | ||
| 183 | } | ||
| 128 | } | 184 | } |
| 129 | Event::Suspend => { | 185 | Event::Suspend => { |
| 130 | trace!("usb: suspend"); | 186 | trace!("usb: suspend"); |
| 131 | self.bus.suspend(); | 187 | self.suspended = true; |
| 132 | self.device_state = UsbDeviceState::Suspend; | 188 | if let Some(h) = &mut self.handler { |
| 189 | h.suspended(true); | ||
| 190 | } | ||
| 133 | } | 191 | } |
| 134 | }, | 192 | }, |
| 135 | Either::Right(req) => match req { | 193 | Either3::Second(req) => match req { |
| 136 | Setup::DataIn(req, stage) => self.handle_control_in(req, stage).await, | 194 | Setup::DataIn(req, stage) => self.handle_control_in(req, stage).await, |
| 137 | Setup::DataOut(req, stage) => self.handle_control_out(req, stage).await, | 195 | Setup::DataOut(req, stage) => self.handle_control_out(req, stage).await, |
| 138 | }, | 196 | }, |
| 197 | Either3::Third(cmd) => match cmd { | ||
| 198 | DeviceCommand::Enable => warn!("usb: Enable command received while enabled."), | ||
| 199 | DeviceCommand::Disable => { | ||
| 200 | trace!("usb: disable"); | ||
| 201 | self.bus.disable(); | ||
| 202 | self.device_state = UsbDeviceState::Disabled; | ||
| 203 | if let Some(h) = &mut self.handler { | ||
| 204 | h.disabled(); | ||
| 205 | } | ||
| 206 | self.wait_for_enable().await; | ||
| 207 | } | ||
| 208 | DeviceCommand::RemoteWakeup => { | ||
| 209 | if self.remote_wakeup_enabled { | ||
| 210 | match self.bus.remote_wakeup().await { | ||
| 211 | Ok(()) => (), | ||
| 212 | Err(Unsupported) => warn!("Remote wakeup is unsupported!"), | ||
| 213 | } | ||
| 214 | } else { | ||
| 215 | warn!("Remote wakeup not enabled."); | ||
| 216 | } | ||
| 217 | } | ||
| 218 | }, | ||
| 139 | } | 219 | } |
| 140 | } | 220 | } |
| 141 | } | 221 | } |
| 142 | 222 | ||
| 223 | async fn wait_for_enable(&mut self) { | ||
| 224 | loop { | ||
| 225 | // When disabled just wait until we're told to re-enable | ||
| 226 | match recv_or_wait(self.commands).await { | ||
| 227 | DeviceCommand::Enable => break, | ||
| 228 | cmd => warn!("usb: {:?} received while disabled", cmd), | ||
| 229 | } | ||
| 230 | } | ||
| 231 | |||
| 232 | trace!("usb: enable"); | ||
| 233 | self.bus.enable().await; | ||
| 234 | self.device_state = UsbDeviceState::Default; | ||
| 235 | } | ||
| 236 | |||
| 143 | async fn handle_control_out(&mut self, req: Request, stage: DataOutStage) { | 237 | async fn handle_control_out(&mut self, req: Request, stage: DataOutStage) { |
| 144 | const CONFIGURATION_NONE_U16: u16 = CONFIGURATION_NONE as u16; | 238 | const CONFIGURATION_NONE_U16: u16 = CONFIGURATION_NONE as u16; |
| 145 | const CONFIGURATION_VALUE_U16: u16 = CONFIGURATION_VALUE as u16; | 239 | const CONFIGURATION_VALUE_U16: u16 = CONFIGURATION_VALUE as u16; |
| @@ -156,20 +250,33 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> { | |||
| 156 | (RequestType::Standard, Recipient::Device) => match (req.request, req.value) { | 250 | (RequestType::Standard, Recipient::Device) => match (req.request, req.value) { |
| 157 | (Request::CLEAR_FEATURE, Request::FEATURE_DEVICE_REMOTE_WAKEUP) => { | 251 | (Request::CLEAR_FEATURE, Request::FEATURE_DEVICE_REMOTE_WAKEUP) => { |
| 158 | self.remote_wakeup_enabled = false; | 252 | self.remote_wakeup_enabled = false; |
| 253 | if let Some(h) = &mut self.handler { | ||
| 254 | h.remote_wakeup_enabled(false); | ||
| 255 | } | ||
| 159 | self.control.accept(stage) | 256 | self.control.accept(stage) |
| 160 | } | 257 | } |
| 161 | (Request::SET_FEATURE, Request::FEATURE_DEVICE_REMOTE_WAKEUP) => { | 258 | (Request::SET_FEATURE, Request::FEATURE_DEVICE_REMOTE_WAKEUP) => { |
| 162 | self.remote_wakeup_enabled = true; | 259 | self.remote_wakeup_enabled = true; |
| 260 | if let Some(h) = &mut self.handler { | ||
| 261 | h.remote_wakeup_enabled(true); | ||
| 262 | } | ||
| 163 | self.control.accept(stage) | 263 | self.control.accept(stage) |
| 164 | } | 264 | } |
| 165 | (Request::SET_ADDRESS, addr @ 1..=127) => { | 265 | (Request::SET_ADDRESS, addr @ 1..=127) => { |
| 166 | self.pending_address = addr as u8; | 266 | self.pending_address = addr as u8; |
| 167 | self.bus.set_device_address(self.pending_address); | 267 | self.bus.set_device_address(self.pending_address); |
| 268 | self.device_state = UsbDeviceState::Addressed; | ||
| 269 | if let Some(h) = &mut self.handler { | ||
| 270 | h.addressed(self.pending_address); | ||
| 271 | } | ||
| 168 | self.control.accept(stage) | 272 | self.control.accept(stage) |
| 169 | } | 273 | } |
| 170 | (Request::SET_CONFIGURATION, CONFIGURATION_VALUE_U16) => { | 274 | (Request::SET_CONFIGURATION, CONFIGURATION_VALUE_U16) => { |
| 171 | self.device_state = UsbDeviceState::Configured; | 275 | self.device_state = UsbDeviceState::Configured; |
| 172 | self.bus.set_configured(true); | 276 | self.bus.set_configured(true); |
| 277 | if let Some(h) = &mut self.handler { | ||
| 278 | h.configured(true); | ||
| 279 | } | ||
| 173 | self.control.accept(stage) | 280 | self.control.accept(stage) |
| 174 | } | 281 | } |
| 175 | (Request::SET_CONFIGURATION, CONFIGURATION_NONE_U16) => match self.device_state { | 282 | (Request::SET_CONFIGURATION, CONFIGURATION_NONE_U16) => match self.device_state { |
| @@ -177,6 +284,9 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> { | |||
| 177 | _ => { | 284 | _ => { |
| 178 | self.device_state = UsbDeviceState::Addressed; | 285 | self.device_state = UsbDeviceState::Addressed; |
| 179 | self.bus.set_configured(false); | 286 | self.bus.set_configured(false); |
| 287 | if let Some(h) = &mut self.handler { | ||
| 288 | h.configured(false); | ||
| 289 | } | ||
| 180 | self.control.accept(stage) | 290 | self.control.accept(stage) |
| 181 | } | 291 | } |
| 182 | }, | 292 | }, |
diff --git a/embassy-usb/src/util.rs b/embassy-usb/src/util.rs index 18cc875c6..4fc55461f 100644 --- a/embassy-usb/src/util.rs +++ b/embassy-usb/src/util.rs | |||
| @@ -1,45 +1,85 @@ | |||
| 1 | use core::future::Future; | 1 | use core::future::Future; |
| 2 | use core::marker::PhantomData; | ||
| 2 | use core::pin::Pin; | 3 | use core::pin::Pin; |
| 3 | use core::task::{Context, Poll}; | 4 | use core::task::{Context, Poll}; |
| 4 | 5 | ||
| 6 | use embassy::blocking_mutex::raw::RawMutex; | ||
| 7 | use embassy::channel::Channel; | ||
| 8 | |||
| 5 | #[derive(Debug, Clone)] | 9 | #[derive(Debug, Clone)] |
| 6 | pub enum Either<A, B> { | 10 | pub enum Either3<A, B, C> { |
| 7 | Left(A), | 11 | First(A), |
| 8 | Right(B), | 12 | Second(B), |
| 13 | Third(C), | ||
| 9 | } | 14 | } |
| 10 | 15 | ||
| 11 | pub fn select<A, B>(a: A, b: B) -> Select<A, B> | 16 | /// Same as [`select`], but with more futures. |
| 17 | pub fn select3<A, B, C>(a: A, b: B, c: C) -> Select3<A, B, C> | ||
| 12 | where | 18 | where |
| 13 | A: Future, | 19 | A: Future, |
| 14 | B: Future, | 20 | B: Future, |
| 21 | C: Future, | ||
| 15 | { | 22 | { |
| 16 | Select { a, b } | 23 | Select3 { a, b, c } |
| 17 | } | 24 | } |
| 18 | 25 | ||
| 19 | pub struct Select<A, B> { | 26 | /// Future for the [`select3`] function. |
| 27 | #[derive(Debug)] | ||
| 28 | #[must_use = "futures do nothing unless you `.await` or poll them"] | ||
| 29 | pub struct Select3<A, B, C> { | ||
| 20 | a: A, | 30 | a: A, |
| 21 | b: B, | 31 | b: B, |
| 32 | c: C, | ||
| 22 | } | 33 | } |
| 23 | 34 | ||
| 24 | impl<A: Unpin, B: Unpin> Unpin for Select<A, B> {} | 35 | impl<A, B, C> Future for Select3<A, B, C> |
| 25 | |||
| 26 | impl<A, B> Future for Select<A, B> | ||
| 27 | where | 36 | where |
| 28 | A: Future, | 37 | A: Future, |
| 29 | B: Future, | 38 | B: Future, |
| 39 | C: Future, | ||
| 30 | { | 40 | { |
| 31 | type Output = Either<A::Output, B::Output>; | 41 | type Output = Either3<A::Output, B::Output, C::Output>; |
| 32 | 42 | ||
| 33 | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { | 43 | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { |
| 34 | let this = unsafe { self.get_unchecked_mut() }; | 44 | let this = unsafe { self.get_unchecked_mut() }; |
| 35 | let a = unsafe { Pin::new_unchecked(&mut this.a) }; | 45 | let a = unsafe { Pin::new_unchecked(&mut this.a) }; |
| 36 | let b = unsafe { Pin::new_unchecked(&mut this.b) }; | 46 | let b = unsafe { Pin::new_unchecked(&mut this.b) }; |
| 37 | match a.poll(cx) { | 47 | let c = unsafe { Pin::new_unchecked(&mut this.c) }; |
| 38 | Poll::Ready(x) => Poll::Ready(Either::Left(x)), | 48 | if let Poll::Ready(x) = a.poll(cx) { |
| 39 | Poll::Pending => match b.poll(cx) { | 49 | return Poll::Ready(Either3::First(x)); |
| 40 | Poll::Ready(x) => Poll::Ready(Either::Right(x)), | 50 | } |
| 41 | Poll::Pending => Poll::Pending, | 51 | if let Poll::Ready(x) = b.poll(cx) { |
| 42 | }, | 52 | return Poll::Ready(Either3::Second(x)); |
| 53 | } | ||
| 54 | if let Poll::Ready(x) = c.poll(cx) { | ||
| 55 | return Poll::Ready(Either3::Third(x)); | ||
| 56 | } | ||
| 57 | Poll::Pending | ||
| 58 | } | ||
| 59 | } | ||
| 60 | |||
| 61 | pub struct Pending<T> { | ||
| 62 | _phantom: PhantomData<T>, | ||
| 63 | } | ||
| 64 | |||
| 65 | impl<T> Pending<T> { | ||
| 66 | fn new() -> Self { | ||
| 67 | Pending { | ||
| 68 | _phantom: PhantomData, | ||
| 43 | } | 69 | } |
| 44 | } | 70 | } |
| 45 | } | 71 | } |
| 72 | |||
| 73 | impl<T> Future for Pending<T> { | ||
| 74 | type Output = T; | ||
| 75 | fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> { | ||
| 76 | Poll::Pending | ||
| 77 | } | ||
| 78 | } | ||
| 79 | |||
| 80 | pub async fn recv_or_wait<M: RawMutex, T, const N: usize>(ch: Option<&Channel<M, T, N>>) -> T { | ||
| 81 | match ch { | ||
| 82 | Some(ch) => ch.recv().await, | ||
| 83 | None => Pending::new().await, | ||
| 84 | } | ||
| 85 | } | ||
diff --git a/examples/nrf/src/bin/usb_hid_keyboard.rs b/examples/nrf/src/bin/usb_hid_keyboard.rs index 0812697e4..483d86b81 100644 --- a/examples/nrf/src/bin/usb_hid_keyboard.rs +++ b/examples/nrf/src/bin/usb_hid_keyboard.rs | |||
| @@ -4,8 +4,12 @@ | |||
| 4 | #![feature(type_alias_impl_trait)] | 4 | #![feature(type_alias_impl_trait)] |
| 5 | 5 | ||
| 6 | use core::mem; | 6 | use core::mem; |
| 7 | use core::sync::atomic::{AtomicBool, Ordering}; | ||
| 7 | use defmt::*; | 8 | use defmt::*; |
| 9 | use embassy::blocking_mutex::raw::CriticalSectionRawMutex; | ||
| 10 | use embassy::channel::Channel; | ||
| 8 | use embassy::executor::Spawner; | 11 | use embassy::executor::Spawner; |
| 12 | use embassy::interrupt::InterruptExt; | ||
| 9 | use embassy::time::Duration; | 13 | use embassy::time::Duration; |
| 10 | use embassy_nrf::gpio::{Input, Pin, Pull}; | 14 | use embassy_nrf::gpio::{Input, Pin, Pull}; |
| 11 | use embassy_nrf::interrupt; | 15 | use embassy_nrf::interrupt; |
| @@ -13,7 +17,7 @@ use embassy_nrf::pac; | |||
| 13 | use embassy_nrf::usb::Driver; | 17 | use embassy_nrf::usb::Driver; |
| 14 | use embassy_nrf::Peripherals; | 18 | use embassy_nrf::Peripherals; |
| 15 | use embassy_usb::control::OutResponse; | 19 | use embassy_usb::control::OutResponse; |
| 16 | use embassy_usb::{Config, UsbDeviceBuilder}; | 20 | use embassy_usb::{Config, DeviceCommand, DeviceStateHandler, UsbDeviceBuilder}; |
| 17 | use embassy_usb_hid::{HidClass, ReportId, RequestHandler, State}; | 21 | use embassy_usb_hid::{HidClass, ReportId, RequestHandler, State}; |
| 18 | use futures::future::join; | 22 | use futures::future::join; |
| 19 | use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; | 23 | use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; |
| @@ -21,6 +25,29 @@ use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; | |||
| 21 | use defmt_rtt as _; // global logger | 25 | use defmt_rtt as _; // global logger |
| 22 | use panic_probe as _; | 26 | use panic_probe as _; |
| 23 | 27 | ||
| 28 | static USB_COMMANDS: Channel<CriticalSectionRawMutex, DeviceCommand, 1> = Channel::new(); | ||
| 29 | static SUSPENDED: AtomicBool = AtomicBool::new(false); | ||
| 30 | |||
| 31 | fn on_power_interrupt(_: *mut ()) { | ||
| 32 | let regs = unsafe { &*pac::POWER::ptr() }; | ||
| 33 | |||
| 34 | if regs.events_usbdetected.read().bits() != 0 { | ||
| 35 | regs.events_usbdetected.reset(); | ||
| 36 | info!("Vbus detected, enabling USB..."); | ||
| 37 | if USB_COMMANDS.try_send(DeviceCommand::Enable).is_err() { | ||
| 38 | warn!("Failed to send enable command to USB channel"); | ||
| 39 | } | ||
| 40 | } | ||
| 41 | |||
| 42 | if regs.events_usbremoved.read().bits() != 0 { | ||
| 43 | regs.events_usbremoved.reset(); | ||
| 44 | info!("Vbus removed, disabling USB..."); | ||
| 45 | if USB_COMMANDS.try_send(DeviceCommand::Disable).is_err() { | ||
| 46 | warn!("Failed to send disable command to USB channel"); | ||
| 47 | }; | ||
| 48 | } | ||
| 49 | } | ||
| 50 | |||
| 24 | #[embassy::main] | 51 | #[embassy::main] |
| 25 | async fn main(_spawner: Spawner, p: Peripherals) { | 52 | async fn main(_spawner: Spawner, p: Peripherals) { |
| 26 | let clock: pac::CLOCK = unsafe { mem::transmute(()) }; | 53 | let clock: pac::CLOCK = unsafe { mem::transmute(()) }; |
| @@ -30,10 +57,6 @@ async fn main(_spawner: Spawner, p: Peripherals) { | |||
| 30 | clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) }); | 57 | clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) }); |
| 31 | while clock.events_hfclkstarted.read().bits() != 1 {} | 58 | while clock.events_hfclkstarted.read().bits() != 1 {} |
| 32 | 59 | ||
| 33 | info!("Waiting for vbus..."); | ||
| 34 | while !power.usbregstatus.read().vbusdetect().is_vbus_present() {} | ||
| 35 | info!("vbus OK"); | ||
| 36 | |||
| 37 | // Create the driver, from the HAL. | 60 | // Create the driver, from the HAL. |
| 38 | let irq = interrupt::take!(USBD); | 61 | let irq = interrupt::take!(USBD); |
| 39 | let driver = Driver::new(p.USBD, irq); | 62 | let driver = Driver::new(p.USBD, irq); |
| @@ -45,6 +68,8 @@ async fn main(_spawner: Spawner, p: Peripherals) { | |||
| 45 | config.serial_number = Some("12345678"); | 68 | config.serial_number = Some("12345678"); |
| 46 | config.max_power = 100; | 69 | config.max_power = 100; |
| 47 | config.max_packet_size_0 = 64; | 70 | config.max_packet_size_0 = 64; |
| 71 | config.supports_remote_wakeup = true; | ||
| 72 | config.start_enabled = false; | ||
| 48 | 73 | ||
| 49 | // Create embassy-usb DeviceBuilder using the driver and config. | 74 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 50 | // It needs some buffers for building the descriptors. | 75 | // It needs some buffers for building the descriptors. |
| @@ -53,16 +78,19 @@ async fn main(_spawner: Spawner, p: Peripherals) { | |||
| 53 | let mut bos_descriptor = [0; 256]; | 78 | let mut bos_descriptor = [0; 256]; |
| 54 | let mut control_buf = [0; 16]; | 79 | let mut control_buf = [0; 16]; |
| 55 | let request_handler = MyRequestHandler {}; | 80 | let request_handler = MyRequestHandler {}; |
| 81 | let device_state_handler = MyDeviceStateHandler::new(); | ||
| 56 | 82 | ||
| 57 | let mut state = State::<8, 1>::new(); | 83 | let mut state = State::<8, 1>::new(); |
| 58 | 84 | ||
| 59 | let mut builder = UsbDeviceBuilder::new( | 85 | let mut builder = UsbDeviceBuilder::new_with_channel( |
| 60 | driver, | 86 | driver, |
| 61 | config, | 87 | config, |
| 62 | &mut device_descriptor, | 88 | &mut device_descriptor, |
| 63 | &mut config_descriptor, | 89 | &mut config_descriptor, |
| 64 | &mut bos_descriptor, | 90 | &mut bos_descriptor, |
| 65 | &mut control_buf, | 91 | &mut control_buf, |
| 92 | Some(&device_state_handler), | ||
| 93 | &USB_COMMANDS, | ||
| 66 | ); | 94 | ); |
| 67 | 95 | ||
| 68 | // Create classes on the builder. | 96 | // Create classes on the builder. |
| @@ -76,7 +104,7 @@ async fn main(_spawner: Spawner, p: Peripherals) { | |||
| 76 | ); | 104 | ); |
| 77 | 105 | ||
| 78 | // Build the builder. | 106 | // Build the builder. |
| 79 | let mut usb = builder.build().await; | 107 | let mut usb = builder.build(); |
| 80 | 108 | ||
| 81 | // Run the USB device. | 109 | // Run the USB device. |
| 82 | let usb_fut = usb.run(); | 110 | let usb_fut = usb.run(); |
| @@ -90,6 +118,12 @@ async fn main(_spawner: Spawner, p: Peripherals) { | |||
| 90 | loop { | 118 | loop { |
| 91 | button.wait_for_low().await; | 119 | button.wait_for_low().await; |
| 92 | info!("PRESSED"); | 120 | info!("PRESSED"); |
| 121 | |||
| 122 | if SUSPENDED.load(Ordering::Acquire) { | ||
| 123 | info!("Triggering remote wakeup"); | ||
| 124 | USB_COMMANDS.send(DeviceCommand::RemoteWakeup); | ||
| 125 | } | ||
| 126 | |||
| 93 | let report = KeyboardReport { | 127 | let report = KeyboardReport { |
| 94 | keycodes: [4, 0, 0, 0, 0, 0], | 128 | keycodes: [4, 0, 0, 0, 0, 0], |
| 95 | leds: 0, | 129 | leds: 0, |
| @@ -119,6 +153,16 @@ async fn main(_spawner: Spawner, p: Peripherals) { | |||
| 119 | let out_fut = async { | 153 | let out_fut = async { |
| 120 | hid_out.run(false, &request_handler).await; | 154 | hid_out.run(false, &request_handler).await; |
| 121 | }; | 155 | }; |
| 156 | |||
| 157 | let power_irq = interrupt::take!(POWER_CLOCK); | ||
| 158 | power_irq.set_handler(on_power_interrupt); | ||
| 159 | power_irq.unpend(); | ||
| 160 | power_irq.enable(); | ||
| 161 | |||
| 162 | power | ||
| 163 | .intenset | ||
| 164 | .write(|w| w.usbdetected().set().usbremoved().set()); | ||
| 165 | |||
| 122 | // Run everything concurrently. | 166 | // Run everything concurrently. |
| 123 | // If we had made everything `'static` above instead, we could do this using separate tasks instead. | 167 | // If we had made everything `'static` above instead, we could do this using separate tasks instead. |
| 124 | join(usb_fut, join(in_fut, out_fut)).await; | 168 | join(usb_fut, join(in_fut, out_fut)).await; |
| @@ -146,3 +190,59 @@ impl RequestHandler for MyRequestHandler { | |||
| 146 | None | 190 | None |
| 147 | } | 191 | } |
| 148 | } | 192 | } |
| 193 | |||
| 194 | struct MyDeviceStateHandler { | ||
| 195 | configured: AtomicBool, | ||
| 196 | } | ||
| 197 | |||
| 198 | impl MyDeviceStateHandler { | ||
| 199 | fn new() -> Self { | ||
| 200 | MyDeviceStateHandler { | ||
| 201 | configured: AtomicBool::new(false), | ||
| 202 | } | ||
| 203 | } | ||
| 204 | } | ||
| 205 | |||
| 206 | impl DeviceStateHandler for MyDeviceStateHandler { | ||
| 207 | fn reset(&self) { | ||
| 208 | self.configured.store(false, Ordering::Relaxed); | ||
| 209 | info!("Bus reset, the Vbus current limit is 100mA"); | ||
| 210 | } | ||
| 211 | |||
| 212 | fn addressed(&self, addr: u8) { | ||
| 213 | self.configured.store(false, Ordering::Relaxed); | ||
| 214 | info!("USB address set to: {}", addr); | ||
| 215 | } | ||
| 216 | |||
| 217 | fn configured(&self, configured: bool) { | ||
| 218 | self.configured.store(configured, Ordering::Relaxed); | ||
| 219 | if configured { | ||
| 220 | info!( | ||
| 221 | "Device configured, it may now draw up to the configured current limit from Vbus." | ||
| 222 | ) | ||
| 223 | } else { | ||
| 224 | info!("Device is no longer configured, the Vbus current limit is 100mA."); | ||
| 225 | } | ||
| 226 | } | ||
| 227 | |||
| 228 | fn suspended(&self, suspended: bool) { | ||
| 229 | if suspended { | ||
| 230 | info!("Device suspended, the Vbus current limit is 500µA (or 2.5mA for high-power devices with remote wakeup enabled)."); | ||
| 231 | SUSPENDED.store(true, Ordering::Release); | ||
| 232 | } else { | ||
| 233 | SUSPENDED.store(false, Ordering::Release); | ||
| 234 | if self.configured.load(Ordering::Relaxed) { | ||
| 235 | info!( | ||
| 236 | "Device resumed, it may now draw up to the configured current limit from Vbus" | ||
| 237 | ); | ||
| 238 | } else { | ||
| 239 | info!("Device resumed, the Vbus current limit is 100mA"); | ||
| 240 | } | ||
| 241 | } | ||
| 242 | } | ||
| 243 | |||
| 244 | fn disabled(&self) { | ||
| 245 | self.configured.store(false, Ordering::Relaxed); | ||
| 246 | info!("Device disabled"); | ||
| 247 | } | ||
| 248 | } | ||
diff --git a/examples/nrf/src/bin/usb_hid_mouse.rs b/examples/nrf/src/bin/usb_hid_mouse.rs index ca9383827..fe27e76fb 100644 --- a/examples/nrf/src/bin/usb_hid_mouse.rs +++ b/examples/nrf/src/bin/usb_hid_mouse.rs | |||
| @@ -61,6 +61,7 @@ async fn main(_spawner: Spawner, p: Peripherals) { | |||
| 61 | &mut config_descriptor, | 61 | &mut config_descriptor, |
| 62 | &mut bos_descriptor, | 62 | &mut bos_descriptor, |
| 63 | &mut control_buf, | 63 | &mut control_buf, |
| 64 | None, | ||
| 64 | ); | 65 | ); |
| 65 | 66 | ||
| 66 | // Create classes on the builder. | 67 | // Create classes on the builder. |
| @@ -74,7 +75,7 @@ async fn main(_spawner: Spawner, p: Peripherals) { | |||
| 74 | ); | 75 | ); |
| 75 | 76 | ||
| 76 | // Build the builder. | 77 | // Build the builder. |
| 77 | let mut usb = builder.build().await; | 78 | let mut usb = builder.build(); |
| 78 | 79 | ||
| 79 | // Run the USB device. | 80 | // Run the USB device. |
| 80 | let usb_fut = usb.run(); | 81 | let usb_fut = usb.run(); |
diff --git a/examples/nrf/src/bin/usb_serial.rs b/examples/nrf/src/bin/usb_serial.rs index 684322837..987cc4139 100644 --- a/examples/nrf/src/bin/usb_serial.rs +++ b/examples/nrf/src/bin/usb_serial.rs | |||
| @@ -54,13 +54,14 @@ async fn main(_spawner: Spawner, p: Peripherals) { | |||
| 54 | &mut config_descriptor, | 54 | &mut config_descriptor, |
| 55 | &mut bos_descriptor, | 55 | &mut bos_descriptor, |
| 56 | &mut control_buf, | 56 | &mut control_buf, |
| 57 | None, | ||
| 57 | ); | 58 | ); |
| 58 | 59 | ||
| 59 | // Create classes on the builder. | 60 | // Create classes on the builder. |
| 60 | let mut class = CdcAcmClass::new(&mut builder, &mut state, 64); | 61 | let mut class = CdcAcmClass::new(&mut builder, &mut state, 64); |
| 61 | 62 | ||
| 62 | // Build the builder. | 63 | // Build the builder. |
| 63 | let mut usb = builder.build().await; | 64 | let mut usb = builder.build(); |
| 64 | 65 | ||
| 65 | // Run the USB device. | 66 | // Run the USB device. |
| 66 | let usb_fut = usb.run(); | 67 | let usb_fut = usb.run(); |
diff --git a/examples/nrf/src/bin/usb_serial_multitask.rs b/examples/nrf/src/bin/usb_serial_multitask.rs index bfb09014c..5fcb0e052 100644 --- a/examples/nrf/src/bin/usb_serial_multitask.rs +++ b/examples/nrf/src/bin/usb_serial_multitask.rs | |||
| @@ -79,13 +79,14 @@ async fn main(spawner: Spawner, p: Peripherals) { | |||
| 79 | &mut res.config_descriptor, | 79 | &mut res.config_descriptor, |
| 80 | &mut res.bos_descriptor, | 80 | &mut res.bos_descriptor, |
| 81 | &mut res.control_buf, | 81 | &mut res.control_buf, |
| 82 | None, | ||
| 82 | ); | 83 | ); |
| 83 | 84 | ||
| 84 | // Create classes on the builder. | 85 | // Create classes on the builder. |
| 85 | let class = CdcAcmClass::new(&mut builder, &mut res.serial_state, 64); | 86 | let class = CdcAcmClass::new(&mut builder, &mut res.serial_state, 64); |
| 86 | 87 | ||
| 87 | // Build the builder. | 88 | // Build the builder. |
| 88 | let usb = builder.build().await; | 89 | let usb = builder.build(); |
| 89 | 90 | ||
| 90 | unwrap!(spawner.spawn(usb_task(usb))); | 91 | unwrap!(spawner.spawn(usb_task(usb))); |
| 91 | unwrap!(spawner.spawn(echo_task(class))); | 92 | unwrap!(spawner.spawn(echo_task(class))); |
