aboutsummaryrefslogtreecommitdiff
path: root/embassy-usb/src
diff options
context:
space:
mode:
authoralexmoon <[email protected]>2022-03-27 17:12:57 -0400
committerDario Nieuwenhuis <[email protected]>2022-04-06 05:38:11 +0200
commit52c622b1cd02ba13accc84cd57e90b04797f0405 (patch)
tree67057b66716715a75a2ca60ecf6115720d577961 /embassy-usb/src
parentbdc6e0481c42d20d5cca19dfc8ec56306e47296e (diff)
Use trait objects instead of generics for UsbDevice::classes
Diffstat (limited to 'embassy-usb/src')
-rw-r--r--embassy-usb/src/builder.rs5
-rw-r--r--embassy-usb/src/class.rs147
-rw-r--r--embassy-usb/src/lib.rs48
3 files changed, 68 insertions, 132 deletions
diff --git a/embassy-usb/src/builder.rs b/embassy-usb/src/builder.rs
index f0f94b932..bcb838ff5 100644
--- a/embassy-usb/src/builder.rs
+++ b/embassy-usb/src/builder.rs
@@ -175,10 +175,7 @@ impl<'d, D: Driver<'d>> UsbDeviceBuilder<'d, D> {
175 } 175 }
176 176
177 /// Creates the [`UsbDevice`] instance with the configuration in this builder. 177 /// Creates the [`UsbDevice`] instance with the configuration in this builder.
178 /// 178 pub fn build(mut self, classes: &'d mut [&'d mut dyn UsbClass]) -> UsbDevice<'d, D> {
179 /// If a device has mutliple [`UsbClass`]es, they can be provided as a tuple list:
180 /// `(class1, (class2, (class3, ()))`.
181 pub fn build<C: UsbClass<'d, D>>(mut self, classes: C) -> UsbDevice<'d, D, C> {
182 self.config_descriptor.end_configuration(); 179 self.config_descriptor.end_configuration();
183 self.bos_descriptor.end_bos(); 180 self.bos_descriptor.end_bos();
184 181
diff --git a/embassy-usb/src/class.rs b/embassy-usb/src/class.rs
index 97bf7aba1..a0141e318 100644
--- a/embassy-usb/src/class.rs
+++ b/embassy-usb/src/class.rs
@@ -1,7 +1,4 @@
1use core::future::Future;
2
3use crate::control::Request; 1use crate::control::Request;
4use crate::driver::{ControlPipe, Driver};
5 2
6#[derive(Copy, Clone, Eq, PartialEq, Debug)] 3#[derive(Copy, Clone, Eq, PartialEq, Debug)]
7#[cfg_attr(feature = "defmt", derive(defmt::Format))] 4#[cfg_attr(feature = "defmt", derive(defmt::Format))]
@@ -21,19 +18,7 @@ impl Default for RequestStatus {
21/// 18///
22/// All methods are optional callbacks that will be called by 19/// All methods are optional callbacks that will be called by
23/// [`UsbDevice::run()`](crate::UsbDevice::run) 20/// [`UsbDevice::run()`](crate::UsbDevice::run)
24pub trait UsbClass<'d, D: Driver<'d>> { 21pub trait UsbClass {
25 type ControlOutFuture<'a>: Future<Output = RequestStatus> + 'a
26 where
27 Self: 'a,
28 'd: 'a,
29 D: 'a;
30
31 type ControlInFuture<'a>: Future<Output = ControlInRequestStatus> + 'a
32 where
33 Self: 'a,
34 'd: 'a,
35 D: 'a;
36
37 /// Called after a USB reset after the bus reset sequence is complete. 22 /// Called after a USB reset after the bus reset sequence is complete.
38 fn reset(&mut self) {} 23 fn reset(&mut self) {}
39 24
@@ -50,10 +35,7 @@ pub trait UsbClass<'d, D: Driver<'d>> {
50 /// 35 ///
51 /// * `req` - The request from the SETUP packet. 36 /// * `req` - The request from the SETUP packet.
52 /// * `data` - The data from the request. 37 /// * `data` - The data from the request.
53 fn control_out<'a>(&'a mut self, req: Request, data: &'a [u8]) -> Self::ControlOutFuture<'a> 38 fn control_out(&mut self, req: Request, data: &[u8]) -> RequestStatus;
54 where
55 'd: 'a,
56 D: 'a;
57 39
58 /// Called when a control request is received with direction DeviceToHost. 40 /// Called when a control request is received with direction DeviceToHost.
59 /// 41 ///
@@ -71,120 +53,63 @@ pub trait UsbClass<'d, D: Driver<'d>> {
71 /// * `req` - The request from the SETUP packet. 53 /// * `req` - The request from the SETUP packet.
72 /// * `control` - The control pipe. 54 /// * `control` - The control pipe.
73 fn control_in<'a>( 55 fn control_in<'a>(
74 &'a mut self, 56 &mut self,
75 req: Request, 57 req: Request,
76 control: ControlIn<'a, 'd, D>, 58 control: ControlIn<'a>,
77 ) -> Self::ControlInFuture<'a> 59 ) -> ControlInRequestStatus<'a>;
78 where
79 'd: 'a;
80}
81
82impl<'d, D: Driver<'d>> UsbClass<'d, D> for () {
83 type ControlOutFuture<'a> = impl Future<Output = RequestStatus> + 'a where Self: 'a, 'd: 'a, D: 'a;
84 type ControlInFuture<'a> = impl Future<Output = ControlInRequestStatus> + 'a where Self: 'a, 'd: 'a, D: 'a;
85
86 fn control_out<'a>(&'a mut self, _req: Request, _data: &'a [u8]) -> Self::ControlOutFuture<'a>
87 where
88 'd: 'a,
89 D: 'a,
90 {
91 async move { RequestStatus::default() }
92 }
93
94 fn control_in<'a>(
95 &'a mut self,
96 _req: Request,
97 control: ControlIn<'a, 'd, D>,
98 ) -> Self::ControlInFuture<'a>
99 where
100 'd: 'a,
101 D: 'a,
102 {
103 async move { control.ignore() }
104 }
105}
106
107impl<'d, D: Driver<'d>, Head, Tail> UsbClass<'d, D> for (Head, Tail)
108where
109 Head: UsbClass<'d, D>,
110 Tail: UsbClass<'d, D>,
111{
112 type ControlOutFuture<'a> = impl Future<Output = RequestStatus> + 'a where Self: 'a, 'd: 'a, D: 'a;
113 type ControlInFuture<'a> = impl Future<Output = ControlInRequestStatus> + 'a where Self: 'a, 'd: 'a, D: 'a;
114
115 fn control_out<'a>(&'a mut self, req: Request, data: &'a [u8]) -> Self::ControlOutFuture<'a>
116 where
117 'd: 'a,
118 D: 'a,
119 {
120 async move {
121 match self.0.control_out(req, data).await {
122 RequestStatus::Unhandled => self.1.control_out(req, data).await,
123 status => status,
124 }
125 }
126 }
127
128 fn control_in<'a>(
129 &'a mut self,
130 req: Request,
131 control: ControlIn<'a, 'd, D>,
132 ) -> Self::ControlInFuture<'a>
133 where
134 'd: 'a,
135 {
136 async move {
137 match self
138 .0
139 .control_in(req, ControlIn::new(control.control))
140 .await
141 {
142 ControlInRequestStatus(RequestStatus::Unhandled) => {
143 self.1.control_in(req, control).await
144 }
145 status => status,
146 }
147 }
148 }
149} 60}
150 61
151/// Handle for a control IN transfer. When implementing a class, use the methods of this object to 62/// Handle for a control IN transfer. When implementing a class, use the methods of this object to
152/// response to the transfer with either data or an error (STALL condition). To ignore the request 63/// response to the transfer with either data or an error (STALL condition). To ignore the request
153/// and pass it on to the next class, call [`Self::ignore()`]. 64/// and pass it on to the next class, call [`Self::ignore()`].
154pub struct ControlIn<'a, 'd: 'a, D: Driver<'d>> { 65pub struct ControlIn<'a> {
155 control: &'a mut D::ControlPipe, 66 buf: &'a mut [u8],
156} 67}
157 68
158#[derive(Eq, PartialEq, Debug)] 69#[derive(Eq, PartialEq, Debug)]
159#[cfg_attr(feature = "defmt", derive(defmt::Format))] 70#[cfg_attr(feature = "defmt", derive(defmt::Format))]
160pub struct ControlInRequestStatus(pub(crate) RequestStatus); 71pub struct ControlInRequestStatus<'a> {
72 pub(crate) status: RequestStatus,
73 pub(crate) data: &'a [u8],
74}
161 75
162impl ControlInRequestStatus { 76impl<'a> ControlInRequestStatus<'a> {
163 pub fn status(self) -> RequestStatus { 77 pub fn status(&self) -> RequestStatus {
164 self.0 78 self.status
165 } 79 }
166} 80}
167 81
168impl<'a, 'd: 'a, D: Driver<'d>> ControlIn<'a, 'd, D> { 82impl<'a> ControlIn<'a> {
169 pub(crate) fn new(control: &'a mut D::ControlPipe) -> Self { 83 pub(crate) fn new(buf: &'a mut [u8]) -> Self {
170 ControlIn { control } 84 ControlIn { buf }
171 } 85 }
172 86
173 /// Ignores the request and leaves it unhandled. 87 /// Ignores the request and leaves it unhandled.
174 pub fn ignore(self) -> ControlInRequestStatus { 88 pub fn ignore(self) -> ControlInRequestStatus<'a> {
175 ControlInRequestStatus(RequestStatus::Unhandled) 89 ControlInRequestStatus {
90 status: RequestStatus::Unhandled,
91 data: &[],
92 }
176 } 93 }
177 94
178 /// Accepts the transfer with the supplied buffer. 95 /// Accepts the transfer with the supplied buffer.
179 pub async fn accept(self, data: &[u8]) -> ControlInRequestStatus { 96 pub fn accept(self, data: &[u8]) -> ControlInRequestStatus<'a> {
180 self.control.accept_in(data).await; 97 assert!(data.len() < self.buf.len());
181 98
182 ControlInRequestStatus(RequestStatus::Accepted) 99 let buf = &mut self.buf[0..data.len()];
100 buf.copy_from_slice(data);
101
102 ControlInRequestStatus {
103 status: RequestStatus::Accepted,
104 data: buf,
105 }
183 } 106 }
184 107
185 /// Rejects the transfer by stalling the pipe. 108 /// Rejects the transfer by stalling the pipe.
186 pub fn reject(self) -> ControlInRequestStatus { 109 pub fn reject(self) -> ControlInRequestStatus<'a> {
187 self.control.reject(); 110 ControlInRequestStatus {
188 ControlInRequestStatus(RequestStatus::Rejected) 111 status: RequestStatus::Unhandled,
112 data: &[],
113 }
189 } 114 }
190} 115}
diff --git a/embassy-usb/src/lib.rs b/embassy-usb/src/lib.rs
index 4082868fb..ff3930afa 100644
--- a/embassy-usb/src/lib.rs
+++ b/embassy-usb/src/lib.rs
@@ -13,6 +13,8 @@ pub mod driver;
13pub mod types; 13pub mod types;
14mod util; 14mod util;
15 15
16use class::ControlInRequestStatus;
17
16use self::class::{RequestStatus, UsbClass}; 18use self::class::{RequestStatus, UsbClass};
17use self::control::*; 19use self::control::*;
18use self::descriptor::*; 20use self::descriptor::*;
@@ -51,7 +53,7 @@ pub const CONFIGURATION_VALUE: u8 = 1;
51/// The default value for bAlternateSetting for all interfaces. 53/// The default value for bAlternateSetting for all interfaces.
52pub const DEFAULT_ALTERNATE_SETTING: u8 = 0; 54pub const DEFAULT_ALTERNATE_SETTING: u8 = 0;
53 55
54pub struct UsbDevice<'d, D: Driver<'d>, C: UsbClass<'d, D>> { 56pub struct UsbDevice<'d, D: Driver<'d>> {
55 bus: D::Bus, 57 bus: D::Bus,
56 control: D::ControlPipe, 58 control: D::ControlPipe,
57 59
@@ -65,17 +67,17 @@ pub struct UsbDevice<'d, D: Driver<'d>, C: UsbClass<'d, D>> {
65 self_powered: bool, 67 self_powered: bool,
66 pending_address: u8, 68 pending_address: u8,
67 69
68 classes: C, 70 classes: &'d mut [&'d mut dyn UsbClass],
69} 71}
70 72
71impl<'d, D: Driver<'d>, C: UsbClass<'d, D>> UsbDevice<'d, D, C> { 73impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
72 pub(crate) fn build( 74 pub(crate) fn build(
73 mut driver: D, 75 mut driver: D,
74 config: Config<'d>, 76 config: Config<'d>,
75 device_descriptor: &'d [u8], 77 device_descriptor: &'d [u8],
76 config_descriptor: &'d [u8], 78 config_descriptor: &'d [u8],
77 bos_descriptor: &'d [u8], 79 bos_descriptor: &'d [u8],
78 classes: C, 80 classes: &'d mut [&'d mut dyn UsbClass],
79 ) -> Self { 81 ) -> Self {
80 let control = driver 82 let control = driver
81 .alloc_control_pipe(config.max_packet_size_0 as u16) 83 .alloc_control_pipe(config.max_packet_size_0 as u16)
@@ -113,7 +115,9 @@ impl<'d, D: Driver<'d>, C: UsbClass<'d, D>> UsbDevice<'d, D, C> {
113 self.remote_wakeup_enabled = false; 115 self.remote_wakeup_enabled = false;
114 self.pending_address = 0; 116 self.pending_address = 0;
115 117
116 self.classes.reset(); 118 for c in self.classes.iter_mut() {
119 c.reset();
120 }
117 } 121 }
118 Event::Resume => {} 122 Event::Resume => {}
119 Event::Suspend => { 123 Event::Suspend => {
@@ -155,10 +159,12 @@ impl<'d, D: Driver<'d>, C: UsbClass<'d, D>> UsbDevice<'d, D, C> {
155 &[] 159 &[]
156 }; 160 };
157 161
158 match self.classes.control_out(req, data).await { 162 for c in self.classes.iter_mut() {
159 RequestStatus::Accepted => return self.control.accept(), 163 match c.control_out(req, data) {
160 RequestStatus::Rejected => return self.control.reject(), 164 RequestStatus::Accepted => return self.control.accept(),
161 RequestStatus::Unhandled => (), 165 RequestStatus::Rejected => return self.control.reject(),
166 RequestStatus::Unhandled => (),
167 }
162 } 168 }
163 } 169 }
164 170
@@ -233,14 +239,22 @@ impl<'d, D: Driver<'d>, C: UsbClass<'d, D>> UsbDevice<'d, D, C> {
233 } 239 }
234 240
235 async fn handle_control_in(&mut self, req: Request) { 241 async fn handle_control_in(&mut self, req: Request) {
236 match self 242 let mut buf = [0; 128];
237 .classes 243 for c in self.classes.iter_mut() {
238 .control_in(req, class::ControlIn::new(&mut self.control)) 244 match c.control_in(req, class::ControlIn::new(&mut buf)) {
239 .await 245 ControlInRequestStatus {
240 .status() 246 status: RequestStatus::Accepted,
241 { 247 data,
242 RequestStatus::Accepted | RequestStatus::Rejected => return, 248 } => return self.control.accept_in(data).await,
243 RequestStatus::Unhandled => (), 249 ControlInRequestStatus {
250 status: RequestStatus::Rejected,
251 ..
252 } => return self.control.reject(),
253 ControlInRequestStatus {
254 status: RequestStatus::Unhandled,
255 ..
256 } => (),
257 }
244 } 258 }
245 259
246 match req.request_type { 260 match req.request_type {