aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2022-03-09 23:06:27 +0100
committerDario Nieuwenhuis <[email protected]>2022-04-06 05:38:11 +0200
commit77ceced036d574c7d67259b85e1d61b96e82d0d3 (patch)
tree4f1a250f92d59922ae7ceda0779aae16cfa767bb
parent37598a5b3792ec1b763b5c16fe422c9e1347d7d6 (diff)
Working CDC-ACM host->device
-rw-r--r--embassy-nrf/src/usb.rs209
-rw-r--r--embassy-usb/Cargo.toml2
-rw-r--r--embassy-usb/src/driver.rs87
-rw-r--r--embassy-usb/src/lib.rs64
-rw-r--r--embassy-usb/src/util.rs45
-rw-r--r--examples/nrf/src/bin/usb/cdc_acm.rs17
-rw-r--r--examples/nrf/src/bin/usb/main.rs15
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};
8use embassy::util::Unborrow; 8use embassy::util::Unborrow;
9use embassy::waitqueue::AtomicWaker; 9use embassy::waitqueue::AtomicWaker;
10use embassy_hal_common::unborrow; 10use embassy_hal_common::unborrow;
11use embassy_usb::driver::{self, ReadError, WriteError}; 11use embassy_usb::driver::{self, Event, ReadError, WriteError};
12use embassy_usb::types::{EndpointAddress, EndpointInfo, EndpointType, UsbDirection}; 12use embassy_usb::types::{EndpointAddress, EndpointInfo, EndpointType, UsbDirection};
13use futures::future::poll_fn; 13use futures::future::poll_fn;
14use futures::Future; 14use futures::Future;
@@ -19,7 +19,10 @@ pub use embassy_usb;
19use crate::interrupt::Interrupt; 19use crate::interrupt::Interrupt;
20use crate::pac; 20use crate::pac;
21 21
22static EP0_WAKER: AtomicWaker = AtomicWaker::new(); 22const NEW_AW: AtomicWaker = AtomicWaker::new();
23static BUS_WAKER: AtomicWaker = NEW_AW;
24static EP_IN_WAKERS: [AtomicWaker; 9] = [NEW_AW; 9];
25static EP_OUT_WAKERS: [AtomicWaker; 9] = [NEW_AW; 9];
23 26
24pub struct Driver<'d, T: Instance> { 27pub 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
174impl<'d, T: Instance> driver::Bus for Bus<'d, T> { 218impl<'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 &regs.epout0,
412 &regs.epout1,
413 &regs.epout2,
414 &regs.epout3,
415 &regs.epout4,
416 &regs.epout5,
417 &regs.epout6,
418 &regs.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]
2name = "embassy-usb" 2name = "embassy-usb"
3version = "0.1.0" 3version = "0.1.0"
4edition = "2018" 4edition = "2021"
5 5
6[dependencies] 6[dependencies]
7embassy = { version = "0.1.0", path = "../embassy" } 7embassy = { 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
3use super::types::*; 3use super::types::*;
4 4
5#[derive(Copy, Clone, Eq, PartialEq, Debug)]
6#[cfg_attr(feature = "defmt", derive(defmt::Format))]
7pub 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.
13pub 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`]
19pub 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`]
31pub 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.
41pub trait Driver<'a> { 7pub trait Driver<'a> {
@@ -82,6 +48,12 @@ pub trait Driver<'a> {
82} 48}
83 49
84pub trait Bus { 50pub 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`].
137pub 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))]
152pub 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.
157pub struct Unsupported;
158
159#[derive(Copy, Clone, Eq, PartialEq, Debug)]
160#[cfg_attr(feature = "defmt", derive(defmt::Format))]
161/// Errors returned by [`EndpointIn::write`]
162pub 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`]
173pub 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;
9pub mod descriptor; 9pub mod descriptor;
10pub mod driver; 10pub mod driver;
11pub mod types; 11pub mod types;
12mod util;
12 13
13use self::control::*; 14use self::control::*;
14use self::descriptor::*; 15use self::descriptor::*;
15use self::driver::*; 16use self::driver::*;
16use self::types::*; 17use self::types::*;
18use self::util::*;
17 19
18pub use self::builder::Config; 20pub use self::builder::Config;
19pub use self::builder::UsbDeviceBuilder; 21pub use self::builder::UsbDeviceBuilder;
@@ -47,7 +49,7 @@ pub const CONFIGURATION_VALUE: u8 = 1;
47pub const DEFAULT_ALTERNATE_SETTING: u8 = 0; 49pub const DEFAULT_ALTERNATE_SETTING: u8 = 0;
48 50
49pub struct UsbDevice<'d, D: Driver<'d>> { 51pub 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 @@
1use core::future::Future;
2use core::pin::Pin;
3use core::task::{Context, Poll};
4
5#[derive(Debug, Clone)]
6pub enum Either<A, B> {
7 Left(A),
8 Right(B),
9}
10
11pub fn select<A, B>(a: A, b: B) -> Select<A, B>
12where
13 A: Future,
14 B: Future,
15{
16 Select { a, b }
17}
18
19pub struct Select<A, B> {
20 a: A,
21 b: B,
22}
23
24impl<A: Unpin, B: Unpin> Unpin for Select<A, B> {}
25
26impl<A, B> Future for Select<A, B>
27where
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.
40pub struct CdcAcmClass<'d, D: Driver<'d>> { 40pub 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
51impl<'d, D: Driver<'d>> CdcAcmClass<'d, D> { 52impl<'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;
14use embassy_nrf::pac; 14use embassy_nrf::pac;
15use embassy_nrf::usb::{self, Driver}; 15use embassy_nrf::usb::{self, Driver};
16use embassy_nrf::Peripherals; 16use embassy_nrf::Peripherals;
17use embassy_usb::driver::EndpointOut;
17use embassy_usb::{Config, UsbDeviceBuilder}; 18use embassy_usb::{Config, UsbDeviceBuilder};
19use futures::future::{join, select};
18 20
19use crate::cdc_acm::CdcAcmClass; 21use 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}