diff options
| author | alexmoon <[email protected]> | 2022-04-13 13:09:08 -0400 |
|---|---|---|
| committer | alexmoon <[email protected]> | 2022-04-13 14:55:02 -0400 |
| commit | ff7c6b350e2338a0b1e4327f4b2eb0435468f313 (patch) | |
| tree | 1a045db7348d2562b9c8a19299467a30b62e501e | |
| parent | 1d875fab2dc9d765ebf9f4b37112581301f2ed7e (diff) | |
Remove channel and make run future cancelable
| -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 | 71 | ||||
| -rw-r--r-- | embassy-usb/src/lib.rs | 140 | ||||
| -rw-r--r-- | embassy-usb/src/util.rs | 33 | ||||
| -rw-r--r-- | examples/nrf/src/bin/usb_hid_keyboard.rs | 63 |
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; | |||
| 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; | ||
| 15 | use embassy::time::Duration; | 14 | use embassy::time::Duration; |
| 16 | use embassy_usb::driver::EndpointOut; | 15 | use embassy_usb::driver::EndpointOut; |
| 17 | use embassy_usb::{ | 16 | use 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; | |||
| 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; | ||
| 12 | use embassy::blocking_mutex::CriticalSectionMutex; | 11 | use embassy::blocking_mutex::CriticalSectionMutex; |
| 13 | use embassy_usb::control::{self, ControlHandler, InResponse, OutResponse, Request}; | 12 | use embassy_usb::control::{self, ControlHandler, InResponse, OutResponse, Request}; |
| 14 | use embassy_usb::driver::{Endpoint, EndpointError, EndpointIn, EndpointOut}; | 13 | use embassy_usb::driver::{Endpoint, EndpointError, EndpointIn, EndpointOut}; |
| @@ -163,8 +162,8 @@ impl<'d> ControlHandler for Control<'d> { | |||
| 163 | impl<'d, D: Driver<'d>> CdcAcmClass<'d, D> { | 162 | impl<'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 @@ | |||
| 1 | use embassy::blocking_mutex::raw::{NoopRawMutex, RawMutex}; | ||
| 2 | use embassy::channel::Channel; | ||
| 3 | use heapless::Vec; | 1 | use heapless::Vec; |
| 4 | 2 | ||
| 5 | use crate::DeviceCommand; | ||
| 6 | |||
| 7 | use super::control::ControlHandler; | 3 | use super::control::ControlHandler; |
| 8 | use super::descriptor::{BosWriter, DescriptorWriter}; | 4 | use super::descriptor::{BosWriter, DescriptorWriter}; |
| 9 | use super::driver::{Driver, EndpointAllocError}; | 5 | use 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 | ||
| 108 | impl<'a> Config<'a> { | 99 | impl<'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. |
| 131 | pub struct UsbDeviceBuilder<'d, D: Driver<'d>, M: RawMutex> { | 121 | pub 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 | ||
| 148 | impl<'d, D: Driver<'d>> UsbDeviceBuilder<'d, D, NoopRawMutex> { | 137 | impl<'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 | |||
| 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>>, | ||
| 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; | |||
| 10 | pub mod descriptor; | 10 | pub mod descriptor; |
| 11 | pub mod driver; | 11 | pub mod driver; |
| 12 | pub mod types; | 12 | pub mod types; |
| 13 | mod util; | ||
| 14 | 13 | ||
| 15 | use driver::Unsupported; | 14 | use embassy::util::{select, Either}; |
| 16 | use embassy::blocking_mutex::raw::{NoopRawMutex, RawMutex}; | ||
| 17 | use embassy::channel::Channel; | ||
| 18 | use embassy::util::{select3, Either3}; | ||
| 19 | use heapless::Vec; | 15 | use heapless::Vec; |
| 20 | 16 | ||
| 21 | use self::control::*; | 17 | use self::control::*; |
| 22 | use self::descriptor::*; | 18 | use self::descriptor::*; |
| 23 | use self::driver::{Bus, Driver, Event}; | 19 | use self::driver::{Bus, Driver, Event}; |
| 24 | use self::types::*; | 20 | use self::types::*; |
| 25 | use self::util::*; | ||
| 26 | 21 | ||
| 27 | pub use self::builder::Config; | 22 | pub use self::builder::Config; |
| 28 | pub use self::builder::UsbDeviceBuilder; | 23 | pub 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))] | ||
| 47 | pub enum RemoteWakeupError { | ||
| 48 | InvalidState, | ||
| 49 | Unsupported, | ||
| 50 | } | ||
| 51 | |||
| 52 | impl From<driver::Unsupported> for RemoteWakeupError { | ||
| 53 | fn from(_: driver::Unsupported) -> Self { | ||
| 54 | RemoteWakeupError::Unsupported | ||
| 55 | } | ||
| 56 | } | ||
| 57 | |||
| 50 | /// The bConfiguration value for the not configured state. | 58 | /// The bConfiguration value for the not configured state. |
| 51 | pub const CONFIGURATION_NONE: u8 = 0; | 59 | pub const CONFIGURATION_NONE: u8 = 0; |
| 52 | 60 | ||
| @@ -58,16 +66,11 @@ pub const DEFAULT_ALTERNATE_SETTING: u8 = 0; | |||
| 58 | 66 | ||
| 59 | pub const MAX_INTERFACE_COUNT: usize = 4; | 67 | pub const MAX_INTERFACE_COUNT: usize = 4; |
| 60 | 68 | ||
| 61 | #[derive(PartialEq, Eq, Copy, Clone, Debug)] | ||
| 62 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 63 | pub 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]. |
| 70 | pub trait DeviceStateHandler { | 70 | pub 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 | ||
| 90 | pub struct UsbDevice<'d, D: Driver<'d>, M: RawMutex = NoopRawMutex> { | 90 | pub 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 | ||
| 111 | impl<'d, D: Driver<'d>, M: RawMutex> UsbDevice<'d, D, M> { | 111 | impl<'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 @@ | |||
| 1 | use core::future::Future; | ||
| 2 | use core::marker::PhantomData; | ||
| 3 | use core::pin::Pin; | ||
| 4 | use core::task::{Context, Poll}; | ||
| 5 | |||
| 6 | use embassy::blocking_mutex::raw::RawMutex; | ||
| 7 | use embassy::channel::Channel; | ||
| 8 | |||
| 9 | pub struct Pending<T> { | ||
| 10 | _phantom: PhantomData<T>, | ||
| 11 | } | ||
| 12 | |||
| 13 | impl<T> Pending<T> { | ||
| 14 | fn new() -> Self { | ||
| 15 | Pending { | ||
| 16 | _phantom: PhantomData, | ||
| 17 | } | ||
| 18 | } | ||
| 19 | } | ||
| 20 | |||
| 21 | impl<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 | |||
| 28 | pub 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; | |||
| 11 | use embassy::executor::Spawner; | 11 | use embassy::executor::Spawner; |
| 12 | use embassy::interrupt::InterruptExt; | 12 | use embassy::interrupt::InterruptExt; |
| 13 | use embassy::time::Duration; | 13 | use embassy::time::Duration; |
| 14 | use embassy::util::select; | ||
| 14 | use embassy_nrf::gpio::{Input, Pin, Pull}; | 15 | use embassy_nrf::gpio::{Input, Pin, Pull}; |
| 15 | use embassy_nrf::interrupt; | 16 | use embassy_nrf::interrupt; |
| 16 | use embassy_nrf::pac; | 17 | use embassy_nrf::pac; |
| 17 | use embassy_nrf::usb::Driver; | 18 | use embassy_nrf::usb::Driver; |
| 18 | use embassy_nrf::Peripherals; | 19 | use embassy_nrf::Peripherals; |
| 19 | use embassy_usb::control::OutResponse; | 20 | use embassy_usb::control::OutResponse; |
| 20 | use embassy_usb::{Config, DeviceCommand, DeviceStateHandler, UsbDeviceBuilder}; | 21 | use embassy_usb::{Config, DeviceStateHandler, UsbDeviceBuilder}; |
| 21 | use embassy_usb_hid::{HidClass, ReportId, RequestHandler, State}; | 22 | use embassy_usb_hid::{HidClass, ReportId, RequestHandler, State}; |
| 22 | use futures::future::join; | 23 | use futures::future::join; |
| 23 | use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; | 24 | use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; |
| @@ -25,7 +26,14 @@ use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; | |||
| 25 | use defmt_rtt as _; // global logger | 26 | use defmt_rtt as _; // global logger |
| 26 | use panic_probe as _; | 27 | use panic_probe as _; |
| 27 | 28 | ||
| 28 | static USB_COMMANDS: Channel<CriticalSectionRawMutex, DeviceCommand, 1> = Channel::new(); | 29 | #[derive(defmt::Format)] |
| 30 | enum Command { | ||
| 31 | Enable, | ||
| 32 | Disable, | ||
| 33 | RemoteWakeup, | ||
| 34 | } | ||
| 35 | |||
| 36 | static USB_COMMANDS: Channel<CriticalSectionRawMutex, Command, 1> = Channel::new(); | ||
| 29 | static SUSPENDED: AtomicBool = AtomicBool::new(false); | 37 | static SUSPENDED: AtomicBool = AtomicBool::new(false); |
| 30 | 38 | ||
| 31 | fn on_power_interrupt(_: *mut ()) { | 39 | fn 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 | ||
| 192 | async 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 | |||
| 171 | struct MyRequestHandler {} | 201 | struct MyRequestHandler {} |
| 172 | 202 | ||
| 173 | impl RequestHandler for MyRequestHandler { | 203 | impl RequestHandler for MyRequestHandler { |
| @@ -204,6 +234,16 @@ impl MyDeviceStateHandler { | |||
| 204 | } | 234 | } |
| 205 | 235 | ||
| 206 | impl DeviceStateHandler for MyDeviceStateHandler { | 236 | impl 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 | } |
