aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoralexmoon <[email protected]>2022-04-13 13:09:08 -0400
committeralexmoon <[email protected]>2022-04-13 14:55:02 -0400
commitff7c6b350e2338a0b1e4327f4b2eb0435468f313 (patch)
tree1a045db7348d2562b9c8a19299467a30b62e501e
parent1d875fab2dc9d765ebf9f4b37112581301f2ed7e (diff)
Remove channel and make run future cancelable
-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.rs71
-rw-r--r--embassy-usb/src/lib.rs140
-rw-r--r--embassy-usb/src/util.rs33
-rw-r--r--examples/nrf/src/bin/usb_hid_keyboard.rs63
6 files changed, 129 insertions, 196 deletions
diff --git a/embassy-usb-hid/src/lib.rs b/embassy-usb-hid/src/lib.rs
index 4a1df0eab..e870becf5 100644
--- a/embassy-usb-hid/src/lib.rs
+++ b/embassy-usb-hid/src/lib.rs
@@ -11,7 +11,6 @@ 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;
15use embassy::time::Duration; 14use embassy::time::Duration;
16use embassy_usb::driver::EndpointOut; 15use embassy_usb::driver::EndpointOut;
17use embassy_usb::{ 16use embassy_usb::{
@@ -89,8 +88,8 @@ impl<'d, D: Driver<'d>, const IN_N: usize> HidClass<'d, D, (), IN_N> {
89 /// high performance uses, and a value of 255 is good for best-effort usecases. 88 /// high performance uses, and a value of 255 is good for best-effort usecases.
90 /// 89 ///
91 /// This allocates an IN endpoint only. 90 /// This allocates an IN endpoint only.
92 pub fn new<M: RawMutex, const OUT_N: usize>( 91 pub fn new<const OUT_N: usize>(
93 builder: &mut UsbDeviceBuilder<'d, D, M>, 92 builder: &mut UsbDeviceBuilder<'d, D>,
94 state: &'d mut State<'d, IN_N, OUT_N>, 93 state: &'d mut State<'d, IN_N, OUT_N>,
95 report_descriptor: &'static [u8], 94 report_descriptor: &'static [u8],
96 request_handler: Option<&'d dyn RequestHandler>, 95 request_handler: Option<&'d dyn RequestHandler>,
@@ -133,8 +132,8 @@ impl<'d, D: Driver<'d>, const IN_N: usize, const OUT_N: usize>
133 /// high performance uses, and a value of 255 is good for best-effort usecases. 132 /// high performance uses, and a value of 255 is good for best-effort usecases.
134 /// 133 ///
135 /// This allocates two endpoints (IN and OUT). 134 /// This allocates two endpoints (IN and OUT).
136 pub fn with_output_ep<M: RawMutex>( 135 pub fn with_output_ep(
137 builder: &mut UsbDeviceBuilder<'d, D, M>, 136 builder: &mut UsbDeviceBuilder<'d, D>,
138 state: &'d mut State<'d, IN_N, OUT_N>, 137 state: &'d mut State<'d, IN_N, OUT_N>,
139 report_descriptor: &'static [u8], 138 report_descriptor: &'static [u8],
140 request_handler: Option<&'d dyn RequestHandler>, 139 request_handler: Option<&'d dyn RequestHandler>,
@@ -393,9 +392,9 @@ impl<'a> Control<'a> {
393 } 392 }
394 } 393 }
395 394
396 fn build<'d, D: Driver<'d>, M: RawMutex>( 395 fn build<'d, D: Driver<'d>>(
397 &'d mut self, 396 &'d mut self,
398 builder: &mut UsbDeviceBuilder<'d, D, M>, 397 builder: &mut UsbDeviceBuilder<'d, D>,
399 ep_out: Option<&D::EndpointOut>, 398 ep_out: Option<&D::EndpointOut>,
400 ep_in: &D::EndpointIn, 399 ep_in: &D::EndpointIn,
401 ) { 400 ) {
diff --git a/embassy-usb-serial/src/lib.rs b/embassy-usb-serial/src/lib.rs
index 7f006c0fd..7b25398d0 100644
--- a/embassy-usb-serial/src/lib.rs
+++ b/embassy-usb-serial/src/lib.rs
@@ -8,7 +8,6 @@ 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;
12use embassy::blocking_mutex::CriticalSectionMutex; 11use embassy::blocking_mutex::CriticalSectionMutex;
13use embassy_usb::control::{self, ControlHandler, InResponse, OutResponse, Request}; 12use embassy_usb::control::{self, ControlHandler, InResponse, OutResponse, Request};
14use embassy_usb::driver::{Endpoint, EndpointError, EndpointIn, EndpointOut}; 13use embassy_usb::driver::{Endpoint, EndpointError, EndpointIn, EndpointOut};
@@ -163,8 +162,8 @@ impl<'d> ControlHandler for Control<'d> {
163impl<'d, D: Driver<'d>> CdcAcmClass<'d, D> { 162impl<'d, D: Driver<'d>> CdcAcmClass<'d, D> {
164 /// Creates a new CdcAcmClass with the provided UsbBus and max_packet_size in bytes. For 163 /// Creates a new CdcAcmClass with the provided UsbBus and max_packet_size in bytes. For
165 /// full-speed devices, max_packet_size has to be one of 8, 16, 32 or 64. 164 /// full-speed devices, max_packet_size has to be one of 8, 16, 32 or 64.
166 pub fn new<M: RawMutex>( 165 pub fn new(
167 builder: &mut UsbDeviceBuilder<'d, D, M>, 166 builder: &mut UsbDeviceBuilder<'d, D>,
168 state: &'d mut State<'d>, 167 state: &'d mut State<'d>,
169 max_packet_size: u16, 168 max_packet_size: u16,
170 ) -> Self { 169 ) -> Self {
diff --git a/embassy-usb/src/builder.rs b/embassy-usb/src/builder.rs
index 30d31ac74..486672055 100644
--- a/embassy-usb/src/builder.rs
+++ b/embassy-usb/src/builder.rs
@@ -1,9 +1,5 @@
1use embassy::blocking_mutex::raw::{NoopRawMutex, RawMutex};
2use embassy::channel::Channel;
3use heapless::Vec; 1use heapless::Vec;
4 2
5use crate::DeviceCommand;
6
7use super::control::ControlHandler; 3use super::control::ControlHandler;
8use super::descriptor::{BosWriter, DescriptorWriter}; 4use super::descriptor::{BosWriter, DescriptorWriter};
9use super::driver::{Driver, EndpointAllocError}; 5use super::driver::{Driver, EndpointAllocError};
@@ -98,11 +94,6 @@ pub struct Config<'a> {
98 /// Default: 100mA 94 /// Default: 100mA
99 /// Max: 500mA 95 /// Max: 500mA
100 pub max_power: u16, 96 pub max_power: u16,
101
102 /// Whether the USB bus should be enabled when built.
103 ///
104 /// Default: true
105 pub start_enabled: bool,
106} 97}
107 98
108impl<'a> Config<'a> { 99impl<'a> Config<'a> {
@@ -122,18 +113,16 @@ impl<'a> Config<'a> {
122 supports_remote_wakeup: false, 113 supports_remote_wakeup: false,
123 composite_with_iads: false, 114 composite_with_iads: false,
124 max_power: 100, 115 max_power: 100,
125 start_enabled: true,
126 } 116 }
127 } 117 }
128} 118}
129 119
130/// Used to build new [`UsbDevice`]s. 120/// Used to build new [`UsbDevice`]s.
131pub struct UsbDeviceBuilder<'d, D: Driver<'d>, M: RawMutex> { 121pub struct UsbDeviceBuilder<'d, D: Driver<'d>> {
132 config: Config<'d>, 122 config: Config<'d>,
133 handler: Option<&'d dyn DeviceStateHandler>, 123 handler: Option<&'d dyn DeviceStateHandler>,
134 interfaces: Vec<(u8, &'d mut dyn ControlHandler), MAX_INTERFACE_COUNT>, 124 interfaces: Vec<(u8, &'d mut dyn ControlHandler), MAX_INTERFACE_COUNT>,
135 control_buf: &'d mut [u8], 125 control_buf: &'d mut [u8],
136 commands: Option<&'d Channel<M, DeviceCommand, 1>>,
137 126
138 driver: D, 127 driver: D,
139 next_interface_number: u8, 128 next_interface_number: u8,
@@ -145,7 +134,7 @@ pub struct UsbDeviceBuilder<'d, D: Driver<'d>, M: RawMutex> {
145 pub bos_descriptor: BosWriter<'d>, 134 pub bos_descriptor: BosWriter<'d>,
146} 135}
147 136
148impl<'d, D: Driver<'d>> UsbDeviceBuilder<'d, D, NoopRawMutex> { 137impl<'d, D: Driver<'d>> UsbDeviceBuilder<'d, D> {
149 /// Creates a builder for constructing a new [`UsbDevice`]. 138 /// Creates a builder for constructing a new [`UsbDevice`].
150 /// 139 ///
151 /// `control_buf` is a buffer used for USB control request data. It should be sized 140 /// `control_buf` is a buffer used for USB control request data. It should be sized
@@ -160,57 +149,6 @@ impl<'d, D: Driver<'d>> UsbDeviceBuilder<'d, D, NoopRawMutex> {
160 control_buf: &'d mut [u8], 149 control_buf: &'d mut [u8],
161 handler: Option<&'d dyn DeviceStateHandler>, 150 handler: Option<&'d dyn DeviceStateHandler>,
162 ) -> Self { 151 ) -> 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>>,
213 ) -> Self {
214 // Magic values specified in USB-IF ECN on IADs. 152 // Magic values specified in USB-IF ECN on IADs.
215 if config.composite_with_iads 153 if config.composite_with_iads
216 && (config.device_class != 0xEF 154 && (config.device_class != 0xEF
@@ -243,8 +181,6 @@ impl<'d, D: Driver<'d>, M: RawMutex> UsbDeviceBuilder<'d, D, M> {
243 config, 181 config,
244 interfaces: Vec::new(), 182 interfaces: Vec::new(),
245 control_buf, 183 control_buf,
246 commands: channel,
247
248 next_interface_number: 0, 184 next_interface_number: 0,
249 next_string_index: 4, 185 next_string_index: 4,
250 186
@@ -255,7 +191,7 @@ impl<'d, D: Driver<'d>, M: RawMutex> UsbDeviceBuilder<'d, D, M> {
255 } 191 }
256 192
257 /// Creates the [`UsbDevice`] instance with the configuration in this builder. 193 /// Creates the [`UsbDevice`] instance with the configuration in this builder.
258 pub fn build(mut self) -> UsbDevice<'d, D, M> { 194 pub fn build(mut self) -> UsbDevice<'d, D> {
259 self.config_descriptor.end_configuration(); 195 self.config_descriptor.end_configuration();
260 self.bos_descriptor.end_bos(); 196 self.bos_descriptor.end_bos();
261 197
@@ -263,7 +199,6 @@ impl<'d, D: Driver<'d>, M: RawMutex> UsbDeviceBuilder<'d, D, M> {
263 self.driver, 199 self.driver,
264 self.config, 200 self.config,
265 self.handler, 201 self.handler,
266 self.commands,
267 self.device_descriptor.into_buf(), 202 self.device_descriptor.into_buf(),
268 self.config_descriptor.into_buf(), 203 self.config_descriptor.into_buf(),
269 self.bos_descriptor.writer.into_buf(), 204 self.bos_descriptor.writer.into_buf(),
diff --git a/embassy-usb/src/lib.rs b/embassy-usb/src/lib.rs
index 102ccbb3a..ccea8bc7a 100644
--- a/embassy-usb/src/lib.rs
+++ b/embassy-usb/src/lib.rs
@@ -10,19 +10,14 @@ pub mod control;
10pub mod descriptor; 10pub mod descriptor;
11pub mod driver; 11pub mod driver;
12pub mod types; 12pub mod types;
13mod util;
14 13
15use driver::Unsupported; 14use embassy::util::{select, Either};
16use embassy::blocking_mutex::raw::{NoopRawMutex, RawMutex};
17use embassy::channel::Channel;
18use embassy::util::{select3, Either3};
19use heapless::Vec; 15use heapless::Vec;
20 16
21use self::control::*; 17use self::control::*;
22use self::descriptor::*; 18use self::descriptor::*;
23use self::driver::{Bus, Driver, Event}; 19use self::driver::{Bus, Driver, Event};
24use self::types::*; 20use self::types::*;
25use self::util::*;
26 21
27pub use self::builder::Config; 22pub use self::builder::Config;
28pub use self::builder::UsbDeviceBuilder; 23pub use self::builder::UsbDeviceBuilder;
@@ -47,6 +42,19 @@ pub enum UsbDeviceState {
47 Configured, 42 Configured,
48} 43}
49 44
45#[derive(PartialEq, Eq, Copy, Clone, Debug)]
46#[cfg_attr(feature = "defmt", derive(defmt::Format))]
47pub enum RemoteWakeupError {
48 InvalidState,
49 Unsupported,
50}
51
52impl From<driver::Unsupported> for RemoteWakeupError {
53 fn from(_: driver::Unsupported) -> Self {
54 RemoteWakeupError::Unsupported
55 }
56}
57
50/// The bConfiguration value for the not configured state. 58/// The bConfiguration value for the not configured state.
51pub const CONFIGURATION_NONE: u8 = 0; 59pub const CONFIGURATION_NONE: u8 = 0;
52 60
@@ -58,16 +66,11 @@ pub const DEFAULT_ALTERNATE_SETTING: u8 = 0;
58 66
59pub const MAX_INTERFACE_COUNT: usize = 4; 67pub const MAX_INTERFACE_COUNT: usize = 4;
60 68
61#[derive(PartialEq, Eq, Copy, Clone, Debug)]
62#[cfg_attr(feature = "defmt", derive(defmt::Format))]
63pub enum DeviceCommand {
64 Enable,
65 Disable,
66 RemoteWakeup,
67}
68
69/// A handler trait for changes in the device state of the [UsbDevice]. 69/// A handler trait for changes in the device state of the [UsbDevice].
70pub trait DeviceStateHandler { 70pub trait DeviceStateHandler {
71 /// Called when the USB device has been enabled or disabled.
72 fn enabled(&self, _enabled: bool) {}
73
71 /// Called when the host resets the device. 74 /// Called when the host resets the device.
72 fn reset(&self) {} 75 fn reset(&self) {}
73 76
@@ -82,15 +85,11 @@ pub trait DeviceStateHandler {
82 85
83 /// Called when remote wakeup feature is enabled or disabled. 86 /// Called when remote wakeup feature is enabled or disabled.
84 fn remote_wakeup_enabled(&self, _enabled: bool) {} 87 fn remote_wakeup_enabled(&self, _enabled: bool) {}
85
86 /// Called when the USB device has been disabled.
87 fn disabled(&self) {}
88} 88}
89 89
90pub struct UsbDevice<'d, D: Driver<'d>, M: RawMutex = NoopRawMutex> { 90pub struct UsbDevice<'d, D: Driver<'d>> {
91 bus: D::Bus, 91 bus: D::Bus,
92 handler: Option<&'d dyn DeviceStateHandler>, 92 handler: Option<&'d dyn DeviceStateHandler>,
93 commands: Option<&'d Channel<M, DeviceCommand, 1>>,
94 control: ControlPipe<D::ControlPipe>, 93 control: ControlPipe<D::ControlPipe>,
95 94
96 config: Config<'d>, 95 config: Config<'d>,
@@ -101,6 +100,7 @@ pub struct UsbDevice<'d, D: Driver<'d>, M: RawMutex = NoopRawMutex> {
101 100
102 device_state: UsbDeviceState, 101 device_state: UsbDeviceState,
103 suspended: bool, 102 suspended: bool,
103 in_control_handler: bool,
104 remote_wakeup_enabled: bool, 104 remote_wakeup_enabled: bool,
105 self_powered: bool, 105 self_powered: bool,
106 pending_address: u8, 106 pending_address: u8,
@@ -108,18 +108,17 @@ pub struct UsbDevice<'d, D: Driver<'d>, M: RawMutex = NoopRawMutex> {
108 interfaces: Vec<(u8, &'d mut dyn ControlHandler), MAX_INTERFACE_COUNT>, 108 interfaces: Vec<(u8, &'d mut dyn ControlHandler), MAX_INTERFACE_COUNT>,
109} 109}
110 110
111impl<'d, D: Driver<'d>, M: RawMutex> UsbDevice<'d, D, M> { 111impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
112 pub(crate) fn build( 112 pub(crate) fn build(
113 mut driver: D, 113 mut driver: D,
114 config: Config<'d>, 114 config: Config<'d>,
115 handler: Option<&'d dyn DeviceStateHandler>, 115 handler: Option<&'d dyn DeviceStateHandler>,
116 commands: Option<&'d Channel<M, DeviceCommand, 1>>,
117 device_descriptor: &'d [u8], 116 device_descriptor: &'d [u8],
118 config_descriptor: &'d [u8], 117 config_descriptor: &'d [u8],
119 bos_descriptor: &'d [u8], 118 bos_descriptor: &'d [u8],
120 interfaces: Vec<(u8, &'d mut dyn ControlHandler), MAX_INTERFACE_COUNT>, 119 interfaces: Vec<(u8, &'d mut dyn ControlHandler), MAX_INTERFACE_COUNT>,
121 control_buf: &'d mut [u8], 120 control_buf: &'d mut [u8],
122 ) -> UsbDevice<'d, D, M> { 121 ) -> UsbDevice<'d, D> {
123 let control = driver 122 let control = driver
124 .alloc_control_pipe(config.max_packet_size_0 as u16) 123 .alloc_control_pipe(config.max_packet_size_0 as u16)
125 .expect("failed to alloc control endpoint"); 124 .expect("failed to alloc control endpoint");
@@ -132,14 +131,14 @@ impl<'d, D: Driver<'d>, M: RawMutex> UsbDevice<'d, D, M> {
132 bus, 131 bus,
133 config, 132 config,
134 handler, 133 handler,
135 commands,
136 control: ControlPipe::new(control), 134 control: ControlPipe::new(control),
137 device_descriptor, 135 device_descriptor,
138 config_descriptor, 136 config_descriptor,
139 bos_descriptor, 137 bos_descriptor,
140 control_buf, 138 control_buf,
141 device_state: UsbDeviceState::Default, 139 device_state: UsbDeviceState::Disabled,
142 suspended: false, 140 suspended: false,
141 in_control_handler: false,
143 remote_wakeup_enabled: false, 142 remote_wakeup_enabled: false,
144 self_powered: false, 143 self_powered: false,
145 pending_address: 0, 144 pending_address: 0,
@@ -148,19 +147,24 @@ impl<'d, D: Driver<'d>, M: RawMutex> UsbDevice<'d, D, M> {
148 } 147 }
149 148
150 pub async fn run(&mut self) -> ! { 149 pub async fn run(&mut self) -> ! {
151 if self.config.start_enabled { 150 if self.device_state == UsbDeviceState::Disabled {
152 self.bus.enable().await; 151 self.bus.enable().await;
153 } else { 152 self.device_state = UsbDeviceState::Default;
154 self.wait_for_enable().await 153
154 if let Some(h) = &self.handler {
155 h.enabled(true);
156 }
157 } else if self.in_control_handler {
158 warn!("usb: control request interrupted");
159 self.control.reject();
160 self.in_control_handler = false;
155 } 161 }
156 162
157 loop { 163 loop {
158 let control_fut = self.control.setup(); 164 let control_fut = self.control.setup();
159 let bus_fut = self.bus.poll(); 165 let bus_fut = self.bus.poll();
160 let commands_fut = recv_or_wait(self.commands); 166 match select(bus_fut, control_fut).await {
161 167 Either::First(evt) => match evt {
162 match select3(bus_fut, control_fut, commands_fut).await {
163 Either3::First(evt) => match evt {
164 Event::Reset => { 168 Event::Reset => {
165 trace!("usb: reset"); 169 trace!("usb: reset");
166 self.device_state = UsbDeviceState::Default; 170 self.device_state = UsbDeviceState::Default;
@@ -191,54 +195,48 @@ impl<'d, D: Driver<'d>, M: RawMutex> UsbDevice<'d, D, M> {
191 } 195 }
192 } 196 }
193 }, 197 },
194 Either3::Second(req) => match req { 198 Either::Second(req) => {
195 Setup::DataIn(req, stage) => self.handle_control_in(req, stage).await, 199 self.in_control_handler = true;
196 Setup::DataOut(req, stage) => self.handle_control_out(req, stage).await, 200 match req {
197 }, 201 Setup::DataIn(req, stage) => self.handle_control_in(req, stage).await,
198 Either3::Third(cmd) => match cmd { 202 Setup::DataOut(req, stage) => self.handle_control_out(req, stage).await,
199 DeviceCommand::Enable => warn!("usb: Enable command received while enabled."),
200 DeviceCommand::Disable => {
201 trace!("usb: disable");
202 self.bus.disable().await;
203 self.device_state = UsbDeviceState::Disabled;
204 if let Some(h) = &self.handler {
205 h.disabled();
206 }
207 self.wait_for_enable().await;
208 } 203 }
209 DeviceCommand::RemoteWakeup => { 204 self.in_control_handler = false;
210 trace!("usb: remote wakeup"); 205 }
211 if self.suspended && self.remote_wakeup_enabled {
212 match self.bus.remote_wakeup().await {
213 Ok(()) => {
214 self.suspended = false;
215 if let Some(h) = &self.handler {
216 h.suspended(false);
217 }
218 }
219 Err(Unsupported) => warn!("Remote wakeup is unsupported!"),
220 }
221 } else {
222 warn!("Remote wakeup requested when not enabled or not suspended.");
223 }
224 }
225 },
226 } 206 }
227 } 207 }
228 } 208 }
229 209
230 async fn wait_for_enable(&mut self) { 210 pub async fn disable(&mut self) {
231 loop { 211 if self.device_state != UsbDeviceState::Disabled {
232 // When disabled just wait until we're told to re-enable 212 self.bus.disable().await;
233 match recv_or_wait(self.commands).await { 213 self.device_state = UsbDeviceState::Disabled;
234 DeviceCommand::Enable => break, 214 self.suspended = false;
235 cmd => warn!("usb: {:?} received while disabled", cmd), 215 self.remote_wakeup_enabled = false;
216 self.in_control_handler = false;
217
218 if let Some(h) = &self.handler {
219 h.enabled(false);
236 } 220 }
237 } 221 }
222 }
223
224 pub async fn remote_wakeup(&mut self) -> Result<(), RemoteWakeupError> {
225 if self.device_state == UsbDeviceState::Configured
226 && self.suspended
227 && self.remote_wakeup_enabled
228 {
229 self.bus.remote_wakeup().await?;
230 self.suspended = false;
238 231
239 trace!("usb: enable"); 232 if let Some(h) = &self.handler {
240 self.bus.enable().await; 233 h.suspended(false);
241 self.device_state = UsbDeviceState::Default; 234 }
235
236 Ok(())
237 } else {
238 Err(RemoteWakeupError::InvalidState)
239 }
242 } 240 }
243 241
244 async fn handle_control_out(&mut self, req: Request, stage: DataOutStage) { 242 async fn handle_control_out(&mut self, req: Request, stage: DataOutStage) {
diff --git a/embassy-usb/src/util.rs b/embassy-usb/src/util.rs
deleted file mode 100644
index 3f20262c6..000000000
--- a/embassy-usb/src/util.rs
+++ /dev/null
@@ -1,33 +0,0 @@
1use core::future::Future;
2use core::marker::PhantomData;
3use core::pin::Pin;
4use core::task::{Context, Poll};
5
6use embassy::blocking_mutex::raw::RawMutex;
7use embassy::channel::Channel;
8
9pub struct Pending<T> {
10 _phantom: PhantomData<T>,
11}
12
13impl<T> Pending<T> {
14 fn new() -> Self {
15 Pending {
16 _phantom: PhantomData,
17 }
18 }
19}
20
21impl<T> Future for Pending<T> {
22 type Output = T;
23 fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
24 Poll::Pending
25 }
26}
27
28pub async fn recv_or_wait<M: RawMutex, T, const N: usize>(ch: Option<&Channel<M, T, N>>) -> T {
29 match ch {
30 Some(ch) => ch.recv().await,
31 None => Pending::new().await,
32 }
33}
diff --git a/examples/nrf/src/bin/usb_hid_keyboard.rs b/examples/nrf/src/bin/usb_hid_keyboard.rs
index fb3a198a7..32659dfbb 100644
--- a/examples/nrf/src/bin/usb_hid_keyboard.rs
+++ b/examples/nrf/src/bin/usb_hid_keyboard.rs
@@ -11,13 +11,14 @@ use embassy::channel::Channel;
11use embassy::executor::Spawner; 11use embassy::executor::Spawner;
12use embassy::interrupt::InterruptExt; 12use embassy::interrupt::InterruptExt;
13use embassy::time::Duration; 13use embassy::time::Duration;
14use embassy::util::select;
14use embassy_nrf::gpio::{Input, Pin, Pull}; 15use embassy_nrf::gpio::{Input, Pin, Pull};
15use embassy_nrf::interrupt; 16use embassy_nrf::interrupt;
16use embassy_nrf::pac; 17use embassy_nrf::pac;
17use embassy_nrf::usb::Driver; 18use embassy_nrf::usb::Driver;
18use embassy_nrf::Peripherals; 19use embassy_nrf::Peripherals;
19use embassy_usb::control::OutResponse; 20use embassy_usb::control::OutResponse;
20use embassy_usb::{Config, DeviceCommand, DeviceStateHandler, UsbDeviceBuilder}; 21use embassy_usb::{Config, DeviceStateHandler, UsbDeviceBuilder};
21use embassy_usb_hid::{HidClass, ReportId, RequestHandler, State}; 22use embassy_usb_hid::{HidClass, ReportId, RequestHandler, State};
22use futures::future::join; 23use futures::future::join;
23use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; 24use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor};
@@ -25,7 +26,14 @@ use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor};
25use defmt_rtt as _; // global logger 26use defmt_rtt as _; // global logger
26use panic_probe as _; 27use panic_probe as _;
27 28
28static USB_COMMANDS: Channel<CriticalSectionRawMutex, DeviceCommand, 1> = Channel::new(); 29#[derive(defmt::Format)]
30enum Command {
31 Enable,
32 Disable,
33 RemoteWakeup,
34}
35
36static USB_COMMANDS: Channel<CriticalSectionRawMutex, Command, 1> = Channel::new();
29static SUSPENDED: AtomicBool = AtomicBool::new(false); 37static SUSPENDED: AtomicBool = AtomicBool::new(false);
30 38
31fn on_power_interrupt(_: *mut ()) { 39fn on_power_interrupt(_: *mut ()) {
@@ -34,7 +42,7 @@ fn on_power_interrupt(_: *mut ()) {
34 if regs.events_usbdetected.read().bits() != 0 { 42 if regs.events_usbdetected.read().bits() != 0 {
35 regs.events_usbdetected.reset(); 43 regs.events_usbdetected.reset();
36 info!("Vbus detected, enabling USB..."); 44 info!("Vbus detected, enabling USB...");
37 if USB_COMMANDS.try_send(DeviceCommand::Enable).is_err() { 45 if USB_COMMANDS.try_send(Command::Enable).is_err() {
38 warn!("Failed to send enable command to USB channel"); 46 warn!("Failed to send enable command to USB channel");
39 } 47 }
40 } 48 }
@@ -42,7 +50,7 @@ fn on_power_interrupt(_: *mut ()) {
42 if regs.events_usbremoved.read().bits() != 0 { 50 if regs.events_usbremoved.read().bits() != 0 {
43 regs.events_usbremoved.reset(); 51 regs.events_usbremoved.reset();
44 info!("Vbus removed, disabling USB..."); 52 info!("Vbus removed, disabling USB...");
45 if USB_COMMANDS.try_send(DeviceCommand::Disable).is_err() { 53 if USB_COMMANDS.try_send(Command::Disable).is_err() {
46 warn!("Failed to send disable command to USB channel"); 54 warn!("Failed to send disable command to USB channel");
47 }; 55 };
48 } 56 }
@@ -69,7 +77,6 @@ async fn main(_spawner: Spawner, p: Peripherals) {
69 config.max_power = 100; 77 config.max_power = 100;
70 config.max_packet_size_0 = 64; 78 config.max_packet_size_0 = 64;
71 config.supports_remote_wakeup = true; 79 config.supports_remote_wakeup = true;
72 config.start_enabled = false;
73 80
74 // Create embassy-usb DeviceBuilder using the driver and config. 81 // Create embassy-usb DeviceBuilder using the driver and config.
75 // It needs some buffers for building the descriptors. 82 // It needs some buffers for building the descriptors.
@@ -82,7 +89,7 @@ async fn main(_spawner: Spawner, p: Peripherals) {
82 89
83 let mut state = State::<8, 1>::new(); 90 let mut state = State::<8, 1>::new();
84 91
85 let mut builder = UsbDeviceBuilder::new_with_channel( 92 let mut builder = UsbDeviceBuilder::new(
86 driver, 93 driver,
87 config, 94 config,
88 &mut device_descriptor, 95 &mut device_descriptor,
@@ -90,7 +97,6 @@ async fn main(_spawner: Spawner, p: Peripherals) {
90 &mut bos_descriptor, 97 &mut bos_descriptor,
91 &mut control_buf, 98 &mut control_buf,
92 Some(&device_state_handler), 99 Some(&device_state_handler),
93 &USB_COMMANDS,
94 ); 100 );
95 101
96 // Create classes on the builder. 102 // Create classes on the builder.
@@ -107,7 +113,22 @@ async fn main(_spawner: Spawner, p: Peripherals) {
107 let mut usb = builder.build(); 113 let mut usb = builder.build();
108 114
109 // Run the USB device. 115 // Run the USB device.
110 let usb_fut = usb.run(); 116 let usb_fut = async {
117 enable_command().await;
118 loop {
119 match select(usb.run(), USB_COMMANDS.recv()).await {
120 embassy::util::Either::First(_) => defmt::unreachable!(),
121 embassy::util::Either::Second(cmd) => match cmd {
122 Command::Enable => warn!("Enable when already enabled!"),
123 Command::Disable => {
124 usb.disable().await;
125 enable_command().await;
126 }
127 Command::RemoteWakeup => unwrap!(usb.remote_wakeup().await),
128 },
129 }
130 }
131 };
111 132
112 let mut button = Input::new(p.P0_11.degrade(), Pull::Up); 133 let mut button = Input::new(p.P0_11.degrade(), Pull::Up);
113 134
@@ -121,7 +142,7 @@ async fn main(_spawner: Spawner, p: Peripherals) {
121 142
122 if SUSPENDED.load(Ordering::Acquire) { 143 if SUSPENDED.load(Ordering::Acquire) {
123 info!("Triggering remote wakeup"); 144 info!("Triggering remote wakeup");
124 USB_COMMANDS.send(DeviceCommand::RemoteWakeup).await; 145 USB_COMMANDS.send(Command::RemoteWakeup).await;
125 } else { 146 } else {
126 let report = KeyboardReport { 147 let report = KeyboardReport {
127 keycodes: [4, 0, 0, 0, 0, 0], 148 keycodes: [4, 0, 0, 0, 0, 0],
@@ -168,6 +189,15 @@ async fn main(_spawner: Spawner, p: Peripherals) {
168 join(usb_fut, join(in_fut, out_fut)).await; 189 join(usb_fut, join(in_fut, out_fut)).await;
169} 190}
170 191
192async fn enable_command() {
193 loop {
194 match USB_COMMANDS.recv().await {
195 Command::Enable => break,
196 cmd => warn!("Received command {:?} when disabled!", cmd),
197 }
198 }
199}
200
171struct MyRequestHandler {} 201struct MyRequestHandler {}
172 202
173impl RequestHandler for MyRequestHandler { 203impl RequestHandler for MyRequestHandler {
@@ -204,6 +234,16 @@ impl MyDeviceStateHandler {
204} 234}
205 235
206impl DeviceStateHandler for MyDeviceStateHandler { 236impl DeviceStateHandler for MyDeviceStateHandler {
237 fn enabled(&self, enabled: bool) {
238 self.configured.store(false, Ordering::Relaxed);
239 SUSPENDED.store(false, Ordering::Release);
240 if enabled {
241 info!("Device enabled");
242 } else {
243 info!("Device disabled");
244 }
245 }
246
207 fn reset(&self) { 247 fn reset(&self) {
208 self.configured.store(false, Ordering::Relaxed); 248 self.configured.store(false, Ordering::Relaxed);
209 info!("Bus reset, the Vbus current limit is 100mA"); 249 info!("Bus reset, the Vbus current limit is 100mA");
@@ -240,9 +280,4 @@ impl DeviceStateHandler for MyDeviceStateHandler {
240 } 280 }
241 } 281 }
242 } 282 }
243
244 fn disabled(&self) {
245 self.configured.store(false, Ordering::Relaxed);
246 info!("Device disabled");
247 }
248} 283}