1use std::time::Duration;
2
3use dfu_core::{
4 asynchronous::DfuAsyncIo, functional_descriptor::FunctionalDescriptor, DfuIo, DfuProtocol,
5};
6use nusb::transfer::{Control, ControlIn, ControlOut, ControlType, Recipient, TransferError};
7use thiserror::Error;
8
9pub type DfuASync = dfu_core::asynchronous::DfuASync<DfuNusb, Error>;
10pub type DfuSync = dfu_core::sync::DfuSync<DfuNusb, Error>;
11
12#[derive(Debug, Error)]
13pub enum Error {
14 #[error("Device not found")]
15 DeviceNotFound,
16 #[error("Functional Desciptor not found")]
17 FunctionalDescriptorNotFound,
18 #[error("Alternative setting not found")]
19 AltSettingNotFound,
20 #[error(transparent)]
21 FunctionalDescriptor(#[from] dfu_core::functional_descriptor::Error),
22 #[error(transparent)]
23 Dfu(#[from] dfu_core::Error),
24 #[error(transparent)]
25 Nusb(#[from] nusb::Error),
26 #[error(transparent)]
27 Transfer(#[from] TransferError),
28}
29
30pub struct DfuNusb {
31 device: nusb::Device,
32 interface: nusb::Interface,
33 descriptor: FunctionalDescriptor,
34 protocol: dfu_core::DfuProtocol<dfu_core::memory_layout::MemoryLayout>,
35}
36
37impl DfuNusb {
38 pub fn open(device: nusb::Device, interface: nusb::Interface, alt: u8) -> Result<Self, Error> {
40 interface.set_alt_setting(alt)?;
41 let descriptor = interface
42 .descriptors()
43 .find_map(|alt| {
44 alt.descriptors()
45 .find_map(|d| FunctionalDescriptor::from_bytes(&d))
46 })
47 .ok_or(Error::FunctionalDescriptorNotFound)??;
48 let alt = interface
49 .descriptors()
50 .find(|a| a.alternate_setting() == alt)
51 .ok_or(Error::AltSettingNotFound)?;
52
53 let s = if let Some(index) = alt.string_index() {
54 let lang = device
55 .get_string_descriptor_supported_languages(Duration::from_secs(3))?
56 .next()
57 .unwrap_or_default();
58 device
59 .get_string_descriptor(index, lang, Duration::from_secs(3))
60 .unwrap_or_default()
61 } else {
62 String::new()
63 };
64 let protocol = DfuProtocol::new(&s, descriptor.dfu_version)?;
65
66 Ok(Self {
67 device,
68 interface,
69 descriptor,
70 protocol,
71 })
72 }
73
74 pub fn into_async_dfu(self) -> DfuASync {
76 DfuASync::new(self)
77 }
78
79 pub fn into_sync_dfu(self) -> DfuSync {
81 DfuSync::new(self)
82 }
83}
84
85fn split_request_type(request_type: u8) -> (ControlType, Recipient) {
86 (
87 match request_type >> 5 & 0x03 {
88 0 => ControlType::Standard,
89 1 => ControlType::Class,
90 2 => ControlType::Vendor,
91 _ => ControlType::Standard,
92 },
93 match request_type & 0x1f {
94 0 => Recipient::Device,
95 1 => Recipient::Interface,
96 2 => Recipient::Endpoint,
97 3 => Recipient::Other,
98 _ => Recipient::Device,
99 },
100 )
101}
102
103impl DfuIo for DfuNusb {
104 type Read = usize;
105 type Write = usize;
106 type Reset = ();
107 type Error = Error;
108 type MemoryLayout = dfu_core::memory_layout::MemoryLayout;
109
110 fn read_control(
111 &self,
112 request_type: u8,
113 request: u8,
114 value: u16,
115 buffer: &mut [u8],
116 ) -> Result<Self::Read, Self::Error> {
117 let (control_type, recipient) = split_request_type(request_type);
118 let req = Control {
119 control_type,
120 recipient,
121 request,
122 value,
123 index: self.interface.interface_number() as u16,
124 };
125 let r = self
126 .interface
127 .control_in_blocking(req, buffer, Duration::from_secs(3))?;
128 Ok(r)
129 }
130
131 fn write_control(
132 &self,
133 request_type: u8,
134 request: u8,
135 value: u16,
136 buffer: &[u8],
137 ) -> Result<Self::Write, Self::Error> {
138 let (control_type, recipient) = split_request_type(request_type);
139 let req = Control {
140 control_type,
141 recipient,
142 request,
143 value,
144 index: self.interface.interface_number() as u16,
145 };
146 let r = self
147 .interface
148 .control_out_blocking(req, buffer, Duration::from_secs(3))?;
149 Ok(r)
150 }
151
152 fn usb_reset(&self) -> Result<Self::Reset, Self::Error> {
153 self.device.reset()?;
154 Ok(())
155 }
156
157 fn protocol(&self) -> &dfu_core::DfuProtocol<Self::MemoryLayout> {
158 &self.protocol
159 }
160
161 fn functional_descriptor(&self) -> &FunctionalDescriptor {
162 &self.descriptor
163 }
164}
165
166impl DfuAsyncIo for DfuNusb {
167 type Read = usize;
168 type Write = usize;
169 type Reset = ();
170 type Error = Error;
171 type MemoryLayout = dfu_core::memory_layout::MemoryLayout;
172
173 async fn read_control(
174 &self,
175 request_type: u8,
176 request: u8,
177 value: u16,
178 buffer: &mut [u8],
179 ) -> Result<Self::Read, Self::Error> {
180 let (control_type, recipient) = split_request_type(request_type);
181 let req = ControlIn {
182 control_type,
183 recipient,
184 request,
185 value,
186 index: self.interface.interface_number() as u16,
187 length: buffer.len() as u16,
188 };
189 let r = self.interface.control_in(req).await.into_result()?;
190 let len = buffer.len().min(r.len());
191 buffer[0..len].copy_from_slice(&r[0..len]);
192 Ok(len)
193 }
194
195 async fn write_control(
196 &self,
197 request_type: u8,
198 request: u8,
199 value: u16,
200 buffer: &[u8],
201 ) -> Result<Self::Write, Self::Error> {
202 let (control_type, recipient) = split_request_type(request_type);
203 let req = ControlOut {
204 control_type,
205 recipient,
206 request,
207 value,
208 index: self.interface.interface_number() as u16,
209 data: buffer,
210 };
211 let r = self.interface.control_out(req).await.into_result()?;
212 Ok(r.actual_length())
213 }
214
215 async fn usb_reset(&self) -> Result<Self::Reset, Self::Error> {
216 self.device.reset()?;
217 Ok(())
218 }
219
220 fn protocol(&self) -> &dfu_core::DfuProtocol<Self::MemoryLayout> {
221 &self.protocol
222 }
223
224 fn functional_descriptor(&self) -> &FunctionalDescriptor {
225 &self.descriptor
226 }
227}