use crate::context::UsbContext;
use crate::error::{Error, Result};
use crate::target_handle::TargetHandle;
use crate::TIMEOUT;
use rusb::Device;
use std::convert::TryFrom;
pub struct Target<T: UsbContext> {
usb_device: Device<T>,
}
impl<T: UsbContext> Target<T> {
pub fn serial(&self) -> Result<String> {
let device_handle = self.usb_device.open()?;
let device_desc = self.usb_device.device_descriptor()?;
let language = device_handle.read_languages(TIMEOUT)?[0];
Ok(device_handle.read_serial_number_string(language, &device_desc, TIMEOUT)?)
}
pub fn open(&self) -> Result<TargetHandle<T>> {
let config_descriptor = self.usb_device.active_config_descriptor()?;
let interface_descriptor = config_descriptor
.interfaces()
.next()
.ok_or(Error::IoError(rusb::Error::Io))?
.descriptors()
.next()
.ok_or(Error::IoError(rusb::Error::Io))?;
let mut endpoint_descriptors = interface_descriptor.endpoint_descriptors();
let in_buffer_length = endpoint_descriptors
.next()
.ok_or(Error::IoError(rusb::Error::Io))?
.max_packet_size();
let out_buffer_length = endpoint_descriptors
.next()
.ok_or(Error::IoError(rusb::Error::Io))?
.max_packet_size();
let mut device_handle = self.usb_device.open()?;
device_handle.reset()?;
Ok(TargetHandle {
usb_device_handle: device_handle,
in_buffer_length,
out_buffer_length,
serial: self.serial()?,
})
}
}
impl<T: UsbContext> TryFrom<rusb::Device<T>> for Target<T> {
type Error = Error;
fn try_from(device: Device<T>) -> Result<Target<T>> {
const VENDOR_STRING: &str = "25120.org";
const PRODUCT_STRING: &str = "punt";
const VENDOR_ID: u16 = 0x16c0;
const PRODUCT_ID: u16 = 0x05dc;
let device_desc = device.device_descriptor()?;
if device_desc.vendor_id() != VENDOR_ID || device_desc.product_id() != PRODUCT_ID {
return Err(Error::UnsupportedTarget);
}
let device_handle = device.open()?;
let language = device_handle.read_languages(TIMEOUT)?[0];
let vendor_string =
device_handle.read_manufacturer_string(language, &device_desc, TIMEOUT)?;
let product_string = device_handle.read_product_string(language, &device_desc, TIMEOUT)?;
if vendor_string != VENDOR_STRING || product_string != PRODUCT_STRING {
return Err(Error::UnsupportedTarget);
}
Ok(Target { usb_device: device })
}
}