diff options
| author | huntc <[email protected]> | 2022-06-16 16:08:58 +1000 |
|---|---|---|
| committer | huntc <[email protected]> | 2022-07-07 10:08:57 +1000 |
| commit | 4a8f117f2520df9d1919cbbac3d2840ea1539e04 (patch) | |
| tree | 37312b498d3bce9e05a906a88e290063e4d610ca /embassy-usb | |
| parent | c46e9b6cfc1375f5e5e2bade8eb2174cc47c4a28 (diff) | |
Puts in the machinery to handle power detected/removed
Diffstat (limited to 'embassy-usb')
| -rw-r--r-- | embassy-usb/src/driver.rs | 6 | ||||
| -rw-r--r-- | embassy-usb/src/lib.rs | 20 | ||||
| -rw-r--r-- | embassy-usb/src/util.rs | 68 |
3 files changed, 23 insertions, 71 deletions
diff --git a/embassy-usb/src/driver.rs b/embassy-usb/src/driver.rs index bfe44d627..2a84ff9e7 100644 --- a/embassy-usb/src/driver.rs +++ b/embassy-usb/src/driver.rs | |||
| @@ -202,6 +202,12 @@ pub enum Event { | |||
| 202 | /// A USB resume request has been detected after being suspended or, in the case of self-powered | 202 | /// A USB resume request has been detected after being suspended or, in the case of self-powered |
| 203 | /// devices, the device has been connected to the USB bus. | 203 | /// devices, the device has been connected to the USB bus. |
| 204 | Resume, | 204 | Resume, |
| 205 | |||
| 206 | /// The USB power has been detected. | ||
| 207 | PowerDetected, | ||
| 208 | |||
| 209 | /// The USB power has been removed. Not supported by all devices. | ||
| 210 | PowerRemoved, | ||
| 205 | } | 211 | } |
| 206 | 212 | ||
| 207 | #[derive(Copy, Clone, Eq, PartialEq, Debug)] | 213 | #[derive(Copy, Clone, Eq, PartialEq, Debug)] |
diff --git a/embassy-usb/src/lib.rs b/embassy-usb/src/lib.rs index eba46b892..af102e589 100644 --- a/embassy-usb/src/lib.rs +++ b/embassy-usb/src/lib.rs | |||
| @@ -11,7 +11,6 @@ pub mod descriptor; | |||
| 11 | mod descriptor_reader; | 11 | mod descriptor_reader; |
| 12 | pub mod driver; | 12 | pub mod driver; |
| 13 | pub mod types; | 13 | pub mod types; |
| 14 | pub mod util; | ||
| 15 | 14 | ||
| 16 | use embassy::util::{select, Either}; | 15 | use embassy::util::{select, Either}; |
| 17 | use heapless::Vec; | 16 | use heapless::Vec; |
| @@ -115,6 +114,7 @@ struct Inner<'d, D: Driver<'d>> { | |||
| 115 | 114 | ||
| 116 | device_state: UsbDeviceState, | 115 | device_state: UsbDeviceState, |
| 117 | suspended: bool, | 116 | suspended: bool, |
| 117 | power_available: bool, | ||
| 118 | remote_wakeup_enabled: bool, | 118 | remote_wakeup_enabled: bool, |
| 119 | self_powered: bool, | 119 | self_powered: bool, |
| 120 | 120 | ||
| @@ -157,6 +157,7 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> { | |||
| 157 | 157 | ||
| 158 | device_state: UsbDeviceState::Disabled, | 158 | device_state: UsbDeviceState::Disabled, |
| 159 | suspended: false, | 159 | suspended: false, |
| 160 | power_available: false, | ||
| 160 | remote_wakeup_enabled: false, | 161 | remote_wakeup_enabled: false, |
| 161 | self_powered: false, | 162 | self_powered: false, |
| 162 | address: 0, | 163 | address: 0, |
| @@ -186,6 +187,11 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> { | |||
| 186 | /// before calling any other `UsbDevice` methods to fully reset the | 187 | /// before calling any other `UsbDevice` methods to fully reset the |
| 187 | /// peripheral. | 188 | /// peripheral. |
| 188 | pub async fn run_until_suspend(&mut self) -> () { | 189 | pub async fn run_until_suspend(&mut self) -> () { |
| 190 | while !self.inner.power_available { | ||
| 191 | let evt = self.inner.bus.poll().await; | ||
| 192 | self.inner.handle_bus_event(evt); | ||
| 193 | } | ||
| 194 | |||
| 189 | if self.inner.device_state == UsbDeviceState::Disabled { | 195 | if self.inner.device_state == UsbDeviceState::Disabled { |
| 190 | self.inner.bus.enable().await; | 196 | self.inner.bus.enable().await; |
| 191 | self.inner.device_state = UsbDeviceState::Default; | 197 | self.inner.device_state = UsbDeviceState::Default; |
| @@ -195,7 +201,7 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> { | |||
| 195 | } | 201 | } |
| 196 | } | 202 | } |
| 197 | 203 | ||
| 198 | while !self.inner.suspended { | 204 | while !self.inner.suspended && self.inner.power_available { |
| 199 | let control_fut = self.control.setup(); | 205 | let control_fut = self.control.setup(); |
| 200 | let bus_fut = self.inner.bus.poll(); | 206 | let bus_fut = self.inner.bus.poll(); |
| 201 | match select(bus_fut, control_fut).await { | 207 | match select(bus_fut, control_fut).await { |
| @@ -223,7 +229,7 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> { | |||
| 223 | /// | 229 | /// |
| 224 | /// This future is cancel-safe. | 230 | /// This future is cancel-safe. |
| 225 | pub async fn wait_resume(&mut self) { | 231 | pub async fn wait_resume(&mut self) { |
| 226 | while self.inner.suspended { | 232 | while self.inner.suspended || !self.inner.power_available { |
| 227 | let evt = self.inner.bus.poll().await; | 233 | let evt = self.inner.bus.poll().await; |
| 228 | self.inner.handle_bus_event(evt); | 234 | self.inner.handle_bus_event(evt); |
| 229 | } | 235 | } |
| @@ -377,6 +383,14 @@ impl<'d, D: Driver<'d>> Inner<'d, D> { | |||
| 377 | h.suspended(true); | 383 | h.suspended(true); |
| 378 | } | 384 | } |
| 379 | } | 385 | } |
| 386 | Event::PowerDetected => { | ||
| 387 | trace!("usb: power detected"); | ||
| 388 | self.power_available = true; | ||
| 389 | } | ||
| 390 | Event::PowerRemoved => { | ||
| 391 | trace!("usb: power removed"); | ||
| 392 | self.power_available = false; | ||
| 393 | } | ||
| 380 | } | 394 | } |
| 381 | } | 395 | } |
| 382 | 396 | ||
diff --git a/embassy-usb/src/util.rs b/embassy-usb/src/util.rs deleted file mode 100644 index ac56691b8..000000000 --- a/embassy-usb/src/util.rs +++ /dev/null | |||
| @@ -1,68 +0,0 @@ | |||
| 1 | use embassy::channel::signal::Signal; | ||
| 2 | use embassy::util::{select, Either}; | ||
| 3 | |||
| 4 | use crate::driver::Driver; | ||
| 5 | use crate::UsbDevice; | ||
| 6 | |||
| 7 | /// Am enabled usb device is a device that further receives external notifications | ||
| 8 | /// regarding whether it is enabled or not. A common example of where this is | ||
| 9 | /// required is when receiving notifications from the POWER peripheral that | ||
| 10 | /// USB has been connected to or removed. The device here wraps an existing | ||
| 11 | /// USB device, keeping it publically available so that device-oriented operations | ||
| 12 | /// may still be performed. A signal is also provided that enables/disables the | ||
| 13 | /// USB device, taking care of suspension and resumption. In the case of the POWER | ||
| 14 | /// peripheral, this signal can be used from within a POWER_CLOCK interrupt | ||
| 15 | /// handler. Alternatively, for softdevice usage where the POWER peripheral is not | ||
| 16 | /// available, similar USB power events can be leveraged. | ||
| 17 | pub struct EnabledUsbDevice<'d, D: Driver<'d>> { | ||
| 18 | pub underlying: UsbDevice<'d, D>, | ||
| 19 | enable_usb_signal: &'d Signal<bool>, | ||
| 20 | } | ||
| 21 | |||
| 22 | impl<'d, D: Driver<'d>> EnabledUsbDevice<'d, D> { | ||
| 23 | /// Wrap an existing UsbDevice and take a signal that will be used | ||
| 24 | /// to enable/disable it, perhaps from an external POWER_CLOCK | ||
| 25 | /// interrupt, or the equivalent when dealing with softdevices. | ||
| 26 | pub fn new(underlying: UsbDevice<'d, D>, enable_usb_signal: &'d Signal<bool>) -> Self { | ||
| 27 | Self { | ||
| 28 | underlying, | ||
| 29 | enable_usb_signal, | ||
| 30 | } | ||
| 31 | } | ||
| 32 | |||
| 33 | /// Runs the underlying `UsbDevice` taking care of reacting to USB becoming | ||
| 34 | /// enabled/disabled. | ||
| 35 | /// | ||
| 36 | /// This future may leave the bus in an invalid state if it is dropped. | ||
| 37 | /// After dropping the future, [`UsbDevice::disable()`] should be called | ||
| 38 | /// before calling any other `UsbDevice` methods to fully reset the | ||
| 39 | /// peripheral. | ||
| 40 | pub async fn run(&mut self) -> ! { | ||
| 41 | while !self.enable_usb_signal.wait().await {} | ||
| 42 | loop { | ||
| 43 | match select( | ||
| 44 | self.underlying.run_until_suspend(), | ||
| 45 | self.enable_usb_signal.wait(), | ||
| 46 | ) | ||
| 47 | .await | ||
| 48 | { | ||
| 49 | Either::First(_) => {} | ||
| 50 | Either::Second(enable) => { | ||
| 51 | if !enable { | ||
| 52 | self.underlying.disable().await; | ||
| 53 | while !self.enable_usb_signal.wait().await {} | ||
| 54 | } | ||
| 55 | } | ||
| 56 | } | ||
| 57 | match select(self.underlying.wait_resume(), self.enable_usb_signal.wait()).await { | ||
| 58 | Either::First(_) => {} | ||
| 59 | Either::Second(enable) => { | ||
| 60 | if !enable { | ||
| 61 | self.underlying.disable().await; | ||
| 62 | while !self.enable_usb_signal.wait().await {} | ||
| 63 | } | ||
| 64 | } | ||
| 65 | } | ||
| 66 | } | ||
| 67 | } | ||
| 68 | } | ||
