1use core::num::NonZeroU8;
4
5use embassy_usb::control::Request;
6use embassy_usb_driver::Direction;
7pub use embassy_usb_driver::host::pipe;
8use embassy_usb_driver::host::{HostError, UsbPipe};
9
10use crate::descriptor::{USBDescriptor, descriptor_type};
11
12#[repr(u8)]
18#[derive(Copy, Clone, Eq, PartialEq, Debug)]
19#[cfg_attr(feature = "defmt", derive(defmt::Format))]
20pub enum Recipient {
21 Device = 0,
23 Interface = 1,
25 Endpoint = 2,
27 Other = 3,
29 Reserved = 4,
31}
32
33#[repr(u8)]
39#[derive(Copy, Clone, Eq, PartialEq, Debug)]
40#[cfg_attr(feature = "defmt", derive(defmt::Format))]
41pub enum ControlType {
42 Standard = 0,
44 Class = 1,
46 Vendor = 2,
48 Reserved = 3,
50}
51
52#[derive(Copy, Clone, Eq, PartialEq, Debug)]
57#[cfg_attr(feature = "defmt", derive(defmt::Format))]
58pub struct RequestType {
59 pub direction: Direction,
61
62 pub control_type: ControlType,
64
65 pub recipient: Recipient,
67}
68
69impl RequestType {
70 pub const fn to_bits(self) -> u8 {
72 let d = match self.direction {
73 Direction::Out => 0,
74 Direction::In => 1 << 7,
75 };
76 let t = (self.control_type as u8) << 5;
77 let r = self.recipient as u8;
78 d | t | r
79 }
80
81 pub const fn from_bits(b: u8) -> Self {
86 let direction = if b & 0x80 != 0 { Direction::In } else { Direction::Out };
87 let control_type = match (b >> 5) & 0b11 {
88 0 => ControlType::Standard,
89 1 => ControlType::Class,
90 2 => ControlType::Vendor,
91 _ => ControlType::Reserved,
92 };
93 let recipient = match b & 0b1_1111 {
94 0 => Recipient::Device,
95 1 => Recipient::Interface,
96 2 => Recipient::Endpoint,
97 3 => Recipient::Other,
98 _ => Recipient::Reserved,
99 };
100 Self {
101 direction,
102 control_type,
103 recipient,
104 }
105 }
106}
107
108#[cfg_attr(feature = "defmt", derive(defmt::Format))]
115#[derive(Copy, Clone, Eq, PartialEq, Debug)]
116pub struct SetupPacket {
117 pub request_type: RequestType,
121
122 pub request: u8,
126
127 pub value: u16,
129
130 pub index: u16,
132
133 pub length: u16,
135}
136
137const HID_REPORT_DESCRIPTOR_TYPE: u8 = 0x22;
139
140impl SetupPacket {
141 pub const fn to_bytes(self) -> [u8; 8] {
146 let v = self.value.to_le_bytes();
147 let i = self.index.to_le_bytes();
148 let l = self.length.to_le_bytes();
149 [
150 self.request_type.to_bits(),
151 self.request,
152 v[0],
153 v[1],
154 i[0],
155 i[1],
156 l[0],
157 l[1],
158 ]
159 }
160
161 pub const fn from_bytes(wire: [u8; 8]) -> Self {
166 Self {
167 request_type: RequestType::from_bits(wire[0]),
168 request: wire[1],
169 value: u16::from_le_bytes([wire[2], wire[3]]),
170 index: u16::from_le_bytes([wire[4], wire[5]]),
171 length: u16::from_le_bytes([wire[6], wire[7]]),
172 }
173 }
174
175 pub const fn get_descriptor(class: bool, desc_type: u8, index: u8, max_len: u16) -> Self {
179 Self {
180 request_type: RequestType {
181 direction: Direction::In,
182 control_type: if class {
183 ControlType::Class
184 } else {
185 ControlType::Standard
186 },
187 recipient: Recipient::Device,
188 },
189 request: Request::GET_DESCRIPTOR,
190 value: ((desc_type as u16) << 8) | index as u16,
191 index: 0,
192 length: max_len,
193 }
194 }
195
196 pub const fn get_device_descriptor(max_len: u16) -> Self {
198 Self::get_descriptor(false, descriptor_type::DEVICE, 0, max_len)
199 }
200
201 pub const fn get_config_descriptor(index: u8, max_len: u16) -> Self {
203 Self::get_descriptor(false, descriptor_type::CONFIGURATION, index, max_len)
204 }
205
206 pub const fn get_interface_descriptor(desc_type: u8, interface: u16, max_len: u16) -> Self {
210 Self {
211 request_type: RequestType {
212 direction: Direction::In,
213 control_type: ControlType::Standard,
214 recipient: Recipient::Interface,
215 },
216 request: Request::GET_DESCRIPTOR,
217 value: (desc_type as u16) << 8,
218 index: interface,
219 length: max_len,
220 }
221 }
222
223 pub const fn get_hid_report_descriptor(interface: u8, len: u16) -> Self {
227 Self::get_interface_descriptor(HID_REPORT_DESCRIPTOR_TYPE, interface as u16, len)
228 }
229
230 pub const fn set_address(address: u8) -> Self {
232 Self {
233 request_type: RequestType {
234 direction: Direction::Out,
235 control_type: ControlType::Standard,
236 recipient: Recipient::Device,
237 },
238 request: Request::SET_ADDRESS,
239 value: address as u16,
240 index: 0,
241 length: 0,
242 }
243 }
244
245 pub const fn set_configuration(config_value: u8) -> Self {
247 Self {
248 request_type: RequestType {
249 direction: Direction::Out,
250 control_type: ControlType::Standard,
251 recipient: Recipient::Device,
252 },
253 request: Request::SET_CONFIGURATION,
254 value: config_value as u16,
255 index: 0,
256 length: 0,
257 }
258 }
259
260 pub const fn get_configuration() -> Self {
262 Self {
263 request_type: RequestType {
264 direction: Direction::In,
265 control_type: ControlType::Standard,
266 recipient: Recipient::Device,
267 },
268 request: Request::GET_CONFIGURATION,
269 value: 0,
270 index: 0,
271 length: 1,
272 }
273 }
274
275 pub const fn class_interface_out(request: u8, value: u16, interface: u16, length: u16) -> Self {
279 Self {
280 request_type: RequestType {
281 direction: Direction::Out,
282 control_type: ControlType::Class,
283 recipient: Recipient::Interface,
284 },
285 request,
286 value,
287 index: interface,
288 length,
289 }
290 }
291
292 pub const fn class_interface_in(request: u8, value: u16, interface: u16, length: u16) -> Self {
294 Self {
295 request_type: RequestType {
296 direction: Direction::In,
297 control_type: ControlType::Class,
298 recipient: Recipient::Interface,
299 },
300 request,
301 value,
302 index: interface,
303 length,
304 }
305 }
306
307 pub const fn vendor_interface_out(request: u8, value: u16, interface: u16, length: u16) -> Self {
309 Self {
310 request_type: RequestType {
311 direction: Direction::Out,
312 control_type: ControlType::Vendor,
313 recipient: Recipient::Interface,
314 },
315 request,
316 value,
317 index: interface,
318 length,
319 }
320 }
321
322 pub const fn vendor_interface_in(request: u8, value: u16, interface: u16, length: u16) -> Self {
324 Self {
325 request_type: RequestType {
326 direction: Direction::In,
327 control_type: ControlType::Vendor,
328 recipient: Recipient::Interface,
329 },
330 request,
331 value,
332 index: interface,
333 length,
334 }
335 }
336}
337
338pub trait ControlPipeExt<D: pipe::Direction>: UsbPipe<pipe::Control, D> {
342 async fn request_descriptor<T: USBDescriptor, const SIZE: usize>(
344 &mut self,
345 index: u8,
346 class: bool,
347 ) -> Result<T, HostError>
348 where
349 D: pipe::IsIn,
350 {
351 let mut buf = [0u8; SIZE];
352 let setup = SetupPacket::get_descriptor(class, T::DESC_TYPE, index, SIZE as u16);
353 self.control_in(&setup.to_bytes(), &mut buf).await?;
354 trace!("Descriptor {}: {:?}", core::any::type_name::<T>(), buf);
355 T::try_from_bytes(&buf).map_err(|_| HostError::InvalidDescriptor)
356 }
357
358 async fn request_descriptor_bytes(&mut self, desc_type: u8, index: u8, buf: &mut [u8]) -> Result<usize, HostError>
360 where
361 D: pipe::IsIn,
362 {
363 let setup = SetupPacket::get_descriptor(false, desc_type, index, buf.len() as u16);
364 self.control_in(&setup.to_bytes(), buf)
365 .await
366 .map_err(HostError::PipeError)
367 }
368
369 async fn interface_request_descriptor_bytes<T: USBDescriptor>(
371 &mut self,
372 interface_num: u8,
373 buf: &mut [u8],
374 ) -> Result<usize, HostError>
375 where
376 D: pipe::IsIn,
377 {
378 let setup = SetupPacket::get_interface_descriptor(T::DESC_TYPE, interface_num as u16, buf.len() as u16);
379 self.control_in(&setup.to_bytes(), buf)
380 .await
381 .map_err(HostError::PipeError)
382 }
383
384 async fn active_configuration_value(&mut self) -> Result<Option<NonZeroU8>, HostError>
386 where
387 D: pipe::IsIn,
388 {
389 let setup = SetupPacket::get_configuration();
390 let mut buf = [0u8; 1];
391 self.control_in(&setup.to_bytes(), &mut buf).await?;
392 Ok(NonZeroU8::new(buf[0]))
393 }
394
395 async fn set_configuration(&mut self, config_no: u8) -> Result<(), HostError>
397 where
398 D: pipe::IsOut,
399 {
400 let setup = SetupPacket::set_configuration(config_no);
401 self.control_out(&setup.to_bytes(), &[]).await?;
402 Ok(())
403 }
404
405 async fn device_set_address(&mut self, new_addr: u8) -> Result<(), HostError>
410 where
411 D: pipe::IsOut,
412 {
413 let setup = SetupPacket::set_address(new_addr);
414 self.control_out(&setup.to_bytes(), &[]).await?;
415 Ok(())
416 }
417
418 async fn class_request_out(&mut self, request: u8, value: u16, index: u16, buf: &[u8]) -> Result<(), HostError>
420 where
421 D: pipe::IsOut,
422 {
423 let setup = SetupPacket::class_interface_out(request, value, index, buf.len() as u16);
424 self.control_out(&setup.to_bytes(), buf).await?;
425 Ok(())
426 }
427}
428
429impl<D: pipe::Direction, C> ControlPipeExt<D> for C where C: UsbPipe<pipe::Control, D> {}
430
431#[cfg(test)]
432mod tests {
433 use super::*;
434
435 #[test]
436 fn roundtrip_setup_packet() {
437 let directions = [Direction::In, Direction::Out];
438 let control_types = [ControlType::Standard, ControlType::Class, ControlType::Vendor];
439 let recipients = [
440 Recipient::Device,
441 Recipient::Interface,
442 Recipient::Endpoint,
443 Recipient::Other,
444 ];
445 for direction in directions {
446 for control_type in control_types {
447 for recipient in recipients {
448 let setup = SetupPacket {
449 request_type: RequestType {
450 direction,
451 control_type,
452 recipient,
453 },
454 request: 0x11,
455 value: 0x2233,
456 index: 0x4455,
457 length: 0x6677,
458 };
459 let bytes = setup.to_bytes();
460 assert!(setup == SetupPacket::from_bytes(bytes));
461 }
462 }
463 }
464 }
465}