aboutsummaryrefslogtreecommitdiff
path: root/embassy-usb
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 /embassy-usb
parent37598a5b3792ec1b763b5c16fe422c9e1347d7d6 (diff)
Working CDC-ACM host->device
Diffstat (limited to 'embassy-usb')
-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
4 files changed, 146 insertions, 52 deletions
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}