diff options
| -rw-r--r-- | embassy-nrf/src/usb.rs | 209 | ||||
| -rw-r--r-- | embassy-usb/Cargo.toml | 2 | ||||
| -rw-r--r-- | embassy-usb/src/driver.rs | 87 | ||||
| -rw-r--r-- | embassy-usb/src/lib.rs | 64 | ||||
| -rw-r--r-- | embassy-usb/src/util.rs | 45 | ||||
| -rw-r--r-- | examples/nrf/src/bin/usb/cdc_acm.rs | 17 | ||||
| -rw-r--r-- | examples/nrf/src/bin/usb/main.rs | 15 |
7 files changed, 345 insertions, 94 deletions
diff --git a/embassy-nrf/src/usb.rs b/embassy-nrf/src/usb.rs index 0f7d68d8c..163b2c794 100644 --- a/embassy-nrf/src/usb.rs +++ b/embassy-nrf/src/usb.rs | |||
| @@ -8,7 +8,7 @@ use embassy::time::{with_timeout, Duration}; | |||
| 8 | use embassy::util::Unborrow; | 8 | use embassy::util::Unborrow; |
| 9 | use embassy::waitqueue::AtomicWaker; | 9 | use embassy::waitqueue::AtomicWaker; |
| 10 | use embassy_hal_common::unborrow; | 10 | use embassy_hal_common::unborrow; |
| 11 | use embassy_usb::driver::{self, ReadError, WriteError}; | 11 | use embassy_usb::driver::{self, Event, ReadError, WriteError}; |
| 12 | use embassy_usb::types::{EndpointAddress, EndpointInfo, EndpointType, UsbDirection}; | 12 | use embassy_usb::types::{EndpointAddress, EndpointInfo, EndpointType, UsbDirection}; |
| 13 | use futures::future::poll_fn; | 13 | use futures::future::poll_fn; |
| 14 | use futures::Future; | 14 | use futures::Future; |
| @@ -19,7 +19,10 @@ pub use embassy_usb; | |||
| 19 | use crate::interrupt::Interrupt; | 19 | use crate::interrupt::Interrupt; |
| 20 | use crate::pac; | 20 | use crate::pac; |
| 21 | 21 | ||
| 22 | static EP0_WAKER: AtomicWaker = AtomicWaker::new(); | 22 | const NEW_AW: AtomicWaker = AtomicWaker::new(); |
| 23 | static BUS_WAKER: AtomicWaker = NEW_AW; | ||
| 24 | static EP_IN_WAKERS: [AtomicWaker; 9] = [NEW_AW; 9]; | ||
| 25 | static EP_OUT_WAKERS: [AtomicWaker; 9] = [NEW_AW; 9]; | ||
| 23 | 26 | ||
| 24 | pub struct Driver<'d, T: Instance> { | 27 | pub struct Driver<'d, T: Instance> { |
| 25 | phantom: PhantomData<&'d mut T>, | 28 | phantom: PhantomData<&'d mut T>, |
| @@ -47,13 +50,48 @@ impl<'d, T: Instance> Driver<'d, T> { | |||
| 47 | fn on_interrupt(_: *mut ()) { | 50 | fn on_interrupt(_: *mut ()) { |
| 48 | let regs = T::regs(); | 51 | let regs = T::regs(); |
| 49 | 52 | ||
| 53 | if regs.events_usbreset.read().bits() != 0 { | ||
| 54 | regs.intenclr.write(|w| w.usbreset().clear()); | ||
| 55 | BUS_WAKER.wake(); | ||
| 56 | } | ||
| 57 | |||
| 50 | if regs.events_ep0setup.read().bits() != 0 { | 58 | if regs.events_ep0setup.read().bits() != 0 { |
| 51 | regs.intenclr.write(|w| w.ep0setup().clear()); | 59 | regs.intenclr.write(|w| w.ep0setup().clear()); |
| 52 | EP0_WAKER.wake(); | 60 | EP_OUT_WAKERS[0].wake(); |
| 53 | } | 61 | } |
| 62 | |||
| 54 | if regs.events_ep0datadone.read().bits() != 0 { | 63 | if regs.events_ep0datadone.read().bits() != 0 { |
| 55 | regs.intenclr.write(|w| w.ep0datadone().clear()); | 64 | regs.intenclr.write(|w| w.ep0datadone().clear()); |
| 56 | EP0_WAKER.wake(); | 65 | EP_IN_WAKERS[0].wake(); |
| 66 | } | ||
| 67 | |||
| 68 | // USBEVENT and EPDATA events are weird. They're the "aggregate" | ||
| 69 | // of individual bits in EVENTCAUSE and EPDATASTATUS. We handle them | ||
| 70 | // differently than events normally. | ||
| 71 | // | ||
| 72 | // They seem to be edge-triggered, not level-triggered: when an | ||
| 73 | // individual bit goes 0->1, the event fires *just once*. | ||
| 74 | // Therefore, it's fine to clear just the event, and let main thread | ||
| 75 | // check the individual bits in EVENTCAUSE and EPDATASTATUS. It | ||
| 76 | // doesn't cause an infinite irq loop. | ||
| 77 | if regs.events_usbevent.read().bits() != 0 { | ||
| 78 | regs.events_usbevent.reset(); | ||
| 79 | //regs.intenclr.write(|w| w.usbevent().clear()); | ||
| 80 | BUS_WAKER.wake(); | ||
| 81 | } | ||
| 82 | |||
| 83 | if regs.events_epdata.read().bits() != 0 { | ||
| 84 | regs.events_epdata.reset(); | ||
| 85 | |||
| 86 | let r = regs.epdatastatus.read().bits(); | ||
| 87 | for i in 1..=7 { | ||
| 88 | if r & (1 << i) != 0 { | ||
| 89 | EP_IN_WAKERS[i].wake(); | ||
| 90 | } | ||
| 91 | if r & (1 << (i + 16)) != 0 { | ||
| 92 | EP_OUT_WAKERS[i].wake(); | ||
| 93 | } | ||
| 94 | } | ||
| 57 | } | 95 | } |
| 58 | } | 96 | } |
| 59 | 97 | ||
| @@ -153,6 +191,12 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> { | |||
| 153 | 191 | ||
| 154 | unsafe { NVIC::unmask(pac::Interrupt::USBD) }; | 192 | unsafe { NVIC::unmask(pac::Interrupt::USBD) }; |
| 155 | 193 | ||
| 194 | regs.intenset.write(|w| { | ||
| 195 | w.usbreset().set_bit(); | ||
| 196 | w.usbevent().set_bit(); | ||
| 197 | w.epdata().set_bit(); | ||
| 198 | w | ||
| 199 | }); | ||
| 156 | // Enable the USB pullup, allowing enumeration. | 200 | // Enable the USB pullup, allowing enumeration. |
| 157 | regs.usbpullup.write(|w| w.connect().enabled()); | 201 | regs.usbpullup.write(|w| w.connect().enabled()); |
| 158 | info!("enabled"); | 202 | info!("enabled"); |
| @@ -172,6 +216,49 @@ pub struct Bus<'d, T: Instance> { | |||
| 172 | } | 216 | } |
| 173 | 217 | ||
| 174 | impl<'d, T: Instance> driver::Bus for Bus<'d, T> { | 218 | impl<'d, T: Instance> driver::Bus for Bus<'d, T> { |
| 219 | type PollFuture<'a> | ||
| 220 | where | ||
| 221 | Self: 'a, | ||
| 222 | = impl Future<Output = Event> + 'a; | ||
| 223 | |||
| 224 | fn poll<'a>(&'a mut self) -> Self::PollFuture<'a> { | ||
| 225 | poll_fn(|cx| { | ||
| 226 | BUS_WAKER.register(cx.waker()); | ||
| 227 | let regs = T::regs(); | ||
| 228 | |||
| 229 | if regs.events_usbreset.read().bits() != 0 { | ||
| 230 | regs.events_usbreset.reset(); | ||
| 231 | regs.intenset.write(|w| w.usbreset().set()); | ||
| 232 | return Poll::Ready(Event::Reset); | ||
| 233 | } | ||
| 234 | |||
| 235 | let r = regs.eventcause.read(); | ||
| 236 | |||
| 237 | if r.isooutcrc().bit() { | ||
| 238 | regs.eventcause.write(|w| w.isooutcrc().set_bit()); | ||
| 239 | info!("USB event: isooutcrc"); | ||
| 240 | } | ||
| 241 | if r.usbwuallowed().bit() { | ||
| 242 | regs.eventcause.write(|w| w.usbwuallowed().set_bit()); | ||
| 243 | info!("USB event: usbwuallowed"); | ||
| 244 | } | ||
| 245 | if r.suspend().bit() { | ||
| 246 | regs.eventcause.write(|w| w.suspend().set_bit()); | ||
| 247 | info!("USB event: suspend"); | ||
| 248 | } | ||
| 249 | if r.resume().bit() { | ||
| 250 | regs.eventcause.write(|w| w.resume().set_bit()); | ||
| 251 | info!("USB event: resume"); | ||
| 252 | } | ||
| 253 | if r.ready().bit() { | ||
| 254 | regs.eventcause.write(|w| w.ready().set_bit()); | ||
| 255 | info!("USB event: ready"); | ||
| 256 | } | ||
| 257 | |||
| 258 | Poll::Pending | ||
| 259 | }) | ||
| 260 | } | ||
| 261 | |||
| 175 | #[inline] | 262 | #[inline] |
| 176 | fn reset(&mut self) { | 263 | fn reset(&mut self) { |
| 177 | let regs = T::regs(); | 264 | let regs = T::regs(); |
| @@ -260,40 +347,95 @@ impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> { | |||
| 260 | fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> { | 347 | fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> { |
| 261 | async move { | 348 | async move { |
| 262 | let regs = T::regs(); | 349 | let regs = T::regs(); |
| 350 | let i = self.info.addr.index(); | ||
| 263 | 351 | ||
| 264 | if buf.len() == 0 { | 352 | if i == 0 { |
| 265 | regs.tasks_ep0status.write(|w| unsafe { w.bits(1) }); | 353 | if buf.len() == 0 { |
| 266 | return Ok(0); | 354 | regs.tasks_ep0status.write(|w| unsafe { w.bits(1) }); |
| 267 | } | 355 | return Ok(0); |
| 356 | } | ||
| 357 | |||
| 358 | // Wait for SETUP packet | ||
| 359 | regs.events_ep0setup.reset(); | ||
| 360 | regs.intenset.write(|w| w.ep0setup().set()); | ||
| 361 | poll_fn(|cx| { | ||
| 362 | EP_OUT_WAKERS[0].register(cx.waker()); | ||
| 363 | let regs = T::regs(); | ||
| 364 | if regs.events_ep0setup.read().bits() != 0 { | ||
| 365 | Poll::Ready(()) | ||
| 366 | } else { | ||
| 367 | Poll::Pending | ||
| 368 | } | ||
| 369 | }) | ||
| 370 | .await; | ||
| 371 | info!("got SETUP"); | ||
| 268 | 372 | ||
| 269 | // Wait for SETUP packet | 373 | if buf.len() < 8 { |
| 270 | regs.events_ep0setup.reset(); | 374 | return Err(ReadError::BufferOverflow); |
| 271 | regs.intenset.write(|w| w.ep0setup().set()); | ||
| 272 | poll_fn(|cx| { | ||
| 273 | EP0_WAKER.register(cx.waker()); | ||
| 274 | if regs.events_ep0setup.read().bits() != 0 { | ||
| 275 | Poll::Ready(()) | ||
| 276 | } else { | ||
| 277 | Poll::Pending | ||
| 278 | } | 375 | } |
| 279 | }) | ||
| 280 | .await; | ||
| 281 | info!("got SETUP"); | ||
| 282 | 376 | ||
| 283 | if buf.len() < 8 { | 377 | buf[0] = regs.bmrequesttype.read().bits() as u8; |
| 284 | return Err(ReadError::BufferOverflow); | 378 | buf[1] = regs.brequest.read().brequest().bits(); |
| 285 | } | 379 | buf[2] = regs.wvaluel.read().wvaluel().bits(); |
| 380 | buf[3] = regs.wvalueh.read().wvalueh().bits(); | ||
| 381 | buf[4] = regs.windexl.read().windexl().bits(); | ||
| 382 | buf[5] = regs.windexh.read().windexh().bits(); | ||
| 383 | buf[6] = regs.wlengthl.read().wlengthl().bits(); | ||
| 384 | buf[7] = regs.wlengthh.read().wlengthh().bits(); | ||
| 385 | |||
| 386 | Ok(8) | ||
| 387 | } else { | ||
| 388 | poll_fn(|cx| { | ||
| 389 | EP_OUT_WAKERS[i].register(cx.waker()); | ||
| 390 | let regs = T::regs(); | ||
| 391 | let r = regs.epdatastatus.read().bits(); | ||
| 392 | if r & (1 << (i + 16)) != 0 { | ||
| 393 | Poll::Ready(()) | ||
| 394 | } else { | ||
| 395 | Poll::Pending | ||
| 396 | } | ||
| 397 | }) | ||
| 398 | .await; | ||
| 286 | 399 | ||
| 287 | buf[0] = regs.bmrequesttype.read().bits() as u8; | 400 | // Clear status |
| 288 | buf[1] = regs.brequest.read().brequest().bits(); | 401 | regs.epdatastatus |
| 289 | buf[2] = regs.wvaluel.read().wvaluel().bits(); | 402 | .write(|w| unsafe { w.bits(1 << (i + 16)) }); |
| 290 | buf[3] = regs.wvalueh.read().wvalueh().bits(); | ||
| 291 | buf[4] = regs.windexl.read().windexl().bits(); | ||
| 292 | buf[5] = regs.windexh.read().windexh().bits(); | ||
| 293 | buf[6] = regs.wlengthl.read().wlengthl().bits(); | ||
| 294 | buf[7] = regs.wlengthh.read().wlengthh().bits(); | ||
| 295 | 403 | ||
| 296 | Ok(8) | 404 | // Check that the packet fits into the buffer |
| 405 | let size = regs.size.epout[i].read().bits(); | ||
| 406 | if size as usize > buf.len() { | ||
| 407 | return Err(ReadError::BufferOverflow); | ||
| 408 | } | ||
| 409 | |||
| 410 | let epout = [ | ||
| 411 | ®s.epout0, | ||
| 412 | ®s.epout1, | ||
| 413 | ®s.epout2, | ||
| 414 | ®s.epout3, | ||
| 415 | ®s.epout4, | ||
| 416 | ®s.epout5, | ||
| 417 | ®s.epout6, | ||
| 418 | ®s.epout7, | ||
| 419 | ]; | ||
| 420 | epout[i] | ||
| 421 | .ptr | ||
| 422 | .write(|w| unsafe { w.bits(buf.as_ptr() as u32) }); | ||
| 423 | // MAXCNT must match SIZE | ||
| 424 | epout[i].maxcnt.write(|w| unsafe { w.bits(size) }); | ||
| 425 | |||
| 426 | dma_start(); | ||
| 427 | regs.events_endepout[i].reset(); | ||
| 428 | regs.tasks_startepout[i].write(|w| w.tasks_startepout().set_bit()); | ||
| 429 | while regs.events_endepout[i] | ||
| 430 | .read() | ||
| 431 | .events_endepout() | ||
| 432 | .bit_is_clear() | ||
| 433 | {} | ||
| 434 | regs.events_endepout[i].reset(); | ||
| 435 | dma_end(); | ||
| 436 | |||
| 437 | Ok(size as usize) | ||
| 438 | } | ||
| 297 | } | 439 | } |
| 298 | } | 440 | } |
| 299 | } | 441 | } |
| @@ -331,7 +473,8 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> { | |||
| 331 | let res = with_timeout( | 473 | let res = with_timeout( |
| 332 | Duration::from_millis(10), | 474 | Duration::from_millis(10), |
| 333 | poll_fn(|cx| { | 475 | poll_fn(|cx| { |
| 334 | EP0_WAKER.register(cx.waker()); | 476 | EP_IN_WAKERS[0].register(cx.waker()); |
| 477 | let regs = T::regs(); | ||
| 335 | if regs.events_ep0datadone.read().bits() != 0 { | 478 | if regs.events_ep0datadone.read().bits() != 0 { |
| 336 | Poll::Ready(()) | 479 | Poll::Ready(()) |
| 337 | } else { | 480 | } else { |
diff --git a/embassy-usb/Cargo.toml b/embassy-usb/Cargo.toml index dfdc8fbac..5a5a6d7ab 100644 --- a/embassy-usb/Cargo.toml +++ b/embassy-usb/Cargo.toml | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | [package] | 1 | [package] |
| 2 | name = "embassy-usb" | 2 | name = "embassy-usb" |
| 3 | version = "0.1.0" | 3 | version = "0.1.0" |
| 4 | edition = "2018" | 4 | edition = "2021" |
| 5 | 5 | ||
| 6 | [dependencies] | 6 | [dependencies] |
| 7 | embassy = { version = "0.1.0", path = "../embassy" } | 7 | embassy = { version = "0.1.0", path = "../embassy" } |
diff --git a/embassy-usb/src/driver.rs b/embassy-usb/src/driver.rs index ed4edb576..a7b16efa5 100644 --- a/embassy-usb/src/driver.rs +++ b/embassy-usb/src/driver.rs | |||
| @@ -2,40 +2,6 @@ use core::future::Future; | |||
| 2 | 2 | ||
| 3 | use super::types::*; | 3 | use super::types::*; |
| 4 | 4 | ||
| 5 | #[derive(Copy, Clone, Eq, PartialEq, Debug)] | ||
| 6 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 7 | pub struct EndpointAllocError; | ||
| 8 | |||
| 9 | #[derive(Copy, Clone, Eq, PartialEq, Debug)] | ||
| 10 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 11 | |||
| 12 | /// Operation is unsupported by the driver. | ||
| 13 | pub struct Unsupported; | ||
| 14 | |||
| 15 | #[derive(Copy, Clone, Eq, PartialEq, Debug)] | ||
| 16 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 17 | |||
| 18 | /// Errors returned by [`EndpointIn::write`] | ||
| 19 | pub enum WriteError { | ||
| 20 | /// The packet is too long to fit in the | ||
| 21 | /// transmission buffer. This is generally an error in the class implementation, because the | ||
| 22 | /// class shouldn't provide more data than the `max_packet_size` it specified when allocating | ||
| 23 | /// the endpoint. | ||
| 24 | BufferOverflow, | ||
| 25 | } | ||
| 26 | |||
| 27 | #[derive(Copy, Clone, Eq, PartialEq, Debug)] | ||
| 28 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 29 | |||
| 30 | /// Errors returned by [`EndpointOut::read`] | ||
| 31 | pub enum ReadError { | ||
| 32 | /// The received packet is too long to | ||
| 33 | /// fit in `buf`. This is generally an error in the class implementation, because the class | ||
| 34 | /// should use a buffer that is large enough for the `max_packet_size` it specified when | ||
| 35 | /// allocating the endpoint. | ||
| 36 | BufferOverflow, | ||
| 37 | } | ||
| 38 | |||
| 39 | /// Driver for a specific USB peripheral. Implement this to add support for a new hardware | 5 | /// Driver for a specific USB peripheral. Implement this to add support for a new hardware |
| 40 | /// platform. | 6 | /// platform. |
| 41 | pub trait Driver<'a> { | 7 | pub trait Driver<'a> { |
| @@ -82,6 +48,12 @@ pub trait Driver<'a> { | |||
| 82 | } | 48 | } |
| 83 | 49 | ||
| 84 | pub trait Bus { | 50 | pub trait Bus { |
| 51 | type PollFuture<'a>: Future<Output = Event> + 'a | ||
| 52 | where | ||
| 53 | Self: 'a; | ||
| 54 | |||
| 55 | fn poll<'a>(&'a mut self) -> Self::PollFuture<'a>; | ||
| 56 | |||
| 85 | /// Called when the host resets the device. This will be soon called after | 57 | /// Called when the host resets the device. This will be soon called after |
| 86 | /// [`poll`](crate::device::UsbDevice::poll) returns [`PollResult::Reset`]. This method should | 58 | /// [`poll`](crate::device::UsbDevice::poll) returns [`PollResult::Reset`]. This method should |
| 87 | /// reset the state of all endpoints and peripheral flags back to a state suitable for | 59 | /// reset the state of all endpoints and peripheral flags back to a state suitable for |
| @@ -158,3 +130,50 @@ pub trait EndpointIn: Endpoint { | |||
| 158 | /// Writes a single packet of data to the endpoint. | 130 | /// Writes a single packet of data to the endpoint. |
| 159 | fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a>; | 131 | fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a>; |
| 160 | } | 132 | } |
| 133 | |||
| 134 | #[derive(Copy, Clone, Eq, PartialEq, Debug)] | ||
| 135 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 136 | /// Event returned by [`Bus::poll`]. | ||
| 137 | pub enum Event { | ||
| 138 | /// The USB reset condition has been detected. | ||
| 139 | Reset, | ||
| 140 | |||
| 141 | /// A USB suspend request has been detected or, in the case of self-powered devices, the device | ||
| 142 | /// has been disconnected from the USB bus. | ||
| 143 | Suspend, | ||
| 144 | |||
| 145 | /// A USB resume request has been detected after being suspended or, in the case of self-powered | ||
| 146 | /// devices, the device has been connected to the USB bus. | ||
| 147 | Resume, | ||
| 148 | } | ||
| 149 | |||
| 150 | #[derive(Copy, Clone, Eq, PartialEq, Debug)] | ||
| 151 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 152 | pub struct EndpointAllocError; | ||
| 153 | |||
| 154 | #[derive(Copy, Clone, Eq, PartialEq, Debug)] | ||
| 155 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 156 | /// Operation is unsupported by the driver. | ||
| 157 | pub struct Unsupported; | ||
| 158 | |||
| 159 | #[derive(Copy, Clone, Eq, PartialEq, Debug)] | ||
| 160 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 161 | /// Errors returned by [`EndpointIn::write`] | ||
| 162 | pub enum WriteError { | ||
| 163 | /// The packet is too long to fit in the | ||
| 164 | /// transmission buffer. This is generally an error in the class implementation, because the | ||
| 165 | /// class shouldn't provide more data than the `max_packet_size` it specified when allocating | ||
| 166 | /// the endpoint. | ||
| 167 | BufferOverflow, | ||
| 168 | } | ||
| 169 | |||
| 170 | #[derive(Copy, Clone, Eq, PartialEq, Debug)] | ||
| 171 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 172 | /// Errors returned by [`EndpointOut::read`] | ||
| 173 | pub enum ReadError { | ||
| 174 | /// The received packet is too long to | ||
| 175 | /// fit in `buf`. This is generally an error in the class implementation, because the class | ||
| 176 | /// should use a buffer that is large enough for the `max_packet_size` it specified when | ||
| 177 | /// allocating the endpoint. | ||
| 178 | BufferOverflow, | ||
| 179 | } | ||
diff --git a/embassy-usb/src/lib.rs b/embassy-usb/src/lib.rs index 397db96c4..33f3d4712 100644 --- a/embassy-usb/src/lib.rs +++ b/embassy-usb/src/lib.rs | |||
| @@ -9,11 +9,13 @@ mod control; | |||
| 9 | pub mod descriptor; | 9 | pub mod descriptor; |
| 10 | pub mod driver; | 10 | pub mod driver; |
| 11 | pub mod types; | 11 | pub mod types; |
| 12 | mod util; | ||
| 12 | 13 | ||
| 13 | use self::control::*; | 14 | use self::control::*; |
| 14 | use self::descriptor::*; | 15 | use self::descriptor::*; |
| 15 | use self::driver::*; | 16 | use self::driver::*; |
| 16 | use self::types::*; | 17 | use self::types::*; |
| 18 | use self::util::*; | ||
| 17 | 19 | ||
| 18 | pub use self::builder::Config; | 20 | pub use self::builder::Config; |
| 19 | pub use self::builder::UsbDeviceBuilder; | 21 | pub use self::builder::UsbDeviceBuilder; |
| @@ -47,7 +49,7 @@ pub const CONFIGURATION_VALUE: u8 = 1; | |||
| 47 | pub const DEFAULT_ALTERNATE_SETTING: u8 = 0; | 49 | pub const DEFAULT_ALTERNATE_SETTING: u8 = 0; |
| 48 | 50 | ||
| 49 | pub struct UsbDevice<'d, D: Driver<'d>> { | 51 | pub struct UsbDevice<'d, D: Driver<'d>> { |
| 50 | driver: D::Bus, | 52 | bus: D::Bus, |
| 51 | control_in: D::EndpointIn, | 53 | control_in: D::EndpointIn, |
| 52 | control_out: D::EndpointOut, | 54 | control_out: D::EndpointOut, |
| 53 | 55 | ||
| @@ -93,7 +95,7 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> { | |||
| 93 | let driver = driver.enable(); | 95 | let driver = driver.enable(); |
| 94 | 96 | ||
| 95 | Self { | 97 | Self { |
| 96 | driver, | 98 | bus: driver, |
| 97 | config, | 99 | config, |
| 98 | control_in, | 100 | control_in, |
| 99 | control_out, | 101 | control_out, |
| @@ -108,20 +110,47 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> { | |||
| 108 | } | 110 | } |
| 109 | 111 | ||
| 110 | pub async fn run(&mut self) { | 112 | pub async fn run(&mut self) { |
| 113 | let mut buf = [0; 8]; | ||
| 114 | |||
| 111 | loop { | 115 | loop { |
| 112 | let mut buf = [0; 8]; | 116 | let control_fut = self.control_out.read(&mut buf); |
| 113 | let n = self.control_out.read(&mut buf).await.unwrap(); | 117 | let bus_fut = self.bus.poll(); |
| 114 | assert_eq!(n, 8); | 118 | match select(bus_fut, control_fut).await { |
| 115 | let req = Request::parse(&buf).unwrap(); | 119 | Either::Left(evt) => match evt { |
| 116 | info!("setup request: {:x}", req); | 120 | Event::Reset => { |
| 117 | 121 | self.bus.reset(); | |
| 118 | // Now that we have properly parsed the setup packet, ensure the end-point is no longer in | 122 | |
| 119 | // a stalled state. | 123 | self.device_state = UsbDeviceState::Default; |
| 120 | self.control_out.set_stalled(false); | 124 | self.remote_wakeup_enabled = false; |
| 121 | 125 | self.pending_address = 0; | |
| 122 | match req.direction { | 126 | |
| 123 | UsbDirection::In => self.handle_control_in(req).await, | 127 | // TODO |
| 124 | UsbDirection::Out => self.handle_control_out(req).await, | 128 | //self.control.reset(); |
| 129 | //for cls in classes { | ||
| 130 | // cls.reset(); | ||
| 131 | //} | ||
| 132 | } | ||
| 133 | Event::Resume => {} | ||
| 134 | Event::Suspend => { | ||
| 135 | self.bus.suspend(); | ||
| 136 | self.device_state = UsbDeviceState::Suspend; | ||
| 137 | } | ||
| 138 | }, | ||
| 139 | Either::Right(n) => { | ||
| 140 | let n = n.unwrap(); | ||
| 141 | assert_eq!(n, 8); | ||
| 142 | let req = Request::parse(&buf).unwrap(); | ||
| 143 | info!("control request: {:x}", req); | ||
| 144 | |||
| 145 | // Now that we have properly parsed the setup packet, ensure the end-point is no longer in | ||
| 146 | // a stalled state. | ||
| 147 | self.control_out.set_stalled(false); | ||
| 148 | |||
| 149 | match req.direction { | ||
| 150 | UsbDirection::In => self.handle_control_in(req).await, | ||
| 151 | UsbDirection::Out => self.handle_control_out(req).await, | ||
| 152 | } | ||
| 153 | } | ||
| 125 | } | 154 | } |
| 126 | } | 155 | } |
| 127 | } | 156 | } |
| @@ -205,7 +234,8 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> { | |||
| 205 | } | 234 | } |
| 206 | 235 | ||
| 207 | (Recipient::Endpoint, Request::SET_FEATURE, Request::FEATURE_ENDPOINT_HALT) => { | 236 | (Recipient::Endpoint, Request::SET_FEATURE, Request::FEATURE_ENDPOINT_HALT) => { |
| 208 | //self.bus.set_stalled(((req.index as u8) & 0x8f).into(), true); | 237 | self.bus |
| 238 | .set_stalled(((req.index as u8) & 0x8f).into(), true); | ||
| 209 | self.control_out_accept(req).await; | 239 | self.control_out_accept(req).await; |
| 210 | } | 240 | } |
| 211 | 241 | ||
| @@ -266,7 +296,7 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> { | |||
| 266 | (Recipient::Endpoint, Request::GET_STATUS) => { | 296 | (Recipient::Endpoint, Request::GET_STATUS) => { |
| 267 | let ep_addr: EndpointAddress = ((req.index as u8) & 0x8f).into(); | 297 | let ep_addr: EndpointAddress = ((req.index as u8) & 0x8f).into(); |
| 268 | let mut status: u16 = 0x0000; | 298 | let mut status: u16 = 0x0000; |
| 269 | if self.driver.is_stalled(ep_addr) { | 299 | if self.bus.is_stalled(ep_addr) { |
| 270 | status |= 0x0001; | 300 | status |= 0x0001; |
| 271 | } | 301 | } |
| 272 | self.control_in_accept(req, &status.to_le_bytes()).await; | 302 | self.control_in_accept(req, &status.to_le_bytes()).await; |
diff --git a/embassy-usb/src/util.rs b/embassy-usb/src/util.rs new file mode 100644 index 000000000..18cc875c6 --- /dev/null +++ b/embassy-usb/src/util.rs | |||
| @@ -0,0 +1,45 @@ | |||
| 1 | use core::future::Future; | ||
| 2 | use core::pin::Pin; | ||
| 3 | use core::task::{Context, Poll}; | ||
| 4 | |||
| 5 | #[derive(Debug, Clone)] | ||
| 6 | pub enum Either<A, B> { | ||
| 7 | Left(A), | ||
| 8 | Right(B), | ||
| 9 | } | ||
| 10 | |||
| 11 | pub fn select<A, B>(a: A, b: B) -> Select<A, B> | ||
| 12 | where | ||
| 13 | A: Future, | ||
| 14 | B: Future, | ||
| 15 | { | ||
| 16 | Select { a, b } | ||
| 17 | } | ||
| 18 | |||
| 19 | pub struct Select<A, B> { | ||
| 20 | a: A, | ||
| 21 | b: B, | ||
| 22 | } | ||
| 23 | |||
| 24 | impl<A: Unpin, B: Unpin> Unpin for Select<A, B> {} | ||
| 25 | |||
| 26 | impl<A, B> Future for Select<A, B> | ||
| 27 | where | ||
| 28 | A: Future, | ||
| 29 | B: Future, | ||
| 30 | { | ||
| 31 | type Output = Either<A::Output, B::Output>; | ||
| 32 | |||
| 33 | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { | ||
| 34 | let this = unsafe { self.get_unchecked_mut() }; | ||
| 35 | let a = unsafe { Pin::new_unchecked(&mut this.a) }; | ||
| 36 | let b = unsafe { Pin::new_unchecked(&mut this.b) }; | ||
| 37 | match a.poll(cx) { | ||
| 38 | Poll::Ready(x) => Poll::Ready(Either::Left(x)), | ||
| 39 | Poll::Pending => match b.poll(cx) { | ||
| 40 | Poll::Ready(x) => Poll::Ready(Either::Right(x)), | ||
| 41 | Poll::Pending => Poll::Pending, | ||
| 42 | }, | ||
| 43 | } | ||
| 44 | } | ||
| 45 | } | ||
diff --git a/examples/nrf/src/bin/usb/cdc_acm.rs b/examples/nrf/src/bin/usb/cdc_acm.rs index 345d00389..b7c112ae6 100644 --- a/examples/nrf/src/bin/usb/cdc_acm.rs +++ b/examples/nrf/src/bin/usb/cdc_acm.rs | |||
| @@ -38,14 +38,15 @@ const REQ_SET_CONTROL_LINE_STATE: u8 = 0x22; | |||
| 38 | /// can be sent if there is no other data to send. This is because USB bulk transactions must be | 38 | /// can be sent if there is no other data to send. This is because USB bulk transactions must be |
| 39 | /// terminated with a short packet, even if the bulk endpoint is used for stream-like data. | 39 | /// terminated with a short packet, even if the bulk endpoint is used for stream-like data. |
| 40 | pub struct CdcAcmClass<'d, D: Driver<'d>> { | 40 | pub struct CdcAcmClass<'d, D: Driver<'d>> { |
| 41 | comm_if: InterfaceNumber, | 41 | // TODO not pub |
| 42 | comm_ep: D::EndpointIn, | 42 | pub comm_if: InterfaceNumber, |
| 43 | data_if: InterfaceNumber, | 43 | pub comm_ep: D::EndpointIn, |
| 44 | read_ep: D::EndpointOut, | 44 | pub data_if: InterfaceNumber, |
| 45 | write_ep: D::EndpointIn, | 45 | pub read_ep: D::EndpointOut, |
| 46 | line_coding: LineCoding, | 46 | pub write_ep: D::EndpointIn, |
| 47 | dtr: bool, | 47 | pub line_coding: LineCoding, |
| 48 | rts: bool, | 48 | pub dtr: bool, |
| 49 | pub rts: bool, | ||
| 49 | } | 50 | } |
| 50 | 51 | ||
| 51 | impl<'d, D: Driver<'d>> CdcAcmClass<'d, D> { | 52 | impl<'d, D: Driver<'d>> CdcAcmClass<'d, D> { |
diff --git a/examples/nrf/src/bin/usb/main.rs b/examples/nrf/src/bin/usb/main.rs index 21ca2ba4f..d175766bb 100644 --- a/examples/nrf/src/bin/usb/main.rs +++ b/examples/nrf/src/bin/usb/main.rs | |||
| @@ -14,7 +14,9 @@ use embassy_nrf::interrupt; | |||
| 14 | use embassy_nrf::pac; | 14 | use embassy_nrf::pac; |
| 15 | use embassy_nrf::usb::{self, Driver}; | 15 | use embassy_nrf::usb::{self, Driver}; |
| 16 | use embassy_nrf::Peripherals; | 16 | use embassy_nrf::Peripherals; |
| 17 | use embassy_usb::driver::EndpointOut; | ||
| 17 | use embassy_usb::{Config, UsbDeviceBuilder}; | 18 | use embassy_usb::{Config, UsbDeviceBuilder}; |
| 19 | use futures::future::{join, select}; | ||
| 18 | 20 | ||
| 19 | use crate::cdc_acm::CdcAcmClass; | 21 | use crate::cdc_acm::CdcAcmClass; |
| 20 | 22 | ||
| @@ -49,5 +51,16 @@ async fn main(_spawner: Spawner, p: Peripherals) { | |||
| 49 | let mut class = CdcAcmClass::new(&mut builder, 64); | 51 | let mut class = CdcAcmClass::new(&mut builder, 64); |
| 50 | 52 | ||
| 51 | let mut usb = builder.build(); | 53 | let mut usb = builder.build(); |
| 52 | usb.run().await; | 54 | |
| 55 | let fut1 = usb.run(); | ||
| 56 | let fut2 = async { | ||
| 57 | let mut buf = [0; 64]; | ||
| 58 | loop { | ||
| 59 | let n = class.read_ep.read(&mut buf).await.unwrap(); | ||
| 60 | let data = &buf[..n]; | ||
| 61 | info!("data: {:x}", data); | ||
| 62 | } | ||
| 63 | }; | ||
| 64 | |||
| 65 | join(fut1, fut2).await; | ||
| 53 | } | 66 | } |
