aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoralexmoon <[email protected]>2022-04-10 15:41:51 -0400
committeralexmoon <[email protected]>2022-04-13 14:55:02 -0400
commitf5656e354485888cc7c2697052ae2c79b94a59ad (patch)
tree8580410dbaca2c3f0db6e431f77f248dd6bd5dc9
parent2217de24c02e9f7e0aafeb8315ab6be8b644c52f (diff)
Add DeviceStateHandler, DeviceCommand channel, and remote wakeup support
-rw-r--r--embassy-nrf/src/usb.rs104
-rw-r--r--embassy-usb-hid/src/lib.rs13
-rw-r--r--embassy-usb-serial/src/lib.rs5
-rw-r--r--embassy-usb/src/builder.rs77
-rw-r--r--embassy-usb/src/driver.rs44
-rw-r--r--embassy-usb/src/lib.rs144
-rw-r--r--embassy-usb/src/util.rs72
-rw-r--r--examples/nrf/src/bin/usb_hid_keyboard.rs114
-rw-r--r--examples/nrf/src/bin/usb_hid_mouse.rs3
-rw-r--r--examples/nrf/src/bin/usb_serial.rs3
-rw-r--r--examples/nrf/src/bin/usb_serial_multitask.rs3
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;
10use embassy::waitqueue::AtomicWaker; 10use embassy::waitqueue::AtomicWaker;
11use embassy_hal_common::unborrow; 11use embassy_hal_common::unborrow;
12use embassy_usb::control::Request; 12use embassy_usb::control::Request;
13use embassy_usb::driver::{self, EndpointError, Event}; 13use embassy_usb::driver::{self, EndpointError, Event, Unsupported};
14use embassy_usb::types::{EndpointAddress, EndpointInfo, EndpointType, UsbDirection}; 14use embassy_usb::types::{EndpointAddress, EndpointInfo, EndpointType, UsbDirection};
15use futures::future::poll_fn; 15use futures::future::poll_fn;
16use futures::Future; 16use futures::Future;
@@ -140,7 +140,6 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> {
140 type EndpointIn = Endpoint<'d, T, In>; 140 type EndpointIn = Endpoint<'d, T, In>;
141 type ControlPipe = ControlPipe<'d, T>; 141 type ControlPipe = ControlPipe<'d, T>;
142 type Bus = Bus<'d, T>; 142 type Bus = Bus<'d, T>;
143 type EnableFuture = impl Future<Output = Self::Bus> + 'd;
144 143
145 fn alloc_endpoint_in( 144 fn alloc_endpoint_in(
146 &mut self, 145 &mut self,
@@ -192,7 +191,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
203pub struct Bus<'d, T: Instance> {
204 phantom: PhantomData<&'d mut T>,
205 alloc_in: Allocator,
206 alloc_out: Allocator,
207}
208
209impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
210 type EnableFuture<'a> = impl Future<Output = ()> + 'a where Self: 'a;
211 type 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
239pub struct Bus<'d, T: Instance> {
240 phantom: PhantomData<&'d mut T>,
241 alloc_in: Allocator,
242 alloc_out: Allocator,
243}
244 250
245impl<'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;
11use core::ops::Range; 11use core::ops::Range;
12use core::sync::atomic::{AtomicUsize, Ordering}; 12use core::sync::atomic::{AtomicUsize, Ordering};
13 13
14use embassy::blocking_mutex::raw::RawMutex;
14use embassy::time::Duration; 15use embassy::time::Duration;
15use embassy_usb::driver::EndpointOut; 16use embassy_usb::driver::EndpointOut;
16use embassy_usb::{ 17use 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;
8use core::cell::Cell; 8use core::cell::Cell;
9use core::mem::{self, MaybeUninit}; 9use core::mem::{self, MaybeUninit};
10use core::sync::atomic::{AtomicBool, Ordering}; 10use core::sync::atomic::{AtomicBool, Ordering};
11use embassy::blocking_mutex::raw::RawMutex;
11use embassy::blocking_mutex::CriticalSectionMutex; 12use embassy::blocking_mutex::CriticalSectionMutex;
12use embassy_usb::control::{self, ControlHandler, InResponse, OutResponse, Request}; 13use embassy_usb::control::{self, ControlHandler, InResponse, OutResponse, Request};
13use embassy_usb::driver::{Endpoint, EndpointError, EndpointIn, EndpointOut}; 14use embassy_usb::driver::{Endpoint, EndpointError, EndpointIn, EndpointOut};
@@ -162,8 +163,8 @@ impl<'d> ControlHandler for Control<'d> {
162impl<'d, D: Driver<'d>> CdcAcmClass<'d, D> { 163impl<'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 @@
1use embassy::blocking_mutex::raw::{NoopRawMutex, RawMutex};
2use embassy::channel::Channel;
1use heapless::Vec; 3use heapless::Vec;
2 4
5use crate::DeviceCommand;
6
3use super::control::ControlHandler; 7use super::control::ControlHandler;
4use super::descriptor::{BosWriter, DescriptorWriter}; 8use super::descriptor::{BosWriter, DescriptorWriter};
5use super::driver::{Driver, EndpointAllocError}; 9use super::driver::{Driver, EndpointAllocError};
6use super::types::*; 10use super::types::*;
11use super::DeviceStateHandler;
7use super::UsbDevice; 12use super::UsbDevice;
8use super::MAX_INTERFACE_COUNT; 13use 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
98impl<'a> Config<'a> { 108impl<'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.
120pub struct UsbDeviceBuilder<'d, D: Driver<'d>> { 131pub 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
135impl<'d, D: Driver<'d>> UsbDeviceBuilder<'d, D> { 148impl<'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
176impl<'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
59pub trait Bus { 58pub 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
111pub trait Endpoint { 115pub 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;
12pub mod types; 12pub mod types;
13mod util; 13mod util;
14 14
15use driver::Unsupported;
16use embassy::blocking_mutex::raw::{NoopRawMutex, RawMutex};
17use embassy::channel::Channel;
15use heapless::Vec; 18use heapless::Vec;
16 19
17use self::control::*; 20use 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))]
31pub enum UsbDeviceState { 35pub 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
54pub const MAX_INTERFACE_COUNT: usize = 4; 58pub const MAX_INTERFACE_COUNT: usize = 4;
55 59
56pub struct UsbDevice<'d, D: Driver<'d>> { 60#[derive(PartialEq, Eq, Copy, Clone, Debug)]
61#[cfg_attr(feature = "defmt", derive(defmt::Format))]
62pub enum DeviceCommand {
63 Enable,
64 Disable,
65 RemoteWakeup,
66}
67
68/// A handler trait for changes in the device state of the [UsbDevice].
69pub 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
89pub 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
74impl<'d, D: Driver<'d>> UsbDevice<'d, D> { 110impl<'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 @@
1use core::future::Future; 1use core::future::Future;
2use core::marker::PhantomData;
2use core::pin::Pin; 3use core::pin::Pin;
3use core::task::{Context, Poll}; 4use core::task::{Context, Poll};
4 5
6use embassy::blocking_mutex::raw::RawMutex;
7use embassy::channel::Channel;
8
5#[derive(Debug, Clone)] 9#[derive(Debug, Clone)]
6pub enum Either<A, B> { 10pub enum Either3<A, B, C> {
7 Left(A), 11 First(A),
8 Right(B), 12 Second(B),
13 Third(C),
9} 14}
10 15
11pub fn select<A, B>(a: A, b: B) -> Select<A, B> 16/// Same as [`select`], but with more futures.
17pub fn select3<A, B, C>(a: A, b: B, c: C) -> Select3<A, B, C>
12where 18where
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
19pub 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"]
29pub struct Select3<A, B, C> {
20 a: A, 30 a: A,
21 b: B, 31 b: B,
32 c: C,
22} 33}
23 34
24impl<A: Unpin, B: Unpin> Unpin for Select<A, B> {} 35impl<A, B, C> Future for Select3<A, B, C>
25
26impl<A, B> Future for Select<A, B>
27where 36where
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
61pub struct Pending<T> {
62 _phantom: PhantomData<T>,
63}
64
65impl<T> Pending<T> {
66 fn new() -> Self {
67 Pending {
68 _phantom: PhantomData,
43 } 69 }
44 } 70 }
45} 71}
72
73impl<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
80pub 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
6use core::mem; 6use core::mem;
7use core::sync::atomic::{AtomicBool, Ordering};
7use defmt::*; 8use defmt::*;
9use embassy::blocking_mutex::raw::CriticalSectionRawMutex;
10use embassy::channel::Channel;
8use embassy::executor::Spawner; 11use embassy::executor::Spawner;
12use embassy::interrupt::InterruptExt;
9use embassy::time::Duration; 13use embassy::time::Duration;
10use embassy_nrf::gpio::{Input, Pin, Pull}; 14use embassy_nrf::gpio::{Input, Pin, Pull};
11use embassy_nrf::interrupt; 15use embassy_nrf::interrupt;
@@ -13,7 +17,7 @@ use embassy_nrf::pac;
13use embassy_nrf::usb::Driver; 17use embassy_nrf::usb::Driver;
14use embassy_nrf::Peripherals; 18use embassy_nrf::Peripherals;
15use embassy_usb::control::OutResponse; 19use embassy_usb::control::OutResponse;
16use embassy_usb::{Config, UsbDeviceBuilder}; 20use embassy_usb::{Config, DeviceCommand, DeviceStateHandler, UsbDeviceBuilder};
17use embassy_usb_hid::{HidClass, ReportId, RequestHandler, State}; 21use embassy_usb_hid::{HidClass, ReportId, RequestHandler, State};
18use futures::future::join; 22use futures::future::join;
19use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; 23use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor};
@@ -21,6 +25,29 @@ use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor};
21use defmt_rtt as _; // global logger 25use defmt_rtt as _; // global logger
22use panic_probe as _; 26use panic_probe as _;
23 27
28static USB_COMMANDS: Channel<CriticalSectionRawMutex, DeviceCommand, 1> = Channel::new();
29static SUSPENDED: AtomicBool = AtomicBool::new(false);
30
31fn on_power_interrupt(_: *mut ()) {
32 let regs = unsafe { &*pac::POWER::ptr() };
33
34 if regs.events_usbdetected.read().bits() != 0 {
35 regs.events_usbdetected.reset();
36 info!("Vbus detected, enabling USB...");
37 if USB_COMMANDS.try_send(DeviceCommand::Enable).is_err() {
38 warn!("Failed to send enable command to USB channel");
39 }
40 }
41
42 if regs.events_usbremoved.read().bits() != 0 {
43 regs.events_usbremoved.reset();
44 info!("Vbus removed, disabling USB...");
45 if USB_COMMANDS.try_send(DeviceCommand::Disable).is_err() {
46 warn!("Failed to send disable command to USB channel");
47 };
48 }
49}
50
24#[embassy::main] 51#[embassy::main]
25async fn main(_spawner: Spawner, p: Peripherals) { 52async fn main(_spawner: Spawner, p: Peripherals) {
26 let clock: pac::CLOCK = unsafe { mem::transmute(()) }; 53 let clock: pac::CLOCK = unsafe { mem::transmute(()) };
@@ -30,10 +57,6 @@ async fn main(_spawner: Spawner, p: Peripherals) {
30 clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) }); 57 clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) });
31 while clock.events_hfclkstarted.read().bits() != 1 {} 58 while clock.events_hfclkstarted.read().bits() != 1 {}
32 59
33 info!("Waiting for vbus...");
34 while !power.usbregstatus.read().vbusdetect().is_vbus_present() {}
35 info!("vbus OK");
36
37 // Create the driver, from the HAL. 60 // Create the driver, from the HAL.
38 let irq = interrupt::take!(USBD); 61 let irq = interrupt::take!(USBD);
39 let driver = Driver::new(p.USBD, irq); 62 let driver = Driver::new(p.USBD, irq);
@@ -45,6 +68,8 @@ async fn main(_spawner: Spawner, p: Peripherals) {
45 config.serial_number = Some("12345678"); 68 config.serial_number = Some("12345678");
46 config.max_power = 100; 69 config.max_power = 100;
47 config.max_packet_size_0 = 64; 70 config.max_packet_size_0 = 64;
71 config.supports_remote_wakeup = true;
72 config.start_enabled = false;
48 73
49 // Create embassy-usb DeviceBuilder using the driver and config. 74 // Create embassy-usb DeviceBuilder using the driver and config.
50 // It needs some buffers for building the descriptors. 75 // It needs some buffers for building the descriptors.
@@ -53,16 +78,19 @@ async fn main(_spawner: Spawner, p: Peripherals) {
53 let mut bos_descriptor = [0; 256]; 78 let mut bos_descriptor = [0; 256];
54 let mut control_buf = [0; 16]; 79 let mut control_buf = [0; 16];
55 let request_handler = MyRequestHandler {}; 80 let request_handler = MyRequestHandler {};
81 let device_state_handler = MyDeviceStateHandler::new();
56 82
57 let mut state = State::<8, 1>::new(); 83 let mut state = State::<8, 1>::new();
58 84
59 let mut builder = UsbDeviceBuilder::new( 85 let mut builder = UsbDeviceBuilder::new_with_channel(
60 driver, 86 driver,
61 config, 87 config,
62 &mut device_descriptor, 88 &mut device_descriptor,
63 &mut config_descriptor, 89 &mut config_descriptor,
64 &mut bos_descriptor, 90 &mut bos_descriptor,
65 &mut control_buf, 91 &mut control_buf,
92 Some(&device_state_handler),
93 &USB_COMMANDS,
66 ); 94 );
67 95
68 // Create classes on the builder. 96 // Create classes on the builder.
@@ -76,7 +104,7 @@ async fn main(_spawner: Spawner, p: Peripherals) {
76 ); 104 );
77 105
78 // Build the builder. 106 // Build the builder.
79 let mut usb = builder.build().await; 107 let mut usb = builder.build();
80 108
81 // Run the USB device. 109 // Run the USB device.
82 let usb_fut = usb.run(); 110 let usb_fut = usb.run();
@@ -90,6 +118,12 @@ async fn main(_spawner: Spawner, p: Peripherals) {
90 loop { 118 loop {
91 button.wait_for_low().await; 119 button.wait_for_low().await;
92 info!("PRESSED"); 120 info!("PRESSED");
121
122 if SUSPENDED.load(Ordering::Acquire) {
123 info!("Triggering remote wakeup");
124 USB_COMMANDS.send(DeviceCommand::RemoteWakeup);
125 }
126
93 let report = KeyboardReport { 127 let report = KeyboardReport {
94 keycodes: [4, 0, 0, 0, 0, 0], 128 keycodes: [4, 0, 0, 0, 0, 0],
95 leds: 0, 129 leds: 0,
@@ -119,6 +153,16 @@ async fn main(_spawner: Spawner, p: Peripherals) {
119 let out_fut = async { 153 let out_fut = async {
120 hid_out.run(false, &request_handler).await; 154 hid_out.run(false, &request_handler).await;
121 }; 155 };
156
157 let power_irq = interrupt::take!(POWER_CLOCK);
158 power_irq.set_handler(on_power_interrupt);
159 power_irq.unpend();
160 power_irq.enable();
161
162 power
163 .intenset
164 .write(|w| w.usbdetected().set().usbremoved().set());
165
122 // Run everything concurrently. 166 // Run everything concurrently.
123 // If we had made everything `'static` above instead, we could do this using separate tasks instead. 167 // If we had made everything `'static` above instead, we could do this using separate tasks instead.
124 join(usb_fut, join(in_fut, out_fut)).await; 168 join(usb_fut, join(in_fut, out_fut)).await;
@@ -146,3 +190,59 @@ impl RequestHandler for MyRequestHandler {
146 None 190 None
147 } 191 }
148} 192}
193
194struct MyDeviceStateHandler {
195 configured: AtomicBool,
196}
197
198impl MyDeviceStateHandler {
199 fn new() -> Self {
200 MyDeviceStateHandler {
201 configured: AtomicBool::new(false),
202 }
203 }
204}
205
206impl DeviceStateHandler for MyDeviceStateHandler {
207 fn reset(&self) {
208 self.configured.store(false, Ordering::Relaxed);
209 info!("Bus reset, the Vbus current limit is 100mA");
210 }
211
212 fn addressed(&self, addr: u8) {
213 self.configured.store(false, Ordering::Relaxed);
214 info!("USB address set to: {}", addr);
215 }
216
217 fn configured(&self, configured: bool) {
218 self.configured.store(configured, Ordering::Relaxed);
219 if configured {
220 info!(
221 "Device configured, it may now draw up to the configured current limit from Vbus."
222 )
223 } else {
224 info!("Device is no longer configured, the Vbus current limit is 100mA.");
225 }
226 }
227
228 fn suspended(&self, suspended: bool) {
229 if suspended {
230 info!("Device suspended, the Vbus current limit is 500µA (or 2.5mA for high-power devices with remote wakeup enabled).");
231 SUSPENDED.store(true, Ordering::Release);
232 } else {
233 SUSPENDED.store(false, Ordering::Release);
234 if self.configured.load(Ordering::Relaxed) {
235 info!(
236 "Device resumed, it may now draw up to the configured current limit from Vbus"
237 );
238 } else {
239 info!("Device resumed, the Vbus current limit is 100mA");
240 }
241 }
242 }
243
244 fn disabled(&self) {
245 self.configured.store(false, Ordering::Relaxed);
246 info!("Device disabled");
247 }
248}
diff --git a/examples/nrf/src/bin/usb_hid_mouse.rs b/examples/nrf/src/bin/usb_hid_mouse.rs
index ca9383827..fe27e76fb 100644
--- a/examples/nrf/src/bin/usb_hid_mouse.rs
+++ b/examples/nrf/src/bin/usb_hid_mouse.rs
@@ -61,6 +61,7 @@ async fn main(_spawner: Spawner, p: Peripherals) {
61 &mut config_descriptor, 61 &mut config_descriptor,
62 &mut bos_descriptor, 62 &mut bos_descriptor,
63 &mut control_buf, 63 &mut control_buf,
64 None,
64 ); 65 );
65 66
66 // Create classes on the builder. 67 // Create classes on the builder.
@@ -74,7 +75,7 @@ async fn main(_spawner: Spawner, p: Peripherals) {
74 ); 75 );
75 76
76 // Build the builder. 77 // Build the builder.
77 let mut usb = builder.build().await; 78 let mut usb = builder.build();
78 79
79 // Run the USB device. 80 // Run the USB device.
80 let usb_fut = usb.run(); 81 let usb_fut = usb.run();
diff --git a/examples/nrf/src/bin/usb_serial.rs b/examples/nrf/src/bin/usb_serial.rs
index 684322837..987cc4139 100644
--- a/examples/nrf/src/bin/usb_serial.rs
+++ b/examples/nrf/src/bin/usb_serial.rs
@@ -54,13 +54,14 @@ async fn main(_spawner: Spawner, p: Peripherals) {
54 &mut config_descriptor, 54 &mut config_descriptor,
55 &mut bos_descriptor, 55 &mut bos_descriptor,
56 &mut control_buf, 56 &mut control_buf,
57 None,
57 ); 58 );
58 59
59 // Create classes on the builder. 60 // Create classes on the builder.
60 let mut class = CdcAcmClass::new(&mut builder, &mut state, 64); 61 let mut class = CdcAcmClass::new(&mut builder, &mut state, 64);
61 62
62 // Build the builder. 63 // Build the builder.
63 let mut usb = builder.build().await; 64 let mut usb = builder.build();
64 65
65 // Run the USB device. 66 // Run the USB device.
66 let usb_fut = usb.run(); 67 let usb_fut = usb.run();
diff --git a/examples/nrf/src/bin/usb_serial_multitask.rs b/examples/nrf/src/bin/usb_serial_multitask.rs
index bfb09014c..5fcb0e052 100644
--- a/examples/nrf/src/bin/usb_serial_multitask.rs
+++ b/examples/nrf/src/bin/usb_serial_multitask.rs
@@ -79,13 +79,14 @@ async fn main(spawner: Spawner, p: Peripherals) {
79 &mut res.config_descriptor, 79 &mut res.config_descriptor,
80 &mut res.bos_descriptor, 80 &mut res.bos_descriptor,
81 &mut res.control_buf, 81 &mut res.control_buf,
82 None,
82 ); 83 );
83 84
84 // Create classes on the builder. 85 // Create classes on the builder.
85 let class = CdcAcmClass::new(&mut builder, &mut res.serial_state, 64); 86 let class = CdcAcmClass::new(&mut builder, &mut res.serial_state, 64);
86 87
87 // Build the builder. 88 // Build the builder.
88 let usb = builder.build().await; 89 let usb = builder.build();
89 90
90 unwrap!(spawner.spawn(usb_task(usb))); 91 unwrap!(spawner.spawn(usb_task(usb)));
91 unwrap!(spawner.spawn(echo_task(class))); 92 unwrap!(spawner.spawn(echo_task(class)));