use rusb::{Device, DeviceHandle, GlobalContext, UsbContext};
use std::time::Duration;
use super::Socket;
use crate::{Error, Result};
const NXT_VENDOR: u16 = 0x0694;
const NXT_PRODUCT: u16 = 0x0002;
const USB_TIMEOUT: Duration = Duration::from_millis(500);
const WRITE_ENDPOINT: u8 = 0x01;
const READ_ENDPOINT: u8 = 0x82;
const USB_INTERFACE: u8 = 0;
fn device_filter<Usb: UsbContext>(dev: &Device<Usb>) -> bool {
dev.device_descriptor().map_or(false, |desc| {
desc.vendor_id() == NXT_VENDOR && desc.product_id() == NXT_PRODUCT
})
}
#[derive(Debug)]
pub struct Usb {
device: DeviceHandle<GlobalContext>,
}
#[async_trait::async_trait]
impl Socket for Usb {
async fn send(&self, data: &[u8]) -> Result<usize> {
Ok(self.device.write_bulk(WRITE_ENDPOINT, data, USB_TIMEOUT)?)
}
async fn recv<'buf>(&self, buf: &'buf mut [u8]) -> Result<&'buf [u8]> {
let read = self.device.read_bulk(READ_ENDPOINT, buf, USB_TIMEOUT)?;
Ok(&buf[..read])
}
}
impl Usb {
pub fn first() -> Result<Self> {
let device = rusb::devices()?
.iter()
.find(device_filter)
.ok_or(Error::NoBrick)?;
Self::open(device)
}
pub fn all() -> Result<Vec<Self>> {
rusb::devices()?
.iter()
.filter(device_filter)
.map(Self::open)
.collect()
}
#[allow(clippy::needless_pass_by_value)]
fn open(device: Device<GlobalContext>) -> Result<Self> {
let mut device = device.open()?;
device.claim_interface(USB_INTERFACE)?;
Ok(Self { device })
}
}