use crate::{
error::usb_result, ConfigDescriptor, Context, DeviceDescriptor, DeviceHandle, Error, Port,
Result, Speed,
};
use libusb1_sys::*;
use std::{
fmt::{self, Debug},
mem,
ptr::NonNull,
};
#[derive(Eq, PartialEq)]
pub struct Device {
ctx: Context,
device: NonNull<libusb_device>,
}
impl Device {
pub fn as_raw(&self) -> *mut libusb_device {
self.device.as_ptr()
}
pub fn context(&self) -> Context {
self.ctx.clone()
}
pub unsafe fn from_libusb(ctx: Context, device: NonNull<libusb_device>) -> Self {
libusb_ref_device(device.as_ptr());
Self { ctx, device }
}
pub fn device_descriptor(&self) -> Result<DeviceDescriptor> {
let mut descriptor = mem::MaybeUninit::<libusb_device_descriptor>::uninit();
try_unsafe!(libusb_get_device_descriptor(
self.device.as_ptr(),
descriptor.as_mut_ptr()
));
Ok(DeviceDescriptor::from(unsafe { descriptor.assume_init() }))
}
pub fn config_descriptor(&self, config_index: u8) -> Result<ConfigDescriptor> {
let mut config = mem::MaybeUninit::<*const libusb_config_descriptor>::uninit();
try_unsafe!(libusb_get_config_descriptor(
self.device.as_ptr(),
config_index,
config.as_mut_ptr()
));
Ok(unsafe { ConfigDescriptor::from(config.assume_init()) })
}
pub fn active_config_descriptor(&self) -> Result<ConfigDescriptor> {
let mut config = mem::MaybeUninit::<*const libusb_config_descriptor>::uninit();
try_unsafe!(libusb_get_active_config_descriptor(
self.device.as_ptr(),
config.as_mut_ptr()
));
Ok(unsafe { ConfigDescriptor::from(config.assume_init()) })
}
pub fn bus_number(&self) -> u8 {
unsafe { libusb_get_bus_number(self.device.as_ptr()) }
}
pub fn address(&self) -> u8 {
unsafe { libusb_get_device_address(self.device.as_ptr()) }
}
pub fn speed(&self) -> Speed {
Speed::from(unsafe { libusb_get_device_speed(self.device.as_ptr()) })
}
pub fn open(&self) -> Result<DeviceHandle> {
let mut handle = mem::MaybeUninit::<*mut libusb_device_handle>::uninit();
try_unsafe!(libusb_open(self.device.as_ptr(), handle.as_mut_ptr()));
Ok(unsafe {
let ptr = NonNull::new(handle.assume_init()).ok_or(Error::NoDevice)?;
DeviceHandle::from_libusb(self.context(), ptr)
})
}
pub fn port_number(&self) -> u8 {
unsafe { libusb_get_port_number(self.device.as_ptr()) }
}
pub fn get_parent(&self) -> Option<Self> {
let device = unsafe { libusb_get_parent(self.device.as_ptr()) };
NonNull::new(device).map(|device| unsafe { Device::from_libusb(self.context(), device) })
}
pub fn port_numbers(&self) -> Result<Vec<u8>> {
let mut ports = [0; 7];
let n = usb_result(unsafe {
libusb_get_port_numbers(self.device.as_ptr(), ports.as_mut_ptr(), ports.len() as i32)
})?;
Ok(ports[0..n].to_vec())
}
pub fn port(&self) -> Result<Port> {
let bus = self.bus_number();
let ports = self.port_numbers()?;
Ok(Port::new(bus, ports))
}
pub fn matches_vid(&self, vid: u16) -> bool {
match self.device_descriptor() {
Ok(d) => vid == d.vendor_id(),
_ => false,
}
}
pub fn matches_vid_pid(&self, vid: u16, pid: u16) -> bool {
match self.device_descriptor() {
Ok(d) => vid == d.vendor_id() && pid == d.product_id(),
_ => false,
}
}
}
impl Drop for Device {
fn drop(&mut self) {
unsafe {
libusb_unref_device(self.device.as_ptr());
}
}
}
impl Clone for Device {
fn clone(&self) -> Self {
unsafe { Self::from_libusb(self.context(), self.device) }
}
}
unsafe impl Send for Device {}
unsafe impl Sync for Device {}
impl Debug for Device {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let descriptor = match self.device_descriptor() {
Ok(descriptor) => descriptor,
Err(e) => {
return write!(f, "Can't read device descriptor {:?}", e);
}
};
write!(
f,
"Bus {:03} Device {:03}: ID {:04x}:{:04x}",
self.bus_number(),
self.address(),
descriptor.vendor_id(),
descriptor.product_id(),
)
}
}