embassy_usb_host/
handler.rs1#![allow(missing_docs)]
3
4use embassy_usb_driver::Speed;
5use embassy_usb_driver::host::pipe::{self, IsIn, IsOut};
6use embassy_usb_driver::host::{HostError, SplitInfo, SplitSpeed, UsbPipe};
7
8use crate::control::ControlPipeExt;
9use crate::descriptor::{ConfigurationDescriptor, DeviceDescriptor, USBDescriptor};
10
11#[derive(Copy, Clone, Eq, PartialEq, Debug)]
18#[cfg_attr(feature = "defmt", derive(defmt::Format))]
19pub enum BusRoute {
20 Direct(Speed),
25
26 Translated(SplitInfo),
31}
32
33impl BusRoute {
34 pub const fn device_speed(self) -> Speed {
36 match self {
37 BusRoute::Direct(s) => s,
38 BusRoute::Translated(info) => match info.device_speed() {
39 SplitSpeed::Low => Speed::Low,
40 SplitSpeed::Full => Speed::Full,
41 },
42 }
43 }
44
45 pub const fn split(self) -> Option<SplitInfo> {
48 match self {
49 BusRoute::Direct(_) => None,
50 BusRoute::Translated(info) => Some(info),
51 }
52 }
53}
54
55#[derive(Clone, Copy, Debug)]
57#[cfg_attr(feature = "defmt", derive(defmt::Format))]
58pub struct EnumerationInfo {
59 pub device_address: u8,
61 pub route: BusRoute,
64 pub device_desc: DeviceDescriptor,
66}
67
68impl EnumerationInfo {
69 pub const fn speed(&self) -> Speed {
71 self.route.device_speed()
72 }
73
74 pub const fn split(&self) -> Option<SplitInfo> {
79 self.route.split()
80 }
81}
82
83impl EnumerationInfo {
84 pub async fn active_config_or_set_default<'a, D: IsIn + IsOut, C: UsbPipe<pipe::Control, D>>(
86 &self,
87 channel: &mut C,
88 cfg_desc_buf: &'a mut [u8],
89 ) -> Result<ConfigurationDescriptor<'a>, HostError> {
90 Ok(match channel.active_configuration_value().await? {
91 Some(_) => self.get_active_configuration(channel, cfg_desc_buf).await?.unwrap(),
92 None => {
93 let default_cfg = self.get_configuration(0, channel, cfg_desc_buf).await?;
94 channel.set_configuration(default_cfg.configuration_value).await?;
95 default_cfg
96 }
97 })
98 }
99
100 pub async fn get_active_configuration<'a, D: IsIn, C: UsbPipe<pipe::Control, D>>(
102 &self,
103 channel: &mut C,
104 cfg_desc_buf: &'a mut [u8],
105 ) -> Result<Option<ConfigurationDescriptor<'a>>, HostError> {
106 let cfg_id = match channel.active_configuration_value().await? {
107 Some(v) => v.into(),
108 None => return Ok(None),
109 };
110
111 let mut index = None;
112 let mut cfg_len = 0;
113 for i in 0..self.device_desc.num_configurations {
114 let cfg_desc_short = channel
115 .request_descriptor::<ConfigurationDescriptor, { ConfigurationDescriptor::SIZE }>(i, false)
116 .await?;
117
118 if cfg_desc_short.configuration_value == cfg_id {
119 if cfg_desc_short.total_len as usize > cfg_desc_buf.len() {
120 return Err(HostError::InsufficientMemory);
121 }
122 cfg_len = cfg_desc_short.total_len as usize;
123 index.replace(i);
124 break;
125 }
126 }
127
128 let index = index.ok_or(HostError::Other("Active configuration not found on device"))?;
129 let dest = &mut cfg_desc_buf[0..cfg_len];
130 channel
131 .request_descriptor_bytes(ConfigurationDescriptor::DESC_TYPE, index, dest)
132 .await?;
133
134 let cfg = ConfigurationDescriptor::try_from_slice(cfg_desc_buf).map_err(|_| HostError::InvalidDescriptor)?;
135 Ok(Some(cfg))
136 }
137
138 pub async fn get_configuration<'a, D: pipe::IsIn, C: UsbPipe<pipe::Control, D>>(
140 &self,
141 index: u8,
142 channel: &mut C,
143 cfg_desc_buf: &'a mut [u8],
144 ) -> Result<ConfigurationDescriptor<'a>, HostError> {
145 if index >= self.device_desc.num_configurations {
146 return Err(HostError::InvalidDescriptor);
147 }
148
149 let cfg_desc_short = channel
150 .request_descriptor::<ConfigurationDescriptor, { ConfigurationDescriptor::SIZE }>(index, false)
151 .await?;
152
153 let total_len = cfg_desc_short.total_len as usize;
154 if total_len > cfg_desc_buf.len() {
155 return Err(HostError::InsufficientMemory);
156 }
157 let dest = &mut cfg_desc_buf[0..total_len];
158 channel
159 .request_descriptor_bytes(ConfigurationDescriptor::DESC_TYPE, index, dest)
160 .await?;
161
162 trace!(
163 "Full Configuration Descriptor [{}]: {:?}",
164 cfg_desc_short.total_len, dest
165 );
166
167 ConfigurationDescriptor::try_from_slice(dest).map_err(|_| HostError::InvalidDescriptor)
168 }
169}
170
171#[derive(Copy, Clone, Eq, PartialEq, Debug)]
172#[cfg_attr(feature = "defmt", derive(defmt::Format))]
173pub enum HandlerEvent<T> {
174 NoChange,
175 HandlerDisconnected,
176 HandlerEvent(T),
177}
178
179#[derive(Copy, Clone, Eq, PartialEq, Debug)]
180#[cfg_attr(feature = "defmt", derive(defmt::Format))]
181pub enum RegisterError {
182 NoSupportedInterface,
183 InvalidDescriptor,
184 HostError(HostError),
185}
186
187impl From<HostError> for RegisterError {
188 fn from(value: HostError) -> Self {
189 RegisterError::HostError(value)
190 }
191}