aboutsummaryrefslogtreecommitdiff
path: root/embassy-hal-common
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2021-07-29 13:44:51 +0200
committerDario Nieuwenhuis <[email protected]>2021-07-29 13:44:51 +0200
commit7bfb763e0990aac1b0bc4ad95dcc55df53cdb6d9 (patch)
treea7552da59a774d79a3cd73ad7c109b02b8bac921 /embassy-hal-common
parentc8a48d726a7cc92ef989a519fdf55ec1f9fffbcd (diff)
Rename embassy-extras to embassy-hal-common
Diffstat (limited to 'embassy-hal-common')
-rw-r--r--embassy-hal-common/Cargo.toml20
-rw-r--r--embassy-hal-common/src/fmt.rs225
-rw-r--r--embassy-hal-common/src/interrupt.rs571
-rw-r--r--embassy-hal-common/src/lib.rs21
-rw-r--r--embassy-hal-common/src/macros.rs130
-rw-r--r--embassy-hal-common/src/peripheral.rs160
-rw-r--r--embassy-hal-common/src/peripheral_shared.rs122
-rw-r--r--embassy-hal-common/src/ring_buffer.rs84
-rw-r--r--embassy-hal-common/src/usb/cdc_acm.rs338
-rw-r--r--embassy-hal-common/src/usb/mod.rs258
-rw-r--r--embassy-hal-common/src/usb/usb_serial.rs310
11 files changed, 2239 insertions, 0 deletions
diff --git a/embassy-hal-common/Cargo.toml b/embassy-hal-common/Cargo.toml
new file mode 100644
index 000000000..4db536de4
--- /dev/null
+++ b/embassy-hal-common/Cargo.toml
@@ -0,0 +1,20 @@
1[package]
2name = "embassy-hal-common"
3version = "0.1.0"
4authors = ["Dario Nieuwenhuis <[email protected]>"]
5edition = "2018"
6
7[features]
8defmt-trace = [ ]
9defmt-debug = [ ]
10defmt-info = [ ]
11defmt-warn = [ ]
12defmt-error = [ ]
13
14[dependencies]
15embassy = { version = "0.1.0", path = "../embassy" }
16
17defmt = { version = "0.2.0", optional = true }
18log = { version = "0.4.11", optional = true }
19cortex-m = "0.7.1"
20usb-device = "0.2.7"
diff --git a/embassy-hal-common/src/fmt.rs b/embassy-hal-common/src/fmt.rs
new file mode 100644
index 000000000..066970813
--- /dev/null
+++ b/embassy-hal-common/src/fmt.rs
@@ -0,0 +1,225 @@
1#![macro_use]
2#![allow(unused_macros)]
3
4#[cfg(all(feature = "defmt", feature = "log"))]
5compile_error!("You may not enable both `defmt` and `log` features.");
6
7macro_rules! assert {
8 ($($x:tt)*) => {
9 {
10 #[cfg(not(feature = "defmt"))]
11 ::core::assert!($($x)*);
12 #[cfg(feature = "defmt")]
13 ::defmt::assert!($($x)*);
14 }
15 };
16}
17
18macro_rules! assert_eq {
19 ($($x:tt)*) => {
20 {
21 #[cfg(not(feature = "defmt"))]
22 ::core::assert_eq!($($x)*);
23 #[cfg(feature = "defmt")]
24 ::defmt::assert_eq!($($x)*);
25 }
26 };
27}
28
29macro_rules! assert_ne {
30 ($($x:tt)*) => {
31 {
32 #[cfg(not(feature = "defmt"))]
33 ::core::assert_ne!($($x)*);
34 #[cfg(feature = "defmt")]
35 ::defmt::assert_ne!($($x)*);
36 }
37 };
38}
39
40macro_rules! debug_assert {
41 ($($x:tt)*) => {
42 {
43 #[cfg(not(feature = "defmt"))]
44 ::core::debug_assert!($($x)*);
45 #[cfg(feature = "defmt")]
46 ::defmt::debug_assert!($($x)*);
47 }
48 };
49}
50
51macro_rules! debug_assert_eq {
52 ($($x:tt)*) => {
53 {
54 #[cfg(not(feature = "defmt"))]
55 ::core::debug_assert_eq!($($x)*);
56 #[cfg(feature = "defmt")]
57 ::defmt::debug_assert_eq!($($x)*);
58 }
59 };
60}
61
62macro_rules! debug_assert_ne {
63 ($($x:tt)*) => {
64 {
65 #[cfg(not(feature = "defmt"))]
66 ::core::debug_assert_ne!($($x)*);
67 #[cfg(feature = "defmt")]
68 ::defmt::debug_assert_ne!($($x)*);
69 }
70 };
71}
72
73macro_rules! todo {
74 ($($x:tt)*) => {
75 {
76 #[cfg(not(feature = "defmt"))]
77 ::core::todo!($($x)*);
78 #[cfg(feature = "defmt")]
79 ::defmt::todo!($($x)*);
80 }
81 };
82}
83
84macro_rules! unreachable {
85 ($($x:tt)*) => {
86 {
87 #[cfg(not(feature = "defmt"))]
88 ::core::unreachable!($($x)*);
89 #[cfg(feature = "defmt")]
90 ::defmt::unreachable!($($x)*);
91 }
92 };
93}
94
95macro_rules! panic {
96 ($($x:tt)*) => {
97 {
98 #[cfg(not(feature = "defmt"))]
99 ::core::panic!($($x)*);
100 #[cfg(feature = "defmt")]
101 ::defmt::panic!($($x)*);
102 }
103 };
104}
105
106macro_rules! trace {
107 ($s:literal $(, $x:expr)* $(,)?) => {
108 {
109 #[cfg(feature = "log")]
110 ::log::trace!($s $(, $x)*);
111 #[cfg(feature = "defmt")]
112 ::defmt::trace!($s $(, $x)*);
113 #[cfg(not(any(feature = "log", feature="defmt")))]
114 let _ = ($( & $x ),*);
115 }
116 };
117}
118
119macro_rules! debug {
120 ($s:literal $(, $x:expr)* $(,)?) => {
121 {
122 #[cfg(feature = "log")]
123 ::log::debug!($s $(, $x)*);
124 #[cfg(feature = "defmt")]
125 ::defmt::debug!($s $(, $x)*);
126 #[cfg(not(any(feature = "log", feature="defmt")))]
127 let _ = ($( & $x ),*);
128 }
129 };
130}
131
132macro_rules! info {
133 ($s:literal $(, $x:expr)* $(,)?) => {
134 {
135 #[cfg(feature = "log")]
136 ::log::info!($s $(, $x)*);
137 #[cfg(feature = "defmt")]
138 ::defmt::info!($s $(, $x)*);
139 #[cfg(not(any(feature = "log", feature="defmt")))]
140 let _ = ($( & $x ),*);
141 }
142 };
143}
144
145macro_rules! warn {
146 ($s:literal $(, $x:expr)* $(,)?) => {
147 {
148 #[cfg(feature = "log")]
149 ::log::warn!($s $(, $x)*);
150 #[cfg(feature = "defmt")]
151 ::defmt::warn!($s $(, $x)*);
152 #[cfg(not(any(feature = "log", feature="defmt")))]
153 let _ = ($( & $x ),*);
154 }
155 };
156}
157
158macro_rules! error {
159 ($s:literal $(, $x:expr)* $(,)?) => {
160 {
161 #[cfg(feature = "log")]
162 ::log::error!($s $(, $x)*);
163 #[cfg(feature = "defmt")]
164 ::defmt::error!($s $(, $x)*);
165 #[cfg(not(any(feature = "log", feature="defmt")))]
166 let _ = ($( & $x ),*);
167 }
168 };
169}
170
171#[cfg(feature = "defmt")]
172macro_rules! unwrap {
173 ($($x:tt)*) => {
174 ::defmt::unwrap!($($x)*)
175 };
176}
177
178#[cfg(not(feature = "defmt"))]
179macro_rules! unwrap {
180 ($arg:expr) => {
181 match $crate::fmt::Try::into_result($arg) {
182 ::core::result::Result::Ok(t) => t,
183 ::core::result::Result::Err(e) => {
184 ::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e);
185 }
186 }
187 };
188 ($arg:expr, $($msg:expr),+ $(,)? ) => {
189 match $crate::fmt::Try::into_result($arg) {
190 ::core::result::Result::Ok(t) => t,
191 ::core::result::Result::Err(e) => {
192 ::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e);
193 }
194 }
195 }
196}
197
198#[derive(Debug, Copy, Clone, Eq, PartialEq)]
199pub struct NoneError;
200
201pub trait Try {
202 type Ok;
203 type Error;
204 fn into_result(self) -> Result<Self::Ok, Self::Error>;
205}
206
207impl<T> Try for Option<T> {
208 type Ok = T;
209 type Error = NoneError;
210
211 #[inline]
212 fn into_result(self) -> Result<T, NoneError> {
213 self.ok_or(NoneError)
214 }
215}
216
217impl<T, E> Try for Result<T, E> {
218 type Ok = T;
219 type Error = E;
220
221 #[inline]
222 fn into_result(self) -> Self {
223 self
224 }
225}
diff --git a/embassy-hal-common/src/interrupt.rs b/embassy-hal-common/src/interrupt.rs
new file mode 100644
index 000000000..80b2cad5d
--- /dev/null
+++ b/embassy-hal-common/src/interrupt.rs
@@ -0,0 +1,571 @@
1use core::mem;
2
3macro_rules! prio {
4 ($name:ident, $mask:expr, ($($k:ident = $v:expr,)*)) => {
5 #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
6 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
7 #[repr(u8)]
8 pub enum $name {
9 $($k = $v),*
10 }
11
12 impl From<u8> for $name {
13 fn from(priority: u8) -> Self {
14 unsafe { mem::transmute(priority & $mask) }
15 }
16 }
17
18 impl From<$name> for u8 {
19 fn from(p: $name) -> Self {
20 p as u8
21 }
22 }
23 };
24}
25
26#[rustfmt::skip]
27prio!(Priority0, 0x00, (
28 P0 = 0x0,
29));
30
31#[rustfmt::skip]
32prio!(Priority1, 0x80, (
33 P0 = 0x0,
34 P1 = 0x80,
35));
36
37#[rustfmt::skip]
38prio!(Priority2, 0xc0, (
39 P0 = 0x0,
40 P1 = 0x40,
41 P2 = 0x80,
42 P3 = 0xc0,
43));
44
45#[rustfmt::skip]
46prio!(Priority3, 0xe0, (
47 P0 = 0x0,
48 P1 = 0x20,
49 P2 = 0x40,
50 P3 = 0x60,
51 P4 = 0x80,
52 P5 = 0xa0,
53 P6 = 0xc0,
54 P7 = 0xe0,
55));
56
57#[rustfmt::skip]
58prio!(Priority4, 0xf0, (
59 P0 = 0x0,
60 P1 = 0x10,
61 P2 = 0x20,
62 P3 = 0x30,
63 P4 = 0x40,
64 P5 = 0x50,
65 P6 = 0x60,
66 P7 = 0x70,
67 P8 = 0x80,
68 P9 = 0x90,
69 P10 = 0xa0,
70 P11 = 0xb0,
71 P12 = 0xc0,
72 P13 = 0xd0,
73 P14 = 0xe0,
74 P15 = 0xf0,
75));
76
77#[rustfmt::skip]
78prio!(Priority5, 0xf8, (
79 P0 = 0x0,
80 P1 = 0x8,
81 P2 = 0x10,
82 P3 = 0x18,
83 P4 = 0x20,
84 P5 = 0x28,
85 P6 = 0x30,
86 P7 = 0x38,
87 P8 = 0x40,
88 P9 = 0x48,
89 P10 = 0x50,
90 P11 = 0x58,
91 P12 = 0x60,
92 P13 = 0x68,
93 P14 = 0x70,
94 P15 = 0x78,
95 P16 = 0x80,
96 P17 = 0x88,
97 P18 = 0x90,
98 P19 = 0x98,
99 P20 = 0xa0,
100 P21 = 0xa8,
101 P22 = 0xb0,
102 P23 = 0xb8,
103 P24 = 0xc0,
104 P25 = 0xc8,
105 P26 = 0xd0,
106 P27 = 0xd8,
107 P28 = 0xe0,
108 P29 = 0xe8,
109 P30 = 0xf0,
110 P31 = 0xf8,
111));
112
113#[rustfmt::skip]
114prio!(Priority6, 0xfc, (
115 P0 = 0x0,
116 P1 = 0x4,
117 P2 = 0x8,
118 P3 = 0xc,
119 P4 = 0x10,
120 P5 = 0x14,
121 P6 = 0x18,
122 P7 = 0x1c,
123 P8 = 0x20,
124 P9 = 0x24,
125 P10 = 0x28,
126 P11 = 0x2c,
127 P12 = 0x30,
128 P13 = 0x34,
129 P14 = 0x38,
130 P15 = 0x3c,
131 P16 = 0x40,
132 P17 = 0x44,
133 P18 = 0x48,
134 P19 = 0x4c,
135 P20 = 0x50,
136 P21 = 0x54,
137 P22 = 0x58,
138 P23 = 0x5c,
139 P24 = 0x60,
140 P25 = 0x64,
141 P26 = 0x68,
142 P27 = 0x6c,
143 P28 = 0x70,
144 P29 = 0x74,
145 P30 = 0x78,
146 P31 = 0x7c,
147 P32 = 0x80,
148 P33 = 0x84,
149 P34 = 0x88,
150 P35 = 0x8c,
151 P36 = 0x90,
152 P37 = 0x94,
153 P38 = 0x98,
154 P39 = 0x9c,
155 P40 = 0xa0,
156 P41 = 0xa4,
157 P42 = 0xa8,
158 P43 = 0xac,
159 P44 = 0xb0,
160 P45 = 0xb4,
161 P46 = 0xb8,
162 P47 = 0xbc,
163 P48 = 0xc0,
164 P49 = 0xc4,
165 P50 = 0xc8,
166 P51 = 0xcc,
167 P52 = 0xd0,
168 P53 = 0xd4,
169 P54 = 0xd8,
170 P55 = 0xdc,
171 P56 = 0xe0,
172 P57 = 0xe4,
173 P58 = 0xe8,
174 P59 = 0xec,
175 P60 = 0xf0,
176 P61 = 0xf4,
177 P62 = 0xf8,
178 P63 = 0xfc,
179));
180
181#[rustfmt::skip]
182prio!(Priority7, 0xfe, (
183 P0 = 0x0,
184 P1 = 0x2,
185 P2 = 0x4,
186 P3 = 0x6,
187 P4 = 0x8,
188 P5 = 0xa,
189 P6 = 0xc,
190 P7 = 0xe,
191 P8 = 0x10,
192 P9 = 0x12,
193 P10 = 0x14,
194 P11 = 0x16,
195 P12 = 0x18,
196 P13 = 0x1a,
197 P14 = 0x1c,
198 P15 = 0x1e,
199 P16 = 0x20,
200 P17 = 0x22,
201 P18 = 0x24,
202 P19 = 0x26,
203 P20 = 0x28,
204 P21 = 0x2a,
205 P22 = 0x2c,
206 P23 = 0x2e,
207 P24 = 0x30,
208 P25 = 0x32,
209 P26 = 0x34,
210 P27 = 0x36,
211 P28 = 0x38,
212 P29 = 0x3a,
213 P30 = 0x3c,
214 P31 = 0x3e,
215 P32 = 0x40,
216 P33 = 0x42,
217 P34 = 0x44,
218 P35 = 0x46,
219 P36 = 0x48,
220 P37 = 0x4a,
221 P38 = 0x4c,
222 P39 = 0x4e,
223 P40 = 0x50,
224 P41 = 0x52,
225 P42 = 0x54,
226 P43 = 0x56,
227 P44 = 0x58,
228 P45 = 0x5a,
229 P46 = 0x5c,
230 P47 = 0x5e,
231 P48 = 0x60,
232 P49 = 0x62,
233 P50 = 0x64,
234 P51 = 0x66,
235 P52 = 0x68,
236 P53 = 0x6a,
237 P54 = 0x6c,
238 P55 = 0x6e,
239 P56 = 0x70,
240 P57 = 0x72,
241 P58 = 0x74,
242 P59 = 0x76,
243 P60 = 0x78,
244 P61 = 0x7a,
245 P62 = 0x7c,
246 P63 = 0x7e,
247 P64 = 0x80,
248 P65 = 0x82,
249 P66 = 0x84,
250 P67 = 0x86,
251 P68 = 0x88,
252 P69 = 0x8a,
253 P70 = 0x8c,
254 P71 = 0x8e,
255 P72 = 0x90,
256 P73 = 0x92,
257 P74 = 0x94,
258 P75 = 0x96,
259 P76 = 0x98,
260 P77 = 0x9a,
261 P78 = 0x9c,
262 P79 = 0x9e,
263 P80 = 0xa0,
264 P81 = 0xa2,
265 P82 = 0xa4,
266 P83 = 0xa6,
267 P84 = 0xa8,
268 P85 = 0xaa,
269 P86 = 0xac,
270 P87 = 0xae,
271 P88 = 0xb0,
272 P89 = 0xb2,
273 P90 = 0xb4,
274 P91 = 0xb6,
275 P92 = 0xb8,
276 P93 = 0xba,
277 P94 = 0xbc,
278 P95 = 0xbe,
279 P96 = 0xc0,
280 P97 = 0xc2,
281 P98 = 0xc4,
282 P99 = 0xc6,
283 P100 = 0xc8,
284 P101 = 0xca,
285 P102 = 0xcc,
286 P103 = 0xce,
287 P104 = 0xd0,
288 P105 = 0xd2,
289 P106 = 0xd4,
290 P107 = 0xd6,
291 P108 = 0xd8,
292 P109 = 0xda,
293 P110 = 0xdc,
294 P111 = 0xde,
295 P112 = 0xe0,
296 P113 = 0xe2,
297 P114 = 0xe4,
298 P115 = 0xe6,
299 P116 = 0xe8,
300 P117 = 0xea,
301 P118 = 0xec,
302 P119 = 0xee,
303 P120 = 0xf0,
304 P121 = 0xf2,
305 P122 = 0xf4,
306 P123 = 0xf6,
307 P124 = 0xf8,
308 P125 = 0xfa,
309 P126 = 0xfc,
310 P127 = 0xfe,
311));
312
313#[rustfmt::skip]
314prio!(Priority8, 0xff, (
315 P0 = 0x0,
316 P1 = 0x1,
317 P2 = 0x2,
318 P3 = 0x3,
319 P4 = 0x4,
320 P5 = 0x5,
321 P6 = 0x6,
322 P7 = 0x7,
323 P8 = 0x8,
324 P9 = 0x9,
325 P10 = 0xa,
326 P11 = 0xb,
327 P12 = 0xc,
328 P13 = 0xd,
329 P14 = 0xe,
330 P15 = 0xf,
331 P16 = 0x10,
332 P17 = 0x11,
333 P18 = 0x12,
334 P19 = 0x13,
335 P20 = 0x14,
336 P21 = 0x15,
337 P22 = 0x16,
338 P23 = 0x17,
339 P24 = 0x18,
340 P25 = 0x19,
341 P26 = 0x1a,
342 P27 = 0x1b,
343 P28 = 0x1c,
344 P29 = 0x1d,
345 P30 = 0x1e,
346 P31 = 0x1f,
347 P32 = 0x20,
348 P33 = 0x21,
349 P34 = 0x22,
350 P35 = 0x23,
351 P36 = 0x24,
352 P37 = 0x25,
353 P38 = 0x26,
354 P39 = 0x27,
355 P40 = 0x28,
356 P41 = 0x29,
357 P42 = 0x2a,
358 P43 = 0x2b,
359 P44 = 0x2c,
360 P45 = 0x2d,
361 P46 = 0x2e,
362 P47 = 0x2f,
363 P48 = 0x30,
364 P49 = 0x31,
365 P50 = 0x32,
366 P51 = 0x33,
367 P52 = 0x34,
368 P53 = 0x35,
369 P54 = 0x36,
370 P55 = 0x37,
371 P56 = 0x38,
372 P57 = 0x39,
373 P58 = 0x3a,
374 P59 = 0x3b,
375 P60 = 0x3c,
376 P61 = 0x3d,
377 P62 = 0x3e,
378 P63 = 0x3f,
379 P64 = 0x40,
380 P65 = 0x41,
381 P66 = 0x42,
382 P67 = 0x43,
383 P68 = 0x44,
384 P69 = 0x45,
385 P70 = 0x46,
386 P71 = 0x47,
387 P72 = 0x48,
388 P73 = 0x49,
389 P74 = 0x4a,
390 P75 = 0x4b,
391 P76 = 0x4c,
392 P77 = 0x4d,
393 P78 = 0x4e,
394 P79 = 0x4f,
395 P80 = 0x50,
396 P81 = 0x51,
397 P82 = 0x52,
398 P83 = 0x53,
399 P84 = 0x54,
400 P85 = 0x55,
401 P86 = 0x56,
402 P87 = 0x57,
403 P88 = 0x58,
404 P89 = 0x59,
405 P90 = 0x5a,
406 P91 = 0x5b,
407 P92 = 0x5c,
408 P93 = 0x5d,
409 P94 = 0x5e,
410 P95 = 0x5f,
411 P96 = 0x60,
412 P97 = 0x61,
413 P98 = 0x62,
414 P99 = 0x63,
415 P100 = 0x64,
416 P101 = 0x65,
417 P102 = 0x66,
418 P103 = 0x67,
419 P104 = 0x68,
420 P105 = 0x69,
421 P106 = 0x6a,
422 P107 = 0x6b,
423 P108 = 0x6c,
424 P109 = 0x6d,
425 P110 = 0x6e,
426 P111 = 0x6f,
427 P112 = 0x70,
428 P113 = 0x71,
429 P114 = 0x72,
430 P115 = 0x73,
431 P116 = 0x74,
432 P117 = 0x75,
433 P118 = 0x76,
434 P119 = 0x77,
435 P120 = 0x78,
436 P121 = 0x79,
437 P122 = 0x7a,
438 P123 = 0x7b,
439 P124 = 0x7c,
440 P125 = 0x7d,
441 P126 = 0x7e,
442 P127 = 0x7f,
443 P128 = 0x80,
444 P129 = 0x81,
445 P130 = 0x82,
446 P131 = 0x83,
447 P132 = 0x84,
448 P133 = 0x85,
449 P134 = 0x86,
450 P135 = 0x87,
451 P136 = 0x88,
452 P137 = 0x89,
453 P138 = 0x8a,
454 P139 = 0x8b,
455 P140 = 0x8c,
456 P141 = 0x8d,
457 P142 = 0x8e,
458 P143 = 0x8f,
459 P144 = 0x90,
460 P145 = 0x91,
461 P146 = 0x92,
462 P147 = 0x93,
463 P148 = 0x94,
464 P149 = 0x95,
465 P150 = 0x96,
466 P151 = 0x97,
467 P152 = 0x98,
468 P153 = 0x99,
469 P154 = 0x9a,
470 P155 = 0x9b,
471 P156 = 0x9c,
472 P157 = 0x9d,
473 P158 = 0x9e,
474 P159 = 0x9f,
475 P160 = 0xa0,
476 P161 = 0xa1,
477 P162 = 0xa2,
478 P163 = 0xa3,
479 P164 = 0xa4,
480 P165 = 0xa5,
481 P166 = 0xa6,
482 P167 = 0xa7,
483 P168 = 0xa8,
484 P169 = 0xa9,
485 P170 = 0xaa,
486 P171 = 0xab,
487 P172 = 0xac,
488 P173 = 0xad,
489 P174 = 0xae,
490 P175 = 0xaf,
491 P176 = 0xb0,
492 P177 = 0xb1,
493 P178 = 0xb2,
494 P179 = 0xb3,
495 P180 = 0xb4,
496 P181 = 0xb5,
497 P182 = 0xb6,
498 P183 = 0xb7,
499 P184 = 0xb8,
500 P185 = 0xb9,
501 P186 = 0xba,
502 P187 = 0xbb,
503 P188 = 0xbc,
504 P189 = 0xbd,
505 P190 = 0xbe,
506 P191 = 0xbf,
507 P192 = 0xc0,
508 P193 = 0xc1,
509 P194 = 0xc2,
510 P195 = 0xc3,
511 P196 = 0xc4,
512 P197 = 0xc5,
513 P198 = 0xc6,
514 P199 = 0xc7,
515 P200 = 0xc8,
516 P201 = 0xc9,
517 P202 = 0xca,
518 P203 = 0xcb,
519 P204 = 0xcc,
520 P205 = 0xcd,
521 P206 = 0xce,
522 P207 = 0xcf,
523 P208 = 0xd0,
524 P209 = 0xd1,
525 P210 = 0xd2,
526 P211 = 0xd3,
527 P212 = 0xd4,
528 P213 = 0xd5,
529 P214 = 0xd6,
530 P215 = 0xd7,
531 P216 = 0xd8,
532 P217 = 0xd9,
533 P218 = 0xda,
534 P219 = 0xdb,
535 P220 = 0xdc,
536 P221 = 0xdd,
537 P222 = 0xde,
538 P223 = 0xdf,
539 P224 = 0xe0,
540 P225 = 0xe1,
541 P226 = 0xe2,
542 P227 = 0xe3,
543 P228 = 0xe4,
544 P229 = 0xe5,
545 P230 = 0xe6,
546 P231 = 0xe7,
547 P232 = 0xe8,
548 P233 = 0xe9,
549 P234 = 0xea,
550 P235 = 0xeb,
551 P236 = 0xec,
552 P237 = 0xed,
553 P238 = 0xee,
554 P239 = 0xef,
555 P240 = 0xf0,
556 P241 = 0xf1,
557 P242 = 0xf2,
558 P243 = 0xf3,
559 P244 = 0xf4,
560 P245 = 0xf5,
561 P246 = 0xf6,
562 P247 = 0xf7,
563 P248 = 0xf8,
564 P249 = 0xf9,
565 P250 = 0xfa,
566 P251 = 0xfb,
567 P252 = 0xfc,
568 P253 = 0xfd,
569 P254 = 0xfe,
570 P255 = 0xff,
571));
diff --git a/embassy-hal-common/src/lib.rs b/embassy-hal-common/src/lib.rs
new file mode 100644
index 000000000..7036986ef
--- /dev/null
+++ b/embassy-hal-common/src/lib.rs
@@ -0,0 +1,21 @@
1#![no_std]
2
3// This mod MUST go first, so that the others see its macros.
4pub(crate) mod fmt;
5
6pub mod interrupt;
7mod macros;
8pub mod peripheral;
9pub mod peripheral_shared;
10pub mod ring_buffer;
11pub mod usb;
12
13/// Low power blocking wait loop using WFE/SEV.
14pub fn low_power_wait_until(mut condition: impl FnMut() -> bool) {
15 while !condition() {
16 // WFE might "eat" an event that would have otherwise woken the executor.
17 cortex_m::asm::wfe();
18 }
19 // Retrigger an event to be transparent to the executor.
20 cortex_m::asm::sev();
21}
diff --git a/embassy-hal-common/src/macros.rs b/embassy-hal-common/src/macros.rs
new file mode 100644
index 000000000..771db40f6
--- /dev/null
+++ b/embassy-hal-common/src/macros.rs
@@ -0,0 +1,130 @@
1#[macro_export]
2macro_rules! peripherals {
3 ($($(#[$cfg:meta])? $name:ident),*$(,)?) => {
4 pub mod peripherals {
5 $(
6 $(#[$cfg])?
7 #[allow(non_camel_case_types)]
8 pub struct $name { _private: () }
9
10 $(#[$cfg])?
11 impl embassy::util::Steal for $name {
12 #[inline]
13 unsafe fn steal() -> Self {
14 Self{ _private: ()}
15 }
16 }
17
18 $(#[$cfg])?
19 unsafe impl embassy::util::Unborrow for $name {
20 type Target = $name;
21 #[inline]
22 unsafe fn unborrow(self) -> $name {
23 self
24 }
25 }
26
27 )*
28 }
29
30 #[allow(non_snake_case)]
31 pub struct Peripherals {
32 $(
33 $(#[$cfg])?
34 pub $name: peripherals::$name,
35 )*
36 }
37
38 impl Peripherals {
39 ///Returns all the peripherals *once*
40 #[inline]
41 pub(crate) fn take() -> Self {
42
43 #[no_mangle]
44 static mut _EMBASSY_DEVICE_PERIPHERALS: bool = false;
45
46 critical_section::with(|_| unsafe {
47 if _EMBASSY_DEVICE_PERIPHERALS {
48 panic!("init called more than once!")
49 }
50 _EMBASSY_DEVICE_PERIPHERALS = true;
51 <Self as embassy::util::Steal>::steal()
52 })
53 }
54 }
55
56 impl embassy::util::Steal for Peripherals {
57 #[inline]
58 unsafe fn steal() -> Self {
59 Self {
60 $(
61 $(#[$cfg])?
62 $name: <peripherals::$name as embassy::util::Steal>::steal(),
63 )*
64 }
65 }
66 }
67
68 };
69}
70
71#[macro_export]
72macro_rules! unborrow {
73 ($($name:ident),*) => {
74 $(
75 let mut $name = unsafe { $name.unborrow() };
76 )*
77 }
78}
79
80#[macro_export]
81macro_rules! unsafe_impl_unborrow {
82 ($type:ident) => {
83 unsafe impl ::embassy::util::Unborrow for $type {
84 type Target = $type;
85 #[inline]
86 unsafe fn unborrow(self) -> Self::Target {
87 self
88 }
89 }
90 };
91}
92
93#[macro_export]
94macro_rules! std_peripherals {
95 ($($(#[$cfg:meta])? $name:ident),*$(,)?) => {
96 #[doc = r"All the peripherals"]
97 #[allow(non_snake_case)]
98 pub struct Peripherals {
99 $(
100 $(#[$cfg])?
101 pub $name: pac::$name,
102 )+
103 }
104
105 static mut GLOBAL_CLOCKS: Option<Clocks> = None;
106
107 impl Peripherals {
108 pub fn take() -> Option<(Peripherals, Clocks)> {
109 match unsafe {GLOBAL_CLOCKS.take()} {
110 Some(clocks) => {
111 let dp = unsafe { pac::Peripherals::steal() };
112 let peripherals = Peripherals {
113 $(
114 $(#[$cfg])?
115 $name: dp.$name,
116 )+
117 };
118
119 Some((peripherals, clocks))
120 },
121 None => None,
122 }
123 }
124
125 pub unsafe fn set_peripherals(clocks: Clocks) {
126 GLOBAL_CLOCKS.replace(clocks);
127 }
128 }
129 };
130}
diff --git a/embassy-hal-common/src/peripheral.rs b/embassy-hal-common/src/peripheral.rs
new file mode 100644
index 000000000..92512a0f6
--- /dev/null
+++ b/embassy-hal-common/src/peripheral.rs
@@ -0,0 +1,160 @@
1use core::cell::UnsafeCell;
2use core::marker::{PhantomData, PhantomPinned};
3use core::pin::Pin;
4
5use cortex_m::peripheral::scb::VectActive;
6use cortex_m::peripheral::{NVIC, SCB};
7use embassy::interrupt::{Interrupt, InterruptExt};
8
9/// A type which can be used as state with `PeripheralMutex`.
10///
11/// It needs to be `Send` because `&mut` references are sent back and forth between the 'thread' which owns the `PeripheralMutex` and the interrupt,
12/// and `&mut T` is only `Send` where `T: Send`.
13///
14/// It also requires `'static` to be used safely with `PeripheralMutex::register_interrupt`,
15/// because although `Pin` guarantees that the memory of the state won't be invalidated,
16/// it doesn't guarantee that the lifetime will last.
17pub trait PeripheralState: Send {
18 type Interrupt: Interrupt;
19 fn on_interrupt(&mut self);
20}
21
22pub struct PeripheralMutex<S: PeripheralState> {
23 state: UnsafeCell<S>,
24
25 irq_setup_done: bool,
26 irq: S::Interrupt,
27
28 _not_send: PhantomData<*mut ()>,
29 _pinned: PhantomPinned,
30}
31
32/// Whether `irq` can be preempted by the current interrupt.
33pub(crate) fn can_be_preempted(irq: &impl Interrupt) -> bool {
34 match SCB::vect_active() {
35 // Thread mode can't preempt anything.
36 VectActive::ThreadMode => false,
37 // Exceptions don't always preempt interrupts,
38 // but there isn't much of a good reason to be keeping a `PeripheralMutex` in an exception anyway.
39 VectActive::Exception(_) => true,
40 VectActive::Interrupt { irqn } => {
41 #[derive(Clone, Copy)]
42 struct NrWrap(u16);
43 unsafe impl cortex_m::interrupt::InterruptNumber for NrWrap {
44 fn number(self) -> u16 {
45 self.0
46 }
47 }
48 NVIC::get_priority(NrWrap(irqn.into())) < irq.get_priority().into()
49 }
50 }
51}
52
53impl<S: PeripheralState + 'static> PeripheralMutex<S> {
54 /// Registers `on_interrupt` as the wrapped interrupt's interrupt handler and enables it.
55 ///
56 /// This requires this `PeripheralMutex`'s `PeripheralState` to live for `'static`,
57 /// because `Pin` only guarantees that it's memory won't be repurposed,
58 /// not that it's lifetime will last.
59 ///
60 /// To use non-`'static` `PeripheralState`, use the unsafe `register_interrupt_unchecked`.
61 ///
62 /// Note: `'static` doesn't mean it _has_ to live for the entire program, like an `&'static T`;
63 /// it just means it _can_ live for the entire program - for example, `u8` lives for `'static`.
64 pub fn register_interrupt(self: Pin<&mut Self>) {
65 // SAFETY: `S: 'static`, so there's no way it's lifetime can expire.
66 unsafe { self.register_interrupt_unchecked() }
67 }
68}
69
70impl<S: PeripheralState> PeripheralMutex<S> {
71 /// Create a new `PeripheralMutex` wrapping `irq`, with the initial state `state`.
72 pub fn new(state: S, irq: S::Interrupt) -> Self {
73 if can_be_preempted(&irq) {
74 panic!("`PeripheralMutex` cannot be created in an interrupt with higher priority than the interrupt it wraps");
75 }
76
77 Self {
78 irq,
79 irq_setup_done: false,
80
81 state: UnsafeCell::new(state),
82 _not_send: PhantomData,
83 _pinned: PhantomPinned,
84 }
85 }
86
87 /// Registers `on_interrupt` as the wrapped interrupt's interrupt handler and enables it.
88 ///
89 /// # Safety
90 /// The lifetime of any data in `PeripheralState` that is accessed by the interrupt handler
91 /// must not end without `Drop` being called on this `PeripheralMutex`.
92 ///
93 /// This can be accomplished by either not accessing any data with a lifetime in `on_interrupt`,
94 /// or making sure that nothing like `mem::forget` is used on the `PeripheralMutex`.
95
96 // TODO: this name isn't the best.
97 pub unsafe fn register_interrupt_unchecked(self: Pin<&mut Self>) {
98 let this = self.get_unchecked_mut();
99 if this.irq_setup_done {
100 return;
101 }
102
103 this.irq.disable();
104 this.irq.set_handler(|p| {
105 // Safety: it's OK to get a &mut to the state, since
106 // - We checked that the thread owning the `PeripheralMutex` can't preempt us in `new`.
107 // Interrupts' priorities can only be changed with raw embassy `Interrupts`,
108 // which can't safely store a `PeripheralMutex` across invocations.
109 // - We can't have preempted a with() call because the irq is disabled during it.
110 let state = unsafe { &mut *(p as *mut S) };
111 state.on_interrupt();
112 });
113 this.irq
114 .set_handler_context((&mut this.state) as *mut _ as *mut ());
115 this.irq.enable();
116
117 this.irq_setup_done = true;
118 }
119
120 pub fn with<R>(self: Pin<&mut Self>, f: impl FnOnce(&mut S) -> R) -> R {
121 let this = unsafe { self.get_unchecked_mut() };
122
123 this.irq.disable();
124
125 // Safety: it's OK to get a &mut to the state, since the irq is disabled.
126 let state = unsafe { &mut *this.state.get() };
127 let r = f(state);
128
129 this.irq.enable();
130
131 r
132 }
133
134 /// Returns whether the wrapped interrupt is currently in a pending state.
135 pub fn is_pending(&self) -> bool {
136 self.irq.is_pending()
137 }
138
139 /// Forces the wrapped interrupt into a pending state.
140 pub fn pend(&self) {
141 self.irq.pend()
142 }
143
144 /// Forces the wrapped interrupt out of a pending state.
145 pub fn unpend(&self) {
146 self.irq.unpend()
147 }
148
149 /// Gets the priority of the wrapped interrupt.
150 pub fn priority(&self) -> <S::Interrupt as Interrupt>::Priority {
151 self.irq.get_priority()
152 }
153}
154
155impl<S: PeripheralState> Drop for PeripheralMutex<S> {
156 fn drop(&mut self) {
157 self.irq.disable();
158 self.irq.remove_handler();
159 }
160}
diff --git a/embassy-hal-common/src/peripheral_shared.rs b/embassy-hal-common/src/peripheral_shared.rs
new file mode 100644
index 000000000..71d746341
--- /dev/null
+++ b/embassy-hal-common/src/peripheral_shared.rs
@@ -0,0 +1,122 @@
1use core::marker::{PhantomData, PhantomPinned};
2use core::pin::Pin;
3
4use embassy::interrupt::{Interrupt, InterruptExt};
5
6use crate::peripheral::can_be_preempted;
7
8/// A type which can be used as state with `Peripheral`.
9///
10/// It needs to be `Sync` because references are shared between the 'thread' which owns the `Peripheral` and the interrupt.
11///
12/// It also requires `'static` to be used safely with `Peripheral::register_interrupt`,
13/// because although `Pin` guarantees that the memory of the state won't be invalidated,
14/// it doesn't guarantee that the lifetime will last.
15pub trait PeripheralState: Sync {
16 type Interrupt: Interrupt;
17 fn on_interrupt(&self);
18}
19
20pub struct Peripheral<S: PeripheralState> {
21 state: S,
22
23 irq_setup_done: bool,
24 irq: S::Interrupt,
25
26 _not_send: PhantomData<*mut ()>,
27 _pinned: PhantomPinned,
28}
29
30impl<S: PeripheralState + 'static> Peripheral<S> {
31 /// Registers `on_interrupt` as the wrapped interrupt's interrupt handler and enables it.
32 ///
33 /// This requires this `Peripheral`'s `PeripheralState` to live for `'static`,
34 /// because `Pin` only guarantees that it's memory won't be repurposed,
35 /// not that it's lifetime will last.
36 ///
37 /// To use non-`'static` `PeripheralState`, use the unsafe `register_interrupt_unchecked`.
38 ///
39 /// Note: `'static` doesn't mean it _has_ to live for the entire program, like an `&'static T`;
40 /// it just means it _can_ live for the entire program - for example, `u8` lives for `'static`.
41 pub fn register_interrupt(self: Pin<&mut Self>) {
42 // SAFETY: `S: 'static`, so there's no way it's lifetime can expire.
43 unsafe { self.register_interrupt_unchecked() }
44 }
45}
46
47impl<S: PeripheralState> Peripheral<S> {
48 pub fn new(irq: S::Interrupt, state: S) -> Self {
49 if can_be_preempted(&irq) {
50 panic!("`Peripheral` cannot be created in an interrupt with higher priority than the interrupt it wraps");
51 }
52
53 Self {
54 irq,
55 irq_setup_done: false,
56
57 state,
58 _not_send: PhantomData,
59 _pinned: PhantomPinned,
60 }
61 }
62
63 /// Registers `on_interrupt` as the wrapped interrupt's interrupt handler and enables it.
64 ///
65 /// # Safety
66 /// The lifetime of any data in `PeripheralState` that is accessed by the interrupt handler
67 /// must not end without `Drop` being called on this `Peripheral`.
68 ///
69 /// This can be accomplished by either not accessing any data with a lifetime in `on_interrupt`,
70 /// or making sure that nothing like `mem::forget` is used on the `Peripheral`.
71 pub unsafe fn register_interrupt_unchecked(self: Pin<&mut Self>) {
72 let this = self.get_unchecked_mut();
73 if this.irq_setup_done {
74 return;
75 }
76
77 this.irq.disable();
78 this.irq.set_handler(|p| {
79 // The state can't have been dropped, otherwise the interrupt would have been disabled.
80 // We checked in `new` that the thread owning the `Peripheral` can't preempt the interrupt,
81 // so someone can't have preempted us before this point and dropped the `Peripheral`.
82 let state = unsafe { &*(p as *const S) };
83 state.on_interrupt();
84 });
85 this.irq
86 .set_handler_context((&this.state) as *const _ as *mut ());
87 this.irq.enable();
88
89 this.irq_setup_done = true;
90 }
91
92 pub fn state(self: Pin<&mut Self>) -> &S {
93 &self.into_ref().get_ref().state
94 }
95
96 /// Returns whether the wrapped interrupt is currently in a pending state.
97 pub fn is_pending(&self) -> bool {
98 self.irq.is_pending()
99 }
100
101 /// Forces the wrapped interrupt into a pending state.
102 pub fn pend(&self) {
103 self.irq.pend()
104 }
105
106 /// Forces the wrapped interrupt out of a pending state.
107 pub fn unpend(&self) {
108 self.irq.unpend()
109 }
110
111 /// Gets the priority of the wrapped interrupt.
112 pub fn priority(&self) -> <S::Interrupt as Interrupt>::Priority {
113 self.irq.get_priority()
114 }
115}
116
117impl<S: PeripheralState> Drop for Peripheral<S> {
118 fn drop(&mut self) {
119 self.irq.disable();
120 self.irq.remove_handler();
121 }
122}
diff --git a/embassy-hal-common/src/ring_buffer.rs b/embassy-hal-common/src/ring_buffer.rs
new file mode 100644
index 000000000..18795787f
--- /dev/null
+++ b/embassy-hal-common/src/ring_buffer.rs
@@ -0,0 +1,84 @@
1pub struct RingBuffer<'a> {
2 buf: &'a mut [u8],
3 start: usize,
4 end: usize,
5 empty: bool,
6}
7
8impl<'a> RingBuffer<'a> {
9 pub fn new(buf: &'a mut [u8]) -> Self {
10 Self {
11 buf,
12 start: 0,
13 end: 0,
14 empty: true,
15 }
16 }
17
18 pub fn push_buf(&mut self) -> &mut [u8] {
19 if self.start == self.end && !self.empty {
20 trace!(" ringbuf: push_buf empty");
21 return &mut self.buf[..0];
22 }
23
24 let n = if self.start <= self.end {
25 self.buf.len() - self.end
26 } else {
27 self.start - self.end
28 };
29
30 trace!(" ringbuf: push_buf {:?}..{:?}", self.end, self.end + n);
31 &mut self.buf[self.end..self.end + n]
32 }
33
34 pub fn push(&mut self, n: usize) {
35 trace!(" ringbuf: push {:?}", n);
36 if n == 0 {
37 return;
38 }
39
40 self.end = self.wrap(self.end + n);
41 self.empty = false;
42 }
43
44 pub fn pop_buf(&mut self) -> &mut [u8] {
45 if self.empty {
46 trace!(" ringbuf: pop_buf empty");
47 return &mut self.buf[..0];
48 }
49
50 let n = if self.end <= self.start {
51 self.buf.len() - self.start
52 } else {
53 self.end - self.start
54 };
55
56 trace!(" ringbuf: pop_buf {:?}..{:?}", self.start, self.start + n);
57 &mut self.buf[self.start..self.start + n]
58 }
59
60 pub fn pop(&mut self, n: usize) {
61 trace!(" ringbuf: pop {:?}", n);
62 if n == 0 {
63 return;
64 }
65
66 self.start = self.wrap(self.start + n);
67 self.empty = self.start == self.end;
68 }
69
70 pub fn clear(&mut self) {
71 self.start = 0;
72 self.end = 0;
73 self.empty = true;
74 }
75
76 fn wrap(&self, n: usize) -> usize {
77 assert!(n <= self.buf.len());
78 if n == self.buf.len() {
79 0
80 } else {
81 n
82 }
83 }
84}
diff --git a/embassy-hal-common/src/usb/cdc_acm.rs b/embassy-hal-common/src/usb/cdc_acm.rs
new file mode 100644
index 000000000..5a85b3846
--- /dev/null
+++ b/embassy-hal-common/src/usb/cdc_acm.rs
@@ -0,0 +1,338 @@
1// Copied from https://github.com/mvirkkunen/usbd-serial
2#![allow(dead_code)]
3
4use core::convert::TryInto;
5use core::mem;
6use usb_device::class_prelude::*;
7use usb_device::Result;
8
9/// This should be used as `device_class` when building the `UsbDevice`.
10pub const USB_CLASS_CDC: u8 = 0x02;
11
12const USB_CLASS_CDC_DATA: u8 = 0x0a;
13const CDC_SUBCLASS_ACM: u8 = 0x02;
14const CDC_PROTOCOL_NONE: u8 = 0x00;
15
16const CS_INTERFACE: u8 = 0x24;
17const CDC_TYPE_HEADER: u8 = 0x00;
18const CDC_TYPE_CALL_MANAGEMENT: u8 = 0x01;
19const CDC_TYPE_ACM: u8 = 0x02;
20const CDC_TYPE_UNION: u8 = 0x06;
21
22const REQ_SEND_ENCAPSULATED_COMMAND: u8 = 0x00;
23#[allow(unused)]
24const REQ_GET_ENCAPSULATED_COMMAND: u8 = 0x01;
25const REQ_SET_LINE_CODING: u8 = 0x20;
26const REQ_GET_LINE_CODING: u8 = 0x21;
27const REQ_SET_CONTROL_LINE_STATE: u8 = 0x22;
28
29/// Packet level implementation of a CDC-ACM serial port.
30///
31/// This class can be used directly and it has the least overhead due to directly reading and
32/// writing USB packets with no intermediate buffers, but it will not act like a stream-like serial
33/// port. The following constraints must be followed if you use this class directly:
34///
35/// - `read_packet` must be called with a buffer large enough to hold max_packet_size bytes, and the
36/// method will return a `WouldBlock` error if there is no packet to be read.
37/// - `write_packet` must not be called with a buffer larger than max_packet_size bytes, and the
38/// method will return a `WouldBlock` error if the previous packet has not been sent yet.
39/// - If you write a packet that is exactly max_packet_size bytes long, it won't be processed by the
40/// host operating system until a subsequent shorter packet is sent. A zero-length packet (ZLP)
41/// can be sent if there is no other data to send. This is because USB bulk transactions must be
42/// terminated with a short packet, even if the bulk endpoint is used for stream-like data.
43pub struct CdcAcmClass<'a, B: UsbBus> {
44 comm_if: InterfaceNumber,
45 comm_ep: EndpointIn<'a, B>,
46 data_if: InterfaceNumber,
47 read_ep: EndpointOut<'a, B>,
48 write_ep: EndpointIn<'a, B>,
49 line_coding: LineCoding,
50 dtr: bool,
51 rts: bool,
52}
53
54impl<B: UsbBus> CdcAcmClass<'_, B> {
55 /// Creates a new CdcAcmClass with the provided UsbBus and max_packet_size in bytes. For
56 /// full-speed devices, max_packet_size has to be one of 8, 16, 32 or 64.
57 pub fn new(alloc: &UsbBusAllocator<B>, max_packet_size: u16) -> CdcAcmClass<'_, B> {
58 CdcAcmClass {
59 comm_if: alloc.interface(),
60 comm_ep: alloc.interrupt(8, 255),
61 data_if: alloc.interface(),
62 read_ep: alloc.bulk(max_packet_size),
63 write_ep: alloc.bulk(max_packet_size),
64 line_coding: LineCoding {
65 stop_bits: StopBits::One,
66 data_bits: 8,
67 parity_type: ParityType::None,
68 data_rate: 8_000,
69 },
70 dtr: false,
71 rts: false,
72 }
73 }
74
75 /// Gets the maximum packet size in bytes.
76 pub fn max_packet_size(&self) -> u16 {
77 // The size is the same for both endpoints.
78 self.read_ep.max_packet_size()
79 }
80
81 /// Gets the current line coding. The line coding contains information that's mainly relevant
82 /// for USB to UART serial port emulators, and can be ignored if not relevant.
83 pub fn line_coding(&self) -> &LineCoding {
84 &self.line_coding
85 }
86
87 /// Gets the DTR (data terminal ready) state
88 pub fn dtr(&self) -> bool {
89 self.dtr
90 }
91
92 /// Gets the RTS (request to send) state
93 pub fn rts(&self) -> bool {
94 self.rts
95 }
96
97 /// Writes a single packet into the IN endpoint.
98 pub fn write_packet(&mut self, data: &[u8]) -> Result<usize> {
99 self.write_ep.write(data)
100 }
101
102 /// Reads a single packet from the OUT endpoint.
103 pub fn read_packet(&mut self, data: &mut [u8]) -> Result<usize> {
104 self.read_ep.read(data)
105 }
106
107 /// Gets the address of the IN endpoint.
108 pub fn write_ep_address(&self) -> EndpointAddress {
109 self.write_ep.address()
110 }
111
112 /// Gets the address of the OUT endpoint.
113 pub fn read_ep_address(&self) -> EndpointAddress {
114 self.read_ep.address()
115 }
116}
117
118impl<B: UsbBus> UsbClass<B> for CdcAcmClass<'_, B> {
119 fn get_configuration_descriptors(&self, writer: &mut DescriptorWriter) -> Result<()> {
120 writer.iad(
121 self.comm_if,
122 2,
123 USB_CLASS_CDC,
124 CDC_SUBCLASS_ACM,
125 CDC_PROTOCOL_NONE,
126 )?;
127
128 writer.interface(
129 self.comm_if,
130 USB_CLASS_CDC,
131 CDC_SUBCLASS_ACM,
132 CDC_PROTOCOL_NONE,
133 )?;
134
135 writer.write(
136 CS_INTERFACE,
137 &[
138 CDC_TYPE_HEADER, // bDescriptorSubtype
139 0x10,
140 0x01, // bcdCDC (1.10)
141 ],
142 )?;
143
144 writer.write(
145 CS_INTERFACE,
146 &[
147 CDC_TYPE_ACM, // bDescriptorSubtype
148 0x00, // bmCapabilities
149 ],
150 )?;
151
152 writer.write(
153 CS_INTERFACE,
154 &[
155 CDC_TYPE_UNION, // bDescriptorSubtype
156 self.comm_if.into(), // bControlInterface
157 self.data_if.into(), // bSubordinateInterface
158 ],
159 )?;
160
161 writer.write(
162 CS_INTERFACE,
163 &[
164 CDC_TYPE_CALL_MANAGEMENT, // bDescriptorSubtype
165 0x00, // bmCapabilities
166 self.data_if.into(), // bDataInterface
167 ],
168 )?;
169
170 writer.endpoint(&self.comm_ep)?;
171
172 writer.interface(self.data_if, USB_CLASS_CDC_DATA, 0x00, 0x00)?;
173
174 writer.endpoint(&self.write_ep)?;
175 writer.endpoint(&self.read_ep)?;
176
177 Ok(())
178 }
179
180 fn reset(&mut self) {
181 self.line_coding = LineCoding::default();
182 self.dtr = false;
183 self.rts = false;
184 }
185
186 fn control_in(&mut self, xfer: ControlIn<B>) {
187 let req = xfer.request();
188
189 if !(req.request_type == control::RequestType::Class
190 && req.recipient == control::Recipient::Interface
191 && req.index == u8::from(self.comm_if) as u16)
192 {
193 return;
194 }
195
196 match req.request {
197 // REQ_GET_ENCAPSULATED_COMMAND is not really supported - it will be rejected below.
198 REQ_GET_LINE_CODING if req.length == 7 => {
199 xfer.accept(|data| {
200 data[0..4].copy_from_slice(&self.line_coding.data_rate.to_le_bytes());
201 data[4] = self.line_coding.stop_bits as u8;
202 data[5] = self.line_coding.parity_type as u8;
203 data[6] = self.line_coding.data_bits;
204
205 Ok(7)
206 })
207 .ok();
208 }
209 _ => {
210 xfer.reject().ok();
211 }
212 }
213 }
214
215 fn control_out(&mut self, xfer: ControlOut<B>) {
216 let req = xfer.request();
217
218 if !(req.request_type == control::RequestType::Class
219 && req.recipient == control::Recipient::Interface
220 && req.index == u8::from(self.comm_if) as u16)
221 {
222 return;
223 }
224
225 match req.request {
226 REQ_SEND_ENCAPSULATED_COMMAND => {
227 // We don't actually support encapsulated commands but pretend we do for standards
228 // compatibility.
229 xfer.accept().ok();
230 }
231 REQ_SET_LINE_CODING if xfer.data().len() >= 7 => {
232 self.line_coding.data_rate =
233 u32::from_le_bytes(xfer.data()[0..4].try_into().unwrap());
234 self.line_coding.stop_bits = xfer.data()[4].into();
235 self.line_coding.parity_type = xfer.data()[5].into();
236 self.line_coding.data_bits = xfer.data()[6];
237
238 xfer.accept().ok();
239 }
240 REQ_SET_CONTROL_LINE_STATE => {
241 self.dtr = (req.value & 0x0001) != 0;
242 self.rts = (req.value & 0x0002) != 0;
243
244 xfer.accept().ok();
245 }
246 _ => {
247 xfer.reject().ok();
248 }
249 };
250 }
251}
252
253/// Number of stop bits for LineCoding
254#[derive(Copy, Clone, PartialEq, Eq)]
255pub enum StopBits {
256 /// 1 stop bit
257 One = 0,
258
259 /// 1.5 stop bits
260 OnePointFive = 1,
261
262 /// 2 stop bits
263 Two = 2,
264}
265
266impl From<u8> for StopBits {
267 fn from(value: u8) -> Self {
268 if value <= 2 {
269 unsafe { mem::transmute(value) }
270 } else {
271 StopBits::One
272 }
273 }
274}
275
276/// Parity for LineCoding
277#[derive(Copy, Clone, PartialEq, Eq)]
278pub enum ParityType {
279 None = 0,
280 Odd = 1,
281 Event = 2,
282 Mark = 3,
283 Space = 4,
284}
285
286impl From<u8> for ParityType {
287 fn from(value: u8) -> Self {
288 if value <= 4 {
289 unsafe { mem::transmute(value) }
290 } else {
291 ParityType::None
292 }
293 }
294}
295
296/// Line coding parameters
297///
298/// This is provided by the host for specifying the standard UART parameters such as baud rate. Can
299/// be ignored if you don't plan to interface with a physical UART.
300pub struct LineCoding {
301 stop_bits: StopBits,
302 data_bits: u8,
303 parity_type: ParityType,
304 data_rate: u32,
305}
306
307impl LineCoding {
308 /// Gets the number of stop bits for UART communication.
309 pub fn stop_bits(&self) -> StopBits {
310 self.stop_bits
311 }
312
313 /// Gets the number of data bits for UART communication.
314 pub fn data_bits(&self) -> u8 {
315 self.data_bits
316 }
317
318 /// Gets the parity type for UART communication.
319 pub fn parity_type(&self) -> ParityType {
320 self.parity_type
321 }
322
323 /// Gets the data rate in bits per second for UART communication.
324 pub fn data_rate(&self) -> u32 {
325 self.data_rate
326 }
327}
328
329impl Default for LineCoding {
330 fn default() -> Self {
331 LineCoding {
332 stop_bits: StopBits::One,
333 data_bits: 8,
334 parity_type: ParityType::None,
335 data_rate: 8_000,
336 }
337 }
338}
diff --git a/embassy-hal-common/src/usb/mod.rs b/embassy-hal-common/src/usb/mod.rs
new file mode 100644
index 000000000..1fb501d7f
--- /dev/null
+++ b/embassy-hal-common/src/usb/mod.rs
@@ -0,0 +1,258 @@
1use core::cell::RefCell;
2use core::marker::PhantomData;
3use core::pin::Pin;
4
5use usb_device::bus::UsbBus;
6use usb_device::class::UsbClass;
7use usb_device::device::UsbDevice;
8
9mod cdc_acm;
10pub mod usb_serial;
11
12use crate::peripheral::{PeripheralMutex, PeripheralState};
13use embassy::interrupt::Interrupt;
14use usb_serial::{ReadInterface, UsbSerial, WriteInterface};
15
16/// Marker trait to mark an interrupt to be used with the [`Usb`] abstraction.
17pub unsafe trait USBInterrupt: Interrupt + Send {}
18
19pub(crate) struct State<'bus, B, T, I>
20where
21 B: UsbBus,
22 T: ClassSet<B>,
23 I: USBInterrupt,
24{
25 device: UsbDevice<'bus, B>,
26 pub(crate) classes: T,
27 _interrupt: PhantomData<I>,
28}
29
30pub struct Usb<'bus, B, T, I>
31where
32 B: UsbBus,
33 T: ClassSet<B>,
34 I: USBInterrupt,
35{
36 // Don't you dare moving out `PeripheralMutex`
37 inner: RefCell<PeripheralMutex<State<'bus, B, T, I>>>,
38}
39
40impl<'bus, B, T, I> Usb<'bus, B, T, I>
41where
42 B: UsbBus,
43 T: ClassSet<B>,
44 I: USBInterrupt,
45{
46 pub fn new<S: IntoClassSet<B, T>>(device: UsbDevice<'bus, B>, class_set: S, irq: I) -> Self {
47 let state = State {
48 device,
49 classes: class_set.into_class_set(),
50 _interrupt: PhantomData,
51 };
52 let mutex = PeripheralMutex::new(state, irq);
53 Self {
54 inner: RefCell::new(mutex),
55 }
56 }
57
58 /// # Safety
59 /// The `UsbDevice` passed to `Self::new` must not be dropped without calling `Drop` on this `Usb` first.
60 pub unsafe fn start(self: Pin<&mut Self>) {
61 let this = self.get_unchecked_mut();
62 let mut mutex = this.inner.borrow_mut();
63 let mutex = Pin::new_unchecked(&mut *mutex);
64
65 // Use inner to register the irq
66 // SAFETY: the safety contract of this function makes sure the `UsbDevice` won't be invalidated
67 // without the `PeripheralMutex` being dropped.
68 mutex.register_interrupt_unchecked();
69 }
70}
71
72impl<'bus, 'c, B, T, I> Usb<'bus, B, T, I>
73where
74 B: UsbBus,
75 T: ClassSet<B> + SerialState<'bus, 'c, B, Index0>,
76 I: USBInterrupt,
77{
78 /// Take a serial class that was passed as the first class in a tuple
79 pub fn take_serial_0<'a>(
80 self: Pin<&'a Self>,
81 ) -> (
82 ReadInterface<'a, 'bus, 'c, Index0, B, T, I>,
83 WriteInterface<'a, 'bus, 'c, Index0, B, T, I>,
84 ) {
85 let this = self.get_ref();
86
87 let r = ReadInterface {
88 inner: &this.inner,
89 _buf_lifetime: PhantomData,
90 _index: PhantomData,
91 };
92
93 let w = WriteInterface {
94 inner: &this.inner,
95 _buf_lifetime: PhantomData,
96 _index: PhantomData,
97 };
98 (r, w)
99 }
100}
101
102impl<'bus, 'c, B, T, I> Usb<'bus, B, T, I>
103where
104 B: UsbBus,
105 T: ClassSet<B> + SerialState<'bus, 'c, B, Index1>,
106 I: USBInterrupt,
107{
108 /// Take a serial class that was passed as the second class in a tuple
109 pub fn take_serial_1<'a>(
110 self: Pin<&'a Self>,
111 ) -> (
112 ReadInterface<'a, 'bus, 'c, Index1, B, T, I>,
113 WriteInterface<'a, 'bus, 'c, Index1, B, T, I>,
114 ) {
115 let this = self.get_ref();
116
117 let r = ReadInterface {
118 inner: &this.inner,
119 _buf_lifetime: PhantomData,
120 _index: PhantomData,
121 };
122
123 let w = WriteInterface {
124 inner: &this.inner,
125 _buf_lifetime: PhantomData,
126 _index: PhantomData,
127 };
128 (r, w)
129 }
130}
131
132impl<'bus, B, T, I> PeripheralState for State<'bus, B, T, I>
133where
134 B: UsbBus,
135 T: ClassSet<B>,
136 I: USBInterrupt,
137{
138 type Interrupt = I;
139 fn on_interrupt(&mut self) {
140 self.classes.poll_all(&mut self.device);
141 }
142}
143
144pub trait ClassSet<B: UsbBus>: Send {
145 fn poll_all(&mut self, device: &mut UsbDevice<'_, B>) -> bool;
146}
147
148pub trait IntoClassSet<B: UsbBus, C: ClassSet<B>> {
149 fn into_class_set(self) -> C;
150}
151
152pub struct ClassSet1<B, C1>
153where
154 B: UsbBus,
155 C1: UsbClass<B>,
156{
157 class: C1,
158 _bus: PhantomData<B>,
159}
160
161pub struct ClassSet2<B, C1, C2>
162where
163 B: UsbBus,
164 C1: UsbClass<B>,
165 C2: UsbClass<B>,
166{
167 class1: C1,
168 class2: C2,
169 _bus: PhantomData<B>,
170}
171
172/// The first class into a [`ClassSet`]
173pub struct Index0;
174
175/// The second class into a [`ClassSet`]
176pub struct Index1;
177
178impl<B, C1> ClassSet<B> for ClassSet1<B, C1>
179where
180 B: UsbBus + Send,
181 C1: UsbClass<B> + Send,
182{
183 fn poll_all(&mut self, device: &mut UsbDevice<'_, B>) -> bool {
184 device.poll(&mut [&mut self.class])
185 }
186}
187
188impl<B, C1, C2> ClassSet<B> for ClassSet2<B, C1, C2>
189where
190 B: UsbBus + Send,
191 C1: UsbClass<B> + Send,
192 C2: UsbClass<B> + Send,
193{
194 fn poll_all(&mut self, device: &mut UsbDevice<'_, B>) -> bool {
195 device.poll(&mut [&mut self.class1, &mut self.class2])
196 }
197}
198
199impl<B, C1> IntoClassSet<B, ClassSet1<B, C1>> for C1
200where
201 B: UsbBus + Send,
202 C1: UsbClass<B> + Send,
203{
204 fn into_class_set(self) -> ClassSet1<B, C1> {
205 ClassSet1 {
206 class: self,
207 _bus: PhantomData,
208 }
209 }
210}
211
212impl<B, C1, C2> IntoClassSet<B, ClassSet2<B, C1, C2>> for (C1, C2)
213where
214 B: UsbBus + Send,
215 C1: UsbClass<B> + Send,
216 C2: UsbClass<B> + Send,
217{
218 fn into_class_set(self) -> ClassSet2<B, C1, C2> {
219 ClassSet2 {
220 class1: self.0,
221 class2: self.1,
222 _bus: PhantomData,
223 }
224 }
225}
226
227/// Trait for a USB State that has a serial class inside
228pub trait SerialState<'bus, 'a, B: UsbBus, I> {
229 fn get_serial(&mut self) -> &mut UsbSerial<'bus, 'a, B>;
230}
231
232impl<'bus, 'a, B: UsbBus> SerialState<'bus, 'a, B, Index0>
233 for ClassSet1<B, UsbSerial<'bus, 'a, B>>
234{
235 fn get_serial(&mut self) -> &mut UsbSerial<'bus, 'a, B> {
236 &mut self.class
237 }
238}
239
240impl<'bus, 'a, B, C2> SerialState<'bus, 'a, B, Index0> for ClassSet2<B, UsbSerial<'bus, 'a, B>, C2>
241where
242 B: UsbBus,
243 C2: UsbClass<B>,
244{
245 fn get_serial(&mut self) -> &mut UsbSerial<'bus, 'a, B> {
246 &mut self.class1
247 }
248}
249
250impl<'bus, 'a, B, C1> SerialState<'bus, 'a, B, Index1> for ClassSet2<B, C1, UsbSerial<'bus, 'a, B>>
251where
252 B: UsbBus,
253 C1: UsbClass<B>,
254{
255 fn get_serial(&mut self) -> &mut UsbSerial<'bus, 'a, B> {
256 &mut self.class2
257 }
258}
diff --git a/embassy-hal-common/src/usb/usb_serial.rs b/embassy-hal-common/src/usb/usb_serial.rs
new file mode 100644
index 000000000..a229b2000
--- /dev/null
+++ b/embassy-hal-common/src/usb/usb_serial.rs
@@ -0,0 +1,310 @@
1use core::cell::RefCell;
2use core::marker::{PhantomData, Unpin};
3use core::pin::Pin;
4use core::task::{Context, Poll};
5
6use embassy::io::{self, AsyncBufRead, AsyncWrite};
7use embassy::util::WakerRegistration;
8use usb_device::bus::UsbBus;
9use usb_device::class_prelude::*;
10use usb_device::UsbError;
11
12use super::cdc_acm::CdcAcmClass;
13use crate::peripheral::PeripheralMutex;
14use crate::ring_buffer::RingBuffer;
15use crate::usb::{ClassSet, SerialState, State, USBInterrupt};
16
17pub struct ReadInterface<'a, 'bus, 'c, I, B, T, INT>
18where
19 I: Unpin,
20 B: UsbBus,
21 T: SerialState<'bus, 'c, B, I> + ClassSet<B>,
22 INT: USBInterrupt,
23{
24 // Don't you dare moving out `PeripheralMutex`
25 pub(crate) inner: &'a RefCell<PeripheralMutex<State<'bus, B, T, INT>>>,
26 pub(crate) _buf_lifetime: PhantomData<&'c T>,
27 pub(crate) _index: PhantomData<I>,
28}
29
30/// Write interface for USB CDC_ACM
31///
32/// This interface is buffered, meaning that after the write returns the bytes might not be fully
33/// on the wire just yet
34pub struct WriteInterface<'a, 'bus, 'c, I, B, T, INT>
35where
36 I: Unpin,
37 B: UsbBus,
38 T: SerialState<'bus, 'c, B, I> + ClassSet<B>,
39 INT: USBInterrupt,
40{
41 // Don't you dare moving out `PeripheralMutex`
42 pub(crate) inner: &'a RefCell<PeripheralMutex<State<'bus, B, T, INT>>>,
43 pub(crate) _buf_lifetime: PhantomData<&'c T>,
44 pub(crate) _index: PhantomData<I>,
45}
46
47impl<'a, 'bus, 'c, I, B, T, INT> AsyncBufRead for ReadInterface<'a, 'bus, 'c, I, B, T, INT>
48where
49 I: Unpin,
50 B: UsbBus,
51 T: SerialState<'bus, 'c, B, I> + ClassSet<B>,
52 INT: USBInterrupt,
53{
54 fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<&[u8]>> {
55 let this = self.get_mut();
56 let mut mutex = this.inner.borrow_mut();
57 let mutex = unsafe { Pin::new_unchecked(&mut *mutex) };
58 mutex.with(|state| {
59 let serial = state.classes.get_serial();
60 let serial = Pin::new(serial);
61
62 match serial.poll_fill_buf(cx) {
63 Poll::Ready(Ok(buf)) => {
64 let buf: &[u8] = buf;
65 // NOTE(unsafe) This part of the buffer won't be modified until the user calls
66 // consume, which will invalidate this ref
67 let buf: &[u8] = unsafe { core::mem::transmute(buf) };
68 Poll::Ready(Ok(buf))
69 }
70 Poll::Ready(Err(_)) => Poll::Ready(Err(io::Error::Other)),
71 Poll::Pending => Poll::Pending,
72 }
73 })
74 }
75
76 fn consume(self: Pin<&mut Self>, amt: usize) {
77 let this = self.get_mut();
78 let mut mutex = this.inner.borrow_mut();
79 let mutex = unsafe { Pin::new_unchecked(&mut *mutex) };
80 mutex.with(|state| {
81 let serial = state.classes.get_serial();
82 let serial = Pin::new(serial);
83
84 serial.consume(amt);
85 })
86 }
87}
88
89impl<'a, 'bus, 'c, I, B, T, INT> AsyncWrite for WriteInterface<'a, 'bus, 'c, I, B, T, INT>
90where
91 I: Unpin,
92 B: UsbBus,
93 T: SerialState<'bus, 'c, B, I> + ClassSet<B>,
94 INT: USBInterrupt,
95{
96 fn poll_write(
97 self: Pin<&mut Self>,
98 cx: &mut Context<'_>,
99 buf: &[u8],
100 ) -> Poll<io::Result<usize>> {
101 let this = self.get_mut();
102 let mut mutex = this.inner.borrow_mut();
103 let mutex = unsafe { Pin::new_unchecked(&mut *mutex) };
104 mutex.with(|state| {
105 let serial = state.classes.get_serial();
106 let serial = Pin::new(serial);
107
108 serial.poll_write(cx, buf)
109 })
110 }
111}
112
113pub struct UsbSerial<'bus, 'a, B: UsbBus> {
114 inner: CdcAcmClass<'bus, B>,
115 read_buf: RingBuffer<'a>,
116 write_buf: RingBuffer<'a>,
117 read_waker: WakerRegistration,
118 write_waker: WakerRegistration,
119 write_state: WriteState,
120 read_error: bool,
121 write_error: bool,
122}
123
124impl<'bus, 'a, B: UsbBus> AsyncBufRead for UsbSerial<'bus, 'a, B> {
125 fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<&[u8]>> {
126 let this = self.get_mut();
127
128 if this.read_error {
129 this.read_error = false;
130 return Poll::Ready(Err(io::Error::Other));
131 }
132
133 let buf = this.read_buf.pop_buf();
134 if buf.is_empty() {
135 this.read_waker.register(cx.waker());
136 return Poll::Pending;
137 }
138 Poll::Ready(Ok(buf))
139 }
140
141 fn consume(self: Pin<&mut Self>, amt: usize) {
142 self.get_mut().read_buf.pop(amt);
143 }
144}
145
146impl<'bus, 'a, B: UsbBus> AsyncWrite for UsbSerial<'bus, 'a, B> {
147 fn poll_write(
148 self: Pin<&mut Self>,
149 cx: &mut Context<'_>,
150 buf: &[u8],
151 ) -> Poll<io::Result<usize>> {
152 let this = self.get_mut();
153
154 if this.write_error {
155 this.write_error = false;
156 return Poll::Ready(Err(io::Error::Other));
157 }
158
159 let write_buf = this.write_buf.push_buf();
160 if write_buf.is_empty() {
161 this.write_waker.register(cx.waker());
162 return Poll::Pending;
163 }
164
165 let count = write_buf.len().min(buf.len());
166 write_buf[..count].copy_from_slice(&buf[..count]);
167 this.write_buf.push(count);
168
169 this.flush_write();
170 Poll::Ready(Ok(count))
171 }
172}
173
174/// Keeps track of the type of the last written packet.
175enum WriteState {
176 /// No packets in-flight
177 Idle,
178
179 /// Short packet currently in-flight
180 Short,
181
182 /// Full packet current in-flight. A full packet must be followed by a short packet for the host
183 /// OS to see the transaction. The data is the number of subsequent full packets sent so far. A
184 /// short packet is forced every SHORT_PACKET_INTERVAL packets so that the OS sees data in a
185 /// timely manner.
186 Full(usize),
187}
188
189impl<'bus, 'a, B: UsbBus> UsbSerial<'bus, 'a, B> {
190 pub fn new(
191 alloc: &'bus UsbBusAllocator<B>,
192 read_buf: &'a mut [u8],
193 write_buf: &'a mut [u8],
194 ) -> Self {
195 Self {
196 inner: CdcAcmClass::new(alloc, 64),
197 read_buf: RingBuffer::new(read_buf),
198 write_buf: RingBuffer::new(write_buf),
199 read_waker: WakerRegistration::new(),
200 write_waker: WakerRegistration::new(),
201 write_state: WriteState::Idle,
202 read_error: false,
203 write_error: false,
204 }
205 }
206
207 fn flush_write(&mut self) {
208 /// If this many full size packets have been sent in a row, a short packet will be sent so that the
209 /// host sees the data in a timely manner.
210 const SHORT_PACKET_INTERVAL: usize = 10;
211
212 let full_size_packets = match self.write_state {
213 WriteState::Full(c) => c,
214 _ => 0,
215 };
216
217 let ep_size = self.inner.max_packet_size() as usize;
218 let max_size = if full_size_packets > SHORT_PACKET_INTERVAL {
219 ep_size - 1
220 } else {
221 ep_size
222 };
223
224 let buf = {
225 let buf = self.write_buf.pop_buf();
226 if buf.len() > max_size {
227 &buf[..max_size]
228 } else {
229 buf
230 }
231 };
232
233 if !buf.is_empty() {
234 let count = match self.inner.write_packet(buf) {
235 Ok(c) => c,
236 Err(UsbError::WouldBlock) => 0,
237 Err(_) => {
238 self.write_error = true;
239 return;
240 }
241 };
242
243 if buf.len() == ep_size {
244 self.write_state = WriteState::Full(full_size_packets + 1);
245 } else {
246 self.write_state = WriteState::Short;
247 }
248 self.write_buf.pop(count);
249 } else if full_size_packets > 0 {
250 if let Err(e) = self.inner.write_packet(&[]) {
251 if !matches!(e, UsbError::WouldBlock) {
252 self.write_error = true;
253 }
254 return;
255 }
256 self.write_state = WriteState::Idle;
257 }
258 }
259}
260
261impl<B> UsbClass<B> for UsbSerial<'_, '_, B>
262where
263 B: UsbBus,
264{
265 fn get_configuration_descriptors(&self, writer: &mut DescriptorWriter) -> Result<(), UsbError> {
266 self.inner.get_configuration_descriptors(writer)
267 }
268
269 fn reset(&mut self) {
270 self.inner.reset();
271 self.read_buf.clear();
272 self.write_buf.clear();
273 self.write_state = WriteState::Idle;
274 }
275
276 fn endpoint_in_complete(&mut self, addr: EndpointAddress) {
277 if addr == self.inner.write_ep_address() {
278 self.write_waker.wake();
279
280 self.flush_write();
281 }
282 }
283
284 fn endpoint_out(&mut self, addr: EndpointAddress) {
285 if addr == self.inner.read_ep_address() {
286 let buf = self.read_buf.push_buf();
287 let count = match self.inner.read_packet(buf) {
288 Ok(c) => c,
289 Err(UsbError::WouldBlock) => 0,
290 Err(_) => {
291 self.read_error = true;
292 return;
293 }
294 };
295
296 if count > 0 {
297 self.read_buf.push(count);
298 self.read_waker.wake();
299 }
300 }
301 }
302
303 fn control_in(&mut self, xfer: ControlIn<B>) {
304 self.inner.control_in(xfer);
305 }
306
307 fn control_out(&mut self, xfer: ControlOut<B>) {
308 self.inner.control_out(xfer);
309 }
310}