dfu_nusb/
lib.rs

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    /// Open a device
39    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    /// Wrap device in an *async* dfu helper
75    pub fn into_async_dfu(self) -> DfuASync {
76        DfuASync::new(self)
77    }
78
79    /// Wrap device in an *sync* dfu helper
80    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}