Skip to main content

libbladerf_rs/transport/
usb.rs

1use crate::channel::Channel;
2use crate::error::{Error, Result};
3use crate::protocol::nios::NiosPacketError;
4use crate::transport::Transport;
5use nusb::transfer::{Buffer, Bulk, ControlIn, ControlOut, ControlType, In, Out, Recipient};
6use nusb::{Device, Endpoint, Interface, MaybeFuture};
7use std::num::NonZero;
8use std::time::Duration;
9pub const CONTROL_ENDPOINT_OUT: u8 = 0x02;
10pub const CONTROL_ENDPOINT_IN: u8 = 0x82;
11pub const STREAM_ENDPOINT_RX: u8 = 0x81;
12pub const STREAM_ENDPOINT_TX: u8 = 0x01;
13pub const USB_IF_NULL: u8 = 0;
14pub const USB_IF_RF_LINK: u8 = 1;
15pub const BLADE_USB_CMD_RF_RX: u8 = 4;
16pub const BLADE_USB_CMD_RF_TX: u8 = 5;
17pub const BLADE_USB_CMD_SET_LOOPBACK: u8 = 113;
18pub const BLADE_USB_CMD_GET_LOOPBACK: u8 = 114;
19pub const BLADE_USB_CMD_QUERY_DEVICE_READY: u8 = 6;
20pub const BLADE_USB_CMD_RESET: u8 = 105;
21const TIMEOUT: Duration = Duration::from_secs(1);
22#[repr(u8)]
23pub enum StringDescriptors {
24    Manufacturer = 0x1,
25    Product,
26    Serial,
27    Fx3Firmware,
28}
29#[repr(u8)]
30pub enum DescriptorTypes {
31    Configuration = 0x2,
32}
33pub trait DeviceCommands {
34    fn get_supported_languages(&self) -> Result<Vec<u16>>;
35    fn get_configuration_descriptor(&self, descriptor_index: u8) -> Result<Vec<u8>>;
36    fn get_string_descriptor_simple(&self, descriptor_index: NonZero<u8>) -> Result<String>;
37    fn serial(&self) -> Result<String>;
38    fn manufacturer(&self) -> Result<String>;
39    fn product(&self) -> Result<String>;
40}
41impl DeviceCommands for Device {
42    fn get_supported_languages(&self) -> Result<Vec<u16>> {
43        let languages = self
44            .get_string_descriptor_supported_languages(TIMEOUT)
45            .wait()
46            .map_err(|_| Error::Invalid)?
47            .collect();
48        Ok(languages)
49    }
50    fn get_configuration_descriptor(&self, descriptor_index: u8) -> Result<Vec<u8>> {
51        let descriptor = self
52            .get_descriptor(
53                DescriptorTypes::Configuration as u8,
54                descriptor_index,
55                0x00,
56                TIMEOUT,
57            )
58            .wait()
59            .map_err(|_| Error::Invalid)?;
60        Ok(descriptor)
61    }
62    fn get_string_descriptor_simple(&self, descriptor_index: NonZero<u8>) -> Result<String> {
63        let descriptor = self
64            .get_string_descriptor(descriptor_index, 0x409, TIMEOUT)
65            .wait()
66            .map_err(|_| Error::Invalid)?;
67        Ok(descriptor)
68    }
69    fn serial(&self) -> Result<String> {
70        self.get_string_descriptor_simple(
71            NonZero::try_from(StringDescriptors::Serial as u8).map_err(|_| Error::Invalid)?,
72        )
73    }
74    fn manufacturer(&self) -> Result<String> {
75        self.get_string_descriptor_simple(
76            NonZero::try_from(StringDescriptors::Manufacturer as u8).map_err(|_| Error::Invalid)?,
77        )
78    }
79    fn product(&self) -> Result<String> {
80        self.get_string_descriptor_simple(
81            NonZero::try_from(StringDescriptors::Product as u8).map_err(|_| Error::Invalid)?,
82        )
83    }
84}
85pub trait BladeRf1DeviceCommands: DeviceCommands {
86    fn fx3_firmware_version(&self) -> Result<String>;
87}
88impl BladeRf1DeviceCommands for Device {
89    fn fx3_firmware_version(&self) -> Result<String> {
90        self.get_string_descriptor_simple(
91            NonZero::try_from(StringDescriptors::Fx3Firmware as u8).map_err(|_| Error::Invalid)?,
92        )
93    }
94}
95pub trait UsbInterfaceCommands {
96    fn usb_vendor_cmd_int(&self, cmd: u8) -> Result<u32>;
97    fn usb_vendor_cmd_int_wvalue(&self, cmd: u8, wvalue: u16) -> Result<u32>;
98    fn usb_change_setting(&mut self, setting: u8) -> Result<()>;
99    fn usb_set_configuration(&self, configuration: u16) -> Result<()>;
100}
101impl UsbInterfaceCommands for Interface {
102    fn usb_vendor_cmd_int(&self, cmd: u8) -> Result<u32> {
103        let pkt = ControlIn {
104            control_type: ControlType::Vendor,
105            recipient: Recipient::Device,
106            request: cmd,
107            value: 0,
108            index: 0,
109            length: 0x4,
110        };
111        let vec = self.control_in(pkt, TIMEOUT).wait()?;
112        log::debug!("get_vendor_cmd_int response data: {vec:?}");
113        Ok(u32::from_le_bytes(
114            vec.as_slice()[0..4]
115                .try_into()
116                .map_err(|_| Error::Invalid)?,
117        ))
118    }
119    fn usb_vendor_cmd_int_wvalue(&self, cmd: u8, wvalue: u16) -> Result<u32> {
120        let pkt = ControlIn {
121            control_type: ControlType::Vendor,
122            recipient: Recipient::Device,
123            request: cmd,
124            value: wvalue,
125            index: 0,
126            length: 0x4,
127        };
128        let vec = self.control_in(pkt, TIMEOUT).wait()?;
129        log::trace!("vendor_cmd_int_wvalue response data: {vec:?}");
130        Ok(u32::from_le_bytes(
131            vec.as_slice()[0..4]
132                .try_into()
133                .map_err(|_| Error::Invalid)?,
134        ))
135    }
136    fn usb_change_setting(&mut self, setting: u8) -> Result<()> {
137        Ok(self.set_alt_setting(setting).wait()?)
138    }
139    fn usb_set_configuration(&self, configuration: u16) -> Result<()> {
140        Ok(self
141            .control_out(
142                ControlOut {
143                    control_type: ControlType::Standard,
144                    recipient: Recipient::Device,
145                    request: 0x09,
146                    value: configuration,
147                    index: 0x00,
148                    data: &[],
149                },
150                TIMEOUT,
151            )
152            .wait()?)
153    }
154}
155pub trait BladeRf1UsbInterfaceCommands: UsbInterfaceCommands {
156    fn usb_enable_module(&self, channel: Channel, enable: bool) -> Result<()>;
157    fn usb_set_firmware_loopback(&mut self, enable: bool) -> Result<()>;
158    fn usb_get_firmware_loopback(&self) -> Result<bool>;
159    fn usb_device_reset(&self) -> Result<()>;
160    fn usb_is_firmware_ready(&self) -> Result<bool>;
161}
162impl BladeRf1UsbInterfaceCommands for Interface {
163    fn usb_enable_module(&self, channel: Channel, enable: bool) -> Result<()> {
164        let val = enable as u16;
165        let cmd = if channel.is_rx() {
166            BLADE_USB_CMD_RF_RX
167        } else {
168            BLADE_USB_CMD_RF_TX
169        };
170        let _fx3_ret = self.usb_vendor_cmd_int_wvalue(cmd, val)?;
171        Ok(())
172    }
173    fn usb_set_firmware_loopback(&mut self, enable: bool) -> Result<()> {
174        self.usb_vendor_cmd_int_wvalue(BLADE_USB_CMD_SET_LOOPBACK, enable as u16)?;
175        self.usb_change_setting(USB_IF_NULL)?;
176        self.usb_change_setting(USB_IF_RF_LINK)?;
177        Ok(())
178    }
179    fn usb_get_firmware_loopback(&self) -> Result<bool> {
180        let result = self.usb_vendor_cmd_int(BLADE_USB_CMD_GET_LOOPBACK)?;
181        Ok(result != 0)
182    }
183    fn usb_device_reset(&self) -> Result<()> {
184        let pkt = ControlOut {
185            control_type: ControlType::Vendor,
186            recipient: Recipient::Device,
187            request: BLADE_USB_CMD_RESET,
188            value: 0x0,
189            index: 0x0,
190            data: &[],
191        };
192        self.control_out(pkt, TIMEOUT).wait()?;
193        Ok(())
194    }
195    fn usb_is_firmware_ready(&self) -> Result<bool> {
196        Ok(self.usb_vendor_cmd_int(BLADE_USB_CMD_QUERY_DEVICE_READY)? != 0)
197    }
198}
199impl UsbInterfaceCommands for UsbTransport {
200    fn usb_vendor_cmd_int(&self, cmd: u8) -> Result<u32> {
201        self.interface.usb_vendor_cmd_int(cmd)
202    }
203    fn usb_vendor_cmd_int_wvalue(&self, cmd: u8, wvalue: u16) -> Result<u32> {
204        self.interface.usb_vendor_cmd_int_wvalue(cmd, wvalue)
205    }
206    fn usb_change_setting(&mut self, setting: u8) -> Result<()> {
207        self.release_endpoints();
208        self.interface.set_alt_setting(setting).wait()?;
209        Ok(())
210    }
211    fn usb_set_configuration(&self, configuration: u16) -> Result<()> {
212        self.interface.usb_set_configuration(configuration)
213    }
214}
215impl BladeRf1UsbInterfaceCommands for UsbTransport {
216    fn usb_enable_module(&self, channel: Channel, enable: bool) -> Result<()> {
217        self.interface.usb_enable_module(channel, enable)
218    }
219    fn usb_set_firmware_loopback(&mut self, enable: bool) -> Result<()> {
220        self.interface
221            .usb_vendor_cmd_int_wvalue(BLADE_USB_CMD_SET_LOOPBACK, enable as u16)?;
222        self.usb_change_setting(USB_IF_NULL)?;
223        self.usb_change_setting(USB_IF_RF_LINK)?;
224        Ok(())
225    }
226    fn usb_get_firmware_loopback(&self) -> Result<bool> {
227        self.interface.usb_get_firmware_loopback()
228    }
229    fn usb_device_reset(&self) -> Result<()> {
230        self.interface.usb_device_reset()
231    }
232    fn usb_is_firmware_ready(&self) -> Result<bool> {
233        self.interface.usb_is_firmware_ready()
234    }
235}
236struct NiosEndpoints {
237    ep_out: Endpoint<Bulk, Out>,
238    ep_in: Endpoint<Bulk, In>,
239    buf_out: Option<Buffer>,
240    buf_in: Option<Buffer>,
241}
242pub struct UsbTransport {
243    interface: Interface,
244    nios_endpoints: Option<NiosEndpoints>,
245}
246impl UsbTransport {
247    const NIOS_PKT_SIZE: usize = 16;
248    pub fn new(interface: Interface) -> Self {
249        Self {
250            interface,
251            nios_endpoints: None,
252        }
253    }
254    pub fn interface(&self) -> &Interface {
255        &self.interface
256    }
257    pub fn release_endpoints(&mut self) {
258        self.nios_endpoints = None;
259    }
260    fn ensure_nios_endpoints(&mut self) -> Result<&mut NiosEndpoints> {
261        if self.nios_endpoints.is_none() {
262            let ep_out = self
263                .interface
264                .endpoint::<Bulk, Out>(CONTROL_ENDPOINT_OUT)
265                .map_err(|_| Error::EndpointBusy)?;
266            let ep_in = self
267                .interface
268                .endpoint::<Bulk, In>(CONTROL_ENDPOINT_IN)
269                .map_err(|_| Error::EndpointBusy)?;
270            let buf_out = Some(ep_out.allocate(Self::NIOS_PKT_SIZE));
271            let buf_in = Some(ep_in.allocate(ep_in.max_packet_size()));
272            self.nios_endpoints = Some(NiosEndpoints {
273                ep_out,
274                ep_in,
275                buf_out,
276                buf_in,
277            });
278        }
279        Ok(self.nios_endpoints.as_mut().unwrap())
280    }
281    pub fn out_buffer(&mut self) -> Result<&mut [u8]> {
282        Transport::out_buffer(self)
283    }
284    pub fn acquire_streaming_rx_endpoint(&self) -> Result<Endpoint<Bulk, In>> {
285        self.interface
286            .endpoint::<Bulk, In>(STREAM_ENDPOINT_RX)
287            .map_err(|_| Error::EndpointBusy)
288    }
289    pub fn acquire_streaming_tx_endpoint(&self) -> Result<Endpoint<Bulk, Out>> {
290        self.interface
291            .endpoint::<Bulk, Out>(STREAM_ENDPOINT_TX)
292            .map_err(|_| Error::EndpointBusy)
293    }
294}
295impl Transport for UsbTransport {
296    fn out_buffer(&mut self) -> Result<&mut [u8]> {
297        let endpoints = self.ensure_nios_endpoints()?;
298        let buf = endpoints.buf_out.as_mut().ok_or(Error::EndpointBusy)?;
299        buf.clear();
300        buf.extend_fill(Self::NIOS_PKT_SIZE, 0);
301        Ok(buf)
302    }
303    fn submit(&mut self, timeout: Option<Duration>) -> Result<&[u8]> {
304        let endpoints = self.ensure_nios_endpoints()?;
305        let t = timeout.unwrap_or(TIMEOUT);
306        let buf_out = endpoints.buf_out.take().ok_or(Error::EndpointBusy)?;
307        log::trace!("submit: OUT buffer len = {}", buf_out.len());
308        endpoints.ep_out.submit(buf_out);
309        let mut response = endpoints
310            .ep_out
311            .wait_next_complete(t)
312            .ok_or(Error::Timeout)?;
313        response.status?;
314        endpoints.buf_out = Some(response.buffer);
315        let mut buf_in = endpoints.buf_in.take().ok_or(Error::EndpointBusy)?;
316        buf_in.set_requested_len(endpoints.ep_in.max_packet_size());
317        endpoints.ep_in.submit(buf_in);
318        response = endpoints
319            .ep_in
320            .wait_next_complete(t)
321            .ok_or(Error::Timeout)?;
322        response.status?;
323        endpoints.buf_in = Some(response.buffer);
324        let in_buf = endpoints.buf_in.as_ref().unwrap();
325        let in_len = in_buf.len();
326        if in_len < Self::NIOS_PKT_SIZE {
327            return Err(NiosPacketError::InvalidSize(in_len).into());
328        }
329        Ok(&in_buf[..Self::NIOS_PKT_SIZE])
330    }
331}
332impl From<Interface> for UsbTransport {
333    fn from(interface: Interface) -> Self {
334        Self::new(interface)
335    }
336}